refactor: modularize frontend flows
This commit is contained in:
+15
-12
@@ -1,12 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { STORAGE_KEYS } from '@/constants'
|
||||
import type { AdminUser } from '@/types'
|
||||
import {
|
||||
clearStoredAuth,
|
||||
readStoredAdminPassword,
|
||||
readStoredToken,
|
||||
writeStoredAdminPassword,
|
||||
writeStoredToken
|
||||
} from '@/utils/auth-storage'
|
||||
|
||||
export const useAdminStore = defineStore('admin', () => {
|
||||
// 状态
|
||||
const adminPassword = ref(localStorage.getItem(STORAGE_KEYS.ADMIN_PASSWORD) || '')
|
||||
const token = ref(localStorage.getItem(STORAGE_KEYS.TOKEN) || '')
|
||||
const adminPassword = ref(readStoredAdminPassword())
|
||||
const token = ref(readStoredToken())
|
||||
const isLoggedIn = ref(false)
|
||||
const userInfo = ref<AdminUser | null>(null)
|
||||
|
||||
@@ -14,16 +20,17 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
const isAuthenticated = computed(() => {
|
||||
return isLoggedIn.value && !!token.value
|
||||
})
|
||||
const hasToken = computed(() => !!token.value)
|
||||
|
||||
// 方法
|
||||
const updateAdminPassword = (pwd: string) => {
|
||||
adminPassword.value = pwd
|
||||
localStorage.setItem(STORAGE_KEYS.ADMIN_PASSWORD, pwd)
|
||||
writeStoredAdminPassword(pwd)
|
||||
}
|
||||
|
||||
const setToken = (newToken: string) => {
|
||||
token.value = newToken
|
||||
localStorage.setItem(STORAGE_KEYS.TOKEN, newToken)
|
||||
writeStoredToken(newToken)
|
||||
}
|
||||
|
||||
const setUserInfo = (user: AdminUser) => {
|
||||
@@ -42,13 +49,11 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
isLoggedIn.value = false
|
||||
userInfo.value = null
|
||||
|
||||
// 清除本地存储
|
||||
localStorage.removeItem(STORAGE_KEYS.ADMIN_PASSWORD)
|
||||
localStorage.removeItem(STORAGE_KEYS.TOKEN)
|
||||
clearStoredAuth()
|
||||
}
|
||||
|
||||
const initAuth = () => {
|
||||
const storedToken = localStorage.getItem(STORAGE_KEYS.TOKEN)
|
||||
const storedToken = readStoredToken()
|
||||
if (storedToken) {
|
||||
token.value = storedToken
|
||||
isLoggedIn.value = true
|
||||
@@ -64,6 +69,7 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
|
||||
// 计算属性
|
||||
isAuthenticated,
|
||||
hasToken,
|
||||
|
||||
// 方法
|
||||
updateAdminPassword,
|
||||
@@ -74,6 +80,3 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
initAuth
|
||||
}
|
||||
})
|
||||
|
||||
// 保持向后兼容
|
||||
export const useAdminData = useAdminStore
|
||||
|
||||
@@ -2,6 +2,8 @@ import { defineStore } from 'pinia'
|
||||
import type { Alert, AlertType } from '@/types'
|
||||
import { TIME_CONSTANTS } from '@/constants'
|
||||
|
||||
let progressTimer: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
export const useAlertStore = defineStore('alert', {
|
||||
state: () => ({
|
||||
alerts: [] as Alert[]
|
||||
@@ -33,6 +35,25 @@ export const useAlertStore = defineStore('alert', {
|
||||
this.removeAlert(id)
|
||||
}
|
||||
}
|
||||
},
|
||||
startProgressTimer() {
|
||||
if (progressTimer) {
|
||||
return
|
||||
}
|
||||
|
||||
progressTimer = setInterval(() => {
|
||||
this.alerts.forEach((alert) => {
|
||||
this.updateAlertProgress(alert.id)
|
||||
})
|
||||
}, TIME_CONSTANTS.PROGRESS_UPDATE_INTERVAL)
|
||||
},
|
||||
stopProgressTimer() {
|
||||
if (!progressTimer) {
|
||||
return
|
||||
}
|
||||
|
||||
clearInterval(progressTimer)
|
||||
progressTimer = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { ConfigState } from '@/types'
|
||||
import {
|
||||
DEFAULT_PUBLIC_CONFIG,
|
||||
readNotifyKey,
|
||||
readStoredConfig,
|
||||
toPublicConfig,
|
||||
writeNotifyKey,
|
||||
writeStoredConfig,
|
||||
type PublicConfig
|
||||
} from '@/utils/config-storage'
|
||||
|
||||
export const useConfigStore = defineStore('config', () => {
|
||||
const config = ref<PublicConfig>({
|
||||
...DEFAULT_PUBLIC_CONFIG,
|
||||
...toPublicConfig(readStoredConfig<Partial<ConfigState>>())
|
||||
})
|
||||
|
||||
const uploadSizeLimit = computed(() => config.value.uploadSize)
|
||||
|
||||
const updateConfig = (nextConfig: Partial<ConfigState>) => {
|
||||
config.value = {
|
||||
...DEFAULT_PUBLIC_CONFIG,
|
||||
...config.value,
|
||||
...toPublicConfig(nextConfig)
|
||||
}
|
||||
writeStoredConfig(config.value)
|
||||
}
|
||||
|
||||
const applyRemoteConfig = (nextConfig: Partial<ConfigState>): string | null => {
|
||||
updateConfig(nextConfig)
|
||||
|
||||
const { notify_title: notifyTitle, notify_content: notifyContent } = nextConfig
|
||||
if (!notifyTitle || !notifyContent) {
|
||||
return null
|
||||
}
|
||||
|
||||
const notifyKey = notifyTitle + notifyContent
|
||||
if (readNotifyKey() === notifyKey) {
|
||||
return null
|
||||
}
|
||||
|
||||
writeNotifyKey(notifyKey)
|
||||
return `${notifyTitle}: ${notifyContent}`
|
||||
}
|
||||
|
||||
const reloadStoredConfig = () => {
|
||||
config.value = {
|
||||
...DEFAULT_PUBLIC_CONFIG,
|
||||
...toPublicConfig(readStoredConfig<Partial<ConfigState>>())
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
config,
|
||||
uploadSizeLimit,
|
||||
applyRemoteConfig,
|
||||
updateConfig,
|
||||
reloadStoredConfig
|
||||
}
|
||||
})
|
||||
+17
-252
@@ -1,197 +1,24 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import type { FileInfo, UploadProgress, UploadStatus } from '@/types'
|
||||
import { UPLOAD_STATUS } from '@/constants'
|
||||
import { ref } from 'vue'
|
||||
import type { ReceivedFileRecord, SentFileRecord } from '@/types'
|
||||
|
||||
export const useFileDataStore = defineStore('fileData', () => {
|
||||
// 上传相关状态
|
||||
const uploadStatus = ref<UploadStatus>(UPLOAD_STATUS.IDLE)
|
||||
const uploadProgress = ref<UploadProgress>({
|
||||
loaded: 0,
|
||||
total: 0,
|
||||
percentage: 0
|
||||
})
|
||||
const uploadedCode = ref('')
|
||||
const currentFile = ref<File | null>(null)
|
||||
|
||||
// 下载相关状态
|
||||
const downloadCode = ref('')
|
||||
const fileInfo = ref<FileInfo | null>(null)
|
||||
const isDownloading = ref(false)
|
||||
|
||||
// 文件列表状态(管理页面使用)
|
||||
const fileList = ref<FileInfo[]>([])
|
||||
const totalFiles = ref(0)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const isLoadingList = ref(false)
|
||||
|
||||
// 接收数据状态(取件记录)
|
||||
const receiveData = ref<Array<{
|
||||
id: number
|
||||
code: string
|
||||
filename: string
|
||||
size: string
|
||||
downloadUrl: string | null
|
||||
content: string | null
|
||||
date: string
|
||||
}>>([])
|
||||
|
||||
// 分享数据状态(发送记录)
|
||||
const shareData = ref<Array<{
|
||||
id: number
|
||||
filename: string
|
||||
date: string
|
||||
size: string
|
||||
expiration: string
|
||||
retrieveCode: string
|
||||
}>>([])
|
||||
|
||||
// 计算属性
|
||||
const isUploading = computed(() => uploadStatus.value === UPLOAD_STATUS.UPLOADING)
|
||||
const isUploadSuccess = computed(() => uploadStatus.value === UPLOAD_STATUS.SUCCESS)
|
||||
const isUploadError = computed(() => uploadStatus.value === UPLOAD_STATUS.ERROR)
|
||||
const hasFileInfo = computed(() => fileInfo.value !== null)
|
||||
const canDownload = computed(() => hasFileInfo.value && !isDownloading.value)
|
||||
|
||||
const totalPages = computed(() => {
|
||||
return Math.ceil(totalFiles.value / pageSize.value)
|
||||
})
|
||||
|
||||
// 上传相关方法
|
||||
const setUploadStatus = (status: UploadStatus) => {
|
||||
uploadStatus.value = status
|
||||
}
|
||||
|
||||
const setUploadProgress = (progress: UploadProgress) => {
|
||||
uploadProgress.value = progress
|
||||
}
|
||||
|
||||
const setUploadedCode = (code: string) => {
|
||||
uploadedCode.value = code
|
||||
}
|
||||
|
||||
const setCurrentFile = (file: File | null) => {
|
||||
currentFile.value = file
|
||||
}
|
||||
|
||||
const resetUpload = () => {
|
||||
uploadStatus.value = UPLOAD_STATUS.IDLE
|
||||
uploadProgress.value = {
|
||||
loaded: 0,
|
||||
total: 0,
|
||||
percentage: 0
|
||||
}
|
||||
uploadedCode.value = ''
|
||||
currentFile.value = null
|
||||
}
|
||||
|
||||
// 下载相关方法
|
||||
const setDownloadCode = (code: string) => {
|
||||
downloadCode.value = code
|
||||
}
|
||||
|
||||
const setFileInfo = (info: FileInfo | null) => {
|
||||
fileInfo.value = info
|
||||
}
|
||||
|
||||
const setDownloading = (loading: boolean) => {
|
||||
isDownloading.value = loading
|
||||
}
|
||||
|
||||
const resetDownload = () => {
|
||||
downloadCode.value = ''
|
||||
fileInfo.value = null
|
||||
isDownloading.value = false
|
||||
}
|
||||
|
||||
// 文件列表相关方法
|
||||
const setFileList = (files: FileInfo[]) => {
|
||||
fileList.value = files
|
||||
}
|
||||
|
||||
const addFile = (file: FileInfo) => {
|
||||
fileList.value.unshift(file)
|
||||
totalFiles.value += 1
|
||||
}
|
||||
|
||||
const removeFile = (fileId: string) => {
|
||||
const index = fileList.value.findIndex(file => file.id === fileId)
|
||||
if (index > -1) {
|
||||
fileList.value.splice(index, 1)
|
||||
totalFiles.value -= 1
|
||||
}
|
||||
}
|
||||
|
||||
const updateFile = (fileId: string, updates: Partial<FileInfo>) => {
|
||||
const index = fileList.value.findIndex(file => file.id === fileId)
|
||||
if (index > -1) {
|
||||
fileList.value[index] = { ...fileList.value[index], ...updates }
|
||||
}
|
||||
}
|
||||
|
||||
const setTotalFiles = (total: number) => {
|
||||
totalFiles.value = total
|
||||
}
|
||||
|
||||
const setCurrentPage = (page: number) => {
|
||||
currentPage.value = page
|
||||
}
|
||||
|
||||
const setPageSize = (size: number) => {
|
||||
pageSize.value = size
|
||||
}
|
||||
|
||||
const setLoadingList = (loading: boolean) => {
|
||||
isLoadingList.value = loading
|
||||
}
|
||||
|
||||
const resetFileList = () => {
|
||||
fileList.value = []
|
||||
totalFiles.value = 0
|
||||
currentPage.value = 1
|
||||
isLoadingList.value = false
|
||||
}
|
||||
const receiveData = ref<ReceivedFileRecord[]>([])
|
||||
const shareData = ref<SentFileRecord[]>([])
|
||||
|
||||
// 添加分享数据方法
|
||||
const addShareData = (data: { code: string; name?: string }) => {
|
||||
setUploadedCode(data.code)
|
||||
if (data.name) {
|
||||
// 如果有文件名,可以创建一个临时的 FileInfo 对象
|
||||
const fileInfo: FileInfo = {
|
||||
id: data.code,
|
||||
name: data.name,
|
||||
size: 0,
|
||||
type: '',
|
||||
uploadTime: new Date().toISOString(),
|
||||
downloadCount: 0
|
||||
}
|
||||
addFile(fileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// 接收数据相关方法
|
||||
const addReceiveData = (data: {
|
||||
id: number
|
||||
code: string
|
||||
filename: string
|
||||
size: string
|
||||
downloadUrl: string | null
|
||||
content: string | null
|
||||
date: string
|
||||
}) => {
|
||||
receiveData.value.push(data)
|
||||
const addReceiveData = (record: ReceivedFileRecord) => {
|
||||
receiveData.value.push(record)
|
||||
}
|
||||
|
||||
const removeReceiveData = (id: number) => {
|
||||
const index = receiveData.value.findIndex(item => item.id === id)
|
||||
if (index > -1) {
|
||||
const index = receiveData.value.findIndex((record) => record.id === id)
|
||||
if (index !== -1) {
|
||||
receiveData.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const deleteReceiveData = (index: number) => {
|
||||
if (index > -1 && index < receiveData.value.length) {
|
||||
if (index >= 0 && index < receiveData.value.length) {
|
||||
receiveData.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
@@ -199,90 +26,28 @@ export const useFileDataStore = defineStore('fileData', () => {
|
||||
const clearReceiveData = () => {
|
||||
receiveData.value = []
|
||||
}
|
||||
|
||||
// 分享数据相关方法
|
||||
const addShareDataRecord = (data: {
|
||||
id: number
|
||||
filename: string
|
||||
date: string
|
||||
size: string
|
||||
expiration: string
|
||||
retrieveCode: string
|
||||
}) => {
|
||||
shareData.value.push(data)
|
||||
|
||||
const addShareDataRecord = (record: SentFileRecord) => {
|
||||
shareData.value.push(record)
|
||||
}
|
||||
|
||||
|
||||
const deleteShareData = (index: number) => {
|
||||
if (index > -1 && index < shareData.value.length) {
|
||||
if (index >= 0 && index < shareData.value.length) {
|
||||
shareData.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const clearShareData = () => {
|
||||
shareData.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
// 上传状态
|
||||
uploadStatus,
|
||||
uploadProgress,
|
||||
uploadedCode,
|
||||
currentFile,
|
||||
|
||||
// 下载状态
|
||||
downloadCode,
|
||||
fileInfo,
|
||||
isDownloading,
|
||||
|
||||
// 文件列表状态
|
||||
fileList,
|
||||
totalFiles,
|
||||
currentPage,
|
||||
pageSize,
|
||||
isLoadingList,
|
||||
|
||||
// 计算属性
|
||||
isUploading,
|
||||
isUploadSuccess,
|
||||
isUploadError,
|
||||
hasFileInfo,
|
||||
canDownload,
|
||||
totalPages,
|
||||
|
||||
// 上传方法
|
||||
setUploadStatus,
|
||||
setUploadProgress,
|
||||
setUploadedCode,
|
||||
setCurrentFile,
|
||||
resetUpload,
|
||||
|
||||
// 下载方法
|
||||
setDownloadCode,
|
||||
setFileInfo,
|
||||
setDownloading,
|
||||
resetDownload,
|
||||
|
||||
// 文件列表方法
|
||||
setFileList,
|
||||
addFile,
|
||||
removeFile,
|
||||
updateFile,
|
||||
setTotalFiles,
|
||||
setCurrentPage,
|
||||
setPageSize,
|
||||
setLoadingList,
|
||||
resetFileList,
|
||||
addShareData,
|
||||
|
||||
// 接收数据状态和方法
|
||||
receiveData,
|
||||
shareData,
|
||||
addReceiveData,
|
||||
removeReceiveData,
|
||||
deleteReceiveData,
|
||||
clearReceiveData,
|
||||
|
||||
// 分享数据状态和方法
|
||||
shareData,
|
||||
addShareDataRecord,
|
||||
deleteShareData,
|
||||
clearShareData
|
||||
|
||||
Reference in New Issue
Block a user