"use strict"; /** * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates * SPDX-License-Identifier: MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CardConverter = exports.MODE = void 0; const utils_1 = require("../utils.js"); const types_1 = require("./types.js"); const card_utils_1 = require("./card-utils.js"); exports.MODE = { Concise: 0, Detailed: 1 }; const elementConverters = new Map([ ['plain_text', (c, _elem, prop) => c.convertPlainText(prop)], ['markdown', (c, _elem, prop) => c.convertMarkdown(prop)], ['markdown_v1', (c, elem, prop) => c.convertMarkdownV1(elem, prop)], ['text', (c, _elem, prop) => c.convertPlainText(prop)], ['div', (c, _elem, prop, id) => c.convertDiv(prop, id)], ['note', (c, _elem, prop) => c.convertNote(prop)], ['hr', () => '---'], ['br', () => '\n'], ['column_set', (c, _elem, prop, _id, depth) => c.convertColumnSet(prop, depth)], ['column', (c, _elem, prop, _id, depth) => c.convertColumn(prop, depth)], ['person', (c, _elem, prop, id) => c.convertPerson(prop, id)], ['person_v1', (c, _elem, prop, id) => c.convertPersonV1(prop, id)], ['person_list', (c, _elem, prop) => c.convertPersonList(prop)], ['avatar', (c, _elem, prop, id) => c.convertAvatar(prop, id)], ['at', (c, _elem, prop) => c.convertAt(prop)], ['at_all', () => '@所有人'], ['button', (c, _elem, prop, id) => c.convertButton(prop, id)], ['actions', (c, _elem, prop) => c.convertActions(prop)], ['action', (c, _elem, prop) => c.convertActions(prop)], ['overflow', (c, _elem, prop) => c.convertOverflow(prop)], ['select_static', (c, _elem, prop, id) => c.convertSelect(prop, id, false)], ['multi_select_static', (c, _elem, prop, id) => c.convertSelect(prop, id, true)], ['select_person', (c, _elem, prop, id) => c.convertSelect(prop, id, false)], ['multi_select_person', (c, _elem, prop, id) => c.convertSelect(prop, id, true)], ['select_img', (c, _elem, prop, id) => c.convertSelectImg(prop, id)], ['input', (c, _elem, prop, id) => c.convertInput(prop, id)], ['date_picker', (c, _elem, prop, id) => c.convertDatePicker(prop, id, 'date')], ['picker_time', (c, _elem, prop, id) => c.convertDatePicker(prop, id, 'time')], ['picker_datetime', (c, _elem, prop, id) => c.convertDatePicker(prop, id, 'datetime')], ['checker', (c, _elem, prop, id) => c.convertChecker(prop, id)], ['img', (c, _elem, prop, id) => c.convertImage(prop, id)], ['image', (c, _elem, prop, id) => c.convertImage(prop, id)], ['img_combination', (c, _elem, prop) => c.convertImgCombination(prop)], ['table', (c, _elem, prop) => c.convertTable(prop)], ['chart', (c, _elem, prop, id) => c.convertChart(prop, id)], ['audio', (c, _elem, prop, id) => c.convertAudio(prop, id)], ['video', (c, _elem, prop, id) => c.convertVideo(prop, id)], ['collapsible_panel', (c, _elem, prop, id) => c.convertCollapsiblePanel(prop, id)], ['form', (c, _elem, prop, id) => c.convertForm(prop, id)], ['interactive_container', (c, _elem, prop, id) => c.convertInteractiveContainer(prop, id)], ['text_tag', (c, _elem, prop) => c.convertTextTag(prop)], ['number_tag', (c, _elem, prop) => c.convertNumberTag(prop)], ['link', (c, _elem, prop) => c.convertLink(prop)], ['emoji', (c, _elem, prop) => c.convertEmoji(prop)], ['local_datetime', (c, _elem, prop) => c.convertLocalDatetime(prop)], ['list', (c, _elem, prop) => c.convertList(prop)], ['blockquote', (c, _elem, prop) => c.convertBlockquote(prop)], ['code_block', (c, _elem, prop) => c.convertCodeBlock(prop)], ['code_span', (c, _elem, prop) => c.convertCodeSpan(prop)], ['heading', (c, _elem, prop) => c.convertHeading(prop)], ['fallback_text', (c, _elem, prop) => c.convertFallbackText(prop)], ['repeat', (c, _elem, prop) => c.convertRepeat(prop)], ['card_header', () => ''], ['custom_icon', () => ''], ['standard_icon', () => ''], ]); class CardConverter { mode; attachment; constructor(mode) { this.mode = mode; } convert(input) { const card = (0, utils_1.safeParse)(input.json_card); if (!card) { return { content: '\n[无法解析卡片内容]\n', schema: 0 }; } if (input.json_attachment) { this.attachment = (0, utils_1.safeParse)(input.json_attachment); } let schema = input.card_schema ?? 0; if (schema === 0) { const s = card.schema; schema = typeof s === 'number' ? s : 1; } const header = card.header; const title = header ? this.extractHeaderTitle(header, schema) : ''; const body = this.extractBody(card, schema); const bodyContent = body ? this.convertBody(body, schema) : ''; let out = title ? `\n` : '\n'; if (bodyContent) out += bodyContent + '\n'; out += ''; return { content: out, schema }; } extractBody(card, _schema) { if (card.body && typeof card.body === 'object') { return card.body; } return undefined; } extractHeaderTitle(header, _schema) { const prop = header.property; if (prop) { const titleElem = prop.title; if (titleElem) return this.extractTextContent(titleElem); } else { const titleElem = header.title; if (titleElem) return this.extractTextContent(titleElem); } return ''; } convertBody(body, _schema) { let elements; const prop = body.property; if (prop) { const e = prop.elements; if (Array.isArray(e) && e.length > 0) elements = e; } if (!elements || elements.length === 0) { const e = body.elements; if (Array.isArray(e)) elements = e; } if (!elements || elements.length === 0) return ''; return this.convertElements(elements, 0); } convertElements(elements, depth) { const results = []; for (const elem of elements) { if (typeof elem !== 'object' || elem == null) continue; const result = this.convertElement(elem, depth); if (result) results.push(result); } return results.join('\n'); } convertElement(elem, depth) { const tag = elem.tag ?? ''; const id = elem.id ?? ''; const prop = this.extractProperty(elem); const fn = elementConverters.get(tag); if (fn) return fn(this, elem, prop, id, depth); return this.convertUnknown(prop, tag); } extractProperty(elem) { if (elem.property && typeof elem.property === 'object') { return elem.property; } return elem; } extractTextContent(textElem) { if (textElem == null) return ''; if (typeof textElem === 'string') return textElem; if (typeof textElem === 'object') { const m = textElem; if (m.property && typeof m.property === 'object') { return this.extractTextFromProperty(m.property); } return this.extractTextFromProperty(m); } return ''; } extractTextFromProperty(prop) { const i18n = prop.i18nContent; if (i18n && typeof i18n === 'object') { for (const lang of ['zh_cn', 'en_us', 'ja_jp']) { const t = i18n[lang]; if (typeof t === 'string' && t) return t; } } if (typeof prop.content === 'string') return prop.content; const elements = prop.elements; if (Array.isArray(elements) && elements.length > 0) { const texts = []; for (const elem of elements) { if (typeof elem === 'object' && elem != null) { const t = this.extractTextContent(elem); if (t) texts.push(t); } } return texts.join(''); } if (typeof prop.text === 'string') return prop.text; return ''; } convertPlainText(prop) { const content = prop.content; if (!content) return ''; const style = this.extractTextStyle(prop); return this.applyTextStyle(content, style); } convertMarkdown(prop) { const elements = prop.elements; if (Array.isArray(elements) && elements.length > 0) { return this.convertMarkdownElements(elements); } if (typeof prop.content === 'string') return prop.content; return ''; } convertMarkdownV1(elem, prop) { const elements = prop.elements; if (Array.isArray(elements) && elements.length > 0) { return this.convertMarkdownElements(elements); } const fallback = elem.fallback; if (fallback && typeof fallback === 'object') { return this.convertElement(fallback, 0); } if (typeof prop.content === 'string') return prop.content; return ''; } convertMarkdownElements(elements) { const parts = []; for (const elem of elements) { if (typeof elem !== 'object' || elem == null) continue; const result = this.convertElement(elem, 0); if (result) parts.push(result); } return parts.join(''); } convertDiv(prop, _id) { const results = []; const textElem = prop.text; if (textElem && typeof textElem === 'object') { const text = this.convertElement(textElem, 0); if (text) results.push(text); } const fields = prop.fields; if (Array.isArray(fields) && fields.length > 0) { const fieldTexts = []; for (const field of fields) { if (typeof field !== 'object' || field == null) continue; const fm = field; const te = fm.text; if (te && typeof te === 'object') { const ft = this.convertElement(te, 0); if (ft) fieldTexts.push(ft); } } if (fieldTexts.length > 0) results.push(fieldTexts.join('\n')); } const extraElem = prop.extra; if (extraElem && typeof extraElem === 'object') { const extra = this.convertElement(extraElem, 0); if (extra) results.push(extra); } return results.join('\n'); } convertNote(prop) { const elements = prop.elements; if (!Array.isArray(elements) || elements.length === 0) return ''; const texts = []; for (const elem of elements) { if (typeof elem !== 'object' || elem == null) continue; const text = this.convertElement(elem, 0); if (text) texts.push(text); } if (texts.length === 0) return ''; return `📝 ${texts.join(' ')}`; } convertLink(prop) { const content = prop.content || '链接'; let url = ''; const urlObj = prop.url; if (urlObj && typeof urlObj === 'object') { url = urlObj.url || ''; } if (url) return `[${content}](${url})`; return content; } convertEmoji(prop) { const key = prop.key || ''; return types_1.EMOJI_MAP[key] ?? `:${key}:`; } convertLocalDatetime(prop) { const milliseconds = prop.milliseconds; const fallbackText = prop.fallbackText; if (milliseconds) { const formatted = (0, card_utils_1.formatMillisecondsToISO8601)(milliseconds); if (formatted) return formatted; } return fallbackText || ''; } convertList(prop) { const items = prop.items; if (!Array.isArray(items) || items.length === 0) return ''; const lines = []; for (const item of items) { if (typeof item !== 'object' || item == null) continue; const im = item; const level = im.level || 0; const listType = im.type || ''; const order = im.order || 0; const indent = ' '.repeat(level); const marker = listType === 'ol' ? `${Math.floor(order)}.` : '-'; const elements = im.elements; if (Array.isArray(elements)) { const content = this.convertMarkdownElements(elements); lines.push(`${indent}${marker} ${content}`); } } return lines.join('\n'); } convertBlockquote(prop) { let content = ''; if (typeof prop.content === 'string') { content = prop.content; } else { const elements = prop.elements; if (Array.isArray(elements)) { content = this.convertMarkdownElements(elements); } } if (!content) return ''; return content .split('\n') .map((line) => `> ${line}`) .join('\n'); } convertCodeBlock(prop) { const language = prop.language || 'plaintext'; let code = ''; const contents = prop.contents; if (Array.isArray(contents)) { for (const line of contents) { if (typeof line !== 'object' || line == null) continue; const lm = line; const lineContents = lm.contents; if (Array.isArray(lineContents)) { for (const c of lineContents) { if (typeof c !== 'object' || c == null) continue; const cm = c; if (typeof cm.content === 'string') code += cm.content; } } } } return `\`\`\`${language}\n${code}\`\`\``; } convertCodeSpan(prop) { const content = prop.content || ''; return `\`${content}\``; } convertHeading(prop) { let level = prop.level || 1; if (level < 1) level = 1; if (level > 6) level = 6; let content = ''; if (typeof prop.content === 'string') { content = prop.content; } else { const elements = prop.elements; if (Array.isArray(elements)) { content = this.convertMarkdownElements(elements); } } return `${'#'.repeat(level)} ${content}`; } convertFallbackText(prop) { const textElem = prop.text; if (textElem && typeof textElem === 'object') { return this.extractTextContent(textElem); } const elements = prop.elements; if (Array.isArray(elements)) { return this.convertMarkdownElements(elements); } return ''; } convertTextTag(prop) { const textElem = prop.text; let text = ''; if (textElem && typeof textElem === 'object') { text = this.extractTextContent(textElem); } if (!text) return ''; return `「${text}」`; } convertNumberTag(prop) { const textElem = prop.text; let text = ''; if (textElem && typeof textElem === 'object') { text = this.extractTextContent(textElem); } if (!text) return ''; const urlObj = prop.url; if (urlObj && typeof urlObj === 'object') { const url = urlObj.url; if (url) return `[${text}](${url})`; } return text; } convertUnknown(prop, tag) { if (!prop) { if (this.mode === exports.MODE.Detailed) return `[未知内容](tag:${tag})`; return '[未知内容]'; } const paths = ['content', 'text', 'title', 'label', 'placeholder']; for (const path of paths) { if (prop[path] != null) { const text = this.extractTextContent(prop[path]); if (text) return text; } } const elements = prop.elements; if (Array.isArray(elements) && elements.length > 0) { return this.convertElements(elements, 0); } if (this.mode === exports.MODE.Detailed) return `[未知内容](tag:${tag})`; return '[未知内容]'; } convertColumnSet(prop, depth) { const columns = prop.columns; if (!Array.isArray(columns) || columns.length === 0) return ''; const results = []; for (const col of columns) { if (typeof col !== 'object' || col == null) continue; const result = this.convertElement(col, depth + 1); if (result) results.push(result); } return results.join('\n\n'); } convertColumn(prop, depth) { const elements = prop.elements; if (!Array.isArray(elements) || elements.length === 0) return ''; return this.convertElements(elements, depth); } convertForm(prop, _id) { let out = '
\n'; const elements = prop.elements; if (Array.isArray(elements)) { out += this.convertElements(elements, 0); } out += '\n
'; return out; } convertCollapsiblePanel(prop, _id) { const expanded = prop.expanded === true; let title = '详情'; const header = prop.header; if (header && typeof header === 'object') { const titleElem = header.title; if (titleElem) { const t = this.extractTextContent(titleElem); if (t) title = t; } } const shouldExpand = expanded || this.mode === exports.MODE.Detailed; if (shouldExpand) { let out = `▼ ${title}\n`; const elements = prop.elements; if (Array.isArray(elements)) { const content = this.convertElements(elements, 1); for (const line of content.split('\n')) { if (line) out += ` ${line}\n`; } } out += '▲'; return out; } return `▶ ${title}`; } convertInteractiveContainer(prop, _id) { let url = ''; const actions = prop.actions; if (Array.isArray(actions) && actions.length > 0) { const action = actions[0]; if (action && typeof action === 'object') { const actionType = action.type; if (actionType === 'open_url') { const actionData = action.action; if (actionData && typeof actionData === 'object') { url = actionData.url || ''; } } } } let out = '= 0 && initialIndex < options.length) { const opt = options[initialIndex]; if (opt && typeof opt === 'object') { const val = opt.value; if (val) selectedValues.add(val); } } } const optionTexts = []; let hasSelected = false; for (const opt of options) { if (typeof opt !== 'object' || opt == null) continue; const om = opt; let optText = ''; const textElem = om.text; if (textElem && typeof textElem === 'object') { optText = this.extractTextContent(textElem); } if (!optText) optText = om.value || ''; if (!optText) continue; const value = om.value || ''; if (selectedValues.has(value)) { optText = '✓' + optText; hasSelected = true; } optionTexts.push(optText); } if (optionTexts.length === 0) { let placeholder = '请选择'; const phElem = prop.placeholder; if (phElem && typeof phElem === 'object') { const ph = this.extractTextContent(phElem); if (ph) placeholder = ph; } optionTexts.push(placeholder + ' ▼'); } else if (!hasSelected) { optionTexts[optionTexts.length - 1] += ' ▼'; } let result = `{${optionTexts.join(' / ')}}`; if (this.mode === exports.MODE.Detailed) { const attrs = []; if (isMulti) attrs.push('multi'); if (_id.includes('person') || prop.type === 'person') attrs.push('type:person'); if (attrs.length > 0) result += `(${attrs.join(' ')})`; } return result; } convertSelectImg(prop, _id) { const options = prop.options; if (!Array.isArray(options)) return ''; const selectedValues = new Set(); const vals = prop.selectedValues; if (Array.isArray(vals)) { for (const v of vals) { if (typeof v === 'string') selectedValues.add(v); } } const optTexts = []; for (let i = 0; i < options.length; i++) { const opt = options[i]; if (!opt || typeof opt !== 'object') continue; const value = opt.value || ''; let text = `🖼️图${i + 1}`; if (selectedValues.has(value)) text = '✓' + text; optTexts.push(text); } return `{${optTexts.join(' / ')}}`; } convertInput(prop, _id) { let label = ''; const labelElem = prop.label; if (labelElem && typeof labelElem === 'object') { label = this.extractTextContent(labelElem); } const defaultValue = prop.defaultValue || ''; let placeholder = ''; const phElem = prop.placeholder; if (phElem && typeof phElem === 'object') { placeholder = this.extractTextContent(phElem); } let result; if (defaultValue) { result = defaultValue + '___'; } else if (placeholder) { result = placeholder + '_____'; } else { result = '_____'; } if (label) result = label + ': ' + result; const inputType = prop.inputType; if (inputType === 'multiline_text') { result = result.replace(/_____/g, '...'); } return result; } convertDatePicker(prop, _id, pickerType) { let emoji; let value = ''; switch (pickerType) { case 'date': emoji = '📅'; value = prop.initialDate || ''; break; case 'time': emoji = '🕐'; value = prop.initialTime || ''; break; case 'datetime': emoji = '📅'; value = prop.initialDatetime || ''; break; default: emoji = '📅'; } if (value) value = (0, card_utils_1.normalizeTimeFormat)(value); if (!value) { let placeholder = '选择'; const phElem = prop.placeholder; if (phElem && typeof phElem === 'object') { const ph = this.extractTextContent(phElem); if (ph) placeholder = ph; } value = placeholder; } return `${emoji} ${value}`; } convertChecker(prop, _id) { const checked = prop.checked === true; const checkMark = checked ? '[x]' : '[ ]'; let text = ''; const textElem = prop.text; if (textElem && typeof textElem === 'object') { text = this.extractTextContent(textElem); } let result = `${checkMark} ${text}`; if (this.mode === exports.MODE.Detailed && _id) { result += `(id:${_id})`; } return result; } convertOverflow(prop) { const options = prop.options; if (!Array.isArray(options) || options.length === 0) return ''; const optTexts = []; for (const opt of options) { if (typeof opt !== 'object' || opt == null) continue; const om = opt; const textElem = om.text; if (textElem && typeof textElem === 'object') { const text = this.extractTextContent(textElem); if (text) optTexts.push(text); } } return `⋮ ${optTexts.join(', ')}`; } convertPerson(prop, _id) { const userID = prop.userID || ''; if (!userID) return ''; let personName = ''; if (this.attachment) { const persons = this.attachment.persons; if (persons && typeof persons === 'object') { const person = persons[userID]; if (person && typeof person === 'object') { const content = person.content; if (content) personName = content; } } } if (!personName) { const notation = prop.notation; if (notation && typeof notation === 'object') { personName = this.extractTextContent(notation); } } if (personName) { if (this.mode === exports.MODE.Detailed) return `@${personName}(open_id:${userID})`; return `@${personName}`; } if (this.mode === exports.MODE.Detailed) return `@用户(open_id:${userID})`; return `@${userID}`; } convertPersonV1(prop, _id) { const userID = prop.userID || ''; if (!userID) return ''; let personName = ''; if (this.attachment) { const persons = this.attachment.persons; if (persons && typeof persons === 'object') { const person = persons[userID]; if (person && typeof person === 'object') { const content = person.content; if (content) personName = content; } } } if (personName) { if (this.mode === exports.MODE.Detailed) return `@${personName}(open_id:${userID})`; return `@${personName}`; } if (this.mode === exports.MODE.Detailed) return `@用户(open_id:${userID})`; return `@${userID}`; } convertPersonList(prop) { const persons = prop.persons; if (!Array.isArray(persons) || persons.length === 0) return ''; const names = []; for (const person of persons) { if (typeof person !== 'object' || person == null) continue; const pm = person; const personID = pm.id || ''; const name = '用户'; if (this.mode === exports.MODE.Detailed && personID) { names.push(`@${name}(id:${personID})`); } else { names.push(`@${name}`); } } return names.join(', '); } convertAvatar(prop, _id) { const userID = prop.userID || ''; let result = '👤'; if (this.mode === exports.MODE.Detailed && userID) { result += `(id:${userID})`; } return result; } convertAt(prop) { const userID = prop.userID || ''; if (!userID) return ''; let userName = ''; let actualUserID = ''; if (this.attachment) { const atUsers = this.attachment.at_users; if (atUsers && typeof atUsers === 'object') { const userInfo = atUsers[userID]; if (userInfo && typeof userInfo === 'object') { const content = userInfo.content; if (content) userName = content; const uid = userInfo.user_id; if (uid) actualUserID = uid; } } } if (userName) { if (this.mode === exports.MODE.Detailed) { if (actualUserID) return `@${userName}(user_id:${actualUserID})`; return `@${userName}(open_id:${userID})`; } return `@${userName}`; } if (this.mode === exports.MODE.Detailed) { if (actualUserID) return `@用户(user_id:${actualUserID})`; return `@用户(open_id:${userID})`; } return `@${userID}`; } convertImage(prop, _id) { let alt = '图片'; const altElem = prop.alt; if (altElem && typeof altElem === 'object') { const altText = this.extractTextContent(altElem); if (altText) alt = altText; } const titleElem = prop.title; if (titleElem && typeof titleElem === 'object') { const titleText = this.extractTextContent(titleElem); if (titleText) alt = titleText; } let result = `🖼️ ${alt}`; if (this.mode === exports.MODE.Detailed) { const imageID = prop.imageID; if (imageID) { const token = this.getImageToken(imageID); if (token) { result += `(img_token:${token})`; } else { result += `(img_key:${imageID})`; } } } return result; } convertImgCombination(prop) { const imgList = prop.imgList; if (!Array.isArray(imgList) || imgList.length === 0) return ''; let result = `🖼️ ${imgList.length}张图片`; if (this.mode === exports.MODE.Detailed) { const keys = []; for (const img of imgList) { if (typeof img !== 'object' || img == null) continue; const im = img; const imageID = im.imageID; if (imageID) keys.push(imageID); } if (keys.length > 0) result += `(keys:${keys.join(',')})`; } return result; } convertChart(prop, _id) { let title = '图表'; let chartType = ''; const chartSpec = prop.chartSpec; if (chartSpec && typeof chartSpec === 'object') { const titleObj = chartSpec.title; if (titleObj && typeof titleObj === 'object') { const text = titleObj.text; if (text) title = text; } const ct = chartSpec.type; if (ct) { chartType = ct; const typeName = types_1.CHART_TYPE_NAMES[chartType]; if (typeName) title = `${title}${typeName}`; } } const summary = this.extractChartSummary(prop, chartType); let result = `📊 ${title}`; if (summary) result += `\n数据摘要: ${summary}`; return result; } extractChartSummary(prop, chartType) { const chartSpec = prop.chartSpec; if (!chartSpec || typeof chartSpec !== 'object') return ''; const dataObj = chartSpec.data; if (!dataObj || typeof dataObj !== 'object') return ''; const values = dataObj.values; if (!Array.isArray(values) || values.length === 0) return ''; switch (chartType) { case 'line': case 'bar': case 'area': return this.extractLineBarSummary(chartSpec, values); case 'pie': return this.extractPieSummary(chartSpec, values); default: return this.extractGenericSummary(values); } } extractLineBarSummary(chartSpec, values) { const xField = chartSpec.xField; const yField = chartSpec.yField; if (!xField || !yField || values.length === 0) { return this.extractGenericSummary(values); } const parts = []; for (const v of values) { if (typeof v !== 'object' || v == null) continue; const vm = v; parts.push(`${vm[xField]}:${vm[yField]}`); } return parts.length > 0 ? parts.join(', ') : this.extractGenericSummary(values); } extractPieSummary(chartSpec, values) { const categoryField = chartSpec.categoryField; const valueField = chartSpec.valueField; if (!categoryField || !valueField || values.length === 0) { return this.extractGenericSummary(values); } const parts = []; for (const v of values) { if (typeof v !== 'object' || v == null) continue; const vm = v; parts.push(`${vm[categoryField]}:${vm[valueField]}`); } return parts.length > 0 ? parts.join(', ') : this.extractGenericSummary(values); } extractGenericSummary(values) { return `${values.length}个数据点`; } convertAudio(prop, _id) { let result = '🎵 音频'; if (this.mode === exports.MODE.Detailed) { const fileID = prop.fileID || prop.audioID || ''; if (fileID) result += `(key:${fileID})`; } return result; } convertVideo(prop, _id) { let result = '🎬 视频'; if (this.mode === exports.MODE.Detailed) { const fileID = prop.fileID || prop.videoID || ''; if (fileID) result += `(key:${fileID})`; } return result; } convertTable(prop) { const columns = prop.columns; if (!Array.isArray(columns) || columns.length === 0) return ''; const rows = prop.rows || []; const colNames = []; const colKeys = []; for (const col of columns) { if (typeof col !== 'object' || col == null) continue; const cm = col; let displayName = cm.displayName || ''; const name = cm.name || ''; if (!displayName) displayName = name; colNames.push(displayName); colKeys.push(name); } const lines = []; lines.push('| ' + colNames.join(' | ') + ' |'); lines.push('|' + colNames.map(() => '------|').join('')); for (const row of rows) { if (typeof row !== 'object' || row == null) continue; const rm = row; const cells = []; for (const key of colKeys) { let cellValue = ''; const cellData = rm[key]; if (cellData && typeof cellData === 'object') { if (cellData.data != null) { cellValue = this.extractTableCellValue(cellData.data); } } cells.push(cellValue); } lines.push('| ' + cells.join(' | ') + ' |'); } return lines.join('\n'); } extractTableCellValue(data) { if (typeof data === 'string') return data; if (typeof data === 'number') return data.toFixed(2); if (Array.isArray(data)) { const texts = []; for (const item of data) { if (typeof item === 'object' && item != null) { const im = item; if (typeof im.text === 'string') texts.push(`「${im.text}」`); } } return texts.join(' '); } if (typeof data === 'object' && data != null) { return this.extractTextContent(data); } return ''; } extractTextStyle(prop) { const style = { bold: false, italic: false, strikethrough: false, }; const textStyle = prop.textStyle; if (!textStyle || typeof textStyle !== 'object') return style; const attrs = textStyle.attributes; if (Array.isArray(attrs)) { for (const attr of attrs) { if (typeof attr !== 'string') continue; switch (attr) { case 'bold': style.bold = true; break; case 'italic': style.italic = true; break; case 'strikethrough': style.strikethrough = true; break; } } } return style; } applyTextStyle(content, style) { if (!content) return content; if (style.strikethrough) content = `~~${content}~~`; if (style.italic) content = `*${content}*`; if (style.bold) content = `**${content}**`; return content; } getImageToken(imageID) { if (!this.attachment) return ''; const images = this.attachment.images; if (!images || typeof images !== 'object') return ''; const imageInfo = images[imageID]; if (!imageInfo || typeof imageInfo !== 'object') return ''; return imageInfo.token || ''; } } exports.CardConverter = CardConverter;