feat: 完善知识库、策略预览与OnlyOffice集成

## 配置与环境
- .env.example: 更新环境变量配置
- docker-compose.yml: 完善Docker编排配置
- docker/README.md: 更新Docker文档

## 后端知识库模块
- endpoints/knowledge.py: 增强知识库API端点
- schemas/knowledge.py: 扩展知识库数据模型
- services/knowledge.py: 完善知识库业务逻辑
- config.py: 优化配置管理
- storage/knowledge/.index.json: 更新知识库索引

## 前端功能
- api.js: 完善API服务层
- knowledge.js: 优化知识库服务
- onlyoffice.js: 新增OnlyOffice文档服务集成
- TopBar.vue: 优化顶部导航栏
- PoliciesView.vue: 完善策略视图
- AppShellRouteView.vue: 新增应用外壳路由视图
- views/scripts/PoliciesView.js: 优化策略脚本
- policiesPreviewFormatters.js: 新增策略预览格式化工具

## 样式
- policies-view.css: 完善策略页样式

## 测试
- api-request.test.mjs: API请求测试
- onlyoffice-service.test.mjs: OnlyOffice服务测试
- policies-preview-formatters.test.mjs: 策略预览格式化测试
This commit is contained in:
caoxiaozhu
2026-05-09 04:25:30 +00:00
parent 619281afc3
commit d9ffa9ce2c
21 changed files with 1469 additions and 508 deletions

View File

@@ -1,4 +1,37 @@
const API_BASE_STORAGE_KEY = 'x-financial-api-base-url'
const AUTH_USER_STORAGE_KEY = 'x-financial-auth-user'
function readCurrentUserHeaders() {
if (typeof window === 'undefined') {
return {}
}
const raw = window.sessionStorage.getItem(AUTH_USER_STORAGE_KEY)
if (!raw) {
return {}
}
try {
const payload = JSON.parse(raw)
const username = String(payload?.username || '').trim()
const name = String(payload?.name || username).trim()
const roleCodes = Array.isArray(payload?.roleCodes) ? payload.roleCodes.filter(Boolean) : []
const isAdmin = Boolean(payload?.isAdmin)
if (!username && !name) {
return {}
}
return {
'x-auth-username': username,
'x-auth-name': name,
'x-auth-role-codes': roleCodes.join(','),
'x-auth-is-admin': String(isAdmin)
}
} catch {
return {}
}
}
function normalizeApiBaseUrl(value) {
return String(value || '/api/v1').replace(/\/$/, '')
@@ -66,22 +99,50 @@ function buildUrl(path) {
}
export async function apiRequest(path, options = {}) {
const {
contentType = 'application/json',
responseType = 'json',
headers: customHeaders,
...fetchOptions
} = options
const headers = {
...readCurrentUserHeaders(),
...(customHeaders || {})
}
if (contentType !== null && typeof headers['Content-Type'] === 'undefined') {
headers['Content-Type'] = contentType
}
let response
try {
response = await fetch(buildUrl(path), {
headers: {
'Content-Type': 'application/json',
...(options.headers || {})
},
...options
...fetchOptions,
headers
})
} catch {
throw new Error('无法连接 FastAPI 后端服务,请确认后端已启动且浏览器可访问后端端口。')
}
let payload = null
if (responseType === 'blob') {
if (!response.ok) {
let payload = null
try {
payload = await response.json()
} catch {
payload = null
}
throw new Error(payload?.detail || '接口请求失败,请稍后重试。')
}
return response.blob()
}
let payload = null
try {
payload = await response.json()
} catch {