feat(review-tablet): 优化目录交互与文件识别展示
parent
06cd96067d
commit
2566d1e311
|
|
@ -45,3 +45,8 @@ export const getFileOpenUrl = (fileId: number): Promise<ReviewTabletOpenUrlVO> =
|
|||
url: '/project/review-tablet/file-open-url',
|
||||
params: { fileId }
|
||||
})
|
||||
|
||||
export const getAgendaOpenUrl = (): Promise<string> =>
|
||||
request.get({
|
||||
url: '/project/review-tablet/agenda-open-url'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,7 +15,17 @@
|
|||
<div class="left-title">专家评审资料</div>
|
||||
<el-button text :icon="Refresh" @click="loadCatalog" />
|
||||
</div>
|
||||
<div class="left-sub">当前评审会议编目:{{ projectCount }}篇</div>
|
||||
<div class="left-sub-row">
|
||||
<div class="left-sub">当前评审会议编目:{{ projectCount }}篇</div>
|
||||
<el-button
|
||||
class="agenda-entry-btn"
|
||||
size="small"
|
||||
:loading="agendaLoading"
|
||||
:disabled="treeData.length === 0"
|
||||
@click="openTodayAgenda"
|
||||
>今日议程</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
|
|
@ -57,12 +67,13 @@
|
|||
</div>
|
||||
<div v-else class="tree-item tree-file">
|
||||
<div class="node-main">
|
||||
<el-icon class="node-icon file-icon"><Document /></el-icon>
|
||||
<el-icon class="node-icon file-icon" :class="resolveFileIconClass(data.fileType)">
|
||||
<component :is="resolveFileIcon(data.fileType)" />
|
||||
</el-icon>
|
||||
<el-tooltip :content="data.label" placement="top-start" :show-after="300">
|
||||
<span class="node-label">{{ data.label }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<span class="node-ext">{{ data.fileType?.toUpperCase() }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
|
@ -72,12 +83,10 @@
|
|||
|
||||
<section class="center-pane">
|
||||
<header class="center-header">
|
||||
<div class="center-title">{{ activeFileName || '请选择左侧资料进行预览' }}</div>
|
||||
<div class="center-sub">{{
|
||||
activeFileDesc || '预览区支持 PDF/Office 等资料在线查看'
|
||||
}}</div>
|
||||
<div class="center-title" :class="{ 'is-file-title': isFilePreviewing }">{{ centerTitle }}</div>
|
||||
<div v-if="centerSub" class="center-sub">{{ centerSub }}</div>
|
||||
<div class="center-actions">
|
||||
<el-button text :icon="Refresh" :disabled="!activeFileId" @click="refreshPreview"
|
||||
<el-button text :icon="Refresh" :disabled="!canRefreshPreview" @click="refreshPreview"
|
||||
>刷新预览</el-button
|
||||
>
|
||||
<el-button text :icon="Link" :disabled="!newWindowPreviewUrl" @click="openInNewWindow"
|
||||
|
|
@ -88,48 +97,7 @@
|
|||
</header>
|
||||
|
||||
<div class="center-body" v-loading="previewLoading">
|
||||
<div v-if="showAgendaOverview" class="agenda-overview">
|
||||
<div class="agenda-head">
|
||||
<div class="agenda-title">今日议程</div>
|
||||
<div class="agenda-sub">{{ agendaMeetingLabel }}</div>
|
||||
</div>
|
||||
<div class="agenda-content">
|
||||
<div class="agenda-projects-panel">
|
||||
<div class="agenda-panel-title">项目信息</div>
|
||||
<div class="agenda-list">
|
||||
<div v-for="item in agendaOverviewList" :key="item.id" class="agenda-item">
|
||||
<div class="agenda-card">
|
||||
<div class="agenda-index">{{ item.seqNoText }}</div>
|
||||
<div class="agenda-main">
|
||||
<div class="agenda-name">{{ item.projectTitle }}</div>
|
||||
<div class="agenda-meta">
|
||||
<span>{{ item.agendaCategory || '未设置议程分类' }}</span>
|
||||
<span>{{ item.reporter || '未填写汇报人' }}</span>
|
||||
<span v-if="item.reporterUnit">{{ item.reporterUnit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="agenda-experts-panel">
|
||||
<div class="agenda-panel-title">专家信息</div>
|
||||
<div v-if="agendaExpertInfos.length > 0" class="agenda-experts">
|
||||
<div v-for="expert in agendaExpertInfos" :key="expert.key" class="agenda-expert">
|
||||
<div class="agenda-expert-name">{{ expert.name }}</div>
|
||||
<div class="agenda-expert-meta">
|
||||
<span v-if="expert.organization">{{ expert.organization }}</span>
|
||||
<span v-if="expert.title">{{ expert.title }}</span>
|
||||
<span v-if="expert.position">{{ expert.position }}</span>
|
||||
<span v-if="expert.remark">{{ expert.remark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="agenda-experts-empty">暂无专家信息</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!activeFileId && !previewLoading" class="welcome-panel">
|
||||
<div v-if="!activeFileId && !isAgendaPreview && !previewLoading" class="welcome-panel">
|
||||
<div class="welcome-title">欢迎查阅评审资料</div>
|
||||
<div class="welcome-sub">请从左侧目录中选择文件开始浏览</div>
|
||||
</div>
|
||||
|
|
@ -427,14 +395,18 @@ import {
|
|||
ArrowLeftBold,
|
||||
ArrowRightBold,
|
||||
Close,
|
||||
DataBoard,
|
||||
Document,
|
||||
Files,
|
||||
Folder,
|
||||
InfoFilled,
|
||||
Link,
|
||||
Loading,
|
||||
Picture,
|
||||
Promotion,
|
||||
Refresh,
|
||||
Search,
|
||||
Tickets,
|
||||
WarningFilled
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
|
@ -449,6 +421,7 @@ import {
|
|||
import {
|
||||
getFileOpenUrl,
|
||||
getProjectFiles,
|
||||
getAgendaOpenUrl,
|
||||
getActiveCatalog,
|
||||
type ReviewTabletCatalogVO,
|
||||
type ReviewTabletOpenUrlVO
|
||||
|
|
@ -518,6 +491,7 @@ const pageLoading = ref(false)
|
|||
const previewLoading = ref(false)
|
||||
const previewError = ref('')
|
||||
const keyword = ref('')
|
||||
const agendaLoading = ref(false)
|
||||
const leftCollapsed = ref(false)
|
||||
const rightCollapsed = ref(false)
|
||||
const sideTab = ref<SideTab>('ai')
|
||||
|
|
@ -532,6 +506,7 @@ const fileCache = ref<Record<number, ReviewMeetingFileRespVO[]>>({})
|
|||
const activeProjectId = ref<number>()
|
||||
const activeFileId = ref<number>()
|
||||
const activeFileNode = ref<FileTreeNode>()
|
||||
const isAgendaPreview = ref(false)
|
||||
const previewUrl = ref('')
|
||||
const previewPayload = ref<ReviewTabletOpenUrlVO>()
|
||||
const previewFrameLoading = ref(false)
|
||||
|
|
@ -541,65 +516,19 @@ const previewRequestToken = ref(0)
|
|||
const treeProps = { label: 'label', children: 'children' }
|
||||
|
||||
const projectCount = computed(() => treeData.value.length)
|
||||
const showAgendaOverview = computed(
|
||||
() =>
|
||||
!previewLoading.value &&
|
||||
!activeFileId.value &&
|
||||
treeData.value.length > 0 &&
|
||||
expandedKeys.value.length === 0
|
||||
)
|
||||
const agendaOverviewList = computed(() =>
|
||||
treeData.value.map((item) => ({
|
||||
id: item.id,
|
||||
projectTitle: item.label,
|
||||
agendaCategory: item.source.agendaCategory,
|
||||
expertInfos: (item.source.expertInfos || []).map((expert, index) => ({
|
||||
key: `${item.id}-${index}-${expert.name || 'expert'}`,
|
||||
name: expert.name,
|
||||
organization: expert.organization,
|
||||
title: expert.title,
|
||||
position: expert.position,
|
||||
remark: expert.remark ? `备注:${expert.remark}` : ''
|
||||
})),
|
||||
reporter: item.source.reporter,
|
||||
reporterUnit: item.source.reporterUnit,
|
||||
seqNoText: item.seqNo ? String(item.seqNo).padStart(2, '0') : '--'
|
||||
}))
|
||||
)
|
||||
const agendaExpertInfos = computed(() => {
|
||||
const seen = new Set<string>()
|
||||
return agendaOverviewList.value
|
||||
.flatMap((item) => item.expertInfos)
|
||||
.filter((expert) => {
|
||||
const key = [
|
||||
expert.name,
|
||||
expert.organization,
|
||||
expert.title,
|
||||
expert.position,
|
||||
expert.remark
|
||||
].join('|')
|
||||
if (seen.has(key)) return false
|
||||
seen.add(key)
|
||||
return true
|
||||
})
|
||||
})
|
||||
const agendaMeetingLabel = computed(() => {
|
||||
const first = treeData.value[0]?.source
|
||||
if (!first) return '当日评审项目总览'
|
||||
const timeSegments = [first.meetingName]
|
||||
if (first.meetingStartTime && first.meetingEndTime) {
|
||||
timeSegments.push(
|
||||
`${formatDate(new Date(first.meetingStartTime), 'HH:mm')} - ${formatDate(
|
||||
new Date(first.meetingEndTime),
|
||||
'HH:mm'
|
||||
)}`
|
||||
)
|
||||
}
|
||||
return timeSegments.filter(Boolean).join(' · ')
|
||||
})
|
||||
const activeFileName = computed(
|
||||
() => activeFileNode.value?.label || previewPayload.value?.fileName || ''
|
||||
)
|
||||
const isFilePreviewing = computed(() => !!activeFileId.value && !isAgendaPreview.value)
|
||||
const centerTitle = computed(() =>
|
||||
isAgendaPreview.value ? '今日议程' : activeFileName.value || '请选择左侧资料进行预览'
|
||||
)
|
||||
const centerSub = computed(() =>
|
||||
isAgendaPreview.value
|
||||
? ''
|
||||
: activeFileDesc.value || '预览区支持 PDF/Office 等资料在线查看'
|
||||
)
|
||||
const canRefreshPreview = computed(() => isAgendaPreview.value || !!activeFileId.value)
|
||||
const activeProjectTitle = computed(() => {
|
||||
if (!activeProjectId.value) return ''
|
||||
return (
|
||||
|
|
@ -828,7 +757,50 @@ const loadPreview = async (fileId: number) => {
|
|||
}
|
||||
}
|
||||
|
||||
const loadAgendaPreview = async () => {
|
||||
const requestToken = ++previewRequestToken.value
|
||||
clearPreviewFrameTimeout()
|
||||
previewLoading.value = true
|
||||
previewFrameLoading.value = true
|
||||
previewError.value = ''
|
||||
previewUrl.value = ''
|
||||
previewPayload.value = undefined
|
||||
previewFrameKey.value += 1
|
||||
agendaLoading.value = true
|
||||
try {
|
||||
const openUrl = await getAgendaOpenUrl()
|
||||
if (requestToken !== previewRequestToken.value) return
|
||||
if (!openUrl) {
|
||||
previewFrameLoading.value = false
|
||||
previewError.value = '当前会议暂无议程文件,请先在会议新建阶段生成议程'
|
||||
return
|
||||
}
|
||||
previewUrl.value = openUrl
|
||||
startPreviewFrameTimeout(requestToken)
|
||||
} catch {
|
||||
if (requestToken !== previewRequestToken.value) return
|
||||
previewFrameLoading.value = false
|
||||
previewError.value = '议程文件预览加载失败,请稍后重试'
|
||||
} finally {
|
||||
agendaLoading.value = false
|
||||
if (requestToken === previewRequestToken.value) {
|
||||
previewLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const openTodayAgenda = async () => {
|
||||
if (treeData.value.length === 0) return
|
||||
isAgendaPreview.value = true
|
||||
activeFileId.value = undefined
|
||||
activeFileNode.value = undefined
|
||||
await nextTick()
|
||||
treeRef.value?.setCurrentKey(undefined)
|
||||
await loadAgendaPreview()
|
||||
}
|
||||
|
||||
const selectFileNode = async (fileNode: FileTreeNode) => {
|
||||
isAgendaPreview.value = false
|
||||
activeProjectId.value = fileNode.projectId
|
||||
activeFileId.value = fileNode.fileId
|
||||
activeFileNode.value = fileNode
|
||||
|
|
@ -845,6 +817,10 @@ const openInNewWindow = () => {
|
|||
}
|
||||
|
||||
const refreshPreview = async () => {
|
||||
if (isAgendaPreview.value) {
|
||||
await loadAgendaPreview()
|
||||
return
|
||||
}
|
||||
if (activeFileId.value) await loadPreview(activeFileId.value)
|
||||
}
|
||||
|
||||
|
|
@ -878,6 +854,7 @@ const handleNodeExpand = async (data: TreeNode) => {
|
|||
}
|
||||
|
||||
const resetPreviewSelection = async () => {
|
||||
isAgendaPreview.value = false
|
||||
clearPreviewFrameTimeout()
|
||||
previewRequestToken.value += 1
|
||||
previewError.value = ''
|
||||
|
|
@ -899,12 +876,22 @@ const handleNodeCollapse = (data: TreeNode) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleNodeClick = async (data: TreeNode) => {
|
||||
const handleNodeClick = async (data: TreeNode, node: any) => {
|
||||
if (data.type === 'project') {
|
||||
persistCurrentProjectAiState()
|
||||
const switched = activeProjectId.value !== data.projectId
|
||||
activeProjectId.value = data.projectId
|
||||
await loadProjectFiles(data)
|
||||
const isExpanded = !!node?.expanded
|
||||
if (!isExpanded) {
|
||||
await loadProjectFiles(data)
|
||||
}
|
||||
if (node) {
|
||||
if (isExpanded) {
|
||||
node.collapse()
|
||||
} else {
|
||||
node.expand()
|
||||
}
|
||||
}
|
||||
if (isAiTabActive.value && (switched || !aiSummary.value)) {
|
||||
restoreOrLoadProjectAi(data.projectId)
|
||||
}
|
||||
|
|
@ -924,6 +911,7 @@ const loadCatalog = async () => {
|
|||
clearPreviewFrameTimeout()
|
||||
clearOfficeWarmupTimers()
|
||||
previewRequestToken.value += 1
|
||||
isAgendaPreview.value = false
|
||||
previewError.value = ''
|
||||
previewUrl.value = ''
|
||||
previewPayload.value = undefined
|
||||
|
|
@ -1241,6 +1229,26 @@ const formatFileSize = (bytes: number): string => {
|
|||
const isOfficeFile = (fileType?: string) =>
|
||||
['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes((fileType || '').toLowerCase())
|
||||
|
||||
const resolveFileIcon = (fileType?: string) => {
|
||||
const normalized = (fileType || '').toLowerCase()
|
||||
if (['ppt', 'pptx'].includes(normalized)) return Tickets
|
||||
if (['xls', 'xlsx', 'csv'].includes(normalized)) return DataBoard
|
||||
if (['doc', 'docx', 'txt', 'rtf'].includes(normalized)) return Document
|
||||
if (normalized === 'pdf') return Files
|
||||
if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'].includes(normalized)) return Picture
|
||||
return Document
|
||||
}
|
||||
|
||||
const resolveFileIconClass = (fileType?: string) => {
|
||||
const normalized = (fileType || '').toLowerCase()
|
||||
if (['ppt', 'pptx'].includes(normalized)) return 'file-icon--ppt'
|
||||
if (['xls', 'xlsx', 'csv'].includes(normalized)) return 'file-icon--excel'
|
||||
if (['doc', 'docx', 'txt', 'rtf'].includes(normalized)) return 'file-icon--doc'
|
||||
if (normalized === 'pdf') return 'file-icon--pdf'
|
||||
if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'].includes(normalized)) return 'file-icon--image'
|
||||
return ''
|
||||
}
|
||||
|
||||
const clearOfficeWarmupTimers = () => {
|
||||
officeWarmupTimers.forEach((timer) => clearTimeout(timer))
|
||||
officeWarmupTimers = []
|
||||
|
|
@ -1426,9 +1434,63 @@ loadCatalog()
|
|||
}
|
||||
|
||||
.left-sub {
|
||||
margin-top: 8px;
|
||||
color: var(--tablet-text-soft);
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.left-sub-row {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.agenda-entry-btn {
|
||||
flex-shrink: 0;
|
||||
height: 30px;
|
||||
padding: 0 14px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #b8cbea;
|
||||
background: #dbe7fa;
|
||||
color: #2d5ca3;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.3px;
|
||||
box-shadow:
|
||||
0 5px 12px rgba(60, 99, 182, 0.16),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.88);
|
||||
transition:
|
||||
transform 0.18s ease,
|
||||
box-shadow 0.18s ease,
|
||||
border-color 0.18s ease,
|
||||
color 0.18s ease,
|
||||
background 0.18s ease;
|
||||
}
|
||||
|
||||
.agenda-entry-btn:hover:not(.is-disabled) {
|
||||
border-color: #9eb9e2;
|
||||
color: #244b88;
|
||||
background: #cfe0fa;
|
||||
box-shadow:
|
||||
0 7px 16px rgba(45, 92, 163, 0.2),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.9);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.agenda-entry-btn:active:not(.is-disabled) {
|
||||
transform: translateY(0);
|
||||
box-shadow:
|
||||
0 4px 10px rgba(45, 92, 163, 0.16),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.agenda-entry-btn.is-disabled {
|
||||
border-color: var(--tablet-border);
|
||||
background: var(--tablet-surface-muted);
|
||||
color: #8695ab;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.left-search {
|
||||
|
|
@ -1487,17 +1549,15 @@ loadCatalog()
|
|||
}
|
||||
|
||||
.node-label {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
display: block;
|
||||
overflow: visible;
|
||||
white-space: normal;
|
||||
line-height: 1.4;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--tablet-text);
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.node-icon {
|
||||
|
|
@ -1515,6 +1575,26 @@ loadCatalog()
|
|||
color: #5d7395;
|
||||
}
|
||||
|
||||
.file-icon--doc {
|
||||
color: #2f67be;
|
||||
}
|
||||
|
||||
.file-icon--ppt {
|
||||
color: #d86a34;
|
||||
}
|
||||
|
||||
.file-icon--excel {
|
||||
color: #2f9d62;
|
||||
}
|
||||
|
||||
.file-icon--pdf {
|
||||
color: #cc4a4a;
|
||||
}
|
||||
|
||||
.file-icon--image {
|
||||
color: #7b5ac8;
|
||||
}
|
||||
|
||||
.node-badge {
|
||||
min-width: 20px;
|
||||
padding: 2px 6px;
|
||||
|
|
@ -1527,14 +1607,6 @@ loadCatalog()
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.node-ext {
|
||||
font-size: 12px;
|
||||
line-height: 1.3;
|
||||
color: var(--tablet-text-soft);
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.center-header {
|
||||
padding: 14px 16px 10px;
|
||||
border-bottom: 1px solid var(--tablet-border);
|
||||
|
|
@ -1543,7 +1615,7 @@ loadCatalog()
|
|||
|
||||
.center-title {
|
||||
font-size: 42px;
|
||||
line-height: 1;
|
||||
line-height: 1.1;
|
||||
color: var(--tablet-text);
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
|
|
@ -1551,6 +1623,16 @@ loadCatalog()
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.center-title.is-file-title {
|
||||
font-size: clamp(20px, 2.2vw, 30px);
|
||||
line-height: 1.3;
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.center-sub {
|
||||
margin-top: 10px;
|
||||
color: var(--tablet-text-soft);
|
||||
|
|
@ -1577,169 +1659,6 @@ loadCatalog()
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.agenda-overview {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 18px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
overflow-y: auto;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(196, 213, 239, 0.4), transparent 28%),
|
||||
linear-gradient(180deg, var(--tablet-panel-soft) 0%, var(--tablet-panel) 100%);
|
||||
}
|
||||
|
||||
.agenda-head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.agenda-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--tablet-text);
|
||||
}
|
||||
|
||||
.agenda-sub {
|
||||
font-size: 13px;
|
||||
color: var(--tablet-text-soft);
|
||||
}
|
||||
|
||||
.agenda-list {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.agenda-content {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr);
|
||||
gap: 14px;
|
||||
align-items: stretch;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.agenda-project {
|
||||
min-width: 0;
|
||||
background: var(--tablet-panel);
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
.agenda-projects-panel,
|
||||
.agenda-experts-panel {
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--tablet-border);
|
||||
box-shadow: 0 8px 24px rgba(139, 158, 191, 0.06);
|
||||
}
|
||||
|
||||
.agenda-projects-panel {
|
||||
height: 100%;
|
||||
background: var(--tablet-panel);
|
||||
}
|
||||
|
||||
.agenda-experts-panel {
|
||||
background: var(--tablet-panel);
|
||||
}
|
||||
|
||||
.agenda-item {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.agenda-panel-title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: var(--tablet-accent);
|
||||
}
|
||||
|
||||
.agenda-card {
|
||||
display: grid;
|
||||
grid-template-columns: 48px minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--tablet-border-strong);
|
||||
background: var(--tablet-surface-strong);
|
||||
}
|
||||
|
||||
.agenda-index {
|
||||
height: 28px;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #d5e3f8, #e5edf9);
|
||||
color: var(--tablet-accent);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.agenda-main {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.agenda-name {
|
||||
font-size: 15px;
|
||||
line-height: 1.35;
|
||||
color: var(--tablet-text);
|
||||
font-weight: 600;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.agenda-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 10px;
|
||||
color: var(--tablet-text-soft);
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.agenda-experts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.agenda-expert {
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
background: #e3ebf7;
|
||||
border: 1px solid var(--tablet-border-strong);
|
||||
}
|
||||
|
||||
.agenda-expert-name {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: var(--tablet-text);
|
||||
}
|
||||
|
||||
.agenda-expert-meta {
|
||||
margin-top: 3px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 10px;
|
||||
color: var(--tablet-text-soft);
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.agenda-experts-empty {
|
||||
color: var(--tablet-text-soft);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.preview-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
@ -2253,6 +2172,11 @@ loadCatalog()
|
|||
padding-right: 6px;
|
||||
}
|
||||
|
||||
:deep(.catalog-tree .el-tree-node__expand-icon) {
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:deep(.el-tree-node__content:hover) {
|
||||
background: var(--tablet-surface-muted);
|
||||
}
|
||||
|
|
@ -2350,6 +2274,13 @@ loadCatalog()
|
|||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-entry-btn {
|
||||
height: 34px;
|
||||
padding: 0 16px;
|
||||
font-size: 14px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .center-header {
|
||||
padding: 12px 14px 10px;
|
||||
}
|
||||
|
|
@ -2358,6 +2289,10 @@ loadCatalog()
|
|||
font-size: clamp(22px, 2.8vw, 34px);
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .center-title.is-file-title {
|
||||
font-size: clamp(18px, 2.1vw, 24px);
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .center-sub {
|
||||
margin-top: 8px;
|
||||
font-size: clamp(14px, 1.8vw, 19px);
|
||||
|
|
@ -2368,32 +2303,6 @@ loadCatalog()
|
|||
gap: 6px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-overview {
|
||||
padding: 14px 14px calc(16px + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-content {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-card {
|
||||
grid-template-columns: 42px minmax(0, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-index {
|
||||
height: 26px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .agenda-meta {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-touch-tablet .side-tabbar {
|
||||
padding: 8px;
|
||||
}
|
||||
|
|
@ -2443,15 +2352,6 @@ loadCatalog()
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-compact-tablet .agenda-content {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.tablet-shell.is-compact-tablet .agenda-projects-panel,
|
||||
.tablet-shell.is-compact-tablet .agenda-experts-panel {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-compact-tablet .ai-summary-wrap {
|
||||
max-height: 188px;
|
||||
}
|
||||
|
|
@ -2460,6 +2360,10 @@ loadCatalog()
|
|||
font-size: clamp(20px, 2.4vw, 28px);
|
||||
}
|
||||
|
||||
.tablet-shell.is-dense-tablet .center-title.is-file-title {
|
||||
font-size: clamp(16px, 2vw, 21px);
|
||||
}
|
||||
|
||||
.tablet-shell.is-dense-tablet .center-sub {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
|
@ -2468,8 +2372,7 @@ loadCatalog()
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
.tablet-shell.is-dense-tablet .left-sub,
|
||||
.tablet-shell.is-dense-tablet .agenda-sub {
|
||||
.tablet-shell.is-dense-tablet .left-sub {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue