This commit is contained in:
ylj20011123 2025-09-23 19:14:35 +08:00
parent d0c4edded6
commit cee81d5037
17 changed files with 907 additions and 239 deletions

View File

@ -1,6 +1,6 @@
{
"name": "ant-design-pro",
"version": "4.5.61",
"version": "4.5.62",
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
"scripts": {

View File

@ -51,6 +51,9 @@ const Model: LoginModelType = {
// 登录方法
* login({ payload }, { call, put }) {
const response = yield call(accountLogin, payload);
console.log('responseresponseresponseresponse', response);
yield put({
type: 'changeLoginStatus',
payload: response,
@ -58,8 +61,16 @@ const Model: LoginModelType = {
// Login successfully
if (response.status === 'ok') {
// yield put({ type: 'global/getMenuData', payload: response.currentUser.ID }); // 生成左侧菜单
yield put({ type: 'user/saveCurrentUser', payload: { ...response.currentUser } }); // 存储用户信息
// 这里拿一下用户信息 顺便判断一下 当前用户 是不是密码等级过低
if (!response?.passwordRes) {
message.error('密码过于简单,请重新设置密码!')
history.push('/user/forgetPassword');
return
}
yield put({ type: 'user/saveCurrentUser', payload: { ...response.currentUser } }); // 存储用户信息
message.success('🎉 🎉 🎉 登录成功!');
if (!history) return;

View File

@ -43,7 +43,7 @@ const ForgetPasswordContent: React.FC = () => {
const [step, setStep] = useState<1 | 2>(1) // 1填写信息 2 修改成功
return (
<div>
<Typography.Title level={2} style={{ textAlign: 'center', paddingTop: 60, paddingBottom: 30 }}> {step === 1 ? '驿商云忘记密码' : ''}</Typography.Title>
<Typography.Title level={2} style={{ textAlign: 'center', paddingTop: 60, paddingBottom: 30 }}> {step === 1 ? '驿商云重置密码' : ''}</Typography.Title>
<Card bordered={false} style={{ width: 910, margin: 'auto', height: 560 }} bodyStyle={{ padding: 80 }}>
{step === 1 &&
<ProForm
@ -147,11 +147,39 @@ const ForgetPasswordContent: React.FC = () => {
rules={[
{
required: true,
message: ''
message: '请输入新密码'
},
{
min: 8,
message: '密码长度至少8位'
},
{
validator: (_, value) => {
if (!value) return Promise.resolve();
// 检查密码复杂度数字、大小写字母、特殊字符中的2种以上组成
const hasNumber = /\d/.test(value);
const hasLowercase = /[a-z]/.test(value);
const hasUppercase = /[A-Z]/.test(value);
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value);
const typeCount = [hasNumber, hasLowercase, hasUppercase, hasSpecialChar].filter(Boolean).length;
if (typeCount < 2) {
return Promise.reject(new Error('密码不符合安全要求请设置长度8位以上由数字、大小写字母、特殊字符中的2种以上组成'));
}
return Promise.resolve();
}
}
]}
placeholder=""
hasFeedback
extra={
<Typography.Text type="secondary" style={{ fontSize: '12px' }}>
82
</Typography.Text>
}
/>
<ProFormText.Password
dependencies={['NewPassword']}

View File

@ -1,6 +1,5 @@
// 营收汇总报表
import moment from 'moment';
import numeral from 'numeral';
import { connect, history } from 'umi';
@ -35,6 +34,8 @@ import rectification from '@/assets/rectification.png'
import codeIcon from '@/assets/DataVerification/code.png'
import interfaceIcon from '@/assets/DataVerification/interface.png'
import PageTitleBox from '@/components/PageTitleBox';
import { formatTreeData, sortTreeData } from '@/utils/format';
import { exportXlsxFromProColumnsExcelJS } from '@/utils/exportExcelFun';
const { Text } = Typography;
@ -82,6 +83,7 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
MERCHANTS_NAME: { show: false },
ShopTrade: { show: false },
})
const SHOPTRADEObj = session.get('SHOPTRADEObj')
// 显示每日流水抽屉
const [showDailyDrawer, setShowDailyDrawer] = useState<boolean>(false)
const [currentRow, setCurrentRow] = useState<any>()
@ -384,11 +386,12 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
width: 120,
valueType: 'select',
hideInSearch: true,
request: async () => {
// 这里要手动添加枚举字段(从下面这些字典中选择一个):商品业态[BUSINESSTYPE]
const options = await getFieldEnum({ FieldExplainField: 'BUSINESSTYPE' });
return options;
},
valueEnum: SHOPTRADEObj
// request: async () => {
// // 这里要手动添加枚举字段(从下面这些字典中选择一个):商品业态[BUSINESSTYPE]
// const options = await getFieldEnum({ FieldExplainField: 'BUSINESSTYPE' });
// return options;
// },
},
]
},
@ -764,18 +767,22 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
span: 6,
defaultCollapsed: false,
}}
request={async (params) => {
request={async (params, sorter) => {
const sortstr = Object.keys(sorter).map(n => {
const value = sorter[n]
return value ? `${n} ${value.replace('end', '')}` : ''
})
console.log('sortstrsortstrsortstr', sortstr);
params.ServerpartIds = selectedId || '0'
if (params?.StartDate === params?.EndDate) {
setIsSameDay(true)
} else {
setIsSameDay(false)
}
const req: RevenueStatisticsParams = {
...params,
DataType: activeKey || '1',
DataSourceType: DataSourceType || '1',
ShowShop: params.ShowShop === '1',
@ -789,6 +796,11 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
const data = await getRevenueReport(req);
setSearchParamsTime(params)
setSearchTime([params.StartDate, params.EndDate])
let filterList: any = sortTreeData(data.data, sortstr.toString())
console.log('filterList', filterList);
setReqDetailList(data.data);
setPrintOut(undefined);
const list = data.data
@ -805,7 +817,6 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
isOneService = true
}
let result: any = []
if (list && list.length > 0) {
list.forEach((item: any, index: number) => {
@ -869,21 +880,30 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
}
}
// if (list && list.length>0){
// list.forEach((item: any)=>{
// if (item.children && item.children.length>0){
// // item.SPRegionType_Name = item.Serverpart_Name
// // item.Serverpart_Name = ''
//
// item.children.forEach((subItem: any)=>{
// subItem.SPRegionType_Name = subItem.Serverpart_Name
// subItem.Serverpart_Name = ''
// })
// }
// })
// }
let fieldData: any = [
'TotalRevenue.Revenue_Amount',
'TotalRevenue.MobilePay_Amount',
'TotalRevenue.CashPay_Amount',
'TotalRevenue.Mobile_Correct',
'TotalRevenue.Cash_Correct',
'RegionARevenue.Revenue_Amount',
'RegionARevenue.MobilePay_Amount',
'RegionARevenue.CashPay_Amount',
'RegionARevenue.Mobile_Correct',
'RegionARevenue.Cash_Correct',
'RegionBRevenue.Revenue_Amount',
'RegionBRevenue.MobilePay_Amount',
'RegionBRevenue.CashPay_Amount',
'RegionBRevenue.Mobile_Correct',
'RegionBRevenue.Cash_Correct',
]
let enumList: any = ['ShopTrade']
setReqDetailList(result);
// 处理一下导出数据
let newPrintData: any = formatTreeData(result, fieldData, enumList, SHOPTRADEObj, [])
console.log('newPrintDatanewPrintDatanewPrintData', newPrintData);
setReqDetailList(newPrintData);
if (result) {
return { data: result, success: true };
}
@ -926,15 +946,15 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
headerTitle={<PageTitleBox props={props} />}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-RevenueReport"
filename={`门店经营报表(${moment(searchTime[0] || '').format('YYYY/MM/DD')}-${moment(searchTime[1] || '').format('YYYY/MM/DD')}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-RevenueReport"
// filename={`门店经营报表(${moment(searchTime[0] || '').format('YYYY/MM/DD')}-${moment(searchTime[1] || '').format('YYYY/MM/DD')}`}
// sheet="sheet1"
// />
// </span>,
<ReactToPrint
trigger={() => (
<Button key="printout" type="default" onClick={() => {
@ -962,16 +982,29 @@ const RevenueSummaryTable: React.FC<{ currentUser?: CurrentUser }> = (props) =>
type="primary"
onClick={async (e) => {
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e, true)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`营收汇总报表${searchParamsTime?.StartDate}-${searchParamsTime?.EndDate}`,
{
// topTitle: `营收汇总报表`, // 顶部大标题
}
)
} else {
message.error('暂无数据可导出!')
}
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e, true)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
}}
>
excel

View File

@ -15,8 +15,9 @@ import LeftSelectTree from "@/pages/reports/settlementAccount/component/leftSele
import moment from 'moment'
import session from "@/utils/session";
import { handleCorrectShopCigarette, handleGetCigaretteReport } from "../../Finance/service";
import { handleGetSumRow } from "@/utils/format";
import { formatTreeData, handleGetSumRow } from "@/utils/format";
import PageTitleBox from "@/components/PageTitleBox";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
const cigaretteReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -418,22 +419,47 @@ const cigaretteReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
res.push(item)
})
let result: any = handleGetSumRow(res, ['sumRevenue_Amount', 'sumCigarette_Amount', 'sumDifferent_Price_More', 'sumDifferent_Price_Less', 'sumCashPay_Amount', 'sumMobilePay_Amount', 'ARevenue_Amount', 'ACigarette_Amount', 'ADifferent_Price_More', 'ADifferent_Price_Less', 'ACashPay_Amount', 'AMobilePay_Amount', 'BRevenue_Amount', 'BCigarette_Amount', 'BDifferent_Price_More', 'BDifferent_Price_Less', 'BCashPay_Amount', 'BMobilePay_Amount'], 'Statistics_Date')
setReqDetailList(result)
let fieldData: any = [
"sumRevenue_Amount",
"sumCigarette_Amount",
"sumDifferent_Price_More",
"sumDifferent_Price_Less",
"sumCashPay_Amount",
"sumMobilePay_Amount",
"ARevenue_Amount",
"ACigarette_Amount",
"ADifferent_Price_More",
"ADifferent_Price_Less",
"ACashPay_Amount",
"AMobilePay_Amount",
"BRevenue_Amount",
"BCigarette_Amount",
"BDifferent_Price_More",
"BDifferent_Price_Less",
"BCashPay_Amount",
"BMobilePay_Amount",
]
let enumList: any = []
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(result)), fieldData, enumList, [], [])
setReqDetailList(newPrintData)
return { data: result, success: true }
}
setReqDetailList([])
return { data: [], success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-cigaretteReport"
filename={`香烟报表${searchParams?.StartDate}-${searchParams?.EndDate}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-cigaretteReport"
// filename={`香烟报表${searchParams?.StartDate}-${searchParams?.EndDate}`}
// sheet="sheet1"
// />
// </span>,
<Button type="primary" loading={btnLoading} onClick={async (e) => {
if (!searchParams?.ServerpartIds) {
message.error('请选择服务区!')
@ -468,17 +494,31 @@ const cigaretteReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
key="new"
type="primary"
onClick={(e) => {
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`香烟营收报表${searchParams?.StartDate}-${searchParams?.EndDate}`,
// {
// topTitle: `单品销售排行统计`, // 顶部大标题
// }
)
} else {
message.error('暂无数据可导出!')
}
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
}}
>
excel

View File

@ -19,6 +19,8 @@ import numeral from "numeral";
import { contractType } from "@/pages/contract/emun";
import { handleGetShopShortNamesGet } from "@/pages/reports/BusinessAnalysis/transactionAnalysis/service";
import PageTitleBox from "@/components/PageTitleBox";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
import { formatTreeData } from "@/utils/format";
const personSellReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -49,6 +51,8 @@ const personSellReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
const [showExportTable, setShowExportTable] = useState<boolean>(false)
// 自营业态的选择列表
const [shopNamesList, setShopNamesList] = useState<any>()
// 表格数据
const [tableData, setTableData] = useState<any>()
// 自营业态的选择的列表方法
const handleGetShopNamesList = async (id: any) => {
const req: any = {
@ -361,10 +365,10 @@ const personSellReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
formRef={formRef}
columns={columns}
bordered
scroll={{ x: '100%', y: 'calc(100vh - 520px)' }}
scroll={{ x: '100%', y: 'calc(100vh - 560px)' }}
// pagination={false}
headerTitle={<PageTitleBox props={props} />}
search={{ span: 8 }}
search={{ span: 8, defaultCollapsed: false }}
request={async (params) => {
if (!selectedId) {
return
@ -392,37 +396,69 @@ const personSellReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
SERVERPART_NAME: '合计'
})
console.log('list', list)
setReqDetailList(list)
let fieldData: any = [
"TICKETCOUNT",
"TOTALCOUNT",
"TOTALOFFAMOUNT",
"RealActualCashpay",
"TOTALSELLAMOUNT",
"CASHPAY",
"CASH",
"DIFFERENT_PRICE",
"MobilyPay",
]
let enumList: any = []
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(list)), fieldData, enumList, [], [])
setReqDetailList(newPrintData)
setTableData(list)
return { data: list, success: true }
}
setReqDetailList([])
setTableData([])
return { data: [], success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-personSellReport"
filename={`服务区收银员报表${searchParams?.SELL_ENDDATE_Start}-${searchParams?.SELL_ENDDATE_End}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-personSellReport"
// filename={`服务区收银员报表${searchParams?.SELL_ENDDATE_Start}-${searchParams?.SELL_ENDDATE_End}`}
// sheet="sheet1"
// />
// </span>,
<Button
key="new"
type="primary"
onClick={(e) => {
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`服务区收银员报表${searchParams?.SELL_ENDDATE_Start}-${searchParams?.SELL_ENDDATE_End}`,
// {
// topTitle: `单品销售排行统计`, // 顶部大标题
// }
)
} else {
message.error('暂无数据可导出!')
}
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
}}
>
excel
@ -430,7 +466,7 @@ const personSellReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
if (tableData && tableData.length > 0) {
let TICKETCOUNTSum: number = 0
let TOTALCOUNTSum: number = 0
let TOTALOFFAMOUNTSum: number = 0
@ -441,7 +477,7 @@ const personSellReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
let DIFFERENT_PRICESum: number = 0
let MobilyPaySum: number = 0
reqDetailList.forEach((item: any) => {
tableData.forEach((item: any) => {
TICKETCOUNTSum += item.TICKETCOUNT
TOTALCOUNTSum += item.TOTALCOUNT
TOTALOFFAMOUNTSum += item.TOTALOFFAMOUNT

View File

@ -28,6 +28,7 @@ import AccountChildren from '../../Finance/components/accountChildren';
import { handleGetSumRow } from '@/utils/format';
import FlowDrawerSC from '@/pages/merchantManagement/mobilePayment/bankArrival/components/flowDrawerSC';
import PageTitleBox from '@/components/PageTitleBox';
import { exportXlsxFromProColumnsExcelJS } from '@/utils/exportExcelFun';
const { Text } = Typography;
@ -957,28 +958,40 @@ const revenueDistributionReport: React.FC<{ currentUser?: CurrentUser }> = (prop
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-revenueDistributionReport"
filename={`合作商户资金到账汇总表${searchDate && searchDate.length > 0 ? `${moment(searchDate[0]).format('YYYY-MM-DD')}-${moment(searchDate[1]).format('YYYY-MM-DD')}` : ''}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-revenueDistributionReport"
// filename={`合作商户资金到账汇总表${searchDate && searchDate.length > 0 ? `${moment(searchDate[0]).format('YYYY-MM-DD')}-${moment(searchDate[1]).format('YYYY-MM-DD')}` : ''}`}
// sheet="sheet1"
// />
// </span>,
<Typography.Text type="secondary"></Typography.Text>,
<Button
key="new"
type="primary"
onClick={(e) => {
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`合作商户资金到账汇总表${searchDate && searchDate.length > 0 ? `${moment(searchDate[0]).format('YYYY-MM-DD')}-${moment(searchDate[1]).format('YYYY-MM-DD')}` : ''}`,
// {
// topTitle: `单品销售排行统计`, // 顶部大标题
// }
)
} else {
message.error('暂无数据可导出!')
}

View File

@ -32,6 +32,8 @@ import './salesFlow.less'
import FlowDetail from "@/pages/merchantManagement/reports/SalesFlow/components/FlowDetail";
import SubMenu from "antd/lib/menu/SubMenu";
import PageTitleBox from '@/components/PageTitleBox';
import { exportXlsxFromProColumnsExcelJS } from '@/utils/exportExcelFun';
import { formatTreeData } from '@/utils/format';
const { Text } = Typography;
@ -75,7 +77,7 @@ const saleFlow: React.FC<{ currentUser: CurrentUser | undefined }> = (props) =>
const [showExportTable, setShowExportTable] = useState<boolean>(false)
const columns: ProColumns<YSSELLMASTERModel>[] = [
const columns: any = [
{
dataIndex: 'index',
title: '序号',
@ -317,11 +319,21 @@ const saleFlow: React.FC<{ currentUser: CurrentUser | undefined }> = (props) =>
console.log('data1', data);
if (data.List && data.List.length > 0) {
const list: any = JSON.parse(JSON.stringify(data.List))
setReqDetailList(list);
let fieldData: any = [
"SELLMASTER_COUNT",
"SELLMASTER_AMOUNT",
"SELLMASTER_OFFPRICE"
]
let enumList: any = []
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(list)), fieldData, enumList, [], [])
setReqDetailList(newPrintData);
console.log('data.otherData', data.otherData)
setOtherData(data.OtherData)
return { data: list, success: true }
}
setReqDetailList([]);
return { data: [], success: true }
}
@ -331,31 +343,44 @@ const saleFlow: React.FC<{ currentUser: CurrentUser | undefined }> = (props) =>
columns={columns}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-saleRankReport"
filename={`销售流水统计${searchParams?.SELLMASTER_DATE}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-saleRankReport"
// filename={`销售流水统计${searchParams?.SELLMASTER_DATE}`}
// sheet="sheet1"
// />
// </span>,
<Button
key="new"
type="primary"
onClick={async (e) => {
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`销售流水查询${searchParams?.SELLMASTER_DATE}`,
// {
// topTitle: `单品销售排行统计`, // 顶部大标题
// }
)
} else {
message.error('暂无数据可导出!')
}
// const success = await exportExcel(
// columns.slice(2),
// reqDetailList || [],

View File

@ -23,6 +23,7 @@ import ProDescriptions from "@ant-design/pro-descriptions";
import numeral from "numeral";
import PageTitleBox from "@/components/PageTitleBox";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
import { formatTreeData } from "@/utils/format";
const saleHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -54,6 +55,8 @@ const saleHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
const [showExportTable, setShowExportTable] = useState<boolean>(false)
const businessTypeObj = session.get("BUSINESSTYPEObj")
const [printIndex, setPrintIndex] = useState<number>(new Date().getTime())
// 表格数据
const [tableData, setTableData] = useState<any>()
// 商品业态列表
const [commodityFormatsObj, setCommodityFormatsObj] = useState<any>()
@ -329,8 +332,8 @@ const saleHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
columns={columns}
bordered
headerTitle={<PageTitleBox props={props} />}
scroll={{ y: 'calc(100vh - 540px)' }}
search={{ span: 6 }}
scroll={{ y: 'calc(100vh - 570px)' }}
search={{ span: 6, defaultCollapsed: false }}
pagination={{ pageSize: 100 }}
request={async (params) => {
@ -362,20 +365,32 @@ const saleHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
})
list = data
}
setReqDetailList(list)
let fieldData: any = [
"Commodity_RetailPrice",
"Total_Count",
"Total_OffAmount",
"Total_SellAmount",
"Commodity_PurchasePrice",
]
let enumList: any = []
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(list)), fieldData, enumList, [], ["Total_SellAmountRate"])
setReqDetailList(newPrintData)
setTableData(list)
return { data: list, success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-saleHisReport"
filename={`单品统计报表${searchParams?.StartTime}-${searchParams?.EndTime}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-saleHisReport"
// filename={`单品统计报表${searchParams?.StartTime}-${searchParams?.EndTime}`}
// sheet="sheet1"
// />
// </span>,
<Button
key="new"
type="primary"
@ -411,12 +426,12 @@ const saleHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
if (tableData && tableData.length > 0) {
let Total_CountSum: number = 0
let Total_OffAmountSum: number = 0
let Total_SellAmountSum: number = 0
reqDetailList.forEach((item: any) => {
tableData.forEach((item: any) => {
Total_CountSum += item.Total_Count
Total_OffAmountSum += item.Total_OffAmount
Total_SellAmountSum += item.Total_SellAmount

View File

@ -21,6 +21,7 @@ import { contractType } from "@/pages/contract/emun";
import { handleGetShopShortNamesGet } from "@/pages/reports/BusinessAnalysis/transactionAnalysis/service";
import PageTitleBox from "@/components/PageTitleBox";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
import { formatTreeData } from "@/utils/format";
const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -56,6 +57,9 @@ const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
const [commodityTypeList, setCommodityTypeList] = useState<any>()
// 商品类别的选择值
const [commodityTypeValue, setCommodityTypeValue] = useState<any>()
// 表格数据
const [tableData, setTableData] = useState<any>()
const { loading: nestLoading, data: nestList } = useRequest(async () => {
const req = {
PROVINCE_CODE: currentUser?.ProvinceCode,
@ -355,8 +359,8 @@ const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
columns={columns}
bordered
headerTitle={<PageTitleBox props={props} />}
search={{ span: 6 }}
scroll={{ x: "100%", y: 'calc(100vh - 420px)' }}
search={{ span: 6, defaultCollapsed: false }}
scroll={{ x: "100%", y: 'calc(100vh - 480px)' }}
pagination={false}
request={async (params) => {
if (!selectShopId) {
@ -373,22 +377,31 @@ const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
const data = await handleGetSaleRank(req)
console.log('data', data)
if (data && data.length > 0) {
setReqDetailList(data)
let fieldData: any = [
"Total_Count",
"Total_SellAmount",
]
let enumList: any = []
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(data)), fieldData, enumList, [], [])
setReqDetailList(newPrintData)
setTableData(data)
return { data, success: true }
}
setReqDetailList([])
setTableData([])
return { data: [], success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-saleRankReport"
filename={`单品销售排行统计${searchParams?.startDate}-${searchParams?.endDate}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-saleRankReport"
// filename={`单品销售排行统计${searchParams?.startDate}-${searchParams?.endDate}`}
// sheet="sheet1"
// />
// </span>,
<Button
key="new"
type="primary"
@ -397,10 +410,10 @@ const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`单品销售排行统计${searchParams?.startDate}-${searchParams?.endDate}`,
{
topTitle: `单品销售排行统计`, // 顶部大标题
}
`商品销售排名${searchParams?.startDate}-${searchParams?.endDate}`,
// {
// topTitle: `单品销售排行统计`, // 顶部大标题
// }
)
} else {
message.error('暂无数据可导出!')
@ -425,11 +438,11 @@ const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
if (tableData && tableData.length > 0) {
let Total_CountSum: number = 0
let Total_SellAmountSum: number = 0
reqDetailList.forEach((item: any) => {
tableData.forEach((item: any) => {
Total_CountSum += item.Total_Count
Total_SellAmountSum += item.Total_SellAmount
})

View File

@ -21,7 +21,8 @@ import ProTable from "@ant-design/pro-table";
import ReactHTMLTableToExcel from "react-html-table-to-excel";
import {
handleGetBusinessTrades,
handleGetCommoditySaleSummary
handleGetCommoditySaleSummary,
handleGetDailyCommoditySaleList
} from "@/pages/reports/BusinessAnalysis/saleReport/service";
import moment from "moment/moment";
import session from "@/utils/session";
@ -31,6 +32,7 @@ import { handleGetShopShortNamesGet } from "@/pages/reports/BusinessAnalysis/tra
import PageTitleBox from "@/components/PageTitleBox";
import center from "@/pages/account/center";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
import { formatTreeData, sortTreeData } from "@/utils/format";
const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -90,8 +92,19 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
setShopNamesList(obj)
}
}
// 表格数据
const [tableData, setTableData] = useState<any>()
const columns: any = [
{
title: "数据类型",
dataIndex: "statisticalType",
valueType: 'select',
hideInTable: true,
fieldProps: {
options: [{ label: "按账期统计", value: 1 }, { label: "按自然日统计", value: 2 }]
},
initialValue: 1
},
{
title: '统计时间',
dataIndex: 'search_date',
@ -189,6 +202,15 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
ellipsis: true,
align: 'center'
},
{
width: 120,
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: 'Commodity_Code',
hideInSearch: true,
hideInTable: currentUser?.ProvinceCode !== '734100',
ellipsis: true,
align: 'center'
},
{
dataIndex: 'Commodity_Name',
title: <div style={{ textAlign: 'center' }}></div>,
@ -385,16 +407,50 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
handleCallLogs()
console.log('params', params)
setSearchParams(params)
const sortstr = Object.keys(sorter).map(n => {
const value = sorter[n]
return value ? `${n} ${value.replace('end', '')}` : ''
})
let data: any = []
console.log('sortstrsortstr', sortstr);
if (params?.statisticalType === 1) {
const req = {
...params,
DataType: 1,
ServerpartShopIds: selectedId,
SearchKeyName: "Commodity_Name,Commodity_Barcode",
}
const data = await handleGetCommoditySaleSummary(req)
console.log('reqreqreq', req);
data = await handleGetCommoditySaleSummary(req)
} else {
// 等有了新接口 换上去
const req = {
SearchKeyValue: params?.SearchKeyValue || "",
StartDate: params?.StartTime || "",
EndDate: params?.EndTime || "",
ServerpartShopId: selectedId,
SearchKeyName: "Commodity_Name,Commodity_Barcode",
SortStr: sortstr.toString()
}
console.log('reqreqreq', req);
data = await handleGetDailyCommoditySaleList(req)
}
console.log('data', data)
if (data && data.length > 0) {
setReqDetailList(data)
let newData: any = sortTreeData(JSON.parse(JSON.stringify(data)), sortstr.toString())
let fieldData: any = [
"Total_SellAmount",
"Commodity_RetailPrice",
"Total_OffAmount",
]
let enumList: any = []
let newPrintData: any = formatTreeData(newData, fieldData, enumList, [], ['Total_SellAmountRate'])
setReqDetailList(newPrintData)
setTableData(data)
return { data, success: true }
}
return { data: [], success: true }
@ -446,12 +502,12 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
if (tableData && tableData.length > 0) {
let Total_CountSum: number = 0
let Total_OffAmountSum: number = 0
let Total_SellAmountSum: number = 0
reqDetailList.forEach((item: any) => {
tableData.forEach((item: any) => {
Total_CountSum += item.Total_Count
Total_OffAmountSum += item.Total_OffAmount
Total_SellAmountSum += item.Total_SellAmount
@ -460,7 +516,7 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
<ProDescriptions column={4} className="commity-sale-description" labelStyle={{ color: "#00000073" }}>
<ProDescriptions.Item label="销售数量" contentStyle={{ color: 'orangered' }}>{Total_CountSum ? numeral(Total_CountSum).format('0,0.00') : '0'}</ProDescriptions.Item>
<ProDescriptions.Item label="优惠金额" valueType="money" contentStyle={{ color: 'orangered' }}>{Total_OffAmountSum || '0.00'}</ProDescriptions.Item>
<ProDescriptions.Item label="对客营收" valueType="money" contentStyle={{ color: 'orangered' }}>{Total_SellAmountSum}</ProDescriptions.Item>
<ProDescriptions.Item label="对客营收" valueType="money" contentStyle={{ color: 'orangered' }}>{Total_SellAmountSum || '0.00'}</ProDescriptions.Item>
{/* <ProDescriptions.Item label="毛利率" contentStyle={{ color: 'orangered' }}></ProDescriptions.Item> */}
</ProDescriptions>
<ProDescriptions column={4} className="commity-sale-description" labelStyle={{ color: "#00000073" }}>

View File

@ -1,4 +1,5 @@
import request from '@/utils/request';
import requestEncryption from '@/utils/requestEncryption';
// 获取销售同环比
export async function handleGetCommoditySaleSummary(params: any) {
@ -21,6 +22,18 @@ export async function handleGetCommoditySaleSummary(params: any) {
return data.Result_Data.List
}
// 获取自然日单品销售数据
export async function handleGetDailyCommoditySaleList(params: any) {
const data = await requestEncryption('/Revenue/GetDailyCommoditySaleList', {
method: 'POST',
data: {
...params,
requestEncryption: true
}
})
return data.Result_Data.List
}
// 获取商品业态
export async function handleGetBusinessTrades(params: any) {
const data = await request('/BaseInfo/GetBusinessTrades', {

View File

@ -1,3 +1,6 @@
// 历史销售类别报表
import { connect } from "umi";
import type { CurrentUser } from "umi";
import type { ConnectState } from "@/models/connect";
@ -19,6 +22,8 @@ import { handleGetNestingCOMMODITYTYPETree } from "@/pages/reports/BusinessAnaly
import ProDescriptions from "@ant-design/pro-descriptions";
import numeral from "numeral";
import PageTitleBox from "@/components/PageTitleBox";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
import { formatTreeData } from "@/utils/format";
const saleTypeHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -67,6 +72,8 @@ const saleTypeHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
setCommodityTypeList(data)
})
const [printIndex, setPrintIndex] = useState<number>(new Date().getTime())
// 表格数据
const [tableData, setTableData] = useState<any>()
const columns: any = [
{
@ -331,35 +338,58 @@ const saleTypeHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
})
list = data
}
setReqDetailList(list)
let fieldData: any = [
"Total_Count",
"Total_OffAmount",
"Total_SellAmount",
]
let enumList: any = []
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(list)), fieldData, enumList, [], ["Total_SellAmountRate"])
setReqDetailList(newPrintData)
setTableData(list)
return { data: list, success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-saleReport"
filename={`类别统计报表${searchParams?.startDate}-${searchParams?.endDate}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-saleReport"
// filename={`类别统计报表${searchParams?.startDate}-${searchParams?.endDate}`}
// sheet="sheet1"
// />
// </span>,
<Button
key="new"
type="primary"
onClick={(e) => {
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`类别统计报表${searchParams?.startDate}-${searchParams?.endDate}`,
// {
// topTitle: `历史销售单品报表`, // 顶部大标题
// }
)
} else {
message.error('暂无数据可导出!')
}
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
}}
>
excel
@ -367,12 +397,12 @@ const saleTypeHisReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
if (tableData && tableData.length > 0) {
let Total_CountSum: number = 0
let Total_OffAmountSum: number = 0
let Total_SellAmountSum: number = 0
reqDetailList.forEach((item: any) => {
tableData.forEach((item: any) => {
Total_CountSum += item.Total_Count
Total_OffAmountSum += item.Total_OffAmount
Total_SellAmountSum += item.Total_SellAmount

View File

@ -22,6 +22,8 @@ import { handleGetBusinessTrades } from "./service";
import ProDescriptions from "@ant-design/pro-descriptions";
import numeral from "numeral";
import PageTitleBox from "@/components/PageTitleBox";
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
import { formatTreeData } from "@/utils/format";
const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -62,6 +64,8 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
// 商品业态列表
const [commodityFormatsObj, setCommodityFormatsObj] = useState<any>()
// 表格数据
const [tableData, setTableData] = useState<any>()
const { loading: nestLoading, data: nestList } = useRequest(async () => {
@ -312,9 +316,9 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
columns={columns}
bordered
headerTitle={<PageTitleBox props={props} />}
search={{ span: 6 }}
search={{ span: 6, defaultCollapsed: false }}
pagination={false}
scroll={{ y: 'calc(100vh - 470px)' }}
scroll={{ y: 'calc(100vh - 520px)' }}
request={async (params) => {
if (isFirst) {
setIsFirst(false)
@ -341,35 +345,58 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
})
list = data
}
setReqDetailList(list)
let fieldData: any = [
"Total_Count",
"Total_OffAmount",
"Total_SellAmount",
]
let enumList: any = []
let newPrintData: any = formatTreeData(list, fieldData, enumList, [], ['Total_SellAmountRate'])
setReqDetailList(newPrintData)
setTableData(list)
return { data: list, success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-saleTypeReport"
filename={`类别统计报表${searchParams?.startDate}-${searchParams?.endDate}`}
sheet="sheet1"
/>
</span>,
// <span style={{ visibility: 'hidden' }}>
// <ReactHTMLTableToExcel
// buttonText={'导出excel'}
// ref={downloadBtnRef}
// table="table-to-xls-saleTypeReport"
// filename={`类别统计报表${searchParams?.startDate}-${searchParams?.endDate}`}
// sheet="sheet1"
// />
// </span>,
<Button
key="new"
type="primary"
onClick={(e) => {
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
// 尝试一下 导出新方法
exportXlsxFromProColumnsExcelJS(columns,
reqDetailList,
`销售类别报表${searchParams?.startDate}-${searchParams?.endDate}`,
{
// topTitle: `营收汇总报表`, // 顶部大标题
}
)
} else {
message.error('暂无数据可导出!')
}
// if (reqDetailList && reqDetailList.length > 0) {
// setShowLoading(true)
// setTimeout(() => {
// setShowExportTable(true)
// setTimeout(() => {
// exportTable(e)
// }, 100)
// }, 100)
// } else {
// message.error('暂无数据可导出!')
// }
}}
>
excel
@ -377,12 +404,12 @@ const saleReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
if (tableData && tableData.length > 0) {
let Total_CountSum: number = 0
let Total_OffAmountSum: number = 0
let Total_SellAmountSum: number = 0
reqDetailList.forEach((item: any) => {
tableData.forEach((item: any) => {
Total_CountSum += item.Total_Count
Total_OffAmountSum += item.Total_OffAmount
Total_SellAmountSum += item.Total_SellAmount

View File

@ -11,6 +11,7 @@
import request from '@/utils/request';
import CryptoJs from 'crypto-js';
import type { CurrentUser } from '@/models/user';
import { validatePassword } from '@/utils/format';
export type LoginParamsType = {
UserPassport: string;
@ -23,9 +24,14 @@ export type LoginResult = {
currentAuthority: string;
status: string;
currentUser?: CurrentUser;
passwordRes?: any
};
export async function accountLogin(params: LoginParamsType): Promise<LoginResult> {
let realParams: any = JSON.parse(JSON.stringify(params))
let passwordRes: any = validatePassword(realParams.UserPassWord)
params.UserPassWord = CryptoJs.MD5(params.UserPassWord + params.UserPassport).toString();
const data = await request(`/Logging/UserLogin`, {
method: 'POST',
@ -46,6 +52,7 @@ export async function accountLogin(params: LoginParamsType): Promise<LoginResult
currentAuthority: 'admin',// data.Result_Data.UserName,
status: 'ok',
currentUser: user,
passwordRes: passwordRes
};
// const resp = await request('/api/login/account', {
// method: 'POST',

View File

@ -764,3 +764,324 @@ export function convertTreeFieldToNumber(tree: any[], key: string): any[] {
return newNode;
});
}
// 登录密码的正则校验 判断是否符合规则
export function validatePassword(password: string) {
if (!password || password.length < 8) {
return false;
}
const hasDigit = /\d/.test(password);
const hasLower = /[a-z]/.test(password);
const hasUpper = /[A-Z]/.test(password);
const hasSpecial = /[!@#$%^&*(),.?":{}|<>_\-+=~`[\]\\;]/.test(password);
// 统计符合的种类
let count = 0;
if (hasDigit) count++;
if (hasLower || hasUpper) count++; // 大小写都算作字母
if (hasSpecial) count++;
return count >= 2;
}
/**
*
* @param data
* @param sortField : "字段名 排序方式" (: "Total_Count desc""TotalRevenue.Revenue_Amount asc")
* @param childrenKey key名称 'children'
* @returns
*/
export function sortTreeData(data: any[], sortField: string, childrenKey: string = 'children'): any[] {
if (!data || !Array.isArray(data) || data.length === 0 || !sortField) {
return data;
}
const parts = sortField.trim().split(/\s+/);
if (parts.length !== 2) {
console.warn('排序字段格式错误,应为: "字段名 排序方式",如: "Total_Count desc" 或 "TotalRevenue.Revenue_Amount asc"');
return data;
}
const [fieldPath, sortOrder] = parts;
const isDesc = sortOrder.toLowerCase() === 'desc';
/**
*
* @param obj
* @param path "TotalRevenue.Revenue_Amount"
* @returns
*/
function getNestedValue(obj: any, path: string): any {
if (!obj || typeof obj !== 'object') {
return null;
}
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (current === null || current === undefined) {
return null;
}
current = current[key];
}
return current;
}
function sortRecursive(nodes: any[]): any[] {
// 对当前层级进行排序
const sortedNodes = [...nodes].sort((a, b) => {
const aValue = getNestedValue(a, fieldPath);
const bValue = getNestedValue(b, fieldPath);
// 处理 null, undefined 的情况,将它们排到最后
if (aValue == null && bValue == null) return 0;
if (aValue == null) return 1;
if (bValue == null) return -1;
// 数值比较
if (typeof aValue === 'number' && typeof bValue === 'number') {
return isDesc ? bValue - aValue : aValue - bValue;
}
// 字符串比较(先尝试转换为数字)
const aNum = Number(aValue);
const bNum = Number(bValue);
if (!isNaN(aNum) && !isNaN(bNum)) {
return isDesc ? bNum - aNum : aNum - bNum;
}
// 字符串比较
const aStr = String(aValue);
const bStr = String(bValue);
if (isDesc) {
return bStr.localeCompare(aStr);
} else {
return aStr.localeCompare(bStr);
}
});
// 递归排序子节点
return sortedNodes.map(node => {
if (node[childrenKey] && Array.isArray(node[childrenKey]) && node[childrenKey].length > 0) {
return {
...node,
[childrenKey]: sortRecursive(node[childrenKey])
};
}
return node;
});
}
return sortRecursive(data);
}
/**
* -
* @param data
* @param formatFields ( "obj.fieldName")
* @param enumFields ()
* @param enumData enumFields
* @param childrenKey key名称 'children'
* @returns
*/
export function formatTreeData(
data: any[],
formatFields: string[] = [],
enumFields: string[] = [],
enumData: any[] = [],
percentFields: string[] = [],
childrenKey: string = 'children'
): any[] {
if (!data || !Array.isArray(data) || data.length === 0) {
return data;
}
/**
*
* @param obj
* @param path "obj.fieldName"
* @returns
*/
function getNestedValue(obj: any, path: string): any {
if (!obj || typeof obj !== 'object') {
return undefined;
}
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (current === null || current === undefined) {
return undefined;
}
current = current[key];
}
return current;
}
/**
*
* @param obj
* @param path "obj.fieldName"
* @param value
*/
function setNestedValue(obj: any, path: string, value: any): void {
if (!obj || typeof obj !== 'object') {
return;
}
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (current[key] === null || current[key] === undefined || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
}
/**
*
* @param value
* @returns
*/
function formatNumber(value: any): string {
if (value === null || value === undefined || value === '') {
return '';
}
const num = Number(value);
if (isNaN(num)) {
return String(value);
}
return num.toLocaleString();
}
/**
*
* @param value
* @param enumData {1000:"枚举1",2000:"枚举2"}
* @returns
*/
function parseEnumValue(value: any, enumData: any): any {
if (!enumData) {
return value;
}
// 支持对象格式 {1000:"枚举1",2000:"枚举2"}
if (typeof enumData === 'object' && !Array.isArray(enumData)) {
// 直接匹配
let enumValue = enumData[value];
if (enumValue !== undefined) {
return enumValue;
}
// 类型转换匹配:尝试字符串和数字的相互转换
const valueStr = String(value);
const valueNum = Number(value);
// 如果原值是数字,尝试用字符串匹配
if (!isNaN(valueNum)) {
enumValue = enumData[valueStr];
if (enumValue !== undefined) {
return enumValue;
}
}
// 如果原值是字符串,尝试用数字匹配
if (!isNaN(valueNum)) {
enumValue = enumData[valueNum];
if (enumValue !== undefined) {
return enumValue;
}
}
// 遍历所有键进行宽松匹配
for (const key in enumData) {
if (String(key) === String(value) || Number(key) === Number(value)) {
return enumData[key];
}
}
return value;
}
// 支持数组格式(保持向下兼容)
if (Array.isArray(enumData) && enumData.length > 0) {
const enumItem = enumData.find(item => {
// 支持多种匹配方式,包括类型转换
const itemValue = item.value || item.id || item.key || item.code;
return itemValue === value ||
String(itemValue) === String(value) ||
Number(itemValue) === Number(value);
});
if (enumItem) {
// 返回枚举项的显示文本
return enumItem.label || enumItem.name || enumItem.text || enumItem.title || value;
}
}
return value;
}
function formatRecursive(nodes: any[]): any[] {
return nodes.map(node => {
// 深拷贝节点,避免修改原数据
const newNode = JSON.parse(JSON.stringify(node));
// 处理格式化字段
formatFields.forEach(fieldPath => {
const value = getNestedValue(newNode, fieldPath);
if (value !== undefined) {
const formattedValue = formatNumber(value);
setNestedValue(newNode, fieldPath, formattedValue);
}
});
// 处理枚举字段
enumFields.forEach((fieldPath, index) => {
const value = getNestedValue(newNode, fieldPath);
if (value !== undefined && enumData[index]) {
const parsedValue = parseEnumValue(value, enumData[index]);
setNestedValue(newNode, fieldPath, parsedValue);
}
});
// 处理百分号字段
percentFields.forEach((fieldPath) => {
const value = getNestedValue(newNode, fieldPath);
if (value !== undefined) {
const currentValueStr = String(value);
// 如果值后面还没有百分号,则添加
if (!currentValueStr.endsWith('%')) {
const percentValue = currentValueStr + '%';
setNestedValue(newNode, fieldPath, percentValue);
}
}
});
// 递归处理子节点
if (newNode[childrenKey] && Array.isArray(newNode[childrenKey]) && newNode[childrenKey].length > 0) {
newNode[childrenKey] = formatRecursive(newNode[childrenKey]);
}
return newNode;
});
}
return formatRecursive(data);
}

View File

@ -1,4 +1,4 @@
// 由 scripts/writeVersion.js 自动生成
export const VERSION = "4.5.61";
export const GIT_HASH = "c58125e";
export const BUILD_TIME = "2025-09-22T02:36:17.457Z";
export const VERSION = "4.5.62";
export const GIT_HASH = "d0c4edd";
export const BUILD_TIME = "2025-09-23T05:40:18.538Z";