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 @@
-
+
+
+
+
+
+
+
+
+
+ 动作说明
+
+ {{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