This commit is contained in:
ylj20011123 2025-07-16 20:46:34 +08:00
parent b3eba7b8bd
commit 010680be5a
38 changed files with 4800 additions and 119 deletions

View File

@ -999,7 +999,30 @@ export default [
name: 'TradingLedger',
component: './travelMember/TradingLedger/index'
},
// 埋点配置
{
path: 'BuriedPointConfig',
name: 'BuriedPointConfig',
component: './travelMember/BuriedPointConfig/index'
},
// 会员类型统计
{
path: 'MembershipTypeStatistics',
name: 'MembershipTypeStatistics',
component: './travelMember/MembershipTypeStatistics/index'
},
// 会员等级统计
{
path: 'MembershipLevelStatistics',
name: 'MembershipLevelStatistics',
component: './travelMember/MembershipLevelStatistics/index'
},
// 会员汇总统计
{
path: 'MemberSummaryStatistics',
name: 'MemberSummaryStatistics',
component: './travelMember/MemberSummaryStatistics/index'
},
]
},
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -128,6 +128,14 @@ const MerchantInformation: React.FC<{ currentUser: CurrentUser | undefined }> =
// 定义列表字段内容
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProp: {
placeholder: "请输入商户名称"
}
},
{
dataIndex: 'SELLER_NAME',
title: '商家名称',
@ -759,7 +767,8 @@ const MerchantInformation: React.FC<{ currentUser: CurrentUser | undefined }> =
CASHPAY: obj.TotalRevenue.Revenue_Amount || "0",
PERCAPITA: obj.TotalRevenue.Ticket_Count ? (obj.TotalRevenue.Revenue_Amount / obj.TotalRevenue.Ticket_Count).toFixed(2) : "0",
})
} else {
message.error('暂无数据!')
}
}
@ -913,6 +922,11 @@ const MerchantInformation: React.FC<{ currentUser: CurrentUser | undefined }> =
},
PageIndex: params.current,
PageSize: params.pageSize,
keyWord: {
Key: "SELLER_NAME",
Value: params?.searchText || ""
},
}
console.log('reqreqreqreq', req);
const data = await handleGetMEMBERADDRESSList(req);
@ -997,20 +1011,20 @@ const MerchantInformation: React.FC<{ currentUser: CurrentUser | undefined }> =
onOk={async () => { // 提交框内的数据
handleModalOk()
}}
// footer={<ModalFooter
// hideDelete={!currentRow?.SELLER_ID}
// handleDelete={async () => {
// await handelDelete(currentRow?.SELLER_ID)
// }}
// handleCancel={() => {
// setShowAddModal(false)
// setSelectRowKeys(null)
// setSelectRowDetail(null)
// setSelectAssociationServerpart(null)
// }}
// handleOK={() => {
// handleModalOk()
// }} />}
// footer={<ModalFooter
// hideDelete={!currentRow?.SELLER_ID}
// handleDelete={async () => {
// await handelDelete(currentRow?.SELLER_ID)
// }}
// handleCancel={() => {
// setShowAddModal(false)
// setSelectRowKeys(null)
// setSelectRowDetail(null)
// setSelectAssociationServerpart(null)
// }}
// handleOK={() => {
// handleModalOk()
// }} />}
>
<div style={{ display: 'flex', alignItems: 'flex-start' }}>
<LeftSelectTree setSelectedId={setSelectAssociationServerpart} />

View File

@ -883,6 +883,14 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
return list
}}
disabled={currentRow?.BusinessProcess_State > 1000 || (currentRow?.BusinessApproval_ID && currentRow?.ApproveStaff_ID !== currentUser?.ID)}
fieldProps={{
showSearch: true, // 启用搜索框
filterOption: (inputValue: any, option: any) => {
// 通过 label 搜索
return option.label.toLowerCase().includes(inputValue.toLowerCase());
}
}}
/>
</Col>
<Col span={12} style={{ display: currentRow?.BusinessProcess_State > 1000 && ApprovalType !== 0 ? "none" : "" }}>
@ -1238,6 +1246,14 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
}
console.log('newList', newList);
// 如果进入到了添加商品 里面选了服务区 会 带给外面的表单
if (res.SERVERPART_ID) {
modalFormRef.current?.setFieldsValue({
ServerpartId: res.SERVERPART_ID
})
}
setShopData(newList)
setShowAddShopModal(false)
@ -1330,6 +1346,11 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
setCommodityList([])
setCustomClassList([])
}
},
showSearch: true, // 启用搜索框
filterOption: (inputValue: any, option: any) => {
// 通过 label 搜索
return option.label.toLowerCase().includes(inputValue.toLowerCase());
}
}}
/>

View File

@ -303,6 +303,18 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
dataIndex: "COMMODITY_NAME",
ellipsis: true,
align: 'center',
render: (_, record) => {
return record?.COMMODITY_NAME ? <a onClick={() => {
let obj: any = {}
if (shopData && shopData.length > 0) {
obj = shopData.filter((item: any) => item.COMMODITY_ID === record?.COMMODITY_ID)[0]
}
setEditSelectRow(obj)
setEditShopModal(true)
}}>
{record?.COMMODITY_NAME}
</a> : "-"
}
},
{
title: "条码",
@ -416,6 +428,14 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
// 选择商品的表格结构
const selectShopColumns: any = [
{
title: "商品查询",
dataIndex: "searchText",
hideInTable: true,
fieldProp: {
fieldholder: "请输入商品名称"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 70,
@ -428,10 +448,10 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
width: 150,
ellipsis: true,
align: 'center',
dataIndex: 'SERVERPART_NAME',
dataIndex: 'SERVERPART_ID',
hideInSearch: true,
valueType: "select",
valueEnum: ServerpartIdsList
valueEnum: ServerpartIdsList,
},
{
title: <div style={{ textAlign: 'center' }}></div>,
@ -439,11 +459,15 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
ellipsis: true,
dataIndex: 'BUSINESSTYPE',
align: 'center',
hideInSearch: true,
valueType: 'select',
request: async () => {
return await getFieldEnum({ FieldExplainField: 'BUSINESSTYPE', sessionName: 'SHOPTRADE', notformate: true })
},
fieldProps: {
showSearch: true,
filterOption: (input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
}
},
{
@ -500,10 +524,10 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
width: 100,
ellipsis: true,
dataIndex: 'COMMODITY_STATE',
hideInSearch: true,
align: 'center',
valueType: 'select',
valueEnum: { 0: { text: '无效', status: 'error' }, 1: { text: '有效', status: 'success' }, 2: { text: '不可选', status: 'default' } },
initialValue: '1',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
@ -1020,6 +1044,13 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
return list
}}
disabled={currentRow?.BusinessProcess_State > 1000 || (currentRow?.BusinessApproval_ID && currentRow?.ApproveStaff_ID !== currentUser?.ID)}
fieldProps={{
showSearch: true, // 启用搜索框
filterOption: (inputValue: any, option: any) => {
// 通过 label 搜索
return option.label.toLowerCase().includes(inputValue.toLowerCase());
}
}}
/>
</Col>
<Col span={12} style={{ display: currentRow?.BusinessProcess_State > 1000 && ApprovalType !== 0 ? "none" : "" }}>
@ -1349,10 +1380,11 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
}}
>
<ProTable
search={false}
// search={false}
options={false}
scroll={{ x: "100%", y: "500px" }}
bordered
search={{ span: 6 }}
rowKey={"COMMODITY_ID"}
request={async () => {
let formRes = modalFormRef.current?.getFieldsValue()
@ -1395,6 +1427,45 @@ const ProductChangeInfoApproval: React.FC<{ currentUser: CurrentUser }> = (props
wrapClassName={'shopModal'}
destroyOnClose
title={'编辑商品'}
footer={
currentRow?.BusinessProcess_State > 1000 ? '' :
<div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', boxSizing: 'border-box', padding: '0 16px' }}>
{/* 审批过程中只能看 所以把底部隐藏 这样即使修改也没用 */}
<div></div>
<div>
<Button onClick={() => {
setEditSelectRow(undefined)
setEditShopModal(false)
}}></Button>
<Button type={"primary"} onClick={() => {
modalShopFormRef.current?.validateFields().then(async (res: any) => {
let oldData: any = shopData && shopData.length > 0 ? JSON.parse(JSON.stringify(shopData)) : []
let newList: any = []
// 判断当前的里面有没有一样的
if (oldData && oldData.length > 0) {
oldData.forEach((item: any, index: number) => {
if (item.ADDTIME === res.ADDTIME) {
newList.push({
...item,
...res
})
} else {
newList.push(item)
}
})
} else {
newList.push(res)
}
setShopData(newList)
setEditSelectRow(undefined)
setEditShopModal(false)
})
}}></Button>
</div>
</div>
}
onOk={() => {
modalShopFormRef.current?.validateFields().then(async (res: any) => {
let oldData: any = shopData && shopData.length > 0 ? JSON.parse(JSON.stringify(shopData)) : []

View File

@ -64,6 +64,31 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
const [InitiateApplication, setInitiateApplication] = useState<boolean>(false)
// 显示类型
const [showDetailType, setShowDetailType] = useState<any>()
// 商品业态 的枚举
const [BUSINESSTYPESHOPTRADE, setBUSINESSTYPESHOPTRADE] = useState<any>()
// 选择的商品数据
const [currentShopRow, setCurrentShopRow] = useState<any>()
// 显示编辑商品的悬浮框
const [editShopModal, setShowEditShopModal] = useState<boolean>(false);
// 商品业态的搜索框内容
const [commodityList, setCommodityList] = useState<any>([])
const [selectSERVERPARTID, setSelectSERVERPARTID] = useState<any>()
const [selectBUSINESSTYPE, setSelectBUSINESSTYPE] = useState<any>()
const [treeView, setTreeView] = useState<any>()
const [customClassList, setCustomClassList] = useState<any>()
// 加载服务区树
const { loading: treeLoading, data: treeViews } = useRequest(async () => {
const req = {
PROVINCE_CODE: currentUser?.ProvinceCode,
COMMODITYTYPE_VALID: 1,
ShowCode: true
}
const data = await handleGetNestingCOMMODITYTYPETree(req)
setTreeView(data)
return data
})
const { loading: CommodityLoading, data: CommodityData } = useRequest(async () => {
const data = await getFieldEnumTree({ FieldExplainField: 'CommodityTypeIds' })
@ -279,6 +304,14 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
dataIndex: "COMMODITY_NAME",
ellipsis: true,
align: 'center',
render: (_, record) => {
return record?.COMMODITY_NAME ? <a onClick={() => {
setCurrentShopRow(record)
setShowEditShopModal(true)
}}>
{record?.COMMODITY_NAME}
</a> : "-"
}
},
{
title: "条码",
@ -389,9 +422,16 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
},
},
]
// 选择商品的表格结构
const selectShopColumns: any = [
{
title: "商品查询",
dataIndex: "searchText",
hideInTable: true,
fieldProp: {
fieldholder: "请输入商品名称"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 70,
@ -415,11 +455,15 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
ellipsis: true,
dataIndex: 'BUSINESSTYPE',
align: 'center',
hideInSearch: true,
valueType: 'select',
request: async () => {
return await getFieldEnum({ FieldExplainField: 'BUSINESSTYPE', sessionName: 'SHOPTRADE', notformate: true })
const BUSINESSTYPERes = await getFieldEnum({ FieldExplainField: 'BUSINESSTYPE', sessionName: 'SHOPTRADE', notformate: true })
return BUSINESSTYPERes
},
fieldProps: {
showSearch: true,
filterOption: (input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
}
},
{
@ -438,6 +482,14 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
align: 'left',
dataIndex: 'COMMODITY_NAME',
hideInSearch: true,
// render: (_, record) => {
// return record?.COMMODITY_NAME ? <a onClick={() => {
// setCurrentShopRow(record)
// setShowEditShopModal(true)
// }}>
// {record?.COMMODITY_NAME}
// </a> : "-"
// }
},
{
title: <div style={{ textAlign: 'center' }}></div>,
@ -476,10 +528,10 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
width: 100,
ellipsis: true,
dataIndex: 'COMMODITY_STATE',
hideInSearch: true,
align: 'center',
valueType: 'select',
valueEnum: { 0: { text: '无效', status: 'error' }, 1: { text: '有效', status: 'success' }, 2: { text: '不可选', status: 'default' } },
initialValue: '1',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
@ -522,6 +574,40 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
}, [])
// 拿到对应的商品业态
const handleGetCommodity = async (id: any) => {
const req: any = {
ProvinceCode: currentUser?.ProvinceCode,
ServerpartId: id
}
const data = await handleGetServerpartShopTrade(req)
console.log('data', data)
setCommodityList(data)
}
// 请求自定义类的选择列表
const handleGetCustomClassList = async (id: any) => {
const req: any = {
SearchParameter: {
USERDEFINEDTYPE_STATE: 1,
SERVERPART_ID: id,
BUSINESSTYPE: selectBUSINESSTYPE
},
PageIndex: 1,
PageSize: 999999,
pageSize: 999999,
}
const data = await handleGetUSERDEFINEDTYPEList(req)
if (data && data.length > 0) {
const list: any = []
data.forEach((item: any) => {
list.push({ label: item.USERDEFINEDTYPE_NAME, value: item.USERDEFINEDTYPE_ID })
})
setCustomClassList(list)
}
console.log('data', data)
}
return (
<div>
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
@ -852,15 +938,12 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
}
}}
>
<ProForm
// layout={'horizontal'}
formRef={modalFormRef}
submitter={false}
preserve={false}
request={async () => {
console.log('currentRowcurrentRowdsada', currentRow);
if (currentRow?.BusinessApproval_ID) {
const req: any = {
BUSINESSAPPROVALId: currentRow?.BusinessApproval_ID,
@ -1008,6 +1091,13 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
return list
}}
disabled={currentRow?.BusinessProcess_State > 1000 || (currentRow?.BusinessApproval_ID && currentRow?.ApproveStaff_ID !== currentUser?.ID)}
fieldProps={{
showSearch: true, // 启用搜索框
filterOption: (inputValue: any, option: any) => {
// 通过 label 搜索
return option.label.toLowerCase().includes(inputValue.toLowerCase());
}
}}
/>
</Col>
<Col span={12} style={{ display: currentRow?.BusinessProcess_State > 1000 && ApprovalType !== 0 ? "none" : "" }}>
@ -1349,22 +1439,25 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
}}
>
<ProTable
search={false}
options={false}
scroll={{ x: "100%", y: "500px" }}
bordered
search={{ span: 6 }}
rowKey={"COMMODITY_ID"}
request={async () => {
request={async (params) => {
let formRes = modalFormRef.current?.getFieldsValue()
const req: any = {
SearchType: 3,
ShopTrade: params?.BUSINESSTYPE || "",
ProvinceCode: currentUser?.ProvinceCode,
// CommodityTypeId: currenMenu,
CommodityState: 1,
CommodityState: params?.COMMODITY_STATE || "",
ServerpartID: formRes?.ServerpartId,
PageIndex: 1,
PageSize: 999999,
SortStr: "OPERATE_DATE desc"
SortStr: "OPERATE_DATE desc",
SearchKey: "COMMODITY_NAME",
SearchValue: params?.searchText || ""
// PageSize: 20
}
const data = await handleGetCommodityList(req)
@ -1388,6 +1481,447 @@ const ProductChangePriceApproval: React.FC<{ currentUser: CurrentUser }> = (prop
}}
/>
</Modal>
{/* 新增商品的悬浮框 */}
<Modal
open={editShopModal}
width={1200}
wrapClassName={'shopModal'}
destroyOnClose
title={currentShopRow?.COMMODITY_ID ? '编辑商品' : '添加商品'}
onOk={() => {
modalShopFormRef.current?.validateFields().then(async (res: any) => {
setShowEditShopModal(false)
setCommodityList([])
setCurrentShopRow(undefined)
})
}}
footer={false}
onCancel={() => {
setShowEditShopModal(false)
setCommodityList([])
setCurrentShopRow(undefined)
}}
>
<ProForm
formRef={modalShopFormRef}
submitter={false}
initialValues={currentShopRow}
request={async () => {
// !currentShopRow?.COMMODITY_ID &&
if (currentShopRow?.SERVERPART_ID) {
await handleGetCommodity(currentShopRow?.SERVERPART_ID)
}
return {
...currentShopRow,
BUSINESSTYPE: currentShopRow?.BUSINESSTYPE.toString(),
COMMODITY_GRADE: Number(currentShopRow?.COMMODITY_GRADE),
ADDTIME: moment(currentShopRow?.ADDTIME).format('YYYY-MM-DD HH:mm:ss')
}
}}
disabled={currentRow?.BusinessProcess_State === 9000}
>
<div className={'modalTitle'}></div>
<Row gutter={16}>
<Col span={16}>
<ProFormText
name="COMMODITY_NAME"
label="商品名称"
placeholder="请输入商品名称"
rules={[
{
required: true,
message: '请输入商品名称',
},
]}
readonly
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_EN"
label="拼音简码"
readonly
/>
</Col>
<Col span={8}>
<ProFormSelect
name="SERVERPART_ID"
label="服务区名"
readonly
request={async () => {
const data = await getServerpartTree(currentUser?.ProvinceCode, currentUser?.CityAuthority, true, true, true)
const list: any = []
if (data && data.length > 0) {
data.forEach((item: any) => {
if (item.children && item.children.length > 0) {
item.children.forEach((subItem: any) => {
list.push({ label: subItem.label, value: subItem.value })
})
}
})
data.forEach((item: any) => {
list.push({ label: item.label, value: item.value })
})
}
return list
}}
rules={[
{
required: true,
message: '请选择服务区',
},
]}
fieldProps={{
onChange: async (e: any) => {
console.log('e', e)
if (e) {
setSelectSERVERPARTID(e)
await handleGetCommodity(e)
if (selectBUSINESSTYPE) {
await handleGetCustomClassList(e)
}
} else {
setSelectSERVERPARTID(undefined)
setCommodityList([])
setCustomClassList([])
}
},
showSearch: true, // 启用搜索框
filterOption: (inputValue: any, option: any) => {
// 通过 label 搜索
return option.label.toLowerCase().includes(inputValue.toLowerCase());
}
}}
/>
</Col>
<Col span={8}>
<ProFormSelect
name="BUSINESSTYPE"
label="商品业态"
readonly
rules={[
{
required: true,
message: '请选择商品业态',
},
]}
options={commodityList}
fieldProps={{
onChange: async (e: any) => {
if (e) {
setSelectBUSINESSTYPE(e)
if (selectSERVERPARTID) {
await handleGetCustomClassList(e)
}
} else {
setSelectBUSINESSTYPE(undefined)
}
}
}}
/>
</Col>
<Col span={8}>
<ProFormTreeSelect
name="COMMODITY_TYPE"
label="商品类别"
readonly
rules={[
{
required: true,
message: '请选择商品类别',
},
]}
request={() => {
return treeView
}}
fieldProps={{
treeDefaultExpandAll: true
}}
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_BARCODE"
label="商品条码"
readonly
disabled={currentRow}
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_UNIT"
label="商品单位"
readonly
rules={[
{
required: true,
message: '请输入商品单位',
},
]}
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_RULE"
label="商品规格"
readonly
rules={[
{
required: true,
message: '请输入商品规格',
},
]}
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_HOTKEY"
label="快捷键值"
readonly
/>
</Col>
<Col span={8}>
<ProFormSelect
name="COMMODITY_GRADE"
label="质量等级"
readonly
rules={[
{
required: true,
message: '请选择质量等级',
},
]}
initialValue={1000}
options={[{ label: '一等品', value: 1000 }, { label: '二等品', value: 2000 }, { label: '三等品', value: 5000 }, { label: '优等品', value: 3000 }, { label: '合格品', value: 4000 },]}
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_ORI"
label="商品产地"
readonly
rules={[
{
required: true,
message: '请输入商品产地',
},
]}
/>
</Col>
<Col span={8}>
<ProFormSelect
name="USERDEFINEDTYPE_ID"
label="自定义类"
readonly
options={customClassList}
/>
</Col>
<Col span={8}>
<ProFormText
name="PROVINCE_CODE"
label="省份编码"
readonly
disabled
// initialValue={currentUser?.ProvinceCode}
/>
</Col>
<Col span={8}>
<ProFormText
name="COMMODITY_CODE"
label="商品编码"
readonly
disabled
/>
</Col>
<Col span={24}>
<ProFormTextArea
name="COMMODITY_DESC"
label="商品说明"
readonly
/>
</Col>
</Row>
<div className={'modalTitle'}></div>
<Row gutter={16}>
<Col span={8}>
<ProFormSelect
name="CANSALE"
readonly
label="是否销售"
rules={[
{
required: true,
message: '请选择是否销售',
},
]}
initialValue={1}
options={[{ label: '是', value: 1 }, { label: '否', value: 0 }]}
/>
</Col>
<Col span={8}>
<ProFormSelect
name="ISBULK"
label="是否散装"
readonly
rules={[
{
required: true,
message: '请选择是否散装',
},
]}
initialValue={0}
options={[{ label: '是', value: 1 }, { label: '否', value: 0 }]}
/>
</Col>
<Col span={8}>
<ProFormSelect
name="METERINGMETHOD"
label="称重方式"
readonly
rules={[
{
required: true,
message: '请选择称重方式',
},
]}
initialValue={1}
options={[{ label: '计价', value: 1 }, { label: '散装称重', value: 0 }]}
/>
</Col>
<Col span={8}>
<ProFormSelect
name="COMMODITY_STATE"
label="审核状态"
readonly
rules={[
{
required: true,
message: '请选择审核状态',
},
]}
initialValue={1}
options={[{ label: '有效', value: 1 }, { label: '审核中', value: 2 }, { label: '无效', value: 0 }]}
/>
</Col>
<Col span={8}>
<ProFormText
name="ADDTIME"
label="添加时间"
readonly
disabled
initialValue={moment().format('YYYY-MM-DD HH:mm:ss')}
/>
</Col>
<Col span={8}>
<ProFormDateTimePicker
name="OPERATE_DATE"
label="生效时间"
readonly
initialValue={moment().format('YYYY-MM-DD HH:mm:ss')}
/>
</Col>
</Row>
<div className={'modalTitle'}></div>
<Row gutter={16}>
<Col span={8}>
<ProFormDigit
name="COMMODITY_RETAILPRICE"
label="零售价"
readonly
rules={[
{
required: true,
message: '请输入零售价',
},
]}
/>
</Col>
<Col span={8}>
<ProFormDigit
name="COMMODITY_CURRPRICE"
label="当前价格"
readonly
rules={[
{
required: true,
message: '请输入当前价格',
},
]}
/>
</Col>
<Col span={8}>
<ProFormDigit
name="COMMODITY_MEMBERPRICE"
label="会员价"
readonly
/>
</Col>
<Col span={8}>
<ProFormDigit
name="COMMODITY_PURCHASEPRICE"
label="进货价"
readonly
rules={[
{
required: true,
message: '请输入进货价',
},
]}
/>
</Col>
<Col span={8}>
<ProFormDigit
name="COMMODITY_MINPRICE"
label="最低价"
readonly
/>
</Col>
<Col span={8}>
<ProFormDigit
name="COMMODITY_MAXPRICE"
label="最高价"
readonly
/>
</Col>
</Row>
<div className={'modalTitle'}></div>
<Row gutter={16}>
<Col span={8}>
<ProFormDigit
name="DUTY_PARAGRAPH"
label="进价税率"
readonly
/>
</Col>
<Col span={8}>
<ProFormDigit
name="RETAIL_DUTY"
label="零售税率"
readonly
/>
</Col>
<Col span={8}>
<ProFormSelect
name="COMMODITY_FROZENCOUNT"
label="采购状态"
readonly
options={[{ label: '允许', value: 1000 }, { label: '禁止', value: 2000 }]}
/>
</Col>
</Row>
</ProForm>
</Modal>
</div >
)
}

View File

@ -306,9 +306,9 @@ const shopCommodity: React.FC<{ currentUser: CurrentUser }> = (props) => {
const req: any = {
...params,
SearchType: 4,
ProvinceCode: currentUser?.USER_PROVINCE,
ProvinceCode: currentUser?.ProvinceCode,
ServerpartShopID: selectedId,
CommodityState: 1,
CommodityState: params?.COMMODITY_STATE,
PageIndex: 1,
PageSize: 999999,
pageSize: 999999

View File

@ -55,6 +55,11 @@ const BookingMealOrder: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
};
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
},
{
title: '查询时间',
dataIndex: 'search_date',
@ -85,11 +90,10 @@ const BookingMealOrder: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
title: '订单编号',
align: 'center',
hideInSearch: true,
width: 200,
width: 250,
ellipsis: true,
render: (_, record) => {
return record?.SALEBILL_CODE ? <a onClick={() => {
console.log('recordrecordrecordrecord', record);
setCurrentRow(record);
handleModalVisible(true)
}}>{record?.SALEBILL_CODE}</a> : "-"
@ -267,7 +271,8 @@ const BookingMealOrder: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
SALEBILL_TYPES: 6000,
ORDER_DATE_Start: params?.ORDER_DATE_Start || "",
ORDER_DATE_End: params?.ORDER_DATE_End || "",
SALEBILL_STATES: params?.SALEBILL_STATE === "0" ? "1010,2000,3000" : params?.SALEBILL_STATE
SALEBILL_STATES: params?.SALEBILL_STATE === "0" ? "1010,2000,3000" : params?.SALEBILL_STATE,
SearchKeyValue: params?.searchText || ""
},
PageIndex: 1,
PageSize: 999999,

View File

@ -0,0 +1,481 @@
// 埋点配置
import React, { useRef, useState, Suspense } from 'react';
import moment from 'moment'; // 时间相关引用,没有使用可以删除
import numeral from "numeral"; // 数字相关引用,没有使用可以删除
import { connect } from 'umi';
import useRequest from '@ahooksjs/use-request'; // 请求数据的引用
import Draggable from 'react-draggable';
import SubMenu from "antd/lib/menu/SubMenu";
import ProTable from '@ant-design/pro-table';
import ProDescriptions from '@ant-design/pro-descriptions';
import ProForm, { ProFormDatePicker, ProFormDateTimePicker, ProFormMoney, ProFormSelect, ProFormText, ProFormTextArea, ProFormUploadButton } from '@ant-design/pro-form';
import { MenuFoldOutlined, PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-layout';
import { Button, Col, Drawer, message, Row, Popconfirm, Space, Image, Modal, Form, Switch, Upload, Tooltip, Descriptions, TreeSelect } from 'antd';
import type { CurrentUser } from "umi";
import type { ConnectState } from '@/models/connect';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import type { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import type { FormInstance } from 'antd';
import { getFieldEnumTree, getFieldEnumName } from "@/services/options"; // 枚举的引用,没有使用可以删除
import PageTitleBox from "@/components/PageTitleBox";
import { handeDeleteWECHATAPPBURYPOINT, handeGetWECHATAPPBURYPOINTList, handeGetWECHATAPPSIGNList, handeSynchroWECHATAPPBURYPOINT } from '../service';
import ModalFooter from '../scenicSpotConfig/component/modalFooter';
const BuriedPointConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const [currentRow, setCurrentRow] = useState<any>();
const [showDetail, setShowDetail] = useState<boolean>();
const [modalVisible, handleModalVisible] = useState<boolean>();
const [confirmLoading, handleConfirmLoading] = useState<boolean>(false) // 弹出框的内容表单是否在提交
const [searchParams, setSearchParams] = useState<any>();
// 弹出框拖动效果
const [bounds, setBounds] = useState<{ left: number, right: number, top: number, bottom: number }>() // 移动的位置
const [disabled, setDraggleDisabled] = useState<boolean>() // 是否拖动
const draggleRef = React.createRef<any>()
// 获取小程序的列表
const [WECHATAPP_APPID, setWECHATAPP_APPID] = useState<any>()
const onDraggaleStart = (event, uiData) => {
const { clientWidth, clientHeight } = window.document.documentElement;
const targetRect = draggleRef.current?.getBoundingClientRect();
if (!targetRect) {
return;
}
setBounds({
left: -targetRect.left + uiData.x,
right: clientWidth - (targetRect.right - uiData.x),
top: -targetRect.top + uiData.y,
bottom: clientHeight - (targetRect.bottom - uiData.y),
});
};
// 拖动结束
// 定义列表字段内容
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldprop: {
placeholder: "请输入页面路径/模块名称"
}
},
{
dataIndex: 'WECHATAPP_APPID',
title: '小程序类别',
hideInTable: true,
valueType: 'select',
request: async () => {
const req: any = {
SearchParameter: {
OWNERUNIT_ID: currentUser?.OwnerUnitId,
// PROVINCE_CODE: currentUser?.ProvinceCode
},
PageIndex: 1,
PageSize: 99,
}
const data = await handeGetWECHATAPPSIGNList(req)
console.log('datadsda', data);
let list: any = []
if (data && data.length > 0) {
data.forEach((item: any) => {
list.push({ label: item.WECHATAPPSIGN_NAME, value: item.WECHATAPP_APPID })
})
}
setWECHATAPP_APPID(list)
return list
},
initialValue: "wxee018fb96955552a"
},
{
dataIndex: 'WECHATAPP_ROUTE',
width: 300,
title: <div style={{ textAlign: 'center' }}></div>,
align: 'left',
ellipsis: true,
hideInSearch: true,
render: (_, record) => {
return record?.WECHATAPP_ROUTE ? <a onClick={() => {
setCurrentRow({ ...record });
handleModalVisible(true);
}}>{record?.WECHATAPP_ROUTE}</a> : "-"
}
},
{
dataIndex: 'WECHATAPP_MOULD',
title: '小程序模板',
width: 150,
ellipsis: true,
align: 'center',
hideInSearch: true,
},
{
dataIndex: 'WECHATAPP_APPID',
title: '小程序APPID',
align: 'center',
width: 150,
ellipsis: true,
hideInSearch: true,
},
{
dataIndex: 'WECHATAPPSIGN_NAME',
title: '小程序名称',
align: 'center',
width: 150,
ellipsis: true,
hideInSearch: true,
},
{
dataIndex: 'ISSHOW',
// title: '小程序埋点是显示',
title: '有效状态',
align: 'center',
width: 150,
ellipsis: true,
hideInSearch: true,
valueType: "select",
valueEnum: {
"1": "有效",
"0": "无效"
}
},
{
dataIndex: 'UPDATE_STAFF_NAME',
title: '修改人员名称',
width: 150,
ellipsis: true,
align: 'center',
hideInSearch: true,
},
{
dataIndex: 'UPDATE_DATE',
title: '修改时间',
valueType: 'date',
width: 150,
ellipsis: true,
align: 'center',
hideInSearch: true,
render: (_, record) => {
return record?.UPDATE_DATE ? moment(record?.UPDATE_DATE).format('YYYY-MM-DD HH:mm:ss') : "-"
}
},
// {
// dataIndex: 'option',
// title: '操作',
// valueType: 'option',
// hideInSearch: true,
// render: (_, record) => {
// return (
// <Space>
// <a
// onClick={() => {
// setCurrentRow(record);
// setShowDetail(true);
// }}
// >
// 查看
// </a>
// <a
// onClick={() => {
// setCurrentRow({ ...record });
// handleModalVisible(true);
// }}
// >
// 编辑
// </a>
// <Popconfirm
// title="确认删除该小程序埋点配置列表信息吗?"
// onConfirm={async () => {
// await handelDelete(record.WECHATAPPBURYPOINT_ID);
// }}
// >
// <a>删除</a>
// </Popconfirm>
// </Space >
// );
// },
// },
];
const handelDelete = async (id: number) => {
const result = await handeDeleteWECHATAPPBURYPOINT({ WECHATAPPBURYPOINTId: id });
if (result.Result_Code !== 100) {
message.error(`${result.Result_Desc}` || `${result.Result_Code}:删除失败`);
} else {
message.success('删除成功!');
actionRef.current?.reload()
}
};
const handleAddUpdate = async (res: any) => {
let req: any = {}
if (currentRow?.WECHATAPPBURYPOINT_ID) {
req = {
...currentRow,
...res,
UPDATE_STAFF_ID: currentUser?.ID,
UPDATE_STAFF_NAME: currentUser?.Name,
UPDATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss')
}
} else {
req = {
...res,
CREATE_STAFF_ID: currentUser?.ID,
CREATE_STAFF_NAME: currentUser?.Name,
CREATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'),
UPDATE_STAFF_ID: currentUser?.ID,
UPDATE_STAFF_NAME: currentUser?.Name,
UPDATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss')
}
}
const data = await handeSynchroWECHATAPPBURYPOINT(req)
handleConfirmLoading(false)
if (data.Result_Code === 100) {
message.success("新增成功!")
setCurrentRow(undefined)
formRef?.current?.resetFields()
handleModalVisible(false)
actionRef.current?.reload()
} else {
message.error(data.Result_Desc)
}
};
return (
<div>
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
<ProTable
style={{ height: 'calc(100vh - 135px)', background: '#fff' }}
scroll={{ y: 'calc(100vh - 410px)' }}
rowKey={(record) => {
return `${record?.WECHATAPPBURYPOINT_ID}`
}}
formRef={formRef}
headerTitle={<PageTitleBox props={props} />} // 列表表头
actionRef={actionRef}
search={{ span: 6, labelWidth: 'auto' }}
bordered
// 请求数据
request={async (params, sorter) => {
const req = {
SearchParameter: {
// WECHATAPP_APPID: "wxee018fb96955552a"
WECHATAPP_APPID: params?.WECHATAPP_APPID || "",
ISSHOW: 1
},
PageIndex: 1,
PageSize: 999,
keyWord: {
Key: "WECHATAPP_ROUTE,WECHATAPP_MOULD",
value: params?.searchText || ""
},
SortStr: "UPDATE_DATE desc",
}
console.log('reqreqreqreqreq', req);
const data = await handeGetWECHATAPPBURYPOINTList(req);
console.log('datadatadatadatadata', data);
if (data.List && data.List.length > 0) {
return { data: data.List, success: true, total: data.TotalCount }
}
return { data: [], success: true }
}}
columns={columns}
toolbar={{
actions: [
// 新增按钮
<Button
key="new"
icon={<PlusOutlined />}
type="primary"
onClick={() => {
handleModalVisible(true);
}}
>
</Button>,
],
}}
pagination={{ defaultPageSize: 20 }}
/>
<Drawer
width={600}
visible={showDetail}
onClose={() => {
setCurrentRow(undefined);
setShowDetail(false);
}}
closable={false}
>
{currentRow?.WECHATAPPBURYPOINT_ID && (
<ProDescriptions
column={2}
request={async () => ({
data: currentRow || {},
})}
params={{
id: currentRow?.WECHATAPPBURYPOINT_ID,
}}
columns={columns}
/>
)}
</Drawer>
<Modal
title={
<div
className='buriedPointConfig'
style={{
width: '100%',
cursor: 'move',
}}
onMouseOver={() => {
if (disabled) {
setDraggleDisabled(false)
}
}}
onMouseOut={() => {
setDraggleDisabled(true)
}}
onFocus={() => { }}
onBlur={() => { }}
>
{currentRow ? '更新小程序埋点配置' : '新建小程序埋点配置'}
</div>
}
destroyOnClose={true}
width={900}
bodyStyle={{
height: '700px', // 你可以根据需要调整高度
overflowY: 'auto',
}}
visible={modalVisible}
confirmLoading={confirmLoading}
afterClose={() => {
formRef.current?.resetFields();
setCurrentRow(undefined);
}}
onCancel={() => {
handleConfirmLoading(false)
handleModalVisible(false)
}}
footer={<ModalFooter
hideDelete={!currentRow?.WECHATAPPBURYPOINT_ID}
handleDelete={async () => {
console.log('currentRow', currentRow);
await handelDelete(currentRow?.WECHATAPPBURYPOINT_ID)
}}
handleCancel={() => {
handleConfirmLoading(false)
handleModalVisible(false)
formRef.current?.resetFields();
setCurrentRow(undefined);
}}
handleOK={() => {
formRef?.current?.validateFields().then(() => {
handleConfirmLoading(true)
formRef?.current?.submit()
})
}}
/>}
onOk={async () => { // 提交框内的数据
formRef?.current?.validateFields().then(() => {
handleConfirmLoading(true)
formRef?.current?.submit()
})
}}
modalRender={(modal) => {
return <Draggable
disabled={disabled}
bounds={bounds}
onStart={(event, uiData) => onDraggaleStart(event, uiData)}
handle='.buriedPointConfig'
>
<div ref={draggleRef}>{modal}</div>
</Draggable>
}}
>
<ProForm
layout={'horizontal'}
labelCol={{ style: { width: 80 } }}
formRef={formRef}
autoFocusFirstInput
submitter={false}
preserve={false}
initialValues={currentRow}
onFinish={async (values) => {
let newValue: any = { ...values };
if (currentRow) {
// 编辑数据
newValue = { ...values, WECHATAPPBURYPOINT_ID: currentRow.WECHATAPPBURYPOINT_ID };
}
// 如果有开关,要把开关的代码写进去
const success = await handleAddUpdate(newValue);
handleConfirmLoading(false)
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
handleModalVisible(false);
}
}}
>
<Row>
<Col span={12}>
<ProFormText
name="WECHATAPP_ROUTE"
label="页面路径"
/>
</Col>
<Col span={12}>
<ProFormText
name="WECHATAPP_MOULD"
label="模块名称"
/>
</Col>
<Col span={12}>
<ProFormSelect
name="WECHATAPP_APPID"
label="小程序名称"
options={WECHATAPP_APPID}
/>
</Col>
<Col span={12} style={{ display: 'none' }}>
<ProFormText
name="WECHATAPPSIGN_NAME"
label="小程序名称"
/>
</Col>
<Col span={12}>
<ProFormSelect
name="ISSHOW"
label="有效状态"
options={[{ label: "有效", value: 1 }, { label: "无效", value: 0 }]}
/>
</Col>
</Row>
</ProForm>
</Modal>
</div>
</div>
);
};
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(BuriedPointConfig);

View File

@ -47,6 +47,14 @@ const ConsumptionRecordSearch: React.FC<{ currentUser: CurrentUser }> = (props)
const [searchParams, setSearchParams] = useState<any>()
const columns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true,
fieldprop: {
placeholder: "请输入用户昵称/手机号"
}
},
{
title: '查询时间',
dataIndex: 'search_date',
@ -224,7 +232,11 @@ const ConsumptionRecordSearch: React.FC<{ currentUser: CurrentUser }> = (props)
CONSUMPTIONRECORD_TYPE: params?.CONSUMPTIONRECORD_TYPE === '0' ? '' : params?.CONSUMPTIONRECORD_TYPE
},
PageIndex: params?.current,
PageSize: 20
PageSize: params?.pageSize,
keyWord: {
Key: "MEMBERSHIP_NAME,MEMBERSHIP_MOBILEPHONE",
Value: params?.searchText || ""
}
}
const data = await handleGetCONSUMPTIONRECORDList(req)
if (data.List && data.List.length > 0) {
@ -237,6 +249,10 @@ const ConsumptionRecordSearch: React.FC<{ currentUser: CurrentUser }> = (props)
]
}}
pagination={{
defaultPageSize: 20,
showTotal: (total) => `${total} 条记录`
}}
/>
</div>
</div>

View File

@ -102,6 +102,12 @@ const GrowthValueRecordSearch: React.FC<{ currentUser: CurrentUser }> = (props)
valueType: 'treeSelect',
request: () => {
return SCORETYPETree
},
fieldProps: {
allowClear: true, // 允许清除已选中的值
treeDefaultExpandAll: true, // 默认展开所有节点(可选)
showSearch: true, // 允许搜索(可选)
treeNodeFilterProp: 'title', // 按 title 搜索(可选)
}
// valueEnum: {
// "0": "全部",

View File

@ -28,6 +28,7 @@ import classNames from 'classnames';
import session from '@/utils/session';
import ModalFooter from '../../scenicSpotConfig/component/modalFooter';
import { handeDeleteFIELDENUM, handeGetFIELDEXPLAINList, handeGetNestingFIELDENUMList, handeSynchroFIELDENUM } from '../../service';
import { convertTreeToLabelValue } from '@/utils/format';
const beforeUpload = (file: any) => {
@ -267,8 +268,21 @@ const GrowthConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (props)
SearchKey: ""
}
const data = await handeGetNestingFIELDENUMList(req);
console.log('dasjkdas', data);
if (data && data.length > 0) {
setTypeTreeData(data)
if (data && data.length > 0) {
const obj: any = {}
const list: any = []
data.forEach((item: any) => {
list.push({ label: item.FIELDENUM_NAME, value: item.FIELDENUM_VALUE })
obj[item.FIELDENUM_VALUE] = item.FIELDENUM_NAME
})
session.set('GROWTHTYPEList', list);
session.set('GROWTHTYPEObj', obj);
session.set('GROWTHTYPETree', convertTreeToLabelValue(data, 'FIELDENUM_NAME', 'FIELDENUM_VALUE'));
}
return { data: data, success: true, total: data.length }
}
return { data: [], success: true }

View File

@ -1,4 +1,4 @@
// 成长值规则配置
// 成长值规则配置 成长规则配置
import React, { useRef, useState, Suspense } from 'react';
import moment from 'moment'; // 时间相关引用,没有使用可以删除
import numeral from "numeral"; // 数字相关引用,没有使用可以删除
@ -78,7 +78,11 @@ const GrowthValueRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }>
align: 'center',
hideInSearch: true,
valueType: 'select',
valueEnum: GROWTHTYPEObj
// valueEnum: GROWTHTYPEObj
request: () => {
let GROWTHTYPEList = session.get('GROWTHTYPEList')
return GROWTHTYPEList
}
},
{
dataIndex: 'GROWTHSETTING_NAME',
@ -287,6 +291,7 @@ const GrowthValueRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }>
OWNERUNIT_ID: 911,
GROWTHSETTING_STATE: params?.GROWTHSETTING_STATE
},
SortStr: "PROMOTION_LEVEL desc",
PageIndex: 1,
PageSize: 20
}
@ -432,7 +437,10 @@ const GrowthValueRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }>
labelCol={{ style: { width: 80 } }}
initialValues={{
...currentRow,
SCORESETTING_STATE: (currentRow?.GROWTHSETTING_STATE || currentRow?.GROWTHSETTING_STATE === 0) ? currentRow?.GROWTHSETTING_STATE : 1
SCORESETTING_STATE: (currentRow?.GROWTHSETTING_STATE || currentRow?.GROWTHSETTING_STATE === 0) ? currentRow?.GROWTHSETTING_STATE : 1,
GROWTHSETTING_TYPE: currentRow?.GROWTHSETTING_TYPE ? currentRow?.GROWTHSETTING_TYPE.toString() : "",
MEMBERSHIP_LEVEL: currentRow?.MEMBERSHIP_LEVEL ? currentRow?.MEMBERSHIP_LEVEL.toString() : "",
PROMOTION_LEVEL: currentRow?.PROMOTION_LEVEL ? currentRow?.PROMOTION_LEVEL.toString() : "",
}}
onFinish={async (values) => {
let newValue: any = { ...values };
@ -457,7 +465,11 @@ const GrowthValueRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }>
message: '请选择规则类型'
}
]}
options={GROWTHTYPEList}
request={() => {
let GROWTHTYPEList = session.get('GROWTHTYPEList')
return GROWTHTYPEList
}}
// options={GROWTHTYPEList}
/>
</Col>
<Col span={12}>

