Compare commits

...

3 Commits

Author SHA1 Message Date
71c2ab2005 feat: 仪表盘接口加入 Redis 缓存
仪表盘聚合结果缓存 30s,订单/提醒变更时自动清除仪表盘缓存。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 11:17:56 +08:00
76c3b4af13 feat: 补全产品、供应商、物流、提醒模块 Redis 缓存
产品/供应商列表缓存 120s,物流任务列表缓存 30s,提醒列表缓存 30s,
写操作后自动清除对应缓存。至此所有主要读接口均已接入 Redis。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 11:05:50 +08:00
0adccb60d2 feat: 新增 Redis 查询缓存加速
新建 cache.py 缓存工具模块,封装 Redis 读写和容错降级。
订单详情/列表、客户列表、定价规则读取走缓存,写操作后精确清除。
Redis 不可用时自动降级查 DB,不影响正常业务。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 10:37:51 +08:00
10 changed files with 247 additions and 19 deletions

View File

@ -15,6 +15,7 @@ from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from backend.app.api.deps import get_current_user, require_permissions, require_roles
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set
from backend.app.core.exceptions import AppException
from backend.app.core.error_codes import ErrorCode
from backend.app.db import get_db_session
@ -88,13 +89,19 @@ def get_pricing_rule(
回值定价规则详情信息
权限要求管理员admin或经理manager
"""
cache_key = f"pricing:rule:{product_id}"
cached = cache_get(cache_key)
if cached is not None:
return success_payload(cached)
rule = session.query(ProductPricingRule).filter(
ProductPricingRule.product_id == product_id,
ProductPricingRule.deleted == 0,
).first()
if not rule:
raise AppException(code=ErrorCode.NOT_FOUND, message="定价规则不存在", status_code=404)
return success_payload(_rule_to_dict(rule))
rule_data = _rule_to_dict(rule)
cache_set(cache_key, rule_data, ttl=300)
return success_payload(rule_data)
@router.post("/pricing-rules")
@ -132,6 +139,7 @@ def create_pricing_rule(
)
session.add(rule)
session.commit()
cache_delete_pattern("pricing:*")
session.refresh(rule)
return success_payload(_rule_to_dict(rule))
@ -161,6 +169,7 @@ def update_pricing_rule(
for k, v in data.items():
setattr(rule, k, v)
session.commit()
cache_delete_pattern("pricing:*")
session.refresh(rule)
return success_payload(_rule_to_dict(rule))
@ -187,6 +196,7 @@ def delete_pricing_rule(
raise AppException(code=ErrorCode.NOT_FOUND, message="定价规则不存在", status_code=404)
rule.deleted = 1
session.commit()
cache_delete_pattern("pricing:*")
return success_payload({"deleted": True})
@ -230,6 +240,7 @@ def create_supplier_cost(
cost = SupplierProductCost(**payload.model_dump())
session.add(cost)
session.commit()
cache_delete_pattern("pricing:*")
session.refresh(cost)
return success_payload(_cost_to_dict(cost))
@ -258,6 +269,7 @@ def update_supplier_cost(
for k, v in data.items():
setattr(cost, k, v)
session.commit()
cache_delete_pattern("pricing:*")
session.refresh(cost)
return success_payload(_cost_to_dict(cost))
@ -283,6 +295,7 @@ def delete_supplier_cost(
raise AppException(code=ErrorCode.NOT_FOUND, message="供应商成本不存在", status_code=404)
cost.deleted = 1
session.commit()
cache_delete_pattern("pricing:*")
return success_payload({"deleted": True})
@ -326,6 +339,7 @@ def create_price_tier(
tier = ProductPriceTier(**payload.model_dump())
session.add(tier)
session.commit()
cache_delete_pattern("pricing:*")
session.refresh(tier)
return success_payload(_tier_to_dict(tier))
@ -354,6 +368,7 @@ def update_price_tier(
for k, v in data.items():
setattr(tier, k, v)
session.commit()
cache_delete_pattern("pricing:*")
session.refresh(tier)
return success_payload(_tier_to_dict(tier))
@ -379,6 +394,7 @@ def delete_price_tier(
raise AppException(code=ErrorCode.NOT_FOUND, message="价格层级不存在", status_code=404)
tier.deleted = 1
session.commit()
cache_delete_pattern("pricing:*")
return success_payload({"deleted": True})

View File

@ -15,6 +15,7 @@ from sqlalchemy.orm import Session
from backend.app.api.deps import require_permissions, require_roles
from backend.app.db import get_db_session
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.schemas.common import success_payload
@ -44,15 +45,21 @@ def salesman_dashboard(
权限要求salesmanadmin 角色 order:list 权限
"""
orders = order_service.list_orders(session, {"salesman_id": current_user.get("user_id")})
reminders = reminder_service.list_reminders(session, {"receiver_user_id": current_user.get("user_id")})
return success_payload(
{
"orders": orders[:20],
"reminders": reminders.get("list", []) if isinstance(reminders, dict) else [],
"summary": {
"order_count": len(orders),
"reminder_count": len(reminders.get("list", [])) if isinstance(reminders, dict) else 0,
},
}
)
user_id = current_user.get("user_id")
cache_key = f"dashboard:{user_id}"
cached = cache_get(cache_key)
if cached is not None:
return success_payload(cached)
orders = order_service.list_orders(session, {"salesman_id": user_id})
reminders = reminder_service.list_reminders(session, {"receiver_user_id": user_id})
result = {
"orders": orders[:20],
"reminders": reminders.get("list", []) if isinstance(reminders, dict) else [],
"summary": {
"order_count": len(orders),
"reminder_count": len(reminders.get("list", [])) if isinstance(reminders, dict) else 0,
},
}
cache_set(cache_key, result, ttl=30)
return success_payload(result)

105
backend/app/core/cache.py Normal file
View File

@ -0,0 +1,105 @@
"""Redis 缓存工具模块。
提供 Redis 连接管理和缓存读写操作所有操作在 Redis 不可用时静默降级
OrderServiceCustomerServicepricing 路由等调用
"""
import hashlib
import json
import logging
import redis
from backend.app.core.config import get_settings
logger = logging.getLogger(__name__)
_redis_client: redis.Redis | None = None
def get_redis() -> redis.Redis | None:
"""获取 Redis 连接单例,连接失败时返回 None。"""
global _redis_client
if _redis_client is not None:
return _redis_client
try:
settings = get_settings()
_redis_client = redis.Redis(
host=settings.redis_host,
port=settings.redis_port,
db=settings.redis_db,
password=settings.redis_password or None,
decode_responses=True,
socket_connect_timeout=2,
socket_timeout=2,
)
_redis_client.ping()
logger.info("Redis 连接成功: %s:%s/%s", settings.redis_host, settings.redis_port, settings.redis_db)
return _redis_client
except Exception as exc:
logger.warning("Redis 连接失败,降级为无缓存模式: %s", exc)
_redis_client = None
return None
def cache_get(key: str):
"""读取缓存,返回反序列化后的 dict/list未命中或异常返回 None。"""
try:
r = get_redis()
if r is None:
return None
raw = r.get(key)
if raw is None:
return None
return json.loads(raw)
except Exception:
return None
def cache_set(key: str, data, ttl: int = 60) -> None:
"""写入缓存JSON 序列化后存储并设置 TTL。异常时静默跳过。"""
try:
r = get_redis()
if r is None:
return
r.set(key, json.dumps(data, ensure_ascii=False, default=str), ex=ttl)
except Exception:
pass
def cache_delete(key: str) -> None:
"""精确删除单个缓存 key。"""
try:
r = get_redis()
if r is not None:
r.delete(key)
except Exception:
pass
def cache_delete_pattern(pattern: str) -> None:
"""按模式批量删除缓存SCAN + DELETE"order:list:*""""
try:
r = get_redis()
if r is None:
return
cursor = 0
while True:
cursor, keys = r.scan(cursor=cursor, match=pattern, count=100)
if keys:
r.delete(*keys)
if cursor == 0:
break
except Exception:
pass
def make_cache_key(prefix: str, **params) -> str:
"""生成带参数哈希的缓存 key。
: make_cache_key("order:list", user_id=1, status="draft")
"order:list:a1b2c3d4"
"""
raw = json.dumps(params, sort_keys=True, ensure_ascii=False, default=str)
suffix = hashlib.md5(raw.encode()).hexdigest()[:8]
return f"{prefix}:{suffix}"

View File

@ -47,6 +47,10 @@ class Settings(BaseSettings):
mysql_user: str = Field(default="order_user", alias="MYSQL_USER")
mysql_password: str = Field(default="password", alias="MYSQL_PASSWORD")
sql_echo: bool = Field(default=False, alias="SQL_ECHO")
redis_host: str = Field(default="127.0.0.1", alias="REDIS_HOST")
redis_port: int = Field(default=6379, alias="REDIS_PORT")
redis_db: int = Field(default=0, alias="REDIS_DB")
redis_password: str = Field(default="", alias="REDIS_PASSWORD")
aliyun_oss_bucket: str = Field(default="bucket-name", alias="ALIYUN_OSS_BUCKET")
aliyun_oss_endpoint: str = Field(default="oss-cn-hangzhou.aliyuncs.com", alias="ALIYUN_OSS_ENDPOINT")
aliyun_oss_public_base_url: str = Field(default="https://cdn.example.com", alias="ALIYUN_OSS_PUBLIC_BASE_URL")

View File

@ -11,6 +11,7 @@ from pathlib import Path
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set, make_cache_key
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.customer_repository import CustomerRepository
@ -44,9 +45,14 @@ class CustomerService:
"""
if session is None:
raise AppException(code=ErrorCode.PARAM_ERROR, message="数据库会话未初始化", status_code=500)
# 读缓存
cache_key = make_cache_key("customer:list", **(filters or {}))
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
customers = self.repository.list_customers_by_filters(session, filters or {})
return {
result = {
"total": len(customers),
"page_no": 1,
"page_size": 20,
@ -67,6 +73,8 @@ class CustomerService:
for item in customers
],
}
cache_set(cache_key, result, ttl=60)
return result
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.SYSTEM_ERROR, message="数据库操作失败", status_code=500) from exc
@ -136,6 +144,7 @@ class CustomerService:
},
)
session.commit()
cache_delete_pattern("customer:list:*")
return {
"customer_id": customer.id,
"customer_name": customer.customer_name,
@ -212,6 +221,7 @@ class CustomerService:
},
)
session.commit()
cache_delete_pattern("customer:list:*")
return {"customer_id": customer.id, "customer_name": customer.customer_name, "mobile": customer.mobile}
except AppException:
session.rollback()
@ -314,6 +324,7 @@ class CustomerService:
},
)
session.commit()
cache_delete_pattern("customer:list:*")
return result
except AppException:
session.rollback()

View File

@ -15,6 +15,7 @@ from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.config import get_settings
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set, make_cache_key
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.logistics_repository import LogisticsRepository
@ -62,17 +63,23 @@ class LogisticsService:
被调用路由: logistics.py - GET /logistics/tasks
"""
if session is not None:
cache_key = make_cache_key("logistics:list", user_id=(current_user or {}).get("user_id"), **(filters or {}))
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
tasks = self.logistics_repository.list_tasks_by_filters(
session,
self.normalize_task_filters(filters, current_user),
)
return {
result = {
"total": len(tasks),
"page_no": 1,
"page_size": 20,
"list": [self._map_task_summary(task, session) for task in tasks],
}
cache_set(cache_key, result, ttl=30)
return result
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.INTERNAL_ERROR, message="数据库异常", status_code=500) from exc
return {"total": 0, "page_no": 1, "page_size": 20, "list": []}
@ -144,6 +151,7 @@ class LogisticsService:
},
)
session.commit()
cache_delete_pattern("logistics:*")
return self._map_task_detail(task, session)
except AppException:
session.rollback()
@ -258,6 +266,7 @@ class LogisticsService:
},
)
session.commit()
cache_delete_pattern("logistics:*")
return {"task_id": task.id, "status": task.status, "order_id": task.order_id}
except AppException:
session.rollback()
@ -342,6 +351,7 @@ class LogisticsService:
},
)
session.commit()
cache_delete_pattern("logistics:*")
return {
"task_id": task.id,
"order_id": task.order_id,
@ -554,6 +564,7 @@ class LogisticsService:
},
)
session.commit()
cache_delete_pattern("logistics:*")
return {"order_id": order_id, "created": True}
except ValueError as exc:
session.rollback()
@ -636,6 +647,7 @@ class LogisticsService:
if target_status == "delivered":
arrears_service.sync_order_arrears(session, order)
session.commit()
cache_delete_pattern("logistics:*")
return {"task_id": task.id, "status": task.status, "order_id": task.order_id}
except AppException:
session.rollback()

