fix(模块): 修复了一些 bug

This commit is contained in:
cclu 2025-03-07 18:30:25 +08:00
parent b4e5a3349c
commit 55d599824e
9 changed files with 860 additions and 46 deletions

View File

@ -15,7 +15,10 @@
"axios": "^1.7.7",
"crypto-js": "^4.2.0",
"dva": "^3.0.0-alpha.1",
"umi": "^4.3.24"
"moment": "^2.30.1",
"umi": "^4.3.24",
"xlsx": "^0.18.5",
"xlsx-style-fixed": "^0.0.4"
},
"devDependencies": {
"@types/express": "^5.0.0",

View File

@ -0,0 +1,237 @@
import { connect } from "umi";
// import type { ConnectState } from "@/models/connect";
import ProCard from "@ant-design/pro-card";
// import searchIcon from '@/assets/ai/searchIcon.png'
import { useRef, useState } from "react";
import { MenuFoldOutlined } from "@ant-design/icons";
import ProForm, { ProFormText } from "@ant-design/pro-form";
import { Button, Col, FormInstance, Row, Tree } from "antd";
// import { getServerpartTree } from "@/services/options";
import useRequest from "@ahooksjs/use-request";
// import './style.less'
// import { getMerchantShopTree } from "@/pages/Setting/Users/service";
type DetailProps = {
setSelectedId: any; // 把选择的服务区 可以带给外层
reload?: boolean; // 选择服务区 是否可以刷新组件之外的内容
actionRef?: any; // 和reload配合使用 确认要刷新的内容
currentUser: any; // 当前用户的信息
width?: number; // 组件的宽度
otherFun?: any; // 点击之后要进行的其他操作 多个操作可以写在一个方法里面传进来
setCollapsible: any; // 是否收缩组件
collapsible: boolean; // 收缩组件的判断依据
haveTest?: boolean;// 是否有测试服务区
handleGetLeftTreeData?: any // 拿到树数据的方法 必须要有输出值的
noWj?: any // 把万佳商贸隐藏
}
const LeftSelectTree = ({ setSelectedId, reload, actionRef, currentUser, width, otherFun, setCollapsible, collapsible, haveTest, handleGetLeftTreeData, noWj }: DetailProps) => {
const searchTreeRef = useRef<FormInstance>();
// 默认的服务区树
const [allTreeViews, setAllTreeViews] = useState<any>()
// 是否要显示全部
const [isShowAllInTree, setIsShowAllInTree] = useState<boolean>(false)
// 加载服务区树
const { loading: treeLoading, data: treeViews } = useRequest(async () => {
let data: any = []
if (currentUser?.UserPattern === 2000) {
data = await getMerchantShopTree({ BusinessManId: currentUser?.BusinessManID, ShowShop: false });
} else {
data = await getServerpartTree(currentUser?.ProvinceCode, currentUser?.CityAuthority, true, true, true)
}
console.log('datatree', data);
// 判断是否有多个片区的权限
if (data && data.length > 1) {
// 那么就显示全部
setIsShowAllInTree(true)
}
let list: any = []
data.forEach((item: any) => {
// 判断 item这一层已经是片区了 如果item.children 只有一个的话 那就说明 也只有一个服务区 那么就可以判断不显示全部和片区的树形选择层了
if (item.children && item.children.length === 1) {
list.push(item.children[0])
} else {
if (haveTest) {
if (item.value !== 424) {
list.push(item)
}
} else {
if (item.value !== 424 && item.value !== 586) {
list.push(item)
}
}
}
})
if (noWj) {
list = handleFilterList(list, 89)
}
console.log('list2', list);
if (handleGetLeftTreeData) {
let newData: any = await handleGetLeftTreeData()
console.log('newData', newData);
setTreeView(newData)
} else {
setTreeView(list)
}
setAllTreeViews(list)
return data
})
// 显示服务区树搜索框
const [showServiceSearchBox, setShowServiceSearchBox] = useState<boolean>(false)
// 实际显示在左侧的服务区树
const [treeView, setTreeView] = useState<any>()
// 树要展开的行
const [treeShowRow, setTreeShowRow] = useState<any>()
// 筛选左侧的服务区树
const handleFilterServiceTree = async (value?: string) => {
const resList: any = JSON.parse(JSON.stringify(allTreeViews))
setSelectedId('')
if (resList && resList.length > 0 && value) {
setTreeView([])
const list: any = []
resList.forEach((item: any) => {
if (item.label.indexOf(value) !== -1) {
list.push(item)
} else {
if (item.children && item.children.length > 0) {
const childrenList: any = []
item.children.forEach((subItem: any) => {
if (subItem.label.indexOf(value) !== -1) {
childrenList.push(subItem)
}
})
item.children = childrenList
if (childrenList && childrenList.length > 0) {
list.push(item)
}
}
}
})
if (list && list.length > 0) {
const keyList: any = ['0-0']
list.forEach((item: any) => {
keyList.push(item.key)
})
setTreeShowRow(keyList)
}
setTimeout(() => {
setTreeView(list)
}, 100)
} else {
setTreeView([])
setTreeShowRow([])
setTreeView(allTreeViews)
}
}
// 根据传入的服务区id筛选剔除掉这个服务区
const handleFilterList = (list: any, id: any) => {
let res: any = []
list.forEach((item: any) => {
if (item.value === id) {
} else {
res.push(item)
}
})
console.log('res', res);
return res
}
return (
<div>
<ProCard
style={{ width: !collapsible ? width ? `${width}px` : "300px" : "60px" }}
className="pageTable-leftnav"
bodyStyle={{ padding: 0, paddingTop: 20, paddingLeft: 20, width: !collapsible ? width ? `${width}px` : "300px" : "60px" }}
extra={<div className="leftSelectBox">
{/* src={searchIcon} */}
<img className="searchIcon" onClick={() => {
setShowServiceSearchBox(true)
}} />
<MenuFoldOutlined onClick={() => {
setCollapsible(!collapsible);
}} />
<div className="fixedBox" style={{ display: showServiceSearchBox ? 'flex' : 'none', width: width ? `${width}px` : '275px' }}>
<ProForm
formRef={searchTreeRef}
layout={'horizontal'}
submitter={{
render: () => {
return []
}
}}
isKeyPressSubmit
onFinish={(values: any) => {
return handleFilterServiceTree(values?.searchValue || '')
}}
>
<Row>
<Col span={15} className={'noBottom'}>
<ProFormText
name={'searchValue'}
fieldProps={{
placeholder: '请输入服务区名称'
}}
allowClear
/>
</Col>
<Col span={2}></Col>
<Col span={5}>
<Button type={'primary'} onClick={() => {
searchTreeRef.current?.submit()
}}></Button>
</Col>
</Row>
</ProForm>
<img style={{ width: '20px', height: '20px', cursor: 'pointer', marginLeft: '5px' }} src={close} onClick={() => {
setShowServiceSearchBox(false)
}} />
</div>
</div>}
colSpan={!collapsible ? "300px" : "60px"}
title={!collapsible ? "请选择服务区" : ""}
headerBordered
collapsed={collapsible}
>
{treeView && treeView.length > 0 ? <Tree
checkable
treeData={isShowAllInTree ? [{
label: '全部',
value: 0,
key: '0-0',
children: treeView
}] : treeView}
fieldNames={{
title: "label",
key: "key"
}}
blockNode
defaultExpandAll={isShowAllInTree ? false : true}
defaultExpandedKeys={isShowAllInTree ? treeShowRow && treeShowRow.length > 0 ? treeShowRow : ['0-0'] : []}
onCheck={(checkedKeys: React.Key[] | any, info) => {
const selectedIds = info.checkedNodes.filter((n: any) => n?.type === 1)
setSelectedId(selectedIds.map(n => n?.value)?.toString() || '')
if (reload) {
actionRef?.current?.reload()
}
if (otherFun) {
otherFun(info)
}
}}
/> : ''}
</ProCard>
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser,
}))(LeftSelectTree);

