- 9 个端点:目录快照(asOf)/单参数历史/变更批次提交与撤回/批次分页与明细/两日期对比/Excel 导出/计算预览 - submit_change 全量前置校验(注册表/维度岗位/取值域/同批去重)→ 建批次 → 逐项留痕(旧值取提交时生效值) - 撤回:FOR UPDATE 锁行 + 已生效禁撤,删除后解析自然回退;同日多次变更取最新留痕 - 预览按岗位模板分派公式(经理聚合口径明确拒绝),出参含所用参数与生效时点;导出走 openpyxl - ECharts 决策记录:前端统计图使用 echarts(用户指定) Co-Authored-By: Claude Code <noreply@anthropic.com>
109 lines
4.3 KiB
TOML
109 lines
4.3 KiB
TOML
[project]
|
||
name = "payroll-backend"
|
||
version = "0.1.0"
|
||
description = "衍水集团营销人员工资管理系统 —— 后端服务"
|
||
readme = "README.md"
|
||
# 锁定 3.12:系统默认是 3.14,第三方库轮子覆盖不如 3.12 完备
|
||
requires-python = ">=3.12,<3.13"
|
||
|
||
dependencies = [
|
||
"fastapi>=0.115",
|
||
# starlette 已进入 1.x(当前 1.7.0)。FastAPI 对它的约束是 `starlette>=0.46.0`,
|
||
# **没有上界** —— uv lock --upgrade 时可能漂移到未验证的大版本。
|
||
# 我们的异常处理器与 TestClient 直接依赖其 API,故显式限定主版本。
|
||
# 当前组合(fastapi 0.143 + starlette 1.7.0)已实测通过全部用例。
|
||
"starlette>=1.7,<2",
|
||
"uvicorn[standard]>=0.32",
|
||
"pydantic>=2.9",
|
||
"pydantic-settings>=2.6",
|
||
# ORM 与驱动:采用同步 —— 本项目并发极低,异步无吞吐收益;
|
||
# 而重活(绩效批量核算、pandas 报表、Excel 导出)全是同步阻塞代码,
|
||
# 在异步路由里跑会卡死事件循环。同步路由由 FastAPI 自动放入线程池执行。
|
||
"sqlalchemy>=2.0.36",
|
||
# 必须带 [rsa]:MySQL 8.0 默认 caching_sha2_password,容器重启后首次连接走
|
||
# 全量认证需要 cryptography 做 RSA 交换,缺失时 PyMySQL 直接抛 RuntimeError
|
||
# (报错出现在建连阶段,极易被误读成"密码错误")
|
||
"pymysql[rsa]>=1.2.3",
|
||
"alembic>=1.14",
|
||
# 验证码、登录限流、Token 黑名单
|
||
"redis[hiredis]>=5.2",
|
||
# 鉴权与密码哈希
|
||
# 注意:不用 passlib —— 它与 bcrypt>=4.1 存在 __about__ 属性缺失的不兼容问题
|
||
"pyjwt>=2.10",
|
||
"pwdlib[bcrypt]>=0.2",
|
||
# 图形验证码(纯 Python,依赖 Pillow)
|
||
"captcha>=0.6",
|
||
"pillow>=11.0",
|
||
"openpyxl>=3.1.5",
|
||
]
|
||
|
||
[dependency-groups]
|
||
dev = [
|
||
"pytest>=8.3",
|
||
"pytest-cov>=7",
|
||
"httpx>=0.28,<1.0",
|
||
# 用假 Redis 做单测,无需起容器即可覆盖 GETDEL 一次性语义
|
||
"fakeredis>=2.30",
|
||
# lint + format 二合一,替代 flake8 + isort + black
|
||
"ruff>=0.14",
|
||
]
|
||
|
||
# 本项目按应用而非库来管理,不打包安装自身
|
||
[tool.uv]
|
||
package = false
|
||
|
||
[tool.pytest.ini_options]
|
||
testpaths = ["tests"]
|
||
markers = [
|
||
"integration: 需要 MySQL/Redis 容器或完整应用实例的测试",
|
||
]
|
||
|
||
# ==================== 代码检查与格式化 ====================
|
||
|
||
[tool.ruff]
|
||
# 与项目根 .editorconfig 保持一致:Python 用 4 空格(缩进由 formatter 控制)
|
||
target-version = "py312"
|
||
line-length = 100
|
||
src = ["app", "tests"]
|
||
|
||
[tool.ruff.lint]
|
||
select = [
|
||
"E", # pycodestyle 错误
|
||
"W", # pycodestyle 警告
|
||
"F", # pyflakes:未使用的导入、未定义的名称等
|
||
"I", # isort:导入顺序
|
||
"B", # flake8-bugbear:常见陷阱(可变默认参数、循环引用等)
|
||
"C4", # flake8-comprehensions:推导式可简化处
|
||
"UP", # pyupgrade:按目标 Python 版本升级旧写法
|
||
"SIM", # flake8-simplify:可简化的分支与判断
|
||
"RUF", # ruff 自有规则
|
||
]
|
||
ignore = [
|
||
# 行宽已由 formatter 控制,lint 不再重复报——长中文注释很容易触发
|
||
"E501",
|
||
# FastAPI 的依赖注入要求在参数默认值处调用 Depends(),是框架约定而非缺陷。
|
||
# 项目内已尽量改用 Annotated 形式(见 api/deps.py),此处兜底。
|
||
"B008",
|
||
# RUF001/002/003 检查「易混淆的 Unicode 字符」,分别针对字符串字面量、
|
||
# 文档字符串、注释 —— 这套规则的默认前提是英文文本。
|
||
# 对中文会把全角逗号、句号、括号、冒号全部判定为混淆字符(本项目实测 800+ 条),
|
||
# 而中文里全角标点正是规范写法,故一并关闭。
|
||
"RUF001",
|
||
"RUF002",
|
||
"RUF003",
|
||
]
|
||
|
||
[tool.ruff.lint.isort]
|
||
# 必须显式声明:本项目 `[tool.uv] package = false`(不作为包安装),
|
||
# ruff 无法从项目布局推断出 `app` 是第一方包,否则会把第三方依赖
|
||
# 排到 `app.*` 之后(按字母序把两者当成同一组)。
|
||
known-first-party = ["app", "tests"]
|
||
|
||
[tool.ruff.lint.per-file-ignores]
|
||
# Alembic 自动生成的迁移脚本不按手写代码的标准要求。
|
||
# 这些文件由 `alembic revision --autogenerate` 产出,手工修 lint 会在下次生成时被覆盖。
|
||
"alembic/versions/*.py" = ["E501", "I001", "W291"]
|
||
|
||
[tool.ruff.format]
|
||
quote-style = "double"
|