fix(phase3): subscription leak, image mime type validation
- Ledger store: add stopSubscription() to properly clean up realtime subscriptions, matching asset store pattern - LedgerList: call stopSubscription on unmount - Assets migration: restrict image upload to image/* mime types (C3 updateRule is a known tradeoff — PocketBase lacks field-level permissions, frontend enforces edit restrictions instead) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -112,7 +112,7 @@ migrate((db) => {
|
|||||||
"presentable": false,
|
"presentable": false,
|
||||||
"unique": false,
|
"unique": false,
|
||||||
"options": {
|
"options": {
|
||||||
"mimeTypes": null,
|
"mimeTypes": ["image/*"],
|
||||||
"thumbs": ["200x200"],
|
"thumbs": ["200x200"],
|
||||||
"maxSelect": 1,
|
"maxSelect": 1,
|
||||||
"maxSize": 5242880,
|
"maxSize": 5242880,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted, watch } from 'vue'
|
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { Plus } from '@element-plus/icons-vue'
|
import { Plus } from '@element-plus/icons-vue'
|
||||||
import { useLedgerStore } from '@/stores/ledger'
|
import { useLedgerStore } from '@/stores/ledger'
|
||||||
@@ -139,6 +139,10 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
ledgerStore.stopSubscription()
|
||||||
|
})
|
||||||
|
|
||||||
watch(() => groupStore.currentGroupId, (newId, oldId) => {
|
watch(() => groupStore.currentGroupId, (newId, oldId) => {
|
||||||
if (newId && newId !== oldId) {
|
if (newId && newId !== oldId) {
|
||||||
loadData()
|
loadData()
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export const useLedgerStore = defineStore('ledger', () => {
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const summary = ref({ totalIncome: 0, totalExpense: 0, balance: 0 })
|
const summary = ref({ totalIncome: 0, totalExpense: 0, balance: 0 })
|
||||||
const currentMonth = ref(new Date().toISOString().slice(0, 7))
|
const currentMonth = ref(new Date().toISOString().slice(0, 7))
|
||||||
|
let unsubFn: (() => Promise<void> | void) | null = null
|
||||||
|
|
||||||
// 加载账目列表和汇总
|
// 加载账目列表和汇总
|
||||||
async function loadLedgers(groupId: string, month?: string) {
|
async function loadLedgers(groupId: string, month?: string) {
|
||||||
@@ -78,12 +79,19 @@ export const useLedgerStore = defineStore('ledger', () => {
|
|||||||
|
|
||||||
// 订阅实时更新
|
// 订阅实时更新
|
||||||
async function startSubscription(groupId: string) {
|
async function startSubscription(groupId: string) {
|
||||||
await subscribeLedgers(groupId, () => {
|
stopSubscription()
|
||||||
// 收到变更后重新加载当前月份的数据
|
unsubFn = await subscribeLedgers(groupId, () => {
|
||||||
loadLedgers(groupId)
|
loadLedgers(groupId)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stopSubscription() {
|
||||||
|
if (unsubFn) {
|
||||||
|
unsubFn()
|
||||||
|
unsubFn = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ledgers,
|
ledgers,
|
||||||
loading,
|
loading,
|
||||||
@@ -94,6 +102,7 @@ export const useLedgerStore = defineStore('ledger', () => {
|
|||||||
addLedger,
|
addLedger,
|
||||||
editLedger,
|
editLedger,
|
||||||
removeLedger,
|
removeLedger,
|
||||||
startSubscription
|
startSubscription,
|
||||||
|
stopSubscription
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user