更新
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
|
||||
import pymysql
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
conn = pymysql.connect(
|
||||
host="127.0.0.1", user="root", password="root", database="zyt", charset="utf8mb4"
|
||||
)
|
||||
cur = conn.cursor(pymysql.cursors.DictCursor)
|
||||
|
||||
START, END = 1786464000, 1786550399 # 2026-08-12
|
||||
|
||||
|
||||
def q(sql, args=None):
|
||||
cur.execute(sql, args or ())
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
def parse_follow(follow):
|
||||
if isinstance(follow, str) and follow:
|
||||
try:
|
||||
return json.loads(follow)
|
||||
except Exception:
|
||||
return []
|
||||
return follow if isinstance(follow, list) else []
|
||||
|
||||
|
||||
def contact_info(ext, user_id):
|
||||
rows = q(
|
||||
"SELECT id, name, follow_users, delete_time FROM zyt_qywx_external_contact WHERE external_userid=%s ORDER BY id DESC",
|
||||
(ext,),
|
||||
)
|
||||
name = None
|
||||
remark = None
|
||||
add_way = None
|
||||
still = False
|
||||
createtime = None
|
||||
for c in rows:
|
||||
if name is None:
|
||||
name = c.get("name")
|
||||
for fu in parse_follow(c.get("follow_users")):
|
||||
if not isinstance(fu, dict):
|
||||
continue
|
||||
uid = str(fu.get("userid") or fu.get("UserId") or "")
|
||||
if uid == user_id:
|
||||
still = True
|
||||
remark = fu.get("remark") or fu.get("Remark") or remark
|
||||
add_way = fu.get("add_way", fu.get("AddWay"))
|
||||
createtime = fu.get("createtime") or fu.get("create_time") or createtime
|
||||
if remark:
|
||||
break
|
||||
return {
|
||||
"name": name,
|
||||
"remark": remark,
|
||||
"add_way": add_way,
|
||||
"still_following": still,
|
||||
"follow_createtime": createtime,
|
||||
"follow_createtime_at": datetime.fromtimestamp(int(createtime)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
if createtime
|
||||
else None,
|
||||
"contact_rows": len(rows),
|
||||
}
|
||||
|
||||
|
||||
def events_for(user_id, ext):
|
||||
return q(
|
||||
"""
|
||||
SELECT change_type, FROM_UNIXTIME(event_time) AS event_at
|
||||
FROM zyt_qywx_external_contact_event
|
||||
WHERE user_id=%s AND external_userid=%s
|
||||
AND change_type IN ('add_external_contact','del_follow_user','del_external_contact','msg_audit_approved')
|
||||
ORDER BY event_time
|
||||
""",
|
||||
(user_id, ext),
|
||||
)
|
||||
|
||||
|
||||
def analyze(label, user_id):
|
||||
print(f"\n========== {label} / {user_id} ==========")
|
||||
admins = q(
|
||||
"SELECT id, name, work_wechat_userid, disable, delete_time FROM zyt_admin WHERE work_wechat_userid=%s OR name LIKE %s",
|
||||
(user_id, f"%{label}%"),
|
||||
)
|
||||
print("admin", json.dumps(admins, ensure_ascii=False, default=str))
|
||||
|
||||
raw = q(
|
||||
"""
|
||||
SELECT e.external_userid, COUNT(*) AS add_events,
|
||||
FROM_UNIXTIME(MIN(e.event_time)) AS first_in_day,
|
||||
FROM_UNIXTIME(MAX(e.event_time)) AS last_in_day
|
||||
FROM zyt_qywx_external_contact_event e
|
||||
WHERE e.change_type='add_external_contact'
|
||||
AND e.user_id=%s
|
||||
AND e.event_time BETWEEN %s AND %s
|
||||
AND e.external_userid <> ''
|
||||
GROUP BY e.external_userid
|
||||
ORDER BY MIN(e.event_time)
|
||||
""",
|
||||
(user_id, START, END),
|
||||
)
|
||||
print("raw unique adds", len(raw))
|
||||
|
||||
def filtered(extra_prev=False):
|
||||
sql = """
|
||||
SELECT e.external_userid, MIN(e.event_time) AS first_add,
|
||||
FROM_UNIXTIME(MIN(e.event_time)) AS first_add_at
|
||||
FROM zyt_qywx_external_contact_event e
|
||||
WHERE e.change_type='add_external_contact'
|
||||
AND e.user_id=%s
|
||||
AND e.event_time BETWEEN %s AND %s
|
||||
AND e.external_userid <> ''
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM zyt_qywx_external_contact_event audit_e
|
||||
WHERE audit_e.user_id=e.user_id
|
||||
AND audit_e.external_userid=e.external_userid
|
||||
AND audit_e.change_type='msg_audit_approved'
|
||||
AND audit_e.event_time >= e.event_time
|
||||
AND audit_e.event_time <= %s
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM zyt_qywx_external_contact_event del_e
|
||||
WHERE del_e.user_id=e.user_id
|
||||
AND del_e.external_userid=e.external_userid
|
||||
AND del_e.change_type='del_external_contact'
|
||||
AND del_e.event_time >= e.event_time
|
||||
AND del_e.event_time <= %s
|
||||
)
|
||||
"""
|
||||
args = [user_id, START, END, END, END]
|
||||
if extra_prev:
|
||||
sql += """
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM zyt_qywx_external_contact_event prev_e
|
||||
WHERE prev_e.user_id=e.user_id
|
||||
AND prev_e.external_userid=e.external_userid
|
||||
AND prev_e.change_type='add_external_contact'
|
||||
AND prev_e.event_time < %s
|
||||
)
|
||||
"""
|
||||
args.append(START)
|
||||
sql += " GROUP BY e.external_userid ORDER BY first_add"
|
||||
return q(sql, args)
|
||||
|
||||
old_pairs = filtered(False)
|
||||
new_pairs = filtered(True)
|
||||
print("system OLD (before readd fix)", len(old_pairs))
|
||||
print("system NEW (after readd fix)", len(new_pairs))
|
||||
|
||||
old_ids = {p["external_userid"] for p in old_pairs}
|
||||
new_ids = {p["external_userid"] for p in new_pairs}
|
||||
raw_ids = {p["external_userid"] for p in raw}
|
||||
|
||||
dropped_no_audit_or_del = raw_ids - old_ids
|
||||
dropped_readd = old_ids - new_ids
|
||||
|
||||
print("\n--- dropped vs raw (no audit / customer-deleted) ---")
|
||||
for ext in sorted(dropped_no_audit_or_del, key=lambda x: next(r["first_in_day"] for r in raw if r["external_userid"] == x)):
|
||||
info = contact_info(ext, user_id)
|
||||
ev = events_for(user_id, ext)
|
||||
print(json.dumps({"ext": ext, **info, "events": ev, "raw": next(r for r in raw if r["external_userid"] == ext)}, ensure_ascii=False, default=str))
|
||||
|
||||
print("\n--- dropped as re-add (old counted, new excluded) ---")
|
||||
for ext in sorted(dropped_readd):
|
||||
info = contact_info(ext, user_id)
|
||||
ev = events_for(user_id, ext)
|
||||
print(json.dumps({"ext": ext, **info, "events": ev}, ensure_ascii=False, default=str))
|
||||
|
||||
print("\n--- inheritance add_way 201/202 among NEW pairs ---")
|
||||
for p in new_pairs:
|
||||
info = contact_info(p["external_userid"], user_id)
|
||||
if info["add_way"] in (201, 202):
|
||||
print(json.dumps({"ext": p["external_userid"], **info, "first_add_at": p["first_add_at"]}, ensure_ascii=False, default=str))
|
||||
|
||||
print("\n--- NEW counted list ---")
|
||||
for p in new_pairs:
|
||||
info = contact_info(p["external_userid"], user_id)
|
||||
types = [e["change_type"] for e in events_for(user_id, p["external_userid"])]
|
||||
print(json.dumps({
|
||||
"first_add_at": p["first_add_at"],
|
||||
"name": info["name"],
|
||||
"remark": info["remark"],
|
||||
"add_way": info["add_way"],
|
||||
"follow_createtime_at": info["follow_createtime_at"],
|
||||
"still_following": info["still_following"],
|
||||
"event_types": sorted(set(types)),
|
||||
}, ensure_ascii=False, default=str))
|
||||
|
||||
# people in old but check missing audit on the in-day add specifically
|
||||
print("\n--- raw adds missing audit after THAT add or del_external ---")
|
||||
for r in raw:
|
||||
ext = r["external_userid"]
|
||||
if ext in old_ids:
|
||||
continue
|
||||
ev = events_for(user_id, ext)
|
||||
print(json.dumps({"ext": ext, "raw": r, "events": ev, **contact_info(ext, user_id)}, ensure_ascii=False, default=str))
|
||||
|
||||
|
||||
analyze("李晓焕", "LiXiaoHuan")
|
||||
analyze("彭世博", "GeiWoNaHaoDeA")
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import sys
|
||||
import pymysql
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
conn = pymysql.connect(host="127.0.0.1", user="root", password="root", database="zyt", charset="utf8mb4")
|
||||
cur = conn.cursor(pymysql.cursors.DictCursor)
|
||||
|
||||
def q(sql, args=None):
|
||||
cur.execute(sql, args or ())
|
||||
return cur.fetchall()
|
||||
|
||||
print("=== dept bindings ===")
|
||||
print(json.dumps(q("""
|
||||
SELECT a.id, a.name, a.work_wechat_userid, d.id AS dept_id, d.name AS dept_name
|
||||
FROM zyt_admin a
|
||||
LEFT JOIN zyt_admin_dept ad ON ad.admin_id=a.id
|
||||
LEFT JOIN zyt_dept d ON d.id=ad.dept_id AND d.delete_time IS NULL
|
||||
WHERE a.work_wechat_userid IN ('LiXiaoHuan','GeiWoNaHaoDeA','mu')
|
||||
ORDER BY a.id, d.id
|
||||
"""), ensure_ascii=False, default=str, indent=2))
|
||||
|
||||
print("=== 员工@ contact type ===")
|
||||
print(json.dumps(q("""
|
||||
SELECT c.id, c.external_userid, c.name, c.type, c.corp_name, c.gender
|
||||
FROM zyt_qywx_external_contact_event e
|
||||
JOIN zyt_qywx_external_contact c ON c.external_userid=e.external_userid
|
||||
WHERE e.user_id='LiXiaoHuan' AND e.change_type='add_external_contact'
|
||||
AND e.event_time BETWEEN 1786464000 AND 1786550399
|
||||
AND (c.name LIKE '%@%' OR c.name LIKE '%员工%')
|
||||
GROUP BY c.id
|
||||
"""), ensure_ascii=False, default=str, indent=2))
|
||||
|
||||
print("=== today Aug 13 counts ===")
|
||||
start, end = 1786550400, 1786636799
|
||||
for uid, name in [("LiXiaoHuan","李晓焕"),("GeiWoNaHaoDeA","彭世博")]:
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) AS c FROM (
|
||||
SELECT e.external_userid
|
||||
FROM zyt_qywx_external_contact_event e
|
||||
WHERE e.change_type='add_external_contact' AND e.user_id=%s
|
||||
AND e.event_time BETWEEN %s AND %s AND e.external_userid<>''
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM zyt_qywx_external_contact_event a
|
||||
WHERE a.user_id=e.user_id AND a.external_userid=e.external_userid
|
||||
AND a.change_type='msg_audit_approved' AND a.event_time>=e.event_time AND a.event_time<=%s
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM zyt_qywx_external_contact_event d
|
||||
WHERE d.user_id=e.user_id AND d.external_userid=e.external_userid
|
||||
AND d.change_type='del_external_contact' AND d.event_time>=e.event_time AND d.event_time<=%s
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM zyt_qywx_external_contact_event p
|
||||
WHERE p.user_id=e.user_id AND p.external_userid=e.external_userid
|
||||
AND p.change_type='add_external_contact' AND p.event_time<%s
|
||||
)
|
||||
GROUP BY e.external_userid
|
||||
) t
|
||||
""", (uid, start, end, end, end, start))
|
||||
print(name, "today unique", cur.fetchone())
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) AS raw FROM (
|
||||
SELECT external_userid FROM zyt_qywx_external_contact_event
|
||||
WHERE change_type='add_external_contact' AND user_id=%s
|
||||
AND event_time BETWEEN %s AND %s GROUP BY external_userid
|
||||
) t
|
||||
""", (uid, start, end))
|
||||
print(name, "today raw unique", cur.fetchone())
|
||||
|
||||
print("=== personal yeji 8/12 open/fans ===")
|
||||
print(json.dumps(q("""
|
||||
SELECT a.name, y.yeji_date, y.add_fans_count, y.total_open_count, y.media_source, y.creator_id
|
||||
FROM zyt_personal_yeji y
|
||||
JOIN zyt_admin a ON a.id=y.creator_id
|
||||
WHERE a.work_wechat_userid IN ('LiXiaoHuan','GeiWoNaHaoDeA')
|
||||
AND y.yeji_date BETWEEN '2026-08-12' AND '2026-08-13'
|
||||
ORDER BY a.name, y.yeji_date
|
||||
"""), ensure_ascii=False, default=str, indent=2))
|
||||
|
||||
print("=== 李晓焕 add_way mix ===")
|
||||
print(json.dumps(q("""
|
||||
SELECT change_type, COUNT(*) c FROM zyt_qywx_external_contact_event
|
||||
WHERE user_id='LiXiaoHuan' AND event_time BETWEEN 1786464000 AND 1786550399
|
||||
GROUP BY change_type
|
||||
"""), ensure_ascii=False, default=str))
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 203 KiB |
Reference in New Issue
Block a user