613 lines
14 KiB
Markdown
613 lines
14 KiB
Markdown
# 系统使用统计表设计
|
|
|
|
## 1. 设计目标
|
|
|
|
基于《系统使用统计最终需求》和《系统使用统计接口设计》,设计一套可落地的数据库方案,用于支持以下统计场景:
|
|
|
|
- 登录统计
|
|
- 文档上传统计
|
|
- 文档评查统计
|
|
- 按用户、部门、地区、文档大类、文档类型、入口模块进行动态汇总
|
|
- 支持时间范围查询、排行榜、趋势图与明细导出
|
|
|
|
本次设计遵循两个原则:
|
|
|
|
- 能复用现有业务表的地方尽量复用
|
|
- 只为现有表无法满足的统计能力补最小新增表结构
|
|
|
|
## 2. 总体设计思路
|
|
|
|
统计数据来源分为两类:
|
|
|
|
- 现有业务事实表
|
|
- 新增统计事件表
|
|
|
|
其中:
|
|
|
|
- 上传、评查相关统计,尽量直接复用现有业务表
|
|
- 登录统计由于当前没有稳定入库明细,需要新增登录事件表
|
|
- 为了提升用户管理页的查询效率,建议给 `sso_users` 增加最近登录时间字段
|
|
|
|
## 3. 现有可复用表
|
|
|
|
### 3.1 用户表 `sso_users`
|
|
|
|
用途:
|
|
|
|
- 用户基础信息来源
|
|
- 部门、地区、组织维度来源
|
|
- 最近登录时间展示
|
|
|
|
当前已使用字段:
|
|
|
|
- `id`
|
|
- `sub`
|
|
- `username`
|
|
- `nick_name`
|
|
- `phone_number`
|
|
- `email`
|
|
- `ou_id`
|
|
- `ou_name`
|
|
- `area`
|
|
- `tenant_name`
|
|
- `dep_name`
|
|
- `dep_short_name`
|
|
- `status`
|
|
- `deleted_at`
|
|
|
|
代码参考:
|
|
|
|
- `fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py:36`
|
|
- `fastapi_modules/fastapi_leaudit/services/impl/rbacAdminServiceImpl.py:374`
|
|
|
|
### 3.2 文档主表 `leaudit_documents`
|
|
|
|
用途:
|
|
|
|
- 文档主记录
|
|
- 文档类型、地区、版本、处理状态来源
|
|
|
|
主要字段:
|
|
|
|
- `id`
|
|
- `type_id`
|
|
- `group_id`
|
|
- `region`
|
|
- `processing_status`
|
|
- `current_run_id`
|
|
- `version_group_key`
|
|
- `version_no`
|
|
- `is_latest_version`
|
|
- `created_at`
|
|
- `updated_at`
|
|
- `deleted_at`
|
|
|
|
代码参考:
|
|
|
|
- `fastapi_modules/fastapi_leaudit/models/leauditDocument.py:19`
|
|
|
|
### 3.3 文档文件表 `leaudit_document_files`
|
|
|
|
用途:
|
|
|
|
- 上传主文件统计
|
|
- 上传附件统计
|
|
- 上传人、上传时间明细来源
|
|
|
|
主要字段:
|
|
|
|
- `id`
|
|
- `document_id`
|
|
- `file_role`
|
|
- `file_name`
|
|
- `file_ext`
|
|
- `mime_type`
|
|
- `file_size`
|
|
- `oss_url`
|
|
- `is_active`
|
|
- `created_by`
|
|
- `created_at`
|
|
|
|
口径建议:
|
|
|
|
- 主文件上传:`file_role = 'primary'`
|
|
- 附件上传:`file_role = 'attachment'`
|
|
|
|
代码参考:
|
|
|
|
- `fastapi_modules/fastapi_leaudit/models/leauditDocumentFile.py:15`
|
|
- `fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py:224`
|
|
- `fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py:889`
|
|
|
|
### 3.4 评查运行表 `leaudit_audit_runs`
|
|
|
|
用途:
|
|
|
|
- 评查发起次数
|
|
- 评查完成次数
|
|
- 评查失败次数
|
|
- 评查时间趋势
|
|
- 评查状态与结果明细
|
|
|
|
主要字段:
|
|
|
|
- `id`
|
|
- `document_id`
|
|
- `document_file_id`
|
|
- `run_no`
|
|
- `trigger_source`
|
|
- `trigger_user_id`
|
|
- `status`
|
|
- `phase`
|
|
- `rule_set_id`
|
|
- `rule_version_id`
|
|
- `result_status`
|
|
- `total_score`
|
|
- `passed_count`
|
|
- `failed_count`
|
|
- `skipped_count`
|
|
- `started_at`
|
|
- `finished_at`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
现状说明:
|
|
|
|
- 表结构已预留 `trigger_user_id`
|
|
- 但当前代码创建 run 时尚未写入该字段
|
|
- 统计功能上线前建议补齐该字段写入逻辑
|
|
|
|
代码参考:
|
|
|
|
- `fastapi_modules/fastapi_leaudit/models/leauditAuditRun.py:16`
|
|
- `fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py:203`
|
|
|
|
### 3.5 评查指标表 `leaudit_run_metrics`
|
|
|
|
用途:
|
|
|
|
- 评查页数
|
|
- 评查耗时
|
|
- 规则数量等运行指标
|
|
|
|
主要字段:
|
|
|
|
- `run_id`
|
|
- `ocr_seconds`
|
|
- `normalize_seconds`
|
|
- `extract_seconds`
|
|
- `evaluate_seconds`
|
|
- `rescue_seconds`
|
|
- `total_seconds`
|
|
- `page_count`
|
|
- `sub_document_count`
|
|
- `field_count`
|
|
- `rule_count`
|
|
- `llm_call_count`
|
|
- `vlm_call_count`
|
|
- `rescue_rule_count`
|
|
- `artifact_count`
|
|
|
|
代码参考:
|
|
|
|
- `fastapi_modules/fastapi_leaudit/leaudit_bridge/storage_adapter.py:260`
|
|
|
|
### 3.6 文档类型表 `leaudit_document_types`
|
|
|
|
用途:
|
|
|
|
- 文档类型维度统计
|
|
- 入口模块归属
|
|
|
|
建议依赖字段:
|
|
|
|
- `id`
|
|
- `code`
|
|
- `name`
|
|
- `entry_module_id`
|
|
- `is_enabled`
|
|
- `sort_order`
|
|
|
|
### 3.7 入口模块表 `leaudit_entry_modules`
|
|
|
|
用途:
|
|
|
|
- 入口模块维度统计
|
|
- 首页/业务模块使用分析
|
|
|
|
建议依赖字段:
|
|
|
|
- `id`
|
|
- `name`
|
|
- `path`
|
|
- `sort_order`
|
|
- `is_enabled`
|
|
|
|
## 4. 建议调整的现有表
|
|
|
|
### 4.1 为 `sso_users` 增加最近登录时间字段
|
|
|
|
#### 建议新增字段
|
|
|
|
```sql
|
|
ALTER TABLE sso_users
|
|
ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ NULL;
|
|
```
|
|
|
|
#### 字段说明
|
|
|
|
| 字段 | 类型 | 允许空 | 说明 |
|
|
| --- | --- | --- | --- |
|
|
| `last_login_at` | `TIMESTAMPTZ` | 是 | 最近一次登录成功时间 |
|
|
|
|
#### 用途
|
|
|
|
- 用户列表展示“最近登录时间”
|
|
- 后台快速判断用户活跃情况
|
|
- 避免每次都扫登录事件表取最大时间
|
|
|
|
#### 更新规则
|
|
|
|
- 登录成功:更新 `last_login_at`
|
|
- 登录失败:不更新
|
|
|
|
## 5. 新增表设计
|
|
|
|
### 5.1 登录事件表 `usage_login_events`
|
|
|
|
#### 设计目的
|
|
|
|
当前系统缺少结构化登录明细表,无法稳定支撑:
|
|
|
|
- 登录次数
|
|
- 登录用户数
|
|
- 按部门登录统计
|
|
- 按地区登录统计
|
|
- 登录趋势图
|
|
- 最近登录明细导出
|
|
|
|
因此建议新增登录事件表。
|
|
|
|
#### 建表建议
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS usage_login_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NULL,
|
|
sub VARCHAR(128) NULL,
|
|
username_snapshot VARCHAR(128) NULL,
|
|
nick_name_snapshot VARCHAR(128) NULL,
|
|
department_name_snapshot VARCHAR(255) NULL,
|
|
ou_id_snapshot VARCHAR(128) NULL,
|
|
ou_name_snapshot VARCHAR(255) NULL,
|
|
area_snapshot VARCHAR(64) NULL,
|
|
login_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
login_result VARCHAR(16) NOT NULL,
|
|
login_type VARCHAR(32) NOT NULL,
|
|
ip_address VARCHAR(64) NULL,
|
|
user_agent VARCHAR(1024) NULL,
|
|
client_type VARCHAR(32) NULL,
|
|
token_jti VARCHAR(128) NULL,
|
|
failure_reason VARCHAR(255) NULL,
|
|
extra JSONB NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
#### 字段说明
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
| --- | --- | --- |
|
|
| `id` | `BIGSERIAL` | 主键 |
|
|
| `user_id` | `BIGINT` | 用户 ID,失败登录时可为空 |
|
|
| `sub` | `VARCHAR(128)` | 登录标识,兼容账号字段 |
|
|
| `username_snapshot` | `VARCHAR(128)` | 登录时用户名快照 |
|
|
| `nick_name_snapshot` | `VARCHAR(128)` | 登录时姓名快照 |
|
|
| `department_name_snapshot` | `VARCHAR(255)` | 登录时部门快照 |
|
|
| `ou_id_snapshot` | `VARCHAR(128)` | 登录时组织 ID 快照 |
|
|
| `ou_name_snapshot` | `VARCHAR(255)` | 登录时组织名称快照 |
|
|
| `area_snapshot` | `VARCHAR(64)` | 登录时地区快照 |
|
|
| `login_time` | `TIMESTAMPTZ` | 登录时间 |
|
|
| `login_result` | `VARCHAR(16)` | `success` / `failed` |
|
|
| `login_type` | `VARCHAR(32)` | `password` / `oauth` |
|
|
| `ip_address` | `VARCHAR(64)` | 登录来源 IP |
|
|
| `user_agent` | `VARCHAR(1024)` | 浏览器/终端标识 |
|
|
| `client_type` | `VARCHAR(32)` | `pc` / `mobile` / `other` |
|
|
| `token_jti` | `VARCHAR(128)` | 成功登录后的 token jti,可选 |
|
|
| `failure_reason` | `VARCHAR(255)` | 失败原因 |
|
|
| `extra` | `JSONB` | 扩展字段 |
|
|
| `created_at` | `TIMESTAMPTZ` | 记录创建时间 |
|
|
|
|
#### 索引建议
|
|
|
|
```sql
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_login_time
|
|
ON usage_login_events(login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_user_id
|
|
ON usage_login_events(user_id, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_department
|
|
ON usage_login_events(department_name_snapshot, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_area
|
|
ON usage_login_events(area_snapshot, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_result
|
|
ON usage_login_events(login_result, login_time DESC);
|
|
```
|
|
|
|
#### 统计口径建议
|
|
|
|
- 登录次数:仅统计 `login_result = 'success'`
|
|
- 登录失败次数:统计 `login_result = 'failed'`
|
|
- 最近登录时间:按用户取最后一次成功登录时间
|
|
|
|
### 5.2 文档大类映射表 `usage_document_category_mappings`(可选但强烈建议)
|
|
|
|
#### 设计目的
|
|
|
|
需求中明确要求:
|
|
|
|
- 不写死“合同类”“案卷类”
|
|
- 后续新增文档大类、文档类型后可自动纳入统计
|
|
|
|
如果当前系统已经有稳定的一级文档大类实体,可直接复用;
|
|
如果没有一张适合统计使用的稳定“大类表”,建议新增一张统计映射表。
|
|
|
|
#### 建表建议
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS usage_document_category_mappings (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
category_code VARCHAR(64) NOT NULL,
|
|
category_name VARCHAR(128) NOT NULL,
|
|
document_type_id BIGINT NOT NULL,
|
|
entry_module_id BIGINT NULL,
|
|
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
created_by BIGINT NULL,
|
|
updated_by BIGINT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ NULL
|
|
);
|
|
```
|
|
|
|
#### 字段说明
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
| --- | --- | --- |
|
|
| `id` | `BIGSERIAL` | 主键 |
|
|
| `category_code` | `VARCHAR(64)` | 统计大类编码 |
|
|
| `category_name` | `VARCHAR(128)` | 统计大类名称 |
|
|
| `document_type_id` | `BIGINT` | 关联文档类型 ID |
|
|
| `entry_module_id` | `BIGINT` | 可选,关联入口模块 |
|
|
| `is_enabled` | `BOOLEAN` | 是否启用 |
|
|
| `sort_order` | `INTEGER` | 排序 |
|
|
| `created_by` | `BIGINT` | 创建人 |
|
|
| `updated_by` | `BIGINT` | 更新人 |
|
|
| `created_at` | `TIMESTAMPTZ` | 创建时间 |
|
|
| `updated_at` | `TIMESTAMPTZ` | 更新时间 |
|
|
| `deleted_at` | `TIMESTAMPTZ` | 软删除时间 |
|
|
|
|
#### 约束与索引建议
|
|
|
|
```sql
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_usage_document_category_type
|
|
ON usage_document_category_mappings(document_type_id)
|
|
WHERE deleted_at IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_document_category_code
|
|
ON usage_document_category_mappings(category_code, is_enabled);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_document_category_module
|
|
ON usage_document_category_mappings(entry_module_id, is_enabled);
|
|
```
|
|
|
|
#### 说明
|
|
|
|
- 一种文档类型只归属一个统计大类
|
|
- 若后续系统已有成熟的一级文档大类表,可取消本表,直接复用业务表
|
|
|
|
## 6. 查询口径与表关系建议
|
|
|
|
### 6.1 登录统计
|
|
|
|
来源:
|
|
|
|
- `usage_login_events`
|
|
- `sso_users.last_login_at`
|
|
|
|
用途:
|
|
|
|
- 登录次数
|
|
- 登录用户数
|
|
- 最近登录时间
|
|
- 按部门、地区统计登录情况
|
|
|
|
### 6.2 上传统计
|
|
|
|
来源:
|
|
|
|
- `leaudit_document_files`
|
|
- `leaudit_documents`
|
|
- `sso_users`
|
|
- `leaudit_document_types`
|
|
- `leaudit_entry_modules`
|
|
- `usage_document_category_mappings`(若启用)
|
|
|
|
口径:
|
|
|
|
- 主文件上传:`leaudit_document_files.file_role = 'primary'`
|
|
- 附件上传:`leaudit_document_files.file_role = 'attachment'`
|
|
|
|
### 6.3 评查统计
|
|
|
|
来源:
|
|
|
|
- `leaudit_audit_runs`
|
|
- `leaudit_documents`
|
|
- `leaudit_document_types`
|
|
- `leaudit_entry_modules`
|
|
- `usage_document_category_mappings`(若启用)
|
|
|
|
口径:
|
|
|
|
- 发起评查次数:`leaudit_audit_runs` 记录数
|
|
- 完成评查次数:`status = 'completed'`
|
|
- 失败评查次数:`status = 'failed'`
|
|
|
|
### 6.4 地区统计
|
|
|
|
支持两种口径:
|
|
|
|
- 用户地区口径
|
|
- 登录:取 `usage_login_events.area_snapshot`
|
|
- 上传:取上传人 `sso_users.area`
|
|
- 评查:优先取触发人地区
|
|
- 文档地区口径
|
|
- 上传:取 `leaudit_documents.region`
|
|
- 评查:取 `leaudit_documents.region`
|
|
|
|
## 7. 一期是否需要聚合表
|
|
|
|
### 7.1 一期建议
|
|
|
|
一期先不新增日汇总聚合表,先使用:
|
|
|
|
- 明细事实表 + SQL 聚合
|
|
|
|
原因:
|
|
|
|
- 功能验证阶段,需求还可能变
|
|
- 统计范围目前只有登录、上传、评查三类,复杂度可控
|
|
- 先把口径跑通,比过早做聚合更重要
|
|
|
|
### 7.2 二期建议
|
|
|
|
若后续数据量变大,再补以下日汇总表:
|
|
|
|
- `usage_user_daily_stats`
|
|
- `usage_department_daily_stats`
|
|
- `usage_area_daily_stats`
|
|
- `usage_document_category_daily_stats`
|
|
- `usage_entry_module_daily_stats`
|
|
|
|
## 8. 配套代码改造建议
|
|
|
|
### 8.1 登录成功时
|
|
|
|
需要做两件事:
|
|
|
|
- 写入 `usage_login_events`
|
|
- 更新 `sso_users.last_login_at`
|
|
|
|
### 8.2 登录失败时
|
|
|
|
建议:
|
|
|
|
- 写入 `usage_login_events`
|
|
- 不更新 `sso_users.last_login_at`
|
|
|
|
### 8.3 触发评查时
|
|
|
|
建议补齐:
|
|
|
|
- `leaudit_audit_runs.trigger_user_id`
|
|
|
|
当前表已存在该字段,但创建 run 时未写入,需要补逻辑。
|
|
|
|
## 9. 推荐 SQL 变更清单
|
|
|
|
### 9.1 为 `sso_users` 增加最近登录时间
|
|
|
|
```sql
|
|
ALTER TABLE sso_users
|
|
ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ NULL;
|
|
```
|
|
|
|
### 9.2 新增登录事件表
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS usage_login_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NULL,
|
|
sub VARCHAR(128) NULL,
|
|
username_snapshot VARCHAR(128) NULL,
|
|
nick_name_snapshot VARCHAR(128) NULL,
|
|
department_name_snapshot VARCHAR(255) NULL,
|
|
ou_id_snapshot VARCHAR(128) NULL,
|
|
ou_name_snapshot VARCHAR(255) NULL,
|
|
area_snapshot VARCHAR(64) NULL,
|
|
login_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
login_result VARCHAR(16) NOT NULL,
|
|
login_type VARCHAR(32) NOT NULL,
|
|
ip_address VARCHAR(64) NULL,
|
|
user_agent VARCHAR(1024) NULL,
|
|
client_type VARCHAR(32) NULL,
|
|
token_jti VARCHAR(128) NULL,
|
|
failure_reason VARCHAR(255) NULL,
|
|
extra JSONB NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
### 9.3 新增登录事件索引
|
|
|
|
```sql
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_login_time
|
|
ON usage_login_events(login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_user_id
|
|
ON usage_login_events(user_id, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_department
|
|
ON usage_login_events(department_name_snapshot, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_area
|
|
ON usage_login_events(area_snapshot, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_result
|
|
ON usage_login_events(login_result, login_time DESC);
|
|
```
|
|
|
|
### 9.4 新增统计大类映射表(可选)
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS usage_document_category_mappings (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
category_code VARCHAR(64) NOT NULL,
|
|
category_name VARCHAR(128) NOT NULL,
|
|
document_type_id BIGINT NOT NULL,
|
|
entry_module_id BIGINT NULL,
|
|
is_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
created_by BIGINT NULL,
|
|
updated_by BIGINT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ NULL
|
|
);
|
|
```
|
|
|
|
## 10. 一期最终建议
|
|
|
|
一期最小可落地表设计建议如下:
|
|
|
|
必须做:
|
|
|
|
- `sso_users.last_login_at`
|
|
- `usage_login_events`
|
|
- 补齐 `leaudit_audit_runs.trigger_user_id` 写入逻辑
|
|
|
|
建议做:
|
|
|
|
- `usage_document_category_mappings`
|
|
|
|
可后置:
|
|
|
|
- 各类日汇总聚合表
|
|
- 复杂会话表
|
|
- 全量行为审计表
|