PUGE 1 miesiąc temu
rodzic
commit
4c6e769534
2 zmienionych plików z 593 dodań i 12 usunięć
  1. 440 0
      三一平台.py
  2. 153 12
      飞书提交数据.py

+ 440 - 0
三一平台.py

@@ -0,0 +1,440 @@
+import sys
+import hashlib
+import requests
+import json
+import time
+from datetime import datetime, timedelta
+from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
+                             QHBoxLayout, QLabel, QLineEdit, QPushButton, 
+                             QTableWidget, QTableWidgetItem, QHeaderView, 
+                             QCheckBox, QMessageBox, QGroupBox, QTextEdit,
+                             QGridLayout, QSplitter)
+from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
+from PyQt5.QtGui import QTextDocument
+
+class LoginThread(QThread):
+    """登录线程"""
+    finished = pyqtSignal(dict)
+    error = pyqtSignal(str)
+    
+    def __init__(self, username, password):
+        super().__init__()
+        self.username = username
+        self.password = password
+    
+    def run(self):
+        try:
+            md5_password = hashlib.md5(self.password.encode('utf-8')).hexdigest()
+            url = f"http://119.91.58.175:9999/gps-web/api/login.jsp?userId={self.username}&password={md5_password}&loginType=user&onlyValidate=false&plateColor=&loginWay=interface&loginLang=zh_CN"
+            
+            response = requests.get(url, timeout=10)
+            response.encoding = 'utf-8'
+            
+            if response.status_code == 200:
+                data = response.json()
+                if data.get('rspCode') == '1':
+                    self.finished.emit(data)
+                else:
+                    self.error.emit(f"登录失败: {data.get('msg', '未知错误')}")
+            else:
+                self.error.emit(f"请求失败: HTTP {response.status_code}")
+        except Exception as e:
+            self.error.emit(f"登录异常: {str(e)}")
+
+class QueryThread(QThread):
+    """查询车辆定位线程"""
+    finished = pyqtSignal(dict)
+    error = pyqtSignal(str)
+    
+    def __init__(self, session_id):
+        super().__init__()
+        self.session_id = session_id
+    
+    def run(self):
+        try:
+            url = f"http://119.91.58.175:9999/gps-web/api/get_gps_r.jsp?sessionId={self.session_id}&teamId=&carIds=&simple=false"
+            
+            response = requests.get(url, timeout=15)
+            response.encoding = 'utf-8'
+            
+            if response.status_code == 200:
+                data = response.json()
+                if data.get('rspCode') == '1':
+                    self.finished.emit(data)
+                else:
+                    self.error.emit(f"查询失败: {data.get('msg', '未知错误')}")
+            else:
+                self.error.emit(f"请求失败: HTTP {response.status_code}")
+        except Exception as e:
+            self.error.emit(f"查询异常: {str(e)}")
+
+class MainWindow(QMainWindow):
+    def __init__(self):
+        super().__init__()
+        self.session_id = None
+        self.username = None
+        self.car_data = []
+        self.car_checked_state = {}  # 存储每辆车的勾选状态
+        self.triggered_records = {}  # 存储触发记录 {car_plate: {'load': last_time, 'unload': last_time}}
+        self.is_monitoring = False
+        self.refresh_timer = QTimer()
+        self.refresh_timer.timeout.connect(self.auto_refresh)
+        self.initUI()
+    
+    def initUI(self):
+        self.setWindowTitle('车辆定位监控系统')
+        self.setGeometry(100, 100, 1400, 800)
+        
+        # 中央窗口
+        central_widget = QWidget()
+        self.setCentralWidget(central_widget)
+        main_layout = QVBoxLayout(central_widget)
+        
+        # 登录区域
+        login_group = QGroupBox("登录")
+        login_layout = QHBoxLayout()
+        
+        login_layout.addWidget(QLabel("账号:"))
+        self.username_input = QLineEdit()
+        self.username_input.setPlaceholderText("请输入账号")
+        self.username_input.setText("深金川")
+        login_layout.addWidget(self.username_input)
+        
+        login_layout.addWidget(QLabel("密码:"))
+        self.password_input = QLineEdit()
+        self.password_input.setPlaceholderText("请输入密码")
+        self.password_input.setEchoMode(QLineEdit.Password)
+        self.password_input.setText("123456")
+        login_layout.addWidget(self.password_input)
+        
+        self.login_btn = QPushButton("登录")
+        self.login_btn.clicked.connect(self.handle_login)
+        login_layout.addWidget(self.login_btn)
+        
+        self.status_label = QLabel("未登录")
+        login_layout.addWidget(self.status_label)
+        
+        login_layout.addStretch()
+        login_group.setLayout(login_layout)
+        main_layout.addWidget(login_group)
+        
+        # 地址输入区域
+        addr_group = QGroupBox("地址监控设置")
+        addr_layout = QGridLayout()
+        
+        addr_layout.addWidget(QLabel("装车地址:"), 0, 0)
+        self.load_addr_input = QLineEdit()
+        self.load_addr_input.setPlaceholderText("请输入装车地址关键词")
+        addr_layout.addWidget(self.load_addr_input, 0, 1)
+        
+        addr_layout.addWidget(QLabel("卸车地址:"), 0, 2)
+        self.unload_addr_input = QLineEdit()
+        self.unload_addr_input.setPlaceholderText("请输入卸车地址关键词")
+        addr_layout.addWidget(self.unload_addr_input, 0, 3)
+        
+        # 控制按钮
+        self.start_btn = QPushButton("启动监控")
+        self.start_btn.clicked.connect(self.start_monitoring)
+        self.start_btn.setEnabled(False)
+        addr_layout.addWidget(self.start_btn, 0, 4)
+        
+        self.stop_btn = QPushButton("停止监控")
+        self.stop_btn.clicked.connect(self.stop_monitoring)
+        self.stop_btn.setEnabled(False)
+        addr_layout.addWidget(self.stop_btn, 0, 5)
+        
+        self.manual_query_btn = QPushButton("手动刷新")
+        self.manual_query_btn.clicked.connect(self.handle_query)
+        self.manual_query_btn.setEnabled(False)
+        addr_layout.addWidget(self.manual_query_btn, 0, 6)
+        
+        addr_layout.addWidget(QLabel("刷新间隔:5秒"), 0, 7)
+        
+        addr_group.setLayout(addr_layout)
+        main_layout.addWidget(addr_group)
+        
+        # 分割器:表格和日志
+        splitter = QSplitter(Qt.Vertical)
+        
+        # 车辆信息表格
+        table_widget = QWidget()
+        table_layout = QVBoxLayout(table_widget)
+        table_layout.setContentsMargins(0, 0, 0, 0)
+        
+        self.table = QTableWidget()
+        self.table.setColumnCount(5)
+        self.table.setHorizontalHeaderLabels(["选择", "车队名", "车牌号", "在线状态", "定位地址"])
+        self.table.horizontalHeader().setSectionResizeMode(4, QHeaderView.Stretch)
+        self.table.setAlternatingRowColors(True)
+        table_layout.addWidget(self.table)
+        
+        # 表格按钮
+        table_btn_layout = QHBoxLayout()
+        self.select_all_btn = QPushButton("全选")
+        self.select_all_btn.clicked.connect(self.select_all)
+        table_btn_layout.addWidget(self.select_all_btn)
+        
+        self.deselect_all_btn = QPushButton("取消全选")
+        self.deselect_all_btn.clicked.connect(self.deselect_all)
+        table_btn_layout.addWidget(self.deselect_all_btn)
+        
+        table_btn_layout.addStretch()
+        table_layout.addLayout(table_btn_layout)
+        
+        splitter.addWidget(table_widget)
+        
+        # 日志输出框
+        log_widget = QWidget()
+        log_layout = QVBoxLayout(log_widget)
+        log_layout.setContentsMargins(0, 0, 0, 0)
+        
+        log_label = QLabel("日志输出")
+        log_layout.addWidget(log_label)
+        
+        self.log_output = QTextEdit()
+        self.log_output.setReadOnly(True)
+        # 限制日志行数 - 使用document().setMaximumBlockCount()
+        self.log_output.document().setMaximumBlockCount(1000)
+        log_layout.addWidget(self.log_output)
+        
+        splitter.addWidget(log_widget)
+        splitter.setSizes([500, 300])
+        
+        main_layout.addWidget(splitter)
+        
+        # 状态栏
+        self.statusBar().showMessage("就绪")
+        
+        # 初始化触发记录
+        self.triggered_records = {}
+    
+    def handle_login(self):
+        username = self.username_input.text().strip()
+        password = self.password_input.text().strip()
+        
+        if not username or not password:
+            QMessageBox.warning(self, "警告", "请输入账号和密码")
+            return
+        
+        self.login_btn.setEnabled(False)
+        self.status_label.setText("登录中...")
+        self.statusBar().showMessage("正在登录...")
+        
+        self.login_thread = LoginThread(username, password)
+        self.login_thread.finished.connect(self.on_login_success)
+        self.login_thread.error.connect(self.on_login_error)
+        self.login_thread.start()
+    
+    def on_login_success(self, data):
+        self.session_id = data.get('sessionId')
+        self.username = data.get('userName', '')
+        
+        if self.session_id:
+            self.login_btn.setEnabled(True)
+            self.status_label.setText(f"已登录: {self.username}")
+            self.manual_query_btn.setEnabled(True)
+            self.start_btn.setEnabled(True)
+            self.statusBar().showMessage(f"登录成功,Session ID: {self.session_id[:20]}...")
+            
+            # 登录成功后自动查询
+            self.handle_query()
+        else:
+            self.on_login_error("登录响应中没有sessionId")
+    
+    def on_login_error(self, error_msg):
+        self.login_btn.setEnabled(True)
+        self.status_label.setText("登录失败")
+        self.statusBar().showMessage("登录失败")
+        QMessageBox.critical(self, "错误", error_msg)
+    
+    def handle_query(self):
+        if not self.session_id:
+            QMessageBox.warning(self, "警告", "请先登录")
+            return
+        
+        self.manual_query_btn.setEnabled(False)
+        self.statusBar().showMessage("正在查询车辆定位...")
+        
+        self.query_thread = QueryThread(self.session_id)
+        self.query_thread.finished.connect(self.on_query_success)
+        self.query_thread.error.connect(self.on_query_error)
+        self.query_thread.start()
+    
+    def on_query_success(self, data):
+        self.manual_query_btn.setEnabled(True)
+        
+        car_list = data.get('list', [])
+        self.car_data = car_list
+        
+        # 保存当前勾选状态
+        self.save_check_state()
+        
+        self.table.setRowCount(len(car_list))
+        
+        for row, car in enumerate(car_list):
+            car_plate = car.get('carPlate', '')
+            
+            # 选择框 - 恢复保存的状态
+            checkbox = QCheckBox()
+            checkbox.setChecked(self.car_checked_state.get(car_plate, False))
+            checkbox.stateChanged.connect(lambda state, plate=car_plate: self.on_check_changed(plate, state))
+            self.table.setCellWidget(row, 0, checkbox)
+            
+            # 车队名
+            team_name = car.get('teamName', '')
+            self.table.setItem(row, 1, QTableWidgetItem(team_name))
+            
+            # 车牌号
+            self.table.setItem(row, 2, QTableWidgetItem(car_plate))
+            
+            # 在线状态
+            state_cn = car.get('stateCn', '')
+            self.table.setItem(row, 3, QTableWidgetItem(state_cn))
+            
+            # 定位地址
+            addr = car.get('addr', '')
+            self.table.setItem(row, 4, QTableWidgetItem(addr))
+        
+        self.statusBar().showMessage(f"查询成功,共 {len(car_list)} 辆车")
+        
+        # 如果正在监控,进行地址匹配检查
+        if self.is_monitoring:
+            self.check_address_match()
+    
+    def on_query_error(self, error_msg):
+        self.manual_query_btn.setEnabled(True)
+        self.statusBar().showMessage("查询失败")
+        QMessageBox.critical(self, "错误", error_msg)
+    
+    def save_check_state(self):
+        """保存当前表格中的勾选状态"""
+        for row in range(self.table.rowCount()):
+            checkbox = self.table.cellWidget(row, 0)
+            if checkbox:
+                car_plate = self.table.item(row, 2).text() if self.table.item(row, 2) else ''
+                if car_plate:
+                    self.car_checked_state[car_plate] = checkbox.isChecked()
+    
+    def on_check_changed(self, car_plate, state):
+        """勾选框状态变化时保存"""
+        self.car_checked_state[car_plate] = (state == Qt.Checked)
+    
+    def select_all(self):
+        for row in range(self.table.rowCount()):
+            checkbox = self.table.cellWidget(row, 0)
+            if checkbox:
+                checkbox.setChecked(True)
+                car_plate = self.table.item(row, 2).text() if self.table.item(row, 2) else ''
+                if car_plate:
+                    self.car_checked_state[car_plate] = True
+    
+    def deselect_all(self):
+        for row in range(self.table.rowCount()):
+            checkbox = self.table.cellWidget(row, 0)
+            if checkbox:
+                checkbox.setChecked(False)
+                car_plate = self.table.item(row, 2).text() if self.table.item(row, 2) else ''
+                if car_plate:
+                    self.car_checked_state[car_plate] = False
+    
+    def start_monitoring(self):
+        """启动监控"""
+        load_addr = self.load_addr_input.text().strip()
+        unload_addr = self.unload_addr_input.text().strip()
+        
+        if not load_addr and not unload_addr:
+            QMessageBox.warning(self, "警告", "请至少输入一个地址关键词")
+            return
+        
+        if not self.session_id:
+            QMessageBox.warning(self, "警告", "请先登录")
+            return
+        
+        self.is_monitoring = True
+        self.start_btn.setEnabled(False)
+        self.stop_btn.setEnabled(True)
+        self.manual_query_btn.setEnabled(False)
+        
+        # 清空触发记录
+        self.triggered_records = {}
+        
+        self.add_log("=" * 50)
+        self.add_log(f"监控已启动 - 装车地址: {load_addr or '无'}, 卸车地址: {unload_addr or '无'}")
+        self.add_log("=" * 50)
+        
+        # 立即执行一次检查
+        self.handle_query()
+        
+        # 启动定时器,每5秒刷新一次
+        self.refresh_timer.start(5000)
+        self.statusBar().showMessage("监控运行中...")
+    
+    def stop_monitoring(self):
+        """停止监控"""
+        self.is_monitoring = False
+        self.refresh_timer.stop()
+        self.start_btn.setEnabled(True)
+        self.stop_btn.setEnabled(False)
+        self.manual_query_btn.setEnabled(True)
+        
+        self.add_log("=" * 50)
+        self.add_log("监控已停止")
+        self.add_log("=" * 50)
+        self.statusBar().showMessage("监控已停止")
+    
+    def auto_refresh(self):
+        """自动刷新"""
+        if self.is_monitoring and self.session_id:
+            self.handle_query()
+    
+    def check_address_match(self):
+        """检查地址匹配"""
+        load_keyword = self.load_addr_input.text().strip()
+        unload_keyword = self.unload_addr_input.text().strip()
+        current_time = datetime.now()
+        
+        for row in range(self.table.rowCount()):
+            car_plate = self.table.item(row, 2).text() if self.table.item(row, 2) else ''
+            addr = self.table.item(row, 4).text() if self.table.item(row, 4) else ''
+            
+            if not car_plate or not addr:
+                continue
+            
+            # 初始化该车辆的触发记录
+            if car_plate not in self.triggered_records:
+                self.triggered_records[car_plate] = {'load': None, 'unload': None}
+            
+            # 检查装车地址
+            if load_keyword and load_keyword in addr:
+                last_trigger = self.triggered_records[car_plate]['load']
+                if last_trigger is None or (current_time - last_trigger) >= timedelta(minutes=5):
+                    self.triggered_records[car_plate]['load'] = current_time
+                    self.add_log(f"🚛 {car_plate} 到达装车位置 ({load_keyword})")
+                    self.statusBar().showMessage(f"{car_plate} 到达装车位置")
+            
+            # 检查卸车地址
+            if unload_keyword and unload_keyword in addr:
+                last_trigger = self.triggered_records[car_plate]['unload']
+                if last_trigger is None or (current_time - last_trigger) >= timedelta(minutes=5):
+                    self.triggered_records[car_plate]['unload'] = current_time
+                    self.add_log(f"🚛 {car_plate} 到达卸车位置 ({unload_keyword})")
+                    self.statusBar().showMessage(f"{car_plate} 到达卸车位置")
+    
+    def add_log(self, message):
+        """添加日志"""
+        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+        log_line = f"[{timestamp}] {message}"
+        self.log_output.append(log_line)
+        
+        # 保持最新日志可见
+        scrollbar = self.log_output.verticalScrollBar()
+        scrollbar.setValue(scrollbar.maximum())
+
+def main():
+    app = QApplication(sys.argv)
+    window = MainWindow()
+    window.show()
+    sys.exit(app.exec_())
+
+if __name__ == '__main__':
+    main()

