支付及优惠券页面更新
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/background.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/background.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 187 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useful1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useful1.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useful2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useful2.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useless1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useless1.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useless2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/imgs/shop/coupon/bg_useless2.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.3 KiB | 
| @@ -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 | ||||
|   | ||||
| @@ -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') { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										192
									
								
								src/utils/api.js
									
									
									
									
									
								
							
							
						
						
									
										192
									
								
								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 | ||||
| @@ -2,20 +2,70 @@ | ||||
|   <div class="coupon-container"> | ||||
|     <div class="header"> | ||||
|       <div class="back-btn" @click="$router.go(-1)"><</div> | ||||
|       <div class="text"> | ||||
|       <div class="header-text"> | ||||
|         优惠券包 | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="coupon-content"> | ||||
|       <div class="coupon-item" @click="getCoupon('1')"> | ||||
|         领满减 | ||||
|       <div class="discount_for_a_amount_container"> | ||||
|         <div class="container-title"> | ||||
|           满减券限量 | ||||
|         </div> | ||||
|         <div class="coupons-content"> | ||||
|           <div class="coupon-item" v-for="coupon in coupons" :key="coupon.id"> | ||||
|             <div class="coupon-filtered-item" v-if="coupon.type === 'discount_for_a_amount'"  | ||||
|             :style="{ | ||||
|               backgroundImage: coupon.got | ||||
|                 ? 'url(/imgs/shop/coupon/bg_useless1.png)'  | ||||
|                 : 'url(/imgs/shop/coupon/bg_useful1.png)' | ||||
|             }"> | ||||
|               <div class="text-left">¥{{ coupon.discount }}</div> | ||||
|               <div class="text-mid-w">满{{ coupon.for_a_amount }}可用</div> | ||||
|               <div class="text-right" @click="getCoupon('discount_for_a_amount',coupon.id)" v-if="!coupon.got">立即领取</div> | ||||
|               <div class="text-right" v-else>已领取</div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="coupon-item" @click="getCoupon('2')"> | ||||
|         领折扣 | ||||
|       <div class="discount_container"> | ||||
|         <div class="container-title" style="margin-bottom: 10px;"> | ||||
|           抵扣券限量 | ||||
|         </div> | ||||
|         <div class="coupons-content grid-container"> | ||||
|           <div class="coupon-item" v-for="coupon in coupons" :key="coupon.id"> | ||||
|             <div class="coupon-filtered-item2" v-if="coupon.type === 'deduction'" | ||||
|             :style="{ | ||||
|               backgroundImage: coupon.got | ||||
|                 ? 'url(/imgs/shop/coupon/bg_useless2.png)'  | ||||
|                 : 'url(/imgs/shop/coupon/bg_useful2.png)' | ||||
|             }"> | ||||
|               <div class="text-top">¥{{ coupon.price }}</div> | ||||
|               <div class="text-mid-h">无门槛</div> | ||||
|               <div class="text-bottom" @click="getCoupon('deduction',coupon.id)" v-if="!coupon.got">立即领取</div> | ||||
|               <div class="text-bottom" v-else>已领取</div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="coupon-item" @click="getCoupon('3')"> | ||||
|         领抵扣 | ||||
|       <div class="deduction_container"> | ||||
|         <div class="container-title"> | ||||
|           折扣券限量 | ||||
|         </div> | ||||
|         <div class="coupons-content"> | ||||
|           <div class="coupon-item" v-for="coupon in coupons" :key="coupon.id"> | ||||
|             <div class="coupon-filtered-item" v-if="coupon.type === 'discount'" | ||||
|             :style="{ | ||||
|               backgroundImage: coupon.got | ||||
|                 ? 'url(/imgs/shop/coupon/bg_useless1.png)'  | ||||
|                 : 'url(/imgs/shop/coupon/bg_useful1.png)' | ||||
|             }"> | ||||
|               <div class="text-left">{{ coupon.precent/10 }}折</div> | ||||
|               <div class="text-right" @click="getCoupon('discount',coupon.id)" v-if="!coupon.got">立即领取</div> | ||||
|               <div class="text-right" v-else>已领取</div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
| @@ -30,11 +80,27 @@ import { ElMessage } from 'element-plus' | ||||
|  | ||||
| const userStore = useUserStore() | ||||
|  | ||||
| const getCoupon = async (coupon_id) => { | ||||
| const coupons = ref([]) | ||||
|  | ||||
| const getAllCoupons = async () => { | ||||
|   const {data} = await api.get('/coupon',{ | ||||
|     params: { | ||||
|       user_id: userStore.user.id | ||||
|     } | ||||
|   }) | ||||
|   if (data.success) { | ||||
|     coupons.value = data.coupon | ||||
|     console.log(123,coupons.value) | ||||
|   } else { | ||||
|     ElMessage.error(data.message || '优惠券领取失败') | ||||
|   } | ||||
| } | ||||
|  | ||||
| const getCoupon = async (coupon_type,coupon_id) => { | ||||
|   try { | ||||
|     console.log(userStore) | ||||
|     const {data} = await api.get(`/coupon/${userStore.user.id}`,{ | ||||
|       params: { | ||||
|         coupon_type: coupon_type, | ||||
|         coupon_id: coupon_id | ||||
|       } | ||||
|     }) | ||||
| @@ -50,18 +116,23 @@ const getCoupon = async (coupon_id) => { | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
|   // getCoupon() | ||||
|   getAllCoupons() | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .coupon-container { | ||||
|   width: 100%; | ||||
|   height: 100vh; | ||||
|   background-image: url(/imgs/shop/coupon/background.png); | ||||
| } | ||||
|  | ||||
| .header { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   padding-left: 20px; | ||||
|   position: relative; | ||||
|   margin-top: 25px; | ||||
| } | ||||
|  | ||||
| .back-btn { | ||||
| @@ -74,22 +145,161 @@ onMounted(() => { | ||||
|   position: absolute; | ||||
|   left: 0; | ||||
|   margin-left: 30px; | ||||
|    margin-top: 5px; | ||||
|   margin-top: 5px; | ||||
| } | ||||
|  | ||||
| .text { | ||||
| .header-text { | ||||
|   width: 80px; | ||||
|   height: 28px; | ||||
|   angle: 0 deg; | ||||
|   opacity: 1; | ||||
|   font-family: SF Pro; | ||||
|   font-weight: 650; | ||||
|   font-style: Expanded Semibold; | ||||
|   font-size: 20px; | ||||
|   leading-trim: NONE; | ||||
|   line-height: 28px; | ||||
|   letter-spacing: 0%; | ||||
|   color: #2F4FB5; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| .coupon-content { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   align-items: center; | ||||
|   margin-top: 20px; | ||||
|   padding: 20px; | ||||
|   height: 100vh; | ||||
| } | ||||
|  | ||||
| .discount_for_a_amount_container, | ||||
| .discount_container, | ||||
| .deduction_container { | ||||
|   background: white; | ||||
|   width: 348px; | ||||
|   padding: 10px; | ||||
|   top: 32px; | ||||
|   opacity: 1; | ||||
|   border-radius: 8px; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
|  | ||||
| .container-title { | ||||
|   width: 96; | ||||
|   height: 20; | ||||
|   top: 324px; | ||||
|   left: 105px; | ||||
|   opacity: 1; | ||||
|   font-family: SF Pro; | ||||
|   font-weight: 700; | ||||
|   font-style: Bold; | ||||
|   font-size: 16px; | ||||
|   line-height: 20px; | ||||
|   letter-spacing: 0%; | ||||
|   color: #2F4FB5; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| .coupon-filtered-item { | ||||
|   width: 324px; | ||||
|   height: 66px; | ||||
|   top: 58px; | ||||
|   left: 12px; | ||||
|   opacity: 1; | ||||
|   background-size: 100% 100%; | ||||
|   margin-top: 10px; | ||||
|  | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: space-between; | ||||
|   padding: 0 20px; | ||||
| } | ||||
|  | ||||
| .text-left { | ||||
|   font-size: 25px; | ||||
|   font-weight: bold; | ||||
|   color: #305DEF; | ||||
| } | ||||
|  | ||||
| .text-mid-w { | ||||
|   font-size: 14px; | ||||
|   color: #305DEF; | ||||
|   flex: 1; | ||||
|   text-align: center; | ||||
|   font-family: SF Pro; | ||||
|   font-weight: 590; | ||||
|   font-style: Semibold; | ||||
|   font-size: 16px; | ||||
|   line-height: 20px; | ||||
|   letter-spacing: 0%; | ||||
| } | ||||
|  | ||||
| .text-right { | ||||
|   font-size: 14px; | ||||
|   color: #ffffff; | ||||
|   cursor: pointer; | ||||
|   padding: 5px 10px; | ||||
|   border-radius: 100px; | ||||
|   background: #305DEF; | ||||
|   transition: background-color 0.3s; | ||||
|   margin-right: -10px; | ||||
| } | ||||
|  | ||||
| .text-right:hover { | ||||
|   background-color: #305DEF; | ||||
| } | ||||
|  | ||||
| .grid-container { | ||||
|   display: grid; | ||||
|   grid-template-columns: repeat(3, 1fr); | ||||
|   gap: 10px; | ||||
|   justify-items: center; | ||||
| } | ||||
|  | ||||
| .coupon-item { | ||||
|   display: contents; | ||||
| } | ||||
|  | ||||
| .coupon-filtered-item2 { | ||||
|   width: 83px; | ||||
|   height: 94px; | ||||
|   opacity: 1; | ||||
|   border-radius: 4px; | ||||
|   background-size: 100% 100%; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   align-items: center; | ||||
|   justify-content: space-between; | ||||
|   padding: 10px 0; | ||||
| } | ||||
|  | ||||
| .text-top { | ||||
|   font-family: SF Pro; | ||||
|   font-weight: 700; | ||||
|   font-style: Bold; | ||||
|   font-size: 18px; | ||||
|   line-height: 20px; | ||||
|   letter-spacing: 0%; | ||||
|   color: #305DEF; | ||||
| } | ||||
|  | ||||
| .text-mid-h { | ||||
|   font-family: SF Pro; | ||||
|   font-weight: 400; | ||||
|   font-style: Regular; | ||||
|   font-size: 15px; | ||||
|   line-height: 20px; | ||||
|   letter-spacing: 0%; | ||||
|   color: #305DEF; | ||||
|   margin-top: 10px; | ||||
| } | ||||
|  | ||||
| .text-bottom { | ||||
|   font-size: 10px; | ||||
|   color: #305DEF; | ||||
|   cursor: pointer; | ||||
|   padding: 5px 10px; | ||||
|   border-radius: 100px; | ||||
|   transition: background-color 0.3s; | ||||
|   margin-top: 8px; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -384,7 +384,7 @@ import { | ||||
|   Orange, | ||||
|   Check | ||||
| } from '@element-plus/icons-vue' | ||||
| import api from '@/utils/api' | ||||
| import api, { buyAPI } from '@/utils/api' | ||||
| import { getImageUrl } from '@/config' | ||||
|  | ||||
| const route = useRoute() | ||||
| @@ -418,10 +418,10 @@ const totalPointsPrice = computed(() => { | ||||
|   }, 0) | ||||
| }) | ||||
|  | ||||
| // 计算人民币价格(融豆价格1:1换算) | ||||
| // 计算人民币价格(1融豆 = 1元) | ||||
| const getRMBPrice = () => { | ||||
|   const totalRongdou = totalRongdouPrice.value | ||||
|   return (totalRongdou).toFixed(2) // 假设1融豆=0.01元,可根据实际汇率调整 | ||||
|   return (totalRongdou).toFixed(2) | ||||
| } | ||||
| // 用户余额数据 | ||||
| const userBalance = ref({ | ||||
| @@ -747,7 +747,27 @@ const confirmPayment = async () => { | ||||
|  | ||||
|     paying.value = true | ||||
|  | ||||
|     // 创建订单数据 | ||||
|     if (selectedPaymentMethod.value === 'wechat_h5' || selectedPaymentMethod.value === 'alipay_wap') { | ||||
|       const amount = Number(getRMBPrice()) | ||||
|       const response = await buyAPI.buy({ | ||||
|         paymentMethod: selectedPaymentMethod.value, | ||||
|         amount: amount*100 | ||||
|       }) | ||||
|        | ||||
|       if (response?.data?.success) { | ||||
|         const payUrl = response.data.data?.payUrl | ||||
|         if (payUrl) { | ||||
|           window.location.href = payUrl | ||||
|           return | ||||
|         } else { | ||||
|           throw new Error('未获取到支付链接') | ||||
|         } | ||||
|       } else { | ||||
|         throw new Error(response?.data?.message || '创建支付订单失败') | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // 其他支付方式:走原订单确认流程 | ||||
|     const orderData = { | ||||
|       orderId: paymentData.value.orderId, | ||||
|       addressId: selectedAddress.value.id, | ||||
| @@ -756,40 +776,12 @@ const confirmPayment = async () => { | ||||
|       beansAmount: paymentData.value.beansAmount | ||||
|     } | ||||
|  | ||||
|     // 向后端发送订单支付请求 | ||||
|     const response = await api.post('/orders/confirm-payment', orderData) | ||||
|      | ||||
|     if (response.data.success) { | ||||
|       // 微信支付 | ||||
|       if (selectedPaymentMethod.value === 'wechat_h5') { | ||||
|         // 获取支付URL并跳转 | ||||
|         const payUrl = response.data.data?.payUrl | ||||
|         if (payUrl) { | ||||
|           // 跳转到第三方支付页面 | ||||
|           window.location.href = payUrl | ||||
|           return // 不再执行后续代码 | ||||
|         } | ||||
|       } | ||||
|        | ||||
|       // 支付宝支付 | ||||
|       if (selectedPaymentMethod.value === 'alipay_wap') { | ||||
|         // 获取支付URL并跳转 | ||||
|         const payUrl = response.data.data?.payUrl | ||||
|         if (payUrl) { | ||||
|           // 跳转到支付宝支付页面 | ||||
|           window.location.href = payUrl | ||||
|           return // 不再执行后续代码 | ||||
|         } | ||||
|       } | ||||
|        | ||||
|       ElMessage.success('订单创建成功!') | ||||
|        | ||||
|       // 跳转到PayLoading页面,传递订单ID | ||||
|       router.push({ | ||||
|         path: '/payloading', | ||||
|         query: { | ||||
|           orderId: paymentData.value.orderId | ||||
|         } | ||||
|         query: { orderId: paymentData.value.orderId } | ||||
|       }) | ||||
|     } else { | ||||
|       throw new Error(response.data.message || '创建订单失败') | ||||
|   | ||||
| @@ -309,6 +309,7 @@ const getProductDetail = async () => { | ||||
|     }) | ||||
|   } catch (error) { | ||||
|     ElMessage.error('获取商品详情失败') | ||||
|     console.log('获取商品详情失败',error); | ||||
|     router.go(-1) | ||||
|   } finally { | ||||
|     loading.value = false | ||||
|   | ||||
| @@ -16,7 +16,12 @@ export default defineConfig({ | ||||
|     proxy: { | ||||
|       '/api': { | ||||
|         target: 'http://192.168.0.26:3000', | ||||
|         changeOrigin: true | ||||
|         changeOrigin: true, | ||||
|       }, | ||||
|       '/mid': { | ||||
|         target: 'http://192.168.0.12:3005', | ||||
|         changeOrigin: true, | ||||
|         // rewrite: (path) => path.replace(/^\/mid/, '') | ||||
|       }, | ||||
|       '/uploads': { | ||||
|         target: 'http://192.168.0.26:3000', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user