dongyukun
2025-05-29 be664d7c011a473002c1b413bac8303f7905d160
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<template>
  <div>
    <!-- 文件处理列表 -->
    <div class="mt-15px grid grid-cols-1 gap-2">
      <div
        v-for="(file, index) in modelValue.list"
        :key="index"
        class="flex items-center py-4px px-12px border-l-4 border-l-[#409eff] rounded-sm shadow-sm hover:bg-[#ecf5ff] transition-all duration-300"
      >
        <!-- 文件图标和名称 -->
        <div class="flex items-center min-w-[200px] mr-10px">
          <Icon icon="ep:document" class="mr-8px text-[#409eff]" />
          <span class="text-[13px] text-[#303133] break-all">{{ file.name }}</span>
        </div>
 
        <!-- 处理进度 -->
        <div class="flex-1">
          <el-progress
            :percentage="file.progress || 0"
            :stroke-width="10"
            :status="isProcessComplete(file) ? 'success' : ''"
          />
        </div>
 
        <!-- 分段数量 -->
        <div class="ml-10px text-[13px] text-[#606266]">
          分段数量:{{ file.count ? file.count : '-' }}
        </div>
      </div>
    </div>
 
    <!-- 底部完成按钮 -->
    <div class="flex justify-end mt-20px">
      <el-button
        :type="allProcessComplete ? 'success' : 'primary'"
        :disabled="!allProcessComplete"
        @click="handleComplete"
      >
        完成
      </el-button>
    </div>
  </div>
</template>
 
<script setup lang="ts">
import { KnowledgeSegmentApi } from '@/api/ai/knowledge/segment'
 
const props = defineProps({
  modelValue: {
    type: Object,
    required: true
  }
})
 
const emit = defineEmits(['update:modelValue'])
const parent = inject('parent') as any
const pollingTimer = ref<number | null>(null) // 轮询定时器 ID,用于跟踪和清除轮询进程
 
/** 判断文件处理是否完成 */
const isProcessComplete = (file) => {
  return file.progress === 100
}
 
/** 判断所有文件是否都处理完成 */
const allProcessComplete = computed(() => {
  return props.modelValue.list.every((file) => isProcessComplete(file))
})
 
/** 完成按钮点击事件处理 */
const handleComplete = () => {
  if (parent?.exposed?.handleBack) {
    parent.exposed.handleBack()
  }
}
 
/** 获取文件处理进度 */
const getProcessList = async () => {
  try {
    // 1. 调用 API 获取处理进度
    const documentIds = props.modelValue.list.filter((item) => item.id).map((item) => item.id)
    if (documentIds.length === 0) {
      return
    }
    const result = await KnowledgeSegmentApi.getKnowledgeSegmentProcessList(documentIds)
 
    // 2.1更新进度
    const updatedList = props.modelValue.list.map((file) => {
      const processInfo = result.find((item) => item.documentId === file.id)
      if (processInfo) {
        // 计算进度百分比:已嵌入数量 / 总数量 * 100
        const progress =
          processInfo.embeddingCount && processInfo.count
            ? Math.floor((processInfo.embeddingCount / processInfo.count) * 100)
            : 0
        return {
          ...file,
          progress: progress,
          count: processInfo.count || 0
        }
      }
      return file
    })
 
    // 2.2 更新数据
    emit('update:modelValue', {
      ...props.modelValue,
      list: updatedList
    })
 
    // 3. 如果未完成,继续轮询
    if (!updatedList.every((file) => isProcessComplete(file))) {
      pollingTimer.value = window.setTimeout(getProcessList, 3000)
    }
  } catch (error) {
    // 出错后也继续轮询
    console.error('获取处理进度失败:', error)
    pollingTimer.value = window.setTimeout(getProcessList, 5000)
  }
}
 
/** 组件挂载时开始轮询 */
onMounted(() => {
  // 1. 初始化进度为 0
  const initialList = props.modelValue.list.map((file) => ({
    ...file,
    progress: 0
  }))
 
  emit('update:modelValue', {
    ...props.modelValue,
    list: initialList
  })
 
  // 2. 开始轮询获取进度
  getProcessList()
})
 
/** 组件卸载前清除轮询 */
onBeforeUnmount(() => {
  // 1. 清除定时器
  if (pollingTimer.value) {
    clearTimeout(pollingTimer.value)
    pollingTimer.value = null
  }
})
</script>