+ 153 - 12
飞书提交数据.py

@@ -8,6 +8,7 @@ import time
 import random
 import re
 from datetime import datetime
+import os
 
 class FeishuSubmitApp:
     def __init__(self, root):
@@ -131,6 +132,7 @@ class FeishuSubmitApp:
         self.log_text.tag_config("error", foreground="red")
         self.log_text.tag_config("info", foreground="blue")
         self.log_text.tag_config("warning", foreground="orange")
+        self.log_text.tag_config("debug", foreground="purple")
         
         # ========== 底部状态栏 ==========
         status_bar = ttk.Frame(self.root)
@@ -237,10 +239,51 @@ class FeishuSubmitApp:
                 cookies[key.strip()] = value.strip()
         return cookies
     
+    def extract_image_info(self, row):
+        """
+        从行数据中提取图片信息
+        返回: dict 包含图片字段名称和值
+        """
+        image_fields = {}
+        
+        # 常见的图片字段名(根据你的实际情况调整)
+        possible_image_columns = ['图片', '照片', '附件', '头像', 'image', 'photo', 'picture', 'img']
+        
+        # 检查所有列,寻找可能包含图片的列
+        for col in row.index:
+            col_lower = str(col).lower()
+            # 检查列名是否包含图片相关关键词
+            if any(keyword in col_lower for keyword in ['图', '片', '照', '像', 'image', 'photo', 'pic', 'img', '附件']):
+                value = row.get(col)
+                if pd.notna(value) and value:
+                    # 检查是否为文件路径或URL
+                    value_str = str(value).strip()
+                    if value_str:
+                        # 检查是否为文件路径
+                        if os.path.exists(value_str):
+                            image_fields[col] = {
+                                'type': 'file',
+                                'path': value_str,
+                                'size': os.path.getsize(value_str)
+                            }
+                            self.log(f"  📎 检测到图片文件: {col} -> {os.path.basename(value_str)} ({os.path.getsize(value_str)} bytes)", "debug")
+                        # 检查是否为URL
+                        elif value_str.startswith(('http://', 'https://')):
+                            image_fields[col] = {
+                                'type': 'url',
+                                'url': value_str
+                            }
+                            self.log(f"  🔗 检测到图片URL: {col} -> {value_str}", "debug")
+                        else:
+                            self.log(f"  ℹ️ 列 '{col}' 包含非图片数据: {value_str[:50]}...", "debug")
+        
+        if not image_fields:
+            self.log("  📝 未检测到图片字段", "debug")
+        
+        return image_fields
+    
     def build_request_body(self, row):
         """根据Excel行数据构建请求体"""
