chore: 基线提交(重构前代码快照)

- git 初始化 + .gitignore 补全(根 .env / logs / instance / __pycache__ 等)
- 修复 utils/.gitignore 误将整个 utils/ 源码层忽略的问题,补入全部工具源码(含 ip2region.xdb)
- 含后端全部代码:application / extensions / utils / config / migrations
- 含前端 ui/(后续整体迁走)
- 不含根 .env(含密钥,本地保留)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 12:12:06 +08:00
co-authored by Claude
commit 15f2a5e097
591 changed files with 95894 additions and 0 deletions
+193
View File
@@ -0,0 +1,193 @@
"""
短信发送服务模块
=============================================================
封装阿里云短信 SDK 提供短信发送能力,供业务模块和定时任务调用。
使用方式:
from application.services import sms_svc
# 模板短信(推荐)
sms_svc.send_sms(
phone='13800138000',
template_code='SMS_123456',
template_params={'code': '123456'}
)
# 指定签名(覆盖默认签名)
sms_svc.send_sms(
phone='13800138000',
template_code='SMS_123456',
template_params={'code': '123456'},
sign_name='我的应用'
)
# 群发(多号码)
sms_svc.send_sms(
phone=['13800138000', '13900139000'],
template_code='SMS_123456',
template_params={'name': '张三'}
)
"""
import json
import logging
from typing import Dict, List, Optional, Union
from config import (
SMS_ALIYUN_ACCESS_KEY_ID,
SMS_ALIYUN_ACCESS_KEY_SECRET,
SMS_ALIYUN_CONNECT_TIMEOUT,
SMS_ALIYUN_ENDPOINT,
SMS_ALIYUN_READ_TIMEOUT,
SMS_ALIYUN_SIGN_NAME,
SMS_PROVIDER,
)
logger = logging.getLogger(__name__)
# ============================================================
# 阿里云短信客户端(延迟初始化)
# ============================================================
_client = None
def _get_client():
"""
获取阿里云短信客户端(单例,延迟初始化)
Returns:
dysmsapi.Client: 阿里云短信客户端实例
Raises:
ImportError: 阿里云 SDK 未安装
Exception: 客户端创建失败
"""
global _client
if _client is not None:
return _client
try:
from alibabacloud_dysmsapi20170525.client import Client
from alibabacloud_tea_openapi.models import Config
except ImportError:
raise ImportError(
"阿里云短信 SDK 未安装,请执行: "
"pip install alibabacloud-dysmsapi20170525 alibabacloud-tea-openapi"
)
config = Config(
access_key_id=SMS_ALIYUN_ACCESS_KEY_ID,
access_key_secret=SMS_ALIYUN_ACCESS_KEY_SECRET,
endpoint=SMS_ALIYUN_ENDPOINT,
connect_timeout=SMS_ALIYUN_CONNECT_TIMEOUT,
read_timeout=SMS_ALIYUN_READ_TIMEOUT,
)
_client = Client(config)
return _client
# ============================================================
# 短信发送
# ============================================================
def send_sms(
phone: Union[str, List[str]],
template_code: str,
template_params: Optional[Dict] = None,
sign_name: Optional[str] = None,
) -> bool:
"""
发送短信(阿里云模板短信)
Args:
phone: 手机号,字符串或列表(群发时传入多个号码)
template_code: 短信模板CODE(在阿里云控制台获取,如 SMS_123456)
template_params: 模板变量,如 {'code': '123456'} 对应模板中的 ${code}
sign_name: 短信签名(可选,默认使用配置中的 SMS_ALIYUN_SIGN_NAME)
Returns:
bool: 全部发送成功返回 True,任一失败返回 False
"""
if not phone:
logger.warning("发送短信失败:手机号不能为空")
return False
if not template_code:
logger.warning("发送短信失败:模板CODE不能为空")
return False
if not sign_name:
sign_name = SMS_ALIYUN_SIGN_NAME
if not sign_name:
logger.warning("发送短信失败:短信签名未配置")
return False
# 统一转为列表
phones = [phone] if isinstance(phone, str) else phone
# 检查 AccessKey 配置
if not SMS_ALIYUN_ACCESS_KEY_ID or not SMS_ALIYUN_ACCESS_KEY_SECRET:
logger.warning("发送短信失败:阿里云 AccessKey 未配置")
return False
# 模板变量序列化
params_str = json.dumps(template_params, ensure_ascii=False) if template_params else ''
# 逐条发送(阿里云短信 API 不支持批量同发)
all_success = True
for p in phones:
if not _send_one(p, sign_name, template_code, params_str):
all_success = False
return all_success
def _send_one(phone: str, sign_name: str, template_code: str, template_params: str) -> bool:
"""
发送单条短信
Args:
phone: 手机号
sign_name: 短信签名
template_code: 模板CODE
template_params: 模板变量 JSON 字符串
Returns:
bool: 发送成功返回 True
"""
try:
from alibabacloud_dysmsapi20170525 import models as dysms_models
client = _get_client()
request = dysms_models.SendSmsRequest(
phone_numbers=phone,
sign_name=sign_name,
template_code=template_code,
template_param=template_params,
)
response = client.send_sms(request)
body = response.body
if body.code == 'OK':
logger.info(f"短信发送成功: phone={phone}, template={template_code}, biz_id={body.biz_id}")
return True
else:
logger.warning(
f"短信发送失败: phone={phone}, template={template_code}, "
f"code={body.code}, message={body.message}"
)
return False
except ImportError as e:
logger.error(f"阿里云短信 SDK 未安装: {str(e)}")
return False
except Exception as e:
logger.error(f"短信发送异常: phone={phone}, template={template_code}, error={str(e)}")
return False