脚本
This commit is contained in:
+64
-65
@@ -2,14 +2,32 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
"id": "initial_id",
|
"id": "initial_id",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"collapsed": true,
|
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2026-01-22T03:01:15.515786400Z",
|
"end_time": "2026-01-22T03:01:15.515786400Z",
|
||||||
"start_time": "2026-01-22T03:01:12.175041100Z"
|
"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": [
|
"source": [
|
||||||
"import time\n",
|
"import time\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -100,40 +118,42 @@
|
|||||||
"ndf.to_excel(fr\"C:\\Users\\zy187\\Desktop\\云材料结果2.xlsx\")\n",
|
"ndf.to_excel(fr\"C:\\Users\\zy187\\Desktop\\云材料结果2.xlsx\")\n",
|
||||||
"fdf = pd.DataFrame(fild_data)\n",
|
"fdf = pd.DataFrame(fild_data)\n",
|
||||||
"fdf.to_excel(fr\"C:\\Users\\zy187\\Desktop\\失败项目材料2.xlsx\")"
|
"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",
|
"cell_type": "markdown",
|
||||||
"source": "# 关键字搜索",
|
"id": "713d0645f9b5b8b0",
|
||||||
"id": "713d0645f9b5b8b0"
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# 关键字搜索"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"id": "56303413fee1137",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2026-01-22T03:07:17.414079900Z",
|
"end_time": "2026-01-22T03:07:17.414079900Z",
|
||||||
"start_time": "2026-01-22T03:04:41.187628900Z"
|
"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": [
|
"source": [
|
||||||
"import time\n",
|
"import time\n",
|
||||||
"import pandas as pd\n",
|
"import pandas as pd\n",
|
||||||
@@ -143,13 +163,13 @@
|
|||||||
"import requests\n",
|
"import requests\n",
|
||||||
"\n",
|
"\n",
|
||||||
"cookies = {\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",
|
" 'erpLanguage': 'zh-CN',\n",
|
||||||
" 'tmall': 'false',\n",
|
" 'tmall': 'false',\n",
|
||||||
" 'prodOrg': '11240984669917188035',\n",
|
" 'prodOrg': '11240984669917217520',\n",
|
||||||
" 'unp': '15919462121159692302',\n",
|
" 'unp': '15865484595890778191',\n",
|
||||||
" '_up': '-NillNN-qyBEJ--t3vnSknvoOF52zPiJts8E0Xo-X-5bX_PCp5vQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqEvoUrY0m3wAK_vRRv-ZNHu3M-GTc15m4EXGqr-9UiO4Tll_BPRNtrEj9nhm_qsCwNGE.',\n",
|
" '_up': '-NillNN-qyBEJ--t3vnSknvoOF53y_SJuMkA2n43U-daUfnArpjQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqE_MWrI8g0QME_vJRv-ZNHu3M-GTc1p60EX-sq-RQgeIal1HLPxpurEj9mUa59cnvQWI.',\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",
|
" '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",
|
"\n",
|
||||||
"headers = {\n",
|
"headers = {\n",
|
||||||
@@ -166,14 +186,14 @@
|
|||||||
" 'sec-fetch-mode': 'cors',\n",
|
" 'sec-fetch-mode': 'cors',\n",
|
||||||
" 'sec-fetch-site': 'same-origin',\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",
|
" '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",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"all_data = []\n",
|
"all_data = []\n",
|
||||||
"for i in tqdm(range(1, 56)):\n",
|
"for i in tqdm(range(1, 4)):\n",
|
||||||
" json_data = {\n",
|
" json_data = {\n",
|
||||||
" 'keyword': '凤凰',\n",
|
" 'keyword': \"思卫博\",\n",
|
||||||
" 'type': 0,\n",
|
" 'type': 0,\n",
|
||||||
" 'facetFields': [\n",
|
" 'facetFields': [\n",
|
||||||
" ],\n",
|
" ],\n",
|
||||||
@@ -198,64 +218,43 @@
|
|||||||
" all_data.append(item)\n",
|
" all_data.append(item)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"ndf = pd.DataFrame(all_data)\n",
|
"ndf = pd.DataFrame(all_data)\n",
|
||||||
"ndf.to_excel(fr\"D:\\Idea Project\\F6+宜搭+其它(1)\\张阳脚本\\云材料结果.xlsx\")"
|
"ndf.to_excel(fr\"D:\\Idea Project\\F6+宜搭+其它(1)\\张阳脚本\\云材料结果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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"id": "15e7fa1e9c5b91b",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2026-01-05T06:05:31.695215600Z",
|
"end_time": "2026-01-05T06:05:31.695215600Z",
|
||||||
"start_time": "2026-01-05T06:05:30.160772900Z"
|
"start_time": "2026-01-05T06:05:30.160772900Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cell_type": "code",
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"ndf = pd.DataFrame(all_data)\n",
|
"ndf = pd.DataFrame(all_data)\n",
|
||||||
"ndf.to_excel(fr\"C:\\Users\\hp_z66\\Desktop\\云材料结果.xlsx\")"
|
"ndf.to_excel(fr\"C:\\Users\\hp_z66\\Desktop\\云材料结果.xlsx\")"
|
||||||
],
|
]
|
||||||
"id": "15e7fa1e9c5b91b",
|
|
||||||
"outputs": [],
|
|
||||||
"execution_count": 2
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "Python 3",
|
"display_name": "F6+宜搭+其它",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
"name": "python3"
|
"name": "python3"
|
||||||
},
|
},
|
||||||
"language_info": {
|
"language_info": {
|
||||||
"codemirror_mode": {
|
"codemirror_mode": {
|
||||||
"name": "ipython",
|
"name": "ipython",
|
||||||
"version": 2
|
"version": 3
|
||||||
},
|
},
|
||||||
"file_extension": ".py",
|
"file_extension": ".py",
|
||||||
"mimetype": "text/x-python",
|
"mimetype": "text/x-python",
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython2",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "2.7.6"
|
"version": "3.13.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+105
-106
@@ -10,9 +10,9 @@ from module import F6_module
|
|||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
f6_module = F6_module()
|
f6_module = F6_module()
|
||||||
username = "18911549229"
|
username = "18751893221"
|
||||||
password = "Zyj030415"
|
password = "123456Ab"
|
||||||
store_name = "乾多多洗车美容"
|
store_name = "新众合车酷"
|
||||||
|
|
||||||
res = f6_module.login_in(username, password, store_name)
|
res = f6_module.login_in(username, password, store_name)
|
||||||
|
|
||||||
@@ -23,13 +23,13 @@ headers = {
|
|||||||
}
|
}
|
||||||
count = 1
|
count = 1
|
||||||
try:
|
try:
|
||||||
df = pd.read_excel(r"C:\Users\zy187\Desktop\钉钉文件\会员卡信息-刷折扣.xls",
|
df = pd.read_excel(r"C:\Users\hp_z66\OneDrive\Desktop\钉钉文件\会员卡信息.新.xlsx",
|
||||||
sheet_name='0.90',
|
sheet_name='Sheet2',
|
||||||
dtype='string')
|
dtype='string')
|
||||||
|
|
||||||
items = {'洗车': '2694036', '美容': '2694033', } # 修改的内容(含新增)
|
items = {'洗车': '2759725',"美容":"2759722"} # 修改的内容(含新增)
|
||||||
discount = '0.90' # 需要修改的折扣
|
# discount = '0.90' # 需要修改的折扣
|
||||||
# discount_list = {'维修': '0.80', '美容': '0.80', '保养': '0.80', '洗车': '0.80'}
|
discount_list = { '美容': '0.68', '洗车': '0.68'}
|
||||||
|
|
||||||
# print(df)
|
# print(df)
|
||||||
cookies = requests.utils.dict_from_cookiejar(res.cookies)
|
cookies = requests.utils.dict_from_cookiejar(res.cookies)
|
||||||
@@ -61,102 +61,101 @@ try:
|
|||||||
carInfoList.append(List)
|
carInfoList.append(List)
|
||||||
# 提取cardEntityBusinessList
|
# 提取cardEntityBusinessList
|
||||||
cardEntityBusinessList = [
|
cardEntityBusinessList = [
|
||||||
{
|
{
|
||||||
"labelName": "维修",
|
"labelName": "维修",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694031"
|
"labelId": "2759720"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "保养",
|
"labelName": "保养",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694032"
|
"labelId": "2759721"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "美容",
|
"labelName": "美容",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694033"
|
"labelId": "2759722"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "钣喷",
|
"labelName": "钣喷",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694034"
|
"labelId": "2759723"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "轮胎",
|
"labelName": "轮胎",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694035"
|
"labelId": "2759724"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "洗车",
|
"labelName": "洗车",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694036"
|
"labelId": "2759725"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "精品",
|
"labelName": "精品",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694037"
|
"labelId": "2759726"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "其他",
|
"labelName": "其他",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694038"
|
"labelId": "2759727"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "零售",
|
"labelName": "零售",
|
||||||
"businessType": 0,
|
"businessType": 0,
|
||||||
"labelId": "2694039"
|
"labelId": "2759728"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "维修",
|
"labelName": "维修",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694031"
|
"labelId": "2759720"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "保养",
|
"labelName": "保养",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694032"
|
"labelId": "2759721"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "美容",
|
"labelName": "美容",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694033"
|
"labelId": "2759722"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "钣喷",
|
"labelName": "钣喷",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694034"
|
"labelId": "2759723"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "轮胎",
|
"labelName": "轮胎",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694035"
|
"labelId": "2759724"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "洗车",
|
"labelName": "洗车",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694036"
|
"labelId": "2759725"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "精品",
|
"labelName": "精品",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694037"
|
"labelId": "2759726"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "其他",
|
"labelName": "其他",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694038"
|
"labelId": "2759727"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"labelName": "零售",
|
"labelName": "零售",
|
||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"labelId": "2694039"
|
"labelId": "2759728"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"businessType": 2,
|
"businessType": 2,
|
||||||
"labelId": "0"
|
"labelId": "0"
|
||||||
}
|
}
|
||||||
|
]
|
||||||
]
|
|
||||||
|
|
||||||
# 提取cardEntityBusinessDiscountList
|
# 提取cardEntityBusinessDiscountList
|
||||||
cardEntityBusinessDiscountList = []
|
cardEntityBusinessDiscountList = []
|
||||||
@@ -166,7 +165,7 @@ try:
|
|||||||
# for cardEntityBusinessDiscount in cardEntityBusinessList:
|
# for cardEntityBusinessDiscount in cardEntityBusinessList:
|
||||||
try:
|
try:
|
||||||
for item, labe in items.items(): # items() 返回一个列表
|
for item, labe in items.items(): # items() 返回一个列表
|
||||||
# discount = discount_list.get(item, 0) # 针对不同折扣
|
discount = discount_list.get(item, 0) # 针对不同折扣
|
||||||
List = {
|
List = {
|
||||||
# "labelName": cardEntityBusinessList['labelName'], # 修改原来有折扣的选项
|
# "labelName": cardEntityBusinessList['labelName'], # 修改原来有折扣的选项
|
||||||
"labelName": item, #
|
"labelName": item, #
|
||||||
@@ -222,7 +221,7 @@ try:
|
|||||||
"businessType": 1,
|
"businessType": 1,
|
||||||
"useIdOwnOrgList":
|
"useIdOwnOrgList":
|
||||||
[
|
[
|
||||||
"15982098507125256267"
|
"16041647893945294910"
|
||||||
], # 需要修改
|
], # 需要修改
|
||||||
# 适用门店需要获取 res_version['data']['idOwnOrg']
|
# 适用门店需要获取 res_version['data']['idOwnOrg']
|
||||||
"cardEntitySkuDiscountList": res['info']['valueCardEntitySkuDiscountInfoList']
|
"cardEntitySkuDiscountList": res['info']['valueCardEntitySkuDiscountInfoList']
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from tqdm import tqdm
|
|||||||
from module import F6_module
|
from module import F6_module
|
||||||
import time
|
import time
|
||||||
from http.cookies import SimpleCookie
|
from http.cookies import SimpleCookie
|
||||||
|
|
||||||
# f6_module = F6_module()
|
# f6_module = F6_module()
|
||||||
#
|
|
||||||
# username = "18742526670"
|
# username = "18742526670"
|
||||||
# password = "Zy18742526670"
|
# password = "Zy18742526670"
|
||||||
# store_name = "F6汽车科技数据组测试(废弃)"
|
# store_name = "F6汽车科技数据组测试(废弃)"
|
||||||
@@ -20,10 +20,10 @@ def parse_cookie_string(cookie_str):
|
|||||||
return {k: v.value for k, v in cookie.items()}
|
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)
|
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()):
|
for index,row in tqdm(df.iterrows()):
|
||||||
brandNmae = row["品牌名"]
|
brandNmae = row["品牌名"]
|
||||||
# cookies = requests.utils.dict_from_cookiejar(cookies)
|
# 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
@@ -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
|
FORMID1 = "FORM-33666CB1XDU37AU57RKPK990C79S2YMOEEC8LS" # [表单]异常服务跟进待办2023
|
||||||
|
|
||||||
# 读取excel表格
|
# 读取excel表格
|
||||||
df = pd.read_excel(r"C:\Users\hp_z66\Desktop\钉钉文件\(流程)续约服务流程_20260129144824.xlsx",
|
df = pd.read_excel(r"C:\Users\hp_z66\OneDrive\Desktop\钉钉文件\2026-1回访已回访.xlsx",
|
||||||
sheet_name='Sheet1', dtype='string', header=1) # 此处将表头设置为了第二行
|
sheet_name='Sheet5', dtype='string', header=1) # 此处将表头设置为了第二行
|
||||||
df.fillna('', inplace=True)
|
df.fillna('', inplace=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class Main:
|
|||||||
|
|
||||||
|
|
||||||
# 读取excel表格获取数据
|
# 读取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("已读取表格")
|
print("已读取表格")
|
||||||
|
|
||||||
# 执行自动化脚本
|
# 执行自动化脚本
|
||||||
|
|||||||
-479
@@ -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}')
|
|
||||||
@@ -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" # 接车宝历史派发表单
|
|
||||||
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user