import json, os from collections import Counter base = r'.scratch/opportunity-e2e/env-raw' out_path = r'.scratch/opportunity-e2e/env-analysis.txt' _buf = [] def out(s=''): _buf.append(str(s)) def load(name): with open(os.path.join(base, name + '.json'), encoding='utf-8-sig') as f: return json.load(f) def fix(s): """PS5.1 把 UTF-8 响应按 Latin-1 解码的 mojibake,可逆还原""" if not isinstance(s, str): return s try: t = s.encode('latin-1').decode('utf-8') return t except (UnicodeEncodeError, UnicodeDecodeError): return s def deepfix(x): if isinstance(x, str): return fix(x) if isinstance(x, list): return [deepfix(i) for i in x] if isinstance(x, dict): return {k: deepfix(v) for k, v in x.items()} return x def content(payload): d = payload.get('data') if isinstance(d, list): return d, len(d) d = d or {} for k in ('content', 'list', 'records', 'rows'): if isinstance(d.get(k), list): return d.get(k), d.get('total') return [], d.get('total') # 1. 部门树(只打前 3 层,全量在 json 里) depts = load('depts') rows = depts.get('data') or [] out('=== DEPTS TREE (top3 levels) ===') def walk(nodes, depth=0): for n in nodes: if not isinstance(n, dict): continue out(' ' * depth + '- id=%s name=%s parent=%s' % (n.get('id'), fix(n.get('deptName') or n.get('name')), n.get('parentId'))) if depth < 2: walk(n.get('children') or [], depth + 1) walk(rows) # 2. 用户 users = load('users') ul, utotal = content(users) out('=== USERS total=%s n_page1=%s ===' % (utotal, len(ul))) if ul: out('sample-fields: ' + json.dumps(deepfix(ul[0]), ensure_ascii=False)[:700]) me = [u for u in ul if str(u.get('id')) == '739564171091247104'] out('me row: ' + (json.dumps(deepfix(me[0]), ensure_ascii=False)[:700] if me else 'not-in-page1')) cnt = Counter(fix(u.get('deptName')) or 'dept-null' for u in ul) out('dept dist top12: ' + repr(cnt.most_common(12))) # 3. 商机 opp = load('opp-page-MINE') ol, ot = content(opp) out('=== OPP MINE total=%s n=%s ===' % (ot, len(ol))) if ol: out('fields: ' + repr(sorted(ol[0].keys()))) for k in ol[0].keys(): if 'status' in k.lower(): out('dist(%s): %s' % (k, Counter(str(o.get(k)) for o in ol).most_common())) out('sample row: ' + json.dumps(deepfix(ol[0]), ensure_ascii=False)[:900]) # 4. 规则三族 for f in ['rule-opp-stage-template', 'rule-opp-scheme-template', 'rule-opp-pool-rule']: r = load(f) rl, rt = content(r) out('=== %s total=%s ===' % (f, rt)) for x in rl: out(json.dumps(deepfix(x), ensure_ascii=False)[:900]) # 5. 字典 22 组 g = load('dict-groups') gl, gt = content(g) out('=== DICT GROUPS (enabled) total=%s ===' % gt) for x in gl: out('%s | %s | sort=%s' % (x.get('code'), fix(x.get('name')), x.get('sortNo'))) with open(out_path, 'w', encoding='utf-8') as f: f.write('\n'.join(_buf)) print('written', out_path, len(_buf), 'lines')