feat: 拆分邮件通知选项,根据会员权益显示

- 翻译完成邮件通知(所有用户)
- 鮮件带附件发送(VIP专属,free用户显示需VIP)
- 会员到期提醒(仅VIP用户显示)
- 添加 notify_with_attachment 字段
- 更新各等级权益:email_notify/email_attachment
This commit is contained in:
2026-04-15 01:10:59 +08:00
parent 56709b1a65
commit 9a36b9245a
4 changed files with 53 additions and 8 deletions

17
app.py
View File

@@ -223,6 +223,8 @@ def pricing():
'priority_queue': '优先处理队列',
'custom_instruction': '自定义翻译要求',
'api_access': 'API接口调用',
'email_notify': '邮件通知',
'email_attachment': '邮件附件发送',
}
# 从数据库读取动态配置的会员套餐
@@ -289,10 +291,15 @@ def profile():
daily_remaining = limits['daily_translations'] - user.daily_count if limits['daily_translations'] > 0 else '无限'
max_pages = limits['max_pages'] if limits['max_pages'] > 0 else '无限'
# 检查是否有邮件附件权限
user_features = limits.get('features', [])
has_email_attachment = 'email_attachment' in user_features or user_features == ['all']
return render_template('profile.html',
user=user,
daily_remaining=daily_remaining,
max_pages=max_pages
max_pages=max_pages,
has_email_attachment=has_email_attachment
)
@@ -876,6 +883,14 @@ def update_settings():
user.notify_on_complete = data.get('notify_on_complete', True)
if 'notify_on_expire' in data:
user.notify_on_expire = data.get('notify_on_expire', True)
if 'notify_with_attachment' in data:
# 检查是否有附件权限
limits = USER_LIMITS.get(user.user_type, USER_LIMITS['free'])
user_features = limits.get('features', [])
if 'email_attachment' in user_features or user_features == ['all']:
user.notify_with_attachment = data.get('notify_with_attachment', False)
else:
return jsonify({'error': '邮件附件功能需VIP会员', 'feature': 'email_attachment'}), 403
if 'email_notify' in data:
user.email_notify = data.get('email_notify', True)

View File

@@ -39,19 +39,19 @@ USER_LIMITS = {
"daily_translations": 10,
"max_pages": 50,
"max_file_size": 30 * 1024 * 1024, # 30MB
"features": ["basic_translate", "retranslate", "export_pdf", "history"],
"features": ["basic_translate", "retranslate", "export_pdf", "history", "email_notify"],
},
"vip_basic": { # 基础会员 (月付 ¥29)
"daily_translations": 50,
"max_pages": 100,
"max_file_size": 50 * 1024 * 1024,
"features": ["basic_translate", "compare_view", "retranslate", "history", "priority_queue", "export_pdf"],
"features": ["basic_translate", "compare_view", "retranslate", "history", "priority_queue", "export_pdf", "email_notify", "email_attachment"],
},
"vip_pro": { # 专业会员 (月付 ¥99)
"daily_translations": 200,
"max_pages": 500,
"max_file_size": 100 * 1024 * 1024,
"features": ["basic_translate", "compare_view", "retranslate", "history", "priority_queue", "export_pdf", "batch_translate", "custom_terms"],
"features": ["basic_translate", "compare_view", "retranslate", "history", "priority_queue", "export_pdf", "batch_translate", "custom_terms", "email_notify", "email_attachment"],
},
"vip_enterprise": { # 企业会员 (年付 ¥999)
"daily_translations": -1, # 无限制

View File

@@ -54,6 +54,7 @@ class User(db.Model):
# 邮件通知设置
email_notify = db.Column(db.Boolean, default=True) # 邮件通知开关
notify_on_complete = db.Column(db.Boolean, default=True) # 翻译完成通知
notify_with_attachment = db.Column(db.Boolean, default=False) # 邮件带附件VIP功能
notify_on_expire = db.Column(db.Boolean, default=True) # 会员到期提醒
# 关系
@@ -132,6 +133,7 @@ class User(db.Model):
'invite_rewards': self.invite_rewards,
'email_notify': self.email_notify,
'notify_on_complete': self.notify_on_complete,
'notify_with_attachment': self.notify_with_attachment,
'notify_on_expire': self.notify_on_expire,
'daily_count': self.daily_count,
'total_count': self.total_count,

View File

@@ -198,18 +198,40 @@
<hr class="my-2">
<!-- 翻译完成邮件通知(所有用户都有) -->
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="notifyComplete"
{% if user.notify_on_complete %}checked{% endif %}
onchange="updateNotifySettings()">
<label class="form-check-label">翻译完成通知(含附件)</label>
<label class="form-check-label">翻译完成邮件通知</label>
</div>
<!-- 邮件带附件VIP功能 -->
{% if has_email_attachment %}
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="notifyAttachment"
{% if user.notify_with_attachment %}checked{% endif %}
onchange="updateNotifySettings()">
<label class="form-check-label">邮件带附件发送 <span class="badge bg-success">VIP</span></label>
</div>
{% else %}
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" disabled>
<label class="form-check-label text-muted">邮件带附件发送 <span class="badge bg-secondary">需VIP</span></label>
<a href="/pricing" class="small ms-2">升级会员</a>
</div>
{% endif %}
<!-- 会员到期提醒 -->
{% if user.user_type.startswith('vip') %}
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="notifyExpire"
{% if user.notify_on_expire %}checked{% endif %}
onchange="updateNotifySettings()">
<label class="form-check-label">会员到期提醒</label>
</div>
{% endif %}
<small class="text-muted">通知将发送至上述邮箱</small>
</div>
</div>
@@ -524,21 +546,27 @@
// 更新通知设置
function updateNotifySettings() {
const notifyComplete = document.getElementById('notifyComplete').checked;
const notifyExpire = document.getElementById('notifyExpire').checked;
const notifyExpire = document.getElementById('notifyExpire')?.checked || false;
const notifyAttachment = document.getElementById('notifyAttachment')?.checked || false;
fetch('/api/profile/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
notify_on_complete: notifyComplete,
notify_on_expire: notifyExpire
notify_on_expire: notifyExpire,
notify_with_attachment: notifyAttachment
})
})
.then(r => r.json())
.then(data => {
if (data.success) {
// 不刷新页面,只显示提示
console.log('设置已更新');
} else if (data.feature === 'email_attachment') {
alert('邮件附件功能需要VIP会员');
location.href = '/pricing';
} else {
alert('更新失败:' + data.error);
}
});
}