wiz_monthly_document_report.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import pymysql
  4. import requests
  5. import json
  6. import calendar
  7. from datetime import datetime
  8. # 数据库配置
  9. DB_CONFIG = {
  10. 'host': '192.168.5.23',
  11. 'port': 3316,
  12. 'user': 'kali',
  13. 'password': '123456',
  14. 'database': 'wizksent',
  15. 'charset': 'utf8mb4'
  16. }
  17. # 企业微信机器人webhook地址
  18. # WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=42952463-05dd-4935-a2d1-8304de70f1e8"
  19. # 子兰生活
  20. WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=795d0b1e-20e9-40ab-979c-a5752cd2de678"
  21. def send_wechat_robot_message(content, msg_type="markdown_v2"):
  22. """通过企业微信机器人发送消息"""
  23. if msg_type == "markdown_v2":
  24. payload = {
  25. "msgtype": "markdown_v2",
  26. "markdown_v2": {
  27. "content": content
  28. }
  29. }
  30. elif msg_type == "text":
  31. payload = {
  32. "msgtype": "text",
  33. "text": {
  34. "content": content
  35. }
  36. }
  37. try:
  38. response = requests.post(WEBHOOK_URL, json=payload, timeout=10)
  39. result = response.json()
  40. if result.get('errcode') != 0:
  41. print(f"发送消息失败: {result}")
  42. return False
  43. return True
  44. except Exception as e:
  45. print(f"发送消息异常: {e}")
  46. return False
  47. def get_month_date_range():
  48. """获取当月1号到月底的时间范围"""
  49. today = datetime.now()
  50. first_day = today.replace(day=1)
  51. last_day = today.replace(day=calendar.monthrange(today.year, today.month)[1])
  52. start_date = first_day.strftime('%Y-%m-%d 00:00:00')
  53. end_date = last_day.strftime('%Y-%m-%d 23:59:59')
  54. return start_date, end_date
  55. def get_document_statistics():
  56. """获取文档统计数据"""
  57. start_date, end_date = get_month_date_range()
  58. try:
  59. connection = pymysql.connect(**DB_CONFIG)
  60. with connection.cursor() as cursor:
  61. sql = """
  62. SELECT
  63. wk.KB_NAME as 一级目录,
  64. wt.TAG_NAME as 二级目录,
  65. COUNT(*) as 文档数量,
  66. MIN(d.DT_CREATED) as 最早创建时间,
  67. MAX(d.DT_CREATED) as 最晚创建时间
  68. FROM wizksent.wiz_document d
  69. INNER JOIN wizksent.wiz_document_tag dt
  70. ON d.DOCUMENT_GUID = dt.DOCUMENT_GUID
  71. INNER JOIN wizksent.wiz_tag wt
  72. ON dt.TAG_GUID = wt.TAG_GUID
  73. INNER JOIN wizasent.wiz_kb wk
  74. ON HEX(wt.KB_GUID) = UPPER(REPLACE(wk.KB_GUID, '-', ''))
  75. WHERE wk.KB_NAME IS NOT NULL
  76. AND d.DT_CREATED >= %s
  77. AND d.DT_CREATED <= %s
  78. GROUP BY wk.KB_NAME, wt.TAG_NAME
  79. ORDER BY wk.KB_NAME, wt.TAG_NAME
  80. """
  81. cursor.execute(sql, (start_date, end_date))
  82. results = cursor.fetchall()
  83. return results, start_date, end_date
  84. except pymysql.Error as e:
  85. raise Exception(f"数据库查询失败: {e}")
  86. finally:
  87. if 'connection' in locals() and connection:
  88. connection.close()
  89. def format_markdown_v2_message(data, start_date, end_date):
  90. """格式化企业微信markdown_v2消息 - 使用正确的表格格式"""
  91. current_month = datetime.now().strftime('%Y年%m月')
  92. total_docs = sum(row[2] for row in data) if data else 0
  93. message = f"# 📊 为知笔记文档统计报告 ({current_month})\n\n"
  94. message += f"**统计周期**: {start_date.split(' ')[0]} 至 {end_date.split(' ')[0]}\n\n"
  95. message += f"**文档总数**: {total_docs} 篇\n\n"
  96. if data:
  97. # 按一级目录分组统计
  98. category_stats = {}
  99. for row in data:
  100. kb_name, tag_name, count, min_date, max_date = row
  101. if kb_name not in category_stats:
  102. category_stats[kb_name] = {
  103. 'total': 0,
  104. 'sub_categories': []
  105. }
  106. category_stats[kb_name]['total'] += count
  107. category_stats[kb_name]['sub_categories'].append({
  108. 'name': tag_name,
  109. 'count': count,
  110. 'min_date': min_date,
  111. 'max_date': max_date
  112. })
  113. # 按文档数量排序
  114. sorted_categories = sorted(category_stats.items(), key=lambda x: x[1]['total'], reverse=True)
  115. message += "## 📋 分类统计详情\n\n"
  116. # 使用正确的表格格式
  117. message += "| 集团 | 部门 | 文档数量 | 最早创建 | 最晚创建 |\n"
  118. message += "| :--- | :--- | :---: | :---: | :---: |\n"
  119. for kb_name, stats in sorted_categories:
  120. # 先显示一级目录的汇总行
  121. message += f"| **{kb_name}** | **汇总** | **{stats['total']}** | - | - |\n"
  122. # 显示该一级目录下的所有二级目录
  123. for sub_cat in sorted(stats['sub_categories'], key=lambda x: x['count'], reverse=True):
  124. min_date_str = sub_cat['min_date'].strftime('%m-%d') if sub_cat['min_date'] else '-'
  125. max_date_str = sub_cat['max_date'].strftime('%m-%d') if sub_cat['max_date'] else '-'
  126. message += f"| ↳ | {sub_cat['name']} | {sub_cat['count']} | {min_date_str} | {max_date_str} |\n"
  127. # 添加空行分隔不同的一级目录
  128. message += "| | | | | |\n"
  129. # 添加汇总表格
  130. message += "## 📈 数据汇总\n\n"
  131. message += "| 集团 | 文档数量 | 占比 |\n"
  132. message += "| :--- | :---: | :---: |\n"
  133. for kb_name, stats in sorted_categories:
  134. percentage = f"{(stats['total']/total_docs*100):.1f}%" if total_docs > 0 else "0%"
  135. message += f"| {kb_name} | {stats['total']} | {percentage} |\n"
  136. else:
  137. message += "> 本月暂无文档数据\n"
  138. message += f"\n**统计时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
  139. message += "### 统计范围🕐:\n"
  140. message += "**未分类**📌标签下的笔记不在统计范围内!请将📓笔记移动到相关部门的标签下\n"
  141. return message
  142. def format_simple_markdown_v2_message(data, start_date, end_date):
  143. """简洁版markdown_v2消息"""
  144. current_month = datetime.now().strftime('%Y年%m月')
  145. total_docs = sum(row[2] for row in data) if data else 0
  146. message = f"# 📊 {current_month}文档统计\n\n"
  147. message += f"**统计周期**: {start_date.split(' ')[0]} 至 {end_date.split(' ')[0]}\n"
  148. message += f"**文档总数**: {total_docs}篇\n\n"
  149. if data:
  150. # 按一级目录分组统计
  151. category_totals = {}
  152. for row in data:
  153. kb_name, _, count, _, _ = row
  154. category_totals[kb_name] = category_totals.get(kb_name, 0) + count
  155. message += "## 📋 分类统计\n\n"
  156. for kb_name, count in sorted(category_totals.items(), key=lambda x: x[1], reverse=True):
  157. message += f"**{kb_name}**: {count}篇\n"
  158. # 简单表格
  159. message += "\n## 📊 详细数据\n\n"
  160. message += "| 集团 | 部门 | 数量 |\n"
  161. message += "| :--- | :--- | :---: |\n"
  162. for row in data:
  163. kb_name, tag_name, count, _, _ = row
  164. message += f"| {kb_name} | {tag_name} | {count} |\n"
  165. message += f"\n⏰ {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
  166. return message
  167. def main():
  168. try:
  169. print("开始获取文档统计数据...")
  170. data, start_date, end_date = get_document_statistics()
  171. # 使用markdown_v2格式
  172. markdown_content = format_markdown_v2_message(data, start_date, end_date)
  173. print("消息内容生成成功!")
  174. # 打印消息内容(用于调试)
  175. print("\n" + "="*50)
  176. print(markdown_content)
  177. print("="*50 + "\n")
  178. # 发送到企业微信机器人
  179. success = send_wechat_robot_message(markdown_content, msg_type="markdown_v2")
  180. if success:
  181. print("消息发送成功!")
  182. else:
  183. print("消息发送失败,请检查webhook配置")
  184. except Exception as e:
  185. error_message = f"❌ 统计任务失败\n\n错误信息: {str(e)}\n\n发生时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
  186. print(f"执行失败: {e}")
  187. # 发送错误通知
  188. send_wechat_robot_message(error_message, msg_type="text")
  189. if __name__ == "__main__":
  190. main()