Flask項目實戰——3—(ajax實現修改密碼功能、restful定義項目規範、彈窗顯示信息功能)

1、ajax實現修改密碼

在之前的個人中心界面渲染綁定之後,就可以綁定用戶修改密碼的界面了,需要添加模板文件:
修改密碼文件templates/cms/cms_resetpwd.html

<!--  繼承模板文件cms/cms_base.html  簡化代碼 -->
{% extends 'cms/cms_base.html' %}

<!-- 頁面標題 -->
{% block title %}
    修改密碼
{% endblock %}

<!--  標題  -->
{% block page_title %}
    {{self.title()}}
{% endblock %}

<!--  寫修改密碼的form表單格式  -->
{% block head %}
<style>
    .form-container{
        width:300px;
    }
</style>

<!--  關聯本地的resetpwd.js樣式 -->
<script src="{{ url_for('static', filename='cms/js/resetpwd.js') }}"></script>

{% endblock %}

<!-- 只有form表單信息不一樣 -->
{% block content %}
    <form action="" method="post">
        <!--   這裏的csrf驗證信息在cms_base.html的頭文件中已經添加了     -->
        <div class="form-container">
            <div class="form-group">
                <div class="input-group">
                    <span class="input-group-addon">舊密碼</span>
                    <input type="password" class="form-control" name="oldpwd" placeholder="請輸入舊密碼">
                </div>
            </div>
            <div class="form-group">
                <div class="input-group">
                    <span class="input-group-addon">新密碼</span>
                    <input type="password" class="form-control" name="newpwd" placeholder="請輸入新密碼">
                </div>
            </div>
            <div class="form-group">
                <div class="input-group">
                    <span class="input-group-addon">確認新密碼</span>
                    <input type="password" class="form-control" name="newpwd2" placeholder="請輸入確認密碼">
                </div>
            </div>
            <div class="form-group">
                <button class="btn btn-primary" id="submit">立即保存</button>
            </div>
        </div>
    </form>
{% endblock %}

ajax:局部刷新,網頁中的局部信息更新。
綁定修改密碼的提交submit按鈕,使用ajax來實現頁面的局部刷新

創建新靜態文件:static/cms/js/resetpwd.js


$(function () {
    // #綁定submit按鈕
    $("#submit").click(function (event) {
        // event.preventDefault
        // 是阻止按鈕默認的提交表單的事件
        event.preventDefault();

        // 獲取input表單中的值
        var oldpwdE = $("input[name=oldpwd]");
        var newpwdE = $("input[name=newpwd]");
        var newpwd2E = $("input[name=newpwd2]");

        var oldpwd = oldpwdE.val();
        var newpwd = newpwdE.val();
        var newpwd2 = newpwd2E.val();

        // 1. 要在模版的meta標籤中渲染一個csrf-token
        // 2. 在ajax請求的頭部中設置X-CSRFtoken
        var lgajax = {
            '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方法
                    'beforeSend':function(xhr,settings) {
                        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {

                            // 請求之前發送csrf信息   將csrf信息name=csrf-token和content傳遞給cms_base.html頭文件
                            var csrftoken = $('meta[name=csrf-token]').attr('content');
                            // var csrftoken = $('input[name=csrf-token]').attr('value');
                            xhr.setRequestHeader("X-CSRFToken", csrftoken)
                        }
                    }
                });
            }
        };

        // 表單提交方法:post提交
        lgajax.post({
            'url': '/cms/resetpwd/',      // 表單發送地址
            'data': {                     // 表單發送數據
                'oldpwd': oldpwd,
                'newpwd': newpwd,
                'newpwd2': newpwd2
            },
            'success': function (data) {     // 表單提交成功
                console.log(data);
            },
            'fail': function (error) {       // 表單提交失敗
                console.log(error);
            }
        });
    });
});

修改表單提交文件:cms/forms.py文件

# -*- encoding: utf-8 -*-
"""
@File    : forms.py
@Time    : 2020/5/11 10:00
@Author  : chen

"""
# forms表單信息
from wtforms import Form, StringField, IntegerField
from wtforms.validators import Email, InputRequired, Length, EqualTo  # EqualTo驗證新密碼是否相同


# 登錄頁面中的Form表單
class LoginForm(Form):
    email = StringField(validators=[Email(message="請輸入正確的郵箱"),  InputRequired(message="請輸入郵箱")])
    password = StringField(validators=[Length(3, 15, message='請輸入正確長度的密碼')])
    remember = IntegerField()                # 記住cookie操作  賦值爲0或1


# 修改密碼頁面中的form表單信息
class ResetPwdForm(Form):
    oldpwd = StringField(validators=[Length(3,15, message="密碼長度有誤")])
    newpwd = StringField(validators=[Length(3,15, message="密碼長度有誤")])
    newpwd2 = StringField(validators=[EqualTo("newpwd", message="兩次輸入密碼不一致")])
    

視圖文件views.py

# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 藍圖文件:實現模塊化應用,應用可以分解成一系列的藍圖   後端的類視圖函數寫在這個文件
from flask import (
    request, redirect, url_for,                  # 頁面跳轉redirect   request請求收集
    Blueprint, render_template, views, session,   # 定義類視圖,顯示模板文件
    jsonify, g                                       # jsonify強制轉換成json數據
)
from exts import db                               # 數據庫中更新密碼、郵箱等使用

# 導入form表單   .forms代表同級目錄下的forms.py       ResetPwdForm修改密碼的form信息
from .forms import LoginForm, ResetPwdForm

# 導入模型  .models代表同級目錄下的models.py
from .models import CMS_User

# 導入裝飾器:判斷當前界面是否是登錄界面,不是就將url重定向到登錄界面
from .decorators import login_required

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前綴url_prefix

# 鉤子函數是在cms_bp創建之後才創建的,順序在cms_bp創建之後
from .hooks import before_request


@cms_bp.route("/")                                          # 後臺界面
# @login_required             # 裝飾器判定當前界面是否是登錄界面,但是需要每個路由函數都要加該裝飾器,比較麻煩,推薦使用鉤子函數
def index():
    # return "cms index:後端類視圖文件"
    return render_template('cms/cms_index.html')       # 登陸之後進入CMS後臺管理界面,路徑寫全cms/cms_index.html


# 用戶註銷登錄
@cms_bp.route("/logout/")                              # 需要關聯到cms/cms_index.html中的註銷屬性
def logout():
    # session清除user_id
    del session['user_id']
    # 重定向到登錄界面
    return redirect(url_for('cms.login'))             # 重定向(redirec)爲把url變爲重定向的url


# 定義個人中心的路由
@cms_bp.route("/profile/")
def profile():
    return render_template("cms/cms_profile.html")   # 模板渲染(render_template)則不會改變url,模板渲染是用模板來渲染請求的url


# 定義類視圖,顯示模板文件   用戶登錄功能實現
class LoginView(views.MethodView):
    def get(self, message=None):                                         # message=None時候不傳輸信息到cms_login.html頁面
        return render_template("cms/cms_login.html", message=message)    # 針對post方法中同樣要返回到cms_login.html頁面進行代碼簡化
    
    # 用戶登錄操作驗證
    def post(self):
        # 收集表單信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 數據庫驗證
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查詢數據庫中的用戶信息
            user = CMS_User.query.filter_by(email=email).first()    # 郵箱唯一,用於查詢驗證用戶
            if user and user.check_password(password):              # 驗證用戶和密碼是否都正確
                session['user_id'] = user.id                        # 查詢到用戶數據時,保存session的id到瀏覽器
                # session['user_name'] = user.username                # 將數據庫中的user.username保存到session中,在hooks.py中判斷
                # session['user_email'] = user.email                  # 將數據庫中的email保存到session中,方便html調用信息
                # session['user_join_time'] = user.join_time          # 將數據庫中的join_time保存到session中,方便html調用信息
                
                if remember:                                        # 如果用戶點擊了remember選擇,在瀏覽器中進行數據持久化
                    session.permanent = True                        # 數據持久化,默認31天,需要設置session_key在config.py中
            
                # 登錄成功,跳轉到後臺首頁
                return redirect(url_for('cms.index'))               # 在藍圖中必須加cms   跳轉到index方法
            else:
                # return "郵箱或密碼錯誤"                              # 登錄出錯,返回結果
                # return render_template("cms/cms_login.html", message="郵箱或密碼錯誤")  # 登錄出錯,返回結果渲染到cms_login.html頁面
                return self.get(message="郵箱或密碼錯誤")             # 傳參到get方法中,多加一個傳輸錯誤信息的參數到方法中
        else:
            print(login_form.errors)                                 # forms.py中的錯誤信息  字典類型數據
            print(login_form.errors.popitem())                       # forms.py中的錯誤信息  元祖類型數據
            # return "表單驗證錯誤"                                   # 錯誤信息需要渲染到cms_login.html頁面
            return self.get(message=login_form.errors.popitem()[1][0])  # 字典類型數據信息提取
        
    
# 修改密碼的類視圖驗證
class ResetPwd(views.MethodView):
    def get(self):
        return render_template('cms/cms_resetpwd.html')         # 模板渲染到cms_resetpwd.html
    
    # post提交密碼修改
    def post(self):
        # 先審查舊密碼是否與數據庫中的信息相同
        form = ResetPwdForm(request.form)
        if form.validate():
            oldpwd = form.oldpwd.data
            newpwd = form.newpwd.data
            # 對象
            user = g.cms_user
            # 將用戶輸入的密碼進行加密檢測是否與數據庫中的相同
            if user.check_password(oldpwd):
                # 更新我的密碼  將新密碼賦值,此時的新密碼已經經過驗證二次密碼是否一致
                user.password = newpwd         # user.password已經調用了models.py中的 @property裝飾器進行密碼加密
                # 數據庫更新
                db.session.commit()
                return jsonify({"code": 400, "message": "密碼修改成功"})
            else:
                # 當前用戶輸入的舊密碼與數據庫中的不符
                return jsonify({"code": 400, "message": "舊密碼輸入錯誤"})
        else:
            # ajax 需要返回一個json類型的數據
            message = form.errors.popitem()[1][0]    # 收集錯誤信息
            return jsonify({"code": 400, "message": message})    # 將數據轉換成json類型
        
        
