From 4e681dcb59c17e85782492927bc738147a58d13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=A1=E8=89=B2?= Date: Tue, 18 Dec 2018 20:40:29 +0800 Subject: [PATCH] feat(module:st): support response body is an array type (#327) --- _mock/user.ts | 10 +++-- packages/abc/table/demo/basic.md | 2 +- packages/abc/table/index.en-US.md | 1 + packages/abc/table/index.zh-CN.md | 1 + packages/abc/table/table-data-source.ts | 35 ++++++++++++------ packages/abc/table/table.component.ts | 3 ++ .../abc/table/test/table-data-source.spec.ts | 13 +++++++ packages/abc/table/test/table.spec.ts | 37 +++++++++++++------ src/app/shared/shared.module.ts | 33 ++++++++--------- src/styles.less | 10 +++-- 10 files changed, 96 insertions(+), 49 deletions(-) diff --git a/_mock/user.ts b/_mock/user.ts index 260223c566..be87c89fa9 100644 --- a/_mock/user.ts +++ b/_mock/user.ts @@ -1,4 +1,4 @@ -import { MockStatusError, MockRequest } from '@delon/mock'; +import { MockRequest, MockStatusError } from '@delon/mock'; // import * as Mock from 'mockjs'; const r = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1) + min); @@ -11,7 +11,9 @@ export const USERS = { list: [], total, }; - for (let i = 0; i < +req.queryString.ps; i++) { + const onlyList = req.queryString!.field === 'list'; + const num = onlyList ? total : +req.queryString.ps; + for (let i = 0; i < num; i++) { res.list.push({ id: i + 1, picture: { @@ -26,10 +28,10 @@ export const USERS = { email: `aaa${r(1, 10)}@qq.com`, phone: `phone-${r(1000, 100000)}`, price: r(10, 10000000), - registered: new Date() + registered: new Date(), }); } - return res; + return onlyList ? res.list : res; }, 'GET /user/check/': () => false, 'GET /user/check/:name': (req: MockRequest) => req.params.name === 'cipchk', diff --git a/packages/abc/table/demo/basic.md b/packages/abc/table/demo/basic.md index 79e8572b55..d398e4c2b8 100644 --- a/packages/abc/table/demo/basic.md +++ b/packages/abc/table/demo/basic.md @@ -23,7 +23,7 @@ import { STColumn } from '@delon/abc'; `, }) export class DemoComponent { - url = `/users?total=100`; + url = `/users?total=2&field=list`; params = { a: 1, b: 2 }; columns: STColumn[] = [ { title: '编号', index: 'id' }, diff --git a/packages/abc/table/index.en-US.md b/packages/abc/table/index.en-US.md index 3cc455e0e0..820f189bcd 100644 --- a/packages/abc/table/index.en-US.md +++ b/packages/abc/table/index.en-US.md @@ -22,6 +22,7 @@ The value is URL. - Resolve backend data format through `res.reName` mapping data - Use `res.process` to optimize data before rendering table - Use `page.zeroIndexed` to adjust the http request when `pi` parameter follows the `0` base index, default is `1` base index +- Automatically cancel paging when the response body value is an array type - Use `_HttpClient` send request, so applies to [AlainThemeConfig](/theme/http#AlainThemeConfig) configuration ### Static diff --git a/packages/abc/table/index.zh-CN.md b/packages/abc/table/index.zh-CN.md index 5bf1dca3ea..2701a77d5d 100644 --- a/packages/abc/table/index.zh-CN.md +++ b/packages/abc/table/index.zh-CN.md @@ -22,6 +22,7 @@ config: STConfig - 通过 `res.reName` 重置数据 `key` 而无须担心后端数据格式是否满足 `st` 需求 - 通过 `res.process` 可以对表格渲染前对数据进一步优化 - 通过 `page.zeroIndexed` 可以调整 http 请求时 `pi` 参数是否遵循 0 基索引,默认情况下为 1 基索引 +- 若返回体的值是数组类型,则强制不分页 - 使用 `_HttpClient` 发起请求,因此满足 [AlainThemeConfig](/theme/http#AlainThemeConfig) 的配置也适用 ### 静态数据 diff --git a/packages/abc/table/table-data-source.ts b/packages/abc/table/table-data-source.ts index e2dac0646f..2d8eb2fda5 100644 --- a/packages/abc/table/table-data-source.ts +++ b/packages/abc/table/table-data-source.ts @@ -38,6 +38,8 @@ export interface STDataSourceResult { pageShow?: boolean; /** 新 `pi`,若返回 `undefined` 表示用户受控 */ pi?: number; + /** 新 `ps`,若返回 `undefined` 表示用户受控 */ + ps?: number; /** 新 `total`,若返回 `undefined` 表示用户受控 */ total?: number; /** 数据 */ @@ -61,24 +63,32 @@ export class STDataSource { let isRemote = false; const { data, res, total, page, pi, ps, columns } = options; let retTotal: number; + let retPs: number; let retList: STData[]; let retPi: number; + let showPage = page.show; if (typeof data === 'string') { isRemote = true; data$ = this.getByHttp(data, options).pipe( map((result) => { - // list - let ret = deepGet(result, res.reName.list as string[], []); - if (ret == null || !Array.isArray(ret)) { - ret = []; + let ret: STData[]; + if (Array.isArray(result)) { + ret = result; + retTotal = ret.length; + retPs = retTotal; + showPage = false; + } else { + // list + ret = deepGet(result, res.reName.list as string[], []); + if (ret == null || !Array.isArray(ret)) { + ret = []; + } + // total + const resultTotal = res.reName.total && deepGet(result, res.reName.total as string[], null); + retTotal = resultTotal == null ? total || 0 : +resultTotal; } - // total - const resultTotal = - res.reName.total && - deepGet(result, res.reName.total as string[], null); - retTotal = resultTotal == null ? total || 0 : +resultTotal; - return ret as STData[]; + return ret; }), catchError(err => { rejectPromise(err); @@ -152,11 +162,14 @@ export class STDataSource { ); data$.forEach((result: STData[]) => (retList = result)).then(() => { + const realTotal = retTotal || total; + const realPs = retPs || ps; resolvePromise({ pi: retPi, + ps: retPs, total: retTotal, list: retList, - pageShow: typeof page.show === 'undefined' ? (retTotal || total) > ps : page.show, + pageShow: typeof showPage === 'undefined' ? realTotal > realPs : showPage, }); }); }); diff --git a/packages/abc/table/table.component.ts b/packages/abc/table/table.component.ts index caeca56182..48f5c8b0ab 100644 --- a/packages/abc/table/table.component.ts +++ b/packages/abc/table/table.component.ts @@ -233,6 +233,9 @@ export class STComponent implements AfterViewInit, OnChanges, OnDestroy { if (typeof result.pi !== 'undefined') { this.pi = result.pi; } + if (typeof result.ps !== 'undefined') { + this.ps = result.ps; + } if (typeof result.total !== 'undefined') { this.total = result.total; } diff --git a/packages/abc/table/test/table-data-source.spec.ts b/packages/abc/table/test/table-data-source.spec.ts index 8f98c25a9d..c943ec0d71 100644 --- a/packages/abc/table/test/table-data-source.spec.ts +++ b/packages/abc/table/test/table-data-source.spec.ts @@ -385,6 +385,19 @@ describe('abc: table: data-souce', () => { done(); }); }); + it('should be support array data', (done: () => void) => { + spyOn(http, 'request').and.callFake( + (method: string, url: string, opt: any) => { + return of(genData(DEFAULT.ps)); + }, + ); + srv.process(options).then(res => { + expect(res.total).toBe(DEFAULT.ps); + expect(res.list.length).toBe(DEFAULT.ps); + expect(res.ps).toBe(res.total); + done(); + }); + }); }); describe('[sort]', () => { let resParams: any; diff --git a/packages/abc/table/test/table.spec.ts b/packages/abc/table/test/table.spec.ts index 684de2d83d..ab9bb4f9f9 100644 --- a/packages/abc/table/test/table.spec.ts +++ b/packages/abc/table/test/table.spec.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { Component, DebugElement, Injector, Type, ViewChild } from '@angular/core'; import { discardPeriodicTasks, @@ -825,7 +825,11 @@ describe('abc: table', () => { }); }); }); - describe('#data', () => { + describe('[data source]', () => { + let httpBed: HttpTestingController; + beforeEach(() => { + httpBed = injector.get(HttpTestingController); + }); it('support null data', (done: () => void) => { context.data = null; fixture.detectChanges(); @@ -842,6 +846,26 @@ describe('abc: table', () => { done(); }); }); + it('should only restore data', () => { + // tslint:disable-next-line:no-string-literal + const dataSource: STDataSource = comp['dataSource']; + spyOn(dataSource, 'process').and.callFake(() => Promise.resolve({})); + fixture.detectChanges(); + expect(comp.ps).toBe(PS); + }); + it('should be automatically cancel paging when the returned body value is an array type', (done) => { + context.pi = 1; + context.ps = 2; + context.data = '/mock'; + fixture.detectChanges(); + httpBed.expectOne(req => true).flush([ {}, {}, {} ]); + fixture.whenStable().then(() => { + expect(comp.pi).toBe(1); + expect(comp.ps).toBe(3); + expect(comp._isPagination).toBe(false); + done(); + }); + }); }); describe('#req', () => { it('should be keep reName valid', () => { @@ -1037,15 +1061,6 @@ describe('abc: table', () => { }); }); }); - describe('[data source]', () => { - it('should only restore data', () => { - // tslint:disable-next-line:no-string-literal - const dataSource: STDataSource = comp['dataSource']; - spyOn(dataSource, 'process').and.callFake(() => Promise.resolve({})); - fixture.detectChanges(); - expect(comp.ps).toBe(PS); - }); - }); describe('[filter]', () => { describe('in local-data', () => { let filter: STColumnFilter; diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index fc445a69d3..6b68a14ece 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -1,35 +1,33 @@ -import { NgModule, ModuleWithProviders } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router'; -import { AlainThemeModule } from '@delon/theme'; import { DelonABCModule } from '@delon/abc'; import { DelonACLModule } from '@delon/acl'; -import { DelonFormModule } from '@delon/form'; -import { DelonChartModule } from '@delon/chart'; -import { DelonMockModule } from '@delon/mock'; import { DelonCacheModule } from '@delon/cache'; +import { DelonChartModule } from '@delon/chart'; +import { DelonFormModule } from '@delon/form'; +import { AlainThemeModule } from '@delon/theme'; -import { NgZorroAntdModule } from 'ng-zorro-antd'; import { TranslateModule } from '@ngx-translate/core'; -import { HighlightJsModule } from 'ngx-highlight-js'; import { GithubButtonModule } from 'ng-github-button'; +import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { HighlightJsModule } from 'ngx-highlight-js'; +import { SimplemdeModule } from 'ngx-simplemde'; import { NgxTinymceModule } from 'ngx-tinymce'; import { UEditorModule } from 'ngx-ueditor'; -import { SimplemdeModule } from 'ngx-simplemde'; -import { MainMenuComponent } from './components/main-menu/main-menu.component'; -import { ContentComponent } from './components/content/content.component'; -import { ConfigButtonComponent } from './components/config-button/config-button.component'; -import { EditButtonComponent } from './components/edit-button/edit-button.component'; -import { DocsComponent } from './components/docs/docs.component'; import { CodeBoxComponent } from './components/code-box/code-box.component'; -import { DemoModalComponent } from './components/dialog/modal.component'; +import { ConfigButtonComponent } from './components/config-button/config-button.component'; +import { ContentComponent } from './components/content/content.component'; import { DemoDrawerComponent } from './components/dialog/drawer.component'; -import { RouteTransferDirective } from './components/route-transfer/route-transfer.directive'; +import { DemoModalComponent } from './components/dialog/modal.component'; +import { DocsComponent } from './components/docs/docs.component'; +import { EditButtonComponent } from './components/edit-button/edit-button.component'; import { IconComponent } from './components/icon/icon.component'; +import { MainMenuComponent } from './components/main-menu/main-menu.component'; +import { RouteTransferDirective } from './components/route-transfer/route-transfer.directive'; const DIALOG_COMPONENTS = [ DemoModalComponent, @@ -45,7 +43,7 @@ const COMPONENTS = [ DocsComponent, CodeBoxComponent, RouteTransferDirective, - ...DIALOG_COMPONENTS + ...DIALOG_COMPONENTS, ]; const THIRDS = [ @@ -70,7 +68,6 @@ const THIRDS = [ DelonFormModule, DelonChartModule, DelonCacheModule, - DelonMockModule.forChild(), ...THIRDS, ], declarations: COMPONENTS, diff --git a/src/styles.less b/src/styles.less index ffb604acdb..22cc802f88 100644 --- a/src/styles.less +++ b/src/styles.less @@ -1,8 +1,10 @@ // alain -@import '../packages/theme/styles/index'; -@import '../packages/theme/styles/layout/default/index'; -@import '../packages/abc/index'; -@import '../packages/chart/index'; +@import '../packages/theme/styles/index.less'; +@import '../packages/theme/styles/layout/default/index.less'; +@import '../packages/abc/index.less'; +@import '../packages/chart/index.less'; // docs @import './app/styles/index.less'; + +.scrollbar-mixin(~'.ant-affix');