<template>
  <div style="width: 100%; height: auto;">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div v-show="showSearch" class="mb-[10px]">
        <div class="p-4 bg-white rounded">
          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
            <el-form-item label="知识库名称" prop="knowledgeName">
              <el-input v-model="queryParams.knowledgeName" placeholder="请输入知识库名称" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="描述" prop="description">
              <el-input v-model="queryParams.description" placeholder="请输入描述" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </transition>

    <div class="bg-white p-4 rounded">
      <div class="flex justify-between items-center mb-4">
        <h2 class="text-xl font-bold">知识库列表</h2>
        <div class="flex space-x-2">
          <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:knowledgeInfo:add']">新增</el-button>
          <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:knowledgeInfo:remove']">删除</el-button>
          <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:knowledgeInfo:export']">导出</el-button>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </div>
      </div>

      <el-table
          v-loading="loading"
          :data="knowledgeInfoList"
          @selection-change="handleSelectionChange"
          class="compact-table"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="知识库编号" align="center" prop="knowledgeCode" />
        <el-table-column label="知识库名称" align="center" prop="knowledgeName" />
        <el-table-column label="描述" align="center" prop="description" width="600" ellipsis />
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <div class="flex space-x-2 items-center">
              <el-tooltip content="上传文件" placement="top">
                <el-upload
                    :action="uploadUrl"
                    :headers="headers"
                    :show-file-list="false"
                    accept=".txt,.pdf,.docx,.pptx,.xlsx,.xls,.csv,.json"
                    :data="{ knowledgeCode: scope.row.knowledgeCode }"
                    :before-upload="beforeUpload"
                    :on-success="handleUploadSuccess"
                    :on-error="handleUploadError"
                >
                  <el-button link type="primary" icon="Upload"></el-button>
                </el-upload>
              </el-tooltip>
              <el-tooltip content="查看附件" placement="top">
                <el-button link type="primary" icon="Folder" @click="handleAttachment(scope.row)"></el-button>
              </el-tooltip>
              <el-tooltip content="删除" placement="top">
                <el-button
                    link
                    type="danger"
                    icon="Delete"
                    @click="handleDelete(scope.row)"
                    v-hasPermi="['system:knowledgeInfo:remove']"
                ></el-button>
              </el-tooltip>
            </div>
          </template>
        </el-table-column>
      </el-table>

      <div class="flex justify-center mt-4">
        <el-pagination
            v-show="total > 0"
            :total="total"
            v-model:current-page="queryParams.pageNum"
            v-model:page-size="queryParams.pageSize"
            @current-change="getList"
            layout="prev, pager, next"
        />
      </div>

    </div>

    <!-- 添加或修改知识库对话框 -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="knowledgeInfoFormRef" :model="form" :rules="rules" label-width="100px">
        <el-form-item label="知识库名称" prop="knowledgeName">
          <el-input v-model="form.knowledgeName" placeholder="请输入知识库名称" />
        </el-form-item>
        <el-form-item label="描述" prop="description">
          <el-input v-model="form.description" placeholder="请输入描述" />
        </el-form-item>
        <el-form-item label="是否公开" prop="share">
          <el-radio-group v-model="form.share">
            <el-radio :label="1">是</el-radio>
            <el-radio :label="0">否</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="知识分隔符" prop="knowledgeSeparator">
          <el-input v-model="form.knowledgeSeparator" placeholder="请输入知识分隔符" />
        </el-form-item>
        <el-form-item label="提问分隔符" prop="questionSeparator">
          <el-input v-model="form.questionSeparator" placeholder="请输入提问分隔符" />
        </el-form-item>
        <el-form-item label="重叠字符数" prop="overlapChar">
          <el-input-number v-model="form.overlapChar" placeholder="请输入重叠字符数" style="width: 100%" />
        </el-form-item>
        <el-form-item label="检索条数" prop="retrieveLimit">
          <el-input-number v-model="form.retrieveLimit" placeholder="请输入知识库中检索的条数" style="width: 100%" />
        </el-form-item>
        <el-form-item label="文本块大小" prop="textBlockSize">
          <el-input-number v-model="form.textBlockSize" placeholder="请输入文本块大小" style="width: 100%" />
        </el-form-item>
        <el-form-item label="向量库" prop="vectorModelName">
          <el-select v-model="form.vectorModelName" placeholder="请选择向量库" style="width: 100%">
            <el-option label="weaviate" value="weaviate" />
            <el-option label="milvus" value="milvus" />
          </el-select>
        </el-form-item>
        <el-form-item label="向量模型" prop="embeddingModelName">
          <el-select v-model="form.embeddingModelName" placeholder="请选择向量模型" style="width: 100%">
            <el-option label="text-embedding-3-small" value="text-embedding-3-small" />
            <el-option label="quentinz/bge-large-zh-v1.5" value="quentinz/bge-large-zh-v1.5" />
            <el-option label="baai/bge-m3" value="baai/bge-m3" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 附件管理对话框 -->
    <el-dialog
        title="知识库附件"
        v-model="fileVisible"
        width="80%"
        append-to-body
    >
      <div class="flex justify-between items-center mb-4">
        <div class="text-lg font-semibold">知识库: {{ currentKnowledgeName }}</div>
        <div>
          <el-upload
              :action="uploadUrl"
              :headers="headers"
              :show-file-list="false"
              accept=".txt,.pdf,.docx,.pptx,.xlsx,.xls,.csv,.json"
              multiple
              :data="{ knowledgeCode: currentKnowledgeCode }"
              :on-success="handleUploadSuccess"
              :before-upload="beforeUpload"
              :on-error="handleUploadError"
          >
            <el-button type="primary" icon="Upload">文件上传</el-button>
          </el-upload>
        </div>
      </div>

      <el-table :data="fileData" v-loading="fileLoading" class="attachment-table">
        <el-table-column prop="docName" label="文档名称" width="250" />
        <el-table-column prop="docType" label="文档类型" width="120" />
        <el-table-column label="状态" width="150">
          <template #default="scope">
            <el-tag :type="getStatusTagType(scope.row.vectorStatus)">
              {{ getStatusText(scope.row.vectorStatus) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="大小" width="120">
          <template #default="scope">
            {{ formatFileSize(scope.row.fileSize) }}
          </template>
        </el-table-column>
        <el-table-column label="上传时间" width="180">
          <template #default="scope">
            {{ formatDateTime(scope.row.createTime) }}
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200">
          <template #default="scope">
            <el-button
                type="danger"
                size="small"
                icon="Delete"
                @click="handleDeleteFile(scope.row)"
            >删除</el-button>
            <el-button
                type="primary"
                size="small"
                icon="Document"
                @click="handleFragment(scope.row)"
            >片段</el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="mt-4 text-sm text-gray-500">
        <div class="flex items-center mb-2">
          <div class="w-3 h-3 bg-blue-500 rounded-full mr-2"></div>
          <span>支持的文件类型: .txt, .pdf, .docx, .pptx, .xlsx, .xls, .csv, .json</span>
        </div>
        <div class="flex items-center">
          <div class="w-3 h-3 bg-blue-500 rounded-full mr-2"></div>
          <span>最大文件大小: 10MB</span>
        </div>
      </div>
    </el-dialog>

    <!-- 知识片段对话框 -->
    <el-dialog
        title="知识片段"
        v-model="fragmentVisible"
        width="80%"
        append-to-body
    >
      <div class="mb-4">
        <div class="text-lg font-semibold">{{ currentDocumentName }}</div>
        <div class="text-sm text-gray-500">共 {{ fragmentData.length }} 个片段</div>
      </div>

      <el-table :data="fragmentData" class="fragment-table">
        <el-table-column label="序号" width="80">
          <template #default="scope">
            <div class="text-center">{{ scope.$index + 1 }}</div>
          </template>
        </el-table-column>
        <el-table-column prop="content" label="片段内容">
          <template #default="scope">
            <div class="fragment-content">
              {{ scope.row.content }}
            </div>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="120">
          <template #default="scope">
            <el-button
                type="danger"
                size="small"
                icon="Delete"
                @click="handleDeleteFragment(scope.row)"
            >删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
  </div>
</template>

<script setup name="KnowledgeInfo" lang="ts">
import { listKnowledgeInfo, getKnowledgeInfo, delKnowledgeInfo, addKnowledgeInfo, updateKnowledgeInfo,listKnowledgeAttach, delKnowledgeAttach, listKnowledgeFragment, delKnowledgeFragment } from '@/api/system/knowledgeInfo';
import { KnowledgeInfoVO, KnowledgeInfoQuery, KnowledgeInfoForm, KnowledgeFragmentVO, KnowledgeAttachVO } from '@/api/system/knowledgeInfo/types';
import { getCurrentInstance, ComponentInternalInstance } from 'vue';
import { useUserStore } from '@/store/modules/user';

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStore();

const knowledgeInfoList = ref<KnowledgeInfoVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);

// 附件相关状态
const fileVisible = ref(false);
const fragmentVisible = ref(false);
const fileLoading = ref(false);
const fileData = ref<KnowledgeAttachVO[]>([]);
const fragmentData = ref<KnowledgeFragmentVO[]>([]);
const currentKnowledgeCode = ref('');
const currentKnowledgeName = ref('');
const currentDocumentName = ref('');
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + '/system/knowledgeAttach/upload');
const headers = ref({
  Authorization: 'Bearer ' + userStore.token,
  clientId: import.meta.env.VITE_APP_CLIENT_ID
});