# 添加登錄路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址
# 類視圖函數添加綁定路由  注意類視圖需要修改ResetPwd.as_view('resetpwd')
cms_bp.add_url_rule("/resetpwd/", view_func=ResetPwd.as_view('resetpwd'))  # view_func 命名操作名字,/resetpwd/路由地址

基礎模板文件cms_base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--  在頭文件中接收csrf信息  -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{% block title %}

    {% endblock %}</title>
    <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>

<!--  關聯本地的cms_base.css樣式 後臺管理界面CMS的樣式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='cms/css/cms_base.css') }}">
<!--  關聯本地的cms_base.js樣式 後臺管理界面CMS的樣式 -->
    <script src="{{ url_for('static', filename='cms/js/cms_base.js') }}"></script>

<!--  預留空間,給之後的html文件進行修改調整  -->
    {% block head %}

    {% endblock %}

</head>
<body>
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <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="#">論壇CMS管理系統</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
        <!--       從數據庫中調用用戶名,g對象全局調用g.cms_user對象  .username是該對象的一個字段屬性      -->
            <li><a href="#">{{ g.cms_user.username }}<span>[超級管理員]</span></a></li>

        <!--  用戶註銷,關聯到views.py中的@cms_bp.route("/logout/")路由,重定向到該路由      -->
            <li><a href="{{ url_for('cms.logout') }}">註銷</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="查找...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
              <ul class="nav-sidebar">
                <li class="unfold"><a href="#">首頁</a></li>
                <li class="profile-li">
                    <a href="#">個人中心<span></span></a>
                    <ul class="subnav">

                        <!--          url重定向到/cms/profile/下   這個路由在views.py中定義了       -->
                        <li><a href="{{ url_for('cms.profile') }}">個人信息</a></li>
                        <!--           密碼修改的url_for 重定向到/cms/resetpwd/  路由在views.py中定義了           -->
                        <li><a href="{{ url_for('cms.resetpwd') }}">修改密碼</a></li>
                        <!--         修改郵箱的url_for        -->
                        <li><a href="#">修改郵箱</a></li>
                    </ul>
                </li>

                <li class="nav-group post-manage"><a href="#">帖子管理</a></li>
                <li class="comments-manage"><a href="#">評論管理</a></li>
                <li class="board-manage"><a href="#">板塊管理</a></li>

                <li class="nav-group user-manage"><a href="#">用戶管理</a></li>
                <li class="role-manage"><a href="#">組管理</a></li>

                <li class="nav-group cmsuser-manage"><a href="#">CMS用戶管理</a></li>
                <li class="cmsrole-manage"><a href="#">CMS組管理</a></li>
            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1>{% block page_title %}

            {% endblock %}</h1>
            <div class="main_content">
                {% block content %}

                {% endblock %}
            </div>
          </div>
      </div>
    </div>
</body>
</html>

實現效果如下:

在這裏插入圖片描述

2、restful定義項目規範

新建工具文件夾utils:用於存放項目中需要使用的工具,包括驗證碼的發送,驗證等。

新建工具文件utils/restful.py文件
用於定義項目中的一些規範和代稱

# -*- encoding: utf-8 -*-
"""
@File    : restful.py
@Time    : 2020/5/16 22:04
@Author  : chen

"""
# 此文件是定義項目中使用到的各種代稱和規範
from flask import jsonify


class HttpCode(object):
    ok = 200                # 網頁訪問成功
    unautherror = 401       # 用戶需要驗證
    paramserror = 400       # 參數錯誤
    servererror = 500       # 服務器錯誤
    
    
# 定義訪問網頁狀態的的函數
def restful_result(code, message, data):
    return jsonify({"code": code, "message": message, "data": data})


# 網頁訪問成功   狀態碼200
def success(message='', data=None):
    return restful_result(code=HttpCode.ok, message=message, data=data)


# 網頁訪問缺少權限 用戶需要驗證   狀態碼401
def unauth_error(message, data=None):
    return restful_result(code=HttpCode.unautherror, message=message, data=data)


# 網頁訪問參數錯誤   狀態碼400
def params_error(message, data=None):
    return restful_result(code=HttpCode.paramserror, message=message, data=data)


# 網頁訪問服務器錯誤  狀態碼500
def server_error(message, data=None):
    return restful_result(code=HttpCode.servererror, message=message, data=data)

此時修改views.py文件中返回json數據類型語句,就需要定義一個form表單的父類,用於輸出錯誤信息。

修改表單文件forms.py文件

# -*- encoding: utf-8 -*-
"""
@File    : forms.py
@Time    : 2020/5/11 10:00
@Author  : chen

"""
# forms表單信息
from wtforms import Form, StringField, IntegerField
from wtforms.validators import Email, InputRequired, Length, EqualTo  # EqualTo驗證新密碼是否相同


# 創父類form表單,用於輸出錯誤信息
class BaseForm(Form):
    def get_error(self):
        message = self.errors.popitem()[1][0]          # 錯誤信息的收集,字典類型數據信息提取
        return message                                 # 返回錯誤信息方便調用


# 登錄頁面中的Form表單      繼承父類form
class LoginForm(BaseForm):
    email = StringField(validators=[Email(message="請輸入正確的郵箱"),  InputRequired(message="請輸入郵箱")])
    password = StringField(validators=[Length(3, 15, message='請輸入正確長度的密碼')])
    remember = IntegerField()                # 記住cookie操作  賦值爲0或1


# 修改密碼頁面中的form表單信息    繼承父類form
class ResetPwdForm(BaseForm):
    oldpwd = StringField(validators=[Length(3,15, message="密碼長度有誤")])
    newpwd = StringField(validators=[Length(3,15, message="密碼長度有誤")])
    newpwd2 = StringField(validators=[EqualTo("newpwd", message="兩次輸入密碼不一致")])

視圖文件apps/cms/views.py文件

# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 藍圖文件:實現模塊化應用,應用可以分解成一系列的藍圖   後端的類視圖函數寫在這個文件
from flask import (
    request, redirect, url_for,                  # 頁面跳轉redirect   request請求收集
    Blueprint, render_template, views, session,   # 定義類視圖,顯示模板文件
    jsonify, g                                       # jsonify強制轉換成json數據
)
from exts import db                               # 數據庫中更新密碼、郵箱等使用

# 導入form表單   .forms代表同級目錄下的forms.py       ResetPwdForm修改密碼的form信息
from .forms import LoginForm, ResetPwdForm

# 導入模型  .models代表同級目錄下的models.py
from .models import CMS_User

# 導入裝飾器:判斷當前界面是否是登錄界面,不是就將url重定向到登錄界面
from .decorators import login_required

# 導入restful.py中的訪問網頁狀態碼的函數
from utils import restful

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前綴url_prefix

# 鉤子函數是在cms_bp創建之後才創建的,順序在cms_bp創建之後
from .hooks import before_request


@cms_bp.route("/")                                          # 後臺界面
# @login_required             # 裝飾器判定當前界面是否是登錄界面,但是需要每個路由函數都要加該裝飾器,比較麻煩,推薦使用鉤子函數
def index():
    # return "cms index:後端類視圖文件"
    return render_template('cms/cms_index.html')       # 登陸之後進入CMS後臺管理界面,路徑寫全cms/cms_index.html


# 用戶註銷登錄
@cms_bp.route("/logout/")                              # 需要關聯到cms/cms_index.html中的註銷屬性
def logout():
    # session清除user_id
    del session['user_id']
    # 重定向到登錄界面
    return redirect(url_for('cms.login'))             # 重定向(redirec)爲把url變爲重定向的url


# 定義個人中心的路由
@cms_bp.route("/profile/")
def profile():
    return render_template("cms/cms_profile.html")   # 模板渲染(render_template)則不會改變url,模板渲染是用模板來渲染請求的url


# 定義類視圖,顯示模板文件   用戶登錄功能實現
class LoginView(views.MethodView):
    def get(self, message=None):                                         # message=None時候不傳輸信息到cms_login.html頁面
        return render_template("cms/cms_login.html", message=message)    # 針對post方法中同樣要返回到cms_login.html頁面進行代碼簡化
    
    # 用戶登錄操作驗證
    def post(self):
        # 收集表單信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 數據庫驗證
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查詢數據庫中的用戶信息
            user = CMS_User.query.filter_by(email=email).first()    # 郵箱唯一,用於查詢驗證用戶
            if user and user.check_password(password):              # 驗證用戶和密碼是否都正確
                session['user_id'] = user.id                        # 查詢到用戶數據時,保存session的id到瀏覽器
                # session['user_name'] = user.username                # 將數據庫中的user.username保存到session中,在hooks.py中判斷
                # session['user_email'] = user.email                  # 將數據庫中的email保存到session中,方便html調用信息
                # session['user_join_time'] = user.join_time          # 將數據庫中的join_time保存到session中,方便html調用信息
                
                if remember:                                        # 如果用戶點擊了remember選擇,在瀏覽器中進行數據持久化
                    session.permanent = True                        # 數據持久化,默認31天,需要設置session_key在config.py中
            
                # 登錄成功,跳轉到後臺首頁
                return redirect(url_for('cms.index'))               # 在藍圖中必須加cms   跳轉到index方法
            else:
                # return "郵箱或密碼錯誤"                              # 登錄出錯,返回結果
                # return render_template("cms/cms_login.html", message="郵箱或密碼錯誤")  # 登錄出錯,返回結果渲染到cms_login.html頁面
                return self.get(message="郵箱或密碼錯誤")             # 傳參到get方法中,多加一個傳輸錯誤信息的參數到方法中
        else:
            # print(login_form.errors)                                 # forms.py中的錯誤信息  字典類型數據
            # print(login_form.errors.popitem())                       # forms.py中的錯誤信息  元祖類型數據
            # return "表單驗證錯誤"                                     # 錯誤信息需要渲染到cms_login.html頁面
            # return self.get(message=login_form.errors.popitem()[1][0])  # 字典類型數據信息提取
            return self.get(message=login_form.get_error())            # login_form是收集到的表單信息,信息提取放置到forms.py的父類中實現
    
    
