财务统计接入后端
parent
0579658b6f
commit
0c91c3d29d
|
@ -0,0 +1,64 @@
|
|||
export interface StaffList {
|
||||
records: Staff[];
|
||||
/**
|
||||
* 总条数
|
||||
*/
|
||||
total: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主管部门
|
||||
*
|
||||
* Department
|
||||
*/
|
||||
export interface Department {
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
departmentId: number;
|
||||
/**
|
||||
* 部门主管
|
||||
*/
|
||||
departmentManager?: Staff;
|
||||
/**
|
||||
* 部门名
|
||||
*/
|
||||
departmentName?: string;
|
||||
/**
|
||||
* 部门员工
|
||||
*/
|
||||
staff?: Staff[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff
|
||||
*
|
||||
* 部门主管
|
||||
*/
|
||||
export interface Staff {
|
||||
banned?: boolean;
|
||||
/**
|
||||
* 主管部门
|
||||
*/
|
||||
managingDepartment?: Department;
|
||||
/**
|
||||
* 员工工作地点
|
||||
*/
|
||||
staffBase?: string;
|
||||
/**
|
||||
* 工作部门
|
||||
*/
|
||||
staffDepartments?: Department[];
|
||||
/**
|
||||
* 员工工号
|
||||
*/
|
||||
staffId: string;
|
||||
/**
|
||||
* 员工姓名
|
||||
*/
|
||||
staffName: string;
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
staffPassword?: string;
|
||||
}
|
|
@ -1,54 +1,53 @@
|
|||
import {Tabs} from "antd";
|
||||
import React from "react";
|
||||
import {Tabs, theme} from "antd";
|
||||
import React, {useState} from "react";
|
||||
import UserConfig from "./subpage/UserConfig";
|
||||
import CityConfig from "./subpage/CityConfig";
|
||||
import DepartmentConfig from "./subpage/DepartmentConfig";
|
||||
import OtherConfig from "./subpage/OtherConfig";
|
||||
|
||||
class Configuration extends React.Component<any,any> {
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
activatedTab: 0
|
||||
}
|
||||
}
|
||||
|
||||
tabItems = () => {
|
||||
return [{
|
||||
label: "用户配置",
|
||||
key: "0",
|
||||
children: <UserConfig activate={this.state.activatedTab === 0}/>
|
||||
},
|
||||
{
|
||||
function Configuration() {
|
||||
const {
|
||||
token: {colorBgContainer},
|
||||
} = theme.useToken();
|
||||
const [activatedTab, setActivatedTab] = useState(0)
|
||||
return (
|
||||
<Tabs
|
||||
type="line"
|
||||
activeKey={activatedTab.toString()}
|
||||
onChange={(key: string) => {
|
||||
setActivatedTab(Number(key))
|
||||
}}
|
||||
renderTabBar={(props, DefaultTabBar) => (
|
||||
<div style={{
|
||||
paddingLeft: 30,
|
||||
height: 72,
|
||||
background: colorBgContainer,
|
||||
display: "flex",
|
||||
alignItems: 'flex-end'
|
||||
}}>
|
||||
<DefaultTabBar {...props} style={{marginBottom: 0, height: 64}}/>
|
||||
</div>
|
||||
)}
|
||||
items={[{
|
||||
label: "用户配置",
|
||||
key: "0",
|
||||
children: <UserConfig activate={activatedTab === 0}/>
|
||||
}, {
|
||||
label: "城市配置",
|
||||
key: "1",
|
||||
children: <CityConfig activate={this.state.activatedTab === 1}/>
|
||||
},
|
||||
{
|
||||
children: <CityConfig activate={activatedTab === 1}/>
|
||||
}, {
|
||||
label: "部门配置",
|
||||
key: "2",
|
||||
children: <DepartmentConfig activate={this.state.activatedTab === 2}/>
|
||||
},
|
||||
{
|
||||
children: <DepartmentConfig activate={activatedTab === 2}/>
|
||||
}, {
|
||||
label: "其他配置",
|
||||
key: "3",
|
||||
children:<OtherConfig activate={this.state.activatedTab === 3}/>
|
||||
}]
|
||||
}
|
||||
tabChange = (key: string) => {
|
||||
this.setState({activatedTab: Number(key)})
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Tabs
|
||||
style={{backgroundColor: "white",paddingLeft:10}}
|
||||
activeKey={this.state.activatedTab.toString()}
|
||||
onChange={this.tabChange}
|
||||
type="line"
|
||||
items={this.tabItems()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
children: <OtherConfig activate={activatedTab === 3}/>
|
||||
}]}
|
||||
/>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default Configuration;
|
|
@ -1,12 +1,118 @@
|
|||
import React from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Button, Space, Table, Tag, Typography} from 'antd';
|
||||
import type {ColumnsType} from 'antd/es/table';
|
||||
import {Staff} from "../../../models/UserConfigModels";
|
||||
import axiosInstance from "../../../utils/axiosInstance";
|
||||
import {Department} from "../../../models/Staff";
|
||||
|
||||
class UserConfig extends React.Component<any,any> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>User Config</h1>
|
||||
</div>
|
||||
);
|
||||
const {Text, Link} = Typography;
|
||||
|
||||
|
||||
function UserConfig(props: any) {
|
||||
|
||||
const [departmentMap, setDepartmentMap] = useState(new Map<number, string>())
|
||||
|
||||
|
||||
const departmentToString = (staff: Staff) => {
|
||||
if (staff.staffId === 'manager')
|
||||
return '总经理'
|
||||
let result = !staff.managingDepartment ? '' : departmentMap.get(staff.managingDepartment.departmentId) + '主管'
|
||||
if (staff.staffDepartments)
|
||||
for (const department of staff.staffDepartments) {
|
||||
result += '\xa0\xa0' + departmentMap.get(department.departmentId)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const columns: ColumnsType<Staff> = [
|
||||
{
|
||||
title: '工号',
|
||||
dataIndex: 'staffId',
|
||||
key: 'staffId',
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'staffName',
|
||||
key: 'staffName',
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
dataIndex: 'managingDepartment',
|
||||
key: 'department',
|
||||
render: (value, record, index) => <Text>{departmentToString(record)}</Text>,
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
key: 'action',
|
||||
render: (_, record) => (
|
||||
<Space size="middle">
|
||||
<a>重置密码</a>
|
||||
<a>移除</a>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
const data: Staff[] = [
|
||||
{
|
||||
staffId: 'sb123007',
|
||||
staffName: 'John Brown',
|
||||
managingDepartment: {
|
||||
departmentId: 1
|
||||
},
|
||||
staffDepartments: [{
|
||||
departmentId: 1
|
||||
}]
|
||||
},
|
||||
{
|
||||
staffId: 'sb123008',
|
||||
staffName: 'John Brown',
|
||||
managingDepartment: {
|
||||
departmentId: 1
|
||||
},
|
||||
staffDepartments: [{
|
||||
departmentId: 1
|
||||
}]
|
||||
},
|
||||
{
|
||||
staffId: 'sb123009',
|
||||
staffName: 'John Brown',
|
||||
managingDepartment: {
|
||||
departmentId: 1
|
||||
},
|
||||
staffDepartments: [{
|
||||
departmentId: 1
|
||||
}]
|
||||
},
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
axiosInstance({
|
||||
url: 'common/department',
|
||||
method: 'get'
|
||||
}).then(response => {
|
||||
const departments: Department[] = response.data
|
||||
let map = new Map<number, string>()
|
||||
for (const department of departments)
|
||||
map.set(department.departmentId, department.departmentName)
|
||||
setDepartmentMap(map)
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{margin:30}}>
|
||||
<Table columns={columns} dataSource={data}/>
|
||||
<div style={{position:"absolute", left: 0, top: 0, width: '100%', height: 55, display: "flex", justifyContent:"flex-end", alignItems:"center", paddingRight: 50}}>
|
||||
<Space>
|
||||
<Button >批量导入</Button>
|
||||
<Button >创建用户</Button>
|
||||
</Space>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default UserConfig;
|
||||
|
||||
export default UserConfig
|
|
@ -100,6 +100,7 @@ function StatView() {
|
|||
token: {colorBgContainer, colorPrimary, colorSuccess, colorBorder},
|
||||
} = theme.useToken();
|
||||
|
||||
const [selectedTime, setSelectedTime] = useState<Dayjs|null>(null);
|
||||
const [type, setType] = useState<StatType>('month');
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [reimbursementAmount, setReimbursementAmount] = useState(0)
|
||||
|
@ -124,7 +125,7 @@ function StatView() {
|
|||
const getStatData = (time: Dayjs | null) => {
|
||||
console.log(time)
|
||||
setLoading(true)
|
||||
|
||||
setSelectedTime(time)
|
||||
axiosInstance({
|
||||
url: 'common/department',
|
||||
method: 'get'
|
||||
|
@ -146,7 +147,143 @@ function StatView() {
|
|||
dates.push(i + '月')
|
||||
}
|
||||
setDates(dates)
|
||||
setTimeout(() => {
|
||||
axiosInstance({
|
||||
url: 'financial/stats',
|
||||
method: 'get',
|
||||
params: {
|
||||
yearly: type==='year',
|
||||
target: time.format('YYYY-MM-DD')
|
||||
}
|
||||
}).then(response => {
|
||||
const statResponse: StatResponse = response.data
|
||||
setReimbursementAmount(statResponse.reimbursementAllTotalAmount/100.)
|
||||
setReimbursementAmountTrend(
|
||||
(statResponse.reimbursementAllTotalAmount - statResponse.lastAllTotalAmount) / statResponse.lastAllTotalAmount)
|
||||
setReimbursementAdditionalAmount(statResponse.reimbursementAdditionalTotalAmount/100.)
|
||||
setReimbursementAdditionalAmountTrend(
|
||||
(statResponse.reimbursementAdditionalTotalAmount - statResponse.lastAdditionalTotalAmount) / statResponse.lastAdditionalTotalAmount)
|
||||
|
||||
setAmounts([statResponse.invoiceLaunchCount, statResponse.reimbursementLaunchCount])
|
||||
setInvoiceKinds(statResponse.invoiceKindsStats.map((item) => {
|
||||
return {value: item.invoiceLaunchCount, name: invoiceTypeNameMap.get(item.invoiceKind)}
|
||||
}))
|
||||
|
||||
|
||||
let departmentAmountMap = new Map<number, Map<number, number>>()
|
||||
departmentMap.forEach(function (value, key, map) {
|
||||
departmentAmountMap.set(key, new Map<number, number>())
|
||||
})
|
||||
|
||||
for (const temporalDepartmentStat of statResponse.temporalDepartmentStats) {
|
||||
for (const departmentStat of temporalDepartmentStat.departmentStats) {
|
||||
let valueMap = departmentAmountMap.get(departmentStat.departmentId)
|
||||
if (valueMap) {
|
||||
valueMap.set(temporalDepartmentStat.value, departmentStat.reimbursementAmount)
|
||||
departmentAmountMap.set(departmentStat.departmentId, valueMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
let data: { value: number, name: string }[] = []
|
||||
let series: any = []
|
||||
|
||||
departmentAmountMap.forEach(function (valueMap, key, map) {
|
||||
let departmentName = departmentMap.get(key)
|
||||
if (!departmentName) return
|
||||
let total = 0
|
||||
valueMap.forEach(function (value, key) {
|
||||
total += value
|
||||
})
|
||||
data.push({value: total, name: departmentName})
|
||||
|
||||
let valueMapArray = Array.from(valueMap);
|
||||
valueMapArray.sort(function (a, b) {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
|
||||
series.push({
|
||||
name: departmentName,
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: valueMapArray.map(function ([key, value]) {
|
||||
return value
|
||||
})
|
||||
})
|
||||
})
|
||||
setDepartmentPieData(data)
|
||||
setDepartmentSeries(series)
|
||||
|
||||
|
||||
const geoCoordMap = Object.entries(GeoCoordMap)
|
||||
const getCoords = (placeName: string) => {
|
||||
return geoCoordMap.find(([name,]) => name.includes(placeName))
|
||||
}
|
||||
|
||||
let maxValue = 0
|
||||
for (const item of statResponse.reimbursementPlaceStats) {
|
||||
maxValue = Math.max(maxValue, item.reimbursementLaunchCount)
|
||||
}
|
||||
let mapDataTemp: any[] = []
|
||||
let departures = new Map<string, number>()
|
||||
let destinations = new Map<string, number>()
|
||||
for (const item of statResponse.reimbursementPlaceStats) {
|
||||
let departureValue = departures.get(item.departureName)
|
||||
if (departureValue)
|
||||
departures.set(item.departureName, departureValue + item.reimbursementLaunchCount)
|
||||
else
|
||||
departures.set(item.departureName, item.reimbursementLaunchCount)
|
||||
|
||||
let destinationValue = departures.get(item.destinationName)
|
||||
if (destinationValue)
|
||||
destinations.set(item.destinationName, destinationValue + item.reimbursementLaunchCount)
|
||||
else
|
||||
destinations.set(item.destinationName, item.reimbursementLaunchCount)
|
||||
|
||||
const fromCoords = getCoords(item.departureName)
|
||||
const toCoords = getCoords(item.destinationName)
|
||||
|
||||
if (fromCoords && toCoords) {
|
||||
mapDataTemp.push({
|
||||
fromName: fromCoords[0],
|
||||
toName: toCoords[0],
|
||||
coords: [fromCoords[1], toCoords[1]],
|
||||
value: item.reimbursementLaunchCount,
|
||||
lineStyle: {
|
||||
width: item.reimbursementLaunchCount / maxValue * 10
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
setMapData(mapDataTemp)
|
||||
|
||||
{
|
||||
let placeNames: string[] = []
|
||||
let reimbursementCounts: number[] = []
|
||||
departures.forEach(function (val, key, map) {
|
||||
placeNames.push(key)
|
||||
reimbursementCounts.push(val)
|
||||
})
|
||||
setDepartureNames(placeNames)
|
||||
setDepartureValues(reimbursementCounts)
|
||||
}
|
||||
{
|
||||
let placeNames: string[] = []
|
||||
let reimbursementCounts: number[] = []
|
||||
destinations.forEach(function (val, key, map) {
|
||||
placeNames.push(key)
|
||||
reimbursementCounts.push(val)
|
||||
})
|
||||
setDestinationNames(placeNames)
|
||||
setDestinationValues(reimbursementCounts)
|
||||
}
|
||||
setLoading(false)
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
})
|
||||
/* setTimeout(() => {
|
||||
let statResponse: StatResponse = {
|
||||
"temporalDepartmentStats": [
|
||||
{
|
||||
|
@ -296,131 +433,8 @@ function StatView() {
|
|||
}
|
||||
]
|
||||
}
|
||||
setReimbursementAmount(statResponse.reimbursementAllTotalAmount)
|
||||
setReimbursementAmountTrend(
|
||||
(statResponse.reimbursementAllTotalAmount - statResponse.lastAllTotalAmount) / statResponse.lastAllTotalAmount)
|
||||
setReimbursementAdditionalAmount(statResponse.reimbursementAdditionalTotalAmount)
|
||||
setReimbursementAdditionalAmountTrend(
|
||||
(statResponse.reimbursementAdditionalTotalAmount - statResponse.lastAdditionalTotalAmount) / statResponse.lastAdditionalTotalAmount)
|
||||
|
||||
setAmounts([statResponse.invoiceLaunchCount, statResponse.reimbursementLaunchCount])
|
||||
setInvoiceKinds(statResponse.invoiceKindsStats.map((item) => {
|
||||
return {value: item.invoiceLaunchCount, name: invoiceTypeNameMap.get(item.invoiceKind)}
|
||||
}))
|
||||
|
||||
|
||||
let departmentAmountMap = new Map<number, Map<number, number>>()
|
||||
departmentMap.forEach(function (value, key, map) {
|
||||
departmentAmountMap.set(key, new Map<number, number>())
|
||||
})
|
||||
|
||||
for (const temporalDepartmentStat of statResponse.temporalDepartmentStats) {
|
||||
for (const departmentStat of temporalDepartmentStat.departmentStats) {
|
||||
let valueMap = departmentAmountMap.get(departmentStat.departmentId)
|
||||
if (valueMap) {
|
||||
valueMap.set(temporalDepartmentStat.value, departmentStat.reimbursementAmount)
|
||||
departmentAmountMap.set(departmentStat.departmentId, valueMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
let data: { value: number, name: string }[] = []
|
||||
let series: any = []
|
||||
|
||||
departmentAmountMap.forEach(function (valueMap, key, map) {
|
||||
let departmentName = departmentMap.get(key)
|
||||
if (!departmentName) return
|
||||
let total = 0
|
||||
valueMap.forEach(function (value, key) {
|
||||
total += value
|
||||
})
|
||||
data.push({value: total, name: departmentName})
|
||||
|
||||
let valueMapArray = Array.from(valueMap);
|
||||
valueMapArray.sort(function (a, b) {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
|
||||
series.push({
|
||||
name: departmentName,
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: valueMapArray.map(function ([key, value]) {
|
||||
return value
|
||||
})
|
||||
})
|
||||
})
|
||||
setDepartmentPieData(data)
|
||||
setDepartmentSeries(series)
|
||||
|
||||
|
||||
const geoCoordMap = Object.entries(GeoCoordMap)
|
||||
const getCoords = (placeName: string) => {
|
||||
return geoCoordMap.find(([name,]) => name.includes(placeName))
|
||||
}
|
||||
|
||||
let maxValue = 0
|
||||
for (const item of statResponse.reimbursementPlaceStats) {
|
||||
maxValue = Math.max(maxValue, item.reimbursementLaunchCount)
|
||||
}
|
||||
let mapDataTemp: any[] = []
|
||||
let departures = new Map<string, number>()
|
||||
let destinations = new Map<string, number>()
|
||||
for (const item of statResponse.reimbursementPlaceStats) {
|
||||
let departureValue = departures.get(item.departureName)
|
||||
if (departureValue)
|
||||
departures.set(item.departureName, departureValue + item.reimbursementLaunchCount)
|
||||
else
|
||||
departures.set(item.departureName, item.reimbursementLaunchCount)
|
||||
|
||||
let destinationValue = departures.get(item.destinationName)
|
||||
if (destinationValue)
|
||||
destinations.set(item.destinationName, destinationValue + item.reimbursementLaunchCount)
|
||||
else
|
||||
destinations.set(item.destinationName, item.reimbursementLaunchCount)
|
||||
|
||||
const fromCoords = getCoords(item.departureName)
|
||||
const toCoords = getCoords(item.destinationName)
|
||||
|
||||
if (fromCoords && toCoords) {
|
||||
mapDataTemp.push({
|
||||
fromName: fromCoords[0],
|
||||
toName: toCoords[0],
|
||||
coords: [fromCoords[1], toCoords[1]],
|
||||
value: item.reimbursementLaunchCount,
|
||||
lineStyle: {
|
||||
width: item.reimbursementLaunchCount / maxValue * 10
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
setMapData(mapDataTemp)
|
||||
|
||||
{
|
||||
let placeNames: string[] = []
|
||||
let reimbursementCounts: number[] = []
|
||||
departures.forEach(function (val, key, map) {
|
||||
placeNames.push(key)
|
||||
reimbursementCounts.push(val)
|
||||
})
|
||||
setDepartureNames(placeNames)
|
||||
setDepartureValues(reimbursementCounts)
|
||||
}
|
||||
{
|
||||
let placeNames: string[] = []
|
||||
let reimbursementCounts: number[] = []
|
||||
destinations.forEach(function (val, key, map) {
|
||||
placeNames.push(key)
|
||||
reimbursementCounts.push(val)
|
||||
})
|
||||
setDestinationNames(placeNames)
|
||||
setDestinationValues(reimbursementCounts)
|
||||
}
|
||||
setLoading(false)
|
||||
}, 1000);
|
||||
}, 1000);*/
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
|
@ -444,7 +458,10 @@ function StatView() {
|
|||
alignItems: "center"
|
||||
}}>
|
||||
<Space>
|
||||
<Select value={type} onChange={setType}>
|
||||
<Select value={type} onChange={(value, option) => {
|
||||
setType(value)
|
||||
getStatData(selectedTime)
|
||||
}}>
|
||||
<Option value="month">月度统计</Option>
|
||||
<Option value="year">年度统计</Option>
|
||||
</Select>
|
||||
|
|
Loading…
Reference in New Issue