feat: 1. 添加axios全局路由拦截进行自动添加请求jwt。 2.重新整理路由表。 3. 文档列表新增版本差异对比。 4.菜单路由可访问列表通过对接接口返回,添加全局路由检测。

5. 修改统一认证登录和管理员登录是通过接口形式进行,存储返回的accessToken。    6. 修改交叉评查的部分样式
This commit is contained in:
2025-11-18 11:06:24 +08:00
parent 8a50671c39
commit bfe39e45a9
53 changed files with 9503 additions and 2796 deletions
@@ -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格式
```
### 错误3in运算符语法错误
```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)