ylj20011123 debd5be7f6 update
2025-08-28 18:50:55 +08:00

628 lines
20 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 { Button, message, Space, Spin, Tree, Drawer } from "antd";
import useRequest from "@ahooksjs/use-request";
import { getServerpartTree, handleCallLogs } 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 moment from "moment";
import { handleGetCheckAccountReport } from "./service";
import upload from "@/assets/upload.png";
import { handleGetCHECKACCOUNTList } from "@/pages/reports/audit/feedback/service";
import PageTitleBox from "@/components/PageTitleBox";
const checkAccountReport: React.FC<{ currentUser: CurrentUser }> = (props) => {
const { currentUser } = props
const downloadBtnRef = useRef<any>()
const actionRef = useRef<ActionType>();
const actionDrawerRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const formDrawerRef = 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 [currentRow, setCurrentRow] = useState<any>()
// 显示抽屉
const [showDetail, setShowDetail] = useState<boolean>(false)
const columns: any = [
{
title: '统计时间',
dataIndex: 'search_date',
valueType: 'dateRange',
hideInTable: true,
hideInDescriptions: true,
initialValue: [moment().subtract(7, 'days'), moment().add(-1, 'day')],
search: {
transform: (value) => {
return {
startDate: value[0],
endDate: value[1],
};
},
},
fieldProps: {
disabledDate: (current: any) => current && current > moment().endOf('day')
}
},
{
title: '稽查类型',
dataIndex: 'checkType',
hideInTable: true,
hideInDescriptions: true,
valueEnum: {
1: "现场稽查",
2: "区域稽查",
3: "公司稽查",
4: "指令稽查",
},
initialValue: "1"
},
{
title: '统计口径',
dataIndex: 'ShowShop',
hideInTable: true,
hideInDescriptions: true,
valueType: 'select',
valueEnum: {
"1": "服务区",
"2": "门店",
},
initialValue: "1"
},
{
title: '服务区信息',
hideInSearch: true,
dataIndex: 'basicInfo',
align: 'center',
children: [
// {
// title:'序号',
// dataIndex:'index',
// },
{
title: '服务区名称',
width: 200,
ellipsis: true,
dataIndex: 'Name',
align: 'center',
render: (_, record) => {
return record?.ServerpartId ? <a onClick={() => {
setCurrentRow(record)
setShowDetail(true)
}}>{record?.Name}</a> : <span>{record?.Name}</span>
}
},
{
title: '稽查点位',
width: 120,
align: 'center',
dataIndex: 'TypePoint',
},
]
},
{
title: '异常信息(误差率大于0.2%)',
hideInSearch: true,
align: 'center',
dataIndex: 'errorInfo',
children: [
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
valueType: 'digit',
dataIndex: 'ExauditCount',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
dataIndex: 'ExauditRate',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
dataIndex: 'FeedbackRate',
},
]
},
{
title: '稽核信息',
dataIndex: 'reportInfo',
hideInSearch: true,
children: [
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
dataIndex: 'TypeCount',
align: 'right',
valueType: 'digit',
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
dataIndex: 'PricePercent',
render: (_, record) => {
return record?.PricePercent ? `${record?.PricePercent}` : '-'
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
valueType: 'digit',
dataIndex: 'PriceMore'
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
valueType: 'digit',
dataIndex: 'PriceLess'
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
valueType: 'digit',
dataIndex: 'TypeDays'
},
{
title: <div style={{ textAlign: 'center' }}></div>,
width: 120,
align: 'right',
dataIndex: 'DaysCpercent'
},
]
}
]
const drawerColumns: any = [
{
title: '处理状态',
hideInTable: true,
dataIndex: 'TREATMENT_MARKSTATE',
valueType: 'select',
valueEnum: {
0: '全部',
1: '未反馈',
2: '未冲正'
},
initialValue: '0'
},
{
title: '统计时间',
dataIndex: 'search_date',
valueType: 'dateRange',
hideInTable: true,
hideInDescriptions: true,
colSize: 1,
initialValue: [moment().add(-1, 'month').format('YYYY-MM-DD'), moment().add(-1, "day").format('YYYY-MM-DD')],
search: {
transform: (value) => {
return {
CHECK_STARTDATE: value[0],
CHECK_ENDDATE: value[1],
};
},
},
fieldProps: {
disabledDate: (current: any) => current && current > moment()
}
},
{
title: '稽查类型',
hideInTable: true,
dataIndex: 'CHECK_TYPE',
valueType: 'select',
valueEnum: {
"": "全部",
"现场稽查": "现场稽查",
"区域稽查": "区域稽查",
"公司稽查": "公司稽查",
},
initialValue: ""
},
{
title: '图片上传',
hideInTable: true,
hideInSearch: true,
dataIndex: ''
},
{
title: '稽核误差率',
hideInTable: true,
dataIndex: 'ERROR_RATE',
valueType: 'select',
valueEnum: {
0: '全部',
1: '大于0.2%'
},
initialValue: '1'
},
{
title: '上传标识',
hideInTable: true,
dataIndex: 'HasImage',
valueType: 'select',
valueEnum: {
"0": '全部',
"1": '支持',
"2": '不支持'
},
initialValue: "0"
},
{
title: <div style={{ textAlign: 'center' }}>{'序号'}</div>,
hideInSearch: true,
width: 70,
valueType: 'index',
dataIndex: ''
},
{
title: <div style={{ textAlign: 'center' }}>{'服务区名称'}</div>,
hideInSearch: true,
width: 120,
dataIndex: 'SERVERPART_NAME',
// render:(_,record)=>{
// return <div style={{display:'flex',alignItems:'center'}}>
// {record?.SERVERPART_NAME ||''}
// {
// record?.HasImage ?
// <img style={{width:'20px',height:'20px'}} src={upload}/>
// :''
// }
// </div>
// }
},
{
title: <div style={{ textAlign: 'center' }}>{'门店名称'}</div>,
hideInSearch: true,
width: 150,
dataIndex: 'SHOPNAME',
render: (_, record) => {
return <div style={{ display: 'flex', alignItems: 'center' }}>
{
record?.HasImage ?
<img style={{ width: '20px', height: '20px' }} src={upload} />
: ''
}
{record?.SHOPNAME || ''}
</div>
}
},
{
title: <div style={{ textAlign: 'center' }}>{'稽核反馈'}</div>,
width: 200,
ellipsis: true,
hideInSearch: true,
dataIndex: 'CHECKACCOUNT_DESC'
},
{
title: <div style={{ textAlign: 'center' }}>{'稽核误差率'}</div>,
width: 140,
hideInSearch: true,
align: 'right',
dataIndex: 'ERROR_RATE',
render: (_, record) => {
return record?.ERROR_RATE ?
<span style={{ color: 'red', fontWeight: 'bold' }}>{`${record?.ERROR_RATE}%`}</span>
: '-'
}
},
{
title: <div style={{ textAlign: 'center' }}>{'长短款/冲正流水'}</div>,
width: 160,
hideInSearch: true,
align: 'right',
dataIndex: 'DIFFERENT_PRICE',
render: (_, record) => {
return <span style={{ color: record.DIFFERENT_PRICE < 0 || record?.REPLENISH_AMOUNT < 0 ? 'red' : record.DIFFERENT_PRICE > 0 || record?.REPLENISH_AMOUNT > 0 ? '#008000' : '', fontWeight: 'bold' }}>
{`${record.DIFFERENT_PRICE || '0'}/${record?.REPLENISH_AMOUNT || '0'}`}
</span>
}
},
{
title: <div style={{ textAlign: 'center' }}>{'稽核现金/对客现金'}</div>,
width: 160,
hideInSearch: true,
dataIndex: 'CASH',
align: 'right',
render: (_, record) => {
return `${record.CASHPAY || ''}/${record?.CASH || ''}`
}
},
{
title: <div style={{ textAlign: 'center' }}>{'对客营收'}</div>,
width: 120,
hideInSearch: true,
align: 'right',
dataIndex: 'TOTALSELLAMOUNT'
},
{
title: <div style={{ textAlign: 'center' }}>{'稽查时间'}</div>,
width: 160,
hideInSearch: true,
align: 'right',
dataIndex: 'CHECK_ENDDATE',
render: (_, record) => {
return record?.CALIBRATOR_DATE ? moment(record?.CHECK_ENDDATE).format('YYYY-MM-DD HH:mm:ss') : '-'
}
}
]
const exportTable = (e) => {
e.stopPropagation(); // 防止Collapse组件收起
const main = document.getElementsByClassName('checkAccountReportHideBox')[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-checkAccountReport'); // 给table添加id值与按钮上的table字段对应
container.appendChild(tempTable); // 把创建的节点添加到页面容器中
setShowLoading(false)
downloadBtnRef.current.handleDownload();
setShowExportTable(false)
tempTable.remove() // 防止重复打印一个内容
}
// 查询的条件
const [searchParams, setSearchParams] = useState<any>()
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={'checkAccountReportHideBox'} 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' }}>
<ProCard
style={{ width: !collapsible ? "300px" : "60px" }}
className="pageTable-leftnav"
bodyStyle={{ padding: 0, paddingTop: 20, paddingLeft: 20, width: !collapsible ? "300px" : "60px" }}
extra={<MenuFoldOutlined onClick={() => {
setCollapsible(!collapsible)
}} />}
colSpan={!collapsible ? "300px" : "60px"}
title={!collapsible ? "请选择服务区" : ""}
headerBordered
collapsed={collapsible}
>
{treeView && treeView.length > 0 ? <Tree
checkable
treeData={[{
label: '全部',
value: 0,
key: '0-0',
children: treeView
}]}
fieldNames={{
title: "label",
key: "key"
}}
blockNode
defaultExpandedKeys={['0-0']}
onCheck={(checkedKeys: React.Key[] | any, info) => {
const selectedIds = info.checkedNodes.filter(n => n?.type === 1)
setSelectedId(selectedIds.map(n => n?.value)?.toString() || '')
// actionRef?.current?.reload()
// getData(selectedIds.map(n => n?.value)?.toString() || '')
}}
// switcherIcon={<PlusOutlined />}
/> : ''}
</ProCard>
<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) => record?.index + record?.Id}
bordered
headerTitle={<PageTitleBox props={props} />}
search={{ span: 6 }}
scroll={{ y: 'calc(100vh - 470px)' }}
pagination={false}
request={async (params) => {
if (!selectedId) {
return
}
const req = {
...params,
ServerpartIds: selectedId || '',
ShowShop: params?.ShowShop === '1' ? false : params?.ShowShop === '2' ? true : ''
}
handleCallLogs()
setSearchParams(params)
console.log('req', req)
const data = await handleGetCheckAccountReport(req)
console.log('data', data)
let list: any = []
if (data && data.length > 0) {
list = JSON.parse(JSON.stringify(data))
list.forEach((item: any, index: number) => {
item.index = index + 1
if (item.children && item.children.length > 0) {
item.children.forEach((subItem: any, subIndex: number) => {
subItem.index = `${index + 1}.${subIndex + 1}`
if (subItem.children && subItem.children.length > 0) {
subItem.children.forEach((thirdItem: any, thirdIndex: number) => {
thirdItem.index = `${index + 1}.${subIndex + 1}.${thirdIndex + 1}`
})
}
})
}
})
}
console.log('list', list)
setReqDetailList(list)
return { data: list, success: true }
}}
toolbar={{
actions: [
<span style={{ visibility: 'hidden' }}>
<ReactHTMLTableToExcel
buttonText={'导出excel'}
ref={downloadBtnRef}
table="table-to-xls-checkAccountReport"
filename={`稽核情况汇总表${searchParams?.startDate}-${searchParams?.endDate}`}
sheet="sheet1"
/>
</span>,
<Button
key="new"
type="primary"
onClick={(e) => {
if (reqDetailList && reqDetailList.length > 0) {
setShowLoading(true)
setTimeout(() => {
setShowExportTable(true)
setTimeout(() => {
exportTable(e)
}, 100)
}, 100)
} else {
message.error('暂无数据可导出!')
}
}}
>
excel
</Button>
]
}}
/>
</div>
</div>
<Drawer
width="80%"
visible={showDetail}
onClose={() => {
setCurrentRow(undefined);
setShowDetail(false);
}}
bodyStyle={{ backgroundColor: "#f9f9f9", padding: 16 }}
destroyOnClose
closable={false}
>
<div style={{ width: '100%' }}>
<ProTable
actionRef={actionDrawerRef}
formRef={formDrawerRef}
columns={drawerColumns}
search={{ span: 6 }}
request={async (params: any) => {
console.log('currentRow', currentRow)
if (!currentRow?.ServerpartId) {
return
}
const req = {
SearchParameter: {
...params,
TREATMENT_MARKSTATE: params.TREATMENT_MARKSTATE === '0' ? '' : params.TREATMENT_MARKSTATE,
SERVERPART_IDS: currentRow?.ServerpartId,
// SERVERPARTSHOP_ID: currentRow?.Id ?,
HasImage: params.HasImage === '0' ? null : params.HasImage === '1' ? true : params.HasImage === '2' ? false : '',
VALID: 1,// 有效
},
PageIndex: 1,
PageSize: 99999
}
handleCallLogs()
const data = await handleGetCHECKACCOUNTList(req)
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
/>
</div>
</Drawer>
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser
}))(checkAccountReport);