excel_to_sql.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 旅检三部"三三"数字管理平台 Excel → SQL 导入脚本
  5. 运行: python excel_to_sql.py
  6. 输出: ledger_data_import.sql
  7. """
  8. import os, re, sys
  9. from datetime import datetime, date
  10. try:
  11. import openpyxl
  12. except ImportError:
  13. sys.exit("请先安装 openpyxl: pip install openpyxl")
  14. # ──────────────────────────────────────────────
  15. # 配置
  16. # ──────────────────────────────────────────────
  17. EXCEL_DIR = r'C:\Users\linzo\Downloads'
  18. OUTPUT_SQL = r'C:\Users\linzo\IdeaProjects\chongqing-server\sql\ledger_data_import.sql'
  19. BATCH_NO = datetime.now().strftime('BATCH_%Y%m%d_%H%M%S')
  20. CREATE_BY = 'admin'
  21. CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  22. # ──────────────────────────────────────────────
  23. # 工具函数
  24. # ──────────────────────────────────────────────
  25. def find_excel():
  26. for f in os.listdir(EXCEL_DIR):
  27. if '旅检' in f and f.endswith('.xlsx') and not f.startswith('~'):
  28. return os.path.join(EXCEL_DIR, f)
  29. raise FileNotFoundError('找不到 旅检*.xlsx 文件,请检查路径')
  30. def esc(v, maxlen=None):
  31. """转义 SQL 字符串值,可选最大长度截断"""
  32. if v is None:
  33. return 'NULL'
  34. s = str(v).strip()
  35. if s == '' or s == 'None':
  36. return 'NULL'
  37. s = s.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n').replace('\r', '').replace('\t', ' ')
  38. if maxlen and len(s) > maxlen:
  39. s = s[:maxlen]
  40. return f"'{s}'"
  41. def to_date(v):
  42. """将各种格式的日期转成 'YYYY-MM-DD' 或 NULL"""
  43. if v is None:
  44. return 'NULL'
  45. if isinstance(v, (datetime, date)):
  46. return f"'{v.strftime('%Y-%m-%d')}'"
  47. s = str(v).strip()
  48. if not s or s == 'None':
  49. return 'NULL'
  50. # 尝试多种格式
  51. for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%Y/%m/%d', '%m/%d/%Y'):
  52. try:
  53. return f"'{datetime.strptime(s.split('.')[0].strip(), fmt).strftime('%Y-%m-%d')}'"
  54. except ValueError:
  55. pass
  56. # 返回原始字符串(可能有特殊格式)
  57. return esc(s[:10])
  58. def to_decimal(v, default='NULL'):
  59. if v is None:
  60. return default
  61. s = str(v).strip().replace('¥', '').replace(',', '').strip()
  62. if not s or s == 'None':
  63. return default
  64. try:
  65. return str(float(s))
  66. except ValueError:
  67. return default
  68. def to_int(v, default='NULL'):
  69. if v is None:
  70. return default
  71. try:
  72. return str(int(float(str(v))))
  73. except (ValueError, TypeError):
  74. return default
  75. def row_vals(ws, row_num):
  76. """返回一行所有单元格值(列表)"""
  77. row = list(ws.iter_rows(min_row=row_num, max_row=row_num, values_only=True))
  78. return list(row[0]) if row else []
  79. def iter_data_rows(ws, header_row=2):
  80. """从 header_row+1 开始迭代有效数据行"""
  81. for row in ws.iter_rows(min_row=header_row + 1, values_only=True):
  82. # 跳过全空行
  83. if all(v is None or str(v).strip() == '' for v in row):
  84. continue
  85. yield list(row)
  86. def pad(lst, n):
  87. """把列表补齐到 n 长度"""
  88. return lst + [None] * max(0, n - len(lst))
  89. # ──────────────────────────────────────────────
  90. # 各 sheet 的映射函数
  91. # 每个函数返回 list of SQL INSERT 语句
  92. # ──────────────────────────────────────────────
  93. def sheet_supervision_problem(ws):
  94. """部门监察问题记录表 → ledger_supervision_problem
  95. Excel R2: 时间(0) 区域(1) 工作点(2) 岗位(3) 责任人(4) 问题描述(5)
  96. 问题类型(6) 整改措施(7) 依据(8) 问题层级(9) 班组(10)
  97. 队室质控员(11) 质控推送队室负责人(12) 附件(13) 整改情况(14)
  98. 佐证材料(15) 发送至相关人员(16) 本月内发生问题次数(17)
  99. 上月质控问题超过三次人员(18) 检查人员(19) 分管质控经理(20)
  100. 录入时间(21) 部门培训教员(22) 队室内勤(23) 队室负责人(24)
  101. """
  102. stmts = []
  103. for cols in iter_data_rows(ws, header_row=2):
  104. c = pad(cols, 25)
  105. stmts.append(
  106. f"INSERT INTO ledger_supervision_problem "
  107. f"(record_date,location,channel_no,inspected_name,problem_desc,problem_type,"
  108. f"result_handling,remark,team_name,inspector_name,evidence_file,"
  109. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  110. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},{esc(c[4])},{esc(c[5])},{esc(c[6])},"
  111. f"{esc(c[7])},{esc(c[8])},{esc(c[10])},{esc(c[11])},{esc(c[13])},"
  112. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  113. )
  114. return stmts
  115. def sheet_patrol_inspection(ws):
  116. """队室三级质控巡查记录表 → ledger_patrol_inspection
  117. Excel R2: 巡查日期(0) 巡查区域(1) 巡查工作点(2) 巡查时间段(3) 巡查岗位(4)
  118. 被检查人员(5) 有无问题(6) 检查情况描述(7) 类型(8) 整改措施(9)
  119. 附件(10) 整改情况(11) 佐证材料(12) 班组(13) 责任组长(14)
  120. 队室质控员(15) 队室负责人(16) 填报人(17) 队室内勤(18) 填报时间(19)
  121. """
  122. stmts = []
  123. for cols in iter_data_rows(ws, header_row=2):
  124. c = pad(cols, 20)
  125. stmts.append(
  126. f"INSERT INTO ledger_patrol_inspection "
  127. f"(record_date,location,channel_no,inspected_name,patrol_type,patrol_item,"
  128. f"problem_desc,result_handling,evidence_file,team_name,inspector_name,"
  129. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  130. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},{esc(c[5])},{esc(c[8])},{esc(c[4])},"
  131. f"{esc(c[7])},{esc(c[9])},{esc(c[10])},{esc(c[13])},{esc(c[14])},"
  132. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  133. )
  134. return stmts
  135. def _parse_datetime(v):
  136. """返回 (date_str, time_str) tuple for SQL"""
  137. if v is None:
  138. return 'NULL', 'NULL'
  139. if isinstance(v, datetime):
  140. return f"'{v.strftime('%Y-%m-%d')}'", f"'{v.strftime('%H:%M:%S')}'"
  141. s = str(v).strip()
  142. if not s or s == 'None':
  143. return 'NULL', 'NULL'
  144. for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d'):
  145. try:
  146. dt = datetime.strptime(s.split('.')[0].strip(), fmt)
  147. return f"'{dt.strftime('%Y-%m-%d')}'", f"'{dt.strftime('%H:%M:%S')}'"
  148. except ValueError:
  149. pass
  150. return esc(s[:10]), 'NULL'
  151. def sheet_realtime_interception(ws):
  152. """部门实时质控拦截情况记录表 → ledger_realtime_interception
  153. Excel R2: 时间(0) 区域(1) 工作点(2) 岗位(3) 责任人(4) 实时质控拦截物品(5)
  154. 个数(6) 问题类型(7) 整改措施(8) 问题层级(9) 班组(10)
  155. 附件(11) 问题类别(12) 个人复盘(13) 队室复盘(14)
  156. 队室质控员(15) 质控推送队室负责人(16) 开机年限(17)
  157. 责任人开机年龄(18) 发送至相关人员(19)
  158. """
  159. stmts = []
  160. for cols in iter_data_rows(ws, header_row=2):
  161. c = pad(cols, 20)
  162. d, t = _parse_datetime(c[0])
  163. stmts.append(
  164. f"INSERT INTO ledger_realtime_interception "
  165. f"(record_date,record_time,channel_no,inspector_name,item_name,"
  166. f"item_quantity,item_category,handling_method,team_name,evidence_file,remark,"
  167. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  168. f"{d},{t},{esc(c[2])},{esc(c[4])},{esc(c[5])},"
  169. f"{to_int(c[6])},{esc(c[7])},{esc(c[8])},{esc(c[10])},{esc(c[11])},{esc(c[12])},"
  170. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  171. )
  172. return stmts
  173. def sheet_service_patrol(ws):
  174. """服务巡查 → ledger_service_patrol
  175. Excel R2: 时间(0) 区域(1) 工作点(2) 岗位(3) 责任人(4) 问题描述(5)
  176. 问题类型(6) 整改措施(7) 班组(8) 问题层级(9)
  177. 队室服务联络人(10) 服务推送队室负责人(11) 附件(12)
  178. 整改情况(13) 佐证材料(14) 发送至相关人员(15)
  179. 本月内发生问题次数(16) 检查人员(17) 分管服务经理(18) 队室内勤(19)
  180. """
  181. stmts = []
  182. for cols in iter_data_rows(ws, header_row=2):
  183. c = pad(cols, 20)
  184. stmts.append(
  185. f"INSERT INTO ledger_service_patrol "
  186. f"(record_date,location,inspected_name,problem_desc,service_type,"
  187. f"result_handling,team_name,evidence_file,inspector_name,"
  188. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  189. f"{to_date(c[0])},{esc(c[1])},{esc(c[4])},{esc(c[5])},{esc(c[6])},"
  190. f"{esc(c[7])},{esc(c[8])},{esc(c[12])},{esc(c[17])},"
  191. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  192. )
  193. return stmts
  194. def sheet_complaint(ws):
  195. """投诉情况 → ledger_complaint
  196. Excel R2: 时间(0) 航班号(1) 旅客姓名(2) 班组(3) 责任人(4)
  197. 投诉情况(5) 旅客诉求(6) 类别(7) 渠道来源(8)
  198. 是否有责(9) 处理进度(10) 责任队长(11) 队室内勤(12)
  199. """
  200. stmts = []
  201. for cols in iter_data_rows(ws, header_row=2):
  202. c = pad(cols, 13)
  203. stmts.append(
  204. f"INSERT INTO ledger_complaint "
  205. f"(record_date,flight_no,passenger_name,team_name,responsible_name,"
  206. f"complaint_desc,complaint_type,result_handling,remark,"
  207. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  208. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},{esc(c[3])},{esc(c[4])},"
  209. f"{esc(c[5])},{esc(c[7])},{esc(c[10])},{esc(c[8])},"
  210. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  211. )
  212. return stmts
  213. def sheet_security_test(ws):
  214. """安保测试记录表(部门)→ ledger_security_test
  215. Excel R2: 开展时间(0) 测试区域(1) 测试通道(2) 测试项目(3)
  216. 被测试人员(4) 被测试岗位(5) 测试物品(6) 开展项目图片或视频(7)
  217. 是否通过(8) 层级(9) 整改措施(10) 复查地点及时间(11)
  218. 整改材料(12) 班组(13) 推送队室质控员(14) 推送质控队长(15)
  219. 队室内勤(16) 点击推送至相关人员(17) 队室负责人(18)
  220. """
  221. stmts = []
  222. for cols in iter_data_rows(ws, header_row=2):
  223. c = pad(cols, 19)
  224. stmts.append(
  225. f"INSERT INTO ledger_security_test "
  226. f"(record_date,location,channel_no,test_item,tested_name,test_type,"
  227. f"evidence_file,test_result,result_handling,team_name,"
  228. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  229. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},{esc(c[3])},{esc(c[4])},{esc(c[6])},"
  230. f"{esc(c[7])},{esc(c[8])},{esc(c[10])},{esc(c[13])},"
  231. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  232. )
  233. return stmts
  234. def sheet_channel_pass_rate(ws):
  235. """通道过检率 → ledger_channel_pass_rate
  236. Excel R2: 组长(0) 班组(1) 队室内勤(2) 2026年1月平均过检率(3) 2026年2月...(4) 2026年3月...(5) ...
  237. 结构是 pivot:一行=一个班组,多列=多月;展开为多行
  238. """
  239. headers = row_vals(ws, 2)
  240. # 找月份列(列3起)
  241. month_cols = []
  242. for idx, h in enumerate(headers[3:], start=3):
  243. if h and str(h).strip():
  244. month_cols.append((idx, str(h).strip()))
  245. # 提取月份年份
  246. def parse_month(label):
  247. m = re.search(r'(\d{4})年(\d{1,2})月', label)
  248. if m:
  249. return f"{m.group(1)}-{int(m.group(2)):02d}-01"
  250. return None
  251. stmts = []
  252. for cols in iter_data_rows(ws, header_row=2):
  253. c = pad(cols, len(headers) + 5)
  254. team = esc(c[1])
  255. for col_idx, label in month_cols:
  256. rate = to_decimal(c[col_idx] if col_idx < len(c) else None)
  257. if rate == 'NULL':
  258. continue
  259. month_date = parse_month(label)
  260. rec_date = f"'{month_date}'" if month_date else 'NULL'
  261. stmts.append(
  262. f"INSERT INTO ledger_channel_pass_rate "
  263. f"(record_date,team_name,pass_rate,remark,"
  264. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  265. f"{rec_date},{team},{rate},{esc(label)},"
  266. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  267. )
  268. return stmts
  269. def sheet_unsafe_event(ws):
  270. """不安全事件 → ledger_unsafe_event
  271. Excel R2: 时间(0) 事件描述(1) 类别(2) 航班号(3) 责任人(4)
  272. 涉及班组(5) 涉及物品(6) 岗位(7) 区域(8) 通道号(9)
  273. 图像(10) 队室内勤(11)
  274. """
  275. stmts = []
  276. for cols in iter_data_rows(ws, header_row=2):
  277. c = pad(cols, 12)
  278. stmts.append(
  279. f"INSERT INTO ledger_unsafe_event "
  280. f"(record_date,event_desc,event_type,responsible_name,team_name,"
  281. f"evidence_file,remark,"
  282. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  283. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},{esc(c[4])},{esc(c[5])},"
  284. f"{esc(c[10])},{esc(c[8])},"
  285. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  286. )
  287. return stmts
  288. def sheet_seizure_stats(ws):
  289. """2026查获违规品统计 → ledger_seizure_stats
  290. Excel R2: 查获时间(0) 信息提取(1) 信息提取2(2) 部门/队室(3) 工作区域(4)
  291. 安检员(5) 安检资格证书等级(6) 岗位(7) 航班号(8) 目的地(9)
  292. 进/出港(10) 违规主体(11) 旅客姓名(12) 旅客性别(13) 旅客民族(14)
  293. 旅客年龄(15) 违规类别(16) 违规物品种类(17) 二级分类(18) 数量(19)
  294. ...(可能更多列)
  295. """
  296. stmts = []
  297. for cols in iter_data_rows(ws, header_row=2):
  298. c = pad(cols, 30)
  299. stmts.append(
  300. f"INSERT INTO ledger_seizure_stats "
  301. f"(record_date,team_name,inspector_name,flight_no,passenger_name,"
  302. f"item_category,item_name,item_quantity,"
  303. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  304. f"{to_date(c[0])},{esc(c[3])},{esc(c[5])},{esc(c[8])},{esc(c[12])},"
  305. f"{esc(c[16])},{esc(c[17])},{to_int(c[19])},"
  306. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  307. )
  308. return stmts
  309. def sheet_terminal_bonus(ws):
  310. """航站楼加分 → ledger_terminal_bonus
  311. Excel R2: 审核日期(0) 姓名(1) 班组(2) 加分分数(3) 队室内勤(4) 总加分数(5) 队室负责人(6)
  312. """
  313. stmts = []
  314. for cols in iter_data_rows(ws, header_row=2):
  315. c = pad(cols, 7)
  316. stmts.append(
  317. f"INSERT INTO ledger_terminal_bonus "
  318. f"(approve_date,person_name,team_name,add_score,remark,"
  319. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  320. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},{to_decimal(c[3],'0')},{esc(c[4])},"
  321. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  322. )
  323. return stmts
  324. def sheet_exam_score(ws):
  325. """成绩收集 → ledger_exam_score
  326. Excel R2: 类别(0) 期数(1) 考试人员(2) 理论成绩(3) 图像成绩(4) 班组(5) 分类(6) 备注(补考分数)(7) 队室教员(8)
  327. """
  328. stmts = []
  329. for cols in iter_data_rows(ws, header_row=2):
  330. c = pad(cols, 9)
  331. stmts.append(
  332. f"INSERT INTO ledger_exam_score "
  333. f"(exam_category,exam_period,person_name,score,team_name,remark,"
  334. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  335. f"{esc(c[0])},{esc(c[1])},{esc(c[2])},{to_decimal(c[3],'NULL')},{esc(c[5])},{esc(c[7])},"
  336. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  337. )
  338. return stmts
  339. def sheet_reward_approval(ws):
  340. """小额奖励审批单-安检-质控 → ledger_reward_approval
  341. 特殊:R1 就是表头(没有 title row)
  342. Excel R1: 员工编码(0) 姓名(1) 查获(事件)时间(2) 奖励类别(3) 查获物品(4)
  343. 类别(5) 奖励事由(安全)(6) 人员类别(7) 主要事由简述(8)
  344. 数据从 R2 开始
  345. """
  346. stmts = []
  347. for cols in iter_data_rows(ws, header_row=1): # header_row=1 means data from row 2
  348. c = pad(cols, 9)
  349. stmts.append(
  350. f"INSERT INTO ledger_reward_approval "
  351. f"(approve_date,person_name,reward_type,approval_status,remark,"
  352. f"import_batch,source_type,create_by,create_time,del_flag) VALUES ("
  353. f"{to_date(c[2])},{esc(c[1])},{esc(c[3])},'待审批',{esc(c[8])},"
  354. f"'{BATCH_NO}','1','{CREATE_BY}','{CREATE_TIME}','0');"
  355. )
  356. return stmts
  357. def sheet_reward_penalty(ws):
  358. """部门奖惩记录表 → ledger_reward_penalty
  359. Excel R2: 姓名(0) 班组(1) 事由(2) 扣罚金额(3) 最后更新时间(4)
  360. """
  361. stmts = []
  362. for cols in iter_data_rows(ws, header_row=2):
  363. c = pad(cols, 5)
  364. # 扣罚金额转为负数分值(仅金额,非分值,存为负数)
  365. amt = to_decimal(c[3], 'NULL')
  366. score_change = f"-{amt}" if amt != 'NULL' else 'NULL'
  367. stmts.append(
  368. f"INSERT INTO ledger_reward_penalty "
  369. f"(record_date,person_name,team_name,type,event_desc,score_change,"
  370. f"create_by,create_time,del_flag) VALUES ("
  371. f"{to_date(c[4])},{esc(c[0])},{esc(c[1])},'2',{esc(c[2])},{score_change},"
  372. f"'{CREATE_BY}','{CREATE_TIME}','0');"
  373. )
  374. return stmts
  375. def sheet_leave_special(ws):
  376. """请、休假记录表(特殊)→ ledger_leave_special
  377. Excel R2: 姓名(0) 班组(1) 时间(起)(2) 时间(止)(3) 休假类别(4) 天数/时长(5)
  378. """
  379. stmts = []
  380. for cols in iter_data_rows(ws, header_row=2):
  381. c = pad(cols, 6)
  382. stmts.append(
  383. f"INSERT INTO ledger_leave_special "
  384. f"(person_name,team_name,leave_type,start_date,end_date,days,"
  385. f"create_by,create_time,del_flag) VALUES ("
  386. f"{esc(c[0])},{esc(c[1])},{esc(c[4])},{to_date(c[2])},{to_date(c[3])},{to_decimal(c[5],'NULL')},"
  387. f"'{CREATE_BY}','{CREATE_TIME}','0');"
  388. )
  389. return stmts
  390. def sheet_banner_letter(ws):
  391. """锦旗及感谢信 → ledger_banner_letter
  392. Excel R2: 时间(0) 姓名(1) 获得感谢信的具体内容(2) 类别(3) 图片和附件(4) 班组(5) 队室内勤(6)
  393. 类别: 感谢信→'2', 锦旗→'1', 其他→'2'
  394. """
  395. stmts = []
  396. for cols in iter_data_rows(ws, header_row=2):
  397. c = pad(cols, 7)
  398. typ = '1' if str(c[3] or '').strip() in ('锦旗',) else '2'
  399. stmts.append(
  400. f"INSERT INTO ledger_banner_letter "
  401. f"(record_date,person_name,content_desc,type,evidence_file,team_name,remark,"
  402. f"create_by,create_time,del_flag) VALUES ("
  403. f"{to_date(c[0])},{esc(c[1])},{esc(c[2])},'{typ}',{esc(c[4])},{esc(c[5])},{esc(c[6])},"
  404. f"'{CREATE_BY}','{CREATE_TIME}','0');"
  405. )
  406. return stmts
  407. # ──────────────────────────────────────────────
  408. # sheet name → handler mapping
  409. # ──────────────────────────────────────────────
  410. SHEET_MAP = {
  411. '部门监察问题记录表': ('ledger_supervision_problem', sheet_supervision_problem),
  412. '队室三级质控巡查记录表': ('ledger_patrol_inspection', sheet_patrol_inspection),
  413. '部门实时质控拦截情况记录表': ('ledger_realtime_interception', sheet_realtime_interception),
  414. '服务巡查': ('ledger_service_patrol', sheet_service_patrol),
  415. '投诉情况': ('ledger_complaint', sheet_complaint),
  416. '安保测试记录表(部门)': ('ledger_security_test', sheet_security_test),
  417. '通道过检率': ('ledger_channel_pass_rate', sheet_channel_pass_rate),
  418. '不安全事件': ('ledger_unsafe_event', sheet_unsafe_event),
  419. '2026查获违规品统计': ('ledger_seizure_stats', sheet_seizure_stats),
  420. '航站楼加分': ('ledger_terminal_bonus', sheet_terminal_bonus),
  421. '成绩收集': ('ledger_exam_score', sheet_exam_score),
  422. '小额奖励审批单-安检-质控': ('ledger_reward_approval', sheet_reward_approval),
  423. '部门奖惩记录表': ('ledger_reward_penalty', sheet_reward_penalty),
  424. '请、休假记录表(特殊)': ('ledger_leave_special', sheet_leave_special),
  425. '锦旗及感谢信': ('ledger_banner_letter', sheet_banner_letter),
  426. }
  427. SKIP_SHEETS = {
  428. '旅检三部人员信息表', '日常培训记录', '组长履职情况记录表',
  429. '健康锐兵(2026_3)', '宿舍消防安全专项自查表(部门)', '培训台账问题通报',
  430. }
  431. # ──────────────────────────────────────────────
  432. # 主程序
  433. # ──────────────────────────────────────────────
  434. def main():
  435. excel_path = find_excel()
  436. print(f'读取文件: {excel_path}')
  437. wb = openpyxl.load_workbook(excel_path, read_only=True, data_only=True)
  438. lines = [
  439. '-- =============================================',
  440. f'-- 台账数据导入 SQL 批次: {BATCH_NO}',
  441. f'-- 生成时间: {CREATE_TIME}',
  442. f'-- 来源文件: {os.path.basename(excel_path)}',
  443. '-- =============================================',
  444. 'SET NAMES utf8mb4;',
  445. 'SET FOREIGN_KEY_CHECKS=0;',
  446. '',
  447. ]
  448. total = 0
  449. for sheet_name in wb.sheetnames:
  450. if sheet_name in SKIP_SHEETS:
  451. print(f' [跳过] {sheet_name}')
  452. continue
  453. if sheet_name not in SHEET_MAP:
  454. print(f' [未映射] {sheet_name}')
  455. continue
  456. table_name, handler = SHEET_MAP[sheet_name]
  457. ws = wb[sheet_name]
  458. try:
  459. stmts = handler(ws)
  460. except Exception as e:
  461. print(f' [ERROR] {sheet_name}: {e}')
  462. import traceback; traceback.print_exc()
  463. stmts = []
  464. lines.append(f'-- ── {sheet_name} → {table_name} ({len(stmts)} 行) ──')
  465. lines.extend(stmts)
  466. lines.append('')
  467. total += len(stmts)
  468. print(f' [OK] {sheet_name} → {table_name}: {len(stmts)} 条')
  469. lines.append('SET FOREIGN_KEY_CHECKS=1;')
  470. lines.append(f'-- 共生成 {total} 条 INSERT 语句')
  471. wb.close()
  472. with open(OUTPUT_SQL, 'w', encoding='utf-8') as f:
  473. f.write('\n'.join(lines))
  474. print(f'\n✅ 完成!共 {total} 条,已写入:\n {OUTPUT_SQL}')
  475. print(f'\n执行方式(在 MySQL 客户端中):')
  476. print(f' USE chongqing; -- 替换为你的库名')
  477. print(f' SOURCE {OUTPUT_SQL.replace(chr(92), "/")};')
  478. if __name__ == '__main__':
  479. main()