diff --git a/code/allapp/allapp-rn/src/app/money/category/setting/components/CreateCategory.tsx b/code/allapp/allapp-rn/src/app/money/category/setting/components/CreateCategory.tsx new file mode 100644 index 00000000..59b1cacb --- /dev/null +++ b/code/allapp/allapp-rn/src/app/money/category/setting/components/CreateCategory.tsx @@ -0,0 +1,105 @@ +import { useEffect, useState } from 'react' +import { Pressable, ScrollView, Text, View } from 'react-native' +import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' +import { + Drawer, + DrawerBackdrop, + DrawerBody, + DrawerContent, + DrawerHeader, +} from '@/components/ui/drawer' +import { Input, InputField } from '@/components/ui/input' + +import { useMoneyCategoryStore } from '@/store/moneyCategory' + +interface CreateCategoryProps { + open: boolean + onClose?: () => void +} + +export default function CreateCategory({ + open, + onClose, +}: CreateCategoryProps) { + const moneyCategoryStore = useMoneyCategoryStore() + + const [isOpen, setIsOpen] = useState(open) + + useEffect(() => { + setIsOpen(open) + }, [open]) + + function handleClose() { + setIsOpen(false) + onClose && onClose() + } + + return ( + + + + + + + 取消 + + + 类别 + + + 确认 + + + + + + + + + + + {Object.entries(moneyCategoryStore.ICON_GROUPS).map(([groupName, icons]) => ( + + + {groupName} + + + + {icons.map(icon => ( + { + console.log('select icon:', icon) + }} + > + + + + + ))} + + + ))} + + + + + ) +} diff --git a/code/allapp/allapp-rn/src/app/money/category/setting/index.tsx b/code/allapp/allapp-rn/src/app/money/category/setting/index.tsx index 551450b4..768f9f68 100644 --- a/code/allapp/allapp-rn/src/app/money/category/setting/index.tsx +++ b/code/allapp/allapp-rn/src/app/money/category/setting/index.tsx @@ -9,6 +9,7 @@ import { AButton, ATab, LucideIcon } from '@/components/common/ao' import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' import CustomHeader from '@/components/custom/Header' import { useMoneyCategoryStore } from '@/store/moneyCategory' +import CreateCategory from './components/CreateCategory' export default function MoneyCategorySetting() { const [selectedTab, setSelectedTab] = useState(0) @@ -21,6 +22,8 @@ export default function MoneyCategorySetting() { const [draggingDeleteZone, setDraggingDeleteZone] = useState(false) const [deleteTimer, setDeleteTimer] = useState(null) + const [openCreateCategory, setOpenCreateCategory] = useState(false) + useEffect(() => { setCategories(selectedTab === 0 ? moneyCategoryStore.getExpenseCategories() : moneyCategoryStore.getIncomeCategories()) }, [selectedTab]) @@ -90,6 +93,9 @@ export default function MoneyCategorySetting() { color: '#fff', clickable: false, }} + onPress={(() => + setOpenCreateCategory(true) + )} > 新增 @@ -114,14 +120,16 @@ export default function MoneyCategorySetting() { Vibration.vibrate(50) setDraggingId(data.key) }} - onDragEnd={(data) => { + onDragEnd={(dragData) => { setDraggingId('') if (draggingDeleteZone) return - const newOrder = data.data + const newData = dragData.data - moneyCategoryStore.updateCategories(newOrder, selectedTab) + if (JSON.stringify(categories) !== JSON.stringify(newData)) { + moneyCategoryStore.updateSortNumbers(newData, selectedTab) + } }} /> @@ -139,7 +147,7 @@ export default function MoneyCategorySetting() { const deleteId = Number(draggingId) setCategories(prev => prev.filter(c => c.id !== deleteId)) - moneyCategoryStore.deleteCategoryById(deleteId, selectedTab) + moneyCategoryStore.deleteCategoryById(deleteId) setDraggingId('') setDraggingDeleteZone(false) @@ -179,6 +187,11 @@ export default function MoneyCategorySetting() { + + setOpenCreateCategory(false)} + /> ) } diff --git a/code/allapp/allapp-rn/src/app/system/share/index.tsx b/code/allapp/allapp-rn/src/app/system/share/index.tsx index 7dcd0e37..83b03466 100644 --- a/code/allapp/allapp-rn/src/app/system/share/index.tsx +++ b/code/allapp/allapp-rn/src/app/system/share/index.tsx @@ -18,7 +18,7 @@ export default function PagerWithTab() { const fetchData = async () => { await Promise.all([ - getUserSpaceApi({}) + getUserSpaceApi() .then((res) => { if (res.isSuccess) { if (res.data === null) { diff --git a/code/allapp/allapp-rn/src/request/api/space/spaceUser.ts b/code/allapp/allapp-rn/src/request/api/space/spaceUser.ts index f1b8cc3f..cee36e52 100644 --- a/code/allapp/allapp-rn/src/request/api/space/spaceUser.ts +++ b/code/allapp/allapp-rn/src/request/api/space/spaceUser.ts @@ -1,8 +1,6 @@ import type { ExitSpaceParams, ExitSpaceResult, - GetUserSpaceParams, - GetUserSpaceResult, JoinSpaceParams, JoinSpaceResult, ListSpaceUsersParams, @@ -14,8 +12,8 @@ import alovaInstance from '../../index' const API_PREFIX = '/space/user' -export function getUserSpaceApi(params: GetUserSpaceParams) { - return alovaInstance.Get>(`${API_PREFIX}/get`, params) +export function getUserSpaceApi() { + return alovaInstance.Get>(`${API_PREFIX}/get`) } export function exitSpaceApi(params: ExitSpaceParams) { diff --git a/code/allapp/allapp-rn/src/store/app.ts b/code/allapp/allapp-rn/src/store/app.ts index 8f466252..9f229324 100644 --- a/code/allapp/allapp-rn/src/store/app.ts +++ b/code/allapp/allapp-rn/src/store/app.ts @@ -18,7 +18,6 @@ export const useAppStore = create((set, get) => ({ setReady: (v: boolean) => set({ ready: v }), init: async () => { - // 如果已经初始化过就不重复执行(除非你手动 setReady(false) 再 init) if (get().ready) return @@ -40,7 +39,7 @@ export const useAppStore = create((set, get) => ({ await moneyCategoryStore.init() // 获取空间信息 - const res = await getUserSpaceApi({}) + const res = await getUserSpaceApi() spaceStore.setUserSpace(res.data) } catch (err) { diff --git a/code/allapp/allapp-rn/src/store/moneyCategory.ts b/code/allapp/allapp-rn/src/store/moneyCategory.ts index 379077a2..3d27bf67 100644 --- a/code/allapp/allapp-rn/src/store/moneyCategory.ts +++ b/code/allapp/allapp-rn/src/store/moneyCategory.ts @@ -1,147 +1,180 @@ import type { MoneyCategoryItem, UpdateMoneyCategorySortItem } from '@/types/money/category' -import AsyncStorage from '@react-native-async-storage/async-storage' import { create } from 'zustand' -import { createJSONStorage, persist } from 'zustand/middleware' import { deleteMoneyCategoryApi, queryMoneyCategoryApi, updateMoneyCategorySortApi } from '@/request/api/money/category' interface MoneyCategoryStore { + ICON_GROUPS: Record categories: MoneyCategoryItem[] + init: () => Promise setCategories: (categories: MoneyCategoryItem[]) => void addCategory: (category: MoneyCategoryItem) => void - removeCategory: (id: number) => void - init: () => Promise getExpenseCategories: () => MoneyCategoryItem[] getIncomeCategories: () => MoneyCategoryItem[] getCategoryById: (id: number) => MoneyCategoryItem | null - updateCategories: (data: MoneyCategoryItem[], type: number) => void - deleteCategoryById: (id: number, type: number) => void - - sysCategories: MoneyCategoryItem[] - setSysCategories: (categories: MoneyCategoryItem[]) => void + updateSortNumbers: (data: MoneyCategoryItem[], type: number) => void + deleteCategoryById: (id: number) => void clear: () => void } export const useMoneyCategoryStore = create()( - persist( - (set, get) => ({ - categories: [], - sysCategories: [], + (set, get) => ({ + ICON_GROUPS: { + 餐饮: [ + 'money_canyin', + 'money_yinpin', + 'money_lingshi', + 'money_xiaoye', + ], + 娱乐: [ + 'money_yule', + 'money_youxi', + 'money_dianying', + ], + 交通: [ + 'money_jiaotong', + 'money_tingchefei', + 'money_jiayou', + ], + 生活消费: [ + 'money_lijin', + 'money_jiadian', + 'money_riyongpin', + 'money_shucai', + 'money_meifa', + 'money_shuidian', + 'money_wenju', + 'money_zhufang', + 'money_baoxian', + 'money_baojianpin', + 'money_huafei', + 'money_lvyou', + 'money_gouwu', + 'money_shuben', + 'money_chongwu', + 'money_ruanjian', + ], + 健康: [ + 'money_tijian', + 'money_yao', + 'money_jiuyi', + ], + 公益: [ + 'money_gongyi', + ], + 兼职与收入: [ + 'money_gongzi', + 'money_jianzhi', + ], + 鲜花与水果: [ + 'money_shuiguo', + 'money_xianhua', + ], + 转账与转移: [ + 'money_zhuanzhang', + ], + 家庭与家电: [ + 'money_kuaidi', + 'money_weixiu', + 'money_jiaju', + 'money_muying', + 'money_liwu', + ], + 运动与娱乐: [ + 'money_yundong', + 'money_peixun', + ], + }, - setCategories: categories => set({ categories }), - setSysCategories: categories => set({ categories }), + categories: [], - addCategory: category => - set({ categories: [...get().categories, category] }), + setCategories: categories => set({ categories }), - removeCategory: id => - set({ categories: get().categories.filter(c => c.id !== id) }), + addCategory: category => + set({ categories: [...get().categories, category] }), - init: async () => { - try { - await queryMoneyCategoryApi().then((res) => { - if (res.isSuccess) { - set({ categories: res.data.categories || [] }) - } - }).catch((err) => { - console.log(err) - }).finally(() => { - - }) - } - catch (e) { - console.error('Fetch category failed:', e) - } - }, - - clear: () => { - set({ categories: [] }) - }, - - 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 - }, - - getSysCategoryById: (id: number) => { - return get().sysCategories.find(c => c.id === id) || null - }, - - updateCategories: (data, type) => { - // 获取当前所有分类 - const allCategories = get().categories - - // 保留另一类分类 - const otherCategories = allCategories.filter(c => c.type !== type) - - // 给当前类型的数据重新计算 sort_number - const updatedData = data.map((item, index) => ({ - ...item, - sort_number: index, // 按顺序重新赋值 - })) - - // 合并另一类分类 - const finalCategories = [...otherCategories, ...updatedData] - - // 构造后端请求 payload,只需要 id 和 sort_number - const payload: UpdateMoneyCategorySortItem[] = updatedData.map(item => ({ - id: item.id, - sort_number: item.sort_number, - })) - - // 调用后端接口更新排序 - updateMoneyCategorySortApi({ - data: payload, - }).then((res) => { - console.log('后端返回:', res) + init: async () => { + try { + await queryMoneyCategoryApi().then((res) => { + if (res.isSuccess) { + set({ categories: res.data.categories || [] }) + } }).catch((err) => { console.log(err) + }).finally(() => { + }) - - // 更新前端 state - set({ categories: finalCategories }) - }, - - deleteCategoryById: async (id: number, type: number) => { - const allCategories = get().categories - - // 删除指定 id,同时只处理同类型的数据 - const finalCategories = allCategories - .filter(c => c.id !== id) - .map((item, index) => { - if (item.type === type) { - return { ...item, sort_number: index } - } - return item - }) - - // 更新 state - set({ categories: finalCategories }) - - // 调用删除接口 - await deleteMoneyCategoryApi({ id }).catch((err) => { - console.log(err) - }) - - // 同步更新排序给后端,仅同类型 - const payload = finalCategories - .filter(c => c.type === type) - .map(item => ({ - id: item.id, - sort_number: item.sort_number, - })) - await updateMoneyCategorySortApi({ data: payload }) - }, - }), - { - name: 'money-category-storage', - storage: createJSONStorage(() => AsyncStorage), + } + catch (e) { + console.error('Fetch category failed:', e) + } }, - ), + + clear: () => { + set({ categories: [] }) + }, + + 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 + }, + + updateSortNumbers: (data, type) => { + // 获取当前所有分类 + const allCategories = get().categories + + // 保留另一类分类 + const otherCategories = allCategories.filter(c => c.type !== type) + + // 给当前类型的数据重新计算 sort_number + const updatedData = data.map((item, index) => ({ + ...item, + sort_number: index, // 按顺序重新赋值 + })) + + // 合并另一类分类 + const finalCategories = [...otherCategories, ...updatedData] + + // 构造后端请求 payload,只需要 id 和 sort_number + const payload: UpdateMoneyCategorySortItem[] = updatedData.map(item => ({ + id: item.id, + sort_number: item.sort_number, + })) + + // 调用后端接口更新排序 + updateMoneyCategorySortApi({ + data: payload, + }).then((res) => { + console.log('后端返回:', res) + }).catch((err) => { + console.log(err) + }) + + // 更新前端 state + set({ categories: finalCategories }) + }, + + deleteCategoryById: async (id: number) => { + const allCategories = get().categories + + // 删除指定 id,同时只处理同类型的数据 + const finalCategories = allCategories + .filter(c => c.id !== id) + + // 更新 state + set({ categories: finalCategories }) + + // 调用删除接口 + await deleteMoneyCategoryApi({ id }).catch((err) => { + console.log(err) + }) + }, + }), + ) diff --git a/code/allapp/allapp-rn/src/store/moneyRecord.ts b/code/allapp/allapp-rn/src/store/moneyRecord.ts index 749ee58b..4f07e3b6 100644 --- a/code/allapp/allapp-rn/src/store/moneyRecord.ts +++ b/code/allapp/allapp-rn/src/store/moneyRecord.ts @@ -42,7 +42,7 @@ export const useMoneyRecordStore = create((set, get) => ({ if (!isInMonth(data.record_time, prev.currentMonth)) return prev - const category = useMoneyCategoryStore.getState().getCategoryById(data.category_id) + const category = useMoneyCategoryStore.getState().getById(data.category_id) const records = [...prev.records] const groupIndex = records.findIndex(g => g.record_time === data.record_time) const amount = data.amount @@ -88,12 +88,12 @@ export const useMoneyRecordStore = create((set, get) => ({ if (oldGroupIndex === -1) return prev - const updateRecordCategory = useMoneyCategoryStore.getState().getCategoryById((updated.category_id)) + const updateRecordCategory = useMoneyCategoryStore.getState().getById((updated.category_id)) const oldGroup = { ...records[oldGroupIndex], records: [...records[oldGroupIndex].records] } const oldRecordIndex = oldGroup.records.findIndex(r => r.id === updated.id) const oldRecord = oldGroup.records[oldRecordIndex] - const oldRecordCategory = useMoneyCategoryStore.getState().getCategoryById((oldRecord.category_id)) + const oldRecordCategory = useMoneyCategoryStore.getState().getById((oldRecord.category_id)) const oldAmount = oldRecord.amount const newAmount = updated.amount @@ -158,7 +158,7 @@ export const useMoneyRecordStore = create((set, get) => ({ const index = group.records.findIndex(r => r.id === id) if (index !== -1) { const record = group.records[index] - const category = useMoneyCategoryStore.getState().getCategoryById(record.category_id) + const category = useMoneyCategoryStore.getState().getById(record.category_id) if (category?.id === 0) total_expense = sub(total_expense, record.amount) diff --git a/code/allapp/allapp-rn/src/types/space/spaceUser.ts b/code/allapp/allapp-rn/src/types/space/spaceUser.ts index c1bab83a..f0e009bf 100644 --- a/code/allapp/allapp-rn/src/types/space/spaceUser.ts +++ b/code/allapp/allapp-rn/src/types/space/spaceUser.ts @@ -1,14 +1,3 @@ -// 获取用户的空间 -export interface GetUserSpaceParams { - -} -export interface GetUserSpaceResult { - space_id: number - space_name: string - role: number - invite_code: string -} - // 退出空间 export interface ExitSpaceParams {