Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: render member #WIK-16256 #42

Merged
merged 7 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@for (menu of fieldMenus; track index; let index = $index) {
@if (menu._id === 'divider') {
@if (menu.type === 'divider') {
<thy-divider [thyStyle]="'solid'"></thy-divider>
} @else {
<a thyDropdownMenuItem href="javascript:;" (click)="execute(menu)">
Expand Down
6 changes: 3 additions & 3 deletions packages/grid/src/constants/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { ElementRef, signal, Signal, WritableSignal } from '@angular/core';
import { AITableFieldMenuItem } from '../types';

export const DividerMenuItem = {
_id: 'divider'
type: 'divider'
};

export const EditFieldPropertyItem = {
_id: 'editFieldProperty',
type: 'editFieldProperty',
name: '编辑列',
icon: 'edit',
exec: (aiTable: AITable, field: Signal<AITableField>, origin?: HTMLElement | ElementRef<any>) => {
Expand All @@ -19,7 +19,7 @@ export const EditFieldPropertyItem = {
};

export const RemoveFieldItem = {
_id: 'removeField',
type: 'removeField',
name: '删除列',
icon: 'trash',
exec: (aiTable: AITable, field: Signal<AITableField>) => {
Expand Down
8 changes: 7 additions & 1 deletion packages/grid/src/constants/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ export const DEFAULT_COLUMN_WIDTH = 200;

export const MIN_COLUMN_WIDTH = 80;

export const DBL_CLICK_EDIT_TYPE = [AITableFieldType.text, AITableFieldType.number, AITableFieldType.select, AITableFieldType.date];
export const DBL_CLICK_EDIT_TYPE = [
AITableFieldType.text,
AITableFieldType.number,
AITableFieldType.select,
AITableFieldType.date,
AITableFieldType.member
];

export const MOUSEOVER_EDIT_TYPE = [AITableFieldType.progress];

Expand Down
30 changes: 26 additions & 4 deletions packages/grid/src/core/constants/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { AITableFieldInfo, AITableFieldType } from '../types';
export const BasicFields = [
{
type: AITableFieldType.text,
name: '文本',
name: '单行文本',
icon: 'font',
width: 300
},
// 多行文本
{
type: AITableFieldType.select,
name: '单选',
icon: 'check-circle',
width: 200
},
// 多选
{
type: AITableFieldType.number,
name: '数字',
Expand All @@ -26,6 +28,20 @@ export const BasicFields = [
icon: 'calendar',
width: 200
},
{
type: AITableFieldType.member,
name: '成员',
icon: 'user',
width: 200
},
// 级联单选
// 级联多选
{
type: AITableFieldType.progress,
name: '进度',
icon: 'progress',
width: 200
},
{
type: AITableFieldType.rate,
name: '评分',
Expand All @@ -39,9 +55,9 @@ export const BasicFields = [
width: 300
},
{
type: AITableFieldType.progress,
name: '进度',
icon: 'progress',
type: AITableFieldType.createdBy,
name: '创建人',
icon: 'user',
width: 200
},
{
Expand All @@ -50,6 +66,12 @@ export const BasicFields = [
icon: 'calendar',
width: 200
},
{
type: AITableFieldType.updateBy,
name: '更新人',
icon: 'user',
width: 200
},
{
type: AITableFieldType.updatedAt,
name: '更新时间',
Expand Down
5 changes: 3 additions & 2 deletions packages/grid/src/core/types/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export enum AITableFieldType {
rate = 'rate',
link = 'link',
createdAt = 'created_at',
updatedAt= 'updated_at'
updatedAt = 'updated_at',
createdBy = 'created_by',
updateBy = 'update_by'
huanhuanwa marked this conversation as resolved.
Show resolved Hide resolved
}

export enum AITableStatType {
Expand Down Expand Up @@ -87,7 +89,6 @@ export type FieldValue =

export interface AITableRecord {
_id: string;
checked?: boolean;
values: Record<string, FieldValue>;
}

Expand Down
40 changes: 34 additions & 6 deletions packages/grid/src/grid.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="grid-header d-flex">
<div class="grid-column-checkbox grid-cell grid-checkbox">
<label thyCheckbox thyLabelText="" [ngModel]="isSelectedAll" (ngModelChange)="toggleSelectAll($event)"></label>
<label thyCheckbox thyLabelText="" [ngModel]="isSelectedAll()" (ngModelChange)="toggleSelectAll($event)"></label>
</div>
@for (field of gridData().fields; track field._id) {
<div
Expand Down Expand Up @@ -34,16 +34,18 @@
</div>
<div class="grid-body d-flex">
@for (record of gridData().records; track record._id; let index = $index) {
<div class="grid-row d-flex" [ngClass]="{ highlight: aiTable.selection().selectedRecords.has(record._id) }">
<div class="grid-row d-flex" [ngClass]="{ highlight: (record._id | isSelectRecord: aiTable.selection()) }">
<div class="grid-row-index grid-checkbox">
<label
[ngClass]="record.checked ? 'checked-box' : 'unchecked-box'"
[ngClass]="(record._id | isSelectRecord: aiTable.selection()) ? 'checked-box' : 'unchecked-box'"
thyCheckbox
thyLabelText=""
[ngModel]="record.checked"
[ngModel]="record._id | isSelectRecord: aiTable.selection()"
(ngModelChange)="selectRecord(record._id)"
></label>
<span [ngClass]="record.checked ? 'grid-row-no-number' : 'grid-row-number'"> {{ index + 1 }} </span>
<span [ngClass]="(record._id | isSelectRecord: aiTable.selection()) ? 'grid-row-no-number' : 'grid-row-number'">
{{ index + 1 }}
</span>
</div>
@for (field of gridData().fields; track field._id) {
<div
Expand Down Expand Up @@ -83,7 +85,7 @@
</div>
}
@case (AITableFieldType.rate) {
<thy-rate [(ngModel)]="record.values[field._id]"></thy-rate>
<thy-rate [ngModel]="record.values[field._id]"></thy-rate>
}
@case (AITableFieldType.link) {
<a
Expand All @@ -108,6 +110,23 @@
<span> {{ record.values[field._id] }}{{ record.values[field._id]?.config?.suffix || '%' }} </span>
</thy-progress>
}
@case (AITableFieldType.member) {
@if (!field.isMultiple) {
<ng-template [ngTemplateOutlet]="member" [ngTemplateOutletContext]="{ record, field }"></ng-template>
} @else {
<thy-avatar-list thyAvatarSize="xs">
@for (item of record.values[field._id]; track $index) {
<thy-avatar [thyName]="item.display_name" [thySrc]="item.avatar"></thy-avatar>
}
</thy-avatar-list>
}
}
@case (AITableFieldType.createdBy) {
<ng-template [ngTemplateOutlet]="member" [ngTemplateOutletContext]="{ record, field }"></ng-template>
}
@case (AITableFieldType.updateBy) {
<ng-template [ngTemplateOutlet]="member" [ngTemplateOutletContext]="{ record, field }"></ng-template>
}
@default {
<span class="text-truncate"> {{ record.values[field._id] }}</span>
}
Expand All @@ -124,3 +143,12 @@
</div>

<div #activeBorder class="active-border"></div>

<ng-template #member let-record="record" let-field="field">
huanhuanwa marked this conversation as resolved.
Show resolved Hide resolved
<thy-avatar
[thyName]="record.values[field._id].display_name"
[thySrc]="record.values[field._id].avatar"
thySize="xs"
thyShowName="true"
></thy-avatar>
</ng-template>
20 changes: 12 additions & 8 deletions packages/grid/src/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ import {
createDefaultField,
getDefaultRecord
} from './core';
import { SelectOptionPipe } from './pipes/grid.pipe';
import { IsSelectRecordPipe, SelectOptionPipe } from './pipes/grid.pipe';
import { AITableGridEventService } from './services/event.service';
import { AI_TABLE_GRID_FIELD_SERVICE_MAP, AITableGridFieldService } from './services/field.service';
import { AITableGridSelectionService } from './services/selection.service';
import { AIFieldConfig, AITableFieldMenuItem, AITableRowHeight } from './types';
import { AIFieldConfig, AITableFieldMenuItem, AITableReferences } from './types';
import { buildGridData } from './utils';
import { ThyAvatarModule } from 'ngx-tethys/avatar';

@Component({
selector: 'ai-table-grid',
Expand Down Expand Up @@ -79,7 +80,10 @@ import { buildGridData } from './utils';
ThyDropdownDirective,
ThyDropdownMenuComponent,
ThyCheckboxModule,
ProgressEditorComponent
ProgressEditorComponent,
ThyAvatarModule,
NgTemplateOutlet,
IsSelectRecordPipe
],
providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService]
})
Expand All @@ -88,21 +92,21 @@ export class AITableGrid implements OnInit {

aiFields = model.required<AITableFields>();

aiRowHeight = input<AITableRowHeight>();

aiFieldConfig = input<AIFieldConfig>();

aiReadonly = input<boolean>();

aiPlugins = input<AIPlugin[]>();

aiReferences = input<AITableReferences>();

AITableFieldType = AITableFieldType;

aiTable!: AITable;

get isSelectedAll() {
isSelectedAll = computed(() => {
return this.aiTable.selection().selectedRecords.size === this.aiRecords().length;
}
});

onChange = output<AITableChangeOptions>();

Expand All @@ -113,7 +117,7 @@ export class AITableGrid implements OnInit {
mouseoverRef!: ThyPopoverRef<any>;

gridData = computed(() => {
return buildGridData(this.aiRecords(), this.aiFields(), this.aiTable.selection());
return buildGridData(this.aiRecords(), this.aiFields(), this.aiReferences());
});

private ngZone = inject(NgZone);
Expand Down
11 changes: 11 additions & 0 deletions packages/grid/src/pipes/grid.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Pipe, PipeTransform } from '@angular/core';
import { AITableSelectOption } from '../core';
import { AITableSelection } from '../types';

@Pipe({
name: 'selectOption',
Expand All @@ -10,3 +11,13 @@ export class SelectOptionPipe implements PipeTransform {
return options.find((item) => item._id === _id);
}
}

@Pipe({
name: 'isSelectRecord',
standalone: true
})
export class IsSelectRecordPipe implements PipeTransform {
transform(recordId: string, selection: AITableSelection) {
return selection.selectedRecords.has(recordId);
}
}
2 changes: 1 addition & 1 deletion packages/grid/src/types/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ElementRef, Signal } from '@angular/core';
import { AITable, AITableField } from '../core';

export interface AITableFieldMenuItem {
_id: string;
type: string;
name?: string;
icon?: string;
exec?: (aiTable: AITable, field: Signal<AITableField>, origin?: HTMLElement | ElementRef<any>) => void;
Expand Down
17 changes: 10 additions & 7 deletions packages/grid/src/types/grid.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { AITableField, AITableFieldType, AITableRecord } from '../core';
import { AITableFieldMenuItem } from './field';

export enum AITableRowHeight {
Short = 1,
Medium = 2,
Tall = 3,
ExtraTall = 4
}

export interface AITableGridCellRenderSchema {
editor: any;
}
Expand All @@ -28,3 +21,13 @@ export interface AIFieldConfig {
fieldPropertyEditor?: any;
fieldMenus?: AITableFieldMenuItem[];
}

export interface AITableUserInfo {
uid?: string;
display_name?: string;
avatar?: string;
}

export interface AITableReferences {
members: AITableUserInfo[];
}
62 changes: 49 additions & 13 deletions packages/grid/src/utils/build.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
import { AITableFields, AITableRecords, FieldsMap } from '../core';
import { AITableGridData, AITableSelection } from '../types';
import { createDraft, finishDraft } from 'immer';
import { AITableFields, AITableFieldType, AITableRecords, FieldsMap } from '../core';
import { AITableGridData, AITableReferences, AITableSelection, AITableUserInfo } from '../types';

export const buildGridData = (recordValue: AITableRecords, fieldsValue: AITableFields, selection: AITableSelection): AITableGridData => {
export const buildGridData = (
recordValue: AITableRecords,
fieldsValue: AITableFields,
references?: AITableReferences
): AITableGridData => {
const fields = fieldsValue.map((item) => {
return {
...item,
icon: item.icon || FieldsMap[item.type].icon,
width: item.width || FieldsMap[item.type].width
};
});
let records = buildRecordsByReferences(recordValue, fieldsValue, references);
return {
type: 'grid',
fields: fieldsValue.map(item=>{
return {
...item,
icon: item.icon || FieldsMap[item.type].icon,
width: item.width || FieldsMap[item.type].width
}
}),
records: recordValue.map((item) => {
return { ...item, checked: selection.selectedRecords.has(item._id) };
})
fields,
records
};
};

export function buildRecordsByReferences(records: AITableRecords, fields: AITableFields, references?: AITableReferences) {
if (!references) {
return records;
}
const memberFields = fields.filter((field) =>
[AITableFieldType.createdBy, AITableFieldType.updateBy, AITableFieldType.member].includes(field.type)
);
if (memberFields.length) {
const uidToMember = references.members.reduce(
(map: { [key: string]: any }, member: AITableUserInfo) => {
map[member.uid!] = member;
return map;
},
{} as Record<string, AITableUserInfo>
);
const draftRecords = createDraft(records);
draftRecords.forEach((record) => {
memberFields.forEach((field) => {
const value = record.values[field._id];
if (field.isMultiple) {
record.values[field._id] = value.map((uid: string) => uidToMember[uid]).filter(Boolean);
} else {
record.values[field._id] = uidToMember[value] || {};
}
});
});
records = finishDraft(draftRecords);
}
return records;
}
Loading