View File

@ -63,6 +63,30 @@ const MallEvaluationManage: React.FC<{ currentUser: CurrentUser | undefined }> =
// 定义列表字段内容
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProp: {
placeholder: "请输入评价人员/商家名称"
}
},
{
title: '评价时间',
dataIndex: 'search_date',
valueType: 'dateRange',
hideInTable: true,
hideInDescriptions: true,
search: {
transform: (value) => {
return {
CREATE_DATE_Start: value[0],
CREATE_DATE_End: value[1],
};
},
},
initialValue: [moment().format('YYYY-MM-DD'), moment().add(-1, 'M').format('YYYY-MM-DD')],
},
{
dataIndex: 'index',
title: '序号',
@ -249,11 +273,17 @@ const MallEvaluationManage: React.FC<{ currentUser: CurrentUser | undefined }> =
searchParameter: {
OWNERUNIT_ID: currentUser?.OwnerUnitId,
PROVINCE_CODE: currentUser?.ProvinceCode,
ISVALID: 1
ISVALID: 1,
CREATE_DATE_Start: params?.CREATE_DATE_Start || "",
CREATE_DATE_End: params?.CREATE_DATE_End || "",
},
PageIndex: 1,
PageSize: 999999,
SortStr: "CREATE_DATE desc"
SortStr: "CREATE_DATE desc",
keyWord: {
Key: "SELLER_NAME,MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
}
const data = await handeGetMALLCOMMENTList(req)
console.log('datadatadatadatadata', data);

View File

@ -47,6 +47,14 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser }> = (props) => {
};
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProp: {
placeholder: "请输入供货商/购买的商品/收货人"
}
},
{
title: '查询时间',
dataIndex: 'search_date',
@ -360,6 +368,10 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser }> = (props) => {
PageIndex: 1,
PageSize: 999999,
SortStr: "ORDER_DATE desc",
keyWord: {
Key: "MERCHANTS_NAME,ORDER_PERSON,ORDER_PERSONTEL,SALEBILL_CODE,COMMODITY_NAME",
Value: params?.searchText || ""
},
}
console.log('reqreqreqreqreq', req);

View File

@ -84,7 +84,7 @@ const MemberAddress: React.FC<{ currentUser: CurrentUser | undefined }> = (props
align: 'center',
hideInTable: true,
fieldProps: {
placeholder: "输入收货人名称"
placeholder: "输入收货人名称/手机号"
}
},
{
@ -512,9 +512,9 @@ const MemberAddress: React.FC<{ currentUser: CurrentUser | undefined }> = (props
OwnerUnitId: currentUser?.OwnerUnitId || "",
Isvalid: 1,
PageIndex: params.current,
PageSize: params.pageSize,
PageSize: params?.pageSize,
SortStr: "CREATE_DATE desc",
SearchKeyName: "USER_NAME",
SearchKeyName: "MEMBERSHIP_NAME,MEMBERSHIP_MOBILEPHONE",
SearchKeyValue: params?.searchText || ""
}
@ -530,6 +530,10 @@ const MemberAddress: React.FC<{ currentUser: CurrentUser | undefined }> = (props
toolbar={{
actions: []
}}
pagination={{
defaultPageSize: 20,
showTotal: (total) => `${total} 条记录`
}}
/>
{/* 这里和 会员详情里面的同步 如果有什么修改 记得一起改 */}

View File

@ -0,0 +1,253 @@
.MemberSummaryStatisticsMain {
width: 100%;
.MemberSummaryStatisticsTop {
width: 100%;
background: #FFFFFF;
box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
border-radius: 4px;
box-sizing: border-box;
padding: 16px;
.MemberSummaryStatisticsTitleBox {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.MemberSummaryStatisticsTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 18px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
margin-left: 12px;
position: relative;
}
.MemberSummaryStatisticsTitle::after {
content: "";
width: 4px;
height: 18px;
background: #1492FF;
border-radius: 2px;
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
}
}
.MemberSummaryStatisticsContentBox {
width: 100%;
margin-top: 16px;
display: flex;
align-items: center;
justify-content: space-between;
// .MemberSummaryStatisticsItemFirst {
// width: 280px;
// height: 180px;
// background-image: url('../../../assets/detail/staticSumTotalBg.png');
// background-size: 100% 100%;
// background-repeat: no-repeat;
// box-sizing: border-box;
// padding: 26px 39px;
// margin-right: 16px;
// .firstItemTitle {
// font-family: PingFangSC, PingFang SC;
// font-weight: 500;
// font-size: 18px;
// color: #FFFFFF;
// line-height: 13px;
// text-align: left;
// font-style: normal;
// }
// .firstItemValue {
// font-family: DINAlternate, DINAlternate;
// font-weight: bold;
// font-size: 28px;
// color: #FFFFFF;
// line-height: 32px;
// text-align: left;
// font-style: normal;
// margin-top: 12px;
// }
// }
.MemberSummaryStatisticsItemOther {
width: 100%;
height: 180px;
display: flex;
align-items: center;
justify-content: space-between;
.MemberSummaryStatisticsOtherItem {
width: calc((100% - 96px) / 6);
height: 100%;
background: #F6F9FF;
border-radius: 8px;
box-sizing: border-box;
padding: 29px 24px;
position: relative;
cursor: pointer;
.otherItemTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
}
.otherItemValue {
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 32px;
color: #1492FF;
line-height: 38px;
text-align: left;
margin-top: 17px;
font-style: normal;
}
.otherItemAddBox {
display: flex;
align-items: center;
margin-top: 29px;
.addLabel {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 12px;
text-align: center;
font-style: normal;
margin-right: 5px;
}
.addIcon {
width: 7px;
height: 10px;
margin-right: 6px;
}
.addValue {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
line-height: 16px;
text-align: center;
font-style: normal;
}
}
// .otherBgIcon {
// width: 76px;
// height: 51px;
// position: absolute;
// top: 29px;
// right: 4px;
// background-image: url(../../../assets/detail/otherBgIcon.png);
// background-repeat: no-repeat;
// background-size: 100% 100%;
// }
}
.MemberSummaryStatisticsOtherItemSelect {
background-image: url('../../../assets/detail/staticSumTotalBg.png');
background-size: 100% 100%;
background-repeat: no-repeat;
.otherItemTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #fff;
line-height: 18px;
text-align: left;
font-style: normal;
}
.otherItemValue {
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 32px;
color: #fff;
line-height: 38px;
text-align: left;
margin-top: 17px;
font-style: normal;
}
.otherItemAddBox {
.addLabel {
color: #fff;
}
.addValue {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #fff;
line-height: 16px;
text-align: center;
font-style: normal;
}
}
}
}
}
}
.MemberSummaryStatisticsBottom {
width: 100%;
margin-top: 16px;
box-sizing: border-box;
background: #FFFFFF;
box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
border-radius: 4px;
padding: 16px;
.MemberSummaryStatisticsTitleBox {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.MemberSummaryStatisticsTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 18px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
margin-left: 12px;
position: relative;
}
.MemberSummaryStatisticsTitle::after {
content: "";
width: 4px;
height: 18px;
background: #1492FF;
border-radius: 2px;
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
}
}
}
}

View File