-        # 这个函数需要根据你的实际列名和字段映射来调整
-        # 这里是一个示例,你需要根据实际情况修改
         try:
             # 获取各列数据
             name = str(row.get("姓名", "")) if pd.notna(row.get("姓名")) else ""
@@ -254,6 +297,18 @@ class FeishuSubmitApp:
             source = str(row.get("线索来源", "")) if pd.notna(row.get("线索来源")) else ""
             market_person = str(row.get("市场人员", "")) if pd.notna(row.get("市场人员")) else ""
             
+            # 提取图片信息
+            self.log("  📷 检查图片字段...", "debug")
+            image_info = self.extract_image_info(row)
+            
+            if image_info:
+                self.log(f"  ✅ 找到 {len(image_info)} 个图片字段: {', '.join(image_info.keys())}", "debug")
+                # 这里可以添加图片上传逻辑
+                # 注意:飞书可能使用特定的字段ID存储图片
+                # 你需要根据实际的字段ID来设置
+            else:
+                self.log("  ⚠️ 未找到图片字段,请检查Excel列名是否包含'图片'、'照片'等关键词", "warning")
+            
             # 构建备注文本(包含所有信息)
             remark_text = f"姓名:{name},性别:{gender},手机号码:{phone}"
             if remark:
@@ -297,6 +352,21 @@ class FeishuSubmitApp:
                 "fldMpwPaI1": {"type": 17}
             }
             
