CheckFilter/SelectFilter过滤器组件

效果图

views.py

class CheckFilter(object):
    def __init__(self, name, data_list, request):
        self.name = name
        self.data_list = data_list
        self.request = request

    def __iter__(self):
        for item in self.data_list:
            key = str(item[0])
            text = item[1]
            ck = ''
            # 如果url中过滤字段和循环的key相等,则默认checked为True
            value_list = self.request.GET.getlist(self.name)
            if key in value_list:
                ck = 'checked'
                value_list.remove(key)
            else:
                value_list.append(key)

            from django.http import QueryDict
            query_dict = self.request.GET.copy()
            query_dict._mutable = True
            query_dict.setlist(self.name, value_list)
            # 如果筛选的内容不足一页
            if 'page' in query_dict:
                query_dict.pop('page')

            param_url = query_dict.urlencode()  # status=1&status=2&xx=3

            if param_url:
                url = '{}?{}'.format(self.request.path_info, param_url)
            else:
                url = self.request.path_info

            tpl = '<a class="cell" href="{url}"><input type="checkbox" {ck} /><label>{text}</label></a>'
            html = tpl.format(url=url, ck=ck, text=text)
            yield mark_safe(html)  # 生成器生成标签


class SelectFilter(object):
    def __init__(self, name, data_list, request):
        self.name = name
        self.data_list = data_list
        self.request = request

    def __iter__(self):
        yield mark_safe("<select class='select2' multiple='multiple' style='width: 100%;'>")
        for item in self.data_list:
            key = str(item[0])
            text = item[1]

            selected = ''
            value_list = self.request.GET.getlist(self.name)
            if key in value_list:
                selected = 'selected'
                value_list.remove(key)
            else:
                value_list.append(key)

            query_dict = self.request.GET.copy()
            query_dict._mutable = True
            query_dict.setlist(self.name, value_list)
            if 'page' in query_dict:
                query_dict.pop('page')

            param_url = query_dict.urlencode()
            if param_url:
                url = '{}?{}'.format(self.request.path_info, param_url)
            else:
                url = self.request.path_info
            html = "<option value='{url}' {selected}>{text}</option>".format(url=url, selected=selected, text=text)
            yield mark_safe(html)
        yield mark_safe("</select>")


def issues(request, project_id):
    """创建问题、问题列表"""
    if request.method == 'GET':
        # 根据URL中get传参来过滤筛选
        allow_filter_name = ['issues_type', 'status', 'priority', 'assign', 'attention']
        condition = {}
        for item in allow_filter_name:
            value_list = request.GET.getlist(item)
            if not value_list:
                continue
            condition['{}__in'.format(item)] = value_list

            """
            condition = {
                "status__in":[1,2],
                'issues_type__in':[1,]
            }
            """

        form = IssuesModelForm(request)
        queryset = models.Issues.objects.filter(project_id=project_id).filter(**condition)

        page_obj = Pagination(current_page=request.GET.get('page'), all_count=queryset.count(),
                              base_url=request.path_info, query_params=request.GET, per_page=10)
        issues_obj_list = queryset[page_obj.start: page_obj.end]

        project_issues_type = models.IssuesType.objects.filter(project_id=project_id).values_list('id', 'title')

        project_total_user = [(request.tracer.project.creator_id, request.tracer.project.creator.username), ]
        project_join_user = models.ProjectUser.objects.filter(project_id=project_id).values_list('user_id',
                                                                                                 'user__username')  # 项目参与者
        project_total_user.extend(project_join_user)  # 项目创建者+项目参与者

        invite_form = InviteFormModelForm()
        context = {
            'form': form,
            'issues_obj_list': issues_obj_list,
            'page_html': page_obj.page_html(),
            'invite_form': invite_form,
            'filter_list': [
                # FK字段
                {'title': '问题类型', 'filter': CheckFilter('issues_type', project_issues_type, request)},
                # choices字段
                {'title': '状态', 'filter': CheckFilter('status', models.Issues.status_choices, request)},
                {'title': '优先级', 'filter': CheckFilter('priority', models.Issues.priority_choices, request)},
                # select筛选
                {'title': '指派者', 'filter': SelectFilter('assign', project_total_user, request)},
                {'title': '关注者', 'filter': SelectFilter('attention', project_total_user, request)},
            ]
        }
        return render(request, 'manage/issues.html', context)

    form = IssuesModelForm(request, data=request.POST)
    if form.is_valid():
        form.instance.project = request.tracer.project
        form.instance.creator = request.tracer
        form.save()
        return JsonResponse({'status': True})
    return JsonResponse({'status': False, 'errors': form.errors})

