tab2.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/usr/bin/env python3
  2. """
  3. Tab2内容生成器 - L3单元解构
  4. 包含:单元列表,每个单元包含单元编号、时间范围、单元核心概括、完整文案、实质
  5. """
  6. import html as html_module
  7. from typing import Dict, Any, List
  8. def render_unit_card(unit: Dict[str, Any], idx: int) -> str:
  9. """渲染单元卡片"""
  10. unit_num = unit.get("单元编号", idx)
  11. time_range = unit.get("时间范围", "")
  12. core_summary = unit.get("单元核心概括", "")
  13. full_text = unit.get("完整文案", "")
  14. substance = unit.get("实质", {})
  15. card_id = f'unit-{unit_num}'
  16. html = f'<div class="point-card unit-card" data-card-id="{card_id}">\n'
  17. html += f'<div class="point-card-header" onclick="toggleCardDetails(\'{card_id}\')">\n'
  18. html += f'<span class="point-number">单元 #{unit_num}</span>\n'
  19. if time_range:
  20. html += f'<span class="point-time">{html_module.escape(time_range)}</span>\n'
  21. if core_summary:
  22. html += f'<span class="point-text">{html_module.escape(core_summary)}</span>\n'
  23. html += '<span class="toggle-icon">▼</span>\n'
  24. html += '</div>\n'
  25. html += f'<div class="point-card-details" id="{card_id}-details">\n'
  26. # 完整文案
  27. if full_text:
  28. html += '<div class="detail-section">\n'
  29. html += '<strong>完整文案:</strong>\n'
  30. html += f'<div class="detail-text">{html_module.escape(full_text)}</div>\n'
  31. html += '</div>\n'
  32. # 实质内容
  33. if substance:
  34. # 具体元素
  35. concrete_elements = substance.get("具体元素", {})
  36. if concrete_elements:
  37. html += '<div class="detail-section">\n'
  38. html += '<strong>具体元素:</strong>\n'
  39. keywords = concrete_elements.get("关键词", [])
  40. if keywords:
  41. html += '<div class="sub-section">\n'
  42. html += '<strong>关键词:</strong>\n'
  43. html += '<div class="tag-group">\n'
  44. for keyword in keywords:
  45. html += f'<span class="keyword-tag">{html_module.escape(str(keyword))}</span>\n'
  46. html += '</div>\n'
  47. html += '</div>\n'
  48. forms = concrete_elements.get("对应形式", {})
  49. if forms:
  50. html += '<div class="sub-section">\n'
  51. html += '<strong>对应形式:</strong>\n'
  52. if forms.get("文案形式"):
  53. html += f'<div class="form-item"><strong>文案形式:</strong>{html_module.escape(forms["文案形式"])}</div>\n'
  54. if forms.get("画面形式"):
  55. html += f'<div class="form-item"><strong>画面形式:</strong>{html_module.escape(forms["画面形式"])}</div>\n'
  56. if forms.get("声音形式"):
  57. html += f'<div class="form-item"><strong>声音形式:</strong>{html_module.escape(forms["声音形式"])}</div>\n'
  58. html += '</div>\n'
  59. html += '</div>\n'
  60. # 具象概念
  61. concrete_concepts = substance.get("具象概念", {})
  62. if concrete_concepts:
  63. html += '<div class="detail-section">\n'
  64. html += '<strong>具象概念:</strong>\n'
  65. keywords = concrete_concepts.get("关键词", [])
  66. if keywords:
  67. html += '<div class="sub-section">\n'
  68. html += '<strong>关键词:</strong>\n'
  69. html += '<div class="tag-group">\n'
  70. for keyword in keywords:
  71. html += f'<span class="keyword-tag">{html_module.escape(str(keyword))}</span>\n'
  72. html += '</div>\n'
  73. html += '</div>\n'
  74. forms = concrete_concepts.get("对应形式", {})
  75. if forms:
  76. html += '<div class="sub-section">\n'
  77. html += '<strong>对应形式:</strong>\n'
  78. if forms.get("文案形式"):
  79. html += f'<div class="form-item"><strong>文案形式:</strong>{html_module.escape(forms["文案形式"])}</div>\n'
  80. if forms.get("画面形式"):
  81. html += f'<div class="form-item"><strong>画面形式:</strong>{html_module.escape(forms["画面形式"])}</div>\n'
  82. if forms.get("声音形式"):
  83. html += f'<div class="form-item"><strong>声音形式:</strong>{html_module.escape(forms["声音形式"])}</div>\n'
  84. html += '</div>\n'
  85. html += '</div>\n'
  86. # 抽象概念
  87. abstract_concepts = substance.get("抽象概念", {})
  88. if abstract_concepts:
  89. html += '<div class="detail-section">\n'
  90. html += '<strong>抽象概念:</strong>\n'
  91. keywords = abstract_concepts.get("关键词", [])
  92. if keywords:
  93. html += '<div class="sub-section">\n'
  94. html += '<strong>关键词:</strong>\n'
  95. html += '<div class="tag-group">\n'
  96. for keyword in keywords:
  97. html += f'<span class="keyword-tag">{html_module.escape(str(keyword))}</span>\n'
  98. html += '</div>\n'
  99. html += '</div>\n'
  100. forms = abstract_concepts.get("对应形式", {})
  101. if forms:
  102. html += '<div class="sub-section">\n'
  103. html += '<strong>对应形式:</strong>\n'
  104. if forms.get("文案形式"):
  105. html += f'<div class="form-item"><strong>文案形式:</strong>{html_module.escape(forms["文案形式"])}</div>\n'
  106. if forms.get("画面形式"):
  107. html += f'<div class="form-item"><strong>画面形式:</strong>{html_module.escape(forms["画面形式"])}</div>\n'
  108. if forms.get("声音形式"):
  109. html += f'<div class="form-item"><strong>声音形式:</strong>{html_module.escape(forms["声音形式"])}</div>\n'
  110. html += '</div>\n'
  111. html += '</div>\n'
  112. html += '</div>\n'
  113. html += '</div>\n'
  114. return html
  115. def generate_tab2_content(data: Dict[str, Any]) -> str:
  116. """生成Tab2内容:L3单元解构"""
  117. html = '<div class="tab-content" id="tab2" style="display: none;">\n'
  118. html += '<div class="section">\n'
  119. html += '<h3>L3单元解构</h3>\n'
  120. l3_deconstruction = data.get("L3单元解构", {})
  121. unit_list = l3_deconstruction.get("单元列表", [])
  122. if not unit_list:
  123. html += '<p>暂无数据</p>\n'
  124. else:
  125. html += f'<div class="section-info">共 {len(unit_list)} 个单元</div>\n'
  126. for idx, unit in enumerate(unit_list, start=1):
  127. html += render_unit_card(unit, idx)
  128. html += '</div>\n'
  129. html += '</div>\n'
  130. return html