Metadata-Version: 2.4
Name: fred_admin
Version: 1.0.32
Summary: A Flask-based web framework with built-in utilities and extensions
Author-email: chenyg <chenyougang@126.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/yourusername/fred-framework
Project-URL: Repository, https://github.com/yourusername/fred-framework
Project-URL: Documentation, https://github.com/yourusername/fred-framework#readme
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: flask>=3.1.2
Requires-Dist: flask_cors>=6.0.1
Requires-Dist: flask_jwt_extended>=4.7.1
Requires-Dist: Pillow>=11.3.0
Requires-Dist: flask_smorest>=0.46.2
Requires-Dist: flask_swagger_ui>=5.21.0
Requires-Dist: cryptography>=46.0.0
Requires-Dist: requests>=2.32.5
Requires-Dist: flask_apscheduler>=1.13.1
Requires-Dist: flask_babelplus>=2.2.0
Requires-Dist: flask_sqlacodegen>=2.0.0
Requires-Dist: flask_sqlalchemy>=3.1.1
Requires-Dist: pymysql>=1.1.2
Requires-Dist: pytz>=2025.2
Requires-Dist: flask_mail>=0.10.0
Requires-Dist: redis>=7.0.0
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Dynamic: license-file

# Fred Admin

基于 Flask 的后台管理框架，开箱即用的企业级脚手架。

## 特性

- 开箱即用：`pip install` 后直接 `create_app()` 即得完整后台，无需任何初始化命令
- 内置 Admin：完整的后台管理系统（前后端 + 预构建产物 + 种子数据）
- 后台自更新：界面内检查新版本、预览数据库差异、备份后一键升级
- 安全迁移：升级时按差异改表结构，保留全部业务数据，破坏性变更需显式确认
- 模块化设计：支持多模块热加载，业务隔离，项目内模块可覆盖内置实现
- 定时任务：APScheduler 持久化到数据库，重启自动恢复
- 多数据库：默认 SQLite，可切换 MySQL
- Swagger 文档：自动生成 API 文档
- 国际化：内置多语言支持

## 安装

```bash
pip install fred_admin
```

## 快速开始

框架已内置完整 admin（后端代码 + 前端构建产物 + 数据库种子数据），**安装后无需执行任何初始化命令**。

```bash
# 1. 创建项目目录
mkdir myproject && cd myproject

# 2. 创建虚拟环境
python -m venv .venv
source .venv/bin/activate  # Linux/Mac
.venv\Scripts\activate     # Windows

# 3. 安装框架
pip install fred_admin
```

然后只需一个 `app.py`：

```python
from fred_admin import create_app

app = create_app()

if __name__ == "__main__":
    app.run()
```

```bash
python app.py
```

访问 http://127.0.0.1:5000 即可看到管理后台，默认账号 `admin` / `Fred@2026`（登录后请立即修改）。

首次启动会自动在当前目录创建：

| 产物 | 说明 |
|------|------|
| `data/app.db` | 从包内复制的数据库，已含表结构、管理员账号与菜单/按钮权限数据 |
| `common/model/model.py` | 由 sqlacodegen 从数据库反推生成的 ORM 模型 |
| `logs/`、`upload/`、`download/` | 运行时目录 |

### 需要自定义项目结构时

执行 `fred-init` 可把完整项目骨架（含前端源码、文档、配置样例）复制到当前目录：

```bash
fred-init
```

- 复制 `app.py`、`common/`、`data/`、`modules/`、`docs/` 等
- 已存在的文件一律跳过，不覆盖你的代码
- `demo_` 前缀文件自动重命名为隐藏文件（`.gitignore` 等）
- 各模块 `templates/` 已存在时跳过前端构建；缺失时用 pnpm 构建（需先 `npm install -g pnpm`）

`fred-init` 是**可选的**，只在你需要前端源码或想自定义 admin 时才需要。

### 两种模式的区别

| | 开箱即用（默认） | `fred-init` 后 |
|---|---|---|
| 后台代码来源 | 包内 `_template/modules/fred_admin/`（只读） | 项目内 `modules/fred_admin/`（可自由修改） |
| 前端产物 | 包内预构建产物 | 项目内产物，可用 pnpm 自行构建 |
| 升级方式 | `pip install -U fred_admin` 即生效 | 需同步项目内代码 |
| 适用场景 | 直接使用后台、只开发业务模块 | 需要改造 admin 界面或逻辑 |

