项目初始化
This commit is contained in:
20
src/app/shared/widget/address/address.widget.ts
Normal file
20
src/app/shared/widget/address/address.widget.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
|
||||
@Component({
|
||||
selector: 'sf-address',
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<address [ngModel]="value" name="sf.address" (ngModelChange)="_change($event)"></address>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class AddressWidget extends ControlWidget {
|
||||
static readonly KEY = 'address';
|
||||
|
||||
_change(value: string): void {
|
||||
this.setValue(value);
|
||||
}
|
||||
}
|
||||
23
src/app/shared/widget/editor/editor.widget.ts
Normal file
23
src/app/shared/widget/editor/editor.widget.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
|
||||
@Component({
|
||||
selector: 'sf-editor',
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<editor [ngModel]="value" name="sf.editor" (ngModelChange)="_change($event)"></editor>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class EditorWidget extends ControlWidget {
|
||||
static readonly KEY = 'editor';
|
||||
|
||||
_change(value: string): void {
|
||||
this.setValue(value);
|
||||
if (this.ui.contentChanged) {
|
||||
this.ui.contentChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<ng-container *ngIf="type === 'date'">
|
||||
<div style="display: flex">
|
||||
<nz-date-picker
|
||||
[nzMode]="mode"
|
||||
[nzFormat]="displayFormat"
|
||||
[(ngModel)]="startDate"
|
||||
(ngModelChange)="onChange($event)"
|
||||
nzPlaceHolder="开始时间"
|
||||
></nz-date-picker>
|
||||
<span style="padding: 4px">-</span>
|
||||
<nz-date-picker
|
||||
[nzMode]="mode"
|
||||
[nzFormat]="displayFormat"
|
||||
[(ngModel)]="endDate"
|
||||
(ngModelChange)="onChange($event)"
|
||||
nzPlaceHolder="结束时间"
|
||||
></nz-date-picker>
|
||||
</div>
|
||||
</ng-container>
|
||||
</sf-item-wrap>
|
||||
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SLFromToSearchWidget } from './from-to-search.widget';
|
||||
|
||||
describe('SLFromToSearchWidget', () => {
|
||||
let component: SLFromToSearchWidget;
|
||||
let fixture: ComponentFixture<SLFromToSearchWidget>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [SLFromToSearchWidget],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SLFromToSearchWidget);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
104
src/app/shared/widget/from-to-search/from-to-search.widget.ts
Normal file
104
src/app/shared/widget/from-to-search/from-to-search.widget.ts
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* @Descripttion: Do not edit
|
||||
* @version: 1.0
|
||||
* @Author: Eclipse
|
||||
* @Date: 2021-05-08 15:57:42
|
||||
* @LastEditors: Eclipse
|
||||
* @LastEditTime: 2021-05-08 16:05:26
|
||||
*/
|
||||
import { ChangeDetectorRef, Component, Injector, OnInit } from '@angular/core';
|
||||
import { ControlWidget, SFComponent, SFItemComponent } from '@delon/form';
|
||||
import { format, getISOWeek } from 'date-fns';
|
||||
|
||||
@Component({
|
||||
selector: 'sl-from-to-search',
|
||||
templateUrl: './from-to-search.widget.html',
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class SLFromToSearchWidget extends ControlWidget implements OnInit {
|
||||
static readonly KEY = 'sl-from-to-search';
|
||||
/**
|
||||
* 组件类型
|
||||
*/
|
||||
type: 'date' | 'number' = 'date';
|
||||
/**
|
||||
* 控件模式
|
||||
*/
|
||||
mode: 'date' | 'week' | 'month' | 'year' = 'date';
|
||||
/**
|
||||
* 组件返回值
|
||||
*/
|
||||
data: { start: any; end: any } | null = null;
|
||||
/**
|
||||
* 组件日期显示格式
|
||||
*/
|
||||
displayFormat = 'yyyy-MM-dd';
|
||||
/**
|
||||
* 组件日期格式
|
||||
*/
|
||||
format = 'yyyy-MM-dd';
|
||||
/**
|
||||
* 最小值
|
||||
*/
|
||||
min: any;
|
||||
/**
|
||||
* 最大值
|
||||
*/
|
||||
max: any;
|
||||
/**
|
||||
* 日期区间
|
||||
*/
|
||||
date: Array<any> = [];
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
startDate: any;
|
||||
/**
|
||||
* 结束日期
|
||||
*/
|
||||
endDate: any;
|
||||
|
||||
constructor(cd: ChangeDetectorRef, injector: Injector, sfItemComp?: SFItemComponent, sfComp?: SFComponent) {
|
||||
super(cd, injector, sfItemComp, sfComp);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.type = this.ui?.type || 'date';
|
||||
this.mode = this.ui?.mode || 'date';
|
||||
this.displayFormat = this.ui?.displayFormat;
|
||||
this.format = this.ui?.format || 'yyyy-MM-dd';
|
||||
}
|
||||
onChange(result: any): void {
|
||||
if (this.startDate && this.endDate) {
|
||||
const date1 = new Date(this.startDate);
|
||||
const date2 = new Date(this.endDate);
|
||||
if (date1.getTime() > date2.getTime()) {
|
||||
const date3 = this.endDate;
|
||||
this.endDate = this.startDate;
|
||||
this.startDate = date3;
|
||||
}
|
||||
}
|
||||
if (this.startDate) {
|
||||
this.date[0] = format(this.startDate, this.format);
|
||||
} else {
|
||||
this.date[0] = '';
|
||||
}
|
||||
if (this.endDate) {
|
||||
this.date[1] = format(this.endDate, this.format);
|
||||
} else {
|
||||
this.date[1] = '';
|
||||
}
|
||||
|
||||
if (this.type === 'date') {
|
||||
this.setValue(this.date);
|
||||
} else if (this.type === 'number') {
|
||||
} else {
|
||||
this.setValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
reset(value: string) {
|
||||
this.startDate = null;
|
||||
this.endDate = null;
|
||||
}
|
||||
}
|
||||
11
src/app/shared/widget/from-to/from-to.widget.html
Normal file
11
src/app/shared/widget/from-to/from-to.widget.html
Normal file
@ -0,0 +1,11 @@
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<ng-container *ngIf="type === 'date'">
|
||||
<nz-range-picker
|
||||
[(ngModel)]="date"
|
||||
[nzMode]="mode"
|
||||
(ngModelChange)="onChange($event)"
|
||||
[nzFormat]="displayFormat"
|
||||
[nzShowTime]="displayFormat === 'yyyy-MM-dd HH:mm:ss'"
|
||||
></nz-range-picker>
|
||||
</ng-container>
|
||||
</sf-item-wrap>
|
||||
0
src/app/shared/widget/from-to/from-to.widget.less
Normal file
0
src/app/shared/widget/from-to/from-to.widget.less
Normal file
24
src/app/shared/widget/from-to/from-to.widget.spec.ts
Normal file
24
src/app/shared/widget/from-to/from-to.widget.spec.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EAFromToWidget } from './from-to.widget';
|
||||
|
||||
describe('EAFromToWidget', () => {
|
||||
let component: EAFromToWidget;
|
||||
let fixture: ComponentFixture<EAFromToWidget>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [EAFromToWidget],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EAFromToWidget);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
85
src/app/shared/widget/from-to/from-to.widget.ts
Normal file
85
src/app/shared/widget/from-to/from-to.widget.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { ChangeDetectorRef, Component, Injector, OnInit } from '@angular/core';
|
||||
import { ControlWidget, SFComponent, SFItemComponent } from '@delon/form';
|
||||
import { format, getISOWeek } from 'date-fns';
|
||||
|
||||
@Component({
|
||||
selector: 'sl-from-to',
|
||||
templateUrl: './from-to.widget.html',
|
||||
styleUrls: ['./from-to.widget.less'],
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class EAFromToWidget extends ControlWidget implements OnInit {
|
||||
static readonly KEY = 'sl-from-to';
|
||||
/**
|
||||
* 组件类型
|
||||
*/
|
||||
type: 'date' | 'number' = 'date';
|
||||
/**
|
||||
* 控件模式
|
||||
*/
|
||||
mode: 'date' | 'week' | 'month' | 'year' = 'date';
|
||||
/**
|
||||
* 组件返回值
|
||||
*/
|
||||
data: { start: any; end: any } | null = null;
|
||||
/**
|
||||
* 组件日期显示格式
|
||||
*/
|
||||
displayFormat = 'yyyy-MM-dd';
|
||||
/**
|
||||
* 组件日期格式
|
||||
*/
|
||||
format = 'yyyy-MM-dd';
|
||||
/**
|
||||
* 最小值
|
||||
*/
|
||||
min: any;
|
||||
/**
|
||||
* 最大值
|
||||
*/
|
||||
max: any;
|
||||
/**
|
||||
* 日期区间
|
||||
*/
|
||||
date: any;
|
||||
|
||||
constructor(cd: ChangeDetectorRef, injector: Injector, sfItemComp?: SFItemComponent, sfComp?: SFComponent) {
|
||||
super(cd, injector, sfItemComp, sfComp);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.data = this.formProperty?.formData as { start: any; end: any };
|
||||
this.date = this.initData(this.data);
|
||||
this.type = this.ui?.type || 'date';
|
||||
this.mode = this.ui?.mode || 'date';
|
||||
this.displayFormat = this.ui?.displayFormat;
|
||||
this.format = this.ui?.format || 'yyyy-MM-dd';
|
||||
}
|
||||
|
||||
initData(data: { start: any; end: any }): Date[] | null {
|
||||
return data ? [new Date(this.data?.start), new Date(this.data?.end)] : null;
|
||||
}
|
||||
|
||||
onChange(result: Array<any>): void {
|
||||
console.log('onChange: ', result);
|
||||
|
||||
if (this.type === 'date') {
|
||||
if (JSON.stringify(result) !== '[]') {
|
||||
this.setValue({ start: format(result[0], this.format), end: format(result[1], this.format) });
|
||||
} else {
|
||||
this.setValue(null);
|
||||
}
|
||||
} else if (this.type === 'number') {
|
||||
} else {
|
||||
this.setValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
getWeek(result: Date[]): void {
|
||||
console.log('week: ', result.map(getISOWeek));
|
||||
}
|
||||
|
||||
_change(value: string): void {
|
||||
this.setValue(value);
|
||||
}
|
||||
}
|
||||
63
src/app/shared/widget/img/img.widget.ts
Normal file
63
src/app/shared/widget/img/img.widget.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
|
||||
@Component({
|
||||
selector: 'sf-img',
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<div class="d-flex align-items-center">
|
||||
<ng-container *ngIf="result.length > 0">
|
||||
<img *ngFor="let i of result" src="{{ i.mp }}" height="64" width="64" class="mr-sm" />
|
||||
</ng-container>
|
||||
<button nz-button type="button" nzType="primary" nzSize="small" dialog-img [multiple]="ui.multiple" (selected)="_change($event)">
|
||||
选择
|
||||
</button>
|
||||
<button *ngIf="result.length > 0" class="ml-sm" nz-button type="button" nzSize="small" (click)="_clean()">删除</button>
|
||||
</div>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class ImgWidget extends ControlWidget {
|
||||
static readonly KEY = 'img';
|
||||
result: any[] = [];
|
||||
|
||||
private notify(value: any): void {
|
||||
const { selected } = this.ui;
|
||||
this.setValue(value);
|
||||
if (selected) {
|
||||
selected(value);
|
||||
}
|
||||
}
|
||||
|
||||
reset(value: any): void {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let res = Array.isArray(value) ? value : [value];
|
||||
if (res.length > 0 && typeof res[0] === 'string') {
|
||||
res = res.map((mp) => mp);
|
||||
}
|
||||
this.result = res;
|
||||
}
|
||||
|
||||
_change(list: any): void {
|
||||
const { multiple, field } = this.ui;
|
||||
if (!Array.isArray(list)) {
|
||||
list = [list];
|
||||
}
|
||||
this.result = list;
|
||||
// get fields
|
||||
list = (list as any[]).map((item) => (field ? item[field] : item)).filter((item) => !!item);
|
||||
const value = list.length > 0 ? (multiple === true ? list : list[0]) : null;
|
||||
|
||||
this.notify(value);
|
||||
}
|
||||
|
||||
_clean(): void {
|
||||
this.result.length = 0;
|
||||
this.notify(null);
|
||||
}
|
||||
}
|
||||
77
src/app/shared/widget/noun/noun.widget.ts
Normal file
77
src/app/shared/widget/noun/noun.widget.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
|
||||
@Component({
|
||||
selector: 'sl-noun',
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<nz-input-group nzCompact>
|
||||
<nz-input-number
|
||||
nzPlaceHolder="从"
|
||||
class="number-input"
|
||||
[nzMin]="ui.min || 0"
|
||||
[nzMax]="ui.max || 100000"
|
||||
[nzStep]="ui.step || 1"
|
||||
[ngModel]="min"
|
||||
(ngModelChange)="_change($event, 0)"
|
||||
></nz-input-number>
|
||||
<input
|
||||
type="text"
|
||||
disabled
|
||||
nz-input
|
||||
placeholder="~"
|
||||
style="width: 30px; text-align: center; pointer-events: none; background-color: rgb(255, 255, 255);"
|
||||
/>
|
||||
<nz-input-number
|
||||
nzPlaceHolder="到"
|
||||
class="number-input"
|
||||
[nzMin]="ui.min || 0"
|
||||
[nzMax]="ui.max || 100000"
|
||||
[nzStep]="ui.step || 1"
|
||||
[ngModel]="max"
|
||||
(ngModelChange)="_change($event, 1)"
|
||||
></nz-input-number>
|
||||
</nz-input-group>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
styles: [
|
||||
`
|
||||
.number-input {
|
||||
width: calc(50% - 15px);
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class NounWidget extends ControlWidget {
|
||||
static readonly KEY = 'noun';
|
||||
min!: number | null;
|
||||
max!: number | null;
|
||||
val: any[] = [];
|
||||
|
||||
_change(value: any, index: number) {
|
||||
if (value.toString().trim() === '') {
|
||||
value = null;
|
||||
}
|
||||
if (index === 0) {
|
||||
this.min = value;
|
||||
}
|
||||
if (index === 1) {
|
||||
this.max = value;
|
||||
}
|
||||
|
||||
this.val[index] = value;
|
||||
if (this.val.length === 2 && this.val[0] !== null && this.val[1] !== null) {
|
||||
this.setValue(this.val);
|
||||
} else {
|
||||
this.setValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
reset(value: string) {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
}
|
||||
}
|
||||
184
src/app/shared/widget/property-values/property-values.widget.ts
Normal file
184
src/app/shared/widget/property-values/property-values.widget.ts
Normal file
@ -0,0 +1,184 @@
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { Component } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
export class PV {
|
||||
_$id?: any;
|
||||
id?: string;
|
||||
propertyId?: string;
|
||||
sortId?: number;
|
||||
stateShow?: number;
|
||||
storeId?: number;
|
||||
value?: string;
|
||||
status?: number;
|
||||
}
|
||||
@Component({
|
||||
selector: 'sl-property-values',
|
||||
styles: [
|
||||
`
|
||||
::ng-deep .cdk-drag-preview {
|
||||
display: table;
|
||||
}
|
||||
|
||||
::ng-deep .cdk-drag-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
`,
|
||||
],
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<button nz-button nzType="primary" (click)="addRow()">
|
||||
<i nz-icon nzType="plus" nzTheme="outline"></i>
|
||||
新增属性值
|
||||
</button>
|
||||
<nz-table
|
||||
#editRowTable
|
||||
nzBordered
|
||||
nzSize="small"
|
||||
[nzData]="listOfData"
|
||||
nzTableLayout="fixed"
|
||||
[nzFrontPagination]="false"
|
||||
[nzShowPagination]="false"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzWidth="70px">排序</th>
|
||||
<th nzWidth="200px">属性值</th>
|
||||
<!-- <th nzWidth="200px">状态</th> -->
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody cdkDropList (cdkDropListDropped)="drop($event)">
|
||||
<tr *ngFor="let data of editRowTable.data" cdkDrag>
|
||||
<ng-container *ngIf="!editCache[data._$id]?.edit; else editTemplate">
|
||||
<td>{{ data.sortId }}</td>
|
||||
<td>{{ data.value }}</td>
|
||||
<!-- <td>
|
||||
<span *ngIf="data.stateShow == 0 || data.status == 0">隐藏</span><span *ngIf="data.stateShow == 1 || data.status == 1">显示</span>
|
||||
</td> -->
|
||||
<td>
|
||||
<a (click)="startEdit(data._$id)">编辑</a>
|
||||
<nz-divider nzType="vertical"></nz-divider>
|
||||
<a (click)="deleteRow(data._$id)" class="text-danger">删除</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-template #editTemplate>
|
||||
<td>
|
||||
<input type="text" nz-input [(ngModel)]="editCache[data._$id].data.sortId" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" nz-input [(ngModel)]="editCache[data._$id].data.value" />
|
||||
</td>
|
||||
<!-- <td>
|
||||
<nz-radio-group
|
||||
[(ngModel)]="editCache[data._$id].data.stateShow"
|
||||
(ngModelChange)="changeRadio($event, editCache[data._$id].data)"
|
||||
nzButtonStyle="solid"
|
||||
nzSize="small"
|
||||
>
|
||||
<label nz-radio-button [nzValue]="1">显示</label>
|
||||
<label nz-radio-button [nzValue]="0">隐藏</label>
|
||||
</nz-radio-group>
|
||||
</td> -->
|
||||
<td>
|
||||
<a (click)="saveEdit(data._$id)" class="save">保存</a>
|
||||
<nz-divider nzType="vertical"></nz-divider>
|
||||
<a (click)="cancelEdit(data._$id)">取消</a>
|
||||
</td>
|
||||
</ng-template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</nz-table>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class PropertyValuesWidget extends ControlWidget {
|
||||
static readonly KEY = 'property-values';
|
||||
|
||||
i = 0;
|
||||
editId: string | null = null;
|
||||
|
||||
editCache: { [key: string]: { edit: boolean; data: PV } } = {};
|
||||
listOfData: PV[] = [];
|
||||
|
||||
startEdit(id: string): void {
|
||||
this.editCache[id].edit = true;
|
||||
console.log(this.editCache[id]);
|
||||
// 开始编辑时禁止提交表单
|
||||
this.setValue(null);
|
||||
}
|
||||
|
||||
changeRadio(e: any, item: any) {
|
||||
item.status = e;
|
||||
console.log(e, item);
|
||||
}
|
||||
|
||||
cancelEdit(id: string): void {
|
||||
const index = this.listOfData.findIndex((item) => item._$id === id);
|
||||
this.editCache[id] = {
|
||||
data: { ...this.listOfData[index] },
|
||||
edit: false,
|
||||
};
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
saveEdit(id: string): void {
|
||||
const index = this.listOfData.findIndex((item) => item._$id === id);
|
||||
Object.assign(this.listOfData[index], this.editCache[id].data);
|
||||
this.editCache[id].edit = false;
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
updateEditCache(): void {
|
||||
this.listOfData.forEach((item) => {
|
||||
this.editCache[item._$id] = {
|
||||
edit: false,
|
||||
data: { ...item },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
addRow(): void {
|
||||
this.i++;
|
||||
this.listOfData = [
|
||||
...this.listOfData,
|
||||
{
|
||||
_$id: `${this.i}`,
|
||||
stateShow: 1,
|
||||
},
|
||||
];
|
||||
this.updateEditCache();
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
deleteRow(id: string): void {
|
||||
this.listOfData = this.listOfData.filter((d) => d._$id !== id);
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
_change(value: any, index: number) {}
|
||||
|
||||
reset(value: string) {}
|
||||
afterViewInit() {
|
||||
// 初始化数据
|
||||
this.listOfData = [];
|
||||
const formData: any = this.formProperty?.formData;
|
||||
if (formData) {
|
||||
const data = [...formData];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
this.i = i;
|
||||
this.listOfData.push({
|
||||
_$id: `${this.i}`,
|
||||
...data[i],
|
||||
});
|
||||
}
|
||||
this.updateEditCache();
|
||||
}
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<string[]>): void {
|
||||
moveItemInArray(this.listOfData, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
}
|
||||
176
src/app/shared/widget/spec-values/spec-values.widget.ts
Normal file
176
src/app/shared/widget/spec-values/spec-values.widget.ts
Normal file
@ -0,0 +1,176 @@
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { Component } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
export class PV {
|
||||
_$id?: any;
|
||||
id?: string;
|
||||
specId?: string;
|
||||
sortId?: number;
|
||||
stateShow?: number;
|
||||
storeId?: number;
|
||||
value?: string;
|
||||
}
|
||||
@Component({
|
||||
selector: 'sl-spec-values',
|
||||
styles: [
|
||||
`
|
||||
::ng-deep .cdk-drag-preview {
|
||||
display: table;
|
||||
}
|
||||
|
||||
::ng-deep .cdk-drag-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
`,
|
||||
],
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<button style="margin-bottom: 20px" nz-button nzType="primary" (click)="addRow()">
|
||||
<i nz-icon nzType="plus" nzTheme="outline"></i>
|
||||
新增规格值
|
||||
</button>
|
||||
|
||||
<nz-table
|
||||
#editRowTable
|
||||
nzBordered
|
||||
nzSize="small"
|
||||
[nzData]="listOfData"
|
||||
nzTableLayout="fixed"
|
||||
[nzFrontPagination]="false"
|
||||
[nzShowPagination]="false"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzWidth="70px">排序</th>
|
||||
<th nzWidth="200px">规格值</th>
|
||||
<!-- <th nzWidth="200px">状态</th> -->
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody cdkDropList (cdkDropListDropped)="drop($event)">
|
||||
<tr *ngFor="let data of editRowTable.data" cdkDrag>
|
||||
<ng-container *ngIf="!editCache[data._$id]?.edit; else editTemplate">
|
||||
<td>{{ data.sortId }}</td>
|
||||
<td>{{ data.value }}</td>
|
||||
<!-- <td><span *ngIf="data.stateShow == 0">隐藏</span><span *ngIf="data.stateShow == 1">显示</span></td> -->
|
||||
<td>
|
||||
<a (click)="startEdit(data._$id)">编辑</a>
|
||||
<nz-divider nzType="vertical"></nz-divider>
|
||||
<a (click)="deleteRow(data._$id)" class="text-danger">删除</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-template #editTemplate>
|
||||
<td>
|
||||
<input type="text" nz-input [(ngModel)]="editCache[data._$id].data.sortId" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" nz-input [(ngModel)]="editCache[data._$id].data.value" />
|
||||
</td>
|
||||
<!-- <td>
|
||||
<nz-radio-group [(ngModel)]="editCache[data._$id].data.stateShow" (ngModelChange)="changeRadio($event, editCache[data._$id].data)" nzButtonStyle="solid" nzSize="small">
|
||||
<label nz-radio-button [nzValue]="1">显示</label>
|
||||
<label nz-radio-button [nzValue]="0">隐藏</label>
|
||||
</nz-radio-group>
|
||||
</td> -->
|
||||
<td>
|
||||
<a (click)="saveEdit(data._$id)" class="save">保存</a>
|
||||
<nz-divider nzType="vertical"></nz-divider>
|
||||
<a (click)="cancelEdit(data._$id)">取消</a>
|
||||
</td>
|
||||
</ng-template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</nz-table>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class SpecValuesWidget extends ControlWidget {
|
||||
static readonly KEY = 'spec-values';
|
||||
|
||||
i = 0;
|
||||
editId: string | null = null;
|
||||
|
||||
editCache: { [key: string]: { edit: boolean; data: PV } } = {};
|
||||
listOfData: PV[] = [];
|
||||
|
||||
startEdit(id: string): void {
|
||||
this.editCache[id].edit = true;
|
||||
// 开始编辑时禁止提交表单
|
||||
this.setValue(null);
|
||||
}
|
||||
|
||||
changeRadio(e: any, item: any) {
|
||||
item.status = e;
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
cancelEdit(id: string): void {
|
||||
const index = this.listOfData.findIndex((item) => item._$id === id);
|
||||
this.editCache[id] = {
|
||||
data: { ...this.listOfData[index] },
|
||||
edit: false,
|
||||
};
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
saveEdit(id: string): void {
|
||||
const index = this.listOfData.findIndex((item) => item._$id === id);
|
||||
Object.assign(this.listOfData[index], this.editCache[id].data);
|
||||
this.editCache[id].edit = false;
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
updateEditCache(): void {
|
||||
this.listOfData.forEach((item) => {
|
||||
this.editCache[item._$id] = {
|
||||
edit: false,
|
||||
data: { ...item },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
addRow(): void {
|
||||
this.i++;
|
||||
this.listOfData = [
|
||||
...this.listOfData,
|
||||
{
|
||||
_$id: `${this.i}`,
|
||||
stateShow: 1,
|
||||
},
|
||||
];
|
||||
this.updateEditCache();
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
deleteRow(id: string): void {
|
||||
this.listOfData = this.listOfData.filter((d) => d._$id !== id);
|
||||
this.setValue(this.listOfData);
|
||||
}
|
||||
|
||||
_change(value: any, index: number) {}
|
||||
|
||||
reset(value: string) {}
|
||||
afterViewInit() {
|
||||
this.listOfData = [];
|
||||
// 初始化数据
|
||||
const formData: any = this.formProperty?.formData;
|
||||
if (formData) {
|
||||
const data = [...formData];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
this.i = i;
|
||||
this.listOfData.push({
|
||||
_$id: `${this.i}`,
|
||||
...data[i],
|
||||
});
|
||||
}
|
||||
this.updateEditCache();
|
||||
}
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<string[]>): void {
|
||||
moveItemInArray(this.listOfData, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
}
|
||||
72
src/app/shared/widget/st-widget.module.ts
Normal file
72
src/app/shared/widget/st-widget.module.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { STWidgetRegistry } from '@delon/abc/st';
|
||||
import { DelonFormModule } from '@delon/form';
|
||||
import { AddressModule, EditorModule, FileManagerModule } from '@shared';
|
||||
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
|
||||
import { NzDividerModule } from 'ng-zorro-antd/divider';
|
||||
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||
import { NzStepsModule } from 'ng-zorro-antd/steps';
|
||||
import { NgxTinymceModule } from 'ngx-tinymce';
|
||||
|
||||
// import { STWidgetRegistry } from '@delon/abc/st';
|
||||
import { SharedModule } from '../shared.module';
|
||||
import { AddressWidget } from './address/address.widget';
|
||||
import { EditorWidget } from './editor/editor.widget';
|
||||
import { SLFromToSearchWidget } from './from-to-search/from-to-search.widget';
|
||||
import { EAFromToWidget } from './from-to/from-to.widget';
|
||||
import { ImgWidget } from './img/img.widget';
|
||||
import { NounWidget } from './noun/noun.widget';
|
||||
import { PropertyValuesWidget } from './property-values/property-values.widget';
|
||||
import { SpecValuesWidget } from './spec-values/spec-values.widget';
|
||||
import { TinymceWidget } from './tinymce/tinymce.widget';
|
||||
|
||||
export const STWIDGET_COMPONENTS = [
|
||||
EditorWidget,
|
||||
ImgWidget,
|
||||
AddressWidget,
|
||||
TinymceWidget,
|
||||
NounWidget,
|
||||
EAFromToWidget,
|
||||
SpecValuesWidget,
|
||||
PropertyValuesWidget,
|
||||
SLFromToSearchWidget
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: STWIDGET_COMPONENTS,
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
DelonFormModule.forRoot(),
|
||||
AddressModule,
|
||||
EditorModule,
|
||||
FileManagerModule,
|
||||
NzDividerModule,
|
||||
NzStepsModule,
|
||||
NzButtonModule,
|
||||
NzInputModule,
|
||||
NzDatePickerModule,
|
||||
NzInputNumberModule,
|
||||
NgxTinymceModule,
|
||||
SharedModule
|
||||
],
|
||||
exports: [...STWIDGET_COMPONENTS],
|
||||
entryComponents: STWIDGET_COMPONENTS
|
||||
})
|
||||
export class STWidgetModule {
|
||||
constructor(widgetRegistry: STWidgetRegistry) {
|
||||
widgetRegistry.register(EditorWidget.KEY, EditorWidget);
|
||||
widgetRegistry.register(ImgWidget.KEY, ImgWidget);
|
||||
widgetRegistry.register(AddressWidget.KEY, AddressWidget);
|
||||
widgetRegistry.register(TinymceWidget.KEY, TinymceWidget);
|
||||
widgetRegistry.register(NounWidget.KEY, NounWidget);
|
||||
widgetRegistry.register(EAFromToWidget.KEY, EAFromToWidget);
|
||||
widgetRegistry.register(SpecValuesWidget.KEY, SpecValuesWidget);
|
||||
widgetRegistry.register(PropertyValuesWidget.KEY, PropertyValuesWidget);
|
||||
widgetRegistry.register(SLFromToSearchWidget.KEY, SLFromToSearchWidget);
|
||||
}
|
||||
}
|
||||
31
src/app/shared/widget/tinymce/tinymce.widget.ts
Normal file
31
src/app/shared/widget/tinymce/tinymce.widget.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
|
||||
@Component({
|
||||
selector: 'sf-tinymce',
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
<tinymce [ngModel]="value" (ngModelChange)="change($event)" [config]="config" [loading]="loading"> </tinymce>
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
// tslint:disable-next-line: component-class-suffix
|
||||
export class TinymceWidget extends ControlWidget implements OnInit {
|
||||
static readonly KEY = 'tinymce';
|
||||
|
||||
config: any = {};
|
||||
loading = '';
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loading = this.ui.loading || '加载中……';
|
||||
this.config = this.ui.config || {};
|
||||
}
|
||||
|
||||
change(value: string): void {
|
||||
if (this.ui.change) {
|
||||
this.ui.change(value);
|
||||
}
|
||||
this.setValue(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user