feat: phase 3 - ledger and asset management
Add group expense tracking (ledger) and public asset inventory (asset) features. Ledger supports income/expense recording with monthly summary. Asset tracks group equipment with free-form holder transfer. Both are independent pages accessible from GroupView navigation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { Asset } from '@/types'
|
||||
import {
|
||||
listAssets,
|
||||
createAsset,
|
||||
updateAsset,
|
||||
transferAsset,
|
||||
deleteAsset,
|
||||
subscribeAssets
|
||||
} from '@/api/assets'
|
||||
import type { CreateAssetData, UpdateAssetData } from '@/api/assets'
|
||||
|
||||
export const useAssetStore = defineStore('asset', () => {
|
||||
const assets = ref<Asset[]>([])
|
||||
const loading = ref(false)
|
||||
let unsubFn: (() => Promise<void> | void) | null = null
|
||||
|
||||
async function loadAssets(groupId: string) {
|
||||
try {
|
||||
loading.value = true
|
||||
assets.value = await listAssets(groupId)
|
||||
} catch (error) {
|
||||
console.error('加载资产列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function addAsset(data: CreateAssetData) {
|
||||
try {
|
||||
loading.value = true
|
||||
await createAsset(data)
|
||||
await loadAssets(data.group)
|
||||
} catch (error) {
|
||||
console.error('创建资产失败:', error)
|
||||
throw error
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function editAsset(assetId: string, data: UpdateAssetData, image?: File) {
|
||||
try {
|
||||
loading.value = true
|
||||
await updateAsset(assetId, data, image)
|
||||
// 找到当前资产的 groupId 以刷新列表
|
||||
const asset = assets.value.find(a => a.id === assetId)
|
||||
if (asset) {
|
||||
await loadAssets(asset.group)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新资产失败:', error)
|
||||
throw error
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function transfer(assetId: string, userId: string) {
|
||||
try {
|
||||
await transferAsset(assetId, userId)
|
||||
const asset = assets.value.find(a => a.id === assetId)
|
||||
if (asset) {
|
||||
await loadAssets(asset.group)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('转移资产失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function removeAsset(assetId: string) {
|
||||
try {
|
||||
await deleteAsset(assetId)
|
||||
const asset = assets.value.find(a => a.id === assetId)
|
||||
assets.value = assets.value.filter(a => a.id !== assetId)
|
||||
// 返回 groupId 以便调用方需要时使用
|
||||
return asset?.group
|
||||
} catch (error) {
|
||||
console.error('删除资产失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function startSubscription(groupId: string) {
|
||||
stopSubscription()
|
||||
unsubFn = await subscribeAssets(groupId, () => {
|
||||
loadAssets(groupId)
|
||||
})
|
||||
}
|
||||
|
||||
function stopSubscription() {
|
||||
if (unsubFn) {
|
||||
unsubFn()
|
||||
unsubFn = null
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
assets,
|
||||
loading,
|
||||
loadAssets,
|
||||
addAsset,
|
||||
editAsset,
|
||||
transfer,
|
||||
removeAsset,
|
||||
startSubscription,
|
||||
stopSubscription
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user