From 3af982d669d6574c7091e2d1bad9cb009334f582 Mon Sep 17 00:00:00 2001 From: ZhangAo Date: Fri, 5 Dec 2025 17:28:46 +0800 Subject: [PATCH] u --- .../money/components/TransactionsList.tsx | 15 +- .../base-app/src/app/(tabs)/money/index.tsx | 2 + .../base-app/src/app/(tabs)/user/index.tsx | 7 +- .../base-project/base-app/src/app/_layout.tsx | 8 +- .../src/app/money/record/detail/index.tsx | 9 +- .../src/app/money/record/editor/index.tsx | 4 + .../src/app/system/settings/index.tsx | 2 +- .../app/system/share/components/SpaceHome.tsx | 1 - .../system/share/components/SpaceInvite.tsx | 158 ++++++++--- .../base-app/src/app/system/share/index.tsx | 42 ++- .../src/request/api/space/spaceUser.ts | 6 - .../base-app/src/request/index.ts | 11 +- .../base-app/src/store/moneyCategory.ts | 13 +- code/base-project/base-app/src/store/space.ts | 12 - .../base-app/src/types/money/record.ts | 12 +- .../base-app/src/types/space/spaceUser.ts | 8 - .../biz/handler/money/money_record_service.go | 102 +++++-- .../biz/handler/space/space_user_service.go | 37 ++- .../base-go-v3/biz/model/api/api.pb.go | 2 +- .../base-go-v3/biz/model/money/money.pb.go | 2 +- .../model/money/money_category_types.pb.go | 2 +- .../biz/model/money/money_record_types.pb.go | 256 ++++++++++-------- .../base-go-v3/biz/model/space/space.pb.go | 2 +- .../biz/model/space/space_types.pb.go | 2 +- .../biz/model/space/space_user_types.pb.go | 59 ++-- .../base-go-v3/biz/router/middleware/auth.go | 61 +++-- .../base-go-v3/db/queries/money_record.sql | 14 + .../base-go-v3/db/repo/money_record.sql.go | 69 +++++ .../idl/money/money_record_types.proto | 4 + .../idl/space/space_user_types.proto | 3 +- .../base-go-v3/utils/pgtypex/pgtypex.go | 23 +- 31 files changed, 632 insertions(+), 316 deletions(-) diff --git a/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx b/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx index 0c02eea5..3a0eae9b 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx @@ -12,6 +12,7 @@ import { LucideIcon } from '@/components/common/ao' import EmptyState from '@/components/common/EmptyStatus' import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' import { useMoneyCategoryStore } from '@/store/moneyCategory' +import { useUserStore } from '@/store/user' interface StaticTransactionsProps { records: MoneyRecordGroup[] @@ -30,7 +31,7 @@ export default function StaticTransactions({ onLoadMore, onRefreshData, }: StaticTransactionsProps) { - const moneyCategoryStore = useMoneyCategoryStore() + const userID = useUserStore().userInfo?.id const [refreshing, setRefreshing] = useState(false) const [loadingMore, setLoadingMore] = useState(false) const [selectedId, setSelectedId] = useState(null) @@ -119,7 +120,6 @@ export default function StaticTransactions({ )} renderItem={({ item, index }) => { - const category = moneyCategoryStore.getCategoryById(item.category_id) return ( - + - {item.remark ? item.remark : category?.name} + {item.remark ? item.remark : item.category_name} { - index === 1 && ( + item.user_id !== userID && ( - 张三 + {item.username} ) } - - {category?.type === 1 ? '+' : '-'} + {item.category_type === 1 ? '+' : '-'} {' '} {item.amount} 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 3ec6b8e8..21284fa4 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 @@ -30,6 +30,8 @@ export default function Money() { }).then((res) => { if (res.isSuccess) { moneyRecordStore.setRecords(res.data.records, res.data.total_expense, res.data.total_income, searchParams.record_time) + + console.log(res.data.records) } else { toast.show({ diff --git a/code/base-project/base-app/src/app/(tabs)/user/index.tsx b/code/base-project/base-app/src/app/(tabs)/user/index.tsx index a1397a49..c3707e9b 100644 --- a/code/base-project/base-app/src/app/(tabs)/user/index.tsx +++ b/code/base-project/base-app/src/app/(tabs)/user/index.tsx @@ -1,13 +1,16 @@ -import { Text, TouchableOpacity, View } from 'react-native' +import { Text, View } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import { LucideIcon } from '@/components/common/ao/index' import { Avatar, AvatarImage, } from '@/components/ui/avatar' +import { useUserStore } from '@/store/user' import ListItem from './components/ListItem' export default function User() { + const userStore = useUserStore() + return ( @@ -17,7 +20,7 @@ export default function User() { source={require('@/static/images/logo.png')} /> - 张三 + {userStore.userInfo?.username} diff --git a/code/base-project/base-app/src/app/_layout.tsx b/code/base-project/base-app/src/app/_layout.tsx index ad3c49ed..18a0440a 100644 --- a/code/base-project/base-app/src/app/_layout.tsx +++ b/code/base-project/base-app/src/app/_layout.tsx @@ -11,6 +11,7 @@ import { MenuProvider } from 'react-native-popup-menu' import { AButton } from '@/components/common/ao' import EmptyState from '@/components/common/EmptyStatus' import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider' +import { getUserSpaceApi } from '@/request/api/space/spaceUser' import { useMoneyCategoryStore } from '@/store/moneyCategory' import { useNavStore } from '@/store/navigation' import { useSpaceStore } from '@/store/space' @@ -70,7 +71,12 @@ export default function RootLayout() { // 如果登录的话,就初始化下 moneyCategoryStore.init() - spaceStore.init() + + getUserSpaceApi({}).then((res) => { + spaceStore.setUserSpace(res.data) + }).catch((err) => { + console.log(err) + }) // 隐藏 splash SplashScreen.hideAsync() diff --git a/code/base-project/base-app/src/app/money/record/detail/index.tsx b/code/base-project/base-app/src/app/money/record/detail/index.tsx index 6c39c9fd..53db9cd4 100644 --- a/code/base-project/base-app/src/app/money/record/detail/index.tsx +++ b/code/base-project/base-app/src/app/money/record/detail/index.tsx @@ -4,18 +4,15 @@ import { Text, View } from 'react-native' import { AButton, ACell, ACellGroup, AModal } from '@/components/common/ao' import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' import CustomHeader from '@/components/custom/Header' -import { useMoneyCategoryStore } from '@/store/moneyCategory' import { useMoneyRecordStore } from '@/store/moneyRecord' import { toDateString, toDateTimeString } from '@/utils/time' export default function MoneyRecordDetail() { const router = useRouter() const moneyRecordStore = useMoneyRecordStore() - const moneyCategoryStore = useMoneyCategoryStore() const { id: detailId } = useLocalSearchParams<{ id: string }>() const moneryRecord = moneyRecordStore.getMoneyRecordById(Number(detailId)) - const moneyCategory = moneyCategoryStore.getCategoryById(moneryRecord?.category_id || 0) const [showDeleteModal, setShowDeleteModal] = useState(false) @@ -29,12 +26,12 @@ export default function MoneyRecordDetail() { - - {moneyCategory?.name} + + {moneryRecord.category_name} - + 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 924e1131..fc06b41a 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 @@ -31,6 +31,10 @@ export default function MoenyRecordEditor() { const defaultMoneyRecord: MoneyRecordBase = { id: -1, category_id: -1, + username: '', + category_icon: '', + category_name: '', + category_type: 0, user_id: -1, amount: '0.00', remark: '', diff --git a/code/base-project/base-app/src/app/system/settings/index.tsx b/code/base-project/base-app/src/app/system/settings/index.tsx index a96af01a..34187666 100644 --- a/code/base-project/base-app/src/app/system/settings/index.tsx +++ b/code/base-project/base-app/src/app/system/settings/index.tsx @@ -33,7 +33,7 @@ export default function Share() { style={{ backgroundColor: '#d9d9db', }} - onPress={() => setShowExitModal(true)} + onPress={() => exitLogin()} > 退出登录 diff --git a/code/base-project/base-app/src/app/system/share/components/SpaceHome.tsx b/code/base-project/base-app/src/app/system/share/components/SpaceHome.tsx index 121e57a4..18a1d7e7 100644 --- a/code/base-project/base-app/src/app/system/share/components/SpaceHome.tsx +++ b/code/base-project/base-app/src/app/system/share/components/SpaceHome.tsx @@ -1,4 +1,3 @@ -import type { UserSpace } from '@/types/space/spaceUser' import { Text, View } from 'react-native' import { AButton, ADivider, LucideIcon } from '@/components/common/ao' diff --git a/code/base-project/base-app/src/app/system/share/components/SpaceInvite.tsx b/code/base-project/base-app/src/app/system/share/components/SpaceInvite.tsx index 8d586a1e..1eb226ca 100644 --- a/code/base-project/base-app/src/app/system/share/components/SpaceInvite.tsx +++ b/code/base-project/base-app/src/app/system/share/components/SpaceInvite.tsx @@ -1,4 +1,4 @@ -import type { SpaceUser, UserSpace } from '@/types/space/spaceUser' +import type { SpaceUser } from '@/types/space/spaceUser' import * as Clipboard from 'expo-clipboard' import { useState } from 'react' import { FlatList, TouchableHighlight, TouchableOpacity, View } from 'react-native' @@ -32,19 +32,29 @@ import { HStack } from '@/components/ui/hstack' import { ChevronDownIcon, ChevronUpIcon } from '@/components/ui/icon' import { Text } from '@/components/ui/text' import { VStack } from '@/components/ui/vstack' -import { exitSpaceApi } from '@/request/api/space/spaceUser' +import { dissolveSpaceApi } from '@/request/api/space/space' +import { exitSpaceApi, removeSpaceUserApi } from '@/request/api/space/spaceUser' import { useUserStore } from '@/store/user' import { formatRelativeTime } from '@/utils/time' import { toast } from '@/utils/toast' +type ExitAction = 'exit' | 'remove' | 'dissolve' + +interface ExitParams { + type: ExitAction + userId?: number +} + interface SpaceInviteProps { userSpace: UserSpace | null spaceUsers: SpaceUser[] + onExit?: (params: ExitParams) => void } export default function SpaceInvite({ userSpace, spaceUsers, + onExit, }: SpaceInviteProps) { const userStore = useUserStore() @@ -52,13 +62,14 @@ export default function SpaceInvite({ const [modal, setModal] = useState<{ open: boolean title: string - type: 'exit' | 'remove' | 'dissolve' + type: ExitAction + userId?: number }>({ open: false, title: '', type: 'dissolve', }) - , + const [accordion, setAccordion] = useState(['a']) async function copyInviteCode() { @@ -69,8 +80,43 @@ export default function SpaceInvite({ }) } - function exitSpace() { + function handleModalConfirm() { + if (userSpace === null) { + return + } + if (modal.type === 'exit') { + // 退出 + exitSpaceApi({}).catch((err) => { + console.log(err) + }) + } + else if (modal.type === 'remove') { + if (!modal.userId) { + return + } + // 移除 + removeSpaceUserApi({ + user_id: modal.userId, + }).catch((err) => { + console.log(err) + }) + } + else { + // 解散 + dissolveSpaceApi({}).catch((err) => { + console.log(err) + }) + } + setModal({ + ...modal, + open: false, + }) + + onExit?.({ + type: modal.type, + userId: modal.userId, + }) } return ( @@ -207,36 +253,31 @@ export default function SpaceInvite({ }, }} > - { - }} - > - - 授予管理员 - - - { - }} - > - - 踢出空间 - - + {userSpace.role === 0 && userStore.userInfo?.id !== item.user_id && ( + { + setModal({ + ...modal, + open: true, + title: `确定将 ${item.username} 提出空间?`, + type: 'remove', + userId: item.user_id, + }) + }} + > + + 踢出空间 + + + )} + @@ -247,15 +288,50 @@ export default function SpaceInvite({ )} /> - 退出该空间 + { + if (userSpace?.role === 0) { + setModal({ + ...modal, + open: true, + title: `确定解散该空间么?不可恢复!`, + type: 'dissolve', + }) + } + else { + setModal({ + ...modal, + open: true, + title: `确定退出该空间么?`, + type: 'exit', + }) + } + }} + > + {userSpace?.role === 0 ? '解散空间' : '退出空间'} + setShowExitModal(false)} - onClose={() => setShowExitModal(false)} - onConfirm={exitLogin} + title={modal.title} + isOpen={modal.open} + onCancel={() => { + setModal({ + ...modal, + open: false, + }) + }} + onClose={() => { + setModal({ + ...modal, + open: false, + }) + }} + onConfirm={() => { + handleModalConfirm() + }} /> ) diff --git a/code/base-project/base-app/src/app/system/share/index.tsx b/code/base-project/base-app/src/app/system/share/index.tsx index a044366d..7dcd0e37 100644 --- a/code/base-project/base-app/src/app/system/share/index.tsx +++ b/code/base-project/base-app/src/app/system/share/index.tsx @@ -1,17 +1,19 @@ -import type { SpaceUser, UserSpace } from '@/types/space/spaceUser' +import type { SpaceUser } from '@/types/space/spaceUser' import { useEffect, useState } from 'react' import { View } from 'react-native' import CustomHeader from '@/components/custom/Header' import { createSpaceApi } from '@/request/api/space/space' import { getUserSpaceApi, joinSpaceApi, listSpaceUsersApi } from '@/request/api/space/spaceUser' +import { useSpaceStore } from '@/store/space' import JoinSpace from './components/JoinSpace' import SpaceHome from './components/SpaceHome' -import SpaceInviteAndMembers from './components/SpaceInvite' +import SpaceInvite from './components/SpaceInvite' import StepFade from './components/StepFade' export default function PagerWithTab() { + const spaceStore = useSpaceStore() + const [step, setStep] = useState<'join' | 'invite' | 'home'>('home') - const [userSpace, setUserSpace] = useState(null) const [spaceUsers, setSpaceUsers] = useState([]) const fetchData = async () => { @@ -20,11 +22,11 @@ export default function PagerWithTab() { .then((res) => { if (res.isSuccess) { if (res.data === null) { - setUserSpace(null) + spaceStore.setUserSpace(null) setStep('home') } else { - setUserSpace({ + spaceStore.setUserSpace({ space_id: res.data.space_id, space_name: res.data.space_name, role: res.data.role, @@ -51,6 +53,7 @@ export default function PagerWithTab() { .catch(err => console.error('listSpaceUsersApi error:', err)), ]) } + useEffect(() => { fetchData() }, []) @@ -58,13 +61,22 @@ export default function PagerWithTab() { function createSpace() { createSpaceApi({}).then((res) => { if (res.isSuccess) { - setUserSpace({ + spaceStore.setUserSpace({ space_id: res.data.id, space_name: '', role: 0, invite_code: res.data.invite_code, }) - + listSpaceUsersApi({}) + .then((res) => { + if (res.isSuccess) { + setSpaceUsers(res.data.users) + } + else { + // 提示 + } + }) + .catch(err => console.error('listSpaceUsersApi error:', err)) setStep('invite') } }).catch((err) => { @@ -111,7 +123,21 @@ export default function PagerWithTab() { - + { + if (data.type === 'remove' && data.userId !== undefined) { + setSpaceUsers(prevUsers => + prevUsers.filter(user => user.user_id !== data.userId), + ) + return + } + setStep('home') + spaceStore.setUserSpace(null) + setSpaceUsers([]) + }} + /> diff --git a/code/base-project/base-app/src/request/api/space/spaceUser.ts b/code/base-project/base-app/src/request/api/space/spaceUser.ts index 254d4eef..f1b8cc3f 100644 --- a/code/base-project/base-app/src/request/api/space/spaceUser.ts +++ b/code/base-project/base-app/src/request/api/space/spaceUser.ts @@ -9,8 +9,6 @@ import type { ListSpaceUsersResult, RemoveSpaceUserParams, RemoveSpaceUserResult, - UpdateSpaceUserRoleParams, - UpdateSpaceUserRoleResult, } from '@/types/space/spaceUser' import alovaInstance from '../../index' @@ -35,7 +33,3 @@ export function listSpaceUsersApi(params: ListSpaceUsersParams) { export function removeSpaceUserApi(params: RemoveSpaceUserParams) { return alovaInstance.Post>(`${API_PREFIX}/remove`, params) } - -export function updateSpaceUserRoleApi(params: UpdateSpaceUserRoleParams) { - return alovaInstance.Post>(`${API_PREFIX}/updateRole`, params) -} diff --git a/code/base-project/base-app/src/request/index.ts b/code/base-project/base-app/src/request/index.ts index 6c363d85..70db1f04 100644 --- a/code/base-project/base-app/src/request/index.ts +++ b/code/base-project/base-app/src/request/index.ts @@ -4,6 +4,7 @@ import type { RefreshTokenResult } from '@/types/auth' import { axiosRequestAdapter } from '@alova/adapter-axios' import { createAlova } from 'alova' import { useNavStore } from '@/store/navigation' +import { useSpaceStore } from '@/store/space' import { useUserStore } from '@/store/user' import { toast } from '@/utils/toast' @@ -31,8 +32,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - baseURL: 'http://192.168.5.6:8086/app', - // baseURL: 'http://192.168.1.136:8086/app', + // baseURL: 'http://192.168.5.6:8086/app', + baseURL: 'http://192.168.1.136:8086/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null, @@ -149,6 +150,12 @@ const alovaInstance = createAlova({ } method.config.headers.token = useUserStore.getState().userInfo?.token ?? '' + + const userSpace = useSpaceStore.getState().userSpace + if (userSpace !== null) { + const spaceID = userSpace.space_id + method.config.headers['x-space-id'] = spaceID + } }, }) diff --git a/code/base-project/base-app/src/store/moneyCategory.ts b/code/base-project/base-app/src/store/moneyCategory.ts index 407e09df..c61ce810 100644 --- a/code/base-project/base-app/src/store/moneyCategory.ts +++ b/code/base-project/base-app/src/store/moneyCategory.ts @@ -19,15 +19,20 @@ interface MoneyCategoryStore { updateCategories: (data: MoneyCategoryItem[], type: number) => void deleteCategoryById: (id: number, type: number) => void + + sysCategories: MoneyCategoryItem[] + setSysCategories: (categories: MoneyCategoryItem[]) => void } export const useMoneyCategoryStore = create()( persist( (set, get) => ({ categories: [], + sysCategories:[], setCategories: categories => set({ categories }), - + setSysCategories: categories => set({ categories }), + addCategory: category => set({ categories: [...get().categories, category] }), @@ -35,7 +40,6 @@ export const useMoneyCategoryStore = create()( set({ categories: get().categories.filter(c => c.id !== id) }), init: async () => { - try { await queryMoneyCategoryApi().then((res) => { if (res.isSuccess) { @@ -58,6 +62,11 @@ export const useMoneyCategoryStore = create()( 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 diff --git a/code/base-project/base-app/src/store/space.ts b/code/base-project/base-app/src/store/space.ts index e35a4d2d..9350a4d4 100644 --- a/code/base-project/base-app/src/store/space.ts +++ b/code/base-project/base-app/src/store/space.ts @@ -1,23 +1,11 @@ import { create } from 'zustand' -import { getUserSpaceApi } from '@/request/api/space/spaceUser' interface SpaceState { userSpace: UserSpace | null setUserSpace: (space: UserSpace | null) => void - init: () => Promise } export const useSpaceStore = create(set => ({ userSpace: null, setUserSpace: space => set({ userSpace: space }), - init: async () => { - try { - const res = await getUserSpaceApi({}) - set({ userSpace: res.isSuccess ? res.data : null }) - } - catch (err) { - set({ userSpace: null }) - console.error(err) - } - }, })) diff --git a/code/base-project/base-app/src/types/money/record.ts b/code/base-project/base-app/src/types/money/record.ts index e2750bb7..b01e13d4 100644 --- a/code/base-project/base-app/src/types/money/record.ts +++ b/code/base-project/base-app/src/types/money/record.ts @@ -4,7 +4,11 @@ export interface MoneyRecordBase { id: number category_id: number + category_type: number + category_name: string + category_icon: string user_id: number + username: string amount: string remark: string record_time: string @@ -47,7 +51,13 @@ export interface InsertMoneyRecordParams { export interface InsertMoneyRecordResult extends MoneyRecordBase {} // 更新 -export interface UpdateMoneyRecordParams extends Omit {} +export interface UpdateMoneyRecordParams { + id: number + category_id: number + amount: string + remark: string + record_time: string +} // 删除 export interface DeleteMoneyRecordParams { diff --git a/code/base-project/base-app/src/types/space/spaceUser.ts b/code/base-project/base-app/src/types/space/spaceUser.ts index 138b943e..c1bab83a 100644 --- a/code/base-project/base-app/src/types/space/spaceUser.ts +++ b/code/base-project/base-app/src/types/space/spaceUser.ts @@ -1,10 +1,3 @@ -export interface UserSpace { - space_id: number - space_name: string - role: number - invite_code: string -} - // 获取用户的空间 export interface GetUserSpaceParams { @@ -41,7 +34,6 @@ export interface ListSpaceUsersResult { // 踢出空间 export interface RemoveSpaceUserParams { - space_id: number user_id: number } diff --git a/code/base-project/base-go-v3/biz/handler/money/money_record_service.go b/code/base-project/base-go-v3/biz/handler/money/money_record_service.go index 1410bf1a..f4cbd407 100644 --- a/code/base-project/base-go-v3/biz/handler/money/money_record_service.go +++ b/code/base-project/base-go-v3/biz/handler/money/money_record_service.go @@ -39,20 +39,75 @@ func QueryMoneyRecord(ctx context.Context, c *app.RequestContext) { } endTime := startTime.AddDate(0, 1, 0).Add(-time.Nanosecond) - // 获取 userID + // 获取 userID 和 spaceID userID := middleware.GetUserID(ctx) + spaceID, ok := middleware.GetSpaceID(ctx) - // 查询记录 - params := repo.FindUserMoneyRecordsParams{ - UserID: userID, - RecordTime: pgtype.Timestamp{Time: startTime, Valid: true}, - RecordTime_2: pgtype.Timestamp{Time: endTime, Valid: true}, - } + // 定义统一的 records 切片 + var dbRecordsUser []repo.FindUserMoneyRecordsRow + var dbRecordsSpace []repo.FindMoneyRecordsBySpaceRow + var errQuery error - records, err := db.Queries.FindUserMoneyRecords(ctx, params) - if err != nil { - errorx.AddError(c, err) - return + // 最终返回统一类型 + var records []*money.MoneyRecordItem + + if ok { // 有空间ID,查询空间内所有用户 + params := repo.FindMoneyRecordsBySpaceParams{ + SpaceID: spaceID, + RecordTime: pgtype.Timestamp{Time: startTime, Valid: true}, + RecordTime_2: pgtype.Timestamp{Time: endTime, Valid: true}, + } + dbRecordsSpace, errQuery = db.Queries.FindMoneyRecordsBySpace(ctx, params) + if errQuery != nil { + errorx.AddError(c, errQuery) + return + } + + for _, r := range dbRecordsSpace { + records = append(records, &money.MoneyRecordItem{ + Id: r.ID, + CategoryId: r.CategoryID, + CategoryType: r.CategoryType.Int32, + CategoryIcon: r.CategoryIcon.String, + CategoryName: r.CategoryName.String, + UserId: r.UserID, + Username: r.Username.String, + Amount: pgtypex.NumericToString(r.Amount), + Remark: r.Remark.String, + RecordTime: pgtypex.TimestampToDateString(r.RecordTime), + CreateTime: pgtypex.TimestampToDateTimeString(r.CreateTime), + UpdateTime: pgtypex.TimestampToDateTimeString(r.UpdateTime), + }) + } + + } else { // 没有空间ID,只查询单用户 + params := repo.FindUserMoneyRecordsParams{ + UserID: userID, + RecordTime: pgtype.Timestamp{Time: startTime, Valid: true}, + RecordTime_2: pgtype.Timestamp{Time: endTime, Valid: true}, + } + dbRecordsUser, errQuery = db.Queries.FindUserMoneyRecords(ctx, params) + if errQuery != nil { + errorx.AddError(c, errQuery) + return + } + + for _, r := range dbRecordsUser { + records = append(records, &money.MoneyRecordItem{ + Id: r.ID, + CategoryId: r.CategoryID, + CategoryType: r.CategoryType.Int32, + CategoryIcon: r.CategoryIcon.String, + CategoryName: r.CategoryName.String, + UserId: r.UserID, + Username: "", // 单用户查询没有 username + Amount: pgtypex.NumericToString(r.Amount), + Remark: r.Remark.String, + RecordTime: pgtypex.TimestampToDateString(r.RecordTime), + CreateTime: pgtypex.TimestampToDateTimeString(r.CreateTime), + UpdateTime: pgtypex.TimestampToDateTimeString(r.UpdateTime), + }) + } } // 分组统计 @@ -61,7 +116,7 @@ func QueryMoneyRecord(ctx context.Context, c *app.RequestContext) { totalExpense := decimal.NewFromInt(0) for _, r := range records { - day := r.RecordTime.Time.Format("2006-01-02") + day := r.RecordTime[:10] // "YYYY-MM-DD" group, ok := groupMap[day] if !ok { @@ -74,28 +129,16 @@ func QueryMoneyRecord(ctx context.Context, c *app.RequestContext) { groupMap[day] = group } - // 构造单条记录 - item := &money.MoneyRecordItem{ - Id: r.ID, - CategoryId: r.CategoryID, - UserId: r.UserID, - Amount: pgtypex.NumericToString(r.Amount), - Remark: r.Remark.String, - RecordTime: pgtypex.TimestampToDateString(r.RecordTime), - CreateTime: pgtypex.TimestampToDateTimeString(r.CreateTime), - UpdateTime: pgtypex.TimestampToDateTimeString(r.UpdateTime), - } - - group.Records = append(group.Records, item) + group.Records = append(group.Records, r) // 收支累加 - amount := pgtypex.NumericToDecimal(r.Amount) - if r.CategoryType.Int32 == 1 { + amount := decimal.RequireFromString(r.Amount) + if r.CategoryType == 1 { incomeDec, _ := decimal.NewFromString(group.Income) incomeDec = incomeDec.Add(amount) group.Income = incomeDec.Round(2).StringFixed(2) totalIncome = totalIncome.Add(amount) - } else if r.CategoryType.Int32 == 0 { + } else if r.CategoryType == 0 { expenseDec, _ := decimal.NewFromString(group.Expense) expenseDec = expenseDec.Add(amount) group.Expense = expenseDec.Round(2).StringFixed(2) @@ -103,14 +146,13 @@ func QueryMoneyRecord(ctx context.Context, c *app.RequestContext) { } } - // 对日期排序,最新在前 + // 对日期排序 dates := make([]string, 0, len(groupMap)) for k := range groupMap { dates = append(dates, k) } sort.Slice(dates, func(i, j int) bool { return dates[i] > dates[j] }) - // 构建最终返回数组 resultGroups := make([]*money.MoneyRecordGroup, 0, len(dates)) for _, day := range dates { resultGroups = append(resultGroups, groupMap[day]) diff --git a/code/base-project/base-go-v3/biz/handler/space/space_user_service.go b/code/base-project/base-go-v3/biz/handler/space/space_user_service.go index 8b096ee3..31a76f5b 100644 --- a/code/base-project/base-go-v3/biz/handler/space/space_user_service.go +++ b/code/base-project/base-go-v3/biz/handler/space/space_user_service.go @@ -89,7 +89,7 @@ func ListSpaceUsers(ctx context.Context, c *app.RequestContext) { response.Success(c).Data(resp).Send() } -// RemoveSpaceUser . +// RemoveSpaceUser 移除空间用户 // @router /space/user/remove [POST] func RemoveSpaceUser(ctx context.Context, c *app.RequestContext) { var req space.RemoveSpaceUserParams @@ -98,17 +98,17 @@ func RemoveSpaceUser(ctx context.Context, c *app.RequestContext) { return } - spaceId := req.SpaceId - delUserId := req.UserId - userID := middleware.GetUserID(ctx) + delUserID := req.UserId + currentUserID := middleware.GetUserID(ctx) - if userID == delUserId { + // 不能删除自己 + if currentUserID == delUserID { response.Fail(c).Message("请退出空间或解散空间").Send() return } - // 当前操作者信息 - spaceUser, err := db.Queries.GetSpaceUserByUserId(ctx, userID) + // 获取当前操作者所在空间及角色 + spaceUser, err := db.Queries.GetSpaceUserByUserId(ctx, currentUserID) if err != nil { if errorx.IsNotFound(err) { response.Fail(c).Message("权限不足").Send() @@ -118,36 +118,31 @@ func RemoveSpaceUser(ctx context.Context, c *app.RequestContext) { return } - if spaceUser.SpaceID != spaceId { - response.Fail(c).Message("权限不足").Send() - return - } - + // 检查权限 if spaceUser.Role != 0 && spaceUser.Role != 1 { response.Fail(c).Message("权限不足").Send() return } - // 被踢用户是否在该空间 - targetUser, err := db.Queries.GetSpaceUserByUserId(ctx, delUserId) + // 获取待删除用户的空间信息 + delUserSpace, err := db.Queries.GetSpaceByUserId(ctx, delUserID) if err != nil { if errorx.IsNotFound(err) { - response.Success(c).Message("用户不在空间").Send() + response.Fail(c).Message("待删除用户不存在或权限不足").Send() return } errorx.AddError(c, err) return } - if targetUser.SpaceID != spaceId { - response.Fail(c).Message("用户不在该空间").Send() + // 校验是否在同一个空间 + if spaceUser.SpaceID != delUserSpace.ID { + response.Fail(c).Message("权限不足").Send() return } - // 删除 - err = db.Queries.DeleteSpaceUser(ctx, delUserId) - - if err != nil { + // 删除用户 + if err := db.Queries.DeleteSpaceUser(ctx, delUserID); err != nil { errorx.AddError(c, err) return } diff --git a/code/base-project/base-go-v3/biz/model/api/api.pb.go b/code/base-project/base-go-v3/biz/model/api/api.pb.go index 37434df6..09470162 100644 --- a/code/base-project/base-go-v3/biz/model/api/api.pb.go +++ b/code/base-project/base-go-v3/biz/model/api/api.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: api.proto package api diff --git a/code/base-project/base-go-v3/biz/model/money/money.pb.go b/code/base-project/base-go-v3/biz/model/money/money.pb.go index 6beae543..f66054af 100644 --- a/code/base-project/base-go-v3/biz/model/money/money.pb.go +++ b/code/base-project/base-go-v3/biz/model/money/money.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: money.proto package money diff --git a/code/base-project/base-go-v3/biz/model/money/money_category_types.pb.go b/code/base-project/base-go-v3/biz/model/money/money_category_types.pb.go index 154eb7e1..8505dc57 100644 --- a/code/base-project/base-go-v3/biz/model/money/money_category_types.pb.go +++ b/code/base-project/base-go-v3/biz/model/money/money_category_types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: money/money_category_types.proto package money diff --git a/code/base-project/base-go-v3/biz/model/money/money_record_types.pb.go b/code/base-project/base-go-v3/biz/model/money/money_record_types.pb.go index 0d79e677..da5bf116 100644 --- a/code/base-project/base-go-v3/biz/model/money/money_record_types.pb.go +++ b/code/base-project/base-go-v3/biz/model/money/money_record_types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: money/money_record_types.proto package money @@ -27,14 +27,18 @@ type MoneyRecordItem struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id int64 `protobuf:"varint,1,opt,name=Id,proto3" form:"id" json:"id"` - CategoryId int64 `protobuf:"varint,2,opt,name=CategoryId,proto3" form:"category_id" json:"category_id"` - UserId int64 `protobuf:"varint,3,opt,name=UserId,proto3" form:"user_id" json:"user_id"` - Amount string `protobuf:"bytes,4,opt,name=Amount,proto3" form:"amount" json:"amount"` - Remark string `protobuf:"bytes,5,opt,name=Remark,proto3" form:"remark" json:"remark"` - RecordTime string `protobuf:"bytes,6,opt,name=RecordTime,proto3" form:"record_time" json:"record_time"` - CreateTime string `protobuf:"bytes,7,opt,name=CreateTime,proto3" form:"create_time" json:"create_time"` - UpdateTime string `protobuf:"bytes,8,opt,name=UpdateTime,proto3" form:"update_time" json:"update_time"` + Id int64 `protobuf:"varint,1,opt,name=Id,proto3" form:"id" json:"id"` + CategoryId int64 `protobuf:"varint,2,opt,name=CategoryId,proto3" form:"category_id" json:"category_id"` + UserId int64 `protobuf:"varint,3,opt,name=UserId,proto3" form:"user_id" json:"user_id"` + Amount string `protobuf:"bytes,4,opt,name=Amount,proto3" form:"amount" json:"amount"` + Remark string `protobuf:"bytes,5,opt,name=Remark,proto3" form:"remark" json:"remark"` + RecordTime string `protobuf:"bytes,6,opt,name=RecordTime,proto3" form:"record_time" json:"record_time"` + CreateTime string `protobuf:"bytes,7,opt,name=CreateTime,proto3" form:"create_time" json:"create_time"` + UpdateTime string `protobuf:"bytes,8,opt,name=UpdateTime,proto3" form:"update_time" json:"update_time"` + Username string `protobuf:"bytes,9,opt,name=Username,proto3" form:"username" json:"username"` + CategoryType int32 `protobuf:"varint,10,opt,name=CategoryType,proto3" form:"category_type" json:"category_type"` + CategoryIcon string `protobuf:"bytes,11,opt,name=CategoryIcon,proto3" form:"category_icon" json:"category_icon"` + CategoryName string `protobuf:"bytes,12,opt,name=CategoryName,proto3" form:"category_name" json:"category_name"` } func (x *MoneyRecordItem) Reset() { @@ -125,6 +129,34 @@ func (x *MoneyRecordItem) GetUpdateTime() string { return "" } +func (x *MoneyRecordItem) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *MoneyRecordItem) GetCategoryType() int32 { + if x != nil { + return x.CategoryType + } + return 0 +} + +func (x *MoneyRecordItem) GetCategoryIcon() string { + if x != nil { + return x.CategoryIcon + } + return "" +} + +func (x *MoneyRecordItem) GetCategoryName() string { + if x != nil { + return x.CategoryName + } + return "" +} + // 同一天的记账记录分组 type MoneyRecordGroup struct { state protoimpl.MessageState @@ -695,7 +727,7 @@ var file_money_money_record_types_proto_rawDesc = []byte{ 0x0a, 0x1e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x1a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xda, 0x02, 0x0a, 0x0f, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, + 0x74, 0x6f, 0x22, 0xa9, 0x04, 0x0a, 0x0f, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x06, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, @@ -716,103 +748,115 @@ var file_money_money_record_types_proto_rawDesc = []byte{ 0x6d, 0x65, 0x52, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, - 0xcd, 0x01, 0x0a, 0x10, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x65, 0x78, 0x70, 0x65, - 0x6e, 0x73, 0x65, 0x52, 0x07, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x06, - 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, - 0x18, 0x06, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x52, 0x06, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, - 0x12, 0x3d, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, - 0x4a, 0x0a, 0x17, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, - 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, - 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xc4, 0x01, 0x0a, 0x17, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, - 0x2e, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x07, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x54, 0x6f, 0x74, 0x61, 0x6c, - 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xca, 0xbb, - 0x18, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x52, 0x0b, - 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0c, 0x54, - 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x11, 0xca, 0xbb, 0x18, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x70, - 0x65, 0x6e, 0x73, 0x65, 0x52, 0x0c, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x65, 0x6e, - 0x73, 0x65, 0x22, 0xa4, 0x02, 0x0a, 0x17, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, - 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x38, - 0x0a, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x42, 0x18, 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x5f, 0x69, 0x64, 0xda, 0xbb, 0x18, 0x05, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x52, 0x0a, 0x43, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0xca, 0xbb, 0x18, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0xda, 0xbb, 0x18, 0x27, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, - 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x28, 0x27, 0x5e, 0x5c, 0x64, 0x2b, 0x28, 0x5c, 0x2e, - 0x5c, 0x64, 0x7b, 0x31, 0x2c, 0x32, 0x7d, 0x29, 0x3f, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, - 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, - 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, - 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x5c, 0x0a, 0x0a, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x3c, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0xda, 0xbb, 0x18, 0x29, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, 0x20, 0x72, 0x65, 0x67, - 0x65, 0x78, 0x70, 0x28, 0x27, 0x5e, 0x5c, 0x64, 0x7b, 0x34, 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, - 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, 0x7d, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x0a, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe2, 0x02, 0x0a, 0x17, 0x49, 0x6e, - 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x42, 0x06, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, - 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, - 0x69, 0x64, 0x52, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x23, - 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0b, - 0xca, 0xbb, 0x18, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x06, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, - 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, - 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x0a, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x0a, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x52, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, - 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x52, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe3, - 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, - 0x18, 0x04, 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x43, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0f, - 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x52, - 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x41, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, - 0x61, 0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, + 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x28, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x0c, 0xca, 0xbb, 0x18, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, + 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0c, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x42, + 0x11, 0xca, 0xbb, 0x18, 0x0d, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x52, 0x0c, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x35, 0x0a, 0x0c, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x63, 0x6f, 0x6e, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x11, 0xca, 0xbb, 0x18, 0x0d, 0x63, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x52, 0x0c, 0x43, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x49, 0x63, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x0c, 0x43, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x11, 0xca, + 0xbb, 0x18, 0x0d, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x52, 0x0c, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xcd, + 0x01, 0x0a, 0x10, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x54, 0x69, 0x6d, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, - 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x39, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, - 0x18, 0x04, 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x42, 0x22, 0x5a, 0x20, 0x63, 0x6e, 0x2f, 0x6f, 0x6e, 0x65, 0x61, - 0x6f, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, - 0x64, 0x65, 0x6c, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x65, 0x78, 0x70, 0x65, 0x6e, + 0x73, 0x65, 0x52, 0x07, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x06, 0x49, + 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, + 0x06, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x52, 0x06, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x12, + 0x3d, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x4a, + 0x0a, 0x17, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, + 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x0a, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xc4, 0x01, 0x0a, 0x17, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, + 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x07, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x49, + 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xca, 0xbb, 0x18, + 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x52, 0x0b, 0x54, + 0x6f, 0x74, 0x61, 0x6c, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0c, 0x54, 0x6f, + 0x74, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x11, 0xca, 0xbb, 0x18, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x70, 0x65, + 0x6e, 0x73, 0x65, 0x52, 0x0c, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x65, 0x6e, 0x73, + 0x65, 0x22, 0xa4, 0x02, 0x0a, 0x17, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, + 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x38, 0x0a, + 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x18, 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, + 0x69, 0x64, 0xda, 0xbb, 0x18, 0x05, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x52, 0x0a, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0xca, 0xbb, 0x18, 0x06, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0xda, 0xbb, 0x18, 0x27, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, 0x20, + 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x28, 0x27, 0x5e, 0x5c, 0x64, 0x2b, 0x28, 0x5c, 0x2e, 0x5c, + 0x64, 0x7b, 0x31, 0x2c, 0x32, 0x7d, 0x29, 0x3f, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x06, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, + 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x5c, 0x0a, 0x0a, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3c, + 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0xda, + 0xbb, 0x18, 0x29, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, 0x20, 0x72, 0x65, 0x67, 0x65, + 0x78, 0x70, 0x28, 0x27, 0x5e, 0x5c, 0x64, 0x7b, 0x34, 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, 0x7d, + 0x2d, 0x5c, 0x64, 0x7b, 0x32, 0x7d, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x0a, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe2, 0x02, 0x0a, 0x17, 0x49, 0x6e, 0x73, + 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x06, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x0a, + 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, + 0x64, 0x52, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x23, 0x0a, + 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0b, 0xca, + 0xbb, 0x18, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x06, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, + 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, + 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, + 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x52, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x0a, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x52, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe3, 0x01, + 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, 0x18, + 0x04, 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0f, 0xca, + 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0a, + 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, + 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, + 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, + 0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, + 0x69, 0x6d, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, + 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x39, + 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, 0x18, + 0x04, 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x42, 0x22, 0x5a, 0x20, 0x63, 0x6e, 0x2f, 0x6f, 0x6e, 0x65, 0x61, 0x6f, + 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/code/base-project/base-go-v3/biz/model/space/space.pb.go b/code/base-project/base-go-v3/biz/model/space/space.pb.go index 32072a56..b5efae1c 100644 --- a/code/base-project/base-go-v3/biz/model/space/space.pb.go +++ b/code/base-project/base-go-v3/biz/model/space/space.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: space.proto package space diff --git a/code/base-project/base-go-v3/biz/model/space/space_types.pb.go b/code/base-project/base-go-v3/biz/model/space/space_types.pb.go index b0506d37..70ab913b 100644 --- a/code/base-project/base-go-v3/biz/model/space/space_types.pb.go +++ b/code/base-project/base-go-v3/biz/model/space/space_types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: space/space_types.proto package space diff --git a/code/base-project/base-go-v3/biz/model/space/space_user_types.pb.go b/code/base-project/base-go-v3/biz/model/space/space_user_types.pb.go index a5f3617f..203e20d4 100644 --- a/code/base-project/base-go-v3/biz/model/space/space_user_types.pb.go +++ b/code/base-project/base-go-v3/biz/model/space/space_user_types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: space/space_user_types.proto package space @@ -347,8 +347,7 @@ type RemoveSpaceUserParams struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SpaceId int64 `protobuf:"varint,1,opt,name=SpaceId,proto3" form:"space_id" json:"space_id" vd:"$ != 0"` - UserId int64 `protobuf:"varint,2,opt,name=UserId,proto3" form:"user_id" json:"user_id" vd:"$ != 0"` + UserId int64 `protobuf:"varint,1,opt,name=UserId,proto3" form:"user_id" json:"user_id" vd:"$ != 0"` } func (x *RemoveSpaceUserParams) Reset() { @@ -383,13 +382,6 @@ func (*RemoveSpaceUserParams) Descriptor() ([]byte, []int) { return file_space_space_user_types_proto_rawDescGZIP(), []int{7} } -func (x *RemoveSpaceUserParams) GetSpaceId() int64 { - if x != nil { - return x.SpaceId - } - return 0 -} - func (x *RemoveSpaceUserParams) GetUserId() int64 { if x != nil { return x.UserId @@ -576,32 +568,29 @@ var file_space_space_user_types_proto_rawDesc = []byte{ 0x6f, 0x64, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x45, 0x78, 0x69, - 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x78, 0x0a, 0x15, + 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x46, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x30, 0x0a, 0x07, 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x16, 0xca, 0xbb, 0x18, 0x08, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0xda, 0xbb, 0x18, 0x06, 0x24, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x52, 0x07, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x15, 0xca, 0xbb, 0x18, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0xda, 0xbb, 0x18, 0x06, 0x24, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x52, 0x06, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xb9, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x26, 0x0a, 0x07, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0c, 0xca, - 0xbb, 0x18, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x07, 0x53, 0x70, 0x61, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x0a, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x69, 0x6e, 0x76, 0x69, - 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, - 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x42, 0x08, 0xca, 0xbb, 0x18, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x52, 0x6f, 0x6c, - 0x65, 0x42, 0x22, 0x5a, 0x20, 0x63, 0x6e, 0x2f, 0x6f, 0x6e, 0x65, 0x61, 0x6f, 0x2f, 0x62, 0x61, - 0x73, 0x65, 0x2d, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2d, 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x15, 0xca, 0xbb, 0x18, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0xda, 0xbb, 0x18, 0x06, 0x24, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x52, 0x06, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x14, 0x0a, + 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x22, 0xb9, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x26, 0x0a, 0x07, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0c, 0xca, 0xbb, 0x18, + 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x07, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x0a, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x2f, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, + 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, + 0x08, 0xca, 0xbb, 0x18, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x42, + 0x22, 0x5a, 0x20, 0x63, 0x6e, 0x2f, 0x6f, 0x6e, 0x65, 0x61, 0x6f, 0x2f, 0x62, 0x61, 0x73, 0x65, + 0x2d, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/code/base-project/base-go-v3/biz/router/middleware/auth.go b/code/base-project/base-go-v3/biz/router/middleware/auth.go index f0125893..5fb892d6 100644 --- a/code/base-project/base-go-v3/biz/router/middleware/auth.go +++ b/code/base-project/base-go-v3/biz/router/middleware/auth.go @@ -6,14 +6,20 @@ import ( "cn/oneao/base-go/utils/response" "context" "github.com/cloudwego/hertz/pkg/app" + "strconv" ) // 私有 key,防止冲突 -type ctxKeyUserID struct{} +type ctxKeyUser struct{} + +// ContextUser 保存用户信息,包括 UserID 和 SpaceID +type ContextUser struct { + UserID int64 + SpaceID int64 +} // Auth 中间件,直接在中间件里过滤白名单路径 func Auth() app.HandlerFunc { - // 白名单路径,直接写死 whitelistPaths := []string{ "/auth/login", "/auth/register", @@ -23,14 +29,13 @@ func Auth() app.HandlerFunc { return func(ctx context.Context, c *app.RequestContext) { path := string(c.Request.URI().Path()) - // 使用工具函数判断是否在白名单 if pathx.MatchPath(path, whitelistPaths) { c.Next(ctx) return } - // 获取 token token := string(c.GetHeader("token")) + spaceId := string(c.GetHeader("x-space-id")) if token == "" { response.Fail(c).Code(response.HttpCode.Unauthorized).Send() @@ -41,28 +46,52 @@ func Auth() app.HandlerFunc { verifyToken := jwtx.VerifyToken(token) if verifyToken.IsValid { - // 设置 userID 到 context - ctx = setUserID(ctx, verifyToken.Claims.UserID) + user := &ContextUser{ + UserID: verifyToken.Claims.UserID, + SpaceID: 0, + } + if spaceId != "" { + i, err := strconv.ParseInt(spaceId, 10, 64) + if err != nil { + response.Fail(c).Message("Invalid x-space-id").Send() + c.Abort() + return + } + + user.SpaceID = i + } + + ctx = setContextUser(ctx, user) c.Next(ctx) return } - // token 无效 response.Fail(c).Code(response.HttpCode.RefreshToken).Send() c.Abort() } } -// GetUserID 从 context 中获取 user_id -func GetUserID(ctx context.Context) int64 { - userID, ok := ctx.Value(ctxKeyUserID{}).(int64) - if !ok { - return 0 // 或者返回 error,根据业务需求 +// GetContextUser 从 context 获取用户信息 +func GetContextUser(ctx context.Context) *ContextUser { + user, ok := ctx.Value(ctxKeyUser{}).(*ContextUser) + if !ok || user == nil { + return &ContextUser{} } - return userID + return user } -// 内部中间件设置 user_id -func setUserID(ctx context.Context, userID int64) context.Context { - return context.WithValue(ctx, ctxKeyUserID{}, userID) +// GetUserID 从 context 获取 user_id +func GetUserID(ctx context.Context) int64 { + return GetContextUser(ctx).UserID +} + +// GetSpaceID 从 context 获取 space_id,并返回是否有效 +func GetSpaceID(ctx context.Context) (int64, bool) { + spaceID := GetContextUser(ctx).SpaceID + return spaceID, spaceID != 0 +} + +// 内部中间件设置 ContextUser +func setContextUser(ctx context.Context, user *ContextUser) context.Context { + return context.WithValue(ctx, ctxKeyUser{}, user) } diff --git a/code/base-project/base-go-v3/db/queries/money_record.sql b/code/base-project/base-go-v3/db/queries/money_record.sql index 64b5eb7a..15b92082 100644 --- a/code/base-project/base-go-v3/db/queries/money_record.sql +++ b/code/base-project/base-go-v3/db/queries/money_record.sql @@ -10,6 +10,20 @@ WHERE mr.user_id = $1 AND mr.record_time BETWEEN $2 AND $3 ORDER BY mr.record_time DESC, mr.create_time DESC; +-- name: FindMoneyRecordsBySpace :many +SELECT + mr.*, + u.username AS username, + muc.name AS category_name, + muc.icon AS category_icon, + muc.type AS category_type +FROM money_record mr + LEFT JOIN money_user_category muc ON mr.category_id = muc.id + INNER JOIN space_user su ON mr.user_id = su.user_id AND su.space_id = $1 + LEFT JOIN user_info u ON mr.user_id = u.id +WHERE mr.record_time BETWEEN $2 AND $3 +ORDER BY mr.record_time DESC, mr.create_time DESC; + -- name: InsertMoneyRecord :one INSERT INTO money_record ( id, diff --git a/code/base-project/base-go-v3/db/repo/money_record.sql.go b/code/base-project/base-go-v3/db/repo/money_record.sql.go index 466116a8..190976a6 100644 --- a/code/base-project/base-go-v3/db/repo/money_record.sql.go +++ b/code/base-project/base-go-v3/db/repo/money_record.sql.go @@ -20,6 +20,75 @@ func (q *Queries) DeleteMoneyRecord(ctx context.Context, id int64) error { return err } +const findMoneyRecordsBySpace = `-- name: FindMoneyRecordsBySpace :many +SELECT + mr.id, mr.category_id, mr.user_id, mr.amount, mr.remark, mr.record_time, mr.create_time, mr.update_time, + u.username AS username, + muc.name AS category_name, + muc.icon AS category_icon, + muc.type AS category_type +FROM money_record mr + LEFT JOIN money_user_category muc ON mr.category_id = muc.id + INNER JOIN space_user su ON mr.user_id = su.user_id AND su.space_id = $1 + LEFT JOIN user_info u ON mr.user_id = u.id +WHERE mr.record_time BETWEEN $2 AND $3 +ORDER BY mr.record_time DESC, mr.create_time DESC +` + +type FindMoneyRecordsBySpaceParams struct { + SpaceID int64 + RecordTime pgtype.Timestamp + RecordTime_2 pgtype.Timestamp +} + +type FindMoneyRecordsBySpaceRow struct { + ID int64 + CategoryID int64 + UserID int64 + Amount pgtype.Numeric + Remark pgtype.Text + RecordTime pgtype.Timestamp + CreateTime pgtype.Timestamp + UpdateTime pgtype.Timestamp + Username pgtype.Text + CategoryName pgtype.Text + CategoryIcon pgtype.Text + CategoryType pgtype.Int4 +} + +func (q *Queries) FindMoneyRecordsBySpace(ctx context.Context, arg FindMoneyRecordsBySpaceParams) ([]FindMoneyRecordsBySpaceRow, error) { + rows, err := q.db.Query(ctx, findMoneyRecordsBySpace, arg.SpaceID, arg.RecordTime, arg.RecordTime_2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FindMoneyRecordsBySpaceRow + for rows.Next() { + var i FindMoneyRecordsBySpaceRow + if err := rows.Scan( + &i.ID, + &i.CategoryID, + &i.UserID, + &i.Amount, + &i.Remark, + &i.RecordTime, + &i.CreateTime, + &i.UpdateTime, + &i.Username, + &i.CategoryName, + &i.CategoryIcon, + &i.CategoryType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const findUserMoneyRecords = `-- name: FindUserMoneyRecords :many SELECT mr.id, mr.category_id, mr.user_id, mr.amount, mr.remark, mr.record_time, mr.create_time, mr.update_time, diff --git a/code/base-project/base-go-v3/idl/money/money_record_types.proto b/code/base-project/base-go-v3/idl/money/money_record_types.proto index c4c8ed73..cf23dd26 100644 --- a/code/base-project/base-go-v3/idl/money/money_record_types.proto +++ b/code/base-project/base-go-v3/idl/money/money_record_types.proto @@ -16,6 +16,10 @@ message MoneyRecordItem { string RecordTime = 6 [(api.body)="record_time"]; string CreateTime = 7 [(api.body)="create_time"]; string UpdateTime = 8 [(api.body)="update_time"]; + string Username = 9 [(api.body)="username"]; + int32 CategoryType = 10 [(api.body)="category_type"]; + string CategoryIcon = 11 [(api.body)="category_icon"]; + string CategoryName = 12 [(api.body)="category_name"]; } // 同一天的记账记录分组 diff --git a/code/base-project/base-go-v3/idl/space/space_user_types.proto b/code/base-project/base-go-v3/idl/space/space_user_types.proto index 634df8ad..79cb3596 100644 --- a/code/base-project/base-go-v3/idl/space/space_user_types.proto +++ b/code/base-project/base-go-v3/idl/space/space_user_types.proto @@ -40,8 +40,7 @@ message ExitSpaceResult { // 踢出成员 message RemoveSpaceUserParams { - int64 SpaceId = 1 [(api.body) = "space_id",(api.vd)="$ != 0"]; - int64 UserId = 2 [(api.body) = "user_id",(api.vd)="$ != 0"]; + int64 UserId = 1 [(api.body) = "user_id",(api.vd)="$ != 0"]; } message RemoveSpaceUserResult { diff --git a/code/base-project/base-go-v3/utils/pgtypex/pgtypex.go b/code/base-project/base-go-v3/utils/pgtypex/pgtypex.go index c06f5d74..28ef7203 100644 --- a/code/base-project/base-go-v3/utils/pgtypex/pgtypex.go +++ b/code/base-project/base-go-v3/utils/pgtypex/pgtypex.go @@ -88,8 +88,8 @@ func StringToTimestamp(s string) pgtype.Timestamp { var err error layouts := []string{ - "2006-01-02 15:04:05", - "2006-01-02", + "2006-01-02 15:04:05", // 完整时间 + "2006-01-02", // 仅日期也可解析 } for _, layout := range layouts { @@ -104,3 +104,22 @@ func StringToTimestamp(s string) pgtype.Timestamp { return pgtype.Timestamp{Valid: false} } + +// StringToDate 将字符串解析为 pgtype.Date +// 支持格式:YYYY-MM-DD +// 解析失败或空字符串返回零值 Date +func StringToDate(s string) pgtype.Date { + if s == "" { + return pgtype.Date{Valid: false} + } + + t, err := time.Parse("2006-01-02", s) + if err != nil { + return pgtype.Date{Valid: false} + } + + return pgtype.Date{ + Time: t, + Valid: true, + } +}