前端修改3.0

hyx_brand
hyx 2 months ago
parent 44c71c9562
commit b2e3d51c0e

@ -66,18 +66,42 @@
</template> </template>
<script setup> <script setup>
import { computed } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useStore } from 'vuex' 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'
const store = useStore() const store = useStore()
const router = useRouter() 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 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) const isAdmin = computed(() => store.getters.isAdmin)
@ -94,6 +118,8 @@ const activeIndex = computed(() => {
return '' return ''
}) })
const handleSelect = (index) => { const handleSelect = (index) => {
switch(index) { switch(index) {
case 'home': case 'home':
@ -131,10 +157,6 @@ const goToRegister = () => {
router.push('/register') router.push('/register')
} }
const goToProfile = () => {
router.push('/profile')
}
const goToRecharge = () => { const goToRecharge = () => {
router.push('/recharge') router.push('/recharge')
} }

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

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

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

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

@ -44,7 +44,7 @@
</div> </div>
<div class="book-status"> <div class="book-status">
<el-tag <el-tag
:type="book.state === '可借' ? 'success' : 'danger'" :type="book.state === '正常' ? 'success' : 'danger'"
size="small"> size="small">
{{ book.state }} {{ book.state }}
</el-tag> </el-tag>
@ -102,20 +102,7 @@ const fetchBooks = async () => {
} 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: '文学' },
{ 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 total.value = books.value.length
} }
} }

@ -73,18 +73,9 @@ const fetchBooks = async () => {
ElMessage.error('获取书籍列表失败') ElMessage.error('获取书籍列表失败')
// //
books.value = [ books.value = [
{ id: 1, title: '三体', url: 'https://picsum.photos/id/24/200/300', money: 5, number: 12, 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: 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: 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 total.value = books.value.length
} }
@ -97,7 +88,7 @@ const searchBooks = () => {
const handleBorrow = async (book) => { const handleBorrow = async (book) => {
try { try {
if (book.number <= 0) { if (book.state !=='正常') {
ElMessage.warning('该书籍维护中,无法借阅') ElMessage.warning('该书籍维护中,无法借阅')
return return
} }

Loading…
Cancel
Save