yuzhiran
4e4e1ca271
ux: 无有效语音时友好提示
...
onStop 时:
- 识别文字 >=2 字: 自动发送 (正常流程)
- 识别文字 =1 字: toast '语音过短,请重试'
- 无识别文字: toast '未检测到语音,请重试'
2026-07-05 20:32:29 +08:00
yuzhiran
50bb3c45ed
ux: 录音改为点击开始/点击结束
...
- 移除长按交互 (touchstart/touchend/mousedown/mouseup)
- 改为单击 toggle: 点击🎤 开始录音, 再点击结束录音
- 按钮默认只显示🎤 , 录音中显示🔴 +秒数
- 下方提示改为'点击结束'
- 录音开始时清空 inputText
- 移除 suppressAutoSend 标志 (点击结束都是有意操作)
2026-07-05 19:41:21 +08:00
yuzhiran
db1b3baa60
fix: 录音UX + 发送按钮录音中禁用
...
- 发送按钮录音中禁用 (disabled: isRecording)
- sendAnswer() 加 isRecording 守卫
- 麦克风按钮录音时下方显示'松开结束'提示
- 默认标签改为'按住'
2026-07-05 19:19:16 +08:00
yuzhiran
df7d51d888
refactor: 录音换成微信同声传译插件
...
替换整个录音+ASR流程:
- 移除 uni.getRecorderManager() + 后端上传 ASR 方案
- 接入 WechatSI 插件 getRecordRecognitionManager()
- start() 一次性完成录音+实时流式识别
- onRecognize 实时回填 inputText (用户可见)
- onStop 自动调用 sendAnswer(),无需手动点击发送
- 移除 asrLoading/skipAsr/recorderStarted/pendingStop 状态
效果: 8步→3步, 延时2-10s→~500ms, 不再有录音格式兼容问题
注意: 需在 mp.weixin.qq.com 后台添加同声传译插件(插件ID: wx069ba97219f66d99)
2026-07-05 18:44:54 +08:00
yuzhiran
462884a321
fix: recorderStart 异步竞争条件
...
微信 RecorderManager.start() 是异步的,onStart 回调触发前
调用 stop() 会报 'operateRecorder:fail recorder not start'。
- 增加 recorderStarted 标志,onStart 时置 true
- 增加 pendingStop 标志,stop() 在 start 前被调用时延迟执行
- onError 时全面清理 pendingStop/recorderStarted/skipAsr 状态
2026-07-05 18:06:17 +08:00
yuzhiran
48354e634b
fix: 录音可靠性修复 + ASR 后端优化
...
前端:
- recorder.onError 时重置 recorder = null,避免错误后录音永久失效
- 增加 asrLoading 状态,ASR 处理中输入框 disabled 并显示'语音识别中...'
- 增加 skipAsr 标志,<1s 的录音跳过 ASR 上传
- uploadFile 增加 30s timeout
后端:
- ASR: OpenAI 失败后 fallback 到本地 whisper,日志级别降为 warn
- try/catch/finally 重构,确保临时文件在所有路径都清理
- OpenAI 和 whisper 结果分别 try,互不影响
2026-07-05 17:45:03 +08:00
yuzhiran
8152278b86
fix: 录音格式改回 aac + 对话 UX 优化
...
录音:
- 从 mp3/16kHz/48kbps 改回原始工作配置 aac/22050Hz/16kbps
(mp3 和 48kbps 在部分微信版本兼容不佳)
- 增加 recordingDuration ref 显示录音秒数
- onError 增加 JSON.stringify 打印详细错误原因
- 增加权限被拒的判断提示
UX 优化:
- 每条消息增加角色头像 (🤖 AI / 👤 用户)
- 增加 msg-body 容器 + msg-label 角色标签 (面试官/我)
- 对话布局改为左侧头像+气泡+名称,右侧用户头像+气泡
- msg-body max-width:70% 限制气泡宽度
- 麦克风按钮放大(80rpx),增加文字标签「按住」/「Ns」
- 录音时禁用输入框(isRecording 时 textarea disabled)
2026-07-05 17:00:29 +08:00
yuzhiran
b38b38d0c8
fix: 录音 - 移除 uni.authorize + 修复 encodeBitRate 越界
...
录音按住松手无效根因有两处:
1. encodeBitRate:128000 对 sampleRate:16000 越界(微信规定16000Hz
下 encodeBitRate 必须在 24000~96000 之间),导致 recorder.start()
立即触发 onError,修改为 encodeBitRate:48000
2. uni.authorize 异步回调延迟 recorder.start(),用户松手时
stopRecord 已执行但 recorder 尚未开始录,且之前的 recordingStarted
守卫跳过 stopRecord 后 authorize 回调又启动录音无法停止。
解决方案: 直接调 recorder.start(),不再前置 uni.authorize。
微信会在需要时自动弹录音权限窗。
format 从 wav 改为 mp3(mp3 在微信各平台兼容性更好),
后端 ffmpeg 会自动转码为 wav 后再送 whisper。
2026-07-05 14:14:45 +08:00
yuzhiran
07b81f57a6
fix: 面试创建时机 + 录音开始状态守卫
...
问题1(录音失败): recorder.start() 在 uni.authorize 异步回调里调用,
用户松手触发 stopRecord 时录音还没实际开始,调 recorder.stop() 报错。
修复: 增加 recordingStarted 标记,onsStart 回调设为 true,stopRecord
检查该标记,若录音未开始直接跳过。
问题2(开始被当答案):
- onMounted 不再自动调用 startInterview() 创建面试,等待用户首次发送
- greeting 文案改为准备好后发送任意消息,我会立即开始面试并给出第一个问题
- sendAnswer 首次发送: 用户消息仅显示在本地对话中,调用 startInterview()
创建面试并追加第一个问题,不提交答案到 /interview/{id}/answer
- startInterview 不再替换 messages,改为 push AI 消息追加到现有对话
- selectPosition 同理,不再立即 startInterview,等用户发消息
2026-07-05 13:38:20 +08:00
yuzhiran
1422c04b2c
fix: sendAnswer await startInterview + stopRecord guard
...
- sendAnswer: await startInterview() 后再发答案,避免面试还没创建
就把用户输入 '你好' 当成答案提交给空 interviewId
- stopRecord: 加 !isRecording.value 守卫,防止 user touchend 在
uni.authorize success 回调之前触发 recorder.stop() 导致报错
2026-07-05 13:04:40 +08:00
yuzhiran
656dfabb29
fix: interview 录音改为长按按住录音松开提交
...
startRecord 先同步设 isRecording=true 再异步 uni.authorize,避免
touchend 在 authorize success 回调前就触发 stopRecord 导致录音没
来得及开始就被停止。
移除冗余 doStartRecorder 函数,inline 到 authorize success 回调中。
stopRecord 不再检查 isRecording 守卫(可能已被 startRecord 设为 true),
直接 recorder.stop()。
2026-07-05 09:32:36 +08:00
yuzhiran
fe688096a4
fix: interview 页面 22x ReferenceError + 引力值明细追加余额栏
...
interview.vue: 上次会话修改时丢失了 timerSeconds/timerInterval 两个 let 声明
(它们在 git 历史里 d8a7872 时本和 onMounted 同段定义),导致页面渲染时
20+ 次 'ReferenceError: timerSeconds is not defined' 刷屏、对话框/计时器
被白屏错误覆盖。补回两行声明即可还原,无其它改动。
user.vue: 引力值明细每行除金额外追加变动后「余额 N」尾列(schema 中 balance
字段已记录,仅前端未展示)。.detail-item-right 容器纵向堆叠金额+小字余额。
2026-07-05 08:59:02 +08:00
yuzhiran
31703af4f2
fix: mp-weixin 录音失败 - 权限声明+authorize+移除TS注解+空音频守卫
...
- interview.vue: 移除 `let recorder: any` TS 类型注解(小程序构建器不解析 TS,上次修改直接破坏构建从未部署)
- interview.vue: 合并两个 onMounted 调用,删除凭空引入的 refreshState() 未定义函数引用
- interview.vue: startRecord 增加 uni.authorize scope.record 权限预请求,拒绝时引导 openSetting
- interview.vue: recorder.start 改 wav/16kHz/128kbps(旧 aac/22050/16kbps 产生全 0 损坏文件)
- manifest.json: mp-weixin.permission 增加 scope.record 录音权限声明
- tts.controller.ts: ASR 拒绝 <500B 空音频文件,避免 whisper 调 ffmpeg 解码失败刷错日志
2026-07-05 01:57:24 +08:00
yuzhiran
a9c6b03c67
fix: ASR audio format conversion + share.vue deduplicate share creation
...
- TTS /tts/asr: convert non-WAV (AAC/MP3) to WAV before whisper transcription
- share.vue: only create share record if no cached shareCode exists
(prevents duplicate share records on every page load)
2026-07-04 13:13:32 +08:00
yuzhiran
2230a95b45
feat: gravity transaction logging + user-facing history popup
...
- New GravityTransaction schema tracks all gravity changes (registration,
interview/optimize/download deduction, purchase, monthly topup, migration)
- GravityTopUpService: bulk log for monthly VIP topup
- PaymentController.activateMembership: log plan_set transactions
- QuotaService: add logTransaction, wire into all gravity-modifying methods
- UserService: log registration grants (phone/wx/email/password)
- GET /user/gravity-transactions?page=&limit= API
- Frontend: user.vue '明细' button + paginated popup
- Docs: update PROJECT-STATUS v4.10, FEATURE-LIST, DEPLOYMENT
2026-07-04 11:12:55 +08:00
yuzhiran
d8a7872cd2
fix: interview create returns HTTP 201, frontend only accepted 200
...
NestJS POST 默认返回 201 Created,前端 startInterview() 和
sendAnswer() 只判断 statusCode === 200 导致成功创建也落入
else 分支显示创建面试失败。改为 >= 200 && < 300。
2026-07-03 15:52:35 +08:00
yuzhiran
59fc35dad9
fix: interview creation show real error msg instead of generic failure
...
- Backend: wrap AI call in try/catch, throw HttpException(503)
with msg 'AI 服务暂时不可用,请稍后重试'
- Backend: AllExceptionsFilter preserve original error message
for non-HttpException errors
- Frontend: handle string/object res.data, show statusCode
as fallback when message is unavailable
2026-07-03 15:32:22 +08:00
yuzhiran
bd398f154a
fix: 微信虚拟支付错误消息改为用户友好中文提示
...
- 新增 friendlyVpError() 工具函数,映射 VP 常见错误码
(pay cancel, access denied, SIGNATURE_INVALID 等) 为友好中文
- member.vue 两个 VP fail 回调使用 friendlyVpError 显示
原始: requestVirtualPayment:fail pay cancel
优化: 你已取消支付
2026-07-02 13:12:55 +08:00
yuzhiran
f955ecc71d
fix: token 过期时前端自动清除登录态并跳转登录
...
根因: 页面使用 uni.request() 直接请求,401 时只有静默 catch,
不清除本地 token,导致界面显示已登录但后端拒接。
修复:
- 新增 utils/auth.ts: clearAuth() + checkAuth() 统一处理 401
- member.vue: refreshState / startGravityPay / startPlanPay /
pollPayResult / activatePlan 全部添加 401 检测
- user.vue: fetchUserInfo / loadMemberStatus / loadStats /
preCreateShare 添加 401 检测
- interview.vue: startInterview / sendAnswer / speakAiText /
startRecord 添加 401 检测
2026-07-02 12:52:43 +08:00
yuzhiran
b8aaa51eb1
fix: voice input recording format + ASR logging
...
- Change recorder format from mp3 (8kHz) to aac (22kHz) for better
whisper ASR accuracy
- Move recorder.onStop binding before recorder.stop() to prevent
race condition (onStop may fire before handler is registered)
- Backend: add Logger, log ASR errors instead of silent catch {}
- Backend: change default extension from .mp3 to .aac
2026-06-25 08:49:55 +08:00
yuzhiran
2fddd39301
feat: registration gravity from DB config instead of hardcoded
...
- Add registrationGravity to pricing config (default 50, adjustable via admin)
- Inject PricingService into UserService, read config for all 4 registration paths
- Expose registrationGravity in /member/plans response for frontend
- Login page fetches dynamic value from API, replaces hardcoded '50'
- Update user.vue gravity card copy
2026-06-25 08:12:01 +08:00
yuzhiran
52e5350ba0
补充 VP 模块注册 + 前端 API 封装
...
- app.module.ts: 注册 VirtualPaymentModule
- config.ts + api.ts: 添加虚拟支付 API 端点
- useGravityPurchase.ts: VP 购买逻辑
- interview.vue / user.vue: 适配 VP 调用
- admin.controller.ts: 管理端虚拟支付相关调整
- payment.controller.spec.ts: 测试适配
2026-06-24 10:35:25 +08:00
yuzhiran
81f86d995d
v1.0.18: 小程序虚拟支付上线 + 定价调整为整数
...
- 新增虚拟支付 (short_series_coin 代币模式,1:1 兑换)
- 后端 修复为正确 VP 格式,返回 mode 参数
- 前端 VP 调用补齐 、 格式调整
- 套餐价格调整:成长版 ¥19.9 → ¥19,冲刺版 ¥49.9 → ¥49
- 数据库定价同步更新为 1900/4900(分)
- 会员页未登录时也拉取 ,套餐对比数据由服务端返回
- 文档统一更新定价和 VP 说明
- 修正 AGENTS.md 引力值数据(250/600 → 80/200)
2026-06-22 20:29:51 +08:00
yuzhiran
1a45822a58
fix(mp): handle mini-program launch params and pre-create share code for user page
...
App.vue: add handleLaunchParams() to read token/shareCode from onLaunch/onShow query in MP-WEIXIN context. user.vue: pre-create share record on page load, use dynamic path with shareCode in onShareAppMessage.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-22 14:23:27 +08:00
yuzhiran
d74fc74f28
feat(admin): convert all timestamps to Beijing time (UTC+8) for display
...
Create utils/format.ts with toBeijing() helper. Replace 13 raw .slice().replace() date displays in admin.vue with centralized timezone-aware formatting.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-22 12:51:58 +08:00
yuzhiran
b6323f02eb
feat(admin): show last login time/IP/location in user list
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-22 12:38:26 +08:00
yuzhiran
70c4f28eb5
fix(admin): add wxOpenid to fuzzy search, enhance admin tab info
...
- Backend getUsers: add wxOpenid to regex search
- Backend getAdmins: return gravity, plan, wxOpenid, email fields
- Frontend admin tab: show full user info (ID copy, email, gravity, plan)
- Frontend search result: show complete user details like user list rows
2026-06-22 12:07:52 +08:00
yuzhiran
d37bbd7a61
feat(admin): fuzzy search by email/ID, display full userId in user list
...
- Backend: add email + _id to filter in getUsers() for fuzzy search
- Frontend: show full MongoDB _id in user row with tap-to-copy
- Search placeholder updated to mention email/ID
2026-06-22 11:46:14 +08:00
yuzhiran
d8fb8e3bba
feat: enable WeChat share/forward on all pages via onShareAppMessage + onShareTimeline
2026-06-21 18:51:35 +08:00
yuzhiran
214571688c
feat: SEO optimization - canonical URL, robots.txt, sitemap, structured data, keyword-rich titles, manifest update
2026-06-21 09:48:41 +08:00
yuzhiran
8532776fa1
refactor: remove duplicate contact button in about page
2026-06-21 09:38:24 +08:00
yuzhiran
b8667395ac
feat: unify contact button styles, dynamic version from git tag, enrich AI positions & homepage UX
2026-06-21 09:16:31 +08:00
yuzhiran
1d1c4ab590
fix: bump patch version automatically on mp upload (v1.0.16 → 1.0.17)
2026-06-21 09:03:34 +08:00
yuzhiran
310176a11b
chore: production cleanup - remove debug logs, add DB cleanup script
...
- App.vue: remove console.log on launch/show/hide, drop unused onShow/onHide imports
- interview.vue: remove verbose console.log('[ASR] upload response')
- login.vue: remove debug console.log('[wxLogin]') logs (keep error logs)
- scripts/cleanup-test-data.ts: new script to identify and remove test data
while preserving admin accounts; supports --dry-run preview mode
- All 43 backend tests pass
2026-06-20 23:08:44 +08:00
yuzhiran
ef4d22a633
feat(admin): enrich admin panel fields; add user index constraint and customer service
...
- admin controller: add updatedAt to interview/resume selects; add orderCount,
todayOrders, totalRevenue to overview
- admin.vue: enrich all tabs with more fields
- overview: order cards (count, revenue)
- users: wxOpenid, email, createdAt, interviewCount, vipExpireAt, role badge
- interviews: user email, updatedAt, summary preview
- orders: title, type, channel, paidAt, wxTransactionId, refund info
- resumes: user email, updatedAt
- share: sharer phone, shareCode, isActive, visitorId(IP), creditedAt
- admins: email, createdAt
- user.schema: add unique indexes on phone/wxOpenid/email; pre-save hook
requiring at least one contact method
- user/about: add WeChat contact button (open-type=contact) for customer service
2026-06-20 22:38:33 +08:00
yuzhiran
8ee27fdd32
feat: refactor member to pay-per-use gravity purchase; mv webview to clipboard+browser
...
- member.vue: rewrite from subscription plans (free/growth/sprint) to
H5-only pay-per-use gravity purchase with quantity selector + QR code
- user.vue: gravity card replacing quota card, add share/contribute/H5-buy
entry points, plus gravity acquisition modal (share/contribute/buy)
- share.vue: layout fix (flex column), smarter copyLink with cached URL,
WeChat timeline hint instead of open-type
- share.controller.ts: add GET /:shareCode redirect route (IP record + 302)
- interview.vue: guest mode fix, H5 buy modal, clipboard copy instead of
webview for mini-program
- App.vue: handleH5UrlParams for ?token=&buy=gravity auto-login
- composables/useGravityPurchase.ts: reusable gravity purchase composable
- remove webview.vue (no longer used), replace with clipboard+browser flow
- AGENTS.md: sync all above changes, fix duplicate numbering
2026-06-20 20:49:15 +08:00
yuzhiran
2fbab1072f
feat: unified gravity system - VIP members consume gravity instead of unlimited; add monthly gravity top-up cron
2026-06-19 22:43:52 +08:00
yuzhiran
c2ba810a02
fix: use onShow lifecycle to refresh login state in member center
...
1. member.vue: added onShow to refresh login state when returning from login page
2. manifest.json: bump to v1.0.15
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 21:23:20 +08:00
yuzhiran
3f1239c35e
fix: add network error detection and timeout for mini program JSAPI payment
...
1. member.vue: check for res.statusCode === 0 (network failure) before accessing data, add 30s timeout
2. manifest.json: bump to v1.0.14
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 20:54:42 +08:00
yuzhiran
1be5b34906
chore: bump version to 1.0.13
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 20:39:56 +08:00
yuzhiran
c58bb27575
fix: admin page reactive import + member payment toast show real error
...
1. admin.vue: 添加缺失的reactive导入,修复管理后台只显示标题不显示功能的问题
2. member.vue: 支付失败toast改为显示后端真实错误信息,而非硬编码'创建订单失败'
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 20:39:49 +08:00
yuzhiran
c161ffbc3c
feat: payment refund support + admin payment management
...
- Add refund()/queryRefund()/downloadPlatformCerts() to WechatPayService
- Add refundId field to PaymentOrder schema
- Fix WeChat Pay callback to auto-download platform certs on verification failure
- Fix syncOrder to handle sprint plan properly
- Add admin refund, refund-query, order-detail endpoints
- Add refund UI (button, modal, query) to admin.vue orders tab
- Fix member.vue MP payment: pass outTradeNo instead of prepayId to pollPayResult
2026-06-18 19:33:10 +08:00
yuzhiran
7e1bf669ab
fix: show toast when clicking login without agreeing to privacy terms
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 18:54:44 +08:00
yuzhiran
bed9dce943
chore: bump version to 1.0.12
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 18:48:27 +08:00
yuzhiran
4ac42f6575
fix: privacy policy compliance - checkbox must be manually checked, add WeChat privacy API
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 18:46:57 +08:00
yuzhiran
7cf4636b8c
fix: auto-verify admin on mount (onMounted doVerify)
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 18:21:41 +08:00
yuzhiran
27e4d06da7
fix: show devCode modal in email login for non-production mode
...
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent )
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai >
2026-06-18 18:21:34 +08:00
yuzhiran
e049be280e
fix: auto-copy avatars on build, show masked user ID on profile page
2026-06-18 17:58:54 +08:00
yuzhiran
b9651a9ff3
chore: hide company-bank and internship entries from homepage (content empty)
2026-06-18 17:44:11 +08:00
yuzhiran
54c21e2953
refactor: rewrite company-bank and internship pages
...
- bank.vue: Composition API, design tokens, 2-col grid, better UX
- internship.vue: search bar, category tabs, card list layout
2026-06-18 17:27:37 +08:00