const queryFormRef = ref<ElFormInstance>();
const knowledgeInfoFormRef = ref<ElFormInstance>();

const dialog = reactive<DialogOption>({
  visible: false,
  title: ''
});

const initFormData: KnowledgeInfoForm = {
  id: undefined,
  knowledgeCode: undefined,
  knowledgeName: undefined,
  description: undefined,
  userId: undefined,
  share: undefined,
  knowledgeSeparator: undefined,
  questionSeparator: undefined,
  overlapChar: undefined,
  retrieveLimit: undefined,
  textBlockSize: undefined,
  vectorModelName: undefined,
  embeddingModelName: undefined,
  systemPrompt: undefined,
  remark: undefined
}
const data = reactive<PageData<KnowledgeInfoForm, KnowledgeInfoQuery>>({
  form: {...initFormData},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    knowledgeCode: undefined,
    knowledgeName: undefined,
    description: undefined,
    userId: undefined,
    share: undefined,
    knowledgeSeparator: undefined,
    questionSeparator: undefined,
    overlapChar: undefined,
    retrieveLimit: undefined,
    textBlockSize: undefined,
    vectorModelName: undefined,
    embeddingModelName: undefined,
    systemPrompt: undefined,
    params: {
    }
  },
  rules: {
    knowledgeName: [{ required: true, message: "知识库名称不能为空", trigger: "blur" }],
    retrieveLimit: [{ required: true, message: "检索条数不能为空", trigger: "blur" }],
    textBlockSize: [{ required: true, message: "文本块大小不能为空", trigger: "blur" }],
    vectorModelName: [{ required: true, message: "向量库不能为空", trigger: "change" }],
    embeddingModelName: [{ required: true, message: "向量模型不能为空", trigger: "change" }],
    share: [{ required: true, message: "是否公开不能为空", trigger: "change" }]
  }
});

