Commit 379c80fadb924ce41c583bd302fba4012a0cbbd8

Authored by boyang
1 parent e7087f45

feat: 用户查询三种方式弹窗

src/pages/Prepaid/components/PointsExchangeRecordsModal.tsx 0 → 100644
  1 +import { postIntegralUserExchangeRecords } from '@/services';
  2 +import { formatDateTime } from '@/utils';
  3 +import { Empty, Modal, Table, Tabs } from 'antd';
  4 +import React, { useEffect, useState } from 'react';
  5 +import '../index.less';
  6 +
  7 +interface PointsExchangeRecordsModalProps {
  8 + setVisible: (visible: boolean) => void;
  9 + userInfoObj: {
  10 + uid: string;
  11 + phone?: string;
  12 + nickname?: string;
  13 + realName?: string;
  14 + [key: string]: any;
  15 + };
  16 + onClose: () => void;
  17 +}
  18 +
  19 +interface RecordItem {
  20 + createByName: string | null;
  21 + createTime: string;
  22 + delta: number;
  23 + remark: string | null;
  24 + sourceId: string | null;
  25 +}
  26 +
  27 +interface RecordsData {
  28 + exchangeRecords: RecordItem[];
  29 + collectedRecords: RecordItem[];
  30 + pendingRecords: RecordItem[];
  31 +}
  32 +
  33 +const PointsExchangeRecordsModal: React.FC<PointsExchangeRecordsModalProps> = ({
  34 + setVisible,
  35 + userInfoObj,
  36 + onClose,
  37 +}) => {
  38 + const [activeTab, setActiveTab] = useState<string>('1');
  39 + const [loading, setLoading] = useState<boolean>(false);
  40 + const [recordsData, setRecordsData] = useState<RecordsData>({
  41 + exchangeRecords: [],
  42 + collectedRecords: [],
  43 + pendingRecords: [],
  44 + });
  45 +
  46 + const uid = userInfoObj?.uid;
  47 + const phone = userInfoObj?.phone;
  48 +
  49 + // Function to fetch records data from API
  50 + const fetchRecordsData = async () => {
  51 + try {
  52 + setLoading(true);
  53 + const response = await postIntegralUserExchangeRecords({
  54 + data: {
  55 + id: Number(uid),
  56 + phone: phone,
  57 + },
  58 + });
  59 +
  60 + if (response && response.data) {
  61 + setRecordsData({
  62 + exchangeRecords: response.data.exchangeRecords || [],
  63 + collectedRecords: response.data.collectedRecords || [],
  64 + pendingRecords: response.data.pendingRecords || [],
  65 + });
  66 + }
  67 + } catch (error) {
  68 + console.error('Failed to fetch exchange records:', error);
  69 + } finally {
  70 + setLoading(false);
  71 + }
  72 + };
  73 +
  74 + // Fetch records data when component mounts
  75 + useEffect(() => {
  76 + if (uid || phone) {
  77 + fetchRecordsData();
  78 + }
  79 + }, [uid, phone]);
  80 + // Exchange records columns
  81 + const exchangeRecordsColumns = [
  82 + {
  83 + title: '兑换日期',
  84 + dataIndex: 'createTime',
  85 + key: 'createTime',
  86 + render: (text: string) => formatDateTime(text),
  87 + },
  88 + {
  89 + title: '扣除积分',
  90 + dataIndex: 'delta',
  91 + key: 'delta',
  92 + render: (delta: number) => (
  93 + <span style={{ color: delta < 0 ? 'red' : 'green' }}>{delta}</span>
  94 + ),
  95 + },
  96 + {
  97 + title: '操作人',
  98 + dataIndex: 'createByName',
  99 + key: 'createByName',
  100 + render: (text: string | null) => text || '-',
  101 + },
  102 + {
  103 + title: '积分用途',
  104 + dataIndex: 'remark',
  105 + key: 'remark',
  106 + render: (text: string | null) => text || '-',
  107 + },
  108 + ];
  109 +
  110 + // Collected records columns
  111 + const collectedRecordsColumns = [
  112 + {
  113 + title: '订单号',
  114 + dataIndex: 'sourceId',
  115 + key: 'sourceId',
  116 + render: (text: string | null) => text || '-',
  117 + },
  118 + {
  119 + title: '领取积分',
  120 + dataIndex: 'delta',
  121 + key: 'delta',
  122 + render: (delta: number) => (
  123 + <span style={{ color: delta > 0 ? 'green' : 'red' }}>{delta}</span>
  124 + ),
  125 + },
  126 + {
  127 + title: '领取日期',
  128 + dataIndex: 'createTime',
  129 + key: 'createTime',
  130 + render: (text: string) => formatDateTime(text),
  131 + },
  132 + ];
  133 +
  134 + // Pending records columns
  135 + const pendingRecordsColumns = [
  136 + {
  137 + title: '订单号',
  138 + dataIndex: 'sourceId',
  139 + key: 'sourceId',
  140 + render: (text: string | null) => text || '-',
  141 + },
  142 + {
  143 + title: '领取积分',
  144 + dataIndex: 'delta',
  145 + key: 'delta',
  146 + render: (delta: number) => (
  147 + <span style={{ color: delta > 0 ? 'green' : 'red' }}>{delta}</span>
  148 + ),
  149 + },
  150 + {
  151 + title: '过期日期',
  152 + dataIndex: 'createTime',
  153 + key: 'createTime',
  154 + render: (text: string) => formatDateTime(text),
  155 + },
  156 + ];
  157 +
  158 + // Tab items
  159 + const tabItems = [
  160 + {
  161 + key: '1',
  162 + label: '兑换记录',
  163 + children: (
  164 + <Table
  165 + columns={exchangeRecordsColumns}
  166 + dataSource={recordsData.exchangeRecords.map((item, index) => ({
  167 + ...item,
  168 + key: `exchange-${index}`,
  169 + }))}
  170 + pagination={{ pageSize: 5 }}
  171 + loading={loading && activeTab === '1'}
  172 + locale={{
  173 + emptyText: <Empty description="暂无兑换记录" />,
  174 + }}
  175 + />
  176 + ),
  177 + },
  178 + {
  179 + key: '2',
  180 + label: '已领取积分',
  181 + children: (
  182 + <Table
  183 + columns={collectedRecordsColumns}
  184 + dataSource={recordsData.collectedRecords.map((item, index) => ({
  185 + ...item,
  186 + key: `collected-${index}`,
  187 + }))}
  188 + pagination={{ pageSize: 5 }}
  189 + loading={loading && activeTab === '2'}
  190 + locale={{
  191 + emptyText: <Empty description="暂无已领取积分记录" />,
  192 + }}
  193 + />
  194 + ),
  195 + },
  196 + {
  197 + key: '3',
  198 + label: '待领取积分',
  199 + children: (
  200 + <Table
  201 + columns={pendingRecordsColumns}
  202 + dataSource={recordsData.pendingRecords.map((item, index) => ({
  203 + ...item,
  204 + key: `pending-${index}`,
  205 + }))}
  206 + pagination={{ pageSize: 5 }}
  207 + loading={loading && activeTab === '3'}
  208 + locale={{
  209 + emptyText: <Empty description="暂无待领取积分记录" />,
  210 + }}
  211 + />
  212 + ),
  213 + },
  214 + ];
  215 +
  216 + return (
  217 + <Modal
  218 + open={true}
  219 + title="积分兑换记录"
  220 + width={800}
  221 + onCancel={() => {
  222 + setVisible(false);
  223 + onClose();
  224 + }}
  225 + footer={null}
  226 + destroyOnClose
  227 + >
  228 + <Tabs
  229 + activeKey={activeTab}
  230 + onChange={(key) => setActiveTab(key)}
  231 + items={tabItems}
  232 + />
  233 + </Modal>
  234 + );
  235 +};
  236 +
  237 +export default PointsExchangeRecordsModal;
... ...
src/pages/Prepaid/index.tsx
... ... @@ -17,6 +17,7 @@ import CheckModal from &#39;../Order/Order/components/CheckModal&#39;;
17 17 import { CHECK_TYPE } from '../Order/constant';
18 18 import BalanceChangeRecordsModal from './components/BalanceChangeRecordsModal';
19 19 import PointsExchangeModal from './components/PointsExchangeModal';
  20 +import PointsExchangeRecordsModal from './components/PointsExchangeRecordsModal';
20 21 import RechargePrepaymentModal from './components/RechargePrepaymentModal';
21 22 import {
22 23 ACCOUNT_COLUMNS,
... ... @@ -39,6 +40,10 @@ const PrepaidPage = () =&gt; {
39 40 ] = useState<boolean>(false);
40 41 const [pointsExchangeModalVisible, setPointsExchangeModalVisible] =
41 42 useState<boolean>(false);
  43 + const [
  44 + pointsExchangeRecordsModalVisible,
  45 + setPointsExchangeRecordsModalVisible,
  46 + ] = useState<boolean>(false);
42 47  
43 48 const reloadPrepaidTable = () => {
44 49 prepaidActionRef.current?.reload();
... ... @@ -198,7 +203,7 @@ const PrepaidPage = () =&gt; {
198 203 valueType: 'option',
199 204 key: 'option',
200 205 fixed: 'right',
201   - width: 200,
  206 + width: 240,
202 207 render: (text, record) => {
203 208 let btns = [];
204 209 btns.push(
... ... @@ -227,6 +232,19 @@ const PrepaidPage = () =&gt; {
227 232 消费记录
228 233 </Button>,
229 234 );
  235 + btns.push(
  236 + <Button
  237 + className="p-0 ml-2"
  238 + key="pointsRecords"
  239 + type="link"
  240 + onClick={() => {
  241 + setCurrentOptUserObj(record);
  242 + setPointsExchangeRecordsModalVisible(true);
  243 + }}
  244 + >
  245 + 积分兑换记录
  246 + </Button>,
  247 + );
230 248 return btns;
231 249 },
232 250 });
... ... @@ -407,6 +425,18 @@ const PrepaidPage = () =&gt; {
407 425 }}
408 426 />
409 427 )}
  428 +
  429 + {pointsExchangeRecordsModalVisible && currentOptUserObj && (
  430 + <PointsExchangeRecordsModal
  431 + setVisible={(val: boolean) => {
  432 + setPointsExchangeRecordsModalVisible(val);
  433 + }}
  434 + userInfoObj={currentOptUserObj}
  435 + onClose={() => {
  436 + setPointsExchangeRecordsModalVisible(false);
  437 + }}
  438 + />
  439 + )}
410 440 </div>
411 441 );
412 442 };
... ...
src/services/definition.ts
... ... @@ -1529,6 +1529,28 @@ export interface ExchangeIntegralDto {
1529 1529 remark?: string;
1530 1530 }
1531 1531  
  1532 +export interface ExchangeRecordsRequestDto {
  1533 + createByName?: string;
  1534 + createByNameLike?: string;
  1535 + /** @format date-time */
  1536 + createTimeGe?: string;
  1537 + /** @format date-time */
  1538 + createTimeLe?: string;
  1539 + /** @format int32 */
  1540 + current?: number;
  1541 + /** @format int32 */
  1542 + end?: number;
  1543 + /** @format int32 */
  1544 + id?: number;
  1545 + /** @format int32 */
  1546 + pageSize?: number;
  1547 + phone?: string;
  1548 + /** @format int32 */
  1549 + start?: number;
  1550 + /** @format int32 */
  1551 + total?: number;
  1552 +}
  1553 +
1532 1554 export interface FilePathDto {
1533 1555 url?: string;
1534 1556 }
... ...
src/services/request.ts
... ... @@ -57,6 +57,7 @@ import type {
57 57 DistrictSearchDo,
58 58 Dto,
59 59 ExchangeIntegralDto,
  60 + ExchangeRecordsRequestDto,
60 61 FeedbackRegistrationDTO,
61 62 InventoryMaterialStockReq,
62 63 InvoiceBatchDownloadDto,
... ... @@ -4732,6 +4733,77 @@ export const postIntegralQuerySumByUser = /* #__PURE__ */ (() =&gt; {
4732 4733 return request;
4733 4734 })();
4734 4735  
  4736 +/** @description request parameter type for postIntegralUserExchangeRecords */
  4737 +export interface PostIntegralUserExchangeRecordsOption {
  4738 + /**
  4739 + * @description
  4740 + * dto
  4741 + */
  4742 + body: {
  4743 + /**
  4744 + @description
  4745 + dto */
  4746 + dto: ExchangeRecordsRequestDto;
  4747 + };
  4748 +}
  4749 +
  4750 +/** @description response type for postIntegralUserExchangeRecords */
  4751 +export interface PostIntegralUserExchangeRecordsResponse {
  4752 + /**
  4753 + * @description
  4754 + * OK
  4755 + */
  4756 + 200: ServerResult;
  4757 + /**
  4758 + * @description
  4759 + * Created
  4760 + */
  4761 + 201: any;
  4762 + /**
  4763 + * @description
  4764 + * Unauthorized
  4765 + */
  4766 + 401: any;
  4767 + /**
  4768 + * @description
  4769 + * Forbidden
  4770 + */
  4771 + 403: any;
  4772 + /**
  4773 + * @description
  4774 + * Not Found
  4775 + */
  4776 + 404: any;
  4777 +}
  4778 +
  4779 +export type PostIntegralUserExchangeRecordsResponseSuccess =
  4780 + PostIntegralUserExchangeRecordsResponse[200];
  4781 +/**
  4782 + * @description
  4783 + * 用户积分兑换记录
  4784 + * @tags 积分接口
  4785 + * @produces *
  4786 + * @consumes application/json
  4787 + */
  4788 +export const postIntegralUserExchangeRecords = /* #__PURE__ */ (() => {
  4789 + const method = 'post';
  4790 + const url = '/integral/userExchangeRecords';
  4791 + function request(
  4792 + option: PostIntegralUserExchangeRecordsOption,
  4793 + ): Promise<PostIntegralUserExchangeRecordsResponseSuccess> {
  4794 + return requester(request.url, {
  4795 + method: request.method,
  4796 + ...option,
  4797 + }) as unknown as Promise<PostIntegralUserExchangeRecordsResponseSuccess>;
  4798 + }
  4799 +
  4800 + /** http method */
  4801 + request.method = method;
  4802 + /** request url */
  4803 + request.url = url;
  4804 + return request;
  4805 +})();
  4806 +
4735 4807 /** @description request parameter type for postKingdeeRepCustomer */
4736 4808 export interface PostKingdeeRepCustomerOption {
4737 4809 /**
... ...