From 2aebbc9601ab439707f69b08e467808df9f7549c Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期五, 07 十一月 2025 11:50:26 +0800
Subject: [PATCH] feat: weixin

---
 app/api/task.js                                                                          |   33 
 ruoyi-system/src/main/java/com/ruoyi/system/imagedata/WxImageUploadRequest.java          |   30 
 ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java               |   19 
 ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java                                |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/ImageTypeEnum.java              |   64 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java |   84 +
 ruoyi-common/src/main/java/com/ruoyi/common/utils/InputStreamBase64Converter.java        |   35 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java                 |   22 
 ruoyi-system/src/main/java/com/ruoyi/system/imagedata/ImageDataServiceImpl.java          |  644 ++++++++
 sql/update_attachment_category.sql                                                       |    8 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java  |   26 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/imagedata/ImageDataController.java    | 1074 ++++++++++++++
 ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml                |    7 
 app/pages/task/detail.vue                                                                |  514 ++++++
 ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadServiceImpl.java              |  549 +++++++
 ruoyi-common/src/main/java/com/ruoyi/common/config/WechatMpConfig.java                   |   47 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java                |   13 
 ruoyi-system/src/main/java/com/ruoyi/system/file/IFileUploadService.java                 |  108 +
 ruoyi-system/src/main/resources/mapper/system/ImageDataMapper.xml                        |  121 +
 ruoyi-common/src/main/java/com/ruoyi/common/config/WechatConfig.java                     |   37 
 ruoyi-admin/src/main/resources/application.yml                                           |    9 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java         |  140 +
 /dev/null                                                                                |  218 --
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/ImageDataMapper.java                  |   78 +
 ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java                    |  183 ++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/ImageData.java                        |   92 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/wechat/WechatController.java          |   42 
 ruoyi-system/src/main/java/com/ruoyi/system/imagedata/IImageDataService.java             |  200 ++
 ruoyi-admin/src/main/resources/application-dev.yml                                       |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadResponse.java                 |   41 
 30 files changed, 4,194 insertions(+), 250 deletions(-)

diff --git a/app/api/task.js b/app/api/task.js
index 9287710..f43e912 100644
--- a/app/api/task.js
+++ b/app/api/task.js
@@ -61,11 +61,14 @@
 }
 
 // 闄勪欢绠$悊API
-export function uploadAttachment(taskId, file) {
+export function uploadAttachment(taskId, file, category) {
   const formData = new FormData()
   formData.append('file', file)
+  if (category) {
+    formData.append('category', category)
+  }
   return request({
-    url: '/task/' + taskId + '/attachment',
+    url: '/task/attachment/upload/' + taskId,
     method: 'post',
     data: formData,
     headers: {
@@ -74,6 +77,24 @@
   })
 }
 
+export function uploadAttachmentFromWechat(taskId, mediaId, category) {
+  return request({
+    url: '/task/attachment/uploadFromWechat/' + taskId,
+    method: 'post',
+    params: {
+      mediaId: mediaId,
+      category: category
+    }
+  })
+}
+
+export function getAttachmentList(taskId) {
+  return request({
+    url: '/task/attachment/list/' + taskId,
+    method: 'get'
+  })
+}
+
 export function deleteAttachment(attachmentId) {
   return request({
     url: '/task/attachment/' + attachmentId,
@@ -81,6 +102,14 @@
   })
 }
 
+// 鑾峰彇寰俊AccessToken
+export function getWechatAccessToken() {
+  return request({
+    url: '/wechat/accessToken',
+    method: 'get'
+  })
+}
+
 // 缁熻API
 export function getTaskStatistics() {
   return request({
diff --git a/app/pages/task/detail.vue b/app/pages/task/detail.vue
index 8598db2..58d3f7b 100644
--- a/app/pages/task/detail.vue
+++ b/app/pages/task/detail.vue
@@ -194,6 +194,35 @@
         </view>
       </view>
       
+      <!-- 闄勪欢淇℃伅 -->
+      <view class="detail-section">
+        <view class="section-title">
+          浠诲姟闄勪欢
+          <button class="upload-btn" @click="showUploadDialog">涓婁紶闄勪欢</button>
+        </view>
+        <view v-if="attachmentList && attachmentList.length > 0">
+          <view class="attachment-item" v-for="(item, index) in attachmentList" :key="item.attachmentId">
+            <view class="attachment-info">
+              <view class="attachment-category">
+                <text class="category-tag">{{ getCategoryName(item.attachmentCategory) }}</text>
+              </view>
+              <view class="attachment-name">{{ item.fileName }}</view>
+              <view class="attachment-meta">
+                <text class="upload-time">{{ formatTime(item.uploadTime) }}</text>
+                <text class="file-size">{{ formatFileSize(item.fileSize) }}</text>
+              </view>
+            </view>
+            <view class="attachment-actions">
+              <button class="action-btn view-btn" @click="viewAttachment(item)">鏌ョ湅</button>
+              <button class="action-btn delete-btn" @click="deleteAttachment(item.attachmentId, index)">鍒犻櫎</button>
+            </view>
+          </view>
+        </view>
+        <view v-else class="no-attachment">
+          <text>鏆傛棤闄勪欢</text>
+        </view>
+      </view>
+      
       <!-- 绂忕杞︿换鍔$壒鏈変俊鎭� -->
       <view class="detail-section" v-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo">
         <view class="section-title">涔樺淇℃伅</view>
@@ -314,18 +343,66 @@
       
       <!-- 宸插畬鎴�/宸插彇娑�: 涓嶆樉绀烘寜閽� -->
     </view>
+    
+    <!-- 闄勪欢涓婁紶瀵硅瘽妗� -->
+    <uni-popup ref="uploadPopup" type="bottom">
+      <view class="upload-dialog">
+        <view class="dialog-header">
+          <text class="dialog-title">涓婁紶闄勪欢</text>
+          <uni-icons type="closeempty" size="24" @click="closeUploadDialog"></uni-icons>
+        </view>
+        <view class="dialog-content">
+          <view class="form-item">
+            <view class="form-label">闄勪欢鍒嗙被</view>
+            <picker @change="onCategoryChange" :value="selectedCategoryIndex" :range="categoryList" range-key="label">
+              <view class="picker-value">
+                {{ categoryList[selectedCategoryIndex].label }}
+                <uni-icons type="arrowdown" size="16"></uni-icons>
+              </view>
+            </picker>
+          </view>
+          <view class="form-item">
+            <view class="form-label">閫夋嫨鍥剧墖</view>
+            <button class="choose-image-btn" @click="chooseImage">
+              <uni-icons type="image" size="20"></uni-icons>
+              <text>鐐瑰嚮閫夋嫨</text>
+            </button>
+          </view>
+          <view class="preview-area" v-if="tempImagePath">
+            <image :src="tempImagePath" mode="aspectFit" class="preview-image"></image>
+          </view>
+        </view>
+        <view class="dialog-footer">
+          <button class="cancel-btn" @click="closeUploadDialog">鍙栨秷</button>
+          <button class="confirm-btn" @click="confirmUpload" :disabled="!tempImagePath">纭畾涓婁紶</button>
+        </view>
+      </view>
+    </uni-popup>
   </view>
 </template>
 
 <script>
   import { getTask, changeTaskStatus } from '@/api/task'
+  import { getAttachmentList, uploadAttachmentFromWechat, deleteAttachment, getWechatAccessToken } from '@/api/task'
   import { formatDateTime } from '@/utils/common'
   
   export default {
     data() {
       return {
         taskDetail: null,
-        taskId: null
+        taskId: null,
+        attachmentList: [],
+        categoryList: [
+          { label: '鐭ユ儏鍚屾剰涔�', value: '1' },
+          { label: '鐥呬汉璧勬枡', value: '2' },
+          { label: '鎿嶄綔璁板綍', value: '3' },
+          { label: '鍑鸿溅鍓�', value: '4' },
+          { label: '鍑鸿溅鍚�', value: '5' },
+          { label: '绯诲畨鍏ㄥ甫', value: '6' }
+        ],
+        selectedCategoryIndex: 0,
+        tempImagePath: null,
+        isWechatMiniProgram: false // 鏄惁鏄井淇″皬绋嬪簭鐜
       }
     },
     computed: {
@@ -387,6 +464,12 @@
     onLoad(options) {
       this.taskId = options.id
       this.loadTaskDetail()
+      this.loadAttachmentList()
+      
+      // 妫�娴嬫槸鍚︽槸寰俊灏忕▼搴忕幆澧�
+      // #ifdef MP-WEIXIN
+      this.isWechatMiniProgram = true
+      // #endif
     },
     methods: {
       // 鍔犺浇浠诲姟璇︽儏
@@ -592,6 +675,249 @@
             })
           }
         })
+      },
+      
+      // 鍔犺浇闄勪欢鍒楄〃
+      loadAttachmentList() {
+        if (!this.taskId) {
+          return
+        }
+        
+        getAttachmentList(this.taskId).then(response => {
+          this.attachmentList = response.data || response || []
+        }).catch(error => {
+          console.error('鍔犺浇闄勪欢鍒楄〃澶辫触:', error)
+        })
+      },
+      
+      // 鏄剧ず涓婁紶瀵硅瘽妗�
+      showUploadDialog() {
+        this.selectedCategoryIndex = 0
+        this.tempImagePath = null
+        this.$refs.uploadPopup.open()
+      },
+      
+      // 鍏抽棴涓婁紶瀵硅瘽妗�
+      closeUploadDialog() {
+        this.$refs.uploadPopup.close()
+      },
+      
+      // 鍒嗙被閫夋嫨鍙樺寲
+      onCategoryChange(e) {
+        this.selectedCategoryIndex = e.detail.value
+      },
+      
+      // 閫夋嫨鍥剧墖
+      chooseImage() {
+        const that = this
+        uni.chooseImage({
+          count: 1,
+          sizeType: ['compressed'],
+          sourceType: ['album', 'camera'],
+          success: function(res) {
+            that.tempImagePath = res.tempFilePaths[0]
+          },
+          fail: function(err) {
+            console.error('閫夋嫨鍥剧墖澶辫触:', err)
+            that.$modal.showToast('閫夋嫨鍥剧墖澶辫触')
+          }
+        })
+      },
+      
+      // 纭涓婁紶
+      confirmUpload() {
+        if (!this.tempImagePath) {
+          this.$modal.showToast('璇峰厛閫夋嫨鍥剧墖')
+          return
+        }
+        
+        const that = this
+        const category = this.categoryList[this.selectedCategoryIndex].value
+        
+        // 寰俊灏忕▼搴忕幆澧冿細鍏堣幏鍙朅ccessToken锛屽啀涓婁紶鍒板井淇℃湇鍔″櫒锛屾渶鍚庢彁浜ediaId鍒板悗绔�
+        // #ifdef MP-WEIXIN
+        if (this.isWechatMiniProgram) {
+          uni.showLoading({
+            title: '涓婁紶涓�...'
+          })
+          
+          // 绗竴姝ワ細浠庡悗绔幏鍙朅ccessToken
+          getWechatAccessToken().then(tokenResponse => {
+            const accessToken = tokenResponse.data || tokenResponse
+            if (!accessToken) {
+              uni.hideLoading()
+              that.$modal.showToast('鑾峰彇AccessToken澶辫触')
+              return
+            }
+            
+            // 绗簩姝ワ細涓婁紶鍒板井淇℃湇鍔″櫒
+            const uploadUrl = `https://api.weixin.qq.com/cgi-bin/media/upload?access_token=${accessToken}&type=image`
+            
+            uni.uploadFile({
+              url: uploadUrl,
+              filePath: that.tempImagePath,
+              name: 'media',
+              success: function(res) {
+                console.log('寰俊涓婁紶鍝嶅簲:', res)
+                try {
+                  const data = JSON.parse(res.data)
+                  if (data.media_id) {
+                    // 绗笁姝ワ細鎻愪氦mediaId鍒板悗绔�
+                    uploadAttachmentFromWechat(that.taskId, data.media_id, category).then(response => {
+                      uni.hideLoading()
+                      that.$modal.showToast('涓婁紶鎴愬姛')
+                      that.closeUploadDialog()
+                      that.loadAttachmentList()
+                    }).catch(error => {
+                      uni.hideLoading()
+                      console.error('鎻愪氦mediaId澶辫触:', error)
+                      that.$modal.showToast('涓婁紶澶辫触锛�' + (error.msg || '璇烽噸璇�'))
+                    })
+                  } else {
+                    uni.hideLoading()
+                    const errMsg = data.errmsg || '鏈煡閿欒'
+                    console.error('寰俊杩斿洖閿欒:', data)
+                    that.$modal.showToast('寰俊涓婁紶澶辫触锛�' + errMsg)
+                  }
+                } catch (e) {
+                  uni.hideLoading()
+                  console.error('瑙f瀽寰俊鍝嶅簲澶辫触:', e, res.data)
+                  that.$modal.showToast('涓婁紶澶辫触锛氬搷搴旇В鏋愰敊璇�')
+                }
+              },
+              fail: function(err) {
+                uni.hideLoading()
+                console.error('涓婁紶鍒板井淇″け璐�:', err)
+                that.$modal.showToast('涓婁紶澶辫触锛�' + (err.errMsg || '璇锋鏌ョ綉缁�'))
+              }
+            })
+          }).catch(error => {
+            uni.hideLoading()
+            console.error('鑾峰彇AccessToken澶辫触:', error)
+            that.$modal.showToast('鑾峰彇AccessToken澶辫触')
+          })
+          return
+        }
+        // #endif
+        
+        // 闈炲井淇″皬绋嬪簭鐜锛氱洿鎺ヤ笂浼犲埌鍚庣鏈嶅姟鍣�
+        uni.showLoading({
+          title: '涓婁紶涓�...'
+        })
+        
+        uni.uploadFile({
+          url: that.$baseUrl + '/task/attachment/upload/' + that.taskId,
+          filePath: that.tempImagePath,
+          name: 'file',
+          formData: {
+            'category': category
+          },
+          header: {
+            'Authorization': 'Bearer ' + uni.getStorageSync('token')
+          },
+          success: function(uploadRes) {
+            uni.hideLoading()
+            
+            if (uploadRes.statusCode === 200) {
+              const result = JSON.parse(uploadRes.data)
+              if (result.code === 200) {
+                that.$modal.showToast('涓婁紶鎴愬姛')
+                that.closeUploadDialog()
+                that.loadAttachmentList()
+              } else {
+                that.$modal.showToast(result.msg || '涓婁紶澶辫触')
+              }
+            } else {
+              that.$modal.showToast('涓婁紶澶辫触')
+            }
+          },
+          fail: function(err) {
+            uni.hideLoading()
+            console.error('涓婁紶澶辫触:', err)
+            that.$modal.showToast('涓婁紶澶辫触')
+          }
+        })
+      },
+      
+      // 鏌ョ湅闄勪欢
+      viewAttachment(item) {
+        // 濡傛灉鏄浘鐗囷紝浣跨敤鍥剧墖棰勮
+        const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
+        const fileExt = item.fileName.split('.').pop().toLowerCase()
+        
+        if (imageTypes.includes(fileExt)) {
+          // 鏋勫缓鍥剧墖璁块棶鍦板潃
+          // 濡傛灉鏄痜ilePath鏄畬鏁磋矾寰勶紝闇�瑕侀�氳繃涓嬭浇鎺ュ彛璁块棶
+          const imageUrl = this.$baseUrl + '/task/attachment/download/' + item.attachmentId
+          
+          // 寰俊灏忕▼搴忎腑棰勮鍥剧墖
+          // #ifdef MP-WEIXIN
+          // 寰俊灏忕▼搴忛渶瑕佸厛涓嬭浇鍒版湰鍦板啀棰勮
+          uni.showLoading({ title: '鍔犺浇涓�...' })
+          uni.downloadFile({
+            url: imageUrl,
+            success: function(res) {
+              uni.hideLoading()
+              if (res.statusCode === 200) {
+                uni.previewImage({
+                  urls: [res.tempFilePath],
+                  current: res.tempFilePath
+                })
+              } else {
+                uni.showToast({ title: '鍔犺浇鍥剧墖澶辫触', icon: 'none' })
+              }
+            },
+            fail: function() {
+              uni.hideLoading()
+              uni.showToast({ title: '涓嬭浇澶辫触', icon: 'none' })
+            }
+          })
+          // #endif
+          
+          // 闈炲井淇″皬绋嬪簭鐜锛岀洿鎺ラ瑙�
+          // #ifndef MP-WEIXIN
+          uni.previewImage({
+            urls: [imageUrl],
+            current: imageUrl
+          })
+          // #endif
+        } else {
+          this.$modal.showToast('浠呮敮鎸侀瑙堝浘鐗�')
+        }
+      },
+      
+      // 鍒犻櫎闄勪欢
+      deleteAttachment(attachmentId, index) {
+        const that = this
+        this.$modal.confirm('纭畾瑕佸垹闄よ闄勪欢鍚楋紵').then(() => {
+          deleteAttachment(attachmentId).then(response => {
+            that.$modal.showToast('鍒犻櫎鎴愬姛')
+            that.attachmentList.splice(index, 1)
+          }).catch(error => {
+            console.error('鍒犻櫎闄勪欢澶辫触:', error)
+            that.$modal.showToast('鍒犻櫎澶辫触')
+          })
+        }).catch(() => {})
+      },
+      
+      // 鑾峰彇鍒嗙被鍚嶇О
+      getCategoryName(category) {
+        const item = this.categoryList.find(c => c.value === category)
+        return item ? item.label : '鏈垎绫�'
+      },
+      
+      // 鏍煎紡鍖栨椂闂�
+      formatTime(time) {
+        if (!time) return ''
+        return formatDateTime(time, 'YYYY-MM-DD HH:mm')
+      },
+      
+      // 鏍煎紡鍖栨枃浠跺ぇ灏�
+      formatFileSize(size) {
+        if (!size) return '0B'
+        if (size < 1024) return size + 'B'
+        if (size < 1024 * 1024) return (size / 1024).toFixed(2) + 'KB'
+        return (size / 1024 / 1024).toFixed(2) + 'MB'
       }
     }
   }
@@ -647,6 +973,18 @@
         color: #333;
         border-bottom: 1rpx solid #f0f0f0;
         padding-bottom: 10rpx;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        
+        .upload-btn {
+          font-size: 24rpx;
+          padding: 8rpx 20rpx;
+          background-color: #007AFF;
+          color: white;
+          border-radius: 8rpx;
+          border: none;
+        }
       }
       
       .info-item {
@@ -694,6 +1032,84 @@
         background-color: #f9f9f9;
         padding: 20rpx;
         border-radius: 10rpx;
+      }
+      
+      .no-attachment {
+        text-align: center;
+        padding: 40rpx 0;
+        color: #999;
+        font-size: 28rpx;
+      }
+      
+      .attachment-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 20rpx;
+        margin-bottom: 15rpx;
+        background-color: #f9f9f9;
+        border-radius: 10rpx;
+        
+        &:last-child {
+          margin-bottom: 0;
+        }
+        
+        .attachment-info {
+          flex: 1;
+          margin-right: 20rpx;
+          
+          .attachment-category {
+            margin-bottom: 8rpx;
+            
+            .category-tag {
+              display: inline-block;
+              padding: 4rpx 12rpx;
+              background-color: #007AFF;
+              color: white;
+              font-size: 22rpx;
+              border-radius: 4rpx;
+            }
+          }
+          
+          .attachment-name {
+            font-size: 28rpx;
+            color: #333;
+            margin-bottom: 8rpx;
+            word-break: break-all;
+          }
+          
+          .attachment-meta {
+            font-size: 24rpx;
+            color: #999;
+            
+            .upload-time {
+              margin-right: 20rpx;
+            }
+          }
+        }
+        
+        .attachment-actions {
+          display: flex;
+          flex-direction: column;
+          gap: 10rpx;
+          
+          .action-btn {
+            padding: 8rpx 20rpx;
+            font-size: 24rpx;
+            border-radius: 6rpx;
+            border: none;
+            
+            &.view-btn {
+              background-color: #007AFF;
+              color: white;
+            }
+            
+            &.delete-btn {
+              background-color: #ff3b30;
+              color: white;
+            }
+          }
+        }
       }
     }
     
@@ -749,5 +1165,101 @@
         }
       }
     }
+    
+    .upload-dialog {
+      background-color: white;
+      border-radius: 20rpx 20rpx 0 0;
+      padding: 30rpx;
+      
+      .dialog-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 30rpx;
+        
+        .dialog-title {
+          font-size: 32rpx;
+          font-weight: bold;
+          color: #333;
+        }
+      }
+      
+      .dialog-content {
+        .form-item {
+          margin-bottom: 30rpx;
+          
+          .form-label {
+            font-size: 28rpx;
+            color: #333;
+            margin-bottom: 15rpx;
+          }
+          
+          .picker-value {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 20rpx;
+            background-color: #f5f5f5;
+            border-radius: 10rpx;
+            font-size: 28rpx;
+            color: #333;
+          }
+          
+          .choose-image-btn {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 30rpx;
+            background-color: #f5f5f5;
+            border-radius: 10rpx;
+            border: 2rpx dashed #ccc;
+            color: #666;
+            font-size: 28rpx;
+            
+            text {
+              margin-left: 10rpx;
+            }
+          }
+        }
+        
+        .preview-area {
+          margin-top: 20rpx;
+          
+          .preview-image {
+            width: 100%;
+            height: 400rpx;
+            border-radius: 10rpx;
+          }
+        }
+      }
+      
+      .dialog-footer {
+        display: flex;
+        gap: 20rpx;
+        margin-top: 30rpx;
+        
+        button {
+          flex: 1;
+          height: 80rpx;
+          border-radius: 10rpx;
+          font-size: 30rpx;
+          border: none;
+        }
+        
+        .cancel-btn {
+          background-color: #f5f5f5;
+          color: #666;
+        }
+        
+        .confirm-btn {
+          background-color: #007AFF;
+          color: white;
+          
+          &:disabled {
+            background-color: #ccc;
+          }
+        }
+      }
+    }
   }
 </style>
