This commit is contained in:
2026-02-25 09:46:59 +08:00
parent a0845a8169
commit e00fa3e0ad
19 changed files with 5373 additions and 1491 deletions
@@ -2,14 +2,32 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "initial_id",
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2026-01-22T03:01:15.515786400Z",
"start_time": "2026-01-22T03:01:12.175041100Z"
}
},
"collapsed": true
},
"outputs": [
{
"ename": "FileNotFoundError",
"evalue": "[Errno 2] No such file or directory: 'C:\\\\Users\\\\zy187\\\\Desktop\\\\钉钉文件\\\\失败项目材料(1).xlsx'",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mFileNotFoundError\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 38\u001b[39m\n\u001b[32m 36\u001b[39m all_data = []\n\u001b[32m 37\u001b[39m fild_data = []\n\u001b[32m---> \u001b[39m\u001b[32m38\u001b[39m df = \u001b[43mpd\u001b[49m\u001b[43m.\u001b[49m\u001b[43mread_excel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msheet_name\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mSheet1\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 39\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m index, row \u001b[38;5;129;01min\u001b[39;00m tqdm(df.iterrows(), total=\u001b[38;5;28mlen\u001b[39m(df), desc=\u001b[33m\"\u001b[39m\u001b[33m处理中\u001b[39m\u001b[33m\"\u001b[39m, leave=\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[32m 40\u001b[39m json_data = {\n\u001b[32m 41\u001b[39m \u001b[33m'\u001b[39m\u001b[33mkeyword\u001b[39m\u001b[33m'\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33m凤凰\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 42\u001b[39m \u001b[33m'\u001b[39m\u001b[33mtype\u001b[39m\u001b[33m'\u001b[39m: \u001b[32m0\u001b[39m,\n\u001b[32m (...)\u001b[39m\u001b[32m 54\u001b[39m \u001b[33m'\u001b[39m\u001b[33mcurrentPage\u001b[39m\u001b[33m'\u001b[39m: \u001b[32m1\u001b[39m,\n\u001b[32m 55\u001b[39m }\n",
"\u001b[36mFile \u001b[39m\u001b[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\excel\\_base.py:495\u001b[39m, in \u001b[36mread_excel\u001b[39m\u001b[34m(io, sheet_name, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, parse_dates, date_parser, date_format, thousands, decimal, comment, skipfooter, storage_options, dtype_backend, engine_kwargs)\u001b[39m\n\u001b[32m 493\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(io, ExcelFile):\n\u001b[32m 494\u001b[39m should_close = \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m495\u001b[39m io = \u001b[43mExcelFile\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 496\u001b[39m \u001b[43m \u001b[49m\u001b[43mio\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 497\u001b[39m \u001b[43m \u001b[49m\u001b[43mstorage_options\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstorage_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 498\u001b[39m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[43m=\u001b[49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 499\u001b[39m \u001b[43m \u001b[49m\u001b[43mengine_kwargs\u001b[49m\u001b[43m=\u001b[49m\u001b[43mengine_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 500\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 501\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m engine \u001b[38;5;129;01mand\u001b[39;00m engine != io.engine:\n\u001b[32m 502\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 503\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mEngine should not be specified when passing \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 504\u001b[39m \u001b[33m\"\u001b[39m\u001b[33man ExcelFile - ExcelFile already has the engine set\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 505\u001b[39m )\n",
"\u001b[36mFile \u001b[39m\u001b[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\excel\\_base.py:1550\u001b[39m, in \u001b[36mExcelFile.__init__\u001b[39m\u001b[34m(self, path_or_buffer, engine, storage_options, engine_kwargs)\u001b[39m\n\u001b[32m 1548\u001b[39m ext = \u001b[33m\"\u001b[39m\u001b[33mxls\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1549\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1550\u001b[39m ext = \u001b[43minspect_excel_format\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 1551\u001b[39m \u001b[43m \u001b[49m\u001b[43mcontent_or_path\u001b[49m\u001b[43m=\u001b[49m\u001b[43mpath_or_buffer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstorage_options\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstorage_options\u001b[49m\n\u001b[32m 1552\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1553\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m ext \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 1554\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 1555\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mExcel file format cannot be determined, you must specify \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1556\u001b[39m \u001b[33m\"\u001b[39m\u001b[33man engine manually.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1557\u001b[39m )\n",
"\u001b[36mFile \u001b[39m\u001b[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\excel\\_base.py:1402\u001b[39m, in \u001b[36minspect_excel_format\u001b[39m\u001b[34m(content_or_path, storage_options)\u001b[39m\n\u001b[32m 1399\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(content_or_path, \u001b[38;5;28mbytes\u001b[39m):\n\u001b[32m 1400\u001b[39m content_or_path = BytesIO(content_or_path)\n\u001b[32m-> \u001b[39m\u001b[32m1402\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[43mget_handle\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 1403\u001b[39m \u001b[43m \u001b[49m\u001b[43mcontent_or_path\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mrb\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstorage_options\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstorage_options\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mis_text\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\n\u001b[32m 1404\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m handle:\n\u001b[32m 1405\u001b[39m stream = handle.handle\n\u001b[32m 1406\u001b[39m stream.seek(\u001b[32m0\u001b[39m)\n",
"\u001b[36mFile \u001b[39m\u001b[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\common.py:882\u001b[39m, in \u001b[36mget_handle\u001b[39m\u001b[34m(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\u001b[39m\n\u001b[32m 873\u001b[39m handle = \u001b[38;5;28mopen\u001b[39m(\n\u001b[32m 874\u001b[39m handle,\n\u001b[32m 875\u001b[39m ioargs.mode,\n\u001b[32m (...)\u001b[39m\u001b[32m 878\u001b[39m newline=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 879\u001b[39m )\n\u001b[32m 880\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 881\u001b[39m \u001b[38;5;66;03m# Binary mode\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m882\u001b[39m handle = \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mhandle\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mioargs\u001b[49m\u001b[43m.\u001b[49m\u001b[43mmode\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 883\u001b[39m handles.append(handle)\n\u001b[32m 885\u001b[39m \u001b[38;5;66;03m# Convert BytesIO or file objects passed with an encoding\u001b[39;00m\n",
"\u001b[31mFileNotFoundError\u001b[39m: [Errno 2] No such file or directory: 'C:\\\\Users\\\\zy187\\\\Desktop\\\\钉钉文件\\\\失败项目材料(1).xlsx'"
]
}
],
"source": [
"import time\n",
"\n",
@@ -100,40 +118,42 @@
"ndf.to_excel(fr\"C:\\Users\\zy187\\Desktop\\云材料结果2.xlsx\")\n",
"fdf = pd.DataFrame(fild_data)\n",
"fdf.to_excel(fr\"C:\\Users\\zy187\\Desktop\\失败项目材料2.xlsx\")"
],
"outputs": [
{
"ename": "FileNotFoundError",
"evalue": "[Errno 2] No such file or directory: 'C:\\\\Users\\\\zy187\\\\Desktop\\\\钉钉文件\\\\失败项目材料(1).xlsx'",
"output_type": "error",
"traceback": [
"\u001B[31m---------------------------------------------------------------------------\u001B[39m",
"\u001B[31mFileNotFoundError\u001B[39m Traceback (most recent call last)",
"\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[1]\u001B[39m\u001B[32m, line 38\u001B[39m\n\u001B[32m 36\u001B[39m all_data = []\n\u001B[32m 37\u001B[39m fild_data = []\n\u001B[32m---> \u001B[39m\u001B[32m38\u001B[39m df = \u001B[43mpd\u001B[49m\u001B[43m.\u001B[49m\u001B[43mread_excel\u001B[49m\u001B[43m(\u001B[49m\u001B[43mpath\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43msheet_name\u001B[49m\u001B[43m=\u001B[49m\u001B[33;43m\"\u001B[39;49m\u001B[33;43mSheet1\u001B[39;49m\u001B[33;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[32m 39\u001B[39m \u001B[38;5;28;01mfor\u001B[39;00m index, row \u001B[38;5;129;01min\u001B[39;00m tqdm(df.iterrows(), total=\u001B[38;5;28mlen\u001B[39m(df), desc=\u001B[33m\"\u001B[39m\u001B[33m处理中\u001B[39m\u001B[33m\"\u001B[39m, leave=\u001B[38;5;28;01mFalse\u001B[39;00m):\n\u001B[32m 40\u001B[39m json_data = {\n\u001B[32m 41\u001B[39m \u001B[33m'\u001B[39m\u001B[33mkeyword\u001B[39m\u001B[33m'\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33m凤凰\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 42\u001B[39m \u001B[33m'\u001B[39m\u001B[33mtype\u001B[39m\u001B[33m'\u001B[39m: \u001B[32m0\u001B[39m,\n\u001B[32m (...)\u001B[39m\u001B[32m 54\u001B[39m \u001B[33m'\u001B[39m\u001B[33mcurrentPage\u001B[39m\u001B[33m'\u001B[39m: \u001B[32m1\u001B[39m,\n\u001B[32m 55\u001B[39m }\n",
"\u001B[36mFile \u001B[39m\u001B[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\excel\\_base.py:495\u001B[39m, in \u001B[36mread_excel\u001B[39m\u001B[34m(io, sheet_name, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, parse_dates, date_parser, date_format, thousands, decimal, comment, skipfooter, storage_options, dtype_backend, engine_kwargs)\u001B[39m\n\u001B[32m 493\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(io, ExcelFile):\n\u001B[32m 494\u001B[39m should_close = \u001B[38;5;28;01mTrue\u001B[39;00m\n\u001B[32m--> \u001B[39m\u001B[32m495\u001B[39m io = \u001B[43mExcelFile\u001B[49m\u001B[43m(\u001B[49m\n\u001B[32m 496\u001B[39m \u001B[43m \u001B[49m\u001B[43mio\u001B[49m\u001B[43m,\u001B[49m\n\u001B[32m 497\u001B[39m \u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[43m=\u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[43m,\u001B[49m\n\u001B[32m 498\u001B[39m \u001B[43m \u001B[49m\u001B[43mengine\u001B[49m\u001B[43m=\u001B[49m\u001B[43mengine\u001B[49m\u001B[43m,\u001B[49m\n\u001B[32m 499\u001B[39m \u001B[43m \u001B[49m\u001B[43mengine_kwargs\u001B[49m\u001B[43m=\u001B[49m\u001B[43mengine_kwargs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[32m 500\u001B[39m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[32m 501\u001B[39m \u001B[38;5;28;01melif\u001B[39;00m engine \u001B[38;5;129;01mand\u001B[39;00m engine != io.engine:\n\u001B[32m 502\u001B[39m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[32m 503\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mEngine should not be specified when passing \u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 504\u001B[39m \u001B[33m\"\u001B[39m\u001B[33man ExcelFile - ExcelFile already has the engine set\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 505\u001B[39m )\n",
"\u001B[36mFile \u001B[39m\u001B[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\excel\\_base.py:1550\u001B[39m, in \u001B[36mExcelFile.__init__\u001B[39m\u001B[34m(self, path_or_buffer, engine, storage_options, engine_kwargs)\u001B[39m\n\u001B[32m 1548\u001B[39m ext = \u001B[33m\"\u001B[39m\u001B[33mxls\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 1549\u001B[39m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[32m-> \u001B[39m\u001B[32m1550\u001B[39m ext = \u001B[43minspect_excel_format\u001B[49m\u001B[43m(\u001B[49m\n\u001B[32m 1551\u001B[39m \u001B[43m \u001B[49m\u001B[43mcontent_or_path\u001B[49m\u001B[43m=\u001B[49m\u001B[43mpath_or_buffer\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[43m=\u001B[49m\u001B[43mstorage_options\u001B[49m\n\u001B[32m 1552\u001B[39m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[32m 1553\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m ext \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[32m 1554\u001B[39m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[32m 1555\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mExcel file format cannot be determined, you must specify \u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 1556\u001B[39m \u001B[33m\"\u001B[39m\u001B[33man engine manually.\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 1557\u001B[39m )\n",
"\u001B[36mFile \u001B[39m\u001B[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\excel\\_base.py:1402\u001B[39m, in \u001B[36minspect_excel_format\u001B[39m\u001B[34m(content_or_path, storage_options)\u001B[39m\n\u001B[32m 1399\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(content_or_path, \u001B[38;5;28mbytes\u001B[39m):\n\u001B[32m 1400\u001B[39m content_or_path = BytesIO(content_or_path)\n\u001B[32m-> \u001B[39m\u001B[32m1402\u001B[39m \u001B[38;5;28;01mwith\u001B[39;00m \u001B[43mget_handle\u001B[49m\u001B[43m(\u001B[49m\n\u001B[32m 1403\u001B[39m \u001B[43m \u001B[49m\u001B[43mcontent_or_path\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[33;43m\"\u001B[39;49m\u001B[33;43mrb\u001B[39;49m\u001B[33;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[43m=\u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mis_text\u001B[49m\u001B[43m=\u001B[49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\n\u001B[32m 1404\u001B[39m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;28;01mas\u001B[39;00m handle:\n\u001B[32m 1405\u001B[39m stream = handle.handle\n\u001B[32m 1406\u001B[39m stream.seek(\u001B[32m0\u001B[39m)\n",
"\u001B[36mFile \u001B[39m\u001B[32mD:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\pandas\\io\\common.py:882\u001B[39m, in \u001B[36mget_handle\u001B[39m\u001B[34m(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\u001B[39m\n\u001B[32m 873\u001B[39m handle = \u001B[38;5;28mopen\u001B[39m(\n\u001B[32m 874\u001B[39m handle,\n\u001B[32m 875\u001B[39m ioargs.mode,\n\u001B[32m (...)\u001B[39m\u001B[32m 878\u001B[39m newline=\u001B[33m\"\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 879\u001B[39m )\n\u001B[32m 880\u001B[39m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[32m 881\u001B[39m \u001B[38;5;66;03m# Binary mode\u001B[39;00m\n\u001B[32m--> \u001B[39m\u001B[32m882\u001B[39m handle = \u001B[38;5;28;43mopen\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43mhandle\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mioargs\u001B[49m\u001B[43m.\u001B[49m\u001B[43mmode\u001B[49m\u001B[43m)\u001B[49m\n\u001B[32m 883\u001B[39m handles.append(handle)\n\u001B[32m 885\u001B[39m \u001B[38;5;66;03m# Convert BytesIO or file objects passed with an encoding\u001B[39;00m\n",
"\u001B[31mFileNotFoundError\u001B[39m: [Errno 2] No such file or directory: 'C:\\\\Users\\\\zy187\\\\Desktop\\\\钉钉文件\\\\失败项目材料(1).xlsx'"
]
}
],
"execution_count": 1
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "# 关键字搜索",
"id": "713d0645f9b5b8b0"
"id": "713d0645f9b5b8b0",
"metadata": {},
"source": [
"# 关键字搜索"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "56303413fee1137",
"metadata": {
"ExecuteTime": {
"end_time": "2026-01-22T03:07:17.414079900Z",
"start_time": "2026-01-22T03:04:41.187628900Z"
}
},
"cell_type": "code",
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7ad7a6cd83cf4722a92c3fd9dc6e56a9",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/3 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import time\n",
"import pandas as pd\n",
@@ -143,13 +163,13 @@
"import requests\n",
"\n",
"cookies = {\n",
" 'f6-ids-goodsSESSIONID': '5933f16b-f9b7-4653-9696-a7d46ecbfba3',\n",
" 'f6-ids-goodsSESSIONID': '1608f49b-0c52-4dd4-b46e-01664c841a45',\n",
" 'erpLanguage': 'zh-CN',\n",
" 'tmall': 'false',\n",
" 'prodOrg': '11240984669917188035',\n",
" 'unp': '15919462121159692302',\n",
" '_up': '-NillNN-qyBEJ--t3vnSknvoOF52zPiJts8E0Xo-X-5bX_PCp5vQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqEvoUrY0m3wAK_vRRv-ZNHu3M-GTc15m4EXGqr-9UiO4Tll_BPRNtrEj9nhm_qsCwNGE.',\n",
" 'sensorsdata2015jssdkcross': '%7B%22distinct_id%22%3A%2215919462121159692302%22%2C%22first_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%7D',\n",
" 'prodOrg': '11240984669917217520',\n",
" 'unp': '15865484595890778191',\n",
" '_up': '-NillNN-qyBEJ--t3vnSknvoOF53y_SJuMkA2n43U-daUfnArpjQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqE_MWrI8g0QME_vJRv-ZNHu3M-GTc1p60EX-sq-RQgeIal1HLPxpurEj9mUa59cnvQWI.',\n",
" 'sensorsdata2015jssdkcross': '%7B%22distinct_id%22%3A%2215865484595890778191%22%2C%22first_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%7D',\n",
"}\n",
"\n",
"headers = {\n",
@@ -166,14 +186,14 @@
" 'sec-fetch-mode': 'cors',\n",
" 'sec-fetch-site': 'same-origin',\n",
" 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0',\n",
" # 'cookie': 'f6-ids-goodsSESSIONID=5933f16b-f9b7-4653-9696-a7d46ecbfba3; erpLanguage=zh-CN; tmall=false; prodOrg=11240984669917188035; unp=15919462121159692302; _up=-NillNN-qyBEJ--t3vnSknvoOF52zPiJts8E0Xo-X-5bX_PCp5vQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqEvoUrY0m3wAK_vRRv-ZNHu3M-GTc15m4EXGqr-9UiO4Tll_BPRNtrEj9nhm_qsCwNGE.; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2215919462121159692302%22%2C%22first_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%7D',\n",
" # 'cookie': 'f6-ids-goodsSESSIONID=1608f49b-0c52-4dd4-b46e-01664c841a45; erpLanguage=zh-CN; tmall=false; prodOrg=11240984669917217520; unp=15865484595890778191; _up=-NillNN-qyBEJ--t3vnSknvoOF53y_SJuMkA2n43U-daUfnArpjQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqE_MWrI8g0QME_vJRv-ZNHu3M-GTc1p60EX-sq-RQgeIal1HLPxpurEj9mUa59cnvQWI.; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2215865484595890778191%22%2C%22first_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%7D',\n",
"}\n",
"\n",
"\n",
"all_data = []\n",
"for i in tqdm(range(1, 56)):\n",
"for i in tqdm(range(1, 4)):\n",
" json_data = {\n",
" 'keyword': '凤凰',\n",
" 'keyword': \"思卫博\",\n",
" 'type': 0,\n",
" 'facetFields': [\n",
" ],\n",
@@ -198,64 +218,43 @@
" all_data.append(item)\n",
"\n",
"ndf = pd.DataFrame(all_data)\n",
"ndf.to_excel(fr\"D:\\Idea Project\\F6+宜搭+其它(1)\\张阳脚本\\云材料结果.xlsx\")"
],
"id": "56303413fee1137",
"outputs": [
{
"data": {
"text/plain": [
" 0%| | 0/55 [00:00<?, ?it/s]"
],
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "c02fb63c7f4c4b0ca4b44f2fc27ce650"
}
},
"metadata": {},
"output_type": "display_data",
"jetTransient": {
"display_id": null
}
}
],
"execution_count": 3
"ndf.to_excel(fr\"D:\\Idea Project\\F6+宜搭+其它(1)\\张阳脚本\\云材料结果1.xlsx\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "15e7fa1e9c5b91b",
"metadata": {
"ExecuteTime": {
"end_time": "2026-01-05T06:05:31.695215600Z",
"start_time": "2026-01-05T06:05:30.160772900Z"
}
},
"cell_type": "code",
"outputs": [],
"source": [
"ndf = pd.DataFrame(all_data)\n",
"ndf.to_excel(fr\"C:\\Users\\hp_z66\\Desktop\\云材料结果.xlsx\")"
],
"id": "15e7fa1e9c5b91b",
"outputs": [],
"execution_count": 2
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "F6+宜搭+其它",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
"pygments_lexer": "ipython3",
"version": "3.13.11"
}
},
"nbformat": 4,
File diff suppressed because it is too large Load Diff
@@ -10,9 +10,9 @@ from module import F6_module
start_time = time.time()
f6_module = F6_module()
username = "18911549229"
password = "Zyj030415"
store_name = "乾多多洗车美容"
username = "18751893221"
password = "123456Ab"
store_name = "新众合车酷"
res = f6_module.login_in(username, password, store_name)
@@ -23,13 +23,13 @@ headers = {
}
count = 1
try:
df = pd.read_excel(r"C:\Users\zy187\Desktop\钉钉文件\会员卡信息-刷折扣.xls",
sheet_name='0.90',
df = pd.read_excel(r"C:\Users\hp_z66\OneDrive\Desktop\钉钉文件\会员卡信息.新.xlsx",
sheet_name='Sheet2',
dtype='string')
items = {'洗车': '2694036', '美容': '2694033', } # 修改的内容(含新增)
discount = '0.90' # 需要修改的折扣
# discount_list = {'维修': '0.80', '美容': '0.80', '保养': '0.80', '洗车': '0.80'}
items = {'洗车': '2759725',"美容":"2759722"} # 修改的内容(含新增)
# discount = '0.90' # 需要修改的折扣
discount_list = { '美容': '0.68', '洗车': '0.68'}
# print(df)
cookies = requests.utils.dict_from_cookiejar(res.cookies)
@@ -61,102 +61,101 @@ try:
carInfoList.append(List)
# 提取cardEntityBusinessList
cardEntityBusinessList = [
{
"labelName": "维修",
"businessType": 0,
"labelId": "2694031"
},
{
"labelName": "保养",
"businessType": 0,
"labelId": "2694032"
},
{
"labelName": "美容",
"businessType": 0,
"labelId": "2694033"
},
{
"labelName": "钣喷",
"businessType": 0,
"labelId": "2694034"
},
{
"labelName": "轮胎",
"businessType": 0,
"labelId": "2694035"
},
{
"labelName": "洗车",
"businessType": 0,
"labelId": "2694036"
},
{
"labelName": "精品",
"businessType": 0,
"labelId": "2694037"
},
{
"labelName": "其他",
"businessType": 0,
"labelId": "2694038"
},
{
"labelName": "零售",
"businessType": 0,
"labelId": "2694039"
},
{
"labelName": "维修",
"businessType": 1,
"labelId": "2694031"
},
{
"labelName": "保养",
"businessType": 1,
"labelId": "2694032"
},
{
"labelName": "美容",
"businessType": 1,
"labelId": "2694033"
},
{
"labelName": "钣喷",
"businessType": 1,
"labelId": "2694034"
},
{
"labelName": "轮胎",
"businessType": 1,
"labelId": "2694035"
},
{
"labelName": "洗车",
"businessType": 1,
"labelId": "2694036"
},
{
"labelName": "精品",
"businessType": 1,
"labelId": "2694037"
},
{
"labelName": "其他",
"businessType": 1,
"labelId": "2694038"
},
{
"labelName": "零售",
"businessType": 1,
"labelId": "2694039"
},
{
"businessType": 2,
"labelId": "0"
}
]
{
"labelName": "维修",
"businessType": 0,
"labelId": "2759720"
},
{
"labelName": "保养",
"businessType": 0,
"labelId": "2759721"
},
{
"labelName": "美容",
"businessType": 0,
"labelId": "2759722"
},
{
"labelName": "钣喷",
"businessType": 0,
"labelId": "2759723"
},
{
"labelName": "轮胎",
"businessType": 0,
"labelId": "2759724"
},
{
"labelName": "洗车",
"businessType": 0,
"labelId": "2759725"
},
{
"labelName": "精品",
"businessType": 0,
"labelId": "2759726"
},
{
"labelName": "其他",
"businessType": 0,
"labelId": "2759727"
},
{
"labelName": "零售",
"businessType": 0,
"labelId": "2759728"
},
{
"labelName": "维修",
"businessType": 1,
"labelId": "2759720"
},
{
"labelName": "保养",
"businessType": 1,
"labelId": "2759721"
},
{
"labelName": "美容",
"businessType": 1,
"labelId": "2759722"
},
{
"labelName": "钣喷",
"businessType": 1,
"labelId": "2759723"
},
{
"labelName": "轮胎",
"businessType": 1,
"labelId": "2759724"
},
{
"labelName": "洗车",
"businessType": 1,
"labelId": "2759725"
},
{
"labelName": "精品",
"businessType": 1,
"labelId": "2759726"
},
{
"labelName": "其他",
"businessType": 1,
"labelId": "2759727"
},
{
"labelName": "零售",
"businessType": 1,
"labelId": "2759728"
},
{
"businessType": 2,
"labelId": "0"
}
]
# 提取cardEntityBusinessDiscountList
cardEntityBusinessDiscountList = []
@@ -166,7 +165,7 @@ try:
# for cardEntityBusinessDiscount in cardEntityBusinessList:
try:
for item, labe in items.items(): # items() 返回一个列表
# discount = discount_list.get(item, 0) # 针对不同折扣
discount = discount_list.get(item, 0) # 针对不同折扣
List = {
# "labelName": cardEntityBusinessList['labelName'], # 修改原来有折扣的选项
"labelName": item, #
@@ -222,7 +221,7 @@ try:
"businessType": 1,
"useIdOwnOrgList":
[
"15982098507125256267"
"16041647893945294910"
], # 需要修改
# 适用门店需要获取 res_version['data']['idOwnOrg']
"cardEntitySkuDiscountList": res['info']['valueCardEntitySkuDiscountInfoList']
@@ -4,8 +4,8 @@ from tqdm import tqdm
from module import F6_module
import time
from http.cookies import SimpleCookie
# f6_module = F6_module()
#
# username = "18742526670"
# password = "Zy18742526670"
# store_name = "F6汽车科技数据组测试(废弃)"
@@ -20,10 +20,10 @@ def parse_cookie_string(cookie_str):
return {k: v.value for k, v in cookie.items()}
cookies = "f6-ids-goodsSESSIONID=f6263faa-6a04-4684-a9d5-e6d4b22358f2; erpLanguage=zh-CN; prodOrg=16024893747162546234; unp=16024896179200360473; _up=-NillNN-qyBEJ--t3vnSknvoOF1_z_WFucsE1HI9WudeUPHFoJrQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqEvUXoYkn0QUL9vhRv-ZNHu3M-GTf3pq1HX6ur-pci-sak1DDOhRsrEj95Vz7qLHTPSI.; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2216024896179200360473%22%2C%22first_id%22%3A%2219a48e066e68e2-067b1e693596828-4c657b58-2073600-19a48e066e71500%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219a48e066e68e2-067b1e693596828-4c657b58-2073600-19a48e066e71500%22%7D; tmall=false"
cookies = "maintainSESSIONID=5668579a-89bd-4faf-8bc3-71e045e4c19f; sajssdk_2015_cross_new_user=1; erpLanguage=zh-CN; prodOrg=11240984669917717605; unp=15658191795152506944; un=15658191795152506944; _up=-NillNN-qyBEJ--t3vnSknvoOF55yPmMucwC2n4-X-VYVvfIo53QjaZJ9Q3d-WrAAGgt60MgQHajHWBHMqWxj0OjWylpxpYEXk7xGLY883DqFPoSrYgr3wsF_O1f6PpAWPXU62Df25CwHHavp-hUjOkfkFDKOhd98xbtwx3f_My0TQ..; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2215658191795152506944%22%2C%22first_id%22%3A%2219c55b3f719b4d-0c0ba8a14163198-4c657b58-2073600-19c55b3f71a1e63%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219c55b3f719b4d-0c0ba8a14163198-4c657b58-2073600-19c55b3f71a1e63%22%7D; tmall=false; Hm_lvt_25f5e7a3a5dbb293d7dd35d5f1be8d0a=1770964400; HMACCOUNT=592B0DDEAFF7F37D; Hm_lpvt_25f5e7a3a5dbb293d7dd35d5f1be8d0a=1770964405"
cookies_dict = parse_cookie_string(cookies)
df = pd.read_excel(fr"C:\Users\zy187\Desktop\钉钉文件\1_品牌名.xlsx",sheet_name=0)
df = pd.read_excel(fr"C:\Users\hp_z66\OneDrive\Desktop\品牌名.xlsx",sheet_name=0)
for index,row in tqdm(df.iterrows()):
brandNmae = row["品牌名"]
# cookies = requests.utils.dict_from_cookiejar(cookies)
@@ -0,0 +1,652 @@
{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": "材料条码",
"id": "8c2170413e567816"
},
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2026-02-04T02:44:16.921927300Z",
"start_time": "2026-02-04T01:49:57.940495Z"
}
},
"source": [
"import requests\n",
"import logging\n",
"import traceback\n",
"import requests\n",
"import time\n",
"from typing import Dict, Any\n",
"from tqdm import tqdm\n",
"import pandas as pd\n",
"import os\n",
"\n",
"\n",
"\n",
"cookies = {\n",
" 'f6-ids-goodsSESSIONID': '32660868-f969-4f7f-9267-db66aafad920',\n",
" 'erpLanguage': 'zh-CN',\n",
" 'prodOrg': '16034652297803894850',\n",
" 'unp': '16034652300295311374',\n",
" '_up': '-NillNN-qyBEJ--t3vnSknvoOF1_zvWLtc8G03s9U-JeV_DCoJ3QjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqE_MVr4Mq1wsM__VRv-ZNHu3M-GTf3pu1E3Kqre1Vi-Ifk1fCPRRrrEj9m1mw9bCwNGQ.',\n",
" 'sensorsdata2015jssdkcross': '%7B%22distinct_id%22%3A%2216034652300295311374%22%2C%22first_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%7D',\n",
" 'tmall': 'false',\n",
"}\n",
"\n",
"headers = {\n",
" 'accept': 'application/json, text/plain, */*',\n",
" 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',\n",
" 'content-type': 'application/json;charset=UTF-8',\n",
" 'origin': 'https://ids-goods.f6car.cn',\n",
" 'priority': 'u=1, i',\n",
" 'referer': 'https://ids-goods.f6car.cn/f6-ids-goods/view/material.html',\n",
" 'sec-ch-ua': '\"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"144\", \"Microsoft Edge\";v=\"144\"',\n",
" 'sec-ch-ua-mobile': '?0',\n",
" 'sec-ch-ua-platform': '\"Windows\"',\n",
" 'sec-fetch-dest': 'empty',\n",
" 'sec-fetch-mode': 'cors',\n",
" 'sec-fetch-site': 'same-origin',\n",
" 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0',\n",
" # 'cookie': 'f6-ids-goodsSESSIONID=32660868-f969-4f7f-9267-db66aafad920; erpLanguage=zh-CN; prodOrg=16034652297803894850; unp=16034652300295311374; _up=-NillNN-qyBEJ--t3vnSknvoOF1_zvWLtc8G03s9U-JeV_DCoJ3QjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqE_MVr4Mq1wsM__VRv-ZNHu3M-GTf3pu1E3Kqre1Vi-Ifk1fCPRRrrEj9m1mw9bCwNGQ.; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2216034652300295311374%22%2C%22first_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%2219b6df76a22f46-04a98afdd2a11d8-4c657b58-1327104-19b6df76a2312c7%22%7D; tmall=false',\n",
"}\n",
"org_id = '16034652297803894850'\n",
"# 第一步:获取所有材料列表(分页)\n",
"json_data = {\n",
" 'keyWord': '',\n",
" 'idOwnOrg': org_id,\n",
" 'currentPage': 1,\n",
" 'pageSize': 100,\n",
" 'name': '',\n",
" 'brand': '',\n",
" 'supplierCode': '',\n",
" 'customCode': '',\n",
" 'categoryName': '',\n",
" 'categoryId': '',\n",
" 'labelId': '',\n",
" 'labelName': '',\n",
" 'spec': '',\n",
" 'applyModel': '',\n",
" 'sellPurchaseStatuses': [2, 3, 4, 5],\n",
" 'customInvoiceCategory': 0,\n",
" 'getThirdPlatformCode': 0,\n",
"}\n",
"\n",
"\n",
"def safe_str(val):\n",
" \"\"\"将值转为字符串,NaN 返回空字符串\"\"\"\n",
" if pd.isna(val):\n",
" return \"\"\n",
" return str(val).strip()\n",
"\n",
"\n",
"def should_update(new_val):\n",
" \"\"\"判断是否应该用 new_val 更新:非 NaN 且非空字符串\"\"\"\n",
" return not (pd.isna(new_val) or (isinstance(new_val, str) and new_val.strip() == \"\"))\n",
"\n",
"\n",
"try:\n",
" response = requests.post(\n",
" 'https://ids-goods.f6car.com/f6-ids-goods/part/getExactPartStockInfo',\n",
" cookies=cookies,\n",
" json=json_data,\n",
" )\n",
" response.raise_for_status()\n",
" total_pages = response.json().get(\"data\", {}).get(\"totalPages\", 0)\n",
" print(f\"材料列表页数: {total_pages}\")\n",
"\n",
" all_materials_list = []\n",
" total_pages = int(total_pages)\n",
" for page in tqdm(range(1, total_pages + 1), desc=\"获取材料列表\"):\n",
" json_data['currentPage'] = page\n",
" try:\n",
" resp = requests.post(\n",
" 'https://ids-goods.f6car.com/f6-ids-goods/part/getExactPartStockInfo',\n",
" cookies=cookies,\n",
" json=json_data,\n",
" )\n",
" time.sleep(1)\n",
" resp.raise_for_status()\n",
" records = resp.json().get(\"data\", {}).get(\"records\", [])\n",
" all_materials_list.extend(records)\n",
" except requests.exceptions.RequestException as e:\n",
" print(\n",
" f\"获取第{page}页材料列表失败: {str(e)}, 响应状态码: {getattr(e.response, 'status_code', 'N/A')}\")\n",
" raise\n",
" print(f\"材料列表获取完成,总计: {len(all_materials_list)}条\")\n",
"except requests.exceptions.RequestException as e:\n",
" print(f\"获取材料列表失败: {str(e)}, 堆栈信息: {traceback.format_exc()}\")\n",
" raise\n",
"\n",
"df = pd.read_excel(fr\"C:\\Users\\hp_z66\\Desktop\\钉钉文件\\一号车库材料信息需添加条码(宗川涵).xls\", engine='xlrd',sheet_name=0)\n",
"# 第二步:构建 update_map(只存原始值,不预处理)\n",
"update_map = {}\n",
"skipped_count = 0\n",
"for _, row in df.iterrows():\n",
" orig_code = row.iloc[0] # 原材料编码\n",
" if pd.isna(orig_code) or str(orig_code).strip() == \"\":\n",
" skipped_count += 1\n",
" continue\n",
" orig_code = str(orig_code).strip()\n",
" update_map[orig_code] = {\n",
" \"材料条码\": row.iloc[1],\n",
" }\n",
"print(f\"待更新材料数: {len(update_map)},跳过空编码行: {skipped_count}\")\n",
"\n",
"# 第三步:遍历材料,按需更新\n",
"results = []\n",
"consecutive_failures = 0 # 连续失败计数器\n",
"MAX_CONSECUTIVE_FAILURES = 100 # 最大连续失败次数\n",
"success_count = 0\n",
"failure_count = 0\n",
"skip_count = 0\n",
"\n",
"for item in tqdm(all_materials_list, desc=\"处理材料更新\",total = len(all_materials_list)):\n",
" custom_code = item.get(\"customCode\")\n",
" if not custom_code or str(custom_code) not in update_map:\n",
" continue\n",
"\n",
" part_id = item.get(\"partId\")\n",
" if not part_id:\n",
" error_msg = '缺少 partId'\n",
" results.append({'材料编码': custom_code, '状态': error_msg})\n",
" failure_count += 1\n",
" consecutive_failures += 1\n",
" print(f\"材料编码 {custom_code} 跳过/失败: {error_msg}\")\n",
" if consecutive_failures >= MAX_CONSECUTIVE_FAILURES:\n",
" results.append({'材料编码': '系统保护', '状态': '连续100次失败已终止'})\n",
" print(f\"连续失败{MAX_CONSECUTIVE_FAILURES}次,已中止任务执行\")\n",
" break\n",
" continue\n",
"\n",
" try:\n",
" # 获取材料明细\n",
" params = {\n",
" 'partId': part_id,\n",
" 'customInvoiceCategory': '0',\n",
" 'getThirdPlatformCode': '0',\n",
" }\n",
" materials_response = requests.get(\n",
" 'https://ids-goods.f6car.com/f6-ids-goods/part/getPartInfo',\n",
" params=params,\n",
" cookies=cookies,\n",
" )\n",
" time.sleep(1)\n",
" if materials_response.status_code != 200:\n",
" error_msg = f'获取明细失败: {materials_response.status_code}'\n",
" results.append({'材料编码': custom_code, '状态': error_msg})\n",
" failure_count += 1\n",
" consecutive_failures += 1\n",
" print(f\"材料编码 {custom_code} {error_msg}, 响应内容: {materials_response.text[:200]}\")\n",
" if consecutive_failures >= MAX_CONSECUTIVE_FAILURES:\n",
" results.append({'材料编码': '系统保护', '状态': '连续100次失败已终止'})\n",
" print(f\"连续失败{MAX_CONSECUTIVE_FAILURES}次,已中止任务执行\")\n",
" break\n",
" continue\n",
"\n",
" detail = materials_response.json().get(\"data\")\n",
" if not detail:\n",
" error_msg = '明细为空'\n",
" results.append({'材料编码': custom_code, '状态': error_msg})\n",
" failure_count += 1\n",
" consecutive_failures += 1\n",
" print(f\"材料编码 {custom_code} {error_msg}, 响应JSON: {materials_response.json()}\")\n",
" if consecutive_failures >= MAX_CONSECUTIVE_FAILURES:\n",
" results.append({'材料编码': '系统保护', '状态': '连续100次失败已终止'})\n",
" print(f\"连续失败{MAX_CONSECUTIVE_FAILURES}次,已中止任务执行\")\n",
" break\n",
" continue\n",
"\n",
" updates = update_map[str(custom_code)]\n",
" import time\n",
"\n",
" # 获取当前时间戳(秒),乘以1000转为毫秒,并取整\n",
" timestamp_ms = int(time.time() * 1000)\n",
"\n",
" # 安全更新字段:仅当 Excel 提供有效值时才覆盖\n",
" if should_update(updates[\"材料条码\"]):\n",
" detail[\"partBarCodeVos\"] = [\n",
" {\n",
" 'barCode': safe_str(updates[\"材料条码\"]),\n",
" 'barId': None,\n",
" 'createTime': timestamp_ms,\n",
" 'creator': '15865484595890778191',\n",
" 'groupId': None,\n",
" 'infoId': '14582097883364187448',\n",
" 'isDel': 0,\n",
" 'modifier': '15865484595890778191',\n",
" 'modifyTime': timestamp_ms,\n",
" },\n",
" ]\n",
" # 修复价格格式和数组(必须!)\n",
" for f in [\"purchasePrice\", \"sellPrice\"]:\n",
" val = detail.get(f)\n",
" if isinstance(val, (int, float)):\n",
" detail[f] = f\"{val:.2f}\"\n",
" if detail.get(\"partBarCodeVos\") is None:\n",
" detail[\"partBarCodeVos\"] = []\n",
"\n",
" # 提交更新\n",
" update_resp = requests.post(\n",
" 'https://ids-goods.f6car.com/f6-ids-goods/part/updateAreaPartBasicInfo',\n",
" cookies=cookies,\n",
" json=detail\n",
" )\n",
" time.sleep(2)\n",
"\n",
" if update_resp.status_code == 200 and update_resp.json().get(\"code\") == 200:\n",
" results.append({'材料编码': custom_code, '状态': '修改成功'})\n",
" success_count += 1\n",
" consecutive_failures = 0 # 成功时重置计数器\n",
" else:\n",
" msg = update_resp.json().get(\"message\", \"未知错误\")\n",
" error_msg = f'修改失败: {msg}'\n",
" results.append({'材料编码': custom_code, '状态': error_msg})\n",
" failure_count += 1\n",
" consecutive_failures += 1\n",
" print(f\"材料编码 {custom_code} {error_msg}, 响应数据: {update_resp.json()}\")\n",
"\n",
" except requests.exceptions.RequestException as e:\n",
" error_msg = f'请求异常: {str(e)}'\n",
" results.append({'材料编码': custom_code, '状态': error_msg})\n",
" failure_count += 1\n",
" consecutive_failures += 1\n",
" print(f\"材料编码 {custom_code} {error_msg}, 堆栈信息: {traceback.format_exc()}\")\n",
" except Exception as e:\n",
" error_msg = f'内部错误: {str(e)}'\n",
" results.append({'材料编码': custom_code, '状态': error_msg})\n",
" failure_count += 1\n",
" consecutive_failures += 1\n",
" print(f\"材料编码 {custom_code} {error_msg}, 堆栈信息: {traceback.format_exc()}\")\n",
" # 检查连续失败次数\n",
" if consecutive_failures >= MAX_CONSECUTIVE_FAILURES:\n",
" results.append({'材料编码': '系统保护', '状态': '连续100次失败已终止'})\n",
" print(f\"连续失败{MAX_CONSECUTIVE_FAILURES}次,已中止任务执行\")\n",
" break\n",
"\n",
"# 统计汇总(总行数 / 待处理 / 成功 / 失败 / 跳过)\n",
"total_rows = len(df)\n",
"to_process = len(update_map)\n",
"# results 里可能包含 “缺少 partId” 等失败信息;这里跳过数按空编码行计数即可\n",
"skip_count = skipped_count\n",
"summary = {\n",
" \"总行数\": total_rows,\n",
" \"待处理\": to_process,\n",
" \"成功\": success_count,\n",
" \"失败\": failure_count,\n",
" \"跳过\": skip_count,\n",
"}\n",
"results.insert(0, {\"汇总\": summary})\n",
"print(f\"材料修改汇总: {summary}\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"材料列表页数: 10\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"获取材料列表: 100%|██████████| 10/10 [00:15<00:00, 1.55s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"材料列表获取完成,总计: 922条\n",
"待更新材料数: 813,跳过空编码行: 0\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"处理材料更新: 39%|███▉ | 360/922 [16:41<39:48, 4.25s/it]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"材料编码 CL0000564 请求异常: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None)), 堆栈信息: Traceback (most recent call last):\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 773, in urlopen\n",
" self._prepare_proxy(conn)\n",
" ~~~~~~~~~~~~~~~~~~~^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 1042, in _prepare_proxy\n",
" conn.connect()\n",
" ~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 796, in connect\n",
" sock_and_verified = _ssl_wrap_socket_and_match_hostname(\n",
" sock=sock,\n",
" ...<14 lines>...\n",
" assert_fingerprint=self.assert_fingerprint,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 975, in _ssl_wrap_socket_and_match_hostname\n",
" ssl_sock = ssl_wrap_socket(\n",
" sock=sock,\n",
" ...<8 lines>...\n",
" tls_in_tls=tls_in_tls,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 483, in ssl_wrap_socket\n",
" ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 527, in _ssl_wrap_socket_impl\n",
" return ssl_context.wrap_socket(sock, server_hostname=server_hostname)\n",
" ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 455, in wrap_socket\n",
" return self.sslsocket_class._create(\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n",
" sock=sock,\n",
" ^^^^^^^^^^\n",
" ...<5 lines>...\n",
" session=session\n",
" ^^^^^^^^^^^^^^^\n",
" )\n",
" ^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1076, in _create\n",
" self.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1372, in do_handshake\n",
" self._sslobj.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n",
"ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。\n",
"\n",
"During handling of the above exception, another exception occurred:\n",
"\n",
"Traceback (most recent call last):\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\adapters.py\", line 644, in send\n",
" resp = conn.urlopen(\n",
" method=request.method,\n",
" ...<9 lines>...\n",
" chunked=chunked,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 841, in urlopen\n",
" retries = retries.increment(\n",
" method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\retry.py\", line 474, in increment\n",
" raise reraise(type(error), error, _stacktrace)\n",
" ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\util.py\", line 38, in reraise\n",
" raise value.with_traceback(tb)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 773, in urlopen\n",
" self._prepare_proxy(conn)\n",
" ~~~~~~~~~~~~~~~~~~~^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 1042, in _prepare_proxy\n",
" conn.connect()\n",
" ~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 796, in connect\n",
" sock_and_verified = _ssl_wrap_socket_and_match_hostname(\n",
" sock=sock,\n",
" ...<14 lines>...\n",
" assert_fingerprint=self.assert_fingerprint,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 975, in _ssl_wrap_socket_and_match_hostname\n",
" ssl_sock = ssl_wrap_socket(\n",
" sock=sock,\n",
" ...<8 lines>...\n",
" tls_in_tls=tls_in_tls,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 483, in ssl_wrap_socket\n",
" ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 527, in _ssl_wrap_socket_impl\n",
" return ssl_context.wrap_socket(sock, server_hostname=server_hostname)\n",
" ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 455, in wrap_socket\n",
" return self.sslsocket_class._create(\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n",
" sock=sock,\n",
" ^^^^^^^^^^\n",
" ...<5 lines>...\n",
" session=session\n",
" ^^^^^^^^^^^^^^^\n",
" )\n",
" ^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1076, in _create\n",
" self.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1372, in do_handshake\n",
" self._sslobj.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n",
"urllib3.exceptions.ProtocolError: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))\n",
"\n",
"During handling of the above exception, another exception occurred:\n",
"\n",
"Traceback (most recent call last):\n",
" File \"C:\\Users\\hp_z66\\AppData\\Local\\Temp\\ipykernel_105196\\2551472138.py\", line 155, in <module>\n",
" materials_response = requests.get(\n",
" 'https://ids-goods.f6car.com/f6-ids-goods/part/getPartInfo',\n",
" params=params,\n",
" cookies=cookies,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\api.py\", line 73, in get\n",
" return request(\"get\", url, params=params, **kwargs)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\api.py\", line 59, in request\n",
" return session.request(method=method, url=url, **kwargs)\n",
" ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\sessions.py\", line 589, in request\n",
" resp = self.send(prep, **send_kwargs)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\sessions.py\", line 703, in send\n",
" r = adapter.send(request, **kwargs)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\adapters.py\", line 659, in send\n",
" raise ConnectionError(err, request=request)\n",
"requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"处理材料更新: 53%|█████▎ | 486/922 [25:00<31:25, 4.32s/it]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"材料编码 CL0000457 请求异常: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None)), 堆栈信息: Traceback (most recent call last):\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 773, in urlopen\n",
" self._prepare_proxy(conn)\n",
" ~~~~~~~~~~~~~~~~~~~^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 1042, in _prepare_proxy\n",
" conn.connect()\n",
" ~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 796, in connect\n",
" sock_and_verified = _ssl_wrap_socket_and_match_hostname(\n",
" sock=sock,\n",
" ...<14 lines>...\n",
" assert_fingerprint=self.assert_fingerprint,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 975, in _ssl_wrap_socket_and_match_hostname\n",
" ssl_sock = ssl_wrap_socket(\n",
" sock=sock,\n",
" ...<8 lines>...\n",
" tls_in_tls=tls_in_tls,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 483, in ssl_wrap_socket\n",
" ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 527, in _ssl_wrap_socket_impl\n",
" return ssl_context.wrap_socket(sock, server_hostname=server_hostname)\n",
" ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 455, in wrap_socket\n",
" return self.sslsocket_class._create(\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n",
" sock=sock,\n",
" ^^^^^^^^^^\n",
" ...<5 lines>...\n",
" session=session\n",
" ^^^^^^^^^^^^^^^\n",
" )\n",
" ^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1076, in _create\n",
" self.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1372, in do_handshake\n",
" self._sslobj.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n",
"ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。\n",
"\n",
"During handling of the above exception, another exception occurred:\n",
"\n",
"Traceback (most recent call last):\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\adapters.py\", line 644, in send\n",
" resp = conn.urlopen(\n",
" method=request.method,\n",
" ...<9 lines>...\n",
" chunked=chunked,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 841, in urlopen\n",
" retries = retries.increment(\n",
" method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\retry.py\", line 474, in increment\n",
" raise reraise(type(error), error, _stacktrace)\n",
" ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\util.py\", line 38, in reraise\n",
" raise value.with_traceback(tb)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 773, in urlopen\n",
" self._prepare_proxy(conn)\n",
" ~~~~~~~~~~~~~~~~~~~^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connectionpool.py\", line 1042, in _prepare_proxy\n",
" conn.connect()\n",
" ~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 796, in connect\n",
" sock_and_verified = _ssl_wrap_socket_and_match_hostname(\n",
" sock=sock,\n",
" ...<14 lines>...\n",
" assert_fingerprint=self.assert_fingerprint,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\connection.py\", line 975, in _ssl_wrap_socket_and_match_hostname\n",
" ssl_sock = ssl_wrap_socket(\n",
" sock=sock,\n",
" ...<8 lines>...\n",
" tls_in_tls=tls_in_tls,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 483, in ssl_wrap_socket\n",
" ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\urllib3\\util\\ssl_.py\", line 527, in _ssl_wrap_socket_impl\n",
" return ssl_context.wrap_socket(sock, server_hostname=server_hostname)\n",
" ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 455, in wrap_socket\n",
" return self.sslsocket_class._create(\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n",
" sock=sock,\n",
" ^^^^^^^^^^\n",
" ...<5 lines>...\n",
" session=session\n",
" ^^^^^^^^^^^^^^^\n",
" )\n",
" ^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1076, in _create\n",
" self.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\ssl.py\", line 1372, in do_handshake\n",
" self._sslobj.do_handshake()\n",
" ~~~~~~~~~~~~~~~~~~~~~~~~~^^\n",
"urllib3.exceptions.ProtocolError: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))\n",
"\n",
"During handling of the above exception, another exception occurred:\n",
"\n",
"Traceback (most recent call last):\n",
" File \"C:\\Users\\hp_z66\\AppData\\Local\\Temp\\ipykernel_105196\\2551472138.py\", line 155, in <module>\n",
" materials_response = requests.get(\n",
" 'https://ids-goods.f6car.com/f6-ids-goods/part/getPartInfo',\n",
" params=params,\n",
" cookies=cookies,\n",
" )\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\api.py\", line 73, in get\n",
" return request(\"get\", url, params=params, **kwargs)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\api.py\", line 59, in request\n",
" return session.request(method=method, url=url, **kwargs)\n",
" ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\sessions.py\", line 589, in request\n",
" resp = self.send(prep, **send_kwargs)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\sessions.py\", line 703, in send\n",
" r = adapter.send(request, **kwargs)\n",
" File \"D:\\Program Files\\anaconda3\\envs\\F6+宜搭+其它\\Lib\\site-packages\\requests\\adapters.py\", line 659, in send\n",
" raise ConnectionError(err, request=request)\n",
"requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"处理材料更新: 100%|██████████| 922/922 [54:02<00:00, 3.52s/it]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"材料修改汇总: {'总行数': 813, '待处理': 813, '成功': 811, '失败': 2, '跳过': 0}\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"execution_count": 4
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-02-03T07:29:11.795586Z",
"start_time": "2026-02-03T07:29:11.747501600Z"
}
},
"cell_type": "code",
"source": "",
"id": "b5c78eb02e2607ec",
"outputs": [
{
"data": {
"text/plain": [
"{'code': 400, 'message': '材料名称不能为空!'}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"execution_count": 4
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+128
View File
@@ -0,0 +1,128 @@
SELECT
'{{%%p_start_date}}' AS ,
'{{%%p_end_date}}' AS ,
sos.id_storage AS id,
sos.storage_name AS ,
sos.part_name AS ,
sos.custom_code AS ,
sos.supplier_code AS ,
sos.category_root_name AS ,
sos.category_name AS ,
sos.part_brand AS ,
/* ---------- 期初(begin_*:仅在开始日取值;>60天仅月初保留) ---------- */
SUM(
CASE
WHEN DATEDIFF(CURRENT_DATE(), STR_TO_DATE('{{%%p_start_date}}', '%Y-%m-%d')) > 60
AND DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')) <> 1
THEN 0
WHEN sos.bill_day = '{{%%p_start_date}}'
THEN sos.begin_number
ELSE 0
END
) AS ,
SUM(
CASE
WHEN DATEDIFF(CURRENT_DATE(), STR_TO_DATE('{{%%p_start_date}}', '%Y-%m-%d')) > 60
AND DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')) <> 1
THEN 0
WHEN sos.bill_day = '{{%%p_start_date}}'
THEN sos.begin_price
ELSE 0
END
) AS ,
SUM(
CASE
WHEN DATEDIFF(CURRENT_DATE(), STR_TO_DATE('{{%%p_start_date}}', '%Y-%m-%d')) > 60
AND DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')) <> 1
THEN 0
WHEN sos.bill_day = '{{%%p_start_date}}'
THEN sos.begin_price_no_tax
ELSE 0
END
) AS ,
/* ---------- 入库数量 ---------- */
SUM(sos.cgdin_number) AS ,
SUM(sos.cgtin_number) AS 退,
SUM(sos.drdin_number) AS ,
SUM(sos.rkdin_number) AS ,
SUM(sos.ykrin_number) AS ,
SUM(sos.czrin_number) AS ,
/* ---------- 入库成本(除税) ---------- */
SUM(sos.cgdin_amount_no_tax) AS ,
SUM(sos.cgtin_amount_no_tax) AS 退,
SUM(sos.drdin_amount_no_tax) AS ,
SUM(sos.rkdin_amount_no_tax) AS ,
SUM(sos.ykrin_amount_no_tax) AS ,
SUM(sos.czrin_amount_no_tax) AS ,
/* ---------- 出库/退料相关数量 ---------- */
SUM(sos.pickout_number) AS ,
SUM(sos.tin_number) AS 退,
SUM(sos.dcdout_number) AS ,
SUM(sos.ckdout_number) AS ,
SUM(sos.czcout_number) AS ,
SUM(sos.ykcout_number) AS ,
/* ---------- 出库/退料相关成本(除税) ---------- */
SUM(sos.pickout_amount_no_tax) AS ,
SUM(sos.tin_amount_no_tax) AS 退,
SUM(sos.dcdout_amount_no_tax) AS ,
SUM(sos.ckdout_amount_no_tax) AS ,
SUM(sos.czcout_amount_no_tax) AS ,
SUM(sos.ykcout_amount_no_tax) AS ,
/* ---------- 期末(end_*:仅在结束日取值;>60天仅月末保留) ---------- */
SUM(
CASE
WHEN DATEDIFF(CURRENT_DATE(), STR_TO_DATE('{{%%p_end_date}}', '%Y-%m-%d')) > 60
AND DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')) <> DAY(LAST_DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')))
THEN 0
WHEN sos.bill_day = '{{%%p_end_date}}'
THEN sos.end_number
ELSE 0
END
) AS ,
SUM(
CASE
WHEN DATEDIFF(CURRENT_DATE(), STR_TO_DATE('{{%%p_end_date}}', '%Y-%m-%d')) > 60
AND DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')) <> DAY(LAST_DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')))
THEN 0
WHEN sos.bill_day = '{{%%p_end_date}}'
THEN sos.end_price
ELSE 0
END
) AS ,
SUM(
CASE
WHEN DATEDIFF(CURRENT_DATE(), STR_TO_DATE('{{%%p_end_date}}', '%Y-%m-%d')) > 60
AND DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')) <> DAY(LAST_DAY(STR_TO_DATE(sos.bill_day, '%Y-%m-%d')))
THEN 0
WHEN sos.bill_day = '{{%%p_end_date}}'
THEN sos.end_price_no_tax
ELSE 0
END
) AS
FROM rpt_customized_ndsd_storage_order_stat AS sos
WHERE 1=1
/* ---------- 固定过滤条件(按你现有配置保留) ---------- */
AND sos.id_own_group = '11240984669918396614'
AND sos.id_own_org IN ('11240984669918400634')
/* ---------- 日期区间过滤(bill_day 为文本 YYYY-MM-DD ---------- */
AND sos.bill_day >= '{{%%p_start_date}}'
AND sos.bill_day <= '{{%%p_end_date}}'
GROUP BY
sos.id_storage,
sos.part_name,
sos.custom_code,
sos.supplier_code,
sos.category_root_name,
sos.category_name;
@@ -21,8 +21,8 @@ class Main:
FORMID1 = "FORM-33666CB1XDU37AU57RKPK990C79S2YMOEEC8LS" # [表单]异常服务跟进待办2023
# 读取excel表格
df = pd.read_excel(r"C:\Users\hp_z66\Desktop\钉钉文件\(流程)续约服务流程_20260129144824.xlsx",
sheet_name='Sheet1', dtype='string', header=1) # 此处将表头设置为了第二行
df = pd.read_excel(r"C:\Users\hp_z66\OneDrive\Desktop\钉钉文件\2026-1回访已回访.xlsx",
sheet_name='Sheet5', dtype='string', header=1) # 此处将表头设置为了第二行
df.fillna('', inplace=True)
@staticmethod
@@ -28,7 +28,7 @@ class Main:
# 读取excel表格获取数据
ceshi_data = pd.read_excel(r"C:\Users\hp_z66\Desktop\钉钉文件\2025-12回访导入.xlsx",sheet_name='7天节点且联系上(自动同意)')
ceshi_data = pd.read_excel(r"C:\Users\hp_z66\OneDrive\Desktop\钉钉文件\2026-1回访已回访.xlsx",sheet_name='7天')
print("已读取表格")
# 执行自动化脚本
-479
View File
@@ -1,479 +0,0 @@
"""
API 模块
"""
import requests
import json
from typing import Optional, List, Dict, Any
from config import Config
from decimal import Decimal
import time
import numpy as np
# from log_config import configure_task_logger, configure_error_task_logger
# 获取已经配置好的常规日志记录器
# logger = configure_task_logger()
#
# # 获取已经配置好的错误任务日志记录器
# error_task_logger = configure_error_task_logger()
class NpEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(NpEncoder, self).default(obj)
def replace_decimals(obj):
if isinstance(obj, dict):
return {k: replace_decimals(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [replace_decimals(item) for item in obj]
elif isinstance(obj, Decimal):
return float(obj) # 或者 str(obj)
return obj
class API:
def entry_data_get(self, data: dict, replace: bool = False) -> Dict: # 获取单条表单数据
"""
获取单条表单数据
:param replace: 是否替换字段,默认为关
:param data: 简道云插件发送过来的data,包含应用id、表单id、数据id等信息
:return:
"""
url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/get'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 app_key
'Content-Type': 'application/json'
}
payload = json.dumps({
"app_id": data['api_key'], # 应用ID
"entry_id": data['entry_id'], # 表单ID
"data_id": data['data_id'] # 数据ID
})
res = requests.post(url=url, data=payload, headers=headers)
data_get = res.json()
print(data_get)
if replace:
data_get = self.field_replacement(data, data_get) # 字段替换,由id替换为标签名
return data_get
def entry_data_list(self, data: dict, replace: bool = False, max_retries: int = 100) -> Dict: # 获取多条表单数据
"""
获取多条表单数据
:param max_retries: 最大重试次数
:param replace: 是否替换字段
:param data:
api_key: 应用id
entry_id: 表单id
:return:
"""
url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/list'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 app_key
'Content-Type': 'application/json'
}
all_data_batches = [] # 用于存储每次请求返回的数据批次
last_data_id = None
exit_flag = False
while True:
payload = json.dumps({
"app_id": data['api_key'], # 应用ID
"entry_id": data['entry_id'], # 表单ID
"limit": 100,
"data_id": last_data_id
})
# res = requests.post(url=url, data=payload, headers=headers)
# data_get = res.json() # 此时返回的数据是一个字典
# if 'data' not in data_get or len(data_get['data']) == 0:
# break
#
# # 将当前批次的数据作为一个整体添加到 all_data_batches 中
# all_data_batches.extend(data_get['data'])
#
# last_data_id = data_get['data'][-1].get('_id')
# time.sleep(0.2)
# print(f"已获取 {len(all_data_batches)} 条数据")
retries = 0
while retries <= max_retries:
try:
res = requests.post(url=url, data=payload, headers=headers)
res.raise_for_status() # 检查HTTP响应状态码,如果不等于200会抛出异常
data_get = res.json()
# print("返回结果:", data_get)
if data_get["data"]:
all_data_batches.extend(data_get['data'])
last_data_id = data_get['data'][-1].get('_id')
print(f"已获取 {len(all_data_batches)} 条数据")
break # 成功则跳出循环
else:
if 'data' not in data_get or len(data_get['data']) == 0:
exit_flag = True
break
print("请求失败, 将重新请求")
retries += 1
time.sleep(0.1) # 在重试之间稍作停顿
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}, 将重新请求")
retries += 1
time.sleep(0.1) # 在重试之间稍作停顿
if retries > max_retries:
print(f"超过最大重试次数({max_retries}),放弃此次请求")
# error_task_logger.error(f"任务 {last_data_id}组 连续{max_retries}次请求失败,放弃此次请求。")
all_data_batches.append(None) # 或者可以选择记录失败的payload以便后续处理
if exit_flag:
break
# 构建最终返回的字典
final_data = {
'data': all_data_batches # 'data' 键对应的值是列表的列表
}
if replace:
print("进行了替换")
final_data = self.field_replacement(data, final_data) # 字段替换,由id替换为标签名
return final_data
@staticmethod
def entry_widget_list(data: dict) -> Optional[Dict[str, Any]]: # 获取表单字段
"""
获取表单字段
:param data: 简道云插件发送过来的data,包含应用id、表单id、数据id等信息
:return:
"""
url = 'https://api.jiandaoyun.com/api/v5/app/entry/widget/list'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 app_key
'Content-Type': 'application/json'
}
payload = json.dumps({
"app_id": data['api_key'],
"entry_id": data['entry_id'],
})
res = requests.post(url=url, data=payload, headers=headers)
# print(type(res.json()))
return res.json()
def field_replacement(self, data: dict, data_get: dict) -> dict: # 字段替换(id替换为标签名) json_str:请求后的返回数据
"""
字段替换,将id替换为标签名,即唯一值替换为表单中显示字段的名字
:param data: 简道云插件发送过来的data,包含表单id、数据id、应用id
:param data_get: 简道云请求的数据,一般是根据数据id获取到表单的数据
:return: 将根据数据id获取到的表单数据,进行替换,返回替换后的数据
"""
# 获取表单对应字段标签名称
widget_list = self.entry_widget_list(data)
# 检查widget_list是否有效
if not widget_list or 'widgets' not in widget_list or not isinstance(widget_list['widgets'], list):
raise ValueError("映射表没有接受到数据")
# 创建一个映射表,将_widget_名称映射到label
name_to_label = {widget['name']: widget['label'] for widget in widget_list['widgets']}
print(name_to_label)
# 遍历data_get对象中的"data"部分,替换键名
data = data_get.get('data', {})
new_data = {}
if isinstance(data, list): # 多数据查询返回list
# 当 data 是列表时执行的代码
for item in data:
new_data = {}
for key, value in item.items():
if key in name_to_label:
new_key = name_to_label[key]
else:
new_key = key
new_data[new_key] = value
item['data'] = new_data # 对每个item进行更新
elif isinstance(data, dict): # 单数据查询返回dict
# 当 data 是字典时执行的代码
for key, value in data.items():
if key in name_to_label:
new_key = name_to_label[key]
else:
new_key = key
new_data[new_key] = value
data_get['data'] = new_data # 更新JSON对象中的"data"部分
# 将更新后的JSON对象转换回JSON字符串
new_json = json.dumps(data_get, ensure_ascii=False, indent=2)
new_json = json.loads(new_json)
return new_json
@staticmethod
def data_batch_create(data: dict) -> Optional[requests.Response]: # 新建单条数据
"""
新建单条表单数据
:param data: 应该包含应用id、表单id,以及新建的数据data['data']
:return: 返回创建后简道云返回的信息
"""
url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/create'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 app_key
'Content-Type': 'application/json'
}
"""
data 样式 # 后续优化发送数据样式 目前输入字段,后续优化输入表单名称
jiandaoyun_data['data'] = {"_widget_1731650067055":{"value":f'{username}{password}'},
"_widget_1731650067056":{"value": f"{group}"}}
"""
payload = json.dumps({
"app_id": data['api_key'], # 应用ID
"entry_id": data['entry_id'], # 表单ID
"data": data['data'],
"is_start_workflow": data.get('is_start_workflow', "false"),
"is_start_trigger": data.get('is_start_trigger', "false"),
}
)
res = requests.post(url=url, data=payload, headers=headers)
data_get = res.json()
return data_get
@staticmethod
def entry_data_batch_create(
data: dict,
chunk_size: int = 90,
max_retries: int = 100
) -> List[Optional[requests.Response]]: # 新建多条数据 注意简道云限制1次最多100条数据
"""
新建多条数据
:param max_retries: 最大重试次数,此处设置100次
:param data:应包含数据id、表单id、以及需要新建的信息,新建信息应该是一个列表
:param chunk_size: 简道云限制批量新建一次最多100条,这里默认值设置为90条一次
:return:返回请求后的结果
"""
data = replace_decimals(data)
url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/batch_create'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 appKey
'Content-Type': 'application/json'
}
"""
data_list 样式 # 后续优化发送数据样式 目前输入字段,后续优化输入表单名称
jiandaoyun_data_list['data_list'] = [{"_widget_1731650067055":{"value":f'{username}{password}'},
"_widget_1731650067056":{"value": f"{group}"}},
{"_widget_1731650067055":{"value":f'{username}{password}'},
"_widget_1731650067056":{"value": f"{group}"}}]
"""
# 获取data_list长度
total_length = len(data['data_list'])
print(f"多数据写入行数: {total_length}")
# 计算需要发送的次数
num_chunks = (total_length + chunk_size - 1) // chunk_size # //整除向下取证,需要加上chunk_size - 1保证不会有缺失数据
print(num_chunks)
data_get_list = []
for i in range(num_chunks):
start_index = i * chunk_size
end_index = min(start_index + chunk_size, total_length)
payload = json.dumps({
"app_id": data['api_key'], # 应用ID
"entry_id": data['entry_id'], # 表单ID
"data_list": data['data_list'][start_index:end_index],
"is_start_workflow": data.get('is_start_workflow', "false"),
"is_start_trigger": data.get('is_start_trigger', "false"),
}, cls=NpEncoder)
retries = 0
while retries <= max_retries:
try:
res = requests.post(url=url, data=payload, headers=headers)
res.raise_for_status() # 检查HTTP响应状态码,如果不等于200会抛出异常
data_get = res.json()
print(i, "返回结果:", data_get)
if data_get["status"] == "success":
data_get_list.append(data_get)
break # 成功则跳出循环
else:
print("请求失败, 将重新请求")
retries += 1
time.sleep(0.1) # 在重试之间稍作停顿
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}, 将重新请求")
retries += 1
time.sleep(0.1) # 在重试之间稍作停顿
if retries > max_retries:
print(f"超过最大重试次数({max_retries}),放弃此次请求")
# error_task_logger.error(
# f"任务 {data['data_list'][start_index:end_index]} 连续{max_retries}次请求失败,放弃此次请求。")
data_get_list.append(None) # 或者可以选择记录失败的payload以便后续处理
return data_get_list
@staticmethod
def entry_data_update(data: dict, max_retries: int = 100) -> dict: # 修改数据
"""
修改数据
:param max_retries: 最大重试次数,此处设置100次
:param data: 简道云插件发送过来的data,包含应用id、表单id、数据id等信息
:return: 修改数据后简道云返回的结果
"""
url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/update'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 appKey
'Content-Type': 'application/json'
}
payload = json.dumps({
"app_id": data['api_key'], # 应用ID
"entry_id": data['entry_id'], # 表单ID
"data_id": data['data_id'], # 数据ID
"data": data['data']
}
)
print(payload)
data_get = None
retries = 0
while retries <= max_retries:
try:
res = requests.post(url=url, data=payload, headers=headers)
res.raise_for_status() # 检查HTTP响应状态码,如果不等于200会抛出异常
data_get = res.json()
print("返回结果:", data_get)
if res.status_code == 200:
break # 成功则跳出循环
else:
print("请求失败, 将重新请求")
retries += 1
time.sleep(0.1) # 在重试之间稍作停顿
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}, 将重新请求")
retries += 1
time.sleep(10) # 在重试之间稍作停顿
if retries > max_retries:
print(f"超过最大重试次数({max_retries}),放弃此次请求")
# error_task_logger.error(f"任务 {data['data_id']} 连续{max_retries}次请求失败,放弃此次请求。")
continue
return data_get
@staticmethod
def entry_data_delete(data: dict, max_retries: int = 100, ) -> dict:
url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/delete'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 appKey
'Content-Type': 'application/json'
}
payload = json.dumps({
"app_id": data['api_key'], # 应用ID
"entry_id": data['entry_id'], # 表单ID
"data_id": data['data_id'], # 数据ID
}
)
retries = 0
delete_status = None
while retries <= max_retries:
try:
res = requests.post(url=url, data=payload, headers=headers)
delete_status = res.json()
# 手动处理状态码 4001
if delete_status == {
"code": 4001,
"msg": "Data does not exist."
}:
print("返回结果:", delete_status)
break # 成功则跳出循环
# 检查其他状态码
res.raise_for_status() # 只对非 4001 的状态码进行检查
print("返回结果:", delete_status)
if res.status_code == 200 :
break # 成功则跳出循环
else:
print("请求失败, 将重新请求")
retries += 1
time.sleep(0.1) # 在重试之间稍作停顿
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}, 将重新请求")
retries += 1
time.sleep(10) # 在重试之间稍作停顿
if retries > max_retries:
print(f"超过最大重试次数({max_retries}),放弃此次请求")
# error_task_logger.error(f"任务 {data['data_id']} 连续{max_retries}次请求失败,放弃此次请求。")
continue
return delete_status
@staticmethod
def workflow_instance_get(data: dict) -> dict:
"""
查询实例流程信息
:param data: 简道云插件发送过来的data,包含应用id
:return: 查询简道云流程实例信息返回的结果
"""
url = 'https://api.jiandaoyun.com/api/v5/workflow/instance/get'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 appKey
'Content-Type': 'application/json'
}
payload = json.dumps({
"instance_id": data['data_id'],
"tasks_type": 1
}
)
res = requests.post(url=url, data=payload, headers=headers)
return res.json()
@staticmethod
def workflow_task_approve(data: dict) -> dict:
"""
流程待办提交
:param data:应包含username、instance_id(data_id)、task_id等信息
:return:返回简道云流程待办提交的结果
"""
url = 'https://api.jiandaoyun.com/api/v1/workflow/task/approve'
headers = {
'Authorization': Config.JIANDAOYUN_API_TOKEN, # 曹伟应用api测试 appKey
'Content-Type': 'application/json'
}
payload = json.dumps({
"username": data["username"],
"instance_id": data["instance_id"],
"task_id": data['task_id'],
"comment": "自动转交"
}
)
res = requests.post(url=url, data=payload, headers=headers)
return res.json()
@@ -1,67 +0,0 @@
import requests
import pandas as pd
import os
from typing import Dict, Any
from api import API
import time
from tqdm import tqdm
api_instance = API()
def update_jiandaoyun(data: Dict[str, Any], results: str):
""" 更新简道云表单 """
# 定义简道云数据配置
jiandaoyun_data = {
'api_key': data['api_key'],
'entry_id': data['entry_id'],
'data_id': data['data_id'],
"data": {
'_widget_1731379774828': {"value": "已执行"}, # f6系统批量操作测试 是否执行成功
'_widget_1731381334870': {"value": results} # f6系统批量操作测试 执行明细
}
}
time.sleep(1)
print(jiandaoyun_data)
api_instance.entry_data_update(jiandaoyun_data)
print('更新简道云表单成功')
def create_brand_background(data: Dict[str, Any], cookies: Dict[str, str], df: pd.DataFrame, save_path: str):
# 定义请求URL
url = 'https://yunxiu.f6car.cn/camaro/brand/getOrCreate'
# 遍历DataFrame中的每一行数据
results = []
for index, row in tqdm(df.iterrows(), total=df.shape[0], desc="创建品牌"):
brand_name = row['品牌名']
try:
response = requests.post(url, cookies=cookies, json={"brandName": brand_name})
response.raise_for_status() # 抛出HTTP错误
results.append({'品牌名': brand_name, '状态': '创建成功'})
except requests.exceptions.RequestException as e:
results.append({'品牌名': brand_name, '状态': f'创建失败: {str(e)}'})
print({'msg': '已执行', 'msg_details': f'{results}'})
os.remove(save_path)
print(f'{save_path}已删除')
print(data)
# 调用api回写改掉 执行明细与执行状态
update_jiandaoyun(data, f'{results}')
def delete_history_background(data: Dict[str, Any], cookies: Dict[str, str], org_id: str, org_name: str):
url = f'https://yunxiu.f6car.cn/maintain-dump/maintainHistory/?orgid={org_id}' # 删除url
res = requests.delete(url=url, cookies=cookies)
res_data = res.json()
if res.status_code == 200 and res_data.get('code') == 200:
results = f'{org_name} 历史维修记录已删除'
print(results)
else:
results = f'删除 {org_name} 历史维修记录失败: {res_data.get("message")}'
print(results)
# 调用api回写改掉 执行明细与执行状态
time.sleep(1)
update_jiandaoyun(data, f'{results}')
-33
View File
@@ -1,33 +0,0 @@
# config.py
"""
配置类,负责加载和提供项目配置。
"""
class Config:
CONN_INFO = {
"database": "f6_bi",
"user": "BASIC$ro_caowei",
"password": "!ro_caowei123",
"host": "hgprecn-cn-nif1vnv0y002-cn-shanghai.hologres.aliyuncs.com",
"port": "80"
} # SaaS-NGV 数据库链接配置-postgresql
# 接车宝数据库链接配置-mysql
JCB_CONN_INFO_database = "f6insight_gzczj"
JCB_CONN_INFO_user = "rw_insight_gzczj"
JCB_CONN_INFO_password = "wEBT5LBHzbbhJisheCsE"
JCB_CONN_host = "rm-uf6r230vbtxf5gdz63o.mysql.rds.aliyuncs.com"
JIANDAOYUN_API_TOKEN = 'Bearer qygHulymo1fekJk4CIZyNKjyQAzG8CFN' # token
EFFICIENT_CAR_PICKUP_APP_ID = "6717470a0b3975ef583c6df1" # 接车宝应用id
SCHEDULED_TASKS_APP_ID = "6694d3c4fcb69ca9a111a6c4" # 数据支持应用id
SaaS_Tasks_APP_ID = "675b900991ad2491c69389ca" # saas日常回访应用id
SCHEDULED_TASKS_ENTRY_ID = "6760e5e7672af4621ab8128a" # 定时任务表单id
NGV_TASKS_ENTRY_ID = "675bb02bd2d53c2034c665e4" # NGV任务表单id
EFFICIENT_CAR_PICKUP_ENTRY_ID = "67174710da507490d8ac12c1" # 接车宝表单id
EFFICIENT_CAR_PICKUP_CUSTOMER_SERVICE_ID = "67b6f2462f9ac03b783d409a" # 接车宝客服表单id
EFFICIENT_CAR_PICKUP_CUSTOMER_HISTORY_ID = "67c156ba635191b64af8a110" # 接车宝历史派发表单
-171
View File
@@ -1,171 +0,0 @@
from flask import Flask, request, jsonify
from module import module, F6_Plugin_module
from urllib.parse import unquote
from config import Config
import queue
import threading
import logging
import os
from logging.handlers import RotatingFileHandler
from apscheduler.schedulers.background import BackgroundScheduler
import requests
import atexit
app = Flask(__name__)
app.config.from_object(Config)
f6_module = module.F6Module()
f6_plugin_module = F6_Plugin_module.F6PluginModule()
# 定义一个映射表,将操作与处理函数关联起来
action_map = {
'login_in': f6_module.accept_login_message,
'get_company_information': f6_module.get_company_information,
'get_store_information': f6_module.get_store_information,
"keep_alive": f6_module.get_keep_heart,
'check_file': f6_plugin_module.check_file,
'create_brand': f6_plugin_module.create_brand,
'delete_history': f6_plugin_module.delete_history,
# 'delete_customer': f6_plugin_module.delete_customer,
# 'delete_cars': f6_plugin_module.delete_cars,
}
# 创建一个消息队列
task_queue = queue.Queue()
# 创建一个线程来处理队列中的任务
def process_tasks():
while True:
task = task_queue.get()
if task is None:
logger.error("任务处理线程已终止")
break # 停止处理任务
try:
result = task['handler'](task['data'])
task['response'].put(result)
except Exception as e:
logger.error(f"任务执行失败: {str(e)}")
task['response'].put({'msg': f'任务执行失败: {str(e)}'})
finally:
task_queue.task_done()
logger.info("任务处理完成")
# 启动任务处理线程
task_thread = threading.Thread(target=process_tasks, daemon=True)
task_thread.start()
# 配置日志记录器
log_dir = './日志' # 日志文件夹路径
if not os.path.exists(log_dir):
os.makedirs(log_dir) # 如果日志文件夹不存在,则创建它
log_file = os.path.join(log_dir, '简道云日志.log')
# 设置日志格式和级别
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# 创建RotatingFileHandler,支持日志文件滚动
file_handler = RotatingFileHandler(log_file, maxBytes=1024 * 1024 * 5, backupCount=5)
file_handler.setLevel(logging.INFO)
# 定义日志格式
formatter = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s')
file_handler.setFormatter(formatter)
# 将处理器添加到记录器
logger.addHandler(file_handler)
# 将Flask的默认日志记录器也配置为使用相同的处理器
app.logger.addHandler(file_handler)
# 创建一个后台调度器
scheduler = BackgroundScheduler()
# 定义一个定时任务,定期发送心跳请求以保持服务活跃
def keep_alive():
try:
data = {
'Action': 'keep_alive'
}
header = {
'Action': 'keep_alive'
}
# 发送一个GET请求到自己的API端点,模拟活动
response = requests.post(url='http://192.168.10.86:5000/webhook', data=data, headers=header, timeout=5)
if response.status_code == 200:
logger.info("Heartbeat sent successfully")
else:
logger.warning(f"Heartbeat failed with status code: {response.status_code}")
except requests.RequestException as e:
logger.error(f"Failed to send heartbeat: {e}")
# 添加定时任务,每隔1分钟执行一次
scheduler.add_job(keep_alive, 'interval', minutes=1)
# 启动调度器
scheduler.start()
# 确保在应用退出时关闭调度器
atexit.register(lambda: scheduler.shutdown())
@app.route('/webhook', methods=['POST'])
def webhook():
logging.info('Received POST request to /webhook')
"""
接受前端请求后将任务放入消息队列
Returns:
any: 返回任务处理的结果
"""
# 获取请求体中的 JSON 数据
data = request.json
header = request.headers
header = decode_headers(header)
action = header.get('Action')
if action == 'F6_Plugin':
check = header.get('Check')
if check == '':
handler = f6_plugin_module.check_file
elif check == '':
sub_action = data.get('Action')
handler = action_map.get(sub_action, lambda x: {'msg': '未执行'})
else:
return jsonify({'msg': '未知的操作'})
else:
handler = action_map.get(action, lambda x: {'msg': '未知的操作'})
# 创建一个队列用于存储任务处理结果
response_queue = queue.Queue()
# 将任务放入消息队列
task_queue.put({
'handler': handler,
'data': data,
'response': response_queue
})
# 等待任务处理结果
result = response_queue.get()
return jsonify(result)
def decode_headers(headers):
"""
解码包含中文字符的 HTTP 请求头。
:param headers: 包含编码后头部字段的字典
:return: 解码后的头部字段字典
"""
return {key: unquote(value, encoding='utf-8') for key, value in headers.items()}
if __name__ == '__main__':
# from waitress import serve
# serve(app, host='192.168.10.86', port=5000)
app.run(debug=True, port=5000)
@@ -1,315 +0,0 @@
import requests
from urllib.parse import quote
import pandas as pd
import os
import urllib.parse
import time
from datetime import datetime
from api import API
from typing import Optional, Dict, Any, Tuple
from config import Config
from module.module import F6Module
import threading
import back_ground_tasks
api_instance = API()
class F6PluginModule:
@staticmethod
def accept_file(data: Dict[str, Any]) -> Tuple[Optional[str], Dict[str, Any]]: # 接收文件
"""
接收文件。
此方法用于处理前端上传的文件,下载文件并保存到指定目录。主要步骤包括:
1. 处理前端传递的数据,获取文件的URL。
2. 解析URL以获取文件名。
3. 根据当前时间生成新的文件名,以避免文件名冲突。
4. 下载文件并保存到指定目录。
5. 返回文件保存路径和处理后的数据。
Args:
data (dict): 包含文件URL和其他必要信息的字典。
Returns:
tuple: 包含文件保存路径和处理后的数据的元组。如果文件保存成功,返回保存路径和数据;如果失败,返回 None 和数据。
"""
data = api_instance.entry_data_get(data=data)
try:
url = data['data']['附件'][0]['url']
print(url)
except Exception as e:
print(f'上传url未读取到,或无上传文件:{e}')
save_path = ''
return save_path, data
parsed_url = urllib.parse.urlparse(url)
query_params = urllib.parse.parse_qs(parsed_url.query)
attname = query_params.get('attname', [''])[0]
filename = urllib.parse.unquote(attname)
# 获取当前时间并格式化为指定格式的字符串
timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
# 分离文件名和扩展名
name_part, ext_part = filename.rsplit('.', 1) if '.' in filename else (filename, '')
# 构建新文件名
new_filename = f"{name_part}{timestamp}.{ext_part}" if ext_part else f"{name_part}{timestamp}"
save_path = os.path.join(Config.SAVE_DIRECTORY, new_filename)
print(save_path)
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(save_path, 'wb') as file:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
file.write(chunk)
return save_path, data
else:
return None, data
def check_file(self, data: Dict[str, Any]) -> Dict[str, str]: # 校验上传文件
"""
校验上传文件。
此方法负责接收前端上传的文件,并根据文件类型和操作指令进行相应的校验。主要步骤包括:
1. 调用 `accept_file` 方法处理前端传递的数据,获取文件保存路径和处理后的数据。
2. 根据数据中的 `Action` 字段判断需要执行的操作类型。
3. 如果文件保存路径有效,继续执行以下步骤:
- 如果操作类型为 `create_brand`,则读取文件和模板文件,校验文件格式是否正确。
- 如果文件格式正确,返回成功消息;否则返回错误消息。
4. 如果文件保存路径无效,返回相应的错误消息。
5. 如果读取文件过程中发生异常,捕获异常并返回错误消息。
Args:
data (dict): 前端请求发送过来的数据,包含文件信息和其他必要参数。
Returns:
dict: 包含文件校验结果的消息字典。如果校验成功,则返回文件路径和校验标志;如果失败,则返回错误消息。
"""
save_path, data1 = self.accept_file(data)
action = data1['data']['Action(隐藏)']
if save_path:
try:
if action == 'create_brand':
template_path = os.path.join(Config.MODE_DIRECTORY, '品牌名.xlsx')
# 读取指定的工作表
df1 = pd.read_excel(save_path, sheet_name='品牌名')
df2 = pd.read_excel(template_path, sheet_name='品牌名')
if df1.columns.tolist() == df2.columns.tolist(): # 校验表头名字
print('文件校验成功')
return {'msg': f'{save_path}', 'check': ''}
else:
print("'msg':'文件上传格式错误'")
return {'msg': '文件上传格式错误'}
elif action == 'delete_customer':
pass
elif action == 'delete_cars':
pass
else:
pass
except Exception as e:
return {'msg': f'读取Excel文件失败: {str(e)},文件路径:{save_path}'}
else:
return {'msg': '当前节点无附件上传', 'check': ''} # 注意前端上传url必须为必填的,否则这个返回会出现错误
@staticmethod
def create_brand(data: Dict[str, Any]) -> Dict[str, str]: # 创建品牌
"""
创建品牌函数。
此方法用于处理前端发送的品牌创建请求,并执行相应的品牌创建逻辑。
Args:
data (dict): 包含品牌信息及用户凭证等数据的字典。
Returns:
dict: 包含操作结果的消息字典。如果操作成功,则返回成功消息和详情;如果失败,则返回错误消息。
Process:
1. 调用 `entry_data_get` 方法处理前端传递的数据。
2. 从处理后的数据中提取用户名、密码、公司名称以及文件保存地址。
3. 使用提供的用户名和密码尝试登录。
4. 如果登录失败,立即返回错误消息。
5. 登录成功后,读取指定路径的Excel文件,该文件应包含待创建品牌的列表。
6. 若读取Excel文件失败,返回相应的错误消息。
7. 利用登录获取到的cookies构造请求头,准备发起创建品牌的POST请求。
8. 遍历Excel文件中的每一条记录(即每个品牌),向指定的API发送创建请求。
9. 每个品牌的创建结果(成功或失败)都会被记录下来。
10. 所有品牌的创建请求完成后,删除原始的Excel文件。
11. 最后,将所有操作的结果汇总成字典并返回给调用者。
"""
entry_data = api_instance.entry_data_get(data=data) # 获取表单数据
# print(data)
print('执行 品牌批量新建')
username = entry_data['data']['账号']
password = entry_data['data']['密码']
company_name = entry_data['data']['公司名称']
save_path = entry_data['data']['文件保存地址']
# 尝试登录
login_response = F6Module.login_in(username, password, company_name)
if login_response is None:
return {'msg': '登录失败'}
# 读取Excel文件
try:
df = pd.read_excel(save_path, dtype='string')
except Exception as e:
return {'msg': f'读取Excel文件失败: {str(e)},文件路径:{save_path}'}
# 获取登录cookies
cookies = requests.utils.dict_from_cookiejar(login_response.cookies)
# 启动后台线程执行品牌创建任务
try:
thread = threading.Thread(target=back_ground_tasks.create_brand_background, args=(data, cookies, df, save_path))
thread.start()
except Exception as e:
print(f'创建线程失败: {str(e)}')
# 立即返回消息
return {'msg': '正在执行', 'msg_details': '正在执行,请稍后看结果'}
@staticmethod
def delete_history(data: Dict[str, Any]) -> Dict[str, str]: # 删除历史维修记录
# endregion
"""
删除历史维修记录。
此方法用于处理用户的请求,删除指定门店的历史维修记录。主要步骤包括:
1. 处理前端传递的数据,提取必要的登录信息和门店信息。
2. 尝试登录系统,获取登录cookies。
3. 获取所有门店的信息,找到与用户提供的门店名称匹配的门店ID。
4. 使用门店ID发送删除请求,删除历史维修记录。
5. 返回操作结果。
Args:
data (dict): 包含登录信息和门店信息的字典。
Returns:
dict: 包含操作结果的消息字典。如果删除成功,返回成功消息和详细信息;如果失败,返回错误消息。
"""
entry_data = api_instance.entry_data_get(data=data) # 获取表单数据,将ID替换为中文
username = entry_data['data']['账号']
password = entry_data['data']['密码']
company_name = entry_data['data']['公司名称']
org_name = entry_data['data']['门店名称']
login_response = F6Module.login_in(username, password, company_name) # 尝试登录
if login_response is None:
return {'msg': '未执行', 'msg_details': '登录失败'}
# 获取登录cookies
cookies = requests.utils.dict_from_cookiejar(login_response.cookies)
# 获取门店列表
url = 'https://yunxiu.f6car.cn/hive/org/getPageOrgGroupMembers?currentPage=1&pageSize=1000&name=' # 获取门店名称url
res = requests.get(url=url, cookies=cookies)
store_data = res.json()
org_lists = store_data['data']['list']
org_id = ''
org_name1 = ''
for org in org_lists: # 确认删除门店信息
org_name1 = org['orgName']
if org_name == org['orgName']:
org_id = org['orgId']
if org_id:
# 启动后台线程执行删除任务
thread = threading.Thread(target=back_ground_tasks.delete_history_background, args=(data, cookies, org_id, org_name1))
thread.start()
# 立即返回消息
return {'msg': '正在执行中', 'msg_details': '请稍后查看结果'}
else:
return {'msg': '未执行', 'msg_details': '门店信息错误'}
@staticmethod
def delete_customer(data): # 客户信息删除(删除所有客户信息)
username = data['username']
password = data['password']
company_name = data['company_name']
res = F6Module.login_in(username, password, company_name)
if res is not None:
cookies = requests.utils.dict_from_cookiejar(res.cookies)
url = "https://yunxiu.f6car.cn/member/customer/listForPermission?pageSize=5&pageNo=1" # 获取客户信息列表
res = requests.get(url, cookies=cookies)
json = res.json()
for item in json['data']['data']:
idCustomer = item['idCustomer']
phone = item['cellPhone']
try:
url = f"https://yunxiu.f6car.cn/member/customer/{idCustomer}" # 客户信息删除url
res = requests.delete(url, cookies=cookies) # 客户信息删除
print(res.json, idCustomer, phone)
time.sleep(0.2)
except Exception as e:
print("删除失败,", res.json, idCustomer, phone, e)
@staticmethod
def delete_cars(data):
"""
删除客户车辆信息
参数:
data (dict): 包含用户名、密码和公司名称的字典。
- username (str): 用户名
- password (str): 密码
- company_name (str): 公司名称
返回:
功能描述:
1. 使用提供的用户名、密码和公司名称登录系统。
2. 如果登录成功,获取登录后的 cookies 和操作组织 ID。
3. 发送 POST 请求获取客户车辆信息列表。
4. 遍历车辆信息列表,逐个删除客户车辆信息。
5. 每次删除操作后,打印删除成功或失败的信息,并暂停 0.2 秒。
"""
username = data['username']
password = data['password']
company_name = data['company_name']
res = F6Module.login_in(username, password, company_name)
if res is not None:
cookies = requests.utils.dict_from_cookiejar(res.cookies)
operateOrgId = cookies['prodOrg']
url = "https://yunxiu.f6car.cn/member/car/carListForPermission" # 获取客户车辆信息列表
header = {
'Referer': 'https://yunxiu.f6car.cn/erp/view/index.html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
}
data = {"pageSize": 10, "pageNo": 2} # 根据需求修改
res = requests.post(url=url, cookies=cookies, json=data, headers=header) # 注意需要用json发送数据
data = res.json()
for item in data['data']['data']:
carId = item['tmCarInfo']['pkId']
customerId = item['tmCustomerInfo']['pkId']
try:
url = f"https://yunxiu.f6car.cn/macan/coupon/car/batchRemove?customerId={customerId}&carId={carId}&operateOrgId={operateOrgId}" # 删除客户车辆信息url
res = requests.delete(url, cookies=cookies) # 客户车辆信息删除
print("删除成功:", res.json, customerId, carId)
time.sleep(0.2)
except Exception as e:
print("删除失败:", res.json, customerId, operateOrgId, e)
-232
View File
@@ -1,232 +0,0 @@
import requests
import hashlib
from urllib.parse import quote
from datetime import datetime
from api import API
from typing import Optional, Dict
api_instance = API()
class F6Module:
@staticmethod
def login_in(username: str, password: str, company_name: str = '默认门店') -> Optional[requests.Response]:
"""
登录模块。
此方法用于处理用户的登录请求,包括认证和选择门店的整个过程。
Args:
username (str): 用户名。
password (str): 密码。
company_name (str, optional): 默认为 '默认门店',表示用户要登录的门店名称。
Returns:
Response or None: 如果登录成功,返回包含登录信息的响应对象;如果登录失败,返回 None。
"""
url = "https://yunxiu.f6car.com/kzf6/login/confirm"
session = requests.Session()
header = {
'Referer': url,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/129.0.0.0'
}
data = {
'username': username,
'password': hashlib.md5(password.encode('utf-8')).hexdigest(),
}
try:
res = session.post(url=url, headers=header, data=data)
res_json = res.json()
if res_json.get("data") is None:
return res
else:
group_id = ''
for group in res_json.get('data', []):
if group["groupName"] == company_name:
group_id = group.get("groupId")
token = quote(res_json['token']) # URL 编码
url = f'https://yunxiu.f6car.cn/kzf6/user/loginAfterChooseGroup?token={token}&groupId={group_id}&macAddress='
res1 = session.get(url, cookies=res.cookies)
return res1
except Exception as e:
print(f"Error during login: {e}")
return None
def accept_login_message(self, data: Dict[str, str]) -> Dict[str, str]: # 获取登录信息
"""
获取登录信息。
此方法用于处理用户的登录请求,验证登录信息的正确性,并返回相应的登录状态。
Args:
data (dict): 包含用户名、密码和门店名称的字典。
Returns:
dict: 包含登录状态的消息字典。
"""
username = data['username']
password = data['password']
company_name = data['company_name']
res = self.login_in(username, password, company_name)
if res is not None:
cookies = requests.utils.dict_from_cookiejar(res.cookies)
json = res.json()
url = 'https://yunxiu.f6car.cn/hive/company/getGroupName'
res1 = requests.get(url=url, cookies=cookies)
data1 = res1.json()
if data1['code'] == 200:
if data1['data'] == company_name:
if json['status'] == 'success':
json['status'] = '登录成功'
elif json['status'] == 'Error':
json['status'] = '登录失败,请检查账号密码'
else:
json['status'] = '公司名称不正确,请重试'
else:
json['status'] = '请输入正确的账号密码并选择公司名称'
return json
else:
return {"status": "登录失败,请检查公司名称"}
def get_company_information(self, data: Dict[str, str]) -> Dict[str, str]: # 获取登录账号下公司信息
"""
获取登录账号下公司信息。前端事件触发
此方法用于处理用户的登录请求,获取与该用户关联的所有门店名称。
Args:
data (dict): 包含用户名和密码的字典。
Returns:
dict: 包含门店信息的消息字典。如果成功获取门店信息,返回门店列表;如果失败,返回错误消息。
"""
username = data['username']
password = data['password']
timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
print(username)
url = "https://yunxiu.f6car.com/kzf6/login/confirm"
session = requests.Session()
header = {
'Referer': url,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
}
data = {
'username': username,
'password': hashlib.md5(password.encode('utf-8')).hexdigest(),
}
try:
res = session.post(url=url, headers=header, data=data)
res_json = res.json()
if res_json.get('message') == '请输入图形验证码':
pass
# 添加公司名称映射表单ID应用ID
jiandaoyun_data = {'api_key': '6694d3c4fcb69ca9a111a6c4', 'entry_id': '6736e2112ad50045f041a827'}
if res_json.get("data") is None:
print('单店')
res = self.login_in(username, password)
if res is not None:
cookies = requests.utils.dict_from_cookiejar(res.cookies)
url = 'https://yunxiu.f6car.cn/hive/company/getGroupName' # 获取门店名称url
res = requests.get(url=url, cookies=cookies)
data = res.json()
store_name = data['data'] # 获取店铺名称
jiandaoyun_data['data_list'] = [
{"_widget_1731650067055": {"value": f'{username}{password}{timestamp}'}, # 公司名称映射表 公司名称唯一值
"_widget_1731650067056": {"value": f"{store_name}"}}] # 公司名称映射表 公司名称
api_instance.entry_data_batch_create(jiandaoyun_data) # 调用api写入数据
res = {'msg': f'{username}{password}{timestamp}'}
else:
jiandaoyun_data_list = []
for group in res_json.get('data', []):
append_data = {"_widget_1731650067055": {"value": f'{username}{password}{timestamp}'},
"_widget_1731650067056": {"value": f"{group['groupName']}"}}
jiandaoyun_data_list.append(append_data)
jiandaoyun_data['data_list'] = jiandaoyun_data_list
res = api_instance.entry_data_batch_create(jiandaoyun_data) # 调用api写入数据
print(res)
res = {'msg': f'{username}{password}{timestamp}'}
return res
except Exception as e:
print(f"获取公司名称失败: {e}")
res = {'msg': '获取公司名称失败,请重新获取'}
return res
def get_store_information(self, data: Dict[str, str]) -> Dict[str, str]: # 获取登录公司下门店信息
"""
获取门店登录信息。前端事件触发
此方法用于处理用户的登录请求,获取与该用户关联的所有门店名称,并将这些信息连同用户登录信息一并记录至简道云表单中。
Args:
data (dict): 包含用户名、密码及公司名称的字典。
Returns:
dict: 包含操作结果的消息字典。如果成功获取门店信息并记录至简道云,返回成功消息及记录信息;如果登录或数据记录过程中出现错误,返回相应的错误消息。
"""
username = data['username']
password = data['password']
company_name = data['company_name']
timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
login_response = self.login_in(username, password, company_name) # 尝试登录
if login_response is None:
return {'msg': '未执行', 'msg_details': '登录失败'}
# 获取登录cookies
cookies = requests.utils.dict_from_cookiejar(login_response.cookies)
# 获取门店列表
url = 'https://yunxiu.f6car.cn/hive/org/getPageOrgGroupMembers?currentPage=1&pageSize=100&name=' # 获取门店名称url
res = requests.get(url=url, cookies=cookies)
data = res.json()
org_lists = data['data']['list']
# print(org_lists)
# noinspection SpellCheckingInspection
jiandaoyun_data = {'api_key': '6694d3c4fcb69ca9a111a6c4',
'entry_id': '673c38ccca57a5cf266eb18c'} # 添加公司名称映射表单ID应用ID
jiandaoyun_data_list = []
for org in org_lists:
append_data = {"_widget_1731999948708": {"value": f'{username}{password}{company_name}{timestamp}'},
# 公司门店映射表 公司名称唯一值
"_widget_1731999948709": {"value": f"{org['orgName']}"}} # 公司门店映射表 公司名称
jiandaoyun_data_list.append(append_data)
jiandaoyun_data['data_list'] = jiandaoyun_data_list
api_instance.entry_data_batch_create(jiandaoyun_data) # 调用api写入数据
res = {'msg': f'{username}{password}{company_name}{timestamp}'}
return res
@staticmethod
def get_keep_heart(data: Dict[str, str]) -> Dict[str, str]:
"""
获取心跳信息。前端事件触发
Args:
data(dict):包含心跳内容
returns:
dict:返回心跳内容
"""
return data
-17
View File
@@ -1,17 +0,0 @@
from api import API
import pandas as pd
from config import Config
api_instance = API()
df = pd.read_excel(r"C:\Users\Administrator.DESKTOP-7IC2USJ\Downloads\接车宝日常回访单_20250313091252.xlsx",
sheet_name='Sheet3', dtype='string')
for index,row in df.iterrows():# 在列表格式固定
data_id = row['data_id']
delete_data = {"api_key": Config.EFFICIENT_CAR_PICKUP_APP_ID,
"entry_id": "67174710da507490d8ac12c1",
"data_id": data_id}
api_instance.entry_data_delete(delete_data)
@@ -0,0 +1,655 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "f698c340",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 8,
"id": "8800f2ff",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"正在筛选日期为:2026-02-23 的任务...\n",
"正在从简道云获取源数据...\n",
"已获取 73 条数据\n",
"API 返回原始数据条数: 73\n",
"{'_id': '699b9891bb267647270882ac', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:00:17.084Z', 'updateTime': '2026-02-23T00:00:17.084Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T00:00:01.000Z', '_widget_1744873387502': '2026-02-23T00:00:16.000Z', '_widget_1744873387504': '15', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b98cbe276a38cb2450192', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:01:15.225Z', 'updateTime': '2026-02-23T00:01:15.225Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '省市区人员关系表转BI', '_widget_1744873387501': '2026-02-23T00:00:22.000Z', '_widget_1744873387502': '2026-02-23T00:01:14.000Z', '_widget_1744873387504': '52', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b98da14a266a4faaec87b', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:01:30.245Z', 'updateTime': '2026-02-23T00:01:30.245Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '非标业绩提报转BI', '_widget_1744873387501': '2026-02-23T00:01:22.000Z', '_widget_1744873387502': '2026-02-23T00:01:29.000Z', '_widget_1744873387504': '7', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b98e7506e3a1c9db63a1a', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:01:43.368Z', 'updateTime': '2026-02-23T00:01:43.368Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T00:00:01.000Z', '_widget_1744873387502': '2026-02-23T00:01:42.000Z', '_widget_1744873387504': '101', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b992c654487d78fad28d4', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:02:52.229Z', 'updateTime': '2026-02-23T00:02:52.229Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '合伙人结算登记同步到BI', '_widget_1744873387501': '2026-02-23T00:02:22.000Z', '_widget_1744873387502': '2026-02-23T00:02:51.000Z', '_widget_1744873387504': '29', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b9956ed29cdb3bc0359a0', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:03:34.573Z', 'updateTime': '2026-02-23T00:03:34.573Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '分母报备调整', '_widget_1744873387501': '2026-02-23T00:03:22.000Z', '_widget_1744873387502': '2026-02-23T00:03:34.000Z', '_widget_1744873387504': '12', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b99c5c92edf9a18ddd2e5', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:05:25.913Z', 'updateTime': '2026-02-23T00:05:25.913Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '经销商新签服务单转BI', '_widget_1744873387501': '2026-02-23T00:05:23.000Z', '_widget_1744873387502': '2026-02-23T00:05:25.000Z', '_widget_1744873387504': '2', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b9a023fa4592f7ff27d2b', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:06:26.403Z', 'updateTime': '2026-02-23T00:06:26.403Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '分子报备调整', '_widget_1744873387501': '2026-02-23T00:06:23.000Z', '_widget_1744873387502': '2026-02-23T00:06:26.000Z', '_widget_1744873387504': '3', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699b9f36faa412358146bcec', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:28:38.775Z', 'updateTime': '2026-02-23T00:28:38.775Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '海外邮件推送', '_widget_1744873387501': '2026-02-23T00:28:26.000Z', '_widget_1744873387502': '2026-02-23T00:28:38.000Z', '_widget_1744873387504': '12', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ba149bb2676472710a0fe', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T00:37:29.703Z', 'updateTime': '2026-02-23T00:37:29.703Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云海外项目CRM客户档案迁移BI', '_widget_1744873387501': '2026-02-23T00:37:28.000Z', '_widget_1744873387502': '2026-02-23T00:37:29.000Z', '_widget_1744873387504': '1', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ba696205acb4b4cadef32', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:00:06.276Z', 'updateTime': '2026-02-23T01:00:06.276Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T01:00:02.000Z', '_widget_1744873387502': '2026-02-23T01:00:05.000Z', '_widget_1744873387504': '3', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ba6fda0e00405891ad3fa', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:01:49.001Z', 'updateTime': '2026-02-23T01:01:49.001Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T01:00:02.000Z', '_widget_1744873387502': '2026-02-23T01:01:48.000Z', '_widget_1744873387504': '106', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ba91f5debe6469c395fb9', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:10:55.697Z', 'updateTime': '2026-02-23T01:10:55.697Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '接车宝日常派发', '_widget_1744873387501': '2026-02-23T01:10:32.000Z', '_widget_1744873387502': '2026-02-23T01:10:55.000Z', '_widget_1744873387504': '23', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bacabded5b58a521b70f0', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:26:03.296Z', 'updateTime': '2026-02-23T01:26:03.296Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '新签客户回访', '_widget_1744873387501': '2026-02-23T01:05:32.000Z', '_widget_1744873387502': '2026-02-23T01:26:02.000Z', '_widget_1744873387504': '1230', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bb02f057a5fdbf0f7a2ff', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:41:03.569Z', 'updateTime': '2026-02-23T01:41:03.569Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '续约客户回访', '_widget_1744873387501': '2026-02-23T01:08:32.000Z', '_widget_1744873387502': '2026-02-23T01:41:03.000Z', '_widget_1744873387504': '1951', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bb0432121acc1031813b5', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:41:23.436Z', 'updateTime': '2026-02-23T01:41:23.436Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '续约回访待办', '_widget_1744873387501': '2026-02-23T01:35:37.000Z', '_widget_1744873387502': '2026-02-23T01:41:23.000Z', '_widget_1744873387504': '346', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bb3af78f713d2ee49d55b', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T01:55:59.287Z', 'updateTime': '2026-02-23T01:55:59.287Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '履约表数据支撑', '_widget_1744873387501': '2026-02-23T01:11:32.000Z', '_widget_1744873387502': '2026-02-23T01:55:59.000Z', '_widget_1744873387504': '2667', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bb4a5ba28a77430759c97', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T02:00:05.474Z', 'updateTime': '2026-02-23T02:00:05.474Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T02:00:01.000Z', '_widget_1744873387502': '2026-02-23T02:00:05.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bb50fd89e0cfb588ef327', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T02:01:51.376Z', 'updateTime': '2026-02-23T02:01:51.376Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T02:00:01.000Z', '_widget_1744873387502': '2026-02-23T02:01:51.000Z', '_widget_1744873387504': '110', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bb6aabb2676472722b26f', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T02:08:42.043Z', 'updateTime': '2026-02-23T02:08:42.043Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '异常服务待办派发', '_widget_1744873387501': '2026-02-23T02:00:41.000Z', '_widget_1744873387502': '2026-02-23T02:08:41.000Z', '_widget_1744873387504': '480', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bc2b6bb267647272be5f3', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T03:00:06.432Z', 'updateTime': '2026-02-23T03:00:06.432Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T03:00:02.000Z', '_widget_1744873387502': '2026-02-23T03:00:06.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bc31a21b865706e9a07c7', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T03:01:46.581Z', 'updateTime': '2026-02-23T03:01:46.581Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T03:00:02.000Z', '_widget_1744873387502': '2026-02-23T03:01:46.000Z', '_widget_1744873387504': '104', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bd0c8c4526a0fb31cab52', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T04:00:08.047Z', 'updateTime': '2026-02-23T04:00:08.047Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T04:00:02.000Z', '_widget_1744873387502': '2026-02-23T04:00:07.000Z', '_widget_1744873387504': '5', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bd12c6cc6edda46f611f3', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T04:01:48.665Z', 'updateTime': '2026-02-23T04:01:48.665Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T04:00:02.000Z', '_widget_1744873387502': '2026-02-23T04:01:48.000Z', '_widget_1744873387504': '106', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bd13b6b865746fe647937', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T04:02:03.180Z', 'updateTime': '2026-02-23T04:02:03.180Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '非标业绩提报转BI', '_widget_1744873387501': '2026-02-23T04:02:00.000Z', '_widget_1744873387502': '2026-02-23T04:02:03.000Z', '_widget_1744873387504': '3', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bd192ab309d2e5743b60f', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T04:03:30.300Z', 'updateTime': '2026-02-23T04:03:30.300Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '合伙人结算登记同步到BI', '_widget_1744873387501': '2026-02-23T04:03:00.000Z', '_widget_1744873387502': '2026-02-23T04:03:30.000Z', '_widget_1744873387504': '30', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bded6ba28a774309b02e3', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T05:00:06.698Z', 'updateTime': '2026-02-23T05:00:06.698Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T05:00:02.000Z', '_widget_1744873387502': '2026-02-23T05:00:06.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bdf40f3ced099adef4533', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T05:01:52.919Z', 'updateTime': '2026-02-23T05:01:52.919Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T05:00:02.000Z', '_widget_1744873387502': '2026-02-23T05:01:52.000Z', '_widget_1744873387504': '110', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699be198a6312699f3f66600', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T05:11:52.618Z', 'updateTime': '2026-02-23T05:11:52.618Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': 'NGV更新数据', '_widget_1744873387501': '2026-02-23T04:30:04.000Z', '_widget_1744873387502': '2026-02-23T05:11:52.000Z', '_widget_1744873387504': '2508', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bece6a6312699f3ff7a78', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T06:00:06.979Z', 'updateTime': '2026-02-23T06:00:06.979Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T06:00:02.000Z', '_widget_1744873387502': '2026-02-23T06:00:06.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bed46049df941e555738a', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T06:01:42.686Z', 'updateTime': '2026-02-23T06:01:42.686Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T06:00:02.000Z', '_widget_1744873387502': '2026-02-23T06:01:42.000Z', '_widget_1744873387504': '100', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bfaf8e276a38cb29811e1', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T07:00:08.733Z', 'updateTime': '2026-02-23T07:00:08.733Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T07:00:02.000Z', '_widget_1744873387502': '2026-02-23T07:00:08.000Z', '_widget_1744873387504': '6', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699bfb5ae606c83377b26a83', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T07:01:46.229Z', 'updateTime': '2026-02-23T07:01:46.229Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T07:00:02.000Z', '_widget_1744873387502': '2026-02-23T07:01:46.000Z', '_widget_1744873387504': '104', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c09072444810c0bf158a4', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T08:00:07.983Z', 'updateTime': '2026-02-23T08:00:07.983Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T08:00:02.000Z', '_widget_1744873387502': '2026-02-23T08:00:07.000Z', '_widget_1744873387504': '5', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c096d0231857db5783021', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T08:01:49.310Z', 'updateTime': '2026-02-23T08:01:49.310Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T08:00:02.000Z', '_widget_1744873387502': '2026-02-23T08:01:48.000Z', '_widget_1744873387504': '106', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c17151278494a264cd984', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T09:00:05.447Z', 'updateTime': '2026-02-23T09:00:05.447Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T09:00:02.000Z', '_widget_1744873387502': '2026-02-23T09:00:04.000Z', '_widget_1744873387504': '2', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c1772ed29cdb3bc6edf57', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T09:01:38.528Z', 'updateTime': '2026-02-23T09:01:38.528Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '非标业绩提报转BI', '_widget_1744873387501': '2026-02-23T09:01:23.000Z', '_widget_1744873387502': '2026-02-23T09:01:38.000Z', '_widget_1744873387504': '15', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c17795afe4f1583e6e4a4', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T09:01:45.259Z', 'updateTime': '2026-02-23T09:01:45.259Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T09:00:02.000Z', '_widget_1744873387502': '2026-02-23T09:01:44.000Z', '_widget_1744873387504': '102', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c17c00bdffe31d5db6ec4', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T09:02:56.522Z', 'updateTime': '2026-02-23T09:02:56.522Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '合伙人结算登记同步到BI', '_widget_1744873387501': '2026-02-23T09:02:23.000Z', '_widget_1744873387502': '2026-02-23T09:02:55.000Z', '_widget_1744873387504': '32', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c25267bf0348e327bed5a', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T10:00:06.295Z', 'updateTime': '2026-02-23T10:00:06.295Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T10:00:02.000Z', '_widget_1744873387502': '2026-02-23T10:00:06.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c2593a4b0d9369ba61515', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T10:01:55.536Z', 'updateTime': '2026-02-23T10:01:55.536Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T10:00:02.000Z', '_widget_1744873387502': '2026-02-23T10:01:55.000Z', '_widget_1744873387504': '113', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c33367bf0348e32885df8', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T11:00:06.453Z', 'updateTime': '2026-02-23T11:00:06.453Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T11:00:01.000Z', '_widget_1744873387502': '2026-02-23T11:00:06.000Z', '_widget_1744873387504': '5', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c33a843db686ad5f7cb1b', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T11:02:00.440Z', 'updateTime': '2026-02-23T11:02:00.440Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T11:00:01.000Z', '_widget_1744873387502': '2026-02-23T11:02:00.000Z', '_widget_1744873387504': '119', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c4147205acb4b4c3439a0', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T12:00:07.284Z', 'updateTime': '2026-02-23T12:00:07.284Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T12:00:02.000Z', '_widget_1744873387502': '2026-02-23T12:00:07.000Z', '_widget_1744873387504': '5', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c41ad9fc801efc734512c', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T12:01:49.178Z', 'updateTime': '2026-02-23T12:01:49.178Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T12:00:02.000Z', '_widget_1744873387502': '2026-02-23T12:01:49.000Z', '_widget_1744873387504': '107', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c4f5614a266a4fa4c955a', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T13:00:06.759Z', 'updateTime': '2026-02-23T13:00:06.759Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T13:00:02.000Z', '_widget_1744873387502': '2026-02-23T13:00:06.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c4fb6654487d78f493dbf', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T13:01:42.670Z', 'updateTime': '2026-02-23T13:01:42.670Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T13:00:02.000Z', '_widget_1744873387502': '2026-02-23T13:01:42.000Z', '_widget_1744873387504': '100', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c5d67bd4f2251f9fcfa06', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T14:00:07.768Z', 'updateTime': '2026-02-23T14:00:07.768Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T14:00:02.000Z', '_widget_1744873387502': '2026-02-23T14:00:07.000Z', '_widget_1744873387504': '5', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c5dd1a4b0d9369bd6e1d7', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T14:01:53.102Z', 'updateTime': '2026-02-23T14:01:53.102Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T14:00:02.000Z', '_widget_1744873387502': '2026-02-23T14:01:52.000Z', '_widget_1744873387504': '110', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c6b7c806941eed69e73fc', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T15:00:12.027Z', 'updateTime': '2026-02-23T15:00:12.027Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T15:00:02.000Z', '_widget_1744873387502': '2026-02-23T15:00:11.000Z', '_widget_1744873387504': '9', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c6bd8ce153aec688c0292', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T15:01:44.333Z', 'updateTime': '2026-02-23T15:01:44.333Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T15:00:02.000Z', '_widget_1744873387502': '2026-02-23T15:01:44.000Z', '_widget_1744873387504': '102', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c7985ce153aec689731ec', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T16:00:05.670Z', 'updateTime': '2026-02-23T16:00:05.670Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T16:00:02.000Z', '_widget_1744873387502': '2026-02-23T16:00:05.000Z', '_widget_1744873387504': '3', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c79ec16d3c9c3257a4579', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T16:01:48.284Z', 'updateTime': '2026-02-23T16:01:48.284Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T16:00:02.000Z', '_widget_1744873387502': '2026-02-23T16:01:48.000Z', '_widget_1744873387504': '106', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c87942444810c0b611f96', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T17:00:04.032Z', 'updateTime': '2026-02-23T17:00:04.032Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T17:00:02.000Z', '_widget_1744873387502': '2026-02-23T17:00:03.000Z', '_widget_1744873387504': '1', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c87f920538415f63cfa50', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T17:01:45.155Z', 'updateTime': '2026-02-23T17:01:45.155Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T17:00:02.000Z', '_widget_1744873387502': '2026-02-23T17:01:44.000Z', '_widget_1744873387504': '102', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c95a3e276a38cb21eff48', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T18:00:03.746Z', 'updateTime': '2026-02-23T18:00:03.746Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T18:00:01.000Z', '_widget_1744873387502': '2026-02-23T18:00:03.000Z', '_widget_1744873387504': '2', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699c96100c4d4882f5f28406', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T18:01:52.916Z', 'updateTime': '2026-02-23T18:01:52.916Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T18:00:01.000Z', '_widget_1744873387502': '2026-02-23T18:01:52.000Z', '_widget_1744873387504': '111', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ca3b50c32d8de42e92d47', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T19:00:05.295Z', 'updateTime': '2026-02-23T19:00:05.295Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T19:00:01.000Z', '_widget_1744873387502': '2026-02-23T19:00:05.000Z', '_widget_1744873387504': '4', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ca41b057a5fdbf0c8299f', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T19:01:47.041Z', 'updateTime': '2026-02-23T19:01:47.041Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T19:00:02.000Z', '_widget_1744873387502': '2026-02-23T19:01:46.000Z', '_widget_1744873387504': '104', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cb1c90231857db50cc269', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T20:00:09.267Z', 'updateTime': '2026-02-23T20:00:09.267Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T20:00:01.000Z', '_widget_1744873387502': '2026-02-23T20:00:08.000Z', '_widget_1744873387504': '7', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cb2280c4d4882f50ce59d', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T20:01:44.704Z', 'updateTime': '2026-02-23T20:01:44.704Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T20:00:02.000Z', '_widget_1744873387502': '2026-02-23T20:01:43.000Z', '_widget_1744873387504': '101', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cb4b31e0ffac0b145194e', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T20:12:35.781Z', 'updateTime': '2026-02-23T20:12:35.781Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '短信数据支撑', '_widget_1744873387501': '2026-02-23T20:10:10.000Z', '_widget_1744873387502': '2026-02-23T20:12:35.000Z', '_widget_1744873387504': '145', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cb67a9fa5a1c0477231cb', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T20:20:10.896Z', 'updateTime': '2026-02-23T20:20:10.896Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '异业合作数据支撑', '_widget_1744873387501': '2026-02-23T20:20:10.000Z', '_widget_1744873387502': '2026-02-23T20:20:10.000Z', '_widget_1744873387504': '0', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cbb44cfbbc4fa3b1ced3c', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T20:40:36.637Z', 'updateTime': '2026-02-23T20:40:36.637Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '私域小程序数据支撑', '_widget_1744873387501': '2026-02-23T20:40:10.000Z', '_widget_1744873387502': '2026-02-23T20:40:36.000Z', '_widget_1744873387504': '26', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cbb8563a6e46a0627003d', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T20:41:41.090Z', 'updateTime': '2026-02-23T20:41:41.090Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '小六提成数据支撑', '_widget_1744873387501': '2026-02-23T20:41:10.000Z', '_widget_1744873387502': '2026-02-23T20:41:40.000Z', '_widget_1744873387504': '30', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cbfdc314eb23a7b205dfe', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T21:00:12.877Z', 'updateTime': '2026-02-23T21:00:12.877Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T21:00:02.000Z', '_widget_1744873387502': '2026-02-23T21:00:12.000Z', '_widget_1744873387504': '10', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cbfe9600aa8fbf9d72bde', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T21:00:25.816Z', 'updateTime': '2026-02-23T21:00:25.816Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '高德匹配手机号', '_widget_1744873387501': '2026-02-23T21:00:10.000Z', '_widget_1744873387502': '2026-02-23T21:00:25.000Z', '_widget_1744873387504': '15', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cc034e276a38cb245a282', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T21:01:40.495Z', 'updateTime': '2026-02-23T21:01:40.495Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T21:00:03.000Z', '_widget_1744873387502': '2026-02-23T21:01:40.000Z', '_widget_1744873387504': '97', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ccdee775b2d60749f0ee5', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T22:00:14.885Z', 'updateTime': '2026-02-23T22:00:14.885Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T22:00:02.000Z', '_widget_1744873387502': '2026-02-23T22:00:14.000Z', '_widget_1744873387504': '12', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cce470c32d8de4210d760', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T22:01:43.313Z', 'updateTime': '2026-02-23T22:01:43.313Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T22:00:02.000Z', '_widget_1744873387502': '2026-02-23T22:01:42.000Z', '_widget_1744873387504': '100', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cdbf6314eb23a7b3b1120', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T23:00:06.937Z', 'updateTime': '2026-02-23T23:00:06.937Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '简道云员工ID表更新', '_widget_1744873387501': '2026-02-23T23:00:01.000Z', '_widget_1744873387502': '2026-02-23T23:00:06.000Z', '_widget_1744873387504': '5', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699cdc57a4b0d9369b4bc3a2', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T23:01:43.061Z', 'updateTime': '2026-02-23T23:01:43.061Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': '字段监控', '_widget_1744873387501': '2026-02-23T23:00:02.000Z', '_widget_1744873387502': '2026-02-23T23:01:42.000Z', '_widget_1744873387504': '100', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"{'_id': '699ce3b61278494a26043fb2', 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0}, 'deleter': None, 'createTime': '2026-02-23T23:33:10.251Z', 'updateTime': '2026-02-23T23:33:10.251Z', 'deleteTime': None, '_widget_1744873387500': '2026-02-23T00:00:00.000Z', '_widget_1743644977694': 'NGV新增数据', '_widget_1744873387501': '2026-02-23T23:30:25.000Z', '_widget_1744873387502': '2026-02-23T23:33:09.000Z', '_widget_1744873387504': '164', 'appId': '6694d3c4fcb69ca9a111a6c4', 'entryId': '67ede908eb9c22261016466e'}\n",
"正在计算 [2026-02-23] 的 48 个时间槽并发情况...\n",
"正在写入 48 条统计数据到目标表单...\n",
"{'code': 200, 'msg': '处理完成。统计日期:2026-02-23, 成功批次: 1/1', 'detail': [{'status': 'success', 'success_count': 48, 'success_ids': ['699d7316e1be306334210cab', '699d7316e1be306334210cac', '699d7316e1be306334210cad', '699d7316e1be306334210cae', '699d7316e1be306334210caf', '699d7316e1be306334210cb0', '699d7316e1be306334210cb1', '699d7316e1be306334210cb2', '699d7316e1be306334210cb3', '699d7316e1be306334210cb4', '699d7316e1be306334210cb5', '699d7316e1be306334210cb6', '699d7316e1be306334210cb7', '699d7316e1be306334210cb8', '699d7316e1be306334210cb9', '699d7316e1be306334210cba', '699d7316e1be306334210cbb', '699d7316e1be306334210cbc', '699d7316e1be306334210cbd', '699d7316e1be306334210cbe', '699d7316e1be306334210cbf', '699d7316e1be306334210cc0', '699d7316e1be306334210cc1', '699d7316e1be306334210cc2', '699d7316e1be306334210cc3', '699d7316e1be306334210cc4', '699d7316e1be306334210cc5', '699d7316e1be306334210cc6', '699d7316e1be306334210cc7', '699d7316e1be306334210cc8', '699d7316e1be306334210cc9', '699d7316e1be306334210cca', '699d7316e1be306334210ccb', '699d7316e1be306334210ccc', '699d7316e1be306334210ccd', '699d7316e1be306334210cce', '699d7316e1be306334210ccf', '699d7316e1be306334210cd0', '699d7316e1be306334210cd1', '699d7316e1be306334210cd2', '699d7316e1be306334210cd3', '699d7316e1be306334210cd4', '699d7316e1be306334210cd5', '699d7316e1be306334210cd6', '699d7316e1be306334210cd7', '699d7316e1be306334210cd8', '699d7316e1be306334210cd9', '699d7316e1be306334210cda']}]}\n"
]
}
],
"source": [
"import json\n",
"from datetime import datetime, timedelta\n",
"import requests\n",
"import time\n",
"from decimal import Decimal\n",
"\n",
"# ================= 辅助函数定义 =================\n",
"\n",
"def replace_decimals(obj):\n",
" if isinstance(obj, dict):\n",
" return {k: replace_decimals(v) for k, v in obj.items()}\n",
" elif isinstance(obj, list):\n",
" return [replace_decimals(item) for item in obj]\n",
" elif isinstance(obj, Decimal):\n",
" return float(obj)\n",
" return obj\n",
"\n",
"class NpEncoder(json.JSONEncoder):\n",
" def default(self, obj):\n",
" try:\n",
" import numpy as np\n",
" if isinstance(obj, np.integer):\n",
" return int(obj)\n",
" elif isinstance(obj, np.floating):\n",
" return float(obj)\n",
" elif isinstance(obj, np.ndarray):\n",
" return obj.tolist()\n",
" except ImportError:\n",
" pass\n",
" return super(NpEncoder, self).default(obj)\n",
"\n",
"def entry_data_list(data: dict, replace: bool = False, max_retries: int = 20):\n",
" \"\"\"获取多条表单数据\"\"\"\n",
" url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/list'\n",
" API_TOKEN = \"Bearer qygHulymo1fekJk4CIZyNKjyQAzG8CFN\"\n",
" headers = {\n",
" 'Authorization': API_TOKEN,\n",
" 'Content-Type': 'application/json'\n",
" }\n",
" \n",
" all_data_batches = []\n",
" last_data_id = None\n",
" exit_flag = False\n",
" \n",
" while True:\n",
" payload = json.dumps({\n",
" \"app_id\": data['api_key'],\n",
" \"entry_id\": data['entry_id'],\n",
" \"limit\": 90,\n",
" \"data_id\": last_data_id,\n",
" \"filter\": data.get('filter', None)\n",
" })\n",
" retries = 0\n",
" while retries <= max_retries:\n",
" data_get = None\n",
" try:\n",
" res = requests.post(url=url, data=payload, headers=headers, timeout=10)\n",
" res.raise_for_status()\n",
" data_get = res.json()\n",
" \n",
" if data_get.get(\"data\"):\n",
" all_data_batches.extend(data_get['data'])\n",
" last_data_id = data_get['data'][-1].get('_id')\n",
" print(f\"已获取 {len(all_data_batches)} 条数据\")\n",
" break\n",
" else:\n",
" exit_flag = True\n",
" break\n",
" except requests.exceptions.RequestException as e:\n",
" print(f\"请求异常: {e}, 重试 ({retries+1}/{max_retries})\")\n",
" retries += 1\n",
" time.sleep(0.5)\n",
" \n",
" if retries > max_retries:\n",
" print(\"达到最大重试次数,停止获取。\")\n",
" break\n",
" if exit_flag:\n",
" break\n",
"\n",
" final_data = {'data': all_data_batches}\n",
" \n",
" if replace:\n",
" print(\"警告:replace=True 但 field_replacement 函数未在此脚本定义,将返回原始数据。\")\n",
" # 如果需要替换,请确保环境中定义了 field_replacement 函数\n",
" # return_data = field_replacement(data, final_data) \n",
" # return return_data\n",
" return final_data\n",
" else:\n",
" return final_data\n",
"\n",
"def entry_data_batch_create(data: dict, chunk_size: int = 90, max_retries: int = 20):\n",
" \"\"\"新建多条数据\"\"\"\n",
" data = replace_decimals(data)\n",
" url = 'https://api.jiandaoyun.com/api/v5/app/entry/data/batch_create'\n",
" API_TOKEN = \"Bearer qygHulymo1fekJk4CIZyNKjyQAzG8CFN\"\n",
" headers = {\n",
" 'Authorization': API_TOKEN,\n",
" 'Content-Type': 'application/json'\n",
" }\n",
"\n",
" total_length = len(data['data_list'])\n",
" num_chunks = (total_length + chunk_size - 1) // chunk_size\n",
" data_get_list = []\n",
"\n",
" for i in range(num_chunks):\n",
" start_index = i * chunk_size\n",
" end_index = min(start_index + chunk_size, total_length)\n",
" \n",
" payload = json.dumps({\n",
" \"app_id\": data['api_key'],\n",
" \"entry_id\": data['entry_id'],\n",
" \"data_list\": data['data_list'][start_index:end_index],\n",
" \"is_start_workflow\": data.get('is_start_workflow', \"false\"),\n",
" \"is_start_trigger\": data.get('is_start_trigger', \"false\"),\n",
" }, cls=NpEncoder)\n",
" \n",
" retries = 0\n",
" while retries <= max_retries:\n",
" try:\n",
" res = requests.post(url=url, data=payload, headers=headers, timeout=15)\n",
" res.raise_for_status()\n",
" data_get = res.json()\n",
" \n",
" if data_get.get(\"status\") == \"success\":\n",
" data_get_list.append(data_get)\n",
" break\n",
" else:\n",
" retries += 1\n",
" time.sleep(3)\n",
" except requests.exceptions.RequestException as e:\n",
" print(f\"批量创建请求异常: {e}\")\n",
" retries += 1\n",
" time.sleep(0.5)\n",
" \n",
" if retries > max_retries:\n",
" print(f\"批次 {i+1}/{num_chunks} 请求失败,已放弃。\")\n",
" data_get_list.append(None)\n",
"\n",
" return data_get_list\n",
"\n",
"# ================= 主业务逻辑 =================\n",
"\n",
"def calculate_server_load():\n",
" # --- 配置 ---\n",
" APP_ID = \"6694d3c4fcb69ca9a111a6c4\"\n",
" SOURCE_FORM_ID = \"67ede908eb9c22261016466e\"\n",
" TARGET_FORM_ID = \"699d4f82ae9623e204969627\"\n",
" \n",
" # 【重要】请核实 ID\n",
" # 用于过滤和读取的“日期”字段 (精确到日)\n",
" WIDGET_DATE_FIELD = \"_widget_1744873387500\" \n",
" # 用于读取具体时间的“开始时间”和“结束时间”字段 (精确到时分秒)\n",
" # 注意:如果源表单只有一个“日期”字段而没有具体时间点,逻辑需要调整。\n",
" # 假设你仍有具体的开始/结束时间字段用于计算时长。如果没有,需确认如何计算30分钟槽。\n",
" # 此处假设你有具体的时分秒字段,如果只有日期字段,所有任务将被视为全天或无法计算精确并发。\n",
" # 如果你的业务逻辑是:只要日期是昨天,就算作昨天的任务,且没有具体时间点,\n",
" # 那么下面的时间解析部分需要适配。\n",
" # **这里假设你依然有具体的开始/结束时间组件用于计算并发**\n",
" WIDGET_START_TIME = \"_widget_1744873387501\" # 请替换为实际的开始时间(含时分) ID\n",
" WIDGET_END_TIME = \"_widget_1744873387502\" # 请替换为实际的结束时间(含时分) ID\n",
" \n",
" now = datetime.now()\n",
" today_str = now.strftime(\"%Y-%m-%d\")\n",
" \n",
" # 计算昨天的日期\n",
" yesterday_dt = now - timedelta(days=1)\n",
" yesterday_str = yesterday_dt.strftime(\"%Y-%m-%d\")\n",
" \n",
" print(f\"正在筛选日期为:{yesterday_str} 的任务...\")\n",
"\n",
" # --- 构造过滤器 ---\n",
" # 使用日期字段 (精确到日) 进行等值匹配\n",
" FILTER = {\n",
" \"rel\": \"and\",\n",
" \"cond\": [\n",
" {\n",
" \"field\": WIDGET_DATE_FIELD,\n",
" \"type\": \"date\", # 注意这里是 date 不是 datetime\n",
" \"method\": \"eq\", # 等于\n",
" \"value\": [yesterday_str] # 格式 YYYY-MM-DD\n",
" }\n",
" ]\n",
" }\n",
" \n",
" data = {\n",
" \"api_key\": APP_ID, \n",
" \"entry_id\": SOURCE_FORM_ID, \n",
" \"filter\": FILTER\n",
" } \n",
"\n",
" print(\"正在从简道云获取源数据...\")\n",
" # 使用 replace=False,通过 Widget ID 获取\n",
" raw_response = entry_data_list(data, replace=False)\n",
" tasks_raw = raw_response.get(\"data\", [])\n",
" \n",
" if not tasks_raw:\n",
" print(f\"未获取到日期为 {yesterday_str} 的任务数据。\")\n",
" # 即使没有数据,也可以生成全0的统计表,或者根据需求直接返回\n",
" # 这里选择继续生成全0的统计\n",
" tasks = []\n",
" else:\n",
" print(f\"API 返回原始数据条数: {len(tasks_raw)}\")\n",
" tasks = []\n",
" for item in tasks_raw:\n",
" print(item)\n",
" # 获取具体时间值\n",
" s_val = item.get(WIDGET_START_TIME, {})\n",
" e_val = item.get(WIDGET_END_TIME, {})\n",
" \n",
" # 如果源数据只有日期没有具体时间,可能需要默认设为当天 00:00 到 23:59\n",
" # 这里假设必须有具体时间才能计算并发\n",
" if not s_val or not e_val:\n",
" # 兼容处理:如果只有日期字段,尝试用日期字段补全\n",
" # 如果业务上不需要精确到分,可在此处设定默认值\n",
" continue \n",
" \n",
" try:\n",
" # --- 核心修复:处理 ISO 8601 格式 (含 T 和 Z) ---\n",
" # 1. 转为字符串\n",
" s_str = str(s_val)\n",
" e_str = str(e_val)\n",
" \n",
" # 2. 替换 'T' 为空格,去掉 'Z' 和毫秒部分\n",
" # 示例: 2026-02-23T00:00:01.000Z -> 2026-02-23 00:00:01\n",
" s_clean = s_str.replace('T', ' ').replace('Z', '').split('.')[0]\n",
" e_clean = e_str.replace('T', ' ').replace('Z', '').split('.')[0]\n",
" \n",
" # 3. 解析\n",
" s_dt = datetime.strptime(s_clean, \"%Y-%m-%d %H:%M:%S\")\n",
" e_dt = datetime.strptime(e_clean, \"%Y-%m-%d %H:%M:%S\")\n",
" \n",
" tasks.append({\"start\": s_dt, \"end\": e_dt})\n",
" \n",
" except Exception as e:\n",
" # 调试用:打印具体哪条数据失败\n",
" print(f\"解析失败: {s_val}, 错误: {e}\")\n",
" continue\n",
"\n",
" # --- 确定统计哪一天的时间槽 ---\n",
" # 既然过滤的是昨天的数据,推测你需要生成【昨天】的负载报表\n",
" stats_date_str = yesterday_str\n",
" base_time = datetime.strptime(stats_date_str, \"%Y-%m-%d\")\n",
" stats_date_end = base_time + timedelta(days=1)\n",
" \n",
" print(f\"正在计算 [{stats_date_str}] 的 48 个时间槽并发情况...\")\n",
" \n",
" # 目标表单 Widget ID (请替换为真实 ID)\n",
" WIDGET_T_DATE = \"_widget_1771917185994\"\n",
" WIDGET_T_SLOT = \"_widget_1771917185995\"\n",
" WIDGET_T_COUNT = \"_widget_1771917185996\"\n",
" WIDGET_T_IDLE = \"_widget_1771917264186\"\n",
" WIDGET_T_NORMAL = \"_widget_1771917918805\"\n",
" WIDGET_T_BUSY = \"_widget_1771917918806\"\n",
"\n",
" slots = []\n",
" for i in range(48): \n",
" slot_start = base_time + timedelta(minutes=i*30)\n",
" slot_end = slot_start + timedelta(minutes=30)\n",
" \n",
" count = 0\n",
" for t in tasks:\n",
" # 判断任务是否与该30分钟槽有重叠\n",
" if t[\"start\"] < slot_end and slot_start < t[\"end\"]:\n",
" count += 1\n",
" \n",
" is_idle = 1 if count == 0 else 0\n",
" is_normal = 1 if 1 <= count <= 3 else 0\n",
" is_busy = 1 if count > 3 else 0\n",
" \n",
" slots.append({\n",
" WIDGET_T_DATE: {\"value\": stats_date_str},\n",
" WIDGET_T_SLOT: {\"value\": slot_start.strftime(\"%H:%M\")},\n",
" WIDGET_T_COUNT: {\"value\": count},\n",
" WIDGET_T_IDLE: {\"value\": is_idle},\n",
" WIDGET_T_NORMAL: {\"value\": is_normal},\n",
" WIDGET_T_BUSY: {\"value\": is_busy},\n",
" })\n",
"\n",
" if not slots:\n",
" return {\"code\": 200, \"msg\": \"未生成时间槽数据\"}\n",
" \n",
" payload = {\n",
" \"api_key\": APP_ID,\n",
" \"entry_id\": TARGET_FORM_ID,\n",
" \"data_list\": slots,\n",
" \"is_start_workflow\": \"false\", \n",
" \"is_start_trigger\": \"false\"\n",
" }\n",
" \n",
" print(f\"正在写入 {len(slots)} 条统计数据到目标表单...\")\n",
" result = entry_data_batch_create(payload)\n",
" \n",
" success_count = sum(1 for r in result if r and r.get(\"status\") == \"success\")\n",
" \n",
" return {\n",
" \"code\": 200, \n",
" \"msg\": f\"处理完成。统计日期:{stats_date_str}, 成功批次: {success_count}/{len(result)}\", \n",
" \"detail\": result\n",
" }\n",
"\n",
"# 如果需要直接运行测试\n",
"if __name__ == \"__main__\":\n",
" # 确保在实际运行前替换了所有 WIDGET_ID\n",
" res = calculate_server_load()\n",
" print(res)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "342edfbf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"正在获取源数据...\n",
"已获取 90 条数据\n",
"已获取 180 条数据\n",
"已获取 270 条数据\n",
"已获取 360 条数据\n",
"已获取 450 条数据\n",
"已获取 540 条数据\n",
"已获取 630 条数据\n",
"已获取 720 条数据\n",
"已获取 810 条数据\n",
"已获取 900 条数据\n",
"已获取 990 条数据\n",
"已获取 1080 条数据\n",
"已获取 1170 条数据\n",
"已获取 1260 条数据\n",
"已获取 1350 条数据\n",
"已获取 1440 条数据\n",
"已获取 1530 条数据\n",
"已获取 1620 条数据\n",
"已获取 1710 条数据\n",
"已获取 1800 条数据\n",
"已获取 1890 条数据\n",
"已获取 1980 条数据\n",
"已获取 2070 条数据\n",
"已获取 2160 条数据\n",
"已获取 2250 条数据\n",
"已获取 2340 条数据\n",
"已获取 2430 条数据\n",
"已获取 2520 条数据\n",
"已获取 2610 条数据\n",
"已获取 2700 条数据\n",
"已获取 2790 条数据\n",
"已获取 2880 条数据\n",
"已获取 2970 条数据\n",
"已获取 3060 条数据\n",
"已获取 3150 条数据\n",
"已获取 3240 条数据\n",
"已获取 3330 条数据\n",
"已获取 3420 条数据\n",
"已获取 3510 条数据\n",
"已获取 3600 条数据\n",
"已获取 3690 条数据\n",
"已获取 3780 条数据\n",
"已获取 3870 条数据\n",
"已获取 3960 条数据\n",
"已获取 4050 条数据\n",
"已获取 4140 条数据\n",
"已获取 4230 条数据\n",
"已获取 4320 条数据\n",
"已获取 4410 条数据\n",
"已获取 4500 条数据\n",
"已获取 4590 条数据\n",
"已获取 4680 条数据\n",
"已获取 4770 条数据\n",
"已获取 4860 条数据\n",
"已获取 4950 条数据\n",
"已获取 5040 条数据\n",
"已获取 5130 条数据\n",
"已获取 5220 条数据\n",
"已获取 5310 条数据\n",
"已获取 5400 条数据\n",
"已获取 5490 条数据\n",
"已获取 5580 条数据\n",
"已获取 5670 条数据\n",
"已获取 5760 条数据\n",
"已获取 5850 条数据\n",
"已获取 5940 条数据\n",
"已获取 6030 条数据\n",
"已获取 6120 条数据\n",
"已获取 6210 条数据\n",
"已获取 6300 条数据\n",
"已获取 6390 条数据\n",
"已获取 6480 条数据\n",
"已获取 6570 条数据\n",
"已获取 6660 条数据\n",
"已获取 6750 条数据\n",
"已获取 6840 条数据\n",
"已获取 6930 条数据\n",
"已获取 7020 条数据\n",
"已获取 7110 条数据\n",
"已获取 7200 条数据\n",
"已获取 7290 条数据\n",
"已获取 7380 条数据\n",
"已获取 7470 条数据\n",
"已获取 7560 条数据\n",
"已获取 7650 条数据\n",
"已获取 7740 条数据\n",
"已获取 7830 条数据\n",
"已获取 7920 条数据\n",
"已获取 8010 条数据\n",
"已获取 8100 条数据\n",
"已获取 8190 条数据\n",
"已获取 8280 条数据\n",
"已获取 8370 条数据\n",
"已获取 8460 条数据\n",
"已获取 8550 条数据\n",
"已获取 8640 条数据\n",
"已获取 8730 条数据\n",
"已获取 8820 条数据\n",
"已获取 8910 条数据\n",
"已获取 9000 条数据\n",
"已获取 9090 条数据\n",
"已获取 9180 条数据\n",
"已获取 9270 条数据\n",
"已获取 9360 条数据\n",
"已获取 9450 条数据\n",
"已获取 9540 条数据\n",
"已获取 9630 条数据\n",
"已获取 9720 条数据\n",
"已获取 9810 条数据\n",
"已获取 9900 条数据\n",
"已获取 9990 条数据\n",
"已获取 10080 条数据\n",
"已获取 10170 条数据\n",
"已获取 10260 条数据\n",
"已获取 10350 条数据\n",
"已获取 10440 条数据\n",
"已获取 10530 条数据\n",
"已获取 10620 条数据\n",
"已获取 10710 条数据\n",
"已获取 10800 条数据\n",
"已获取 10890 条数据\n",
"已获取 10980 条数据\n",
"已获取 11070 条数据\n",
"已获取 11160 条数据\n",
"已获取 11250 条数据\n",
"已获取 11340 条数据\n",
"已获取 11430 条数据\n",
"已获取 11520 条数据\n",
"已获取 11610 条数据\n",
"已获取 11700 条数据\n",
"已获取 11790 条数据\n",
"已获取 11880 条数据\n",
"已获取 11970 条数据\n",
"已获取 12060 条数据\n",
"已获取 12150 条数据\n",
"已获取 12240 条数据\n",
"已获取 12330 条数据\n",
"已获取 12420 条数据\n",
"已获取 12510 条数据\n",
"已获取 12600 条数据\n",
"已获取 12690 条数据\n",
"已获取 12780 条数据\n",
"已获取 12870 条数据\n",
"已获取 12960 条数据\n",
"已获取 13050 条数据\n",
"已获取 13140 条数据\n",
"已获取 13230 条数据\n",
"已获取 13320 条数据\n",
"已获取 13410 条数据\n",
"已获取 13500 条数据\n",
"已获取 13590 条数据\n",
"已获取 13680 条数据\n",
"已获取 13770 条数据\n",
"已获取 13860 条数据\n",
"已获取 13950 条数据\n",
"已获取 14040 条数据\n",
"已获取 14130 条数据\n",
"已获取 14220 条数据\n",
"已获取 14310 条数据\n",
"已获取 14400 条数据\n",
"已获取 14490 条数据\n",
"已获取 14580 条数据\n",
"已获取 14670 条数据\n",
"已获取 14760 条数据\n",
"已获取 14850 条数据\n",
"已获取 14940 条数据\n",
"已获取 15030 条数据\n",
"已获取 15096 条数据\n"
]
},
{
"ename": "AttributeError",
"evalue": "'str' object has no attribute 'get'",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m result = \u001b[43mcalculate_server_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 2\u001b[39m result\n",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 226\u001b[39m, in \u001b[36mcalculate_server_load\u001b[39m\u001b[34m()\u001b[39m\n\u001b[32m 223\u001b[39m tasks = []\n\u001b[32m 224\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m item \u001b[38;5;129;01min\u001b[39;00m tasks_raw:\n\u001b[32m 225\u001b[39m \u001b[38;5;66;03m# 使用 Widget ID 获取值\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m226\u001b[39m s_val = \u001b[43mitem\u001b[49m\u001b[43m.\u001b[49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mWIDGET_START_TIME\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\u001b[43m.\u001b[49m\u001b[43mget\u001b[49m(\u001b[33m'\u001b[39m\u001b[33mvalue\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m 227\u001b[39m e_val = item.get(WIDGET_END_TIME, {}).get(\u001b[33m'\u001b[39m\u001b[33mvalue\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m 229\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m s_val \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m e_val:\n",
"\u001b[31mAttributeError\u001b[39m: 'str' object has no attribute 'get'"
]
}
],
"source": [
"result = calculate_server_load()\n",
"result"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "60531b14",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'tasks_raw' is not defined",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mNameError\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mtasks_raw\u001b[49m\n",
"\u001b[31mNameError\u001b[39m: name 'tasks_raw' is not defined"
]
}
],
"source": [
"tasks_raw"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "F6+宜搭+其它",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,113 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "92f27fd2",
"metadata": {},
"source": [
"管理后台-使用统计"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "679fdcc5",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<>:60: SyntaxWarning: invalid escape sequence '\\I'\n",
"<>:60: SyntaxWarning: invalid escape sequence '\\I'\n",
"C:\\Users\\hp_z66\\AppData\\Local\\Temp\\ipykernel_25140\\3645530864.py:60: SyntaxWarning: invalid escape sequence '\\I'\n",
" df.to_csv(\"D:\\Idea Project\\F6+宜搭+其它(1)\\张阳脚本\\文件输出\\人员使用记录.csv\")\n"
]
}
],
"source": [
"import requests\n",
"import pandas as pd\n",
"\n",
"cookies = {\n",
" 'fx-lang': 'zh_cn',\n",
" 'auth_token': 's%3A.9uztgExtmqUJXHCi00hv9SGq6eVYSvH%2BxQSwrox1Yls',\n",
" 'sensorsdata2015jssdkcross': '%7B%22distinct_id%22%3A%2257956c24ceedab0c48c17b4e%22%2C%22first_id%22%3A%2219b6dd1a10c148a-063e3a033b10ed-4c657b58-2073600-19b6dd1a10d145b%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTliNmRkMWExMGMxNDhhLTA2M2UzYTAzM2IxMGVkLTRjNjU3YjU4LTIwNzM2MDAtMTliNmRkMWExMGQxNDViIiwiJGlkZW50aXR5X2xvZ2luX2lkIjoiNTc5NTZjMjRjZWVkYWIwYzQ4YzE3YjRlIn0%3D%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%24identity_login_id%22%2C%22value%22%3A%2257956c24ceedab0c48c17b4e%22%7D%7D',\n",
" '_csrf': 's%3A_D_KxBikFhOaA2gkTYpORFF6.AqupOk5Q%2B7GUjR1bKbiQLAXksxGmkcsVthKkDYiBQRE',\n",
" 'Hm_lvt_de47dd1629940fe88b02865de93dd9fe': '1770176033,1770257492,1770281854,1770359422',\n",
" 'HMACCOUNT': 'A6A0585E8C70051D',\n",
" 'Hm_lpvt_de47dd1629940fe88b02865de93dd9fe': '1770600610',\n",
" 'GSuvNKHqfvX2r6v7P8HkZv2bow': 's%3ANKEleTNCioVWeMitYN3WOVYYmCXbGFB0.qD1J8obD4MP4FNXKiVimB2UWfI2g3Nm%2FFOuYEmdeQek',\n",
" 'JDY_SID': 's%3Aar54WVlu4J-OyZzN0zEvAOU_FgbWMSvc.nCgiElAa2EoL3zf2gCIUV4XCFBE6aF6fsodt4%2F1daj4',\n",
" 'acw_tc': '743e76f717706025725901488e72f65ae43f08af57c9b931c35df2a672f5ff',\n",
"}\n",
"\n",
"headers = {\n",
" 'accept': 'application/json, text/plain, */*',\n",
" 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',\n",
" 'content-type': 'application/json',\n",
" 'origin': 'https://www.jiandaoyun.com',\n",
" 'priority': 'u=1, i',\n",
" 'referer': 'https://www.jiandaoyun.com/product/usage_statistics',\n",
" 'sec-ch-ua': '\"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"144\", \"Microsoft Edge\";v=\"144\"',\n",
" 'sec-ch-ua-mobile': '?0',\n",
" 'sec-ch-ua-platform': '\"Windows\"',\n",
" 'sec-fetch-dest': 'empty',\n",
" 'sec-fetch-mode': 'cors',\n",
" 'sec-fetch-site': 'same-origin',\n",
" 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0',\n",
" 'x-csrf-token': 'V3tEncMi-0KtoUAbnjwbKp66GsbVQMEL4bAc',\n",
" 'x-jdy-ver': '10.17.2',\n",
" 'x-request-id': 'c16157d6-0b12-4bf2-b56c-6858f66831e1',\n",
" # 'cookie': 'fx-lang=zh_cn; auth_token=s%3A.9uztgExtmqUJXHCi00hv9SGq6eVYSvH%2BxQSwrox1Yls; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2257956c24ceedab0c48c17b4e%22%2C%22first_id%22%3A%2219b6dd1a10c148a-063e3a033b10ed-4c657b58-2073600-19b6dd1a10d145b%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTliNmRkMWExMGMxNDhhLTA2M2UzYTAzM2IxMGVkLTRjNjU3YjU4LTIwNzM2MDAtMTliNmRkMWExMGQxNDViIiwiJGlkZW50aXR5X2xvZ2luX2lkIjoiNTc5NTZjMjRjZWVkYWIwYzQ4YzE3YjRlIn0%3D%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%24identity_login_id%22%2C%22value%22%3A%2257956c24ceedab0c48c17b4e%22%7D%7D; _csrf=s%3A_D_KxBikFhOaA2gkTYpORFF6.AqupOk5Q%2B7GUjR1bKbiQLAXksxGmkcsVthKkDYiBQRE; Hm_lvt_de47dd1629940fe88b02865de93dd9fe=1770176033,1770257492,1770281854,1770359422; HMACCOUNT=A6A0585E8C70051D; Hm_lpvt_de47dd1629940fe88b02865de93dd9fe=1770600610; GSuvNKHqfvX2r6v7P8HkZv2bow=s%3ANKEleTNCioVWeMitYN3WOVYYmCXbGFB0.qD1J8obD4MP4FNXKiVimB2UWfI2g3Nm%2FFOuYEmdeQek; JDY_SID=s%3Aar54WVlu4J-OyZzN0zEvAOU_FgbWMSvc.nCgiElAa2EoL3zf2gCIUV4XCFBE6aF6fsodt4%2F1daj4; acw_tc=743e76f717706025725901488e72f65ae43f08af57c9b931c35df2a672f5ff',\n",
"}\n",
"\n",
"json_data = {\n",
" 'from': None,\n",
" 'to': None,\n",
" 'granularity': 'daily',\n",
" 'members': [],\n",
" 'has_count': False,\n",
" 'sort': {},\n",
" 'limit': 50,\n",
" 'skip': 0,\n",
"}\n",
"all_data_list = []\n",
"for i in range(0,28):\n",
" json_data[\"skip\"] = i*50\n",
" response = requests.post(\n",
" 'https://www.jiandaoyun.com/corp/activity/user_user_metrics',\n",
" cookies=cookies,\n",
" headers=headers,\n",
" json=json_data,\n",
" )\n",
"\n",
" data_list = response.json().get(\"data\",[])\n",
" all_data_list.extend(data_list)\n",
"df = pd.DataFrame(all_data_list)\n",
"df.to_csv(\"D:\\Idea Project\\F6+宜搭+其它(1)\\张阳脚本\\文件输出\\人员使用记录.csv\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "F6+宜搭+其它",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,24 @@
import os
# 设置你的根路径(注意:路径中的反斜杠在 Python 字符串中需转义,或使用 raw string)
root_path = r"C:\Users\hp_z66\OneDrive\Desktop\新建文件夹\合作跟进_20260207110728_resources_4"
# 遍历根路径下的所有文件
for dirpath, dirnames, filenames in os.walk(root_path):
# 判断当前路径是否包含 "FINST-" 开头的父目录
# 我们假设 FINST 目录是 root_path 的直接子目录
rel_path = os.path.relpath(dirpath, root_path)
parts = rel_path.split(os.sep)
if parts[0].startswith("FINST-"):
finst_id = parts[0]
for filename in filenames:
old_file_path = os.path.join(dirpath, filename)
_, ext = os.path.splitext(filename) # 获取原扩展名
new_filename = finst_id + ext
new_file_path = os.path.join(dirpath, new_filename)
# 防止覆盖同名文件(可选)
if old_file_path != new_file_path:
os.rename(old_file_path, new_file_path)
print(f"Renamed: {old_file_path}{new_file_path}")
@@ -0,0 +1,388 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "59aa4a03",
"metadata": {},
"source": [
"### 文件重命名并放在一个路径下"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "479a84ce",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🔍 正在扫描所有文件...\n",
"✅ 共找到 66 个实例,总计 90 个文件\n",
"📁 正在生成批次 1: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_1\n",
"[Batch 1] ✅ FINST-0CC662718BILO83CEX5TJ4OXZP2C3X1PCLRWLFGL.png\n",
"[Batch 1] ✅ FINST-0D866I81JANY5WG8A2DT15S63HZH20YFR68FMQJA.png\n",
"[Batch 1] ✅ FINST-0HD66Z81DFXYBP816VRKD6S2HA2H3RYCBYKFMR6.jpg\n",
"[Batch 1] ✅ FINST-3MF66MB1C62UYQ70B6VFWCC72LWD3WFATRQ8MJF1.jpg\n",
"[Batch 1] ✅ FINST-3RB66I91KLXKFLFLFENM3DP0BQER2D0BEAXVLS11.xlsx\n",
"[Batch 1] ✅ FINST-3SC66EA1POUU8OOK7YW2GDJEKD972XTSC1V9MCB1.png\n",
"[Batch 1] ✅ FINST-42766EA129TVP57F6HGFPAATXT4K2J17LS7BMPS2.png\n",
"[Batch 1] ✅ FINST-54A66HC1426KP5L87MXEA682I67O23YKVXUUL9U9.jpg\n",
"[Batch 1] ✅ FINST-54A66HC1BDILGOIO8D24RCKSUXOU2641DLRWLFY5.png\n",
"[Batch 1] ✅ FINST-54A66HC1NBQSMDDUEDQU4CSW0OJI27EQ2TV6MHV.xlsx\n",
"[Batch 1] ✅ FINST-5B866X816C0WLA139FUCS6ISBUCK3KXV3UIBMX22.jpg\n",
"[Batch 1] ✅ FINST-5W966981KWJJ06WS8VXCYC10RV7U31E6282ULAHS.png\n",
"[Batch 1] ✅ FINST-5X866U8169BBPU9BFDL61ASKGDPW3RJM5LIILSNA.png\n",
"[Batch 1] ✅ FINST-65D66X71VHAPFNPZ9OFURCIREZAS28FI7P12MJS.png\n",
"[Batch 1] ✅ FINST-69E66NA11AKXLE2R7DOP3AOZM8SD3R64OXNDM7G.png\n",
"[Batch 1] ✅ FINST-69E66NA1ATDYE53ADVQ8DCX122G53OQC1ETEM62.png\n",
"[Batch 1] ✅ FINST-6B966W917QETCTT5ARDDR8J2IOJD26ZQYVT7M3I.png\n",
"[Batch 1] ✅ FINST-8AD662D1X8VOJJUGCZ7NFCI1XLDM3EUX97H1MKJ1.png\n",
"[Batch 1] ✅ FINST-8EC66FA15UNNQPWWBOPENDDJ6EQM2MDGX4SZLOP4.jpg\n",
"[Batch 1] ✅ FINST-8O866AA142HTFEQ18XDVG5SQ0Y7Z14EVF6Y7MBHB.jpg\n",
"[Batch 1] ✅ FINST-9FA66WC1LDJNFROD7HJUI4OJ6C2J22UP25SZLUQA.jpg\n",
"[Batch 1] ✅ FINST-AZC667816Z9TV9Z4DD1PDD4OLN5825J8S4O7MOJ1.png\n",
"[Batch 1] ✅ FINST-BL866S61XU8DOZG5BZ6E4DZ2UOIV3B6CEHALL3QI.jpg\n",
"[Batch 1] ✅ FINST-ETA66681ZAHDHL2OA0MQR6UB9W5N2MZM2DGLLU2.png\n",
"[Batch 1] ✅ FINST-FX7660A1N11VJB6IBDBRE8N012ZQ2HVJIWBAMYL2.jpg\n",
"[Batch 1] ✅ FINST-G7B66QC1U162UFRMHJFJ59Q5VZZD3VQ1MS4KM0F.png\n",
"[Batch 1] ✅ FINST-HI766JB1ORJFF6STEI8PR6E3YJTF2B87VNDOLSM5.xlsx\n",
"[Batch 1] ✅ FINST-HRD66W919462UFW0NG4PODHZZUW63074RZAKM1DK.png\n",
"[Batch 1] ✅ FINST-IO766F81JX9VU83Z6OR927WUWBUJ3FDQKEGAM0X.xlsx\n",
"[Batch 1] ✅ FINST-IQC66GC18W4YQ8GSCL23T582HU1H3960PVGEML8.png\n",
"[Batch 1] ✅ FINST-IRD66GC15CA2MFOFM8MHCBN7OSWA3PKSUZAKMKS.png\n",
"[Batch 1] ✅ FINST-IRD66PB1X8I2R8DLJKVF9667G4LC3TWHHZLKM0J.png\n",
"[Batch 1] ✅ FINST-IUF66391KP8W6U35CG7JL8UC2GK52JXZA6TBM6P.png\n",
"[Batch 1] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"[Batch 1] ✅ FINST-J3D66LA13NTHEZAICABNRCD3KVCY222Q7IORL7UD.jpg\n",
"[Batch 1] ✅ FINST-JB966E91FW8YJMLMD52WCCZCXO5V28E0JHMEMM.jpg\n",
"[Batch 1] ✅ FINST-JXA66PB1ONATQBEIBDMEZ45MLMVB3M0CO6O7MH01.png\n",
"[Batch 1] ✅ FINST-JZE66UC1Q8H2F0E3M38EX853TR242SGJFJKKMK8.xlsx\n",
"[Batch 1] ✅ FINST-K7E66Z91F5NYOC0UD20BO775JN8C3D763K6FM16.xlsx\n",
"[Batch 1] ✅ FINST-KW866QB13VPZ5OSE9CE0LAWVKEO23QA4XVOGM92.jpg\n",
"[Batch 1] ✅ FINST-L3D66981YN31J5O8MGQCCCPF6FE82J0EBZMIMQ61.xlsx\n",
"[Batch 1] ✅ FINST-LCC66CA1BTTCK1HQ9S8TP91UHORX3JHYWOQKLO65.pptx\n",
"[Batch 1] ✅ FINST-LLA66D71DDUN56UUBRVZVD2EO3TS291ZDU00M734.png\n",
"[Batch 1] ✅ FINST-NLD66NA171BT4QDDCKR6HBD8XSHG3UJ1FSP7MJ39.png\n",
"[Batch 1] ✅ FINST-OPA665A1KV9TAY9UA78YID6X4S4Y2HPA03N7MO3.png\n",
"[Batch 1] ✅ FINST-P6D66F71YYMY4D4PE6FL58E9BU8X3JUP0G6FM6R.xlsx\n",
"[Batch 1] ✅ FINST-PF866EA1IKDECQEC8I8IECI2W3YI38JSXOPMLP8.jpg\n",
"[Batch 1] ✅ FINST-PJE66J91RJNZ1RSPBUYJB5ZF2PTI2TGY7PLGMAN.jpg\n",
"[Batch 1] ✅ FINST-PQ5669911JFP4W356K5HS98S8MZC2MUHMO82MX5.png\n",
"[Batch 1] ✅ FINST-PRF66GB105ZWQSK7CUNWR97ZV6LG3050I9UCMAY.png\n",
"[Batch 1] ✅ FINST-QJG66FC1JCE085Q3N439VAMLKVFF3GUQFMOHMEF2.xlsx\n",
"[Batch 1] ✅ FINST-QJG66IB1GWQZN4GVAGZCW8NQ61VB3AK3KSRGMWY1.xlsx\n",
"[Batch 1] ✅ FINST-QKC666919BQY70PZ8G3T57AX7UNA29H3N0BFMSC.xlsx\n",
"[Batch 1] ✅ FINST-QW8665B1XE41XSIJK01GJCNZ5YNQ2CRLVXNIMZW.png\n",
"[Batch 1] ✅ FINST-RAC66GD197JYBI9Q9WU4B731F3O52QOQQ42FMFR5.jpg\n",
"[Batch 1] ✅ FINST-UAD66591M1KJAXF6CROAFDK9Y4PD3IFY2QZTLUR1.jpg\n",
"[Batch 1] ✅ FINST-UH9665D1TLYDLO5TDNPV0CEJTFGX2AMSWP4MLGP.png\n",
"[Batch 1] ✅ FINST-USC66V6144XYJV79FR19G4JRKPA52X6OX8LFMWU3.xlsx\n",
"[Batch 1] ✅ FINST-UZA66QC18I9WZM23F0GIC4UMA25B2C14SHUBM742.png\n",
"[Batch 1] ✅ FINST-WM6666B10OZIDIA9C6K6R8A6NXEU3UON1HETL2ZJ.jpg\n",
"[Batch 1] ✅ FINST-WSF66J812FUXCO5ZCWI70C2TW7TG2OMS0F2EMAP1.png\n",
"[Batch 1] ✅ FINST-WSF66J818UYXDCKS8IZ7K50QAGNH2K3MJG8EMJP1.xlsx\n",
"[Batch 1] ✅ FINST-WYG66T718EQ0Z4TMNO8P2CRTS6NE3EUF016IMSDA.pptx\n",
"[Batch 1] ✅ FINST-Z6966NB14IDEWL268Y71A8FOS0HD2ROSG3QMLGZ3.mp4\n",
"[Batch 1] ✅ FINST-ZH866O918DRFX8WWEBEDSBMRTNU93TRYXNNOLVY.jpg\n",
"[Batch 1] ✅ FINST-ZKD66Q71XPBRGBVI8Z5FGCIWR2KS2NCI9TZ4MQ5L.xlsx\n",
"📁 正在生成批次 2: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_2\n",
"[Batch 2] ✅ FINST-0D866I81JANY5WG8A2DT15S63HZH20YFR68FMQJA.png\n",
"[Batch 2] ✅ FINST-0HD66Z81DFXYBP816VRKD6S2HA2H3RYCBYKFMR6.jpg\n",
"[Batch 2] ✅ FINST-54A66HC1426KP5L87MXEA682I67O23YKVXUUL9U9.jpg\n",
"[Batch 2] ✅ FINST-65D66X71VHAPFNPZ9OFURCIREZAS28FI7P12MJS.jpg\n",
"[Batch 2] ✅ FINST-9FA66WC1LDJNFROD7HJUI4OJ6C2J22UP25SZLUQA.jpg\n",
"[Batch 2] ✅ FINST-BL866S61XU8DOZG5BZ6E4DZ2UOIV3B6CEHALL3QI.png\n",
"[Batch 2] ✅ FINST-ETA66681ZAHDHL2OA0MQR6UB9W5N2MZM2DGLLU2.xlsx\n",
"[Batch 2] ✅ FINST-HRD66W919462UFW0NG4PODHZZUW63074RZAKM1DK.png\n",
"[Batch 2] ✅ FINST-IQC66GC18W4YQ8GSCL23T582HU1H3960PVGEML8.png\n",
"[Batch 2] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"[Batch 2] ✅ FINST-J3D66LA13NTHEZAICABNRCD3KVCY222Q7IORL7UD.xlsx\n",
"[Batch 2] ✅ FINST-K7E66Z91F5NYOC0UD20BO775JN8C3D763K6FM16.xlsx\n",
"[Batch 2] ✅ FINST-KW866QB13VPZ5OSE9CE0LAWVKEO23QA4XVOGM92.jpg\n",
"[Batch 2] ✅ FINST-LLA66D71DDUN56UUBRVZVD2EO3TS291ZDU00M734.png\n",
"[Batch 2] ✅ FINST-NLD66NA171BT4QDDCKR6HBD8XSHG3UJ1FSP7MJ39.png\n",
"[Batch 2] ✅ FINST-PF866EA1IKDECQEC8I8IECI2W3YI38JSXOPMLP8.jpg\n",
"📁 正在生成批次 3: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_3\n",
"[Batch 3] ✅ FINST-65D66X71VHAPFNPZ9OFURCIREZAS28FI7P12MJS.png\n",
"[Batch 3] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"📁 正在生成批次 4: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_4\n",
"[Batch 4] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"📁 正在生成批次 5: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_5\n",
"[Batch 5] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"📁 正在生成批次 6: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_6\n",
"[Batch 6] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"📁 正在生成批次 7: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_7\n",
"[Batch 7] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"📁 正在生成批次 8: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_8\n",
"[Batch 8] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"📁 正在生成批次 9: C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\\输出_9\n",
"[Batch 9] ✅ FINST-J0A66981DAZDOPI7EF20N91K9UM72O8N526MLZO2.png\n",
"\n",
"🎉 处理完成!共生成 9 个批次文件夹。\n"
]
}
],
"source": [
"import os\n",
"import shutil\n",
"import re\n",
"import hashlib\n",
"\n",
"# 配置\n",
"root_path = r\"C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\FPO提交_20260207112107_resources_1\"\n",
"\n",
"# 存储:{finst_id: [file_path1, file_path2, ...]}\n",
"instance_files = {}\n",
"\n",
"# Windows 非法字符\n",
"ILLEGAL_CHARS = r'[<>:\"/\\\\|?*\\x00-\\x1f]'\n",
"\n",
"def extract_or_fallback_prefix(dirname):\n",
" match = re.match(r'^(FINST-[A-Z0-9]{10,})', dirname)\n",
" return match.group(1) if match else dirname\n",
"\n",
"def sanitize_filename_part(part):\n",
" return re.sub(ILLEGAL_CHARS, '_', part)\n",
"\n",
"print(\"🔍 正在扫描所有文件...\")\n",
"\n",
"# 第一步:遍历并按 FINST-ID 分组\n",
"for dirpath, dirnames, filenames in os.walk(root_path):\n",
" rel_path = os.path.relpath(dirpath, root_path)\n",
" if rel_path.startswith(\"输出_\"):\n",
" continue\n",
"\n",
" parts = rel_path.split(os.sep)\n",
" \n",
" # 找到路径中第一个 FINST- 开头的目录\n",
" finst_dirname = None\n",
" for part in parts:\n",
" if part.startswith(\"FINST-\"):\n",
" finst_dirname = part\n",
" break\n",
" \n",
" if finst_dirname is None:\n",
" continue\n",
"\n",
" clean_prefix = extract_or_fallback_prefix(finst_dirname)\n",
" safe_prefix = sanitize_filename_part(clean_prefix)\n",
"\n",
" for filename in filenames:\n",
" src_file = os.path.join(dirpath, filename)\n",
" instance_files.setdefault(safe_prefix, []).append(src_file)\n",
"\n",
"print(f\"✅ 共找到 {len(instance_files)} 个实例,总计 {sum(len(v) for v in instance_files.values())} 个文件\")\n",
"\n",
"# 第二步:按轮次分发到输出文件夹\n",
"max_rounds = max(len(files) for files in instance_files.values()) if instance_files else 0\n",
"\n",
"for round_index in range(max_rounds):\n",
" batch_index = round_index + 1\n",
" output_dir = os.path.join(root_path, f\"输出_{batch_index}\")\n",
" os.makedirs(output_dir, exist_ok=True)\n",
" print(f\"📁 正在生成批次 {batch_index}: {output_dir}\")\n",
"\n",
" for finst_id, file_list in instance_files.items():\n",
" if round_index < len(file_list):\n",
" src_file = file_list[round_index]\n",
" _, ext = os.path.splitext(src_file)\n",
" safe_ext = sanitize_filename_part(ext)\n",
" if safe_ext and not safe_ext.startswith('.'):\n",
" safe_ext = '.' + safe_ext\n",
"\n",
" # 编号从 2 开始:第0个 → -2, 第1个 → -3, ...\n",
" counter = round_index + 1\n",
" target_name = f\"{finst_id}{safe_ext}\"\n",
"\n",
"\n",
"\n",
" dst_file = os.path.join(output_dir, target_name)\n",
"\n",
" try:\n",
" shutil.copy2(src_file, dst_file)\n",
" print(f\"[Batch {batch_index}] ✅ {target_name}\")\n",
" except Exception as e:\n",
" print(f\"[Batch {batch_index}] ❌ 复制失败: {e}\")\n",
"\n",
"print(f\"\\n🎉 处理完成!共生成 {max_rounds} 个批次文件夹。\")"
]
},
{
"cell_type": "markdown",
"id": "3bf861d3",
"metadata": {},
"source": [
"附件、图片\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "90309f69",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🔍 正在扫描所有文件...\n",
"✅ 共找到 9 个文件,分属:附件、图片、其他\n",
"\n",
"📦 处理类别: 附件 (共 1 批)\n",
"[附件 Batch 1] ✅ FINST-56B66Q91XU6TMONCFZBLBCVK9MS03SSG3SI7MR1.pdf\n",
"[附件 Batch 1] ✅ FINST-C98664A1A8XJTVAW9W0256C4AF5S2JIWPBIULNM3.pdf\n",
"[附件 Batch 1] ✅ FINST-JZ766R91YWUW0FZ6CXRXSBAVXQ0J2ZOZEEOCMGA.pdf\n",
"[附件 Batch 1] ✅ FINST-R3D664B1B7ZYYR569QITJB9VCZXT2B8WIUNFM4X2.xlsx\n",
"[附件 Batch 1] ✅ FINST-RC966V713AMLLTHG8M1UBD6OK7EG3M3PWTYWLQYL.pdf\n",
"[附件 Batch 1] ✅ FINST-SUC66KA1UDIL18KXAMFCK9PW64XN375YHFQWLLC.pdf\n",
"[附件 Batch 1] ✅ FINST-TM966BD1Y9HK1YK1BFUOL9IO9TSI3WK4G6CVLS45.xlsx\n",
"[附件 Batch 1] ✅ FINST-ZKD66Q719O2TZRLY5HZJNAFGJW2F2IE4JYC7M0F.jpg\n",
"\n",
"📦 处理类别: 图片 (共 1 批)\n",
"[图片 Batch 1] ✅ FINST-SUC66KA1C5YJQ4NNAKAGHBOOPPFQ3QX7EJQULEKV1.jpg\n",
"\n",
"🎉 所有类别处理完成!\n"
]
}
],
"source": [
"import os\n",
"import shutil\n",
"import re\n",
"import hashlib\n",
"\n",
"# 配置\n",
"root_path = r\"C:\\Users\\hp_z66\\OneDrive\\Desktop\\新建文件夹\\商机提交_20260209161647_resources_1\"\n",
"\n",
"# 分类存储:{\"附件\": {finst_id: [file1, file2, ...]}, \"图片\": {...}, \"其他\": {...}}\n",
"categorized_files = {\n",
" \"附件\": {},\n",
" \"图片\": {},\n",
" \"其他\": {}\n",
"}\n",
"\n",
"# Windows 非法字符\n",
"ILLEGAL_CHARS = r'[<>:\"/\\\\|?*\\x00-\\x1f]'\n",
"\n",
"def extract_or_fallback_prefix(dirname):\n",
" match = re.match(r'^(FINST-[A-Z0-9]{10,})', dirname)\n",
" return match.group(1) if match else dirname\n",
"\n",
"def sanitize_filename_part(part):\n",
" return re.sub(ILLEGAL_CHARS, '_', part)\n",
"\n",
"print(\"🔍 正在扫描所有文件...\")\n",
"\n",
"# 第一步:遍历并按来源分类 + 按 FINST-ID 分组\n",
"for dirpath, dirnames, filenames in os.walk(root_path):\n",
" rel_path = os.path.relpath(dirpath, root_path)\n",
" if rel_path.startswith(\"输出_\"):\n",
" continue\n",
"\n",
" parts = rel_path.split(os.sep)\n",
" \n",
" # 找到第一个 FINST- 开头的目录\n",
" finst_dirname = None\n",
" for part in parts:\n",
" if part.startswith(\"FINST-\"):\n",
" finst_dirname = part\n",
" break\n",
" \n",
" if finst_dirname is None:\n",
" continue\n",
"\n",
" clean_prefix = extract_or_fallback_prefix(finst_dirname)\n",
" safe_prefix = sanitize_filename_part(clean_prefix)\n",
"\n",
" # 判断当前路径相对于 FINST-xxx 的位置\n",
" relative_to_finst = rel_path[len(finst_dirname):].lstrip(os.sep)\n",
" source_type = \"其他\"\n",
"\n",
" if relative_to_finst == \"\" or not relative_to_finst:\n",
" # 文件直接在 FINST-xxx 下\n",
" source_type = \"其他\"\n",
" elif relative_to_finst.startswith(\"附件\") or \"附件\" in relative_to_finst.split(os.sep):\n",
" source_type = \"附件\"\n",
" elif relative_to_finst.startswith(\"图片\") or \"图片\" in relative_to_finst.split(os.sep):\n",
" source_type = \"图片\"\n",
" else:\n",
" source_type = \"其他\"\n",
"\n",
" for filename in filenames:\n",
" src_file = os.path.join(dirpath, filename)\n",
" categorized_files[source_type].setdefault(safe_prefix, []).append(src_file)\n",
"\n",
"# 统计\n",
"total_files = sum(\n",
" len(files) \n",
" for category in categorized_files.values() \n",
" for files in category.values()\n",
")\n",
"print(f\"✅ 共找到 {total_files} 个文件,分属:附件、图片、其他\")\n",
"\n",
"# 第二步:对每种类别独立进行轮次分发\n",
"for category_name, instance_dict in categorized_files.items():\n",
" if not instance_dict:\n",
" continue\n",
"\n",
" max_rounds = max(len(files) for files in instance_dict.values())\n",
" print(f\"\\n📦 处理类别: {category_name} (共 {max_rounds} 批)\")\n",
"\n",
" for round_index in range(max_rounds):\n",
" batch_index = round_index + 1\n",
" output_dir = os.path.join(root_path, f\"输出_{category_name}_{batch_index}\")\n",
" os.makedirs(output_dir, exist_ok=True)\n",
"\n",
" for finst_id, file_list in instance_dict.items():\n",
" if round_index < len(file_list):\n",
" src_file = file_list[round_index]\n",
" _, ext = os.path.splitext(src_file)\n",
" safe_ext = sanitize_filename_part(ext)\n",
" if safe_ext and not safe_ext.startswith('.'):\n",
" safe_ext = '.' + safe_ext\n",
"\n",
" # 文件名:FINST-XXX.ext (无任何后缀)\n",
" target_name = f\"{finst_id}{safe_ext}\"\n",
"\n",
" # 防止过长\n",
" if len(target_name) > 200:\n",
" hash_part = hashlib.md5(finst_id.encode()).hexdigest()[:8]\n",
" truncated = finst_id[:100] + \"_\" + hash_part\n",
" target_name = f\"{truncated}{safe_ext}\"\n",
"\n",
" dst_file = os.path.join(output_dir, target_name)\n",
"\n",
" try:\n",
" shutil.copy2(src_file, dst_file)\n",
" print(f\"[{category_name} Batch {batch_index}] ✅ {target_name}\")\n",
" except Exception as e:\n",
" print(f\"[{category_name} Batch {batch_index}] ❌ 复制失败: {e}\")\n",
"\n",
"print(f\"\\n🎉 所有类别处理完成!\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "F6+宜搭+其它",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}