Initial project commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<link rel="stylesheet" href="{{ url_for('admin:statics', path='css/tabler.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('admin:statics', path='css/tabler-icons.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('admin:statics', path='css/fontawesome.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('admin:statics', path='css/select2.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('admin:statics', path='css/flatpickr.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('admin:statics', path='css/main.css') }}">
|
||||
{% if admin.favicon_url %}
|
||||
<link rel="icon" href="{{ admin.favicon_url }}">
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="/static/admin/custom.css">
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
<title>{{ admin.title }}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block body %}
|
||||
<main>
|
||||
{% block main %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
{% endblock %}
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/jquery.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/tabler.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/popper.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/bootstrap.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/select2.full.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/flatpickr.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('admin:statics', path='js/main.js') }}"></script>
|
||||
<script type="text/javascript" src="/static/admin/i18n.js"></script>
|
||||
<script type="text/javascript" src="/static/admin/image-picker.js"></script>
|
||||
{% block tail %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,38 @@
|
||||
{% extends "sqladmin/layout.html" %}
|
||||
{% from 'sqladmin/_macros.html' import render_form_fields %}
|
||||
{% block content %}
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">新建 {{ model_view.name }}</h3>
|
||||
</div>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<form action="{{ url_for('admin:create', identity=model_view.identity) }}" method="POST"
|
||||
enctype="multipart/form-data">
|
||||
<div class="row">
|
||||
{% if error %}
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ render_form_fields(form, form_opts=form_opts) }}
|
||||
</fieldset>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="{{ url_for('admin:list', identity=model_view.identity) }}" class="btn">
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="btn-group flex-wrap" data-toggle="buttons">
|
||||
<input type="submit" name="save" value="Save" class="btn btn-primary">
|
||||
<input type="submit" name="save" value="Save and continue editing" class="btn">
|
||||
<input type="submit" name="save" value="Save and add another" class="btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,106 @@
|
||||
{% extends "sqladmin/layout.html" %}
|
||||
{% block content %}
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
{% for pk in model_view.pk_columns -%}
|
||||
{{ pk.name | title }}
|
||||
{%- if not loop.last %};{% endif -%}
|
||||
{% endfor %}: {{ get_object_identifier(model) }}</h3>
|
||||
</div>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<div class="table-responsive">
|
||||
<table class="table card-table table-vcenter text-nowrap table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">字段</th>
|
||||
<th class="w-1">值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for name in model_view._details_prop_names %}
|
||||
{% set label = model_view._column_labels.get(name, name) %}
|
||||
<tr>
|
||||
<td>{{ label }}</td>
|
||||
{% set value, formatted_value = model_view.get_detail_value(model, name) %}
|
||||
{% if name in model_view._relation_names %}
|
||||
{% if is_list( value ) %}
|
||||
<td>
|
||||
{% for elem, formatted_elem in zip(value, formatted_value) %}
|
||||
{% if model_view.show_compact_lists %}
|
||||
<a href="{{ model_view._build_url_for('admin:details', request, elem) }}">({{ formatted_elem }})</a>
|
||||
{% else %}
|
||||
<a href="{{ model_view._build_url_for('admin:details', request, elem) }}">{{ formatted_elem }}</a><br/>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% else %}
|
||||
<td><a href="{{ model_view._url_for_details_with_prop(request, model, name) }}">{{ formatted_value }}</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<td>{{ formatted_value }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer container">
|
||||
<div class="row row-gap-2">
|
||||
<div class="col-auto">
|
||||
<a href="{{ url_for('admin:list', identity=model_view.identity) }}" class="btn">
|
||||
返回列表
|
||||
</a>
|
||||
</div>
|
||||
{% if model_view.can_delete %}
|
||||
<div class="col-auto">
|
||||
<a href="#" data-name="{{ model_view.name }}" data-pk="{{ get_object_identifier(model) }}"
|
||||
data-url="{{ model_view._url_for_delete(request, model) }}" data-bs-toggle="modal"
|
||||
data-bs-target="#modal-delete" class="btn btn-danger">
|
||||
删除
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if model_view.can_edit %}
|
||||
<div class="col-auto">
|
||||
<a href="{{ model_view._build_url_for('admin:edit', request, model) }}" class="btn btn-primary">
|
||||
编辑
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for custom_action,label in model_view._custom_actions_in_detail.items() %}
|
||||
<div class="col-auto">
|
||||
{% if custom_action in model_view._custom_actions_confirmation %}
|
||||
<a href="#" class="btn btn-secondary" data-bs-toggle="modal"
|
||||
data-bs-target="#modal-confirmation-{{ custom_action }}">
|
||||
{{ label }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ model_view._url_for_action(request, custom_action) }}?pks={{ get_object_identifier(model) }}"
|
||||
class="btn btn-secondary">
|
||||
{{ label }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if model_view.can_delete %}
|
||||
{% include 'sqladmin/modals/delete.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% for custom_action in model_view._custom_actions_in_detail %}
|
||||
{% if custom_action in model_view._custom_actions_confirmation %}
|
||||
{% with confirmation_message = model_view._custom_actions_confirmation[custom_action], custom_action=custom_action,
|
||||
url=model_view._url_for_action(request, custom_action) + '?pks=' + (get_object_identifier(model) | string) %}
|
||||
{% include 'sqladmin/modals/details_action_confirmation.html' %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,44 @@
|
||||
{% extends "sqladmin/layout.html" %}
|
||||
{% from 'sqladmin/_macros.html' import render_form_fields %}
|
||||
{% block content %}
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">编辑 {{ model_view.name }}</h3>
|
||||
</div>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<form action="{{ model_view._build_url_for('admin:edit', request, obj) }}" method="POST"
|
||||
enctype="multipart/form-data">
|
||||
<div class="row">
|
||||
{% if error %}
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<fieldset class="form-fieldset">
|
||||
{{ render_form_fields(form, form_opts=form_opts) }}
|
||||
</fieldset>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<a href="{{ url_for('admin:list', identity=model_view.identity) }}" class="btn">
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="btn-group flex-wrap" data-toggle="buttons">
|
||||
<input type="submit" name="save" value="Save" class="btn btn-primary">
|
||||
<input type="submit" name="save" value="Save and continue editing" class="btn">
|
||||
{% if model_view.can_create %}
|
||||
{% if model_view.save_as %}
|
||||
<input type="submit" name="save" value="Save as new" class="btn">
|
||||
{% else %}
|
||||
<input type="submit" name="save" value="Save and add another" class="btn">
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,55 @@
|
||||
{% extends "sqladmin/base.html" %}
|
||||
{% from 'sqladmin/_macros.html' import display_menu %}
|
||||
{% block body %}
|
||||
<div class="wrapper">
|
||||
<aside class="navbar navbar-expand-lg navbar-vertical navbar-expand-md navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<h1 class="navbar-brand navbar-brand-autodark">
|
||||
<a href="{{ url_for('admin:index') }}">
|
||||
{% if admin.logo_url %}
|
||||
<img src="{{ admin.logo_url }}" width="64" height="64" alt="Admin" class="navbar-brand-image" />
|
||||
{% else %}
|
||||
<h3>{{ admin.title }}</h3>
|
||||
{% endif %}
|
||||
</a>
|
||||
</h1>
|
||||
<nav class="navbar navbar-expand-sm" id="navbar-menu">
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
{{ display_menu(admin._menu, request) }}
|
||||
</div>
|
||||
</nav>
|
||||
{% if admin.authentication_backend %}
|
||||
<a href="{{ request.url_for('admin:logout') }}" class="btn btn-secondary btn-icon">
|
||||
<i class="fa fa-sign-out"></i>
|
||||
<span>退出登录</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</aside>
|
||||
<div class="page-wrapper">
|
||||
<div class="container-fluid">
|
||||
<div class="page-header d-print-none">
|
||||
{% block content_header %}
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
<div class="page-pretitle">{{ subtitle }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-body flex-grow-1">
|
||||
<div class="container-fluid">
|
||||
<div class="row row-deck row-cards">
|
||||
{% block content %} {% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,304 @@
|
||||
{% extends "sqladmin/layout.html" %}
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1 me-2">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">{{ model_view.name_plural }}</h3>
|
||||
<div class="ms-auto">
|
||||
{% if model_view.can_export %}
|
||||
{% if model_view.export_types | length > 1 %}
|
||||
<div class="ms-3 d-inline-block dropdown">
|
||||
<a href="#" class="btn btn-secondary dropdown-toggle" id="dropdownMenuButton1" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
导出
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
|
||||
{% for export_type in model_view.export_types %}
|
||||
<li><a class="dropdown-item"
|
||||
href="{{ url_for('admin:export', identity=model_view.identity, export_type=export_type) }}">{{
|
||||
export_type | upper }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% elif model_view.export_types | length == 1 %}
|
||||
<div class="ms-3 d-inline-block">
|
||||
<a href="{{ url_for('admin:export', identity=model_view.identity, export_type=model_view.export_types[0]) }}"
|
||||
class="btn btn-secondary">
|
||||
导出
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if model_view.can_create %}
|
||||
<div class="ms-3 d-inline-block">
|
||||
<a href="{{ url_for('admin:create', identity=model_view.identity) }}" class="btn btn-primary">
|
||||
+ 新建{{ model_view.name }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="dropdown col-4">
|
||||
<button {% if not model_view.can_delete and not model_view._custom_actions_in_list %} disabled {% endif %}
|
||||
class="btn btn-light dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
批量操作
|
||||
</button>
|
||||
{% if model_view.can_delete or model_view._custom_actions_in_list %}
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
{% if model_view.can_delete %}
|
||||
<a class="dropdown-item" id="action-delete" href="#" data-name="{{ model_view.name }}"
|
||||
data-url="{{ url_for('admin:delete', identity=model_view.identity) }}" data-bs-toggle="modal"
|
||||
data-bs-target="#modal-delete">删除选中项</a>
|
||||
{% endif %}
|
||||
{% for custom_action, label in model_view._custom_actions_in_list.items() %}
|
||||
{% if custom_action in model_view._custom_actions_confirmation %}
|
||||
<a class="dropdown-item" id="action-customconfirm-{{ custom_action }}" href="#" data-bs-toggle="modal"
|
||||
data-bs-target="#modal-confirmation-{{ custom_action }}">
|
||||
{{ label }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a class="dropdown-item" id="action-custom-{{ custom_action }}" href="#"
|
||||
data-url="{{ model_view._url_for_action(request, custom_action) }}">
|
||||
{{ label }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if model_view.column_searchable_list %}
|
||||
<div class="col-md-4 text-muted">
|
||||
<div class="input-group">
|
||||
<input id="search-input" type="text" class="form-control"
|
||||
placeholder="搜索:{{ model_view.search_placeholder() }}"
|
||||
value="{{ request.query_params.get('search', '') }}">
|
||||
<button id="search-button" class="btn" type="button">搜索</button>
|
||||
<button id="search-reset" class="btn" type="button" {% if not request.query_params.get('search')
|
||||
%}disabled{% endif %}><i class="fa-solid fa-times"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table card-table table-vcenter text-nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1"><input class="form-check-input m-0 align-middle" type="checkbox" aria-label="全选"
|
||||
id="select-all"></th>
|
||||
<th class="w-1">操作</th>
|
||||
{% for name in model_view._list_prop_names %}
|
||||
{% set label = model_view._column_labels.get(name, name) %}
|
||||
<th>
|
||||
{% if name in model_view._sort_fields %}
|
||||
{% if request.query_params.get("sortBy") == name and request.query_params.get("sort") == "asc" %}
|
||||
<a href="{{ request.url.include_query_params(sort='desc') }}"><i class="fa-solid fa-arrow-up"></i> {{
|
||||
label }}</a>
|
||||
{% elif request.query_params.get("sortBy") == name and request.query_params.get("sort") == "desc" %}
|
||||
<a href="{{ request.url.include_query_params(sort='asc') }}"><i class="fa-solid fa-arrow-down"></i> {{ label
|
||||
}}</a>
|
||||
{% else %}
|
||||
<a href="{{ request.url.include_query_params(sortBy=name, sort='asc') }}">{{ label }}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ label }}
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in pagination.rows %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="hidden" value="{{ get_object_identifier(row) }}">
|
||||
<input class="form-check-input m-0 align-middle select-box" type="checkbox" aria-label="选择">
|
||||
</td>
|
||||
<td class="text-end">
|
||||
{% if model_view.can_view_details %}
|
||||
<a href="{{ model_view._build_url_for('admin:details', request, row) }}" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" title="查看">
|
||||
<span class="me-1"><i class="fa-solid fa-eye"></i></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if model_view.can_edit %}
|
||||
<a href="{{ model_view._build_url_for('admin:edit', request, row) }}" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" title="编辑">
|
||||
<span class="me-1"><i class="fa-solid fa-pen-to-square"></i></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if model_view.can_delete %}
|
||||
<a href="#" data-name="{{ model_view.name }}" data-pk="{{ get_object_identifier(row) }}"
|
||||
data-url="{{ model_view._url_for_delete(request, row) }}" data-bs-toggle="modal"
|
||||
data-bs-target="#modal-delete" title="删除">
|
||||
<span class="me-1"><i class="fa-solid fa-trash"></i></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% for name in model_view._list_prop_names %}
|
||||
{% set value, formatted_value = model_view.get_list_value(row, name) %}
|
||||
{% if name in model_view._relation_names %}
|
||||
{% if is_list( value ) %}
|
||||
<td>
|
||||
{% for elem, formatted_elem in zip(value, formatted_value) %}
|
||||
{% if model_view.show_compact_lists %}
|
||||
<a href="{{ model_view._build_url_for('admin:details', request, elem) }}">({{ formatted_elem }})</a>
|
||||
{% else %}
|
||||
<a href="{{ model_view._build_url_for('admin:details', request, elem) }}">{{ formatted_elem }}</a><br/>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% else %}
|
||||
<td><a href="{{ model_view._url_for_details_with_prop(request, row, name) }}">{{ formatted_value }}</a></td>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<td>{{ formatted_value }}</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-between align-items-center gap-2">
|
||||
<p class="m-0 text-muted">显示第 <span>{{ ((pagination.page - 1) * pagination.page_size) + 1 }}</span> 至
|
||||
<span>{{ min(pagination.page * pagination.page_size, pagination.count) }}</span> 条,共 <span>{{ pagination.count
|
||||
}}</span> 条
|
||||
</p>
|
||||
<ul class="pagination m-0 ms-auto">
|
||||
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
|
||||
{% if pagination.has_previous %}
|
||||
<a class="page-link" href="{{ pagination.previous_page.url }}">
|
||||
{% else %}
|
||||
<a class="page-link" href="#">
|
||||
{% endif %}
|
||||
<i class="fa-solid fa-chevron-left"></i>
|
||||
上一页
|
||||
</a>
|
||||
</li>
|
||||
{% for page_control in pagination.page_controls %}
|
||||
<li class="page-item {% if page_control.number == pagination.page %}active{% endif %}"><a class="page-link"
|
||||
href="{{ page_control.url }}">{{ page_control.number }}</a></li>
|
||||
{% endfor %}
|
||||
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
|
||||
{% if pagination.has_next %}
|
||||
<a class="page-link" href="{{ pagination.next_page.url }}">
|
||||
{% else %}
|
||||
<a class="page-link" href="#">
|
||||
{% endif %}
|
||||
下一页
|
||||
<i class="fa-solid fa-chevron-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="dropdown text-muted">
|
||||
每页
|
||||
<a href="#" class="btn btn-sm btn-light dropdown-toggle" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
{{ request.query_params.get("pageSize") or model_view.page_size }} 条
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
{% for page_size_option in model_view.page_size_options %}
|
||||
<a class="dropdown-item" href="{{ request.url.include_query_params(pageSize=page_size_option, page=pagination.resize(page_size_option).page) }}">
|
||||
{{ page_size_option }} 条/页
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if model_view.get_filters() %}
|
||||
<div class="col-md-3" style="width: 300px; flex-shrink: 0;">
|
||||
<div id="filter-sidebar" class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">筛选</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% for filter in model_view.get_filters() %}
|
||||
{% if filter.has_operator %}
|
||||
<div class="mb-3">
|
||||
<div class="fw-bold text-truncate">{{ filter.title }}</div>
|
||||
<div>
|
||||
{% set current_filter = request.query_params.get(filter.parameter_name, '') %}
|
||||
{% set current_op = request.query_params.get(filter.parameter_name + '_op', '') %}
|
||||
{% if current_filter %}
|
||||
<div class="mb-2 text-muted small">
|
||||
当前: {{ current_op }} {{ current_filter }}
|
||||
<a href="{{ request.url.remove_query_params(filter.parameter_name).remove_query_params(filter.parameter_name + '_op') }}" class="text-decoration-none">[清除]</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<form method="get" class="d-flex flex-column" style="gap: 8px;">
|
||||
{% for key, value in request.query_params.items() %}
|
||||
{% if key != filter.parameter_name and key != filter.parameter_name + '_op' %}
|
||||
<input type="hidden" name="{{ key }}" value="{{ value }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<select name="{{ filter.parameter_name }}_op" class="form-select form-select-sm" required>
|
||||
<option value="">选择操作...</option>
|
||||
{% for op_value, op_label in filter.get_operation_options_for_model(model_view.model) %}
|
||||
<option value="{{ op_value }}" {% if current_op == op_value %}selected{% endif %}>{{ op_label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="text"
|
||||
name="{{ filter.parameter_name }}"
|
||||
placeholder="输入值"
|
||||
class="form-control form-control-sm"
|
||||
value="{{ current_filter }}"
|
||||
required>
|
||||
<button type="submit" class="btn btn-sm btn-outline-primary">应用筛选</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="mb-3">
|
||||
<div class="fw-bold text-truncate fs-3 mb-2">{{ filter.title }}</div>
|
||||
<div>
|
||||
{% for lookup in filter.lookups(request, model_view.model, model_view._run_arbitrary_query) %}
|
||||
{% if request.query_params.get(filter.parameter_name) == lookup[0] %}
|
||||
<div class="d-flex align-items-center justify-content-between bg-secondary-lt px-2 py-1 rounded">
|
||||
<span class="text-truncate fw-bold text-dark">
|
||||
{{ lookup[1] }}
|
||||
</span>
|
||||
<a href="{{ request.url.remove_query_params(filter.parameter_name) }}" class="text-decoration-none ms-2" title="清除筛选">
|
||||
<i class="fa-solid fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="{{ request.url.include_query_params(**{filter.parameter_name: lookup[0]}) }}" class="d-block text-decoration-none text-truncate px-2 py-1">
|
||||
{{ lookup[1] }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if model_view.can_delete %}
|
||||
{% include 'sqladmin/modals/delete.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% for custom_action in model_view._custom_actions_in_list %}
|
||||
{% if custom_action in model_view._custom_actions_confirmation %}
|
||||
{% with confirmation_message = model_view._custom_actions_confirmation[custom_action], custom_action=custom_action,
|
||||
url=model_view._url_for_action(request, custom_action) %}
|
||||
{% include 'sqladmin/modals/list_action_confirmation.html' %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,35 @@
|
||||
{% extends "sqladmin/base.html" %}
|
||||
{% block body %}
|
||||
<div class="d-flex align-items-center justify-content-center vh-100">
|
||||
<form class="col-lg-4 col-md-6 card card-md" action="{{ url_for('admin:login') }}" method="POST" autocomplete="off">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-center mb-4">{{ admin.title }}</h2>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">用户名</label>
|
||||
{% if error %}
|
||||
<input name="username" type="text" class="form-control is-invalid" placeholder="请输入用户名"
|
||||
autocomplete="off">
|
||||
<div class="invalid-feedback">{{ error }}</div>
|
||||
{% else %}
|
||||
<input name="username" type="text" class="form-control" placeholder="请输入用户名" autocomplete="off">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">密码</label>
|
||||
<div class="input-group input-group-flat">
|
||||
{% if error %}
|
||||
<input name="password" type="password" class="form-control is-invalid" placeholder="请输入密码"
|
||||
autocomplete="off">
|
||||
<div class="invalid-feedback">{{ error }}</div>
|
||||
{% else %}
|
||||
<input name="password" type="password" class="form-control" placeholder="请输入密码" autocomplete="off">
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-footer">
|
||||
<button type="submit" class="btn btn-primary w-100">登 录</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="modal modal-blur fade" id="modal-delete" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"></button>
|
||||
<div class="modal-status bg-danger"></div>
|
||||
<div class="modal-body text-center py-4">
|
||||
<i class="text-danger fa-solid fa-triangle-exclamation fa-2x"></i>
|
||||
<h3>确认删除</h3>
|
||||
<div id="modal-delete-text" class="text-muted"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="w-100">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="#" class="btn w-100" data-bs-dismiss="modal">
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button id="modal-delete-button" data-url="" class="btn btn-danger w-100">
|
||||
确认删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="modal modal-blur fade" id="modal-confirmation-{{ custom_action }}" tabindex="-1" role="dialog"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"></button>
|
||||
<div class="modal-status bg-blue"></div>
|
||||
<div class="modal-body text-center py-4">
|
||||
<h3>{{ confirmation_message }}</h3>
|
||||
<div id="modal-delete-text" class="text-muted"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="w-100">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="#" class="btn w-100" data-bs-dismiss="modal">
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="{{ url }}" class="btn btn-blue w-100">
|
||||
确认
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="modal modal-blur fade" id="modal-confirmation-{{ custom_action }}" tabindex="-1" role="dialog"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"></button>
|
||||
<div class="modal-status bg-blue"></div>
|
||||
<div class="modal-body text-center py-4">
|
||||
<h3>{{ confirmation_message }}</h3>
|
||||
<div id="modal-delete-text" class="text-muted"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="w-100">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="#" class="btn w-100" data-bs-dismiss="modal">
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="#" class="btn btn-blue w-100" id="action-custom-modal-{{ custom_action }}" data-url="{{ url }}">
|
||||
确认
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user