# 修改密碼的類視圖驗證
class ResetPwd(views.MethodView):
    def get(self):
        return render_template('cms/cms_resetpwd.html')         # 模板渲染到cms_resetpwd.html
    
    # post提交密碼修改
    def post(self):
        # 先審查舊密碼是否與數據庫中的信息相同
        form = ResetPwdForm(request.form)
        if form.validate():
            oldpwd = form.oldpwd.data
            newpwd = form.newpwd.data
            # 對象
            user = g.cms_user
            # 將用戶輸入的密碼進行加密檢測是否與數據庫中的相同
            if user.check_password(oldpwd):
                # 更新我的密碼  將新密碼賦值,此時的新密碼已經經過驗證二次密碼是否一致
                user.password = newpwd         # user.password已經調用了models.py中的 @property裝飾器進行密碼加密
                # 數據庫更新
                db.session.commit()
                # return jsonify({"code": 400, "message": "密碼修改成功"})        # 代碼改寫爲下面
                return restful.success("密碼修改成功")             # 調用restful.py中定義的訪問網頁成功的函數
            else:
                # 當前用戶輸入的舊密碼與數據庫中的不符
                # return jsonify({"code": 400, "message": "舊密碼輸入錯誤"})
                return restful.params_error(message="舊密碼輸入錯誤")      # 參數錯誤
        else:
            # ajax 需要返回一個json類型的數據
            # message = form.errors.popitem()[1][0]                     # 收集錯誤信息
            # return jsonify({"code": 400, "message": message})         # 將數據轉換成json類型
            return restful.params_error(message=form.get_error())       # 參數錯誤,信息的收集在forms.py的父類函數中實現
        
        
# 添加登錄路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址
# 類視圖函數添加綁定路由  注意類視圖需要修改ResetPwd.as_view('resetpwd')
cms_bp.add_url_rule("/resetpwd/", view_func=ResetPwd.as_view('resetpwd'))  # view_func 命名操作名字,/resetpwd/路由地址


3、彈窗顯示信息功能

新建文件夾:彈窗顯示靜態文件
在這裏插入圖片描述
彈窗顯示靜態文件:static/common/sweetalert/lgalert.js


var lgalert = {
    /*
        功能:提示錯誤
        參數:
            - msg:提示的內容(可選)
    */
    'alertError': function (msg) {
        swal('提示',msg,'error');
    },
    /*
        功能:信息提示
        參數:
            - msg:提示的內容(可選)
    */
    'alertInfo':function (msg) {
        swal('提示',msg,'warning');
    },
    /*
        功能:可以自定義標題的信息提示
        參數:
            - msg:提示的內容(可選)
    */
    'alertInfoWithTitle': function (title,msg) {
        swal(title,msg);
    },
    /*
        功能:成功的提示
        參數:
            - msg:提示的內容(必須)
            - confirmCallback:確認按鈕的執行事件(可選)
    */
    'alertSuccess':function (msg,confirmCallback) {
        args = {
            'title': '提示',
            'text': msg,
            'type': 'success',
        }
        swal(args,confirmCallback);
    }, 
    /*
        功能:帶有標題的成功提示
        參數:
            - title:提示框的標題(必須)
            - msg:提示的內容(必須)
    */
    'alertSuccessWithTitle':function (title,msg) {
        swal(title,msg,'success');
    },
    /*
        功能:確認提示
        參數:字典的形式
            - title:提示框標題(可選)
            - type:提示框的類型(可選)
            - confirmText:確認按鈕文本(可選)
            - cancelText:取消按鈕文本(可選)
            - msg:提示框內容(必須)
            - confirmCallback:確認按鈕點擊回調(可選)
            - cancelCallback:取消按鈕點擊回調(可選)
    */
    'alertConfirm':function (params) {
        swal({
            'title': params['title'] ? params['title'] : '提示',
            'showCancelButton': true,
            'showConfirmButton': true,
            'type': params['type'] ? params['type'] : '',
            'confirmButtonText': params['confirmText'] ? params['confirmText'] : '確定',
            'cancelButtonText': params['cancelText'] ? params['cancelText'] : '取消',
            'text': params['msg'] ? params['msg'] : ''
        },function (isConfirm) {
            if(isConfirm){
                if(params['confirmCallback']){
                    params['confirmCallback']();
                }
            }else{
                if(params['cancelCallback']){
                    params['cancelCallback']();
                }
            }
        });
    },
    /*
        功能:帶有一個輸入框的提示
        參數:字典的形式
            - title:提示框的標題(可選)
            - text:提示框的內容(可選)
            - placeholder:輸入框的佔位文字(可選)
            - confirmText:確認按鈕文字(可選)
            - cancelText:取消按鈕文字(可選)
            - confirmCallback:確認後的執行事件
    */
    'alertOneInput': function (params) {
        swal({
            'title': params['title'] ? params['title'] : '請輸入',
            'text': params['text'] ? params['text'] : '',
            'type':'input',
            'showCancelButton': true,
            'animation': 'slide-from-top',
            'closeOnConfirm': false,
            'showLoaderOnConfirm': true,
            'inputPlaceholder': params['placeholder'] ? params['placeholder'] : '',
            'confirmButtonText': params['confirmText'] ? params['confirmText'] : '確定',
            'cancelButtonText': params['cancelText'] ? params['cancelText'] : '取消',
        },function (inputValue) {
            if(inputValue === false) return false;
            if(inputValue === ''){
                swal.showInputError('輸入框不能爲空!');
                return false;
            }
            if(params['confirmCallback']){
                params['confirmCallback'](inputValue);
            }
        });
    },
    /*
        功能:網絡錯誤提示
        參數:無
    */
    'alertNetworkError':function () {
        this.alertErrorToast('網絡錯誤');
    },
    /*
        功能:信息toast提示(1s後消失)
        參數:
            - msg:提示消息
    */
    'alertInfoToast':function (msg) {
        this.alertToast(msg,'info');
    },
    /*
        功能:錯誤toast提示(1s後消失)
        參數:
            - msg:提示消息
    */
    'alertErrorToast':function (msg) {
        this.alertToast(msg,'error');
    },
    /*
        功能:成功toast提示(1s後消失)
        參數:
            - msg:提示消息
    */
    'alertSuccessToast':function (msg) {
        if(!msg){msg = '成功!';}
        this.alertToast(msg,'success');
    },
    /*
        功能:彈出toast(1s後消失)
        參數:
            - msg:提示消息
            - type:toast的類型
    */
    'alertToast':function (msg,type) {
        swal({
            'title': msg,
            'text': '',
            'type': type,
            'showCancelButton': false,
            'showConfirmButton': false,
            'timer': 1000,
        });
    },
    // 關閉當前對話框
    'close': function () {
        swal.close();
    }
};

彈窗顯示靜態文件:static/common/sweetalert/sweetalert.css

body.stop-scrolling {
  height: 100%;
  overflow: hidden; }

.sweet-overlay {
  background-color: black;
  /* IE8 */
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
  /* IE8 */
  background-color: rgba(0, 0, 0, 0.4);
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: none;
  z-index: 10000; }

