|
@@ -44,7 +44,11 @@
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
|
|
- <el-table-column prop="collection_name" label="知识库表名" min-width="150" />
|
|
|
|
|
|
|
+ <el-table-column label="知识库表名" min-width="150">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div style="white-space: pre-wrap; line-height: 1.5;">{{ row.collection_name }}</div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
|
|
|
<el-table-column prop="document_count" label="文档数量" width="100" />
|
|
<el-table-column prop="document_count" label="文档数量" width="100" />
|
|
|
|
|
|
|
@@ -56,17 +60,17 @@
|
|
|
|
|
|
|
|
<el-table-column prop="created_by" label="创建人" width="100" />
|
|
<el-table-column prop="created_by" label="创建人" width="100" />
|
|
|
|
|
|
|
|
- <el-table-column prop="created_at" label="创建时间" width="160">
|
|
|
|
|
|
|
+ <el-table-column prop="created_time" label="创建时间" width="160">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
- {{ formatTime(row.created_at) }}
|
|
|
|
|
|
|
+ {{ formatTime(row.created_time) }}
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column prop="updated_by" label="修改人" width="100" />
|
|
<el-table-column prop="updated_by" label="修改人" width="100" />
|
|
|
|
|
|
|
|
- <el-table-column prop="updated_at" label="修改时间" width="160">
|
|
|
|
|
|
|
+ <el-table-column prop="updated_time" label="修改时间" width="160">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
- {{ formatTime(row.updated_at) }}
|
|
|
|
|
|
|
+ {{ formatTime(row.updated_time) }}
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
|
@@ -144,12 +148,19 @@
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
- <el-form-item label="集合名称" prop="collection_name" v-if="dialogType === 'create'">
|
|
|
|
|
- <el-input v-model="formData.collection_name" placeholder="Milvus集合名(英文)" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- <el-form-item label="集合名称" v-else>
|
|
|
|
|
- <el-input v-model="formData.collection_name" disabled />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
|
|
+ <template v-if="dialogType === 'create'">
|
|
|
|
|
+ <el-form-item label="父集合名称" prop="parent_collection_name">
|
|
|
|
|
+ <el-input v-model="formData.parent_collection_name" placeholder="父集合名(英文)" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="子集合名称" prop="child_collection_name">
|
|
|
|
|
+ <el-input v-model="formData.child_collection_name" placeholder="子集合名(英文)" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <el-form-item label="集合名称">
|
|
|
|
|
+ <el-input v-model="formData.collection_name" disabled />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </template>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
@@ -253,12 +264,61 @@
|
|
|
</span>
|
|
</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
|
|
+ <!-- View Dialog -->
|
|
|
|
|
+ <el-dialog
|
|
|
|
|
+ v-model="viewDialogVisible"
|
|
|
|
|
+ title="知识库详情"
|
|
|
|
|
+ width="800px"
|
|
|
|
|
+ class="view-dialog"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-descriptions :column="2" border class="detail-descriptions">
|
|
|
|
|
+ <el-descriptions-item label="知识库名称" label-class-name="desc-label">{{ viewData.name }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="集合名称" label-class-name="desc-label">{{ viewData.collection_name }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="状态" label-class-name="desc-label">
|
|
|
|
|
+ <el-tag :type="getStatusType(viewData.status)" effect="plain">
|
|
|
|
|
+ {{ getStatusText(viewData.status) }}
|
|
|
|
|
+ </el-tag>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="文档数量" label-class-name="desc-label">{{ viewData.document_count }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="创建时间" label-class-name="desc-label">{{ formatTime(viewData.created_time) }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="修改时间" label-class-name="desc-label">{{ formatTime(viewData.updated_time) }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="描述" :span="2" label-class-name="desc-label">{{ viewData.description || '暂无描述' }}</el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="view-content-section">
|
|
|
|
|
+ <div class="section-title">
|
|
|
|
|
+ <el-icon><Menu /></el-icon> Milvus Schema 定义
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-table :data="viewSchema" border stripe size="small" style="width: 100%">
|
|
|
|
|
+ <el-table-column prop="name" label="字段名称" width="150" />
|
|
|
|
|
+ <el-table-column prop="type" label="数据类型" width="150" />
|
|
|
|
|
+ <el-table-column prop="desc" label="说明" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="view-content-section">
|
|
|
|
|
+ <div class="section-title">
|
|
|
|
|
+ <el-icon><List /></el-icon> 元数据字段 (Metadata)
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-table v-if="viewMetadata.length > 0" :data="viewMetadata" border stripe size="small" style="width: 100%">
|
|
|
|
|
+ <el-table-column prop="field_zh_name" label="中文名称" width="150" />
|
|
|
|
|
+ <el-table-column prop="field_en_name" label="英文标识" width="150" />
|
|
|
|
|
+ <el-table-column prop="field_type" label="类型" width="100">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-tag size="small" type="info">{{ row.field_type === 'text' ? '文本' : '数字' }}</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="remark" label="备注" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ <div v-else class="empty-text">暂无元数据字段定义</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
|
-import { Search, Plus, Collection, View, Edit, Delete, MoreFilled, Refresh } from '@element-plus/icons-vue'
|
|
|
|
|
|
|
+import { Search, Plus, Collection, View, Edit, Delete, MoreFilled, Refresh, Menu, List } from '@element-plus/icons-vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
|
import {
|
|
import {
|
|
@@ -299,12 +359,20 @@ const formData = reactive({
|
|
|
id: '',
|
|
id: '',
|
|
|
name: '',
|
|
name: '',
|
|
|
collection_name: '',
|
|
collection_name: '',
|
|
|
|
|
+ parent_collection_name: '',
|
|
|
|
|
+ child_collection_name: '',
|
|
|
description: '',
|
|
description: '',
|
|
|
dimension: 768,
|
|
dimension: 768,
|
|
|
status: 'normal',
|
|
status: 'normal',
|
|
|
metadata_fields: [{ field_zh_name: '', field_en_name: '', field_type: 'text', remark: '' }]
|
|
metadata_fields: [{ field_zh_name: '', field_en_name: '', field_type: 'text', remark: '' }]
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+// View Dialog
|
|
|
|
|
+const viewDialogVisible = ref(false)
|
|
|
|
|
+const viewData = ref<KnowledgeBase>({} as KnowledgeBase)
|
|
|
|
|
+const viewMetadata = ref<any[]>([])
|
|
|
|
|
+const viewSchema = ref<any[]>([])
|
|
|
|
|
+
|
|
|
// 可选字段列表
|
|
// 可选字段列表
|
|
|
const availableFields = [
|
|
const availableFields = [
|
|
|
{ label: "文件名称", value: "文件名称" },
|
|
{ label: "文件名称", value: "文件名称" },
|
|
@@ -331,7 +399,14 @@ const getDisabledOptions = (currentIndex: number) => {
|
|
|
const rules: FormRules = {
|
|
const rules: FormRules = {
|
|
|
name: [{ required: true, message: '请输入知识库名称', trigger: 'blur' }],
|
|
name: [{ required: true, message: '请输入知识库名称', trigger: 'blur' }],
|
|
|
collection_name: [
|
|
collection_name: [
|
|
|
- { required: true, message: '请输入集合名称', trigger: 'blur' },
|
|
|
|
|
|
|
+ { required: false, message: '请输入集合名称', trigger: 'blur' }
|
|
|
|
|
+ ],
|
|
|
|
|
+ parent_collection_name: [
|
|
|
|
|
+ { required: true, message: '请输入父集合名称', trigger: 'blur' },
|
|
|
|
|
+ { pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: '必须以字母或下划线开头,只能包含字母、数字和下划线', trigger: 'blur' }
|
|
|
|
|
+ ],
|
|
|
|
|
+ child_collection_name: [
|
|
|
|
|
+ { required: true, message: '请输入子集合名称', trigger: 'blur' },
|
|
|
{ pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: '必须以字母或下划线开头,只能包含字母、数字和下划线', trigger: 'blur' }
|
|
{ pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: '必须以字母或下划线开头,只能包含字母、数字和下划线', trigger: 'blur' }
|
|
|
],
|
|
],
|
|
|
dimension: [{ required: true, message: '请输入维度', trigger: 'blur' }]
|
|
dimension: [{ required: true, message: '请输入维度', trigger: 'blur' }]
|
|
@@ -400,8 +475,10 @@ const handleAdd = () => {
|
|
|
formData.id = ''
|
|
formData.id = ''
|
|
|
formData.name = ''
|
|
formData.name = ''
|
|
|
formData.collection_name = ''
|
|
formData.collection_name = ''
|
|
|
|
|
+ formData.parent_collection_name = ''
|
|
|
|
|
+ formData.child_collection_name = ''
|
|
|
formData.description = ''
|
|
formData.description = ''
|
|
|
- formData.dimension = 768
|
|
|
|
|
|
|
+ formData.dimension = 768
|
|
|
formData.status = 'normal'
|
|
formData.status = 'normal'
|
|
|
formData.metadata_fields = [{ field_zh_name: '', field_en_name: '', field_type: 'text', remark: '' }]
|
|
formData.metadata_fields = [{ field_zh_name: '', field_en_name: '', field_type: 'text', remark: '' }]
|
|
|
dialogVisible.value = true
|
|
dialogVisible.value = true
|
|
@@ -411,6 +488,7 @@ const handleEdit = async (row: KnowledgeBase) => {
|
|
|
formData.id = row.id
|
|
formData.id = row.id
|
|
|
formData.name = row.name
|
|
formData.name = row.name
|
|
|
formData.collection_name = row.collection_name
|
|
formData.collection_name = row.collection_name
|
|
|
|
|
+ // 暂时不需要回显 parent/child,因为编辑是对单个进行的
|
|
|
formData.description = row.description || ''
|
|
formData.description = row.description || ''
|
|
|
formData.status = row.status
|
|
formData.status = row.status
|
|
|
|
|
|
|
@@ -444,68 +522,39 @@ const handleSync = async (row: KnowledgeBase) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const handleView = async (row: KnowledgeBase) => {
|
|
const handleView = async (row: KnowledgeBase) => {
|
|
|
- // 复用编辑时的逻辑加载元数据,但不打开编辑弹窗
|
|
|
|
|
|
|
+ viewData.value = row
|
|
|
|
|
+ viewMetadata.value = []
|
|
|
|
|
+ viewSchema.value = [
|
|
|
|
|
+ { name: 'pk', type: 'INT64', desc: '主键' },
|
|
|
|
|
+ { name: 'text', type: 'VARCHAR', desc: '内容 (Max: 65535)' },
|
|
|
|
|
+ { name: 'vector', type: 'FLOAT_VECTOR', desc: '向量列 (Dim: 768)' },
|
|
|
|
|
+ { name: 'sparse', type: 'BM25', desc: '关键字检索' },
|
|
|
|
|
+ { name: 'document_id', type: 'VARCHAR', desc: '文档ID' },
|
|
|
|
|
+ { name: 'parent_id', type: 'VARCHAR', desc: '父段ID' },
|
|
|
|
|
+ { name: 'index', type: 'INT64', desc: '索引序号' },
|
|
|
|
|
+ { name: 'tag_list', type: 'VARCHAR', desc: '标签' },
|
|
|
|
|
+ { name: 'permission', type: 'JSON', desc: '权限' },
|
|
|
|
|
+ { name: 'metadata', type: 'JSON', desc: '元数据' },
|
|
|
|
|
+ { name: 'is_deleted', type: 'BOOL/INT64', desc: '删除标志' },
|
|
|
|
|
+ { name: 'created_by', type: 'VARCHAR', desc: '创建人' },
|
|
|
|
|
+ { name: 'created_time', type: 'INT64', desc: '创建时间' },
|
|
|
|
|
+ { name: 'updated_by', type: 'VARCHAR', desc: '修改人' },
|
|
|
|
|
+ { name: 'updated_time', type: 'INT64', desc: '修改时间' }
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
const res = await getKnowledgeBaseMetadata(row.id)
|
|
const res = await getKnowledgeBaseMetadata(row.id)
|
|
|
- let metadataInfo = ''
|
|
|
|
|
- let schemaInfo = ''
|
|
|
|
|
-
|
|
|
|
|
if (res.code === 0 && res.data) {
|
|
if (res.code === 0 && res.data) {
|
|
|
if (res.data.metadata_fields && res.data.metadata_fields.length > 0) {
|
|
if (res.data.metadata_fields && res.data.metadata_fields.length > 0) {
|
|
|
- metadataInfo = res.data.metadata_fields.map((f: any) =>
|
|
|
|
|
- `<li>${f.field_zh_name} (${f.field_en_name}): ${f.field_type === 'text' ? '文本' : '数字'} - ${f.remark || '无备注'}</li>`
|
|
|
|
|
- ).join('')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (res.data.custom_schemas && res.data.custom_schemas.length > 0) {
|
|
|
|
|
- schemaInfo = res.data.custom_schemas.map((s: any) =>
|
|
|
|
|
- `<li>${s.field_name}: ${s.field_type} ${s.max_length ? `(Max: ${s.max_length})` : ''} - ${s.description || '无描述'}</li>`
|
|
|
|
|
- ).join('')
|
|
|
|
|
|
|
+ viewMetadata.value = res.data.metadata_fields
|
|
|
}
|
|
}
|
|
|
|
|
+ // 如果有动态 Schema 也可以合并到 viewSchema 中,但目前是固定的
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- const content = `
|
|
|
|
|
- <div style="text-align: left;">
|
|
|
|
|
- <p><strong>名称:</strong> ${row.name}</p>
|
|
|
|
|
- <p><strong>集合:</strong> ${row.collection_name}</p>
|
|
|
|
|
- <p><strong>描述:</strong> ${row.description || '暂无'}</p>
|
|
|
|
|
- <p><strong>状态:</strong> ${getStatusText(row.status)}</p>
|
|
|
|
|
- <p><strong>文档数:</strong> ${row.document_count}</p>
|
|
|
|
|
- <p><strong>创建时间:</strong> ${formatTime(row.created_at)}</p>
|
|
|
|
|
- <br>
|
|
|
|
|
- <p><strong>自定义 Schema (Milvus):</strong></p>
|
|
|
|
|
- <ul>
|
|
|
|
|
- <li>pk: INT64 (主键)</li>
|
|
|
|
|
- <li>text: VARCHAR (65535) - 内容</li>
|
|
|
|
|
- <li>vector: FLOAT_VECTOR (768) - 向量列</li>
|
|
|
|
|
- <li>sparse: BM25 - 关键字检索</li>
|
|
|
|
|
- <li>document_id: VARCHAR (128) - 文档ID</li>
|
|
|
|
|
- <li>parent_id: VARCHAR (128) - 父段ID</li>
|
|
|
|
|
- <li>index: INT64 - 索引序号</li>
|
|
|
|
|
- <li>tag_list: VARCHAR (2048) - 标签</li>
|
|
|
|
|
- <li>permission: JSON - 权限</li>
|
|
|
|
|
- <li>metadata: JSON - 元数据</li>
|
|
|
|
|
- <li>is_deleted: BOOL - 删除标志</li>
|
|
|
|
|
- <li>created_by: VARCHAR (128) - 创建人</li>
|
|
|
|
|
- <li>created_time: INT64 - 创建时间</li>
|
|
|
|
|
- <li>updated_by: VARCHAR (128) - 修改人</li>
|
|
|
|
|
- <li>updated_time: INT64 - 修改时间</li>
|
|
|
|
|
- </ul>
|
|
|
|
|
- <br>
|
|
|
|
|
- <p><strong>元数据字段 (Metadata):</strong></p>
|
|
|
|
|
- <ul>${metadataInfo || '<li>无元数据字段</li>'}</ul>
|
|
|
|
|
- </div>
|
|
|
|
|
- `
|
|
|
|
|
-
|
|
|
|
|
- ElMessageBox.alert(content, '知识库详情', {
|
|
|
|
|
- dangerouslyUseHTMLString: true,
|
|
|
|
|
- confirmButtonText: '关闭',
|
|
|
|
|
- customStyle: { maxWidth: '600px' }
|
|
|
|
|
- })
|
|
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error("加载详情失败", error)
|
|
console.error("加载详情失败", error)
|
|
|
- ElMessage.error("获取详情失败")
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ viewDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const handleDelete = (row: KnowledgeBase) => {
|
|
const handleDelete = (row: KnowledgeBase) => {
|
|
@@ -564,13 +613,24 @@ const handleSubmit = async () => {
|
|
|
submitLoading.value = true
|
|
submitLoading.value = true
|
|
|
try {
|
|
try {
|
|
|
if (dialogType.value === 'create') {
|
|
if (dialogType.value === 'create') {
|
|
|
|
|
+ // 1. 创建父集合 KB
|
|
|
await createKnowledgeBase({
|
|
await createKnowledgeBase({
|
|
|
- name: formData.name,
|
|
|
|
|
- collection_name: formData.collection_name,
|
|
|
|
|
|
|
+ name: formData.name + ' (父)',
|
|
|
|
|
+ collection_name: formData.parent_collection_name,
|
|
|
description: formData.description,
|
|
description: formData.description,
|
|
|
dimension: formData.dimension,
|
|
dimension: formData.dimension,
|
|
|
metadata_fields: formData.metadata_fields.filter(f => f.field_zh_name && f.field_en_name)
|
|
metadata_fields: formData.metadata_fields.filter(f => f.field_zh_name && f.field_en_name)
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 创建子集合 KB
|
|
|
|
|
+ await createKnowledgeBase({
|
|
|
|
|
+ name: formData.name + ' (子)',
|
|
|
|
|
+ collection_name: formData.child_collection_name,
|
|
|
|
|
+ description: formData.description,
|
|
|
|
|
+ dimension: formData.dimension,
|
|
|
|
|
+ metadata_fields: formData.metadata_fields.filter(f => f.field_zh_name && f.field_en_name)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
ElMessage.success('创建成功')
|
|
ElMessage.success('创建成功')
|
|
|
} else {
|
|
} else {
|
|
|
await updateKnowledgeBase(formData.id, {
|
|
await updateKnowledgeBase(formData.id, {
|
|
@@ -585,6 +645,8 @@ const handleSubmit = async () => {
|
|
|
loadData()
|
|
loadData()
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error(error)
|
|
console.error(error)
|
|
|
|
|
+ // 注意:如果是第二个失败,第一个可能已经创建成功。
|
|
|
|
|
+ // 这里简单提示错误,用户可以刷新列表看到已创建的,然后手动处理。
|
|
|
} finally {
|
|
} finally {
|
|
|
submitLoading.value = false
|
|
submitLoading.value = false
|
|
|
}
|
|
}
|
|
@@ -779,4 +841,37 @@ onMounted(() => {
|
|
|
.delete-btn {
|
|
.delete-btn {
|
|
|
margin-left: 10px;
|
|
margin-left: 10px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+/* Detail View Styles */
|
|
|
|
|
+:deep(.detail-descriptions .desc-label) {
|
|
|
|
|
+ width: 120px;
|
|
|
|
|
+ background-color: #f9fafc !important;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.view-content-section {
|
|
|
|
|
+ margin-top: 24px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.view-content-section .section-title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ font-size: 15px;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+ border-left: 4px solid #409EFF;
|
|
|
|
|
+ padding-left: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-text {
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ padding: 10px 0;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ background-color: #f8f9fa;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|