add:管理页面页码+Banner配置

This commit is contained in:
lan
2022-12-19 18:01:50 +08:00
parent a907a8bfa7
commit 630052076a
4 changed files with 221 additions and 27 deletions
+8 -1
View File
@@ -1,5 +1,5 @@
import datetime
from sqlalchemy import Boolean, Column, Integer, String, DateTime
from sqlalchemy import Boolean, Column, Integer, String, DateTime, JSON
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.ext.asyncio.session import AsyncSession
@@ -20,6 +20,13 @@ async def get_session():
yield s
class Values(Base):
__tablename__ = 'values'
id = Column(Integer, primary_key=True, index=True)
key = Column(String, unique=True)
value = Column(JSON)
class Codes(Base):
__tablename__ = "codes"
id = Column(Integer, primary_key=True, index=True)
+51 -9
View File
@@ -4,15 +4,16 @@ import asyncio
from pathlib import Path
from fastapi import FastAPI, Depends, UploadFile, Form, File, HTTPException, BackgroundTasks
from starlette.requests import Request
from starlette.responses import HTMLResponse, FileResponse
from starlette.staticfiles import StaticFiles
from sqlalchemy import select, update
from sqlalchemy import select, update, func
from sqlalchemy.ext.asyncio.session import AsyncSession
import settings
from utils import delete_expire_files, storage, get_code, error_ip_limit, upload_ip_limit
from database import get_session, Codes, init_models
from database import get_session, Codes, init_models, Values
from depends import admin_required
# 实例化FastAPI
@@ -48,16 +49,33 @@ admin_html = open('templates/admin.html', 'r', encoding='utf-8').read() \
.replace('{{keywords}}', settings.KEYWORDS)
@app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面', response_class=HTMLResponse)
@app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面')
async def admin():
return HTMLResponse(admin_html)
@app.post(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='查询数据库列表')
async def admin_post(s: AsyncSession = Depends(get_session)):
# 查询数据库列表
codes = (await s.execute(select(Codes))).scalars().all()
return {'detail': '查询成功', 'data': codes}
async def admin_post(page: int = Form(default=1), size: int = Form(default=10), s: AsyncSession = Depends(get_session)):
codes = (await s.execute(select(Codes).offset((page - 1) * size).limit(size))).scalars().all()
total = (await s.execute(select(func.count(Codes.id)))).scalar()
return {'detail': '查询成功', 'data': codes, 'paginate': {
'page': page,
'size': size,
'total': total
}}
@app.patch(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='修改数据库数据')
async def admin_patch(request: Request, s: AsyncSession = Depends(get_session)):
# 从数据库获取系统配置
# 如果不存在config这个key,就创建一个
config = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none()
if not config:
s.add(Values(key='config', value=await request.json()))
else:
await s.execute(update(Values).where(Values.key == 'config').values(value=await request.json()))
await s.commit()
return {'detail': '修改成功'}
@app.delete(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='删除数据库记录')
@@ -76,16 +94,40 @@ async def admin_delete(code: str, s: AsyncSession = Depends(get_session)):
return {'detail': '删除成功'}
@app.get('/config', description='获取系统配置', dependencies=[Depends(admin_required)])
async def config(s: AsyncSession = Depends(get_session)):
# 从数据库获取系统配置
data = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none()
return {'detail': '获取成功', 'data': data.value}
@app.get('/')
async def index():
return HTMLResponse(index_html)
@app.get('/banner')
async def banner():
async def banner(s: AsyncSession = Depends(get_session)):
# 数据库查询config
config = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none()
# 如果存在config,就返回config的value
if config and config.value.get('banners'):
return {
'detail': '查询成功',
'data': config.value['banners']
}
# 如果不存在config,就返回默认的banner
return {
'detail': 'banner',
'data': settings.UPLOAD_BANNERS.split(',')
'data': [{
'text': 'FileCodeBox',
'url': 'https://github.com/vastsa/FileCodeBox',
'src': '/static/banners/img_1.png'
}, {
'text': 'FileCodeBox',
'url': 'https://www.lanol.cn',
'src': '/static/banners/img_2.png'
}]
}
+160 -15
View File
@@ -12,18 +12,26 @@
<meta name="keywords" content="{{keywords}}"/>
<meta name="generator" content="FileCodeBox"/>
<meta name="template" content="Lan"/>
<script src="/static/asserts/vue.min.js"></script>
<script src="/static/asserts/vue.js"></script>
<script src="/static/asserts/index.js"></script>
<style>
.el-menu-demo {
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<el-row v-if="login" :gutter="10">
<el-col :xs="0" :sm="4" :md="4" :lg="4" :xl="4">
&nbsp;
<el-col :span="24" style="text-align: center">
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="2">文件管理</el-menu-item>
<el-menu-item index="3">系统配置</el-menu-item>
</el-menu>
</el-col>
<el-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<el-card>
<el-empty v-if="files.length===0" description="暂时还没有文件"></el-empty>
<el-col v-if="activeIndex === '2'">
<el-card style="height: 80vh;overflow: scroll;margin-bottom: 1rem">
<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">
@@ -49,8 +57,87 @@
</el-row>
</el-card>
</el-card>
<el-pagination
background
style="text-align: center"
layout="prev, pager, next, sizes"
:page-size="paginate.page_size"
@current-change="loginAdmin"
@size-change="updateSize"
:total="paginate.total"
>
</el-pagination>
</el-col>
<el-col v-if="activeIndex === '3'">
<el-form ref="form" style="width: 50%;margin:2rem auto" :model="config" label-width="200px">
<!--? <el-form-item label="错误限制">-->
<!--? <div>-->
<!--? 间隔-->
<!--? <el-input-number v-model="config.error_count" :min="1"></el-input-number>-->
<!--? 分钟-->
<!--? </div>-->
<!--? <div>-->
<!--? 数量-->
<!--? <el-input-number v-model="config.error_minute" :min="1"></el-input-number>-->
<!--? -->
<!--? </div>-->
<!--? </el-form-item>-->
<!--? <el-form-item label="上传限制">-->
<!--? <div>-->
<!--? 开启上传-->
<!--? <el-switch-->
<!--? v-model="config.enable_upload"-->
<!--? active-color="#13ce66"-->
<!--? inactive-color="#ff4949">-->
<!--? </el-switch>-->
<!--? </div>-->
<!--? <div>-->
<!--? 间隔-->
<!--? <el-input-number v-model="config.upload_minute" :min="1"></el-input-number>-->
<!--? 分钟-->
<!--? </div>-->
<!--? <div>-->
<!--? 数量-->
<!--? <el-input-number v-model="config.upload_count" :min="1"></el-input-number>-->
<!--? -->
<!--? </div>-->
<!--? <div>-->
<!--? 最长-->
<!--? <el-input-number v-model="config.max_days" :min="1"></el-input-number>-->
<!--? -->
<!--? </div>-->
<!--? <div>-->
<!--? 大小-->
<!--? <el-input-number v-model="config.file_size_limit" :min="1"></el-input-number>-->
<!--? MB-->
<!--? </div>-->
<!--? </el-form-item>-->
<!--? <el-form-item label="删除间隔">-->
<!--? 时长-->
<!--? <el-input-number v-model="config.delete_expire_files_interval"></el-input-number>-->
<!--? 分钟-->
<!--? </el-form-item>-->
<!--? <el-form-item label="管理员密码">-->
<!--? <el-input v-model="config.admin_password" type="password"></el-input>-->
<!--? </el-form-item>-->
<el-form-item v-for="(banner,index) in config.banners" :label="'Banner'+ (index+1)">
<div style="width: 50%;display: inline-block">
<el-input v-model="banner.text" placeholder="文本"></el-input>
<el-input v-model="banner.url" placeholder="跳转链接"></el-input>
<el-input v-model="banner.src" placeholder="图片路径"></el-input>
</div>
<div style="display: inline-block">
<el-button type="danger" @click="deleteBanner(index)">删除</el-button>
</div>
</el-form-item>
<el-form-item>
<el-button size="mini" @click="addBanner" type="primary">新增Banner</el-button>
</el-form-item>
<el-form-item>
<el-button @click="updateConfig" type="primary">更新</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :xs="0" :sm="4" :md="4" :lg="4" :xl="4">&nbsp;</el-col>
</el-row>
<div v-else style="width: 250px;text-align: center;margin: 40vh auto">
<el-input v-model="pwd" placeholder="请输入登录密码">
@@ -69,12 +156,25 @@
return {
login: false,
pwd: '',
files: [],
activeIndex: '2',
config: {
error_count: 0,
file_size: 0,
admin_pwd: 'admin'
}
// enable_upload: true,
// max_days: 7,
// error_count: 3,
// error_minute: 10,
// upload_count: 10,
// upload_minute: 10,
// delete_expire_files_interval: 10,
// admin_password: 'admin',
// file_size_limit: 10,
banners: []
},
files: [],
paginate: {
page: 1,
size: 10,
total: 0,
},
};
},
mounted: function () {
@@ -82,13 +182,55 @@
if (pwd) {
login = true;
this.pwd = pwd;
axios.get('/config', {
headers: {
pwd: pwd
}
}).then(res => {
console.log(res.data.data)
this.config = res.data.data;
});
this.loginAdmin();
}
},
methods: {
loginAdmin: function () {
axios.post('', {}, {'headers': {'pwd': this.pwd}}).then(res => {
this.files = res.data.data;
updateSize: function (value) {
this.paginate.size = value;
this.loginAdmin();
},
deleteBanner: function (index) {
this.config.banners.splice(index, 1);
},
addBanner: function () {
this.config.banners.push({
'url': '',
'src': '',
'text': '',
})
},
updateConfig: function () {
axios.patch('', this.config, {
'headers': {
'pwd': this.pwd,
'Content-Type': 'multipart/json'
}
}).then(res => {
this.$message({
message: res.data.detail,
type: 'success'
});
})
},
loginAdmin: function (current_page = 1) {
this.paginate.page = current_page;
axios.post('', this.paginate, {
'headers': {
'pwd': this.pwd,
'Content-Type': 'multipart/form-data'
}
}).then(res => {
this.paginate = res.data.paginate;
this.files = res.data.data
this.login = true;
localStorage.setItem('pwd', this.pwd);
}).catch(e => {
@@ -96,6 +238,9 @@
this.$message({'message': e.response.data.detail, 'type': 'error'});
});
},
handleSelect(key, keyPath) {
this.activeIndex = key;
},
deleteFile: function (code) {
axios.delete('?code=' + code, {'headers': {'pwd': this.pwd}}).then(res => {
this.files = this.files.filter(item => item.code !== code)
+2 -2
View File
@@ -93,8 +93,8 @@
<div class="block" style="margin-bottom: 1rem">
<el-carousel height="150px">
<el-carousel-item v-for="item in banners" :key="item">
<a href="" target="_blank">
<img class="image" style="width: 400px" :src="item" alt="1">
<a :href="item.url" target="_blank">
<img class="image" style="width: 400px" :src="item.src" :alt="item.text">
</a>
</el-carousel-item>
</el-carousel>