Skip to content

Commit 983d7ac

Browse files
committed
Merge remote-tracking branch 'origin/dev' into dev
2 parents 5aedda8 + df69dd1 commit 983d7ac

8 files changed

Lines changed: 132 additions & 118 deletions

File tree

app/src/assets/scss/business/_av.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,11 @@
10121012
margin-left: 4px;
10131013
}
10141014

1015+
// “添加筛选条件”按钮:label 按内容宽度,使下拉箭头紧跟文案而非被推到最右
1016+
.av__filter-add-label {
1017+
flex: none;
1018+
}
1019+
10151020
&__item[data-type="nobg"] {
10161021
cursor: auto;
10171022
}

app/src/block/popover.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {BlockPanel} from "./Panel";
22
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName,} from "../protyle/util/hasClosest";
33
import {fetchPost, fetchSyncPost} from "../util/fetch";
4-
import {hideTooltip, showTooltip} from "../dialog/tooltip";
4+
import {hideTooltip, showTooltip, tooltipTargetElement} from "../dialog/tooltip";
55
import {getIdFromSYProtocol, isLocalPath} from "../util/pathName";
66
import {App} from "../index";
77
import {Constants} from "../constants";
@@ -213,9 +213,11 @@ export const initBlockPopover = (app: App) => {
213213
const tipElement = hasClosestByAttribute(event.target, "id", "tooltip", true);
214214
if (!tipElement) {
215215
hideTooltip();
216+
} else if (tooltipTargetElement && !tooltipTargetElement.contains(event.target)) {
217+
// 鼠标在 #tooltip 上但已离开触发元素范围,正常隐藏
218+
// 仍在触发元素范围内时不隐藏,避免 showTooltip ↔ hideTooltip 循环闪烁
219+
hideTooltip();
216220
}
217-
// 鼠标仍在 #tooltip 上时不主动隐藏,避免 showTooltip ↔ hideTooltip 循环闪烁;
218-
// 待鼠标移到非 tooltip 处再由上面的分支隐藏
219221
}
220222
if (window.siyuan.config.editor.floatWindowMode === 1 || window.siyuan.shiftIsPressed) {
221223
clearTimeout(timeoutHide);

app/src/dialog/tooltip.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import {isMobile} from "../util/functions";
22

3+
// 记录当前 tooltip 对应的触发元素,便于判断鼠标是否已离开触发区域
4+
export let tooltipTargetElement: Element | null = null;
5+
36
export const showTooltip = (
47
message: string,
58
target: Element,
@@ -10,6 +13,7 @@ export const showTooltip = (
1013
if (isMobile() || !message) {
1114
return;
1215
}
16+
tooltipTargetElement = target;
1317
let targetRect = target.getBoundingClientRect();
1418
// 跨行元素
1519
const clientRects = Array.from(target.getClientRects());
@@ -128,5 +132,6 @@ export const showTooltip = (
128132
};
129133

130134
export const hideTooltip = () => {
135+
tooltipTargetElement = null;
131136
document.getElementById("tooltip").classList.add("fn__none");
132137
};

app/src/protyle/render/av/col.ts

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -847,42 +847,26 @@ export const showColMenu = (protyle: IProtyle, blockElement: Element, cellElemen
847847
id: avID,
848848
}, (response) => {
849849
const avData = response.data as IAV;
850-
let filter: IAVFilter;
851-
// 递归在过滤树中查找该列已存在的叶子
852-
const findFilter = (nodes: IAVFilter[]): IAVFilter => {
853-
for (const n of nodes) {
854-
if (n.filters) {
855-
const found = findFilter(n.filters);
856-
if (found) return found;
857-
} else if (n.column === colId && n.value.type === type) {
858-
return n;
859-
}
860-
}
861-
return undefined;
850+
// 始终新建一个占位条件(允许同列多条件,支持“主键包含111 OR 主键包含222”等组合)
851+
const filter: IAVFilter = {
852+
column: colId,
853+
operator: getDefaultOperatorByType(type),
854+
value: genCellValue(type, ""),
862855
};
863-
filter = findFilter(getEditableFilters(avData));
864-
if (!filter) {
865-
// 新建占位条件并保存,随后打开筛选面板 inline 编辑
866-
filter = {
867-
column: colId,
868-
operator: getDefaultOperatorByType(type),
869-
value: genCellValue(type, ""),
870-
};
871-
// 深拷贝旧值用于 undo,撤销时恢复完整筛选状态而非清空全部
872-
const oldFilters = JSON.parse(JSON.stringify(avData.view.filters));
873-
getEditableFilters(avData).push(filter);
874-
transaction(protyle, [{
875-
action: "setAttrViewFilters",
876-
avID,
877-
data: avData.view.filters,
878-
blockID: blockElement.getAttribute("data-node-id")
879-
}], [{
880-
action: "setAttrViewFilters",
881-
avID,
882-
data: oldFilters,
883-
blockID: blockElement.getAttribute("data-node-id")
884-
}]);
885-
}
856+
// 深拷贝旧值用于 undo,撤销时恢复完整筛选状态而非清空全部
857+
const oldFilters = JSON.parse(JSON.stringify(avData.view.filters));
858+
getEditableFilters(avData).push(filter);
859+
transaction(protyle, [{
860+
action: "setAttrViewFilters",
861+
avID,
862+
data: avData.view.filters,
863+
blockID: blockElement.getAttribute("data-node-id")
864+
}], [{
865+
action: "setAttrViewFilters",
866+
avID,
867+
data: oldFilters,
868+
blockID: blockElement.getAttribute("data-node-id")
869+
}]);
886870
// 打开筛选面板,用户在内联控件中编辑(替代原 setFilter 弹层)
887871
openMenuPanel({
888872
protyle,

app/src/protyle/render/av/filter.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,17 @@ export const addFilter = (options: {
150150
parentPath?: string
151151
}) => {
152152
const menu = new Menu(Constants.MENU_AV_ADD_FILTER);
153-
// 仅在目标分组内查重:同一分组内不重复添加同列叶子,但不同分组允许同列(嵌套的核心价值,如 状态=完成 OR 状态=进行中)
153+
// 定位目标分组:支持向指定分组内追加,同分组允许同列多条件(如 状态=完成 OR 状态=进行中)
154154
let targetGroupFilters: IAVFilter[];
155155
if (options.parentPath && options.parentPath !== "") {
156156
const node = getFilterByPath(getRootFilters(options.data), options.parentPath);
157157
targetGroupFilters = node && node.filters ? node.filters : getEditableFilters(options.data);
158158
} else {
159159
targetGroupFilters = getEditableFilters(options.data);
160160
}
161-
const usedColumns = new Set<string>();
162-
targetGroupFilters.forEach(n => {
163-
if (!n.filters && n.column) {
164-
usedColumns.add(n.column);
165-
}
166-
});
167161
getFieldsByData(options.data).forEach((column) => {
168-
// 该列是行号类型列,或目标分组内已有该列叶子,则不重复添加
169-
if (column.type !== "lineNumber" && !usedColumns.has(column.id)) {
162+
// 行号类型列不可筛选
163+
if (column.type !== "lineNumber") {
170164
menu.addItem({
171165
label: column.name,
172166
iconHTML: column.icon ? unicode2Emoji(column.icon, "b3-menu__icon", true) : `<svg class="b3-menu__icon"><use xlink:href="#${getColIconByType(column.type)}"></use></svg>`,
@@ -308,7 +302,7 @@ export const getFiltersHTML = (data: IAV) => {
308302
${html}
309303
<button class="b3-menu__item" data-type="addFilterCondition" data-path="" data-depth="0">
310304
<svg class="b3-menu__icon"><use xlink:href="#iconAdd"></use></svg>
311-
<span class="b3-menu__label fn__flex-shrink">${window.siyuan.languages.addFilterCondition}</span>
305+
<span class="b3-menu__label av__filter-add-label">${window.siyuan.languages.addFilterCondition}</span>
312306
<svg class="av__filter-arrow"><use xlink:href="#iconDown"></use></svg>
313307
</button>
314308
<button class="b3-menu__item b3-menu__item--warning${leafCount > 0 ? "" : " fn__none"}" data-type="removeFilters">

app/src/protyle/render/av/openMenuPanel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ export const openMenuPanel = (options: {
484484
data: JSON.parse(JSON.stringify(data.view.filters)),
485485
blockID
486486
}]);
487-
data.view.filters = [];
487+
// 本地状态保持“顶层单个空根组”不变量(后端会同样归一化),避免后续 addFilterGroup 误把新分组当成根组
488+
data.view.filters = [{combination: "and", filters: []}];
488489
menuElement.innerHTML = getFiltersHTML(data);
489490
setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height);
490491
window.siyuan.menus.menu.remove();

0 commit comments

Comments
 (0)