项目内 `modules/fred_admin/` 存在时始终优先于内置版本，因此可以先开箱即用，之后随时 `fred-init` 转为可定制模式。

## 目录结构

### 框架包结构（fred_admin）

```
fred_admin/
├── __init__.py           # create_app() 入口
├── BuiltinModules.py     # 内置模块加载 + 开箱即用兜底（建目录、复制内置库、补建缺失表）
├── SchemaMigration.py    # sqlite 表结构差异迁移引擎（升级时保留数据改表）
├── UpdateService.py      # 版本检查、下载预览、pip 安装（后台「检查更新」后端）
├── install_hook.py       # fred-init 命令实现
├── create_module.py      # fred-create 命令实现
├── common/               # 框架核心组件
│   ├── AliyunSms.py      # 阿里云短信
│   ├── Blueprints.py     # 蓝图自动注册（项目 modules → 内置模块 → EXTERNAL_MODULES）
│   ├── Email.py          # 邮件发送
│   ├── Extensions.py     # 扩展初始化（DB、JWT、Scheduler等）+ 运行时环境准备
│   ├── HandleExcetion.py # 全局异常处理
│   ├── ImageVerification.py # 图片验证码
│   ├── IoTDBClient.py    # Apache IoTDB 时序数据库客户端
│   ├── PageSchema.py     # 分页 Schema
│   ├── PortalCors.py     # 门户 qiankun 跨域中间件
│   ├── Response.py       # 统一响应格式
│   ├── Route.py          # SPA 路由与静态资源（支持包内产物回退、UI 前缀可配）
│   ├── RuntimeHook.py    # 运行时模块加载钩子
│   ├── SchedulerLog.py   # 定时任务执行日志
│   ├── Sqlacodegen.py    # 数据库模型自动生成
│   ├── Swagger.py        # Swagger UI 配置
│   ├── SystemLog.py      # 系统日志
│   ├── Utils.py          # 工具函数（含控制器加载、模型导入）
│   └── WechatLogin.py    # 微信登录
├── config/               # 框架默认配置
│   ├── Config.py         # 默认配置项
│   └── Logger.py         # 日志配置
├── fonts/                # 字体文件
└── _template/            # 双重用途：开箱即用时的内置运行时资产 + fred-init 复制源
    ├── app.py            # 应用入口模板
    ├── common/           # 公共模块模板
    │   ├── config/       # 项目配置样例（Config.py、Config.example.py）
    │   └── model/        # 内置默认模型（24 个 ORM 类）
    ├── data/             # 数据库文件（app.db 种子库、fred.sql MySQL 脚本）
    ├── docs/             # 文档模板
    ├── modules/          # 模块模板
    │   └── admin/        # 内置 Admin 模块
    │       ├── backend/  # 后端（controller/service/schema）
    │       ├── frontend/ # 前端源码（Vue 3 + TypeScript）
    │       └── templates/# 前端构建产物（开箱即用直接读取，无需 pnpm）
    └── requirements.txt
```

> `_template/` 在包内是**只读**的：开箱即用模式下框架直接从中加载 admin 代码与前端产物，所有运行时写入（数据库、日志、上传文件）都发生在你的项目目录，绝不写入 site-packages。

### 初始化后的项目结构

```
myproject/
├── app.py                # 应用入口
├── common/               # 项目公共模块
│   ├── config/
│   │   ├── Config.py          # 项目配置（覆盖框架默认值）
│   │   └── Config.example.py  # 完整可覆盖项目录（可选参考）
│   └── model/
│       └── model.py      # 数据库模型（sqlacodegen 生成）
├── data/                 # 数据文件
│   ├── app.db            # SQLite 数据库
│   ├── backup/           # 数据库备份（执行更新或迁移前自动生成）
│   └── fred.sql          # SQL 初始化脚本
├── docs/                 # 项目文档
├── logs/                 # 日志目录
├── upload/               # 上传文件目录（首次启动自动创建）
├── download/             # 下载文件目录（首次启动自动创建）
├── modules/              # 业务模块
│   └── admin/            # 内置 Admin
│       ├── backend/
│       │   ├── constant/ # 常量定义
│       │   ├── controller/ # 控制器（API 入口，含 UpdateController）
│       │   ├── schema/   # 请求/响应 Schema
│       │   └── service/  # 业务逻辑层
│       ├── frontend/     # 前端源码
│       └── templates/    # 前端构建产物
├── requirements.txt      # 项目依赖
└── .gitignore
```

