u
This commit is contained in:
1 parent
cb4562361a
commit
b38583a9fe
11 files changed
+174
-85
No files matched your search
@@ -87,7 +87,7 @@ func RegisterDefault(ctx context.Context, c *app.RequestContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 初始化用户分类
|
// 初始化用户分类
|
||||||
err = initMoneyCategoryTx(ctx, tx, params.ID)
|
err = InitMoneyCategoryTx(ctx, tx, params.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorx.AddError(c, err)
|
errorx.AddError(c, err)
|
||||||
return
|
return
|
||||||
@@ -97,8 +97,15 @@ func RegisterDefault(ctx context.Context, c *app.RequestContext) {
|
|||||||
response.Success(c).Message("注册成功").Send()
|
response.Success(c).Message("注册成功").Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
func initMoneyCategoryTx(ctx context.Context, tx pgx.Tx, userId int64) error {
|
func InitMoneyCategoryTx(
|
||||||
sysCategories, err := db.Queries.ListMoneySysCategory(ctx)
|
ctx context.Context,
|
||||||
|
tx pgx.Tx,
|
||||||
|
userId int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
q := db.Queries.WithTx(tx)
|
||||||
|
|
||||||
|
sysCategories, err := q.ListMoneySysCategory(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -118,9 +125,12 @@ func initMoneyCategoryTx(ctx context.Context, tx pgx.Tx, userId int64) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Queries.WithTx(tx).BatchInsertMoneyUserCategories(ctx, userCategories)
|
// ⚠️ 注意:这里是 DeleteMoneyCategoryByUserId,不是 ById(你代码里疑似写错)
|
||||||
|
if err := q.DeleteMoneyCategoryByUserId(ctx, userId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if _, err := q.BatchInsertMoneyUserCategories(ctx, userCategories); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func DeleteUserMoneyCategory(ctx context.Context, c *app.RequestContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Queries.DeleteUserMoneyCategoryById(ctx, req.Id)
|
err = db.Queries.DeleteMoneyCategoryById(ctx, req.Id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorx.AddError(c, err)
|
errorx.AddError(c, err)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ SELECT *
|
|||||||
FROM money_user_category
|
FROM money_user_category
|
||||||
WHERE user_id = $1;
|
WHERE user_id = $1;
|
||||||
|
|
||||||
-- name: DeleteUserMoneyCategoryById :exec
|
-- name: DeleteMoneyCategoryById :exec
|
||||||
DELETE FROM money_user_category
|
DELETE FROM money_user_category
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
@@ -15,3 +15,7 @@ WHERE id = $1;
|
|||||||
UPDATE money_user_category
|
UPDATE money_user_category
|
||||||
SET sort_number = $2
|
SET sort_number = $2
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: DeleteMoneyCategoryByUserId :exec
|
||||||
|
DELETE FROM money_user_category
|
||||||
|
WHERE user_id = $1;
|
||||||
@@ -18,13 +18,23 @@ type BatchInsertMoneyUserCategoriesParams struct {
|
|||||||
SortNumber int32
|
SortNumber int32
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteUserMoneyCategoryById = `-- name: DeleteUserMoneyCategoryById :exec
|
const deleteMoneyCategoryById = `-- name: DeleteMoneyCategoryById :exec
|
||||||
DELETE FROM money_user_category
|
DELETE FROM money_user_category
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeleteUserMoneyCategoryById(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteMoneyCategoryById(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, deleteUserMoneyCategoryById, id)
|
_, err := q.db.Exec(ctx, deleteMoneyCategoryById, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteMoneyCategoryByUserId = `-- name: DeleteMoneyCategoryByUserId :exec
|
||||||
|
DELETE FROM money_user_category
|
||||||
|
WHERE user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteMoneyCategoryByUserId(ctx context.Context, userID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteMoneyCategoryByUserId, userID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
"@types/big.js": "^6.2.2",
|
"@types/big.js": "^6.2.2",
|
||||||
"@types/react": "~19.1.0",
|
"@types/react": "~19.1.0",
|
||||||
"babel-plugin-module-resolver": "^5.0.2",
|
"babel-plugin-module-resolver": "^5.0.2",
|
||||||
|
"baseline-browser-mapping": "^2.9.14",
|
||||||
"eslint": "^9.38.0",
|
"eslint": "^9.38.0",
|
||||||
"react-native-iconfont-cli": "^2.2.4",
|
"react-native-iconfont-cli": "^2.2.4",
|
||||||
"react-native-svg-transformer": "^1.5.2",
|
"react-native-svg-transformer": "^1.5.2",
|
||||||
|
|||||||
Generated
+7
-4
@@ -162,6 +162,9 @@ importers:
|
|||||||
babel-plugin-module-resolver:
|
babel-plugin-module-resolver:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
|
baseline-browser-mapping:
|
||||||
|
specifier: ^2.9.14
|
||||||
|
version: 2.9.14
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.38.0
|
specifier: ^9.38.0
|
||||||
version: 9.39.1(jiti@1.21.7)
|
version: 9.39.1(jiti@1.21.7)
|
||||||
@@ -2509,8 +2512,8 @@ packages:
|
|||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
baseline-browser-mapping@2.8.28:
|
baseline-browser-mapping@2.9.14:
|
||||||
resolution: {integrity: sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==}
|
resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
better-opn@3.0.2:
|
better-opn@3.0.2:
|
||||||
@@ -9105,7 +9108,7 @@ snapshots:
|
|||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
baseline-browser-mapping@2.8.28: {}
|
baseline-browser-mapping@2.9.14: {}
|
||||||
|
|
||||||
better-opn@3.0.2:
|
better-opn@3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9146,7 +9149,7 @@ snapshots:
|
|||||||
|
|
||||||
browserslist@4.28.0:
|
browserslist@4.28.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
baseline-browser-mapping: 2.8.28
|
baseline-browser-mapping: 2.9.14
|
||||||
caniuse-lite: 1.0.30001754
|
caniuse-lite: 1.0.30001754
|
||||||
electron-to-chromium: 1.5.252
|
electron-to-chromium: 1.5.252
|
||||||
node-releases: 2.0.27
|
node-releases: 2.0.27
|
||||||
|
|||||||
+76
-41
@@ -1,37 +1,67 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Pressable, ScrollView, Text, View } from 'react-native'
|
import { Pressable, Text, View } from 'react-native'
|
||||||
|
import { AButton } from '@/components/common/ao'
|
||||||
import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon'
|
import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon'
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
DrawerBackdrop,
|
DrawerBackdrop,
|
||||||
DrawerBody,
|
DrawerBody,
|
||||||
DrawerContent,
|
DrawerContent,
|
||||||
|
DrawerFooter,
|
||||||
DrawerHeader,
|
DrawerHeader,
|
||||||
} from '@/components/ui/drawer'
|
} from '@/components/ui/drawer'
|
||||||
import { Input, InputField } from '@/components/ui/input'
|
import { Input, InputField } from '@/components/ui/input'
|
||||||
|
|
||||||
import { useMoneyCategoryStore } from '@/store/moneyCategory'
|
import { useMoneyCategoryStore } from '@/store/moneyCategory'
|
||||||
|
import { MoneyCategoryEnum } from '@/types/money/category'
|
||||||
|
|
||||||
interface CreateCategoryProps {
|
interface CreateCategoryProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
onClose?: () => void
|
onClose?: () => void
|
||||||
|
type: MoneyCategoryEnum
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateCategoryForm {
|
||||||
|
icon: string
|
||||||
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CreateCategory({
|
export default function CreateCategory({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
|
type,
|
||||||
}: CreateCategoryProps) {
|
}: CreateCategoryProps) {
|
||||||
const moneyCategoryStore = useMoneyCategoryStore()
|
const moneyCategoryStore = useMoneyCategoryStore()
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(open)
|
const [isOpen, setIsOpen] = useState(open)
|
||||||
|
|
||||||
|
const [form, setForm] = useState<CreateCategoryForm>({
|
||||||
|
icon: '',
|
||||||
|
name: '',
|
||||||
|
})
|
||||||
|
const [confirmDisabled, setConfirmDisabled] = useState(true)
|
||||||
|
const [confirmLoading, setConfirmLoading] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsOpen(open)
|
setIsOpen(open)
|
||||||
}, [open])
|
}, [open])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (form.name && form.name.length < 6) {
|
||||||
|
setConfirmDisabled(false)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setConfirmDisabled(true)
|
||||||
|
}
|
||||||
|
}, [form.name])
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
onClose && onClose()
|
onClose && onClose()
|
||||||
|
|
||||||
|
setForm({
|
||||||
|
icon: '',
|
||||||
|
name: '',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -45,60 +75,65 @@ export default function CreateCategory({
|
|||||||
>
|
>
|
||||||
<DrawerHeader className="px-4 flex flex-col gap-4">
|
<DrawerHeader className="px-4 flex flex-col gap-4">
|
||||||
<View className="flex flex-row items-center justify-between w-full">
|
<View className="flex flex-row items-center justify-between w-full">
|
||||||
<Pressable>
|
<AButton size="xs" variant="outline" onPress={handleClose}>取消</AButton>
|
||||||
<Text className="text-gray-600">取消</Text>
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
<Text className="text-xl font-medium">类别</Text>
|
<Text className="text-lg font-medium">{type === MoneyCategoryEnum.Expense ? '添加支出分类' : '添加收入分类'}</Text>
|
||||||
|
|
||||||
<Pressable>
|
<AButton size="xs" disabled={confirmDisabled} loading={confirmLoading}>确认</AButton>
|
||||||
<Text className="text-gray-600">确认</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
variant="outline"
|
variant="outline"
|
||||||
>
|
>
|
||||||
<InputField placeholder="请输入名称" />
|
<InputField placeholder="请输入名称(不超过5个字符)" />
|
||||||
</Input>
|
</Input>
|
||||||
|
|
||||||
</DrawerHeader>
|
</DrawerHeader>
|
||||||
<DrawerBody>
|
<DrawerBody className="mb-16">
|
||||||
<ScrollView className="flex-1">
|
{Object.entries(moneyCategoryStore.ICON_GROUPS).map(([groupName, icons]) => (
|
||||||
{Object.entries(moneyCategoryStore.ICON_GROUPS).map(([groupName, icons]) => (
|
<View key={groupName} className="mb-2">
|
||||||
<View key={groupName} className="mb-4">
|
<Text className="text-center text-sm mb-4">
|
||||||
<Text className="text-center mb-4">
|
{groupName}
|
||||||
{groupName}
|
</Text>
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View className="flex flex-row flex-wrap">
|
<View className="flex flex-row flex-wrap">
|
||||||
{icons.map(icon => (
|
{icons.map(icon => (
|
||||||
<Pressable
|
<Pressable
|
||||||
key={icon}
|
key={icon}
|
||||||
className="w-1/5 mb-3 flex items-center"
|
className="w-1/5 mb-3 flex items-center"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
console.log('select icon:', icon)
|
setForm(val => ({
|
||||||
|
...val,
|
||||||
|
icon,
|
||||||
|
}))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
width: 46,
|
||||||
|
height: 46,
|
||||||
|
borderRadius: 28,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: icon === form.icon ? '#333' : '#F3F4F6',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View
|
<MoneyCategoryIcon
|
||||||
style={{
|
name={icon}
|
||||||
width: 46,
|
size={32}
|
||||||
height: 46,
|
color={
|
||||||
borderRadius: 28,
|
icon === form.icon ? '#fff' : '#000'
|
||||||
justifyContent: 'center',
|
}
|
||||||
alignItems: 'center',
|
/>
|
||||||
backgroundColor: '#F3F4F6',
|
</View>
|
||||||
}}
|
</Pressable>
|
||||||
>
|
))}
|
||||||
<MoneyCategoryIcon name={icon} size={28} />
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
))}
|
</View>
|
||||||
</ScrollView>
|
))}
|
||||||
</DrawerBody>
|
</DrawerBody>
|
||||||
|
|
||||||
|
<DrawerFooter />
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import { AButton, ATab, LucideIcon } from '@/components/common/ao'
|
|||||||
import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon'
|
import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon'
|
||||||
import CustomHeader from '@/components/custom/Header'
|
import CustomHeader from '@/components/custom/Header'
|
||||||
import { useMoneyCategoryStore } from '@/store/moneyCategory'
|
import { useMoneyCategoryStore } from '@/store/moneyCategory'
|
||||||
|
import { MoneyCategoryEnum } from '@/types/money/category'
|
||||||
import CreateCategory from './components/CreateCategory'
|
import CreateCategory from './components/CreateCategory'
|
||||||
|
|
||||||
export default function MoneyCategorySetting() {
|
export default function MoneyCategorySetting() {
|
||||||
const [selectedTab, setSelectedTab] = useState(0)
|
const [selectedTab, setSelectedTab] = useState(MoneyCategoryEnum.Expense)
|
||||||
const moneyCategoryStore = useMoneyCategoryStore()
|
const moneyCategoryStore = useMoneyCategoryStore()
|
||||||
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
|
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ export default function MoneyCategorySetting() {
|
|||||||
const [openCreateCategory, setOpenCreateCategory] = useState<boolean>(false)
|
const [openCreateCategory, setOpenCreateCategory] = useState<boolean>(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCategories(selectedTab === 0 ? moneyCategoryStore.getExpenseCategories() : moneyCategoryStore.getIncomeCategories())
|
setCategories(selectedTab === MoneyCategoryEnum.Expense ? moneyCategoryStore.getExpenseCategories() : moneyCategoryStore.getIncomeCategories())
|
||||||
}, [selectedTab])
|
}, [selectedTab])
|
||||||
|
|
||||||
const renderItem = useCallback<SortableGridRenderItem<MoneyCategoryItem>>(
|
const renderItem = useCallback<SortableGridRenderItem<MoneyCategoryItem>>(
|
||||||
@@ -69,18 +70,18 @@ export default function MoneyCategorySetting() {
|
|||||||
<View className="flex-1">
|
<View className="flex-1">
|
||||||
<View className="pt-2 mb-4 px-3 flex flex-row items-center justify-between">
|
<View className="pt-2 mb-4 px-3 flex flex-row items-center justify-between">
|
||||||
<ATab
|
<ATab
|
||||||
defaultIndex={selectedTab}
|
defaultKey={selectedTab}
|
||||||
onChange={(index) => {
|
onChange={(key) => {
|
||||||
setSelectedTab(index)
|
setSelectedTab(key as MoneyCategoryEnum)
|
||||||
}}
|
}}
|
||||||
data={[
|
data={[
|
||||||
{
|
{
|
||||||
key: 'income',
|
key: MoneyCategoryEnum.Expense,
|
||||||
label: '收入',
|
label: '支出',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'expense',
|
key: MoneyCategoryEnum.Income,
|
||||||
label: '支出',
|
label: '收入',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
@@ -189,6 +190,7 @@ export default function MoneyCategorySetting() {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<CreateCategory
|
<CreateCategory
|
||||||
|
type={selectedTab}
|
||||||
open={openCreateCategory}
|
open={openCreateCategory}
|
||||||
onClose={() => setOpenCreateCategory(false)}
|
onClose={() => setOpenCreateCategory(false)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import PagerView from 'react-native-pager-view'
|
|||||||
|
|
||||||
interface TabItem {
|
interface TabItem {
|
||||||
label: string
|
label: string
|
||||||
key: string
|
key: string | number
|
||||||
content?: React.ReactNode
|
content?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TabProps {
|
interface TabProps {
|
||||||
data?: TabItem[]
|
data?: TabItem[]
|
||||||
defaultIndex?: number
|
defaultKey?: TabItem['key']
|
||||||
onChange?: (index: number) => void
|
onChange?: (key: TabItem['key']) => void
|
||||||
tabBarClass?: string
|
tabBarClass?: string
|
||||||
tabItemClass?: string
|
tabItemClass?: string
|
||||||
activeTabItemClass?: string
|
activeTabItemClass?: string
|
||||||
@@ -19,47 +19,66 @@ interface TabProps {
|
|||||||
|
|
||||||
export default function Tab({
|
export default function Tab({
|
||||||
data,
|
data,
|
||||||
defaultIndex = 0,
|
defaultKey,
|
||||||
onChange,
|
onChange,
|
||||||
tabBarClass = 'flex flex-row gap-2 overflow-hidden',
|
tabBarClass = 'flex flex-row gap-2 overflow-hidden',
|
||||||
tabItemClass = 'items-center justify-center rounded-md px-4 py-2 bg-gray-200',
|
tabItemClass = 'items-center justify-center rounded-md px-4 py-2 bg-gray-200',
|
||||||
activeTabItemClass = 'items-center justify-center rounded-md px-4 py-2 bg-gray-800',
|
activeTabItemClass = 'items-center justify-center rounded-md px-4 py-2 bg-gray-800',
|
||||||
}: TabProps) {
|
}: TabProps) {
|
||||||
const [selectedIndex, setSelectedIndex] = useState(defaultIndex)
|
|
||||||
const pagerRef = useRef<PagerView>(null)
|
|
||||||
|
|
||||||
if (!data || data.length === 0)
|
if (!data || data.length === 0)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
// 判断是否至少有一个 tab 含 content
|
// 默认选中 key(没传就用第一个)
|
||||||
|
const initialKey = defaultKey ?? data[0].key
|
||||||
|
const [selectedKey, setSelectedKey] = useState(initialKey)
|
||||||
|
|
||||||
|
const pagerRef = useRef<PagerView>(null)
|
||||||
|
|
||||||
|
// 是否有 content
|
||||||
const hasContent = useMemo(
|
const hasContent = useMemo(
|
||||||
() => data.some(item => item.content),
|
() => data.some(item => item.content),
|
||||||
[data],
|
[data],
|
||||||
)
|
)
|
||||||
|
|
||||||
const handlePress = (index: number) => {
|
// key -> index
|
||||||
setSelectedIndex(index)
|
const getIndexByKey = (key: TabItem['key']) =>
|
||||||
onChange?.(index)
|
data.findIndex(item => item.key === key)
|
||||||
if (hasContent)
|
|
||||||
pagerRef.current?.setPage(index)
|
// index -> key
|
||||||
|
const getKeyByIndex = (index: number) =>
|
||||||
|
data[index]?.key
|
||||||
|
|
||||||
|
const handlePress = (key: TabItem['key']) => {
|
||||||
|
setSelectedKey(key)
|
||||||
|
onChange?.(key)
|
||||||
|
|
||||||
|
if (hasContent) {
|
||||||
|
const index = getIndexByKey(key)
|
||||||
|
if (index !== -1)
|
||||||
|
pagerRef.current?.setPage(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPageSelected = (e: any) => {
|
const onPageSelected = (e: any) => {
|
||||||
const index = e.nativeEvent.position
|
const index = e.nativeEvent.position
|
||||||
setSelectedIndex(index)
|
const key = getKeyByIndex(index)
|
||||||
onChange?.(index)
|
|
||||||
|
if (key !== undefined) {
|
||||||
|
setSelectedKey(key)
|
||||||
|
onChange?.(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className="flex-1">
|
<View className="flex-1">
|
||||||
{/* tab bar */}
|
{/* tab bar */}
|
||||||
<View className={tabBarClass}>
|
<View className={tabBarClass}>
|
||||||
{data.map((item, index) => {
|
{data.map((item) => {
|
||||||
const isActive = index === selectedIndex
|
const isActive = item.key === selectedKey
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onPress={() => handlePress(index)}
|
onPress={() => handlePress(item.key)}
|
||||||
className={isActive ? activeTabItemClass : tabItemClass}
|
className={isActive ? activeTabItemClass : tabItemClass}
|
||||||
>
|
>
|
||||||
<Text className={isActive ? 'text-white' : 'text-gray-700'}>
|
<Text className={isActive ? 'text-white' : 'text-gray-700'}>
|
||||||
@@ -74,7 +93,7 @@ export default function Tab({
|
|||||||
<PagerView
|
<PagerView
|
||||||
ref={pagerRef}
|
ref={pagerRef}
|
||||||
style={{ flex: 1, marginTop: 16 }}
|
style={{ flex: 1, marginTop: 16 }}
|
||||||
initialPage={defaultIndex}
|
initialPage={getIndexByKey(initialKey)}
|
||||||
onPageSelected={onPageSelected}
|
onPageSelected={onPageSelected}
|
||||||
>
|
>
|
||||||
{data.map(item => (
|
{data.map(item => (
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ function isWhiteListed(url: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const alovaInstance = createAlova({
|
const alovaInstance = createAlova({
|
||||||
// baseURL: 'http://192.168.5.6:8086/app',
|
baseURL: 'http://192.168.5.6:8086/app',
|
||||||
baseURL: 'http://192.168.1.137:8086/app',
|
// baseURL: 'http://192.168.1.137:8086/app',
|
||||||
requestAdapter: axiosRequestAdapter(),
|
requestAdapter: axiosRequestAdapter(),
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
cacheFor: null,
|
cacheFor: null,
|
||||||
|
|||||||
@@ -28,3 +28,8 @@ export interface UpdateMoneyCategorySortItem {
|
|||||||
export interface UpdateMoneyCategorySortParams {
|
export interface UpdateMoneyCategorySortParams {
|
||||||
data: UpdateMoneyCategorySortItem[]
|
data: UpdateMoneyCategorySortItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum MoneyCategoryEnum {
|
||||||
|
Expense = 0, // 支出
|
||||||
|
Income = 1, // 收入
|
||||||
|
}
|
||||||
Reference in new issue
Block a user