#

query-table

索引
标题
等级 badge 操作
1 bat hight Poodle
2 bat hight Welsh Springer Spaniel
3 bat all Dogue de Bordeaux
4 bat hight Carpathian Shepherd Dog
5 bat low Dachshund
6 bat hight Vizsla
7 bat all Smooth Fox Terrier
8 bat low Bulldog
9 bat hight Estonian Hound
10 bat all Bruno Jura Hound
// src/app/piying/page/component/function/table/example/query-table/mock.service.ts
import { Injectable } from '@angular/core';
import { faker } from '@faker-js/faker';
import { RequestFn, SortList } from '@piying-lib/angular-daisyui/extension';

export type RequestInput = {
  page: {
    index: number;
    size: number;
  };
  query?: { content?: string; level?: number };
  sort?: SortList;
};

@Injectable({ providedIn: 'root' })
export class DemoTableResourceService {
  private readonly mockData: any[] = Array.from({ length: 500 }, () => ({
    id: faker.string.uuid(),
    title: faker.animal.type(),
    level: faker.number.int(2),
    badge: faker.animal.dog(),
    createdAt: faker.date.past().toISOString(),
  }));

  readonly requestFn: RequestFn = (input: RequestInput): [number, any[]] => {
    const { index, size } = input.page ?? { index: 0, size: 10 };

    let data = [...this.mockData];

    if (input.query?.content) {
      const queryLower = input.query.content.toLowerCase();
      data = data.filter((item) => item.title.toLowerCase().includes(queryLower));
    }

    if (input.query?.level !== undefined) {
      data = data.filter((item) => item.level === input.query!.level);
    }

    if (input.sort && input.sort.length > 0) {
      input.sort.forEach(({ key, value }) => {
        data.sort((a, b) => {
          const aValue = a[key];
          const bValue = b[key];
          if (aValue == null && bValue == null) return 0;
          if (aValue == null) return value;
          if (bValue == null) return -value;
          if (aValue < bValue) return value;
          if (aValue > bValue) return -value;
          return 0;
        });
      });
    }

    data = data.slice(index * size, index * size + size);

    return [this.mockData.length, data];
  };
}