## 配置说明

项目配置位于 `common/config/Config.py`，只需配置项目特有项，其余使用框架默认值。  
完整可覆盖项目录见模板 `common/config/Config.example.py`（与 `fred_admin.config.Config` 键对齐）；框架源码注释见 `src/fred_admin/config/Config.py`。

### 必须配置

| 配置项 | 说明 | 默认值 |
|--------|------|--------|
| `SQLALCHEMY_DATABASE_URI` | 数据库连接 | `sqlite:///data/app.db` |
| `SECRET_KEY` | Flask Session 密钥 | 需在生产环境替换 |
| `JWT_SECRET_KEY` | JWT 签名密钥 | 需在生产环境替换 |

### 基础配置

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `ENABLE_SWAGGER` | `False` | 是否启用 Swagger 文档（模板脚手架常开 `True`） |
| `ENCRYPT_DATA` | `False` | 返回数据是否加密 |
| `ENABLE_GLOBAL_EXCEPTION` | `True` | 全局异常处理 |
| `DEFAULT_PASSWORD` | `'Fred@2026'` | 新建/重置用户默认密码 |
| `DEFAULT_MODULE` | `'fred_admin'` | 访问 `/` 重定向到 `/{模块名}` |

### 模块加载

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `LOAD_CUSTOM_MODULES` | `[]` | 只加载指定模块，空列表加载所有 |
| `EXTERNAL_MODULES` | `[]` | pip 包模块，如 `['uc_integration']` |
| `ENABLE_BUILTIN_ADMIN` | `True` | 是否启用包内内置 admin（开箱即用开关） |
| `ADMIN_URL_PREFIX` | `'fred_admin'` | 后台界面访问地址前缀，改成 `'backend'` 即 `http://host/backend` |

> `ADMIN_URL_PREFIX` 只影响界面挂载点，根路径 `/` 也随之跳转。
> 后端 API 前缀与蓝图名一致（`/fred_admin`），由前端构建期固化，改动 API 前缀须重建前端产物。
> 项目内 `modules/fred_admin/` 存在时始终优先于内置版本。

### 自更新

后台右上角「检查更新」按钮对应的能力，分三步：检查版本 → 预览差异 → 执行更新。

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `ENABLE_SELF_UPDATE` | `False` | 是否允许通过界面触发 pip 安装新版本 |

检查更新与预览数据库差异是只读操作，不受该开关限制；只有「执行更新」需要开启。开启后执行更新会先强制备份数据库（存于 `data/backup/`），再迁移表结构，最后安装新版本，完成后需重启应用进程。

### 门户 qiankun CORS

子系统嵌入 gss-portal 时开启；最外层 WSGI，带 credentials，不被 `after_request` 信封冲掉。

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `PORTAL_CORS_ENABLED` | `False` | 是否启用门户跨域 |
| `PORTAL_CORS_ORIGINS` | `http://127.0.0.1:5002` 等 | 允许的门户 Origin 白名单 |
| `PORTAL_CORS_PATH_PREFIXES` | `[]` | 路径前缀；空列表=全部路径，建议如 `['/todo']` |

### 数据库

```python
# SQLite（默认，无需安装）
SQLALCHEMY_DATABASE_URI = 'sqlite:///data/app.db'

# MySQL
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:pwd@127.0.0.1:3306/db'

# 多数据库绑定
SQLALCHEMY_BINDS = {'other': 'mysql+pymysql://user:pwd@127.0.0.1:3306/other'}
```

### Redis

```python
REDIS_URL = 'redis://:password@127.0.0.1:6379/1'
```

