279 lines
8.4 KiB
TypeScript
279 lines
8.4 KiB
TypeScript
import type { AnalysisMoneyAmount } from '@/types/money/analysis'
|
|
import dayjs from 'dayjs'
|
|
import { useEffect, useState } from 'react'
|
|
import { ScrollView, Text, TouchableOpacity, View } from 'react-native'
|
|
import Svg from 'react-native-svg'
|
|
import { VictoryChart, VictoryLabel, VictoryLine, VictoryPie, VictoryTheme, VictoryTooltip } from 'victory-native'
|
|
import { ADatePicker, ADateRangePicker, ASegmentedTabs, LucideIcon } from '@/components/common/ao'
|
|
import EmptyState from '@/components/common/EmptyStatus'
|
|
import CustomHeader from '@/components/custom/Header'
|
|
import PagerTabs from '@/components/custom/PagerTabs'
|
|
import { analysisMoneyLineApi, analysisMoneyPieApi } from '@/request/api/money/analysis'
|
|
import { MoneyCategoryEnum } from '@/types/money/category'
|
|
import { getCurrentYear, getCurrentYearMonth, getEndOfMonth, getStartOfMonth } from '@/utils/time'
|
|
|
|
interface AnalysisContentProps {
|
|
analysisType: MoneyCategoryEnum
|
|
}
|
|
|
|
export default function Analysis() {
|
|
function AnalysisContent({ analysisType }: AnalysisContentProps) {
|
|
// 按月0 按年1 自定义2
|
|
const [timeType, setTimeType] = useState<number>(0)
|
|
|
|
// 开始结束时间
|
|
const [startDate, setStartDate] = useState(getCurrentYearMonth())
|
|
const [endDate, setEndDate] = useState('')
|
|
|
|
// 显示
|
|
const [showDatePicker, setShowDatePicker] = useState(false)
|
|
|
|
// 数据
|
|
const [lineRecords, setLineRecords] = useState<AnalysisMoneyAmount[]>([])
|
|
const [pieRecords, setPieRecords] = useState<AnalysisMoneyAmount[]>([])
|
|
|
|
// 请求
|
|
function fetchChartsData() {
|
|
let start = ''
|
|
let end = ''
|
|
|
|
const selectedStartDate = dayjs(startDate)
|
|
const selectedEndDate = dayjs(endDate)
|
|
|
|
let periodType = 0
|
|
|
|
if (timeType === 0) {
|
|
start = selectedStartDate.startOf('month').format('YYYY-MM-DD')
|
|
end = selectedStartDate.endOf('month').format('YYYY-MM-DD')
|
|
|
|
periodType = 0
|
|
}
|
|
else if (timeType === 1) {
|
|
start = selectedStartDate.startOf('year').format('YYYY-MM-DD')
|
|
end = selectedStartDate.endOf('year').format('YYYY-MM-DD')
|
|
|
|
periodType = 1
|
|
}
|
|
else {
|
|
console.log(selectedStartDate.isSame(selectedEndDate, 'day'))
|
|
console.log(selectedStartDate.isSame(selectedEndDate, 'month'))
|
|
console.log(selectedStartDate.isSame(selectedEndDate, 'year'))
|
|
|
|
if (selectedStartDate.isSame(selectedEndDate, 'month')) {
|
|
periodType = 0
|
|
start = selectedStartDate.startOf('month').format('YYYY-MM-DD')
|
|
end = selectedEndDate.endOf('month').format('YYYY-MM-DD')
|
|
}
|
|
else if (selectedStartDate.isSame(selectedEndDate, 'year')) {
|
|
periodType = 1
|
|
start = selectedStartDate.startOf('year').format('YYYY-MM-DD')
|
|
end = selectedEndDate.endOf('year').format('YYYY-MM-DD')
|
|
}
|
|
else {
|
|
periodType = 2
|
|
start = selectedStartDate.format('YYYY-MM-DD')
|
|
end = selectedEndDate.format('YYYY-MM-DD')
|
|
}
|
|
}
|
|
|
|
analysisMoneyLineApi({
|
|
start_date: start,
|
|
end_date: end,
|
|
type: analysisType,
|
|
period_type: periodType,
|
|
}).then((res) => {
|
|
if (res.isSuccess) {
|
|
setLineRecords(res.data.records)
|
|
}
|
|
})
|
|
|
|
analysisMoneyPieApi({
|
|
start_date: start,
|
|
end_date: end,
|
|
type: analysisType,
|
|
period_type: periodType,
|
|
}).then((res) => {
|
|
if (res.isSuccess) {
|
|
setPieRecords(res.data.records)
|
|
}
|
|
})
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchChartsData()
|
|
}, [timeType, startDate, endDate])
|
|
|
|
return (
|
|
<ScrollView
|
|
className="p-4"
|
|
>
|
|
<ASegmentedTabs
|
|
value={timeType}
|
|
onChange={(index) => {
|
|
setTimeType(index)
|
|
if (index === 2) {
|
|
// 自定义类型,本月的 1号 - 终止号
|
|
setStartDate(getStartOfMonth())
|
|
setEndDate(getEndOfMonth())
|
|
}
|
|
else if (index === 1) {
|
|
// 按年
|
|
setStartDate(getCurrentYear())
|
|
setEndDate('')
|
|
}
|
|
else {
|
|
// 按月
|
|
setStartDate(getCurrentYearMonth())
|
|
setEndDate('')
|
|
}
|
|
}}
|
|
tabs={[
|
|
{ key: '1', label: '按月' },
|
|
{ key: '2', label: '按年' },
|
|
{ key: '3', label: '自定义' },
|
|
]}
|
|
/>
|
|
|
|
<TouchableOpacity
|
|
className="flex flex-row justify-center items-center"
|
|
>
|
|
<LucideIcon icon="CalendarDays" size={14} color="#666" clickable={false} />
|
|
<Text className="font-semibold text-lg mr-2 ml-1">{startDate}</Text>
|
|
{timeType === 2 && (
|
|
<>
|
|
<Text> - </Text>
|
|
<Text className="font-semibold text-lg mx-1">
|
|
{endDate}
|
|
</Text>
|
|
</>
|
|
)}
|
|
<LucideIcon icon="ChevronDown" size={16} color="#666" clickable={false} />
|
|
</TouchableOpacity>
|
|
|
|
<View className="mt-4">
|
|
<Text className="text-lg font-semibold text-gray-700">趋势分析</Text>
|
|
|
|
<VictoryChart
|
|
height={220}
|
|
theme={VictoryTheme.material}
|
|
>
|
|
<VictoryLine
|
|
interpolation="catmullRom"
|
|
data={lineRecords}
|
|
animate={{
|
|
duration: 1000,
|
|
}}
|
|
/>
|
|
</VictoryChart>
|
|
</View>
|
|
|
|
<View
|
|
className="mt-4"
|
|
>
|
|
<Text className="text-lg font-semibold text-gray-700">分类构成</Text>
|
|
|
|
{
|
|
pieRecords.length > 0
|
|
? (
|
|
<VictoryPie
|
|
height={250}
|
|
animate={{ duration: 1000 }}
|
|
data={pieRecords}
|
|
theme={VictoryTheme.material}
|
|
/>
|
|
)
|
|
: (
|
|
<EmptyState title="空" />
|
|
)
|
|
}
|
|
|
|
</View>
|
|
|
|
<View className="mt-4" style={{ paddingBottom: 24 }}>
|
|
<Text className="text-lg font-semibold text-gray-700">分类详细</Text>
|
|
|
|
{
|
|
pieRecords.length > 0
|
|
? (
|
|
<View className="mt-4 space-y-3">
|
|
{pieRecords.map((item, index) => (
|
|
<View
|
|
key={index}
|
|
className={`flex flex-row justify-between items-center p-3 bg-white shadow-md rounded-lg ${index !== pieRecords.length - 1 ? 'border-b border-gray-300' : ''}`}
|
|
>
|
|
<Text className="text-base font-medium text-gray-800">{item.x}</Text>
|
|
<Text className="text-base font-semibold text-gray-700">
|
|
{item.y}
|
|
{' '}
|
|
元
|
|
</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
)
|
|
: (
|
|
<EmptyState title="空" />
|
|
)
|
|
|
|
}
|
|
|
|
</View>
|
|
|
|
{
|
|
timeType === 2
|
|
? (
|
|
<ADateRangePicker
|
|
show={showDatePicker}
|
|
onConfirm={(startDate, endDate) => {
|
|
setStartDate(startDate)
|
|
setEndDate(endDate)
|
|
setShowDatePicker(false)
|
|
}}
|
|
onClose={() => {
|
|
setShowDatePicker(false)
|
|
}}
|
|
/>
|
|
)
|
|
: (
|
|
<ADatePicker
|
|
show={showDatePicker}
|
|
mode={timeType === 0 ? 'month' : 'year'}
|
|
onConfirm={(val) => {
|
|
setStartDate(val)
|
|
setShowDatePicker(false)
|
|
}}
|
|
onClose={() => {
|
|
setShowDatePicker(false)
|
|
}}
|
|
/>
|
|
)
|
|
}
|
|
</ScrollView>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<View className="flex-1">
|
|
<CustomHeader
|
|
showHeader={false}
|
|
/>
|
|
|
|
<PagerTabs
|
|
showCustomHeader={true}
|
|
routes={[
|
|
{
|
|
key: 'expense',
|
|
title: '支出',
|
|
element: <AnalysisContent analysisType={MoneyCategoryEnum.Expense} />,
|
|
},
|
|
{
|
|
key: 'income',
|
|
title: '收入',
|
|
element: <AnalysisContent analysisType={MoneyCategoryEnum.Income} />,
|
|
},
|
|
]}
|
|
/>
|
|
</View>
|
|
)
|
|
}
|