Integration

Keyword

<wpx-keyword></wpx-keyword>
  • @Input({ required: true }) wpxModel!: WpxModel<T> universal model

  • @Input({ required: true }) wpxKeys!: string[] keyword fields

  • @Input() wpxWidth: number width, default 220 px

  • @Input() wpxPlaceholder: string prompt filling, default ``

  • @Output() wpxSubmit: EventEmitter<void> submit event

Example: project experiment/table, used in dynamic list or dynamic table

<wpx-keyword
  [wpxModel]="model"
  [wpxKeys]="['no', 'name', 'account']"
  (wpxSubmit)="getData()"
  wpxPlaceholder="订单号、姓名、账户"
></wpx-keyword>

Toolbox

<wpx-toolbox></wpx-toolbox>
  • @Input({ required: true }) wpxModel!: WpxModel<T> universal model

  • @Input() wpxSearchHeight: number height, default 340 px

  • @Input() wpxSearchForm?: FormGroup custom search FormGroup

  • @Input() wpxSearchTitle?: TemplateRef<Any> custom search panel title, default Search

  • @Output() wpxClear: EventEmitter<void> clear search event

  • @Output() wpxRefresh: EventEmitter<void> refresh event

Example: project experiment/table, used in dynamic list or dynamic table

<wpx-toolbox [wpxModel]="model" [wpxSearchForm]="form" (wpxClear)="clear()" (wpxRefresh)="getData()">
  <form *ngIf="form" nz-form id="search" [formGroup]="form" (wpxSubmit)="search($event)">
    <nz-row [nzGutter]="[16, 16]">
      <nz-col [nzSpan]="6">
        <nz-form-item>
          <nz-form-label>订单号</nz-form-label>
          <nz-form-control>
            <input nz-input formControlName="no" />
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzSpan]="6">
        <nz-form-item>
          <nz-form-label>姓名</nz-form-label>
          <nz-form-control>
            <input nz-input formControlName="name" />
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzSpan]="6">
        <nz-form-item>
          <nz-form-label>贌戡</nz-form-label>
          <nz-form-control>
            <input nz-input formControlName="account" />
          </nz-form-control>
        </nz-form-item>
      </nz-col>
    </nz-row>
  </form>
</wpx-toolbox>

The effect is as shown:

Table

<wpx-table></wpx-table>
  • @Input({ required: true }) wpxModel!: WpxModel<T> universal model

  • @Input({ required: true }) wpxColumns!: WpxColumn<T>[] table columns definition

  • @Input({ required: true }) wpxAction!: TemplateRef<{ $implicit: AnyDto }> custom action panel

  • @Input() wpxTitle?: TemplateRef<void> custom title

  • @Input() wpxExtra?: TemplateRef<void> custom extra

  • @Input() wpxX?: string fixed width

  • @Input() wpxBodyStyle: NgStyleInterface | null custom card style, default { height: 'calc(100% - 64px)' }

  • @Output() wpxChange: EventEmitter<void> update event

For example. The project experiment/table has a complete demonstration, the effect is as follows:

Upload Avatar

<wpx-upload-avatar></wpx-upload-avatar>
  • @Input() wpxExt?: string file extension suffix

  • @Input() wpxAccept: string[] allow accept

  • @Input() wpxFallback!: string loading image

Use in form

<wpx-upload-avatar
  wpxExt="image"
  [wpxAccept]="['image/jpeg', 'image/png']"
  [wpxFallback]="['assets', 'photon.svg'] | wpxAssets"
  formControlName="avatar"
>
</wpx-upload-avatar>

Upload Transport

Batch upload and return the component of the progress bar

<wpx-upload-transport></wpx-upload-transport>
  • @Input() wpxExt?: string file extension suffix

  • @Input() wpxAccept: string[] allow accept, default []

  • @Output() wpxChange: EventEmitter<Transport[]> transports status

    • Transport

      • name string

      • percent number

      • file NzUploadFile

Used in FileBrowser

<wpx-upload-transport
  *nzSpaceItem
  [wpxExt]="ext"
  [wpxAccept]="accept"
  (wpxChange)="upload($event)"
></wpx-upload-transport>

The effect is as shown:

Richtext

WpxRichtextComponent integrated editorjs block editor

<wpx-richtext></wpx-richtext>
  • @Input() wpxPlaceholder?: string

  • @Input() wpxFallback?: string loading image

  • @Input() wpxPictures?: (done: ResolveDone) => void picture custom

  • @Input() wpxVideos?: (done: ResolveDone) => void video custom

To use it, you need to load UMD scripts, and also support its extensions/plugins, for example:

this.wpx.loadScript('editorjs', 'https://cdn.jsdelivr.net/npm/@editorjs/editorjs@2.27.2/dist/editorjs.umd.min.js', [
  'https://cdn.jsdelivr.net/npm/@editorjs/paragraph@2.10.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/header@2.7.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/delimiter@1.3.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/underline@1.1.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/nested-list@1.3.0/dist/nested-list.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/checklist@1.5.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/table@2.2.2/dist/table.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/quote@2.5.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/code@2.8.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/marker@1.3.0/dist/bundle.min.js',
  'https://cdn.jsdelivr.net/npm/@editorjs/inline-code@1.4.0/dist/bundle.min.js'
]);

The component reserves the customized way of gallery and video insertion.

You can wrap and customize the component. For example, define a RichtextComponent in app/common/components.

