Commit 87cbbe84 authored by LeeJiancong's avatar LeeJiancong
parents 5e9bf539 127e149c
......@@ -123,7 +123,7 @@ export function onRouteChange({ routes, matchedRoutes, location, action }) {
return;
}
// 无权限访问时
history.replace('/memberCenter/noAuth')
// history.replace('/memberCenter/noAuth')
} else {
history.replace('/user/login')
}
......
......@@ -2,6 +2,7 @@ import React from 'react';
import SchemaForm, {
IAntdSchemaFormProps, createVirtualBox, registerVirtualBox, Schema, SchemaField, FormButtonGroup, Reset, createControllerBox,
} from '@formily/antd';
import { Input } from '@formily/antd-components';
import { Button, Space, Row, Col } from 'antd';
import styled from 'styled-components'
import CustomUpload from './components/CustomUpload';
......@@ -98,7 +99,8 @@ const NiceForm: React.FC<NiceFormProps> = props => {
CircleBox,
SchemaFormButtonGroup,
FlexBox,
Phone,
Phone,
Input,
};
const defineComponents = Object.assign(customComponents, components);
......
/*
* @Author: XieZhiXiong
* @Date: 2020-08-20 16:15:59
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-08-21 17:08:26
* @Description: 基于 NormalTable 简单的可编辑列 Table
*/
import React, { useContext, useState, useEffect, useRef } from 'react';
import {
Card,
Input,
Button,
Form,
message,
} from 'antd';
import { StandardTableProps, EditableCellProps, EditableColumns } from './interface';
import NormalTable from './NormalTable';
const EditableContext = React.createContext<any>({});
interface EditableRowProps {
index: number;
}
const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell: React.FC<EditableCellProps> = ({
title,
editable,
children,
dataIndex,
index,
record,
rules = [],
addonAfter = null,
onSave,
onValidateError,
...restProps
}) => {
const [editing, setEditing] = useState(true);
const inputRef = useRef();
const form = useContext(EditableContext);
const inputId = `${dataIndex}-${index}`; // 拼接 name-index,不然全部展示输入框会警告 id 不唯一的问题
useEffect(() => {
if (editing) {
// inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
const save = async e => {
try {
const values = await form.validateFields();
// toggleEdit();
if (onSave) {
onSave({
...record,
[dataIndex]: values[inputId],
});
}
} catch (errInfo) {
if (onValidateError) {
onValidateError(errInfo);
}
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={inputId}
rules={rules}
initialValue={record[dataIndex]}
>
<Input
ref={inputRef}
onPressEnter={save}
onBlur={save}
addonAfter={addonAfter}
/>
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }} onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const EditableCellTable: React.FC<StandardTableProps> = props => {
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
return (
<NormalTable
components={components}
rowClassName={() => 'editable-row'}
{...props}
/>
);
};
export default React.memo(EditableCellTable);
\ No newline at end of file
/*
* @Author: XieZhiXiong
* @Date: 2020-08-20 16:15:59
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-08-21 17:07:35
* @Description: 简单封装了分页事件的 Table
*/
import React from 'react';
import { Table } from 'antd';
import classNames from 'classnames';
import { StandardTableProps } from './interface';
import styles from './index.less';
export default class NormalTable extends React.PureComponent<StandardTableProps> {
state = {
page: 1,
size: 10,
};
handlePaginationChange = (page: number, size: number) => {
const { pagination = {}, onPaginationChange } = this.props;
const { current, pageSize } = pagination;
// 内部自己维护 page、size, 单独控制当前页 或 当前页数
if (!('current' in pagination)) {
this.setState({ page: current });
}
if (!('pageSize' in pagination)) {
this.setState({ size: pageSize });
}
if (onPaginationChange) {
onPaginationChange(page, size);
}
};
render() {
const { page, size } = this.state;
const {
columns,
dataSource,
rowKey = 'id',
pagination = {},
loading,
className,
onPaginationChange,
...restProps
} = this.props;
const newPagination: any = pagination ? {
current: page,
pageSize: size,
showSizeChanger: true,
showQuickJumper: true,
onChange: this.handlePaginationChange,
onShowSizeChange: this.handlePaginationChange,
size: 'small',
showTotal: () => `共 ${pagination.total || 0} 条`,
...pagination,
} : false;
return (
<div className={classNames(className)}>
<Table
rowKey={rowKey}
columns={columns}
dataSource={dataSource}
loading={loading}
pagination={newPagination}
{...restProps}
/>
</div>
)
}
}
\ No newline at end of file
import React from 'react';
import { Table } from 'antd';
import classNames from 'classnames';
import { TableProps, TablePaginationConfig, ColumnType } from 'antd/lib/table';
import { PaginationProps } from 'antd/lib/pagination';
import styles from './index.less';
import NormalTable from './NormalTable';
import EditableCellTable from './EditableCellTable';
export interface StandardTableProps extends TableProps<any> {
pagination: TablePaginationConfig;
onPaginationChange?: (page: number, size: number) => void;
};
export default class StandardTable extends React.PureComponent<StandardTableProps> {
state = {
page: 1,
size: 10,
};
handlePaginationChange = (page: number, size: number) => {
const { pagination = {}, onPaginationChange } = this.props;
const { current, pageSize } = pagination;
// 内部自己维护 page、size, 单独控制当前页 或 当前页数
if (!('current' in pagination)) {
this.setState({ page: current });
}
if (!('pageSize' in pagination)) {
this.setState({ size: pageSize });
}
if (onPaginationChange) {
onPaginationChange(page, size);
}
};
render() {
const { page, size } = this.state;
const {
columns,
dataSource,
rowKey = 'id',
pagination = {},
loading,
className,
onPaginationChange,
...restProps
} = this.props;
const newPagination: any = pagination ? {
current: page,
pageSize: size,
showSizeChanger: true,
showQuickJumper: true,
onChange: this.handlePaginationChange,
onShowSizeChange: this.handlePaginationChange,
size: 'small',
showTotal: () => `共 ${pagination.total || 0} 条`,
...pagination,
} : false;
return (
<div className={classNames(className)}>
<Table
rowKey={rowKey}
columns={columns}
dataSource={dataSource}
loading={loading}
pagination={newPagination}
{...restProps}
/>
</div>
)
}
export {
NormalTable as default,
EditableCellTable,
}
\ No newline at end of file
import { TableProps, TablePaginationConfig, ColumnType } from 'antd/lib/table';
export interface StandardTableProps extends TableProps<any> {
pagination?: TablePaginationConfig;
onPaginationChange?: (page: number, size: number) => void;
}
export interface EditableCellProps {
onSave?: (row: {[key: string]: any}) => void,
onValidateError?: (error: {[key: string]: any}) => void,
record?: any;
index?: number;
dataIndex: string | number;
title?: React.ReactNode;
editable?: boolean;
children?: React.ReactNode;
rules?: Array<any>;
addonAfter?: React.ReactNode;
}
interface EditableColumns extends ColumnType<any> {
dataIndex?: string | number;
editable?: boolean;
rules?: Array<any>;
}
\ No newline at end of file
......@@ -259,8 +259,8 @@ h6 {
padding: 4px 11px;
}
.editable-row .ant-form-explain {
.editable-row .ant-form-item-explain {
position: absolute;
top: 100%;
font-size: 12px;
margin-top: -4px;
}
\ No newline at end of file
......@@ -71,24 +71,16 @@
&-right {
flex: 1;
text-align: right;
.saveBtn {
color: #fff;
background: @main-color
}
}
}
.extra {
margin-bottom: 48px;
&-main {
display: flex;
&-content {
position: relative;
flex: 1;
height: 104px;
&:nth-last-of-type(1) {
flex: 2.5;
......@@ -99,6 +91,9 @@
display: flex;
justify-content: center;
align-items: center;
padding: 35px 0 28px;
background: rgba(250, 251, 252, 1);
border-radius: 4px;
.icon {
position: absolute;
......
import React, { ReactNode, useState, useRef } from 'react'
import { history } from 'umi'
import { Button, Popconfirm, Card, Input, Slider } from 'antd'
import { ColumnType } from 'antd/lib/table/interface'
import classNames from 'classnames'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import { PlayCircleOutlined, ContainerOutlined } from '@ant-design/icons'
import { StandardTable } from 'god'
import styles from './addEquity.less'
import React, { useState } from 'react';
import { history } from 'umi';
import { Button, Popconfirm, Card, Input, Slider, Space, message } from 'antd';
import classNames from 'classnames';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { ContainerOutlined } from '@ant-design/icons';
import { usePageStatus } from '@/hooks/usePageStatus';
import { PublicApi } from '@/services/api';
import StatusSwitch from '@/components/StatusSwitch';
import { EditableCellTable } from '@/components/StandardTable';
import { EditableCellProps, EditableColumns } from '@/components/StandardTable/interface';
import styles from './addEquity.less';
const data = [
{
......@@ -32,8 +35,11 @@ const data = [
]
const addEquity: React.FC<[]> = () => {
const ref = useRef({})
const [thresholdValue, setThresholdValue] = useState(10000)
const { id } = usePageStatus();
const [dataSource, setDataSource] = useState([]);
const [thresholdValue, setThresholdValue] = useState(100);
const [submitLoading, setSubmitLoading] = useState(false);
const marks = {
0: '0',
......@@ -44,18 +50,16 @@ const addEquity: React.FC<[]> = () => {
50000: '50000',
};
const columns: ColumnType<any>[] = [
const columns: EditableColumns[] = [
{
title: 'ID',
dataIndex: 'id',
align: 'center',
key: 'id',
},
{
title: '会员权益名称',
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: '会员权益说明',
......@@ -67,40 +71,30 @@ const addEquity: React.FC<[]> = () => {
title: '权益获取方式',
dataIndex: 'type',
align: 'center',
key: 'type',
},
{
title: '参数设置方式',
dataIndex: 'setting',
align: 'center',
key: 'setting',
},
{
title: '参数',
dataIndex: 'params',
align: 'center',
key: 'params',
width: '20%',
editable: true,
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
key: 'status',
render: (text: any, record: any) => {
let component: ReactNode = null
component = (
<Popconfirm
title="确定要执行这个操作?"
onConfirm={confirm}
onCancel={cancel}
okText="是"
cancelText="否"
>
<Button type="link" onClick={() => handleModify(record)} style={record.status === 1 ? { color: '#00B37A' } : { color: 'red' }}>{record.status === 1 ? '有效' : '无效'} <PlayCircleOutlined /></Button>
</Popconfirm>
)
return component
}
render: (text: any, record: any) => (
<StatusSwitch
handleConfirm={() => handleConfirm(record)}
record={record}
fieldNames="status"
/>
)
}
];
......@@ -118,26 +112,75 @@ const addEquity: React.FC<[]> = () => {
})
}
const handleSee = (record: any) => {
}
const confirm = () => {
const handleConfirm = record => {
console.log('confirm')
}
const cancel = () => {
console.log('cancel')
}
};
const handleModify = (record: object) => {
// 通过传入的params字符串判断是修改那种类型的数据
console.log('执行状态修改', record)
}
};
const handleInput = (e: any) => {
console.log(e)
}
const handleThresholdChange = e => {
const { value } = e.target;
setThresholdValue(+value);
};
// 重新保存 dataSource
const handleSave = row => {
console.log('save', row)
};
const updateThreshold = () => {
return PublicApi.postMemberManageLevelSetpoint({
id,
levelUpPoint: thresholdValue,
}, {
ctlType: 'none',
});
};
const handleSubmit = async () => {
const promises = [updateThreshold()];
setSubmitLoading(true);
try {
const res = await Promise.all(promises);
message.success('保存成功');
} catch (errInfo) {
}
setSubmitLoading(false);
};
const newColumns: any = columns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record, index): EditableCellProps => ({
onSave: handleSave,
record,
index,
dataIndex: col.dataIndex,
title: col.title,
editable: col.editable || false,
rules: [
{
required: true,
message: '请输入相应值',
},
{
pattern: /^([0]|[1-9]+[0-9]*)(\.[0-9]+)?$/,
message: '请输入整数或小数',
},
],
addonAfter: '%',
}),
};
});
return (
<PageHeaderWrapper
......@@ -180,50 +223,66 @@ const addEquity: React.FC<[]> = () => {
</div>
</div>
<div className={styles['headerMain-right']}>
<Button className={styles.saveBtn} icon={<ContainerOutlined />}>保存</Button>
<Button
type="primary"
icon={<ContainerOutlined />}
loading={submitLoading}
onClick={handleSubmit}
>
保存
</Button>
</div>
</div>
}
>
<Card>
<StandardTable
tableProps={{
rowKey: 'id',
pagination: false,
}}
columns={columns}
currentRef={ref}
fetchTableData={(params: any) => fetchData(params)}
controlRender={
<>
<div className={styles.extra}>
<h3>升级阀值</h3>
<div className={styles['extra-main']}>
<div className={classNames(styles['extra-main-content'], styles.left)}>
<div className={styles.icon}>当前阀值</div>
<div className={styles.input}>
<div className={styles['input-main']}>
<Input
className={styles['input-main-com']}
value={thresholdValue}
onChange={(e: any) => { e.persist(); setThresholdValue(e.target.value) }}
/>
</div>
</div>
</div>
<div className={classNames(styles['extra-main-content'], styles.right)}>
<Slider
marks={marks}
max={50000}
value={thresholdValue}
onChange={(val: number) => setThresholdValue(val)}
/>
</div>
<Card
title="升级阀值"
headStyle={{
borderBottom: 'none',
}}
bordered={false}
>
<div className={styles.extra}>
<div className={styles['extra-main']}>
<div className={classNames(styles['extra-main-content'], styles.left)}>
<div className={styles.icon}>当前阀值</div>
<div className={styles.input}>
<div className={styles['input-main']}>
<Input
className={styles['input-main-com']}
value={`${thresholdValue}`}
onChange={handleThresholdChange}
/>
</div>
</div>
<h3>会员权益</h3>
</>
}
</div>
<div className={classNames(styles['extra-main-content'], styles.right)}>
<Slider
marks={marks}
max={50000}
value={thresholdValue}
disabled
/>
</div>
</div>
</div>
</Card>
<Card
title="会员权益"
headStyle={{
borderBottom: 'none',
}}
style={{
marginTop: 24,
}}
bordered={false}
>
<EditableCellTable
dataSource={data}
columns={newColumns}
loading={false}
pagination={null}
/>
</Card>
</PageHeaderWrapper>
......
import React, { useRef } from 'react';
import { history } from 'umi';
import { Button, Card } from 'antd';
import { Button, Card, message } from 'antd';
import { StandardTable } from 'god';
import { ColumnType } from 'antd/lib/table/interface';
import { createFormActions } from '@formily/antd';
......@@ -118,12 +118,19 @@ const MemberLevel: React.FC<[]> = () => {
},
];
// status: 0-无效 1-生效
const handleModify = record => {
const disabled = record.status === 0;
PublicApi.postMemberManageLevelStatus({
id: record.id,
status: record.status === 1 ? 0 : 1,
status: disabled ? 1 : 0,
}).then(res => {
if (res.code === 1000) return ref.current.reload();
if (res.code === 1000) {
const msg = disabled ? '启用成功' : '禁用成功'
message.success(msg);
ref.current.reload();
}
});
};
......@@ -140,6 +147,7 @@ const MemberLevel: React.FC<[]> = () => {
onSubmit={values => ref.current.reload(values)}
effects={($, actions) => {
$('onFormInputChange').subscribe(state => {
console.log('InputChange')
ref.current.reload(state.values);
});
useStateFilterSearchLinkageEffect(
......
......@@ -15,7 +15,7 @@ export const levelSchema: ISchema = {
grid: true,
},
properties: {
name: {
cond: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
......@@ -24,6 +24,33 @@ export const levelSchema: ISchema = {
},
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
flexWrap: 'nowrap',
},
colStyle: {
marginLeft: 20,
},
},
properties: {
roleName: {
type: 'string',
'x-component': 'Input',
'x-component-props': {
placeholder: '角色名称',
},
},
submit: {
'x-component': 'Submit',
'x-component-props': {
children: '查询',
},
},
},
},
},
},
},
......
import React, { useContext, useState, useEffect, useRef } from 'react';
import React, { useState, useEffect } from 'react';
import {
Card,
Input,
Button,
Form,
message,
} from 'antd';
import { ColumnType } from 'antd/lib/table/interface';
import { PublicApi } from '@/services/api';
import { VIP_RULE_TRANSACTION, VIP_RULE_LOGIN, VIP_RULE_COMMENT } from '@/constants';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { ContainerOutlined } from '@ant-design/icons';
import StandardTable from '@/components/StandardTable';
const EditableContext = React.createContext<any>({});
interface EditableRowProps {
index: number;
}
const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
interface EditableCellProps {
title: React.ReactNode;
editable: boolean;
children: React.ReactNode;
dataIndex: string;
index: number;
record: any;
rules: any;
handleSave: (record: any) => void;
addonAfter: React.ReactNode,
}
const EditableCell: React.FC<EditableCellProps> = ({
title,
editable,
children,
dataIndex,
index,
record,
rules = [],
addonAfter = null,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(true);
const inputRef = useRef();
const form = useContext(EditableContext);
const inputId = `${dataIndex}-${index}`; // 拼接 name-index,不然全部展示输入框会警告 id 不唯一的问题
useEffect(() => {
if (editing) {
// inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
const save = async e => {
try {
const values = await form.validateFields();
// toggleEdit();
handleSave({
...record,
[dataIndex]: values[inputId],
});
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={inputId}
rules={rules}
initialValue={record[dataIndex]}
>
<Input
ref={inputRef}
onPressEnter={save}
onBlur={save}
addonAfter={addonAfter}
/>
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }} onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
interface Columns extends ColumnType<any> {
editable?: boolean;
rules?: Array<any>;
}
import { EditableCellTable } from '@/components/StandardTable';
import { EditableCellProps, EditableColumns } from '@/components/StandardTable/interface';
const MemberUpgradeRule: React.FC<[]> = () => {
const PAGE_SIZE = 10;
const [page, setPage] = useState(1);
const [size, setSize] = useState(10);
const [size, setSize] = useState(PAGE_SIZE);
const [total, setTotal] = useState(0);
const [dataSource, setDataSource] = useState([]);
const [listLoading, setListLoading] = useState(true);
const [submitLoading, setSubmitLoading] = useState(false);
const [submitDisabled, setSubmitDisabled] = useState(false);
const getRuleList = async (params) => {
setListLoading(true);
......@@ -147,7 +40,7 @@ const MemberUpgradeRule: React.FC<[]> = () => {
});
}, [page, size]);
const columns: Columns[] = [
const columns: EditableColumns[] = [
{
title: 'ID',
dataIndex: 'id',
......@@ -167,6 +60,7 @@ const MemberUpgradeRule: React.FC<[]> = () => {
{
title: '可获取的分值',
dataIndex: 'point',
align: 'center',
width: '30%',
editable: true,
},
......@@ -190,6 +84,11 @@ const MemberUpgradeRule: React.FC<[]> = () => {
setDataSource(newData);
};
// 表单元素校验失败事件
const handleValidateError = errInfo => {
// do something
};
const handleSubmit = async () => {
if (!dataSource.length) {
return;
......@@ -213,30 +112,23 @@ const MemberUpgradeRule: React.FC<[]> = () => {
setSubmitLoading(false);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const rulesMap = {
[VIP_RULE_TRANSACTION]: [
{
pattern: /^([0]|[1-9]+[0-9]*)(\.[0-9]+)?$/,
message: '请输入正确的格式',
message: '请输入整数或小数',
},
],
[VIP_RULE_LOGIN]: [
{
pattern: /^[0]$|^[1-9]+[0-9]*$/,
message: '请输入正确的格式',
message: '请输入整数数值',
},
],
[VIP_RULE_COMMENT]: [
{
pattern: /^[0]$|^[1-9]+[0-9]*$/,
message: '请输入正确的格式',
message: '请输入整数数值',
},
],
};
......@@ -247,8 +139,9 @@ const MemberUpgradeRule: React.FC<[]> = () => {
}
return {
...col,
onCell: (record, index) => ({
handleSave,
onCell: (record, index): EditableCellProps => ({
onSave: handleSave,
onValidateError: handleValidateError,
record,
index,
dataIndex: col.dataIndex,
......@@ -273,6 +166,7 @@ const MemberUpgradeRule: React.FC<[]> = () => {
type="primary"
icon={<ContainerOutlined />}
loading={submitLoading}
disabled={submitDisabled}
onClick={handleSubmit}
>
保存
......@@ -280,17 +174,9 @@ const MemberUpgradeRule: React.FC<[]> = () => {
}
>
<Card>
<div className="editable-row">
<div className="ant-form-explain">
123
</div>
</div>
<StandardTable
<EditableCellTable
dataSource={dataSource}
columns={newColumns}
components={components}
rowClassName={() => 'editable-row'}
loading={listLoading}
pagination={{
pageSize: size,
......
......@@ -338,8 +338,28 @@ export const getQueryStringParams = (url?: string) => {
return queryString.parse(searchParam)
}
/**
* 节流函数
* @param {func} func 需要执行的函数
* @param {number} delay 间隔
*/
export function debounce(func: (any?) => void, delay: number) {
let timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
}
}
export default {
isArray,
isObject,
omit
omit,
debounce,
}
\ No newline at end of file
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