Commit 4b592c1d authored by super-lin0's avatar super-lin0

add list block

parent 59636700
{ {
"name": "nemean-cli", "name": "nemean-cli",
"version": "0.2.7", "version": "0.2.8",
"main": "src/index.js", "main": "src/index.js",
"bin": "bin/npmrc.js", "bin": "bin/npmrc.js",
"license": "ISC", "license": "ISC",
......
...@@ -3,10 +3,9 @@ import defaultSettings from './defaultSettings'; // https://umijs.org/config/ ...@@ -3,10 +3,9 @@ import defaultSettings from './defaultSettings'; // https://umijs.org/config/
import slash from 'slash2'; import slash from 'slash2';
import webpackPlugin from './plugin.config'; import webpackPlugin from './plugin.config';
const { pwa, primaryColor } = defaultSettings; const { pwa, primaryColor } = defaultSettings; // preview.pro.ant.design only do not use in your production ;
// preview.pro.ant.design only do not use in your production ;
// preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 // preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env; const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env;
const isAntDesignProPreview = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site'; const isAntDesignProPreview = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site';
const plugins: IPlugin[] = [ const plugins: IPlugin[] = [
...@@ -37,8 +36,7 @@ const plugins: IPlugin[] = [ ...@@ -37,8 +36,7 @@ const plugins: IPlugin[] = [
importWorkboxFrom: 'local', importWorkboxFrom: 'local',
}, },
} }
: false, : false, // default close dll, because issue https://github.com/ant-design/ant-design-pro/issues/4665
// default close dll, because issue https://github.com/ant-design/ant-design-pro/issues/4665
// dll features https://webpack.js.org/plugins/dll-plugin/ // dll features https://webpack.js.org/plugins/dll-plugin/
// dll: { // dll: {
// include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'], // include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
...@@ -116,6 +114,12 @@ export default { ...@@ -116,6 +114,12 @@ export default {
icon: 'smile', icon: 'smile',
component: './Welcome', component: './Welcome',
}, },
{
name: 'list',
icon: 'smile',
path: '/list/table/list',
component: './list/table/list',
},
{ {
component: './404', component: './404',
}, },
...@@ -126,7 +130,6 @@ export default { ...@@ -126,7 +130,6 @@ export default {
}, },
], ],
}, },
{ {
component: './404', component: './404',
}, },
...@@ -151,7 +154,7 @@ export default { ...@@ -151,7 +154,7 @@ export default {
resourcePath: string; resourcePath: string;
}, },
_: string, _: string,
localName: string, localName: string
) => { ) => {
if ( if (
context.resourcePath.includes('node_modules') || context.resourcePath.includes('node_modules') ||
......
import { Request, Response } from 'express';
import { parse } from 'url';
import { TableListItem, TableListParams } from './data.d';
// mock tableListDataSource
let tableListDataSource: TableListItem[] = [];
for (let i = 0; i < 8; i += 1) {
tableListDataSource.push({
key: i,
disabled: i % 6 === 0,
href: 'https://ant.design',
avatar: [
'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
][i % 2],
name: `TradeCode ${i}`,
title: `一个任务名称 ${i}`,
owner: '曲丽丽',
desc: '这是一段描述',
callNo: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 4,
updatedAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
createdAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
progress: Math.ceil(Math.random() * 100),
});
}
function getRule(req: Request, res: Response, u: string) {
let url = u;
if (!url || Object.prototype.toString.call(url) !== '[object String]') {
// eslint-disable-next-line prefer-destructuring
url = req.url;
}
const params = (parse(url, true).query as unknown) as TableListParams;
let dataSource = tableListDataSource;
if (params.sorter) {
const s = params.sorter.split('_');
dataSource = dataSource.sort((prev, next) => {
if (s[1] === 'descend') {
return next[s[0]] - prev[s[0]];
}
return prev[s[0]] - next[s[0]];
});
}
if (params.status) {
const status = params.status.split(',');
let filterDataSource: TableListItem[] = [];
status.forEach((s: string) => {
filterDataSource = filterDataSource.concat(
dataSource.filter(item => {
if (parseInt(`${item.status}`, 10) === parseInt(s.split('')[0], 10)) {
return true;
}
return false;
}),
);
});
dataSource = filterDataSource;
}
if (params.name) {
dataSource = dataSource.filter(data => data.name.indexOf(params.name) > -1);
}
let pageSize = 10;
if (params.pageSize) {
pageSize = parseInt(`${params.pageSize}`, 0);
}
const result = {
list: dataSource,
pagination: {
total: dataSource.length,
pageSize,
current: parseInt(`${params.currentPage}`, 10) || 1,
},
};
return res.json(result);
}
function postRule(req: Request, res: Response, u: string, b: Request) {
let url = u;
if (!url || Object.prototype.toString.call(url) !== '[object String]') {
// eslint-disable-next-line prefer-destructuring
url = req.url;
}
const body = (b && b.body) || req.body;
const { method, name, desc, key } = body;
switch (method) {
/* eslint no-case-declarations:0 */
case 'delete':
tableListDataSource = tableListDataSource.filter(item => key.indexOf(item.key) === -1);
break;
case 'post':
const i = Math.ceil(Math.random() * 10000);
tableListDataSource.unshift({
key: i,
href: 'https://ant.design',
avatar: [
'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
][i % 2],
name: `TradeCode ${i}`,
title: `一个任务名称 ${i}`,
owner: '曲丽丽',
desc,
callNo: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 2,
updatedAt: new Date(),
createdAt: new Date(),
progress: Math.ceil(Math.random() * 100),
});
break;
case 'update':
tableListDataSource = tableListDataSource.map(item => {
if (item.key === key) {
return { ...item, desc, name };
}
return item;
});
break;
default:
break;
}
const result = {
list: tableListDataSource,
pagination: {
total: tableListDataSource.length,
},
};
return res.json(result);
}
export default {
'GET /api/rule': getRule,
'POST /api/rule': postRule,
};
import { Form, Input, Modal } from 'antd';
import { FormComponentProps } from 'antd/es/form';
import React from 'react';
const FormItem = Form.Item;
interface CreateFormProps extends FormComponentProps {
modalVisible: boolean;
handleAdd: (fieldsValue: { desc: string }) => void;
handleModalVisible: () => void;
}
const CreateForm: React.FC<CreateFormProps> = props => {
const { modalVisible, form, handleAdd, handleModalVisible } = props;
const okHandle = () => {
form.validateFields((err, fieldsValue) => {
if (err) return;
form.resetFields();
handleAdd(fieldsValue);
});
};
return (
<Modal
destroyOnClose
title="新建规则"
visible={modalVisible}
onOk={okHandle}
onCancel={() => handleModalVisible()}
>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="描述">
{form.getFieldDecorator('desc', {
rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
})(<Input placeholder="请输入" />)}
</FormItem>
</Modal>
);
};
export default Form.create<CreateFormProps>()(CreateForm);
@import '~antd/es/style/themes/default.less';
.standardTable {
:global {
.ant-table-pagination {
margin-top: 24px;
}
}
.tableAlert {
margin-bottom: 16px;
}
}
import { Alert, Table } from 'antd';
import { ColumnProps, TableRowSelection, TableProps } from 'antd/es/table';
import React, { Component, Fragment } from 'react';
import { TableListItem } from '../../data.d';
import styles from './index.less';
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
export interface StandardTableProps<T> extends Omit<TableProps<T>, 'columns'> {
columns: StandardTableColumnProps[];
data: {
list: TableListItem[];
pagination: StandardTableProps<TableListItem>['pagination'];
};
selectedRows: TableListItem[];
onSelectRow: (rows: any) => void;
}
export interface StandardTableColumnProps extends ColumnProps<TableListItem> {
needTotal?: boolean;
total?: number;
}
function initTotalList(columns: StandardTableColumnProps[]) {
if (!columns) {
return [];
}
const totalList: StandardTableColumnProps[] = [];
columns.forEach(column => {
if (column.needTotal) {
totalList.push({ ...column, total: 0 });
}
});
return totalList;
}
interface StandardTableState {
selectedRowKeys: string[];
needTotalList: StandardTableColumnProps[];
}
class StandardTable extends Component<StandardTableProps<TableListItem>, StandardTableState> {
static getDerivedStateFromProps(nextProps: StandardTableProps<TableListItem>) {
// clean state
if (nextProps.selectedRows.length === 0) {
const needTotalList = initTotalList(nextProps.columns);
return {
selectedRowKeys: [],
needTotalList,
};
}
return null;
}
constructor(props: StandardTableProps<TableListItem>) {
super(props);
const { columns } = props;
const needTotalList = initTotalList(columns);
this.state = {
selectedRowKeys: [],
needTotalList,
};
}
handleRowSelectChange: TableRowSelection<TableListItem>['onChange'] = (
selectedRowKeys,
selectedRows: TableListItem[],
) => {
const currySelectedRowKeys = selectedRowKeys as string[];
let { needTotalList } = this.state;
needTotalList = needTotalList.map(item => ({
...item,
total: selectedRows.reduce((sum, val) => sum + parseFloat(val[item.dataIndex || 0]), 0),
}));
const { onSelectRow } = this.props;
if (onSelectRow) {
onSelectRow(selectedRows);
}
this.setState({ selectedRowKeys: currySelectedRowKeys, needTotalList });
};
handleTableChange: TableProps<TableListItem>['onChange'] = (
pagination,
filters,
sorter,
...rest
) => {
const { onChange } = this.props;
if (onChange) {
onChange(pagination, filters, sorter, ...rest);
}
};
cleanSelectedKeys = () => {
if (this.handleRowSelectChange) {
this.handleRowSelectChange([], []);
}
};
render() {
const { selectedRowKeys, needTotalList } = this.state;
const { data, rowKey, ...rest } = this.props;
const { list = [], pagination = false } = data || {};
const paginationProps = pagination
? {
showSizeChanger: true,
showQuickJumper: true,
...pagination,
}
: false;
const rowSelection: TableRowSelection<TableListItem> = {
selectedRowKeys,
onChange: this.handleRowSelectChange,
getCheckboxProps: (record: TableListItem) => ({
disabled: record.disabled,
}),
};
return (
<div className={styles.standardTable}>
<div className={styles.tableAlert}>
<Alert
message={
<Fragment>
已选择 <a style={{ fontWeight: 600 }}>{selectedRowKeys.length}</a>&nbsp;&nbsp;
{needTotalList.map((item, index) => (
<span style={{ marginLeft: 8 }} key={item.dataIndex}>
{item.title}
总计&nbsp;
<span style={{ fontWeight: 600 }}>
{item.render
? item.render(item.total, item as TableListItem, index)
: item.total}
</span>
</span>
))}
<a onClick={this.cleanSelectedKeys} style={{ marginLeft: 24 }}>
清空
</a>
</Fragment>
}
type="info"
showIcon
/>
</div>
<Table
rowKey={rowKey || 'key'}
rowSelection={rowSelection}
dataSource={list}
pagination={paginationProps}
onChange={this.handleTableChange}
{...rest}
/>
</div>
);
}
}
export default StandardTable;
import { Button, DatePicker, Form, Input, Modal, Radio, Select, Steps } from 'antd';
import React, { Component } from 'react';
import { FormComponentProps } from 'antd/es/form';
import { TableListItem } from '../data.d';
export interface FormValueType extends Partial<TableListItem> {
target?: string;
template?: string;
type?: string;
time?: string;
frequency?: string;
}
export interface UpdateFormProps extends FormComponentProps {
handleUpdateModalVisible: (flag?: boolean, formVals?: FormValueType) => void;
handleUpdate: (values: FormValueType) => void;
updateModalVisible: boolean;
values: Partial<TableListItem>;
}
const FormItem = Form.Item;
const { Step } = Steps;
const { TextArea } = Input;
const { Option } = Select;
const RadioGroup = Radio.Group;
export interface UpdateFormState {
formVals: FormValueType;
currentStep: number;
}
class UpdateForm extends Component<UpdateFormProps, UpdateFormState> {
static defaultProps = {
handleUpdate: () => {},
handleUpdateModalVisible: () => {},
values: {},
};
formLayout = {
labelCol: { span: 7 },
wrapperCol: { span: 13 },
};
constructor(props: UpdateFormProps) {
super(props);
this.state = {
formVals: {
name: props.values.name,
desc: props.values.desc,
key: props.values.key,
target: '0',
template: '0',
type: '1',
time: '',
frequency: 'month',
},
currentStep: 0,
};
}
handleNext = (currentStep: number) => {
const { form, handleUpdate } = this.props;
const { formVals: oldValue } = this.state;
form.validateFields((err, fieldsValue) => {
if (err) return;
const formVals = { ...oldValue, ...fieldsValue };
this.setState(
{
formVals,
},
() => {
if (currentStep < 2) {
this.forward();
} else {
handleUpdate(formVals);
}
},
);
});
};
backward = () => {
const { currentStep } = this.state;
this.setState({
currentStep: currentStep - 1,
});
};
forward = () => {
const { currentStep } = this.state;
this.setState({
currentStep: currentStep + 1,
});
};
renderContent = (currentStep: number, formVals: FormValueType) => {
const { form } = this.props;
if (currentStep === 1) {
return [
<FormItem key="target" {...this.formLayout} label="监控对象">
{form.getFieldDecorator('target', {
initialValue: formVals.target,
})(
<Select style={{ width: '100%' }}>
<Option value="0">表一</Option>
<Option value="1">表二</Option>
</Select>,
)}
</FormItem>,
<FormItem key="template" {...this.formLayout} label="规则模板">
{form.getFieldDecorator('template', {
initialValue: formVals.template,
})(
<Select style={{ width: '100%' }}>
<Option value="0">规则模板一</Option>
<Option value="1">规则模板二</Option>
</Select>,
)}
</FormItem>,
<FormItem key="type" {...this.formLayout} label="规则类型">
{form.getFieldDecorator('type', {
initialValue: formVals.type,
})(
<RadioGroup>
<Radio value="0"></Radio>
<Radio value="1"></Radio>
</RadioGroup>,
)}
</FormItem>,
];
}
if (currentStep === 2) {
return [
<FormItem key="time" {...this.formLayout} label="开始时间">
{form.getFieldDecorator('time', {
rules: [{ required: true, message: '请选择开始时间!' }],
})(
<DatePicker
style={{ width: '100%' }}
showTime
format="YYYY-MM-DD HH:mm:ss"
placeholder="选择开始时间"
/>,
)}
</FormItem>,
<FormItem key="frequency" {...this.formLayout} label="调度周期">
{form.getFieldDecorator('frequency', {
initialValue: formVals.frequency,
})(
<Select style={{ width: '100%' }}>
<Option value="month"></Option>
<Option value="week"></Option>
</Select>,
)}
</FormItem>,
];
}
return [
<FormItem key="name" {...this.formLayout} label="规则名称">
{form.getFieldDecorator('name', {
rules: [{ required: true, message: '请输入规则名称!' }],
initialValue: formVals.name,
})(<Input placeholder="请输入" />)}
</FormItem>,
<FormItem key="desc" {...this.formLayout} label="规则描述">
{form.getFieldDecorator('desc', {
rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
initialValue: formVals.desc,
})(<TextArea rows={4} placeholder="请输入至少五个字符" />)}
</FormItem>,
];
};
renderFooter = (currentStep: number) => {
const { handleUpdateModalVisible, values } = this.props;
if (currentStep === 1) {
return [
<Button key="back" style={{ float: 'left' }} onClick={this.backward}>
上一步
</Button>,
<Button key="cancel" onClick={() => handleUpdateModalVisible(false, values)}>
取消
</Button>,
<Button key="forward" type="primary" onClick={() => this.handleNext(currentStep)}>
下一步
</Button>,
];
}
if (currentStep === 2) {
return [
<Button key="back" style={{ float: 'left' }} onClick={this.backward}>
上一步
</Button>,
<Button key="cancel" onClick={() => handleUpdateModalVisible(false, values)}>
取消
</Button>,
<Button key="submit" type="primary" onClick={() => this.handleNext(currentStep)}>
完成
</Button>,
];
}
return [
<Button key="cancel" onClick={() => handleUpdateModalVisible(false, values)}>
取消
</Button>,
<Button key="forward" type="primary" onClick={() => this.handleNext(currentStep)}>
下一步
</Button>,
];
};
render() {
const { updateModalVisible, handleUpdateModalVisible, values } = this.props;
const { currentStep, formVals } = this.state;
return (
<Modal
width={640}
bodyStyle={{ padding: '32px 40px 48px' }}
destroyOnClose
title="规则配置"
visible={updateModalVisible}
footer={this.renderFooter(currentStep)}
onCancel={() => handleUpdateModalVisible(false, values)}
afterClose={() => handleUpdateModalVisible()}
>
<Steps style={{ marginBottom: 28 }} size="small" current={currentStep}>
<Step title="基本信息" />
<Step title="配置规则属性" />
<Step title="设定调度周期" />
</Steps>
{this.renderContent(currentStep, formVals)}
</Modal>
);
}
}
export default Form.create<UpdateFormProps>()(UpdateForm);
export interface TableListItem {
key: number;
disabled?: boolean;
href: string;
avatar: string;
name: string;
title: string;
owner: string;
desc: string;
callNo: number;
status: number;
updatedAt: Date;
createdAt: Date;
progress: number;
}
export interface TableListPagination {
total: number;
pageSize: number;
current: number;
}
export interface TableListData {
list: TableListItem[];
pagination: Partial<TableListPagination>;
}
export interface TableListParams {
sorter: string;
status: string;
name: string;
pageSize: number;
currentPage: number;
}
import {
Badge,
Button,
Card,
Col,
DatePicker,
Divider,
Dropdown,
Form,
Icon,
Input,
InputNumber,
Menu,
Row,
Select,
message,
} from 'antd';
import React, { Component, Fragment } from 'react';
import { Dispatch, Action } from 'redux';
import { FormComponentProps } from 'antd/es/form';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { SorterResult } from 'antd/es/table';
import { connect } from 'dva';
import moment from 'moment';
import { StateType } from './model';
import CreateForm from './components/CreateForm';
import StandardTable, { StandardTableColumnProps } from './components/StandardTable';
import UpdateForm, { FormValueType } from './components/UpdateForm';
import { TableListItem, TableListPagination, TableListParams } from './data.d';
import styles from './style.less';
const FormItem = Form.Item;
const { Option } = Select;
const getValue = (obj: { [x: string]: string[] }) =>
Object.keys(obj)
.map(key => obj[key])
.join(',');
type IStatusMapType = 'default' | 'processing' | 'success' | 'error';
const statusMap = ['default', 'processing', 'success', 'error'];
const status = ['关闭', '运行中', '已上线', '异常'];
interface TableListProps extends FormComponentProps {
dispatch: Dispatch<
Action<
| 'listAndtableAndlist/add'
| 'listAndtableAndlist/fetch'
| 'listAndtableAndlist/remove'
| 'listAndtableAndlist/update'
>
>;
loading: boolean;
listAndtableAndlist: StateType;
}
interface TableListState {
modalVisible: boolean;
updateModalVisible: boolean;
expandForm: boolean;
selectedRows: TableListItem[];
formValues: { [key: string]: string };
stepFormValues: Partial<TableListItem>;
}
/* eslint react/no-multi-comp:0 */
@connect(
({
listAndtableAndlist,
loading,
}: {
listAndtableAndlist: StateType;
loading: {
models: {
[key: string]: boolean;
};
};
}) => ({
listAndtableAndlist,
loading: loading.models.listAndtableAndlist,
}),
)
class TableList extends Component<TableListProps, TableListState> {
state: TableListState = {
modalVisible: false,
updateModalVisible: false,
expandForm: false,
selectedRows: [],
formValues: {},
stepFormValues: {},
};
columns: StandardTableColumnProps[] = [
{
title: '规则名称',
dataIndex: 'name',
},
{
title: '描述',
dataIndex: 'desc',
},
{
title: '服务调用次数',
dataIndex: 'callNo',
sorter: true,
align: 'right',
render: (val: string) => `${val} 万`,
// mark to display a total number
needTotal: true,
},
{
title: '状态',
dataIndex: 'status',
filters: [
{
text: status[0],
value: '0',
},
{
text: status[1],
value: '1',
},
{
text: status[2],
value: '2',
},
{
text: status[3],
value: '3',
},
],
render(val: IStatusMapType) {
return <Badge status={statusMap[val]} text={status[val]} />;
},
},
{
title: '上次调度时间',
dataIndex: 'updatedAt',
sorter: true,
render: (val: string) => <span>{moment(val).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '操作',
render: (text, record) => (
<Fragment>
<a onClick={() => this.handleUpdateModalVisible(true, record)}>配置</a>
<Divider type="vertical" />
<a href="">订阅警报</a>
</Fragment>
),
},
];
componentDidMount() {
const { dispatch } = this.props;
dispatch({
type: 'listAndtableAndlist/fetch',
});
}
handleStandardTableChange = (
pagination: Partial<TableListPagination>,
filtersArg: Record<keyof TableListItem, string[]>,
sorter: SorterResult<TableListItem>,
) => {
const { dispatch } = this.props;
const { formValues } = this.state;
const filters = Object.keys(filtersArg).reduce((obj, key) => {
const newObj = { ...obj };
newObj[key] = getValue(filtersArg[key]);
return newObj;
}, {});
const params: Partial<TableListParams> = {
currentPage: pagination.current,
pageSize: pagination.pageSize,
...formValues,
...filters,
};
if (sorter.field) {
params.sorter = `${sorter.field}_${sorter.order}`;
}
dispatch({
type: 'listAndtableAndlist/fetch',
payload: params,
});
};
handleFormReset = () => {
const { form, dispatch } = this.props;
form.resetFields();
this.setState({
formValues: {},
});
dispatch({
type: 'listAndtableAndlist/fetch',
payload: {},
});
};
toggleForm = () => {
const { expandForm } = this.state;
this.setState({
expandForm: !expandForm,
});
};
handleMenuClick = (e: { key: string }) => {
const { dispatch } = this.props;
const { selectedRows } = this.state;
if (!selectedRows) return;
switch (e.key) {
case 'remove':
dispatch({
type: 'listAndtableAndlist/remove',
payload: {
key: selectedRows.map(row => row.key),
},
callback: () => {
this.setState({
selectedRows: [],
});
},
});
break;
default:
break;
}
};
handleSelectRows = (rows: TableListItem[]) => {
this.setState({
selectedRows: rows,
});
};
handleSearch = (e: React.FormEvent) => {
e.preventDefault();
const { dispatch, form } = this.props;
form.validateFields((err, fieldsValue) => {
if (err) return;
const values = {
...fieldsValue,
updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
};
this.setState({
formValues: values,
});
dispatch({
type: 'listAndtableAndlist/fetch',
payload: values,
});
});
};
handleModalVisible = (flag?: boolean) => {
this.setState({
modalVisible: !!flag,
});
};
handleUpdateModalVisible = (flag?: boolean, record?: FormValueType) => {
this.setState({
updateModalVisible: !!flag,
stepFormValues: record || {},
});
};
handleAdd = (fields: { desc: any }) => {
const { dispatch } = this.props;
dispatch({
type: 'listAndtableAndlist/add',
payload: {
desc: fields.desc,
},
});
message.success('添加成功');
this.handleModalVisible();
};
handleUpdate = (fields: FormValueType) => {
const { dispatch } = this.props;
dispatch({
type: 'listAndtableAndlist/update',
payload: {
name: fields.name,
desc: fields.desc,
key: fields.key,
},
});
message.success('配置成功');
this.handleUpdateModalVisible();
};
renderSimpleForm() {
const { form } = this.props;
const { getFieldDecorator } = form;
return (
<Form onSubmit={this.handleSearch} layout="inline">
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="规则名称">
{getFieldDecorator('name')(<Input placeholder="请输入" />)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="使用状态">
{getFieldDecorator('status')(
<Select placeholder="请选择" style={{ width: '100%' }}>
<Option value="0">关闭</Option>
<Option value="1">运行中</Option>
</Select>,
)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<span className={styles.submitButtons}>
<Button type="primary" htmlType="submit">
查询
</Button>
<Button style={{ marginLeft: 8 }} onClick={this.handleFormReset}>
重置
</Button>
<a style={{ marginLeft: 8 }} onClick={this.toggleForm}>
展开 <Icon type="down" />
</a>
</span>
</Col>
</Row>
</Form>
);
}
renderAdvancedForm() {
const {
form: { getFieldDecorator },
} = this.props;
return (
<Form onSubmit={this.handleSearch} layout="inline">
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="规则名称">
{getFieldDecorator('name')(<Input placeholder="请输入" />)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="使用状态">
{getFieldDecorator('status')(
<Select placeholder="请选择" style={{ width: '100%' }}>
<Option value="0">关闭</Option>
<Option value="1">运行中</Option>
</Select>,
)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="调用次数">
{getFieldDecorator('number')(<InputNumber style={{ width: '100%' }} />)}
</FormItem>
</Col>
</Row>
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="更新日期">
{getFieldDecorator('date')(
<DatePicker style={{ width: '100%' }} placeholder="请输入更新日期" />,
)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="使用状态">
{getFieldDecorator('status3')(
<Select placeholder="请选择" style={{ width: '100%' }}>
<Option value="0">关闭</Option>
<Option value="1">运行中</Option>
</Select>,
)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="使用状态">
{getFieldDecorator('status4')(
<Select placeholder="请选择" style={{ width: '100%' }}>
<Option value="0">关闭</Option>
<Option value="1">运行中</Option>
</Select>,
)}
</FormItem>
</Col>
</Row>
<div style={{ overflow: 'hidden' }}>
<div style={{ float: 'right', marginBottom: 24 }}>
<Button type="primary" htmlType="submit">
查询
</Button>
<Button style={{ marginLeft: 8 }} onClick={this.handleFormReset}>
重置
</Button>
<a style={{ marginLeft: 8 }} onClick={this.toggleForm}>
收起 <Icon type="up" />
</a>
</div>
</div>
</Form>
);
}
renderForm() {
const { expandForm } = this.state;
return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
}
render() {
const {
listAndtableAndlist: { data },
loading,
} = this.props;
const { selectedRows, modalVisible, updateModalVisible, stepFormValues } = this.state;
const menu = (
<Menu onClick={this.handleMenuClick} selectedKeys={[]}>
<Menu.Item key="remove">删除</Menu.Item>
<Menu.Item key="approval">批量审批</Menu.Item>
</Menu>
);
const parentMethods = {
handleAdd: this.handleAdd,
handleModalVisible: this.handleModalVisible,
};
const updateMethods = {
handleUpdateModalVisible: this.handleUpdateModalVisible,
handleUpdate: this.handleUpdate,
};
return (
<PageHeaderWrapper>
<Card bordered={false}>
<div className={styles.tableList}>
<div className={styles.tableListForm}>{this.renderForm()}</div>
<div className={styles.tableListOperator}>
<Button icon="plus" type="primary" onClick={() => this.handleModalVisible(true)}>
新建
</Button>
{selectedRows.length > 0 && (
<span>
<Button>批量操作</Button>
<Dropdown overlay={menu}>
<Button>
更多操作 <Icon type="down" />
</Button>
</Dropdown>
</span>
)}
</div>
<StandardTable
selectedRows={selectedRows}
loading={loading}
data={data}
columns={this.columns}
onSelectRow={this.handleSelectRows}
onChange={this.handleStandardTableChange}
/>
</div>
</Card>
<CreateForm {...parentMethods} modalVisible={modalVisible} />
{stepFormValues && Object.keys(stepFormValues).length ? (
<UpdateForm
{...updateMethods}
updateModalVisible={updateModalVisible}
values={stepFormValues}
/>
) : null}
</PageHeaderWrapper>
);
}
}
export default Form.create<TableListProps>()(TableList);
import { AnyAction, Reducer } from 'redux';
import { EffectsCommandMap } from 'dva';
import { addRule, queryRule, removeRule, updateRule } from './service';
import { TableListData } from './data.d';
export interface StateType {
data: TableListData;
}
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: StateType) => T) => T },
) => void;
export interface ModelType {
namespace: string;
state: StateType;
effects: {
fetch: Effect;
add: Effect;
remove: Effect;
update: Effect;
};
reducers: {
save: Reducer<StateType>;
};
}
const Model: ModelType = {
namespace: 'listAndtableAndlist',
state: {
data: {
list: [],
pagination: {},
},
},
effects: {
*fetch({ payload }, { call, put }) {
const response = yield call(queryRule, payload);
yield put({
type: 'save',
payload: response,
});
},
*add({ payload, callback }, { call, put }) {
const response = yield call(addRule, payload);
yield put({
type: 'save',
payload: response,
});
if (callback) callback();
},
*remove({ payload, callback }, { call, put }) {
const response = yield call(removeRule, payload);
yield put({
type: 'save',
payload: response,
});
if (callback) callback();
},
*update({ payload, callback }, { call, put }) {
const response = yield call(updateRule, payload);
yield put({
type: 'save',
payload: response,
});
if (callback) callback();
},
},
reducers: {
save(state, action) {
return {
...state,
data: action.payload,
};
},
},
};
export default Model;
import request from '@/utils/request';
import { TableListParams } from './data.d';
export async function queryRule(params: TableListParams) {
return request('/api/rule', {
params,
});
}
export async function removeRule(params: TableListParams) {
return request('/api/rule', {
method: 'POST',
data: {
...params,
method: 'delete',
},
});
}
export async function addRule(params: TableListParams) {
return request('/api/rule', {
method: 'POST',
data: {
...params,
method: 'post',
},
});
}
export async function updateRule(params: TableListParams) {
return request('/api/rule', {
method: 'POST',
data: {
...params,
method: 'update',
},
});
}
@import '~antd/es/style/themes/default.less';
@import './utils/utils.less';
.tableList {
.tableListOperator {
margin-bottom: 16px;
button {
margin-right: 8px;
}
}
}
.tableListForm {
:global {
.ant-form-item {
display: flex;
margin-right: 0;
margin-bottom: 24px;
> .ant-form-item-label {
width: auto;
padding-right: 8px;
line-height: 32px;
}
.ant-form-item-control {
line-height: 32px;
}
}
.ant-form-item-control-wrapper {
flex: 1;
}
}
.submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
}
@media screen and (max-width: @screen-lg) {
.tableListForm :global(.ant-form-item) {
margin-right: 24px;
}
}
@media screen and (max-width: @screen-md) {
.tableListForm :global(.ant-form-item) {
margin-right: 8px;
}
}
.textOverflow() {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
word-break: break-all;
}
.textOverflowMulti(@line: 3, @bg: #fff) {
position: relative;
max-height: @line * 1.5em;
margin-right: -1em;
padding-right: 1em;
overflow: hidden;
line-height: 1.5em;
text-align: justify;
&::before {
position: absolute;
right: 14px;
bottom: 0;
padding: 0 1px;
background: @bg;
content: '...';
}
&::after {
position: absolute;
right: 14px;
width: 1em;
height: 1em;
margin-top: 0.2em;
background: white;
content: '';
}
}
// mixins for clearfix
// ------------------------
.clearfix() {
zoom: 1;
&::before,
&::after {
display: table;
content: ' ';
}
&::after {
clear: both;
height: 0;
font-size: 0;
visibility: hidden;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment