Commit 576a38ce95fa74baff8d977d2480d9d06bbdfffd

Authored by boyang
2 parents 3fa11755 850ffdd2

Merge remote-tracking branch 'origin/IntegralRecord'

# Conflicts:
#	src/pages/ResearchGroup/constant.tsx
src/pages/Order/FeedBack/OrderDrawer copy.tsx deleted 100644 → 0
1   -import { RESPONSE_CODE } from '@/constants/enum';
2   -import {
3   - postKingdeeRepCustomer,
4   - postKingdeeRepCustomerDetail,
5   - postKingdeeRepMaterial,
6   - postKingdeeRepMaterialUnit,
7   - postKingdeeRepMeasureUnit,
8   - postServiceOrderAddOrder,
9   - postServiceOrderQuerySalesCode,
10   - postServiceOrderUpdateOrder,
11   -} from '@/services';
12   -import {
13   - enumToSelect,
14   - getAliYunOSSFileNameFromUrl,
15   - getUserInfo,
16   -} from '@/utils';
17   -import { getTeacherCustomFieldNumber } from '@/utils/kingdee';
18   -import {
19   - DrawerForm,
20   - FormListActionType,
21   - ProCard,
22   - ProFormDateTimePicker,
23   - ProFormDigit,
24   - ProFormList,
25   - ProFormSelect,
26   - ProFormText,
27   - ProFormTextArea,
28   - ProFormUploadDragger,
29   -} from '@ant-design/pro-components';
30   -import { Button, Form, message } from 'antd';
31   -import { cloneDeep } from 'lodash';
32   -import { useEffect, useRef, useState } from 'react';
33   -import KingdeeCustomerModal from './KingdeeCustomerModal';
34   -import {
35   - INVOCING_STATUS_OPTIONS,
36   - INVOCING_STATUS_OPTIONS_OLD,
37   - PAYMENT_CHANNEL_OPTIONS,
38   - PAYMENT_METHOD_OPTIONS,
39   - PRODUCT_BELONG_DEPARTMENT_OPTIONS,
40   -} from './constant';
41   -
42   -export default ({ onClose, data, subOrders, orderOptType }) => {
43   - const [invoicingStatus, setInvoicingStatus] = useState('');
44   - const [salesCodeOptions, setSalesCodeOptions] = useState([]);
45   - const [customer, setCustomer] = useState({});
46   - const [kingdeeCstomerModalVisible, setKingdeeCstomerModalVisible] =
47   - useState(false);
48   - const [
49   - productParametersDisabledFlagList,
50   - setProductParametersDisabledFlagList,
51   - ] = useState([]);
52   - // const [productInvStockOptionsList, setProductInvStockOptionsList] = useState(
53   - // [],
54   - // ); //商品的仓库选项
55   - const [productUnitOptionsList, setProductUnitOptionsList] = useState([]); //商品的单位选项
56   - const [productCustomerContactOptions, setProductCustomerContactOptions] =
57   - useState([]); //客户的收货人选项
58   - const [form] = Form.useForm<{
59   - salesCode: '';
60   - customerName: '';
61   - customerContactNumber: '';
62   - institution: '';
63   - institutionContactName: '';
64   - customerShippingAddress: '';
65   - totalPayment: '';
66   - paymentChannel: '';
67   - paymentMethod: '';
68   - productBelongBusiness: '';
69   - invoicingStatus: '';
70   - invoiceIdentificationNumber: '';
71   - invoicingTime: '';
72   - bank: '';
73   - bankAccountNumber: '';
74   - deleteSubOrderLists: [];
75   - notes: '';
76   - list: [
77   - {
78   - productCode: '';
79   - productName: '';
80   - quantity: '';
81   - productPrice: '';
82   - parameters: '';
83   - subOrderPayment: '';
84   - unit: '';
85   - serialNumber: '';
86   - notes: '';
87   - },
88   - ];
89   - }>();
90   -
91   - let originSubOrders = cloneDeep(subOrders);
92   - /**
93   - * 获取当前的操作类型boolean值
94   - * @param type 操作类型,如果与当前匹配返回true
95   - */
96   - function optType(type: string) {
97   - return orderOptType === type;
98   - }
99   -
100   - /**
101   - *
102   - * @returns 获取开票选项
103   - */
104   - function getInvoicingSelect() {
105   - if (optType('edit')) {
106   - return enumToSelect(INVOCING_STATUS_OPTIONS_OLD);
107   - }
108   - return enumToSelect(INVOCING_STATUS_OPTIONS);
109   - }
110   -
111   - const fileList: any = [];
112   -
113   - const getSalesCodeOptions = async () => {
114   - const res = await postServiceOrderQuerySalesCode();
115   - let options = res.data?.map((item) => {
116   - return {
117   - label: item.userName,
118   - value: item.userName,
119   - number: item.number,
120   - };
121   - });
122   - setSalesCodeOptions(options);
123   -
124   - if (optType('copy') || optType('edit')) {
125   - let includeFlag = false;
126   - //销售代码校验,如果是旧的销售代码,则提示并清空
127   - for (let option of options) {
128   - if (option.value === data.salesCode) {
129   - includeFlag = true;
130   - }
131   - }
132   - if (!includeFlag) {
133   - form.resetFields(['salesCode']);
134   - message.warning('检测到销售代码为旧的,已清空,请重新选择');
135   - }
136   - }
137   - };
138   -
139   - //复制的时候,如果是不需要开票,要把开票信息清空
140   - if (optType('copy') && data.invoicingStatus === 'UN_INVOICE') {
141   - data.invoiceIdentificationNumber = undefined;
142   - }
143   -
144   - if (subOrders !== undefined && subOrders.length > 0) {
145   - data.list = subOrders;
146   - }
147   -
148   - const actionRef = useRef<
149   - FormListActionType<{
150   - name: string;
151   - }>
152   - >();
153   -
154   - useEffect(() => {
155   - form.setFieldsValue({ ...data });
156   - //如果是新建,需要清空list
157   - if (optType('add')) {
158   - form.resetFields(['list']);
159   - }
160   - }, [data]);
161   -
162   - /**
163   - * 选择客户后自动为收货人Select添加选项,填充课题组和单位信息
164   - * @param option 客户选项
165   - */
166   - async function autoFillCustomerContactSelectOptions(customerId: any) {
167   - //查询单位详细信息
168   - let res = await postKingdeeRepCustomerDetail({
169   - data: {
170   - id: customerId,
171   - },
172   - });
173   -
174   - //erp客户名称
175   - form.setFieldValue('erpCustomerName', res?.name);
176   -
177   - //重新设置当前option
178   - form.setFieldValue('erpCustomerId', {
179   - label: res?.name,
180   - value: res?.id,
181   - id: res?.id,
182   - });
183   -
184   - //查询客户自定义字段,课题组
185   - let entity_number = await getTeacherCustomFieldNumber();
186   -
187   - //在单位详细信息中拿到自定义字段的值
188   - let customField = res?.custom_field;
189   - if (customField) {
190   - let teacherName = customField[entity_number];
191   - //填充到课题组老师表单字段中
192   - form.setFieldValue('institutionContactName', teacherName);
193   - }
194   -
195   - //单位名称,从客户名称中获取,客户名称规则<单位名称>-<联系人名称和电话>
196   - let namePortions = res?.name?.split('-');
197   - if (namePortions && namePortions.length >= 2) {
198   - form.setFieldValue('institution', namePortions[0]);
199   - }
200   -
201   - //如果原来的收货信息没有包含在这次查询出来的收货人选项中,那么清除原来的收货人信息
202   - let existFlag = false;
203   -
204   - //填充收货人选项
205   - let newProductCustomerContactOptions = res?.bomentity?.map((item) => {
206   - let address =
207   - item.contact_person + ',' + item.mobile + ',' + item.contact_address;
208   - if (address === data.contactAddress) {
209   - existFlag = true;
210   - }
211   - return { ...item, label: address, value: address };
212   - });
213   -
214   - setProductCustomerContactOptions(newProductCustomerContactOptions);
215   -
216   - if (!existFlag) {
217   - //清空原来的收货人信息
218   - form.setFieldValue('customerShippingAddress', undefined);
219   - form.setFieldValue('customerContactNumber', undefined);
220   - form.setFieldValue('customerName', undefined);
221   - form.setFieldValue('erpCustomerAddress', undefined);
222   - }
223   - }
224   -
225   - /**
226   - * 回显金蝶信息
227   - */
228   - async function showKindeeInfo() {
229   - //客户信息
230   - if (data.customerId) {
231   - //客户回显
232   - autoFillCustomerContactSelectOptions(data.customerId);
233   - }
234   -
235   - //商品单位回显
236   - let list = data?.subOrderInformationLists;
237   - if (list) {
238   - let newProductUnitOptionsList = [...productUnitOptionsList];
239   - for (let i = 0; i < list.length; i++) {
240   - newProductUnitOptionsList[i] = [
241   - { label: list[i].unit, value: list[i].unitId },
242   - ];
243   - }
244   - setProductUnitOptionsList(newProductUnitOptionsList);
245   - }
246   - }
247   -
248   - /**
249   - *
250   - * @param option 商品名称所对应的商品数据
251   - * @param currentRowData list中当前行的数据
252   - */
253   - async function autoFillProductInfo(
254   - option: any,
255   - currentRowData: any,
256   - index: any,
257   - ) {
258   - let newProductParametersDisabledFlagList = [
259   - ...productParametersDisabledFlagList,
260   - ];
261   - let newProductUnitOptionsList = [...productUnitOptionsList];
262   - newProductUnitOptionsList[index] = [];
263   -
264   - //是新增商品
265   - if (option.type === 'add') {
266   - //商品参数开放权限可以编辑
267   - newProductParametersDisabledFlagList[index] = false;
268   -
269   - //清空商品信息
270   - let copyList = form.getFieldValue('list');
271   - let currentData = copyList[index];
272   - currentData.productCode = undefined;
273   - currentData.parameters = undefined;
274   - currentData.unit = undefined;
275   - currentData.subOrderPayment = undefined;
276   - currentData.quantity = undefined;
277   - currentData.notes = undefined;
278   - currentData.productPrice = undefined;
279   - form.setFieldValue('list', copyList);
280   -
281   - //查询计量单价列表
282   - let res = await postKingdeeRepMeasureUnit({ data: {} });
283   - if (res && res?.rows) {
284   - for (let row of res?.rows) {
285   - newProductUnitOptionsList[index].push({
286   - label: row.name,
287   - value: row.id,
288   - });
289   - }
290   - }
291   - } else {
292   - //选择的是已有的商品,进行内容自动填充
293   - let copyList = form.getFieldValue('list');
294   - let currentData = copyList[index];
295   - currentData.productCode = option?.number;
296   - currentData.parameters = option?.model;
297   - currentData.unit = option?.base_unit_name;
298   -
299   - //商品id
300   - currentData.materialId = option?.id;
301   -
302   - //单位
303   - currentData.unit = option.base_unit_name;
304   - currentData.unitId = option.base_unit_id;
305   -
306   - form.setFieldValue('list', copyList);
307   -
308   - //商品所在的仓库选项填充
309   - // let res = await postKingdeeRepMaterialStock({
310   - // data: {
311   - // material_id: option.id,
312   - // },
313   - // });
314   - // let newProductInvStockOptionsList = [...productInvStockOptionsList];
315   - // newProductInvStockOptionsList[index] = res?.rows?.map((item) => {
316   - // return { label: item.inv_stock, value: item.inv_stock_id };
317   - // });
318   - // setProductInvStockOptionsList(newProductInvStockOptionsList);
319   -
320   - //商品单位填充,查询商品单位列表
321   - let res = await postKingdeeRepMaterialUnit({
322   - data: { material_id: option.id },
323   - });
324   - if (res && res.rows) {
325   - for (let row of res.rows) {
326   - newProductUnitOptionsList[index].push({
327   - label: row.unit_name,
328   - value: row.unit_id,
329   - });
330   - }
331   - }
332   - //商品参数不允许编辑
333   - newProductParametersDisabledFlagList[index] = true;
334   - }
335   -
336   - setProductParametersDisabledFlagList(newProductParametersDisabledFlagList);
337   - setProductUnitOptionsList(newProductUnitOptionsList);
338   - }
339   -
340   - /**
341   - * 选择收货人后自动填充信息
342   - * @param option 收货人信息
343   - */
344   - async function autoFillCustomerInfo(option: any) {
345   - form.setFieldValue('customerShippingAddress', option.contact_address);
346   - form.setFieldValue('customerContactNumber', option.mobile);
347   - form.setFieldValue('customerName', option.contact_person);
348   -
349   - //erp收货地址:需要与客户联系人中的地址一样:姓名,手机号,地址
350   - form.setFieldValue('contactAddress', option.value);
351   - }
352   -
353   - /**
354   - * 填充销售代表的信息
355   - * @param option
356   - */
357   - function autoFillSalesInfo(option: any) {
358   - console.log(option);
359   - //销售代表对应职员编码填充
360   - form.setFieldValue('empNumber', option.number);
361   - }
362   -
363   - /**
364   - * 选择商品单位后自动填充
365   - * @param option
366   - * @param index
367   - */
368   - function autoFillUnit(option: any, index: any) {
369   - let copyList = form.getFieldValue('list');
370   - let currentData = copyList[index];
371   - currentData.unit = option?.label;
372   - form.setFieldValue('list', copyList);
373   - }
374   -
375   - /**
376   - * 计算子订单金额
377   - * @param listMeta 当前商品信息
378   - */
379   - function computeSubOrderPayment(listMeta: any) {
380   - let quantity = listMeta?.record?.quantity;
381   - let productPrice = listMeta?.record?.productPrice;
382   - quantity = quantity === '' || quantity === undefined ? 0 : quantity;
383   - productPrice =
384   - productPrice === '' || productPrice === undefined ? 0 : productPrice;
385   -
386   - listMeta.subOrderPayment = quantity * productPrice;
387   - let list = form.getFieldValue('list');
388   - list[listMeta?.index].subOrderPayment = quantity * productPrice;
389   - form.setFieldValue('list', list);
390   - }
391   -
392   - /**
393   - * 计算支付总额
394   - */
395   - function computeTotalPayment() {
396   - let list = form.getFieldValue('list');
397   - let totalPayment = 0;
398   - list?.forEach((subOrder: any) => {
399   - let subOrderPayment = subOrder?.subOrderPayment;
400   - if (subOrderPayment === '' || subOrderPayment === undefined) {
401   - totalPayment += 0;
402   - } else {
403   - totalPayment += subOrderPayment;
404   - }
405   - });
406   - form.setFieldValue('totalPayment', totalPayment);
407   - }
408   -
409   - useEffect(() => {
410   - getSalesCodeOptions();
411   - showKindeeInfo();
412   - }, []);
413   -
414   - useEffect(() => {
415   - // 在组件挂载或数据变化时,更新组件状态
416   - if (data) {
417   - setInvoicingStatus(data.invoicingStatus);
418   - }
419   - }, [data]);
420   -
421   - // let mainInfoDisbled = optType('edit');
422   - if (optType('edit') || optType('copy')) {
423   - //如果是复制,需要开票,不回显是否需要开票字段
424   - if (optType('copy')) {
425   - if (data.invoicingStatus === 'INVOICED') {
426   - data.invoicingStatus = undefined;
427   - }
428   - }
429   - //订单修改和新增的子订单列表命名是list
430   - data.list = data.subOrderInformationLists;
431   - //主订单事业部默认显示子订单第一条的事业部
432   - data.productBelongBusiness = data.list[0].productBelongBusiness;
433   - data.paymentMethod = data.list[0].paymentMethod;
434   - data.paymentChannel = data.list[0].paymentChannel;
435   - data.invoicingStatus = data.list[0].invoicingStatus;
436   -
437   - data.list = data.list?.map((item) => {
438   - item.filePaths = item.listAnnex?.map((path) => {
439   - let i = 0;
440   - return {
441   - uid: i++,
442   - name: getAliYunOSSFileNameFromUrl(path),
443   - status: 'uploaded',
444   - url: path,
445   - response: { data: [path] },
446   - };
447   - });
448   - return item;
449   - });
450   - }
451   -
452   - return (
453   - <>
454   - <DrawerForm<{
455   - deleteSubOrderLists: any;
456   - name: string;
457   - company: string;
458   - }>
459   - open
460   - width="35%"
461   - title={optType('add') || optType('copy') ? '新建订单' : '修改订单'}
462   - resize={{
463   - onResize() {
464   - console.log('resize!');
465   - },
466   - maxWidth: window.innerWidth * 0.8,
467   - minWidth: 400,
468   - }}
469   - // layout="horizontal"
470   - // labelCol={{ span: 8 }}
471   - form={form}
472   - autoFocusFirstInput
473   - drawerProps={{
474   - destroyOnClose: true,
475   - maskClosable: false,
476   - }}
477   - submitTimeout={2000}
478   - onFinish={async (values) => {
479   - let res = {};
480   - //附件处理
481   - let list = values.list;
482   - // console.log(list);
483   - list = list.map((item) => {
484   - item.filePaths = item.filePaths?.map((file) => {
485   - console.log(file);
486   - return { url: file.response.data[0] };
487   - });
488   - return item;
489   - });
490   -
491   - values.list = list;
492   - values.institution = values.institution?.trim();
493   - values.institutionContactName = values.institutionContactName?.trim();
494   -
495   - if (typeof values.erpCustomerId !== 'string') {
496   - values.erpCustomerId = values.erpCustomerId?.id;
497   - }
498   -
499   - if (optType('add') || optType('copy')) {
500   - res = await postServiceOrderAddOrder({ data: values });
501   - } else {
502   - //计算已删除的子订单id
503   - const originIds = originSubOrders.map((item) => {
504   - return item.id;
505   - });
506   - const curIds = form.getFieldValue('list')?.map((item) => {
507   - return item.id;
508   - });
509   - let diff = originIds.filter((item) => !curIds.includes(item));
510   - values.deleteSubOrderLists = diff;
511   - res = await postServiceOrderUpdateOrder({ data: values });
512   - }
513   -
514   - if (res.result === RESPONSE_CODE.SUCCESS) {
515   - message.success(res.message);
516   - // 不返回不会关闭弹框
517   - onClose(true);
518   - return true;
519   - }
520   - }}
521   - onOpenChange={(val) => {
522   - return !val && onClose();
523   - }}
524   - >
525   - <h2>订单基本信息</h2>
526   - <ProFormText
527   - key="id"
528   - name="id"
529   - width="lg"
530   - disabled
531   - label="id"
532   - placeholder="id"
533   - hidden
534   - />
535   -
536   - <ProFormText
537   - key="empNumber"
538   - name="empNumber"
539   - width="lg"
540   - label="销售职员编码"
541   - placeholder="销售职员编码"
542   - hidden
543   - />
544   -
545   - <ProFormSelect
546   - name="salesCode"
547   - key="salesCode"
548   - width="lg"
549   - showSearch
550   - label="销售代表"
551   - placeholder="请输入销售代表"
552   - rules={[{ required: true, message: '销售代表必填' }]}
553   - options={salesCodeOptions}
554   - onChange={(_, option) => {
555   - autoFillSalesInfo(option);
556   - }}
557   - // disabled={mainInfoDisbled}
558   - />
559   -
560   - <ProFormText
561   - key="erpCustomerName"
562   - name="erpCustomerName"
563   - hidden
564   - ></ProFormText>
565   -
566   - <ProFormText
567   - key="contactAddress"
568   - name="contactAddress"
569   - hidden
570   - ></ProFormText>
571   -
572   - <ProFormSelect
573   - name="erpCustomerId"
574   - key="erpCustomerId"
575   - width="lg"
576   - showSearch
577   - label={
578   - <>
579   - <span>客户</span>
580   - <span
581   - className="pl-2 text-xs text-[#1677ff] cursor-pointer"
582   - onClick={() => {
583   - let customerId = form.getFieldValue('erpCustomerId');
584   - if (typeof customerId === 'string') {
585   - setCustomer({ ...customer, id: customerId });
586   - } else {
587   - setCustomer({ ...customer, id: customerId.id });
588   - }
589   - setKingdeeCstomerModalVisible(true);
590   - }}
591   - >
592   - 编辑客户信息
593   - </span>
594   - </>
595   - }
596   - placeholder="请选择客户"
597   - rules={[{ required: true, message: '客户必填' }]}
598   - onChange={(_, option) => {
599   - //新增客户
600   - if (option.type === 'add') {
601   - setCustomer({ name: option.name });
602   - setKingdeeCstomerModalVisible(true);
603   - return;
604   - }
605   - autoFillCustomerContactSelectOptions(option.id);
606   - }}
607   - initialValue={{
608   - label: data?.erpCustomerName,
609   - value: data?.customerId,
610   - id: data?.customerId,
611   - }}
612   - fieldProps={{
613   - optionItemRender(item) {
614   - if (item.type === 'add') {
615   - return (
616   - <div title={item.name + '(新增客户)'}>
617   - <span style={{ color: '#333333' }}>{item.name}</span>
618   - {' | '}
619   - <span style={{ color: 'orange' }}>自定义</span>
620   - </div>
621   - );
622   - }
623   - return (
624   - <div
625   - title={
626   - item.name +
627   - ' | ' +
628   - item.customerContactNumber +
629   - ' | ' +
630   - (item.customerShippingAddress === undefined
631   - ? '无地址'
632   - : item.customerShippingAddress) +
633   - ' | ' +
634   - item.institutionContactName +
635   - ' | ' +
636   - item.institution
637   - }
638   - >
639   - <span style={{ color: '#333333' }}>{item.name}</span>
640   - </div>
641   - );
642   - },
643   - }}
644   - debounceTime={1000}
645   - request={async (value, {}) => {
646   - const keywords = value.keyWords;
647   - const res = await postKingdeeRepCustomer({
648   - data: { search: keywords },
649   - });
650   - console.log(res);
651   -
652   - let options = res?.rows?.map((c: any) => {
653   - return {
654   - ...c,
655   - label: c.name,
656   - value: c.id,
657   - key: c.id,
658   - };
659   - });
660   -
661   - //第一个商品默认为要新增客户
662   - if (keywords.trim() !== '') {
663   - options.unshift({
664   - name: keywords,
665   - type: 'add',
666   - label: keywords,
667   - value: 3.1415926,
668   - key: keywords,
669   - });
670   - }
671   - return options;
672   - }}
673   - />
674   - <ProFormSelect
675   - key="customerName"
676   - label="收货人"
677   - width="lg"
678   - showSearch
679   - name="customerName"
680   - placeholder="请选择收货人"
681   - rules={[{ required: true, message: '收货人必填' }]}
682   - onChange={(_, option) => {
683   - autoFillCustomerInfo(option);
684   - }}
685   - initialValue={data.contactAddress}
686   - options={productCustomerContactOptions}
687   - />
688   - <ProFormText
689   - width="lg"
690   - key="customerContactNumber"
691   - name="customerContactNumber"
692   - label="联系方式"
693   - placeholder="请输入联系方式"
694   - rules={[{ required: true, message: '联系方式必填' }]}
695   - disabled
696   - />
697   - <ProFormText
698   - width="lg"
699   - key="institution"
700   - name="institution"
701   - label="单位"
702   - placeholder="请输入单位"
703   - rules={[{ required: true, message: '单位必填' }]}
704   - disabled
705   - />
706   - <ProFormText
707   - width="lg"
708   - key="institutionContactName"
709   - name="institutionContactName"
710   - label="课题组"
711   - placeholder="请输入课题组"
712   - rules={[{ required: true, message: '课题组必填' }]}
713   - disabled
714   - />
715   - <ProFormTextArea
716   - width="lg"
717   - key="customerShippingAddress"
718   - name="customerShippingAddress"
719   - label="收货地址"
720   - placeholder="请输入收货地址"
721   - rules={[{ required: true, message: '收货地址必填' }]}
722   - disabled
723   - />
724   - <div id="total-payment">
725   - <ProFormDigit
726   - name="totalPayment"
727   - width="lg"
728   - key="totalPayment"
729   - label="支付总额(¥)"
730   - rules={[{ required: true, message: '支付总额必填' }]}
731   - tooltip="点击计算,合计所有子订单金额"
732   - fieldProps={{
733   - addonAfter: (
734   - <Button
735   - className="rounded-l-none"
736   - type="primary"
737   - onClick={computeTotalPayment}
738   - >
739   - 计算
740   - </Button>
741   - ),
742   - }}
743   - // disabled={mainInfoDisbled}
744   - />
745   - </div>
746   -
747   - <ProFormSelect
748   - placeholder="请输入支付渠道"
749   - name="paymentChannel"
750   - width="lg"
751   - key="paymentChannel"
752   - label="支付渠道"
753   - options={enumToSelect(PAYMENT_CHANNEL_OPTIONS)}
754   - rules={[{ required: true, message: '支付渠道必填' }]}
755   - // disabled={mainInfoDisbled}
756   - />
757   - <ProFormSelect
758   - placeholder="请输入支付方式"
759   - name="paymentMethod"
760   - width="lg"
761   - key="paymentMethod"
762   - label="支付方式"
763   - options={enumToSelect(PAYMENT_METHOD_OPTIONS)}
764   - rules={[{ required: true, message: '支付方式必填' }]}
765   - // disabled={mainInfoDisbled}
766   - />
767   - <ProFormSelect
768   - placeholder="选择是否需要开票"
769   - name="invoicingStatus"
770   - width="lg"
771   - key="invoicingStatus"
772   - label="是否需要开票"
773   - options={getInvoicingSelect()}
774   - // disabled={mainInfoDisbled}
775   - onChange={(_, option) => {
776   - setInvoicingStatus(option.value);
777   - if (option.value === 'UN_INVOICE') {
778   - form.setFieldValue('invoiceIdentificationNumber', undefined);
779   - form.setFieldValue('bank', undefined);
780   - form.setFieldValue('bankAccountNumber', undefined);
781   - }
782   - }}
783   - rules={[{ required: true, message: '是否需要开票必填' }]}
784   - />
785   - <ProFormText
786   - width="lg"
787   - name="invoiceIdentificationNumber"
788   - label="开票信息"
789   - key="invoiceIdentificationNumber"
790   - // disabled={mainInfoDisbled}
791   - hidden={invoicingStatus === 'UN_INVOICE'}
792   - placeholder="请输入开票信息"
793   - rules={[
794   - {
795   - required: invoicingStatus === 'UN_INVOICE' ? false : true,
796   - message: '开票信息必填',
797   - },
798   - ]}
799   - />
800   -
801   - {getUserInfo().roleSmallVO?.code === 'admin' ? (
802   - <ProFormDateTimePicker
803   - width="lg"
804   - key="invoicingTime"
805   - name="invoicingTime"
806   - // disabled={mainInfoDisbled}
807   - hidden={invoicingStatus === 'UN_INVOICE'}
808   - label="开票时间"
809   - placeholder="请输入开票时间"
810   - />
811   - ) : (
812   - ''
813   - )}
814   - <ProFormText
815   - width="lg"
816   - name="bank"
817   - key="bank"
818   - label="开户银行"
819   - // disabled={mainInfoDisbled}
820   - hidden={invoicingStatus === 'UN_INVOICE'}
821   - placeholder="请输入开户银行"
822   - />
823   - <ProFormText
824   - width="lg"
825   - key="bankAccountNumber"
826   - name="bankAccountNumber"
827   - hidden={invoicingStatus === 'UN_INVOICE'}
828   - label="银行账号"
829   - // disabled={mainInfoDisbled}
830   - placeholder="请输入银行账号"
831   - />
832   - <ProFormTextArea
833   - width="lg"
834   - name="notes"
835   - label="备注"
836   - key="notes"
837   - // disabled={mainInfoDisbled}
838   - placeholder="请输入备注"
839   - rules={[
840   - {
841   - max: 120, // 最大长度为120个字符
842   - message: '备注不能超过120个字符',
843   - },
844   - ]}
845   - />
846   -
847   - <h2>商品信息</h2>
848   - <ProFormList
849   - creatorButtonProps={{ disabled: false }}
850   - name="list"
851   - label=""
852   - copyIconProps={false} //复制按钮不显示
853   - initialValue={[
854   - {
855   - productCode: '',
856   - productName: '',
857   - quantity: '',
858   - productPrice: '',
859   - parameters: '',
860   - subOrderPayment: '',
861   - },
862   - ]}
863   - actionGuard={{
864   - beforeRemoveRow: async (index) => {
865   - return new Promise((resolve) => {
866   - if (index === 0) {
867   - message.error('第一行数据不能删除');
868   - resolve(false);
869   - return;
870   - }
871   - resolve(true);
872   - });
873   - },
874   - }}
875   - itemRender={(doms, listMeta) => {
876   - if (optType('edit')) {
877   - let i = 0;
878   - let defaultFileList = listMeta.record?.listAnnex?.map((annex) => {
879   - return {
880   - uid: i++,
881   - name: annex,
882   - status: 'uploaded',
883   - url: annex,
884   - response: { data: [annex] },
885   - };
886   - });
887   - fileList[listMeta.index] = defaultFileList;
888   - }
889   - let itemFileList = fileList[listMeta.index];
890   - return (
891   - <ProCard
892   - bordered
893   - extra={doms.action}
894   - title={'商品' + (listMeta.index + 1)}
895   - style={{
896   - marginBlockEnd: 8,
897   - }}
898   - >
899   - {[
900   - <ProFormText
901   - key={'material' + listMeta.index}
902   - name="materialId"
903   - hidden
904   - ></ProFormText>,
905   - <ProFormSelect
906   - key="key"
907   - label="商品名称"
908   - width="lg"
909   - showSearch
910   - name="productName"
911   - // options={options}
912   - placeholder="请搜索商品"
913   - rules={[{ required: true, message: '商品名称必填' }]}
914   - onChange={(_, option) => {
915   - autoFillProductInfo(option, listMeta, listMeta.index);
916   - }}
917   - initialValue={{
918   - label: listMeta?.record?.productName,
919   - value: listMeta?.record?.materialId,
920   - }}
921   - fieldProps={{
922   - optionItemRender(item) {
923   - if (item.type === 'add') {
924   - return (
925   - <div title={item.name + '(新增商品信息)'}>
926   - <span style={{ color: '#333333' }}>
927   - {item.label}
928   - </span>
929   - {' | '}
930   - <span style={{ color: 'orange' }}>新增商品</span>
931   - </div>
932   - );
933   - }
934   - return (
935   - <div
936   - title={
937   - item.label +
938   - ' | ' +
939   - (item.model === undefined
940   - ? '无参数'
941   - : item.model) +
942   - ' | ' +
943   - item.base_unit_name
944   - }
945   - >
946   - <span style={{ color: '#333333' }}>
947   - {item.label}
948   - </span>
949   - {' | '}
950   - <span style={{ color: '#339999' }}>
951   - {item.model === undefined ? '无参数' : item.model}
952   - </span>
953   - {' | '}
954   - <span style={{ color: '#666666' }}>
955   - {item.base_unit_name === undefined
956   - ? '无单位'
957   - : item.base_unit_name}
958   - </span>
959   - </div>
960   - );
961   - },
962   - }}
963   - debounceTime={1000}
964   - request={async (value) => {
965   - const keywords = value.keyWords;
966   - const res = await postKingdeeRepMaterial({
967   - data: { search: keywords },
968   - });
969   - let options = res?.rows?.map((p: any) => {
970   - return {
971   - ...p,
972   - label: p.name,
973   - value: p.id + '|' + p.name,
974   - key: p.id,
975   - };
976   - });
977   -
978   - //第一个商品默认为要新增的商品
979   - if (keywords.trim() !== '') {
980   - options.unshift({
981   - productName: keywords,
982   - type: 'add',
983   - label: keywords,
984   - value: 13 + '|' + keywords,
985   - key: keywords,
986   - });
987   - }
988   - return options;
989   - }}
990   - />,
991   - <ProFormText
992   - key={'productCode' + listMeta.index}
993   - width="lg"
994   - name="productCode"
995   - disabled
996   - label={
997   - <>
998   - <span>商品编码</span>
999   - <span className="pl-2 text-xs text-gray-400">
1000   - 新增商品时,商品编码由系统自动生成
1001   - </span>
1002   - </>
1003   - }
1004   - placeholder="商品编码"
1005   - />,
1006   - // <ProFormSelect
1007   - // key="inv_stock"
1008   - // placeholder="请选择仓库"
1009   - // name="invStockId"
1010   - // width="lg"
1011   - // label="仓库"
1012   - // options={productInvStockOptionsList[listMeta.index]}
1013   - // />,
1014   - <ProFormText
1015   - key={'parameters' + listMeta.index}
1016   - width="lg"
1017   - name="parameters"
1018   - label="商品参数"
1019   - placeholder="请输入商品参数"
1020   - rules={[{ required: true, message: '商品参数必填' }]}
1021   - disabled={
1022   - productParametersDisabledFlagList[listMeta.index] !==
1023   - false
1024   - }
1025   - />,
1026   - <ProFormDigit
1027   - key={'quantity' + listMeta.index}
1028   - width="lg"
1029   - name="quantity"
1030   - label="商品数量"
1031   - fieldProps={{
1032   - onChange: (value) => {
1033   - listMeta.record.quantity = value;
1034   - computeSubOrderPayment(listMeta);
1035   - },
1036   - }}
1037   - placeholder="请输入商品数量"
1038   - rules={[{ required: true, message: '商品数量必填' }]}
1039   - />,
1040   -
1041   - <ProFormDigit
1042   - key={'productPrice' + listMeta.index}
1043   - width="lg"
1044   - name="productPrice"
1045   - label="商品单价"
1046   - fieldProps={{
1047   - onChange: (value) => {
1048   - listMeta.record.productPrice = value;
1049   - computeSubOrderPayment(listMeta);
1050   - },
1051   - }}
1052   - placeholder="请输入商品单价"
1053   - rules={[{ required: true, message: '商品单价必填' }]}
1054   - />,
1055   -
1056   - <ProFormSelect
1057   - key="unitId"
1058   - placeholder="请选择单位"
1059   - name="unitId"
1060   - width="lg"
1061   - label="单位"
1062   - showSearch
1063   - onChange={(_, option) => {
1064   - autoFillUnit(option, listMeta.index);
1065   - }}
1066   - options={productUnitOptionsList[listMeta.index]}
1067   - rules={[{ required: true, message: '商品单位必填' }]}
1068   - />,
1069   - <ProFormText
1070   - key={'unit' + listMeta.index}
1071   - width="lg"
1072   - name="unit"
1073   - label="商品单位"
1074   - placeholder="请输入商品单位"
1075   - rules={[{ required: true, message: '商品单位必填' }]}
1076   - hidden
1077   - />,
1078   -
1079   - <ProFormDigit
1080   - width="lg"
1081   - key={'subOrderPayment' + listMeta.index}
1082   - name="subOrderPayment"
1083   - label="子订单金额"
1084   - placeholder="请输入子订单金额"
1085   - tooltip="商品数量和单价变化后会自动计算子订单金额"
1086   - rules={[{ required: true, message: '子订单金额必填' }]}
1087   - />,
1088   - <ProFormSelect
1089   - key={'productBelongBusiness' + listMeta.index}
1090   - placeholder="请输入所属事业部"
1091   - name="productBelongBusiness"
1092   - width="lg"
1093   - label="所属事业部"
1094   - options={enumToSelect(PRODUCT_BELONG_DEPARTMENT_OPTIONS)}
1095   - initialValue={'EXPERIMENTAL_CONSUMABLES'}
1096   - rules={[{ required: true, message: '所属事业部必填' }]}
1097   - // disabled={mainInfoDisbled}
1098   - />,
1099   - <ProFormTextArea
1100   - key={'notes' + listMeta.index}
1101   - width="lg"
1102   - name="notes"
1103   - label={
1104   - <div>
1105   - <span>备注</span>
1106   - <span className="pl-2 text-xs text-gray-400">
1107   - 备注将体现在出货单上,请将需要仓管看见的信息写在备注上,例如需要开收据等信息。
1108   - </span>
1109   - </div>
1110   - }
1111   - placeholder="请输入备注"
1112   - rules={[
1113   - {
1114   - max: 120, // 最大长度为120个字符
1115   - message: '备注不能超过120个字符',
1116   - },
1117   - ]}
1118   - />,
1119   - <>
1120   - <ProFormUploadDragger
1121   - key={'filePaths' + listMeta.index}
1122   - label="附件"
1123   - name="filePaths"
1124   - action="/api/service/order/fileProcess"
1125   - fieldProps={{
1126   - headers: {
1127   - Authorization: localStorage.getItem('token'),
1128   - },
1129   - itemFileList,
1130   - }}
1131   - />
1132   - </>,
1133   - ]}
1134   - </ProCard>
1135   - );
1136   - }}
1137   - actionRef={actionRef}
1138   - ></ProFormList>
1139   - </DrawerForm>
1140   -
1141   - {kingdeeCstomerModalVisible && (
1142   - <KingdeeCustomerModal
1143   - setVisible={setKingdeeCstomerModalVisible}
1144   - data={customer}
1145   - onClose={(customerId: any) => {
1146   - setKingdeeCstomerModalVisible(false);
1147   - //回显已经新建好的客户
1148   - autoFillCustomerContactSelectOptions(customerId);
1149   - }}
1150   - />
1151   - )}
1152   - </>
1153   - );
1154   -};
src/pages/Order/OrderList/OrderDrawer.tsx
... ... @@ -32,8 +32,8 @@ import { getTeacherCustomFieldNumber } from &#39;@/utils/kingdee&#39;;
32 32 import { getSalesCodeOptions } from '@/utils/order';
33 33 import { getDefaultString } from '@/utils/StringUtil';
34 34 import {
35   - DrawerForm,
36 35 FormListActionType,
  36 + ModalForm,
37 37 ProCard,
38 38 ProFormDatePicker,
39 39 ProFormDateTimePicker,
... ... @@ -760,14 +760,14 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
760 760  
761 761 return (
762 762 <>
763   - <DrawerForm<{
  763 + <ModalForm<{
764 764 isLocalData: any;
765 765 deleteSubOrderLists: any;
766 766 name: string;
767 767 company: string;
768 768 }>
769 769 open
770   - width="35%"
  770 + width={1000}
771 771 title={drawerTitle}
772 772 resize={{
773 773 onResize() {
... ... @@ -1913,6 +1913,9 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1913 1913 value: listMeta?.record?.materialId,
1914 1914 }}
1915 1915 fieldProps={{
  1916 + popupMatchSelectWidth: false,
  1917 + listHeight: 400,
  1918 + dropdownStyle: { width: '55%' },
1916 1919 filterOption() {
1917 1920 return true;
1918 1921 },
... ... @@ -2230,7 +2233,7 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
2230 2233 }}
2231 2234 actionRef={actionRef}
2232 2235 ></ProFormList>
2233   - </DrawerForm>
  2236 + </ModalForm>
2234 2237 {kingdeeCstomerModalVisible && (
2235 2238 <KingdeeCustomerModal
2236 2239 setVisible={setKingdeeCstomerModalVisible}
... ...
src/pages/Prepaid/components/PointsExchangeModal.tsx 0 → 100644
  1 +import { postIntegralExchangeIntegral } from '@/services/request';
  2 +import {
  3 + ModalForm,
  4 + ProFormInstance,
  5 + ProFormTextArea,
  6 +} from '@ant-design/pro-components';
  7 +import { Form, Input, message } from 'antd';
  8 +import React, { useEffect, useRef, useState } from 'react';
  9 +import '../index.less';
  10 +
  11 +interface PointsExchangeModalProps {
  12 + setVisible: (visible: boolean) => void;
  13 + userInfoObj: {
  14 + uid: string;
  15 + nickname?: string;
  16 + realName?: string;
  17 + [key: string]: any;
  18 + };
  19 + onClose: () => void;
  20 +}
  21 +
  22 +const PointsExchangeModal: React.FC<PointsExchangeModalProps> = ({
  23 + setVisible,
  24 + userInfoObj,
  25 + onClose,
  26 +}) => {
  27 + const [form] = Form.useForm<{ delta: string; remark: string }>();
  28 + const formRef = useRef<ProFormInstance>();
  29 + const uid = userInfoObj?.uid;
  30 + const userName = userInfoObj?.nickname || userInfoObj?.realName || '';
  31 + const [accountPoints, setAccountPoints] = useState<number>(0);
  32 +
  33 + useEffect(() => {
  34 + if (userInfoObj && userInfoObj.delta) {
  35 + setAccountPoints(Number(userInfoObj.delta) || 0);
  36 + }
  37 + }, [userInfoObj]);
  38 +
  39 + // Validate that delta is not greater than available points
  40 + const validateDelta = (rule: any, value: string) => {
  41 + const deltaValue = Number(value);
  42 + if (isNaN(deltaValue)) {
  43 + return Promise.reject('请输入有效的积分数值');
  44 + }
  45 + if (deltaValue <= 0) {
  46 + return Promise.reject('兑换积分必须大于0');
  47 + }
  48 + if (deltaValue > accountPoints) {
  49 + return Promise.reject('兑换积分不能大于账户积分');
  50 + }
  51 + return Promise.resolve();
  52 + };
  53 +
  54 + return (
  55 + <div className="prepaid-index">
  56 + <ModalForm<{
  57 + delta: string;
  58 + remark: string;
  59 + }>
  60 + width={600}
  61 + open
  62 + title="积分兑换"
  63 + form={form}
  64 + formRef={formRef}
  65 + autoFocusFirstInput
  66 + submitter={{
  67 + searchConfig: {
  68 + submitText: '确认兑换',
  69 + resetText: '取消',
  70 + },
  71 + }}
  72 + modalProps={{
  73 + destroyOnClose: true,
  74 + onCancel: () => {
  75 + setVisible(false);
  76 + },
  77 + }}
  78 + onFinish={async (values) => {
  79 + try {
  80 + // 调用积分兑换API
  81 + await postIntegralExchangeIntegral({
  82 + data: {
  83 + id: Number(uid), // 使用用户的uid作为id参数
  84 + delta: values.delta, // 将delta设为负数
  85 + remark: values.remark, // 兑换说明
  86 + relationEntityType: 'USER', // 关联实体类型
  87 + createByName: userName, // 使用昵称或真实姓名作为createByName
  88 + },
  89 + });
  90 +
  91 + message.success('积分兑换成功');
  92 + setVisible(false);
  93 + onClose();
  94 + return true;
  95 + } catch (error) {
  96 + console.error(error);
  97 + return false;
  98 + }
  99 + }}
  100 + onOpenChange={setVisible}
  101 + >
  102 + <Form.Item
  103 + label="兑换积分"
  104 + name="delta"
  105 + rules={[
  106 + { required: true, message: '请输入兑换积分' },
  107 + { validator: validateDelta },
  108 + ]}
  109 + >
  110 + <Input style={{ height: '30px' }} placeholder="请输入兑换积分数量" />
  111 + </Form.Item>
  112 +
  113 + <Form.Item
  114 + label="兑换说明"
  115 + name="remark"
  116 + rules={[{ required: true, message: '请输入兑换说明' }]}
  117 + >
  118 + <ProFormTextArea
  119 + style={{ height: '100px' }}
  120 + placeholder="请输入兑换说明"
  121 + />
  122 + </Form.Item>
  123 + </ModalForm>
  124 + </div>
  125 + );
  126 +};
  127 +
  128 +export default PointsExchangeModal;
... ...
src/pages/Prepaid/components/PointsExchangeRecordsModal.tsx 0 → 100644
  1 +import { postIntegralUserExchangeRecords } from '@/services';
  2 +import { formatDateTime } from '@/utils';
  3 +import { Button, DatePicker, Empty, Modal, Space, 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 + // Add date range state for each tab
  47 + const [exchangeStartTime, setExchangeStartTime] = useState<string | null>(
  48 + null,
  49 + );
  50 + const [exchangeEndTime, setExchangeEndTime] = useState<string | null>(null);
  51 + const [collectedStartTime, setCollectedStartTime] = useState<string | null>(
  52 + null,
  53 + );
  54 + const [collectedEndTime, setCollectedEndTime] = useState<string | null>(null);
  55 + const [pendingStartTime, setPendingStartTime] = useState<string | null>(null);
  56 + const [pendingEndTime, setPendingEndTime] = useState<string | null>(null);
  57 +
  58 + const uid = userInfoObj?.uid;
  59 + const phone = userInfoObj?.phone;
  60 +
  61 + // Function to fetch records data from API with date parameters
  62 + const fetchRecordsData = async (
  63 + params: {
  64 + startTime?: string | null;
  65 + endTime?: string | null;
  66 + tabKey?: string;
  67 + } = {},
  68 + ) => {
  69 + try {
  70 + setLoading(true);
  71 + const { startTime, endTime, tabKey } = params;
  72 +
  73 + // Prepare API request data
  74 + const requestData: any = {
  75 + id: Number(uid),
  76 + phone: phone,
  77 + };
  78 +
  79 + // Add date range if provided
  80 + if (startTime) requestData.startTime = startTime;
  81 + if (endTime) requestData.endTime = endTime;
  82 +
  83 + const response = await postIntegralUserExchangeRecords({
  84 + data: requestData,
  85 + });
  86 +
  87 + if (response && response.data) {
  88 + // Update only the data for the active tab if tabKey is provided
  89 + if (tabKey) {
  90 + setRecordsData((prevData) => {
  91 + const newData = { ...prevData };
  92 +
  93 + if (tabKey === '1') {
  94 + newData.exchangeRecords = response.data.exchangeRecords || [];
  95 + } else if (tabKey === '2') {
  96 + newData.collectedRecords = response.data.collectedRecords || [];
  97 + } else if (tabKey === '3') {
  98 + newData.pendingRecords = response.data.pendingRecords || [];
  99 + }
  100 +
  101 + return newData;
  102 + });
  103 + } else {
  104 + // Update all data if no specific tab is targeted
  105 + setRecordsData({
  106 + exchangeRecords: response.data.exchangeRecords || [],
  107 + collectedRecords: response.data.collectedRecords || [],
  108 + pendingRecords: response.data.pendingRecords || [],
  109 + });
  110 + }
  111 + }
  112 + } catch (error) {
  113 + console.error('Failed to fetch exchange records:', error);
  114 + } finally {
  115 + setLoading(false);
  116 + }
  117 + };
  118 +
  119 + // Fetch records data when component mounts
  120 + useEffect(() => {
  121 + if (uid || phone) {
  122 + fetchRecordsData();
  123 + }
  124 + }, [uid, phone]);
  125 +
  126 + // Exchange records columns
  127 + const exchangeRecordsColumns = [
  128 + {
  129 + title: '兑换日期',
  130 + dataIndex: 'createTime',
  131 + key: 'createTime',
  132 + width: 160,
  133 + render: (text: string) => formatDateTime(text),
  134 + },
  135 + {
  136 + title: '扣除积分',
  137 + dataIndex: 'delta',
  138 + key: 'delta',
  139 + width: 100,
  140 + render: (delta: number) => (
  141 + <span style={{ color: delta < 0 ? 'green' : 'red' }}>{delta}</span>
  142 + ),
  143 + },
  144 + {
  145 + title: '操作人',
  146 + dataIndex: 'createByName',
  147 + key: 'createByName',
  148 + width: 100,
  149 + render: (text: string | null) => text || '-',
  150 + },
  151 + {
  152 + title: '积分用途',
  153 + dataIndex: 'remark',
  154 + key: 'remark',
  155 + render: (text: string | null) => text || '-',
  156 + },
  157 + ];
  158 +
  159 + // Collected records columns
  160 + const collectedRecordsColumns = [
  161 + {
  162 + title: '订单号',
  163 + dataIndex: 'sourceId',
  164 + key: 'sourceId',
  165 + render: (text: string | null) => text || '-',
  166 + },
  167 + {
  168 + title: '领取积分',
  169 + dataIndex: 'delta',
  170 + key: 'delta',
  171 + render: (delta: number) => (
  172 + <span style={{ color: delta > 0 ? 'green' : 'red' }}>{delta}</span>
  173 + ),
  174 + },
  175 + {
  176 + title: '领取日期',
  177 + dataIndex: 'createTime',
  178 + key: 'createTime',
  179 + render: (text: string) => formatDateTime(text),
  180 + },
  181 + ];
  182 +
  183 + // Pending records columns
  184 + const pendingRecordsColumns = [
  185 + {
  186 + title: '订单号',
  187 + dataIndex: 'sourceId',
  188 + key: 'sourceId',
  189 + render: (text: string | null) => text || '-',
  190 + },
  191 + {
  192 + title: '领取积分',
  193 + dataIndex: 'delta',
  194 + key: 'delta',
  195 + render: (delta: number) => (
  196 + <span style={{ color: delta > 0 ? 'green' : 'red' }}>{delta}</span>
  197 + ),
  198 + },
  199 + {
  200 + title: '过期日期',
  201 + dataIndex: 'createTime',
  202 + key: 'createTime',
  203 + render: (text: string) => formatDateTime(text),
  204 + },
  205 + ];
  206 +
  207 + // Tab items
  208 + const tabItems = [
  209 + {
  210 + key: '1',
  211 + label: '兑换记录',
  212 + children: (
  213 + <>
  214 + <div
  215 + style={{ marginBottom: 16, display: 'flex', alignItems: 'center' }}
  216 + >
  217 + <span>兑换日期:</span>
  218 + <Space>
  219 + <DatePicker
  220 + placeholder="开始日期"
  221 + onChange={(date, dateString) =>
  222 + setExchangeStartTime(dateString)
  223 + }
  224 + style={{ width: 150 }}
  225 + />
  226 + <DatePicker
  227 + placeholder="结束日期"
  228 + onChange={(date, dateString) => setExchangeEndTime(dateString)}
  229 + style={{ width: 150 }}
  230 + />
  231 + <Button
  232 + type="primary"
  233 + onClick={() =>
  234 + fetchRecordsData({
  235 + startTime: exchangeStartTime,
  236 + endTime: exchangeEndTime,
  237 + tabKey: '1',
  238 + })
  239 + }
  240 + >
  241 + 查询
  242 + </Button>
  243 + </Space>
  244 + </div>
  245 + <Table
  246 + columns={exchangeRecordsColumns}
  247 + dataSource={recordsData.exchangeRecords.map((item, index) => ({
  248 + ...item,
  249 + key: `exchange-${index}`,
  250 + }))}
  251 + pagination={{ pageSize: 5 }}
  252 + loading={loading && activeTab === '1'}
  253 + locale={{
  254 + emptyText: <Empty description="暂无兑换记录" />,
  255 + }}
  256 + />
  257 + </>
  258 + ),
  259 + },
  260 + {
  261 + key: '2',
  262 + label: '已领取积分',
  263 + children: (
  264 + <>
  265 + <div
  266 + style={{ marginBottom: 16, display: 'flex', alignItems: 'center' }}
  267 + >
  268 + <span>领取日期:</span>
  269 + <Space>
  270 + <DatePicker
  271 + placeholder="开始日期"
  272 + onChange={(date, dateString) =>
  273 + setCollectedStartTime(dateString)
  274 + }
  275 + style={{ width: 150 }}
  276 + />
  277 + <DatePicker
  278 + placeholder="结束日期"
  279 + onChange={(date, dateString) => setCollectedEndTime(dateString)}
  280 + style={{ width: 150 }}
  281 + />
  282 + <Button
  283 + type="primary"
  284 + onClick={() =>
  285 + fetchRecordsData({
  286 + startTime: collectedStartTime,
  287 + endTime: collectedEndTime,
  288 + tabKey: '2',
  289 + })
  290 + }
  291 + >
  292 + 查询
  293 + </Button>
  294 + </Space>
  295 + </div>
  296 + <Table
  297 + columns={collectedRecordsColumns}
  298 + dataSource={recordsData.collectedRecords.map((item, index) => ({
  299 + ...item,
  300 + key: `collected-${index}`,
  301 + }))}
  302 + pagination={{ pageSize: 5 }}
  303 + loading={loading && activeTab === '2'}
  304 + locale={{
  305 + emptyText: <Empty description="暂无已领取积分记录" />,
  306 + }}
  307 + />
  308 + </>
  309 + ),
  310 + },
  311 + {
  312 + key: '3',
  313 + label: '待领取积分',
  314 + children: (
  315 + <>
  316 + <div
  317 + style={{ marginBottom: 16, display: 'flex', alignItems: 'center' }}
  318 + >
  319 + <span>过期日期:</span>
  320 + <Space>
  321 + <DatePicker
  322 + placeholder="开始日期"
  323 + onChange={(date, dateString) => setPendingStartTime(dateString)}
  324 + style={{ width: 150 }}
  325 + />
  326 + <DatePicker
  327 + placeholder="结束日期"
  328 + onChange={(date, dateString) => setPendingEndTime(dateString)}
  329 + style={{ width: 150 }}
  330 + />
  331 + <Button
  332 + type="primary"
  333 + onClick={() =>
  334 + fetchRecordsData({
  335 + startTime: pendingStartTime,
  336 + endTime: pendingEndTime,
  337 + tabKey: '3',
  338 + })
  339 + }
  340 + >
  341 + 查询
  342 + </Button>
  343 + </Space>
  344 + </div>
  345 + <Table
  346 + columns={pendingRecordsColumns}
  347 + dataSource={recordsData.pendingRecords.map((item, index) => ({
  348 + ...item,
  349 + key: `pending-${index}`,
  350 + }))}
  351 + pagination={{ pageSize: 5 }}
  352 + loading={loading && activeTab === '3'}
  353 + locale={{
  354 + emptyText: <Empty description="暂无待领取积分记录" />,
  355 + }}
  356 + />
  357 + </>
  358 + ),
  359 + },
  360 + ];
  361 +
  362 + return (
  363 + <Modal
  364 + open={true}
  365 + title="积分兑换记录"
  366 + width={1000}
  367 + onCancel={() => {
  368 + setVisible(false);
  369 + onClose();
  370 + }}
  371 + footer={null}
  372 + destroyOnClose
  373 + >
  374 + <Tabs
  375 + activeKey={activeTab}
  376 + onChange={(key) => setActiveTab(key)}
  377 + items={tabItems}
  378 + />
  379 + </Modal>
  380 + );
  381 +};
  382 +
  383 +export default PointsExchangeRecordsModal;
... ...
src/pages/Prepaid/constant.tsx
... ... @@ -187,6 +187,27 @@ export const ACCOUNT_COLUMNS = [
187 187 hideInSearch: true,
188 188 },
189 189 {
  190 + title: '账户积分',
  191 + dataIndex: 'delta',
  192 + key: 'delta',
  193 + valueType: 'number',
  194 + hideInSearch: true,
  195 + },
  196 + {
  197 + title: '待领取积分',
  198 + dataIndex: 'pendingDelta',
  199 + key: 'pendingDelta',
  200 + valueType: 'number',
  201 + hideInSearch: true,
  202 + },
  203 + {
  204 + title: '已扣除积分',
  205 + dataIndex: 'deleteDelta',
  206 + key: 'deleteDelta',
  207 + valueType: 'number',
  208 + hideInSearch: true,
  209 + },
  210 + {
190 211 title: '账号',
191 212 dataIndex: 'account',
192 213 key: 'account',
... ...
src/pages/Prepaid/index.tsx
... ... @@ -16,6 +16,8 @@ import React, { useRef, useState } from &#39;react&#39;;
16 16 import CheckModal from '../Order/Order/components/CheckModal';
17 17 import { CHECK_TYPE } from '../Order/constant';
18 18 import BalanceChangeRecordsModal from './components/BalanceChangeRecordsModal';
  19 +import PointsExchangeModal from './components/PointsExchangeModal';
  20 +import PointsExchangeRecordsModal from './components/PointsExchangeRecordsModal';
19 21 import RechargePrepaymentModal from './components/RechargePrepaymentModal';
20 22 import {
21 23 ACCOUNT_COLUMNS,
... ... @@ -23,18 +25,25 @@ import {
23 25 SALES_RECHARGE_PREPAYMENT_COLUMNS,
24 26 } from './constant';
25 27 import './index.less';
  28 +
26 29 const PrepaidPage = () => {
27 30 const prepaidActionRef = useRef<ActionType>();
28 31 const accountActionRef = useRef<ActionType>();
29 32 const [rechargePrepaymentModalVisible, setRechargePrepaymentModalVisible] =
30   - useState(false);
  33 + useState<boolean>(false);
31 34 const [currentOptPrepaymentObj, setCurrentOptPrepaymentObj] = useState(null);
32 35 const [currentOptUserObj, setCurrentOptUserObj] = useState(null);
33   - const [checkVisible, setCheckVisible] = useState(false);
  36 + const [checkVisible, setCheckVisible] = useState<boolean>(false);
34 37 const [
35 38 balanceChangeRecordsModalVisible,
36 39 setBalanceChangeRecordsModalVisible,
37   - ] = useState(false);
  40 + ] = useState<boolean>(false);
  41 + const [pointsExchangeModalVisible, setPointsExchangeModalVisible] =
  42 + useState<boolean>(false);
  43 + const [
  44 + pointsExchangeRecordsModalVisible,
  45 + setPointsExchangeRecordsModalVisible,
  46 + ] = useState<boolean>(false);
38 47  
39 48 const reloadPrepaidTable = () => {
40 49 prepaidActionRef.current?.reload();
... ... @@ -194,11 +203,24 @@ const PrepaidPage = () =&gt; {
194 203 valueType: 'option',
195 204 key: 'option',
196 205 fixed: 'right',
197   - width: 120,
  206 + width: 240,
198 207 render: (text, record) => {
199 208 let btns = [];
200 209 btns.push(
201 210 <Button
  211 + className="p-0 ml-2"
  212 + key="points"
  213 + type="link"
  214 + onClick={() => {
  215 + setCurrentOptUserObj(record);
  216 + setPointsExchangeModalVisible(true);
  217 + }}
  218 + >
  219 + 积分兑换
  220 + </Button>,
  221 + );
  222 + btns.push(
  223 + <Button
202 224 className="p-0"
203 225 key="view"
204 226 type="link"
... ... @@ -210,6 +232,19 @@ const PrepaidPage = () =&gt; {
210 232 消费记录
211 233 </Button>,
212 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 + );
213 248 return btns;
214 249 },
215 250 });
... ... @@ -377,6 +412,31 @@ const PrepaidPage = () =&gt; {
377 412 }}
378 413 />
379 414 )}
  415 +
  416 + {pointsExchangeModalVisible && currentOptUserObj && (
  417 + <PointsExchangeModal
  418 + setVisible={(val: boolean) => {
  419 + setPointsExchangeModalVisible(val);
  420 + }}
  421 + userInfoObj={currentOptUserObj}
  422 + onClose={() => {
  423 + setPointsExchangeModalVisible(false);
  424 + reloadAccountTable();
  425 + }}
  426 + />
  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 + )}
380 440 </div>
381 441 );
382 442 };
... ...
src/pages/ResearchGroup/components/PointsExchangeModal.tsx 0 → 100644
  1 +import { postIntegralExchangeIntegral } from '@/services/request';
  2 +import { getUserInfo } from '@/utils';
  3 +import {
  4 + ModalForm,
  5 + ProFormInstance,
  6 + ProFormTextArea,
  7 +} from '@ant-design/pro-components';
  8 +import { Form, Input, message } from 'antd';
  9 +import React, { useEffect, useRef, useState } from 'react';
  10 +import '../index.less';
  11 +
  12 +interface PointsExchangeModalProps {
  13 + setVisible: (visible: boolean) => void;
  14 + record: any;
  15 + onClose: () => void;
  16 +}
  17 +const userInfo = getUserInfo();
  18 +const PointsExchangeModal: React.FC<PointsExchangeModalProps> = ({
  19 + setVisible,
  20 + record,
  21 + onClose,
  22 +}) => {
  23 + const [form] = Form.useForm<{ delta: string; remark: string }>();
  24 + const formRef = useRef<ProFormInstance>();
  25 + const [accountPoints, setAccountPoints] = useState<number>(0);
  26 +
  27 + // Get account points from record
  28 + useEffect(() => {
  29 + if (record && record.delta) {
  30 + setAccountPoints(Number(record.delta) || 0);
  31 + }
  32 + }, [record]);
  33 +
  34 + // Validate that delta is not greater than available points
  35 + const validateDelta = (rule: any, value: string) => {
  36 + const deltaValue = Number(value);
  37 + if (isNaN(deltaValue)) {
  38 + return Promise.reject('请输入有效的积分数值');
  39 + }
  40 + if (deltaValue <= 0) {
  41 + return Promise.reject('兑换积分必须大于0');
  42 + }
  43 + if (deltaValue > accountPoints) {
  44 + return Promise.reject('兑换积分不能大于账户积分');
  45 + }
  46 + return Promise.resolve();
  47 + };
  48 +
  49 + return (
  50 + <div className="prepaid-index">
  51 + <ModalForm<{
  52 + delta: string;
  53 + remark: string;
  54 + }>
  55 + width={600}
  56 + open
  57 + title="确认兑换"
  58 + form={form}
  59 + formRef={formRef}
  60 + autoFocusFirstInput
  61 + submitter={{
  62 + searchConfig: {
  63 + submitText: '确认兑换',
  64 + resetText: '取消',
  65 + },
  66 + }}
  67 + modalProps={{
  68 + destroyOnClose: true,
  69 + onCancel: () => {
  70 + setVisible(false);
  71 + },
  72 + }}
  73 + onFinish={async (values) => {
  74 + try {
  75 + // 调用积分兑换API
  76 + await postIntegralExchangeIntegral({
  77 + data: {
  78 + id: Number(record.id),
  79 + delta: Number(values.delta),
  80 + remark: values.remark,
  81 + relationEntityType: 'RESEARCH_GROUP',
  82 + createByName: userInfo?.username,
  83 + },
  84 + });
  85 +
  86 + message.success('积分兑换成功');
  87 + setVisible(false);
  88 + onClose();
  89 + return true;
  90 + } catch (error) {
  91 + console.error(error);
  92 + return false;
  93 + }
  94 + }}
  95 + onOpenChange={setVisible}
  96 + >
  97 + <Form.Item
  98 + label="兑换积分"
  99 + name="delta"
  100 + rules={[
  101 + { required: true, message: '请输入兑换积分' },
  102 + { validator: validateDelta },
  103 + ]}
  104 + >
  105 + <Input style={{ height: '30px' }} placeholder="请输入兑换积分数量" />
  106 + </Form.Item>
  107 +
  108 + <Form.Item
  109 + label="兑换说明"
  110 + name="remark"
  111 + rules={[{ required: true, message: '请输入兑换说明' }]}
  112 + >
  113 + <ProFormTextArea
  114 + style={{ height: '100px' }}
  115 + placeholder="请输入兑换说明"
  116 + />
  117 + </Form.Item>
  118 + </ModalForm>
  119 + </div>
  120 + );
  121 +};
  122 +
  123 +export default PointsExchangeModal;
... ...
src/pages/ResearchGroup/components/PointsExchangeRecordsModal.tsx 0 → 100644
  1 +import { postIntegralGroupExchangeRecords } from '@/services/request';
  2 +import { ModalForm, ProTable } from '@ant-design/pro-components';
  3 +import { Button, DatePicker, Space, Tabs, message } from 'antd';
  4 +import dayjs from 'dayjs';
  5 +import React, { useState } from 'react';
  6 +import '../index.less';
  7 +
  8 +interface PointsExchangeRecordsModalProps {
  9 + setVisible: (visible: boolean) => void;
  10 + record: any;
  11 +}
  12 +
  13 +// Define a type for the records data
  14 +type RecordsDataType = {
  15 + exchangeRecords: any[];
  16 + collectedRecords: any[];
  17 + pendingRecords: any[];
  18 +};
  19 +
  20 +const PointsExchangeRecordsModal: React.FC<PointsExchangeRecordsModalProps> = ({
  21 + setVisible,
  22 + record,
  23 +}) => {
  24 + const [activeTab, setActiveTab] = useState('1');
  25 +
  26 + // Separate date ranges for each tab
  27 + const [exchangeDateRange, setExchangeDateRange] = useState<any[]>([]);
  28 + const [collectedDateRange, setCollectedDateRange] = useState<any[]>([]);
  29 + const [pendingDateRange, setPendingDateRange] = useState<any[]>([]);
  30 +
  31 + const [loading, setLoading] = useState(false);
  32 + const [recordsData, setRecordsData] = useState<RecordsDataType>({
  33 + exchangeRecords: [], // 兑换记录
  34 + collectedRecords: [], // 已领取积分
  35 + pendingRecords: [], // 待领取积分
  36 + });
  37 +
  38 + // Function to fetch records data from API with date parameters
  39 + const fetchRecordsData = async (params: {
  40 + startTime?: string | null;
  41 + endTime?: string | null;
  42 + tabKey: string;
  43 + }) => {
  44 + try {
  45 + setLoading(true);
  46 + const { startTime, endTime, tabKey } = params;
  47 +
  48 + // Prepare API request data
  49 + const requestDto: any = {
  50 + id: Number(record.id),
  51 + };
  52 +
  53 + // Add date range if provided
  54 + if (startTime) requestDto.startTime = startTime;
  55 + if (endTime) requestDto.endTime = endTime;
  56 +
  57 + console.log(`Fetching data for tab: ${tabKey}`);
  58 +
  59 + // Use postIntegralGroupExchangeRecords instead of postIntegralUserExchangeRecords
  60 + const response = await postIntegralGroupExchangeRecords({
  61 + data: requestDto,
  62 + });
  63 +
  64 + if (response && response.data) {
  65 + // Update only the data for the active tab
  66 + setRecordsData((prevData: RecordsDataType) => {
  67 + const newData = { ...prevData };
  68 +
  69 + switch (tabKey) {
  70 + case '1': // 兑换记录
  71 + newData.exchangeRecords = response.data.exchangeRecords || [];
  72 + break;
  73 + case '2': // 已领取积分
  74 + newData.collectedRecords = response.data.collectedRecords || [];
  75 + break;
  76 + case '3': // 待领取积分
  77 + newData.pendingRecords = response.data.pendingRecords || [];
  78 + break;
  79 + }
  80 +
  81 + return newData;
  82 + });
  83 + } else {
  84 + message.error('获取积分记录失败');
  85 + }
  86 + } catch (error) {
  87 + console.error(error);
  88 + message.error('获取积分记录失败');
  89 + } finally {
  90 + setLoading(false);
  91 + }
  92 + };
  93 +
  94 + // Initial data fetch for all tabs
  95 + React.useEffect(() => {
  96 + const loadAllTabs = async () => {
  97 + try {
  98 + setLoading(true);
  99 + const requestDto = {
  100 + id: Number(record.id),
  101 + };
  102 +
  103 + const response = await postIntegralGroupExchangeRecords({
  104 + data: requestDto,
  105 + });
  106 +
  107 + if (response && response.data) {
  108 + setRecordsData({
  109 + exchangeRecords: response.data.exchangeRecords || [],
  110 + collectedRecords: response.data.collectedRecords || [],
  111 + pendingRecords: response.data.pendingRecords || [],
  112 + });
  113 + } else {
  114 + message.error('获取积分记录失败');
  115 + }
  116 + } catch (error) {
  117 + console.error(error);
  118 + message.error('获取积分记录失败');
  119 + } finally {
  120 + setLoading(false);
  121 + }
  122 + };
  123 +
  124 + loadAllTabs();
  125 + }, [record.id]);
  126 +
  127 + const handleTabChange = (key: string) => {
  128 + setActiveTab(key);
  129 + };
  130 +
  131 + // Get current date range based on active tab
  132 + const getCurrentDateRange = () => {
  133 + switch (activeTab) {
  134 + case '1':
  135 + return exchangeDateRange;
  136 + case '2':
  137 + return collectedDateRange;
  138 + case '3':
  139 + return pendingDateRange;
  140 + default:
  141 + return [];
  142 + }
  143 + };
  144 +
  145 + // Set date range for current tab
  146 + const handleDateRangeChange = (dates: any) => {
  147 + switch (activeTab) {
  148 + case '1':
  149 + setExchangeDateRange(dates);
  150 + break;
  151 + case '2':
  152 + setCollectedDateRange(dates);
  153 + break;
  154 + case '3':
  155 + setPendingDateRange(dates);
  156 + break;
  157 + }
  158 + };
  159 +
  160 + const handleSearchClick = () => {
  161 + const dateRange = getCurrentDateRange();
  162 + // Only get the dates that are actually selected
  163 + const startTime = dateRange?.[0]
  164 + ? dayjs(dateRange[0]).format('YYYY-MM-DD')
  165 + : null;
  166 + const endTime = dateRange?.[1]
  167 + ? dayjs(dateRange[1]).format('YYYY-MM-DD')
  168 + : null;
  169 +
  170 + fetchRecordsData({
  171 + startTime,
  172 + endTime,
  173 + tabKey: activeTab,
  174 + });
  175 + };
  176 +
  177 + const handleClearClick = () => {
  178 + // Clear date range for current tab
  179 + switch (activeTab) {
  180 + case '1':
  181 + setExchangeDateRange([]);
  182 + break;
  183 + case '2':
  184 + setCollectedDateRange([]);
  185 + break;
  186 + case '3':
  187 + setPendingDateRange([]);
  188 + break;
  189 + }
  190 +
  191 + // Fetch data without date filters
  192 + fetchRecordsData({
  193 + startTime: null,
  194 + endTime: null,
  195 + tabKey: activeTab,
  196 + });
  197 + };
  198 +
  199 + // 兑换记录表格列定义
  200 + const exchangeColumns = [
  201 + {
  202 + title: '兑换日期',
  203 + dataIndex: 'createTime',
  204 + key: 'createTime',
  205 + width: 30,
  206 + },
  207 + {
  208 + title: '扣除积分',
  209 + dataIndex: 'delta',
  210 + key: 'delta',
  211 + width: 20,
  212 + },
  213 + {
  214 + title: '操作人',
  215 + dataIndex: 'createByName',
  216 + key: 'createByName',
  217 + width: 20,
  218 + },
  219 + {
  220 + title: '积分用途',
  221 + dataIndex: 'remark',
  222 + key: 'remark',
  223 + width: 100,
  224 + },
  225 + ];
  226 +
  227 + // 已领取积分表格列定义
  228 + const collectedColumns = [
  229 + {
  230 + title: '订单号',
  231 + dataIndex: 'sourceId',
  232 + key: 'sourceId',
  233 + },
  234 + {
  235 + title: '领取积分',
  236 + dataIndex: 'delta',
  237 + key: 'delta',
  238 + },
  239 + {
  240 + title: '领取日期',
  241 + dataIndex: 'createTime',
  242 + key: 'createTime',
  243 + },
  244 + ];
  245 +
  246 + // 待领取积分表格列定义
  247 + const pendingColumns = [
  248 + {
  249 + title: '订单号',
  250 + dataIndex: 'sourceId',
  251 + key: 'sourceId',
  252 + },
  253 + {
  254 + title: '领取积分',
  255 + dataIndex: 'delta',
  256 + key: 'delta',
  257 + },
  258 + {
  259 + title: '过期日期',
  260 + dataIndex: 'createTime',
  261 + key: 'createTime',
  262 + },
  263 + ];
  264 +
  265 + // Render date picker and search buttons for current tab
  266 + const renderDateRangePicker = () => {
  267 + return (
  268 + <Space style={{ marginBottom: 16 }}>
  269 + <DatePicker.RangePicker
  270 + value={getCurrentDateRange()}
  271 + onChange={handleDateRangeChange}
  272 + allowEmpty={[true, true]}
  273 + />
  274 + <Button type="primary" onClick={handleSearchClick}>
  275 + 搜索
  276 + </Button>
  277 + <Button onClick={handleClearClick}>重置</Button>
  278 + </Space>
  279 + );
  280 + };
  281 +
  282 + return (
  283 + <div className="prepaid-index">
  284 + <ModalForm
  285 + width={1000}
  286 + open
  287 + title="积分兑换记录"
  288 + submitter={false}
  289 + modalProps={{
  290 + destroyOnClose: true,
  291 + onCancel: () => {
  292 + setVisible(false);
  293 + },
  294 + }}
  295 + >
  296 + <Tabs activeKey={activeTab} onChange={handleTabChange}>
  297 + <Tabs.TabPane tab="兑换记录" key="1">
  298 + {renderDateRangePicker()}
  299 + <ProTable
  300 + headerTitle={false}
  301 + search={false}
  302 + options={false}
  303 + pagination={{
  304 + pageSize: 10,
  305 + }}
  306 + loading={loading && activeTab === '1'}
  307 + dataSource={recordsData.exchangeRecords}
  308 + columns={exchangeColumns}
  309 + rowKey="id"
  310 + />
  311 + </Tabs.TabPane>
  312 + <Tabs.TabPane tab="已领取积分" key="2">
  313 + {renderDateRangePicker()}
  314 + <ProTable
  315 + headerTitle={false}
  316 + search={false}
  317 + options={false}
  318 + pagination={{
  319 + pageSize: 10,
  320 + }}
  321 + loading={loading && activeTab === '2'}
  322 + dataSource={recordsData.collectedRecords}
  323 + columns={collectedColumns}
  324 + rowKey="id"
  325 + />
  326 + </Tabs.TabPane>
  327 + <Tabs.TabPane tab="待领取积分" key="3">
  328 + {renderDateRangePicker()}
  329 + <ProTable
  330 + headerTitle={false}
  331 + search={false}
  332 + options={false}
  333 + pagination={{
  334 + pageSize: 10,
  335 + }}
  336 + loading={loading && activeTab === '3'}
  337 + dataSource={recordsData.pendingRecords}
  338 + columns={pendingColumns}
  339 + rowKey="id"
  340 + />
  341 + </Tabs.TabPane>
  342 + </Tabs>
  343 + </ModalForm>
  344 + </div>
  345 + );
  346 +};
  347 +
  348 +export default PointsExchangeRecordsModal;
... ...
src/pages/ResearchGroup/constant.tsx
1   -import { enumToProTableEnumValue } from '@/utils';
2   -
  1 +import { postServiceConstListResearchGroupsStatus } from '@/services';
  2 +import { enumToProTableEnumValue, enumToSelect } from '@/utils';
  3 +import { MessageTwoTone } from '@ant-design/icons';
  4 +import { Space, Tooltip } from 'antd';
3 5 export const AUDIT_STATUS_OPTIONS = {
4 6 CREATED: '未审核',
5 7 AUDIT_PASS: '审核通过',
... ... @@ -53,6 +55,59 @@ export const RESEARCH_GROUP_COLUMNS = [
53 55 hideInSearch: true,
54 56 },
55 57 {
  58 + title: '账户积分',
  59 + dataIndex: 'delta',
  60 + key: 'delta',
  61 + valueType: 'number',
  62 + hideInSearch: true,
  63 + },
  64 + {
  65 + title: '待领取积分',
  66 + dataIndex: 'pendingDelta',
  67 + key: 'pendingDelta',
  68 + valueType: 'number',
  69 + hideInSearch: true,
  70 + },
  71 + {
  72 + title: '已扣除积分',
  73 + dataIndex: 'deleteDelta',
  74 + key: 'deleteDelta',
  75 + valueType: 'number',
  76 + hideInSearch: true,
  77 + },
  78 + {
  79 + title: '状态',
  80 + dataIndex: 'statusText',
  81 + key: 'statusText',
  82 + hideInSearch: true,
  83 + render: (_, record) => {
  84 + console.log('1111' + JSON.stringify(record));
  85 + return (
  86 + <>
  87 + <Space>
  88 + {record.statusText}
  89 + {record.statusNotes && (
  90 + <Tooltip title={record.statusNotes}>
  91 + <MessageTwoTone />
  92 + </Tooltip>
  93 + )}
  94 + </Space>
  95 + </>
  96 + );
  97 + },
  98 + },
  99 + {
  100 + title: '状态',
  101 + dataIndex: 'status',
  102 + key: 'status',
  103 + valueType: 'select',
  104 + request: async () => {
  105 + const groupStatus = await postServiceConstListResearchGroupsStatus();
  106 + return enumToSelect(groupStatus.data);
  107 + },
  108 + hideInTable: true,
  109 + },
  110 + {
56 111 title: '预存手机号',
57 112 dataIndex: 'accountPhone',
58 113 key: 'accountPhone',
... ...
src/pages/ResearchGroup/index.tsx
... ... @@ -29,6 +29,8 @@ import {
29 29 import React, { useRef, useState } from 'react';
30 30 import AuditModal from './components/AuditModal';
31 31 import ImportModal from './components/ImportModal';
  32 +import PointsExchangeModal from './components/PointsExchangeModal';
  33 +import PointsExchangeRecordsModal from './components/PointsExchangeRecordsModal';
32 34 import ResearchGroupAddModal from './components/ResearchGroupAddModal';
33 35 import ResearchGroupMemberRequestAddModal from './components/ResearchGroupMemberRequestAddModal';
34 36 import {
... ... @@ -60,6 +62,13 @@ const PrepaidPage = () =&gt; {
60 62 const [accountInfoLoading, setAccountInfoLoading] = useState(false);
61 63 const [perms, setPerms] = useState<string[]>([]);
62 64 const [optRecordId, setOptRecordId] = useState<any>(null);
  65 + const [pointsExchangeModalVisible, setPointsExchangeModalVisible] =
  66 + useState<boolean>(false);
  67 + const [
  68 + pointsExchangeRecordsModalVisible,
  69 + setPointsExchangeRecordsModalVisible,
  70 + ] = useState<boolean>(false);
  71 + const [currentRecord, setCurrentRecord] = useState<any>(null);
63 72  
64 73 const reloadResearchGroupTable = () => {
65 74 researchGroupActionRef.current?.reload();
... ... @@ -306,9 +315,39 @@ const PrepaidPage = () =&gt; {
306 315 valueType: 'option',
307 316 key: 'option',
308 317 fixed: 'right',
309   - width: 120,
  318 + width: 240,
310 319 render: (text, record) => {
311 320 let btns = [];
  321 +
  322 + // Add Points Exchange button if there are accounts
  323 + btns.push(
  324 + <Button
  325 + className="p-0"
  326 + key="points-exchange"
  327 + type="link"
  328 + onClick={() => {
  329 + setCurrentRecord(record);
  330 + setPointsExchangeModalVisible(true);
  331 + }}
  332 + >
  333 + 积分兑换
  334 + </Button>,
  335 + );
  336 +
  337 + btns.push(
  338 + <Button
  339 + className="p-0"
  340 + key="points-records"
  341 + type="link"
  342 + onClick={() => {
  343 + setCurrentRecord(record);
  344 + setPointsExchangeRecordsModalVisible(true);
  345 + }}
  346 + >
  347 + 积分兑换记录
  348 + </Button>,
  349 + );
  350 +
312 351 if (perms?.includes('modify')) {
313 352 btns.push(
314 353 <Button
... ... @@ -794,6 +833,24 @@ const PrepaidPage = () =&gt; {
794 833 }}
795 834 />
796 835 )}
  836 +
  837 + {pointsExchangeModalVisible && currentRecord && (
  838 + <PointsExchangeModal
  839 + setVisible={setPointsExchangeModalVisible}
  840 + record={currentRecord}
  841 + onClose={() => {
  842 + reloadResearchGroupTable();
  843 + }}
  844 + />
  845 + )}
  846 +
  847 + {pointsExchangeRecordsModalVisible && currentRecord && (
  848 + <PointsExchangeRecordsModal
  849 + setVisible={setPointsExchangeRecordsModalVisible}
  850 + record={currentRecord}
  851 + onClose={() => {}}
  852 + />
  853 + )}
797 854 </div>
798 855 );
799 856 };
... ...
src/services/definition.ts
... ... @@ -1521,36 +1521,70 @@ export interface Entry {
1521 1521 unEmpInsuranceC?: string;
1522 1522 }
1523 1523  
1524   -export interface File {
1525   - absolute?: boolean;
1526   - absoluteFile?: File;
1527   - absolutePath?: string;
1528   - canonicalFile?: File;
1529   - canonicalPath?: string;
1530   - directory?: boolean;
1531   - executable?: boolean;
1532   - file?: boolean;
1533   - /** @format int64 */
1534   - freeSpace?: number;
1535   - hidden?: boolean;
1536   - /** @format int64 */
1537   - lastModified?: number;
1538   - name?: string;
1539   - parent?: string;
1540   - parentFile?: File;
1541   - path?: string;
1542   - readable?: boolean;
1543   - /** @format int64 */
1544   - totalSpace?: number;
  1524 +export interface ExchangeIntegralDto {
  1525 + createByName?: string;
  1526 + delta?: number;
1545 1527 /** @format int64 */
1546   - usableSpace?: number;
1547   - writable?: boolean;
  1528 + id?: number;
  1529 + relationEntityType?: string;
  1530 + remark?: string;
  1531 +}
  1532 +
  1533 +export interface ExchangeRecordsRequestDto {
  1534 + createByName?: string;
  1535 + createByNameLike?: string;
  1536 + /** @format date-time */
  1537 + createTimeGe?: string;
  1538 + /** @format date-time */
  1539 + createTimeLe?: string;
  1540 + /** @format int32 */
  1541 + current?: number;
  1542 + /** @format int32 */
  1543 + end?: number;
  1544 + /** @format date-time */
  1545 + endTime?: string;
  1546 + /** @format int32 */
  1547 + id?: number;
  1548 + /** @format int32 */
  1549 + pageSize?: number;
  1550 + phone?: string;
  1551 + /** @format int32 */
  1552 + start?: number;
  1553 + /** @format date-time */
  1554 + startTime?: string;
  1555 + /** @format int32 */
  1556 + total?: number;
1548 1557 }
1549 1558  
1550 1559 export interface FilePathDto {
1551 1560 url?: string;
1552 1561 }
1553 1562  
  1563 +export interface GroupExchangeRecordsRequestDto {
  1564 + createByName?: string;
  1565 + createByNameLike?: string;
  1566 + /** @format date-time */
  1567 + createTimeGe?: string;
  1568 + /** @format date-time */
  1569 + createTimeLe?: string;
  1570 + /** @format int32 */
  1571 + current?: number;
  1572 + /** @format int32 */
  1573 + end?: number;
  1574 + /** @format date-time */
  1575 + endTime?: string;
  1576 + /** @format int64 */
  1577 + id?: number;
  1578 + /** @format int32 */
  1579 + pageSize?: number;
  1580 + /** @format int32 */
  1581 + start?: number;
  1582 + /** @format date-time */
  1583 + startTime?: string;
  1584 + /** @format int32 */
  1585 + total?: number;
  1586 +}
  1587 +
1554 1588 export type InputStream = any;
1555 1589  
1556 1590 export interface InventoryMaterialStockReq {
... ... @@ -3727,6 +3761,16 @@ export interface ResearchGroupEditRequest {
3727 3761 createTime?: string;
3728 3762 /**
3729 3763 * @description
  3764 + * 已扣除积分
  3765 + */
  3766 + deleteDelta?: number;
  3767 + /**
  3768 + * @description
  3769 + * 账户积分
  3770 + */
  3771 + delta?: number;
  3772 + /**
  3773 + * @description
3730 3774 * 课题组名称
3731 3775 */
3732 3776 groupName?: string;
... ... @@ -3744,6 +3788,11 @@ export interface ResearchGroupEditRequest {
3744 3788 logicDelete?: boolean;
3745 3789 members?: Array<ResearchGroupMembers>;
3746 3790 paths?: Array<string>;
  3791 + /**
  3792 + * @description
  3793 + * 待领取积分
  3794 + */
  3795 + pendingDelta?: number;
3747 3796 requestStatus?: string;
3748 3797 /**
3749 3798 * @description
... ... @@ -4062,6 +4111,16 @@ export interface ResearchGroupsDTO {
4062 4111 createTime?: string;
4063 4112 /**
4064 4113 * @description
  4114 + * 已扣除积分
  4115 + */
  4116 + deleteDelta?: number;
  4117 + /**
  4118 + * @description
  4119 + * 账户积分
  4120 + */
  4121 + delta?: number;
  4122 + /**
  4123 + * @description
4065 4124 * 课题组名称
4066 4125 */
4067 4126 groupName?: string;
... ... @@ -4079,6 +4138,11 @@ export interface ResearchGroupsDTO {
4079 4138 logicDelete?: boolean;
4080 4139 members?: Array<ResearchGroupMembers>;
4081 4140 paths?: Array<string>;
  4141 + /**
  4142 + * @description
  4143 + * 待领取积分
  4144 + */
  4145 + pendingDelta?: number;
4082 4146 requestStatus?: string;
4083 4147 /**
4084 4148 * @description
... ... @@ -4107,7 +4171,7 @@ export interface ResetPwdVO {
4107 4171  
4108 4172 export interface Resource {
4109 4173 description?: string;
4110   - file?: File;
  4174 + file?: TsgFile;
4111 4175 filename?: string;
4112 4176 inputStream?: InputStream;
4113 4177 open?: boolean;
... ... @@ -4815,6 +4879,32 @@ export interface CompanyInfo {
4815 4879 taxIdIsNotNull?: boolean;
4816 4880 }
4817 4881  
  4882 +export interface TsgFile {
  4883 + absolute?: boolean;
  4884 + absoluteFile?: TsgFile;
  4885 + absolutePath?: string;
  4886 + canonicalFile?: TsgFile;
  4887 + canonicalPath?: string;
  4888 + directory?: boolean;
  4889 + executable?: boolean;
  4890 + file?: boolean;
  4891 + /** @format int64 */
  4892 + freeSpace?: number;
  4893 + hidden?: boolean;
  4894 + /** @format int64 */
  4895 + lastModified?: number;
  4896 + name?: string;
  4897 + parent?: string;
  4898 + parentFile?: TsgFile;
  4899 + path?: string;
  4900 + readable?: boolean;
  4901 + /** @format int64 */
  4902 + totalSpace?: number;
  4903 + /** @format int64 */
  4904 + usableSpace?: number;
  4905 + writable?: boolean;
  4906 +}
  4907 +
4818 4908 export interface InvoiceDetail {
4819 4909 createByName?: string;
4820 4910 /** @format date-time */
... ...
src/services/request.ts
... ... @@ -56,7 +56,10 @@ import type {
56 56 DistrictDo,
57 57 DistrictSearchDo,
58 58 Dto,
  59 + ExchangeIntegralDto,
  60 + ExchangeRecordsRequestDto,
59 61 FeedbackRegistrationDTO,
  62 + GroupExchangeRecordsRequestDto,
60 63 InventoryMaterialStockReq,
61 64 InvoiceBatchDownloadDto,
62 65 InvoiceDto,
... ... @@ -71,7 +74,6 @@ import type {
71 74 MeasureUnitListRes,
72 75 MergeIntegralDto,
73 76 MessageQueryDTO,
74   - ModelAndView,
75 77 OrderAddVO,
76 78 OrderAuditLogQueryVO,
77 79 OrderBaseInfoQueryVO,
... ... @@ -3830,7 +3832,9 @@ export interface GetErrorResponse {
3830 3832 * @description
3831 3833 * OK
3832 3834 */
3833   - 200: ModelAndView;
  3835 + 200: {
  3836 + [propertyName: string]: any;
  3837 + };
3834 3838 /**
3835 3839 * @description
3836 3840 * Unauthorized
... ... @@ -3851,9 +3855,9 @@ export interface GetErrorResponse {
3851 3855 export type GetErrorResponseSuccess = GetErrorResponse[200];
3852 3856 /**
3853 3857 * @description
3854   - * errorHtml
  3858 + * error
3855 3859 * @tags basic-error-controller
3856   - * @produces text/html
  3860 + * @produces *
3857 3861 */
3858 3862 export const getError = /* #__PURE__ */ (() => {
3859 3863 const method = 'get';
... ... @@ -3877,7 +3881,9 @@ export interface PutErrorResponse {
3877 3881 * @description
3878 3882 * OK
3879 3883 */
3880   - 200: ModelAndView;
  3884 + 200: {
  3885 + [propertyName: string]: any;
  3886 + };
3881 3887 /**
3882 3888 * @description
3883 3889 * Created
... ... @@ -3903,9 +3909,9 @@ export interface PutErrorResponse {
3903 3909 export type PutErrorResponseSuccess = PutErrorResponse[200];
3904 3910 /**
3905 3911 * @description
3906   - * errorHtml
  3912 + * error
3907 3913 * @tags basic-error-controller
3908   - * @produces text/html
  3914 + * @produces *
3909 3915 * @consumes application/json
3910 3916 */
3911 3917 export const putError = /* #__PURE__ */ (() => {
... ... @@ -3930,7 +3936,9 @@ export interface PostErrorResponse {
3930 3936 * @description
3931 3937 * OK
3932 3938 */
3933   - 200: ModelAndView;
  3939 + 200: {
  3940 + [propertyName: string]: any;
  3941 + };
3934 3942 /**
3935 3943 * @description
3936 3944 * Created
... ... @@ -3956,9 +3964,9 @@ export interface PostErrorResponse {
3956 3964 export type PostErrorResponseSuccess = PostErrorResponse[200];
3957 3965 /**
3958 3966 * @description
3959   - * errorHtml
  3967 + * error
3960 3968 * @tags basic-error-controller
3961   - * @produces text/html
  3969 + * @produces *
3962 3970 * @consumes application/json
3963 3971 */
3964 3972 export const postError = /* #__PURE__ */ (() => {
... ... @@ -3983,7 +3991,9 @@ export interface DeleteErrorResponse {
3983 3991 * @description
3984 3992 * OK
3985 3993 */
3986   - 200: ModelAndView;
  3994 + 200: {
  3995 + [propertyName: string]: any;
  3996 + };
3987 3997 /**
3988 3998 * @description
3989 3999 * No Content
... ... @@ -4004,9 +4014,9 @@ export interface DeleteErrorResponse {
4004 4014 export type DeleteErrorResponseSuccess = DeleteErrorResponse[200];
4005 4015 /**
4006 4016 * @description
4007   - * errorHtml
  4017 + * error
4008 4018 * @tags basic-error-controller
4009   - * @produces text/html
  4019 + * @produces *
4010 4020 */
4011 4021 export const deleteError = /* #__PURE__ */ (() => {
4012 4022 const method = 'delete';
... ... @@ -4030,7 +4040,9 @@ export interface OptionsErrorResponse {
4030 4040 * @description
4031 4041 * OK
4032 4042 */
4033   - 200: ModelAndView;
  4043 + 200: {
  4044 + [propertyName: string]: any;
  4045 + };
4034 4046 /**
4035 4047 * @description
4036 4048 * No Content
... ... @@ -4051,9 +4063,9 @@ export interface OptionsErrorResponse {
4051 4063 export type OptionsErrorResponseSuccess = OptionsErrorResponse[200];
4052 4064 /**
4053 4065 * @description
4054   - * errorHtml
  4066 + * error
4055 4067 * @tags basic-error-controller
4056   - * @produces text/html
  4068 + * @produces *
4057 4069 * @consumes application/json
4058 4070 */
4059 4071 export const optionsError = /* #__PURE__ */ (() => {
... ... @@ -4078,7 +4090,9 @@ export interface HeadErrorResponse {
4078 4090 * @description
4079 4091 * OK
4080 4092 */
4081   - 200: ModelAndView;
  4093 + 200: {
  4094 + [propertyName: string]: any;
  4095 + };
4082 4096 /**
4083 4097 * @description
4084 4098 * No Content
... ... @@ -4099,9 +4113,9 @@ export interface HeadErrorResponse {
4099 4113 export type HeadErrorResponseSuccess = HeadErrorResponse[200];
4100 4114 /**
4101 4115 * @description
4102   - * errorHtml
  4116 + * error
4103 4117 * @tags basic-error-controller
4104   - * @produces text/html
  4118 + * @produces *
4105 4119 * @consumes application/json
4106 4120 */
4107 4121 export const headError = /* #__PURE__ */ (() => {
... ... @@ -4126,7 +4140,9 @@ export interface PatchErrorResponse {
4126 4140 * @description
4127 4141 * OK
4128 4142 */
4129   - 200: ModelAndView;
  4143 + 200: {
  4144 + [propertyName: string]: any;
  4145 + };
4130 4146 /**
4131 4147 * @description
4132 4148 * No Content
... ... @@ -4147,9 +4163,9 @@ export interface PatchErrorResponse {
4147 4163 export type PatchErrorResponseSuccess = PatchErrorResponse[200];
4148 4164 /**
4149 4165 * @description
4150   - * errorHtml
  4166 + * error
4151 4167 * @tags basic-error-controller
4152   - * @produces text/html
  4168 + * @produces *
4153 4169 * @consumes application/json
4154 4170 */
4155 4171 export const patchError = /* #__PURE__ */ (() => {
... ... @@ -4238,6 +4254,77 @@ export const postFileDirectDown = /* #__PURE__ */ (() =&gt; {
4238 4254 return request;
4239 4255 })();
4240 4256  
  4257 +/** @description request parameter type for postIntegralExchangeIntegral */
  4258 +export interface PostIntegralExchangeIntegralOption {
  4259 + /**
  4260 + * @description
  4261 + * dto
  4262 + */
  4263 + body: {
  4264 + /**
  4265 + @description
  4266 + dto */
  4267 + dto: ExchangeIntegralDto;
  4268 + };
  4269 +}
  4270 +
  4271 +/** @description response type for postIntegralExchangeIntegral */
  4272 +export interface PostIntegralExchangeIntegralResponse {
  4273 + /**
  4274 + * @description
  4275 + * OK
  4276 + */
  4277 + 200: ServerResult;
  4278 + /**
  4279 + * @description
  4280 + * Created
  4281 + */
  4282 + 201: any;
  4283 + /**
  4284 + * @description
  4285 + * Unauthorized
  4286 + */
  4287 + 401: any;
  4288 + /**
  4289 + * @description
  4290 + * Forbidden
  4291 + */
  4292 + 403: any;
  4293 + /**
  4294 + * @description
  4295 + * Not Found
  4296 + */
  4297 + 404: any;
  4298 +}
  4299 +
  4300 +export type PostIntegralExchangeIntegralResponseSuccess =
  4301 + PostIntegralExchangeIntegralResponse[200];
  4302 +/**
  4303 + * @description
  4304 + * 积分兑换
  4305 + * @tags 积分接口
  4306 + * @produces *
  4307 + * @consumes application/json
  4308 + */
  4309 +export const postIntegralExchangeIntegral = /* #__PURE__ */ (() => {
  4310 + const method = 'post';
  4311 + const url = '/integral/exchangeIntegral';
  4312 + function request(
  4313 + option: PostIntegralExchangeIntegralOption,
  4314 + ): Promise<PostIntegralExchangeIntegralResponseSuccess> {
  4315 + return requester(request.url, {
  4316 + method: request.method,
  4317 + ...option,
  4318 + }) as unknown as Promise<PostIntegralExchangeIntegralResponseSuccess>;
  4319 + }
  4320 +
  4321 + /** http method */
  4322 + request.method = method;
  4323 + /** request url */
  4324 + request.url = url;
  4325 + return request;
  4326 +})();
  4327 +
4241 4328 /** @description response type for postIntegralGetIntegralRecordTypes */
4242 4329 export interface PostIntegralGetIntegralRecordTypesResponse {
4243 4330 /**
... ... @@ -4292,6 +4379,77 @@ export const postIntegralGetIntegralRecordTypes = /* #__PURE__ */ (() =&gt; {
4292 4379 return request;
4293 4380 })();
4294 4381  
  4382 +/** @description request parameter type for postIntegralGroupExchangeRecords */
  4383 +export interface PostIntegralGroupExchangeRecordsOption {
  4384 + /**
  4385 + * @description
  4386 + * dto
  4387 + */
  4388 + body: {
  4389 + /**
  4390 + @description
  4391 + dto */
  4392 + dto: GroupExchangeRecordsRequestDto;
  4393 + };
  4394 +}
  4395 +
  4396 +/** @description response type for postIntegralGroupExchangeRecords */
  4397 +export interface PostIntegralGroupExchangeRecordsResponse {
  4398 + /**
  4399 + * @description
  4400 + * OK
  4401 + */
  4402 + 200: ServerResult;
  4403 + /**
  4404 + * @description
  4405 + * Created
  4406 + */
  4407 + 201: any;
  4408 + /**
  4409 + * @description
  4410 + * Unauthorized
  4411 + */
  4412 + 401: any;
  4413 + /**
  4414 + * @description
  4415 + * Forbidden
  4416 + */
  4417 + 403: any;
  4418 + /**
  4419 + * @description
  4420 + * Not Found
  4421 + */
  4422 + 404: any;
  4423 +}
  4424 +
  4425 +export type PostIntegralGroupExchangeRecordsResponseSuccess =
  4426 + PostIntegralGroupExchangeRecordsResponse[200];
  4427 +/**
  4428 + * @description
  4429 + * 课题组积分兑换记录
  4430 + * @tags 积分接口
  4431 + * @produces *
  4432 + * @consumes application/json
  4433 + */
  4434 +export const postIntegralGroupExchangeRecords = /* #__PURE__ */ (() => {
  4435 + const method = 'post';
  4436 + const url = '/integral/groupExchangeRecords';
  4437 + function request(
  4438 + option: PostIntegralGroupExchangeRecordsOption,
  4439 + ): Promise<PostIntegralGroupExchangeRecordsResponseSuccess> {
  4440 + return requester(request.url, {
  4441 + method: request.method,
  4442 + ...option,
  4443 + }) as unknown as Promise<PostIntegralGroupExchangeRecordsResponseSuccess>;
  4444 + }
  4445 +
  4446 + /** http method */
  4447 + request.method = method;
  4448 + /** request url */
  4449 + request.url = url;
  4450 + return request;
  4451 +})();
  4452 +
4295 4453 /** @description request parameter type for postIntegralMergeUserIntegralToGroup */
4296 4454 export interface PostIntegralMergeUserIntegralToGroupOption {
4297 4455 /**
... ... @@ -4647,6 +4805,77 @@ export const postIntegralQuerySumByUser = /* #__PURE__ */ (() =&gt; {
4647 4805 return request;
4648 4806 })();
4649 4807  
  4808 +/** @description request parameter type for postIntegralUserExchangeRecords */
  4809 +export interface PostIntegralUserExchangeRecordsOption {
  4810 + /**
  4811 + * @description
  4812 + * dto
  4813 + */
  4814 + body: {
  4815 + /**
  4816 + @description
  4817 + dto */
  4818 + dto: ExchangeRecordsRequestDto;
  4819 + };
  4820 +}
  4821 +
  4822 +/** @description response type for postIntegralUserExchangeRecords */
  4823 +export interface PostIntegralUserExchangeRecordsResponse {
  4824 + /**
  4825 + * @description
  4826 + * OK
  4827 + */
  4828 + 200: ServerResult;
  4829 + /**
  4830 + * @description
  4831 + * Created
  4832 + */
  4833 + 201: any;
  4834 + /**
  4835 + * @description
  4836 + * Unauthorized
  4837 + */
  4838 + 401: any;
  4839 + /**
  4840 + * @description
  4841 + * Forbidden
  4842 + */
  4843 + 403: any;
  4844 + /**
  4845 + * @description
  4846 + * Not Found
  4847 + */
  4848 + 404: any;
  4849 +}
  4850 +
  4851 +export type PostIntegralUserExchangeRecordsResponseSuccess =
  4852 + PostIntegralUserExchangeRecordsResponse[200];
  4853 +/**
  4854 + * @description
  4855 + * 用户积分兑换记录
  4856 + * @tags 积分接口
  4857 + * @produces *
  4858 + * @consumes application/json
  4859 + */
  4860 +export const postIntegralUserExchangeRecords = /* #__PURE__ */ (() => {
  4861 + const method = 'post';
  4862 + const url = '/integral/userExchangeRecords';
  4863 + function request(
  4864 + option: PostIntegralUserExchangeRecordsOption,
  4865 + ): Promise<PostIntegralUserExchangeRecordsResponseSuccess> {
  4866 + return requester(request.url, {
  4867 + method: request.method,
  4868 + ...option,
  4869 + }) as unknown as Promise<PostIntegralUserExchangeRecordsResponseSuccess>;
  4870 + }
  4871 +
  4872 + /** http method */
  4873 + request.method = method;
  4874 + /** request url */
  4875 + request.url = url;
  4876 + return request;
  4877 +})();
  4878 +
4650 4879 /** @description request parameter type for postKingdeeRepCustomer */
4651 4880 export interface PostKingdeeRepCustomerOption {
4652 4881 /**
... ...