From abb95fc4d0f50b9a75e135404b632225ae69669c Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 8 Jan 2026 16:34:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=A2=E6=9C=8D:=20=E5=9C=B0?= =?UTF-8?q?=E6=8E=A5=E7=A4=BE=E6=8E=A5=E5=9B=A2=E4=BF=A1=E6=81=AF:=20?= =?UTF-8?q?=E6=94=B9=E7=BB=9F=E8=AE=A1=E4=B8=8EHT=E4=B8=80=E8=87=B4;=20+?= =?UTF-8?q?=E7=AB=99=E5=A4=96=E5=A5=BD=E8=AF=84,=20=E6=8A=95=E8=AF=89,=20?= =?UTF-8?q?=E4=B8=9C=E9=81=93=E4=B8=BB=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: `urils/commons` --> `@haina/utils-commons, `@haina/utils-request`, `@haina/utils-pagespy` --- package-lock.json | 33 +++++ package.json | 3 + src/components/Data.jsx | 32 ++++- src/stores/CustomerServices.js | 6 + src/views/AgentGroupCount.jsx | 249 ++++++++++++++++++++++++++++++--- src/views/AgentGroupList.jsx | 195 ++++++++++++++++++++++++-- 6 files changed, 486 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index a57720e..31d28f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,9 @@ "dependencies": { "@ant-design/charts": "^1.4.2", "@ant-design/pro-components": "^2.6.16", + "@haina/utils-commons": "https://research.hainatravel.com/npm/utils-commons-0.1.1.tgz", + "@haina/utils-pagespy": "https://research.hainatravel.com/npm/utils-pagespy-0.1.1.tgz", + "@haina/utils-request": "https://research.hainatravel.com/npm/utils-request-0.1.1.tgz", "antd": "^4.22.6", "dingtalk-jsapi": "^3.0.9", "docx": "^9.5.1", @@ -3843,6 +3846,24 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@haina/utils-commons": { + "version": "0.1.1", + "resolved": "https://research.hainatravel.com/npm/utils-commons-0.1.1.tgz", + "integrity": "sha512-I3Ll5iNLtrnOCzs0IB3OXGQa0l75aQT740NKCUFwR1DHRx9vjeoqestS/PamZN1fuiodxWHkOao3JXOPRwSSfw==", + "hasInstallScript": true + }, + "node_modules/@haina/utils-pagespy": { + "version": "0.1.1", + "resolved": "https://research.hainatravel.com/npm/utils-pagespy-0.1.1.tgz", + "integrity": "sha512-aMyp8QPDM1URGOn0Bw1z1zUM7MDUDuHiPT8U5Zmusb6EIka+7XVmunQGy7HMPSgrfByD5DlNFkF/l5ej45PRtA==", + "hasInstallScript": true + }, + "node_modules/@haina/utils-request": { + "version": "0.1.1", + "resolved": "https://research.hainatravel.com/npm/utils-request-0.1.1.tgz", + "integrity": "sha512-p+0ApwEf+lcSOr7tS9kdgZmW+vZc0Gol6+8IejNv/qfMk6cmuBJYn5khvcSR1mblBPMag+464YpoBI32R9OMDQ==", + "hasInstallScript": true + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -24391,6 +24412,18 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==" }, + "@haina/utils-commons": { + "version": "https://research.hainatravel.com/npm/utils-commons-0.1.1.tgz", + "integrity": "sha512-I3Ll5iNLtrnOCzs0IB3OXGQa0l75aQT740NKCUFwR1DHRx9vjeoqestS/PamZN1fuiodxWHkOao3JXOPRwSSfw==" + }, + "@haina/utils-pagespy": { + "version": "https://research.hainatravel.com/npm/utils-pagespy-0.1.1.tgz", + "integrity": "sha512-aMyp8QPDM1URGOn0Bw1z1zUM7MDUDuHiPT8U5Zmusb6EIka+7XVmunQGy7HMPSgrfByD5DlNFkF/l5ej45PRtA==" + }, + "@haina/utils-request": { + "version": "https://research.hainatravel.com/npm/utils-request-0.1.1.tgz", + "integrity": "sha512-p+0ApwEf+lcSOr7tS9kdgZmW+vZc0Gol6+8IejNv/qfMk6cmuBJYn5khvcSR1mblBPMag+464YpoBI32R9OMDQ==" + }, "@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", diff --git a/package.json b/package.json index 97e4712..7493481 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "dependencies": { "@ant-design/charts": "^1.4.2", "@ant-design/pro-components": "^2.6.16", + "@haina/utils-commons": "https://research.hainatravel.com/npm/utils-commons-0.1.1.tgz", + "@haina/utils-pagespy": "https://research.hainatravel.com/npm/utils-pagespy-0.1.1.tgz", + "@haina/utils-request": "https://research.hainatravel.com/npm/utils-request-0.1.1.tgz", "antd": "^4.22.6", "dingtalk-jsapi": "^3.0.9", "docx": "^9.5.1", diff --git a/src/components/Data.jsx b/src/components/Data.jsx index 7b2ae3f..bfd2d52 100644 --- a/src/components/Data.jsx +++ b/src/components/Data.jsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { Tag, Button, message } from 'antd'; import { CaretUpOutlined, CaretDownOutlined, DownloadOutlined } from '@ant-design/icons'; import { utils, writeFile } from "xlsx"; -import { isEmpty, getNestedValue } from "../utils/commons"; +import { isEmpty, getNestedValue, fixTo2Decimals } from "@haina/utils-commons"; /** * @property diffPercent @@ -28,6 +28,36 @@ export const VSTag = (props) => { ); }; +/** + * @property {number} [diffPercent=0] + * @property {number} diffData + * @property {number} data1 + * @property {number} data2 + * @property {string} dataSuffix + */ +export const VSDataTag = ({ diffPercent=0, diffData=0, data1=0, data2=0, dataSuffix='' }) => { + const _diffPercent = diffPercent || (data2) ? fixTo2Decimals((data1-data2)/data2*100) : 100; + const _diffData = diffData || isNaN(data2) ? fixTo2Decimals(data1-0) : (fixTo2Decimals(data1-data2)); + const CaretIcon = parseInt(_diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined; + const tagColor = parseInt(_diffPercent) < 0 ? 'gold' : 'lime'; + // parseInt(_diffPercent) === 0 ? ( + // '-' + // ) : + return ( + +
+ {data1}{dataSuffix} VS {data2}{dataSuffix} +
+ {_diffData !== 0 && ( + } color={tagColor}> + {_diffPercent} + %  {_diffData}{dataSuffix} + + )} +
+ ); +}; + /** * 导出表格数据存为xlsx * @property label 文件名字 diff --git a/src/stores/CustomerServices.js b/src/stores/CustomerServices.js index 22a643e..f37af87 100644 --- a/src/stores/CustomerServices.js +++ b/src/stores/CustomerServices.js @@ -37,6 +37,9 @@ class CustomerServices { }); } + /** + * @deprecated 已迁移到zustand + */ fetchAgentGroupCount() { this.inProgress = true; const fetchUrl = prepareUrl(config.HT_HOST + '/service-web/QueryData/GetAgentGroupInfoALL') @@ -327,6 +330,9 @@ class CustomerServices { }); } + /** + * @deprecated 已迁移到zustand + */ fetchGroupListByAgentId(agentId) { this.inProgress = true; this.agentCompany = '...'; diff --git a/src/views/AgentGroupCount.jsx b/src/views/AgentGroupCount.jsx index 8d7dc5d..999e297 100644 --- a/src/views/AgentGroupCount.jsx +++ b/src/views/AgentGroupCount.jsx @@ -1,32 +1,245 @@ -import { useContext, useEffect } from 'react'; +import { useContext } from 'react'; +import { NavLink } from "react-router-dom"; import { Row, Col, Typography, Space, Table, Divider } from 'antd'; import { stores_Context } from '../config'; import { observer } from 'mobx-react'; +import { toJS } from 'mobx'; import 'moment/locale/zh-cn'; -import { utils, writeFileXLSX } from 'xlsx'; import SearchForm from './../components/search/SearchForm'; -import { TableExportBtn } from './../components/Data'; +import { TableExportBtn, VSDataTag } from './../components/Data'; +import useCustomerServicesStore from '../zustand/CustomerServices'; +import { useShallow } from 'zustand/shallow'; +import { fixTo2Decimals } from "@haina/utils-commons"; + +const sorter = (a, b, key) => a[key] - b[key]; +// 注意TdCell要提到DataTable作用域外声明 +const TdCell = (tdprops) => { + // onMouseEnter, onMouseLeave在数据量多的时候,会严重阻塞表格单元格渲染,严重影响性能 + const { onMouseEnter, onMouseLeave, ...restProps } = tdprops; + return ; +}; + +const DataRenderCell = ({ data1, data2, dataSuffix = '', showDiffData }) => { + if (showDiffData) { + return ; + } + return
{data1}{dataSuffix}
; +}; const AgentGroupCount = () => { const { customerServicesStore, date_picker_store } = useContext(stores_Context); - const agentGroupList = customerServicesStore.agentGroupList; - const agentGroupListColumns = customerServicesStore.agentGroupListColumns; - const { inProgress } = customerServicesStore; + const [loading, searchValues, setSearchValues, searchValuesToSub] = useCustomerServicesStore(useShallow((state) => [state.loading, state.searchValues, state.setSearchValues, state.searchValuesToSub])); + + const [agentGroupList, total1] = useCustomerServicesStore(useShallow((state) => [state.agentCountList, state.agentCountTotal])); + const getAgentGroupCount = useCustomerServicesStore((state) => state.getAgentGroupCount); - useEffect(() => { - customerServicesStore.fetchAllAgent(); - }, []); + const columns = [ + { + title: '地接社名称', + dataIndex: 'VendorName', + fixed: 'left', + children: [ + { + // title: this.startDate.format(config.DATE_FORMAT) + '~' + this.endDate.format(config.DATE_FORMAT), + dataIndex: 'VendorName', + fixed: 'left', + render: (text, record) => {record.VendorName}, + }, + ], + }, + { + title: '团数', + dataIndex: 'GroupCount', + sorter: (a, b) => sorter(a, b, 'GroupCount'), + children: [ + { + title: , // total1.GroupCount, + dataIndex: 'GroupCount', + render: (text, r) => , + }, + ], + }, + { + title: '人数', + dataIndex: 'PersonNum', + sorter: (a, b) => sorter(a, b, 'PersonNum'), + children: [ + { + title: , // total1.PersonNum, + dataIndex: 'PersonNum', + render: (text, r) => , + }, + ], + }, + { + title: '团天数', + dataIndex: 'GroupDays', + sorter: (a, b) => sorter(a, b, 'GroupDays'), + children: [ + { + title: , // total1.GroupDays, + dataIndex: 'GroupDays', + render: (text, r) => , + }, + ], + }, + { + title: '交易额', + dataIndex: 'totalcost', + sorter: (a, b) => sorter(a, b, 'totalcost'), + children: [ + { + title: , // total1.totalcost, + dataIndex: 'totalcost', + render: (text, r) => , + }, + ], + }, + { + title: '反馈表团数', + dataIndex: 'FKBTS', + sorter: (a, b) => sorter(a, b, 'FKBTS'), + children: [ + { + title: , // total1.FKBTS, + dataIndex: 'FKBTS', + render: (text, r) => , + }, + ], + }, + { + title: '东道主团数', + dataIndex: 'DDZTS', + sorter: (a, b) => sorter(a, b, 'DDZTS'), + children: [ + { + title: , // total1.DDZTS, + dataIndex: 'DDZTS', + render: (text, r) => , + }, + ], + }, + { + title: '东道主案例数', + dataIndex: 'DDZCases', + sorter: (a, b) => sorter(a, b, 'DDZCases'), + children: [ + { + title: , // total1.DDZCases, + dataIndex: 'DDZCases', + render: (text, r) => , + }, + ], + }, + { + title: '东道主案例比例', + dataIndex: 'DDZRate', + sorter: (a, b) => sorter(a, b, 'DDZRate'), + children: [ + { + title: , // total1.DDZRate, + dataIndex: 'DDZRate', + render: (text, r) => , + }, + ], + }, + { + title: '站外好评团数', + dataIndex: 'ZWHP', + sorter: (a, b) => sorter(a, b, 'ZWHP'), + children: [ + { + title: , // total1.ZWHP, + dataIndex: 'ZWHP', + render: (text, r) => , + }, + ], + }, + { + title: '站外好评数', + dataIndex: 'ZWHPCases', + sorter: (a, b) => sorter(a, b, 'ZWHPCases'), + children: [ + { + title: , // total1.ZWHPCases, + dataIndex: 'ZWHPCases', + render: (text, r) => , + }, + ], + }, + { + title: '站外好评率', + dataIndex: 'ZWHPRate', + sorter: (a, b) => sorter(a, b, 'ZWHPRate'), // parseInt(a.ZWHPRate) - parseInt(b.ZWHPRate), + children: [ + { + title: , // total1.ZWHPRate, + dataIndex: 'ZWHPRate', + render: (text, r) => , + }, + ], + }, + { + title: '不满数', + dataIndex: 'BMS', + sorter: (a, b) => sorter(a, b, 'BMS'), + children: [ + { + title: , // total1.BMS, + dataIndex: 'BMS', + render: (text, r) => , + }, + ], + }, + { + title: '不满率', + dataIndex: 'BMRate', + sorter: (a, b) => sorter(a, b, 'BMRate'), // parseInt(a.BMRate) - parseInt(b.BMRate), + children: [ + { + title: , // total1.BMRate, + dataIndex: 'BMRate', + render: (text, r) => , + }, + ], + }, + { + title: '投诉数', + dataIndex: 'TS', + sorter: (a, b) => sorter(a, b, 'TS'), + children: [ + { + title: , // total1.TS, + dataIndex: 'TS', + render: (text, r) => , + }, + ], + }, + { + title: '投诉率', + dataIndex: 'TSRate', + sorter: (a, b) => sorter(a, b, 'TSRate'), // parseInt(a.TSRate) - parseInt(b.TSRate), + children: [ + { + title: , // total1.TSRate, + dataIndex: 'TSRate', + render: (text, r) => , + }, + ], + }, + ]; return ( <> - + { }} onSubmit={(_err, obj, form) => { customerServicesStore.setSearchValues(obj, form); - customerServicesStore.fetchAgentGroupCount(); + setSearchValues(obj, form); + getAgentGroupCount(obj); }} /> @@ -47,18 +261,19 @@ const AgentGroupCount = () => { 地接社团信息 - + record.key} - loading={inProgress} + rowKey={(record) => record.EOI_ObjSN} + loading={loading} pagination={false} - scroll={{ x: 1000 }} + scroll={{ x: 2000 }} /> diff --git a/src/views/AgentGroupList.jsx b/src/views/AgentGroupList.jsx index 545c8ac..57dbe77 100644 --- a/src/views/AgentGroupList.jsx +++ b/src/views/AgentGroupList.jsx @@ -1,22 +1,161 @@ -import { useContext, useEffect } from 'react'; +import { useContext, useEffect, useMemo } from 'react'; import { Row, Col, Typography, Space, Table, List } from 'antd'; import { stores_Context } from '../config'; import { observer } from 'mobx-react'; import { NavLink, useParams } from 'react-router-dom'; import 'moment/locale/zh-cn'; import SearchForm from './../components/search/SearchForm'; +import useCustomerServicesStore from '../zustand/CustomerServices'; +import { useShallow } from 'zustand/shallow'; +import { isEmpty } from '@haina/utils-commons'; +import { toJS } from 'mobx'; + +const buildColumns = (total) => [ + { + title: '团名', + dataIndex: 'GRI_Name', + children: [ + { + title: '', + dataIndex: 'GRI_Name', + }, + ], + }, + { + title: '人数', + dataIndex: 'COLI_PersonNum', + sorter: (a, b) => a.COLI_PersonNum - b.COLI_PersonNum, + children: [ + { + title: total.COLI_PersonNum, + dataIndex: 'COLI_PersonNum', + }, + ], + }, + { + title: '天数', + dataIndex: 'COLI_Days', + sorter: (a, b) => a.COLI_Days - b.COLI_Days, + children: [ + { + title: total.COLI_Days, + dataIndex: 'COLI_Days', + }, + ], + }, + { + title: '交易额', + dataIndex: 'totalcost', + sorter: (a, b) => a.totalcost - b.totalcost, + children: [ + { + title: total.totalcost, + dataIndex: 'totalcost', + }, + ], + }, + { + title: '导游', + dataIndex: 'GuideName', + children: [ + { + title: '-', + dataIndex: 'GuideName', + }, + ], + }, + { + title: '反馈表', + dataIndex: 'FKB', + sorter: (a, b) => a.FKB - b.FKB, + children: [ + { + title: total.FKB, + dataIndex: 'FKB', + }, + ], + }, + { + title: '东道主', + dataIndex: 'DDZCases', + sorter: (a, b) => a.DDZCases - b.DDZCases, + children: [ + { + title: total.DDZCases, + dataIndex: 'DDZCases', + }, + ], + }, + { + title: '前勤分', + dataIndex: 'qianqin', + children: [ + { + title: total.qianqin, + dataIndex: 'qianqin', + }, + ], + }, + { + title: '好评', + dataIndex: 'Good', + sorter: (a, b) => a.Good - b.Good, + children: [ + { + title: total.Good, + dataIndex: 'Good', + }, + ], + }, + { + title: '差评', + dataIndex: 'Bad', + sorter: (a, b) => a.Bad - b.Bad, + children: [ + { + title: total.Bad, + dataIndex: 'Bad', + }, + ], + }, + { + title: '投诉', + dataIndex: 'TS', + sorter: (a, b) => a.TS - b.TS, + children: [ + { + title: total.TS, + dataIndex: 'TS', + }, + ], + }, + { + title: '不满', + dataIndex: 'BM', + sorter: (a, b) => a.BM - b.BM, + children: [ + { + title: total.BM, + dataIndex: 'BM', + }, + ], + }, +]; const AgentGroupList = () => { const { agentId } = useParams(); const { customerServicesStore, date_picker_store } = useContext(stores_Context); + const [loading, searchValues, setSearchValues] = useCustomerServicesStore(useShallow((state) => [state.loading, state.searchValues, state.setSearchValues])); + + const [{ result1, result2, total1, total2, title1, title2 }, agencyName] = useCustomerServicesStore(useShallow((state) => [state.agencyGroups, state.agencyName])); + const getGroupListByAgentId = useCustomerServicesStore((state) => state.getGroupListByAgentId); useEffect(() => { - customerServicesStore.fetchGroupListByAgentId(agentId); + getGroupListByAgentId(agentId); }, []); - const groupList = customerServicesStore.groupList; - const groupListColumns = customerServicesStore.groupListColumns; - const { startDate, endDate, dateType, inProgress } = customerServicesStore; + const columns1 = useMemo(() => buildColumns(total1), [total1]); + const columns2 = useMemo(() => buildColumns(total2), [total2]); return ( <> @@ -29,34 +168,37 @@ const AgentGroupList = () => { { customerServicesStore.setSearchValues(obj, form); - customerServicesStore.fetchGroupListByAgentId(agentId); + setSearchValues(obj, form); + getGroupListByAgentId(agentId); }} /> - {customerServicesStore.agentCompany} + {agencyName}
title1} sticky - dataSource={groupList} - columns={groupListColumns} + dataSource={result1} + columns={columns1} size="small" - rowKey={(record) => record.key} - loading={inProgress} + rowKey={(record) => record.GRI_SN} + loading={loading} pagination={false} scroll={{ x: 1000 }} expandable={{ @@ -72,6 +214,31 @@ const AgentGroupList = () => { ), }} /> + {isEmpty(result2) ? null : ( +
title2} + sticky + dataSource={result2} + columns={columns2} + size="small" + rowKey={(record) => record.GRI_SN} + loading={loading} + pagination={false} + scroll={{ x: 1000 }} + expandable={{ + expandedRowRender: (record) => ( + + + + + + + + + ), + }} + /> + )}