//----------
// src/app/piying/page/component/function/table/example/query-table/content.ts
import * as v from 'valibot';
import { actions, formConfig, NFCSchema, setComponent } from '@piying/view-angular-core';
import { computed } from '@angular/core';
import {
  TableResourceService,
  SortService,
  CheckboxService,
} from '@piying-lib/angular-daisyui/extension';
import { FormDialogService } from '@piying-lib/angular-daisyui/overlay';
import { DemoTableResourceService } from './mock.service';
const LevelOptions = [
  {
    label: 'all',
    value: 0,
  },
  {
    label: 'low',
    value: 1,
  },
  { label: 'hight', value: 2 },
];
const LevelObj = LevelOptions.reduce((obj, item) => {
  obj[item.value] = item.label;
  return obj;
}, {} as any);
const QueryCondition = v.pipe(
  v.object({
    params: v.pipe(
      v.object({
        content: v.pipe(
          v.string(),
          v.title('searchTitle'),
          actions.wrappers.set(['label-wrapper']),
          actions.props.patch({
            labelPosition: 'left',
          }),
          actions.class.top('gap-2'),
        ),

        level: v.pipe(
          v.number(),
          v.title('level'),
          actions.wrappers.set(['label-wrapper']),
          actions.class.top('gap-2'),
          actions.props.patch({
            labelPosition: 'left',
          }),
          setComponent('select'),
          actions.inputs.patch({
            options: LevelOptions,
          }),
        ),
      }),
      formConfig({ updateOn: 'submit' }),
      actions.wrappers.set(['div']),
      actions.class.top('flex gap-4'),
    ),
    submit: v.pipe(
      NFCSchema,
      setComponent('input-button'),
      actions.inputs.patch({
        type: 'submit',
        color: 'primary',
      }),
      actions.inputs.patchAsync({
        clicked: (field) => {
          return () => {
            const result = field.get(['..', 'params'])!.form.control!;
            result.emitSubmit();
            field.injector.get(TableResourceService).setParams('query', result.value);
          };
        },
      }),
    ),
  }),
  actions.wrappers.set(['div']),
  actions.class.top('flex justify-between'),
);
const TableDefine = v.pipe(
  v.object({
    table: v.pipe(
      NFCSchema,
      setComponent('table'),
      actions.inputs.patchAsync({
        define: (field) => {
          const pageFiled = field.get(['..', 'bottom', 'page']);
          return {
            row: {
              head: [
                {
                  columns: ['checkbox', 'index', 'title', 'level', 'badge', 'actions'],
                  define: v.pipe(v.tuple([]), setComponent('tr'), actions.class.top('bg-base-200')),
                },
              ],
              body: [
                {
                  define: v.pipe(v.tuple([]), setComponent('tr')),
                  columns: ['checkbox', 'index', 'title', 'level', 'badge', 'actions'],
                },
              ],
            },
            columns: {
              checkbox: {
                head: ' ',
                body: v.pipe(
                  v.boolean(),
                  setComponent('checkbox'),
                  actions.wrappers.set(['td', 'table-checkbox-body']),
                ),
              },
              index: {
                head: '索引',
                body: (node: any, index: number) => {
                  const { pageQueryParams } = pageFiled!.props();
                  return `${index + 1 + pageQueryParams.index * pageQueryParams.size}`;
                },
              },
              title: {
                head: v.pipe(
                  NFCSchema,
                  setComponent('common-data'),
                  actions.inputs.patch({ content: '标题' }),
                  actions.wrappers.set(['td', 'sort-header']),
                  actions.props.patch({
                    key: 'title',
                  }),
                ),

                // '标题',
                body: (data: any) => {
                  return data.title;
                },
              },
              level: {
                head: '等级',
                body: (data: any) => {
                  return LevelObj[data.level];
                },
              },
              badge: {
                head: 'badge',
                body: v.pipe(
                  NFCSchema,
                  setComponent('badge'),
                  actions.wrappers.set(['td']),
                  actions.inputs.patchAsync({
                    content: ({ context }) => {
                      return computed(() => context.item$().badge);
                    },
                  }),
                ),
              },
              actions: {
                head: '操作',
                body: v.pipe(
                  v.object({
                    edit: v.pipe(
                      NFCSchema,
                      setComponent('button'),
                      actions.inputs.patch({
                        content: { icon: { fontIcon: 'edit' } },
                        shape: 'circle',
                        size: 'sm',
                      }),
                      actions.inputs.patchAsync({
                        clicked: (field) => {
                          return () => {
                            console.log(field.context['item$']());
                          };
                        },
                      }),
                    ),
                    delete: v.pipe(
                      NFCSchema,
                      setComponent('button'),
                      actions.inputs.patch({
                        content: { icon: { fontIcon: 'delete' } },
                        shape: 'circle',
                        size: 'sm',
                      }),
                      actions.class.top('text-error'),
                      actions.inputs.patchAsync({
                        clicked: (field) => {
                          return () => {
                            console.log(field.context['item$']());
                          };
                        },
                      }),
                    ),
                  }),
                  actions.class.top('flex gap-2'),
                  actions.wrappers.set(['td']),
                ),
              },
            },
          };
        },
        data: (field) => {
          return field.injector.get(TableResourceService).list$$;
        },
      }),

      actions.class.bottom('mt-4 border rounded-box border-base-content/5'),
      actions.providers.patch([SortService, CheckboxService]),
      actions.hooks.merge({
        allFieldsResolved: (field) => {
          const sort = field.injector.get(SortService);
          sort.sortList.set(['title']);
          sort.setInitValue({
            title: -1,
          });
          sort.value$$.subscribe((value) => {
            field.injector.get(TableResourceService).setParams('sort', value);
          });
          field.injector.get(CheckboxService).init();
        },
      }),
    ),
    bottom: v.pipe(
      v.object({
        add: v.pipe(
          NFCSchema,
          setComponent('button'),
          actions.inputs.patch({ content: { icon: { fontIcon: 'add' }, title: 'add' } }),
          actions.inputs.patchAsync({
            clicked: (field) => {
              return () => {
                const service = field.injector.get(FormDialogService);
                service.open({
                  title: '添加',
                  schema: v.pipe(
                    v.string(),
                    actions.wrappers.set(['div']),
                    actions.class.top('grid gap-2'),
                  ),
                  applyValue: async (value) => {
                    // 更新或添加
                  },
                  injector: field.injector,
                });
              };
            },
          }),
        ),
        page: v.pipe(
          NFCSchema,
          setComponent('pagination'),
          actions.class.top('mt-4 flex justify-end'),
          actions.inputs.patch({
            value: {
              size: 10,
              index: 0,
            },
          }),
          actions.inputs.patchAsync({
            count: (field) => {
              return field.injector.get(TableResourceService).count$$;
            },
          }),
          actions.outputs.patchAsync({
            valueChange: (field) => {
              return (data) => {
                field.injector.get(TableResourceService).setParams('page', data);
              };
            },
          }),
        ),
      }),
      actions.wrappers.set(['div']),
      actions.class.top('flex justify-between items-center'),
    ),
  }),
);
export default v.pipe(
  v.pipe(
    v.object({ query: QueryCondition, table: TableDefine }),
    actions.wrappers.set(['div']),
    actions.class.top('m-4'),
    actions.providers.patch([TableResourceService]),
    actions.hooks.merge({
      allFieldsResolved: (field) => {
        const demoRequest = field.injector.get(DemoTableResourceService);
        field.injector.get(TableResourceService).setRequest(demoRequest.requestFn);
      },
    }),
  ),
);
content_copy