html

{% extends 'layout/manage.html' %}
{% load static %}
{% load issues %}

{% block css %}
    <link rel="stylesheet" href="{% static 'plugin/editor-md/css/editormd.min.css' %}">
    <link rel="stylesheet" href="{% static 'plugin/bootstrap-datepicker/css/bootstrap-datepicker.min.css' %}">
    <link rel="stylesheet" href="{% static 'plugin/bootstrap-select/css/bootstrap-select.min.css' %}">
    <link rel="stylesheet" href="{% static 'plugin/select2/css/select2.min.css' %}">
    <style>
        .issues-list .number {
            width: 100px;
            text-align: right;
        }

        .issues-list .number a {
            font-weight: 500;
            padding: 0 10px;
        }

        .issues-list .issue .tags {
            padding: 10px 0;
        }

        .issues-list .issue .tags span {
            margin-right: 20px;
            display: inline-block;
            font-size: 12px;
        }

        .issues-list .issue .tags .type {
            color: white;
            padding: 1px 5px;
            border-radius: 5px;
            background-color: #dddddd;
        }

        .editormd {
            margin-bottom: 0;
        }

        .pd-0 {
            padding: 0 !important;
        }

        /* 筛选 */
        .filter-area .item {
            margin-bottom: 15px;
        }

        .filter-area .item .title {
            padding: 5px 0;
        }

        .filter-area .item .check-list a {
            text-decoration: none;
            display: inline-block;
            min-width: 65px;
        }

        .filter-area .item .check-list label {
            font-weight: 200;
            font-size: 13px;
            margin-left: 3px;
        }

        .filter-area .item .check-list a:hover {
            font-weight: 300;
        }

        .filter-area .item .check-list .cell {
            margin-right: 10px;
        }
    </style>
{% endblock %}

