前端修改3.0

hyx_brand
hyx 2 months ago
parent 44c71c9562
commit b2e3d51c0e

@ -66,18 +66,42 @@
</template>
<script setup>
import { computed } from 'vue'
import { useRouter } from 'vue-router'
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'
const store = useStore()
const router = useRouter()
// onMounted
onMounted(async () => {
//
if (store.getters.isAuthenticated) {
await fetchUserInfo()
}
})
//
async function fetchUserInfo() {
try {
// VIP
await store.dispatch('fetchBalanceAndVip')
} catch (error) {
console.error('获取用户信息失败:', error)
//
if (store.getters.isAuthenticated) {
ElMessage.error('获取用户信息失败')
}
}
}
const vip = computed(() => store.state.vipLevel)
const balance = computed(() => store.state.balance)
const user = computed(() => store.state.user)
const isAdmin = computed(() => store.getters.isAdmin)
@ -94,6 +118,8 @@ const activeIndex = computed(() => {
return ''
})
const handleSelect = (index) => {
switch(index) {
case 'home':
@ -131,10 +157,6 @@ const goToRegister = () => {
router.push('/register')
}
const goToProfile = () => {
router.push('/profile')
}
const goToRecharge = () => {
router.push('/recharge')
}

@ -1,18 +1,12 @@
import { createStore } from 'vuex'
import service from '../utils/request'
// // 配置axios基础路径
// axios.defaults.baseURL = 'http://localhost:8877'
// // 允许跨域携带cookie
// axios.defaults.withCredentials = true
export default createStore({
state: {
user: null,
balance: 0,
vipLevel: 0,
borrowedBooks: []
},
getters: {
isAuthenticated: state => !!state.user,
@ -44,13 +38,12 @@ export default createStore({
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
if (response.data.code !== 200) {
throw new Error(response.data.message || '登录失败')
}
// 登录成功后获取用户信息
await dispatch('fetchUser')
return response.data
const userInfo = await dispatch('fetchUser')
return {
...response.data,
user: userInfo
}
},
// 用户注册
@ -60,70 +53,82 @@ export default createStore({
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
if (response.data.code !== 200) {
throw new Error(response.data.message || '注册失败')
}
return response.data
},
// 获取当前用户信息
async fetchUser({ commit, dispatch }) {
const response = await service.get('/user/getinfo')
// 接口可能返回两种格式:
// 1. 带code的标准格式{code:200, message:..., data: null}
// 2. 直接返回用户信息:{username: "张三", pic: "..."}
if (response.data.code === 200) {
// 情况1如果code=200但data为null可能接口直接在根节点返回用户信息
const userData = response.data.data || response.data;
// 过滤掉非用户信息字段如code/message
const filteredUser = {
username: userData.username || '',
pic: userData.pic || ''
};
commit('setUser', filteredUser);
await dispatch('fetchBalanceAndVip');
await dispatch('fetchBorrowedBooks');
} else {
// 处理接口返回非200的情况如未登录
commit('setUser', null);
}
return response.data;
},
// 获取当前用户信息 - 符合接口文档
async fetchUser({ commit, dispatch }) {
try {
const userData = await service.get('/user/getinfo')
// 用户信息接口直接返回用户对象
commit('setUser', {
username: userData.username || '',
pic: userData.pic || '',
admin: userData.admin || false
})
// 获取关联信息
try {
await dispatch('fetchBalanceAndVip')
} catch (balanceError) {
console.error('获取余额信息失败:', balanceError)
}
try {
await dispatch('fetchBorrowedBooks')
} catch (booksError) {
console.error('获取借阅书籍失败:', booksError)
}
return userData
} catch (error) {
commit('clearUser')
throw error
}
},
// 获取余额和VIP等级
// 获取余额和VIP等级
async fetchBalanceAndVip({ commit }) {
const response = await service.post('/user/findmoney')
if (response.data.code === 200) {
try {
const response = await service.post('/user/findmoney')
// 解析消息提取余额和VIP等级
const balanceMatch = response.data.message.match(/余额为:(\d+\.\d+)元/)
const vipMatch = response.data.message.match(/当前VIP等级为(\d+)/)
const message = response.data.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 {
console.error('无法解析余额信息:', message)
// 尝试从数据字段获取
if (response.data.data) {
commit('setBalanceAndVip', {
balance: parseFloat(response.data.data.balance) || 0,
vip: parseInt(response.data.data.vipLevel) || 0
})
}
}
return response.data
} catch (error) {
console.error('获取余额失败:', error)
throw error
}
return response.data
},
// 账户充值
// 账户充值
async recharge(_, { money }) {
const response = await service.post('/user/recharge',
`money=${money}`,
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
if (response.data.code !== 200) {
throw new Error(response.data.message || '充值失败')
}
// 充值后刷新余额
await dispatch('fetchBalanceAndVip')
return response.data
},
@ -133,136 +138,130 @@ export default createStore({
return { code: 200, message: '已退出登录' }
},
// 获取借阅记录
// 查询个人借书记录
async fetchBorrowRecords() {
const response = await service.get('/user/findone')
if (response.data.code !== 200) {
throw new Error(response.data.message || '获取借阅记录失败')
}
return response.data
},
// 获取当前用户已借书籍
async fetchBorrowedBooks({ commit }) {
const response = await service.get('/user/borrow/books')
if (response.data.code === 200) {
commit('setBorrowedBooks', response.data.data || [])
}
return response.data
},
const response = await service.get('/user/borrow/books')
// 按照接口文档处理响应
if (response.data.code === 200) {
commit('setBorrowedBooks', response.data.data || [])
} else {
throw new Error(response.data.message || '获取已借书籍失败')
}
return response.data
},
// 借书
// 借书
async borrowBook(_, { title }) {
const response = await service.post('/borrow/borrowbook',
`title=${encodeURIComponent(title)}`,
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
if (response.data.code !== 200) {
throw new Error(response.data.message || '借阅失败')
}
return response.data
},
// 还书
// 归还书籍
async returnBook(_, { title }) {
const response = await service.post('/borrow/returnbook',
`title=${encodeURIComponent(title)}`,
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
if (response.data.code !== 200) {
throw new Error(response.data.message || '归还失败')
}
return response.data
},
// 查询全部书籍 - 符合接口文档
async fetchBooks(_, params = {}) {
let url = '/api/select'
const queryParams = new URLSearchParams()
if (params.page) queryParams.append('page', params.page)
if (params.pageSize) queryParams.append('pageSize', params.pageSize)
if (params.keyword) queryParams.append('title', params.keyword)
if (queryParams.toString()) {
url += `?${queryParams.toString()}`
const config = {
params: {
page: params.page || 1,
pageSize: params.pageSize || 10,
title: params.keyword || ''
}
}
const response = await service.get(url)
const response = await service.get('/api/select', config)
if (response.data.code !== 200) {
throw new Error(response.data.message || '获取书籍列表失败')
// 处理不同响应格式
let list = []
let total = 0
if (Array.isArray(response)) {
list = response
total = response.length
} else if (Array.isArray(response.data)) {
list = response.data
total = response.data.length
} else if (response.data && Array.isArray(response.data.data)) {
list = response.data.data
total = response.data.total || response.data.data.length
} else if (response.data && Array.isArray(response.data.list)) {
list = response.data.list
total = response.data.total || response.data.list.length
}
return {
data: {
list: response.data.data || [],
total: response.data.data?.length || 0
list,
total
}
}
},
async fetchBookById(_, id) {
const response = await service.get(`/api/selectone?id=${id}`)
// 根据书名查单本书 - 符合接口文档
async fetchBookByTitle(_, title) {
const response = await service.get('/api/selectone', {
params: { title }
})
if (response.data.code !== 200) {
throw new Error(response.data.message || '获取书籍详情失败')
// 处理不同响应格式
let book = null
if (response.data) {
book = response.data.data || response.data
} else {
book = response
}
return { data: response.data.data }
return { data: book }
},
// 新增书籍
async addBook(_, bookData) {
const response = await service.post('/api/add', bookData, {
headers: { 'Content-Type': 'application/json' }
})
if (response.data.code !== 200) {
throw new Error(response.data.message || '添加书籍失败')
}
return response.data
},
// 管理员删除书籍
async deleteBook(_, { title }) {
const response = await service.post('/user/delete',
`title=${encodeURIComponent(title)}`,
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
if (response.data.code !== 200) {
throw new Error(response.data.message || '删除书籍失败')
}
return response.data
},
// 本周热租榜 - 符合接口文档
async fetchWeeklyRank() {
const response = await service.get('/api/rank/weekly')
if (response.data.code !== 200) {
throw new Error(response.data.message || '获取本周热租榜失败')
}
return { data: response.data.data || [] }
return { data: Array.isArray(response) ? response : response.data || [] }
},
// 本月热租榜 - 符合接口文档
async fetchMonthlyRank() {
const response = await service.get('/api/rank/monthly')
if (response.data.code !== 200) {
throw new Error(response.data.message || '获取本月热租榜失败')
}
return { data: response.data.data || [] }
return { data: Array.isArray(response) ? response : response.data || [] }
}
}
})
})

@ -1,4 +1,7 @@
import axios from 'axios'
import { ElMessage } from 'element-plus'
import store from '../store/index'
import router from '../router/index'
// 创建axios实例
const service = axios.create({
@ -10,7 +13,7 @@ const service = axios.create({
// 请求拦截器
service.interceptors.request.use(
config => {
// 这里可以添加token等全局请求头
return config
},
error => {
@ -18,27 +21,46 @@ service.interceptors.request.use(
}
)
// 响应拦截器
// 响应拦截器 - 增强版
service.interceptors.response.use(
response => {
const res = response.data
// 业务错误处理
if (res.code !== 200) {
ElMessage.error(res.message || '请求失败')
return Promise.reject(new Error(res.message || 'Error'))
// 只处理有 code 字段的响应
if (res && typeof res === 'object' && res.code !== undefined) {
// 业务错误处理 (code 不为 200)
if (res.code !== 200) {
ElMessage.error(res.message || '请求失败')
return Promise.reject(new Error(res.message || 'Error'))
}
// 成功响应返回整个响应对象
return response
}
// 没有 code 字段的响应直接返回数据
return res
},
error => {
// 处理HTTP错误
if (error.response && error.response.status === 401) {
// 未登录处理
store.dispatch('user/logout')
router.push('/login')
ElMessage.error('请先登录')
if (error.response) {
switch (error.response.status) {
case 401:
// 未登录处理
store.dispatch('logout')
router.push('/login')
ElMessage.error('请先登录')
break
case 403:
ElMessage.error('没有操作权限')
break
case 500:
ElMessage.error('服务器内部错误')
break
default:
ElMessage.error(error.message || '请求失败')
}
} else {
ElMessage.error(error.message || '请求失败')
ElMessage.error('网络错误,请检查连接')
}
return Promise.reject(error)
}

@ -79,7 +79,9 @@ const login = async () => {
//
await store.dispatch('fetchUser')
// localStorage
const userInfo = store.state.user
localStorage.setItem('userInfo', JSON.stringify(userInfo))
//
router.push('/')
} catch (error) {

@ -10,7 +10,7 @@
<el-tag type="success" size="large">{{ book.money }}/</el-tag>
</div>
<div class="status">
<el-tag :type="book.number > 0 ? 'success' : 'danger'" size="large">
<el-tag :type="book.state === '正常' ? 'success' : 'danger'" size="large">
{{ book.state }}
</el-tag>
<span>阅读量: {{ book.number }}</span>
@ -19,7 +19,7 @@
<el-button
type="primary"
size="large"
:disabled="book.state = '维护中'"
:disabled="book.state !== '正常'"
@click="borrowBook"
v-if="!isAdmin">
立即借阅
@ -56,7 +56,7 @@ const route = useRoute()
const router = useRouter()
const store = useStore()
const bookId = route.params.id
const bookTitle = route.params.title
const book = ref(null)
const isAdmin = computed(() => store.getters.isAdmin)
@ -67,7 +67,7 @@ onMounted(async () => {
const fetchBook = async () => {
try {
const response = await store.dispatch('fetchBookById', bookId)
const response = await store.dispatch('fetchBookByTitle', bookTitle)
book.value = response.data
} catch (error) {
console.error('获取书籍详情失败:', error)

@ -44,7 +44,7 @@
</div>
<div class="book-status">
<el-tag
:type="book.state === '可借' ? 'success' : 'danger'"
:type="book.state === '正常' ? 'success' : 'danger'"
size="small">
{{ book.state }}
</el-tag>
@ -102,20 +102,7 @@ const fetchBooks = async () => {
} catch (error) {
console.error('获取书籍列表失败:', 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: '文学' },
{ id: 4, title: '活着', url: 'https://picsum.photos/id/27/200/300', money: 3, number: 15, state: '可借', content: '小说' },
{ id: 5, title: '追风筝的人', url: 'https://picsum.photos/id/28/200/300', money: 4, number: 9, state: '可借', content: '小说' },
{ id: 6, title: '解忧杂货店', url: 'https://picsum.photos/id/29/200/300', money: 5, number: 7, state: '可借', content: '小说' },
{ id: 7, title: '小王子', url: 'https://picsum.photos/id/30/200/300', money: 2, number: 20, state: '可借', content: '童话' },
{ id: 8, title: '围城', url: 'https://picsum.photos/id/31/200/300', money: 4, number: 18, state: '可借', content: '文学' },
{ id: 9, title: '月亮与六便士', url: 'https://picsum.photos/id/32/200/300', money: 5, number: 16, state: '可借', content: '小说' },
{ id: 10, title: '哈利波特', url: 'https://picsum.photos/id/33/200/300', money: 7, number: 25, state: '可借', content: '魔幻' },
{ id: 11, title: '水浒传', url: 'https://picsum.photos/id/34/200/300', money: 6, number: 14, state: '可借', content: '古典' },
{ id: 12, title: '三国演义', url: 'https://picsum.photos/id/35/200/300', money: 6, number: 12, state: '可借',content: '古典' }
]
total.value = books.value.length
}
}

@ -73,19 +73,10 @@ const fetchBooks = async () => {
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: 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: '文学' },
{ id: 4, title: '活着', url: 'https://picsum.photos/id/27/200/300', money: 3, number: 15, state: '可借', content: '小说' },
{ id: 5, title: '追风筝的人', url: 'https://picsum.photos/id/28/200/300', money: 4, number: 9, state: '可借', content: '小说' },
{ id: 6, title: '解忧杂货店', url: 'https://picsum.photos/id/29/200/300', money: 5, number: 7, state: '可借', content: '小说' },
{ id: 7, title: '小王子', url: 'https://picsum.photos/id/30/200/300', money: 2, number: 20, state: '可借', content: '童话' },
{ id: 8, title: '围城', url: 'https://picsum.photos/id/31/200/300', money: 4, number: 18, state: '可借', content: '文学' },
{ id: 9, title: '月亮与六便士', url: 'https://picsum.photos/id/32/200/300', money: 5, number: 16, state: '可借', content: '小说' },
{ id: 10, title: '哈利波特', url: 'https://picsum.photos/id/33/200/300', money: 7, number: 25, state: '可借', content: '魔幻' },
{ id: 11, title: '水浒传', url: 'https://picsum.photos/id/34/200/300', money: 6, number: 14, state: '可借', content: '古典' },
{ id: 12, title: '三国演义', url: 'https://picsum.photos/id/35/200/300', money: 6, number: 12, state: '可借',content: '古典' }
]
]
total.value = books.value.length
}
}
@ -97,7 +88,7 @@ const searchBooks = () => {
const handleBorrow = async (book) => {
try {
if (book.number <= 0) {
if (book.state !=='正常') {
ElMessage.warning('该书籍维护中,无法借阅')
return
}

Loading…
Cancel
Save