\ No newline at end of file
diff --git a/bin/clean.bat b/bin/clean.bat
deleted file mode 100644
index 24c0974..0000000
--- a/bin/clean.bat
+++ /dev/null
@@ -1,12 +0,0 @@
-@echo off
-echo.
-echo [信息] 清理工程target生成路径。
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-call mvn clean
-
-pause
\ No newline at end of file
diff --git a/bin/package.bat b/bin/package.bat
deleted file mode 100644
index c693ec0..0000000
--- a/bin/package.bat
+++ /dev/null
@@ -1,12 +0,0 @@
-@echo off
-echo.
-echo [信息] 打包Web工程,生成war/jar包文件。
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-call mvn clean package -Dmaven.test.skip=true
-
-pause
\ No newline at end of file
diff --git a/bin/run.bat b/bin/run.bat
deleted file mode 100644
index 41efbd0..0000000
--- a/bin/run.bat
+++ /dev/null
@@ -1,14 +0,0 @@
-@echo off
-echo.
-echo [信息] 使用Jar命令运行Web工程。
-echo.
-
-cd %~dp0
-cd ../ruoyi-admin/target
-
-set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
-
-java -jar %JAVA_OPTS% ruoyi-admin.jar
-
-cd bin
-pause
\ No newline at end of file
diff --git "a/doc/966120API\346\216\245\345\217\243\350\247\204\350\214\203.pdf" "b/doc/966120API\346\216\245\345\217\243\350\247\204\350\214\203.pdf"
deleted file mode 100644
index 0914adb..0000000
--- "a/doc/966120API\346\216\245\345\217\243\350\247\204\350\214\203.pdf"
+++ /dev/null
Binary files differ
diff --git "a/doc/966120\347\224\237\346\210\220\346\234\215\345\212\241\345\215\225\346\216\245\345\217\243.pdf" "b/doc/966120\347\224\237\346\210\220\346\234\215\345\212\241\345\215\225\346\216\245\345\217\243.pdf"
deleted file mode 100644
index 51381f4..0000000
--- "a/doc/966120\347\224\237\346\210\220\346\234\215\345\212\241\345\215\225\346\216\245\345\217\243.pdf"
+++ /dev/null
Binary files differ
diff --git a/doc/java8.rar b/doc/java8.rar
deleted file mode 100644
index 7cc0344..0000000
--- a/doc/java8.rar
+++ /dev/null
Binary files differ
diff --git a/doc/jdk-8u291-windows-x64.exe b/doc/jdk-8u291-windows-x64.exe
deleted file mode 100644
index da5cb5f..0000000
--- a/doc/jdk-8u291-windows-x64.exe
+++ /dev/null
Binary files differ
diff --git a/doc/sqlncli.msi b/doc/sqlncli.msi
deleted file mode 100644
index a01b934..0000000
--- a/doc/sqlncli.msi
+++ /dev/null
Binary files differ
diff --git "a/doc/\345\271\277\345\267\236\351\235\236\346\200\245\346\225\221\350\275\254\350\277\220\345\257\271\346\216\245\347\254\254\344\270\211\346\226\271\346\216\245\345\217\243\346\226\207\346\241\243\0501\051.docx" "b/doc/\345\271\277\345\267\236\351\235\236\346\200\245\346\225\221\350\275\254\350\277\220\345\257\271\346\216\245\347\254\254\344\270\211\346\226\271\346\216\245\345\217\243\346\226\207\346\241\243\0501\051.docx"
deleted file mode 100644
index 3b92eda..0000000
--- "a/doc/\345\271\277\345\267\236\351\235\236\346\200\245\346\225\221\350\275\254\350\277\220\345\257\271\346\216\245\347\254\254\344\270\211\346\226\271\346\216\245\345\217\243\346\226\207\346\241\243\0501\051.docx"
+++ /dev/null
Binary files differ
diff --git "a/doc/\345\271\277\345\267\236\351\235\236\346\200\245\346\225\221\350\275\254\350\277\220\345\257\271\346\216\245\347\254\254\344\270\211\346\226\271\346\216\245\345\217\243\346\226\207\346\241\243\0501\051.pdf" "b/doc/\345\271\277\345\267\236\351\235\236\346\200\245\346\225\221\350\275\254\350\277\220\345\257\271\346\216\245\347\254\254\344\270\211\346\226\271\346\216\245\345\217\243\346\226\207\346\241\243\0501\051.pdf"
deleted file mode 100644
index 9a06182..0000000
--- "a/doc/\345\271\277\345\267\236\351\235\236\346\200\245\346\225\221\350\275\254\350\277\220\345\257\271\346\216\245\347\254\254\344\270\211\346\226\271\346\216\245\345\217\243\346\226\207\346\241\243\0501\051.pdf"
+++ /dev/null
Binary files differ
diff --git "a/doc/\350\213\245\344\276\235\347\216\257\345\242\203\344\275\277\347\224\250\346\211\213\345\206\214.docx" "b/doc/\350\213\245\344\276\235\347\216\257\345\242\203\344\275\277\347\224\250\346\211\213\345\206\214.docx"
deleted file mode 100644
index 9e4daef..0000000
--- "a/doc/\350\213\245\344\276\235\347\216\257\345\242\203\344\275\277\347\224\250\346\211\213\345\206\214.docx"
+++ /dev/null
Binary files differ
diff --git "a/doc/\350\256\242\345\215\225\347\212\266\346\200\201\345\233\236\350\260\203\346\216\245\345\217\243\346\226\207\346\241\243.docx" "b/doc/\350\256\242\345\215\225\347\212\266\346\200\201\345\233\236\350\260\203\346\216\245\345\217\243\346\226\207\346\241\243.docx"
deleted file mode 100644
index 6e3f130..0000000
--- "a/doc/\350\256\242\345\215\225\347\212\266\346\200\201\345\233\236\350\260\203\346\216\245\345\217\243\346\226\207\346\241\243.docx"
+++ /dev/null
Binary files differ
diff --git "a/doc/\350\256\242\345\215\225\350\257\246\346\203\205.png" "b/doc/\350\256\242\345\215\225\350\257\246\346\203\205.png"
deleted file mode 100644
index 9a75e7d..0000000
--- "a/doc/\350\256\242\345\215\225\350\257\246\346\203\205.png"
+++ /dev/null
Binary files differ
diff --git "a/doc/\350\256\242\345\215\225\350\257\246\346\203\205.rp" "b/doc/\350\256\242\345\215\225\350\257\246\346\203\205.rp"
deleted file mode 100644
index 3ac2e97..0000000
--- "a/doc/\350\256\242\345\215\225\350\257\246\346\203\205.rp"
+++ /dev/null
Binary files differ
diff --git "a/docs/\344\273\273\345\212\241\347\212\266\346\200\201\345\217\230\346\233\264GPS\345\256\232\344\275\215\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/docs/\344\273\273\345\212\241\347\212\266\346\200\201\345\217\230\346\233\264GPS\345\256\232\344\275\215\345\212\237\350\203\275\350\257\264\346\230\216.md"
deleted file mode 100644
index 5844142..0000000
--- "a/docs/\344\273\273\345\212\241\347\212\266\346\200\201\345\217\230\346\233\264GPS\345\256\232\344\275\215\345\212\237\350\203\275\350\257\264\346\230\216.md"
+++ /dev/null
@@ -1,282 +0,0 @@
-# 浠诲姟鐘舵�佸彉鏇碐PS瀹氫綅鍔熻兘璇存槑
-
-## 鍔熻兘姒傝堪
-
-鍦ㄦ墜鏈虹鎿嶄綔浠诲姟鐘舵�佸彉鏇存椂锛堝鍑哄彂銆佸埌杈俱�佽繑绋嬨�佸畬鎴愮瓑锛夛紝绯荤粺浼氳嚜鍔ㄨ幏鍙栧綋鍓嶇敤鎴风殑GPS浣嶇疆淇℃伅鍜屽湴鐞嗕綅缃俊鎭紝骞惰褰曞埌浠诲姟鎿嶄綔鏃ュ織涓��
-
-## 鏁版嵁搴撳彉鏇�
-
-### 1. 浠诲姟鎿嶄綔鏃ュ織琛ㄦ柊澧炲瓧娈�
-
-鍦� `sys_task_log` 琛ㄤ腑鏂板浜嗕互涓嬪瓧娈电敤浜庡瓨鍌℅PS鍜屼綅缃俊鎭細
-
-| 瀛楁鍚� | 绫诲瀷 | 璇存槑 |
-|--------|------|------|
-| latitude | DECIMAL(10,6) | 绾害 |
-| longitude | DECIMAL(10,6) | 缁忓害 |
-| location_address | VARCHAR(500) | 浣嶇疆鍦板潃锛堣閬撴垨POI鍚嶇О锛� |
-| location_province | VARCHAR(50) | 鐪佷唤 |
-| location_city | VARCHAR(50) | 鍩庡競 |
-| location_district | VARCHAR(50) | 鍖哄幙 |
-| gps_accuracy | DECIMAL(10,2) | GPS绮惧害锛堢背锛� |
-| altitude | DECIMAL(10,2) | 娴锋嫈楂樺害锛堢背锛� |
-| speed | DECIMAL(10,2) | 閫熷害锛堢背/绉掞級 |
-| heading | DECIMAL(10,2) | 鏂瑰悜瑙掑害锛�0-360搴︼級 |
-
-### 2. 鎵ц鏁版嵁搴撹剼鏈�
-
-```sql
--- 鎵ц姝よ剼鏈坊鍔燝PS浣嶇疆瀛楁
-source sql/add_location_fields.sql
-```
-
-## 鍚庣瀹炵幇
-
-### 1. 瀹炰綋绫讳慨鏀�
-
-**SysTaskLog.java** - 娣诲姞GPS浣嶇疆淇℃伅瀛楁鍙奼etter/setter鏂规硶
-
-### 2. Mapper淇敼
-
-**SysTaskLogMapper.xml** - 鏇存柊SQL璇彞锛屾敮鎸丟PS瀛楁鐨勬煡璇㈠拰鎻掑叆
-
-### 3. Service灞備慨鏀�
-
-**ISysTaskService.java** - 鏂板甯PS浣嶇疆淇℃伅鐨勭姸鎬佸彉鏇存柟娉�
-```java
-public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog);
-```
-
-**SysTaskServiceImpl.java** - 瀹炵幇GPS浣嶇疆璁板綍閫昏緫
-- 淇濈暀鍘熸湁鐨� `changeTaskStatus` 鏂规硶锛堜笉甯PS淇℃伅锛�
-- 鏂板 `changeTaskStatusWithLocation` 鏂规硶锛堝甫GPS淇℃伅锛�
-- 淇敼 `recordTaskLog` 鏂规硶鏀寔GPS淇℃伅浼犻��
-
-### 4. Controller灞備慨鏀�
-
-**SysTaskController.java**
-- `ChangeStatusRequest` 璇锋眰瀵硅薄鏂板GPS浣嶇疆淇℃伅瀛楁
-- `changeTaskStatus` 鏂规硶鑷姩鍒ゆ柇鏄惁鍖呭惈GPS淇℃伅锛岃皟鐢ㄥ搴旂殑Service鏂规硶
-
-## 鍓嶇瀹炵幇
-
-### 1. 淇敼鐨勯〉闈�
-
-浠ヤ笅涓変釜椤甸潰鐨勪换鍔$姸鎬佸彉鏇村姛鑳藉潎宸查泦鎴怗PS瀹氫綅锛�
-
-1. **app/pages/task/detail.vue** - 浠诲姟璇︽儏椤�
-2. **app/pages/task/index.vue** - 浠诲姟鍒楄〃椤�
-3. **app/pages/index.vue** - 棣栭〉锛堣繍琛屼腑浠诲姟锛�
-
-### 2. 瀹炵幇閫昏緫
-
-#### 鑾峰彇GPS浣嶇疆淇℃伅
-
-浣跨敤UniApp鐨� `uni.getLocation` API鑾峰彇GPS淇℃伅锛�
-
-```javascript
-uni.getLocation({
-  type: 'gcj02',        // 浣跨敤鍥芥祴灞�鍧愭爣绯�
-  geocode: true,        // 瑙f瀽鍦板潃淇℃伅
-  altitude: true,       // 鑾峰彇楂樺害淇℃伅
-  success: function(res) {
-    // GPS瀹氫綅鎴愬姛锛屾惡甯︿綅缃俊鎭洿鏂扮姸鎬�
-  },
-  fail: function(err) {
-    // GPS瀹氫綅澶辫触锛屾彁绀虹敤鎴锋槸鍚︾户缁�
-  }
-})
-```
-
-#### 鑾峰彇鐨凣PS淇℃伅鍖呮嫭
-
-- **缁忕含搴�**锛歚latitude`, `longitude`
-- **鍦板潃淇℃伅**锛歚address.province`, `address.city`, `address.district`, `address.street`
-- **瀹氫綅绮惧害**锛歚accuracy`锛堢背锛�
-- **娴锋嫈楂樺害**锛歚altitude`锛堢背锛�
-- **绉诲姩閫熷害**锛歚speed`锛堢背/绉掞級
-- **绉诲姩鏂瑰悜**锛歚heading`/`direction`锛堝害锛�
-
-#### 鐘舵�佹洿鏂版祦绋�
-
-1. 鐢ㄦ埛鐐瑰嚮鐘舵�佸彉鏇存寜閽紙濡�"鍑哄彂"銆�"宸插埌杈�"绛夛級
-2. 绯荤粺寮瑰嚭浜屾纭瀵硅瘽妗�
-3. 鐢ㄦ埛纭鍚庯紝鑷姩鑾峰彇GPS浣嶇疆淇℃伅
-4. 灏嗙姸鎬佹暟鎹拰GPS淇℃伅涓�璧峰彂閫佸埌鍚庣
-5. GPS瀹氫綅澶辫触鏃讹紝鎻愮ず鐢ㄦ埛鏄惁缁х画锛堝彲閫夋嫨涓嶅甫GPS淇℃伅鏇存柊锛�
-
-### 3. 淇敼鐨勬柟娉�
-
-鎵�鏈夐〉闈㈢殑 `updateTaskStatus` 鏂规硶缁熶竴鏀逛负璋冪敤 `getLocationAndUpdateStatus` 鏂规硶锛�
-
-```javascript
-// 鏇存柊浠诲姟鐘舵��
-updateTaskStatus(taskId, status, remark) {
-  this.getLocationAndUpdateStatus(taskId, status, remark)
-},
-
-// 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
-getLocationAndUpdateStatus(taskId, status, remark) {
-  const that = this
-  
-  uni.getLocation({
-    type: 'gcj02',
-    geocode: true,
-    altitude: true,
-    success: function(res) {
-      // 鎼哄甫GPS淇℃伅鏇存柊鐘舵��
-      const statusData = {
-        taskStatus: status,
-        remark: remark,
-        latitude: res.latitude,
-        longitude: res.longitude,
-        locationAddress: res.address ? res.address.street || res.address.poiName || '' : '',
-        locationProvince: res.address ? res.address.province || '' : '',
-        locationCity: res.address ? res.address.city || '' : '',
-        locationDistrict: res.address ? res.address.district || '' : '',
-        gpsAccuracy: res.accuracy,
-        altitude: res.altitude,
-        speed: res.speed,
-        heading: res.direction || res.heading
-      }
-      
-      changeTaskStatus(taskId, statusData).then(response => {
-        that.$modal.showToast('鐘舵�佹洿鏂版垚鍔�')
-        that.loadTaskList()
-      })
-    },
-    fail: function(err) {
-      // GPS瀹氫綅澶辫触锛屾彁绀虹敤鎴�
-      that.$modal.confirm('GPS瀹氫綅澶辫触锛屾槸鍚︾户缁洿鏂扮姸鎬侊紵').then(() => {
-        // 涓嶅甫GPS淇℃伅鏇存柊
-      })
-    }
-  })
-}
-```
-
-## API鎺ュ彛
-
-### 璇锋眰绀轰緥
-
-```
-PUT /task/{taskId}/status
-Content-Type: application/json
-
-{
-  "taskStatus": "DEPARTING",
-  "remark": "浠诲姟宸插嚭鍙�",
-  "latitude": 39.908722,
-  "longitude": 116.397496,
-  "locationAddress": "涓滈暱瀹夎",
-  "locationProvince": "鍖椾含甯�",
-  "locationCity": "鍖椾含甯�",
-  "locationDistrict": "涓滃煄鍖�",
-  "gpsAccuracy": 15.5,
-  "altitude": 45.2,
-  "speed": 0.0,
-  "heading": 90.5
-}
-```
-
-### 鍝嶅簲绀轰緥
-
-```json
-{
-  "code": 200,
-  "msg": "鎿嶄綔鎴愬姛"
-}
-```
-
-## 鏉冮檺閰嶇疆
-
-### UniApp manifest.json閰嶇疆
-
-闇�瑕佸湪 `manifest.json` 涓坊鍔犲畾浣嶆潈闄愶細
-
-```json
-{
-  "mp-weixin": {
-    "permission": {
-      "scope.userLocation": {
-        "desc": "鎮ㄧ殑浣嶇疆淇℃伅灏嗙敤浜庤褰曚换鍔℃搷浣滀綅缃�"
-      }
-    }
-  },
-  "app-plus": {
-    "distribute": {
-      "android": {
-        "permissions": [
-          "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
-          "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
-          "<uses-permission android:name=\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\"/>"
-        ]
-      },
-      "ios": {
-        "idfa": false,
-        "privacyDescription": {
-          "NSLocationWhenInUseUsageDescription": "姝ゅ簲鐢ㄩ渶瑕佽幏鍙栨偍鐨勪綅缃俊鎭敤浜庤褰曚换鍔℃搷浣滀綅缃�"
-        }
-      }
-    }
-  }
-}
-```
-
-## 浣跨敤鍦烘櫙
-
-姝ゅ姛鑳介�傜敤浜庢墍鏈夐渶瑕佽褰曟搷浣滀綅缃殑浠诲姟鐘舵�佸彉鏇存搷浣滐細
-
-1. **鍑哄彂锛圖EPARTING锛�** - 璁板綍鍑哄彂鏃剁殑GPS浣嶇疆
-2. **宸插埌杈撅紙ARRIVED锛�** - 璁板綍鍒拌揪鐩殑鍦扮殑GPS浣嶇疆
-3. **杩旂▼涓紙RETURNING锛�** - 璁板綍寮�濮嬭繑绋嬫椂鐨凣PS浣嶇疆
-4. **宸插畬鎴愶紙COMPLETED锛�** - 璁板綍浠诲姟瀹屾垚鏃剁殑GPS浣嶇疆
-5. **宸插彇娑堬紙CANCELLED锛�** - 璁板綍鍙栨秷浠诲姟鏃剁殑GPS浣嶇疆
-
-## 鏁版嵁鏌ヨ
-
-### 鏌ヨ浠诲姟鎿嶄綔鏃ュ織锛堝惈GPS淇℃伅锛�
-
-```sql
-SELECT 
-  log_id, task_id, operation_type, operation_desc,
-  operator_name, operation_time,
-  latitude, longitude, location_address,
-  location_province, location_city, location_district,
-  gps_accuracy, altitude, speed, heading
-FROM sys_task_log
-WHERE task_id = ?
-ORDER BY operation_time DESC;
-```
-
-### 鏌ヨ鐗瑰畾鏃堕棿鑼冨洿鍐呯殑鎿嶄綔浣嶇疆
-
-```sql
-SELECT 
-  task_id, operation_type, operator_name, operation_time,
-  latitude, longitude, location_address
-FROM sys_task_log
-WHERE operation_time BETWEEN ? AND ?
-  AND latitude IS NOT NULL
-  AND longitude IS NOT NULL
-ORDER BY operation_time DESC;
-```
-
-## 娉ㄦ剰浜嬮」
-
-1. **鐢ㄦ埛闅愮**锛氬湪棣栨浣跨敤瀹氫綅鍔熻兘鏃讹紝浼氳姹傜敤鎴锋巿鏉冧綅缃潈闄�
-2. **瀹氫綅澶辫触澶勭悊**锛氬鏋淕PS瀹氫綅澶辫触锛岀郴缁熶細鎻愮ず鐢ㄦ埛鏄惁缁х画鎿嶄綔锛堜笉甯PS淇℃伅锛�
-3. **缃戠粶瑕佹眰**锛氬湴鐞嗙紪鐮侊紙閫嗗湴鐞嗚В鏋愶級闇�瑕佺綉缁滆繛鎺�
-4. **鍧愭爣绯荤粺**锛氫娇鐢℅CJ-02鍧愭爣绯伙紙鍥芥祴灞�鍧愭爣绯伙級锛岄�傜敤浜庡浗鍐呭湴鍥�
-5. **绮惧害褰卞搷鍥犵礌**锛�
-   - 瀹ゅ唴瀹氫綅绮惧害杈冧綆
-   - 澶╂皵銆佸缓绛戠墿閬尅浼氬奖鍝嶇簿搴�
-   - 绉诲姩鐘舵�佷笅绮惧害杈冮潤姝㈡椂鐣ヤ綆
-
-## 鍚庣画浼樺寲寤鸿
-
-1. **绂荤嚎瀹氫綅**锛氭敮鎸佺绾挎椂鍏堢紦瀛楪PS淇℃伅锛岃仈缃戝悗鍐嶄笂浼�
-2. **杞ㄨ抗璁板綍**锛氬彲浠ヨ褰曚换鍔℃墽琛岃繃绋嬩腑鐨勫畬鏁碐PS杞ㄨ抗
-3. **鍦板浘灞曠ず**锛氬湪浠诲姟璇︽儏椤靛睍绀烘搷浣滀綅缃殑鍦板浘鏍囪
-4. **寮傚父妫�娴�**锛氶�氳繃GPS浣嶇疆鍒ゆ柇鏄惁瀛樺湪寮傚父鎿嶄綔锛堝浣嶇疆涓嶅尮閰嶏級
-5. **缁熻鍒嗘瀽**锛氬熀浜嶨PS鏁版嵁杩涜杩愯惀鍒嗘瀽锛堝骞冲潎鍝嶅簲鏃堕棿銆佹湇鍔¤寖鍥寸瓑锛�
diff --git "a/docs/\345\234\260\347\220\206\347\274\226\347\240\201\346\234\215\345\212\241\344\275\277\347\224\250\350\257\264\346\230\216.md" "b/docs/\345\234\260\347\220\206\347\274\226\347\240\201\346\234\215\345\212\241\344\275\277\347\224\250\350\257\264\346\230\216.md"
deleted file mode 100644
index 7b0bffb..0000000
--- "a/docs/\345\234\260\347\220\206\347\274\226\347\240\201\346\234\215\345\212\241\344\275\277\347\224\250\350\257\264\346\230\216.md"
+++ /dev/null
@@ -1,218 +0,0 @@
-# 鍦扮悊缂栫爜鏈嶅姟浣跨敤璇存槑
-
-## 鍔熻兘璇存槑
-
-鍦扮悊缂栫爜鏈嶅姟鍙互灏嗗湴鍧�瀛楃涓茶浆鎹负GPS鍧愭爣锛堢粡绾害锛夛紝鐢ㄤ簬鑷姩璁$畻鍖婚櫌涔嬮棿鐨勮浆杩愯窛绂汇��
-
-## 鍚庣鎺ュ彛
-
-### 鎺ュ彛鍦板潃
-```
-GET /system/geocode/address
-```
-
-### 璇锋眰鍙傛暟
-
-| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|--------|------|------|------|
-| address | String | 鏄� | 鍦板潃瀛楃涓诧紝渚嬪锛�"鍖椾含甯傛湞闃冲尯鏌愭煇鍖婚櫌" |
-| city | String | 鍚� | 鍩庡競鍚嶇О锛岀敤浜庢彁楂樿В鏋愬噯纭害锛屼緥濡傦細"鍖椾含甯�" |
-
-### 鍝嶅簲绀轰緥
-
-鎴愬姛鍝嶅簲锛�
-```json
-{
-  "code": 200,
-  "msg": "鍦扮悊缂栫爜鎴愬姛",
-  "data": {
-    "latitude": 39.908722,
-    "longitude": 116.397496,
-    "address": "鍖椾含甯備笢鍩庡尯涓滈暱瀹夎1鍙�",
-    "success": true,
-    "errorMessage": null
-  }
-}
-```
-
-澶辫触鍝嶅簲锛�
-```json
-{
-  "code": 500,
-  "msg": "鍦扮悊缂栫爜澶辫触: 鍦板潃涓嶅瓨鍦�"
-}
-```
-
-## 鍓嶇浣跨敤绀轰緥
-
-### 1. 瀵煎叆API
-```javascript
-import { getCoordinatesByAddress } from '@/api/geocode'
-```
-
-### 2. 璋冪敤鎺ュ彛鑾峰彇鍧愭爣
-
-```javascript
-// 鍩烘湰鐢ㄦ硶
-async getHospitalCoordinates() {
-  try {
-    const res = await getCoordinatesByAddress('鍖椾含鍗忓拰鍖婚櫌')
-    if (res.code === 200) {
-      const { latitude, longitude } = res.data
-      console.log('GPS鍧愭爣:', latitude, longitude)
-      // 淇濆瓨鍧愭爣鍒拌〃鍗�
-      this.taskForm.hospitalOut.latitude = latitude
-      this.taskForm.hospitalOut.longitude = longitude
-    }
-  } catch (error) {
-    console.error('鑾峰彇鍧愭爣澶辫触', error)
-  }
-}
-
-// 鎸囧畾鍩庡競锛屾彁楂樺噯纭害
-async getHospitalCoordinates() {
-  try {
-    const res = await getCoordinatesByAddress('鍗忓拰鍖婚櫌', '鍖椾含甯�')
-    if (res.code === 200) {
-      const { latitude, longitude, address } = res.data
-      console.log('GPS鍧愭爣:', latitude, longitude)
-      console.log('鏍囧噯鍖栧湴鍧�:', address)
-    }
-  } catch (error) {
-    console.error('鑾峰彇鍧愭爣澶辫触', error)
-  }
-}
-```
-
-### 3. 鍦ㄦ�ユ晳杞繍椤甸潰涓泦鎴�
-
-鍦� `create-emergency.vue` 涓紝褰撶敤鎴烽�夋嫨鍖婚櫌鍚庤嚜鍔ㄨ幏鍙栧潗鏍囷細
-
-```javascript
-// 閫夋嫨杞嚭鍖婚櫌
-selectHospitalOut(hospital) {
-  this.taskForm.hospitalOut.name = hospital.hospName
-  this.taskForm.hospitalOut.address = hospital.hospAddress
-  this.hospitalOutSearchKeyword = hospital.hospName
-  this.showHospitalOutResults = false
-  this.hospitalOutResults = []
-  
-  // 鑷姩鑾峰彇GPS鍧愭爣
-  this.getHospitalOutCoordinates(hospital.hospAddress, hospital.hopsCity)
-},
-
-// 鑾峰彇杞嚭鍖婚櫌鍧愭爣
-async getHospitalOutCoordinates(address, city) {
-  try {
-    const res = await getCoordinatesByAddress(address, city)
-    if (res.code === 200) {
-      this.taskForm.hospitalOut.latitude = res.data.latitude
-      this.taskForm.hospitalOut.longitude = res.data.longitude
-      // 濡傛灉杞叆鍖婚櫌涔熷凡閫夋嫨锛岃嚜鍔ㄨ绠楄窛绂�
-      if (this.taskForm.hospitalIn.latitude) {
-        this.calculateDistance()
-      }
-    }
-  } catch (error) {
-    console.error('鑾峰彇杞嚭鍖婚櫌鍧愭爣澶辫触', error)
-  }
-},
-
-// 鑾峰彇杞叆鍖婚櫌鍧愭爣
-async getHospitalInCoordinates(address, city) {
-  try {
-    const res = await getCoordinatesByAddress(address, city)
-    if (res.code === 200) {
-      this.taskForm.hospitalIn.latitude = res.data.latitude
-      this.taskForm.hospitalIn.longitude = res.data.longitude
-      // 濡傛灉杞嚭鍖婚櫌涔熷凡閫夋嫨锛岃嚜鍔ㄨ绠楄窛绂�
-      if (this.taskForm.hospitalOut.latitude) {
-        this.calculateDistance()
-      }
-    }
-  } catch (error) {
-    console.error('鑾峰彇杞叆鍖婚櫌鍧愭爣澶辫触', error)
-  }
-},
-
-// 璁$畻涓ょ偣涔嬮棿鐨勮窛绂伙紙浣跨敤Haversine鍏紡锛�
-calculateDistance() {
-  const lat1 = this.taskForm.hospitalOut.latitude
-  const lon1 = this.taskForm.hospitalOut.longitude
-  const lat2 = this.taskForm.hospitalIn.latitude
-  const lon2 = this.taskForm.hospitalIn.longitude
-  
-  if (!lat1 || !lon1 || !lat2 || !lon2) {
-    return
-  }
-  
-  const R = 6371 // 鍦扮悆鍗婂緞锛堝叕閲岋級
-  const dLat = (lat2 - lat1) * Math.PI / 180
-  const dLon = (lon2 - lon1) * Math.PI / 180
-  const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
-            Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
-            Math.sin(dLon / 2) * Math.sin(dLon / 2)
-  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
-  const distance = R * c
-  
-  // 鑷姩濉厖璺濈瀛楁锛堜繚鐣�2浣嶅皬鏁帮級
-  this.taskForm.transferDistance = distance.toFixed(2)
-  
-  uni.showToast({
-    title: `棰勪及璺濈: ${distance.toFixed(2)}鍏噷`,
-    icon: 'none'
-  })
-}
-```
-
-## 閰嶇疆璇存槑
-
-### 鑵捐鍦板浘API瀵嗛挜閰嶇疆
-
-鍦� `application.yml` 涓厤缃吘璁湴鍥続PI瀵嗛挜锛�
-
-```yaml
-# 鑵捐鍦板浘閰嶇疆
-tencent:
-  map:
-    key: YOUR_TENCENT_MAP_API_KEY
-```
-
-### 鑾峰彇鑵捐鍦板浘API瀵嗛挜
-
-1. 璁块棶鑵捐浣嶇疆鏈嶅姟锛歨ttps://lbs.qq.com/
-2. 娉ㄥ唽骞剁櫥褰曞紑鍙戣�呰处鍙�
-3. 杩涘叆鎺у埗鍙帮紝鍒涘缓搴旂敤
-4. 娣诲姞Key锛岄�夋嫨WebService API
-5. 灏嗙敓鎴愮殑Key濉叆閰嶇疆鏂囦欢
-
-## 鎶�鏈疄鐜�
-
-### 鍚庣鏋舵瀯
-
-- **GeocodeResult.java**: 鍦扮悊缂栫爜缁撴灉DTO锛屽寘鍚粡绾害銆佸湴鍧�銆佹垚鍔熺姸鎬佺瓑淇℃伅
-- **IGeocodeService.java**: 鍦扮悊缂栫爜鏈嶅姟鎺ュ彛
-- **GeocodeServiceImpl.java**: 鍦扮悊缂栫爜鏈嶅姟瀹炵幇绫伙紝璋冪敤鑵捐鍦板浘WebService API
-- **GeocodeController.java**: 鍦扮悊缂栫爜鎺у埗鍣紝鎻愪緵RESTful鎺ュ彛
-
-### API璇存槑
-
-浣跨敤鑵捐鍦板浘WebService API鐨勫湴鐞嗙紪鐮佹帴鍙o細
-- API鏂囨。锛歨ttps://lbs.qq.com/service/webService/webServiceGuide/webServiceGcoder
-- 鍏嶈垂棰濋厤棰濓細10000娆�/澶�/Key
-- 璇锋眰闄愭祦锛�5娆�/绉�/Key
-
-## 娉ㄦ剰浜嬮」
-
-1. **API瀵嗛挜瀹夊叏**锛氫笉瑕佸皢API瀵嗛挜鎻愪氦鍒板叕寮�鐨勪唬鐮佷粨搴�
-2. **璋冪敤棰戠巼**锛氭敞鎰忎笉瑕佽秴杩嘇PI鐨勮皟鐢ㄩ檺鍒讹紙5娆�/绉掞級
-3. **閿欒澶勭悊**锛氶渶瑕佸鐞嗙綉缁滃紓甯搞�丄PI璋冪敤澶辫触绛夋儏鍐�
-4. **鍦板潃鍑嗙‘鎬�**锛氳緭鍏ョ殑鍦板潃瓒婅缁嗭紝瑙f瀽缁撴灉瓒婂噯纭�
-5. **鍧愭爣绯荤粺**锛氳吘璁湴鍥句娇鐢℅CJ-02鍧愭爣绯伙紙鐏槦鍧愭爣绯伙級
-
-## 鍚庣画浼樺寲寤鸿
-
-1. **缂撳瓨鏈哄埗**锛氬宸茶В鏋愯繃鐨勫湴鍧�杩涜缂撳瓨锛屽噺灏慉PI璋冪敤
-2. **鎵归噺鏌ヨ**锛氬鏋滈渶瑕佹煡璇㈠涓湴鍧�锛屽彲浠ヨ�冭檻鎵归噺鎺ュ彛
-3. **璺濈璁$畻**锛氬彲浠ョ洿鎺ヨ皟鐢ㄨ吘璁湴鍥剧殑璺嚎瑙勫垝API鑾峰彇瀹為檯瀵艰埅璺濈锛岃�屼笉鏄洿绾胯窛绂�
-4. **鍧愭爣瀛樺偍**锛氬皢瑙f瀽鍚庣殑鍧愭爣瀛樺偍鍒版暟鎹簱锛岄伩鍏嶉噸澶嶈В鏋�
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
index 32eb6f1..cd4693f 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -16,7 +16,7 @@
     {
         // System.setProperty("spring.devtools.restart.enabled", "false");
         SpringApplication.run(RuoYiApplication.class, args);
-        System.out.println("(鈾モ棤鈥库棤)锞夛緸  鑻ヤ緷鍚姩鎴愬姛   醿�(麓凇`醿�)锞�  \n" +
+        System.out.println("(鈾モ棤鈥库棤)锞夛緸  姘戣埅鍚姩鎴愬姛   醿�(麓凇`醿�)锞�  \n" +
                 " .-------.       ____     __        \n" +
                 " |  _ _   \\      \\   \\   /  /    \n" +
                 " | ( ' )  |       \\  _. /  '       \n" +
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
index 2786bef..06bf884 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
@@ -8,13 +8,13 @@
 
 import com.ruoyi.common.utils.WechatUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.config.WechatMpConfig;
 import com.alibaba.fastjson2.JSONObject;
 import com.ruoyi.system.domain.EvaluationDetail;
 import com.ruoyi.system.service.IEvaluationDimensionService;
 import com.ruoyi.system.domain.EvaluationDimension;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -47,6 +47,9 @@
 
     @Autowired
     private IEvaluationDimensionService evaluationDimensionService;
+    
+    @Autowired
+    private WechatMpConfig wechatMpConfig;
 
     /**
      * 鏌ヨ瀹㈡埛璇勪环鍒楄〃
@@ -150,12 +153,6 @@
         }
     }
 
-    @Value("${wechat.appId}")
-    private String wechatAppId;
-
-    @Value("${wechat.appSecret}")
-    private String wechatAppSecret;
-
     /**
      * 鐢熸垚寰俊鎺堟潈URL
      */
@@ -170,7 +167,12 @@
             logger.info("鐢熸垚寰俊鎺堟潈URL - 鍘熷redirectUri: {}", redirectUri);
             
             // 鐢熸垚寰俊鎺堟潈URL锛屼娇鐢╯nsapi_userinfo鑾峰彇鐢ㄦ埛淇℃伅
-            String authUrl = WechatUtils.generateAuthUrl(wechatAppId, redirectUri, "snsapi_userinfo", state);
+            String authUrl = WechatUtils.generateAuthUrl(
+                wechatMpConfig.getAppId(), 
+                redirectUri, 
+                "snsapi_userinfo", 
+                state
+            );
             if (authUrl == null) {
                 return error("鐢熸垚寰俊鎺堟潈URL澶辫触");
             }
@@ -180,7 +182,7 @@
             Map<String, String> result = new HashMap<>();
             result.put("authUrl", authUrl);
             result.put("originalRedirectUri", redirectUri);
-            result.put("appId", wechatAppId);
+            result.put("appId", wechatMpConfig.getAppId());
             return success(result);
         } catch (Exception e) {
             logger.error("鐢熸垚寰俊鎺堟潈URL澶辫触", e);
@@ -201,7 +203,11 @@
             }
 
             // 鑾峰彇缃戦〉鎺堟潈Access Token
-            JSONObject tokenInfo = WechatUtils.getWebAccessToken(wechatAppId, wechatAppSecret, code);
+            JSONObject tokenInfo = WechatUtils.getWebAccessToken(
+                wechatMpConfig.getAppId(), 
+                wechatMpConfig.getAppSecret(), 
+                code
+            );
             if (tokenInfo == null) {
                 return error("鑾峰彇寰俊鎺堟潈淇℃伅澶辫触");
             }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/imagedata/ImageDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/imagedata/ImageDataController.java
new file mode 100644
index 0000000..f1ca714
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/imagedata/ImageDataController.java
@@ -0,0 +1,1074 @@
+package com.ruoyi.web.controller.imagedata;
+
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.InputStreamBase64Converter;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.file.FileUploadResponse;
+import com.ruoyi.system.file.IFileUploadService;
+import com.ruoyi.system.imagedata.IImageDataService;
+import com.ruoyi.system.domain.ImageData;
+import com.ruoyi.system.domain.enums.ImageTypeEnum;
+import com.ruoyi.system.imagedata.WxImageUploadRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.util.*;
+import java.util.List;
+
+/**
+ * 鍥剧墖鏁版嵁鎺у埗鍣�
+ *
+ * @author mhyl
+ * @date 2024-01-01
+ */
+@RestController
+@DataSource(DataSourceType.SQLSERVER)
+@RequestMapping("/hospital/imagedata")
+public class ImageDataController extends BaseController {
+
+    private static final Logger log = LoggerFactory.getLogger(ImageDataController.class);
+    @Autowired
+    private IImageDataService imageDataService;
+
+    @Autowired
+    private IFileUploadService fileUploadService;
+
+
+    @Autowired
+    private LegacySystemConfig legacyConfig;
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁鍒楄〃
+     */
+//    @PreAuthorize("@ss.hasPermi('hospital:imagedata:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ImageData imageData) {
+//        startPage();
+        List<ImageData> list = imageDataService.selectImageDataList(imageData);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭鍥剧墖鏁版嵁鍒楄〃
+     */
+
+    @Log(title = "鍥剧墖鏁版嵁", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ImageData imageData) {
+        List<ImageData> list = imageDataService.selectImageDataList(imageData);
+        ExcelUtil<ImageData> util = new ExcelUtil<ImageData>(ImageData.class);
+        util.exportExcel(response, list, "鍥剧墖鏁版嵁鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇鍥剧墖鏁版嵁璇︾粏淇℃伅
+     */
+
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(imageDataService.selectImageDataById(id));
+    }
+
+    /**
+     * 鏂板鍥剧墖鏁版嵁
+     */
+
+    @Log(title = "鍥剧墖鏁版嵁", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ImageData imageData) {
+        return toAjax(imageDataService.insertImageData(imageData));
+    }
+
+    /**
+     * 淇敼鍥剧墖鏁版嵁
+     */
+    @Log(title = "鍥剧墖鏁版嵁", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ImageData imageData) {
+        return toAjax(imageDataService.updateImageData(imageData));
+    }
+
+    /**
+     * 鍒犻櫎鍥剧墖鏁版嵁
+     */
+    @Log(title = "鍥剧墖鏁版嵁", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(imageDataService.deleteImageDataByIds(ids));
+    }
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     */
+    @GetMapping("/byDispatchOrder/{dispatchOrdID}")
+    public AjaxResult getByDispatchOrder(@PathVariable("dispatchOrdID") Long dispatchOrdID) {
+        List<ImageData> list = imageDataService.selectImageDataByDOrdIDDt(dispatchOrdID);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鍜屽浘鐗囩被鍨嬭幏鍙栨湁鏁堝浘鐗囷紙鍖呭惈瀹屾暣閾炬帴锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 鍥剧墖鏁版嵁锛堝寘鍚畬鏁撮摼鎺ワ級
+     */
+//    @PreAuthorize("@ss.hasPermi('hospital:imagedata:query')")
+    @Anonymous()
+    @GetMapping("/byDispatchOrderAndType/{dispatchOrdID}/{imageType}")
+    public AjaxResult getByDispatchOrderAndType(@PathVariable("dispatchOrdID") Long dispatchOrdID,
+                                                @PathVariable("imageType") Integer imageType) {
+        try {
+            // 鏌ヨ鎸囧畾璋冨害鍗曞拰绫诲瀷鐨勬湁鏁堝浘鐗�
+            List<ImageData> imageDataList = imageDataService.selectImageDataByDOrdIDDtAndType(dispatchOrdID, imageType);
+
+            // 杩囨护鏈夋晥鍥剧墖锛堟湭鍒犻櫎鐨勶級
+            List<ImageData> validImages = imageDataList.stream()
+                    .filter(img -> img.getImageDel() == null || img.getImageDel() == 0)
+                    .collect(java.util.stream.Collectors.toList());
+
+            // 涓烘瘡涓浘鐗囨坊鍔犲畬鏁撮摼鎺�
+            for (ImageData imageData : validImages) {
+                // 娣诲姞鍘熷鍥剧墖瀹屾暣閾炬帴
+                if (StringUtils.hasText(imageData.getImageUrl())) {
+                    String fullImageUrl = buildFullImageUrl(imageData.getImageUrl());
+                    imageData.setImageUrl(fullImageUrl);
+                }
+
+                // 娣诲姞缂╃暐鍥惧畬鏁撮摼鎺�
+                if (StringUtils.hasText(imageData.getImageUrls())) {
+                    String fullThumbnailUrl = buildFullImageUrl(imageData.getImageUrls());
+                    imageData.setImageUrls(fullThumbnailUrl);
+                }
+            }
+
+            return AjaxResult.success("鑾峰彇鍥剧墖鎴愬姛", validImages);
+        } catch (Exception e) {
+            return AjaxResult.error("鑾峰彇鍥剧墖澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鍜屽浘鐗囩被鍨嬭幏鍙栨湁鏁堝浘鐗囷紙绠�鍖栫増锛屽彧杩斿洖鍥剧墖閾炬帴锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 鍥剧墖閾炬帴鍒楄〃
+     */
+    // @PreAuthorize("@ss.hasPermi('hospital:imagedata:query')")
+    @Anonymous()
+    @GetMapping("/links/byDispatchOrderAndType/{dispatchOrdID}/{imageType}")
+    public AjaxResult getImageLinksByDispatchOrderAndType(@PathVariable("dispatchOrdID") Long dispatchOrdID,
+                                                          @PathVariable("imageType") Integer imageType) {
+        try {
+            // 鏌ヨ鎸囧畾璋冨害鍗曞拰绫诲瀷鐨勬湁鏁堝浘鐗�
+            List<ImageData> imageDataList = imageDataService.selectImageDataByDOrdIDDtAndType(dispatchOrdID, imageType);
+
+            // 鏋勫缓鍥剧墖閾炬帴鍒楄〃
+            List<java.util.Map<String, String>> imageLinks = new java.util.ArrayList<>();
+
+            for (ImageData imageData : imageDataList) {
+                // 鍙鐞嗘湭鍒犻櫎鐨勫浘鐗�
+                if (imageData.getImageDel() == null || imageData.getImageDel() == 0) {
+                    java.util.Map<String, String> linkMap = new java.util.HashMap<>();
+
+                    // 鍘熷鍥剧墖閾炬帴
+                    if (StringUtils.hasText(imageData.getImageUrl())) {
+                        linkMap.put("originalUrl", buildFullImageUrl(imageData.getImageUrl()));
+                    }
+
+                    // 缂╃暐鍥鹃摼鎺�
+                    if (StringUtils.hasText(imageData.getImageUrls())) {
+                        linkMap.put("thumbnailUrl", buildFullImageUrl(imageData.getImageUrls()));
+                    }
+
+                    // 鍥剧墖ID
+                    linkMap.put("imageId", String.valueOf(imageData.getId()));
+
+                    // 鍥剧墖绫诲瀷
+                    linkMap.put("imageType", String.valueOf(imageData.getImageType()));
+
+                    // 涓婁紶鏃堕棿
+                    if (imageData.getUpImageTime() != null) {
+                        linkMap.put("uploadTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, imageData.getUpImageTime()));
+                    }
+
+                    imageLinks.add(linkMap);
+                }
+            }
+
+            return AjaxResult.success("鑾峰彇鍥剧墖閾炬帴鎴愬姛", imageLinks);
+        } catch (Exception e) {
+            return AjaxResult.error("鑾峰彇鍥剧墖閾炬帴澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鏋勫缓瀹屾暣鐨勫浘鐗嘦RL
+     *
+     * @param imagePath 鍥剧墖璺緞
+     * @return 瀹屾暣鐨勫浘鐗嘦RL
+     */
+    private String buildFullImageUrl(String imagePath) {
+        if (!StringUtils.hasText(imagePath)) {
+            return "";
+        }
+
+        // 濡傛灉宸茬粡鏄畬鏁碪RL锛岀洿鎺ヨ繑鍥�
+        if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
+            return imagePath;
+        }
+
+        // 浠庨厤缃腑璇诲彇鏂囦欢鏈嶅姟鍣║RL
+        String fileServerUrl = legacyConfig.getFileServerUrl();
+
+        // 濡傛灉閰嶇疆涓病鏈夎缃紝浣跨敤榛樿鍊�
+        if (!StringUtils.hasText(fileServerUrl)) {
+            // 璁板綍璀﹀憡鏃ュ織
+            System.err.println("璀﹀憡锛氶厤缃枃浠朵腑鏈缃� legacy.system.fileServerUrl锛屼娇鐢ㄩ粯璁ゅ��");
+            fileServerUrl = "https://sync.966120.com.cn";
+        }
+
+        // 纭繚鏂囦欢鏈嶅姟鍣║RL涓嶄互/缁撳熬
+        if (fileServerUrl.endsWith("/")) {
+            fileServerUrl = fileServerUrl.substring(0, fileServerUrl.length() - 1);
+        }
+
+        // 澶勭悊鍥剧墖璺緞锛氱Щ闄ゅ紑澶村拰缁撳熬鐨勭┖鐧藉瓧绗�
+        imagePath = imagePath.trim();
+
+        // 绉婚櫎寮�澶村拰缁撳熬鐨勬枩鏉�
+        while (imagePath.startsWith("/")) {
+            imagePath = imagePath.substring(1);
+        }
+        while (imagePath.endsWith("/")) {
+            imagePath = imagePath.substring(0, imagePath.length() - 1);
+        }
+
+        // 澶勭悊鍙嶆枩鏉狅細灏嗗弽鏂滄潬鏇挎崲涓烘鏂滄潬
+        imagePath = imagePath.replace("\\", "/");
+
+        // 绉婚櫎璺緞涓彲鑳界殑閲嶅鏂滄潬
+        imagePath = imagePath.replaceAll("/+", "/");
+
+        // 纭繚鍥剧墖璺緞浠�/寮�澶�
+        if (!imagePath.startsWith("/")) {
+            imagePath = "/" + imagePath;
+        }
+
+        // 鏋勫缓瀹屾暣URL
+        String fullUrl = fileServerUrl + imagePath;
+
+        // 璁板綍璋冭瘯淇℃伅
+        System.out.println("鏋勫缓鍥剧墖URL - 閰嶇疆URL: " + fileServerUrl + ", 鍥剧墖璺緞: " + imagePath + ", 瀹屾暣URL: " + fullUrl);
+
+        return fullUrl;
+    }
+
+    /**
+     * 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     */
+    @PreAuthorize("@ss.hasPermi('hospital:imagedata:query')")
+    @GetMapping("/byServiceOrder/{serviceOrdID}")
+    public AjaxResult getByServiceOrder(@PathVariable("serviceOrdID") Long serviceOrdID) {
+        List<ImageData> list = imageDataService.selectImageDataBySOrdIDDt(serviceOrdID);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 鏍规嵁鍥剧墖绫诲瀷鏌ヨ鍥剧墖鏁版嵁
+     */
+    @PreAuthorize("@ss.hasPermi('hospital:imagedata:query')")
+    @GetMapping("/byType/{imageType}")
+    public AjaxResult getByType(@PathVariable("imageType") Integer imageType) {
+        List<ImageData> list = imageDataService.selectImageDataByType(imageType);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 鏍囪鍥剧墖涓哄垹闄ょ姸鎬�
+     */
+    @PreAuthorize("@ss.hasPermi('hospital:imagedata:remove')")
+    @Log(title = "鏍囪鍥剧墖鍒犻櫎", businessType = BusinessType.DELETE)
+    @PutMapping("/markDelete/{id}")
+    public AjaxResult markDelete(@PathVariable("id") Long id) {
+        return toAjax(imageDataService.markImageDataAsDeleted(id));
+    }
+
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝師ASP浠g爜杞崲锛�
+     */
+    @Log(title = "寰俊鍥剧墖涓婁紶", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadWxImage")
+    public AjaxResult uploadWxImage(@RequestBody WxImageUploadRequest request) {
+
+        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛ID
+        Integer adminId = getUserId().intValue();
+
+        String result = imageDataService.uploadWxImage(
+                request.getDispatchOrdID(),
+                request.getServiceOrdID(),
+                request.getOaid(),
+                request.getMediaId(),
+                request.getImageType(),
+                adminId
+        );
+
+        if (result.contains("鎴愬姛")) {
+            return success(result);
+        } else {
+            return error(result);
+        }
+    }
+
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝吋瀹瑰師鏈夊弬鏁版牸寮忥級
+     */
+    @Log(title = "寰俊鍥剧墖涓婁紶", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadWxImageForm")
+    public AjaxResult uploadWxImageForm(
+            @RequestParam(value = "DispatchOrdID", required = false) Long dispatchOrdID,
+            @RequestParam(value = "ServiceOrdID", required = false) Long serviceOrdID,
+            @RequestParam(value = "OAID", required = false) Integer oaid,
+            @RequestParam(value = "media_id", required = true) String mediaId,
+            @RequestParam(value = "ImageType", required = false) Integer imageType) {
+
+        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛ID
+        Integer adminId = getUserId().intValue();
+
+        String result = imageDataService.uploadWxImage(dispatchOrdID, serviceOrdID, oaid, mediaId, imageType, adminId);
+
+        if (result.contains("鎴愬姛")) {
+            return success(result);
+        } else {
+            return error(result);
+        }
+    }
+
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝畬鏁寸増鏈紝鍖呭惈鏂囦欢涓嬭浇鍜岀缉鐣ュ浘鐢熸垚锛�
+     */
+    @Log(title = "寰俊鍥剧墖涓婁紶瀹屾暣鐗�", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadWxImageWithDownload")
+    public AjaxResult uploadWxImageWithDownload(@RequestBody WxImageUploadRequest request) {
+
+        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛ID
+        Integer adminId = getUserId().intValue();
+
+        // 杩欓噷闇�瑕佷粠閰嶇疆鎴栬姹備腑鑾峰彇access_token
+        // 瀹為檯浣跨敤鏃跺簲璇ヤ粠寰俊閰嶇疆鎴栫紦瀛樹腑鑾峰彇
+        String accessToken = request.getAccessToken(); // 闇�瑕佸湪WxImageUploadRequest涓坊鍔犳瀛楁
+
+        if (accessToken == null || accessToken.isEmpty()) {
+            return error("缂哄皯寰俊璁块棶浠ょ墝");
+        }
+
+        String result = imageDataService.uploadWxImageWithDownload(
+                accessToken,
+                request.getMediaId(),
+                request.getDispatchOrdID(),
+                request.getOaid(),
+                request.getImageType(),
+                adminId
+        );
+
+        if (result.contains("鎴愬姛")) {
+            return success(result);
+        } else {
+            return error(result);
+        }
+    }
+
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝畬鏁寸増鏈紝鍏煎鍘熸湁鍙傛暟鏍煎紡锛�
+     */
+    @Log(title = "寰俊鍥剧墖涓婁紶瀹屾暣鐗�", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadWxImageWithDownloadForm")
+    public AjaxResult uploadWxImageWithDownloadForm(
+            @RequestParam(value = "access_token", required = true) String accessToken,
+            @RequestParam(value = "media_id", required = true) String mediaId,
+            @RequestParam(value = "DispatchOrdID", required = false) Long dispatchOrdID,
+            @RequestParam(value = "ServiceOrdID", required = false) Long serviceOrdID,
+            @RequestParam(value = "OAID", required = false) Integer oaid,
+            @RequestParam(value = "ImageType", required = false) Integer imageType) {
+
+        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛ID
+        Integer adminId = getUserId().intValue();
+
+        String result = imageDataService.uploadWxImageWithDownload(
+                accessToken, mediaId, dispatchOrdID, oaid, imageType, adminId);
+
+        if (result.contains("鎴愬姛")) {
+            return success(result);
+        } else {
+            return error(result);
+        }
+    }
+
+
+
+    /**
+     * 鐢熸垚缂╃暐鍥�
+     */
+    @Log(title = "鐢熸垚缂╃暐鍥�", businessType = BusinessType.OTHER)
+    @PostMapping("/createThumbnail")
+    public AjaxResult createThumbnail(
+            @RequestParam(value = "bigImgPath", required = true) String bigImgPath,
+            @RequestParam(value = "width", required = true) int width,
+            @RequestParam(value = "height", required = false, defaultValue = "0") int height,
+            @RequestParam(value = "smallImgPath", required = true) String smallImgPath) {
+
+        boolean result = imageDataService.createThumbnail(bigImgPath, width, height, smallImgPath);
+
+        if (result) {
+            return success("缂╃暐鍥剧敓鎴愭垚鍔�");
+        } else {
+            return error("缂╃暐鍥剧敓鎴愬け璐�");
+        }
+    }
+
+    /**
+     * 妫�鏌ユ枃浠跺吋瀹规��
+     */
+
+    @GetMapping("/checkCompatibility")
+    public AjaxResult checkFileCompatibility(@RequestParam("filePath") String filePath) {
+        try {
+            String result = imageDataService.checkFileCompatibility(filePath);
+            return AjaxResult.success("鍏煎鎬ф鏌ュ畬鎴�", result);
+        } catch (Exception e) {
+            return AjaxResult.error("鍏煎鎬ф鏌ュけ璐ワ細" + e.getMessage());
+        }
+    }
+
+    /**
+     * 楠岃瘉URL鏍煎紡鏄惁涓庢棫绯荤粺鍏煎
+     */
+    @GetMapping("/checkUrlCompatibility")
+    public AjaxResult checkUrlCompatibility(@RequestParam("url") String url) {
+        try {
+            boolean isCompatible = imageDataService.isUrlCompatible(url);
+            return AjaxResult.success("URL鍏煎鎬ф鏌ュ畬鎴�", isCompatible);
+        } catch (Exception e) {
+            return AjaxResult.error("URL鍏煎鎬ф鏌ュけ璐ワ細" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鐢熸垚涓庢棫绯荤粺鍏煎鐨勬枃浠惰矾寰�
+     */
+
+    @GetMapping("/generateCompatibleFilePath")
+    public AjaxResult generateCompatibleFilePath(@RequestParam("dispatchOrdID") Long dispatchOrdID,
+                                                 @RequestParam("mediaId") String mediaId,
+                                                 @RequestParam(value = "isThumbnail", defaultValue = "false") boolean isThumbnail) {
+        try {
+            String filePath = imageDataService.generateCompatibleFilePath(dispatchOrdID, mediaId, isThumbnail);
+            return AjaxResult.success("鐢熸垚鍏煎鏂囦欢璺緞鎴愬姛", filePath);
+        } catch (Exception e) {
+            return AjaxResult.error("鐢熸垚鍏煎鏂囦欢璺緞澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鐢熸垚涓庢棫绯荤粺鍏煎鐨勮闂甎RL
+     */
+
+    @GetMapping("/generateCompatibleUrl")
+    public AjaxResult generateCompatibleUrl(@RequestParam("dispatchOrdID") Long dispatchOrdID,
+                                            @RequestParam("mediaId") String mediaId,
+                                            @RequestParam(value = "isThumbnail", defaultValue = "false") boolean isThumbnail) {
+        try {
+            String url = imageDataService.generateCompatibleUrl(dispatchOrdID, mediaId, isThumbnail);
+            return AjaxResult.success("鐢熸垚鍏煎URL鎴愬姛", url);
+        } catch (Exception e) {
+            return AjaxResult.error("鐢熸垚鍏煎URL澶辫触锛�" + e.getMessage());
+        }
+    }
+
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛堝畬鏁寸増鏈級
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageUrl 鍥剧墖URL
+     * @param thumbnailUrl 缂╃暐鍥綰RL
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 澶勭悊缁撴灉
+     */
+    @PreAuthorize("@ss.hasPermi('hospital:imagedata:add')")
+    @Log(title = "鍥剧墖URL涓婁紶", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadByUrl")
+    public AjaxResult uploadImageByUrl(@RequestParam(value = "dispatchOrdID", required = false) Long dispatchOrdID,
+                                       @RequestParam(value = "serviceOrdID", required = false) Long serviceOrdID,
+                                       @RequestParam(value = "oaid", required = false) Integer oaid,
+                                       @RequestParam("imageUrl") String imageUrl,
+                                       @RequestParam(value = "thumbnailUrl", required = false) String thumbnailUrl,
+                                       @RequestParam(value = "imageType", defaultValue = "0") Integer imageType) {
+        try {
+            // 鑾峰彇褰撳墠绠$悊鍛業D
+            Integer adminId = getUserId().intValue();
+
+            // 璋冪敤鍥剧墖鏁版嵁鏈嶅姟澶勭悊涓婁紶
+            String result = imageDataService.uploadImageByUrl(dispatchOrdID, serviceOrdID, oaid,
+                    imageUrl, thumbnailUrl, imageType, adminId);
+
+            if (result.contains("鎴愬姛")) {
+                return AjaxResult.success("鍥剧墖URL涓婁紶鎴愬姛", result);
+            } else {
+                return AjaxResult.error(result);
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鍥剧墖URL涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛堢畝鍖栫増鏈級
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageUrl 鍥剧墖URL
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 澶勭悊缁撴灉
+     */
+    @Log(title = "鍥剧墖URL涓婁紶绠�鍖栫増", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadByUrlSimple")
+    public AjaxResult uploadImageByUrlSimple(@RequestParam(value = "dispatchOrdID", required = false) Long dispatchOrdID,
+                                             @RequestParam(value = "serviceOrdID", required = false) Long serviceOrdID,
+                                             @RequestParam(value = "oaid", required = false) Integer oaid,
+                                             @RequestParam("imageUrl") String imageUrl,
+                                             @RequestParam(value = "imageType", defaultValue = "0") Integer imageType) {
+        try {
+            // 鑾峰彇褰撳墠绠$悊鍛業D
+            Integer adminId = getUserId().intValue();
+
+            // 璋冪敤鍥剧墖鏁版嵁鏈嶅姟澶勭悊涓婁紶锛堢畝鍖栫増锛�
+            String result = imageDataService.uploadImageByUrlSimple(dispatchOrdID, serviceOrdID, oaid,
+                    imageUrl, imageType, adminId);
+
+            if (result.contains("鎴愬姛")) {
+                return AjaxResult.success("鍥剧墖URL涓婁紶鎴愬姛", result);
+            } else {
+                return AjaxResult.error(result);
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鍥剧墖URL涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛圝SON鏍煎紡锛�
+     *
+     * @param requestBody 璇锋眰浣�
+     * @return 澶勭悊缁撴灉
+     */
+    @PreAuthorize("@ss.hasPermi('hospital:imagedata:add')")
+    @Log(title = "鍥剧墖URL涓婁紶JSON", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadByUrlJson")
+    public AjaxResult uploadImageByUrlJson(@RequestBody ImageUrlUploadRequest requestBody) {
+        try {
+            // 鑾峰彇褰撳墠绠$悊鍛業D
+            Integer adminId = getUserId().intValue();
+
+            // 璋冪敤鍥剧墖鏁版嵁鏈嶅姟澶勭悊涓婁紶
+            String result = imageDataService.uploadImageByUrl(requestBody.getDispatchOrdID(),
+                    requestBody.getServiceOrdID(), requestBody.getOaid(), requestBody.getImageUrl(),
+                    requestBody.getThumbnailUrl(), requestBody.getImageType(), adminId);
+
+            if (result.contains("鎴愬姛")) {
+                return AjaxResult.success("鍥剧墖URL涓婁紶鎴愬姛", result);
+            } else {
+                return AjaxResult.error(result);
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鍥剧墖URL涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鍥剧墖URL涓婁紶璇锋眰瀵硅薄
+     */
+    public static class ImageUrlUploadRequest {
+
+        private Long dispatchOrdID;
+        private Long serviceOrdID;
+        private Integer oaid;
+        private String imageUrl;
+        private String thumbnailUrl;
+        private Integer imageType;
+
+        // getter鍜宻etter鏂规硶
+        public Long getDispatchOrdID() {
+            return dispatchOrdID;
+        }
+
+        public void setDispatchOrdID(Long dispatchOrdID) {
+            this.dispatchOrdID = dispatchOrdID;
+        }
+
+        public Long getServiceOrdID() {
+            return serviceOrdID;
+        }
+
+        public void setServiceOrdID(Long serviceOrdID) {
+            this.serviceOrdID = serviceOrdID;
+        }
+
+        public Integer getOaid() {
+            return oaid;
+        }
+
+        public void setOaid(Integer oaid) {
+            this.oaid = oaid;
+        }
+
+        public String getImageUrl() {
+            return imageUrl;
+        }
+
+        public void setImageUrl(String imageUrl) {
+            this.imageUrl = imageUrl;
+        }
+
+        public String getThumbnailUrl() {
+            return thumbnailUrl;
+        }
+
+        public void setThumbnailUrl(String thumbnailUrl) {
+            this.thumbnailUrl = thumbnailUrl;
+        }
+
+        public Integer getImageType() {
+            return imageType;
+        }
+
+        public void setImageType(Integer imageType) {
+            this.imageType = imageType;
+        }
+    }
+
+    /**
+     * 鍥剧墖鏂囦欢涓婁紶鎺ュ彛
+     *
+     * @param file 涓婁紶鐨勫浘鐗囨枃浠�
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 澶勭悊缁撴灉
+     */
+//    @PreAuthorize("@ss.hasPermi('hospital:imagedata:add')")
+    @Anonymous()
+    @Log(title = "鍥剧墖鏂囦欢涓婁紶", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadFile")
+    public AjaxResult uploadImageFile(@RequestParam("file") MultipartFile file,
+                                      @RequestParam(value = "dispatchOrdID", required = false) Long dispatchOrdID,
+                                      @RequestParam(value = "serviceOrdID", required = false) Long serviceOrdID,
+                                      @RequestParam(value = "imageType", defaultValue = "0", required = true) Integer imageType,
+                                      @RequestParam(value = "adminId", defaultValue = "0", required = false) Integer adminId) {
+        try {
+
+            adminId = getUserId().intValue();
+
+            // 楠岃瘉鏂囦欢
+            if (file.isEmpty()) {
+                return AjaxResult.error("璇烽�夋嫨瑕佷笂浼犵殑鍥剧墖鏂囦欢");
+            }
+
+            // 楠岃瘉鏂囦欢绫诲瀷
+            String originalFilename = file.getOriginalFilename();
+            if (originalFilename == null || !isValidImageFile(originalFilename)) {
+                return AjaxResult.error("鍙敮鎸佷笂浼犲浘鐗囨枃浠讹紙jpg銆乯peg銆乸ng銆乬if銆乥mp锛�");
+            }
+
+            // 鐢熸垚鐩爣璺緞锛堜娇鐢ㄥ勾鏈堢洰褰曠粨鏋勶級
+            String yearMonth = DateUtils.datePath();
+            String targetPath = dispatchOrdID.toString();
+            //鍦ㄧ粨鏋滃彟杩斿洖 fileUrl,thumbnailUrl,鍙妋ediaid
+            // 浣跨敤鏂囦欢涓婁紶鏈嶅姟淇濆瓨鍒版枃浠舵湇鍔″櫒锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+            FileUploadResponse uploadResponse = fileUploadService.uploadMultipartFileWithThumbnail(file, targetPath);
+
+            // 娣诲姞璋冭瘯淇℃伅
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 鎴愬姛: " + uploadResponse.isSuccess());
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 娑堟伅: " + uploadResponse.getMessage());
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 鏂囦欢璺緞: " + uploadResponse.getFilePath());
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 缂╃暐鍥捐矾寰�: " + uploadResponse.getThumbnailPath());
+
+            if (!uploadResponse.isSuccess()) {
+                return AjaxResult.error("鏂囦欢涓婁紶澶辫触锛�" + uploadResponse.getMessage());
+            }
+
+            // 鍒涘缓鍥剧墖鏁版嵁瀵硅薄
+            ImageData imageData = new ImageData();
+            imageData.setDOrdIDDt(dispatchOrdID);
+            imageData.setSOrdIDDt(serviceOrdID);
+            imageData.setImageType(imageType);
+            imageData.setImageUrl(uploadResponse.getFilePath());
+            imageData.setImageUrls(uploadResponse.getThumbnailPath()); // 缂╃暐鍥捐矾寰�
+            imageData.setUpImageTime(new Date());
+            imageData.setUpImageOAid(adminId);
+            imageData.setImageDel(0);
+
+            // 鎻掑叆鏁版嵁搴�
+            int result = imageDataService.insertImageData(imageData);
+
+            if (result > 0) {
+                // 鏍规嵁鍥剧墖绫诲瀷杩涜鐗规畩澶勭悊
+                ImageTypeEnum imageTypeEnum = ImageTypeEnum.getByCode(imageType);
+
+
+                //杩斿洖鍏ㄨ矾寰�
+                //鍦ㄧ粨鏋滃彟杩斿洖 fileUrl,thumbnailUrl,鍙奿d
+                HashMap<String, String> map = new HashMap<>();
+                //鍔犱笂fileServerUrl
+                map.put("fileUrl", buildFullImageUrl(uploadResponse.getFilePath()));
+                map.put("thumbnailUrl", buildFullImageUrl(uploadResponse.getThumbnailPath()));
+                map.put("id", imageData.getId().toString());
+
+                return AjaxResult.success("鍥剧墖涓婁紶鎴愬姛", map);
+            } else {
+                return AjaxResult.error("鍥剧墖鏁版嵁淇濆瓨澶辫触");
+            }
+
+        } catch (Exception e) {
+            return AjaxResult.error("鍥剧墖涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+    @Anonymous()
+    @Log(title = "鍥剧墖鏂囦欢涓婁紶", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadFileBase64")
+    public AjaxResult uploadFileBase64(@RequestParam("fileContent") String fileContent,@RequestParam("filename") String filename,
+                                       @RequestParam(value = "dispatchOrdID", required = false) Long dispatchOrdID,
+                                       @RequestParam(value = "serviceOrdID", required = false) Long serviceOrdID,
+                                       @RequestParam(value = "imageType", defaultValue = "0", required = true) Integer imageType,
+                                       @RequestParam(value = "adminId", defaultValue = "0", required = false) Integer adminId) {
+        try {
+
+            if( adminId == 0)
+                adminId = getUserId().intValue();
+
+            InputStream stream= InputStreamBase64Converter.base64ToInputStream(fileContent);
+
+            // 鐢熸垚鐩爣璺緞锛堜娇鐢ㄥ勾鏈堢洰褰曠粨鏋勶級
+            String yearMonth = DateUtils.datePath();
+            String targetPath = dispatchOrdID.toString();
+            //鍦ㄧ粨鏋滃彟杩斿洖 fileUrl,thumbnailUrl,鍙妋ediaid
+            // 浣跨敤鏂囦欢涓婁紶鏈嶅姟淇濆瓨鍒版枃浠舵湇鍔″櫒锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+            FileUploadResponse uploadResponse = fileUploadService.uploadInputStream(stream,filename, targetPath);
+
+            // 娣诲姞璋冭瘯淇℃伅
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 鎴愬姛: " + uploadResponse.isSuccess());
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 娑堟伅: " + uploadResponse.getMessage());
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 鏂囦欢璺緞: " + uploadResponse.getFilePath());
+            System.out.println("鏂囦欢涓婁紶鍝嶅簲 - 缂╃暐鍥捐矾寰�: " + uploadResponse.getThumbnailPath());
+
+            if (!uploadResponse.isSuccess()) {
+                return AjaxResult.error("鏂囦欢涓婁紶澶辫触锛�" + uploadResponse.getMessage());
+            }
+
+            // 鍒涘缓鍥剧墖鏁版嵁瀵硅薄
+            ImageData imageData = new ImageData();
+            imageData.setDOrdIDDt(dispatchOrdID);
+            imageData.setSOrdIDDt(serviceOrdID);
+            imageData.setImageType(imageType);
+            imageData.setImageUrl(uploadResponse.getFilePath());
+            imageData.setImageUrls(uploadResponse.getThumbnailPath()); // 缂╃暐鍥捐矾寰�
+            imageData.setUpImageTime(new Date());
+            imageData.setUpImageOAid(adminId);
+            imageData.setImageDel(0);
+
+            // 鎻掑叆鏁版嵁搴�
+            int result = imageDataService.insertImageData(imageData);
+
+            if (result > 0) {
+                // 鏍规嵁鍥剧墖绫诲瀷杩涜鐗规畩澶勭悊
+                ImageTypeEnum imageTypeEnum = ImageTypeEnum.getByCode(imageType);
+
+
+                //杩斿洖鍏ㄨ矾寰�
+                //鍦ㄧ粨鏋滃彟杩斿洖 fileUrl,thumbnailUrl,鍙奿d
+                HashMap<String, String> map = new HashMap<>();
+                //鍔犱笂fileServerUrl
+                map.put("fileUrl", buildFullImageUrl(uploadResponse.getFilePath()));
+                map.put("thumbnailUrl", buildFullImageUrl(uploadResponse.getThumbnailPath()));
+                map.put("id", imageData.getId().toString());
+
+                return AjaxResult.success("鍥剧墖涓婁紶鎴愬姛", map);
+            } else {
+                return AjaxResult.error("鍥剧墖鏁版嵁淇濆瓨澶辫触");
+            }
+
+        } catch (Exception e) {
+            return AjaxResult.error("鍥剧墖涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 寰俊灏忕▼搴忎笓鐢ㄥ浘鐗囨枃浠朵笂浼犳帴鍙�
+     * 鏀寔寰俊灏忕▼搴忕殑 wx.uploadFile API
+     *
+     * @param request HttpServletRequest 璇锋眰瀵硅薄
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    @Anonymous()
+    @Log(title = "寰俊灏忕▼搴忓浘鐗囦笂浼�", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadWxFile")
+    public AjaxResult uploadWxFile(HttpServletRequest request,
+                                   @RequestParam(value = "dispatchOrdID", required = false) Long dispatchOrdID,
+                                   @RequestParam(value = "serviceOrdID", required = false) Long serviceOrdID,
+                                   @RequestParam(value = "imageType", defaultValue = "0", required = true) Integer imageType,
+                                   @RequestParam(value = "adminId", defaultValue = "0", required = false) Integer adminId) {
+        try {
+            adminId = getUserId().intValue();
+
+            // 鑾峰彇鏂囦欢鍙傛暟 - 寰俊灏忕▼搴忎笓鐢�
+            MultipartFile file = null;
+
+            // 妫�鏌ユ槸鍚︿负 multipart 璇锋眰
+            if (request instanceof MultipartHttpServletRequest) {
+                MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+
+                // 寰俊灏忕▼搴忛�氬父浣跨敤 "file" 浣滀负鏂囦欢鍙傛暟鍚�
+                file = multipartRequest.getFile("file");
+
+                // 濡傛灉娌℃壘鍒帮紝灏濊瘯鍏朵粬鍙兘鐨勫弬鏁板悕
+                if (file == null || file.isEmpty()) {
+                    String[] possibleFileParams = {"image", "photo", "upload"};
+                    for (String paramName : possibleFileParams) {
+                        file = multipartRequest.getFile(paramName);
+                        if (file != null && !file.isEmpty()) {
+                            break;
+                        }
+                    }
+                }
+
+                // 濡傛灉杩樻槸娌℃壘鍒版枃浠讹紝鑾峰彇绗竴涓枃浠�
+                if (file == null || file.isEmpty()) {
+                    Iterator<String> fileNames = multipartRequest.getFileNames();
+                    if (fileNames.hasNext()) {
+                        file = multipartRequest.getFile(fileNames.next());
+                    }
+                }
+            }
+
+            // 楠岃瘉鏂囦欢
+            if (file == null || file.isEmpty()) {
+                return AjaxResult.error("璇烽�夋嫨瑕佷笂浼犵殑鍥剧墖鏂囦欢");
+            }
+
+            // 楠岃瘉鏂囦欢绫诲瀷
+            String originalFilename = file.getOriginalFilename();
+            if (originalFilename == null || !isValidImageFile(originalFilename)) {
+                return AjaxResult.error("鍙敮鎸佷笂浼犲浘鐗囨枃浠讹紙jpg銆乯peg銆乸ng銆乬if銆乥mp锛�");
+            }
+
+            // 鐢熸垚鐩爣璺緞
+            String targetPath = dispatchOrdID != null ? dispatchOrdID.toString() : "default";
+
+            // 浣跨敤鏂囦欢涓婁紶鏈嶅姟淇濆瓨鍒版枃浠舵湇鍔″櫒锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+            FileUploadResponse uploadResponse = fileUploadService.uploadMultipartFileWithThumbnail(file, targetPath);
+
+            // 娣诲姞璋冭瘯淇℃伅
+            System.out.println("寰俊灏忕▼搴忔枃浠朵笂浼犲搷搴� - 鎴愬姛: " + uploadResponse.isSuccess());
+            System.out.println("寰俊灏忕▼搴忔枃浠朵笂浼犲搷搴� - 娑堟伅: " + uploadResponse.getMessage());
+            System.out.println("寰俊灏忕▼搴忔枃浠朵笂浼犲搷搴� - 鏂囦欢璺緞: " + uploadResponse.getFilePath());
+            System.out.println("寰俊灏忕▼搴忔枃浠朵笂浼犲搷搴� - 缂╃暐鍥捐矾寰�: " + uploadResponse.getThumbnailPath());
+
+            if (!uploadResponse.isSuccess()) {
+                return AjaxResult.error("鏂囦欢涓婁紶澶辫触锛�" + uploadResponse.getMessage());
+            }
+
+            // 鍒涘缓鍥剧墖鏁版嵁瀵硅薄
+            ImageData imageData = new ImageData();
+            imageData.setDOrdIDDt(dispatchOrdID);
+            imageData.setSOrdIDDt(serviceOrdID);
+            imageData.setImageType(imageType);
+            imageData.setImageUrl(uploadResponse.getFilePath());
+            imageData.setImageUrls(uploadResponse.getThumbnailPath()); // 缂╃暐鍥捐矾寰�
+            imageData.setUpImageTime(new Date());
+            imageData.setUpImageOAid(adminId);
+            imageData.setImageDel(0);
+
+            // 鎻掑叆鏁版嵁搴�
+            int result = imageDataService.insertImageData(imageData);
+
+            if (result > 0) {
+                // 鏍规嵁鍥剧墖绫诲瀷杩涜鐗规畩澶勭悊
+                ImageTypeEnum imageTypeEnum = ImageTypeEnum.getByCode(imageType);
+
+
+
+                // 杩斿洖寰俊灏忕▼搴忛渶瑕佺殑鏍煎紡
+                HashMap<String, Object> map = new HashMap<>();
+                map.put("fileUrl", buildFullImageUrl(uploadResponse.getFilePath()));
+                map.put("thumbnailUrl", buildFullImageUrl(uploadResponse.getThumbnailPath()));
+                map.put("id", imageData.getId());
+                map.put("success", true);
+                map.put("message", "鍥剧墖涓婁紶鎴愬姛");
+
+                return AjaxResult.success("鍥剧墖涓婁紶鎴愬姛", map);
+            } else {
+                return AjaxResult.error("鍥剧墖鏁版嵁淇濆瓨澶辫触");
+            }
+
+        } catch (Exception e) {
+            log.error("寰俊灏忕▼搴忓浘鐗囦笂浼犲け璐�", e);
+            return AjaxResult.error("鍥剧墖涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 寰俊灏忕▼搴廈ase64鍥剧墖涓婁紶鎺ュ彛
+     * 鏀寔寰俊灏忕▼搴忓皢鍥剧墖杞崲涓築ase64鍚庝笂浼�
+     *
+     * @param fileContent Base64缂栫爜鐨勫浘鐗囧唴瀹�
+     * @param filename 鏂囦欢鍚�
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    @Anonymous()
+    @Log(title = "寰俊灏忕▼搴廈ase64鍥剧墖涓婁紶", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadWxBase64")
+    public AjaxResult uploadWxBase64(@RequestParam("fileContent") String fileContent,
+                                     @RequestParam("filename") String filename,
+                                     @RequestParam(value = "dispatchOrdID", required = false) Long dispatchOrdID,
+                                     @RequestParam(value = "serviceOrdID", required = false) Long serviceOrdID,
+                                     @RequestParam(value = "imageType", defaultValue = "0", required = true) Integer imageType,
+                                     @RequestParam(value = "adminId", defaultValue = "0", required = false) Integer adminId) {
+        try {
+            if (adminId == 0) {
+                adminId = getUserId().intValue();
+            }
+
+            // 楠岃瘉Base64鍐呭
+            if (fileContent == null || fileContent.trim().isEmpty()) {
+                return AjaxResult.error("鍥剧墖鍐呭涓嶈兘涓虹┖");
+            }
+
+            // 楠岃瘉鏂囦欢绫诲瀷
+            if (filename == null || !isValidImageFile(filename)) {
+                return AjaxResult.error("鍙敮鎸佷笂浼犲浘鐗囨枃浠讹紙jpg銆乯peg銆乸ng銆乬if銆乥mp锛�");
+            }
+
+            // 灏咮ase64杞崲涓篒nputStream
+            InputStream stream = InputStreamBase64Converter.base64ToInputStream(fileContent);
+
+            // 鐢熸垚鐩爣璺緞
+            String targetPath = dispatchOrdID != null ? dispatchOrdID.toString() : "default";
+
+            // 浣跨敤鏂囦欢涓婁紶鏈嶅姟淇濆瓨鍒版枃浠舵湇鍔″櫒
+            FileUploadResponse uploadResponse = fileUploadService.uploadInputStream(stream, filename, targetPath);
+
+            // 娣诲姞璋冭瘯淇℃伅
+            System.out.println("寰俊灏忕▼搴廈ase64涓婁紶鍝嶅簲 - 鎴愬姛: " + uploadResponse.isSuccess());
+            System.out.println("寰俊灏忕▼搴廈ase64涓婁紶鍝嶅簲 - 娑堟伅: " + uploadResponse.getMessage());
+            System.out.println("寰俊灏忕▼搴廈ase64涓婁紶鍝嶅簲 - 鏂囦欢璺緞: " + uploadResponse.getFilePath());
+            System.out.println("寰俊灏忕▼搴廈ase64涓婁紶鍝嶅簲 - 缂╃暐鍥捐矾寰�: " + uploadResponse.getThumbnailPath());
+
+            if (!uploadResponse.isSuccess()) {
+                return AjaxResult.error("鏂囦欢涓婁紶澶辫触锛�" + uploadResponse.getMessage());
+            }
+
+            // 鍒涘缓鍥剧墖鏁版嵁瀵硅薄
+            ImageData imageData = new ImageData();
+            imageData.setDOrdIDDt(dispatchOrdID);
+            imageData.setSOrdIDDt(serviceOrdID);
+            imageData.setImageType(imageType);
+            imageData.setImageUrl(uploadResponse.getFilePath());
+            imageData.setImageUrls(uploadResponse.getThumbnailPath()); // 缂╃暐鍥捐矾寰�
+            imageData.setUpImageTime(new Date());
+            imageData.setUpImageOAid(adminId);
+            imageData.setImageDel(0);
+
+            // 鎻掑叆鏁版嵁搴�
+            int result = imageDataService.insertImageData(imageData);
+
+            if (result > 0) {
+                // 鏍规嵁鍥剧墖绫诲瀷杩涜鐗规畩澶勭悊
+                ImageTypeEnum imageTypeEnum = ImageTypeEnum.getByCode(imageType);
+
+
+
+                // 杩斿洖寰俊灏忕▼搴忛渶瑕佺殑鏍煎紡
+                HashMap<String, Object> map = new HashMap<>();
+                map.put("fileUrl", buildFullImageUrl(uploadResponse.getFilePath()));
+                map.put("thumbnailUrl", buildFullImageUrl(uploadResponse.getThumbnailPath()));
+                map.put("id", imageData.getId());
+                map.put("success", true);
+                map.put("message", "鍥剧墖涓婁紶鎴愬姛");
+
+                return AjaxResult.success("鍥剧墖涓婁紶鎴愬姛", map);
+            } else {
+                return AjaxResult.error("鍥剧墖鏁版嵁淇濆瓨澶辫触");
+            }
+
+        } catch (Exception e) {
+            log.error("寰俊灏忕▼搴廈ase64鍥剧墖涓婁紶澶辫触", e);
+            return AjaxResult.error("鍥剧墖涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 楠岃瘉鏄惁涓烘湁鏁堢殑鍥剧墖鏂囦欢
+     */
+    private boolean isValidImageFile(String filename) {
+        String[] allowedExtensions = {".jpg", ".jpeg", ".png", ".gif", ".bmp"};
+        String lowerFilename = filename.toLowerCase();
+        for (String ext : allowedExtensions) {
+            if (lowerFilename.endsWith(ext)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢鎵╁睍鍚�
+     */
+    private String getFileExtension(String filename) {
+        int lastDotIndex = filename.lastIndexOf('.');
+        if (lastDotIndex > 0) {
+            return filename.substring(lastDotIndex + 1);
+        }
+        return "jpg"; // 榛樿鎵╁睍鍚�
+    }
+
+    /**
+     * 鑾峰彇涓婁紶璺緞
+     */
+    private String getUploadPath() {
+        // 杩欓噷鍙互鏍规嵁瀹為檯閰嶇疆杩斿洖涓婁紶璺緞
+        // 鍙互浠庨厤缃枃浠朵腑璇诲彇鎴栦娇鐢ㄩ粯璁よ矾寰�
+        return System.getProperty("user.dir") + "/upload";
+    }
+
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java
index b12fa9e..d9e5490 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java
@@ -1,8 +1,13 @@
 package com.ruoyi.web.controller.task;
 
 import java.util.List;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.OutputStream;
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.common.utils.WechatUtils;
+import com.ruoyi.common.config.WechatConfig;
 import com.ruoyi.system.domain.SysTask;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +38,9 @@
     
     @Autowired
     private ISysTaskService sysTaskService;
+    
+    @Autowired
+    private WechatConfig wechatConfig;
 
     /**
      * 鏌ヨ浠诲姟闄勪欢鍒楄〃
@@ -50,9 +58,11 @@
     @PreAuthorize("@ss.hasPermi('task:general:edit')")
     @Log(title = "浠诲姟闄勪欢", businessType = BusinessType.INSERT)
     @PostMapping("/upload/{taskId}")
-    public AjaxResult upload(@PathVariable("taskId") Long taskId, @RequestParam("file") MultipartFile file) {
+    public AjaxResult upload(@PathVariable("taskId") Long taskId, 
+                            @RequestParam("file") MultipartFile file,
+                            @RequestParam(value = "category", required = false) String category) {
         try {
-            int result = sysTaskService.uploadAttachment(taskId, file);
+            int result = sysTaskService.uploadAttachment(taskId, file, category);
             if (result > 0) {
                 return success("涓婁紶鎴愬姛");
             } else {
@@ -81,4 +91,74 @@
             return error("鍒犻櫎澶辫触锛�" + e.getMessage());
         }
     }
+    
+    /**
+     * 浠庡井淇ediaId涓婁紶闄勪欢锛堝井淇″皬绋嬪簭涓撶敤锛�
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:edit')")
+    @Log(title = "浠诲姟闄勪欢", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadFromWechat/{taskId}")
+    public AjaxResult uploadFromWechat(@PathVariable("taskId") Long taskId,
+                                       @RequestParam("mediaId") String mediaId,
+                                       @RequestParam(value = "category", required = false) String category) {
+        try {
+            // 鑾峰彇寰俊AccessToken
+            String accessToken = WechatUtils.getAccessToken(
+                wechatConfig.getAppId(), 
+                wechatConfig.getAppSecret()
+            );
+            if (accessToken == null || accessToken.isEmpty()) {
+                return error("鑾峰彇寰俊AccessToken澶辫触");
+            }
+            
+            // 閫氳繃mediaId涓婁紶闄勪欢
+            int result = sysTaskService.uploadAttachmentFromWechat(taskId, accessToken, mediaId, category);
+            if (result > 0) {
+                return success("涓婁紶鎴愬姛");
+            } else {
+                return error("涓婁紶澶辫触");
+            }
+        } catch (Exception e) {
+            return error("涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 涓嬭浇闄勪欢
+     */
+    @GetMapping("/download/{attachmentId}")
+    public void downloadAttachment(@PathVariable("attachmentId") Long attachmentId, HttpServletResponse response) {
+        try {
+            SysTaskAttachment attachment = sysTaskService.getAttachmentById(attachmentId);
+            if (attachment == null) {
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+            
+            File file = new File(attachment.getFilePath());
+            if (!file.exists()) {
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+            
+            // 璁剧疆鍝嶅簲澶�
+            response.setContentType("application/octet-stream");
+            response.setHeader("Content-Disposition", "attachment; filename=" + attachment.getFileName());
+            response.setContentLengthLong(file.length());
+            
+            // 璇诲彇鏂囦欢骞惰緭鍑�
+            try (FileInputStream fis = new FileInputStream(file);
+                 OutputStream os = response.getOutputStream()) {
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = fis.read(buffer)) != -1) {
+                    os.write(buffer, 0, bytesRead);
+                }
+                os.flush();
+            }
+        } catch (Exception e) {
+            logger.error("涓嬭浇闄勪欢澶辫触", e);
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+        }
+    }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wechat/WechatController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wechat/WechatController.java
new file mode 100644
index 0000000..d5b8c99
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wechat/WechatController.java
@@ -0,0 +1,42 @@
+package com.ruoyi.web.controller.wechat;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.config.WechatConfig;
+import com.ruoyi.common.utils.WechatUtils;
+
+/**
+ * 寰俊鎺ュ彛Controller
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/wechat")
+public class WechatController extends BaseController {
+    
+    @Autowired
+    private WechatConfig wechatConfig;
+    
+    /**
+     * 鑾峰彇寰俊AccessToken
+     */
+    @GetMapping("/accessToken")
+    public AjaxResult getAccessToken() {
+        try {
+            String accessToken = WechatUtils.getAccessToken(
+                wechatConfig.getAppId(), 
+                wechatConfig.getAppSecret()
+            );
+            if (accessToken == null || accessToken.isEmpty()) {
+                return error("鑾峰彇寰俊AccessToken澶辫触");
+            }
+            return success(accessToken);
+        } catch (Exception e) {
+            return error("鑾峰彇寰俊AccessToken寮傚父锛�" + e.getMessage());
+        }
+    }
+}
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index 735283f..8c0477f 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -97,6 +97,10 @@
     # 鏃х郴缁熷熀纭�URL (蹇呴』閰嶇疆)
     # 绀轰緥: http://192.168.1.100:8080 鎴� http://legacy.yourdomain.com
     base-url: http://120.25.98.119:8083
+    # 鏂囦欢涓婁紶URL
+    fileUploadUrl: http://120.25.98.119:8083/weixin/upload_file.php
+    # 鏂囦欢涓嬭浇URL
+    fileServerUrl: http://120.25.98.119:8083
     
     # 鎬ユ晳杞繍鍒涘缓鎺ュ彛璺緞 (鍙�夛紝榛樿鍊煎涓�)
     emergency-create-path: /admin_save_19.gds
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index bd5fb75..18f8574 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -56,7 +56,7 @@
     basename: i18n/messages
   profiles:
     # 鐜 dev|test|prod
-    active: prod
+    active: dev
   # 鏂囦欢涓婁紶
   servlet:
     multipart:
@@ -146,11 +146,14 @@
   apiUrl: http://120.25.98.119:8084/v1/   #娴嬭瘯鐜锛歭ocalhost:8011
 
 # 寰俊閰嶇疆
-wechat:
+evaluationWechat:
   appId: wx70f6a7346ee842c0
   appSecret: 2d6c59de85e876b7eadebeba62e5417a
   redirectUri: http://yourdomain.com/evaluation
-
+# 璋冨害鐢ㄧ殑weixin閰嶇疆
+transferConfigWeixin:
+  appId: wx40692cc44953a8cb
+  appSecret: 9638b7d8bb988e4daaac7ac35457f296
 # 鑵捐鍦板浘閰嶇疆
 tencent:
   map:
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java
index 5038fe6..02ef3e2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java
@@ -24,6 +24,10 @@
     /** 浠诲姟鐘舵�佹煡璇㈡帴鍙h矾寰勶紙宸插純鐢紝鐩存帴鏌ヨSQL Server鏁版嵁搴擄級 */
     @Deprecated
     private String statusQueryPath = "/task_status_query.asp";
+
+    private String fileUploadUrl;
+
+    private String fileServerUrl;
     
     /** 杩炴帴瓒呮椂鏃堕棿(姣) */
     private int connectTimeout = 30000;
@@ -41,6 +45,21 @@
         return baseUrl;
     }
 
+    public String getFileUploadUrl(){
+        return fileUploadUrl;
+    }
+
+    public void setFileUploadUrl(String fileUploadUrl){
+        this.fileUploadUrl = fileUploadUrl;
+    }
+
+    public String getFileServerUrl(){
+        return fileServerUrl;
+    }
+
+    public void setFileServerUrl(String fileServerUrl){
+        this.fileServerUrl = fileServerUrl;
+        }
     public void setBaseUrl(String baseUrl) {
         this.baseUrl = baseUrl;
     }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/WechatConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/WechatConfig.java
new file mode 100644
index 0000000..b60bb7a
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/WechatConfig.java
@@ -0,0 +1,37 @@
+package com.ruoyi.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 寰俊灏忕▼搴忛厤缃被锛堢敤浜庨檮浠朵笂浼犵瓑灏忕▼搴忓姛鑳斤級
+ * 閰嶇疆鏉ユ簮锛歵ransferConfig.weixin
+ * 
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "transfer-config-weixin")
+public class WechatConfig {
+    
+    /** 寰俊灏忕▼搴廇ppID */
+    private String appId;
+    
+    /** 寰俊灏忕▼搴廇ppSecret */
+    private String appSecret;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getAppSecret() {
+        return appSecret;
+    }
+
+    public void setAppSecret(String appSecret) {
+        this.appSecret = appSecret;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/WechatMpConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/WechatMpConfig.java
new file mode 100644
index 0000000..2a3c209
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/WechatMpConfig.java
@@ -0,0 +1,47 @@
+package com.ruoyi.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 寰俊鍏紬鍙烽厤缃被锛堢敤浜庣綉椤垫巿鏉冦�佽瘎浠风瓑鍏紬鍙峰姛鑳斤級
+ * 
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "evaluation-wechat")
+public class WechatMpConfig {
+    
+    /** 寰俊鍏紬鍙稟ppID */
+    private String appId;
+    
+    /** 寰俊鍏紬鍙稟ppSecret */
+    private String appSecret;
+    
+    /** 寰俊鎺堟潈鍥炶皟鍦板潃 */
+    private String redirectUri;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getAppSecret() {
+        return appSecret;
+    }
+
+    public void setAppSecret(String appSecret) {
+        this.appSecret = appSecret;
+    }
+
+    public String getRedirectUri() {
+        return redirectUri;
+    }
+
+    public void setRedirectUri(String redirectUri) {
+        this.redirectUri = redirectUri;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/InputStreamBase64Converter.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/InputStreamBase64Converter.java
new file mode 100644
index 0000000..88a1591
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/InputStreamBase64Converter.java
@@ -0,0 +1,35 @@
+package com.ruoyi.common.utils;
+
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Base64;
+
+public class InputStreamBase64Converter {
+
+    /**
+     * 灏咺nputStream杞崲涓築ase64瀛楃涓�
+     */
+    public static String inputStreamToBase64(InputStream inputStream) throws Exception {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        byte[] buffer = new byte[4096];
+        int bytesRead;
+
+        while ((bytesRead = inputStream.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, bytesRead);
+        }
+
+        byte[] bytes = outputStream.toByteArray();
+        return Base64.getEncoder().encodeToString(bytes);
+    }
+
+    /**
+     * 灏咮ase64瀛楃涓茶浆鎹㈠洖InputStream
+     */
+    public static InputStream base64ToInputStream(String base64String) {
+        byte[] bytes = Base64.getDecoder().decode(base64String);
+        return new ByteArrayInputStream(bytes);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
index feb555a..1094430 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -1,16 +1,10 @@
 package com.ruoyi.common.utils.http;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.net.ConnectException;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.net.URLConnection;
+import java.io.*;
+import java.net.*;
 import java.nio.charset.StandardCharsets;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
@@ -33,6 +27,43 @@
     private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
 
     public static final int DEFAULT_READ_TIMEOUT = 60000;
+    private static final String BOUNDARY_PREFIX = "----WebKitFormBoundary";
+    private static final String LINE_END = "\r\n";
+    private static final String TWO_HYPHENS = "--";
+
+
+    /**
+     * 鐢熸垚鍞竴鐨刡oundary
+     */
+    private static String generateBoundary() {
+        return BOUNDARY_PREFIX + System.currentTimeMillis();
+    }
+
+    /**
+     * 鏍规嵁鏂囦欢鍚嶈幏鍙朇ontent-Type
+     */
+    private static String getContentType(String fileName) {
+        if (fileName == null) {
+            return "application/octet-stream";
+        }
+
+        String extension = fileName.toLowerCase();
+        if (extension.endsWith(".jpg") || extension.endsWith(".jpeg")) {
+            return "image/jpeg";
+        } else if (extension.endsWith(".png")) {
+            return "image/png";
+        } else if (extension.endsWith(".gif")) {
+            return "image/gif";
+        } else if (extension.endsWith(".pdf")) {
+            return "application/pdf";
+        } else if (extension.endsWith(".doc")) {
+            return "application/msword";
+        } else if (extension.endsWith(".docx")) {
+            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+        } else {
+            return "application/octet-stream";
+        }
+    }
 
     /**
      * 鍚戞寚瀹� URL 鍙戦�丟ET鏂规硶鐨勮姹�
@@ -299,4 +330,138 @@
             return true;
         }
     }
+
+    /**
+     * 鍙戦�佹枃浠朵笂浼犺姹�
+     *
+     * @param url 璇锋眰URL
+     * @param params 璇锋眰鍙傛暟锛堝寘鍚枃浠舵祦锛�
+     * @return 鍝嶅簲鍐呭
+     */
+    public static String postFile(String url, Map<String, Object> params) {
+        return postFile(url, params, null);
+    }
+
+    /**
+     * 鍙戦�佹枃浠朵笂浼犺姹傦紙鏀寔鑷畾涔夋枃浠跺悕锛�
+     *
+     * @param url 璇锋眰URL
+     * @param params 璇锋眰鍙傛暟锛堝寘鍚枃浠舵祦锛�
+     * @param fileName 鏂囦欢鍚嶏紙鍙�夛紝濡傛灉涓簄ull鍒欎娇鐢ㄥ弬鏁伴敭鍚嶏級
+     * @return 鍝嶅簲鍐呭
+     */
+    public static String postFile(String url, Map<String, Object> params, String fileName) {
+        HttpURLConnection connection = null;
+        try {
+            // 鐢熸垚鍞竴鐨刡oundary
+            String boundary = generateBoundary();
+
+            log.info("寮�濮嬫枃浠朵笂浼� - URL: {}, fileName: {}, boundary: {}", url, fileName, boundary);
+            log.info("鍙傛暟鏁伴噺: {}", params.size());
+            for (Map.Entry<String, Object> entry : params.entrySet()) {
+                log.info("鍙傛暟: {} = {}", entry.getKey(), entry.getValue() instanceof InputStream ? "InputStream" : entry.getValue());
+            }
+
+            // 鍒涘缓杩炴帴
+            URL requestUrl = new URL(url);
+            connection = (HttpURLConnection) requestUrl.openConnection();
+
+            // 璁剧疆璇锋眰灞炴��
+            connection.setRequestMethod("POST");
+            connection.setDoOutput(true);
+            connection.setDoInput(true);
+            connection.setUseCaches(false);
+            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+            connection.setRequestProperty("Accept", "application/json");
+            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
+            connection.setRequestProperty("Connection", "Keep-Alive");
+            connection.setRequestProperty("Accept-Charset", "utf-8");
+            connection.setConnectTimeout(30000);
+            connection.setReadTimeout(60000);
+
+            // 鏋勫缓璇锋眰浣�
+            try (OutputStream outputStream = connection.getOutputStream();
+                 PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true)) {
+
+                // 鍐欏叆鏅�氬弬鏁�
+                for (Map.Entry<String, Object> entry : params.entrySet()) {
+                    Object value = entry.getValue();
+                    if (!(value instanceof InputStream)) {
+                        writer.append(TWO_HYPHENS).append(boundary).append(LINE_END);
+                        writer.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"").append(LINE_END);
+                        writer.append("Content-Type: text/plain; charset=UTF-8").append(LINE_END);
+                        writer.append(LINE_END);
+                        writer.append(value.toString()).append(LINE_END);
+                        writer.flush();
+                    }
+                }
+
+                // 鍐欏叆鏂囦欢鍙傛暟
+                for (Map.Entry<String, Object> entry : params.entrySet()) {
+                    Object value = entry.getValue();
+                    if (value instanceof InputStream) {
+                        // 纭畾鏂囦欢鍚�
+                        String actualFileName = fileName != null ? fileName : entry.getKey();
+
+                        writer.append(TWO_HYPHENS).append(boundary).append(LINE_END);
+                        writer.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"; filename=\"").append(actualFileName).append("\"").append(LINE_END);
+                        writer.append("Content-Type: ").append(getContentType(actualFileName)).append(LINE_END);
+                        writer.append(LINE_END);
+                        writer.flush();
+
+                        // 鍐欏叆鏂囦欢鍐呭
+                        try (InputStream inputStream = (InputStream) value) {
+                            byte[] buffer = new byte[4096];
+                            int bytesRead;
+                            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                                outputStream.write(buffer, 0, bytesRead);
+                            }
+                            outputStream.flush();
+                        }
+
+                        writer.append(LINE_END);
+                        writer.flush();
+                    }
+                }
+
+                // 鍐欏叆缁撴潫鏍囪
+                writer.append(TWO_HYPHENS).append(boundary).append(TWO_HYPHENS).append(LINE_END);
+                writer.flush();
+            }
+
+            // 鑾峰彇鍝嶅簲
+            int responseCode = connection.getResponseCode();
+            log.info("鏂囦欢涓婁紶鍝嶅簲鐮侊細{}", responseCode);
+
+            // 璇诲彇鍝嶅簲鍐呭
+            StringBuilder response = new StringBuilder();
+            try (BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(
+                            responseCode == HttpURLConnection.HTTP_OK ?
+                                    connection.getInputStream() :
+                                    connection.getErrorStream(),
+                            StandardCharsets.UTF_8))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    response.append(line);
+                }
+            }
+
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                log.error("鏂囦欢涓婁紶澶辫触锛屽搷搴旂爜锛歿}锛屽搷搴斿唴瀹癸細{}", responseCode, response.toString());
+                throw new RuntimeException("鏂囦欢涓婁紶澶辫触锛屽搷搴旂爜: " + responseCode + "锛屽搷搴斿唴瀹�: " + response.toString());
+            }
+
+            log.info("鏂囦欢涓婁紶鎴愬姛锛屽搷搴旓細{}", response.toString());
+            return response.toString();
+
+        } catch (Exception e) {
+            log.error("鏂囦欢涓婁紶寮傚父锛歿}", e.getMessage(), e);
+            throw new RuntimeException("鏂囦欢涓婁紶澶辫触: " + e.getMessage(), e);
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImageData.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImageData.java
new file mode 100644
index 0000000..e6af077
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImageData.java
@@ -0,0 +1,92 @@
+package com.ruoyi.system.domain;
+
+
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import com.ruoyi.common.annotation.Excel;
+/**
+ * 鍥剧墖鏁版嵁瀵硅薄 ImageData
+ */
+@Data
+public class ImageData extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭ID
+     */
+    private Long id;
+
+    /**
+     * 璋冨害鍗旾D
+     */
+    @Excel(name = "璋冨害鍗旾D")
+    private Long dOrdIDDt;
+
+    /**
+     * 鏈嶅姟鍗旾D
+     */
+    @Excel(name = "鏈嶅姟鍗旾D")
+    private Long sOrdIDDt;
+
+    /**
+     * 鍥剧墖绫诲瀷
+     */
+    @Excel(name = "鍥剧墖绫诲瀷")
+    private Integer imageType;
+
+    /**
+     * 鍥剧墖URL
+     */
+    @Excel(name = "鍥剧墖URL")
+    private String imageUrl;
+
+    /**
+     * 鍥剧墖URLs
+     */
+    @Excel(name = "鍥剧墖URLs")
+    private String imageUrls;
+
+    /**
+     * 鍥剧墖搴︽暟
+     */
+    @Excel(name = "鍥剧墖搴︽暟")
+    private Integer imageDeg;
+
+    /**
+     * 涓婁紶鍥剧墖鏃堕棿
+     */
+    @Excel(name = "涓婁紶鍥剧墖鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date upImageTime;
+
+    /**
+     * 涓婁紶鍥剧墖OA鐢ㄦ埛ID
+     */
+    @Excel(name = "涓婁紶鍥剧墖OA鐢ㄦ埛ID")
+    private Integer upImageOAid;
+
+    /**
+     * 鍥剧墖鍒犻櫎鏍囪
+     */
+    @Excel(name = "鍥剧墖鍒犻櫎鏍囪")
+    private Integer imageDel;
+
+    /**
+     * 鏄惁AP
+     */
+    @Excel(name = "鏄惁AP")
+    private Integer isAP;
+
+    /**
+     * AP ID
+     */
+    @Excel(name = "AP ID")
+    private Integer isAP_ID;
+
+    /**
+     * AP鏃堕棿
+     */
+    @Excel(name = "AP鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date isAP_Time;
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java
index 6dd5bff..51a83db 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java
@@ -37,6 +37,10 @@
     @Excel(name = "鏂囦欢绫诲瀷")
     private String fileType;
 
+    /** 闄勪欢鍒嗙被 */
+    @Excel(name = "闄勪欢鍒嗙被")
+    private String attachmentCategory;
+
     /** 涓婁紶鏃堕棿 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Excel(name = "涓婁紶鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@@ -94,6 +98,14 @@
         return fileType;
     }
 
+    public void setAttachmentCategory(String attachmentCategory) {
+        this.attachmentCategory = attachmentCategory;
+    }
+
+    public String getAttachmentCategory() {
+        return attachmentCategory;
+    }
+
     public void setUploadTime(Date uploadTime) {
         this.uploadTime = uploadTime;
     }
@@ -119,6 +131,7 @@
                 ", filePath='" + filePath + '\'' +
                 ", fileSize=" + fileSize +
                 ", fileType='" + fileType + '\'' +
+                ", attachmentCategory='" + attachmentCategory + '\'' +
                 ", uploadTime=" + uploadTime +
                 ", uploadBy='" + uploadBy + '\'' +
                 '}';
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/ImageTypeEnum.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/ImageTypeEnum.java
new file mode 100644
index 0000000..425888d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/ImageTypeEnum.java
@@ -0,0 +1,64 @@
+package com.ruoyi.system.domain.enums;
+
+public enum ImageTypeEnum {
+
+    DEFAULT(0, "榛樿"),
+
+    INFORMED_CONSENT(1, "鐭ユ儏鍚屾剰涔�"),
+    BRZL(2, "鐥呬汉璧勬枡"),
+    CZJL(3, "鎿嶄綔璁板綍"),
+    CCQ(4, "鍑鸿溅鍓�"),
+    CCH(5, "鍑鸿溅鍚�"),
+    SEAT_BELT(6, "缁戝畨鍏ㄥ甫鍥剧墖");
+//    鐭ユ儏鍚屾剰涔�	1
+//    鐥呬汉璧勬枡	2
+//    鎿嶄綔璁板綍	3
+//    鍑鸿溅鍓�	4
+//    鍑鸿溅鍚�	5
+//    绯诲畨鍏ㄥ甫	6
+    private final Integer code;
+    private final String description;
+
+    ImageTypeEnum(Integer code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 鏍规嵁浠g爜鑾峰彇鏋氫妇
+     */
+    public static ImageTypeEnum getByCode(Integer code) {
+        if (code == null) {
+            return DEFAULT;
+        }
+
+        for (ImageTypeEnum type : values()) {
+            if (type.getCode().equals(code)) {
+                return type;
+            }
+        }
+        return DEFAULT;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁涓虹煡鎯呭悓鎰忎功
+     */
+    public boolean isInformedConsent() {
+        return this == INFORMED_CONSENT;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁涓虹粦瀹夊叏甯﹀浘鐗�
+     */
+    public boolean isSeatBelt() {
+        return this == SEAT_BELT;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadResponse.java b/ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadResponse.java
new file mode 100644
index 0000000..7038649
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadResponse.java
@@ -0,0 +1,41 @@
+package com.ruoyi.system.file;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FileUploadResponse implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    @JsonProperty("success")
+    private boolean success;
+    
+    @JsonProperty("message")
+    private String message;
+    
+    @JsonProperty("filePath")
+    private String filePath;
+
+    @JsonProperty("thumbnailPath")
+    private String thumbnailPath;
+
+
+    public static FileUploadResponse error(String error) {
+        FileUploadResponse response = new FileUploadResponse();
+        response.setSuccess(false);
+        response.setMessage(error);
+        return response;
+    }
+    public static FileUploadResponse success(String file,String message) {
+        FileUploadResponse response = new FileUploadResponse();
+        response.setSuccess(true);
+        response.setFilePath(file);
+        response.setMessage(message);
+
+        return response;
+    }
+
+
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadServiceImpl.java
new file mode 100644
index 0000000..1abb2aa
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/file/FileUploadServiceImpl.java
@@ -0,0 +1,549 @@
+package com.ruoyi.system.file;
+
+import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.utils.http.HttpUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+
+import java.io.*;
+
+@Service
+public class FileUploadServiceImpl implements IFileUploadService {
+    
+    private static final Logger log = LoggerFactory.getLogger(FileUploadServiceImpl.class);
+
+
+    @Autowired
+    private LegacySystemConfig legacyConfig;
+
+    
+    @Override
+    public FileUploadResponse uploadLocalFile(File file, String targetPath) {
+        if (file == null || !file.exists()) {
+            return FileUploadResponse.error("鏂囦欢涓嶅瓨鍦�");
+        }
+        
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return uploadInputStream(fis, file.getName(), targetPath);
+        } catch (IOException e) {
+            log.error("璇诲彇鏈湴鏂囦欢澶辫触: {}", file.getAbsolutePath(), e);
+            return FileUploadResponse.error("璇诲彇鏂囦欢澶辫触: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    public FileUploadResponse uploadMultipartFile(MultipartFile multipartFile, String targetPath) {
+        if (multipartFile == null || multipartFile.isEmpty()) {
+            return FileUploadResponse.error("鏂囦欢涓虹┖");
+        }
+        
+        try (InputStream inputStream = multipartFile.getInputStream()) {
+            return uploadInputStream(inputStream, multipartFile.getOriginalFilename(), targetPath);
+        } catch (IOException e) {
+            log.error("璇诲彇MultipartFile澶辫触", e);
+            return FileUploadResponse.error("璇诲彇鏂囦欢澶辫触: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    public FileUploadResponse uploadBytes(byte[] fileBytes, String fileName, String targetPath) {
+        if (fileBytes == null || fileBytes.length == 0) {
+            return FileUploadResponse.error("鏂囦欢瀛楄妭鏁扮粍涓虹┖");
+        }
+        
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(fileBytes)) {
+            return uploadInputStream(bis, fileName, targetPath);
+        } catch (IOException e) {
+            log.error("澶勭悊瀛楄妭鏁扮粍澶辫触", e);
+            return FileUploadResponse.error("澶勭悊鏂囦欢澶辫触: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    public FileUploadResponse uploadInputStream(InputStream inputStream, String fileName, String targetPath) {
+        if (inputStream == null) {
+            return FileUploadResponse.error("杈撳叆娴佷负绌�");
+        }
+        
+        try {
+            // 鏋勫缓璇锋眰鍙傛暟
+            Map<String, Object> params = new HashMap<>();
+            params.put("file", inputStream);
+            params.put("uploadFileName", targetPath);
+            
+            log.info("寮�濮嬩笂浼犳枃浠跺埌PHP鎺ュ彛: fileName={}, targetPath={}", fileName, targetPath);
+            
+            // 璋冪敤PHP涓婁紶鎺ュ彛
+            String response = HttpUtils.postFile(legacyConfig.getFileServerUrl(), params, fileName);
+            
+            log.info("PHP鎺ュ彛鍝嶅簲: {}", response);
+            
+            // 瑙f瀽鍝嶅簲
+            return parseUploadResponse(response);
+            
+        } catch (Exception e) {
+            log.error("涓婁紶鏂囦欢鍒癙HP鎺ュ彛澶辫触: fileName={}, targetPath={}", fileName, targetPath, e);
+            return FileUploadResponse.error("涓婁紶澶辫触: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    public FileUploadResponse uploadFromUrl(String fileUrl, String targetPath) {
+        if (fileUrl == null || fileUrl.trim().isEmpty()) {
+            return FileUploadResponse.error("鏂囦欢URL涓虹┖");
+        }
+        
+        try {
+            // 浠嶶RL涓嬭浇鏂囦欢
+            byte[] fileBytes = downloadFromUrl(fileUrl);
+            if (fileBytes == null || fileBytes.length == 0) {
+                return FileUploadResponse.error("浠嶶RL涓嬭浇鏂囦欢澶辫触");
+            }
+            
+            // 浠嶶RL涓彁鍙栨枃浠跺悕
+            String fileName = extractFileNameFromUrl(fileUrl);
+            
+            // 涓婁紶鏂囦欢
+            return uploadBytes(fileBytes, fileName, targetPath);
+            
+        } catch (Exception e) {
+            log.error("浠嶶RL涓婁紶鏂囦欢澶辫触: fileUrl={}, targetPath={}", fileUrl, targetPath, e);
+            return FileUploadResponse.error("浠嶶RL涓婁紶澶辫触: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    public FileUploadResponse uploadFromWechat(String accessToken, String mediaId, String targetPath) {
+        if (accessToken == null || mediaId == null) {
+            return FileUploadResponse.error("寰俊鍙傛暟涓虹┖");
+        }
+        
+        try {
+            // 浠庡井淇PI涓嬭浇鏂囦欢
+            byte[] fileBytes = downloadFromWechat(accessToken, mediaId);
+            if (fileBytes == null || fileBytes.length == 0) {
+                return FileUploadResponse.error("浠庡井淇′笅杞芥枃浠跺け璐�");
+            }
+            
+            // 鐢熸垚鏂囦欢鍚�
+            String fileName = "wechat_" + mediaId + ".jpg";
+            
+            // 涓婁紶鏂囦欢
+            return uploadBytes(fileBytes, fileName, targetPath);
+            
+        } catch (Exception e) {
+            log.error("浠庡井淇′笂浼犳枃浠跺け璐�: mediaId={}, targetPath={}", mediaId, targetPath, e);
+            return FileUploadResponse.error("浠庡井淇′笂浼犲け璐�: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    public boolean fileExists(String filePath) {
+        if (filePath == null || filePath.trim().isEmpty()) {
+            return false;
+        }
+        
+        try {
+            // 鏋勫缓瀹屾暣鐨勬枃浠惰矾寰�
+            String fullPath = legacyConfig.getFileServerUrl() + "/" + filePath;
+            File file = new File(fullPath);
+            return file.exists() && file.isFile();
+        } catch (Exception e) {
+            log.error("妫�鏌ユ枃浠舵槸鍚﹀瓨鍦ㄥけ璐�: {}", filePath, e);
+            return false;
+        }
+    }
+    
+    @Override
+    public boolean deleteFile(String filePath) {
+        if (filePath == null || filePath.trim().isEmpty()) {
+            return false;
+        }
+        
+        try {
+            // 鏋勫缓瀹屾暣鐨勬枃浠惰矾寰�
+            String fullPath = legacyConfig.getFileServerUrl() + "/" + filePath;
+            File file = new File(fullPath);
+            
+            if (file.exists() && file.isFile()) {
+                return file.delete();
+            }
+            return false;
+        } catch (Exception e) {
+            log.error("鍒犻櫎鏂囦欢澶辫触: {}", filePath, e);
+            return false;
+        }
+    }
+    
+    @Override
+    public String getFileUrl(String filePath) {
+        if (filePath == null || filePath.trim().isEmpty()) {
+            return null;
+        }
+        
+        // 鏋勫缓鏂囦欢璁块棶URL
+        return legacyConfig.getFileServerUrl() + "/" + filePath;
+    }
+    
+    /**
+     * 浠嶶RL涓嬭浇鏂囦欢
+     */
+    private byte[] downloadFromUrl(String fileUrl) throws IOException {
+        URL url = new URL(fileUrl);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setRequestMethod("GET");
+        connection.setConnectTimeout(10000);
+        connection.setReadTimeout(30000);
+        
+        try (InputStream inputStream = connection.getInputStream();
+             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+            
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            
+            return outputStream.toByteArray();
+        } finally {
+            connection.disconnect();
+        }
+    }
+    
+    /**
+     * 浠庡井淇PI涓嬭浇鏂囦欢
+     */
+    private byte[] downloadFromWechat(String accessToken, String mediaId) throws IOException {
+        String wechatUrl = String.format(
+            "https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s",
+            accessToken, mediaId
+        );
+        
+        return downloadFromUrl(wechatUrl);
+    }
+    
+    /**
+     * 浠嶶RL涓彁鍙栨枃浠跺悕
+     */
+    private String extractFileNameFromUrl(String fileUrl) {
+        try {
+            String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
+            // 绉婚櫎鏌ヨ鍙傛暟
+            if (fileName.contains("?")) {
+                fileName = fileName.substring(0, fileName.indexOf('?'));
+            }
+            return fileName.isEmpty() ? "downloaded_file" : fileName;
+        } catch (Exception e) {
+            return "downloaded_file";
+        }
+    }
+    
+    /**
+     * 瑙f瀽涓婁紶鍝嶅簲
+     */
+    private FileUploadResponse parseUploadResponse(String response) {
+        if (response == null || response.trim().isEmpty()) {
+            return FileUploadResponse.error("PHP鎺ュ彛杩斿洖绌哄搷搴�");
+        }
+        
+        try {
+            log.info("寮�濮嬭В鏋怭HP鍝嶅簲: {}", response);
+            
+            // 鏍规嵁PHP鎺ュ彛鐨勫疄闄呰繑鍥炴牸寮忚繘琛岃В鏋�
+            // PHP杩斿洖鏍煎紡: {"success": true, "message": "鏂囦欢涓婁紶鎴愬姛", "data": {...}}
+            if (response.contains("\"success\":true") || response.contains("success")) {
+                // 鎻愬彇鏂囦欢璺緞鍜岀缉鐣ュ浘璺緞
+                String filePath = extractFilePathFromResponse(response);
+                String thumbnailPath = extractThumbnailPathFromResponse(response);
+                
+                log.info("瑙f瀽缁撴灉 - filePath: {}, thumbnailPath: {}", filePath, thumbnailPath);
+                
+                // 鍒涘缓鍝嶅簲瀵硅薄
+                FileUploadResponse uploadResponse = FileUploadResponse.success(filePath, "涓婁紶鎴愬姛");
+                if (thumbnailPath != null && !thumbnailPath.isEmpty()) {
+                    uploadResponse.setThumbnailPath(thumbnailPath);
+                }
+                
+                return uploadResponse;
+            } else {
+                // 鎻愬彇閿欒淇℃伅
+                String errorMessage = extractErrorMessageFromResponse(response);
+                log.error("涓婁紶澶辫触锛岄敊璇俊鎭�: {}", errorMessage);
+                return FileUploadResponse.error(errorMessage != null ? errorMessage : "涓婁紶澶辫触");
+            }
+        } catch (Exception e) {
+            log.error("瑙f瀽涓婁紶鍝嶅簲澶辫触: {}", response, e);
+            return FileUploadResponse.error("瑙f瀽鍝嶅簲澶辫触: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * 浠庡搷搴斾腑鎻愬彇鏂囦欢璺緞
+     */
+    private String extractFilePathFromResponse(String response) {
+        // 瑙f瀽PHP鎺ュ彛杩斿洖鐨凧SON鏍煎紡: {"success": true, "data": {"filePath": "..."}}
+        try {
+            if (response.contains("\"data\":")) {
+                // 鎵惧埌data瀵硅薄
+                int dataStart = response.indexOf("\"data\":{") + 7;
+                if (dataStart > 6) {
+                    // 鍦╠ata瀵硅薄涓煡鎵緁ilePath
+                    String dataSection = response.substring(dataStart);
+                    if (dataSection.contains("\"filePath\":")) {
+                        int start = dataSection.indexOf("\"filePath\":\"") + 12;
+                        int end = dataSection.indexOf("\"", start);
+                        if (start > 11 && end > start) {
+                            String filePath = dataSection.substring(start, end);
+                            log.info("鎻愬彇鍒版枃浠惰矾寰�: {}", filePath);
+                            return filePath;
+                        }
+                    }
+                }
+            }
+            
+            // 鍏煎鏃ф牸寮忥紝鐩存帴鏌ユ壘filePath
+            if (response.contains("\"filePath\":")) {
+                int start = response.indexOf("\"filePath\":\"") + 12;
+                int end = response.indexOf("\"", start);
+                if (start > 11 && end > start) {
+                    String filePath = response.substring(start, end);
+                    log.info("鎻愬彇鍒版枃浠惰矾寰�(鏃ф牸寮�): {}", filePath);
+                    return filePath;
+                }
+            }
+        } catch (Exception e) {
+            log.error("鎻愬彇鏂囦欢璺緞澶辫触: {}", response, e);
+        }
+        return null;
+    }
+    
+    /**
+     * 浠庡搷搴斾腑鎻愬彇缂╃暐鍥捐矾寰�
+     */
+    private String extractThumbnailPathFromResponse(String response) {
+        // 瑙f瀽PHP鎺ュ彛杩斿洖鐨凧SON鏍煎紡: {"success": true, "data": {"thumbnailPath": "..."}}
+        try {
+            if (response.contains("\"data\":")) {
+                // 鎵惧埌data瀵硅薄
+                int dataStart = response.indexOf("\"data\":{") + 7;
+                if (dataStart > 6) {
+                    // 鍦╠ata瀵硅薄涓煡鎵総humbnailPath
+                    String dataSection = response.substring(dataStart);
+                    if (dataSection.contains("\"thumbnailPath\":")) {
+                        int start = dataSection.indexOf("\"thumbnailPath\":\"") + 17;
+                        int end = dataSection.indexOf("\"", start);
+                        if (start > 16 && end > start) {
+                            String thumbnailPath = dataSection.substring(start, end);
+                            log.info("鎻愬彇鍒扮缉鐣ュ浘璺緞: {}", thumbnailPath);
+                            return thumbnailPath;
+                        }
+                    }
+                }
+            }
+            
+            // 鍏煎鏃ф牸寮忥紝鐩存帴鏌ユ壘thumbnailPath
+            if (response.contains("\"thumbnailPath\":")) {
+                int start = response.indexOf("\"thumbnailPath\":\"") + 17;
+                int end = response.indexOf("\"", start);
+                if (start > 16 && end > start) {
+                    String thumbnailPath = response.substring(start, end);
+                    log.info("鎻愬彇鍒扮缉鐣ュ浘璺緞(鏃ф牸寮�): {}", thumbnailPath);
+                    return thumbnailPath;
+                }
+            }
+        } catch (Exception e) {
+            log.error("鎻愬彇缂╃暐鍥捐矾寰勫け璐�: {}", response, e);
+        }
+        return null;
+    }
+    
+    /**
+     * 浠庡搷搴斾腑鎻愬彇閿欒淇℃伅
+     */
+    private String extractErrorMessageFromResponse(String response) {
+        // 瑙f瀽PHP鎺ュ彛杩斿洖鐨凧SON鏍煎紡: {"success": false, "message": "閿欒淇℃伅"}
+        try {
+            if (response.contains("\"message\":")) {
+                int start = response.indexOf("\"message\":\"") + 11;
+                int end = response.indexOf("\"", start);
+                if (start > 10 && end > start) {
+                    String errorMessage = response.substring(start, end);
+                    log.info("鎻愬彇鍒伴敊璇俊鎭�: {}", errorMessage);
+                    return errorMessage;
+                }
+            }
+        } catch (Exception e) {
+            log.error("鎻愬彇閿欒淇℃伅澶辫触: {}", response, e);
+        }
+        return null;
+    }
+    
+    /**
+     * 鐢熸垚缂╃暐鍥�
+     * 
+     * @param sourcePath 婧愬浘鐗囪矾寰�
+     * @param targetPath 鐩爣缂╃暐鍥捐矾寰�
+     * @param width 瀹藉害
+     * @param height 楂樺害锛�0琛ㄧず鎸夋瘮渚嬬缉鏀撅級
+     * @return 鏄惁鐢熸垚鎴愬姛
+     */
+    private boolean createThumbnail(String sourcePath, String targetPath, int width, int height) {
+        try {
+            // 璇诲彇婧愬浘鐗�
+            BufferedImage sourceImage = ImageIO.read(new File(sourcePath));
+            if (sourceImage == null) {
+                log.error("鏃犳硶璇诲彇婧愬浘鐗囷細{}", sourcePath);
+                return false;
+            }
+            
+            // 璁$畻缂╃暐鍥惧昂瀵�
+            int sourceWidth = sourceImage.getWidth();
+            int sourceHeight = sourceImage.getHeight();
+            
+            if (height == 0) {
+                height = (int) Math.floor((double) width / sourceWidth * sourceHeight);
+            } else if (width == 0) {
+                width = (int) Math.floor((double) height / sourceHeight * sourceWidth);
+            }
+            
+            // 鍒涘缓缂╃暐鍥�
+            BufferedImage thumbnailImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+            Graphics2D g2d = thumbnailImage.createGraphics();
+            
+            // 璁剧疆娓叉煋璐ㄩ噺
+            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            
+            // 缁樺埗缂╃暐鍥�
+            g2d.drawImage(sourceImage, 0, 0, width, height, null);
+            g2d.dispose();
+            
+            // 淇濆瓨缂╃暐鍥�
+            String extension = getFileExtension(sourcePath);
+            return ImageIO.write(thumbnailImage, extension, new File(targetPath));
+            
+        } catch (Exception e) {
+            log.error("鐢熸垚缂╃暐鍥惧け璐ワ細sourcePath={}, targetPath={}", sourcePath, targetPath, e);
+            return false;
+        }
+    }
+    
+    /**
+     * 鑾峰彇鏂囦欢鎵╁睍鍚�
+     */
+    private String getFileExtension(String filePath) {
+        int lastDotIndex = filePath.lastIndexOf('.');
+        if (lastDotIndex > 0) {
+            return filePath.substring(lastDotIndex + 1).toLowerCase();
+        }
+        return "jpg"; // 榛樿鎵╁睍鍚�
+    }
+    
+    /**
+     * 鏈湴鏂囦欢涓婁紶锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+     */
+    public FileUploadResponse uploadLocalFileWithThumbnail(File file, String targetPath) {
+        if (file == null || !file.exists()) {
+            return FileUploadResponse.error("鏂囦欢涓嶅瓨鍦�");
+        }
+        
+        try {
+            // 妫�鏌ユ槸鍚︿负鍥剧墖鏂囦欢
+            String fileName = file.getName().toLowerCase();
+            boolean isImage = fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || 
+                             fileName.endsWith(".png") || fileName.endsWith(".gif");
+            
+            // 涓婁紶鍘熸枃浠�
+            FileUploadResponse uploadResponse = uploadLocalFile(file, targetPath);
+            if (!uploadResponse.isSuccess()) {
+                return uploadResponse;
+            }
+            
+            // 濡傛灉鏄浘鐗囷紝鐢熸垚缂╃暐鍥�
+            if (isImage && uploadResponse.getFilePath() != null) {
+                String originalPath = uploadResponse.getFilePath();
+                String thumbnailPath = generateThumbnailPath(originalPath);
+                
+                // 鐢熸垚缂╃暐鍥�
+                if (createThumbnail(originalPath, thumbnailPath, 100, 0)) {
+                    uploadResponse.setThumbnailPath(thumbnailPath);
+                    log.info("缂╃暐鍥剧敓鎴愭垚鍔燂細{}", thumbnailPath);
+                } else {
+                    log.warn("缂╃暐鍥剧敓鎴愬け璐ワ細{}", originalPath);
+                }
+            }
+            
+            return uploadResponse;
+            
+        } catch (Exception e) {
+            log.error("涓婁紶鏂囦欢骞剁敓鎴愮缉鐣ュ浘澶辫触锛歿}", file.getAbsolutePath(), e);
+            return FileUploadResponse.error("涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+    
+    /**
+     * MultipartFile涓婁紶锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+     */
+    public FileUploadResponse uploadMultipartFileWithThumbnail(MultipartFile multipartFile, String targetPath) {
+        if (multipartFile == null || multipartFile.isEmpty()) {
+            return FileUploadResponse.error("鏂囦欢涓虹┖");
+        }
+        
+        try {
+            // 妫�鏌ユ槸鍚︿负鍥剧墖鏂囦欢
+            String originalFilename = multipartFile.getOriginalFilename();
+            if (originalFilename != null) {
+                String fileName = originalFilename.toLowerCase();
+                boolean isImage = fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || 
+                                 fileName.endsWith(".png") || fileName.endsWith(".gif");
+                
+                // 涓婁紶鍘熸枃浠�
+                FileUploadResponse uploadResponse = uploadMultipartFile(multipartFile, targetPath);
+                if (!uploadResponse.isSuccess()) {
+                    return uploadResponse;
+                }
+                
+
+                
+                return uploadResponse;
+            }
+            
+            return uploadMultipartFile(multipartFile, targetPath);
+            
+        } catch (Exception e) {
+            log.error("涓婁紶MultipartFile骞剁敓鎴愮缉鐣ュ浘澶辫触", e);
+            return FileUploadResponse.error("涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 鐢熸垚缂╃暐鍥捐矾寰�
+     */
+    private String generateThumbnailPath(String originalPath) {
+        if (originalPath == null || originalPath.isEmpty()) {
+            return null;
+        }
+        
+        // 鍦ㄦ枃浠跺悕鍓嶆坊鍔� "s_" 鍓嶇紑
+        int lastSlashIndex = originalPath.lastIndexOf('/');
+        if (lastSlashIndex >= 0) {
+            String directory = originalPath.substring(0, lastSlashIndex + 1);
+            String fileName = originalPath.substring(lastSlashIndex + 1);
+            return directory + "s_" + fileName;
+        } else {
+            return "s_" + originalPath;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/file/IFileUploadService.java b/ruoyi-system/src/main/java/com/ruoyi/system/file/IFileUploadService.java
new file mode 100644
index 0000000..0e11986
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/file/IFileUploadService.java
@@ -0,0 +1,108 @@
+package com.ruoyi.system.file;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.InputStream;
+
+public interface IFileUploadService {
+
+    /**
+     * 涓婁紶鏈湴鏂囦欢鍒癙HP鎺ュ彛
+     *
+     * @param file 瑕佷笂浼犵殑鏂囦欢
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadLocalFile(File file, String targetPath);
+
+    /**
+     * 涓婁紶MultipartFile鍒癙HP鎺ュ彛
+     *
+     * @param multipartFile 瑕佷笂浼犵殑鏂囦欢
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadMultipartFile(MultipartFile multipartFile, String targetPath);
+
+    /**
+     * 涓婁紶瀛楄妭鏁扮粍鍒癙HP鎺ュ彛
+     *
+     * @param fileBytes 鏂囦欢瀛楄妭鏁扮粍
+     * @param fileName 鏂囦欢鍚�
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadBytes(byte[] fileBytes, String fileName, String targetPath);
+
+    /**
+     * 涓婁紶杈撳叆娴佸埌PHP鎺ュ彛
+     *
+     * @param inputStream 鏂囦欢杈撳叆娴�
+     * @param fileName 鏂囦欢鍚�
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadInputStream(InputStream inputStream, String fileName, String targetPath);
+
+    /**
+     * 浠嶶RL涓嬭浇鏂囦欢骞朵笂浼犲埌PHP鎺ュ彛
+     *
+     * @param fileUrl 鏂囦欢URL
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadFromUrl(String fileUrl, String targetPath);
+
+    /**
+     * 浠庡井淇PI涓嬭浇鏂囦欢骞朵笂浼犲埌PHP鎺ュ彛
+     *
+     * @param accessToken 寰俊璁块棶浠ょ墝
+     * @param mediaId 寰俊濯掍綋ID
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadFromWechat(String accessToken, String mediaId, String targetPath);
+
+    /**
+     * 妫�鏌ユ枃浠舵槸鍚﹀瓨鍦�
+     *
+     * @param filePath 鏂囦欢璺緞
+     * @return 鏄惁瀛樺湪
+     */
+    boolean fileExists(String filePath);
+
+    /**
+     * 鍒犻櫎鏂囦欢
+     *
+     * @param filePath 鏂囦欢璺緞
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    boolean deleteFile(String filePath);
+
+    /**
+     * 鑾峰彇鏂囦欢璁块棶URL
+     *
+     * @param filePath 鏂囦欢璺緞
+     * @return 璁块棶URL
+     */
+    String getFileUrl(String filePath);
+
+    /**
+     * 涓婁紶鏈湴鏂囦欢鍒癙HP鎺ュ彛锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+     *
+     * @param file 瑕佷笂浼犵殑鏂囦欢
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadLocalFileWithThumbnail(File file, String targetPath);
+
+    /**
+     * 涓婁紶MultipartFile鍒癙HP鎺ュ彛锛堝寘鍚缉鐣ュ浘鐢熸垚锛�
+     *
+     * @param multipartFile 瑕佷笂浼犵殑鏂囦欢
+     * @param targetPath 鐩爣璺緞锛堢浉瀵逛簬PHP涓婁紶鐩綍锛�
+     * @return 涓婁紶缁撴灉
+     */
+    FileUploadResponse uploadMultipartFileWithThumbnail(MultipartFile multipartFile, String targetPath);
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/IImageDataService.java b/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/IImageDataService.java
new file mode 100644
index 0000000..e2b48b3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/IImageDataService.java
@@ -0,0 +1,200 @@
+package com.ruoyi.system.imagedata;
+
+
+import com.ruoyi.system.domain.ImageData;
+
+import java.util.List;
+
+/**
+ * 鍥剧墖鏁版嵁Service鎺ュ彛
+ */
+public interface IImageDataService {
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 鍥剧墖鏁版嵁
+     */
+    public ImageData selectImageDataById(Long id);
+
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁鍒楄〃
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataList(ImageData imageData);
+
+    /**
+     * 鏂板鍥剧墖鏁版嵁
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 缁撴灉
+     */
+    public int insertImageData(ImageData imageData);
+
+    /**
+     * 淇敼鍥剧墖鏁版嵁
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 缁撴灉
+     */
+    public int updateImageData(ImageData imageData);
+
+    /**
+     * 鎵归噺鍒犻櫎鍥剧墖鏁版嵁
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鍥剧墖鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteImageDataByIds(Long[] ids);
+
+    /**
+     * 鍒犻櫎鍥剧墖鏁版嵁淇℃伅
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteImageDataById(Long id);
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param dOrdIDDt 璋冨害鍗旾D
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataByDOrdIDDt(Long dOrdIDDt);
+
+    String generateCompatibleFilePath(Long dispatchOrdID, String mediaId, boolean isThumbnail);
+
+    String generateCompatibleUrl(Long dispatchOrdID, String mediaId, boolean isThumbnail);
+
+    /**
+     * 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param sOrdIDDt 鏈嶅姟鍗旾D
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataBySOrdIDDt(Long sOrdIDDt);
+
+    /**
+     * 鏍规嵁鍥剧墖绫诲瀷鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataByType(Integer imageType);
+
+    /**
+     * 鏍囪鍥剧墖涓哄垹闄ょ姸鎬�
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 缁撴灉
+     */
+    public int markImageDataAsDeleted(Long id);
+
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝師ASP浠g爜杞崲锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param mediaId 寰俊濯掍綋ID
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    public String uploadWxImage(Long dispatchOrdID, Long serviceOrdID, Integer oaid,
+                                String mediaId, Integer imageType, Integer adminId);
+
+
+    /**
+     * 淇濆瓨寰俊鏂囦欢鍒版湰鍦帮紙鍘烶HP浠g爜杞崲锛�
+     *
+     * @param filename 鏂囦欢鍚�
+     * @param fileContent 鏂囦欢鍐呭
+     * @return 鏄惁淇濆瓨鎴愬姛
+     */
+    public boolean saveWeixinFile(String filename, byte[] fileContent);
+
+    /**
+     * 鐢熸垚缂╃暐鍥撅紙鍘烶HP浠g爜杞崲锛�
+     *
+     * @param bigImgPath 鍘熷澶у浘璺緞
+     * @param width 缂╃暐鍥惧搴�
+     * @param height 缂╃暐鍥鹃珮搴︼紙0琛ㄧず鎸夋瘮渚嬭绠楋級
+     * @param smallImgPath 缂╃暐鍥句繚瀛樿矾寰�
+     * @return 鏄惁鐢熸垚鎴愬姛
+     */
+    public boolean createThumbnail(String bigImgPath, int width, int height, String smallImgPath);
+
+
+
+    /**
+     * 妫�鏌ユ枃浠跺吋瀹规�э紙纭繚涓庢棫绯荤粺鍏煎锛�
+     *
+     * @param filePath 鏂囦欢璺緞
+     * @return 鍏煎鎬ф鏌ョ粨鏋�
+     */
+    public String checkFileCompatibility(String filePath);
+
+    /**
+     * 楠岃瘉URL鏍煎紡鏄惁涓庢棫绯荤粺鍏煎
+     *
+     * @param url 鍥剧墖URL
+     * @return 鏄惁鍏煎
+     */
+    public boolean isUrlCompatible(String url);
+
+
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛堝厑璁哥洿鎺ヤ紶鍏ュ浘鐗嘦RL锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageUrl 鍥剧墖URL
+     * @param thumbnailUrl 缂╃暐鍥綰RL锛堝彲閫夛級
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    public String uploadImageByUrl(Long dispatchOrdID, Long serviceOrdID, Integer oaid,
+                                   String imageUrl, String thumbnailUrl, Integer imageType, Integer adminId);
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛堢畝鍖栫増鏈紝鑷姩鐢熸垚缂╃暐鍥綰RL锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageUrl 鍥剧墖URL
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    public String uploadImageByUrlSimple(Long dispatchOrdID, Long serviceOrdID, Integer oaid,
+                                         String imageUrl, Integer imageType, Integer adminId);
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝畬鏁寸増鏈紝鍖呭惈鏂囦欢涓嬭浇鍜岀缉鐣ュ浘鐢熸垚锛�
+     *
+     * @param accessToken 寰俊璁块棶浠ょ墝
+     * @param mediaId 寰俊濯掍綋ID
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    public String uploadWxImageWithDownload(String accessToken, String mediaId, Long dispatchOrdID,
+                                            Integer oaid, Integer imageType, Integer adminId);
+    /**
+     * 鏍规嵁璋冨害鍗旾D鍜屽浘鐗囩被鍨嬫煡璇㈠浘鐗囨暟鎹�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataByDOrdIDDtAndType(Long dispatchOrdID, Integer imageType);
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/ImageDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/ImageDataServiceImpl.java
new file mode 100644
index 0000000..f98fe8a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/ImageDataServiceImpl.java
@@ -0,0 +1,644 @@
+package com.ruoyi.system.imagedata;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.system.domain.ImageData;
+import com.ruoyi.system.domain.enums.ImageTypeEnum;
+import com.ruoyi.system.file.FileUploadResponse;
+import com.ruoyi.system.file.IFileUploadService;
+import com.ruoyi.system.mapper.ImageDataMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+@Service
+@DataSource(DataSourceType.SQLSERVER)
+public class ImageDataServiceImpl implements IImageDataService {
+
+    private static final Logger log = LoggerFactory.getLogger(ImageDataServiceImpl.class);
+    @Autowired
+    private ImageDataMapper imageDataMapper;
+
+    @Autowired
+    private IFileUploadService fileUploadService;
+
+    @Autowired
+    private LegacySystemConfig legacyConfig;
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 鍥剧墖鏁版嵁
+     */
+    @Override
+    public ImageData selectImageDataById(Long id) {
+        return imageDataMapper.selectImageDataById(id);
+    }
+
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁鍒楄〃
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 鍥剧墖鏁版嵁
+     */
+    @Override
+    public List<ImageData> selectImageDataList(ImageData imageData) {
+        return imageDataMapper.selectImageDataList(imageData);
+    }
+
+    /**
+     * 鏂板鍥剧墖鏁版嵁
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertImageData(ImageData imageData) {
+        return imageDataMapper.insertImageData(imageData);
+    }
+
+    /**
+     * 淇敼鍥剧墖鏁版嵁
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateImageData(ImageData imageData) {
+        return imageDataMapper.updateImageData(imageData);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鍥剧墖鏁版嵁
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鍥剧墖鏁版嵁涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteImageDataByIds(Long[] ids) {
+        return imageDataMapper.deleteImageDataByIds(ids);
+    }
+
+    /**
+     * 鍒犻櫎鍥剧墖鏁版嵁淇℃伅
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteImageDataById(Long id) {
+        return imageDataMapper.deleteImageDataById(id);
+    }
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param dOrdIDDt 璋冨害鍗旾D
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    @Override
+    public List<ImageData> selectImageDataByDOrdIDDt(Long dOrdIDDt) {
+        return imageDataMapper.selectImageDataByDOrdIDDt(dOrdIDDt);
+    }
+    /**
+     * 鐢熸垚涓庢棫绯荤粺鍏煎鐨勬枃浠惰矾寰�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param mediaId 濯掍綋ID
+     * @param isThumbnail 鏄惁涓虹缉鐣ュ浘
+     * @return 鍏煎鐨勬枃浠惰矾寰�
+     */
+
+    @Override
+    public String generateCompatibleFilePath(Long dispatchOrdID, String mediaId, boolean isThumbnail) {
+        try {
+            String yearMonth = DateUtils.dateTimeNow("yyyyMM");
+            String fileName = dispatchOrdID + "_" + mediaId + ".jpg";
+
+            if (isThumbnail) {
+                fileName = "s_" + fileName;
+            }
+
+            return legacyConfig.getFileServerUrl() + "/" + yearMonth + "/" + fileName;
+        } catch (Exception e) {
+            log.error("鐢熸垚鍏煎鏂囦欢璺緞澶辫触锛歿}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 鐢熸垚涓庢棫绯荤粺鍏煎鐨勮闂甎RL
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param mediaId 濯掍綋ID
+     * @param isThumbnail 鏄惁涓虹缉鐣ュ浘
+     * @return 鍏煎鐨勮闂甎RL
+     */
+    @Override
+    public String generateCompatibleUrl(Long dispatchOrdID, String mediaId, boolean isThumbnail) {
+        try {
+            String yearMonth = DateUtils.dateTimeNow("yyyyMM");
+            String fileName = dispatchOrdID + "_" + mediaId + ".jpg";
+
+            if (isThumbnail) {
+                fileName = "s_" + fileName;
+            }
+
+            return legacyConfig.getFileServerUrl() + "/" + yearMonth + "/" + fileName;
+        } catch (Exception e) {
+            log.error("鐢熸垚鍏煎URL澶辫触锛歿}", e.getMessage());
+            return null;
+        }
+    }
+    /**
+     * 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param sOrdIDDt 鏈嶅姟鍗旾D
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    @Override
+    public List<ImageData> selectImageDataBySOrdIDDt(Long sOrdIDDt) {
+        return imageDataMapper.selectImageDataBySOrdIDDt(sOrdIDDt);
+    }
+
+    /**
+     * 鏍规嵁鍥剧墖绫诲瀷鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    @Override
+    public List<ImageData> selectImageDataByType(Integer imageType) {
+        ImageData imageData = new ImageData();
+        imageData.setImageType(imageType);
+        return imageDataMapper.selectImageDataList(imageData);
+    }
+
+    /**
+     * 鏍囪鍥剧墖涓哄垹闄ょ姸鎬�
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int markImageDataAsDeleted(Long id) {
+        ImageData imageData = new ImageData();
+        imageData.setId(id);
+        imageData.setImageDel(1); // 1琛ㄧず宸插垹闄�
+        return imageDataMapper.updateImageData(imageData);
+    }
+
+
+    /**
+     * 寰俊鍥剧墖涓婁紶澶勭悊锛堝師ASP浠g爜杞崲锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param mediaId 寰俊濯掍綋ID
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+
+    public String uploadWxImage(Long dispatchOrdID, Long serviceOrdID, Integer oaid,
+                                String mediaId, Integer imageType, Integer adminId) {
+        try {
+            // 鑾峰彇鍥剧墖绫诲瀷鏋氫妇
+            ImageTypeEnum imageTypeEnum = ImageTypeEnum.getByCode(imageType);
+
+            // 濡傛灉鏈夎皟搴﹀崟ID锛屽垯澶勭悊璋冨害鍗曠浉鍏冲浘鐗�
+            if (dispatchOrdID != null && dispatchOrdID > 0) {
+                return processDispatchOrderImage(dispatchOrdID, serviceOrdID, mediaId, imageTypeEnum, adminId);
+            }
+            // 濡傛灉鍙湁OA鐢ㄦ埛ID锛屽垯鏇存柊鐢ㄦ埛澶村儚
+            else if (oaid != null && oaid > 0) {
+                return updateUserAvatar(oaid, mediaId);
+            }
+            else {
+                return "鍙傛暟閿欒锛氱己灏戝繀瑕佺殑鍙傛暟";
+            }
+        } catch (Exception e) {
+            return "澶勭悊澶辫触锛�" + e.getMessage();
+        }
+    }
+
+    /**
+     * 澶勭悊璋冨害鍗曠浉鍏冲浘鐗囦笂浼�
+     */
+    private String processDispatchOrderImage(Long dispatchOrdID, Long serviceOrdID,
+                                             String mediaId, ImageTypeEnum imageTypeEnum, Integer adminId) {
+        try {
+            // 鐢熸垚鍥剧墖URL璺緞
+            String imageUrl = generateImageUrl(dispatchOrdID, mediaId, false);
+            String imageUrls = generateImageUrl(dispatchOrdID, mediaId, true);
+
+            // 鍒涘缓鍥剧墖鏁版嵁瀵硅薄
+            ImageData imageData = new ImageData();
+            imageData.setDOrdIDDt(dispatchOrdID);
+            imageData.setSOrdIDDt(serviceOrdID);
+            imageData.setImageType(imageTypeEnum.getCode());
+            imageData.setImageUrl(imageUrl);
+            imageData.setImageUrls(imageUrls);
+            imageData.setUpImageTime(new Date());
+            imageData.setUpImageOAid(adminId);
+            imageData.setImageDel(0); // 0琛ㄧず鏈垹闄�
+
+            // 鎻掑叆鍥剧墖鏁版嵁
+            int result = imageDataMapper.insertImageData(imageData);
+            if (result <= 0) {
+                return "鍥剧墖鏁版嵁淇濆瓨澶辫触";
+            }
+
+
+                return "鍥剧墖涓婁紶鎴愬姛锛孖D: " + imageData.getId() + "锛岀被鍨�: " + imageTypeEnum.getDescription();
+
+        } catch (Exception e) {
+            return "澶勭悊璋冨害鍗曞浘鐗囧け璐ワ細" + e.getMessage();
+        }
+    }
+
+    /**
+     * 鏇存柊鐢ㄦ埛澶村儚
+     */
+    private String updateUserAvatar(Integer oaid, String mediaId) {
+        try {
+            // 杩欓噷闇�瑕佽皟鐢∣A鐢ㄦ埛鏈嶅姟鏉ユ洿鏂板ご鍍�
+            // 鐢变簬娌℃湁OA鐢ㄦ埛鏈嶅姟鐨勫叿浣撳疄鐜帮紝杩欓噷鍙槸绀轰緥
+            String avatarUrl = "/upload/" + oaid + "_" + mediaId + ".jpg";
+
+            // TODO: 璋冪敤OA鐢ㄦ埛鏈嶅姟鏇存柊澶村儚
+            // oaUserService.updateAvatar(oaid, avatarUrl);
+
+            return "鐢ㄦ埛澶村儚鏇存柊鎴愬姛";
+        } catch (Exception e) {
+            return "鏇存柊鐢ㄦ埛澶村儚澶辫触锛�" + e.getMessage();
+        }
+    }
+
+    /**
+     * 鐢熸垚鍥剧墖URL
+     */
+    private String generateImageUrl(Long dispatchOrdID, String mediaId, boolean isThumbnail) {
+        Date now = new Date();
+        int year = now.getYear() + 1900; // Java鐨勫勾浠介渶瑕佸姞1900
+        int month = now.getMonth() + 1;  // Java鐨勬湀浠戒粠0寮�濮�
+
+        String monthStr = String.format("%02d", month);
+        String prefix = isThumbnail ? "/upload/" + year + monthStr + "/s_" : "/upload/" + year + monthStr + "/";
+
+        return prefix + dispatchOrdID + "_" + mediaId + ".jpg";
+    }
+
+
+
+
+    /**
+     * 淇濆瓨寰俊鏂囦欢鍒版湰鍦帮紙鍘烶HP浠g爜杞崲锛�
+     *
+     * @param filename 鏂囦欢鍚�
+     * @param fileContent 鏂囦欢鍐呭
+     * @return 鏄惁淇濆瓨鎴愬姛
+     */
+    public boolean saveWeixinFile(String filename, byte[] fileContent) {
+        FileOutputStream localFile = null;
+        try {
+            // 纭繚鐩綍瀛樺湪
+            File file = new File(filename);
+            File parentDir = file.getParentFile();
+            if (!parentDir.exists()) {
+                parentDir.mkdirs();
+            }
+
+            localFile = new FileOutputStream(filename);
+            localFile.write(fileContent);
+            localFile.flush();
+
+            log.info("鎴愬姛淇濆瓨寰俊鏂囦欢锛歿}", filename);
+            return true;
+        } catch (Exception e) {
+            log.error("淇濆瓨寰俊鏂囦欢澶辫触锛歿}", e.getMessage(), e);
+            return false;
+        } finally {
+            if (localFile != null) {
+                try {
+                    localFile.close();
+                } catch (IOException e) {
+                    log.error("鍏抽棴鏂囦欢娴佸け璐ワ細{}", e.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * 鐢熸垚缂╃暐鍥撅紙鍘烶HP浠g爜杞崲锛�
+     *
+     * @param bigImgPath 鍘熷澶у浘璺緞
+     * @param width 缂╃暐鍥惧搴�
+     * @param height 缂╃暐鍥鹃珮搴︼紙0琛ㄧず鎸夋瘮渚嬭绠楋級
+     * @param smallImgPath 缂╃暐鍥句繚瀛樿矾寰�
+     * @return 鏄惁鐢熸垚鎴愬姛
+     */
+    public boolean createThumbnail(String bigImgPath, int width, int height, String smallImgPath) {
+        try {
+            // 璇诲彇鍘熷鍥剧墖
+            BufferedImage originalImage = ImageIO.read(new File(bigImgPath));
+            if (originalImage == null) {
+                log.error("鏃犳硶璇诲彇鍘熷鍥剧墖锛歿}", bigImgPath);
+                return false;
+            }
+
+            int srcWidth = originalImage.getWidth();
+            int srcHeight = originalImage.getHeight();
+
+            // 璁$畻缂╃暐鍥惧昂瀵�
+            if (height == 0) {
+                height = (int) Math.floor((double) width / srcWidth * srcHeight);
+            } else if (width == 0) {
+                width = (int) Math.floor((double) height / srcHeight * srcWidth);
+            }
+
+            // 鍒涘缓缂╃暐鍥�
+            BufferedImage thumbnail = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+            Graphics2D g = thumbnail.createGraphics();
+
+            // 璁剧疆娓叉煋璐ㄩ噺
+            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+            // 缁樺埗缂╃暐鍥�
+            g.drawImage(originalImage, 0, 0, width, height, null);
+            g.dispose();
+
+            // 纭繚鐩綍瀛樺湪
+            File smallImgFile = new File(smallImgPath);
+            File parentDir = smallImgFile.getParentFile();
+            if (!parentDir.exists()) {
+                parentDir.mkdirs();
+            }
+
+            // 淇濆瓨缂╃暐鍥�
+            ImageIO.write(thumbnail, "jpg", smallImgFile);
+
+            log.info("鎴愬姛鐢熸垚缂╃暐鍥撅細{} -> {} ({}x{})", bigImgPath, smallImgPath, width, height);
+            return true;
+        } catch (Exception e) {
+            log.error("鐢熸垚缂╃暐鍥惧け璐ワ細{}", e.getMessage(), e);
+            return false;
+        }
+    }
+
+
+    /**
+     * 澶勭悊璋冨害鍗曠浉鍏冲浘鐗囦笂浼狅紙鍖呭惈鏂囦欢URL锛�
+     */
+    private String processDispatchOrderImageWithFiles(Long dispatchOrdID, Long serviceOrdID,
+                                                      String mediaId, ImageTypeEnum imageTypeEnum,
+                                                      Integer adminId, String originalImageUrl, String thumbnailUrl) {
+        try {
+            // 鍒涘缓鍥剧墖鏁版嵁瀵硅薄
+            ImageData imageData = new ImageData();
+            imageData.setDOrdIDDt(dispatchOrdID);
+            imageData.setSOrdIDDt(serviceOrdID);
+            imageData.setImageType(imageTypeEnum.getCode());
+            imageData.setImageUrl(originalImageUrl);
+            imageData.setImageUrls(thumbnailUrl);
+            imageData.setUpImageTime(new Date());
+            imageData.setUpImageOAid(adminId);
+            imageData.setImageDel(0); // 0琛ㄧず鏈垹闄�
+
+            // 鎻掑叆鍥剧墖鏁版嵁
+            int result = imageDataMapper.insertImageData(imageData);
+            if (result <= 0) {
+                return "鍥剧墖鏁版嵁淇濆瓨澶辫触";
+            }
+
+
+                return "鍥剧墖涓婁紶鎴愬姛锛孖D: " + imageData.getId() + "锛岀被鍨�: " + imageTypeEnum.getDescription() +
+                        "锛屽師濮嬪浘鐗嘦RL: " + originalImageUrl + "锛岀缉鐣ュ浘URL: " + thumbnailUrl;
+
+        } catch (Exception e) {
+            return "澶勭悊璋冨害鍗曞浘鐗囧け璐ワ細" + e.getMessage();
+        }
+    }
+
+    /**
+     * 鏇存柊鐢ㄦ埛澶村儚锛堝寘鍚枃浠禪RL锛�
+     */
+    private String updateUserAvatarWithFile(Integer oaid, String mediaId, String imageUrl) {
+        try {
+            // 杩欓噷闇�瑕佽皟鐢∣A鐢ㄦ埛鏈嶅姟鏉ユ洿鏂板ご鍍�
+            // TODO: 璋冪敤OA鐢ㄦ埛鏈嶅姟鏇存柊澶村儚
+            // oaUserService.updateAvatar(oaid, imageUrl);
+
+            return "鐢ㄦ埛澶村儚鏇存柊鎴愬姛锛孶RL锛�" + imageUrl;
+        } catch (Exception e) {
+            return "鏇存柊鐢ㄦ埛澶村儚澶辫触锛�" + e.getMessage();
+        }
+    }
+
+    /**
+     * 妫�鏌ユ枃浠跺吋瀹规�э紙纭繚涓庢棫绯荤粺鍏煎锛�
+     *
+     * @param filePath 鏂囦欢璺緞
+     * @return 鍏煎鎬ф鏌ョ粨鏋�
+     */
+    public String checkFileCompatibility(String filePath) {
+        try {
+            File file = new File(filePath);
+
+            if (!file.exists()) {
+                return "鏂囦欢涓嶅瓨鍦細" + filePath;
+            }
+
+            // 妫�鏌ユ枃浠跺懡鍚嶆槸鍚︾鍚堟棫绯荤粺瑙勮寖
+            String fileName = file.getName();
+            if (!fileName.matches("^(\\d+|[A-Z]+)_[A-Za-z0-9_]+\\.jpg$")) {
+                return "鏂囦欢鍛藉悕涓嶇鍚堟棫绯荤粺瑙勮寖锛�" + fileName;
+            }
+
+            // 妫�鏌ョ洰褰曠粨鏋勬槸鍚︾鍚堟棫绯荤粺瑙勮寖
+            String parentDir = file.getParentFile().getName();
+            if (!parentDir.matches("^\\d{6}$")) { // 骞存湀鏍煎紡锛�202412
+                return "鐩綍缁撴瀯涓嶇鍚堟棫绯荤粺瑙勮寖锛�" + parentDir;
+            }
+
+            return "鏂囦欢鍏煎鎬ф鏌ラ�氳繃锛�" + filePath;
+        } catch (Exception e) {
+            return "鍏煎鎬ф鏌ュけ璐ワ細" + e.getMessage();
+        }
+    }
+
+    /**
+     * 楠岃瘉URL鏍煎紡鏄惁涓庢棫绯荤粺鍏煎
+     *
+     * @param url 鍥剧墖URL
+     * @return 鏄惁鍏煎
+     */
+    public boolean isUrlCompatible(String url) {
+        try {
+            // 妫�鏌RL鏍煎紡鏄惁绗﹀悎鏃х郴缁熻鑼�
+            // 鏃х郴缁熸牸寮忥細/upload/骞存湀/鏂囦欢鍚�.jpg
+            return url.matches("^/upload/\\d{6}/[A-Za-z0-9_]+\\.jpg$");
+        } catch (Exception e) {
+            log.error("URL鍏煎鎬ф鏌ュけ璐ワ細{}", e.getMessage());
+            return false;
+        }
+    }
+
+
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛堝厑璁哥洿鎺ヤ紶鍏ュ浘鐗嘦RL锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageUrl 鍥剧墖URL
+     * @param thumbnailUrl 缂╃暐鍥綰RL锛堝彲閫夛級
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    @Override
+
+    public String uploadImageByUrl(Long dispatchOrdID, Long serviceOrdID, Integer oaid,
+                                   String imageUrl, String thumbnailUrl, Integer imageType, Integer adminId) {
+        try {
+            // 楠岃瘉鍙傛暟
+            if (imageUrl == null || imageUrl.trim().isEmpty()) {
+                return "鍥剧墖URL涓嶈兘涓虹┖";
+            }
+
+            // 澶勭悊涓氬姟閫昏緫
+            if (dispatchOrdID != null && dispatchOrdID > 0) {
+                // 璋冨害鍗曠浉鍏冲浘鐗�
+                ImageTypeEnum imageTypeEnum = ImageTypeEnum.getByCode(imageType);
+                return processDispatchOrderImageWithFiles(dispatchOrdID, serviceOrdID, null,
+                        imageTypeEnum, adminId, imageUrl, thumbnailUrl);
+            } else if (oaid != null && oaid > 0) {
+                // OA鐢ㄦ埛澶村儚
+                return updateUserAvatarWithFile(oaid, null, imageUrl);
+            } else {
+                return "鍙傛暟閿欒锛氱己灏戝繀瑕佺殑鍙傛暟锛堣皟搴﹀崟ID鎴朞A鐢ㄦ埛ID锛�";
+            }
+        } catch (Exception e) {
+            log.error("閫氳繃URL涓婁紶鍥剧墖澶辫触锛歿}", e.getMessage(), e);
+            return "澶勭悊澶辫触锛�" + e.getMessage();
+        }
+    }
+
+    /**
+     * 閫氳繃鍥剧墖URL涓婁紶澶勭悊锛堢畝鍖栫増鏈紝鑷姩鐢熸垚缂╃暐鍥綰RL锛�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @param oaid OA鐢ㄦ埛ID
+     * @param imageUrl 鍥剧墖URL
+     * @param imageType 鍥剧墖绫诲瀷
+     * @param adminId 褰撳墠绠$悊鍛業D
+     * @return 澶勭悊缁撴灉
+     */
+    @Override
+
+    public String uploadImageByUrlSimple(Long dispatchOrdID, Long serviceOrdID, Integer oaid,
+                                         String imageUrl, Integer imageType, Integer adminId) {
+        try {
+            // 楠岃瘉鍙傛暟
+            if (imageUrl == null || imageUrl.trim().isEmpty()) {
+                return "鍥剧墖URL涓嶈兘涓虹┖";
+            }
+
+            // 鑷姩鐢熸垚缂╃暐鍥綰RL锛堝鏋滃師鍥綰RL鍖呭惈鏂囦欢鍚嶏級
+            String thumbnailUrl = null;
+            if (imageUrl.contains("/")) {
+                String fileName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
+                if (fileName.contains(".")) {
+                    String nameWithoutExt = fileName.substring(0, fileName.lastIndexOf("."));
+                    String extension = fileName.substring(fileName.lastIndexOf("."));
+                    String thumbnailFileName = "s_" + nameWithoutExt + extension;
+                    thumbnailUrl = imageUrl.substring(0, imageUrl.lastIndexOf("/") + 1) + thumbnailFileName;
+                }
+            }
+
+            // 璋冪敤瀹屾暣鐗堟湰鐨勬柟娉�
+            return uploadImageByUrl(dispatchOrdID, serviceOrdID, oaid, imageUrl, thumbnailUrl, imageType, adminId);
+        } catch (Exception e) {
+            log.error("閫氳繃URL涓婁紶鍥剧墖锛堢畝鍖栫増锛夊け璐ワ細{}", e.getMessage(), e);
+            return "澶勭悊澶辫触锛�" + e.getMessage();
+        }
+    }
+
+    @Override
+    public String uploadWxImageWithDownload(String accessToken, String mediaId, Long dispatchOrdID, Integer oaid, Integer imageType, Integer adminId) {
+        try {
+            // 纭畾鐩爣璺緞
+            String targetPath;
+            if (dispatchOrdID != null && dispatchOrdID > 0) {
+                // 璋冨害鍗曠浉鍏冲浘鐗囷細鎸夊勾鏈堢粍缁囩洰褰�
+                String yearMonth = DateUtils.dateTimeNow("yyyyMM");
+                targetPath = yearMonth + "/" + dispatchOrdID;
+            } else if (oaid != null && oaid > 0) {
+                // OA鐢ㄦ埛澶村儚
+                targetPath = "avatar/" + oaid;
+            } else {
+                return "鍙傛暟閿欒锛氱己灏戝繀瑕佺殑鍙傛暟";
+            }
+
+            // 浣跨敤鏂囦欢涓婁紶鏈嶅姟浠庡井淇′笅杞藉苟涓婁紶鏂囦欢
+            FileUploadResponse uploadResponse = fileUploadService.uploadFromWechat(accessToken, mediaId, targetPath);
+            if (!uploadResponse.isSuccess()) {
+                return "鏂囦欢涓婁紶澶辫触锛�" + uploadResponse.getMessage();
+            }
+
+            // 鑾峰彇涓婁紶鍚庣殑鏂囦欢璺緞
+            String originalImageUrl = uploadResponse.getFilePath();
+            String thumbnailUrl = uploadResponse.getThumbnailPath();
+
+            // 澶勭悊涓氬姟閫昏緫
+            if (dispatchOrdID != null && dispatchOrdID > 0) {
+                return processDispatchOrderImageWithFiles(dispatchOrdID, null, mediaId,
+                        ImageTypeEnum.getByCode(imageType), adminId, originalImageUrl, thumbnailUrl);
+            } else if (oaid != null && oaid > 0) {
+                return updateUserAvatarWithFile(oaid, mediaId, originalImageUrl);
+            }
+
+            return "鍥剧墖涓婁紶鎴愬姛锛屾枃浠惰矾寰勶細" + originalImageUrl;
+        } catch (Exception e) {
+            log.error("寰俊鍥剧墖涓婁紶澶勭悊澶辫触锛歿}", e.getMessage(), e);
+            return "澶勭悊澶辫触锛�" + e.getMessage();
+        }
+    }
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鍜屽浘鐗囩被鍨嬫煡璇㈠浘鐗囨暟鎹�
+     *
+     * @param dispatchOrdID 璋冨害鍗旾D
+     * @param imageType 鍥剧墖绫诲瀷
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    @Override
+    public List<ImageData> selectImageDataByDOrdIDDtAndType(Long dispatchOrdID, Integer imageType) {
+        // 鍒涘缓鏌ヨ鏉′欢
+        ImageData imageData = new ImageData();
+        imageData.setDOrdIDDt(dispatchOrdID);
+        imageData.setImageType(imageType);
+
+        // 鏌ヨ鍥剧墖鏁版嵁
+        return imageDataMapper.selectImageDataList(imageData);
+    }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/WxImageUploadRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/WxImageUploadRequest.java
new file mode 100644
index 0000000..41da5e1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/imagedata/WxImageUploadRequest.java
@@ -0,0 +1,30 @@
+package com.ruoyi.system.imagedata;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * 寰俊鍥剧墖涓婁紶璇锋眰DTO
+ */
+@Data
+public class WxImageUploadRequest {
+
+    @JsonProperty("access_token")
+    private String accessToken;
+
+    @JsonProperty("DispatchOrdID")
+    private Long dispatchOrdID;
+
+    @JsonProperty("ServiceOrdID")
+    private Long serviceOrdID;
+
+    @JsonProperty("OAID")
+    private Integer oaid;
+
+    @JsonProperty("media_id")
+    private String mediaId;
+
+    @JsonProperty("ImageType")
+    private Integer imageType;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ImageDataMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ImageDataMapper.java
new file mode 100644
index 0000000..b973de9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ImageDataMapper.java
@@ -0,0 +1,78 @@
+package com.ruoyi.system.mapper;
+
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.system.domain.ImageData;
+
+import java.util.List;
+
+/**
+ * 鍥剧墖鏁版嵁Mapper鎺ュ彛
+ */
+@DataSource(DataSourceType.SQLSERVER)
+public interface ImageDataMapper {
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 鍥剧墖鏁版嵁
+     */
+    public ImageData selectImageDataById(Long id);
+
+    /**
+     * 鏌ヨ鍥剧墖鏁版嵁鍒楄〃
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataList(ImageData imageData);
+
+    /**
+     * 鏂板鍥剧墖鏁版嵁
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 缁撴灉
+     */
+    public int insertImageData(ImageData imageData);
+
+    /**
+     * 淇敼鍥剧墖鏁版嵁
+     *
+     * @param imageData 鍥剧墖鏁版嵁
+     * @return 缁撴灉
+     */
+    public int updateImageData(ImageData imageData);
+
+    /**
+     * 鍒犻櫎鍥剧墖鏁版嵁
+     *
+     * @param id 鍥剧墖鏁版嵁涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteImageDataById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎鍥剧墖鏁版嵁
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteImageDataByIds(Long[] ids);
+
+    /**
+     * 鏍规嵁璋冨害鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param dOrdIDDt 璋冨害鍗旾D
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataByDOrdIDDt(Long dOrdIDDt);
+
+    /**
+     * 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鍥剧墖鏁版嵁
+     *
+     * @param sOrdIDDt 鏈嶅姟鍗旾D
+     * @return 鍥剧墖鏁版嵁闆嗗悎
+     */
+    public List<ImageData> selectImageDataBySOrdIDDt(Long sOrdIDDt);
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
index 362d630..de3a1c3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
@@ -96,9 +96,21 @@
      * 
      * @param taskId 浠诲姟ID
      * @param file 鏂囦欢
+     * @param category 闄勪欢鍒嗙被
      * @return 缁撴灉
      */
-    public int uploadAttachment(Long taskId, MultipartFile file);
+    public int uploadAttachment(Long taskId, MultipartFile file, String category);
+    
+    /**
+     * 浠庡井淇ediaId涓婁紶浠诲姟闄勪欢
+     * 
+     * @param taskId 浠诲姟ID
+     * @param accessToken 寰俊AccessToken
+     * @param mediaId 寰俊mediaId
+     * @param category 闄勪欢鍒嗙被
+     * @return 缁撴灉
+     */
+    public int uploadAttachmentFromWechat(Long taskId, String accessToken, String mediaId, String category);
 
     /**
      * 鍒犻櫎浠诲姟闄勪欢
@@ -107,6 +119,14 @@
      * @return 缁撴灉
      */
     public int deleteAttachment(Long attachmentId);
+    
+    /**
+     * 鏍规嵁ID鑾峰彇闄勪欢璇︽儏
+     * 
+     * @param attachmentId 闄勪欢ID
+     * @return 闄勪欢璇︽儏
+     */
+    public SysTaskAttachment getAttachmentById(Long attachmentId);
 
     /**
      * 鍒嗛厤杞﹁締缁欎换鍔�
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
index ac521d2..56a2244 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -6,7 +6,11 @@
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
 
 import com.ruoyi.system.utils.TaskCodeGenerator;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -496,11 +500,12 @@
      * 
      * @param taskId 浠诲姟ID
      * @param file 鏂囦欢
+     * @param category 闄勪欢鍒嗙被
      * @return 缁撴灉
      */
     @Override
     @Transactional
-    public int uploadAttachment(Long taskId, MultipartFile file) {
+    public int uploadAttachment(Long taskId, MultipartFile file, String category) {
         try {
             // 涓婁紶鏂囦欢
             String fileName = FileUploadUtils.upload("/task", file);
@@ -512,6 +517,7 @@
             attachment.setFilePath(filePath);
             attachment.setFileSize(file.getSize());
             attachment.setFileType(getFileType(file.getOriginalFilename()));
+            attachment.setAttachmentCategory(category);
             attachment.setUploadTime(DateUtils.getNowDate());
             attachment.setUploadBy(SecurityUtils.getUsername());
             
@@ -519,14 +525,112 @@
             
             // 璁板綍鎿嶄綔鏃ュ織
             if (result > 0) {
+                String categoryDesc = getCategoryDesc(category);
                 recordTaskLog(taskId, "UPDATE", "涓婁紶闄勪欢", null, 
-                             "涓婁紶鏂囦欢锛�" + file.getOriginalFilename(), 
+                             "涓婁紶鏂囦欢锛�" + file.getOriginalFilename() + "(鍒嗙被锛�" + categoryDesc + ")", 
                              SecurityUtils.getUserId(), SecurityUtils.getUsername());
             }
             
             return result;
         } catch (IOException e) {
             throw new RuntimeException("鏂囦欢涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 浠庡井淇ediaId涓婁紶浠诲姟闄勪欢
+     * 
+     * @param taskId 浠诲姟ID
+     * @param accessToken 寰俊AccessToken
+     * @param mediaId 寰俊mediaId
+     * @param category 闄勪欢鍒嗙被
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int uploadAttachmentFromWechat(Long taskId, String accessToken, String mediaId, String category) {
+        try {
+            // 浠庡井淇℃湇鍔″櫒涓嬭浇鏂囦欢
+            String wechatUrl = String.format(
+                "https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s",
+                accessToken, mediaId
+            );
+            
+            byte[] fileBytes = downloadFromUrl(wechatUrl);
+            if (fileBytes == null || fileBytes.length == 0) {
+                throw new RuntimeException("浠庡井淇′笅杞芥枃浠跺け璐�");
+            }
+            
+            // 鐢熸垚鏂囦欢鍚嶏紙浣跨敤mediaId浣滀负鏂囦欢鍚嶇殑涓�閮ㄥ垎锛�
+            String fileName = "wx_" + mediaId.substring(0, Math.min(20, mediaId.length())) + "_" + System.currentTimeMillis() + ".jpg";
+            
+            // 淇濆瓨鍒版湰鍦�
+            String baseDir = FileUploadUtils.getDefaultBaseDir();
+            String datePath = DateUtils.datePath();
+            String uploadDir = baseDir + "/task/" + datePath;
+            
+            // 鍒涘缓鐩綍
+            File uploadPath = new File(uploadDir);
+            if (!uploadPath.exists()) {
+                uploadPath.mkdirs();
+            }
+            
+            // 淇濆瓨鏂囦欢
+            String filePath = uploadDir + "/" + fileName;
+            File file = new File(filePath);
+            try (FileOutputStream fos = new FileOutputStream(file)) {
+                fos.write(fileBytes);
+            }
+            
+            // 淇濆瓨闄勪欢璁板綍
+            SysTaskAttachment attachment = new SysTaskAttachment();
+            attachment.setTaskId(taskId);
+            attachment.setFileName(fileName);
+            attachment.setFilePath(filePath);
+            attachment.setFileSize((long) fileBytes.length);
+            attachment.setFileType("jpg");
+            attachment.setAttachmentCategory(category);
+            attachment.setUploadTime(DateUtils.getNowDate());
+            attachment.setUploadBy(SecurityUtils.getUsername());
+            
+            int result = sysTaskAttachmentMapper.insertSysTaskAttachment(attachment);
+            
+            // 璁板綍鎿嶄綔鏃ュ織
+            if (result > 0) {
+                String categoryDesc = getCategoryDesc(category);
+                recordTaskLog(taskId, "UPDATE", "涓婁紶闄勪欢", null, 
+                             "閫氳繃寰俊涓婁紶鏂囦欢锛�" + fileName + "(鍒嗙被锛�" + categoryDesc + ")", 
+                             SecurityUtils.getUserId(), SecurityUtils.getUsername());
+            }
+            
+            return result;
+        } catch (Exception e) {
+            throw new RuntimeException("浠庡井淇′笂浼犳枃浠跺け璐ワ細" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 浠� URL 涓嬭浇鏂囦欢
+     */
+    private byte[] downloadFromUrl(String fileUrl) throws IOException {
+        URL url = new URL(fileUrl);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setRequestMethod("GET");
+        connection.setConnectTimeout(10000);
+        connection.setReadTimeout(30000);
+        
+        try (InputStream inputStream = connection.getInputStream()) {
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
+            
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            
+            return outputStream.toByteArray();
+        } finally {
+            connection.disconnect();
         }
     }
 
@@ -561,6 +665,17 @@
         }
         
         return result;
+    }
+    
+    /**
+     * 鏍规嵁ID鑾峰彇闄勪欢璇︽儏
+     * 
+     * @param attachmentId 闄勪欢ID
+     * @return 闄勪欢璇︽儏
+     */
+    @Override
+    public SysTaskAttachment getAttachmentById(Long attachmentId) {
+        return sysTaskAttachmentMapper.selectSysTaskAttachmentByAttachmentId(attachmentId);
     }
 
     /**
@@ -1055,4 +1170,25 @@
         
         sysTaskWelfareMapper.insertSysTaskWelfare(welfareInfo);
     }
+    
+    /**
+     * 鑾峰彇闄勪欢鍒嗙被鎻忚堪
+     * 
+     * @param category 闄勪欢鍒嗙被浠g爜
+     * @return 鍒嗙被鎻忚堪
+     */
+    private String getCategoryDesc(String category) {
+        if (category == null || category.isEmpty()) {
+            return "鏈垎绫�";
+        }
+        switch (category) {
+            case "1": return "鐭ユ儏鍚屾剰涔�";
+            case "2": return "鐥呬汉璧勬枡";
+            case "3": return "鎿嶄綔璁板綍";
+            case "4": return "鍑鸿溅鍓�";
+            case "5": return "鍑鸿溅鍚�";
+            case "6": return "绯诲畨鍏ㄥ甫";
+            default: return "鍏朵粬";
+        }
+    }
 }
diff --git a/ruoyi-system/src/main/resources/mapper/system/ImageDataMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ImageDataMapper.xml
new file mode 100644
index 0000000..a810574
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/ImageDataMapper.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.ImageDataMapper">
+    
+    <resultMap type="ImageData" id="ImageDataResult">
+        <result property="id" column="id"/>
+        <result property="dOrdIDDt" column="DOrdIDDt"/>
+        <result property="sOrdIDDt" column="SOrdIDDt"/>
+        <result property="imageType" column="ImageType"/>
+        <result property="imageUrl" column="ImageUrl"/>
+        <result property="imageUrls" column="ImageUrls"/>
+        <result property="imageDeg" column="ImageDeg"/>
+        <result property="upImageTime" column="UpImageTime"/>
+        <result property="upImageOAid" column="UpImageOAid"/>
+        <result property="imageDel" column="ImageDel"/>
+        <result property="isAP" column="isAP"/>
+        <result property="isAP_ID" column="isAP_ID"/>
+        <result property="isAP_Time" column="isAP_Time"/>
+    </resultMap>
+
+    <sql id="selectImageDataVo">
+        select id, DOrdIDDt, SOrdIDDt, ImageType, ImageUrl, ImageUrls, ImageDeg, UpImageTime, UpImageOAid, ImageDel, isAP, isAP_ID, isAP_Time
+        from ImageData
+    </sql>
+
+    <select id="selectImageDataList" parameterType="ImageData" resultMap="ImageDataResult">
+        <include refid="selectImageDataVo"/>
+        <where>  
+            <if test="dOrdIDDt != null "> and DOrdIDDt = #{dOrdIDDt}</if>
+            <if test="sOrdIDDt != null "> and SOrdIDDt = #{sOrdIDDt}</if>
+            <if test="imageType != null "> and ImageType = #{imageType}</if>
+            <if test="imageUrl != null  and imageUrl != ''"> and ImageUrl like concat('%', #{imageUrl}, '%')</if>
+            <if test="imageUrls != null  and imageUrls != ''"> and ImageUrls like concat('%', #{imageUrls}, '%')</if>
+            <if test="imageDeg != null "> and ImageDeg = #{imageDeg}</if>
+            <if test="upImageTime != null "> and UpImageTime = #{upImageTime}</if>
+            <if test="upImageOAid != null "> and UpImageOAid = #{upImageOAid}</if>
+            <if test="imageDel != null "> and ImageDel = #{imageDel}</if>
+            <if test="isAP != null "> and isAP = #{isAP}</if>
+            <if test="isAP_ID != null "> and isAP_ID = #{isAP_ID}</if>
+            <if test="isAP_Time != null "> and isAP_Time = #{isAP_Time}</if>
+        </where>
+    </select>
+    
+    <select id="selectImageDataById" parameterType="Long" resultMap="ImageDataResult">
+        <include refid="selectImageDataVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectImageDataByDOrdIDDt" parameterType="Long" resultMap="ImageDataResult">
+        <include refid="selectImageDataVo"/>
+        where DOrdIDDt = #{dOrdIDDt}
+    </select>
+
+    <select id="selectImageDataBySOrdIDDt" parameterType="Long" resultMap="ImageDataResult">
+        <include refid="selectImageDataVo"/>
+        where SOrdIDDt = #{sOrdIDDt}
+    </select>
+        
+    <insert id="insertImageData" parameterType="ImageData" useGeneratedKeys="true" keyProperty="id">
+        insert into ImageData
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="dOrdIDDt != null">DOrdIDDt,</if>
+            <if test="sOrdIDDt != null">SOrdIDDt,</if>
+            <if test="imageType != null">ImageType,</if>
+            <if test="imageUrl != null">ImageUrl,</if>
+            <if test="imageUrls != null">ImageUrls,</if>
+            <if test="imageDeg != null">ImageDeg,</if>
+            <if test="upImageTime != null">UpImageTime,</if>
+            <if test="upImageOAid != null">UpImageOAid,</if>
+            <if test="imageDel != null">ImageDel,</if>
+            <if test="isAP != null">isAP,</if>
+            <if test="isAP_ID != null">isAP_ID,</if>
+            <if test="isAP_Time != null">isAP_Time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="dOrdIDDt != null">#{dOrdIDDt},</if>
+            <if test="sOrdIDDt != null">#{sOrdIDDt},</if>
+            <if test="imageType != null">#{imageType},</if>
+            <if test="imageUrl != null">#{imageUrl},</if>
+            <if test="imageUrls != null">#{imageUrls},</if>
+            <if test="imageDeg != null">#{imageDeg},</if>
+            <if test="upImageTime != null">#{upImageTime},</if>
+            <if test="upImageOAid != null">#{upImageOAid},</if>
+            <if test="imageDel != null">#{imageDel},</if>
+            <if test="isAP != null">#{isAP},</if>
+            <if test="isAP_ID != null">#{isAP_ID},</if>
+            <if test="isAP_Time != null">#{isAP_Time},</if>
+         </trim>
+    </insert>
+
+    <update id="updateImageData" parameterType="ImageData">
+        update ImageData
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="dOrdIDDt != null">DOrdIDDt = #{dOrdIDDt},</if>
+            <if test="sOrdIDDt != null">SOrdIDDt = #{sOrdIDDt},</if>
+            <if test="imageType != null">ImageType = #{imageType},</if>
+            <if test="imageUrl != null">ImageUrl = #{imageUrl},</if>
+            <if test="imageUrls != null">ImageUrls = #{imageUrls},</if>
+            <if test="imageDeg != null">ImageDeg = #{imageDeg},</if>
+            <if test="upImageTime != null">UpImageTime = #{upImageTime},</if>
+            <if test="upImageOAid != null">UpImageOAid = #{upImageOAid},</if>
+            <if test="imageDel != null">ImageDel = #{imageDel},</if>
+            <if test="isAP != null">isAP = #{isAP},</if>
+            <if test="isAP_ID != null">isAP_ID = #{isAP_ID},</if>
+            <if test="isAP_Time != null">isAP_Time = #{isAP_Time},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteImageDataById" parameterType="Long">
+        delete from ImageData where id = #{id}
+    </delete>
+
+    <delete id="deleteImageDataByIds" parameterType="String">
+        delete from ImageData where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml
index dcda30a..49220e7 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml
@@ -11,12 +11,13 @@
         <result property="filePath"         column="file_path"         />
         <result property="fileSize"         column="file_size"         />
         <result property="fileType"         column="file_type"         />
+        <result property="attachmentCategory" column="attachment_category" />
         <result property="uploadTime"       column="upload_time"       />
         <result property="uploadBy"         column="upload_by"         />
     </resultMap>
 
     <sql id="selectSysTaskAttachmentVo">
-        select attachment_id, task_id, file_name, file_path, file_size, file_type, upload_time, upload_by 
+        select attachment_id, task_id, file_name, file_path, file_size, file_type, attachment_category, upload_time, upload_by 
         from sys_task_attachment
     </sql>
 
@@ -26,6 +27,7 @@
             <if test="taskId != null "> and task_id = #{taskId}</if>
             <if test="fileName != null  and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
             <if test="fileType != null  and fileType != ''"> and file_type = #{fileType}</if>
+            <if test="attachmentCategory != null and attachmentCategory != ''"> and attachment_category = #{attachmentCategory}</if>
             <if test="uploadBy != null  and uploadBy != ''"> and upload_by like concat('%', #{uploadBy}, '%')</if>
         </where>
         order by upload_time desc
@@ -50,6 +52,7 @@
             <if test="filePath != null and filePath != ''">file_path,</if>
             <if test="fileSize != null">file_size,</if>
             <if test="fileType != null">file_type,</if>
+            <if test="attachmentCategory != null and attachmentCategory != ''">attachment_category,</if>
             <if test="uploadTime != null">upload_time,</if>
             <if test="uploadBy != null and uploadBy != ''">upload_by,</if>
          </trim>
@@ -59,6 +62,7 @@
             <if test="filePath != null and filePath != ''">#{filePath},</if>
             <if test="fileSize != null">#{fileSize},</if>
             <if test="fileType != null">#{fileType},</if>
+            <if test="attachmentCategory != null and attachmentCategory != ''">#{attachmentCategory},</if>
             <if test="uploadTime != null">#{uploadTime},</if>
             <if test="uploadBy != null and uploadBy != ''">#{uploadBy},</if>
          </trim>
@@ -72,6 +76,7 @@
             <if test="filePath != null and filePath != ''">file_path = #{filePath},</if>
             <if test="fileSize != null">file_size = #{fileSize},</if>
             <if test="fileType != null">file_type = #{fileType},</if>
+            <if test="attachmentCategory != null and attachmentCategory != ''">attachment_category = #{attachmentCategory},</if>
             <if test="uploadTime != null">upload_time = #{uploadTime},</if>
             <if test="uploadBy != null and uploadBy != ''">upload_by = #{uploadBy},</if>
         </trim>
diff --git a/sql/update_attachment_category.sql b/sql/update_attachment_category.sql
new file mode 100644
index 0000000..6e363dc
--- /dev/null
+++ b/sql/update_attachment_category.sql
@@ -0,0 +1,8 @@
+-- 涓洪檮浠惰〃娣诲姞闄勪欢鍒嗙被瀛楁
+-- ----------------------------
+ALTER TABLE sys_task_attachment 
+ADD COLUMN attachment_category VARCHAR(20) COMMENT '闄勪欢鍒嗙被锛�1-鐭ユ儏鍚屾剰涔︼紝2-鐥呬汉璧勬枡锛�3-鎿嶄綔璁板綍锛�4-鍑鸿溅鍓嶏紝5-鍑鸿溅鍚庯紝6-绯诲畨鍏ㄥ甫' 
+AFTER file_type;
+
+-- 娣诲姞绱㈠紩
+ALTER TABLE sys_task_attachment ADD INDEX idx_attachment_category (attachment_category);

--
Gitblit v1.9.1