Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
jinfa-platform
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
shenshaokai
jinfa-platform
Commits
8f9958f6
Commit
8f9958f6
authored
Mar 30, 2022
by
XieZhiXiong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 完成 会员拜访管理 功能
parent
13fb3ee3
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1438 additions
and
0 deletions
+1438
-0
memberRoute.ts
config/routes/memberRoute.ts
+30
-0
menu.ts
src/locales/zh-CN/menu.ts
+4
-0
addMemberVisit.tsx
src/pages/member/memberVisitManage/addMemberVisit.tsx
+52
-0
index.less
...isitForm/components/AnchorCardVirtualFieldWrap/index.less
+0
-0
index.tsx
...VisitForm/components/AnchorCardVirtualFieldWrap/index.tsx
+41
-0
index.less
.../MemberVisitForm/components/SubMemberFieldItem/index.less
+0
-0
index.tsx
...s/MemberVisitForm/components/SubMemberFieldItem/index.tsx
+196
-0
schema.ts
...s/MemberVisitForm/components/SubMemberFieldItem/schema.ts
+20
-0
index.less
...berVisitForm/components/VisitorMemberFieldItem/index.less
+0
-0
index.tsx
...mberVisitForm/components/VisitorMemberFieldItem/index.tsx
+214
-0
schema.ts
...mberVisitForm/components/VisitorMemberFieldItem/schema.ts
+65
-0
config.ts
...er/memberVisitManage/components/MemberVisitForm/config.ts
+15
-0
index.less
...r/memberVisitManage/components/MemberVisitForm/index.less
+0
-0
index.tsx
...er/memberVisitManage/components/MemberVisitForm/index.tsx
+196
-0
schema.ts
...er/memberVisitManage/components/MemberVisitForm/schema.ts
+146
-0
index.less
src/pages/member/memberVisitManage/index.less
+0
-0
index.tsx
src/pages/member/memberVisitManage/index.tsx
+217
-0
memberVisitDetails.tsx
src/pages/member/memberVisitManage/memberVisitDetails.tsx
+54
-0
modifyMemberVisit.tsx
src/pages/member/memberVisitManage/modifyMemberVisit.tsx
+89
-0
querySchema.ts
src/pages/member/memberVisitManage/querySchema.ts
+99
-0
No files found.
config/routes/memberRoute.ts
View file @
8f9958f6
...
...
@@ -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
,
},
]
}
...
...
src/locales/zh-CN/menu.ts
View file @
8f9958f6
...
...
@@ -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'
:
'店铺'
,
...
...
src/pages/member/memberVisitManage/addMemberVisit.tsx
0 → 100644
View file @
8f9958f6
/**
* @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
;
src/pages/member/memberVisitManage/components/MemberVisitForm/components/AnchorCardVirtualFieldWrap/index.less
0 → 100644
View file @
8f9958f6
src/pages/member/memberVisitManage/components/MemberVisitForm/components/AnchorCardVirtualFieldWrap/index.tsx
0 → 100644
View file @
8f9958f6
/*
* @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
src/pages/member/memberVisitManage/components/MemberVisitForm/components/SubMemberFieldItem/index.less
0 → 100644
View file @
8f9958f6
src/pages/member/memberVisitManage/components/MemberVisitForm/components/SubMemberFieldItem/index.tsx
0 → 100644
View file @
8f9958f6
/*
* @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
;
src/pages/member/memberVisitManage/components/MemberVisitForm/components/SubMemberFieldItem/schema.ts
0 → 100644
View file @
8f9958f6
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
,
},
},
},
};
src/pages/member/memberVisitManage/components/MemberVisitForm/components/VisitorMemberFieldItem/index.less
0 → 100644
View file @
8f9958f6
src/pages/member/memberVisitManage/components/MemberVisitForm/components/VisitorMemberFieldItem/index.tsx
0 → 100644
View file @
8f9958f6
/*
* @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
;
src/pages/member/memberVisitManage/components/MemberVisitForm/components/VisitorMemberFieldItem/schema.ts
0 → 100644
View file @
8f9958f6
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
:
'查询'
,
},
},
},
},
},
},
},
};
src/pages/member/memberVisitManage/components/MemberVisitForm/config.ts
0 → 100644
View file @
8f9958f6
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
src/pages/member/memberVisitManage/components/MemberVisitForm/index.less
0 → 100644
View file @
8f9958f6
src/pages/member/memberVisitManage/components/MemberVisitForm/index.tsx
0 → 100644
View file @
8f9958f6
/*
* @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
;
src/pages/member/memberVisitManage/components/MemberVisitForm/schema.ts
0 → 100644
View file @
8f9958f6
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
;
src/pages/member/memberVisitManage/index.less
0 → 100644
View file @
8f9958f6
src/pages/member/memberVisitManage/index.tsx
0 → 100644
View file @
8f9958f6
/**
* @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
src/pages/member/memberVisitManage/memberVisitDetails.tsx
0 → 100644
View file @
8f9958f6
/**
* @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
src/pages/member/memberVisitManage/modifyMemberVisit.tsx
0 → 100644
View file @
8f9958f6
/**
* @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
src/pages/member/memberVisitManage/querySchema.ts
0 → 100644
View file @
8f9958f6
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment