feat(documents): 文书库筛选条按院区-科室-状态三级重构
This commit is contained in:
@@ -1,23 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 文书库的两级筛选条(原型 V10.2 的 #libTabs / #libStatus)。
|
||||
* 文书库的分级筛选条:院区 → 科室 → 状态。
|
||||
*
|
||||
* 类名刻意沿用原型的 lib-tabs / lib-tab / lib-status / lib-st:这套样式在原型里
|
||||
* 是文档库页面独有的筛选语言(胶囊 + 虚线分隔),与通用 Tabs 组件的观感不同,
|
||||
* 换成通用组件会把「全部(8)」这类计数排版搞丢。
|
||||
* 原型 V10.2 只有「科室 + 状态」两行(#libTabs / #libStatus)。这里把科室那一级按
|
||||
* 「组织架构」的口径拆成两级:先选院区(同一份院区字典、同一个 sortNo 顺序,
|
||||
* 与架构树的院区顺序一致),再在该院区的科室里筛。院区不做「全部院区」——
|
||||
* 架构树里也始终落在某一个院区上,两处口径保持一致。
|
||||
*
|
||||
* 类名沿用原型的 lib-tabs / lib-tab / lib-status / lib-st:这套样式是文档库页面独有的
|
||||
* 筛选语言(胶囊 + 虚线分隔),与通用 Tabs 组件的观感不同,换成通用组件会把
|
||||
* 「全部(8)」这类计数排版搞丢。
|
||||
*
|
||||
* 用 <button> 而不是原型的 <span onclick>:保留键盘可达与 aria-selected。
|
||||
*/
|
||||
import type { DepartmentTab, DocumentFilterStatus, StatusTab } from '../types'
|
||||
import type { CampusTab, DepartmentTab, DocumentFilterStatus, StatusTab } from '../types'
|
||||
|
||||
defineProps<{
|
||||
/** 当前院区 id。院区是页面级的取数口径,由页面持有(见 index.vue) */
|
||||
campus: string
|
||||
department: string | null
|
||||
status: DocumentFilterStatus
|
||||
/** 演示文库没有院区维度,页面会传空数组,这一级整行不渲染 */
|
||||
campuses: CampusTab[]
|
||||
departments: DepartmentTab[]
|
||||
statuses: StatusTab[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'select-campus': [value: string]
|
||||
'update:department': [value: string | null]
|
||||
'update:status': [value: DocumentFilterStatus]
|
||||
}>()
|
||||
@@ -25,40 +35,65 @@ const emit = defineEmits<{
|
||||
|
||||
<template>
|
||||
<div class="lib-filter">
|
||||
<div class="lib-tabs" role="tablist" aria-label="按科室筛选">
|
||||
<button
|
||||
v-for="tab in departments"
|
||||
:key="tab.key ?? 'all'"
|
||||
type="button"
|
||||
class="lib-tab"
|
||||
:class="{ on: department === tab.key }"
|
||||
:aria-selected="department === tab.key"
|
||||
role="tab"
|
||||
@click="emit('update:department', tab.key)"
|
||||
>
|
||||
{{ tab.label }}({{ tab.count }})
|
||||
</button>
|
||||
<div v-if="campuses.length" class="lib-row">
|
||||
<span class="lib-row__label">院区</span>
|
||||
<div class="lib-tabs" role="tablist" aria-label="按院区筛选">
|
||||
<button
|
||||
v-for="tab in campuses"
|
||||
:key="tab.key"
|
||||
type="button"
|
||||
class="lib-tab"
|
||||
:class="{ on: campus === tab.key }"
|
||||
:aria-selected="campus === tab.key"
|
||||
role="tab"
|
||||
@click="emit('select-campus', tab.key)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lib-status" role="tablist" aria-label="按状态筛选">
|
||||
<button
|
||||
v-for="tab in statuses"
|
||||
:key="tab.key"
|
||||
type="button"
|
||||
class="lib-st"
|
||||
:class="{ on: status === tab.key }"
|
||||
:aria-selected="status === tab.key"
|
||||
role="tab"
|
||||
@click="emit('update:status', tab.key)"
|
||||
>
|
||||
{{ tab.label }}<template v-if="tab.count"> · {{ tab.count }}</template>
|
||||
</button>
|
||||
<!-- 没有院区这一级时(演示模式)科室行就是首行,不再加分隔线 -->
|
||||
<div class="lib-row" :class="{ 'lib-row--sub': campuses.length }">
|
||||
<span class="lib-row__label">科室</span>
|
||||
<div class="lib-tabs" role="tablist" aria-label="按科室筛选">
|
||||
<button
|
||||
v-for="tab in departments"
|
||||
:key="tab.key ?? 'all'"
|
||||
type="button"
|
||||
class="lib-tab"
|
||||
:class="{ on: department === tab.key }"
|
||||
:aria-selected="department === tab.key"
|
||||
role="tab"
|
||||
@click="emit('update:department', tab.key)"
|
||||
>
|
||||
{{ tab.label }}({{ tab.count }})
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lib-row lib-row--sub">
|
||||
<span class="lib-row__label">状态</span>
|
||||
<div class="lib-status" role="tablist" aria-label="按状态筛选">
|
||||
<button
|
||||
v-for="tab in statuses"
|
||||
:key="tab.key"
|
||||
type="button"
|
||||
class="lib-st"
|
||||
:class="{ on: status === tab.key }"
|
||||
:aria-selected="status === tab.key"
|
||||
role="tab"
|
||||
@click="emit('update:status', tab.key)"
|
||||
>
|
||||
{{ tab.label }}<template v-if="tab.count"> · {{ tab.count }}</template>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 原型把两条页签包在 .card 里(padding:12px 16px; margin-bottom:12px),照抄 */
|
||||
/* 原型把筛选条包在 .card 里(padding:12px 16px; margin-bottom:12px),照抄 */
|
||||
.lib-filter {
|
||||
padding: 12px 16px;
|
||||
margin-bottom: 12px;
|
||||
@@ -67,12 +102,40 @@ const emit = defineEmits<{
|
||||
box-shadow: var(--sh);
|
||||
}
|
||||
|
||||
/* 原型 .lib-tabs:flex-wrap + gap 8,块间距靠 margin-bottom 交给外层 */
|
||||
.lib-tabs {
|
||||
/*
|
||||
* 每一级筛选占一行:行首一个小标签写明「这一行筛的是什么」。
|
||||
* 三行胶囊外观相近,不标出来就分不清哪行是院区、哪行是科室。
|
||||
*/
|
||||
.lib-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* 下级与上级之间用一条虚线分开(原型里科室与状态之间就是这条线) */
|
||||
.lib-row--sub {
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
border-top: 1px dashed var(--line);
|
||||
}
|
||||
|
||||
/* 标签与第一行胶囊(约 29px 高)视觉居中 */
|
||||
.lib-row__label {
|
||||
flex: 0 0 auto;
|
||||
padding-top: 6px;
|
||||
color: var(--mut);
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.lib-tabs,
|
||||
.lib-status {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.lib-tab {
|
||||
@@ -99,15 +162,7 @@ const emit = defineEmits<{
|
||||
background: var(--brand);
|
||||
}
|
||||
|
||||
/* 原型 .lib-status:与科室行之间用一条虚线分开,表达「同一维度下的第二级筛选」 */
|
||||
.lib-status {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px dashed var(--line);
|
||||
}
|
||||
|
||||
/* 状态是比科室更细的一档,用描边胶囊而不是实底,视觉上轻一级 */
|
||||
.lib-st {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -149,8 +149,6 @@ const togglePermission = computed(() =>
|
||||
历史记录
|
||||
</button>
|
||||
|
||||
<span class="ft-spacer" />
|
||||
|
||||
<button
|
||||
v-if="toggleAction"
|
||||
v-permission="togglePermission"
|
||||
@@ -326,21 +324,18 @@ const togglePermission = computed(() =>
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
|
||||
/* 按钮组不做左右两侧分栏:从左到右依次排布(预览 / 编辑属性 / 编辑正文 / 历史记录 / 停用 / 发起) */
|
||||
.tpl-ft {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding-top: 10px;
|
||||
margin-top: 4px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
/* 把状态动作与发起推到右侧,左侧四个入口(预览/属性/正文/历史)成一组 */
|
||||
.ft-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
padding: 4px 9px;
|
||||
color: var(--ink);
|
||||
@@ -366,10 +361,4 @@ const togglePermission = computed(() =>
|
||||
background: var(--brand-d);
|
||||
border-color: var(--brand-d);
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.ft-spacer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user