Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bcdf903945 |
112
dingtalk.py
112
dingtalk.py
@@ -5,6 +5,11 @@ from flask import Blueprint, render_template, jsonify, current_app, request
|
|||||||
|
|
||||||
dingtalk_bp = Blueprint('dingtalk', __name__)
|
dingtalk_bp = Blueprint('dingtalk', __name__)
|
||||||
|
|
||||||
|
# 延迟导入避免循环引用
|
||||||
|
def get_user_model():
|
||||||
|
from models import User
|
||||||
|
return User
|
||||||
|
|
||||||
def get_dingtalk_config():
|
def get_dingtalk_config():
|
||||||
print('[后端] [1] ============== get_dingtalk_config 开始 ==============')
|
print('[后端] [1] ============== get_dingtalk_config 开始 ==============')
|
||||||
app_key = current_app.config.get('DINGTALK_APP_KEY', '')
|
app_key = current_app.config.get('DINGTALK_APP_KEY', '')
|
||||||
@@ -166,6 +171,113 @@ def get_dept_name(dept_id):
|
|||||||
print(f'[后端] [5] 异常:', e)
|
print(f'[后端] [5] 异常:', e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def send_dingtalk_card_to_user(user_id, title, content, jump_url):
|
||||||
|
"""发送钉钉消息卡片给指定用户"""
|
||||||
|
print(f'[后端] [N] ============== send_dingtalk_card_to_user 开始, user_id={user_id} ==============')
|
||||||
|
access_token = get_access_token()
|
||||||
|
if not access_token:
|
||||||
|
print('[后端] [N] 获取 access_token 失败')
|
||||||
|
return False
|
||||||
|
|
||||||
|
url = f'https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token={access_token}'
|
||||||
|
headers = {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
|
agent_id = current_app.config.get('DINGTALK_AGENT_ID', '')
|
||||||
|
data = {
|
||||||
|
'agent_id': int(agent_id) if agent_id else 0,
|
||||||
|
'userid_list': user_id,
|
||||||
|
'msg': {
|
||||||
|
'msgtype': 'link',
|
||||||
|
'link': {
|
||||||
|
'title': title,
|
||||||
|
'text': content,
|
||||||
|
'picUrl': 'https://img.alicdn.com/tfs/TB1NwmBkeL2gK0jSZPhXXahviXa-72-72.png',
|
||||||
|
'messageUrl': jump_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f'[后端] [N] 发送消息卡片: {data}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, json=data, headers=headers, timeout=10)
|
||||||
|
result = response.json()
|
||||||
|
print(f'[后端] [N] 钉钉响应:', result)
|
||||||
|
if result.get('errcode') == 0:
|
||||||
|
print(f'[后端] [N] 消息发送成功')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f'[后端] [N] 消息发送失败: {result.get("errmsg", "未知错误")}')
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f'[后端] [N] 异常:', e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def notify_admins_new_demand(demand, base_url):
|
||||||
|
"""通知所有管理员有新需求提交"""
|
||||||
|
print(f'[后端] [N] ============== notify_admins_new_demand 开始 ==============')
|
||||||
|
|
||||||
|
# 获取所有管理员用户
|
||||||
|
from models import User
|
||||||
|
admins = User.query.filter_by(role='admin').all()
|
||||||
|
print(f'[后端] [N] 找到 {len(admins)} 个管理员')
|
||||||
|
|
||||||
|
if not admins:
|
||||||
|
print('[后端] [N] 没有管理员用户,跳过通知')
|
||||||
|
return
|
||||||
|
|
||||||
|
# 构建消息内容
|
||||||
|
title = f'📋 新需求提交:{demand.title}'
|
||||||
|
content = f'''需求标题:{demand.title}
|
||||||
|
|
||||||
|
提交者:{demand.contact or "未知"}
|
||||||
|
|
||||||
|
分会:{demand.branch}
|
||||||
|
|
||||||
|
点击查看并回答'''.strip()
|
||||||
|
|
||||||
|
# 回答页面的跳转链接
|
||||||
|
jump_url = f'{base_url}/demand/{demand.id}/answer'
|
||||||
|
|
||||||
|
success_count = 0
|
||||||
|
for admin in admins:
|
||||||
|
if admin.dingtalk_userid:
|
||||||
|
if send_dingtalk_card_to_user(admin.dingtalk_userid, title, content, jump_url):
|
||||||
|
success_count += 1
|
||||||
|
|
||||||
|
print(f'[后端] [N] 消息发送完成,成功: {success_count}/{len(admins)}')
|
||||||
|
|
||||||
|
def notify_asker_answer(demand, base_url):
|
||||||
|
"""通知提问者问题已被回答"""
|
||||||
|
print(f'[后端] [N] ============== notify_asker_answer 开始 ==============')
|
||||||
|
|
||||||
|
# 获取提问者
|
||||||
|
User = get_user_model()
|
||||||
|
asker = User.query.get(demand.user_id)
|
||||||
|
if not asker:
|
||||||
|
print('[后端] [N] 未找到提问者,跳过通知')
|
||||||
|
return
|
||||||
|
|
||||||
|
if not asker.dingtalk_userid:
|
||||||
|
print(f'[后端] [N] 提问者 {asker.username} 没有钉钉userid,跳过通知')
|
||||||
|
return
|
||||||
|
|
||||||
|
# 构建消息内容
|
||||||
|
title = f'✅ 您的需求已被回答:{demand.title}'
|
||||||
|
content = f'''需求标题:{demand.title}
|
||||||
|
|
||||||
|
管理员已回复您的问题,点击查看详情'''.strip()
|
||||||
|
|
||||||
|
# 跳转链接 - 指向首页
|
||||||
|
jump_url = f'{base_url}' + '/dingtalk'
|
||||||
|
|
||||||
|
print(f'[后端] [N] 准备通知提问者: {asker.username}, dingtalk_userid: {asker.dingtalk_userid}')
|
||||||
|
|
||||||
|
if send_dingtalk_card_to_user(asker.dingtalk_userid, title, content, jump_url):
|
||||||
|
print(f'[后端] [N] 提问者通知发送成功')
|
||||||
|
else:
|
||||||
|
print(f'[后端] [N] 提问者通知发送失败')
|
||||||
|
|
||||||
@dingtalk_bp.route('/')
|
@dingtalk_bp.route('/')
|
||||||
def dingtalk_entry():
|
def dingtalk_entry():
|
||||||
print('[后端] [0] ============== dingtalk_entry 请求到达 ==============')
|
print('[后端] [0] ============== dingtalk_entry 请求到达 ==============')
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ tar -czvf "$OUTPUT_DIR/${PROJECT_NAME}_$(date +%Y%m%d_%H%M%S).tar.gz" \
|
|||||||
--exclude='.git' \
|
--exclude='.git' \
|
||||||
--exclude='.codebuddy' \
|
--exclude='.codebuddy' \
|
||||||
--exclude='node_modules' \
|
--exclude='node_modules' \
|
||||||
--exclude='*.db' \
|
|
||||||
--exclude='venv' \
|
--exclude='venv' \
|
||||||
--exclude='env' \
|
--exclude='env' \
|
||||||
--exclude='.env' \
|
--exclude='.env' \
|
||||||
|
|||||||
11
routes.py
11
routes.py
@@ -4,6 +4,7 @@ from flask_login import login_user, logout_user, login_required, current_user
|
|||||||
from __init__ import app, db
|
from __init__ import app, db
|
||||||
from models import User, Demand, now_shanghai
|
from models import User, Demand, now_shanghai
|
||||||
from forms import DemandForm, AnswerForm, LoginForm, RegisterForm
|
from forms import DemandForm, AnswerForm, LoginForm, RegisterForm
|
||||||
|
from dingtalk import notify_admins_new_demand, notify_asker_answer
|
||||||
|
|
||||||
BRANCH_NAMES = {
|
BRANCH_NAMES = {
|
||||||
'comprehensive': '综合分会',
|
'comprehensive': '综合分会',
|
||||||
@@ -125,6 +126,11 @@ def new_demand():
|
|||||||
)
|
)
|
||||||
db.session.add(demand)
|
db.session.add(demand)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
# 通知管理员有新需求提交
|
||||||
|
base_url = request.host_url.rstrip('/').replace('http://', 'https://') + '/requirement-collection'
|
||||||
|
notify_admins_new_demand(demand, base_url)
|
||||||
|
|
||||||
flash('需求提交成功', 'success')
|
flash('需求提交成功', 'success')
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
return render_template('demand_form.html', form=form, title='提交新需求')
|
return render_template('demand_form.html', form=form, title='提交新需求')
|
||||||
@@ -164,6 +170,11 @@ def answer_demand(id):
|
|||||||
demand.answer = form.answer.data
|
demand.answer = form.answer.data
|
||||||
demand.answered_at = now_shanghai()
|
demand.answered_at = now_shanghai()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
# 通知提问者问题已被回答
|
||||||
|
base_url = request.host_url.rstrip('/').replace('http://', 'https://') + '/requirement-collection'
|
||||||
|
notify_asker_answer(demand, base_url)
|
||||||
|
|
||||||
flash('回答已保存', 'success')
|
flash('回答已保存', 'success')
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
return render_template('answer_form.html', form=form, demand=demand)
|
return render_template('answer_form.html', form=form, demand=demand)
|
||||||
|
|||||||
0
start_dingtalk.sh
Normal file → Executable file
0
start_dingtalk.sh
Normal file → Executable file
@@ -55,7 +55,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<img src="/static/logo.png" alt="logo" class="logo">
|
<img src="{{ url_for('static', filename='logo.png') }}" alt="logo" class="logo">
|
||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
<p class="loading">正在跳转...</p>
|
<p class="loading">正在跳转...</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user