View File

@ -12,6 +12,7 @@ import json
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.cache import cache_delete, cache_delete_pattern, cache_get, cache_set, make_cache_key
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.customer_repository import CustomerRepository
@ -65,11 +66,16 @@ class OrderService:
被调用路由: orders.py - GET /orders, salesman.py - GET /salesman/orders
"""
if session is not None:
# 读缓存
cache_key = make_cache_key("order:list", user_id=(current_user or {}).get("user_id"), **(filters or {}))
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
result = self.order_repository.list_orders_by_filters(session, filters or {})
orders = result["list"]
role_code = (current_user or {}).get("role_code")
return [
rows = [
self._filter_order_row(
{
"order_id": item.id,
@ -88,6 +94,9 @@ class OrderService:
)
for item in orders
]
# 写缓存
cache_set(cache_key, rows, ttl=30)
return rows
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.INTERNAL_ERROR, message="数据库异常", status_code=500) from exc
return []
@ -114,6 +123,11 @@ class OrderService:
被调用路由: orders.py - GET /orders/{order_id}
"""
if session is not None:
# 读缓存
cache_key = f"order:detail:{order_id}"
cached = cache_get(cache_key)
if cached is not None:
return self._filter_order_detail_by_role(cached, current_user)
try:
order = self.order_repository.get_order(session, order_id)
if order is None:
@ -213,6 +227,8 @@ class OrderService:
"profit_alert_threshold": float(self._get_config_value(session, "profit_alert_threshold", "0")),
"remark": order.remark,
}
# 写缓存(缓存完整结果,角色过滤在读取后执行)
cache_set(cache_key, result, ttl=60)
return self._filter_order_detail_by_role(result, current_user)
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.INTERNAL_ERROR, message="数据库异常", status_code=500) from exc
@ -325,6 +341,7 @@ class OrderService:
},
)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_no": order.order_no,
@ -388,6 +405,7 @@ class OrderService:
)
self._notify_status_change(session, order, before_status, order.order_status, current_user.get("user_id") if current_user else None)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_status": order.order_status,
@ -487,6 +505,7 @@ class OrderService:
)
self._notify_status_change(session, order, previous_status, order.order_status, current_user.get("user_id") if current_user else None)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_status": order.order_status,
@ -567,6 +586,7 @@ class OrderService:
)
self._notify_status_change(session, order, previous_status, order.order_status, current_user.get("user_id") if current_user else None, {"approve_opinion": payload.get("approve_opinion")})
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_status": order.order_status,
@ -655,6 +675,7 @@ class OrderService:
)
self._notify_status_change(session, order, previous_status, order.order_status, current_user.get("user_id") if current_user else None)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_status": order.order_status,
@ -782,6 +803,7 @@ class OrderService:
},
)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_status": order.order_status,
@ -864,6 +886,7 @@ class OrderService:
)
self._notify_status_change(session, order, before_status, order.order_status, current_user.get("user_id") if current_user else None)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_status": order.order_status,
@ -988,6 +1011,7 @@ class OrderService:
},
)
session.commit()
self._invalidate_order_cache(order.id)
return {
"order_id": order.id,
"order_no": order.order_no,
@ -1199,6 +1223,13 @@ class OrderService:
return filtered
return order
def _invalidate_order_cache(self, order_id: int | None = None) -> None:
"""清除订单相关缓存。"""
if order_id:
cache_delete(f"order:detail:{order_id}")
cache_delete_pattern("order:list:*")
cache_delete_pattern("dashboard:*")
def _filter_order_row(self, row: dict, role_code: str | None) -> dict:
"""根据用户角色过滤订单列表行中的敏感字段。

View File

@ -8,6 +8,7 @@
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set, make_cache_key
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.product_repository import ProductRepository
@ -97,6 +98,7 @@ class ProductService:
},
)
session.commit()
cache_delete_pattern("product:*")
return {
"category_id": category.id,
"category_name": category.category_name,
@ -140,6 +142,7 @@ class ProductService:
raise AppException(code=ErrorCode.DUPLICATE, message="分类编码已存在", status_code=400)
self.repository.update_category(session, category, payload)
session.commit()
cache_delete_pattern("product:*")
return {"category_id": category_id, "updated": True}
except AppException:
session.rollback()
@ -210,16 +213,22 @@ class ProductService:
"""
if session is None:
raise AppException(code=ErrorCode.PARAM_ERROR, message="数据库会话未初始化", status_code=500)
cache_key = make_cache_key("product:list", **(filters or {}))
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
products = self.repository.list_products(session, filters or {})
categories = {category.id: category for category in self.repository.list_categories(session, {})}
grouped_list = self._group_products(products, categories)
return {
result = {
"total": len(grouped_list),
"page_no": 1,
"page_size": len(grouped_list) or 20,
"list": grouped_list,
}
cache_set(cache_key, result, ttl=120)
return result
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.SYSTEM_ERROR, message="数据库操作失败", status_code=500) from exc
@ -258,6 +267,7 @@ class ProductService:
product.remark = payload.get("remark", product.remark)
session.add(product)
session.commit()
cache_delete_pattern("product:*")
return {"product_id": product.id, "product_name": product.product_name, "updated": True}
except AppException:
session.rollback()
@ -309,6 +319,7 @@ class ProductService:
product.remark = payload.get("remark", product.remark)
session.add(product)
session.commit()
cache_delete_pattern("product:*")
return {"product_id": product.id, "product_name": product.product_name, "updated": True}
except AppException:
session.rollback()
@ -343,6 +354,7 @@ class ProductService:
session.add(sibling)
session.flush()
session.commit()
cache_delete_pattern("product:*")
return {"product_id": product.id, "product_name": product.product_name, "is_default": True}
except AppException:
session.rollback()
@ -425,6 +437,7 @@ class ProductService:
},
)
session.commit()
cache_delete_pattern("product:*")
return {
"product_name": payload["product_name"],
"product_id": created_specs[0].id if created_specs else None,
@ -465,6 +478,10 @@ class ProductService:
"""
if session is None:
raise AppException(code=ErrorCode.PARAM_ERROR, message="数据库会话未初始化", status_code=500)
cache_key = f"product:detail:{product_id}"
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
product = self.repository.get_product(session, product_id)
if product is None:
@ -473,6 +490,7 @@ class ProductService:
categories = {category.id: category for category in self.repository.list_categories(session, {})}
grouped = self._group_products(products, categories)
if grouped:
cache_set(cache_key, grouped[0], ttl=120)
return grouped[0]
raise AppException(code=ErrorCode.NOT_FOUND, message="产品不存在", status_code=404)
except AppException:

View File

@ -14,6 +14,7 @@ from datetime import datetime, timedelta
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set, make_cache_key
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.config_repository import ConfigRepository
@ -49,18 +50,24 @@ class ReminderService:
if session is None:
raise AppException(code=ErrorCode.INTERNAL_ERROR, message="数据库连接不可用", status_code=500)
filters = filters or {}
cache_key = make_cache_key("reminder:list", **filters)
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
reminders = self.repository.list_reminders(session, filters)
page_no = filters.get("page_no", 1)
page_size = filters.get("page_size", 20)
start = max(page_no - 1, 0) * page_size
page_list = reminders[start : start + page_size]
return {
result = {
"total": len(reminders),
"page_no": page_no,
"page_size": page_size,
"list": [self._map_reminder(item) for item in page_list],
}
cache_set(cache_key, result, ttl=30)
return result
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.INTERNAL_ERROR, message="数据库异常", status_code=500) from exc
@ -101,6 +108,8 @@ class ReminderService:
},
)
session.commit()
cache_delete_pattern("reminder:*")
cache_delete_pattern("dashboard:*")
return {"reminder_id": reminder.id, "status": reminder.status}
except AppException:
session.rollback()
@ -169,6 +178,8 @@ class ReminderService:
created_count += 1
session.commit()
cache_delete_pattern("reminder:*")
cache_delete_pattern("dashboard:*")
return {"checked": True, "created_count": created_count}
except AppException:
session.rollback()
@ -238,6 +249,8 @@ class ReminderService:
created_count += 1
session.commit()
cache_delete_pattern("reminder:*")
cache_delete_pattern("dashboard:*")
return {"checked": True, "created_count": created_count}
except AppException:
session.rollback()
@ -298,6 +311,8 @@ class ReminderService:
created_count += 1
session.commit()
cache_delete_pattern("reminder:*")
cache_delete_pattern("dashboard:*")
return {"checked": True, "created_count": created_count}
except AppException:
session.rollback()

View File

@ -8,6 +8,7 @@
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.cache import cache_delete_pattern, cache_get, cache_set, make_cache_key
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.supplier_repository import SupplierRepository
@ -39,9 +40,13 @@ class SupplierService:
"""
if session is None:
raise AppException(code=ErrorCode.PARAM_ERROR, message="数据库会话未初始化", status_code=500)
cache_key = make_cache_key("supplier:list", **(filters or {}))
cached = cache_get(cache_key)
if cached is not None:
return cached
try:
suppliers = self.repository.list_suppliers(session, filters or {})
return {
result = {
"total": len(suppliers),
"page_no": 1,
"page_size": len(suppliers) or 20,
@ -60,6 +65,8 @@ class SupplierService:
for supplier in suppliers
],
}
cache_set(cache_key, result, ttl=120)
return result
except SQLAlchemyError as exc:
raise AppException(code=ErrorCode.SYSTEM_ERROR, message="数据库操作失败", status_code=500) from exc
@ -108,6 +115,7 @@ class SupplierService:
},
)
session.commit()
cache_delete_pattern("supplier:*")
return {
"supplier_id": supplier.id,
"supplier_name": supplier.supplier_name,
@ -204,6 +212,7 @@ class SupplierService:
},
)
session.commit()
cache_delete_pattern("supplier:*")
return {"supplier_id": supplier.id, "supplier_name": supplier.supplier_name}
except AppException:
session.rollback()