feat: 品牌文案配置化 + 全页面下拉刷新

- 新增 configStore 管理品牌文案(appName, appSlogan, appDescription)
- 关于弹窗、分享标题使用 configStore 读取品牌名
- 所有数据页面添加下拉刷新功能
- 所有数据页面 onShow 时自动刷新数据
This commit is contained in:
2026-06-08 10:59:09 +08:00
parent 62ca400b64
commit 6af876a8f4
12 changed files with 161 additions and 24 deletions

View File

@@ -52,6 +52,7 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { waitForReady } from '@/utils/app-ready'
import { statusBarHeight } from '@/utils/system'
import { getConfig, updateConfig } from '@/api/config'
@@ -80,6 +81,26 @@ onMounted(async () => {
}
})
// 加载配置数据
async function loadConfig() {
try {
const config = await getConfig()
form.app_version = config.app_version || '1.0.0'
form.app_slogan = config.app_slogan || ''
form.app_description = config.app_description || ''
} catch {}
}
// 返回页面时静默刷新
onShow(() => {
loadConfig()
})
onPullDownRefresh(async () => {
await loadConfig()
uni.stopPullDownRefresh()
})
async function saveConfig() {
if (saving.value) return

View File

@@ -82,7 +82,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { waitForReady } from '@/utils/app-ready'
import { statusBarHeight } from '@/utils/system'
import { getFeedbackList, updateFeedbackStatus } from '@/api/feedback'
@@ -121,6 +121,11 @@ onShow(() => {
if (initialLoaded.value) loadList(true)
})
onPullDownRefresh(async () => {
await loadList(true)
uni.stopPullDownRefresh()
})
function switchStatus(status: string) {
filterStatus.value = status
loadList(true)

View File

@@ -89,6 +89,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { waitForReady } from '@/utils/app-ready'
import { statusBarHeight } from '@/utils/system'
import { getDashboard } from '@/api/admin'
@@ -121,6 +122,26 @@ onMounted(async () => {
}
})
// 静默刷新(强制刷新缓存)
async function refreshDashboard(force = false) {
try {
if (force || !dashboardCache || Date.now() - dashboardCache.time >= CACHE_TTL) {
dashboard.value = await getDashboard()
dashboardCache = { data: dashboard.value, time: Date.now() }
}
} catch {}
}
// 返回页面时静默刷新
onShow(() => {
refreshDashboard()
})
onPullDownRefresh(async () => {
await refreshDashboard(true)
uni.stopPullDownRefresh()
})
function goBack() { uni.navigateBack() }
function goUsers() { uni.navigateTo({ url: '/pages/admin/users' }) }
function goNotificationManage() { uni.navigateTo({ url: '/pages/admin/notifications' }) }

View File

@@ -54,7 +54,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { onReachBottom } from '@dcloudio/uni-app'
import { onShow, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import { waitForReady } from '@/utils/app-ready'
import { statusBarHeight } from '@/utils/system'
import { API_BASE } from '@/config'
@@ -71,9 +71,22 @@ const page = ref(1)
const total = ref(0)
const loading = ref(false)
const initialLoaded = ref(false)
onMounted(async () => {
await waitForReady()
await loadUsers(true)
initialLoaded.value = true
})
// 返回页面时静默刷新
onShow(() => {
if (initialLoaded.value) loadUsers(true)
})
onPullDownRefresh(async () => {
await loadUsers(true)
uni.stopPullDownRefresh()
})
async function loadUsers(reset = false) {

View File

@@ -75,7 +75,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { useBudgetStore } from '@/stores/budget'
import { useGroupStore } from '@/stores/group'
import { getOverview } from '@/api/stats'
@@ -150,6 +150,15 @@ onShow(async () => {
} catch {}
})
onPullDownRefresh(async () => {
try {
await budgetStore.fetchBudget(currentMonth)
syncBudgetData()
fetchMyExpense()
} catch {}
uni.stopPullDownRefresh()
})
function selectPreset(val: number) {
amountStr.value = String(val)
}

View File

@@ -111,7 +111,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { useCategoryStore, type Category } from '@/stores/category'
import { waitForReady } from '@/utils/app-ready'
import { getCategoryTransactionCount } from '@/api/category'
@@ -158,6 +158,11 @@ onShow(() => {
if (initialLoaded.value) catStore.fetchCategories()
})
onPullDownRefresh(async () => {
await catStore.fetchCategories()
uni.stopPullDownRefresh()
})
function goBack() {
uni.navigateBack()
}

View File

@@ -140,8 +140,9 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { onShow, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
import { onShow, onPullDownRefresh, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
import { useGroupStore } from '@/stores/group'
import { useConfigStore } from '@/stores/config'
import { waitForReady } from '@/utils/app-ready'
import { statusBarHeight, capsuleRight } from '@/utils/system'
import { API_BASE } from '@/config'
@@ -149,6 +150,7 @@ import Icon from '@/components/Icon/Icon.vue'
import type { GroupMember, Group } from '@/api/group'
const groupStore = useGroupStore()
const configStore = useConfigStore()
const actionTab = ref<'create' | 'join'>('create')
const newGroupName = ref('')
@@ -174,6 +176,11 @@ onShow(() => {
if (initialLoaded.value) groupStore.fetchGroups()
})
onPullDownRefresh(async () => {
await groupStore.fetchGroups()
uni.stopPullDownRefresh()
})
// #ifdef MP-WEIXIN
onShareAppMessage(() => {
// 空值保护:通过右上角菜单触发时 invite_code 可能为空
@@ -188,7 +195,7 @@ onShareAppMessage(() => {
})
onShareTimeline(() => ({
title: '小菜记账 — 一起来记账吧!'
title: `${configStore.appName} — 一起来记账吧!`
}))
// #endif

View File

@@ -84,10 +84,10 @@
<!-- 关于弹窗 -->
<view class="modal-mask" v-if="showAbout" @tap="showAbout = false">
<view class="modal" @tap.stop>
<text class="about-title">小菜记账</text>
<text class="about-version">v{{ appConfig.app_version || '1.0.0' }}</text>
<text class="about-desc">{{ appConfig.app_slogan || '温暖 x 轻松的个人记账小程序' }}</text>
<text class="about-desc">{{ appConfig.app_description || '让记账从负担变成享受' }}</text>
<text class="about-title">{{ configStore.appName }}</text>
<text class="about-version">v{{ configStore.config.app_version || '1.0.0' }}</text>
<text class="about-desc">{{ configStore.appSlogan }}</text>
<text class="about-desc">{{ configStore.appDescription }}</text>
<view class="modal-btns modal-btns-top">
<view class="modal-btn confirm" @tap="showAbout = false">知道了</view>
</view>
@@ -135,15 +135,15 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app'
import { useTransactionStore } from '@/stores/transaction'
import { useStatsStore } from '@/stores/stats'
import { useBudgetStore } from '@/stores/budget'
import { useUserStore } from '@/stores/user'
import { useGroupStore } from '@/stores/group'
import { useConfigStore } from '@/stores/config'
import { waitForReady } from '@/utils/app-ready'
import { getTransactions } from '@/api/transaction'
import { getConfig } from '@/api/config'
import { formatAmount } from '@/utils/format'
import { statusBarHeight } from '@/utils/system'
import Icon from '@/components/Icon/Icon.vue'
@@ -153,6 +153,7 @@ const statsStore = useStatsStore()
const budgetStore = useBudgetStore()
const userStore = useUserStore()
const groupStore = useGroupStore()
const configStore = useConfigStore()
const overview = computed(() => statsStore.overview)
const budget = computed(() => budgetStore.budget)
@@ -160,7 +161,6 @@ const loading = ref(true)
const showAbout = ref(false)
const showIdentity = ref(false)
const initialLoaded = ref(false)
const appConfig = ref<Record<string, string>>({})
onMounted(async () => {
await waitForReady()
@@ -171,8 +171,7 @@ onMounted(async () => {
budgetStore.fetchBudget(),
txStore.fetchTransactions({ page: 1, pageSize: 1 }),
userStore.fetchUserInfo(),
groupStore.fetchGroups(),
getConfig().then(config => { appConfig.value = config }).catch(() => {})
groupStore.fetchGroups()
])
} catch (e) {
console.error('Profile load error:', e)
@@ -196,6 +195,20 @@ onShow(async () => {
} catch {}
})
onPullDownRefresh(async () => {
try {
await Promise.all([
statsStore.fetchOverview(),
budgetStore.fetchBudget(),
txStore.fetchTransactions({ page: 1, pageSize: 1 }),
groupStore.fetchGroups(),
userStore.fetchUserInfo(),
configStore.fetchConfig()
])
} catch {}
uni.stopPullDownRefresh()
})
function goBudget() {
uni.navigateTo({ url: '/pages/budget/index' })
}

View File

@@ -123,6 +123,7 @@ import { storeToRefs } from 'pinia'
import { onShow, onPullDownRefresh, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
import { useStatsStore } from '@/stores/stats'
import { useGroupStore } from '@/stores/group'
import { useConfigStore } from '@/stores/config'
import { waitForReady } from '@/utils/app-ready'
import { getTransactions } from '@/api/transaction'
import { getOverview } from '@/api/stats'
@@ -134,6 +135,7 @@ import ChartWrapper from '@/components/ChartWrapper/ChartWrapper.vue'
const statsStore = useStatsStore()
const groupStore = useGroupStore()
const configStore = useConfigStore()
const currentMonth = ref(getCurrentMonth())
const tabType = ref<'expense' | 'income'>('expense')
@@ -322,7 +324,7 @@ onShareAppMessage(() => {
})
onShareTimeline(() => ({
title: `小菜记账 — 我的${formatMonth(currentMonth.value)}账单`
title: `${configStore.appName} — 我的${formatMonth(currentMonth.value)}账单`
}))
// #endif