diff --git a/scripts/build_dingtalk_card_template.py b/scripts/build_dingtalk_card_template.py index 8508ac0c1..aae64418c 100644 --- a/scripts/build_dingtalk_card_template.py +++ b/scripts/build_dingtalk_card_template.py @@ -602,9 +602,9 @@ def build_editor_data(): 'conditionGroup': '', 'children': [ avatar('node_avatar', name='LangBot'), + markdown_block('node_text_content', variable='content'), input_block('node_input'), select_block('node_select'), - markdown_block('node_text_content', variable='content'), button_group('node_btn_group'), ], } diff --git a/src/langbot/pkg/platform/sources/dingtalk.py b/src/langbot/pkg/platform/sources/dingtalk.py index 943cc46a7..e412cf0ae 100644 --- a/src/langbot/pkg/platform/sources/dingtalk.py +++ b/src/langbot/pkg/platform/sources/dingtalk.py @@ -213,12 +213,45 @@ def _dingtalk_pending_input_defs(form_data: dict) -> list[dict]: def _dingtalk_clean_form_content(form_data: dict) -> str: - content = form_data.get('raw_form_content') or form_data.get('form_content') or '' - field_names = { - str(field.get('output_variable_name') or '').strip() - for field in _dingtalk_form_input_defs(form_data) - if str(field.get('output_variable_name') or '').strip() - } + is_field_step = bool(form_data.get('_current_input_field')) and not form_data.get('_action_select_only') + raw_content = str(form_data.get('raw_form_content') or '') + content = raw_content or form_data.get('form_content') or '' + input_defs = _dingtalk_form_input_defs(form_data) + field_names = {_dingtalk_field_name(field) for field in input_defs if _dingtalk_field_name(field)} + + if is_field_step and raw_content: + current_field = str(form_data.get('_current_input_field') or '').strip() + current_placeholder = next( + ( + match + for match in re.finditer(r'\{\{#\$output\.([^#{}]+)#\}\}', raw_content) + if match.group(1).strip() == current_field + ), + None, + ) + content = ( + raw_content[: current_placeholder.end()] if current_placeholder else form_data.get('form_content') or '' + ) + + if form_data.get('_action_select_only') or is_field_step: + fields = {_dingtalk_field_name(field): field for field in input_defs if _dingtalk_field_name(field)} + inputs = form_data.get('inputs') or {} + + def replace_placeholder(match: re.Match[str]) -> str: + field_name = match.group(1).strip() + field = fields.get(field_name) + if not field or inputs.get(field_name) in (None, '', []): + return '' + lines = _dingtalk_completed_input_lines( + { + 'input_defs': [field], + 'inputs': {field_name: inputs[field_name]}, + } + ) + return lines[0] if lines else '' + + content = re.sub(r'\{\{#\$output\.([^#{}]+)#\}\}', replace_placeholder, str(content)) + kept_lines: list[str] = [] for line in str(content).splitlines(): placeholder = re.fullmatch(r'\s*\{\{#\$output\.([^#{}]+)#\}\}\s*', line) @@ -228,6 +261,11 @@ def _dingtalk_clean_form_content(form_data: dict) -> str: return re.sub(r'\n{3,}', '\n\n', '\n'.join(kept_lines).strip()) +def _dingtalk_card_markdown(content: str) -> str: + """Preserve line breaks inside DingTalk card-template markdown slots.""" + return '
'.join(str(content or '').splitlines()) + + def _dingtalk_form_input_defs(form_data: dict) -> list[dict]: return list(form_data.get('all_input_defs') or form_data.get('input_defs') or []) @@ -261,11 +299,11 @@ def _dingtalk_completed_input_lines(form_data: dict) -> list[str]: field_type = _dingtalk_field_type(field) display_value = _dingtalk_display_input_value(field, value) if field_type == 'select': - lines.append(f'✅ 已选择 {field_name}:**{display_value}**') + lines.append(f'✅ 已选择 {field_name}:{display_value}') elif field_type in {'file', 'file-list'}: - lines.append(f'✅ 已上传 {field_name}:**{display_value}**') + lines.append(f'✅ 已上传 {field_name}:{display_value}') else: - lines.append(f'✅ 已填写 {field_name}:**{display_value}**') + lines.append(f'✅ 已填写 {field_name}:{display_value}') return lines @@ -915,9 +953,9 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): if node_title: parts.append(f'**{node_title}**') if form_content: - parts.append(form_content) + parts.append(_dingtalk_card_markdown(form_content)) completed_lines = _dingtalk_completed_input_lines(form_data) - if completed_lines: + if completed_lines and not all(line in form_content for line in completed_lines): parts.append('
' + '
'.join(completed_lines)) input_hint_lines = [] if native_field else _dingtalk_input_hint_lines(form_data) if input_hint_lines: @@ -1017,9 +1055,9 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): if node_title: parts.append(f'**{node_title}**') if form_content: - parts.append(form_content) + parts.append(_dingtalk_card_markdown(form_content)) completed_lines = _dingtalk_completed_input_lines(form_data) - if completed_lines: + if completed_lines and not all(line in form_content for line in completed_lines): parts.append('
' + '
'.join(completed_lines)) input_hint_lines = [] if native_field else _dingtalk_input_hint_lines(form_data) if input_hint_lines: @@ -1457,14 +1495,14 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): if node_title: parts.append(f'**{node_title}**') if form_content: - parts.append(form_content) + parts.append(_dingtalk_card_markdown(form_content)) completed_lines = _dingtalk_completed_input_lines( { 'input_defs': input_defs or [], 'inputs': inputs or {}, } ) - if completed_lines: + if completed_lines and not all(line in form_content for line in completed_lines): parts.append('
' + '
'.join(completed_lines)) parts.append(f'
✅ 已选择:**{action_title}**') content = '

