Functions-d 1.2.5__tar.gz → 1.28__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d/Functions_d.py +311 -13
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d/__init__.py +1 -1
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d.egg-info/PKG-INFO +1 -1
- {functions_d-1.2.5 → functions_d-1.28}/PKG-INFO +1 -1
- {functions_d-1.2.5 → functions_d-1.28}/setup.cfg +1 -1
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d.egg-info/SOURCES.txt +0 -0
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d.egg-info/dependency_links.txt +0 -0
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d.egg-info/requires.txt +0 -0
- {functions_d-1.2.5 → functions_d-1.28}/Functions_d.egg-info/top_level.txt +0 -0
- {functions_d-1.2.5 → functions_d-1.28}/README.md +0 -0
- {functions_d-1.2.5 → functions_d-1.28}/pyproject.toml +0 -0
- {functions_d-1.2.5 → functions_d-1.28}/setup.py +0 -0
|
@@ -148,6 +148,7 @@ class DataProcessingAndMessaging:
|
|
|
148
148
|
self.logger.info('\n' * 10)
|
|
149
149
|
|
|
150
150
|
# -------------------------- 企业微信消息发送 --------------------------
|
|
151
|
+
# 仅展示修改后的 uxin_wx 方法,其余代码不变
|
|
151
152
|
def uxin_wx(self, name, message, mentioned_list=None):
|
|
152
153
|
sender = WeComMsg.WeChatWorkSender(self.corpid, self.corpsecret, self.agentid)
|
|
153
154
|
try:
|
|
@@ -158,6 +159,43 @@ class DataProcessingAndMessaging:
|
|
|
158
159
|
target_type = "群聊(Webhook)" if name.startswith("https://") else "单个用户"
|
|
159
160
|
self.logger.info(f"开始向{target_type}发送消息,目标:{name}")
|
|
160
161
|
|
|
162
|
+
# ========== 新增:Markdown消息识别与处理 ==========
|
|
163
|
+
# 识别规则:message以特定标识开头(如「MD:」),或显式传入markdown类型
|
|
164
|
+
is_markdown = False
|
|
165
|
+
md_content = ""
|
|
166
|
+
if isinstance(message, dict) and message.get("type") == "markdown":
|
|
167
|
+
# 支持字典格式传参:{"type": "markdown", "content": "markdown内容"}
|
|
168
|
+
is_markdown = True
|
|
169
|
+
md_content = message.get("content", "")
|
|
170
|
+
elif isinstance(message, str) and message.startswith("MD:"):
|
|
171
|
+
# 支持字符串前缀标识:"MD:### 标题\n内容"
|
|
172
|
+
is_markdown = True
|
|
173
|
+
md_content = message[3:].strip() # 去掉前缀"MD:"
|
|
174
|
+
|
|
175
|
+
if is_markdown:
|
|
176
|
+
# 处理Markdown消息
|
|
177
|
+
if isinstance(name, str) and name.startswith("https://"):
|
|
178
|
+
# 群聊Webhook发送Markdown
|
|
179
|
+
self.logger.info(f"发送群聊Markdown消息:内容={md_content}")
|
|
180
|
+
result = sender.send_markdown_to_group(name, md_content)
|
|
181
|
+
else:
|
|
182
|
+
# 个人/多用户发送Markdown
|
|
183
|
+
receivers = name if isinstance(name, list) else [name]
|
|
184
|
+
self.logger.info(f"发送个人Markdown消息:内容={md_content},接收者:{receivers}")
|
|
185
|
+
result = sender.send_markdown(receivers, md_content)
|
|
186
|
+
|
|
187
|
+
msg_id = result.get('msgid', '未知')
|
|
188
|
+
self.logger.info(
|
|
189
|
+
f"Markdown消息发送结果:{'成功' if result.get('errcode') == 0 else '失败'},错误信息:{result.get('errmsg')},消息ID:{msg_id}")
|
|
190
|
+
|
|
191
|
+
if result.get('errcode') == 0:
|
|
192
|
+
print(f"给 {target_type} 的Markdown消息发送成功,消息ID:{msg_id}")
|
|
193
|
+
else:
|
|
194
|
+
print(
|
|
195
|
+
f"给 {target_type} 的Markdown消息发送失败,错误码:{result.get('errcode')},错误信息:{result.get('errmsg')},消息ID:{msg_id}")
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
# ========== 原有逻辑(文本/文件/图片)保持不变 ==========
|
|
161
199
|
if isinstance(name, str) and name.startswith("https://"):
|
|
162
200
|
if isinstance(message, str) and message.endswith(('.xlsx', '.docx', '.pdf', '.txt')) and os.path.isfile(
|
|
163
201
|
message):
|
|
@@ -1028,15 +1066,55 @@ class DataProcessingAndMessaging:
|
|
|
1028
1066
|
self._wechat_doc_log(error_msg)
|
|
1029
1067
|
raise Exception(error_msg)
|
|
1030
1068
|
docid = result.get("docid")
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1069
|
+
# ========== 新增:添加创建时间 ==========
|
|
1070
|
+
# 获取当前时间(北京时间,格式:YYYY-MM-DD HH:MM:SS)
|
|
1071
|
+
create_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
1072
|
+
|
|
1073
|
+
# ========== 核心新增:创建成功后自动查询子sheet ==========
|
|
1074
|
+
self._wechat_doc_log(f"开始查询新创建表格[{docid}]的子表信息")
|
|
1075
|
+
# 然后修改wx_create_table中调用wx_get_sheets的代码,传入send_notice=False:
|
|
1076
|
+
sheet_list = self.wx_get_sheets(docid, send_notice=False)
|
|
1077
|
+
|
|
1078
|
+
# ========== 构造包含子sheet的完整消息内容 ==========
|
|
1079
|
+
# 基础信息
|
|
1080
|
+
msg_content = f"✅ 智能表格创建成功\n表格名称:{sheet_name}\n创建时间:{create_time}\ndocid:{docid}\n\n子表信息:"
|
|
1081
|
+
# 子sheet信息
|
|
1082
|
+
if sheet_list:
|
|
1083
|
+
for idx, sheet in enumerate(sheet_list, 1):
|
|
1084
|
+
sheet_visibility = '可见' if sheet['is_visible'] else '不可见'
|
|
1085
|
+
msg_content += f"\n{idx}. ID: {sheet['sheet_id']} | 标题: {sheet['title']} | 类型: {sheet['type']} | 可见性: {sheet_visibility}"
|
|
1086
|
+
else:
|
|
1087
|
+
msg_content += "\n暂无子表信息"
|
|
1088
|
+
|
|
1089
|
+
self._wechat_doc_log(
|
|
1090
|
+
f"智能表格:{sheet_name} 创建成功,docid={docid},创建时间={create_time},子表数量:{len(sheet_list)}")
|
|
1091
|
+
print(f"智能表格:{sheet_name} 创建成功,docid={docid},创建时间={create_time}")
|
|
1092
|
+
print(f"该表格的子表信息:")
|
|
1093
|
+
if sheet_list:
|
|
1094
|
+
for idx, sheet in enumerate(sheet_list, 1):
|
|
1095
|
+
sheet_visibility = '可见' if sheet['is_visible'] else '不可见'
|
|
1096
|
+
print(
|
|
1097
|
+
f" {idx}. ID: {sheet['sheet_id']} | 标题: {sheet['title']} | 类型: {sheet['type']} | 可见性: {sheet_visibility}")
|
|
1098
|
+
else:
|
|
1099
|
+
print(" 暂无子表信息")
|
|
1100
|
+
|
|
1101
|
+
# 调用uxin_wx发送包含子sheet的完整消息
|
|
1102
|
+
self.uxin_wx('dongyang', msg_content)
|
|
1103
|
+
|
|
1104
|
+
return {
|
|
1105
|
+
"智能表格": sheet_name,
|
|
1106
|
+
"docid": docid,
|
|
1107
|
+
"url": result.get("url"),
|
|
1108
|
+
"创建时间": create_time,
|
|
1109
|
+
"子表列表": sheet_list # 返回值新增子sheet列表
|
|
1110
|
+
}
|
|
1034
1111
|
except Exception as e:
|
|
1035
1112
|
self._wechat_doc_log(f"创建异常: {str(e)}")
|
|
1036
1113
|
raise
|
|
1037
1114
|
|
|
1038
1115
|
# -------------------------- 企微文档:查询子表 --------------------------
|
|
1039
|
-
|
|
1116
|
+
# 修改wx_get_sheets方法的定义,新增send_notice参数
|
|
1117
|
+
def wx_get_sheets(self, docid, send_notice=True):
|
|
1040
1118
|
self._wechat_doc_log(f"查询文档[{docid}]的子表信息")
|
|
1041
1119
|
self._wechat_doc_refresh_token_if_needed()
|
|
1042
1120
|
|
|
@@ -1052,10 +1130,30 @@ class DataProcessingAndMessaging:
|
|
|
1052
1130
|
if result.get("errcode") != 0:
|
|
1053
1131
|
error_msg = f"查询子表失败: {result.get('errmsg')}"
|
|
1054
1132
|
self._wechat_doc_log(error_msg)
|
|
1133
|
+
# 失败时仍发送通知
|
|
1134
|
+
fail_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
1135
|
+
fail_content = f"⚠️ 企微文档子表查询失败\n查询时间:{fail_time}\n文档ID:{docid}\n错误信息:{result.get('errmsg')}"
|
|
1136
|
+
self.uxin_wx('dongyang', fail_content)
|
|
1055
1137
|
raise Exception(error_msg)
|
|
1056
1138
|
|
|
1057
1139
|
sheet_list = result.get("sheet_list", [])
|
|
1140
|
+
query_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
1058
1141
|
self._wechat_doc_log(f"查询文档[{docid}]子表完成,共找到{len(sheet_list)}个子表")
|
|
1142
|
+
|
|
1143
|
+
# 构造通知内容
|
|
1144
|
+
msg_content = f"✅ 企微文档子表查询完成\n查询时间:{query_time}\n文档ID:{docid}\n子表总数:{len(sheet_list)}\n\n子表详细信息:"
|
|
1145
|
+
if sheet_list:
|
|
1146
|
+
for idx, sheet in enumerate(sheet_list, 1):
|
|
1147
|
+
sheet_visibility = '可见' if sheet['is_visible'] else '不可见'
|
|
1148
|
+
msg_content += f"\n{idx}. ID: {sheet['sheet_id']} | 标题: {sheet['title']} | 类型: {sheet['type']} | 可见性: {sheet_visibility}"
|
|
1149
|
+
else:
|
|
1150
|
+
msg_content += "\n暂无子表信息"
|
|
1151
|
+
|
|
1152
|
+
# 仅当send_notice为True时发送通知
|
|
1153
|
+
if send_notice:
|
|
1154
|
+
self.uxin_wx('dongyang', msg_content)
|
|
1155
|
+
|
|
1156
|
+
# 原有日志和打印逻辑
|
|
1059
1157
|
for sheet in sheet_list:
|
|
1060
1158
|
sheet_info = (f"子表信息 - ID: {sheet['sheet_id']}, 标题: {sheet['title']}, "
|
|
1061
1159
|
f"类型: {sheet['type']}, 可见性: {'可见' if sheet['is_visible'] else '不可见'}")
|
|
@@ -1098,6 +1196,40 @@ class DataProcessingAndMessaging:
|
|
|
1098
1196
|
print(f"[企业微信文档] {msg}")
|
|
1099
1197
|
return pd.DataFrame()
|
|
1100
1198
|
|
|
1199
|
+
# 新增:解析公式列的核心函数
|
|
1200
|
+
def _parse_formula_field(field_value):
|
|
1201
|
+
"""
|
|
1202
|
+
解析公式列数据,提取公式计算后的数值结果
|
|
1203
|
+
公式列典型格式:{"type":"FormulaFieldProperty","value": 100, "expression": "A1+B1"}
|
|
1204
|
+
"""
|
|
1205
|
+
if not field_value:
|
|
1206
|
+
return ""
|
|
1207
|
+
|
|
1208
|
+
# 处理公式列的嵌套字典格式
|
|
1209
|
+
if isinstance(field_value, dict) and field_value.get("type") == "FormulaFieldProperty":
|
|
1210
|
+
formula_value = field_value.get("value")
|
|
1211
|
+
# 如果公式计算结果是数字,直接返回;否则返回空字符串
|
|
1212
|
+
if isinstance(formula_value, (int, float)):
|
|
1213
|
+
self._wechat_doc_log(f"解析公式列值:{field_value} → 提取数值{formula_value}")
|
|
1214
|
+
return formula_value
|
|
1215
|
+
else:
|
|
1216
|
+
self._wechat_doc_log(f"公式列无有效数值:{field_value}")
|
|
1217
|
+
return ""
|
|
1218
|
+
|
|
1219
|
+
# 兼容列表嵌套公式字典的情况
|
|
1220
|
+
elif isinstance(field_value, list) and len(field_value) > 0:
|
|
1221
|
+
formula_values = []
|
|
1222
|
+
for item in field_value:
|
|
1223
|
+
if isinstance(item, dict) and item.get("type") == "FormulaFieldProperty":
|
|
1224
|
+
val = item.get("value")
|
|
1225
|
+
if isinstance(val, (int, float)):
|
|
1226
|
+
formula_values.append(val)
|
|
1227
|
+
return formula_values[0] if formula_values else ""
|
|
1228
|
+
|
|
1229
|
+
# 非公式格式直接返回原值
|
|
1230
|
+
else:
|
|
1231
|
+
return field_value
|
|
1232
|
+
|
|
1101
1233
|
# 时间转换工具
|
|
1102
1234
|
def _unified_time_convert(value):
|
|
1103
1235
|
if value is None or str(value).strip() in ["", "None", "nan"]:
|
|
@@ -1149,6 +1281,118 @@ class DataProcessingAndMessaging:
|
|
|
1149
1281
|
else:
|
|
1150
1282
|
return raw_text
|
|
1151
1283
|
|
|
1284
|
+
# 判断是否为包含user_id的有效人员字段格式
|
|
1285
|
+
def _is_valid_person_format(field_value):
|
|
1286
|
+
"""
|
|
1287
|
+
判断字段值是否为包含user_id的有效人员格式(字典/列表嵌套字典且有user_id)
|
|
1288
|
+
"""
|
|
1289
|
+
# 空值直接返回False
|
|
1290
|
+
if not field_value:
|
|
1291
|
+
return False
|
|
1292
|
+
|
|
1293
|
+
# 列表类型:检查是否有元素包含user_id字段
|
|
1294
|
+
if isinstance(field_value, list):
|
|
1295
|
+
for item in field_value:
|
|
1296
|
+
if isinstance(item, dict) and item.get("user_id") is not None:
|
|
1297
|
+
return True
|
|
1298
|
+
return False
|
|
1299
|
+
|
|
1300
|
+
# 字典类型:检查是否有user_id字段
|
|
1301
|
+
elif isinstance(field_value, dict):
|
|
1302
|
+
return field_value.get("user_id") is not None
|
|
1303
|
+
|
|
1304
|
+
# 其他类型返回False
|
|
1305
|
+
else:
|
|
1306
|
+
return False
|
|
1307
|
+
|
|
1308
|
+
# 解析人员列数据的函数
|
|
1309
|
+
def _parse_person_field(field_value):
|
|
1310
|
+
"""
|
|
1311
|
+
解析人员列数据,提取所有人员名称/user_id,用逗号分隔
|
|
1312
|
+
"""
|
|
1313
|
+
if not field_value:
|
|
1314
|
+
return ""
|
|
1315
|
+
|
|
1316
|
+
# 如果是列表,遍历所有元素
|
|
1317
|
+
if isinstance(field_value, list):
|
|
1318
|
+
person_names = []
|
|
1319
|
+
for item in field_value:
|
|
1320
|
+
if isinstance(item, dict):
|
|
1321
|
+
# 优先获取名称相关字段,没有则用user_id
|
|
1322
|
+
name = item.get("name") or item.get("user_id") or item.get("text") or item.get("title")
|
|
1323
|
+
if name:
|
|
1324
|
+
person_names.append(str(name))
|
|
1325
|
+
else:
|
|
1326
|
+
# 如果没有名称字段,拼接有用的信息
|
|
1327
|
+
person_info = []
|
|
1328
|
+
if item.get("user_id"):
|
|
1329
|
+
person_info.append(item["user_id"])
|
|
1330
|
+
if item.get("id_type"):
|
|
1331
|
+
person_info.append(f"类型{item['id_type']}")
|
|
1332
|
+
if person_info:
|
|
1333
|
+
person_names.append("-".join(person_info))
|
|
1334
|
+
else:
|
|
1335
|
+
person_names.append(str(item))
|
|
1336
|
+
else:
|
|
1337
|
+
person_names.append(str(item))
|
|
1338
|
+
# 去重并拼接
|
|
1339
|
+
unique_names = list(set(person_names)) # 去重
|
|
1340
|
+
return ", ".join(unique_names)
|
|
1341
|
+
|
|
1342
|
+
# 如果是字典
|
|
1343
|
+
elif isinstance(field_value, dict):
|
|
1344
|
+
name = field_value.get("name") or field_value.get("user_id") or field_value.get(
|
|
1345
|
+
"text") or field_value.get("title")
|
|
1346
|
+
if name:
|
|
1347
|
+
return str(name)
|
|
1348
|
+
else:
|
|
1349
|
+
# 返回格式化的字典信息
|
|
1350
|
+
return f"{field_value.get('user_id', '')}"
|
|
1351
|
+
|
|
1352
|
+
# 其他类型直接转字符串
|
|
1353
|
+
else:
|
|
1354
|
+
return str(field_value)
|
|
1355
|
+
|
|
1356
|
+
# 判断字符串是否为纯数字(支持整数/小数)
|
|
1357
|
+
def _is_pure_number(s):
|
|
1358
|
+
"""
|
|
1359
|
+
判断字符串是否为纯数字(包含整数、小数、负数)
|
|
1360
|
+
"""
|
|
1361
|
+
if not s or str(s).strip() in ["", "None", "nan"]:
|
|
1362
|
+
return True # 空值不影响列的数字判断
|
|
1363
|
+
try:
|
|
1364
|
+
float(str(s).strip())
|
|
1365
|
+
return True
|
|
1366
|
+
except (ValueError, TypeError):
|
|
1367
|
+
return False
|
|
1368
|
+
|
|
1369
|
+
# 转换列为数值格式
|
|
1370
|
+
def _convert_numeric_columns(df):
|
|
1371
|
+
"""
|
|
1372
|
+
遍历DataFrame列,将全为数字的列转换为数值格式(int/float自动适配)
|
|
1373
|
+
"""
|
|
1374
|
+
numeric_columns = []
|
|
1375
|
+
for col in df.columns:
|
|
1376
|
+
# 跳过时间/人员相关列(避免误转换)
|
|
1377
|
+
if any(kw in str(col) for kw in
|
|
1378
|
+
["日期", "时间", "记录ID", "创建", "更新", "编辑者", "人员", "负责人", "经办人", "对接人",
|
|
1379
|
+
"联系人", "使用人", "成交人", "交付人", "品牌专家", "姓名", "销售", "维护人", "操作人",
|
|
1380
|
+
"转移人", "执行人", "人", "编辑"]):
|
|
1381
|
+
continue
|
|
1382
|
+
|
|
1383
|
+
# 检查列中所有非空值是否为纯数字
|
|
1384
|
+
all_numeric = df[col].apply(lambda x: _is_pure_number(x)).all()
|
|
1385
|
+
if all_numeric:
|
|
1386
|
+
# 先转换为float,再判断是否能转int(保留小数的自动适配)
|
|
1387
|
+
df[col] = pd.to_numeric(df[col], errors="coerce")
|
|
1388
|
+
# 若所有值都是整数,转int类型;否则保留float
|
|
1389
|
+
if (df[col].dropna() % 1 == 0).all():
|
|
1390
|
+
df[col] = df[col].astype('Int64') # Int64支持空值
|
|
1391
|
+
numeric_columns.append(col)
|
|
1392
|
+
self._wechat_doc_log(f"列[{col}]全为数字,已转换为{df[col].dtype}格式")
|
|
1393
|
+
|
|
1394
|
+
return df, numeric_columns
|
|
1395
|
+
|
|
1152
1396
|
# 处理记录
|
|
1153
1397
|
rows = []
|
|
1154
1398
|
custom_fields = set()
|
|
@@ -1158,7 +1402,18 @@ class DataProcessingAndMessaging:
|
|
|
1158
1402
|
break
|
|
1159
1403
|
all_fields = ["记录ID", "创建时间", "更新时间", "最后编辑者"] + list(custom_fields)
|
|
1160
1404
|
date_related_columns = [col for col in all_fields if any(kw in str(col) for kw in ["日期", "时间"])]
|
|
1405
|
+
# 识别人员相关列(包含"人员"、"负责人"、"经办人"等关键词)
|
|
1406
|
+
person_related_columns = [col for col in all_fields if
|
|
1407
|
+
any(kw in str(col) for kw in
|
|
1408
|
+
["人员", "负责人", "经办人", "对接人", "联系人", "使用人", "成交人", "交付人",
|
|
1409
|
+
"品牌专家", "姓名", "销售", "维护人", "操作人", "更新人", "转移人", "执行人",
|
|
1410
|
+
"人"])]
|
|
1411
|
+
# 识别公式相关列(可根据实际列名关键词调整)
|
|
1412
|
+
formula_related_columns = [col for col in all_fields if
|
|
1413
|
+
any(kw in str(col) for kw in ["公式", "计算", "合计", "总和", "金额", "数量", "天数"])]
|
|
1161
1414
|
self._wechat_doc_log(f"识别到需转换的日期相关列:{date_related_columns}")
|
|
1415
|
+
self._wechat_doc_log(f"识别到人员相关列:{person_related_columns}")
|
|
1416
|
+
self._wechat_doc_log(f"识别到公式相关列:{formula_related_columns}")
|
|
1162
1417
|
|
|
1163
1418
|
for record in all_records:
|
|
1164
1419
|
row = {
|
|
@@ -1170,15 +1425,49 @@ class DataProcessingAndMessaging:
|
|
|
1170
1425
|
|
|
1171
1426
|
values = record.get("values", {})
|
|
1172
1427
|
for field_name, field_value in values.items():
|
|
1173
|
-
|
|
1428
|
+
# 1. 公式列优先解析
|
|
1429
|
+
if field_name in formula_related_columns:
|
|
1430
|
+
row[field_name] = _parse_formula_field(field_value)
|
|
1431
|
+
# 2. 日期相关列 - 时间转换
|
|
1432
|
+
elif field_name in date_related_columns:
|
|
1174
1433
|
row[field_name] = _unified_time_convert(field_value)
|
|
1434
|
+
# 3. 人员相关列 - 先判断是否为有效格式,再解析
|
|
1435
|
+
elif field_name in person_related_columns:
|
|
1436
|
+
# 核心修改:先判断是否包含user_id的有效人员格式
|
|
1437
|
+
if _is_valid_person_format(field_value):
|
|
1438
|
+
row[field_name] = _parse_person_field(field_value)
|
|
1439
|
+
self._wechat_doc_log(f"列[{field_name}]值[{field_value}]符合人员格式,已解析")
|
|
1440
|
+
else:
|
|
1441
|
+
# 非有效格式,按普通字段处理
|
|
1442
|
+
if isinstance(field_value, list) and len(field_value) > 0:
|
|
1443
|
+
if isinstance(field_value[0], dict):
|
|
1444
|
+
# 处理普通列表字典,提取所有text/title并用逗号分隔
|
|
1445
|
+
text_values = []
|
|
1446
|
+
for item in field_value:
|
|
1447
|
+
text_val = item.get("text", item.get("title", str(item)))
|
|
1448
|
+
text_values.append(str(text_val))
|
|
1449
|
+
row[field_name] = ", ".join(text_values)
|
|
1450
|
+
else:
|
|
1451
|
+
row[field_name] = ", ".join([str(item) for item in field_value])
|
|
1452
|
+
else:
|
|
1453
|
+
row[field_name] = str(field_value) if field_value is not None else ""
|
|
1454
|
+
self._wechat_doc_log(f"列[{field_name}]值[{field_value}]非有效人员格式,按普通字段处理")
|
|
1455
|
+
# 4. 其他列 - 常规处理
|
|
1175
1456
|
else:
|
|
1176
|
-
|
|
1457
|
+
# 兼容普通列中嵌套公式格式的情况
|
|
1458
|
+
parsed_val = _parse_formula_field(field_value)
|
|
1459
|
+
if parsed_val != "":
|
|
1460
|
+
row[field_name] = parsed_val
|
|
1461
|
+
elif isinstance(field_value, list) and len(field_value) > 0:
|
|
1177
1462
|
if isinstance(field_value[0], dict):
|
|
1178
|
-
|
|
1179
|
-
|
|
1463
|
+
# 处理普通列表字典,提取所有text/title并用逗号分隔
|
|
1464
|
+
text_values = []
|
|
1465
|
+
for item in field_value:
|
|
1466
|
+
text_val = item.get("text", item.get("title", str(item)))
|
|
1467
|
+
text_values.append(str(text_val))
|
|
1468
|
+
row[field_name] = ", ".join(text_values)
|
|
1180
1469
|
else:
|
|
1181
|
-
row[field_name] = str(field_value)
|
|
1470
|
+
row[field_name] = ", ".join([str(item) for item in field_value])
|
|
1182
1471
|
else:
|
|
1183
1472
|
row[field_name] = str(field_value) if field_value is not None else ""
|
|
1184
1473
|
|
|
@@ -1187,12 +1476,17 @@ class DataProcessingAndMessaging:
|
|
|
1187
1476
|
df = pd.DataFrame(rows)
|
|
1188
1477
|
df = df[df['更新时间'] != '0']
|
|
1189
1478
|
|
|
1190
|
-
|
|
1479
|
+
# 核心新增:转换全数字列为数值格式(包含公式列)
|
|
1480
|
+
df, numeric_columns = _convert_numeric_columns(df)
|
|
1481
|
+
|
|
1482
|
+
# 优化日志信息,包含数值列转换结果
|
|
1483
|
+
msg = (f"成功读取{len(rows)}条记录到dataframe({len(date_related_columns)}个日期相关列已转为北京时间,"
|
|
1484
|
+
f"{len(person_related_columns)}个人员相关列已检查格式并处理,{len(formula_related_columns)}个公式列已解析,"
|
|
1485
|
+
f"{len(numeric_columns)}个全数字列已转为数值格式:{numeric_columns})")
|
|
1191
1486
|
self._wechat_doc_log(msg)
|
|
1192
1487
|
print(f"[企业微信文档] {msg}")
|
|
1193
1488
|
|
|
1194
1489
|
return df
|
|
1195
|
-
|
|
1196
1490
|
# -------------------------- 企微文档:删除表格 --------------------------
|
|
1197
1491
|
def wx_delete_table(self, docid):
|
|
1198
1492
|
self._wechat_doc_log(f"开始删除文档:docid={docid}")
|
|
@@ -1209,8 +1503,12 @@ class DataProcessingAndMessaging:
|
|
|
1209
1503
|
self._wechat_doc_log(error_msg)
|
|
1210
1504
|
raise Exception(error_msg)
|
|
1211
1505
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1506
|
+
# 获取当前时间(北京时间,格式:YYYY-MM-DD HH:MM:SS)
|
|
1507
|
+
create_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
1508
|
+
msg_content = f"企微文档删除成功:docid={docid} \n 删除时间:{create_time}"
|
|
1509
|
+
self._wechat_doc_log(msg_content)
|
|
1510
|
+
print(msg_content)
|
|
1511
|
+
self.uxin_wx('dongyang', msg_content)
|
|
1214
1512
|
return True
|
|
1215
1513
|
|
|
1216
1514
|
# -------------------------- 辅助方法:检查文件是否被占用 --------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|