Commit 8f9958f6 authored by XieZhiXiong's avatar XieZhiXiong

feat: 完成 会员拜访管理 功能

parent 13fb3ee3
......@@ -945,6 +945,36 @@ const MemberRoute: RouterChild = {
},
]
},
// 会员拜访管理
{
path: '/memberCenter/memberAbility/memberVisitManage',
name: 'memberVisitManage',
component: '@/pages/member/memberVisitManage',
},
// 会员拜访管理 - 新增
{
path: '/memberCenter/memberAbility/memberVisitManage/add',
name: 'memberVisitManage.add',
component: '@/pages/member/memberVisitManage/addMemberVisit',
hideInMenu: true,
noMargin: true,
},
// 会员拜访管理 - 修改
{
path: '/memberCenter/memberAbility/memberVisitManage/modify',
name: 'memberVisitManage.modify',
component: '@/pages/member/memberVisitManage/modifyMemberVisit',
hideInMenu: true,
noMargin: true,
},
// 会员拜访管理 - 详情
{
path: '/memberCenter/memberAbility/memberVisitManage/details',
name: 'memberVisitManage.details',
component: '@/pages/member/memberVisitManage/memberVisitDetails',
hideInMenu: true,
noMargin: true,
},
]
}
......
......@@ -155,6 +155,10 @@ export default {
'menu.memberAbility.memberRuleConfiguration.memberFlowRuleAdd': '新建会员管理流程规则配置',
'menu.memberAbility.memberRuleConfiguration.memberFlowRuleEdit': '编辑会员管理流程规则配置',
'menu.memberAbility.memberRuleConfiguration.memberFlowRuleDetail': '查看会员管理流程规则配置',
'menu.memberAbility.memberVisitManage': '会员拜访管理',
'menu.memberAbility.memberVisitManage.add': '新增会员拜访',
'menu.memberAbility.memberVisitManage.modify': '编辑会员拜访',
'menu.memberAbility.memberVisitManage.details': '查看会员拜访',
// 店铺能力
'menu.shopAbility': '店铺',
......
/**
* @Description 会员拜访管理 - 新增
*/
import React from 'react';
import { message } from 'antd';
import { history } from 'umi';
import moment from 'moment';
import { postMemberVisitAddOrUpdate } from '@/services/MemberV2Api';
import MemberVisitForm, { SubmitValue } from './components/MemberVisitForm';
const AddMemberVisit: React.FC<{}> = (props) => {
const handleRoleRuleConfigFormSubmit = (value: SubmitValue): Promise<void> => (
new Promise((resolve, reject) => {
const msg = message.loading({
content: '正在添加,请稍候...',
duration: 0,
});
const { subMember, visitorMember, visitDate, files, ...rest } = value;
postMemberVisitAddOrUpdate({
...rest,
memberId: subMember[0].memberId,
visitorId: visitorMember[0].userId,
visitDate: moment(visitDate).valueOf(),
visitAttachments: files ? files.map((item) => ({
name: item.name,
url: item.url,
})) : [],
}).then((res) => {
if (res.code === 1000) {
resolve();
setTimeout(() => {
history.goBack();
}, 800);
} else {
reject();
}
}).finally(() => {
msg();
});
})
);
return (
<MemberVisitForm
title='新增会员拜访'
onSubmit={handleRoleRuleConfigFormSubmit}
/>
);
};
export default AddMemberVisit;
/*
* @Description: 锚点Card容器
*/
import React from 'react';
import AnchorPage from '@/components/AnchorPage';
import MellowCard, { MellowCardProps } from '@/components/MellowCard';
interface AnchorCardVirtualFieldWrapProps extends MellowCardProps {
/**
* 标题
*/
title: string,
/**
* 锚点key
*/
anchorKey: string,
}
const AnchorCardVirtualFieldWrap = (props) => {
const { children } = props;
const xComponentProps: AnchorCardVirtualFieldWrapProps = props.props['x-component-props'] || {};
const { anchorKey, title, ...rest } = xComponentProps;
return (
<AnchorPage.Item itemKey={anchorKey}>
<MellowCard
title={title}
bodyStyle={{
paddingBottom: 0,
}}
{...rest}
>
{children}
</MellowCard>
</AnchorPage.Item>
);
};
AnchorCardVirtualFieldWrap.isVirtualFieldComponent = true;
export default AnchorCardVirtualFieldWrap;
\ No newline at end of file
/*
* @Description: 被拜访的会员表单项组件
*/
import React, { useState, useEffect } from 'react';
import { Input, Button, Drawer, message } from 'antd';
import { LinkOutlined } from '@ant-design/icons';
import { ColumnType } from 'antd/lib/table/interface';
import { useSchemaProps } from '@formily/antd';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import { getMemberAbilityMaintenancePage } from '@/services/MemberV2Api';
import PolymericTable, { FetchParamsType, FetchResponse } from '@/components/PolymericTable';
import { querySchema } from './schema';
export type MemberType = {
/**
* 会员id
*/
memberId: number,
/**
* 会员名称
*/
name: string,
/**
* 会员类型
*/
memberTypeName: string,
/**
* 会员角色
*/
roleName: string,
/**
* 会员等级
*/
levelTag: string,
}
export type SubMemberValue = MemberType[]
interface MemberVisitedFieldItemProps {
/**
* 值
*/
value: SubMemberValue,
/**
* 选择会员触发事件
*/
onChange?: (value: SubMemberValue) => void,
/**
* 是否是禁用的
*/
disabled?: boolean,
}
type ExtraFetchType = FetchParamsType & {
/**
* 会员角色名称
*/
name: string,
}
const MemberVisitedFieldItem = (props) => {
const { value } = props;
const [visibleDrawer, setVisibleDrawer] = useState(false);
const [rowSelection, rowCtl] = useRowSelectionTable({ type: 'radio', customKey: 'memberId' });
const schemaProps = useSchemaProps();
const componentProps = props.props['x-component-props'] || {};
useEffect(() => {
if (value) {
rowCtl.setSelectRow(value);
rowCtl.setSelectedRowKeys(value.map((item) => item.memberId));
}
}, [value]);
const columns: ColumnType<MemberType>[] = [
{
title: '序号',
dataIndex: 'index',
width: '10%',
render: (_, record, index) => index + 1,
},
{
title: '会员ID',
dataIndex: 'memberId',
width: '15%',
},
{
title: '会员名称',
dataIndex: 'name',
},
{
title: '会员类型',
dataIndex: 'memberTypeName',
},
{
title: '会员角色',
dataIndex: 'roleName',
},
{
title: '会员等级',
dataIndex: 'levelTag',
},
];
const handleVisibleDrawer = (flag?: boolean) => {
setVisibleDrawer(!!flag);
};
const fetchMemberList = async (params: ExtraFetchType) => {
const res = await getMemberAbilityMaintenancePage({
...(params as any),
current: `${params.current}`,
pageSize: `${params.pageSize}`,
});
if (res.code === 1000) {
return res.data;
}
return { data: [], totalCount: 0 };
};
const handleConfirm = () => {
if (!rowCtl.selectRow.length) {
message.warning('请选择会员');
return;
}
if (props.mutators.change) {
props.mutators.change(rowCtl.selectRow);
}
handleVisibleDrawer(false);
};
return (
<>
<Input.Group compact>
<Input
value={value && value.length ? value[0].name : ''}
placeholder="请选择会员"
style={{ width: 'calc(100% - 32px)' }}
disabled
/>
<Button
type="primary"
icon={<LinkOutlined />}
onClick={() => handleVisibleDrawer(true)}
disabled={!schemaProps.editable || componentProps?.disabled}
/>
</Input.Group>
<Drawer
title="选择会员"
visible={visibleDrawer}
width={800}
onClose={() => handleVisibleDrawer(false)}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={() => handleVisibleDrawer(false)} style={{ marginRight: 16 }}>
取消
</Button>
<Button onClick={handleConfirm} type="primary">
确 定
</Button>
</div>
}
bodyStyle={{
paddingBottom: 0,
}}
>
<PolymericTable
rowKey="memberId"
columns={columns}
fetchDataSource={(params) => fetchMemberList(params as ExtraFetchType)}
rowSelection={rowSelection}
defaultPageSize={20}
searchFormProps={{
schema: querySchema,
effects: ($, actions) => {
},
}}
full
/>
</Drawer>
</>
);
};
MemberVisitedFieldItem.isFieldComponent = true;
export default MemberVisitedFieldItem;
import { ISchema } from '@formily/antd';
export const querySchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
'x-mega-props': {
wrapperCol: 12,
},
'x-component': 'Search',
'x-component-props': {
placeholder: '搜索',
align: 'flex-left',
tip: '输入 会员名称 进行搜索',
advanced: false,
},
},
},
};
/*
* @Description: 被拜访的会员表单项组件
*/
import React, { useState, useEffect } from 'react';
import { Input, Button, Drawer, message } from 'antd';
import { LinkOutlined } from '@ant-design/icons';
import { ColumnType } from 'antd/lib/table/interface';
import { useSchemaProps } from '@formily/antd';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import { getMemberUserPage } from '@/services/MemberV2Api';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import PolymericTable, { FetchParamsType, FetchResponse } from '@/components/PolymericTable';
import { querySchema } from './schema';
export type MemberType = {
/**
* 用户id
*/
userId: number
/**
* 账号
*/
account: string
/**
* 姓名
*/
name: string
/**
* 手机号码前缀(国家代码)
*/
countryCode: string
/**
* 手机号码
*/
phone: string
/**
* 最后一次登录时间
*/
lastLoginTime: string
/**
* 所属角色
*/
roleName: string
/**
* 所属组织机构名称
*/
orgName: string
/**
* 状态0-无效1-有效
*/
status: number
}
export type VisitorMemberValue = MemberType[]
interface VisitorMemberFieldItemProps {
/**
* 值
*/
value: VisitorMemberValue,
/**
* 选择会员触发事件
*/
onChange?: (value: VisitorMemberValue) => void,
/**
* 是否是禁用的
*/
disabled?: boolean,
}
type ExtraFetchType = FetchParamsType & {
/**
* 会员角色名称
*/
name: string,
}
const VisitorMemberFieldItem = (props) => {
const { value } = props;
const [visibleDrawer, setVisibleDrawer] = useState(false);
const [rowSelection, rowCtl] = useRowSelectionTable({ type: 'radio', customKey: 'userId' });
const schemaProps = useSchemaProps();
const componentProps = props.props['x-component-props'] || {};
useEffect(() => {
if (value) {
rowCtl.setSelectRow(value);
rowCtl.setSelectedRowKeys(value.map((item) => item.userId));
}
}, [value]);
const columns: ColumnType<MemberType>[] = [
{
title: '序号',
dataIndex: 'index',
width: '10%',
render: (_, record, index) => index + 1,
},
{
title: '姓名',
dataIndex: 'name',
},
{
title: '手机号',
dataIndex: 'phone',
},
{
title: '所属机构',
dataIndex: 'orgName',
},
{
title: '职位',
dataIndex: 'roleName',
},
];
const handleVisibleDrawer = (flag?: boolean) => {
setVisibleDrawer(!!flag);
};
const fetchMemberList = async (params: ExtraFetchType) => {
const res = await getMemberUserPage({
...(params as any),
current: `${params.current}`,
pageSize: `${params.pageSize}`,
});
if (res.code === 1000) {
return res.data;
}
return { data: [], totalCount: 0 };
};
const handleConfirm = () => {
if (!rowCtl.selectRow.length) {
message.warning('请选择会员');
return;
}
if (props.mutators.change) {
props.mutators.change(rowCtl.selectRow);
}
handleVisibleDrawer(false);
};
return (
<>
<Input.Group compact>
<Input
value={value && value.length ? value[0].name : ''}
placeholder="请选择用户"
style={{ width: 'calc(100% - 32px)' }}
disabled
/>
<Button
type="primary"
icon={<LinkOutlined />}
onClick={() => handleVisibleDrawer(true)}
disabled={!schemaProps.editable || componentProps?.disabled}
/>
</Input.Group>
<Drawer
title="选择用户"
visible={visibleDrawer}
width={800}
onClose={() => handleVisibleDrawer(false)}
footer={
<div
style={{
textAlign: 'right',
}}
>
<Button onClick={() => handleVisibleDrawer(false)} style={{ marginRight: 16 }}>
取消
</Button>
<Button onClick={handleConfirm} type="primary">
确 定
</Button>
</div>
}
bodyStyle={{
paddingBottom: 0,
}}
>
<PolymericTable
rowKey="userId"
columns={columns}
fetchDataSource={(params) => fetchMemberList(params as ExtraFetchType)}
rowSelection={rowSelection}
defaultPageSize={20}
searchFormProps={{
schema: querySchema,
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
},
}}
full
/>
</Drawer>
</>
);
};
VisitorMemberFieldItem.isFieldComponent = true;
export default VisitorMemberFieldItem;
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
export const querySchema: ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
columns: 1,
},
properties: {
name: {
type: 'string',
'x-mega-props': {
wrapperCol: 12,
},
'x-component': 'Search',
'x-component-props': {
placeholder: '搜索',
align: 'flex-left',
tip: '输入 姓名 进行搜索',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
full: true,
autoRow: true,
columns: 6,
},
properties: {
orgName: {
type: 'string',
'x-component-props': {
placeholder: '所属机构',
allowClear: true,
},
},
roleName: {
type: 'string',
'x-component-props': {
placeholder: '职位',
allowClear: true,
},
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
},
},
},
},
};
export const MEMBER_VISIT_BASIC_INFO = 'MEMBER_VISIT_BASIC_INFO';
export const MEMBER_VISIT_FILES = 'MEMBER_VISIT_FILES';
export const anchorsArr = [
{
key: MEMBER_VISIT_BASIC_INFO,
name: '基本信息',
},
{
key: MEMBER_VISIT_FILES,
name: '附件',
},
];
\ No newline at end of file
/*
* @Description: 新增/修改 平台会员等级
*/
import React, { useState } from 'react';
import { Button } from 'antd';
import { SaveOutlined } from '@ant-design/icons';
import { createFormActions, FormEffectHooks } from '@formily/antd';
import { Input, DatePicker } from '@formily/antd-components';
import { Prompt } from 'umi';
import { useAsyncInitSelect } from '@/formSchema/effects/useAsyncInitSelect';
import { getMemberVisitVisitTypeItems } from '@/services/MemberV2Api';
import AnchorPage from '@/components/AnchorPage';
import NiceForm from '@/components/NiceForm';
import FormilyUploadFiles from '@/components/UploadFiles/FormilyUploadFiles';
import schema from './schema';
import { anchorsArr } from './config';
import AnchorCardVirtualFieldWrap from './components/AnchorCardVirtualFieldWrap';
import MemberVisitedFieldItem, { SubMemberValue } from './components/SubMemberFieldItem';
import VisitorMemberFieldItem, { VisitorMemberValue } from './components/VisitorMemberFieldItem';
import styles from './index.less';
const formActions = createFormActions();
const {
onFormInit$,
onFormInputChange$,
} = FormEffectHooks;
export type SubmitValueType = {
/**
* 拜访主题
*/
visitTheme: string,
/**
* 会员名称
*/
subMember: SubMemberValue,
/**
* 拜访类型
*/
visitType: number,
/**
* 拜访人
*/
visitorMember: VisitorMemberValue,
/**
* 拜访级别
*/
visitLevel: number,
/**
* 拜访日期
*/
visitDate: string,
/**
* 同行人
*/
peer: string,
/**
* 备注
*/
visitRemark: string,
/**
* 附件
*/
files?: React.ComponentProps<typeof FormilyUploadFiles>['value'],
}
// 暂定
export type SubmitValue = SubmitValueType & {}
interface MemberVisitFormProps {
/**
* title
*/
title: string,
/**
* 数据id
*/
value?: SubmitValueType,
/**
* 点击保存触发事件
*/
onSubmit?: (value: SubmitValue) => Promise<void>,
/**
* 是否可编辑的,默认 true
*/
editable?: boolean,
/**
* 是否禁用部分不可以编辑的表单项,默认 false
*/
cloudy?: boolean,
}
const MemberVisitForm: React.FC<MemberVisitFormProps> = (props) => {
const {
title,
value,
onSubmit,
editable = true,
cloudy = false,
} = props;
const [submitLoading, setSubmitLoading] = useState(false);
const [unsaved, setUnsaved] = useState(false);
const handleSubmit = (values: SubmitValueType) => {
if (onSubmit) {
setSubmitLoading(true);
onSubmit(values)
.then(() => {
setUnsaved(false);
})
.finally(() => {
setSubmitLoading(false);
});
}
};
return (
<div className={styles['role-rule-config-form']}>
<AnchorPage
title={title}
anchors={anchorsArr}
extra={[
(editable
? (
<Button
key="1"
type="primary"
icon={<SaveOutlined />}
loading={submitLoading}
onClick={() => formActions.submit()}
>
保存
</Button>
)
: null
),
]}
>
<NiceForm
previewPlaceholder=" "
onSubmit={handleSubmit}
actions={formActions}
initialValues={value}
components={{
TextArea: Input.TextArea,
DatePicker,
FormilyUploadFiles,
AnchorCardVirtualFieldWrap,
MemberVisitedFieldItem,
VisitorMemberFieldItem,
}}
effects={($, actions) => {
const { setFieldState } = actions;
onFormInit$().subscribe(() => {
if (cloudy) {
actions.setFieldState(
'*(memberApplicableRole)',
(state) => {
state.editable = false;
}
);
}
});
onFormInputChange$().subscribe(() => {
if (!unsaved) {
setUnsaved(true);
}
});
useAsyncInitSelect(
['visitType', 'visitLevel'],
async () => {
const { data, code } = await getMemberVisitVisitTypeItems();
if (code === 1000) {
return {
visitType: data.visitTypes.map((item) => ({ label: item.visitTypeName, value: item.visitType })),
visitLevel: data.visitLevels.map((item) => ({ label: item.visitLevelName, value: item.visitLevel })),
};
}
return {};
},
);
}}
schema={schema}
editable={!!editable}
/>
</AnchorPage>
<Prompt when={unsaved} message="您还有未保存的内容,是否确定要离开?" />
</div>
);
};
export default MemberVisitForm;
import { ISchema } from '@formily/antd';
import themeConfig from '@/../config/lingxi.theme.config';
import { MEMBER_VISIT_BASIC_INFO, MEMBER_VISIT_FILES } from './config';
const schema: ISchema = {
type: 'object',
properties: {
BASIC_INFO: {
type: 'object',
'x-component': 'AnchorCardVirtualFieldWrap',
'x-component-props': {
title: '基本信息',
anchorKey: MEMBER_VISIT_BASIC_INFO,
},
properties: {
MEGA_LADYOUT_1: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
grid: true,
full: true,
columns: 2,
autoRow: true,
labelCol: 6,
labelAlign: 'left',
},
properties: {
visitTheme: {
title: '拜访主题',
type: 'string',
'x-component-props': {
placeholder: '最长40个字符,20个文字',
},
'x-rules': [
{
required: true,
message: '请输入拜访主题',
},
{
limitByte: true, // 自定义校验规则
maxByte: 40,
}
],
},
subMember: {
title: '会员名称',
type: 'array',
required: true,
'x-component': 'MemberVisitedFieldItem',
},
visitType: {
title: '拜访类型',
type: 'string',
enum: [],
required: true,
'x-component-props': {
placeholder: '请选择',
},
},
visitorMember: {
title: '拜访人',
type: 'array',
'x-component': 'VisitorMemberFieldItem',
'x-component-props': {
placeholder: '请选择',
},
},
visitLevel: {
title: '拜访级别',
type: 'string',
enum: [],
required: true,
'x-component-props': {
placeholder: '请选择',
},
},
peer: {
title: '同行人',
type: 'string',
'x-component-props': {
placeholder: '请输入',
},
},
visitDate: {
title: '拜访日期',
type: 'string',
'x-component': 'DatePicker',
'x-component-props': {
placeholder: '请输入',
},
},
visitRemark: {
title: '备注',
type: 'string',
'x-component': 'TextArea',
'x-component-props': {
placeholder: '最长200个字符,100个汉字',
rows: 1,
},
'x-rules': [
{
limitByte: true, // 自定义校验规则
maxByte: 200,
}
],
},
},
},
},
},
VISIT_FILES: {
type: 'object',
'x-component': 'AnchorCardVirtualFieldWrap',
'x-component-props': {
title: '附件',
anchorKey: MEMBER_VISIT_FILES,
style: {
marginTop: themeConfig['@margin-md'],
},
},
properties: {
MEGA_LADYOUT_1: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
grid: true,
full: true,
columns: 2,
autoRow: true,
labelCol: 6,
labelAlign: 'left',
},
properties: {
files: {
type: 'string',
'x-component': 'FormilyUploadFiles',
description: '一次上传一个文件,每个附件大小不能超过 20M',
},
},
},
},
},
},
};
export default schema;
/**
* @Description 会员拜访管理 - 列表
*/
import React, { useState, useRef } from 'react';
import { history } from 'umi';
import { Card, Button, Space, Popconfirm, Modal, message } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { ColumnType } from 'antd/lib/table/interface';
import { createFormActions } from '@formily/antd';
import moment from 'moment';
import { GetMemberVisitListResponseDetail, getMemberVisitDelete, getMemberVisitList, getMemberVisitVisitTypeItems } from '@/services/MemberV2Api';
import { useAsyncInitSelect } from '@/formSchema/effects/useAsyncInitSelect';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import EyePreview from '@/components/EyePreview';
import PolymericTable, { FetchParamsType, NormalTableRefHandleType } from '@/components/PolymericTable';
import { querySchema } from './querySchema';
const queryFormActions = createFormActions();
type GetMemberVisitListRequestParams = FetchParamsType & {
memberName: string,
visitTheme: string,
visitType: number,
visitLevel: number,
visitor: string,
peer: string,
}
type GetMemberVisitListRequestResponse = GetMemberVisitListResponseDetail & {}
const MemberVisitManageIndex: React.FC<{}> = props => {
const [deleteLoadingKey, setDeleteLoadingKey] = useState(0);
const polymericRef = useRef<NormalTableRefHandleType | null>(null);
const handleJumpFormPage = (record?: GetMemberVisitListRequestResponse) => {
history.push(!record ? '/memberCenter/memberAbility/memberVisitManage/add' : `/memberCenter/memberAbility/memberVisitManage/modify?id=${record.id}`);
};
const handleDeleteMemberVisitRecord = (record: GetMemberVisitListRequestResponse) => {
if (record.id === deleteLoadingKey) {
return;
}
const msg = message.loading({
content: '正在删除,请稍候...',
duration: 0,
});
setDeleteLoadingKey(record.id);
getMemberVisitDelete({
id: `${record.id}`,
}).then((res) => {
if (res.code === 1000) {
polymericRef.current?.reload();
}
}).finally(() => {
msg();
setDeleteLoadingKey(0);
});
};
const columns: ColumnType<GetMemberVisitListRequestResponse>[] = [
{
title: '序号',
dataIndex: 'index',
width: '10%',
render: (_, record, index) => index + 1,
},
{
title: '会员名称',
dataIndex: 'memberName',
width: '10%',
render: (text: any, record) => (
<>
<EyePreview
url={`/memberCenter/memberAbility/memberVisitManage/details?id=${record.id}`}
>
{text}
</EyePreview>
</>
),
},
{
title: '拜访主题',
dataIndex: 'visitTheme',
width: '15%',
},
{
title: '拜访类型',
dataIndex: 'visitType',
width: '10%',
},
{
title: '拜访日期',
dataIndex: 'visitDate',
width: '10%',
render: (text) => text ? moment(text).format('YYYY-MM-DD') : '',
},
{
title: '拜访级别',
dataIndex: 'visitLevel',
width: '10%',
},
{
title: '拜访人',
dataIndex: 'visitor',
width: '10%',
},
{
title: '同行人',
dataIndex: 'peer',
width: '10%',
},
{
title: '操作',
dataIndex: 'actions',
align: 'center',
fixed: 'right',
width: 200,
render: (text: any, record) => (
<>
<Button
type="link"
onClick={() => handleJumpFormPage(record)}
>
编辑
</Button>
<Popconfirm
title="是否确认删除该拜访信息?"
onConfirm={() => handleDeleteMemberVisitRecord(record)}
okText="确认"
cancelText="取消"
>
<Button
type="link"
loading={record.id === deleteLoadingKey}
>
删除
</Button>
</Popconfirm>
</>
),
},
];
const fetchMemberVisitList = async (params: GetMemberVisitListRequestParams) => {
const res = await getMemberVisitList({
...params,
visitType: params.visitType ? `${params.visitType}` : undefined,
visitLevel: params.visitLevel ? `${params.visitLevel}` : undefined,
current: `${params.current}`,
pageSize: `${params.pageSize}`,
});
if (res.code === 1000) {
return res.data;
}
return { data: [], totalCount: 0 };
};
const RoleRuleConfigCtl = () => (
<Space>
<Button
type="primary"
onClick={() => handleJumpFormPage()}
icon={<PlusOutlined />}
>
新增
</Button>
</Space>
);
return (
<Card>
<PolymericTable
rowKey="id"
columns={columns}
fetchDataSource={(params) => fetchMemberVisitList(params as GetMemberVisitListRequestParams)}
defaultPageSize={10}
searchFormProps={{
actions: queryFormActions,
schema: querySchema,
components: {
RoleRuleConfigCtl,
},
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'memberName',
FORM_FILTER_PATH,
);
useAsyncInitSelect(
['visitType', 'visitLevel'],
async () => {
const { data, code } = await getMemberVisitVisitTypeItems();
if (code === 1000) {
return {
visitType: data.visitTypes.map((item) => ({ label: item.visitTypeName, value: item.visitType })),
visitLevel: data.visitLevels.map((item) => ({ label: item.visitLevelName, value: item.visitLevel })),
};
}
return {};
},
);
},
}}
scroll={{ x: 1200 }}
ref={polymericRef}
/>
</Card>
);
};
export default MemberVisitManageIndex;
\ No newline at end of file
/**
* @Description 会员拜访 - 详情
*/
import React, { useState, useEffect } from 'react';
import { Spin } from 'antd';
import moment from 'moment';
import { getMemberVisitDetails } from '@/services/MemberV2Api';
import { usePageStatus } from '@/hooks/usePageStatus';
import { normalizeFiledata } from '@/utils';
import MemberVisitForm, { SubmitValueType } from './components/MemberVisitForm';
const MemberVisitDetails: React.FC<{}> = (props) => {
const [memberLevelDetails, setMemberLevelDetails] = useState<SubmitValueType | undefined>(undefined);
const [detailsLoading, setDetailsLoading] = useState(false);
const { id } = usePageStatus();
const fetchMemberLevelDetails = () => {
setDetailsLoading(true);
getMemberVisitDetails({
id: id,
}).then((res) => {
if (res.code === 1000) {
const { memberId, visitorId, visitDate, visitAttachments, ...rest } = res.data;
setMemberLevelDetails({
...rest,
subMember: [{ memberId: memberId, name: rest.memberName }] as any[],
visitorMember: [{ userId: visitorId }] as any[],
visitDate: moment(visitDate).format('YYYY-MM-DD'),
files: visitAttachments ? visitAttachments.map((item) => normalizeFiledata(item.url)) : [],
});
}
}).finally(() => {
setDetailsLoading(false);
});
};
useEffect(() => {
fetchMemberLevelDetails();
}, []);
return (
<Spin spinning={detailsLoading}>
<MemberVisitForm
title='查看会员拜访'
value={memberLevelDetails}
editable={false}
/>
</Spin>
);
};
export default MemberVisitDetails;
\ No newline at end of file
/**
* @Description 会员拜访 - 编辑
*/
import React, { useState, useEffect } from 'react';
import { Spin, message } from 'antd';
import { history } from 'umi';
import moment from 'moment';
import { getMemberVisitDetails, postMemberVisitAddOrUpdate } from '@/services/MemberV2Api';
import { usePageStatus } from '@/hooks/usePageStatus';
import { normalizeFiledata } from '@/utils';
import MemberVisitForm, { SubmitValue, SubmitValueType } from './components/MemberVisitForm';
const ModifyMemberVisit: React.FC<{}> = (props) => {
const [memberLevelDetails, setMemberLevelDetails] = useState<SubmitValueType | undefined>(undefined);
const [detailsLoading, setDetailsLoading] = useState(false);
const { id } = usePageStatus();
const fetchMemberLevelDetails = () => {
setDetailsLoading(true);
getMemberVisitDetails({
id: id,
}).then((res) => {
if (res.code === 1000) {
const { memberId, visitorId, visitDate, visitAttachments, ...rest } = res.data;
setMemberLevelDetails({
...rest,
subMember: [{ memberId: memberId, name: rest.memberName }] as any[],
visitorMember: [{ userId: visitorId }] as any[],
visitDate: moment(visitDate).format('YYYY-MM-DD'),
files: visitAttachments ? visitAttachments.map((item) => normalizeFiledata(item.url)) : [],
});
}
}).finally(() => {
setDetailsLoading(false);
});
};
useEffect(() => {
fetchMemberLevelDetails();
}, []);
const handleRoleRuleConfigFormSubmit = (value: SubmitValue): Promise<void> => (
new Promise((resolve, reject) => {
const msg = message.loading({
content: '正在修改,请稍候...',
duration: 0,
});
const { subMember, visitorMember, visitDate, files, ...rest } = value;
postMemberVisitAddOrUpdate({
id: +id,
...rest,
memberId: subMember[0].memberId,
visitorId: visitorMember[0].userId,
visitDate: moment(visitDate).valueOf(),
visitAttachments: files ? files.map((item) => ({
name: item.name,
url: item.url,
})) : [],
}).then((res) => {
if (res.code === 1000) {
resolve();
setTimeout(() => {
history.goBack();
}, 800);
} else {
reject();
}
}).finally(() => {
msg();
});
})
);
return (
<Spin spinning={detailsLoading}>
<MemberVisitForm
title='编辑会员拜访'
value={memberLevelDetails}
onSubmit={handleRoleRuleConfigFormSubmit}
cloudy
/>
</Spin>
);
};
export default ModifyMemberVisit;
\ No newline at end of file
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { ISchema } from '@formily/antd';
export const querySchema: ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
},
properties: {
ctl: {
type: 'object',
'x-component': 'RoleRuleConfigCtl',
},
memberName: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
placeholder: '搜索',
tip: '输入 会员名称 进行搜索',
},
},
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
colStyle: {
marginLeft: 20,
},
},
properties: {
MEGA_LAYOUT_1: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
full: true,
autoRow: true,
columns: 5, // 同检索项数量
},
properties: {
visitTheme: {
type: 'string',
'x-component-props': {
placeholder: '拜访主题',
allowClear: true,
},
},
visitType: {
type: 'string',
enum: [],
'x-component-props': {
placeholder: '拜访类型',
allowClear: true,
},
},
visitLevel: {
type: 'string',
enum: [],
'x-component-props': {
placeholder: '拜访级别',
allowClear: true,
},
},
visitor: {
type: 'string',
'x-component-props': {
placeholder: '拜访人',
allowClear: true,
},
},
peer: {
type: 'string',
'x-component-props': {
placeholder: '同行人',
allowClear: true,
},
},
},
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
},
},
};
\ 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