ai_member_xiaoxi/scripts/batch_update_sheet.py
2026-05-24 08:00:01 +08:00

143 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
批量更新飞书电子表格回填用户ID和匹配状态
用于 2DOxEI 表 R915-R992 行
"""
import json
import subprocess
import sys
# 78个手机号按表格行顺序 915-992
PHONES = [
'18898596908', '13104122113', '18616818587', '18600641856', '18527822530',
'15301808320', '15921183656', '18969141986', '18853077186', '19879837192',
'15013730773', '18240307314', '15133168361', '18607715299', '18640248566',
'15229999262', '18615767595', '15880070471', '15210946014', '13416197660',
'18030731125', '13372561305', '13438029626', '13426271919', '13380241801',
'13331090268', '13941957202', '13668236095', '18666339866', '18193473383',
'18719069856', '15092617699', '15602091300', '18906300189', '18823116345',
'16675181845', '15805920790', '13631576638', '13825629898', '18689550023',
'13858852527', '17701557793', '18800105821', '18243588666', '15070812805',
'15906585627', '13818184885', '18609909747', '18501055123', '18781333078',
'13510511993', '13763607518', '19131773001', '13429170125', '13548532992',
'18273336778', '15004066188', '15386183750', '15002087823', '15622866383',
'15236831122', '13980065537', '17351768736', '13752368975', '18988791586',
'13465563287', '18268989827', '18358369704', '13370181982', '15062199752',
'13009161168', '17701717015', '13969392995', '13560010506', '18042928605',
'13603503266', '15776824932', '18131135363',
]
# 数据库查询结果: 脱敏手机号 -> [account_id列表]
# rn=1 作为首选最大account_id
MATCHES = {}
raw_matches = [
('188****6908', 26655), ('131****2113', 27442), ('186****8587', 27410),
('186****1856', 27213), ('185****2530', 27227), ('153****8320', 27417),
('159****3656', 27316), ('189****1986', 27591), ('188****7186', 27248),
('198****7192', 27686), ('150****0773', 27464), ('182****7314', 27429),
('151****8361', 27432), ('186****5299', 27017), ('186****8566', 27630),
('152****9262', 27483), ('186****7595', 27467), ('158****0471', 27693),
('152****6014', 27490), ('134****7660', 27619), ('180****1125', 27618),
('133****1305', 26920), ('134****9626', 27583), ('134****1919', 27755),
('133****1801', 27633), ('133****0268', 27983), ('139****7202', 27499),
('136****6095', 27598), ('186****9866', 27745), ('181****3383', 27576),
('187****9856', 27585), ('150****7699', 28052), ('156****1300', 27672),
('189****0189', 27292), ('188****6345', 27836), ('166****1845', 27955),
('158****0790', 27951), ('136****6638', 5149), ('138****9898', 3612),
('186****0023', 27674), ('138****2527', 4882), ('177****7793', 27890),
('188****5821', 27761), ('182****8666', 27812), ('150****2805', 27813),
('159****5627', 27882), ('138****4885', 27911), ('186****9747', 27809),
('185****5123', 27776), ('187****3078', 27738), ('135****1993', 27806),
('137****7518', 27770), ('191****3001', 27638), ('134****0125', 27794),
('135****2992', 27750), ('182****6778', 27728), ('150****6188', 27803),
('153****3750', 27790), ('150****7823', 11807), ('156****6383', 28018),
('152****1122', 27869), ('139****5537', 27947), ('173****8736', 28070),
('137****8975', 27916), ('189****1586', 27941), ('134****3287', 28079),
('182****9827', 27860), ('183****9704', 27849), ('133****1982', 4923),
('150****9752', 28071), ('130****1168', 27936), ('177****7015', 27946),
('139****2995', 27889), ('135****0506', 28394), ('180****8605', 28011),
('136****3266', 27965), ('157****4932', 28088), ('181****5363', 27979),
]
for tel_masked, acc_id in raw_matches:
MATCHES[tel_masked] = acc_id # rn=1 优先,后出现的会覆盖
def mask_phone(phone):
"""脱敏手机号: 前3位 + **** + 后4位"""
return f"{phone[:3]}****{phone[-4:]}"
def get_tat():
"""获取 Tenant Access Token"""
import json
config = json.load(open('/root/.openclaw/credentials/xiaoxi/config.json'))
app = config['apps'][0]
import urllib.request
data = json.dumps({"app_id": app['appId'], "app_secret": app['appSecret']}).encode()
req = urllib.request.Request(
'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
data=data,
headers={'Content-Type': 'application/json; charset=utf-8'}
)
resp = json.loads(urllib.request.urlopen(req).read())
return resp['tenant_access_token']
def update_sheet_range(tat, token, sheet_id, range_str, values):
"""批量更新电子表格范围"""
import urllib.request
url = f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{token}/values'
body = json.dumps({
"valueRange": {
"range": f"{sheet_id}!{range_str}",
"values": values
}
}).encode()
req = urllib.request.Request(url, data=body, method='PUT')
req.add_header('Authorization', f'Bearer {tat}')
req.add_header('Content-Type', 'application/json; charset=utf-8')
resp = json.loads(urllib.request.urlopen(req).read())
return resp
if __name__ == '__main__':
# 构建回填数据
f_values = [] # F列: account_id
g_values = [] # G列: 回填状态
matched_count = 0
multi_count = 0
for phone in PHONES:
masked = mask_phone(phone)
acc_id = MATCHES.get(masked)
if acc_id:
f_values.append([str(acc_id)])
g_values.append(["已匹配"])
matched_count += 1
else:
f_values.append(["未匹配"])
g_values.append(["未匹配"])
print(f"Total: {len(PHONES)}, Matched: {matched_count}, Unmatched: {len(PHONES) - matched_count}")
# 获取 token
tat = get_tat()
token = 'RFIJsXT8FhGHhctY4RwczcOfnac'
sheet_id = '2DOxEI'
# 更新 F 列 (F915:F992) - 回填用户ID
resp_f = update_sheet_range(tat, token, sheet_id, 'F915:F992', f_values)
print(f"Update F column: code={resp_f.get('code')}, msg={resp_f.get('msg')}")
# 更新 G 列 (G915:G992) - 回填状态
resp_g = update_sheet_range(tat, token, sheet_id, 'G915:G992', g_values)
print(f"Update G column: code={resp_g.get('code')}, msg={resp_g.get('msg')}")
# 更新 E 列 (E915:E992) - 请求状态改为"已返回"
e_values = [["已返回"] for _ in range(len(PHONES))]
resp_e = update_sheet_range(tat, token, sheet_id, 'E915:E992', e_values)
print(f"Update E column: code={resp_e.get('code')}, msg={resp_e.get('msg')}")
if resp_f.get('code') == 0 and resp_g.get('code') == 0:
print("\n✅ 所有78条记录已成功回填")
else:
print("\n⚠️ 部分更新可能失败,请检查。")