feat: align with upstream 1.5.9.9
This commit is contained in:
@@ -0,0 +1,369 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user