From 7e45ecd1446f5696b46c1081369ccee6987d4ffe Mon Sep 17 00:00:00 2001 From: liwentao Date: Wed, 15 Jul 2026 17:26:07 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E9=87=8D=E5=86=99=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E7=AB=AF=EF=BC=8C=E5=88=9D=E6=AD=A5=E5=AE=8C=E5=96=84=E9=A6=96?= =?UTF-8?q?=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gym-manage-uniapp/.gitignore | 4 + gym-manage-uniapp/App.vue | 25 + gym-manage-uniapp/exmp/style1.html | 624 ++++++++++++++++++ gym-manage-uniapp/exmp/style2.html | 590 +++++++++++++++++ gym-manage-uniapp/exmp/style3.html | 591 +++++++++++++++++ gym-manage-uniapp/index.html | 20 + gym-manage-uniapp/main.js | 22 + gym-manage-uniapp/manifest.json | 128 ++-- gym-manage-uniapp/package-lock.json | 22 + gym-manage-uniapp/package.json | 21 +- gym-manage-uniapp/pages.json | 90 ++- .../pages/course-detail/course-detail.vue | 202 ++++++ gym-manage-uniapp/pages/index/index.vue | 171 +++++ gym-manage-uniapp/pages/login/login.vue | 101 +++ gym-manage-uniapp/pages/profile/profile.vue | 211 ++++++ gym-manage-uniapp/pages/search/search.vue | 241 +++++++ gym-manage-uniapp/src/api/index.js | 29 - gym-manage-uniapp/src/pages/index/index.vue | 40 -- gym-manage-uniapp/src/store/index.ts | 5 - gym-manage-uniapp/src/store/user.ts | 27 - gym-manage-uniapp/static/logo.png | Bin 0 -> 4023 bytes gym-manage-uniapp/style/base/style1.css | 96 +++ gym-manage-uniapp/style/base/style2.css | 129 ++++ gym-manage-uniapp/style/base/style3.css | 126 ++++ gym-manage-uniapp/uni.promisify.adaptor.js | 13 + gym-manage-uniapp/uni.scss | 76 +++ 26 files changed, 3405 insertions(+), 199 deletions(-) create mode 100644 gym-manage-uniapp/.gitignore create mode 100644 gym-manage-uniapp/App.vue create mode 100644 gym-manage-uniapp/exmp/style1.html create mode 100644 gym-manage-uniapp/exmp/style2.html create mode 100644 gym-manage-uniapp/exmp/style3.html create mode 100644 gym-manage-uniapp/index.html create mode 100644 gym-manage-uniapp/main.js create mode 100644 gym-manage-uniapp/package-lock.json create mode 100644 gym-manage-uniapp/pages/course-detail/course-detail.vue create mode 100644 gym-manage-uniapp/pages/index/index.vue create mode 100644 gym-manage-uniapp/pages/login/login.vue create mode 100644 gym-manage-uniapp/pages/profile/profile.vue create mode 100644 gym-manage-uniapp/pages/search/search.vue delete mode 100644 gym-manage-uniapp/src/api/index.js delete mode 100644 gym-manage-uniapp/src/pages/index/index.vue delete mode 100644 gym-manage-uniapp/src/store/index.ts delete mode 100644 gym-manage-uniapp/src/store/user.ts create mode 100644 gym-manage-uniapp/static/logo.png create mode 100644 gym-manage-uniapp/style/base/style1.css create mode 100644 gym-manage-uniapp/style/base/style2.css create mode 100644 gym-manage-uniapp/style/base/style3.css create mode 100644 gym-manage-uniapp/uni.promisify.adaptor.js create mode 100644 gym-manage-uniapp/uni.scss diff --git a/gym-manage-uniapp/.gitignore b/gym-manage-uniapp/.gitignore new file mode 100644 index 0000000..2370852 --- /dev/null +++ b/gym-manage-uniapp/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +unpackage/ +.hbuilderx/ +.DS_Store diff --git a/gym-manage-uniapp/App.vue b/gym-manage-uniapp/App.vue new file mode 100644 index 0000000..589851a --- /dev/null +++ b/gym-manage-uniapp/App.vue @@ -0,0 +1,25 @@ + + + diff --git a/gym-manage-uniapp/exmp/style1.html b/gym-manage-uniapp/exmp/style1.html new file mode 100644 index 0000000..f907f13 --- /dev/null +++ b/gym-manage-uniapp/exmp/style1.html @@ -0,0 +1,624 @@ + + + + + + 健身房预约 · 配色方案展示 + + + + + + + +
+ +
+ 9:41 + 📶 📶 🔋 +
+ + + + + +
+ + +
+
+ 👋 你好,Jason + 🔥 今日 420 kcal +
+
+
+ 68 + 总课时 +
+
+ 12 + 连续打卡 +
+
+ 4.8 + ⭐ 评分 +
+
+
+ + +
+ 全部 + 力量区 + 有氧 + 瑜伽 + 私教 + 团课 +
+ + +
+
+ 12 + 周日 +
+
+ 13 + 周一 +
+
+ 14 + 周二 +
+
+ 15 + 周三 +
+
+ 16 + 周四 +
+
+ + +
+
🏋️
+
+
综合力量训练
+
+ ⏱️ 45 min + 🔥 热门 + 📍 力量区 +
+
+ +
+ + +
+
🧘
+
+
流瑜伽 · 中级
+
+ ⏱️ 60 min + 🧘 瑜伽 + 📍 3号教室 +
+
+ +
+ + +
+
🚴
+
+
动感单车 · 冲刺
+
+ ⏱️ 40 min + ⚡ 有氧 + 📍 单车房 +
+
+ +
+ + +
+
+
J
+
+

Jason Wang

+

🏆 高级会员 · 已练 68 课时

+
+
+ +
+ +
配色方案 · 能量黑 + 荧光绿 · 预约小程序
+
+ + +
+
+ 🏠 + 首页 +
+
+ 📅 + 课程 +
+ +
+ + 预约 +
+
+ 💬 + 消息 +
+
+ 👤 + 我的 +
+
+
+ + \ No newline at end of file diff --git a/gym-manage-uniapp/exmp/style2.html b/gym-manage-uniapp/exmp/style2.html new file mode 100644 index 0000000..14d9474 --- /dev/null +++ b/gym-manage-uniapp/exmp/style2.html @@ -0,0 +1,590 @@ + + + + + + 健身房预约 · 极光紫配色 + + + + + + +
+ +
+ 9:41 + 📶 📶 🔋 +
+ + + + + +
+ +
+
+ 👋 你好,Jason + 🔥 今日 420 kcal +
+
+
+ 68 + 总课时 +
+
+ 12 + 连续打卡 +
+
+ 4.8 + ⭐ 评分 +
+
+
+ + +
+ 全部 + 力量区 + 有氧 + 瑜伽 + 私教 + 团课 +
+ + +
+
+ 12 + 周日 +
+
+ 13 + 周一 +
+
+ 14 + 周二 +
+
+ 15 + 周三 +
+
+ 16 + 周四 +
+
+ + +
+
🏋️
+
+
综合力量训练
+
+ ⏱️ 45 min + 🔥 热门 + 📍 力量区 +
+
+ +
+ + +
+
🧘
+
+
流瑜伽 · 中级
+
+ ⏱️ 60 min + 🧘 瑜伽 + 📍 3号教室 +
+
+ +
+ + +
+
🚴
+
+
动感单车 · 冲刺
+
+ ⏱️ 40 min + ⚡ 有氧 + 📍 单车房 +
+
+ +
+ + +
+
+
J
+
+

