完善文档并添加示例插件
This commit is contained in:
@@ -72,7 +72,7 @@ class BaseConfig:
|
|||||||
MAIL_DEFAULT_SENDER = MAIL_USERNAME
|
MAIL_DEFAULT_SENDER = MAIL_USERNAME
|
||||||
|
|
||||||
# 插件配置,填写插件的文件名名称,默认不启用插件。
|
# 插件配置,填写插件的文件名名称,默认不启用插件。
|
||||||
PLUGIN_ENABLE_FOLDERS = []
|
PLUGIN_ENABLE_FOLDERS = ["giftManager"]
|
||||||
|
|
||||||
# Session 设置
|
# Session 设置
|
||||||
PERMANENT_SESSION_LIFETIME = timedelta(days=7)
|
PERMANENT_SESSION_LIFETIME = timedelta(days=7)
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -493,3 +493,8 @@
|
|||||||
return success_api(msg="编辑成功")
|
return success_api(msg="编辑成功")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return fail_api(msg="编辑失败")
|
return fail_api(msg="编辑失败")
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
插件方式接入项目,请查看 :ref:`以插件的方式接入项目` 章节。
|
||||||
|
|
||||||
|
|||||||
@@ -553,5 +553,7 @@ Pear Admin Layui 的控制主题色逻辑是通过设置全局的 css 属性:`
|
|||||||
对应的视图函数,可以查看 :ref:`编写修改视图函数` 章节。
|
对应的视图函数,可以查看 :ref:`编写修改视图函数` 章节。
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
插件方式接入项目,请查看 :ref:`以插件的方式接入项目` 章节。
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
插件功能旨在最大限度不修改原框架的前提下添加新功能,并可以像程序原有框架一样进行流程注册,而且不需要修改任何程序框架原有代码(仅在配置文件中设置即可)。
|
插件功能旨在最大限度不修改原框架的前提下添加新功能,并可以像程序原有框架一样进行流程注册,而且不需要修改任何程序框架原有代码(仅在配置文件中设置即可)。
|
||||||
|
|
||||||
所有插件放置在 `plugins` 文件夹中,项目提供了三个示例插件,分别是 `helloworld` 、 `realip` 和 `replacePage` ,分别用于示例页面的注册、修改 Flask 上下文和页面替换。
|
所有插件放置在 `plugins` 文件夹中,项目提供了三个示例插件,分别是 `helloworld` 、 `realip` 、 `replacePage` 和 `giftManager`,
|
||||||
|
分别用于示例页面的注册、修改 Flask 上下文、页面替换和新功能接入。
|
||||||
|
|
||||||
像项目自带的用户管理、部门管理等基本功能属于程序自身的“功能插件”,对于大多数衍生项目来说,多的是修改字符串和删除部分不需要的功能,
|
像项目自带的用户管理、部门管理等基本功能属于程序自身的“功能插件”,对于大多数衍生项目来说,多的是修改字符串和删除部分不需要的功能,
|
||||||
而插件开发主要可以用于添加自己的视图函数和功能,可以完美于项目融合,增加可拓展性,尤其是用于既想保留原项目功能又想填写新功能的项目开发。
|
而插件开发主要可以用于添加自己的视图函数和功能,可以完美于项目融合,增加可拓展性,尤其是用于既想保留原项目功能又想填写新功能的项目开发。
|
||||||
@@ -17,8 +18,8 @@
|
|||||||
|
|
||||||
PLUGIN_ENABLE_FOLDERS = []
|
PLUGIN_ENABLE_FOLDERS = []
|
||||||
|
|
||||||
而在目录 `plugins` 中,你会发现存在 文件夹名称 为 `helloworld` 、 `realip` 和 `replacePage` 三个插件。比如我们想要启用 `helloworld` 插件,
|
而在目录 `plugins` 中,你会发现存在 文件夹名称 为 `helloworld` 、 `realip` 、 `replacePage` 和 `giftManager` 三个插件。
|
||||||
仅需要做如下修改:
|
比如我们想要启用 `helloworld` 插件,仅需要做如下修改:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@@ -48,6 +49,18 @@
|
|||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
对于 `giftManager` 插件,需要在启用的情况下,先使用 `flask gift init` 来初始化其数据库。假设项目已经搭建完成(已经初始化数据库),需要进行以下步骤:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
flask db migrate
|
||||||
|
flask db upgrade
|
||||||
|
flask gift init
|
||||||
|
|
||||||
|
该命令行用于创建新 admin_gift 表并写入数据。
|
||||||
|
|
||||||
插件的目录架构
|
插件的目录架构
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
@@ -150,3 +163,215 @@
|
|||||||
当然另一种做法是像 helloworld 插件那样,直接放在插件目录的 templates 中,但是一定要做好模板名称的区分,
|
当然另一种做法是像 helloworld 插件那样,直接放在插件目录的 templates 中,但是一定要做好模板名称的区分,
|
||||||
因为 flask 默认找模板行为是从根目录开始找的,如果根目录 templates 和插件目录的 templates 中存在的模板重名,
|
因为 flask 默认找模板行为是从根目录开始找的,如果根目录 templates 和插件目录的 templates 中存在的模板重名,
|
||||||
则会优先使用根目录 templates 的模板文件。
|
则会优先使用根目录 templates 的模板文件。
|
||||||
|
|
||||||
|
.. _以插件的方式接入项目:
|
||||||
|
|
||||||
|
以插件的方式接入项目
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
在 :ref:`简单前端页面示例` 和 :ref:`后端页面编写` 章节中,我们编写了新的管理页面。接下来,我们将其改为插件接入,获得更高的拓展性。
|
||||||
|
|
||||||
|
首先在 `plugins` 新建一个名为 `giftManager` 的文件夹,将兑换码管理页面相关的功能一五一十的照搬到这个文件夹中。
|
||||||
|
|
||||||
|
我们可以规划如下的目录架构:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
|
.. image:: ../_static/插件目录规划.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
|
入口文件
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
入口文件相对简单,
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
from .cli import gift_cli
|
||||||
|
from .view.gift import bp
|
||||||
|
|
||||||
|
|
||||||
|
def event_init(app: Flask):
|
||||||
|
app.register_blueprint(bp)
|
||||||
|
|
||||||
|
|
||||||
|
def event_finish(app: Flask):
|
||||||
|
app.cli.add_command(gift_cli)
|
||||||
|
|
||||||
|
在 `event_init` 事件中注册相关蓝图(页面),在 `event_finish` 中,注册了初始化数据库的命令。
|
||||||
|
|
||||||
|
注册初始化数据库命令
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
一个合理的设想是,我已经搭建了 Pear Admin Flask 原项目,而之后我想要加入新的功能,新功能中存在添加权限管理等数据库的操作,
|
||||||
|
所以我们想使用其他的初始化命令,来新增数据库记录行。
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from flask.cli import AppGroup
|
||||||
|
|
||||||
|
from ..models import Gift
|
||||||
|
from applications.models import Power
|
||||||
|
from applications.extensions import db
|
||||||
|
|
||||||
|
gift_cli = AppGroup("gift")
|
||||||
|
|
||||||
|
now_time = datetime.datetime.now()
|
||||||
|
|
||||||
|
powerdata = [
|
||||||
|
Power(
|
||||||
|
name='兑换码添加',
|
||||||
|
type='2',
|
||||||
|
code='system:gift:add',
|
||||||
|
url='',
|
||||||
|
open_type='',
|
||||||
|
parent_id='60',
|
||||||
|
icon='',
|
||||||
|
sort=0,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
), Power(
|
||||||
|
name='兑换码删除',
|
||||||
|
type='2',
|
||||||
|
code='system:gift:remove',
|
||||||
|
url='',
|
||||||
|
open_type='',
|
||||||
|
parent_id='60',
|
||||||
|
icon='',
|
||||||
|
sort=0,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
), Power(
|
||||||
|
name='兑换码编辑',
|
||||||
|
type='2',
|
||||||
|
code='system:gift:edit',
|
||||||
|
url='',
|
||||||
|
open_type='',
|
||||||
|
parent_id='60',
|
||||||
|
icon='',
|
||||||
|
sort=0,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
giftdata = [
|
||||||
|
Gift(
|
||||||
|
id=0,
|
||||||
|
key='myTestCode',
|
||||||
|
content='8折优惠',
|
||||||
|
enable=1,
|
||||||
|
used=0,
|
||||||
|
create_at=now_time
|
||||||
|
),
|
||||||
|
Gift(
|
||||||
|
id=1,
|
||||||
|
key='DisableCode',
|
||||||
|
content='1折优惠',
|
||||||
|
enable=0,
|
||||||
|
used=0,
|
||||||
|
create_at=now_time
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@gift_cli.command("init")
|
||||||
|
def init_db():
|
||||||
|
print("存入兑换码管理页面数据")
|
||||||
|
|
||||||
|
top_power = Power(
|
||||||
|
name='兑换码管理',
|
||||||
|
type='1',
|
||||||
|
code='system:gift:main',
|
||||||
|
url='/system/gift/',
|
||||||
|
open_type='_iframe',
|
||||||
|
parent_id='1',
|
||||||
|
icon='layui-icon layui-icon layui-icon layui-icon-diamond',
|
||||||
|
sort=8,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
)
|
||||||
|
|
||||||
|
db.session.add(top_power)
|
||||||
|
db.session.commit() # 提交了才有 id
|
||||||
|
|
||||||
|
for i in range(len(powerdata)):
|
||||||
|
powerdata[i].parent_id = top_power.id
|
||||||
|
|
||||||
|
db.session.add_all(powerdata)
|
||||||
|
|
||||||
|
db.session.add_all(giftdata)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
上述代码中,主要说明一下 `top_power` 的做法,由于兑换码管理需要新的菜单(权限),但是新的菜单在添加之前可能已经存在了其他菜单,
|
||||||
|
我们并不知道新菜单的 ID 是什么,所以需要让主菜单(top_power)先添加,并获取到其 ID 而后才可以把子菜单添加进去。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
|
.. image:: ../_static/添加菜单.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
要获取添加菜单的 ID 必须先 commit 一次数据库。
|
||||||
|
|
||||||
|
随后我们可以使用 `flask gift init` 来初始化兑换码管理的数据库数据。
|
||||||
|
|
||||||
|
注册蓝图
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
注册蓝图部分和设计一般前端页面差不多,只不过要注意正确把模板文件夹的路径提供给蓝图进行初始化。
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from flask import Blueprint, request, render_template
|
||||||
|
|
||||||
|
from ..models import Gift
|
||||||
|
from ..schemas import GiftSchema
|
||||||
|
from applications.extensions import db
|
||||||
|
|
||||||
|
from applications.common.helper import ModelFilter
|
||||||
|
from applications.common.curd import enable_status, disable_status, delete_one_by_id, get_one_by_id
|
||||||
|
from applications.common.utils.http import table_api, success_api, fail_api
|
||||||
|
from applications.common.utils.rights import authorize
|
||||||
|
|
||||||
|
# 获取插件所在的目录(结尾没有分割符号)
|
||||||
|
dir_path = os.path.dirname(__file__).replace("\\", "/")
|
||||||
|
|
||||||
|
bp = Blueprint('gift', __name__, url_prefix='/system/gift',
|
||||||
|
template_folder=dir_path + '/../templates')
|
||||||
|
|
||||||
|
上述代码中,获取了 `dir_path` 并指定了上一级目录的 `templates` 为该蓝图的模板文件夹。另外,对于 `url_prefix` ,在统一规划下,
|
||||||
|
我们建议将 gift 路由放在 `system` 下,在 :ref:`后端页面编写` 中,我们似乎并没有指定 `system` 这是因为当时注册蓝图的时候是在 system_bp 的蓝图中注册的:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
system_bp = Blueprint('system', __name__, url_prefix='/system') # 但是是在这个蓝图下注册的
|
||||||
|
|
||||||
|
|
||||||
|
def register_system_bps(app: Flask):
|
||||||
|
...
|
||||||
|
system_bp.register_blueprint(gift_bp)
|
||||||
|
app.register_blueprint(index_bp)
|
||||||
|
app.register_blueprint(system_bp)
|
||||||
|
|
||||||
|
我们不能通过正常方法拿到 system_bp 就只能使用指定路由在 `system` 下了,唯一的缺点就是不能使用 “system.gift.\*” 来指定路由中的函数,而是要使用 “gift.\*” .
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
from flask import Flask, url_for
|
||||||
|
|
||||||
|
url_for("system.gift.index") # 不能这样写
|
||||||
|
url_for("gift.index") # 要这样写
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
from .cli import gift_cli
|
||||||
|
from .view.gift import bp
|
||||||
|
|
||||||
|
|
||||||
|
def event_init(app: Flask):
|
||||||
|
app.register_blueprint(bp)
|
||||||
|
|
||||||
|
|
||||||
|
def event_finish(app: Flask):
|
||||||
|
app.cli.add_command(gift_cli)
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
|
from flask.cli import AppGroup
|
||||||
|
|
||||||
|
from ..models import Gift
|
||||||
|
from applications.models import Power
|
||||||
|
from applications.extensions import db
|
||||||
|
|
||||||
|
gift_cli = AppGroup("gift")
|
||||||
|
|
||||||
|
now_time = datetime.datetime.now()
|
||||||
|
|
||||||
|
powerdata = [
|
||||||
|
Power(
|
||||||
|
name='兑换码添加',
|
||||||
|
type='2',
|
||||||
|
code='system:gift:add',
|
||||||
|
url='',
|
||||||
|
open_type='',
|
||||||
|
parent_id='60',
|
||||||
|
icon='',
|
||||||
|
sort=0,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
), Power(
|
||||||
|
name='兑换码删除',
|
||||||
|
type='2',
|
||||||
|
code='system:gift:remove',
|
||||||
|
url='',
|
||||||
|
open_type='',
|
||||||
|
parent_id='60',
|
||||||
|
icon='',
|
||||||
|
sort=0,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
), Power(
|
||||||
|
name='兑换码编辑',
|
||||||
|
type='2',
|
||||||
|
code='system:gift:edit',
|
||||||
|
url='',
|
||||||
|
open_type='',
|
||||||
|
parent_id='60',
|
||||||
|
icon='',
|
||||||
|
sort=0,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
giftdata = [
|
||||||
|
Gift(
|
||||||
|
id=0,
|
||||||
|
key='myTestCode',
|
||||||
|
content='8折优惠',
|
||||||
|
enable=1,
|
||||||
|
used=0,
|
||||||
|
create_at=now_time
|
||||||
|
),
|
||||||
|
Gift(
|
||||||
|
id=1,
|
||||||
|
key='DisableCode',
|
||||||
|
content='1折优惠',
|
||||||
|
enable=0,
|
||||||
|
used=0,
|
||||||
|
create_at=now_time
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@gift_cli.command("init")
|
||||||
|
def init_db():
|
||||||
|
print("存入兑换码管理页面数据")
|
||||||
|
|
||||||
|
top_power = Power(
|
||||||
|
name='兑换码管理',
|
||||||
|
type='1',
|
||||||
|
code='system:gift:main',
|
||||||
|
url='/system/gift/',
|
||||||
|
open_type='_iframe',
|
||||||
|
parent_id='1',
|
||||||
|
icon='layui-icon layui-icon layui-icon layui-icon-diamond',
|
||||||
|
sort=8,
|
||||||
|
create_time=now_time,
|
||||||
|
enable=1
|
||||||
|
)
|
||||||
|
|
||||||
|
db.session.add(top_power)
|
||||||
|
db.session.commit() # 提交了才有 id
|
||||||
|
|
||||||
|
for i in range(len(powerdata)):
|
||||||
|
powerdata[i].parent_id = top_power.id
|
||||||
|
|
||||||
|
db.session.add_all(powerdata)
|
||||||
|
|
||||||
|
db.session.add_all(giftdata)
|
||||||
|
db.session.commit()
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import datetime
|
||||||
|
from applications.extensions import db
|
||||||
|
|
||||||
|
|
||||||
|
class Gift(db.Model):
|
||||||
|
__tablename__ = 'admin_gift'
|
||||||
|
id = db.Column(db.Integer, primary_key=True, comment="唯一ID")
|
||||||
|
key = db.Column(db.String(50), comment="兑换码")
|
||||||
|
content = db.Column(db.String(), comment="具体内容")
|
||||||
|
enable = db.Column(db.Integer, default=0, comment='是否启用')
|
||||||
|
used = db.Column(db.Integer, default=0, comment='是否已经使用')
|
||||||
|
create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间')
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from flask_marshmallow.sqla import SQLAlchemyAutoSchema
|
||||||
|
|
||||||
|
from ..models import Gift
|
||||||
|
|
||||||
|
|
||||||
|
class GiftSchema(SQLAlchemyAutoSchema):
|
||||||
|
class Meta:
|
||||||
|
model = Gift # table = models.Album.__table__
|
||||||
|
# include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理
|
||||||
|
include_fk = True # 序列化阶段是否也一并返回主键
|
||||||
|
# fields= ["id","name"] # 启动的字段列表
|
||||||
|
# exclude = ["id","name"] # 排除字段列表
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>兑换码添加</title>
|
||||||
|
{% include 'system/common/header.html' %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form class="layui-form">
|
||||||
|
<div class="mainBox">
|
||||||
|
<div class="main-container">
|
||||||
|
<div class="main-container">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">兑换码</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="text" name="key" lay-verify="title" autocomplete="off" placeholder="请输入兑换码"
|
||||||
|
class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">兑换内容</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<textarea placeholder="请输入兑换内容" name="content" class="layui-textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">状态</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="radio" name="enable" value="1" title="开启" checked>
|
||||||
|
<input type="radio" name="enable" value="0" title="关闭">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="button-container">
|
||||||
|
<button type="submit" class="layui-btn layui-btn-sm" lay-submit="" lay-filter="save">
|
||||||
|
<i class="layui-icon layui-icon-ok"></i>
|
||||||
|
提交
|
||||||
|
</button>
|
||||||
|
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">
|
||||||
|
<i class="layui-icon layui-icon-refresh"></i>
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% include 'system/common/footer.html' %}
|
||||||
|
<script>
|
||||||
|
layui.use(['form', 'jquery'], function () {
|
||||||
|
let form = layui.form
|
||||||
|
let $ = layui.jquery
|
||||||
|
|
||||||
|
form.on('submit(save)', function (data) {
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/system/gift/save',
|
||||||
|
data: JSON.stringify(data.field),
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'post',
|
||||||
|
success: function (result) {
|
||||||
|
if (result.success) {
|
||||||
|
layer.msg(result.msg, {icon: 1, time: 1000}, function () {
|
||||||
|
parent.layer.close(parent.layer.getFrameIndex(window.name)) //关闭当前页
|
||||||
|
parent.layui.table.reload('gift-table') // 目标表格
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
layer.msg(result.msg, {icon: 2, time: 1000})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>兑换码编辑</title>
|
||||||
|
{% include 'system/common/header.html' %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form class="layui-form">
|
||||||
|
<div class="mainBox">
|
||||||
|
<div class="main-container">
|
||||||
|
<div class="main-container">
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">编号</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="text" name="id" lay-verify="title" autocomplete="off" placeholder="请输入编号"
|
||||||
|
class="layui-input" value="{{ gift.id }}" disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">兑换码</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="text" name="key" lay-verify="title" autocomplete="off" placeholder="请输入兑换码"
|
||||||
|
class="layui-input" value="{{ gift.key }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">兑换内容</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<textarea placeholder="请输入兑换内容" name="content" class="layui-textarea">{{ gift.content }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">状态</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="radio" name="enable" value="1" title="开启" {{ 'checked' if gift.enable == 1 }}>
|
||||||
|
<input type="radio" name="enable" value="0" title="关闭" {{ 'checked' if gift.enable == 0 }}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="button-container">
|
||||||
|
<button type="submit" class="layui-btn layui-btn-sm" lay-submit="" lay-filter="save">
|
||||||
|
<i class="layui-icon layui-icon-ok"></i>
|
||||||
|
提交
|
||||||
|
</button>
|
||||||
|
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">
|
||||||
|
<i class="layui-icon layui-icon-refresh"></i>
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% include 'system/common/footer.html' %}
|
||||||
|
<script>
|
||||||
|
layui.use(['form', 'jquery'], function () {
|
||||||
|
let form = layui.form
|
||||||
|
let $ = layui.jquery
|
||||||
|
|
||||||
|
form.on('submit(save)', function (data) {
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/system/gift/update',
|
||||||
|
data: JSON.stringify(data.field),
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'post',
|
||||||
|
success: function (result) {
|
||||||
|
if (result.success) {
|
||||||
|
layer.msg(result.msg, {icon: 1, time: 1000}, function () {
|
||||||
|
parent.layer.close(parent.layer.getFrameIndex(window.name)) //关闭当前页
|
||||||
|
parent.layui.table.reload('gift-table') // 目标表格
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
layer.msg(result.msg, {icon: 2, time: 1000})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>兑换码管理</title>
|
||||||
|
{% include 'system/common/header.html' %}
|
||||||
|
</head>
|
||||||
|
<body class="pear-container">
|
||||||
|
|
||||||
|
{# 查询表单 #}
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<form class="layui-form" action="" lay-filter="query-form">
|
||||||
|
<div class="layui-form-item" style="margin-bottom: unset;">
|
||||||
|
<label class="layui-form-label">激活码</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="key" placeholder="" class="layui-input">
|
||||||
|
</div>
|
||||||
|
<button class="layui-btn layui-btn-md" lay-submit lay-filter="gift-query">
|
||||||
|
<i class="layui-icon layui-icon-search"></i>
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
<button type="reset" class="layui-btn layui-btn-primary layui-btn-md">
|
||||||
|
<i class="layui-icon layui-icon-refresh"></i>
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# 用户表格 #}
|
||||||
|
<div>
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<table id="gift-table" lay-filter="gift-table"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<!-- 这里写的都是表格一行元素组件 -->
|
||||||
|
{% raw %}
|
||||||
|
<script type="text/html" id="enable-element">
|
||||||
|
<input type="checkbox" name="enable" value="{{ d.id }}" lay-skin="switch" lay-text="启用|禁用"
|
||||||
|
lay-filter="gift-enable"
|
||||||
|
{{# if(d.enable==1){ }} checked {{# } }}/>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" id="used-element">
|
||||||
|
{{# if(d.used==1){ }}
|
||||||
|
<span style="color: red">已用</span>
|
||||||
|
{{# } else { }}
|
||||||
|
<span style="color: green">未用</span>
|
||||||
|
{{# } }}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" id="createTime-element">
|
||||||
|
{{layui.util.toDateString(d.create_at, "yyyy-MM-dd HH:mm:ss")}}
|
||||||
|
</script>
|
||||||
|
{% endraw %}
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/html" id="table-bar">
|
||||||
|
{% if authorize("system:gift:edit") %}
|
||||||
|
<button class="layui-btn layui-btn-xs" lay-event="edit"><i class="pear-icon pear-icon-edit"> 编辑</i>
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
{% if authorize("system:gift:remove") %}
|
||||||
|
<button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="remove"><i
|
||||||
|
class="pear-icon pear-icon-ashbin"> 删除</i>
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 这里是表格的工具栏 -->
|
||||||
|
<script type="text/html" id="table-toolbar">
|
||||||
|
{% if authorize("system:gift:add") %}
|
||||||
|
<button class="layui-btn layui-btn-primary layui-btn-sm" lay-event="add">
|
||||||
|
<i class="pear-icon pear-icon-add"></i>
|
||||||
|
新增
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
{% include 'system/common/footer.html' %}
|
||||||
|
<script>
|
||||||
|
layui.use(['table', 'form', 'popup'], function () {
|
||||||
|
let $ = layui.jquery;
|
||||||
|
let table = layui.table;
|
||||||
|
let form = layui.form;
|
||||||
|
let popup = layui.popup;
|
||||||
|
|
||||||
|
// 表格数据
|
||||||
|
let cols = [
|
||||||
|
[
|
||||||
|
{title: '编号', field: 'id', align: 'center'},
|
||||||
|
{title: '激活码', field: 'key', align: 'center'},
|
||||||
|
{title: '内容', field: 'content', align: 'center'},
|
||||||
|
{title: '启用', field: 'enable', align: 'center', templet: '#enable-element'},
|
||||||
|
{title: '已用', field: 'used', align: 'center', templet: '#used-element'},
|
||||||
|
{title: '创建时间', field: 'create_at', templet: '#createTime-element', align: 'center'},
|
||||||
|
{title: '操作', toolbar: '#table-bar', align: 'center', width: 180}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
// 渲染表格数据
|
||||||
|
table.render({
|
||||||
|
elem: '#gift-table',
|
||||||
|
url: '/system/gift/data', // 请求链接
|
||||||
|
page: true,
|
||||||
|
cols: cols,
|
||||||
|
skin: 'line',
|
||||||
|
toolbar: '#table-toolbar',
|
||||||
|
text: {none: '暂无激活码信息'},
|
||||||
|
defaultToolbar: [{layEvent: 'refresh', icon: 'layui-icon-refresh'}, 'filter', 'print', 'exports']
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 表单查询
|
||||||
|
form.on('submit(gift-query)', function (data) {
|
||||||
|
table.reload('gift-table', {where: data.field});
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
// 启用与禁用
|
||||||
|
form.on('switch(gift-enable)', function (obj) {
|
||||||
|
let operate;
|
||||||
|
if (obj.elem.checked) {
|
||||||
|
operate = 'enable'
|
||||||
|
} else {
|
||||||
|
operate = 'disable'
|
||||||
|
}
|
||||||
|
let loading = layer.load()
|
||||||
|
$.ajax({
|
||||||
|
url: '/system/gift/' + operate,
|
||||||
|
data: JSON.stringify({id: this.value}),
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'put',
|
||||||
|
success: function (result) {
|
||||||
|
layer.close(loading)
|
||||||
|
if (result.success) {
|
||||||
|
popup.success(result.msg)
|
||||||
|
} else {
|
||||||
|
popup.failure(result.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表格各行工具事件
|
||||||
|
table.on('tool(gift-table)', function (obj) {
|
||||||
|
if (obj.event === 'remove') {
|
||||||
|
|
||||||
|
layer.confirm('确定要删除该兑换码?', {icon: 3, title: '提示'}, function (index) {
|
||||||
|
layer.close(index)
|
||||||
|
let loading = layer.load()
|
||||||
|
$.ajax({
|
||||||
|
url: '/system/gift/remove/' + obj.data['id'],
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'delete',
|
||||||
|
success: function (result) {
|
||||||
|
layer.close(loading)
|
||||||
|
if (result.success) {
|
||||||
|
popup.success(result.msg, function () {
|
||||||
|
obj.del()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
popup.failure(result.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
} else if (obj.event === 'edit') {
|
||||||
|
|
||||||
|
layer.open({
|
||||||
|
type: 2,
|
||||||
|
title: '修改',
|
||||||
|
shade: 0.1,
|
||||||
|
area: ['550px', '500px'],
|
||||||
|
content: '/system/gift/edit/' + obj.data['id']
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 顶部工具栏
|
||||||
|
table.on('toolbar(gift-table)', function (obj) {
|
||||||
|
if (obj.event === 'add') {
|
||||||
|
layer.open({
|
||||||
|
type: 2,
|
||||||
|
title: '新增',
|
||||||
|
shade: 0.1,
|
||||||
|
area: ['550px', '550px'],
|
||||||
|
content: '/system/gift/add'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from flask import Blueprint, request, render_template
|
||||||
|
|
||||||
|
from ..models import Gift
|
||||||
|
from ..schemas import GiftSchema
|
||||||
|
from applications.extensions import db
|
||||||
|
|
||||||
|
from applications.common.helper import ModelFilter
|
||||||
|
from applications.common.curd import enable_status, disable_status, delete_one_by_id, get_one_by_id
|
||||||
|
from applications.common.utils.http import table_api, success_api, fail_api
|
||||||
|
from applications.common.utils.rights import authorize
|
||||||
|
|
||||||
|
# 获取插件所在的目录(结尾没有分割符号)
|
||||||
|
dir_path = os.path.dirname(__file__).replace("\\", "/")
|
||||||
|
|
||||||
|
bp = Blueprint('gift', __name__, url_prefix='/system/gift',
|
||||||
|
template_folder=dir_path + '/../templates')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.get('/')
|
||||||
|
@authorize("system:gift:main")
|
||||||
|
def index():
|
||||||
|
return render_template('system/gift/main.html')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.get('/add')
|
||||||
|
@authorize("system:gift:main")
|
||||||
|
def add():
|
||||||
|
return render_template('system/gift/add.html')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.get('/data')
|
||||||
|
@authorize("system:gift:main")
|
||||||
|
def data():
|
||||||
|
key = request.args.get('key', type=str)
|
||||||
|
|
||||||
|
mf = ModelFilter()
|
||||||
|
if key:
|
||||||
|
mf.vague('key', key) # 模糊查询
|
||||||
|
|
||||||
|
data, total, page, limit = db.session.query(Gift).filter(mf.get_filter(Gift)).layui_paginate_json(GiftSchema)
|
||||||
|
|
||||||
|
return table_api(
|
||||||
|
data=data,
|
||||||
|
count=total,
|
||||||
|
limit=limit
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.put('/enable')
|
||||||
|
@authorize("system:gift:edit")
|
||||||
|
def enable_api():
|
||||||
|
data = request.get_json(force=True)
|
||||||
|
|
||||||
|
if enable_status(Gift, data.get('id')):
|
||||||
|
return success_api(msg="启用成功")
|
||||||
|
|
||||||
|
return success_api(msg="启用失败")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.put('/disable')
|
||||||
|
@authorize("system:gift:edit")
|
||||||
|
def disable_api():
|
||||||
|
req_json = request.get_json(force=True)
|
||||||
|
|
||||||
|
if disable_status(Gift, req_json.get('id')):
|
||||||
|
return success_api(msg="禁用成功")
|
||||||
|
|
||||||
|
return success_api(msg="禁用失败")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.delete('/remove/<int:_id>')
|
||||||
|
@authorize("system:gift:remove")
|
||||||
|
def remove_api(_id):
|
||||||
|
if delete_one_by_id(Gift, _id):
|
||||||
|
return success_api(msg="删除成功")
|
||||||
|
|
||||||
|
return success_api(msg="删除失败")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.post('/save')
|
||||||
|
@authorize("system:gift:add", log=True)
|
||||||
|
def save():
|
||||||
|
req_json = request.get_json(force=True)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'key': req_json.get('key'),
|
||||||
|
'content': req_json.get('content'),
|
||||||
|
'enable': req_json.get('enable'),
|
||||||
|
'used': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 效验参数
|
||||||
|
if not all(list(data.keys())):
|
||||||
|
return fail_api(msg="参数不全")
|
||||||
|
|
||||||
|
if not data['enable'].isdigit():
|
||||||
|
return fail_api(msg="参数 enable 错误")
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.add(Gift(**data))
|
||||||
|
db.session.commit()
|
||||||
|
return success_api(msg="添加成功")
|
||||||
|
except Exception as e:
|
||||||
|
return fail_api(msg="添加失败")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.get('/edit/<int:_id>')
|
||||||
|
@authorize("system:gift:edit", log=True)
|
||||||
|
def edit(_id):
|
||||||
|
gift = get_one_by_id(Gift, _id)
|
||||||
|
return render_template('system/gift/edit.html', gift=gift)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.post('/update')
|
||||||
|
@authorize("system:gift:edit", log=True)
|
||||||
|
def update():
|
||||||
|
req_json = request.get_json(force=True)
|
||||||
|
|
||||||
|
_id = req_json.get('id')
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'key': req_json.get('key'),
|
||||||
|
'content': req_json.get('content'),
|
||||||
|
'enable': req_json.get('enable'),
|
||||||
|
'used': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 效验参数
|
||||||
|
if not all(list(data.keys())):
|
||||||
|
return fail_api(msg="参数不全")
|
||||||
|
|
||||||
|
if not data['enable'].isdigit():
|
||||||
|
return fail_api(msg="参数 enable 错误")
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.query(Gift).filter(Gift.id == _id).update(data)
|
||||||
|
db.session.commit()
|
||||||
|
return success_api(msg="编辑成功")
|
||||||
|
except Exception as e:
|
||||||
|
return fail_api(msg="编辑失败")
|
||||||
Reference in New Issue
Block a user