From 31cb15235ab4a4f550c90bb459303d34b6cc07bd Mon Sep 17 00:00:00 2001 From: chashaobao Date: Tue, 30 Dec 2025 00:40:25 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20feat(=E6=A8=A1=E5=9D=97):=20?= =?UTF-8?q?=E8=B5=A0=E9=80=81=E4=BC=9A=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/routes.ts | 1 + src/constants/api.ts | 5 + src/pages/table-list/give-vip/index.tsx | 189 ++++++++++++++++++++++++ src/services/list.ts | 29 ++++ src/services/typings.d.ts | 39 +++++ 5 files changed, 263 insertions(+) create mode 100644 src/pages/table-list/give-vip/index.tsx diff --git a/config/routes.ts b/config/routes.ts index 8989cfa..6b53e2f 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -13,6 +13,7 @@ export default [ { 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/city-operation', component: './table-list/city-operation' }, + { name: '赠送会员', icon: 'table', path: '/list/give-vip', component: './table-list/give-vip' }, { path: '/', redirect: '/list/job' }, { path: '*', layout: false, component: './404' }, ]; diff --git a/src/constants/api.ts b/src/constants/api.ts index 19c539d..8b9d2ba 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -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}', } diff --git a/src/pages/table-list/give-vip/index.tsx b/src/pages/table-list/give-vip/index.tsx new file mode 100644 index 0000000..ee79931 --- /dev/null +++ b/src/pages/table-list/give-vip/index.tsx @@ -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 = { + VIP: '主播', + BOSSVIP: 'BOSSVIP', + GROUP_BATCH_PUSH: 'GROUP_BATCH_PUSH', + BOSS_VIP_NEW: '企业', +}; + +const TableList: React.FC = () => { + const [updateModalOpen, handleUpdateModalOpen] = useState(false); + const [productVipList, setProductVipList] = useState([]); + const [productBossVipList, setProductBossVipList] = useState([]); + const actionRef = useRef(); + const formRef = useRef(); + + 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[] = [ + { + 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 ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="key" + search={{ labelWidth: 120, collapsed: false, collapseRender: false }} + request={getGiveVipList} + columns={columns} + toolBarRender={() => [ + , + ]} + /> + { + 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); + }} + > + + { + formRef.current?.setFieldsValue({ + productSpecId: undefined, + }); + }, + }} + options={[ + { + value: 'VIP', + label: ProductTypeText.VIP, + }, + { + value: 'BOSS_VIP_NEW', + label: ProductTypeText.BOSS_VIP_NEW, + }, + ]} + /> + + {({ productType }) => { + return ( + ({ + value: it.productSpecId, + label: it.productName, + }))} + rules={[{ required: true, message: '必填项' }]} + /> + ); + }} + + + + + ); +}; +export default TableList; diff --git a/src/services/list.ts b/src/services/list.ts index 8bbc876..1c5a4a2 100644 --- a/src/services/list.ts +++ b/src/services/list.ts @@ -298,3 +298,32 @@ export async function deleteCityOperator(id: number) { method: 'DELETE', }); } + +export async function getGiveVipList( + params: API.PageParams & Partial, + options?: { [key: string]: any }, +) { + const result = await request>(AdminAPI.GIVE_VIP_LIST, { + method: 'POST', + data: { + ...transformPageParams(params), + ...(options || {}), + }, + }); + return result; +} + +export async function postGiveVip(options: API.PostGiveVip) { + return request(AdminAPI.GIVE_VIP, { + method: 'POST', + data: { + ...(options || {}), + }, + }); +} + +export async function getProductList(productType: API.ProductType) { + return request(buildUrl(AdminAPI.PRODUCT_LIST, { productType }), { + method: 'GET', + }); +} diff --git a/src/services/typings.d.ts b/src/services/typings.d.ts index cba34b9..db44701 100644 --- a/src/services/typings.d.ts +++ b/src/services/typings.d.ts @@ -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; + } }