diff --git a/public/imgs/shop/coupon/background.png b/public/imgs/shop/coupon/background.png new file mode 100644 index 0000000..fb94313 Binary files /dev/null and b/public/imgs/shop/coupon/background.png differ diff --git a/public/imgs/shop/coupon/bg_useful1.png b/public/imgs/shop/coupon/bg_useful1.png new file mode 100644 index 0000000..f9b639b Binary files /dev/null and b/public/imgs/shop/coupon/bg_useful1.png differ diff --git a/public/imgs/shop/coupon/bg_useful2.png b/public/imgs/shop/coupon/bg_useful2.png new file mode 100644 index 0000000..f431b06 Binary files /dev/null and b/public/imgs/shop/coupon/bg_useful2.png differ diff --git a/public/imgs/shop/coupon/bg_useless1.png b/public/imgs/shop/coupon/bg_useless1.png new file mode 100644 index 0000000..a7da863 Binary files /dev/null and b/public/imgs/shop/coupon/bg_useless1.png differ diff --git a/public/imgs/shop/coupon/bg_useless2.png b/public/imgs/shop/coupon/bg_useless2.png new file mode 100644 index 0000000..3ffc11d Binary files /dev/null and b/public/imgs/shop/coupon/bg_useless2.png differ diff --git a/src/components/Captcha.vue b/src/components/Captcha.vue index 99d6a86..64568f0 100644 --- a/src/components/Captcha.vue +++ b/src/components/Captcha.vue @@ -44,7 +44,7 @@ import { ref, onMounted, watch } from 'vue' import { ElMessage } from 'element-plus' import { Refresh, Loading } from '@element-plus/icons-vue' -import api from '@/utils/api' +import api,{captchaAPI} from '@/utils/api' // Props const props = defineProps({ @@ -81,7 +81,7 @@ const loading = ref(false) const getCaptcha = async () => { try { loading.value = true - const response = await api.get('/captcha/generate') + const response = await captchaAPI.generate() if (response.data.success) { captchaImage.value = response.data.data.image diff --git a/src/router/index.js b/src/router/index.js index a157b40..62ab11e 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -312,7 +312,7 @@ router.beforeEach(async (to, from, next) => { } } else { // 普通用户页面认证逻辑 - console.log(userStore.isAuthenticated, 'isAuthenticated'); + // console.log(userStore.isAuthenticated, 'isAuthenticated'); if (!userStore.isAuthenticated) { // 尝试从本地存储恢复登录状态 @@ -328,10 +328,10 @@ router.beforeEach(async (to, from, next) => { } // 检查支付状态(管理员除外) - console.log(userStore.user); + // console.log(userStore.user); if (userStore.user && userStore.user.role !== 'admin' && userStore.user.payment_status === 'unpaid') { - console.log('进来了'); + // console.log('进来了'); // 如果当前不在支付页面,静默重定向到支付页面(不显示额外通知) if (to.name !== 'Payment') { diff --git a/src/stores/user.js b/src/stores/user.js index a3b398c..a0c1ccd 100644 --- a/src/stores/user.js +++ b/src/stores/user.js @@ -1,6 +1,6 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' -import api from '@/utils/api' +import api,{authAPI} from '@/utils/api' import { ElMessage } from 'element-plus' export const useUserStore = defineStore('user', () => { @@ -23,10 +23,9 @@ export const useUserStore = defineStore('user', () => { token.value = newToken if (newToken) { localStorage.setItem('token', newToken) - api.defaults.headers.common['Authorization'] = `Bearer ${newToken}` } else { localStorage.removeItem('token') - delete api.defaults.headers.common['Authorization'] + console.log('token已移除'); } } @@ -39,7 +38,9 @@ export const useUserStore = defineStore('user', () => { const login = async (credentials) => { try { loading.value = true - const response = await api.post('/auth/login', credentials) + const response = await authAPI.login(credentials) + + console.log('response',response); if (response.data.success && response.data.token) { setToken(response.data.token) @@ -72,6 +73,7 @@ export const useUserStore = defineStore('user', () => { return { success: false, message } } } catch (error) { + console.log(error,'error'); const errorData = error.response?.data if (errorData?.needPayment) { // 处理403状态码返回的需要支付情况 @@ -146,15 +148,13 @@ export const useUserStore = defineStore('user', () => { try { // 确保请求头已设置 - if (token.value && !api.defaults.headers.common['Authorization']) { - api.defaults.headers.common['Authorization'] = `Bearer ${token.value}` - } const response = await api.get('/auth/me') setUser(response.data.user) return true } catch (error) { // token无效,清除本地存储 + console.log('token无效,清除本地存储',error); setToken('') setUser(null) return false diff --git a/src/utils/api.js b/src/utils/api.js index 168b7c0..55c856b 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -1,65 +1,66 @@ import axios from 'axios' import { ElMessage, ElLoading } from 'element-plus' import router from '@/router' +import NProgress from 'nprogress' // 创建axios实例 -const api = axios.create({ - baseURL: '/api', - timeout: 10000, - headers: { - 'Content-Type': 'application/json' +// 工厂函数(复用拦截器逻辑) +export const createRequest = (baseURL) => { + const request = axios.create({ + baseURL, + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } + }) + + // 初始化时设置token + const token = localStorage.getItem('token') + if (token) { + request.defaults.headers.common['Authorization'] = `Bearer ${token}` } -}) -// 初始化时设置token -const token = localStorage.getItem('token') -if (token) { - api.defaults.headers.common['Authorization'] = `Bearer ${token}` -} - -// 请求拦截器 -let loadingInstance = null -api.interceptors.request.use( + // 请求拦截器 + request.interceptors.request.use( (config) => { - // 从localStorage获取token + // 开始进度条 + NProgress.start() + + // 显示加载动画(除了某些不需要的请求) + if (!config.hideLoading) { + showLoading() + } + + // 添加认证token const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } - // 显示加载动画(可选) - if (config.showLoading !== false) { - loadingInstance = ElLoading.service({ - text: '加载中...', - background: 'rgba(0, 0, 0, 0.7)' - }) - } - return config }, (error) => { - if (loadingInstance) { - loadingInstance.close() - } + hideLoading() + NProgress.done() return Promise.reject(error) } ) -// 响应拦截器 -api.interceptors.response.use( + // 响应拦截器 + request.interceptors.response.use( (response) => { - if (loadingInstance) { - loadingInstance.close() - } + hideLoading() + NProgress.done() return response }, (error) => { - if (loadingInstance) { - loadingInstance.close() - } + hideLoading() + NProgress.done() + + const { response } = error // 处理不同的错误状态码 - if (error.response) { + if (response) { const { status, data } = error.response switch (status) { @@ -136,13 +137,53 @@ api.interceptors.response.use( } ) + return request +} + +let loadingInstance = null +let requestCount = 0 +let isLoggingOut = false // 防止重复登出 + +// 显示加载 +const showLoading = () => { + if (requestCount === 0) { + loadingInstance = ElLoading.service({ + text: '加载中...', + background: 'rgba(0, 0, 0, 0.7)' + }) + } + requestCount++ +} + +// 隐藏加载 +const hideLoading = () => { + requestCount-- + if (requestCount <= 0) { + requestCount = 0 + if (loadingInstance) { + loadingInstance.close() + loadingInstance = null + } + } +} + +// 生成不同的实例 +export const apiRequest = createRequest('/api') +export const midRequest = createRequest('/mid') + +// 初始化时设置token +const token = localStorage.getItem('token') +if (token) { + apiRequest.defaults.headers.common['Authorization'] = `Bearer ${token}` +} + // 封装常用的请求方法 -export const request = { - get: (url, config = {}) => api.get(url, config), - post: (url, data = {}, config = {}) => api.post(url, data, config), - put: (url, data = {}, config = {}) => api.put(url, data, config), - delete: (url, config = {}) => api.delete(url, config), - patch: (url, data = {}, config = {}) => api.patch(url, data, config) +const api = { + get: (url, config = {}) => apiRequest.get(url, config), + post: (url, data = {}, config = {}) => apiRequest.post(url, data, config), + put: (url, data = {}, config = {}) => apiRequest.put(url, data, config), + delete: (url, config = {}) => apiRequest.delete(url, config), + patch: (url, data = {}, config = {}) => apiRequest.patch(url, data, config) } @@ -150,43 +191,43 @@ export const request = { // 用户相关API export const userAPI = { // 获取用户列表 - getList: (params = {}) => request.get('/users', { params }), + getList: (params = {}) => apiRequest.get('/users', { params }), // 获取用户详情 - getDetail: (id) => request.get(`/users/${id}`), + getDetail: (id) => apiRequest.get(`/users/${id}`), // 更新用户信息 - update: (id, data) => request.put(`/users/${id}`, data), + update: (id, data) => apiRequest.put(`/users/${id}`, data), // 删除用户 - delete: (id) => request.delete(`/users/${id}`), + delete: (id) => apiRequest.delete(`/users/${id}`), // 获取用户统计 - getStats: () => request.get('/users/stats/overview') + getStats: () => apiRequest.get('/users/stats/overview') } // 认证相关API export const authAPI = { // 登录 - login: (data) => request.post('/auth/login', data), + login: (data) => midRequest.post('/auth/login', data), // 注册 - register: (data) => request.post('/auth/register', data), + register: (data) => midRequest.post('/auth/register', data), // 获取当前用户信息 - me: () => request.get('/auth/me'), + me: () => apiRequest.get('/auth/me'), // 修改密码 - changePassword: (data) => request.put('/auth/change-password', data) + changePassword: (data) => apiRequest.put('/auth/change-password', data) } // 验证码相关API export const captchaAPI = { // 生成验证码 - generate: () => request.get('/captcha/generate'), + generate: () => midRequest.get('/captcha/generate'), // 验证验证码 - verify: (data) => request.post('/captcha/verify', data) + verify: (data) => midRequest.post('/captcha/verify', data) } // 文件上传API @@ -195,7 +236,7 @@ export const uploadAPI = { uploadImage: (file) => { const formData = new FormData() formData.append('image', file) - return request.post('/upload/image', formData, { + return midRequest.post('/upload/image', formData, { headers: { 'Content-Type': 'multipart/form-data' } @@ -206,7 +247,7 @@ export const uploadAPI = { uploadFile: (file) => { const formData = new FormData() formData.append('file', file) - return request.post('/upload/file', formData, { + return midRequest.post('/upload/file', formData, { headers: { 'Content-Type': 'multipart/form-data' } @@ -217,24 +258,29 @@ export const uploadAPI = { // 支付相关API export const paymentAPI = { // 获取支付方式 - getMethods: () => request.get('/payment/methods'), + getMethods: () => apiRequest.get('/payment/methods'), // 创建支付订单 - createOrder: (data) => request.post('/payment/create-order', data), + createOrder: (data) => apiRequest.post('/payment/create-order', data), // 查询支付状态 - queryStatus: (outTradeNo) => request.get(`/payment/query-status/${outTradeNo}`), + queryStatus: (outTradeNo) => apiRequest.get(`/payment/query-status/${outTradeNo}`), - getOrder: () => request.get('/payment/check-status'), + getOrder: () => apiRequest.get('/payment/check-status'), // 获取支付记录 - getOrders: (params = {}) => request.get('/payment/orders', { params }) + getOrders: (params = {}) => apiRequest.get('/payment/orders', { params }) +} + +// 购买商品 +export const buyAPI = { + buy: (data) => midRequest.post('/payment/create-order', data), } // 转账相关API export const transferAPI = { // 获取公户信息 - getPublicAccount: () => request.get('/transfers/public-account'), + getPublicAccount: () => apiRequest.get('/transfers/public-account'), // 创建转账记录 create: (data) => { @@ -242,7 +288,7 @@ export const transferAPI = { Object.keys(data).forEach(key => { formData.append(key, data[key]) }) - return request.post('/transfers', formData, { + return apiRequest.post('/transfers', formData, { headers: { 'Content-Type': 'multipart/form-data' } @@ -250,38 +296,38 @@ export const transferAPI = { }, // 确认转账 - confirm: (id) => request.put(`/transfers/${id}/confirm`), + confirm: (id) => apiRequest.put(`/transfers/${id}/confirm`), // 拒绝转账 - reject: (id) => request.put(`/transfers/${id}/reject`), + reject: (id) => apiRequest.put(`/transfers/${id}/reject`), // 确认收款 - confirmReceived: (id) => request.post('/transfers/confirm-received', { transfer_id: id }), + confirmReceived: (id) => apiRequest.post('/transfers/confirm-received', { transfer_id: id }), // 确认未收到款 - confirmNotReceived: (id) => request.post('/transfers/confirm-not-received', { transfer_id: id }), + confirmNotReceived: (id) => apiRequest.post('/transfers/confirm-not-received', { transfer_id: id }), // 获取用户转账记录 - getUserTransfers: (params = {}) => request.get('/transfers/user', { params }), + getUserTransfers: (params = {}) => apiRequest.get('/transfers/user', { params }), // 获取指定用户的转账记录 - getUserTransfersByUserId: (userId, params = {}) => request.get(`/transfers/user/${userId}`, { params }), + getUserTransfersByUserId: (userId, params = {}) => apiRequest.get(`/transfers/user/${userId}`, { params }), // 获取待确认转账 - getPendingTransfers: (params = {}) => request.get('/transfers/pending', { params }), + getPendingTransfers: (params = {}) => apiRequest.get('/transfers/pending', { params }), // 获取用户账户信息 - getUserAccount: () => request.get('/transfers/account'), + getUserAccount: () => apiRequest.get('/transfers/account'), // 获取转账列表(管理员) - getList: (params = {}) => request.get('/transfers', { params }), + getList: (params = {}) => apiRequest.get('/transfers', { params }), // 获取转账统计 - getStats: () => request.get('/transfers/stats') + getStats: () => apiRequest.get('/transfers/stats') } export const distributionAPI = { - getLowerUsers: (params) => request.get('/agents/distribution', { params }), + getLowerUsers: (params) => apiRequest.get('/agents/distribution', { params }), } export default api \ No newline at end of file diff --git a/src/views/CouponManage.vue b/src/views/CouponManage.vue index 042e612..0dc19b2 100644 --- a/src/views/CouponManage.vue +++ b/src/views/CouponManage.vue @@ -2,20 +2,70 @@