8/15二次更新

hyx_brand
hyx 4 weeks ago
parent 9e8ce09450
commit 19862dc69d

@ -1,4 +1,5 @@
<template> <template>
<div v-if="sessionInitialized">
<el-container class="app-container"> <el-container class="app-container">
<el-header> <el-header>
<HeaderBar /> <HeaderBar />
@ -12,10 +13,20 @@
</div> </div>
</el-footer> </el-footer>
</el-container> </el-container>
</div>
<div v-else class="loading-container">
<el-loading-spinner />
<p>正在初始化...</p>
</div>
</template> </template>
<script setup> <script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
import HeaderBar from './components/HeaderBar.vue' import HeaderBar from './components/HeaderBar.vue'
const store = useStore()
const sessionInitialized = computed(() => store.state.sessionInitialized)
</script> </script>
<style> <style>
@ -42,4 +53,19 @@ import HeaderBar from './components/HeaderBar.vue'
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
} }
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f5f7fa;
}
.loading-container p {
margin-top: 20px;
color: #606266;
font-size: 16px;
}
</style> </style>

@ -22,10 +22,10 @@
<el-menu-item index="weekly">本周热租榜</el-menu-item> <el-menu-item index="weekly">本周热租榜</el-menu-item>
<el-menu-item index="monthly">本月热租榜</el-menu-item> <el-menu-item index="monthly">本月热租榜</el-menu-item>
</el-sub-menu> </el-sub-menu>
<el-menu-item index="bookManagement" v-if="isAdmin"> <el-menu-item index="bookManagement" v-if="user && user.admin">
图书管理 图书管理
</el-menu-item> </el-menu-item>
<el-menu-item index="allBorrowRecords" v-if="isAdmin"> <el-menu-item index="allBorrowRecords" v-if="user && user.admin">
用户借阅记录 用户借阅记录
</el-menu-item> </el-menu-item>
</el-menu> </el-menu>
@ -72,15 +72,22 @@ import { useStore } from 'vuex'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Reading, ArrowDown } from '@element-plus/icons-vue' import { Reading, ArrowDown } from '@element-plus/icons-vue'
import { Wallet } from '@element-plus/icons-vue' import { Wallet } from '@element-plus/icons-vue'
import { computed, onMounted } from 'vue' import { computed, onMounted, watch } from 'vue'
const store = useStore() const store = useStore()
const router = useRouter() const router = useRouter()
onMounted(async () => { onMounted(async () => {
// //
if (store.getters.isAuthenticated) { if (store.state.sessionInitialized && store.getters.isAuthenticated) {
await fetchUserInfo()
}
})
//
watch(() => store.state.sessionInitialized, async (newVal) => {
if (newVal && store.getters.isAuthenticated) {
await fetchUserInfo() await fetchUserInfo()
} }
}) })
@ -88,7 +95,7 @@ onMounted(async () => {
// //
async function fetchUserInfo() { async function fetchUserInfo() {
try { try {
// VIP // VIP
await store.dispatch('fetchBalanceAndVip') await store.dispatch('fetchBalanceAndVip')
} catch (error) { } catch (error) {
console.error('获取用户信息失败:', error) console.error('获取用户信息失败:', error)
@ -103,8 +110,6 @@ async function fetchUserInfo() {
const vip = computed(() => store.state.vipLevel) const vip = computed(() => store.state.vipLevel)
const balance = computed(() => store.state.balance) const balance = computed(() => store.state.balance)
const user = computed(() => store.state.user) const user = computed(() => store.state.user)
const isAdmin = computed(() => store.getters.isAdmin)

@ -17,6 +17,9 @@ app.use(ElementPlus)
app.use(store) app.use(store)
app.use(router) app.use(router)
// 初始化会话
store.dispatch('initSession')
app.mount('#app') app.mount('#app')
window.store = store window.store = store

@ -102,6 +102,11 @@ const router = createRouter({
// 路由守卫 // 路由守卫
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
// 等待会话初始化完成
if (!store.state.sessionInitialized) {
return next()
}
const isAuthenticated = store.getters.isAuthenticated const isAuthenticated = store.getters.isAuthenticated
const isAdmin = store.getters.isAdmin const isAdmin = store.getters.isAdmin

@ -6,7 +6,8 @@ export default createStore({
user: JSON.parse(sessionStorage.getItem('user')) || null, user: JSON.parse(sessionStorage.getItem('user')) || null,
balance: JSON.parse(sessionStorage.getItem('balance')) || 0, balance: JSON.parse(sessionStorage.getItem('balance')) || 0,
vipLevel: JSON.parse(sessionStorage.getItem('vipLevel')) || 0, vipLevel: JSON.parse(sessionStorage.getItem('vipLevel')) || 0,
borrowedBooks: JSON.parse(sessionStorage.getItem('borrowedBooks')) || [] borrowedBooks: JSON.parse(sessionStorage.getItem('borrowedBooks')) || [],
sessionInitialized: false
}, },
getters: { getters: {
isAuthenticated: state => !!state.user, isAuthenticated: state => !!state.user,
@ -14,6 +15,12 @@ export default createStore({
}, },
mutations: { mutations: {
setUser(state, user) { setUser(state, user) {
const admin = user.admin === 1;
const userData = {
...user,
admin
};
state.user = user state.user = user
sessionStorage.setItem('user', JSON.stringify(user)) sessionStorage.setItem('user', JSON.stringify(user))
}, },
@ -53,18 +60,31 @@ export default createStore({
}) })
if (userData && userData.username) { if (userData && userData.username) {
const admin = userData.admin === 1;
commit('setUser', { commit('setUser', {
username: userData.username, username: userData.username,
pic: userData.pic || '', pic: userData.pic || '',
admin: userData.admin || false admin
}) })
// 获取关联信息 // 获取关联信息
try {
await dispatch('fetchBalanceAndVip') await dispatch('fetchBalanceAndVip')
} catch (balanceError) {
console.warn('获取余额信息失败:', balanceError)
}
try {
await dispatch('fetchBorrowedBooks') await dispatch('fetchBorrowedBooks')
} catch (booksError) {
console.warn('获取借阅书籍失败:', booksError)
}
} }
} catch (error) { } catch (error) {
console.log('未检测到有效会话') console.log('未检测到有效会话,用户需要重新登录')
// 清除可能存在的无效数据
commit('clearUser')
} finally { } finally {
commit('setSessionInitialized', true) commit('setSessionInitialized', true)
} }
@ -100,12 +120,12 @@ export default createStore({
async fetchUser({ commit, dispatch }) { async fetchUser({ commit, dispatch }) {
try { try {
const userData = await service.get('/user/getinfo') const userData = await service.get('/user/getinfo')
const admin = userData.admin === 1;
// 用户信息接口直接返回用户对象 // 用户信息接口直接返回用户对象
commit('setUser', { commit('setUser', {
username: userData.username || '', username: userData.username || '',
pic: userData.pic || '', pic: userData.pic || '',
admin: userData.admin || false admin
}) })
// 获取关联信息 // 获取关联信息
@ -128,29 +148,25 @@ export default createStore({
} }
}, },
// 获取余额和VIP等级 // 获取余额和VIP等级 - 符合接口文档1.5
async fetchBalanceAndVip({ commit }) { async fetchBalanceAndVip({ commit }) {
try { try {
const response = await service.post('/user/findmoney') const response = await service.post('/user/findmoney')
const resData = response.data || {} const resData = response.data || {}
// 正确解析响应数据
if (resData.code === 200) { if (resData.code === 200) {
const message = resData.message || '' const message = resData.message || ''
const balanceMatch = message.match(/余额为:(\d+\.\d+)元/) // 使用正则表达式解析余额和VIP等级
const balanceMatch = message.match(/余额为:(\d+\.?\d*)元/)
const vipMatch = message.match(/当前VIP等级为(\d+)/) const vipMatch = message.match(/当前VIP等级为(\d+)/)
if (balanceMatch && vipMatch) { if (balanceMatch && vipMatch) {
commit('setBalanceAndVip', { const balance = parseFloat(balanceMatch[1])
balance: parseFloat(balanceMatch[1]), const vip = parseInt(vipMatch[1])
vip: parseInt(vipMatch[1])
})
} else {
// 尝试从其他字段获取
const balance = parseFloat(resData.balance) || 0
const vip = parseInt(resData.vipLevel) || 0
commit('setBalanceAndVip', { balance, vip }) commit('setBalanceAndVip', { balance, vip })
} else {
console.warn('无法解析余额或VIP信息:', message)
commit('setBalanceAndVip', { balance: 0, vip: 0 })
} }
} else { } else {
throw new Error(resData.message || '获取余额信息失败') throw new Error(resData.message || '获取余额信息失败')
@ -159,7 +175,8 @@ export default createStore({
return resData return resData
} catch (error) { } catch (error) {
console.error('获取余额失败:', error) console.error('获取余额失败:', error)
throw error // 不抛出错误,避免影响其他功能
return { code: 500, message: '获取余额失败' }
} }
}, },
@ -214,16 +231,22 @@ async borrowBook({ dispatch }, { title }) {
return response.data return response.data
}, },
// 归还书籍 // 归还书籍 - 符合接口文档3.2
async returnBook({ dispatch }, { title }) { async returnBook({ dispatch }, { title }) {
try {
const response = await service.post('/borrow/returnbook', const response = await service.post('/borrow/returnbook',
`title=${encodeURIComponent(title)}`, `title=${encodeURIComponent(title)}`,
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
) )
// 还书后刷新用户信息 // 还书成功后刷新借阅书籍列表
await dispatch('fetchUser') await dispatch('fetchBorrowedBooks')
return response.data return response.data
} catch (error) {
console.error('还书失败:', error)
throw error
}
}, },
// 查询全部书籍 - 符合接口文档 // 查询全部书籍 - 符合接口文档
@ -265,7 +288,7 @@ async returnBook({ dispatch }, { title }) {
} }
}, },
// 根据书名查单本书 - 符合接口文档 // 根据书名查单本书 - 符合接口文档2.3
async fetchBookByTitle(_, payload) { async fetchBookByTitle(_, payload) {
const { title } = payload; const { title } = payload;

@ -29,7 +29,10 @@ service.interceptors.response.use(
// 处理业务错误 (code !== 200) // 处理业务错误 (code !== 200)
if (res && typeof res === 'object' && res.code !== undefined && res.code !== 200) { if (res && typeof res === 'object' && res.code !== undefined && res.code !== 200) {
// 检查是否为静默请求
if (!response.config.silent) {
ElMessage.error(res.message || '请求失败') ElMessage.error(res.message || '请求失败')
}
return Promise.reject(new Error(res.message || 'Error')) return Promise.reject(new Error(res.message || 'Error'))
} }
@ -41,19 +44,28 @@ service.interceptors.response.use(
if (error.response) { if (error.response) {
switch (error.response.status) { switch (error.response.status) {
case 401: case 401:
// 只有在非静默请求时才显示错误信息
if (!error.config?.silent) {
store.dispatch('logout') store.dispatch('logout')
router.push('/login') router.push('/login')
ElMessage.error('请先登录') ElMessage.error('请先登录')
}
break break
case 403: case 403:
if (!error.config?.silent) {
ElMessage.error('没有操作权限') ElMessage.error('没有操作权限')
}
break break
default: default:
if (!error.config?.silent) {
ElMessage.error(error.response.data?.message || '请求失败') ElMessage.error(error.response.data?.message || '请求失败')
} }
}
} else { } else {
if (!error.config?.silent) {
ElMessage.error('网络错误,请检查连接') ElMessage.error('网络错误,请检查连接')
} }
}
return Promise.reject(error) return Promise.reject(error)
} }
) )

@ -69,20 +69,49 @@ const rules = ref({
const loginForm = ref(null) const loginForm = ref(null)
const loading = ref(false) const loading = ref(false)
// const login = async () => {
// try {
// await loginForm.value.validate()
// loading.value = true
// await store.dispatch('login', form.value)
// ElMessage.success('')
// //
// await store.dispatch('fetchUser')
// // localStorage
// const userInfo = store.state.user
// localStorage.setItem('userInfo', JSON.stringify(userInfo))
// //
// router.push('/')
// } catch (error) {
// console.error(':', error)
// ElMessage.error(error.message || '')
// } finally {
// loading.value = false
// }
// }
const login = async () => { const login = async () => {
try { try {
//
await loginForm.value.validate() await loginForm.value.validate()
loading.value = true loading.value = true
await store.dispatch('login', form.value) // action
ElMessage.success('登录成功') const response = await store.dispatch('login', form.value)
// //
await store.dispatch('fetchUser') const userInfo = response.user
// localStorage
const userInfo = store.state.user // admin
localStorage.setItem('userInfo', JSON.stringify(userInfo)) store.commit('setUser', {
// ...userInfo,
admin: userInfo.admin === 1 // 1/0 true/false
})
ElMessage.success('登录成功')
router.push('/') router.push('/')
} catch (error) { } catch (error) {
console.error('登录失败:', error) console.error('登录失败:', error)

@ -73,11 +73,8 @@ const fetchBook = async () => {
// //
const response = await store.dispatch('fetchBookByTitle', { title }) const response = await store.dispatch('fetchBookByTitle', { title })
// API // 2.3
if (response.data && response.data.code === 200) { if (response.data) {
book.value = response.data.data
} else if (response.data) {
// code
book.value = response.data book.value = response.data
} else { } else {
throw new Error('书籍不存在') throw new Error('书籍不存在')

@ -73,16 +73,17 @@
try { try {
const response = await store.dispatch('returnBook', { title: book.title }) const response = await store.dispatch('returnBook', { title: book.title })
// if (response.code === 200) {
const returnTime = response.data?.return_time || new Date().toISOString() ElMessage.success(`${book.title}》归还成功`)
// //
store.commit('removeBorrowedBook', book.title) store.commit('removeBorrowedBook', book.title)
ElMessage.success(`${book.title}》归还成功`) //
await fetchBorrowedBooks()
// } else {
await store.dispatch('fetchBorrowedBooks') ElMessage.error(response.message || '归还失败')
}
} catch (error) { } catch (error) {
console.error('归还失败:', error) console.error('归还失败:', error)
ElMessage.error(error.message || '归还失败') ElMessage.error(error.message || '归还失败')

Loading…
Cancel
Save