fix(pl): 将证书齐备改为独立菜单权限,避免取消授权后仍随计划段次用证显示。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-11-06 17:39:18 +08:00
1 parent 421332cad4
commit 13ed7f5be0
8 files changed
+129 -7

No files matched your search

+6 -1
View File
@@ -14,10 +14,15 @@ from app.api.pl.vehicle_fuel_card import router as vehicle_fuel_card_router
from app.api.pl.dispatch_calendar import router as dispatch_calendar_router
from app.api.pl.site_dispatch_calendar import router as site_dispatch_calendar_router
from app.api.wechat_notices import router as wechat_notices_router
from app.api.pl.quota_cert import router as quota_cert_router, legal_router as legal_use_document_router
from app.api.pl.quota_cert import (
router as quota_cert_router,
legal_router as legal_use_document_router,
cert_ready_router,
)
__all__ = [
"quota_cert_router",
"cert_ready_router",
"legal_use_document_router",
"wechat_notices_router",
"public_router",
+23 -3
View File
@@ -11,7 +11,7 @@ from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.db_auth import DbUserContext, get_db_current_user
from app.core.menu_guard import require_menu_code
from app.core.menu_guard import get_user_menu_codes, require_admin_or_super_admin, require_menu_code
from app.core.oper_log_decorator import oper_log
from app.core.tenant_context import get_tenant_no
from app.schemas.pl.quota_cert import InputBody, CertConfirmBody, CertVerifyBody, CertTotalAdjustBody
@@ -36,6 +36,26 @@ router = APIRouter(prefix='/transport/quota-certs', tags=['购买证与运输证
dependencies=[Depends(require_menu_code('pl:quota-cert:list'))])
legal_router = APIRouter(prefix='/transport/legal-use-documents', tags=['合法使用证明'],
dependencies=[Depends(require_menu_code('pl:legal-use-document:list'))])
def _require_cert_ready_menu(
current_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
"""证书齐备页面权限。小程序运输证件仍走原入口,不要求单独的 Web 菜单。"""
if current_user.get("role") == "super_admin":
return current_user
codes = get_user_menu_codes(db, current_user.get("user_id"))
if "pl:cert-ready:list" in codes or "mini:pl:plan-cert:list" in codes:
return current_user
raise HTTPException(status_code=403, detail="无菜单访问权限")
cert_ready_router = APIRouter(
prefix='/transport/quota-certs',
tags=['证书齐备'],
dependencies=[Depends(_require_cert_ready_menu)],
)
CertType = Literal['purchase', 'transport']
@@ -86,7 +106,7 @@ def plan_overview(keyword: str = '', status: Optional[str] = None,
conversion_only=conversion_only))
@router.get('/plans/cert-ready')
@cert_ready_router.get('/plans/cert-ready')
def list_cert_ready(keyword: str = '', waived: Optional[str] = Query(None, max_length=1),
plan_no: Optional[str] = Query(None, alias='planNo', max_length=200),
license_plate: Optional[str] = Query(None, alias='licensePlate', max_length=100),
@@ -111,7 +131,7 @@ def list_cert_ready(keyword: str = '', waived: Optional[str] = Query(None, max_l
waived_time_to=waived_time_to))
@router.post('/plans/{plan_id}/cert-ready')
@cert_ready_router.post('/plans/{plan_id}/cert-ready')
def mark_cert_ready(plan_id: str, db: Session = Depends(get_db), user: DbUserContext = Depends(current_user)):
from app.services.pl_quota_waiver import mark_ready
return _write(db, lambda: mark_ready(db, user, plan_id))
+2
View File
@@ -36,6 +36,7 @@ from app.api import (
site_dispatch_calendar_router,
wechat_notices_router,
quota_cert_router,
cert_ready_router,
legal_use_document_router,
)
from app.api.pl import pl_router
@@ -185,6 +186,7 @@ app.include_router(bx_router, prefix=settings.API_V1_PREFIX)
app.include_router(db_router, prefix=settings.API_V1_PREFIX)
app.include_router(pl_router, prefix=settings.API_V1_PREFIX)
app.include_router(quota_cert_router, prefix=settings.API_V1_PREFIX)
app.include_router(cert_ready_router, prefix=settings.API_V1_PREFIX)
app.include_router(legal_use_document_router, prefix=settings.API_V1_PREFIX)
app.include_router(vehicle_fuel_card_router, prefix=settings.API_V1_PREFIX)
app.include_router(dispatch_calendar_router, prefix=settings.API_V1_PREFIX)
@@ -0,0 +1,15 @@
-- 「证书齐备」与「计划段次用证」拆开权限码。
-- 仍勾选该菜单的角色自动获得 pl:cert-ready:list;已解除授权的角色不会恢复。
-- MySQL 5.7。可重复执行。仅 shanxia2.0。
SET NAMES utf8mb4;
UPDATE sys_menu
SET perms='pl:cert-ready:list',
update_by='system',
update_time=NOW()
WHERE id='PL_CERT_READY'
AND tenant_no='shanxia2.0'
AND del_flag=0
AND menu_type='C'
AND path='cert-ready'
AND perms='pl:plan-cert:list';
@@ -0,0 +1,79 @@
-- 恢复 Web「运输证件管理」目录,并把五个证件页面挂回其下。
-- 不改子页面、按钮的权限码,不删除已有角色授权;仅为目录补齐已拥有任一子页面的角色。
-- MySQL 5.7。可重复执行。仅 shanxia2.0。
SET NAMES utf8mb4;
START TRANSACTION;
UPDATE sys_menu
SET menu_name='运输证件管理',
parent_id='PL_MENU_ROOT',
menu_type='M',
path='cert-upload',
visible='1',
status='1',
order_num=3,
del_flag=0,
remark='运输证件管理目录',
update_by='system',
update_time=NOW()
WHERE id='PL_GROUP_CERT'
AND tenant_no='shanxia2.0'
AND parent_id='PL_MENU_ROOT';
UPDATE sys_menu
SET parent_id='PL_GROUP_CERT',
order_num=CASE id
WHEN 'PL_QUOTA_CERT' THEN 1
WHEN 'PL_CONTRACT_QUOTA' THEN 2
WHEN 'PL_CERTIFICATE_USAGE' THEN 3
WHEN 'PL_PLAN_CERT' THEN 4
WHEN 'PL_CERT_READY' THEN 5
END,
update_by='system',
update_time=NOW()
WHERE tenant_no='shanxia2.0'
AND del_flag=0
AND menu_type='C'
AND id IN (
'PL_QUOTA_CERT',
'PL_CONTRACT_QUOTA',
'PL_CERTIFICATE_USAGE',
'PL_PLAN_CERT',
'PL_CERT_READY'
)
AND parent_id IN ('PL_MENU_ROOT', 'PL_GROUP_CERT');
INSERT INTO sys_role_menu (
id, role_id, menu_id, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_time, del_flag
)
SELECT MD5(CONCAT(access_row.role_id, '|PL_GROUP_CERT|cert-folder|v1')),
access_row.role_id, 'PL_GROUP_CERT', access_row.tenant_no, 0,
'恢复运输证件管理目录:沿用已有子菜单角色',
'system', '', NOW(), NOW(), 0
FROM (
SELECT DISTINCT role_id, tenant_no
FROM sys_role_menu
WHERE del_flag=0
AND tenant_no='shanxia2.0'
AND menu_id IN (
'PL_QUOTA_CERT',
'PL_CONTRACT_QUOTA',
'PL_CERTIFICATE_USAGE',
'PL_PLAN_CERT',
'PL_CERT_READY'
)
) access_row
WHERE NOT EXISTS (
SELECT 1 FROM sys_role_menu existing
WHERE existing.role_id=access_row.role_id
AND existing.menu_id='PL_GROUP_CERT'
AND existing.tenant_no=access_row.tenant_no
AND existing.del_flag=0
)
ON DUPLICATE KEY UPDATE
del_flag=0,
update_time=NOW(),
remark='恢复运输证件管理目录:沿用已有子菜单角色';
COMMIT;
+1 -1
View File
@@ -165,7 +165,7 @@ test('cert tabs keep their identities and legal proof is a sibling menu', () =>
'pl:quota-cert:list',
'pl:quota-cert:list',
'pl:plan-cert:list',
'pl:plan-cert:list'
'pl:cert-ready:list'
]
)
assert.equal(legal.children![0].id, 'PL_LEGAL_USE_DOCUMENT')
+2 -2
View File
@@ -94,7 +94,7 @@ export const plRoutes: AppRouteRecord[] = [
name: 'PlCertReady',
path: 'cert-ready',
component: '/pl/cert-ready/index',
meta: { title: '证书齐备', keepAlive: false, menuCode: 'pl:plan-cert:list' }
meta: { title: '证书齐备', keepAlive: false, menuCode: 'pl:cert-ready:list' }
},
{
id: 'PL_REDIRECT_LEGAL_USE_OLD',
@@ -286,7 +286,7 @@ export const plRoutes: AppRouteRecord[] = [
name: 'PlCertReadyRedirect',
path: 'cert-ready',
redirect: '/pl/cert-upload/cert-ready',
meta: { title: '证书齐备', isHide: true }
meta: { title: '证书齐备', isHide: true, menuCode: 'pl:cert-ready:list' }
},
{
id: 'PL_REDIRECT_FREIGHT',
+1
View File
@@ -150,6 +150,7 @@ export const SIDEBAR_MENU_ICON_BY_CODE: Record<string, string> = {
'pl:plan:list': 'ri:route-line',
'pl:plan-archive:list': 'ri:folder-check-line',
'pl:plan-cert:list': 'ri:shield-check-line',
'pl:cert-ready:list': 'ri:shield-check-line',
'pl:freight:list': 'ri:money-cny-box-line',
'pl:freight-approval:list': 'ri:checkbox-circle-line',
'pl:freight-disburse:list': 'ri:bank-card-line',