472 lines
18 KiB
TypeScript
472 lines
18 KiB
TypeScript
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);
|