提交 d57d609c 编写于 作者: C Corley

V1.7

上级 c51e2976
...@@ -24,4 +24,7 @@ ...@@ -24,4 +24,7 @@
这一版本开始进入前台开发阶段,首先定义前台的用户模型,并在此基础上搭建前台注册页面和完成图形验证码类,再实现点击更换图形验证码的功能,接下来实现发送短信验证码的功能,并实现短信验证码接口的MD5加密和JS加密代码的加密。 这一版本开始进入前台开发阶段,首先定义前台的用户模型,并在此基础上搭建前台注册页面和完成图形验证码类,再实现点击更换图形验证码的功能,接下来实现发送短信验证码的功能,并实现短信验证码接口的MD5加密和JS加密代码的加密。
#### V1.6 #### V1.6
在V1.5的基础上进一步完成注册功能,将验证码保存到Redis中,并实现注册完成跳转回上一个页面;再实现登录功能;最后完善首页,在导航栏的基础上初步实现轮播图效果。 在V1.5的基础上进一步完成注册功能,将验证码保存到Redis中,并实现注册完成跳转回上一个页面;再实现登录功能;最后完善首页,在导航栏的基础上初步实现轮播图效果。
\ No newline at end of file
#### V1.7
在前一版本的基础上进一步美化轮播图的效果、完善其功能,并实现后台的轮播图管理页面,添加了轮播图管理权限,实现基本的页面布局,在此基础上实现添加、编辑和删除轮播图的功能,最后简单地介绍了七牛云的基本使用。
\ No newline at end of file
from wtforms import Form, StringField, IntegerField, ValidationError from wtforms import Form, StringField, IntegerField, ValidationError
from wtforms.validators import Email, InputRequired, Length, EqualTo from wtforms.validators import Email, InputRequired, Length, EqualTo, URL
from utils import clcache from utils import clcache
...@@ -30,4 +30,15 @@ class ResetEmailForm(BaseForm): ...@@ -30,4 +30,15 @@ class ResetEmailForm(BaseForm):
email = self.email.data email = self.email.data
redis_captcha = clcache.get_captcha(email) redis_captcha = clcache.get_captcha(email)
if not redis_captcha or captcha.lower() != redis_captcha.lower(): if not redis_captcha or captcha.lower() != redis_captcha.lower():
raise ValidationError('邮箱验证码错误') raise ValidationError('邮箱验证码错误')
\ No newline at end of file
class AddBannerForm(BaseForm):
name = StringField(validators=[InputRequired(message='请输入轮播图名称')])
image_url = StringField(validators=[InputRequired(message='请输入图片链接'), URL(message='请注意图片链接格式')])
link_url = StringField(validators=[InputRequired(message='请输入跳转链接'), URL(message='请注意跳转链接格式')])
priority = IntegerField(validators=[InputRequired(message='请输入轮播图优先级')])
class UpdateBannerForm(AddBannerForm):
banner_id = IntegerField(validators=[InputRequired(message='轮播图不存在')])
\ No newline at end of file
...@@ -66,20 +66,23 @@ class CMSPermission(object): ...@@ -66,20 +66,23 @@ class CMSPermission(object):
# 管理帖子权限 # 管理帖子权限
POSTER = 0b00000010 POSTER = 0b00000010
# 管理轮播图
BANNER = 0b00000100
# 管理评论权限 # 管理评论权限
COMMENTER = 0b00000100 COMMENTER = 0b00001000
# 管理板块 # 管理板块
BOARDER = 0b00001000 BOARDER = 0b00010000
# 管理前台用户 # 管理前台用户
FRONTUSER = 0b00010000 FRONTUSER = 0b00100000
# 管理前台用户 # 管理前台用户
CMSUSER = 0b00100000 CMSUSER = 0b01000000
# 管理前台用户 # 管理前台用户
ADMINER = 0b01000000 ADMINER = 0b10000000
cms_role_user = db.Table( cms_role_user = db.Table(
...@@ -97,3 +100,18 @@ class CMSRole(db.Model): ...@@ -97,3 +100,18 @@ class CMSRole(db.Model):
permissions = db.Column(db.Integer, default=CMSPermission.VISITOR) permissions = db.Column(db.Integer, default=CMSPermission.VISITOR)
users = db.relationship('CMSUser', secondary=cms_role_user, backref='roles') users = db.relationship('CMSUser', secondary=cms_role_user, backref='roles')
class BannerModel(db.Model):
__tablename__ = 'banner'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), nullable=False)
# 图片链接
image_url = db.Column(db.String(255), nullable=False)
# 跳转链接
link_url = db.Column(db.String(255), nullable=False)
# 优先级
priority = db.Column(db.Integer, default=0)
create_time = db.Column(db.DateTime, default=datetime.now)
# 1表示被删除,0表示未删除,默认为0
is_delete = db.Column(db.Integer, default=0)
\ No newline at end of file
from flask import Blueprint, render_template, views, request, redirect, url_for, session, g from flask import Blueprint, render_template, views, request, redirect, url_for, session, g
from flask_mail import Message from flask_mail import Message
from sqlalchemy import or_
from apps.cms.forms import LoginForm, ResetPwdForm, ResetEmailForm from apps.cms.forms import LoginForm, ResetPwdForm, ResetEmailForm, AddBannerForm, UpdateBannerForm
from apps.cms.models import CMSUser, CMSPermission from apps.cms.models import CMSUser, CMSPermission, BannerModel
from exts import db, mail from exts import db, mail
from utils import restful, random_captcha, clcache from utils import restful, random_captcha, clcache
from .decorators import permission_required # .代表当前路径 from .decorators import permission_required # .代表当前路径
...@@ -121,6 +122,67 @@ def posts(): ...@@ -121,6 +122,67 @@ def posts():
return render_template('cms/cms_posts.html', max_role=g.max_role) return render_template('cms/cms_posts.html', max_role=g.max_role)
@cms_bp.route('/banners/')
@permission_required(CMSPermission.BANNER)
def banners():
banners = BannerModel.query.filter(or_(BannerModel.is_delete == 0, BannerModel.is_delete == None)).order_by(BannerModel.priority.desc()).all()
return render_template('cms/cms_banners.html', max_role=g.max_role, banners=banners)
@cms_bp.route('/abanner/', methods=['POST'])
def abanner():
form = AddBannerForm(request.form)
if form.validate():
name = form.name.data
image_url = form.image_url.data
link_url = form.link_url.data
priority = form.priority.data
banner = BannerModel(name=name, image_url=image_url, link_url=link_url, priority=priority)
db.session.add(banner)
db.session.commit()
return restful.success()
else:
return restful.params_error(message=form.get_error())
@cms_bp.route('/ubanner/', methods=['POST'])
def ubanner():
# 根据id修改数据
form = UpdateBannerForm(request.form)
if form.validate():
banner_id = form.banner_id.data
name = form.name.data
image_url = form.image_url.data
link_url = form.link_url.data
priority = form.priority.data
banner = BannerModel.query.get(banner_id)
if banner and banner.is_delete != 1:
banner.name = name
banner.image_url = image_url
banner.link_url = link_url
banner.priority = priority
db.session.commit()
return restful.success()
else:
return restful.params_error(message='轮播图不存在')
else:
return restful.params_error(form.get_error())
@cms_bp.route('/dbanner/', methods=['POST'])
def dbanner():
banner_id = request.form.get('banner_id')
if not banner_id:
return restful.params_error(message='数据请求有误')
banner = BannerModel.query.get(banner_id)
if banner and banner.is_delete != 1:
banner.is_delete = 1
db.session.commit()
return restful.success()
else:
return restful.params_error(message='轮播图不存在')
@cms_bp.route('/comments/') @cms_bp.route('/comments/')
@permission_required(CMSPermission.COMMENTER) @permission_required(CMSPermission.COMMENTER)
def comments(): def comments():
......
...@@ -31,4 +31,8 @@ MAIL_PASSWORD = 'vrxiqciwjnbcxxxx' ...@@ -31,4 +31,8 @@ MAIL_PASSWORD = 'vrxiqciwjnbcxxxx'
MAIL_DEFAULT_SENDER = '379869029@qq.com' MAIL_DEFAULT_SENDER = '379869029@qq.com'
# 云片APIKEY # 云片APIKEY
YP_API = 'edf71361381f31b3957beda37f20xxxx' YP_API = 'edf71361381f31b3957beda37f20xxxx'
\ No newline at end of file
# 七牛云密钥
QN_AK = '_PL7p4sTSlfAKl71hIkuG3F6y18681ZKkNJ3xxxx'
QN_SK = '4P09jodUqhhEqIOcaqT9daVFmKjCJI3l6gsAxxxx'
\ No newline at end of file
...@@ -2,7 +2,7 @@ from flask_script import Manager ...@@ -2,7 +2,7 @@ from flask_script import Manager
from bbs import app from bbs import app
from flask_migrate import Migrate, MigrateCommand from flask_migrate import Migrate, MigrateCommand
from exts import db from exts import db
from apps.cms.models import CMSUser, CMSRole, CMSPermission from apps.cms.models import CMSUser, CMSRole, CMSPermission, BannerModel
from apps.front.models import FrontUser from apps.front.models import FrontUser
manager = Manager(app) manager = Manager(app)
...@@ -28,12 +28,12 @@ def create_role(): ...@@ -28,12 +28,12 @@ def create_role():
visitor.permissions = CMSPermission.VISITOR # 也可以省去,因为默认权限就是VISITOR visitor.permissions = CMSPermission.VISITOR # 也可以省去,因为默认权限就是VISITOR
# 运营者 # 运营者
operator = CMSRole(name='运营', desc='管理帖子,管理评论,管理前台和后台用户') operator = CMSRole(name='运营', desc='管理帖子,管理评论,管理前台和后台用户,管理轮播图')
# 有多个权限时,使用或运算表示 # 有多个权限时,使用或运算表示
operator.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FRONTUSER operator.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FRONTUSER | CMSPermission.BANNER
# 管理员 # 管理员
admin = CMSRole(name='管理员', desc='拥有本系统大部分权限') admin = CMSRole(name='管理员', desc='拥有本系统大部分权限')
admin.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FRONTUSER | CMSPermission.BOARDER admin.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FRONTUSER | CMSPermission.BOARDER | CMSPermission.BANNER
# 开发人员 # 开发人员
developer = CMSRole(name='开发者', desc='拥有所有权限') developer = CMSRole(name='开发者', desc='拥有所有权限')
......
"""empty message
Revision ID: 02bd2cd7181a
Revises: 05b4318c5600
Create Date: 2020-06-27 17:26:38.212179
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '02bd2cd7181a'
down_revision = '05b4318c5600'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
"""empty message
Revision ID: 05b4318c5600
Revises: 7c0603064b34
Create Date: 2020-06-27 13:55:13.753498
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '05b4318c5600'
down_revision = '7c0603064b34'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('banner',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=30), nullable=False),
sa.Column('image_url', sa.String(length=255), nullable=False),
sa.Column('link_url', sa.String(length=255), nullable=False),
sa.Column('priority', sa.Integer(), nullable=True),
sa.Column('create_time', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('banner')
# ### end Alembic commands ###
"""empty message
Revision ID: 23fa298b6e40
Revises: 495dbcec29c8
Create Date: 2020-06-27 18:51:35.614598
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '23fa298b6e40'
down_revision = '495dbcec29c8'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', mysql.ENUM('DELETE', 'NOT_DELETE'), nullable=True))
# ### end Alembic commands ###
"""empty message
Revision ID: 418954f97705
Revises: dbdc069de73b
Create Date: 2020-06-27 12:06:51.146235
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '418954f97705'
down_revision = 'dbdc069de73b'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('banner',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=30), nullable=False),
sa.Column('image_url', sa.String(length=100), nullable=False),
sa.Column('link_url', sa.String(length=100), nullable=False),
sa.Column('priority', sa.Integer(), nullable=True),
sa.Column('create_time', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('banner')
# ### end Alembic commands ###
"""empty message
Revision ID: 4738817cef26
Revises: 88b0d07a7f54
Create Date: 2020-06-27 13:50:51.943960
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4738817cef26'
down_revision = '88b0d07a7f54'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('image_url', sa.String(length=255), nullable=False))
op.add_column('banner', sa.Column('link_url', sa.String(length=255), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'link_url')
op.drop_column('banner', 'image_url')
# ### end Alembic commands ###
"""empty message
Revision ID: 48e7bfc163da
Revises: 101f06ec28fb
Create Date: 2020-06-27 09:32:35.903756
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '48e7bfc163da'
down_revision = '101f06ec28fb'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_foreign_key(None, 'cms_role_user', 'cms_user', ['cms_user_id'], ['id'])
op.create_foreign_key(None, 'cms_role_user', 'cms_role', ['cms_role_id'], ['id'])
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'cms_role_user', type_='foreignkey')
op.drop_constraint(None, 'cms_role_user', type_='foreignkey')
# ### end Alembic commands ###
"""empty message
Revision ID: 495dbcec29c8
Revises: 6a31d802985b
Create Date: 2020-06-27 18:07:17.650877
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '495dbcec29c8'
down_revision = '6a31d802985b'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', sa.Enum('DELETE', 'NOT_DELETE', name='deleteenum'), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
"""empty message
Revision ID: 6a31d802985b
Revises: c3fa96c8ba5e
Create Date: 2020-06-27 18:07:01.812105
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '6a31d802985b'
down_revision = 'c3fa96c8ba5e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', mysql.ENUM('DELETE', 'NOT_DELETE'), nullable=True))
# ### end Alembic commands ###
"""empty message
Revision ID: 7c0603064b34
Revises: 4738817cef26
Create Date: 2020-06-27 13:54:28.319985
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '7c0603064b34'
down_revision = '4738817cef26'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('banner')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('banner',
sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False),
sa.Column('name', mysql.VARCHAR(length=30), nullable=False),
sa.Column('priority', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
sa.Column('create_time', mysql.DATETIME(), nullable=True),
sa.Column('image_url', mysql.VARCHAR(length=255), nullable=False),
sa.Column('link_url', mysql.VARCHAR(length=255), nullable=False),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset='utf8',
mysql_engine='InnoDB'
)
# ### end Alembic commands ###
"""empty message
Revision ID: 88b0d07a7f54
Revises: 418954f97705
Create Date: 2020-06-27 13:50:29.644760
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '88b0d07a7f54'
down_revision = '418954f97705'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'link_url')
op.drop_column('banner', 'image_url')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('image_url', mysql.VARCHAR(length=100), nullable=False))
op.add_column('banner', sa.Column('link_url', mysql.VARCHAR(length=100), nullable=False))
# ### end Alembic commands ###
"""empty message
Revision ID: b18839d4793f
Revises: 23fa298b6e40
Create Date: 2020-06-27 18:52:09.838233
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'b18839d4793f'
down_revision = '23fa298b6e40'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
"""empty message
Revision ID: c1dfed7157ce
Revises: 48e7bfc163da
Create Date: 2020-06-27 09:36:17.992262
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'c1dfed7157ce'
down_revision = '48e7bfc163da'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('cms_role_user')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('cms_role_user',
sa.Column('cms_role_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False),
sa.Column('cms_user_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('cms_role_id', 'cms_user_id'),
mysql_default_charset='utf8',
mysql_engine='MyISAM'
)
# ### end Alembic commands ###
"""empty message
Revision ID: c3fa96c8ba5e
Revises: e66cdc55820a
Create Date: 2020-06-27 17:35:15.751809
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c3fa96c8ba5e'
down_revision = 'e66cdc55820a'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', sa.Enum('DELETE', 'NOT_DELETE', name='deleteenum'), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
"""empty message
Revision ID: dbdc069de73b
Revises: c1dfed7157ce
Create Date: 2020-06-27 09:37:49.379922
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'dbdc069de73b'
down_revision = 'c1dfed7157ce'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('cms_role_user',
sa.Column('cms_role_id', sa.Integer(), nullable=False),
sa.Column('cms_user_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['cms_role_id'], ['cms_role.id'], ),
sa.ForeignKeyConstraint(['cms_user_id'], ['cms_user.id'], ),
sa.PrimaryKeyConstraint('cms_role_id', 'cms_user_id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('cms_role_user')
# ### end Alembic commands ###
"""empty message
Revision ID: e66cdc55820a
Revises: 02bd2cd7181a
Create Date: 2020-06-27 17:34:59.139405
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'e66cdc55820a'
down_revision = '02bd2cd7181a'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('banner', 'is_delete')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('banner', sa.Column('is_delete', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
# ### end Alembic commands ###
...@@ -26,6 +26,7 @@ PyMySQL==0.9.3 ...@@ -26,6 +26,7 @@ PyMySQL==0.9.3
python-dateutil==2.8.1 python-dateutil==2.8.1
python-editor==1.0.4 python-editor==1.0.4
pytz==2020.1 pytz==2020.1
qiniu==7.2.8
redis==3.5.3 redis==3.5.3
requests==2.24.0 requests==2.24.0
shortuuid==1.0.1 shortuuid==1.0.1
......
var clajax = {
'get': function (args) {
args['method'] = 'get';
this.ajax(args);
},
'post': function (args) {
args['method'] = 'post';
this.ajax(args);
},
'ajax': function (args) {
// 设置csrftoken
this._ajaxSetup();
$.ajax(args);
},
'_ajaxSetup': function () {
$.ajaxSetup({
'beforeSend': function (xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
var csrftoken = $('meta[name=csrf-token]').attr('content');
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
}
});
}
};
$(function () {
$("#save-banner-btn").click(function (event) {
event.preventDefault();
var self = $(this);
var dialog = $("#banner-dialog");
var nameInput = $("input[name='name']");
var imageInput = $("input[name='image_url']");
var linkInput = $("input[name='link_url']");
var priorityInput = $("input[name='priority']");
var name = nameInput.val();
var image_url = imageInput.val();
var link_url = linkInput.val();
var priority = priorityInput.val();
var submitType = self.attr('data-type');
var bannerId = self.attr("data-id");
if (!name || !image_url || !link_url || !priority) {
clalert.alertInfoToast('请输入完整的轮播图数据!');
return;
}
var url = '';
if (submitType === 'update') {
url = '/cms/ubanner/';
} else {
url = '/cms/abanner/';
}
clajax.post({
"url": url,
'data': {
'name': name,
'image_url': image_url,
'link_url': link_url,
'priority': priority,
'banner_id': bannerId
},
'success': function (data) {
dialog.modal("hide");
if (data['code'] === 200) {
// 重新加载这个页面
window.location.reload();
} else {
clalert.alertInfo(data['message']);
}
},
'fail': function () {
clalert.alertNetworkError();
}
});
});
});
$(function () {
$(".edit-banner-btn").click(function (event) {
var self = $(this);
var dialog = $("#banner-dialog");
dialog.modal("show");
var tr = self.parent().parent();
var name = tr.attr("data-name");
var image_url = tr.attr("data-image");
var link_url = tr.attr("data-link");
var priority = tr.attr("data-priority");
var nameInput = dialog.find("input[name='name']");
var imageInput = dialog.find("input[name='image_url']");
var linkInput = dialog.find("input[name='link_url']");
var priorityInput = dialog.find("input[name='priority']");
var saveBtn = dialog.find("#save-banner-btn");
nameInput.val(name);
imageInput.val(image_url);
linkInput.val(link_url);
priorityInput.val(priority);
saveBtn.attr("data-type", 'update');
saveBtn.attr('data-id', tr.attr('data-id'));
});
});
$(function () {
$(".delete-banner-btn").click(function (event) {
var self = $(this);
var tr = self.parent().parent();
var banner_id = tr.attr('data-id');
clalert.alertConfirm({
"msg": "您确定要删除这个轮播图吗?",
'confirmCallback': function () {
clajax.post({
'url': '/cms/dbanner/',
'data': {
'banner_id': banner_id
},
'success': function (data) {
if (data['code'] === 200) {
window.location.reload();
} else {
clalert.alertInfo(data['message']);
}
}
})
}
});
});
});
$(function () {
clqiniu.setUp({
'domain': 'http://7xqenu.com1.z0.glb.clouddn.com/',
'browse_btn': 'upload-btn',
'uptoken_url': '/c/uptoken/',
'success': function (up, file, info) {
var imageInput = $("input[name='image_url']");
imageInput.val(file.name);
}
});
});
\ No newline at end of file
...@@ -35,6 +35,9 @@ $(function () { ...@@ -35,6 +35,9 @@ $(function () {
} else if (url.indexOf('posts') >= 0) { } else if (url.indexOf('posts') >= 0) {
var postManageLi = $('.post-manage'); var postManageLi = $('.post-manage');
postManageLi.addClass('unfold').siblings().removeClass('unfold'); postManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('banners') >= 0) {
var postManageLi = $('.banner-manage');
postManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('boards') >= 0) { } else if (url.indexOf('boards') >= 0) {
var boardManageLi = $('.board-manage'); var boardManageLi = $('.board-manage');
boardManageLi.addClass('unfold').siblings().removeClass('unfold'); boardManageLi.addClass('unfold').siblings().removeClass('unfold');
......
//'use strict';
var clqiniu = {
'setUp': function (args) {
var domain = args['domain'];
var params = {
browse_button: args['browse_btn'],
runtimes: 'html5,flash,html4', //上传模式,依次退化
max_file_size: '500mb', //文件最大允许的尺寸
dragdrop: false, //是否开启拖拽上传
chunk_size: '4mb', //分块上传时,每片的大小
uptoken_url: args['uptoken_url'], //ajax请求token的url
domain: domain, //图片下载时候的域名
get_new_uptoken: false, //是否每次上传文件都要从业务服务器获取token
auto_start: true, //如果设置了true,只要选择了图片,就会自动上传
unique_names: true,
multi_selection: false,
filters: {
mime_types: [
{title: 'Image files', extensions: 'jpg,gif,png'},
{title: 'Video files', extensions: 'flv,mpg,mpeg,avi,wmv,mov,asf,rm,rmvb,mkv,m4v,mp4'}
]
},
log_level: 5, //log级别
init: {
'FileUploaded': function (up, file, info) {
if (args['success']) {
var success = args['success'];
file.name = domain + file.target_name;
success(up, file, info);
}
},
'Error': function (up, err, errTip) {
if (args['error']) {
var error = args['error'];
error(up, err, errTip);
}
},
'UploadProgress': function (up, file) {
if (args['progress']) {
args['progress'](up, file);
}
},
'FilesAdded': function (up, files) {
if (args['fileadded']) {
args['fileadded'](up, files);
}
},
'UploadComplete': function () {
if (args['complete']) {
args['complete']();
}
}
}
};
// 把args中的参数放到params中去
for (var key in args) {
params[key] = args[key];
}
var uploader = Qiniu.uploader(params);
return uploader;
}
};
a, abbr, acronym, address, applet, article, aside, audio, b, big, blockquote, body, canvas, caption, center, cite, code, dd, del, details, dfn, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, header, html, i, iframe, img, ins, kbd, label, legend, li, mark, menu, nav, object, ol, output, p, pre, q, ruby, s, samp, section, small, span, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, time, tr, tt, u, ul, var, video {
margin: 0;
padding: 0;
border: 0;
vertical-align: baseline;
list-style: none;
}
.main-container {
width: 990px;
margin: 0 auto;
overflow: hidden;
}
.cl-container {
width: 730px;
float: left;
}
.sm-container {
width: 250px;
float: right;
}
\ No newline at end of file
.index-banner {
border-radius: 10px;
overflow: hidden;
height: 200px;
}
.index-banner img {
height: 200px;
}
.post-group {
border: 1px solid #ddd;
margin-top: 20px;
overflow: hidden;
border-radius: 5px;
padding: 10px;
}
.post-group-head {
overflow: hidden;
list-style: none;
}
.post-group-head li {
float: left;
padding: 5px 10px;
}
.post-group-head li a {
color: #333;
}
.post-group-head li.active {
background: #ccc;
}
.post-list-group {
margin-top: 20px;
}
.post-list-group li {
overflow: hidden;
padding-bottom: 20px;
}
.author-avatar-group {
float: left;
}
.author-avatar-group img {
width: 50px;
height: 50px;
border-radius: 50%;
}
.post-info-group {
float: left;
margin-left: 10px;
border-bottom: 1px solid #e6e6e6;
width: 85%;
padding-bottom: 10px;
}
.post-info-group .post-info {
margin-top: 10px;
font-size: 12px;
color: #8c8c8c;
}
.post-info span {
margin-right: 10px;
}
\ No newline at end of file
static/front/images/python-1.jpg

435.6 KB | W: | H:

static/front/images/python-1.jpg

374.5 KB | W: | H:

static/front/images/python-1.jpg
static/front/images/python-1.jpg
static/front/images/python-1.jpg
static/front/images/python-1.jpg
  • 2-up
  • Swipe
  • Onion skin
static/front/images/python-2.jpg

33.7 KB | W: | H:

static/front/images/python-2.jpg

48.6 KB | W: | H:

static/front/images/python-2.jpg
static/front/images/python-2.jpg
static/front/images/python-2.jpg
static/front/images/python-2.jpg
  • 2-up
  • Swipe
  • Onion skin
static/front/images/python-3.jpg

17.3 KB | W: | H:

static/front/images/python-3.jpg

37.0 KB | W: | H:

static/front/images/python-3.jpg
static/front/images/python-3.jpg
static/front/images/python-3.jpg
static/front/images/python-3.jpg
  • 2-up
  • Swipe
  • Onion skin
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛后台轮播图管理
{% endblock %}
{% block head %}
<script src="https://cdn.staticfile.org/Plupload/2.1.1/moxie.js"></script>
<script src="https://cdn.staticfile.org/Plupload/2.1.1/plupload.dev.js"></script>
<script src="https://cdn.staticfile.org/qiniu-js-sdk/1.0.14-beta/qiniu.js"></script>
<script src="{{ url_for('static', filename='common/clqiniu.js') }}"></script>
<script src="{{ url_for('static',filename='cms/js/banners.js') }}"></script>
<style>
.top-box button {
float: right;
}
</style>
{% endblock %}
{% block page_title %}
熊熊轮播图管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
<div class="top-box">
<button class="btn btn-warning" data-toggle="modal" data-target="#banner-dialog">添加轮播图</button>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>名称</th>
<th>图片链接</th>
<th>跳转链接</th>
<th>优先级</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for banner in banners %}
<tr data-name="{{ banner.name }}" data-image="{{ banner.image_url }}" data-link="{{ banner.link_url }}"
data-priority="{{ banner.priority }}" data-id="{{ banner.id }}">
<td>{{ banner.name}}</td>
<td><a href="{{ banner.image_url }}" target="_blank">{{ banner.image_url | truncate(45) }}</a></td>
<td><a href="{{ banner.link_url }}" target="_blank">{{ banner.link_url | truncate(35) }}</a></td>
<td>{{ banner.priority }}</td>
<td>{{ banner.create_time }}</td>
<td>
<button class="btn btn-default btn-xs edit-banner-btn">编辑</button>
<button class="btn btn-danger btn-xs delete-banner-btn">删除</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Modal -->
<div class="modal fade" id="banner-dialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="myModalLabel">轮播图</h4>
</div>
<div class="modal-body">
<form action="" class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">名称:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" placeholder="轮播图名称">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">图片:</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="image_url"
placeholder="轮播图图片">
</div>
<button class="btn btn-info col-sm-2" id="upload-btn">添加图片</button>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">跳转:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="link_url" placeholder="跳转链接">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">权重:</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="priority" placeholder="优先级">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="save-banner-btn">保存</button>
</div>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
...@@ -63,6 +63,9 @@ ...@@ -63,6 +63,9 @@
{% if user.has_permission(CMSPermission.POSTER) %} {% if user.has_permission(CMSPermission.POSTER) %}
<li class="nav-group post-manage"><a href="{{ url_for('cms.posts') }}">帖子管理</a></li> <li class="nav-group post-manage"><a href="{{ url_for('cms.posts') }}">帖子管理</a></li>
{% endif %} {% endif %}
{% if user.has_permission(CMSPermission.BANNER) %}
<li class="banner-manage"><a href="{{ url_for('cms.banners') }}">轮播图管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.COMMENTER) %} {% if user.has_permission(CMSPermission.COMMENTER) %}
<li class="comments-manage"><a href="{{ url_for('cms.comments') }}">评论管理</a></li> <li class="comments-manage"><a href="{{ url_for('cms.comments') }}">评论管理</a></li>
{% endif %} {% endif %}
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='front/css/front_base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='front/css/front_index.css') }}">
<title>{% block title %}{% endblock %}</title>
<title>{% block head %}{% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Python栏目</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="/">首页 <span class="sr-only">(current)</span></a></li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">搜索</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="{{ url_for('front.signin') }}">登录</a></li>
<li><a href="{{ url_for('front.signup') }}">注册</a></li>
{# <li class="dropdown">#}
{# <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"#}
{# aria-expanded="false">Dropdown <span class="caret"></span></a>#}
{# <ul class="dropdown-menu">#}
{# <li><a href="#">Action</a></li>#}
{# <li><a href="#">Another action</a></li>#}
{# <li><a href="#">Something else here</a></li>#}
{# <li role="separator" class="divider"></li>#}
{# <li><a href="#">Separated link</a></li>#}
{# </ul>#}
{# </li>#}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% block main_content %}
{% endblock %}
</body>
</html>
\ No newline at end of file
<!DOCTYPE html> {% extends 'front/front_base.html' %}
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<title>首页</title>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Python栏目</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling --> {% block title %}首页{% endblock %}
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="/">首页 <span class="sr-only">(current)</span></a></li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">搜索</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="{{ url_for('front.signin') }}">登录</a></li>
<li><a href="{{ url_for('front.signup') }}">注册</a></li>
{# <li class="dropdown">#}
{# <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"#}
{# aria-expanded="false">Dropdown <span class="caret"></span></a>#}
{# <ul class="dropdown-menu">#}
{# <li><a href="#">Action</a></li>#}
{# <li><a href="#">Another action</a></li>#}
{# <li><a href="#">Something else here</a></li>#}
{# <li role="separator" class="divider"></li>#}
{# <li><a href="#">Separated link</a></li>#}
{# </ul>#}
{# </li>#}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="main-container"> {% block main_content %}
<div class="cl-container"> <div class="main-container">
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel"> <div class="cl-container">
<!-- Indicators 指令 --> <div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators"> <!-- Indicators 指令 -->
<li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li> <ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="1"></li> <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li> <li data-target="#carousel-example-generic" data-slide-to="1"></li>
</ol> <li data-target="#carousel-example-generic" data-slide-to="2"></li>
</ol>
<!-- Wrapper for slides 轮播图 --> <!-- Wrapper for slides 轮播图 -->
<div class="carousel-inner" role="listbox"> <div class="carousel-inner" role="listbox">
<div class="item active"> <div class="item active">
<img src="{{ url_for('static', filename='front/images/python-1.jpg') }}" alt="..."> <img src="{{ url_for('static', filename='front/images/python-1.jpg') }}" alt="...">
<div class="carousel-caption"> <div class="carousel-caption">
... ...
</div>
</div> </div>
</div> <div class="item">
<div class="item"> <img src="{{ url_for('static', filename='front/images/python-2.jpg') }}" alt="...">
<img src="{{ url_for('static', filename='front/images/python-2.jpg') }}" alt="..."> <div class="carousel-caption">
<div class="carousel-caption"> ...
... </div>
</div> </div>
</div> <div class="item">
<div class="item"> <img src="{{ url_for('static', filename='front/images/python-3.jpg') }}" alt="...">
<img src="{{ url_for('static', filename='front/images/python-3.jpg') }}" alt="..."> <div class="carousel-caption">
<div class="carousel-caption"> ...
... </div>
</div> </div>
...
</div> </div>
...
</div>
<!-- Controls 左右切换控制 --> <!-- Controls 左右切换控制 -->
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev"> <a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span> <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span> <span class="sr-only">Previous</span>
</a> </a>
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next"> <a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span> <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span> <span class="sr-only">Next</span>
</a> </a>
</div>
</div> </div>
</div>
<div class="sm-container"> <div class="sm-container">
</div>
</div> </div>
</div> {% endblock %}
\ No newline at end of file
</body>
</html>
\ No newline at end of file
{"http:_PL7p4sTSlfAKl71hIkuG3F6y18681ZKkNJ3SRvh:corley-images": {"upHosts": ["http://up-z2.qiniu.com", "http://upload-z2.qiniu.com", "-H up-z2.qiniu.com http://14.152.58.16"], "ioHosts": ["http://iovip-z2.qbox.me"], "deadline": 1593345158}}
\ No newline at end of file
from qiniu import Auth, put_file, etag
from config import QN_AK, QN_SK
# 构建鉴权对象
q = Auth(QN_AK, QN_SK)
# 要上传的空间
bucket_name = 'corley-images'
# 上传后保存的文件名
key = 'logo.png'
# 生成上传 Token,可以指定过期时间等
token = q.upload_token(bucket_name, key, 3600)
# 要上传文件的本地路径
localfile = 'E:\Test\logo.gif'
ret, info = put_file(token, key, localfile)
print('ret :', ret)
print('info:', info)
assert ret['key'] == key
assert ret['hash'] == etag(localfile)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册