.sweet-alert {
  background-color: white;
  font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  width: 478px;
  padding: 17px;
  border-radius: 5px;
  text-align: center;
  position: fixed;
  left: 50%;
  top: 50%;
  margin-left: -256px;
  margin-top: -200px;
  overflow: hidden;
  display: none;
  z-index: 99999; }
  @media all and (max-width: 540px) {
    .sweet-alert {
      width: auto;
      margin-left: 0;
      margin-right: 0;
      left: 15px;
      right: 15px; } }
  .sweet-alert h2 {
    color: #575757;
    font-size: 30px;
    text-align: center;
    font-weight: 600;
    text-transform: none;
    position: relative;
    margin: 25px 0;
    padding: 0;
    line-height: 40px;
    display: block; }
  .sweet-alert p {
    color: #797979;
    font-size: 16px;
    text-align: center;
    font-weight: 300;
    position: relative;
    text-align: inherit;
    float: none;
    margin: 0;
    padding: 0;
    line-height: normal; }
  .sweet-alert fieldset {
    border: none;
    position: relative; }
  .sweet-alert .sa-error-container {
    background-color: #f1f1f1;
    margin-left: -17px;
    margin-right: -17px;
    overflow: hidden;
    padding: 0 10px;
    max-height: 0;
    webkit-transition: padding 0.15s, max-height 0.15s;
    transition: padding 0.15s, max-height 0.15s; }
    .sweet-alert .sa-error-container.show {
      padding: 10px 0;
      max-height: 100px;
      webkit-transition: padding 0.2s, max-height 0.2s;
      transition: padding 0.25s, max-height 0.25s; }
    .sweet-alert .sa-error-container .icon {
      display: inline-block;
      width: 24px;
      height: 24px;
      border-radius: 50%;
      background-color: #ea7d7d;
      color: white;
      line-height: 24px;
      text-align: center;
      margin-right: 3px; }
    .sweet-alert .sa-error-container p {
      display: inline-block; }
  .sweet-alert .sa-input-error {
    position: absolute;
    top: 29px;
    right: 26px;
    width: 20px;
    height: 20px;
    opacity: 0;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    -webkit-transform-origin: 50% 50%;
    transform-origin: 50% 50%;
    -webkit-transition: all 0.1s;
    transition: all 0.1s; }
    .sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after {
      content: "";
      width: 20px;
      height: 6px;
      background-color: #f06e57;
      border-radius: 3px;
      position: absolute;
      top: 50%;
      margin-top: -4px;
      left: 50%;
      margin-left: -9px; }
    .sweet-alert .sa-input-error::before {
      -webkit-transform: rotate(-45deg);
      transform: rotate(-45deg); }
    .sweet-alert .sa-input-error::after {
      -webkit-transform: rotate(45deg);
      transform: rotate(45deg); }
    .sweet-alert .sa-input-error.show {
      opacity: 1;
      -webkit-transform: scale(1);
      transform: scale(1); }
  .sweet-alert input {
    width: 100%;
    box-sizing: border-box;
    border-radius: 3px;
    border: 1px solid #d7d7d7;
    height: 43px;
    margin-top: 10px;
    margin-bottom: 17px;
    font-size: 18px;
    box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06);
    padding: 0 12px;
    display: none;
    -webkit-transition: all 0.3s;
    transition: all 0.3s; }
    .sweet-alert input:focus {
      outline: none;
      box-shadow: 0px 0px 3px #c4e6f5;
      border: 1px solid #b4dbed; }
      .sweet-alert input:focus::-moz-placeholder {
        transition: opacity 0.3s 0.03s ease;
        opacity: 0.5; }
      .sweet-alert input:focus:-ms-input-placeholder {
        transition: opacity 0.3s 0.03s ease;
        opacity: 0.5; }
      .sweet-alert input:focus::-webkit-input-placeholder {
        transition: opacity 0.3s 0.03s ease;
        opacity: 0.5; }
    .sweet-alert input::-moz-placeholder {
      color: #bdbdbd; }
    .sweet-alert input:-ms-input-placeholder {
      color: #bdbdbd; }
    .sweet-alert input::-webkit-input-placeholder {
      color: #bdbdbd; }
  .sweet-alert.show-input input {
    display: block; }
  .sweet-alert .sa-confirm-button-container {
    display: inline-block;
    position: relative; }
  .sweet-alert .la-ball-fall {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -27px;
    margin-top: 4px;
    opacity: 0;
    visibility: hidden; }
  .sweet-alert button {
    background-color: #8CD4F5;
    color: white;
    border: none;
    box-shadow: none;
    font-size: 17px;
    font-weight: 500;
    -webkit-border-radius: 4px;
    border-radius: 5px;
    padding: 10px 32px;
    margin: 26px 5px 0 5px;
    cursor: pointer; }
    .sweet-alert button:focus {
      outline: none;
      box-shadow: 0 0 2px rgba(128, 179, 235, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.05); }
    .sweet-alert button:hover {
      background-color: #7ecff4; }
    .sweet-alert button:active {
      background-color: #5dc2f1; }
    .sweet-alert button.cancel {
      background-color: #C1C1C1; }
      .sweet-alert button.cancel:hover {
        background-color: #b9b9b9; }
      .sweet-alert button.cancel:active {
        background-color: #a8a8a8; }
      .sweet-alert button.cancel:focus {
        box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; }
    .sweet-alert button[disabled] {
      opacity: .6;
      cursor: default; }
    .sweet-alert button.confirm[disabled] {
      color: transparent; }
      .sweet-alert button.confirm[disabled] ~ .la-ball-fall {
        opacity: 1;
        visibility: visible;
        transition-delay: 0s; }
    .sweet-alert button::-moz-focus-inner {
      border: 0; }
  .sweet-alert[data-has-cancel-button=false] button {
    box-shadow: none !important; }
  .sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] {
    padding-bottom: 40px; }
  .sweet-alert .sa-icon {
    width: 80px;
    height: 80px;
    border: 4px solid gray;
    -webkit-border-radius: 40px;
    border-radius: 40px;
    border-radius: 50%;
    margin: 20px auto;
    padding: 0;
    position: relative;
    box-sizing: content-box; }
    .sweet-alert .sa-icon.sa-error {
      border-color: #F27474; }
      .sweet-alert .sa-icon.sa-error .sa-x-mark {
        position: relative;
        display: block; }
      .sweet-alert .sa-icon.sa-error .sa-line {
        position: absolute;
        height: 5px;
        width: 47px;
        background-color: #F27474;
        display: block;
        top: 37px;
        border-radius: 2px; }
        .sweet-alert .sa-icon.sa-error .sa-line.sa-left {
          -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
          left: 17px; }
        .sweet-alert .sa-icon.sa-error .sa-line.sa-right {
          -webkit-transform: rotate(-45deg);
          transform: rotate(-45deg);
          right: 16px; }
    .sweet-alert .sa-icon.sa-warning {
      border-color: #F8BB86; }
      .sweet-alert .sa-icon.sa-warning .sa-body {
        position: absolute;
        width: 5px;
        height: 47px;
        left: 50%;
        top: 10px;
        -webkit-border-radius: 2px;
        border-radius: 2px;
        margin-left: -2px;
        background-color: #F8BB86; }
      .sweet-alert .sa-icon.sa-warning .sa-dot {
        position: absolute;
        width: 7px;
        height: 7px;
        -webkit-border-radius: 50%;
        border-radius: 50%;
        margin-left: -3px;
        left: 50%;
        bottom: 10px;
        background-color: #F8BB86; }
    .sweet-alert .sa-icon.sa-info {
      border-color: #C9DAE1; }
      .sweet-alert .sa-icon.sa-info::before {
        content: "";
        position: absolute;
        width: 5px;
        height: 29px;
        left: 50%;
        bottom: 17px;
        border-radius: 2px;
        margin-left: -2px;
        background-color: #C9DAE1; }
      .sweet-alert .sa-icon.sa-info::after {
        content: "";
        position: absolute;
        width: 7px;
        height: 7px;
        border-radius: 50%;
        margin-left: -3px;
        top: 19px;
        background-color: #C9DAE1;
        left: 50%; }
    .sweet-alert .sa-icon.sa-success {
      border-color: #A5DC86; }
      .sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after {
        content: '';
        -webkit-border-radius: 40px;
        border-radius: 40px;
        border-radius: 50%;
        position: absolute;
        width: 60px;
        height: 120px;
        background: white;
        -webkit-transform: rotate(45deg);
        transform: rotate(45deg); }
      .sweet-alert .sa-icon.sa-success::before {
        -webkit-border-radius: 120px 0 0 120px;
        border-radius: 120px 0 0 120px;
        top: -7px;
        left: -33px;
        -webkit-transform: rotate(-45deg);
        transform: rotate(-45deg);
        -webkit-transform-origin: 60px 60px;
        transform-origin: 60px 60px; }
      .sweet-alert .sa-icon.sa-success::after {
        -webkit-border-radius: 0 120px 120px 0;
        border-radius: 0 120px 120px 0;
        top: -11px;
        left: 30px;
        -webkit-transform: rotate(-45deg);
        transform: rotate(-45deg);
        -webkit-transform-origin: 0px 60px;
        transform-origin: 0px 60px; }
      .sweet-alert .sa-icon.sa-success .sa-placeholder {
        width: 80px;
        height: 80px;
        border: 4px solid rgba(165, 220, 134, 0.2);
        -webkit-border-radius: 40px;
        border-radius: 40px;
        border-radius: 50%;
        box-sizing: content-box;
        position: absolute;
        left: -4px;
        top: -4px;
        z-index: 2; }
      .sweet-alert .sa-icon.sa-success .sa-fix {
        width: 5px;
        height: 90px;
        background-color: white;
        position: absolute;
        left: 28px;
        top: 8px;
        z-index: 1;
        -webkit-transform: rotate(-45deg);
        transform: rotate(-45deg); }
      .sweet-alert .sa-icon.sa-success .sa-line {
        height: 5px;
        background-color: #A5DC86;
        display: block;
        border-radius: 2px;
        position: absolute;
        z-index: 2; }
        .sweet-alert .sa-icon.sa-success .sa-line.sa-tip {
          width: 25px;
          left: 14px;
          top: 46px;
          -webkit-transform: rotate(45deg);
          transform: rotate(45deg); }
        .sweet-alert .sa-icon.sa-success .sa-line.sa-long {
          width: 47px;
          right: 8px;
          top: 38px;
          -webkit-transform: rotate(-45deg);
          transform: rotate(-45deg); }
    .sweet-alert .sa-icon.sa-custom {
      background-size: contain;
      border-radius: 0;
      border: none;
      background-position: center center;
      background-repeat: no-repeat; }

/*
 * Animations
 */
@-webkit-keyframes showSweetAlert {
  0% {
    transform: scale(0.7);
    -webkit-transform: scale(0.7); }
  45% {
    transform: scale(1.05);
    -webkit-transform: scale(1.05); }
  80% {
    transform: scale(0.95);
    -webkit-transform: scale(0.95); }
  100% {
    transform: scale(1);
    -webkit-transform: scale(1); } }

@keyframes showSweetAlert {
  0% {
    transform: scale(0.7);
    -webkit-transform: scale(0.7); }
  45% {
    transform: scale(1.05);
    -webkit-transform: scale(1.05); }
  80% {
    transform: scale(0.95);
    -webkit-transform: scale(0.95); }
  100% {
    transform: scale(1);
    -webkit-transform: scale(1); } }

@-webkit-keyframes hideSweetAlert {
  0% {
    transform: scale(1);
    -webkit-transform: scale(1); }
  100% {
    transform: scale(0.5);
    -webkit-transform: scale(0.5); } }

@keyframes hideSweetAlert {
  0% {
    transform: scale(1);
    -webkit-transform: scale(1); }
  100% {
    transform: scale(0.5);
    -webkit-transform: scale(0.5); } }

@-webkit-keyframes slideFromTop {
  0% {
    top: 0%; }
  100% {
    top: 50%; } }

@keyframes slideFromTop {
  0% {
    top: 0%; }
  100% {
    top: 50%; } }

@-webkit-keyframes slideToTop {
  0% {
    top: 50%; }
  100% {
    top: 0%; } }

@keyframes slideToTop {
  0% {
    top: 50%; }
  100% {
    top: 0%; } }

@-webkit-keyframes slideFromBottom {
  0% {
    top: 70%; }
  100% {
    top: 50%; } }

@keyframes slideFromBottom {
  0% {
    top: 70%; }
  100% {
    top: 50%; } }

@-webkit-keyframes slideToBottom {
  0% {
    top: 50%; }
  100% {
    top: 70%; } }

@keyframes slideToBottom {
  0% {
    top: 50%; }
  100% {
    top: 70%; } }

.showSweetAlert[data-animation=pop] {
  -webkit-animation: showSweetAlert 0.3s;
  animation: showSweetAlert 0.3s; }

.showSweetAlert[data-animation=none] {
  -webkit-animation: none;
  animation: none; }

.showSweetAlert[data-animation=slide-from-top] {
  -webkit-animation: slideFromTop 0.3s;
  animation: slideFromTop 0.3s; }

.showSweetAlert[data-animation=slide-from-bottom] {
  -webkit-animation: slideFromBottom 0.3s;
  animation: slideFromBottom 0.3s; }

.hideSweetAlert[data-animation=pop] {
  -webkit-animation: hideSweetAlert 0.2s;
  animation: hideSweetAlert 0.2s; }

.hideSweetAlert[data-animation=none] {
  -webkit-animation: none;
  animation: none; }

.hideSweetAlert[data-animation=slide-from-top] {
  -webkit-animation: slideToTop 0.4s;
  animation: slideToTop 0.4s; }

.hideSweetAlert[data-animation=slide-from-bottom] {
  -webkit-animation: slideToBottom 0.3s;
  animation: slideToBottom 0.3s; }

@-webkit-keyframes animateSuccessTip {
  0% {
    width: 0;
    left: 1px;
    top: 19px; }
  54% {
    width: 0;
    left: 1px;
    top: 19px; }
  70% {
    width: 50px;
    left: -8px;
    top: 37px; }
  84% {
    width: 17px;
    left: 21px;
    top: 48px; }
  100% {
    width: 25px;
    left: 14px;
    top: 45px; } }

@keyframes animateSuccessTip {
  0% {
    width: 0;
    left: 1px;
    top: 19px; }
  54% {
    width: 0;
    left: 1px;
    top: 19px; }
  70% {
    width: 50px;
    left: -8px;
    top: 37px; }
  84% {
    width: 17px;
    left: 21px;
    top: 48px; }
  100% {
    width: 25px;
    left: 14px;
    top: 45px; } }

@-webkit-keyframes animateSuccessLong {
  0% {
    width: 0;
    right: 46px;
    top: 54px; }
  65% {
    width: 0;
    right: 46px;
    top: 54px; }
  84% {
    width: 55px;
    right: 0px;
    top: 35px; }
  100% {
    width: 47px;
    right: 8px;
    top: 38px; } }

@keyframes animateSuccessLong {
  0% {
    width: 0;
    right: 46px;
    top: 54px; }
  65% {
    width: 0;
    right: 46px;
    top: 54px; }
  84% {
    width: 55px;
    right: 0px;
    top: 35px; }
  100% {
    width: 47px;
    right: 8px;
    top: 38px; } }

@-webkit-keyframes rotatePlaceholder {
  0% {
    transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg); }
  5% {
    transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg); }
  12% {
    transform: rotate(-405deg);
    -webkit-transform: rotate(-405deg); }
  100% {
    transform: rotate(-405deg);
    -webkit-transform: rotate(-405deg); } }

@keyframes rotatePlaceholder {
  0% {
    transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg); }
  5% {
    transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg); }
  12% {
    transform: rotate(-405deg);
    -webkit-transform: rotate(-405deg); }
  100% {
    transform: rotate(-405deg);
    -webkit-transform: rotate(-405deg); } }

.animateSuccessTip {
  -webkit-animation: animateSuccessTip 0.75s;
  animation: animateSuccessTip 0.75s; }

.animateSuccessLong {
  -webkit-animation: animateSuccessLong 0.75s;
  animation: animateSuccessLong 0.75s; }

.sa-icon.sa-success.animate::after {
  -webkit-animation: rotatePlaceholder 4.25s ease-in;
  animation: rotatePlaceholder 4.25s ease-in; }

@-webkit-keyframes animateErrorIcon {
  0% {
    transform: rotateX(100deg);
    -webkit-transform: rotateX(100deg);
    opacity: 0; }
  100% {
    transform: rotateX(0deg);
    -webkit-transform: rotateX(0deg);
    opacity: 1; } }

@keyframes animateErrorIcon {
  0% {
    transform: rotateX(100deg);
    -webkit-transform: rotateX(100deg);
    opacity: 0; }
  100% {
    transform: rotateX(0deg);
    -webkit-transform: rotateX(0deg);
    opacity: 1; } }

.animateErrorIcon {
  -webkit-animation: animateErrorIcon 0.5s;
  animation: animateErrorIcon 0.5s; }

@-webkit-keyframes animateXMark {
  0% {
    transform: scale(0.4);
    -webkit-transform: scale(0.4);
    margin-top: 26px;
    opacity: 0; }
  50% {
    transform: scale(0.4);
    -webkit-transform: scale(0.4);
    margin-top: 26px;
    opacity: 0; }
  80% {
    transform: scale(1.15);
    -webkit-transform: scale(1.15);
    margin-top: -6px; }
  100% {
    transform: scale(1);
    -webkit-transform: scale(1);
    margin-top: 0;
    opacity: 1; } }

@keyframes animateXMark {
  0% {
    transform: scale(0.4);
    -webkit-transform: scale(0.4);
    margin-top: 26px;
    opacity: 0; }
  50% {
    transform: scale(0.4);
    -webkit-transform: scale(0.4);
    margin-top: 26px;
    opacity: 0; }
  80% {
    transform: scale(1.15);
    -webkit-transform: scale(1.15);
    margin-top: -6px; }
  100% {
    transform: scale(1);
    -webkit-transform: scale(1);
    margin-top: 0;
    opacity: 1; } }

.animateXMark {
  -webkit-animation: animateXMark 0.5s;
  animation: animateXMark 0.5s; }

@-webkit-keyframes pulseWarning {
  0% {
    border-color: #F8D486; }
  100% {
    border-color: #F8BB86; } }

@keyframes pulseWarning {
  0% {
    border-color: #F8D486; }
  100% {
    border-color: #F8BB86; } }

.pulseWarning {
  -webkit-animation: pulseWarning 0.75s infinite alternate;
  animation: pulseWarning 0.75s infinite alternate; }

@-webkit-keyframes pulseWarningIns {
  0% {
    background-color: #F8D486; }
  100% {
    background-color: #F8BB86; } }

@keyframes pulseWarningIns {
  0% {
    background-color: #F8D486; }
  100% {
    background-color: #F8BB86; } }

.pulseWarningIns {
  -webkit-animation: pulseWarningIns 0.75s infinite alternate;
  animation: pulseWarningIns 0.75s infinite alternate; }

@-webkit-keyframes rotate-loading {
  0% {
    transform: rotate(0deg); }
  100% {
    transform: rotate(360deg); } }

@keyframes rotate-loading {
  0% {
    transform: rotate(0deg); }
  100% {
    transform: rotate(360deg); } }

/* Internet Explorer 9 has some special quirks that are fixed here */
/* The icons are not animated. */
/* This file is automatically merged into sweet-alert.min.js through Gulp */
/* Error icon */
.sweet-alert .sa-icon.sa-error .sa-line.sa-left {
  -ms-transform: rotate(45deg) \9; }

.sweet-alert .sa-icon.sa-error .sa-line.sa-right {
  -ms-transform: rotate(-45deg) \9; }

/* Success icon */
.sweet-alert .sa-icon.sa-success {
  border-color: transparent\9; }

.sweet-alert .sa-icon.sa-success .sa-line.sa-tip {
  -ms-transform: rotate(45deg) \9; }

.sweet-alert .sa-icon.sa-success .sa-line.sa-long {
  -ms-transform: rotate(-45deg) \9; }

/*!
 * Load Awesome v1.1.0 (http://github.danielcardoso.net/load-awesome/)
 * Copyright 2015 Daniel Cardoso <@DanielCardoso>
 * Licensed under MIT
 */
.la-ball-fall,
.la-ball-fall > div {
  position: relative;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box; }

.la-ball-fall {
  display: block;
  font-size: 0;
  color: #fff; }

.la-ball-fall.la-dark {
  color: #333; }

.la-ball-fall > div {
  display: inline-block;
  float: none;
  background-color: currentColor;
  border: 0 solid currentColor; }

.la-ball-fall {
  width: 54px;
  height: 18px; }

.la-ball-fall > div {
  width: 10px;
  height: 10px;
  margin: 4px;
  border-radius: 100%;
  opacity: 0;
  -webkit-animation: ball-fall 1s ease-in-out infinite;
  -moz-animation: ball-fall 1s ease-in-out infinite;
  -o-animation: ball-fall 1s ease-in-out infinite;
  animation: ball-fall 1s ease-in-out infinite; }

.la-ball-fall > div:nth-child(1) {
  -webkit-animation-delay: -200ms;
  -moz-animation-delay: -200ms;
  -o-animation-delay: -200ms;
  animation-delay: -200ms; }

.la-ball-fall > div:nth-child(2) {
  -webkit-animation-delay: -100ms;
  -moz-animation-delay: -100ms;
  -o-animation-delay: -100ms;
  animation-delay: -100ms; }

.la-ball-fall > div:nth-child(3) {
  -webkit-animation-delay: 0ms;
  -moz-animation-delay: 0ms;
  -o-animation-delay: 0ms;
  animation-delay: 0ms; }

.la-ball-fall.la-sm {
  width: 26px;
  height: 8px; }

.la-ball-fall.la-sm > div {
  width: 4px;
  height: 4px;
  margin: 2px; }

.la-ball-fall.la-2x {
  width: 108px;
  height: 36px; }

.la-ball-fall.la-2x > div {
  width: 20px;
  height: 20px;
  margin: 8px; }

.la-ball-fall.la-3x {
  width: 162px;
  height: 54px; }

.la-ball-fall.la-3x > div {
  width: 30px;
  height: 30px;
  margin: 12px; }

/*
 * Animation
 */
@-webkit-keyframes ball-fall {
  0% {
    opacity: 0;
    -webkit-transform: translateY(-145%);
    transform: translateY(-145%); }
  10% {
    opacity: .5; }
  20% {
    opacity: 1;
    -webkit-transform: translateY(0);
    transform: translateY(0); }
  80% {
    opacity: 1;
    -webkit-transform: translateY(0);
    transform: translateY(0); }
  90% {
    opacity: .5; }
  100% {
    opacity: 0;
    -webkit-transform: translateY(145%);
    transform: translateY(145%); } }

@-moz-keyframes ball-fall {
  0% {
    opacity: 0;
    -moz-transform: translateY(-145%);
    transform: translateY(-145%); }
  10% {
    opacity: .5; }
  20% {
    opacity: 1;
    -moz-transform: translateY(0);
    transform: translateY(0); }
  80% {
    opacity: 1;
    -moz-transform: translateY(0);
    transform: translateY(0); }
  90% {
    opacity: .5; }
  100% {
    opacity: 0;
    -moz-transform: translateY(145%);
    transform: translateY(145%); } }

@-o-keyframes ball-fall {
  0% {
    opacity: 0;
    -o-transform: translateY(-145%);
    transform: translateY(-145%); }
  10% {
    opacity: .5; }
  20% {
    opacity: 1;
    -o-transform: translateY(0);
    transform: translateY(0); }
  80% {
    opacity: 1;
    -o-transform: translateY(0);
    transform: translateY(0); }
  90% {
    opacity: .5; }
  100% {
    opacity: 0;
    -o-transform: translateY(145%);
    transform: translateY(145%); } }

@keyframes ball-fall {
  0% {
    opacity: 0;
    -webkit-transform: translateY(-145%);
    -moz-transform: translateY(-145%);
    -o-transform: translateY(-145%);
    transform: translateY(-145%); }
  10% {
    opacity: .5; }
  20% {
    opacity: 1;
    -webkit-transform: translateY(0);
    -moz-transform: translateY(0);
    -o-transform: translateY(0);
    transform: translateY(0); }
  80% {
    opacity: 1;
    -webkit-transform: translateY(0);
    -moz-transform: translateY(0);
    -o-transform: translateY(0);
    transform: translateY(0); }
  90% {
    opacity: .5; }
  100% {
    opacity: 0;
    -webkit-transform: translateY(145%);
    -moz-transform: translateY(145%);
    -o-transform: translateY(145%);
    transform: translateY(145%); } }

彈窗顯示靜態文件:static/common/sweetalert/sweetalert…min.js

!function(e,t,n){"use strict";!function o(e,t,n){function a(s,l){if(!t[s]){if(!e[s]){var i="function"==typeof require&&require;if(!l&&i)return i(s,!0);if(r)return r(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=t[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return a(n?n:t)},c,c.exports,o,e,t,n)}return t[s].exports}for(var r="function"==typeof require&&require,s=0;s<n.length;s++)a(n[s]);return a}({1:[function(o,a,r){function s(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var l,i,u,c,d=o("./modules/handle-dom"),f=o("./modules/utils"),p=o("./modules/handle-swal-dom"),m=o("./modules/handle-click"),v=o("./modules/handle-key"),y=s(v),b=o("./modules/default-params"),h=s(b),g=o("./modules/set-params"),w=s(g);r["default"]=u=c=function(){function o(e){var t=a;return t[e]===n?h["default"][e]:t[e]}var a=arguments[0];if((0,d.addClass)(t.body,"stop-scrolling"),(0,p.resetInput)(),a===n)return(0,f.logStr)("SweetAlert expects at least 1 attribute!"),!1;var r=(0,f.extend)({},h["default"]);switch(typeof a){case"string":r.title=a,r.text=arguments[1]||"",r.type=arguments[2]||"";break;case"object":if(a.title===n)return(0,f.logStr)('Missing "title" argument!'),!1;r.title=a.title;for(var s in h["default"])r[s]=o(s);r.confirmButtonText=r.showCancelButton?"Confirm":h["default"].confirmButtonText,r.confirmButtonText=o("confirmButtonText"),r.doneFunction=arguments[1]||null;break;default:return(0,f.logStr)('Unexpected type of argument! Expected "string" or "object", got '+typeof a),!1}(0,w["default"])(r),(0,p.fixVerticalPosition)(),(0,p.openModal)(arguments[1]);for(var u=(0,p.getModal)(),v=u.querySelectorAll("button"),b=["onclick","onmouseover","onmouseout","onmousedown","onmouseup","onfocus"],g=function(e){return(0,m.handleButton)(e,r,u)},C=0;C<v.length;C++)for(var S=0;S<b.length;S++){var x=b[S];v[C][x]=g}(0,p.getOverlay)().onclick=g,l=e.onkeydown;var k=function(e){return(0,y["default"])(e,r,u)};e.onkeydown=k,e.onfocus=function(){setTimeout(function(){i!==n&&(i.focus(),i=n)},0)},c.enableButtons()},u.setDefaults=c.setDefaults=function(e){if(!e)throw new Error("userParams is required");if("object"!=typeof e)throw new Error("userParams has to be a object");(0,f.extend)(h["default"],e)},u.close=c.close=function(){var o=(0,p.getModal)();(0,d.fadeOut)((0,p.getOverlay)(),5),(0,d.fadeOut)(o,5),(0,d.removeClass)(o,"showSweetAlert"),(0,d.addClass)(o,"hideSweetAlert"),(0,d.removeClass)(o,"visible");var a=o.querySelector(".sa-icon.sa-success");(0,d.removeClass)(a,"animate"),(0,d.removeClass)(a.querySelector(".sa-tip"),"animateSuccessTip"),(0,d.removeClass)(a.querySelector(".sa-long"),"animateSuccessLong");var r=o.querySelector(".sa-icon.sa-error");(0,d.removeClass)(r,"animateErrorIcon"),(0,d.removeClass)(r.querySelector(".sa-x-mark"),"animateXMark");var s=o.querySelector(".sa-icon.sa-warning");return(0,d.removeClass)(s,"pulseWarning"),(0,d.removeClass)(s.querySelector(".sa-body"),"pulseWarningIns"),(0,d.removeClass)(s.querySelector(".sa-dot"),"pulseWarningIns"),setTimeout(function(){var e=o.getAttribute("data-custom-class");(0,d.removeClass)(o,e)},300),(0,d.removeClass)(t.body,"stop-scrolling"),e.onkeydown=l,e.previousActiveElement&&e.previousActiveElement.focus(),i=n,clearTimeout(o.timeout),!0},u.showInputError=c.showInputError=function(e){var t=(0,p.getModal)(),n=t.querySelector(".sa-input-error");(0,d.addClass)(n,"show");var o=t.querySelector(".sa-error-container");(0,d.addClass)(o,"show"),o.querySelector("p").innerHTML=e,setTimeout(function(){u.enableButtons()},1),t.querySelector("input").focus()},u.resetInputError=c.resetInputError=function(e){if(e&&13===e.keyCode)return!1;var t=(0,p.getModal)(),n=t.querySelector(".sa-input-error");(0,d.removeClass)(n,"show");var o=t.querySelector(".sa-error-container");(0,d.removeClass)(o,"show")},u.disableButtons=c.disableButtons=function(e){var t=(0,p.getModal)(),n=t.querySelector("button.confirm"),o=t.querySelector("button.cancel");n.disabled=!0,o.disabled=!0},u.enableButtons=c.enableButtons=function(e){var t=(0,p.getModal)(),n=t.querySelector("button.confirm"),o=t.querySelector("button.cancel");n.disabled=!1,o.disabled=!1},"undefined"!=typeof e?e.sweetAlert=e.swal=u:(0,f.logStr)("SweetAlert is a frontend module!"),a.exports=r["default"]},{"./modules/default-params":2,"./modules/handle-click":3,"./modules/handle-dom":4,"./modules/handle-key":5,"./modules/handle-swal-dom":6,"./modules/set-params":8,"./modules/utils":9}],2:[function(e,t,n){Object.defineProperty(n,"__esModule",{value:!0});var o={title:"",text:"",type:null,allowOutsideClick:!1,showConfirmButton:!0,showCancelButton:!1,closeOnConfirm:!0,closeOnCancel:!0,confirmButtonText:"OK",confirmButtonColor:"#8CD4F5",cancelButtonText:"Cancel",imageUrl:null,imageSize:null,timer:null,customClass:"",html:!1,animation:!0,allowEscapeKey:!0,inputType:"text",inputPlaceholder:"",inputValue:"",showLoaderOnConfirm:!1};n["default"]=o,t.exports=n["default"]},{}],3:[function(t,n,o){Object.defineProperty(o,"__esModule",{value:!0});var a=t("./utils"),r=(t("./handle-swal-dom"),t("./handle-dom")),s=function(t,n,o){function s(e){m&&n.confirmButtonColor&&(p.style.backgroundColor=e)}var u,c,d,f=t||e.event,p=f.target||f.srcElement,m=-1!==p.className.indexOf("confirm"),v=-1!==p.className.indexOf("sweet-overlay"),y=(0,r.hasClass)(o,"visible"),b=n.doneFunction&&"true"===o.getAttribute("data-has-done-function");switch(m&&n.confirmButtonColor&&(u=n.confirmButtonColor,c=(0,a.colorLuminance)(u,-.04),d=(0,a.colorLuminance)(u,-.14)),f.type){case"mouseover":s(c);break;case"mouseout":s(u);break;case"mousedown":s(d);break;case"mouseup":s(c);break;case"focus":var h=o.querySelector("button.confirm"),g=o.querySelector("button.cancel");m?g.style.boxShadow="none":h.style.boxShadow="none";break;case"click":var w=o===p,C=(0,r.isDescendant)(o,p);if(!w&&!C&&y&&!n.allowOutsideClick)break;m&&b&&y?l(o,n):b&&y||v?i(o,n):(0,r.isDescendant)(o,p)&&"BUTTON"===p.tagName&&sweetAlert.close()}},l=function(e,t){var n=!0;(0,r.hasClass)(e,"show-input")&&(n=e.querySelector("input").value,n||(n="")),t.doneFunction(n),t.closeOnConfirm&&sweetAlert.close(),t.showLoaderOnConfirm&&sweetAlert.disableButtons()},i=function(e,t){var n=String(t.doneFunction).replace(/\s/g,""),o="function("===n.substring(0,9)&&")"!==n.substring(9,10);o&&t.doneFunction(!1),t.closeOnCancel&&sweetAlert.close()};o["default"]={handleButton:s,handleConfirm:l,handleCancel:i},n.exports=o["default"]},{"./handle-dom":4,"./handle-swal-dom":6,"./utils":9}],4:[function(n,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=function(e,t){return new RegExp(" "+t+" ").test(" "+e.className+" ")},s=function(e,t){r(e,t)||(e.className+=" "+t)},l=function(e,t){var n=" "+e.className.replace(/[\t\r\n]/g," ")+" ";if(r(e,t)){for(;n.indexOf(" "+t+" ")>=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},i=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},u=function(e){e.style.opacity="",e.style.display="block"},c=function(e){if(e&&!e.length)return u(e);for(var t=0;t<e.length;++t)u(e[t])},d=function(e){e.style.opacity="",e.style.display="none"},f=function(e){if(e&&!e.length)return d(e);for(var t=0;t<e.length;++t)d(e[t])},p=function(e,t){for(var n=t.parentNode;null!==n;){if(n===e)return!0;n=n.parentNode}return!1},m=function(e){e.style.left="-9999px",e.style.display="block";var t,n=e.clientHeight;return t="undefined"!=typeof getComputedStyle?parseInt(getComputedStyle(e).getPropertyValue("padding-top"),10):parseInt(e.currentStyle.padding),e.style.left="",e.style.display="none","-"+parseInt((n+t)/2)+"px"},v=function(e,t){if(+e.style.opacity<1){t=t||16,e.style.opacity=0,e.style.display="block";var n=+new Date,o=function a(){e.style.opacity=+e.style.opacity+(new Date-n)/100,n=+new Date,+e.style.opacity<1&&setTimeout(a,t)};o()}e.style.display="block"},y=function(e,t){t=t||16,e.style.opacity=1;var n=+new Date,o=function a(){e.style.opacity=+e.style.opacity-(new Date-n)/100,n=+new Date,+e.style.opacity>0?setTimeout(a,t):e.style.display="none"};o()},b=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},h=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)};a.hasClass=r,a.addClass=s,a.removeClass=l,a.escapeHtml=i,a._show=u,a.show=c,a._hide=d,a.hide=f,a.isDescendant=p,a.getTopMargin=m,a.fadeIn=v,a.fadeOut=y,a.fireClick=b,a.stopEventPropagation=h},{}],5:[function(t,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=t("./handle-dom"),s=t("./handle-swal-dom"),l=function(t,o,a){var l=t||e.event,i=l.keyCode||l.which,u=a.querySelector("button.confirm"),c=a.querySelector("button.cancel"),d=a.querySelectorAll("button[tabindex]");if(-1!==[9,13,32,27].indexOf(i)){for(var f=l.target||l.srcElement,p=-1,m=0;m<d.length;m++)if(f===d[m]){p=m;break}9===i?(f=-1===p?u:p===d.length-1?d[0]:d[p+1],(0,r.stopEventPropagation)(l),f.focus(),o.confirmButtonColor&&(0,s.setFocusStyle)(f,o.confirmButtonColor)):13===i?("INPUT"===f.tagName&&(f=u,u.focus()),f=-1===p?u:n):27===i&&o.allowEscapeKey===!0?(f=c,(0,r.fireClick)(f,l)):f=n}};a["default"]=l,o.exports=a["default"]},{"./handle-dom":4,"./handle-swal-dom":6}],6:[function(n,o,a){function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(a,"__esModule",{value:!0});var s=n("./utils"),l=n("./handle-dom"),i=n("./default-params"),u=r(i),c=n("./injected-html"),d=r(c),f=".sweet-alert",p=".sweet-overlay",m=function(){var e=t.createElement("div");for(e.innerHTML=d["default"];e.firstChild;)t.body.appendChild(e.firstChild)},v=function x(){var e=t.querySelector(f);return e||(m(),e=x()),e},y=function(){var e=v();return e?e.querySelector("input"):void 0},b=function(){return t.querySelector(p)},h=function(e,t){var n=(0,s.hexToRgb)(t);e.style.boxShadow="0 0 2px rgba("+n+", 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)"},g=function(n){var o=v();(0,l.fadeIn)(b(),10),(0,l.show)(o),(0,l.addClass)(o,"showSweetAlert"),(0,l.removeClass)(o,"hideSweetAlert"),e.previousActiveElement=t.activeElement;var a=o.querySelector("button.confirm");a.focus(),setTimeout(function(){(0,l.addClass)(o,"visible")},500);var r=o.getAttribute("data-timer");if("null"!==r&&""!==r){var s=n;o.timeout=setTimeout(function(){var e=(s||null)&&"true"===o.getAttribute("data-has-done-function");e?s(null):sweetAlert.close()},r)}},w=function(){var e=v(),t=y();(0,l.removeClass)(e,"show-input"),t.value=u["default"].inputValue,t.setAttribute("type",u["default"].inputType),t.setAttribute("placeholder",u["default"].inputPlaceholder),C()},C=function(e){if(e&&13===e.keyCode)return!1;var t=v(),n=t.querySelector(".sa-input-error");(0,l.removeClass)(n,"show");var o=t.querySelector(".sa-error-container");(0,l.removeClass)(o,"show")},S=function(){var e=v();e.style.marginTop=(0,l.getTopMargin)(v())};a.sweetAlertInitialize=m,a.getModal=v,a.getOverlay=b,a.getInput=y,a.setFocusStyle=h,a.openModal=g,a.resetInput=w,a.resetInputError=C,a.fixVerticalPosition=S},{"./default-params":2,"./handle-dom":4,"./injected-html":7,"./utils":9}],7:[function(e,t,n){Object.defineProperty(n,"__esModule",{value:!0});var o='<div class="sweet-overlay" tabIndex="-1"></div><div class="sweet-alert"><div class="sa-icon sa-error">\n      <span class="sa-x-mark">\n        <span class="sa-line sa-left"></span>\n        <span class="sa-line sa-right"></span>\n      </span>\n    </div><div class="sa-icon sa-warning">\n      <span class="sa-body"></span>\n      <span class="sa-dot"></span>\n    </div><div class="sa-icon sa-info"></div><div class="sa-icon sa-success">\n      <span class="sa-line sa-tip"></span>\n      <span class="sa-line sa-long"></span>\n\n      <div class="sa-placeholder"></div>\n      <div class="sa-fix"></div>\n    </div><div class="sa-icon sa-custom"></div><h2>Title</h2>\n    <p>Text</p>\n    <fieldset>\n      <input type="text" tabIndex="3" />\n      <div class="sa-input-error"></div>\n    </fieldset><div class="sa-error-container">\n      <div class="icon">!</div>\n      <p>Not valid!</p>\n    </div><div class="sa-button-container">\n      <button class="cancel" tabIndex="2">Cancel</button>\n      <div class="sa-confirm-button-container">\n        <button class="confirm" tabIndex="1">OK</button><div class="la-ball-fall">\n          <div></div>\n          <div></div>\n          <div></div>\n        </div>\n      </div>\n    </div></div>';n["default"]=o,t.exports=n["default"]},{}],8:[function(e,t,o){Object.defineProperty(o,"__esModule",{value:!0});var a=e("./utils"),r=e("./handle-swal-dom"),s=e("./handle-dom"),l=["error","warning","info","success","input","prompt"],i=function(e){var t=(0,r.getModal)(),o=t.querySelector("h2"),i=t.querySelector("p"),u=t.querySelector("button.cancel"),c=t.querySelector("button.confirm");if(o.innerHTML=e.html?e.title:(0,s.escapeHtml)(e.title).split("\n").join("<br>"),i.innerHTML=e.html?e.text:(0,s.escapeHtml)(e.text||"").split("\n").join("<br>"),e.text&&(0,s.show)(i),e.customClass)(0,s.addClass)(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var d=t.getAttribute("data-custom-class");(0,s.removeClass)(t,d),t.setAttribute("data-custom-class","")}if((0,s.hide)(t.querySelectorAll(".sa-icon")),e.type&&!(0,a.isIE8)()){var f=function(){for(var o=!1,a=0;a<l.length;a++)if(e.type===l[a]){o=!0;break}if(!o)return logStr("Unknown alert type: "+e.type),{v:!1};var i=["success","error","warning","info"],u=n;-1!==i.indexOf(e.type)&&(u=t.querySelector(".sa-icon.sa-"+e.type),(0,s.show)(u));var c=(0,r.getInput)();switch(e.type){case"success":(0,s.addClass)(u,"animate"),(0,s.addClass)(u.querySelector(".sa-tip"),"animateSuccessTip"),(0,s.addClass)(u.querySelector(".sa-long"),"animateSuccessLong");break;case"error":(0,s.addClass)(u,"animateErrorIcon"),(0,s.addClass)(u.querySelector(".sa-x-mark"),"animateXMark");break;case"warning":(0,s.addClass)(u,"pulseWarning"),(0,s.addClass)(u.querySelector(".sa-body"),"pulseWarningIns"),(0,s.addClass)(u.querySelector(".sa-dot"),"pulseWarningIns");break;case"input":case"prompt":c.setAttribute("type",e.inputType),c.value=e.inputValue,c.setAttribute("placeholder",e.inputPlaceholder),(0,s.addClass)(t,"show-input"),setTimeout(function(){c.focus(),c.addEventListener("keyup",swal.resetInputError)},400)}}();if("object"==typeof f)return f.v}if(e.imageUrl){var p=t.querySelector(".sa-icon.sa-custom");p.style.backgroundImage="url("+e.imageUrl+")",(0,s.show)(p);var m=80,v=80;if(e.imageSize){var y=e.imageSize.toString().split("x"),b=y[0],h=y[1];b&&h?(m=b,v=h):logStr("Parameter imageSize expects value with format WIDTHxHEIGHT, got "+e.imageSize)}p.setAttribute("style",p.getAttribute("style")+"width:"+m+"px; height:"+v+"px")}t.setAttribute("data-has-cancel-button",e.showCancelButton),e.showCancelButton?u.style.display="inline-block":(0,s.hide)(u),t.setAttribute("data-has-confirm-button",e.showConfirmButton),e.showConfirmButton?c.style.display="inline-block":(0,s.hide)(c),e.cancelButtonText&&(u.innerHTML=(0,s.escapeHtml)(e.cancelButtonText)),e.confirmButtonText&&(c.innerHTML=(0,s.escapeHtml)(e.confirmButtonText)),e.confirmButtonColor&&(c.style.backgroundColor=e.confirmButtonColor,c.style.borderLeftColor=e.confirmLoadingButtonColor,c.style.borderRightColor=e.confirmLoadingButtonColor,(0,r.setFocusStyle)(c,e.confirmButtonColor)),t.setAttribute("data-allow-outside-click",e.allowOutsideClick);var g=!!e.doneFunction;t.setAttribute("data-has-done-function",g),e.animation?"string"==typeof e.animation?t.setAttribute("data-animation",e.animation):t.setAttribute("data-animation","pop"):t.setAttribute("data-animation","none"),t.setAttribute("data-timer",e.timer)};o["default"]=i,t.exports=o["default"]},{"./handle-dom":4,"./handle-swal-dom":6,"./utils":9}],9:[function(t,n,o){Object.defineProperty(o,"__esModule",{value:!0});var a=function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e},r=function(e){var t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?parseInt(t[1],16)+", "+parseInt(t[2],16)+", "+parseInt(t[3],16):null},s=function(){return e.attachEvent&&!e.addEventListener},l=function(t){"undefined"!=typeof e&&e.console&&e.console.log("SweetAlert: "+t)},i=function(e,t){e=String(e).replace(/[^0-9a-f]/gi,""),e.length<6&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),t=t||0;var n,o,a="#";for(o=0;3>o;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a};o.extend=a,o.hexToRgb=r,o.isIE8=s,o.logStr=l,o.colorLuminance=i},{}]},{},[1]),"function"==typeof define&&define.amd?define(function(){return sweetAlert}):"undefined"!=typeof module&&module.exports&&(module.exports=sweetAlert)}(window,document);

模板文件進行修改,關聯提示框靜態資源文件

模板文件templates/cms/cms_base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--  在頭文件中接收csrf信息  -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{% block title %}

    {% endblock %}</title>
    <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>

<!--  關聯本地的cms_base.css樣式 後臺管理界面CMS的樣式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='cms/css/cms_base.css') }}">
<!--  關聯本地的cms_base.js樣式 後臺管理界面CMS的樣式 -->
    <script src="{{ url_for('static', filename='cms/js/cms_base.js') }}"></script>

<!--  提示框的靜態資源文件  -->
    <link rel="stylesheet" href="{{ url_for('static', filename='common/sweetalert/sweetalert.css') }}">
<!-- 關聯提示框的js樣式  -->
    <script src="{{ url_for('static', filename='common/sweetalert/lgalert.js') }}"></script>
    <script src="{{ url_for('static', filename='common/sweetalert/sweetalert.min.js') }}"></script>

<!--  預留空間,給之後的html文件進行修改調整  -->
    {% block head %}

    {% endblock %}

</head>
<body>
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <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="#">論壇CMS管理系統</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
        <!--       從數據庫中調用用戶名,g對象全局調用g.cms_user對象  .username是該對象的一個字段屬性      -->
            <li><a href="#">{{ g.cms_user.username }}<span>[超級管理員]</span></a></li>

        <!--  用戶註銷,關聯到views.py中的@cms_bp.route("/logout/")路由,重定向到該路由      -->
            <li><a href="{{ url_for('cms.logout') }}">註銷</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="查找...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
              <ul class="nav-sidebar">
                <li class="unfold"><a href="#">首頁</a></li>
                <li class="profile-li">
                    <a href="#">個人中心<span></span></a>
                    <ul class="subnav">

                        <!--          url重定向到/cms/profile/下   這個路由在views.py中定義了       -->
                        <li><a href="{{ url_for('cms.profile') }}">個人信息</a></li>
                        <!--           密碼修改的url_for 重定向到/cms/resetpwd/  路由在views.py中定義了           -->
                        <li><a href="{{ url_for('cms.resetpwd') }}">修改密碼</a></li>
                        <!--         修改郵箱的url_for        -->
                        <li><a href="#">修改郵箱</a></li>
                    </ul>
                </li>

                <li class="nav-group post-manage"><a href="#">帖子管理</a></li>
                <li class="comments-manage"><a href="#">評論管理</a></li>
                <li class="board-manage"><a href="#">板塊管理</a></li>

                <li class="nav-group user-manage"><a href="#">用戶管理</a></li>
                <li class="role-manage"><a href="#">組管理</a></li>

                <li class="nav-group cmsuser-manage"><a href="#">CMS用戶管理</a></li>
                <li class="cmsrole-manage"><a href="#">CMS組管理</a></li>
            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1>{% block page_title %}

            {% endblock %}</h1>
            <div class="main_content">
                {% block content %}

                {% endblock %}
            </div>
          </div>
      </div>
    </div>
</body>
</html>

還需要修改ajax中的返回彈窗信息message信息:
靜態文件:static/cms/css/resetpwd.js


$(function () {
    // #綁定submit按鈕
    $("#submit").click(function (event) {
        // event.preventDefault
        // 是阻止按鈕默認的提交表單的事件
        event.preventDefault();

        // 獲取input表單中的值
        var oldpwdE = $("input[name=oldpwd]");
        var newpwdE = $("input[name=newpwd]");
        var newpwd2E = $("input[name=newpwd2]");

        var oldpwd = oldpwdE.val();
        var newpwd = newpwdE.val();
        var newpwd2 = newpwd2E.val();

        // 1. 要在模版的meta標籤中渲染一個csrf-token
        // 2. 在ajax請求的頭部中設置X-CSRFtoken
        var lgajax = {
            '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方法
                    'beforeSend':function(xhr,settings) {
                        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {

                            // 請求之前發送csrf信息   將csrf信息name=csrf-token和content傳遞給cms_base.html頭文件
                            var csrftoken = $('meta[name=csrf-token]').attr('content');
                            // var csrftoken = $('input[name=csrf-token]').attr('value');
                            xhr.setRequestHeader("X-CSRFToken", csrftoken)
                        }
                    }
                });
            }
        };

        // 表單提交方法:post提交
        lgajax.post({
            'url': '/cms/resetpwd/',      // 表單發送地址必須要和views.py中綁定的url地址相同
            'data': {                     // 表單發送數據
                'oldpwd': oldpwd,
                'newpwd': newpwd,
                'newpwd2': newpwd2
            },
            'success': function (data) {     // 表單提交成功
                // console.log(data);

            //  信息返回給彈窗進行顯示在html頁面
                if(data['code'] == 200){
                    lgalert.alertSuccess("密碼修改成功")

                    // 修改密碼的輸入框清空
                    oldpwd.val("")
                    newpwd.val("")
                    newpwd2.val("")

                }else{
                    var message = data['message']    // 修改不成功
                    lgalert.alertInfo(message)       // 彈出錯誤信息

                    // 清空輸入框
                    oldpwd.val("")
                    newpwd.val("")
                    newpwd2.val("")

                }
            },
            'fail': function (error) {               // 表單提交失敗
                // console.log(error);
                lgalert.alertNetworkError()          // 彈出網絡錯誤

                // 清空輸入框
                oldpwd.val("")
                newpwd.val("")
                newpwd2.val("")
            }
        });
    });
});

需要注意的是:在ajax中的url綁定地址一定要和views.py中類視圖函數添加綁定路由綁定的url地址相同!即下面代碼中綁定的url地址

視圖文件:apps/cms/views.py文件

# 類視圖函數添加綁定路由  注意類視圖需要修改ResetPwd.as_view('resetpwd')
cms_bp.add_url_rule("/resetpwd/", view_func=ResetPwd.as_view('resetpwd'))  # view_func 命名操作名字,/resetpwd/路由地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章