From 4c4c83c25971717ef408c466eaa9d635d652522c Mon Sep 17 00:00:00 2001 From: ltx <1006158920@qq.com> Date: Wed, 1 Jul 2026 15:10:17 +0800 Subject: [PATCH] =?UTF-8?q?update:=E6=B7=BB=E5=8A=A0=E5=A4=9A=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.json | 1 + pages/student/my/my.wxss | 16 +- pages/student/train/train.js | 14 +- pages/student/train/train.wxss | 2 + project.config.json | 2 +- project.private.config.json | 11 +- subpackage/bluebooth/search.js | 222 ++++++++++- subpackage/bluebooth/search.wxml | 40 ++ subpackage/bluebooth/search.wxss | 146 +++++++ subpackage/train/bluetooth/bluetoothServe.js | 38 +- subpackage/train/result/result.js | 23 +- subpackage/train/select-sport/select-sport.js | 39 ++ .../train/select-sport/select-sport.json | 8 + .../train/select-sport/select-sport.wxml | 55 +++ .../train/select-sport/select-sport.wxss | 357 ++++++++++++++++++ subpackage/train/train/train.js | 32 +- subpackage/train/train/train.wxml | 35 +- subpackage/train/train/train.wxss | 81 +++- utils/soprt-key.js | 17 +- 19 files changed, 1096 insertions(+), 43 deletions(-) create mode 100644 subpackage/train/select-sport/select-sport.js create mode 100644 subpackage/train/select-sport/select-sport.json create mode 100644 subpackage/train/select-sport/select-sport.wxml create mode 100644 subpackage/train/select-sport/select-sport.wxss diff --git a/app.json b/app.json index 3f406ee..ad9087e 100644 --- a/app.json +++ b/app.json @@ -48,6 +48,7 @@ "train/user-report/user-report", "train/check-type/check-page", "train/train/train", + "train/select-sport/select-sport", "bluebooth/search", "train/bluetooth/train", "train/result/result", diff --git a/pages/student/my/my.wxss b/pages/student/my/my.wxss index 682d623..6886e16 100644 --- a/pages/student/my/my.wxss +++ b/pages/student/my/my.wxss @@ -51,7 +51,7 @@ page { } .chose { - margin: 34rpx 20rpx 0; + margin: 64rpx 30rpx 0; text-align: center; color: #fff; /* background-color: brown; */ @@ -62,7 +62,7 @@ page { align-items: center; flex-direction: column; justify-content: center; - border-radius: 20rpx 20rpx 0 0; + border-radius: 20rpx; } @@ -75,8 +75,11 @@ page { justify-content: space-evenly; align-items: center; background-color: #fff; - font-size: 24rpx; + font-size: 26rpx; padding: 20rpx 0; + margin: 26rpx 30rpx 20rpx; + border-radius: 20rpx; + box-shadow:0 0 12px #0000000d; } .lab-item { @@ -87,10 +90,10 @@ page { } .lab-img { - width: 48rpx; - height: 48rpx; + width: 64rpx; + height: 64rpx; /* margin-top: 20rpx; */ - margin-bottom: 20rpx; + margin-bottom: 10rpx; } .cell { @@ -103,6 +106,7 @@ page { align-items: center; font-size: 26rpx; margin: 20rpx 30rpx 0 30rpx; + box-shadow:0 0 12px #0000000d; } .left { diff --git a/pages/student/train/train.js b/pages/student/train/train.js index 576ed5c..f7d15be 100644 --- a/pages/student/train/train.js +++ b/pages/student/train/train.js @@ -147,10 +147,16 @@ Page({ }, goTrainer(e){ //去训练 - console.log('aaaa') - wx.navigateTo({ - url: '/subpackage/train/train/train?type='+ e.currentTarget.id.replace('.png',''), - }) + const type = e.currentTarget.id.replace('.png','') + if(type === 'fit'){ + wx.navigateTo({ + url: '/subpackage/train/select-sport/select-sport', + }) + } else { + wx.navigateTo({ + url: '/subpackage/train/train/train?type=' + type, + }) + } }, // 下拉刷新 diff --git a/pages/student/train/train.wxss b/pages/student/train/train.wxss index a1ee1bd..532c911 100644 --- a/pages/student/train/train.wxss +++ b/pages/student/train/train.wxss @@ -47,6 +47,8 @@ page{ background: linear-gradient(180deg, #e8f5fd 0%, #fff 100%); /* height: 480rpx; */ padding: 29rpx; + box-shadow:0 0 12px #0000000d; + } .goal{ diff --git a/project.config.json b/project.config.json index 0f3b3f3..d1f1539 100644 --- a/project.config.json +++ b/project.config.json @@ -55,7 +55,7 @@ "compileType": "miniprogram", "libVersion": "3.7.12", "appid": "wx9d179138d229d06b", - "projectname": "YZ-Ai-Sport-Native-Demo", + "projectname": "跃动", "condition": {}, "editorSetting": { "tabIndent": "insertSpaces", diff --git a/project.private.config.json b/project.private.config.json index 45d8a1a..65d777a 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -24,12 +24,19 @@ "condition": { "miniprogram": { "list": [ + { + "name": "subpackage/train/result/result", + "pathName": "subpackage/train/result/result", + "query": "type=time&count=0&time=3&theme=myself&isAi=true&sportType=%E4%BF%AF%E5%8D%A7%E6%92%91", + "scene": null, + "launchMode": "default" + }, { "name": "module-sport/pages/sport-full-screen", "pathName": "module-sport/pages/sport-full-screen", "query": "sportKey=Rope-Skipping&time=120&number=20&type=num&theme=homeWork&homeWorkId=51&groupNumber=2&timeout=3&music=https%3A%2F%2Fyuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com%2FUpload%2FBackgroundMusic%2FCarly%2520Rae%2520Jepsen-Turn%2520Me%2520Up.mp3", - "scene": null, - "launchMode": "default" + "launchMode": "default", + "scene": null }, { "name": "subpackage/train/check-type/check-page", diff --git a/subpackage/bluebooth/search.js b/subpackage/bluebooth/search.js index c47523c..6532d25 100644 --- a/subpackage/bluebooth/search.js +++ b/subpackage/bluebooth/search.js @@ -8,7 +8,12 @@ Page({ connectedDeviceId: null, deviceServices: [], deviceCharacteristics: [], - blueIsOk: false + blueIsOk: false, + battery: null, + batteryLoading: false, + deviceName: '', + nameInput: '', + nameLoading: false }, // 1. 初始化蓝牙模块 @@ -133,7 +138,7 @@ Page({ wx.onBluetoothDeviceFound((res) => { console.log('发现新设备', res.devices); res.devices.forEach(device => { - if (device.name == 'YD-Jump' || device.name == 'YD_Jump' || device.name == 'YD-O1' || device.localName == 'YD-O1' || device.localName == 'YD-Jump' || device.localName == 'YD_Jump') { + if (device.name == 'YD-Jump' || device.name == 'YD_Jump' || device.name == 'YD-O1' || device.localName == 'YD-O1' || device.localName == 'YD-Jump' || device.localName == 'YD_Jump') { const exists = this.data.devices.find(d => d.deviceId === device.deviceId); if (!exists) { if (device.deviceId == last_device_id) { @@ -190,7 +195,7 @@ Page({ deviceId: device.deviceId, success: () => { console.log('连接成功', device.deviceId); - console.log('连接成功', device); + console.log('连接成功的设备信息:', JSON.stringify(device)); wx.showToast({ title: '连接成功', icon: 'success' @@ -204,14 +209,20 @@ Page({ wx.setStorageSync('device_id', device.deviceId) wx.setStorageSync('device_name', device.name) if (device.name == 'YD-O1') { - wx.setStorageSync('uuid', device.advertisServiceUUIDs[0]) + const serviceId = device.advertisServiceUUIDs[0]; + wx.setStorageSync('uuid', serviceId) + this.setupWriteAndNotify(device.deviceId, serviceId); } else { // 获取设备的服务 wx.getBLEDeviceServices({ deviceId: device.deviceId, success: (res) => { console.log('设备服务', res.services); - wx.setStorageSync('uuid', res.services[0].uuid) + // YD_Jump(下划线)使用 services[1],YD-Jump(短横线)使用 services[0] + const serviceIndex = device.name === 'YD_Jump' ? 1 : 0; + const serviceId = res.services[serviceIndex].uuid; + wx.setStorageSync('uuid', serviceId) + this.setupWriteAndNotify(device.deviceId, serviceId); }, fail: (err) => { console.error('获取服务失败', err); @@ -373,6 +384,69 @@ Page({ }); }, + // 连接成功后获取特征值、存储写特征并建立通知监听 + setupWriteAndNotify(deviceId, serviceId) { + wx.getBLEDeviceCharacteristics({ + deviceId, + serviceId, + success: (res) => { + const writeChar = res.characteristics.find(c => c.properties.write || c.properties.writeNoResponse); + if (writeChar) { + wx.setStorageSync('writeCharacteristic', writeChar.uuid); + } + const notifyChar = res.characteristics.find(c => c.properties.notify); + if (notifyChar) { + wx.notifyBLECharacteristicValueChange({ + deviceId, + serviceId, + characteristicId: notifyChar.uuid, + state: true, + }); + wx.onBLECharacteristicValueChange((result) => { + const deviceName = wx.getStorageSync('device_name'); + if (deviceName === 'YD-O1') { + // YD-O1: 二进制协议解析电量响应 + const int16Array = new Int16Array(result.value); + if (int16Array.length > 0) { + const battery = int16Array[0]; // 根据实际协议调整字段索引 + if (battery >= 0 && battery <= 100) { + this.setData({ battery, batteryLoading: false }); + wx.hideLoading(); + } + } + } else { + // YD_Jump / YD-Jump: 字符串协议解析 $Batt,xx! + const bytes = new Uint8Array(result.value); + let str = ''; + for (let i = 0; i < bytes.length; i++) { + str += String.fromCharCode(bytes[i]); + } + console.log('收到蓝牙数据:', str); + // 解析电量响应 $Batt,xx! + const battMatch = str.match(/\$Batt,(\d+)!/); + if (battMatch) { + this.setData({ battery: parseInt(battMatch[1], 10), batteryLoading: false }); + wx.hideLoading(); + } + // 解析获取名称响应 $My Name:xxxxxxxx! + const nameMatch = str.match(/\$My Name:(.+)!/); + if (nameMatch) { + this.setData({ deviceName: nameMatch[1].trim(), nameLoading: false }); + wx.hideLoading(); + } + // 解析修改名称响应 $Set Name OK! + if (str.includes('$Set Name OK!')) { + wx.hideLoading(); + wx.showToast({ title: '名称修改成功', icon: 'success' }); + } + } + }); + } + }, + fail: (err) => console.error('获取特征值失败', err) + }); + }, + // 4. 断开连接 disconnectDevice(id) { wx.closeBLEConnection({ @@ -381,9 +455,145 @@ Page({ console.log('断开连接'); this.setData({ status: '未连接', - connected: false + connected: false, + battery: null, + batteryLoading: false, + deviceName: '', + nameInput: '', + nameLoading: false }); } }); + }, + + // 5. 获取设备电量(按设备类型发送不同协议命令) + getBattery() { + if (!this.data.connected || !this.data.connectedDeviceId) { + wx.showToast({ title: '请先连接设备', icon: 'none' }); + return; + } + const characteristic = wx.getStorageSync('writeCharacteristic'); + if (!characteristic) { + wx.showToast({ title: '特征值未就绪,请重新连接', icon: 'none' }); + return; + } + const deviceId = this.data.connectedDeviceId; + const serviceId = wx.getStorageSync('uuid'); + const deviceName = wx.getStorageSync('device_name'); + + wx.showLoading({ title: '获取电量中...' }); + this.setData({ batteryLoading: true }); + + let commandData; + if (deviceName === 'YD-O1') { + // YD-O1: 二进制协议获取电量 + commandData = new ArrayBuffer(4); + const dataView = new DataView(commandData); + dataView.setUint8(0, 0x07); // 获取电量命令字节 + dataView.setUint8(1, 0x00); + dataView.setUint8(2, 0x00); + dataView.setUint8(3, 0x00); + } else { + // YD_Jump / YD-Jump: 字符串协议获取电量 + commandData = this.stringToArrayBuffer('$Get Batt!'); + } + + wx.writeBLECharacteristicValue({ + deviceId, + serviceId, + characteristicId: characteristic, + value: commandData, + success: () => { + console.log(`${deviceName} 发送获取电量命令成功`); + }, + fail: (err) => { + console.error('发送命令失败', err); + wx.hideLoading(); + this.setData({ batteryLoading: false }); + wx.showToast({ title: '发送命令失败', icon: 'none' }); + } + }); + }, + + // 获取设备名称 + getDeviceName() { + if (!this.data.connected || !this.data.connectedDeviceId) { + wx.showToast({ title: '请先连接设备', icon: 'none' }); + return; + } + const characteristic = wx.getStorageSync('writeCharacteristic'); + if (!characteristic) { + wx.showToast({ title: '特征值未就绪,请重新连接', icon: 'none' }); + return; + } + const deviceId = this.data.connectedDeviceId; + const serviceId = wx.getStorageSync('uuid'); + wx.showLoading({ title: '获取名称中...' }); + this.setData({ nameLoading: true }); + wx.writeBLECharacteristicValue({ + deviceId, + serviceId, + characteristicId: characteristic, + value: this.stringToArrayBuffer('$Get Name!'), + success: () => console.log('发送获取名称命令成功'), + fail: (err) => { + console.error('发送命令失败', err); + wx.hideLoading(); + this.setData({ nameLoading: false }); + wx.showToast({ title: '发送命令失败', icon: 'none' }); + } + }); + }, + + // 修改设备名称(名称不足8位用空格填充,超过8位截断) + setDeviceName() { + if (!this.data.connected || !this.data.connectedDeviceId) { + wx.showToast({ title: '请先连接设备', icon: 'none' }); + return; + } + const nameInput = this.data.nameInput.trim(); + if (!nameInput) { + wx.showToast({ title: '请输入新名称', icon: 'none' }); + return; + } + const characteristic = wx.getStorageSync('writeCharacteristic'); + if (!characteristic) { + wx.showToast({ title: '特征值未就绪,请重新连接', icon: 'none' }); + return; + } + const deviceId = this.data.connectedDeviceId; + const serviceId = wx.getStorageSync('uuid'); + // 名称固定8字节:不足补空格,超过截断 + const paddedName = nameInput.padEnd(8, ' ').substring(0, 8); + const cmd = `$Set Name:${paddedName}!`; + console.log('发送修改名称命令:', cmd); + wx.showLoading({ title: '修改名称中...' }); + wx.writeBLECharacteristicValue({ + deviceId, + serviceId, + characteristicId: characteristic, + value: this.stringToArrayBuffer(cmd), + success: () => console.log('修改名称命令已发送:', cmd), + fail: (err) => { + console.error('发送命令失败', err); + wx.hideLoading(); + wx.showToast({ title: '发送命令失败', icon: 'none' }); + } + }); + }, + + // 名称输入框变化 + onNameInput(e) { + this.setData({ nameInput: e.detail.value }); + }, + + // 字符串转 ArrayBuffer(与 bluetoothServe.js 保持一致) + stringToArrayBuffer(str) { + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + for (let i = 0; i < str.length; i++) { + view[i] = str.charCodeAt(i) & 0xFF; + } + return buffer; } }); \ No newline at end of file diff --git a/subpackage/bluebooth/search.wxml b/subpackage/bluebooth/search.wxml index 21f86b4..5864f5d 100644 --- a/subpackage/bluebooth/search.wxml +++ b/subpackage/bluebooth/search.wxml @@ -44,4 +44,44 @@ + + + + + 设备电量 + + + + + + + + + + {{battery}}% + + + -- + + + + + + + + + 设备名称 + + + + 当前名称 + {{deviceName || '--'}} + + + + + + + + \ No newline at end of file diff --git a/subpackage/bluebooth/search.wxss b/subpackage/bluebooth/search.wxss index 47ef671..7096398 100644 --- a/subpackage/bluebooth/search.wxss +++ b/subpackage/bluebooth/search.wxss @@ -166,3 +166,149 @@ button { margin-top: 20rpx; font-size: 30rpx; } + +/* 电量区域 */ +.battery-section { + margin-top: 10rpx; +} + +.battery-card { + margin: 0 30rpx; + background-color: #fff; + border-radius: 20rpx; + box-shadow: 0 10rpx 10rpx rgba(0, 0, 0, 0.06); + padding: 40rpx 30rpx; + display: flex; + align-items: center; + justify-content: space-between; +} + +.battery-display { + display: flex; + align-items: center; + gap: 20rpx; +} + +.battery-placeholder { + font-size: 60rpx; + color: #ccc; + font-weight: bold; + line-height: 1; +} + +.battery-icon-wrap { + display: flex; + align-items: center; +} + +.battery-icon { + width: 80rpx; + height: 40rpx; + border: 4rpx solid #333; + border-radius: 6rpx; + padding: 4rpx; + box-sizing: border-box; + background-color: #f5f5f5; + overflow: hidden; +} + +.battery-level { + height: 100%; + border-radius: 3rpx; + background: linear-gradient(90deg, #4cd964, #26a5f6); + transition: width 0.4s ease; +} + +.battery-cap { + width: 8rpx; + height: 18rpx; + background-color: #333; + border-radius: 0 3rpx 3rpx 0; + margin-left: 2rpx; +} + +.battery-percent { + font-size: 48rpx; + font-weight: bold; + color: #333; +} + +.battery-btn { + margin: 0 !important; + padding: 0 30rpx !important; + height: 70rpx; + line-height: 70rpx; + font-size: 26rpx; + background-color: #007aff; + color: white; + border-radius: 50rpx; + min-width: 160rpx; +} + +/* 名称管理区域 */ +.name-section { + margin-top: 10rpx; +} + +.name-card { + margin: 0 30rpx; + background-color: #fff; + border-radius: 20rpx; + box-shadow: 0 10rpx 10rpx rgba(0, 0, 0, 0.06); + padding: 30rpx; + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20rpx; +} + +.name-info { + display: flex; + flex-direction: column; + gap: 8rpx; +} + +.name-label { + font-size: 24rpx; + color: #999; +} + +.name-value { + font-size: 36rpx; + font-weight: bold; + color: #333; +} + +.name-action-btn { + margin: 0 !important; + padding: 0 30rpx !important; + height: 70rpx; + line-height: 70rpx; + font-size: 26rpx; + background-color: #007aff; + color: white; + border-radius: 50rpx; + min-width: 160rpx; +} + +.name-edit-card { + margin: 0 30rpx; + background-color: #fff; + border-radius: 20rpx; + box-shadow: 0 10rpx 10rpx rgba(0, 0, 0, 0.06); + padding: 30rpx; + display: flex; + align-items: center; + gap: 20rpx; +} + +.name-input { + flex: 1; + height: 70rpx; + border: 2rpx solid #e0e0e0; + border-radius: 12rpx; + padding: 0 20rpx; + font-size: 28rpx; + color: #333; + box-sizing: border-box; +} diff --git a/subpackage/train/bluetooth/bluetoothServe.js b/subpackage/train/bluetooth/bluetoothServe.js index 2f2a2af..b1a602c 100644 --- a/subpackage/train/bluetooth/bluetoothServe.js +++ b/subpackage/train/bluetooth/bluetoothServe.js @@ -4,10 +4,11 @@ const COMMAND = { PAUSE: 0x04, RESUME: 0x05, STOP: 0x06, - GET_COUNT: 'Get CT', + GET_COUNT: 'Get CT', START_COUNT: 'Start Count', STOP_COUNT: 'Stop Count', - CLEAN_COUNT: 'Clean Count' + CLEAN_COUNT: 'Clean Count', + GET_BATTERY: 'Get Batt' }; const DEVICE_TYPE = { @@ -73,9 +74,40 @@ function stringToArrayBuffer(str) { return buffer; } +// 获取设备电量,根据设备型号发送不同协议的命令 +function getBattery(deviceId, serviceId, deviceName) { + const characteristic = wx.getStorageSync('writeCharacteristic'); + if (!characteristic) { + console.error('没有可写的特征值'); + return; + } + + if (deviceName === DEVICE_TYPE.YD_O1) { + // YD-O1:二进制协议获取电量 + const commandData = new ArrayBuffer(4); + const dataView = new DataView(commandData); + dataView.setUint8(0, 0x07); // 获取电量命令字节 + dataView.setUint8(1, 0x00); + dataView.setUint8(2, 0x00); + dataView.setUint8(3, 0x00); + wx.writeBLECharacteristicValue({ + deviceId, + serviceId, + characteristicId: characteristic, + value: commandData, + success: () => console.log('YD-O1 获取电量命令已发送'), + fail: err => console.error('YD-O1 获取电量命令失败', err) + }); + } else { + // YD_Jump / YD-Jump:字符串协议获取电量 + sendCommandJump(deviceId, serviceId, COMMAND.GET_BATTERY); + } +} + module.exports = { COMMAND, DEVICE_TYPE, startFreeJumpRope, - sendCommandJump + sendCommandJump, + getBattery }; \ No newline at end of file diff --git a/subpackage/train/result/result.js b/subpackage/train/result/result.js index 0e1c6ab..aac6db1 100644 --- a/subpackage/train/result/result.js +++ b/subpackage/train/result/result.js @@ -58,7 +58,7 @@ Page({ }) if (who == 'user') { //用户端仅有跳绳====================================================================================== - if (theme == 'team') { + if (theme == 'team') { //2.添加团队任务成绩 const { data @@ -77,14 +77,23 @@ Page({ //1.添加个人目标成绩 const app = getApp() console.log(app) + console.log('自由训练') + const homeWorkList = await getHomeWorkType() + const sportObj = homeWorkList.data.filter(item => item.name == options.sportType) + let isTime = options.type == 'time' + let calorie = isTime ? options.count * sportObj[0].kcalIndex : amount * sportObj[0].kcalIndex * groupNumber let params = { - "personalGoalName": this.data.theme == 'small' ? '小学体测' : this.data.theme == 'fit' ? '健身减肥' : '中学考试', - "workModeType": 1, - "workModeTypeName": this.data.theme == 'small' ? '小学体测' : this.data.theme == 'fit' ? '健身减肥' : '中学考试', + "workType": sportObj[0].id, + "workTypeName": sportType, + "workModeType": isTime ? 1 : 2, + "workModeTypeName": isTime ? '定时计数' : this.data.type == 'num' ? '定数计时' : '自由训练', "duration": time, "amount": count, - "PersonalGoalType": this.data.theme == 'small' ? 2 : this.data.theme == 'fit' ? 1 : 2, - "dataSourceType": isAi == 'true' ? 2 : 1 + "dataSourceType": isAi == 'true' ? 2 : 1, + "calorie":calorie, + "startTime":this.getCurrentDateTime(), + "endTime":this.getCurrentDateTime(), + "groupNumber":1 } if (this.data.theme == 'small') { const dd = await getSmallScore({ @@ -165,7 +174,7 @@ Page({ console.log(params) const res = await postParentTrain(params) } - } + } }, diff --git a/subpackage/train/select-sport/select-sport.js b/subpackage/train/select-sport/select-sport.js new file mode 100644 index 0000000..b230c3c --- /dev/null +++ b/subpackage/train/select-sport/select-sport.js @@ -0,0 +1,39 @@ +const { sportKeyList } = require('../../../utils/soprt-key'); + +const sportEmojiMap = { + 'Rope-Skipping': '🪢', + 'Jumping-Jack': '🤸', + 'Sit-Up': '💪', + 'Push-Up': '🏋️', + 'Squat': '🦵', + 'Plank': '⚡', + 'High-Knee': '🏃', + 'Sit-Forward-Bend': '🧘', +}; + +const colorClasses = ['c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7']; + +Page({ + data: { + sportList: [] + }, + + onLoad(options) { + const excluded = ['Squat-Horse', 'Crunch']; + const sportList = sportKeyList + .filter(item => !excluded.includes(item.key)) + .map((item, index) => ({ + ...item, + emoji: sportEmojiMap[item.key] || '🏃', + colorClass: colorClasses[index % colorClasses.length], + })); + this.setData({ sportList }); + }, + + selectSport(e) { + const sportKey = e.currentTarget.id; + wx.navigateTo({ + url: '/subpackage/train/train/train?type=fit&sportKey=' + sportKey, + }); + } +}); diff --git a/subpackage/train/select-sport/select-sport.json b/subpackage/train/select-sport/select-sport.json new file mode 100644 index 0000000..0979b18 --- /dev/null +++ b/subpackage/train/select-sport/select-sport.json @@ -0,0 +1,8 @@ +{ + "usingComponents": { + "mp-bar": "weui-miniprogram/navigation-bar/navigation-bar" + }, + "navigationStyle": "custom", + "backgroundColor": "#f0f5ff", + "backgroundColorContent": "#f0f5ff" +} diff --git a/subpackage/train/select-sport/select-sport.wxml b/subpackage/train/select-sport/select-sport.wxml new file mode 100644 index 0000000..0b230d5 --- /dev/null +++ b/subpackage/train/select-sport/select-sport.wxml @@ -0,0 +1,55 @@ + + + + + + 一键开启 + + + 定制专属你的减脂蜕变 + + + + + + + {{ + theme=='small'?'小学体测':theme=='mid'?'中学考试':'健身减肥' + }} + + + + + 运动偏好 + + + + + + + + + + + + + + {{item.name}} + + › + + + + + + + + diff --git a/subpackage/train/select-sport/select-sport.wxss b/subpackage/train/select-sport/select-sport.wxss new file mode 100644 index 0000000..80b66ed --- /dev/null +++ b/subpackage/train/select-sport/select-sport.wxss @@ -0,0 +1,357 @@ +page{ + background-color: rgb(247, 247, 247); +} + +.page-content{ + background-color: rgb(247, 247, 247); + background: linear-gradient(190deg, #49a5fc 0%, #f7f7f7 800rpx, #f7f7f7 100%); + padding: 0 30rpx; + box-sizing: border-box; + min-height: 100vh; + padding-bottom: 80rpx; +} + + + +/* ===== 头部 ===== */ +.header { + /* background: linear-gradient(160deg, #0d1f3c 0%, #0d2a55 100%); */ + padding: 0 44rpx 52rpx; + position: relative; + overflow: hidden; +} + +.header-glow { + position: absolute; + width: 500rpx; + height: 500rpx; + border-radius: 50%; + background: radial-gradient(circle, rgba(0,130,255,0.2) 0%, transparent 70%); + top: -180rpx; + right: -120rpx; + pointer-events: none; +} + +.header-content { + position: relative; + z-index: 1; + padding-top: 6rpx; +} + +.header-kicker { + font-size: 22rpx; + color: #4fc3f7; + letter-spacing: 3rpx; + margin-bottom: 18rpx; + font-weight: 500; +} + +.header-title { + font-size: 58rpx; + font-weight: bold; + color: #fff; + line-height: 1.15; + margin-bottom: 22rpx; + letter-spacing: 1rpx; +} + +.header-meta { + display: flex; + align-items: center; + gap: 14rpx; + font-size: 24rpx; + color: rgba(255,255,255,0.45); +} + +.meta-dot { + width: 8rpx; + height: 8rpx; + border-radius: 50%; + background: #4fc3f7; + opacity: 0.7; + flex-shrink: 0; +} + +/* ===== 2列卡片网格 ===== */ +.grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 28rpx; + padding: 30rpx 0 ; + box-sizing: border-box; +} + +/* 单张卡片 */ +.card { + border-radius: 22rpx; + padding: 28rpx 24rpx 24rpx; + box-sizing: border-box; + display: flex; + flex-direction: column; + /* height: 272rpx; */ + position: relative; + overflow: hidden; + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.12); +} + +.card:active { + opacity: 0.82; + transform: scale(0.96); +} + +/* 卡片内装饰圆 */ +.card-circle-1 { + position: absolute; + width: 200rpx; + height: 200rpx; + border-radius: 50%; + background: rgba(255, 255, 255, 0.12); + top: -80rpx; + right: -60rpx; + pointer-events: none; +} + +.card-circle-2 { + position: absolute; + width: 100rpx; + height: 100rpx; + border-radius: 50%; + background: rgba(255, 255, 255, 0.08); + bottom: -30rpx; + left: -20rpx; + pointer-events: none; +} + +/* emoji 区域:占据卡片中局上半部分 */ +.card-emoji-wrap { + flex: 1; + display: flex; + align-items: center; + position: relative; + z-index: 1; +} +.card-emoji-wrap image { + width: 100rpx; + height: 100rpx; +} + + +.card-emoji { + font-size: 80rpx; + line-height: 1; + filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.15)); +} + +/* 底部:名称 + 箭头同一行 */ +.card-bottom { + display: flex; + align-items: center; + justify-content: space-between; + position: relative; + z-index: 1; +} + +.card-name { + font-size: 30rpx; + font-weight: bold; + color: #fff; + line-height: 1; + text-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.15); +} + +.card-arrow-circle { + width: 48rpx; + height: 48rpx; + border-radius: 50%; + background: rgba(255, 255, 255, 0.25); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.card-arrow-text { + font-size: 32rpx; + color: #fff; + line-height: 1; + margin-top: -2rpx; + padding-left: 2rpx; +} + +/* ===== 8种卡片颜色 ===== */ +.c0 { background: linear-gradient(140deg, #ff6b6b 0%, #ee2d2d98 100%); } +.c1 { background: linear-gradient(140deg, #ffa340 0%, #f0600098 100%); } +.c2 { background: linear-gradient(140deg, #20c997 0%, #0a8f6098 100%); } +.c3 { background: linear-gradient(140deg, #a855f7 0%, #6d28d998 100%); } +.c4 { background: linear-gradient(140deg, #3b82f6 0%, #1d4ed898 100%); } +.c5 { background: linear-gradient(140deg, #06b6d4 0%, #0284c798 100%); } +.c6 { background: linear-gradient(140deg, #f43f8e 0%, #be185d98 100%); } +.c7 { background: linear-gradient(140deg, #34d399 0%, #05966998 100%); } + + + +.title{ + font-weight: bold; + font-size: 32rpx; + display: flex; + align-items: center; + justify-content: center; + margin-top: 66rpx; + margin-bottom: 20rpx; +} + +.title-before{ + height: 24rpx; + border-radius: 6rpx; + width: 6rpx; + margin-right: 20rpx; + background:linear-gradient(180.00deg, rgb(38, 165, 246),rgba(38, 165, 246, 0) 100%) +} + +.play{ + padding: 0 30rpx 0 30rpx; + box-sizing: border-box; + display: flex; + justify-content: space-between; + /* margin-bottom: -170rpx; */ + /* min-height: 428rpx; */ + height: 350rpx; + overflow: hidden; +} + +.logo-play{ + margin-right: -82rpx; + width: 428rpx; + height: 428rpx; + /* z-index: 1; */ + /* overflow: hidden; */ +} + +.play-text{ + font-size: 28rpx; + padding-top: 70rpx; +} + +.text-style{ + font-weight: bold; +} + +.text-line{ + height: 16rpx; + background-color: #FFC20E; + border-radius: 10rpx; + width: 110rpx; + margin-top: -18rpx; + margin-bottom: 10rpx; +} + +.tab{ + width: 536rpx; + display: flex; + height: 80rpx; + font-size: 28rpx; + margin-top: -80rpx; + font-weight: bold; +} + +.tab-l{ + flex: 1; + background-color: rgba(38, 165, 246, 1); + /* backdrop-filter: blur(20rpx); */ + border-radius: 20rpx 0 0 0; + color: #000; +} + +.tab-l-content{ + background-color: #fff; + border-radius: 20rpx 38rpx 0 0; + height: 80rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.tab-r{ + flex: 1; + background:linear-gradient(90deg,rgba(255,255,255,1) 0%, rgba(255,255,255,.6) 30%) ; + border-radius: 0 20rpx 0 0rpx; + +} + +.tab-r-content{ + background: linear-gradient(90deg, rgba(38, 165, 246, 1) 0%, rgba(38, 165, 246, 0.7) 50%, + rgba(38, 165, 246, 0.7) 100%); + border-radius: 0 20rpx 0 38rpx; + display: flex; + align-items: center; + justify-content: center; + height: 80rpx; + color: #fff; +} + +.card1{ + width: 100%; + background: #fff; + border-radius: 0 20rpx 20rpx 20rpx; + padding: 16rpx 18rpx 24rpx; + box-sizing: border-box; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); +} + +.iconn{ + margin-right: 6rpx; + margin-top: -6rpx; +} + +.cell{ + padding: 44rpx 4rpx; + box-sizing: border-box; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 26rpx; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); +} + +.left{ + display: flex; + align-items: center; +} + +.left-img{ + width: 48rpx; + height: 48rpx; + margin-right: 26rpx; +} + +.desc{ + text-align: center; + font-size: 26rpx; + max-width: 60%; + text-align: left; +} + +.name{ + margin-top: 4rpx; + font-size: 24rpx; + color: #777777; +} + +.right{ + border-radius: 75px; + background: rgb(38, 166, 246); + padding: 12rpx 0rpx; + width: 120rpx; + color: #fff; + font-size: 24rpx; + box-sizing: border-box; + text-align: center; + width: 160rpx; + min-width: 160rpx; +} + +.use{ + color: rgb(38, 166, 246); + background-color: #fff; + border: 2rpx solid rgb(38, 166, 246); +} diff --git a/subpackage/train/train/train.js b/subpackage/train/train/train.js index 70f172e..4bd1e0f 100644 --- a/subpackage/train/train/train.js +++ b/subpackage/train/train/train.js @@ -1,5 +1,6 @@ const tabService = require("../../../utils/tab-serve"); const util = require("../../../utils/utils") +const { sportKeyObj, sportDes } = require('../../../utils/soprt-key') import {getAreaList} from "../../../utils/serve/train" const app = getApp() Page({ @@ -14,6 +15,10 @@ Page({ number: 100, //计数 timeStr:'01:00', theme:'small', + sportKey: '', + sportName: '', + sportDesc: '', + videoUrl: '', gradeList:[ '一年级', '二年级', @@ -34,8 +39,16 @@ Page({ */ async onLoad(options) { this.setData({ - theme:options.type + theme: options.type }) + if (options.sportKey) { + this.setData({ + sportKey: options.sportKey, + sportName: sportKeyObj[options.sportKey] || '', + sportDesc: sportDes[options.sportKey] || '', + videoUrl: 'https://yuedong-wechatapplet.oss-cn-shanghai.aliyuncs.com/static/train/video/new/' + options.sportKey + '.mp4', + }) + } if(options.type == 'mid'){ const res = await getAreaList() this.setData({ @@ -132,12 +145,17 @@ Page({ if(this.data.sex == '' && this.data.theme != 'fit') return app.showToast('请选择性别') if(this.data.theme == 'small' && this.data.grade == '') return app.showToast('请选择年级') if(this.data.theme == 'mid' && this.data.areaId == '') return app.showToast('请选择省份') - console.log(getApp()) - const data = `&type=${this.data.tabName}&time=${this.data.time}&number=${this.data.number}&theme=${this.data.theme}` - wx.navigateTo({ - // url: '/module-sport/pages/sport-full-screen?sportKey=Rope-Skipping'+data, - url: '/subpackage/train/check-type/check-page?sportKey=Rope-Skipping'+data, - }) + const sportKey = this.data.sportKey || 'Rope-Skipping' + const data = `&type=${this.data.tabName}&time=${this.data.time}&number=${this.data.number}&theme=myself` + if(this.data.sportKey == 'Rope-Skipping' ){ + wx.navigateTo({ + url: '/subpackage/train/check-type/check-page?sportKey=' + this.data.sportKey + data, + }) + }else{ + wx.navigateTo({ + url: '/module-sport/pages/sport-full-screen?sportKey=' + this.data.sportKey + data, + }) + } }, handleCancel() { diff --git a/subpackage/train/train/train.wxml b/subpackage/train/train/train.wxml index 5468d4f..5146f96 100644 --- a/subpackage/train/train/train.wxml +++ b/subpackage/train/train/train.wxml @@ -1,7 +1,8 @@ - + + 一键开启 @@ -12,7 +13,35 @@ - + + + + {{sportName}} + 健身减肥 + + + + + + + + 动作说明 + + {{sportDesc}} + + + + diff --git a/subpackage/train/train/train.wxss b/subpackage/train/train/train.wxss index 8d227e2..de5983e 100644 --- a/subpackage/train/train/train.wxss +++ b/subpackage/train/train/train.wxss @@ -74,6 +74,10 @@ page{ margin-top: -80rpx; } +.tab-fit { + margin-top: 0; +} + .tab-l{ flex: 1; background-color: rgba(38, 165, 246, 1); @@ -114,10 +118,10 @@ page{ min-height: 1000rpx; width: 100%; background: #fff; - border-radius: 0 20rpx 20rpx 20rpx; + border-radius: 20rpx; padding: 60rpx 100rpx; box-sizing: border-box; - box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.04); + box-shadow: 1px 1px 4px 2px rgba(0, 0, 0, 0.04); } .iconn{ @@ -223,5 +227,76 @@ page{ .click{ color: #0082FF; background-color: #e9f6fe; +} -} \ No newline at end of file +/* ===== 健身减肥模式 - 视频展示区 ===== */ +.play-fit { + /* padding: 0 30rpx; */ + box-sizing: border-box; + margin-bottom: 20rpx; +} + +.play-fit-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 24rpx 0 20rpx 0; +} + +.play-fit-name { + font-size: 44rpx; + font-weight: bold; + color: #fff; +} + +.play-fit-tag { + font-size: 22rpx; + color: rgba(255, 255, 255, 0.9); + background: rgba(255, 255, 255, 0.25); + border-radius: 20rpx; + padding: 6rpx 20rpx; + backdrop-filter: blur(10rpx); +} + +.video-wrap { + width: 100%; + border-radius: 24rpx; + overflow: hidden; + box-shadow: 0 8rpx 32rpx rgba(0, 130, 255, 0.2); + /* background: #000; */ +} + +.sport-video { + width: 100%; + height: 400rpx; + display: block; +} + +.sport-desc-card { + margin-top: 20rpx; + background: rgba(255, 255, 255, 0.95); + border-radius: 20rpx; + padding: 28rpx 30rpx; + box-sizing: border-box; + box-shadow: 0 4rpx 16rpx rgba(0, 130, 255, 0.1); +} + +.sport-desc-title { + display: flex; + align-items: center; + font-size: 28rpx; + font-weight: bold; + color: #1a1a2e; + margin-bottom: 16rpx; +} + +.desc-icon { + margin-right: 10rpx; + font-size: 28rpx; +} + +.sport-desc-text { + font-size: 26rpx; + color: #555; + line-height: 1.8; +} diff --git a/utils/soprt-key.js b/utils/soprt-key.js index c3f9174..f50513f 100644 --- a/utils/soprt-key.js +++ b/utils/soprt-key.js @@ -56,8 +56,23 @@ let sportKeyObj = { "Sit-Forward-Bend":"坐位体前屈", } +let sportDes = { + "Rope-Skipping":"双手打开与肩同宽或稍宽,手指指向前方,手掌平放在地面上,确保双手稳定支撑身体。慢慢弯曲手肘,使身体逐渐下降,下降至胸部几乎贴近地面时停止,伸臂起身还原。", + "Jumping-Jack":"双脚掌蹬地跳起,打开双脚与肩同宽,双手举过头顶击掌落地。.面正对手机,保持在图像中间。", + "Sit-Up":"手臂抱头于头部两侧,脚底并拢,脚跟靠近臀部,腹肌发力起身,下放时背部、肩部、头部依次着地。", + "Push-Up":"双手打开与肩同宽或稍宽,手指指向前方,手掌平放在地面上,确保双手稳定支撑身体。慢慢弯曲手肘,使身体逐渐下降,下降至胸部几乎贴近地面时停止,伸臂起身还原。", + "Crunch":"", + "Squat":"双脚分开与肩同宽或略宽,脚尖可以稍微外展(约30度),在保持背部挺直的前提下,慢慢屈膝下蹲至髌骨顶端所在的水平面,再缓慢起身。", + "Plank":"俯身面对地面,屈肘,前臂平放在地面上,确保手肘与肩膀处于同一垂直线上,双腿伸直,双脚并拢或稍微分开,使身体从头到脚呈一条直线。在整个平板支撑过程中,需要保持腹部肌肉持续收紧,这有助于维持身体的稳定性和平衡性", + "High-Knee":"双脚与肩同宽,身体保持直立,保持腹部收紧,前脚掌着地快速交替抬腿。在整个动作过程中,保持身体直立且稳定,避免晃动或摇摆。", + "Squat-Horse":"马步蹲", + "Sit-Forward-Bend":"坐位体前屈", +} + + module.exports = { sportKeyList, sportNameObj, - sportKeyObj + sportKeyObj, + sportDes } \ No newline at end of file