ylj20011123 e876df2bde update
2025-09-30 14:42:08 +08:00

472 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { connect } from "umi";
import type { CurrentUser } from "umi";
import type { ConnectState } from "@/models/connect";
import React, { useRef, useState } from "react";
import ProCard from "@ant-design/pro-card";
import { MenuFoldOutlined } from "@ant-design/icons";
import type { FormInstance } from "antd";
import { Avatar, Button, Menu, message, Space, Spin, Tree } from "antd";
import useRequest from "@ahooksjs/use-request";
import { getServerpartTree, handleCallLogs, handleGetCashierStatus } from "@/services/options";
import type { ActionType } from "@ant-design/pro-table";
import ProTable from "@ant-design/pro-table";
import ReactHTMLTableToExcel from "react-html-table-to-excel";
import SubMenu from "antd/lib/menu/SubMenu";
import { handleGetDailyRevenueReport } from "@/pages/reports/audit/curDailyReport/service";
import moment from "moment";
import * as numeral from "numeral";
import ProDescriptions from "@ant-design/pro-descriptions";
import PageTitleBox from "@/components/PageTitleBox";
import LeftSelectTree from "../../settlementAccount/component/leftSelectTree";
const curDailyReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
const { currentUser } = props
const downloadBtnRef = useRef<any>()
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const [reqDetailList, setReqDetailList] = useState<any>(); // 合计项数据源
const [printOut, setPrintOut] = useState<any>(); // 打印数据的内容
const [collapsible, setCollapsible] = useState<boolean>(false)
const [treeView, setTreeView] = useState<any>()
// 加载服务区树
const { loading: treeLoading, data: treeViews } = useRequest(async () => {
const data = await getServerpartTree(currentUser?.ProvinceCode, currentUser?.CityAuthority, true, true, true)
setTreeView(data)
return data
})
// 树相关的属性和方法
const [selectedId, setSelectedId] = useState<string>()
// 导出的加载效果
const [showLoading, setShowLoading] = useState<boolean>(false)
// 是否显示打印的表格
const [showExportTable, setShowExportTable] = useState<boolean>(false)
const [currenMenu, setCurrenMenu] = useState<any>(); // 当前选中左侧菜单的服务区节点
// 因为要查全部 所以不能用是否选择服务区去判断 得把第一次请求return出去
const [isFirst, setIsFirst] = useState<boolean>(true)
// 拿到现在查到数据的服务区名称
const [currentServerpartName, setCurrentServerpartName] = useState<string>('')
const [isAll, setIsAll] = useState<boolean>(false)
const columns: any = [
{
title: '门店信息',
dataIndex: 'shopBaseInfo',
hideInSearch: true,
children: [
{
title: '序号',
width: 120,
dataIndex: 'index',
valueType: 'index',
ellipsis: true,
align: 'center'
},
{
title: '门店',
width: 180,
dataIndex: 'ServerPartShop_Name',
ellipsis: true,
align: 'center',
render: (_, record) => {
return record?.ServerPartShop_Name || record?.ServerPart_Name || record?.SpregionType_Name
}
}
]
},
{
title: '东(南)区',
dataIndex: 'RevenueA',
hideInSearch: true,
children: [
{
title: '收银状态',
width: 140,
align: 'center',
ellipsis: true,
dataIndex: 'RevenueA.ConnectState',
// hideInTable: isAll,
render: (_, record) => {
return record?.ServerPartShop_Id ? handleGetCashierStatus(record?.RevenueA.TradeDate, 10) ?
<span style={{ color: '#00bfff' }}>{'收银状态正常'}</span> :
<span style={{ color: '#c71585' }}>{'网络未连接'}</span> : '-'
}
// render:(_,record)=>{
// return record?.ServerPartShop_Id? new Date(moment(record?.RevenueA.TradeDate).format('YYYY-MM-DD HH:mm:ss')).getTime()>new Date().getTime() || new Date(moment(record?.RevenueA.TradeDate).format('YYYY-MM-DD HH:mm:ss')).getTime() + 5*60*1000 > new Date().getTime()?
// <span style={{color:'#00bfff'}}>{'收银状态正常'}</span>:<span style={{color:'#c71585'}}>{'网络未连接'}</span>:'-'
// }
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 100,
align: 'right',
valueType: 'digit',
ellipsis: true,
dataIndex: 'RevenueA.TicketCount',
render: (_, record) => {
return `${record?.RevenueA.TicketCount ? record?.RevenueA.TicketCount : '-'}`
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 100,
align: 'right',
valueType: 'digit',
dataIndex: 'RevenueA.AvgTicketAmount',
render: (_, record) => {
return `${record?.RevenueA.AvgTicketAmount ? record?.RevenueA.AvgTicketAmount : '-'}`
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 100,
align: 'right',
valueType: 'digit',
dataIndex: 'RevenueA.TotalAmount',
render: (_, record) => {
return `${record?.RevenueA.TotalAmount ? numeral(record?.RevenueA.TotalAmount).format('0,0.00') : '-'}`
}
},
]
},
{
title: '西(北)区',
dataIndex: 'RevenueB',
align: 'center',
hideInSearch: true,
children: [
{
title: '收银状态',
align: 'center',
width: 140,
dataIndex: 'RevenueB.ConnectState',
// hideInTable: isAll,
render: (_, record) => {
return record?.ServerPartShop_Id ? handleGetCashierStatus(record?.RevenueB.TradeDate, 10) ?
<span style={{ color: '#00bfff' }}>{'收银状态正常'}</span> :
<span style={{ color: '#c71585' }}>{'网络未连接'}</span> : '-'
}
// render:(_,record)=>{
// return record?.ServerPartShop_Id? new Date(moment(record?.RevenueB.TradeDate).format('YYYY-MM-DD HH:mm:ss')).getTime()>new Date().getTime() || new Date(moment(record?.RevenueB.TradeDate).format('YYYY-MM-DD HH:mm:ss')).getTime() + 5*60*1000 > new Date().getTime()?
// <span style={{color:'#00bfff'}}>{'收银状态正常'}</span>:<span style={{color:'#c71585'}}>{'网络未连接'}</span>:'-'
// }
},
{
title: <div style={{ textAlign: 'center' }}></div>,
align: 'right',
valueType: 'digit',
width: 100,
dataIndex: 'RevenueB.TicketCount',
render: (_, record) => {
return `${record?.RevenueB.TicketCount ? record?.RevenueB.TicketCount : '-'}`
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
align: 'right',
valueType: 'digit',
width: 100,
dataIndex: 'RevenueB.AvgTicketAmount',
render: (_, record) => {
return `${record?.RevenueB.AvgTicketAmount ? record?.RevenueB.AvgTicketAmount : '-'}`
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
align: 'right',
valueType: 'digit',
width: 100,
dataIndex: 'RevenueB.TotalAmount',
render: (_, record) => {
return `${record?.RevenueB.TotalAmount ? numeral(record?.RevenueB.TotalAmount).format('0,0.00') : '-'}`
}
},
]
},
{
title: '合计',
dataIndex: 'TotalRevenue',
align: 'center',
hideInSearch: true,
children: [
{
title: '收银状态',
align: 'center',
width: 140,
dataIndex: 'TotalRevenue.ConnectState',
// hideInTable: !isAll,
render: (_, record) => {
return record?.ServerPartShop_Id ? handleGetCashierStatus(record?.TotalRevenue.TradeDate, 10) ?
<span style={{ color: '#00bfff' }}>{'收银状态正常'}</span> :
<span style={{ color: '#c71585' }}>{'网络未连接'}</span> : '-'
}
// render:(_,record)=>{
// return record?.ServerPartShop_Id? new Date(moment(record?.TotalRevenue.TradeDate).format('YYYY-MM-DD HH:mm:ss')).getTime()>new Date().getTime() || new Date(moment(record?.TotalRevenue.TradeDate).format('YYYY-MM-DD HH:mm:ss')).getTime() + 5*60*1000 > new Date().getTime()?
// <span style={{color:'#00bfff'}}>{'收银状态正常'}</span>:<span style={{color:'#c71585'}}>{'网络未连接'}</span>:'-'
// }
},
{
title: <div style={{ textAlign: 'center' }}></div>,
align: 'right',
valueType: 'digit',
width: 100,
dataIndex: '',
render: (_, record) => {
return `${record?.TotalRevenue.TicketCount ? record?.TotalRevenue.TicketCount : '-'}`
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
align: 'right',
valueType: 'digit',
width: 100,
dataIndex: '',
render: (_, record) => {
return `${record?.TotalRevenue.AvgTicketAmount ? record?.TotalRevenue.AvgTicketAmount : '-'}`
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
align: 'right',
valueType: 'digit',
width: 100,
dataIndex: '',
render: (_, record) => {
return `${record?.TotalRevenue.TotalAmount ? numeral(record?.TotalRevenue.TotalAmount).format('0,0.00') : '-'}`
}
},
]
}
]
const exportTable = (e) => {
e.stopPropagation(); // 防止Collapse组件收起
const main = document.getElementsByClassName('saleReportHideBox')[0]
const thead = main.querySelector('thead').cloneNode(true); // 深克隆DOM节点
const tbody = main.querySelector('tbody').cloneNode(true); // 深克隆DOM节点
const container = document.querySelector('#hiddenBox');
const tempTable = document.createElement('table');
tempTable.appendChild(thead);
tempTable.appendChild(tbody);
tempTable.setAttribute('id', 'table-to-xls-curDailyReport'); // 给table添加id值与按钮上的table字段对应
container.appendChild(tempTable); // 把创建的节点添加到页面容器中
setShowLoading(false)
downloadBtnRef.current.handleDownload();
setShowExportTable(false)
tempTable.remove() // 防止重复打印一个内容
}
// 查询的条件
const [searchParams, setSearchParams] = useState<any>()
const getMenuDom = (data: any[], callback: (item: any) => void) => {
return (data.map((element: any) => {
// 绑定嵌套树的子节点
if (element.children && element.children.length > 0) {
return (
<SubMenu title={<span>{element.label}</span>}
icon={element.ico ? <Avatar src={element.ico} size={16} style={{ marginRight: 4 }} shape="square" /> : null}
key={`${element.key || element.value}`}
onTitleClick={(item) => {
// 选中一级菜单
if (!currenMenu || item.key !== `${currenMenu?.key}`) {
callback.call(callback, item)
}
item.domEvent.stopPropagation();
}}
>
{element.children && element.children.length > 0 && getMenuDom(element.children, callback)}
</SubMenu>
)
}
return (<Menu.Item icon={element.ico ? <Avatar src={element.ico} size={16} shape="square" /> : null}
key={`${element.key || element.value}`}>{element.desc && element.desc !== '0/0' ? <><span>{element.label}</span>
<span style={{ position: 'absolute', right: '10', top: '9px', lineHeight: '20px', padding: '2px 3px' }}>
[<span style={{ color: 'red' }}>{element.desc.split('/')[0]}</span>/<span style={{ color: '#1890ff' }}>{element.desc.split('/')[1]}</span>]</span></> : element.label}</Menu.Item>)
}))
}
const loadSelectedId = (item?: any) => {
// 选中的子菜单key
const [type, value] = item.key.split('-')
if (type === '1') {
setCurrenMenu(value)
// actionRef?.current?.reload()
} else {
setCurrenMenu('')
}
}
return (
<div ref={(el) => {
// 打印报表
if (!reqDetailList || reqDetailList.length === 0) return;
setPrintOut(el);
}} >
{
showLoading ?
<div
style={{
width: '100%',
height: '100%',
background: 'rgba(0,0,0,0.1)',
position: 'fixed',
zIndex: 5,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '15px 20px 10px',
background: '#fff',
borderRadius: '8px',
width: '200px'
}}>
<Spin />
<span style={{ marginLeft: '5px' }}>...</span>
</div>
</div> : ''
}
<div className={'saleReportHideBox'} style={{ position: 'fixed', zIndex: -1, top: 0, left: 0 }}>
{
showExportTable && reqDetailList && reqDetailList.length > 0 ?
<ProTable
columns={columns}
dataSource={reqDetailList}
pagination={false}
expandable={{
defaultExpandAllRows: true
}}
/> : ''
}
</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} otherFun={(info: any) => {
const all = info.checkedNodes.filter(n => n?.key === '0-0')
if (all && all.length > 0) {
// setIsAll(true)
setSelectedId(undefined)
} else {
// setIsAll(false)
const selectedIds = info.checkedNodes.filter(n => n?.type === 1)
setSelectedId(selectedIds.map(n => n?.value)?.toString() || '')
}
}} />
<div style={{
width: !collapsible ? 'calc(100% - 300px)' : 'calc(100% - 60px)',
paddingTop: 0,
paddingBottom: 0,
paddingRight: 0
}}>
<ProTable
actionRef={actionRef}
formRef={formRef}
columns={columns}
rowKey={(record) => {
return `${record?.SpregionType_Id}-${record?.ServerPart_Id}-${record?.ServerPartShop_Id}`
}}
bordered
// headerTitle={`${currentServerpartName ||''}营收实时汇总表`}
headerTitle={<PageTitleBox props={props} />}
search={{ span: 6 }}
scroll={{ x: 1400 }}
request={async (params) => {
setCurrentServerpartName('')
if (isFirst) {
setIsFirst(false)
return
}
if (selectedId) {
setIsAll(false)
} else {
setIsAll(true)
}
handleCallLogs()
const req = {
provinceCode: currentUser?.ProvinceCode || '340000',
ServerpartIds: selectedId || ''
}
// setSearchParams(params)
const data = await handleGetDailyRevenueReport(req)
console.log('data', data)
if (data && data.length > 0) {
setReqDetailList(data)
if (selectedId) {
setCurrentServerpartName(data[0].children[0].ServerPart_Name)
}
return { data, success: true }
}
return { data: [], success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-curDailyReport"
filename={`当日营收报表${moment().format('YYYY-MM-DD')}`}
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)
} else {
message.error('暂无数据可导出!')
}
}}
>
excel
</Button>
]
}}
tableExtraRender={() => {
if (reqDetailList && reqDetailList.length > 0) {
let Current_SellAmountSum: number = 0
reqDetailList.forEach((item: any) => {
Current_SellAmountSum += item.TotalRevenue.TotalAmount
})
return <div style={{ paddingLeft: 30, paddingBottom: 0 }}>
<ProDescriptions column={2} className="commity-sale-description" labelStyle={{ color: "#00000073" }}>
<ProDescriptions.Item label="今日营收合计" valueType="money" contentStyle={{ color: 'orangered' }}>{Current_SellAmountSum || '0.00'}</ProDescriptions.Item>
<ProDescriptions.Item label="统计时间">{`${moment().format('YYYY/MM/DD 0:00:00')}${moment().format('YYYY/MM/DD HH:mm:ss')}`}</ProDescriptions.Item>
</ProDescriptions>
</div>
}
}}
/>
</div>
</div>
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(curDailyReport);