feat(layout): tabs 纯导航 + 面板外置,响应区固定分区滚动

参照 t-design-starter 与 Naive UI display-directive=show 语义:t-tabs 只当导航条(list 不传 panel),EndpointPanel 渲染在外置自有容器,v-show 常驻切换(面板不销毁,sk-key/滚动位置/局部状态全保留);删除两条 :deep 穿透,仅留一条收敛规则隐藏空 panel 壳;响应区 overflow:hidden + min-height 220px 固定分区,滚动收敛到 JsonTextView 自身;新增 request-tabs 4 用例锁死显隐/不销毁语义。
This commit is contained in:
2026-09-08 10:48:22 +08:00
parent c021294322
commit d4fe766373
3 changed files with 182 additions and 49 deletions
+18 -14
View File
@@ -1,11 +1,7 @@
/**
* 单接口完整面板:信息行 → 注意事项折叠 → sk-key 输入 + 发送按钮 → 响应区
*
* sk-key 存在 bench-store(每 tab 独立、无持久化、随刷新重置):
* 2026-09 起从组件局部 ref 提升——EndpointPanel 随 tab 切换卸载重建,
* 局部 ref 会在切回时丢输入;store 持有则切 tab 保留(数据仍由 Query 缓存兜底)
* 响应区:元信息行(状态/耗时/大小)+ 操作(复制/下载)+ 虚拟滚动 JSON 视图
*/
/** * 单接口完整面板:信息行 → 注意事项折叠 → sk-key 输入 + 发送按钮 → 响应区 * * sk-key 存在
bench-store(每 tab 独立、无持久化、随刷新重置): * 2026-09 起从组件局部 ref 提升——EndpointPanel 随
tab 切换卸载重建, * 局部 ref 会在切回时丢输入;store 持有则切 tab 保留(数据仍由 Query 缓存兜底) *
响应区:元信息行(状态/耗时/大小)+ 操作(复制/下载)+ 虚拟滚动 JSON 视图 */
<script setup lang="ts">
import { useClipboard } from '@vueuse/core';
@@ -37,10 +33,12 @@ const skKeyInput = computed({
/* ---------- 手动请求(TanStack Query) ---------- */
const endpointPathRef = computed(() => props.endpointPath);
const { data: responseData, isFetching, hasSent, sendRequest } = useManualEndpointQuery(
endpointPathRef,
skKeyInput,
);
const {
data: responseData,
isFetching,
hasSent,
sendRequest,
} = useManualEndpointQuery(endpointPathRef, skKeyInput);
const keyInputStatus = computed(() =>
hasSent.value && !skKeyInput.value.trim() ? 'error' : 'default',
@@ -53,7 +51,11 @@ function handleSend(): void {
/* ---------- 响应区操作:复制 / 下载 ---------- */
const { copy: copyResponseToClipboard, copied, isSupported: clipboardSupported } = useClipboard({
const {
copy: copyResponseToClipboard,
copied,
isSupported: clipboardSupported,
} = useClipboard({
source: () => responseData.value?.text ?? '',
legacy: true, // 非 https 环境降级 execCommand
});
@@ -182,9 +184,10 @@ function downloadResponseAsFile(): void {
.response-section {
flex: 1;
min-height: 0;
min-height: 220px; /* 响应区保底高度:窄窗口下不被上部固定分区压缩到不可用 */
display: flex;
flex-direction: column;
overflow: hidden; /* 分区固定:滚动收敛到 JsonTextView 自身 */
}
.response-meta {
@@ -192,6 +195,7 @@ function downloadResponseAsFile(): void {
gap: 14px;
align-items: center;
margin-bottom: 10px;
flex-shrink: 0; /* 元信息行固定:不随响应区压缩 */
font-size: 12.5px;
color: var(--td-text-color-secondary);
font-family: var(--td-font-family-mono, monospace);