const { queryParams, form, rules } = toRefs(data);

/** 查询知识库列表 */
const getList = async () => {
  loading.value = true;
  try {
    const res = await listKnowledgeInfo(queryParams.value);
    knowledgeInfoList.value = res.rows;
    total.value = res.total;
  } catch (error) {
    console.error('获取知识库列表失败:', error);
    proxy?.$modal.msgError("获取知识库列表失败");
  } finally {
    loading.value = false;
  }
}

/** 取消按钮 */
const cancel = () => {
  reset();
  dialog.visible = false;
}

/** 表单重置 */
const reset = () => {
  form.value = {...initFormData};
  knowledgeInfoFormRef.value?.resetFields();
}

/** 搜索按钮操作 */
const handleQuery = () => {
  queryParams.value.pageNum = 1;
  getList();
}

/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  handleQuery();
}

/** 多选框选中数据 */
const handleSelectionChange = (selection: KnowledgeInfoVO[]) => {
  ids.value = selection.map(item => item.id);
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}

/** 新增按钮操作 */
const handleAdd = () => {
  reset();
  form.value = {
    ...initFormData,
    share: 0,        // 默认选"否"
    overlapChar: 30,  // 默认重叠字符数为30
    knowledgeCode: generateRandomString(), //随机编号
    textBlockSize: 300,
    retrieveLimit: 5,
    vectorModelName: "weaviate",
    embeddingModelName: "quentinz/bge-large-zh-v1.5",
  };
  dialog.visible = true;
  dialog.title = "添加知识库";
}

