feat: 1. 添加axios全局路由拦截进行自动添加请求jwt。 2.重新整理路由表。 3. 文档列表新增版本差异对比。 4.菜单路由可访问列表通过对接接口返回,添加全局路由检测。
5. 修改统一认证登录和管理员登录是通过接口形式进行,存储返回的accessToken。 6. 修改交叉评查的部分样式
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
# API接口速查表
|
||||
|
||||
**版本**: v1.0
|
||||
**日期**: 2025-11-17
|
||||
**后端地址**: `http://172.16.0.55:8073`
|
||||
|
||||
---
|
||||
|
||||
## 📌 认证接口
|
||||
|
||||
### 1. 统一登录接口
|
||||
|
||||
**端点**: `POST /auth/login`
|
||||
|
||||
**支持两种方式**:
|
||||
|
||||
#### OAuth登录
|
||||
|
||||
```typescript
|
||||
POST /auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userInfo": {
|
||||
"sub": "user123", // 必填
|
||||
"username": "zhangsan", // 可选
|
||||
"nickname": "张三", // 可选
|
||||
"email": "...", // 可选
|
||||
"phone_number": "...", // 可选
|
||||
"ou_id": "dept001", // 可选
|
||||
"ou_name": "技术部", // 可选
|
||||
"is_leader": false // 可选
|
||||
},
|
||||
"expiresIn": 3600, // 必填
|
||||
"area": "梅州" // 可选,仅首次创建时保存
|
||||
}
|
||||
```
|
||||
|
||||
#### 密码登录
|
||||
|
||||
```typescript
|
||||
POST /auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "000", // 实际是sub字段
|
||||
"password": "admin06111"
|
||||
}
|
||||
```
|
||||
|
||||
**成功响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600,
|
||||
"user_info": {
|
||||
"user_id": "5",
|
||||
"username": "admin",
|
||||
"nick_name": "管理员",
|
||||
"email": null,
|
||||
"phone_number": null,
|
||||
"ou_id": "default",
|
||||
"ou_name": "未分配部门",
|
||||
"is_leader": true,
|
||||
"user_role": "admin",
|
||||
"sub": "000"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "用户名或密码错误"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📌 RBAC路由接口
|
||||
|
||||
### 2. 获取用户路由
|
||||
|
||||
**端点**: `GET /user/routes` 或 `GET /rbac/user/routes`
|
||||
|
||||
**请求头**:
|
||||
|
||||
```
|
||||
Authorization: Bearer {JWT_TOKEN}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"user_id": 6,
|
||||
"username": "001",
|
||||
"routes": [
|
||||
{
|
||||
"id": 1,
|
||||
"route_path": "/",
|
||||
"route_name": "Layout",
|
||||
"component": "layout/index",
|
||||
"route_title": "入口页",
|
||||
"icon": "el-icon-s-home",
|
||||
"sort_order": 1,
|
||||
"is_hidden": false,
|
||||
"is_cache": true,
|
||||
"children": [...]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 检查路由权限
|
||||
|
||||
**端点**: `GET /rbac/check-route`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
```
|
||||
route_path: /system/users
|
||||
```
|
||||
|
||||
**请求头**:
|
||||
|
||||
```
|
||||
Authorization: Bearer {JWT_TOKEN}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"route_path": "/system/users",
|
||||
"has_access": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 清除路由缓存
|
||||
|
||||
**端点**: `POST /rbac/clear-routes-cache`
|
||||
|
||||
**请求头**:
|
||||
|
||||
```
|
||||
Authorization: Bearer {JWT_TOKEN}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"message": "路由缓存已清除"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📌 PostgREST数据接口
|
||||
|
||||
### 通用规则
|
||||
|
||||
**所有数据表访问格式**:
|
||||
|
||||
```
|
||||
GET /{table_name} # 查询
|
||||
POST /{table_name} # 创建
|
||||
PATCH /{table_name}?{filter} # 更新
|
||||
DELETE /{table_name}?{filter} # 删除
|
||||
```
|
||||
|
||||
**请求头**:
|
||||
|
||||
```
|
||||
Authorization: Bearer {JWT_TOKEN}
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### PostgREST过滤操作符
|
||||
|
||||
| 操作符 | 说明 | 示例 |
|
||||
|-------|------|------|
|
||||
| `eq` | 等于 | `id=eq.5` |
|
||||
| `neq` | 不等于 | `status=neq.1` |
|
||||
| `gt` | 大于 | `id=gt.10` |
|
||||
| `gte` | 大于等于 | `id=gte.10` |
|
||||
| `lt` | 小于 | `id=lt.100` |
|
||||
| `lte` | 小于等于 | `id=lte.100` |
|
||||
| `like` | 模糊匹配 | `title=like.*合同*` |
|
||||
| `ilike` | 不区分大小写模糊匹配 | `title=ilike.*word*` |
|
||||
| `in` | 在列表中 | `id=in.(1,2,3)` |
|
||||
| `is` | 是NULL | `deleted_at=is.null` |
|
||||
| `not.is` | 不是NULL | `deleted_at=not.is.null` |
|
||||
|
||||
### 查询参数
|
||||
|
||||
| 参数 | 说明 | 示例 |
|
||||
|-----|------|------|
|
||||
| `select` | 选择字段 | `select=id,title,created_at` |
|
||||
| `order` | 排序 | `order=created_at.desc` |
|
||||
| `limit` | 限制数量 | `limit=20` |
|
||||
| `offset` | 偏移量 | `offset=40` |
|
||||
|
||||
---
|
||||
|
||||
## 📌 常用数据表
|
||||
|
||||
### documents(文档表)
|
||||
|
||||
**查询文档列表**:
|
||||
|
||||
```typescript
|
||||
GET /documents?user_id=eq.5&status=eq.0&select=id,title,created_at&order=created_at.desc&limit=20&offset=0
|
||||
```
|
||||
|
||||
**创建文档**:
|
||||
|
||||
```typescript
|
||||
POST /documents
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"title": "测试文档",
|
||||
"user_id": 5,
|
||||
"status": 0
|
||||
}
|
||||
```
|
||||
|
||||
**更新文档**:
|
||||
|
||||
```typescript
|
||||
PATCH /documents?id=eq.123
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"title": "新标题",
|
||||
"status": 1
|
||||
}
|
||||
```
|
||||
|
||||
**删除文档**:
|
||||
|
||||
```typescript
|
||||
DELETE /documents?id=eq.123
|
||||
```
|
||||
|
||||
### sso_users(用户表)
|
||||
|
||||
**查询用户**:
|
||||
|
||||
```typescript
|
||||
GET /sso_users?sub=eq.000&select=id,username,nick_name,email
|
||||
```
|
||||
|
||||
**注意**: 普通用户无法直接访问 `sso_users` 表,需要通过特殊接口。
|
||||
|
||||
### roles(角色表)
|
||||
|
||||
**查询所有角色**:
|
||||
|
||||
```typescript
|
||||
GET /roles?is_system_role=eq.true&select=id,role_key,role_name,priority&order=priority.desc
|
||||
```
|
||||
|
||||
### user_role(用户-角色关联表)
|
||||
|
||||
**查询用户角色**:
|
||||
|
||||
```typescript
|
||||
GET /user_role?user_id=eq.5&select=role_id
|
||||
```
|
||||
|
||||
### sys_routes(路由表)
|
||||
|
||||
**查询所有路由**:
|
||||
|
||||
```typescript
|
||||
GET /sys_routes?status=eq.0&deleted_at=is.null&select=id,route_path,route_title&order=sort_order
|
||||
```
|
||||
|
||||
### role_route(角色-路由关联表)
|
||||
|
||||
**查询角色路由**:
|
||||
|
||||
```typescript
|
||||
GET /role_route?role_id=eq.1&select=route_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📌 完整示例
|
||||
|
||||
### 登录 + 获取路由 + 查询数据
|
||||
|
||||
```typescript
|
||||
import axios from 'axios';
|
||||
|
||||
const API_BASE = 'http://172.16.0.55:8073';
|
||||
|
||||
// 1. 登录
|
||||
const login = async () => {
|
||||
const response = await axios.post(`${API_BASE}/auth/login`, {
|
||||
username: '001',
|
||||
password: 'gdyc06111'
|
||||
});
|
||||
|
||||
const { access_token, user_info } = response.data.data;
|
||||
localStorage.setItem('token', access_token);
|
||||
|
||||
return { token: access_token, userInfo: user_info };
|
||||
};
|
||||
|
||||
// 2. 获取路由
|
||||
const fetchRoutes = async (token: string) => {
|
||||
const response = await axios.get(`${API_BASE}/user/routes`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
return response.data.data.routes;
|
||||
};
|
||||
|
||||
// 3. 查询文档(普通用户)
|
||||
const fetchDocuments = async (token: string, userId: string) => {
|
||||
const response = await axios.get(`${API_BASE}/documents`, {
|
||||
params: {
|
||||
user_id: `eq.${userId}`, // 只查自己的数据
|
||||
status: `eq.0`,
|
||||
select: 'id,title,created_at',
|
||||
order: 'created_at.desc',
|
||||
limit: 20,
|
||||
offset: 0
|
||||
},
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// 4. 创建文档
|
||||
const createDocument = async (token: string, userId: string) => {
|
||||
const response = await axios.post(`${API_BASE}/documents`, {
|
||||
title: '测试文档',
|
||||
user_id: parseInt(userId),
|
||||
status: 0
|
||||
}, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// 使用示例
|
||||
const main = async () => {
|
||||
// 登录
|
||||
const { token, userInfo } = await login();
|
||||
console.log('登录成功:', userInfo);
|
||||
|
||||
// 获取路由
|
||||
const routes = await fetchRoutes(token);
|
||||
console.log('用户路由:', routes);
|
||||
|
||||
// 查询文档
|
||||
const docs = await fetchDocuments(token, userInfo.user_id);
|
||||
console.log('文档列表:', docs);
|
||||
|
||||
// 创建文档
|
||||
const newDoc = await createDocument(token, userInfo.user_id);
|
||||
console.log('新建文档:', newDoc);
|
||||
};
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📌 错误码对照表
|
||||
|
||||
| HTTP状态码 | 说明 | 处理方式 |
|
||||
|-----------|------|---------|
|
||||
| 200 | 成功 | 正常处理 |
|
||||
| 400 | 请求参数错误 | 检查请求参数 |
|
||||
| 401 | 未授权/Token过期 | 重新登录 |
|
||||
| 403 | 无权限访问 | 提示用户无权限 |
|
||||
| 404 | 资源不存在 | 检查路径是否正确 |
|
||||
| 500 | 服务器错误 | 联系后端开发人员 |
|
||||
|
||||
---
|
||||
|
||||
## 📌 测试账号
|
||||
|
||||
| 用户名 | 密码 | 角色 | 路由数 | 说明 |
|
||||
|--------|------|------|-------|------|
|
||||
| 000 | admin06111 | 超级管理员 | 29 | 所有权限 |
|
||||
| 001 | gdyc06111 | 普通用户 | 19 | 有限权限 |
|
||||
| jy001 | jyyc0814 | 系统管理员 | 29 | 管理员权限 |
|
||||
| mz001 | mzyc06111 | 系统管理员 | 29 | 管理员权限 |
|
||||
| yf001 | yfyc06111 | 系统管理员 | 29 | 管理员权限 |
|
||||
| cz001 | czyc06111 | 系统管理员 | 29 | 管理员权限 |
|
||||
|
||||
---
|
||||
|
||||
## 📌 快速链接
|
||||
|
||||
- **完整对接文档**: `docs/RBAC/前端完整对接文档_RBAC与PostgREST.md`
|
||||
- **快速开始**: `docs/RBAC/前端快速开始_5分钟集成.md`
|
||||
- **用户管理**: `docs/RBAC/用户管理完整指南.md`
|
||||
- **RBAC总结**: `docs/RBAC/RBAC系统使用总结.md`
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025-11-17
|
||||
**维护者**: Claude Code
|
||||
+1316
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,121 @@
|
||||
# API端点列表
|
||||
|
||||
## PostgREST代理端点
|
||||
|
||||
所有PostgREST代理端点都位于 `/api/v1/postgrest/{table_name}`
|
||||
|
||||
支持的HTTP方法:GET, POST, PATCH, DELETE
|
||||
|
||||
### 文档管理模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| documents | /api/v1/postgrest/documents | 文档表 | document:document:view/create/update/delete |
|
||||
| document_types | /api/v1/postgrest/document_types | 文档类型(公共数据) | document:type:view/create/update/delete |
|
||||
| document_metadata | /api/v1/postgrest/document_metadata | 文档元数据 | document:metadata:view/create/update/delete |
|
||||
|
||||
### 评查管理模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| evaluation_results | /api/v1/postgrest/evaluation_results | 评查结果 | evaluation:result:view/create/update/delete |
|
||||
| evaluation_points | /api/v1/postgrest/evaluation_points | 评查点配置 | evaluation:point:view/create/update/delete |
|
||||
| evaluation_point_categories | /api/v1/postgrest/evaluation_point_categories | 评查点分类 | evaluation:category:view/create/update/delete |
|
||||
| evaluation_rules | /api/v1/postgrest/evaluation_rules | 评查规则 | evaluation:rule:view/create/update/delete |
|
||||
|
||||
### 交叉评查模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| cross_examination_tasks | /api/v1/postgrest/cross_examination_tasks | 交叉评查任务 | crossreview:task:view/create/update/delete |
|
||||
| cross_task_document_mapping | /api/v1/postgrest/cross_task_document_mapping | 任务-文档映射 | crossreview:mapping:view/create/update/delete |
|
||||
| cross_scoring_proposals | /api/v1/postgrest/cross_scoring_proposals | 评分提案 | crossreview:proposal:view/create/update/delete |
|
||||
| cross_proposal_votes | /api/v1/postgrest/cross_proposal_votes | 提案投票 | crossreview:vote:view/create/update/delete |
|
||||
|
||||
### 用户管理模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| sso_users | /api/v1/postgrest/sso_users | 用户表 | system:user:view/create/update/delete |
|
||||
| user_role | /api/v1/postgrest/user_role | 用户-角色关联 | system:user_role:view/create/update/delete |
|
||||
|
||||
### 系统管理模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| roles | /api/v1/postgrest/roles | 角色表 | system:role:view/create/update/delete |
|
||||
| sys_routes | /api/v1/postgrest/sys_routes | 系统路由(菜单) | system:route:view/create/update/delete |
|
||||
| role_route | /api/v1/postgrest/role_route | 角色-路由关联 | system:role_route:view/create/update/delete |
|
||||
|
||||
### RBAC权限管理模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| permissions | /api/v1/postgrest/permissions | 权限定义 | system:permission:view/create/update/delete |
|
||||
| role_permissions | /api/v1/postgrest/role_permissions | 角色-权限关联 | system:role_permission:view/create/update/delete |
|
||||
| user_permissions | /api/v1/postgrest/user_permissions | 用户-权限关联 | system:user_permission:view/create/update/delete |
|
||||
| data_permission_rules | /api/v1/postgrest/data_permission_rules | 数据权限规则 | system:data_rule:view/create/update/delete |
|
||||
| permission_audit_logs | /api/v1/postgrest/permission_audit_logs | 权限审计日志 | system:audit_log:view/create/update/delete |
|
||||
| jwt_tokens | /api/v1/postgrest/jwt_tokens | JWT Token管理 | system:jwt_token:view/create/update/delete |
|
||||
|
||||
### 报表统计模块
|
||||
|
||||
| 表名 | 端点 | 说明 | 所需权限 |
|
||||
|------|------|------|---------|
|
||||
| statistics_summary | /api/v1/postgrest/statistics_summary | 统计汇总 | report:summary:view/create/update/delete |
|
||||
|
||||
## FastAPI业务端点
|
||||
|
||||
### 认证端点
|
||||
|
||||
| 端点 | 方法 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| /api/v1/auth/login | POST | 用户登录 | 否 |
|
||||
| /api/v1/auth/logout | POST | 用户登出 | 是 |
|
||||
| /api/v1/auth/refresh | POST | 刷新Token | 是 |
|
||||
|
||||
### 文档业务端点(示例)
|
||||
|
||||
| 端点 | 方法 | 说明 | 认证 |
|
||||
|------|------|------|------|
|
||||
| /api/v1/documents/{id}/ocr | POST | 文档OCR处理 | 是 |
|
||||
| /api/v1/documents/{id}/merge | POST | 合并PDF文档 | 是 |
|
||||
| /api/v1/documents/{id}/extract | POST | AI提取信息 | 是 |
|
||||
|
||||
## 请求示例
|
||||
|
||||
### GET请求示例
|
||||
```bash
|
||||
GET /api/v1/postgrest/documents?status=eq.active&limit=10&order=created_at.desc
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
### POST请求示例
|
||||
```bash
|
||||
POST /api/v1/postgrest/documents
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"title": "新文档",
|
||||
"content": "文档内容",
|
||||
"status": "draft"
|
||||
}
|
||||
```
|
||||
|
||||
### PATCH请求示例
|
||||
```bash
|
||||
PATCH /api/v1/postgrest/documents?id=eq.1936
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "reviewed"
|
||||
}
|
||||
```
|
||||
|
||||
### DELETE请求示例
|
||||
```bash
|
||||
DELETE /api/v1/postgrest/documents?id=eq.1936
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
@@ -0,0 +1,316 @@
|
||||
# PostgREST查询参考
|
||||
|
||||
## 过滤运算符完整列表
|
||||
|
||||
### 比较运算符
|
||||
|
||||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||||
|--------|------|---------------|----------------|
|
||||
| eq | 等于 | `field=eq.value` | `{ field: 'eq.value' }` |
|
||||
| neq | 不等于 | `field=neq.value` | `{ field: 'neq.value' }` |
|
||||
| gt | 大于 | `field=gt.value` | `{ field: 'gt.100' }` |
|
||||
| gte | 大于等于 | `field=gte.value` | `{ field: 'gte.100' }` |
|
||||
| lt | 小于 | `field=lt.value` | `{ field: 'lt.100' }` |
|
||||
| lte | 小于等于 | `field=lte.value` | `{ field: 'lte.100' }` |
|
||||
|
||||
### 模式匹配运算符
|
||||
|
||||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||||
|--------|------|---------------|----------------|
|
||||
| like | 模糊匹配(区分大小写) | `field=like.*pattern*` | `{ field: 'like.*测试*' }` |
|
||||
| ilike | 模糊匹配(不区分大小写) | `field=ilike.*pattern*` | `{ field: 'ilike.*TEST*' }` |
|
||||
|
||||
**模式匹配通配符**:
|
||||
- `*`: 匹配任意字符(等同于SQL的`%`)
|
||||
- `_`: 匹配单个字符
|
||||
|
||||
**示例**:
|
||||
```javascript
|
||||
// 查询标题以"合同"开头的文档
|
||||
{ title: 'like.合同*' }
|
||||
|
||||
// 查询标题以"合同"结尾的文档
|
||||
{ title: 'like.*合同' }
|
||||
|
||||
// 查询标题包含"合同"的文档
|
||||
{ title: 'like.*合同*' }
|
||||
|
||||
// 不区分大小写查找
|
||||
{ title: 'ilike.*contract*' }
|
||||
```
|
||||
|
||||
### 列表运算符
|
||||
|
||||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||||
|--------|------|---------------|----------------|
|
||||
| in | 在列表中 | `field=in.(value1,value2,...)` | `{ field: 'in.(active,pending)' }` |
|
||||
| cs | 包含(数组字段) | `field=cs.{value1,value2}` | `{ tags: 'cs.{重要,紧急}' }` |
|
||||
| cd | 被包含(数组字段) | `field=cd.{value1,value2}` | `{ tags: 'cd.{重要,紧急}' }` |
|
||||
| ov | 重叠(数组字段) | `field=ov.{value1,value2}` | `{ tags: 'ov.{重要,紧急}' }` |
|
||||
|
||||
**示例**:
|
||||
```javascript
|
||||
// 查询状态为active或pending的文档
|
||||
{ status: 'in.(active,pending)' }
|
||||
|
||||
// 查询ID在[1, 2, 3]中的文档
|
||||
{ id: 'in.(1,2,3)' }
|
||||
|
||||
// 查询标签包含"重要"和"紧急"的文档(数组字段)
|
||||
{ tags: 'cs.{重要,紧急}' }
|
||||
```
|
||||
|
||||
### Null检查运算符
|
||||
|
||||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||||
|--------|------|---------------|----------------|
|
||||
| is | 是null | `field=is.null` | `{ field: 'is.null' }` |
|
||||
| nt | 不是null | `field=nt.null` (或 `is.not.null`) | `{ field: 'nt.null' }` |
|
||||
|
||||
**示例**:
|
||||
```javascript
|
||||
// 查询deleted_at为null的文档(未删除)
|
||||
{ deleted_at: 'is.null' }
|
||||
|
||||
// 查询deleted_at不为null的文档(已删除)
|
||||
{ deleted_at: 'nt.null' }
|
||||
```
|
||||
|
||||
## 排序
|
||||
|
||||
### 单字段排序
|
||||
|
||||
```javascript
|
||||
// 按创建时间升序
|
||||
{ order: 'created_at.asc' }
|
||||
|
||||
// 按创建时间降序
|
||||
{ order: 'created_at.desc' }
|
||||
```
|
||||
|
||||
### 多字段排序
|
||||
|
||||
```javascript
|
||||
// 先按状态升序,再按创建时间降序
|
||||
{ order: 'status.asc,created_at.desc' }
|
||||
```
|
||||
|
||||
## 分页
|
||||
|
||||
### Limit和Offset
|
||||
|
||||
```javascript
|
||||
// 每页10条,第1页
|
||||
{ limit: 10, offset: 0 }
|
||||
|
||||
// 每页10条,第2页
|
||||
{ limit: 10, offset: 10 }
|
||||
|
||||
// 每页20条,第3页
|
||||
{ limit: 20, offset: 40 }
|
||||
```
|
||||
|
||||
### 获取总数
|
||||
|
||||
PostgREST会在响应头中返回`Content-Range`,包含总记录数:
|
||||
|
||||
```
|
||||
Content-Range: 0-9/50
|
||||
```
|
||||
表示:返回第0-9条记录,总共50条记录。
|
||||
|
||||
**解析示例**:
|
||||
```javascript
|
||||
const response = await apiClient.get('/postgrest/documents', {
|
||||
params: { limit: 10, offset: 0 }
|
||||
});
|
||||
|
||||
const contentRange = response.headers['content-range'];
|
||||
const total = parseInt(contentRange.split('/')[1]); // 50
|
||||
```
|
||||
|
||||
## 字段选择
|
||||
|
||||
### 选择特定字段
|
||||
|
||||
```javascript
|
||||
// 只返回id, title, status字段
|
||||
{ select: 'id,title,status' }
|
||||
```
|
||||
|
||||
### 嵌套查询(外键关联)
|
||||
|
||||
PostgREST支持嵌套查询,但DocAuditAI暂未启用此功能。
|
||||
|
||||
## 高级查询
|
||||
|
||||
### 逻辑运算符
|
||||
|
||||
**注意**: 前端应避免使用`or`、`and`、`not`参数,这些参数由后端自动生成(用于数据范围和交叉评查权限)。
|
||||
|
||||
### 复杂查询示例
|
||||
|
||||
```javascript
|
||||
// 查询状态为active且创建时间在2025年之后的文档,按创建时间降序,每页10条
|
||||
const params = {
|
||||
status: 'eq.active',
|
||||
created_at: 'gte.2025-01-01',
|
||||
order: 'created_at.desc',
|
||||
limit: 10,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
const response = await apiClient.get('/postgrest/documents', { params });
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 示例1:文档列表查询
|
||||
|
||||
```javascript
|
||||
// 需求:查询标题包含"合同"、状态为active的文档,
|
||||
// 按创建时间降序排列,每页20条,第2页
|
||||
|
||||
async function getDocumentList() {
|
||||
const response = await apiClient.get('/postgrest/documents', {
|
||||
params: {
|
||||
title: 'ilike.*合同*',
|
||||
status: 'eq.active',
|
||||
order: 'created_at.desc',
|
||||
limit: 20,
|
||||
offset: 20 // 第2页
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
data: response.data,
|
||||
total: parseInt(response.headers['content-range'].split('/')[1])
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 示例2:高级搜索
|
||||
|
||||
```javascript
|
||||
// 需求:搜索2025年创建的、状态为active或pending的文档
|
||||
|
||||
async function advancedSearch() {
|
||||
const response = await apiClient.get('/postgrest/documents', {
|
||||
params: {
|
||||
status: 'in.(active,pending)',
|
||||
created_at: 'gte.2025-01-01',
|
||||
created_at: 'lt.2026-01-01', // 注意:PostgREST会组合多个同名参数
|
||||
order: 'created_at.desc'
|
||||
}
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
```
|
||||
|
||||
### 示例3:分页封装
|
||||
|
||||
```javascript
|
||||
// 通用分页函数
|
||||
async function fetchPaginated(table, page, pageSize, filters = {}) {
|
||||
const params = {
|
||||
limit: pageSize,
|
||||
offset: (page - 1) * pageSize,
|
||||
...filters
|
||||
};
|
||||
|
||||
const response = await apiClient.get(`/postgrest/${table}`, { params });
|
||||
|
||||
const contentRange = response.headers['content-range'];
|
||||
const total = contentRange ? parseInt(contentRange.split('/')[1]) : 0;
|
||||
|
||||
return {
|
||||
data: response.data,
|
||||
total: total,
|
||||
page: page,
|
||||
pageSize: pageSize,
|
||||
totalPages: Math.ceil(total / pageSize)
|
||||
};
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const result = await fetchPaginated('documents', 1, 10, {
|
||||
status: 'eq.active',
|
||||
order: 'created_at.desc'
|
||||
});
|
||||
|
||||
console.log(`共${result.total}条记录,第${result.page}/${result.totalPages}页`);
|
||||
```
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 1. 始终使用分页
|
||||
|
||||
```javascript
|
||||
// ✅ 好的做法
|
||||
{ limit: 10, offset: 0 }
|
||||
|
||||
// ❌ 不好的做法(返回所有数据)
|
||||
{}
|
||||
```
|
||||
|
||||
### 2. 只查询需要的字段
|
||||
|
||||
```javascript
|
||||
// ✅ 好的做法(只查询id和title)
|
||||
{ select: 'id,title' }
|
||||
|
||||
// ❌ 不好的做法(查询所有字段)
|
||||
{}
|
||||
```
|
||||
|
||||
### 3. 使用索引字段进行过滤
|
||||
|
||||
优先使用已建立索引的字段(如id, user_id, ou_id, status)进行过滤,提升查询性能。
|
||||
|
||||
### 4. 避免过度模糊查询
|
||||
|
||||
```javascript
|
||||
// ✅ 好的做法(明确的过滤条件)
|
||||
{ title: 'like.合同*' }
|
||||
|
||||
// ❌ 不好的做法(前后通配符,性能差)
|
||||
{ title: 'like.*合同*' }
|
||||
```
|
||||
|
||||
## 常见错误
|
||||
|
||||
### 错误1:运算符拼写错误
|
||||
|
||||
```javascript
|
||||
// ❌ 错误
|
||||
{ status: 'equal.active' } // 应该是 eq
|
||||
|
||||
// ✅ 正确
|
||||
{ status: 'eq.active' }
|
||||
```
|
||||
|
||||
### 错误2:日期格式错误
|
||||
|
||||
```javascript
|
||||
// ❌ 错误
|
||||
{ created_at: 'gte.2025/01/01' } // 格式错误
|
||||
|
||||
// ✅ 正确
|
||||
{ created_at: 'gte.2025-01-01' } // ISO 8601格式
|
||||
```
|
||||
|
||||
### 错误3:in运算符语法错误
|
||||
|
||||
```javascript
|
||||
// ❌ 错误
|
||||
{ status: 'in.active,pending' } // 缺少括号
|
||||
|
||||
// ✅ 正确
|
||||
{ status: 'in.(active,pending)' }
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [PostgREST官方文档](https://postgrest.org/en/stable/)
|
||||
- [PostgREST API查询语法](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows)
|
||||
@@ -0,0 +1,338 @@
|
||||
# 权限列表
|
||||
|
||||
本文档列出DocAuditAI系统中所有权限及其对应的操作。
|
||||
|
||||
## 权限键格式
|
||||
|
||||
权限键格式:`{module}:{resource}:{action}`
|
||||
|
||||
- **module**: 模块名称(如document, system, evaluation)
|
||||
- **resource**: 资源名称(如document, user, role)
|
||||
- **action**: 操作类型(view, create, update, delete等)
|
||||
|
||||
## 文档管理模块 (document)
|
||||
|
||||
| 权限键 | 说明 | 对应操作 |
|
||||
|--------|------|---------|
|
||||
| document:document:view | 查看文档 | GET /postgrest/documents |
|
||||
| document:document:create | 创建文档 | POST /postgrest/documents |
|
||||
| document:document:update | 更新文档 | PATCH /postgrest/documents |
|
||||
| document:document:delete | 删除文档 | DELETE /postgrest/documents |
|
||||
| document:type:view | 查看文档类型 | GET /postgrest/document_types |
|
||||
| document:type:create | 创建文档类型 | POST /postgrest/document_types |
|
||||
| document:type:update | 更新文档类型 | PATCH /postgrest/document_types |
|
||||
| document:type:delete | 删除文档类型 | DELETE /postgrest/document_types |
|
||||
| document:metadata:view | 查看文档元数据 | GET /postgrest/document_metadata |
|
||||
| document:metadata:create | 创建文档元数据 | POST /postgrest/document_metadata |
|
||||
| document:metadata:update | 更新文档元数据 | PATCH /postgrest/document_metadata |
|
||||
| document:metadata:delete | 删除文档元数据 | DELETE /postgrest/document_metadata |
|
||||
|
||||
## 评查管理模块 (evaluation)
|
||||
|
||||
| 权限键 | 说明 | 对应操作 |
|
||||
|--------|------|---------|
|
||||
| evaluation:result:view | 查看评查结果 | GET /postgrest/evaluation_results |
|
||||
| evaluation:result:create | 创建评查结果 | POST /postgrest/evaluation_results |
|
||||
| evaluation:result:update | 更新评查结果 | PATCH /postgrest/evaluation_results |
|
||||
| evaluation:result:delete | 删除评查结果 | DELETE /postgrest/evaluation_results |
|
||||
| evaluation:point:view | 查看评查点 | GET /postgrest/evaluation_points |
|
||||
| evaluation:point:create | 创建评查点 | POST /postgrest/evaluation_points |
|
||||
| evaluation:point:update | 更新评查点 | PATCH /postgrest/evaluation_points |
|
||||
| evaluation:point:delete | 删除评查点 | DELETE /postgrest/evaluation_points |
|
||||
| evaluation:category:view | 查看评查点分类 | GET /postgrest/evaluation_point_categories |
|
||||
| evaluation:category:create | 创建评查点分类 | POST /postgrest/evaluation_point_categories |
|
||||
| evaluation:category:update | 更新评查点分类 | PATCH /postgrest/evaluation_point_categories |
|
||||
| evaluation:category:delete | 删除评查点分类 | DELETE /postgrest/evaluation_point_categories |
|
||||
| evaluation:rule:view | 查看评查规则 | GET /postgrest/evaluation_rules |
|
||||
| evaluation:rule:create | 创建评查规则 | POST /postgrest/evaluation_rules |
|
||||
| evaluation:rule:update | 更新评查规则 | PATCH /postgrest/evaluation_rules |
|
||||
| evaluation:rule:delete | 删除评查规则 | DELETE /postgrest/evaluation_rules |
|
||||
|
||||
## 交叉评查模块 (crossreview)
|
||||
|
||||
| 权限键 | 说明 | 对应操作 |
|
||||
|--------|------|---------|
|
||||
| crossreview:task:view | 查看交叉评查任务 | GET /postgrest/cross_examination_tasks |
|
||||
| crossreview:task:create | 创建交叉评查任务 | POST /postgrest/cross_examination_tasks |
|
||||
| crossreview:task:update | 更新交叉评查任务 | PATCH /postgrest/cross_examination_tasks |
|
||||
| crossreview:task:delete | 删除交叉评查任务 | DELETE /postgrest/cross_examination_tasks |
|
||||
| crossreview:mapping:view | 查看任务文档映射 | GET /postgrest/cross_task_document_mapping |
|
||||
| crossreview:mapping:create | 创建任务文档映射 | POST /postgrest/cross_task_document_mapping |
|
||||
| crossreview:mapping:update | 更新任务文档映射 | PATCH /postgrest/cross_task_document_mapping |
|
||||
| crossreview:mapping:delete | 删除任务文档映射 | DELETE /postgrest/cross_task_document_mapping |
|
||||
| crossreview:proposal:view | 查看评分提案 | GET /postgrest/cross_scoring_proposals |
|
||||
| crossreview:proposal:create | 创建评分提案 | POST /postgrest/cross_scoring_proposals |
|
||||
| crossreview:proposal:update | 更新评分提案 | PATCH /postgrest/cross_scoring_proposals |
|
||||
| crossreview:proposal:delete | 删除评分提案 | DELETE /postgrest/cross_scoring_proposals |
|
||||
| crossreview:vote:view | 查看提案投票 | GET /postgrest/cross_proposal_votes |
|
||||
| crossreview:vote:create | 创建提案投票 | POST /postgrest/cross_proposal_votes |
|
||||
| crossreview:vote:update | 更新提案投票 | PATCH /postgrest/cross_proposal_votes |
|
||||
| crossreview:vote:delete | 删除提案投票 | DELETE /postgrest/cross_proposal_votes |
|
||||
|
||||
## 系统管理模块 (system)
|
||||
|
||||
| 权限键 | 说明 | 对应操作 |
|
||||
|--------|------|---------|
|
||||
| system:user:view | 查看用户 | GET /postgrest/sso_users |
|
||||
| system:user:create | 创建用户 | POST /postgrest/sso_users |
|
||||
| system:user:update | 更新用户 | PATCH /postgrest/sso_users |
|
||||
| system:user:delete | 删除用户 | DELETE /postgrest/sso_users |
|
||||
| system:role:view | 查看角色 | GET /postgrest/roles |
|
||||
| system:role:create | 创建角色 | POST /postgrest/roles |
|
||||
| system:role:update | 更新角色 | PATCH /postgrest/roles |
|
||||
| system:role:delete | 删除角色 | DELETE /postgrest/roles |
|
||||
| system:route:view | 查看系统路由 | GET /postgrest/sys_routes |
|
||||
| system:route:create | 创建系统路由 | POST /postgrest/sys_routes |
|
||||
| system:route:update | 更新系统路由 | PATCH /postgrest/sys_routes |
|
||||
| system:route:delete | 删除系统路由 | DELETE /postgrest/sys_routes |
|
||||
| system:user_role:view | 查看用户-角色关联 | GET /postgrest/user_role |
|
||||
| system:user_role:create | 创建用户-角色关联 | POST /postgrest/user_role |
|
||||
| system:user_role:update | 更新用户-角色关联 | PATCH /postgrest/user_role |
|
||||
| system:user_role:delete | 删除用户-角色关联 | DELETE /postgrest/user_role |
|
||||
| system:role_route:view | 查看角色-路由关联 | GET /postgrest/role_route |
|
||||
| system:role_route:create | 创建角色-路由关联 | POST /postgrest/role_route |
|
||||
| system:role_route:update | 更新角色-路由关联 | PATCH /postgrest/role_route |
|
||||
| system:role_route:delete | 删除角色-路由关联 | DELETE /postgrest/role_route |
|
||||
| system:permission:view | 查看权限定义 | GET /postgrest/permissions |
|
||||
| system:permission:create | 创建权限定义 | POST /postgrest/permissions |
|
||||
| system:permission:update | 更新权限定义 | PATCH /postgrest/permissions |
|
||||
| system:permission:delete | 删除权限定义 | DELETE /postgrest/permissions |
|
||||
| system:role_permission:view | 查看角色-权限关联 | GET /postgrest/role_permissions |
|
||||
| system:role_permission:create | 创建角色-权限关联 | POST /postgrest/role_permissions |
|
||||
| system:role_permission:update | 更新角色-权限关联 | PATCH /postgrest/role_permissions |
|
||||
| system:role_permission:delete | 删除角色-权限关联 | DELETE /postgrest/role_permissions |
|
||||
| system:user_permission:view | 查看用户-权限关联 | GET /postgrest/user_permissions |
|
||||
| system:user_permission:create | 创建用户-权限关联 | POST /postgrest/user_permissions |
|
||||
| system:user_permission:update | 更新用户-权限关联 | PATCH /postgrest/user_permissions |
|
||||
| system:user_permission:delete | 删除用户-权限关联 | DELETE /postgrest/user_permissions |
|
||||
| system:data_rule:view | 查看数据权限规则 | GET /postgrest/data_permission_rules |
|
||||
| system:data_rule:create | 创建数据权限规则 | POST /postgrest/data_permission_rules |
|
||||
| system:data_rule:update | 更新数据权限规则 | PATCH /postgrest/data_permission_rules |
|
||||
| system:data_rule:delete | 删除数据权限规则 | DELETE /postgrest/data_permission_rules |
|
||||
| system:audit_log:view | 查看审计日志 | GET /postgrest/permission_audit_logs |
|
||||
| system:audit_log:create | 创建审计日志 | POST /postgrest/permission_audit_logs |
|
||||
| system:audit_log:update | 更新审计日志 | PATCH /postgrest/permission_audit_logs |
|
||||
| system:audit_log:delete | 删除审计日志 | DELETE /postgrest/permission_audit_logs |
|
||||
| system:jwt_token:view | 查看JWT Token | GET /postgrest/jwt_tokens |
|
||||
| system:jwt_token:create | 创建JWT Token | POST /postgrest/jwt_tokens |
|
||||
| system:jwt_token:update | 更新JWT Token | PATCH /postgrest/jwt_tokens |
|
||||
| system:jwt_token:delete | 删除JWT Token | DELETE /postgrest/jwt_tokens |
|
||||
|
||||
## 报表统计模块 (report)
|
||||
|
||||
| 权限键 | 说明 | 对应操作 |
|
||||
|--------|------|---------|
|
||||
| report:summary:view | 查看统计汇总 | GET /postgrest/statistics_summary |
|
||||
| report:summary:create | 创建统计汇总 | POST /postgrest/statistics_summary |
|
||||
| report:summary:update | 更新统计汇总 | PATCH /postgrest/statistics_summary |
|
||||
| report:summary:delete | 删除统计汇总 | DELETE /postgrest/statistics_summary |
|
||||
|
||||
## 预定义角色及其权限
|
||||
|
||||
### 1. 系统管理员
|
||||
拥有所有权限(71个权限)
|
||||
|
||||
### 2. 文档管理员
|
||||
- document:document:view
|
||||
- document:document:create
|
||||
- document:document:update
|
||||
- document:document:delete
|
||||
- document:type:view
|
||||
- document:type:create
|
||||
- document:type:update
|
||||
- document:type:delete
|
||||
- document:metadata:view
|
||||
- document:metadata:create
|
||||
- document:metadata:update
|
||||
- document:metadata:delete
|
||||
|
||||
### 3. 文档审查员
|
||||
- document:document:view
|
||||
- document:document:update
|
||||
- evaluation:result:view
|
||||
- evaluation:result:create
|
||||
- evaluation:result:update
|
||||
- evaluation:point:view
|
||||
|
||||
### 4. 交叉评查管理员
|
||||
- crossreview:task:view
|
||||
- crossreview:task:create
|
||||
- crossreview:task:update
|
||||
- crossreview:task:delete
|
||||
- crossreview:mapping:view
|
||||
- crossreview:mapping:create
|
||||
- crossreview:mapping:update
|
||||
- crossreview:mapping:delete
|
||||
- crossreview:proposal:view
|
||||
- crossreview:proposal:create
|
||||
- crossreview:proposal:update
|
||||
- crossreview:vote:view
|
||||
- crossreview:vote:create
|
||||
- crossreview:vote:update
|
||||
|
||||
### 5. 交叉评查参与者
|
||||
- crossreview:task:view
|
||||
- crossreview:mapping:view
|
||||
- crossreview:proposal:view
|
||||
- crossreview:proposal:create
|
||||
- crossreview:vote:view
|
||||
- crossreview:vote:create
|
||||
|
||||
### 6. 评价点管理员
|
||||
- evaluation:point:view
|
||||
- evaluation:point:create
|
||||
- evaluation:point:update
|
||||
- evaluation:point:delete
|
||||
- evaluation:category:view
|
||||
- evaluation:category:create
|
||||
- evaluation:category:update
|
||||
- evaluation:category:delete
|
||||
- evaluation:rule:view
|
||||
- evaluation:rule:create
|
||||
- evaluation:rule:update
|
||||
- evaluation:rule:delete
|
||||
|
||||
### 7. 报表查看员
|
||||
- report:summary:view
|
||||
- document:document:view
|
||||
- evaluation:result:view
|
||||
|
||||
### 8. 普通用户
|
||||
- document:document:view
|
||||
- document:type:view
|
||||
- evaluation:point:view
|
||||
- evaluation:category:view
|
||||
|
||||
### 9. 审计员
|
||||
- system:audit_log:view
|
||||
- document:document:view
|
||||
- evaluation:result:view
|
||||
- crossreview:task:view
|
||||
|
||||
## 前端权限控制示例
|
||||
|
||||
### 示例1:按钮权限控制
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- 只有拥有document:document:delete权限的用户才能看到删除按钮 -->
|
||||
<button v-permission="'document:document:delete'" @click="deleteDoc">
|
||||
删除文档
|
||||
</button>
|
||||
|
||||
<!-- 只有系统管理员才能看到 -->
|
||||
<button v-role="'系统管理员'" @click="showAdminPanel">
|
||||
管理面板
|
||||
</button>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 示例2:菜单权限控制
|
||||
|
||||
```javascript
|
||||
// 菜单配置(根据权限动态生成)
|
||||
const menuConfig = [
|
||||
{
|
||||
name: '文档管理',
|
||||
permission: 'document:document:view',
|
||||
children: [
|
||||
{ name: '文档列表', permission: 'document:document:view', path: '/documents' },
|
||||
{ name: '新建文档', permission: 'document:document:create', path: '/documents/new' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '评查管理',
|
||||
permission: 'evaluation:point:view',
|
||||
children: [
|
||||
{ name: '评查点配置', permission: 'evaluation:point:view', path: '/evaluation/points' },
|
||||
{ name: '评查结果', permission: 'evaluation:result:view', path: '/evaluation/results' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '系统管理',
|
||||
role: '系统管理员', // 只有系统管理员才能看到
|
||||
children: [
|
||||
{ name: '用户管理', permission: 'system:user:view', path: '/system/users' },
|
||||
{ name: '角色管理', permission: 'system:role:view', path: '/system/roles' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// 过滤菜单(根据用户权限)
|
||||
function filterMenuByPermission(menu, userPermissions, userRoles) {
|
||||
return menu.filter(item => {
|
||||
// 检查角色
|
||||
if (item.role && !userRoles.includes(item.role)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
if (item.permission && !userPermissions.includes(item.permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 递归过滤子菜单
|
||||
if (item.children) {
|
||||
item.children = filterMenuByPermission(item.children, userPermissions, userRoles);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 示例3:路由守卫
|
||||
|
||||
```javascript
|
||||
// router.js
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/documents',
|
||||
component: DocumentList,
|
||||
meta: { permission: 'document:document:view' }
|
||||
},
|
||||
{
|
||||
path: '/system/users',
|
||||
component: UserManagement,
|
||||
meta: { role: '系统管理员' }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 全局路由守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
const userInfo = JSON.parse(localStorage.getItem('user_info') || '{}');
|
||||
|
||||
// 检查角色
|
||||
if (to.meta.role && !userInfo.roles?.includes(to.meta.role)) {
|
||||
alert('无权访问此页面');
|
||||
next('/');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查权限(简化版,实际应维护权限列表)
|
||||
if (to.meta.permission) {
|
||||
// TODO: 检查用户是否有该权限
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **权限检查由后端强制执行**
|
||||
即使前端绕过权限控制,后端也会拒绝无权请求。
|
||||
|
||||
2. **前端权限控制是为了提升用户体验**
|
||||
隐藏用户无权操作的按钮和菜单,避免用户点击后被拒绝。
|
||||
|
||||
3. **定期同步权限列表**
|
||||
登录时从后端获取用户的完整权限列表,存储到前端状态管理中。
|
||||
|
||||
4. **角色权限继承**
|
||||
用户通过角色继承权限,也可以直接分配权限(优先级高于角色)。
|
||||
+1562
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,333 @@
|
||||
# 前端快速开始 - 5分钟集成RBAC系统
|
||||
|
||||
**版本**: v1.0
|
||||
**日期**: 2025-11-17
|
||||
**目标**: 最快速度集成登录、动态路由和数据访问
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 5分钟集成步骤
|
||||
|
||||
### 步骤1: 安装依赖(1分钟)
|
||||
|
||||
```bash
|
||||
npm install axios pinia vue-router@4 element-plus
|
||||
```
|
||||
|
||||
### 步骤2: 配置环境变量(30秒)
|
||||
|
||||
创建 `.env.development`:
|
||||
|
||||
```env
|
||||
VITE_API_BASE_URL=http://172.16.0.55:8073
|
||||
```
|
||||
|
||||
### 步骤3: 创建请求工具(1分钟)
|
||||
|
||||
**文件**: `src/utils/request.ts`
|
||||
|
||||
```typescript
|
||||
import axios from 'axios';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://172.16.0.55:8073',
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
// 请求拦截器:自动添加Token
|
||||
service.interceptors.request.use(config => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
// 响应拦截器:统一错误处理
|
||||
service.interceptors.response.use(
|
||||
response => response,
|
||||
error => {
|
||||
if (error.response?.status === 401) {
|
||||
ElMessage.error('登录已过期');
|
||||
localStorage.clear();
|
||||
window.location.href = '/login';
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
```
|
||||
|
||||
### 步骤4: 创建用户Store(2分钟)
|
||||
|
||||
**文件**: `src/stores/user.ts`
|
||||
|
||||
```typescript
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import request from '@/utils/request';
|
||||
import router from '@/router';
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
const token = ref('');
|
||||
const userInfo = ref<any>(null);
|
||||
const routes = ref<any[]>([]);
|
||||
|
||||
// 登录
|
||||
const login = async (username: string, password: string) => {
|
||||
const res = await request.post('/auth/login', { username, password });
|
||||
|
||||
if (res.data.success) {
|
||||
token.value = res.data.data.access_token;
|
||||
userInfo.value = res.data.data.user_info;
|
||||
|
||||
localStorage.setItem('token', token.value);
|
||||
localStorage.setItem('userInfo', JSON.stringify(userInfo.value));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 获取路由
|
||||
const fetchRoutes = async () => {
|
||||
const res = await request.get('/user/routes');
|
||||
|
||||
if (res.data.code === 200) {
|
||||
routes.value = res.data.data.routes;
|
||||
|
||||
// 动态注册路由
|
||||
routes.value.forEach(route => {
|
||||
router.addRoute({
|
||||
path: route.route_path,
|
||||
name: route.route_name,
|
||||
component: () => import(`@/views/${route.component}.vue`),
|
||||
meta: { title: route.route_title }
|
||||
});
|
||||
});
|
||||
|
||||
return routes.value;
|
||||
}
|
||||
};
|
||||
|
||||
// 登出
|
||||
const logout = () => {
|
||||
token.value = '';
|
||||
userInfo.value = null;
|
||||
routes.value = [];
|
||||
localStorage.clear();
|
||||
router.push('/login');
|
||||
};
|
||||
|
||||
return { token, userInfo, routes, login, fetchRoutes, logout };
|
||||
});
|
||||
```
|
||||
|
||||
### 步骤5: 配置路由守卫(30秒)
|
||||
|
||||
**文件**: `src/router/index.ts`
|
||||
|
||||
```typescript
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{ path: '/login', component: () => import('@/views/Login.vue') }
|
||||
]
|
||||
});
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const userStore = useUserStore();
|
||||
const token = localStorage.getItem('token');
|
||||
|
||||
if (token && !userStore.token) {
|
||||
userStore.token = token;
|
||||
userStore.userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
|
||||
}
|
||||
|
||||
if (to.path !== '/login' && !token) {
|
||||
next('/login');
|
||||
} else if (token && !userStore.routes.length) {
|
||||
await userStore.fetchRoutes();
|
||||
next({ ...to, replace: true });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
```
|
||||
|
||||
### 步骤6: 创建登录页(30秒)
|
||||
|
||||
**文件**: `src/views/Login.vue`
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<el-form @submit.prevent="handleLogin">
|
||||
<el-form-item>
|
||||
<el-input v-model="username" placeholder="用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input v-model="password" type="password" placeholder="密码" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" native-type="submit" :loading="loading">
|
||||
登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
const loading = ref(false);
|
||||
|
||||
const handleLogin = async () => {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const success = await userStore.login(username.value, password.value);
|
||||
|
||||
if (success) {
|
||||
await userStore.fetchRoutes();
|
||||
router.push('/home');
|
||||
} else {
|
||||
ElMessage.error('登录失败');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('登录失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 完成!
|
||||
|
||||
现在你已经完成了基础集成,可以:
|
||||
|
||||
1. ✅ 用户登录
|
||||
2. ✅ 动态加载路由
|
||||
3. ✅ 访问受保护的页面
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步:数据访问
|
||||
|
||||
### 查询数据
|
||||
|
||||
```typescript
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 查询文档列表
|
||||
const fetchDocuments = async () => {
|
||||
const res = await request.get('/documents', {
|
||||
params: {
|
||||
user_id: `eq.${userInfo.user_id}`, // 只查自己的数据
|
||||
limit: 20,
|
||||
offset: 0
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
};
|
||||
```
|
||||
|
||||
### 创建数据
|
||||
|
||||
```typescript
|
||||
const createDocument = async (data: any) => {
|
||||
const res = await request.post('/documents', data);
|
||||
return res.data;
|
||||
};
|
||||
```
|
||||
|
||||
### 更新数据
|
||||
|
||||
```typescript
|
||||
const updateDocument = async (id: number, data: any) => {
|
||||
const res = await request.patch(`/documents?id=eq.${id}`, data);
|
||||
return res.data;
|
||||
};
|
||||
```
|
||||
|
||||
### 删除数据
|
||||
|
||||
```typescript
|
||||
const deleteDocument = async (id: number) => {
|
||||
const res = await request.delete(`/documents?id=eq.${id}`);
|
||||
return res.data;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 测试账号
|
||||
|
||||
| 用户名 | 密码 | 角色 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 000 | admin06111 | 超级管理员 | 所有权限(29个路由) |
|
||||
| 001 | gdyc06111 | 普通用户 | 有限权限(19个路由) |
|
||||
| jy001 | jyyc0814 | 系统管理员 | 所有权限(29个路由) |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 常见问题
|
||||
|
||||
### 1. Token过期怎么办?
|
||||
|
||||
后端返回401时,自动清除Token并跳转登录页。
|
||||
|
||||
### 2. 路由404怎么办?
|
||||
|
||||
检查组件路径是否正确:
|
||||
|
||||
```typescript
|
||||
// 后端返回: component: "views/Home"
|
||||
// 前端import: @/views/views/Home.vue ❌
|
||||
|
||||
// 修改为:
|
||||
component: () => import(`@/views/Home.vue`)
|
||||
```
|
||||
|
||||
### 3. 普通用户能看到所有数据?
|
||||
|
||||
前端必须手动添加 `user_id` 过滤:
|
||||
|
||||
```typescript
|
||||
// ❌ 错误
|
||||
const docs = await request.get('/documents');
|
||||
|
||||
// ✅ 正确
|
||||
const docs = await request.get('/documents', {
|
||||
params: { user_id: `eq.${userInfo.user_id}` }
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 详细文档
|
||||
|
||||
完整API说明请查看:
|
||||
- **完整对接文档**: `docs/RBAC/前端完整对接文档_RBAC与PostgREST.md`
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025-11-17
|
||||
**维护者**: Claude Code
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user