💥 feat(模块): 赠送会员

This commit is contained in:
chashaobao
2025-12-30 00:40:25 +08:00
parent 447934d5ff
commit 31cb15235a
5 changed files with 263 additions and 0 deletions

View File

@ -37,4 +37,9 @@ export enum AdminAPI {
CITY_OPERATOR_LIST = '/api/cityOperator/getStaffPageList',
CITY_OPERATOR_UPDATE = '/api/cityOperator/addOrEdit',
CITY_OPERATOR_DELETE = '/api/cityOperator/{id}',
// 赠送会员
GIVE_VIP_LIST = '/api/bo/giveVip/pageList',
GIVE_VIP = '/api/bo/giveVip/give',
// 产品列表
PRODUCT_LIST = '/api/bo/product/listByType/{productType}',
}

View File

@ -0,0 +1,189 @@
import { PlusOutlined } from '@ant-design/icons';
import {
ActionType,
ProColumns,
ProFormInstance,
ProFormText,
ProFormDigit,
ProFormRadio,
ProFormDependency,
} from '@ant-design/pro-components';
import { ModalForm, PageContainer, ProTable } from '@ant-design/pro-components';
import '@umijs/max';
import { Button } from 'antd';
import dayjs from 'dayjs';
import React, { useEffect, useRef, useState } from 'react';
import { TIME_FORMAT } from '@/constants/global';
import { postGiveVip, getGiveVipList, getProductList } from '@/services/list';
const ProductTypeText: Record<API.ProductType, string> = {
VIP: '主播',
BOSSVIP: 'BOSSVIP',
GROUP_BATCH_PUSH: 'GROUP_BATCH_PUSH',
BOSS_VIP_NEW: '企业',
};
const TableList: React.FC = () => {
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [productVipList, setProductVipList] = useState<API.ProductSpecListItem[]>([]);
const [productBossVipList, setProductBossVipList] = useState<API.ProductSpecListItem[]>([]);
const actionRef = useRef<ActionType>();
const formRef = useRef<ProFormInstance>();
const getProducts = async () => {
try {
const [vipList, bossVipList] = await Promise.all([getProductList('VIP'), getProductList('BOSS_VIP_NEW')]);
setProductVipList(vipList);
setProductBossVipList(bossVipList);
} catch (e) {
} finally {
}
};
useEffect(() => {
getProducts();
}, []);
const columns: ProColumns<API.GiveVipListItem>[] = [
{
title: '用户ID',
dataIndex: 'imOpenId',
valueType: 'textarea',
search: true,
},
{
title: '用户手机号',
dataIndex: 'userPhone',
valueType: 'textarea',
search: true,
},
{
title: '类型',
dataIndex: 'productType',
valueType: 'textarea',
search: false,
renderText: productType => ProductTypeText[productType as API.ProductType],
},
{
title: '会员',
dataIndex: 'productSpecId',
valueType: 'textarea',
search: false,
renderText: (productSpecId: string, record: API.GiveVipListItem) => {
let product;
if (record.productType === 'VIP') {
product = productVipList.find(it => it.productSpecId === productSpecId);
}
if (record.productType === 'BOSS_VIP_NEW') {
product = productBossVipList.find(it => it.productSpecId === productSpecId);
}
return product ? product.productName : productSpecId || '-';
},
},
{
title: '赠送个数',
dataIndex: 'giveCount',
valueType: 'textarea',
search: false,
},
{
title: '赠送时间',
dataIndex: 'createTime',
valueType: 'dateTime',
renderText(created: string) {
return dayjs(created).format(TIME_FORMAT);
},
search: false,
},
];
return (
<PageContainer>
<ProTable<API.GiveVipListItem, API.PageParams>
headerTitle="查询表格"
actionRef={actionRef}
rowKey="key"
search={{ labelWidth: 120, collapsed: false, collapseRender: false }}
request={getGiveVipList}
columns={columns}
toolBarRender={() => [
<Button
type="primary"
key="add"
icon={<PlusOutlined />}
onClick={() => {
handleUpdateModalOpen(true);
formRef.current?.resetFields();
}}
>
</Button>,
]}
/>
<ModalForm
title="新增赠送"
width="400px"
formRef={formRef}
open={updateModalOpen}
initialValues={{ giveCount: 1, productType: 'VIP' }}
onOpenChange={handleUpdateModalOpen}
onFinish={async formData => {
const params: API.PostGiveVip = {
imOpenId: formData.imOpenId,
userPhone: formData.userPhone,
productType: formData.productType,
productSpecId: formData.productSpecId,
giveCount: formData.giveCount,
};
console.log('update confirm', formData, params);
try {
await postGiveVip(params);
actionRef.current?.reload();
formRef.current?.resetFields();
} catch (e) {}
handleUpdateModalOpen(false);
}}
>
<ProFormText name="imOpenId" label="用户ID" rules={[{ message: '请输入用户ID', required: true }]} />
<ProFormRadio.Group
label="选择类型"
name="productType"
fieldProps={{
onChange: () => {
formRef.current?.setFieldsValue({
productSpecId: undefined,
});
},
}}
options={[
{
value: 'VIP',
label: ProductTypeText.VIP,
},
{
value: 'BOSS_VIP_NEW',
label: ProductTypeText.BOSS_VIP_NEW,
},
]}
/>
<ProFormDependency name={['productType']}>
{({ productType }) => {
return (
<ProFormRadio.Group
name="productSpecId"
label="选择会员"
options={(productType === 'VIP' ? productVipList : productBossVipList).map(it => ({
value: it.productSpecId,
label: it.productName,
}))}
rules={[{ required: true, message: '必填项' }]}
/>
);
}}
</ProFormDependency>
<ProFormDigit name="giveCount" label="赠送会员个数" min={1} fieldProps={{ precision: 0 }} />
</ModalForm>
</PageContainer>
);
};
export default TableList;

View File

@ -298,3 +298,32 @@ export async function deleteCityOperator(id: number) {
method: 'DELETE',
});
}
export async function getGiveVipList(
params: API.PageParams & Partial<API.GiveVipListItem>,
options?: { [key: string]: any },
) {
const result = await request<API.TableList<API.GiveVipListItem>>(AdminAPI.GIVE_VIP_LIST, {
method: 'POST',
data: {
...transformPageParams(params),
...(options || {}),
},
});
return result;
}
export async function postGiveVip(options: API.PostGiveVip) {
return request<API.GiveVipListItem>(AdminAPI.GIVE_VIP, {
method: 'POST',
data: {
...(options || {}),
},
});
}
export async function getProductList(productType: API.ProductType) {
return request<API.ProductSpecListItem[]>(buildUrl(AdminAPI.PRODUCT_LIST, { productType }), {
method: 'GET',
});
}

View File

@ -380,4 +380,43 @@ declare namespace API {
created?: string;
updated?: string;
}
type ProductType = 'VIP' | 'BOSSVIP' | 'BOSS_VIP_NEW' | 'GROUP_BATCH_PUSH';
interface GiveVipListItem {
id: number;
imOpenId: string;
userPhone: string;
productType: ProductType;
productSpecId: string;
giveCount: number;
operator: string;
createTime: string;
updateTime: string;
}
interface PostGiveVip {
imOpenId: string;
userPhone?: string;
productType?: ProductType;
productSpecId?: string;
giveCount?: number;
}
interface ProductSpecListItem {
productId: string;
productSpecId: string;
productType: ProductType;
productName: string;
title: string;
priceText: string;
payPrice: number;
showPrice: number;
originalPrice: number;
badge: string;
contentSingle: string;
contentsJson: string;
sort: number;
createTime: string;
}
}