项目初始化

This commit is contained in:
Taric Xin
2021-11-26 16:34:35 +08:00
parent 66644bcf0a
commit 5287578452
354 changed files with 45736 additions and 0 deletions

View File

@ -0,0 +1,53 @@
<div nz-row [nzGutter]="8">
<div nz-col [nzSpan]="6">
<nz-tree [nzData]="cat.ls" (nzClick)="changeCat($event)"> </nz-tree>
</div>
<div nz-col [nzSpan]="18">
<file-manager #fm [actions]="fmAction" [multiple]="multiple" (selected)="cho($event)" [params]="params">
<ng-template #fmAction>
<button *ngIf="result.length > 0" nz-button nz-dropdown [nzDropdownMenu]="copyMenu" class="ml-md">
<i nz-icon nzType="setting"></i>
<i nz-icon nzType="down"></i>
</button>
<nz-dropdown-menu #copyMenu="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item (click)="copyData('link')">Copy Link</li>
<li nz-menu-item (click)="copyData('code')">Copy Code</li>
</ul>
</nz-dropdown-menu>
<nz-input-group nzCompact style="display: inherit; width: 270px" class="ml-md">
<nz-select [(ngModel)]="params.orderby" (ngModelChange)="load()">
<nz-option [nzValue]="0" nzLabel="按上传时间从晚到早"></nz-option>
<nz-option [nzValue]="2" nzLabel="按修改时间从晚到早"></nz-option>
<nz-option [nzValue]="4" nzLabel="按修改时间从早到晚"></nz-option>
<nz-option [nzValue]="6" nzLabel="按图片名升序"></nz-option>
<nz-option [nzValue]="8" nzLabel="按图片名降序"></nz-option>
</nz-select>
<input [(ngModel)]="params.q" delay (delayChange)="load()" nz-input placeholder="按文件名称" />
</nz-input-group>
</ng-template>
</file-manager>
</div>
</div>
<nz-card
[nzTitle]="choTpl"
nzType="inner"
*ngIf="multiple && result.length > 0"
[nzBodyStyle]="{ background: 'rgba(204, 204, 204, 0.33)' }"
class="mt-sm"
>
<ng-template #choTpl>
已选图
<small class="pl-md text-grey">(按住拖动可调整顺序)</small>
<button (click)="ok()" nz-button nzType="primary">确认所选</button>
</ng-template>
<div class="file-manager" cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="drop($event)">
<div class="file-item" *ngFor="let i of result" cdkDrag [title]="i.title">
<div class="file-item__img" [ngStyle]="{ 'background-image': 'url(' + i.mp + ')' }"></div>
<div class="file-item__name">{{ i.title }}</div>
<div class="file-item__pixel">
<span *ngIf="i.is_img">{{ i.width }}x{{ i.height }}</span>
</div>
</div>
</div>
</nz-card>

View File

