Files
pear-admin-flask/plugins/navManager/view/nav_category.py
T
bwadmin 4d6325c70e feat(public): 首页分类移至左侧侧栏 + 大屏自适应布局
- 分类导航由顶部横条改为左侧 sticky 侧栏(≥1025px),含快速导航/我常访问/热门/书签分类/站点页面
- 首页左右去留白:.container 与 .topbar-inner 改为 max-width:100%,布局铺满视口
- 卡片网格按屏宽自适应(minmax(var(--card-min),1fr)),1920 固定 6 列
- 移除顶部 .actions 菜单(与侧栏站点页面重复),主题切换改由侧栏按钮循环切换
- 新增 get_nav_categories() 统一锚点(侧栏/顶部/抽屉/section id 四者同源),修复空分类错位;后台分类增删改/启停后失效前台缓存
2026-09-07 11:11:22 +08:00

176 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
导航分类管理后台视图 — navManager 插件内的子模块。
URL/system/nav-category
权限:system:nav-category:*
"""
import os
from flask import Blueprint, render_template, request
from flask_login import current_user
from applications.common import curd
from applications.common.utils.http import table_api, fail_api, success_api
from applications.common.utils.rights import authorize
from applications.common.utils.validate import str_escape
from applications.extensions import db
from applications.extensions.init_limit import limiter
from applications.models import NavCategory
from applications.schemas import NavCategorySchema
dir_path = os.path.dirname(os.path.abspath(__file__))
bp = Blueprint(
'nav_category', __name__,
url_prefix='/system/nav-category',
template_folder=os.path.join(dir_path, '..', 'templates'),
)
def _invalidate_nav_cache():
"""分类变更后立即失效前台侧栏分类缓存(延迟导入避免循环依赖)。"""
try:
from applications.view.public.nav import clear_nav_categories_cache
clear_nav_categories_cache()
except Exception: # 缓存失效失败不影响主流程
pass
@bp.get('/')
@authorize("system:nav-category:main")
def main():
return render_template('system/nav/category_main.html')
@bp.get('/data')
@limiter.limit("60 per minute")
@authorize("system:nav-category:main")
def data():
keyword = str_escape(request.args.get('keyword', type=str))
query = NavCategory.query.filter()
if keyword:
query = query.filter(
db.or_(
NavCategory.name.contains(keyword),
NavCategory.description.contains(keyword),
)
)
items = query.order_by(NavCategory.sort.desc(), NavCategory.id.asc()).layui_paginate()
return table_api(
msg='请求成功',
data=curd.model_to_dicts(schema=NavCategorySchema, data=items.items),
count=items.total,
)
@bp.get('/add')
@authorize("system:nav-category:add", log=True)
def add():
return render_template('system/nav/category_add.html')
@bp.post('/save')
@authorize("system:nav-category:add", log=True)
def save():
req_json = request.get_json(force=True, silent=True) or {}
name = str_escape(req_json.get('name'))
if not name:
return fail_api(msg='分类名不能为空')
if NavCategory.query.filter_by(name=name).first():
return fail_api(msg=f'分类"{name}"已存在')
try:
cat = NavCategory(
name=name,
icon=str_escape(req_json.get('icon')) or 'layui-icon-list',
description=str_escape(req_json.get('description')),
sort=int(req_json.get('sort') or 0),
enable=int(req_json.get('enable') or 1),
)
db.session.add(cat)
db.session.commit()
except Exception as e:
db.session.rollback()
return fail_api(msg=f'新增失败:{e}')
return success_api(msg='新增成功')
@bp.get('/edit')
@authorize("system:nav-category:edit", log=True)
def edit():
cat_id = request.args.get('catId', type=int)
cat = curd.get_one_by_id(NavCategory, cat_id)
if not cat:
return fail_api(msg='分类不存在')
return render_template('system/nav/category_edit.html', cat=cat)
@bp.put('/update')
@authorize("system:nav-category:edit", log=True)
def update():
req_json = request.get_json(force=True, silent=True) or {}
cat_id = req_json.get('catId')
cat = curd.get_one_by_id(NavCategory, cat_id)
if not cat:
return fail_api(msg='分类不存在')
name = str_escape(req_json.get('name'))
if not name:
return fail_api(msg='分类名不能为空')
# name 是否被其他行占用
other = NavCategory.query.filter(NavCategory.name == name, NavCategory.id != cat_id).first()
if other:
return fail_api(msg=f'分类"{name}"已被占用')
try:
cat.name = name
cat.icon = str_escape(req_json.get('icon')) or 'layui-icon-list'
cat.description = str_escape(req_json.get('description'))
cat.sort = int(req_json.get('sort') or 0)
cat.enable = int(req_json.get('enable') or 1)
db.session.commit()
_invalidate_nav_cache()
except Exception as e:
db.session.rollback()
return fail_api(msg=f'更新失败:{e}')
return success_api(msg='更新成功')
@bp.delete('/remove/<int:cat_id>')
@authorize("system:nav-category:remove", log=True)
def remove(cat_id):
"""删除分类时不会动 Nav 记录,但 Nav.category 字段会孤立成 '未分组' 显示"""
cat = curd.get_one_by_id(NavCategory, cat_id)
if cat is None:
return fail_api(msg='分类不存在')
res = curd.delete_one_by_id(NavCategory, cat_id)
if not res:
return fail_api(msg='删除失败')
return success_api(msg='删除成功(分类下导航已自动归入「未分组」)')
@bp.put('/enable')
@authorize("system:nav-category:edit", log=True)
def enable():
req_json = request.get_json(force=True, silent=True) or {}
cat_id = req_json.get('catId')
if not cat_id:
return fail_api(msg='数据错误')
res = curd.enable_status(NavCategory, cat_id)
if not res:
return fail_api(msg='操作失败')
_invalidate_nav_cache()
return success_api(msg='已启用')
@bp.put('/disable')
@authorize("system:nav-category:edit", log=True)
def dis_enable():
req_json = request.get_json(force=True, silent=True) or {}
cat_id = req_json.get('catId')
if not cat_id:
return fail_api(msg='数据错误')
res = curd.disable_status(NavCategory, cat_id)
if not res:
return fail_api(msg='操作失败')
_invalidate_nav_cache()
return success_api(msg='已禁用')