feat(view): JSON 折叠交互——chevron、行尾摘要、滚动补偿与折叠全部

- json-text-view:投影层接线(可视窗口/spacer/行号反查/指针换算/边缘滚动八接入点);折叠事务带 scrollTop 补偿(锚点=视口顶部 model 行号,折叠视口上方块无跳变);选区端点写入前钳制,syncDomSelection 修正坐标混用隐患;props.json 变化重置折叠态;chevron(hover 显/已折叠常显)与行尾摘要 {…} N 行;非 JSON 响应折叠 UI 整体关闭(hasFolds 门控)
- endpoint-panel:meta 行「折叠全部/展开全部」(收 depth=1 顶层块,经 defineExpose 通道)
- 新增 6 个视图层测试(折叠渲染/chevron 交互/选区隔离/补偿无跳变/状态重置/非 JSON 降级)
- 附技术博客 docs/JSON预览器代码折叠技术博客.md
- 全量 89/89 四绿(test/type-check/lint/build)
This commit is contained in:
2026-09-09 14:17:42 +08:00
parent b3ad8a5a8e
commit a77cd71888
4 changed files with 505 additions and 37 deletions
+30 -2
View File
@@ -9,7 +9,7 @@
*/
import { useClipboard } from '@vueuse/core';
import { computed } from 'vue';
import { computed, ref, watch } from 'vue';
import { findEndpointByPath } from '@/api/endpoints';
import { useManualEndpointQuery } from '@/api/endpoint-queries';
@@ -58,6 +58,28 @@ function handleSend(): void {
sendRequest();
}
/* ---------- 折叠全部 / 展开全部(JsonTextView defineExpose 通道) ---------- */
const jsonTextViewRef = ref<InstanceType<typeof JsonTextView> | null>(null);
const foldable = ref(false);
// hasFolds 是 JsonTextView 内部的 computed,经 watch 桥接为面板侧响应式标志
watch(
() => jsonTextViewRef.value?.hasFolds,
(value) => {
foldable.value = value === true;
},
{ immediate: true },
);
function collapseAllFolds(): void {
jsonTextViewRef.value?.collapseAll();
}
function expandAllFolds(): void {
jsonTextViewRef.value?.expandAll();
}
/* ---------- 响应区操作:复制 / 下载 ---------- */
const {
@@ -150,6 +172,12 @@ function downloadResponseAsFile(): void {
{{ responseData.networkError }}
</span>
<span class="meta-spacer"></span>
<t-button v-if="foldable" size="small" variant="outline" @click="collapseAllFolds">
折叠全部
</t-button>
<t-button v-if="foldable" size="small" variant="outline" @click="expandAllFolds">
展开全部
</t-button>
<t-button
v-if="clipboardSupported"
size="small"
@@ -160,7 +188,7 @@ function downloadResponseAsFile(): void {
</t-button>
<t-button size="small" variant="outline" @click="downloadResponseAsFile">下载</t-button>
</div>
<JsonTextView :json="responseData.json" :raw-text="responseData.text" />
<JsonTextView ref="jsonTextViewRef" :json="responseData.json" :raw-text="responseData.text" />
</section>
<section v-else-if="!hasSent" class="panel-section response-placeholder">
{{ requiresKey ? '填写 sk-key 后点击「发送请求」' : '点击「发送请求」查看站点配置' }}