/** 修改按钮操作 */
const handleUpdate = async (row?: KnowledgeInfoVO) => {
  reset();
  const _id = row?.id || ids.value[0]
  try {
    const res = await getKnowledgeInfo(_id);
    Object.assign(form.value, res.data);
    dialog.visible = true;
    dialog.title = "修改知识库";
  } catch (error) {
    console.error('获取知识库详情失败:', error);
    proxy?.$modal.msgError("获取知识库详情失败");
  }
}

/** 提交按钮 */
const submitForm = () => {
  knowledgeInfoFormRef.value?.validate(async (valid: boolean) => {
    if (valid) {
      buttonLoading.value = true;
      try {
        if (form.value.id) {
          await updateKnowledgeInfo(form.value);
        } else {
          await addKnowledgeInfo(form.value);
        }
        proxy?.$modal.msgSuccess("操作成功");
        dialog.visible = false;
        await getList();
      } catch (error) {
        console.error('操作失败:', error);
        proxy?.$modal.msgError("操作失败");
      } finally {
        buttonLoading.value = false;
      }
    }
  });
}

const handleDelete = async (row?: KnowledgeInfoVO) => {
  // 获取要删除的ID数组 - 使用主键id而不是knowledgeCode
  const deleteIds = row ? [row.id] : ids.value;

  // 确认删除提示
  const message = row
      ? `是否确认删除知识库名称为"${row.knowledgeName}"的数据项？`
      : `是否确认删除选中的${deleteIds.length}项数据？`;

  try {
    await proxy?.$modal.confirm(message);

    // 调用删除API，传递ID数组
    await delKnowledgeInfo(deleteIds);

    proxy?.$modal.msgSuccess("删除成功");
    await getList();
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除失败:', error);
      proxy?.$modal.msgError("删除失败");
    }
  }
}

/** 导出按钮操作 */
const handleExport = () => {
  proxy?.download('system/knowledgeInfo/export', {
    ...queryParams.value
  }, `knowledgeInfo_${new Date().getTime()}.xlsx`)
}

/** 查看附件 */
const handleAttachment = async (row: KnowledgeInfoVO) => {
  currentKnowledgeCode.value = row.knowledgeCode;
  currentKnowledgeName.value = row.knowledgeName;
  fileLoading.value = true;
  try {
    const res = await listKnowledgeAttach({ knowledgeCode: row.knowledgeCode });
    fileData.value = res.rows;
    fileVisible.value = true;
  } catch (error) {
    console.error('获取附件列表失败:', error);
    proxy?.$modal.msgError("获取附件列表失败");
  } finally {
    fileLoading.value = false;
  }
}

/** 删除附件 */
const handleDeleteFile = async (row: KnowledgeAttachVO) => {
  try {
    await proxy?.$modal.confirm('是否确认删除文档"' + row.docName + '"?');
    // 使用主键id而不是docCode
    await delKnowledgeAttach(row.id);
    proxy?.$modal.msgSuccess("删除成功");
    // 刷新附件列表
    await handleAttachment({ knowledgeCode: currentKnowledgeCode.value } as KnowledgeInfoVO);
  } catch (error) {
    console.error('删除失败:', error);
    proxy?.$modal.msgError("删除失败");
  }
}
/** 查看知识片段 */
const handleFragment = async (row: KnowledgeAttachVO) => {
  currentDocumentName.value = row.docName;
  try {
    const res = await listKnowledgeFragment({ docCode: row.docCode });
    fragmentData.value = res.rows;
    fragmentVisible.value = true;
  } catch (error) {
    console.error('获取知识片段失败:', error);
    proxy?.$modal.msgError("获取知识片段失败");
  }
}

/** 删除知识片段 */
const handleDeleteFragment = async (row: KnowledgeFragmentVO) => {
  try {
    await proxy?.$modal.confirm('是否确认删除该知识片段?');
    // 使用主键id而不是fragmentCode
    await delKnowledgeFragment(row.id);
    proxy?.$modal.msgSuccess("删除成功");
    // 刷新片段列表
    await handleFragment({ docCode: row.docCode } as KnowledgeAttachVO);
  } catch (error) {
    console.error('删除失败:', error);
    proxy?.$modal.msgError("删除失败");
  }
}