@ -0,0 +1,108 @@
import { moveItemInArray } from '@angular/cdk/drag-drop';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, ViewChild } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { ArrayService, copy } from '@delon/util';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { NzFormatEmitEvent } from 'ng-zorro-antd/tree';
import { FileManagerComponent } from './file-manager.component';
@Component({
selector: 'file-manager-img',
templateUrl: './file-manager-img.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FileManagerImgComponent implements AfterViewInit {
result: any[] = [];
cat: any = {
ls: [],
item: {}
};
@Input()
params = {
type: 'file',
q: '',
is_img: true,
parent_id: 0,
orderby: 0
};
@Input() multiple: boolean | number = false;
@ViewChild('fm', { static: false }) fm!: FileManagerComponent;
constructor(
private http: _HttpClient,
private arrSrv: ArrayService,
private msg: NzMessageService,
private modal: NzModalRef,
private cdr: ChangeDetectorRef
) {}
ngAfterViewInit(): void {
this.loadCat();
}
copyData(type: 'link' | 'code'): void {
copy(this.result.map(v => this.fm.getCode(v.mp, type)).join('\n')).then(() => this.msg.success('Copy Success'));
}
// #region category
changeCat(e: NzFormatEmitEvent): void {
this.cat.item = e.node!.origin;
this.params.parent_id = e.node!.origin.id;
this.fm.load(1);
this.cdr.detectChanges();
}
loadCat(): void {
this.http.get('/file/folder').subscribe((res: any[]) => {
res.splice(0, 0, { id: 0, title: '所有图片' });
this.cat.ls = this.arrSrv.arrToTreeNode(res, {
cb: (item, parent, deep) => {
item.expanded = deep <= 1;
item.selected = item.id === 0;
}
});
this.cat.item = res[0];
this.cdr.detectChanges();
});
}
// #endregion
load(): void {
this.fm.load(1);
}
cho(i: any): void {
if (i.on === true) {
this.result.splice(this.result.indexOf(i), 1);
i.on = false;
return;
}
if (!this.multiple) {
this.result.push(i);
this.ok();
return;
}
if (typeof this.multiple === 'number' && this.result.length >= this.multiple) {
this.msg.error(`最多只能选取${this.multiple}`);
return;
}
i.on = true;
this.result.push(i);
this.cdr.detectChanges();
}
drop(e: any): void {
moveItemInArray(this.result, e.previousIndex, e.currentIndex);
this.cdr.detectChanges();
}
ok(): void {
this.modal.close(this.result);
}
}

View File

@ -0,0 +1,39 @@
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { ModalHelper } from '@delon/theme';
import { FileManagerImgComponent } from './file-manager-img.component';
@Directive({ selector: '[dialog-img]' })
export class FileManagerImgDirective {
@Input() multiple: boolean | number = false;
@Input() field?: string;
@Output() readonly selected = new EventEmitter<any>();
constructor(private modalHelper: ModalHelper) {}
@HostListener('click')
_click(): void {
this.modalHelper
.create(
FileManagerImgComponent,
{
multiple: this.multiple
},
{
size: 1000,
modalOptions: {
nzClosable: false
}
}
)
.subscribe((res: any) => {
if (Array.isArray(res)) {
let ret = res.length > 0 && !this.multiple ? res[0] : res;
if (this.field && ret) {
ret = ret[this.field];
}
this.selected.emit(ret);
}
});
}
}

View File

@ -0,0 +1,73 @@
<div class="d-flex justify-content-between">
<div class="d-flex align-items-center flex-1">
<nz-upload nzAction="/file" [nzShowUploadList]="false" [nzData]="uploadData" nzMultiple (nzChange)="uploadChange($event)">
<button nz-button nzType="primary" [nzLoading]="loading">
<i nz-icon nzType="upload"></i>
<span>{{ loading ? '上传中' : '选择图像' }}</span>
</button>
</nz-upload>
<ng-template [ngTemplateOutlet]="actions"></ng-template>
</div>
<nz-button-group>
<button nz-button (click)="showType = 'big'" [disabled]="showType === 'big'">
<i nz-icon nzType="appstore"></i>
</button>
<button nz-button (click)="showType = 'small'" [disabled]="showType === 'small'">
<i nz-icon nzType="bars"></i>
</button>
</nz-button-group>
</div>
<nz-spin [nzSpinning]="loading">
<div *ngIf="showType === 'small'" class="file-manager__header">
<div class="file-manager__header-name">Filename</div>
<div class="file-manager__header-pixel">Pixel</div>
<div class="file-manager__header-time">Changed</div>
</div>
<div class="file-manager" [ngClass]="{ 'file-manager__small': showType === 'small' }">
<div *ngIf="path.length > 1" (click)="back()" class="file-item">
<i class="file-item__icon" nz-icon nzType="rollback"></i>
<div class="file-item__name">..</div>
</div>
<div *ngFor="let i of list; let idx = index" class="file-item" [ngClass]="{ 'file-item__selected': i.selected }" (click)="cho(i)">
<i *ngIf="i.type === 'folder'" class="file-item__icon" nz-icon nzType="folder"></i>
<ng-container *ngIf="i.type === 'file'">
<i *ngIf="!i.is_img" class="file-item__icon" nz-icon nzType="file-{{ i.ext }}"></i>
<div class="file-item__img" *ngIf="i.is_img" [ngStyle]="{ 'background-image': 'url(' + i.mp + ')' }"></div>
</ng-container>
<div class="file-item__name">{{ i.title }}</div>
<div class="file-item__pixel">
<span *ngIf="i.is_img">{{ i.width }}x{{ i.height }}</span>
</div>
<div class="file-item__time">{{ i.created | _date }}</div>
<span nz-dropdown [nzDropdownMenu]="actionMenu" class="dd-btn file-item__actions">
<i nz-icon nzType="ellipsis"></i>
</span>
<nz-dropdown-menu #actionMenu="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item nz-popconfirm nzPopconfirmTitle="确定吗?" (nzOnConfirm)="copyImg(i.id)">Copy</li>
<li nz-menu-item (click)="copyData(i.mp, 'link')">Copy Link</li>
<li nz-menu-item (click)="copyData(i.mp, 'code')">Copy Code</li>
<li nz-menu-item (click)="rename(i)">Rename</li>
<li nz-menu-item (click)="move(i)">Move</li>
<li nz-menu-item nz-popconfirm nzPopconfirmTitle="确定吗?" (nzOnConfirm)="remove(i.id, idx)">Remove</li>
</ul>
</nz-dropdown-menu>
</div>
</div>
<div class="text-center mt-md">
<nz-pagination
[(nzPageIndex)]="s.pi"
(nzPageIndexChange)="load(s.pi)"
[nzPageSize]="s.ps"
[nzTotal]="total"
nzHideOnSinglePage
></nz-pagination>
</div>
<div class="no-data" *ngIf="total === 0">暂无</div>
</nz-spin>
<nz-modal [(nzVisible)]="renameModel" nzTitle="重命名" (nzOnOk)="renameOk()" (nzOnCancel)="renameModel = false">
<input nz-input [(ngModel)]="renameTitle" name="renameTitle" />
</nz-modal>
<nz-modal [(nzVisible)]="moveModel" nzTitle="移动" (nzOnOk)="moveOk()" (nzOnCancel)="moveModel = false">
<nz-tree-select class="d-block" [nzNodes]="folderNodes" nzShowSearch nzExpandAll [(ngModel)]="moveId"> </nz-tree-select>
</nz-modal>

View File

@ -0,0 +1,188 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { ArrayService, copy } from '@delon/util';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzUploadFile } from 'ng-zorro-antd/upload';
@Component({
selector: 'file-manager',
templateUrl: './file-manager.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FileManagerComponent implements OnInit {
private get parent_id(): number {
return this.path[this.path.length - 1];
}
constructor(private http: _HttpClient, private cdr: ChangeDetectorRef, private arrSrv: ArrayService, private msg: NzMessageService) {}
showType: 'big' | 'small' = 'big';
s: any = { orderby: 0, ps: 20, pi: 1, q: '' };
loading = false;
list: any[] = [];
item: any;
path: number[] = [0];
total = 0;
@Input() params: any;
@Input() actions!: TemplateRef<any>;
@Input() multiple: boolean | number = false;
@Output() readonly selected = new EventEmitter<any>();
// #endregion
// #region rename
renameModel = false;
renameTitle = '';
// #endregion
// #region move
moveModel = false;
moveId = '';
folderNodes: any[] = [];
ngOnInit(): void {
this.load(1);
}
getCode(mp: string, type: 'link' | 'code'): string {
return type === 'link' ? mp : `<img src="${mp}">`;
}
// #region op
back(): void {
this.path.pop();
this.load(1);
}
next(i: any): void {
this.path.push(i.id);
this.load(1);
}
load(pi: number): void {
const data = {
...this.s,
pi,
parent_id: this.parent_id,
...this.params
};
this.loading = true;
this.cdr.markForCheck();
this.http.get('/file', data).subscribe((res: any) => {
this.loading = false;
this.list = res.list;
this.total = res.total;
this.cdr.markForCheck();
});
}
cho(i: any): void {
if (i.type === 'folder') {
this.next(i);
return;
}
i.selected = !i.selected;
this.selected.emit(i);
this.cdr.detectChanges();
}
// #endregion
// #region upload
uploadData = () => {
return {
parent_id: this.parent_id
};
};
uploadChange({ file }: { file: NzUploadFile }): void {
if (file.status === 'done') {
this.load(1);
}
}
rename(i: any): void {
this.renameModel = true;
this.item = i;
this.renameTitle = i.title;
}
renameOk(): void {
this.http
.post(`/file/rename`, {
id: this.item.id,
title: this.renameTitle
})
.subscribe(() => {
this.msg.success('Success');
this.item.title = this.renameTitle;
this.renameModel = false;
this.cdr.detectChanges();
});
}
move(i: any): void {
this.moveModel = true;
this.item = i;
this.moveId = i.parent_id;
this.http.get(`/file/folder`).subscribe((res: any[]) => {
res.splice(0, 0, { id: 0, title: '根目录' });
this.folderNodes = this.arrSrv.arrToTree(res, {
cb: item => {
item.key = item.id;
if (item.id === this.moveId) {
item.disabled = true;
}
}
});
this.cdr.detectChanges();
});
}
moveOk(): void {
this.http
.post(`/file/move`, {
id: this.item.id,
moveId: this.moveId
})
.subscribe(() => {
this.msg.success('Success');
this.moveModel = false;
this.list.splice(
this.list.findIndex(w => w.id === this.item.id),
1
);
this.cdr.detectChanges();
});
}
// #endregion
// #region copy
copyImg(id: number): void {
this.http.post(`/file/copy/${id}`).subscribe((res: any) => {
this.msg.success('Success');
this.list.push(res.item);
this.cdr.detectChanges();
});
}
copyData(mp: string, type: 'link' | 'code'): void {
copy(this.getCode(mp, type)).then(() => this.msg.success('Copy Success'));
}
// #endregion
// #region remove
remove(id: number, idx: number): void {
this.http.delete(`/file/${id}`).subscribe(() => {
this.msg.success('Success');
this.list.splice(idx, 1);
this.cdr.detectChanges();
});
}
// #endregion
}

View File

@ -0,0 +1,47 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AlainThemeModule } from '@delon/theme';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
import { NzGridModule } from 'ng-zorro-antd/grid';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { NzPaginationModule } from 'ng-zorro-antd/pagination';
import { NzSelectModule } from 'ng-zorro-antd/select';
import { NzSpinModule } from 'ng-zorro-antd/spin';
import { NzTreeModule } from 'ng-zorro-antd/tree';
import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';
import { NzUploadModule } from 'ng-zorro-antd/upload';
import { FileManagerImgComponent } from './file-manager-img.component';
import { FileManagerImgDirective } from './file-manager-img.directive';
import { FileManagerComponent } from './file-manager.component';
const COMPONENTS = [FileManagerComponent, FileManagerImgComponent, FileManagerImgDirective];
@NgModule({
imports: [
CommonModule,
FormsModule,
AlainThemeModule.forChild(),
NzUploadModule,
NzButtonModule,
NzIconModule,
NzSpinModule,
NzPaginationModule,
NzDropDownModule,
NzModalModule,
NzInputModule,
NzTreeSelectModule,
NzGridModule,
NzTreeModule,
NzSelectModule,
NzCardModule
],
declarations: COMPONENTS,
exports: COMPONENTS
})
export class FileManagerModule {}

