hyx_brand
hyx 2 months ago
parent 19862dc69d
commit 6afa988017

@ -15,7 +15,7 @@
</el-container> </el-container>
</div> </div>
<div v-else class="loading-container"> <div v-else class="loading-container">
<el-loading-spinner /> <el-icon class="is-loading"><Loading /></el-icon>
<p>正在初始化...</p> <p>正在初始化...</p>
</div> </div>
</template> </template>
@ -23,6 +23,7 @@
<script setup> <script setup>
import { computed } from 'vue' import { computed } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { Loading } from '@element-plus/icons-vue'
import HeaderBar from './components/HeaderBar.vue' import HeaderBar from './components/HeaderBar.vue'
const store = useStore() const store = useStore()

@ -92,6 +92,13 @@ watch(() => store.state.sessionInitialized, async (newVal) => {
} }
}) })
//
watch(() => store.getters.isAuthenticated, async (newVal) => {
if (newVal && store.state.sessionInitialized) {
await fetchUserInfo()
}
})
// //
async function fetchUserInfo() { async function fetchUserInfo() {
try { try {

@ -17,9 +17,17 @@ app.use(ElementPlus)
app.use(store) app.use(store)
app.use(router) app.use(router)
// 初始化会话 // 初始化会话并挂载应用
store.dispatch('initSession') async function initializeApp() {
try {
await store.dispatch('initSession')
} catch (error) {
console.error('会话初始化失败:', error)
} finally {
app.mount('#app')
}
}
app.mount('#app') initializeApp()
window.store = store window.store = store

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

@ -1,12 +1,13 @@
import { createStore } from 'vuex' import { createStore } from 'vuex'
import service from '../utils/request' import service from '../utils/request'
import { safeGetItem, safeSetItem, safeRemoveItem } from '../utils/storage'
export default createStore({ export default createStore({
state: { state: {
user: JSON.parse(sessionStorage.getItem('user')) || null, user: safeGetItem('user', null),
balance: JSON.parse(sessionStorage.getItem('balance')) || 0, balance: safeGetItem('balance', 0),
vipLevel: JSON.parse(sessionStorage.getItem('vipLevel')) || 0, vipLevel: safeGetItem('vipLevel', 0),
borrowedBooks: JSON.parse(sessionStorage.getItem('borrowedBooks')) || [], borrowedBooks: safeGetItem('borrowedBooks', []),
sessionInitialized: false sessionInitialized: false
}, },
getters: { getters: {
@ -14,71 +15,115 @@ export default createStore({
isAdmin: state => state.user?.admin || false isAdmin: state => state.user?.admin || false
}, },
mutations: { mutations: {
setUser(state, user) { setUser(state, user) {
const admin = user.admin === 1; const admin = user.admin === 1;
const userData = { const userData = {
...user, ...user,
admin admin
}; };
state.user = user state.user = userData
sessionStorage.setItem('user', JSON.stringify(user)) safeSetItem('user', userData)
}, },
setBalanceAndVip(state, { balance, vip }) { setBalanceAndVip(state, { balance, vip }) {
state.balance = balance state.balance = balance
state.vipLevel = vip state.vipLevel = vip
sessionStorage.setItem('balance', JSON.stringify(balance)) safeSetItem('balance', balance)
sessionStorage.setItem('vipLevel', JSON.stringify(vip)) safeSetItem('vipLevel', vip)
}, },
setBorrowedBooks(state, books) { setBorrowedBooks(state, books) {
state.borrowedBooks = books state.borrowedBooks = books
sessionStorage.setItem('borrowedBooks', JSON.stringify(books)) safeSetItem('borrowedBooks', books)
}, },
clearUser(state) { clearUser(state) {
state.user = null state.user = null
state.balance = 0 state.balance = 0
state.vipLevel = 0 state.vipLevel = 0
state.borrowedBooks = [] state.borrowedBooks = []
sessionStorage.removeItem('user') safeRemoveItem('user')
sessionStorage.removeItem('balance') safeRemoveItem('balance')
sessionStorage.removeItem('vipLevel') safeRemoveItem('vipLevel')
sessionStorage.removeItem('borrowedBooks') safeRemoveItem('borrowedBooks')
// 不清除sessionInitialized保持应用状态
}, },
removeBorrowedBook(state, title) { removeBorrowedBook(state, title) {
state.borrowedBooks = state.borrowedBooks.filter(book => book.title !== title) state.borrowedBooks = state.borrowedBooks.filter(book => book.title !== title)
safeSetItem('borrowedBooks', state.borrowedBooks)
}, },
setSessionInitialized(state, value) { setSessionInitialized(state, value) {
state.sessionInitialized = value state.sessionInitialized = value
} }
}, },
actions: { actions: {
async initSession({ commit, dispatch }) { async initSession({ commit, dispatch, state }) {
try { try {
// 静默获取用户信息 // 首先检查本地是否有保存的用户信息
const userData = await service.get('/user/getinfo', { const savedUser = safeGetItem('user', null)
silent: true // 避免未登录时显示错误 if (savedUser) {
})
if (userData && userData.username) {
const admin = userData.admin === 1;
commit('setUser', {
username: userData.username,
pic: userData.pic || '',
admin
})
// 获取关联信息
try { try {
await dispatch('fetchBalanceAndVip') const userData = savedUser
} catch (balanceError) { if (userData && userData.username) {
console.warn('获取余额信息失败:', balanceError) // 验证服务器端会话是否仍然有效
const serverUserData = await service.get('/user/getinfo', {
silent: true // 避免未登录时显示错误
})
if (serverUserData && serverUserData.username) {
// 服务器会话有效,更新用户信息
const admin = serverUserData.admin === 1;
commit('setUser', {
username: serverUserData.username,
pic: serverUserData.pic || '',
admin
})
// 获取关联信息
try {
await dispatch('fetchBalanceAndVip')
} catch (balanceError) {
console.warn('获取余额信息失败:', balanceError)
}
try {
await dispatch('fetchBorrowedBooks')
} catch (booksError) {
console.warn('获取借阅书籍失败:', booksError)
}
} else {
// 服务器会话无效,清除本地数据
commit('clearUser')
}
}
} catch (parseError) {
console.error('解析保存的用户信息失败:', parseError)
commit('clearUser')
} }
} else {
// 没有保存的用户信息,尝试静默获取
const userData = await service.get('/user/getinfo', {
silent: true
})
try { if (userData && userData.username) {
await dispatch('fetchBorrowedBooks') const admin = userData.admin === 1;
} catch (booksError) { commit('setUser', {
console.warn('获取借阅书籍失败:', booksError) username: userData.username,
pic: userData.pic || '',
admin
})
// 获取关联信息
try {
await dispatch('fetchBalanceAndVip')
} catch (balanceError) {
console.warn('获取余额信息失败:', balanceError)
}
try {
await dispatch('fetchBorrowedBooks')
} catch (booksError) {
console.warn('获取借阅书籍失败:', booksError)
}
} }
} }
} catch (error) { } catch (error) {
@ -130,16 +175,16 @@ export default createStore({
// 获取关联信息 // 获取关联信息
try { try {
await dispatch('fetchBalanceAndVip') await dispatch('fetchBalanceAndVip')
} catch (balanceError) { } catch (balanceError) {
console.error('获取余额信息失败:', balanceError) console.error('获取余额信息失败:', balanceError)
} }
try { try {
await dispatch('fetchBorrowedBooks') await dispatch('fetchBorrowedBooks')
} catch (booksError) { } catch (booksError) {
console.error('获取借阅书籍失败:', booksError) console.error('获取借阅书籍失败:', booksError)
} }
return userData return userData
} catch (error) { } catch (error) {
@ -199,10 +244,16 @@ export default createStore({
return { code: 200, message: '已退出登录' } return { code: 200, message: '已退出登录' }
}, },
// 查询个人借书记录 // 查询个人借书记录 - 符合接口文档1.6
async fetchBorrowRecords() { async fetchBorrowRecords() {
const response = await service.get('/user/findone') const response = await service.get('/user/findone')
return response.data
// 根据接口文档1.6,管理员返回数组,普通用户返回单个对象
if (response.data && response.data.code === 200) {
return response.data
} else {
throw new Error(response.data?.message || '获取借阅记录失败')
}
}, },
// 获取当前用户已借书籍 // 获取当前用户已借书籍
@ -249,7 +300,7 @@ async returnBook({ dispatch }, { title }) {
} }
}, },
// 查询全部书籍 - 符合接口文档 // 查询全部书籍 - 符合接口文档2.2
async fetchBooks(_, params = {}) { async fetchBooks(_, params = {}) {
const config = { const config = {
params: { params: {
@ -260,24 +311,21 @@ async returnBook({ dispatch }, { title }) {
} }
const response = await service.get('/api/select', config) const response = await service.get('/api/select', config)
console.log('请求书籍:', route.params.title)
console.log('API响应:', response) // 根据接口文档2.2,直接返回数组
// 处理不同响应格式
let list = [] let list = []
let total = 0 let total = 0
if (Array.isArray(response)) { if (Array.isArray(response.data)) {
list = response
total = response.length
} else if (Array.isArray(response.data)) {
list = response.data list = response.data
total = response.data.length total = response.data.length
} else if (response.data && Array.isArray(response.data.data)) { } else if (Array.isArray(response)) {
list = response.data.data list = response
total = response.data.total || response.data.data.length total = response.length
} else if (response.data && Array.isArray(response.data.list)) { } else {
list = response.data.list console.warn('API返回格式不符合预期:', response)
total = response.data.total || response.data.list.length list = []
total = 0
} }
return { return {
@ -318,14 +366,18 @@ async returnBook({ dispatch }, { title }) {
return response.data return response.data
}, },
// 管理员删除书籍 // 管理员删除书籍 - 符合接口文档
async deleteBook(_, { title }) { async deleteBook(_, { title }) {
const response = await service.post('/user/delete', const response = await service.post('/user/delete',
`title=${encodeURIComponent(title)}`, `title=${encodeURIComponent(title)}`,
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
) )
return response.data if (response.data && response.data.code === 200) {
return response.data
} else {
throw new Error(response.data?.message || '删除书籍失败')
}
}, },
// 本周热租榜 - 符合接口文档 // 本周热租榜 - 符合接口文档

@ -0,0 +1,43 @@
// 安全地解析JSON字符串
export function safeParseJSON(str, defaultValue = null) {
if (!str) return defaultValue
try {
return JSON.parse(str)
} catch (error) {
console.error('JSON解析失败:', error)
return defaultValue
}
}
// 安全地存储数据到sessionStorage
export function safeSetItem(key, value) {
try {
sessionStorage.setItem(key, JSON.stringify(value))
return true
} catch (error) {
console.error('存储数据失败:', error)
return false
}
}
// 安全地从sessionStorage获取数据
export function safeGetItem(key, defaultValue = null) {
try {
const item = sessionStorage.getItem(key)
return item ? JSON.parse(item) : defaultValue
} catch (error) {
console.error('获取数据失败:', error)
return defaultValue
}
}
// 安全地从sessionStorage删除数据
export function safeRemoveItem(key) {
try {
sessionStorage.removeItem(key)
return true
} catch (error) {
console.error('删除数据失败:', error)
return false
}
}

@ -70,7 +70,6 @@
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons-vue' import { Search } from '@element-plus/icons-vue'
import { formatDate } from '@/utils/date' import { formatDate } from '@/utils/date'
import axios from 'axios'
const store = useStore() const store = useStore()
const records = ref([]) const records = ref([])
@ -106,28 +105,28 @@
const fetchAllRecords = async () => { const fetchAllRecords = async () => {
try { try {
loading.value = true loading.value = true
const params = {
page: currentPage.value,
pageSize: pageSize.value,
sort: sortType.value,
username: searchUsername.value
}
const response = await axios.get('/user/findone', { params }) // 1.6/user/findone
if (response.data.code === 200) { const response = await store.dispatch('fetchBorrowRecords')
records.value = response.data.data.list if (response.code === 200) {
total.value = response.data.data.total //
if (Array.isArray(response.data)) {
records.value = response.data
total.value = response.data.length
} else {
// 使
records.value = presetRecords
total.value = presetRecords.length
}
} else { } else {
//使 // 使
records.value = presetRecords records.value = presetRecords
total.value = presetRecords.length total.value = presetRecords.length
} }
} catch (error) { } catch (error) {
console.error('获取借阅记录失败:', error) console.error('获取借阅记录失败:', error)
ElMessage.error('接口调用失败,使用预设数据') ElMessage.error('获取借阅记录失败,使用预设数据')
records.value = presetRecords records.value = presetRecords
total.value = presetRecords.length total.value = presetRecords.length

@ -74,11 +74,12 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Plus } from '@element-plus/icons-vue' import { Search, Plus } from '@element-plus/icons-vue'
import axios from 'axios'
const router = useRouter() const router = useRouter()
const store = useStore()
const books = ref([]) const books = ref([])
const loading = ref(false) const loading = ref(false)
const total = ref(0) const total = ref(0)
@ -90,6 +91,31 @@
await fetchBooks() await fetchBooks()
}) })
// const fetchBooks = async () => {
// try {
// loading.value = true
// const params = {
// page: currentPage.value,
// pageSize: pageSize.value,
// keyword: searchKeyword.value
// }
// const response = await axios.get('/api/select', { params })
// if (response.data.code === 200) {
// books.value = response.data.data.list
// total.value = response.data.data.total
// } else {
// ElMessage.error('')
// total.value = books.value.length
// }
// } catch (error) {
// console.error(':', error)
// ElMessage.error('')
// } finally {
// loading.value = false
// }
// }
const fetchBooks = async () => { const fetchBooks = async () => {
try { try {
loading.value = true loading.value = true
@ -99,22 +125,23 @@
keyword: searchKeyword.value keyword: searchKeyword.value
} }
const response = await axios.get('/api/select', { params }) const response = await store.dispatch('fetchBooks', params)
if (response.data.code === 200) { books.value = response.data.list
books.value = response.data.data.list total.value = response.data.total
total.value = response.data.data.total
} else {
ElMessage.error('获取图书列表失败')
total.value = books.value.length
}
} catch (error) { } catch (error) {
console.error('获取图书列表失败:', error) console.error('获取书籍列表失败:', error)
ElMessage.error('获取图书列表失败') ElMessage.error('获取书籍列表失败,使用预设数据')
books.value = [
{ id: 1, title: '三体', url: 'https://picsum.photos/id/24/200/300', money: 5, number: 12, state: '正常', content: '科幻' },
{ id: 2, title: '人类简史', url: 'https://picsum.photos/id/25/200/300', money: 4, number: 10, state: '正常', content: '历史' },
{ id: 3, title: '百年孤独', url: 'https://picsum.photos/id/26/200/300', money: 6, number: 0, state: '维护中', content: '文学' },
]
total.value = books.value.length
} finally { } finally {
loading.value = false loading.value = false
} }
} }
const handlePageChange = (page) => { const handlePageChange = (page) => {
currentPage.value = page currentPage.value = page
fetchBooks() fetchBooks()
@ -136,7 +163,7 @@
} }
) )
await axios.delete(`/api/select/${book.id}`) await store.dispatch('deleteBook', { title: book.title })
ElMessage.success('删除成功') ElMessage.success('删除成功')
fetchBooks() fetchBooks()
} catch (error) { } catch (error) {

@ -59,7 +59,7 @@ const store = useStore()
const book = ref(null) const book = ref(null)
const loading = ref(true) const loading = ref(true)
const isAdmin = computed(() => store.getters.isAdmin) const isAdmin = computed(() => store.state.user?.admin || false)
onMounted(async () => { onMounted(async () => {
await fetchBook() await fetchBook()

@ -15,7 +15,7 @@
<el-button <el-button
type="primary" type="primary"
@click="goToAddBook" @click="goToAddBook"
v-if="isAdmin" v-if="user && user.admin"
class="add-button"> class="add-button">
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
添加书籍 添加书籍
@ -75,15 +75,13 @@ import { ElMessage } from 'element-plus'
const store = useStore() const store = useStore()
const router = useRouter() const router = useRouter()
const isAdmin = computed(() => store.state.user?.admin || false)
const books = ref([]) const books = ref([])
const searchKeyword = ref('') const searchKeyword = ref('')
const currentPage = ref(1) const currentPage = ref(1)
const pageSize = ref(12) const pageSize = ref(12)
const total = ref(0) const total = ref(0)
const isAdmin = computed(() => store.getters.isAdmin)
onMounted(() => { onMounted(() => {
fetchBooks() fetchBooks()
}) })

Loading…
Cancel
Save