@ -0,0 +1,551 @@
// 会员汇总统计
import { ConnectState } from "@/models/connect";
import { connect, CurrentUser } from "umi";
import './MemberSummaryStatistics.less'
import ProTable, { ActionType } from "@ant-design/pro-table";
import { useEffect, useRef, useState } from "react";
import { Button, Col, FormInstance, Row, Tooltip } from "antd";
import { handeGetPointGrowthSummary, handleGetMEMBERGROWTHList, handleGetPOINTRECORDList } from "../service";
import moment from 'moment'
import addIcon from '@/assets/detail/addIcon.png'
import reduceIcon from '@/assets/detail/reduceIcon.png'
import session from "@/utils/session";
import ProForm, { ProFormDateRangePicker } from "@ant-design/pro-form";
const MemberSummaryStatistics: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
// 顶部内容的对象值
const [topData, setTopData] = useState<any>()
// 当前顶部的选择到了第几个
const [selectTab, setSelectTab] = useState<number>(1)
// 搜索参数
const [searchParams, setSearchParams] = useState<any>({
StartDate: moment().startOf('M').format('YYYY-MM-DD'),
EndDate: moment().format('YYYY-MM-DD')
})
let SCORETYPETree = session.get('SCORETYPETree')
// 主表隐藏的字段
const [columnsStateMap, setColumnsStateMap] = useState<any>({
TotalPointQOQData: { show: false },
EarnPointQOQData: { show: false },
ConsumePointQOQData: { show: false },
TotalGrowthQOQData: { show: false },
EarnGrowthQOQData: { show: false },
ConsumeGrowthQOQData: { show: false },
})
// 积分的columns
const columns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true
},
{
title: '查询时间',
dataIndex: 'search_date',
valueType: 'dateRange',
hideInTable: true,
hideInDescriptions: true,
search: {
transform: (value: any) => {
return {
StartDate: value[0],
EndDate: value[1],
};
},
},
initialValue: [moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
},
{
title: "服务区名称",
width: 150,
dataIndex: "SERVERPART_NAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "门店名称",
width: 150,
dataIndex: "SHOPNAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "积分方式",
width: 120,
dataIndex: "POINT_TYPE",
ellipsis: true,
hideInSearch: true,
valueType: 'select',
align: 'center',
valueEnum: {
"-2": "全部",
"1": "累计",
"-1": "消耗"
}
},
{
title: "积分来源",
width: 120,
dataIndex: "POINT_SOURCE",
ellipsis: true,
hideInSearch: true,
valueType: 'treeSelect',
align: 'center',
request: () => {
return SCORETYPETree
}
},
{
title: "本次积分",
width: 120,
dataIndex: "CURRENT_POINT",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: "digit"
},
{
title: "累计积分",
width: 120,
dataIndex: "MEMBERSHIP_POINT",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: "digit"
},
{
title: "会员名称",
width: 150,
dataIndex: "MEMBERSHIP_NAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "获取时间",
width: 150,
dataIndex: "CREATE_DATE",
hideInSearch: true,
align: 'center',
ellipsis: true,
render: (_, record) => {
return record?.CREATE_DATE ? moment(record?.CREATE_DATE).format('YYYY-MM-DD') : "-"
}
},
]
// 成长值的columns
const growthColumns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true
},
{
title: '查询时间',
dataIndex: 'search_date',
valueType: 'dateRange',
hideInTable: true,
hideInDescriptions: true,
search: {
transform: (value: any) => {
return {
StartDate: value[0],
EndDate: value[1],
};
},
},
initialValue: [moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
},
{
title: "服务区名称",
width: 150,
dataIndex: "SERVERPART_NAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "门店名称",
width: 150,
dataIndex: "SHOPNAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "累计成长值",
width: 120,
dataIndex: "MEMBERSHIP_GROWTH",
hideInSearch: true,
align: 'center',
ellipsis: true,
valueType: 'digit'
},
{
title: "本次成长值",
width: 120,
dataIndex: "CURRENT_GROWTH",
hideInSearch: true,
align: 'center',
ellipsis: true,
valueType: 'digit'
},
{
title: "成长来源",
width: 120,
dataIndex: "GROWTH_SOURCE",
align: 'center',
ellipsis: true,
hideInSearch: true,
valueType: 'treeSelect',
request: () => {
return SCORETYPETree
}
},
{
title: "成长方式",
width: 120,
dataIndex: "GROWTH_TYPE",
ellipsis: true,
align: 'center',
valueType: 'select',
hideInSearch: true,
valueEnum: {
"-2": "全部",
"1": "积累",
"-1": "消耗",
},
},
{
title: "会员名称",
width: 150,
dataIndex: "MEMBERSHIP_NAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "操作时间",
width: 120,
dataIndex: "OPERATE_DATE",
align: 'center',
hideInSearch: true,
render: (_, record) => {
return record?.OPERATE_DATE ? moment(record?.OPERATE_DATE).format('YYYY-MM-DD') : "-"
}
},
]
useEffect(() => {
handleGetTopData()
}, [])
// 获取顶部的数据
const handleGetTopData = async (StartDate?: string, EndDate?: string) => {
const req: any = {
CalcType: 1, // 1 汇总 2 会员等级 3 会员类型
OwnerUnitId: currentUser?.OwnerUnitId,
StartDate: StartDate ? StartDate : searchParams?.StartDate ? searchParams?.StartDate : "",
EndDate: EndDate ? EndDate : searchParams?.EndDate ? searchParams?.EndDate : "",
PointSource: "",
ServerpartId: "",
MemberShipId: "",
MembershipType: "",
MembershipLevel: "",
MembershipTarget: ""
}
const data = await handeGetPointGrowthSummary(req)
console.log('datadatadatadatadata', data);
let sumObj: any = data[0]
setTopData(sumObj)
}
// 改变顶部的选择
const handleChangeTab = (value: number) => {
setSelectTab(value)
actionRef.current?.reload()
}
return (
<div className="MemberSummaryStatisticsMain">
<div className="MemberSummaryStatisticsTop">
<div className="MemberSummaryStatisticsTitleBox">
<div className="MemberSummaryStatisticsTitle"></div>
</div>
<Row style={{ marginTop: "16px" }}>
<Col span={18}>
<ProForm
layout={'horizontal'}
formRef={formRef}
submitter={false}
onFinish={async (values: any) => {
console.log('values', values);
let [StartDate, EndDate] = ['', '']
if (values.searchTime && values.searchTime.length > 0) {
[StartDate, EndDate] = values.searchTime
}
handleGetTopData(StartDate, EndDate)
setSearchParams({
StartDate: StartDate,
EndDate: EndDate
})
actionRef.current?.reload()
}}
>
<ProFormDateRangePicker
label={"查询时间"}
name={"searchTime"}
initialValue={[moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]}
/>
</ProForm>
</Col>
<Col span={6}>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button style={{ marginRight: '8px' }} onClick={() => {
formRef.current?.resetFields()
}}></Button>
<Button type={"primary"} onClick={() => {
formRef.current?.submit()
}}></Button>
</div>
</Col>
</Row>
<div className="MemberSummaryStatisticsContentBox">
<div className="MemberSummaryStatisticsItemOther">
<div className={selectTab === 1 ? 'MemberSummaryStatisticsOtherItem MemberSummaryStatisticsOtherItemSelect' : 'MemberSummaryStatisticsOtherItem'} onClick={() => {
handleChangeTab(1)
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{topData && topData?.TotalPoint ? topData?.TotalPoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
topData && topData?.TotalPoint && topData?.TotalPoint.QOQData && topData?.TotalPoint.summaryData ?
<img className="addIcon" src={((topData?.TotalPoint.summaryData - topData?.TotalPoint.QOQData) / topData?.TotalPoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
topData && topData?.TotalPoint && topData?.TotalPoint.QOQData && topData?.TotalPoint.summaryData ?
// <span className="addValue">{topData && topData?.TotalPoint ? topData?.TotalPoint.QOQData : "-"}</span>
<Tooltip title={`((${topData?.TotalPoint.summaryData} - ${topData?.TotalPoint.QOQData}) / ${topData?.TotalPoint.QOQData}) * 100`}>
<span className="addValue">{(((topData?.TotalPoint.summaryData - topData?.TotalPoint.QOQData) / topData?.TotalPoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: "-"
}
</div>
</div>
<div className={selectTab === 2 ? 'MemberSummaryStatisticsOtherItem MemberSummaryStatisticsOtherItemSelect' : 'MemberSummaryStatisticsOtherItem'} onClick={() => {
handleChangeTab(2)
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{topData && topData?.EarnPoint ? topData?.EarnPoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
topData && topData?.EarnPoint && topData?.EarnPoint.QOQData && topData?.EarnPoint.summaryData ?
<img className="addIcon" src={((topData?.EarnPoint.summaryData - topData?.EarnPoint.QOQData) / topData?.EarnPoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
topData && topData?.EarnPoint && topData?.EarnPoint.QOQData && topData?.EarnPoint.summaryData ?
// <span className="addValue">{topData && topData?.EarnPoint ? topData?.EarnPoint.QOQData : "-"}</span>
<Tooltip title={`((${topData?.EarnPoint.summaryData} - ${topData?.EarnPoint.QOQData}) / ${topData?.EarnPoint.QOQData}) * 100`}>
<span className="addValue">{(((topData?.EarnPoint.summaryData - topData?.EarnPoint.QOQData) / topData?.EarnPoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={selectTab === 3 ? 'MemberSummaryStatisticsOtherItem MemberSummaryStatisticsOtherItemSelect' : 'MemberSummaryStatisticsOtherItem'} onClick={() => {
handleChangeTab(3)
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{topData && topData?.ConsumePoint ? topData?.ConsumePoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
topData && topData?.ConsumePoint && topData?.ConsumePoint.QOQData && topData?.ConsumePoint.summaryData ?
<img className="addIcon" src={((topData?.ConsumePoint.summaryData - topData?.ConsumePoint.QOQData) / topData?.ConsumePoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
topData && topData?.ConsumePoint && topData?.ConsumePoint.QOQData && topData?.ConsumePoint.summaryData ?
// <span className="addValue">{topData && topData?.ConsumePoint ? topData?.ConsumePoint.QOQData : "-"}</span>
<Tooltip title={`((${topData?.ConsumePoint.summaryData} - ${topData?.ConsumePoint.QOQData}) / ${topData?.ConsumePoint.QOQData}) * 100`}>
<span className="addValue">{(((topData?.ConsumePoint.summaryData - topData?.ConsumePoint.QOQData) / topData?.ConsumePoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={selectTab === 4 ? 'MemberSummaryStatisticsOtherItem MemberSummaryStatisticsOtherItemSelect' : 'MemberSummaryStatisticsOtherItem'} onClick={() => {
handleChangeTab(4)
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{topData && topData?.TotalGrowth ? topData?.TotalGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
topData && topData?.TotalGrowth && topData?.TotalGrowth.QOQData && topData?.TotalGrowth.summaryData ?
<img className="addIcon" src={((topData?.TotalGrowth.summaryData - topData?.TotalGrowth.QOQData) / topData?.TotalGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
topData && topData?.TotalGrowth && topData?.TotalGrowth.QOQData && topData?.TotalGrowth.summaryData ?
// <span className="addValue">{topData && topData?.TotalGrowth ? topData?.TotalGrowth.QOQData : "-"}</span>
<Tooltip title={`((${topData?.TotalGrowth.summaryData} - ${topData?.TotalGrowth.QOQData}) / ${topData?.TotalGrowth.QOQData}) * 100`}>
<span className="addValue">{(((topData?.TotalGrowth.summaryData - topData?.TotalGrowth.QOQData) / topData?.TotalGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
</div>
<div className={selectTab === 5 ? 'MemberSummaryStatisticsOtherItem MemberSummaryStatisticsOtherItemSelect' : 'MemberSummaryStatisticsOtherItem'} onClick={() => {
handleChangeTab(5)
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{topData && topData?.EarnGrowth ? topData?.EarnGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
topData && topData?.EarnGrowth && topData?.EarnGrowth.QOQData && topData?.EarnGrowth.summaryData ?
<img className="addIcon" src={((topData?.EarnGrowth.summaryData - topData?.EarnGrowth.QOQData) / topData?.EarnGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
topData && topData?.EarnGrowth && topData?.EarnGrowth.QOQData && topData?.EarnGrowth.summaryData ?
// <span className="addValue">{topData && topData?.EarnGrowth ? topData?.EarnGrowth.QOQData : "-"}</span>
<Tooltip title={`((${topData?.EarnGrowth.summaryData} - ${topData?.EarnGrowth.QOQData}) / ${topData?.EarnGrowth.QOQData}) * 100`}>
<span className="addValue">{(((topData?.EarnGrowth.summaryData - topData?.EarnGrowth.QOQData) / topData?.EarnGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={selectTab === 6 ? 'MemberSummaryStatisticsOtherItem MemberSummaryStatisticsOtherItemSelect' : 'MemberSummaryStatisticsOtherItem'} onClick={() => {
handleChangeTab(6)
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{topData && topData?.ConsumeGrowth ? topData?.ConsumeGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
topData && topData?.ConsumeGrowth && topData?.ConsumeGrowth.QOQData && topData?.ConsumeGrowth.summaryData ?
<img className="addIcon" src={((topData?.ConsumeGrowth.summaryData - topData?.ConsumeGrowth.QOQData) / topData?.ConsumeGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
topData && topData?.ConsumeGrowth && topData?.ConsumeGrowth.QOQData && topData?.ConsumeGrowth.summaryData ?
// <span className="addValue">{topData && topData?.ConsumeGrowth ? topData?.ConsumeGrowth.QOQData : "-"}</span>
<Tooltip title={`((${topData?.ConsumeGrowth.summaryData} - ${topData?.ConsumeGrowth.QOQData}) / ${topData?.ConsumeGrowth.QOQData}) * 100`}>
<span className="addValue">{(((topData?.ConsumeGrowth.summaryData - topData?.ConsumeGrowth.QOQData) / topData?.ConsumeGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
</div>
</div>
</div>
<div className="MemberSummaryStatisticsBottom">
<ProTable
actionRef={actionRef}
columns={selectTab <= 3 ? columns : growthColumns}
bordered
search={false}
scroll={{ x: "100%", y: '400px' }}
request={async () => {
// 判断当前选择的 1、2、3为积分的 4、5、6 为成长值的
let req: any = {}
let data: any = {}
const params = searchParams;
if (selectTab <= 3) {
req = {
SearchParameter: {
// PROVINCE_CODE: currentUser?.ProvinceCode || "",
OPERATE_DATE_Start: params?.StartDate || "",
OPERATE_DATE_End: params?.EndDate || "",
OWNERUNIT_ID: 911,
POINT_TYPE: selectTab === 1 ? '' : selectTab === 2 ? '1' : selectTab === 3 ? '-1' : '',
POINT_SOURCE: ''
},
keyWord: {
Key: "MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
PageIndex: params?.current,
PageSize: 20,
sortstr: "OPERATE_DATE desc",
}
data = await handleGetPOINTRECORDList(req)
} else {
req = {
searchParameter: {
// PROVINCE_CODE: currentUser?.ProvinceCode || "",
OPERATE_DATE_Start: params?.StartDate || "",
OPERATE_DATE_End: params?.EndDate || "",
OWNERUNIT_ID: 911,
SCORESETTING_STATE: 1,
GROWTH_SOURCES: "",
GROWTH_TYPE: selectTab === 4 ? '' : selectTab === 5 ? '1' : selectTab === 6 ? '-1' : ''
},
PageIndex: params?.current,
PageSize: 20,
sortstr: "OPERATE_DATE desc",
keyWord: {
Key: "MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
}
data = await handleGetMEMBERGROWTHList(req);
}
// if (searchParams.StartDate !== params?.StartDate || searchParams.EndDate !== params?.EndDate) {
// await handleGetTopData(params?.StartDate, params?.EndDate)
// }
setSearchParams(params)
if (data.List && data.List.length > 0) {
return { data: data.List, success: true, total: data.TotalCount }
}
return { data: [], success: true }
}}
columnsState={{
value: columnsStateMap,
onChange: setColumnsStateMap,
}}
/>
</div>
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(MemberSummaryStatistics);

View File

@ -1,15 +1,485 @@
// 会员标签管理
import { ConnectState } from "@/models/connect";
import { connect, CurrentUser } from "umi";
import React, { useRef, useState, Suspense } from 'react';
import moment from 'moment'; // 时间相关引用,没有使用可以删除
import numeral from "numeral"; // 数字相关引用,没有使用可以删除
import { connect } from 'umi';
const MemberTagManage: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => {
return (
<div>
import useRequest from '@ahooksjs/use-request'; // 请求数据的引用
import Draggable from 'react-draggable';
import SubMenu from "antd/lib/menu/SubMenu";
import ProTable from '@ant-design/pro-table';
import ProDescriptions from '@ant-design/pro-descriptions';
import ProForm, { ProFormDatePicker, ProFormDateTimePicker, ProFormDateTimeRangePicker, ProFormDigit, ProFormMoney, ProFormSelect, ProFormText, ProFormTextArea, ProFormTreeSelect, ProFormUploadButton } from '@ant-design/pro-form';
import { MenuFoldOutlined, PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-layout';
import { Button, Col, Drawer, message, Row, Popconfirm, Space, Image, Modal, Form, Switch, Upload, Tooltip, Descriptions, TreeSelect } from 'antd';
</div>
)
import type { CurrentUser } from "umi";
import type { ConnectState } from '@/models/connect';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import type { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import type { FormInstance } from 'antd';
import { getFieldEnumTree, getFieldEnumName } from "@/services/options"; // 枚举的引用,没有使用可以删除
import { handeDeleteAUTOTYPE, handeDeleteFIELDENUM, handeGetFIELDENUMList, handeGetFIELDEXPLAINList, handeGetNestingAUTOTYPEList, handeGetNestingFIELDENUMList, handeSynchroAUTOTYPE, handeSynchroFIELDENUM, handlDeleteUSERDEFINEDTYPE, handlGetUSERDEFINEDTYPEList, handlSynchroUSERDEFINEDTYPE } from '../service';
import PageTitleBox from '@/components/PageTitleBox';
import { uploadPicture } from '@/services/picture';
import defaultIcon from '../../../assets/brand/defaultIcon.png'
import classNames from 'classnames';
import session from '@/utils/session';
import ModalFooter from '../scenicSpotConfig/component/modalFooter';
const beforeUpload = (file: any) => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('请上传JPEG、jpg、png格式的图片文件!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('图片大小不超过 2MB!');
}
return isJpgOrPng && isLt2M;
}
const MemberTagManage: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => {
const { currentUser } = props
const { confirm } = Modal;
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const [currentRow, setCurrentRow] = useState<any>();
const [showDetail, setShowDetail] = useState<boolean>();
const [modalVisible, handleModalVisible] = useState<boolean>();
const [confirmLoading, handleConfirmLoading] = useState<boolean>(false) // 弹出框的内容表单是否在提交
const [searchParams, setSearchParams] = useState<any>();
// 分类的树形结构数据
const [typeTreeData, setTypeTreeData] = useState<any>()
// 表单里面的是否预售
const [formPRESALE_TYPE, setFormPRESALE_TYPE] = useState<boolean>(false)
// 弹出框拖动效果
const [bounds, setBounds] = useState<{ left: number, right: number, top: number, bottom: number }>() // 移动的位置
const [disabled, setDraggleDisabled] = useState<boolean>() // 是否拖动
const draggleRef = React.createRef<any>()
let AFTERSALETYPEObj = session.get('AFTERSALETYPEObj')
const { data: FIELDEXPLAIN_ID } = useRequest(async () => {
const req: any = {
SearchParameter: {
FIELDEXPLAIN_FIELD: "MEMBERSHIP_LEVEL_YN"
}
}
const data = await handeGetFIELDEXPLAINList(req)
if (data && data.length > 0) {
let obj: any = data[0]
return obj.FIELDEXPLAIN_ID
}
})
// 文件列表
const [fileList, setFileList] = useState<any>([])
const [imagePreviewVisible, setImagePreviewVisible] = useState<boolean>(false) // 预览图片
const onDraggaleStart = (event, uiData) => {
const { clientWidth, clientHeight } = window.document.documentElement;
const targetRect = draggleRef.current?.getBoundingClientRect();
if (!targetRect) {
return;
}
setBounds({
left: -targetRect.left + uiData.x,
right: clientWidth - (targetRect.right - uiData.x),
top: -targetRect.top + uiData.y,
bottom: clientHeight - (targetRect.bottom - uiData.y),
});
};
// 定义列表字段内容
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
},
{
dataIndex: 'AUTOTYPE_NAME',
title: '类别名称',
align: 'center',
width: 300,
ellipsis: true,
hideInSearch: true,
hideInDescriptions: true,
render: (_, record) => {
return <a
onClick={() => {
setCurrentRow({ ...record });
handleModalVisible(true);
}}
>{record?.AUTOTYPE_NAME || ""}</a>
}
},
{
dataIndex: 'AUTOTYPE_INDEX',
title: '类别索引',
align: 'center',
width: 120,
ellipsis: true,
hideInSearch: true,
},
{
dataIndex: 'AUTOTYPE_VALID',
title: '有效状态',
align: 'center',
width: 120,
ellipsis: true,
valueType: "select",
valueEnum: {
"1": "有效",
"0": "无效"
},
initialValue: "1"
},
{
dataIndex: 'AUTOTYPE_DESC',
title: '备注说明',
align: 'center',
ellipsis: true,
hideInSearch: true,
},
];
// 预览上传后的图片
const handlePreview = async () => {
setFileList(fileList)
setImagePreviewVisible(true)
};
const handleChangePreview = (val: any) => {
setImagePreviewVisible(val)
}
// 删除点餐类别
const handelDelete = async (id: any) => {
const req: any = {
AUTOTYPEId: id
}
const result = await handeDeleteAUTOTYPE(req)
if (result.Result_Code !== 100) {
message.error(`${result.Result_Desc}` || `${result.Result_Code}:删除失败`);
} else {
message.success('删除成功!');
actionRef.current?.reload()
handleConfirmLoading(false)
handleModalVisible(false)
setFormPRESALE_TYPE(false)
setFileList([])
}
}
// 同步点餐列表
const handleAddUpdate = async (res: any) => {
let req: any = {}
if (currentRow?.FIELDENUM_ID) {
req = {
...currentRow,
...res,
AUTOTYPE_TYPEID: 2000,
AUTOTYPE_TYPENAME: "会员标签",
STAFF_ID: currentUser?.ID,
STAFF_NAME: currentUser?.Name,
OPERATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'),
}
} else {
req = {
...res,
AUTOTYPE_TYPEID: 2000,
AUTOTYPE_TYPENAME: "会员标签",
STAFF_ID: currentUser?.ID,
STAFF_NAME: currentUser?.Name,
OPERATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'),
ADDTIME: moment().format('YYYY-MM-DD HH:mm:ss'),
}
}
const data = await handeSynchroAUTOTYPE(req)
handleConfirmLoading(false)
if (data.Result_Code === 100) {
message.success("新增成功!")
setCurrentRow(undefined)
formRef?.current?.resetFields()
handleModalVisible(false)
setFormPRESALE_TYPE(false)
setFileList([])
actionRef.current?.reload()
} else {
message.error(data.Result_Desc)
}
}
return (
<PageContainer header={{
title: '',
breadcrumb: {}
}}>
<ProTable
style={{ height: 'calc(100vh - 135px)', background: '#fff' }}
scroll={{ y: 'calc(100vh - 410px)' }}
rowKey={(record) => {
return `${record?.AUTOTYPE_PID}-${record?.AUTOTYPE_ID}`
}}
formRef={formRef}
headerTitle={<PageTitleBox props={props} />} // 列表表头
actionRef={actionRef}
search={{ span: 6, labelWidth: 'auto' }}
bordered
// 请求数据
request={async (params, sorter) => {
const req = {
AUTOTYPE_TYPEID: '2000',
AUTOTYPE_PID: "",
OWNERUNIT_ID: currentUser?.OwnerUnitId,
AUTOTYPE_VALID: params?.AUTOTYPE_VALID,
SearchKey: params?.searchText || ""
}
const data = await handeGetNestingAUTOTYPEList(req);
console.log('datadatadatadatadata', data);
if (data && data.length > 0) {
setTypeTreeData(data)
return { data: data, success: true, total: data.length }
}
return { data: [], success: true }
}}
columns={columns}
toolbar={{
actions: [
// 新增按钮
<Button
key="new"
icon={<PlusOutlined />}
type="primary"
onClick={() => {
handleModalVisible(true);
}}
>
</Button>,
],
}}
/>
{/* 图片预览组件 */}
{fileList && fileList.length > 0 && <div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible: imagePreviewVisible,
onVisibleChange: vis => {
handleChangePreview(vis)
}
}}>
{
fileList.map((n) => <Image src={n.url} key={n.url} />)
}
</Image.PreviewGroup>
</div>}
<Modal
title={
<div
className='membershipLevel'
style={{
width: '100%',
cursor: 'move',
}}
onMouseOver={() => {
if (disabled) {
setDraggleDisabled(false)
}
}}
onMouseOut={() => {
setDraggleDisabled(true)
}}
onFocus={() => { }}
onBlur={() => { }}
>
{currentRow ? '更新会员标签类别' : '新建会员标签类别'}
</div>
}
destroyOnClose={true}
width={900}
bodyStyle={{
height: '700px', // 你可以根据需要调整高度
overflowY: 'auto',
}}
visible={modalVisible}
confirmLoading={confirmLoading}
afterClose={() => {
formRef.current?.resetFields();
setCurrentRow(undefined);
}}
footer={<ModalFooter
hideDelete={!currentRow?.AUTOTYPE_ID}
handleDelete={async () => {
await handelDelete(currentRow?.AUTOTYPE_ID)
}}
handleCancel={() => {
handleConfirmLoading(false)
handleModalVisible(false)
setFormPRESALE_TYPE(false)
setFileList([])
}}
handleOK={() => {
formRef?.current?.validateFields().then(() => {
handleConfirmLoading(true)
formRef?.current?.submit()
})
}}
/>}
onCancel={() => {
handleConfirmLoading(false)
handleModalVisible(false)
setFormPRESALE_TYPE(false)
setFileList([])
}}
onOk={async () => { // 提交框内的数据
formRef?.current?.validateFields().then(() => {
handleConfirmLoading(true)
formRef?.current?.submit()
})
}}
modalRender={(modal) => {
return <Draggable
disabled={disabled}
bounds={bounds}
onStart={(event, uiData) => onDraggaleStart(event, uiData)}
handle='.membershipLevel'
>
<div ref={draggleRef}>{modal}</div>
</Draggable>
}}
>
<ProForm
layout={'horizontal'}
formRef={formRef}
autoFocusFirstInput
labelCol={{ style: { width: 80 } }}
submitter={false}
preserve={false}
initialValues={currentRow ? {
...currentRow,
} : {
AUTOTYPE_VALID: 1,
}}
onFinish={async (values) => {
let newValue = { ...values };
if (currentRow) {
// 编辑数据
newValue = { ...values, FIELDENUM_ID: currentRow.FIELDENUM_ID };
}
// 如果有开关,要把开关的代码写进去
await handleAddUpdate(newValue);
handleConfirmLoading(false)
setFormPRESALE_TYPE(false)
}}
>
<Row gutter={8}>
<Col span={12}>
<ProFormTreeSelect
name="AUTOTYPE_PID"
label="上级类别"
request={async () => {
if (typeTreeData && typeTreeData.length > 0) {
let list: any = [{ AUTOTYPE_NAME: "默认类别", AUTOTYPE_ID: -1 }, ...typeTreeData]
return list
} else {
const req = {
AUTOTYPE_TYPEID: '2000',
AUTOTYPE_PID: "",
OWNERUNIT_ID: currentUser?.OwnerUnitId,
AUTOTYPE_VALID: 1,
SearchKey: ""
}
const data = await handeGetNestingAUTOTYPEList(req);
if (data && data.length > 0) {
data.unshirft({ AUTOTYPE_NAME: "默认类别", AUTOTYPE_ID: -1 })
setTypeTreeData(data)
return data
} else {
return [{ AUTOTYPE_NAME: "默认类别", AUTOTYPE_ID: -1 }]
}
}
}}
fieldProps={{
fieldNames: {
label: 'AUTOTYPE_NAME',
value: 'AUTOTYPE_ID',
children: 'children'
},
showSearch: true,
filterTreeNode: (input, node) =>
(node.AUTOTYPE_NAME || '').toLowerCase().includes(input.toLowerCase())
}}
rules={[
{
required: true,
message: "请选择上级类别"
}
]}
/>
</Col>
<Col span={12}>
<ProFormText
name="AUTOTYPE_NAME"
label="类别名称"
rules={[
{
required: true,
message: "请输入类别名称"
}
]}
/>
</Col>
<Col span={12}>
<ProFormDigit
name="AUTOTYPE_INDEX"
label="类别索引"
rules={[
{
required: true,
message: "请输入类别索引"
}
]}
/>
</Col>
<Col span={12}>
<ProFormSelect
name="AUTOTYPE_VALID"
label="有效状态"
options={[{ label: "有效", value: 1 }, { label: "无效", value: 0 }]}
rules={[
{
required: true,
message: "请选择有效状态"
}
]}
/>
</Col>
<Col span={24}>
<ProFormTextArea
name="AUTOTYPE_DESC"
label="备注"
/>
</Col>
</Row>
</ProForm>
</Modal>
</PageContainer >
);
};
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(MemberTagManage);

View File

@ -0,0 +1,258 @@
.MembershipLevelStatisticsMain {
width: 100%;
height: calc(100vh - 150px);
box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
background: #FFFFFF;
border-radius: 4px;
overflow-y: auto;
.MembershipLevelStatisticsTop {
width: 100%;
background: #FFFFFF;
// box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
// border-radius: 4px;
box-sizing: border-box;
padding: 16px;
.MembershipLevelStatisticsTitleBox {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.MembershipLevelStatisticsTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 18px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
margin-left: 12px;
position: relative;
}
.MembershipLevelStatisticsTitle::after {
content: "";
width: 4px;
height: 18px;
background: #1492FF;
border-radius: 2px;
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
}
}
.MembershipLevelStatisticsContentBox {
width: 100%;
margin-top: 16px;
display: flex;
align-items: center;
justify-content: space-between;
// .MembershipLevelStatisticsItemFirst {
// width: 280px;
// height: 180px;
// background-image: url('../../../assets/detail/staticSumTotalBg.png');
// background-size: 100% 100%;
// background-repeat: no-repeat;
// box-sizing: border-box;
// padding: 26px 39px;
// margin-right: 16px;
// .firstItemTitle {
// font-family: PingFangSC, PingFang SC;
// font-weight: 500;
// font-size: 18px;
// color: #FFFFFF;
// line-height: 13px;
// text-align: left;
// font-style: normal;
// }
// .firstItemValue {
// font-family: DINAlternate, DINAlternate;
// font-weight: bold;
// font-size: 28px;
// color: #FFFFFF;
// line-height: 32px;
// text-align: left;
// font-style: normal;
// margin-top: 12px;
// }
// }
.MembershipLevelStatisticsItemOther {
width: 100%;
height: 180px;
display: flex;
align-items: center;
justify-content: space-between;
.MembershipLevelStatisticsOtherItem {
width: calc((100% - 96px) / 6);
height: 100%;
background: #F6F9FF;
border-radius: 8px;
box-sizing: border-box;
padding: 29px 24px;
position: relative;
cursor: pointer;
.otherItemTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
}
.otherItemValue {
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 32px;
color: #1492FF;
line-height: 38px;
text-align: left;
margin-top: 17px;
font-style: normal;
}
.otherItemAddBox {
display: flex;
align-items: center;
margin-top: 29px;
.addLabel {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 12px;
text-align: center;
font-style: normal;
margin-right: 5px;
}
.addIcon {
width: 7px;
height: 10px;
margin-right: 6px;
}
.addValue {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
line-height: 16px;
text-align: center;
font-style: normal;
}
}
.otherBgIcon {
width: 76px;
height: 51px;
position: absolute;
top: 29px;
right: 4px;
background-image: url(../../../assets/detail/otherBgIcon.png);
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
.MembershipLevelStatisticsOtherItemSelect {
background-image: url('../../../assets/detail/staticSumTotalBg.png');
background-size: 100% 100%;
background-repeat: no-repeat;
.otherItemTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #fff;
line-height: 18px;
text-align: left;
font-style: normal;
}
.otherItemValue {
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 32px;
color: #fff;
line-height: 38px;
text-align: left;
margin-top: 17px;
font-style: normal;
}
.otherItemAddBox {
.addLabel {
color: #fff;
}
.addValue {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #fff;
line-height: 16px;
text-align: center;
font-style: normal;
}
}
}
}
}
}
.MembershipLevelStatisticsBottom {
width: 100%;
margin-top: 16px;
box-sizing: border-box;
background: #FFFFFF;
box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
border-radius: 4px;
padding: 16px;
.MembershipLevelStatisticsTitleBox {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.MembershipLevelStatisticsTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 18px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
margin-left: 12px;
position: relative;
}
.MembershipLevelStatisticsTitle::after {
content: "";
width: 4px;
height: 18px;
background: #1492FF;
border-radius: 2px;
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
}
}
}
}

View File

@ -0,0 +1,702 @@
// 会员汇总统计
import { ConnectState } from "@/models/connect";
import { connect, CurrentUser } from "umi";
import './MembershipLevelStatistics.less'
import ProTable, { ActionType } from "@ant-design/pro-table";
import { useEffect, useRef, useState } from "react";
import { Button, Col, Drawer, FormInstance, Row, Spin, Tabs, Tooltip } from "antd";
import { handeGetPointGrowthSummary, handleGetMEMBERGROWTHList, handleGetPOINTRECORDList } from "../service";
import moment from 'moment'
import addIcon from '@/assets/detail/addIcon.png'
import reduceIcon from '@/assets/detail/reduceIcon.png'
import session from "@/utils/session";
import ProForm, { ProFormDateRangePicker } from "@ant-design/pro-form";
const MembershipLevelStatistics: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
// 顶部内容的对象值
const [topData, setTopData] = useState<any>()
// 当前顶部的选择到了第几个
const [selectTab, setSelectTab] = useState<number>(1)
// 搜索参数
const [searchParams, setSearchParams] = useState<any>({
StartDate: moment().startOf('M').format('YYYY-MM-DD'),
EndDate: moment().format('YYYY-MM-DD')
})
// 选择的大的tab
const [selectBigTab, setSelectBigTab] = useState<string>('1')
// 大tab能切换的内容
const [tabList, setTabList] = useState<any>([])
// 判断是不是第一次进入页面
const [isFirst, setIsFirst] = useState<boolean>(true)
// 数据的加载效果
const [topLoading, setTopLoading] = useState<boolean>(false)
// 当前选中的是第几个数据
const [currentIndex, setCurrentIndex] = useState<any>()
const [currentRow, setCurrentRow] = useState<any>()
// 抽屉显示的值
const [currentDrawerTitle, setCurrentDrawerTitle] = useState<string>('')
let SCORETYPETree = session.get('SCORETYPETree')
let MEMBERSHIPLEVELYNObj = session.get('MEMBERSHIPLEVELYNObj')
let MEMBERSHIPTYPEYNObj = session.get('MEMBERSHIPTYPEYNObj')
// 主表隐藏的字段
const [columnsStateMap, setColumnsStateMap] = useState<any>({
TotalPointQOQData: { show: false },
EarnPointQOQData: { show: false },
ConsumePointQOQData: { show: false },
TotalGrowthQOQData: { show: false },
EarnGrowthQOQData: { show: false },
ConsumeGrowthQOQData: { show: false },
})
// 显示详情抽屉
const [showDetail, setShowDetail] = useState<boolean>(false)
// 顶部的数组内容
const [topListData, setTopListData] = useState<any>([])
// 积分的columns
const columns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true
},
// {
// title: '查询时间',
// dataIndex: 'search_date',
// valueType: 'dateRange',
// hideInTable: true,
// hideInDescriptions: true,
// search: {
// transform: (value: any) => {
// return {
// StartDate: value[0],
// EndDate: value[1],
// };
// },
// },
// initialValue: [moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
// },
{
title: "服务区名称",
width: 150,
dataIndex: "SERVERPART_NAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "门店名称",
width: 150,
dataIndex: "SHOPNAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "积分方式",
width: 120,
dataIndex: "POINT_TYPE",
ellipsis: true,
hideInSearch: true,
valueType: 'select',
align: 'center',
valueEnum: {
"-2": "全部",
"1": "累计",
"-1": "消耗"
}
},
{
title: "积分来源",
width: 120,
dataIndex: "POINT_SOURCE",
ellipsis: true,
hideInSearch: true,
valueType: 'treeSelect',
align: 'center',
request: () => {
return SCORETYPETree
}
},
{
title: "本次积分",
width: 120,
dataIndex: "CURRENT_POINT",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: "digit"
},
{
title: "累计积分",
width: 120,
dataIndex: "MEMBERSHIP_POINT",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: "digit"
},
{
title: "会员类型",
width: 120,
dataIndex: "MEMBERSHIP_TYPE",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: 'select',
valueEnum: MEMBERSHIPTYPEYNObj
},
{
title: "会员名称",
width: 150,
dataIndex: "MEMBERSHIP_NAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "获取时间",
width: 150,
dataIndex: "CREATE_DATE",
hideInSearch: true,
align: 'center',
ellipsis: true,
render: (_, record) => {
return record?.CREATE_DATE ? moment(record?.CREATE_DATE).format('YYYY-MM-DD') : "-"
}
},
]
// 成长值的columns
const growthColumns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true
},
// {
// title: '查询时间',
// dataIndex: 'search_date',
// valueType: 'dateRange',
// hideInTable: true,
// hideInDescriptions: true,
// search: {
// transform: (value: any) => {
// return {
// StartDate: value[0],
// EndDate: value[1],
// };
// },
// },
// initialValue: [moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
// },
{
title: "服务区名称",
width: 150,
dataIndex: "SERVERPART_NAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "门店名称",
width: 150,
dataIndex: "SHOPNAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "累计成长值",
width: 120,
dataIndex: "MEMBERSHIP_GROWTH",
hideInSearch: true,
align: 'center',
ellipsis: true,
valueType: 'digit'
},
{
title: "本次成长值",
width: 120,
dataIndex: "CURRENT_GROWTH",
hideInSearch: true,
align: 'center',
ellipsis: true,
valueType: 'digit'
},
{
title: "成长来源",
width: 120,
dataIndex: "GROWTH_SOURCE",
align: 'center',
ellipsis: true,
hideInSearch: true,
valueType: 'treeSelect',
request: () => {
return SCORETYPETree
}
},
{
title: "成长方式",
width: 120,
dataIndex: "GROWTH_TYPE",
ellipsis: true,
align: 'center',
valueType: 'select',
hideInSearch: true,
valueEnum: {
"-2": "全部",
"1": "积累",
"-1": "消耗",
},
},
{
title: "会员等级",
width: 120,
dataIndex: "MEMBERSHIP_LEVEL",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: 'select',
valueEnum: MEMBERSHIPLEVELYNObj
},
{
title: "会员名称",
width: 150,
dataIndex: "MEMBERSHIP_NAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "操作时间",
width: 120,
dataIndex: "OPERATE_DATE",
align: 'center',
hideInSearch: true,
render: (_, record) => {
return record?.OPERATE_DATE ? moment(record?.OPERATE_DATE).format('YYYY-MM-DD') : "-"
}
},
]
useEffect(() => {
const initData = async () => {
await handleGetTopData();
// 使用最新的selectBigTab值触发表格加载
// actionRef.current?.reload();
};
initData();
}, [])
// 获取顶部的数据
const handleGetTopData = async (StartDate?: string, EndDate?: string) => {
const req: any = {
CalcType: 2, // 1 汇总 2 会员等级 3 会员类型
OwnerUnitId: currentUser?.OwnerUnitId,
StartDate: StartDate ? StartDate : searchParams?.StartDate ? searchParams?.StartDate : "",
EndDate: EndDate ? EndDate : searchParams?.EndDate ? searchParams?.EndDate : "",
PointSource: "",
ServerpartId: "",
MemberShipId: "",
MembershipType: "",
MembershipLevel: "",
MembershipTarget: ""
}
setTopLoading(true)
const data = await handeGetPointGrowthSummary(req)
setTopLoading(false)
console.log('datadatadatadatadata', data);
let sumObj: any = data[0]
setTopListData(data)
setTopData(sumObj)
let list: any = []
if (data && data.length > 0) {
data.forEach((item: any) => {
list.push({ label: item.StatisticalName && MEMBERSHIPLEVELYNObj && MEMBERSHIPLEVELYNObj[item.StatisticalName] ? MEMBERSHIPLEVELYNObj[item.StatisticalName.toString()] : "", value: item.StatisticalName, key: item.StatisticalName })
})
}
console.log('listlistlistlist', list);
// 使用函数形式的setState确保获取到最新值
return new Promise<string>((resolve) => {
setTabList(list);
const newTabKey = list[0]?.key || '1';
setSelectBigTab(newTabKey);
resolve(newTabKey);
});
}
// 改变顶部的选择
const handleChangeTab = (value: number) => {
// 立即更新状态
setSelectTab(value);
// 使用setTimeout确保状态更新后再触发表格重新加载
setTimeout(() => {
actionRef.current?.reload();
}, 0);
}
// 判断当前是点击看哪个的详情
const handleShowDetail = (index: number, obj: any) => {
setCurrentIndex(index)
setCurrentRow(obj)
let item: any = topListData[index]
let type: string = obj.TotalPoint ? '总积分' : obj.EarnPoint ? '赚取积分' : obj.ConsumePoint ? '消耗积分' : obj.TotalGrowth ? '总成长值' : obj.EarnGrowth ? '赚取成长值' : obj.ConsumeGrowth ? '消耗成长值' : ''
let typeTab: number = obj.TotalPoint ? 1 : obj.EarnPoint ? 2 : obj.ConsumePoint ? 3 : obj.TotalGrowth ? 4 : obj.EarnGrowth ? 5 : obj.ConsumeGrowth ? 6 : 0
console.log('typetypetype', type);
setSelectTab(typeTab)
let str: string = `${item.StatisticalName && MEMBERSHIPLEVELYNObj && MEMBERSHIPLEVELYNObj[item.StatisticalName] ? MEMBERSHIPLEVELYNObj[item.StatisticalName.toString()] : ""}${type}`
setCurrentDrawerTitle(str)
setShowDetail(true)
}
return (
<div className="MembershipLevelStatisticsMain">
{/* <Tabs
activeKey={selectBigTab}
onChange={(e: any) => {
// 立即更新状态确保UI立即响应
setSelectBigTab(e);
// 使用setTimeout确保状态更新后再触发表格重新加载
setTimeout(() => {
actionRef.current?.reload();
}, 0);
}}
items={tabList}
/> */}
{
topLoading ?
<div
style={{
width: '100%',
height: '100%',
background: 'rgba(0,0,0,0.1)',
position: 'fixed',
zIndex: 5,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '15px 20px 10px',
background: '#fff',
borderRadius: '8px',
width: '200px'
}}>
<Spin />
<span style={{ marginLeft: '5px' }}>...</span>
</div>
</div> : ''
}
<div style={{ width: '100%', boxSizing: 'border-box', padding: '0 16px' }}>
<Row style={{ marginTop: "16px" }}>
<Col span={18}>
<ProForm
layout={'horizontal'}
formRef={formRef}
submitter={false}
onFinish={async (values: any) => {
console.log('values', values);
let [StartDate, EndDate] = ['', '']
if (values.searchTime && values.searchTime.length > 0) {
[StartDate, EndDate] = values.searchTime
}
handleGetTopData(StartDate, EndDate)
setSearchParams({
StartDate: StartDate,
EndDate: EndDate
})
actionRef.current?.reload()
}}
>
<ProFormDateRangePicker
label={"查询时间"}
name={"searchTime"}
initialValue={[moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]}
/>
</ProForm>
</Col>
<Col span={6}>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button style={{ marginRight: '8px' }} onClick={() => {
formRef.current?.resetFields()
}}></Button>
<Button type={"primary"} onClick={() => {
formRef.current?.submit()
}}></Button>
</div>
</Col>
</Row>
</div>
{
topListData && topListData.length > 0 ?
topListData.map((item: any, index: number) => {
return <div className="MembershipLevelStatisticsTop">
<div className="MembershipLevelStatisticsTitleBox">
<div className="MembershipLevelStatisticsTitle">{item.StatisticalName && MEMBERSHIPLEVELYNObj && MEMBERSHIPLEVELYNObj[item.StatisticalName] ? MEMBERSHIPLEVELYNObj[item.StatisticalName.toString()] : ""}</div>
</div>
<div className="MembershipLevelStatisticsContentBox">
<div className="MembershipLevelStatisticsItemOther">
<div className={'MembershipLevelStatisticsOtherItem MembershipLevelStatisticsOtherItemSelect'} onClick={() => {
handleShowDetail(index, {
TotalPoint: item?.TotalPoint
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.TotalPoint ? item?.TotalPoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.TotalPoint && item?.TotalPoint.QOQData && item?.TotalPoint.summaryData ?
<img className="addIcon" src={((item?.TotalPoint.summaryData - item?.TotalPoint.QOQData) / item?.TotalPoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.TotalPoint && item?.TotalPoint.QOQData && item?.TotalPoint.summaryData ?
// <span className="addValue">{item && item?.TotalPoint ? item?.TotalPoint.QOQData : "-"}</span>
<Tooltip title={`((${item?.TotalPoint.summaryData} - ${item?.TotalPoint.QOQData}) / ${item?.TotalPoint.QOQData}) * 100`}>
<span className="addValue">{(((item?.TotalPoint.summaryData - item?.TotalPoint.QOQData) / item?.TotalPoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: "-"
}
</div>
</div>
<div className={'MembershipLevelStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
EarnPoint: item?.EarnPoint
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.EarnPoint ? item?.EarnPoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.EarnPoint && item?.EarnPoint.QOQData && item?.EarnPoint.summaryData ?
<img className="addIcon" src={((item?.EarnPoint.summaryData - item?.EarnPoint.QOQData) / item?.EarnPoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.EarnPoint && item?.EarnPoint.QOQData && item?.EarnPoint.summaryData ?
// <span className="addValue">{item && item?.EarnPoint ? item?.EarnPoint.QOQData : "-"}</span>
<Tooltip title={`((${item?.EarnPoint.summaryData} - ${item?.EarnPoint.QOQData}) / ${item?.EarnPoint.QOQData}) * 100`}>
<span className="addValue">{(((item?.EarnPoint.summaryData - item?.EarnPoint.QOQData) / item?.EarnPoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={'MembershipLevelStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
ConsumePoint: item?.ConsumePoint
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.ConsumePoint ? item?.ConsumePoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.ConsumePoint && item?.ConsumePoint.QOQData && item?.ConsumePoint.summaryData ?
<img className="addIcon" src={((item?.ConsumePoint.summaryData - item?.ConsumePoint.QOQData) / item?.ConsumePoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.ConsumePoint && item?.ConsumePoint.QOQData && item?.ConsumePoint.summaryData ?
// <span className="addValue">{item && item?.ConsumePoint ? item?.ConsumePoint.QOQData : "-"}</span>
<Tooltip title={`((${item?.ConsumePoint.summaryData} - ${item?.ConsumePoint.QOQData}) / ${item?.ConsumePoint.QOQData}) * 100`}>
<span className="addValue">{(((item?.ConsumePoint.summaryData - item?.ConsumePoint.QOQData) / item?.ConsumePoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={'MembershipLevelStatisticsOtherItem MembershipLevelStatisticsOtherItemSelect'} onClick={() => {
handleShowDetail(index, {
TotalGrowth: item?.TotalGrowth
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.TotalGrowth ? item?.TotalGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.TotalGrowth && item?.TotalGrowth.QOQData && item?.TotalGrowth.summaryData ?
<img className="addIcon" src={((item?.TotalGrowth.summaryData - item?.TotalGrowth.QOQData) / item?.TotalGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.TotalGrowth && item?.TotalGrowth.QOQData && item?.TotalGrowth.summaryData ?
// <span className="addValue">{item && item?.TotalGrowth ? item?.TotalGrowth.QOQData : "-"}</span>
<Tooltip title={`((${item?.TotalGrowth.summaryData} - ${item?.TotalGrowth.QOQData}) / ${item?.TotalGrowth.QOQData}) * 100`}>
<span className="addValue">{(((item?.TotalGrowth.summaryData - item?.TotalGrowth.QOQData) / item?.TotalGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
</div>
<div className={'MembershipLevelStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
EarnGrowth: item?.EarnGrowth
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.EarnGrowth ? item?.EarnGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.EarnGrowth && item?.EarnGrowth.QOQData && item?.EarnGrowth.summaryData ?
<img className="addIcon" src={((item?.EarnGrowth.summaryData - item?.EarnGrowth.QOQData) / item?.EarnGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.EarnGrowth && item?.EarnGrowth.QOQData && item?.EarnGrowth.summaryData ?
// <span className="addValue">{item && item?.EarnGrowth ? item?.EarnGrowth.QOQData : "-"}</span>
<Tooltip title={`((${item?.EarnGrowth.summaryData} - ${item?.EarnGrowth.QOQData}) / ${topData?.EarnGrowth.QOQData}) * 100`}>
<span className="addValue">{(((item?.EarnGrowth.summaryData - item?.EarnGrowth.QOQData) / item?.EarnGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={'MembershipLevelStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
ConsumeGrowth: item?.ConsumeGrowth
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.ConsumeGrowth ? item?.ConsumeGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.ConsumeGrowth && item?.ConsumeGrowth.QOQData && item?.ConsumeGrowth.summaryData ?
<img className="addIcon" src={((item?.ConsumeGrowth.summaryData - item?.ConsumeGrowth.QOQData) / item?.ConsumeGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.ConsumeGrowth && item?.ConsumeGrowth.QOQData && item?.ConsumeGrowth.summaryData ?
// <span className="addValue">{item && item?.ConsumeGrowth ? item?.ConsumeGrowth.QOQData : "-"}</span>
<Tooltip title={`((${item?.ConsumeGrowth.summaryData} - ${item?.ConsumeGrowth.QOQData}) / ${item?.ConsumeGrowth.QOQData}) * 100`}>
<span className="addValue">{(((item?.ConsumeGrowth.summaryData - item?.ConsumeGrowth.QOQData) / item?.ConsumeGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
</div>
</div>
</div>
}) : ""
}
<Drawer
width={'80%'}
title={currentDrawerTitle || ""}
visible={showDetail}
destroyOnClose
closable={false}
onClose={() => {
setCurrentIndex(null)
setCurrentRow(null)
setSelectTab(0)
setCurrentDrawerTitle('')
setShowDetail(false)
}}
>
<ProTable
actionRef={actionRef}
// formRef={formRef}
columns={selectTab <= 3 ? columns : growthColumns}
bordered
scroll={{ x: "100%", y: 'calc(100vh - 400px)' }}
request={async (params) => {
// 判断当前选择的 1、2、3为积分的 4、5、6 为成长值的
let req: any = {}
let data: any = {}
// 确保使用最新的状态值
const currentTabValue = topListData[currentIndex].StatisticalName;
const currentSelectTab = selectTab;
if (selectTab <= 3) {
req = {
SearchParameter: {
MEMBERSHIP_TYPE: currentTabValue || "",
// PROVINCE_CODE: currentUser?.ProvinceCode || "",
OPERATE_DATE_Start: searchParams?.StartDate || "",
OPERATE_DATE_End: searchParams?.EndDate || "",
OWNERUNIT_ID: 911,
POINT_TYPE: selectTab === 1 ? '' : selectTab === 2 ? '1' : selectTab === 3 ? '-1' : '',
POINT_SOURCE: ''
},
keyWord: {
Key: "MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
PageIndex: params?.current,
PageSize: 20,
sortstr: "OPERATE_DATE desc",
}
data = await handleGetPOINTRECORDList(req)
} else {
req = {
searchParameter: {
// PROVINCE_CODE: currentUser?.ProvinceCode || "",
OPERATE_DATE_Start: searchParams?.StartDate || "",
OPERATE_DATE_End: searchParams?.EndDate || "",
OWNERUNIT_ID: 911,
SCORESETTING_STATE: 1,
GROWTH_SOURCES: "",
GROWTH_TYPE: selectTab === 4 ? '' : selectTab === 5 ? '1' : selectTab === 6 ? '-1' : ''
},
PageIndex: params?.current,
PageSize: 20,
sortstr: "OPERATE_DATE desc",
keyWord: {
Key: "MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
}
data = await handleGetMEMBERGROWTHList(req);
}
if (data.List && data.List.length > 0) {
return { data: data.List, success: true, total: data.TotalCount }
}
return { data: [], success: true }
}}
columnsState={{
value: columnsStateMap,
onChange: setColumnsStateMap,
}}
/>
</Drawer>
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(MembershipLevelStatistics);

View File

@ -0,0 +1,258 @@
.MembershipTypeStatisticsMain {
width: 100%;
height: calc(100vh - 150px);
box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
background: #FFFFFF;
border-radius: 4px;
overflow-y: auto;
.MembershipTypeStatisticsTop {
width: 100%;
background: #FFFFFF;
// box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
// border-radius: 4px;
box-sizing: border-box;
padding: 16px;
.MembershipTypeStatisticsTitleBox {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.MembershipTypeStatisticsTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 18px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
margin-left: 12px;
position: relative;
}
.MembershipTypeStatisticsTitle::after {
content: "";
width: 4px;
height: 18px;
background: #1492FF;
border-radius: 2px;
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
}
}
.MembershipTypeStatisticsContentBox {
width: 100%;
margin-top: 16px;
display: flex;
align-items: center;
justify-content: space-between;
// .MembershipTypeStatisticsItemFirst {
// width: 280px;
// height: 180px;
// background-image: url('../../../assets/detail/staticSumTotalBg.png');
// background-size: 100% 100%;
// background-repeat: no-repeat;
// box-sizing: border-box;
// padding: 26px 39px;
// margin-right: 16px;
// .firstItemTitle {
// font-family: PingFangSC, PingFang SC;
// font-weight: 500;
// font-size: 18px;
// color: #FFFFFF;
// line-height: 13px;
// text-align: left;
// font-style: normal;
// }
// .firstItemValue {
// font-family: DINAlternate, DINAlternate;
// font-weight: bold;
// font-size: 28px;
// color: #FFFFFF;
// line-height: 32px;
// text-align: left;
// font-style: normal;
// margin-top: 12px;
// }
// }
.MembershipTypeStatisticsItemOther {
width: 100%;
height: 180px;
display: flex;
align-items: center;
justify-content: space-between;
.MembershipTypeStatisticsOtherItem {
width: calc((100% - 96px) / 6);
height: 100%;
background: #F6F9FF;
border-radius: 8px;
box-sizing: border-box;
padding: 29px 24px;
position: relative;
cursor: pointer;
.otherItemTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
}
.otherItemValue {
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 32px;
color: #1492FF;
line-height: 38px;
text-align: left;
margin-top: 17px;
font-style: normal;
}
.otherItemAddBox {
display: flex;
align-items: center;
margin-top: 29px;
.addLabel {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 12px;
text-align: center;
font-style: normal;
margin-right: 5px;
}
.addIcon {
width: 7px;
height: 10px;
margin-right: 6px;
}
.addValue {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
line-height: 16px;
text-align: center;
font-style: normal;
}
}
.otherBgIcon {
width: 76px;
height: 51px;
position: absolute;
top: 29px;
right: 4px;
background-image: url(../../../assets/detail/otherBgIcon.png);
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
.MembershipTypeStatisticsOtherItemSelect {
background-image: url('../../../assets/detail/staticSumTotalBg.png');
background-size: 100% 100%;
background-repeat: no-repeat;
.otherItemTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 16px;
color: #fff;
line-height: 18px;
text-align: left;
font-style: normal;
}
.otherItemValue {
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 32px;
color: #fff;
line-height: 38px;
text-align: left;
margin-top: 17px;
font-style: normal;
}
.otherItemAddBox {
.addLabel {
color: #fff;
}
.addValue {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #fff;
line-height: 16px;
text-align: center;
font-style: normal;
}
}
}
}
}
}
.MembershipTypeStatisticsBottom {
width: 100%;
margin-top: 16px;
box-sizing: border-box;
background: #FFFFFF;
box-shadow: 0px 0px 6px 0px rgba(31, 48, 95, 0.2);
border-radius: 4px;
padding: 16px;
.MembershipTypeStatisticsTitleBox {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.MembershipTypeStatisticsTitle {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 18px;
color: #333333;
line-height: 18px;
text-align: left;
font-style: normal;
margin-left: 12px;
position: relative;
}
.MembershipTypeStatisticsTitle::after {
content: "";
width: 4px;
height: 18px;
background: #1492FF;
border-radius: 2px;
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
}
}
}
}

View File

@ -0,0 +1,728 @@
// 会员汇总统计
import { ConnectState } from "@/models/connect";
import { connect, CurrentUser } from "umi";
import './MembershipTypeStatistics.less'
import ProTable, { ActionType } from "@ant-design/pro-table";
import { useEffect, useRef, useState } from "react";
import { Button, Col, Drawer, FormInstance, Row, Spin, Tabs, Tooltip } from "antd";
import { handeGetPointGrowthSummary, handleGetMEMBERGROWTHList, handleGetPOINTRECORDList } from "../service";
import moment from 'moment'
import addIcon from '@/assets/detail/addIcon.png'
import reduceIcon from '@/assets/detail/reduceIcon.png'
import session from "@/utils/session";
import ProForm, { ProFormDateRangePicker } from "@ant-design/pro-form";
const MembershipTypeStatistics: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
// 顶部内容的对象值
const [topData, setTopData] = useState<any>()
// 顶部的数组内容
const [topListData, setTopListData] = useState<any>([])
// 当前顶部的选择到了第几个
const [selectTab, setSelectTab] = useState<number>(1)
// 搜索参数
const [searchParams, setSearchParams] = useState<any>({
StartDate: moment().startOf('M').format('YYYY-MM-DD'),
EndDate: moment().format('YYYY-MM-DD')
})
// 选择的大的tab
const [selectBigTab, setSelectBigTab] = useState<string>('1')
// 大tab能切换的内容
const [tabList, setTabList] = useState<any>([])
// 判断是不是第一次进入页面
const [isFirst, setIsFirst] = useState<boolean>(true)
// 数据的加载效果
const [topLoading, setTopLoading] = useState<boolean>(false)
// 当前选中的是第几个数据
const [currentIndex, setCurrentIndex] = useState<any>()
const [currentRow, setCurrentRow] = useState<any>()
// 抽屉显示的值
const [currentDrawerTitle, setCurrentDrawerTitle] = useState<string>('')
let SCORETYPETree = session.get('SCORETYPETree')
let MEMBERSHIPTYPEYNObj = session.get('MEMBERSHIPTYPEYNObj')
let MEMBERSHIPLEVELYNObj = session.get('MEMBERSHIPLEVELYNObj')
// 主表隐藏的字段
const [columnsStateMap, setColumnsStateMap] = useState<any>({
TotalPointQOQData: { show: false },
EarnPointQOQData: { show: false },
ConsumePointQOQData: { show: false },
TotalGrowthQOQData: { show: false },
EarnGrowthQOQData: { show: false },
ConsumeGrowthQOQData: { show: false },
})
// 显示详情抽屉
const [showDetail, setShowDetail] = useState<boolean>(false)
// 积分的columns
const columns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true
},
// {
// title: '查询时间',
// dataIndex: 'search_date',
// valueType: 'dateRange',
// hideInTable: true,
// hideInDescriptions: true,
// search: {
// transform: (value: any) => {
// return {
// StartDate: value[0],
// EndDate: value[1],
// };
// },
// },
// initialValue: [moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
// },
{
title: "服务区名称",
width: 150,
dataIndex: "SERVERPART_NAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "门店名称",
width: 150,
dataIndex: "SHOPNAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "积分方式",
width: 120,
dataIndex: "POINT_TYPE",
ellipsis: true,
hideInSearch: true,
valueType: 'select',
align: 'center',
valueEnum: {
"-2": "全部",
"1": "累计",
"-1": "消耗"
}
},
{
title: "积分来源",
width: 120,
dataIndex: "POINT_SOURCE",
ellipsis: true,
hideInSearch: true,
valueType: 'treeSelect',
align: 'center',
request: () => {
return SCORETYPETree
}
},
{
title: "本次积分",
width: 120,
dataIndex: "CURRENT_POINT",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: "digit"
},
{
title: "累计积分",
width: 120,
dataIndex: "MEMBERSHIP_POINT",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: "digit"
},
{
title: "会员类型",
width: 120,
dataIndex: "MEMBERSHIP_TYPE",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: 'select',
valueEnum: MEMBERSHIPTYPEYNObj
},
{
title: "会员名称",
width: 150,
dataIndex: "MEMBERSHIP_NAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "获取时间",
width: 150,
dataIndex: "CREATE_DATE",
hideInSearch: true,
align: 'center',
ellipsis: true,
render: (_, record) => {
return record?.CREATE_DATE ? moment(record?.CREATE_DATE).format('YYYY-MM-DD') : "-"
}
},
]
// 成长值的columns
const growthColumns: any = [
{
title: '查询内容',
dataIndex: 'searchText',
hideInTable: true
},
// {
// title: '查询时间',
// dataIndex: 'search_date',
// valueType: 'dateRange',
// hideInTable: true,
// hideInDescriptions: true,
// search: {
// transform: (value: any) => {
// return {
// StartDate: value[0],
// EndDate: value[1],
// };
// },
// },
// initialValue: [moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
// },
{
title: "服务区名称",
width: 150,
dataIndex: "SERVERPART_NAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "门店名称",
width: 150,
dataIndex: "SHOPNAME",
hideInSearch: true,
align: 'center',
ellipsis: true,
},
{
title: "累计成长值",
width: 120,
dataIndex: "MEMBERSHIP_GROWTH",
hideInSearch: true,
align: 'center',
ellipsis: true,
valueType: 'digit'
},
{
title: "本次成长值",
width: 120,
dataIndex: "CURRENT_GROWTH",
hideInSearch: true,
align: 'center',
ellipsis: true,
valueType: 'digit'
},
{
title: "成长来源",
width: 120,
dataIndex: "GROWTH_SOURCE",
align: 'center',
ellipsis: true,
hideInSearch: true,
valueType: 'treeSelect',
request: () => {
return SCORETYPETree
}
},
{
title: "成长方式",
width: 120,
dataIndex: "GROWTH_TYPE",
ellipsis: true,
align: 'center',
valueType: 'select',
hideInSearch: true,
valueEnum: {
"-2": "全部",
"1": "积累",
"-1": "消耗",
},
},
{
title: "会员等级",
width: 120,
dataIndex: "MEMBERSHIP_LEVEL",
hideInSearch: true,
ellipsis: true,
align: 'center',
valueType: 'select',
valueEnum: MEMBERSHIPLEVELYNObj
},
{
title: "会员名称",
width: 150,
dataIndex: "MEMBERSHIP_NAME",
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: "操作时间",
width: 120,
dataIndex: "OPERATE_DATE",
align: 'center',
hideInSearch: true,
render: (_, record) => {
return record?.OPERATE_DATE ? moment(record?.OPERATE_DATE).format('YYYY-MM-DD') : "-"
}
},
]
useEffect(() => {
const initData = async () => {
await handleGetTopData();
// 使用最新的selectBigTab值触发表格加载
actionRef.current?.reload();
};
initData();
}, [])
// 获取顶部的数据
const handleGetTopData = async (StartDate?: string, EndDate?: string) => {
const req: any = {
CalcType: 3, // 1 汇总 2 会员等级 3 会员类型
OwnerUnitId: currentUser?.OwnerUnitId,
StartDate: StartDate ? StartDate : searchParams?.StartDate ? searchParams?.StartDate : "",
EndDate: EndDate ? EndDate : searchParams?.EndDate ? searchParams?.EndDate : "",
PointSource: "",
ServerpartId: "",
MemberShipId: "",
MembershipType: "",
MembershipLevel: "",
MembershipTarget: ""
}
setTopLoading(true)
const data = await handeGetPointGrowthSummary(req)
setTopLoading(false)
console.log('datadatadatadatadata', data);
let sumObj: any = data[0]
setTopListData(data)
setTopData(sumObj)
let list: any = []
if (data && data.length > 0) {
data.forEach((item: any) => {
list.push({ label: item.StatisticalName && MEMBERSHIPTYPEYNObj && MEMBERSHIPTYPEYNObj[item.StatisticalName] ? MEMBERSHIPTYPEYNObj[item.StatisticalName.toString()] : "", value: item.StatisticalName, key: item.StatisticalName })
})
}
console.log('listlistlistlist', list);
// 使用函数形式的setState确保获取到最新值
return new Promise<string>((resolve) => {
setTabList(list);
const newTabKey = list[0]?.key || '1';
setSelectBigTab(newTabKey);
resolve(newTabKey);
});
}
// 改变顶部的选择
const handleChangeTab = (value: number) => {
// 立即更新状态
setSelectTab(value);
// 使用setTimeout确保状态更新后再触发表格重新加载
setTimeout(() => {
actionRef.current?.reload();
}, 0);
}
// 判断当前是点击看哪个的详情
const handleShowDetail = (index: number, obj: any) => {
setCurrentIndex(index)
setCurrentRow(obj)
let item: any = topListData[index]
let type: string = obj.TotalPoint ? '总积分' : obj.EarnPoint ? '赚取积分' : obj.ConsumePoint ? '消耗积分' : obj.TotalGrowth ? '总成长值' : obj.EarnGrowth ? '赚取成长值' : obj.ConsumeGrowth ? '消耗成长值' : ''
let typeTab: number = obj.TotalPoint ? 1 : obj.EarnPoint ? 2 : obj.ConsumePoint ? 3 : obj.TotalGrowth ? 4 : obj.EarnGrowth ? 5 : obj.ConsumeGrowth ? 6 : 0
console.log('typetypetype', type);
setSelectTab(typeTab)
let str: string = `${item.StatisticalName && MEMBERSHIPTYPEYNObj && MEMBERSHIPTYPEYNObj[item.StatisticalName] ? MEMBERSHIPTYPEYNObj[item.StatisticalName.toString()] : ""}${type}`
setCurrentDrawerTitle(str)
setShowDetail(true)
}
return (
<div className="MembershipTypeStatisticsMain">
{/* <Tabs
activeKey={selectBigTab}
onChange={(e: any) => {
// 立即更新状态确保UI立即响应
setSelectBigTab(e);
// 使用setTimeout确保状态更新后再触发表格重新加载
setTimeout(() => {
actionRef.current?.reload();
}, 0);
}}
items={tabList}
/> */}
{
topLoading ?
<div
style={{
width: '100%',
height: '100%',
background: 'rgba(0,0,0,0.1)',
position: 'fixed',
zIndex: 5,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '15px 20px 10px',
background: '#fff',
borderRadius: '8px',
width: '200px'
}}>
<Spin />
<span style={{ marginLeft: '5px' }}>...</span>
</div>
</div> : ''
}
<div style={{ width: '100%', boxSizing: 'border-box', padding: '0 16px' }}>
<Row style={{ marginTop: "16px" }}>
<Col span={18}>
<ProForm
layout={'horizontal'}
formRef={formRef}
submitter={false}
onFinish={async (values: any) => {
console.log('values', values);
let [StartDate, EndDate] = ['', '']
if (values.searchTime && values.searchTime.length > 0) {
[StartDate, EndDate] = values.searchTime
}
handleGetTopData(StartDate, EndDate)
setSearchParams({
StartDate: StartDate,
EndDate: EndDate
})
actionRef.current?.reload()
}}
>
<ProFormDateRangePicker
label={"查询时间"}
name={"searchTime"}
initialValue={[moment().startOf('M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]}
/>
</ProForm>
</Col>
<Col span={6}>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button style={{ marginRight: '8px' }} onClick={() => {
formRef.current?.resetFields()
}}></Button>
<Button type={"primary"} onClick={() => {
formRef.current?.submit()
}}></Button>
</div>
</Col>
</Row>
</div>
{
topListData && topListData.length > 0 ?
topListData.map((item: any, index: number) => {
return <div className="MembershipTypeStatisticsTop">
<div className="MembershipTypeStatisticsTitleBox">
<div className="MembershipTypeStatisticsTitle">{item.StatisticalName && MEMBERSHIPTYPEYNObj && MEMBERSHIPTYPEYNObj[item.StatisticalName] ? MEMBERSHIPTYPEYNObj[item.StatisticalName.toString()] : ""}</div>
</div>
<div className="MembershipTypeStatisticsContentBox">
<div className="MembershipTypeStatisticsItemOther">
<div className={'MembershipTypeStatisticsOtherItem MembershipTypeStatisticsOtherItemSelect'} onClick={() => {
handleShowDetail(index, {
TotalPoint: item?.TotalPoint
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.TotalPoint ? item?.TotalPoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.TotalPoint && item?.TotalPoint.QOQData && item?.TotalPoint.summaryData ?
<img className="addIcon" src={((item?.TotalPoint.summaryData - item?.TotalPoint.QOQData) / item?.TotalPoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.TotalPoint && item?.TotalPoint.QOQData && item?.TotalPoint.summaryData ?
// <span className="addValue">{item && item?.TotalPoint ? item?.TotalPoint.QOQData : "-"}</span>
<Tooltip title={`((${item?.TotalPoint.summaryData} - ${item?.TotalPoint.QOQData}) / ${item?.TotalPoint.QOQData}) * 100`}>
<span className="addValue">{(((item?.TotalPoint.summaryData - item?.TotalPoint.QOQData) / item?.TotalPoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: "-"
}
</div>
</div>
<div className={'MembershipTypeStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
EarnPoint: item?.EarnPoint
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.EarnPoint ? item?.EarnPoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.EarnPoint && item?.EarnPoint.QOQData && item?.EarnPoint.summaryData ?
<img className="addIcon" src={((item?.EarnPoint.summaryData - item?.EarnPoint.QOQData) / item?.EarnPoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.EarnPoint && item?.EarnPoint.QOQData && item?.EarnPoint.summaryData ?
// <span className="addValue">{item && item?.EarnPoint ? item?.EarnPoint.QOQData : "-"}</span>
<Tooltip title={`((${item?.EarnPoint.summaryData} - ${item?.EarnPoint.QOQData}) / ${item?.EarnPoint.QOQData}) * 100`}>
<span className="addValue">{(((item?.EarnPoint.summaryData - item?.EarnPoint.QOQData) / item?.EarnPoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={'MembershipTypeStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
ConsumePoint: item?.ConsumePoint
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.ConsumePoint ? item?.ConsumePoint.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.ConsumePoint && item?.ConsumePoint.QOQData && item?.ConsumePoint.summaryData ?
<img className="addIcon" src={((item?.ConsumePoint.summaryData - item?.ConsumePoint.QOQData) / item?.ConsumePoint.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.ConsumePoint && item?.ConsumePoint.QOQData && item?.ConsumePoint.summaryData ?
// <span className="addValue">{item && item?.ConsumePoint ? item?.ConsumePoint.QOQData : "-"}</span>
<Tooltip title={`((${item?.ConsumePoint.summaryData} - ${item?.ConsumePoint.QOQData}) / ${item?.ConsumePoint.QOQData}) * 100`}>
<span className="addValue">{(((item?.ConsumePoint.summaryData - item?.ConsumePoint.QOQData) / item?.ConsumePoint.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={'MembershipTypeStatisticsOtherItem MembershipTypeStatisticsOtherItemSelect'} onClick={() => {
handleShowDetail(index, {
TotalGrowth: item?.TotalGrowth
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.TotalGrowth ? item?.TotalGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.TotalGrowth && item?.TotalGrowth.QOQData && item?.TotalGrowth.summaryData ?
<img className="addIcon" src={((item?.TotalGrowth.summaryData - item?.TotalGrowth.QOQData) / item?.TotalGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.TotalGrowth && item?.TotalGrowth.QOQData && item?.TotalGrowth.summaryData ?
// <span className="addValue">{item && item?.TotalGrowth ? item?.TotalGrowth.QOQData : "-"}</span>
<Tooltip title={`((${item?.TotalGrowth.summaryData} - ${item?.TotalGrowth.QOQData}) / ${item?.TotalGrowth.QOQData}) * 100`}>
<span className="addValue">{(((item?.TotalGrowth.summaryData - item?.TotalGrowth.QOQData) / item?.TotalGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
</div>
<div className={'MembershipTypeStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
EarnGrowth: item?.EarnGrowth
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.EarnGrowth ? item?.EarnGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.EarnGrowth && item?.EarnGrowth.QOQData && item?.EarnGrowth.summaryData ?
<img className="addIcon" src={((item?.EarnGrowth.summaryData - item?.EarnGrowth.QOQData) / item?.EarnGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.EarnGrowth && item?.EarnGrowth.QOQData && item?.EarnGrowth.summaryData ?
// <span className="addValue">{item && item?.EarnGrowth ? item?.EarnGrowth.QOQData : "-"}</span>
<Tooltip title={`((${item?.EarnGrowth.summaryData} - ${item?.EarnGrowth.QOQData}) / ${topData?.EarnGrowth.QOQData}) * 100`}>
<span className="addValue">{(((item?.EarnGrowth.summaryData - item?.EarnGrowth.QOQData) / item?.EarnGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
<div className={'MembershipTypeStatisticsOtherItem'} onClick={() => {
handleShowDetail(index, {
ConsumeGrowth: item?.ConsumeGrowth
})
}}>
<div className="otherItemTitle"></div>
<div className="otherItemValue">{item && item?.ConsumeGrowth ? item?.ConsumeGrowth.summaryData : "-"}</div>
<div className="otherItemAddBox">
<span className="addLabel"></span>
{
item && item?.ConsumeGrowth && item?.ConsumeGrowth.QOQData && item?.ConsumeGrowth.summaryData ?
<img className="addIcon" src={((item?.ConsumeGrowth.summaryData - item?.ConsumeGrowth.QOQData) / item?.ConsumeGrowth.QOQData) > 0 ? addIcon : reduceIcon} /> : ""
}
{
item && item?.ConsumeGrowth && item?.ConsumeGrowth.QOQData && item?.ConsumeGrowth.summaryData ?
// <span className="addValue">{item && item?.ConsumeGrowth ? item?.ConsumeGrowth.QOQData : "-"}</span>
<Tooltip title={`((${item?.ConsumeGrowth.summaryData} - ${item?.ConsumeGrowth.QOQData}) / ${item?.ConsumeGrowth.QOQData}) * 100`}>
<span className="addValue">{(((item?.ConsumeGrowth.summaryData - item?.ConsumeGrowth.QOQData) / item?.ConsumeGrowth.QOQData) * 100).toFixed(2) + '%'}</span>
</Tooltip>
: ""
}
</div>
{/* <div className="otherBgIcon"></div> */}
</div>
</div>
</div>
</div>
}) : ""
}
<Drawer
width={'80%'}
title={currentDrawerTitle || ""}
visible={showDetail}
destroyOnClose
closable={false}
onClose={() => {
setCurrentIndex(null)
setCurrentRow(null)
setSelectTab(0)
setCurrentDrawerTitle('')
setShowDetail(false)
}}
>
<ProTable
actionRef={actionRef}
// formRef={formRef}
columns={selectTab <= 3 ? columns : growthColumns}
bordered
scroll={{ x: "100%", y: 'calc(100vh - 400px)' }}
request={async (params) => {
// 判断当前选择的 1、2、3为积分的 4、5、6 为成长值的
let req: any = {}
let data: any = {}
// 确保使用最新的状态值
const currentTabValue = topListData[currentIndex].StatisticalName;
const currentSelectTab = selectTab;
if (selectTab <= 3) {
req = {
SearchParameter: {
MEMBERSHIP_TYPE: currentTabValue || "",
// PROVINCE_CODE: currentUser?.ProvinceCode || "",
OPERATE_DATE_Start: searchParams?.StartDate || "",
OPERATE_DATE_End: searchParams?.EndDate || "",
OWNERUNIT_ID: 911,
POINT_TYPE: selectTab === 1 ? '' : selectTab === 2 ? '1' : selectTab === 3 ? '-1' : '',
POINT_SOURCE: ''
},
keyWord: {
Key: "MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
PageIndex: params?.current,
PageSize: 20,
sortstr: "OPERATE_DATE desc",
}
data = await handleGetPOINTRECORDList(req)
} else {
req = {
searchParameter: {
// PROVINCE_CODE: currentUser?.ProvinceCode || "",
OPERATE_DATE_Start: searchParams?.StartDate || "",
OPERATE_DATE_End: searchParams?.EndDate || "",
OWNERUNIT_ID: 911,
SCORESETTING_STATE: 1,
GROWTH_SOURCES: "",
GROWTH_TYPE: selectTab === 4 ? '' : selectTab === 5 ? '1' : selectTab === 6 ? '-1' : ''
},
keyWord: {
Key: "MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
PageIndex: params?.current,
PageSize: 20,
sortstr: "OPERATE_DATE desc",
}
data = await handleGetMEMBERGROWTHList(req);
}
// req = {
// SearchParameter: {
// MEMBERSHIP_TYPE: currentTabValue || "",
// // PROVINCE_CODE: currentUser?.ProvinceCode || "",
// OPERATE_DATE_Start: params?.StartDate || "",
// OPERATE_DATE_End: params?.EndDate || "",
// OWNERUNIT_ID: 911,
// POINT_TYPE: currentSelectTab === 1 ? '' : currentSelectTab === 2 ? '1' : currentSelectTab === 3 ? '-1' : '',
// POINT_SOURCE: ''
// },
// PageIndex: params?.current,
// PageSize: 20,
// sortstr: "OPERATE_DATE desc",
// }
// console.log('请求参数:', req);
// data = await handleGetPOINTRECORDList(req)
// if (searchParams.StartDate !== params?.StartDate || searchParams.EndDate !== params?.EndDate) {
// await handleGetTopData(params?.StartDate, params?.EndDate)
// }
// setSearchParams(params)
if (data.List && data.List.length > 0) {
return { data: data.List, success: true, total: data.TotalCount }
}
return { data: [], success: true }
}}
columnsState={{
value: columnsStateMap,
onChange: setColumnsStateMap,
}}
/>
</Drawer>
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(MembershipTypeStatistics);

View File

@ -12,6 +12,7 @@ import LeftSelectTree from "@/pages/reports/settlementAccount/component/leftSele
import PageTitleBox from "@/components/PageTitleBox";
import { handeGetCOMMENTList } from "../service";
import moment from 'moment'
import session from "@/utils/session";
const MerchantEvaluationManage: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -21,11 +22,22 @@ const MerchantEvaluationManage: React.FC<{ currentUser: CurrentUser }> = (props)
const [collapsible, setCollapsible] = useState<boolean>(false)
const MEMBERSHIPLEVELYNObj = session.get('MEMBERSHIPLEVELYNObj')
// 树相关的属性和方法
const [selectedId, setSelectedId] = useState<string>()
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProp: {
placeholder: "请输入评价人员/商家名称"
}
},
{
title: '评价时间',
dataIndex: 'search_date',
@ -84,6 +96,8 @@ const MerchantEvaluationManage: React.FC<{ currentUser: CurrentUser }> = (props)
hideInSearch: true,
ellipsis: true,
align: "center",
valueType: "select",
valueEnum: MEMBERSHIPLEVELYNObj
},
{
title: "消费评价",
@ -157,6 +171,10 @@ const MerchantEvaluationManage: React.FC<{ currentUser: CurrentUser }> = (props)
},
PageIndex: 1,
PageSize: 999999,
keyWord: {
Key: "SELLER_NAME,MEMBERSHIP_NAME",
Value: params?.searchText || ""
},
}
const data = await handeGetCOMMENTList(req)
console.log('datadatadatadatadata', data);

View File

@ -46,6 +46,14 @@ const OrderAfterSalesManage: React.FC<{ currentUser: CurrentUser }> = (props) =>
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProp: {
placeholder: "请输入购买的商品/订单编号/联系电话/会员名称"
}
},
{
title: '查询时间',
dataIndex: 'search_date',
@ -272,6 +280,11 @@ const OrderAfterSalesManage: React.FC<{ currentUser: CurrentUser }> = (props) =>
PageIndex: 1,
PageSize: 999999,
SortStr: "ORDER_DATE desc",
keyWord: {
Key: "ORDER_PERSON,ORDER_PERSONTEL,SALEBILL_CODE,COMMODITY_NAME",
Value: params?.searchText || ""
},
}
console.log('reqreqreqreqreq', req);

View File

@ -101,23 +101,31 @@ const OrderProductManage: React.FC<{ currentUser: CurrentUser | undefined }> = (
};
// 定义列表字段内容
const columns: any = [
{
title: '查询时间',
dataIndex: 'search_date',
valueType: 'dateRange',
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
hideInDescriptions: true,
search: {
transform: (value) => {
return {
OPERATE_DATE_Start: value[0],
OPERATE_DATE_End: value[1],
};
},
},
// initialValue: [moment().format('YYYY-MM-DD'), moment().subtract(1, 'M').format('YYYY-MM-DD')],
fieldProp: {
placeholder: "请输入商品名称"
}
},
// {
// title: '查询时间',
// dataIndex: 'search_date',
// valueType: 'dateRange',
// hideInTable: true,
// hideInDescriptions: true,
// search: {
// transform: (value) => {
// return {
// OPERATE_DATE_Start: value[0],
// OPERATE_DATE_End: value[1],
// };
// },
// },
// // initialValue: [moment().format('YYYY-MM-DD'), moment().subtract(1, 'M').format('YYYY-MM-DD')],
// },
// {
// title: '上级类别',
// align: 'center',
@ -432,7 +440,7 @@ const OrderProductManage: React.FC<{ currentUser: CurrentUser | undefined }> = (
<ProTable
scroll={{ x: "100%", y: 'calc(100vh - 410px)' }}
rowKey={(record) => {
return `${record?.USERDEFINEDTYPE_PID}-${record?.USERDEFINEDTYPE_ID}`
return `${record?.COMMODITY_ID}-${record?.OPERATE_DATE}`
}}
formRef={formRef}
headerTitle={<PageTitleBox props={props} />} // 列表表头
@ -457,12 +465,17 @@ const OrderProductManage: React.FC<{ currentUser: CurrentUser | undefined }> = (
SELLER_IDS: selectedId || "",
UPPER_STATE: params?.UPPER_STATE === "-1" ? "" : params?.UPPER_STATE,
OPERATE_DATE_Start: params?.OPERATE_DATE_Start || "",
OPERATE_DATE_End: params?.OPERATE_DATE_End || "",
// OPERATE_DATE_Start: params?.OPERATE_DATE_Start || "",
// OPERATE_DATE_End: params?.OPERATE_DATE_End || "",
},
PageIndex: 1,
PageSize: 999999,
SortStr: "OPERATE_DATE desc"
SortStr: "OPERATE_DATE desc",
keyWord: {
Key: "COMMODITY_NAME",
Value: params?.searchText || ""
},
}
console.log('reqreqreqreq', req);

View File

@ -28,6 +28,7 @@ import classNames from 'classnames';
import session from '@/utils/session';
import { handeDeleteFIELDENUM, handeGetFIELDEXPLAINList, handeGetNestingFIELDENUMList, handeSynchroFIELDENUM } from '../service';
import ModalFooter from '../scenicSpotConfig/component/modalFooter';
import { convertTreeToLabelValue } from '@/utils/format';
const beforeUpload = (file: any) => {
@ -267,8 +268,22 @@ const PointConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (props)
SearchKey: ""
}
const data = await handeGetNestingFIELDENUMList(req);
console.log('datadatadata', data);
if (data && data.length > 0) {
setTypeTreeData(data)
if (data && data.length > 0) {
const obj: any = {}
const list: any = []
data.forEach((item: any) => {
list.push({ label: item.label, value: item.value })
obj[item.value] = item.label
})
session.set('SCORETYPEList', list);
session.set('SCORETYPEObj', obj);
session.set('SCORETYPETree', convertTreeToLabelValue(data, "FIELDENUM_NAME", "FIELDENUM_VALUE"))
}
return { data: data, success: true, total: data.length }
}
return { data: [], success: true }

View File

@ -79,6 +79,7 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
hideInSearch: true,
valueType: 'treeSelect',
request: () => {
let SCORETYPETree = session.get('SCORETYPETree')
return SCORETYPETree
}
// valueEnum: SCORETYPEObj
@ -103,7 +104,6 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
title: '会员等级',
width: 120,
align: 'center',
hideInSearch: true,
valueType: 'select',
valueEnum: MEMBERSHIPLEVELYNObj
},
@ -112,7 +112,6 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
title: '会员类型',
width: 120,
align: 'center',
hideInSearch: true,
valueType: 'select',
valueEnum: MEMBERSHIPTYPEYNObj
},
@ -206,13 +205,13 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
initialValue: "1"
},
{
dataIndex: 'ADDTIME',
title: '添加时间',
dataIndex: 'OPERATE_DATE',
title: '操作时间',
width: 150,
align: 'center',
hideInSearch: true,
render: (_, record) => {
return record?.ADDTIME ? moment(record?.ADDTIME).format('YYYY-MM-DD HH:mm:ss') : ""
return record?.OPERATE_DATE ? moment(record?.OPERATE_DATE).format('YYYY-MM-DD HH:mm:ss') : ""
}
},
// {
@ -340,15 +339,17 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
search={{ span: 6, labelWidth: 'auto' }}
// 请求数据
request={async (params, sorter) => {
const searchWholeParams = {
searchParameter: {
PROVINCE_CODE: currentUser?.ProvinceCode || "",
OWNERUNIT_ID: 911,
SCORESETTING_STATE: params?.SCORESETTING_STATE
SCORESETTING_STATE: params?.SCORESETTING_STATE,
MEMBERSHIP_TYPE: params?.MEMBERSHIP_TYPE || "",
MEMBERSHIP_LEVEL: params?.MEMBERSHIP_LEVEL || "",
},
PageIndex: 1,
PageSize: 20
PageSize: 999999,
SortStr: "OPERATE_DATE desc"
}
setSearchParams(searchWholeParams)
const data = await handleGetSCORESETTINGList(searchWholeParams);
@ -382,7 +383,7 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
</Button>
],
}}
pagination={{ defaultPageSize: 10 }}
// pagination={{ defaultPageSize: 10 }}
/>
<Modal
@ -489,6 +490,7 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
name="SCORE_TYPE"
label="积分类别"
request={async () => {
let SCORETYPETree = session.get('SCORETYPETree')
return SCORETYPETree
}}
fieldProps={{
@ -620,7 +622,7 @@ const PointsRuleConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
>
<PointConfig />
</Modal>
</PageContainer>
</PageContainer >
);
};
export default connect(({ user }: ConnectState) => ({

View File

@ -78,25 +78,24 @@ const RegistrationRetentionAnalysis: React.FC<{ currentUser: CurrentUser }> = (p
hideInSearch: true,
ellipsis: true,
dataIndex: 'BEHAVIORRECORD_ROUTNAME',
render: (_, record) => {
// return record?.BEHAVIORRECORD_ROUTNAME ? <a onClick={() => {
// console.log('record', record);
// const req: any = {
// key: record.BEHAVIORRECORD_ROUT,
// path: record.BEHAVIORRECORD_ROUT,
// title: record.BEHAVIORRECORD_ROUTNAME,
// children: children
// }
// console.log('req', req);
// handleTabsPanes(req)
// }}>
// {record?.BEHAVIORRECORD_ROUTNAME || ""}
// </a> : "-"
return record?.BEHAVIORRECORD_ROUTNAME ? <Link to={record.BEHAVIORRECORD_ROUT}>
{record?.BEHAVIORRECORD_ROUTNAME}
</Link> : ""
}
// render: (_, record) => {
// return record?.BEHAVIORRECORD_ROUTNAME ? <a onClick={() => {
// console.log('record', record);
// const req: any = {
// key: record.BEHAVIORRECORD_ROUT,
// path: record.BEHAVIORRECORD_ROUT,
// title: record.BEHAVIORRECORD_ROUTNAME,
// children: children
// }
// console.log('req', req);
// handleTabsPanes(req)
// }}>
// {record?.BEHAVIORRECORD_ROUTNAME || ""}
// </a> : "-"
// return record?.BEHAVIORRECORD_ROUTNAME ? <Link to={record.BEHAVIORRECORD_ROUT}>
// {record?.BEHAVIORRECORD_ROUTNAME}
// </Link> : ""
// }
},
{
title: '操作类型',
@ -138,17 +137,17 @@ const RegistrationRetentionAnalysis: React.FC<{ currentUser: CurrentUser }> = (p
width: 160,
ellipsis: true,
},
{
title: '响应时间(s)',
hideInSearch: true,
dataIndex: 'BEHAVIORRECORD_DURATION',
width: 120,
align: 'center',
sorter: (a, b) => a.BEHAVIORRECORD_DURATION - b.BEHAVIORRECORD_DURATION,
render: (_, record) => {
return `${record?.BEHAVIORRECORD_DURATION ? record?.BEHAVIORRECORD_DURATION : ""}`
}
},
// {
// title: '响应时间(s)',
// hideInSearch: true,
// dataIndex: 'BEHAVIORRECORD_DURATION',
// width: 120,
// align: 'center',
// sorter: (a, b) => a.BEHAVIORRECORD_DURATION - b.BEHAVIORRECORD_DURATION,
// render: (_, record) => {
// return `${record?.BEHAVIORRECORD_DURATION ? record?.BEHAVIORRECORD_DURATION : ""}`
// }
// },
{
title: '操作内容',
hideInSearch: true,

View File

@ -122,6 +122,14 @@ const ShoppingMallProductSearch: React.FC<{ currentUser: CurrentUser | undefined
// 定义列表字段内容
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProp: {
placeholder: "请输入品牌名称/商品名称"
}
},
{
dataIndex: 'index',
title: '序号',
@ -644,6 +652,10 @@ const ShoppingMallProductSearch: React.FC<{ currentUser: CurrentUser | undefined
COMMODITY_TYPE: 4000,
COMMODITY_STATE: 1,
},
keyWord: {
Key: "BRAND_NAME,COMMODITY_NAME",
Value: params?.searchText || ""
},
PageIndex: 1,
PageSize: 999999,
}

View File

@ -325,6 +325,7 @@ const SupplierMerchantManage: React.FC<{ currentUser: CurrentUser | undefined }>
<Modal
title={
<div
className="SupplierMerchantManageModalTitle"
style={{
width: '100%',
cursor: 'move',
@ -388,6 +389,7 @@ const SupplierMerchantManage: React.FC<{ currentUser: CurrentUser | undefined }>
disabled={disabled}
bounds={bounds}
onStart={(event, uiData) => onDraggaleStart(event, uiData)}
handle=".SupplierMerchantManageModalTitle"
>
<div ref={draggleRef}>{modal}</div>
</Draggable>
@ -486,7 +488,7 @@ const SupplierMerchantManage: React.FC<{ currentUser: CurrentUser | undefined }>
<Col span={8}>
<ProFormText
name="TAXPAYER_IDENTIFYCODE"
label="统一信用代码"
label="信用代码"
rules={[
{
required: true,

View File

@ -662,6 +662,8 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
headerTitle={<PageTitleBox props={props} />}
search={{ span: 6 }}
request={async (params, sorter) => {
console.log('paramsparamsparams', params);
const sortstr = Object.keys(sorter).map(n => {
const value = sorter[n]
return value ? `${n} ${value.replace('end', '')}` : ''
@ -679,7 +681,7 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
value: params?.MEMBERSHIP_NAME || ""
},
PageIndex: params.current || 1,
PageSize: 20,
PageSize: params?.pageSize,
sortstr: sortstr.length ? sortstr.toString() : "",
}
setSearchParams(params)
@ -1008,7 +1010,7 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
OWNERUNIT_ID: 911
},
PageIndex: params.current,
PageSize: 20,
PageSize: params?.pageSize,
SortStr: "CONSUMPTIONRECORD_DATE desc"
}
const data = await handleGetCONSUMPTIONRECORDList(req)
@ -1017,6 +1019,10 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
}
return { data: [], success: true }
}}
pagination={{
defaultPageSize: 20,
showTotal: (total) => `${total} 条记录`
}}
/> : ""
}
@ -1037,7 +1043,7 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
OWNERUNIT_ID: 911
},
PageIndex: params.current,
PageSize: 20,
PageSize: params?.pageSize,
SortStr: "OPERATE_DATE desc"
}
const data = await handleGetPOINTRECORDList(req)
@ -1047,6 +1053,10 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
}
return { data: [], success: true }
}}
pagination={{
defaultPageSize: 20,
showTotal: (total) => `${total} 条记录`
}}
/>
: ""
}
@ -1068,7 +1078,7 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
OWNERUNIT_ID: 911
},
PageIndex: params.current,
PageSize: 20,
PageSize: params?.pageSize,
SortStr: "OPERATE_DATE desc"
}
const data = await handleGetMEMBERGROWTHList(req)
@ -1078,6 +1088,10 @@ const memberInfor: React.FC<{ currentUser: CurrentUser }> = (props) => {
}
return { data: [], success: true }
}}
pagination={{
defaultPageSize: 20,
showTotal: (total) => `${total} 条记录`
}}
/>
: ''
}

View File

@ -85,6 +85,14 @@ const scenicSpotConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
// 定义列表字段内容
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldprop: {
placeholder: '请输入景区名称/景区位置'
}
},
{
dataIndex: 'SCENICAREA_NAME',
title: '景区名称',
@ -379,6 +387,10 @@ const scenicSpotConfig: React.FC<{ currentUser: CurrentUser | undefined }> = (pr
SCENICAREA_TYPES: params?.SCENICAREA_TYPE,
SCENICAREA_STATES: params?.SCENICAREA_STATE,
},
keyWord: {
Key: "SCENICAREA_NAME,SCENICAREA_LOCATION",
Value: params?.searchText || ""
},
PageIndex: 1,
PageSize: 999999,
}

View File

@ -724,4 +724,103 @@ export async function handeGetSupplierSaleBillList(params: any) {
return []
}
return data.Result_Data.List
}
}
// 拿到埋点的配置数据
export async function handeGetWECHATAPPBURYPOINTList(params: any) {
const data = await requestEncryption(`/WeChat/GetWECHATAPPBURYPOINTList`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return []
}
return data.Result_Data
}
// 同步小程序埋点配置
export async function handeSynchroWECHATAPPBURYPOINT(params: any) {
const data = await requestEncryption(`/WeChat/SynchroWECHATAPPBURYPOINT`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data
}
// 删除小程序埋点配置
export async function handeDeleteWECHATAPPBURYPOINT(params: any) {
const data = await requestEncryption(`/WeChat/DeleteWECHATAPPBURYPOINT`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data
}
// 拿到所有小程序的列表
export async function handeGetWECHATAPPSIGNList(params: any) {
const data = await requestEncryption(`/WeChat/GetWECHATAPPSIGNList`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data.Result_Data.List
}
// 获取自定义类别表嵌套列表
export async function handeGetNestingAUTOTYPEList(params: any) {
const data = await requestEncryption(`/Member/GetNestingAUTOTYPEList`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return wrapTreeNode(data.Result_Data.List)
}
// 同步自定义列表
export async function handeSynchroAUTOTYPE(params: any) {
const data = await requestEncryption(`/Member/SynchroAUTOTYPE`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data
}
// 删除自定义类别表
export async function handeDeleteAUTOTYPE(params: any) {
const data = await requestEncryption(`/Member/DeleteAUTOTYPE`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data
}
// 新增三个统计报表页面
export async function handeGetPointGrowthSummary(params: any) {
const data = await requestEncryption(`/Member/GetPointGrowthSummary`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data.Result_Data.List
}

View File

@ -531,4 +531,23 @@ export const handleSetlogSave = async (str: string) => {
BROWSER_VERSION: browserVersion,
OPERATING_SYSTEM: systemBasin
})
}
export function convertTreeToLabelValue<T>(
tree: T[],
labelKey: keyof T,
valueKey: keyof T,
childrenKey: keyof T = 'children' as keyof T
): any[] {
return tree.map((item: any) => {
const node: any = {
label: item[labelKey],
value: item[valueKey]
};
if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {
node.children = convertTreeToLabelValue(item[childrenKey], labelKey, valueKey, childrenKey);
}
return node;
});
}