diff --git a/app/src/protyle/render/av/col.ts b/app/src/protyle/render/av/col.ts index ba92529e4..028324cf8 100644 --- a/app/src/protyle/render/av/col.ts +++ b/app/src/protyle/render/av/col.ts @@ -654,23 +654,16 @@ export const showColMenu = (protyle: IProtyle, blockElement: Element, cellElemen filter = { column: colId, operator: getDefaultOperatorByType(type), - value: genCellValue(type, "") + value: genCellValue(type, ""), + type, }; avData.view.filters.push(filter); - transaction(protyle, [{ - action: "setAttrViewFilters", - avID, - data: [filter] - }], [{ - action: "setAttrViewFilters", - avID, - data: [] - }]); } setFilter({ filter, protyle, data: avData, + blockElement: blockElement, target: blockElement.querySelector(`.av__row--header .av__cell[data-col-id="${colId}"]`), }); }); diff --git a/app/src/protyle/render/av/filter.ts b/app/src/protyle/render/av/filter.ts index 795dbfc17..5e508a9cc 100644 --- a/app/src/protyle/render/av/filter.ts +++ b/app/src/protyle/render/av/filter.ts @@ -7,6 +7,8 @@ import {objEquals} from "../../../util/functions"; import {genCellValue} from "./cell"; import * as dayjs from "dayjs"; import {unicode2Emoji} from "../../../emoji"; +import {openMenuPanel} from "./openMenuPanel"; +import {fetchSyncPost} from "../../../util/fetch"; export const getDefaultOperatorByType = (type: TAVCol) => { if (["select", "number"].includes(type)) { @@ -50,11 +52,12 @@ const toggleEmpty = (element: HTMLElement, operator: string, type: TAVCol) => { } }; -export const setFilter = (options: { +export const setFilter = async (options: { filter: IAVFilter, protyle: IProtyle, data: IAV, target: HTMLElement, + blockElement: Element }) => { let rectTarget = options.target.getBoundingClientRect(); if (rectTarget.height === 0) { @@ -66,8 +69,8 @@ export const setFilter = (options: { let hasMatch = false; let cellValue: IAVCellValue; if (textElements.length > 0) { - if (["date", "updated", "created"].includes(colData.type)) { - cellValue = genCellValue(colData.type, { + if (["date", "updated", "created"].includes(filterType)) { + cellValue = genCellValue(filterType, { isNotEmpty2: textElements[1].value !== "", isNotEmpty: textElements[0].value !== "", content: new Date(textElements[0].value + " 00:00").getTime(), @@ -75,9 +78,9 @@ export const setFilter = (options: { hasEndDate: operator === "Is between" }); } else { - cellValue = genCellValue(colData.type, textElements[0].value); + cellValue = genCellValue(filterType, textElements[0].value); } - } else { + } else if (filterType === "select" || filterType === "mSelect") { const mSelect: { color: string, content: string @@ -94,14 +97,15 @@ export const setFilter = (options: { if (mSelect.length === 0) { mSelect.push({color: "", content: ""}); } - cellValue = genCellValue(colData.type, mSelect); + cellValue = genCellValue(filterType, mSelect); + } else { + cellValue = genCellValue(filterType, undefined); } const newFilter: IAVFilter = { column: options.filter.column, value: cellValue, operator }; - let isSame = false; options.data.view.filters.find((filter, index) => { if (filter.column === options.filter.column) { @@ -142,7 +146,41 @@ export const setFilter = (options: { return true; } }); - switch (colData.type) { + let filterType = colData.type; + if (filterType === "rollup") { + if (!colData.rollup.relationKeyID || !colData.rollup.keyID) { + openMenuPanel({ + protyle: options.protyle, + blockElement: options.blockElement, + type: "edit", + colId: colData.id + }); + return; + } + let targetAVId = "" + options.data.view.columns.find((column) => { + if (column.id === colData.rollup.relationKeyID) { + targetAVId = column.relation.avID + return true; + } + }); + const response = await fetchSyncPost("/api/av/getAttributeView", {id: targetAVId}); + response.data.av.keyValues.find((item: { key: { id: string, name: string, type: TAVCol } }) => { + if (item.key.id === colData.rollup.keyID) { + filterType = item.key.type; + return true; + } + }); + options.data.view.filters.find(item => { + if (item.column === colData.id && item.type) { + item.operator = getDefaultOperatorByType(filterType); + item.value = genCellValue(filterType, ""); + delete item.type + return true; + } + }) + } + switch (filterType) { case "checkbox": selectHTML = ` `; @@ -215,7 +253,7 @@ export const setFilter = (options: { iconHTML: "", label: `` }); - if (colData.type === "select" || colData.type === "mSelect") { + if (filterType === "select" || filterType === "mSelect") { colData.options?.forEach((option) => { let icon = "iconUncheck"; options.filter.value?.mSelect.find((optionItem) => { @@ -240,29 +278,29 @@ export const setFilter = (options: { } }); }); - } else if (["text", "url", "block", "email", "phone", "template", "relation"].includes(colData.type)) { + } else if (["text", "url", "block", "email", "phone", "template", "relation"].includes(filterType)) { let value = ""; if (options.filter.value) { - if (colData.type === "relation") { + if (filterType === "relation") { value = options.filter.value.relation.contents[0] || ""; } else { - value = options.filter.value[colData.type as "text"].content || ""; + value = options.filter.value[filterType as "text"].content || ""; } } menu.addItem({ iconHTML: "", label: `` }); - } else if (colData.type === "number") { + } else if (filterType === "number") { menu.addItem({ iconHTML: "", label: `` }); - } else if (["date", "updated", "created"].includes(colData.type)) { - const dateValue = options.filter.value ? options.filter.value[colData.type as "date"] : null; + } else if (["date", "updated", "created"].includes(filterType)) { + const dateValue = options.filter.value ? options.filter.value[filterType as "date"] : null; menu.addItem({ iconHTML: "", - label: `` + label: `` }); menu.addItem({ iconHTML: "", @@ -297,7 +335,7 @@ export const setFilter = (options: { }); const selectElement = (window.siyuan.menus.menu.element.querySelector(".b3-select") as HTMLSelectElement); selectElement.addEventListener("change", () => { - toggleEmpty(selectElement, selectElement.value, colData.type); + toggleEmpty(selectElement, selectElement.value, filterType); }); const textElements: NodeListOf = window.siyuan.menus.menu.element.querySelectorAll(".b3-text-field"); textElements.forEach(item => { @@ -312,7 +350,7 @@ export const setFilter = (options: { } }); }); - toggleEmpty(selectElement, selectElement.value, colData.type); + toggleEmpty(selectElement, selectElement.value, filterType); menu.open({x: rectTarget.left, y: rectTarget.bottom}); if (textElements.length > 0) { textElements[0].select(); @@ -326,6 +364,7 @@ export const addFilter = (options: { tabRect: DOMRect, avId: string, protyle: IProtyle + blockElement: Element }) => { const menu = new Menu("av-add-filter"); options.data.view.columns.forEach((column) => { @@ -341,22 +380,13 @@ export const addFilter = (options: { label: column.name, iconHTML: column.icon ? unicode2Emoji(column.icon, "b3-menu__icon", true) : ``, click: () => { - const oldFilters = Object.assign([], options.data.view.filters); const cellValue = genCellValue(column.type, ""); options.data.view.filters.push({ column: column.id, operator: getDefaultOperatorByType(column.type), value: cellValue, + type: column.type }); - transaction(options.protyle, [{ - action: "setAttrViewFilters", - avID: options.data.id, - data: options.data.view.filters - }], [{ - action: "setAttrViewFilters", - avID: options.data.id, - data: oldFilters - }]); options.menuElement.innerHTML = getFiltersHTML(options.data.view); setPosition(options.menuElement, options.tabRect.right - options.menuElement.clientWidth, options.tabRect.bottom, options.tabRect.height); const filterElement = options.menuElement.querySelector(`[data-id="${column.id}"] .b3-chip`) as HTMLElement; @@ -368,7 +398,8 @@ export const addFilter = (options: { }, protyle: options.protyle, data: options.data, - target: filterElement + target: filterElement, + blockElement: options.blockElement }); } }); @@ -430,7 +461,7 @@ export const getFiltersHTML = (data: IAVTable) => { filterValue = ` ≤ ${filter.value.number.content}`; } } else if (filter.value?.text?.content || filter.value?.block?.content || filter.value?.url?.content || - filter.value?.phone?.content || filter.value?.email?.content || filter.value?.relation?.contents.length>0) { + filter.value?.phone?.content || filter.value?.email?.content || filter.value?.relation?.contents.length > 0) { const content = filter.value?.text?.content || filter.value?.block?.content || filter.value?.url?.content || filter.value?.phone?.content || filter.value?.email?.content || filter.value?.relation?.contents[0]; diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts index 517672430..10324e8f0 100644 --- a/app/src/protyle/render/av/openMenuPanel.ts +++ b/app/src/protyle/render/av/openMenuPanel.ts @@ -517,7 +517,8 @@ export const openMenuPanel = (options: { menuElement, tabRect, avId: avID, - protyle: options.protyle + protyle: options.protyle, + blockElement: options.blockElement }); event.preventDefault(); event.stopPropagation(); @@ -552,7 +553,8 @@ export const openMenuPanel = (options: { filter: item, protyle: options.protyle, data, - target + target, + blockElement: options.blockElement }); return true; } diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index d391e1f6c..1ab99bb2a 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -1063,7 +1063,8 @@ interface IAVTable extends IAVView { interface IAVFilter { column: string, operator: TAVFilterOperator, - value: IAVCellValue + value: IAVCellValue, + type?: TAVCol // 仅用于标识新增时的类型,用于区分 rollup } interface IAVSort {