123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482 |
- <template>
- <div class="app-container">
- <!-- 顶部导航 -->
- <div class="app-header">
- <div class="header-content">
- <div class="header-main">
- <!-- 返回按钮 -->
- <div class="header-back">
- <el-button
- class="back-btn"
- @click="goBack"
- text
- >
- <span class="back-icon">←</span>
- <span style="color: white">返回知识库</span>
- </el-button>
- </div>
- <div class="header-titles">
- <h1 class="app-title">知识库内容管理</h1>
- <p class="app-subtitle">管理知识库中的文档和内容</p>
- </div>
- </div>
- <div class="header-stats">
- <div class="stat-item">
- <span class="stat-number">{{ totalItems }}</span>
- <span class="stat-label">总文档</span>
- </div>
- <div class="stat-item">
- <span class="stat-number">{{ currentPageItems.length }}</span>
- <span class="stat-label">本页</span>
- </div>
- </div>
- </div>
- </div>
- <div class="main-layout">
- <!-- 左侧文档列表 -->
- <div class="sidebar">
- <div class="sidebar-header">
- <div class="sidebar-title">
- <h3>📚 文档列表</h3>
- <p class="sidebar-subtitle">{{ datasetName }} - 共 {{ totalItems }} 篇文档</p>
- </div>
- <el-button
- class="add-btn"
- type="primary"
- @click="openDialog"
- >
- <span class="button-icon">➕</span>
- 添加文档
- </el-button>
- </div>
- <div class="knowledge-list">
- <div
- v-for="item in currentPageItems"
- :key="item.doc_id"
- :class="['document-card', { 'active': activeItem === String(item.doc_id) }]"
- @click="handleSelect(String(item.doc_id))"
- >
- <div class="card-content">
- <div class="document-icon">
- <span v-if="item.statusDesc === '可用'" class="status-available">✅</span>
- <span v-else class="status-unavailable">❌</span>
- </div>
- <div class="document-info">
- <span class="document-name">{{ item.title || item.text }}</span>
- </div>
- <div class="document-actions">
- <el-tooltip content="删除文档" placement="top">
- <el-button
- text
- class="delete-btn"
- @click.stop="confirmDelete(item.doc_id, item.title)"
- >
- 🗑️
- </el-button>
- </el-tooltip>
- </div>
- </div>
- </div>
- </div>
- <!-- 分页 -->
- <div class="sidebar-footer">
- <div class="pagination-info">
- 共 {{ totalItems }} 篇文档
- </div>
- <el-pagination
- v-model:current-page="pageIndex"
- :page-size="pageSize"
- :total="totalItems"
- :pager-count="5"
- layout="prev, pager, next"
- @current-change="handlePageChange"
- class="custom-pagination"
- />
- </div>
- </div>
- <!-- 右侧内容区域 -->
- <div class="content-area">
- <div class="content-section">
- <div class="content-header">
- <div class="content-title">
- <h2>{{ selectedTitle || '选择文档查看内容' }}</h2>
- <span v-if="statusDesc" class="content-status"
- :class="statusDesc === '可用' ? 'available' : 'unavailable'">
- {{ statusDesc }}
- </span>
- </div>
- <el-button
- v-if="selectedContent"
- type="primary"
- class="chunk-btn"
- @click="openChunkDialog"
- >
- <span class="button-icon">📖</span>
- 查看分段
- </el-button>
- </div>
- <div class="content-body">
- <div v-if="selectedContent" class="content-text">
- <pre>{{ selectedContent }}</pre>
- </div>
- <div v-else class="empty-content">
- <div class="empty-icon">📄</div>
- <h3>选择左侧文档查看内容</h3>
- <p>点击左侧文档列表中的项目查看详细内容</p>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 添加文档弹窗 -->
- <el-dialog
- title="添加新文档"
- v-model="dialogVisible"
- width="600px"
- class="content-dialog"
- @close="resetForm"
- >
- <div class="dialog-content">
- <el-form :model="formData" ref="formRef" label-width="100px">
- <el-form-item label="📝 文档标题" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
- <el-input
- v-model="formData.title"
- placeholder="请输入文档标题"
- size="large"
- ></el-input>
- </el-form-item>
- <el-form-item label="📄 文档内容" :rules="[{ required: true, message: '请输入文本内容', trigger: 'blur' }]">
- <el-input
- type="textarea"
- v-model="formData.text"
- placeholder="请输入文档内容"
- :rows="8"
- resize="none"
- ></el-input>
- </el-form-item>
- <el-form-item label="🔗 是否分块">
- <el-switch
- v-model="formData.isChunk"
- active-text="启用分块"
- inactive-text="禁用分块"
- ></el-switch>
- </el-form-item>
- </el-form>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button
- class="action-btn secondary"
- @click="dialogVisible = false"
- >
- 取消
- </el-button>
- <el-button
- type="primary"
- class="action-btn primary"
- @click="submitData"
- >
- 💾 保存文档
- </el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 分段展示弹窗 -->
- <el-dialog
- title="📑 文档分段"
- v-model="chunkDialogVisible"
- width="90%"
- class="content-dialog chunk-dialog"
- :destroy-on-close="true"
- >
- <div class="chunk-container">
- <div class="chunk-header">
- <div class="chunk-stats">
- <span class="stat-item">共 {{ chunkTotal }} 个分段</span>
- <span class="stat-item">当前显示 {{ chunkList.length }} 个</span>
- </div>
- </div>
- <div class="chunk-content">
- <el-table
- v-if="chunkDialogVisible && chunkList.length > 0"
- :data="chunkList"
- style="width:100%"
- class="chunk-table"
- :scrollbar-always-on="true"
- >
- <el-table-column
- prop="chunk_id"
- label="分段ID"
- width="100"
- header-align="center"
- align="center"
- fixed="left"
- >
- <template #default="scope">
- <span class="chunk-id">#{{ scope.row.chunk_id }}</span>
- </template>
- </el-table-column>
- <el-table-column
- prop="summary"
- label="内容摘要"
- width="300"
- header-align="center"
- min-width="300"
- >
- <template #default="scope">
- <div class="summary-content" :title="scope.row.summary">
- {{ scope.row.summary || '无摘要' }}
- </div>
- </template>
- </el-table-column>
- <el-table-column
- prop="text"
- label="完整内容"
- header-align="center"
- min-width="500"
- >
- <template #default="scope">
- <div class="full-content" :title="scope.row.text">
- {{ scope.row.text }}
- </div>
- </template>
- </el-table-column>
- <el-table-column
- prop="statusDesc"
- label="状态"
- width="120"
- header-align="center"
- align="center"
- fixed="right"
- >
- <template #default="scope">
- <el-tag
- :type="scope.row.statusDesc === '可用' ? 'success' : 'danger'"
- class="status-tag"
- >
- {{ scope.row.statusDesc }}
- </el-tag>
- </template>
- </el-table-column>
- </el-table>
- <div v-else class="empty-chunks">
- <div class="empty-icon">📝</div>
- <h3>暂无分段内容</h3>
- <p>该文档没有分块或分块内容为空</p>
- </div>
- </div>
- <!-- 分页器 -->
- <div v-if="chunkTotal > 0" class="pagination-section">
- <el-pagination
- v-model:current-page="chunkPage"
- :page-size="chunkPageSize"
- :total="chunkTotal"
- :page-sizes="[10, 20, 50, 100]"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="handleSizeChange"
- @current-change="fetchChunks"
- />
- </div>
- </div>
- </el-dialog>
- </div>
- </template>
- <script lang="ts">
- import {API_BASE_URL} from "@/config";
- import {defineComponent, onMounted, ref, computed} from 'vue';
- import {useRouter} from 'vue-router';
- import axios from 'axios';
- import {ElMessage, ElMessageBox} from 'element-plus';
- interface Item {
- doc_id: string;
- title: string | null;
- text: string;
- statusDesc: string;
- }
- export default defineComponent({
- name: 'KnowledgeContent',
- setup() {
- const router = useRouter();
- const datasetId = ref<number | null>(null);
- const datasetName = ref<string | null>('');
- const activeItem = ref('');
- const selectedTitle = ref('');
- const selectedContent = ref('');
- const statusDesc = ref('');
- // 页码控制
- const pageIndex = ref(1);
- const pageSize = ref(10);
- const totalItems = ref(0);
- const allItems = ref<Item[]>([]);
- // 新知识表单数据
- const formData = ref({
- title: '',
- text: '',
- isChunk: true
- });
- const dialogVisible = ref(false);
- const formRef = ref();
- // 分段弹窗
- const chunkDialogVisible = ref(false);
- const chunkList = ref<any[]>([]);
- const chunkPage = ref(1);
- const chunkPageSize = ref(10);
- const chunkTotal = ref(0);
- // 返回按钮功能
- const goBack = () => {
- router.push('/');
- };
- // 获取API数据并填充项
- const fetchData = async (datasetId: number) => {
- console.log(datasetId);
- try {
- const response = await axios.get(`${API_BASE_URL}/content/list`, {
- params: {
- page: pageIndex.value,
- pageSize: pageSize.value,
- datasetId: datasetId,
- }
- });
- const data = response.data.data;
- allItems.value = data.entities;
- totalItems.value = data.total_count;
- console.log(data);
- } catch (error) {
- console.error('Error fetching data:', error);
- ElMessage.error('获取文档列表失败');
- }
- };
- // 当前页面的项目
- const currentPageItems = computed(() => {
- return allItems.value;
- });
- // 处理菜单项选择
- const handleSelect = (doc_id: string) => {
- activeItem.value = doc_id;
- const selected = allItems.value.find(item => item.doc_id === doc_id);
- if (selected) {
- selectedTitle.value = selected.title || '';
- selectedContent.value = selected.text;
- statusDesc.value = selected.statusDesc;
- }
- };
- // 处理页码变更
- const handlePageChange = (newPage: number) => {
- pageIndex.value = newPage;
- if (datasetId.value !== null) {
- fetchData(datasetId.value);
- } else {
- console.error('datasetId is null');
- }
- };
- // 初始化数据
- onMounted(() => {
- const query = new URLSearchParams(window.location.search);
- datasetId.value = query.get('datasetId') ? parseInt(query.get('datasetId')!) : null;
- datasetName.value = query.get('datasetName');
- if (datasetId.value !== null) {
- fetchData(datasetId.value);
- } else {
- console.error('datasetId is null');
- }
- console.log(`知识库 ID: ${datasetId.value}`);
- });
- // 打开弹窗
- const openDialog = () => {
- dialogVisible.value = true;
- };
- // 重置表单
- const resetForm = () => {
- formData.value.title = '';
- formData.value.text = '';
- };
- // 提交表单数据
- const submitData = async () => {
- if (!formData.value.title || !formData.value.text) {
- ElMessage.error('标题和文本不能为空');
- return;
- }
- try {
- const response = await axios.post(`${API_BASE_URL}/chunk`, {
- dataset_id: datasetId.value,
- title: formData.value.title,
- text: formData.value.text,
- dont_chunk: !formData.value.isChunk,
- });
- console.log('提交成功:', response.data);
- dialogVisible.value = false;
- if (datasetId.value !== null) {
- fetchData(datasetId.value);
- } else {
- console.error('datasetId is null');
- }
- ElMessage.success('文档添加成功!');
- resetForm();
- } catch (error) {
- console.error('提交失败:', error);
- ElMessage.error('提交失败,请稍后再试!');
- }
- };
- // 确认删除
- const confirmDelete = (doc_id: string, title: string | null) => {
- ElMessageBox.confirm(
- `确定要删除文档 "${title || doc_id}" 吗?`,
- '删除确认',
- {
- confirmButtonText: '删除',
- cancelButtonText: '取消',
- type: 'warning',
- confirmButtonClass: 'delete-confirm-btn',
- cancelButtonClass: 'delete-cancel-btn'
- }
- ).then(() => {
- deleteDoc(doc_id);
- }).catch(() => {
- // 用户取消,不处理
- });
- };
- // 删除文档方法
- const deleteDoc = async (doc_id: string) => {
- try {
- await axios.post('http://192.168.100.31:8001/api/delete', {
- level: 'doc',
- params: {doc_id}
- });
- ElMessage.success('删除成功');
- if (datasetId.value !== null) {
- fetchData(datasetId.value);
- }
- } catch (error) {
- console.error(error);
- ElMessage.error('删除失败');
- }
- };
- // 打开分段弹窗
- const openChunkDialog = async () => {
- if (!activeItem.value) {
- ElMessage.warning("请先选择一个文档");
- return;
- }
- chunkDialogVisible.value = true;
- await fetchChunks(chunkPage.value);
- };
- // 获取分段数据
- const fetchChunks = async (page: number) => {
- if (!activeItem.value) return;
- try {
- const response = await axios.get(`${API_BASE_URL}/chunk/list`, {
- params: {
- page,
- pageSize: chunkPageSize.value,
- docId: activeItem.value,
- }
- });
- const data = response.data.data;
- chunkList.value = data.entities;
- chunkTotal.value = data.total_count;
- chunkPage.value = data.page;
- } catch (err) {
- console.error(err);
- ElMessage.error("获取分段失败");
- }
- };
- // 分页大小变化处理
- const handleSizeChange = (newSize: number) => {
- chunkPageSize.value = newSize;
- chunkPage.value = 1;
- fetchChunks(1);
- };
- return {
- activeItem,
- selectedTitle,
- selectedContent,
- pageIndex,
- pageSize,
- totalItems,
- currentPageItems,
- handleSelect,
- handlePageChange,
- datasetName,
- formData,
- dialogVisible,
- openDialog,
- submitData,
- resetForm,
- confirmDelete,
- deleteDoc,
- chunkDialogVisible,
- chunkList,
- chunkPage,
- chunkPageSize,
- chunkTotal,
- openChunkDialog,
- fetchChunks,
- statusDesc,
- formRef,
- goBack,
- handleSizeChange
- };
- },
- });
- </script>
- <style scoped>
- /* 基础样式 */
- .app-container {
- min-height: 100vh;
- background: linear-gradient(135deg, rgba(102, 126, 234, 0.81) 0%, rgba(118, 75, 162, 0.77) 100%);
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- }
- /* 顶部导航样式 */
- .app-header {
- background: rgba(255, 255, 255, 0.1);
- backdrop-filter: blur(20px);
- padding: 16px 0;
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
- }
- .header-content {
- max-width: 1400px;
- margin: 0 auto;
- padding: 0 24px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .header-main {
- flex: 1;
- display: flex;
- align-items: flex-start;
- gap: 20px;
- }
- .header-back {
- flex-shrink: 0;
- }
- .back-btn {
- color: white;
- font-weight: 500;
- padding: 8px 16px;
- border-radius: 12px;
- transition: all 0.3s ease;
- background: rgba(255, 255, 255, 0.1);
- border: 1px solid rgba(255, 255, 255, 0.2);
- }
- .back-btn:hover {
- background: rgb(255, 255, 255);
- transform: translateX(-2px);
- }
- .back-icon {
- color: white;
- margin-right: 6px;
- font-weight: bold;
- }
- .header-titles {
- flex: 1;
- }
- .app-title {
- color: white;
- font-size: 2.25rem;
- font-weight: 800;
- margin: 0;
- text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
- background: linear-gradient(135deg, #fff 0%, #e2e8f0 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- }
- .app-subtitle {
- color: rgba(255, 255, 255, 0.9);
- font-size: 1rem;
- margin: 8px 0 0 0;
- font-weight: 500;
- }
- .header-stats {
- display: flex;
- gap: 24px;
- }
- .stat-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .stat-number {
- color: white;
- font-size: 1.5rem;
- font-weight: 700;
- }
- .stat-label {
- color: rgba(255, 255, 255, 0.7);
- font-size: 0.8rem;
- margin-top: 4px;
- }
- /* 主布局 */
- .main-layout {
- display: flex;
- max-width: 1400px;
- margin: 0 auto;
- padding: 24px;
- gap: 24px;
- min-height: calc(100vh - 120px);
- align-items: flex-start;
- }
- /* 侧边栏样式 */
- .sidebar {
- width: 400px;
- flex-shrink: 0;
- display: flex;
- flex-direction: column;
- position: sticky;
- top: 24px;
- max-height: calc(100vh - 120px);
- overflow-y: auto;
- }
- .sidebar-header {
- background: white;
- padding: 20px;
- border-radius: 20px;
- margin-bottom: 16px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- flex-shrink: 0;
- }
- .sidebar-title h3 {
- margin: 0 0 6px 0;
- color: #2d3748;
- font-size: 1.25rem;
- font-weight: 700;
- }
- .sidebar-subtitle {
- margin: 0;
- color: #718096;
- font-size: 0.85rem;
- }
- .add-btn {
- border-radius: 12px;
- padding: 8px 16px;
- font-weight: 500;
- }
- .button-icon {
- margin-right: 6px;
- }
- .knowledge-list {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: 12px;
- overflow-y: auto;
- min-height: 0;
- }
- .document-card {
- background: white;
- border-radius: 16px;
- cursor: pointer;
- transition: all 0.3s ease;
- border: 2px solid transparent;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
- overflow: hidden;
- }
- .document-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
- }
- .document-card.active {
- border-color: #4299e1;
- background: linear-gradient(135deg, #ebf8ff 0%, #ffffff 100%);
- }
- .card-content {
- padding: 5px;
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .document-icon {
- font-size: 1.25rem;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f7fafc;
- border-radius: 10px;
- flex-shrink: 0;
- }
- .document-info {
- flex: 1;
- min-width: 0;
- }
- .document-name {
- display: block;
- font-weight: 600;
- color: #2d3748;
- margin-bottom: 4px;
- font-size: 0.95rem;
- line-height: 1.4;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .document-status {
- font-size: 0.75rem;
- font-weight: 500;
- padding: 2px 8px;
- border-radius: 8px;
- }
- .document-status.available {
- background: #f0fff4;
- color: #2f855a;
- border: 1px solid #c6f6d5;
- }
- .document-status.unavailable {
- background: #fed7d7;
- color: #c53030;
- border: 1px solid #feb2b2;
- }
- .document-actions {
- display: flex;
- align-items: center;
- }
- .delete-btn {
- padding: 6px;
- border-radius: 8px;
- color: #e53e3e;
- transition: all 0.3s ease;
- }
- .delete-btn:hover {
- background: #fed7d7;
- transform: scale(1.1);
- }
- .sidebar-footer {
- background: white;
- padding: 16px 20px;
- border-radius: 16px;
- margin-top: 16px;
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-shrink: 0;
- }
- .pagination-info {
- color: #718096;
- font-size: 0.85rem;
- font-weight: 500;
- }
- .custom-pagination {
- margin: 0;
- }
- .custom-pagination :deep(.el-pagination) {
- justify-content: flex-end;
- }
- /* 主内容区样式 */
- .content-area {
- flex: 1;
- display: flex;
- flex-direction: column;
- min-height: 0;
- }
- .content-section {
- background: white;
- border-radius: 24px;
- padding: 32px;
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .content-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 24px;
- padding-bottom: 20px;
- border-bottom: 1px solid #e2e8f0;
- }
- .content-title {
- flex: 1;
- }
- .content-title h2 {
- margin: 0 0 8px 0;
- color: #2d3748;
- font-size: 1.75rem;
- font-weight: 700;
- line-height: 1.4;
- }
- .content-status {
- font-size: 0.85rem;
- font-weight: 500;
- padding: 4px 12px;
- border-radius: 12px;
- }
- .content-status.available {
- background: #f0fff4;
- color: #2f855a;
- border: 1px solid #c6f6d5;
- }
- .content-status.unavailable {
- background: #fed7d7;
- color: #c53030;
- border: 1px solid #feb2b2;
- }
- .chunk-btn {
- border-radius: 12px;
- padding: 10px 20px;
- font-weight: 500;
- }
- .content-body {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .content-text {
- background: #f7fafc;
- border-radius: 12px;
- border: 1px solid #e2e8f0;
- padding: 24px;
- flex: 1;
- overflow-y: auto;
- }
- .content-text pre {
- margin: 0;
- color: #4a5568;
- line-height: 1.6;
- font-size: 0.95rem;
- white-space: pre-wrap;
- word-wrap: break-word;
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- }
- .empty-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 60px 20px;
- text-align: center;
- }
- .empty-icon {
- font-size: 4rem;
- margin-bottom: 20px;
- opacity: 0.6;
- }
- .empty-content h3 {
- margin: 0 0 12px 0;
- color: #2d3748;
- font-size: 1.5rem;
- font-weight: 600;
- }
- .empty-content p {
- margin: 0;
- color: #718096;
- font-size: 1rem;
- line-height: 1.5;
- }
- /* 弹窗样式 */
- .content-dialog :deep(.el-dialog) {
- border-radius: 24px;
- overflow: hidden;
- box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
- }
- .content-dialog :deep(.el-dialog__header) {
- padding: 0;
- margin: 0;
- border-bottom: 1px solid #e2e8f0;
- }
- .content-dialog :deep(.el-dialog__headerbtn) {
- top: 24px;
- right: 24px;
- width: 32px;
- height: 32px;
- border-radius: 8px;
- background: #f7fafc;
- }
- .content-dialog :deep(.el-dialog__headerbtn:hover) {
- background: #e2e8f0;
- }
- .content-dialog :deep(.el-dialog__title) {
- font-size: 1.5rem;
- font-weight: 700;
- color: #2d3748;
- }
- .dialog-content {
- padding: 0;
- }
- .content-dialog :deep(.el-form-item__label) {
- font-weight: 600;
- color: #2d3748;
- }
- .content-dialog :deep(.el-input__wrapper) {
- border-radius: 12px;
- padding: 12px 16px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
- border: 1px solid #e2e8f0;
- }
- .content-dialog :deep(.el-textarea__inner) {
- border-radius: 12px;
- padding: 12px 16px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
- border: 1px solid #e2e8f0;
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- }
- .content-dialog :deep(.el-switch) {
- --el-switch-on-color: #4299e1;
- }
- .dialog-footer {
- padding: 0;
- margin-top: 24px;
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- }
- .action-btn {
- border-radius: 12px;
- padding: 10px 24px;
- font-weight: 500;
- transition: all 0.3s ease;
- }
- .action-btn.secondary {
- border: 1px solid #e2e8f0;
- background: white;
- color: #718096;
- }
- .action-btn.secondary:hover {
- background: #f7fafc;
- border-color: #cbd5e0;
- }
- .action-btn.primary {
- background: #4299e1;
- border: 1px solid #4299e1;
- color: white;
- }
- .action-btn.primary:hover {
- background: #3182ce;
- border-color: #3182ce;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(66, 153, 225, 0.3);
- }
- /* 分段弹窗样式 */
- .chunk-content {
- padding: 0;
- }
- .chunk-table :deep(.el-table) {
- border-radius: 12px;
- overflow: hidden;
- }
- .chunk-table :deep(.el-table__header) {
- background: #f7fafc;
- }
- .chunk-table :deep(.el-table th) {
- background: #f7fafc;
- color: #2d3748;
- font-weight: 600;
- }
- .status-available {
- color: #2f855a;
- font-weight: 500;
- }
- .status-unavailable {
- color: #c53030;
- font-weight: 500;
- }
- .empty-chunks {
- padding: 60px 20px;
- text-align: center;
- }
- .empty-chunks .empty-icon {
- font-size: 3rem;
- margin-bottom: 16px;
- }
- .empty-chunks h3 {
- margin: 0 0 8px 0;
- color: #2d3748;
- font-size: 1.25rem;
- font-weight: 600;
- }
- .empty-chunks p {
- margin: 0;
- color: #718096;
- font-size: 0.95rem;
- }
- .pagination-section {
- margin-top: 20px;
- text-align: center;
- padding-top: 20px;
- border-top: 1px solid #e2e8f0;
- }
- /* 响应式设计 */
- @media (max-width: 1200px) {
- .main-layout {
- flex-direction: column;
- }
- .sidebar {
- width: 100%;
- position: static;
- max-height: none;
- margin-bottom: 20px;
- }
- .sidebar-footer {
- position: static;
- }
- }
- @media (max-width: 768px) {
- .app-title {
- font-size: 1.75rem;
- }
- .header-content {
- flex-direction: column;
- gap: 16px;
- text-align: center;
- }
- .header-main {
- flex-direction: column;
- gap: 12px;
- align-items: center;
- }
- .header-back {
- align-self: flex-start;
- }
- .header-titles {
- text-align: center;
- }
- .header-stats {
- gap: 32px;
- }
- .main-layout {
- padding: 16px;
- }
- .content-section {
- padding: 24px;
- }
- .content-header {
- flex-direction: column;
- gap: 16px;
- align-items: stretch;
- }
- .chunk-btn {
- width: 100%;
- }
- .sidebar-header {
- flex-direction: column;
- gap: 12px;
- align-items: stretch;
- }
- .add-btn {
- width: 100%;
- }
- }
- @media (max-width: 480px) {
- .app-title {
- font-size: 1.5rem;
- }
- .content-section {
- padding: 20px;
- }
- .sidebar {
- width: 100%;
- }
- }
- /* 侧边栏滚动条样式 */
- .sidebar::-webkit-scrollbar {
- width: 6px;
- }
- .sidebar::-webkit-scrollbar-track {
- background: #f1f1f1;
- border-radius: 3px;
- }
- .sidebar::-webkit-scrollbar-thumb {
- background: #c1c1c1;
- border-radius: 3px;
- }
- .sidebar::-webkit-scrollbar-thumb:hover {
- background: #a8a8a8;
- }
- .knowledge-list::-webkit-scrollbar {
- width: 4px;
- }
- .knowledge-list::-webkit-scrollbar-track {
- background: transparent;
- }
- .knowledge-list::-webkit-scrollbar-thumb {
- background: #d1d1d1;
- border-radius: 2px;
- }
- /* 删除确认按钮样式 */
- :deep(.delete-confirm-btn) {
- background: #e53e3e;
- border-color: #e53e3e;
- }
- :deep(.delete-confirm-btn:hover) {
- background: #c53030;
- border-color: #c53030;
- }
- :deep(.delete-cancel-btn) {
- color: #718096;
- border-color: #e2e8f0;
- }
- /* 分段弹窗样式 */
- .chunk-dialog :deep(.el-dialog) {
- border-radius: 24px;
- overflow: hidden;
- box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
- max-height: 85vh;
- display: flex;
- flex-direction: column;
- }
- .chunk-dialog :deep(.el-dialog__header) {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- margin: 0;
- padding: 24px 32px;
- }
- .chunk-dialog :deep(.el-dialog__title) {
- color: white;
- font-size: 1.5rem;
- font-weight: 700;
- }
- .chunk-dialog :deep(.el-dialog__headerbtn) {
- top: 24px;
- right: 24px;
- }
- .chunk-dialog :deep(.el-dialog__headerbtn .el-dialog__close) {
- color: white;
- font-size: 1.25rem;
- }
- .chunk-dialog :deep(.el-dialog__body) {
- padding: 0;
- flex: 1;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
- .chunk-container {
- display: flex;
- flex-direction: column;
- height: 100%;
- min-height: 400px;
- }
- .chunk-header {
- padding: 20px 24px;
- background: #f8fafc;
- border-bottom: 1px solid #e2e8f0;
- }
- .chunk-stats {
- display: flex;
- gap: 20px;
- }
- .stat-item {
- color: #64748b;
- font-size: 0.9rem;
- font-weight: 500;
- }
- .chunk-content {
- flex: 1;
- overflow: auto;
- padding: 0;
- }
- .chunk-table {
- height: 100%;
- border: none;
- }
- .chunk-table :deep(.el-table__header-wrapper) {
- background: #f7fafc;
- }
- .chunk-table :deep(.el-table__header th) {
- background: #f7fafc;
- color: #374151;
- font-weight: 600;
- border-bottom: 1px solid #e2e8f0;
- }
- .chunk-table :deep(.el-table__body tr:hover > td) {
- background-color: #f0f9ff;
- }
- .chunk-table :deep(.el-table__body td) {
- border-bottom: 1px solid #f1f5f9;
- padding: 12px 16px;
- }
- .chunk-id {
- background: #e2e8f0;
- color: #475569;
- padding: 4px 8px;
- border-radius: 6px;
- font-size: 0.8rem;
- font-weight: 600;
- }
- .summary-content {
- max-height: 60px;
- overflow: hidden;
- line-height: 1.4;
- display: -webkit-box;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
- color: #475569;
- font-size: 0.9rem;
- }
- .full-content {
- max-height: 120px;
- overflow-y: auto;
- line-height: 1.5;
- color: #475569;
- font-size: 0.9rem;
- padding-right: 8px;
- }
- /* 自定义滚动条 */
- .full-content::-webkit-scrollbar {
- width: 4px;
- }
- .full-content::-webkit-scrollbar-track {
- background: #f1f5f9;
- border-radius: 2px;
- }
- .full-content::-webkit-scrollbar-thumb {
- background: #cbd5e1;
- border-radius: 2px;
- }
- .full-content::-webkit-scrollbar-thumb:hover {
- background: #94a3b8;
- }
- .status-tag {
- border: none;
- font-weight: 600;
- padding: 4px 12px;
- border-radius: 20px;
- }
- .empty-chunks {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- height: 300px;
- color: #64748b;
- }
- .empty-icon {
- font-size: 4rem;
- margin-bottom: 16px;
- opacity: 0.5;
- }
- .empty-chunks h3 {
- margin: 0 0 8px 0;
- color: #475569;
- font-size: 1.25rem;
- font-weight: 600;
- }
- .empty-chunks p {
- margin: 0;
- font-size: 0.9rem;
- }
- .pagination-section {
- padding: 20px 24px;
- background: #f8fafc;
- border-top: 1px solid #e2e8f0;
- display: flex;
- justify-content: center;
- }
- .pagination-section :deep(.el-pagination) {
- justify-content: center;
- }
- .pagination-section :deep(.el-pagination .btn-prev),
- .pagination-section :deep(.el-pagination .btn-next) {
- border-radius: 8px;
- border: 1px solid #d1d5db;
- }
- .pagination-section :deep(.el-pagination .number) {
- border-radius: 8px;
- border: 1px solid #d1d5db;
- }
- .pagination-section :deep(.el-pagination .number.active) {
- background: #3b82f6;
- border-color: #3b82f6;
- color: white;
- }
- .pagination-section :deep(.el-pagination .el-select .el-input) {
- border-radius: 8px;
- }
- </style>
|