+            # 如果检测到图片,尝试添加到data_obj中
+            # 注意:你需要知道飞书表格中图片字段的实际ID
+            # 这里假设图片字段ID为 fldImageXxx,你需要根据实际情况修改
+            if image_info:
+                # 这里需要根据实际的字段ID来设置
+                # 示例:如果有图片,添加到某个字段
+                # for field_name, info in image_info.items():
+                #     if info['type'] == 'file':
+                #         # 处理文件上传
+                #         pass
+                #     elif info['type'] == 'url':
+                #         # 处理URL
+                #         pass
+                self.log("  💡 提示: 请根据实际字段ID配置图片上传", "info")
+            
             # 构建完整的请求体
             body = {
                 "shareToken": self.share_token,
@@ -312,21 +382,41 @@ class FeishuSubmitApp:
     def send_request(self, row_data, row_index):
         """发送单条请求"""
         try:
+            # 检查是否有图片字段
+            self.log(f"\n{'='*50}", "info")
+            self.log(f"📤 准备发送第 {row_index} 行数据", "info")
+            
             cookie_string = self.cookie_text.get(1.0, tk.END).strip()
             if not cookie_string:
-                self.log("Cookie为空,请先配置Cookie", "error")
+                self.log("Cookie为空,请先配置Cookie", "error")
                 return False, "Cookie为空"
             
             # 构建请求体
             body = self.build_request_body(row_data)
             if body is None:
+                self.log("❌ 构建请求体失败", "error")
                 return False, "构建请求体失败"
             
+            # 记录请求体大小
+            body_str = json.dumps(body, ensure_ascii=False)
+            self.log(f"📦 请求体大小: {len(body_str)} 字节", "debug")
+            
+            # 检查data字段中的图片内容
+            data_str = body.get('data', '')
+            if data_str:
+                # 检查是否包含图片相关的字段
+                if 'fld' in data_str and ('image' in data_str.lower() or 'picture' in data_str.lower()):
+                    self.log("  🖼️ 请求中包含图片相关字段", "debug")
+                else:
+                    self.log("  📝 请求中未检测到图片字段", "debug")
+            
             # 准备请求
             headers = self.default_headers.copy()
             # 更新Cookie
             cookies = self.parse_cookie(cookie_string)
             
+            self.log(f"🌐 发送请求到: {self.url}", "debug")
+            
             # 发送请求
             response = requests.post(
                 self.url,
@@ -336,26 +426,56 @@ class FeishuSubmitApp:
                 timeout=30
             )
             
+            # 记录响应状态
+            self.log(f"📡 响应状态码: {response.status_code}", "debug")
+            self.log(f"📋 响应头: {dict(response.headers)}", "debug")
+            
             # 解析响应
             try:
                 resp_data = response.json()
                 resp_text = json.dumps(resp_data, ensure_ascii=False, indent=2)
+                
+                # 检查响应中是否有错误信息
+                if isinstance(resp_data, dict):
+                    if resp_data.get('code') != 0 and resp_data.get('code') is not None:
+                        self.log(f"⚠️ 服务器返回错误码: {resp_data.get('code')}", "warning")
+                        self.log(f"  错误信息: {resp_data.get('msg', '未知错误')}", "error")
+                    if 'data' in resp_data:
+                        self.log(f"  📊 响应数据: {json.dumps(resp_data['data'], ensure_ascii=False)[:200]}...", "debug")
             except:
                 resp_text = response.text
+                self.log("⚠️ 响应不是有效的JSON格式", "warning")
             
             if response.status_code == 200:
-                self.log(f"✅ 第{row_index}行 发送成功 | {resp_text[:200]}...", "success")
+                self.log(f"✅ 第{row_index}行 发送成功", "success")
+                # 检查返回的data中是否包含图片上传信息
+                try:
+                    resp_json = response.json()
+                    if 'data' in resp_json:
+                        data_content = resp_json['data']
+                        if isinstance(data_content, dict):
+                            # 检查是否有图片上传相关信息
+                            if 'image' in str(data_content).lower() or 'picture' in str(data_content).lower():
+                                self.log("  🖼️ 响应中包含图片处理信息", "debug")
+                except:
+                    pass
                 return True, resp_text
             else:
-                self.log(f"❌ 第{row_index}行 发送失败 (HTTP {response.status_code}) | {resp_text[:200]}...", "error")
+                self.log(f"❌ 第{row_index}行 发送失败 (HTTP {response.status_code})", "error")
+                self.log(f"  响应内容: {resp_text[:500]}...", "error")
                 return False, resp_text
                 
         except requests.exceptions.Timeout:
             self.log(f"⏱️ 第{row_index}行 请求超时", "error")
             return False, "请求超时"
+        except requests.exceptions.ConnectionError:
+            self.log(f"🔌 第{row_index}行 连接失败,请检查网络", "error")
+            return False, "连接失败"
         except Exception as e:
             self.log(f"💥 第{row_index}行 异常: {str(e)}", "error")
             return False, str(e)
+        finally:
+            self.log(f"{'='*50}\n", "info")
     
     def send_all(self):
         """发送所有数据的主循环"""
@@ -368,21 +488,42 @@ class FeishuSubmitApp:
             start_row = int(self.start_row_var.get()) - 1  # 转为0索引
             
             if not excel_file:
-                self.log("请先选择Excel文件", "error")
+                self.log("请先选择Excel文件", "error")
                 self.status_var.set("❌ 请先选择Excel文件")
                 return
             
             # 读取Excel
             try:
                 df = pd.read_excel(excel_file, sheet_name=sheet_name)
-                self.log(f"成功读取Excel: {len(df)} 行数据", "info")
+                self.log(f"📊 成功读取Excel: {len(df)} 行数据", "info")
+                self.log(f"📋 列名: {', '.join(df.columns.tolist())}", "info")
+                
+                # 检查是否有图片相关列
+                image_cols = [col for col in df.columns if any(kw in str(col).lower() for kw in ['图', '片', '照', '像', 'image', 'photo', 'pic', 'img', '附件'])]
+                if image_cols:
+                    self.log(f"📷 发现图片相关列: {', '.join(image_cols)}", "info")
+                    
+                    # 检查这些列是否有数据
+                    for col in image_cols:
+                        non_empty = df[col].notna().sum()
+                        if non_empty > 0:
+                            self.log(f"  ✅ 列 '{col}' 有 {non_empty} 行数据", "info")
+                            # 显示一些示例数据
+                            sample = df[col].dropna().iloc[0] if non_empty > 0 else None
+                            if sample:
+                                self.log(f"  📎 示例数据: {str(sample)[:100]}...", "debug")
+                        else:
+                            self.log(f"  ⚠️ 列 '{col}' 为空", "warning")
+                else:
+                    self.log("⚠️ 未发现图片相关列,请检查列名是否包含'图片'、'照片'等关键词", "warning")
+                    
             except Exception as e:
-                self.log(f"读取Excel失败: {str(e)}", "error")
+                self.log(f"读取Excel失败: {str(e)}", "error")
                 self.status_var.set(f"❌ 读取失败: {str(e)}")
                 return
             
             if len(df) == 0:
-                self.log("Excel中没有数据", "warning")
+                self.log("⚠️ Excel中没有数据", "warning")
                 self.status_var.set("⚠️ 没有数据")
                 return
             
@@ -392,7 +533,7 @@ class FeishuSubmitApp:
             success_count = 0
             fail_count = 0
             
-            self.log(f"开始发送,共 {total} 条数据", "info")
+            self.log(f"🚀 开始发送,共 {total} 条数据", "info")
             self.status_var.set(f"🔄 发送中... 0/{total}")
             
             for idx, (_, row) in enumerate(df.iterrows()):
@@ -424,7 +565,7 @@ class FeishuSubmitApp:
             self.status_var.set(f"✅ 完成 成功:{success_count} 失败:{fail_count}")
             
         except Exception as e:
-            self.log(f"程序异常: {str(e)}", "error")
+            self.log(f"💥 程序异常: {str(e)}", "error")
             self.status_var.set(f"❌ 异常: {str(e)}")
         finally:
             self.is_running = False
@@ -468,7 +609,7 @@ class FeishuSubmitApp:
     def stop_send(self):
         """停止发送"""
         self.stop_flag = True
-        self.log("正在停止...", "warning")
+        self.log("⏹️ 正在停止...", "warning")
         self.stop_btn.config(state=tk.DISABLED)