write_report.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. """
  2. 报告编写工具 - 创建日报/周报/月报
  3. 支持交互式输入,保存为Markdown格式
  4. """
  5. import sys
  6. import os
  7. from pathlib import Path
  8. from datetime import datetime
  9. # 设置控制台编码为UTF-8(Windows)
  10. if sys.platform == 'win32':
  11. import io
  12. sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
  13. sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
  14. def get_week_number(date=None):
  15. """获取ISO周数"""
  16. if date is None:
  17. date = datetime.now()
  18. year, week, _ = date.isocalendar()
  19. return f"{year}-W{week:02d}"
  20. def get_current_date_id(report_type):
  21. """获取当前日期标识"""
  22. now = datetime.now()
  23. if report_type == "daily":
  24. return now.strftime("%Y-%m-%d")
  25. elif report_type == "weekly":
  26. return get_week_number(now)
  27. elif report_type == "monthly":
  28. return now.strftime("%Y-%m")
  29. else:
  30. return now.strftime("%Y-%m-%d")
  31. def get_report_dir(base_dir, report_type):
  32. """获取报告目录路径"""
  33. report_dir = base_dir / "archive" / "reports" / report_type
  34. report_dir.mkdir(parents=True, exist_ok=True)
  35. return report_dir
  36. def input_multiline(prompt="请输入报告内容(输入空行后按Enter结束):\n"):
  37. """多行输入,以空行结束"""
  38. print(prompt)
  39. lines = []
  40. empty_line_count = 0
  41. while True:
  42. try:
  43. line = input()
  44. if line.strip() == "":
  45. empty_line_count += 1
  46. if empty_line_count >= 1: # 一个空行就结束
  47. break
  48. else:
  49. empty_line_count = 0
  50. lines.append(line)
  51. except EOFError:
  52. break
  53. except KeyboardInterrupt:
  54. print("\n\n⚠️ 输入已取消")
  55. return None
  56. return "\n".join(lines) if lines else None
  57. def save_report(report_dir, date_id, content, report_type):
  58. """保存报告到文件"""
  59. file_path = report_dir / f"{date_id}.md"
  60. # 如果文件已存在,询问是否覆盖
  61. if file_path.exists():
  62. response = input(f"⚠️ 文件 {file_path.name} 已存在,是否覆盖?(y/n): ").strip().lower()
  63. if response not in ['y', 'yes', '是']:
  64. print("❌ 已取消保存")
  65. return False
  66. try:
  67. with open(file_path, 'w', encoding='utf-8') as f:
  68. f.write(content)
  69. print(f"✅ 报告已保存到: {file_path}")
  70. return True
  71. except Exception as e:
  72. print(f"❌ 保存失败: {e}")
  73. return False
  74. def create_report(report_type, base_dir):
  75. """创建报告"""
  76. print("=" * 70)
  77. print(f"创建{report_type}报告")
  78. print("=" * 70)
  79. # 获取日期标识
  80. date_id = get_current_date_id(report_type)
  81. print(f"日期标识: {date_id}")
  82. # 获取报告目录
  83. report_dir = get_report_dir(base_dir, report_type)
  84. # 检查是否已存在
  85. existing_file = report_dir / f"{date_id}.md"
  86. if existing_file.exists():
  87. print(f"📄 发现已有报告: {existing_file.name}")
  88. view = input("是否查看现有内容?(y/n): ").strip().lower()
  89. if view in ['y', 'yes', '是']:
  90. try:
  91. with open(existing_file, 'r', encoding='utf-8') as f:
  92. print("\n" + "=" * 70)
  93. print("现有内容:")
  94. print("=" * 70)
  95. print(f.read())
  96. print("=" * 70)
  97. except Exception as e:
  98. print(f"⚠️ 读取失败: {e}")
  99. edit = input("\n是否编辑/覆盖?(y/n): ").strip().lower()
  100. if edit not in ['y', 'yes', '是']:
  101. print("❌ 已取消")
  102. return
  103. # 输入报告内容
  104. print(f"\n请开始输入{report_type}报告内容...")
  105. print("提示:输入空行后按Enter结束输入")
  106. content = input_multiline()
  107. if content is None or content.strip() == "":
  108. print("❌ 内容为空,已取消保存")
  109. return
  110. # 添加日期标记(可选)
  111. header = f"# {report_type}报告 - {date_id}\n\n"
  112. full_content = header + content
  113. # 保存文件
  114. save_report(report_dir, date_id, full_content, report_type)
  115. def list_reports(base_dir, report_type):
  116. """列出已有报告"""
  117. report_dir = get_report_dir(base_dir, report_type)
  118. if not report_dir.exists():
  119. print(f"📁 目录不存在: {report_dir}")
  120. return
  121. reports = sorted(report_dir.glob("*.md"))
  122. if not reports:
  123. print(f"📁 暂无{report_type}报告")
  124. return
  125. print(f"\n📋 {report_type}报告列表 ({len(reports)}个):")
  126. print("-" * 70)
  127. for report in reports:
  128. size = report.stat().st_size
  129. mtime = datetime.fromtimestamp(report.stat().st_mtime).strftime("%Y-%m-%d %H:%M")
  130. print(f" {report.name:20s} {size:6d} 字节 {mtime}")
  131. print("-" * 70)
  132. def view_report(base_dir, report_type, date_id=None):
  133. """查看报告内容"""
  134. if date_id is None:
  135. date_id = get_current_date_id(report_type)
  136. report_dir = get_report_dir(base_dir, report_type)
  137. file_path = report_dir / f"{date_id}.md"
  138. if not file_path.exists():
  139. print(f"❌ 报告不存在: {file_path}")
  140. return
  141. try:
  142. with open(file_path, 'r', encoding='utf-8') as f:
  143. content = f.read()
  144. print("\n" + "=" * 70)
  145. print(f"{report_type}报告 - {date_id}")
  146. print("=" * 70)
  147. print(content)
  148. print("=" * 70)
  149. except Exception as e:
  150. print(f"❌ 读取失败: {e}")
  151. def main():
  152. """主函数"""
  153. import sys
  154. base_dir = Path(__file__).parent
  155. # 检查命令行参数,支持直接启动日报模式
  156. if len(sys.argv) > 1 and sys.argv[1] in ['--daily', '--auto-daily']:
  157. create_report("daily", base_dir)
  158. return
  159. print("=" * 70)
  160. print("报告编写工具")
  161. print("=" * 70)
  162. print("\n请选择操作:")
  163. print(" 1. 创建日报")
  164. print(" 2. 创建周报")
  165. print(" 3. 创建月报")
  166. print(" 4. 查看日报列表")
  167. print(" 5. 查看周报列表")
  168. print(" 6. 查看月报列表")
  169. print(" 7. 查看报告内容")
  170. print(" 0. 退出")
  171. while True:
  172. choice = input("\n请选择 (0-7): ").strip()
  173. if choice == "0":
  174. print("👋 再见!")
  175. break
  176. elif choice == "1":
  177. create_report("daily", base_dir)
  178. elif choice == "2":
  179. create_report("weekly", base_dir)
  180. elif choice == "3":
  181. create_report("monthly", base_dir)
  182. elif choice == "4":
  183. list_reports(base_dir, "daily")
  184. elif choice == "5":
  185. list_reports(base_dir, "weekly")
  186. elif choice == "6":
  187. list_reports(base_dir, "monthly")
  188. elif choice == "7":
  189. print("\n请选择报告类型:")
  190. print(" 1. 日报")
  191. print(" 2. 周报")
  192. print(" 3. 月报")
  193. type_choice = input("选择 (1-3): ").strip()
  194. if type_choice == "1":
  195. date_id = input("请输入日期 (YYYY-MM-DD,直接Enter使用今天): ").strip()
  196. view_report(base_dir, "daily", date_id if date_id else None)
  197. elif type_choice == "2":
  198. date_id = input("请输入周标识 (YYYY-Www,直接Enter使用当前周): ").strip()
  199. view_report(base_dir, "weekly", date_id if date_id else None)
  200. elif type_choice == "3":
  201. date_id = input("请输入月份 (YYYY-MM,直接Enter使用当前月): ").strip()
  202. view_report(base_dir, "monthly", date_id if date_id else None)
  203. else:
  204. print("⚠️ 无效选择,请重试")
  205. if __name__ == "__main__":
  206. main()