diff --git a/gym-manage-uniapp/App.vue b/gym-manage-uniapp/App.vue
index dabb9d5..7e8caf1 100644
--- a/gym-manage-uniapp/App.vue
+++ b/gym-manage-uniapp/App.vue
@@ -1,28 +1,82 @@
+
-
+
\ No newline at end of file
diff --git a/gym-manage-uniapp/api/main.js b/gym-manage-uniapp/api/main.js
new file mode 100644
index 0000000..eb59c09
--- /dev/null
+++ b/gym-manage-uniapp/api/main.js
@@ -0,0 +1,50 @@
+import request from "@/utils/request.js"
+
+export function login(params) {
+ return request.post('/member/auth/miniapp/login', params)
+}
+
+export function logout() {
+ return request.post('/member/auth/logout')
+}
+
+export function getQRCode(options = { cache: true, cacheTime: 5 * 60 * 1000 }) {
+ return request.get('/checkIn/qrcode', {}, options)
+}
+
+export function checkIn(params) {
+ return request.post('/checkIn/scan', params)
+}
+
+export function getUserInfo(options = { cache: true, cacheTime: 30 * 60 * 1000 }) {
+ return request.get('/member/info', {}, options)
+}
+
+export function updateUserInfo(params) {
+ return request.put('/member/info', params)
+}
+
+export function getRecommendCourses(options = { cache: true, cacheTime: 10 * 60 * 1000 }) {
+ return request.get('/course/recommend', {}, options)
+}
+
+export function getCourseDetail(id, options = { cache: true, cacheTime: 15 * 60 * 1000 }) {
+ return request.get(`/course/${id}`, {}, options)
+}
+
+export function getGroupCoursePage(params = {}, options = { cache: true, cacheTime: 5 * 60 * 1000 }) {
+ const { page = 0, size = 10, sort = 'id', order = 'asc', keyword } = params
+ return request.post('/groupCourse/page', { page, size, sort, order, keyword }, options)
+}
+
+export default {
+ login,
+ logout,
+ getQRCode,
+ checkIn,
+ getUserInfo,
+ updateUserInfo,
+ getRecommendCourses,
+ getCourseDetail,
+ getGroupCoursePage
+}
diff --git a/gym-manage-uniapp/common/constants/routes.js b/gym-manage-uniapp/common/constants/routes.js
index e824abc..dada154 100644
--- a/gym-manage-uniapp/common/constants/routes.js
+++ b/gym-manage-uniapp/common/constants/routes.js
@@ -1,7 +1,7 @@
/** 与 pages.json 保持一致 */
export const PAGE = {
INDEX: '/pages/index/index',
- COURSE: '/pages/groupCourse/list',
+ COURSE: '/pages/course/index',
TRAIN: '/pages/train/index',
DISCOVER: '/pages/discover/index',
MEMBER: '/pages/memberInfo/memberInfo',
diff --git a/gym-manage-uniapp/components/TabBar.vue b/gym-manage-uniapp/components/TabBar.vue
index 8ad3aee..4922c27 100644
--- a/gym-manage-uniapp/components/TabBar.vue
+++ b/gym-manage-uniapp/components/TabBar.vue
@@ -1,14 +1,15 @@
+
@@ -18,7 +19,7 @@
+
\ No newline at end of file
diff --git a/gym-manage-uniapp/pages.json b/gym-manage-uniapp/pages.json
index da2f516..b22206c 100644
--- a/gym-manage-uniapp/pages.json
+++ b/gym-manage-uniapp/pages.json
@@ -3,32 +3,52 @@
{
"path": "pages/index/index",
"style": {
- "navigationBarTitleText": "健身房"
+ "navigationBarTitleText": "健身房",
+ "app-plus": {
+ "animationType": "fade-in",
+ "animationDuration": 200
+ }
}
},
{
"path": "pages/course/index",
"style": {
- "navigationBarTitleText": "课程"
+ "navigationBarTitleText": "课程",
+ "app-plus": {
+ "animationType": "fade-in",
+ "animationDuration": 200
+ }
}
},
{
"path": "pages/train/index",
"style": {
- "navigationBarTitleText": "训练"
+ "navigationBarTitleText": "训练",
+ "app-plus": {
+ "animationType": "fade-in",
+ "animationDuration": 200
+ }
}
},
{
"path": "pages/discover/index",
"style": {
- "navigationBarTitleText": "发现"
+ "navigationBarTitleText": "发现",
+ "app-plus": {
+ "animationType": "fade-in",
+ "animationDuration": 200
+ }
}
},
{
"path": "pages/memberInfo/memberInfo",
"style": {
"navigationStyle": "custom",
- "navigationBarTitleText": "我的"
+ "navigationBarTitleText": "我的",
+ "app-plus": {
+ "animationType": "fade-in",
+ "animationDuration": 200
+ }
}
},
{
@@ -231,13 +251,39 @@
"navigationBarTitleText": "课程详情",
"navigationStyle": "custom"
}
+ },
+ {
+ "path": "pages/LoadingOverlay/LoadingOverlay",
+ "style": {
+ "navigationBarTitleText": ""
+ }
+ },
+ {
+ "path": "pages/searchCourse/searchCourse",
+ "style": {
+ "navigationBarTitleText": "搜索课程"
+ }
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "健身房",
"navigationBarBackgroundColor": "#F8F8F8",
- "backgroundColor": "#F8F8F8"
+ "backgroundColor": "#F8F8F8",
+ "app-plus": {
+ "animationType": "pop-in",
+ "animationDuration": 200
+ }
},
- "uniIdRouter": {}
+ "uniIdRouter": {},
+ "tabBar": {
+ "custom": true, // 启用自定义 tabBar
+ "list": [
+ { "pagePath": "pages/index/index", "text": "首页" },
+ { "pagePath": "pages/course/index", "text": "课程" },
+ { "pagePath": "pages/train/index", "text": "训练" },
+ { "pagePath": "pages/discover/index", "text": "发现" },
+ { "pagePath": "pages/memberInfo/memberInfo", "text": "我的" }
+ ]
+ }
}
\ No newline at end of file
diff --git a/gym-manage-uniapp/pages/LoadingOverlay/LoadingOverlay.vue b/gym-manage-uniapp/pages/LoadingOverlay/LoadingOverlay.vue
new file mode 100644
index 0000000..045d1b1
--- /dev/null
+++ b/gym-manage-uniapp/pages/LoadingOverlay/LoadingOverlay.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+ {{ text }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gym-manage-uniapp/pages/checkIn/checkIn.vue b/gym-manage-uniapp/pages/checkIn/checkIn.vue
index 2fbbb26..09ec852 100644
--- a/gym-manage-uniapp/pages/checkIn/checkIn.vue
+++ b/gym-manage-uniapp/pages/checkIn/checkIn.vue
@@ -104,7 +104,7 @@ import { onLoad, onUnload } from '@dcloudio/uni-app'
// 引入状态组件(路径与你保持一致)
import QrStatus from '@/components/QRCode/StatusCard.vue'
// 引入API封装
-import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
+import { getQRCode, checkIn as apiCheckIn } from '@/api/main.js'
let image = ref("")
let width = ref(0)
@@ -115,6 +115,7 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
const QRStatus = ref("生成中...")
const STQRC = ref(false)//是否扫码
const isCheckIn = ref(false)
+ const webSoketURL = "ws://localhost:8084/webSocket/checkIn"
const qrcode = ref("")
@@ -209,22 +210,31 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
}
/**
- * 清除所有QR_开头的缓存(用于测试阶段)
+ * 清除所有与签到相关的缓存(用于测试阶段)
*/
const clearQRCache = () => {
try {
const keys = uni.getStorageInfoSync().keys || []
let clearedCount = 0
for (const key of keys) {
+ // 清除 QR_ 开头的缓存(页面内部缓存)
if (key.startsWith(CACHE_PREFIX)) {
uni.removeStorageSync(key)
clearedCount++
}
+ // 清除 API_CACHE_ 开头的缓存(通过 utils/cache.js 缓存的接口数据)
+ if (key.startsWith('API_CACHE_')) {
+ // 只清除与签到相关的 API 缓存
+ if (key.includes('checkIn') || key.includes('qrcode')) {
+ uni.removeStorageSync(key)
+ clearedCount++
+ }
+ }
}
- console.log(`已清除 ${clearedCount} 个QR_开头的缓存`)
+ console.log(`已清除 ${clearedCount} 个签到相关缓存`)
return clearedCount
} catch (e) {
- console.error('清除QR缓存失败:', e)
+ console.error('清除 QR 缓存失败:', e)
return 0
}
}
@@ -256,10 +266,8 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
duration: 2000
})
- // 重新请求二维码
- setTimeout(() => {
- getStorage(null)
- }, 500)
+ // 重置页面状态后不再自动请求二维码
+ uni.hideLoading()
}
}
})
@@ -319,7 +327,7 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
errorText.value = '' // 重置错误文本
image.value = ""
- getQRCode(true).then(res => {
+ getQRCode({ cache: true, cacheTime: 5 * 60 * 1000 }).then(res => {
console.log(res)
// 保存到本地缓存(用于签到状态判断)
setCacheData("QRInfo", res)
@@ -403,7 +411,7 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
// 手动签到接口
const checkIn = (qrContent) => {
console.log(qrContent)
- apiCheckIn(qrContent).then(res => {
+ apiCheckIn({ qrContent }).then(res => {
closeWebSocket()
console.log(res)
status.value = 'scanned'
@@ -422,17 +430,20 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
console.error('签到请求失败:', err)
status.value = 'error'
errorText.value = err.message || '签到失败,请重试' // 对应错误文案
+ uni.showToast({
+ title: err.message,
+ icon: 'none'
+ })
})
}
// 建立WebSocket连接
const connectWebSocket = (qrContent) => {
- const wsUrl = `ws://192.168.43.89:8084/webSocket/checkIn`
- console.log('WebSocket 连接地址:', wsUrl)
+ console.log('WebSocket 连接地址:', webSoketURL)
socketTask = uni.connectSocket({
- url: wsUrl,
+ url: webSoketURL,
success: () => {
console.log('WebSocket 连接中...')
},
@@ -477,17 +488,27 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
socketTask.onMessage((res) => {
console.log('收到 WebSocket 消息:', res.data)
const message = res.data
-
+
if (message === '正在进行签到') {
+ // 显示遮罩,防止用户重复扫码
QRStatus.value = "正在进行签到..."
STQRC.value = true
- // status.value = 'scanned'
- // errorText.value = '' // 成功重置错误文本
- // uni.showToast({
- // title: '签到成功!',
- // icon: 'success',
- // duration: 2000
- // })
+ } else if (message === '签到成功' || message.includes('签到成功')) {
+ // 签到成功,更新状态
+ status.value = 'scanned'
+ errorText.value = ''
+ isCheckIn.value = true
+ QRStatus.value = "签到成功"
+ // 缓存签到状态
+ setCacheData("isCheckIn", true)
+ setCacheData("checkInTime", "签到成功")
+ uni.showToast({
+ title: '签到成功!',
+ icon: 'success',
+ duration: 2000
+ })
+ // 关闭WebSocket连接
+ closeWebSocket()
} else if (message.startsWith('二维码无效')) {
uni.showToast({
title: message,
@@ -495,18 +516,32 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
duration: 2000
})
status.value = 'error'
- errorText.value = '二维码无效,请刷新' // 对应错误文案
+ errorText.value = '二维码无效,请刷新'
+ // 隐藏遮罩,允许用户重新操作
+ STQRC.value = false
+ QRStatus.value = "生成中..."
setTimeout(() => {
closeWebSocket()
}, 3000)
} else if (message === '消息格式错误') {
- uni.showToast({
- title: '消息格式错误',
- icon: 'none'
- })
status.value = 'error'
- errorText.value = '消息格式错误' // 对应错误文案
- } else {
+ errorText.value = '消息格式错误'
+ // 隐藏遮罩,允许用户重新操作
+ STQRC.value = false
+ QRStatus.value = "生成中..."
+ } else if (message.includes('失败') || message.includes('错误')) {
+ // 其他失败情况
+ uni.showToast({
+ title: message,
+ icon: 'none',
+ duration: 2000
+ })
+ status.value = 'error'
+ errorText.value = message
+ // 隐藏遮罩,允许用户重新操作
+ STQRC.value = false
+ QRStatus.value = "生成中..."
+ } else {
console.log('未知消息:', message)
}
})
@@ -523,10 +558,6 @@ import { getQRCode, checkIn as apiCheckIn } from '@/request_api/main.js'
console.error('WebSocket 错误:', err)
status.value = 'error'
errorText.value = '连接失败,请重试' // 对应错误文案
- uni.showToast({
- title: '连接失败',
- icon: 'none'
- })
})
}
diff --git a/gym-manage-uniapp/pages/course/index.vue b/gym-manage-uniapp/pages/course/index.vue
index dc11910..82113d6 100644
--- a/gym-manage-uniapp/pages/course/index.vue
+++ b/gym-manage-uniapp/pages/course/index.vue
@@ -1,3 +1,4 @@
+
-
-
-
-
- 预约课程
-
-
- 我的课程
+
+
+
+
+
+
+
+
+
+
+
+ 预约课程
+
+
+ 我的课程
+
+
+
+
-
+
+
+
\ No newline at end of file
diff --git a/gym-manage-uniapp/static/tabBar/home.png b/gym-manage-uniapp/static/tabBar/home.png
new file mode 100644
index 0000000..c4220cc
Binary files /dev/null and b/gym-manage-uniapp/static/tabBar/home.png differ
diff --git a/gym-manage-uniapp/utils/cache.js b/gym-manage-uniapp/utils/cache.js
new file mode 100644
index 0000000..5c196ab
--- /dev/null
+++ b/gym-manage-uniapp/utils/cache.js
@@ -0,0 +1,89 @@
+// 缓存相关常量
+const CACHE_PREFIX = 'API_CACHE_'
+const CACHE_EXPIRE_TIME = 5 * 60 * 1000 // 默认缓存时间5分钟
+
+/**
+ * 获取缓存数据
+ * @param {string} key - 缓存键名
+ * @returns {any} 缓存数据(过期返回null)
+ */
+export const getCache = (key) => {
+ try {
+ const cacheData = uni.getStorageSync(CACHE_PREFIX + key)
+ if (cacheData && cacheData.expireTime && Date.now() < cacheData.expireTime) {
+ return cacheData.data
+ }
+ // 缓存过期,清除
+ uni.removeStorageSync(CACHE_PREFIX + key)
+ return null
+ } catch (e) {
+ console.error('获取缓存失败:', e)
+ return null
+ }
+}
+
+/**
+ * 设置缓存数据
+ * @param {string} key - 缓存键名
+ * @param {any} data - 要缓存的数据
+ * @param {number} expireTime - 过期时间(毫秒),默认5分钟
+ */
+export const setCache = (key, data, expireTime = CACHE_EXPIRE_TIME) => {
+ try {
+ const cacheData = {
+ data: data,
+ expireTime: Date.now() + expireTime
+ }
+ uni.setStorageSync(CACHE_PREFIX + key, cacheData)
+ } catch (e) {
+ console.error('设置缓存失败:', e)
+ }
+}
+
+/**
+ * 清除指定缓存
+ * @param {string} key - 缓存键名
+ */
+export const clearCache = (key) => {
+ try {
+ uni.removeStorageSync(CACHE_PREFIX + key)
+ } catch (e) {
+ console.error('清除缓存失败:', e)
+ }
+}
+
+/**
+ * 清除所有API缓存
+ */
+export const clearAllCache = () => {
+ try {
+ const keys = uni.getStorageInfoSync().keys || []
+ for (const key of keys) {
+ if (key.startsWith(CACHE_PREFIX)) {
+ uni.removeStorageSync(key)
+ }
+ }
+ } catch (e) {
+ console.error('清除所有缓存失败:', e)
+ }
+}
+
+/**
+ * 生成请求缓存键名
+ * @param {string} url - 请求URL
+ * @param {object} data - 请求参数
+ * @param {string} method - 请求方法
+ * @returns {string} 缓存键名
+ */
+export const generateCacheKey = (url, data, method) => {
+ const params = JSON.stringify(data || {})
+ return `${method}_${url}_${params}`
+}
+
+export default {
+ getCache,
+ setCache,
+ clearCache,
+ clearAllCache,
+ generateCacheKey
+}
\ No newline at end of file
diff --git a/gym-manage-uniapp/utils/request.js b/gym-manage-uniapp/utils/request.js
index e7a1898..ccffb07 100644
--- a/gym-manage-uniapp/utils/request.js
+++ b/gym-manage-uniapp/utils/request.js
@@ -1,4 +1,4 @@
-const BASE_URL = 'http://192.168.5.15:8084/api'
+const BASE_URL = '/api'
// 缓存相关常量
const CACHE_PREFIX = 'API_CACHE_'
@@ -212,4 +212,21 @@ export const requestUtils = {
clearAllCache
}
+// 添加便捷方法
+request.get = (url, data = {}, options = {}) => {
+ return request({ url, method: 'GET', data, ...options })
+}
+
+request.post = (url, data = {}, options = {}) => {
+ return request({ url, method: 'POST', data, ...options })
+}
+
+request.put = (url, data = {}, options = {}) => {
+ return request({ url, method: 'PUT', data, ...options })
+}
+
+request.delete = (url, data = {}, options = {}) => {
+ return request({ url, method: 'DELETE', data, ...options })
+}
+
export default request
diff --git a/gym-manage-uniapp/vite.config.js b/gym-manage-uniapp/vite.config.js
index 879e01c..400a2ca 100644
--- a/gym-manage-uniapp/vite.config.js
+++ b/gym-manage-uniapp/vite.config.js
@@ -7,17 +7,22 @@ export default defineConfig({
plugins: [uni()],
resolve: {
alias: {
- '@': path.resolve(__dirname, 'src')
+ '@': path.resolve(__dirname, '.')
},
},
server: {
proxy: {
- // 匹配所有 /api 开头的请求
+ // 匹配所有 /api/ 开头的请求(排除静态文件)
'/api': {
target: 'http://192.168.5.15:8084', // 你的后端SpringBoot地址
changeOrigin: true, // 开启跨域伪装
- // rewrite: (path) => path.replace(/^\/areyouok/, '')
- // 举例:前端请求 /api/login → 代理成 http://localhost:8088/login
+ // 只代理真正的后端API请求,排除 .js .vue 等静态文件
+ bypass: function(req, res, proxyOptions) {
+ if (req.url.indexOf('.js') !== -1 || req.url.indexOf('.vue') !== -1 ||
+ req.url.indexOf('.css') !== -1 || req.url.indexOf('.json') !== -1) {
+ return req.url
+ }
+ }
}
}
}