feat: 完成情绪博物馆项目重构和功能增强 - 新增日记评论和帖子功能 - 重构前端架构,优化用户体验 - 完善WebSocket通信机制 - 更新项目文档和部署配置

This commit is contained in:
2025-07-27 10:05:59 +08:00
parent 6903ac1c0d
commit cc886cd4d5
126 changed files with 21179 additions and 15734 deletions
+269
View File
@@ -0,0 +1,269 @@
/**
* 加载状态管理组合式函数
*/
import { ref, computed } from 'vue'
import { ElLoading } from 'element-plus'
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading'
// 全局加载状态
const globalLoading = ref(false)
const loadingCount = ref(0)
/**
* 使用加载状态
*/
export const useLoading = (initialState = false) => {
const loading = ref(initialState)
/**
* 设置加载状态
*/
const setLoading = (state: boolean) => {
loading.value = state
}
/**
* 开始加载
*/
const startLoading = () => {
loading.value = true
}
/**
* 结束加载
*/
const stopLoading = () => {
loading.value = false
}
/**
* 异步操作包装器
*/
const withLoading = async <T>(fn: () => Promise<T>): Promise<T> => {
try {
startLoading()
return await fn()
} finally {
stopLoading()
}
}
return {
loading: computed(() => loading.value),
setLoading,
startLoading,
stopLoading,
withLoading
}
}
/**
* 使用全局加载状态
*/
export const useGlobalLoading = () => {
/**
* 增加加载计数
*/
const addLoading = () => {
loadingCount.value++
globalLoading.value = true
}
/**
* 减少加载计数
*/
const removeLoading = () => {
loadingCount.value = Math.max(0, loadingCount.value - 1)
if (loadingCount.value === 0) {
globalLoading.value = false
}
}
/**
* 重置加载状态
*/
const resetLoading = () => {
loadingCount.value = 0
globalLoading.value = false
}
/**
* 全局异步操作包装器
*/
const withGlobalLoading = async <T>(fn: () => Promise<T>): Promise<T> => {
try {
addLoading()
return await fn()
} finally {
removeLoading()
}
}
return {
globalLoading: computed(() => globalLoading.value),
loadingCount: computed(() => loadingCount.value),
addLoading,
removeLoading,
resetLoading,
withGlobalLoading
}
}
/**
* 使用页面加载遮罩
*/
export const usePageLoading = () => {
let loadingInstance: LoadingInstance | null = null
/**
* 显示页面加载遮罩
*/
const showPageLoading = (options?: {
text?: string
background?: string
target?: string | HTMLElement
}) => {
const {
text = '加载中...',
background = 'rgba(0, 0, 0, 0.7)',
target = 'body'
} = options || {}
loadingInstance = ElLoading.service({
lock: true,
text,
background,
target
})
}
/**
* 隐藏页面加载遮罩
*/
const hidePageLoading = () => {
if (loadingInstance) {
loadingInstance.close()
loadingInstance = null
}
}
/**
* 页面异步操作包装器
*/
const withPageLoading = async <T>(
fn: () => Promise<T>,
options?: {
text?: string
background?: string
target?: string | HTMLElement
}
): Promise<T> => {
try {
showPageLoading(options)
return await fn()
} finally {
hidePageLoading()
}
}
return {
showPageLoading,
hidePageLoading,
withPageLoading
}
}
/**
* 使用按钮加载状态
*/
export const useButtonLoading = () => {
const buttonLoadings = ref<Record<string, boolean>>({})
/**
* 设置按钮加载状态
*/
const setButtonLoading = (key: string, loading: boolean) => {
buttonLoadings.value[key] = loading
}
/**
* 获取按钮加载状态
*/
const getButtonLoading = (key: string) => {
return computed(() => buttonLoadings.value[key] || false)
}
/**
* 按钮异步操作包装器
*/
const withButtonLoading = async <T>(
key: string,
fn: () => Promise<T>
): Promise<T> => {
try {
setButtonLoading(key, true)
return await fn()
} finally {
setButtonLoading(key, false)
}
}
return {
buttonLoadings: computed(() => buttonLoadings.value),
setButtonLoading,
getButtonLoading,
withButtonLoading
}
}
/**
* 使用延迟加载
*/
export const useDelayedLoading = (delay = 300) => {
const loading = ref(false)
const actualLoading = ref(false)
let timer: NodeJS.Timeout | null = null
/**
* 设置加载状态(带延迟)
*/
const setLoading = (state: boolean) => {
if (state) {
// 立即设置实际加载状态
actualLoading.value = true
// 延迟显示加载UI
timer = setTimeout(() => {
loading.value = true
}, delay)
} else {
// 立即隐藏加载UI
if (timer) {
clearTimeout(timer)
timer = null
}
loading.value = false
actualLoading.value = false
}
}
/**
* 延迟异步操作包装器
*/
const withDelayedLoading = async <T>(fn: () => Promise<T>): Promise<T> => {
try {
setLoading(true)
return await fn()
} finally {
setLoading(false)
}
}
return {
loading: computed(() => loading.value),
actualLoading: computed(() => actualLoading.value),
setLoading,
withDelayedLoading
}
}