Files
dify-plus/web/service/web-extend.ts
T
npc0-hue 17832f2424 fix: Dify 1.8.1问题修复
本次提交整合了多个功能改进和问题修复:

主要功能:
- 批量工作流处理功能完善,支持 Excel 上传和进度跟踪
- 管理中心反向代理和转发配置优化
- 用户同步添加互斥锁,防止并发问题
- 计费系统和额度显示优化
- AI 绘图功能扩展

前端改进:
- 文本生成应用显示修复
- 批量任务进度展示优化
- 按钮样式和 CSS 优化,禁止换行
- 多语言支持完善(新增印尼语等)
- 构建镜像逻辑优化
- 批量处理进度管理器实现

后端改进:
- Docker Compose 配置升级
- 队列任务和 Worker Pool 优化
- Admin API 初始化和验证逻辑改进
- 数据库迁移和初始化完善
- 静态变量处理优化
- URL 签名助手实现
- Celery 扩展优化
- 代码和导入包问题修复(idea 自动调整代码位置)

技术改进:
- 兼容性修复 (flask-restx, jschardet)
- 钉钉 Web API 版本更新
- 代码格式化和导入包问题修复
- 日志处理优化
- 工作流循环管理优化

Docker 相关:
- Nginx 配置更新
- 容器启动脚本优化
- 镜像构建流程改进
- docker-compose.dify-plus.yaml 大幅更新

管理后台:
- 工作流批量处理 API 实现
- 工作池初始化
- 批量工作流服务实现
- 转发扩展配置
- 用户服务扩展
2025-10-17 23:04:25 +08:00

306 lines
7.8 KiB
TypeScript

import { request } from './base'
import { API_ADMIN } from '@/config'
type batchProcessing = {
id: string
}
// 二开部分Begin - 工作流批处理上传excel
export const processExcelUploadApi = async (
image: File, installed_id: string, app_id: string, keyNameMapping?: Record<string, string>): Promise<batchProcessing | null> => {
const formData = new FormData()
formData.append('file', image)
formData.append('installed_id', installed_id)
formData.append('app_id', app_id)
if (keyNameMapping)
formData.append('key_name_mapping', JSON.stringify(keyNameMapping))
const token = localStorage.getItem('console_token')
if (!token)
return null
try {
const s = await request<{ code?: number, data?: batchProcessing, msg?: string }>(
'/gaia/workflow/batch/processing', {
method: 'POST',
body: formData,
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
// 检查返回的错误码
if (s?.code && s.code !== 0) {
const Toast = await import('@/app/components/base/toast')
Toast.default.notify({
type: 'error',
message: s.msg || '批量处理上传失败',
duration: 6000,
})
return null
}
return s?.data || null
}
catch (error: any) {
console.error('工作流批处理上传excel失败,请重新下载或检查现有模板:', error)
// 提取错误消息
let errorMessage = '工作流批处理上传excel失败,请重新下载或检查现有模板'
if (error?.response?.json) {
try {
const errorData = await error.response.json()
errorMessage = errorData.msg || errorData.message || errorMessage
}
catch {
// 忽略JSON解析错误
}
}
else if (error?.message) {
errorMessage = error.message
}
else if (typeof error === 'string') {
errorMessage = error
}
// 显示错误通知
const Toast = await import('@/app/components/base/toast')
Toast.default.notify({
type: 'error',
message: errorMessage,
duration: 6000,
})
return null
}
}
// 获取最近30天的批量工作流列表
export const fetchBatchWorkflowListApi = async (
installedId?: string,
page: number = 1,
limit: number = 10,
): Promise<{
items: Array<{
id: string
file_name: string
status: string
total_rows: number
processed_rows: number
error?: string // 添加错误信息字段
created_at: string
updated_at: string
}>
total: number
page: number
limit: number
total_pages: number
has_more: boolean
} | null> => {
const token = localStorage.getItem('console_token')
if (!token)
return null
try {
const params = new URLSearchParams({
page: page.toString(),
limit: limit.toString(),
})
if (installedId)
params.append('installed_id', installedId)
const response = await request<{
code?: number
data?: {
items: Array<{
id: string
file_name: string
status: string
total_rows: number
processed_rows: number
error?: string // 添加错误信息字段
created_at: string
updated_at: string
}>
total: number
page: number
limit: number
total_pages: number
has_more: boolean
}
msg?: string
}>(`/gaia/workflow/batch/list?${params.toString()}`, {
method: 'GET',
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
if (response?.code && response.code !== 0) {
console.error('获取批量工作流列表失败:', response.msg)
return null
}
return response?.data || null
}
catch (error: any) {
console.error('获取批量工作流列表失败:', error)
return null
}
}
// 获取批量处理进度
export const fetchProgressApi = async (batchId: string) => {
const token = localStorage.getItem('console_token')
if (!token)
return null
try {
const s = await request<{ code?: number, data?: any, msg?: string }>(
`/gaia/workflow/batch/${batchId}/progress`, {
method: 'GET',
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
// 检查返回的错误码
if (s?.code && s.code !== 0) {
console.error('获取批量处理进度失败:', s.msg)
// 对于进度查询错误,我们不显示Toast,因为这是轮询操作
return null
}
return s?.data
}
catch (error) {
console.error('获取批量处理进度失败:', error)
// 对于进度查询错误,我们不显示Toast,因为这是轮询操作
return null
}
}
// 停止批量处理
export const stopBatchApi = async (batchId: string) => {
const token = localStorage.getItem('console_token')
if (!token)
return false
try {
const s = await request<{ code: number, msg: string }>(`/gaia/workflow/batch/${batchId}/stop`, {
method: 'POST',
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
return s?.code === 0
}
catch (error) {
console.error('停止批量处理失败:', error)
return false
}
}
// 恢复批量处理
export const resumeBatchApi = async (batchId: string) => {
const token = localStorage.getItem('console_token')
if (!token)
return false
try {
const s = await request<{ code: number, msg: string }>(`/gaia/workflow/batch/${batchId}/resume`, {
method: 'POST',
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
return s?.code === 0
}
catch (error) {
console.error('恢复批量处理失败:', error)
return false
}
}
// 重试批量处理(完全重新开始所有任务)
export const retryBatchApi = async (batchId: string) => {
const token = localStorage.getItem('console_token')
if (!token)
return false
try {
const s = await request<{ code: number, msg: string }>(`/gaia/workflow/batch/${batchId}/retry`, {
method: 'POST',
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
return s?.code === 0
}
catch (error) {
console.error('重试批量处理失败:', error)
return false
}
}
// 仅重试失败的任务
export const retryFailedTasksApi = async (batchId: string) => {
const token = localStorage.getItem('console_token')
if (!token)
return false
try {
const s = await request<{ code: number, msg: string }>(`/gaia/workflow/batch/${batchId}/retry-failed`, {
method: 'POST',
headers: new Headers({}),
credentials: 'omit',
}, {
isAdminAPI: true,
bodyStringify: false,
deleteContentType: true,
})
return s?.code === 0
}
catch (error) {
console.error('重试失败任务失败:', error)
return false
}
}
// 下载批量处理结果
export const downloadBatchApi = async (batchId: string): Promise<Blob | null> => {
const token = localStorage.getItem('console_token')
if (!token)
return null
try {
const response = await fetch(`${API_ADMIN}/gaia/workflow/batch/${batchId}/download`, {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
},
credentials: 'same-origin',
})
if (!response.ok)
throw new Error(`HTTP error! status: ${response.status}`)
return await response.blob()
}
catch (error) {
console.error('下载批量处理结果失败:', error)
return null
}
}