diff --git a/client/src/api/feedback.ts b/client/src/api/feedback.ts index 93ab2ed..744ca79 100644 --- a/client/src/api/feedback.ts +++ b/client/src/api/feedback.ts @@ -1,5 +1,20 @@ import { request } from '@/utils/request' +/** 反馈条目 */ +export interface Feedback { + id: number + user_id: number + nickname?: string + avatar_url?: string + type: string + content: string + contact: string + status: 'pending' | 'processed' | 'ignored' + admin_reply?: string + created_at: string + updated_at?: string +} + /** 提交反馈 */ export function submitFeedback(data: { type: string @@ -11,7 +26,7 @@ export function submitFeedback(data: { /** 获取反馈列表(管理员) */ export function getFeedbackList(params?: { page?: number; pageSize?: number; status?: string }) { - return request({ url: '/feedback', data: params }) + return request<{ list: Feedback[]; total: number; page: number; pageSize: number }>({ url: '/feedback', data: params }) } /** 更新反馈状态(管理员) */ diff --git a/client/src/pages/add/index.vue b/client/src/pages/add/index.vue index dbffb14..146729d 100644 --- a/client/src/pages/add/index.vue +++ b/client/src/pages/add/index.vue @@ -136,7 +136,7 @@ onMounted(async () => { } const pages = getCurrentPages() - const page = pages[pages.length - 1] as any + const page = pages[pages.length - 1] as { options?: Record } if (page?.options?.type && ['expense', 'income'].includes(page.options.type)) { type.value = page.options.type } diff --git a/client/src/pages/admin/feedback.vue b/client/src/pages/admin/feedback.vue index 8420c54..80d5241 100644 --- a/client/src/pages/admin/feedback.vue +++ b/client/src/pages/admin/feedback.vue @@ -86,6 +86,7 @@ import { onShow, onPullDownRefresh } from '@dcloudio/uni-app' import { waitForReady } from '@/utils/app-ready' import { statusBarHeight } from '@/utils/system' import { getFeedbackList, updateFeedbackStatus } from '@/api/feedback' +import type { Feedback } from '@/api/feedback' import { API_BASE } from '@/config' import Icon from '@/components/Icon/Icon.vue' @@ -102,7 +103,7 @@ const statusMap: Record = { ignored: '已忽略' } -const list = ref([]) +const list = ref([]) const loading = ref(false) const filterStatus = ref('') const page = ref(1) @@ -138,7 +139,7 @@ async function loadList(reset = false) { } loading.value = true try { - const params: any = { page: page.value, pageSize } + const params: { page: number; pageSize: number; status?: string } = { page: page.value, pageSize } if (filterStatus.value) params.status = filterStatus.value const data = await getFeedbackList(params) if (reset) { @@ -160,7 +161,7 @@ function loadMore() { loadList(false) } -async function updateStatus(item: any, status: string) { +async function updateStatus(item: Feedback, status: string) { try { await updateFeedbackStatus(item.id, status) item.status = status diff --git a/client/src/pages/admin/logs.vue b/client/src/pages/admin/logs.vue index 4901d8a..1af2bde 100644 --- a/client/src/pages/admin/logs.vue +++ b/client/src/pages/admin/logs.vue @@ -180,14 +180,12 @@ function loadMore() { function selectDate(date: string) { selectedDate.value = date - page.value = 1 - loadLogs() + // loadLogs() 由 watch([filterLevel, selectedDate]) 统一触发,避免双重请求 } function onDateChange(e: any) { selectedDate.value = e.detail.value - page.value = 1 - loadLogs() + // loadLogs() 由 watch 统一触发 } function getBarWidth(count: number): number { diff --git a/client/src/pages/admin/users.vue b/client/src/pages/admin/users.vue index d3ae4dd..d1bbccd 100644 --- a/client/src/pages/admin/users.vue +++ b/client/src/pages/admin/users.vue @@ -96,7 +96,7 @@ async function loadUsers(reset = false) { } loading.value = true try { - const params: any = { page: page.value, pageSize: 20 } + const params: { page: number; pageSize: number; keyword?: string } = { page: page.value, pageSize: 20 } if (keyword.value.trim()) params.keyword = keyword.value.trim() const data = await getUsers(params) if (reset) { diff --git a/client/src/pages/bills/index.vue b/client/src/pages/bills/index.vue index 7419892..e833eeb 100644 --- a/client/src/pages/bills/index.vue +++ b/client/src/pages/bills/index.vue @@ -79,8 +79,9 @@ 加载失败,下拉刷新重试 - - 暂无账单记录 + + + 暂无账单记录 @@ -98,6 +99,7 @@ import Skeleton from '@/components/Skeleton/Skeleton.vue' import FilterPanel from './filter-panel.vue' import { statusBarHeight } from '@/utils/system' import { formatAmount, formatDate } from '@/utils/format' +import type { Transaction, TransactionParams } from '@/api/transaction' import type { FilterParams } from '@/api/filter' const userStore = useUserStore() @@ -106,7 +108,7 @@ const loading = ref(false) const filterType = ref('all') const page = ref(1) const pageSize = 20 -const txList = ref([]) +const txList = ref([]) const total = ref(0) const loadError = ref(false) let loadSeq = 0 // 请求序号,防止并发覆盖 @@ -162,7 +164,7 @@ async function loadTx(reset = false, silent = false) { if (!silent) txList.value = [] } const seq = ++loadSeq - const params: any = { page: page.value, pageSize, group_id: groupStore.currentGroupId } + const params: TransactionParams & { group_id?: number | null; category_ids?: string } = { page: page.value, pageSize, group_id: groupStore.currentGroupId } if (filterType.value !== 'all') params.type = filterType.value // 合并高级筛选参数 const af = advancedFilters.value @@ -369,13 +371,6 @@ onPullDownRefresh(() => { .loading-text { font-size: $font-md; color: $text-muted; } -.empty { - text-align: center; - padding: 120rpx 0; -} - -.empty-text { font-size: $font-lg; color: $text-muted; } - .state-box { @include state-box; justify-content: center; diff --git a/client/src/pages/budget/index.vue b/client/src/pages/budget/index.vue index b77e6a9..0d22e55 100644 --- a/client/src/pages/budget/index.vue +++ b/client/src/pages/budget/index.vue @@ -81,6 +81,7 @@ import { useGroupStore } from '@/stores/group' import { getOverview } from '@/api/stats' import { waitForReady } from '@/utils/app-ready' import { formatAmount, getCurrentMonth } from '@/utils/format' +import type { Budget } from '@/api/budget' import { statusBarHeight } from '@/utils/system' import BudgetBar from '@/components/BudgetBar/BudgetBar.vue' import Numpad from '@/components/Numpad/Numpad.vue' @@ -90,7 +91,7 @@ const budgetStore = useBudgetStore() const groupStore = useGroupStore() const currentMonth = getCurrentMonth() -const budget = ref(null) +const budget = ref(null) const budgetAmount = ref(0) const monthExpense = ref(0) const loading = ref(true) diff --git a/client/src/pages/index/index.vue b/client/src/pages/index/index.vue index 828357f..7374fcf 100644 --- a/client/src/pages/index/index.vue +++ b/client/src/pages/index/index.vue @@ -146,6 +146,7 @@ import { useGroupStore } from '@/stores/group' import { useNotificationStore } from '@/stores/notification' import { waitForReady } from '@/utils/app-ready' import { getOverview } from '@/api/stats' +import type { Transaction } from '@/api/transaction' import { getNotificationImageUrl } from '@/api/notification' import { formatAmount, formatAmountRaw } from '@/utils/format' import { statusBarHeight, capsuleRight } from '@/utils/system' @@ -165,7 +166,7 @@ const DEFAULT_BUDGET = 500000 // 5000元(分) const overview = computed(() => statsStore.overview) const budget = computed(() => budgetStore.budget) -const recentTx = ref([]) +const recentTx = ref([]) const loading = ref(true) const loadError = ref(false) const todayExpense = ref(0) diff --git a/client/src/pages/notifications/index.vue b/client/src/pages/notifications/index.vue index 5ac8ea1..292e588 100644 --- a/client/src/pages/notifications/index.vue +++ b/client/src/pages/notifications/index.vue @@ -39,7 +39,7 @@ - 📌 + 置顶 {{ item.title }} {{ item.content }} @@ -355,7 +355,12 @@ onReachBottom(() => { } .pin-badge { - font-size: $font-md; + font-size: $font-xs; + color: $primary; + background: #FFE8E0; + padding: 2rpx 10rpx; + border-radius: $radius-xs; + font-weight: 500; } .notif-title { diff --git a/client/src/pages/profile/index.vue b/client/src/pages/profile/index.vue index 9d653e0..e1d7533 100644 --- a/client/src/pages/profile/index.vue +++ b/client/src/pages/profile/index.vue @@ -144,6 +144,7 @@ import { useGroupStore } from '@/stores/group' import { useConfigStore } from '@/stores/config' import { waitForReady } from '@/utils/app-ready' import { getTransactions } from '@/api/transaction' +import type { Transaction } from '@/api/transaction' import { formatAmount } from '@/utils/format' import { statusBarHeight } from '@/utils/system' import Icon from '@/components/Icon/Icon.vue' @@ -326,7 +327,7 @@ async function exportData() { uni.showLoading({ title: '导出中 0%' }) try { // 分页获取全部数据(服务端 pageSize 上限 100) - const allList: any[] = [] + const allList: Transaction[] = [] let page = 1 let total = 0 do { diff --git a/client/src/pages/stats/index.vue b/client/src/pages/stats/index.vue index 3994695..b5bffa6 100644 --- a/client/src/pages/stats/index.vue +++ b/client/src/pages/stats/index.vue @@ -548,6 +548,10 @@ function getBarWidth(amount: number) { border-radius: 6rpx; background: linear-gradient(90deg, $primary, #FFB89A); transition: width 0.6s ease-out; + + @media (prefers-reduced-motion: reduce) { + transition: none; + } } .trend-amount {