仓库初始化+岗位相关页面

This commit is contained in:
2026-03-24 21:06:00 +08:00
commit 0468339d23
113 changed files with 18644 additions and 0 deletions
+210
View File
@@ -0,0 +1,210 @@
import { createStore } from 'vuex'
import type { Router } from 'vue-router'
import { fetchUserRoutes } from '@/api/menu'
import type { MenuItemRaw } from '@/api/menu'
import { buildDynamicRoutes } from '@/router/dynamicRoutes'
import { fetchIndustryTree, fetchJobCategoryTree, fetchRegionTree } from '@/api/common'
import type { IndustryItem, JobCategoryItem, RegionItem } from '@/api/common'
/** 职位列表页缓存数据(从详情页返回时恢复用) */
export interface JobListCache {
/** 缓存的职位列表 */
list: any[]
/** 当前已加载到的页码 */
pageNum: number
/** 总记录数 */
total: number
/** 列表滚动位置 */
scrollTop: number
}
export interface RootState {
appName: string
showLogin: boolean
loginRedirect: string
/**
* 登录状态 — 登录成功设为 true,退出成功设为 false
* 因为后端 Cookie 是 HttpOnly 的,前端 JS 无法读取,所以用内存状态管理
*/
isAuthenticated: boolean
/**
* 后端返回的原始菜单数据,SideNav 用它来渲染导航
*/
dynamicMenus: MenuItemRaw[]
/**
* 标记动态路由是否已经加载过,避免重复请求
* 每次登出时重置为 false
*/
routesLoaded: boolean
/**
* 记录已注册的动态路由 name,登出时用来逐个 removeRoute
*/
dynamicRouteNames: string[]
/**
* 行业树分类数据(一级二级嵌套)
* 由 /public/industries/tree 接口返回,进首页和 Jobs 页时刷新
* 其他页面/组件可直接从 store 读取
*/
industries: IndustryItem[]
/**
* 岗位树分类数据(一级二级三级嵌套)
* 由 /public/job-categories/tree 接口返回,进首页和 Jobs 页时刷新
* 其他页面/组件可直接从 store 读取
*/
jobCategories: JobCategoryItem[]
/**
* 地区树分类数据(省市区三级嵌套)
* 由 /public/regions/tree 接口返回,进首页和 Jobs 页时刷新
* 其他页面/组件可直接从 store 读取
*/
regions: RegionItem[]
/**
* 职位列表页缓存 — 从详情页返回时恢复列表和滚动位置
* 为 null 表示没有缓存,需要重新请求
*/
jobListCache: JobListCache | null
}
export default createStore<RootState>({
state: {
appName: 'JobAssistant',
showLogin: false,
loginRedirect: '',
isAuthenticated: sessionStorage.getItem('isAuthenticated') === 'true',
dynamicMenus: [],
routesLoaded: false,
dynamicRouteNames: [],
industries: [],
jobCategories: [],
regions: [],
jobListCache: null,
},
getters: {
getAppName: (state) => state.appName,
},
mutations: {
SET_APP_NAME(state, name: string) {
state.appName = name
},
SET_SHOW_LOGIN(state, show: boolean) {
state.showLogin = show
},
SET_LOGIN_REDIRECT(state, path: string) {
state.loginRedirect = path
},
SET_AUTHENTICATED(state, val: boolean) {
state.isAuthenticated = val
if (val) {
sessionStorage.setItem('isAuthenticated', 'true')
} else {
sessionStorage.removeItem('isAuthenticated')
}
},
SET_DYNAMIC_MENUS(state, menus: MenuItemRaw[]) {
state.dynamicMenus = menus
},
SET_ROUTES_LOADED(state, loaded: boolean) {
state.routesLoaded = loaded
},
SET_DYNAMIC_ROUTE_NAMES(state, names: string[]) {
state.dynamicRouteNames = names
},
SET_INDUSTRIES(state, data: IndustryItem[]) {
state.industries = data
},
SET_JOB_CATEGORIES(state, data: JobCategoryItem[]) {
state.jobCategories = data
},
SET_REGIONS(state, data: RegionItem[]) {
state.regions = data
},
SET_JOB_LIST_CACHE(state, cache: JobListCache | null) {
state.jobListCache = cache
},
},
actions: {
updateAppName({ commit }, name: string) {
commit('SET_APP_NAME', name)
},
openLogin({ commit }, redirect = '') {
commit('SET_LOGIN_REDIRECT', redirect)
commit('SET_SHOW_LOGIN', true)
},
closeLogin({ commit }) {
commit('SET_SHOW_LOGIN', false)
commit('SET_LOGIN_REDIRECT', '')
},
/**
* 核心 action:从后端(或 mock)拉取菜单,转成路由并注册
*
* @param router — vue-router 实例,由路由守卫调用时传入
*
* 流程:
* 1. 调 fetchUserRoutes 拿到后端菜单数据
* 2. 存到 state.dynamicMenus(给 SideNav 渲染用)
* 3. 用 buildDynamicRoutes 转成 RouteRecordRaw
* 4. 逐条 router.addRoute 注册
* 5. 记录已注册的路由名,标记 routesLoaded = true
*/
async loadDynamicRoutes({ commit }, router: Router) {
const menus = await fetchUserRoutes()
commit('SET_DYNAMIC_MENUS', menus)
const routes = buildDynamicRoutes(menus)
const names: string[] = []
for (const route of routes) {
router.addRoute(route)
if (route.name) names.push(route.name as string)
}
commit('SET_DYNAMIC_ROUTE_NAMES', names)
commit('SET_ROUTES_LOADED', true)
},
/**
* 登出:重置状态(不再操作 localStorage,登录状态由 Cookie 管理)
* 注意:动态路由不清除,与登录状态无关
*/
logout({ commit }) {
commit('SET_AUTHENTICATED', false)
commit('SET_SHOW_LOGIN', false)
commit('SET_LOGIN_REDIRECT', '')
},
/**
* 加载工具类公共数据(行业分类、岗位分类等)
* 进首页和 Jobs 页时调用,刷新全局数据
*/
async loadCommonData({ commit }) {
try {
const [industryRes, jobCategoryRes, regionRes] = await Promise.all([
fetchIndustryTree(),
fetchJobCategoryTree(),
fetchRegionTree(),
])
if (industryRes.code === '0' && industryRes.data) {
commit('SET_INDUSTRIES', industryRes.data)
}
if (jobCategoryRes.code === '0' && jobCategoryRes.data) {
commit('SET_JOB_CATEGORIES', jobCategoryRes.data)
}
if (regionRes.code === '0' && regionRes.data) {
commit('SET_REGIONS', regionRes.data)
}
} catch (err) {
console.error('[store] 加载公共分类数据失败', err)
}
},
},
modules: {},
})