v4.2 冲刺版+每日推送+支付修复+全量代码评审

## 新增功能
- 冲刺版 ¥49.9/月:完整支付→激活→权益扣减链路
- 每日一题定时推送(@nestjs/schedule,早8点微信订阅消息)
- miniprogram-ci 编译上传脚本(scripts/upload-mp.js)

## Bug修复
- 套餐值统一:vip→growth/sprint(interview轮次限制、analyze次数检查)
- member/pay 移除开发绕过:改为订单校验后激活
- progress→report 参数名不匹配:id→interviewId
- result.vue resume.create() 参数传错(对象→独立参数)
- resume.vue analyze请求缺少Authorization header
- bank.vue contribution请求缺少Authorization header
- member.vue startPay() 缺少try/catch导致网络错误崩溃
- login.vue 调试面板 v-if="true" 生产泄漏

## 配置
- 微信支付生产证书就位(商户号1113760598)
- .env 清理冗余文件(删除.example/.production)
- WX_NOTIFY_URL 更新为 zhiyinwx.yzrcloud.cn

## 文档
- PROJECT-STATUS.md v4.1→v4.2,状态全面更新
- DEPLOYMENT.md 新增小程序编译上传章节、清理检查清单
This commit is contained in:
yuzhiran
2026-06-09 20:03:05 +08:00
parent 37cfdfe93c
commit 9276ab9028
44 changed files with 15205 additions and 2062 deletions
+72
View File
@@ -0,0 +1,72 @@
/**
* 面试回答中的语气词/填充词分析
* 检测用户回答中的语气词密度、语速估算等
*/
const CHINESE_FILLER_WORDS = [
'嗯', '啊', '呃', '哦', '那个', '这个', '然后', '就是',
'对吧', '所以说', '反正', '其实', '就是说', '那', '那么',
'还有一个', '另外', '基本上', '大概', '可能', '应该',
'的话', '的时候', '一种', '一个', '一种', '可以说',
]
const ENGLISH_FILLER_WORDS = [
'um', 'uh', 'er', 'ah', 'like', 'you know', 'actually',
'basically', 'literally', 'honestly', 'sort of', 'kind of',
'i mean', 'you see', 'well', 'so', 'anyway',
]
function countOccurrences(text: string, words: string[]): { word: string; count: number }[] {
const result: { word: string; count: number }[] = []
const lowerText = text.toLowerCase()
for (const word of words) {
const escaped = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const regex = new RegExp(escaped, 'g')
const matches = lowerText.match(regex)
if (matches && matches.length > 0) {
result.push({ word, count: matches.length })
}
}
return result.sort((a, b) => b.count - a.count)
}
export function analyzeSpeech(text: string) {
const totalChars = text.length
const totalWords = text.split(/\s+/).filter(Boolean).length
const chineseFillers = countOccurrences(text, CHINESE_FILLER_WORDS)
const englishFillers = countOccurrences(text, ENGLISH_FILLER_WORDS)
const allFillers = [...chineseFillers, ...englishFillers]
const totalFillerCount = allFillers.reduce((s, f) => s + f.count, 0)
// 估算语速(中文字符/秒,假设正常说话速度 ~3-4 字/秒)
const estimatedDurationSec = Math.max(totalChars / 3.5, 10)
const speechRate = totalChars / estimatedDurationSec
// 语气词密度
const fillerDensity = totalChars > 0 ? totalFillerCount / totalChars : 0
// 评分:语气词越少越好
let fillerScore = 100
if (fillerDensity > 0.15) fillerScore = 40
else if (fillerDensity > 0.10) fillerScore = 60
else if (fillerDensity > 0.05) fillerScore = 80
// 判断是否过长/过短
let lengthFeedback = ''
if (totalChars < 20) lengthFeedback = '回答过短,建议展开阐述'
else if (totalChars > 500) lengthFeedback = '回答偏长,建议精简重点'
return {
totalChars,
totalWords,
fillerCount: totalFillerCount,
fillerWords: allFillers.slice(0, 5),
fillerDensity: Math.round(fillerDensity * 1000) / 10,
fillerScore,
estimatedDurationSec: Math.round(estimatedDurationSec),
speechRate: Math.round(speechRate * 10) / 10,
lengthFeedback,
topFiller: allFillers[0]?.word || null,
}
}