regen_mes_icons_current_sql.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. # -*- coding: utf-8 -*-
  2. """Regenerate restore SQL: only current (status=0) image per mes_icons id."""
  3. from __future__ import print_function
  4. from collections import Counter, defaultdict
  5. import os
  6. import sys
  7. sys.path.insert(0, r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work")
  8. from extract_mes_icons_files import ( # noqa: E402
  9. DUMP,
  10. OUT_DIR,
  11. find_offsets,
  12. iter_value_rows,
  13. parse_create_columns,
  14. read_until_stmt_end,
  15. row_to_dict,
  16. sql_quote,
  17. unquote,
  18. )
  19. def pick_latest(lst):
  20. return sorted(
  21. lst,
  22. key=lambda x: (
  23. x.get("update_date") or "",
  24. x.get("create_date") or "",
  25. x.get("id") or "",
  26. ),
  27. reverse=True,
  28. )[0]
  29. def main():
  30. hits = find_offsets(DUMP, ["mes_icons", "js_sys_file_upload", "js_sys_file_entity"])
  31. create_cols = {}
  32. inserts = {}
  33. for off, name in hits:
  34. if name.startswith("CREATE:"):
  35. t = name.split(":", 1)[1]
  36. stmt = read_until_stmt_end(DUMP, off, max_bytes=200 * 1024)
  37. create_cols[t] = parse_create_columns(stmt)
  38. else:
  39. inserts[name] = off
  40. icons_cols = create_cols["mes_icons"]
  41. upload_cols = create_cols["js_sys_file_upload"]
  42. entity_cols = create_cols["js_sys_file_entity"]
  43. icons = [row_to_dict(f, icons_cols) for f in iter_value_rows(DUMP, inserts["mes_icons"])]
  44. icon_by_id = {i["id"]: i for i in icons}
  45. biz_type_idx = upload_cols.index("biz_type")
  46. icon_uploads = []
  47. for fields in iter_value_rows(DUMP, inserts["js_sys_file_upload"]):
  48. if unquote(fields[biz_type_idx]) == "mesIcons_image":
  49. icon_uploads.append(row_to_dict(fields, upload_cols))
  50. print("upload status:", Counter(u.get("status") for u in icon_uploads))
  51. by_biz = defaultdict(list)
  52. for u in icon_uploads:
  53. if (u.get("status") or "0") == "0":
  54. by_biz[u.get("biz_key")].append(u)
  55. current = {}
  56. for k, lst in by_biz.items():
  57. if k:
  58. current[k] = pick_latest(lst)
  59. print(
  60. "modules with active image=%d, multi-active=%d"
  61. % (len(current), sum(1 for v in by_biz.values() if len(v) > 1))
  62. )
  63. needed = set(u["file_id"] for u in current.values() if u.get("file_id"))
  64. file_id_idx = entity_cols.index("file_id")
  65. entities = {}
  66. for fields in iter_value_rows(DUMP, inserts["js_sys_file_entity"]):
  67. fid = unquote(fields[file_id_idx])
  68. if fid in needed:
  69. entities[fid] = row_to_dict(fields, entity_cols)
  70. if len(entities) == len(needed):
  71. break
  72. print("entities=%d" % len(entities))
  73. def disk_rel(e):
  74. if not e:
  75. return ""
  76. path = (e.get("file_path") or "").replace("\\", "/")
  77. md5 = e.get("file_md5") or ""
  78. ext = e.get("file_extension") or ""
  79. return ("%s%s.%s" % (path, md5, ext)) if ext else ("%s%s" % (path, md5))
  80. map2 = os.path.join(OUT_DIR, "mes_icons_image_map_current_only.txt")
  81. with open(map2, "w", encoding="utf-8") as wf:
  82. wf.write(
  83. "icon_id\ttitle\tmode\ticon_status\tupload_id\tfile_id\tfile_name\t"
  84. "file_path\tfile_md5\text\tdisk_rel\tupdate_date\n"
  85. )
  86. for biz_key in sorted(current.keys()):
  87. u = current[biz_key]
  88. e = entities.get(u.get("file_id") or {}, {})
  89. ic = icon_by_id.get(biz_key, {})
  90. wf.write(
  91. "\t".join(
  92. [
  93. biz_key,
  94. ic.get("title") or "",
  95. ic.get("mode") or "",
  96. ic.get("status") or "",
  97. u.get("id") or "",
  98. u.get("file_id") or "",
  99. u.get("file_name") or "",
  100. (e.get("file_path") or "").replace("\\", "/"),
  101. e.get("file_md5") or "",
  102. e.get("file_extension") or "",
  103. disk_rel(e),
  104. u.get("update_date") or "",
  105. ]
  106. )
  107. + "\n"
  108. )
  109. print("Wrote", map2)
  110. sql_path = os.path.join(OUT_DIR, "restore_mes_icons_image_mapping.sql")
  111. with open(sql_path, "w", encoding="utf-8") as wf:
  112. wf.write("-- ============================================================\n")
  113. wf.write("-- Restore PDA功能模块图片映射(仅当前有效图 status=0,每模块取最新一条)\n")
  114. wf.write("-- 来源: mes_cloud_20260919.sql\n")
  115. wf.write("-- 关联: biz_key=mes_icons.id, biz_type=mesIcons_image\n")
  116. wf.write("-- 务必同步拷贝磁盘文件到新服务器 {baseDir}/userfiles/\n")
  117. wf.write("-- ============================================================\n")
  118. wf.write("SET NAMES utf8mb4;\nSTART TRANSACTION;\n\n")
  119. wf.write("-- 1) 文件实体\n")
  120. for fid in sorted(needed):
  121. e = entities[fid]
  122. size = e.get("file_size")
  123. size_sql = size if size is not None else "NULL"
  124. wf.write(
  125. "INSERT INTO `js_sys_file_entity` "
  126. "(`file_id`,`file_md5`,`file_path`,`file_content_type`,`file_extension`,"
  127. "`file_size`,`file_meta`,`file_preview`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s) "
  128. "ON DUPLICATE KEY UPDATE "
  129. "`file_md5`=VALUES(`file_md5`),`file_path`=VALUES(`file_path`),"
  130. "`file_content_type`=VALUES(`file_content_type`),"
  131. "`file_extension`=VALUES(`file_extension`),`file_size`=VALUES(`file_size`),"
  132. "`file_meta`=VALUES(`file_meta`),`file_preview`=VALUES(`file_preview`);\n"
  133. % (
  134. sql_quote(e.get("file_id")),
  135. sql_quote(e.get("file_md5")),
  136. sql_quote(e.get("file_path")),
  137. sql_quote(e.get("file_content_type")),
  138. sql_quote(e.get("file_extension")),
  139. size_sql,
  140. sql_quote(e.get("file_meta")),
  141. sql_quote(e.get("file_preview")),
  142. )
  143. )
  144. wf.write("\n-- 2) 按模块 id 替换绑定\n")
  145. for biz_key in sorted(current.keys()):
  146. u = current[biz_key]
  147. ic = icon_by_id.get(biz_key, {})
  148. e = entities.get(u.get("file_id") or {}, {})
  149. wf.write(
  150. "\n-- id=%s title=%s mode=%s disk=%s\n"
  151. % (biz_key, ic.get("title") or "", ic.get("mode") or "", disk_rel(e))
  152. )
  153. wf.write(
  154. "DELETE FROM `js_sys_file_upload` "
  155. "WHERE `biz_type`='mesIcons_image' AND `biz_key`=%s;\n"
  156. % sql_quote(biz_key)
  157. )
  158. sortv = u.get("file_sort")
  159. sort_sql = sortv if sortv is not None else "NULL"
  160. wf.write(
  161. "INSERT INTO `js_sys_file_upload` "
  162. "(`id`,`file_id`,`file_name`,`file_type`,`file_sort`,`biz_key`,`biz_type`,"
  163. "`status`,`create_by`,`create_date`,`update_by`,`update_date`,`remarks`) "
  164. "VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);\n"
  165. % (
  166. sql_quote(u.get("id")),
  167. sql_quote(u.get("file_id")),
  168. sql_quote(u.get("file_name")),
  169. sql_quote(u.get("file_type")),
  170. sort_sql,
  171. sql_quote(u.get("biz_key")),
  172. sql_quote(u.get("biz_type")),
  173. sql_quote(u.get("status") or "0"),
  174. sql_quote(u.get("create_by") or "system"),
  175. sql_quote(u.get("create_date")),
  176. sql_quote(u.get("update_by") or "system"),
  177. sql_quote(u.get("update_date")),
  178. sql_quote(u.get("remarks")),
  179. )
  180. )
  181. missing = [
  182. i
  183. for i in icons
  184. if i.get("id") not in current and (i.get("status") or "0") == "0"
  185. ]
  186. if missing:
  187. wf.write("\n-- 老库正常模块但无有效图片:\n")
  188. for i in missing:
  189. wf.write(
  190. "-- id=%s title=%s mode=%s\n"
  191. % (i.get("id"), i.get("title"), i.get("mode"))
  192. )
  193. wf.write("\nCOMMIT;\n")
  194. wf.write(
  195. "\n-- 校验:\n"
  196. "-- SELECT u.biz_key, i.title, i.mode, u.file_name, e.file_path, e.file_md5, e.file_extension\n"
  197. "-- FROM js_sys_file_upload u\n"
  198. "-- LEFT JOIN js_sys_file_entity e ON e.file_id=u.file_id\n"
  199. "-- LEFT JOIN mes_icons i ON i.id=u.biz_key\n"
  200. "-- WHERE u.biz_type='mesIcons_image' AND u.status='0'\n"
  201. "-- ORDER BY i.title;\n"
  202. )
  203. print("Wrote", sql_path)
  204. files_list = os.path.join(OUT_DIR, "mes_icons_image_files_to_copy.txt")
  205. seen = set()
  206. with open(files_list, "w", encoding="utf-8") as wf:
  207. wf.write("# 拷到新服务器 {file.baseDir}/userfiles/ 下,保持相对路径\n")
  208. for u in current.values():
  209. rel = disk_rel(entities.get(u.get("file_id") or {}))
  210. if not rel or rel in seen:
  211. continue
  212. seen.add(rel)
  213. wf.write(rel + "\n")
  214. print("files=%d Wrote %s" % (len(seen), files_list))
  215. print("--- preview (first 15) ---")
  216. with open(map2, encoding="utf-8") as rf:
  217. for i, line in enumerate(rf):
  218. if i <= 15:
  219. print(line.rstrip())
  220. else:
  221. break
  222. print("DONE")
  223. if __name__ == "__main__":
  224. main()