feat: add SingleRecordMnt component for student record maintenance with search, add, edit, view, and delete functionalities

This commit is contained in:
skytek_xinliang
2026-03-26 11:24:37 +08:00
parent 507afcc99c
commit 069141794e
116 changed files with 15247 additions and 107 deletions
+83
View File
@@ -0,0 +1,83 @@
import { ref } from 'vue'
import { type ApiRequestError, normalizeError } from '@/services/error'
import { useSnackbarStore } from '@/stores/snackbar'
type ToastLevel = 'info' | 'warning' | 'error'
type Options = {
showErrorToast?: boolean
errorToastLevel?: (error: ApiRequestError) => ToastLevel
}
function getDefaultToastLevel (error: ApiRequestError): ToastLevel {
if (typeof error.status === 'number' && error.status >= 500) return 'error'
return 'warning'
}
function levelToColor (level: ToastLevel): string {
if (level === 'error') return 'error'
if (level === 'warning') return 'warning'
return 'info'
}
export function useApiCall <TResult, TArgs extends unknown[]>(action: (...args: TArgs) => Promise<TResult>,
options?: Options) {
const loading = ref(false)
const data = ref<TResult | null>(null)
const error = ref<ApiRequestError | null>(null)
const snackbar = useSnackbarStore()
const execute = async (...args: TArgs): Promise<TResult> => {
loading.value = true
error.value = null
try {
const result = await action(...args)
data.value = result
return result
} catch (error_) {
const normalized = normalizeError(error_)
error.value = normalized
const showErrorToast = options?.showErrorToast ?? true
if (showErrorToast && normalized.name !== 'CanceledRequestError') {
const level = (options?.errorToastLevel ?? getDefaultToastLevel)(normalized)
snackbar.show({
message: normalized.message,
color: levelToColor(level),
timeout: 3000,
location: 'top right',
variant: 'flat',
})
}
throw normalized
} finally {
loading.value = false
}
}
const executeSafe = async (...args: TArgs): Promise<TResult | null> => {
try {
return await execute(...args)
} catch {
return null
}
}
const reset = () => {
loading.value = false
data.value = null
error.value = null
}
return {
loading,
data,
error,
execute,
executeSafe,
reset,
}
}