diff --git a/code/allapp/allapp-go/api/handler/finance/record.go b/code/allapp/allapp-go/api/handler/finance/record.go index d811bfc5..493249f6 100644 --- a/code/allapp/allapp-go/api/handler/finance/record.go +++ b/code/allapp/allapp-go/api/handler/finance/record.go @@ -5,6 +5,7 @@ import ( "allapp/api/types" "allapp/db" "allapp/db/repo" + "allapp/utils/errorx" "allapp/utils/pgtypex" "allapp/utils/requestx" "allapp/utils/responsex" @@ -57,6 +58,7 @@ func ListFinanceRecords(c fiber.Ctx) error { RecordTime: pgtypex.TimePtrToPgDate(startTime), RecordTime_2: pgtypex.TimePtrToPgDate(endTime), Column4: categoryId, + Column5: dto.CategoryType, }) if err != nil { @@ -131,7 +133,7 @@ func UpdateFinanceRecord(c fiber.Ctx) error { } err = db.Queries.UpdateFinanceRecord(c.Context(), repo.UpdateFinanceRecordParams{ - ID: uniqueid.NextId(), + ID: dto.Id, CategoryID: dto.CategoryId, Amount: pgtypex.StringToNumeric(dto.Amount), Remark: pgtypex.StringToText(dto.Remark), @@ -161,3 +163,38 @@ func DeleteFinanceRecord(c fiber.Ctx) error { return responsex.OK(c, nil) } + +// GetFinanceRecordDetail 删除记账记录 +func GetFinanceRecordDetail(c fiber.Ctx) error { + dto := new(types.FinanceRecordDetailDTO) + if err := requestx.BindAndValidate(c, dto); err != nil { + return err + } + + recordDetail, err := db.Queries.GetFinanceRecordDetail(c.Context(), dto.Id) + + if err != nil { + if errorx.IsNotFound(err) { + return responsex.Error(c, "该条记录不存在") + } + return err + } + + vo := new(types.FinanceRecordDetailVO) + + vo.Id = recordDetail.ID + vo.CategoryId = recordDetail.CategoryID + vo.Amount = pgtypex.NumericToString(recordDetail.Amount) + vo.RecordTime = pgtypex.DateToString(recordDetail.RecordTime) + vo.Remark = pgtypex.TextToString(recordDetail.Remark) + + vo.CreateTime = pgtypex.TimestamptzToMillis(recordDetail.CreateTime) + vo.CreateMemberId = recordDetail.CreateBy + vo.CreateMemberName = pgtypex.TextToString(recordDetail.CreateMemberName) + + vo.UpdateTime = pgtypex.TimestamptzToMillis(recordDetail.UpdateTime) + vo.UpdateMemberId = recordDetail.UpdateBy + vo.UpdateMemberName = pgtypex.TextToString(recordDetail.UpdateMemberName) + + return responsex.OK(c, vo) +} diff --git a/code/allapp/allapp-go/api/router/router.go b/code/allapp/allapp-go/api/router/router.go index 04a4aaa4..506ee7aa 100644 --- a/code/allapp/allapp-go/api/router/router.go +++ b/code/allapp/allapp-go/api/router/router.go @@ -52,6 +52,7 @@ func SetupRouters(app *fiber.App) { financeRouter.Post("/record/create", finance.CreateFinanceRecord) financeRouter.Post("/record/update", finance.UpdateFinanceRecord) financeRouter.Post("/record/delete", finance.DeleteFinanceRecord) + financeRouter.Post("/record/detail", finance.GetFinanceRecordDetail) // authGroup.Get("/user/profile", user.GetProfile) // spaceGroup.Get("/space/info", space.GetInfo) diff --git a/code/allapp/allapp-go/api/types/finance.go b/code/allapp/allapp-go/api/types/finance.go index b2be4fa4..7f51fcfc 100644 --- a/code/allapp/allapp-go/api/types/finance.go +++ b/code/allapp/allapp-go/api/types/finance.go @@ -63,9 +63,10 @@ type FinanceRecord struct { } type ListFinanceRecordsDTO struct { - StartTime string `json:"start_time"` - EndTime string `json:"end_time"` - CategoryId int64 `json:"category_id"` + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` + CategoryId int64 `json:"category_id"` + CategoryType int16 `json:"category_type"` } type ListFinanceRecordsVO struct { @@ -93,3 +94,21 @@ type UpdateFinanceRecordDTO struct { type DeleteFinanceRecordDTO struct { Id int64 `json:"id" validate:"required"` } + +type FinanceRecordDetailDTO struct { + Id int64 `json:"id" validate:"required"` +} + +type FinanceRecordDetailVO struct { + Id int64 `json:"id"` + CategoryId int64 `json:"category_id"` + Amount string `json:"amount"` + RecordTime string `json:"record_time"` + Remark string `json:"remark"` + CreateTime int64 `json:"create_time"` + CreateMemberId int64 `json:"create_member_id"` + CreateMemberName string `json:"create_member_name"` + UpdateTime int64 `json:"update_time"` + UpdateMemberId int64 `json:"update_member_id"` + UpdateMemberName string `json:"update_member_name"` +} diff --git a/code/allapp/allapp-go/db/queries/finance_record.sql b/code/allapp/allapp-go/db/queries/finance_record.sql index 0d996237..2b555bac 100644 --- a/code/allapp/allapp-go/db/queries/finance_record.sql +++ b/code/allapp/allapp-go/db/queries/finance_record.sql @@ -4,16 +4,14 @@ SELECT su.member_name FROM finance_record fr LEFT JOIN space_member su - ON fr.space_id = su.space_id - AND fr.update_by = su.user_id + ON fr.space_id = su.space_id AND fr.update_by = su.user_id + LEFT JOIN finance_category_space fcs ON fr.category_id = fcs.id WHERE fr.space_id = $1 AND fr.record_time >= $2 AND fr.record_time < $3 - AND ( - $4 = 0 - OR fr.category_id = $4 - ) + AND fr.category_id = COALESCE(NULLIF($4::bigint, 0), fr.category_id) + AND fcs.type = COALESCE(NULLIF($5::smallint, 0), fcs.type) ORDER BY fr.record_time DESC, fr.create_time DESC; @@ -37,4 +35,23 @@ WHERE id = $1; DELETE FROM finance_record WHERE id = $1; -- name: DeleteFinanceRecordByCategoryId :exec -DELETE FROM finance_record WHERE category_id = $1; \ No newline at end of file +DELETE FROM finance_record WHERE category_id = $1; + +-- name: GetFinanceRecordDetail :one +SELECT + fr.id, + fr.category_id, + fr.amount, + fr.record_time, + fr.remark, + fr.create_by, + fr.create_time, + cm.nickname AS create_member_name, + fr.update_by, + fr.update_time, + um.nickname AS update_member_name +FROM finance_record fr + LEFT JOIN "user" cm ON cm.id = fr.create_by + LEFT JOIN "user" um ON um.id = fr.update_by +WHERE fr.id = $1 +LIMIT 1; \ No newline at end of file diff --git a/code/allapp/allapp-go/db/repo/finance_record.sql.go b/code/allapp/allapp-go/db/repo/finance_record.sql.go index fae9f4d7..1642daa5 100644 --- a/code/allapp/allapp-go/db/repo/finance_record.sql.go +++ b/code/allapp/allapp-go/db/repo/finance_record.sql.go @@ -29,6 +29,59 @@ func (q *Queries) DeleteFinanceRecordByCategoryId(ctx context.Context, categoryI return err } +const getFinanceRecordDetail = `-- name: GetFinanceRecordDetail :one +SELECT + fr.id, + fr.category_id, + fr.amount, + fr.record_time, + fr.remark, + fr.create_by, + fr.create_time, + cm.nickname AS create_member_name, + fr.update_by, + fr.update_time, + um.nickname AS update_member_name +FROM finance_record fr + LEFT JOIN "user" cm ON cm.id = fr.create_by + LEFT JOIN "user" um ON um.id = fr.update_by +WHERE fr.id = $1 +LIMIT 1 +` + +type GetFinanceRecordDetailRow struct { + ID int64 + CategoryID int64 + Amount pgtype.Numeric + RecordTime pgtype.Date + Remark pgtype.Text + CreateBy int64 + CreateTime pgtype.Timestamptz + CreateMemberName pgtype.Text + UpdateBy int64 + UpdateTime pgtype.Timestamptz + UpdateMemberName pgtype.Text +} + +func (q *Queries) GetFinanceRecordDetail(ctx context.Context, id int64) (GetFinanceRecordDetailRow, error) { + row := q.db.QueryRow(ctx, getFinanceRecordDetail, id) + var i GetFinanceRecordDetailRow + err := row.Scan( + &i.ID, + &i.CategoryID, + &i.Amount, + &i.RecordTime, + &i.Remark, + &i.CreateBy, + &i.CreateTime, + &i.CreateMemberName, + &i.UpdateBy, + &i.UpdateTime, + &i.UpdateMemberName, + ) + return i, err +} + const insertFinanceRecord = `-- name: InsertFinanceRecord :exec INSERT INTO finance_record(id,category_id,space_id,amount,record_time,remark,create_by,update_by,create_time,update_time) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NOW(),NOW()) @@ -65,16 +118,14 @@ SELECT su.member_name FROM finance_record fr LEFT JOIN space_member su - ON fr.space_id = su.space_id - AND fr.update_by = su.user_id + ON fr.space_id = su.space_id AND fr.update_by = su.user_id + LEFT JOIN finance_category_space fcs ON fr.category_id = fcs.id WHERE fr.space_id = $1 AND fr.record_time >= $2 AND fr.record_time < $3 - AND ( - $4 = 0 - OR fr.category_id = $4 - ) + AND fr.category_id = COALESCE(NULLIF($4::bigint, 0), fr.category_id) + AND fcs.type = COALESCE(NULLIF($5::smallint, 0), fcs.type) ORDER BY fr.record_time DESC, fr.create_time DESC @@ -84,7 +135,8 @@ type ListFinanceRecordsParams struct { SpaceID int64 RecordTime pgtype.Date RecordTime_2 pgtype.Date - Column4 interface{} + Column4 int64 + Column5 int16 } type ListFinanceRecordsRow struct { @@ -107,6 +159,7 @@ func (q *Queries) ListFinanceRecords(ctx context.Context, arg ListFinanceRecords arg.RecordTime, arg.RecordTime_2, arg.Column4, + arg.Column5, ) if err != nil { return nil, err diff --git a/code/allapp/allapp-go/db/schema.sql b/code/allapp/allapp-go/db/schema.sql index 42277ddf..5b010a47 100644 --- a/code/allapp/allapp-go/db/schema.sql +++ b/code/allapp/allapp-go/db/schema.sql @@ -110,4 +110,3 @@ create table finance_record update_by bigint not null, update_time timestamp with time zone default now() ); - diff --git a/code/allapp/allapp-rn/src/app/(tabs)/chat.tsx b/code/allapp/allapp-rn/src/app/(tabs)/chat.tsx index a070106e..914bfbbb 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/chat.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/chat.tsx @@ -10,7 +10,7 @@ export default function TestScreen() { const spaceStore = useSpaceStore() const navigation = useNavigation() - console.log(navigation.getState()?.routes) + console.log(navigation.getState()?.routeNames) return ( diff --git a/code/allapp/allapp-rn/src/app/(tabs)/finance/components/CategorySheet.tsx b/code/allapp/allapp-rn/src/app/(tabs)/finance/components/CategorySheet.tsx index 3521c251..7f57bd5e 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/finance/components/CategorySheet.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/finance/components/CategorySheet.tsx @@ -46,6 +46,7 @@ export default function CategorySheet({ const handleSelect = useCallback( (item: FinanceCategory) => { + console.log(item) onSelect?.(item) onClose?.() }, @@ -74,9 +75,9 @@ export default function CategorySheet({ { title: '筛选', data: [ - createVirtualCategory(-1, '全部', -1), - createVirtualCategory(-2, '支出', 0), - createVirtualCategory(-3, '收入', 1), + createVirtualCategory(0, '全部', -1), + createVirtualCategory(-1, '支出', 0), + createVirtualCategory(-2, '收入', 1), ], }, { diff --git a/code/allapp/allapp-rn/src/app/(tabs)/finance/components/TransactionsList.tsx b/code/allapp/allapp-rn/src/app/(tabs)/finance/components/TransactionsList.tsx index 42323ad1..cf5195a7 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/finance/components/TransactionsList.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/finance/components/TransactionsList.tsx @@ -1,16 +1,15 @@ -import type { FinanceRecord, FinanceRecordGroup } from '@/types/finance/record' -import React, { useCallback, useState } from 'react' +import type { FinanceRecord } from '@/types/finance/record' +import React, { useCallback, useEffect, useState } from 'react' import { Pressable, RefreshControl, SectionList, Text, Vibration, View } from 'react-native' import { LucideIcon } from '@/components/common/ao' import EmptyState from '@/components/common/EmptyStatus' import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' import { Menu, MenuItem, MenuItemLabel, MenuSeparator } from '@/components/ui/menu' -import { useMoneyCategoryStore } from '@/store/moneyCategory' +import { useFinanceStore } from '@/store/finance' import { useUserStore } from '@/store/user' -import { MoneyCategoryEnum } from '@/types/money/category' +import { FinanceCategoryEnum } from '@/types/finance/category' interface StaticTransactionsProps { - records: FinanceRecordGroup[] onUpdate?: (data: FinanceRecord) => void onDelete?: (id: number) => void onDetail?: (id: number) => void @@ -19,18 +18,18 @@ interface StaticTransactionsProps { } export default function StaticTransactions({ - records, onUpdate, onDelete, onDetail, onLoadMore, onRefreshData, }: StaticTransactionsProps) { - const moneyCategoryStore = useMoneyCategoryStore() + const financeStore = useFinanceStore() const userID = useUserStore().userInfo?.id const [refreshing, setRefreshing] = useState(false) const [loadingMore, setLoadingMore] = useState(false) const [selectedId, setSelectedId] = useState(null) + const [sections, setSections] = useState([]) const handleRefresh = useCallback(async () => { if (!onRefreshData) @@ -56,12 +55,14 @@ export default function StaticTransactions({ } }, [onLoadMore, loadingMore]) - const sections = records.map(group => ({ - title: group.record_time, - totalIncome: group.income, - totalExpense: group.expense, - data: group.records, - })) + useEffect(() => { + setSections(financeStore.records.map(group => ({ + title: group.record_time, + totalIncome: group.income, + totalExpense: group.expense, + data: group.records, + }))) + }, [financeStore.records]) return ( { - const category = moneyCategoryStore.getCategoryById(item.category_id) + const category = financeStore.getCategoryById(item.category_id) return ( - {category?.type === MoneyCategoryEnum.Income ? '+' : '-'} + {category?.type === FinanceCategoryEnum.Income ? '+' : '-'} {' '} {item.amount} @@ -184,32 +185,27 @@ export default function StaticTransactions({ ) }} > - { - userID === item.member_id && ( - <> - { - onUpdate?.(item) - }} - > - - 更新 - - - - ) - } + + { + onUpdate?.(item) + }} + > + + 更新 + + 删除 + ('month') - const [searchParams, setSearchParams] = useState({ + const [searchParams, setSearchParams] = useState<{ + startTime: string + endTime: string + category: FinanceCategory | null + }>({ startTime: getCurrentYearMonth(), endTime: '', - category: -1, + category: null, }) const [showCategorySheet, setShowCategorySheet] = useState(false) @@ -41,21 +45,23 @@ export default function Money() { function fetchFinanceRecords() { const resolveDate = resolveDateRange(dateMode, searchParams.startTime) + let searchType = 0 + + if (searchParams.category) { + if (searchParams.category.id === -1 || searchParams.category.id === -2) { + searchType = searchParams.category.type + } + } + listFinanceRecordsApi({ start_time: resolveDate.startTime, end_time: resolveDate.endTime, - category_id: 0, + category_id: searchParams.category ? searchParams.category.id : 0, + category_type: searchType, }).then((res) => { if (res.isSuccess) { financeStore.setRecords(res.data.records || []) } - else { - toast.show({ - title: res.message || '查询错误,请稍后再试', - }) - } - }).catch((err) => { - console.log(err) }) } @@ -63,15 +69,25 @@ export default function Money() { useCallback(() => { financeStore.ensureCategoriesLoaded() fetchFinanceRecords() - }, [searchParams.startTime, searchParams.endTime]), + }, [searchParams.startTime, searchParams.endTime, searchParams.category]), ) async function handleDeleteRecord(id: number) { - await deleteMoneyRecordApi({ - id, + const toastId = toast.loading('正在删除...', { + duration: Infinity, }) - fetchFinanceRecords() + await deleteFinanceRecordApi({ + id, + }).then((res) => { + if (res.isSuccess) { + toast.success('删除成功') + + fetchFinanceRecords() + } + }).finally(() => { + toast.dismiss(toastId) + }) } function timeModeTip() { @@ -117,7 +133,11 @@ export default function Money() { onPress={() => setShowCategorySheet(true)} className="flex flex-row items-center gap-1" > - 分类 + + { + searchParams.category ? searchParams.category.name : '分类' + } + @@ -180,7 +200,6 @@ export default function Money() { { router.push({ pathname: '/finance/record/editor', @@ -188,7 +207,7 @@ export default function Money() { }) }} onDetail={(id) => { - router.navigate({ + router.push({ pathname: '/finance/record/detail', params: { id }, }) @@ -248,15 +267,16 @@ export default function Money() { { setShowCategorySheet(false) }} onSelect={(category) => { + console.log(category) setSearchParams(prev => ({ ...prev, - category: category.id, + category, })) }} /> diff --git a/code/allapp/allapp-rn/src/app/auth/index.tsx b/code/allapp/allapp-rn/src/app/auth/index.tsx index f5fd8458..30978b41 100644 --- a/code/allapp/allapp-rn/src/app/auth/index.tsx +++ b/code/allapp/allapp-rn/src/app/auth/index.tsx @@ -181,7 +181,7 @@ export default function Auth() { userStore.setUserInfo({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo3Nzk4OTU0MTkxMjE3MzMsImlhdCI6MTc3MjU0MDU1OH0.M5KqfPWdpOAlCCtZrJRxwKc8bRpGBjEt9BNCfgBZgnc', - id: 778115032100933, + id: 779895419121733, nickname: 'Zhang', avatar: 'http://thirdqq.qlogo.cn/ek_qqapp/AQHVialeUibE42oV8RvTTVZ4tyRlPYeJrUibWTwtCPfV68E4rSzn9cw00GkXQ3QDTiawwhjoqQb7/100', }) @@ -194,7 +194,7 @@ export default function Auth() { // name: '(tabs)' as never, // }], // }) - // console.log(navigation.getState()?.routeNames) + console.log(navigation.getState()?.routeNames) // ('/') } diff --git a/code/allapp/allapp-rn/src/app/finance/category/index.tsx b/code/allapp/allapp-rn/src/app/finance/category/index.tsx index 0f7ea71c..86ac2dfe 100644 --- a/code/allapp/allapp-rn/src/app/finance/category/index.tsx +++ b/code/allapp/allapp-rn/src/app/finance/category/index.tsx @@ -10,7 +10,7 @@ import { AButton, ATab, LucideIcon } from '@/components/common/ao' import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' import CustomHeader from '@/components/custom/Header' import { Spinner } from '@/components/ui/spinner' -import { createFinanceCategoryApi, deleteFinanceCategoryApi, updateFinanceCategoryApi } from '@/request/api/finance/category' +import { createFinanceCategoryApi, deleteFinanceCategoryApi, updateFinanceCategoryApi, updateFinanceCategorySortNumberApi } from '@/request/api/finance/category' import { useFinanceStore } from '@/store/finance' import { useMoneyCategoryStore } from '@/store/moneyCategory' import { useSpaceStore } from '@/store/space' @@ -209,7 +209,23 @@ export default function MoneyCategorySetting() { const newData = dragData.data if (JSON.stringify(categories) !== JSON.stringify(newData)) { - moneyCategoryStore.updateSortNumbers(newData, selectedTab) + const updateData: any[] = [] + newData.forEach((item, index) => { + item.sort_number = index + + updateData.push({ + id: item.id, + sort_number: index, + }) + }) + + financeStore.setCategories(newData) + + updateFinanceCategorySortNumberApi({ + categories: updateData, + }).then((res) => { + console.log(res) + }) } }} /> diff --git a/code/allapp/allapp-rn/src/app/finance/record/detail/index.tsx b/code/allapp/allapp-rn/src/app/finance/record/detail/index.tsx new file mode 100644 index 00000000..9c38abe1 --- /dev/null +++ b/code/allapp/allapp-rn/src/app/finance/record/detail/index.tsx @@ -0,0 +1,155 @@ +import type { FinanceCategory } from '@/types/finance/category' +import type { FinanceRecordDetail } from '@/types/finance/record' +import { useFocusEffect, useLocalSearchParams, useRouter } from 'expo-router' +import { useCallback, useEffect, useState } from 'react' +import { ActivityIndicator, Text, View } from 'react-native' +import { toast } from 'sonner-native' +import { AButton, ACell, ACellGroup, AModal } from '@/components/common/ao' +import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' +import CustomHeader from '@/components/custom/Header' +import { deleteFinanceRecordApi, getFinanceRecordDetailApi } from '@/request/api/finance/record' +import { useFinanceStore } from '@/store/finance' +import { useNavStore } from '@/store/navigation' +import { MoneyCategoryEnum } from '@/types/money/category' +import { toDateTimeString } from '@/utils/time' + +export default function MoneyRecordDetail() { + const router = useRouter() + const financeStore = useFinanceStore() + const navStore = useNavStore() + + const { id: detailId } = useLocalSearchParams<{ id: string }>() + + const [showDeleteModal, setShowDeleteModal] = useState(false) + const [detail, setDetail] = useState(null) + const [loading, setLoading] = useState(true) + + const [category, setCategory] = useState(null) + + useFocusEffect( + useCallback(() => { + if (detailId) { + setLoading(true) + + getFinanceRecordDetailApi({ + id: Number(detailId), + }).then((res) => { + if (res.isSuccess) { + setDetail(res.data) + setLoading(false) + + const category = financeStore.getCategoryById(res.data.category_id) + if (category) { + setCategory(category) + } + } + }) + } + }, []), + ) + + return ( + <> + + + + { + loading + ? ( + + + + ) + : ( + <> + + + {category?.name} + + + + + + + + + + { + detail?.create_member_id !== detail?.update_member_id && ( + <> + + + + ) + } + + + + + + { + setShowDeleteModal(true) + }} + > + 删除 + + { + router.navigate({ + pathname: '/finance/record/editor', + params: { id: detailId }, + }) + }} + > + 编辑 + + + + ) + } + + + + { + setShowDeleteModal(false) + if (!detail) { + toast.warning('当前记录无效') + router.back() + return + } + + const toastId = toast.loading('正在删除...', { + duration: Infinity, + }) + + await deleteFinanceRecordApi({ + id: detail?.id, + }).then((res) => { + if (res.isSuccess) { + toast.success('删除成功') + + router.back() + } + }).finally(() => { + toast.dismiss(toastId) + }) + }} + onCancel={() => { + setShowDeleteModal(false) + }} + onClose={() => { + setShowDeleteModal(false) + }} + /> + + ) +} diff --git a/code/allapp/allapp-rn/src/app/finance/record/editor/components/AmountKeyboard.tsx b/code/allapp/allapp-rn/src/app/finance/record/editor/components/AmountKeyboard.tsx index 20e03858..a4fb0e3f 100644 --- a/code/allapp/allapp-rn/src/app/finance/record/editor/components/AmountKeyboard.tsx +++ b/code/allapp/allapp-rn/src/app/finance/record/editor/components/AmountKeyboard.tsx @@ -1,3 +1,4 @@ +import type { FinanceRecord } from '@/types/finance/record' import Big from 'big.js' import { useEffect, useState } from 'react' import { Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native' @@ -39,23 +40,15 @@ const keys: KeydownItem[] = [ interface AmountKeyboardProps { show?: boolean - record_time?: string - amount?: string - remark?: string - - // 回调:当键盘输入或修改数据时触发 - onChange?: (data: { record_time: string, amount: string, remark: string }) => void + record: FinanceRecord // 可选:点击完成按钮触发 - onDone?: () => void + onDone?: (record: FinanceRecord) => void } export default function AmountKeyboard({ show = false, - record_time = '', - amount = '', - remark = '', - onChange, + record, onDone, }: AmountKeyboardProps) { // 自定义键盘计算过程 @@ -67,43 +60,36 @@ export default function AmountKeyboard({ // 键盘高度 const keyboardHeight = useKeyboardHeight() - // 使用一个对象管理三个字段 - const [internalData, setInternalData] = useState({ - record_time: record_time || getCurrentDate(), - amount: amount || '0', - remark: remark || '', + const [innerRecord, setInnerRecord] = useState({ + id: 0, + category_id: 0, + amount: '', + remark: '', + record_time: getCurrentDate(), + member_id: 0, + member_name: '', }) - // 如果父组件 props 变化,需要同步 useEffect(() => { - setInternalData({ - record_time: record_time || getCurrentDate(), - amount: amount || '0', - remark: remark || '', + setInnerRecord(record) + setKeydownInput(record.amount || '') + }, [record]) + + useEffect(() => { + setInnerRecord((prev) => { + if (!keydownInput) { + return { ...prev, amount: '0' } + } + try { + const result = calculateWithBig(keydownInput) + return { ...prev, amount: result } + } + catch { + return { ...prev, amount: '0' } + } }) - }, [record_time, amount, remark]) - - useEffect(() => { - if (!keydownInput) { - handleChange({ amount: '0' }) - return - } - - try { - const computed = calculateWithBig(keydownInput) - handleChange({ amount: computed }) - } - catch { - handleChange({ amount: '0' }) - } }, [keydownInput]) - const handleChange = (newData: Partial) => { - const updated = { ...internalData, ...newData } - setInternalData(updated) - onChange?.(updated) - } - // 计算过程 const handlePress = (key: string | number) => { setKeydownInput((prev) => { @@ -113,7 +99,8 @@ export default function AmountKeyboard({ newInput = prev.slice(0, -1) } else if (key === 'clear') { - setInternalData({ + setInnerRecord({ + ...innerRecord, record_time: getCurrentDate(), amount: '0', remark: '', @@ -121,7 +108,7 @@ export default function AmountKeyboard({ return '' } else if (key === '/') { - onDone?.() + onDone?.(innerRecord) return prev } else { @@ -206,7 +193,7 @@ export default function AmountKeyboard({ newInput = prev + keyStr } } - + return newInput }) } @@ -271,10 +258,11 @@ export default function AmountKeyboard({ } return ( - @@ -284,19 +272,24 @@ export default function AmountKeyboard({ onPress={() => setShowDatePicker(true)} > - {internalData.record_time} + {innerRecord.record_time} - {internalData.amount} + {innerRecord.amount} {keydownInput} handleChange({ remark: val })} + onChangeText={(val) => { + setInnerRecord({ + ...innerRecord, + remark: val, + }) + }} onFocus={() => setRemarkIsFocused(true)} onBlur={() => setRemarkIsFocused(false)} /> @@ -352,14 +345,18 @@ export default function AmountKeyboard({ { setShowDatePicker(false) }} onConfirm={(date) => { setShowDatePicker(false) - handleChange({ record_time: date }) + + setInnerRecord({ + ...innerRecord, + record_time: date, + }) }} /> diff --git a/code/allapp/allapp-rn/src/app/finance/record/editor/index.tsx b/code/allapp/allapp-rn/src/app/finance/record/editor/index.tsx index 2871d104..abb17bbf 100644 --- a/code/allapp/allapp-rn/src/app/finance/record/editor/index.tsx +++ b/code/allapp/allapp-rn/src/app/finance/record/editor/index.tsx @@ -29,7 +29,7 @@ export default function MoenyRecordEditor() { const defaultFinanceRecord: FinanceRecord = { id: -1, category_id: -1, - amount: '0.00', + amount: '', remark: '', record_time: getCurrentDate(), member_id: -1, @@ -58,26 +58,26 @@ export default function MoenyRecordEditor() { }, []) // 保存记录 - function handleSaveRecord() { + async function handleSaveRecord(record: FinanceRecord) { if (selectedCategory === null) { toast.warning('请选择分类') return } - if (financeRecord.amount === '0.00') { + if (record.amount === '0.00') { toast.warning('请输入金额') return } - const amount = financeRecord.amount.replace(/^-+/, '') + const innerAmount = record.amount.replace(/^-+/, '') if (updateId) { - updateFinanceRecordApi({ + await updateFinanceRecordApi({ id: financeRecord.id, category_id: selectedCategory.id, - amount, - remark: financeRecord.remark, - record_time: financeRecord.record_time, + amount: innerAmount, + remark: record.remark, + record_time: record.record_time, }).then((res) => { if (res.isSuccess) { router.back() @@ -85,11 +85,11 @@ export default function MoenyRecordEditor() { }) } else { - createFinanceRecordApi({ - amount, + await createFinanceRecordApi({ + amount: innerAmount, category_id: selectedCategory.id, - remark: financeRecord.remark, - record_time: financeRecord.record_time, + remark: record.remark, + record_time: record.record_time, }) .then((res) => { if (res.isSuccess) { @@ -116,7 +116,7 @@ export default function MoenyRecordEditor() { { - router.navigate('/finance/category/setting') + router.push('/finance/category') }} > @@ -169,17 +169,7 @@ export default function MoenyRecordEditor() { { - setFinanceRecord({ - ...financeRecord, - record_time: data.record_time, - amount: data.amount, - remark: data.remark, - }) - }} + record={financeRecord} onDone={handleSaveRecord} /> diff --git a/code/allapp/allapp-rn/src/components/common/ao/Input.tsx b/code/allapp/allapp-rn/src/components/common/ao/Input.tsx index d3510f1b..afa22600 100644 --- a/code/allapp/allapp-rn/src/components/common/ao/Input.tsx +++ b/code/allapp/allapp-rn/src/components/common/ao/Input.tsx @@ -47,7 +47,6 @@ const AInput = forwardRef, AInputProps>( isFocused={isFocused} className={className} style={style} - > {leftIcon && ( diff --git a/code/allapp/allapp-rn/src/request/api/finance/record.ts b/code/allapp/allapp-rn/src/request/api/finance/record.ts index 878663db..abe152a3 100644 --- a/code/allapp/allapp-rn/src/request/api/finance/record.ts +++ b/code/allapp/allapp-rn/src/request/api/finance/record.ts @@ -1,4 +1,4 @@ -import type { CreateFinanceRecordParams, DeleteFinanceRecordParams, ListFinanceRecordsParams, ListFinanceRecordsResult, UpdateFinanceRecordParams } from '@/types/finance/record' +import type { CreateFinanceRecordParams, DeleteFinanceRecordParams, GetFinanceRecordDetailParams, GetFinanceRecordDetailResult, ListFinanceRecordsParams, ListFinanceRecordsResult, UpdateFinanceRecordParams } from '@/types/finance/record' import alovaInstance from '../../index' const API_PREFIX = '/finance/record' @@ -18,3 +18,7 @@ export function updateFinanceRecordApi(params: UpdateFinanceRecordParams) { export function deleteFinanceRecordApi(params: DeleteFinanceRecordParams) { return alovaInstance.Post>(`${API_PREFIX}/delete`, params) } + +export function getFinanceRecordDetailApi(params: GetFinanceRecordDetailParams) { + return alovaInstance.Post>(`${API_PREFIX}/detail`, params) +} diff --git a/code/allapp/allapp-rn/src/request/index.ts b/code/allapp/allapp-rn/src/request/index.ts index 960c014f..e1b1517e 100644 --- a/code/allapp/allapp-rn/src/request/index.ts +++ b/code/allapp/allapp-rn/src/request/index.ts @@ -31,8 +31,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - // baseURL: 'http://192.168.5.6:8086/app', - baseURL: 'http://192.168.1.137:8086/app', + baseURL: 'http://192.168.5.6:8086/app', + // baseURL: 'http://192.168.1.137:8086/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null, diff --git a/code/allapp/allapp-rn/src/store/finance.ts b/code/allapp/allapp-rn/src/store/finance.ts index c4dc0ce1..55e068cf 100644 --- a/code/allapp/allapp-rn/src/store/finance.ts +++ b/code/allapp/allapp-rn/src/store/finance.ts @@ -16,7 +16,6 @@ interface FinanceState { createCategory: (category: FinanceCategory) => void updateCategory: (category: FinanceCategory) => void deleteCategory: (id: number) => void - updateCategorySortNumber: (data: FinanceCategory[], type: number) => void isDuplicateCategory: (name: string, type: number, excludeId: number | null) => boolean getDefaultGroupRow: (iconName: string) => number getCategoryById: (id: number) => FinanceCategory | null @@ -301,16 +300,6 @@ export const useFinanceStore = create()( const finalCategories = allCategories.filter(c => c.id !== id) set({ categories: finalCategories }) }, - updateCategorySortNumber: (data, type) => { - const allCategories = get().categories - const otherCategories = allCategories.filter(c => c.type !== type) - const updatedData = data.map((item, index) => ({ - ...item, - sort_number: index, - })) - - set({ categories: [...otherCategories, ...updatedData] }) - }, isDuplicateCategory: (name, type, excludeId) => { const categories = get().categories || [] return categories.some(c => diff --git a/code/allapp/allapp-rn/src/types/finance/record.ts b/code/allapp/allapp-rn/src/types/finance/record.ts index 2465c38f..9ccbf736 100644 --- a/code/allapp/allapp-rn/src/types/finance/record.ts +++ b/code/allapp/allapp-rn/src/types/finance/record.ts @@ -19,6 +19,7 @@ export interface ListFinanceRecordsParams { start_time: string end_time: string category_id: number + category_type: number } export interface ListFinanceRecordsResult { @@ -43,3 +44,27 @@ export interface UpdateFinanceRecordParams { export interface DeleteFinanceRecordParams { id: number } + +export interface FinanceRecordDetail { + id: number + category_id: number + amount: string + remark: string + record_time: string + + create_time: number + create_member_id: number + create_member_name: string + + update_time: number + update_member_id: number + update_member_name: string +} + +export interface GetFinanceRecordDetailParams { + id: number +} + +export interface GetFinanceRecordDetailResult extends FinanceRecordDetail { + +} diff --git a/code/allapp/allapp-rn/test.html b/code/allapp/allapp-rn/test.html index a1f81fca..d90f90cb 100644 --- a/code/allapp/allapp-rn/test.html +++ b/code/allapp/allapp-rn/test.html @@ -1,130 +1,177 @@ - - +import type { FinanceRecord } from '@/types/finance/record' +import Big from 'big.js' +import { useEffect, useState } from 'react' +import { Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native' +import { ADatePicker, AInput, LucideIcon } from '@/components/common/ao/index' +import { useKeyboardHeight } from '@/hooks/useKeyboardHeight' +import { getCurrentDate } from '@/utils/time' - - - - 加入其它空间 Demo - - - - - - -
- 加入其它空间 - → -
- - - - - - - - - \ No newline at end of file + setInnerRecord({ + ...innerRecord, + record_time: date, + }) + }} + /> + + ) +}