#!/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⚠️ 部分更新可能失败,请检查。")