diff --git a/BasicList/package.json b/BasicList/package.json index e236692c5b787ec4a91cc0e86240b14bfcfb3be0..40cfd4814cabb075d9df58b5f3cc47199387c9b1 100644 --- a/BasicList/package.json +++ b/BasicList/package.json @@ -2,16 +2,17 @@ "name": "@umi-block/basic-list", "version": "0.0.1", "description": "BasicList", - "main": "src/index.js", - "scripts": { - "dev": "umi dev" - }, "repository": { "type": "git", "url": "https://github.com/umijs/umi-blocks/ant-design-pro/basiclist" }, + "license": "ISC", + "main": "src/index.js", + "scripts": { + "dev": "umi dev" + }, "dependencies": { - "ant-design-pro": "^2.1.1", + "@ant-design/pro-layout": "^4.0.5", "antd": "^3.10.9", "dva": "^2.4.0", "hash.js": "^1.1.5", @@ -22,8 +23,7 @@ }, "devDependencies": { "umi": "^2.6.9", - "umi-plugin-react": "^1.7.2", - "umi-plugin-block-dev": "^1.0.0" - }, - "license": "ISC" -} + "umi-plugin-block-dev": "^1.0.0", + "umi-plugin-react": "^1.7.2" + } +} \ No newline at end of file diff --git a/BasicList/src/Result/index.less b/BasicList/src/Result/index.less new file mode 100644 index 0000000000000000000000000000000000000000..00c958793c541ca8e5ca4c6cba0aceda83d23dc3 --- /dev/null +++ b/BasicList/src/Result/index.less @@ -0,0 +1,58 @@ +@import '~antd/lib/style/themes/default.less'; + +.result { + width: 72%; + margin: 0 auto; + text-align: center; + @media screen and (max-width: @screen-xs) { + width: 100%; + } + + .icon { + margin-bottom: 24px; + font-size: 72px; + line-height: 72px; + + & > .success { + color: @success-color; + } + + & > .error { + color: @error-color; + } + } + + .title { + margin-bottom: 16px; + color: @heading-color; + font-weight: 500; + font-size: 24px; + line-height: 32px; + } + + .description { + margin-bottom: 24px; + color: @text-color-secondary; + font-size: 14px; + line-height: 22px; + } + + .extra { + padding: 24px 40px; + text-align: left; + background: #fafafa; + border-radius: @border-radius-sm; + + @media screen and (max-width: @screen-xs) { + padding: 18px 20px; + } + } + + .actions { + margin-top: 32px; + + button:not(:last-child) { + margin-right: 8px; + } + } +} diff --git a/BasicList/src/Result/index.tsx b/BasicList/src/Result/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..63ba3ebc21b6db3f3e254e5686e48d37ea3e4ffc --- /dev/null +++ b/BasicList/src/Result/index.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Icon } from 'antd'; +import styles from './index.less'; + +export interface ResultProps { + actions?: React.ReactNode; + className?: string; + description?: React.ReactNode; + extra?: React.ReactNode; + style?: React.CSSProperties; + title?: React.ReactNode; + type: 'success' | 'error'; +} + +const Result: React.SFC = ({ + className, + type, + title, + description, + extra, + actions, + ...restProps +}) => { + const iconMap = { + error: , + success: , + }; + const clsString = classNames(styles.result, className); + return ( +
+
{iconMap[type]}
+
{title}
+ {description &&
{description}
} + {extra &&
{extra}
} + {actions &&
{actions}
} +
+ ); +}; + +export default Result; diff --git a/BasicList/src/_mock.js b/BasicList/src/_mock.ts similarity index 90% rename from BasicList/src/_mock.js rename to BasicList/src/_mock.ts index 5c0578b52afee7e587cc3334c17e907d990c339f..70894bc755b8cd6a6f8173d85a6fa9b3a93677f5 100644 --- a/BasicList/src/_mock.js +++ b/BasicList/src/_mock.ts @@ -1,3 +1,5 @@ +import { BasicListItemDataType } from './data'; + const titles = [ 'Alipay', 'Angular', @@ -46,7 +48,7 @@ const user = [ '仲尼', ]; -function fakeList(count) { +function fakeList(count: number): BasicListItemDataType[] { const list = []; for (let i = 0; i < count; i += 1) { list.push({ @@ -54,13 +56,13 @@ function fakeList(count) { owner: user[i % 10], title: titles[i % 8], avatar: avatars[i % 8], - cover: parseInt(i / 4, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], + cover: parseInt(i / 4 + '', 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], status: ['active', 'exception', 'normal'][i % 3], percent: Math.ceil(Math.random() * 50) + 50, logo: avatars[i % 8], href: 'https://ant.design', - updatedAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i), - createdAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i), + updatedAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i).getTime(), + createdAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i).getTime(), subDescription: desc[i % 5], description: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', @@ -94,9 +96,9 @@ function fakeList(count) { return list; } -let sourceData; +let sourceData: Array; -function getFakeList(req, res) { +function getFakeList(req: { query: any }, res: { json: (arg0: BasicListItemDataType[]) => void }) { const params = req.query; const count = params.count * 1 || 20; @@ -106,7 +108,7 @@ function getFakeList(req, res) { return res.json(result); } -function postFakeList(req, res) { +function postFakeList(req: { body: any }, res: { json: (arg0: BasicListItemDataType[]) => void }) { const { /* url = '', */ body } = req; // const params = getUrlParams(url); const { method, id } = body; @@ -126,7 +128,7 @@ function postFakeList(req, res) { break; case 'post': result.unshift({ - body, + ...body, id: `fake-list-${result.length}`, createdAt: new Date().getTime(), }); diff --git a/BasicList/src/data.d.ts b/BasicList/src/data.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..9796369f880bbd79449c0f6b89c5f0d5b2388c3b --- /dev/null +++ b/BasicList/src/data.d.ts @@ -0,0 +1,29 @@ +export interface Member { + avatar: string; + name: string; + id: string; +} + +export interface BasicListItemDataType { + id: string; + owner: string; + title: string; + avatar: string; + cover: string; + status: 'normal' | 'exception' | 'active' | 'success'; + percent: number; + logo: string; + href: string; + body?: any; + updatedAt: number; + createdAt: number; + subDescription: string; + description: string; + activeUser: number; + newUser: number; + star: number; + like: number; + message: number; + content: string; + members: Member[]; +} diff --git a/BasicList/src/index.js b/BasicList/src/index.tsx similarity index 59% rename from BasicList/src/index.js rename to BasicList/src/index.tsx index 054d96361422fb21cb505f0179045ad673d4efcc..1da98f5cdf7011145a7e3094d6f4824e9f4ba22b 100644 --- a/BasicList/src/index.js +++ b/BasicList/src/index.tsx @@ -1,5 +1,4 @@ -import React, { PureComponent } from 'react'; -import { FormattedMessage } from 'umi-plugin-react/locale'; +import React, { Component } from 'react'; import { findDOMNode } from 'react-dom'; import moment from 'moment'; import { connect } from 'dva'; @@ -21,8 +20,12 @@ import { DatePicker, Select, } from 'antd'; - -import { Result } from 'ant-design-pro'; +import { FormComponentProps } from 'antd/lib/form'; +import { IStateType } from './model'; +import { Dispatch } from 'redux'; +import { BasicListItemDataType } from './data'; +import Result from './Result'; +import { GridContent } from '@ant-design/pro-layout'; import styles from './style.less'; @@ -32,13 +35,35 @@ const RadioGroup = Radio.Group; const SelectOption = Select.Option; const { Search, TextArea } = Input; -@connect(({ BLOCK_NAME_CAMEL_CASE, loading }) => ({ - BLOCK_NAME_CAMEL_CASE, - loading: loading.models.BLOCK_NAME_CAMEL_CASE, -})) -@Form.create() -class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { - state = { visible: false, done: false }; +interface PAGE_NAME_UPPER_CAMEL_CASEProps extends FormComponentProps { + BLOCK_NAME_CAMEL_CASE: IStateType; + dispatch: Dispatch; + loading: boolean; +} +interface PAGE_NAME_UPPER_CAMEL_CASEState { + visible: boolean; + done: boolean; + current?: Partial; +} +@connect( + ({ + BLOCK_NAME_CAMEL_CASE, + loading, + }: { + BLOCK_NAME_CAMEL_CASE: IStateType; + loading: { + models: { [key: string]: boolean }; + }; + }) => ({ + BLOCK_NAME_CAMEL_CASE, + loading: loading.models.BLOCK_NAME_CAMEL_CASE, + }) +) +class PAGE_NAME_UPPER_CAMEL_CASE extends Component< + PAGE_NAME_UPPER_CAMEL_CASEProps, + PAGE_NAME_UPPER_CAMEL_CASEState +> { + state: PAGE_NAME_UPPER_CAMEL_CASEState = { visible: false, done: false, current: undefined }; formLayout = { labelCol: { span: 7 }, @@ -62,7 +87,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { }); }; - showEditModal = item => { + showEditModal = (item: BasicListItemDataType) => { this.setState({ visible: true, current: item, @@ -70,7 +95,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { }; handleDone = () => { - setTimeout(() => this.addBtn.blur(), 0); + setTimeout(() => this.addBtn && this.addBtn.blur(), 0); this.setState({ done: false, visible: false, @@ -78,20 +103,20 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { }; handleCancel = () => { - setTimeout(() => this.addBtn.blur(), 0); + setTimeout(() => this.addBtn && this.addBtn.blur(), 0); this.setState({ visible: false, }); }; - handleSubmit = e => { + handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const { dispatch, form } = this.props; const { current } = this.state; const id = current ? current.id : ''; - setTimeout(() => this.addBtn.blur(), 0); - form.validateFields((err, fieldsValue) => { + setTimeout(() => this.addBtn && this.addBtn.blur(), 0); + form.validateFields((err: string | undefined, fieldsValue: BasicListItemDataType) => { if (err) return; this.setState({ done: true, @@ -103,13 +128,14 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { }); }; - deleteItem = id => { + deleteItem = (id: string) => { const { dispatch } = this.props; dispatch({ type: 'BLOCK_NAME_CAMEL_CASE/submit', payload: { id }, }); }; + addBtn: HTMLButtonElement | undefined | null; render() { const { @@ -119,9 +145,10 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { const { form: { getFieldDecorator }, } = this.props; + const { visible, done, current = {} } = this.state; - const editAndDelete = (key, currentItem) => { + const editAndDelete = (key: string, currentItem: BasicListItemDataType) => { if (key === 'edit') this.showEditModal(currentItem); else if (key === 'delete') { Modal.confirm({ @@ -138,7 +165,11 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { ? { footer: null, onCancel: this.handleDone } : { okText: '保存', onOk: this.handleSubmit, onCancel: this.handleCancel }; - const Info = ({ title, value, bordered }) => ( + const Info: React.SFC<{ + title: React.ReactNode; + value: React.ReactNode; + bordered?: boolean; + }> = ({ title, value, bordered }) => (
{title}

{value}

@@ -164,7 +195,11 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { total: 50, }; - const ListContent = ({ data: { owner, createdAt, percent, status } }) => ( + const ListContent = ({ + data: { owner, createdAt, percent, status }, + }: { + data: BasicListItemDataType; + }) => (
Owner @@ -180,10 +215,12 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
); - const MoreBtn = props => ( + const MoreBtn: React.SFC<{ + current: BasicListItemDataType; + }> = ({ current }) => ( editAndDelete(key, props.current)}> + editAndDelete(key, current)}> 编辑 删除 @@ -254,73 +291,76 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { }; return ( -
- - - - - - - - - - - - - + +
+ + + + + + + + + + + + + - } - style={{ marginTop: 24 }} - bodyStyle={{ padding: '0 32px 40px 32px' }} - extra={extraContent} - > - - ( - { - e.preventDefault(); - this.showEditModal(item); - }} - > - 编辑 - , - , - ]} - > - } - title={{item.title}} - description={item.subDescription} - /> - - - )} - /> - -
+ + ( + { + e.preventDefault(); + this.showEditModal(item); + }} + > + 编辑 + , + , + ]} + > + } + title={{item.title}} + description={item.subDescription} + /> + + + )} + /> + +
+ + (func: (state: IStateType) => T) => T } +) => void; + +export interface ModelType { + namespace: string; + state: IStateType; + effects: { + fetch: Effect; + appendFetch: Effect; + submit: Effect; + }; + reducers: { + queryList: Reducer; + appendList: Reducer; + }; +} + +const Model: ModelType = { namespace: 'BLOCK_NAME_CAMEL_CASE', state: { @@ -44,7 +71,7 @@ export default { list: action.payload, }; }, - appendList(state, action) { + appendList(state = { list: [] }, action) { return { ...state, list: state.list.concat(action.payload), @@ -52,3 +79,5 @@ export default { }, }, }; + +export default Model; diff --git a/BasicList/src/service.js b/BasicList/src/service.ts similarity index 67% rename from BasicList/src/service.js rename to BasicList/src/service.ts index 1f7cfc8aad178c98d0e24c3d777064ab7092bcf3..05a787f3ead9cacd5ecbbffc5ae14d2705f43773 100644 --- a/BasicList/src/service.js +++ b/BasicList/src/service.ts @@ -1,12 +1,17 @@ import request from 'umi-request'; +import { BasicListItemDataType } from './data'; -export async function queryFakeList(params) { +interface ParamsType extends Partial { + count?: number; +} + +export async function queryFakeList(params: ParamsType) { return request('/api/BLOCK_NAME/fake_list', { params, }); } -export async function removeFakeList(params) { +export async function removeFakeList(params: ParamsType) { const { count = 5, ...restParams } = params; return request('/api/BLOCK_NAME/fake_list', { method: 'POST', @@ -20,7 +25,7 @@ export async function removeFakeList(params) { }); } -export async function addFakeList(params) { +export async function addFakeList(params: ParamsType) { const { count = 5, ...restParams } = params; return request('/api/BLOCK_NAME/fake_list', { method: 'POST', @@ -34,7 +39,7 @@ export async function addFakeList(params) { }); } -export async function updateFakeList(params) { +export async function updateFakeList(params: ParamsType) { const { count = 5, ...restParams } = params; return request('/api/BLOCK_NAME/fake_list', { method: 'POST', diff --git a/package.json b/package.json index 60eae38b6841389954106e1d70b13eef4125e009..d366bd1a5e450899d671df6b96e7845e19d2e6d7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "scripts": { - "dev": "cross-env PAGES_PATH='BasicForm/src' umi dev", + "dev": "cross-env PAGES_PATH='BasicList/src' umi dev", "lint:style": "stylelint \"src/**/*.less\" --syntax less", "lint": "eslint --ext .js src mock tests && npm run lint:style", "lint:fix": "eslint --fix --ext .js src mock tests && npm run lint:style", @@ -49,4 +49,4 @@ "dependencies": { "cross-env": "^5.2.0" } -} +} \ No newline at end of file