View File

@ -1,13 +1,16 @@
import { connect } from "umi";
import React, { useRef, useState } from "react";
import ProCard from "@ant-design/pro-card";
import { MenuFoldOutlined } from "@ant-design/icons";
import { MouseEvent, useRef, useState } from "react";
import type { FormInstance } from "antd";
import { Button, message, Space, Spin, Tree } from "antd";
import useRequest from "@ahooksjs/use-request";
import { getServerpartTree } from "@/services/options";
import { Button, message, Spin } from "antd";
import type { ActionType } from "@ant-design/pro-table";
import ProTable from "@ant-design/pro-table";
import * as XLSX from 'xlsx'; // 读写数据的核心工具(无需写样式时可用)
import XLSXStyle from 'xlsx-style-fixed';
import moment from "moment";
import { handleFormatNumber } from "@/utils/publicMethods";
import LeftSelectTree from "@/components/leftSelectTree";
import { UserConnectedProps } from "@/models/user";
const saleRankReport = (props: any) => {
@ -15,7 +18,28 @@ const saleRankReport = (props: any) => {
const downloadBtnRef = useRef<any>()
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const [reqDetailList, setReqDetailList] = useState<any>(); // 合计项数据源
const [reqDetailList, setReqDetailList] = useState<any>([{
SPREGIONTYPE_NAME: "1",
SERVERPART_NAME: "1",
MERCHANTS_NAME: "1",
SERVERPARTSHOP_NAME: "1",
IndexStr: "1",
COMPACT_STARTDATECOMPACT_ENDDATE: "1",
RENTFEE: "1",
GUARANTEERATIO: "1",
CASHPAY_AMOUNT: "1",
MOBILEPAY_AMOUNT: "1",
REVENUEDAILY_AMOUNTTotal: "1",
GUARANTEERATIOAMOUNT: "1",
BANKACCOUNT_AMOUNT: "1",
RECEIVABLEAMOUNT: "1",
SHOPEXPENSE_AMOUNT: "1",
PAID_AMOUNT: "1",
REFUND_SUPPLEMENT: "1",
STATISTICS_MONTH: "1",
settlementStateObjApprovalstate: "1",
REFUND_SUPPLEMENTdesc: "1",
}]); // 合计项数据源
const [printOut, setPrintOut] = useState<any>(); // 打印数据的内容
const [collapsible, setCollapsible] = useState<boolean>(false)
const [treeView, setTreeView] = useState<any>()
@ -31,28 +55,413 @@ const saleRankReport = (props: any) => {
// 查询的条件
const [searchParams, setSearchParams] = useState<any>()
const columns: any = []
const columns: any = [
{
title: '统计日期',
dataIndex: 'StatisticsYear',
valueType: "date",
hideInTable: true,
hideInDescriptions: true,
initialValue: moment().subtract('1', 'month'),
const exportTable = (e) => {
e.stopPropagation(); // 防止Collapse组件收起
const main = document.getElementsByClassName(`saleReportHideBox${printIndex}`)[0]
const thead = main.querySelector('thead').cloneNode(true); // 深克隆DOM节点
const tbody = main.querySelector('tbody').cloneNode(true); // 深克隆DOM节点
const container = document.querySelector('#hiddenBox');
fieldProps: {
picker: "year",
format: 'YYYY'
}
},
{
title: "结算状态",
dataIndex: 'SettlementState',
valueType: 'select',
hideInTable: true,
valueEnum: {
"9": "已结算",
"0": "待结算",
"-1": "提前退场",
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '管理中心',
dataIndex: 'SPREGIONTYPE_NAME',
width: 200,
hideInSearch: true,
ellipsis: true,
align: 'center'
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '服务区',
dataIndex: 'SERVERPART_NAME',
width: 200,
hideInSearch: true,
ellipsis: true,
align: 'center'
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '经营商户',
dataIndex: 'MERCHANTS_NAME',
width: 200,
hideInSearch: true,
ellipsis: true,
align: 'center'
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '门店',
dataIndex: 'SERVERPARTSHOP_NAME',
width: 150,
hideInSearch: true,
ellipsis: true,
align: 'center',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: 'termInfo',
titleStr: '基础信息',
// fixed: 'left',
hideInSearch: true,
children: [
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '期数',
dataIndex: 'IndexStr',
width: 100,
align: 'center',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '时限',
dataIndex: 'COMPACT_STARTDATECOMPACT_ENDDATE',
width: 180,
align: 'center',
},
{
title: <div style={{ textAlign: 'center' }}>/</div>,
titleStr: '保底/固定租金',
exportType: "momeny",
align: 'right',
width: 140,
valueType: 'digit',
dataIndex: 'RENTFEE',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '提成比率',
exportType: "rate",
dataIndex: 'GUARANTEERATIO',
align: 'center',
width: 120,
}
]
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '营业额',
dataIndex: '',
hideInSearch: true,
children: [
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '现金',
exportType: "momeny",
align: 'right',
width: 120,
valueType: 'digit',
dataIndex: 'CASHPAY_AMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '移动支付',
exportType: "momeny",
align: 'right',
width: 120,
valueType: 'digit',
dataIndex: 'MOBILEPAY_AMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '小计',
exportType: "momeny",
align: 'right',
valueType: 'digit',
width: 120,
dataIndex: 'REVENUEDAILY_AMOUNTTotal',
},
const tempTable = document.createElement('table');
tempTable.appendChild(thead);
tempTable.appendChild(tbody);
]
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '提成金额',
exportType: "momeny",
align: 'right',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'GUARANTEERATIOAMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '业主收款',
exportType: "momeny",
align: 'right',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'BANKACCOUNT_AMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '应收租金',
exportType: "momeny",
align: 'right',
width: 120,
hideInSearch: true,
valueType: 'digit',
dataIndex: 'RECEIVABLEAMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '应收费用',
exportType: "momeny",
align: 'right',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'SHOPEXPENSE_AMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '已缴费用',
exportType: "momeny",
align: 'right',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'PAID_AMOUNT',
},
{
title: <div style={{ textAlign: 'center' }}>退</div>,
titleStr: '退补款',
exportType: "momeny",
align: 'right',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'REFUND_SUPPLEMENT',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '结算月份',
align: 'center',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'STATISTICS_MONTH',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
titleStr: '是否结算',
align: 'center',
valueType: 'digit',
hideInSearch: true,
width: 120,
dataIndex: 'settlementStateObjApprovalstate',
},
{
title: <div style={{ textAlign: 'center' }}>退</div>,
titleStr: '备注(收退款)',
align: 'center',
hideInSearch: true,
width: 120,
dataIndex: 'REFUND_SUPPLEMENTdesc',
},
]
tempTable.setAttribute('id', 'table-to-xls-saleRankReport'); // 给table添加id值与按钮上的table字段对应
const exportTable = (isHaveChildren: boolean, isHaveTitle?: boolean) => {
// isHaveChildren 判断表头是否有子集
// isHaveTitle 判断是否有title
let columnsNoChildren: any = []
// 先创建需要显示的列表头
let headerArray: any = isHaveChildren ? [[], []] : []
// 需要合并单元格的内容
let mergesList: any = []
// 因为子集也拆出来了 这样实际的行数会比columns多 所以得知道多了多少
let moreColumns: number = 0
// 显示的列表有多少个
let showItemNumber: number = 0
container.appendChild(tempTable); // 把创建的节点添加到页面容器中
let showIndex: number = 0
if (columns && columns.length > 0) {
columns.forEach((item: any, index: number) => {
if (!item.hideInTable) {
showItemNumber += 1
if (item.children && item.children.length > 0) {
mergesList.push({
s: { r: 0 + (isHaveTitle ? 1 : 0), c: showIndex },
e: { r: 0 + (isHaveTitle ? 1 : 0), c: showIndex + item.children.length - 1 },
})
moreColumns += item.children.length - 1
showIndex += item.children.length
item.children.forEach((subItem: any) => {
if (!subItem.hideInTable) {
columnsNoChildren.push(subItem)
headerArray[0].push(item.titleStr)
headerArray[1].push(subItem.titleStr)
}
})
} else {
columnsNoChildren.push(item)
headerArray[0].push(item.titleStr)
if (isHaveChildren) {
headerArray[1].push(item.titleStr)
mergesList.push({
s: { r: 0 + (isHaveTitle ? 1 : 0), c: showIndex },
e: { r: 1 + (isHaveTitle ? 1 : 0), c: showIndex },
})
}
showIndex += 1
}
}
})
}
setShowLoading(false)
// **创建工作表**
let ws = XLSX.utils.aoa_to_sheet([]);
downloadBtnRef.current.handleDownload();
setShowExportTable(false)
tempTable.remove() // 防止重复打印一个内容
// 设置列宽:动态计算每列的最大内容长度
let colWidths: any = [];
// 设置样式:对齐方式
const cellStyle: any = {
alignment: {
horizontal: 'center',
vertical: 'center'
}
};
if (headerArray && headerArray.length > 0) {
headerArray.forEach((row: any, rowIndex: any) => {
row.forEach((cell: any, colIndex: any) => {
const cellRef = XLSX.utils.encode_cell({ r: (isHaveChildren ? rowIndex : rowIndex) + (isHaveTitle ? 1 : 0), c: colIndex });
ws[cellRef] = {
v: cell, t: 's', s: cellStyle
};
const cellLength = getCharWidth((cell && cell.toString()) || '');
if (!colWidths[colIndex]) {
colWidths[colIndex] = cellLength;
} else {
colWidths[colIndex] = Math.max(colWidths[colIndex], cellLength);
}
})
})
}
// 设置工作表的范围(必需)
const range = {
s: { r: 0, c: 0 }, // 开始行列
e: { r: reqDetailList.length + (isHaveChildren ? 2 : 1) + (isHaveTitle ? 1 : 0), c: columnsNoChildren.length } // 结束行列
};
ws["A1"] = {
v: `(${searchParams?.StatisticsYear})年度结算汇总表`, t: 's', s: {
font: {
bold: true, // 字体加粗
color: { rgb: "#000" }, // 字体颜色红色
sz: 20 // 字号为14
},
alignment: {
horizontal: 'center', // 水平居中
vertical: 'center' // 垂直居中
},
}
};
if (isHaveTitle) {
mergesList.push(
{
s: { r: 0, c: 0 },
e: { r: 0, c: columnsNoChildren.length },
}
)
}
ws['!merges'] = mergesList
ws['!ref'] = XLSX.utils.encode_range(range); // 设置单元格范围
if (reqDetailList && reqDetailList.length > 0) {
reqDetailList.forEach((item: any, index: number) => {
columnsNoChildren.forEach((subItem: any, subIndex: number) => {
for (let key in item) {
if (subItem.dataIndex === key) {
let res = item[key]
const cellRef = XLSX.utils.encode_cell({ r: (isHaveChildren ? index + 2 : index + 1) + (isHaveTitle ? 1 : 0), c: subIndex });
let newRes = res ? subItem.exportType === 'momeny' ? handleFormatNumber(res) : subItem.exportType === 'rate' ? `${res}%` : res : subItem.exportType === 'momeny' ? '0' : ""
ws[cellRef] = {
v: newRes, t: 's', s: {
alignment: {
horizontal: subItem.align, // 水平居中
vertical: 'center' // 垂直居中
}
}
};
const cellLength = getCharWidth((newRes && newRes.toString()) || '');
if (!colWidths[subIndex]) {
colWidths[subIndex] = cellLength;
} else {
colWidths[subIndex] = Math.max(colWidths[subIndex], cellLength);
}
}
}
})
})
}
ws['!cols'] = colWidths.map((width: any) => ({ wch: width + 2 })); // wch 表示字符宽度
// 创建工作簿
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
const wbout = XLSXStyle.write(wb, { bookType: 'xlsx', type: 'binary' });
const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `(${searchParams?.StatisticsYear})年度结算汇总表.xlsx`;
document.body.appendChild(a);
a.click();
setTimeout(() => {
URL.revokeObjectURL(url);
document.body.removeChild(a);
setShowLoading(false)
}, 100);
}
const s2ab = (s: string) => {
const buf = new ArrayBuffer(s.length);
const view = new Uint8Array(buf);
for (let i = 0; i < s.length; i++) {
view[i] = s.charCodeAt(i) & 0xff;
}
return buf;
}
// 判断字符类型的辅助函数
const getCharWidth = (cell: any) => {
if (!cell) {
return ''
}
if (typeof cell === 'number') {
return cell.toString().length > 150 ? 150 : cell.toString().length; // 数字通常和英文字符宽度相同
} else if (/[^\x00-\xff]/.test(cell)) {
return cell.length * 1.8 > 300 ? 300 : cell.length * 1.8; // 中文字符宽度大约是英文字符的2倍
} else {
return cell.length > 150 ? 150 : cell.length; // 英文字符的宽度为1
}
}
@ -105,9 +514,11 @@ const saleRankReport = (props: any) => {
/> : ''
}
</div>
<div id='hiddenBox' style={{ position: 'fixed', zIndex: -1, top: 0, left: 0 }} />
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
<LeftSelectTree setSelectedId={setSelectedId} setCollapsible={setCollapsible} collapsible={collapsible} />
<div style={{
width: !collapsible ? 'calc(100% - 300px)' : 'calc(100% - 60px)',
paddingTop: 0,
@ -122,13 +533,13 @@ const saleRankReport = (props: any) => {
expandable={{
expandRowByClick: true
}}
scroll={{ x: '100%' }}
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}></span>}
search={{ span: 6 }}
request={async (params) => {
if (!selectedId) {
return
}
setSearchParams(params)
}}
toolbar={{
@ -145,7 +556,7 @@ const saleRankReport = (props: any) => {
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
exportTable(true, true)
}, 100)
}, 100)
} else {
@ -164,6 +575,8 @@ const saleRankReport = (props: any) => {
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(saleRankReport);
export default connect(
({ user }: { user: UserConnectedProps['user'] }) => ({
user
}),
)(saleRankReport);

View File

@ -1,23 +1,17 @@
import type { FC } from 'react';
import { useState, Fragment } from 'react';
import { Col, Divider, notification, Row, Space, Tabs, Typography } from 'antd';
import { useState } from 'react';
import { Col, Divider, Row, Space, Typography } from 'antd';
import { connect, Link } from 'umi';
import {
AlipayCircleOutlined,
LockFilled,
LockOutlined,
MobileOutlined,
TaobaoCircleOutlined,
UserOutlined,
WeiboCircleOutlined,
} from '@ant-design/icons';
import { ProFormCaptcha, ProFormCheckbox, ProFormText, LoginForm } from '@ant-design/pro-components';
import { LockFilled, UserOutlined } from '@ant-design/icons';
import { ProFormText, LoginForm } from '@ant-design/pro-components';
import Footer from '@/components/Footer';
import { retrieveCaptcha } from '@/services/user';
import type { UserConnectedProps } from '@/models/user';
import styles from './index.less';
import logo from '@/assets/logo.svg'
import loginBg from '@/assets/login-bg.png'
const logo = '@/assets/logo.svg'
const loginBg = '@/assets/login-bg.png'
// import logo from '@/assets/logo.svg'
// import loginBg from '@/assets/login-bg.png'
const Index: FC<UserConnectedProps> = (props) => {
const [type, setType] = useState<string>('account');

View File

@ -0,0 +1,4 @@
// 生成 tsx 页面的方法
export const handleCreatePageFile = () => {
}

View File

@ -0,0 +1,24 @@
// 封装的一些公共方法
// 保留两位小数 不满两位小数的用0补齐 有千分号
export const handleFormatNumber = (num: any) => {
// 确保 num 是数字类型
const parsedNum = Number(num);
// 如果转换后仍然是 NaN返回原始值
if (isNaN(parsedNum)) return "NaN";
// 如果输入为 0直接返回 '0.00'
if (parsedNum === 0) return "0.00";
// 先处理千分号格式,保留两位小数
let [integer, decimal] = parsedNum.toFixed(2).split("."); // 保留两位小数
// 处理千分号
integer = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
// 返回格式化后的数字
return `${integer}.${decimal}`;
};

View File

@ -17,7 +17,10 @@
"allowJs": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"strict": true
"strict": true,
"paths": {
"@/*": ["src/*"]
}
},
"include": [
"mock/**/*",

Binary file not shown.

140
yarn.lock
View File

@ -3524,6 +3524,11 @@ add-dom-event-listener@^1.1.0:
dependencies:
object-assign "4.x"
adler-32@, adler-32@~1.3.0:
version "1.3.1"
resolved "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
ajv-keywords@^3.5.2:
version "3.5.2"
resolved "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
@ -4275,6 +4280,14 @@ caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001688:
resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz#26cd429cf09b4fd4e745daf4916039c794d720f6"
integrity sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==
cfb@>=0.10.0, cfb@~1.2.1:
version "1.2.2"
resolved "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
dependencies:
adler-32 "~1.3.0"
crc-32 "~1.2.0"
chalk@4, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@ -4363,6 +4376,20 @@ cliui@^8.0.1:
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
codepage@~1.15.0:
version "1.15.0"
resolved "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
codepage@~1.3.6:
version "1.3.8"
resolved "https://registry.npmmirror.com/codepage/-/codepage-1.3.8.tgz#4f2e5d7c0975de28f88498058dcb5afcab6a5f71"
integrity sha512-cjAoQW5L/TCKWRbzt/xGBvhwJKQFhcIVO0jWQtpKQx4gr9qvXNkpRfq6gSmjjA8dB2Is/DPOb7gNwqQXP7UgTQ==
dependencies:
commander ""
concat-stream ""
voc ""
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -4392,6 +4419,11 @@ colord@^2.9.3:
resolved "https://registry.npmmirror.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
colors@0.6.2:
version "0.6.2"
resolved "https://registry.npmmirror.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc"
integrity sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@ -4399,6 +4431,11 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
commander@:
version "13.1.0"
resolved "https://registry.npmmirror.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46"
integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@ -4449,6 +4486,16 @@ concat-map@0.0.1:
resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
concat-stream@:
version "2.0.0"
resolved "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.0.2"
typedarray "^0.0.6"
connect-history-api-fallback@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
@ -4572,6 +4619,11 @@ cosmiconfig@^8.2.0:
parse-json "^5.2.0"
path-type "^4.0.0"
crc-32@, crc-32@~1.2.0, crc-32@~1.2.1:
version "1.2.2"
resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
create-ecdh@^4.0.4:
version "4.0.4"
resolved "https://registry.npmmirror.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
@ -6126,6 +6178,16 @@ forwarded@0.2.0:
resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
frac@0.3.1:
version "0.3.1"
resolved "https://registry.npmmirror.com/frac/-/frac-0.3.1.tgz#577677b7fdcbe6faf7c461f1801d34137cda4354"
integrity sha512-1Lzf2jOjhIkRaa013KlxNOn2D9FemmQNeYUDpEIyPeFXmpLvbZXJOlaayMBT6JKXx+afQFgQ1QJ4kaF7Z07QFQ==
frac@~1.1.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
fraction.js@^4.3.7:
version "4.3.7"
resolved "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
@ -7356,6 +7418,13 @@ jsonfile@^6.0.1:
object.assign "^4.1.4"
object.values "^1.1.6"
jszip@2.4.0:
version "2.4.0"
resolved "https://registry.npmmirror.com/jszip/-/jszip-2.4.0.tgz#487a93b76c3bffa6cb085cd61eb934eabe2d294f"
integrity sha512-m+yvNmYfRCaf1gr5YFT5e3fnSqLnE9McbNyRd0fNycsT0HltS19NKc18fh3Lvl/AIW/ovL6/MQ1JnfFg4G3o4A==
dependencies:
pako "~0.2.5"
keyv@^4.5.3, keyv@^4.5.4:
version "4.5.4"
resolved "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
@ -7833,7 +7902,7 @@ minimist-options@4.1.0:
resolved "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
moment@^2.29.4:
moment@^2.29.4, moment@^2.30.1:
version "2.30.1"
resolved "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
@ -8261,6 +8330,11 @@ package-json-from-dist@^1.0.0:
resolved "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
pako@~0.2.5:
version "0.2.9"
resolved "https://registry.npmmirror.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==
pako@~1.0.5:
version "1.0.11"
resolved "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
@ -9626,7 +9700,7 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.3, readable
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0:
readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0:
version "3.6.2"
resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@ -10295,6 +10369,22 @@ sprintf-js@~1.0.2:
resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
ssf@~0.11.2:
version "0.11.2"
resolved "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
dependencies:
frac "~1.1.2"
ssf@~0.8.1:
version "0.8.2"
resolved "https://registry.npmmirror.com/ssf/-/ssf-0.8.2.tgz#b9d4dc6a1c1bcf76f8abfa96d7d7656fb2abecd6"
integrity sha512-+ZkFDAG+ImJ48DcZvabx6YTrZ67DKkM0kbyOOtH73mbUEvNhQWWgRZrHC8+k7GuGKWQnACYLi7bj0eCt1jmosQ==
dependencies:
colors "0.6.2"
frac "0.3.1"
voc ""
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
@ -10949,6 +11039,11 @@ typed-array-length@^1.0.7:
possible-typed-array-names "^1.0.0"
reflect.getprototypeof "^1.0.6"
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
typescript@^5.0.4, typescript@^5.6.2:
version "5.7.3"
resolved "https://registry.npmmirror.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e"
@ -11161,6 +11256,11 @@ vm-browserify@^1.0.1:
resolved "https://registry.npmmirror.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
voc@:
version "1.2.0"
resolved "https://registry.npmmirror.com/voc/-/voc-1.2.0.tgz#c459024531d71067c09e2c0c2bda6c2b13af32d8"
integrity sha512-BOuDjFFYvJdZO6e/N65AlaDItXo2TgyLjeyRYcqgAPkXpp5yTJcvkL2n+syO1r9Qc5g96tfBD2tuiMhYDmaGcA==
walker@^1.0.8:
version "1.0.8"
resolved "https://registry.npmmirror.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f"
@ -11273,11 +11373,21 @@ which@^2.0.1:
dependencies:
isexe "^2.0.0"
wmf@~1.0.1:
version "1.0.2"
resolved "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
word-wrap@^1.2.5:
version "1.2.5"
resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
word@~0.3.0:
version "0.3.0"
resolved "https://registry.npmmirror.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
@ -11317,6 +11427,32 @@ write-file-atomic@^5.0.1:
imurmurhash "^0.1.4"
signal-exit "^4.0.1"
xlsx-style-fixed@^0.0.4:
version "0.0.4"
resolved "https://registry.npmmirror.com/xlsx-style-fixed/-/xlsx-style-fixed-0.0.4.tgz#13ec5318a76ad386cb72e0f20e3ebddde52f41f3"
integrity sha512-rk4J+Z4mA7hdJ3k6UTq4jMQjPZCB2JGeXDztsPMDV/9DRywiKVtvcgiHTx8yG1qu8fnxvp/jBIGTRdTSd0Qxyg==
dependencies:
adler-32 ""
cfb ">=0.10.0"
codepage "~1.3.6"
commander ""
crc-32 ""
jszip "2.4.0"
ssf "~0.8.1"
xlsx@^0.18.5:
version "0.18.5"
resolved "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
dependencies:
adler-32 "~1.3.0"
cfb "~1.2.1"
codepage "~1.15.0"
crc-32 "~1.2.1"
ssf "~0.11.2"
wmf "~1.0.1"
word "~0.3.0"
xtend@^4.0.0:
version "4.0.2"
resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"