597 lines
13 KiB
Vue
597 lines
13 KiB
Vue
<template>
|
|||
|
|
<div class="mod-weather__real-time-monitoring" v-loading="state.loading">
|
||
|
|
<div class="page-header">
|
||
|
|
<div>
|
||
|
|
<h2 class="page-title">631气象信息</h2>
|
||
|
|
</div>
|
||
|
|
<div class="page-header-actions">
|
||
|
|
<el-tag type="info">层级 {{ state.selectedPath.length }} 级</el-tag>
|
||
|
|
<el-tag type="success">文件 {{ state.fileItems.length }}</el-tag>
|
||
|
|
<el-button type="primary" plain icon="Refresh" @click="refresh">刷新</el-button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<el-alert v-if="state.errorMessage" :title="state.errorMessage" type="error" :closable="false" show-icon class="mb-16" />
|
||
|
|
|
||
|
|
<div class="dept-bar" v-if="levelRows.length">
|
||
|
|
<div class="level-row" v-for="(row, rowIdx) in levelRows" :key="rowIdx">
|
||
|
|
<span class="level-label" v-if="row.label">{{ row.label }}</span>
|
||
|
|
<div class="level-tabs">
|
||
|
|
<div v-for="tab in row.tabs" :key="tab.id" class="level-tab" :class="[{ 'is-active': row.selectedId === tab.id }, `level-${rowIdx}`]" @click="selectTab(rowIdx, tab)">
|
||
|
|
{{ tab.name }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="page-body" v-if="state.fileItems.length">
|
||
|
|
<aside class="file-list-panel">
|
||
|
|
<div v-for="(item, index) in state.fileItems" :key="item.anchorId" class="file-list-item" :class="{ 'is-active': state.selectedFileIndex === index }" @click="selectFile(index)">
|
||
|
|
<div class="file-list-item__thumb">
|
||
|
|
<span class="file-list-item__icon file-list-item__icon--txt">文</span>
|
||
|
|
</div>
|
||
|
|
<span class="file-list-item__name">{{ item.displayName || `文件-${item.fileId}` }}</span>
|
||
|
|
</div>
|
||
|
|
</aside>
|
||
|
|
|
||
|
|
<section class="preview-panel" v-if="previewItem">
|
||
|
|
<div class="preview-panel__header">
|
||
|
|
<h3 class="preview-panel__title">{{ previewItem.displayName || `文件-${previewItem.fileId}` }}</h3>
|
||
|
|
<el-button type="primary" plain size="small" :loading="state.copyingId === previewItem.anchorId" @click="copyText(previewItem)"> 复制全部文本 </el-button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="preview-panel__body">
|
||
|
|
<div class="preview-panel__text preview-panel__text--full">{{ previewItem.content || "暂无文本内容" }}</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<div class="preview-panel preview-panel--empty" v-else>
|
||
|
|
<el-empty description="请在左侧选择要预览的文件" :image-size="120" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<el-empty v-else-if="!state.loading && !state.errorMessage" description="暂无可供展示的文件" />
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script lang="ts" setup>
|
||
|
|
import app from "@/constants/app";
|
||
|
|
import baseService from "@/service/baseService";
|
||
|
|
import { copyToClipboard } from "@/utils/utils";
|
||
|
|
import { ElMessage } from "element-plus";
|
||
|
|
import { computed, onMounted, reactive } from "vue";
|
||
|
|
|
||
|
|
interface DeptNode {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
children?: DeptNode[];
|
||
|
|
}
|
||
|
|
|
||
|
|
interface DeptTab {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface DeptFileGroupVO {
|
||
|
|
deptId: string;
|
||
|
|
deptName: string;
|
||
|
|
fileList: { displayName: string; fileId: string; type: string; content: string }[];
|
||
|
|
}
|
||
|
|
|
||
|
|
interface FileItem {
|
||
|
|
deptId: string;
|
||
|
|
deptName: string;
|
||
|
|
displayName: string;
|
||
|
|
fileId: string;
|
||
|
|
type: string;
|
||
|
|
content: string;
|
||
|
|
anchorId: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
const IMAGE_EXTS = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg"];
|
||
|
|
|
||
|
|
const isImageFile = (type: string) => {
|
||
|
|
if (!type) return true;
|
||
|
|
const lower = type.toLowerCase();
|
||
|
|
return IMAGE_EXTS.some((ext) => lower.includes(ext));
|
||
|
|
};
|
||
|
|
|
||
|
|
const state = reactive({
|
||
|
|
loading: true,
|
||
|
|
errorMessage: "",
|
||
|
|
fileItems: [] as FileItem[],
|
||
|
|
copyingId: "",
|
||
|
|
deptTreeData: [] as DeptNode[],
|
||
|
|
selectedPath: [] as string[],
|
||
|
|
selectedFileIndex: 0
|
||
|
|
});
|
||
|
|
|
||
|
|
const previewItem = computed(() => {
|
||
|
|
if (state.selectedFileIndex >= 0 && state.selectedFileIndex < state.fileItems.length) {
|
||
|
|
return state.fileItems[state.selectedFileIndex];
|
||
|
|
}
|
||
|
|
return state.fileItems.length > 0 ? state.fileItems[0] : null;
|
||
|
|
});
|
||
|
|
|
||
|
|
const transformGroups = (list: DeptFileGroupVO[]) => {
|
||
|
|
const items: FileItem[] = [];
|
||
|
|
|
||
|
|
list.forEach((group) => {
|
||
|
|
(group.fileList || []).forEach((file) => {
|
||
|
|
if (isImageFile(file.type)) return;
|
||
|
|
items.push({
|
||
|
|
deptId: group.deptId,
|
||
|
|
deptName: group.deptName,
|
||
|
|
displayName: file.displayName,
|
||
|
|
fileId: file.fileId,
|
||
|
|
type: file.type,
|
||
|
|
content: file.content || "",
|
||
|
|
anchorId: `txt-${file.fileId}`
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
state.fileItems = items;
|
||
|
|
state.selectedFileIndex = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
const activeDeptId = computed(() => {
|
||
|
|
if (state.selectedPath.length > 0) {
|
||
|
|
return state.selectedPath[state.selectedPath.length - 1];
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
});
|
||
|
|
|
||
|
|
interface LevelRow {
|
||
|
|
tabs: DeptTab[];
|
||
|
|
selectedId: string | null;
|
||
|
|
label: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
const LEVEL_LABELS = ["一级", "二级", "三级", "四级", "五级", "六级"];
|
||
|
|
|
||
|
|
const levelRows = computed<LevelRow[]>(() => {
|
||
|
|
const rows: LevelRow[] = [];
|
||
|
|
let nodes: DeptNode[] = state.deptTreeData;
|
||
|
|
|
||
|
|
for (let i = 0; i < state.selectedPath.length; i++) {
|
||
|
|
const selId = state.selectedPath[i];
|
||
|
|
rows.push({
|
||
|
|
tabs: nodes.map((n) => ({ id: n.id, name: n.name })),
|
||
|
|
selectedId: selId,
|
||
|
|
label: LEVEL_LABELS[i] || `${i + 1}级`
|
||
|
|
});
|
||
|
|
const selNode = nodes.find((n) => n.id === selId);
|
||
|
|
if (selNode?.children?.length) {
|
||
|
|
nodes = selNode.children;
|
||
|
|
} else {
|
||
|
|
nodes = [];
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nodes.length > 0) {
|
||
|
|
rows.push({
|
||
|
|
tabs: nodes.map((n) => ({ id: n.id, name: n.name })),
|
||
|
|
selectedId: null,
|
||
|
|
label: LEVEL_LABELS[rows.length] || `${rows.length + 1}级`
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return rows;
|
||
|
|
});
|
||
|
|
|
||
|
|
const loadData = async (deptId: string) => {
|
||
|
|
state.loading = true;
|
||
|
|
state.errorMessage = "";
|
||
|
|
try {
|
||
|
|
const res = await baseService.get("/filescan/record/tree", { deptId });
|
||
|
|
transformGroups((res.data || []) as DeptFileGroupVO[]);
|
||
|
|
selectFile(0);
|
||
|
|
} catch (error: any) {
|
||
|
|
state.errorMessage = error?.message || "加载失败";
|
||
|
|
state.fileItems = [];
|
||
|
|
} finally {
|
||
|
|
state.loading = false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const loadDeptTree = async (): Promise<string | null> => {
|
||
|
|
try {
|
||
|
|
const res = await baseService.get("/sys/dept/list");
|
||
|
|
const treeData = (res.data || []) as DeptNode[];
|
||
|
|
state.deptTreeData = treeData;
|
||
|
|
|
||
|
|
if (!treeData.length) return null;
|
||
|
|
|
||
|
|
const firstRoot = treeData[0];
|
||
|
|
const firstChild = firstRoot.children?.length ? firstRoot.children[0] : firstRoot;
|
||
|
|
|
||
|
|
const buildPath = (nodes: DeptNode[], targetId: string, path: string[]): string[] | null => {
|
||
|
|
for (const node of nodes) {
|
||
|
|
const newPath = [...path, node.id];
|
||
|
|
if (node.id === targetId) return newPath;
|
||
|
|
if (node.children?.length) {
|
||
|
|
const found = buildPath(node.children, targetId, newPath);
|
||
|
|
if (found) return found;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const path = buildPath(treeData, firstChild.id, []);
|
||
|
|
state.selectedPath = path || [firstRoot.id];
|
||
|
|
return firstChild.id;
|
||
|
|
} catch {
|
||
|
|
state.deptTreeData = [];
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const selectTab = (levelIdx: number, tab: DeptTab) => {
|
||
|
|
state.selectedPath = [...state.selectedPath.slice(0, levelIdx), tab.id];
|
||
|
|
state.fileItems = [];
|
||
|
|
state.selectedFileIndex = 0;
|
||
|
|
loadData(tab.id);
|
||
|
|
};
|
||
|
|
|
||
|
|
const refresh = () => {
|
||
|
|
if (activeDeptId.value !== null) {
|
||
|
|
loadData(activeDeptId.value);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const selectFile = (index: number) => {
|
||
|
|
state.selectedFileIndex = index;
|
||
|
|
};
|
||
|
|
|
||
|
|
const copyText = (item: FileItem) => {
|
||
|
|
state.copyingId = item.anchorId;
|
||
|
|
copyToClipboard(item.content || "");
|
||
|
|
ElMessage.success("文本已复制成功");
|
||
|
|
state.copyingId = "";
|
||
|
|
};
|
||
|
|
|
||
|
|
onMounted(async () => {
|
||
|
|
const deptId = await loadDeptTree();
|
||
|
|
if (deptId !== null) {
|
||
|
|
loadData(deptId);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.mod-weather__real-time-monitoring {
|
||
|
|
min-height: calc(100vh - 140px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: flex-start;
|
||
|
|
gap: 16px;
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-title {
|
||
|
|
margin: 0;
|
||
|
|
font-size: 24px;
|
||
|
|
color: #303133;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-desc {
|
||
|
|
margin: 8px 0 0;
|
||
|
|
color: #909399;
|
||
|
|
line-height: 1.6;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header-actions {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
}
|
||
|
|
|
||
|
|
.mb-16 {
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==== 部门选择栏 ==== */
|
||
|
|
.dept-bar {
|
||
|
|
margin-bottom: 16px;
|
||
|
|
background: #fff;
|
||
|
|
border: 1px solid #ebeef5;
|
||
|
|
border-radius: 8px;
|
||
|
|
padding: 10px 16px 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-row {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
margin-bottom: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-row:last-child {
|
||
|
|
margin-bottom: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-label {
|
||
|
|
font-size: 13px;
|
||
|
|
color: #909399;
|
||
|
|
flex-shrink: 0;
|
||
|
|
min-width: 32px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tabs {
|
||
|
|
display: flex;
|
||
|
|
gap: 0;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab {
|
||
|
|
padding: 4px 16px;
|
||
|
|
font-size: 13px;
|
||
|
|
color: #606266;
|
||
|
|
background: #f5f7fa;
|
||
|
|
border: 1px solid #e4e7ed;
|
||
|
|
border-radius: 6px;
|
||
|
|
cursor: pointer;
|
||
|
|
user-select: none;
|
||
|
|
transition: color 0.2s, background 0.2s, border-color 0.2s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab + .level-tab {
|
||
|
|
margin-left: 6px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab:hover {
|
||
|
|
color: var(--el-color-primary);
|
||
|
|
background: #ecf5ff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active {
|
||
|
|
color: #fff;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active.level-0 {
|
||
|
|
background: var(--el-color-primary);
|
||
|
|
border-color: var(--el-color-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active.level-1 {
|
||
|
|
background: var(--el-color-primary-light-3);
|
||
|
|
border-color: var(--el-color-primary-light-3);
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active.level-2 {
|
||
|
|
background: var(--el-color-success);
|
||
|
|
border-color: var(--el-color-success);
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active.level-3 {
|
||
|
|
background: var(--el-color-warning);
|
||
|
|
border-color: var(--el-color-warning);
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active.level-4 {
|
||
|
|
background: var(--el-color-danger);
|
||
|
|
border-color: var(--el-color-danger);
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab.is-active.level-5 {
|
||
|
|
background: #8b5cf6;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==== 主体两栏 ==== */
|
||
|
|
.page-body {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: minmax(0, 1fr);
|
||
|
|
gap: 12px;
|
||
|
|
align-items: start;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==== 左侧文件列表 ==== */
|
||
|
|
.file-list-panel {
|
||
|
|
position: sticky;
|
||
|
|
top: 16px;
|
||
|
|
background: #fff;
|
||
|
|
border: 1px solid #ebeef5;
|
||
|
|
border-radius: 8px;
|
||
|
|
padding: 4px;
|
||
|
|
max-height: calc(100vh - 320px);
|
||
|
|
overflow-y: auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
padding: 8px 10px;
|
||
|
|
font-size: 13px;
|
||
|
|
color: #606266;
|
||
|
|
border-radius: 6px;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: background 0.15s, color 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item:hover {
|
||
|
|
background: #f5f7fa;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item.is-active {
|
||
|
|
background: var(--el-color-primary-light-9);
|
||
|
|
color: var(--el-color-primary);
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__thumb {
|
||
|
|
flex-shrink: 0;
|
||
|
|
width: 44px;
|
||
|
|
height: 44px;
|
||
|
|
border-radius: 6px;
|
||
|
|
overflow: hidden;
|
||
|
|
background: #f0f2f5;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__img {
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
object-fit: cover;
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__icon {
|
||
|
|
font-size: 13px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: #fff;
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__icon--img {
|
||
|
|
background: var(--el-color-success);
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__icon--txt {
|
||
|
|
background: var(--el-color-warning);
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__icon--other {
|
||
|
|
background: #c0c4cc;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-list-item__name {
|
||
|
|
flex: 1;
|
||
|
|
min-width: 0;
|
||
|
|
overflow: hidden;
|
||
|
|
text-overflow: ellipsis;
|
||
|
|
white-space: nowrap;
|
||
|
|
line-height: 1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==== 右侧预览面板 ==== */
|
||
|
|
.preview-panel {
|
||
|
|
background: #fff;
|
||
|
|
border: 1px solid #ebeef5;
|
||
|
|
border-radius: 10px;
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel--empty {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
min-height: 400px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
gap: 16px;
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__actions {
|
||
|
|
display: flex;
|
||
|
|
gap: 8px;
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__title {
|
||
|
|
margin: 0;
|
||
|
|
font-size: 20px;
|
||
|
|
color: #303133;
|
||
|
|
word-break: break-all;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__body {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__loading {
|
||
|
|
text-align: center;
|
||
|
|
color: #909399;
|
||
|
|
padding: 60px 0;
|
||
|
|
font-size: 14px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-zoom-area {
|
||
|
|
overflow: hidden;
|
||
|
|
border-radius: 8px;
|
||
|
|
background: #f5f7fa;
|
||
|
|
min-height: 200px;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__img {
|
||
|
|
display: block;
|
||
|
|
max-width: 100%;
|
||
|
|
max-height: 60vh;
|
||
|
|
border-radius: 8px;
|
||
|
|
user-select: none;
|
||
|
|
pointer-events: auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__text--full {
|
||
|
|
min-height: 200px;
|
||
|
|
max-height: 60vh;
|
||
|
|
overflow-y: auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.preview-panel__text {
|
||
|
|
font-size: 13px;
|
||
|
|
color: #606266;
|
||
|
|
line-height: 1.8;
|
||
|
|
white-space: pre-wrap;
|
||
|
|
word-break: break-word;
|
||
|
|
padding: 12px 14px;
|
||
|
|
background: #f5f7fa;
|
||
|
|
border-radius: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.image-card__error,
|
||
|
|
.image-card__unsupported {
|
||
|
|
color: #e6a23c;
|
||
|
|
font-size: 14px;
|
||
|
|
line-height: 1.6;
|
||
|
|
padding: 12px 14px;
|
||
|
|
background: #fdf6ec;
|
||
|
|
border-radius: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==== 响应式 ==== */
|
||
|
|
@media (max-width: 992px) {
|
||
|
|
.page-body {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 768px) {
|
||
|
|
.page-header,
|
||
|
|
.preview-panel__header,
|
||
|
|
.preview-panel__actions {
|
||
|
|
flex-direction: column;
|
||
|
|
align-items: stretch;
|
||
|
|
}
|
||
|
|
|
||
|
|
.level-tab {
|
||
|
|
padding: 4px 10px;
|
||
|
|
font-size: 12px;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</style>
|