View File

@ -0,0 +1,50 @@
---
order: 70
title: file-manager
type: Component
---
File manager, [DEMO](https://preview.ng-alain.com/pro/#/sys/file-manager).
## API
### file-manager
| Property | Description | Type | Default |
| ------------ | ------------------------------------------- | ------------------- | ------- |
| `[params]` | Extra QueryString request parameter | `any` | - |
| `[actions]` | Custom action template | `TemplateRef<any>` | - |
| `[multiple]` | Whether to mulitple, or specified number | `boolean, number` | `false` |
| `(selected)` | Resource selected event, not include folder | `EventEmitter<any>` | - |
### dialog-img
`dialog-img` is modal dialog based on the `file-manager` component, [DEMO](https://preview.ng-alain.com/pro/#/ec/ware/edit/10001).
| Property | Description | Type | Default |
| ------------ | ------------------------------------------- | ------------------- | ------- |
| `[multiple]` | Whether to mulitple, or specified number | `boolean, number` | `false` |
| `[field]` | Specify to return a field data | `string` | - |
| `(selected)` | Resource selected event, not include folder | `EventEmitter<any>` | - |
**DEMO**
You can only chooses 5 at most, trigger the `cho` event after confirmation.
```html
<button dialog-img [multiple]="5" (selected)="cho(i, $event)"
nz-button type="button" nzType="primary" nzSize="small">
Choose
</button>
```
## sf widget
Widget name: `img`.
### ui
| Property | Description | Type | Default |
|--------------|---------------------------------------------|------------------------|---------|
| `[multiple]` | Whether to mulitple, or specified number | `boolean, number` | `false` |
| `(selected)` | Resource selected event, not include folder | `(value: any) => void` | - |

View File

@ -0,0 +1,4 @@
export * from './file-manager.component';
export * from './file-manager-img.component';
export * from './file-manager-img.directive';
export * from './file-manager.module';

View File

@ -0,0 +1,50 @@
---
order: 70
title: file-manager
type: Component
---
文件管理器,参考[示例](https://preview.ng-alain.com/pro/#/sys/file-manager)。
## API
### file-manager
| 参数 | 说明 | 类型 | 默认值 |
| ------------ | ------------------------------ | ------------------- | ------- |
| `[params]` | 额外 QueryString 请求参数 | `any` | - |
| `[actions]` | 自定义动作 | `TemplateRef<any>` | - |
| `[multiple]` | 是否多选,若最多 N 张 | `boolean, number` | `false` |
| `(selected)` | 当前资源选中事件,不包含文件夹 | `EventEmitter<any>` | - |
### dialog-img
`dialog-img` 是在 `file-manager` 组件的基础上对话框化,参考[示例](https://preview.ng-alain.com/pro/#/ec/ware/edit/10001)。
| 参数 | 说明 | 类型 | 默认值 |
| ------------ | ------------------------------ | ------------------- | ------- |
| `[multiple]` | 是否多选,若最多 N 张 | `boolean, number` | `false` |
| `[field]` | 指定返回某字段的数据 | `string` | - |
| `(selected)` | 当前资源选中事件,不包含文件夹 | `EventEmitter<any>` | - |
**示例**
最多只能选择 5 张,确认后触发 `cho` 事件。
```html
<button dialog-img [multiple]="5" (selected)="cho(i, $event)"
nz-button type="button" nzType="primary" nzSize="small">
选择照片
</button>
```
## sf 小部件
小部件名称:`img`
### ui
| 参数 | 说明 | 类型 | 默认值 |
| ------------ | ------------------------------ | ---------------------- | ------- |
| `[multiple]` | 是否多选,若最多 N 张 | `boolean, number` | `false` |
| `(selected)` | 当前资源选中事件,不包含文件夹 | `(value: any) => void` | - |