/** 文件上传成功处理 */
const handleUploadSuccess = (response: any) => {
  if (response.code === 200) {
    proxy?.$modal.msgSuccess("上传成功");
    // 刷新附件列表
    if (fileVisible.value) {
      handleAttachment({ knowledgeCode: currentKnowledgeCode.value } as KnowledgeInfoVO);
    }
  } else {
    proxy?.$modal.msgError(response.msg || "上传失败");
  }
}

/** 文件上传失败处理 */
const handleUploadError = (error: any) => {
  let errMsg = '上传失败';
  if (error.response) {
    const res = error.response;
    errMsg = res.data.msg || `请求错误：${res.status} ${res.statusText}`;
  } else if (error.message) {
    errMsg = error.message;
  }
  proxy?.$modal.msgError(errMsg);
}

/** 文件上传前校验 */
const beforeUpload = (file: File) => {
  const allowedExtensions = ['.txt', '.pdf', '.docx', '.pptx', '.xlsx', '.xls', '.csv', '.json'];
  const fileExtension = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();

  if (!allowedExtensions.includes(fileExtension)) {
    proxy?.$modal.msgError('上传文件格式不支持! 仅支持以下格式：' + allowedExtensions.join(', '));
    return false;
  }

  const isLt10M = file.size / 1024 / 1024 < 10;
  if (!isLt10M) {
    proxy?.$modal.msgError('上传文件大小不能超过 10MB!');
    return false;
  }

  return true;
}

/** 获取状态标签类型 */
const getStatusTagType = (status: number) => {
  switch (status) {
    case 10: return 'info';   // 未开始
    case 20: return 'warning'; // 进行中
    case 30: return 'success'; // 已完成
    default: return 'info';
  }
}

/** 获取状态文本 */
const getStatusText = (status: number) => {
  switch (status) {
    case 10: return '未开始';
    case 20: return '处理中';
    case 30: return '已完成';
    default: return '未知状态';
  }
}

/** 格式化文件大小 */
const formatFileSize = (bytes: number) => {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/** 格式化日期时间 */
const formatDateTime = (dateString: string) => {
  if (!dateString) return '';
  const date = new Date(dateString);
  return date.toLocaleString();
}

//随机生成16位字符串
function generateRandomString() {
  // 可选字符集合
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';

  // 生成16位随机字符
  for (let i = 0; i < 10; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }

  return result;
}

onMounted(() => {
  getList();
});


</script>

<style>
/* 全局生效 */
#app, body, html {
  width: 100%;
  height: auto !important;
}

/* 紧凑表格行间距 */
.el-table.compact-table .el-table__body tr td {
  padding-top: 12px !important;
  padding-bottom: 12px !important;
}

/* 紧凑操作按钮间距 */
.el-button--text {
  margin-top: -2px !important;
  margin-bottom: -2px !important;
}

/* 紧凑分页控件上下间距 */
.flex.justify-center.mt-4 {
  margin-top: 10px !important;
}

/* 紧凑表格行高 */
.el-table__row {
  line-height: 1.2 !important;
}

/* 按钮悬停效果 */
.el-button--primary:hover {
  background-color: transparent !important;
  color: #006BE6 !important;
  border-color: #006BE6 !important;
}

.el-button--danger:hover {
  background-color: transparent !important;
  color: #e74c3c !important;
  border-color: #c0392b !important;
}

.el-button--success:hover {
  background-color: transparent !important;
  color: #9b59b6 !important;
  border-color: #8e44ad !important;
}

/* 标题栏样式 */
.text-xl.font-bold {
  font-size: 18px;
  font-weight: 600;
  color: #333;
}

/* 表单卡片样式 */
.bg-white.rounded {
  border-radius: 4px;
  box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
}

/* 附件表格样式 */
.attachment-table .el-table__row {
  height: 60px;
}

/* 片段表格样式 */
.fragment-table .el-table__row {
  height: auto;
}

.fragment-content {
  padding: 10px;
  background-color: #f9f9f9;
  border-radius: 4px;
  white-space: pre-wrap;
  line-height: 1.5;
  font-size: 14px;
  color: #333;
}

/* 状态标签样式 */
.el-tag {
  padding: 0 8px;
  height: 24px;
  line-height: 24px;
  font-size: 12px;
}

/* 上传按钮样式 */
.upload-button {
  margin-left: 10px;
}
</style>