diff --git a/code/base-project/base-app/src/app/(tabs)/money/index.tsx b/code/base-project/base-app/src/app/(tabs)/money/index.tsx index 7bd1385f..9f47b8ed 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/index.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/index.tsx @@ -1,22 +1,21 @@ import type { MoneyRecordGroup, MoneyRecordItem, QueryMoneyRecordsResult } from '@/types/money/record' import { useRouter } from 'expo-router' import React, { useEffect, useState } from 'react' -import { Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native' +import { Text, TouchableOpacity, View } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { ADatePicker, LucideIcon } from '@/components/common/ao' import { Fab, FabIcon } from '@/components/ui/fab' import { AddIcon } from '@/components/ui/icon' import { Progress, ProgressFilledTrack } from '@/components/ui/progress' import { deleteMoneyRecordApi, queryMoneyRecordsApi } from '@/request/api/money/record' -import { add, sub } from '@/utils/math' -import { getCurrentYearMonth, isInMonth } from '@/utils/time' +import { useMoneyRecordStore } from '@/store/moneyRecord' +import { getCurrentYearMonth } from '@/utils/time' import { toast } from '@/utils/toast' -import AddMoneyDrawer from './components/AddDrawer' import TransactionsList from './components/TransactionsList' export default function Money() { + const moneyRecordStore = useMoneyRecordStore() const router = useRouter() - const [showAddDrawer, setShowAddDrawer] = useState(false) // 安全高度 const insets = useSafeAreaInsets() @@ -25,22 +24,13 @@ export default function Money() { const [searchParams, setSearchParams] = useState({ record_time: getCurrentYearMonth(), }) - // 数据 - const [moneyRecords, setMoneyRecords] = useState({ - total_expense: '0', - total_income: '0', - records: [], - }) - // 更新 - const [updateItem, setUpdateItem] = useState(null) useEffect(() => { queryMoneyRecordsApi({ record_time: searchParams.record_time, }).then((res) => { if (res.isSuccess) { - console.log(res.data.records) - setMoneyRecords(res.data) + moneyRecordStore.setRecords(res.data.records, res.data.total_expense, res.data.total_income, searchParams.record_time) } else { toast.show({ @@ -52,232 +42,6 @@ export default function Money() { }) }, [searchParams]) - function handleAddMoneyRecord(data: MoneyRecordItem) { - const recordTime = data.record_time - - setMoneyRecords((prev) => { - // 不在当前月份 → 不添加,直接返回 - if (!isInMonth(recordTime, searchParams.record_time)) { - return prev - } - - const next = structuredClone(prev) - - // 查找分组 - const group = next.records.find(g => g.record_time === recordTime) - - // === 已存在分组 === - if (group) { - // 插入到最前面 - group.records.unshift(data) - - // 更新分组 & 总计 - if (data.category_type === 1) { - // 收入 - group.income = add(group.income, data.amount) - next.total_income = add(next.total_income, data.amount) - } - else if (data.category_type === 0) { - // 支出 - group.expense = add(group.expense, data.amount) - next.total_expense = add(next.total_expense, data.amount) - } - - return next - } - - // === 无分组,新建 === - const expense = data.category_type === 0 ? data.amount : '0' - const income = data.category_type === 1 ? data.amount : '0' - - const newGroup: MoneyRecordGroup = { - record_time: recordTime, - income, - expense, - records: [data], - } - - // ---- 按日期(YYYY-MM-DD)倒序插入 ---- - // 最新日期插入前面,比如:2025-01-05 > 2025-01-03 - const index = next.records.findIndex(g => g.record_time < recordTime) - - if (index === -1) { - next.records.push(newGroup) - } - else { - next.records.splice(index, 0, newGroup) - } - - // 更新总计 - if (data.category_type === 0) { - next.total_income = add(next.total_income, data.amount) - } - else if (data.category_type === 1) { - next.total_expense = add(next.total_expense, data.amount) - } - - return next - }) - } - - function handleUpdateMoneyRecord(updated: MoneyRecordItem) { - setMoneyRecords((prev) => { - const next = structuredClone(prev) - - // 找到旧记录 - const oldGroupIndex = next.records.findIndex(g => - g.records.some(r => r.id === updated.id), - ) - if (oldGroupIndex === -1) - return next - - const oldGroup = next.records[oldGroupIndex] - const oldRecordIndex = oldGroup.records.findIndex(r => r.id === updated.id) - const oldRecord = oldGroup.records[oldRecordIndex] - - const oldAmount = oldRecord.amount - const newAmount = updated.amount - const oldType = oldRecord.category_type - const newType = updated.category_type - const oldDate = oldRecord.record_time - const newDate = updated.record_time - - // record_time 没变 → 同分组更新 - if (oldDate === newDate) { - oldGroup.records[oldRecordIndex] = updated - - // 调整分组金额 - if (oldType === 1) - oldGroup.income = sub(oldGroup.income, oldAmount) - if (oldType === 0) - oldGroup.expense = sub(oldGroup.expense, oldAmount) - - if (newType === 1) - oldGroup.income = add(oldGroup.income, newAmount) - if (newType === 0) - oldGroup.expense = add(oldGroup.expense, newAmount) - - // 调整总计 - if (oldType === 1) - next.total_income = sub(next.total_income, oldAmount) - if (oldType === 0) - next.total_expense = sub(next.total_expense, oldAmount) - - if (newType === 1) - next.total_income = add(next.total_income, newAmount) - if (newType === 0) - next.total_expense = add(next.total_expense, newAmount) - - return next - } - - // ------------------------- - // 判断是否在当前月份内 - // ------------------------- - const currentMonth = searchParams.record_time // 例如 "2025-01" - - const isInCurrentMonth = isInMonth(newDate, currentMonth) - - // 1. 先移除旧分组 & 调整金额(无论是否在当前月份,都要做) - if (oldType === 1) - oldGroup.income = sub(oldGroup.income, oldAmount) - if (oldType === 0) - oldGroup.expense = sub(oldGroup.expense, oldAmount) - - if (oldType === 1) - next.total_income = sub(next.total_income, oldAmount) - if (oldType === 0) - next.total_expense = sub(next.total_expense, oldAmount) - - oldGroup.records.splice(oldRecordIndex, 1) - if (oldGroup.records.length === 0) { - next.records.splice(oldGroupIndex, 1) - } - - // ------------------------- - // 不在当前月份 → 不显示,直接返回 next - // ------------------------- - if (!isInCurrentMonth) { - return next - } - - // ------------------------- - // 在当前月份 → 移动到新分组 - // ------------------------- - - // 找新分组,如果没有就创建 - let newGroup = next.records.find(g => g.record_time === newDate) - if (!newGroup) { - newGroup = { - record_time: newDate, - income: '0.00', - expense: '0.00', - records: [], - } - // 按日期倒序插入 - const insertIndex = next.records.findIndex(g => g.record_time < newDate) - if (insertIndex === -1) - next.records.push(newGroup) - else - next.records.splice(insertIndex, 0, newGroup) - } - - // 添加到新分组 - newGroup.records.unshift(updated) - - // 加金额 - if (newType === 1) - newGroup.income = add(newGroup.income, newAmount) - if (newType === 0) - newGroup.expense = add(newGroup.expense, newAmount) - - if (newType === 1) - next.total_income = add(next.total_income, newAmount) - if (newType === 0) - next.total_expense = add(next.total_expense, newAmount) - - return next - }) - } - - function handleDeleteRecord(id: number) { - // 直接更新本地状态 - setMoneyRecords((prev) => { - const next = structuredClone(prev) - - // 遍历每个分组 - next.records.forEach((group) => { - const index = group.records.findIndex(r => r.id === id) - if (index !== -1) { - const record = group.records[index] - - // 更新分组金额 - if (record.category_type === 1) { - group.income = sub(group.income, record.amount) - next.total_income = sub(next.total_income, record.amount) - } - else if (record.category_type === 0) { - group.expense = sub(group.expense, record.amount) - next.total_expense = sub(next.total_expense, record.amount) - } - - // 删除记录 - group.records.splice(index, 1) - } - }) - - // 删除空分组 - next.records = next.records.filter(g => g.records.length > 0) - - return next - }) - - // 异步请求删除 API - deleteMoneyRecordApi({ id }).catch((err) => { - console.log(err) - }) - } - return ( - - - 余额 - - 0.00 - - - 收入 - 0.00 + {moneyRecordStore.total_income} @@ -338,7 +90,7 @@ export default function Money() { numberOfLines={1} ellipsizeMode="tail" > - 0.00 + {moneyRecordStore.total_expense} @@ -374,13 +126,15 @@ export default function Money() { { - setUpdateItem(data) - setShowAddDrawer(true) + router.navigate({ + pathname: '/money/record/editor', + params: { id: data.id }, + }) }} onDelete={(id) => { - handleDeleteRecord(id) + moneyRecordStore.deleteMoneyRecord(id) }} /> @@ -388,35 +142,16 @@ export default function Money() { { - // setShowAddDrawer(true) router.navigate('/money/record/editor') }} > - { - setShowAddDrawer(false) - setUpdateItem(null) - }} - onConfirm={(res) => { - setShowAddDrawer(false) - if (updateItem !== null) { - setUpdateItem(null) - handleUpdateMoneyRecord(res) - } - else { - handleAddMoneyRecord(res) - } - }} - /> - { setSearchParams({ ...searchParams, diff --git a/code/base-project/base-app/src/app/money/record/editor/index.tsx b/code/base-project/base-app/src/app/money/record/editor/index.tsx index 18ae283a..e84fbc19 100644 --- a/code/base-project/base-app/src/app/money/record/editor/index.tsx +++ b/code/base-project/base-app/src/app/money/record/editor/index.tsx @@ -1,30 +1,29 @@ import type { MoneyCategoryItem } from '@/types/money/category' import type { MoneyRecordBase, MoneyRecordItem } from '@/types/money/record' -import { useRouter } from 'expo-router' -import { useState } from 'react' +import { useLocalSearchParams, useRouter } from 'expo-router' +import { useEffect, useState } from 'react' import { Text, TouchableOpacity, View } from 'react-native' import { LucideIcon } from '@/components/common/ao' import CustomHeader from '@/components/custom/Header' import PagerTabs from '@/components/custom/PagerTabs' +import { insertMoneyRecordApi } from '@/request/api/money/record' import { useMoneyCategoryStore } from '@/store/moneyCategory' +import { useMoneyRecordStore } from '@/store/moneyRecord' import { getCurrentDate, toDateString } from '@/utils/time' import { toast } from '@/utils/toast' import AmountKeyboard from './components/AmountKeyboard' import CategoryGrid from './components/CategoryGrid' export default function MoenyRecordEditor() { - const router = useRouter() - const moneyCategoryStore = useMoneyCategoryStore() - const expense = useMoneyCategoryStore(state => state.expense) - const income = useMoneyCategoryStore(state => state.income) + const moneyRecordStore = useMoneyRecordStore() - console.log(moneyCategoryStore.categories) - console.log(expense) - console.log(income) + const router = useRouter() + const expense = moneyCategoryStore.getExpenseCategories() + const income = moneyCategoryStore.getIncomeCategories() + + const { id: updateId } = useLocalSearchParams<{ id: string }>() - // 选择顺序:0 支出 1收入 - const [selectedIndex, setSelectedIndex] = useState(0) // 自定义键盘 const [showKeydown, setShowKeydown] = useState(false) // 选中分类 @@ -42,6 +41,25 @@ export default function MoenyRecordEditor() { const [moneyRecord, setMoneyRecord] = useState(defaultMoneyRecord) + useEffect(() => { + if (updateId) { + const updateData = moneyRecordStore.getMoneyRecordById(Number(updateId)) + if (updateData !== null) { + setMoneyRecord({ + ...updateData, + record_time: toDateString(updateData.record_time), + }) + setShowKeydown(true) + + const moneyCategory = moneyCategoryStore.getCategoryById(updateData.category_id) + + if (moneyCategory != null) { + setSelectedCategory(moneyCategory) + } + } + } + }, []) + // 保存记录 function handleSaveRecord() { if (selectedCategory === null) { @@ -55,7 +73,39 @@ export default function MoenyRecordEditor() { toast.show({ title: '请输入金额', }) + return } + + const amount = moneyRecord.amount.replace(/^-+/, '') + + insertMoneyRecordApi({ + ...moneyRecord, + amount, + category_id: selectedCategory.id, + }) + .then((res) => { + if (res.isSuccess) { + const result: MoneyRecordItem = { + ...res.data, + category_name: selectedCategory.name, + category_icon: selectedCategory.icon, + category_type: selectedCategory.type, + } + + moneyRecordStore.addMoneyRecord(result) + + router.back() + } + else { + toast.show({ + title: res.message || '保存失败', + }) + } + }) + .catch((err) => { + console.log('发生异常啦') + console.log(err) + }) } return ( @@ -70,6 +120,7 @@ export default function MoenyRecordEditor() { /> @@ -83,7 +134,7 @@ export default function MoenyRecordEditor() { router.back() }} > - 取消 + 取消 )} routes={[ diff --git a/code/base-project/base-app/src/components/custom/PagerTabs.tsx b/code/base-project/base-app/src/components/custom/PagerTabs.tsx index e23e77b2..c2f8e535 100644 --- a/code/base-project/base-app/src/components/custom/PagerTabs.tsx +++ b/code/base-project/base-app/src/components/custom/PagerTabs.tsx @@ -13,7 +13,7 @@ interface PagerTabsProps { routes: PagerRoute[] left?: React.ReactNode right?: React.ReactNode - initialIndex?: number + selectedIndex?: number // 外部控制选中页 onChange?: (key: string) => void indicatorWidth?: number @@ -25,17 +25,24 @@ export default function PagerTabs({ routes, left, right, - initialIndex = 0, + selectedIndex, onChange, indicatorWidth = 38, className, style, }: PagerTabsProps) { const pagerRef = React.useRef(null) - const [index, setIndex] = React.useState(initialIndex) + const [index, setIndex] = React.useState(selectedIndex ?? 0) const [tabWidth, setTabWidth] = React.useState(0) + const scrollX = React.useRef(new Animated.Value(selectedIndex ?? 0)).current - const scrollX = React.useRef(new Animated.Value(0)).current + // 外部 selectedIndex 更新时同步内部 index + React.useEffect(() => { + if (typeof selectedIndex === 'number' && selectedIndex !== index) { + setIndex(selectedIndex) + pagerRef.current?.setPage(selectedIndex) + } + }, [selectedIndex]) const onTabPress = (i: number) => { pagerRef.current?.setPage(i) @@ -54,7 +61,6 @@ export default function PagerTabs({ } const tabWidthPerTab = tabWidth / routes.length - const indicatorTranslateX = scrollX.interpolate({ inputRange: routes.map((_, i) => i), outputRange: routes.map( @@ -66,9 +72,7 @@ export default function PagerTabs({ return ( {/* Header */} @@ -86,7 +90,7 @@ export default function PagerTabs({ {routes.map((r, i) => ( onTabPress(i)} > onPageSelected(e.nativeEvent.position)} > diff --git a/code/base-project/base-app/src/request/index.ts b/code/base-project/base-app/src/request/index.ts index 89b78e6c..a70533ab 100644 --- a/code/base-project/base-app/src/request/index.ts +++ b/code/base-project/base-app/src/request/index.ts @@ -30,8 +30,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - // baseURL: 'http://192.168.5.6:8085/app', - baseURL: 'http://192.168.1.136:8085/app', + baseURL: 'http://192.168.5.6:8085/app', + // baseURL: 'http://192.168.1.136:8085/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null, diff --git a/code/base-project/base-app/src/store/moneyCategory.ts b/code/base-project/base-app/src/store/moneyCategory.ts index 3eff17c9..e41e48c6 100644 --- a/code/base-project/base-app/src/store/moneyCategory.ts +++ b/code/base-project/base-app/src/store/moneyCategory.ts @@ -7,14 +7,15 @@ import { queryMoneyCategoryApi } from '@/request/api/money/category' interface MoneyCategoryStore { categories: MoneyCategoryItem[] - // 通过 getter 动态计算 - expense: MoneyCategoryItem[] - income: MoneyCategoryItem[] - setCategories: (categories: MoneyCategoryItem[]) => void addCategory: (category: MoneyCategoryItem) => void removeCategory: (id: number) => void init: () => Promise + + getExpenseCategories: () => MoneyCategoryItem[] + getIncomeCategories: () => MoneyCategoryItem[] + + getCategoryById: (id: number) => MoneyCategoryItem | null } export const useMoneyCategoryStore = create()( @@ -22,34 +23,32 @@ export const useMoneyCategoryStore = create()( (set, get) => ({ categories: [], - // getter 样式属性,通过 get() 动态计算 - get expense() { - return get().categories.filter(c => c.type === 0) - }, - get income() { - return get().categories.filter(c => c.type === 1) - }, - setCategories: categories => set({ categories }), addCategory: category => - set(state => ({ categories: [...state.categories, category] })), + set({ categories: [...get().categories, category] }), removeCategory: id => - set(state => ({ categories: state.categories.filter(c => c.id !== id) })), + set({ categories: get().categories.filter(c => c.id !== id) }), init: async () => { try { const res = await queryMoneyCategoryApi() if (res.isSuccess) { - const categories = res.data || [] - set({ categories }) + set({ categories: res.data || [] }) } } - catch (error) { - console.error('Failed to fetch categories:', error) + catch (e) { + console.error('Fetch category failed:', e) } }, + + getExpenseCategories: () => (get().categories || []).filter(c => c.type === 0), + getIncomeCategories: () => (get().categories || []).filter(c => c.type === 1), + + getCategoryById: (id: number) => { + return get().categories.find(c => c.id === id) || null + }, }), { name: 'money-category-storage', diff --git a/code/base-project/base-app/src/store/moneyRecord.ts b/code/base-project/base-app/src/store/moneyRecord.ts index 0488bcee..b14277b5 100644 --- a/code/base-project/base-app/src/store/moneyRecord.ts +++ b/code/base-project/base-app/src/store/moneyRecord.ts @@ -1,3 +1,172 @@ +import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record' import { create } from 'zustand' -import { MoneyCategoryItem } from '@/types/money/category' -import { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record' +import { deleteMoneyRecordApi } from '@/request/api/money/record' +import { add, sub } from '@/utils/math' +import { isInMonth } from '@/utils/time' + +interface MoneyRecordStore { + records: MoneyRecordGroup[] + currentMonth: string + + total_income: string + total_expense: string + + setRecords: (records: MoneyRecordGroup[], total_expense: string, total_income: string, month: string) => void + setCurrentMonth: (month: string) => void + + addMoneyRecord: (data: MoneyRecordItem) => void + updateMoneyRecord: (updated: MoneyRecordItem) => void + deleteMoneyRecord: (id: number) => void + + getMoneyRecordById: (id: number) => MoneyRecordItem | null +} + +export const useMoneyRecordStore = create((set, get) => ({ + records: [], + currentMonth: '', + + total_income: '0.00', + total_expense: '0.00', + + setRecords: (records, total_expense, total_income, month) => { + set({ records, currentMonth: month, total_income, total_expense }) + }, + + setCurrentMonth: month => set({ currentMonth: month }), + + addMoneyRecord: (data) => { + set((prev) => { + if (!isInMonth(data.record_time, prev.currentMonth)) + return prev + + const records = [...prev.records] + const groupIndex = records.findIndex(g => g.record_time === data.record_time) + const amount = data.amount + + if (groupIndex !== -1) { + const group = { ...records[groupIndex], records: [data, ...records[groupIndex].records] } + if (data.category_type === 0) + group.expense = add(group.expense, amount) + if (data.category_type === 1) + group.income = add(group.income, amount) + records[groupIndex] = group + } + else { + const newGroup: MoneyRecordGroup = { + record_time: data.record_time, + records: [data], + expense: data.category_type === 0 ? amount : '0.00', + income: data.category_type === 1 ? amount : '0.00', + } + const insertIndex = records.findIndex(g => g.record_time < data.record_time) + if (insertIndex === -1) + records.push(newGroup) + else records.splice(insertIndex, 0, newGroup) + } + + return { + ...prev, + records, + total_expense: data.category_type === 0 ? add(prev.total_expense, amount) : prev.total_expense, + total_income: data.category_type === 1 ? add(prev.total_income, amount) : prev.total_income, + } + }) + }, + + updateMoneyRecord: (updated) => { + set((prev) => { + const records = [...prev.records] + const oldGroupIndex = records.findIndex(g => g.records.some(r => r.id === updated.id)) + if (oldGroupIndex === -1) + return prev + + const oldGroup = { ...records[oldGroupIndex], records: [...records[oldGroupIndex].records] } + const oldRecordIndex = oldGroup.records.findIndex(r => r.id === updated.id) + const oldRecord = oldGroup.records[oldRecordIndex] + + const oldAmount = oldRecord.amount + const newAmount = updated.amount + + // 移除旧记录 + oldGroup.records.splice(oldRecordIndex, 1) + let total_expense = prev.total_expense + let total_income = prev.total_income + if (oldRecord.category_type === 0) + total_expense = sub(total_expense, oldAmount) + if (oldRecord.category_type === 1) + total_income = sub(total_income, oldAmount) + if (oldGroup.records.length === 0) + records.splice(oldGroupIndex, 1) + else records[oldGroupIndex] = oldGroup + + if (!isInMonth(updated.record_time, prev.currentMonth)) { + return { ...prev, records, total_expense, total_income } + } + + // 添加到新分组 + const newGroupIndex = records.findIndex(g => g.record_time === updated.record_time) + if (newGroupIndex !== -1) { + const group = { ...records[newGroupIndex], records: [updated, ...records[newGroupIndex].records] } + if (updated.category_type === 0) + group.expense = add(group.expense, newAmount) + if (updated.category_type === 1) + group.income = add(group.income, newAmount) + records[newGroupIndex] = group + } + else { + const newGroup: MoneyRecordGroup = { + record_time: updated.record_time, + records: [updated], + expense: updated.category_type === 0 ? newAmount : '0.00', + income: updated.category_type === 1 ? newAmount : '0.00', + } + const insertIndex = records.findIndex(g => g.record_time < updated.record_time) + if (insertIndex === -1) + records.push(newGroup) + else records.splice(insertIndex, 0, newGroup) + } + + if (updated.category_type === 0) + total_expense = add(total_expense, newAmount) + if (updated.category_type === 1) + total_income = add(total_income, newAmount) + + return { ...prev, records, total_expense, total_income } + }) + }, + + deleteMoneyRecord: (id) => { + set((prev) => { + const records = prev.records.map(g => ({ ...g, records: [...g.records] })) + let total_expense = prev.total_expense + let total_income = prev.total_income + + records.forEach((group) => { + const index = group.records.findIndex(r => r.id === id) + if (index !== -1) { + const record = group.records[index] + if (record.category_type === 0) + total_expense = sub(total_expense, record.amount) + if (record.category_type === 1) + total_income = sub(total_income, record.amount) + group.records.splice(index, 1) + } + }) + + const newRecords = records.filter(g => g.records.length > 0) + return { ...prev, records: newRecords, total_expense, total_income } + }) + + deleteMoneyRecordApi({ id }).catch(console.error) + }, + + getMoneyRecordById: (id: number) => { + const records = get().records + for (const group of records) { + const record = group.records.find(r => r.id === id) + if (record) + return record + } + return null + }, +})) diff --git a/code/base-project/base-go-v2/internal/api/money/index.go b/code/base-project/base-go-v2/internal/api/money/index.go index b6c4ff96..14e20645 100644 --- a/code/base-project/base-go-v2/internal/api/money/index.go +++ b/code/base-project/base-go-v2/internal/api/money/index.go @@ -64,6 +64,8 @@ func queryMoneyRecords(c *router.Context) error { recordMonth := bodyData.GetString("record_time") + fmt.Println(recordMonth) + // 解析年月 startTime, err := time.Parse("2006-01", recordMonth) if err != nil { @@ -82,7 +84,7 @@ func queryMoneyRecords(c *router.Context) error { muc.type AS category_type FROM money_record mr LEFT JOIN money_user_category muc ON mr.category_id = muc.id - WHERE mr.create_time BETWEEN '%s' AND '%s' + WHERE mr.record_time BETWEEN '%s' AND '%s' ORDER BY mr.record_time DESC, mr.create_time DESC `, startTime.Format("2006-01-02 15:04:05"), endTime.Format("2006-01-02 15:04:05"))