{% block content %}
    <div class="container-fluid clearfix" style="padding: 20px 0;">
        <div class="col-sm-3">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <i class="fa fa-search" aria-hidden="true"></i> 筛选
                </div>
                <div class="panel-body filter-area">
                   {% for row in filter_list %}
                        <div class="item">
                            <div class="title">{{ row.title }}</div>
                            <div class="check-list">
                                {% for item in row.filter %}
                                    {{ item }}
                                {% endfor %}
                            </div>
                        </div>
                    {% endfor %}

                </div>
            </div>
        </div>
        <div class="col-sm-9">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <i class="fa fa-quora" aria-hidden="true"></i> 问题
                </div>
                <div class="panel-body">
                    <a class="btn btn-success btn-sm" data-toggle="modal" data-target="#addModal">新建问题</a>
                    <a class="btn btn-primary btn-sm" data-toggle="modal" data-target="#inviteModal">邀请成员</a>
                </div>
                <table class="table">

                    <tbody class="issues-list">
                    {% for item in issues_obj_list %}
                        <tr>
                            <td class="number">
                                <i class="fa fa-circle text-{{ item.priority }}"></i>
                                <a target="_blank" href="{% url 'manage:issues_detail' project_id=request.tracer.project.id issues_id=item.id %}">{% string_just item.id %}</a>
                            </td>
                            <td class="issue">
                                <div>
                                    <a target="_blank"
                                       href="{% url 'manage:issues_detail' project_id=request.tracer.project.id issues_id=item.id %}">{{ item.subject }}</a>
                                </div>
                                <div class="tags">
                                    <span class="type">
                                        {{ item.issues_type.title }}
                                    </span>
                                    <span>
                                        <i class="fa fa-refresh" aria-hidden="true"></i>
                                        {{ item.get_status_display }}
                                    </span>
                                    {% if item.assign %}
                                        <span>
                                        <i class="fa fa-hand-o-right" aria-hidden="true"></i>
                                        {{ item.assign.username }}
                                    </span>
                                    {% endif %}

                                    <span>
                                        <i class="fa fa-user-o" aria-hidden="true"></i>
                                        {{ item.creator.username }}
                                    </span>
                                    {% if item.end_date %}
                                        <span><i class="fa fa-calendar"
                                                 aria-hidden="true"></i> {{ item.end_date }} 截止</span>
                                    {% endif %}
                                    <span><i class="fa fa-clock-o"
                                             aria-hidden="true"></i> {{ item.latest_update_datetime }} 更新</span>
                                </div>
                            </td>
                        </tr>
                    {% endfor %}

                    </tbody>
                </table>
            </div>

            <nav aria-label="...">
                <ul class="pagination" style="margin-top: 0;">
                    {{ page_html|safe }}
                </ul>
            </nav>
        </div>

    </div>


    <div id="addModal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog"
         aria-labelledby="myLargeModalLabel">
        <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                            aria-hidden="true">&times;</span></button>
                    <h4 class="modal-title">新建问题</h4>
                </div>
                <div class="modal-body" style="padding-right: 40px;">

                    <form id="addForm" class="form-horizontal">
                        {% csrf_token %}
                        <!-- 问题类型 -->
                        <div class="form-group">
                            <label for="{{ form.issues_type.id_for_label }}"
                                   class="col-md-2 control-label">{{ form.issues_type.label }}</label>
                            <div class="col-md-10">
                                <div>
                                    <div>
                                        {{ form.issues_type }}
                                    </div>
                                    <div class="error-msg"></div>
                                </div>
                                <div class="error-msg"></div>
                            </div>
                        </div>
                        <!-- 主题 -->
                        <div class="form-group">
                            <label for="{{ form.subject.id_for_label }}"
                                   class="col-md-2 control-label">{{ form.subject.label }}</label>
                            <div class="col-md-10">
                                <div>
                                    <div>
                                        {{ form.subject }}
                                    </div>
                                    <div class="error-msg"></div>
                                </div>
                                <div class="error-msg"></div>
                            </div>
                        </div>
                        <!-- 模块 -->
                        <div class="form-group">
                            <label for="{{ form.module.id_for_label }}"
                                   class="col-md-2 control-label">{{ form.module.label }}</label>
                            <div class="col-md-10">
                                <div>
                                    <div>
                                        {{ form.module }}
                                    </div>
                                    <div class="error-msg"></div>
                                </div>
                                <div class="error-msg"></div>
                            </div>
                        </div>
                        <!-- 问题描述 -->
                        <div class="form-group">
                            <label for="{{ form.desc.id_for_label }}"
                                   class="col-md-2 control-label">{{ form.desc.label }}</label>
                            <div class="col-md-10">
                                <div>
                                    <div id="editor">
                                        {{ form.desc }}
                                    </div>

                                    <div class="error-msg"></div>
                                </div>
                                <div class="error-msg"></div>
                            </div>
                        </div>

                        <div class="form-group clearfix">

                            <!-- 状态 -->
                            <div class="col-md-6 pd-0">
                                <label for="{{ form.status.id_for_label }}"
                                       class="col-md-4 control-label">{{ form.status.label }}</label>
                                <div class="col-md-8 clearfix">
                                    <div>
                                        {{ form.status }}
                                    </div>
                                    <div class="error-msg"></div>

                                </div>
                            </div>
                            <!-- 优先级 -->
                            <div class="col-md-6 pd-0">
                                <label for=" {{ form.priority.id_for_label }}"
                                       class="col-md-4 control-label">{{ form.priority.label }}</label>
                                <div class="col-md-8">
                                    <div>
                                        {{ form.priority }}
                                    </div>
                                    <div class="error-msg"></div>

                                </div>
                            </div>
                        </div>

                        <div class="form-group clearfix">
                            <!-- 指派给 -->
                            <div class="col-md-6 pd-0">
                                <label for="inputPassword3" class="col-md-4 control-label">指派给</label>
                                <div class="col-md-8">
                                    {{ form.assign }}
                                    <div class="error-msg"></div>
                                </div>
                            </div>

                            <!-- 关注者 -->
                            <div class="col-md-6 pd-0">
                                <label for="inputPassword3" class="col-md-4 control-label">关注者</label>
                                <div class="col-md-8">

                                    {{ form.attention }}

                                    <div class="error-msg"></div>
                                </div>
                            </div>
                        </div>


                        <div class="form-group clearfix">
                             <!-- 开始时间 -->
                            <div class="col-md-6 pd-0">
                                <label for="inputPassword3" class="col-md-4 control-label">开始时间</label>
                                <div class="col-md-8">

                                    <div class="input-group">
                                        <span class="input-group-addon" id="sizing-addon2">
                                            <i class="fa fa-calendar" aria-hidden="true"></i>
                                        </span>
                                        {{ form.start_date }}
                                    </div>
                                    <span class="error-msg"></span>

                                </div>
                            </div>

                            <!-- 截止时间 -->
                            <div class="col-md-6 pd-0">
                                <label for="inputPassword3" class="col-md-4 control-label">截止时间</label>
                                <div class="col-md-8">

                                    <div class="input-group">
                                        <span class="input-group-addon" id="sizing-addon2">
                                            <i class="fa fa-calendar" aria-hidden="true"></i>
                                        </span>
                                        {{ form.end_date }}
                                    </div>
                                    <span class="error-msg"></span>
                                </div>
                            </div>
                        </div>
                        <div class="form-group clearfix">
                            <!-- 模式 -->
                            <div class="col-md-6 pd-0">
                                <label for="inputPassword3" class="col-md-4 control-label">模式</label>
                                <div class="col-md-8">
                                    <div>
                                        {{ form.mode }}
                                    </div>
                                    <div class="error-msg"></div>
                                </div>
                            </div>

                            <!-- 父问题 -->
                            <div class="col-md-6 pd-0">
                                <label for="inputPassword3" class="col-md-4 control-label"> 父问题</label>
                                <div class="col-md-8">

                                    {{ form.parent }}

                                    <div class="error-msg"></div>
                                </div>
                            </div>
                        </div>

                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
                    <button type="button" class="btn btn-primary" id="btnAddSubmit">添 加</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade in" id="inviteModal" role="dialog">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                            aria-hidden="true">&times;</span></button>
                    <h4 class="modal-title" id="myModalLabel">邀请成员</h4>
                </div>
                <div class="modal-body" style="padding-right: 40px;">
                    <form id="inviteForm">
                        {% csrf_token %}
                        {% for item in invite_form %}
                            <div class="form-group">
                                <label for="{{ item.id_for_label }}">{{ item.label }}</label>
                                <span>{% if  item.help_text %}({{ item.help_text }}){% endif %}</span>
                                {{ item }}
                                <span class="error-msg"></span>
                            </div>
                        {% endfor %}
                        <button type="button" class="btn btn-success" id="btnGenInviteCode">生成邀请码</button>
                    </form>
                    <div id="inviteArea" class="hide">
                        <hr/>
                        <div class="form-group">
                            <div class="input-group">
                                <div class="input-group-btn">
                                    <input type="button" value="邀请链接" class="btn btn-default">
                                </div>
                                <input type="text" class="form-control" id="inviteUrl">
                                <div class="input-group-btn">
                                    <input type="button" value="复制链接" class="btn btn-primary" id="btnCopyUrl">
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

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


