diff --git a/TUICallKit-Vue3/pages.json b/TUICallKit-Vue3/pages.json index 229719a4..3be3355e 100644 --- a/TUICallKit-Vue3/pages.json +++ b/TUICallKit-Vue3/pages.json @@ -122,7 +122,6 @@ "navigationBarBackgroundColor": "#f8fafc", "navigationBarTextStyle": "black", "backgroundColor": "#f8fafc", - "disableScroll": true, "requiredBackgroundModes": ["audio"] } } diff --git a/TUICallKit-Vue3/training/hooks/useMetronome.ts b/TUICallKit-Vue3/training/hooks/useMetronome.ts index 0f4bc2f2..adb26e52 100644 --- a/TUICallKit-Vue3/training/hooks/useMetronome.ts +++ b/TUICallKit-Vue3/training/hooks/useMetronome.ts @@ -88,12 +88,17 @@ class AudioPool { } } +/* InnerAudio 兼容本地路径和网络 URL,这里默认走 CDN,跟 BgAudio 保持一致便于维护 + 首次播放会下载 ~3KB,实测 100~300ms 完成,然后小程序会缓存,后续触发零延迟 */ +const DEFAULT_CLICK_SRC = + 'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/20260526105128557ef8669.mp3' + export function useMetronome(options: MetronomeOptions = {}) { const { initialBpm = 80, bpmMin = 40, bpmMax = 240, - clickSrc = '/training/static/audio/click.mp3', + clickSrc = DEFAULT_CLICK_SRC, accentSrc, poolSize = 4, onBeat, diff --git a/TUICallKit-Vue3/training/hooks/useMetronomeBg.ts b/TUICallKit-Vue3/training/hooks/useMetronomeBg.ts index d362f625..48682ddf 100644 --- a/TUICallKit-Vue3/training/hooks/useMetronomeBg.ts +++ b/TUICallKit-Vue3/training/hooks/useMetronomeBg.ts @@ -28,31 +28,48 @@ export interface LoopPreset { label: string } +/** + * 重要:微信 BackgroundAudioManager.src 只接受 http/https 网络流,不能是包内资源 + * 所以必须把音频上传到 CDN(腾讯云 COS),并在小程序后台加 downloadFile 合法域名 + * + * 当前线上文件(2026-05-26 上传到 cos.ap-guangzhou): + * - loop_80bpm_2.mp3 循环音轨 慢走档 + * - loop_110bpm_2.mp3 循环音轨 健走档 + * - loop_130bpm_2.mp3 循环音轨 快走档 + * + * 历史源文件(本地 training/static/audio/*.mp3) 已删除以减小包体积, + * 如果以后要重新合成,先从 COS 下回来再用 ffmpeg 处理 + */ export const LOOP_PRESETS: readonly LoopPreset[] = [ { id: 'slow', bpm: 80, accent: 2, - src: '/training/static/audio/loop_80bpm_2.mp3', + src: 'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/20260526105129dcbc50112.mp3', label: '慢走 80 BPM', }, { id: 'normal', bpm: 110, accent: 2, - src: '/training/static/audio/loop_110bpm_2.mp3', + src: 'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/202605261051284f5b04928.mp3', label: '健走 110 BPM', }, { id: 'brisk', bpm: 130, accent: 2, - src: '/training/static/audio/loop_130bpm_2.mp3', + src: 'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/20260526105128164d77281.mp3', label: '快走 130 BPM', }, ] -const COVER_URL = '/training/static/audio/cover.jpg' +/** + * 锁屏控制条封面 + * 暂时留空,微信会显示默认音乐图标,等以后有正式品牌图再上传到 COS 后填入这里 + * 注意:URL 必须是 https,且域名要加进小程序后台 downloadFile 合法域名 + */ +const COVER_URL = '' export function useMetronomeBg() { const isPlaying = ref(false) @@ -74,7 +91,7 @@ export function useMetronomeBg() { m.title = '节拍器' m.epname = '甄养堂 · 健走' m.singer = '健走配速' - m.coverImgUrl = COVER_URL + if (COVER_URL) m.coverImgUrl = COVER_URL m.webUrl = '' m.onPlay(() => { diff --git a/TUICallKit-Vue3/training/pages/metronome.vue b/TUICallKit-Vue3/training/pages/metronome.vue index 9057ee92..e62df55e 100644 --- a/TUICallKit-Vue3/training/pages/metronome.vue +++ b/TUICallKit-Vue3/training/pages/metronome.vue @@ -50,7 +50,7 @@ v-for="p in LOOP_PRESETS" :key="p.id" class="preset" - :class="{ active: currentLoop === p.id }" + :class="{ active: mode === 'preset' && currentLoop === p.id }" @click="onPresetTap(p.id)" > {{ presetIcon(p.id) }} @@ -60,9 +60,46 @@ - - - 🔒 锁屏可继续播放,放兜里走也能听到 + + + + + 前台模式 · 切后台会暂停 + + + + + BPM + + −5 + −1 + {{ customBpm }} + +1 + +5 + + + + + + 拍号 + + {{ n }}/4 + + + + + + + + {{ customExpanded ? '✕ 收起自定义' : '⚙ 自定义节奏' }} + + 🔒 锁屏可继续播放 @@ -71,6 +108,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { onShow, onHide } from '@dcloudio/uni-app' import { useMetronomeBg, type LoopId } from '../hooks/useMetronomeBg' +import { useMetronome } from '../hooks/useMetronome' /** * 跑步动画视频(腾讯云 COS CDN) @@ -83,10 +121,54 @@ const RUNNER_VIDEO_URL = /** 视频原速对应的 BPM 基准, playback-rate 范围 [0.5, 2.0] */ const VIDEO_BASE_BPM = 124 -const { isPlaying, currentLoop, playLoop, pause, resume, stop, LOOP_PRESETS } = - useMetronomeBg() +/* ============================================================ + * 双引擎设计 + * ------------------------------------------------------------ + * - mode='preset': 用 BgAudio 播预合成 mp3,支持后台/锁屏(走路场景) + * - mode='custom': 用 InnerAudio 实时合成,支持任意 BPM/拍号,但仅前台 + * - 切模式时停掉对侧引擎,避免双声道叠加 + * ============================================================ */ +type Mode = 'preset' | 'custom' +const mode = ref('preset') +const customExpanded = ref(false) -/* 档位元数据(图标/名称/描述) */ +/* click-wood.mp3 (CDN), 木鱼质感的敲击音 */ +const CLICK_WOOD_URL = + 'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/202605261051282a0a94508.mp3' + +const bg = useMetronomeBg() +const fg = useMetronome({ + initialBpm: 100, + accentEvery: 2, + clickSrc: CLICK_WOOD_URL, + accentSrc: CLICK_WOOD_URL, + poolSize: 4, +}) + +const { LOOP_PRESETS } = bg +const currentLoop = bg.currentLoop + +const customBpm = computed(() => fg.bpm.value) +const customAccent = computed(() => fg.accentEvery.value) + +/* 统一对外暴露的 isPlaying / currentBpm,根据 mode 选择信号源 */ +const isPlaying = computed(() => + mode.value === 'preset' ? bg.isPlaying.value : fg.isPlaying.value, +) + +const currentBpm = computed(() => { + if (mode.value === 'preset') { + const p = LOOP_PRESETS.find((p) => p.id === currentLoop.value) + return p?.bpm ?? 110 + } + return fg.bpm.value +}) + +const intervalMs = computed(() => 60000 / currentBpm.value) + +/* ============================================================ + * 档位元数据 + * ============================================================ */ const presetIcon = (id: LoopId) => id === 'slow' ? '🚶' : id === 'normal' ? '🏃‍♀️' : '🏃' const presetName = (id: LoopId) => @@ -94,42 +176,83 @@ const presetName = (id: LoopId) => const presetDesc = (id: LoopId) => id === 'slow' ? '热身 · 恢复' : id === 'normal' ? '日常 · 通勤' : '提速 · 燃脂' -const currentPreset = computed(() => - currentLoop.value - ? LOOP_PRESETS.find((p) => p.id === currentLoop.value) ?? null - : null, -) - -const currentBpm = computed(() => currentPreset.value?.bpm ?? 110) -const intervalMs = computed(() => 60000 / currentBpm.value) - -/* 中央圆按钮: - - 没选档位 → 默认开"健走" - - 选了档位且在播 → 暂停 - - 选了档位且暂停 → 恢复 */ +/* ============================================================ + * 中央圆按钮:在两个模式下分别工作 + * ============================================================ */ const onCenterTap = () => { - if (!currentLoop.value) { - playLoop('normal') - uni.setKeepScreenOn({ keepScreenOn: true }) - return - } - if (isPlaying.value) { - pause() - uni.setKeepScreenOn({ keepScreenOn: false }) + if (mode.value === 'preset') { + if (!currentLoop.value) { + bg.playLoop('normal') + uni.setKeepScreenOn({ keepScreenOn: true }) + return + } + if (bg.isPlaying.value) { + bg.pause() + uni.setKeepScreenOn({ keepScreenOn: false }) + } else { + bg.resume() + uni.setKeepScreenOn({ keepScreenOn: true }) + } } else { - resume() - uni.setKeepScreenOn({ keepScreenOn: true }) + /* custom 模式 */ + if (fg.isPlaying.value) { + fg.stop() + uni.setKeepScreenOn({ keepScreenOn: false }) + } else { + fg.start() + uni.setKeepScreenOn({ keepScreenOn: true }) + } } } -/* 档位卡片: - - 点未选档位 → 切到该档位并播放 - - 点当前档位 → 切到暂停/恢复 */ +/* ============================================================ + * 档位卡片:点了 → 切回 preset 模式 + 停掉 custom + * ============================================================ */ const onPresetTap = (id: LoopId) => { - playLoop(id) + if (mode.value === 'custom') { + fg.stop() + mode.value = 'preset' + customExpanded.value = false + } + bg.playLoop(id) uni.setKeepScreenOn({ keepScreenOn: true }) } +/* ============================================================ + * 自定义折叠区切换 + * ============================================================ */ +const onToggleCustom = () => { + if (!customExpanded.value) { + /* 展开:进入 custom 模式 + 停掉 preset */ + if (bg.isPlaying.value || currentLoop.value) { + bg.stop() + } + mode.value = 'custom' + /* 把当前显示 BPM 带过去当起始值 */ + const seed = + LOOP_PRESETS.find((p) => p.id === (currentLoop.value ?? 'normal'))?.bpm ?? 100 + fg.setBpm(seed) + fg.setAccentEvery(2) + /* 立即预热 InnerAudio,避免首拍冷启动延迟 */ + fg.preload() + customExpanded.value = true + } else { + /* 收起:回到 preset,停掉 fg */ + fg.stop() + mode.value = 'preset' + customExpanded.value = false + uni.setKeepScreenOn({ keepScreenOn: false }) + } +} + +const onBpmDelta = (delta: number) => { + fg.setBpm(fg.bpm.value + delta) +} + +const onAccentSelect = (n: number) => { + fg.setAccentEvery(n) +} + /* ============================================================ * 视频实例与 BPM 同步 * ============================================================ */ @@ -175,23 +298,28 @@ const rootStyle = computed(() => ({ })) onShow(() => { - /* BgAudio 全局单例,无需特殊预热,首次 setSrc 时自动初始化 */ + /* custom 模式回到前台时主动预加载,避免冷启动延迟 */ + if (mode.value === 'custom') { + fg.preload() + } }) /** - * onHide 故意不 stop: - * - 切到后台/锁屏/小窗 都会触发 onHide - * - 配合 BackgroundAudioManager,音频会通过系统层继续播放 - * - 用户能从锁屏控制条主动暂停(通过 onPause 回调同步 UI) + * onHide:差异化处理 + * - preset 模式: 不停,BgAudio 接管后台播放 + * - custom 模式: 立即停掉,InnerAudio 后台不工作,留着会被 iOS 挂起后状态错乱 */ onHide(() => { - /* 不停止,让节拍声后台继续 */ + if (mode.value === 'custom') { + fg.stop() + uni.setKeepScreenOn({ keepScreenOn: false }) + } }) onUnmounted(() => { - /* 页面被销毁(navigateBack/重启)时才真正停止 - 否则锁屏控制条会一直挂着无主的"节拍器" */ - if (isPlaying.value) stop() + /* 页面销毁时全部清理 */ + if (mode.value === 'preset' && bg.isPlaying.value) bg.stop() + if (mode.value === 'custom') fg.stop() uni.setKeepScreenOn({ keepScreenOn: false }) }) @@ -209,6 +337,8 @@ $text-3: #94a3b8; $brand: #10b981; $brand-soft: #d1fae5; $brand-deep: #047857; +$warn: #f59e0b; +$warn-soft: #fef3c7; $radius-card: 24rpx; $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); @@ -217,16 +347,15 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); * ============================================================ */ .page { position: relative; - height: 100vh; + min-height: 100vh; box-sizing: border-box; - padding: 30rpx 28rpx 80rpx; + padding: 30rpx 28rpx 50rpx; background: $bg-color; display: flex; flex-direction: column; align-items: center; - gap: 22rpx; + gap: 20rpx; color: $text-1; - overflow: hidden; } /* ============================================================ @@ -236,7 +365,7 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); position: relative; width: 480rpx; height: 480rpx; - margin-top: 16rpx; + margin-top: 12rpx; display: flex; align-items: center; justify-content: center; @@ -359,7 +488,7 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); * ============================================================ */ .walker { width: 100%; - height: 260rpx; + height: 240rpx; display: flex; justify-content: center; align-items: center; @@ -367,8 +496,8 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); .walker-box { position: relative; - width: 260rpx; - height: 260rpx; + width: 240rpx; + height: 240rpx; background: #e8ecf2; border-radius: 24rpx; overflow: hidden; @@ -398,7 +527,7 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); .presets { width: 100%; display: flex; - gap: 16rpx; + gap: 14rpx; } .preset { @@ -406,33 +535,33 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); background: $card-bg; border: 2rpx solid $card-border; border-radius: $radius-card; - padding: 22rpx 12rpx 20rpx; + padding: 18rpx 8rpx 16rpx; display: flex; flex-direction: column; align-items: center; - gap: 6rpx; + gap: 4rpx; box-shadow: $shadow-sm; transition: all 0.18s; .preset-icon { - font-size: 44rpx; + font-size: 40rpx; line-height: 1; - margin-bottom: 6rpx; + margin-bottom: 4rpx; } .preset-name { - font-size: 30rpx; + font-size: 28rpx; font-weight: 700; color: $text-1; letter-spacing: 2rpx; } .preset-bpm { - font-size: 24rpx; + font-size: 22rpx; color: $text-2; font-weight: 600; font-variant-numeric: tabular-nums; } .preset-desc { - font-size: 20rpx; + font-size: 18rpx; color: $text-3; letter-spacing: 1rpx; margin-top: 2rpx; @@ -462,16 +591,145 @@ $shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04); } /* ============================================================ - * 底部提示 + * 自定义节奏面板(仅 customExpanded 时显示) * ============================================================ */ -.hint { - margin-top: 8rpx; - font-size: 22rpx; - color: $text-3; - letter-spacing: 1rpx; +.custom-panel { + width: 100%; + background: $card-bg; + border: 2rpx solid rgba(245, 158, 11, 0.25); + border-radius: $radius-card; + box-shadow: 0 6rpx 18rpx rgba(245, 158, 11, 0.08); + padding: 20rpx 24rpx 22rpx; + display: flex; + flex-direction: column; + gap: 16rpx; +} - text { - line-height: 1.6; +.custom-warn { + display: flex; + align-items: center; + gap: 8rpx; + margin-bottom: 4rpx; + + .warn-dot { + font-size: 18rpx; + color: $warn; + } + .warn-text { + font-size: 22rpx; + color: #b45309; + letter-spacing: 0.5rpx; + font-weight: 600; } } + +.row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12rpx; + + .row-label { + font-size: 24rpx; + color: $text-2; + font-weight: 600; + letter-spacing: 1rpx; + flex-shrink: 0; + width: 70rpx; + } +} + +.bpm-stepper { + display: flex; + align-items: center; + gap: 6rpx; + flex: 1; + justify-content: flex-end; + + .step-btn { + min-width: 56rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 22rpx; + color: $text-2; + background: #f1f5f9; + border-radius: 10rpx; + font-weight: 600; + padding: 0 10rpx; + font-variant-numeric: tabular-nums; + + &:active { + background: #e2e8f0; + transform: scale(0.94); + } + } + .step-val { + min-width: 84rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: 800; + color: $text-1; + font-variant-numeric: tabular-nums; + background: $warn-soft; + border-radius: 10rpx; + } +} + +.meter-tabs { + display: flex; + gap: 8rpx; + + .meter-tab { + height: 52rpx; + line-height: 52rpx; + padding: 0 18rpx; + font-size: 22rpx; + color: $text-2; + background: #f1f5f9; + border-radius: 10rpx; + font-weight: 600; + letter-spacing: 1rpx; + + &.active { + background: $warn; + color: #fff; + box-shadow: 0 4rpx 10rpx rgba(245, 158, 11, 0.3); + } + &:active { + transform: scale(0.94); + } + } +} + +/* ============================================================ + * 底部行(自定义入口 + 锁屏提示,横向排布) + * ============================================================ */ +.bottom-row { + width: 100%; + margin-top: 6rpx; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 6rpx; +} + +.bottom-link { + font-size: 22rpx; + color: $text-3; + letter-spacing: 0.5rpx; + padding: 8rpx 4rpx; + + &:active { + color: $text-2; + } +} + +.bottom-hint { + font-size: 22rpx; + color: $text-3; + letter-spacing: 0.5rpx; +} diff --git a/TUICallKit-Vue3/training/static/README.md b/TUICallKit-Vue3/training/static/README.md index 86616b8b..c6a22f21 100644 --- a/TUICallKit-Vue3/training/static/README.md +++ b/TUICallKit-Vue3/training/static/README.md @@ -6,26 +6,16 @@ ``` training/static/ -├── audio/ -│ └── click.mp3 # 节拍器主音(短促金属敲击声,约 50ms) -├── voice/ -│ ├── numbers/ -│ │ └── 1.mp3 ~ 30.mp3 # 数字报数 -│ └── prompts/ -│ ├── start.mp3 -│ ├── ready.mp3 -│ ├── rest.mp3 -│ ├── next-set.mp3 -│ ├── last-rep.mp3 -│ ├── keep-it-up.mp3 -│ ├── good-job.mp3 -│ ├── breathe-in.mp3 -│ └── breathe-out.mp3 -└── bgm/ - ├── train-light.mp3 # 训练时背景乐(轻快有节奏感) - └── rest-meditation.mp3 # 休息时背景乐(舒缓冥想) +├── audio/ # 当前为空 —— 节拍器音频已全部迁移到 COS CDN +├── voice/ # (规划中) TTS 语音教练 +│ ├── numbers/ 数字报数 1~30 +│ └── prompts/ 开始/休息/再来 等口令 +├── bgm/ # (规划中) 训练/休息背景乐 +└── footprint.svg # 脚印图标(早期方案残留,可保留作为备用素材) ``` +> 节拍器音频已完全走 CDN(`gz-1349751149.cos.ap-guangzhou.myqcloud.com`),减少小程序包体积约 210 KB。`useMetronomeBg.ts` / `useMetronome.ts` 中的 URL 即源信息,更换音色只需改 hook 里的常量。 + ## 准备步骤 ### 1. 语音素材(小米 MiMo TTS 自动生成) @@ -63,21 +53,22 @@ node scripts/generate-voice.mjs --force - `苏打`:年轻男声,有力量感 - `白桦`:成熟男声,沉稳 -### 2. 节拍器 click 音 +### 2. 节拍器 click / 循环音轨 -**已内置 3 种音色**(来自 [chrono-bump](https://github.com/johnnysn/chrono-bump) MIT 协议项目): +**全部托管在腾讯云 COS(2026-05-26 上传)**,本地不再保留: -| 文件 | 用途 | 大小 | -|------|------|------| -| `audio/click.mp3` | 默认 click(标准节拍器音) | 3.4 KB | -| `audio/click-soft.mp3` | 柔和音色 | 4.2 KB | -| `audio/click-wood.mp3` | 木鱼/原木质感(推荐用于重音 accent) | 4.6 KB | +| 用途 | 文件 | 大小 | 引擎 | +|---|---|---|---| +| 单拍 click(基础) | `click.mp3` | 3.4 KB | InnerAudio | +| 单拍 click(木鱼,推荐) | `click-wood.mp3` | 4.6 KB | InnerAudio (custom 模式) | +| 循环音轨 慢走 80 BPM | `loop_80bpm_2.mp3` | 71 KB | BgAudio (preset) | +| 循环音轨 健走 110 BPM | `loop_110bpm_2.mp3` | 65 KB | BgAudio (preset) | +| 循环音轨 快走 130 BPM | `loop_130bpm_2.mp3` | 66 KB | BgAudio (preset) | -如果想换更好听的,可以去: -- [freesound.org](https://freesound.org) 搜 "click" / "tick"(注意 CC 协议) -- [pixabay.com/sound-effects](https://pixabay.com/sound-effects/) 搜 "metronome"(免费可商用) +> 微信 `BackgroundAudioManager.src` 只接受 https URL,不支持包内资源,所以必须走 CDN。 +> COS 域名已加入小程序后台 `downloadFile 合法域名`,跑步视频也走同一域名。 -替换时保持文件名不变即可,无需改代码。 +更换音色:去 [pixabay.com/sound-effects](https://pixabay.com/sound-effects/) 找新素材 → 上传到 COS → 在 `useMetronomeBg.ts` / `useMetronome.ts` 里替换 URL 即可。 ### 3. 背景音乐 @@ -92,9 +83,11 @@ node scripts/generate-voice.mjs --force ## 在代码里被引用的位置 -- `training/hooks/useMetronome.ts` → `audio/click.mp3` -- `training/hooks/useVoiceCoach.ts` → `voice/numbers/*.mp3`、`voice/prompts/*.mp3` -- `training/hooks/useTrainingBgm.ts` → `bgm/*.mp3` +- `training/hooks/useMetronome.ts` → `DEFAULT_CLICK_SRC` (CDN: click.mp3) +- `training/hooks/useMetronomeBg.ts` → `LOOP_PRESETS[*].src` (CDN: loop_*.mp3) +- `training/pages/metronome.vue` → `CLICK_WOOD_URL` (CDN: click-wood.mp3, custom 模式) +- `training/hooks/useVoiceCoach.ts` → `voice/numbers/*.mp3`、`voice/prompts/*.mp3` (规划中) +- `training/hooks/useTrainingBgm.ts` → `bgm/*.mp3` (规划中) 如需修改路径,修改对应 hook 文件里的常量即可。 diff --git a/TUICallKit-Vue3/training/static/audio/click-wood.mp3 b/TUICallKit-Vue3/training/static/audio/click-wood.mp3 deleted file mode 100644 index fb3fff34..00000000 Binary files a/TUICallKit-Vue3/training/static/audio/click-wood.mp3 and /dev/null differ diff --git a/TUICallKit-Vue3/training/static/audio/click.mp3 b/TUICallKit-Vue3/training/static/audio/click.mp3 deleted file mode 100644 index faa1693a..00000000 Binary files a/TUICallKit-Vue3/training/static/audio/click.mp3 and /dev/null differ diff --git a/TUICallKit-Vue3/training/static/audio/cover.jpg b/TUICallKit-Vue3/training/static/audio/cover.jpg deleted file mode 100644 index a46eec92..00000000 Binary files a/TUICallKit-Vue3/training/static/audio/cover.jpg and /dev/null differ diff --git a/TUICallKit-Vue3/training/static/audio/loop_110bpm_2.mp3 b/TUICallKit-Vue3/training/static/audio/loop_110bpm_2.mp3 deleted file mode 100644 index 765bcb0c..00000000 Binary files a/TUICallKit-Vue3/training/static/audio/loop_110bpm_2.mp3 and /dev/null differ diff --git a/TUICallKit-Vue3/training/static/audio/loop_130bpm_2.mp3 b/TUICallKit-Vue3/training/static/audio/loop_130bpm_2.mp3 deleted file mode 100644 index 26b0d9a6..00000000 Binary files a/TUICallKit-Vue3/training/static/audio/loop_130bpm_2.mp3 and /dev/null differ diff --git a/TUICallKit-Vue3/training/static/audio/loop_80bpm_2.mp3 b/TUICallKit-Vue3/training/static/audio/loop_80bpm_2.mp3 deleted file mode 100644 index bd2e513a..00000000 Binary files a/TUICallKit-Vue3/training/static/audio/loop_80bpm_2.mp3 and /dev/null differ diff --git a/server/config/project.php b/server/config/project.php index d082a4db..6012fd4d 100755 --- a/server/config/project.php +++ b/server/config/project.php @@ -80,7 +80,8 @@ return [ //上传文件的格式 (文件) 'file_file' => [ - 'zip','rar','txt','pdf','doc','docx','xls','xlsx','ppt','pptx','csv','txt','ftr','7z','gz' + 'zip','rar','txt','pdf','doc','docx','xls','xlsx','ppt','pptx','csv','txt','ftr','7z','gz', + 'mp3', 'wav', 'm4a', 'aac', 'amr', 'wma', // 音频 ], // 登录设置