370 lines
9.6 KiB
TypeScript
370 lines
9.6 KiB
TypeScript
import { readonly, ref } from 'vue'
|
|
import { useLocale } from '~/utils/locale'
|
|
import type { Semester } from '~/types'
|
|
|
|
// 全局事件总线用于学期更新通知
|
|
const semesterUpdateEvent = ref(0)
|
|
|
|
// SessionStorage 键名常量
|
|
const SELECTED_SEMESTER_KEY = 'voicehub_selected_semester'
|
|
const AVAILABLE_SEMESTERS_KEY = 'voicehub_available_semesters'
|
|
|
|
// 持久化工具函数
|
|
const persistenceUtils = {
|
|
// 保存选中的学期
|
|
saveSelectedSemester: (semester: string | null) => {
|
|
try {
|
|
if (semester) {
|
|
sessionStorage.setItem(SELECTED_SEMESTER_KEY, semester)
|
|
} else {
|
|
sessionStorage.removeItem(SELECTED_SEMESTER_KEY)
|
|
}
|
|
} catch (error) {
|
|
console.warn('保存选中学期失败:', error)
|
|
}
|
|
},
|
|
|
|
// 获取选中的学期
|
|
getSelectedSemester: (): string | null => {
|
|
try {
|
|
return sessionStorage.getItem(SELECTED_SEMESTER_KEY)
|
|
} catch (error) {
|
|
console.warn('获取选中学期失败:', error)
|
|
return null
|
|
}
|
|
},
|
|
|
|
// 保存可用学期列表
|
|
saveAvailableSemesters: (semesters: string[]) => {
|
|
try {
|
|
sessionStorage.setItem(AVAILABLE_SEMESTERS_KEY, JSON.stringify(semesters))
|
|
} catch (error) {
|
|
console.warn('保存可用学期列表失败:', error)
|
|
}
|
|
},
|
|
|
|
// 获取可用学期列表
|
|
getAvailableSemesters: (): string[] => {
|
|
try {
|
|
const stored = sessionStorage.getItem(AVAILABLE_SEMESTERS_KEY)
|
|
return stored ? JSON.parse(stored) : []
|
|
} catch (error) {
|
|
console.warn('获取可用学期列表失败:', error)
|
|
return []
|
|
}
|
|
},
|
|
|
|
// 清除所有持久化数据
|
|
clearAll: () => {
|
|
try {
|
|
sessionStorage.removeItem(SELECTED_SEMESTER_KEY)
|
|
sessionStorage.removeItem(AVAILABLE_SEMESTERS_KEY)
|
|
} catch (error) {
|
|
console.warn('清除持久化数据失败:', error)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function useSemesters() {
|
|
const { composableErrors } = useLocale()
|
|
const action = (key: keyof typeof composableErrors.value.actions) => composableErrors.value.actions[key]
|
|
const loginRequired = (key: keyof typeof composableErrors.value.actions) => composableErrors.value.loginRequired(action(key))
|
|
const failed = (key: keyof typeof composableErrors.value.actions) => composableErrors.value.failed(action(key))
|
|
const semesters = ref<Semester[]>([])
|
|
const currentSemester = ref<Semester | null>(null)
|
|
const loading = ref(false)
|
|
const error = ref('')
|
|
|
|
// 触发学期更新事件
|
|
const triggerSemesterUpdate = () => {
|
|
semesterUpdateEvent.value++
|
|
}
|
|
|
|
// 获取学期列表(管理员专用)
|
|
const fetchSemesters = async () => {
|
|
const { isAuthenticated, getAuthConfig } = useAuth()
|
|
|
|
if (!isAuthenticated.value) {
|
|
error.value = loginRequired('getSemesters')
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = ''
|
|
|
|
try {
|
|
const authConfig = getAuthConfig()
|
|
|
|
const response = await fetch('/api/admin/semesters', {
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
...authConfig
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}))
|
|
throw new Error(errorData.message || `${failed('getSemesters')}: ${response.status}`)
|
|
}
|
|
|
|
const data = await response.json()
|
|
semesters.value = data as Semester[]
|
|
} catch (err: any) {
|
|
error.value = err.message || failed('getSemesters')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 获取当前活跃学期
|
|
const fetchCurrentSemester = async () => {
|
|
try {
|
|
const response = await fetch('/api/semesters/current')
|
|
|
|
if (!response.ok) {
|
|
throw new Error(failed('getCurrentSemester'))
|
|
}
|
|
|
|
const data = await response.json()
|
|
currentSemester.value = data
|
|
} catch (err: any) {
|
|
console.error('获取当前学期失败:', err)
|
|
}
|
|
}
|
|
|
|
// 创建学期
|
|
const createSemester = async (semesterData: { name: string; isActive?: boolean }) => {
|
|
const { isAuthenticated, getAuthConfig } = useAuth()
|
|
const payload = {
|
|
...semesterData,
|
|
name: semesterData.name.trim()
|
|
}
|
|
|
|
if (!isAuthenticated.value) {
|
|
error.value = loginRequired('createSemester')
|
|
return null
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = ''
|
|
|
|
try {
|
|
const authConfig = getAuthConfig()
|
|
|
|
const response = await fetch('/api/admin/semesters', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(payload),
|
|
...authConfig
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}))
|
|
throw new Error(errorData.message || failed('createSemester'))
|
|
}
|
|
|
|
const data = await response.json()
|
|
|
|
// 更新学期列表
|
|
await fetchSemesters()
|
|
|
|
// 如果设置为活跃学期,也更新当前学期
|
|
if (payload.isActive) {
|
|
await fetchCurrentSemester()
|
|
}
|
|
|
|
// 触发全局学期更新事件
|
|
triggerSemesterUpdate()
|
|
|
|
return data
|
|
} catch (err: any) {
|
|
error.value = err.message || failed('createSemester')
|
|
return null
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 设置活跃学期
|
|
const setActiveSemester = async (semesterId: number) => {
|
|
const { isAuthenticated, getAuthConfig } = useAuth()
|
|
|
|
if (!isAuthenticated.value) {
|
|
error.value = loginRequired('setActiveSemester')
|
|
return false
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = ''
|
|
|
|
try {
|
|
const authConfig = getAuthConfig()
|
|
|
|
const response = await fetch('/api/admin/semesters/set-active', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ semesterId }),
|
|
...authConfig
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}))
|
|
throw new Error(errorData.message || failed('setActiveSemester'))
|
|
}
|
|
|
|
// 更新学期列表
|
|
await fetchSemesters()
|
|
await fetchCurrentSemester()
|
|
|
|
// 触发全局学期更新事件
|
|
triggerSemesterUpdate()
|
|
|
|
return true
|
|
} catch (err: any) {
|
|
error.value = err.message || failed('setActiveSemester')
|
|
return false
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 更新学期名称
|
|
const updateSemester = async (semesterId: number, semesterData: { name: string }) => {
|
|
const { isAuthenticated, getAuthConfig } = useAuth()
|
|
const payload = {
|
|
...semesterData,
|
|
name: semesterData.name.trim()
|
|
}
|
|
|
|
if (!isAuthenticated.value) {
|
|
error.value = loginRequired('updateSemester')
|
|
return false
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = ''
|
|
|
|
try {
|
|
const authConfig = getAuthConfig()
|
|
|
|
const response = await fetch(`/api/admin/semesters/${semesterId}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(payload),
|
|
...authConfig
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}))
|
|
throw new Error(errorData.message || failed('updateSemester'))
|
|
}
|
|
|
|
// 更新学期列表
|
|
await fetchSemesters()
|
|
|
|
// 如果更新的是当前学期,需要刷新当前学期数据
|
|
if (currentSemester.value?.id === semesterId) {
|
|
await fetchCurrentSemester()
|
|
}
|
|
|
|
// 触发全局学期更新事件
|
|
triggerSemesterUpdate()
|
|
|
|
return true
|
|
} catch (err: any) {
|
|
error.value = err.message || failed('updateSemester')
|
|
return false
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 删除学期
|
|
const deleteSemester = async (semesterId: number) => {
|
|
const { isAuthenticated, getAuthConfig } = useAuth()
|
|
|
|
if (!isAuthenticated.value) {
|
|
error.value = loginRequired('deleteSemester')
|
|
return false
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = ''
|
|
|
|
try {
|
|
const authConfig = getAuthConfig()
|
|
|
|
const response = await fetch(`/api/admin/semesters/${semesterId}`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
...authConfig
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}))
|
|
throw new Error(errorData.message || failed('deleteSemester'))
|
|
}
|
|
|
|
// 更新学期列表
|
|
await fetchSemesters()
|
|
|
|
// 触发全局学期更新事件
|
|
triggerSemesterUpdate()
|
|
|
|
return true
|
|
} catch (err: any) {
|
|
error.value = err.message || failed('deleteSemester')
|
|
return false
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 获取所有学期选项
|
|
const fetchSemesterOptions = async () => {
|
|
loading.value = true
|
|
error.value = ''
|
|
try {
|
|
const response = await fetch('/api/semesters/options')
|
|
if (!response.ok) {
|
|
throw new Error(failed('getSemesterOptions'))
|
|
}
|
|
const data = await response.json()
|
|
if (data.success) {
|
|
semesters.value = data.data
|
|
}
|
|
} catch (err: any) {
|
|
console.error('获取学期选项失败:', err)
|
|
error.value = err.message || failed('getSemesterOptions')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
semesters: readonly(semesters),
|
|
currentSemester: readonly(currentSemester),
|
|
loading: readonly(loading),
|
|
error: readonly(error),
|
|
semesterUpdateEvent: readonly(semesterUpdateEvent),
|
|
fetchSemesters,
|
|
fetchCurrentSemester,
|
|
fetchSemesterOptions,
|
|
createSemester,
|
|
setActiveSemester,
|
|
updateSemester,
|
|
deleteSemester,
|
|
triggerSemesterUpdate,
|
|
// 导出持久化工具函数
|
|
persistenceUtils
|
|
}
|
|
}
|