@Component({
  selector: 'app-richtext',
  templateUrl: './richtext.component.html',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => RichtextComponent),
      multi: true
    }
  ],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RichtextComponent implements ControlValueAccessor {
  @ViewChild('footerRef') footerRef!: TemplateRef<Any>;
  @ViewChild(WpxRichtextComponent) richtext!: WpxRichtextComponent;

  placeholder = $localize`直接输入正文`;
  value: RichtextData | null = null;
  modalRef?: NzModalRef<WpxFilebrowserComponent<Any>>;

  onChanged!: (value: Any) => void;
  private onTouched!: () => void;

  constructor(
    private modal: NzModalService,
    private wpx: WpxService,
    @Optional() private pictures: PicturesService,
    @Optional() private videos: VideosService
  ) {}

  registerOnChange(fn: Any): void {
    this.onChanged = fn;
  }

  registerOnTouched(fn: Any): void {
    this.onTouched = fn;
  }

  writeValue(v: RichtextData): void {
    this.value = v;
  }

  get instance(): WpxFilebrowserComponent<WpxFile> {
    return this.modalRef?.componentInstance as WpxFilebrowserComponent<Any>;
  }

  openPictures = (done: ResolveDone): void => {
    this.modalRef = this.modal.create<WpxFilebrowserComponent<WpxFile>, WpxFilebrowserInput<WpxFile>>({
      nzClosable: false,
      nzBodyStyle: { height: '640px', padding: '8px 24px 24px' },
      nzWidth: 1200,
      nzContent: WpxFilebrowserComponent,
      nzData: {
        api: this.pictures,
        type: 'picture',
        fallback: this.richtext.wpxFallback!
      },
      nzFooter: this.footerRef,
      nzOnOk: instance => {
        const data = [...instance.ds.selection.values()][0];
        done({
          assets: this.wpx.assets,
          url: data.url + (!data.query ? '' : '?' + data.query)
        });
      }
    });
  };

  openVideos = (done: ResolveDone): void => {
    this.modalRef = this.modal.create<WpxFilebrowserComponent<WpxFile>, WpxFilebrowserInput<WpxFile>>({
      nzClosable: false,
      nzBodyStyle: { height: '640px', padding: '8px 24px 24px' },
      nzWidth: 1200,
      nzContent: WpxFilebrowserComponent,
      nzData: {
        api: this.videos,
        type: 'video',
        fallback: this.richtext.wpxFallback!
      },
      nzFooter: this.footerRef,
      nzOnOk: instance => {
        const data = [...instance.ds.selection.values()][0];
        done({
          assets: this.wpx.assets,
          url: data.url + (!data.query ? '' : '?' + data.query)
        });
      }
    });
  };
}

Then use it in the form

<app-richtext formControlName="content"> </app-richtext>

Categories

Repeated categories suite for implementation, integrated business logic with drawer categories lists and form editing

<wpx-categories></wpx-categories>
  • @Input({ required: true }) wpxType!: string The type field of collection categories, which can be used for picture, video, etc

FileBrowser

Current implementation pictures and videos library integration, currently requires COS support

<wpx-filebrowser></wpx-filebrowser>
  • @Input({ required: true }) wpxApi!: WpxApi<T> universal API

  • @Input({ required: true }) wpxType!: WpxFileType type, can be picture or video

  • @Input({ required: true }) wpxFallback!: string loding image

  • @Input() wpxForm?: (doc: AnyDto<T>) => void custom form

  • @Input() wpxTitle?: TemplateRef<void> custom title

  • @Input() wpxExtra?: TemplateRef<void> custom extra

The situation of each project may be different. The component only presets the main functions, so in actual use, the package assemble must be customized. The specific viewable console project is app/filebrowser/*.

In addition, it also includes an input form component, which also needs to be customized by the package. The app/common/components/filebrowser-input in the specific viewable console project.

<wpx-filebrowser-input></wpx-filebrowser-input>
  • @Input({ required: true }) wpxValue!: string[] urls

  • @Input({ required: true }) wpxApi!: WpxApi<T> universal API

  • @Input({ required: true }) wpxType!: WpxFileType type, can be picture or video

  • @Input({ required: true }) wpxFallback!: string loding image

  • @Input() wpxHeight: number custom height

  • @Input() wpxWidth: number custom width

  • @Input() wpxLimit?: number limit total

  • @Output() wpxValueChange: EventEmitter<string[]> change event

Selecting a pictures or videos library will pop up a modal to select, as shown in the figure:

Finally, it can be customized for reservation integration of richtext editor.

openPictures = (done: ResolveDone): void => {
  this.modalRef = this.modal.create<WpxFilebrowserComponent<WpxFile>, WpxFilebrowserInput<WpxFile>>({
    nzClosable: false,
    nzBodyStyle: { height: '640px', padding: '8px 24px 24px' },
    nzWidth: 1200,
    nzContent: WpxFilebrowserComponent,
    nzData: {
      api: this.pictures,
      type: 'picture',
      fallback: this.richtext.wpxFallback!
    },
    nzFooter: this.footerRef,
    nzOnOk: instance => {
      const data = [...instance.ds.selection.values()][0];
      done({
        assets: this.wpx.assets,
        url: data.url + (!data.query ? '' : '?' + data.query)
      });
    }
  });
};

openVideos = (done: ResolveDone): void => {
  this.modalRef = this.modal.create<WpxFilebrowserComponent<WpxFile>, WpxFilebrowserInput<WpxFile>>({
    nzClosable: false,
    nzBodyStyle: { height: '640px', padding: '8px 24px 24px' },
    nzWidth: 1200,
    nzContent: WpxFilebrowserComponent,
    nzData: {
      api: this.videos,
      type: 'video',
      fallback: this.richtext.wpxFallback!
    },
    nzFooter: this.footerRef,
    nzOnOk: instance => {
      const data = [...instance.ds.selection.values()][0];
      done({
        assets: this.wpx.assets,
        url: data.url + (!data.query ? '' : '?' + data.query)
      });
    }
  });
};

Last updated