### JWT 配置

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `JWT_ACCESS_TOKEN_EXPIRES` | `timedelta(days=2)` | 访问令牌有效期 |
| `JWT_REFRESH_TOKEN_EXPIRES` | `timedelta(days=7)` | 刷新令牌有效期 |
| `FERNET_KEY` | `''` | `ENCRYPT_DATA=True` 时的加解密密钥 |

### 日志配置

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `LOG_LEVEL` | `'DEBUG'` | 日志级别 |
| `LOG_FILE` | `'logs/app.log'` | 日志文件路径 |
| `LOG_FORMAT` | 标准格式 | 日志格式字符串 |

### Swagger 配置

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `API_TITLE` | `'FredFrameApi'` | API 标题 |
| `API_VERSION` | `'v1'` | API 版本 |
| `OPENAPI_SWAGGER_UI_PATH` | `'/docs'` | Swagger 访问路径 |

### 定时任务

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `SCHEDULER_API_ENABLED` | `True` | 启用定时任务 API |
| `SCHEDULER_TIMEZONE` | `'Asia/Shanghai'` | 任务时区 |
| `JOBS` | `[]` | 预定义任务列表 |

### 邮件配置

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `MAIL_SERVER` | `''` | 邮件服务器地址 |
| `MAIL_PORT` | `25` | 端口 |
| `MAIL_USE_TLS` | `True` | 使用 TLS |
| `MAIL_USERNAME` | `''` | 邮箱用户名 |
| `MAIL_PASSWORD` | `''` | 邮箱密码 |
| `MAIL_DEFAULT_SENDER` | `''` | 默认发件人 |

### 阿里云短信

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `ALIBABA_SIGN_NAME` | `''` | 短信签名 |
| `ALIBABA_KEY_ID` | `''` | AccessKey ID |
| `ALIBABA_KEY_SECRET` | `''` | AccessKey Secret |
| `ALIBABA_TEMPLATE_CODE` | `''` | 短信模板编号 |

### 路由映射

```python
ROUTE_CONFIG = {
    'upload': 'upload',       # /upload/<path> -> upload/
    'download': 'download'    # /download/<path> -> download/
}
```

## 命令行工具

两个命令都是**可选的**：开箱即用模式下不需要执行任何命令，只在需要项目骨架或新建业务模块时使用。

### fred-init

把完整项目骨架复制到当前目录（需要前端源码或想自定义 admin 时才用）：

```bash
fred-init
```

- 复制 `app.py`、`common/`、`data/`、`modules/`、`docs/` 等
- 已存在的文件一律跳过，不覆盖你的代码
- `demo_` 前缀文件自动重命名为隐藏文件（`.gitignore` 等）
- 各模块 `templates/` 已存在时跳过前端构建；缺失时用 pnpm 构建（需先 `npm install -g pnpm`）

### fred-create

创建业务模块：

```bash
fred-create user    # 创建 user 模块
```

- 生成 `modules/user/backend/`（controller/service/schema）
- 生成 `modules/user/frontend/`（Vue 前端）
- 文档写入 `docs/modules/user.md`

## 升级与数据库迁移

### 升级方式

**开箱即用模式**（后台代码来自包内）：

```bash
pip install -U fred_admin
```

升级后重启应用即可，无需其他操作。也可以直接在后台右上角点「检查更新」完成同样的流程。

**`fred-init` 模式**（项目内有 `modules/fred_admin/`）：项目内代码优先于包内版本，升级 pip 包不会改动你的 `modules/fred_admin/`。需要用框架新特性时，重新执行一次 `fred-init` 补齐缺失文件即可——已存在的文件不会被覆盖。

### 后台「检查更新」流程

点击右上角图标 → 弹窗按三步走：

| 步骤 | 行为 | 对数据库的影响 |
|------|------|---------------|
| 1 检查版本 | 查询 PyPI 最新版本号 | 无（只读） |
| 2 分析差异 | 下载新版本包，比对表结构 | 无（只读） |
| 3 执行更新 | 备份 → 迁移表结构 → pip 安装 | 先备份再改结构 |

第 2 步的弹窗会明确列出本次更新**将影响哪些数据库表**：

