From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/ai/knowledge/document/form/SplitStep.vue |  238 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 238 insertions(+), 0 deletions(-)

diff --git a/src/views/ai/knowledge/document/form/SplitStep.vue b/src/views/ai/knowledge/document/form/SplitStep.vue
new file mode 100644
index 0000000..5b28ce3
--- /dev/null
+++ b/src/views/ai/knowledge/document/form/SplitStep.vue
@@ -0,0 +1,238 @@
+<template>
+  <div>
+    <!-- 涓婇儴鍒嗘璁剧疆閮ㄥ垎 -->
+    <div class="mb-20px">
+      <div class="mb-20px flex justify-between items-center">
+        <div class="text-16px font-bold flex items-center">
+          鍒嗘璁剧疆
+          <el-tooltip
+            content="绯荤粺浼氳嚜鍔ㄥ皢鏂囨。鍐呭鍒嗗壊鎴愬涓钀斤紝鎮ㄥ彲浠ユ牴鎹渶瑕佽皟鏁村垎娈垫柟寮忓拰鍐呭銆�"
+            placement="top"
+          >
+            <Icon icon="ep:warning" class="ml-5px text-gray-400" />
+          </el-tooltip>
+        </div>
+        <div>
+          <el-button type="primary" plain size="small" @click="handleAutoSegment">
+            棰勮鍒嗘
+          </el-button>
+        </div>
+      </div>
+
+      <div class="segment-settings mb-20px">
+        <el-form label-width="120px">
+          <el-form-item label="鏈�澶� Token 鏁�">
+            <el-input-number v-model="modelData.segmentMaxTokens" :min="1" :max="2048" />
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 涓嬮儴鏂囦欢棰勮閮ㄥ垎 -->
+    <div class="mb-10px">
+      <div class="text-16px font-bold mb-10px">鍒嗘棰勮</div>
+
+      <!-- 鏂囦欢閫夋嫨鍣� -->
+      <div class="file-selector mb-10px">
+        <el-dropdown v-if="modelData.list && modelData.list.length > 0" trigger="click">
+          <div class="flex items-center cursor-pointer">
+            <Icon icon="ep:document" class="text-danger mr-5px" />
+            <span>{{ currentFile?.name || '璇烽�夋嫨鏂囦欢' }}</span>
+            <span v-if="currentFile?.segments" class="ml-5px text-gray-500 text-12px">
+              ({{ currentFile.segments.length }}涓垎鐗�)
+            </span>
+            <Icon icon="ep:arrow-down" class="ml-5px" />
+          </div>
+          <template #dropdown>
+            <el-dropdown-menu>
+              <el-dropdown-item
+                v-for="(file, index) in modelData.list"
+                :key="index"
+                @click="selectFile(index)"
+              >
+                {{ file.name }}
+                <span v-if="file.segments" class="ml-5px text-gray-500 text-12px">
+                  ({{ file.segments.length }}涓垎鐗�)
+                </span>
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
+        <div v-else class="text-gray-400">鏆傛棤涓婁紶鏂囦欢</div>
+      </div>
+
+      <!-- 鏂囦欢鍐呭棰勮 -->
+      <div class="file-preview bg-gray-50 p-15px rounded-md max-h-600px overflow-y-auto">
+        <div v-if="splitLoading" class="flex justify-center items-center py-20px">
+          <Icon icon="ep:loading" class="is-loading" />
+          <span class="ml-10px">姝e湪鍔犺浇鍒嗘鍐呭...</span>
+        </div>
+        <template
+          v-else-if="currentFile && currentFile.segments && currentFile.segments.length > 0"
+        >
+          <div v-for="(segment, index) in currentFile.segments" :key="index" class="mb-10px">
+            <div class="text-gray-500 text-12px mb-5px">
+              鍒嗙墖-{{ index + 1 }} 路 {{ segment.contentLength || 0 }} 瀛楃鏁� 路
+              {{ segment.tokens || 0 }} Token
+            </div>
+            <div class="bg-white p-10px rounded-md">{{ segment.content }}</div>
+          </div>
+        </template>
+        <el-empty v-else description="鏆傛棤棰勮鍐呭" />
+      </div>
+    </div>
+
+    <!-- 娣诲姞搴曢儴鎸夐挳 -->
+    <div class="mt-20px flex justify-between">
+      <div>
+        <el-button v-if="!modelData.id" @click="handlePrevStep">涓婁竴姝�</el-button>
+      </div>
+      <div>
+        <el-button type="primary" :loading="submitLoading" @click="handleSave">
+          淇濆瓨骞跺鐞�
+        </el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed, getCurrentInstance, inject, onMounted, PropType, ref } from 'vue'
+import { Icon } from '@/components/Icon'
+import { KnowledgeSegmentApi } from '@/api/ai/knowledge/segment'
+import { useMessage } from '@/hooks/web/useMessage'
+import { KnowledgeDocumentApi } from '@/api/ai/knowledge/document'
+
+const props = defineProps({
+  modelValue: {
+    type: Object as PropType<any>,
+    required: true
+  }
+})
+
+const emit = defineEmits(['update:modelValue'])
+const message = useMessage() // 娑堟伅鎻愮ず
+const parent = inject('parent', null) // 鑾峰彇鐖剁粍浠跺疄渚�
+
+const modelData = computed({
+  get: () => props.modelValue,
+  set: (val) => emit('update:modelValue', val)
+}) // 琛ㄥ崟鏁版嵁
+
+const splitLoading = ref(false) // 鍒嗘鍔犺浇鐘舵��
+const currentFile = ref<any>(null) // 褰撳墠閫変腑鐨勬枃浠�
+const submitLoading = ref(false) // 鎻愪氦鎸夐挳鍔犺浇鐘舵��
+
+/** 閫夋嫨鏂囦欢 */
+const selectFile = async (index: number) => {
+  currentFile.value = modelData.value.list[index]
+  await splitContent(currentFile.value)
+}
+
+/** 鑾峰彇鏂囦欢鍒嗘鍐呭 */
+const splitContent = async (file: any) => {
+  if (!file || !file.url) {
+    message.warning('鏂囦欢 URL 涓嶅瓨鍦�')
+    return
+  }
+
+  splitLoading.value = true
+  try {
+    // 璋冪敤鍚庣鍒嗘鎺ュ彛锛岃幏鍙栨枃妗g殑鍒嗘鍐呭銆佸瓧绗︽暟鍜� Token 鏁�
+    file.segments = await KnowledgeSegmentApi.splitContent(
+      file.url,
+      modelData.value.segmentMaxTokens
+    )
+  } catch (error) {
+    console.error('鑾峰彇鍒嗘鍐呭澶辫触:', file, error)
+  } finally {
+    splitLoading.value = false
+  }
+}
+
+/** 澶勭悊棰勮鍒嗘 */
+const handleAutoSegment = async () => {
+  // 濡傛灉娌℃湁閫変腑鏂囦欢锛岄粯璁ら�変腑绗竴涓�
+  if (!currentFile.value && modelData.value.list && modelData.value.list.length > 0) {
+    currentFile.value = modelData.value.list[0]
+  }
+  // 濡傛灉娌℃湁閫変腑鏂囦欢锛屾彁绀鸿鍏堥�夋嫨鏂囦欢
+  if (!currentFile.value) {
+    message.warning('璇峰厛閫夋嫨鏂囦欢')
+    return
+  }
+
+  // 鑾峰彇鍒嗘鍐呭
+  await splitContent(currentFile.value)
+}
+
+/** 涓婁竴姝ユ寜閽鐞� */
+const handlePrevStep = () => {
+  const parentEl = parent || getCurrentInstance()?.parent
+  if (parentEl && typeof parentEl.exposed?.goToPrevStep === 'function') {
+    parentEl.exposed.goToPrevStep()
+  }
+}
+
+/** 淇濆瓨鎿嶄綔 */
+const handleSave = async () => {
+  // 淇濆瓨鍓嶉獙璇�
+  if (!currentFile?.value?.segments || currentFile.value.segments.length === 0) {
+    message.warning('璇峰厛棰勮鍒嗘鍐呭')
+    return
+  }
+
+  // 璁剧疆鎸夐挳鍔犺浇鐘舵��
+  submitLoading.value = true
+  try {
+    if (modelData.value.id) {
+      // 淇敼鍦烘櫙
+      await KnowledgeDocumentApi.updateKnowledgeDocument({
+        id: modelData.value.id,
+        segmentMaxTokens: modelData.value.segmentMaxTokens
+      })
+    } else {
+      // 鏂板鍦烘櫙
+      const data = await KnowledgeDocumentApi.createKnowledgeDocumentList({
+        knowledgeId: modelData.value.knowledgeId,
+        segmentMaxTokens: modelData.value.segmentMaxTokens,
+        list: modelData.value.list.map((item: any) => ({
+          name: item.name,
+          url: item.url
+        }))
+      })
+      modelData.value.list.forEach((document: any, index: number) => {
+        document.id = data[index]
+      })
+    }
+
+    // 杩涘叆涓嬩竴姝�
+    const parentEl = parent || getCurrentInstance()?.parent
+    if (parentEl && typeof parentEl.exposed?.goToNextStep === 'function') {
+      parentEl.exposed.goToNextStep()
+    }
+  } catch (error: any) {
+    console.error('淇濆瓨澶辫触:', modelData.value, error)
+  } finally {
+    // 鍏抽棴鎸夐挳鍔犺浇鐘舵��
+    submitLoading.value = false
+  }
+}
+
+/** 鍒濆鍖� */
+onMounted(async () => {
+  // 纭繚 segmentMaxTokens 瀛樺湪
+  if (!modelData.value.segmentMaxTokens) {
+    modelData.value.segmentMaxTokens = 500
+  }
+  // 濡傛灉娌℃湁閫変腑鏂囦欢锛岄粯璁ら�変腑绗竴涓�
+  if (!currentFile.value && modelData.value.list && modelData.value.list.length > 0) {
+    currentFile.value = modelData.value.list[0]
+  }
+
+  // 濡傛灉鏈夐�変腑鐨勬枃浠讹紝鑾峰彇鍒嗘鍐呭
+  if (currentFile.value) {
+    await splitContent(currentFile.value)
+  }
+})
+</script>

--
Gitblit v1.8.0