{% block js %}
    <script src="{% static 'plugin/editor-md/editormd.min.js' %}"></script>
    <script src="{% static 'plugin/bootstrap-datepicker/js/bootstrap-datepicker.min.js' %}"></script>
    <script src="{% static 'plugin/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js' %}"></script>
    <script src="{% static 'plugin/bootstrap-select/js/bootstrap-select.min.js' %}"></script>
    <script src="{% static 'plugin/bootstrap-select/js/i18n/defaults-zh_CN.min.js' %}"></script>
    <script src="{% static 'plugin/select2/js/select2.min.js' %}"></script>
    <script src="{% static 'plugin/select2/js/i18n/zh-CN.js' %}"></script>
    <script>
    var WIKI_UPLOAD_URL = "{% url 'manage:wiki_upload' project_id=request.tracer.project.id %}";
    var POST_ISSUES = "{% url 'manage:issues' project_id=request.tracer.project.id %}";
    var INVITE_URL = "{% url 'manage:invite_url' project_id=request.tracer.project.id %}";

    $(function () {
        bindBootStrapShownEvent();
        initDatePicker();
        bindAddSubmit();
        bindClickCheckBox();
        initSelect2();
        bindCreateInviteCode();
        bindCopyUrl();
    })
    // 复制邀请码
    function bindCopyUrl() {
        $('#btnCopyUrl').click(function () {
            var textInput = $('#inviteUrl')[0];
            textInput.select();
            document.execCommand('Copy');
            alert('复制邀请码成功!')
        })
    }
    // 生成邀请码
    function bindCreateInviteCode() {
        $('#btnGenInviteCode').click(function () {
            $('.error-msg').empty()
            $.ajax({
                url: INVITE_URL,
                type: 'POST',
                data: $('#inviteForm').serialize(),
                dataType: 'JSON',
                success: function (res) {
                    if(res.status){
                        $('#inviteArea').removeClass('hide').find('#inviteUrl').val(res.data);
                    }else {
                        $.each(res.errors, function (k, v) {
                            $('#id_' + k).next('.error-msg').text(v[0]);
                        })
                    }
                }
            })
        })
    }
    // 初始化select2标签
    function initSelect2() {
        $('.select2').select2({}).on('select2:select', function (e) {
            // 选中某一项触发
            {#console.log(e);#}
            location.href = e.params.data.id;
        }).on('select2:unselect', function (e) {
            // 取消选中某一项触发
            location.href = e.params.data.id;
        })
    }
    // 点击checkbox进行筛选
    function bindClickCheckBox() {
        $('.filter-area').find(':checkbox').click(function () {
            location.href = $(this).parent().attr('href');
        })
    }

    // 添加问题
    function bindAddSubmit() {
        $('#btnAddSubmit').click(function () {
            $.ajax({
                url: POST_ISSUES,
                type: 'POST',
                data: $('#addForm').serialize(),
                dataType: 'JSON',
                success: function (res) {
                    if(res.status){
                        location.href = location.href;
                    }else {
                        $.each(res.errors, function (k, v) {
                            $('#id_' + k).parent().next('.error-msg').text(v[0]);
                        })
                    }
                }
            })
        })
    }

    /*
    添加对话框:初始化时间选择
     */
    function initDatePicker() {

        $('#id_start_date,#id_end_date').datepicker({
            format: 'yyyy-mm-dd',
            startDate: '0',
            language: "zh-CN",
            clearBtn: true,  //清除按钮
            autoclose: true
        });
    }

    function bindBootStrapShownEvent() {
            $('#addModal').on('shown.bs.modal', function (event) {
                // 对话框弹出时,内容触发。
                initEditorMd();
            })
        }

    /*
    初始化markdown编辑器(textarea转换为编辑器)
     */
    function initEditorMd() {
        editormd('editor', {
            placeholder: "请输入内容",
            height: 300,
            path: "{% static 'plugin/editor-md/lib/' %}",
            imageUpload: true,
            imageFormats: ["jpg", 'jpeg', 'png', 'gif'],
            imageUploadURL: WIKI_UPLOAD_URL
        })
    }
    </script>
{% endblock %}

posted @ 2023-01-02 07:41  凫弥  阅读(114)  评论(0编辑  收藏  举报