You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.0 KiB
96 lines
3.0 KiB
|
1 week ago
|
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')
|