From e4a44ec48910341edd4e74ac05fbc113d3addf10 Mon Sep 17 00:00:00 2001 From: huanhuanwa <2323666215@qq.com> Date: Mon, 5 Aug 2024 11:42:51 +0800 Subject: [PATCH] fix: adjust code --- src/app/app.routes.ts | 22 ++--- src/app/component/basic/basic.component.html | 9 -- src/app/component/basic/basic.component.ts | 35 -------- .../basic/table/table.component.html | 16 ---- .../component/basic/table/table.component.ts | 15 ---- .../content/content.component.html} | 1 - .../content.component.ts} | 87 +++++++++---------- .../component/share/table/table.component.ts | 69 --------------- ...re.component.html => table.component.html} | 0 .../share.component.ts => table.component.ts} | 24 ++--- src/app/service/table.service.ts | 50 +++++------ src/app/share/shared.ts | 33 ++----- src/app/share/utils/translate-to-table.ts | 21 ++--- src/app/utils/utils.ts | 6 +- 14 files changed, 96 insertions(+), 292 deletions(-) delete mode 100644 src/app/component/basic/basic.component.html delete mode 100644 src/app/component/basic/basic.component.ts delete mode 100644 src/app/component/basic/table/table.component.html delete mode 100644 src/app/component/basic/table/table.component.ts rename src/app/component/{share/table/table.component.html => common/content/content.component.html} (99%) rename src/app/component/common/{table.component.ts => content/content.component.ts} (71%) delete mode 100644 src/app/component/share/table/table.component.ts rename src/app/component/{share/share.component.html => table.component.html} (100%) rename src/app/component/{share/share.component.ts => table.component.ts} (62%) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 6531edda..81bcb6c6 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,29 +1,17 @@ import { Routes } from '@angular/router'; -import { BasicComponent } from './component/basic/basic.component'; -import { ShareComponent } from './component/share/share.component'; -import { TableComponent } from './component/basic/table/table.component'; -import { ShareTableComponent } from './component/share/table/table.component'; +import { DemoTableContent } from './component/common/content/content.component'; +import { DemoTable } from './component/table.component'; export const routes: Routes = [ - { - path: 'share', - component: ShareComponent, - children:[ - { - path: ':viewId', - component: ShareTableComponent, - } - ] - }, { path: '', - component: BasicComponent, + component: DemoTable, children:[ { path: ':viewId', - component: TableComponent, + component: DemoTableContent, } ] - }, + } ]; diff --git a/src/app/component/basic/basic.component.html b/src/app/component/basic/basic.component.html deleted file mode 100644 index 51c98079..00000000 --- a/src/app/component/basic/basic.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - @for (item of tableService.views(); track $index) { - - @if (item.isActive) { - - } - - } - diff --git a/src/app/component/basic/basic.component.ts b/src/app/component/basic/basic.component.ts deleted file mode 100644 index b498d386..00000000 --- a/src/app/component/basic/basic.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { Router, RouterOutlet } from '@angular/router'; -import { AITableGrid } from '@ai-table/grid'; -import { ThyAction } from 'ngx-tethys/action'; -import { ThyTabs, ThyTab } from 'ngx-tethys/tabs'; -import { ThyPopoverModule } from 'ngx-tethys/popover'; -import { TableService } from '../../service/table.service'; - -const initViews = [ - { id: 'view1', name: '表格视图1', isActive: true }, - { id: 'view2', name: '表格视图2' } -]; - -@Component({ - selector: 'ai-table-basic', - standalone: true, - imports: [RouterOutlet, AITableGrid, ThyAction, ThyTabs, ThyTab, ThyPopoverModule], - templateUrl: './basic.component.html', - providers: [TableService] -}) -export class BasicComponent implements OnInit { - router = inject(Router); - - tableService = inject(TableService); - - ngOnInit(): void { - this.tableService.initViews(initViews); - this.router.navigate(['/view1']); - } - - activeTabChange(data: any) { - this.tableService.updateActiveView(data); - this.router.navigateByUrl(`/${this.tableService.activeView().id}`); - } -} diff --git a/src/app/component/basic/table/table.component.html b/src/app/component/basic/table/table.component.html deleted file mode 100644 index 90691847..00000000 --- a/src/app/component/basic/table/table.component.html +++ /dev/null @@ -1,16 +0,0 @@ -@if (tableService.activeView()) { -
- 删除行 - 移动选中行到第三行 - 移动选中列到第三列 -
- - -} \ No newline at end of file diff --git a/src/app/component/basic/table/table.component.ts b/src/app/component/basic/table/table.component.ts deleted file mode 100644 index 7f3b232d..00000000 --- a/src/app/component/basic/table/table.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AITableGrid } from '@ai-table/grid'; -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; -import { ThyAction } from 'ngx-tethys/action'; -import { ThyPopoverModule } from 'ngx-tethys/popover'; -import { CommonTableComponent } from '../../common/table.component'; -import { FieldPropertyEditor } from '../../common/field-property-editor/field-property-editor.component'; - -@Component({ - selector: 'ai-table-demo', - standalone: true, - imports: [RouterOutlet, CommonTableComponent, AITableGrid, ThyPopoverModule, FieldPropertyEditor, ThyAction], - templateUrl: './table.component.html' -}) -export class TableComponent extends CommonTableComponent {} diff --git a/src/app/component/share/table/table.component.html b/src/app/component/common/content/content.component.html similarity index 99% rename from src/app/component/share/table/table.component.html rename to src/app/component/common/content/content.component.html index bb75d8fa..2daae67d 100644 --- a/src/app/component/share/table/table.component.html +++ b/src/app/component/common/content/content.component.html @@ -4,7 +4,6 @@ 移动选中行到第三行 移动选中列到第三列 - ; - - fields!: WritableSignal; - +export class DemoTableContent { aiTable!: AITable; plugins = [withCustomApply]; @@ -86,10 +84,14 @@ export class CommonTableComponent implements OnInit, AfterViewInit { } ngOnInit(): void { - const value = getDefaultValue(); - const { records, fields } = getSortFieldsAndRecordsByPositions(value.records, value.fields, this.tableService.activeView().id); - this.records = signal(records); - this.fields = signal(fields); + if (this.tableService.sharedType) { + this.tableService.buildRenderRecords(); + this.tableService.buildRenderFields(); + } else { + const value = getDefaultValue(); + this.tableService.buildRenderRecords(value.records); + this.tableService.buildRenderFields(value.fields); + } console.time('render'); } @@ -102,7 +104,14 @@ export class CommonTableComponent implements OnInit, AfterViewInit { } onChange(data: AITableChangeOptions) { - this.setPositions(data.actions); + // TODO:获取当前的 view 和 path,转换为 sharedType 中原数据的 path + if (this.tableService.sharedType) { + if (!YjsAITable.isRemote(this.aiTable) && !YjsAITable.isUndo(this.aiTable)) { + YjsAITable.asLocal(this.aiTable, () => { + applyActionOps(this.tableService.sharedType!, data.actions, this.aiTable); + }); + } + } } prevent(event: Event) { @@ -113,17 +122,7 @@ export class CommonTableComponent implements OnInit, AfterViewInit { aiTableInitialized(aiTable: AITable) { this.aiTable = aiTable; (this.aiTable as AIViewTable).views = this.tableService.views; - } - - setPositions(actions: AITableAction[]) { - if (actions.some((item) => UpdateRecordTypes.includes(item.type))) { - const records = setActiveViewPositions(this.records(), this.tableService.activeView().id) as DemoAIRecord[]; - this.records.set(records); - } - if (actions.some((item) => UpdateFieldTypes.includes(item.type))) { - const fields = setActiveViewPositions(this.fields(), this.tableService.activeView().id) as DemoAIField[]; - this.fields.set(fields); - } + this.tableService.setAITable(aiTable); } removeRecord() { diff --git a/src/app/component/share/table/table.component.ts b/src/app/component/share/table/table.component.ts deleted file mode 100644 index b784b45f..00000000 --- a/src/app/component/share/table/table.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { AITable, AITableAction, AITableChangeOptions, AITableGrid } from '@ai-table/grid'; -import { Component, inject } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; -import { ThyAction } from 'ngx-tethys/action'; -import { ThyPopoverModule } from 'ngx-tethys/popover'; -import { CommonTableComponent } from '../../common/table.component'; -import { FieldPropertyEditor } from '../../common/field-property-editor/field-property-editor.component'; -import applyActionOps from '../../../share/apply-to-yjs'; -import { YjsAITable } from '../../../share/yjs-table'; -import { FormsModule } from '@angular/forms'; -import { ThyInputDirective } from 'ngx-tethys/input'; -import { setActiveViewPositions } from '../../../utils/utils'; -import { DemoAIField, DemoAIRecord, UpdateFieldTypes, UpdateRecordTypes } from '../../../types'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { TableService } from '../../../service/table.service'; - -@Component({ - selector: 'ai-share-table-demo', - standalone: true, - imports: [ - RouterOutlet, - CommonTableComponent, - AITableGrid, - ThyPopoverModule, - FieldPropertyEditor, - ThyAction, - FormsModule, - ThyInputDirective - ], - templateUrl: './table.component.html' -}) -export class ShareTableComponent extends CommonTableComponent { - takeUntilDestroyed = takeUntilDestroyed(); - - override ngOnInit(): void { - this.tableService.activeViewChange$.pipe(this.takeUntilDestroyed).subscribe(() => { - this.tableService.setRecords(); - this.tableService.setFields(); - }); - console.time('render'); - } - - override aiTableInitialized(aiTable: AITable) { - super.aiTableInitialized(aiTable); - this.tableService.setAITable(aiTable); - } - - override setPositions(actions: AITableAction[]) { - if (actions.some((item) => UpdateRecordTypes.includes(item.type))) { - const records = setActiveViewPositions(this.tableService.records(), this.tableService.activeView().id) as DemoAIRecord[]; - this.tableService.setRecords(records); - } - if (actions.some((item) => UpdateFieldTypes.includes(item.type))) { - const fields = setActiveViewPositions(this.tableService.fields(), this.tableService.activeView().id) as DemoAIField[]; - this.tableService.setFields(fields); - } - } - - override onChange(data: AITableChangeOptions) { - this.setPositions(data.actions); - if (this.tableService.sharedType) { - if (!YjsAITable.isRemote(this.aiTable) && !YjsAITable.isUndo(this.aiTable)) { - YjsAITable.asLocal(this.aiTable, () => { - applyActionOps(this.tableService.sharedType!, data.actions, this.aiTable); - }); - } - } - } -} diff --git a/src/app/component/share/share.component.html b/src/app/component/table.component.html similarity index 100% rename from src/app/component/share/share.component.html rename to src/app/component/table.component.html diff --git a/src/app/component/share/share.component.ts b/src/app/component/table.component.ts similarity index 62% rename from src/app/component/share/share.component.ts rename to src/app/component/table.component.ts index 1085f3da..30734dff 100644 --- a/src/app/component/share/share.component.ts +++ b/src/app/component/table.component.ts @@ -6,10 +6,8 @@ import { AITableGrid } from '@ai-table/grid'; import { FormsModule } from '@angular/forms'; import { ThyPopoverModule } from 'ngx-tethys/popover'; import { ThyTabs, ThyTab } from 'ngx-tethys/tabs'; -import { DemoAIRecord, DemoAIField } from '../../types'; import { ThyInputDirective } from 'ngx-tethys/input'; -import { getDefaultValue } from '../../utils/utils'; -import { TableService } from '../../service/table.service'; +import { TableService } from '../service/table.service'; const initViews = [ { id: 'view1', name: '表格视图1', isActive: true }, @@ -17,35 +15,29 @@ const initViews = [ ]; @Component({ - selector: 'ai-table-share', + selector: 'demo-ai-table', standalone: true, imports: [RouterOutlet, AITableGrid, ThyAction, ThyTabs, ThyTab, ThyPopoverModule, FormsModule, ThyInputDirective], - templateUrl: './share.component.html', + templateUrl: './table.component.html', providers: [TableService] }) -export class ShareComponent implements OnInit, OnDestroy { +export class DemoTable implements OnInit, OnDestroy { provider!: WebsocketProvider | null; - room = 'share-room-1'; - - records!: WritableSignal; - - fields!: WritableSignal; + room = 'share-room-2'; router = inject(Router); tableService = inject(TableService); ngOnInit(): void { - this.router.navigate(['/share/view1']); - this.tableService.initViews(initViews); - const value = getDefaultValue(); - this.tableService.initRecordsAndFields(value.records, value.fields); + this.router.navigate(['/view1']); + this.tableService.initData(initViews); } activeTabChange(data: any) { this.tableService.updateActiveView(data); - this.router.navigateByUrl(`/share/${this.tableService.activeView().id}`); + this.router.navigateByUrl(`/${this.tableService.activeView().id}`); } handleShared() { diff --git a/src/app/service/table.service.ts b/src/app/service/table.service.ts index 4d98b4db..06cbcc48 100644 --- a/src/app/service/table.service.ts +++ b/src/app/service/table.service.ts @@ -3,12 +3,11 @@ import { createSharedType, initSharedType, SharedType } from '../share/shared'; import { WebsocketProvider } from 'y-websocket'; import { getProvider } from '../share/provider'; import { DemoAIField, DemoAIRecord } from '../types'; -import { sortDataByPositions } from '../utils/utils'; +import { getDefaultValue, sortDataByView } from '../utils/utils'; import { applyYjsEvents } from '../share/apply-to-table'; import { translateSharedTypeToTable } from '../share/utils/translate-to-table'; import { YjsAITable } from '../share/yjs-table'; import { AITable } from '@ai-table/grid'; -import { Subject } from 'rxjs'; import { AITableView } from '../types/view'; @Injectable() @@ -26,45 +25,37 @@ export class TableService { sharedType!: SharedType | null; activeView = computed(() => { - const activeView = this.views().find((view) => view?.isActive) as AITableView; - return activeView; + return this.views().find((view) => view?.isActive) as AITableView; }); - activeViewChange$ = new Subject(); - - - initViews(views: AITableView[]) { + initData(views: AITableView[]) { this.views = signal(views); } updateActiveView(activeViewId: string) { this.views.update((value) => { - const result = value.map((item) => { - return { - ...item, - isActive: item.id === activeViewId - }; + value.forEach((item) => { + if (item.isActive && item.id !== activeViewId) { + item.isActive = false; + } + if (!item.isActive && item.id === activeViewId) { + item.isActive = true; + } }); - return result; + return [...value]; }); - this.activeViewChange$.next(this.activeView()); } setAITable(aiTable: AITable) { this.aiTable = aiTable; } - initRecordsAndFields(records: DemoAIRecord[], fields: DemoAIField[]) { - this.records = signal(sortDataByPositions(records, this.activeView().id) as DemoAIRecord[]); - this.fields = signal(sortDataByPositions(fields, this.activeView().id) as DemoAIField[]); - } - - setRecords(records?: DemoAIRecord[]) { - this.records.set(sortDataByPositions(records ?? this.records(), this.activeView().id) as DemoAIRecord[]); + buildRenderRecords(records?: DemoAIRecord[]) { + this.records = signal(sortDataByView(records ?? this.records(), this.activeView().id) as DemoAIRecord[]); } - setFields(fields?: DemoAIField[]) { - this.fields.set(sortDataByPositions(fields ?? this.fields(), this.activeView().id) as DemoAIField[]); + buildRenderFields(fields?: DemoAIField[]) { + this.fields = signal(sortDataByView(fields ?? this.fields(), this.activeView().id) as DemoAIField[]); } handleShared(room: string) { @@ -79,9 +70,9 @@ export class TableService { this.sharedType.observeDeep((events: any) => { if (!YjsAITable.isLocal(this.aiTable)) { if (!isInitialized) { - const data = translateSharedTypeToTable(this.sharedType!, this.views()); - this.records.set(data.records); - this.fields.set(data.fields); + const data = translateSharedTypeToTable(this.sharedType!); + this.buildRenderRecords(data.records); + this.buildRenderFields(data.fields); isInitialized = true; } else { applyYjsEvents(this.aiTable, events); @@ -94,9 +85,10 @@ export class TableService { this.provider.once('synced', () => { if (this.provider!.synced && [...this.sharedType!.doc!.store.clients.keys()].length === 0) { console.log('init shared type'); + const value = getDefaultValue(); initSharedType(this.sharedType!.doc!, { - records: this.records(), - fields: this.fields() + records: value.records, + fields: value.fields }); } }); diff --git a/src/app/share/shared.ts b/src/app/share/shared.ts index d0e43f71..64d744c5 100644 --- a/src/app/share/shared.ts +++ b/src/app/share/shared.ts @@ -1,13 +1,12 @@ import { isArray, isObject } from 'ngx-tethys/util'; import * as Y from 'yjs'; -import { DemoAIField, DemoAIRecord } from '../types'; +import { DemoAIField, DemoAIRecord, Positions } from '../types'; export type SyncMapElement = Y.Map; export type SyncArrayElement = Y.Array>; export type SyncElement = Y.Array; export type SharedType = Y.Map; - export const createSharedType = () => { const doc = new Y.Doc(); const sharedType = doc.getMap('ai-table'); @@ -19,7 +18,7 @@ export const initSharedType = ( initializeValue: { fields: DemoAIField[]; records: DemoAIRecord[]; - }, + } ) => { const sharedType = doc.getMap('ai-table'); toSharedType(sharedType, initializeValue); @@ -43,24 +42,6 @@ export function toSharedType( }); } - - -// export function toSharedType( -// sharedType: Y.Map, -// data: { -// fields: DemoAIField[]; -// records: DemoAIRecord[]; -// } -// ): void { -// const fieldSharedType = new Y.Array(); -// sharedType.set('fields', fieldSharedType); -// fieldSharedType.insert(0, data.fields.map(toSyncElement)); - -// const recordSharedType = new Y.Array>(); -// sharedType.set('records', recordSharedType); -// recordSharedType.insert(0, data.records.map(toRecordSyncElement)); -// } - export function toSyncElement(node: any): SyncMapElement { const element: SyncMapElement = new Y.Map(); for (const key in node) { @@ -91,15 +72,17 @@ export function toRecordSyncElement(record: DemoAIRecord): Y.Array> } customFieldArray.insert(0, customFields); - const positionArray = new Y.Array(); + const positionsArray: Y.Array = new Y.Array(); const positions = []; for (const viewId in record['positions']) { - positions.push(record['positions'][viewId]); + positions.push({ + [viewId]: record['positions'][viewId] + }); } - positionArray.insert(0, positions); + positionsArray.insert(0, positions); // To save memory, convert map to array. const element = new Y.Array>(); - element.insert(0, [fixedFieldArray, customFieldArray, positionArray]); + element.insert(0, [fixedFieldArray, customFieldArray, positionsArray]); return element; } diff --git a/src/app/share/utils/translate-to-table.ts b/src/app/share/utils/translate-to-table.ts index c4664b70..5756eb9d 100644 --- a/src/app/share/utils/translate-to-table.ts +++ b/src/app/share/utils/translate-to-table.ts @@ -1,7 +1,6 @@ import { AITableFields, Path } from '@ai-table/grid'; import { SharedType } from '../shared'; import { DemoAIField, DemoAIRecord } from '../../types'; -import { AITableView } from '../../types/view'; export const translateRecord = (arrayRecord: any[], fields: AITableFields) => { const fieldIds = fields.map((item) => item.id); @@ -12,27 +11,23 @@ export const translateRecord = (arrayRecord: any[], fields: AITableFields) => { return recordValue; }; -export const translatePositions = (arrayPositions: any[], views: AITableView[]) => { - const viewIds = views.map((item) => item.id); - const positions: Record = {}; - viewIds.forEach((item, index) => { - positions[item] = arrayPositions[index] || 0; - }); - return positions; +export const translatePositions = (arrayPositions: any[]) => { + return arrayPositions.reduce((acc, obj) => { + const key = Object.keys(obj)[0]; + acc[key] = obj[key]; + return acc; + }, {}); }; - -export const translateSharedTypeToTable = (sharedType: SharedType, views: AITableView[]) => { +export const translateSharedTypeToTable = (sharedType: SharedType) => { const data = sharedType.toJSON(); const fields: DemoAIField[] = data['fields']; - // TODO: views 支持协同后移除传入 - // const views: AITableView[] = data['fields']; const records: DemoAIRecord[] = data['records'].map((record: any) => { const [fixedField, customField, positions] = record; return { id: fixedField[0], values: translateRecord(customField, fields), - positions: translatePositions(positions, views), + positions: translatePositions(positions) }; }); return { diff --git a/src/app/utils/utils.ts b/src/app/utils/utils.ts index b12bb1ac..5eddcc9e 100644 --- a/src/app/utils/utils.ts +++ b/src/app/utils/utils.ts @@ -2,7 +2,7 @@ import { AITableFieldType } from '@ai-table/grid'; import { DemoAIField, DemoAIRecord } from '../types'; const LOCAL_STORAGE_KEY = 'ai-table-data'; -export function sortDataByPositions(data: DemoAIRecord[] | DemoAIField[], activeViewId: string) { +export function sortDataByView(data: DemoAIRecord[] | DemoAIField[], activeViewId: string) { const hasPositions = data.every((item) => item.positions && item.positions); if (hasPositions) { return [...data].sort((a, b) => a.positions[activeViewId] - b.positions[activeViewId]); @@ -11,8 +11,8 @@ export function sortDataByPositions(data: DemoAIRecord[] | DemoAIField[], active } export function getSortFieldsAndRecordsByPositions(records: DemoAIRecord[], fields: DemoAIField[], activeViewId: string) { - const newRecords = sortDataByPositions(records, activeViewId) as DemoAIRecord[]; - const newFields = sortDataByPositions(fields, activeViewId) as DemoAIField[]; + const newRecords = sortDataByView(records, activeViewId) as DemoAIRecord[]; + const newFields = sortDataByView(fields, activeViewId) as DemoAIField[]; return { records: newRecords, fields: newFields