Jason Wang

+

🏆 高级会员 · 已练 68 课时

+
+
+ +
+ +
配色方案 · 极光紫 · 科技感预约小程序
+
+ + +
+
+ 🏠 + 首页 +
+
+ 📅 + 课程 +
+
+ + 预约 +
+
+ 💬 + 消息 +
+
+ 👤 + 我的 +
+
+
+ + \ No newline at end of file diff --git a/gym-manage-uniapp/exmp/style3.html b/gym-manage-uniapp/exmp/style3.html new file mode 100644 index 0000000..cf3fb71 --- /dev/null +++ b/gym-manage-uniapp/exmp/style3.html @@ -0,0 +1,591 @@ + + + + + + 健身房预约 · 珊瑚橙配色 + + + + + + +
+ +
+ 9:41 + 📶 📶 🔋 +
+ + + + + +
+ +
+
+ 👋 你好,Jason + 🔥 今日 420 kcal +
+
+
+ 68 + 总课时 +
+
+ 12 + 连续打卡 +
+
+ 4.8 + ⭐ 评分 +
+
+
+ + +
+ 全部 + 力量区 + 有氧 + 瑜伽 + 私教 + 团课 +
+ + +
+
+ 12 + 周日 +
+
+ 13 + 周一 +
+
+ 14 + 周二 +
+
+ 15 + 周三 +
+
+ 16 + 周四 +
+
+ + +
+
🏋️
+
+
综合力量训练
+
+ ⏱️ 45 min + 🔥 热门 + 📍 力量区 +
+
+ +
+ + +
+
🧘
+
+
流瑜伽 · 中级
+
+ ⏱️ 60 min + 🧘 瑜伽 + 📍 3号教室 +
+
+ +
+ + +
+
🚴
+
+
动感单车 · 冲刺
+
+ ⏱️ 40 min + ⚡ 有氧 + 📍 单车房 +
+
+ +
+ + +
+
+
J
+
+

Jason Wang

+

🏆 高级会员 · 已练 68 课时

+
+
+ +
+ +
配色方案 · 珊瑚橙 · 温暖活力预约小程序
+
+ + +
+
+ 🏠 + 首页 +
+
+ 📅 + 课程 +
+
+ + 预约 +
+
+ 💬 + 消息 +
+
+ 👤 + 我的 +
+
+
+ + \ No newline at end of file diff --git a/gym-manage-uniapp/index.html b/gym-manage-uniapp/index.html new file mode 100644 index 0000000..b5d330d --- /dev/null +++ b/gym-manage-uniapp/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + diff --git a/gym-manage-uniapp/main.js b/gym-manage-uniapp/main.js new file mode 100644 index 0000000..c1caf36 --- /dev/null +++ b/gym-manage-uniapp/main.js @@ -0,0 +1,22 @@ +import App from './App' + +// #ifndef VUE3 +import Vue from 'vue' +import './uni.promisify.adaptor' +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + ...App +}) +app.$mount() +// #endif + +// #ifdef VUE3 +import { createSSRApp } from 'vue' +export function createApp() { + const app = createSSRApp(App) + return { + app + } +} +// #endif \ No newline at end of file diff --git a/gym-manage-uniapp/manifest.json b/gym-manage-uniapp/manifest.json index 39bd84f..66c6a64 100644 --- a/gym-manage-uniapp/manifest.json +++ b/gym-manage-uniapp/manifest.json @@ -1,64 +1,72 @@ { - "name": "gym-manage-uniapp", - "appid": "", - "description": "Gym Management System Mobile App", - "versionName": "1.0.0", - "versionCode": "100", - "transformPx": false, - "app-plus": { - "usingComponents": true, - "nvueStyleCompiler": "uni-app", - "compilerVersion": 3, - "splashscreen": { - "alwaysShowBeforeRender": true, - "waiting": true, - "autoclose": true, - "delay": 0 + "name" : "gym-manage-uniapp", + "appid" : "", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } }, - "modules": {}, - "distribute": { - "android": { - "permissions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - "ios": {}, - "sdkConfigs": {} - } - }, - "quickapp": {}, - "mp-weixin": { - "appid": "", - "setting": { - "urlCheck": false + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true }, - "usingComponents": true - }, - "mp-alipay": { - "usingComponents": true - }, - "mp-baidu": { - "usingComponents": true - }, - "mp-toutiao": { - "usingComponents": true - }, - "uniStatistics": { - "enable": false - }, - "vueVersion": "3" + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "2" } diff --git a/gym-manage-uniapp/package-lock.json b/gym-manage-uniapp/package-lock.json new file mode 100644 index 0000000..51562fb --- /dev/null +++ b/gym-manage-uniapp/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "gym-manage-uniapp", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gym-manage-uniapp", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@dcloudio/uni-ui": "^1.5.12" + } + }, + "node_modules/@dcloudio/uni-ui": { + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.12.tgz", + "integrity": "sha512-mGDl2OZSz7D8xcUAzJegWDHOqB4MEFBSW9Esb/oJiu2/3Gk9+P/Z4bA4JZ9jv9VWBYbMrYwaTfK1Z728kABdYg==", + "license": "Apache-2.0" + } + } +} diff --git a/gym-manage-uniapp/package.json b/gym-manage-uniapp/package.json index c3506cd..c6761e7 100644 --- a/gym-manage-uniapp/package.json +++ b/gym-manage-uniapp/package.json @@ -1,19 +1,16 @@ { "name": "gym-manage-uniapp", "version": "1.0.0", - "description": "Gym Management System Mobile App", + "description": "", "main": "main.js", "scripts": { - "dev:mp-weixin": "uni -p mp-weixin", - "build:mp-weixin": "uni build -p mp-weixin", - "dev:h5": "uni", - "build:h5": "uni build" + "test": "echo \"Error: no test specified\" && exit 1" }, - "keywords": [ - "uniapp", - "gym", - "management" - ], - "author": "Novalon", - "license": "MIT" + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "@dcloudio/uni-ui": "^1.5.12" + } } diff --git a/gym-manage-uniapp/pages.json b/gym-manage-uniapp/pages.json index bd13bd5..9beaa3e 100644 --- a/gym-manage-uniapp/pages.json +++ b/gym-manage-uniapp/pages.json @@ -1,28 +1,66 @@ { - "pages": [ - { - "path": "pages/index/index", - "style": { - "navigationBarTitleText": "首页" - } - } - ], - "globalStyle": { - "navigationBarTextStyle": "black", - "navigationBarTitleText": "健身房管理系统", - "navigationBarBackgroundColor": "#F8F8F8", - "backgroundColor": "#F8F8F8" - }, - "tabBar": { - "color": "#7A7E83", - "selectedColor": "#007AFF", - "borderStyle": "black", - "backgroundColor": "#F8F8F8", - "list": [ - { - "pagePath": "pages/index/index", - "text": "首页" - } - ] - } + "pages": [ + { + "path": "pages/login/login", + "style": { + "navigationBarTitleText": "登录", + "navigationStyle": "custom" + } + }, + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页", + "navigationStyle": "custom" + } + }, + { + "path": "pages/search/search", + "style": { + "navigationBarTitleText": "团课搜索", + "navigationStyle": "custom" + } + }, + { + "path": "pages/course-detail/course-detail", + "style": { + "navigationBarTitleText": "课程详情", + "navigationStyle": "custom" + } + }, + { + "path": "pages/profile/profile", + "style": { + "navigationBarTitleText": "个人中心", + "navigationStyle": "custom" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "Novalon健身房", + "navigationBarBackgroundColor": "#1A1A1A", + "backgroundColor": "#F5F7FA" + }, + "tabBar": { + "color": "#7A7E84", + "selectedColor": "#00E676", + "backgroundColor": "#1A1A1A", + "borderStyle": "black", + "list": [ + { + "pagePath": "pages/index/index", + "text": "首页" + }, + { + "pagePath": "pages/search/search", + "text": "课程" + }, + { + "pagePath": "pages/profile/profile", + "text": "我的" + } + ] + }, + "uniIdRouter": {} } diff --git a/gym-manage-uniapp/pages/course-detail/course-detail.vue b/gym-manage-uniapp/pages/course-detail/course-detail.vue new file mode 100644 index 0000000..84b7824 --- /dev/null +++ b/gym-manage-uniapp/pages/course-detail/course-detail.vue @@ -0,0 +1,202 @@ + + + + + diff --git a/gym-manage-uniapp/pages/index/index.vue b/gym-manage-uniapp/pages/index/index.vue new file mode 100644 index 0000000..490e6b2 --- /dev/null +++ b/gym-manage-uniapp/pages/index/index.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/gym-manage-uniapp/pages/login/login.vue b/gym-manage-uniapp/pages/login/login.vue new file mode 100644 index 0000000..ced1e1a --- /dev/null +++ b/gym-manage-uniapp/pages/login/login.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/gym-manage-uniapp/pages/profile/profile.vue b/gym-manage-uniapp/pages/profile/profile.vue new file mode 100644 index 0000000..5566267 --- /dev/null +++ b/gym-manage-uniapp/pages/profile/profile.vue @@ -0,0 +1,211 @@ + + + + + diff --git a/gym-manage-uniapp/pages/search/search.vue b/gym-manage-uniapp/pages/search/search.vue new file mode 100644 index 0000000..63e53c4 --- /dev/null +++ b/gym-manage-uniapp/pages/search/search.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/gym-manage-uniapp/src/api/index.js b/gym-manage-uniapp/src/api/index.js deleted file mode 100644 index f29ddad..0000000 --- a/gym-manage-uniapp/src/api/index.js +++ /dev/null @@ -1,29 +0,0 @@ -const BASE_URL = 'http://localhost:8080/api' - -export const request = (options) => { - return new Promise((resolve, reject) => { - uni.request({ - url: BASE_URL + options.url, - method: options.method || 'GET', - data: options.data || {}, - header: { - 'Content-Type': 'application/json', - ...options.header - }, - success: (res) => { - if (res.statusCode === 200) { - resolve(res.data) - } else { - reject(res) - } - }, - fail: (err) => { - reject(err) - } - }) - }) -} - -export default { - request -} diff --git a/gym-manage-uniapp/src/pages/index/index.vue b/gym-manage-uniapp/src/pages/index/index.vue deleted file mode 100644 index 5b7705f..0000000 --- a/gym-manage-uniapp/src/pages/index/index.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - - - diff --git a/gym-manage-uniapp/src/store/index.ts b/gym-manage-uniapp/src/store/index.ts deleted file mode 100644 index 8a05980..0000000 --- a/gym-manage-uniapp/src/store/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createPinia } from 'pinia' - -const pinia = createPinia() - -export default pinia diff --git a/gym-manage-uniapp/src/store/user.ts b/gym-manage-uniapp/src/store/user.ts deleted file mode 100644 index 6b67a0b..0000000 --- a/gym-manage-uniapp/src/store/user.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { defineStore } from 'pinia' - -export const useUserStore = defineStore('user', { - state: () => ({ - token: '', - userInfo: null - }), - - getters: { - isLoggedIn: (state) => !!state.token - }, - - actions: { - setToken(token) { - this.token = token - }, - - setUserInfo(userInfo) { - this.userInfo = userInfo - }, - - logout() { - this.token = '' - this.userInfo = null - } - } -}) diff --git a/gym-manage-uniapp/static/logo.png b/gym-manage-uniapp/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b5771e209bb677e2ebd5ff766ad5ee11790f305a GIT binary patch literal 4023 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 SYs}WS&%*SCNx89m_ { + res.then((res) => { + if (!res) return resolve(res) + return res[0] ? reject(res[0]) : resolve(res[1]) + }); + }); + }, +}); \ No newline at end of file diff --git a/gym-manage-uniapp/uni.scss b/gym-manage-uniapp/uni.scss new file mode 100644 index 0000000..b9249e9 --- /dev/null +++ b/gym-manage-uniapp/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; -- 2.54.0 From a9ccdab421326c139facf8602bba94abe5f49777 Mon Sep 17 00:00:00 2001 From: liwentao Date: Thu, 16 Jul 2026 17:29:27 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=89=8D=E5=90=8E=E7=AB=AF=E7=9B=B8=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filter/RbacAuthorizationFilter.java | 8 +- .../src/main/resources/application.yml | 2 +- gym-manage-uniapp/api/auth.js | 12 + gym-manage-uniapp/api/booking.js | 34 +++ gym-manage-uniapp/api/course.js | 40 +++ gym-manage-uniapp/api/member.js | 34 +++ gym-manage-uniapp/package-lock.json | 25 +- gym-manage-uniapp/package.json | 4 +- .../pages/course-detail/course-detail.vue | 78 +++++- gym-manage-uniapp/pages/index/index.vue | 85 ++++-- gym-manage-uniapp/pages/login/login.vue | 53 +++- gym-manage-uniapp/pages/profile/profile.vue | 157 ++++++------ gym-manage-uniapp/pages/search/search.vue | 242 ++++++++++++------ gym-manage-uniapp/store/index.js | 65 +++++ gym-manage-uniapp/utils/request.js | 63 +++++ gym-manage-uniapp/utils/signature.js | 60 +++++ 16 files changed, 778 insertions(+), 184 deletions(-) create mode 100644 gym-manage-uniapp/api/auth.js create mode 100644 gym-manage-uniapp/api/booking.js create mode 100644 gym-manage-uniapp/api/course.js create mode 100644 gym-manage-uniapp/api/member.js create mode 100644 gym-manage-uniapp/store/index.js create mode 100644 gym-manage-uniapp/utils/request.js create mode 100644 gym-manage-uniapp/utils/signature.js diff --git a/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/RbacAuthorizationFilter.java b/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/RbacAuthorizationFilter.java index 0c87d9a..b1c326f 100644 --- a/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/RbacAuthorizationFilter.java +++ b/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/RbacAuthorizationFilter.java @@ -64,7 +64,13 @@ public class RbacAuthorizationFilter extends AbstractGatewayFilterFactory diff --git a/gym-manage-uniapp/pages/index/index.vue b/gym-manage-uniapp/pages/index/index.vue index 490e6b2..6a854c3 100644 --- a/gym-manage-uniapp/pages/index/index.vue +++ b/gym-manage-uniapp/pages/index/index.vue @@ -11,10 +11,9 @@ - + - 你好,{{ memberInfo.nickname }} - {{ memberInfo.memberNo }} + {{ memberInfo.nickname ? '你好,' + memberInfo.nickname : '欢迎您!点击前往更新您的信息。' }} @@ -52,9 +51,7 @@ - - {{ course.recommendTitle }} - + {{ course.courseName }} {{ course.recommendReason }} @@ -74,39 +71,35 @@ diff --git a/gym-manage-uniapp/pages/login/login.vue b/gym-manage-uniapp/pages/login/login.vue index ced1e1a..130eec6 100644 --- a/gym-manage-uniapp/pages/login/login.vue +++ b/gym-manage-uniapp/pages/login/login.vue @@ -48,20 +48,69 @@ diff --git a/gym-manage-uniapp/pages/profile/profile.vue b/gym-manage-uniapp/pages/profile/profile.vue index 5566267..24398ef 100644 --- a/gym-manage-uniapp/pages/profile/profile.vue +++ b/gym-manage-uniapp/pages/profile/profile.vue @@ -11,82 +11,44 @@ - J + {{ avatarText }} - - 会员编号 - {{ userInfo.memberNo }} - 手机号 {{ userInfo.phone }} 性别 - {{ userInfo.gender === 1 ? '男' : userInfo.gender === 2 ? '女' : '未设置' }} + {{ genderLabel }} 生日 {{ userInfo.birthday || '未设置' }} + + 上次登录 + {{ userInfo.lastLoginAt || '暂无' }} + - {{ userInfo.totalCourses }} - 总课时 + {{ userInfo.totalSignInDays }} + 累计签到(天) - {{ userInfo.streakDays }} - 连续打卡 - - - - - {{ userInfo.rating }} - - - 评分 - - - - - - - 我的会员卡 - - - - {{ card.cardName }} - {{ card.typeLabel }} - - 剩余 {{ card.remainingTimes }} - 余额 {{ card.remainingAmount }} - 有效期至 {{ card.expireTime }} - - {{ card.statusLabel }} - - - - - - - - {{ menu.symbol }} - {{ menu.label }} - + {{ userInfo.monthSignInCount }} + 本月签到 @@ -105,6 +67,7 @@ {{ record.typeLabel }} + {{ record.sourceLabel }} {{ record.statusLabel }} @@ -116,16 +79,18 @@ @@ -158,8 +178,7 @@ .big-avatar { width: 56px; height: 56px; background: linear-gradient(135deg, #00E676, #00BFA5); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 24px; color: #1A1A1A; flex-shrink: 0; margin-right: 14px; } .user-info { flex: 1; display: flex; flex-direction: column; } .user-name { font-size: 18px; font-weight: 700; color: #1E1E1E; } - .user-tag { font-size: 13px; color: #00C853; font-weight: 500; display: flex; align-items: center; } - .tag-symbol { font-size: 12px; margin-right: 4px; } + .user-tag { font-size: 13px; color: #00C853; font-weight: 500; } .edit-symbol { font-size: 20px; color: #7A7E84; } .user-details { background: #F5F7FA; border-radius: 12px; padding: 14px 16px; display: flex; flex-direction: column; } .detail-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } @@ -170,31 +189,9 @@ .stat-number { font-size: 24px; font-weight: 700; color: #00E676; } .stat-label { font-size: 12px; color: rgba(255,255,255,0.6); margin-top: 4px; } .stat-divider { width: 1px; background: rgba(255,255,255,0.15); } - .stat-rating-row { display: flex; align-items: center; } - .star-icon { font-size: 14px; color: #00E676; } - .card-section { margin-bottom: 16px; } .section-title-row { display: flex; align-items: center; margin-bottom: 12px; } .section-symbol { font-size: 16px; color: #00E676; margin-right: 8px; } .section-title { font-size: 16px; font-weight: 700; color: #1E1E1E; } - .card-scroll { display: flex; white-space: nowrap; } - .member-card-item { display: inline-block; width: 200px; background: #FFFFFF; border-radius: 20px; padding: 16px; margin-right: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); position: relative; overflow: hidden; } - .member-card-item::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; } - .card-type-time::before { background: #00E676; } - .card-type-stored::before { background: linear-gradient(135deg, #FFA502, #FF6B4A); } - .card-type-count::before { background: #4A90D9; } - .card-name { font-size: 15px; font-weight: 700; color: #1E1E1E; display: block; margin-top: 4px; } - .card-type-label { font-size: 11px; color: #7A7E84; background: #F5F7FA; padding: 2px 8px; border-radius: 10px; margin-top: 4px; display: inline-block; } - .card-details { margin-top: 12px; display: flex; flex-direction: column; } - .card-remain { font-size: 13px; color: #7A7E84; } - .card-remain-num { font-size: 16px; font-weight: 700; color: #00C853; margin: 0 2px; } - .card-expire { font-size: 11px; color: #BDBDBD; } - .card-status { position: absolute; top: 12px; right: 12px; font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 20px; } - .card-status.active { background: rgba(0,230,118,0.15); color: #00C853; } - .menu-section { margin-bottom: 16px; } - .menu-grid { display: flex; flex-wrap: wrap; } - .menu-item { width: calc(33.33% - 8px); background: #FFFFFF; border-radius: 12px; padding: 16px 0; text-align: center; box-shadow: 0 4px 12px rgba(0,0,0,0.06); display: flex; flex-direction: column; align-items: center; margin-right: 12px; margin-bottom: 12px; } - .menu-symbol { font-size: 22px; color: #7A7E84; } - .menu-label { font-size: 13px; font-weight: 500; color: #7A7E84; } .sign-section { margin-bottom: 16px; } .sign-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .sign-header .section-title-row { margin-bottom: 0; } @@ -204,8 +201,10 @@ .sign-date { font-size: 14px; font-weight: 600; color: #1E1E1E; } .sign-time { font-size: 12px; color: #7A7E84; margin-top: 2px; } .sign-right { display: flex; align-items: center; } - .sign-type { font-size: 12px; color: #7A7E84; margin-right: 10px; } + .sign-type { font-size: 12px; color: #7A7E84; margin-right: 6px; } + .sign-source { font-size: 11px; color: #BDBDBD; background: #F5F7FA; padding: 1px 6px; border-radius: 8px; margin-right: 6px; } .sign-status { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 20px; } .sign-status.success { background: rgba(0,230,118,0.15); color: #00C853; } + .sign-status.fail { background: rgba(255,82,82,0.15); color: #FF5252; } .bottom-safe { height: 50px; } diff --git a/gym-manage-uniapp/pages/search/search.vue b/gym-manage-uniapp/pages/search/search.vue index 63e53c4..0bf0eb2 100644 --- a/gym-manage-uniapp/pages/search/search.vue +++ b/gym-manage-uniapp/pages/search/search.vue @@ -24,15 +24,11 @@ - - 时段 - - - {{ period.symbol }} - {{ period.label }} - - + + + {{ period.label }} + @@ -58,34 +54,48 @@ - - - {{ course.typeChar }} - - - {{ course.courseName }} - - 教练 {{ course.coachName }} - {{ course.difficultyLabel }} - - - 日期 {{ course.startTime }} - - - {{ course.location }} - {{ course.currentMembers }}/{{ course.maxMembers }}人 - - - - {{ course.storedValueAmount > 0 ? course.storedValueAmount + '元/次' : '免费' }} - - + + + + + + {{ course.typeName.slice(0, 2) }} + + + + {{ course.courseName }} + + {{ course.category }} + {{ course.difficultyLabel }} + + + + {{ course.shortDate }} + {{ course.shortTime }} - {{ course.endShortTime }} + {{ course.duration }} + + + {{ course.location }} + + + 已预约 {{ course.currentMembers }}/{{ course.maxMembers }}人 + + + {{ label.labelName }} + + + {{ course.storedValueAmount > 0 ? '¥' + course.storedValueAmount + '/次' : '免费' }} + + + + + - @@ -99,40 +109,35 @@ @@ -184,7 +269,7 @@ .nav-bar { background: #1A1A1A; padding: 0 20px; display: flex; align-items: center; } .nav-title { font-size: 18px; font-weight: 700; color: #FFFFFF; } - .search-area { background: #1A1A1A; padding: 0 16px 20px; } + .search-area { background: #1A1A1A; padding: 18px 16px 20px; } .search-box { background: rgba(255,255,255,0.12); border-radius: 40px; padding: 0 16px; display: flex; align-items: center; height: 42px; margin-bottom: 14px; } .search-symbol { font-size: 15px; color: rgba(255,255,255,0.5); flex-shrink: 0; margin-right: 8px; } .search-input { flex: 1; font-size: 14px; color: #FFFFFF; height: 100%; } @@ -197,12 +282,9 @@ .range-value.placeholder { color: rgba(255,255,255,0.35); font-weight: 400; } .range-sep { color: rgba(255,255,255,0.5); font-size: 14px; flex-shrink: 0; margin-right: 10px; } - .period-selector { display: flex; align-items: center; } - .period-label { font-size: 13px; color: rgba(255,255,255,0.6); flex-shrink: 0; margin-right: 10px; } - .period-scroll { flex: 1; display: flex; white-space: nowrap; } - .period-item { display: inline-flex; align-items: center; padding: 6px 14px; border-radius: 40px; font-size: 13px; color: rgba(255,255,255,0.7); background: rgba(255,255,255,0.08); margin-right: 8px; } + .period-row { display: flex; } + .period-item { flex: 1; text-align: center; padding: 7px 0; border-radius: 40px; font-size: 13px; color: rgba(255,255,255,0.7); background: rgba(255,255,255,0.08); margin: 0 3px; } .period-item.active { background: #00E676; color: #1A1A1A; font-weight: 600; } - .period-symbol { font-size: 13px; margin-right: 4px; } .filter-tabs { background: #FFFFFF; display: flex; white-space: nowrap; border-bottom: 1px solid #EEEEEE; } .filter-tabs-inner { padding: 14px 16px; display: flex; white-space: nowrap; } @@ -216,21 +298,35 @@ .sort-item.active { color: #00C853; font-weight: 600; } .course-list-inner { padding: 12px 16px 0; } - .course-card { background: #FFFFFF; border-radius: 20px; padding: 14px; margin-bottom: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); display: flex; } - .course-cover { width: 72px; height: 72px; border-radius: 12px; background: rgba(0,230,118,0.15); display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-right: 14px; } - .cover-text { font-size: 24px; font-weight: 700; color: #00C853; } - .course-body { flex: 1; display: flex; flex-direction: column; } - .course-name { font-size: 16px; font-weight: 700; color: #1E1E1E; } - .course-row { display: flex; align-items: center; font-size: 12px; color: #7A7E84; } - .course-row > * { margin-right: 12px; } + .course-item { margin-bottom: 12px; border-radius: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); overflow: hidden; } + .course-card { background: #FFFFFF; border-radius: 20px; padding: 14px; display: flex; } + .course-cover { width: 72px; height: 72px; border-radius: 12px; background: rgba(0,230,118,0.12); display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-right: 14px; overflow: hidden; position: relative; } + .cover-skeleton { position: absolute; inset: 0; background: linear-gradient(90deg, #E8E8E8 25%, #F0F0F0 50%, #E8E8E8 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; z-index: 1; } + @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } + .cover-img { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 0.3s; z-index: 0; } + .cover-img.loaded { opacity: 1; z-index: 2; } + .cover-text { font-size: 22px; font-weight: 700; color: #00C853; } + .course-body { flex: 1; display: flex; flex-direction: column; min-width: 0; } + .course-top { display: flex; justify-content: space-between; align-items: flex-start; } + .course-name { font-size: 16px; font-weight: 700; color: #1E1E1E; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .course-tags { display: flex; flex-shrink: 0; margin-left: 6px; } + .course-category { font-size: 11px; color: #00C853; background: rgba(0,230,118,0.12); padding: 1px 8px; border-radius: 20px; font-weight: 500; margin-right: 4px; } .course-difficulty { padding: 1px 8px; border-radius: 20px; font-size: 11px; font-weight: 600; } .diff-low { background: rgba(0,230,118,0.15); color: #00C853; } .diff-mid { background: rgba(255,165,2,0.15); color: #FFA502; } .diff-high { background: rgba(255,82,82,0.15); color: #FF5252; } - .course-bottom { display: flex; justify-content: space-between; align-items: center; margin-top: 4px; } - .course-price { font-size: 13px; font-weight: 600; color: #00C853; } + .course-meta { display: flex; align-items: center; font-size: 12px; color: #7A7E84; margin-top: 4px; } + .course-date { flex-shrink: 0; } + .course-time { margin-left: 8px; } + .course-duration { margin-left: 8px; color: #00C853; font-weight: 500; } + .course-location { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .course-capacity { color: #7A7E84; } + .course-labels { display: flex; flex-wrap: wrap; margin-top: 6px; } + .course-label { font-size: 10px; padding: 1px 6px; border-radius: 10px; margin-right: 4px; margin-bottom: 2px; } + .course-bottom { text-align: right; margin-top: 6px; } + .course-price { font-size: 18px; font-weight: 700; color: #00C853; display: block; margin-top: 6px; } .course-price.free { color: #00C853; } - .btn-book { background: #00E676; color: #1A1A1A; border: none; padding: 6px 16px; border-radius: 40px; font-weight: 700; font-size: 13px; line-height: 1.4; box-shadow: 0 2px 6px rgba(0,230,118,0.3); } + .btn-book { background: #00E676; color: #1A1A1A; border: none; padding: 6px 16px; border-radius: 40px; font-weight: 700; font-size: 13px; line-height: 1.4; box-shadow: 0 2px 8px rgba(0,230,118,0.3); } .btn-book::after { border: none; } .btn-book.disabled { background: #E0E0E0; color: #BDBDBD; box-shadow: none; } diff --git a/gym-manage-uniapp/store/index.js b/gym-manage-uniapp/store/index.js new file mode 100644 index 0000000..d27b3a0 --- /dev/null +++ b/gym-manage-uniapp/store/index.js @@ -0,0 +1,65 @@ +/** + * 全局状态管理 — 以 uni.Storage 为唯一数据源,确保跨页面/跨模块共享 + */ +const TOKEN_KEY = 'gym_token' +const MEMBER_KEY = 'gym_member' + +const store = { + /** 是否已登录 */ + get isLoggedIn() { + try { + return !!uni.getStorageSync(TOKEN_KEY) + } catch (e) { + return false + } + }, + + /** 获取 token */ + getToken() { + try { + return uni.getStorageSync(TOKEN_KEY) || null + } catch (e) { + return null + } + }, + + /** 获取会员信息 */ + getMemberInfo() { + try { + return uni.getStorageSync(MEMBER_KEY) || null + } catch (e) { + return null + } + }, + + /** 设置登录态 */ + setLogin(token, memberInfo) { + try { + uni.setStorageSync(TOKEN_KEY, token) + if (memberInfo) uni.setStorageSync(MEMBER_KEY, memberInfo) + } catch (e) { + console.error('存储登录态失败:', e) + } + }, + + /** 更新会员信息 */ + updateMemberInfo(memberInfo) { + try { + uni.setStorageSync(MEMBER_KEY, memberInfo) + } catch (e) { + console.error('更新会员信息失败:', e) + } + }, + + /** 清除登录态 */ + clearLogin() { + try { + uni.removeStorageSync(TOKEN_KEY) + uni.removeStorageSync(MEMBER_KEY) + } catch (e) { + console.error('清除登录态失败:', e) + } + } +} + +module.exports = store diff --git a/gym-manage-uniapp/utils/request.js b/gym-manage-uniapp/utils/request.js new file mode 100644 index 0000000..bf26275 --- /dev/null +++ b/gym-manage-uniapp/utils/request.js @@ -0,0 +1,63 @@ +const luchRequest = require('luch-request') +const Request = luchRequest.default || luchRequest +const { generateSignatureHeaders } = require('./signature') +const store = require('../store/index') + +const BASE_URL = 'http://localhost:8084/api' + +const http = new Request({ + baseURL: BASE_URL, + timeout: 15000, + header: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +http.interceptors.request.use( + (config) => { + // 注入 JWT token + const token = store.getToken() + if (token) { + config.header = config.header || {} + config.header.Authorization = 'Bearer ' + token + } + + // 注入签名头 + const method = (config.method || 'GET').toUpperCase() + const url = config.url || '' + const body = config.data + + const signatureHeaders = generateSignatureHeaders(method, url, body) + config.header = config.header || {} + Object.assign(config.header, signatureHeaders) + + return config + }, + (error) => Promise.reject(error) +) + +// 响应拦截器 +http.interceptors.response.use( + (response) => { + // 直接返回 data,统一解包 + if (response.statusCode === 200) { + return response.data + } + return response + }, + (error) => { + // 401 处理:清除登录态,跳转登录页 + if (error.statusCode === 401) { + store.clearLogin() + const pages = getCurrentPages() + const currentPage = pages[pages.length - 1] + if (currentPage && currentPage.route !== 'pages/login/login') { + uni.reLaunch({ url: '/pages/login/login' }) + } + } + return Promise.reject(error) + } +) + +module.exports = http diff --git a/gym-manage-uniapp/utils/signature.js b/gym-manage-uniapp/utils/signature.js new file mode 100644 index 0000000..f7d4e2d --- /dev/null +++ b/gym-manage-uniapp/utils/signature.js @@ -0,0 +1,60 @@ +const CryptoJS = require('crypto-js') + +const SIGNATURE_SECRET = 'NovalonManageSystemSecretKey2026' + +/** + * 生成 HMAC-SHA256 签名 + */ +function generateSignature(method, path, query, body, timestamp, nonce) { + const stringToSign = [method, path, query || '', body || '', String(timestamp), nonce].join('\n') + const signature = CryptoJS.HmacSHA256(stringToSign, SIGNATURE_SECRET) + return CryptoJS.enc.Base64.stringify(signature) +} + +/** + * 生成随机 nonce + */ +function generateNonce() { + const timestamp = Date.now().toString(36) + const randomPart = Math.random().toString(36).substring(2, 15) + return timestamp + '-' + randomPart +} + +/** + * 从 URL 解析 path 和 query + */ +function parseUrl(url) { + if (url.startsWith('http://') || url.startsWith('https://')) { + // 小程序环境无 URL 构造函数,手动解析 + const withoutProtocol = url.substring(url.indexOf('://') + 3) + const pathStart = withoutProtocol.indexOf('/') + if (pathStart === -1) return { path: '/', query: '' } + const pathAndQuery = withoutProtocol.substring(pathStart) + const queryIndex = pathAndQuery.indexOf('?') + if (queryIndex === -1) return { path: pathAndQuery, query: '' } + return { path: pathAndQuery.substring(0, queryIndex), query: pathAndQuery.substring(queryIndex + 1) } + } + const queryIndex = url.indexOf('?') + if (queryIndex === -1) return { path: url, query: '' } + return { path: url.substring(0, queryIndex), query: url.substring(queryIndex + 1) } +} + +/** + * 生成签名请求头 + */ +function generateSignatureHeaders(method, url, body) { + const timestamp = Date.now() + const nonce = generateNonce() + const { path, query } = parseUrl(url) + const bodyStr = body ? (typeof body === 'string' ? body : JSON.stringify(body)) : '' + + const signature = generateSignature(method.toUpperCase(), path, query, bodyStr, timestamp, nonce) + + return { + 'X-Signature': signature, + 'X-Timestamp': String(timestamp), + 'X-Nonce': nonce + } +} + +module.exports = { generateSignatureHeaders } -- 2.54.0 From 2e7c2ced431d3e626db0179e799fd12694ff196d Mon Sep 17 00:00:00 2001 From: liwentao Date: Fri, 17 Jul 2026 15:48:36 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=A4=A7=E9=83=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E9=9D=A2=E5=89=8D=E5=90=8E=E7=AB=AF=E4=BA=92?= =?UTF-8?q?=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/MemberServiceImpl.java | 2 + .../gym/manage/member/vo/MemberInfoVO.java | 7 + gym-manage-uniapp/pages.json | 12 +- .../pages/course-detail/course-detail.vue | 352 ++++++++++++------ gym-manage-uniapp/pages/profile/profile.vue | 266 +++++++++---- gym-manage-uniapp/pages/search/search.vue | 134 +++++-- gym-manage-uniapp/utils/request.js | 2 +- 7 files changed, 560 insertions(+), 215 deletions(-) diff --git a/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/service/impl/MemberServiceImpl.java b/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/service/impl/MemberServiceImpl.java index 8567be2..f2003a2 100644 --- a/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/service/impl/MemberServiceImpl.java +++ b/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/service/impl/MemberServiceImpl.java @@ -158,6 +158,7 @@ public class MemberServiceImpl implements MemberService { return MemberInfoVO.builder() .id(member.getId()) + .memberNo(member.getMemberNo()) .nickname(member.getNickname()) .phone(maskedPhone) .gender(genderEnum) @@ -166,6 +167,7 @@ public class MemberServiceImpl implements MemberService { .avatar(member.getAvatar()) .hasPhone(phone != null) .isSubscribed(member.getSubscribed() != null && member.getSubscribed()) + .lastLoginAt(member.getLastLoginAt()) .build(); } diff --git a/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/vo/MemberInfoVO.java b/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/vo/MemberInfoVO.java index f3e763d..7732861 100644 --- a/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/vo/MemberInfoVO.java +++ b/gym-manage-api/gym-member/src/main/java/cn/novalon/gym/manage/member/vo/MemberInfoVO.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.Date; /** @@ -25,6 +26,9 @@ public class MemberInfoVO { // 会员 ID private Long id; + // 会员编号 + private String memberNo; + // 昵称 private String nickname; @@ -48,4 +52,7 @@ public class MemberInfoVO { // 是否已关注公众号 private Boolean isSubscribed; + + // 最后登录时间 + private LocalDateTime lastLoginAt; } \ No newline at end of file diff --git a/gym-manage-uniapp/pages.json b/gym-manage-uniapp/pages.json index 9beaa3e..8ef8f0a 100644 --- a/gym-manage-uniapp/pages.json +++ b/gym-manage-uniapp/pages.json @@ -50,15 +50,21 @@ "list": [ { "pagePath": "pages/index/index", - "text": "首页" + "text": "首页", + "iconPath": "static/icon/shouye.png", + "selectedIconPath": "static/icon/shouye.png" }, { "pagePath": "pages/search/search", - "text": "课程" + "text": "课程", + "iconPath": "static/icon/jianshen.png", + "selectedIconPath": "static/icon/jianshen.png" }, { "pagePath": "pages/profile/profile", - "text": "我的" + "text": "我的", + "iconPath": "static/icon/wode.png", + "selectedIconPath": "static/icon/wode.png" } ] }, diff --git a/gym-manage-uniapp/pages/course-detail/course-detail.vue b/gym-manage-uniapp/pages/course-detail/course-detail.vue index 00d7af3..ad3b7d3 100644 --- a/gym-manage-uniapp/pages/course-detail/course-detail.vue +++ b/gym-manage-uniapp/pages/course-detail/course-detail.vue @@ -1,116 +1,124 @@ + + + - + + + + + + {{ detailRow.id }} + {{ detailRow.courseName }} + {{ getCourseTypeName(detailRow.courseType) }} + {{ getCoachDisplayName(detailRow.coachId) || detailRow.coachName || '-' }} + + + {{ statusMap[detailRow.status || '']?.label || detailRow.status }} + + + {{ detailRow.location || '-' }} + {{ formatDateTime(detailRow.startTime) }} + {{ formatDateTime(detailRow.actualStartTime) || '-' }} + {{ formatDateTime(detailRow.endTime) }} + {{ formatDateTime(detailRow.actualEndTime) || '-' }} + {{ detailRow.currentMembers || 0 }} / {{ detailRow.maxMembers || 0 }} + {{ detailRow.storedValueAmount ?? '-' }} + + + - + + {{ detailRow.description || '-' }} + {{ detailRow.createBy || '-' }} + {{ detailRow.updateBy || '-' }} + {{ formatDateTime(detailRow.createdAt) }} + {{ formatDateTime(detailRow.updatedAt) }} + + + @@ -837,4 +910,11 @@ onMounted(async () => { color: #909399; font-size: 14px; } + +.detail-cover { + width: 120px; + height: 80px; + object-fit: cover; + border-radius: 4px; +} diff --git a/gym-manage-web/src/views/statistics/StatisticsDashboard.vue b/gym-manage-web/src/views/statistics/StatisticsDashboard.vue index 42efa28..6cb96ef 100644 --- a/gym-manage-web/src/views/statistics/StatisticsDashboard.vue +++ b/gym-manage-web/src/views/statistics/StatisticsDashboard.vue @@ -50,9 +50,9 @@ - -
签到总数
-
{{ summary?.signInStatistics?.totalSignIns ?? '-' }}
+ +
教练违规
+
{{ summary?.coachStatistics?.totalViolations ?? '-' }}
@@ -192,12 +192,65 @@ + + + + + + +
+ 教练总数 + {{ summary?.coachStatistics?.totalCoaches ?? '-' }} +
+
+ +
+ 违规教练 + + {{ summary?.coachStatistics?.violatedCoaches ?? '-' }} + +
+
+ +
+ 开课总数 + {{ summary?.coachStatistics?.totalCourses ?? '-' }} +
+
+ +
+ 迟到 + + {{ summary?.coachStatistics?.lateCount ?? '-' }} + +
+
+ +
+ 缺席 + + {{ summary?.coachStatistics?.absentCount ?? '-' }} + +
+
+ +
+ 未手动结课 + + {{ summary?.coachStatistics?.notManualEndCount ?? '-' }} + +
+
+
+
@@ -350,6 +415,7 @@ onMounted(() => { .stat-card--success .stat-card__value { color: #67c23a; } .stat-card--warning .stat-card__value { color: #e6a23c; } .stat-card--info .stat-card__value { color: #909399; } +.stat-card--danger .stat-card__value { color: #f56c6c; } /* ---- 明细分区 ---- */ .section-card { @@ -380,6 +446,14 @@ onMounted(() => { color: #303133; } +.metric-value--warn { + color: #e6a23c; +} + +.metric-value--danger { + color: #f56c6c; +} + .rate-group { display: flex; flex-direction: column; diff --git a/gym-manage-web/src/views/system/CoachManagement.vue b/gym-manage-web/src/views/system/CoachManagement.vue index f864160..d809efa 100644 --- a/gym-manage-web/src/views/system/CoachManagement.vue +++ b/gym-manage-web/src/views/system/CoachManagement.vue @@ -26,7 +26,7 @@ - + @@ -41,12 +41,19 @@ + + + - + + + + + + + @@ -145,13 +237,14 @@ import { ref, reactive, computed, onMounted } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { Search } from '@element-plus/icons-vue' -import { coachApi, type Coach, type CoachCreateRequest, type CoachUpdateRequest, type GroupCourse } from '@/api/coach.api' +import { coachApi, type Coach, type CoachCreateRequest, type CoachUpdateRequest, type GroupCourse, type ViolationCountItem, type ViolationRecord } from '@/api/coach.api' import { handleApiError } from '@/utils/errorHandler' import { formatDateTime } from '@/utils/dateFormat' const loading = ref(false) const dataSource = ref([]) const searchKeyword = ref('') +const violationCounts = reactive>({}) const filteredData = computed(() => { if (!searchKeyword.value) return dataSource.value @@ -209,7 +302,24 @@ const courseStatusMap: Record = { 1: { text: '已取消', tag: 'info' }, 2: { text: '已结束', tag: 'warning' }, 3: { text: '进行中', tag: 'danger' }, - 4: { text: '超时', tag: 'info' }, + 5: { text: '教练缺席', tag: 'danger' }, + 6: { text: '自动结束', tag: 'info' }, + 7: { text: '教练迟到', tag: 'warning' }, +} + +// 违规类型映射 +const violationTypeMap: Record = { + COACH_LATE: { text: '教练迟到', tag: 'warning' }, + COACH_ABSENT: { text: '教练缺席', tag: 'danger' }, + NOT_MANUAL_END: { text: '未手动结课', tag: 'info' }, +} + +function getViolationTypeText(reason: string) { + return violationTypeMap[reason]?.text || reason +} + +function getViolationTypeTag(reason: string) { + return violationTypeMap[reason]?.tag || 'info' } function getCourseStatusText(status: number) { @@ -224,6 +334,13 @@ const fetchData = async () => { loading.value = true try { dataSource.value = await coachApi.getAll() + // 同步获取违规次数统计 + const counts = await coachApi.getViolationCounts() + // 清空旧数据 + Object.keys(violationCounts).forEach(key => delete violationCounts[Number(key)]) + counts.forEach(item => { + violationCounts[item.coach_id] = item.count + }) } catch (error) { handleApiError(error) } finally { @@ -333,6 +450,49 @@ const handleViewCourses = async (row: Coach) => { } } +// 违规次数标签颜色 +function getViolationTag(coachId: number) { + const count = violationCounts[coachId] ?? 0 + if (count === 0) return 'success' + if (count <= 2) return 'warning' + return 'danger' +} + +// 违规行高亮 +function getRowClass({ row }: { row: Coach }) { + const count = violationCounts[Number(row.id)] ?? 0 + return count > 0 ? 'row--has-violation' : '' +} + +// 详情弹窗 +const detailDialogVisible = ref(false) +const detailCoach = ref(null) +const detailViolations = ref([]) +const detailViolationsLoading = ref(false) +const detailCourses = ref([]) +const detailCoursesLoading = ref(false) + +const handleViewDetail = async (row: Coach) => { + detailCoach.value = row + detailDialogVisible.value = true + // 并行加载违规记录和团课记录 + detailViolationsLoading.value = true + detailCoursesLoading.value = true + try { + const [violations, courses] = await Promise.all([ + coachApi.getViolations(row.id), + coachApi.getCourses(row.id), + ]) + detailViolations.value = violations + detailCourses.value = courses + } catch (error) { + handleApiError(error) + } finally { + detailViolationsLoading.value = false + detailCoursesLoading.value = false + } +} + onMounted(() => { fetchData() }) @@ -353,4 +513,10 @@ onMounted(() => { } } } + +/* 有违规记录的教练行:左侧红色边框 + 浅色背景 */ +:deep(.row--has-violation) { + border-left: 3px solid #F56C6C; + background-color: #fef0f0 !important; +} -- 2.54.0 From 53d1ce6fb238498cfa88c532800365956d8ded0e Mon Sep 17 00:00:00 2001 From: liwentao Date: Mon, 20 Jul 2026 17:27:22 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E7=AB=AF=E4=B8=AA=E4=BA=BA=E9=A1=B5=E9=9D=A2=E4=B8=AD=E5=9B=A2?= =?UTF-8?q?=E8=AF=BE=E7=AD=BE=E5=88=B0=E8=AE=B0=E5=BD=95=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gym-manage-uniapp/pages/profile/profile.vue | 78 ++++++++++++++++++++- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/gym-manage-uniapp/pages/profile/profile.vue b/gym-manage-uniapp/pages/profile/profile.vue index 3e6b0c9..5377ac8 100644 --- a/gym-manage-uniapp/pages/profile/profile.vue +++ b/gym-manage-uniapp/pages/profile/profile.vue @@ -71,6 +71,33 @@ {{ record.statusLabel }}
+ + 暂无签到记录 + +
+ + + + + + 团课签到记录 + + 最近{{ courseCheckInRecords.length }}条 + + + + {{ record.fullDate }} + {{ record.shortTime }} + + + {{ record.courseName }} + {{ record.location }} + 已签到 + + + + 暂无团课签到记录 + @@ -116,6 +143,7 @@