8/15二次更新

hyx_brand
hyx 3 weeks ago
parent 9e8ce09450
commit 19862dc69d

@ -1,21 +1,32 @@
<template>
<el-container class="app-container">
<el-header>
<HeaderBar />
</el-header>
<el-main>
<router-view />
</el-main>
<el-footer>
<div class="footer-content">
<p>图书馆管理系统 &copy; {{ new Date().getFullYear() }}</p>
</div>
</el-footer>
</el-container>
<div v-if="sessionInitialized">
<el-container class="app-container">
<el-header>
<HeaderBar />
</el-header>
<el-main>
<router-view />
</el-main>
<el-footer>
<div class="footer-content">
<p>图书馆管理系统 &copy; {{ new Date().getFullYear() }}</p>
</div>
</el-footer>
</el-container>
</div>
<div v-else class="loading-container">
<el-loading-spinner />
<p>正在初始化...</p>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
import HeaderBar from './components/HeaderBar.vue'
const store = useStore()
const sessionInitialized = computed(() => store.state.sessionInitialized)
</script>
<style>
@ -42,4 +53,19 @@ import HeaderBar from './components/HeaderBar.vue'
max-width: 1200px;
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>

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

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

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

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

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

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

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

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

Loading…
Cancel
Save