refactor: 训练模块整体迁入分包,减小主包体积
主包超出 2MB 上限无法上传发布版,把训练相关全部移到独立分包。
目录调整:
- pages/training/* → training/pages/*
- hooks/use{Metronome,VoiceCoach,TrainingSession,TrainingBgm}.ts
→ training/hooks/*
- static/training/* → training/static/*
- 主包 hooks/ 目录已清空,所有 use* 都被分包独占
引用路径更新:
- 分包内 hook import 用相对路径 ../hooks/xxx,不依赖 @/ alias
- 资源路径 /static/training/audio/click.mp3
→ /training/static/audio/click.mp3
- useMetronome 默认 clickSrc / useVoiceCoach VOICE_BASE
/ useTrainingBgm BGM_BASE 全部对齐新路径
pages.json:
- 主包 pages 移除 training/index 和 training/metronome
- subPackages 新增 root="training",含 pages/index 和 pages/metronome
- 跟现有 TUIKit / doctor 分包风格一致
调用方:
- components/dev-training-entry navigateTo URL 更新成
/training/pages/metronome (此组件留在主包,主包跳分包是合法操作)
文档/工具同步:
- training/static/README.md 路径示例改为 training/static/...
- scripts/generate-voice.mjs VOICE_DIR 与提示输出对齐新路径
Git mv 检测到的全是 rename(R),历史完整保留。
分包总体 80K(pages 44K + hooks 20K + static 16K),主包瘦身明显。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
<!-- 展开后的菜单卡片(从下往上动画) -->
|
<!-- 展开后的菜单卡片(从下往上动画) -->
|
||||||
<view v-if="expanded" class="menu-list" @click.stop>
|
<view v-if="expanded" class="menu-list" @click.stop>
|
||||||
<!-- "练一练" 暂时隐藏,后续恢复时取消注释即可
|
<!-- "练一练" 暂时隐藏,后续恢复时取消注释即可
|
||||||
<view class="menu-item" @click="goto('/pages/training/index')">
|
<view class="menu-item" @click="goto('/training/pages/index')">
|
||||||
<view class="menu-icon menu-icon--train">
|
<view class="menu-icon menu-icon--train">
|
||||||
<text class="menu-icon-text">💪</text>
|
<text class="menu-icon-text">💪</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<view class="menu-arrow">›</view>
|
<view class="menu-arrow">›</view>
|
||||||
</view>
|
</view>
|
||||||
-->
|
-->
|
||||||
<view class="menu-item" @click="goto('/pages/training/metronome')">
|
<view class="menu-item" @click="goto('/training/pages/metronome')">
|
||||||
<view class="menu-icon menu-icon--metro">
|
<view class="menu-icon menu-icon--metro">
|
||||||
<view class="metro-bar metro-bar-1" />
|
<view class="metro-bar metro-bar-1" />
|
||||||
<view class="metro-bar metro-bar-2" />
|
<view class="metro-bar metro-bar-2" />
|
||||||
|
|||||||
+21
-16
@@ -69,22 +69,6 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "付款"
|
"navigationBarTitleText": "付款"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/training/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "练一练"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/training/metronome",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "节拍器",
|
|
||||||
"navigationBarBackgroundColor": "#f8fafc",
|
|
||||||
"navigationBarTextStyle": "black",
|
|
||||||
"backgroundColor": "#f8fafc",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
@@ -121,6 +105,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "training",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "pages/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "练一练"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/metronome",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "节拍器",
|
||||||
|
"navigationBarBackgroundColor": "#f8fafc",
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"backgroundColor": "#f8fafc",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
* node scripts/generate-voice.mjs --voice 茉莉
|
* node scripts/generate-voice.mjs --voice 茉莉
|
||||||
* node scripts/generate-voice.mjs --force # 已存在的也重新生成
|
* node scripts/generate-voice.mjs --force # 已存在的也重新生成
|
||||||
*
|
*
|
||||||
* 输出:
|
* 输出(分包):
|
||||||
* src/static/training/voice/numbers/{1..30}.mp3
|
* training/static/voice/numbers/{1..30}.mp3
|
||||||
* src/static/training/voice/prompts/{key}.mp3
|
* training/static/voice/prompts/{key}.mp3
|
||||||
*
|
*
|
||||||
* 需要 Node 18+(用内置 fetch)
|
* 需要 Node 18+(用内置 fetch)
|
||||||
*/
|
*/
|
||||||
@@ -32,7 +32,7 @@ const __filename = fileURLToPath(import.meta.url)
|
|||||||
const __dirname = dirname(__filename)
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
const ROOT = join(__dirname, '..')
|
const ROOT = join(__dirname, '..')
|
||||||
const VOICE_DIR = join(ROOT, 'src/static/training/voice')
|
const VOICE_DIR = join(ROOT, 'training/static/voice')
|
||||||
const NUMBERS_DIR = join(VOICE_DIR, 'numbers')
|
const NUMBERS_DIR = join(VOICE_DIR, 'numbers')
|
||||||
const PROMPTS_DIR = join(VOICE_DIR, 'prompts')
|
const PROMPTS_DIR = join(VOICE_DIR, 'prompts')
|
||||||
|
|
||||||
@@ -202,9 +202,9 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('\n下一步:')
|
console.log('\n下一步:')
|
||||||
console.log(' 1. 准备 click 音 → src/static/training/audio/click.mp3')
|
console.log(' 1. 准备 click 音 → training/static/audio/click.mp3')
|
||||||
console.log(' 2. 准备 BGM → src/static/training/bgm/{train-light,rest-meditation}.mp3')
|
console.log(' 2. 准备 BGM → training/static/bgm/{train-light,rest-meditation}.mp3')
|
||||||
console.log(' 3. npm run dev:mp-weixin → 进入 /pages/training/index')
|
console.log(' 3. 编译运行 → 进入 /training/pages/index')
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((e) => {
|
main().catch((e) => {
|
||||||
|
|||||||
+1
-1
@@ -93,7 +93,7 @@ export function useMetronome(options: MetronomeOptions = {}) {
|
|||||||
initialBpm = 80,
|
initialBpm = 80,
|
||||||
bpmMin = 40,
|
bpmMin = 40,
|
||||||
bpmMax = 240,
|
bpmMax = 240,
|
||||||
clickSrc = '/static/training/audio/click.mp3',
|
clickSrc = '/training/static/audio/click.mp3',
|
||||||
accentSrc,
|
accentSrc,
|
||||||
poolSize = 4,
|
poolSize = 4,
|
||||||
onBeat,
|
onBeat,
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { ref, onUnmounted } from 'vue'
|
import { ref, onUnmounted } from 'vue'
|
||||||
|
|
||||||
const BGM_BASE = '/static/training/bgm'
|
const BGM_BASE = '/training/static/bgm'
|
||||||
|
|
||||||
export type BgmMode = 'none' | 'training' | 'resting'
|
export type BgmMode = 'none' | 'training' | 'resting'
|
||||||
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { onUnmounted } from 'vue'
|
import { onUnmounted } from 'vue'
|
||||||
|
|
||||||
const VOICE_BASE = '/static/training/voice'
|
const VOICE_BASE = '/training/static/voice'
|
||||||
|
|
||||||
export type VoicePromptKey =
|
export type VoicePromptKey =
|
||||||
| 'start'
|
| 'start'
|
||||||
@@ -151,10 +151,10 @@ import { onShow, onHide } from '@dcloudio/uni-app'
|
|||||||
import ExerciseAnim from './components/exercise-anim.vue'
|
import ExerciseAnim from './components/exercise-anim.vue'
|
||||||
import { EXERCISE_PRESETS, getPresetById } from './exercises'
|
import { EXERCISE_PRESETS, getPresetById } from './exercises'
|
||||||
import type { ExercisePreset } from './exercises'
|
import type { ExercisePreset } from './exercises'
|
||||||
import { useMetronome } from '@/hooks/useMetronome'
|
import { useMetronome } from '../hooks/useMetronome'
|
||||||
import { useTrainingSession } from '@/hooks/useTrainingSession'
|
import { useTrainingSession } from '../hooks/useTrainingSession'
|
||||||
import { useVoiceCoach } from '@/hooks/useVoiceCoach'
|
import { useVoiceCoach } from '../hooks/useVoiceCoach'
|
||||||
import { useTrainingBgm } from '@/hooks/useTrainingBgm'
|
import { useTrainingBgm } from '../hooks/useTrainingBgm'
|
||||||
|
|
||||||
const equipmentList = ['哑铃', '握力环', '健身环', '徒手'] as const
|
const equipmentList = ['哑铃', '握力环', '健身环', '徒手'] as const
|
||||||
type Equipment = (typeof equipmentList)[number]
|
type Equipment = (typeof equipmentList)[number]
|
||||||
@@ -286,7 +286,7 @@ const onSkipRest = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const goMetronome = () => {
|
const goMetronome = () => {
|
||||||
uni.navigateTo({ url: '/pages/training/metronome' })
|
uni.navigateTo({ url: '/training/pages/metronome' })
|
||||||
}
|
}
|
||||||
|
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
+3
-3
@@ -89,7 +89,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { onShow, onHide } from '@dcloudio/uni-app'
|
import { onShow, onHide } from '@dcloudio/uni-app'
|
||||||
import { useMetronome } from '@/hooks/useMetronome'
|
import { useMetronome } from '../hooks/useMetronome'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跑步动画视频(腾讯云 COS CDN)
|
* 跑步动画视频(腾讯云 COS CDN)
|
||||||
@@ -145,8 +145,8 @@ const METER_OPTIONS = [
|
|||||||
const metronome = useMetronome({
|
const metronome = useMetronome({
|
||||||
initialBpm: 80,
|
initialBpm: 80,
|
||||||
accentEvery: 4,
|
accentEvery: 4,
|
||||||
clickSrc: '/static/training/audio/click.mp3',
|
clickSrc: '/training/static/audio/click.mp3',
|
||||||
accentSrc: '/static/training/audio/click-wood.mp3',
|
accentSrc: '/training/static/audio/click-wood.mp3',
|
||||||
})
|
})
|
||||||
const {
|
const {
|
||||||
bpm,
|
bpm,
|
||||||
+4
-4
@@ -5,7 +5,7 @@
|
|||||||
## 目录结构
|
## 目录结构
|
||||||
|
|
||||||
```
|
```
|
||||||
src/static/training/
|
training/static/
|
||||||
├── audio/
|
├── audio/
|
||||||
│ └── click.mp3 # 节拍器主音(短促金属敲击声,约 50ms)
|
│ └── click.mp3 # 节拍器主音(短促金属敲击声,约 50ms)
|
||||||
├── voice/
|
├── voice/
|
||||||
@@ -92,9 +92,9 @@ node scripts/generate-voice.mjs --force
|
|||||||
|
|
||||||
## 在代码里被引用的位置
|
## 在代码里被引用的位置
|
||||||
|
|
||||||
- `src/hooks/useMetronome.ts` → `audio/click.mp3`
|
- `training/hooks/useMetronome.ts` → `audio/click.mp3`
|
||||||
- `src/hooks/useVoiceCoach.ts` → `voice/numbers/*.mp3`、`voice/prompts/*.mp3`
|
- `training/hooks/useVoiceCoach.ts` → `voice/numbers/*.mp3`、`voice/prompts/*.mp3`
|
||||||
- `src/hooks/useTrainingBgm.ts` → `bgm/*.mp3`
|
- `training/hooks/useTrainingBgm.ts` → `bgm/*.mp3`
|
||||||
|
|
||||||
如需修改路径,修改对应 hook 文件里的常量即可。
|
如需修改路径,修改对应 hook 文件里的常量即可。
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 730 B |
Reference in New Issue
Block a user