Commit c31233c9 authored by tjy's avatar tjy

调整会员

parent 53199f9e
......@@ -37,26 +37,26 @@ const memberAbility =
{
path: '/memberAbility/manage/memberPr1',
name: 'memberPr1',
component: '@/pages/member/memberPr/index',
component: '@/pages/member/memberPr1/index',
},
{
path: '/memberAbility/manage/auditPr1',
name: 'auditPr1',
hideInMenu: true,
hidePageHeader: true,
component: '@/pages/member/memberPr/auditPr1',
component: '@/pages/member/memberPr1/auditPr1',
},
{
path: '/memberAbility/manage/memberPr2',
name: 'memberPr2',
component: '@/pages/member/memberPr/index',
component: '@/pages/member/memberPr2/index',
},
{
path: '/memberAbility/manage/auditPr2',
name: 'auditPr2',
hideInMenu: true,
hidePageHeader: true,
component: '@/pages/member/memberPr/auditPr2',
component: '@/pages/member/memberPr2/auditPr2',
},
{
path: '/memberAbility/manage/memberPrConfirm',
......
import React from 'react'
import { Link } from 'umi'
import { EyeOutlined } from '@ant-design/icons'
import { Button } from 'antd'
export interface EyePreviewProps {
url?: string,
type?: 'button' | 'link',
handleClick?()
}
const EyePreview:React.FC<EyePreviewProps> = (props) => {
return (
props.type === 'link' ?
<Link to={props.url || ''}>
{props.children} <EyeOutlined />
</Link>
:
<Button onClick={props.handleClick} type='link'>
{props.children} <EyeOutlined />
</Button>
)
}
EyePreview.defaultProps = {
type: 'link'
}
export default EyePreview
\ No newline at end of file
import React from 'react'
import { Popconfirm, Button } from 'antd'
import { PlayCircleOutlined } from '@ant-design/icons'
export interface StatusSwitchProps {
record: any,
handleConfirm?(),
handleCancel?()
}
const StatusSwitch:React.FC<StatusSwitchProps> = (props) => {
const { record } = props
return (
<Popconfirm
title="确定要执行这个操作?"
onConfirm={props.handleConfirm}
onCancel={props.handleCancel}
okText="是"
cancelText="否"
>
<Button type="link" style={record.state===1?{color:'#00B37A'}:{color:'red'}}>{record.state===1?'有效':'无效'} <PlayCircleOutlined /></Button>
</Popconfirm>
)
}
StatusSwitch.defaultProps = {}
export default StatusSwitch
\ No newline at end of file
import { createFormActions, FormEffectHooks, FormPath } from '@formily/antd'
import { useLinkageUtils } from '@/utils/formEffectUtils'
const { onFormInit$ } = FormEffectHooks
/**
* @description 处理异步请求的下拉选择
* @param name 待处理的表单路径
* @param service 触发的异步函数, 需返回一个{label: any, value: any}形式的数组
*/
export const useAsyncInitSelect = (name: string[], service?: () => Promise<any>) => {
const { dispatch, setFieldState } = createFormActions()
const linkage = useLinkageUtils()
onFormInit$().subscribe(() => {
setFieldState(name, state => {
FormPath.setIn(state, 'props.x-props.hasFeedback', true)
})
name.forEach(v => linkage.loaded(v))
service().then(res => {
name.forEach(v => {
linkage.loaded(v)
linkage.enum(v, res[v])
})
//请求结束可以dispatch一个自定义事件收尾,方便后续针对该事件做联动
dispatch('requestAsyncSelect', {
name,
payload: res
})
}).catch(err => {
// linkage.loaded(name)
// linkage.enum(name, [])
})
})
}
\ No newline at end of file
import { createFormActions, FormEffectHooks, FormPath } from '@formily/antd'
import { useLinkageUtils } from '@/utils/formEffectUtils'
const { onFormInit$ } = FormEffectHooks
/**
* @description 处理异步请求的下拉选择
* @param name 待处理的表单路径
* @param service 触发的异步函数, 需返回一个{label: any, value: any}形式的数组
*/
export const useAsyncSelect = (name, service: () => Promise<any[]>) => {
const { dispatch, setFieldState } = createFormActions()
const linkage = useLinkageUtils()
onFormInit$().subscribe(() => {
setFieldState(name, state => {
FormPath.setIn(state, 'props.x-props.hasFeedback', true)
})
linkage.loading(name)
service().then(res => {
linkage.loaded(name)
linkage.enum(name, res)
//请求结束可以dispatch一个自定义事件收尾,方便后续针对该事件做联动
dispatch('requestAsyncSelect', {
name,
payload: res
})
}).catch(err => {
linkage.loaded(name)
linkage.enum(name, [])
})
})
}
\ No newline at end of file
import { usePageStatus } from '@/hooks/usePageStatus'
import { useEffect, useState } from 'react'
/**
* 初始化表单数据, 可传入给NiceForm的initialValues
* @param service 必须保证返回数据中有data属性 并且匹配NiceForm
*/
export const useInitValue = (service) => {
const { id } = usePageStatus()
const [state, setState] = useState<any>(null)
useEffect(() => {
if (id) {
service({id}).then(({data}) => {
setState(data)
})
}
}, [])
return state
}
\ No newline at end of file
import { FormEffectHooks } from '@formily/antd'
import { useLinkageUtils } from '@/utils/formEffectUtils'
const { onFieldValueChange$ } = FormEffectHooks
/**
* @description 用于同步表单的值
* @param target 同步的目标路径
* @param syncArr 被同步的表单字段
*/
export const useSyncValues = (target: string, syncArr: string[]) => {
const linkage = useLinkageUtils()
onFieldValueChange$(target).subscribe(state => {
syncArr.forEach(v => {
linkage.value(v, state.value)
})
})
}
\ No newline at end of file
import React, { useState } from 'react';
import { IApiRequest } from '@/utils/request';
export interface IHttpRequestReturn<T> {
data: T | null,
loading: boolean,
err: any,
run(params?: any)
}
/**
* 简易版本的useRequest hooks, 用于处理带有loading的业务场景
* @auth xjm
*/
export function useHttpRequest<T>(api: (params?, config?) => Promise<T>, config?: IApiRequest): IHttpRequestReturn<T> {
const [loading, setLoading] = useState(false)
const [data, setData] = useState<T | null>(null)
const [err, setErr] = useState()
const run = (params) => {
setLoading(true)
api(params).then((res: any) => {
setData(res.data)
}).catch(err => {
setErr(err)
}).finally(() => {
setTimeout(() => {
setLoading(false)
}, 200)
})
}
return {
data,
loading,
err,
run
}
}
\ No newline at end of file
import { history } from 'umi'
import { useState } from 'react'
export enum PageStatus {
ADD,
EDIT,
PREVIEW
}
export const usePageStatus = () => {
const { preview, id = '' } = history.location.query
// 默认预览状态
let pageStatus = PageStatus.PREVIEW
if (preview === '1') {
pageStatus = PageStatus.PREVIEW
} else {
if (id) {
pageStatus = PageStatus.EDIT
} else {
pageStatus = PageStatus.ADD
}
}
return {
pageStatus,
id,
preview
}
}
\ No newline at end of file
import { useState } from 'react'
import { TableRowSelection } from 'antd/es/table/interface'
interface useRowSelectionTableCtl {
selectRow: any[],
selectedRowKeys: any[],
setSelectRow(rows: any[]),
setSelectedRowKeys(rows: any)
}
interface useRowSelectionOptions {
type?: 'checkbox' | 'radio'
}
/**
* 用于处理table 多选或者单选时的hooks
* @auth xjm
*/
export const useRowSelectionTable = (options: useRowSelectionOptions = {}): [TableRowSelection<any>, useRowSelectionTableCtl] => {
const { type = 'checkbox' } = options
const [selectRow, setSelectRow] = useState<any[]>([]) // 模态框选择的行数据
const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>(() => [])
const rowSelection = {
selectedRowKeys: selectedRowKeys,
type,
onChange: (selectedRowKeys: any, selectedRows: any) => {
setSelectRow(selectedRows);
setSelectedRowKeys(selectedRowKeys);
}
}
return [rowSelection, { selectRow, setSelectRow, selectedRowKeys, setSelectedRowKeys }]
}
\ No newline at end of file
This diff is collapsed.
......@@ -20,6 +20,7 @@ import {
import { StandardTable } from 'god';
import { ColumnType } from 'antd/lib/table/interface';
import style from './index.less';
import EyePreview from '@/components/EyePreview';
import { PublicApi } from '@/services/api';
import { timeRange } from '@/utils/index';
......@@ -62,16 +63,11 @@ const auditList: React.FC<PageProps> = props => {
key: 'name',
render: (text: any, record: any) => {
return (
<div className={style.nameCell}>
<div
className={style.nameCellTitle}
onClick={() => handleChange(record, 'check')}
>
{text}&nbsp;
<EyeOutlined />
</div>
<div className={style[`levelIcon${record.level}`]}></div>
</div>
<EyePreview
url={`/memberCenter/tranactionAbility/stockSellStorage/addWarehouse?id=${record.id}&preview=1`}
>
{text}
</EyePreview>
);
},
},
......
import React, { useState, useEffect, useRef, ReactNode } from 'react';
import { history } from 'umi';
import { Tabs, Badge, Button, Card, Row, Col, message, Upload } from 'antd';
import { Badge, Button, Card, message } from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import {
ContainerOutlined,
PlusOutlined,
SaveOutlined,
} from '@ant-design/icons';
import { SaveOutlined } from '@ant-design/icons';
import { createFormActions } from '@formily/antd';
import { StandardTable } from 'god';
import { ColumnType } from 'antd/lib/table/interface';
import {
IFormFilter,
IButtonFilter,
} from 'god/dist/src/standard-table/TableController';
import ReutrnEle from '@/components/ReturnEle';
import styles from './index.less';
import NiceForm from '@/components/NiceForm';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { initDetailSchema } from './schema';
import style from './index.less';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { useAsyncInitSelect } from '@/formSchema/effects/useAsyncInitSelect';
import { PublicApi } from '@/services/api';
const { TabPane } = Tabs;
const addSchemaAction = createFormActions();
const formActions = createFormActions();
const addMember: React.FC<any> = props => {
const ref = useRef({});
const selectList: any = [
{
label: '',
// (
// <>
// <img src={ChinaImg} style={{ width: 24, height: 17 }} /> +86
// </>
// )
value: '1',
},
];
/* 会员类型、会员角色、会员等级、注册手机号选项 */
const ref = useRef<any>({});
const [memberItems, setMemberItems] = useState<any>({});
const data = [
......@@ -99,6 +76,12 @@ const addMember: React.FC<any> = props => {
},
];
useEffect(() => {
PublicApi.getMemberMaintenanceAddpageitems().then(res => {
setMemberItems(res.data);
});
}, []);
// 模拟请求
const fetchData = (params: any) => {
return new Promise((resolve, reject) => {
......@@ -117,22 +100,25 @@ const addMember: React.FC<any> = props => {
console.log(values);
};
// 处理数据
const processData = (data: any) => {
for (let elem of data) {
elem.label = elem.text;
elem.value = elem.id;
}
// 会员类型、会员角色、会员等级选项
const fetchSelectOptions = async () => {
const { data } = await PublicApi.getMemberMaintenanceAddpageitems();
return {
memberTypeId: fetchSomeOptions(data.memberTypes),
roleId: fetchSomeOptions(data.memberRoles),
level: fetchSomeOptions(data.memberLevels),
};
};
useEffect(() => {
PublicApi.getMemberMaintenanceAddpageitems().then(res => {
processData(res.data.memberLevels);
processData(res.data.memberRoles);
processData(res.data.memberTypes);
setMemberItems(res.data);
});
}, ['memberItems']);
// 获取手机code
const fetchTelCode = async () => {
const { data } = await PublicApi.getManageGetTelCode();
return data;
};
const fetchSomeOptions = data => {
return data.map(v => ({ label: v.text, value: v.id }));
};
const beforeUpload = (file: any) => {
const isJpgOrPng =
......@@ -165,7 +151,7 @@ const addMember: React.FC<any> = props => {
key="1"
type="primary"
icon={<SaveOutlined />}
onClick={() => addSchemaAction.submit()}
onClick={() => formActions.submit()}
>
保存
</Button>,
......@@ -174,7 +160,20 @@ const addMember: React.FC<any> = props => {
<Card>
<NiceForm
onSubmit={handleSubmit}
actions={addSchemaAction}
actions={formActions}
effects={($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
useAsyncInitSelect(
['memberTypeId', 'roleId', 'level'],
fetchSelectOptions,
);
useAsyncSelect('telCode', fetchTelCode);
}}
schema={initDetailSchema(memberItems)}
/>
</Card>
......
This diff is collapsed.
......@@ -303,8 +303,6 @@ const memberMaintain: React.FC<[]> = () => {
]);
useEffect(() => {
// if (!isFirst) return;
// setIsFirst(false);
let timeRanges = timeRange(searchForm.timeRange);
setSearchForm({
...searchForm,
......@@ -312,7 +310,6 @@ const memberMaintain: React.FC<[]> = () => {
endDate: timeRanges.et,
});
ref.current.reload();
// console.log(timeRanges);
}, [searchForm.timeRange]);
useEffect(() => {
......
......@@ -2,57 +2,103 @@ import React from 'react';
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
export const maintianSchema: ISchema = {
export const importSchema: ISchema = {
type: 'object',
properties: {
megaLayout: {
type: 'object',
'x-component': 'mega-layout',
properties: {
search: {
type: 'string',
'x-component': 'Search',
'x-mega-props': {},
topLayout: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
placeholder: '请输入仓位名称',
grid: true,
},
properties: {
ctl: {
type: 'object',
'x-component': 'Children',
'x-component-props': {
children: '{{controllerBtns}}',
},
},
name: {
type: 'string',
'x-component': 'Search',
'x-mega-props': {},
'x-component-props': {
placeholder: '搜索',
},
},
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'mega-layout',
visible: false,
'x-component': 'flex-layout',
'x-component-props': {
inline: true,
rowStyle: {
flexWrap: 'nowrap',
},
colStyle: {
marginLeft: 20,
},
},
properties: {
productName: {
memberType: {
type: 'string',
'x-component-props': {
placeholder: '商品名称',
placeholder: '请选择',
defaultValue: 0,
},
enum: [],
},
productId: {
roleId: {
type: 'string',
'x-component-props': {
placeholder: '商品ID',
placeholder: '请选择',
defaultValue: 0,
},
enum: [],
},
category: {
level: {
type: 'string',
'x-component-props': {
placeholder: '请选择品类',
placeholder: '请选择',
defaultValue: 0,
},
enum: [],
},
brand: {
source: {
type: 'string',
'x-component-props': {
placeholder: '请选择品牌',
placeholder: '请选择',
defaultValue: 0,
},
enum: [],
},
timeRange: {
type: 'string',
'x-component-props': {
placeholder: '请选择',
defaultValue: 0,
},
enum: [
{ label: '时间范围(全部)', value: 0 },
{ label: '今天', value: 1 },
{ label: '一周内', value: 2 },
{ label: '一个月内', value: 3 },
{ label: '三个月内', value: 4 },
{ label: '六个月内', value: 5 },
{ label: '一年内', value: 6 },
{ label: '一年前', value: 7 },
],
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
......@@ -64,8 +110,6 @@ export const maintianSchema: ISchema = {
},
};
const registryPhone = <></>;
const getCompnentValue = (elements: any) => {
let components = {};
for (let item of elements) {
......@@ -78,6 +122,8 @@ const getCompnentValue = (elements: any) => {
listType: 'card',
action: '/api/file/file/upload',
data: { fileType: 2 },
fileList: [],
onChange: file => console.log(file),
};
components[item.fieldName] = {
type: item.fieldType,
......@@ -108,54 +154,69 @@ export const initDetailSchema = (props: any) => {
labelAlign: 'left',
},
properties: {
memberTypes: {
memberTypeId: {
type: 'string',
required: true,
title: '会员类型',
enum: props.memberTypes,
enum: [],
'x-component-props': {
placeholder: '请选择',
},
},
memberRoles: {
roleId: {
type: 'string',
required: true,
title: '会员角色',
enum: props.memberRoles,
enum: [],
'x-component-props': {
placeholder: '请选择',
},
},
memberLevels: {
level: {
type: 'string',
required: true,
title: '会员等级',
enum: [{ label: '1', value: 1 }],
// enum: props.memberLevels,
enum: [],
'x-component-props': {
placeholder: '请选择',
},
},
memberPhone: {
MEGA_LAYOUT1_1: {
type: 'object',
required: true,
title: '注册手机',
'x-component': 'CustomRegistryPhone',
'x-component': 'mega-layout',
'x-component-props': {
dataSource: [
{
text: '+86',
id: 1,
url: require('../../../../../public/static/imgs/level1@2x.png'),
label: '注册手机',
wrapperCol: 24,
required: true,
},
properties: {
MEGA_LAYOUT1_1_1: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
full: true,
},
{
text: '+126',
id: 2,
url: require('../../../../../public/static/imgs/level2@2x.png'),
properties: {
telCode: {
type: 'string',
enum: [],
'x-component-props': {
placeholder: '请选择',
},
required: true,
},
tel: {
type: 'string',
'x-mega-props': { span: 2 },
'x-component-props': {
placeholder: '请输入你的手机号码',
maxLength: 11,
},
required: true,
},
},
],
selectPh: '请选择',
inputPh: '请输入你的手机号码',
},
},
},
memberEmail: {
......
import { createFormActions, FormPath } from '@formily/antd'
export const useLinkageUtils = () => {
const { setFieldState } = createFormActions()
const linkage = (key, defaultValue?) => (path, value?) =>
setFieldState(path, state => {
FormPath.setIn(state, key, value !== undefined ? value : defaultValue)
})
return {
hide: linkage('visible', false),
show: linkage('visible', true),
visible: linkage('visible'),
enum: linkage('props.enum', []),
loading: linkage('loading', true),
loaded: linkage('loading', false),
value: linkage('value')
}
}
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