From f2fd28bf4d1318840f21a680105c0f38ec836811 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 13 May 2026 11:31:38 +0800 Subject: [PATCH] fix(feishu): place images at top of interactive cards and remove body padding for better visual layout --- app/modules/feishu/feishu.py | 21 +++++++++++---------- tests/test_feishu.py | 10 ++++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/modules/feishu/feishu.py b/app/modules/feishu/feishu.py index d0b244ff..ce73fa43 100644 --- a/app/modules/feishu/feishu.py +++ b/app/modules/feishu/feishu.py @@ -717,16 +717,8 @@ class Feishu: ) -> Dict[str, Any]: """构建飞书交互卡片结构。""" elements: List[dict] = [] - title_section = self._build_markdown_section(title, text_size="heading") - body_section = self._build_markdown_section( - self._build_message_text(title=None, text=text, link=link), - text_size="normal", - ) - if title_section: - elements.append(title_section) - if body_section: - elements.append(body_section) if image_key: + # 图文混合消息需要让图片贴近卡片顶部,避免先展示文字再露出海报。 elements.append( { "tag": "img", @@ -738,6 +730,15 @@ class Feishu: "mode": "fit_horizontal", } ) + title_section = self._build_markdown_section(title, text_size="heading") + body_section = self._build_markdown_section( + self._build_message_text(title=None, text=text, link=link), + text_size="normal", + ) + if title_section: + elements.append(title_section) + if body_section: + elements.append(body_section) elements.extend(self._card_actions(buttons)) return { # 飞书卡片消息要支持后续 PATCH 更新,发送和更新时都必须显式声明 update_multi。 @@ -752,7 +753,7 @@ class Feishu: }, "body": { "direction": "vertical", - "padding": "12px 12px 12px 12px", + "padding": "0px 0px 0px 0px", "elements": elements, }, } diff --git a/tests/test_feishu.py b/tests/test_feishu.py index 1af93d81..af4b4ea6 100644 --- a/tests/test_feishu.py +++ b/tests/test_feishu.py @@ -283,7 +283,8 @@ class TestFeishu(unittest.TestCase): request = message_api.create.call_args.args[0] self.assertEqual(request.request_body.msg_type, "interactive") content = json.loads(request.request_body.content) - image_element = content["body"]["elements"][2] + self.assertEqual(content["body"]["padding"], "0px 0px 0px 0px") + image_element = content["body"]["elements"][0] self.assertEqual(image_element["tag"], "img") self.assertEqual(image_element["img_key"], "img_v2_remote") self.assertEqual(content["body"]["elements"][-1]["tag"], "column_set") @@ -582,9 +583,10 @@ class TestFeishu(unittest.TestCase): request = message_api.create.call_args.args[0] self.assertEqual(request.request_body.msg_type, "interactive") content = json.loads(request.request_body.content) - self.assertEqual(content["body"]["elements"][0]["content"], "图片标题") - self.assertEqual(content["body"]["elements"][1]["content"], "图片说明") - self.assertEqual(content["body"]["elements"][2]["img_key"], "img_v2_uploaded") + self.assertEqual(content["body"]["padding"], "0px 0px 0px 0px") + self.assertEqual(content["body"]["elements"][0]["img_key"], "img_v2_uploaded") + self.assertEqual(content["body"]["elements"][1]["content"], "图片标题") + self.assertEqual(content["body"]["elements"][2]["content"], "图片说明") def test_send_file_keeps_non_image_file_message_and_caption(self): client = self._build_client()