'.join(parts) diff --git a/src/langbot/templates/dingtalk_human_input_card.json b/src/langbot/templates/dingtalk_human_input_card.json index e178e7249..81e891ac6 100644 --- a/src/langbot/templates/dingtalk_human_input_card.json +++ b/src/langbot/templates/dingtalk_human_input_card.json @@ -1,5 +1,5 @@ { - "editorData": "{\"schemaVersion\":\"3.0.0\",\"schema\":{\"config\":null,\"componentsMap\":[{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AIPending\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AIPending\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AICardStatusContainer\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AICardStatusContainer\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"BaseText\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"BaseText\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AICardContent\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AICardContent\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AICardContainer\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AICardContainer\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"ButtonGroup\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"ButtonGroup\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"MarkdownBlock\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"MarkdownBlock\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"Avatar\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"Avatar\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"Input\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"Input\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"SelectBlock\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"SelectBlock\"}],\"componentsTree\":[{\"componentName\":\"AICardContainer\",\"id\":\"node_root\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enablePending\":true,\"enableWriting\":true,\"enableDoing\":true,\"enableFailed\":true,\"summaryContent\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"\"},\"enableTitle\":false,\"flowStatusVar\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"flowStatus\"},\"operationPenalType\":\"custom\",\"enableFlowAbort\":true,\"innerOffset\":0,\"enableGradientBorder\":true,\"cardSizeMode\":\"adaptive\",\"cardSizeHeightMode\":\"adaptive\",\"cardSizeWidthMode\":\"adaptive\",\"cardSizeHeight\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":226,\"variable\":\"\",\"variableType\":\"global\"},\"hasBackground\":false,\"backgroundType\":\"Standard\",\"standardBackgroundColor\":\"gray\",\"backgroundColor\":\"#F6F6F6\",\"darkModeBackgroundColor\":\"#3C3C3C\",\"enableEngineUpgrade\":false,\"enableExposeStatPoint\":false,\"enableDebugTool\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_pending\",\"props\":{\"status\":1,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"处理中状态\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AIPending\",\"id\":\"node_pending_inner\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"pendingTip\":{\"type\":\"dynamicString\",\"content\":\"处理中...\",\"i18n\":false},\"style\":\"embed\",\"hideIcon\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_writing\",\"props\":{\"status\":2,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"状态2占位\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_status_writing_content\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[]}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_doing\",\"props\":{\"status\":4,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"状态4占位\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_status_doing_content\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[]}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_done\",\"props\":{\"status\":3,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"完成状态\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_done_content\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"Avatar\",\"id\":\"node_avatar\",\"props\":{\"imageUrl\":{\"value\":\"\",\"valueType\":\"variable\",\"type\":\"dynamicImage\",\"variable\":\"bot_avatar\",\"variableType\":\"global\"},\"name\":{\"i18n\":false,\"type\":\"dynamicString\",\"content\":\"LangBot\"},\"sizeType\":\"Standard\",\"size\":\"extraSmall\",\"customSize\":48,\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":6,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"mode\":\"userInfo\",\"margin\":-2,\"innerOffset\":0},\"title\":\"头像\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"Input\",\"id\":\"node_input\",\"props\":{\"placeholder\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_placeholder\",\"variableType\":\"global\"},\"currentValue\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_value\",\"variableType\":\"global\"},\"message\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_placeholder\",\"variableType\":\"global\"},\"title\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_title\",\"variableType\":\"global\"},\"id\":{\"type\":\"dynamicString\",\"content\":\"input\",\"i18n\":false},\"params\":[{\"type\":\"builtIn\",\"variable\":\"\",\"value\":\"\",\"name\":\"input\",\"variableType\":\"global\",\"id\":\"__built_in_inputResult__\"}],\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"variable\",\"variable\":\"input_visible\",\"variableType\":\"global\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"status\":{\"type\":\"dynamicSelect\",\"valueType\":\"fixed\",\"value\":\"normal\",\"variable\":\"\",\"variableType\":\"global\"},\"actionType\":\"request\",\"localVarAction\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"\"},\"keyOfDynamicObject\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"inlineMode\":false,\"textArea\":true,\"minRows\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":2,\"variable\":\"\",\"variableType\":\"global\"},\"maxRows\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":6,\"variable\":\"\",\"variableType\":\"global\"},\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":6,\"margin\":12,\"innerOffset\":0},\"title\":\"Text input\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"SelectBlock\",\"id\":\"node_select\",\"props\":{\"id\":{\"type\":\"dynamicString\",\"content\":\"select\",\"i18n\":false},\"placeholder\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"select_placeholder\",\"variableType\":\"global\"},\"currentIndex\":{\"type\":\"dynamicNumber\",\"valueType\":\"variable\",\"value\":-1,\"variable\":\"select_index\",\"variableType\":\"global\"},\"options\":{\"type\":\"dynamicSelectOptions\",\"valueType\":\"variable\",\"value\":[],\"variable\":\"index_o\",\"variableType\":\"global\"},\"optionLabelMaxLines\":3,\"params\":[{\"type\":\"builtIn\",\"variable\":\"\",\"value\":\"{\\\"index\\\": ${index}, \\\"value\\\": \\\"${value}\\\"}\",\"name\":\"select\",\"variableType\":\"global\",\"id\":\"__built_in_selectResult__\"}],\"actionType\":\"request\",\"localVarAction\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"\"},\"keyOfDynamicObject\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"status\":{\"type\":\"dynamicSelect\",\"valueType\":\"fixed\",\"value\":\"normal\",\"variable\":\"\",\"variableType\":\"global\"},\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"variable\",\"variable\":\"select_visible\",\"variableType\":\"global\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":6,\"pullOptionsWhileOpen\":false,\"pullOptionsRequestParams\":[],\"margin\":12,\"innerOffset\":0},\"title\":\"Select\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"MarkdownBlock\",\"id\":\"node_text_content\",\"props\":{\"mdVer\":0,\"icon\":{\"type\":\"icon\",\"icon\":\"\",\"iconType\":\"emoji\"},\"content\":{\"variable\":\"content\",\"variableType\":\"global\",\"type\":\"variableValue\",\"varType\":\"markdown\"},\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"isStreaming\":false,\"enableLinkStatPoint\":false,\"linkStatPoint\":{\"type\":\"dynamicString\",\"content\":\"Page_InteractiveCard__Click_markdownOpenlink\",\"i18n\":false},\"linkStatPointParams\":[],\"marginTop\":6,\"marginBottom\":6,\"marginLeft\":12,\"marginRight\":12},\"title\":\"AI 流式富文本\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"ButtonGroup\",\"id\":\"node_btn_group\",\"props\":{\"dynamicButtons\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"btns\"},\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":12,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"responsiveLayoutWidth\":350,\"buttonsSource\":\"variable\",\"fixedButtonIds\":[],\"fixedButtons\":[],\"enableResponsiveLayout\":false,\"matchContent\":false,\"buttonSpacing\":8,\"margin\":-2,\"innerOffset\":0},\"title\":\"按钮组\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"}]}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_failed\",\"props\":{\"status\":5,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"失败状态\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_failed_content\",\"props\":{\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"BaseText\",\"id\":\"node_failed_text\",\"props\":{\"text\":{\"i18n\":false,\"type\":\"dynamicString\",\"content\":\"操作失败,请稍后重试。\"},\"hoverText\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"iconType\":\"iconCode\",\"iconFont\":{\"type\":\"icon\",\"icon\":\"\",\"iconType\":\"ddIcon\"},\"icon\":{\"type\":\"dynamicLink\",\"value\":\"\",\"valueType\":\"fixed\",\"variable\":\"\",\"variableType\":\"global\"},\"darkIcon\":{\"type\":\"dynamicLink\",\"value\":\"\",\"valueType\":\"fixed\",\"variable\":\"\",\"variableType\":\"global\"},\"autoWidth\":false,\"maxWidth\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":0,\"variable\":\"\",\"variableType\":\"global\"},\"fixedWidth\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":0,\"variable\":\"\",\"variableType\":\"global\"},\"marginLeft\":10,\"marginRight\":10,\"marginTop\":10,\"marginBottom\":10,\"fontColorType\":\"Standard\",\"enableHighlight\":false,\"maxLine\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":2,\"variable\":\"\",\"variableType\":\"global\"},\"color\":{\"type\":\"dynamicColor\",\"valueType\":\"fixed\",\"value\":\"common_level1_base_color\",\"variable\":\"\",\"variableType\":\"global\"},\"customLightColor\":{\"type\":\"dynamicColor\",\"valueType\":\"fixed\",\"value\":\"#35404b\",\"variable\":\"\",\"variableType\":\"global\"},\"customDarkColor\":{\"type\":\"dynamicColor\",\"valueType\":\"fixed\",\"value\":\"#f6f6f6\",\"variable\":\"\",\"variableType\":\"global\"},\"gravity\":\"center\",\"fontSizeType\":\"Standard\",\"styleType\":\"custom\",\"styleToken\":\"common_body_text_style\",\"size\":\"middle\",\"customFontSize\":15,\"customFontLineHeight\":22,\"bold\":false,\"italic\":false,\"strikeThrough\":false,\"lineHeight\":\"normal\",\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"autoMaxWidth\":false,\"innerOffset\":0,\"enableIcon\":false,\"widthMode\":\"match_parent\",\"margin\":-2},\"title\":\"基础文本\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"}]}]}]}],\"i18n\":{},\"version\":\"1.0.0\"},\"mockData\":{\"cardData\":{\"flowStatus\":3,\"content\":\"请审核以下报销申请:\\n\\n- 申请人:张三\\n- 金额:¥1,200\\n- 类别:差旅\",\"input_visible\":\"\",\"input_title\":\"\",\"input_placeholder\":\"\",\"input_value\":\"\",\"select_visible\":\"\",\"select_placeholder\":\"\",\"index_o\":[{\"value\":\"\",\"text\":{\"zh_CN\":\"\",\"zh_TW\":\"\",\"en_US\":\"\",\"ja_JP\":\"\",\"vi_VN\":\"\",\"th_TH\":\"\",\"id_ID\":\"\",\"ne_NP\":\"\",\"ms_MY\":\"\",\"ko_KR\":\"\",\"ru_RU\":\"\",\"es_EA\":\"\",\"tr_TR\":\"\",\"fr_FR\":\"\",\"pt_BR\":\"\"}}],\"select_options\":[],\"select_index\":-1,\"btns\":[{\"text\":\"通过\",\"color\":\"blue\",\"status\":\"normal\",\"event\":{\"type\":\"sendCardRequest\",\"params\":{\"actionId\":\"approve\",\"params\":{\"action_id\":\"approve\"}}}},{\"text\":\"驳回\",\"color\":\"gray\",\"status\":\"normal\",\"event\":{\"type\":\"sendCardRequest\",\"params\":{\"actionId\":\"reject\",\"params\":{\"action_id\":\"reject\"}}}},{\"text\":\"补充资料\",\"color\":\"gray\",\"status\":\"normal\",\"event\":{\"type\":\"sendCardRequest\",\"params\":{\"actionId\":\"more_info\",\"params\":{\"action_id\":\"more_info\"}}}}]},\"cardPrivateData\":{},\"localData\":{\"flowStatus\":\"\",\"_cardFoldStatusLocalDataKey\":\"\"},\"richTextData\":{}},\"renderContext\":{\"regenerateEnabled\":\"1\",\"regenerateIndex\":\"2\",\"regenerateTotal\":\"5\"},\"editVersion\":0,\"customWidgetInfo\":\"\",\"useCustomWidgetInfo\":false,\"variableList\":[{\"id\":\"content\",\"type\":\"markdown\",\"name\":\"content\",\"description\":\"人工输入提示词(Dify form_content 含可选 node_title 前缀)\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"flowStatus\",\"type\":\"string\",\"name\":\"flowStatus\",\"description\":\"AI卡片状态:pending(1)、writing(2)、done(3)、failed(5)\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"visible\":false},{\"id\":\"bot_avatar\",\"type\":\"string\",\"name\":\"bot_avatar\",\"description\":\"机器人头像 DingTalk 媒体 ID(@xxx 格式,启动时由 /media/upload 拿到)\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_visible\",\"type\":\"string\",\"name\":\"input_visible\",\"description\":\"Whether to show the text input component\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_title\",\"type\":\"string\",\"name\":\"input_title\",\"description\":\"Text input title\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_placeholder\",\"type\":\"string\",\"name\":\"input_placeholder\",\"description\":\"Text input placeholder\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_value\",\"type\":\"string\",\"name\":\"input_value\",\"description\":\"Text input current value\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"select_visible\",\"type\":\"string\",\"name\":\"select_visible\",\"description\":\"Whether to show the select component\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"select_placeholder\",\"type\":\"string\",\"name\":\"select_placeholder\",\"description\":\"Select placeholder\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"name\":\"index_o\",\"private\":false,\"type\":\"selectOptions\",\"id\":\"index_o\",\"description\":\"Select options\",\"editorVarType\":\"variables\",\"disabled\":false,\"schema\":[{\"id\":\"index_o.value\",\"type\":\"string\",\"name\":\"value\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.text\",\"type\":\"object\",\"name\":\"text\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\",\"schema\":[{\"id\":\"index_o.zh_CN\",\"type\":\"string\",\"name\":\"zh_CN\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.zh_TW\",\"type\":\"string\",\"name\":\"zh_TW\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.en_US\",\"type\":\"string\",\"name\":\"en_US\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ja_JP\",\"type\":\"string\",\"name\":\"ja_JP\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.vi_VN\",\"type\":\"string\",\"name\":\"vi_VN\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.th_TH\",\"type\":\"string\",\"name\":\"th_TH\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.id_ID\",\"type\":\"string\",\"name\":\"id_ID\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ne_NP\",\"type\":\"string\",\"name\":\"ne_NP\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ms_MY\",\"type\":\"string\",\"name\":\"ms_MY\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ko_KR\",\"type\":\"string\",\"name\":\"ko_KR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ru_RU\",\"type\":\"string\",\"name\":\"ru_RU\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.es_EA\",\"type\":\"string\",\"name\":\"es_EA\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.tr_TR\",\"type\":\"string\",\"name\":\"tr_TR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.fr_FR\",\"type\":\"string\",\"name\":\"fr_FR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.pt_BR\",\"type\":\"string\",\"name\":\"pt_BR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"}]}]},{\"id\":\"select_options\",\"type\":\"array\",\"name\":\"select_options\",\"description\":\"Legacy select options\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"select_index\",\"type\":\"number\",\"name\":\"select_index\",\"description\":\"Current select index\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"name\":\"btns\",\"private\":false,\"type\":\"buttonGroup\",\"id\":\"btns\",\"description\":\"动态按钮列表(Dify actions)\",\"editorVarType\":\"variables\",\"disabled\":false,\"schema\":[{\"id\":\"btns.text\",\"type\":\"string\",\"name\":\"text\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮文案\"},{\"id\":\"btns.color\",\"type\":\"string\",\"name\":\"color\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮颜色\"},{\"id\":\"btns.status\",\"type\":\"string\",\"name\":\"status\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮状态\"},{\"id\":\"btns.event\",\"type\":\"dynamicEvent\",\"name\":\"event\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮点击事件\",\"schema\":[{\"id\":\"btns.type\",\"type\":\"string\",\"name\":\"type\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"事件类型:openLink / sendCardRequest\"},{\"id\":\"btns.params\",\"type\":\"object\",\"name\":\"params\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"事件参数\",\"schema\":[{\"id\":\"btns.url\",\"type\":\"string\",\"name\":\"url\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"点击跳转链接(type=openLink)\"},{\"id\":\"btns.actionId\",\"type\":\"string\",\"name\":\"actionId\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"回传请求 id(type=sendCardRequest)\"},{\"id\":\"btns.params\",\"type\":\"object\",\"name\":\"params\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"回传请求参数(type=sendCardRequest)\"}]}]}]}],\"formList\":[],\"customContextList\":[],\"expList\":[],\"localList\":[],\"hsfList\":[],\"lwpList\":[],\"pageData\":{},\"extension\":{\"extendType\":\"AI\",\"aiStatusList\":[3,1,5,2,4],\"fileTypeList\":[]}}", + "editorData": "{\"schemaVersion\":\"3.0.0\",\"schema\":{\"config\":null,\"componentsMap\":[{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AIPending\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AIPending\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AICardStatusContainer\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AICardStatusContainer\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"BaseText\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"BaseText\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AICardContent\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AICardContent\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"AICardContainer\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"AICardContainer\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"ButtonGroup\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"ButtonGroup\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"MarkdownBlock\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"MarkdownBlock\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"Avatar\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"Avatar\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"Input\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"Input\"},{\"package\":\"@ali/dxComponent\",\"version\":\"1.0.0\",\"exportName\":\"SelectBlock\",\"main\":\"./src/index.tsx\",\"destructuring\":false,\"subName\":\"\",\"componentName\":\"SelectBlock\"}],\"componentsTree\":[{\"componentName\":\"AICardContainer\",\"id\":\"node_root\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enablePending\":true,\"enableWriting\":true,\"enableDoing\":true,\"enableFailed\":true,\"summaryContent\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"\"},\"enableTitle\":false,\"flowStatusVar\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"flowStatus\"},\"operationPenalType\":\"custom\",\"enableFlowAbort\":true,\"innerOffset\":0,\"enableGradientBorder\":true,\"cardSizeMode\":\"adaptive\",\"cardSizeHeightMode\":\"adaptive\",\"cardSizeWidthMode\":\"adaptive\",\"cardSizeHeight\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":226,\"variable\":\"\",\"variableType\":\"global\"},\"hasBackground\":false,\"backgroundType\":\"Standard\",\"standardBackgroundColor\":\"gray\",\"backgroundColor\":\"#F6F6F6\",\"darkModeBackgroundColor\":\"#3C3C3C\",\"enableEngineUpgrade\":false,\"enableExposeStatPoint\":false,\"enableDebugTool\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_pending\",\"props\":{\"status\":1,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"处理中状态\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AIPending\",\"id\":\"node_pending_inner\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"pendingTip\":{\"type\":\"dynamicString\",\"content\":\"处理中...\",\"i18n\":false},\"style\":\"embed\",\"hideIcon\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_writing\",\"props\":{\"status\":2,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"状态2占位\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_status_writing_content\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[]}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_doing\",\"props\":{\"status\":4,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"状态4占位\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_status_doing_content\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[]}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_done\",\"props\":{\"status\":3,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"完成状态\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_done_content\",\"props\":{\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"Avatar\",\"id\":\"node_avatar\",\"props\":{\"imageUrl\":{\"value\":\"\",\"valueType\":\"variable\",\"type\":\"dynamicImage\",\"variable\":\"bot_avatar\",\"variableType\":\"global\"},\"name\":{\"i18n\":false,\"type\":\"dynamicString\",\"content\":\"LangBot\"},\"sizeType\":\"Standard\",\"size\":\"extraSmall\",\"customSize\":48,\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":6,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"mode\":\"userInfo\",\"margin\":-2,\"innerOffset\":0},\"title\":\"头像\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"MarkdownBlock\",\"id\":\"node_text_content\",\"props\":{\"mdVer\":0,\"icon\":{\"type\":\"icon\",\"icon\":\"\",\"iconType\":\"emoji\"},\"content\":{\"variable\":\"content\",\"variableType\":\"global\",\"type\":\"variableValue\",\"varType\":\"markdown\"},\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"isStreaming\":false,\"enableLinkStatPoint\":false,\"linkStatPoint\":{\"type\":\"dynamicString\",\"content\":\"Page_InteractiveCard__Click_markdownOpenlink\",\"i18n\":false},\"linkStatPointParams\":[],\"marginTop\":6,\"marginBottom\":6,\"marginLeft\":12,\"marginRight\":12},\"title\":\"AI 流式富文本\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"Input\",\"id\":\"node_input\",\"props\":{\"placeholder\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_placeholder\",\"variableType\":\"global\"},\"currentValue\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_value\",\"variableType\":\"global\"},\"message\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_placeholder\",\"variableType\":\"global\"},\"title\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"input_title\",\"variableType\":\"global\"},\"id\":{\"type\":\"dynamicString\",\"content\":\"input\",\"i18n\":false},\"params\":[{\"type\":\"builtIn\",\"variable\":\"\",\"value\":\"\",\"name\":\"input\",\"variableType\":\"global\",\"id\":\"__built_in_inputResult__\"}],\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"variable\",\"variable\":\"input_visible\",\"variableType\":\"global\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"status\":{\"type\":\"dynamicSelect\",\"valueType\":\"fixed\",\"value\":\"normal\",\"variable\":\"\",\"variableType\":\"global\"},\"actionType\":\"request\",\"localVarAction\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"\"},\"keyOfDynamicObject\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"inlineMode\":false,\"textArea\":true,\"minRows\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":2,\"variable\":\"\",\"variableType\":\"global\"},\"maxRows\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":6,\"variable\":\"\",\"variableType\":\"global\"},\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":6,\"margin\":12,\"innerOffset\":0},\"title\":\"Text input\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"SelectBlock\",\"id\":\"node_select\",\"props\":{\"id\":{\"type\":\"dynamicString\",\"content\":\"select\",\"i18n\":false},\"placeholder\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false,\"variable\":\"select_placeholder\",\"variableType\":\"global\"},\"currentIndex\":{\"type\":\"dynamicNumber\",\"valueType\":\"variable\",\"value\":-1,\"variable\":\"select_index\",\"variableType\":\"global\"},\"options\":{\"type\":\"dynamicSelectOptions\",\"valueType\":\"variable\",\"value\":[],\"variable\":\"index_o\",\"variableType\":\"global\"},\"optionLabelMaxLines\":3,\"params\":[{\"type\":\"builtIn\",\"variable\":\"\",\"value\":\"{\\\"index\\\": ${index}, \\\"value\\\": \\\"${value}\\\"}\",\"name\":\"select\",\"variableType\":\"global\",\"id\":\"__built_in_selectResult__\"}],\"actionType\":\"request\",\"localVarAction\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"\"},\"keyOfDynamicObject\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"status\":{\"type\":\"dynamicSelect\",\"valueType\":\"fixed\",\"value\":\"normal\",\"variable\":\"\",\"variableType\":\"global\"},\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"variable\",\"variable\":\"select_visible\",\"variableType\":\"global\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":6,\"pullOptionsWhileOpen\":false,\"pullOptionsRequestParams\":[],\"margin\":12,\"innerOffset\":0},\"title\":\"Select\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"},{\"componentName\":\"ButtonGroup\",\"id\":\"node_btn_group\",\"props\":{\"dynamicButtons\":{\"type\":\"variableValue\",\"variableType\":\"global\",\"variable\":\"btns\"},\"marginLeft\":12,\"marginRight\":12,\"marginTop\":6,\"marginBottom\":12,\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"responsiveLayoutWidth\":350,\"buttonsSource\":\"variable\",\"fixedButtonIds\":[],\"fixedButtons\":[],\"enableResponsiveLayout\":false,\"matchContent\":false,\"buttonSpacing\":8,\"margin\":-2,\"innerOffset\":0},\"title\":\"按钮组\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"}]}]},{\"componentName\":\"AICardStatusContainer\",\"id\":\"node_status_failed\",\"props\":{\"status\":5,\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"enableExtend\":false,\"autoFoldConfig\":{\"needFold\":true,\"heightLimit\":480,\"foldStatusLocalDataKey\":\"_cardFoldStatusLocalDataKey\"},\"innerOffset\":0,\"enableCollapse\":false,\"margin\":-2},\"title\":\"失败状态\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"AICardContent\",\"id\":\"node_failed_content\",\"props\":{\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"marginLeft\":0,\"marginRight\":0,\"marginTop\":0,\"marginBottom\":0,\"innerOffset\":0,\"disabledWhileForward\":false,\"statPoint\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"statPointParams\":[{\"type\":\"fixed\",\"variable\":\"\",\"value\":\"\",\"name\":\"\",\"variableType\":\"global\",\"id\":\"1\"}],\"margin\":-2,\"transformToEventChain\":false,\"enableStatPoint\":false},\"hidden\":false,\"title\":\"\",\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\",\"children\":[{\"componentName\":\"BaseText\",\"id\":\"node_failed_text\",\"props\":{\"text\":{\"i18n\":false,\"type\":\"dynamicString\",\"content\":\"操作失败,请稍后重试。\"},\"hoverText\":{\"type\":\"dynamicString\",\"content\":\"\",\"i18n\":false},\"iconType\":\"iconCode\",\"iconFont\":{\"type\":\"icon\",\"icon\":\"\",\"iconType\":\"ddIcon\"},\"icon\":{\"type\":\"dynamicLink\",\"value\":\"\",\"valueType\":\"fixed\",\"variable\":\"\",\"variableType\":\"global\"},\"darkIcon\":{\"type\":\"dynamicLink\",\"value\":\"\",\"valueType\":\"fixed\",\"variable\":\"\",\"variableType\":\"global\"},\"autoWidth\":false,\"maxWidth\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":0,\"variable\":\"\",\"variableType\":\"global\"},\"fixedWidth\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":0,\"variable\":\"\",\"variableType\":\"global\"},\"marginLeft\":10,\"marginRight\":10,\"marginTop\":10,\"marginBottom\":10,\"fontColorType\":\"Standard\",\"enableHighlight\":false,\"maxLine\":{\"type\":\"dynamicNumber\",\"valueType\":\"fixed\",\"value\":2,\"variable\":\"\",\"variableType\":\"global\"},\"color\":{\"type\":\"dynamicColor\",\"valueType\":\"fixed\",\"value\":\"common_level1_base_color\",\"variable\":\"\",\"variableType\":\"global\"},\"customLightColor\":{\"type\":\"dynamicColor\",\"valueType\":\"fixed\",\"value\":\"#35404b\",\"variable\":\"\",\"variableType\":\"global\"},\"customDarkColor\":{\"type\":\"dynamicColor\",\"valueType\":\"fixed\",\"value\":\"#f6f6f6\",\"variable\":\"\",\"variableType\":\"global\"},\"gravity\":\"center\",\"fontSizeType\":\"Standard\",\"styleType\":\"custom\",\"styleToken\":\"common_body_text_style\",\"size\":\"middle\",\"customFontSize\":15,\"customFontLineHeight\":22,\"bold\":false,\"italic\":false,\"strikeThrough\":false,\"lineHeight\":\"normal\",\"visible\":{\"type\":\"dynamicVisible\",\"value\":true,\"valueType\":\"fixed\",\"condition\":{\"op\":\"and\",\"conditions\":[]}},\"autoMaxWidth\":false,\"innerOffset\":0,\"enableIcon\":false,\"widthMode\":\"match_parent\",\"margin\":-2},\"title\":\"基础文本\",\"hidden\":false,\"isLocked\":false,\"condition\":true,\"conditionGroup\":\"\"}]}]}]}],\"i18n\":{},\"version\":\"1.0.0\"},\"mockData\":{\"cardData\":{\"flowStatus\":3,\"content\":\"请审核以下报销申请:\\n\\n- 申请人:张三\\n- 金额:¥1,200\\n- 类别:差旅\",\"input_visible\":\"\",\"input_title\":\"\",\"input_placeholder\":\"\",\"input_value\":\"\",\"select_visible\":\"\",\"select_placeholder\":\"\",\"index_o\":[{\"value\":\"\",\"text\":{\"zh_CN\":\"\",\"zh_TW\":\"\",\"en_US\":\"\",\"ja_JP\":\"\",\"vi_VN\":\"\",\"th_TH\":\"\",\"id_ID\":\"\",\"ne_NP\":\"\",\"ms_MY\":\"\",\"ko_KR\":\"\",\"ru_RU\":\"\",\"es_EA\":\"\",\"tr_TR\":\"\",\"fr_FR\":\"\",\"pt_BR\":\"\"}}],\"select_options\":[],\"select_index\":-1,\"btns\":[{\"text\":\"通过\",\"color\":\"blue\",\"status\":\"normal\",\"event\":{\"type\":\"sendCardRequest\",\"params\":{\"actionId\":\"approve\",\"params\":{\"action_id\":\"approve\"}}}},{\"text\":\"驳回\",\"color\":\"gray\",\"status\":\"normal\",\"event\":{\"type\":\"sendCardRequest\",\"params\":{\"actionId\":\"reject\",\"params\":{\"action_id\":\"reject\"}}}},{\"text\":\"补充资料\",\"color\":\"gray\",\"status\":\"normal\",\"event\":{\"type\":\"sendCardRequest\",\"params\":{\"actionId\":\"more_info\",\"params\":{\"action_id\":\"more_info\"}}}}]},\"cardPrivateData\":{},\"localData\":{\"flowStatus\":\"\",\"_cardFoldStatusLocalDataKey\":\"\"},\"richTextData\":{}},\"renderContext\":{\"regenerateEnabled\":\"1\",\"regenerateIndex\":\"2\",\"regenerateTotal\":\"5\"},\"editVersion\":0,\"customWidgetInfo\":\"\",\"useCustomWidgetInfo\":false,\"variableList\":[{\"id\":\"content\",\"type\":\"markdown\",\"name\":\"content\",\"description\":\"人工输入提示词(Dify form_content 含可选 node_title 前缀)\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"flowStatus\",\"type\":\"string\",\"name\":\"flowStatus\",\"description\":\"AI卡片状态:pending(1)、writing(2)、done(3)、failed(5)\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"visible\":false},{\"id\":\"bot_avatar\",\"type\":\"string\",\"name\":\"bot_avatar\",\"description\":\"机器人头像 DingTalk 媒体 ID(@xxx 格式,启动时由 /media/upload 拿到)\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_visible\",\"type\":\"string\",\"name\":\"input_visible\",\"description\":\"Whether to show the text input component\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_title\",\"type\":\"string\",\"name\":\"input_title\",\"description\":\"Text input title\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_placeholder\",\"type\":\"string\",\"name\":\"input_placeholder\",\"description\":\"Text input placeholder\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"input_value\",\"type\":\"string\",\"name\":\"input_value\",\"description\":\"Text input current value\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"select_visible\",\"type\":\"string\",\"name\":\"select_visible\",\"description\":\"Whether to show the select component\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"select_placeholder\",\"type\":\"string\",\"name\":\"select_placeholder\",\"description\":\"Select placeholder\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"name\":\"index_o\",\"private\":false,\"type\":\"selectOptions\",\"id\":\"index_o\",\"description\":\"Select options\",\"editorVarType\":\"variables\",\"disabled\":false,\"schema\":[{\"id\":\"index_o.value\",\"type\":\"string\",\"name\":\"value\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.text\",\"type\":\"object\",\"name\":\"text\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\",\"schema\":[{\"id\":\"index_o.zh_CN\",\"type\":\"string\",\"name\":\"zh_CN\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.zh_TW\",\"type\":\"string\",\"name\":\"zh_TW\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.en_US\",\"type\":\"string\",\"name\":\"en_US\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ja_JP\",\"type\":\"string\",\"name\":\"ja_JP\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.vi_VN\",\"type\":\"string\",\"name\":\"vi_VN\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.th_TH\",\"type\":\"string\",\"name\":\"th_TH\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.id_ID\",\"type\":\"string\",\"name\":\"id_ID\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ne_NP\",\"type\":\"string\",\"name\":\"ne_NP\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ms_MY\",\"type\":\"string\",\"name\":\"ms_MY\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ko_KR\",\"type\":\"string\",\"name\":\"ko_KR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.ru_RU\",\"type\":\"string\",\"name\":\"ru_RU\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.es_EA\",\"type\":\"string\",\"name\":\"es_EA\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.tr_TR\",\"type\":\"string\",\"name\":\"tr_TR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.fr_FR\",\"type\":\"string\",\"name\":\"fr_FR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"},{\"id\":\"index_o.pt_BR\",\"type\":\"string\",\"name\":\"pt_BR\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"\"}]}]},{\"id\":\"select_options\",\"type\":\"array\",\"name\":\"select_options\",\"description\":\"Legacy select options\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"id\":\"select_index\",\"type\":\"number\",\"name\":\"select_index\",\"description\":\"Current select index\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":false},{\"name\":\"btns\",\"private\":false,\"type\":\"buttonGroup\",\"id\":\"btns\",\"description\":\"动态按钮列表(Dify actions)\",\"editorVarType\":\"variables\",\"disabled\":false,\"schema\":[{\"id\":\"btns.text\",\"type\":\"string\",\"name\":\"text\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮文案\"},{\"id\":\"btns.color\",\"type\":\"string\",\"name\":\"color\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮颜色\"},{\"id\":\"btns.status\",\"type\":\"string\",\"name\":\"status\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮状态\"},{\"id\":\"btns.event\",\"type\":\"dynamicEvent\",\"name\":\"event\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"按钮点击事件\",\"schema\":[{\"id\":\"btns.type\",\"type\":\"string\",\"name\":\"type\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"事件类型:openLink / sendCardRequest\"},{\"id\":\"btns.params\",\"type\":\"object\",\"name\":\"params\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"事件参数\",\"schema\":[{\"id\":\"btns.url\",\"type\":\"string\",\"name\":\"url\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"点击跳转链接(type=openLink)\"},{\"id\":\"btns.actionId\",\"type\":\"string\",\"name\":\"actionId\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"回传请求 id(type=sendCardRequest)\"},{\"id\":\"btns.params\",\"type\":\"object\",\"name\":\"params\",\"private\":false,\"editorVarType\":\"variables\",\"disabled\":true,\"description\":\"回传请求参数(type=sendCardRequest)\"}]}]}]}],\"formList\":[],\"customContextList\":[],\"expList\":[],\"localList\":[],\"hsfList\":[],\"lwpList\":[],\"pageData\":{},\"extension\":{\"extendType\":\"AI\",\"aiStatusList\":[3,1,5,2,4],\"fileTypeList\":[]}}", "widgetInfo": "", "type": "im", "mode": "card" diff --git a/tests/unit_tests/platform/test_dingtalk_adapter.py b/tests/unit_tests/platform/test_dingtalk_adapter.py index 8551e613a..0850eab08 100644 --- a/tests/unit_tests/platform/test_dingtalk_adapter.py +++ b/tests/unit_tests/platform/test_dingtalk_adapter.py @@ -7,6 +7,7 @@ import pytest from langbot.pkg.platform.sources.dingtalk import ( DingTalkAdapter, + _dingtalk_card_markdown, _dingtalk_clean_form_content, _dingtalk_completed_input_lines, _dingtalk_extract_component_inputs, @@ -92,7 +93,7 @@ def test_dingtalk_completed_input_lines_include_text_and_select_values(): } ) - assert lines == ['✅ 已填写 comment:**looks good**', '✅ 已选择 choice:**B**'] + assert lines == ['✅ 已填写 comment:looks good', '✅ 已选择 choice:B'] def test_dingtalk_clean_form_content_uses_all_input_defs(): @@ -110,6 +111,49 @@ def test_dingtalk_clean_form_content_uses_all_input_defs(): assert content == 'Hello' +def test_dingtalk_field_stage_keeps_prior_prompts_and_completed_values(): + content = _dingtalk_clean_form_content( + { + '_current_input_field': 'choice', + 'raw_form_content': ('Question\n{{#$output.comment#}}\nChoose an answer\n{{#$output.choice#}}'), + 'form_content': 'Choose an answer', + 'input_defs': [ + {'output_variable_name': 'comment', 'type': 'paragraph'}, + {'output_variable_name': 'choice', 'type': 'select'}, + ], + 'inputs': {'comment': 'hello'}, + } + ) + + assert '{{#$output.' not in content + assert content.index('Question') < content.index('comment') + assert content.index('comment') < content.index('Choose an answer') + + +def test_dingtalk_final_action_stage_interleaves_prompts_and_completed_values(): + content = _dingtalk_clean_form_content( + { + '_action_select_only': True, + 'raw_form_content': ('11\nQuestion\n{{#$output.comment#}}\nChoose an answer\n{{#$output.choice#}}'), + 'all_input_defs': [ + {'output_variable_name': 'comment', 'type': 'paragraph'}, + {'output_variable_name': 'choice', 'type': 'select'}, + ], + 'inputs': {'comment': 'hello', 'choice': 'B'}, + } + ) + + assert '{{#$output.' not in content + assert content.startswith('11\nQuestion') + assert content.index('Question') < content.index('comment') + assert content.index('comment') < content.index('Choose an answer') + assert content.index('Choose an answer') < content.index('choice') + + +def test_dingtalk_card_markdown_preserves_internal_line_breaks(): + assert _dingtalk_card_markdown('11\nQuestion\nCompleted') == '11
Question
Completed' + + def _build_card_action_adapter() -> DingTalkAdapter: adapter = DingTalkAdapter.model_construct( card_state={