diff --git a/package.json b/package.json index 5b0f60a..25a6392 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/leftSelectTree.tsx b/src/components/leftSelectTree.tsx new file mode 100644 index 0000000..01e0f73 --- /dev/null +++ b/src/components/leftSelectTree.tsx @@ -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(); + // 默认的服务区树 + const [allTreeViews, setAllTreeViews] = useState() + // 是否要显示全部 + const [isShowAllInTree, setIsShowAllInTree] = useState(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(false) + // 实际显示在左侧的服务区树 + const [treeView, setTreeView] = useState() + // 树要展开的行 + const [treeShowRow, setTreeShowRow] = useState() + // 筛选左侧的服务区树 + 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 ( +
+ + {/* src={searchIcon} */} + { + setShowServiceSearchBox(true) + }} /> + { + setCollapsible(!collapsible); + }} /> +
+ { + return [] + } + }} + isKeyPressSubmit + onFinish={(values: any) => { + return handleFilterServiceTree(values?.searchValue || '') + }} + > + + + + + + + + + + + + { + setShowServiceSearchBox(false) + }} /> +
+
} + colSpan={!collapsible ? "300px" : "60px"} + title={!collapsible ? "请选择服务区" : ""} + headerBordered + collapsed={collapsible} + > + {treeView && treeView.length > 0 ? 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) + } + }} + /> : ''} + + + ) +} + +export default connect(({ user }: ConnectState) => ({ + currentUser: user.currentUser, +}))(LeftSelectTree); diff --git a/src/pages/about/u/index.tsx b/src/pages/about/u/index.tsx index bb53f6e..05911d1 100644 --- a/src/pages/about/u/index.tsx +++ b/src/pages/about/u/index.tsx @@ -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() const actionRef = useRef(); const formRef = useRef(); - const [reqDetailList, setReqDetailList] = useState(); // 合计项数据源 + const [reqDetailList, setReqDetailList] = useState([{ + 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(); // 打印数据的内容 const [collapsible, setCollapsible] = useState(false) const [treeView, setTreeView] = useState() @@ -31,28 +55,413 @@ const saleRankReport = (props: any) => { // 查询的条件 const [searchParams, setSearchParams] = useState() - 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:
管理中心
, + titleStr: '管理中心', + dataIndex: 'SPREGIONTYPE_NAME', + width: 200, + hideInSearch: true, + ellipsis: true, + align: 'center' + }, + { + title:
服务区
, + titleStr: '服务区', + dataIndex: 'SERVERPART_NAME', + width: 200, + hideInSearch: true, + ellipsis: true, + align: 'center' + }, + { + title:
经营商户
, + titleStr: '经营商户', + dataIndex: 'MERCHANTS_NAME', + width: 200, + hideInSearch: true, + ellipsis: true, + align: 'center' + }, + { + title:
门店
, + titleStr: '门店', + dataIndex: 'SERVERPARTSHOP_NAME', + width: 150, + hideInSearch: true, + ellipsis: true, + align: 'center', + }, + { + title:
基础信息
, + dataIndex: 'termInfo', + titleStr: '基础信息', + // fixed: 'left', + hideInSearch: true, + children: [ + { + title:
期数
, + titleStr: '期数', + dataIndex: 'IndexStr', + width: 100, + align: 'center', + }, + { + title:
时限
, + titleStr: '时限', + dataIndex: 'COMPACT_STARTDATECOMPACT_ENDDATE', + width: 180, + align: 'center', + }, + { + title:
保底/固定租金
, + titleStr: '保底/固定租金', + exportType: "momeny", + align: 'right', + width: 140, + valueType: 'digit', + dataIndex: 'RENTFEE', + }, + { + title:
提成比率
, + titleStr: '提成比率', + exportType: "rate", + dataIndex: 'GUARANTEERATIO', + align: 'center', + width: 120, + } + ] + }, + { + title:
营业额
, + titleStr: '营业额', + dataIndex: '', + hideInSearch: true, + children: [ + { + title:
现金
, + titleStr: '现金', + exportType: "momeny", + align: 'right', + width: 120, + valueType: 'digit', + dataIndex: 'CASHPAY_AMOUNT', + }, + { + title:
移动支付
, + titleStr: '移动支付', + exportType: "momeny", + align: 'right', + width: 120, + valueType: 'digit', + dataIndex: 'MOBILEPAY_AMOUNT', + }, + { + title:
小计
, + titleStr: '小计', + exportType: "momeny", + align: 'right', + valueType: 'digit', + width: 120, + dataIndex: 'REVENUEDAILY_AMOUNTTotal', + }, - const tempTable = document.createElement('table'); - tempTable.appendChild(thead); - tempTable.appendChild(tbody); + ] + }, + { + title:
提成金额
, + titleStr: '提成金额', + exportType: "momeny", + align: 'right', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'GUARANTEERATIOAMOUNT', + }, + { + title:
业主收款
, + titleStr: '业主收款', + exportType: "momeny", + align: 'right', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'BANKACCOUNT_AMOUNT', + }, + { + title:
应收租金
, + titleStr: '应收租金', + exportType: "momeny", + align: 'right', + width: 120, + hideInSearch: true, + valueType: 'digit', + dataIndex: 'RECEIVABLEAMOUNT', + }, + { + title:
应收费用
, + titleStr: '应收费用', + exportType: "momeny", + align: 'right', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'SHOPEXPENSE_AMOUNT', + }, + { + title:
已缴费用
, + titleStr: '已缴费用', + exportType: "momeny", + align: 'right', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'PAID_AMOUNT', + }, + { + title:
退补款
, + titleStr: '退补款', + exportType: "momeny", + align: 'right', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'REFUND_SUPPLEMENT', + }, + { + title:
结算月份
, + titleStr: '结算月份', + align: 'center', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'STATISTICS_MONTH', + }, + { + title:
是否结算
, + titleStr: '是否结算', + align: 'center', + valueType: 'digit', + hideInSearch: true, + width: 120, + dataIndex: 'settlementStateObjApprovalstate', + }, + { + title:
备注(收退款)
, + 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) => { /> : '' } +
+
{ expandable={{ expandRowByClick: true }} + scroll={{ x: '100%' }} headerTitle={单品销售排行统计} 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); diff --git a/src/pages/user/login/index.tsx b/src/pages/user/login/index.tsx index beb6259..aa1201e 100644 --- a/src/pages/user/login/index.tsx +++ b/src/pages/user/login/index.tsx @@ -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 = (props) => { const [type, setType] = useState('account'); diff --git a/src/utils/generateFile.ts b/src/utils/generateFile.ts new file mode 100644 index 0000000..d31ca61 --- /dev/null +++ b/src/utils/generateFile.ts @@ -0,0 +1,4 @@ +// 生成 tsx 页面的方法 +export const handleCreatePageFile = () => { + +} \ No newline at end of file diff --git a/src/utils/publicMethods.ts b/src/utils/publicMethods.ts new file mode 100644 index 0000000..df778d6 --- /dev/null +++ b/src/utils/publicMethods.ts @@ -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}`; +}; + diff --git a/tsconfig.json b/tsconfig.json index 4da29c5..438ae46 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,7 +17,10 @@ "allowJs": true, "skipLibCheck": true, "experimentalDecorators": true, - "strict": true + "strict": true, + "paths": { + "@/*": ["src/*"] + } }, "include": [ "mock/**/*", diff --git a/umi4-admin-main.zip b/umi4-admin-main.zip index b407b44..76f655c 100644 Binary files a/umi4-admin-main.zip and b/umi4-admin-main.zip differ diff --git a/yarn.lock b/yarn.lock index af374f3..a078103 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"