!11787 通知公告优化

Merge pull request !11787 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2026-05-29 09:27:51 +00:00
committed by Gitee
4 changed files with 38 additions and 34 deletions
+14 -31
View File
@@ -487,41 +487,24 @@ class AiConversation(models.Model):
'message': f'已生成报表链接: {url}',
}
# ===== 主动推送到用户企微 =====
try:
employee = self.env['hr.employee'].sudo().search([
('user_id', '=', self.env.uid)
], limit=1)
if employee and employee.wecom_userid:
push_result = self.sudo().env["wecom.apps"].sync_send_message_textcard(
category='notice',
touser=employee.wecom_userid,
title=f"📊 {report_name}",
description=f"数据来源:{model_name}\n生成时间:{fields.Datetime.now().strftime('%Y-%m-%d %H:%M')}\n点击下方按钮查看详细报表",
url=url,
btntxt="查看报表",
)
if push_result and push_result[0]:
result['wecom_sent'] = True
_logger.info(f"报表 {report.id} 已推送到用户 {employee.name} 的企微")
else:
err_msg = push_result[1] if push_result else '推送返回为空'
result['wecom_sent'] = False
result['wecom_msg'] = f'企微推送失败: {err_msg}'
_logger.warning(f"报表 {report.id} 企微推送失败: {err_msg}")
else:
result['wecom_sent'] = False
result['wecom_msg'] = '当前用户未绑定企微账号,无法推送'
_logger.warning(f"用户 {self.env.uid} 未找到企微账号,报表未推送")
except Exception as we:
_logger.exception(f"推送报表到企微失败: {we}")
result['wecom_sent'] = False
result['wecom_msg'] = f'企微推送异常: {we}'
# ===== 静默尝试推送到用户企微(失败不报错) =====
employee = self.env['hr.employee'].sudo().search([
('user_id', '=', self.env.uid)
], limit=1)
if employee and employee.wecom_userid:
push_result = self.sudo().env["wecom.apps"].sync_send_message_textcard(
category='agent',
touser=employee.wecom_userid,
title=f"📊 {report_name}",
description=f"数据来源:{model_name}\n生成时间:{fields.Datetime.now().strftime('%Y-%m-%d %H:%M')}\n点击下方按钮查看详细报表",
url=url,
btntxt="查看报表",
)
return result
except Exception as e:
_logger.exception('generate_report failed: %s', e)
return {'error': f'生成报表失败: {e}'}
return {'success': True, 'url': '', 'message': f'报表生成完毕(记录日志),请稍后查看'} # 失败不报错,静默返回
def _call_chat_completion(self, provider, messages, tools=None):
"""封装一次 HTTP 调用,返回 (assistant_message_dict, error_str)。
@@ -25,6 +25,18 @@ export class AiChatAction extends Component {
}
}
// 渲染消息内容:转义HTML + URL转可点击链接
renderMsgContent(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
const safe = div.innerHTML;
return safe.replace(
/(https?:\/\/[^\s<]+)/g,
'<a href="$1" target="_blank" rel="noopener noreferrer" style="color:#4FC3F7;text-decoration:underline;word-break:break-all">$1</a>'
);
}
async _loadHistory() {
try {
const data = await this.rpc("/ai/chat/history", { conversation_id: this.resId });
+11 -2
View File
@@ -83,6 +83,15 @@ function escapeHtml(text) {
return div.innerHTML;
}
function renderContent(text) {
// 先转义防 XSS,再把 URL 转成可点击链接
const safe = escapeHtml(text || '');
return safe.replace(
/(https?:\/\/[^\s<]+)/g,
'<a href="$1" target="_blank" rel="noopener noreferrer" style="color:#4FC3F7;text-decoration:underline;word-break:break-all">$1</a>'
);
}
function renderChat() {
if (!chatEl) return;
chatEl.innerHTML = "";
@@ -119,7 +128,7 @@ function renderChat() {
<div id="yuthon_chat_msgs" class="o_ai_messages" style="display:${showConvList ? 'none' : 'flex'}">
${msgs.map(m => `
<div class="o_ai_msg ${m.role === 'user' ? 'o_ai_msg_user' : 'o_ai_msg_ai'}">
<div class="o_ai_msg_bubble">${escapeHtml(m.content)}</div>
<div class="o_ai_msg_bubble">${m.role === 'assistant' ? renderContent(m.content) : escapeHtml(m.content)}</div>
<div class="o_ai_msg_time">${m.date || ''}</div>
</div>
`).join('')}
@@ -244,7 +253,7 @@ async function sendMsg() {
if (msgsEl) {
msgsEl.innerHTML += `
<div class="o_ai_msg o_ai_msg_ai">
<div class="o_ai_msg_bubble">${escapeHtml(content)}</div>
<div class="o_ai_msg_bubble">${renderContent(content)}</div>
<div class="o_ai_msg_time">刚刚</div>
</div>
`;
@@ -15,7 +15,7 @@
</div>
<t t-foreach="state.messages" t-as="msg" t-key="msg_index">
<div t-att-class="'ai-chat-msg ' + msg.role">
<div class="ai-chat-bubble" t-out="msg.content"/>
<div class="ai-chat-bubble" t-raw="renderMsgContent(msg.content)"/>
<div class="ai-chat-meta" t-if="msg.date" t-esc="msg.date"/>
</div>
</t>