feat: 基础数据前端缓存 - 使用 Pinia Store 实现
- 新建 baseData Store,缓存年级/学科/区域/班级数据 - 支持 localStorage 持久化,24小时过期 - 编辑/删除操作自动清除对应缓存 - 修改四个管理页面(grade/subject/region/class)使用 Store
This commit is contained in:
parent
bf67282825
commit
124013703f
|
|
@ -0,0 +1,200 @@
|
||||||
|
/**
|
||||||
|
* 基础数据 Store
|
||||||
|
* 缓存年级、学科、区域、班级等基础数据
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
const STORAGE_KEY = 'pguser:baseData'
|
||||||
|
const CACHE_EXPIRE = 24 * 60 * 60 * 1000 // 24小时
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 localStorage 恢复数据
|
||||||
|
*/
|
||||||
|
const loadFromStorage = () => {
|
||||||
|
try {
|
||||||
|
const data = localStorage.getItem(STORAGE_KEY)
|
||||||
|
if (data) {
|
||||||
|
const parsed = JSON.parse(data)
|
||||||
|
// 检查是否过期
|
||||||
|
if (parsed.expire && Date.now() < parsed.expire) {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载缓存失败:', e)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存到 localStorage
|
||||||
|
*/
|
||||||
|
const saveToStorage = (state) => {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
grades: state.grades,
|
||||||
|
subjects: state.subjects,
|
||||||
|
regionTree: state.regionTree,
|
||||||
|
classes: state.classes,
|
||||||
|
expire: Date.now() + CACHE_EXPIRE,
|
||||||
|
updateTime: new Date().toISOString()
|
||||||
|
}
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data))
|
||||||
|
} catch (e) {
|
||||||
|
console.error('保存缓存失败:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const useBaseDataStore = defineStore('baseData', {
|
||||||
|
state: () => {
|
||||||
|
const cached = loadFromStorage()
|
||||||
|
return {
|
||||||
|
grades: cached?.grades || [], // 年级列表
|
||||||
|
subjects: cached?.subjects || [], // 学科列表
|
||||||
|
regionTree: cached?.regionTree || [], // 区域树
|
||||||
|
classes: cached?.classes || [], // 班级列表
|
||||||
|
loading: {
|
||||||
|
grades: false,
|
||||||
|
subjects: false,
|
||||||
|
regionTree: false,
|
||||||
|
classes: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getters: {
|
||||||
|
// 年级选项(用于下拉)
|
||||||
|
gradeOptions: (state) => state.grades.map(g => ({ label: g.gradeName, value: g.gradeId })),
|
||||||
|
// 学科选项(用于下拉)
|
||||||
|
subjectOptions: (state) => state.subjects.map(s => ({ label: s.subjectName, value: s.subjectId })),
|
||||||
|
// 班级选项(用于下拉)
|
||||||
|
classOptions: (state) => state.classes.map(c => ({ label: c.className, value: c.classId }))
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
// ==================== 年级 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取年级列表(带缓存)
|
||||||
|
* @param {boolean} force 是否强制刷新
|
||||||
|
*/
|
||||||
|
async fetchGrades(force = false) {
|
||||||
|
if (!force && this.grades.length > 0) {
|
||||||
|
return this.grades
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading.grades = true
|
||||||
|
try {
|
||||||
|
const res = await request.get('/business/grade/listAll')
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.grades = res.data || []
|
||||||
|
saveToStorage(this)
|
||||||
|
}
|
||||||
|
return this.grades
|
||||||
|
} finally {
|
||||||
|
this.loading.grades = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除年级缓存
|
||||||
|
*/
|
||||||
|
clearGrades() {
|
||||||
|
this.grades = []
|
||||||
|
saveToStorage(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 学科 ====================
|
||||||
|
|
||||||
|
async fetchSubjects(force = false) {
|
||||||
|
if (!force && this.subjects.length > 0) {
|
||||||
|
return this.subjects
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading.subjects = true
|
||||||
|
try {
|
||||||
|
const res = await request.get('/business/subject/listAll')
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.subjects = res.data || []
|
||||||
|
saveToStorage(this)
|
||||||
|
}
|
||||||
|
return this.subjects
|
||||||
|
} finally {
|
||||||
|
this.loading.subjects = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearSubjects() {
|
||||||
|
this.subjects = []
|
||||||
|
saveToStorage(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 区域 ====================
|
||||||
|
|
||||||
|
async fetchRegionTree(force = false) {
|
||||||
|
if (!force && this.regionTree.length > 0) {
|
||||||
|
return this.regionTree
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading.regionTree = true
|
||||||
|
try {
|
||||||
|
const res = await request.get('/business/region/tree')
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.regionTree = res.data || []
|
||||||
|
saveToStorage(this)
|
||||||
|
}
|
||||||
|
return this.regionTree
|
||||||
|
} finally {
|
||||||
|
this.loading.regionTree = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearRegionTree() {
|
||||||
|
this.regionTree = []
|
||||||
|
saveToStorage(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 班级 ====================
|
||||||
|
|
||||||
|
async fetchClasses(force = false) {
|
||||||
|
if (!force && this.classes.length > 0) {
|
||||||
|
return this.classes
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading.classes = true
|
||||||
|
try {
|
||||||
|
const res = await request.get('/business/class/listAll')
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.classes = res.data || []
|
||||||
|
saveToStorage(this)
|
||||||
|
}
|
||||||
|
return this.classes
|
||||||
|
} finally {
|
||||||
|
this.loading.classes = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearClasses() {
|
||||||
|
this.classes = []
|
||||||
|
saveToStorage(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 通用 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除所有缓存
|
||||||
|
*/
|
||||||
|
clearAll() {
|
||||||
|
this.grades = []
|
||||||
|
this.subjects = []
|
||||||
|
this.regionTree = []
|
||||||
|
this.classes = []
|
||||||
|
localStorage.removeItem(STORAGE_KEY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default useBaseDataStore
|
||||||
|
|
@ -93,6 +93,9 @@ import { Delete, Edit, Plus, Refresh, Search } from '@element-plus/icons-vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import useBaseDataStore from '@/store/modules/baseData'
|
||||||
|
|
||||||
|
const baseDataStore = useBaseDataStore()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -169,6 +172,7 @@ const handleSubmit = async () => {
|
||||||
? await request.put('/business/class', form.value)
|
? await request.put('/business/class', form.value)
|
||||||
: await request.post('/business/class', form.value)
|
: await request.post('/business/class', form.value)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearClasses() // 清除班级缓存
|
||||||
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
getList()
|
getList()
|
||||||
|
|
@ -184,6 +188,7 @@ const handleDelete = (row) => {
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
const res = await request.delete(`/business/class/${row.classId}`)
|
const res = await request.delete(`/business/class/${row.classId}`)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearClasses() // 清除班级缓存
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,9 @@ import { Delete, Edit, Plus, Refresh, Search } from '@element-plus/icons-vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import useBaseDataStore from '@/store/modules/baseData'
|
||||||
|
|
||||||
|
const baseDataStore = useBaseDataStore()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -169,6 +172,7 @@ const handleSubmit = async () => {
|
||||||
? await request.put('/business/grade', form.value)
|
? await request.put('/business/grade', form.value)
|
||||||
: await request.post('/business/grade', form.value)
|
: await request.post('/business/grade', form.value)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearGrades() // 清除年级缓存
|
||||||
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
getList()
|
getList()
|
||||||
|
|
@ -184,6 +188,7 @@ const handleDelete = (row) => {
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
const res = await request.delete(`/business/grade/${row.gradeId}`)
|
const res = await request.delete(`/business/grade/${row.gradeId}`)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearGrades() // 清除年级缓存
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,9 @@ import { Delete, Edit, Plus, Refresh, Search, Sort } from '@element-plus/icons-v
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { nextTick, onMounted, ref } from 'vue'
|
import { nextTick, onMounted, ref } from 'vue'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import useBaseDataStore from '@/store/modules/baseData'
|
||||||
|
|
||||||
|
const baseDataStore = useBaseDataStore()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -220,6 +223,7 @@ const handleSubmit = async () => {
|
||||||
? await request.put('/business/region', form.value)
|
? await request.put('/business/region', form.value)
|
||||||
: await request.post('/business/region', form.value)
|
: await request.post('/business/region', form.value)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearRegionTree() // 清除区域缓存
|
||||||
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
getList()
|
getList()
|
||||||
|
|
@ -235,6 +239,7 @@ const handleDelete = (row) => {
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
const res = await request.delete(`/business/region/${row.regionId}`)
|
const res = await request.delete(`/business/region/${row.regionId}`)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearRegionTree() // 清除区域缓存
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,9 @@ import { Delete, Edit, Plus, Refresh, Search } from '@element-plus/icons-vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import useBaseDataStore from '@/store/modules/baseData'
|
||||||
|
|
||||||
|
const baseDataStore = useBaseDataStore()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -169,6 +172,7 @@ const handleSubmit = async () => {
|
||||||
? await request.put('/business/subject', form.value)
|
? await request.put('/business/subject', form.value)
|
||||||
: await request.post('/business/subject', form.value)
|
: await request.post('/business/subject', form.value)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearSubjects() // 清除学科缓存
|
||||||
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
getList()
|
getList()
|
||||||
|
|
@ -184,6 +188,7 @@ const handleDelete = (row) => {
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
const res = await request.delete(`/business/subject/${row.subjectId}`)
|
const res = await request.delete(`/business/subject/${row.subjectId}`)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
baseDataStore.clearSubjects() // 清除学科缓存
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue