628 lines
20 KiB
TypeScript
628 lines
20 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 { 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);
|