💥 feat(模块): 赠送会员
This commit is contained in:
@ -13,6 +13,7 @@ export default [
|
|||||||
{ name: '模卡管理', icon: 'table', path: '/list/resume', component: './table-list/material' },
|
{ name: '模卡管理', icon: 'table', path: '/list/resume', component: './table-list/material' },
|
||||||
{ name: '运营二维码管理', icon: 'table', path: '/list/staff-qrcode', component: './table-list/staff-qrcode' },
|
{ name: '运营二维码管理', icon: 'table', path: '/list/staff-qrcode', component: './table-list/staff-qrcode' },
|
||||||
{ name: '城市运营管理', icon: 'table', path: '/list/city-operation', component: './table-list/city-operation' },
|
{ name: '城市运营管理', icon: 'table', path: '/list/city-operation', component: './table-list/city-operation' },
|
||||||
|
{ name: '赠送会员', icon: 'table', path: '/list/give-vip', component: './table-list/give-vip' },
|
||||||
{ path: '/', redirect: '/list/job' },
|
{ path: '/', redirect: '/list/job' },
|
||||||
{ path: '*', layout: false, component: './404' },
|
{ path: '*', layout: false, component: './404' },
|
||||||
];
|
];
|
||||||
|
|||||||
@ -37,4 +37,9 @@ export enum AdminAPI {
|
|||||||
CITY_OPERATOR_LIST = '/api/cityOperator/getStaffPageList',
|
CITY_OPERATOR_LIST = '/api/cityOperator/getStaffPageList',
|
||||||
CITY_OPERATOR_UPDATE = '/api/cityOperator/addOrEdit',
|
CITY_OPERATOR_UPDATE = '/api/cityOperator/addOrEdit',
|
||||||
CITY_OPERATOR_DELETE = '/api/cityOperator/{id}',
|
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}',
|
||||||
}
|
}
|
||||||
|
|||||||
189
src/pages/table-list/give-vip/index.tsx
Normal file
189
src/pages/table-list/give-vip/index.tsx
Normal 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;
|
||||||
@ -298,3 +298,32 @@ export async function deleteCityOperator(id: number) {
|
|||||||
method: 'DELETE',
|
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',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
39
src/services/typings.d.ts
vendored
39
src/services/typings.d.ts
vendored
@ -380,4 +380,43 @@ declare namespace API {
|
|||||||
created?: string;
|
created?: string;
|
||||||
updated?: 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user