- 将新建的表
- 将新增的字段（已有行取默认值，数据保留）
- 新版本已废弃的字段（默认**只报告不删除**，需勾选确认项才会真正删除）
- 字段类型变更（需重建表搬移数据，同样需勾选确认）
- 你的业务表（列出但**永不触碰**）

若本次更新不涉及数据库变更，弹窗只提示「仅代码更新」，确认后直接安装。

执行更新需要先在 `Config.py` 中开启：

```python
ENABLE_SELF_UPDATE = True
```

未开启时接口返回 403，检查与预览功能仍可用。更新完成后必须重启应用进程，新代码才会生效。

### 数据库迁移规则

迁移引擎比对「你当前的库结构」与「新版本包内置的目标结构」，按以下规则处理，全程只支持 sqlite：

| 差异类型 | 处理方式 | 数据安全 |
|---------|---------|---------|
| 新增表 | `CREATE TABLE` + 灌入种子数据 | 安全 |
| 新增字段 | `ALTER TABLE ADD COLUMN`，已有行取默认值 | 安全，数据保留 |
| 删除字段 | 默认只报告；确认后走 `DROP COLUMN` | 需确认，删前强制备份 |
| 类型变更 | 确认后重建表并搬移数据 | 需确认，删前强制备份 |
| 约束差异（NOT NULL/默认值） | 只报告，不自动执行 | 不改动 |
| 你的业务表（目标结构中不存在） | 永不触碰，仅在界面提示 | 完全保留 |

三条安全保证：

1. **执行破坏性变更前强制备份**，备份写入 `data/backup/`，备份失败则整体中止更新
2. **幂等**：重复执行迁移不会产生重复变更，也不会重复灌入种子数据
3. **绝不覆盖已有数据库文件**：只有当项目内不存在数据库时，才会从包内复制一份初始库

首次接入新版本时，如果你的库里缺少框架所需的表，框架会在启动时自动补建缺失的表并灌入种子数据，你已有的表和数据不受影响。

## 代码规范

### 后端规范（Python）

- **代码风格**: 遵循 PEP 8，使用 Google 风格注释
- **目录分层**: controller → service → model，职责清晰
- **蓝图注册**: 控制器使用 `MethodView`，自动注册到蓝图
- **Schema 验证**: 使用 marshmallow 定义请求/响应 Schema
- **异常处理**: 统一通过 `HandleException` 捕获，返回标准格式
- **日志**: 使用 `app.logger`，格式统一

### 前端规范（Vue 3 + TypeScript）

#### JS/TS 规范
- 使用 Composition API (`<script setup>`)
- 优先 `let/const`，禁止 `var`
- 禁止未使用变量、空函数
- 类型明确，避免 `any`

#### CSS/SCSS 规范
- 组件样式 `scoped`，避免全局污染
- 使用 SCSS 变量与 CSS 变量保持主题一致性
- 属性顺序遵循 recess-order

#### Vue 组件规范
- 使用 `<script setup>` 语法
- 语义化标签，避免内联样式
- Props 单向数据流，命名连字符化

#### Git 提交规范
- type 限定: `feat/fix/docs/style/refactor/perf/test/build/ci/chore/revert`
- 分支命名: `feature/xxx`, `fix/xxx`, `docs/xxx`
- 提交前自动执行 ESLint + Prettier + Stylelint

### 前端构建

```bash
cd modules/fred_admin/frontend

# 安装依赖
pnpm install

# 开发模式
pnpm dev

# 生产构建（输出到 ../templates/）
pnpm build:pro
```

## 模块开发

### 后端模块结构

```
modules/
└── your_module/
    └── backend/
        ├── constant/     # 常量（如 RedisKey.py）
        ├── controller/   # 控制器（API 入口）
        ├── schema/       # 请求/响应验证
        └── service/      # 业务逻辑
```

### 定时任务

在 `modules/your_module/backend/service/SchedulerTasks.py` 中定义任务函数：

```python
def your_task():
    # 任务逻辑
    return {'success': True, 'message': 'done'}
```

通过管理后台或 API 添加定时任务，任务会持久化到数据库，重启后自动恢复。

## License

MIT
