From 23bc712c17554d982f88bee1dfb6202a72daff38 Mon Sep 17 00:00:00 2001 From: minlovehua <321512939@qq.com> Date: Wed, 25 Dec 2024 17:50:30 +0800 Subject: [PATCH 1/2] feat(state): support filter and sort by member, created_by, updated_by --- packages/grid/src/core/types/ai-table.ts | 7 +-- packages/grid/src/core/utils/common.ts | 7 +-- packages/grid/src/grid-base.component.ts | 1 + packages/state/src/utils/field/model/field.ts | 10 ++-- packages/state/src/utils/field/model/index.ts | 7 +-- .../state/src/utils/field/model/member.ts | 51 +++++++++++++++++++ packages/state/src/utils/record/filter.ts | 7 ++- packages/state/src/utils/record/sort.ts | 5 +- .../common/content/content.component.ts | 2 +- 9 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 packages/state/src/utils/field/model/member.ts diff --git a/packages/grid/src/core/types/ai-table.ts b/packages/grid/src/core/types/ai-table.ts index e0bac1f9..c2b1f3fb 100644 --- a/packages/grid/src/core/types/ai-table.ts +++ b/packages/grid/src/core/types/ai-table.ts @@ -1,6 +1,6 @@ import { Signal, WritableSignal } from '@angular/core'; import { Colors } from '../../constants/colors'; -import { AITableSelection } from '../../types'; +import { AITableReferences, AITableSelection } from '../../types'; import { RendererContext } from '../context'; import { AITableField, AITableFields, AITableRecord, AITableRecords } from './core'; @@ -10,10 +10,11 @@ export interface AITable { context?: RendererContext; selection: WritableSignal; matchedCells: WritableSignal; // [`${recordId}-${fieldId}`] - recordsMap: Signal<{ [kay: string]: AITableRecord }>; - fieldsMap: Signal<{ [kay: string]: AITableField }>; + recordsMap: Signal<{ [key: string]: AITableRecord }>; + fieldsMap: Signal<{ [key: string]: AITableField }>; recordsWillHidden: WritableSignal; recordsWillMove: WritableSignal; + references: WritableSignal; } export type AIPlugin = (aiTable: AITable) => AITable; diff --git a/packages/grid/src/core/utils/common.ts b/packages/grid/src/core/utils/common.ts index 5862daee..0a318c3c 100644 --- a/packages/grid/src/core/utils/common.ts +++ b/packages/grid/src/core/utils/common.ts @@ -17,7 +17,7 @@ export function createAITable(records: WritableSignal, fields: W object[item._id] = item; return object; }, - {} as { [kay: string]: AITableRecord } + {} as { [key: string]: AITableRecord } ); }), fieldsMap: computed(() => { @@ -26,11 +26,12 @@ export function createAITable(records: WritableSignal, fields: W object[item._id] = item; return object; }, - {} as { [kay: string]: AITableField } + {} as { [key: string]: AITableField } ); }), recordsWillHidden: signal([]), - recordsWillMove: signal([]) + recordsWillMove: signal([]), + references: signal({ members: {} }) }; return aiTable; } diff --git a/packages/grid/src/grid-base.component.ts b/packages/grid/src/grid-base.component.ts index 6fbdbf80..9e605e93 100644 --- a/packages/grid/src/grid-base.component.ts +++ b/packages/grid/src/grid-base.component.ts @@ -123,6 +123,7 @@ export class AITableGridBase implements OnInit { this.aiTableGridMatchCellService.initialize(this.aiTable); this.aiTableGridEventService.registerEvents(this.elementRef.nativeElement); this.aiTableGridFieldService.initAIFieldConfig(this.aiFieldConfig()); + this.aiTable.references.set(this.aiReferences()); AI_TABLE_GRID_FIELD_SERVICE_MAP.set(this.aiTable, this.aiTableGridFieldService); } diff --git a/packages/state/src/utils/field/model/field.ts b/packages/state/src/utils/field/model/field.ts index fc2e8ce3..2f5632f7 100644 --- a/packages/state/src/utils/field/model/field.ts +++ b/packages/state/src/utils/field/model/field.ts @@ -1,4 +1,4 @@ -import { AITableField, FieldValue } from '@ai-table/grid'; +import { AITableField, AITableReferences, FieldValue } from '@ai-table/grid'; import { AITableFilterCondition, AITableFilterOperation } from '../../../types'; import { isEmpty } from '../../common'; import { isEqual } from 'lodash'; @@ -10,7 +10,7 @@ export abstract class Field { return str.toLowerCase().includes(searchStr.trim().toLowerCase()); } - abstract cellValueToString(cellValue: FieldValue, field: AITableField): string | null; + abstract cellValueToString(cellValue: FieldValue, field: AITableField, references?: AITableReferences): string | null; isMeetFilter(condition: AITableFilterCondition, cellValue: FieldValue) { switch (condition.operation) { @@ -42,7 +42,7 @@ export abstract class Field { return isEqual(cv1, cv2); } - compare(cellValue1: FieldValue, cellValue2: FieldValue, field: AITableField): number { + compare(cellValue1: FieldValue, cellValue2: FieldValue, field: AITableField, references?: AITableReferences): number { if (this.eq(cellValue1, cellValue2)) { return 0; } @@ -53,8 +53,8 @@ export abstract class Field { return 1; } - let str1 = this.cellValueToString(cellValue1, field); - let str2 = this.cellValueToString(cellValue2, field); + let str1 = this.cellValueToString(cellValue1, field, references); + let str2 = this.cellValueToString(cellValue2, field, references); if (str1 === str2) { return 0; diff --git a/packages/state/src/utils/field/model/index.ts b/packages/state/src/utils/field/model/index.ts index deb3ba15..d2f48f41 100644 --- a/packages/state/src/utils/field/model/index.ts +++ b/packages/state/src/utils/field/model/index.ts @@ -6,6 +6,7 @@ import { DateField } from './date'; import { NumberField } from './number'; import { RateField } from './rate'; import { LinkField } from './link'; +import { MemberField } from './member'; export const ViewOperationMap: Record = { [AITableFieldType.text]: new TextField(), @@ -17,8 +18,8 @@ export const ViewOperationMap: Record = { [AITableFieldType.number]: new NumberField(), [AITableFieldType.rate]: new RateField(), [AITableFieldType.link]: new LinkField(), - [AITableFieldType.member]: new SelectField(), + [AITableFieldType.member]: new MemberField(), [AITableFieldType.progress]: new NumberField(), - [AITableFieldType.createdBy]: new SelectField(), - [AITableFieldType.updatedBy]: new SelectField() + [AITableFieldType.createdBy]: new MemberField(), + [AITableFieldType.updatedBy]: new MemberField() }; diff --git a/packages/state/src/utils/field/model/member.ts b/packages/state/src/utils/field/model/member.ts new file mode 100644 index 00000000..a6f79a6b --- /dev/null +++ b/packages/state/src/utils/field/model/member.ts @@ -0,0 +1,51 @@ +import { isEmpty } from '../../common'; +import { AITableFilterCondition, AITableFilterOperation } from '../../../types'; +import { Field } from './field'; +import { AITableField, AITableReferences, MemberFieldValue } from '@ai-table/grid'; + +export class MemberField extends Field { + override isMeetFilter(condition: AITableFilterCondition, cellValue: MemberFieldValue) { + switch (condition.operation) { + case AITableFilterOperation.empty: + return isEmpty(cellValue); + case AITableFilterOperation.exists: + return !isEmpty(cellValue); + case AITableFilterOperation.in: + return Array.isArray(condition.value) && hasIntersect(cellValue, condition.value); + case AITableFilterOperation.nin: + return Array.isArray(condition.value) && !hasIntersect(cellValue, condition.value); + default: + return super.isMeetFilter(condition, cellValue); + } + } + + cellValueToString(cellValue: MemberFieldValue, field: AITableField, references: AITableReferences): string | null { + let memberDisplayNames: string[] = []; + if (cellValue?.length && references) { + for (let index = 0; index < cellValue.length; index++) { + const userInfo = references?.members[cellValue[index]]; + if (!userInfo) { + continue; + } + if (userInfo.display_name) { + memberDisplayNames.push(userInfo.display_name); + } + } + } + return memberDisplayNames && memberDisplayNames.length ? memberDisplayNames.join(', ') : null; + } +} + +function hasIntersect(array1: T[], array2: T[]) { + if (!Array.isArray(array1) || !Array.isArray(array2)) { + return false; + } + const set1 = new Set(array1); + const set2 = new Set(array2); + for (const ele of set1) { + if (set2.has(ele)) { + return true; + } + } + return false; +} diff --git a/packages/state/src/utils/record/filter.ts b/packages/state/src/utils/record/filter.ts index 2dc3aaab..234e0a6f 100644 --- a/packages/state/src/utils/record/filter.ts +++ b/packages/state/src/utils/record/filter.ts @@ -10,6 +10,7 @@ import { AIViewTable } from '../../types'; import { ViewOperationMap } from '../field/model'; +import { isEmpty } from '../common'; export function getFilteredRecords(aiTable: AIViewTable, records: AITableViewRecords, fields: AITableViewFields, activeView: AITableView) { const { conditions, condition_logical } = activeView.settings || {}; @@ -73,7 +74,7 @@ export function getDefaultRecordDataByFilter( return recordValues; } -export function getFilterValue(fields: AITableViewFields, record: AITableRecord, condition: AITableFilterCondition) { +function getFilterValue(fields: AITableViewFields, record: AITableRecord, condition: AITableFilterCondition) { const field = fields.find((item) => item._id === condition.field_id); let cellValue = null; if (field && isSystemField(field)) { @@ -86,6 +87,10 @@ export function getFilterValue(fields: AITableViewFields, record: AITableRecord, cellValue = record.values[condition.field_id]; } + if (field && [AITableFieldType.createdBy, AITableFieldType.updatedBy, AITableFieldType.member].includes(field.type)) { + cellValue = Array.isArray(cellValue) ? cellValue : isEmpty(cellValue) ? [] : [cellValue]; + } + return { field, cellValue diff --git a/packages/state/src/utils/record/sort.ts b/packages/state/src/utils/record/sort.ts index cee5f5cb..4f78f711 100644 --- a/packages/state/src/utils/record/sort.ts +++ b/packages/state/src/utils/record/sort.ts @@ -27,11 +27,12 @@ export function sortRecordsBySortInfo(aiTable: AITable, records: AITableViewReco const cellValue1 = AITableQueries.getFieldValue(aiTable, [prev._id, field._id]); const cellValue2 = AITableQueries.getFieldValue(aiTable, [current._id, field._id]); - const res = fieldMethod.compare(cellValue1, cellValue2, field); + const references = aiTable.references(); + const res = fieldMethod.compare(cellValue1, cellValue2, field, references); return res * rule.direction; }, 0); }); return shallowRows; } return shallowRows; -} \ No newline at end of file +} diff --git a/src/app/component/common/content/content.component.ts b/src/app/component/common/content/content.component.ts index 4798e3ed..eb34d34e 100644 --- a/src/app/component/common/content/content.component.ts +++ b/src/app/component/common/content/content.component.ts @@ -208,7 +208,7 @@ export class DemoTableContent { object[item._id] = item; return object; }, - {} as { [kay: string]: AITableView } + {} as { [key: string]: AITableView } ); }); this.aiTable.onChange = () => { From 4752043b4b0c2dd7fd0b306201c8fc1f3c4d59f7 Mon Sep 17 00:00:00 2001 From: minlovehua <321512939@qq.com> Date: Wed, 25 Dec 2024 18:46:36 +0800 Subject: [PATCH 2/2] feat(state): support filter and sort by member, created_by, updated_by --- packages/grid/src/types/grid.ts | 1 + packages/state/src/utils/field/model/member.ts | 8 ++++---- src/app/utils/utils.ts | 10 +++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/grid/src/types/grid.ts b/packages/grid/src/types/grid.ts index d110e6a1..676a0fee 100644 --- a/packages/grid/src/types/grid.ts +++ b/packages/grid/src/types/grid.ts @@ -30,6 +30,7 @@ export interface AIFieldConfig { export interface AITableUserInfo { uid?: string; display_name?: string; + name?: string; avatar?: string; } diff --git a/packages/state/src/utils/field/model/member.ts b/packages/state/src/utils/field/model/member.ts index a6f79a6b..855fd8e0 100644 --- a/packages/state/src/utils/field/model/member.ts +++ b/packages/state/src/utils/field/model/member.ts @@ -20,19 +20,19 @@ export class MemberField extends Field { } cellValueToString(cellValue: MemberFieldValue, field: AITableField, references: AITableReferences): string | null { - let memberDisplayNames: string[] = []; + let names: string[] = []; if (cellValue?.length && references) { for (let index = 0; index < cellValue.length; index++) { const userInfo = references?.members[cellValue[index]]; if (!userInfo) { continue; } - if (userInfo.display_name) { - memberDisplayNames.push(userInfo.display_name); + if (userInfo.name) { + names.push(userInfo.name); } } } - return memberDisplayNames && memberDisplayNames.length ? memberDisplayNames.join(', ') : null; + return names && names.length ? names.join(', ') : null; } } diff --git a/src/app/utils/utils.ts b/src/app/utils/utils.ts index 5b5fcc73..8d97826c 100644 --- a/src/app/utils/utils.ts +++ b/src/app/utils/utils.ts @@ -1017,41 +1017,49 @@ export function getReferences(): AITableReferences { member_01: { uid: 'member_01', display_name: 'admin', + name: 'admin', avatar: 'https://web.on-premises-alpha.pingcode.live/pc-avatar/c04446a4-bfcc-4a05-846c-e3241e1b68df_80x80.png' }, member_02: { uid: 'member_02', display_name: 'member', + name: 'member', avatar: '' }, member_03: { uid: 'member_03', display_name: 'Maple13', + name: 'Maple13', avatar: '' }, member_04: { uid: 'member_04', display_name: 'canvas', + name: 'canvas', avatar: '' }, member_05: { uid: 'member_05', - display_name: 'svg', + display_name: '虾米', + name: 'xiami', avatar: '' }, member_06: { uid: 'member_06', display_name: 'html', + name: 'html', avatar: '' }, member_07: { uid: 'member_07', display_name: 'css', + name: 'css', avatar: '' }, member_08: { uid: 'member_08', display_name: 'Angular', + name: 'Angular', avatar: '' } }