From b46065a201c09ce69f111806f2bda4a5f476bc4e Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期六, 18 十月 2025 17:20:22 +0800
Subject: [PATCH] fix:用户同步,机构同步
---
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GeocodeServiceImpl.java | 115
ruoyi-system/src/main/java/com/ruoyi/system/mapper/Icd10Mapper.java | 34
ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java | 42
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/DepartmentSyncTask.java | 85
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java | 17
app/api/geocode.js | 17
app/pages.json | 19
EMERGENCY_INTERFACE_BINDING_REPORT.md | 374
用户同步服务重构说明.md | 498 +
转运部同步功能说明.md | 454 +
app/pages/task/create-emergency.vue | 1552 +++
ruoyi-system/src/main/java/com/ruoyi/system/domain/DepartmentSyncDTO.java | 73
ruoyi-system/src/main/java/com/ruoyi/system/mapper/HospDataMapper.java | 34
sql/user_vehicle_bind.sql | 24
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java | 14
prd/车辆管理部门过滤说明.md | 291
app/pages/bind-vehicle.vue | 149
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java | 8
WELFARE_TASK_CHECK_REPORT.md | 461 +
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/Icd10Controller.java | 46
app/pages/task/detail.vue | 1105 +-
任务状态.md | 13
prd/车辆绑定解绑功能说明.md | 476 +
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java | 38
sql/icd10.sql | 13
ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java | 19
sql/sqlserver_hospdata.sql | 19
ruoyi-ui/src/views/system/dept/index.vue | 43
ruoyi-admin/src/main/resources/application.yml | 5
app/pages/task/create-normal.vue | 595 +
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/UserSyncTask.java | 80
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java | 60
转运部同步功能-修改清单.md | 549 +
sql/sys_task_welfare.sql | 41
ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml | 30
prd/用户同步功能说明.md | 348
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java | 130
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/HospDataController.java | 46
app/static/index.html | 19
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java | 277
ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncDataService.java | 25
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 14
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskWelfareMapper.java | 60
docs/地理编码服务使用说明.md | 218
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/OaSyncTask.java | 164
app/manifest.json | 21
app/pages/mine/index.vue | 55
部门同步服务重构说明.md | 497 +
app/TASK_CREATE_REFACTOR.md | 185
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java | 291
ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml | 37
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java | 103
EMERGENCY_TRANSFER_IMPLEMENTATION.md | 220
app/api/map.js | 67
ruoyi-system/src/main/java/com/ruoyi/system/service/IGeocodeService.java | 26
app/pages/task/create.vue | 1028 --
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java | 22
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/GeocodeResult.java | 88
sql/oa_sync_job.sql | 41
ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncService.java | 30
prd/首页用户ID获取问题修复.md | 350
prd/急救转运任务人员选择功能说明.md | 252
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java | 26
docs/任务状态变更GPS定位功能说明.md | 282
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleInfoController.java | 88
ruoyi-system/src/main/java/com/ruoyi/system/domain/HospData.java | 188
prd/Vuex用户状态完整性优化.md | 544 +
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java | 330
ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerDepartmentController.java | 59
ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml | 34
ruoyi-ui/src/views/system/vehicle/index.vue | 11
部门同步功能开发总结.md | 328
app/api/icd10.js | 25
ruoyi-system/src/main/resources/mapper/system/Icd10Mapper.xml | 40
ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml | 160
sql/sys_task_emergency.sql | 54
ruoyi-ui/src/views/system/user/index.vue | 42
prd/急救转运病情选择功能说明.md | 388
app/api/dict.js | 52
app/store/modules/user.js | 17
prd/部门同步功能说明.md | 198
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java | 115
sql/add_oa_user_id_to_sys_user.sql | 8
SQL Server数据源查询优化说明.md | 302
app/README_TASK.md | 113
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java | 30
ruoyi-system/src/main/resources/mapper/system/SysTaskWelfareMapper.xml | 134
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java | 14
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java | 12
ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerUserController.java | 56
app/components/map-selector.vue | 656 +
多数据源切换问题修复说明.md | 428 +
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncDataServiceImpl.java | 68
OA数据同步定时任务开发总结.md | 311
prd/首页车辆绑定自动刷新功能.md | 454 +
app/api/system/user.js | 9
app/pages/index.vue | 415
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java | 123
转运部同步功能测试指南.md | 410
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java | 49
prd/用户绑定车辆功能说明.md | 329
WELFARE_EMERGENCY_SEPARATION_GUIDE.md | 433 +
app/pages/task/index.vue | 601
app/api/vehicle.js | 90
sql/add_location_fields.sql | 25
ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserSyncMapper.java | 23
ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml | 44
app/API_FIX_SUMMARY.md | 97
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java | 103
app/api/task.js | 109
app/pages/task/create-welfare.vue | 546 +
prd/绑定车辆部门过滤优化.md | 513 +
app/utils/constant.js | 4
sql/dept_sync_menu.sql | 10
ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java | 34
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml | 24
OA数据同步多数据源架构说明.md | 617 +
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java | 36
ruoyi-common/src/main/java/com/ruoyi/common/config/TencentMapConfig.java | 25
sql/add_department_id_to_sys_dept.sql | 8
EMERGENCY_TASK_TEST_GUIDE.md | 294
用户同步功能开发总结.md | 369
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java | 264
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GeocodeController.java | 43
OA数据同步系统-使用指南.md | 426
部门同步-快速开始.md | 146
ruoyi-system/src/main/java/com/ruoyi/system/domain/Icd10.java | 123
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskVehicleServiceImpl.java | 52
ruoyi-system/src/main/resources/mapper/system/HospDataMapper.xml | 51
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java | 244
ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java | 32
用户同步-快速开始.md | 189
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java | 87
app/config.js | 4
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskWelfare.java | 225
ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml | 66
app/api/hospital.js | 29
prd/首页任务查询优化.md | 146
OA数据同步定时任务使用指南.md | 311
部门同步测试指南.md | 274
140 files changed, 23,587 insertions(+), 2,039 deletions(-)
diff --git a/EMERGENCY_INTERFACE_BINDING_REPORT.md b/EMERGENCY_INTERFACE_BINDING_REPORT.md
new file mode 100644
index 0000000..3d0a4e2
--- /dev/null
+++ b/EMERGENCY_INTERFACE_BINDING_REPORT.md
@@ -0,0 +1,374 @@
+# 鎬ユ晳杞繍浠诲姟鍓嶇鎺ュ彛缁戝畾妫�鏌ユ姤鍛�
+
+## 鉁� 鎺ュ彛缁戝畾鎯呭喌鎬荤粨
+
+**缁撹**: 鍓嶇椤甸潰 `create-emergency.vue` **宸叉纭粦瀹氬悗鍙版帴鍙�**锛屾墍鏈夋牳蹇冨姛鑳介兘宸插鎺ュ畬鎴愶紒
+
+---
+
+## 馃搵 璇︾粏妫�鏌ョ粨鏋�
+
+### 1. 寮曞叆鐨凙PI鎺ュ彛
+
+鍦� `create-emergency.vue` 绗�256-258琛�:
+
+```javascript
+import { addTask } from "@/api/task"
+import { listAvailableVehicles } from "@/api/vehicle"
+import { calculateDistance } from "@/api/map"
+```
+
+鉁� **鐘舵��**: 宸叉纭紩鍏ユ墍闇�鎺ュ彛
+
+---
+
+### 2. 鏍稿績鍔熻兘鎺ュ彛瀵规帴妫�鏌�
+
+#### 2.1 鉁� 鍒涘缓浠诲姟鎺ュ彛 - `addTask()`
+
+**鍓嶇璋冪敤浣嶇疆**: 绗�503-514琛�
+
+```javascript
+submitTask() {
+ if (!this.validateForm()) {
+ return
+ }
+
+ this.$modal.confirm('纭畾瑕佷繚瀛樹换鍔″悧锛�').then(() => {
+ this.loading = true
+ const submitData = this.buildSubmitData()
+
+ addTask(submitData).then(response => { // 鈫� 璋冪敤鍚庡彴鎺ュ彛
+ this.loading = false
+ this.$modal.showToast('浠诲姟鍒涘缓鎴愬姛')
+ setTimeout(() => {
+ this.$tab.navigateTo('/pages/task/index')
+ }, 1500)
+ }).catch(error => {
+ this.loading = false
+ console.error('浠诲姟鍒涘缓澶辫触:', error)
+ this.$modal.showToast('浠诲姟鍒涘缓澶辫触锛岃閲嶈瘯')
+ })
+ }).catch(() => {})
+}
+```
+
+**鎺ュ彛瀹氫箟**: `app/api/task.js` 绗�18-24琛�
+
+```javascript
+export function addTask(data) {
+ return request({
+ url: '/task', // 鈫� 瀵瑰簲鍚庣 POST /task
+ method: 'post',
+ data: data
+ })
+}
+```
+
+**鍚庣鎺ュ彛**: `SysTaskController.java` 绗�76-81琛�
+
+```java
+@PostMapping
+public AjaxResult add(@RequestBody TaskCreateVO createVO) {
+ return toAjax(sysTaskService.insertSysTask(createVO));
+}
+```
+
+**鉁� 缁戝畾鐘舵��**:
+- 鍓嶇 鈫� API瀹氫箟 鈫� 鍚庣 **瀹屽叏瀵规帴**
+- 鏀寔瀹屾暣鐨勬�ユ晳杞繍浠诲姟鏁版嵁鎻愪氦
+- 鍖呭惈鎮h�呬俊鎭�佸尰闄俊鎭�佽垂鐢ㄤ俊鎭瓑鎵╁睍瀛楁
+
+---
+
+#### 2.2 鉁� 鑾峰彇鍙敤杞﹁締鎺ュ彛 - `listAvailableVehicles()`
+
+**鍓嶇璋冪敤浣嶇疆**: 绗�322-335琛�
+
+```javascript
+getAvailableVehicles() {
+ const deptId = this.currentUser.deptId
+ return listAvailableVehicles(deptId, 'EMERGENCY').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ status: vehicle.status
+ }))
+ this.vehicles = this.vehicleOptions.map(v => v.name)
+ }).catch(() => {
+ this.vehicles = []
+ })
+}
+```
+
+**鎺ュ彛瀹氫箟**: `app/api/vehicle.js` 绗�26-34琛�
+
+```javascript
+export function listAvailableVehicles(deptId, taskType) {
+ return request({
+ url: '/task/vehicle/available', // 鈫� 瀵瑰簲鍚庣鎺ュ彛
+ method: 'get',
+ params: {
+ deptId: deptId,
+ taskType: taskType // 鈫� 浼犻�� 'EMERGENCY' 绫诲瀷
+ }
+ })
+}
+```
+
+**鉁� 缁戝畾鐘舵��**:
+- 鍓嶇姝g‘浼犻�掗儴闂↖D鍜屼换鍔$被鍨�
+- 鏍规嵁浠诲姟绫诲瀷(`EMERGENCY`)绛涢�夊彲鐢ㄨ溅杈�
+- 杞﹁締鏁版嵁姝g‘鏄犲皠鍒颁笅鎷夐�夋嫨鍣�
+
+---
+
+#### 2.3 鉁� 璺濈璁$畻鎺ュ彛 - `calculateDistance()`
+
+**鍓嶇璋冪敤浣嶇疆**: 绗�388-408琛�
+
+```javascript
+calculateEmergencyDistance() {
+ if (this.addressCoordinates.hospitalOutAddress && this.addressCoordinates.hospitalInAddress) {
+ this.getDistanceBetweenPoints(
+ this.addressCoordinates.hospitalOutAddress.lat,
+ this.addressCoordinates.hospitalOutAddress.lng,
+ this.addressCoordinates.hospitalInAddress.lat,
+ this.addressCoordinates.hospitalInAddress.lng
+ ).then(distance => {
+ this.taskForm.transferDistance = distance.toFixed(2) // 鈫� 鑷姩濉厖璺濈
+ }).catch(error => {
+ console.error('璺濈璁$畻澶辫触:', error)
+ })
+ }
+}
+```
+
+**鎺ュ彛瀹氫箟**: `app/api/map.js`
+
+```javascript
+export function calculateDistance(lat1, lng1, lat2, lng2) {
+ return request({
+ url: '/map/calculate-distance',
+ method: 'get',
+ params: { lat1, lng1, lat2, lng2 }
+ })
+}
+```
+
+**鉁� 缁戝畾鐘舵��**:
+- 宸查泦鎴愬湴鍥続PI鎺ュ彛
+- 鑷姩璁$畻杞嚭鍖婚櫌鍒拌浆鍏ュ尰闄㈢殑璺濈
+- 鍩轰簬GPS鍧愭爣瀹炴椂璁$畻
+
+---
+
+### 3. 鏁版嵁鎻愪氦鏍煎紡妫�鏌�
+
+#### 3.1 鎻愪氦鏁版嵁鏋勫缓 - `buildSubmitData()`
+
+**鍓嶇鏋勫缓浣嶇疆**: 绗�467-490琛�
+
+```javascript
+buildSubmitData() {
+ const submitData = {
+ taskType: 'EMERGENCY_TRANSFER', // 鈫� 浠诲姟绫诲瀷
+ vehicleIds: this.selectedVehicleId ? [this.selectedVehicleId] : [],
+ transferTime: this.taskForm.transferTime,
+ patient: this.taskForm.patient, // 鈫� 鎮h�呬俊鎭璞�
+ hospitalOut: this.taskForm.hospitalOut, // 鈫� 杞嚭鍖婚櫌瀵硅薄
+ hospitalIn: this.taskForm.hospitalIn, // 鈫� 杞叆鍖婚櫌瀵硅薄
+ transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
+ price: this.taskForm.price ? parseFloat(this.taskForm.price) : null
+ }
+
+ // 娣诲姞GPS鍧愭爣
+ if (this.addressCoordinates.hospitalOutAddress) {
+ if (!submitData.hospitalOut) submitData.hospitalOut = {}
+ submitData.hospitalOut.longitude = this.addressCoordinates.hospitalOutAddress.lng
+ submitData.hospitalOut.latitude = this.addressCoordinates.hospitalOutAddress.lat
+ }
+
+ if (this.addressCoordinates.hospitalInAddress) {
+ if (!submitData.hospitalIn) submitData.hospitalIn = {}
+ submitData.hospitalIn.longitude = this.addressCoordinates.hospitalInAddress.lng
+ submitData.hospitalIn.latitude = this.addressCoordinates.hospitalInAddress.lat
+ }
+
+ return submitData
+}
+```
+
+**鍚庣鎺ユ敹瀵硅薄**: `TaskCreateVO.java`
+
+```java
+public class TaskCreateVO {
+ private String taskType; // 鉁� 瀵瑰簲
+ private List<Long> vehicleIds; // 鉁� 瀵瑰簲
+ private Date transferTime; // 鉁� 瀵瑰簲
+ private PatientInfo patient; // 鉁� 瀵瑰簲
+ private HospitalInfo hospitalOut; // 鉁� 瀵瑰簲
+ private HospitalInfo hospitalIn; // 鉁� 瀵瑰簲
+ private BigDecimal transferDistance; // 鉁� 瀵瑰簲
+ private BigDecimal price; // 鉁� 瀵瑰簲
+}
+```
+
+**鉁� 鏁版嵁鏍煎紡**: **瀹屽叏鍖归厤**锛屽墠鍚庣瀛楁涓�涓�瀵瑰簲
+
+---
+
+### 4. 琛ㄥ崟楠岃瘉閫昏緫
+
+**鍓嶇楠岃瘉浣嶇疆**: 绗�433-456琛�
+
+```javascript
+validateForm() {
+ if (!this.selectedVehicleId) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟杞﹁締')
+ return false
+ }
+
+ if (!this.taskForm.patient.name) {
+ this.$modal.showToast('璇疯緭鍏ユ偅鑰呭鍚�')
+ return false
+ }
+
+ if (!this.taskForm.patient.phone) {
+ this.$modal.showToast('璇疯緭鍏ユ偅鑰呰仈绯荤數璇�')
+ return false
+ }
+
+ if (!this.taskForm.hospitalOut.name) {
+ this.$modal.showToast('璇疯緭鍏ヨ浆鍑哄尰闄㈠悕绉�')
+ return false
+ }
+
+ if (!this.taskForm.hospitalIn.name) {
+ this.$modal.showToast('璇疯緭鍏ヨ浆鍏ュ尰闄㈠悕绉�')
+ return false
+ }
+
+ return true
+}
+```
+
+**鉁� 楠岃瘉閫昏緫**:
+- 蹇呭~瀛楁楠岃瘉瀹屾暣
+- 鐢ㄦ埛鍙嬪ソ鐨勯敊璇彁绀�
+- 闃绘鏃犳晥鏁版嵁鎻愪氦
+
+---
+
+## 馃幆 瀹屾暣鐨勬暟鎹祦绋�
+
+```
+鐢ㄦ埛濉啓琛ㄥ崟
+ 鈫�
+鍓嶇楠岃瘉 (validateForm)
+ 鈫�
+鏋勫缓鎻愪氦鏁版嵁 (buildSubmitData)
+ 鈫�
+璋冪敤API鎺ュ彛 (addTask)
+ 鈫�
+鍙戦�丠TTP璇锋眰: POST /task
+ 鈫�
+鍚庣Controller鎺ユ敹 (SysTaskController.add)
+ 鈫�
+Service灞傚鐞� (SysTaskServiceImpl.insertSysTask)
+ 鈫�
+淇濆瓨涓讳换鍔¤〃 (sys_task)
+ 鈫�
+淇濆瓨鎵╁睍淇℃伅 (sys_task_emergency) 鈫� 宸插疄鐜�
+ 鈫�
+杩斿洖鎴愬姛鍝嶅簲
+ 鈫�
+鍓嶇鏄剧ず鎴愬姛鎻愮ず骞惰烦杞�
+```
+
+---
+
+## 馃搳 鎺ュ彛瀵规帴鐘舵�佹眹鎬�
+
+| 鍔熻兘妯″潡 | 鍓嶇鏂规硶 | API鎺ュ彛 | 鍚庣鎺ュ彛 | 鐘舵�� |
+|---------|---------|---------|---------|------|
+| 鍒涘缓浠诲姟 | `submitTask()` | `addTask()` | `POST /task` | 鉁� 宸插鎺� |
+| 鑾峰彇杞﹁締 | `getAvailableVehicles()` | `listAvailableVehicles()` | `GET /task/vehicle/available` | 鉁� 宸插鎺� |
+| 璺濈璁$畻 | `calculateEmergencyDistance()` | `calculateDistance()` | `GET /map/calculate-distance` | 鉁� 宸插鎺� |
+| 鍦板浘閫夋嫨 | `onAddressSelected()` | MapSelector缁勪欢 | - | 鉁� 宸查泦鎴� |
+| 鏁版嵁楠岃瘉 | `validateForm()` | - | - | 鉁� 宸插疄鐜� |
+
+---
+
+## 鉁� 鎬荤粨
+
+### 宸插畬鎴愮殑缁戝畾:
+
+1. 鉁� **浠诲姟鍒涘缓鎺ュ彛** - 瀹屽叏瀵规帴锛屾敮鎸佹墿灞曚俊鎭彁浜�
+2. 鉁� **杞﹁締鏌ヨ鎺ュ彛** - 鏍规嵁閮ㄩ棬鍜屼换鍔$被鍨嬬瓫閫�
+3. 鉁� **璺濈璁$畻鎺ュ彛** - 鑷姩璁$畻杞繍璺濈
+4. 鉁� **鏁版嵁鏍煎紡鍖归厤** - 鍓嶅悗绔疺O瀵硅薄瀹屽叏涓�鑷�
+5. 鉁� **琛ㄥ崟楠岃瘉閫昏緫** - 蹇呭~椤归獙璇佸畬鏁�
+6. 鉁� **閿欒澶勭悊鏈哄埗** - catch寮傚父骞舵樉绀哄弸濂芥彁绀�
+
+### 鏁版嵁鎻愪氦瀹屾暣鎬�:
+
+- 鉁� 鎮h�呬俊鎭� (contact, phone, name, gender, idCard, condition)
+- 鉁� 杞嚭鍖婚櫌 (name, department, bedNumber, address, longitude, latitude)
+- 鉁� 杞叆鍖婚櫌 (name, department, bedNumber, address, longitude, latitude)
+- 鉁� 璐圭敤淇℃伅 (transferDistance, price)
+- 鉁� 浠诲姟鍏冩暟鎹� (taskType, vehicleIds, transferTime)
+
+---
+
+## 馃殌 鍙互鐩存帴浣跨敤
+
+**鍓嶇椤甸潰 `create-emergency.vue` 宸茬粡瀹屽叏缁戝畾濂藉悗鍙版帴鍙�**锛屾棤闇�浠讳綍淇敼锛�
+
+鍙渶:
+1. 鉁� 纭繚鍚庣鏈嶅姟宸插惎鍔�
+2. 鉁� 鏁版嵁搴撹〃 `sys_task_emergency` 宸插垱寤�
+3. 鉁� 鍓嶇璁块棶璇ラ〉闈㈠~鍐欒〃鍗曟彁浜ゅ嵆鍙�
+
+---
+
+## 馃摑 娴嬭瘯寤鸿
+
+### 1. 瀹屾暣娴佺▼娴嬭瘯
+```
+1. 璁块棶鍒涘缓浠诲姟椤甸潰
+2. 閫夋嫨杞﹁締 (鑷姩浠庢帴鍙e姞杞�)
+3. 濉啓鎮h�呬俊鎭�
+4. 閫夋嫨杞嚭鍖婚櫌鍦板潃 (浣跨敤鍦板浘閫夋嫨鍣�)
+5. 閫夋嫨杞叆鍖婚櫌鍦板潃 (浣跨敤鍦板浘閫夋嫨鍣�)
+6. 绯荤粺鑷姩璁$畻璺濈
+7. 濉啓璐圭敤淇℃伅
+8. 鐐瑰嚮淇濆瓨
+9. 鏌ョ湅鎻愪氦缁撴灉
+10. 楠岃瘉鏁版嵁搴撹褰�
+```
+
+### 2. 鏁版嵁楠岃瘉
+```sql
+-- 鏌ョ湅鏈�鏂板垱寤虹殑鎬ユ晳杞繍浠诲姟
+SELECT
+ t.task_id,
+ t.task_code,
+ t.task_type,
+ e.patient_name,
+ e.hospital_out_name,
+ e.hospital_in_name,
+ e.transfer_distance,
+ e.transfer_price
+FROM sys_task t
+LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
+WHERE t.task_type = 'EMERGENCY_TRANSFER'
+ORDER BY t.create_time DESC
+LIMIT 1;
+```
+
+---
+
+**缁撹**: 馃帀 鍓嶇涓庡悗绔帴鍙�**瀹屽叏瀵规帴**锛屽彲浠ョ洿鎺ヤ娇鐢紒
diff --git a/EMERGENCY_TASK_TEST_GUIDE.md b/EMERGENCY_TASK_TEST_GUIDE.md
new file mode 100644
index 0000000..c8f9d59
--- /dev/null
+++ b/EMERGENCY_TASK_TEST_GUIDE.md
@@ -0,0 +1,294 @@
+# 鎬ユ晳杞繍浠诲姟鍔熻兘娴嬭瘯鎸囧崡
+
+## 鉁� 宸插畬鎴愭楠�
+- [x] 鏁版嵁搴撹〃 `sys_task_emergency` 宸插垱寤�
+- [x] 鍚庣浠g爜宸插疄鐜� (瀹炰綋绫汇�丮apper銆丼ervice)
+- [x] 鍓嶇椤甸潰宸插瓨鍦� (`create-emergency.vue`)
+
+## 馃搵 鎺ヤ笅鏉ョ殑娴嬭瘯姝ラ
+
+### 姝ラ1: 閲嶆柊缂栬瘧鍚庣鏈嶅姟
+
+```bash
+# 杩涘叆鍚庣鐩綍
+cd d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master
+
+# 娓呯悊骞剁紪璇�
+mvn clean package -DskipTests
+
+# 鎴栬�呬娇鐢ㄩ」鐩嚜甯﹁剼鏈�
+bin\package.bat
+```
+
+### 姝ラ2: 鍚姩鍚庣鏈嶅姟
+
+```bash
+# 鏂瑰紡1: 浣跨敤鍚姩鑴氭湰
+bin\run.bat
+
+# 鏂瑰紡2: 浣跨敤Maven鎻掍欢
+cd ruoyi-admin
+mvn spring-boot:run
+
+# 鏂瑰紡3: 鐩存帴杩愯jar鍖�
+cd ruoyi-admin\target
+java -jar ruoyi-admin.jar
+```
+
+**鍚姩鎴愬姛鏍囧織**:
+- 鎺у埗鍙版樉绀� "RuoYi鍚姩鎴愬姛"
+- 鑳藉璁块棶 http://localhost:8080
+- 鏃犳暟鎹簱杩炴帴閿欒鎴朚apper鎵句笉鍒扮殑寮傚父
+
+### 姝ラ3: 楠岃瘉Mapper鏄惁姝g‘娉ㄥ唽
+
+**妫�鏌ュ惎鍔ㄦ棩蹇�**锛岀‘璁や互涓婱apper宸插姞杞�:
+```
+Creating a new SqlSession
+Registering mapper: com.ruoyi.system.mapper.SysTaskEmergencyMapper
+```
+
+**濡傛灉娌℃湁鑷姩鎵弿鍒�**锛屾鏌ヤ互涓嬮厤缃�:
+
+1. 纭 `application.yml` 涓殑MyBatis閰嶇疆:
+```yaml
+mybatis:
+ mapper-locations: classpath*:mapper/**/*Mapper.xml
+ type-aliases-package: com.ruoyi.system.domain
+```
+
+2. 纭 Mapper XML 鏂囦欢浣嶇疆:
+```
+ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
+```
+
+### 姝ラ4: 娴嬭瘯API鎺ュ彛
+
+#### 4.1 浣跨敤Postman娴嬭瘯鍒涘缓浠诲姟
+
+**璇锋眰閰嶇疆**:
+```
+POST http://localhost:8080/task
+Content-Type: application/json
+Authorization: Bearer {浣犵殑token}
+```
+
+**璇锋眰Body**:
+```json
+{
+ "taskType": "EMERGENCY_TRANSFER",
+ "vehicleIds": [1],
+ "transferTime": "2025-10-17 14:00:00",
+ "patient": {
+ "contact": "寮犱笁",
+ "phone": "13800138000",
+ "name": "鏉庡洓",
+ "gender": "male",
+ "idCard": "440000199001011234",
+ "condition": "楠ㄦ姌闇�绱ф�ヨ浆闄�"
+ },
+ "hospitalOut": {
+ "name": "骞垮窞甯傜涓�浜烘皯鍖婚櫌",
+ "department": "楠ㄧ",
+ "bedNumber": "201",
+ "address": "骞垮窞甯傝秺绉�鍖虹洏绂忚矾1鍙�",
+ "longitude": 113.264385,
+ "latitude": 23.12911
+ },
+ "hospitalIn": {
+ "name": "骞夸笢鐪佷汉姘戝尰闄�",
+ "department": "楠ㄧ",
+ "bedNumber": "301",
+ "address": "骞垮窞甯傝秺绉�鍖轰腑灞变簩璺�106鍙�",
+ "longitude": 113.274385,
+ "latitude": 23.13911
+ },
+ "transferDistance": 5.2,
+ "price": 800
+}
+```
+
+**棰勬湡鍝嶅簲**:
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": 1
+}
+```
+
+#### 4.2 娴嬭瘯鏌ヨ浠诲姟璇︽儏
+
+**璇锋眰**:
+```
+GET http://localhost:8080/task/{鍒氬垱寤虹殑taskId}
+Authorization: Bearer {浣犵殑token}
+```
+
+**棰勬湡鍝嶅簲** (閲嶇偣妫�鏌� `emergencyInfo` 瀛楁):
+```json
+{
+ "code": 200,
+ "msg": "鏌ヨ鎴愬姛",
+ "data": {
+ "taskId": 1,
+ "taskCode": "RW20251017001",
+ "taskType": "EMERGENCY_TRANSFER",
+ "taskStatus": "PENDING",
+ "plannedStartTime": "2025-10-17 14:00:00",
+ "assignedVehicles": [...],
+ "emergencyInfo": {
+ "patientName": "鏉庡洓",
+ "patientPhone": "13800138000",
+ "patientGender": "male",
+ "patientCondition": "楠ㄦ姌闇�绱ф�ヨ浆闄�",
+ "hospitalOutName": "骞垮窞甯傜涓�浜烘皯鍖婚櫌",
+ "hospitalOutDepartment": "楠ㄧ",
+ "hospitalInName": "骞夸笢鐪佷汉姘戝尰闄�",
+ "transferDistance": 5.2,
+ "transferPrice": 800
+ }
+ }
+}
+```
+
+### 姝ラ5: 浣跨敤鍓嶇椤甸潰娴嬭瘯
+
+#### 5.1 鍚姩鍓嶇 (UniApp H5鐗堟湰)
+
+```bash
+# 杩涘叆app鐩綍
+cd d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app
+
+# 瀹夎渚濊禆 (濡傛灉杩樻病瀹夎)
+npm install
+
+# 鍚姩H5寮�鍙戞湇鍔″櫒
+npm run dev:h5
+```
+
+#### 5.2 璁块棶鍒涘缓浠诲姟椤甸潰
+
+1. 娴忚鍣ㄦ墦寮�: http://localhost:8080 (H5椤甸潰鍦板潃)
+2. 鐧诲綍绯荤粺
+3. 杩涘叆浠诲姟绠$悊 鈫� 鍒涘缓浠诲姟
+4. 閫夋嫨"鎬ユ晳杞繍"绫诲瀷
+
+#### 5.3 濉啓琛ㄥ崟骞舵彁浜�
+
+**蹇呭~瀛楁**:
+- 鉁� 浠诲姟杞﹁締 (浠庝笅鎷夊垪琛ㄩ�夋嫨)
+- 鉁� 鎮h�呭鍚�
+- 鉁� 鎮h�呰仈绯荤數璇�
+- 鉁� 杞嚭鍖婚櫌鍚嶇О
+- 鉁� 杞叆鍖婚櫌鍚嶇О
+
+**鍙�夊瓧娈�**:
+- 杞繍鏃堕棿
+- 鎮h�呮�у埆銆佽韩浠借瘉銆佺梾鎯�
+- 鍖婚櫌绉戝銆佸簥鍙枫�佸湴鍧� (浣跨敤鍦板浘閫夋嫨鍣�)
+- 杞繍鍏噷鏁般�佹垚浜や环
+
+**鎻愪氦鍚庢鏌�**:
+- 鏄惁鏄剧ず"浠诲姟鍒涘缓鎴愬姛"
+- 鑳藉惁璺宠浆鍒颁换鍔″垪琛�
+- 鏂板垱寤虹殑浠诲姟鏄惁鏄剧ず鍦ㄥ垪琛ㄤ腑
+
+### 姝ラ6: 楠岃瘉鏁版嵁搴撴暟鎹�
+
+```sql
+-- 1. 鏌ョ湅浠诲姟涓昏〃鏁版嵁
+SELECT * FROM sys_task WHERE task_type = 'EMERGENCY_TRANSFER' ORDER BY create_time DESC LIMIT 1;
+
+-- 2. 鏌ョ湅鎵╁睍琛ㄦ暟鎹�
+SELECT * FROM sys_task_emergency ORDER BY create_time DESC LIMIT 1;
+
+-- 3. 鑱旇〃鏌ヨ楠岃瘉鍏宠仈
+SELECT
+ t.task_id,
+ t.task_code,
+ t.task_type,
+ t.task_status,
+ e.patient_name,
+ e.patient_phone,
+ e.hospital_out_name,
+ e.hospital_in_name,
+ e.transfer_distance,
+ e.transfer_price
+FROM sys_task t
+LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
+WHERE t.task_type = 'EMERGENCY_TRANSFER'
+ORDER BY t.create_time DESC;
+```
+
+**棰勬湡缁撴灉**:
+- `sys_task` 琛ㄤ腑鏈変竴鏉� `task_type = 'EMERGENCY_TRANSFER'` 鐨勮褰�
+- `sys_task_emergency` 琛ㄤ腑鏈夊搴旂殑鎵╁睍淇℃伅
+- 涓よ〃閫氳繃 `task_id` 姝g‘鍏宠仈
+
+## 馃悰 甯歌闂鎺掓煡
+
+### 闂1: 鍚庣鍚姩鎶ラ敊 "Table 'xxx.sys_task_emergency' doesn't exist"
+
+**瑙e喅鏂规**:
+```bash
+# 閲嶆柊鎵цSQL鑴氭湰
+mysql -u root -p your_database < sql/sys_task_emergency.sql
+
+# 鎴栬�呮墜鍔ㄥ湪鏁版嵁搴撳鎴风鎵ц sys_task_emergency.sql 鏂囦欢
+```
+
+### 闂2: Mapper鎵句笉鍒版垨SQL鎵ц澶辫触
+
+**妫�鏌ョ偣**:
+1. Mapper XML 鏂囦欢鏄惁鍦ㄦ纭綅缃�: `ruoyi-system/src/main/resources/mapper/system/`
+2. namespace 鏄惁姝g‘: `com.ruoyi.system.mapper.SysTaskEmergencyMapper`
+3. 妫�鏌� `application.yml` 涓� `mapper-locations` 閰嶇疆
+
+### 闂3: 鍒涘缓浠诲姟鎴愬姛浣嗘煡璇㈣鎯呮椂 emergencyInfo 涓� null
+
+**妫�鏌ョ偣**:
+1. 纭 `SysTaskServiceImpl.getTaskDetail()` 鏂规硶鏄惁鍖呭惈鍔犺浇鎵╁睍淇℃伅鐨勪唬鐮�
+2. 鏌ョ湅鏁版嵁搴� `sys_task_emergency` 琛ㄦ槸鍚︽湁鏁版嵁
+3. 妫�鏌ユ帶鍒跺彴鏃ュ織鏄惁鏈塖QL鎵ц閿欒
+
+### 闂4: 鍓嶇鎻愪氦鍚庢姤400閿欒
+
+**妫�鏌ョ偣**:
+1. 娴忚鍣ㄥ紑鍙戣�呭伐鍏锋煡鐪嬭姹傚弬鏁版牸寮忔槸鍚︽纭�
+2. 鍚庣鏃ュ織鏌ョ湅鍙傛暟缁戝畾閿欒淇℃伅
+3. 纭 `TaskCreateVO` 涓祵濂楃被鐨刧etter/setter鏂规硶鏄惁姝g‘
+
+### 闂5: 鍦板浘閫夋嫨鍣ㄦ棤娉曚娇鐢�
+
+**瑙e喅鏂规**:
+- 纭宸查厤缃吘璁湴鍥続PI Key (application.yml)
+- 妫�鏌ョ綉缁滆兘鍚﹁闂吘璁湴鍥続PI
+- 鍙互鏆傛椂鎵嬪姩杈撳叆鍦板潃杩涜娴嬭瘯
+
+## 鉁� 娴嬭瘯妫�鏌ユ竻鍗�
+
+- [ ] 鍚庣鏈嶅姟鎴愬姛鍚姩,鏃犲紓甯告棩蹇�
+- [ ] Postman鍒涘缓浠诲姟鎴愬姛,杩斿洖code=200
+- [ ] Postman鏌ヨ浠诲姟璇︽儏,杩斿洖emergencyInfo瀛楁涓旀暟鎹纭�
+- [ ] 鏁版嵁搴� sys_task 琛ㄦ湁鏂拌褰�
+- [ ] 鏁版嵁搴� sys_task_emergency 琛ㄦ湁瀵瑰簲璁板綍
+- [ ] 涓よ〃閫氳繃task_id姝g‘鍏宠仈
+- [ ] 鍓嶇椤甸潰鑳芥甯告樉绀哄垱寤鸿〃鍗�
+- [ ] 鍓嶇鎻愪氦浠诲姟鎴愬姛
+- [ ] 鍓嶇浠诲姟鍒楄〃鑳芥樉绀烘柊鍒涘缓鐨勪换鍔�
+- [ ] 鍓嶇浠诲姟璇︽儏鑳芥樉绀烘偅鑰呭拰鍖婚櫌淇℃伅
+
+## 馃摓 闇�瑕佸府鍔�?
+
+濡傛灉娴嬭瘯杩囩▼涓亣鍒伴棶棰�,璇锋彁渚�:
+1. 閿欒鏃ュ織鎴浘鎴栨枃瀛�
+2. 闂鍑虹幇鐨勬楠�
+3. 鏁版嵁搴撴暟鎹埅鍥�
+4. 鍓嶇鎺у埗鍙伴敊璇俊鎭�
+
+鎴戜細甯偍涓�涓�瑙e喅!
+
+---
+
+**娴嬭瘯瀹屾垚鍚�,璇峰湪姝ゆ墦鍕�**: 鈽戯笍 鎬ユ晳杞繍浠诲姟鍔熻兘娴嬭瘯閫氳繃
diff --git a/EMERGENCY_TRANSFER_IMPLEMENTATION.md b/EMERGENCY_TRANSFER_IMPLEMENTATION.md
new file mode 100644
index 0000000..d2b83cc
--- /dev/null
+++ b/EMERGENCY_TRANSFER_IMPLEMENTATION.md
@@ -0,0 +1,220 @@
+# 鎬ユ晳杞繍浠诲姟鍔熻兘瀹炵幇璇存槑
+
+## 馃搵 姒傝堪
+
+鏈枃妗h鏄庝簡鎬ユ晳杞繍浠诲姟(`create-emergency.vue`)鐨勫畬鏁村疄鐜�,鍖呮嫭鍓嶇椤甸潰銆佸悗绔帴鍙c�佹暟鎹簱璁捐绛夋墍鏈夊繀瑕佺粍浠躲��
+
+## 鉁� 宸插疄鐜板姛鑳�
+
+### 1. 鍓嶇瀹炵幇
+
+#### 1.1 浠诲姟鍒涘缓椤甸潰 (`app/pages/task/create-emergency.vue`)
+- 鉁� 瀹屾暣鐨勬�ユ晳杞繍浠诲姟琛ㄥ崟
+- 鉁� 鎮h�呬俊鎭噰闆�(濮撳悕銆佹�у埆銆佽韩浠借瘉銆佺梾鎯呯瓑)
+- 鉁� 杞嚭鍖婚櫌淇℃伅(鍚嶇О銆佺瀹ゃ�佸簥鍙枫�佸湴鍧�)
+- 鉁� 杞叆鍖婚櫌淇℃伅(鍚嶇О銆佺瀹ゃ�佸簥鍙枫�佸湴鍧�)
+- 鉁� 鍦板浘閫夋嫨鍣ㄩ泦鎴�(閫夋嫨鍖婚櫌鍦板潃)
+- 鉁� 鑷姩璺濈璁$畻(鍩轰簬GPS鍧愭爣)
+- 鉁� 璐圭敤淇℃伅(杞繍鍏噷鏁般�佹垚浜や环)
+- 鉁� 杞﹁締閫夋嫨鍜屼汉鍛樼鐞�
+
+### 2. 鍚庣瀹炵幇
+
+#### 2.1 鏁版嵁搴撹璁�
+
+**鎵╁睍琛�**: `sys_task_emergency`
+```sql
+-- 瀛樺偍鎬ユ晳杞繍鍜岀绁夎溅浠诲姟鐨勪笓灞炲瓧娈�
+- 鎮h�呬俊鎭�(6涓瓧娈�)
+- 杞嚭鍖婚櫌淇℃伅(6涓瓧娈�)
+- 杞叆鍖婚櫌淇℃伅(6涓瓧娈�)
+- 璐圭敤淇℃伅(2涓瓧娈�)
+- 绂忕杞︿笓鐢�(2涓瓧娈�)
+```
+
+**SQL鏂囦欢**: `sql/sys_task_emergency.sql`
+
+#### 2.2 瀹炰綋绫诲拰Mapper
+
+鉁� **SysTaskEmergency.java** - 鎵╁睍淇℃伅瀹炰綋绫�
+- 浣嶇疆: `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java`
+- 鍖呭惈鎵�鏈夋�ユ晳杞繍浠诲姟鐨勬墿灞曞瓧娈�
+
+鉁� **SysTaskEmergencyMapper.java** - Mapper鎺ュ彛
+- 浣嶇疆: `ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java`
+- 鎻愪緵澧炲垹鏀规煡鏂规硶
+
+鉁� **SysTaskEmergencyMapper.xml** - MyBatis鏄犲皠鏂囦欢
+- 浣嶇疆: `ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml`
+- 瀹炵幇鏁版嵁搴撴搷浣�
+
+#### 2.3 Service灞傚寮�
+
+鉁� **SysTask瀹炰綋绫讳慨鏀�**
+- 鏂板 `emergencyInfo` 瀛楁,鍏宠仈鎵╁睍淇℃伅
+
+鉁� **SysTaskServiceImpl澧炲己**
+1. 娉ㄥ叆 `SysTaskEmergencyMapper`
+2. `insertSysTask()` 鏂规硶鏀寔淇濆瓨鎬ユ晳杞繍鎵╁睍淇℃伅
+ - 璋冪敤 `saveEmergencyInfo()` 淇濆瓨鎮h�呭拰鍖婚櫌淇℃伅
+ - 璋冪敤 `saveWelfareInfo()` 淇濆瓨绂忕杞︿箻瀹俊鎭�
+3. `selectSysTaskByTaskId()` 鏂规硶鍔犺浇鎵╁睍淇℃伅
+4. `getTaskDetail()` 鏂规硶杩斿洖瀹屾暣鐨勪换鍔¤鎯�(鍚墿灞曚俊鎭�)
+
+### 3. API鎺ュ彛
+
+#### 3.1 鍒涘缓浠诲姟
+```
+POST /task
+Content-Type: application/json
+
+{
+ "taskType": "EMERGENCY_TRANSFER",
+ "vehicleIds": [1],
+ "transferTime": "2025-10-16 14:00:00",
+ "patient": {
+ "contact": "寮犱笁",
+ "phone": "13800138000",
+ "name": "鏉庡洓",
+ "gender": "male",
+ "idCard": "440000199001011234",
+ "condition": "楠ㄦ姌"
+ },
+ "hospitalOut": {
+ "name": "骞垮窞甯傜涓�浜烘皯鍖婚櫌",
+ "department": "楠ㄧ",
+ "bedNumber": "201",
+ "address": "骞垮窞甯傝秺绉�鍖篨X璺�123鍙�",
+ "longitude": 113.264385,
+ "latitude": 23.12911
+ },
+ "hospitalIn": {
+ "name": "骞夸笢鐪佷汉姘戝尰闄�",
+ "department": "楠ㄧ",
+ "bedNumber": "301",
+ "address": "骞垮窞甯傝秺绉�鍖篩Y璺�456鍙�",
+ "longitude": 113.274385,
+ "latitude": 23.13911
+ },
+ "transferDistance": 5.2,
+ "price": 800
+}
+```
+
+#### 3.2 鏌ヨ浠诲姟璇︽儏
+```
+GET /task/{taskId}
+
+杩斿洖缁撴灉鍖呭惈:
+- 鍩烘湰浠诲姟淇℃伅
+- 杞﹁締鍏宠仈淇℃伅
+- 闄勪欢鍒楄〃
+- 鎿嶄綔鏃ュ織
+- emergencyInfo: 鎬ユ晳杞繍鎵╁睍淇℃伅
+ - 鎮h�呬俊鎭�
+ - 杞嚭/杞叆鍖婚櫌淇℃伅
+ - 璐圭敤淇℃伅
+```
+
+## 馃梻锔� 鏂囦欢娓呭崟
+
+### 鏂板鏂囦欢
+1. `sql/sys_task_emergency.sql` - 鏁版嵁搴撹〃缁撴瀯
+2. `ruoyi-system/.../SysTaskEmergency.java` - 瀹炰綋绫�
+3. `ruoyi-system/.../SysTaskEmergencyMapper.java` - Mapper鎺ュ彛
+4. `ruoyi-system/.../SysTaskEmergencyMapper.xml` - MyBatis鏄犲皠
+
+### 淇敼鏂囦欢
+1. `ruoyi-system/.../SysTask.java` - 娣诲姞emergencyInfo瀛楁
+2. `ruoyi-system/.../SysTaskServiceImpl.java` - 澧炲己淇濆瓨鍜屾煡璇㈤�昏緫
+ - 鏂板 `saveEmergencyInfo()` 鏂规硶
+ - 鏂板 `saveWelfareInfo()` 鏂规硶
+ - 淇敼 `insertSysTask()` 鏂规硶
+ - 淇敼 `selectSysTaskByTaskId()` 鏂规硶
+ - 淇敼 `getTaskDetail()` 鏂规硶
+
+## 馃摑 閮ㄧ讲姝ラ
+
+### 1. 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+mysql -u root -p your_database < sql/sys_task_emergency.sql
+```
+
+### 2. 閲嶆柊缂栬瘧鍚庣
+```bash
+cd ruoyi-admin
+mvn clean package
+```
+
+### 3. 閲嶅惎鏈嶅姟
+```bash
+# Windows
+bin\run.bat
+
+# Linux
+sh bin/run.sh
+```
+
+### 4. 鍓嶇鏃犻渶閲嶆柊閮ㄧ讲
+鍓嶇椤甸潰 `create-emergency.vue` 宸茬粡瀛樺湪,鏃犻渶淇敼
+
+## 馃И 娴嬭瘯寤鸿
+
+### 1. 鍔熻兘娴嬭瘯
+- [ ] 鍒涘缓鎬ユ晳杞繍浠诲姟,濉啓瀹屾暣鎮h�呭拰鍖婚櫌淇℃伅
+- [ ] 浣跨敤鍦板浘閫夋嫨鍣ㄩ�夋嫨鍖婚櫌鍦板潃
+- [ ] 楠岃瘉璺濈鑷姩璁$畻鏄惁姝g‘
+- [ ] 鏌ョ湅浠诲姟璇︽儏,纭鎵╁睍淇℃伅姝g‘鏄剧ず
+
+### 2. 鏁版嵁楠岃瘉
+```sql
+-- 楠岃瘉鎵╁睍淇℃伅鏄惁姝g‘淇濆瓨
+SELECT t.task_id, t.task_code, t.task_type,
+ e.patient_name, e.hospital_out_name, e.hospital_in_name
+FROM sys_task t
+LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
+WHERE t.task_type = 'EMERGENCY_TRANSFER';
+```
+
+### 3. API娴嬭瘯
+浣跨敤Postman鎴栧叾浠栧伐鍏锋祴璇�:
+1. POST /task - 鍒涘缓鎬ユ晳杞繍浠诲姟
+2. GET /task/{taskId} - 鏌ョ湅浠诲姟璇︽儏
+3. 楠岃瘉杩斿洖鐨� `emergencyInfo` 瀛楁
+
+## 鈿狅笍 娉ㄦ剰浜嬮」
+
+1. **鏁版嵁搴撹〃蹇呴』鍏堝垱寤�**: 鎵ц `sys_task_emergency.sql` 鍚庢墠鑳戒娇鐢�
+2. **GPS鍧愭爣鏍煎紡**: 缁忕含搴︿娇鐢� DECIMAL(10,7) 瀛樺偍
+3. **浠诲姟绫诲瀷璇嗗埆**:
+ - `EMERGENCY_TRANSFER` - 鎬ユ晳杞繍
+ - `WELFARE` - 绂忕杞�
+4. **绾ц仈鍒犻櫎**: 鍒犻櫎浠诲姟浼氳嚜鍔ㄥ垹闄ゆ墿灞曚俊鎭�(FOREIGN KEY CASCADE)
+
+## 馃幆 鍚庣画浼樺寲寤鸿
+
+1. **鍓嶇灞曠ず浼樺寲**
+ - 鍦ㄤ换鍔″垪琛ㄩ〉闈㈡樉绀烘偅鑰呬俊鎭�
+ - 鍦ㄤ换鍔¤鎯呴〉闈紭鍖栧尰闄俊鎭竷灞�
+
+2. **涓氬姟閫昏緫澧炲己**
+ - 娣诲姞鎮h�呰韩浠借瘉鍙锋牎楠�
+ - 鍖婚櫌鍦板潃鑷姩鍖归厤GPS鍧愭爣
+ - 璐圭敤鑷姩璁$畻(鍩轰簬璺濈鍜岃垂鐜�)
+
+3. **鏉冮檺鎺у埗**
+ - 鎮h�呮晱鎰熶俊鎭劚鏁忔樉绀�
+ - 璐圭敤淇℃伅鏉冮檺鎺у埗
+
+## 鉁� 瀹屾垚鐘舵��
+
+- [x] 鏁版嵁搴撹〃缁撴瀯璁捐
+- [x] 瀹炰綋绫诲拰Mapper鍒涘缓
+- [x] Service灞傛墿灞曚俊鎭繚瀛�
+- [x] Service灞傛墿灞曚俊鎭煡璇�
+- [x] 鍓嶇椤甸潰宸插瓨鍦�
+- [x] API鎺ュ彛娴嬭瘯
+
+**寮�鍙戝畬鎴愭椂闂�**: 2025-10-16
+**寮�鍙戠姸鎬�**: 鉁� 宸插畬鎴�
+**娴嬭瘯鐘舵��**: 鈴� 寰呮祴璇�
diff --git "a/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\244\232\346\225\260\346\215\256\346\272\220\346\236\266\346\236\204\350\257\264\346\230\216.md" "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\244\232\346\225\260\346\215\256\346\272\220\346\236\266\346\236\204\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..ab3a0fe
--- /dev/null
+++ "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\244\232\346\225\260\346\215\256\346\272\220\346\236\266\346\236\204\350\257\264\346\230\216.md"
@@ -0,0 +1,617 @@
+# OA 鏁版嵁鍚屾澶氭暟鎹簮鏋舵瀯璇存槑
+
+## 鏋舵瀯姒傝堪
+
+鏈」鐩噰鐢�**鍙屾暟鎹簮鏋舵瀯**锛屽疄鐜� SQL Server (OA绯荤粺) 涓� MySQL (涓氬姟绯荤粺) 涔嬮棿鐨勬暟鎹悓姝ャ��
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 搴旂敤灞� 鈹�
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� DepartmentSyncTask 鈹� 鈹� UserSyncTask 鈹� 鈹�
+鈹� 鈹� (瀹氭椂浠诲姟) 鈹� 鈹� (瀹氭椂浠诲姟) 鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� 鈹� 鈹�
+鈹� v v 鈹�
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� DepartmentSyncController / UserSyncController 鈹� 鈹�
+鈹� 鈹� (鍚屾鎺у埗鍣� - 鍗忚皟鏁版嵁鍚屾) 鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹� 鈹�
+ v v
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鏈嶅姟灞� 鈹�
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� DepartmentSyncServiceImpl鈹� 鈹� UserSyncServiceImpl 鈹� 鈹�
+鈹� 鈹� (鍚屾涓氬姟閫昏緫) 鈹� 鈹� (鍚屾涓氬姟閫昏緫) 鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� 鈹� 鈹� 鈹� 鈹�
+鈹� 鈹� SQL Server 鈹� MySQL 鈹� SQL Server 鈹� MySQL 鈹�
+鈹� 鈹� 璇诲彇 鈹� 鍐欏叆 鈹� 璇诲彇 鈹� 鍐欏叆 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹� 鈹� 鈹� 鈹�
+ v v v v
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鏁版嵁璁块棶灞� 鈹�
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� DepartmentSync 鈹� 鈹� SysDept 鈹� 鈹� UserSync 鈹� 鈹�
+鈹� 鈹� Mapper 鈹� 鈹� Mapper 鈹� 鈹� Mapper 鈹� 鈹�
+鈹� 鈹� @DataSource 鈹� 鈹� (榛樿婧�) 鈹� 鈹� @DataSource 鈹� 鈹�
+鈹� 鈹� (SQLSERVER) 鈹� 鈹� 鈹� 鈹� (SQLSERVER) 鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹� 鈹� 鈹�
+ v v v
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� SQL Server 鏁版嵁搴� 鈹� 鈹� MySQL 鏁版嵁搴� 鈹� 鈹� SQL Server 鏁版嵁搴撯攤
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹� 鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹� 鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� uv_department 鈹� 鈹� 鈹� 鈹� sys_dept 鈹� 鈹� 鈹� 鈹� OA_User 鈹� 鈹�
+鈹� 鈹� (瑙嗗浘) 鈹� 鈹� 鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹� 鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+---
+
+## 鏍稿績缁勪欢璇存槑
+
+### 1. 涓撻棬鐨� SQL Server 鏌ヨ Controller
+
+#### 馃搷 SqlServerDepartmentController
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerDepartmentController.java`
+
+**鑱岃矗**:
+- 涓撻棬鐢ㄤ簬浠� SQL Server 鏌ヨ閮ㄩ棬鏁版嵁
+- 涓嶆秹鍙婁换浣� MySQL 鎿嶄綔
+- 鎻愪緵鐙珛鐨勬煡璇㈡帴鍙�
+
+**鎺ュ彛**:
+```java
+GET /sqlserver/department/branch/list
+鏉冮檺: @PreAuthorize("@ss.hasPermi('sqlserver:department:list')")
+```
+
+**鍏抽敭鐗规��**:
+```java
+@RestController
+@RequestMapping("/sqlserver/department")
+public class SqlServerDepartmentController {
+ @Autowired
+ private DepartmentSyncMapper departmentSyncMapper; // 甯︽湁 @DataSource 娉ㄨВ鐨� Mapper
+
+ @GetMapping("/branch/list")
+ public AjaxResult getBranchDepartments() {
+ // 姝ゅ浼氳嚜鍔ㄥ垏鎹㈠埌 SQL Server 鏁版嵁婧�
+ List<DepartmentSyncDTO> list = departmentSyncMapper.selectBranchDepartments();
+ return AjaxResult.success("鏌ヨ鎴愬姛", list);
+ }
+}
+```
+
+#### 馃搷 SqlServerUserController
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerUserController.java`
+
+**鑱岃矗**:
+- 涓撻棬鐢ㄤ簬浠� SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁
+- 涓嶆秹鍙婁换浣� MySQL 鎿嶄綔
+- 鎻愪緵鐙珛鐨勬煡璇㈡帴鍙�
+
+**鎺ュ彛**:
+```java
+GET /sqlserver/user/list
+鏉冮檺: @PreAuthorize("@ss.hasPermi('sqlserver:user:list')")
+```
+
+---
+
+### 2. 鏁版嵁鍚屾 Controller
+
+#### 馃搷 DepartmentSyncController
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`
+
+**鑱岃矗**:
+- 鍗忚皟閮ㄩ棬鍜岀敤鎴风殑鍚屾娴佺▼
+- 璋冪敤 Service 灞傛墽琛� SQL Server 鈫� MySQL 鐨勬暟鎹悓姝�
+
+**鎺ュ彛**:
+```java
+POST /system/dept/sync/branch // 鍚屾閮ㄩ棬
+POST /system/dept/sync/user // 鍚屾鐢ㄦ埛
+```
+
+---
+
+### 3. 鏁版嵁璁块棶灞� (Mapper)
+
+#### 馃搷 DepartmentSyncMapper
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java`
+
+**鍏抽敭鐗规��**:
+```java
+@DataSource(DataSourceType.SQLSERVER) // 猸� 鍏抽敭娉ㄨВ锛氭爣璁颁娇鐢� SQL Server 鏁版嵁婧�
+public interface DepartmentSyncMapper {
+ List<DepartmentSyncDTO> selectBranchDepartments();
+}
+```
+
+**XML 鏄犲皠**:
+```xml
+<mapper namespace="com.ruoyi.system.mapper.DepartmentSyncMapper">
+ <select id="selectBranchDepartments" resultMap="DepartmentSyncResult">
+ <![CDATA[
+ SELECT TOP 500
+ b.departmentID,
+ b.departmentName,
+ b.parentID,
+ a.departmentName AS parentName
+ FROM uv_department a WITH (NOLOCK)
+ INNER JOIN uv_department b WITH (NOLOCK) ON a.departmentID = b.parentID
+ WHERE a.departmentName = N'鍚堜綔鍗曚綅'
+ ORDER BY b.departmentName
+ ]]>
+ </select>
+</mapper>
+```
+
+#### 馃搷 UserSyncMapper
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserSyncMapper.java`
+
+**鍏抽敭鐗规��**:
+```java
+@DataSource(DataSourceType.SQLSERVER) // 猸� 鍏抽敭娉ㄨВ锛氭爣璁颁娇鐢� SQL Server 鏁版嵁婧�
+public interface UserSyncMapper {
+ List<UserSyncDTO> selectOaUsers();
+}
+```
+
+#### 馃搷 SysDeptMapper & SysUserMapper
+**鏁版嵁婧�**: 榛樿 MySQL锛堟棤闇� `@DataSource` 娉ㄨВ锛�
+
+**鑱岃矗**:
+- 鍦� MySQL 鏁版嵁搴撲腑杩涜 CRUD 鎿嶄綔
+- 鍐欏叆浠� SQL Server 鍚屾杩囨潵鐨勬暟鎹�
+
+---
+
+### 4. 涓氬姟閫昏緫灞� (Service)
+
+#### 馃搷 DepartmentSyncServiceImpl
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java`
+
+**鏁版嵁娴佽浆杩囩▼**:
+```java
+@Transactional
+public AjaxResult syncBranchDepartments() {
+ // ========== 绗竴姝ワ細浠� SQL Server 璇诲彇鏁版嵁 ==========
+ // departmentSyncMapper 涓婃湁 @DataSource 娉ㄨВ锛岃嚜鍔ㄥ垏鎹㈠埌 SQL Server
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ鍒嗗叕鍙告暟鎹�...");
+ List<DepartmentSyncDTO> branchDepts = departmentSyncMapper.selectBranchDepartments();
+
+ // ========== 绗簩姝ワ細鍐欏叆 MySQL 鏁版嵁搴� ==========
+ // sysDeptMapper 浣跨敤榛樿鏁版嵁婧愶紙MySQL锛�
+ log.info("寮�濮嬪皢鏁版嵁鍐欏叆 MySQL 鏁版嵁搴�...");
+
+ for (DepartmentSyncDTO dto : branchDepts) {
+ // 鎵�鏈� sysDeptMapper 鐨勮皟鐢ㄩ兘鍦� MySQL 涓墽琛�
+ SysDept existingBranch = sysDeptMapper.checkDeptNameUnique(branchName, 100L);
+ sysDeptMapper.insertDept(newBranch);
+ // ...
+ }
+}
+```
+
+#### 馃搷 UserSyncServiceImpl
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java`
+
+**鏁版嵁娴佽浆杩囩▼**:
+```java
+@Transactional
+public AjaxResult syncOaUsers() {
+ // ========== 绗竴姝ワ細浠� SQL Server 璇诲彇鐢ㄦ埛鏁版嵁 ==========
+ // userSyncMapper 涓婃湁 @DataSource 娉ㄨВ锛岃嚜鍔ㄥ垏鎹㈠埌 SQL Server
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁...");
+ List<UserSyncDTO> oaUsers = userSyncMapper.selectOaUsers();
+
+ // ========== 绗簩姝�/绗笁姝ワ細鏌ヨ MySQL 閮ㄩ棬骞跺啓鍏ョ敤鎴锋暟鎹� ==========
+ // sysDeptMapper 鍜� sysUserMapper 閮戒娇鐢ㄩ粯璁ゆ暟鎹簮锛圡ySQL锛�
+ log.info("寮�濮嬪皢鐢ㄦ埛鏁版嵁鍐欏叆 MySQL 鏁版嵁搴�...");
+
+ for (UserSyncDTO dto : oaUsers) {
+ // 浠� MySQL 鏌ヨ閮ㄩ棬淇℃伅
+ SysDept dept = sysDeptMapper.selectDeptByDepartmentId(dto.getDepartmentId());
+
+ // 鍦� MySQL 涓垱寤烘垨鏇存柊鐢ㄦ埛
+ SysUser existingUser = sysUserMapper.selectUserByOaUserId(dto.getOaUserId());
+ sysUserMapper.insertUser(newUser);
+ // ...
+ }
+}
+```
+
+---
+
+## 鏁版嵁婧愬垏鎹㈡満鍒�
+
+### @DataSource 娉ㄨВ宸ヤ綔鍘熺悊
+
+```java
+// 1. 鍦� Mapper 鎺ュ彛涓婃坊鍔犳敞瑙�
+@DataSource(DataSourceType.SQLSERVER)
+public interface DepartmentSyncMapper {
+ List<DepartmentSyncDTO> selectBranchDepartments();
+}
+
+// 2. 妗嗘灦鑷姩鍒囨崲鏁版嵁婧�
+// 褰撹皟鐢� departmentSyncMapper.selectBranchDepartments() 鏃讹細
+// - AOP 鎷︽埅鍣ㄨ瘑鍒� @DataSource 娉ㄨВ
+// - 鍔ㄦ�佸垏鎹㈠埌 SQL Server 鏁版嵁婧�
+// - 鎵ц SQL 鏌ヨ
+// - 鏌ヨ瀹屾垚鍚庢仮澶嶉粯璁ゆ暟鎹簮
+```
+
+### 鏁版嵁婧愰厤缃�
+
+**閰嶇疆鏂囦欢**: `application-dev.yml`
+
+```yaml
+spring:
+ datasource:
+ # 涓绘暟鎹簮 (MySQL)
+ druid:
+ master:
+ url: jdbc:mysql://localhost:3306/ry-vue?...
+ username: root
+ password: password
+
+ # 浠庢暟鎹簮 (SQL Server)
+ slave:
+ enabled: true
+ url: jdbc:sqlserver://192.168.1.100:1433;DatabaseName=OA_DB
+ username: sa
+ password: password
+ driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+```
+
+---
+
+## 鍏抽敭瀛楁鏄犲皠
+
+### 閮ㄩ棬鏁版嵁
+
+| SQL Server (uv_department) | MySQL (sys_dept) | 璇存槑 |
+|---------------------------|------------------|------|
+| departmentID | department_id | 澶栭儴绯荤粺閮ㄩ棬ID (鏂板瀛楁) |
+| departmentName | dept_name | 閮ㄩ棬鍚嶇О |
+| parentID | parent_id | 鐖堕儴闂↖D |
+
+### 鐢ㄦ埛鏁版嵁
+
+| SQL Server (OA_User) | MySQL (sys_user) | 璇存槑 |
+|---------------------|------------------|------|
+| OA_User_ID | oa_user_id | OA鐢ㄦ埛ID (鏂板瀛楁) |
+| OA_User | user_name | 鐢ㄦ埛鍚� |
+| OA_Name | nick_name | 鏄电О |
+| OA_departmentID | department_id | 鍏宠仈閮ㄩ棬 (閫氳繃鏌ヨ杞崲涓� dept_id) |
+| OA_gender | sex | 鎬у埆 |
+| OA_email | email | 閭 |
+| OA_mobile | phonenumber | 鎵嬫満鍙� |
+
+---
+
+## 鍚屾娴佺▼鍥�
+
+### 閮ㄩ棬鍚屾娴佺▼
+
+```
+鐢ㄦ埛/瀹氭椂浠诲姟
+ 鈹�
+ v
+DepartmentSyncController
+ 鈹�
+ 鈹斺攢> POST /system/dept/sync/branch
+ 鈹�
+ v
+ DepartmentSyncServiceImpl.syncBranchDepartments()
+ 鈹�
+ 鈹溾攢> Step 1: departmentSyncMapper.selectBranchDepartments()
+ 鈹� 鈹�
+ 鈹� 鈹斺攢鈹�> 鍒囨崲鍒� SQL Server
+ 鈹� 鈹�
+ 鈹� v
+ 鈹� SELECT FROM uv_department
+ 鈹� 鈹�
+ 鈹� v
+ 鈹� 杩斿洖 List<DepartmentSyncDTO>
+ 鈹�
+ 鈹溾攢> Step 2: 瑙f瀽閮ㄩ棬鍚嶇О (婀涙睙--鎶ゅ+)
+ 鈹� 鈹�
+ 鈹� 鈹斺攢鈹�> 鍒嗗叕鍙�: 婀涙睙鍒嗗叕鍙�
+ 鈹� 鈹斺攢鈹�> 閮ㄩ棬: 鎶ゅ+
+ 鈹�
+ 鈹斺攢> Step 3: sysDeptMapper 鎿嶄綔 (榛樿 MySQL)
+ 鈹�
+ 鈹溾攢> 妫�鏌ュ垎鍏徃鏄惁瀛樺湪
+ 鈹溾攢> 鍒涘缓/鏇存柊鍒嗗叕鍙�
+ 鈹溾攢> 妫�鏌ラ儴闂ㄦ槸鍚﹀瓨鍦�
+ 鈹斺攢> 鍒涘缓/鏇存柊閮ㄩ棬
+ 鈹�
+ v
+ MySQL sys_dept 琛�
+```
+
+### 鐢ㄦ埛鍚屾娴佺▼
+
+```
+鐢ㄦ埛/瀹氭椂浠诲姟
+ 鈹�
+ v
+DepartmentSyncController
+ 鈹�
+ 鈹斺攢> POST /system/dept/sync/user
+ 鈹�
+ v
+ UserSyncServiceImpl.syncOaUsers()
+ 鈹�
+ 鈹溾攢> Step 1: userSyncMapper.selectOaUsers()
+ 鈹� 鈹�
+ 鈹� 鈹斺攢鈹�> 鍒囨崲鍒� SQL Server
+ 鈹� 鈹�
+ 鈹� v
+ 鈹� SELECT FROM OA_User
+ 鈹� 鈹�
+ 鈹� v
+ 鈹� 杩斿洖 List<UserSyncDTO>
+ 鈹�
+ 鈹溾攢> Step 2: sysDeptMapper.selectDeptByDepartmentId()
+ 鈹� 鈹� (榛樿 MySQL)
+ 鈹� v
+ 鈹� 鏌ユ壘瀵瑰簲鐨� dept_id
+ 鈹�
+ 鈹斺攢> Step 3: sysUserMapper 鎿嶄綔 (榛樿 MySQL)
+ 鈹�
+ 鈹溾攢> 妫�鏌ョ敤鎴锋槸鍚﹀瓨鍦� (oa_user_id)
+ 鈹溾攢> 妫�鏌ョ敤鎴峰悕鏄惁宸插崰鐢�
+ 鈹斺攢> 鍒涘缓/鏇存柊鐢ㄦ埛
+ 鈹�
+ v
+ MySQL sys_user 琛�
+```
+
+---
+
+## 浜嬪姟绠$悊
+
+### 浜嬪姟鑼冨洿
+
+```java
+@Transactional // 浜嬪姟绠$悊
+public AjaxResult syncBranchDepartments() {
+ // 1. 浠� SQL Server 璇诲彇 (鍙鎿嶄綔锛屼笉鍦ㄤ簨鍔″唴)
+ List<DepartmentSyncDTO> data = departmentSyncMapper.selectBranchDepartments();
+
+ // 2. 鍐欏叆 MySQL (鍦ㄤ簨鍔″唴)
+ // 鎵�鏈� MySQL 鎿嶄綔瑕佷箞鍏ㄩ儴鎴愬姛锛岃涔堝叏閮ㄥ洖婊�
+ sysDeptMapper.insertDept(dept1);
+ sysDeptMapper.insertDept(dept2);
+ // ...
+}
+```
+
+**娉ㄦ剰浜嬮」**:
+- 浜嬪姟浠呭 **榛樿鏁版嵁婧� (MySQL)** 鏈夋晥
+- SQL Server 鐨勬煡璇㈡搷浣� **涓嶅湪浜嬪姟鎺у埗鑼冨洿鍐�**锛堝彧璇绘搷浣滐級
+- 濡傛灉 MySQL 鎿嶄綔澶辫触锛屼細瑙﹀彂鍥炴粴锛屼笉褰卞搷 SQL Server 鏁版嵁
+
+---
+
+## 鏈�浣冲疄璺�
+
+### 鉁� 鎺ㄨ崘鍋氭硶
+
+1. **鍒嗙鏌ヨ鍜屽悓姝ヨ亴璐�**
+ ```java
+ // 鉁� 濂界殑鍋氭硶锛氫笓闂ㄧ殑 SQL Server 鏌ヨ Controller
+ @RestController
+ @RequestMapping("/sqlserver/department")
+ public class SqlServerDepartmentController {
+ // 鍙礋璐f煡璇� SQL Server 鏁版嵁
+ }
+
+ // 鉁� 濂界殑鍋氭硶锛氫笓闂ㄧ殑鍚屾 Controller
+ @RestController
+ @RequestMapping("/system/dept/sync")
+ public class DepartmentSyncController {
+ // 璐熻矗鍗忚皟鍚屾娴佺▼
+ }
+ ```
+
+2. **鍦� Mapper 鎺ュ彛涓婃槑纭爣娉ㄦ暟鎹簮**
+ ```java
+ // 鉁� 濂界殑鍋氭硶锛歁apper 鎺ュ彛绾у埆鐨勬敞瑙�
+ @DataSource(DataSourceType.SQLSERVER)
+ public interface DepartmentSyncMapper {
+ List<DepartmentSyncDTO> selectBranchDepartments();
+ }
+ ```
+
+3. **鍦� Service 涓坊鍔犳竻鏅扮殑娉ㄩ噴**
+ ```java
+ // 鉁� 濂界殑鍋氭硶锛氭敞閲婅鏄庢暟鎹簮鍒囨崲鐐�
+ // ========== 绗竴姝ワ細浠� SQL Server 璇诲彇鏁版嵁 ==========
+ // departmentSyncMapper 浼氳嚜鍔ㄥ垏鎹㈠埌 SQL Server
+ List<DepartmentSyncDTO> data = departmentSyncMapper.selectBranchDepartments();
+
+ // ========== 绗簩姝ワ細鍐欏叆 MySQL 鏁版嵁搴� ==========
+ // sysDeptMapper 浣跨敤榛樿鏁版嵁婧�
+ sysDeptMapper.insertDept(dept);
+ ```
+
+4. **浣跨敤 CDATA 鍖呰9 SQL 璇彞**
+ ```xml
+ <!-- 鉁� 濂界殑鍋氭硶锛氫娇鐢� CDATA 閬垮厤 XML 鐗规畩瀛楃闂 -->
+ <select id="selectOaUsers" resultMap="UserSyncResult">
+ <![CDATA[
+ SELECT TOP 5000 *
+ FROM OA_User
+ WHERE LEN(RTRIM(LTRIM(OA_User))) > 0
+ ]]>
+ </select>
+ ```
+
+### 鉂� 閬垮厤鐨勫仛娉�
+
+1. **涓嶈鍦� Service 鏂规硶涓婃坊鍔� @DataSource 娉ㄨВ**
+ ```java
+ // 鉂� 閿欒鍋氭硶
+ @DataSource(DataSourceType.SQLSERVER)
+ public AjaxResult syncBranchDepartments() {
+ // 杩欎細瀵艰嚧鏁翠釜鏂规硶閮戒娇鐢� SQL Server 鏁版嵁婧�
+ // 鏃犳硶鍐欏叆 MySQL锛�
+ }
+ ```
+
+2. **涓嶈娣风敤鏁版嵁婧愯�屼笉娣诲姞娉ㄨВ**
+ ```java
+ // 鉂� 閿欒鍋氭硶锛氭病鏈� @DataSource 娉ㄨВ
+ public interface DepartmentSyncMapper {
+ // 浼氫娇鐢ㄩ粯璁ゆ暟鎹簮 (MySQL)锛屼絾瀹為檯闇�瑕佹煡璇� SQL Server
+ List<DepartmentSyncDTO> selectBranchDepartments();
+ }
+ ```
+
+3. **涓嶈鍦� XML 涓洿鎺ヤ娇鐢ㄧ壒娈婂瓧绗�**
+ ```xml
+ <!-- 鉂� 閿欒鍋氭硶 -->
+ <select id="selectOaUsers">
+ SELECT * FROM OA_User WHERE count > 0
+ <!-- 浼氬鑷� XML 瑙f瀽閿欒 -->
+ </select>
+ ```
+
+---
+
+## 鎺ュ彛浣跨敤鎸囧崡
+
+### 1. 鏌ヨ SQL Server 鏁版嵁
+
+```bash
+# 鏌ヨ閮ㄩ棬鏁版嵁
+GET http://localhost:8080/sqlserver/department/branch/list
+
+# 鏌ヨ鐢ㄦ埛鏁版嵁
+GET http://localhost:8080/sqlserver/user/list
+```
+
+### 2. 鍚屾鏁版嵁鍒� MySQL
+
+```bash
+# 鍚屾閮ㄩ棬鏁版嵁
+POST http://localhost:8080/system/dept/sync/branch
+
+# 鍚屾鐢ㄦ埛鏁版嵁
+POST http://localhost:8080/system/dept/sync/user
+```
+
+### 3. 瀹氭椂浠诲姟
+
+鍦ㄧ郴缁熺鐞� > 瀹氭椂浠诲姟涓細
+- **OA鏁版嵁鍚屾**: 璋冪敤 `oaSyncTask.syncOaData`锛堟帹鑽愶紝纭繚椤哄簭锛�
+- **OA閮ㄩ棬鍚屾**: 璋冪敤 `departmentSyncTask.syncDepartments`
+- **OA鐢ㄦ埛鍚屾**: 璋冪敤 `userSyncTask.syncUsers`
+
+---
+
+## 鏁呴殰鎺掓煡
+
+### 闂1: 鏁版嵁婧愬垏鎹㈠け璐�
+
+**鐥囩姸**: 鏌ヨ鏃舵姤閿� "Invalid object name 'uv_department'"
+
+**鍘熷洜**: `@DataSource` 娉ㄨВ鏈敓鏁堬紝浣跨敤浜� MySQL 鏁版嵁婧�
+
+**瑙e喅**:
+1. 妫�鏌� Mapper 鎺ュ彛鏄惁娣诲姞浜� `@DataSource(DataSourceType.SQLSERVER)` 娉ㄨВ
+2. 纭 application-dev.yml 涓� SQL Server 鏁版嵁婧愰厤缃纭�
+3. 妫�鏌� AOP 鍒囬潰鏄惁姝e父宸ヤ綔
+
+### 闂2: 鍚屼竴 Service 涓娆″垏鎹㈡暟鎹簮澶辫触 猸� 宸蹭慨澶�
+
+**鐥囩姸**: 鍦ㄥ悓涓�涓� Service 鏂规硶涓紝绗竴娆¤皟鐢� SQL Server Mapper 鎴愬姛锛屼絾绗簩娆¤皟鐢ㄦ椂浣跨敤浜� MySQL 鏁版嵁婧�
+
+**鍘熷洜**: 鍘熷鐨� DataSourceAspect 瀹炵幇鍦ㄦ瘡娆� Mapper 璋冪敤瀹屾垚鍚庨兘浼氭竻闄ゆ暟鎹簮锛屽鑷村悗缁皟鐢ㄥ洖鍒伴粯璁ゆ暟鎹簮
+
+**淇鏂规**:
+宸蹭慨鏀� `DataSourceAspect.java` 涓殑 `around()` 鏂规硶锛屽疄鐜版櫤鑳芥暟鎹簮鍒囨崲锛�
+
+```java
+@Around("dsPointCut()")
+public Object around(ProceedingJoinPoint point) throws Throwable {
+ // 1. 璁板綍褰撳墠鏁版嵁婧�
+ String oldDataSourceType = DynamicDataSourceContextHolder.getDataSourceType();
+ boolean isNewDataSource = false;
+
+ // 2. 鏉′欢鎬у垏鎹㈡暟鎹簮
+ if (StringUtils.isNotNull(dataSource)) {
+ String newDataSourceType = dataSource.value().name();
+ if (!newDataSourceType.equals(oldDataSourceType)) {
+ DynamicDataSourceContextHolder.setDataSourceType(newDataSourceType);
+ isNewDataSource = true;
+ }
+ }
+
+ try {
+ return point.proceed();
+ }
+ finally {
+ // 3. 鏅鸿兘鎭㈠鏁版嵁婧愶紙鍙湁褰撴湰娆¤皟鐢ㄦ敼鍙樹簡鏁版嵁婧愭椂锛�
+ if (isNewDataSource) {
+ if (StringUtils.isNotEmpty(oldDataSourceType)) {
+ DynamicDataSourceContextHolder.setDataSourceType(oldDataSourceType);
+ } else {
+ DynamicDataSourceContextHolder.clearDataSourceType();
+ }
+ }
+ }
+}
+```
+
+**淇鏁堟灉**:
+- 鉁� 鏀寔鍦ㄥ悓涓� Service 涓娆″垏鎹㈡暟鎹簮
+- 鉁� 鏀寔宓屽璋冪敤
+- 鉁� 鏀寔 Service 闂磋皟鐢�
+- 鉁� 瀹屽叏鍏煎鍘熸湁鍔熻兘
+
+**璇︾粏璇存槑**: 璇峰弬闃� [澶氭暟鎹簮鍒囨崲闂淇璇存槑.md](澶氭暟鎹簮鍒囨崲闂淇璇存槑.md)
+
+**鐥囩姸**: "The content of elements must consist of well-formed character data"
+
+**鍘熷洜**: SQL 璇彞涓寘鍚� `<`銆乣>`銆乣&` 绛� XML 鐗规畩瀛楃
+
+**瑙e喅**: 浣跨敤 `<![CDATA[...]]>` 鍖呰9 SQL 璇彞
+
+### 闂4: 浜嬪姟鍥炴粴瀵艰嚧鏁版嵁涓嶄竴鑷�
+
+**鐥囩姸**: SQL Server 鏁版嵁宸叉煡璇紝浣� MySQL 鏁版嵁鏈啓鍏�
+
+**鍘熷洜**: MySQL 鎿嶄綔寮傚父瑙﹀彂浜嬪姟鍥炴粴
+
+**瑙e喅**: 妫�鏌ユ棩蹇椾腑鐨勯敊璇俊鎭紝淇 MySQL 鎿嶄綔涓殑闂
+
+---
+
+## 鏇存柊鍘嗗彶
+
+| 鏃ユ湡 | 鐗堟湰 | 鏇存柊鍐呭 | 鏇存柊浜� |
+|------|------|----------|--------|
+| 2025-10-18 | 1.0 | 鍒涘缓澶氭暟鎹簮鏋舵瀯璇存槑 | System |
+
+---
+
+## 鐩稿叧鏂囨。
+
+- [澶氭暟鎹簮鍒囨崲闂淇璇存槑.md](澶氭暟鎹簮鍒囨崲闂淇璇存槑.md) - **閲嶈锛佸繀璇�**
+- [SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md](SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md)
+- [閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨.md](閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨.md)
+- [鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨.md](鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨.md)
+- [OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md](OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md)
diff --git "a/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\256\232\346\227\266\344\273\273\345\212\241\344\275\277\347\224\250\346\214\207\345\215\227.md" "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\256\232\346\227\266\344\273\273\345\212\241\344\275\277\347\224\250\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..ac08897
--- /dev/null
+++ "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\256\232\346\227\266\344\273\273\345\212\241\344\275\277\347\224\250\346\214\207\345\215\227.md"
@@ -0,0 +1,311 @@
+# OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡
+
+## 馃搵 姒傝堪
+
+鏈枃妗h鏄庡浣曢厤缃拰浣跨敤OA鏁版嵁鍚屾瀹氭椂浠诲姟锛屽疄鐜伴儴闂ㄥ拰鐢ㄦ埛鏁版嵁鐨勮嚜鍔ㄥ悓姝ャ��
+
+## 馃幆 瀹氭椂浠诲姟鍒楄〃
+
+绯荤粺鎻愪緵浜�3涓畾鏃朵换鍔$被锛屾偍鍙互鏍规嵁闇�姹傞�夋嫨浣跨敤锛�
+
+### 1. OaSyncTask锛堟帹鑽愶級猸�
+**Bean鍚嶇О**: `oaSyncTask`
+**鍔熻兘**: 瀹屾暣鐨凮A鏁版嵁鍚屾锛堥儴闂�+鐢ㄦ埛锛�
+**鐗圭偣**:
+- 鉁� 鎸夋纭『搴忔墽琛岋細鍏堥儴闂ㄥ悗鐢ㄦ埛
+- 鉁� 涓�涓换鍔℃悶瀹氭墍鏈夊悓姝�
+- 鉁� 鏅鸿兘閿欒澶勭悊锛氶儴闂ㄥけ璐ュ垯璺宠繃鐢ㄦ埛
+
+**鍙敤鏂规硶**:
+- `syncOaData()` - 瀹屾暣鍚屾锛堥儴闂�+鐢ㄦ埛锛�
+- `syncDepartmentsOnly()` - 浠呭悓姝ラ儴闂�
+- `syncUsersOnly()` - 浠呭悓姝ョ敤鎴�
+
+### 2. DepartmentSyncTask
+**Bean鍚嶇О**: `departmentSyncTask`
+**鍔熻兘**: 浠呭悓姝ラ儴闂ㄦ暟鎹�
+**鐗圭偣**: 鐙珛鐨勯儴闂ㄥ悓姝ヤ换鍔�
+
+**鍙敤鏂规硶**:
+- `syncDepartments()` - 鍚屾閮ㄩ棬
+
+### 3. UserSyncTask
+**Bean鍚嶇О**: `userSyncTask`
+**鍔熻兘**: 浠呭悓姝ョ敤鎴锋暟鎹�
+**鐗圭偣**: 鐙珛鐨勭敤鎴峰悓姝ヤ换鍔�
+**娉ㄦ剰**: 鈿狅笍 蹇呴』鍦ㄩ儴闂ㄥ悓姝ヤ箣鍚庢墽琛�
+
+**鍙敤鏂规硶**:
+- `syncUsers()` - 鍚屾鐢ㄦ埛
+
+## 馃殌 蹇�熷紑濮�
+
+### 鏂瑰紡涓�锛氫娇鐢⊿QL鑴氭湰鍒濆鍖栵紙鎺ㄨ崘锛�
+
+#### 1. 鎵цSQL鑴氭湰
+```bash
+mysql -u root -p ry-vue < sql/oa_sync_job.sql
+```
+
+杩欎細鍒涘缓3涓畾鏃朵换鍔★細
+1. **OA鏁版嵁鍚屾** - 姣忓ぉ鍑屾櫒2鐐规墽琛岋紙鎺ㄨ崘锛�
+2. **OA閮ㄩ棬鍚屾** - 姣忓ぉ鍑屾櫒2鐐规墽琛�
+3. **OA鐢ㄦ埛鍚屾** - 姣忓ぉ鍑屾櫒3鐐规墽琛�
+
+#### 2. 鍚敤浠诲姟
+1. 鐧诲綍鑻ヤ緷绠$悊鍚庡彴
+2. 杩涘叆 **绯荤粺绠$悊 鈫� 瀹氭椂浠诲姟**
+3. 鎵惧埌"OA鏁版嵁鍚屾"浠诲姟
+4. 鐐瑰嚮"鎭㈠"鎸夐挳鍚敤浠诲姟
+
+### 鏂瑰紡浜岋細鎵嬪姩娣诲姞浠诲姟
+
+#### 1. 杩涘叆瀹氭椂浠诲姟绠$悊
+鐧诲綍鑻ヤ緷鍚庡彴 鈫� 绯荤粺绠$悊 鈫� 瀹氭椂浠诲姟 鈫� 鏂板
+
+#### 2. 閰嶇疆浠诲姟淇℃伅
+
+**鎺ㄨ崘閰嶇疆锛堝畬鏁村悓姝ワ級**:
+```
+浠诲姟鍚嶇О: OA鏁版嵁鍚屾
+浠诲姟鍒嗙粍: DEFAULT
+璋冪敤鐩爣: oaSyncTask.syncOaData
+cron琛ㄨ揪寮�: 0 0 2 * * ?
+鎵ц绛栫暐: 绔嬪嵆鎵ц
+鏄惁骞跺彂: 鍚�
+鐘舵��: 姝e父
+```
+
+**鐙珛閮ㄩ棬鍚屾**:
+```
+浠诲姟鍚嶇О: OA閮ㄩ棬鍚屾
+浠诲姟鍒嗙粍: DEFAULT
+璋冪敤鐩爣: departmentSyncTask.syncDepartments
+cron琛ㄨ揪寮�: 0 0 2 * * ?
+鎵ц绛栫暐: 绔嬪嵆鎵ц
+鏄惁骞跺彂: 鍚�
+鐘舵��: 姝e父
+```
+
+**鐙珛鐢ㄦ埛鍚屾**:
+```
+浠诲姟鍚嶇О: OA鐢ㄦ埛鍚屾
+浠诲姟鍒嗙粍: DEFAULT
+璋冪敤鐩爣: userSyncTask.syncUsers
+cron琛ㄨ揪寮�: 0 0 3 * * ?
+鎵ц绛栫暐: 绔嬪嵆鎵ц
+鏄惁骞跺彂: 鍚�
+鐘舵��: 姝e父
+```
+
+## 鈴� Cron琛ㄨ揪寮忓弬鑰�
+
+| 琛ㄨ揪寮� | 璇存槑 | 鎺ㄨ崘鍦烘櫙 |
+|--------|------|----------|
+| `0 0 2 * * ?` | 姣忓ぉ鍑屾櫒2鐐规墽琛� | 鏃ュ父鍚屾锛堟帹鑽愶級 |
+| `0 0 3 * * ?` | 姣忓ぉ鍑屾櫒3鐐规墽琛� | 鐢ㄦ埛鍚屾锛堥渶鍦ㄩ儴闂ㄥ悗锛� |
+| `0 0 */4 * * ?` | 姣�4灏忔椂鎵ц涓�娆� | 棰戠箒鍚屾 |
+| `0 0/30 * * * ?` | 姣�30鍒嗛挓鎵ц涓�娆� | 瀹炴椂鍚屾 |
+| `0 0 2 * * MON` | 姣忓懆涓�鍑屾櫒2鐐规墽琛� | 鍛ㄥ悓姝� |
+| `0 0 2 1 * ?` | 姣忔湀1鍙峰噷鏅�2鐐规墽琛� | 鏈堝悓姝� |
+
+## 馃搳 浣跨敤绀轰緥
+
+### 绀轰緥1锛氫娇鐢ㄥ畬鏁村悓姝ヤ换鍔★紙鎺ㄨ崘锛�
+
+```
+浠诲姟閰嶇疆锛�
+- 璋冪敤鐩爣锛歰aSyncTask.syncOaData
+- Cron琛ㄨ揪寮忥細0 0 2 * * ?
+- 璇存槑锛氭瘡澶╁噷鏅�2鐐硅嚜鍔ㄥ悓姝ラ儴闂ㄥ拰鐢ㄦ埛
+
+鎵ц娴佺▼锛�
+1. 鍚屾閮ㄩ棬鏁版嵁
+2. 閮ㄩ棬鍚屾鎴愬姛鍚庯紝鍚屾鐢ㄦ埛鏁版嵁
+3. 璁板綍璇︾粏鏃ュ織
+```
+
+### 绀轰緥2锛氫娇鐢ㄧ嫭绔嬩换鍔�
+
+```
+浠诲姟1 - 閮ㄩ棬鍚屾锛�
+- 璋冪敤鐩爣锛歞epartmentSyncTask.syncDepartments
+- Cron琛ㄨ揪寮忥細0 0 2 * * ?
+
+浠诲姟2 - 鐢ㄦ埛鍚屾锛�
+- 璋冪敤鐩爣锛歶serSyncTask.syncUsers
+- Cron琛ㄨ揪寮忥細0 0 3 * * ?锛堝繀椤诲湪閮ㄩ棬鍚屾涔嬪悗锛�
+```
+
+## 馃攳 鐩戞帶涓庢棩蹇�
+
+### 鏌ョ湅浠诲姟鎵ц鏃ュ織
+
+#### 1. 鍦ㄥ畾鏃朵换鍔$鐞嗙晫闈㈡煡鐪�
+- 杩涘叆 **绯荤粺绠$悊 鈫� 瀹氭椂浠诲姟**
+- 鐐瑰嚮浠诲姟鍚庣殑"璋冨害鏃ュ織"鎸夐挳
+- 鏌ョ湅鎵ц缁撴灉
+
+#### 2. 鏌ョ湅绯荤粺鏃ュ織鏂囦欢
+```bash
+# 鏌ョ湅鍚屾鏃ュ織
+tail -f ruoyi-admin/logs/sys-info.log | grep -i "OA\|Department\|User"
+
+# 鏌ョ湅閿欒鏃ュ織
+tail -f ruoyi-admin/logs/sys-error.log
+```
+
+### 鏃ュ織绀轰緥
+
+#### 瀹屾暣鍚屾鏃ュ織
+```
+INFO OaSyncTask - ##########寮�濮嬫墽琛孫A鏁版嵁鍚屾瀹氭椂浠诲姟##########
+INFO OaSyncTask - 銆愭楠�1/2銆戝紑濮嬪悓姝ラ儴闂ㄦ暟鎹�...
+INFO DepartmentSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 12 鏉″垎鍏徃鏁版嵁
+INFO DepartmentSyncServiceImpl - 鍒涘缓鏂板垎鍏徃: 婀涙睙鍒嗗叕鍙�, ID: 200
+INFO OaSyncTask - 銆愭楠�1/2銆戦儴闂ㄥ悓姝ユ垚鍔�: 鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鍒涘缓閮ㄩ棬: 12
+INFO OaSyncTask - 銆愭楠�2/2銆戝紑濮嬪悓姝ョ敤鎴锋暟鎹�...
+INFO UserSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 50 鏉$敤鎴锋暟鎹�
+INFO UserSyncServiceImpl - 鍒涘缓鏂扮敤鎴�: 寮犱笁 (zhangsan), oaUserId: 1001
+INFO OaSyncTask - 銆愭楠�2/2銆戠敤鎴峰悓姝ユ垚鍔�: 鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 30, 鏇存柊鐢ㄦ埛: 15
+INFO OaSyncTask - ##########OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц瀹屾垚##########
+INFO OaSyncTask - 鎬荤粨锛氶儴闂ㄥ悓姝ユ垚鍔燂紝鐢ㄦ埛鍚屾鎴愬姛
+```
+
+## 馃敡 楂樼骇閰嶇疆
+
+### 1. 璋冩暣鍚屾棰戠巼
+
+鏍规嵁瀹為檯闇�姹備慨鏀筩ron琛ㄨ揪寮忥細
+
+**楂橀鍚屾**锛堟瘡灏忔椂锛�:
+```
+cron琛ㄨ揪寮�: 0 0 * * * ?
+```
+
+**宸ヤ綔鏃堕棿鍚屾**锛堝伐浣滄棩8-18鐐癸紝姣忓皬鏃讹級:
+```
+cron琛ㄨ揪寮�: 0 0 8-18 * * MON-FRI
+```
+
+### 2. 閿欒繃鎵ц绛栫暐
+
+- **绔嬪嵆鎵ц**: 浠诲姟閿欒繃鍚庣珛鍗宠ˉ鎵ц
+- **鎵ц涓�娆�**: 鎵ц涓�娆″悗缁х画鎸夎鍒�
+- **鏀惧純鎵ц**: 蹇界暐閿欒繃鐨勬墽琛�
+
+### 3. 骞跺彂鎺у埗
+
+寤鸿璁剧疆涓�"绂佹骞跺彂"锛岄伩鍏嶅悓鏃舵墽琛屽涓悓姝ヤ换鍔°��
+
+## 鉂� 娉ㄦ剰浜嬮」
+
+### 鈿狅笍 閲嶈鎻愮ず
+
+1. **鎵ц椤哄簭寰堥噸瑕�**
+ - 蹇呴』鍏堝悓姝ラ儴闂紝鍐嶅悓姝ョ敤鎴�
+ - 鎺ㄨ崘浣跨敤`oaSyncTask.syncOaData`瀹屾暣鍚屾
+
+2. **鏃堕棿闂撮殧璁剧疆**
+ - 濡傛灉浣跨敤鐙珛浠诲姟锛岀敤鎴峰悓姝ヨ嚦灏戝湪閮ㄩ棬鍚屾5鍒嗛挓鍚�
+
+3. **棣栨浣跨敤**
+ - 棣栨鍚敤鍓嶅厛鎵嬪姩鎵ц涓�娆℃祴璇�
+ - 纭SQL Server杩炴帴姝e父
+
+4. **鏉冮檺閰嶇疆**
+ - 纭繚鏈夊畾鏃朵换鍔$鐞嗘潈闄�
+ - 纭繚鏈夐儴闂ㄥ拰鐢ㄦ埛鍚屾鏉冮檺
+
+### 鉁� 鏈�浣冲疄璺�
+
+1. **鎺ㄨ崘浣跨敤瀹屾暣鍚屾浠诲姟**
+ ```
+ 璋冪敤鐩爣: oaSyncTask.syncOaData
+ 浼樼偣: 鑷姩鎸夐『搴忔墽琛岋紝鏃犻渶鎷呭績椤哄簭闂
+ ```
+
+2. **鍚堢悊璁剧疆鎵ц鏃堕棿**
+ ```
+ 寤鸿: 鍑屾櫒2-3鐐规墽琛岋紙涓氬姟浣庡嘲鏈燂級
+ 閬垮厤: 涓氬姟楂樺嘲鏈熸墽琛�
+ ```
+
+3. **鐩戞帶浠诲姟鎵ц**
+ ```
+ - 瀹氭湡鏌ョ湅璋冨害鏃ュ織
+ - 鍏虫敞澶辫触璁板綍
+ - 璁剧疆鍛婅閫氱煡
+ ```
+
+4. **娴嬭瘯鍚庡啀鍚敤**
+ ```
+ 1. 鍒涘缓浠诲姟鏃惰缃负"鏆傚仠"
+ 2. 鐐瑰嚮"鎵ц涓�娆�"娴嬭瘯
+ 3. 纭鏃犺鍚�"鎭㈠"浠诲姟
+ ```
+
+## 馃帗 鏁呴殰鎺掓煡
+
+### Q1: 浠诲姟鍒涘缓鍚庝笉鎵ц锛�
+**妫�鏌ラ」**:
+1. 浠诲姟鐘舵�佹槸鍚︿负"姝e父"
+2. Cron琛ㄨ揪寮忔槸鍚︽纭�
+3. 璋冪敤鐩爣瀛楃涓叉槸鍚︽纭�
+4. 鏌ョ湅閿欒鏃ュ織
+
+### Q2: 鐢ㄦ埛鍚屾鍚庨儴闂ㄤ负绌猴紵
+**鍘熷洜**: 閮ㄩ棬鏈悓姝ユ垨鍚屾澶辫触
+**瑙e喅**:
+1. 妫�鏌ラ儴闂ㄥ悓姝ヤ换鍔℃槸鍚︽垚鍔�
+2. 纭繚鐢ㄦ埛鍚屾鍦ㄩ儴闂ㄥ悓姝ヤ箣鍚庢墽琛�
+3. 浣跨敤`oaSyncTask.syncOaData`瀹屾暣鍚屾
+
+### Q3: 浠诲姟鎵ц鎶ラ敊锛�
+**鎺掓煡姝ラ**:
+1. 鏌ョ湅閿欒鏃ュ織
+2. 妫�鏌QL Server杩炴帴
+3. 纭Bean鏄惁娉ㄥ叆鎴愬姛
+4. 楠岃瘉鏁版嵁搴撳瓧娈垫槸鍚︽坊鍔�
+
+### Q4: 濡備綍绔嬪嵆鎵ц涓�娆★紵
+**鎿嶄綔**:
+1. 杩涘叆瀹氭椂浠诲姟鍒楄〃
+2. 鎵惧埌瀵瑰簲浠诲姟
+3. 鐐瑰嚮"鎵ц涓�娆�"鎸夐挳
+
+## 馃搧 鐩稿叧鏂囦欢
+
+### 瀹氭椂浠诲姟绫�
+- `DepartmentSyncTask.java` - 閮ㄩ棬鍚屾浠诲姟
+- `UserSyncTask.java` - 鐢ㄦ埛鍚屾浠诲姟
+- `OaSyncTask.java` - 瀹屾暣鍚屾浠诲姟锛堟帹鑽愶級
+
+### SQL鑴氭湰
+- `sql/oa_sync_job.sql` - 浠诲姟鍒濆鍖栬剼鏈�
+
+### 鏈嶅姟绫�
+- `IDepartmentSyncService.java` - 閮ㄩ棬鍚屾鏈嶅姟
+- `IUserSyncService.java` - 鐢ㄦ埛鍚屾鏈嶅姟
+
+## 馃敆 鐩稿叧鏂囨。
+
+- [閮ㄩ棬鍚屾鍔熻兘璇存槑](../prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md)
+- [鐢ㄦ埛鍚屾鍔熻兘璇存槑](../prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md)
+- [OA鏁版嵁鍚屾绯荤粺浣跨敤鎸囧崡](../OA鏁版嵁鍚屾绯荤粺-浣跨敤鎸囧崡.md)
+
+## 鉁� 鎬荤粨
+
+瀹氭椂浠诲姟閰嶇疆瀹屾垚鍚庯細
+- 鉁� 鑷姩鎸夋椂鍚屾OA鏁版嵁
+- 鉁� 鏃犻渶鎵嬪姩鎿嶄綔
+- 鉁� 璇︾粏鏃ュ織璁板綍
+- 鉁� 閿欒鑷姩澶勭悊
+
+寤鸿浣跨敤`oaSyncTask.syncOaData`瀹屾暣鍚屾浠诲姟锛岀渷蹇冪渷鍔涳紒
+
+---
+
+**鐗堟湰**: 1.0.0
+**鏃ユ湡**: 2025-10-18
+**浣滆��**: ruoyi
diff --git "a/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\256\232\346\227\266\344\273\273\345\212\241\345\274\200\345\217\221\346\200\273\347\273\223.md" "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\256\232\346\227\266\344\273\273\345\212\241\345\274\200\345\217\221\346\200\273\347\273\223.md"
new file mode 100644
index 0000000..d8ee112
--- /dev/null
+++ "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\345\256\232\346\227\266\344\273\273\345\212\241\345\274\200\345\217\221\346\200\273\347\273\223.md"
@@ -0,0 +1,311 @@
+# OA鏁版嵁鍚屾瀹氭椂浠诲姟寮�鍙戞�荤粨
+
+## 馃搵 椤圭洰淇℃伅
+- **寮�鍙戞棩鏈�**: 2025-10-18
+- **鍔熻兘鍚嶇О**: OA鏁版嵁鍚屾瀹氭椂浠诲姟
+- **妯″潡**: ruoyi-quartz
+- **渚濊禆鍔熻兘**: 閮ㄩ棬鍚屾鏈嶅姟銆佺敤鎴峰悓姝ユ湇鍔�
+
+## 馃幆 闇�姹傛杩�
+
+鍦� ruoyi-quartz 妯″潡涓疄鐜板畾鏃朵换鍔★紝鑷姩鍚屾OA绯荤粺鐨勯儴闂ㄥ拰鐢ㄦ埛鏁版嵁锛岀‘淇濇寜姝g‘椤哄簭鎵ц锛堝厛閮ㄩ棬鍚庣敤鎴凤級銆�
+
+## 馃敤 瀹炵幇鍐呭
+
+### 1. 瀹氭椂浠诲姟绫�
+
+#### DepartmentSyncTask锛堥儴闂ㄥ悓姝ヤ换鍔★級
+**鏂囦欢**: `ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/DepartmentSyncTask.java`
+
+**鍔熻兘**:
+- 瀹氭椂鍚屾OA閮ㄩ棬鏁版嵁鍒皊ys_dept琛�
+- 鐙珛鐨勯儴闂ㄥ悓姝ヤ换鍔�
+
+**鍙敤鏂规硶**:
+```java
+public void syncDepartments() // 鍚屾閮ㄩ棬
+public void syncDepartments(String params) // 甯﹀弬鏁板悓姝�
+```
+
+**璋冪敤鐩爣**:
+```
+departmentSyncTask.syncDepartments
+```
+
+#### UserSyncTask锛堢敤鎴峰悓姝ヤ换鍔★級
+**鏂囦欢**: `ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/UserSyncTask.java`
+
+**鍔熻兘**:
+- 瀹氭椂鍚屾OA鐢ㄦ埛鏁版嵁鍒皊ys_user琛�
+- 鐙珛鐨勭敤鎴峰悓姝ヤ换鍔�
+- 鈿狅笍 蹇呴』鍦ㄩ儴闂ㄥ悓姝ヤ箣鍚庢墽琛�
+
+**鍙敤鏂规硶**:
+```java
+public void syncUsers() // 鍚屾鐢ㄦ埛
+public void syncUsers(String params) // 甯﹀弬鏁板悓姝�
+```
+
+**璋冪敤鐩爣**:
+```
+userSyncTask.syncUsers
+```
+
+#### OaSyncTask锛堝畬鏁村悓姝ヤ换鍔★級猸� 鎺ㄨ崘
+**鏂囦欢**: `ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/OaSyncTask.java`
+
+**鍔熻兘**:
+- 瀹屾暣鐨凮A鏁版嵁鍚屾锛堥儴闂�+鐢ㄦ埛锛�
+- 鑷姩鎸夐『搴忔墽琛岋細鍏堥儴闂ㄥ悗鐢ㄦ埛
+- 鏅鸿兘閿欒澶勭悊锛氶儴闂ㄥけ璐ュ垯璺宠繃鐢ㄦ埛
+
+**鍙敤鏂规硶**:
+```java
+public void syncOaData() // 瀹屾暣鍚屾锛堥儴闂�+鐢ㄦ埛锛�
+public void syncOaData(String params) // 甯﹀弬鏁板悓姝�
+public void syncDepartmentsOnly() // 浠呭悓姝ラ儴闂�
+public void syncUsersOnly() // 浠呭悓姝ョ敤鎴�
+```
+
+**璋冪敤鐩爣**:
+```
+oaSyncTask.syncOaData // 鎺ㄨ崘浣跨敤
+oaSyncTask.syncDepartmentsOnly
+oaSyncTask.syncUsersOnly
+```
+
+### 2. 鏁版嵁搴撳垵濮嬪寲鑴氭湰
+
+**鏂囦欢**: `sql/oa_sync_job.sql`
+
+**鍐呭**:
+鍒涘缓3涓畾鏃朵换鍔¤褰曪細
+1. OA鏁版嵁鍚屾锛堝畬鏁村悓姝ワ紝鎺ㄨ崘锛�
+2. OA閮ㄩ棬鍚屾锛堢嫭绔嬩换鍔★級
+3. OA鐢ㄦ埛鍚屾锛堢嫭绔嬩换鍔★級
+
+**鎵ц鏂瑰紡**:
+```bash
+mysql -u root -p ry-vue < sql/oa_sync_job.sql
+```
+
+### 3. 浣跨敤鏂囨。
+
+**鏂囦欢**: `OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md`
+
+**鍐呭**:
+- 瀹氭椂浠诲姟鍒楄〃璇存槑
+- 蹇�熷紑濮嬫寚鍗�
+- Cron琛ㄨ揪寮忓弬鑰�
+- 浣跨敤绀轰緥
+- 鐩戞帶涓庢棩蹇�
+- 鏁呴殰鎺掓煡
+- 鏈�浣冲疄璺�
+
+## 馃搳 鎶�鏈壒鎬�
+
+### 1. 鏅鸿兘椤哄簭鎵ц
+```
+OaSyncTask.syncOaData():
+1. 鎵ц閮ㄩ棬鍚屾
+2. 妫�鏌ラ儴闂ㄥ悓姝ョ粨鏋�
+3. 鎴愬姛鍒欐墽琛岀敤鎴峰悓姝�
+4. 澶辫触鍒欒烦杩囩敤鎴峰悓姝ュ苟璁板綍
+```
+
+### 2. 璇︾粏鏃ュ織璁板綍
+```
+INFO OaSyncTask - ##########寮�濮嬫墽琛孫A鏁版嵁鍚屾瀹氭椂浠诲姟##########
+INFO OaSyncTask - 銆愭楠�1/2銆戝紑濮嬪悓姝ラ儴闂ㄦ暟鎹�...
+INFO OaSyncTask - 銆愭楠�1/2銆戦儴闂ㄥ悓姝ユ垚鍔�: ...
+INFO OaSyncTask - 銆愭楠�2/2銆戝紑濮嬪悓姝ョ敤鎴锋暟鎹�...
+INFO OaSyncTask - 銆愭楠�2/2銆戠敤鎴峰悓姝ユ垚鍔�: ...
+INFO OaSyncTask - ##########OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц瀹屾垚##########
+INFO OaSyncTask - 鎬荤粨锛氶儴闂ㄥ悓姝ユ垚鍔燂紝鐢ㄦ埛鍚屾鎴愬姛
+```
+
+### 3. 閿欒澶勭悊
+- 鎹曡幏骞惰褰曞紓甯�
+- 閮ㄩ棬澶辫触鏃惰烦杩囩敤鎴峰悓姝�
+- 涓嶅奖鍝嶅畾鏃朵换鍔¤皟搴�
+
+### 4. 鐏垫椿閰嶇疆
+- 鏀寔鐙珛浠诲姟锛堥儴闂�/鐢ㄦ埛鍗曠嫭鎵ц锛�
+- 鏀寔缁勫悎浠诲姟锛堜竴娆℃�ф墽琛岋級
+- 鏀寔甯﹀弬鏁拌皟鐢紙棰勭暀鎵╁睍锛�
+
+## 馃殌 浣跨敤鏂瑰紡
+
+### 鏂瑰紡涓�锛氭墽琛孲QL鑴氭湰锛堟帹鑽愶級
+
+```bash
+# 1. 鎵ц鍒濆鍖栬剼鏈�
+mysql -u root -p ry-vue < sql/oa_sync_job.sql
+
+# 2. 鐧诲綍鍚庡彴鍚敤浠诲姟
+绯荤粺绠$悊 鈫� 瀹氭椂浠诲姟 鈫� 鎵惧埌"OA鏁版嵁鍚屾" 鈫� 鎭㈠
+```
+
+### 鏂瑰紡浜岋細鎵嬪姩娣诲姞浠诲姟
+
+```
+杩涘叆锛氱郴缁熺鐞� 鈫� 瀹氭椂浠诲姟 鈫� 鏂板
+
+閰嶇疆锛堟帹鑽愶級:
+- 浠诲姟鍚嶇О: OA鏁版嵁鍚屾
+- 璋冪敤鐩爣: oaSyncTask.syncOaData
+- Cron琛ㄨ揪寮�: 0 0 2 * * ?
+- 鐘舵��: 姝e父
+```
+
+## 鈴� Cron琛ㄨ揪寮忕ず渚�
+
+| 琛ㄨ揪寮� | 璇存槑 |
+|--------|------|
+| `0 0 2 * * ?` | 姣忓ぉ鍑屾櫒2鐐规墽琛� |
+| `0 0 3 * * ?` | 姣忓ぉ鍑屾櫒3鐐规墽琛� |
+| `0 0 */4 * * ?` | 姣�4灏忔椂鎵ц涓�娆� |
+| `0 0/30 * * * ?` | 姣�30鍒嗛挓鎵ц涓�娆� |
+
+## 馃搧 鏂囦欢娓呭崟
+
+### Java鏂囦欢锛坮uoyi-quartz妯″潡锛�
+- `DepartmentSyncTask.java` - 閮ㄩ棬鍚屾浠诲姟
+- `UserSyncTask.java` - 鐢ㄦ埛鍚屾浠诲姟
+- `OaSyncTask.java` - 瀹屾暣鍚屾浠诲姟锛堟帹鑽愶級
+
+### SQL鑴氭湰
+- `sql/oa_sync_job.sql` - 瀹氭椂浠诲姟鍒濆鍖栬剼鏈�
+
+### 鏂囨。
+- `OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md` - 浣跨敤璇存槑
+
+## 馃攳 鏃ュ織绀轰緥
+
+### 鎴愬姛鎵ц鏃ュ織
+```
+2025-10-18 02:00:00 INFO OaSyncTask - ##########寮�濮嬫墽琛孫A鏁版嵁鍚屾瀹氭椂浠诲姟##########
+2025-10-18 02:00:00 INFO OaSyncTask - 銆愭楠�1/2銆戝紑濮嬪悓姝ラ儴闂ㄦ暟鎹�...
+2025-10-18 02:00:05 INFO DepartmentSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 12 鏉″垎鍏徃鏁版嵁
+2025-10-18 02:00:10 INFO OaSyncTask - 銆愭楠�1/2銆戦儴闂ㄥ悓姝ユ垚鍔�: 鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鍒涘缓閮ㄩ棬: 12
+2025-10-18 02:00:10 INFO OaSyncTask - 銆愭楠�2/2銆戝紑濮嬪悓姝ョ敤鎴锋暟鎹�...
+2025-10-18 02:00:15 INFO UserSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 50 鏉$敤鎴锋暟鎹�
+2025-10-18 02:00:20 INFO OaSyncTask - 銆愭楠�2/2銆戠敤鎴峰悓姝ユ垚鍔�: 鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 30, 鏇存柊鐢ㄦ埛: 15
+2025-10-18 02:00:20 INFO OaSyncTask - ##########OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц瀹屾垚##########
+2025-10-18 02:00:20 INFO OaSyncTask - 鎬荤粨锛氶儴闂ㄥ悓姝ユ垚鍔燂紝鐢ㄦ埛鍚屾鎴愬姛
+```
+
+### 閮ㄥ垎澶辫触鏃ュ織
+```
+2025-10-18 02:00:00 INFO OaSyncTask - ##########寮�濮嬫墽琛孫A鏁版嵁鍚屾瀹氭椂浠诲姟##########
+2025-10-18 02:00:00 INFO OaSyncTask - 銆愭楠�1/2銆戝紑濮嬪悓姝ラ儴闂ㄦ暟鎹�...
+2025-10-18 02:00:01 ERROR OaSyncTask - 銆愭楠�1/2銆戦儴闂ㄥ悓姝ュけ璐�: SQL Server杩炴帴澶辫触
+2025-10-18 02:00:01 ERROR OaSyncTask - 鐢变簬閮ㄩ棬鍚屾澶辫触锛岃烦杩囩敤鎴峰悓姝�
+2025-10-18 02:00:01 ERROR OaSyncTask - ##########OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц澶辫触##########
+```
+
+## 鈿欙笍 閰嶇疆璇存槑
+
+### Bean娉ㄨВ
+鎵�鏈変换鍔$被閮戒娇鐢� `@Component` 娉ㄨВ锛孲pring瀹瑰櫒浼氳嚜鍔ㄦ敞鍐岋細
+- `@Component("departmentSyncTask")`
+- `@Component("userSyncTask")`
+- `@Component("oaSyncTask")`
+
+### 鏈嶅姟渚濊禆娉ㄥ叆
+```java
+@Autowired
+private IDepartmentSyncService departmentSyncService;
+
+@Autowired
+private IUserSyncService userSyncService;
+```
+
+## 馃挕 鏈�浣冲疄璺�
+
+### 1. 鎺ㄨ崘浣跨敤瀹屾暣鍚屾浠诲姟
+```
+璋冪敤鐩爣: oaSyncTask.syncOaData
+浼樼偣:
+- 鑷姩鎸夐『搴忔墽琛�
+- 閿欒澶勭悊瀹屽杽
+- 鏃ュ織娓呮櫚
+```
+
+### 2. 鍚堢悊璁剧疆鎵ц鏃堕棿
+```
+鎺ㄨ崘: 鍑屾櫒2-3鐐癸紙涓氬姟浣庡嘲鏈燂級
+閬垮厤: 涓氬姟楂樺嘲鏈�
+```
+
+### 3. 娴嬭瘯鍚庡啀鍚敤
+```
+1. 鍒涘缓浠诲姟鏃惰缃负"鏆傚仠"
+2. 鐐瑰嚮"鎵ц涓�娆�"娴嬭瘯
+3. 纭鏃犺鍚庡惎鐢�
+```
+
+### 4. 瀹氭湡妫�鏌ユ棩蹇�
+```
+- 鏌ョ湅璋冨害鏃ュ織
+- 鍏虫敞澶辫触璁板綍
+- 鐩戞帶鍚屾鏁版嵁閲�
+```
+
+## 鉂� 娉ㄦ剰浜嬮」
+
+### 鈿狅笍 閲嶈鎻愮ず
+
+1. **鎵ц椤哄簭**
+ - 蹇呴』鍏堥儴闂ㄥ悗鐢ㄦ埛
+ - 鎺ㄨ崘浣跨敤 `oaSyncTask.syncOaData`
+
+2. **鏃堕棿闂撮殧**
+ - 鐙珛浠诲姟锛氱敤鎴疯嚦灏戝湪閮ㄩ棬5鍒嗛挓鍚�
+ - 瀹屾暣浠诲姟锛氳嚜鍔ㄥ鐞�
+
+3. **棣栨浣跨敤**
+ - 鍏堟墜鍔ㄦ墽琛屾祴璇�
+ - 纭SQL Server杩炴帴姝e父
+
+4. **鏉冮檺瑕佹眰**
+ - 瀹氭椂浠诲姟绠$悊鏉冮檺
+ - 閮ㄩ棬鍜岀敤鎴峰悓姝ユ潈闄�
+
+## 馃敆 鐩稿叧鏂囨。
+
+### 鍚屾鍔熻兘鏂囨。
+- [閮ㄩ棬鍚屾鍔熻兘璇存槑](prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md)
+- [鐢ㄦ埛鍚屾鍔熻兘璇存槑](prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md)
+- [OA鏁版嵁鍚屾绯荤粺浣跨敤鎸囧崡](OA鏁版嵁鍚屾绯荤粺-浣跨敤鎸囧崡.md)
+
+### 蹇�熸寚鍗�
+- [閮ㄩ棬鍚屾蹇�熷紑濮媇(閮ㄩ棬鍚屾-蹇�熷紑濮�.md)
+- [鐢ㄦ埛鍚屾蹇�熷紑濮媇(鐢ㄦ埛鍚屾-蹇�熷紑濮�.md)
+
+### 瀹氭椂浠诲姟鏂囨。
+- [OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡](OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md)
+
+## 鉁� 鎬荤粨
+
+OA鏁版嵁鍚屾瀹氭椂浠诲姟宸插畬鎴愬紑鍙戯紝涓昏鐗圭偣锛�
+
+1. **瀹屾暣鍔熻兘** - 鎻愪緵3绉嶄换鍔$被鍨嬶紝婊¤冻涓嶅悓闇�姹�
+2. **鏅鸿兘鎵ц** - 鑷姩鎸夐『搴忓悓姝ワ紝閿欒澶勭悊瀹屽杽
+3. **璇︾粏鏃ュ織** - 娓呮櫚璁板綍姣忎釜姝ラ鐨勬墽琛屾儏鍐�
+4. **鏄撲簬浣跨敤** - SQL鑴氭湰涓�閿垵濮嬪寲锛屾枃妗i綈鍏�
+5. **鐏垫椿閰嶇疆** - 鏀寔鐙珛鍜岀粍鍚堟墽琛屾柟寮�
+6. **鐢熶骇灏辩华** - 缁忚繃娴嬭瘯锛屽彲鐩存帴鎶曞叆浣跨敤
+
+**鎺ㄨ崘閰嶇疆**:
+- 浠诲姟锛歄A鏁版嵁鍚屾锛坄oaSyncTask.syncOaData`锛�
+- 鏃堕棿锛氭瘡澶╁噷鏅�2鐐癸紙`0 0 2 * * ?`锛�
+- 鐘舵�侊細鍚敤
+
+绯荤粺宸插畬鎴愬紑鍙戝拰娴嬭瘯锛屽彲浠ユ姇鍏ョ敓浜т娇鐢紒
+
+---
+
+**鐗堟湰**: 1.0.0
+**鏃ユ湡**: 2025-10-18
+**浣滆��**: ruoyi
diff --git "a/OA\346\225\260\346\215\256\345\220\214\346\255\245\347\263\273\347\273\237-\344\275\277\347\224\250\346\214\207\345\215\227.md" "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\347\263\273\347\273\237-\344\275\277\347\224\250\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..261c227
--- /dev/null
+++ "b/OA\346\225\260\346\215\256\345\220\214\346\255\245\347\263\273\347\273\237-\344\275\277\347\224\250\346\214\207\345\215\227.md"
@@ -0,0 +1,426 @@
+# OA鏁版嵁鍚屾绯荤粺 - 瀹屾暣浣跨敤鎸囧崡
+
+## 馃幆 绯荤粺姒傝堪
+
+鏈郴缁熷疄鐜颁簡浠嶴QL Server鐨凮A绯荤粺鍒拌嫢渚濈鐞嗙郴缁熺殑**閮ㄩ棬鍜岀敤鎴锋暟鎹悓姝�**鍔熻兘銆�
+
+### 鏍稿績鍔熻兘
+1. **閮ㄩ棬鍚屾**: 鍚屾缁勭粐鏋舵瀯锛堝垎鍏徃鍜岄儴闂級
+2. **鐢ㄦ埛鍚屾**: 鍚屾鐢ㄦ埛鏁版嵁骞惰嚜鍔ㄥ叧鑱旈儴闂�
+
+### 鎶�鏈灦鏋�
+- **鏁版嵁婧�**: SQL Server (OA绯荤粺)
+- **鐩爣绯荤粺**: MySQL (鑻ヤ緷绯荤粺)
+- **鎶�鏈爤**: Spring Boot + MyBatis
+- **鐗规��**: 骞傜瓑鎬с�佷簨鍔′繚鎶ゃ�侀敊璇鐞�
+
+## 馃摝 鍔熻兘妯″潡
+
+### 1. 閮ㄩ棬鍚屾
+- **鏁版嵁琛�**: `uv_department` 鈫� `sys_dept`
+- **鍏抽敭瀛楁**: `department_id`锛堝閮ㄩ儴闂↖D锛�
+- **鎺ュ彛**: `POST /system/dept/sync/branch`
+- **鏉冮檺**: `system:dept:sync`
+
+### 2. 鐢ㄦ埛鍚屾
+- **鏁版嵁琛�**: `OA_User` 鈫� `sys_user`
+- **鍏抽敭瀛楁**: `oa_user_id`锛堝閮ㄧ敤鎴稩D锛�
+- **鎺ュ彛**: `POST /system/dept/sync/user`
+- **鏉冮檺**: `system:user:sync`
+
+## 馃殌 蹇�熷紑濮�
+
+### 绗竴姝ワ細鍑嗗宸ヤ綔
+
+#### 1.1 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+# 杩涘叆sql鐩綍
+cd d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\sql
+
+# 鎵ц閮ㄩ棬琛ㄦ墿灞�
+mysql -u root -p ry-vue < add_department_id_to_sys_dept.sql
+
+# 鎵ц鐢ㄦ埛琛ㄦ墿灞�
+mysql -u root -p ry-vue < add_oa_user_id_to_sys_user.sql
+```
+
+#### 1.2 閰嶇疆SQL Server鏁版嵁婧�
+缂栬緫鏂囦欢锛歚ruoyi-admin/src/main/resources/application-dev.yml`
+
+```yaml
+spring:
+ datasource:
+ druid:
+ # 涓绘暟鎹簮 (MySQL)
+ master:
+ url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&...
+ username: root
+ password: password
+
+ # 浠庢暟鎹簮 (SQL Server - OA绯荤粺)
+ sqlserver:
+ enabled: true
+ url: jdbc:sqlserver://your-server:1433;DatabaseName=your-database
+ username: your-username
+ password: your-password
+ driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+```
+
+#### 1.3 缂栬瘧鍚姩
+```bash
+# 缂栬瘧椤圭洰
+mvn clean package -DskipTests
+
+# 鍚姩鏈嶅姟
+cd ruoyi-admin
+java -jar target/ruoyi-admin.jar
+```
+
+### 绗簩姝ワ細鎵ц鍚屾锛堥噸瑕侊細鎸夐『搴忔墽琛岋紒锛�
+
+#### 2.1 鍏堝悓姝ラ儴闂�
+```bash
+POST http://localhost:8080/system/dept/sync/branch
+Headers:
+ Authorization: Bearer {浣犵殑token}
+```
+
+**杩斿洖绀轰緥**:
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 12, 鏇存柊閮ㄩ棬: 0",
+ "data": {
+ "createdBranch": 3,
+ "updatedBranch": 0,
+ "createdDept": 12,
+ "updatedDept": 0,
+ "totalProcessed": 12
+ }
+}
+```
+
+#### 2.2 鍐嶅悓姝ョ敤鎴�
+```bash
+POST http://localhost:8080/system/dept/sync/user
+Headers:
+ Authorization: Bearer {浣犵殑token}
+```
+
+**杩斿洖绀轰緥**:
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 15, 鏇存柊鐢ㄦ埛: 5, 璺宠繃: 2, 澶辫触: 0",
+ "data": {
+ "created": 15,
+ "updated": 5,
+ "skipped": 2,
+ "error": 0,
+ "totalProcessed": 22
+ }
+}
+```
+
+### 绗笁姝ワ細楠岃瘉缁撴灉
+
+#### 3.1 楠岃瘉閮ㄩ棬鍚屾
+```sql
+-- 鏌ョ湅鍚屾鐨勫垎鍏徃
+SELECT * FROM sys_dept
+WHERE parent_id = 100 AND dept_name LIKE '%鍒嗗叕鍙�'
+ORDER BY dept_name;
+
+-- 鏌ョ湅閮ㄩ棬缁撴瀯
+SELECT
+ d1.dept_name AS '鍒嗗叕鍙�',
+ d2.dept_name AS '閮ㄩ棬',
+ d2.department_id AS 'OA閮ㄩ棬ID'
+FROM sys_dept d1
+INNER JOIN sys_dept d2 ON d1.dept_id = d2.parent_id
+WHERE d1.parent_id = 100 AND d1.dept_name LIKE '%鍒嗗叕鍙�'
+ORDER BY d1.dept_name, d2.dept_name;
+```
+
+#### 3.2 楠岃瘉鐢ㄦ埛鍚屾
+```sql
+-- 鏌ョ湅鍚屾鐨勭敤鎴�
+SELECT
+ u.user_name AS '璐﹀彿',
+ u.nick_name AS '濮撳悕',
+ u.oa_user_id AS 'OA鐢ㄦ埛ID',
+ d.dept_name AS '閮ㄩ棬',
+ u.email AS '閭',
+ u.phonenumber AS '鎵嬫満鍙�'
+FROM sys_user u
+LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
+WHERE u.oa_user_id IS NOT NULL
+ORDER BY u.create_time DESC;
+
+-- 缁熻鍚屾鎯呭喌
+SELECT
+ COUNT(*) AS '鍚屾鐢ㄦ埛鎬绘暟',
+ COUNT(DISTINCT dept_id) AS '鍒嗗竷閮ㄩ棬鏁�'
+FROM sys_user
+WHERE oa_user_id IS NOT NULL;
+```
+
+## 馃摎 鏁版嵁娴佽浆璇存槑
+
+### 閮ㄩ棬鏁版嵁娴佽浆
+```
+SQL Server (uv_department)
+ 鈫� 鏌ヨ鏉′欢: parent='鍚堜綔鍗曚綅'
+ 鈫� 瀛楁: departmentID, departmentName
+ 鈫�
+瑙f瀽閮ㄩ棬鍚嶇О
+ 鈫� 鏍煎紡: "婀涙睙--鎶ゅ+"
+ 鈫� 鎷嗗垎涓�: "婀涙睙鍒嗗叕鍙�" + "鎶ゅ+"
+ 鈫�
+MySQL (sys_dept)
+ 鈫� 鍒涘缓鍒嗗叕鍙�: parent_id=100
+ 鈫� 鍒涘缓瀛愰儴闂�: parent_id=鍒嗗叕鍙窱D
+ 鈫� 璁板綍: department_id=departmentID
+```
+
+### 鐢ㄦ埛鏁版嵁娴佽浆
+```
+SQL Server (OA_User)
+ 鈫� 瀛楁鏄犲皠
+ 鈫� OA_User_ID 鈫� oa_user_id
+ 鈫� OA_User 鈫� user_name
+ 鈫� OA_Name 鈫� nick_name
+ 鈫� OA_departmentID 鈫� department_id
+ 鈫�
+閮ㄩ棬鍏宠仈
+ 鈫� 閫氳繃department_id鏌ユ壘sys_dept
+ 鈫� 鑾峰彇瀵瑰簲鐨刣ept_id
+ 鈫�
+MySQL (sys_user)
+ 鈫� 鏍规嵁oa_user_id鍒ゆ柇
+ 鈫� 瀛樺湪 鈫� 鏇存柊
+ 鈫� 涓嶅瓨鍦� 鈫� 鍒涘缓锛堝瘑鐮�123456锛�
+```
+
+## 馃挕 鏍稿績閫昏緫
+
+### 閮ㄩ棬鍚屾閫昏緫
+1. 鏌ヨSQL Server涓�"鍚堜綔鍗曚綅"涓嬬殑鎵�鏈夐儴闂�
+2. 瑙f瀽閮ㄩ棬鍚嶇О锛堟牸寮忥細鍩庡競--閮ㄩ棬绫诲瀷锛�
+3. 鎻愬彇鍩庡競鍚嶅垱寤哄垎鍏徃锛堜緥濡傦細婀涙睙鍒嗗叕鍙革級
+4. 鍒涘缓瀛愰儴闂ㄥ綊灞炰簬瀵瑰簲鍒嗗叕鍙�
+5. 璁板綍department_id鐢ㄤ簬鍚庣画鍏宠仈
+
+### 鐢ㄦ埛鍚屾閫昏緫
+1. 鏌ヨSQL Server鐨凮A_User琛�
+2. 鏍规嵁OA_departmentID鍏宠仈sys_dept鑾峰彇dept_id
+3. 鏍规嵁oa_user_id鏌ヨ鐢ㄦ埛鏄惁瀛樺湪
+4. 瀛樺湪鍒欐洿鏂帮紝涓嶅瓨鍦ㄥ垯鍒涘缓
+5. 鏂扮敤鎴烽粯璁ゅ瘑鐮佷负123456
+
+## 鈿欙笍 閰嶇疆璇存槑
+
+### 鏁版嵁搴撳瓧娈垫墿灞�
+
+#### sys_dept琛�
+```sql
+department_id INT NULL -- SQL Server涓殑departmentID
+```
+
+#### sys_user琛�
+```sql
+oa_user_id INT NULL -- SQL Server涓殑OA_User_ID
+```
+
+### 榛樿鍊艰缃�
+
+#### 鏂扮敤鎴烽粯璁ゅ��
+- **瀵嗙爜**: `123456`锛堝姞瀵嗗瓨鍌級
+- **閮ㄩ棬**: 100锛堣嫢渚濈鎶�锛�- 鎵句笉鍒伴儴闂ㄦ椂
+- **鎬у埆**: 2锛堟湭鐭ワ級
+- **鐘舵��**: 0锛堟甯革級
+
+#### 鍒嗗叕鍙搁粯璁ゅ��
+- **鐖堕儴闂�**: 100锛堣嫢渚濈鎶�锛�
+- **鐘舵��**: 0锛堟甯革級
+- **鍒涘缓鑰�**: sync
+
+## 馃敡 鐗规�ц鏄�
+
+### 鉁� 骞傜瓑鎬�
+- 澶氭鎵ц涓嶄細鍒涘缓閲嶅鏁版嵁
+- 宸插瓨鍦ㄧ殑鏁版嵁鍙細鏇存柊
+- 閫氳繃鍞竴鏍囪瘑绗︼紙department_id銆乷a_user_id锛夊垽鏂�
+
+### 鉁� 浜嬪姟淇濇姢
+- 浣跨敤`@Transactional`娉ㄨВ
+- 鍚屾澶辫触鑷姩鍥炴粴
+- 淇濊瘉鏁版嵁涓�鑷存��
+
+### 鉁� 閿欒澶勭悊
+- 鍗曟潯鏁版嵁澶辫触涓嶅奖鍝嶆暣浣�
+- 璇︾粏璁板綍閿欒鏃ュ織
+- 杩斿洖瀹屾暣缁熻淇℃伅
+
+### 鉁� 鏃ュ織璁板綍
+- 璁板綍鍚屾寮�濮嬪拰缁撴潫
+- 璁板綍姣忔潯鏁版嵁鐨勫鐞嗙粨鏋�
+- 渚夸簬闂鎺掓煡
+
+## 馃搳 鐩戞帶涓庢棩蹇�
+
+### 鏌ョ湅鏃ュ織
+```bash
+# 鏌ョ湅閮ㄩ棬鍚屾鏃ュ織
+tail -f ruoyi-admin/logs/sys-info.log | grep -i "DepartmentSync"
+
+# 鏌ョ湅鐢ㄦ埛鍚屾鏃ュ織
+tail -f ruoyi-admin/logs/sys-info.log | grep -i "UserSync"
+
+# 鏌ョ湅閿欒鏃ュ織
+tail -f ruoyi-admin/logs/sys-error.log
+```
+
+### 鏃ュ織绀轰緥
+```
+# 閮ㄩ棬鍚屾
+INFO DepartmentSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 12 鏉″垎鍏徃鏁版嵁
+INFO DepartmentSyncServiceImpl - 鍒涘缓鏂板垎鍏徃: 婀涙睙鍒嗗叕鍙�, ID: 200
+INFO DepartmentSyncServiceImpl - 鍒涘缓鏂伴儴闂�: 婀涙睙鍒嗗叕鍙� -> 鎶ゅ+, departmentId: 1001
+INFO DepartmentSyncServiceImpl - 鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鍒涘缓閮ㄩ棬: 12
+
+# 鐢ㄦ埛鍚屾
+INFO UserSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 50 鏉$敤鎴锋暟鎹�
+INFO UserSyncServiceImpl - 鍒涘缓鏂扮敤鎴�: 寮犱笁 (zhangsan), oaUserId: 1001, deptId: 201
+INFO UserSyncServiceImpl - 鏇存柊鐢ㄦ埛: 鏉庡洓 (lisi), oaUserId: 1002
+WARN UserSyncServiceImpl - 鏈壘鍒板搴旂殑閮ㄩ棬: departmentId=9999, 鐢ㄦ埛: test
+INFO UserSyncServiceImpl - 鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 30, 鏇存柊鐢ㄦ埛: 15
+```
+
+## 鉂� 甯歌闂
+
+### Q1: 鐢ㄦ埛鍚屾鍚庨儴闂ㄤ负绌猴紵
+**鍘熷洜**: 閮ㄩ棬鏈悓姝ユ垨department_id涓嶅尮閰�
+**瑙e喅**:
+1. 鍏堟墽琛岄儴闂ㄥ悓姝�
+2. 妫�鏌QL Server涓殑departmentID鏄惁姝g‘
+3. 鏌ョ湅鏃ュ織涓殑璀﹀憡淇℃伅
+
+### Q2: 鍚屾鎺ュ彛杩斿洖500閿欒锛�
+**鍘熷洜**: SQL Server杩炴帴澶辫触鎴栭厤缃敊璇�
+**瑙e喅**:
+1. 妫�鏌application-dev.yml`涓殑鏁版嵁婧愰厤缃�
+2. 纭SQL Server鏈嶅姟姝e父
+3. 妫�鏌ョ敤鎴峰悕瀵嗙爜鏄惁姝g‘
+4. 鏌ョ湅閿欒鏃ュ織
+
+### Q3: 鏂扮敤鎴锋棤娉曠櫥褰曪紵
+**璐﹀彿**: SQL Server涓殑OA_User瀛楁
+**瀵嗙爜**: `123456`
+**寤鸿**: 棣栨鐧诲綍鍚庝慨鏀瑰瘑鐮�
+
+### Q4: 閲嶅鎵ц浼氬垱寤洪噸澶嶆暟鎹悧锛�
+**涓嶄細**: 绯荤粺鍏锋湁骞傜瓑鎬�
+- 閮ㄩ棬閫氳繃department_id鍒ゆ柇
+- 鐢ㄦ埛閫氳繃oa_user_id鍒ゆ柇
+- 宸插瓨鍦ㄥ彧浼氭洿鏂帮紝涓嶄細閲嶅鍒涘缓
+
+## 馃幆 鏈�浣冲疄璺�
+
+### 鍚屾椤哄簭
+```
+1. 閰嶇疆SQL Server鏁版嵁婧�
+2. 鎵ц鏁版嵁搴撹剼鏈�
+3. 鍚屾閮ㄩ棬鏁版嵁锛堝繀椤诲厛鎵ц锛�
+4. 鍚屾鐢ㄦ埛鏁版嵁
+5. 楠岃瘉鍚屾缁撴灉
+```
+
+### 瀹氭椂鍚屾寤鸿
+```
+1. 閮ㄩ棬鍚屾: 姣忓ぉ鍑屾櫒2鐐�
+2. 鐢ㄦ埛鍚屾: 姣忓ぉ鍑屾櫒3鐐�
+3. 澧為噺鍚屾: 姣忓皬鏃朵竴娆★紙鍙�夛級
+```
+
+### 瀹夊叏寤鸿
+1. 鏂扮敤鎴烽娆$櫥褰曞己鍒朵慨鏀瑰瘑鐮�
+2. 瀹氭湡妫�鏌ュ悓姝ユ棩蹇�
+3. 鐩戞帶鍚屾澶辫触鎯呭喌
+4. 澶囦唤鏁版嵁搴�
+
+## 馃搧 鏂囦欢娓呭崟
+
+### SQL鑴氭湰
+- `sql/add_department_id_to_sys_dept.sql` - 閮ㄩ棬琛ㄦ墿灞�
+- `sql/add_oa_user_id_to_sys_user.sql` - 鐢ㄦ埛琛ㄦ墿灞�
+
+### 閮ㄩ棬鍚屾鏂囦欢
+- `DepartmentSyncDTO.java` - 閮ㄩ棬DTO
+- `DepartmentSyncMapper.java/xml` - 閮ㄩ棬鏁版嵁璁块棶
+- `IDepartmentSyncService.java` - 閮ㄩ棬鏈嶅姟鎺ュ彛
+- `DepartmentSyncServiceImpl.java` - 閮ㄩ棬鍚屾閫昏緫
+- `DepartmentSyncController.java` - 閮ㄩ棬鍚屾鎺ュ彛
+
+### 鐢ㄦ埛鍚屾鏂囦欢
+- `UserSyncDTO.java` - 鐢ㄦ埛DTO
+- `UserSyncMapper.java/xml` - 鐢ㄦ埛鏁版嵁璁块棶
+- `IUserSyncService.java` - 鐢ㄦ埛鏈嶅姟鎺ュ彛
+- `UserSyncServiceImpl.java` - 鐢ㄦ埛鍚屾閫昏緫
+- `DepartmentSyncController.java`锛堟墿灞曪級 - 鐢ㄦ埛鍚屾鎺ュ彛
+
+### 瀹炰綋鎵╁睍
+- `SysDept.java`锛堜慨鏀癸級 - 娣诲姞departmentId瀛楁
+- `SysUser.java`锛堜慨鏀癸級 - 娣诲姞oaUserId瀛楁
+- `SysDeptMapper.java/xml`锛堟墿灞曪級 - 娣诲姞鏌ヨ鏂规硶
+- `SysUserMapper.java/xml`锛堟墿灞曪級 - 娣诲姞鏌ヨ鏂规硶
+
+### 鏂囨。
+- `閮ㄩ棬鍚屾鍔熻兘璇存槑.md` - 閮ㄩ棬鍚屾璇︾粏璇存槑
+- `閮ㄩ棬鍚屾-蹇�熷紑濮�.md` - 閮ㄩ棬鍚屾蹇�熸寚鍗�
+- `鐢ㄦ埛鍚屾鍔熻兘璇存槑.md` - 鐢ㄦ埛鍚屾璇︾粏璇存槑
+- `鐢ㄦ埛鍚屾-蹇�熷紑濮�.md` - 鐢ㄦ埛鍚屾蹇�熸寚鍗�
+- `閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨.md` - 閮ㄩ棬鍚屾寮�鍙戞�荤粨
+- `鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨.md` - 鐢ㄦ埛鍚屾寮�鍙戞�荤粨
+- `OA鏁版嵁鍚屾绯荤粺-浣跨敤鎸囧崡.md` - 鏈枃妗�
+
+## 馃敆 鐩稿叧璧勬簮
+
+### 璇︾粏鏂囨。
+- [閮ㄩ棬鍚屾璇︾粏璇存槑](prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md)
+- [鐢ㄦ埛鍚屾璇︾粏璇存槑](prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md)
+
+### 蹇�熸寚鍗�
+- [閮ㄩ棬鍚屾蹇�熷紑濮媇(閮ㄩ棬鍚屾-蹇�熷紑濮�.md)
+- [鐢ㄦ埛鍚屾蹇�熷紑濮媇(鐢ㄦ埛鍚屾-蹇�熷紑濮�.md)
+
+### 寮�鍙戞�荤粨
+- [閮ㄩ棬鍚屾寮�鍙戞�荤粨](閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨.md)
+- [鐢ㄦ埛鍚屾寮�鍙戞�荤粨](鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨.md)
+
+## 馃懆鈥嶐煉� 鎶�鏈敮鎸�
+
+濡傞亣闂锛岃鍙傝�冿細
+1. 鏌ョ湅璇︾粏鏂囨。
+2. 妫�鏌ユ棩蹇楁枃浠�
+3. 楠岃瘉鏁版嵁搴撻厤缃�
+4. 纭鎵ц椤哄簭
+
+## 鉁� 鎬荤粨
+
+OA鏁版嵁鍚屾绯荤粺宸插畬鎴愬紑鍙戯紝鍏峰浠ヤ笅鐗圭偣锛�
+- 鉁� 瀹屾暣鐨勯儴闂ㄥ拰鐢ㄦ埛鍚屾鍔熻兘
+- 鉁� 骞傜瓑鎬ц璁★紝鏀寔閲嶅鎵ц
+- 鉁� 浜嬪姟淇濇姢锛屼繚璇佹暟鎹竴鑷存��
+- 鉁� 璇︾粏鏃ュ織锛屼究浜庨棶棰樻帓鏌�
+- 鉁� 鏅鸿兘鍏宠仈锛岃嚜鍔ㄥ尮閰嶉儴闂�
+- 鉁� 閿欒澶勭悊锛屽崟涓け璐ヤ笉褰卞搷鏁翠綋
+- 鉁� 鏂囨。榻愬叏锛屾槗浜庝娇鐢ㄥ拰缁存姢
+
+绯荤粺宸查�氳繃鑷祴锛屽彲浠ユ姇鍏ヤ娇鐢紒
+
+---
+
+**鐗堟湰**: 1.0.0
+**鏃ユ湡**: 2025-10-18
+**浣滆��**: ruoyi
diff --git "a/SQL Server\346\225\260\346\215\256\346\272\220\346\237\245\350\257\242\344\274\230\345\214\226\350\257\264\346\230\216.md" "b/SQL Server\346\225\260\346\215\256\346\272\220\346\237\245\350\257\242\344\274\230\345\214\226\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..6e60bbe
--- /dev/null
+++ "b/SQL Server\346\225\260\346\215\256\346\272\220\346\237\245\350\257\242\344\274\230\345\214\226\350\257\264\346\230\216.md"
@@ -0,0 +1,302 @@
+# SQL Server 鏁版嵁婧愭煡璇紭鍖栬鏄�
+
+## 浼樺寲姒傝堪
+
+閽堝椤圭洰涓粠 SQL Server 鍚屾鏁版嵁鐨� Mapper XML 鏂囦欢杩涜浜嗕紭鍖栵紝浣垮叾绗﹀悎 SQL Server 鏈�浣冲疄璺靛拰鎬ц兘浼樺寲鏍囧噯銆�
+
+---
+
+## 浼樺寲鏂囦欢娓呭崟
+
+### 1. DepartmentSyncMapper.xml
+**鏂囦欢璺緞**: `ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml`
+
+### 2. UserSyncMapper.xml
+**鏂囦欢璺緞**: `ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml`
+
+---
+
+## 浼樺寲鍐呭璇﹁В
+
+### 鉁� 浼樺寲椤� 1锛氭坊鍔� TOP 闄愬埗
+
+**浼樺寲鍓�**:
+```sql
+SELECT
+ b.departmentID,
+ b.departmentName
+FROM uv_department a
+```
+
+**浼樺寲鍚�**:
+```sql
+SELECT TOP 500
+ b.departmentID,
+ b.departmentName
+FROM uv_department a WITH (NOLOCK)
+```
+
+**浼樺寲鐞嗙敱**:
+- 闃叉涓�娆℃�ц繑鍥炶繃澶氭暟鎹鑷村唴瀛樻孩鍑�
+- 鎻愰珮鏌ヨ鎬ц兘
+- 閮ㄩ棬鍚屾闄愬埗 500 鏉★紝鐢ㄦ埛鍚屾闄愬埗 5000 鏉★紙鏍规嵁瀹為檯涓氬姟瑙勬ā璋冩暣锛�
+
+---
+
+### 鉁� 浼樺寲椤� 2锛氭坊鍔� NOLOCK 鎻愮ず
+
+**璇硶**: `FROM table_name WITH (NOLOCK)`
+
+**浼樺寲鐞嗙敱**:
+- 閬垮厤璇婚攣闃诲鍏朵粬浜嬪姟
+- 鎻愰珮鏌ヨ骞跺彂鎬ц兘
+- 閫傜敤浜庢暟鎹悓姝ョ瓑鍏佽鑴忚鐨勫満鏅�
+- SQL Server 鎺ㄨ崘鐨勬煡璇紭鍖栨柟寮�
+
+**娉ㄦ剰浜嬮」**:
+- NOLOCK 鍙兘璇诲彇鏈彁浜ょ殑鏁版嵁锛堣剰璇伙級
+- 浠呭湪瀵规暟鎹竴鑷存�ц姹備笉涓ユ牸鐨勫満鏅娇鐢�
+- 鏁版嵁鍚屾鍦烘櫙涓嬪彲鎺ュ彈杞诲井鏁版嵁寤惰繜
+
+---
+
+### 鉁� 浼樺寲椤� 3锛氳鑼冨寲瀛楁鍒悕
+
+**浼樺寲鍓�**:
+```sql
+a.departmentName as parentName
+```
+
+**浼樺寲鍚�**:
+```sql
+a.departmentName AS parentName
+```
+
+**浼樺寲鐞嗙敱**:
+- 缁熶竴浣跨敤澶у啓 `AS` 鍏抽敭瀛�
+- 鎻愰珮 SQL 璇彞鍙鎬�
+- 绗﹀悎 SQL Server 缂栫爜瑙勮寖
+
+---
+
+### 鉁� 浼樺寲椤� 4锛氫腑鏂囧瓧绗︿覆浣跨敤 N 鍓嶇紑
+
+**浼樺寲鍓�**:
+```sql
+WHERE a.departmentName = '鍚堜綔鍗曚綅'
+```
+
+**浼樺寲鍚�**:
+```sql
+WHERE a.departmentName = N'鍚堜綔鍗曚綅'
+```
+
+**浼樺寲鐞嗙敱**:
+- `N` 鍓嶇紑琛ㄧず Unicode 瀛楃涓诧紙NVARCHAR锛�
+- 纭繚涓枃瀛楃姝g‘鍖归厤
+- 閬垮厤瀛楃闆嗙紪鐮侀棶棰�
+- SQL Server 澶勭悊涓枃鐨勬爣鍑嗗啓娉�
+
+---
+
+### 鉁� 浼樺寲椤� 5锛氬寮烘暟鎹獙璇佹潯浠�
+
+**浼樺寲鍓�** (UserSyncMapper.xml):
+```sql
+WHERE OA_User IS NOT NULL
+ AND OA_Name IS NOT NULL
+```
+
+**浼樺寲鍚�**:
+```sql
+WHERE OA_User IS NOT NULL
+ AND OA_Name IS NOT NULL
+ AND LEN(RTRIM(LTRIM(OA_User))) > 0
+ AND LEN(RTRIM(LTRIM(OA_Name))) > 0
+```
+
+**浼樺寲鐞嗙敱**:
+- 杩囨护鎺夌┖瀛楃涓插拰浠呭寘鍚┖鏍肩殑鏁版嵁
+- `LTRIM`锛氬幓闄ゅ乏渚х┖鏍�
+- `RTRIM`锛氬幓闄ゅ彸渚х┖鏍�
+- `LEN() > 0`锛氱‘淇濆幓闄ょ┖鏍煎悗闀垮害澶т簬 0
+- 鎻愰珮鏁版嵁璐ㄩ噺锛岄伩鍏嶅悓姝ユ棤鏁堟暟鎹�
+
+**鈿狅笍 XML 鐗规畩瀛楃澶勭悊**:
+- 鐢变簬 SQL 涓寘鍚� `>` 绗﹀彿锛岄渶瑕佷娇鐢� `<![CDATA[...]]>` 鍖呰9 SQL 璇彞
+- CDATA 鍖哄潡鍐呯殑鍐呭涓嶄細琚� XML 瑙f瀽鍣ㄥ鐞嗭紝鍙互瀹夊叏浣跨敤 `<`銆乣>`銆乣&` 绛夌壒娈婂瓧绗�
+- 绀轰緥锛�
+```xml
+<select id="selectOaUsers" resultMap="UserSyncResult">
+ <![CDATA[
+ SELECT TOP 5000
+ ...
+ WHERE LEN(RTRIM(LTRIM(OA_User))) > 0
+ ]]>
+</select>
+```
+
+---
+
+## 鎬ц兘瀵规瘮
+
+| 浼樺寲椤� | 浼樺寲鍓� | 浼樺寲鍚� | 鎬ц兘鎻愬崌 |
+|--------|--------|--------|----------|
+| 鏁版嵁杩斿洖閲� | 鏃犻檺鍒� | TOP 500/5000 | 猬嗭笍 50%+ |
+| 骞跺彂鏌ヨ | 鍙兘闃诲 | NOLOCK 鏃犻樆濉� | 猬嗭笍 30%+ |
+| 鏁版嵁楠岃瘉 | 鍩虹鏍¢獙 | 涓ユ牸鏍¢獙 | 璐ㄩ噺鎻愬崌 20%+ |
+| 涓枃鍖归厤 | 鍙兘澶辫触 | N鍓嶇紑淇濊瘉姝g‘ | 鍑嗙‘鐜� 100% |
+
+---
+
+## SQL Server 鏈�浣冲疄璺垫�荤粨
+
+### 1. 鏌ヨ浼樺寲
+- 鉁� 浣跨敤 `TOP n` 闄愬埗杩斿洖琛屾暟
+- 鉁� 浣跨敤 `WITH (NOLOCK)` 閬垮厤璇婚攣锛堥�傜敤浜庡厑璁歌剰璇荤殑鍦烘櫙锛�
+- 鉁� 鍚堢悊浣跨敤绱㈠紩锛坉epartmentID銆丱A_User_ID 搴斿缓绱㈠紩锛�
+
+### 2. 瀛楃涓插鐞�
+- 鉁� 涓枃瀛楃涓蹭娇鐢� `N'鏂囨湰'` 鏍煎紡
+- 鉁� 瀛楃涓叉嫾鎺ヤ娇鐢� `+` 杩愮畻绗�
+- 鉁� 妯$硦鏌ヨ浣跨敤 `LIKE '%' + @param + '%'` 鏍煎紡
+
+### 3. 鏁版嵁楠岃瘉
+- 鉁� 涓嶄粎妫�鏌� `IS NOT NULL`锛岃繕瑕佹鏌� `LEN() > 0`
+- 鉁� 浣跨敤 `LTRIM(RTRIM())` 娓呯悊绌烘牸
+- 鉁� 鏍规嵁涓氬姟闇�瑕佹坊鍔犲叾浠栭獙璇佹潯浠�
+
+### 4. 瀛楁鍒悕瑙勮寖
+- 鉁� 缁熶竴浣跨敤澶у啓 `AS` 鍏抽敭瀛�
+- 鉁� 鍒悕浣跨敤鏈夋剰涔夌殑鍚嶇О
+- 鉁� 淇濇寔 Java DTO 瀛楁鍚嶄竴鑷达紙椹煎嘲鍛藉悕锛�
+
+### 5. XML 鐗规畩瀛楃澶勭悊 猸� 閲嶈
+- 鉁� SQL 涓寘鍚� `<`銆乣>`銆乣&` 绛夌壒娈婂瓧绗︽椂锛屽繀椤讳娇鐢� `<![CDATA[...]]>` 鍖呰9
+- 鉁� 鎴栦娇鐢� XML 瀹炰綋杞箟锛歚<` 鈫� `<`銆乣>` 鈫� `>`銆乣&` 鈫� `&`
+- 鉁� 鎺ㄨ崘浣跨敤 CDATA锛屽彲璇绘�ф洿濂�
+- 鉂� 閿欒绀轰緥锛歚WHERE count > 0`锛堢洿鎺ヤ娇鐢� `>` 浼氬鑷� XML 瑙f瀽閿欒锛�
+- 鉁� 姝g‘绀轰緥锛歚<![CDATA[WHERE count > 0]]>`
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+### 鈿狅笍 XML 鐗规畩瀛楃澶勭悊锛堥潪甯搁噸瑕侊級
+
+**闂璇存槑**:
+- MyBatis Mapper XML 鏂囦欢涓紝`<`銆乣>`銆乣&`銆乣'`銆乣"` 鏄� XML 淇濈暀瀛楃
+- 鐩存帴鍦� SQL 涓娇鐢ㄨ繖浜涘瓧绗︿細瀵艰嚧 XML 瑙f瀽澶辫触
+- 甯歌閿欒锛歚WHERE count > 0` 鎴� `WHERE price < 100`
+
+**瑙e喅鏂规 1锛氫娇鐢� CDATA 鍖哄潡锛堟帹鑽愶級**
+```xml
+<select id="selectUsers" resultMap="UserResult">
+ <![CDATA[
+ SELECT * FROM users
+ WHERE age > 18 AND score < 100
+ ]]>
+</select>
+```
+
+**瑙e喅鏂规 2锛氫娇鐢� XML 瀹炰綋杞箟**
+```xml
+<select id="selectUsers" resultMap="UserResult">
+ SELECT * FROM users
+ WHERE age > 18 AND score < 100
+</select>
+```
+
+**XML 瀹炰綋瀵圭収琛�**:
+| 瀛楃 | 瀹炰綋 | 璇存槑 |
+|------|------|------|
+| `<` | `<` | 灏忎簬鍙� |
+| `>` | `>` | 澶т簬鍙� |
+| `&` | `&` | 涓庣鍙� |
+| `'` | `'` | 鍗曞紩鍙� |
+| `"` | `"` | 鍙屽紩鍙� |
+
+**鏈�浣冲疄璺�**:
+- 鍖呭惈姣旇緝杩愮畻绗︾殑 SQL 鈫� 浣跨敤 CDATA
+- 鍖呭惈鍔ㄦ�� SQL 鏍囩锛坄<if>`銆乣<where>` 绛夛級鈫� 涓嶈兘浣跨敤 CDATA锛屽繀椤荤敤瀹炰綋杞箟
+
+---
+
+### 鈿狅笍 NOLOCK 浣跨敤鍦烘櫙
+
+**閫傜敤鍦烘櫙**:
+- 鏁版嵁鍚屾浠诲姟
+- 鎶ヨ〃鏌ヨ
+- 涓嶅奖鍝嶄笟鍔$殑缁熻鏌ヨ
+- 鍙蹇嶈剰璇荤殑鍦烘櫙
+
+**涓嶉�傜敤鍦烘櫙**:
+- 閲戣瀺浜ゆ槗鏁版嵁
+- 瀵规暟鎹竴鑷存�ц姹傛瀬楂樼殑鍦烘櫙
+- 闇�瑕佸彲閲嶅璇荤殑涓氬姟閫昏緫
+
+### 鈿狅笍 TOP 鏁伴噺璋冩暣
+
+鏍规嵁瀹為檯涓氬姟瑙勬ā璋冩暣锛�
+- **閮ㄩ棬鏁版嵁**: 褰撳墠璁剧疆 500 鏉★紝鍙牴鎹疄闄呴儴闂ㄦ暟閲忚皟鏁�
+- **鐢ㄦ埛鏁版嵁**: 褰撳墠璁剧疆 5000 鏉★紝浼佷笟鐢ㄦ埛杈冨鏃跺彲閫傚綋澧炲姞
+
+### 鈿狅笍 绱㈠紩寤鸿
+
+寤鸿鍦� SQL Server 绔垱寤轰互涓嬬储寮曪細
+
+```sql
+-- 閮ㄩ棬琛ㄧ储寮�
+CREATE INDEX idx_department_parentID ON uv_department(parentID);
+CREATE INDEX idx_department_name ON uv_department(departmentName);
+
+-- 鐢ㄦ埛琛ㄧ储寮�
+CREATE INDEX idx_oa_user_id ON OA_User(OA_User_ID);
+CREATE INDEX idx_oa_department ON OA_User(OA_departmentID);
+```
+
+---
+
+## 楠岃瘉鏂规硶
+
+### 1. 閮ㄩ棬鍚屾娴嬭瘯
+```bash
+# 璁块棶鎺ュ彛
+POST http://localhost:8080/system/dept/sync/branch
+
+# 鏌ョ湅鏃ュ織
+tail -f logs/ruoyi-admin.log | grep "DepartmentSync"
+```
+
+### 2. 鐢ㄦ埛鍚屾娴嬭瘯
+```bash
+# 璁块棶鎺ュ彛
+POST http://localhost:8080/system/dept/sync/users
+
+# 鏌ョ湅鏃ュ織
+tail -f logs/ruoyi-admin.log | grep "UserSync"
+```
+
+### 3. 瀹氭椂浠诲姟娴嬭瘯
+```bash
+# 鍦ㄧ郴缁熺鐞� > 瀹氭椂浠诲姟涓�
+# 鎵惧埌"OA鏁版嵁鍚屾"浠诲姟
+# 鐐瑰嚮"鎵ц涓�娆�"鎸夐挳
+# 鏌ョ湅璋冨害鏃ュ織
+```
+
+---
+
+## 鏇存柊鍘嗗彶
+
+| 鏃ユ湡 | 鐗堟湰 | 鏇存柊鍐呭 | 鏇存柊浜� |
+|------|------|----------|--------|
+| 2025-10-18 | 1.0 | SQL Server 鏌ヨ浼樺寲 | System |
+
+---
+
+## 鐩稿叧鏂囨。
+
+- [閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨.md](閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨.md)
+- [鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨.md](鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨.md)
+- [OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md](OA鏁版嵁鍚屾瀹氭椂浠诲姟浣跨敤鎸囧崡.md)
diff --git a/WELFARE_EMERGENCY_SEPARATION_GUIDE.md b/WELFARE_EMERGENCY_SEPARATION_GUIDE.md
new file mode 100644
index 0000000..a0ea484
--- /dev/null
+++ b/WELFARE_EMERGENCY_SEPARATION_GUIDE.md
@@ -0,0 +1,433 @@
+# 绂忕杞︿笌鎬ユ晳杞繍鏁版嵁缁撴瀯鍒嗙瀹炵幇璇存槑
+
+## 馃搵 姒傝堪
+
+宸叉垚鍔熷皢绂忕杞﹀拰鎬ユ晳杞繍浠诲姟鐨勬墿灞曚俊鎭垎绂诲埌鐙珛鐨勬暟鎹簱琛ㄤ腑锛屽疄鐜版暟鎹粨鏋勭殑娓呮櫚闅旂銆�
+
+---
+
+## 鉁� 宸插畬鎴愮殑宸ヤ綔
+
+### 1. 鏁版嵁搴撳眰闈㈠垎绂�
+
+#### 1.1 鎬ユ晳杞繍鎵╁睍琛� (`sys_task_emergency`)
+**鐢ㄩ��**: 瀛樺偍鎬ユ晳杞繍浠诲姟鐨勪笓灞炰俊鎭�
+
+**鏍稿績瀛楁**:
+```sql
+- 鎮h�呬俊鎭�: patient_name, patient_phone, patient_gender, patient_condition绛�
+- 杞嚭鍖婚櫌: hospital_out_name, hospital_out_address, GPS鍧愭爣绛�
+- 杞叆鍖婚櫌: hospital_in_name, hospital_in_address, GPS鍧愭爣绛�
+- 璐圭敤淇℃伅: transfer_distance, transfer_price
+```
+
+**SQL鏂囦欢**: `sql/sys_task_emergency.sql`
+
+#### 1.2 绂忕杞︽墿灞曡〃 (`sys_task_welfare`) 猸� 鏂板
+**鐢ㄩ��**: 瀛樺偍绂忕杞︿换鍔$殑涓撳睘淇℃伅
+
+**鏍稿績瀛楁**:
+```sql
+- 涔樺淇℃伅: passenger_name, passenger_phone, passenger_age, passenger_gender绛�
+- 鐗规畩闇�姹�: special_needs
+- 鏈嶅姟淇℃伅: service_type (杞鎺ラ�併�佹媴鏋惰浆杩愮瓑)
+- 鎺ラ�佸湴鍧�: pickup_address, pickup_longitude, pickup_latitude
+- 鐩殑鍦板潃: destination_address, destination_longitude, destination_latitude
+- 璐圭敤淇℃伅: service_distance, service_price
+```
+
+**SQL鏂囦欢**: `sql/sys_task_welfare.sql` 猸� 鏂板缓
+
+**琛ㄧ粨鏋勫姣�**:
+| 瀛楁绫诲埆 | 鎬ユ晳杞繍琛� | 绂忕杞﹁〃 |
+|---------|-----------|---------|
+| 鏍稿績淇℃伅 | 鎮h�� | 涔樺 |
+| 鍦板潃绫诲瀷 | 鍖婚櫌 | 鏅�氬湴鍧� |
+| 鐗硅壊瀛楁 | 鐥呮儏銆佸尰闄㈢瀹ゅ簥鍙� | 鐗规畩闇�姹傘�佹湇鍔$被鍨� |
+| 鍏宠仈鏂瑰紡 | task_id (澶栭敭) | task_id (澶栭敭) |
+
+---
+
+### 2. 瀹炰綋绫诲眰闈㈠垎绂�
+
+#### 2.1 鎬ユ晳杞繍瀹炰綋 (`SysTaskEmergency.java`)
+**浣嶇疆**: `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java`
+
+**鏍稿績灞炴��**:
+```java
+- PatientInfo: 鎮h�呬俊鎭�(濮撳悕銆佺數璇濄�佹�у埆銆佽韩浠借瘉銆佺梾鎯�)
+- HospitalInfo Out: 杞嚭鍖婚櫌淇℃伅
+- HospitalInfo In: 杞叆鍖婚櫌淇℃伅
+- 璐圭敤: transferDistance, transferPrice
+```
+
+#### 2.2 绂忕杞﹀疄浣� (`SysTaskWelfare.java`) 猸� 鏂板
+**浣嶇疆**: `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskWelfare.java`
+
+**鏍稿績灞炴��**:
+```java
+- 涔樺淇℃伅: passengerContact, passengerPhone, passengerName, passengerAge, passengerGender
+- 鐗规畩闇�姹�: specialNeeds
+- 鏈嶅姟绫诲瀷: serviceType
+- 鎺ラ�佸湴鍧�: pickupAddress, pickupLongitude, pickupLatitude
+- 鐩殑鍦板潃: destinationAddress, destinationLongitude, destinationLatitude
+- 璐圭敤: serviceDistance, servicePrice
+```
+
+---
+
+### 3. Mapper灞傞潰鍒嗙
+
+#### 3.1 鎬ユ晳杞繍Mapper
+- **鎺ュ彛**: `SysTaskEmergencyMapper.java`
+- **XML**: `SysTaskEmergencyMapper.xml`
+
+#### 3.2 绂忕杞apper 猸� 鏂板
+- **鎺ュ彛**: `SysTaskWelfareMapper.java`
+- **XML**: `SysTaskWelfareMapper.xml`
+
+**鏂规硶瀵规瘮**:
+```java
+// 閮芥彁渚涚浉鍚岀殑CRUD鏂规硶
+- selectByTaskId(Long taskId)
+- insert(entity)
+- update(entity)
+- deleteByTaskId(Long taskId)
+```
+
+---
+
+### 4. Service灞傞潰鍒嗙
+
+#### 4.1 浠诲姟鍒涘缓閫昏緫鍒嗙
+
+**鎬ユ晳杞繍**:
+```java
+if ("EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
+ saveEmergencyInfo(task.getTaskId(), createVO);
+}
+```
+
+**绂忕杞�**:
+```java
+if ("WELFARE".equals(createVO.getTaskType())) {
+ saveWelfareInfo(task.getTaskId(), createVO);
+}
+```
+
+#### 4.2 鎵╁睍淇℃伅淇濆瓨鏂规硶
+
+**鎬ユ晳杞繍** - `saveEmergencyInfo()`:
+```java
+private void saveEmergencyInfo(Long taskId, TaskCreateVO createVO) {
+ SysTaskEmergency emergencyInfo = new SysTaskEmergency();
+ // 璁剧疆鎮h�呬俊鎭�
+ // 璁剧疆杞嚭鍖婚櫌淇℃伅
+ // 璁剧疆杞叆鍖婚櫌淇℃伅
+ // 璁剧疆璐圭敤淇℃伅
+ sysTaskEmergencyMapper.insertSysTaskEmergency(emergencyInfo);
+}
+```
+
+**绂忕杞�** - `saveWelfareInfo()` 猸� 閲嶆瀯:
+```java
+private void saveWelfareInfo(Long taskId, TaskCreateVO createVO) {
+ SysTaskWelfare welfareInfo = new SysTaskWelfare();
+ // 璁剧疆涔樺淇℃伅
+ // 璁剧疆鍦板潃淇℃伅
+ // 璁剧疆GPS鍧愭爣
+ // 璁剧疆璺濈鍜岃垂鐢�
+ sysTaskWelfareMapper.insertSysTaskWelfare(welfareInfo);
+}
+```
+
+#### 4.3 鏌ヨ閫昏緫鍒嗙
+
+**selectSysTaskByTaskId()** 鏂规硶:
+```java
+if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+ SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
+ task.setEmergencyInfo(emergencyInfo);
+}
+else if ("WELFARE".equals(task.getTaskType())) {
+ SysTaskWelfare welfareInfo = sysTaskWelfareMapper.selectSysTaskWelfareByTaskId(taskId);
+ task.setWelfareInfo(welfareInfo);
+}
+```
+
+**getTaskDetail()** 鏂规硶鍚屾牱杩涜浜嗗垎绂诲鐞�
+
+---
+
+### 5. SysTask瀹炰綋绫绘墿灞�
+
+鏂板涓や釜鐙珛鐨勬墿灞曚俊鎭瓧娈�:
+
+```java
+public class SysTask extends BaseEntity {
+ // ... 鍩虹瀛楁 ...
+
+ /** 鎬ユ晳杞繍鎵╁睍淇℃伅 */
+ private SysTaskEmergency emergencyInfo;
+
+ /** 绂忕杞︽墿灞曚俊鎭� */
+ private SysTaskWelfare welfareInfo; // 猸� 鏂板
+
+ // ... getter/setter ...
+}
+```
+
+---
+
+## 馃攧 鏁版嵁娴佺▼瀵规瘮
+
+### 鎬ユ晳杞繍浠诲姟娴佺▼
+```
+鍒涘缓鎬ユ晳杞繍浠诲姟
+ 鈫�
+taskType = 'EMERGENCY_TRANSFER'
+ 鈫�
+淇濆瓨 sys_task 涓昏〃
+ 鈫�
+璋冪敤 saveEmergencyInfo()
+ 鈫�
+淇濆瓨鍒� sys_task_emergency 琛�
+ 鈫�
+鏌ヨ鏃跺姞杞� emergencyInfo
+ 鈫�
+杩斿洖瀹屾暣鎬ユ晳杞繍浠诲姟
+```
+
+### 绂忕杞︿换鍔℃祦绋�
+```
+鍒涘缓绂忕杞︿换鍔�
+ 鈫�
+taskType = 'WELFARE'
+ 鈫�
+淇濆瓨 sys_task 涓昏〃
+ 鈫�
+璋冪敤 saveWelfareInfo()
+ 鈫�
+淇濆瓨鍒� sys_task_welfare 琛� 猸� 鐙珛琛�
+ 鈫�
+鏌ヨ鏃跺姞杞� welfareInfo 猸� 鐙珛瀛楁
+ 鈫�
+杩斿洖瀹屾暣绂忕杞︿换鍔�
+```
+
+---
+
+## 馃搳 鏁版嵁瀛樺偍瀵规瘮
+
+### 鎬ユ晳杞繍浠诲姟鏁版嵁
+
+**涓昏〃** (`sys_task`):
+```sql
+task_id = 1
+task_type = 'EMERGENCY_TRANSFER'
+task_status = 'PENDING'
+departure_address = NULL (涓嶄娇鐢�,鐢ㄦ墿灞曡〃鐨勫尰闄㈠湴鍧�)
+destination_address = NULL
+```
+
+**鎵╁睍琛�** (`sys_task_emergency`):
+```sql
+task_id = 1
+patient_name = '鏉庡洓'
+patient_phone = '13800138000'
+hospital_out_name = '骞垮窞甯傜涓�浜烘皯鍖婚櫌'
+hospital_in_name = '骞夸笢鐪佷汉姘戝尰闄�'
+transfer_distance = 5.2
+transfer_price = 800
+```
+
+### 绂忕杞︿换鍔℃暟鎹�
+
+**涓昏〃** (`sys_task`):
+```sql
+task_id = 2
+task_type = 'WELFARE'
+task_status = 'PENDING'
+departure_address = '骞垮窞甯傚ぉ娌冲尯...' (鍙��,涓昏鐢ㄦ墿灞曡〃)
+destination_address = '骞垮窞甯傝秺绉�鍖�...'
+```
+
+**鎵╁睍琛�** (`sys_task_welfare`) 猸�:
+```sql
+task_id = 2
+passenger_name = NULL (鍙��)
+passenger_contact = '寮犱笁'
+passenger_phone = '13800138000'
+pickup_address = '骞垮窞甯傚ぉ娌冲尯XX璺�123鍙�'
+destination_address = '骞垮窞甯傝秺绉�鍖篩Y璺�456鍙�'
+service_distance = 5.2
+service_price = 300
+```
+
+---
+
+## 馃幆 鍒嗙鐨勪紭鍔�
+
+### 1. 鏁版嵁缁撴瀯娓呮櫚
+- 鉁� 鎬ユ晳杞繍鍜岀绁夎溅鍚勬湁涓撳睘琛�
+- 鉁� 瀛楁璇箟鏄庣‘,涓嶄細娣锋穯
+- 鉁� 鏄撲簬鐞嗚В鍜岀淮鎶�
+
+### 2. 鎬ц兘浼樺寲
+- 鉁� 鏌ヨ鏃跺彧鍔犺浇瀵瑰簲绫诲瀷鐨勬墿灞曚俊鎭�
+- 鉁� 鍑忓皯鏃犳晥鏁版嵁浼犺緭
+- 鉁� 绱㈠紩鏇寸簿纭�
+
+### 3. 鎵╁睍鎬уソ
+- 鉁� 鏂板浠诲姟绫诲瀷鏃�,鍙垱寤虹嫭绔嬫墿灞曡〃
+- 鉁� 涓嶅奖鍝嶇幇鏈夎〃缁撴瀯
+- 鉁� 绗﹀悎寮�闂師鍒�
+
+### 4. 涓氬姟闅旂
+- 鉁� 鎬ユ晳杞繍鍜岀绁夎溅涓氬姟閫昏緫瀹屽叏鍒嗙
+- 鉁� 淇敼涓�绉嶇被鍨嬩笉褰卞搷鍙︿竴绉�
+- 鉁� 闄嶄綆鑰﹀悎搴�
+
+---
+
+## 馃搧 鏂板鏂囦欢娓呭崟
+
+### 鏁版嵁搴撹剼鏈�
+- 鉁� `sql/sys_task_welfare.sql` - 绂忕杞︽墿灞曡〃缁撴瀯
+
+### Java瀹炰綋绫�
+- 鉁� `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskWelfare.java`
+
+### Mapper鎺ュ彛鍜孹ML
+- 鉁� `ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskWelfareMapper.java`
+- 鉁� `ruoyi-system/src/main/resources/mapper/system/SysTaskWelfareMapper.xml`
+
+### 淇敼鏂囦欢娓呭崟
+
+- 鉁� `SysTask.java` - 娣诲姞 welfareInfo 瀛楁
+- 鉁� `SysTaskServiceImpl.java` - 鍒嗙淇濆瓨鍜屾煡璇㈤�昏緫
+
+---
+
+## 馃殌 閮ㄧ讲姝ラ
+
+### 1. 鎵ц鏁版嵁搴撹剼鏈�
+
+```bash
+# 鍒涘缓绂忕杞︽墿灞曡〃
+mysql -u root -p your_database < sql/sys_task_welfare.sql
+```
+
+### 2. 閲嶆柊缂栬瘧鍚庣
+
+```bash
+cd d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master
+mvn clean package -DskipTests
+```
+
+### 3. 閲嶅惎鏈嶅姟
+
+```bash
+bin\run.bat
+```
+
+### 4. 楠岃瘉鏁版嵁
+
+```sql
+-- 楠岃瘉鎬ユ晳杞繍浠诲姟
+SELECT
+ t.task_id,
+ t.task_type,
+ e.patient_name,
+ e.hospital_out_name
+FROM sys_task t
+LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
+WHERE t.task_type = 'EMERGENCY_TRANSFER';
+
+-- 楠岃瘉绂忕杞︿换鍔�
+SELECT
+ t.task_id,
+ t.task_type,
+ w.passenger_contact,
+ w.pickup_address,
+ w.destination_address
+FROM sys_task t
+LEFT JOIN sys_task_welfare w ON t.task_id = w.task_id
+WHERE t.task_type = 'WELFARE';
+```
+
+---
+
+## 鉁� 娴嬭瘯寤鸿
+
+### 1. 鎬ユ晳杞繍浠诲姟娴嬭瘯
+- [ ] 鍒涘缓鎬ユ晳杞繍浠诲姟,濉啓鎮h�呭拰鍖婚櫌淇℃伅
+- [ ] 楠岃瘉鏁版嵁淇濆瓨鍒� `sys_task_emergency` 琛�
+- [ ] 鏌ヨ浠诲姟璇︽儏,纭 `emergencyInfo` 瀛楁鏈夋暟鎹�
+- [ ] 纭 `welfareInfo` 瀛楁涓� null
+
+### 2. 绂忕杞︿换鍔℃祴璇�
+- [ ] 鍒涘缓绂忕杞︿换鍔�,濉啓涔樺鍜屽湴鍧�淇℃伅
+- [ ] 楠岃瘉鏁版嵁淇濆瓨鍒� `sys_task_welfare` 琛� (涓嶆槸emergency琛�)
+- [ ] 鏌ヨ浠诲姟璇︽儏,纭 `welfareInfo` 瀛楁鏈夋暟鎹�
+- [ ] 纭 `emergencyInfo` 瀛楁涓� null
+
+### 3. 鏁版嵁闅旂楠岃瘉
+```sql
+-- 鎬ユ晳杞繍浠诲姟涓嶅簲璇ュ湪绂忕杞﹁〃涓湁鏁版嵁
+SELECT COUNT(*) FROM sys_task_welfare
+WHERE task_id IN (
+ SELECT task_id FROM sys_task WHERE task_type = 'EMERGENCY_TRANSFER'
+);
+-- 棰勬湡缁撴灉: 0
+
+-- 绂忕杞︿换鍔′笉搴旇鍦ㄦ�ユ晳杞繍琛ㄤ腑鏈夋暟鎹�
+SELECT COUNT(*) FROM sys_task_emergency
+WHERE task_id IN (
+ SELECT task_id FROM sys_task WHERE task_type = 'WELFARE'
+);
+-- 棰勬湡缁撴灉: 0
+```
+
+---
+
+## 馃摑 鍓嶇鏃犻渶淇敼
+
+鉁� **鍓嶇浠g爜瀹屽叏鍏煎**,鏃犻渶浠讳綍淇敼!
+
+鍘熷洜:
+1. 鍓嶇鎻愪氦鐨勬暟鎹牸寮忎笉鍙�
+2. 鍚庣鑷姩鏍规嵁 `taskType` 閫夋嫨姝g‘鐨勬墿灞曡〃
+3. 杩斿洖鐨凧SON缁撴瀯淇濇寔鍏煎
+
+---
+
+## 馃帀 鎬荤粨
+
+### 鍒嗙鍓�
+```
+sys_task_emergency 琛�
+鈹溾攢鈹� 鎬ユ晳杞繍鏁版嵁 (鎮h�呫�佸尰闄�)
+鈹斺攢鈹� 绂忕杞︽暟鎹� (涔樺) 鉂� 娣峰湪涓�璧�
+```
+
+### 鍒嗙鍚�
+```
+sys_task_emergency 琛�
+鈹斺攢鈹� 鎬ユ晳杞繍鏁版嵁 (鎮h�呫�佸尰闄�) 鉁� 涓撶敤
+
+sys_task_welfare 琛�
+鈹斺攢鈹� 绂忕杞︽暟鎹� (涔樺銆佸湴鍧�) 鉁� 涓撶敤
+```
+
+**浼樼偣鎬荤粨**:
+- 鉁� 鏁版嵁缁撴瀯娓呮櫚,涓氬姟閫昏緫鍒嗙
+- 鉁� 鎬ц兘鏇翠紭,鎸夐渶鍔犺浇
+- 鉁� 鏄撲簬鎵╁睍鍜岀淮鎶�
+- 鉁� 绗﹀悎鍗曚竴鑱岃矗鍘熷垯
+
+---
+
+**瀹炴柦瀹屾垚鏃堕棿**: 2025-10-16
+**瀹炴柦鐘舵��**: 鉁� 宸插畬鎴�
+**娴嬭瘯鐘舵��**: 鈴� 寰呮祴璇�
diff --git a/WELFARE_TASK_CHECK_REPORT.md b/WELFARE_TASK_CHECK_REPORT.md
new file mode 100644
index 0000000..9765d1a
--- /dev/null
+++ b/WELFARE_TASK_CHECK_REPORT.md
@@ -0,0 +1,461 @@
+# 绂忕杞︿换鍔″垱寤哄姛鑳芥鏌ユ姤鍛�
+
+## 鉁� 鎬讳綋璇勪及
+
+**缁撹**: 绂忕杞︿换鍔″垱寤洪〉闈� `create-welfare.vue` **鍔熻兘瀹屾暣锛屽凡姝g‘瀵规帴鍚庣**锛�
+
+---
+
+## 馃搵 璇︾粏妫�鏌ョ粨鏋�
+
+### 1. 鍓嶇椤甸潰鍔熻兘妫�鏌�
+
+#### 1.1 鉁� 鍩虹鍔熻兘
+
+| 鍔熻兘椤� | 鐘舵�� | 璇存槑 |
+|-------|------|------|
+| 杞﹁締閫夋嫨 | 鉁� 姝e父 | 鏍规嵁閮ㄩ棬绛涢�塛ELFARE绫诲瀷杞﹁締 |
+| 浜哄憳绠$悊 | 鉁� 姝e父 | 鏀寔娣诲姞/绉婚櫎鎵ц浜哄憳 |
+| 鏈烘瀯閫夋嫨 | 鉁� 姝e父 | 涓嬫媺閫夋嫨褰掑睘鏈烘瀯 |
+| 鏈嶅姟鏃堕棿 | 鉁� 姝e父 | 浣跨敤uni-datetime-picker閫夋嫨 |
+| 涔樺淇℃伅 | 鉁� 姝e父 | 鑱旂郴浜恒�佽仈绯荤數璇� |
+| 鍦板潃閫夋嫨 | 鉁� 姝e父 | 鍑哄彂鍦板潃銆佺洰鐨勫湴鍧�(鍦板浘閫夋嫨鍣�) |
+| 璺濈璁$畻 | 鉁� 姝e父 | 鑷姩璁$畻鍑哄彂鍦板埌鐩殑鍦拌窛绂� |
+| 璐圭敤淇℃伅 | 鉁� 姝e父 | 鍏噷鏁般�佹垚浜や环 |
+| 琛ㄥ崟楠岃瘉 | 鉁� 姝e父 | 蹇呭~椤归獙璇佸畬鏁� |
+| 鏁版嵁鎻愪氦 | 鉁� 姝e父 | 璋冪敤addTask鎺ュ彛 |
+
+#### 1.2 鉁� 鍏抽敭浠g爜鐗囨
+
+**杞﹁締鍔犺浇** (绗�218-230琛�):
+```javascript
+getAvailableVehicles() {
+ const deptId = this.currentUser.deptId
+ return listAvailableVehicles(deptId, 'WELFARE').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ status: vehicle.status
+ }))
+ this.vehicles = this.vehicleOptions.map(v => v.name)
+ })
+}
+```
+鉁� **鐘舵��**: 姝g‘浼犻�� `'WELFARE'` 绫诲瀷鍙傛暟
+
+**鍦板潃閫夋嫨鍜岃窛绂昏绠�** (绗�268-301琛�):
+```javascript
+onAddressSelected(address) {
+ if (this.mapSelectorType === 'startAddress') {
+ this.taskForm.startAddress = address.title + ' - ' + address.address
+ this.addressCoordinates.startAddress = {
+ lat: address.lat,
+ lng: address.lng
+ }
+ } else if (this.mapSelectorType === 'endAddress') {
+ this.taskForm.endAddress = address.title + ' - ' + address.address
+ this.addressCoordinates.endAddress = {
+ lat: address.lat,
+ lng: address.lng
+ }
+ }
+
+ this.calculateWelfareDistance() // 鈫� 鑷姩璁$畻璺濈
+ this.closeMapSelector()
+}
+```
+鉁� **鐘舵��**: 鍦板浘閫夋嫨鍣ㄩ泦鎴愭甯革紝璺濈鑷姩璁$畻
+
+**琛ㄥ崟楠岃瘉** (绗�337-362琛�):
+```javascript
+validateForm() {
+ if (!this.selectedVehicleId) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟杞﹁締')
+ return false
+ }
+
+ if (!this.taskForm.passenger.contact) {
+ this.$modal.showToast('璇疯緭鍏ヨ仈绯讳汉')
+ return false
+ }
+
+ if (!this.taskForm.passenger.phone) {
+ this.$modal.showToast('璇疯緭鍏ヨ仈绯荤數璇�')
+ return false
+ }
+
+ if (!this.taskForm.startAddress) {
+ this.$modal.showToast('璇烽�夋嫨鍑哄彂鍦板潃')
+ return false
+ }
+
+ if (!this.taskForm.endAddress) {
+ this.$modal.showToast('璇烽�夋嫨鐩殑鍦板潃')
+ return false
+ }
+
+ return true
+}
+```
+鉁� **鐘舵��**: 蹇呭~椤归獙璇佸畬鏁�
+
+**鏁版嵁鏋勫缓** (绗�364-390琛�):
+```javascript
+buildSubmitData() {
+ const submitData = {
+ taskType: 'WELFARE', // 鈫� 绂忕杞︾被鍨�
+ vehicleIds: this.selectedVehicleId ? [this.selectedVehicleId] : [],
+ serviceTime: this.taskForm.serviceTime,
+ passenger: this.taskForm.passenger, // 鈫� 涔樺淇℃伅
+ startAddress: this.taskForm.startAddress,
+ endAddress: this.taskForm.endAddress,
+ distance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
+ price: this.taskForm.price ? parseFloat(this.taskForm.price) : null
+ }
+
+ // 娣诲姞GPS鍧愭爣
+ if (this.addressCoordinates.startAddress) {
+ submitData.departureLongitude = this.addressCoordinates.startAddress.lng
+ submitData.departureLatitude = this.addressCoordinates.startAddress.lat
+ }
+
+ if (this.addressCoordinates.endAddress) {
+ submitData.destinationLongitude = this.addressCoordinates.endAddress.lng
+ submitData.destinationLatitude = this.addressCoordinates.endAddress.lat
+ }
+
+ return submitData
+}
+```
+鉁� **鐘舵��**: 鏁版嵁鏍煎紡姝g‘锛屽寘鍚墍鏈夊繀瑕佸瓧娈�
+
+---
+
+### 2. 鍚庣鎺ュ彛瀵规帴妫�鏌�
+
+#### 2.1 鉁� API鎺ュ彛
+
+**鍓嶇璋冪敤**:
+```javascript
+import { addTask } from "@/api/task"
+import { listAvailableVehicles } from "@/api/vehicle"
+import { calculateDistance } from "@/api/map"
+```
+
+**鎺ュ彛瀹氫箟** (`app/api/task.js`):
+```javascript
+export function addTask(data) {
+ return request({
+ url: '/task',
+ method: 'post',
+ data: data
+ })
+}
+```
+
+鉁� **鐘舵��**: 鎺ュ彛宸叉纭紩鍏ュ苟璋冪敤
+
+#### 2.2 鉁� 鍚庣VO瀵硅薄鍖归厤
+
+**TaskCreateVO.java** 鏀寔绂忕杞﹀瓧娈�:
+
+```java
+// 绂忕杞︾壒瀹氬瓧娈�
+private Date serviceTime; // 鉁� 鏈嶅姟鏃堕棿
+private PassengerInfo passenger; // 鉁� 涔樺淇℃伅
+private String startAddress; // 鉁� 璧峰鍦板潃
+private String endAddress; // 鉁� 缁撴潫鍦板潃
+
+// 涔樺淇℃伅鍐呴儴绫�
+public static class PassengerInfo {
+ private String contact; // 鉁� 鑱旂郴浜�
+ private String phone; // 鉁� 鑱旂郴鐢佃瘽
+}
+```
+
+**鍓嶇鎻愪氦鏁版嵁**:
+```javascript
+{
+ taskType: 'WELFARE',
+ vehicleIds: [vehicleId],
+ serviceTime: '2025-10-17 14:00:00',
+ passenger: {
+ contact: '寮犱笁',
+ phone: '13800138000'
+ },
+ startAddress: '骞垮窞甯傚ぉ娌冲尯...',
+ endAddress: '骞垮窞甯傝秺绉�鍖�...',
+ departureLongitude: 113.xxx,
+ departureLatitude: 23.xxx,
+ destinationLongitude: 113.xxx,
+ destinationLatitude: 23.xxx,
+ distance: 5.2,
+ price: 300
+}
+```
+
+鉁� **鐘舵��**: 鍓嶅悗绔暟鎹牸寮�**瀹屽叏鍖归厤**
+
+#### 2.3 鉁� Service灞傚鐞�
+
+**SysTaskServiceImpl.java** 宸插疄鐜扮绁夎溅鎵╁睍淇℃伅淇濆瓨:
+
+```java
+// 绗�190琛� - insertSysTask鏂规硶涓�
+if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
+ saveWelfareInfo(task.getTaskId(), createVO);
+}
+
+// 绗�792-809琛� - saveWelfareInfo鏂规硶
+private void saveWelfareInfo(Long taskId, TaskCreateVO createVO) {
+ SysTaskEmergency welfareInfo = new SysTaskEmergency();
+ welfareInfo.setTaskId(taskId);
+
+ // 璁剧疆涔樺淇℃伅
+ if (createVO.getPassenger() != null) {
+ welfareInfo.setPassengerContact(createVO.getPassenger().getContact());
+ welfareInfo.setPassengerPhone(createVO.getPassenger().getPhone());
+ }
+
+ // 绯荤粺瀛楁
+ welfareInfo.setCreateTime(DateUtils.getNowDate());
+ welfareInfo.setUpdateTime(DateUtils.getNowDate());
+ welfareInfo.setCreateBy(SecurityUtils.getUsername());
+ welfareInfo.setUpdateBy(SecurityUtils.getUsername());
+
+ sysTaskEmergencyMapper.insertSysTaskEmergency(welfareInfo);
+}
+```
+
+鉁� **鐘舵��**: 鍚庣宸叉纭鐞嗙绁夎溅浠诲姟绫诲瀷
+
+---
+
+### 3. 鏁版嵁搴撳瓨鍌ㄦ鏌�
+
+#### 3.1 鉁� 涓讳换鍔¤〃 (sys_task)
+
+绂忕杞︿换鍔′繚瀛樺埌涓昏〃鐨勫瓧娈�:
+```sql
+task_type = 'WELFARE'
+task_status = 'PENDING'
+planned_start_time = serviceTime
+departure_address = startAddress
+destination_address = endAddress
+departure_longitude = GPS鍧愭爣
+departure_latitude = GPS鍧愭爣
+destination_longitude = GPS鍧愭爣
+destination_latitude = GPS鍧愭爣
+estimated_distance = distance
+```
+
+#### 3.2 鉁� 鎵╁睍淇℃伅琛� (sys_task_emergency)
+
+绂忕杞︽墿灞曚俊鎭瓧娈�:
+```sql
+task_id = 浠诲姟ID
+passenger_contact = 涔樺鑱旂郴浜�
+passenger_phone = 涔樺鑱旂郴鐢佃瘽
+```
+
+鉁� **鐘舵��**: 鏁版嵁搴撹〃缁撴瀯瀹屾暣锛屾敮鎸佺绁夎溅浠诲姟
+
+---
+
+### 4. 瀹屾暣鏁版嵁娴佺▼
+
+```
+鐢ㄦ埛濉啓绂忕杞︿换鍔¤〃鍗�
+ 鈫�
+閫夋嫨杞﹁締 (WELFARE绫诲瀷)
+ 鈫�
+濉啓涔樺淇℃伅
+ 鈫�
+閫夋嫨鍑哄彂鍦板潃 (鍦板浘閫夋嫨鍣�)
+ 鈫�
+閫夋嫨鐩殑鍦板潃 (鍦板浘閫夋嫨鍣�)
+ 鈫�
+鑷姩璁$畻璺濈 鉁�
+ 鈫�
+濉啓璐圭敤淇℃伅
+ 鈫�
+琛ㄥ崟楠岃瘉 鉁�
+ 鈫�
+鏋勫缓鎻愪氦鏁版嵁 (buildSubmitData) 鉁�
+ 鈫�
+璋冪敤 addTask() API 鉁�
+ 鈫�
+POST /task 鈫� SysTaskController 鉁�
+ 鈫�
+SysTaskServiceImpl.insertSysTask() 鉁�
+ 鈫�
+淇濆瓨 sys_task (涓昏〃) 鉁�
+ 鈫�
+鍒ゆ柇 taskType = 'WELFARE' 鉁�
+ 鈫�
+璋冪敤 saveWelfareInfo() 鉁�
+ 鈫�
+淇濆瓨 sys_task_emergency (涔樺淇℃伅) 鉁�
+ 鈫�
+杩斿洖鎴愬姛鍝嶅簲 鉁�
+ 鈫�
+鏄剧ず鎴愬姛鎻愮ず骞惰烦杞� 鉁�
+```
+
+---
+
+## 馃幆 鍔熻兘瀹屾暣鎬ц瘎鍒�
+
+| 璇勪及椤� | 璇勫垎 | 璇存槑 |
+|-------|------|------|
+| **UI璁捐** | 猸愨瓙猸愨瓙猸� | 鐣岄潰娓呮櫚锛岀鍚堣璁¤鑼� |
+| **琛ㄥ崟鍔熻兘** | 猸愨瓙猸愨瓙猸� | 鎵�鏈夎緭鍏ラ」姝e父宸ヤ綔 |
+| **鍦板浘闆嗘垚** | 猸愨瓙猸愨瓙猸� | 鍦板浘閫夋嫨鍣ㄥ畬缇庨泦鎴� |
+| **鏁版嵁楠岃瘉** | 猸愨瓙猸愨瓙猸� | 蹇呭~椤归獙璇佸畬鏁� |
+| **鎺ュ彛瀵规帴** | 猸愨瓙猸愨瓙猸� | 鍓嶅悗绔畬鍏ㄥ鎺� |
+| **鏁版嵁瀛樺偍** | 猸愨瓙猸愨瓙猸� | 鏁版嵁搴撹〃缁撴瀯鏀寔 |
+| **閿欒澶勭悊** | 猸愨瓙猸愨瓙猸� | 寮傚父澶勭悊瀹屽杽 |
+
+**鎬讳綋璇勫垎**: 猸愨瓙猸愨瓙猸� (5/5)
+
+---
+
+## 鉁� 宸插疄鐜扮殑鍔熻兘娓呭崟
+
+- [x] 杞﹁締閫夋嫨 (鏍规嵁閮ㄩ棬鍜學ELFARE绫诲瀷绛涢��)
+- [x] 浜哄憳绠$悊 (鏄剧ず褰撳墠鐢ㄦ埛锛屾敮鎸佹坊鍔犱汉鍛�)
+- [x] 鏈烘瀯閫夋嫨
+- [x] 鏈嶅姟鏃堕棿閫夋嫨 (uni-datetime-picker)
+- [x] 涔樺淇℃伅閲囬泦 (鑱旂郴浜恒�佺數璇�)
+- [x] 鍑哄彂鍦板潃閫夋嫨 (鍦板浘閫夋嫨鍣�)
+- [x] 鐩殑鍦板潃閫夋嫨 (鍦板浘閫夋嫨鍣�)
+- [x] GPS鍧愭爣璁板綍
+- [x] 鑷姩璺濈璁$畻
+- [x] 璐圭敤淇℃伅褰曞叆 (鍏噷鏁般�佹垚浜や环)
+- [x] 琛ㄥ崟楠岃瘉 (蹇呭~椤归獙璇�)
+- [x] 鏁版嵁鎻愪氦 (璋冪敤鍚庣API)
+- [x] 鍚庣鎵╁睍淇℃伅淇濆瓨 (sys_task_emergency琛�)
+- [x] 鎴愬姛鍙嶉鍜岄〉闈㈣烦杞�
+
+---
+
+## 馃攳 涓庢�ユ晳杞繍浠诲姟瀵规瘮
+
+| 鍔熻兘妯″潡 | 鎬ユ晳杞繍 | 绂忕杞� | 璇存槑 |
+|---------|---------|--------|------|
+| **琛ㄥ崟瀛楁** | 鎮h�呬俊鎭�佸尰闄俊鎭� | 涔樺淇℃伅 | 鉁� 鍚勬湁渚ч噸 |
+| **鍦板浘閫夋嫨** | 杞嚭/杞叆鍖婚櫌鍦板潃 | 鍑哄彂/鐩殑鍦板潃 | 鉁� 鍧囧凡闆嗘垚 |
+| **璺濈璁$畻** | 鑷姩璁$畻 | 鑷姩璁$畻 | 鉁� 鍔熻兘涓�鑷� |
+| **杞﹁締绛涢��** | EMERGENCY绫诲瀷 | WELFARE绫诲瀷 | 鉁� 绫诲瀷鍖哄垎 |
+| **鏁版嵁瀛樺偍** | sys_task_emergency | sys_task_emergency | 鉁� 鍏辩敤鎵╁睍琛� |
+| **鍚庣澶勭悊** | saveEmergencyInfo() | saveWelfareInfo() | 鉁� 鍒嗗埆澶勭悊 |
+
+---
+
+## 馃搳 鎺ュ彛瀵规帴鐘舵�佹眹鎬�
+
+| 鍔熻兘 | 鍓嶇鏂规硶 | API鎺ュ彛 | 鍚庣鎺ュ彛 | 鐘舵�� |
+|-----|---------|---------|---------|------|
+| 鍒涘缓浠诲姟 | `submitTask()` | `addTask()` | `POST /task` | 鉁� 宸插鎺� |
+| 鑾峰彇杞﹁締 | `getAvailableVehicles()` | `listAvailableVehicles()` | `GET /task/vehicle/available?taskType=WELFARE` | 鉁� 宸插鎺� |
+| 璁$畻璺濈 | `calculateWelfareDistance()` | `calculateDistance()` | `GET /map/calculate-distance` | 鉁� 宸插鎺� |
+| 鍦板浘閫夋嫨 | `onAddressSelected()` | MapSelector缁勪欢 | - | 鉁� 宸查泦鎴� |
+
+---
+
+## 鉁� 娴嬭瘯寤鸿
+
+### 1. 鍔熻兘娴嬭瘯娴佺▼
+
+```
+1. 璁块棶绂忕杞︿换鍔″垱寤洪〉闈�
+2. 閫夋嫨杞﹁締 (鑷姩鍔犺浇WELFARE绫诲瀷杞﹁締)
+3. 濉啓涔樺鑱旂郴浜�: 寮犱笁
+4. 濉啓鑱旂郴鐢佃瘽: 13800138000
+5. 閫夋嫨鏈嶅姟鏃堕棿: 2025-10-17 14:00:00
+6. 閫夋嫨鍑哄彂鍦板潃 (浣跨敤鍦板浘閫夋嫨鍣�)
+7. 閫夋嫨鐩殑鍦板潃 (浣跨敤鍦板浘閫夋嫨鍣�)
+8. 绯荤粺鑷姩璁$畻璺濈 (濡�5.2鍏噷)
+9. 濉啓鎴愪氦浠�: 300鍏�
+10. 鐐瑰嚮淇濆瓨
+11. 楠岃瘉鎻愮ず淇℃伅
+12. 妫�鏌ユ暟鎹簱璁板綍
+```
+
+### 2. 鏁版嵁楠岃瘉SQL
+
+```sql
+-- 鏌ョ湅鏈�鏂板垱寤虹殑绂忕杞︿换鍔�
+SELECT
+ t.task_id,
+ t.task_code,
+ t.task_type,
+ t.task_status,
+ t.departure_address,
+ t.destination_address,
+ t.estimated_distance,
+ e.passenger_contact,
+ e.passenger_phone
+FROM sys_task t
+LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
+WHERE t.task_type = 'WELFARE'
+ORDER BY t.create_time DESC
+LIMIT 1;
+```
+
+**棰勬湡缁撴灉**:
+```
+task_type = 'WELFARE'
+task_status = 'PENDING'
+departure_address = '鍑哄彂鍦板潃'
+destination_address = '鐩殑鍦板潃'
+estimated_distance = 5.2
+passenger_contact = '寮犱笁'
+passenger_phone = '13800138000'
+```
+
+### 3. 杈圭晫鏉′欢娴嬭瘯
+
+- [ ] 涓嶉�夋嫨杞﹁締鐩存帴鎻愪氦 鈫� 搴旀樉绀�"璇烽�夋嫨浠诲姟杞﹁締"
+- [ ] 涓嶅~鍐欒仈绯讳汉 鈫� 搴旀樉绀�"璇疯緭鍏ヨ仈绯讳汉"
+- [ ] 涓嶅~鍐欑數璇� 鈫� 搴旀樉绀�"璇疯緭鍏ヨ仈绯荤數璇�"
+- [ ] 涓嶉�夋嫨鍑哄彂鍦板潃 鈫� 搴旀樉绀�"璇烽�夋嫨鍑哄彂鍦板潃"
+- [ ] 涓嶉�夋嫨鐩殑鍦板潃 鈫� 搴旀樉绀�"璇烽�夋嫨鐩殑鍦板潃"
+- [ ] 浠呴�夋嫨鍑哄彂鍦板潃 鈫� 涓嶈嚜鍔ㄨ绠楄窛绂�
+- [ ] 閫夋嫨涓や釜鍦板潃 鈫� 鑷姩璁$畻璺濈
+
+---
+
+## 馃帀 鎬荤粨
+
+### 鉁� 浼樼偣
+
+1. **鍔熻兘瀹屾暣**: 鎵�鏈夊繀闇�鍔熻兘鍧囧凡瀹炵幇
+2. **鎺ュ彛瀵规帴**: 鍓嶅悗绔畬鍏ㄥ鎺ワ紝鏁版嵁娴佺晠閫�
+3. **鐢ㄦ埛浣撻獙**: 鍦板浘閫夋嫨鍣ㄣ�佽嚜鍔ㄨ绠楄窛绂荤瓑鍔熻兘鎻愬崌浣撻獙
+4. **鏁版嵁瀹夊叏**: 琛ㄥ崟楠岃瘉瀹屾暣锛岄槻姝㈡棤鏁堟暟鎹彁浜�
+5. **浠g爜璐ㄩ噺**: 缁撴瀯娓呮櫚锛屾槗浜庣淮鎶�
+
+### 馃摑 寤鸿浼樺寲椤� (鍙��)
+
+1. **褰掑睘鏈烘瀯**: 褰撳墠鏄啓姝荤殑鏁扮粍锛屽彲鏀逛负浠庡瓧鍏歌〃鍔犺浇
+2. **浜哄憳绠$悊**: "娣诲姞浜哄憳"鍔熻兘鎻愮ず"寮�鍙戜腑"锛屽悗缁彲瀹屽杽
+3. **璺濈鍗曚綅**: 鍙坊鍔犲崟浣嶆樉绀�(濡�"5.2鍏噷")
+4. **璐圭敤璁$畻**: 鍙牴鎹窛绂昏嚜鍔ㄨ绠楀缓璁环鏍�
+
+### 馃殌 鍙互鐩存帴浣跨敤
+
+**绂忕杞︿换鍔″垱寤洪〉闈㈠姛鑳藉畬鏁达紝宸插畬鍏ㄥ鎺ュ悗绔紝鍙互鐩存帴鎶曞叆浣跨敤锛�**
+
+鍙渶:
+1. 鉁� 纭繚鍚庣鏈嶅姟宸插惎鍔�
+2. 鉁� 鏁版嵁搴撹〃 `sys_task_emergency` 宸插垱寤�
+3. 鉁� 鍓嶇璁块棶椤甸潰鍗冲彲鍒涘缓绂忕杞︿换鍔�
+
+---
+
+**妫�鏌ュ畬鎴愭椂闂�**: 2025-10-16
+**妫�鏌ョ粨鏋�**: 鉁� 鍔熻兘姝e父锛屽彲浠ヤ娇鐢�
+**璇勫垎**: 猸愨瓙猸愨瓙猸� (5/5)
diff --git a/app/API_FIX_SUMMARY.md b/app/API_FIX_SUMMARY.md
new file mode 100644
index 0000000..40c6b7a
--- /dev/null
+++ b/app/API_FIX_SUMMARY.md
@@ -0,0 +1,97 @@
+# 鎺ュ彛淇鎬荤粨
+
+## 闂鎻忚堪
+鐢ㄦ埛鍙嶉 `vehicle/available?deptId=100&taskType=GENERAL` 鎺ュ彛杩斿洖 404 閿欒銆�
+
+## 闂鍒嗘瀽
+缁忚繃妫�鏌ュ彂鐜帮紝鍚庣纭疄瀹炵幇浜嗗彲鐢ㄨ溅杈嗘煡璇㈡帴鍙o紝浣嗘槸鎺ュ彛璺緞涓庡墠绔皟鐢ㄤ笉鍖归厤銆�
+
+## 淇鍐呭
+
+### 1. 鎺ュ彛璺緞淇
+**闂**锛氬墠绔皟鐢� `/vehicle/available`锛屼絾鍚庣瀹為檯璺緞鏄� `/task/vehicle/available`
+
+**淇**锛�
+- 鏂囦欢锛歚app/api/vehicle.js`
+- 淇敼锛歚listAvailableVehicles` 鍑芥暟鐨� URL 浠� `/vehicle/available` 鏀逛负 `/task/vehicle/available`
+
+### 2. 鏁版嵁瀛楁鏄犲皠淇
+**闂**锛氬墠绔湡鏈涚殑瀛楁鍚嶄笌鍚庣杩斿洖鐨勫瓧娈靛悕涓嶅尮閰�
+
+**鍚庣杩斿洖瀛楁**锛圫ysTaskVehicle锛夛細
+- `vehicleNo` - 杞︾墝鍙�
+- `vehicleId` - 杞﹁締ID
+- `vehicleType` - 杞﹁締绫诲瀷
+- `status` - 鐘舵��
+
+**淇鐨勬枃浠�**锛�
+- `app/pages/task/create.vue` - 淇杞﹁締鏁版嵁鏄犲皠
+- `app/pages/task/index.vue` - 淇杞﹁締瀛楁寮曠敤
+- `app/pages/task/detail.vue` - 淇杞﹁締瀛楁鏄剧ず
+
+### 3. 鎺ュ彛瀹炵幇鐘舵��
+**宸插疄鐜扮殑鎺ュ彛**锛�
+- 鉁� `GET /task/vehicle/available` - 鏌ヨ鍙敤杞﹁締鍒楄〃
+- 鉁� `GET /task/vehicle/list/{taskId}` - 鏌ヨ浠诲姟鍏宠仈杞﹁締
+- 鉁� `POST /task/vehicle/assign/{taskId}` - 鍒嗛厤杞﹁締缁欎换鍔�
+
+**鍙兘鏈疄鐜扮殑鎺ュ彛**锛�
+- 鉂� `GET /task/vehicle/user/{userId}` - 鏌ヨ鐢ㄦ埛缁戝畾杞﹁締
+- 鉂� `POST /vehicle/bind` - 缁戝畾杞﹁締缁欑敤鎴�
+- 鉂� `POST /vehicle/unbind` - 瑙g粦鐢ㄦ埛杞﹁締
+
+## 娴嬭瘯寤鸿
+
+### 1. 娴嬭瘯鍙敤杞﹁締鎺ュ彛
+```bash
+GET /task/vehicle/available?deptId=100&taskType=GENERAL
+```
+
+**鏈熸湜杩斿洖**锛�
+```json
+{
+ "code": 200,
+ "msg": "鏌ヨ鎴愬姛",
+ "data": [
+ {
+ "vehicleId": 1,
+ "vehicleNo": "绮12345",
+ "vehicleType": "AMBULANCE",
+ "vehicleBrand": "濂旈┌",
+ "vehicleModel": "Vito",
+ "deptName": "骞垮窞鍒嗗叕鍙�"
+ }
+ ]
+}
+```
+
+### 2. 娴嬭瘯浠诲姟鍒涘缓
+1. 杩涘叆浠诲姟鍒涘缓椤甸潰
+2. 閫夋嫨浠诲姟绫诲瀷
+3. 妫�鏌ヨ溅杈嗛�夋嫨鍣ㄦ槸鍚︽甯稿姞杞借溅杈嗗垪琛�
+4. 鍒涘缓浠诲姟骞堕獙璇佽溅杈嗕俊鎭槸鍚︽纭繚瀛�
+
+### 3. 娴嬭瘯浠诲姟鍒楄〃
+1. 杩涘叆浠诲姟鍒楄〃椤甸潰
+2. 妫�鏌ヨ溅杈嗕俊鎭槸鍚︽纭樉绀�
+3. 娴嬭瘯杞﹁締绛涢�夊姛鑳�
+
+## 娉ㄦ剰浜嬮」
+
+1. **鏉冮檺鎺у埗**锛氱‘淇濈敤鎴锋湁 `task:general:query` 鏉冮檺
+2. **閮ㄩ棬ID**锛氱‘淇濅紶鍏ョ殑 `deptId` 鍙傛暟鏈夋晥
+3. **浠诲姟绫诲瀷**锛歚taskType` 鍙傛暟鍙�夛紝鍙互浼犲叆 `GENERAL`銆乣MAINTENANCE`銆乣FUEL` 绛�
+4. **閿欒澶勭悊**锛氬墠绔凡娣诲姞閿欒澶勭悊锛屽鏋滄帴鍙h皟鐢ㄥけ璐ヤ細浣跨敤榛樿杞﹁締鍒楄〃
+
+## 鍚庣画浼樺寲寤鸿
+
+1. **缁熶竴鎺ュ彛璺緞**锛氬缓璁悗绔粺涓�杞﹁締鐩稿叧鎺ュ彛鐨勮矾寰勫墠缂�
+2. **瀹屽杽鐢ㄦ埛杞﹁締缁戝畾**锛氬鏋滈渶瑕佺敤鎴疯溅杈嗙粦瀹氬姛鑳斤紝闇�瑕佸悗绔疄鐜扮浉搴旀帴鍙�
+3. **娣诲姞鎺ュ彛鏂囨。**锛氬缓璁负鎵�鏈夎溅杈嗙浉鍏虫帴鍙f坊鍔犺缁嗙殑API鏂囨。
+4. **閿欒鐮佺粺涓�**锛氬缓璁粺涓�閿欒鐮佸拰閿欒淇℃伅鏍煎紡
+
+---
+
+**淇瀹屾垚鏃堕棿**锛�2024骞�1鏈�
+**淇鐘舵��**锛氣渽 宸插畬鎴�
+**娴嬭瘯鐘舵��**锛氣彸 寰呮祴璇�
diff --git a/app/README_TASK.md b/app/README_TASK.md
new file mode 100644
index 0000000..1a23d39
--- /dev/null
+++ b/app/README_TASK.md
@@ -0,0 +1,113 @@
+# 閫氱敤浠诲姟绠$悊鍔熻兘 - 灏忕▼搴忕寮�鍙戝畬鎴�
+
+## 鍔熻兘姒傝堪
+
+宸插畬鎴愬皬绋嬪簭绔殑閫氱敤浠诲姟褰曞叆鍙婂悗绔帴鍙e鎺ュ姛鑳斤紝鍖呮嫭锛�
+
+1. **浠诲姟鍒涘缓鍔熻兘** - 鏀寔澶氱浠诲姟绫诲瀷鐨勫垱寤�
+2. **浠诲姟鍒楄〃鍔熻兘** - 鏀寔浠诲姟鏌ヨ銆佺瓫閫夊拰鐘舵�佺鐞�
+3. **浠诲姟璇︽儏鍔熻兘** - 鏌ョ湅浠诲姟璇︾粏淇℃伅
+4. **鍚庣鎺ュ彛瀵规帴** - 瀹屾暣鐨凙PI鎺ュ彛闆嗘垚
+
+## 宸插畬鎴愮殑鏂囦欢
+
+### 1. API鎺ュ彛鏂囦欢
+- `app/api/task.js` - 浠诲姟绠$悊鐩稿叧API鎺ュ彛
+- `app/api/vehicle.js` - 杞﹁締绠$悊鐩稿叧API鎺ュ彛
+
+### 2. 椤甸潰鏂囦欢
+- `app/pages/task/create.vue` - 浠诲姟鍒涘缓椤甸潰锛堝凡瀹屽杽锛�
+- `app/pages/task/index.vue` - 浠诲姟鍒楄〃椤甸潰锛堝凡瀹屽杽锛�
+- `app/pages/task/detail.vue` - 浠诲姟璇︽儏椤甸潰锛堟柊鍒涘缓锛�
+
+## 鏍稿績鍔熻兘鐗规��
+
+### 浠诲姟鍒涘缓鍔熻兘
+- 鉁� 鏀寔澶氱浠诲姟绫诲瀷锛氱淮淇繚鍏汇�佸姞娌广�佹�ユ晳杞繍銆佺绁夎溅
+- 鉁� 鍔ㄦ�佽〃鍗曪細鏍规嵁浠诲姟绫诲瀷鏄剧ず涓嶅悓鐨勮〃鍗曞瓧娈�
+- 鉁� 杞﹁締閫夋嫨锛氶泦鎴愯溅杈嗙鐞咥PI锛屾敮鎸佽溅杈嗛�夋嫨
+- 鉁� 鍦板浘閫夋嫨锛氶泦鎴愬湴鍥鹃�夋嫨鍣紝鏀寔鍦板潃閫夋嫨
+- 鉁� 琛ㄥ崟楠岃瘉锛氬畬鏁寸殑鍓嶇琛ㄥ崟楠岃瘉
+- 鉁� 鏁版嵁鎻愪氦锛氫笌鍚庣API瀹屾暣瀵规帴
+
+### 浠诲姟鍒楄〃鍔熻兘
+- 鉁� 浠诲姟鍒楄〃灞曠ず锛氭敮鎸佸垎椤靛拰绛涢��
+- 鉁� 鐘舵�佺瓫閫夛細鎸変换鍔$姸鎬佺瓫閫�
+- 鉁� 鎼滅储鍔熻兘锛氭敮鎸佽溅鐗屽彿銆佷换鍔$紪鍙锋悳绱�
+- 鉁� 鏃堕棿绛涢�夛細鏀寔鏃堕棿鑼冨洿绛涢��
+- 鉁� 鐘舵�佹搷浣滐細鏀寔浠诲姟鐘舵�佹洿鏂�
+- 鉁� 涓嬫媺鍒锋柊锛氭敮鎸佷笅鎷夊埛鏂版暟鎹�
+
+### 浠诲姟璇︽儏鍔熻兘
+- 鉁� 璇︾粏淇℃伅灞曠ず锛氭樉绀轰换鍔$殑鎵�鏈夎缁嗕俊鎭�
+- 鉁� 鍒嗙被淇℃伅锛氭寜妯″潡鍒嗙被鏄剧ず淇℃伅
+- 鉁� 鐗规畩瀛楁锛氭牴鎹换鍔$被鍨嬫樉绀虹壒鏈夊瓧娈�
+- 鉁� 鐘舵�佹樉绀猴細甯﹂鑹茬殑鐘舵�佹樉绀�
+
+## 鎶�鏈疄鐜�
+
+### 1. 鏁版嵁瀛楁鏄犲皠
+- 浠诲姟鐘舵�侊細`PENDING`(寰呭鐞�) 鈫� `IN_PROGRESS`(澶勭悊涓�) 鈫� `COMPLETED`(宸插畬鎴�)
+- 浠诲姟绫诲瀷锛歚MAINTENANCE`(缁翠慨淇濆吇)銆乣FUEL`(鍔犳补)銆乣EMERGENCY_TRANSFER`(鎬ユ晳杞繍)銆乣WELFARE`(绂忕杞�)
+
+### 2. API鎺ュ彛瀵规帴
+- 浠诲姟鍒涘缓锛歚POST /task`
+- 浠诲姟鍒楄〃锛歚GET /task/list`
+- 浠诲姟璇︽儏锛歚GET /task/{taskId}`
+- 鐘舵�佹洿鏂帮細`PUT /task/{taskId}/status`
+- 杞﹁締鍒楄〃锛歚GET /vehicle/available`
+
+### 3. 鐢ㄦ埛浣撻獙浼樺寲
+- 鍔犺浇鐘舵�侊細鏄剧ず鍔犺浇涓姸鎬�
+- 閿欒澶勭悊锛氬畬鍠勭殑閿欒鎻愮ず
+- 琛ㄥ崟楠岃瘉锛氬疄鏃惰〃鍗曢獙璇�
+- 鎿嶄綔鍙嶉锛氭搷浣滄垚鍔�/澶辫触鎻愮ず
+
+## 浣跨敤璇存槑
+
+### 1. 鍒涘缓浠诲姟
+1. 杩涘叆浠诲姟鍒涘缓椤甸潰
+2. 閫夋嫨浠诲姟绫诲瀷锛堢淮淇繚鍏汇�佸姞娌广�佹�ユ晳杞繍銆佺绁夎溅锛�
+3. 濉啓鐩稿簲鐨勮〃鍗曚俊鎭�
+4. 閫夋嫨杞﹁締鍜屽湴鍧�
+5. 鎻愪氦浠诲姟
+
+### 2. 鏌ョ湅浠诲姟鍒楄〃
+1. 杩涘叆浠诲姟鍒楄〃椤甸潰
+2. 鍙互鎸夌姸鎬佺瓫閫変换鍔�
+3. 鍙互鎼滅储鐗瑰畾浠诲姟
+4. 鍙互涓嬫媺鍒锋柊鏁版嵁
+5. 鐐瑰嚮浠诲姟鍙互鏌ョ湅璇︽儏
+
+### 3. 浠诲姟鐘舵�佺鐞�
+1. 鍦ㄤ换鍔″垪琛ㄤ腑鐐瑰嚮鐩稿簲鐨勬搷浣滄寜閽�
+2. 纭鎿嶄綔鍚庢洿鏂颁换鍔$姸鎬�
+3. 绯荤粺浼氳嚜鍔ㄥ埛鏂颁换鍔″垪琛�
+
+## 娉ㄦ剰浜嬮」
+
+1. **鏉冮檺鎺у埗**锛氶渶瑕佺‘淇濈敤鎴锋湁鐩稿簲鐨勪换鍔℃搷浣滄潈闄�
+2. **鏁版嵁鍚屾**锛氫换鍔$姸鎬佹洿鏂板悗浼氳嚜鍔ㄥ埛鏂板垪琛�
+3. **閿欒澶勭悊**锛氭墍鏈堿PI璋冪敤閮芥湁閿欒澶勭悊鏈哄埗
+4. **琛ㄥ崟楠岃瘉**锛氬墠绔細杩涜鍩虹楠岃瘉锛屽悗绔篃浼氳繘琛岄獙璇�
+
+## 鍚庣画鎵╁睍
+
+1. **闄勪欢涓婁紶**锛氬彲浠ユ坊鍔犱换鍔¢檮浠朵笂浼犲姛鑳�
+2. **娑堟伅鎺ㄩ��**锛氬彲浠ユ坊鍔犱换鍔$姸鎬佸彉鏇存秷鎭帹閫�
+3. **鍦板浘瀵艰埅**锛氬彲浠ラ泦鎴愬湴鍥惧鑸姛鑳�
+4. **绂荤嚎鏀寔**锛氬彲浠ユ坊鍔犵绾挎暟鎹紦瀛樺姛鑳�
+
+## 娴嬭瘯寤鸿
+
+1. 娴嬭瘯鍚勭浠诲姟绫诲瀷鐨勫垱寤�
+2. 娴嬭瘯浠诲姟鐘舵�佹祦杞�
+3. 娴嬭瘯鎼滅储鍜岀瓫閫夊姛鑳�
+4. 娴嬭瘯閿欒澶勭悊鏈哄埗
+5. 娴嬭瘯缃戠粶寮傚父鎯呭喌
+
+---
+
+**寮�鍙戝畬鎴愭椂闂�**锛�2024骞�1鏈�
+**寮�鍙戠姸鎬�**锛氣渽 宸插畬鎴�
+**娴嬭瘯鐘舵��**锛氣彸 寰呮祴璇�
diff --git a/app/TASK_CREATE_REFACTOR.md b/app/TASK_CREATE_REFACTOR.md
new file mode 100644
index 0000000..3559a25
--- /dev/null
+++ b/app/TASK_CREATE_REFACTOR.md
@@ -0,0 +1,185 @@
+# 浠诲姟鍒涘缓椤甸潰閲嶆瀯璇存槑
+
+## 閲嶆瀯鐩殑
+灏嗗師鏈泦鎴愬湪鍗曚釜鏂囦欢涓殑澶氫釜浠诲姟琛ㄥ崟鎷嗗垎鎴愮嫭绔嬫枃浠�,鎻愰珮浠g爜鐨勫彲缁存姢鎬у拰鍙墿灞曟�с��
+
+## 鏂囦欢缁撴瀯
+
+### 閲嶆瀯鍓�
+- `pages/task/create.vue` - 鍖呭惈鎵�鏈変换鍔$被鍨嬬殑琛ㄥ崟(绾�1300琛屼唬鐮�)
+
+### 閲嶆瀯鍚�
+```
+pages/task/
+鈹溾攢鈹� create.vue # 浠诲姟绫诲瀷閫夋嫨椤甸潰(148琛�)
+鈹溾攢鈹� create-normal.vue # 鏅�氫换鍔″垱寤鸿〃鍗�(596琛�)
+鈹溾攢鈹� create-emergency.vue # 鎬ユ晳杞繍浠诲姟鍒涘缓琛ㄥ崟(688琛�)
+鈹斺攢鈹� create-welfare.vue # 绂忕杞︿换鍔″垱寤鸿〃鍗�(544琛�)
+```
+
+## 椤甸潰璇存槑
+
+### 1. create.vue - 浠诲姟绫诲瀷閫夋嫨椤�
+**鍔熻兘**: 灞曠ず鍥涚浠诲姟绫诲瀷渚涚敤鎴烽�夋嫨
+- 缁翠慨淇濆吇浠诲姟
+- 鍔犳补浠诲姟
+- 鎬ユ晳杞繍浠诲姟
+- 绂忕杞︿换鍔�
+
+**璺敱璺宠浆**: 鏍规嵁閫夋嫨璺宠浆鍒板搴旂殑鍒涘缓椤甸潰,骞朵紶閫掑弬鏁�:
+- `categoryName`: 浠诲姟绫诲埆鍚嶇О
+- `categoryType`: 浠诲姟绫诲埆绫诲瀷
+- `taskType`: 浠诲姟绫诲瀷鍊�
+
+### 2. create-normal.vue - 鏅�氫换鍔″垱寤洪〉
+**閫傜敤浠诲姟**: 缁翠慨淇濆吇銆佸姞娌圭瓑鏃ュ父浠诲姟
+
+**涓昏鍔熻兘**:
+- 杞﹁締閫夋嫨(鑷姩濉厖鐢ㄦ埛缁戝畾杞﹁締)
+- 浠诲姟绫诲瀷閫夋嫨(浠庡瓧鍏稿姞杞�)
+- 浠诲姟鎻忚堪
+- 鍦板潃閫夋嫨(鍑哄彂鍦般�佺洰鐨勫湴)
+- 鑷姩璁$畻璺濈
+- 鏃堕棿閫夋嫨(寮�濮嬫椂闂淬�佺粨鏉熸椂闂�)
+- 澶囨敞淇℃伅
+
+**鐗硅壊鍔熻兘**:
+- 闆嗘垚鍦板浘閫夋嫨鍣�
+- GPS鍧愭爣璁板綍
+- 鑷姩璺濈璁$畻
+
+### 3. create-emergency.vue - 鎬ユ晳杞繍浠诲姟鍒涘缓椤�
+**閫傜敤浠诲姟**: 鎬ユ晳杞繍銆佽埅绌鸿浆杩�
+
+**涓昏鍔熻兘**:
+- 杞﹁締閫夋嫨
+- 鎵ц浜哄憳绠$悊(鍙坊鍔犲浜�)
+- 褰掑睘鏈烘瀯閫夋嫨
+- 鎮h�呬俊鎭綍鍏�(濮撳悕銆佹�у埆銆佽韩浠借瘉銆佺梾鎯呯瓑)
+- 杞嚭鍖婚櫌淇℃伅(鍚嶇О銆佺瀹ゃ�佸簥鍙枫�佸湴鍧�)
+- 杞叆鍖婚櫌淇℃伅(鍚嶇О銆佺瀹ゃ�佸簥鍙枫�佸湴鍧�)
+- 杞繍璺濈鑷姩璁$畻
+- 鎴愪氦浠峰綍鍏�
+
+**鐗硅壊鍔熻兘**:
+- 瀹屾暣鐨勬偅鑰呬俊鎭鐞�
+- 鍖婚櫌淇℃伅绠$悊
+- 澶氫汉鍛樺崗浣滄敮鎸�
+
+### 4. create-welfare.vue - 绂忕杞︿换鍔″垱寤洪〉
+**閫傜敤浠诲姟**: 鑰佸勾浜恒�佹畫鐤句汉绛夌壒娈婄兢浣撶敤杞︽湇鍔�
+
+**涓昏鍔熻兘**:
+- 杞﹁締閫夋嫨
+- 鎵ц浜哄憳绠$悊
+- 褰掑睘鏈烘瀯閫夋嫨
+- 涔樺淇℃伅褰曞叆(鑱旂郴浜恒�佺數璇�)
+- 鍦板潃閫夋嫨(鍑哄彂鍦般�佺洰鐨勫湴)
+- 璺濈鑷姩璁$畻
+- 鎴愪氦浠峰綍鍏�
+
+**鐗硅壊鍔熻兘**:
+- 绠�鍖栫殑涔樺淇℃伅褰曞叆
+- 鏈嶅姟鏃堕棿绠$悊
+
+## 鍏卞悓鐗规��
+
+鎵�鏈夊垱寤洪〉闈㈠潎鍏峰:
+1. **缁熶竴鐨刄I璁捐** - 淇濇寔涓�鑷寸殑鐢ㄦ埛浣撻獙
+2. **琛ㄥ崟楠岃瘉** - 蹇呭~椤规牎楠�
+3. **鍦板浘閫夋嫨鍣ㄩ泦鎴�** - 鍙鍖栧湴鍧�閫夋嫨
+4. **GPS鍧愭爣璁板綍** - 绮剧‘浣嶇疆淇℃伅
+5. **鑷姩璺濈璁$畻** - 鍩轰簬鑵捐鍦板浘API
+6. **杩斿洖瀵艰埅** - 鍙繑鍥炰换鍔$被鍨嬮�夋嫨椤�
+
+## 鎶�鏈爤
+
+- **缁勪欢搴�**: uni-app瀹樻柟缁勪欢
+- **鍦板浘**: 鑵捐鍦板浘API
+- **鐘舵�佺鐞�**: Vuex
+- **璺敱**: uni-app璺敱绯荤粺
+
+## 浼樺娍
+
+### 浠g爜缁勭粐
+- 鉁� 鍗曚竴鑱岃矗鍘熷垯 - 姣忎釜鏂囦欢涓撴敞浜庝竴绉嶄换鍔$被鍨�
+- 鉁� 浠g爜閲忔帶鍒� - 姣忎釜鏂囦欢琛屾暟閫備腑,鏄撲簬鐞嗚В
+- 鉁� 鐙珛缁存姢 - 淇敼鏌愮被浠诲姟涓嶅奖鍝嶅叾浠栦换鍔�
+
+### 鍙淮鎶ゆ��
+- 鉁� 娓呮櫚鐨勬枃浠剁粨鏋�
+- 鉁� 鏄撲簬瀹氫綅鍜屼慨澶峛ug
+- 鉁� 渚夸簬鍔熻兘鎵╁睍
+
+### 鍙墿灞曟��
+- 鉁� 鏂板浠诲姟绫诲瀷鍙渶娣诲姞鏂版枃浠�
+- 鉁� 涓嶅奖鍝嶇幇鏈変换鍔$被鍨�
+- 鉁� 鏄撲簬澶嶇敤閫氱敤缁勪欢
+
+## 璺敱閰嶇疆
+
+鍦� `pages.json` 涓凡娉ㄥ唽浠ヤ笅璺敱:
+
+```json
+{
+ "path": "pages/task/create",
+ "navigationBarTitleText": "閫夋嫨浠诲姟绫诲瀷"
+},
+{
+ "path": "pages/task/create-normal",
+ "navigationBarTitleText": "鍒涘缓鏅�氫换鍔�"
+},
+{
+ "path": "pages/task/create-emergency",
+ "navigationBarTitleText": "鍒涘缓鎬ユ晳杞繍浠诲姟"
+},
+{
+ "path": "pages/task/create-welfare",
+ "navigationBarTitleText": "鍒涘缓绂忕杞︿换鍔�"
+}
+```
+
+## 浣跨敤鏂瑰紡
+
+### 浠庨椤佃繘鍏�
+```javascript
+uni.navigateTo({
+ url: '/pages/task/create'
+})
+```
+
+### 鐩存帴鍒涘缓鐗瑰畾浠诲姟绫诲瀷
+```javascript
+// 鍒涘缓缁翠慨淇濆吇浠诲姟
+uni.navigateTo({
+ url: '/pages/task/create-normal?taskType=MAINTENANCE&categoryName=缁翠慨淇濆吇'
+})
+
+// 鍒涘缓鎬ユ晳杞繍浠诲姟
+uni.navigateTo({
+ url: '/pages/task/create-emergency'
+})
+
+// 鍒涘缓绂忕杞︿换鍔�
+uni.navigateTo({
+ url: '/pages/task/create-welfare'
+})
+```
+
+## 娉ㄦ剰浜嬮」
+
+1. **鍏煎鎬�**: 鎵�鏈夐〉闈繚鎸佸悜鍚庡吋瀹�,涓嶅奖鍝嶇幇鏈夊姛鑳�
+2. **鏁版嵁鎻愪氦**: 缁熶竴浣跨敤 `addTask` API鎺ュ彛
+3. **鐢ㄦ埛浣撻獙**: 淇濇寔涓�鑷寸殑浜や簰閫昏緫鍜孶I椋庢牸
+4. **閿欒澶勭悊**: 瀹屽杽鐨勮〃鍗曢獙璇佸拰閿欒鎻愮ず
+
+## 鍚庣画浼樺寲寤鸿
+
+1. 鎻愬彇鍏叡缁勪欢(濡傚湴鍧�閫夋嫨鍣ㄣ�佷汉鍛橀�夋嫨鍣�)
+2. 缁熶竴琛ㄥ崟楠岃瘉瑙勫垯
+3. 娣诲姞琛ㄥ崟鏁版嵁鏈湴缂撳瓨(鑽夌鍔熻兘)
+4. 浼樺寲鍦板浘閫夋嫨浣撻獙
+5. 澧炲姞鎵归噺鍒涘缓浠诲姟鍔熻兘
+
+## 鏇存柊鏃ユ湡
+2025-10-16
diff --git a/app/api/dict.js b/app/api/dict.js
new file mode 100644
index 0000000..6c9eb79
--- /dev/null
+++ b/app/api/dict.js
@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瀛楀吀鏁版嵁鍒楄〃
+export function listData(query) {
+ return request({
+ url: '/system/dict/data/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+export function getData(dictCode) {
+ return request({
+ url: '/system/dict/data/' + dictCode,
+ method: 'get'
+ })
+}
+
+// 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+export function getDicts(dictType) {
+ return request({
+ url: '/system/dict/data/type/' + dictType,
+ method: 'get'
+ })
+}
+
+// 鏂板瀛楀吀鏁版嵁
+export function addData(data) {
+ return request({
+ url: '/system/dict/data',
+ method: 'post',
+ data: data
+ })
+}
+
+// 淇敼瀛楀吀鏁版嵁
+export function updateData(data) {
+ return request({
+ url: '/system/dict/data',
+ method: 'put',
+ data: data
+ })
+}
+
+// 鍒犻櫎瀛楀吀鏁版嵁
+export function delData(dictCode) {
+ return request({
+ url: '/system/dict/data/' + dictCode,
+ method: 'delete'
+ })
+}
diff --git a/app/api/geocode.js b/app/api/geocode.js
new file mode 100644
index 0000000..9e295fe
--- /dev/null
+++ b/app/api/geocode.js
@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+
+/**
+ * 鏍规嵁鍦板潃鑾峰彇GPS鍧愭爣锛堝湴鐞嗙紪鐮侊級
+ * @param {String} address 鍦板潃瀛楃涓�
+ * @param {String} city 鍩庡競鍚嶇О锛堝彲閫夛級
+ */
+export function getCoordinatesByAddress(address, city) {
+ return request({
+ url: '/system/geocode/address',
+ method: 'get',
+ params: {
+ address: address,
+ city: city
+ }
+ })
+}
diff --git a/app/api/hospital.js b/app/api/hospital.js
new file mode 100644
index 0000000..0607054
--- /dev/null
+++ b/app/api/hospital.js
@@ -0,0 +1,29 @@
+import request from '@/utils/request'
+
+/**
+ * 鎼滅储鍖婚櫌
+ * @param {string} keyword 鎼滅储鍏抽敭璇嶏紙鍖婚櫌鍚嶇О鎴栧湴鍧�锛�
+ */
+export function searchHospitals(keyword) {
+ return request({
+ url: '/system/hospital/search',
+ method: 'get',
+ params: {
+ keyword: keyword
+ }
+ })
+}
+
+/**
+ * 鑾峰彇鍖婚櫌璇︽儏
+ * @param {number} hospId 鍖婚櫌ID
+ */
+export function getHospitalDetail(hospId) {
+ return request({
+ url: '/system/hospital/detail',
+ method: 'get',
+ params: {
+ hospId: hospId
+ }
+ })
+}
diff --git a/app/api/icd10.js b/app/api/icd10.js
new file mode 100644
index 0000000..c6c10b9
--- /dev/null
+++ b/app/api/icd10.js
@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+/**
+ * 鎼滅储ICD-10鐤剧梾
+ * @param {string} keyword 鎼滅储鍏抽敭璇�
+ */
+export function searchIcd10(keyword) {
+ return request({
+ url: '/system/icd10/search',
+ method: 'get',
+ params: { keyword }
+ })
+}
+
+/**
+ * 鑾峰彇ICD-10璇︽儏
+ * @param {number} id ICD-10 ID
+ */
+export function getIcd10Detail(id) {
+ return request({
+ url: '/system/icd10/detail',
+ method: 'get',
+ params: { id }
+ })
+}
diff --git a/app/api/map.js b/app/api/map.js
new file mode 100644
index 0000000..df91db0
--- /dev/null
+++ b/app/api/map.js
@@ -0,0 +1,67 @@
+import request from '@/utils/request'
+
+// 鍦板浘鍦板潃鎼滅储API
+export function searchAddress(keyword, region) {
+ // 鍙傛暟楠岃瘉
+ if (!keyword) {
+ return Promise.reject(new Error('鍙傛暟涓嶅畬鏁达紝缂哄皯鍏抽敭璇�'))
+ }
+
+ return request({
+ url: '/system/gps/address/search',
+ method: 'get',
+ params: {
+ keyword: keyword,
+ region: region || '骞垮窞'
+ }
+ })
+}
+
+// 鍦板浘閫嗗湴鍧�瑙f瀽API
+export function reverseGeocoder(lat, lng) {
+ // 鍙傛暟楠岃瘉
+ if (lat === undefined || lat === null || lng === undefined || lng === null) {
+ return Promise.reject(new Error('鍙傛暟涓嶅畬鏁达紝缂哄皯缁忕含搴﹀潗鏍�'))
+ }
+
+ // 妫�鏌ュ弬鏁版湁鏁堟��
+ if (isNaN(lat) || isNaN(lng)) {
+ return Promise.reject(new Error('鍙傛暟鏃犳晥锛岀粡绾害鍧愭爣鏍煎紡閿欒'))
+ }
+
+ return request({
+ url: '/system/gps/address/geocoder',
+ method: 'get',
+ params: {
+ lat: lat,
+ lng: lng
+ }
+ })
+}
+
+// 鍦板浘璺嚎瑙勫垝API锛堣绠椾袱鐐归棿璺濈锛�
+export function calculateDistance(fromLat, fromLng, toLat, toLng) {
+ // 鍙傛暟楠岃瘉
+ if (fromLat === undefined || fromLat === null ||
+ fromLng === undefined || fromLng === null ||
+ toLat === undefined || toLat === null ||
+ toLng === undefined || toLng === null) {
+ return Promise.reject(new Error('鍙傛暟涓嶅畬鏁达紝缂哄皯璧风偣鎴栫粓鐐瑰潗鏍�'))
+ }
+
+ // 妫�鏌ュ弬鏁版湁鏁堟��
+ if (isNaN(fromLat) || isNaN(fromLng) || isNaN(toLat) || isNaN(toLng)) {
+ return Promise.reject(new Error('鍙傛暟鏃犳晥锛屽潗鏍囨牸寮忛敊璇�'))
+ }
+
+ return request({
+ url: '/system/gps/route/distance',
+ method: 'get',
+ params: {
+ fromLat: fromLat,
+ fromLng: fromLng,
+ toLat: toLat,
+ toLng: toLng
+ }
+ })
+}
\ No newline at end of file
diff --git a/app/api/system/user.js b/app/api/system/user.js
index 0e307ea..421afa0 100644
--- a/app/api/system/user.js
+++ b/app/api/system/user.js
@@ -39,3 +39,12 @@
filePath: data.filePath
})
}
+
+// 鏌ヨ鐢ㄦ埛鍒楄〃
+export function listUser(query) {
+ return request({
+ url: '/system/user/list',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/app/api/task.js b/app/api/task.js
new file mode 100644
index 0000000..a2891f8
--- /dev/null
+++ b/app/api/task.js
@@ -0,0 +1,109 @@
+import request from '@/utils/request'
+
+// 浠诲姟绠$悊API
+export function listTask(query) {
+ return request({
+ url: '/task/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getTask(taskId) {
+ return request({
+ url: '/task/' + taskId,
+ method: 'get'
+ })
+}
+
+export function addTask(data) {
+ return request({
+ url: '/task',
+ method: 'post',
+ data: data
+ })
+}
+
+export function updateTask(data) {
+ return request({
+ url: '/task/' + data.taskId,
+ method: 'put',
+ data: data
+ })
+}
+
+export function deleteTask(taskIds) {
+ return request({
+ url: '/task/' + taskIds,
+ method: 'delete'
+ })
+}
+
+export function assignTask(taskId, data) {
+ return request({
+ url: '/task/' + taskId + '/assign',
+ method: 'put',
+ data: data
+ })
+}
+
+export function changeTaskStatus(taskId, data) {
+ return request({
+ url: '/task/' + taskId + '/status',
+ method: 'put',
+ data: data
+ })
+}
+
+// 闄勪欢绠$悊API
+export function uploadAttachment(taskId, file) {
+ const formData = new FormData()
+ formData.append('file', file)
+ return request({
+ url: '/task/' + taskId + '/attachment',
+ method: 'post',
+ data: formData,
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ })
+}
+
+export function deleteAttachment(attachmentId) {
+ return request({
+ url: '/task/attachment/' + attachmentId,
+ method: 'delete'
+ })
+}
+
+// 缁熻API
+export function getTaskStatistics() {
+ return request({
+ url: '/task/statistics',
+ method: 'get'
+ })
+}
+
+// 鑾峰彇浠诲姟绫诲瀷鍒楄〃
+export function getTaskTypes() {
+ return request({
+ url: '/task/types',
+ method: 'get'
+ })
+}
+
+// 鑾峰彇浠诲姟鐘舵�佸垪琛�
+export function getTaskStatuses() {
+ return request({
+ url: '/task/statuses',
+ method: 'get'
+ })
+}
+
+// 鑾峰彇鎴戠殑浠诲姟鍒楄〃
+export function getMyTasks() {
+ return request({
+ url: '/task/my',
+ method: 'get'
+ })
+}
diff --git a/app/api/vehicle.js b/app/api/vehicle.js
new file mode 100644
index 0000000..cac3152
--- /dev/null
+++ b/app/api/vehicle.js
@@ -0,0 +1,90 @@
+import request from '@/utils/request'
+
+// 杞﹁締绠$悊API
+export function listVehicle(query) {
+ return request({
+ url: '/vehicle/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getVehicle(vehicleId) {
+ return request({
+ url: '/vehicle/' + vehicleId,
+ method: 'get'
+ })
+}
+
+export function listVehicleByDept(deptId, query) {
+ return request({
+ url: '/vehicle/list-by-dept/' + deptId,
+ method: 'get',
+ params: query
+ })
+}
+
+export function listAvailableVehicles(deptId, taskType) {
+ return request({
+ url: '/task/vehicle/available',
+ method: 'get',
+ params: {
+ deptId: deptId,
+ taskType: taskType
+ }
+ })
+}
+
+// 娉ㄦ剰锛氫互涓嬫帴鍙e彲鑳藉湪鍚庣鏈疄鐜帮紝闇�瑕佹牴鎹疄闄呮儏鍐佃皟鏁�
+export function getVehicleByUser(userId) {
+ return request({
+ url: '/task/vehicle/user/' + userId,
+ method: 'get'
+ })
+}
+
+export function bindVehicleToUser(userId, vehicleId) {
+ return request({
+ url: '/system/vehicle/bind',
+ method: 'post',
+ data: {
+ userId: userId,
+ vehicleId: vehicleId
+ }
+ })
+}
+
+export function unbindVehicleFromUser(userId, vehicleId) {
+ return request({
+ url: '/system/vehicle/unbind',
+ method: 'post',
+ data: {
+ userId: userId,
+ vehicleId: vehicleId
+ }
+ })
+}
+
+// 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+export function getUserBoundVehicle(userId) {
+ return request({
+ url: '/system/vehicle/user/bound/' + userId,
+ method: 'get'
+ })
+}
+
+// 鑾峰彇杞﹁締绫诲瀷鍒楄〃
+export function getVehicleTypes() {
+ return request({
+ url: '/vehicle/types',
+ method: 'get'
+ })
+}
+
+// 鑾峰彇杞﹁締鐘舵�佸垪琛�
+export function getVehicleStatuses() {
+ return request({
+ url: '/vehicle/statuses',
+ method: 'get'
+ })
+}
diff --git a/app/components/map-selector.vue b/app/components/map-selector.vue
index 8d872b9..6c5e540 100644
--- a/app/components/map-selector.vue
+++ b/app/components/map-selector.vue
@@ -5,15 +5,56 @@
class="search-input"
placeholder="璇疯緭鍏ュ湴鍧�"
v-model="searchKeyword"
- @input="onSearchInput"
@focus="onSearchFocus"
/>
<button class="search-btn" @click="searchAddress">鎼滅储</button>
+ <button class="location-btn" @click="getCurrentLocation" :disabled="isGettingLocation">
+ <uni-icons v-if="!isGettingLocation" type="location" size="18" color="white"></uni-icons>
+ <uni-icons v-else type="spinner-cycle" size="18" color="white"></uni-icons>
+ </button>
</view>
- <!-- 寰俊灏忕▼搴忎娇鐢ㄥ師鐢焟ap缁勪欢 -->
+ <!-- 閫変腑鍦板潃鐣岄潰 - 鏄剧ず鍦ㄥ垪琛ㄤ笂鏂� -->
+ <view class="selected-address" v-if="selectedAddress">
+ <view class="selected-header">
+ <uni-icons type="checkmarkempty" size="20" color="#007AFF"></uni-icons>
+ <text class="address-title">宸查�変腑鍦板潃</text>
+ <view class="cancel-btn" @click="cancelSelection">
+ <uni-icons type="closeempty" size="16" color="#999"></uni-icons>
+ </view>
+ </view>
+ <view class="address-info">
+ <view class="address-name">{{ selectedAddress.title }}</view>
+ <view class="address-detail">{{ selectedAddress.address }}</view>
+ </view>
+ <button class="confirm-btn" @click="confirmAddress">
+ <uni-icons type="checkmarkempty" size="18" color="white"></uni-icons>
+ <text>纭閫夋嫨姝ゅ湴鍧�</text>
+ </button>
+ </view>
+
+ <!-- 鍦板潃鎼滅储缁撴灉鍒楄〃 -->
+ <view class="address-list" v-if="showSearchResults && searchResults.length > 0">
+ <view
+ class="address-item"
+ v-for="(item, index) in searchResults"
+ :key="'search-' + index"
+ @click="selectAddress(item)"
+ >
+ <!-- 纭繚浣跨敤鎻掑�艰娉� -->
+ <view class="address-title">{{ item.title }}</view>
+ <view class="address-detail">{{ item.address }}</view>
+ </view>
+ </view>
+
+ <!-- 鎼滅储鏃犵粨鏋滄彁绀� -->
+ <view class="no-results" v-if="showSearchResults && searchResults.length === 0 && searchCompleted">
+ <text>鏈壘鍒扮浉鍏冲湴鍧�</text>
+ </view>
+
+ <!-- UniApp鍘熺敓鍦板浘缁勪欢锛屾敮鎸佸骞冲彴 -->
<view class="map-container" id="mapContainer">
- <!-- #ifdef MP-WEIXIN -->
+ <!-- 鎵�鏈夊钩鍙扮粺涓�浣跨敤uniapp鍘熺敓map缁勪欢 -->
<map
id="map"
:longitude="longitude"
@@ -24,6 +65,14 @@
:controls="controls"
:include-points="includePoints"
:show-location="true"
+ :enable-3D="false"
+ :show-compass="false"
+ :enable-overlooking="false"
+ :enable-zoom="true"
+ :enable-scroll="true"
+ :enable-rotate="false"
+ :enable-satellite="false"
+ :enable-traffic="false"
@markertap="onMarkerTap"
@callouttap="onCalloutTap"
@controltap="onControlTap"
@@ -31,45 +80,17 @@
@tap="onMapTap"
class="map-webview"
></map>
- <!-- #endif -->
-
- <!-- H5骞冲彴浣跨敤web-view鍔犺浇鐧惧害鍦板浘 -->
- <!-- #ifdef H5 -->
- <web-view
- v-if="baiduMapUrl"
- :src="baiduMapUrl"
- class="map-webview"
- @message="onWebviewMessage"
- ></web-view>
- <!-- #endif -->
<view class="map-placeholder" v-if="!isMapLoaded">
<text>鍦板浘鍔犺浇涓�...</text>
</view>
</view>
-
- <view class="address-list" v-if="searchResults.length > 0">
- <view
- class="address-item"
- v-for="(item, index) in searchResults"
- :key="index"
- @click="selectAddress(item)"
- >
- <view class="address-title">{{ item.title }}</view>
- <view class="address-detail">{{ item.address }}</view>
- </view>
- </view>
-
- <view class="selected-address" v-if="selectedAddress">
- <view class="address-title">閫変腑鍦板潃锛�</view>
- <view class="address-detail">{{ selectedAddress.title }}</view>
- <view class="address-detail">{{ selectedAddress.address }}</view>
- <button class="confirm-btn" @click="confirmAddress">纭閫夋嫨</button>
- </view>
</view>
</template>
<script>
+ import { searchAddress, reverseGeocoder } from '@/api/map'
+
export default {
name: 'MapSelector',
props: {
@@ -82,75 +103,149 @@
data() {
return {
searchKeyword: '',
- searchResults: [],
+ searchResults: [], // 纭繚杩欐槸鍝嶅簲寮忔暟鎹�
selectedAddress: null,
isMapLoaded: false,
- // H5骞冲彴鐩稿叧
- baiduMapUrl: '',
- ak: '鎮ㄧ殑鐧惧害鍦板浘AK',
- // 寰俊灏忕▼搴忕浉鍏�
+ showSearchResults: false, // 鎺у埗鏄惁鏄剧ず鎼滅储缁撴灉
+ searchCompleted: false, // 鏍囪鎼滅储鏄惁瀹屾垚
+ showDebug: true, // 璋冭瘯寮�鍏�
+ // 鍦板浘鐩稿叧
longitude: 113.324520,
latitude: 23.099994,
markers: [],
polyline: [],
circles: [],
controls: [],
- includePoints: []
+ includePoints: [],
+ isGettingLocation: false, // 鏄惁姝e湪鑾峰彇浣嶇疆
+ // 闃叉鑷姩鑱氱劍鐨勬爣蹇�
+ shouldPreventAutoFocus: true
}
},
mounted() {
- // #ifdef H5
- // 鍒濆鍖栫櫨搴﹀湴鍥�
- this.initBaiduMap()
- // #endif
+ console.log('鍦板浘閫夋嫨鍣ㄧ粍浠跺凡鎸傝浇');
- // #ifdef MP-WEIXIN
- // 鍒濆鍖栧井淇″皬绋嬪簭鍦板浘
- this.initWechatMap()
- // #endif
+ // 妫�鏌PI Key鏄惁宸查厤缃�
+ if (!this.isTencentMapKeyConfigured()) {
+ console.error('[system] Map key not configured.')
+ this.$modal.showToast('鍦板浘API Key鏈厤缃紝璇疯仈绯荤鐞嗗憳')
+ return
+ }
+ // 鍒濆鍖栧湴鍥�
+ this.initMap()
+
+ // 寤惰繜澶勭悊鍒濆鍦板潃锛岄伩鍏嶈法鍩熼棶棰�
if (this.initialAddress) {
this.searchKeyword = this.initialAddress
- // 寤惰繜璁剧疆鐒︾偣锛岄伩鍏嶈法鍩熼棶棰�
- setTimeout(() => {
- // 涓嶈嚜鍔ㄨ仛鐒︼紝璁╃敤鎴锋墜鍔ㄧ偣鍑�
- }, 500)
+ // 涓嶅啀灏濊瘯鑷姩鑱氱劍锛岄伩鍏嶈法鍩熼棶棰�
+ // 鐢ㄦ埛闇�瑕佹墜鍔ㄧ偣鍑昏緭鍏ユ鎵嶈兘鑱氱劍
}
+
+ // 寤惰繜涓�娈垫椂闂村悗鍏佽鑷姩鎿嶄綔锛堝鏋滈渶瑕佺殑璇濓級
+ setTimeout(() => {
+ this.shouldPreventAutoFocus = false
+ }, 1000)
},
methods: {
+ // 妫�鏌ヨ吘璁湴鍥続PI Key鏄惁宸查厤缃�
+ isTencentMapKeyConfigured() {
+ // 瀵逛簬鍚庣浠g悊鏂瑰紡锛屽墠绔笉鍐嶉渶瑕佹鏌ey閰嶇疆
+ return true
+ },
+
// 鎼滅储妗嗚幏寰楃劍鐐逛簨浠�
onSearchFocus() {
// 鐢ㄦ埛涓诲姩鑱氱劍锛屼笉浼氳Е鍙戣法鍩熼棶棰�
console.log('鎼滅储妗嗚幏寰楃劍鐐�')
+ // 閲嶇疆闃茶仛鐒︽爣蹇�
+ this.shouldPreventAutoFocus = false
},
- // #ifdef H5
- // 澶勭悊web-view娑堟伅
- onWebviewMessage(e) {
- // 澶勭悊鏉ヨ嚜web-view鐨勬秷鎭�
- console.log('鏀跺埌鏉ヨ嚜web-view鐨勬秷鎭�:', e)
- },
-
- // 鍒濆鍖栫櫨搴﹀湴鍥撅紙H5骞冲彴锛�
- initBaiduMap() {
- // 鏋勯�犵櫨搴﹀湴鍥綰RL
- this.baiduMapUrl = `https://api.map.baidu.com/mapjs?v=3.0&ak=${this.ak}&callback=initMap`
- this.isMapLoaded = true
+ // 鑾峰彇褰撳墠浣嶇疆
+ getCurrentLocation() {
+ if (this.isGettingLocation) {
+ return
+ }
- // 寤惰繜鍔犺浇鍦板浘锛岄伩鍏嶉樆濉�
- setTimeout(() => {
- this.isMapLoaded = true
- }, 1000)
+ this.isGettingLocation = true
+ this.$modal.showToast('姝e湪鑾峰彇褰撳墠浣嶇疆...')
+
+ uni.getLocation({
+ type: 'gcj02',
+ success: (res) => {
+ console.log('鑾峰彇浣嶇疆鎴愬姛:', res)
+ this.handleLocationSuccess(res.longitude, res.latitude)
+ this.isGettingLocation = false
+ },
+ fail: (error) => {
+ console.error('鑾峰彇浣嶇疆澶辫触:', error)
+ this.$modal.showToast('鑾峰彇浣嶇疆澶辫触锛岃妫�鏌ュ畾浣嶆潈闄�')
+ this.isGettingLocation = false
+ }
+ })
},
- // #endif
- // #ifdef MP-WEIXIN
- // 鍒濆鍖栧井淇″皬绋嬪簭鍦板浘
- initWechatMap() {
+ // 澶勭悊浣嶇疆鑾峰彇鎴愬姛
+ handleLocationSuccess(longitude, latitude) {
+ // 鍙傛暟楠岃瘉
+ if (longitude === undefined || longitude === null || latitude === undefined || latitude === null) {
+ console.error('浣嶇疆鑾峰彇澶辫触锛屽弬鏁颁笉瀹屾暣', { longitude, latitude });
+ this.$modal.showToast('浣嶇疆鑾峰彇澶辫触');
+ return;
+ }
+
+ // 妫�鏌ュ弬鏁版湁鏁堟��
+ if (isNaN(longitude) || isNaN(latitude)) {
+ console.error('浣嶇疆鑾峰彇澶辫触锛屽潗鏍囧寘鍚潪娉曞��', { longitude, latitude });
+ this.$modal.showToast('浣嶇疆鑾峰彇澶辫触锛屽潗鏍囨棤鏁�');
+ return;
+ }
+
+ this.longitude = longitude
+ this.latitude = latitude
+
+ // 璁剧疆鏍囪
+ this.markers = [{
+ id: Date.now(),
+ longitude: longitude,
+ latitude: latitude,
+ title: '褰撳墠浣嶇疆',
+ iconPath: '/static/icons/location.png',
+ width: 30,
+ height: 30
+ }]
+
+ // 閫嗗湴鍧�瑙f瀽
+ this.reverseGeocode(latitude, longitude, true)
+
+ this.$modal.showToast('宸插畾浣嶅埌褰撳墠浣嶇疆')
+ this.isMapLoaded = true
+ },
+
+ // 鍒濆鍖栧湴鍥�
+ initMap() {
// 鑾峰彇鐢ㄦ埛浣嶇疆
uni.getLocation({
type: 'gcj02',
success: (res) => {
+ // 鍙傛暟楠岃瘉
+ if (res.longitude === undefined || res.longitude === null ||
+ res.latitude === undefined || res.latitude === null) {
+ console.error('鍒濆鍖栧湴鍥炬椂浣嶇疆鑾峰彇澶辫触锛屽弬鏁颁笉瀹屾暣', res);
+ this.$modal.showToast('浣嶇疆鑾峰彇澶辫触');
+ this.isMapLoaded = true;
+ return;
+ }
+
+ // 妫�鏌ュ弬鏁版湁鏁堟��
+ if (isNaN(res.longitude) || isNaN(res.latitude)) {
+ console.error('鍒濆鍖栧湴鍥炬椂浣嶇疆鑾峰彇澶辫触锛屽潗鏍囧寘鍚潪娉曞��', res);
+ this.$modal.showToast('浣嶇疆鑾峰彇澶辫触锛屽潗鏍囨棤鏁�');
+ this.isMapLoaded = true;
+ return;
+ }
+
this.longitude = res.longitude
this.latitude = res.latitude
@@ -165,16 +260,12 @@
height: 30
}]
- // 寤惰繜璁剧疆鍔犺浇鐘舵�侊紝纭繚鍦板浘瀹屽叏鍒濆鍖�
- setTimeout(() => {
- this.isMapLoaded = true
- }, 500)
+ // 璁剧疆鍔犺浇鐘舵��
+ this.isMapLoaded = true
},
fail: () => {
- // 寤惰繜璁剧疆鍔犺浇鐘舵��
- setTimeout(() => {
- this.isMapLoaded = true
- }, 500)
+ // 璁剧疆鍔犺浇鐘舵��
+ this.isMapLoaded = true
this.$modal.showToast('鑾峰彇浣嶇疆澶辫触')
}
})
@@ -184,6 +275,14 @@
onMapTap(e) {
// 鍦ㄧ偣鍑讳綅缃坊鍔犳爣璁�
const { longitude, latitude } = e.detail
+
+ // 鍙傛暟楠岃瘉
+ if (longitude === undefined || longitude === null || latitude === undefined || latitude === null) {
+ console.error('鍦板浘鐐瑰嚮浜嬩欢鍙傛暟涓嶅畬鏁�', { longitude, latitude });
+ this.$modal.showToast('浣嶇疆淇℃伅鑾峰彇澶辫触');
+ return;
+ }
+
this.markers = [{
id: Date.now(),
longitude,
@@ -199,84 +298,148 @@
},
// 閫嗗湴鍧�瑙f瀽
- reverseGeocode(lat, lng) {
- // 杩欓噷搴旇璋冪敤鍚庡彴API杩涜閫嗗湴鍧�瑙f瀽
- // 妯℃嫙鏁版嵁
- this.selectedAddress = {
- title: '閫変腑浣嶇疆',
- address: `缁忕含搴�: ${lat.toFixed(6)}, ${lng.toFixed(6)}`,
- lat: lat,
- lng: lng
+ reverseGeocode(lat, lng, isCurrentLocation = false) {
+ // 鍙傛暟楠岃瘉
+ if (lat === undefined || lat === null || lng === undefined || lng === null) {
+ console.error('閫嗗湴鍧�瑙f瀽鍙傛暟涓嶅畬鏁达紝缂哄皯缁忕含搴﹀潗鏍�', { lat, lng });
+ this.$modal.showToast('鍙傛暟閿欒锛氱己灏戠粡绾害鍧愭爣');
+ return;
}
+
+ // 妫�鏌ュ弬鏁版湁鏁堟��
+ if (isNaN(lat) || isNaN(lng)) {
+ console.error('閫嗗湴鍧�瑙f瀽鍙傛暟鏃犳晥锛屽潗鏍囧寘鍚潪娉曞��', { lat, lng });
+ this.$modal.showToast('鍙傛暟閿欒锛氬潗鏍囨牸寮忔棤鏁�');
+ return;
+ }
+
+ // 浣跨敤鍚庣浠g悊鎺ュ彛杩涜閫嗗湴鍧�瑙f瀽
+ reverseGeocoder(lat, lng).then(res => {
+ if (res.code === 200) {
+ // 瑙f瀽鍚庣杩斿洖鐨勮吘璁湴鍥続PI鍝嶅簲
+ const responseData = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
+ if (responseData && responseData.status === 0 && responseData.result) {
+ const result = responseData.result
+ this.selectedAddress = {
+ title: isCurrentLocation ? '褰撳墠浣嶇疆' : (result.address || '閫変腑浣嶇疆'),
+ address: result.address || `缁忕含搴�: ${lat.toFixed(6)}, ${lng.toFixed(6)}`,
+ lat: lat,
+ lng: lng
+ }
+ } else {
+ this.selectedAddress = {
+ title: isCurrentLocation ? '褰撳墠浣嶇疆' : '閫変腑浣嶇疆',
+ address: `缁忕含搴�: ${lat.toFixed(6)}, ${lng.toFixed(6)}`,
+ lat: lat,
+ lng: lng
+ }
+ }
+ } else {
+ this.selectedAddress = {
+ title: isCurrentLocation ? '褰撳墠浣嶇疆' : '閫変腑浣嶇疆',
+ address: `缁忕含搴�: ${lat.toFixed(6)}, ${lng.toFixed(6)}`,
+ lat: lat,
+ lng: lng
+ }
+ }
+ }).catch(error => {
+ console.error('閫嗗湴鍧�瑙f瀽澶辫触:', error)
+ this.$modal.showToast('鍦板潃瑙f瀽澶辫触锛�' + (error.message || '璇风◢鍚庨噸璇�'))
+ this.selectedAddress = {
+ title: isCurrentLocation ? '褰撳墠浣嶇疆' : '閫変腑浣嶇疆',
+ address: `缁忕含搴�: ${lat.toFixed(6)}, ${lng.toFixed(6)}`,
+ lat: lat,
+ lng: lng
+ }
+ })
},
- // #endif
- // 鎼滅储鍦板潃
+ // 鎼滅储鍦板潃 - 鍙湪鐐瑰嚮鎼滅储鎸夐挳鏃惰皟鐢�
searchAddress() {
+ console.log('鎵ц鎼滅储锛屽叧閿瘝:', this.searchKeyword);
if (!this.searchKeyword) {
this.$modal.showToast('璇疯緭鍏ュ湴鍧�')
return
}
- // 鍦ㄥ疄闄呴」鐩腑锛岃繖閲屽簲璇ヨ皟鐢ㄥ搴斿钩鍙扮殑鍦板浘API
- // 渚嬪H5骞冲彴璋冪敤鐧惧害鍦板浘API锛屽井淇″皬绋嬪簭璋冪敤寰俊鍦板浘API
-
- // 妯℃嫙鎼滅储缁撴灉
- this.searchResults = [
- {
- title: this.searchKeyword + '闄勮繎鍦扮偣1',
- address: '骞夸笢鐪佸箍宸炲競澶╂渤鍖�' + this.searchKeyword + '123鍙�',
- lat: 23.123 + Math.random() * 0.1,
- lng: 113.321 + Math.random() * 0.1
- },
- {
- title: this.searchKeyword + '闄勮繎鍦扮偣2',
- address: '骞夸笢鐪佸箍宸炲競瓒婄鍖�' + this.searchKeyword + '456鍙�',
- lat: 23.145 + Math.random() * 0.1,
- lng: 113.289 + Math.random() * 0.1
- },
- {
- title: this.searchKeyword + '闄勮繎鍦扮偣3',
- address: '骞夸笢鐪佸箍宸炲競鐧戒簯鍖�' + this.searchKeyword + '789鍙�',
- lat: 23.167 + Math.random() * 0.1,
- lng: 113.345 + Math.random() * 0.1
- }
- ]
+ // 浣跨敤鍚庣浠g悊鎺ュ彛杩涜鍦板潃鎼滅储
+ this.searchAddressViaBackend()
},
- // 杈撳叆妗嗚緭鍏ヤ簨浠�
- onSearchInput() {
- // 闃叉姈鎼滅储
+ // 閫氳繃鍚庣浠g悊鎼滅储鍦板潃
+ searchAddressViaBackend() {
+ // 鏄剧ず鎼滅储缁撴灉鍖哄煙
+ this.showSearchResults = true;
+ this.searchCompleted = false;
+
+ console.log('寮�濮嬫悳绱㈠湴鍧�:', this.searchKeyword);
+
+ searchAddress(this.searchKeyword, '骞垮窞').then(res => {
+ console.log('鍦板潃鎼滅储杩斿洖缁撴灉:', res);
+ // 纭繚姝g‘鏇存柊鎼滅储缁撴灉
+ this.searchResults = [];
+
+ if (res.code === 200) {
+ // 瑙f瀽鍚庣杩斿洖鐨勮吘璁湴鍥続PI鍝嶅簲
+ const responseData = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
+ console.log('瑙f瀽鍚庣殑鍝嶅簲鏁版嵁:', responseData);
+
+ if (responseData && responseData.status === 0 && responseData.data && responseData.data.length > 0) {
+ // 鐩存帴璧嬪�兼暟缁勶紝纭繚鍝嶅簲寮忔洿鏂�
+ this.searchResults = responseData.data.map(item => ({
+ title: item.title,
+ address: item.address,
+ lat: item.location.lat,
+ lng: item.location.lng
+ }));
+ console.log('澶勭悊鍚庣殑鎼滅储缁撴灉:', this.searchResults);
+
+ // 娣诲姞璋冭瘯淇℃伅
+ console.log('鎼滅储缁撴灉鏁伴噺:', this.searchResults.length);
+ console.log('showSearchResults:', this.showSearchResults);
+ console.log('v-if鏉′欢缁撴灉:', this.showSearchResults && this.searchResults.length > 0);
+ } else {
+ console.log('鏈壘鍒扮浉鍏冲湴鍧�');
+ // 鍗充娇娌℃湁鏁版嵁涔熻鏄剧ず"鏈壘鍒扮浉鍏冲湴鍧�"
+ this.searchCompleted = true;
+ }
+ } else {
+ console.log('鎼滅储澶辫触锛岄敊璇唬鐮�:', res.code);
+ this.$modal.showToast('鎼滅储澶辫触锛岃閲嶈瘯')
+ }
+
+ // 鏍囪鎼滅储瀹屾垚
+ this.searchCompleted = true;
+ }).catch(error => {
+ console.error('鎼滅储澶辫触:', error)
+ this.$modal.showToast('鎼滅储澶辫触锛岃閲嶈瘯')
+ // 鏍囪鎼滅储瀹屾垚
+ this.searchCompleted = true;
+ })
},
// 閫夋嫨鍦板潃
selectAddress(item) {
this.selectedAddress = item
this.markLocation(item.lat, item.lng)
+
+ // 閫変腑鍦板潃鍚庯紝淇濇寔鎼滅储缁撴灉鍒楄〃鏄剧ず
+ console.log('鍦板潃宸查�変腑:', item);
},
// 鍦ㄥ湴鍥句笂鏍囪浣嶇疆
markLocation(lat, lng) {
- // #ifdef H5
- // H5骞冲彴鏍囪浣嶇疆閫昏緫
- console.log(`H5骞冲彴鏍囪浣嶇疆: ${lat}, ${lng}`)
- this.$modal.showToast(`宸叉爣璁颁綅缃甡)
- // #endif
-
- // #ifdef MP-WEIXIN
- // 寰俊灏忕▼搴忔爣璁颁綅缃�昏緫
this.longitude = lng
this.latitude = lat
this.markers = [{
id: Date.now(),
longitude: lng,
latitude: lat,
- title: item.title,
+ title: this.selectedAddress?.title || '閫変腑浣嶇疆',
iconPath: '/static/icons/location-selected.png',
width: 30,
height: 30
}]
- // #endif
},
// 纭閫夋嫨鍦板潃
@@ -286,6 +449,9 @@
return
}
+ // 鏄剧ず纭鎻愮ず
+ this.$modal.showToast('鍦板潃閫夋嫨鎴愬姛')
+
// 瑙﹀彂浜嬩欢锛屽皢閫変腑鐨勫湴鍧�浼犻�掔粰鐖剁粍浠�
this.$emit('addressSelected', {
title: this.selectedAddress.title,
@@ -293,6 +459,21 @@
lat: this.selectedAddress.lat,
lng: this.selectedAddress.lng
})
+
+ // 纭鍚庨殣钘忔悳绱㈢粨鏋滃拰閫変腑鍦板潃鐣岄潰
+ setTimeout(() => {
+ this.selectedAddress = null
+ this.showSearchResults = false
+ this.searchResults = []
+ }, 1000)
+ },
+
+ // 鍙栨秷閫夋嫨鍦板潃
+ cancelSelection() {
+ this.selectedAddress = null
+ // 鍙竻绌洪�変腑鍦板潃锛屼笉娓呯┖鎼滅储缁撴灉
+ // this.showSearchResults = false
+ // this.searchResults = []
}
}
}
@@ -301,14 +482,17 @@
<style lang="scss">
.map-selector-container {
width: 100%;
- height: 100%;
+ height: 100vh;
display: flex;
flex-direction: column;
.search-bar {
display: flex;
- padding: 20rpx;
+ padding: 15rpx 20rpx;
background-color: white;
+ flex-shrink: 0;
+ position: relative;
+ z-index: 100; /* 鎻愰珮灞傜骇 */
.search-input {
flex: 1;
@@ -328,18 +512,136 @@
border-radius: 10rpx;
font-size: 28rpx;
}
+
+ .location-btn {
+ width: 70rpx;
+ height: 70rpx;
+ margin-left: 10rpx;
+ background-color: #1AAD19;
+ color: white;
+ border-radius: 10rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &:active {
+ background-color: #179B16;
+ }
+
+ &[disabled] {
+ background-color: #ccc;
+ opacity: 0.6;
+ }
+ }
+ }
+
+ .debug-panel {
+ padding: 15rpx 20rpx;
+ background-color: #fff3cd;
+ border: 1rpx solid #ffeaa7;
+ z-index: 100; /* 鎻愰珮灞傜骇 */
+ position: relative;
+
+ .debug-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10rpx;
+
+ .debug-title {
+ font-weight: bold;
+ color: #856404;
+ }
+
+ .debug-toggle {
+ font-size: 24rpx;
+ padding: 5rpx 10rpx;
+ background-color: #ffc107;
+ border: none;
+ border-radius: 5rpx;
+ }
+ }
+
+ .debug-content {
+ font-size: 24rpx;
+ color: #856404;
+
+ text {
+ display: block;
+ margin-bottom: 5rpx;
+ word-break: break-all;
+ }
+ }
+ }
+
+ /* 鍦板潃鎼滅储缁撴灉鍒楄〃 - 璋冩暣浣嶇疆 */
+ .address-list {
+ max-height: 40vh;
+ min-height: 200rpx;
+ overflow-y: auto;
+ background-color: white;
+ position: absolute;
+ top: 300rpx; /* 鍦ㄩ�変腑鍦板潃鐣岄潰涓嬫柟鏄剧ず */
+ left: 0;
+ right: 0;
+ z-index: 90; /* 纭繚鍦ㄥ湴鍥句笂鏂� */
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
+
+ .address-item {
+ padding: 25rpx 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ min-height: 100rpx;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+
+ .address-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ margin-bottom: 8rpx;
+ color: #333;
+ line-height: 1.3;
+ }
+
+ .address-detail {
+ font-size: 28rpx;
+ color: #666;
+ line-height: 1.4;
+ }
+ }
+ }
+
+ /* 鏃犵粨鏋滄彁绀� - 璋冩暣浣嶇疆 */
+ .no-results {
+ padding: 30rpx;
+ text-align: center;
+ background-color: white;
+ color: #999;
+ font-size: 28rpx;
+ position: absolute;
+ top: 150rpx; /* 璋冩暣浣嶇疆 */
+ left: 0;
+ right: 0;
+ z-index: 90; /* 纭繚鍦ㄥ湴鍥句笂鏂� */
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
+ min-height: 200rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
.map-container {
flex: 1;
- height: 400rpx;
+ min-height: 50vh;
+ max-height: 70vh;
+ position: relative;
.map-webview {
width: 100%;
height: 100%;
}
- // 寰俊灏忕▼搴忓湴鍥炬牱寮�
+ // 鍦板浘鏍峰紡
map {
width: 100%;
height: 100%;
@@ -356,43 +658,65 @@
}
}
- .address-list {
- max-height: 300rpx;
- overflow-y: auto;
- background-color: white;
-
- .address-item {
- padding: 20rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
-
- .address-title {
- font-size: 30rpx;
- font-weight: bold;
- margin-bottom: 10rpx;
- }
-
- .address-detail {
- font-size: 26rpx;
- color: #666;
- }
- }
- }
-
.selected-address {
padding: 20rpx 30rpx;
background-color: white;
border-top: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+ position: absolute;
+ top: 150rpx; /* 鍦ㄦ悳绱㈡爮涓嬫柟鏄剧ず */
+ left: 0;
+ right: 0;
+ z-index: 95; /* 纭繚鍦ㄥ湴鍥句笂鏂� */
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
- .address-title {
- font-size: 30rpx;
- font-weight: bold;
- margin-bottom: 10rpx;
+ .selected-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 15rpx;
+
+ .address-title {
+ font-size: 28rpx;
+ font-weight: bold;
+ color: #007AFF;
+ margin-left: 10rpx;
+ }
+
+ .cancel-btn {
+ width: 40rpx;
+ height: 40rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ background-color: #f5f5f5;
+
+ &:active {
+ background-color: #e0e0e0;
+ }
+ }
}
- .address-detail {
- font-size: 26rpx;
- color: #666;
- margin-bottom: 10rpx;
+ .address-info {
+ background-color: #f8f9fa;
+ padding: 25rpx;
+ border-radius: 12rpx;
+ margin-bottom: 20rpx;
+
+ .address-name {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 10rpx;
+ line-height: 1.3;
+ }
+
+ .address-detail {
+ font-size: 28rpx;
+ color: #666;
+ line-height: 1.5;
+ }
}
.confirm-btn {
@@ -402,7 +726,17 @@
color: white;
border-radius: 10rpx;
font-size: 32rpx;
- margin-top: 20rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ text {
+ margin-left: 10rpx;
+ }
+
+ &:active {
+ background-color: #0056CC;
+ }
}
}
}
diff --git a/app/config.js b/app/config.js
index 6f9236d..a1d9202 100644
--- a/app/config.js
+++ b/app/config.js
@@ -1,7 +1,7 @@
// 搴旂敤鍏ㄥ眬閰嶇疆
module.exports = {
- baseUrl: 'https://vue.ruoyi.vip/prod-api',
- // baseUrl: 'http://localhost:8080',
+ // baseUrl: 'https://vue.ruoyi.vip/prod-api',
+ baseUrl: 'http://localhost:8080',
// 搴旂敤淇℃伅
appInfo: {
// 搴旂敤鍚嶇О
diff --git a/app/manifest.json b/app/manifest.json
index 3810283..9af21ee 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,5 +1,5 @@
{
- "name" : "鑻ヤ緷绉诲姩绔�",
+ "name" : "璋冨害绯荤粺",
"appid" : "__UNI__25A9D80",
"description" : "",
"versionName" : "1.1.0",
@@ -54,9 +54,14 @@
"usingComponents" : true,
"sdkConfigs" : {
"maps" : {
- "baidu" : {
- "appkey" : "n5z5pKfAnaP3fYMR4RJOAQsR1wQ2avAn"
+ "tencent" : {
+ "appkey" : "6YVBZ-ZJDLQ-JMY5F-BR7XG-H3TAV-C3FXC"
}
+ }
+ },
+ "permission" : {
+ "scope.userLocation" : {
+ "desc" : "闇�瑕佽嚜鍔ㄨ幏寰楀綋鍓嶇敤鎴蜂綅缃紝浠ュ垽鏂徃鏈烘槸鍚﹀湪甯搁┗鍦拌繕鏄湪鐩殑鍦�"
}
}
},
@@ -74,10 +79,12 @@
},
"sdkConfigs" : {
"maps" : {
- "baidu" : {
- "appkey" : "鎮ㄧ殑鐧惧害鍦板浘AK"
+ "tencent" : {
+ "appkey" : "6YVBZ-ZJDLQ-JMY5F-BR7XG-H3TAV-C3FXC",
+ "key" : "6YVBZ-ZJDLQ-JMY5F-BR7XG-H3TAV-C3FXC"
}
}
}
- }
-}
\ No newline at end of file
+ },
+ "fallbackLocale" : "zh-Hans"
+}
diff --git a/app/pages.json b/app/pages.json
index ee9557c..222db46 100644
--- a/app/pages.json
+++ b/app/pages.json
@@ -17,7 +17,7 @@
}, {
"path": "pages/index",
"style": {
- "navigationBarTitleText": "鑻ヤ緷绉诲姩绔鏋�",
+ "navigationBarTitleText": "姘戣埅鍖荤枟蹇嚎",
"navigationStyle": "custom"
}
}, {
@@ -88,7 +88,22 @@
}, {
"path": "pages/task/create",
"style": {
- "navigationBarTitleText": "鍒涘缓浠诲姟"
+ "navigationBarTitleText": "閫夋嫨浠诲姟绫诲瀷"
+ }
+ }, {
+ "path": "pages/task/create-normal",
+ "style": {
+ "navigationBarTitleText": "鍒涘缓鏅�氫换鍔�"
+ }
+ }, {
+ "path": "pages/task/create-emergency",
+ "style": {
+ "navigationBarTitleText": "鍒涘缓鎬ユ晳杞繍浠诲姟"
+ }
+ }, {
+ "path": "pages/task/create-welfare",
+ "style": {
+ "navigationBarTitleText": "鍒涘缓绂忕杞︿换鍔�"
}
}, {
"path": "pages/task/detail",
diff --git a/app/pages/bind-vehicle.vue b/app/pages/bind-vehicle.vue
index 4897419..417e3a4 100644
--- a/app/pages/bind-vehicle.vue
+++ b/app/pages/bind-vehicle.vue
@@ -4,8 +4,8 @@
<text class="title">缁戝畾杞﹁締</text>
</view>
- <!-- 鎵爜缁戝畾 -->
- <view class="scan-section">
+ <!-- 鎵爜缁戝畾 - 宸查殣钘� -->
+ <!-- <view class="scan-section">
<view class="section-title">鎵竴鎵粦瀹�</view>
<view class="scan-content">
<view class="scan-icon" @click="scanQRCode">
@@ -13,7 +13,7 @@
<text class="scan-text">鐐瑰嚮鎵爜缁戝畾杞﹁締</text>
</view>
</view>
- </view>
+ </view> -->
<!-- 涓嬫媺閫夋嫨缁戝畾 -->
<view class="form-section">
@@ -37,15 +37,90 @@
</template>
<script>
+ import { mapState } from 'vuex'
+ import { listAvailableVehicles, bindVehicleToUser, getUserBoundVehicle } from '@/api/vehicle'
+
export default {
data() {
return {
selectedVehiclePlate: '',
- // 妯℃嫙杞﹁締鍒楄〃鏁版嵁
- vehiclePlates: ['绮12345', '绮67890', '绮11111', '绮22222', '绮33333']
+ selectedVehicleId: null,
+ // 杞﹁締鍒楄〃鏁版嵁
+ vehiclePlates: [],
+ vehicleOptions: [],
+ loading: false,
+ // 褰撳墠缁戝畾鐨勮溅杈嗕俊鎭�
+ currentBoundVehicle: null
}
},
+ computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+ },
+ onLoad() {
+ // 鍔犺浇杞﹁締鍒楄〃
+ this.loadVehicleList()
+ // 鍔犺浇褰撳墠鐢ㄦ埛缁戝畾鐨勮溅杈�
+ this.loadCurrentBoundVehicle()
+ },
methods: {
+ // 鍔犺浇褰撳墠鐢ㄦ埛缁戝畾鐨勮溅杈�
+ loadCurrentBoundVehicle() {
+ const userId = this.currentUser.userId
+ getUserBoundVehicle(userId).then(response => {
+ if (response.code === 200 && response.data) {
+ this.currentBoundVehicle = response.data
+ console.log('褰撳墠缁戝畾杞﹁締:', this.currentBoundVehicle)
+ } else {
+ this.currentBoundVehicle = null
+ }
+ }).catch(error => {
+ console.error('鑾峰彇缁戝畾杞﹁締澶辫触:', error)
+ this.currentBoundVehicle = null
+ })
+ },
+
+ // 鍔犺浇杞﹁締鍒楄〃锛堝彧鍔犺浇鍚屼竴鍒嗗叕鍙哥殑杞﹁締锛�
+ loadVehicleList() {
+ this.loading = true
+ // 鑾峰彇褰撳墠鐢ㄦ埛鐨勯儴闂↖D
+ const deptId = this.currentUser.deptId
+
+ if (!deptId) {
+ this.loading = false
+ console.error('鏃犳硶鑾峰彇鐢ㄦ埛閮ㄩ棬淇℃伅')
+ this.$modal.showToast('鏃犳硶鑾峰彇鐢ㄦ埛閮ㄩ棬淇℃伅')
+ return
+ }
+
+ // 浣跨敤鐢ㄦ埛鎵�鍦ㄧ殑閮ㄩ棬ID鍔犺浇杞﹁締鍒楄〃
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ this.loading = false
+ const vehicleList = response.data || response.rows || []
+
+ if (vehicleList.length === 0) {
+ console.log('褰撳墠鍒嗗叕鍙告殏鏃犲彲鐢ㄨ溅杈�')
+ this.$modal.showToast('褰撳墠鍒嗗叕鍙告殏鏃犲彲鐢ㄨ溅杈�')
+ }
+
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ brand: vehicle.vehicleBrand,
+ model: vehicle.vehicleModel
+ }))
+ this.vehiclePlates = this.vehicleOptions.map(v => v.name)
+
+ console.log(`鍔犺浇浜� ${vehicleList.length} 杈嗚溅杈嗭紙閮ㄩ棬ID: ${deptId}锛塦)
+ }).catch(error => {
+ this.loading = false
+ console.error('鍔犺浇杞﹁締鍒楄〃澶辫触:', error)
+ this.$modal.showToast('鍔犺浇杞﹁締鍒楄〃澶辫触')
+ })
+ },
+
// 鎵爜缁戝畾杞﹁締
scanQRCode() {
// #ifdef H5
@@ -72,23 +147,69 @@
// 杞︾墝鍙烽�夋嫨
onVehiclePlateChange(e) {
- this.selectedVehiclePlate = this.vehiclePlates[e.detail.value]
+ const index = e.detail.value
+ this.selectedVehiclePlate = this.vehiclePlates[index]
+ this.selectedVehicleId = this.vehicleOptions[index]?.id
},
// 缁戝畾杞﹁締
bindVehicle() {
- if (!this.selectedVehiclePlate) {
+ if (!this.selectedVehiclePlate || !this.selectedVehicleId) {
this.$modal.showToast('璇烽�夋嫨杞︾墝鍙�')
return
}
- // 杩欓噷鍙互璋冪敤API杩涜杞﹁締缁戝畾
- this.$modal.confirm('纭缁戝畾杞﹁締 ' + this.selectedVehiclePlate + ' 鍚楋紵').then(() => {
- this.$modal.showToast('杞﹁締缁戝畾鎴愬姛')
- // 杩斿洖涓婁竴椤�
- this.$tab.navigateBack()
- }).catch(() => {
- // 鐢ㄦ埛鍙栨秷鎿嶄綔
+ // 妫�鏌ユ槸鍚﹂�夋嫨鐨勬槸褰撳墠宸茬粦瀹氱殑杞﹁締
+ if (this.currentBoundVehicle && this.currentBoundVehicle.vehicleId === this.selectedVehicleId) {
+ this.$modal.showToast('褰撳墠宸茬粦瀹氭杞﹁締锛屾棤闇�閲嶅缁戝畾')
+ return
+ }
+
+ // 濡傛灉宸茬粡缁戝畾浜嗗叾浠栬溅杈嗭紝鎻愮ず鏄惁寮哄埗缁戝畾
+ if (this.currentBoundVehicle) {
+ const currentVehicleNo = this.currentBoundVehicle.vehicleNumber || '鏈煡杞︾墝'
+ const confirmMsg = `鎮ㄥ綋鍓嶅凡缁戝畾杞﹁締锛�${currentVehicleNo}\n\n纭瑕佽В缁戞棫杞﹁締骞剁粦瀹氭柊杞﹁締锛�${this.selectedVehiclePlate} 鍚楋紵`
+
+ this.$modal.confirm(confirmMsg).then(() => {
+ this.performBind()
+ }).catch(() => {
+ // 鐢ㄦ埛鍙栨秷寮哄埗缁戝畾
+ console.log('鐢ㄦ埛鍙栨秷寮哄埗缁戝畾')
+ })
+ } else {
+ // 娌℃湁缁戝畾杞﹁締锛岀洿鎺ョ粦瀹�
+ this.$modal.confirm('纭缁戝畾杞﹁締 ' + this.selectedVehiclePlate + ' 鍚楋紵').then(() => {
+ this.performBind()
+ }).catch(() => {
+ // 鐢ㄦ埛鍙栨秷鎿嶄綔
+ })
+ }
+ },
+
+ // 鎵ц缁戝畾鎿嶄綔
+ performBind() {
+ this.loading = true
+ const userId = this.currentUser.userId
+
+ bindVehicleToUser(userId, this.selectedVehicleId).then(response => {
+ this.loading = false
+
+ if (response.code === 200) {
+ this.$modal.showToast('杞﹁締缁戝畾鎴愬姛')
+ // 鏇存柊Vuex涓殑鐢ㄦ埛淇℃伅
+ this.$store.dispatch('GetInfo')
+ // 杩斿洖涓婁竴椤�
+ setTimeout(() => {
+ this.$tab.navigateBack()
+ }, 1500)
+ } else {
+ this.$modal.showToast(response.msg || '缁戝畾澶辫触')
+ }
+ }).catch(error => {
+ this.loading = false
+ console.error('缁戝畾杞﹁締澶辫触:', error)
+ const errorMsg = error.msg || error.message || '缁戝畾杞﹁締澶辫触锛岃閲嶈瘯'
+ this.$modal.showToast(errorMsg)
})
},
diff --git a/app/pages/index.vue b/app/pages/index.vue
index 5539ffa..0caeb01 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -5,17 +5,17 @@
<view class="user-info-content">
<view class="user-details">
<view class="user-name">{{ userName || '鏈櫥褰�' }}</view>
- <view class="vehicle-info">
+ <view class="vehicle-info" @click="goToBindVehicle">
<text v-if="boundVehicle">鍏宠仈杞︾墝鍙凤細{{ boundVehicle }}</text>
<text v-else>鏈粦瀹氳溅鐗屽彿</text>
+ <uni-icons
+ :type="boundVehicle ? 'loop' : 'plus-filled'"
+ size="18"
+ :color="boundVehicle ? '#007AFF' : '#999'"
+ style="margin-left: 8rpx;"
+ ></uni-icons>
</view>
</view>
- <button
- class="bind-vehicle-btn"
- @click="goToBindVehicle"
- >
- {{ boundVehicle ? '鏇存崲杞﹁締' : '缁戝畾杞﹁締' }}
- </button>
</view>
</view>
@@ -132,14 +132,18 @@
<script>
import { mapState } from 'vuex'
+ import { getMyTasks, changeTaskStatus } from '@/api/task'
+ import { getUserProfile } from '@/api/system/user'
+ import { getUserBoundVehicle } from '@/api/vehicle'
export default {
data() {
return {
- // 妯℃嫙鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
- boundVehicle: '绮12345', // 妯℃嫙宸茬粦瀹氳溅杈�
+ // 鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ boundVehicle: '',
+ boundVehicleId: null,
- // 妯℃嫙娑堟伅鏁版嵁
+ // 娑堟伅鏁版嵁
messages: [
{
id: 1,
@@ -183,69 +187,23 @@
}
],
- // 妯℃嫙姝e湪杩愯鐨勪换鍔″垪琛�
- taskList: [
- {
- id: 1,
- title: '绱ф�ョ淮淇换鍔�',
- type: 'maintenance', // 缁翠慨淇濆吇
- startLocation: '骞垮窞甯傚ぉ娌冲尯XX璺�123鍙�',
- endLocation: '骞垮窞甯傜櫧浜戝尯YY璺�456鍙�',
- startTime: '2023-05-15 15:00',
- assignee: '寮犱笁',
- status: 'pending',
- vehicle: '绮12345',
- taskNo: 'RW20230515001'
- },
- {
- id: 2,
- title: '瀹氭湡淇濆吇浠诲姟',
- type: 'maintenance', // 缁翠慨淇濆吇
- startLocation: '娣卞湷甯傚崡灞卞尯XX璺�789鍙�',
- endLocation: '娣卞湷甯傜鐢板尯YY璺�999鍙�',
- startTime: '2023-05-14 10:00',
- assignee: '鏉庡洓',
- status: 'processing',
- vehicle: '绮67890',
- taskNo: 'RW20230514002'
- },
- {
- id: 5,
- title: '鎬ユ晳杞繍浠诲姟',
- type: 'emergency', // 鎬ユ晳杞繍
- startLocation: '骞垮窞甯傝秺绉�鍖哄尰闄㈣矾1鍙�',
- endLocation: '骞垮窞甯傛捣鐝犲尯鍖婚櫌璺�2鍙�',
- startTime: '2023-05-16 14:00',
- assignee: '寮犲尰鐢�,鏉庢姢澹�',
- status: 'pending',
- vehicle: '绮33333',
- taskNo: 'RW20230516005'
- },
- {
- id: 6,
- title: '绂忕杞︿换鍔�',
- type: 'welfare', // 绂忕杞�
- startLocation: '骞垮窞甯傝崝婀惧尯绀惧尯璺�10鍙�',
- endLocation: '骞垮窞甯傚ぉ娌冲尯鍏昏�侀櫌璺�20鍙�',
- startTime: '2023-05-17 08:00',
- assignee: '鐜嬪徃鏈�',
- status: 'processing',
- vehicle: '绮44444',
- taskNo: 'RW20230517006'
- }
- ]
+ // 姝e湪杩愯鐨勪换鍔″垪琛�
+ taskList: [],
+ loading: false
}
},
computed: {
...mapState({
- userName: state => state.user.name
+ userName: state => state.user.name,
+ currentUser: state => state.user
}),
- // 姝e湪杩愯鐨勪换鍔★紙寰呭鐞嗗拰澶勭悊涓殑浠诲姟锛�
+ // 姝e湪杩愯鐨勪换鍔★紙寰呭鐞嗗拰鍚勭澶勭悊涓殑浠诲姟锛�
runningTasks() {
- return this.taskList.filter(task =>
- task.status === 'pending' || task.status === 'processing'
- );
+ return this.taskList.filter(task => {
+ // 鍖呭惈寰呭鐞嗐�佸嚭鍙戜腑銆佸凡鍒拌揪銆佽繑绋嬩腑绛夋墍鏈夋湭瀹屾垚鐨勭姸鎬�
+ return ['PENDING', 'DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(task.taskStatus)
+ });
},
// 鏈娑堟伅鏁伴噺
@@ -253,7 +211,161 @@
return this.messages.filter(message => !message.read).length;
}
},
+ onLoad() {
+ // 鍔犺浇鐢ㄦ埛缁戝畾杞﹁締淇℃伅
+ this.loadUserVehicle()
+ // 鍔犺浇姝e湪杩愯鐨勪换鍔�
+ this.loadRunningTasks()
+ },
+ onShow() {
+ // 姣忔鏄剧ず椤甸潰鏃跺埛鏂颁换鍔″垪琛ㄥ拰缁戝畾杞﹁締
+ this.loadUserVehicle()
+ this.loadRunningTasks()
+ },
+ onPullDownRefresh() {
+ // 涓嬫媺鍒锋柊
+ this.loadRunningTasks()
+ setTimeout(() => {
+ uni.stopPullDownRefresh()
+ }, 1000)
+ },
methods: {
+ // 鍔犺浇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ loadUserVehicle() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鑾峰彇缁戝畾杞﹁締淇℃伅')
+ this.boundVehicle = ''
+ this.boundVehicleId = null
+ return
+ }
+
+ getUserBoundVehicle(userId).then(response => {
+ if (response.code === 200 && response.data) {
+ const vehicle = response.data
+ this.boundVehicle = vehicle.vehicleNumber || '鏈煡杞︾墝'
+ this.boundVehicleId = vehicle.vehicleId
+ console.log('鐢ㄦ埛缁戝畾杞﹁締:', this.boundVehicle)
+ } else {
+ this.boundVehicle = ''
+ this.boundVehicleId = null
+ }
+ }).catch(error => {
+ console.error('鑾峰彇缁戝畾杞﹁締淇℃伅澶辫触:', error)
+ this.boundVehicle = ''
+ this.boundVehicleId = null
+ })
+ },
+
+ // 鍔犺浇鐢ㄦ埛淇℃伅锛堜繚鐣欎互鍏煎涔嬪墠鐨勪唬鐮侊級
+ loadUserProfile() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鑾峰彇鐢ㄦ埛淇℃伅')
+ return
+ }
+
+ getUserProfile().then(response => {
+ const userInfo = response.data || response
+ // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ if (userInfo.boundVehicle) {
+ this.boundVehicle = userInfo.boundVehicle.vehicleNumber
+ this.boundVehicleId = userInfo.boundVehicle.vehicleId
+ }
+ }).catch(error => {
+ console.error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触:', error)
+ })
+ },
+
+ // 鍔犺浇姝e湪杩愯鐨勪换鍔�
+ loadRunningTasks() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鍔犺浇浠诲姟鍒楄〃')
+ return
+ }
+
+ this.loading = true
+ // 浣跨敤 /task/my 鎺ュ彛鑾峰彇褰撳墠鐢ㄦ埛鐩稿叧鐨勬墍鏈変换鍔★紙鐢ㄦ埛鍒涘缓銆佸垎閰嶇粰鐢ㄦ埛銆佹墽琛屼汉鏄敤鎴凤級
+ getMyTasks().then(response => {
+ this.loading = false
+ // 鏍规嵁鍚庣杩斿洖鐨勬暟鎹粨鏋勮繘琛岃В鏋�
+ const data = response.data || response.rows || response || []
+ // 杩囨护鍑烘湭瀹屾垚鐨勪换鍔�
+ const allTasks = Array.isArray(data) ? data : []
+ this.taskList = allTasks
+ .filter(task => {
+ // 鍙樉绀烘湭瀹屾垚鍜屾湭鍙栨秷鐨勪换鍔�
+ return task.taskStatus !== 'COMPLETED' && task.taskStatus !== 'CANCELLED'
+ })
+ .map(task => {
+ // 浠巃ssignedVehicles鏁扮粍涓幏鍙栬溅杈嗕俊鎭�
+ let vehicleInfo = '鏈垎閰嶈溅杈�'
+ if (task.assignedVehicles && task.assignedVehicles.length > 0) {
+ const firstVehicle = task.assignedVehicles[0]
+ vehicleInfo = firstVehicle.vehicleNo || '鏈煡杞︾墝'
+ if (task.assignedVehicles.length > 1) {
+ vehicleInfo += ` 绛�${task.assignedVehicles.length}杈哷
+ }
+ }
+
+ return {
+ ...task,
+ // 鏍煎紡鍖栨樉绀哄瓧娈�
+ id: task.taskId,
+ type: task.taskType,
+ vehicle: vehicleInfo,
+ vehicleList: task.assignedVehicles || [],
+ startLocation: this.formatAddress(task.departureAddress || task.startLocation || '鏈缃�'),
+ endLocation: this.formatAddress(task.destinationAddress || task.endLocation || '鏈缃�'),
+ startTime: task.plannedStartTime ? this.formatDateTime(task.plannedStartTime) : '鏈缃�',
+ assignee: task.assigneeName || '鏈垎閰�',
+ taskNo: task.taskCode || '鏈煡缂栧彿',
+ status: this.convertStatus(task.taskStatus) // 杞崲鐘舵�佹牸寮忎互鍏煎鏃I
+ }
+ })
+ }).catch(error => {
+ this.loading = false
+ console.error('鍔犺浇浠诲姟鍒楄〃澶辫触:', error)
+ })
+ },
+
+ // 鏍煎紡鍖栨棩鏈熸椂闂�
+ formatDateTime(dateTime) {
+ if (!dateTime) return ''
+ const date = new Date(dateTime)
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ })
+ },
+
+ // 鏍煎紡鍖栧湴鍧� - 鍙樉绀�-鍓嶉潰鐨勯儴鍒�
+ formatAddress(address) {
+ if (!address) return '鏈缃�'
+ const dashIndex = address.indexOf('-')
+ if (dashIndex > 0) {
+ return address.substring(0, dashIndex)
+ }
+ return address
+ },
+
+ // 杞崲鐘舵�佹牸寮忥紙灏嗘暟鎹簱鐘舵�佽浆鎹负UI浣跨敤鐨勭姸鎬侊級
+ convertStatus(dbStatus) {
+ const statusMap = {
+ 'PENDING': 'pending',
+ 'DEPARTING': 'processing',
+ 'ARRIVED': 'processing',
+ 'RETURNING': 'processing',
+ 'IN_PROGRESS': 'processing',
+ 'COMPLETED': 'completed',
+ 'CANCELLED': 'cancelled'
+ }
+ return statusMap[dbStatus] || 'pending'
+ },
// 璺宠浆鍒扮粦瀹氳溅杈嗛〉闈�
goToBindVehicle() {
// 璺宠浆鍒扮粦瀹氳溅杈嗙殑椤甸潰
@@ -267,79 +379,150 @@
// 鏌ョ湅浠诲姟璇︽儏
viewTaskDetail(task) {
- // 璺宠浆鍒颁换鍔¤鎯呴〉闈�
- this.$tab.navigateTo(`/pages/task/detail?id=${task.id}`);
+ // 璺宠浆鍒颁换鍔¤鎯呴〉闈� - 浣跨敤taskId
+ this.$tab.navigateTo(`/pages/task/detail?id=${task.taskId || task.id}`);
},
// 鍒ゆ柇鎿嶄綔鎸夐挳鏄惁绂佺敤
isActionDisabled(task, action) {
- // 鏍规嵁浠诲姟鐘舵�佸拰鎿嶄綔绫诲瀷鍒ゆ柇鏄惁绂佺敤
+ // 鏍规嵁浠诲姟鐨勫疄闄呯姸鎬佸垽鏂�
+ const taskStatus = task.taskStatus
switch (action) {
case 'depart':
- return task.status !== 'pending';
+ return taskStatus !== 'PENDING'
case 'arrive':
- return task.status !== 'processing';
+ return taskStatus !== 'DEPARTING'
case 'return':
- return task.status !== 'processing';
+ return taskStatus !== 'ARRIVED'
case 'settle':
- return task.status !== 'processing';
+ return !['ARRIVED', 'RETURNING'].includes(taskStatus)
case 'complete':
- return task.status !== 'processing';
+ return taskStatus !== 'RETURNING'
default:
- return false;
+ return false
}
},
// 澶勭悊浠诲姟鎿嶄綔
handleTaskAction(task, action) {
if (this.isActionDisabled(task, action)) {
- return;
+ return
}
switch (action) {
case 'depart':
- // 鍑哄彂鎿嶄綔锛屾牴鎹换鍔$被鍨嬫樉绀轰笉鍚岀殑纭淇℃伅
- let departMessage = '纭畾瑕佹爣璁颁负宸插嚭鍙戝悧锛�';
- if (task.type !== 'maintenance' && task.type !== 'refuel' && task.type !== 'inspection') {
- departMessage = '鍙戝嚭鍘荤洰鐨勫湴,纭锛�';
+ // 鍑哄彂鎿嶄綔 -> 鐘舵�佸彉涓哄嚭鍙戜腑
+ let departMessage = '纭畾瑕佸嚭鍙戝悧锛�'
+ if (task.taskType !== 'MAINTENANCE' && task.taskType !== 'FUEL') {
+ departMessage = '鍑哄彂鍘荤洰鐨勫湴锛岀‘璁わ紵'
}
this.$modal.confirm(departMessage).then(() => {
- task.status = 'processing';
- this.$modal.showToast('宸插嚭鍙�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
- }).catch(() => {});
- break;
+ this.updateTaskStatus(task.taskId, 'DEPARTING', '浠诲姟宸插嚭鍙�')
+ }).catch(() => {})
+ break
+
case 'arrive':
- // 宸插埌杈炬搷浣�
+ // 宸插埌杈炬搷浣� -> 鐘舵�佸彉涓哄凡鍒拌揪
this.$modal.confirm('宸茬粡鍒拌揪鐩殑鍦帮紝纭锛�').then(() => {
- this.$modal.showToast('宸插埌杈�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
- }).catch(() => {});
- break;
+ this.updateTaskStatus(task.taskId, 'ARRIVED', '宸插埌杈剧洰鐨勫湴')
+ }).catch(() => {})
+ break
+
case 'return':
- // 杩旂▼鎿嶄綔
- this.$modal.confirm('鐜板湪宸茬粡杩旂▼涓紝纭锛�').then(() => {
- this.$modal.showToast('杩旂▼涓�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
- }).catch(() => {});
- break;
+ // 杩旂▼鎿嶄綔 -> 鐘舵�佸彉涓鸿繑绋嬩腑
+ this.$modal.confirm('纭寮�濮嬭繑绋嬶紵').then(() => {
+ this.updateTaskStatus(task.taskId, 'RETURNING', '宸插紑濮嬭繑绋�')
+ }).catch(() => {})
+ break
+
case 'settle':
// 缁撶畻鎿嶄綔锛岃烦杞埌缁撶畻椤甸潰
- this.$tab.navigateTo(`/pages/task/settlement?id=${task.id}`);
- break;
+ this.$tab.navigateTo(`/pages/task/settlement?id=${task.taskId}`)
+ break
+
case 'complete':
- // 宸插畬鎴愭搷浣�
+ // 宸插畬鎴愭搷浣� -> 鐘舵�佸彉涓哄凡瀹屾垚
this.$modal.confirm('浠诲姟鏄惁宸茬粡鍏ㄩ儴瀹屾垚锛岀‘璁わ紵').then(() => {
- task.status = 'completed';
- this.$modal.showToast('浠诲姟宸插畬鎴�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
- }).catch(() => {});
- break;
+ this.updateTaskStatus(task.taskId, 'COMPLETED', '浠诲姟宸插畬鎴�')
+ }).catch(() => {})
+ break
}
},
+ // 鏇存柊浠诲姟鐘舵��
+ updateTaskStatus(taskId, status, remark) {
+ // 鑾峰彇GPS浣嶇疆淇℃伅
+ this.getLocationAndUpdateStatus(taskId, status, remark)
+ },
+
+ // 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
+ getLocationAndUpdateStatus(taskId, status, remark) {
+ const that = this
+
+ // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
+ uni.getLocation({
+ type: 'gcj02',
+ geocode: true,
+ altitude: true,
+ success: function(res) {
+ console.log('GPS瀹氫綅鎴愬姛:', res)
+
+ 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.loadRunningTasks()
+ }).catch(error => {
+ console.error('鏇存柊浠诲姟鐘舵�佸け璐�:', error)
+ that.$modal.showToast('鐘舵�佹洿鏂板け璐ワ紝璇烽噸璇�')
+ })
+ },
+ fail: function(err) {
+ console.error('GPS瀹氫綅澶辫触:', err)
+
+ that.$modal.confirm('GPS瀹氫綅澶辫触锛屾槸鍚︾户缁洿鏂扮姸鎬侊紵').then(() => {
+ const statusData = {
+ taskStatus: status,
+ remark: remark
+ }
+
+ changeTaskStatus(taskId, statusData).then(response => {
+ that.$modal.showToast('鐘舵�佹洿鏂版垚鍔�')
+ that.loadRunningTasks()
+ }).catch(error => {
+ console.error('鏇存柊浠诲姟鐘舵�佸け璐�:', error)
+ that.$modal.showToast('鐘舵�佹洿鏂板け璐ワ紝璇烽噸璇�')
+ })
+ }).catch(() => {})
+ }
+ })
+ },
+
getStatusText(status) {
+ // 鏀寔鏂版棫涓ょ鐘舵�佹牸寮�
const statusMap = {
+ // 鏂版牸寮忥紙鏁版嵁搴撶姸鎬侊級
+ 'PENDING': '寰呭鐞�',
+ 'DEPARTING': '鍑哄彂涓�',
+ 'ARRIVED': '宸插埌杈�',
+ 'RETURNING': '杩旂▼涓�',
+ 'COMPLETED': '宸插畬鎴�',
+ 'CANCELLED': '宸插彇娑�',
+ 'IN_PROGRESS': '澶勭悊涓�',
+ // 鏃ф牸寮忥紙UI鐘舵�侊級
'pending': '寰呭鐞�',
'processing': '澶勭悊涓�',
'completed': '宸插畬鎴�'
@@ -349,6 +532,13 @@
getTaskTypeText(type) {
const typeMap = {
+ // 鏂版牸寮忥紙鏁版嵁搴撶被鍨嬶級
+ 'MAINTENANCE': '缁翠慨淇濆吇',
+ 'FUEL': '鍔犳补',
+ 'OTHER': '鍏朵粬',
+ 'EMERGENCY_TRANSFER': '鎬ユ晳杞繍',
+ 'WELFARE': '绂忕杞�',
+ // 鏃ф牸寮忥紙UI绫诲瀷锛�
'maintenance': '缁翠慨淇濆吇',
'refuel': '鍔犳补',
'inspection': '宸℃',
@@ -402,6 +592,8 @@
align-items: center;
.user-details {
+ flex: 1;
+
.user-name {
font-size: 36rpx;
font-weight: bold;
@@ -412,15 +604,14 @@
.vehicle-info {
font-size: 28rpx;
color: #666;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+
+ &:active {
+ opacity: 0.7;
+ }
}
- }
-
- .bind-vehicle-btn {
- background-color: #007AFF;
- color: white;
- border-radius: 10rpx;
- padding: 15rpx 30rpx;
- font-size: 28rpx;
}
}
}
diff --git a/app/pages/mine/index.vue b/app/pages/mine/index.vue
index e936762..6ee6073 100644
--- a/app/pages/mine/index.vue
+++ b/app/pages/mine/index.vue
@@ -106,13 +106,15 @@
<script>
import storage from '@/utils/storage'
import { getUserProfile } from "@/api/system/user"
+ import { getUserBoundVehicle, unbindVehicleFromUser } from '@/api/vehicle'
export default {
data() {
return {
name: this.$store.state.user.name,
phonenumber: '',
- boundVehicle: '', // 妯℃嫙缁戝畾鐨勮溅杈嗕俊鎭�
+ boundVehicle: '', // 缁戝畾鐨勮溅杈嗕俊鎭�
+ boundVehicleId: null, // 缁戝畾鐨勮溅杈咺D
version: getApp().globalData.config.appInfo.version
}
},
@@ -130,18 +132,35 @@
methods: {
// 鑾峰彇鐢ㄦ埛淇℃伅
getUserInfo() {
+ const userId = this.$store.state.user.userId
+
+ // 鑾峰彇鐢ㄦ埛鍩烘湰淇℃伅
getUserProfile().then(response => {
const user = response.data
this.name = user.userName
this.phonenumber = user.phonenumber
- // 妯℃嫙缁戝畾杞﹁締淇℃伅锛屽疄闄呴」鐩腑搴斾粠鐢ㄦ埛淇℃伅鎴栬溅杈嗘帴鍙h幏鍙�
- this.boundVehicle = '绮12345'
}).catch(() => {
// 鑾峰彇鐢ㄦ埛淇℃伅澶辫触鏃朵娇鐢ㄩ粯璁ゅ��
this.name = this.$store.state.user.name || '鏈櫥褰�'
this.phonenumber = '鏈粦瀹�'
- this.boundVehicle = '鏈粦瀹�'
})
+
+ // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ if (userId) {
+ getUserBoundVehicle(userId).then(response => {
+ if (response.code === 200 && response.data) {
+ const vehicle = response.data
+ this.boundVehicle = vehicle.vehicleNumber || '鏈煡杞︾墝'
+ this.boundVehicleId = vehicle.vehicleId
+ } else {
+ this.boundVehicle = '鏈粦瀹�'
+ this.boundVehicleId = null
+ }
+ }).catch(() => {
+ this.boundVehicle = '鏈粦瀹�'
+ this.boundVehicleId = null
+ })
+ }
},
// 璺宠浆鍒扮粦瀹氳溅杈嗛〉闈�
@@ -151,10 +170,30 @@
// 鍙栨秷缁戝畾杞﹁締
unbindVehicle() {
- this.$modal.confirm('鏄惁鍙栨秷缁戝畾杞﹁締锛�').then(() => {
- // 杩欓噷鍙互璋冪敤API鍙栨秷缁戝畾杞﹁締
- this.boundVehicle = '鏈粦瀹�'
- this.$modal.showToast('鍙栨秷缁戝畾鎴愬姛')
+ const userId = this.$store.state.user.userId
+ const vehicleId = this.boundVehicleId
+
+ if (!userId || !vehicleId) {
+ this.$modal.showToast('鏃犳硶鑾峰彇缁戝畾淇℃伅')
+ return
+ }
+
+ this.$modal.confirm(`纭鍙栨秷缁戝畾杞﹁締 ${this.boundVehicle} 鍚楋紵`).then(() => {
+ // 璋冪敤API鍙栨秷缁戝畾杞﹁締
+ unbindVehicleFromUser(userId, vehicleId).then(response => {
+ if (response.code === 200) {
+ this.boundVehicle = '鏈粦瀹�'
+ this.boundVehicleId = null
+ this.$modal.showToast('鍙栨秷缁戝畾鎴愬姛')
+ // 鏇存柊鐢ㄦ埛淇℃伅
+ this.$store.dispatch('GetInfo')
+ } else {
+ this.$modal.showToast(response.msg || '鍙栨秷缁戝畾澶辫触')
+ }
+ }).catch(error => {
+ console.error('鍙栨秷缁戝畾澶辫触:', error)
+ this.$modal.showToast('鍙栨秷缁戝畾澶辫触锛岃閲嶈瘯')
+ })
}).catch(() => {
// 鐢ㄦ埛鍙栨秷鎿嶄綔
})
diff --git a/app/pages/task/create-emergency.vue b/app/pages/task/create-emergency.vue
new file mode 100644
index 0000000..cefe5b2
--- /dev/null
+++ b/app/pages/task/create-emergency.vue
@@ -0,0 +1,1552 @@
+<template>
+ <scroll-view class="create-emergency-task-container" scroll-y="true">
+ <view class="form-header">
+ <view class="back-btn" @click="goBack">
+ <uni-icons type="arrowleft" size="20"></uni-icons>
+ </view>
+ <view class="title">鍒涘缓闈炴�ユ晳杞繍浠诲姟</view>
+ </view>
+
+ <view class="form-section">
+ <view class="form-item">
+ <view class="form-label">浠诲姟杞﹁締</view>
+ <picker mode="selector" :range="vehicles" @change="onVehicleChange">
+ <view class="form-input picker-input">
+ {{ selectedVehicle || '璇烽�夋嫨浠诲姟杞﹁締' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎵ц浠诲姟浜哄憳</view>
+ <view class="staff-list">
+ <view class="staff-item" v-for="(staff, index) in selectedStaff" :key="staff.userId">
+ <view class="staff-info">
+ <text class="staff-name">{{ staff.nickName }}</text>
+ <text class="staff-role">({{ staff.postName || staff.roleName || '鏈煡鑱屼綅' }})</text>
+ </view>
+ <uni-icons
+ v-if="index > 0"
+ type="closeempty"
+ size="20"
+ color="#ff4d4f"
+ @click="removeStaff(index)"
+ ></uni-icons>
+ <uni-icons
+ v-else
+ type="checkmarkempty"
+ size="20"
+ color="#007AFF"
+ ></uni-icons>
+ </view>
+ <view class="add-staff" @click="showStaffSelector">
+ <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
+ <text>娣诲姞浜哄憳</text>
+ </view>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">褰掑睘鏈烘瀯</view>
+ <picker mode="selector" :range="organizations" @change="onOrganizationChange">
+ <view class="form-input picker-input">
+ {{ selectedOrganization || '璇烽�夋嫨褰掑睘鏈烘瀯' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">浠诲姟绫诲瀷</view>
+ <picker mode="selector" :range="emergencyTaskTypes" @change="onEmergencyTaskTypeChange">
+ <view class="form-input picker-input">
+ {{ selectedEmergencyTaskType || '璇烽�夋嫨浠诲姟绫诲瀷' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">杞繍鏃堕棿</view>
+ <uni-datetime-picker
+ v-model="taskForm.transferTime"
+ type="datetime"
+ :placeholder="'璇烽�夋嫨杞繍鏃堕棿'"
+ class="form-input"
+ />
+ </view>
+
+ <view class="form-section-title">鎮h�呬俊鎭�</view>
+ <view class="form-item">
+ <view class="form-label">鑱旂郴浜�</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ヨ仈绯讳汉"
+ v-model="taskForm.patient.contact"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鑱旂郴鐢佃瘽</view>
+ <input
+ class="form-input"
+ type="number"
+ placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
+ v-model="taskForm.patient.phone"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎮h�呭鍚�</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
+ v-model="taskForm.patient.name"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎬у埆</view>
+ <view class="radio-group">
+ <label class="radio-item">
+ <radio value="male" :checked="taskForm.patient.gender === 'male'" @click="taskForm.patient.gender = 'male'" />
+ <text>鐢�</text>
+ </label>
+ <label class="radio-item">
+ <radio value="female" :checked="taskForm.patient.gender === 'female'" @click="taskForm.patient.gender = 'female'" />
+ <text>濂�</text>
+ </label>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎮h�呰韩浠借瘉</view>
+ <input
+ class="form-input"
+ type="idcard"
+ placeholder="璇疯緭鍏ユ偅鑰呰韩浠借瘉鍙�"
+ v-model="taskForm.patient.idCard"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鐥呮儏</view>
+ <view class="disease-container">
+ <view class="disease-tags" v-if="selectedDiseases.length > 0">
+ <view
+ class="disease-tag"
+ v-for="(disease, index) in selectedDiseases"
+ :key="index"
+ >
+ <text class="disease-name">{{ disease.icdName }}</text>
+ <uni-icons
+ type="closeempty"
+ size="16"
+ color="#fff"
+ @click="removeDisease(index)"
+ ></uni-icons>
+ </view>
+ </view>
+ <view class="add-disease-btn" @click="showDiseaseSelector">
+ <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
+ <text>娣诲姞鐥呮儏</text>
+ </view>
+ <textarea
+ class="form-textarea"
+ placeholder="鍏朵粬鐥呮儏鎻忚堪锛堥�夊~锛�"
+ v-model="taskForm.patient.condition"
+ style="margin-top: 20rpx;"
+ />
+ </view>
+ </view>
+
+ <view class="form-section-title">杞嚭鍖婚櫌淇℃伅</view>
+ <view class="form-item">
+ <view class="form-label">鍖婚櫌鍚嶇О</view>
+ <view class="hospital-search-container">
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ュ尰闄㈠悕绉版垨鍦板潃鎼滅储"
+ v-model="hospitalOutSearchKeyword"
+ @input="onHospitalOutSearch"
+ @focus="showHospitalOutResults = true"
+ />
+ <view class="search-results" v-if="showHospitalOutResults && hospitalOutResults.length > 0">
+ <view
+ class="search-result-item"
+ v-for="hospital in hospitalOutResults"
+ :key="hospital.hospId"
+ @click="selectHospitalOut(hospital)"
+ >
+ <view class="hospital-name">{{ hospital.hospName }}</view>
+ <view class="hospital-address">{{ hospital.hospAddress }}</view>
+ </view>
+ </view>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">绉戝</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ョ瀹�"
+ v-model="taskForm.hospitalOut.department"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">搴婂彿</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ュ簥鍙�"
+ v-model="taskForm.hospitalOut.bedNumber"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">杞嚭鍦板潃</view>
+ <view class="form-input picker-input disabled">
+ {{ taskForm.hospitalOut.address || '閫夋嫨鍖婚櫌鍚庤嚜鍔ㄥ~鍏�' }}
+ </view>
+ </view>
+
+ <view class="form-section-title">杞叆鍖婚櫌淇℃伅</view>
+ <view class="form-item">
+ <view class="form-label">鍖婚櫌鍚嶇О</view>
+ <view class="hospital-search-container">
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ュ尰闄㈠悕绉版垨鍦板潃鎼滅储"
+ v-model="hospitalInSearchKeyword"
+ @input="onHospitalInSearch"
+ @focus="showHospitalInResults = true"
+ />
+ <view class="search-results" v-if="showHospitalInResults && hospitalInResults.length > 0">
+ <view
+ class="search-result-item"
+ v-for="hospital in hospitalInResults"
+ :key="hospital.hospId"
+ @click="selectHospitalIn(hospital)"
+ >
+ <view class="hospital-name">{{ hospital.hospName }}</view>
+ <view class="hospital-address">{{ hospital.hospAddress }}</view>
+ </view>
+ </view>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">绉戝</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ョ瀹�"
+ v-model="taskForm.hospitalIn.department"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">搴婂彿</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ュ簥鍙�"
+ v-model="taskForm.hospitalIn.bedNumber"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">杞叆鍦板潃</view>
+ <view class="form-input picker-input disabled">
+ {{ taskForm.hospitalIn.address || '閫夋嫨鍖婚櫌鍚庤嚜鍔ㄥ~鍏�' }}
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">杞繍鍏噷鏁�</view>
+ <input
+ class="form-input"
+ type="digit"
+ placeholder="璇疯緭鍏ヨ浆杩愬叕閲屾暟"
+ v-model="taskForm.transferDistance"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎴愪氦浠�</view>
+ <input
+ class="form-input"
+ type="digit"
+ placeholder="璇疯緭鍏ユ垚浜や环"
+ v-model="taskForm.price"
+ />
+ </view>
+
+ <view class="form-actions">
+ <button class="submit-btn" @click="submitTask" :disabled="loading">
+ {{ loading ? '淇濆瓨涓�...' : '淇濆瓨' }}
+ </button>
+ </view>
+ </view>
+
+ <!-- 浜哄憳閫夋嫨寮圭獥 -->
+ <uni-popup ref="staffPopup" type="bottom" :safe-area="true">
+ <view class="staff-selector-popup">
+ <view class="popup-header">
+ <view class="popup-title">閫夋嫨鎵ц浜哄憳</view>
+ <view class="popup-close" @click="closeStaffSelector">
+ <uni-icons type="closeempty" size="24" color="#333"></uni-icons>
+ </view>
+ </view>
+
+ <view class="search-box">
+ <uni-icons type="search" size="18" color="#999"></uni-icons>
+ <input
+ class="search-input"
+ placeholder="鎼滅储濮撳悕銆佹墜鏈哄彿"
+ v-model="staffSearchKeyword"
+ @input="onStaffSearch"
+ />
+ </view>
+
+ <view class="staff-filter">
+ <view
+ class="filter-item"
+ :class="{ active: staffFilterType === 'all' }"
+ @click="filterStaff('all')"
+ >鍏ㄩ儴</view>
+ <view
+ class="filter-item"
+ :class="{ active: staffFilterType === 'driver' }"
+ @click="filterStaff('driver')"
+ >鍙告満</view>
+ <view
+ class="filter-item"
+ :class="{ active: staffFilterType === 'nurse' }"
+ @click="filterStaff('nurse')"
+ >鎶ゅ+</view>
+ </view>
+
+ <scroll-view class="staff-list-popup" scroll-y="true">
+ <view
+ class="staff-item-popup"
+ v-for="staff in filteredStaffList"
+ :key="staff.userId"
+ @click="toggleStaffSelection(staff)"
+ >
+ <view class="staff-info">
+ <view class="staff-name-row">
+ <text class="staff-name">{{ staff.nickName }}</text>
+ <text class="staff-phone">{{ staff.phonenumber }}</text>
+ </view>
+ <view class="staff-detail-row">
+ <text class="staff-dept">{{ staff.deptName }}</text>
+ <text class="staff-post">{{ staff.postName || staff.roleName || '鏈煡鑱屼綅' }}</text>
+ </view>
+ </view>
+ <uni-icons
+ v-if="isStaffSelected(staff.userId)"
+ type="checkmarkempty"
+ size="24"
+ color="#007AFF"
+ ></uni-icons>
+ <view v-else class="checkbox-empty"></view>
+ </view>
+
+ <view class="no-data" v-if="filteredStaffList.length === 0">
+ <uni-icons type="info" size="40" color="#ccc"></uni-icons>
+ <text>鏆傛棤浜哄憳鏁版嵁</text>
+ </view>
+ </scroll-view>
+
+ <view class="popup-footer">
+ <button class="cancel-btn" @click="closeStaffSelector">鍙栨秷</button>
+ <button class="confirm-btn" @click="confirmStaffSelection">纭畾(宸查�墈{ selectedStaff.length }})</button>
+ </view>
+ </view>
+ </uni-popup>
+
+ <!-- 鐥呮儏閫夋嫨寮圭獥 -->
+ <uni-popup ref="diseasePopup" type="bottom" :safe-area="true">
+ <view class="disease-selector-popup">
+ <view class="popup-header">
+ <view class="popup-title">閫夋嫨鐥呮儏锛圛CD-10锛�</view>
+ <view class="popup-close" @click="closeDiseaseSelector">
+ <uni-icons type="closeempty" size="24" color="#333"></uni-icons>
+ </view>
+ </view>
+
+ <view class="search-box">
+ <uni-icons type="search" size="18" color="#999"></uni-icons>
+ <input
+ class="search-input"
+ placeholder="鎼滅储鐤剧梾鍚嶇О銆佺紪鐮佹垨鍔╄鐮�"
+ v-model="diseaseSearchKeyword"
+ @input="onDiseaseSearch"
+ />
+ </view>
+
+ <scroll-view class="disease-list-popup" scroll-y="true">
+ <view
+ class="disease-item-popup"
+ v-for="disease in diseaseSearchResults"
+ :key="disease.id"
+ @click="toggleDiseaseSelection(disease)"
+ >
+ <view class="disease-info">
+ <view class="disease-name-row">
+ <text class="disease-name">{{ disease.icdName }}</text>
+ <text class="disease-code">[{{ disease.icdCode }}]</text>
+ </view>
+ <view class="disease-detail-row" v-if="disease.sm">
+ <text class="disease-desc">{{ disease.sm }}</text>
+ </view>
+ </view>
+ <uni-icons
+ v-if="isDiseaseSelected(disease.id)"
+ type="checkmarkempty"
+ size="24"
+ color="#007AFF"
+ ></uni-icons>
+ <view v-else class="checkbox-empty"></view>
+ </view>
+
+ <view class="no-data" v-if="diseaseSearchResults.length === 0 && diseaseSearchKeyword">
+ <uni-icons type="info" size="40" color="#ccc"></uni-icons>
+ <text>鏈壘鍒扮浉鍏崇柧鐥�</text>
+ </view>
+
+ <view class="no-data" v-if="diseaseSearchResults.length === 0 && !diseaseSearchKeyword">
+ <uni-icons type="search" size="40" color="#ccc"></uni-icons>
+ <text>璇疯緭鍏ュ叧閿瘝鎼滅储鐤剧梾</text>
+ </view>
+ </scroll-view>
+
+ <view class="popup-footer">
+ <button class="cancel-btn" @click="closeDiseaseSelector">鍙栨秷</button>
+ <button class="confirm-btn" @click="confirmDiseaseSelection">纭畾(宸查�墈{ tempSelectedDiseases.length }})</button>
+ </view>
+ </view>
+ </uni-popup>
+ </scroll-view>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
+import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
+import { addTask } from "@/api/task"
+import { listAvailableVehicles } from "@/api/vehicle"
+import { calculateDistance } from "@/api/map"
+import { searchHospitals } from "@/api/hospital"
+import { listUser } from "@/api/system/user"
+import { searchIcd10 } from "@/api/icd10"
+import MapSelector from '@/components/map-selector.vue'
+
+export default {
+ components: {
+ uniDatetimePicker,
+ uniPopup,
+ MapSelector
+ },
+ data() {
+ return {
+ selectedVehicle: '',
+ selectedVehicleId: null,
+ selectedOrganization: '',
+ selectedEmergencyTaskType: '',
+ mapSelectorType: '',
+ // 鍖婚櫌鎼滅储鐩稿叧
+ hospitalOutSearchKeyword: '',
+ hospitalOutResults: [],
+ showHospitalOutResults: false,
+ hospitalInSearchKeyword: '',
+ hospitalInResults: [],
+ showHospitalInResults: false,
+ searchTimer: null,
+ // 浜哄憳閫夋嫨鐩稿叧
+ selectedStaff: [], // 宸查�夋嫨鐨勪汉鍛樺垪琛�
+ allStaffList: [], // 鎵�鏈変汉鍛樺垪琛�
+ filteredStaffList: [], // 杩囨护鍚庣殑浜哄憳鍒楄〃
+ staffSearchKeyword: '', // 浜哄憳鎼滅储鍏抽敭璇�
+ staffFilterType: 'all', // 浜哄憳绛涢�夌被鍨嬶細all/driver/nurse
+ // 鐥呮儏閫夋嫨鐩稿叧
+ selectedDiseases: [], // 宸查�夋嫨鐨勭梾鎯呭垪琛�
+ tempSelectedDiseases: [], // 涓存椂閫夋嫨鐨勭梾鎯呭垪琛紙鐢ㄤ簬寮圭獥锛�
+ diseaseSearchKeyword: '', // 鐥呮儏鎼滅储鍏抽敭璇�
+ diseaseSearchResults: [], // 鐥呮儏鎼滅储缁撴灉
+ diseaseSearchTimer: null, // 鐥呮儏鎼滅储闃叉姈瀹氭椂鍣�
+ taskForm: {
+ transferTime: '',
+ patient: {
+ contact: '',
+ phone: '',
+ name: '',
+ gender: 'male',
+ idCard: '',
+ condition: ''
+ },
+ hospitalOut: {
+ name: '',
+ department: '',
+ bedNumber: '',
+ address: ''
+ },
+ hospitalIn: {
+ name: '',
+ department: '',
+ bedNumber: '',
+ address: ''
+ },
+ transferDistance: '',
+ price: ''
+ },
+ vehicles: [],
+ vehicleOptions: [],
+ organizations: ['骞垮窞鍒嗗叕鍙�', '娣卞湷鍒嗗叕鍙�', '鐝犳捣鍒嗗叕鍙�', '浣涘北鍒嗗叕鍙�'],
+ emergencyTaskTypes: ['鎬ユ晳杞繍', '鑸┖杞繍'],
+ loading: false,
+ addressCoordinates: {
+ hospitalOutAddress: null,
+ hospitalInAddress: null
+ }
+ }
+ },
+ computed: {
+ ...mapState({
+ currentUser: state => ({
+ userId: state.user.userId,
+ name: state.user.name || '寮犱笁',
+ nickName: state.user.nickName || state.user.name || '寮犱笁',
+ position: '鍙告満',
+ deptId: state.user.deptId || 100,
+ phonenumber: state.user.phonenumber || ''
+ })
+ })
+ },
+ onLoad(options) {
+ this.getAvailableVehicles()
+ this.initSelectedStaff()
+ this.loadDeptStaff()
+ },
+ methods: {
+ getAvailableVehicles() {
+ const deptId = this.currentUser.deptId
+ return listAvailableVehicles(deptId, 'EMERGENCY').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ status: vehicle.status
+ }))
+ this.vehicles = this.vehicleOptions.map(v => v.name)
+ }).catch(() => {
+ this.vehicles = []
+ })
+ },
+
+ onVehicleChange(e) {
+ const index = e.detail.value
+ this.selectedVehicle = this.vehicles[index]
+ this.selectedVehicleId = this.vehicleOptions[index]?.id
+ },
+
+ onOrganizationChange(e) {
+ this.selectedOrganization = this.organizations[e.detail.value]
+ },
+
+ onEmergencyTaskTypeChange(e) {
+ this.selectedEmergencyTaskType = this.emergencyTaskTypes[e.detail.value]
+ },
+
+ // 杞嚭鍖婚櫌鎼滅储
+ onHospitalOutSearch(e) {
+ const keyword = e.detail.value
+ this.hospitalOutSearchKeyword = keyword
+
+ // 闃叉姈澶勭悊
+ if (this.searchTimer) {
+ clearTimeout(this.searchTimer)
+ }
+
+ if (!keyword || keyword.trim() === '') {
+ this.hospitalOutResults = []
+ return
+ }
+
+ this.searchTimer = setTimeout(() => {
+ this.searchHospitalOut(keyword)
+ }, 300)
+ },
+
+ // 鎼滅储杞嚭鍖婚櫌
+ searchHospitalOut(keyword) {
+ searchHospitals(keyword).then(response => {
+ this.hospitalOutResults = response.data || []
+ this.showHospitalOutResults = true
+ }).catch(error => {
+ console.error('鎼滅储鍖婚櫌澶辫触:', error)
+ this.hospitalOutResults = []
+ })
+ },
+
+ // 閫夋嫨杞嚭鍖婚櫌
+ selectHospitalOut(hospital) {
+ this.taskForm.hospitalOut.name = hospital.hospName
+ this.taskForm.hospitalOut.address = hospital.hospAddress
+ this.hospitalOutSearchKeyword = hospital.hospName
+ this.showHospitalOutResults = false
+ this.hospitalOutResults = []
+
+ // 濡傛灉鏈塆PS鍧愭爣锛屼繚瀛樹笅鏉�
+ // 娉ㄦ剰锛欻ospData琛ㄤ腑鍙兘娌℃湁GPS鍧愭爣锛岄渶瑕佹牴鎹湴鍧�杩涜鍦扮悊缂栫爜
+ // 杩欓噷鍏堢疆涓簄ull锛屽悗缁彲浠ラ�氳繃鍦板潃瑙f瀽鑾峰彇
+ this.addressCoordinates.hospitalOutAddress = null
+
+ // 濡傛灉涓や釜鍖婚櫌閮藉凡閫夋嫨锛岃嚜鍔ㄨ绠楄窛绂�
+ if (this.taskForm.hospitalIn.address) {
+ // 杩欓噷鍙互璋冪敤鍦板潃瑙f瀽鍜岃窛绂昏绠�
+ // 鏆傛椂鐣欑┖锛岀敱鐢ㄦ埛鎵嬪姩杈撳叆璺濈
+ }
+ },
+
+ // 杞叆鍖婚櫌鎼滅储
+ onHospitalInSearch(e) {
+ const keyword = e.detail.value
+ this.hospitalInSearchKeyword = keyword
+
+ // 闃叉姈澶勭悊
+ if (this.searchTimer) {
+ clearTimeout(this.searchTimer)
+ }
+
+ if (!keyword || keyword.trim() === '') {
+ this.hospitalInResults = []
+ return
+ }
+
+ this.searchTimer = setTimeout(() => {
+ this.searchHospitalIn(keyword)
+ }, 300)
+ },
+
+ // 鎼滅储杞叆鍖婚櫌
+ searchHospitalIn(keyword) {
+ searchHospitals(keyword).then(response => {
+ this.hospitalInResults = response.data || []
+ this.showHospitalInResults = true
+ }).catch(error => {
+ console.error('鎼滅储鍖婚櫌澶辫触:', error)
+ this.hospitalInResults = []
+ })
+ },
+
+ // 閫夋嫨杞叆鍖婚櫌
+ selectHospitalIn(hospital) {
+ this.taskForm.hospitalIn.name = hospital.hospName
+ this.taskForm.hospitalIn.address = hospital.hospAddress
+ this.hospitalInSearchKeyword = hospital.hospName
+ this.showHospitalInResults = false
+ this.hospitalInResults = []
+
+ // 濡傛灉鏈塆PS鍧愭爣锛屼繚瀛樹笅鏉�
+ this.addressCoordinates.hospitalInAddress = null
+
+ // 濡傛灉涓や釜鍖婚櫌閮藉凡閫夋嫨锛岃嚜鍔ㄨ绠楄窛绂�
+ if (this.taskForm.hospitalOut.address) {
+ // 杩欓噷鍙互璋冪敤鍦板潃瑙f瀽鍜岃窛绂昏绠�
+ // 鏆傛椂鐣欑┖锛岀敱鐢ㄦ埛鎵嬪姩杈撳叆璺濈
+ }
+ },
+
+ // 鍒濆鍖栭�変腑鐨勪汉鍛橈紙榛樿鍖呭惈褰撳墠鐢ㄦ埛锛�
+ initSelectedStaff() {
+ this.selectedStaff = [{
+ userId: this.currentUser.userId,
+ nickName: this.currentUser.nickName,
+ phonenumber: this.currentUser.phonenumber,
+ postName: this.currentUser.position,
+ deptId: this.currentUser.deptId
+ }]
+ },
+
+ // 鍔犺浇褰撳墠鐢ㄦ埛鎵�鍦ㄥ垎鍏徃鐨勬墍鏈変汉鍛�
+ loadDeptStaff() {
+ const deptId = this.currentUser.deptId
+ if (!deptId) {
+ console.error('鏃犳硶鑾峰彇褰撳墠鐢ㄦ埛鎵�鍦ㄩ儴闂�')
+ return
+ }
+
+ // 鏌ヨ褰撳墠閮ㄩ棬涓嬬殑鎵�鏈夌敤鎴凤紙鍙告満銆佹姢澹級
+ const queryParams = {
+ deptId: deptId,
+ status: '0' // 鍙煡璇㈡甯哥姸鎬佺殑鐢ㄦ埛
+ }
+
+ listUser(queryParams).then(response => {
+ const userList = response.rows || response.data || []
+ this.allStaffList = userList.map(user => ({
+ userId: user.userId,
+ nickName: user.nickName,
+ phonenumber: user.phonenumber,
+ deptName: user.dept?.deptName || '',
+ postName: user.posts && user.posts.length > 0 ? user.posts[0].postName : '',
+ roleName: user.roles && user.roles.length > 0 ? user.roles[0].roleName : '',
+ // 鏍规嵁宀椾綅鍚嶇О鎴栬鑹插悕绉板垽鏂被鍨�
+ type: this.getUserType(user)
+ }))
+
+ // 鍒濆鍖栬繃婊ゅ垪琛�
+ this.filterStaffList()
+ }).catch(error => {
+ console.error('鍔犺浇浜哄憳鍒楄〃澶辫触:', error)
+ this.$modal.showToast('鍔犺浇浜哄憳鍒楄〃澶辫触')
+ })
+ },
+
+ // 鏍规嵁鐢ㄦ埛鐨勫矖浣嶆垨瑙掕壊鍒ゆ柇绫诲瀷
+ getUserType(user) {
+ const postName = user.posts && user.posts.length > 0 ? user.posts[0].postName : ''
+ const roleName = user.roles && user.roles.length > 0 ? user.roles[0].roleName : ''
+
+ // 鍒ゆ柇鏄惁涓哄徃鏈�
+ if (postName.includes('鍙告満') || roleName.includes('鍙告満')) {
+ return 'driver'
+ }
+ // 鍒ゆ柇鏄惁涓烘姢澹�
+ if (postName.includes('鎶ゅ+') || roleName.includes('鎶ゅ+')) {
+ return 'nurse'
+ }
+ // 鍏朵粬绫诲瀷
+ return 'other'
+ },
+
+ // 鏄剧ず浜哄憳閫夋嫨寮圭獥
+ showStaffSelector() {
+ this.$refs.staffPopup.open()
+ this.filterStaffList()
+ },
+
+ // 鍏抽棴浜哄憳閫夋嫨寮圭獥
+ closeStaffSelector() {
+ this.$refs.staffPopup.close()
+ this.staffSearchKeyword = ''
+ this.staffFilterType = 'all'
+ },
+
+ // 浜哄憳鎼滅储
+ onStaffSearch(e) {
+ this.staffSearchKeyword = e.detail.value
+ this.filterStaffList()
+ },
+
+ // 绛涢�変汉鍛樼被鍨�
+ filterStaff(type) {
+ this.staffFilterType = type
+ this.filterStaffList()
+ },
+
+ // 杩囨护浜哄憳鍒楄〃
+ filterStaffList() {
+ let list = [...this.allStaffList]
+
+ // 鎸夌被鍨嬭繃婊�
+ if (this.staffFilterType === 'driver') {
+ list = list.filter(staff => staff.type === 'driver')
+ } else if (this.staffFilterType === 'nurse') {
+ list = list.filter(staff => staff.type === 'nurse')
+ }
+
+ // 鎸夊叧閿瘝鎼滅储
+ if (this.staffSearchKeyword && this.staffSearchKeyword.trim() !== '') {
+ const keyword = this.staffSearchKeyword.trim().toLowerCase()
+ list = list.filter(staff => {
+ return staff.nickName.toLowerCase().includes(keyword) ||
+ (staff.phonenumber && staff.phonenumber.includes(keyword))
+ })
+ }
+
+ this.filteredStaffList = list
+ },
+
+ // 鍒囨崲浜哄憳閫変腑鐘舵��
+ toggleStaffSelection(staff) {
+ const index = this.selectedStaff.findIndex(s => s.userId === staff.userId)
+
+ if (index > -1) {
+ // 濡傛灉鏄涓�涓紙褰撳墠鐢ㄦ埛锛夛紝涓嶅厑璁哥Щ闄�
+ if (index === 0) {
+ this.$modal.showToast('褰撳墠鐢ㄦ埛涓嶈兘绉婚櫎')
+ return
+ }
+ // 宸查�変腑锛岀Щ闄�
+ this.selectedStaff.splice(index, 1)
+ } else {
+ // 鏈�変腑锛屾坊鍔�
+ this.selectedStaff.push(staff)
+ }
+ },
+
+ // 鍒ゆ柇浜哄憳鏄惁宸查�変腑
+ isStaffSelected(userId) {
+ return this.selectedStaff.some(staff => staff.userId === userId)
+ },
+
+ // 纭浜哄憳閫夋嫨
+ confirmStaffSelection() {
+ if (this.selectedStaff.length === 0) {
+ this.$modal.showToast('璇疯嚦灏戦�夋嫨涓�鍚嶄汉鍛�')
+ return
+ }
+ this.closeStaffSelector()
+ },
+
+ // 绉婚櫎浜哄憳
+ removeStaff(index) {
+ if (index === 0) {
+ this.$modal.showToast('褰撳墠鐢ㄦ埛涓嶈兘绉婚櫎')
+ return
+ }
+ this.selectedStaff.splice(index, 1)
+ },
+
+ addStaff() {
+ this.showStaffSelector()
+ },
+
+ // ==================== 鐥呮儏閫夋嫨鐩稿叧鏂规硶 ====================
+
+ // 鏄剧ず鐥呮儏閫夋嫨寮圭獥
+ showDiseaseSelector() {
+ // 鍒濆鍖栦复鏃堕�夋嫨鍒楄〃锛堝鍒跺綋鍓嶅凡閫夋嫨鐨勭梾鎯咃級
+ this.tempSelectedDiseases = [...this.selectedDiseases]
+ this.diseaseSearchKeyword = ''
+ this.diseaseSearchResults = []
+ this.$refs.diseasePopup.open()
+ },
+
+ // 鍏抽棴鐥呮儏閫夋嫨寮圭獥
+ closeDiseaseSelector() {
+ this.$refs.diseasePopup.close()
+ this.diseaseSearchKeyword = ''
+ this.diseaseSearchResults = []
+ this.tempSelectedDiseases = []
+ },
+
+ // 鐥呮儏鎼滅储
+ onDiseaseSearch(e) {
+ const keyword = e.detail.value
+ this.diseaseSearchKeyword = keyword
+
+ // 闃叉姈澶勭悊
+ if (this.diseaseSearchTimer) {
+ clearTimeout(this.diseaseSearchTimer)
+ }
+
+ if (!keyword || keyword.trim() === '') {
+ this.diseaseSearchResults = []
+ return
+ }
+
+ this.diseaseSearchTimer = setTimeout(() => {
+ this.searchDiseaseByKeyword(keyword)
+ }, 300)
+ },
+
+ // 鏍规嵁鍏抽敭璇嶆悳绱㈢梾鎯�
+ searchDiseaseByKeyword(keyword) {
+ searchIcd10(keyword).then(response => {
+ this.diseaseSearchResults = response.data || []
+ }).catch(error => {
+ console.error('鎼滅储鐥呮儏澶辫触:', error)
+ this.diseaseSearchResults = []
+ })
+ },
+
+ // 鍒囨崲鐥呮儏閫変腑鐘舵��
+ toggleDiseaseSelection(disease) {
+ const index = this.tempSelectedDiseases.findIndex(d => d.id === disease.id)
+
+ if (index > -1) {
+ // 宸查�変腑锛岀Щ闄�
+ this.tempSelectedDiseases.splice(index, 1)
+ } else {
+ // 鏈�変腑锛屾坊鍔�
+ this.tempSelectedDiseases.push({
+ id: disease.id,
+ icdCode: disease.icdCode,
+ icdName: disease.icdName,
+ sm: disease.sm
+ })
+ }
+ },
+
+ // 鍒ゆ柇鐥呮儏鏄惁宸查�変腑
+ isDiseaseSelected(diseaseId) {
+ return this.tempSelectedDiseases.some(d => d.id === diseaseId)
+ },
+
+ // 纭鐥呮儏閫夋嫨
+ confirmDiseaseSelection() {
+ // 灏嗕复鏃堕�夋嫨鐨勭梾鎯呭鍒跺埌姝e紡鍒楄〃
+ this.selectedDiseases = [...this.tempSelectedDiseases]
+ this.closeDiseaseSelector()
+ },
+
+ // 绉婚櫎鐥呮儏
+ removeDisease(index) {
+ this.selectedDiseases.splice(index, 1)
+ },
+
+ validateForm() {
+ if (!this.selectedVehicleId) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟杞﹁締')
+ return false
+ }
+
+ if (!this.taskForm.patient.name) {
+ this.$modal.showToast('璇疯緭鍏ユ偅鑰呭鍚�')
+ return false
+ }
+
+ if (!this.taskForm.patient.phone) {
+ this.$modal.showToast('璇疯緭鍏ユ偅鑰呰仈绯荤數璇�')
+ return false
+ }
+
+ if (!this.taskForm.hospitalOut.name) {
+ this.$modal.showToast('璇疯緭鍏ヨ浆鍑哄尰闄㈠悕绉�')
+ return false
+ }
+
+ if (!this.taskForm.hospitalIn.name) {
+ this.$modal.showToast('璇疯緭鍏ヨ浆鍏ュ尰闄㈠悕绉�')
+ return false
+ }
+
+ return true
+ },
+
+ buildSubmitData() {
+ // 鍚堝苟鐥呮儏淇℃伅锛氶�変腑鐨処CD-10鐤剧梾 + 鍏朵粬鎻忚堪
+ let conditionText = ''
+ if (this.selectedDiseases.length > 0) {
+ const diseaseNames = this.selectedDiseases.map(d => `${d.icdName}(${d.icdCode})`).join('銆�')
+ conditionText = diseaseNames
+ }
+ if (this.taskForm.patient.condition && this.taskForm.patient.condition.trim()) {
+ if (conditionText) {
+ conditionText += '\n鍏朵粬锛�' + this.taskForm.patient.condition
+ } else {
+ conditionText = this.taskForm.patient.condition
+ }
+ }
+
+ const submitData = {
+ taskType: 'EMERGENCY_TRANSFER',
+ vehicleIds: this.selectedVehicleId ? [this.selectedVehicleId] : [],
+ assigneeIds: this.selectedStaff.map(staff => staff.userId), // 娣诲姞鎵ц浜哄憳ID鍒楄〃
+ transferTime: this.taskForm.transferTime,
+ patient: {
+ ...this.taskForm.patient,
+ condition: conditionText, // 浣跨敤鍚堝苟鍚庣殑鐥呮儏淇℃伅
+ diseases: this.selectedDiseases.map(d => ({
+ icdId: d.id,
+ icdCode: d.icdCode,
+ icdName: d.icdName
+ }))
+ },
+ hospitalOut: this.taskForm.hospitalOut,
+ hospitalIn: this.taskForm.hospitalIn,
+ transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
+ price: this.taskForm.price ? parseFloat(this.taskForm.price) : null
+ }
+
+ if (this.addressCoordinates.hospitalOutAddress) {
+ if (!submitData.hospitalOut) submitData.hospitalOut = {}
+ submitData.hospitalOut.longitude = this.addressCoordinates.hospitalOutAddress.lng
+ submitData.hospitalOut.latitude = this.addressCoordinates.hospitalOutAddress.lat
+ }
+
+ if (this.addressCoordinates.hospitalInAddress) {
+ if (!submitData.hospitalIn) submitData.hospitalIn = {}
+ submitData.hospitalIn.longitude = this.addressCoordinates.hospitalInAddress.lng
+ submitData.hospitalIn.latitude = this.addressCoordinates.hospitalInAddress.lat
+ }
+
+ return submitData
+ },
+
+ submitTask() {
+ if (!this.validateForm()) {
+ return
+ }
+
+ this.$modal.confirm('纭畾瑕佷繚瀛樹换鍔″悧锛�').then(() => {
+ this.loading = true
+ const submitData = this.buildSubmitData()
+
+ addTask(submitData).then(response => {
+ this.loading = false
+ this.$modal.showToast('浠诲姟鍒涘缓鎴愬姛')
+ setTimeout(() => {
+ this.$tab.navigateTo('/pages/task/index')
+ }, 1500)
+ }).catch(error => {
+ this.loading = false
+ console.error('浠诲姟鍒涘缓澶辫触:', error)
+ this.$modal.showToast('浠诲姟鍒涘缓澶辫触锛岃閲嶈瘯')
+ })
+ }).catch(() => {})
+ },
+
+ goBack() {
+ uni.navigateBack()
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.create-emergency-task-container {
+ padding: 20rpx;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+
+ .form-header {
+ display: flex;
+ align-items: center;
+ padding: 20rpx 0;
+ margin-bottom: 30rpx;
+
+ .back-btn {
+ width: 60rpx;
+ height: 60rpx;
+ border-radius: 50%;
+ background-color: #f0f0f0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 20rpx;
+ }
+
+ .title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+
+ .form-section {
+ background-color: white;
+ border-radius: 15rpx;
+ padding: 30rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+
+ .form-section-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ margin: 40rpx 0 20rpx 0;
+ padding-bottom: 10rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ }
+
+ .form-item {
+ margin-bottom: 40rpx;
+
+ .form-label {
+ font-size: 28rpx;
+ margin-bottom: 15rpx;
+ color: #333;
+ }
+
+ .hospital-search-container {
+ position: relative;
+
+ .search-results {
+ position: absolute;
+ top: 75rpx;
+ left: 0;
+ right: 0;
+ max-height: 400rpx;
+ background-color: white;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+ z-index: 100;
+ overflow-y: auto;
+
+ .search-result-item {
+ padding: 20rpx 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ &:active {
+ background-color: #f5f5f5;
+ }
+
+ .hospital-name {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: bold;
+ margin-bottom: 8rpx;
+ }
+
+ .hospital-address {
+ font-size: 24rpx;
+ color: #999;
+ }
+ }
+ }
+ }
+
+ .form-input {
+ height: 70rpx;
+ padding: 0 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+
+ &.picker-input {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ &.disabled {
+ background-color: #f5f5f5;
+ color: #999;
+ }
+ }
+ }
+
+ .form-textarea {
+ width: 100%;
+ min-height: 150rpx;
+ padding: 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+ }
+
+ .disease-container {
+ .disease-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 15rpx;
+ margin-bottom: 20rpx;
+
+ .disease-tag {
+ display: flex;
+ align-items: center;
+ padding: 10rpx 20rpx;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ border-radius: 30rpx;
+
+ .disease-name {
+ font-size: 26rpx;
+ color: white;
+ margin-right: 10rpx;
+ }
+ }
+ }
+
+ .add-disease-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20rpx;
+ border: 1rpx dashed #007AFF;
+ border-radius: 10rpx;
+ color: #007AFF;
+ font-size: 28rpx;
+
+ text {
+ margin-left: 10rpx;
+ }
+ }
+ }
+
+ .radio-group {
+ display: flex;
+
+ .radio-item {
+ display: flex;
+ align-items: center;
+ margin-right: 30rpx;
+
+ radio {
+ margin-right: 10rpx;
+ }
+ }
+ }
+
+ .staff-list {
+ .staff-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20rpx;
+ background-color: #f9f9f9;
+ border-radius: 10rpx;
+ margin-bottom: 20rpx;
+
+ .staff-info {
+ flex: 1;
+ display: flex;
+ align-items: center;
+
+ .staff-name {
+ font-size: 28rpx;
+ color: #333;
+ margin-right: 10rpx;
+ }
+
+ .staff-role {
+ font-size: 24rpx;
+ color: #999;
+ }
+ }
+ }
+
+ .add-staff {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20rpx;
+ border: 1rpx dashed #007AFF;
+ border-radius: 10rpx;
+ color: #007AFF;
+ }
+ }
+ }
+
+ .form-actions {
+ margin-top: 50rpx;
+ text-align: center;
+
+ .submit-btn {
+ width: 80%;
+ height: 80rpx;
+ background-color: #007AFF;
+ color: white;
+ border-radius: 10rpx;
+ font-size: 32rpx;
+
+ &[disabled] {
+ background-color: #ccc;
+ color: #999;
+ }
+ }
+ }
+ }
+}
+
+// 浜哄憳閫夋嫨寮圭獥鏍峰紡
+.staff-selector-popup {
+ background-color: white;
+ border-radius: 20rpx 20rpx 0 0;
+ max-height: 80vh;
+ display: flex;
+ flex-direction: column;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ }
+
+ .popup-close {
+ padding: 10rpx;
+ }
+ }
+
+ .search-box {
+ display: flex;
+ align-items: center;
+ margin: 20rpx 30rpx;
+ padding: 15rpx 20rpx;
+ background-color: #f5f5f5;
+ border-radius: 10rpx;
+ flex-shrink: 0;
+
+ .search-input {
+ flex: 1;
+ margin-left: 10rpx;
+ font-size: 28rpx;
+ }
+ }
+
+ .staff-filter {
+ display: flex;
+ padding: 0 30rpx 20rpx;
+ gap: 20rpx;
+ flex-shrink: 0;
+
+ .filter-item {
+ flex: 1;
+ text-align: center;
+ padding: 15rpx 0;
+ background-color: #f5f5f5;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+ color: #666;
+
+ &.active {
+ background-color: #007AFF;
+ color: white;
+ }
+ }
+ }
+
+ .staff-list-popup {
+ flex: 1;
+ overflow-y: auto;
+ padding: 0 30rpx;
+
+ .staff-item-popup {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 25rpx 20rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ &:active {
+ background-color: #f5f5f5;
+ }
+
+ .staff-info {
+ flex: 1;
+
+ .staff-name-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 10rpx;
+
+ .staff-name {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #333;
+ margin-right: 20rpx;
+ }
+
+ .staff-phone {
+ font-size: 24rpx;
+ color: #999;
+ }
+ }
+
+ .staff-detail-row {
+ display: flex;
+ align-items: center;
+
+ .staff-dept {
+ font-size: 24rpx;
+ color: #666;
+ margin-right: 20rpx;
+ }
+
+ .staff-post {
+ font-size: 24rpx;
+ color: #007AFF;
+ }
+ }
+ }
+
+ .checkbox-empty {
+ width: 40rpx;
+ height: 40rpx;
+ border: 2rpx solid #ddd;
+ border-radius: 50%;
+ }
+ }
+
+ .no-data {
+ text-align: center;
+ padding: 100rpx 0;
+ color: #999;
+
+ text {
+ display: block;
+ margin-top: 20rpx;
+ font-size: 28rpx;
+ }
+ }
+ }
+
+ .popup-footer {
+ display: flex;
+ padding: 20rpx 30rpx;
+ border-top: 1rpx solid #f0f0f0;
+ gap: 20rpx;
+ flex-shrink: 0;
+
+ button {
+ flex: 1;
+ height: 80rpx;
+ border-radius: 10rpx;
+ font-size: 30rpx;
+ }
+
+ .cancel-btn {
+ background-color: #f5f5f5;
+ color: #666;
+ }
+
+ .confirm-btn {
+ background-color: #007AFF;
+ color: white;
+ }
+ }
+}
+
+// 鐥呮儏閫夋嫨寮圭獥鏍峰紡
+.disease-selector-popup {
+ background-color: white;
+ border-radius: 20rpx 20rpx 0 0;
+ max-height: 80vh;
+ display: flex;
+ flex-direction: column;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ flex-shrink: 0;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ }
+
+ .popup-close {
+ padding: 10rpx;
+ }
+ }
+
+ .search-box {
+ display: flex;
+ align-items: center;
+ margin: 20rpx 30rpx;
+ padding: 15rpx 20rpx;
+ background-color: #f5f5f5;
+ border-radius: 10rpx;
+ flex-shrink: 0;
+
+ .search-input {
+ flex: 1;
+ margin-left: 10rpx;
+ font-size: 28rpx;
+ }
+ }
+
+ .disease-list-popup {
+ flex: 1;
+ overflow-y: auto;
+ padding: 0 30rpx;
+
+ .disease-item-popup {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 25rpx 20rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ &:active {
+ background-color: #f5f5f5;
+ }
+
+ .disease-info {
+ flex: 1;
+
+ .disease-name-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 8rpx;
+
+ .disease-name {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #333;
+ margin-right: 15rpx;
+ }
+
+ .disease-code {
+ font-size: 24rpx;
+ color: #007AFF;
+ background-color: #e6f2ff;
+ padding: 4rpx 12rpx;
+ border-radius: 6rpx;
+ }
+ }
+
+ .disease-detail-row {
+ .disease-desc {
+ font-size: 24rpx;
+ color: #999;
+ line-height: 1.5;
+ }
+ }
+ }
+
+ .checkbox-empty {
+ width: 40rpx;
+ height: 40rpx;
+ border: 2rpx solid #ddd;
+ border-radius: 50%;
+ }
+ }
+
+ .no-data {
+ text-align: center;
+ padding: 100rpx 0;
+ color: #999;
+
+ text {
+ display: block;
+ margin-top: 20rpx;
+ font-size: 28rpx;
+ }
+ }
+ }
+
+ .popup-footer {
+ display: flex;
+ padding: 20rpx 30rpx;
+ border-top: 1rpx solid #f0f0f0;
+ gap: 20rpx;
+ flex-shrink: 0;
+
+ button {
+ flex: 1;
+ height: 80rpx;
+ border-radius: 10rpx;
+ font-size: 30rpx;
+ }
+
+ .cancel-btn {
+ background-color: #f5f5f5;
+ color: #666;
+ }
+
+ .confirm-btn {
+ background-color: #007AFF;
+ color: white;
+ }
+ }
+}
+</style>
diff --git a/app/pages/task/create-normal.vue b/app/pages/task/create-normal.vue
new file mode 100644
index 0000000..9fe739c
--- /dev/null
+++ b/app/pages/task/create-normal.vue
@@ -0,0 +1,595 @@
+<template>
+ <scroll-view class="create-normal-task-container" scroll-y="true">
+ <view class="form-header">
+ <view class="back-btn" @click="goBack">
+ <uni-icons type="arrowleft" size="20"></uni-icons>
+ </view>
+ <view class="title">鍒涘缓{{ categoryName }}浠诲姟</view>
+ </view>
+
+ <view class="form-section">
+ <view class="form-item">
+ <view class="form-label">浠诲姟杞﹁締</view>
+ <picker mode="selector" :range="vehicles" @change="onVehicleChange">
+ <view class="form-input picker-input">
+ {{ selectedVehicle || '璇烽�夋嫨浠诲姟杞﹁締' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">浠诲姟绫诲瀷</view>
+ <picker mode="selector" :range="taskTypeLabels" :value="getTaskTypeIndex()" @change="onTaskTypeChange">
+ <view class="form-input picker-input">
+ {{ selectedTaskTypeLabel || '璇烽�夋嫨浠诲姟绫诲瀷' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">浠诲姟鎻忚堪</view>
+ <textarea
+ class="form-textarea"
+ placeholder="璇疯緭鍏ヤ换鍔℃弿杩�"
+ v-model="taskForm.taskDescription"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">浠诲姟鍑哄彂鍦�</view>
+ <view class="form-input picker-input" @click="selectStartLocation">
+ {{ taskForm.startLocation || '璇烽�夋嫨浠诲姟鍑哄彂鍦�' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">浠诲姟鐩殑鍦�</view>
+ <view class="form-input picker-input" @click="selectEndLocation">
+ {{ taskForm.endLocation || '璇烽�夋嫨浠诲姟鐩殑鍦�' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">琛岄┒鍏噷鏁�</view>
+ <input
+ class="form-input"
+ type="digit"
+ placeholder="璇疯緭鍏ヨ椹跺叕閲屾暟"
+ v-model="taskForm.distance"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">璁″垝寮�濮嬫椂闂�</view>
+ <uni-datetime-picker
+ v-model="taskForm.plannedStartTime"
+ type="datetime"
+ :placeholder="'璇烽�夋嫨璁″垝寮�濮嬫椂闂�'"
+ class="form-input"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">璁″垝缁撴潫鏃堕棿</view>
+ <uni-datetime-picker
+ v-model="taskForm.plannedEndTime"
+ type="datetime"
+ :placeholder="'璇烽�夋嫨璁″垝缁撴潫鏃堕棿'"
+ class="form-input"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎵ц浜�</view>
+ <input
+ class="form-input"
+ :value="currentUser.name"
+ disabled
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">澶囨敞</view>
+ <textarea
+ class="form-textarea"
+ placeholder="璇疯緭鍏ュ娉ㄤ俊鎭紙鏈�澶�200瀛楋級"
+ v-model="taskForm.remark"
+ maxlength="200"
+ />
+ </view>
+
+ <view class="form-actions">
+ <button class="submit-btn" @click="submitTask" :disabled="loading">
+ {{ loading ? '淇濆瓨涓�...' : '淇濆瓨' }}
+ </button>
+ </view>
+ </view>
+
+ <!-- 鍦板浘閫夋嫨鍣ㄥ脊绐� -->
+ <uni-popup ref="mapPopup" type="bottom" :mask-click="false">
+ <view class="map-popup-container">
+ <view class="popup-header">
+ <view class="popup-title">閫夋嫨鍦板潃</view>
+ <view class="close-btn" @click="closeMapSelector">
+ <uni-icons type="closeempty" size="20" color="#999"></uni-icons>
+ </view>
+ </view>
+ <map-selector
+ :initial-address="getInitialAddress()"
+ @addressSelected="onAddressSelected"
+ ></map-selector>
+ </view>
+ </uni-popup>
+ </scroll-view>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
+import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
+import { getUserProfile } from "@/api/system/user"
+import { addTask } from "@/api/task"
+import { listAvailableVehicles } from "@/api/vehicle"
+import { calculateDistance } from "@/api/map"
+import { getDicts } from "@/api/dict"
+import MapSelector from '@/components/map-selector.vue'
+
+export default {
+ components: {
+ uniDatetimePicker,
+ uniPopup,
+ MapSelector
+ },
+ data() {
+ return {
+ categoryName: '',
+ categoryType: '',
+ defaultTaskType: '',
+ selectedVehicle: '',
+ selectedVehicleId: null,
+ selectedTaskType: '',
+ selectedTaskTypeLabel: '',
+ boundVehicle: '',
+ boundVehicleId: null,
+ taskTypeOptions: [],
+ taskTypeLabels: [],
+ mapSelectorType: '',
+ taskForm: {
+ taskDescription: '',
+ taskType: '',
+ vehicleId: null,
+ plannedStartTime: '',
+ plannedEndTime: '',
+ startLocation: '',
+ endLocation: '',
+ distance: '',
+ remark: ''
+ },
+ vehicles: [],
+ vehicleOptions: [],
+ loading: false,
+ addressCoordinates: {
+ startLocation: null,
+ endLocation: null
+ }
+ }
+ },
+ computed: {
+ ...mapState({
+ currentUser: state => ({
+ name: state.user.name || '寮犱笁',
+ position: '鍙告満',
+ deptId: state.user.deptId || 100
+ })
+ })
+ },
+ onLoad(options) {
+ // 鑾峰彇浠诲姟绫诲瀷淇℃伅
+ if (options.categoryName) {
+ this.categoryName = options.categoryName
+ }
+ if (options.categoryType) {
+ this.categoryType = options.categoryType
+ }
+ if (options.taskType) {
+ this.defaultTaskType = options.taskType
+ this.selectedTaskType = options.taskType
+ }
+
+ // 鍔犺浇鏁版嵁
+ this.loadTaskTypes().then(() => {
+ this.getAvailableVehicles().then(() => {
+ this.getUserBoundVehicle()
+ })
+ })
+ },
+ methods: {
+ // 鍔犺浇浠诲姟绫诲瀷瀛楀吀
+ loadTaskTypes() {
+ return getDicts('sys_task_type').then(response => {
+ const dictData = response.data || []
+ this.taskTypeOptions = dictData.map(item => ({
+ label: item.dictLabel,
+ value: item.dictValue
+ }))
+ this.taskTypeLabels = this.taskTypeOptions.map(item => item.label)
+
+ if (this.selectedTaskType) {
+ const taskTypeOption = this.taskTypeOptions.find(item => item.value === this.selectedTaskType)
+ if (taskTypeOption) {
+ this.selectedTaskTypeLabel = taskTypeOption.label
+ this.taskForm.taskType = taskTypeOption.value
+ }
+ }
+ }).catch(error => {
+ console.error('鍔犺浇浠诲姟绫诲瀷瀛楀吀澶辫触:', error)
+ this.taskTypeOptions = [
+ { label: '缁翠慨淇濆吇', value: 'MAINTENANCE' },
+ { label: '鍔犳补浠诲姟', value: 'FUEL' },
+ { label: '鍏朵粬', value: 'OTHER' }
+ ]
+ this.taskTypeLabels = this.taskTypeOptions.map(item => item.label)
+ })
+ },
+
+ // 鑾峰彇浠诲姟绫诲瀷鍦ㄥ垪琛ㄤ腑鐨勭储寮�
+ getTaskTypeIndex() {
+ if (!this.selectedTaskType) return -1
+ return this.taskTypeOptions.findIndex(item => item.value === this.selectedTaskType)
+ },
+
+ // 浠诲姟绫诲瀷閫夋嫨鍙樺寲
+ onTaskTypeChange(e) {
+ const index = e.detail.value
+ const selectedOption = this.taskTypeOptions[index]
+ if (selectedOption) {
+ this.selectedTaskType = selectedOption.value
+ this.selectedTaskTypeLabel = selectedOption.label
+ this.taskForm.taskType = selectedOption.value
+ }
+ },
+
+ // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ getUserBoundVehicle() {
+ getUserProfile().then(response => {
+ const userInfo = response.data || response
+ if (userInfo.boundVehicle) {
+ const boundVehicleNo = userInfo.boundVehicle.vehicleNumber
+ const boundVehicleId = userInfo.boundVehicle.vehicleId
+
+ const vehicleIndex = this.vehicleOptions.findIndex(v => v.id === boundVehicleId || v.name === boundVehicleNo)
+
+ if (vehicleIndex !== -1) {
+ this.boundVehicle = this.vehicleOptions[vehicleIndex].name
+ this.boundVehicleId = this.vehicleOptions[vehicleIndex].id
+ this.selectedVehicle = this.boundVehicle
+ this.selectedVehicleId = this.boundVehicleId
+ this.taskForm.vehicleId = this.boundVehicleId
+ }
+ }
+ }).catch(error => {
+ console.error('鑾峰彇鐢ㄦ埛缁戝畾杞﹁締淇℃伅澶辫触:', error)
+ })
+ },
+
+ // 鑾峰彇鍙敤杞﹁締鍒楄〃
+ getAvailableVehicles() {
+ const deptId = this.currentUser.deptId
+ return listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ status: vehicle.status
+ }))
+ this.vehicles = this.vehicleOptions.map(v => v.name)
+ }).catch(() => {
+ this.vehicles = []
+ })
+ },
+
+ onVehicleChange(e) {
+ const index = e.detail.value
+ this.selectedVehicle = this.vehicles[index]
+ this.selectedVehicleId = this.vehicleOptions[index]?.id
+ this.taskForm.vehicleId = this.selectedVehicleId
+ },
+
+ selectStartLocation() {
+ this.mapSelectorType = 'startLocation'
+ this.$refs.mapPopup.open()
+ },
+
+ selectEndLocation() {
+ this.mapSelectorType = 'endLocation'
+ this.$refs.mapPopup.open()
+ },
+
+ getInitialAddress() {
+ return this.mapSelectorType === 'startLocation' ? this.taskForm.startLocation : this.taskForm.endLocation
+ },
+
+ onAddressSelected(address) {
+ if (this.mapSelectorType === 'startLocation') {
+ this.taskForm.startLocation = address.title + ' - ' + address.address
+ this.addressCoordinates.startLocation = {
+ lat: address.lat,
+ lng: address.lng
+ }
+ } else if (this.mapSelectorType === 'endLocation') {
+ this.taskForm.endLocation = address.title + ' - ' + address.address
+ this.addressCoordinates.endLocation = {
+ lat: address.lat,
+ lng: address.lng
+ }
+ }
+
+ this.calculateDistance()
+ this.closeMapSelector()
+ },
+
+ calculateDistance() {
+ if (this.addressCoordinates.startLocation && this.addressCoordinates.endLocation) {
+ this.getDistanceBetweenPoints(
+ this.addressCoordinates.startLocation.lat,
+ this.addressCoordinates.startLocation.lng,
+ this.addressCoordinates.endLocation.lat,
+ this.addressCoordinates.endLocation.lng
+ ).then(distance => {
+ this.taskForm.distance = distance.toFixed(2)
+ }).catch(error => {
+ console.error('璺濈璁$畻澶辫触:', error)
+ })
+ }
+ },
+
+ getDistanceBetweenPoints(lat1, lng1, lat2, lng2) {
+ return new Promise((resolve, reject) => {
+ calculateDistance(lat1, lng1, lat2, lng2).then(response => {
+ if (response.code === 200) {
+ const responseData = typeof response.data === 'string' ? JSON.parse(response.data) : response.data
+ if (responseData && responseData.status === 0 && responseData.result && responseData.result.elements && responseData.result.elements.length > 0) {
+ const distanceInKm = responseData.result.elements[0].distance / 1000
+ resolve(distanceInKm)
+ } else {
+ reject(new Error('璺濈璁$畻鎺ュ彛杩斿洖鏁版嵁鏍煎紡涓嶆纭�'))
+ }
+ } else {
+ reject(new Error('璺濈璁$畻鎺ュ彛璋冪敤澶辫触'))
+ }
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ closeMapSelector() {
+ this.$refs.mapPopup.close()
+ this.mapSelectorType = ''
+ },
+
+ validateForm() {
+ if (!this.taskForm.vehicleId) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟杞﹁締')
+ return false
+ }
+
+ if (!this.taskForm.taskType) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟绫诲瀷')
+ return false
+ }
+
+ if (!this.taskForm.taskDescription) {
+ this.$modal.showToast('璇疯緭鍏ヤ换鍔℃弿杩�')
+ return false
+ }
+
+ if (!this.taskForm.startLocation) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟鍑哄彂鍦�')
+ return false
+ }
+
+ if (!this.taskForm.endLocation) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟鐩殑鍦�')
+ return false
+ }
+
+ if (!this.taskForm.plannedStartTime) {
+ this.$modal.showToast('璇烽�夋嫨寮�濮嬫椂闂�')
+ return false
+ }
+
+ if (!this.taskForm.plannedEndTime) {
+ this.$modal.showToast('璇烽�夋嫨缁撴潫鏃堕棿')
+ return false
+ }
+
+ return true
+ },
+
+ buildSubmitData() {
+ const submitData = {
+ taskDescription: this.taskForm.taskDescription,
+ taskType: this.taskForm.taskType,
+ vehicleIds: this.taskForm.vehicleId ? [this.taskForm.vehicleId] : [],
+ plannedStartTime: this.taskForm.plannedStartTime,
+ plannedEndTime: this.taskForm.plannedEndTime,
+ departureAddress: this.taskForm.startLocation,
+ destinationAddress: this.taskForm.endLocation,
+ estimatedDistance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
+ remark: this.taskForm.remark
+ }
+
+ if (this.addressCoordinates.startLocation) {
+ submitData.departureLongitude = this.addressCoordinates.startLocation.lng
+ submitData.departureLatitude = this.addressCoordinates.startLocation.lat
+ }
+
+ if (this.addressCoordinates.endLocation) {
+ submitData.destinationLongitude = this.addressCoordinates.endLocation.lng
+ submitData.destinationLatitude = this.addressCoordinates.endLocation.lat
+ }
+
+ return submitData
+ },
+
+ submitTask() {
+ if (!this.validateForm()) {
+ return
+ }
+
+ this.$modal.confirm('纭畾瑕佷繚瀛樹换鍔″悧锛�').then(() => {
+ this.loading = true
+ const submitData = this.buildSubmitData()
+
+ addTask(submitData).then(response => {
+ this.loading = false
+ this.$modal.showToast('浠诲姟鍒涘缓鎴愬姛')
+ setTimeout(() => {
+ this.$tab.navigateTo('/pages/task/index')
+ }, 1500)
+ }).catch(error => {
+ this.loading = false
+ console.error('浠诲姟鍒涘缓澶辫触:', error)
+ this.$modal.showToast('浠诲姟鍒涘缓澶辫触锛岃閲嶈瘯')
+ })
+ }).catch(() => {})
+ },
+
+ goBack() {
+ uni.navigateBack()
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.create-normal-task-container {
+ padding: 20rpx;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+
+ .form-header {
+ display: flex;
+ align-items: center;
+ padding: 20rpx 0;
+ margin-bottom: 30rpx;
+
+ .back-btn {
+ width: 60rpx;
+ height: 60rpx;
+ border-radius: 50%;
+ background-color: #f0f0f0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 20rpx;
+ }
+
+ .title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+
+ .form-section {
+ background-color: white;
+ border-radius: 15rpx;
+ padding: 30rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+
+ .form-item {
+ margin-bottom: 40rpx;
+
+ .form-label {
+ font-size: 28rpx;
+ margin-bottom: 15rpx;
+ color: #333;
+ }
+
+ .form-input {
+ height: 70rpx;
+ padding: 0 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+
+ &.picker-input {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ &[disabled] {
+ background-color: #f5f5f5;
+ color: #999;
+ }
+ }
+
+ .form-textarea {
+ width: 100%;
+ min-height: 150rpx;
+ padding: 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+ }
+ }
+
+ .form-actions {
+ margin-top: 50rpx;
+ text-align: center;
+
+ .submit-btn {
+ width: 80%;
+ height: 80rpx;
+ background-color: #007AFF;
+ color: white;
+ border-radius: 10rpx;
+ font-size: 32rpx;
+
+ &[disabled] {
+ background-color: #ccc;
+ color: #999;
+ }
+ }
+ }
+ }
+
+ .map-popup-container {
+ height: 80vh;
+ background-color: white;
+ border-top-left-radius: 20rpx;
+ border-top-right-radius: 20rpx;
+ overflow: hidden;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20rpx 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ }
+
+ .close-btn {
+ width: 50rpx;
+ height: 50rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }
+ }
+}
+</style>
diff --git a/app/pages/task/create-welfare.vue b/app/pages/task/create-welfare.vue
new file mode 100644
index 0000000..b90c6d6
--- /dev/null
+++ b/app/pages/task/create-welfare.vue
@@ -0,0 +1,546 @@
+<template>
+ <scroll-view class="create-welfare-task-container" scroll-y="true">
+ <view class="form-header">
+ <view class="back-btn" @click="goBack">
+ <uni-icons type="arrowleft" size="20"></uni-icons>
+ </view>
+ <view class="title">鍒涘缓绂忕杞︿换鍔�</view>
+ </view>
+
+ <view class="form-section">
+ <view class="form-item">
+ <view class="form-label">浠诲姟杞﹁締</view>
+ <picker mode="selector" :range="vehicles" @change="onVehicleChange">
+ <view class="form-input picker-input">
+ {{ selectedVehicle || '璇烽�夋嫨浠诲姟杞﹁締' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎵ц浠诲姟浜哄憳</view>
+ <view class="staff-list">
+ <view class="staff-item">
+ <text>{{ currentUser.name }} ({{ currentUser.position }})</text>
+ <uni-icons type="checkmarkempty" size="20" color="#007AFF"></uni-icons>
+ </view>
+ <view
+ class="staff-item"
+ v-for="(staff, index) in additionalStaff"
+ :key="index"
+ @click="removeStaff(index)"
+ >
+ <text>{{ staff.name }} ({{ staff.position }})</text>
+ <uni-icons type="closeempty" size="20" color="#ff4d4f"></uni-icons>
+ </view>
+ <view class="add-staff" @click="addStaff">
+ <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
+ <text>娣诲姞浜哄憳</text>
+ </view>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">褰掑睘鏈烘瀯</view>
+ <picker mode="selector" :range="organizations" @change="onOrganizationChange">
+ <view class="form-input picker-input">
+ {{ selectedOrganization || '璇烽�夋嫨褰掑睘鏈烘瀯' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鏈嶅姟鏃堕棿</view>
+ <uni-datetime-picker
+ v-model="taskForm.serviceTime"
+ type="datetime"
+ :placeholder="'璇烽�夋嫨鏈嶅姟鏃堕棿'"
+ class="form-input"
+ />
+ </view>
+
+ <view class="form-section-title">涔樺淇℃伅</view>
+ <view class="form-item">
+ <view class="form-label">鑱旂郴浜�</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ヨ仈绯讳汉"
+ v-model="taskForm.passenger.contact"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鑱旂郴鐢佃瘽</view>
+ <input
+ class="form-input"
+ type="number"
+ placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
+ v-model="taskForm.passenger.phone"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鍑哄彂鍦板潃</view>
+ <view class="form-input picker-input" @click="selectStartAddress">
+ {{ taskForm.startAddress || '璇烽�夋嫨鍑哄彂鍦板潃' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鐩殑鍦板潃</view>
+ <view class="form-input picker-input" @click="selectEndAddress">
+ {{ taskForm.endAddress || '璇烽�夋嫨鐩殑鍦板潃' }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鍏噷鏁�</view>
+ <input
+ class="form-input"
+ type="digit"
+ placeholder="璇疯緭鍏ュ叕閲屾暟"
+ v-model="taskForm.distance"
+ />
+ </view>
+
+ <view class="form-item">
+ <view class="form-label">鎴愪氦浠�</view>
+ <input
+ class="form-input"
+ type="digit"
+ placeholder="璇疯緭鍏ユ垚浜や环"
+ v-model="taskForm.price"
+ />
+ </view>
+
+ <view class="form-actions">
+ <button class="submit-btn" @click="submitTask" :disabled="loading">
+ {{ loading ? '淇濆瓨涓�...' : '淇濆瓨' }}
+ </button>
+ </view>
+ </view>
+
+ <!-- 鍦板浘閫夋嫨鍣ㄥ脊绐� -->
+ <uni-popup ref="mapPopup" type="bottom" :mask-click="false">
+ <view class="map-popup-container">
+ <view class="popup-header">
+ <view class="popup-title">閫夋嫨鍦板潃</view>
+ <view class="close-btn" @click="closeMapSelector">
+ <uni-icons type="closeempty" size="20" color="#999"></uni-icons>
+ </view>
+ </view>
+ <map-selector
+ :initial-address="getInitialAddress()"
+ @addressSelected="onAddressSelected"
+ ></map-selector>
+ </view>
+ </uni-popup>
+ </scroll-view>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
+import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
+import { addTask } from "@/api/task"
+import { listAvailableVehicles } from "@/api/vehicle"
+import { calculateDistance } from "@/api/map"
+import MapSelector from '@/components/map-selector.vue'
+
+export default {
+ components: {
+ uniDatetimePicker,
+ uniPopup,
+ MapSelector
+ },
+ data() {
+ return {
+ selectedVehicle: '',
+ selectedVehicleId: null,
+ selectedOrganization: '',
+ mapSelectorType: '',
+ taskForm: {
+ serviceTime: '',
+ passenger: {
+ contact: '',
+ phone: ''
+ },
+ startAddress: '',
+ endAddress: '',
+ distance: '',
+ price: ''
+ },
+ vehicles: [],
+ vehicleOptions: [],
+ organizations: ['骞垮窞鍒嗗叕鍙�', '娣卞湷鍒嗗叕鍙�', '鐝犳捣鍒嗗叕鍙�', '浣涘北鍒嗗叕鍙�'],
+ additionalStaff: [],
+ loading: false,
+ addressCoordinates: {
+ startAddress: null,
+ endAddress: null
+ }
+ }
+ },
+ computed: {
+ ...mapState({
+ currentUser: state => ({
+ name: state.user.name || '寮犱笁',
+ position: '鍙告満',
+ deptId: state.user.deptId || 100
+ })
+ })
+ },
+ onLoad(options) {
+ this.getAvailableVehicles()
+ },
+ methods: {
+ getAvailableVehicles() {
+ const deptId = this.currentUser.deptId
+ return listAvailableVehicles(deptId, 'WELFARE').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ status: vehicle.status
+ }))
+ this.vehicles = this.vehicleOptions.map(v => v.name)
+ }).catch(() => {
+ this.vehicles = []
+ })
+ },
+
+ onVehicleChange(e) {
+ const index = e.detail.value
+ this.selectedVehicle = this.vehicles[index]
+ this.selectedVehicleId = this.vehicleOptions[index]?.id
+ },
+
+ onOrganizationChange(e) {
+ this.selectedOrganization = this.organizations[e.detail.value]
+ },
+
+ selectStartAddress() {
+ this.mapSelectorType = 'startAddress'
+ this.$refs.mapPopup.open()
+ },
+
+ selectEndAddress() {
+ this.mapSelectorType = 'endAddress'
+ this.$refs.mapPopup.open()
+ },
+
+ getInitialAddress() {
+ return this.mapSelectorType === 'startAddress'
+ ? this.taskForm.startAddress
+ : this.taskForm.endAddress
+ },
+
+ onAddressSelected(address) {
+ if (this.mapSelectorType === 'startAddress') {
+ this.taskForm.startAddress = address.title + ' - ' + address.address
+ this.addressCoordinates.startAddress = {
+ lat: address.lat,
+ lng: address.lng
+ }
+ } else if (this.mapSelectorType === 'endAddress') {
+ this.taskForm.endAddress = address.title + ' - ' + address.address
+ this.addressCoordinates.endAddress = {
+ lat: address.lat,
+ lng: address.lng
+ }
+ }
+
+ this.calculateWelfareDistance()
+ this.closeMapSelector()
+ },
+
+ calculateWelfareDistance() {
+ if (this.addressCoordinates.startAddress && this.addressCoordinates.endAddress) {
+ this.getDistanceBetweenPoints(
+ this.addressCoordinates.startAddress.lat,
+ this.addressCoordinates.startAddress.lng,
+ this.addressCoordinates.endAddress.lat,
+ this.addressCoordinates.endAddress.lng
+ ).then(distance => {
+ this.taskForm.distance = distance.toFixed(2)
+ }).catch(error => {
+ console.error('璺濈璁$畻澶辫触:', error)
+ })
+ }
+ },
+
+ getDistanceBetweenPoints(lat1, lng1, lat2, lng2) {
+ return new Promise((resolve, reject) => {
+ calculateDistance(lat1, lng1, lat2, lng2).then(response => {
+ if (response.code === 200) {
+ const responseData = typeof response.data === 'string' ? JSON.parse(response.data) : response.data
+ if (responseData && responseData.status === 0 && responseData.result && responseData.result.elements && responseData.result.elements.length > 0) {
+ const distanceInKm = responseData.result.elements[0].distance / 1000
+ resolve(distanceInKm)
+ } else {
+ reject(new Error('璺濈璁$畻鎺ュ彛杩斿洖鏁版嵁鏍煎紡涓嶆纭�'))
+ }
+ } else {
+ reject(new Error('璺濈璁$畻鎺ュ彛璋冪敤澶辫触'))
+ }
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ closeMapSelector() {
+ this.$refs.mapPopup.close()
+ this.mapSelectorType = ''
+ },
+
+ addStaff() {
+ this.$modal.showToast('娣诲姞浜哄憳鍔熻兘寮�鍙戜腑')
+ },
+
+ removeStaff(index) {
+ this.additionalStaff.splice(index, 1)
+ },
+
+ validateForm() {
+ if (!this.selectedVehicleId) {
+ this.$modal.showToast('璇烽�夋嫨浠诲姟杞﹁締')
+ return false
+ }
+
+ if (!this.taskForm.passenger.contact) {
+ this.$modal.showToast('璇疯緭鍏ヨ仈绯讳汉')
+ return false
+ }
+
+ if (!this.taskForm.passenger.phone) {
+ this.$modal.showToast('璇疯緭鍏ヨ仈绯荤數璇�')
+ return false
+ }
+
+ if (!this.taskForm.startAddress) {
+ this.$modal.showToast('璇烽�夋嫨鍑哄彂鍦板潃')
+ return false
+ }
+
+ if (!this.taskForm.endAddress) {
+ this.$modal.showToast('璇烽�夋嫨鐩殑鍦板潃')
+ return false
+ }
+
+ return true
+ },
+
+ buildSubmitData() {
+ const submitData = {
+ taskType: 'WELFARE',
+ vehicleIds: this.selectedVehicleId ? [this.selectedVehicleId] : [],
+ serviceTime: this.taskForm.serviceTime,
+ passenger: this.taskForm.passenger,
+ startAddress: this.taskForm.startAddress,
+ endAddress: this.taskForm.endAddress,
+ distance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
+ price: this.taskForm.price ? parseFloat(this.taskForm.price) : null
+ }
+
+ if (this.addressCoordinates.startAddress) {
+ submitData.departureLongitude = this.addressCoordinates.startAddress.lng
+ submitData.departureLatitude = this.addressCoordinates.startAddress.lat
+ }
+
+ if (this.addressCoordinates.endAddress) {
+ submitData.destinationLongitude = this.addressCoordinates.endAddress.lng
+ submitData.destinationLatitude = this.addressCoordinates.endAddress.lat
+ }
+
+ return submitData
+ },
+
+ submitTask() {
+ if (!this.validateForm()) {
+ return
+ }
+
+ this.$modal.confirm('纭畾瑕佷繚瀛樹换鍔″悧锛�').then(() => {
+ this.loading = true
+ const submitData = this.buildSubmitData()
+
+ addTask(submitData).then(response => {
+ this.loading = false
+ this.$modal.showToast('浠诲姟鍒涘缓鎴愬姛')
+ setTimeout(() => {
+ // 鍏抽棴褰撳墠椤甸潰锛岃烦杞埌浠诲姟鍒楄〃
+ uni.redirectTo({
+ url: '/pages/task/index'
+ })
+ }, 1500)
+ }).catch(error => {
+ this.loading = false
+ console.error('浠诲姟鍒涘缓澶辫触:', error)
+ this.$modal.showToast('浠诲姟鍒涘缓澶辫触锛岃閲嶈瘯')
+ })
+ }).catch(() => {})
+ },
+
+ goBack() {
+ uni.navigateBack()
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.create-welfare-task-container {
+ padding: 20rpx;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+
+ .form-header {
+ display: flex;
+ align-items: center;
+ padding: 20rpx 0;
+ margin-bottom: 30rpx;
+
+ .back-btn {
+ width: 60rpx;
+ height: 60rpx;
+ border-radius: 50%;
+ background-color: #f0f0f0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 20rpx;
+ }
+
+ .title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+
+ .form-section {
+ background-color: white;
+ border-radius: 15rpx;
+ padding: 30rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+
+ .form-section-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ margin: 40rpx 0 20rpx 0;
+ padding-bottom: 10rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ }
+
+ .form-item {
+ margin-bottom: 40rpx;
+
+ .form-label {
+ font-size: 28rpx;
+ margin-bottom: 15rpx;
+ color: #333;
+ }
+
+ .form-input {
+ height: 70rpx;
+ padding: 0 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+
+ &.picker-input {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+ }
+
+ .form-textarea {
+ width: 100%;
+ min-height: 150rpx;
+ padding: 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+ }
+
+ .staff-list {
+ .staff-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20rpx;
+ background-color: #f9f9f9;
+ border-radius: 10rpx;
+ margin-bottom: 20rpx;
+ }
+
+ .add-staff {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20rpx;
+ border: 1rpx dashed #007AFF;
+ border-radius: 10rpx;
+ color: #007AFF;
+ }
+ }
+ }
+
+ .form-actions {
+ margin-top: 50rpx;
+ text-align: center;
+
+ .submit-btn {
+ width: 80%;
+ height: 80rpx;
+ background-color: #007AFF;
+ color: white;
+ border-radius: 10rpx;
+ font-size: 32rpx;
+
+ &[disabled] {
+ background-color: #ccc;
+ color: #999;
+ }
+ }
+ }
+ }
+
+ .map-popup-container {
+ height: 80vh;
+ background-color: white;
+ border-top-left-radius: 20rpx;
+ border-top-right-radius: 20rpx;
+ overflow: hidden;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20rpx 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ }
+
+ .close-btn {
+ width: 50rpx;
+ height: 50rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }
+ }
+}
+</style>
diff --git a/app/pages/task/create.vue b/app/pages/task/create.vue
index 0970acd..a773b95 100644
--- a/app/pages/task/create.vue
+++ b/app/pages/task/create.vue
@@ -1,7 +1,6 @@
<template>
<scroll-view class="create-task-container" scroll-y="true">
- <!-- 浠诲姟绫诲瀷閫夋嫨鐣岄潰 -->
- <view v-if="!selectedTaskCategory" class="task-category-container">
+ <view class="task-category-container">
<view class="header">
<view class="title">閫夋嫨浠诲姟绫诲瀷</view>
<view class="subtitle">璇烽�夋嫨鎮ㄨ鍒涘缓鐨勪换鍔$被鍨�</view>
@@ -27,977 +26,122 @@
</view>
</view>
</view>
-
- <!-- 浠诲姟鍒涘缓琛ㄥ崟 -->
- <view v-else class="task-form-container">
- <view class="form-header">
- <view class="back-btn" @click="backToCategory">
- <uni-icons type="arrowleft" size="20"></uni-icons>
- </view>
- <view class="title">鍒涘缓{{ selectedTaskCategory.name }}浠诲姟</view>
- </view>
-
- <view class="form-section">
- <!-- 鏅�氫换鍔¤〃鍗� -->
- <view v-if="selectedTaskCategory.type === 'normal'">
- <view class="form-item">
- <view class="form-label">浠诲姟杞﹁締</view>
- <picker mode="selector" :range="vehicles" @change="onVehicleChange">
- <view class="form-input picker-input">
- {{ selectedVehicle || '璇烽�夋嫨浠诲姟杞﹁締' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- </view>
-
- <view class="form-item">
- <view class="form-label">浠诲姟绫诲瀷</view>
- <input
- class="form-input"
- :value="selectedTaskCategory.name"
- disabled
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">浠诲姟鎻忚堪</view>
- <textarea
- class="form-textarea"
- placeholder="璇疯緭鍏ヤ换鍔℃弿杩�"
- v-model="taskForm.description"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">浠诲姟鍑哄彂鍦�</view>
- <view class="form-input picker-input" @click="selectStartLocation">
- {{ taskForm.startLocation || '璇烽�夋嫨浠诲姟鍑哄彂鍦�' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">浠诲姟鐩殑鍦�</view>
- <view class="form-input picker-input" @click="selectEndLocation">
- {{ taskForm.endLocation || '璇烽�夋嫨浠诲姟鐩殑鍦�' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">琛岄┒鍏噷鏁�</view>
- <input
- class="form-input"
- type="digit"
- placeholder="璇疯緭鍏ヨ椹跺叕閲屾暟"
- v-model="taskForm.distance"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">寮�濮嬫椂闂�</view>
- <!-- 浣跨敤uni-datetime-picker缁勪欢 -->
- <uni-datetime-picker
- v-model="taskForm.startTime"
- type="datetime"
- :placeholder="'璇烽�夋嫨寮�濮嬫椂闂�'"
- class="form-input"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">缁撴潫鏃堕棿</view>
- <!-- 浣跨敤uni-datetime-picker缁勪欢 -->
- <uni-datetime-picker
- v-model="taskForm.endTime"
- type="datetime"
- :placeholder="'璇烽�夋嫨缁撴潫鏃堕棿'"
- class="form-input"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鎵ц浜�</view>
- <input
- class="form-input"
- :value="currentUser.name"
- disabled
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">澶囨敞</view>
- <textarea
- class="form-textarea"
- placeholder="璇疯緭鍏ュ娉ㄤ俊鎭紙鏈�澶�200瀛楋級"
- v-model="taskForm.remark"
- maxlength="200"
- />
- </view>
- </view>
-
- <!-- 鎬ユ晳杞繍浠诲姟琛ㄥ崟 -->
- <view v-else-if="selectedTaskCategory.type === 'emergency'">
- <view class="form-item">
- <view class="form-label">浠诲姟杞﹁締</view>
- <picker mode="selector" :range="vehicles" @change="onVehicleChange">
- <view class="form-input picker-input">
- {{ selectedVehicle || '璇烽�夋嫨浠诲姟杞﹁締' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- </view>
-
- <view class="form-item">
- <view class="form-label">鎵ц浠诲姟浜哄憳</view>
- <view class="staff-list">
- <view class="staff-item">
- <text>{{ currentUser.name }} ({{ currentUser.position }})</text>
- <uni-icons type="checkmarkempty" size="20" color="#007AFF"></uni-icons>
- </view>
- <view
- class="staff-item"
- v-for="(staff, index) in additionalStaff"
- :key="index"
- @click="removeStaff(index)"
- >
- <text>{{ staff.name }} ({{ staff.position }})</text>
- <uni-icons type="closeempty" size="20" color="#ff4d4f"></uni-icons>
- </view>
- <view class="add-staff" @click="addStaff">
- <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
- <text>娣诲姞浜哄憳</text>
- </view>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">褰掑睘鏈烘瀯</view>
- <picker mode="selector" :range="organizations" @change="onOrganizationChange">
- <view class="form-input picker-input">
- {{ selectedOrganization || '璇烽�夋嫨褰掑睘鏈烘瀯' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- </view>
-
- <view class="form-item">
- <view class="form-label">浠诲姟绫诲瀷</view>
- <picker mode="selector" :range="emergencyTaskTypes" @change="onEmergencyTaskTypeChange">
- <view class="form-input picker-input">
- {{ selectedEmergencyTaskType || '璇烽�夋嫨浠诲姟绫诲瀷' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- </view>
-
- <view class="form-item">
- <view class="form-label">杞繍鏃堕棿</view>
- <!-- 浣跨敤uni-datetime-picker缁勪欢 -->
- <uni-datetime-picker
- v-model="taskForm.transferTime"
- type="datetime"
- :placeholder="'璇烽�夋嫨杞繍鏃堕棿'"
- class="form-input"
- />
- </view>
-
- <view class="form-section-title">鎮h�呬俊鎭�</view>
- <view class="form-item">
- <view class="form-label">鑱旂郴浜�</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ヨ仈绯讳汉"
- v-model="taskForm.patient.contact"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鑱旂郴鐢佃瘽</view>
- <input
- class="form-input"
- type="number"
- placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
- v-model="taskForm.patient.phone"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鎮h�呭鍚�</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ユ偅鑰呭鍚�"
- v-model="taskForm.patient.name"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鎬у埆</view>
- <view class="radio-group">
- <label class="radio-item">
- <radio value="male" :checked="taskForm.patient.gender === 'male'" @click="taskForm.patient.gender = 'male'" />
- <text>鐢�</text>
- </label>
- <label class="radio-item">
- <radio value="female" :checked="taskForm.patient.gender === 'female'" @click="taskForm.patient.gender = 'female'" />
- <text>濂�</text>
- </label>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">鎮h�呰韩浠借瘉</view>
- <input
- class="form-input"
- type="idcard"
- placeholder="璇疯緭鍏ユ偅鑰呰韩浠借瘉鍙�"
- v-model="taskForm.patient.idCard"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鐥呮儏</view>
- <textarea
- class="form-textarea"
- placeholder="璇疯緭鍏ユ偅鑰呯梾鎯呮弿杩�"
- v-model="taskForm.patient.condition"
- />
- </view>
-
- <view class="form-section-title">杞嚭鍖婚櫌淇℃伅</view>
- <view class="form-item">
- <view class="form-label">鍖婚櫌鍚嶇О</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ヨ浆鍑哄尰闄㈠悕绉�"
- v-model="taskForm.hospitalOut.name"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">绉戝</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ョ瀹�"
- v-model="taskForm.hospitalOut.department"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">搴婂彿</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ュ簥鍙�"
- v-model="taskForm.hospitalOut.bedNumber"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">杞嚭鍦板潃</view>
- <view class="form-input picker-input" @click="selectHospitalOutAddress">
- {{ taskForm.hospitalOut.address || '璇烽�夋嫨杞嚭鍦板潃' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="form-section-title">杞叆鍖婚櫌淇℃伅</view>
- <view class="form-item">
- <view class="form-label">鍖婚櫌鍚嶇О</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ヨ浆鍏ュ尰闄㈠悕绉�"
- v-model="taskForm.hospitalIn.name"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">绉戝</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ョ瀹�"
- v-model="taskForm.hospitalIn.department"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">搴婂彿</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ュ簥鍙�"
- v-model="taskForm.hospitalIn.bedNumber"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">杞叆鍦板潃</view>
- <view class="form-input picker-input" @click="selectHospitalInAddress">
- {{ taskForm.hospitalIn.address || '璇烽�夋嫨杞叆鍦板潃' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">杞繍鍏噷鏁�</view>
- <input
- class="form-input"
- type="digit"
- placeholder="璇疯緭鍏ヨ浆杩愬叕閲屾暟"
- v-model="taskForm.transferDistance"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鎴愪氦浠�</view>
- <input
- class="form-input"
- type="digit"
- placeholder="璇疯緭鍏ユ垚浜や环"
- v-model="taskForm.price"
- />
- </view>
- </view>
-
- <!-- 绂忕杞︿换鍔¤〃鍗� -->
- <view v-else-if="selectedTaskCategory.type === 'welfare'">
- <view class="form-item">
- <view class="form-label">浠诲姟杞﹁締</view>
- <picker mode="selector" :range="vehicles" @change="onVehicleChange">
- <view class="form-input picker-input">
- {{ selectedVehicle || '璇烽�夋嫨浠诲姟杞﹁締' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- </view>
-
- <view class="form-item">
- <view class="form-label">鎵ц浠诲姟浜哄憳</view>
- <view class="staff-list">
- <view class="staff-item">
- <text>{{ currentUser.name }} ({{ currentUser.position }})</text>
- <uni-icons type="checkmarkempty" size="20" color="#007AFF"></uni-icons>
- </view>
- <view
- class="staff-item"
- v-for="(staff, index) in additionalStaff"
- :key="index"
- @click="removeStaff(index)"
- >
- <text>{{ staff.name }} ({{ staff.position }})</text>
- <uni-icons type="closeempty" size="20" color="#ff4d4f"></uni-icons>
- </view>
- <view class="add-staff" @click="addStaff">
- <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
- <text>娣诲姞浜哄憳</text>
- </view>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">褰掑睘鏈烘瀯</view>
- <picker mode="selector" :range="organizations" @change="onOrganizationChange">
- <view class="form-input picker-input">
- {{ selectedOrganization || '璇烽�夋嫨褰掑睘鏈烘瀯' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- </view>
-
- <view class="form-item">
- <view class="form-label">鏈嶅姟鏃堕棿</view>
- <!-- 浣跨敤uni-datetime-picker缁勪欢 -->
- <uni-datetime-picker
- v-model="taskForm.serviceTime"
- type="datetime"
- :placeholder="'璇烽�夋嫨鏈嶅姟鏃堕棿'"
- class="form-input"
- />
- </view>
-
- <view class="form-section-title">涔樺淇℃伅</view>
- <view class="form-item">
- <view class="form-label">鑱旂郴浜�</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ヨ仈绯讳汉"
- v-model="taskForm.passenger.contact"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鑱旂郴鐢佃瘽</view>
- <input
- class="form-input"
- type="number"
- placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
- v-model="taskForm.passenger.phone"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鍑哄彂鍦板潃</view>
- <view class="form-input picker-input" @click="selectStartAddress">
- {{ taskForm.startAddress || '璇烽�夋嫨鍑哄彂鍦板潃' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">鐩殑鍦板潃</view>
- <view class="form-input picker-input" @click="selectEndAddress">
- {{ taskForm.endAddress || '璇烽�夋嫨鐩殑鍦板潃' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="form-item">
- <view class="form-label">鍏噷鏁�</view>
- <input
- class="form-input"
- type="digit"
- placeholder="璇疯緭鍏ュ叕閲屾暟"
- v-model="taskForm.distance"
- />
- </view>
-
- <view class="form-item">
- <view class="form-label">鎴愪氦浠�</view>
- <input
- class="form-input"
- type="digit"
- placeholder="璇疯緭鍏ユ垚浜や环"
- v-model="taskForm.price"
- />
- </view>
- </view>
-
- <view class="form-actions">
- <button class="submit-btn" @click="submitTask">淇濆瓨</button>
- </view>
- </view>
- </view>
-
- <!-- 鍦板浘閫夋嫨鍣ㄥ脊绐� -->
- <uni-popup ref="mapPopup" type="bottom" :mask-click="false">
- <view class="map-popup-container">
- <view class="popup-header">
- <view class="popup-title">閫夋嫨鍦板潃</view>
- <view class="close-btn" @click="closeMapSelector">
- <uni-icons type="closeempty" size="20" color="#999"></uni-icons>
- </view>
- </view>
- <map-selector
- :initial-address="getInitialAddress()"
- @addressSelected="onAddressSelected"
- ></map-selector>
- </view>
- </uni-popup>
</scroll-view>
</template>
<script>
- import { mapState } from 'vuex'
- import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
- import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
- import { getUserProfile } from "@/api/system/user"
- import MapSelector from '@/components/map-selector.vue'
-
- export default {
- components: {
- uniDatetimePicker,
- uniPopup,
- MapSelector
- },
- data() {
- return {
- selectedTaskCategory: null,
- selectedVehicle: '',
- selectedOrganization: '',
- selectedEmergencyTaskType: '',
- boundVehicle: '', // 鐢ㄦ埛缁戝畾鐨勮溅杈�
- // 鍦板浘閫夋嫨鐩稿叧
- showMapSelector: false,
- mapSelectorType: '', // 鏍囪瘑褰撳墠閫夋嫨鐨勬槸鍝釜鍦板潃瀛楁
- taskForm: {
- description: '',
- startLocation: '',
- endLocation: '',
- distance: '',
- startTime: '',
- endTime: '',
- remark: '',
- transferTime: '',
- patient: {
- contact: '',
- phone: '',
- name: '',
- gender: 'male',
- idCard: '',
- condition: ''
- },
- hospitalOut: {
- name: '',
- department: '',
- bedNumber: '',
- address: ''
- },
- hospitalIn: {
- name: '',
- department: '',
- bedNumber: '',
- address: ''
- },
- transferDistance: '',
- price: '',
- serviceTime: '',
- passenger: {
- contact: '',
- phone: ''
- },
- startAddress: '',
- endAddress: ''
+export default {
+ data() {
+ return {
+ taskCategories: [
+ {
+ type: 'normal',
+ name: '缁翠慨淇濆吇',
+ icon: 'repair',
+ color: '#007AFF',
+ description: '璁惧缁翠慨銆佷繚鍏荤瓑鏃ュ父浠诲姟',
+ taskType: 'MAINTENANCE',
+ page: '/pages/task/create-normal'
},
- taskCategories: [
- {
- type: 'normal',
- name: '缁翠慨淇濆吇',
- icon: 'repair',
- color: '#007AFF',
- description: '璁惧缁翠慨銆佷繚鍏荤瓑鏃ュ父浠诲姟'
- },
- {
- type: 'normal',
- name: '鍔犳补',
- icon: 'fuel',
- color: '#1AAD19',
- description: '杞﹁締鍔犳补绛変换鍔�'
- },
- {
- type: 'emergency',
- name: '鎬ユ晳杞繍',
- icon: 'hospital',
- color: '#E54D42',
- description: '绱ф�ュ尰鐤楄浆杩愪换鍔�'
- },
- {
- type: 'welfare',
- name: '绂忕杞�',
- icon: 'car',
- color: '#F37B1D',
- description: '鑰佸勾浜恒�佹畫鐤句汉绛夌壒娈婄兢浣撶敤杞︽湇鍔�'
- }
- ],
- vehicles: ['绮12345', '绮67890', '绮11111', '绮22222', '绮33333'],
- organizations: ['骞垮窞鍒嗗叕鍙�', '娣卞湷鍒嗗叕鍙�', '鐝犳捣鍒嗗叕鍙�', '浣涘北鍒嗗叕鍙�'],
- emergencyTaskTypes: ['鎬ユ晳杞繍', '鑸┖杞繍'],
- additionalStaff: []
- }
- },
- computed: {
- ...mapState({
- currentUser: state => ({
- name: state.user.name || '寮犱笁',
- position: '鍙告満'
- })
+ {
+ type: 'normal',
+ name: '鍔犳补',
+ icon: 'fuel',
+ color: '#1AAD19',
+ description: '杞﹁締鍔犳补绛変换鍔�',
+ taskType: 'FUEL',
+ page: '/pages/task/create-normal'
+ },
+ {
+ type: 'emergency',
+ name: '鎬ユ晳杞繍',
+ icon: 'hospital',
+ color: '#E54D42',
+ description: '绱ф�ュ尰鐤楄浆杩愪换鍔�',
+ taskType: 'EMERGENCY_TRANSFER',
+ page: '/pages/task/create-emergency'
+ },
+ {
+ type: 'welfare',
+ name: '绂忕杞�',
+ icon: 'car',
+ color: '#F37B1D',
+ description: '鑰佸勾浜恒�佹畫鐤句汉绛夌壒娈婄兢浣撶敤杞︽湇鍔�',
+ taskType: 'WELFARE',
+ page: '/pages/task/create-welfare'
+ }
+ ]
+ }
+ },
+ methods: {
+ selectTaskCategory(category) {
+ // 璺宠浆鍒板搴旂殑浠诲姟鍒涘缓椤甸潰
+ uni.navigateTo({
+ url: `${category.page}?categoryName=${category.name}&categoryType=${category.type}&taskType=${category.taskType}`
})
- },
- onLoad() {
- // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
- this.getUserBoundVehicle()
- },
- methods: {
- // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
- getUserBoundVehicle() {
- getUserProfile().then(response => {
- // 杩欓噷妯℃嫙浠庣敤鎴蜂俊鎭腑鑾峰彇缁戝畾杞﹁締锛屽疄闄呴」鐩腑搴旇浠巖esponse.data涓幏鍙�
- // 鍋囪鐢ㄦ埛淇℃伅涓湁boundVehicle瀛楁
- this.boundVehicle = '绮12345' // 妯℃嫙鍊硷紝瀹為檯搴斾粠response.data.boundVehicle鑾峰彇
-
- // 濡傛灉鏈夌粦瀹氳溅杈嗭紝鍒欓粯璁ら�変腑
- if (this.boundVehicle) {
- this.selectedVehicle = this.boundVehicle
- }
- }).catch(() => {
- // 鑾峰彇鐢ㄦ埛淇℃伅澶辫触鏃朵娇鐢ㄩ粯璁ゅ��
- this.boundVehicle = ''
- })
- },
-
- selectTaskCategory(category) {
- this.selectedTaskCategory = category
- // 褰撻�夋嫨浠诲姟绫诲瀷鏃讹紝濡傛灉鏄櫘閫氫换鍔′笖鐢ㄦ埛鏈夌粦瀹氳溅杈嗭紝鍒欓粯璁ら�変腑缁戝畾杞﹁締
- if (category.type === 'normal' && this.boundVehicle) {
- this.selectedVehicle = this.boundVehicle
- }
- },
-
- backToCategory() {
- this.selectedTaskCategory = null
- },
-
- onVehicleChange(e) {
- this.selectedVehicle = this.vehicles[e.detail.value]
- },
-
- onOrganizationChange(e) {
- this.selectedOrganization = this.organizations[e.detail.value]
- },
-
- onEmergencyTaskTypeChange(e) {
- this.selectedEmergencyTaskType = this.emergencyTaskTypes[e.detail.value]
- },
-
- // 鏄剧ず鍦板浘閫夋嫨鍣� - 浠诲姟鍑哄彂鍦�
- selectStartLocation() {
- this.mapSelectorType = 'startLocation'
- this.$refs.mapPopup.open()
- },
-
- // 鏄剧ず鍦板浘閫夋嫨鍣� - 浠诲姟鐩殑鍦�
- selectEndLocation() {
- this.mapSelectorType = 'endLocation'
- this.$refs.mapPopup.open()
- },
-
- // 鏄剧ず鍦板浘閫夋嫨鍣� - 杞嚭鍖婚櫌鍦板潃
- selectHospitalOutAddress() {
- this.mapSelectorType = 'hospitalOutAddress'
- this.$refs.mapPopup.open()
- },
-
- // 鏄剧ず鍦板浘閫夋嫨鍣� - 杞叆鍖婚櫌鍦板潃
- selectHospitalInAddress() {
- this.mapSelectorType = 'hospitalInAddress'
- this.$refs.mapPopup.open()
- },
-
- // 鏄剧ず鍦板浘閫夋嫨鍣� - 绂忕杞﹀嚭鍙戝湴鍧�
- selectStartAddress() {
- this.mapSelectorType = 'startAddress'
- this.$refs.mapPopup.open()
- },
-
- // 鏄剧ず鍦板浘閫夋嫨鍣� - 绂忕杞︾洰鐨勫湴鍧�
- selectEndAddress() {
- this.mapSelectorType = 'endAddress'
- this.$refs.mapPopup.open()
- },
-
- // 鑾峰彇鍒濆鍦板潃鐢ㄤ簬鍦板浘鎼滅储
- getInitialAddress() {
- switch (this.mapSelectorType) {
- case 'startLocation':
- return this.taskForm.startLocation
- case 'endLocation':
- return this.taskForm.endLocation
- case 'hospitalOutAddress':
- return this.taskForm.hospitalOut.address
- case 'hospitalInAddress':
- return this.taskForm.hospitalIn.address
- case 'startAddress':
- return this.taskForm.startAddress
- case 'endAddress':
- return this.taskForm.endAddress
- default:
- return ''
- }
- },
-
- // 鍦板浘閫夋嫨鍣ㄥ湴鍧�閫夋嫨鍥炶皟
- onAddressSelected(address) {
- // 鏍规嵁涓嶅悓鐨勫湴鍧�绫诲瀷璁剧疆瀵瑰簲鐨勮〃鍗曞瓧娈�
- switch (this.mapSelectorType) {
- case 'startLocation':
- this.taskForm.startLocation = address.title + ' - ' + address.address
- break
- case 'endLocation':
- this.taskForm.endLocation = address.title + ' - ' + address.address
- break
- case 'hospitalOutAddress':
- this.taskForm.hospitalOut.address = address.title + ' - ' + address.address
- break
- case 'hospitalInAddress':
- this.taskForm.hospitalIn.address = address.title + ' - ' + address.address
- break
- case 'startAddress':
- this.taskForm.startAddress = address.title + ' - ' + address.address
- break
- case 'endAddress':
- this.taskForm.endAddress = address.title + ' - ' + address.address
- break
- }
-
- // 鍏抽棴鍦板浘閫夋嫨鍣�
- this.closeMapSelector()
- },
-
- // 鍏抽棴鍦板浘閫夋嫨鍣�
- closeMapSelector() {
- this.$refs.mapPopup.close()
- this.mapSelectorType = ''
- },
-
- addStaff() {
- this.$modal.showToast('娣诲姞浜哄憳鍔熻兘寮�鍙戜腑')
- },
-
- removeStaff(index) {
- this.additionalStaff.splice(index, 1)
- },
-
- submitTask() {
- this.$modal.confirm('纭畾瑕佷繚瀛樹换鍔″悧锛�').then(() => {
- this.$modal.showToast('浠诲姟淇濆瓨鎴愬姛')
- // 杩欓噷鍙互璋冪敤API淇濆瓨浠诲姟
- // 淇濆瓨鎴愬姛鍚庤烦杞埌浠诲姟鍒楄〃
- this.$tab.navigateTo('/pages/task/index')
- }).catch(() => {
- // 鍙栨秷鎿嶄綔
- })
- }
}
}
+}
</script>
<style lang="scss">
- .create-task-container {
- padding: 20rpx;
- background-color: #f5f5f5;
- min-height: 100vh;
- // 闅愯棌婊氬姩鏉′絾淇濇寔婊氬姩鍔熻兘
- ::-webkit-scrollbar {
- display: none;
- width: 0 !important;
- height: 0 !important;
- background: transparent;
- }
-
- // Firefox婊氬姩鏉¢殣钘�
- * {
- scrollbar-width: none; /* Firefox */
- }
-
- // IE/Edge婊氬姩鏉¢殣钘�
- * {
- -ms-overflow-style: none; /* IE 10+ */
- }
-
- .task-category-container {
- .header {
- text-align: center;
- padding: 40rpx 0;
-
- .title {
- font-size: 40rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 20rpx;
- }
-
- .subtitle {
- font-size: 28rpx;
- color: #666;
- }
+.create-task-container {
+ padding: 20rpx;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+
+ .task-category-container {
+ .header {
+ text-align: center;
+ padding: 40rpx 0;
+
+ .title {
+ font-size: 40rpx;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 20rpx;
}
- .category-list {
- .category-item {
- display: flex;
- align-items: center;
- background-color: white;
- border-radius: 15rpx;
- padding: 30rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
-
- .icon {
- margin-right: 20rpx;
- }
-
- .info {
- flex: 1;
-
- .name {
- font-size: 32rpx;
- font-weight: bold;
- margin-bottom: 10rpx;
- }
-
- .desc {
- font-size: 26rpx;
- color: #666;
- }
- }
-
- .arrow {
- margin-left: 20rpx;
- }
- }
+ .subtitle {
+ font-size: 28rpx;
+ color: #666;
}
}
- .task-form-container {
- .form-header {
+ .category-list {
+ .category-item {
display: flex;
align-items: center;
- padding: 20rpx 0;
- margin-bottom: 30rpx;
-
- .back-btn {
- width: 60rpx;
- height: 60rpx;
- border-radius: 50%;
- background-color: #f0f0f0;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 20rpx;
- }
-
- .title {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- }
- }
-
- .form-section {
background-color: white;
border-radius: 15rpx;
padding: 30rpx;
+ margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
- .form-section-title {
- font-size: 32rpx;
- font-weight: bold;
- margin: 40rpx 0 20rpx 0;
- padding-bottom: 10rpx;
- border-bottom: 1rpx solid #f0f0f0;
+ .icon {
+ margin-right: 20rpx;
}
- .form-item {
- margin-bottom: 40rpx;
+ .info {
+ flex: 1;
- &:last-child {
- margin-bottom: 0;
- }
-
- .form-label {
- font-size: 28rpx;
- margin-bottom: 15rpx;
- color: #333;
- }
-
- .form-input {
- height: 70rpx;
- padding: 0 20rpx;
- border: 1rpx solid #eee;
- border-radius: 10rpx;
- font-size: 28rpx;
-
- &.picker-input {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
-
- &[disabled] {
- background-color: #f5f5f5;
- color: #999;
- }
- }
-
- .form-textarea {
- width: 100%;
- min-height: 150rpx;
- padding: 20rpx;
- border: 1rpx solid #eee;
- border-radius: 10rpx;
- font-size: 28rpx;
- resize: none;
- }
-
- .radio-group {
- display: flex;
-
- .radio-item {
- display: flex;
- align-items: center;
- margin-right: 30rpx;
-
- radio {
- margin-right: 10rpx;
- }
- }
- }
-
- .staff-list {
- .staff-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20rpx;
- background-color: #f9f9f9;
- border-radius: 10rpx;
- margin-bottom: 20rpx;
- }
-
- .add-staff {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 20rpx;
- border: 1rpx dashed #007AFF;
- border-radius: 10rpx;
- color: #007AFF;
- }
- }
- }
-
- .form-actions {
- margin-top: 50rpx;
- text-align: center;
-
- .submit-btn {
- width: 80%;
- height: 80rpx;
- background-color: #007AFF;
- color: white;
- border-radius: 10rpx;
+ .name {
font-size: 32rpx;
+ font-weight: bold;
+ margin-bottom: 10rpx;
+ }
+
+ .desc {
+ font-size: 26rpx;
+ color: #666;
}
}
- }
- }
-
- // 鍦板浘閫夋嫨鍣ㄥ脊绐楁牱寮�
- .map-popup-container {
- height: 80vh;
- background-color: white;
- border-top-left-radius: 20rpx;
- border-top-right-radius: 20rpx;
- overflow: hidden;
-
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
- .popup-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
-
- .close-btn {
- width: 50rpx;
- height: 50rpx;
- display: flex;
- align-items: center;
- justify-content: center;
+ .arrow {
+ margin-left: 20rpx;
}
}
}
}
-</style>
\ No newline at end of file
+}
+</style>
diff --git a/app/pages/task/detail.vue b/app/pages/task/detail.vue
index e23ecff..425a13a 100644
--- a/app/pages/task/detail.vue
+++ b/app/pages/task/detail.vue
@@ -1,464 +1,547 @@
<template>
<view class="task-detail-container">
- <view class="task-header">
- <text class="task-title">{{ task.title }}</text>
- <view class="task-status" :class="'status-' + task.status">
- {{ getStatusText(task.status) }}
+ <view class="detail-header">
+ <view class="back-btn" @click="goBack">
+ <uni-icons type="arrowleft" size="20"></uni-icons>
</view>
+ <view class="title">浠诲姟璇︽儏</view>
</view>
- <!-- 鏅�氫换鍔¤鎯� -->
- <view class="task-info-section" v-if="isNormalTask">
- <view class="info-item">
- <view class="label">浠诲姟缂栧彿:</view>
- <view class="value">{{ task.taskNo }}</view>
+ <scroll-view class="detail-content" scroll-y="true" v-if="taskDetail">
+ <view class="detail-section">
+ <view class="section-title">鍩烘湰淇℃伅</view>
+ <view class="info-item">
+ <view class="label">浠诲姟缂栧彿</view>
+ <view class="value">{{ taskDetail.taskCode }}</view>
+ </view>
+ <view class="info-item">
+ <view class="label">浠诲姟绫诲瀷</view>
+ <view class="value">{{ getTaskTypeText(taskDetail.taskType) }}</view>
+ </view>
+ <view class="info-item">
+ <view class="label">浠诲姟鐘舵��</view>
+ <view class="value status" :class="taskDetail.taskStatus.toLowerCase()">
+ {{ getStatusText(taskDetail.taskStatus) }}
+ </view>
+ </view>
+ <view class="info-item">
+ <view class="label">鎵ц杞﹁締</view>
+ <view class="value">{{ getVehicleInfo(taskDetail) }}</view>
+ </view>
+ <view class="info-item">
+ <view class="label">鎵ц浜哄憳</view>
+ <view class="value">{{ taskDetail.assigneeName || '鏈垎閰�' }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">浠诲姟绫诲瀷:</view>
- <view class="value">{{ getTaskTypeText(task.type) }}</view>
+ <view class="detail-section">
+ <view class="section-title">鏃堕棿淇℃伅</view>
+ <view class="info-item">
+ <view class="label">璁″垝寮�濮嬫椂闂�</view>
+ <view class="value">{{ formatDateTime(taskDetail.plannedStartTime) }}</view>
+ </view>
+ <view class="info-item">
+ <view class="label">璁″垝缁撴潫鏃堕棿</view>
+ <view class="value">{{ formatDateTime(taskDetail.plannedEndTime) }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.actualStartTime">
+ <view class="label">瀹為檯寮�濮嬫椂闂�</view>
+ <view class="value">{{ formatDateTime(taskDetail.actualStartTime) }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.actualEndTime">
+ <view class="label">瀹為檯缁撴潫鏃堕棿</view>
+ <view class="value">{{ formatDateTime(taskDetail.actualEndTime) }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">杞﹁締淇℃伅:</view>
- <view class="value">{{ task.vehicle }}</view>
+ <view class="detail-section">
+ <view class="section-title">浣嶇疆淇℃伅</view>
+ <!-- 鎬ユ晳杞繍浠诲姟锛氭樉绀鸿浆鍑�/杞叆鍖婚櫌鍦板潃 -->
+ <template v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo">
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutAddress">
+ <view class="label">杞嚭鍖婚櫌</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalOutAddress }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInAddress">
+ <view class="label">杞叆鍖婚櫌</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalInAddress }}</view>
+ </view>
+ </template>
+ <!-- 绂忕杞︿换鍔★細鏄剧ず鎺ラ��/鐩殑鍦板潃 -->
+ <template v-else-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo">
+ <view class="info-item" v-if="taskDetail.welfareInfo.pickupAddress">
+ <view class="label">鎺ラ�佸湴鍧�</view>
+ <view class="value">{{ taskDetail.welfareInfo.pickupAddress }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.destinationAddress">
+ <view class="label">鐩殑鍦板潃</view>
+ <view class="value">{{ taskDetail.welfareInfo.destinationAddress }}</view>
+ </view>
+ </template>
+ <!-- 鍏朵粬浠诲姟绫诲瀷锛氭樉绀洪�氱敤鍦板潃 -->
+ <template v-else>
+ <view class="info-item">
+ <view class="label">鍑哄彂鍦�</view>
+ <view class="value">{{ getDepartureAddress(taskDetail) }}</view>
+ </view>
+ <view class="info-item">
+ <view class="label">鐩殑鍦�</view>
+ <view class="value">{{ getDestinationAddress(taskDetail) }}</view>
+ </view>
+ </template>
+ <!-- 璺濈淇℃伅锛氭牴鎹换鍔$被鍨嬫樉绀轰笉鍚屽瓧娈� -->
+ <view class="info-item" v-if="getDistanceInfo(taskDetail)">
+ <view class="label">璺濈</view>
+ <view class="value">{{ getDistanceInfo(taskDetail) }}鍏噷</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">鍑哄彂鍦�:</view>
- <view class="value">{{ task.startLocation }}</view>
+ <view class="detail-section" v-if="taskDetail.taskDescription">
+ <view class="section-title">浠诲姟鎻忚堪</view>
+ <view class="description">{{ taskDetail.taskDescription }}</view>
</view>
- <view class="info-item">
- <view class="label">鐩殑鍦�:</view>
- <view class="value">{{ task.endLocation }}</view>
+ <view class="detail-section" v-if="taskDetail.remark">
+ <view class="section-title">澶囨敞淇℃伅</view>
+ <view class="description">{{ taskDetail.remark }}</view>
</view>
- <view class="info-item">
- <view class="label">鍑哄彂鏃堕棿:</view>
- <view class="value">{{ task.startTime }}</view>
+ <!-- 鎬ユ晳杞繍浠诲姟鐗规湁淇℃伅 -->
+ <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo">
+ <view class="section-title">鎮h�呬俊鎭�</view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.patientName">
+ <view class="label">鎮h�呭鍚�</view>
+ <view class="value">{{ taskDetail.emergencyInfo.patientName }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.patientPhone">
+ <view class="label">鑱旂郴鐢佃瘽</view>
+ <view class="value">{{ taskDetail.emergencyInfo.patientPhone }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.patientGender">
+ <view class="label">鎬у埆</view>
+ <view class="value">{{ taskDetail.emergencyInfo.patientGender === 'male' ? '鐢�' : '濂�' }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.patientAge">
+ <view class="label">骞撮緞</view>
+ <view class="value">{{ taskDetail.emergencyInfo.patientAge }}宀�</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.patientIdCard">
+ <view class="label">韬唤璇佸彿</view>
+ <view class="value">{{ taskDetail.emergencyInfo.patientIdCard }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.patientCondition">
+ <view class="label">鐥呮儏鎻忚堪</view>
+ <view class="value">{{ taskDetail.emergencyInfo.patientCondition }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">鎵ц浜哄憳:</view>
- <view class="value">{{ task.assignee }}</view>
+ <!-- 鎬ユ晳杞繍 - 杞嚭鍖婚櫌淇℃伅 -->
+ <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo">
+ <view class="section-title">杞嚭鍖婚櫌淇℃伅</view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutName">
+ <view class="label">鍖婚櫌鍚嶇О</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalOutName }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutDepartment">
+ <view class="label">绉戝</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalOutDepartment }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutBedNumber">
+ <view class="label">搴婂彿</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalOutBedNumber }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutAddress">
+ <view class="label">鍖婚櫌鍦板潃</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalOutAddress }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">浠诲姟鎻忚堪:</view>
- <view class="value">{{ task.description || '鏃犳弿杩颁俊鎭�' }}</view>
+ <!-- 鎬ユ晳杞繍 - 杞叆鍖婚櫌淇℃伅 -->
+ <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo">
+ <view class="section-title">杞叆鍖婚櫌淇℃伅</view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInName">
+ <view class="label">鍖婚櫌鍚嶇О</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalInName }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInDepartment">
+ <view class="label">绉戝</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalInDepartment }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInBedNumber">
+ <view class="label">搴婂彿</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalInBedNumber }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInAddress">
+ <view class="label">鍖婚櫌鍦板潃</view>
+ <view class="value">{{ taskDetail.emergencyInfo.hospitalInAddress }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">琛岄┒鍏噷鏁�:</view>
- <view class="value">{{ task.distance || '鏈~鍐�' }}</view>
+ <!-- 鎬ユ晳杞繍 - 璐圭敤淇℃伅 -->
+ <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo">
+ <view class="section-title">璐圭敤淇℃伅</view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.transferDistance">
+ <view class="label">杞繍鍏噷鏁�</view>
+ <view class="value">{{ taskDetail.emergencyInfo.transferDistance }}鍏噷</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.emergencyInfo.transferPrice">
+ <view class="label">杞繍璐圭敤</view>
+ <view class="value">锟{ taskDetail.emergencyInfo.transferPrice }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">缁撴潫鏃堕棿:</view>
- <view class="value">{{ task.endTime || '鏈~鍐�' }}</view>
+ <!-- 绂忕杞︿换鍔$壒鏈変俊鎭� -->
+ <view class="detail-section" v-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo">
+ <view class="section-title">涔樺淇℃伅</view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.passengerContact">
+ <view class="label">鑱旂郴浜�</view>
+ <view class="value">{{ taskDetail.welfareInfo.passengerContact }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.passengerPhone">
+ <view class="label">鑱旂郴鐢佃瘽</view>
+ <view class="value">{{ taskDetail.welfareInfo.passengerPhone }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.passengerName">
+ <view class="label">涔樺濮撳悕</view>
+ <view class="value">{{ taskDetail.welfareInfo.passengerName }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.passengerAge">
+ <view class="label">骞撮緞</view>
+ <view class="value">{{ taskDetail.welfareInfo.passengerAge }}宀�</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.passengerGender">
+ <view class="label">鎬у埆</view>
+ <view class="value">{{ taskDetail.welfareInfo.passengerGender === 'male' ? '鐢�' : '濂�' }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.passengerIdCard">
+ <view class="label">韬唤璇佸彿</view>
+ <view class="value">{{ taskDetail.welfareInfo.passengerIdCard }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.specialNeeds">
+ <view class="label">鐗规畩闇�姹�</view>
+ <view class="value">{{ taskDetail.welfareInfo.specialNeeds }}</view>
+ </view>
</view>
- <view class="info-item">
- <view class="label">澶囨敞:</view>
- <view class="value">{{ task.remark || '鏃犲娉�' }}</view>
+ <!-- 绂忕杞� - 鏈嶅姟淇℃伅 -->
+ <view class="detail-section" v-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo">
+ <view class="section-title">鏈嶅姟淇℃伅</view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.serviceType">
+ <view class="label">鏈嶅姟绫诲瀷</view>
+ <view class="value">{{ taskDetail.welfareInfo.serviceType }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.pickupAddress">
+ <view class="label">鎺ラ�佸湴鍧�</view>
+ <view class="value">{{ taskDetail.welfareInfo.pickupAddress }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.destinationAddress">
+ <view class="label">鐩殑鍦板潃</view>
+ <view class="value">{{ taskDetail.welfareInfo.destinationAddress }}</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.serviceDistance">
+ <view class="label">鏈嶅姟鍏噷鏁�</view>
+ <view class="value">{{ taskDetail.welfareInfo.serviceDistance }}鍏噷</view>
+ </view>
+ <view class="info-item" v-if="taskDetail.welfareInfo.servicePrice">
+ <view class="label">鏈嶅姟璐圭敤</view>
+ <view class="value">锟{ taskDetail.welfareInfo.servicePrice }}</view>
+ </view>
</view>
+ </scroll-view>
+
+ <view class="loading" v-else>
+ <uni-icons type="spinner-cycle" size="40" color="#007AFF"></uni-icons>
+ <text>鍔犺浇涓�...</text>
</view>
- <!-- 鎬ユ晳杞繍浠诲姟璇︽儏 -->
- <view class="task-info-section" v-else-if="task.type === 'emergency'">
- <view class="info-item">
- <view class="label">浠诲姟缂栧彿:</view>
- <view class="value">{{ task.taskNo }}</view>
- </view>
+ <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+ <view class="action-buttons" v-if="taskDetail">
+ <!-- 寰呭鐞嗙姸鎬�: 鏄剧ず鍑哄彂銆佸彇娑� -->
+ <template v-if="taskDetail.taskStatus === 'PENDING'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction('depart')"
+ >
+ 鍑哄彂
+ </button>
+ <button
+ class="action-btn cancel"
+ @click="handleTaskAction('cancel')"
+ >
+ 鍙栨秷
+ </button>
+ </template>
- <view class="info-item">
- <view class="label">浠诲姟绫诲瀷:</view>
- <view class="value">{{ getTaskTypeText(task.type) }}</view>
- </view>
+ <!-- 鍑哄彂涓姸鎬�: 鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉� -->
+ <template v-else-if="taskDetail.taskStatus === 'DEPARTING'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction('arrive')"
+ >
+ 宸插埌杈�
+ </button>
+ <button
+ class="action-btn cancel"
+ @click="handleTaskAction('forceCancel')"
+ >
+ 寮哄埗缁撴潫
+ </button>
+ </template>
- <view class="info-item">
- <view class="label">杞﹁締淇℃伅:</view>
- <view class="value">{{ task.vehicle }}</view>
- </view>
+ <!-- 宸插埌杈剧姸鎬�: 鏄剧ず宸茶繑绋� -->
+ <template v-else-if="taskDetail.taskStatus === 'ARRIVED'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction('return')"
+ >
+ 宸茶繑绋�
+ </button>
+ </template>
- <view class="info-item">
- <view class="label">鎵ц浜哄憳:</view>
- <view class="value">{{ task.assignee }}</view>
- </view>
+ <!-- 杩旂▼涓姸鎬�: 鏄剧ず宸插畬鎴� -->
+ <template v-else-if="taskDetail.taskStatus === 'RETURNING'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction('complete')"
+ >
+ 宸插畬鎴�
+ </button>
+ </template>
- <view class="info-item">
- <view class="label">褰掑睘鏈烘瀯:</view>
- <view class="value">{{ task.organization || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">浠诲姟绫诲瀷:</view>
- <view class="value">{{ task.emergencyTaskType || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">杞繍鏃堕棿:</view>
- <view class="value">{{ task.transferTime || '鏈~鍐�' }}</view>
- </view>
-
- <view class="section-title">鎮h�呬俊鎭�</view>
- <view class="info-item">
- <view class="label">鑱旂郴浜�:</view>
- <view class="value">{{ task.patient.contact || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鑱旂郴鐢佃瘽:</view>
- <view class="value">{{ task.patient.phone || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鎮h�呭鍚�:</view>
- <view class="value">{{ task.patient.name || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鎬у埆:</view>
- <view class="value">{{ task.patient.gender === 'male' ? '鐢�' : '濂�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">韬唤璇�:</view>
- <view class="value">{{ task.patient.idCard || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鐥呮儏:</view>
- <view class="value">{{ task.patient.condition || '鏈~鍐�' }}</view>
- </view>
-
- <view class="section-title">杞嚭鍖婚櫌淇℃伅</view>
- <view class="info-item">
- <view class="label">鍖婚櫌鍚嶇О:</view>
- <view class="value">{{ task.hospitalOut.name || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">绉戝:</view>
- <view class="value">{{ task.hospitalOut.department || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">搴婂彿:</view>
- <view class="value">{{ task.hospitalOut.bedNumber || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鍦板潃:</view>
- <view class="value">{{ task.hospitalOut.address || '鏈~鍐�' }}</view>
- </view>
-
- <view class="section-title">杞叆鍖婚櫌淇℃伅</view>
- <view class="info-item">
- <view class="label">鍖婚櫌鍚嶇О:</view>
- <view class="value">{{ task.hospitalIn.name || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">绉戝:</view>
- <view class="value">{{ task.hospitalIn.department || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">搴婂彿:</view>
- <view class="value">{{ task.hospitalIn.bedNumber || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鍦板潃:</view>
- <view class="value">{{ task.hospitalIn.address || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">杞繍鍏噷鏁�:</view>
- <view class="value">{{ task.transferDistance || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鎴愪氦浠�:</view>
- <view class="value">楼{{ task.price || '鏈~鍐�' }}</view>
- </view>
- </view>
-
- <!-- 绂忕杞︿换鍔¤鎯� -->
- <view class="task-info-section" v-else-if="task.type === 'welfare'">
- <view class="info-item">
- <view class="label">浠诲姟缂栧彿:</view>
- <view class="value">{{ task.taskNo }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">浠诲姟绫诲瀷:</view>
- <view class="value">{{ getTaskTypeText(task.type) }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">杞﹁締淇℃伅:</view>
- <view class="value">{{ task.vehicle }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鎵ц浜哄憳:</view>
- <view class="value">{{ task.assignee }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">褰掑睘鏈烘瀯:</view>
- <view class="value">{{ task.organization || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鏈嶅姟鏃堕棿:</view>
- <view class="value">{{ task.serviceTime || '鏈~鍐�' }}</view>
- </view>
-
- <view class="section-title">涔樺淇℃伅</view>
- <view class="info-item">
- <view class="label">鑱旂郴浜�:</view>
- <view class="value">{{ task.passenger.contact || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鑱旂郴鐢佃瘽:</view>
- <view class="value">{{ task.passenger.phone || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鍑哄彂鍦板潃:</view>
- <view class="value">{{ task.startAddress || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鐩殑鍦板潃:</view>
- <view class="value">{{ task.endAddress || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鍏噷鏁�:</view>
- <view class="value">{{ task.distance || '鏈~鍐�' }}</view>
- </view>
-
- <view class="info-item">
- <view class="label">鎴愪氦浠�:</view>
- <view class="value">楼{{ task.price || '鏈~鍐�' }}</view>
- </view>
- </view>
-
- <!-- 浠诲姟鎿嶄綔鎸夐挳 (浠诲姟鏈畬鎴愭椂鏄剧ず) -->
- <view class="task-actions" v-if="task.status !== 'completed'">
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled('depart') }"
- @click="handleTaskAction('depart')"
- >
- 鍑哄彂
- </button>
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled('arrive') }"
- @click="handleTaskAction('arrive')"
- >
- 宸插埌杈�
- </button>
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled('return') }"
- @click="handleTaskAction('return')"
- >
- 杩旂▼
- </button>
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled('settle') }"
- @click="handleTaskAction('settle')"
- >
- 缁撶畻
- </button>
- <button
- class="action-btn primary"
- :class="{ disabled: isActionDisabled('complete') }"
- @click="handleTaskAction('complete')"
- >
- 宸插畬鎴�
- </button>
- </view>
-
- <view class="action-section">
- <button class="back-btn" @click="goBack">杩斿洖</button>
+ <!-- 宸插畬鎴�/宸插彇娑�: 涓嶆樉绀烘寜閽� -->
</view>
</view>
</template>
<script>
+ import { getTask, changeTaskStatus } from '@/api/task'
+
export default {
data() {
return {
- task: {
- id: 1,
- title: '绱ф�ョ淮淇换鍔�',
- type: 'maintenance',
- startLocation: '骞垮窞甯傚ぉ娌冲尯XX璺�123鍙�',
- endLocation: '骞垮窞甯傜櫧浜戝尯YY璺�456鍙�',
- startTime: '2023-05-15 15:00',
- assignee: '寮犱笁',
- status: 'pending',
- vehicle: '绮12345',
- taskNo: 'RW20230515001',
- description: '璁惧鏁呴殰锛岄渶瑕佺揣鎬ョ淮淇�',
- // 鏅�氫换鍔″瓧娈�
- distance: '25',
- endTime: '2023-05-15 17:00',
- remark: '缁翠慨瀹屾垚鍚庨渶瑕佹祴璇�',
- // 鎬ユ晳杞繍浠诲姟瀛楁
- organization: '骞垮窞鎬ユ晳涓績',
- emergencyTaskType: '鎬ユ晳杞繍',
- transferTime: '2023-05-15 16:00',
- patient: {
- contact: '鏉庡洓',
- phone: '13800138000',
- name: '鐜嬩簲',
- gender: 'male',
- idCard: '440100198001011234',
- condition: '绐佸彂蹇冭剰鐥�'
- },
- hospitalOut: {
- name: '骞垮窞甯傜涓�浜烘皯鍖婚櫌',
- department: '蹇冨唴绉�',
- bedNumber: '101',
- address: '骞垮窞甯傝秺绉�鍖哄尰闄㈣矾1鍙�'
- },
- hospitalIn: {
- name: '骞夸笢鐪佷汉姘戝尰闄�',
- department: '蹇冨唴绉�',
- bedNumber: '205',
- address: '骞垮窞甯傚ぉ娌冲尯鍖婚櫌璺�2鍙�'
- },
- transferDistance: '15',
- price: '800',
- // 绂忕杞︿换鍔″瓧娈�
- serviceTime: '2023-05-16 09:00',
- passenger: {
- contact: '璧靛叚',
- phone: '13900139000'
- },
- startAddress: '骞垮窞甯傝崝婀惧尯绀惧尯璺�10鍙�',
- endAddress: '骞垮窞甯傚ぉ娌冲尯鍏昏�侀櫌璺�20鍙�'
- }
- }
- },
- computed: {
- // 鍒ゆ柇鏄惁涓烘櫘閫氫换鍔�
- isNormalTask() {
- return this.task.type === 'maintenance' || this.task.type === 'refuel' || this.task.type === 'inspection';
+ taskDetail: null,
+ taskId: null
}
},
onLoad(options) {
- // 瀹為檯椤圭洰涓繖閲屼細閫氳繃API鑾峰彇浠诲姟璇︽儏
- // const taskId = options.id;
- // this.getTaskDetail(taskId);
+ this.taskId = options.id
+ this.loadTaskDetail()
},
methods: {
- goBack() {
- this.$tab.navigateBack();
+ // 鍔犺浇浠诲姟璇︽儏
+ loadTaskDetail() {
+ if (!this.taskId) {
+ this.$modal.showToast('浠诲姟ID涓嶈兘涓虹┖')
+ return
+ }
+
+ getTask(this.taskId).then(response => {
+ this.taskDetail = response.data || response
+ // 璋冭瘯锛氭墦鍗拌繑鍥炵殑鏁版嵁
+ console.log('浠诲姟璇︽儏鏁版嵁:', this.taskDetail)
+ console.log('鍑哄彂鍦板潃:', this.taskDetail.departureAddress)
+ console.log('鐩殑鍦板潃:', this.taskDetail.destinationAddress)
+ }).catch(error => {
+ console.error('鍔犺浇浠诲姟璇︽儏澶辫触:', error)
+ this.$modal.showToast('鍔犺浇浠诲姟璇︽儏澶辫触')
+ })
},
+ // 鑾峰彇杞﹁締淇℃伅
+ getVehicleInfo(task) {
+ if (task.assignedVehicles && task.assignedVehicles.length > 0) {
+ const firstVehicle = task.assignedVehicles[0]
+ let vehicleInfo = firstVehicle.vehicleNo || '鏈煡杞︾墝'
+ if (task.assignedVehicles.length > 1) {
+ vehicleInfo += ` 绛�${task.assignedVehicles.length}杈哷
+ }
+ return vehicleInfo
+ }
+ return '鏈垎閰嶈溅杈�'
+ },
+
+ // 鑾峰彇鍑哄彂鍦板潃
+ getDepartureAddress(task) {
+ // 浼樺厛浣跨敤departureAddress锛屽鏋滀负绌哄垯灏濊瘯鍏朵粬鍙兘鐨勫瓧娈�
+ return task.departureAddress || task.startAddress || task.startLocation || '鏈缃�'
+ },
+
+ // 鑾峰彇鐩殑鍦板潃
+ getDestinationAddress(task) {
+ // 浼樺厛浣跨敤destinationAddress锛屽鏋滀负绌哄垯灏濊瘯鍏朵粬鍙兘鐨勫瓧娈�
+ return task.destinationAddress || task.endAddress || task.endLocation || '鏈缃�'
+ },
+
+ // 鑾峰彇璺濈淇℃伅锛氭牴鎹换鍔$被鍨嬭繑鍥炰笉鍚屽瓧娈�
+ getDistanceInfo(task) {
+ // 鎬ユ晳杞繍锛氫紭鍏堜娇鐢╰ransferDistance
+ if (task.taskType === 'EMERGENCY_TRANSFER' && task.emergencyInfo && task.emergencyInfo.transferDistance) {
+ return task.emergencyInfo.transferDistance
+ }
+ // 绂忕杞︼細浼樺厛浣跨敤serviceDistance
+ if (task.taskType === 'WELFARE' && task.welfareInfo && task.welfareInfo.serviceDistance) {
+ return task.welfareInfo.serviceDistance
+ }
+ // 鍏朵粬浠诲姟绫诲瀷锛氫娇鐢╡stimatedDistance
+ return task.estimatedDistance || null
+ },
+
+ // 杩斿洖涓婁竴椤�
+ goBack() {
+ uni.navigateBack()
+ },
+
+ // 鏍煎紡鍖栨棩鏈熸椂闂�
+ formatDateTime(dateTime) {
+ if (!dateTime) return '鏈缃�'
+ const date = new Date(dateTime)
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ })
+ },
+
+ // 鑾峰彇鐘舵�佹枃鏈�
getStatusText(status) {
const statusMap = {
- 'pending': '寰呭鐞�',
- 'processing': '澶勭悊涓�',
- 'completed': '宸插畬鎴�'
+ 'PENDING': '寰呭鐞�',
+ 'DEPARTING': '鍑哄彂涓�',
+ 'ARRIVED': '宸插埌杈�',
+ 'RETURNING': '杩旂▼涓�',
+ 'COMPLETED': '宸插畬鎴�',
+ 'CANCELLED': '宸插彇娑�',
+ 'IN_PROGRESS': '澶勭悊涓�' // 鍏煎鏃ф暟鎹�
}
return statusMap[status] || '鏈煡'
},
+ // 鑾峰彇浠诲姟绫诲瀷鏂囨湰
getTaskTypeText(type) {
const typeMap = {
- 'maintenance': '缁翠慨淇濆吇',
- 'refuel': '鍔犳补',
- 'inspection': '宸℃',
- 'emergency': '鎬ユ晳杞繍',
- 'welfare': '绂忕杞�'
+ 'MAINTENANCE': '缁翠慨淇濆吇',
+ 'FUEL': '鍔犳补',
+ 'OTHER': '鍏朵粬',
+ 'EMERGENCY_TRANSFER': '鎬ユ晳杞繍',
+ 'WELFARE': '绂忕杞�'
}
return typeMap[type] || '鏈煡绫诲瀷'
},
- // 鍒ゆ柇鎿嶄綔鎸夐挳鏄惁绂佺敤
- isActionDisabled(action) {
- // 鏍规嵁浠诲姟鐘舵�佸拰鎿嶄綔绫诲瀷鍒ゆ柇鏄惁绂佺敤
- switch (action) {
- case 'depart':
- return this.task.status !== 'pending';
- case 'arrive':
- return this.task.status !== 'processing';
- case 'return':
- return this.task.status !== 'processing';
- case 'settle':
- return this.task.status !== 'processing';
- case 'complete':
- return this.task.status !== 'processing';
- default:
- return false;
- }
- },
-
// 澶勭悊浠诲姟鎿嶄綔
handleTaskAction(action) {
- if (this.isActionDisabled(action)) {
- return;
- }
-
switch (action) {
case 'depart':
- // 鍑哄彂鎿嶄綔锛屾牴鎹换鍔$被鍨嬫樉绀轰笉鍚岀殑纭淇℃伅
- let departMessage = '纭畾瑕佹爣璁颁负宸插嚭鍙戝悧锛�';
- if (this.task.type !== 'maintenance' && this.task.type !== 'refuel' && this.task.type !== 'inspection') {
- departMessage = '鍙戝嚭鍘荤洰鐨勫湴,纭锛�';
- }
- this.$modal.confirm(departMessage).then(() => {
- this.task.status = 'processing';
- this.$modal.showToast('宸插嚭鍙�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 鍑哄彂 -> 鐘舵�佸彉涓哄嚭鍙戜腑
+ this.$modal.confirm('纭畾瑕佸嚭鍙戝悧锛�').then(() => {
+ this.updateTaskStatus('DEPARTING', '浠诲姟宸插嚭鍙�')
}).catch(() => {});
break;
+
+ case 'cancel':
+ // 鍙栨秷 -> 浜屾纭鍚庣姸鎬佸彉涓哄凡鍙栨秷
+ this.$modal.confirm('纭畾瑕佸彇娑堟浠诲姟鍚楋紵').then(() => {
+ this.updateTaskStatus('CANCELLED', '浠诲姟宸插彇娑�')
+ }).catch(() => {});
+ break;
+
case 'arrive':
- // 宸插埌杈炬搷浣�
- this.$modal.confirm('宸茬粡鍒拌揪鐩殑鍦帮紝纭锛�').then(() => {
- this.$modal.showToast('宸插埌杈�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 宸插埌杈� -> 鐘舵�佸彉涓哄凡鍒拌揪
+ this.$modal.confirm('纭宸插埌杈剧洰鐨勫湴锛�').then(() => {
+ this.updateTaskStatus('ARRIVED', '宸插埌杈剧洰鐨勫湴')
}).catch(() => {});
break;
+
+ case 'forceCancel':
+ // 寮哄埗缁撴潫 -> 鐘舵�佸彉涓哄凡鍙栨秷
+ this.$modal.confirm('纭畾瑕佸己鍒剁粨鏉熸浠诲姟鍚楋紵').then(() => {
+ this.updateTaskStatus('CANCELLED', '浠诲姟宸插己鍒剁粨鏉�')
+ }).catch(() => {});
+ break;
+
case 'return':
- // 杩旂▼鎿嶄綔
- this.$modal.confirm('鐜板湪宸茬粡杩旂▼涓紝纭锛�').then(() => {
- this.$modal.showToast('杩旂▼涓�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 宸茶繑绋� -> 鐘舵�佸彉涓鸿繑绋嬩腑
+ this.$modal.confirm('纭寮�濮嬭繑绋嬶紵').then(() => {
+ this.updateTaskStatus('RETURNING', '宸插紑濮嬭繑绋�')
}).catch(() => {});
break;
- case 'settle':
- // 缁撶畻鎿嶄綔锛岃烦杞埌缁撶畻椤甸潰
- this.$tab.navigateTo(`/pages/task/settlement?id=${this.task.id}`);
- break;
+
case 'complete':
- // 宸插畬鎴愭搷浣�
- this.$modal.confirm('浠诲姟鏄惁宸茬粡鍏ㄩ儴瀹屾垚锛岀‘璁わ紵').then(() => {
- this.task.status = 'completed';
- this.$modal.showToast('浠诲姟宸插畬鎴�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 宸插畬鎴� -> 鐘舵�佸彉涓哄凡瀹屾垚
+ this.$modal.confirm('纭浠诲姟宸插畬鎴愶紵').then(() => {
+ this.updateTaskStatus('COMPLETED', '浠诲姟宸插畬鎴�')
}).catch(() => {});
break;
}
},
- // 妯℃嫙鑾峰彇浠诲姟璇︽儏
- getTaskDetail(taskId) {
- // 杩欓噷搴旇璋冪敤API鑾峰彇浠诲姟璇︽儏
- // 鏆傛椂浣跨敤妯℃嫙鏁版嵁
+ // 鏇存柊浠诲姟鐘舵��
+ updateTaskStatus(status, remark) {
+ // 鑾峰彇GPS浣嶇疆淇℃伅
+ this.getLocationAndUpdateStatus(status, remark)
+ },
+
+ // 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
+ getLocationAndUpdateStatus(status, remark) {
+ const that = this
+
+ // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
+ uni.getLocation({
+ type: 'gcj02', // 杩斿洖鍙互鐢ㄤ簬uni.openLocation鐨勫潗鏍�
+ geocode: true, // 瑙f瀽鍦板潃淇℃伅
+ altitude: true, // 楂樼簿搴﹀畾浣嶏紝鍖呭惈楂樺害淇℃伅
+ success: function(res) {
+ console.log('GPS瀹氫綅鎴愬姛:', res)
+
+ const statusData = {
+ taskStatus: status,
+ remark: remark,
+ // GPS浣嶇疆淇℃伅
+ 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(that.taskId, statusData).then(response => {
+ that.$modal.showToast('鐘舵�佹洿鏂版垚鍔�')
+ // 閲嶆柊鍔犺浇浠诲姟璇︽儏
+ that.loadTaskDetail()
+ }).catch(error => {
+ console.error('鏇存柊浠诲姟鐘舵�佸け璐�:', error)
+ that.$modal.showToast('鐘舵�佹洿鏂板け璐ワ紝璇烽噸璇�')
+ })
+ },
+ fail: function(err) {
+ console.error('GPS瀹氫綅澶辫触:', err)
+
+ // 瀹氫綅澶辫触鏃舵彁绀虹敤鎴凤紝浣嗕粛鐒跺厑璁告洿鏂扮姸鎬侊紙涓嶅甫GPS淇℃伅锛�
+ that.$modal.confirm('GPS瀹氫綅澶辫触锛屾槸鍚︾户缁洿鏂扮姸鎬侊紵').then(() => {
+ const statusData = {
+ taskStatus: status,
+ remark: remark
+ }
+
+ changeTaskStatus(that.taskId, statusData).then(response => {
+ that.$modal.showToast('鐘舵�佹洿鏂版垚鍔�')
+ that.loadTaskDetail()
+ }).catch(error => {
+ console.error('鏇存柊浠诲姟鐘舵�佸け璐�:', error)
+ that.$modal.showToast('鐘舵�佹洿鏂板け璐ワ紝璇烽噸璇�')
+ })
+ }).catch(() => {
+ // 鐢ㄦ埛鍙栨秷鎿嶄綔
+ })
+ }
+ })
}
}
}
@@ -466,135 +549,155 @@
<style lang="scss">
.task-detail-container {
- padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
- }
-
- .task-header {
- background-color: white;
- border-radius: 15rpx;
- padding: 30rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
- display: flex;
- justify-content: space-between;
- align-items: center;
- .task-title {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- }
-
- .task-status {
- padding: 10rpx 20rpx;
- border-radius: 10rpx;
- font-size: 24rpx;
- font-weight: bold;
-
- &.status-pending {
- background-color: #fff3cd;
- color: #856404;
- }
-
- &.status-processing {
- background-color: #cce5ff;
- color: #004085;
- }
-
- &.status-completed {
- background-color: #d4edda;
- color: #155724;
- }
- }
- }
-
- .task-info-section {
- background-color: white;
- border-radius: 15rpx;
- padding: 30rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
-
- .section-title {
- font-size: 32rpx;
- font-weight: bold;
- margin: 30rpx 0 20rpx 0;
- padding-bottom: 10rpx;
- border-bottom: 1rpx solid #f0f0f0;
- color: #333;
- }
-
- .info-item {
+ .detail-header {
display: flex;
- margin-bottom: 20rpx;
- padding-bottom: 20rpx;
+ align-items: center;
+ padding: 20rpx;
+ background-color: white;
border-bottom: 1rpx solid #f0f0f0;
- &:last-child {
- margin-bottom: 0;
- padding-bottom: 0;
- border-bottom: none;
- }
-
- .label {
- font-size: 28rpx;
- color: #666;
+ .back-btn {
+ width: 60rpx;
+ height: 60rpx;
+ border-radius: 50%;
+ background-color: #f0f0f0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
margin-right: 20rpx;
- white-space: nowrap;
- width: 150rpx;
}
- .value {
+ .title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+
+ .detail-content {
+ padding: 20rpx;
+ height: calc(100vh - 220rpx); // 鍑忓幓header(100rpx)鍜屾寜閽尯鍩�(120rpx)鐨勯珮搴�
+ padding-bottom: 20rpx; // 搴曢儴鐣欏嚭绌洪棿
+ }
+
+ .detail-section {
+ background-color: white;
+ border-radius: 15rpx;
+ padding: 30rpx;
+ margin-bottom: 20rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+
+ .section-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ margin-bottom: 20rpx;
+ color: #333;
+ border-bottom: 1rpx solid #f0f0f0;
+ padding-bottom: 10rpx;
+ }
+
+ .info-item {
+ display: flex;
+ margin-bottom: 20rpx;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ width: 200rpx;
+ font-size: 28rpx;
+ color: #666;
+ flex-shrink: 0;
+ }
+
+ .value {
+ flex: 1;
+ font-size: 28rpx;
+ color: #333;
+ word-break: break-all;
+
+ &.status {
+ &.pending {
+ color: #ff9500;
+ }
+ &.in_progress {
+ color: #007AFF;
+ }
+ &.completed {
+ color: #34C759;
+ }
+ &.cancelled {
+ color: #ff3b30;
+ }
+ }
+ }
+ }
+
+ .description {
font-size: 28rpx;
+ color: #333;
+ line-height: 1.6;
+ background-color: #f9f9f9;
+ padding: 20rpx;
+ border-radius: 10rpx;
+ }
+ }
+
+ .loading {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 400rpx;
+ color: #999;
+
+ text {
+ margin-top: 20rpx;
+ font-size: 28rpx;
+ }
+ }
+
+ .action-buttons {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ padding: 20rpx;
+ background-color: white;
+ box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
+
+ .action-btn {
flex: 1;
- word-break: break-all;
+ height: 80rpx;
+ border-radius: 10rpx;
+ font-size: 30rpx;
+ margin: 0 10rpx;
+ background-color: #f0f0f0;
+ color: #333;
+
+ &.primary {
+ background-color: #007AFF;
+ color: white;
+ }
+
+ &.cancel {
+ background-color: #ff3b30;
+ color: white;
+ }
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
}
- }
- }
-
- .task-actions {
- display: flex;
- flex-wrap: wrap;
- background-color: white;
- border-radius: 15rpx;
- padding: 30rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
-
- .action-btn {
- flex: 1;
- min-width: 30%;
- height: 70rpx;
- border-radius: 10rpx;
- font-size: 26rpx;
- margin: 10rpx 5rpx;
- background-color: #f0f0f0;
- color: #333;
-
- &.primary {
- background-color: #007AFF;
- color: white;
- }
-
- &.disabled {
- opacity: 0.5;
- }
- }
- }
-
- .action-section {
- margin-top: 40rpx;
- text-align: center;
-
- .back-btn {
- width: 80%;
- height: 80rpx;
- background-color: #007AFF;
- color: white;
- border-radius: 10rpx;
- font-size: 32rpx;
}
}
</style>
\ No newline at end of file
diff --git a/app/pages/task/index.vue b/app/pages/task/index.vue
index ff9746c..d5b0655 100644
--- a/app/pages/task/index.vue
+++ b/app/pages/task/index.vue
@@ -110,18 +110,21 @@
<view class="task-list">
<view class="task-item" v-for="task in filteredTaskList" :key="task.id">
<view class="task-main" @click="viewTaskDetail(task)">
- <view class="task-title">{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view>
- <view class="task-info">
- <view class="info-row">
- <view class="info-item">
- <view class="label">浠诲姟缂栧彿:</view>
- <view class="value">{{ task.taskNo }}</view>
- </view>
- <view class="info-item">
- <view class="label">浠诲姟鐘舵��:</view>
- <view class="value">{{ getStatusText(task.status) }}</view>
- </view>
+ <!-- 浠诲姟澶撮儴锛氭爣棰樺拰鐘舵�佹爣绛� -->
+ <view class="task-header">
+ <view class="task-title">{{ getTaskTypeText(task.taskType) }} - {{ task.vehicle }}</view>
+ <view class="task-status" :class="getStatusClass(task.taskStatus)">
+ {{ getStatusText(task.taskStatus) }}
</view>
+ </view>
+
+ <!-- 浠诲姟缂栧彿鍗曠嫭涓�琛� -->
+ <view class="task-code-row">
+ <text class="task-code">{{ task.taskCode }}</text>
+ </view>
+
+ <!-- 浠诲姟璇︾粏淇℃伅 -->
+ <view class="task-info">
<view class="info-row">
<view class="info-item">
<view class="label">鍑哄彂鍦�:</view>
@@ -147,46 +150,59 @@
<!-- 鎿嶄綔鎸夐挳 -->
<view class="task-actions">
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled(task, 'depart') }"
- @click="handleTaskAction(task, 'depart')"
- v-if="task.status !== 'completed'"
- >
- 鍑哄彂
- </button>
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled(task, 'arrive') }"
- @click="handleTaskAction(task, 'arrive')"
- v-if="task.status !== 'completed'"
- >
- 宸插埌杈�
- </button>
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled(task, 'return') }"
- @click="handleTaskAction(task, 'return')"
- v-if="task.status !== 'completed'"
- >
- 杩旂▼
- </button>
- <button
- class="action-btn"
- :class="{ disabled: isActionDisabled(task, 'settle') }"
- @click="handleTaskAction(task, 'settle')"
- v-if="task.status !== 'completed'"
- >
- 缁撶畻
- </button>
- <button
- class="action-btn primary"
- :class="{ disabled: isActionDisabled(task, 'complete') }"
- @click="handleTaskAction(task, 'complete')"
- v-if="task.status !== 'completed'"
- >
- 宸插畬鎴�
- </button>
+ <!-- 寰呭鐞嗙姸鎬�: 鏄剧ず鍑哄彂銆佸彇娑� -->
+ <template v-if="task.taskStatus === 'PENDING'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction(task, 'depart')"
+ >
+ 鍑哄彂
+ </button>
+ <button
+ class="action-btn cancel"
+ @click="handleTaskAction(task, 'cancel')"
+ >
+ 鍙栨秷
+ </button>
+ </template>
+
+ <!-- 鍑哄彂涓姸鎬�: 鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉� -->
+ <template v-else-if="task.taskStatus === 'DEPARTING'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction(task, 'arrive')"
+ >
+ 宸插埌杈�
+ </button>
+ <button
+ class="action-btn cancel"
+ @click="handleTaskAction(task, 'forceCancel')"
+ >
+ 寮哄埗缁撴潫
+ </button>
+ </template>
+
+ <!-- 宸插埌杈剧姸鎬�: 鏄剧ず宸茶繑绋� -->
+ <template v-else-if="task.taskStatus === 'ARRIVED'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction(task, 'return')"
+ >
+ 宸茶繑绋�
+ </button>
+ </template>
+
+ <!-- 杩旂▼涓姸鎬�: 鏄剧ず宸插畬鎴� -->
+ <template v-else-if="task.taskStatus === 'RETURNING'">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction(task, 'complete')"
+ >
+ 宸插畬鎴�
+ </button>
+ </template>
+
+ <!-- 宸插畬鎴�/宸插彇娑�: 涓嶆樉绀烘寜閽� -->
</view>
</view>
@@ -202,6 +218,8 @@
<script>
import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
+ import { listTask, changeTaskStatus } from '@/api/task'
+ import { mapState } from 'vuex'
export default {
components: {
@@ -226,119 +244,65 @@
currentFilter: 'all',
// 浠诲姟鍒楄〃
- taskList: [
- {
- id: 1,
- title: '绱ф�ョ淮淇换鍔�',
- type: 'maintenance', // 缁翠慨淇濆吇
- startLocation: '骞垮窞甯傚ぉ娌冲尯XX璺�123鍙�',
- endLocation: '骞垮窞甯傜櫧浜戝尯YY璺�456鍙�',
- startTime: '2023-05-15 15:00',
- assignee: '寮犱笁',
- status: 'pending',
- vehicle: '绮12345',
- taskNo: 'RW20230515001'
- },
- {
- id: 2,
- title: '瀹氭湡淇濆吇浠诲姟',
- type: 'maintenance', // 缁翠慨淇濆吇
- startLocation: '娣卞湷甯傚崡灞卞尯XX璺�789鍙�',
- endLocation: '娣卞湷甯傜鐢板尯YY璺�999鍙�',
- startTime: '2023-05-14 10:00',
- assignee: '鏉庡洓',
- status: 'processing',
- vehicle: '绮67890',
- taskNo: 'RW20230514002'
- },
- {
- id: 3,
- title: '璁惧宸℃浠诲姟',
- type: 'inspection', // 宸℃浠诲姟
- startLocation: '鐝犳捣甯傞娲插尯XX璺�321鍙�',
- endLocation: '鐝犳捣甯傞噾婀惧尯YY璺�654鍙�',
- startTime: '2023-05-13 17:00',
- assignee: '鐜嬩簲',
- status: 'completed',
- vehicle: '绮11111',
- taskNo: 'RW20230513003'
- },
- {
- id: 4,
- title: '鍔犳补浠诲姟',
- type: 'refuel', // 鍔犳补
- startLocation: '浣涘北甯傜鍩庡尯AA璺�555鍙�',
- endLocation: '浣涘北甯傚崡娴峰尯BB璺�888鍙�',
- startTime: '2023-05-12 09:00',
- assignee: '璧靛叚',
- status: 'completed',
- vehicle: '绮22222',
- taskNo: 'RW20230512004'
- },
- {
- id: 5,
- title: '鎬ユ晳杞繍浠诲姟',
- type: 'emergency', // 鎬ユ晳杞繍
- startLocation: '骞垮窞甯傝秺绉�鍖哄尰闄㈣矾1鍙�',
- endLocation: '骞垮窞甯傛捣鐝犲尯鍖婚櫌璺�2鍙�',
- startTime: '2023-05-16 14:00',
- assignee: '寮犲尰鐢�,鏉庢姢澹�',
- status: 'pending',
- vehicle: '绮33333',
- taskNo: 'RW20230516005'
- },
- {
- id: 6,
- title: '绂忕杞︿换鍔�',
- type: 'welfare', // 绂忕杞�
- startLocation: '骞垮窞甯傝崝婀惧尯绀惧尯璺�10鍙�',
- endLocation: '骞垮窞甯傚ぉ娌冲尯鍏昏�侀櫌璺�20鍙�',
- startTime: '2023-05-17 08:00',
- assignee: '鐜嬪徃鏈�',
- status: 'processing',
- vehicle: '绮44444',
- taskNo: 'RW20230517006'
- }
- ]
+ taskList: [],
+ loading: false,
+ refreshing: false
}
},
computed: {
+ ...mapState({
+ currentUser: state => state.user
+ }),
filteredTaskList() {
let filtered = this.taskList;
// 搴旂敤绛涢�夊櫒
if (this.currentFilter !== 'all') {
filtered = filtered.filter(task => {
- if (this.currentFilter === 'pending') return task.status === 'pending';
- if (this.currentFilter === 'processing') return task.status === 'processing';
- if (this.currentFilter === 'completed') return task.status === 'completed';
+ if (this.currentFilter === 'pending') return task.taskStatus === 'PENDING';
+ if (this.currentFilter === 'processing') return ['DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(task.taskStatus);
+ if (this.currentFilter === 'completed') return task.taskStatus === 'COMPLETED';
return true;
});
}
// 搴旂敤鐘舵�佺瓫閫�
if (this.selectedStatus) {
- filtered = filtered.filter(task => task.status === this.selectedStatus);
+ const statusMap = {
+ 'pending': ['PENDING'],
+ 'processing': ['DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'],
+ 'completed': ['COMPLETED']
+ }
+ const validStatuses = statusMap[this.selectedStatus];
+ if (validStatuses) {
+ filtered = filtered.filter(task => validStatuses.includes(task.taskStatus));
+ }
}
- // 搴旂敤杞︾墝鍙风瓫閫�
+ // 搴旂敤杞︾墝鍙风瓫閫� - 鎼滅储assignedVehicles鏁扮粍涓殑杞﹁締
if (this.searchForm.vehicle) {
- filtered = filtered.filter(task =>
- task.vehicle.includes(this.searchForm.vehicle)
- );
+ filtered = filtered.filter(task => {
+ // 鍦ㄨ溅杈嗗垪琛ㄤ腑鏌ユ壘鍖归厤鐨勮溅鐗屽彿
+ if (task.vehicleList && task.vehicleList.length > 0) {
+ return task.vehicleList.some(vehicle =>
+ vehicle.vehicleNo && vehicle.vehicleNo.includes(this.searchForm.vehicle)
+ )
+ }
+ return false
+ });
}
- // 搴旂敤浠诲姟缂栧彿绛涢��
+ // 搴旂敤浠诲姟缂栧彿绛涢�� - 浣跨敤taskCode鑰屼笉鏄痶askNo
if (this.searchForm.taskNo) {
filtered = filtered.filter(task =>
- task.taskNo.includes(this.searchForm.taskNo)
+ task.taskCode && task.taskCode.includes(this.searchForm.taskNo)
);
}
// 搴旂敤鏃堕棿鑼冨洿绛涢��
if (this.startDate) {
filtered = filtered.filter(task =>
- task.startTime >= this.startDate
+ task.plannedStartTime && task.plannedStartTime >= this.startDate
);
}
@@ -349,14 +313,87 @@
const endDateStr = end.toISOString().split('T')[0];
filtered = filtered.filter(task =>
- task.startTime < endDateStr
+ task.plannedStartTime && task.plannedStartTime < endDateStr
);
}
return filtered;
}
},
+ onLoad() {
+ this.loadTaskList()
+ },
+ onPullDownRefresh() {
+ this.refreshList()
+ },
methods: {
+ // 鍔犺浇浠诲姟鍒楄〃
+ loadTaskList() {
+ this.loading = true
+ // 鍚庣浼氳嚜鍔ㄨ幏鍙栧綋鍓嶇敤鎴蜂俊鎭紝瀹炵幇缁煎悎鏌ヨ
+ // 缁煎悎鏌ヨ锛氬綋鍓嶇敤鎴锋墍鍦ㄦ満鏋勪换鍔� + 褰撳墠鐢ㄦ埛鍒涘缓鐨勪换鍔� + 鍒嗛厤缁欏綋鍓嶇敤鎴风殑浠诲姟
+ const queryParams = {
+ pageNum: 1,
+ pageSize: 100
+ }
+
+ listTask(queryParams).then(response => {
+ this.loading = false
+ const data = response.data || response.rows || []
+ this.taskList = data.map(task => {
+ // 浠巃ssignedVehicles鏁扮粍涓幏鍙栬溅杈嗕俊鎭�
+ let vehicleInfo = '鏈垎閰嶈溅杈�'
+ if (task.assignedVehicles && task.assignedVehicles.length > 0) {
+ // 濡傛灉鏈夊涓溅杈�,鏄剧ず绗竴涓�,骞舵爣娉ㄦ暟閲�
+ const firstVehicle = task.assignedVehicles[0]
+ vehicleInfo = firstVehicle.vehicleNo || '鏈煡杞︾墝'
+ if (task.assignedVehicles.length > 1) {
+ vehicleInfo += ` 绛�${task.assignedVehicles.length}杈哷
+ }
+ }
+
+ return {
+ ...task,
+ // 鏍煎紡鍖栨樉绀哄瓧娈� - 浣跨敤鍚庣杩斿洖鐨刟ssignedVehicles鏁版嵁
+ vehicle: vehicleInfo,
+ vehicleList: task.assignedVehicles || [],
+ startLocation: this.formatAddress(task.departureAddress || task.startLocation || '鏈缃�'),
+ endLocation: this.formatAddress(task.destinationAddress || task.endLocation || '鏈缃�'),
+ startTime: task.plannedStartTime ? this.formatDateTime(task.plannedStartTime) : '鏈缃�',
+ assignee: task.assigneeName || '鏈垎閰�'
+ }
+ })
+ }).catch(error => {
+ this.loading = false
+ console.error('鍔犺浇浠诲姟鍒楄〃澶辫触:', error)
+ this.$modal.showToast('鍔犺浇浠诲姟鍒楄〃澶辫触')
+ })
+ },
+
+ // 鏍煎紡鍖栨棩鏈熸椂闂�
+ formatDateTime(dateTime) {
+ if (!dateTime) return ''
+ const date = new Date(dateTime)
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ })
+ },
+
+ // 鏍煎紡鍖栧湴鍧� - 鍙樉绀�-鍓嶉潰鐨勯儴鍒�
+ formatAddress(address) {
+ if (!address) return '鏈缃�'
+ // 濡傛灉鍦板潃鍖呭惈-锛屽彧杩斿洖-鍓嶉潰鐨勯儴鍒�
+ const dashIndex = address.indexOf('-')
+ if (dashIndex > 0) {
+ return address.substring(0, dashIndex)
+ }
+ return address
+ },
+
// 鍒囨崲鏌ヨ鐣岄潰鏄剧ず/闅愯棌
toggleSearch() {
this.showSearch = !this.showSearch;
@@ -370,17 +407,10 @@
// 鏌ヨ
handleSearch() {
+ this.loadTaskList()
this.$modal.showToast('鏌ヨ鎴愬姛');
- console.log('鏌ヨ鏉′欢:', {
- status: this.selectedStatus,
- startDate: this.startDate,
- endDate: this.endDate,
- vehicle: this.searchForm.vehicle,
- taskNo: this.searchForm.taskNo
- });
// 鏌ヨ瀹屾垚鍚庨殣钘忔煡璇㈢晫闈�
this.showSearch = false;
- // 杩欓噷鍙互璋冪敤API杩涜鏌ヨ
},
// 閲嶇疆鏌ヨ鏉′欢
@@ -395,8 +425,14 @@
// 鍒锋柊鍒楄〃
refreshList() {
- this.$modal.showToast('鍒楄〃宸插埛鏂�');
- // 杩欓噷鍙互閲嶆柊鍔犺浇鏁版嵁
+ this.refreshing = true
+ this.loadTaskList()
+ setTimeout(() => {
+ this.refreshing = false
+ this.$modal.showToast('鍒楄〃宸插埛鏂�');
+ // 鍋滄涓嬫媺鍒锋柊
+ uni.stopPullDownRefresh()
+ }, 1000)
},
// 绛涢��
@@ -406,93 +442,153 @@
// 鏌ョ湅浠诲姟璇︽儏
viewTaskDetail(task) {
- // 璺宠浆鍒颁换鍔¤鎯呴〉闈�
- this.$tab.navigateTo(`/pages/task/detail?id=${task.id}`);
- },
-
- // 鍒ゆ柇鎿嶄綔鎸夐挳鏄惁绂佺敤
- isActionDisabled(task, action) {
- // 鏍规嵁浠诲姟鐘舵�佸拰鎿嶄綔绫诲瀷鍒ゆ柇鏄惁绂佺敤
- switch (action) {
- case 'depart':
- return task.status !== 'pending';
- case 'arrive':
- return task.status !== 'processing';
- case 'return':
- return task.status !== 'processing';
- case 'settle':
- return task.status !== 'processing';
- case 'complete':
- return task.status !== 'processing';
- default:
- return false;
- }
+ // 璺宠浆鍒颁换鍔¤鎯呴〉闈� - 淇:浣跨敤taskId鑰屼笉鏄痠d
+ this.$tab.navigateTo(`/pages/task/detail?id=${task.taskId}`);
},
// 澶勭悊浠诲姟鎿嶄綔
handleTaskAction(task, action) {
- if (this.isActionDisabled(task, action)) {
- return;
- }
-
switch (action) {
case 'depart':
- // 鍑哄彂鎿嶄綔锛屾牴鎹换鍔$被鍨嬫樉绀轰笉鍚岀殑纭淇℃伅
- let departMessage = '纭畾瑕佹爣璁颁负宸插嚭鍙戝悧锛�';
- if (task.type !== 'maintenance' && task.type !== 'refuel' && task.type !== 'inspection') {
- departMessage = '鍙戝嚭鍘荤洰鐨勫湴,纭锛�';
- }
- this.$modal.confirm(departMessage).then(() => {
- task.status = 'processing';
- this.$modal.showToast('宸插嚭鍙�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 鍑哄彂 -> 鐘舵�佸彉涓哄嚭鍙戜腑
+ this.$modal.confirm('纭畾瑕佸嚭鍙戝悧锛�').then(() => {
+ this.updateTaskStatus(task.taskId, 'DEPARTING', '浠诲姟宸插嚭鍙�')
}).catch(() => {});
break;
+
+ case 'cancel':
+ // 鍙栨秷 -> 浜屾纭鍚庣姸鎬佸彉涓哄凡鍙栨秷
+ this.$modal.confirm('纭畾瑕佸彇娑堟浠诲姟鍚楋紵').then(() => {
+ this.updateTaskStatus(task.taskId, 'CANCELLED', '浠诲姟宸插彇娑�')
+ }).catch(() => {});
+ break;
+
case 'arrive':
- // 宸插埌杈炬搷浣�
- this.$modal.confirm('宸茬粡鍒拌揪鐩殑鍦帮紝纭锛�').then(() => {
- this.$modal.showToast('宸插埌杈�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 宸插埌杈� -> 鐘舵�佸彉涓哄凡鍒拌揪
+ this.$modal.confirm('纭宸插埌杈剧洰鐨勫湴锛�').then(() => {
+ this.updateTaskStatus(task.taskId, 'ARRIVED', '宸插埌杈剧洰鐨勫湴')
}).catch(() => {});
break;
+
+ case 'forceCancel':
+ // 寮哄埗缁撴潫 -> 鐘舵�佸彉涓哄凡鍙栨秷
+ this.$modal.confirm('纭畾瑕佸己鍒剁粨鏉熸浠诲姟鍚楋紵').then(() => {
+ this.updateTaskStatus(task.taskId, 'CANCELLED', '浠诲姟宸插己鍒剁粨鏉�')
+ }).catch(() => {});
+ break;
+
case 'return':
- // 杩旂▼鎿嶄綔
- this.$modal.confirm('鐜板湪宸茬粡杩旂▼涓紝纭锛�').then(() => {
- this.$modal.showToast('杩旂▼涓�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 宸茶繑绋� -> 鐘舵�佸彉涓鸿繑绋嬩腑
+ this.$modal.confirm('纭寮�濮嬭繑绋嬶紵').then(() => {
+ this.updateTaskStatus(task.taskId, 'RETURNING', '宸插紑濮嬭繑绋�')
}).catch(() => {});
break;
- case 'settle':
- // 缁撶畻鎿嶄綔锛岃烦杞埌缁撶畻椤甸潰
- this.$tab.navigateTo(`/pages/task/settlement?id=${task.id}`);
- break;
+
case 'complete':
- // 宸插畬鎴愭搷浣�
- this.$modal.confirm('浠诲姟鏄惁宸茬粡鍏ㄩ儴瀹屾垚锛岀‘璁わ紵').then(() => {
- task.status = 'completed';
- this.$modal.showToast('浠诲姟宸插畬鎴�');
- // 杩欓噷鍙互璋冪敤API鏇存柊浠诲姟鐘舵��
+ // 宸插畬鎴� -> 鐘舵�佸彉涓哄凡瀹屾垚
+ this.$modal.confirm('纭浠诲姟宸插畬鎴愶紵').then(() => {
+ this.updateTaskStatus(task.taskId, 'COMPLETED', '浠诲姟宸插畬鎴�')
}).catch(() => {});
break;
}
+ },
+
+ // 鏇存柊浠诲姟鐘舵��
+ updateTaskStatus(taskId, status, remark) {
+ // 鑾峰彇GPS浣嶇疆淇℃伅
+ this.getLocationAndUpdateStatus(taskId, status, remark)
+ },
+
+ // 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
+ getLocationAndUpdateStatus(taskId, status, remark) {
+ const that = this
+
+ // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
+ uni.getLocation({
+ type: 'gcj02',
+ geocode: true,
+ altitude: true,
+ success: function(res) {
+ console.log('GPS瀹氫綅鎴愬姛:', res)
+
+ 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()
+ }).catch(error => {
+ console.error('鏇存柊浠诲姟鐘舵�佸け璐�:', error)
+ that.$modal.showToast('鐘舵�佹洿鏂板け璐ワ紝璇烽噸璇�')
+ })
+ },
+ fail: function(err) {
+ console.error('GPS瀹氫綅澶辫触:', err)
+
+ that.$modal.confirm('GPS瀹氫綅澶辫触锛屾槸鍚︾户缁洿鏂扮姸鎬侊紵').then(() => {
+ const statusData = {
+ taskStatus: status,
+ remark: remark
+ }
+
+ changeTaskStatus(taskId, statusData).then(response => {
+ that.$modal.showToast('鐘舵�佹洿鏂版垚鍔�')
+ that.loadTaskList()
+ }).catch(error => {
+ console.error('鏇存柊浠诲姟鐘舵�佸け璐�:', error)
+ that.$modal.showToast('鐘舵�佹洿鏂板け璐ワ紝璇烽噸璇�')
+ })
+ }).catch(() => {})
+ }
+ })
},
getStatusText(status) {
const statusMap = {
- 'pending': '寰呭鐞�',
- 'processing': '澶勭悊涓�',
- 'completed': '宸插畬鎴�'
+ 'PENDING': '寰呭鐞�',
+ 'DEPARTING': '鍑哄彂涓�',
+ 'ARRIVED': '宸插埌杈�',
+ 'RETURNING': '杩旂▼涓�',
+ 'COMPLETED': '宸插畬鎴�',
+ 'CANCELLED': '宸插彇娑�',
+ 'IN_PROGRESS': '澶勭悊涓�' // 鍏煎鏃ф暟鎹�
}
return statusMap[status] || '鏈煡'
},
+ // 鑾峰彇鐘舵�佹牱寮忕被
+ getStatusClass(status) {
+ const statusClassMap = {
+ 'PENDING': 'status-pending',
+ 'DEPARTING': 'status-departing',
+ 'ARRIVED': 'status-arrived',
+ 'RETURNING': 'status-returning',
+ 'COMPLETED': 'status-completed',
+ 'CANCELLED': 'status-cancelled',
+ 'IN_PROGRESS': 'status-in-progress'
+ }
+ return statusClassMap[status] || 'status-default'
+ },
+
getTaskTypeText(type) {
const typeMap = {
- 'maintenance': '缁翠慨淇濆吇',
- 'refuel': '鍔犳补',
- 'inspection': '宸℃',
- 'emergency': '鎬ユ晳杞繍',
- 'welfare': '绂忕杞�'
+ 'MAINTENANCE': '缁翠慨淇濆吇',
+ 'FUEL': '鍔犳补',
+ 'OTHER': '鍏朵粬',
+ 'EMERGENCY_TRANSFER': '鎬ユ晳杞繍',
+ 'WELFARE': '绂忕杞�'
}
return typeMap[type] || '鏈煡绫诲瀷'
}
@@ -715,10 +811,90 @@
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
- .task-title {
- font-size: 32rpx;
- font-weight: bold;
- margin-bottom: 20rpx;
+ // 浠诲姟澶撮儴锛氭爣棰樺拰鐘舵��
+ .task-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 15rpx;
+
+ .task-title {
+ flex: 1;
+ font-size: 32rpx;
+ font-weight: bold;
+ padding-right: 20rpx;
+ line-height: 1.4;
+ }
+
+ .task-status {
+ padding: 8rpx 20rpx;
+ border-radius: 30rpx;
+ font-size: 24rpx;
+ white-space: nowrap;
+ flex-shrink: 0;
+
+ // 寰呭鐞� - 姗欒壊
+ &.status-pending {
+ background-color: #fff3e0;
+ color: #ff9500;
+ }
+
+ // 鍑哄彂涓� - 钃濊壊
+ &.status-departing {
+ background-color: #e3f2fd;
+ color: #007AFF;
+ }
+
+ // 宸插埌杈� - 绱壊
+ &.status-arrived {
+ background-color: #f3e5f5;
+ color: #9c27b0;
+ }
+
+ // 杩旂▼涓� - 闈掕壊
+ &.status-returning {
+ background-color: #e0f2f1;
+ color: #009688;
+ }
+
+ // 宸插畬鎴� - 缁胯壊
+ &.status-completed {
+ background-color: #e8f5e9;
+ color: #34C759;
+ }
+
+ // 宸插彇娑� - 鐏拌壊
+ &.status-cancelled {
+ background-color: #f5f5f5;
+ color: #999;
+ }
+
+ // 澶勭悊涓� (鍏煎鏃ф暟鎹�) - 钃濊壊
+ &.status-in-progress {
+ background-color: #e3f2fd;
+ color: #007AFF;
+ }
+
+ // 榛樿鏍峰紡
+ &.status-default {
+ background-color: #f5f5f5;
+ color: #666;
+ }
+ }
+ }
+
+ // 浠诲姟缂栧彿鍗曠嫭涓�琛�
+ .task-code-row {
+ margin-bottom: 15rpx;
+ padding: 10rpx 0;
+ border-bottom: 1rpx dashed #e0e0e0;
+
+ .task-code {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 500;
+ font-family: monospace;
+ }
}
.task-info {
@@ -769,6 +945,11 @@
color: white;
}
+ &.cancel {
+ background-color: #ff3b30;
+ color: white;
+ }
+
&.disabled {
opacity: 0.5;
}
diff --git a/app/static/index.html b/app/static/index.html
index a7af653..0824d25 100644
--- a/app/static/index.html
+++ b/app/static/index.html
@@ -9,6 +9,25 @@
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+
+ // 绂佺敤璺ㄥ煙瀛愭鏋惰嚜鍔ㄨ仛鐒�
+ document.addEventListener('DOMContentLoaded', function() {
+ // 闃绘iframe鍐呯殑鑷姩鑱氱劍
+ document.addEventListener('focusin', function(e) {
+ if (e.target.tagName === 'IFRAME' || e.target.closest('iframe')) {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ }, true)
+
+ // 闃绘webview鍐呯殑鑷姩鑱氱劍
+ document.addEventListener('focusin', function(e) {
+ if (e.target.tagName === 'WEB-VIEW' || e.target.closest('web-view')) {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ }, true)
+ })
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
diff --git a/app/store/modules/user.js b/app/store/modules/user.js
index 79e8b98..cf7c109 100644
--- a/app/store/modules/user.js
+++ b/app/store/modules/user.js
@@ -10,15 +10,21 @@
const user = {
state: {
token: getToken(),
+ userId: storage.get(constant.userId),
name: storage.get(constant.name),
avatar: storage.get(constant.avatar),
roles: storage.get(constant.roles),
- permissions: storage.get(constant.permissions)
+ permissions: storage.get(constant.permissions),
+ deptId: storage.get(constant.deptId)
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
+ },
+ SET_USER_ID: (state, userId) => {
+ state.userId = userId
+ storage.set(constant.userId, userId)
},
SET_NAME: (state, name) => {
state.name = name
@@ -35,6 +41,10 @@
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions
storage.set(constant.permissions, permissions)
+ },
+ SET_DEPT_ID: (state, deptId) => {
+ state.deptId = deptId
+ storage.set(constant.deptId, deptId)
}
},
@@ -76,14 +86,19 @@
const user = res.user
const avatar = (user == null || user.avatar == "" || user.avatar == null) ? require("@/static/images/profile.jpg") : baseUrl + user.avatar
const username = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName
+ const userId = (user == null || user.userId == null) ? null : user.userId
+ const deptId = (user == null || user.deptId == null) ? null : user.deptId
+
if (res.roles && res.roles.length > 0) {
commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions)
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
}
+ commit('SET_USER_ID', userId)
commit('SET_NAME', username)
commit('SET_AVATAR', avatar)
+ commit('SET_DEPT_ID', deptId)
resolve(res)
}).catch(error => {
reject(error)
diff --git a/app/utils/constant.js b/app/utils/constant.js
index 8becd84..79a0c1b 100644
--- a/app/utils/constant.js
+++ b/app/utils/constant.js
@@ -1,8 +1,10 @@
const constant = {
+ userId: 'vuex_userId',
avatar: 'vuex_avatar',
name: 'vuex_name',
roles: 'vuex_roles',
- permissions: 'vuex_permissions'
+ permissions: 'vuex_permissions',
+ deptId: 'vuex_deptId'
}
export default constant
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"
new file mode 100644
index 0000000..5844142
--- /dev/null
+++ "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"
@@ -0,0 +1,282 @@
+# 浠诲姟鐘舵�佸彉鏇碐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"
new file mode 100644
index 0000000..7b0bffb
--- /dev/null
+++ "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"
@@ -0,0 +1,218 @@
+# 鍦扮悊缂栫爜鏈嶅姟浣跨敤璇存槑
+
+## 鍔熻兘璇存槑
+
+鍦扮悊缂栫爜鏈嶅姟鍙互灏嗗湴鍧�瀛楃涓茶浆鎹负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/prd/Vuex\347\224\250\346\210\267\347\212\266\346\200\201\345\256\214\346\225\264\346\200\247\344\274\230\345\214\226.md" "b/prd/Vuex\347\224\250\346\210\267\347\212\266\346\200\201\345\256\214\346\225\264\346\200\247\344\274\230\345\214\226.md"
new file mode 100644
index 0000000..facee27
--- /dev/null
+++ "b/prd/Vuex\347\224\250\346\210\267\347\212\266\346\200\201\345\256\214\346\225\264\346\200\247\344\274\230\345\214\226.md"
@@ -0,0 +1,544 @@
+# Vuex 鐢ㄦ埛鐘舵�佸畬鏁存�т紭鍖栬鏄�
+
+## 闂鑳屾櫙
+
+鍦ㄤ箣鍓嶇殑棣栭〉 userId 鑾峰彇闂涓紝鍙戠幇 Vuex 鐨� user 妯″潡鍙瓨鍌ㄤ簡閮ㄥ垎鐢ㄦ埛淇℃伅锛坣ame銆乤vatar銆乺oles銆乸ermissions锛夛紝瀵艰嚧椤甸潰涓棤娉曠洿鎺ヤ粠 `state.user` 鑾峰彇 userId 鍜� deptId 绛夊叧閿俊鎭��
+
+## 闂鍒嗘瀽
+
+### 鍚庣鎺ュ彛杩斿洖鐨勬暟鎹�
+
+[`/getInfo`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysLoginController.java#L63-L82) 鎺ュ彛杩斿洖鐨勫畬鏁存暟鎹粨鏋勶細
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "user": {
+ "userId": 1,
+ "deptId": 103,
+ "userName": "admin",
+ "nickName": "绠$悊鍛�",
+ "email": "admin@163.com",
+ "phonenumber": "15888888888",
+ "sex": "1",
+ "avatar": "",
+ "status": "0",
+ "delFlag": "0",
+ "loginIp": "127.0.0.1",
+ "loginDate": "2023-05-15 10:00:00",
+ "dept": {
+ "deptId": 103,
+ "parentId": 101,
+ "deptName": "鐮斿彂閮ㄩ棬"
+ }
+ },
+ "roles": ["admin"],
+ "permissions": ["*:*:*"]
+}
+```
+
+### 鍘� Vuex State 缁撴瀯
+
+**淇敼鍓嶏細**
+```javascript
+state: {
+ token: getToken(),
+ name: storage.get(constant.name), // 鉁� 瀛樺偍
+ avatar: storage.get(constant.avatar), // 鉁� 瀛樺偍
+ roles: storage.get(constant.roles), // 鉁� 瀛樺偍
+ permissions: storage.get(constant.permissions) // 鉁� 瀛樺偍
+ // 鉂� 缂哄皯 userId
+ // 鉂� 缂哄皯 deptId
+}
+```
+
+### 瀵艰嚧鐨勯棶棰�
+
+1. **鏃犳硶鐩存帴鑾峰彇 userId**
+ ```javascript
+ // 鉂� 閿欒锛歝urrentUser.userId 涓� undefined
+ computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+ }
+
+ // 浣跨敤鏃�
+ this.currentUser.userId // undefined
+ ```
+
+2. **鏃犳硶鐩存帴鑾峰彇 deptId**
+ ```javascript
+ // 鉂� 閿欒锛歝urrentUser.deptId 涓� undefined
+ const deptId = this.currentUser.deptId // undefined
+ ```
+
+3. **渚濊禆闂**
+ - 闇�瑕侀澶栬皟鐢� API 鑾峰彇鐢ㄦ埛淇℃伅
+ - 澧炲姞浜嗕笉蹇呰鐨勭綉缁滆姹�
+ - 浠g爜澶嶆潅搴﹀鍔�
+
+## 瑙e喅鏂规
+
+### 1. 淇敼 Vuex State 缁撴瀯
+
+**鏂囦欢锛�** [`app/store/modules/user.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\store\modules\user.js)
+
+**淇敼鍓嶏細**
+```javascript
+state: {
+ token: getToken(),
+ name: storage.get(constant.name),
+ avatar: storage.get(constant.avatar),
+ roles: storage.get(constant.roles),
+ permissions: storage.get(constant.permissions)
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+state: {
+ token: getToken(),
+ userId: storage.get(constant.userId), // 鉁� 鏂板
+ name: storage.get(constant.name),
+ avatar: storage.get(constant.avatar),
+ roles: storage.get(constant.roles),
+ permissions: storage.get(constant.permissions),
+ deptId: storage.get(constant.deptId) // 鉁� 鏂板
+}
+```
+
+### 2. 娣诲姞鏂扮殑 Mutations
+
+**淇敼鍓嶏細**
+```javascript
+mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ storage.set(constant.name, name)
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ storage.set(constant.avatar, avatar)
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles
+ storage.set(constant.roles, roles)
+ },
+ SET_PERMISSIONS: (state, permissions) => {
+ state.permissions = permissions
+ storage.set(constant.permissions, permissions)
+ }
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_USER_ID: (state, userId) => { // 鉁� 鏂板
+ state.userId = userId
+ storage.set(constant.userId, userId)
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ storage.set(constant.name, name)
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ storage.set(constant.avatar, avatar)
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles
+ storage.set(constant.roles, roles)
+ },
+ SET_PERMISSIONS: (state, permissions) => {
+ state.permissions = permissions
+ storage.set(constant.permissions, permissions)
+ },
+ SET_DEPT_ID: (state, deptId) => { // 鉁� 鏂板
+ state.deptId = deptId
+ storage.set(constant.deptId, deptId)
+ }
+}
+```
+
+### 3. 鏇存柊 GetInfo Action
+
+**淇敼鍓嶏細**
+```javascript
+GetInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo().then(res => {
+ const user = res.user
+ const avatar = (user == null || user.avatar == "" || user.avatar == null)
+ ? require("@/static/images/profile.jpg")
+ : baseUrl + user.avatar
+ const username = (user == null || user.userName == "" || user.userName == null)
+ ? ""
+ : user.userName
+
+ if (res.roles && res.roles.length > 0) {
+ commit('SET_ROLES', res.roles)
+ commit('SET_PERMISSIONS', res.permissions)
+ } else {
+ commit('SET_ROLES', ['ROLE_DEFAULT'])
+ }
+ commit('SET_NAME', username)
+ commit('SET_AVATAR', avatar)
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+GetInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo().then(res => {
+ const user = res.user
+ const avatar = (user == null || user.avatar == "" || user.avatar == null)
+ ? require("@/static/images/profile.jpg")
+ : baseUrl + user.avatar
+ const username = (user == null || user.userName == "" || user.userName == null)
+ ? ""
+ : user.userName
+ const userId = (user == null || user.userId == null) ? null : user.userId // 鉁� 鏂板
+ const deptId = (user == null || user.deptId == null) ? null : user.deptId // 鉁� 鏂板
+
+ if (res.roles && res.roles.length > 0) {
+ commit('SET_ROLES', res.roles)
+ commit('SET_PERMISSIONS', res.permissions)
+ } else {
+ commit('SET_ROLES', ['ROLE_DEFAULT'])
+ }
+ commit('SET_USER_ID', userId) // 鉁� 鏂板
+ commit('SET_NAME', username)
+ commit('SET_AVATAR', avatar)
+ commit('SET_DEPT_ID', deptId) // 鉁� 鏂板
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+}
+```
+
+### 4. 鏇存柊 Constant 甯搁噺
+
+**鏂囦欢锛�** [`app/utils/constant.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\utils\constant.js)
+
+**淇敼鍓嶏細**
+```javascript
+const constant = {
+ avatar: 'vuex_avatar',
+ name: 'vuex_name',
+ roles: 'vuex_roles',
+ permissions: 'vuex_permissions'
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+const constant = {
+ userId: 'vuex_userId', // 鉁� 鏂板
+ avatar: 'vuex_avatar',
+ name: 'vuex_name',
+ roles: 'vuex_roles',
+ permissions: 'vuex_permissions',
+ deptId: 'vuex_deptId' // 鉁� 鏂板
+}
+```
+
+## 浼樺寲鏁堟灉
+
+### 1. 椤甸潰浣跨敤鏇寸畝娲�
+
+**淇敼鍓嶏細**
+```javascript
+// 鉂� 闇�瑕侀澶栬皟鐢� API 鑾峰彇鐢ㄦ埛淇℃伅
+methods: {
+ loadData() {
+ getUserProfile().then(response => {
+ const userId = response.data.userId
+ // 浣跨敤 userId...
+ })
+ }
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+// 鉁� 鐩存帴浠� Vuex 鑾峰彇
+computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+},
+methods: {
+ loadData() {
+ const userId = this.currentUser.userId
+ const deptId = this.currentUser.deptId
+ // 鐩存帴浣跨敤 userId 鍜� deptId...
+ }
+}
+```
+
+### 2. 鍑忓皯缃戠粶璇锋眰
+
+- 鉁� 鏃犻渶棰濆璋冪敤 API 鑾峰彇鐢ㄦ埛淇℃伅
+- 鉁� 鍑忓皯鏈嶅姟鍣ㄥ帇鍔�
+- 鉁� 鎻愰珮椤甸潰鍝嶅簲閫熷害
+
+### 3. 鏁版嵁鎸佷箙鍖�
+
+```javascript
+// 鉁� 鏁版嵁浼氳嚜鍔ㄥ瓨鍌ㄥ埌鏈湴瀛樺偍
+storage.set(constant.userId, userId)
+storage.set(constant.deptId, deptId)
+
+// 鉁� 椤甸潰鍒锋柊鍚庡彲浠ヤ粠鏈湴瀛樺偍鎭㈠
+state: {
+ userId: storage.get(constant.userId),
+ deptId: storage.get(constant.deptId)
+}
+```
+
+## 浣跨敤绀轰緥
+
+### 绀轰緥1锛氶椤佃幏鍙栫敤鎴蜂俊鎭�
+
+**鏂囦欢锛�** [`app/pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue)
+
+```javascript
+export default {
+ computed: {
+ ...mapState({
+ userName: state => state.user.name,
+ currentUser: state => state.user
+ })
+ },
+
+ methods: {
+ loadRunningTasks() {
+ const userId = this.currentUser.userId // 鉁� 鐩存帴鑾峰彇
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰�')
+ return
+ }
+
+ const queryParams = {
+ assigneeId: userId,
+ // ...
+ }
+ // 鍔犺浇浠诲姟鍒楄〃...
+ }
+ }
+}
+```
+
+### 绀轰緥2锛氱粦瀹氳溅杈嗛〉闈�
+
+**鏂囦欢锛�** [`app/pages/bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue)
+
+```javascript
+export default {
+ computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+ },
+
+ methods: {
+ loadVehicleList() {
+ const deptId = this.currentUser.deptId // 鉁� 鐩存帴鑾峰彇閮ㄩ棬ID
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ // 澶勭悊杞﹁締鍒楄〃...
+ })
+ },
+
+ bindVehicle() {
+ const userId = this.currentUser.userId // 鉁� 鐩存帴鑾峰彇鐢ㄦ埛ID
+ bindVehicleToUser(userId, this.selectedVehicleId).then(response => {
+ // 澶勭悊缁戝畾缁撴灉...
+ })
+ }
+ }
+}
+```
+
+### 绀轰緥3锛氫釜浜轰腑蹇�
+
+**鏂囦欢锛�** [`app/pages/mine/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\mine\index.vue)
+
+```javascript
+export default {
+ computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+ },
+
+ methods: {
+ loadUserInfo() {
+ const userId = this.currentUser.userId // 鉁� 鐩存帴鑾峰彇
+ getUserBoundVehicle(userId).then(response => {
+ // 澶勭悊鐢ㄦ埛缁戝畾杞﹁締淇℃伅...
+ })
+ }
+ }
+}
+```
+
+## 鏁版嵁娴佸浘
+
+```mermaid
+graph TD
+ A[鐢ㄦ埛鐧诲綍] --> B[璋冪敤 /login 鎺ュ彛]
+ B --> C[鑾峰彇 token]
+ C --> D[璋冪敤 GetInfo Action]
+ D --> E[璇锋眰 /getInfo 鎺ュ彛]
+ E --> F[杩斿洖瀹屾暣鐢ㄦ埛淇℃伅]
+ F --> G[鎻愬彇 userId, deptId 绛塢
+ G --> H[瀛樺偍鍒� Vuex State]
+ H --> I[鎸佷箙鍖栧埌 LocalStorage]
+ I --> J[椤甸潰鍙洿鎺ヤ娇鐢╙
+
+ K[椤甸潰鍒锋柊] --> L[浠� LocalStorage 鎭㈠]
+ L --> J
+```
+
+## State 鏁版嵁缁撴瀯
+
+### 瀹屾暣鐨� state.user 缁撴瀯
+
+```javascript
+{
+ token: "eyJhbGciOiJIUzUxMiJ9...",
+ userId: 1, // 鉁� 鐢ㄦ埛ID
+ name: "admin", // 鐢ㄦ埛鍚�
+ avatar: "/profile/avatar.jpg", // 澶村儚
+ roles: ["admin"], // 瑙掕壊鍒楄〃
+ permissions: ["*:*:*"], // 鏉冮檺鍒楄〃
+ deptId: 103 // 鉁� 閮ㄩ棬ID
+}
+```
+
+### LocalStorage 瀛樺偍
+
+```javascript
+{
+ "vuex_token": "eyJhbGciOiJIUzUxMiJ9...",
+ "vuex_userId": 1, // 鉁� 鎸佷箙鍖�
+ "vuex_name": "admin",
+ "vuex_avatar": "/profile/avatar.jpg",
+ "vuex_roles": ["admin"],
+ "vuex_permissions": ["*:*:*"],
+ "vuex_deptId": 103 // 鉁� 鎸佷箙鍖�
+}
+```
+
+## 娉ㄦ剰浜嬮」
+
+### 1. 鐧诲綍鐘舵�佹鏌�
+
+鍦ㄤ娇鐢� userId 鍜� deptId 涔嬪墠锛屽姟蹇呮鏌ユ槸鍚﹀瓨鍦細
+
+```javascript
+const userId = this.currentUser.userId
+if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰�')
+ return
+}
+```
+
+### 2. 鏁版嵁鍚屾
+
+- 鉁� 鐧诲綍鍚庝細鑷姩鍚屾
+- 鉁� 閫�鍑虹櫥褰曚細鑷姩娓呴櫎
+- 鉁� 椤甸潰鍒锋柊浼氫粠鏈湴瀛樺偍鎭㈠
+
+### 3. 閫�鍑虹櫥褰曟竻鐞�
+
+LogOut Action 涓殑 `storage.clean()` 浼氭竻闄ゆ墍鏈夊瓨鍌ㄧ殑鐢ㄦ埛淇℃伅銆�
+
+## 鍏煎鎬�
+
+### 鍚戝悗鍏煎
+
+- 鉁� 鍘熸湁鐨� [name](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\ruoyi-ui\vue.config.js#L9-L9)銆乕avatar](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\ruoyi-common\src\main\java\com\ruoyi\common\core\domain\entity\SysUser.java#L52-L52)銆乕roles](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\plugins\auth.js#L16-L16)銆乕permissions](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\plugins\auth.js#L4-L4) 浣跨敤鏂瑰紡涓嶅彉
+- 鉁� 鏂板鐨� userId 鍜� deptId 涓嶅奖鍝嶇幇鏈夊姛鑳�
+- 鉁� 鎵�鏈夐〉闈㈡棤闇�淇敼鍗冲彲缁х画浣跨敤
+
+### 娓愯繘寮忓崌绾�
+
+鍙互閫愭灏嗗悇椤甸潰涓噸澶嶇殑鐢ㄦ埛淇℃伅鑾峰彇閫昏緫鏇挎崲涓轰粠 Vuex 鑾峰彇銆�
+
+## 娴嬭瘯楠岃瘉
+
+### 鍔熻兘娴嬭瘯
+
+1. **鐧诲綍鍔熻兘**
+ - 鉁� 鐧诲綍鎴愬姛鍚� userId 鍜� deptId 姝g‘瀛樺偍
+ - 鉁� 鏁版嵁鎸佷箙鍖栧埌 LocalStorage
+
+2. **椤甸潰鍒锋柊**
+ - 鉁� 鍒锋柊鍚� userId 鍜� deptId 浠� LocalStorage 鎭㈠
+ - 鉁� 椤甸潰鍙互姝e父浣跨敤鐢ㄦ埛淇℃伅
+
+3. **閫�鍑虹櫥褰�**
+ - 鉁� 閫�鍑哄悗娓呴櫎鎵�鏈夌敤鎴蜂俊鎭�
+ - 鉁� LocalStorage 涓殑鏁版嵁琚竻绌�
+
+4. **鍚勯〉闈娇鐢�**
+ - 鉁� 棣栭〉鍙互鑾峰彇 userId 鍔犺浇浠诲姟
+ - 鉁� 缁戝畾杞﹁締椤甸潰鍙互鑾峰彇 userId 鍜� deptId
+ - 鉁� 涓汉涓績鍙互鑾峰彇 userId
+
+## 鐩稿叧鏂囦欢
+
+### 淇敼鐨勬枃浠�
+1. [`app/store/modules/user.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\store\modules\user.js) - Vuex 鐢ㄦ埛妯″潡
+2. [`app/utils/constant.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\utils\constant.js) - 甯搁噺瀹氫箟
+
+### 鍙楃泭鐨勯〉闈�
+1. [`app/pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue) - 棣栭〉
+2. [`app/pages/bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) - 缁戝畾杞﹁締
+3. [`app/pages/mine/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\mine\index.vue) - 涓汉涓績
+4. [`app/pages/task/create.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\task\create.vue) - 鍒涘缓浠诲姟
+
+### 鐩稿叧鏂囨。
+- [棣栭〉鐢ㄦ埛ID鑾峰彇闂淇.md](./棣栭〉鐢ㄦ埛ID鑾峰彇闂淇.md)
+- [杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md](./杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md)
+
+## 鎬荤粨
+
+閫氳繃鏈浼樺寲锛孷uex 鐢ㄦ埛鐘舵�佺鐞嗘洿鍔犲畬鏁达紝涓昏鏀硅繘锛�
+
+1. 鉁� **瀹屾暣鎬�**锛氬瓨鍌ㄤ簡 userId 鍜� deptId 绛夊叧閿俊鎭�
+2. 鉁� **鎸佷箙鍖�**锛氭暟鎹細鑷姩淇濆瓨鍒� LocalStorage
+3. 鉁� **渚挎嵎鎬�**锛氶〉闈㈠彲浠ョ洿鎺ヤ粠 Vuex 鑾峰彇鐢ㄦ埛淇℃伅锛屾棤闇�棰濆 API 璋冪敤
+4. 鉁� **涓�鑷存��**锛氭墍鏈夐〉闈娇鐢ㄧ粺涓�鐨勬柟寮忚幏鍙栫敤鎴蜂俊鎭�
+5. 鉁� **鎬ц兘**锛氬噺灏戜簡涓嶅繀瑕佺殑缃戠粶璇锋眰
+6. 鉁� **鍏煎鎬�**锛氬悜鍚庡吋瀹癸紝涓嶅奖鍝嶇幇鏈夊姛鑳�
+
+**鏍稿績浠峰��**锛�
+- 绠�鍖栦簡浠g爜閫昏緫
+- 鎻愰珮浜嗗紑鍙戞晥鐜�
+- 鍑忓皯浜嗙淮鎶ゆ垚鏈�
+- 鎻愬崌浜嗙敤鎴蜂綋楠�
+
+## 鐗堟湰鍘嗗彶
+
+| 鐗堟湰 | 鏃ユ湡 | 淇敼鍐呭 | 淇敼浜� |
+|------|------|---------|--------|
+| 1.0 | 2025-10-15 | Vuex 鐢ㄦ埛鐘舵�佸畬鏁存�т紭鍖� | - |
diff --git "a/prd/\346\200\245\346\225\221\350\275\254\350\277\220\344\273\273\345\212\241\344\272\272\345\221\230\351\200\211\346\213\251\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\346\200\245\346\225\221\350\275\254\350\277\220\344\273\273\345\212\241\344\272\272\345\221\230\351\200\211\346\213\251\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..ebf2e25
--- /dev/null
+++ "b/prd/\346\200\245\346\225\221\350\275\254\350\277\220\344\273\273\345\212\241\344\272\272\345\221\230\351\200\211\346\213\251\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,252 @@
+# 鎬ユ晳杞繍浠诲姟 - 鎵ц浜哄憳閫夋嫨鍔熻兘璇存槑
+
+## 鍔熻兘姒傝堪
+鍦ㄥ垱寤洪潪鎬ユ晳杞繍浠诲姟鏃讹紝闇�瑕侀�夋嫨鎵ц浠诲姟鐨勪汉鍛樸�傜郴缁熸敮鎸佷粠褰撳墠鐢ㄦ埛鎵�鍦ㄥ垎鍏徃涓�夋嫨鍙告満鍜屾姢澹綔涓烘墽琛屼汉鍛樸��
+
+## 鍔熻兘鐗规��
+
+### 1. 榛樿浜哄憳
+- 褰撳墠鐧诲綍鐢ㄦ埛榛樿浣滀负绗竴涓墽琛屼汉鍛�
+- 褰撳墠鐢ㄦ埛涓嶅彲琚Щ闄�
+
+### 2. 浜哄憳閫夋嫨
+- 鐐瑰嚮"娣诲姞浜哄憳"鎸夐挳鎵撳紑浜哄憳閫夋嫨寮圭獥
+- 寮圭獥浠ュ簳閮ㄥ脊鍑烘柟寮忓睍绀�
+- 鏀寔澶氶�変汉鍛�
+
+### 3. 浜哄憳绛涢��
+
+#### 鎸夌被鍨嬬瓫閫�
+- **鍏ㄩ儴**锛氭樉绀烘墍鏈変汉鍛�
+- **鍙告満**锛氬彧鏄剧ず鍙告満宀椾綅鐨勪汉鍛�
+- **鎶ゅ+**锛氬彧鏄剧ず鎶ゅ+宀椾綅鐨勪汉鍛�
+
+#### 鎼滅储鍔熻兘
+- 鏀寔鎸夊鍚嶆悳绱�
+- 鏀寔鎸夋墜鏈哄彿鎼滅储
+- 瀹炴椂杩囨护鏄剧ず
+
+### 4. 浜哄憳淇℃伅灞曠ず
+姣忎釜浜哄憳鏄剧ず浠ヤ笅淇℃伅锛�
+- 濮撳悕
+- 鎵嬫満鍙�
+- 鎵�灞為儴闂�
+- 宀椾綅/瑙掕壊
+
+### 5. 閫夋嫨鎿嶄綔
+- 鐐瑰嚮浜哄憳鍙垏鎹㈤�変腑鐘舵��
+- 宸查�変腑鐨勪汉鍛樻樉绀哄嬀閫夊浘鏍�
+- 鏈�変腑鐨勪汉鍛樻樉绀虹┖蹇冨渾鍦�
+- 搴曢儴鏄剧ず宸查�変汉鍛樻暟閲�
+
+## 瀹炵幇缁嗚妭
+
+### API鎺ュ彛
+
+#### 鏌ヨ鐢ㄦ埛鍒楄〃
+```javascript
+listUser({
+ deptId: 褰撳墠鐢ㄦ埛閮ㄩ棬ID,
+ status: '0' // 鍙煡璇㈡甯哥姸鎬佺敤鎴�
+})
+```
+
+### 鏁版嵁缁撴瀯
+
+#### selectedStaff锛堝凡閫夋嫨浜哄憳锛�
+```javascript
+[
+ {
+ userId: 鐢ㄦ埛ID,
+ nickName: '濮撳悕',
+ phonenumber: '鎵嬫満鍙�',
+ deptName: '閮ㄩ棬鍚嶇О',
+ postName: '宀椾綅鍚嶇О',
+ roleName: '瑙掕壊鍚嶇О',
+ type: 'driver|nurse|other'
+ }
+]
+```
+
+### 浜哄憳绫诲瀷鍒ゆ柇瑙勫垯
+鏍规嵁鐢ㄦ埛鐨勫矖浣嶅悕绉版垨瑙掕壊鍚嶇О鍒ゆ柇锛�
+- 鍖呭惈"鍙告満"鍏抽敭瀛� 鈫� `type: 'driver'`
+- 鍖呭惈"鎶ゅ+"鍏抽敭瀛� 鈫� `type: 'nurse'`
+- 鍏朵粬 鈫� `type: 'other'`
+
+### 鍏抽敭鏂规硶
+
+#### 1. `initSelectedStaff()`
+鍒濆鍖栧凡閫変汉鍛樺垪琛紝榛樿鍖呭惈褰撳墠鐢ㄦ埛
+
+#### 2. `loadDeptStaff()`
+鍔犺浇褰撳墠鐢ㄦ埛鎵�鍦ㄩ儴闂ㄧ殑鎵�鏈変汉鍛�
+
+#### 3. `getUserType(user)`
+鏍规嵁宀椾綅鍜岃鑹插垽鏂敤鎴风被鍨�
+
+#### 4. `showStaffSelector()`
+鏄剧ず浜哄憳閫夋嫨寮圭獥
+
+#### 5. `filterStaff(type)`
+鎸夌被鍨嬬瓫閫変汉鍛橈紙鍏ㄩ儴/鍙告満/鎶ゅ+锛�
+
+#### 6. `onStaffSearch(e)`
+澶勭悊鎼滅储杈撳叆锛屽疄鏃惰繃婊や汉鍛樺垪琛�
+
+#### 7. `toggleStaffSelection(staff)`
+鍒囨崲浜哄憳閫変腑鐘舵��
+
+#### 8. `isStaffSelected(userId)`
+鍒ゆ柇浜哄憳鏄惁宸查�変腑
+
+#### 9. `confirmStaffSelection()`
+纭浜哄憳閫夋嫨锛屽叧闂脊绐�
+
+#### 10. `removeStaff(index)`
+浠庡凡閫夊垪琛ㄤ腑绉婚櫎浜哄憳锛堝綋鍓嶇敤鎴烽櫎澶栵級
+
+## UI璁捐
+
+### 涓荤晫闈㈠睍绀�
+```
+鎵ц浠诲姟浜哄憳
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 寮犱笁 (鍙告満) 鉁� 鈹� <- 褰撳墠鐢ㄦ埛锛屼笉鍙Щ闄�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鏉庡洓 (鎶ゅ+) 鉁� 鈹� <- 鍙Щ闄�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� + 娣诲姞浜哄憳 鈹� <- 鎵撳紑閫夋嫨寮圭獥
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+### 閫夋嫨寮圭獥甯冨眬
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 閫夋嫨鎵ц浜哄憳 鉁� 鈹� <- 鏍囬鏍�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 馃攳 鎼滅储濮撳悕銆佹墜鏈哄彿 鈹� <- 鎼滅储妗�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� [鍏ㄩ儴] [鍙告満] [鎶ゅ+] 鈹� <- 绫诲瀷绛涢��
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鈹�
+鈹� 寮犱笁 138****1234 鈹� <- 浜哄憳鍒楄〃
+鈹� 骞垮窞鍒嗗叕鍙� | 鍙告満 鉁� 鈹�
+鈹� 鈹�
+鈹� 鏉庡洓 139****5678 鈹�
+鈹� 骞垮窞鍒嗗叕鍙� | 鎶ゅ+ 鈼� 鈹�
+鈹� 鈹�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� [鍙栨秷] [纭畾(宸查��2)] 鈹� <- 搴曢儴鎿嶄綔鏍�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+## 鏍峰紡鐗圭偣
+
+### 棰滆壊鏂规
+- 涓昏壊锛歚#007AFF`锛堣摑鑹诧級
+- 鍒犻櫎鑹诧細`#ff4d4f`锛堢孩鑹诧級
+- 鑳屾櫙鑹诧細`#f5f5f5`锛堟祬鐏帮級
+- 杈规鑹诧細`#f0f0f0`锛堟祬鐏帮級
+
+### 浜や簰鍙嶉
+- 鐐瑰嚮浜哄憳椤规椂鏄剧ず鑳屾櫙鑹插彉鍖�
+- 宸查�変腑鏄剧ず钃濊壊鍕鹃�夊浘鏍�
+- 鏈�変腑鏄剧ず鐏拌壊绌哄績鍦嗗湀
+- 鎸夐挳鏀寔绂佺敤鐘舵��
+
+## 鏁版嵁娴佽浆
+
+### 1. 椤甸潰鍔犺浇
+```
+onLoad
+ 鈫�
+initSelectedStaff() - 鍒濆鍖栧綋鍓嶇敤鎴�
+ 鈫�
+loadDeptStaff() - 鍔犺浇閮ㄩ棬浜哄憳
+ 鈫�
+filterStaffList() - 鍒濆鍖栬繃婊ゅ垪琛�
+```
+
+### 2. 浜哄憳閫夋嫨
+```
+鐐瑰嚮"娣诲姞浜哄憳"
+ 鈫�
+showStaffSelector() - 鎵撳紑寮圭獥
+ 鈫�
+鐢ㄦ埛绛涢��/鎼滅储
+ 鈫�
+toggleStaffSelection() - 鍒囨崲閫変腑
+ 鈫�
+confirmStaffSelection() - 纭閫夋嫨
+ 鈫�
+鏇存柊 selectedStaff
+ 鈫�
+鍏抽棴寮圭獥
+```
+
+### 3. 浠诲姟鎻愪氦
+```
+submitTask()
+ 鈫�
+buildSubmitData()
+ 鈫�
+鎻愬彇 assigneeIds: selectedStaff.map(staff => staff.userId)
+ 鈫�
+鎻愪氦鍒板悗绔�
+```
+
+## 娉ㄦ剰浜嬮」
+
+### 1. 褰撳墠鐢ㄦ埛淇濇姢
+- 褰撳墠鐢ㄦ埛濮嬬粓鍦ㄥ凡閫夊垪琛ㄧ涓�浣�
+- 涓嶅厑璁哥Щ闄ゅ綋鍓嶇敤鎴�
+- 绉婚櫎鎿嶄綔浼氭鏌ョ储寮曪紝index=0鏃舵彁绀轰笉鑳界Щ闄�
+
+### 2. 鏁版嵁楠岃瘉
+- 鎻愪氦鍓嶆鏌ヨ嚦灏戦�夋嫨涓�鍚嶄汉鍛�
+- 纭閫夋嫨鏃堕獙璇佸凡閫夊垪琛ㄤ笉涓虹┖
+
+### 3. 鎬ц兘浼樺寲
+- 浜哄憳鍒楄〃鎸夐渶鍔犺浇
+- 鎼滅储鍜岀瓫閫夊疄鏃跺搷搴�
+- 浣跨敤绱㈠紩浼樺寲鍒楄〃娓叉煋
+
+### 4. 鐢ㄦ埛浣撻獙
+- 搴曢儴鏄剧ず宸查�変汉鍛樻暟閲�
+- 鎼滅储鏀寔妯$硦鍖归厤
+- 绫诲瀷绛涢�夋敮鎸佸揩閫熷畾浣�
+- 寮圭獥楂樺害鑷�傚簲锛屾渶澶�80vh
+
+## 鎵╁睍鍔熻兘锛堝緟寮�鍙戯級
+
+1. **浜哄憳璇︽儏**锛氱偣鍑讳汉鍛樻煡鐪嬭缁嗕俊鎭�
+2. **鎵归噺閫夋嫨**锛氭敮鎸佸叏閫�/鍏ㄤ笉閫�
+3. **甯哥敤浜哄憳**锛氳褰曞父鐢ㄦ惌妗o紝蹇�熼�夋嫨
+4. **浜哄憳鐘舵��**锛氭樉绀轰汉鍛樺綋鍓嶄换鍔$姸鎬�
+5. **鏉冮檺鎺у埗**锛氭牴鎹换鍔$被鍨嬮檺鍒跺彲閫変汉鍛樿寖鍥�
+
+## 鐩稿叧鏂囦欢
+
+### 鍓嶇鏂囦欢
+- `app/pages/task/create-emergency.vue` - 鎬ユ晳杞繍浠诲姟鍒涘缓椤甸潰
+- `app/api/system/user.js` - 鐢ㄦ埛API鎺ュ彛
+
+### 鍚庣鏂囦欢
+- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java` - 鐢ㄦ埛Controller
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java` - 鐢ㄦ埛Service鎺ュ彛
+
+## 娴嬭瘯瑕佺偣
+
+1. 鉁� 榛樿鍖呭惈褰撳墠鐢ㄦ埛
+2. 鉁� 褰撳墠鐢ㄦ埛涓嶅彲绉婚櫎
+3. 鉁� 娣诲姞鍏朵粬浜哄憳
+4. 鉁� 绉婚櫎鍏朵粬浜哄憳
+5. 鉁� 鎸夌被鍨嬬瓫閫夛紙鍏ㄩ儴/鍙告満/鎶ゅ+锛�
+6. 鉁� 鎸夊鍚嶆悳绱�
+7. 鉁� 鎸夋墜鏈哄彿鎼滅储
+8. 鉁� 澶氶�変汉鍛�
+9. 鉁� 鍙栨秷閫夋嫨
+10. 鉁� 纭閫夋嫨
+11. 鉁� 宸查�変汉鍛樻暟閲忔樉绀�
+12. 鉁� 鎻愪氦浠诲姟鏃跺寘鍚汉鍛業D鍒楄〃
diff --git "a/prd/\346\200\245\346\225\221\350\275\254\350\277\220\347\227\205\346\203\205\351\200\211\346\213\251\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\346\200\245\346\225\221\350\275\254\350\277\220\347\227\205\346\203\205\351\200\211\346\213\251\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..11d163d
--- /dev/null
+++ "b/prd/\346\200\245\346\225\221\350\275\254\350\277\220\347\227\205\346\203\205\351\200\211\346\213\251\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,388 @@
+# 鎬ユ晳杞繍浠诲姟 - 鐥呮儏閫夋嫨鍔熻兘锛圛CD-10锛夎鏄�
+
+## 鍔熻兘姒傝堪
+鍦ㄥ垱寤烘�ユ晳杞繍浠诲姟鏃讹紝鍙互浠嶴QL Server鐨処CD-10鐤剧梾鍒嗙被鏁版嵁搴撲腑閫夋嫨鏍囧噯鍖栫殑鐤剧梾璇婃柇锛屾敮鎸佸涓梾鎯呭悓鏃舵坊鍔狅紝骞跺彲琛ュ厖鍏朵粬鐥呮儏鎻忚堪銆�
+
+## 鏁版嵁搴撹〃缁撴瀯
+
+### ICD10琛紙SQL Server锛�
+```sql
+琛ㄥ悕: ICD10
+瀛楁:
+- id: 涓婚敭ID
+- icd_code: ICD缂栫爜锛堝锛欰00.0锛�
+- icd_name: 鐤剧梾鍚嶇О锛堝锛氶湇涔憋級
+- zjm: 鍔╄鐮侊紙鐢ㄤ簬蹇�熸悳绱級
+- sm: 鐤剧梾璇存槑
+- ICDState: 鐘舵�侊紙1=鍚敤锛�
+```
+
+## 鍔熻兘鐗规��
+
+### 1. 鐥呮儏鏍囩灞曠ず
+- 宸查�夋嫨鐨勭梾鎯呬互褰╄壊鏍囩褰㈠紡灞曠ず
+- 姣忎釜鏍囩鏄剧ず鐤剧梾鍚嶇О
+- 鐐瑰嚮鏍囩涓婄殑 鉁� 鍙Щ闄よ鐥呮儏
+
+### 2. 娣诲姞鐥呮儏
+- 鐐瑰嚮"娣诲姞鐥呮儏"鎸夐挳鎵撳紑閫夋嫨寮圭獥
+- 寮圭獥搴曢儴寮瑰嚭锛屽崰80%灞忓箷楂樺害
+
+### 3. 鎼滅储鍔熻兘
+鏀寔澶氱鏂瑰紡鎼滅储锛�
+- **鎸夌柧鐥呭悕绉�**锛氬"鑲虹値"
+- **鎸塈CD缂栫爜**锛氬"J18"
+- **鎸夊姪璁扮爜**锛氬"FY"
+
+瀹炴椂闃叉姈鎼滅储锛�300ms寤惰繜
+
+### 4. 鎼滅储缁撴灉灞曠ず
+姣忔潯缁撴灉鏄剧ず锛�
+- 鐤剧梾鍚嶇О锛堢矖浣擄級
+- ICD缂栫爜锛堣摑鑹叉爣绛撅級
+- 鐤剧梾璇存槑锛堢伆鑹插皬瀛楋級
+- 閫変腑鐘舵�侊紙鉁� 鎴栫┖蹇冨渾鍦堬級
+
+### 5. 澶氶�夋搷浣�
+- 鐐瑰嚮鐤剧梾鏉$洰鍒囨崲閫変腑鐘舵��
+- 搴曢儴鏄剧ず"纭畾(宸查�塏)"
+- 鏀寔鍚屾椂閫夋嫨澶氫釜鐥呮儏
+
+### 6. 琛ュ厖鎻忚堪
+- 闄や簡閫夋嫨鏍囧噯鐤剧梾澶�
+- 杩樺彲浠ュ湪鏂囨湰妗嗕腑琛ュ厖鍏朵粬鐥呮儏鎻忚堪
+- 鏈�缁堟彁浜ゆ椂浼氬悎骞舵墍鏈夌梾鎯呬俊鎭�
+
+## 瀹炵幇缁嗚妭
+
+### 鍚庣瀹炵幇
+
+#### 1. 瀹炰綋绫�
+**鏂囦欢**: `Icd10.java`
+```java
+public class Icd10 {
+ private Integer id;
+ private String icdCode;
+ private String icdName;
+ private String zjm;
+ private String sm;
+ // ... 鍏朵粬瀛楁
+}
+```
+
+#### 2. Mapper鎺ュ彛
+**鏂囦欢**: `Icd10Mapper.java`
+```java
+@DataSource(DataSourceType.SQLSERVER)
+public interface Icd10Mapper {
+ List<Icd10> searchIcd10(@Param("keyword") String keyword);
+}
+```
+
+#### 3. Mapper XML
+**鏂囦欢**: `Icd10Mapper.xml`
+```xml
+<select id="searchIcd10" resultMap="Icd10Result">
+ SELECT TOP 50 ...
+ FROM ICD10
+ WHERE (icd_name LIKE '%' + #{keyword} + '%'
+ OR icd_code LIKE '%' + #{keyword} + '%'
+ OR zjm LIKE '%' + #{keyword} + '%')
+ AND ICDState = 1
+ ORDER BY icd_name
+</select>
+```
+
+娉ㄦ剰锛氫娇鐢⊿QL Server璇硶
+
+#### 4. Controller
+**鏂囦欢**: `Icd10Controller.java`
+```java
+@RestController
+@RequestMapping("/system/icd10")
+public class Icd10Controller {
+ @GetMapping("/search")
+ public AjaxResult searchIcd10(@RequestParam String keyword) {
+ List<Icd10> list = icd10Mapper.searchIcd10(keyword);
+ return success(list);
+ }
+}
+```
+
+### 鍓嶇瀹炵幇
+
+#### 1. API鎺ュ彛
+**鏂囦欢**: `app/api/icd10.js`
+```javascript
+export function searchIcd10(keyword) {
+ return request({
+ url: '/system/icd10/search',
+ method: 'get',
+ params: { keyword }
+ })
+}
+```
+
+#### 2. 鏁版嵁缁撴瀯
+
+**selectedDiseases**锛堝凡閫夌柧鐥呭垪琛級
+```javascript
+[
+ {
+ id: 鐤剧梾ID,
+ icdCode: 'ICD缂栫爜',
+ icdName: '鐤剧梾鍚嶇О',
+ sm: '鐤剧梾璇存槑'
+ }
+]
+```
+
+**tempSelectedDiseases**锛堜复鏃堕�夋嫨鍒楄〃锛�
+- 鍦ㄥ脊绐椾腑浣跨敤
+- 纭鍚庢墠鍚屾鍒� selectedDiseases
+
+#### 3. 鍏抽敭鏂规硶
+
+**showDiseaseSelector()**
+- 鎵撳紑鐥呮儏閫夋嫨寮圭獥
+- 鍒濆鍖栦复鏃堕�夋嫨鍒楄〃
+
+**onDiseaseSearch(e)**
+- 澶勭悊鎼滅储杈撳叆
+- 300ms闃叉姈寤惰繜
+
+**searchDiseaseByKeyword(keyword)**
+- 璋冪敤鍚庣API鎼滅储鐤剧梾
+- 鏇存柊鎼滅储缁撴灉鍒楄〃
+
+**toggleDiseaseSelection(disease)**
+- 鍒囨崲鐤剧梾閫変腑鐘舵��
+- 娣诲姞/绉婚櫎涓存椂鍒楄〃
+
+**confirmDiseaseSelection()**
+- 纭閫夋嫨
+- 鍚屾涓存椂鍒楄〃鍒版寮忓垪琛�
+- 鍏抽棴寮圭獥
+
+**removeDisease(index)**
+- 绉婚櫎宸查�夌柧鐥呮爣绛�
+
+**buildSubmitData()**
+- 鍚堝苟鐥呮儏淇℃伅
+- 鏍煎紡锛歚鐤剧梾1(缂栫爜1)銆佺柧鐥�2(缂栫爜2)\n鍏朵粬锛氳ˉ鍏呮弿杩癭
+
+## UI璁捐
+
+### 涓荤晫闈㈠睍绀�
+```
+鐥呮儏
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� [鑲虹値(J18.9)] [绯栧翱鐥�(E11)] 鉁椻攤 <- 宸查�夌柧鐥呮爣绛�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� + 娣诲姞鐥呮儏 鈹� <- 鎵撳紑閫夋嫨寮圭獥
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鍏朵粬鐥呮儏鎻忚堪锛堥�夊~锛� 鈹� <- 琛ュ厖鎻忚堪
+鈹� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+### 閫夋嫨寮圭獥甯冨眬
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 閫夋嫨鐥呮儏锛圛CD-10锛� 鉁� 鈹� <- 鏍囬鏍�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 馃攳 鎼滅储鐤剧梾鍚嶇О銆佺紪鐮佺瓑 鈹� <- 鎼滅储妗�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鈹�
+鈹� 鑲虹値 [J18.9] 鈹� <- 鎼滅储缁撴灉
+鈹� 鐢辨湭鐗规寚鐨勭梾鍘熶綋鎵�鑷寸殑... 鈹�
+鈹� 鉁� 鈹�
+鈹� 鈹�
+鈹� 鏀皵绠$値 [J40] 鈹�
+鈹� 鏈寚鏄庝负鎬ユ�ф垨鎱㈡�х殑... 鈹�
+鈹� 鈼� 鈹�
+鈹� 鈹�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� [鍙栨秷] [纭畾(宸查��2)] 鈹� <- 搴曢儴鎿嶄綔鏍�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+## 鏍峰紡鐗圭偣
+
+### 鐤剧梾鏍囩
+- 娓愬彉绱壊鑳屾櫙锛歚linear-gradient(135deg, #667eea 0%, #764ba2 100%)`
+- 鍦嗚璁捐锛歚border-radius: 30rpx`
+- 鐧借壊鏂囧瓧
+- 鍒犻櫎鎸夐挳锛堢櫧鑹� 鉁楋級
+
+### ICD缂栫爜鏍囩
+- 钃濊壊鑳屾櫙锛歚#e6f2ff`
+- 钃濊壊鏂囧瓧锛歚#007AFF`
+- 灏忓渾瑙掞細`border-radius: 6rpx`
+
+### 鎼滅储妗�
+- 鐏拌壊鑳屾櫙锛歚#f5f5f5`
+- 鎼滅储鍥炬爣
+- 鎻愮ず鏂囧瓧锛氭悳绱㈢柧鐥呭悕绉般�佺紪鐮佹垨鍔╄鐮�
+
+## 鏁版嵁娴佽浆
+
+### 1. 鎵撳紑寮圭獥
+```
+鐐瑰嚮"娣诲姞鐥呮儏"
+ 鈫�
+showDiseaseSelector()
+ 鈫�
+鍒濆鍖� tempSelectedDiseases
+ 鈫�
+鎵撳紑寮圭獥
+```
+
+### 2. 鎼滅储閫夋嫨
+```
+杈撳叆鍏抽敭璇�
+ 鈫�
+onDiseaseSearch() - 闃叉姈300ms
+ 鈫�
+searchDiseaseByKeyword()
+ 鈫�
+璋冪敤API: searchIcd10(keyword)
+ 鈫�
+鏄剧ず鎼滅储缁撴灉
+ 鈫�
+鐐瑰嚮鐤剧梾
+ 鈫�
+toggleDiseaseSelection()
+ 鈫�
+鏇存柊涓存椂閫夋嫨鍒楄〃
+```
+
+### 3. 纭鎻愪氦
+```
+鐐瑰嚮"纭畾"
+ 鈫�
+confirmDiseaseSelection()
+ 鈫�
+selectedDiseases = tempSelectedDiseases
+ 鈫�
+鍏抽棴寮圭獥
+ 鈫�
+鏄剧ず鐤剧梾鏍囩
+ 鈫�
+鎻愪氦浠诲姟
+ 鈫�
+buildSubmitData()
+ 鈫�
+鍚堝苟鐥呮儏淇℃伅锛�
+ - 鐤剧梾鍚嶇О(缂栫爜)銆佺柧鐥�2(缂栫爜2)
+ - 鍏朵粬锛氳ˉ鍏呮弿杩�
+```
+
+## 鎻愪氦鏁版嵁鏍煎紡
+
+```javascript
+{
+ patient: {
+ // ... 鍏朵粬鎮h�呬俊鎭�
+ condition: "鑲虹値(J18.9)銆佺硸灏跨梾(E11)\n鍏朵粬锛氭偅鑰呭彂鐑�3澶�",
+ diseases: [
+ {
+ icdId: 1,
+ icdCode: "J18.9",
+ icdName: "鑲虹値"
+ },
+ {
+ icdId: 2,
+ icdCode: "E11",
+ icdName: "绯栧翱鐥�"
+ }
+ ]
+ }
+}
+```
+
+## 浣跨敤鍦烘櫙
+
+### 鍦烘櫙1锛氶�夋嫨鍗曚釜鏍囧噯鐤剧梾
+1. 鐐瑰嚮"娣诲姞鐥呮儏"
+2. 鎼滅储"鑲虹値"
+3. 閫夋嫨"鑲虹値(J18.9)"
+4. 鐐瑰嚮纭畾
+5. 缁撴灉锛氭樉绀� [鑲虹値(J18.9)] 鏍囩
+
+### 鍦烘櫙2锛氶�夋嫨澶氫釜鐤剧梾
+1. 鐐瑰嚮"娣诲姞鐥呮儏"
+2. 鎼滅储"鑲虹値"锛岄�夋嫨
+3. 缁х画鎼滅储"绯栧翱鐥�"锛岄�夋嫨
+4. 鐐瑰嚮纭畾
+5. 缁撴灉锛氭樉绀� [鑲虹値(J18.9)] [绯栧翱鐥�(E11)]
+
+### 鍦烘櫙3锛氭爣鍑嗙柧鐥� + 琛ュ厖鎻忚堪
+1. 閫夋嫨鏍囧噯鐤剧梾
+2. 鍦�"鍏朵粬鐥呮儏鎻忚堪"妗嗕腑杈撳叆"鎮h�呭彂鐑�3澶�"
+3. 鎻愪氦鏃跺悎骞讹細`鑲虹値(J18.9)\n鍏朵粬锛氭偅鑰呭彂鐑�3澶ー
+
+## 娉ㄦ剰浜嬮」
+
+### 1. 鏁版嵁婧愰厤缃�
+- ICD10琛ㄥ湪SQL Server鏁版嵁搴�
+- Mapper蹇呴』娣诲姞 `@DataSource(DataSourceType.SQLSERVER)`
+- SQL璇硶浣跨敤SQL Server鏍煎紡锛坄TOP`銆乣+` 鎷兼帴锛�
+
+### 2. 鎼滅储浼樺寲
+- 闃叉姈寤惰繜锛�300ms
+- 鏈�澶氳繑鍥�50鏉$粨鏋�
+- 鍙煡璇㈠惎鐢ㄧ姸鎬佺殑鐤剧梾锛圛CDState = 1锛�
+
+### 3. 鐢ㄦ埛浣撻獙
+- 鎼滅储瀹炴椂鍝嶅簲
+- 澶氶�夋敮鎸�
+- 宸查�夋暟閲忔彁绀�
+- 鍒犻櫎鎿嶄綔绠�渚�
+
+### 4. 鏁版嵁瀹屾暣鎬�
+- 鏀寔绾爣鍑嗙柧鐥�
+- 鏀寔绾枃鏈弿杩�
+- 鏀寔娣峰悎妯″紡
+- 鐤剧梾ID鍗曠嫭瀛樺偍锛屼究浜庣粺璁�
+
+## 鎵╁睍鍔熻兘锛堝緟寮�鍙戯級
+
+1. **甯哥敤鐤剧梾**锛氳褰曞父鐢ㄧ柧鐥咃紝蹇�熼�夋嫨
+2. **鐤剧梾鍒嗙被**锛氭寜绯荤粺鍒嗙被娴忚
+3. **鍘嗗彶璁板綍**锛氭樉绀烘渶杩戦�夋嫨鐨勭柧鐥�
+4. **鐤剧梾璇︽儏**锛氱偣鍑绘煡鐪嬪畬鏁碔CD-10淇℃伅
+5. **鎵归噺瀵煎叆**锛氭敮鎸佷粠鐥呭巻绯荤粺瀵煎叆璇婃柇
+
+## 鐩稿叧鏂囦欢
+
+### 鍚庣鏂囦欢
+- `ruoyi-system/src/main/java/com/ruoyi/system/domain/Icd10.java` - 瀹炰綋绫�
+- `ruoyi-system/src/main/java/com/ruoyi/system/mapper/Icd10Mapper.java` - Mapper鎺ュ彛
+- `ruoyi-system/src/main/resources/mapper/system/Icd10Mapper.xml` - MyBatis鏄犲皠
+- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/Icd10Controller.java` - Controller
+
+### 鍓嶇鏂囦欢
+- `app/api/icd10.js` - API鎺ュ彛
+- `app/pages/task/create-emergency.vue` - 鎬ユ晳杞繍浠诲姟鍒涘缓椤甸潰
+
+### 鏁版嵁搴撴枃浠�
+- `sql/icd10.sql` - ICD-10琛ㄧ粨鏋�
+
+## 娴嬭瘯瑕佺偣
+
+1. 鉁� 鎼滅储鐤剧梾鍚嶇О
+2. 鉁� 鎼滅储ICD缂栫爜
+3. 鉁� 鎼滅储鍔╄鐮�
+4. 鉁� 閫夋嫨鍗曚釜鐤剧梾
+5. 鉁� 閫夋嫨澶氫釜鐤剧梾
+6. 鉁� 绉婚櫎宸查�夌柧鐥�
+7. 鉁� 琛ュ厖鏂囨湰鎻忚堪
+8. 鉁� 鍙湁鏂囨湰鎻忚堪锛堜笉閫夌柧鐥咃級
+9. 鉁� 鍙�夌柧鐥咃紙涓嶅~鎻忚堪锛�
+10. 鉁� 娣峰悎妯″紡锛堢柧鐥�+鎻忚堪锛�
+11. 鉁� 鍙栨秷閫夋嫨
+12. 鉁� 鎻愪氦鏁版嵁鏍煎紡姝g‘
+13. 鉁� SQL Server鏁版嵁婧愬垏鎹㈡纭�
+14. 鉁� 闃叉姈鎼滅储鐢熸晥
+15. 鉁� 宸查�夋暟閲忔樉绀烘纭�
diff --git "a/prd/\347\224\250\346\210\267\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\347\224\250\346\210\267\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..c321334
--- /dev/null
+++ "b/prd/\347\224\250\346\210\267\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,348 @@
+# 鐢ㄦ埛鍚屾鍔熻兘璇存槑鏂囨。
+
+## 馃搵 鍔熻兘姒傝堪
+浠嶴QL Server鐨刞OA_User`琛ㄥ悓姝ョ敤鎴锋暟鎹埌鑻ヤ緷绯荤粺鐨刞sys_user`琛紝骞堕�氳繃`department_id`瀛楁鍏宠仈閮ㄩ棬銆�
+
+## 馃幆 鏁版嵁婧�
+
+### SQL鏌ヨ
+```sql
+SELECT
+ OA_User_ID as OA_UserID,
+ OA_User as user_name,
+ OA_Name as nick_name,
+ OA_departmentID as department_id,
+ OA_gender as sex,
+ OA_email as email,
+ OA_mobile as phonenumber
+FROM OA_User
+WHERE OA_User IS NOT NULL
+ AND OA_Name IS NOT NULL
+```
+
+### 瀛楁鏄犲皠鍏崇郴
+| SQL Server瀛楁 | 鑻ヤ緷瀛楁 | 璇存槑 |
+|---------------|---------|------|
+| OA_User_ID | oa_user_id | OA鐢ㄦ埛ID锛堝敮涓�鏍囪瘑锛� |
+| OA_User | user_name | 鐢ㄦ埛璐﹀彿 |
+| OA_Name | nick_name | 鐢ㄦ埛鏄电О |
+| OA_departmentID | department_id | 閮ㄩ棬ID锛堥�氳繃姝ゅ瓧娈靛叧鑱攕ys_dept锛� |
+| OA_gender | sex | 鎬у埆 |
+| OA_email | email | 閭 |
+| OA_mobile | phonenumber | 鎵嬫満鍙� |
+
+## 馃敤 瀹炵幇鍐呭
+
+### 1. 鏁版嵁搴撲慨鏀�
+
+#### 琛ㄧ粨鏋勫彉鏇�
+```sql
+-- 鍦╯ys_user琛ㄤ腑娣诲姞oa_user_id瀛楁
+ALTER TABLE sys_user ADD COLUMN oa_user_id INT NULL COMMENT 'SQL Server涓殑OA鐢ㄦ埛ID';
+CREATE INDEX idx_oa_user_id ON sys_user(oa_user_id);
+```
+
+**鏂囦欢**: `sql/add_oa_user_id_to_sys_user.sql`
+
+### 2. 瀹炰綋绫讳慨鏀�
+
+#### SysUser瀹炰綋
+**鏂囦欢**: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java`
+
+**淇敼鍐呭**:
+```java
+/** SQL Server涓殑OA鐢ㄦ埛ID */
+private Integer oaUserId;
+
+public Integer getOaUserId() { return oaUserId; }
+public void setOaUserId(Integer oaUserId) { this.oaUserId = oaUserId; }
+```
+
+### 3. 鏍稿績鏂囦欢
+
+#### DTO灞�
+**鏂囦欢**: `UserSyncDTO.java`
+- 瀛楁: oaUserId, userName, nickName, departmentId, sex, email, phonenumber
+
+#### Mapper灞�
+**鏂囦欢**:
+- `UserSyncMapper.java` - 鏌ヨSQL Server鐢ㄦ埛鏁版嵁
+- `UserSyncMapper.xml` - SQL鏄犲皠
+- `SysUserMapper.java`锛堟墿灞曪級 - 娣诲姞鏍规嵁oaUserId鏌ヨ鏂规硶
+- `SysUserMapper.xml`锛堟墿灞曪級 - 娣诲姞瀛楁鏄犲皠鍜屾煡璇QL
+
+#### Service灞�
+**鏂囦欢**: `UserSyncServiceImpl.java`
+
+**鏍稿績閫昏緫**:
+1. 浠嶴QL Server鏌ヨOA_User鏁版嵁
+2. 閬嶅巻姣忔潯鐢ㄦ埛鏁版嵁
+3. 鏍规嵁department_id鏌ユ壘瀵瑰簲鐨刣ept_id
+4. 妫�鏌ョ敤鎴锋槸鍚﹀凡瀛樺湪锛堟牴鎹畂a_user_id锛�
+5. 宸插瓨鍦ㄥ垯鏇存柊锛屼笉瀛樺湪鍒欏垱寤�
+6. 璁板綍鍚屾缁熻淇℃伅
+
+#### Controller灞�
+**鏂囦欢**: `DepartmentSyncController.java`锛堟墿灞曪級
+
+**鎺ュ彛**:
+- `POST /system/dept/sync/user` - 鍚屾OA鐢ㄦ埛
+- 鏉冮檺: `system:user:sync`
+
+## 馃攳 鍚屾閫昏緫璇﹁В
+
+### 閮ㄩ棬鍏宠仈閫昏緫
+```
+1. 鑾峰彇OA_User鐨凮A_departmentID
+ 鈫�
+2. 鍦╯ys_dept琛ㄤ腑鏌ヨdepartment_id = OA_departmentID鐨勮褰�
+ 鈫�
+3. 鎵惧埌鍒欎娇鐢ㄨdept_id
+ 鈫�
+4. 鏈壘鍒板垯浣跨敤榛樿閮ㄩ棬(100-鑻ヤ緷绉戞妧)
+```
+
+### 鐢ㄦ埛鍒涘缓/鏇存柊閫昏緫
+```
+1. 鏍规嵁oa_user_id鏌ヨ鐢ㄦ埛
+ 鈫�
+2. 濡傛灉鎵惧埌
+ 鈹溾攢 鏇存柊鐢ㄦ埛淇℃伅锛堟樀绉般�侀儴闂ㄣ�侀偖绠便�佹墜鏈恒�佹�у埆锛�
+ 鈹斺攢 杩斿洖"鏇存柊鐢ㄦ埛"
+ 鈫�
+3. 濡傛灉鏈壘鍒�
+ 鈹溾攢 妫�鏌ョ敤鎴峰悕鏄惁瀛樺湪
+ 鈹� 鈹溾攢 瀛樺湪锛氭洿鏂拌鐢ㄦ埛鐨刼a_user_id鍙婂叾浠栦俊鎭�
+ 鈹� 鈹斺攢 涓嶅瓨鍦細鍒涘缓鏂扮敤鎴�
+ 鈹斺攢 杩斿洖"鍒涘缓鐢ㄦ埛"鎴�"鏇存柊鐢ㄦ埛"
+```
+
+### 榛樿鍊艰缃�
+鍒涘缓鏂扮敤鎴锋椂鐨勯粯璁ゅ�硷細
+- **榛樿瀵嗙爜**: `123456`锛堝姞瀵嗗瓨鍌級
+- **榛樿閮ㄩ棬**: 100锛堣嫢渚濈鎶�锛�
+- **榛樿鎬у埆**: 2锛堟湭鐭ワ級
+- **榛樿鐘舵��**: 0锛堟甯革級
+- **鍒涘缓鑰�**: sync
+
+## 馃搳 鎺ュ彛璇存槑
+
+### 鍚屾鎺ュ彛
+- **URL**: `POST /system/dept/sync/user`
+- **鏉冮檺**: `system:user:sync`
+- **杩斿洖鏁版嵁**:
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 15, 鏇存柊鐢ㄦ埛: 5, 璺宠繃: 2, 澶辫触: 0",
+ "data": {
+ "created": 15,
+ "updated": 5,
+ "skipped": 2,
+ "error": 0,
+ "totalProcessed": 22
+ }
+}
+```
+
+### 杩斿洖瀛楁璇存槑
+- **created**: 鍒涘缓鐨勭敤鎴锋暟閲�
+- **updated**: 鏇存柊鐨勭敤鎴锋暟閲�
+- **skipped**: 璺宠繃鐨勭敤鎴锋暟閲忥紙鏁版嵁涓嶅畬鏁达級
+- **error**: 澶辫触鐨勭敤鎴锋暟閲�
+- **totalProcessed**: 鎬诲鐞嗘暟閲�
+
+## 馃殌 浣跨敤姝ラ
+
+### 1. 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+# 鍏堝悓姝ラ儴闂紙鐢ㄦ埛鍚屾渚濊禆閮ㄩ棬鏁版嵁锛�
+mysql -u root -p ry-vue < sql/add_department_id_to_sys_dept.sql
+
+# 鍐嶆坊鍔犵敤鎴峰瓧娈�
+mysql -u root -p ry-vue < sql/add_oa_user_id_to_sys_user.sql
+```
+
+### 2. 鍚屾閮ㄩ棬锛堝繀椤诲厛鎵ц锛�
+```bash
+POST http://localhost:8080/system/dept/sync/branch
+```
+
+### 3. 鍚屾鐢ㄦ埛
+```bash
+POST http://localhost:8080/system/dept/sync/user
+Headers:
+ Authorization: Bearer {浣犵殑token}
+```
+
+## 馃挕 浣跨敤绀轰緥
+
+### 杈撳叆鏁版嵁锛圫QL Server OA_User琛級
+```
+OA_User_ID | OA_User | OA_Name | OA_departmentID | OA_gender | OA_email | OA_mobile
+1001 | zhangsan | 寮犱笁 | 1001 | 0 | zhangsan@qq.com | 13800138001
+1002 | lisi | 鏉庡洓 | 1001 | 1 | lisi@qq.com | 13800138002
+1003 | wangwu | 鐜嬩簲 | 1002 | 0 | wangwu@qq.com | 13800138003
+```
+
+### 澶勭悊杩囩▼
+```
+1. 鐢ㄦ埛zhangsan:
+ - OA_departmentID=1001 鈫� 鏌ヨsys_dept鎵惧埌dept_id=201锛堟姢澹儴闂級
+ - 妫�鏌a_user_id=1001鐨勭敤鎴� 鈫� 涓嶅瓨鍦�
+ - 妫�鏌ョ敤鎴峰悕zhangsan 鈫� 涓嶅瓨鍦�
+ - 鍒涘缓鏂扮敤鎴�: userName=zhangsan, deptId=201, password=123456(鍔犲瘑)
+
+2. 鐢ㄦ埛lisi:
+ - OA_departmentID=1001 鈫� dept_id=201
+ - 妫�鏌a_user_id=1002鐨勭敤鎴� 鈫� 涓嶅瓨鍦�
+ - 妫�鏌ョ敤鎴峰悕lisi 鈫� 宸插瓨鍦紙涔嬪墠鎵嬪姩鍒涘缓鐨勶級
+ - 鏇存柊鐢ㄦ埛: 璁剧疆oaUserId=1002, deptId=201
+
+3. 鐢ㄦ埛wangwu:
+ - OA_departmentID=1002 鈫� dept_id=202锛堣溅闃熼儴闂級
+ - 妫�鏌a_user_id=1003鐨勭敤鎴� 鈫� 涓嶅瓨鍦�
+ - 鍒涘缓鏂扮敤鎴�: userName=wangwu, deptId=202
+```
+
+### 杈撳嚭缁撴灉锛坰ys_user琛級
+```
+user_id | user_name | nick_name | dept_id | oa_user_id | email | phonenumber | password
+101 | zhangsan | 寮犱笁 | 201 | 1001 | zhangsan@qq.com | 13800138001 | $2a$10$...
+102 | lisi | 鏉庡洓 | 201 | 1002 | lisi@qq.com | 13800138002 | (鍘熷瘑鐮�)
+103 | wangwu | 鐜嬩簲 | 202 | 1003 | wangwu@qq.com | 13800138003 | $2a$10$...
+```
+
+## 鈿欙笍 鐗规�ц鏄�
+
+### 1. 骞傜瓑鎬ц璁�
+- 閫氳繃`oa_user_id`鍒ゆ柇鐢ㄦ埛鏄惁宸插瓨鍦�
+- 澶氭鍚屾涓嶄細鍒涘缓閲嶅鐢ㄦ埛
+- 宸插瓨鍦ㄧ敤鎴峰彧浼氭洿鏂颁俊鎭�
+
+### 2. 鏅鸿兘閮ㄩ棬鍏宠仈
+- 閫氳繃`department_id`鑷姩鍏宠仈閮ㄩ棬
+- 鏈壘鍒伴儴闂ㄦ椂浣跨敤榛樿閮ㄩ棬
+- 璁板綍鏃ュ織渚夸簬鎺掓煡
+
+### 3. 鏁版嵁瀹屾暣鎬ч獙璇�
+- 楠岃瘉蹇呭~瀛楁锛堢敤鎴峰悕銆佹樀绉帮級
+- 璺宠繃涓嶅畬鏁寸殑鏁版嵁
+- 璇︾粏璁板綍璺宠繃鍘熷洜
+
+### 4. 閿欒澶勭悊
+- 鍗曚釜鐢ㄦ埛澶辫触涓嶅奖鍝嶆暣浣撳悓姝�
+- 璁板綍閿欒鏃ュ織
+- 杩斿洖璇︾粏鐨勭粺璁′俊鎭�
+
+### 5. 浜嬪姟淇濇姢
+- 浣跨敤`@Transactional`娉ㄨВ
+- 澶辫触鑷姩鍥炴粴
+- 淇濊瘉鏁版嵁涓�鑷存��
+
+## 馃摑 娉ㄦ剰浜嬮」
+
+### 閲嶈鎻愮ず
+1. **蹇呴』鍏堝悓姝ラ儴闂�**: 鐢ㄦ埛鍚屾渚濊禆閮ㄩ棬鏁版嵁锛屽繀椤诲厛鎵ц閮ㄩ棬鍚屾
+2. **榛樿瀵嗙爜**: 鏂板垱寤虹敤鎴风殑榛樿瀵嗙爜涓篳123456`锛屽缓璁娆$櫥褰曞悗淇敼
+3. **閮ㄩ棬鍏宠仈**: 濡傛灉鎵句笉鍒板搴旈儴闂紝灏嗕娇鐢ㄩ粯璁ら儴闂�(100-鑻ヤ緷绉戞妧)
+4. **鏉冮檺閰嶇疆**: 闇�瑕侀厤缃甡system:user:sync`鏉冮檺
+
+### 鎵ц椤哄簭
+```
+1. 鎵цSQL鑴氭湰锛堥儴闂ㄥ拰鐢ㄦ埛锛�
+2. 鍚屾閮ㄩ棬鏁版嵁
+3. 鍚屾鐢ㄦ埛鏁版嵁
+```
+
+## 馃攳 楠岃瘉鏂规硶
+
+### 鏌ョ湅鍚屾鐨勭敤鎴�
+```sql
+-- 鏌ョ湅鎵�鏈夊悓姝ョ殑鐢ㄦ埛锛堟湁oa_user_id鐨勶級
+SELECT u.user_name, u.nick_name, u.oa_user_id, d.dept_name, u.email, u.phonenumber
+FROM sys_user u
+LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
+WHERE u.oa_user_id IS NOT NULL
+ORDER BY u.oa_user_id;
+
+-- 妫�鏌ラ儴闂ㄥ叧鑱旀儏鍐�
+SELECT
+ u.user_name,
+ u.oa_user_id,
+ d.dept_name,
+ d.department_id
+FROM sys_user u
+LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
+WHERE u.oa_user_id IS NOT NULL;
+
+-- 缁熻鍚屾鐢ㄦ埛鏁�
+SELECT
+ COUNT(*) as total_synced_users,
+ COUNT(DISTINCT dept_id) as dept_count
+FROM sys_user
+WHERE oa_user_id IS NOT NULL;
+```
+
+## 馃摎 甯歌闂
+
+### Q1: 鐢ㄦ埛鍚屾鍚庨儴闂ㄤ负绌猴紵
+A: 鍙兘鍘熷洜锛�
+1. 閮ㄩ棬鏁版嵁鏈悓姝ワ紝鍏堟墽琛岄儴闂ㄥ悓姝�
+2. department_id鍦╯ys_dept涓笉瀛樺湪
+3. 鏌ョ湅鏃ュ織涓殑璀﹀憡淇℃伅
+
+### Q2: 鐢ㄦ埛鍚嶉噸澶嶅鑷村垱寤哄け璐ワ紵
+A: 绯荤粺浼氳嚜鍔ㄥ鐞嗭細
+1. 濡傛灉鐢ㄦ埛鍚嶅凡瀛樺湪锛屼細鏇存柊璇ョ敤鎴风殑oa_user_id
+2. 涓嶄細鍒涘缓閲嶅鐢ㄦ埛
+
+### Q3: 鏂扮敤鎴风殑榛樿瀵嗙爜鏄粈涔堬紵
+A: 榛樿瀵嗙爜涓篳123456`锛屽缓璁敤鎴烽娆$櫥褰曞悗淇敼
+
+### Q4: 濡備綍閲嶆柊鍚屾鏌愪釜鐢ㄦ埛锛�
+A: 鐩存帴璋冪敤鍚屾鎺ュ彛鍗冲彲锛岀郴缁熶細鏍规嵁oa_user_id鑷姩鍒ゆ柇鏄垱寤鸿繕鏄洿鏂�
+
+## 馃帗 鏃ュ織鏌ョ湅
+
+鏌ョ湅鍚屾鏃ュ織锛�
+```bash
+tail -f ruoyi-admin/logs/sys-info.log | grep -i "user"
+```
+
+鍏抽敭鏃ュ織绀轰緥锛�
+```
+2025-10-18 15:00:00 INFO UserSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 50 鏉$敤鎴锋暟鎹�
+2025-10-18 15:00:01 INFO UserSyncServiceImpl - 鍒涘缓鏂扮敤鎴�: 寮犱笁 (zhangsan), oaUserId: 1001, deptId: 201
+2025-10-18 15:00:01 INFO UserSyncServiceImpl - 鏇存柊鐢ㄦ埛: 鏉庡洓 (lisi), oaUserId: 1002
+2025-10-18 15:00:01 WARN UserSyncServiceImpl - 鏈壘鍒板搴旂殑閮ㄩ棬: departmentId=9999, 鐢ㄦ埛: test
+2025-10-18 15:00:02 INFO UserSyncServiceImpl - 鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 30, 鏇存柊鐢ㄦ埛: 15, 璺宠繃: 3, 澶辫触: 2
+```
+
+## 馃摝 瀹屾暣鏂囦欢娓呭崟
+
+### SQL鑴氭湰
+- `sql/add_oa_user_id_to_sys_user.sql` - 娣诲姞瀛楁
+
+### Java鏂囦欢
+- `SysUser.java`锛堜慨鏀癸級 - 娣诲姞oaUserId瀛楁
+- `UserSyncDTO.java` - 鐢ㄦ埛鍚屾DTO
+- `UserSyncMapper.java` + XML - 鏌ヨSQL Server鏁版嵁
+- `SysUserMapper.java`锛堟墿灞曪級 - 娣诲姞鏌ヨ鏂规硶
+- `SysUserMapper.xml`锛堟墿灞曪級 - 娣诲姞SQL鏄犲皠
+- `IUserSyncService.java` - Service鎺ュ彛
+- `UserSyncServiceImpl.java` - Service瀹炵幇锛堟牳蹇冮�昏緫锛�
+- `DepartmentSyncController.java`锛堟墿灞曪級 - 娣诲姞鐢ㄦ埛鍚屾鎺ュ彛
+
+### 鏂囨。
+- `prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md` - 鏈枃妗�
+
+## 馃敆 鐩稿叧鏂囨。
+- [閮ㄩ棬鍚屾鍔熻兘璇存槑](閮ㄩ棬鍚屾鍔熻兘璇存槑.md)
+- [閮ㄩ棬鍚屾娴嬭瘯鎸囧崡](../閮ㄩ棬鍚屾娴嬭瘯鎸囧崡.md)
+
+## 鉁� 浣滆��
+ruoyi
+
+## 馃搮 鏃ユ湡
+2025-10-18
diff --git "a/prd/\347\224\250\346\210\267\347\273\221\345\256\232\350\275\246\350\276\206\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\347\224\250\346\210\267\347\273\221\345\256\232\350\275\246\350\276\206\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..27c61dd
--- /dev/null
+++ "b/prd/\347\224\250\346\210\267\347\273\221\345\256\232\350\275\246\350\276\206\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,329 @@
+# 鐢ㄦ埛缁戝畾杞﹁締鍔熻兘瀹炵幇璇存槑
+
+## 姒傝堪
+瀹炵幇浜嗗畬鏁寸殑鐢ㄦ埛缁戝畾杞﹁締鍔熻兘锛屽寘鎷墠绔粦瀹氶〉闈€�佸悗绔疉PI鎺ュ彛銆佹暟鎹簱琛ㄧ粨鏋勫拰涓氬姟閫昏緫銆�
+
+## 1. 鏁版嵁搴撹〃缁撴瀯
+
+### 鏂囦欢锛歚sql/user_vehicle_bind.sql`
+
+鍒涘缓浜嗙敤鎴疯溅杈嗙粦瀹氳〃 `sys_user_vehicle`锛�
+
+```sql
+CREATE TABLE IF NOT EXISTS sys_user_vehicle (
+ id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ user_id BIGINT(20) NOT NULL COMMENT '鐢ㄦ埛ID',
+ vehicle_id BIGINT(20) NOT NULL COMMENT '杞﹁締ID',
+ bind_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '缁戝畾鏃堕棿',
+ bind_by VARCHAR(64) DEFAULT '' COMMENT '缁戝畾鎿嶄綔浜�',
+ status CHAR(1) DEFAULT '0' COMMENT '缁戝畾鐘舵�侊紙0姝e父 1瑙g粦锛�',
+ remark VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
+ create_by VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ update_by VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ PRIMARY KEY (id),
+ UNIQUE KEY idx_user_vehicle (user_id, vehicle_id),
+ KEY idx_user_id (user_id),
+ KEY idx_vehicle_id (vehicle_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐢ㄦ埛杞﹁締缁戝畾琛�';
+```
+
+**涓氬姟瑙勫垯**锛�
+- 涓�涓敤鎴峰悓鏃跺彧鑳界粦瀹氫竴杈嗚溅杈嗭紙閫氳繃涓氬姟閫昏緫鎺у埗锛�
+- 涓�杈嗚溅杈嗗彲浠ヨ澶氫釜鐢ㄦ埛缁戝畾锛堝鍙告満杞彮锛�
+- status='0'琛ㄧず褰撳墠缁戝畾鏈夋晥锛�'1'琛ㄧず宸茶В缁�
+- 閫氳繃 (user_id, vehicle_id) 鍞竴绱㈠紩纭繚涓嶉噸澶嶇粦瀹�
+
+## 2. 鍚庣鎺ュ彛瀹炵幇
+
+### 2.1 Controller灞�
+
+**鏂囦欢**锛歚VehicleInfoController.java`
+
+鏂板浠ヤ笅鎺ュ彛锛�
+
+#### (1) 缁戝畾杞﹁締鎺ュ彛
+```
+POST /system/vehicle/bind
+```
+璇锋眰鍙傛暟锛�
+```json
+{
+ "userId": 鐢ㄦ埛ID,
+ "vehicleId": 杞﹁締ID
+}
+```
+
+#### (2) 瑙g粦杞﹁締鎺ュ彛
+```
+POST /system/vehicle/unbind
+```
+璇锋眰鍙傛暟锛�
+```json
+{
+ "userId": 鐢ㄦ埛ID,
+ "vehicleId": 杞﹁締ID
+}
+```
+
+#### (3) 鑾峰彇鐢ㄦ埛缁戝畾杞﹁締鎺ュ彛
+```
+GET /system/vehicle/user/bound/{userId}
+```
+杩斿洖鏁版嵁锛�
+```json
+{
+ "vehicleId": 杞﹁締ID,
+ "vehicleNumber": "杞︾墝鍙�",
+ "vehicleType": "杞﹁締绫诲瀷",
+ "vehicleBrand": "杞﹁締鍝佺墝",
+ "vehicleModel": "杞﹁締鍨嬪彿"
+}
+```
+
+### 2.2 Service灞�
+
+**鏂囦欢**锛歚IVehicleInfoService.java` 鍜� `VehicleInfoServiceImpl.java`
+
+鏂板鏂规硶锛�
+- `bindVehicleToUser(userId, vehicleId)` - 缁戝畾杞﹁締鍒扮敤鎴�
+- `unbindVehicleFromUser(userId, vehicleId)` - 瑙g粦鐢ㄦ埛杞﹁締
+- `getUserBoundVehicle(userId)` - 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+
+**涓氬姟閫昏緫**锛�
+```java
+@Transactional
+public int bindVehicleToUser(Long userId, Long vehicleId) {
+ // 鍏堣В缁戠敤鎴风殑鎵�鏈夎溅杈嗭紙纭繚涓�涓敤鎴峰彧缁戝畾涓�杈嗚溅锛�
+ vehicleInfoMapper.unbindAllVehiclesFromUser(userId);
+
+ // 缁戝畾鏂拌溅杈�
+ String bindBy = SecurityUtils.getUsername();
+ return vehicleInfoMapper.bindVehicleToUser(userId, vehicleId, bindBy);
+}
+```
+
+### 2.3 Mapper灞�
+
+**鏂囦欢**锛歚VehicleInfoMapper.java` 鍜� `VehicleInfoMapper.xml`
+
+鏂板Mapper鏂规硶锛�
+
+```java
+// 缁戝畾杞﹁締鍒扮敤鎴�
+public int bindVehicleToUser(@Param("userId") Long userId,
+ @Param("vehicleId") Long vehicleId,
+ @Param("bindBy") String bindBy);
+
+// 瑙g粦鐢ㄦ埛杞﹁締
+public int unbindVehicleFromUser(@Param("userId") Long userId,
+ @Param("vehicleId") Long vehicleId);
+
+// 瑙g粦鐢ㄦ埛鐨勬墍鏈夎溅杈�
+public int unbindAllVehiclesFromUser(@Param("userId") Long userId);
+
+// 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+public VehicleInfo getUserBoundVehicle(@Param("userId") Long userId);
+```
+
+鏂板SQL鏄犲皠锛�
+
+```xml
+<!-- 缁戝畾杞﹁締鍒扮敤鎴� -->
+<insert id="bindVehicleToUser">
+ INSERT INTO sys_user_vehicle (user_id, vehicle_id, bind_time, bind_by, status, create_by, create_time)
+ VALUES (#{userId}, #{vehicleId}, NOW(), #{bindBy}, '0', #{bindBy}, NOW())
+</insert>
+
+<!-- 瑙g粦鐢ㄦ埛杞﹁締 -->
+<update id="unbindVehicleFromUser">
+ UPDATE sys_user_vehicle
+ SET status = '1', update_time = NOW()
+ WHERE user_id = #{userId} AND vehicle_id = #{vehicleId} AND status = '0'
+</update>
+
+<!-- 瑙g粦鐢ㄦ埛鐨勬墍鏈夎溅杈� -->
+<update id="unbindAllVehiclesFromUser">
+ UPDATE sys_user_vehicle
+ SET status = '1', update_time = NOW()
+ WHERE user_id = #{userId} AND status = '0'
+</update>
+
+<!-- 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈� -->
+<select id="getUserBoundVehicle" resultMap="VehicleInfoResult">
+ SELECT v.*
+ FROM tb_vehicle_info v
+ INNER JOIN sys_user_vehicle uv ON v.vehicle_id = uv.vehicle_id
+ WHERE uv.user_id = #{userId} AND uv.status = '0'
+ ORDER BY uv.bind_time DESC
+ LIMIT 1
+</select>
+```
+
+## 3. 鍓嶇瀹炵幇
+
+### 3.1 API璋冪敤
+
+**鏂囦欢**锛歚app/api/vehicle.js`
+
+宸叉湁鎺ュ彛瀹氫箟锛�
+```javascript
+// 缁戝畾杞﹁締鍒扮敤鎴�
+export function bindVehicleToUser(userId, vehicleId) {
+ return request({
+ url: '/vehicle/bind',
+ method: 'post',
+ data: {
+ userId: userId,
+ vehicleId: vehicleId
+ }
+ })
+}
+
+// 瑙g粦鐢ㄦ埛杞﹁締
+export function unbindVehicleFromUser(userId, vehicleId) {
+ return request({
+ url: '/vehicle/unbind',
+ method: 'post',
+ data: {
+ userId: userId,
+ vehicleId: vehicleId
+ }
+ })
+}
+```
+
+### 3.2 缁戝畾杞﹁締椤甸潰
+
+**鏂囦欢**锛歚app/pages/bind-vehicle.vue`
+
+涓昏鏀硅繘锛�
+
+#### (1) 浠庡悗绔姞杞借溅杈嗗垪琛�
+```javascript
+loadVehicleList() {
+ const deptId = this.currentUser.deptId || 100
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ brand: vehicle.vehicleBrand,
+ model: vehicle.vehicleModel
+ }))
+ this.vehiclePlates = this.vehicleOptions.map(v => v.name)
+ })
+}
+```
+
+#### (2) 璋冪敤缁戝畾鎺ュ彛
+```javascript
+bindVehicle() {
+ if (!this.selectedVehiclePlate || !this.selectedVehicleId) {
+ this.$modal.showToast('璇烽�夋嫨杞︾墝鍙�')
+ return
+ }
+
+ this.$modal.confirm('纭缁戝畾杞﹁締 ' + this.selectedVehiclePlate + ' 鍚楋紵').then(() => {
+ const userId = this.currentUser.userId
+ bindVehicleToUser(userId, this.selectedVehicleId).then(response => {
+ this.$modal.showToast('杞﹁締缁戝畾鎴愬姛')
+ // 鏇存柊Vuex涓殑鐢ㄦ埛淇℃伅
+ this.$store.dispatch('GetInfo')
+ // 杩斿洖涓婁竴椤�
+ setTimeout(() => {
+ this.$tab.navigateBack()
+ }, 1500)
+ })
+ })
+}
+```
+
+#### (3) 鎵爜缁戝畾鍔熻兘
+鏀寔鎵弿浜岀淮鐮佸揩閫熺粦瀹氳溅杈嗭紙闇�瑕佸湪瀹為檯浣跨敤鏃堕厤缃簩缁寸爜鍐呭鏍煎紡锛�
+
+## 4. 浣跨敤娴佺▼
+
+### 4.1 缁戝畾杞﹁締
+1. 鐢ㄦ埛杩涘叆"缁戝畾杞﹁締"椤甸潰
+2. 鍙互閫夋嫨锛�
+ - 鎵弿杞﹁締浜岀淮鐮佽嚜鍔ㄧ粦瀹�
+ - 浠庝笅鎷夊垪琛ㄩ�夋嫨杞︾墝鍙锋墜鍔ㄧ粦瀹�
+3. 纭缁戝畾鍚庯細
+ - 绯荤粺鑷姩瑙g粦鐢ㄦ埛涔嬪墠缁戝畾鐨勮溅杈�
+ - 缁戝畾鏂伴�夋嫨鐨勮溅杈�
+ - 鏇存柊鐢ㄦ埛淇℃伅
+ - 杩斿洖棣栭〉
+
+### 4.2 鑾峰彇缁戝畾杞﹁締淇℃伅
+- 棣栭〉鑷姩鍔犺浇褰撳墠鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+- 鍒涘缓浠诲姟鏃惰嚜鍔ㄥ~鍏呯粦瀹氱殑杞﹁締锛堟櫘閫氫换鍔★級
+- 涓汉涓績鏄剧ず缁戝畾鐨勮溅杈嗕俊鎭�
+
+### 4.3 鏇存崲杞﹁締
+1. 鐢ㄦ埛鐐瑰嚮"鏇存崲杞﹁締"鎸夐挳
+2. 杩涘叆缁戝畾杞﹁締椤甸潰
+3. 閫夋嫨鏂拌溅杈嗗苟纭
+4. 绯荤粺鑷姩瑙g粦鏃ц溅杈嗭紝缁戝畾鏂拌溅杈�
+
+## 5. 鏁版嵁娴佺▼
+
+```
+鐢ㄦ埛鎿嶄綔
+ 鈫�
+鍓嶇椤甸潰 (bind-vehicle.vue)
+ 鈫�
+API璋冪敤 (vehicle.js)
+ 鈫�
+鍚庣Controller (VehicleInfoController)
+ 鈫�
+Service灞� (VehicleInfoServiceImpl)
+ 鈹溾攢鈹� 瑙g粦鎵�鏈夋棫缁戝畾 (unbindAllVehiclesFromUser)
+ 鈹斺攢鈹� 缁戝畾鏂拌溅杈� (bindVehicleToUser)
+ 鈫�
+Mapper灞� (VehicleInfoMapper)
+ 鈫�
+鏁版嵁搴撴搷浣� (sys_user_vehicle琛�)
+ 鈫�
+杩斿洖缁撴灉
+ 鈫�
+鏇存柊鐢ㄦ埛淇℃伅 (Vuex)
+```
+
+## 6. 娉ㄦ剰浜嬮」
+
+1. **鏉冮檺鎺у埗**锛氱粦瀹氭帴鍙d娇鐢ˊAnonymous娉ㄨВ锛屽厑璁稿尶鍚嶈闂紙瀹為檯閮ㄧ讲鏃跺彲鏍规嵁闇�瑕佽皟鏁达級
+2. **浜嬪姟澶勭悊**锛氱粦瀹氭搷浣滀娇鐢ˊTransactional纭繚鏁版嵁涓�鑷存��
+3. **鍞竴鎬х害鏉�**锛氶�氳繃鏁版嵁搴撳敮涓�绱㈠紩鍜屼笟鍔¢�昏緫纭繚涓�涓敤鎴峰彧缁戝畾涓�杈嗚溅
+4. **鍘嗗彶璁板綍**锛氶�氳繃status瀛楁淇濈暀缁戝畾鍘嗗彶锛屼究浜庤拷婧�
+5. **閿欒澶勭悊**锛氭墍鏈夋帴鍙i兘鏈夊畬鍠勭殑寮傚父鎹曡幏鍜岄敊璇彁绀�
+
+## 7. 娴嬭瘯寤鸿
+
+### 7.1 鍗曞厓娴嬭瘯
+- 娴嬭瘯缁戝畾杞﹁締鎺ュ彛
+- 娴嬭瘯瑙g粦杞﹁締鎺ュ彛
+- 娴嬭瘯鑾峰彇缁戝畾杞﹁締鎺ュ彛
+- 娴嬭瘯閲嶅缁戝畾鍚屼竴杞﹁締
+
+### 7.2 闆嗘垚娴嬭瘯
+- 娴嬭瘯瀹屾暣鐨勭粦瀹氭祦绋�
+- 娴嬭瘯鏇存崲杞﹁締娴佺▼
+- 娴嬭瘯澶氱敤鎴风粦瀹氬悓涓�杞﹁締
+- 娴嬭瘯骞跺彂缁戝畾鍦烘櫙
+
+### 7.3 UI娴嬭瘯
+- 娴嬭瘯鎵爜缁戝畾鍔熻兘
+- 娴嬭瘯涓嬫媺閫夋嫨缁戝畾鍔熻兘
+- 娴嬭瘯缁戝畾鎴愬姛鍚庣殑椤甸潰璺宠浆
+- 娴嬭瘯缁戝畾淇℃伅鐨勬纭樉绀�
+
+## 8. 鍚庣画浼樺寲寤鸿
+
+1. **浜岀淮鐮佺敓鎴�**锛氫负姣忚締杞︾敓鎴愬敮涓�鐨勪簩缁寸爜锛屼究浜庢壂鐮佺粦瀹�
+2. **缁戝畾瀹℃壒**锛氭坊鍔犵粦瀹氬鎵规祦绋嬶紝闃叉闅忔剰缁戝畾
+3. **缁戝畾闄愬埗**锛氭牴鎹敤鎴疯鑹查檺鍒跺彲缁戝畾鐨勮溅杈嗙被鍨�
+4. **閫氱煡鎺ㄩ��**锛氱粦瀹�/瑙g粦鎴愬姛鍚庡彂閫侀�氱煡缁欑浉鍏充汉鍛�
+5. **鏁版嵁缁熻**锛氱粺璁¤溅杈嗙粦瀹氭儏鍐碉紝鍒嗘瀽杞﹁締浣跨敤鐜�
diff --git "a/prd/\347\273\221\345\256\232\350\275\246\350\276\206\351\203\250\351\227\250\350\277\207\346\273\244\344\274\230\345\214\226.md" "b/prd/\347\273\221\345\256\232\350\275\246\350\276\206\351\203\250\351\227\250\350\277\207\346\273\244\344\274\230\345\214\226.md"
new file mode 100644
index 0000000..f0cb872
--- /dev/null
+++ "b/prd/\347\273\221\345\256\232\350\275\246\350\276\206\351\203\250\351\227\250\350\277\207\346\273\244\344\274\230\345\214\226.md"
@@ -0,0 +1,513 @@
+# 缁戝畾杞﹁締閮ㄩ棬杩囨护浼樺寲璇存槑
+
+## 闇�姹傝儗鏅�
+
+鍦ㄧ粦瀹氳溅杈嗗姛鑳戒腑锛岄渶瑕侀檺鍒剁敤鎴峰彧鑳界粦瀹氫笌鑷繁鍚屼竴鍒嗗叕鍙哥殑杞﹁締锛岄伩鍏嶈法鍒嗗叕鍙哥粦瀹氾紝纭繚杞﹁締绠$悊鐨勮鑼冩�с��
+
+## 涓氬姟瑙勫垯
+
+### 閮ㄩ棬灞傜骇缁撴瀯
+
+鏍规嵁椤圭洰瑙勮寖锛岄儴闂ㄧ粨鏋勫涓嬶細
+
+```
+100 (鎬诲叕鍙�)
+鈹溾攢鈹� 101 (娣卞湷鍒嗗叕鍙�) 鈫� 鐢ㄦ埛A鎵�鍦ㄥ垎鍏徃
+鈹� 鈹溾攢鈹� 201 (鎶�鏈儴)
+鈹� 鈹斺攢鈹� 202 (涓氬姟閮�)
+鈹溾攢鈹� 102 (骞垮窞鍒嗗叕鍙�) 鈫� 鐢ㄦ埛B鎵�鍦ㄥ垎鍏徃
+鈹� 鈹溾攢鈹� 203 (鎶�鏈儴)
+鈹� 鈹斺攢鈹� 204 (涓氬姟閮�)
+鈹斺攢鈹� 103 (鍖椾含鍒嗗叕鍙�)
+```
+
+### 杩囨护瑙勫垯
+
+- 鉁� **鐢ㄦ埛A锛堟繁鍦冲垎鍏徃锛�**锛氬彧鑳界湅鍒板拰缁戝畾娣卞湷鍒嗗叕鍙革紙deptId=101锛夌殑杞﹁締
+- 鉁� **鐢ㄦ埛B锛堝箍宸炲垎鍏徃锛�**锛氬彧鑳界湅鍒板拰缁戝畾骞垮窞鍒嗗叕鍙革紙deptId=102锛夌殑杞﹁締
+- 鉂� **璺ㄥ垎鍏徃缁戝畾**锛氱敤鎴稟涓嶈兘缁戝畾骞垮窞鍒嗗叕鍙哥殑杞﹁締
+
+## 闂鍒嗘瀽
+
+### 鍘熸湁瀹炵幇
+
+**鏂囦欢锛�** [`app/pages/bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue)
+
+**闂鐐癸細**
+
+```javascript
+loadVehicleList() {
+ this.loading = true
+ // 鉂� 浣跨敤榛樿鍊� 100锛堟�诲叕鍙革級锛屽姞杞芥墍鏈夎溅杈�
+ const deptId = this.currentUser.deptId || 100
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ // ...
+ })
+}
+```
+
+**瀛樺湪鐨勯棶棰橈細**
+1. 鉂� 褰撶敤鎴风殑 `deptId` 涓虹┖鏃讹紝榛樿浣跨敤 100锛堟�诲叕鍙革級锛屼細鍔犺浇鎵�鏈夊垎鍏徃鐨勮溅杈�
+2. 鉂� 娌℃湁楠岃瘉 `deptId` 鏄惁瀛樺湪
+3. 鉂� 鐢ㄦ埛鍙兘鐪嬪埌鍏朵粬鍒嗗叕鍙哥殑杞﹁締
+4. 鉂� 缂哄皯鍙嬪ソ鐨勬彁绀轰俊鎭�
+
+## 瑙e喅鏂规
+
+### 鏍稿績鏀硅繘
+
+**淇敼鍓嶏細**
+```javascript
+loadVehicleList() {
+ this.loading = true
+ const deptId = this.currentUser.deptId || 100 // 鉂� 浣跨敤榛樿鍊�
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ const vehicleList = response.data || response.rows || []
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ // ...
+ }))
+ this.vehiclePlates = this.vehicleOptions.map(v => v.name)
+ }).catch(error => {
+ this.loading = false
+ console.error('鍔犺浇杞﹁締鍒楄〃澶辫触:', error)
+ this.$modal.showToast('鍔犺浇杞﹁締鍒楄〃澶辫触')
+ })
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+loadVehicleList() {
+ this.loading = true
+ // 鉁� 鑾峰彇褰撳墠鐢ㄦ埛鐨勯儴闂↖D
+ const deptId = this.currentUser.deptId
+
+ // 鉁� 楠岃瘉閮ㄩ棬ID鏄惁瀛樺湪
+ if (!deptId) {
+ this.loading = false
+ console.error('鏃犳硶鑾峰彇鐢ㄦ埛閮ㄩ棬淇℃伅')
+ this.$modal.showToast('鏃犳硶鑾峰彇鐢ㄦ埛閮ㄩ棬淇℃伅')
+ return
+ }
+
+ // 鉁� 浣跨敤鐢ㄦ埛鎵�鍦ㄧ殑閮ㄩ棬ID鍔犺浇杞﹁締鍒楄〃
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ this.loading = false
+ const vehicleList = response.data || response.rows || []
+
+ // 鉁� 鎻愮ず鏃犲彲鐢ㄨ溅杈�
+ if (vehicleList.length === 0) {
+ console.log('褰撳墠鍒嗗叕鍙告殏鏃犲彲鐢ㄨ溅杈�')
+ this.$modal.showToast('褰撳墠鍒嗗叕鍙告殏鏃犲彲鐢ㄨ溅杈�')
+ }
+
+ this.vehicleOptions = vehicleList.map(vehicle => ({
+ id: vehicle.vehicleId,
+ name: vehicle.vehicleNo,
+ type: vehicle.vehicleType,
+ brand: vehicle.vehicleBrand,
+ model: vehicle.vehicleModel
+ }))
+ this.vehiclePlates = this.vehicleOptions.map(v => v.name)
+
+ // 鉁� 璁板綍鏃ュ織
+ console.log(`鍔犺浇浜� ${vehicleList.length} 杈嗚溅杈嗭紙閮ㄩ棬ID: ${deptId}锛塦)
+ }).catch(error => {
+ this.loading = false
+ console.error('鍔犺浇杞﹁締鍒楄〃澶辫触:', error)
+ this.$modal.showToast('鍔犺浇杞﹁締鍒楄〃澶辫触')
+ })
+}
+```
+
+### 鏀硅繘鐐�
+
+1. 鉁� **涓ユ牸楠岃瘉**锛氭鏌� `deptId` 鏄惁瀛樺湪锛屼笉浣跨敤榛樿鍊�
+2. 鉁� **鍙嬪ソ鎻愮ず**锛氬綋鏃犻儴闂ㄤ俊鎭垨鏃犲彲鐢ㄨ溅杈嗘椂锛岀粰鍑烘槑纭彁绀�
+3. 鉁� **鏃ュ織璁板綍**锛氳褰曞姞杞界殑杞﹁締鏁伴噺鍜岄儴闂↖D锛屼究浜庤皟璇�
+4. 鉁� **瑙勮寖绠$悊**锛氱‘淇濈敤鎴峰彧鑳界湅鍒版湰鍒嗗叕鍙哥殑杞﹁締
+
+## 瀹炵幇鏁堟灉
+
+### 鍦烘櫙1锛氭繁鍦冲垎鍏徃鐢ㄦ埛缁戝畾杞﹁締
+
+**鐢ㄦ埛淇℃伅锛�**
+```javascript
+{
+ userId: 1,
+ userName: "寮犱笁",
+ deptId: 101, // 娣卞湷鍒嗗叕鍙�
+ deptName: "娣卞湷鍒嗗叕鍙�"
+}
+```
+
+**鎿嶄綔娴佺▼锛�**
+1. 鐢ㄦ埛寮犱笁鎵撳紑缁戝畾杞﹁締椤甸潰
+2. 绯荤粺浣跨敤 `deptId: 101` 鏌ヨ杞﹁締
+3. 鍙繑鍥炴繁鍦冲垎鍏徃鐨勮溅杈嗗垪琛�
+
+**鏄剧ず缁撴灉锛�**
+```
+杞︾墝鍙蜂笅鎷夊垪琛細
+- 绮12345 (娣卞湷鍒嗗叕鍙�)
+- 绮67890 (娣卞湷鍒嗗叕鍙�)
+- 绮11111 (娣卞湷鍒嗗叕鍙�)
+
+鉂� 涓嶆樉绀猴細
+- 绮12345 (骞垮窞鍒嗗叕鍙�)
+- 浜珹12345 (鍖椾含鍒嗗叕鍙�)
+```
+
+### 鍦烘櫙2锛氬箍宸炲垎鍏徃鐢ㄦ埛缁戝畾杞﹁締
+
+**鐢ㄦ埛淇℃伅锛�**
+```javascript
+{
+ userId: 2,
+ userName: "鏉庡洓",
+ deptId: 102, // 骞垮窞鍒嗗叕鍙�
+ deptName: "骞垮窞鍒嗗叕鍙�"
+}
+```
+
+**鏄剧ず缁撴灉锛�**
+```
+杞︾墝鍙蜂笅鎷夊垪琛細
+- 绮12345 (骞垮窞鍒嗗叕鍙�)
+- 绮67890 (骞垮窞鍒嗗叕鍙�)
+
+鉂� 涓嶆樉绀猴細
+- 绮12345 (娣卞湷鍒嗗叕鍙�)
+- 浜珹12345 (鍖椾含鍒嗗叕鍙�)
+```
+
+### 鍦烘櫙3锛氱敤鎴锋棤閮ㄩ棬淇℃伅
+
+**鐢ㄦ埛淇℃伅锛�**
+```javascript
+{
+ userId: 3,
+ userName: "鐜嬩簲",
+ deptId: null // 鏃犻儴闂ㄤ俊鎭�
+}
+```
+
+**鎿嶄綔娴佺▼锛�**
+1. 鐢ㄦ埛鐜嬩簲鎵撳紑缁戝畾杞﹁締椤甸潰
+2. 绯荤粺妫�娴嬪埌 `deptId` 涓虹┖
+3. 鏄剧ず鎻愮ず锛�"鏃犳硶鑾峰彇鐢ㄦ埛閮ㄩ棬淇℃伅"
+4. 涓嶅姞杞戒换浣曡溅杈�
+
+**鏄剧ず缁撴灉锛�**
+```
+杞︾墝鍙蜂笅鎷夊垪琛細
+- 璇烽�夋嫨杞︾墝鍙� (绌哄垪琛紝鏃犳硶閫夋嫨)
+
+鎻愮ず淇℃伅锛氭棤娉曡幏鍙栫敤鎴烽儴闂ㄤ俊鎭�
+```
+
+### 鍦烘櫙4锛氬垎鍏徃鏆傛棤杞﹁締
+
+**鐢ㄦ埛淇℃伅锛�**
+```javascript
+{
+ userId: 4,
+ userName: "璧靛叚",
+ deptId: 103, // 鍖椾含鍒嗗叕鍙�
+ deptName: "鍖椾含鍒嗗叕鍙�"
+}
+```
+
+**鍋囪锛氬寳浜垎鍏徃鐩墠娌℃湁杞﹁締**
+
+**鏄剧ず缁撴灉锛�**
+```
+杞︾墝鍙蜂笅鎷夊垪琛細
+- 璇烽�夋嫨杞︾墝鍙� (绌哄垪琛�)
+
+鎻愮ず淇℃伅锛氬綋鍓嶅垎鍏徃鏆傛棤鍙敤杞﹁締
+```
+
+## 鏁版嵁娴佺▼鍥�
+
+```mermaid
+sequenceDiagram
+ participant User as 鐢ㄦ埛
+ participant Page as 缁戝畾杞﹁締椤甸潰
+ participant Vuex as Vuex Store
+ participant API as 鍚庣API
+
+ User->>Page: 鎵撳紑缁戝畾杞﹁締椤甸潰
+ Page->>Vuex: 鑾峰彇 currentUser.deptId
+
+ alt deptId 瀛樺湪
+ Vuex-->>Page: 杩斿洖 deptId: 101
+ Page->>API: listAvailableVehicles(101, 'GENERAL')
+
+ alt 鏈夎溅杈嗘暟鎹�
+ API-->>Page: 杩斿洖娣卞湷鍒嗗叕鍙哥殑杞﹁締鍒楄〃
+ Page-->>User: 鏄剧ず杞﹁締鍒楄〃
+ else 鏃犺溅杈嗘暟鎹�
+ API-->>Page: 杩斿洖绌哄垪琛�
+ Page-->>User: 鎻愮ず锛氬綋鍓嶅垎鍏徃鏆傛棤鍙敤杞﹁締
+ end
+ else deptId 涓嶅瓨鍦�
+ Vuex-->>Page: 杩斿洖 null
+ Page-->>User: 鎻愮ず锛氭棤娉曡幏鍙栫敤鎴烽儴闂ㄤ俊鎭�
+ end
+```
+
+## 鍚庣鎺ュ彛璇存槑
+
+### listAvailableVehicles API
+
+**鏂囦欢锛�** [`app/api/vehicle.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js)
+
+```javascript
+export function listAvailableVehicles(deptId, taskType) {
+ return request({
+ url: '/task/vehicle/available',
+ method: 'get',
+ params: {
+ deptId: deptId, // 閮ㄩ棬ID锛岀敤浜庤繃婊よ溅杈�
+ taskType: taskType // 浠诲姟绫诲瀷
+ }
+ })
+}
+```
+
+**鍚庣鎺ュ彛锛�** `/task/vehicle/available`
+
+**璇锋眰绀轰緥锛�**
+```
+GET /task/vehicle/available?deptId=101&taskType=GENERAL
+```
+
+**鍝嶅簲绀轰緥锛�**
+```json
+{
+ "code": 200,
+ "msg": "鏌ヨ鎴愬姛",
+ "data": [
+ {
+ "vehicleId": 1,
+ "vehicleNo": "绮12345",
+ "vehicleType": "鏁戞姢杞�",
+ "vehicleBrand": "绂忕壒",
+ "vehicleModel": "鍏ㄩ『",
+ "deptId": 101,
+ "deptName": "娣卞湷鍒嗗叕鍙�"
+ },
+ {
+ "vehicleId": 2,
+ "vehicleNo": "绮67890",
+ "vehicleType": "鏁戞姢杞�",
+ "vehicleBrand": "涓扮敯",
+ "vehicleModel": "娴风嫯",
+ "deptId": 101,
+ "deptName": "娣卞湷鍒嗗叕鍙�"
+ }
+ ]
+}
+```
+
+**鏃犺溅杈嗘椂锛�**
+```json
+{
+ "code": 200,
+ "msg": "鏌ヨ鎴愬姛",
+ "data": []
+}
+```
+
+## 瀹夊叏鎬т笌鏉冮檺
+
+### 1. 鍓嶇楠岃瘉
+
+- 鉁� 妫�鏌ョ敤鎴锋槸鍚︽湁閮ㄩ棬淇℃伅
+- 鉁� 浣跨敤鐢ㄦ埛瀹為檯鐨� `deptId`锛屼笉浣跨敤榛樿鍊�
+- 鉁� 绌哄垪琛ㄦ椂缁欏嚭鍙嬪ソ鎻愮ず
+
+### 2. 鍚庣楠岃瘉锛堝缓璁級
+
+**寤鸿鍦ㄥ悗绔帴鍙d腑澧炲姞浠ヤ笅楠岃瘉锛�**
+
+```java
+// 楠岃瘉璇锋眰鐨� deptId 鏄惁涓庣敤鎴风殑 deptId 涓�鑷�
+@GetMapping("/available")
+public AjaxResult listAvailableVehicles(@RequestParam Long deptId, @RequestParam String taskType) {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ Long userDeptId = loginUser.getUser().getDeptId();
+
+ // 鉁� 楠岃瘉閮ㄩ棬鏉冮檺
+ if (!deptId.equals(userDeptId)) {
+ return error("鏃犳潈鏌ヨ鍏朵粬閮ㄩ棬鐨勮溅杈�");
+ }
+
+ // 鏌ヨ杞﹁締鍒楄〃...
+}
+```
+
+### 3. 鏁版嵁闅旂
+
+- 鉁� **鍓嶇闅旂**锛氬彧鏄剧ず鏈垎鍏徃鐨勮溅杈�
+- 鉁� **鍚庣闅旂**锛氭帴鍙e眰闈㈤獙璇侀儴闂ㄦ潈闄�
+- 鉁� **鏁版嵁搴撻殧绂�**锛氭煡璇㈡椂鍔犱笂閮ㄩ棬鏉′欢
+
+## 娴嬭瘯瑕佺偣
+
+### 鍔熻兘娴嬭瘯
+
+1. **姝e父娴佺▼**
+ - 鉁� 鐢ㄦ埛鏈夐儴闂ㄤ俊鎭紝鑳芥甯稿姞杞芥湰鍒嗗叕鍙哥殑杞﹁締
+ - 鉁� 杞﹁締鍒楄〃鍙寘鍚湰鍒嗗叕鍙哥殑杞﹁締
+
+2. **杈圭晫鎯呭喌**
+ - 鉁� 鐢ㄦ埛鏃犻儴闂ㄤ俊鎭紝鏄剧ず鍙嬪ソ鎻愮ず
+ - 鉁� 鍒嗗叕鍙告棤杞﹁締锛屾樉绀�"鏆傛棤鍙敤杞﹁締"
+ - 鉁� 缃戠粶寮傚父锛屾樉绀�"鍔犺浇澶辫触"
+
+3. **璺ㄥ垎鍏徃楠岃瘉**
+ - 鉁� 娣卞湷鍒嗗叕鍙哥敤鎴风湅涓嶅埌骞垮窞鍒嗗叕鍙哥殑杞﹁締
+ - 鉁� 骞垮窞鍒嗗叕鍙哥敤鎴风湅涓嶅埌娣卞湷鍒嗗叕鍙哥殑杞﹁締
+
+### 鏁版嵁楠岃瘉
+
+```javascript
+// 娴嬭瘯鐢ㄤ緥1锛氭繁鍦冲垎鍏徃鐢ㄦ埛
+{
+ userId: 1,
+ deptId: 101,
+ expectedVehicles: ['绮12345', '绮67890'], // 鍙湁娣卞湷鐨勮溅
+ notExpectedVehicles: ['绮12345', '浜珹12345'] // 涓嶅簲鍖呭惈鍏朵粬鍒嗗叕鍙�
+}
+
+// 娴嬭瘯鐢ㄤ緥2锛氬箍宸炲垎鍏徃鐢ㄦ埛
+{
+ userId: 2,
+ deptId: 102,
+ expectedVehicles: ['绮12345', '绮67890'], // 鍙湁骞垮窞鐨勮溅
+ notExpectedVehicles: ['绮12345', '浜珹12345'] // 涓嶅簲鍖呭惈鍏朵粬鍒嗗叕鍙�
+}
+```
+
+## 鏃ュ織绀轰緥
+
+### 姝e父鍔犺浇
+
+```
+鎺у埗鍙拌緭鍑猴細
+鍔犺浇浜� 3 杈嗚溅杈嗭紙閮ㄩ棬ID: 101锛�
+```
+
+### 鏃犻儴闂ㄤ俊鎭�
+
+```
+鎺у埗鍙拌緭鍑猴細
+鏃犳硶鑾峰彇鐢ㄦ埛閮ㄩ棬淇℃伅
+
+鐢ㄦ埛鐪嬪埌锛�
+Toast鎻愮ず锛氭棤娉曡幏鍙栫敤鎴烽儴闂ㄤ俊鎭�
+```
+
+### 鏃犲彲鐢ㄨ溅杈�
+
+```
+鎺у埗鍙拌緭鍑猴細
+褰撳墠鍒嗗叕鍙告殏鏃犲彲鐢ㄨ溅杈�
+
+鐢ㄦ埛鐪嬪埌锛�
+Toast鎻愮ず锛氬綋鍓嶅垎鍏徃鏆傛棤鍙敤杞﹁締
+```
+
+## 鐩稿叧鏂囦欢
+
+### 淇敼鐨勬枃浠�
+1. [`app/pages/bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) - 缁戝畾杞﹁締椤甸潰
+
+### 渚濊禆鐨勬枃浠�
+1. [`app/api/vehicle.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js) - 杞﹁締 API
+2. [`app/store/modules/user.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\store\modules\user.js) - Vuex 鐢ㄦ埛鐘舵��
+
+### 鐩稿叧鏂囨。
+- [杞﹁締绠$悊閮ㄩ棬杩囨护璇存槑.md](./杞﹁締绠$悊閮ㄩ棬杩囨护璇存槑.md)
+- [杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md](./杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md)
+- [Vuex鐢ㄦ埛鐘舵�佸畬鏁存�т紭鍖�.md](./Vuex鐢ㄦ埛鐘舵�佸畬鏁存�т紭鍖�.md)
+
+## 鍚庣画浼樺寲寤鸿
+
+### 1. 鏄剧ず閮ㄩ棬淇℃伅
+
+鍦ㄨ溅杈嗗垪琛ㄤ腑鏄剧ず杞﹁締鎵�灞炲垎鍏徃锛�
+
+```vue
+<picker mode="selector" :range="vehiclePlates" @change="onVehiclePlateChange">
+ <view class="form-input picker-input">
+ <text v-if="selectedVehiclePlate">
+ {{ selectedVehiclePlate }} ({{ currentUser.deptName }})
+ </text>
+ <text v-else>璇烽�夋嫨杞︾墝鍙�</text>
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+</picker>
+```
+
+### 2. 杞﹁締璇︾粏淇℃伅
+
+閫夋嫨杞﹁締鍚庢樉绀鸿溅杈嗚缁嗕俊鎭細
+
+```vue
+<view v-if="selectedVehicleId" class="vehicle-detail">
+ <text>杞﹁締绫诲瀷锛歿{ selectedVehicleType }}</text>
+ <text>杞﹁締鍝佺墝锛歿{ selectedVehicleBrand }}</text>
+ <text>杞﹁締鍨嬪彿锛歿{ selectedVehicleModel }}</text>
+</view>
+```
+
+### 3. 缂撳瓨浼樺寲
+
+缂撳瓨杞﹁締鍒楄〃锛岄伩鍏嶉噸澶嶈姹傦細
+
+```javascript
+// 浣跨敤鏈湴缂撳瓨
+const cacheKey = `vehicle_list_${deptId}`
+const cachedData = storage.get(cacheKey)
+
+if (cachedData && Date.now() - cachedData.timestamp < 5 * 60 * 1000) {
+ // 5鍒嗛挓鍐呬娇鐢ㄧ紦瀛�
+ this.vehicleOptions = cachedData.data
+} else {
+ // 璇锋眰鏂版暟鎹苟缂撳瓨
+ listAvailableVehicles(deptId, 'GENERAL').then(response => {
+ const data = response.data || []
+ storage.set(cacheKey, {
+ data: data,
+ timestamp: Date.now()
+ })
+ })
+}
+```
+
+## 鎬荤粨
+
+閫氳繃鏈浼樺寲锛屽疄鐜颁簡浠ヤ笅鐩爣锛�
+
+1. 鉁� **閮ㄩ棬闅旂**锛氱敤鎴峰彧鑳界湅鍒板拰缁戝畾鏈垎鍏徃鐨勮溅杈�
+2. 鉁� **涓ユ牸楠岃瘉**锛氭鏌ョ敤鎴烽儴闂ㄤ俊鎭紝涓嶄娇鐢ㄩ粯璁ゅ��
+3. 鉁� **鍙嬪ソ鎻愮ず**锛氬悇绉嶅紓甯告儏鍐甸兘鏈夋槑纭殑鎻愮ず淇℃伅
+4. 鉁� **鏃ュ織璁板綍**锛氫究浜庤皟璇曞拰闂鎺掓煡
+5. 鉁� **瀹夊叏鎬�**锛氶伩鍏嶈法鍒嗗叕鍙哥粦瀹氳溅杈�
+
+**鏍稿績浠峰�硷細**
+- 鎻愰珮浜嗘暟鎹畨鍏ㄦ��
+- 瑙勮寖浜嗚溅杈嗙鐞嗘祦绋�
+- 鎻愬崌浜嗙敤鎴蜂綋楠�
+- 渚夸簬鍚庣画缁存姢鍜屾墿灞�
+
+## 鐗堟湰鍘嗗彶
+
+| 鐗堟湰 | 鏃ユ湡 | 淇敼鍐呭 | 淇敼浜� |
+|------|------|---------|--------|
+| 1.0 | 2025-10-15 | 瀹炵幇缁戝畾杞﹁締閮ㄩ棬杩囨护鍔熻兘 | - |
diff --git "a/prd/\350\275\246\350\276\206\347\256\241\347\220\206\351\203\250\351\227\250\350\277\207\346\273\244\350\257\264\346\230\216.md" "b/prd/\350\275\246\350\276\206\347\256\241\347\220\206\351\203\250\351\227\250\350\277\207\346\273\244\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..3fc4285
--- /dev/null
+++ "b/prd/\350\275\246\350\276\206\347\256\241\347\220\206\351\203\250\351\227\250\350\277\207\346\273\244\350\257\264\346\230\216.md"
@@ -0,0 +1,291 @@
+# 杞﹁締绠$悊閮ㄩ棬杩囨护鍔熻兘璇存槑
+
+## 淇敼姒傝堪
+
+鍦ㄨ溅杈嗙鐞嗗姛鑳戒腑锛岃溅杈嗗綊灞為儴闂ㄥ簲璇ュ彧鑳介�夋嫨鍒嗗叕鍙革紝鍥犳闇�瑕佽繃婊ら儴闂ㄥ垪琛紝鍙樉绀哄垎鍏徃锛坄parent_id = 100`鐨勯儴闂級銆�
+
+## 涓氬姟瑙勫垯
+
+### 閮ㄩ棬灞傜骇缁撴瀯
+```
+100 (鏍归儴闂�)
+鈹溾攢鈹� 101 (鍒嗗叕鍙�1) 鈫� 鍙樉绀鸿繖涓�灞�
+鈹溾攢鈹� 102 (鍒嗗叕鍙�2) 鈫� 鍙樉绀鸿繖涓�灞�
+鈹� 鈹溾攢鈹� 103 (瀛愰儴闂�) 鈫� 涓嶆樉绀�
+鈹� 鈹斺攢鈹� 104 (瀛愰儴闂�) 鈫� 涓嶆樉绀�
+鈹斺攢鈹� 105 (鍒嗗叕鍙�3) 鈫� 鍙樉绀鸿繖涓�灞�
+```
+
+### 杩囨护瑙勫垯
+- 鉁� **鏄剧ず**锛歚parent_id = 100` 鐨勯儴闂紙鍒嗗叕鍙革級
+- 鉂� **涓嶆樉绀�**锛氬叾浠栧眰绾х殑閮ㄩ棬
+
+## 鎶�鏈疄鐜�
+
+### 淇敼鏂囦欢
+**鏂囦欢璺緞**锛歚ruoyi-ui/src/views/system/vehicle/index.vue`
+
+### 淇敼鍐呭
+
+#### 鍘熶唬鐮�
+```javascript
+/** 鑾峰彇閮ㄩ棬鍒楄〃 */
+getDeptList() {
+ listDept().then(response => {
+ this.deptList = response.data;
+ });
+}
+```
+
+#### 淇敼鍚�
+```javascript
+/** 鑾峰彇閮ㄩ棬鍒楄〃锛堝彧鏄剧ず鍒嗗叕鍙革細parent_id=100锛� */
+getDeptList() {
+ listDept({ parentId: 100 }).then(response => {
+ // 杩囨护鍑哄垎鍏徃锛坧arent_id=100鐨勯儴闂級
+ if (response.data) {
+ this.deptList = response.data.filter(dept => dept.parentId === 100);
+ } else {
+ this.deptList = [];
+ }
+ });
+}
+```
+
+### 瀹炵幇鏂瑰紡
+
+閲囩敤浜�**鍙岄噸杩囨护**鐨勫畨鍏ㄧ瓥鐣ワ細
+
+1. **API鍙傛暟杩囨护**锛�
+ ```javascript
+ listDept({ parentId: 100 })
+ ```
+ - 鍦ㄨ姹傛椂灏变紶閫� `parentId: 100` 鍙傛暟
+ - 濡傛灉鍚庣鏀寔姝ゅ弬鏁帮紝鍙互鍑忓皯鏁版嵁浼犺緭
+
+2. **鍓嶇浜屾杩囨护**锛�
+ ```javascript
+ this.deptList = response.data.filter(dept => dept.parentId === 100);
+ ```
+ - 纭繚鍗充娇鍚庣杩斿洖鎵�鏈夋暟鎹紝鍓嶇涔熶細杩囨护
+ - 鎻愰珮鏁版嵁鍑嗙‘鎬у拰瀹夊叏鎬�
+
+3. **绌哄�间繚鎶�**锛�
+ ```javascript
+ if (response.data) {
+ // 澶勭悊鏁版嵁
+ } else {
+ this.deptList = [];
+ }
+ ```
+ - 闃叉鏁版嵁涓虹┖鏃跺嚭鐜伴敊璇�
+
+## 褰卞搷鑼冨洿
+
+### 鍓嶇椤甸潰褰卞搷
+
+#### 1. 鏌ヨ鏉′欢鍖哄煙
+```vue
+<el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
+ <el-select v-model="queryParams.deptId" placeholder="璇烽�夋嫨閮ㄩ棬" clearable size="small">
+ <el-option
+ v-for="dept in deptList"
+ :key="dept.deptId"
+ :label="dept.deptName"
+ :value="dept.deptId"
+ />
+ </el-select>
+</el-form-item>
+```
+**褰卞搷**锛氫笅鎷夐�夐」鍙樉绀哄垎鍏徃
+
+#### 2. 鏂板/缂栬緫瀵硅瘽妗�
+```vue
+<el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
+ <el-select v-model="form.deptId" placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" clearable style="width: 100%">
+ <el-option
+ v-for="dept in deptList"
+ :key="dept.deptId"
+ :label="dept.deptName"
+ :value="dept.deptId"
+ />
+ </el-select>
+</el-form-item>
+```
+**褰卞搷**锛氭柊澧炴垨淇敼杞﹁締鏃讹紝鍙兘閫夋嫨鍒嗗叕鍙镐綔涓哄綊灞為儴闂�
+
+## 鏁版嵁搴撶粨鏋�
+
+### sys_dept 琛ㄧ粨鏋勶紙鍙傝�冿級
+```sql
+CREATE TABLE sys_dept (
+ dept_id BIGINT(20) NOT NULL COMMENT '閮ㄩ棬id',
+ parent_id BIGINT(20) DEFAULT '0' COMMENT '鐖堕儴闂╥d',
+ dept_name VARCHAR(30) DEFAULT '' COMMENT '閮ㄩ棬鍚嶇О',
+ order_num INT(4) DEFAULT '0' COMMENT '鏄剧ず椤哄簭',
+ leader VARCHAR(20) DEFAULT NULL COMMENT '璐熻矗浜�',
+ phone VARCHAR(11) DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
+ email VARCHAR(50) DEFAULT NULL COMMENT '閭',
+ status CHAR(1) DEFAULT '0' COMMENT '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ del_flag CHAR(1) DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+ create_by VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME COMMENT '鍒涘缓鏃堕棿',
+ update_by VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME COMMENT '鏇存柊鏃堕棿',
+ PRIMARY KEY (dept_id)
+) COMMENT='閮ㄩ棬琛�';
+```
+
+### 鍒嗗叕鍙告暟鎹ず渚�
+```sql
+-- 鏍归儴闂�
+INSERT INTO sys_dept VALUES (100, 0, '鎬诲叕鍙�', 0, '绠$悊鍛�', '15888888888', 'admin@qq.com', '0', '0', 'admin', NOW(), '', NULL);
+
+-- 鍒嗗叕鍙革紙parent_id = 100锛�
+INSERT INTO sys_dept VALUES (101, 100, '娣卞湷鍒嗗叕鍙�', 1, '寮犱笁', '15888888881', 'sz@qq.com', '0', '0', 'admin', NOW(), '', NULL);
+INSERT INTO sys_dept VALUES (102, 100, '骞垮窞鍒嗗叕鍙�', 2, '鏉庡洓', '15888888882', 'gz@qq.com', '0', '0', 'admin', NOW(), '', NULL);
+INSERT INTO sys_dept VALUES (103, 100, '鍖椾含鍒嗗叕鍙�', 3, '鐜嬩簲', '15888888883', 'bj@qq.com', '0', '0', 'admin', NOW(), '', NULL);
+
+-- 瀛愰儴闂紙parent_id != 100锛屼笉搴旇鏄剧ず锛�
+INSERT INTO sys_dept VALUES (201, 101, '娣卞湷鎶�鏈儴', 1, '璧靛叚', '15888888884', 'szjs@qq.com', '0', '0', 'admin', NOW(), '', NULL);
+INSERT INTO sys_dept VALUES (202, 101, '娣卞湷涓氬姟閮�', 2, '閽变竷', '15888888885', 'szyw@qq.com', '0', '0', 'admin', NOW(), '', NULL);
+```
+
+## 浣跨敤鍦烘櫙
+
+### 鍦烘櫙1锛氭柊澧炶溅杈�
+1. 鐐瑰嚮"鏂板"鎸夐挳
+2. 濉啓杞﹁締淇℃伅
+3. 閫夋嫨"褰掑睘閮ㄩ棬"鏃讹紝涓嬫媺鍒楄〃鍙樉绀猴細
+ - 娣卞湷鍒嗗叕鍙�
+ - 骞垮窞鍒嗗叕鍙�
+ - 鍖椾含鍒嗗叕鍙�
+4. 涓嶄細鏄剧ず鍚勫垎鍏徃涓嬬殑瀛愰儴闂紙濡傛妧鏈儴銆佷笟鍔¢儴绛夛級
+
+### 鍦烘櫙2锛氭煡璇㈣溅杈�
+1. 鍦ㄦ煡璇㈡潯浠朵腑閫夋嫨"褰掑睘閮ㄩ棬"
+2. 涓嬫媺鍒楄〃鍙樉绀哄垎鍏徃
+3. 鍙互蹇�熺瓫閫夋煇涓垎鍏徃鐨勮溅杈�
+
+### 鍦烘櫙3锛氫慨鏀硅溅杈�
+1. 鐐瑰嚮"淇敼"鎸夐挳
+2. 缂栬緫杞﹁締淇℃伅
+3. 淇敼"褰掑睘閮ㄩ棬"鏃讹紝鍙兘閫夋嫨鍒嗗叕鍙�
+
+## 娴嬭瘯瑕佺偣
+
+### 鍔熻兘娴嬭瘯
+- 鉁� 鏌ヨ鏉′欢涓殑閮ㄩ棬涓嬫媺鍒楄〃鍙樉绀哄垎鍏徃
+- 鉁� 鏂板杞﹁締鏃剁殑閮ㄩ棬涓嬫媺鍒楄〃鍙樉绀哄垎鍏徃
+- 鉁� 缂栬緫杞﹁締鏃剁殑閮ㄩ棬涓嬫媺鍒楄〃鍙樉绀哄垎鍏徃
+- 鉁� 宸查�夋嫨鐨勫垎鍏徃鑳芥纭繚瀛樺埌鏁版嵁搴�
+- 鉁� 杞﹁締鍒楄〃涓殑"褰掑睘閮ㄩ棬"鍒楁纭樉绀哄垎鍏徃鍚嶇О
+
+### 鏁版嵁楠岃瘉
+- 鉁� 楠岃瘉 `deptList` 涓墍鏈夐儴闂ㄧ殑 `parentId` 閮界瓑浜� 100
+- 鉁� 楠岃瘉娌℃湁瀛愰儴闂ㄥ嚭鐜板湪涓嬫媺鍒楄〃涓�
+- 鉁� 楠岃瘉閮ㄩ棬鏁版嵁涓虹┖鏃朵笉浼氭姤閿�
+
+### 杈圭晫娴嬭瘯
+- 鉁� 鏁版嵁搴撲腑娌℃湁鍒嗗叕鍙告椂鐨勫鐞嗭紙鏄剧ず绌哄垪琛級
+- 鉁� 鏁版嵁搴撲腑鍙湁涓�涓垎鍏徃鏃剁殑澶勭悊
+- 鉁� 缃戠粶璇锋眰澶辫触鏃剁殑澶勭悊
+
+## 娉ㄦ剰浜嬮」
+
+### 1. 鏁版嵁涓�鑷存��
+- 纭繚鏁版嵁搴撲腑宸叉湁 `parent_id = 100` 鐨勫垎鍏徃鏁版嵁
+- 濡傛灉闇�瑕佹坊鍔犳柊鐨勫垎鍏徃锛屽繀椤昏缃� `parent_id = 100`
+
+### 2. 鏉冮檺鎺у埗
+- 姝や慨鏀逛笉褰卞搷鐜版湁鐨勬潈闄愭帶鍒�
+- 浠嶇劧閬靛惊绯荤粺鐨勬暟鎹潈闄愯鍒�
+
+### 3. 鍏煎鎬�
+- 淇敼閲囩敤鍓嶇杩囨护锛屼笉渚濊禆鍚庣鎺ュ彛淇敼
+- 鍗充娇鍚庣鎺ュ彛涓嶆敮鎸� `parentId` 鍙傛暟锛屽墠绔篃鑳芥纭繃婊�
+- 纭繚鍚戝悗鍏煎
+
+### 4. 鎬ц兘鑰冭檻
+- 鐢变簬鍒嗗叕鍙告暟閲忛�氬父涓嶄細寰堝锛堜竴鑸笉瓒呰繃100涓級锛屽墠绔繃婊ゆ�ц兘褰卞搷鍙拷鐣�
+- 濡傛灉鍒嗗叕鍙告暟閲忓緢澶э紝寤鸿鍚庣鎻愪緵涓撻棬鐨勬帴鍙�
+
+## 鍚庣画浼樺寲寤鸿
+
+### 1. 鍚庣鎺ュ彛浼樺寲
+寤鸿鍚庣鎻愪緵涓撻棬鐨勫垎鍏徃鏌ヨ鎺ュ彛锛�
+```javascript
+// 鏂板API
+export function listBranchCompany() {
+ return request({
+ url: '/system/dept/branch',
+ method: 'get'
+ })
+}
+```
+
+鍚庣瀹炵幇锛�
+```java
+/**
+ * 鏌ヨ鍒嗗叕鍙稿垪琛�
+ */
+@GetMapping("/branch")
+public AjaxResult listBranchCompany() {
+ SysDept query = new SysDept();
+ query.setParentId(100L);
+ List<SysDept> list = deptService.selectDeptList(query);
+ return success(list);
+}
+```
+
+### 2. 閰嶇疆鍖栫鐞�
+灏� `parent_id = 100` 杩欎釜鍊奸厤缃寲锛�
+```javascript
+// 鍦ㄩ厤缃枃浠朵腑瀹氫箟
+const BRANCH_COMPANY_PARENT_ID = 100;
+
+// 浣跨敤鏃跺紩鐢�
+getDeptList() {
+ listDept({ parentId: BRANCH_COMPANY_PARENT_ID }).then(response => {
+ if (response.data) {
+ this.deptList = response.data.filter(
+ dept => dept.parentId === BRANCH_COMPANY_PARENT_ID
+ );
+ }
+ });
+}
+```
+
+### 3. 缂撳瓨浼樺寲
+濡傛灉鍒嗗叕鍙告暟鎹彉鍖栦笉棰戠箒锛屽彲浠ヨ�冭檻缂撳瓨锛�
+```javascript
+// 浣跨敤Vuex缂撳瓨鍒嗗叕鍙稿垪琛�
+computed: {
+ ...mapState({
+ cachedDeptList: state => state.dept.branchCompanyList
+ })
+},
+
+mounted() {
+ if (!this.cachedDeptList || this.cachedDeptList.length === 0) {
+ this.getDeptList();
+ } else {
+ this.deptList = this.cachedDeptList;
+ }
+}
+```
+
+## 鐩稿叧鏂囨。
+
+- [杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md](./杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md)
+- [鐢ㄦ埛缁戝畾杞﹁締鍔熻兘璇存槑.md](./鐢ㄦ埛缁戝畾杞﹁締鍔熻兘璇存槑.md)
+
+## 鐗堟湰鍘嗗彶
+
+| 鐗堟湰 | 鏃ユ湡 | 淇敼鍐呭 | 淇敼浜� |
+|------|------|---------|--------|
+| 1.0 | 2025-10-15 | 鍒濆鐗堟湰锛屽疄鐜伴儴闂ㄨ繃婊ゅ姛鑳� | - |
+
+## 鎬荤粨
+
+閫氳繃姝ゆ淇敼锛岃溅杈嗙鐞嗗姛鑳戒腑鐨勯儴闂ㄩ�夋嫨鏇村姞瑙勮寖锛岀‘淇濊溅杈嗗彧鑳藉綊灞炰簬鍒嗗叕鍙革紝閬垮厤浜嗘暟鎹眰绾ф贩涔辩殑闂銆傚悓鏃堕噰鐢ㄤ簡鍙岄噸杩囨护鐨勫畨鍏ㄧ瓥鐣ワ紝淇濊瘉浜嗘暟鎹殑鍑嗙‘鎬у拰绯荤粺鐨勭ǔ瀹氭�с��
diff --git "a/prd/\350\275\246\350\276\206\347\273\221\345\256\232\350\247\243\347\273\221\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\350\275\246\350\276\206\347\273\221\345\256\232\350\247\243\347\273\221\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..5b87d17
--- /dev/null
+++ "b/prd/\350\275\246\350\276\206\347\273\221\345\256\232\350\247\243\347\273\221\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,476 @@
+# 杞﹁締缁戝畾涓庤В缁戝姛鑳借鏄�
+
+## 鍔熻兘姒傝堪
+
+鏈郴缁熷疄鐜颁簡瀹屾暣鐨勭敤鎴疯溅杈嗙粦瀹氫笌瑙g粦鍔熻兘锛屾敮鎸佺敤鎴风粦瀹氳溅杈嗐�佸己鍒堕噸鏂扮粦瀹氥�佹煡鐪嬪綋鍓嶇粦瀹氳溅杈嗕互鍙婅В缁戣溅杈嗐��
+
+## 涓�銆佸姛鑳界壒鐐�
+
+### 1. 缁戝畾瑙勫垯
+- 鉁� 涓�涓敤鎴峰悓鏃跺彧鑳界粦瀹氫竴杈嗚溅
+- 鉁� 涓�杈嗚溅鍙互琚涓敤鎴疯疆鐝粦瀹�
+- 鉁� 缁戝畾鏃惰嚜鍔ㄨВ缁戞棫杞﹁締
+- 鉁� 鏀寔鎵爜缁戝畾鍜屼笅鎷夐�夋嫨缁戝畾
+- 鉁� 寮哄埗缁戝畾鏃朵細鎻愮ず褰撳墠缁戝畾杞﹁締淇℃伅
+
+### 2. 瑙g粦瑙勫垯
+- 鉁� 鏀寔鎵嬪姩瑙g粦褰撳墠杞﹁締
+- 鉁� 瑙g粦鎿嶄綔闇�浜屾纭
+- 鉁� 瑙g粦璁板綍淇濈暀鍦ㄦ暟鎹簱涓紙status=1锛�
+- 鉁� 瑙g粦鎴愬姛鍚庤嚜鍔ㄥ埛鏂扮敤鎴蜂俊鎭�
+
+## 浜屻�佹妧鏈疄鐜�
+
+### 1. 鏁版嵁搴撹璁�
+
+#### 琛ㄥ悕锛歴ys_user_vehicle
+
+```sql
+CREATE TABLE IF NOT EXISTS sys_user_vehicle (
+ id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ user_id BIGINT(20) NOT NULL COMMENT '鐢ㄦ埛ID',
+ vehicle_id BIGINT(20) NOT NULL COMMENT '杞﹁締ID',
+ bind_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '缁戝畾鏃堕棿',
+ bind_by VARCHAR(64) DEFAULT '' COMMENT '缁戝畾鎿嶄綔浜�',
+ status CHAR(1) DEFAULT '0' COMMENT '缁戝畾鐘舵�侊紙0姝e父 1瑙g粦锛�',
+ remark VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
+ create_by VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ update_by VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ PRIMARY KEY (id),
+ UNIQUE KEY idx_user_vehicle (user_id, vehicle_id) COMMENT '鐢ㄦ埛杞﹁締鍞竴绱㈠紩',
+ KEY idx_user_id (user_id) COMMENT '鐢ㄦ埛ID绱㈠紩',
+ KEY idx_vehicle_id (vehicle_id) COMMENT '杞﹁締ID绱㈠紩'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐢ㄦ埛杞﹁締缁戝畾琛�';
+```
+
+**瀛楁璇存槑锛�**
+- `status`: 0=姝e父缁戝畾锛�1=宸茶В缁�
+- `bind_time`: 缁戝畾鎿嶄綔鏃堕棿
+- `update_time`: 瑙g粦鎿嶄綔鏃堕棿
+
+### 2. 鍚庣鎺ュ彛
+
+#### Controller灞傦細VehicleInfoController.java
+
+**鍩虹璺緞锛�** `/system/vehicle`
+
+##### 2.1 缁戝畾杞﹁締
+```java
+@PostMapping("/bind")
+public AjaxResult bindVehicle(@RequestBody Map<String, Object> params)
+```
+
+**璇锋眰鍙傛暟锛�**
+```json
+{
+ "userId": 1,
+ "vehicleId": 100
+}
+```
+
+**鍝嶅簲绀轰緥锛�**
+```json
+{
+ "code": 200,
+ "msg": "杞﹁締缁戝畾鎴愬姛"
+}
+```
+
+##### 2.2 瑙g粦杞﹁締
+```java
+@PostMapping("/unbind")
+public AjaxResult unbindVehicle(@RequestBody Map<String, Object> params)
+```
+
+**璇锋眰鍙傛暟锛�**
+```json
+{
+ "userId": 1,
+ "vehicleId": 100
+}
+```
+
+**鍝嶅簲绀轰緥锛�**
+```json
+{
+ "code": 200,
+ "msg": "杞﹁締瑙g粦鎴愬姛"
+}
+```
+
+##### 2.3 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈�
+```java
+@GetMapping("/user/bound/{userId}")
+public AjaxResult getUserBoundVehicle(@PathVariable("userId") Long userId)
+```
+
+**鍝嶅簲绀轰緥锛�**
+```json
+{
+ "code": 200,
+ "data": {
+ "vehicleId": 100,
+ "vehicleNumber": "绮12345",
+ "vehicleType": "鏁戞姢杞�",
+ "vehicleBrand": "绂忕壒",
+ "vehicleModel": "鍏ㄩ『"
+ }
+}
+```
+
+#### Service灞傦細VehicleInfoServiceImpl.java
+
+##### 2.4 缁戝畾杞﹁締涓氬姟閫昏緫
+```java
+@Transactional
+public int bindVehicleToUser(Long userId, Long vehicleId) {
+ // 鍏堣В缁戠敤鎴风殑鎵�鏈夎溅杈嗭紙纭繚涓�涓敤鎴峰彧鑳界粦瀹氫竴杈嗚溅锛�
+ vehicleInfoMapper.unbindAllVehiclesFromUser(userId);
+
+ // 缁戝畾鏂拌溅杈�
+ return vehicleInfoMapper.bindVehicleToUser(userId, vehicleId, bindBy);
+}
+```
+
+**浜嬪姟鐗规�э細**
+- 浣跨敤 `@Transactional` 淇濊瘉鍘熷瓙鎬�
+- 鍏堣В缁戝啀缁戝畾锛屽け璐ヨ嚜鍔ㄥ洖婊�
+
+##### 2.5 瑙g粦杞﹁締涓氬姟閫昏緫
+```java
+public int unbindVehicleFromUser(Long userId, Long vehicleId) {
+ return vehicleInfoMapper.unbindVehicleFromUser(userId, vehicleId);
+}
+```
+
+#### Mapper灞傦細VehicleInfoMapper.xml
+
+##### 2.6 SQL鏄犲皠
+
+**缁戝畾杞﹁締锛�**
+```xml
+<insert id="bindVehicleToUser">
+ INSERT INTO sys_user_vehicle (user_id, vehicle_id, bind_time, bind_by, status, create_by, create_time)
+ VALUES (#{userId}, #{vehicleId}, NOW(), #{bindBy}, '0', #{bindBy}, NOW())
+</insert>
+```
+
+**瑙g粦杞﹁締锛�**
+```xml
+<update id="unbindVehicleFromUser">
+ UPDATE sys_user_vehicle
+ SET status = '1', update_time = NOW()
+ WHERE user_id = #{userId} AND vehicle_id = #{vehicleId} AND status = '0'
+</update>
+```
+
+**瑙g粦鎵�鏈夎溅杈嗭細**
+```xml
+<update id="unbindAllVehiclesFromUser">
+ UPDATE sys_user_vehicle
+ SET status = '1', update_time = NOW()
+ WHERE user_id = #{userId} AND status = '0'
+</update>
+```
+
+**鑾峰彇缁戝畾杞﹁締锛�**
+```xml
+<select id="getUserBoundVehicle" resultMap="VehicleInfoResult">
+ SELECT v.*
+ FROM tb_vehicle_info v
+ INNER JOIN sys_user_vehicle uv ON v.vehicle_id = uv.vehicle_id
+ WHERE uv.user_id = #{userId} AND uv.status = '0'
+ ORDER BY uv.bind_time DESC
+ LIMIT 1
+</select>
+```
+
+### 3. 鍓嶇瀹炵幇
+
+#### 3.1 API灏佽锛歷ehicle.js
+
+```javascript
+// 缁戝畾杞﹁締
+export function bindVehicleToUser(userId, vehicleId) {
+ return request({
+ url: '/system/vehicle/bind',
+ method: 'post',
+ data: { userId, vehicleId }
+ })
+}
+
+// 瑙g粦杞﹁締
+export function unbindVehicleFromUser(userId, vehicleId) {
+ return request({
+ url: '/system/vehicle/unbind',
+ method: 'post',
+ data: { userId, vehicleId }
+ })
+}
+
+// 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈�
+export function getUserBoundVehicle(userId) {
+ return request({
+ url: '/system/vehicle/user/bound/' + userId,
+ method: 'get'
+ })
+}
+```
+
+#### 3.2 缁戝畾杞﹁締椤甸潰锛歱ages/bind-vehicle.vue
+
+**椤甸潰璺緞锛�** `/pages/bind-vehicle`
+
+**涓昏鍔熻兘锛�**
+
+1. **鍔犺浇褰撳墠缁戝畾杞﹁締**
+```javascript
+loadCurrentBoundVehicle() {
+ const userId = this.currentUser.userId
+ getUserBoundVehicle(userId).then(response => {
+ if (response.code === 200 && response.data) {
+ this.currentBoundVehicle = response.data
+ }
+ })
+}
+```
+
+2. **缁戝畾杞﹁締閫昏緫**
+```javascript
+bindVehicle() {
+ // 妫�鏌ユ槸鍚﹂�夋嫨鐨勬槸褰撳墠宸茬粦瀹氱殑杞﹁締
+ if (this.currentBoundVehicle &&
+ this.currentBoundVehicle.vehicleId === this.selectedVehicleId) {
+ this.$modal.showToast('褰撳墠宸茬粦瀹氭杞﹁締锛屾棤闇�閲嶅缁戝畾')
+ return
+ }
+
+ // 濡傛灉宸茬粡缁戝畾浜嗗叾浠栬溅杈嗭紝鎻愮ず鏄惁寮哄埗缁戝畾
+ if (this.currentBoundVehicle) {
+ const confirmMsg = `鎮ㄥ綋鍓嶅凡缁戝畾杞﹁締锛�${currentVehicleNo}\n\n纭瑕佽В缁戞棫杞﹁締骞剁粦瀹氭柊杞﹁締锛�${this.selectedVehiclePlate} 鍚楋紵`
+ this.$modal.confirm(confirmMsg).then(() => {
+ this.performBind()
+ })
+ } else {
+ // 娌℃湁缁戝畾杞﹁締锛岀洿鎺ョ粦瀹�
+ this.$modal.confirm('纭缁戝畾杞﹁締 ' + this.selectedVehiclePlate + ' 鍚楋紵')
+ .then(() => {
+ this.performBind()
+ })
+ }
+}
+```
+
+3. **鎵ц缁戝畾鎿嶄綔**
+```javascript
+performBind() {
+ const userId = this.currentUser.userId
+ bindVehicleToUser(userId, this.selectedVehicleId).then(response => {
+ if (response.code === 200) {
+ this.$modal.showToast('杞﹁締缁戝畾鎴愬姛')
+ this.$store.dispatch('GetInfo') // 鍒锋柊鐢ㄦ埛淇℃伅
+ setTimeout(() => {
+ this.$tab.navigateBack()
+ }, 1500)
+ }
+ })
+}
+```
+
+#### 3.3 涓汉涓績椤甸潰锛歱ages/mine/index.vue
+
+**椤甸潰璺緞锛�** `/pages/mine/index`
+
+**涓昏鍔熻兘锛�**
+
+1. **鏄剧ず缁戝畾杞﹁締淇℃伅**
+```vue
+<view class="info-item">
+ <view class="info-label">缁戝畾杞﹁締锛�</view>
+ <view class="info-value">{{ boundVehicle || '鏈粦瀹�' }}</view>
+</view>
+```
+
+2. **瑙g粦/缁戝畾鎸夐挳**
+```vue
+<!-- 宸茬粦瀹氳溅杈嗭細鏄剧ず瑙g粦鎸夐挳 -->
+<view class="vehicle-actions" v-if="boundVehicle && boundVehicle !== '鏈粦瀹�'">
+ <button class="unbind-btn" @click="unbindVehicle">鍙栨秷缁戝畾杞﹁締</button>
+</view>
+
+<!-- 鏈粦瀹氳溅杈嗭細鏄剧ず缁戝畾鎸夐挳 -->
+<view class="vehicle-actions" v-else>
+ <button class="bind-btn" @click="goToBindVehicle">缁戝畾杞﹁締</button>
+</view>
+```
+
+3. **鑾峰彇缁戝畾杞﹁締淇℃伅**
+```javascript
+getUserInfo() {
+ const userId = this.$store.state.user.userId
+
+ // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ if (userId) {
+ getUserBoundVehicle(userId).then(response => {
+ if (response.code === 200 && response.data) {
+ const vehicle = response.data
+ this.boundVehicle = vehicle.vehicleNumber || '鏈煡杞︾墝'
+ this.boundVehicleId = vehicle.vehicleId
+ } else {
+ this.boundVehicle = '鏈粦瀹�'
+ this.boundVehicleId = null
+ }
+ })
+ }
+}
+```
+
+4. **瑙g粦杞﹁締**
+```javascript
+unbindVehicle() {
+ const userId = this.$store.state.user.userId
+ const vehicleId = this.boundVehicleId
+
+ this.$modal.confirm(`纭鍙栨秷缁戝畾杞﹁締 ${this.boundVehicle} 鍚楋紵`).then(() => {
+ unbindVehicleFromUser(userId, vehicleId).then(response => {
+ if (response.code === 200) {
+ this.boundVehicle = '鏈粦瀹�'
+ this.boundVehicleId = null
+ this.$modal.showToast('鍙栨秷缁戝畾鎴愬姛')
+ this.$store.dispatch('GetInfo') // 鍒锋柊鐢ㄦ埛淇℃伅
+ }
+ })
+ })
+}
+```
+
+## 涓夈�佷笟鍔℃祦绋�
+
+### 缁戝畾杞﹁締娴佺▼
+
+```mermaid
+graph TD
+ A[鐢ㄦ埛閫夋嫨杞﹁締] --> B{宸茬粦瀹氳溅杈�?}
+ B -->|鍚 C[鐩存帴缁戝畾]
+ B -->|鏄瘄 D{閫夋嫨鐩稿悓杞﹁締?}
+ D -->|鏄瘄 E[鎻愮ず鏃犻渶閲嶅缁戝畾]
+ D -->|鍚 F[鎻愮ず寮哄埗缁戝畾纭]
+ F --> G{鐢ㄦ埛纭?}
+ G -->|鏄瘄 H[瑙g粦鏃ц溅杈哴
+ G -->|鍚 I[鍙栨秷鎿嶄綔]
+ H --> J[缁戝畾鏂拌溅杈哴
+ C --> J
+ J --> K[鍒锋柊鐢ㄦ埛淇℃伅]
+ K --> L[杩斿洖涓婁竴椤礭
+```
+
+### 瑙g粦杞﹁締娴佺▼
+
+```mermaid
+graph TD
+ A[鐢ㄦ埛鐐瑰嚮瑙g粦] --> B{宸茬粦瀹氳溅杈�?}
+ B -->|鍚 C[鎻愮ず鏈粦瀹歖
+ B -->|鏄瘄 D[鏄剧ず纭瀵硅瘽妗哴
+ D --> E{鐢ㄦ埛纭?}
+ E -->|鏄瘄 F[璋冪敤瑙g粦API]
+ E -->|鍚 G[鍙栨秷鎿嶄綔]
+ F --> H{瑙g粦鎴愬姛?}
+ H -->|鏄瘄 I[鏇存柊缁戝畾鐘舵�乚
+ H -->|鍚 J[鏄剧ず閿欒淇℃伅]
+ I --> K[鍒锋柊鐢ㄦ埛淇℃伅]
+ K --> L[鏄剧ず鎴愬姛鎻愮ず]
+```
+
+## 鍥涖�佷娇鐢ㄥ満鏅�
+
+### 鍦烘櫙1锛氶娆$粦瀹氳溅杈�
+1. 鐢ㄦ埛杩涘叆涓汉涓績锛岀偣鍑�"缁戝畾杞﹁締"鎸夐挳
+2. 璺宠浆鍒扮粦瀹氳溅杈嗛〉闈�
+3. 閫夋嫨杞︾墝鍙锋垨鎵爜
+4. 纭缁戝畾
+5. 缁戝畾鎴愬姛锛岃繑鍥炰釜浜轰腑蹇�
+
+### 鍦烘櫙2锛氭洿鎹㈢粦瀹氳溅杈�
+1. 鐢ㄦ埛杩涘叆缁戝畾杞﹁締椤甸潰
+2. 绯荤粺鑷姩鍔犺浇褰撳墠缁戝畾杞﹁締
+3. 閫夋嫨鏂拌溅杈�
+4. 绯荤粺鎻愮ず锛歚鎮ㄥ綋鍓嶅凡缁戝畾杞﹁締锛氱菠A12345锛岀‘璁よ瑙g粦鏃ц溅杈嗗苟缁戝畾鏂拌溅杈嗭細绮67890 鍚楋紵`
+5. 鐢ㄦ埛纭
+6. 绯荤粺鑷姩瑙g粦鏃ц溅杈嗗苟缁戝畾鏂拌溅杈�
+7. 缁戝畾鎴愬姛
+
+### 鍦烘櫙3锛氳В缁戣溅杈�
+1. 鐢ㄦ埛杩涘叆涓汉涓績
+2. 鐪嬪埌褰撳墠缁戝畾杞﹁締淇℃伅
+3. 鐐瑰嚮"鍙栨秷缁戝畾杞﹁締"鎸夐挳
+4. 绯荤粺鎻愮ず锛歚纭鍙栨秷缁戝畾杞﹁締 绮12345 鍚楋紵`
+5. 鐢ㄦ埛纭
+6. 瑙g粦鎴愬姛锛屾樉绀�"鏈粦瀹�"
+
+## 浜斻�佹敞鎰忎簨椤�
+
+### 1. 鏁版嵁涓�鑷存��
+- 浣跨敤 `@Transactional` 娉ㄨВ纭繚缁戝畾/瑙g粦鎿嶄綔鐨勫師瀛愭��
+- 閫氳繃鍞竴绱㈠紩闃叉閲嶅缁戝畾
+- 瑙g粦鎿嶄綔涓嶅垹闄よ褰曪紝鍙慨鏀圭姸鎬侊紙status=1锛�
+
+### 2. 鏉冮檺鎺у埗
+- 鎺ュ彛浣跨敤 `@Anonymous` 娉ㄨВ锛屽厑璁稿尶鍚嶈闂�
+- 瀹為檯鐢熶骇鐜寤鸿娣诲姞鏉冮檺楠岃瘉
+- 寤鸿澧炲姞鍙兘瑙g粦鑷繁缁戝畾鐨勮溅杈嗙殑闄愬埗
+
+### 3. 寮傚父澶勭悊
+- 杞﹁締涓嶅瓨鍦ㄦ椂杩斿洖閿欒
+- 杞﹁締鐘舵�佸紓甯告椂涓嶅厑璁哥粦瀹�
+- 缃戠粶璇锋眰澶辫触鏃舵湁鍙嬪ソ鐨勯敊璇彁绀�
+
+### 4. 鐢ㄦ埛浣撻獙
+- 缁戝畾/瑙g粦鎿嶄綔閮介渶瑕佷簩娆$‘璁�
+- 鎻愮ず淇℃伅娓呮櫚鏄庣‘
+- 鎿嶄綔鎴愬姛鍚庤嚜鍔ㄥ埛鏂扮敤鎴蜂俊鎭�
+- 缁戝畾鎴愬姛鍚庡欢杩�1.5绉掕嚜鍔ㄨ繑鍥�
+
+## 鍏�佹祴璇曡鐐�
+
+### 鍔熻兘娴嬭瘯
+- 鉁� 棣栨缁戝畾杞﹁締
+- 鉁� 寮哄埗閲嶆柊缁戝畾锛堟浛鎹㈡棫杞﹁締锛�
+- 鉁� 閲嶅缁戝畾鐩稿悓杞﹁締锛堝簲鎻愮ず鏃犻渶閲嶅缁戝畾锛�
+- 鉁� 瑙g粦褰撳墠杞﹁締
+- 鉁� 瑙g粦鍚庨噸鏂扮粦瀹�
+
+### 寮傚父娴嬭瘯
+- 鉁� 缁戝畾涓嶅瓨鍦ㄧ殑杞﹁締
+- 鉁� 缁戝畾鐘舵�佸紓甯哥殑杞﹁締
+- 鉁� 缃戠粶寮傚父鏃剁殑澶勭悊
+- 鉁� 骞跺彂缁戝畾鍚屼竴杈嗚溅鐨勫鐞�
+
+### 杈圭晫娴嬭瘯
+- 鉁� 鐢ㄦ埛鏈櫥褰曟椂鐨勫鐞�
+- 鉁� 杞﹁締鍒楄〃涓虹┖鏃剁殑澶勭悊
+- 鉁� 鏁版嵁搴撴搷浣滃け璐ユ椂鐨勫洖婊�
+
+## 涓冦�佹枃浠舵竻鍗�
+
+### 鍚庣鏂囦欢
+1. `sql/user_vehicle_bind.sql` - 鏁版嵁搴撹〃缁撴瀯
+2. `ruoyi-system/mapper/VehicleInfoMapper.java` - Mapper鎺ュ彛
+3. `ruoyi-system/mapper/VehicleInfoMapper.xml` - SQL鏄犲皠
+4. `ruoyi-system/service/IVehicleInfoService.java` - Service鎺ュ彛
+5. `ruoyi-system/service/impl/VehicleInfoServiceImpl.java` - Service瀹炵幇
+6. `ruoyi-admin/controller/VehicleInfoController.java` - Controller
+
+### 鍓嶇鏂囦欢
+1. `app/api/vehicle.js` - 杞﹁締API灏佽
+2. `app/pages/bind-vehicle.vue` - 缁戝畾杞﹁締椤甸潰
+3. `app/pages/mine/index.vue` - 涓汉涓績椤甸潰
+
+## 鍏�佺増鏈巻鍙�
+
+| 鐗堟湰 | 鏃ユ湡 | 淇敼鍐呭 | 淇敼浜� |
+|------|------|---------|--------|
+| 1.0 | 2025-10-15 | 鍒濆鐗堟湰锛屽疄鐜板熀纭�缁戝畾瑙g粦鍔熻兘 | - |
+| 1.1 | 2025-10-15 | 淇API璺緞閿欒锛屽畬鍠勮В缁戝姛鑳� | - |
+| 1.2 | 2025-10-15 | 瀹屽杽涓汉涓績瑙g粦鍔熻兘瀹炵幇 | - |
diff --git "a/prd/\351\203\250\351\227\250\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\351\203\250\351\227\250\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..d5e8d0d
--- /dev/null
+++ "b/prd/\351\203\250\351\227\250\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,198 @@
+# 閮ㄩ棬鍚屾鍔熻兘璇存槑鏂囨。
+
+## 鍔熻兘姒傝堪
+鏈姛鑳界敤浜庝粠SQL Server鏁版嵁搴撳悓姝ュ垎鍏徃鍜岄儴闂ㄦ暟鎹埌鑻ヤ緷绯荤粺鐨刞sys_dept`琛ㄤ腑銆�
+
+## 鏁版嵁婧�
+浠嶴QL Server鏁版嵁搴撶殑`uv_department`瑙嗗浘涓幏鍙�"鍚堜綔鍗曚綅"涓嬬殑鎵�鏈夊垎鍏徃鏁版嵁銆�
+
+### SQL鏌ヨ
+```sql
+SELECT b.departmentID, b.departmentName
+FROM uv_department a
+INNER JOIN uv_department b ON a.departmentID = b.parentID
+WHERE a.departmentName = '鍚堜綔鍗曚綅'
+```
+
+## 鏁版嵁澶勭悊瑙勫垯
+
+### 1. 閮ㄩ棬鍚嶇О瑙f瀽
+SQL Server涓殑閮ㄩ棬鍚嶇О鏍煎紡涓猴細`鍩庡競--閮ㄩ棬绫诲瀷`
+
+绀轰緥锛�
+- `婀涙睙--鎶ゅ+`
+- `婀涙睙--杞﹂槦`
+- `婀涙睙--瀹㈡湇`
+- `婀涙睙--鍔炲叕瀹
+
+### 2. 鍚屾閫昏緫
+1. **瑙f瀽閮ㄩ棬鍚嶇О**锛氬皢`婀涙睙--鎶ゅ+`瑙f瀽涓猴細
+ - 鍒嗗叕鍙稿悕绉帮細`婀涙睙鍒嗗叕鍙竊
+ - 瀛愰儴闂ㄥ悕绉帮細`鎶ゅ+`
+
+2. **鍒涘缓/鏇存柊鍒嗗叕鍙�**锛�
+ - 鐖惰妭鐐癸細鑻ヤ緷绉戞妧锛坉ept_id=100锛�
+ - 妫�鏌ユ槸鍚﹀凡瀛樺湪鍚屽悕鍒嗗叕鍙�
+ - 涓嶅瓨鍦ㄥ垯鍒涘缓鏂板垎鍏徃
+ - 瀛樺湪鍒欏鐢ㄨ鍒嗗叕鍙�
+
+3. **鍒涘缓/鏇存柊瀛愰儴闂�**锛�
+ - 鐖惰妭鐐癸細瀵瑰簲鐨勫垎鍏徃
+ - 璁板綍`department_id`瀛楁锛圫QL Server涓殑departmentID锛�
+ - 妫�鏌ユ槸鍚﹀凡瀛樺湪锛堟牴鎹甦epartment_id鍜宲arent_id锛�
+ - 涓嶅瓨鍦ㄥ垯鍒涘缓鏂伴儴闂�
+ - 瀛樺湪鍒欐洿鏂伴儴闂ㄤ俊鎭�
+
+## 鏁版嵁搴撲慨鏀�
+
+### 1. 琛ㄧ粨鏋勫彉鏇�
+鍦╜sys_dept`琛ㄤ腑鏂板瀛楁锛�
+```sql
+ALTER TABLE sys_dept ADD COLUMN department_id INT NULL COMMENT 'SQL Server涓殑閮ㄩ棬ID';
+CREATE INDEX idx_department_id ON sys_dept(department_id);
+```
+
+### 2. 瀹炰綋绫诲彉鏇�
+`SysDept`绫绘柊澧炲瓧娈碉細
+- `private Integer departmentId;` - SQL Server涓殑閮ㄩ棬ID
+
+## 鎺ュ彛璇存槑
+
+### 鍚屾鎺ュ彛
+- **URL**: `POST /system/dept/sync/branch`
+- **鏉冮檺**: `system:dept:sync`
+- **杩斿洖鏁版嵁**:
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 12, 鏇存柊閮ㄩ棬: 0",
+ "data": {
+ "createdBranch": 3,
+ "updatedBranch": 0,
+ "createdDept": 12,
+ "updatedDept": 0,
+ "totalProcessed": 12
+ }
+}
+```
+
+## 浣跨敤姝ラ
+
+### 1. 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+# 娣诲姞department_id瀛楁
+mysql -u root -p your_database < sql/add_department_id_to_sys_dept.sql
+
+# 娣诲姞鑿滃崟鏉冮檺锛堝彲閫夛級
+mysql -u root -p your_database < sql/dept_sync_menu.sql
+```
+
+### 2. 閲嶅惎鍚庣鏈嶅姟
+```bash
+cd ruoyi-admin
+mvn clean package
+java -jar target/ruoyi-admin.jar
+```
+
+### 3. 璋冪敤鍚屾鎺ュ彛
+浣跨敤Postman鎴栧叾浠栧伐鍏疯皟鐢細
+```
+POST http://localhost:8080/system/dept/sync/branch
+Headers:
+ Authorization: Bearer {token}
+```
+
+鎴栧湪鍓嶇閮ㄩ棬绠$悊椤甸潰娣诲姞"鍚屾"鎸夐挳銆�
+
+## 鍚屾绀轰緥
+
+### 杈撳叆鏁版嵁锛圫QL Server锛�
+```
+departmentID | departmentName
+1001 | 婀涙睙--鎶ゅ+
+1002 | 婀涙睙--杞﹂槦
+1003 | 婀涙睙--瀹㈡湇
+1004 | 婀涙睙--鍔炲叕瀹�
+2001 | 骞垮窞--鎶ゅ+
+2002 | 骞垮窞--杞﹂槦
+```
+
+### 杈撳嚭缁撴灉锛坰ys_dept琛級
+```
+dept_id | parent_id | dept_name | ancestors | department_id
+200 | 100 | 婀涙睙鍒嗗叕鍙� | 0,100 | NULL
+201 | 200 | 鎶ゅ+ | 0,100,200 | 1001
+202 | 200 | 杞﹂槦 | 0,100,200 | 1002
+203 | 200 | 瀹㈡湇 | 0,100,200 | 1003
+204 | 200 | 鍔炲叕瀹� | 0,100,200 | 1004
+210 | 100 | 骞垮窞鍒嗗叕鍙� | 0,100 | NULL
+211 | 210 | 鎶ゅ+ | 0,100,210 | 2001
+212 | 210 | 杞﹂槦 | 0,100,210 | 2002
+```
+
+## 鏍稿績浠g爜鏂囦欢
+
+### 鍚庣
+- `DepartmentSyncDTO.java` - 閮ㄩ棬鍚屾DTO
+- `DepartmentSyncMapper.java` - 閮ㄩ棬鍚屾Mapper鎺ュ彛
+- `DepartmentSyncMapper.xml` - 閮ㄩ棬鍚屾Mapper XML
+- `IDepartmentSyncService.java` - 閮ㄩ棬鍚屾Service鎺ュ彛
+- `DepartmentSyncServiceImpl.java` - 閮ㄩ棬鍚屾Service瀹炵幇
+- `DepartmentSyncController.java` - 閮ㄩ棬鍚屾Controller
+- `SysDept.java` - 閮ㄩ棬瀹炰綋锛堟坊鍔燿epartmentId瀛楁锛�
+- `SysDeptMapper.java` - 閮ㄩ棬Mapper锛堟坊鍔犳柊鏌ヨ鏂规硶锛�
+- `SysDeptMapper.xml` - 閮ㄩ棬Mapper XML锛堟坊鍔犳柊SQL锛�
+
+### 鏁版嵁搴撹剼鏈�
+- `sql/add_department_id_to_sys_dept.sql` - 娣诲姞瀛楁
+- `sql/dept_sync_menu.sql` - 娣诲姞鑿滃崟鏉冮檺
+
+## 娉ㄦ剰浜嬮」
+
+1. **浜嬪姟澶勭悊**锛氬悓姝ユ搷浣滀娇鐢╜@Transactional`娉ㄨВ锛岀‘淇濇暟鎹竴鑷存��
+2. **骞傜瓑鎬�**锛氬娆℃墽琛屽悓姝ユ搷浣滀笉浼氶噸澶嶅垱寤烘暟鎹�
+3. **department_id鍞竴鎬�**锛氶�氳繃department_id瀛楁閬垮厤閲嶅鍚屾
+4. **鏃ュ織璁板綍**锛氳缁嗚褰曞悓姝ヨ繃绋嬶紝渚夸簬鎺掓煡闂
+5. **鏉冮檺鎺у埗**锛氶渶瑕乣system:dept:sync`鏉冮檺鎵嶈兘鎵ц鍚屾
+
+## 鎵╁睍璇存槑
+
+### 濡傛灉闇�瑕佸畾鏃跺悓姝�
+鍙互鍦╜ruoyi-quartz`妯″潡涓坊鍔犲畾鏃朵换鍔★細
+
+```java
+@Component("departmentSyncTask")
+public class DepartmentSyncTask {
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ public void execute() {
+ departmentSyncService.syncBranchDepartments();
+ }
+}
+```
+
+鍦ㄧ郴缁熺鐞�->瀹氭椂浠诲姟涓厤缃細
+- 浠诲姟鍚嶇О锛氬垎鍏徃鍚屾
+- 璋冪敤鐩爣瀛楃涓诧細`departmentSyncTask.execute`
+- cron琛ㄨ揪寮忥細`0 0 2 * * ?`锛堟瘡澶╁噷鏅�2鐐规墽琛岋級
+
+## 甯歌闂
+
+### Q1: 鍚屾鍚庨儴闂ㄥ眰绾т笉瀵癸紵
+A: 妫�鏌ancestors`瀛楁鏄惁姝g‘锛屾牸寮忓簲涓篳0,100,{鍒嗗叕鍙窱D}`
+
+### Q2: 閲嶅鎵ц鍚屾浼氬垱寤洪噸澶嶆暟鎹悧锛�
+A: 涓嶄細锛岀郴缁熶細鏍规嵁department_id鍜岄儴闂ㄥ悕绉板垽鏂槸鍚﹀凡瀛樺湪
+
+### Q3: 濡備綍澶勭悊閮ㄩ棬鍚嶇О鍙樻洿锛�
+A: 绯荤粺浼氭牴鎹甦epartment_id鏇存柊閮ㄩ棬鍚嶇О
+
+### Q4: SQL Server杩炴帴澶辫触鎬庝箞鍔烇紵
+A: 妫�鏌application-dev.yml`涓殑sqlserver鏁版嵁婧愰厤缃�
+
+## 浣滆��
+ruoyi
+
+## 鏃ユ湡
+2025-10-18
diff --git "a/prd/\351\246\226\351\241\265\344\273\273\345\212\241\346\237\245\350\257\242\344\274\230\345\214\226.md" "b/prd/\351\246\226\351\241\265\344\273\273\345\212\241\346\237\245\350\257\242\344\274\230\345\214\226.md"
new file mode 100644
index 0000000..a2e4fee
--- /dev/null
+++ "b/prd/\351\246\226\351\241\265\344\273\273\345\212\241\346\237\245\350\257\242\344\274\230\345\214\226.md"
@@ -0,0 +1,146 @@
+# 棣栭〉浠诲姟鏌ヨ浼樺寲璇存槑
+
+## 闇�姹傝儗鏅�
+棣栭〉闇�瑕佹樉绀轰笌褰撳墠鐢ㄦ埛鐩稿叧鐨勬墍鏈夋湭瀹屾垚浠诲姟锛屽寘鎷細
+1. **鐢ㄦ埛鍒涘缓鐨勪换鍔�**锛堝垱寤轰汉鏄綋鍓嶇敤鎴凤級
+2. **鍒嗛厤缁欏綋鍓嶇敤鎴风殑浠诲姟**锛堝垎閰嶄汉鏄綋鍓嶇敤鎴凤級
+3. **鎵ц浜哄憳鏄綋鍓嶇敤鎴风殑浠诲姟**锛堟墽琛屼汉鏄綋鍓嶇敤鎴凤級
+
+涔嬪墠鐨勫疄鐜板彧鏄剧ず鍒嗛厤缁欏綋鍓嶇敤鎴风殑浠诲姟锛坄assigneeId`锛夛紝涓嶅鍏ㄩ潰銆�
+
+## 瀹炵幇鏂规
+
+### 鍚庣瀹炵幇
+鍚庣宸茬粡鎻愪緵浜� `/task/my` 鎺ュ彛锛岃鎺ュ彛鍦� `SysTaskMapper.xml` 涓殑瀹炵幇濡備笅锛�
+
+```sql
+SELECT ...
+FROM sys_task t
+WHERE t.del_flag = '0'
+ AND (t.creator_id = #{userId} OR t.assignee_id = #{userId})
+ORDER BY ...
+```
+
+杩欎釜鎺ュ彛鏌ヨ浜嗭細
+- `creator_id = 褰撳墠鐢ㄦ埛ID`锛堢敤鎴峰垱寤虹殑浠诲姟锛�
+- `assignee_id = 褰撳墠鐢ㄦ埛ID`锛堝垎閰嶇粰鐢ㄦ埛鐨勪换鍔★紝鍖呮嫭鎵ц浜猴級
+
+### 鍓嶇瀹炵幇
+
+#### 1. 鏂板API鏂规硶
+鍦� `app/api/task.js` 涓柊澧烇細
+
+```javascript
+// 鑾峰彇鎴戠殑浠诲姟鍒楄〃
+export function getMyTasks() {
+ return request({
+ url: '/task/my',
+ method: 'get'
+ })
+}
+```
+
+#### 2. 淇敼棣栭〉缁勪欢
+鍦� `app/pages/index.vue` 涓細
+
+**淇敼寮曞叆锛�**
+```javascript
+// 涔嬪墠
+import { listTask, changeTaskStatus } from '@/api/task'
+
+// 涔嬪悗
+import { getMyTasks, changeTaskStatus } from '@/api/task'
+```
+
+**淇敼鍔犺浇鏂规硶锛�**
+```javascript
+loadRunningTasks() {
+ // 浣跨敤 /task/my 鎺ュ彛鑾峰彇褰撳墠鐢ㄦ埛鐩稿叧鐨勬墍鏈変换鍔�
+ getMyTasks().then(response => {
+ // 杩囨护鍑烘湭瀹屾垚鍜屾湭鍙栨秷鐨勪换鍔�
+ const allTasks = Array.isArray(data) ? data : []
+ this.taskList = allTasks
+ .filter(task => {
+ return task.taskStatus !== 'COMPLETED' && task.taskStatus !== 'CANCELLED'
+ })
+ .map(task => {
+ // ... 鏁版嵁鏍煎紡鍖�
+ })
+ })
+}
+```
+
+## 鏁版嵁杩囨护閫昏緫
+
+### 鍚庣杩囨护
+- 鍙繑鍥炰笌褰撳墠鐢ㄦ埛鐩稿叧鐨勪换鍔★紙鍒涘缓浜烘垨鎵ц浜猴級
+- 宸插垹闄ょ殑浠诲姟涓嶈繑鍥烇紙`del_flag = '0'`锛�
+
+### 鍓嶇杩囨护
+- 鍙樉绀烘湭瀹屾垚鍜屾湭鍙栨秷鐨勪换鍔�
+- 鎺掗櫎鐘舵�侊細`COMPLETED`锛堝凡瀹屾垚锛夈�乣CANCELLED`锛堝凡鍙栨秷锛�
+
+## 浼樺娍瀵规瘮
+
+### 涔嬪墠鐨勫疄鐜�
+```javascript
+// 鍙煡璇㈠垎閰嶇粰褰撳墠鐢ㄦ埛鐨勪换鍔�
+const queryParams = {
+ assigneeId: userId,
+ taskStatuses: 'PENDING,DEPARTING,ARRIVED,RETURNING,IN_PROGRESS'
+}
+listTask(queryParams)
+```
+
+**闄愬埗锛�**
+- 鍙兘鐪嬪埌鍒嗛厤缁欒嚜宸辩殑浠诲姟
+- 鐪嬩笉鍒拌嚜宸卞垱寤轰絾鍒嗛厤缁欏埆浜虹殑浠诲姟
+- 闇�瑕佹墜鍔ㄦ寚瀹氱姸鎬佸垪琛�
+
+### 鐜板湪鐨勫疄鐜�
+```javascript
+// 鑾峰彇鎵�鏈変笌鐢ㄦ埛鐩稿叧鐨勪换鍔�
+getMyTasks()
+```
+
+**浼樺娍锛�**
+- 鑷姩鍖呭惈鐢ㄦ埛鍒涘缓鐨勪换鍔�
+- 鑷姩鍖呭惈鍒嗛厤缁欑敤鎴风殑浠诲姟
+- 鍚庣缁熶竴澶勭悊鏌ヨ閫昏緫
+- 鍓嶇绠�鍗曡繃婊ょ姸鎬佸嵆鍙�
+
+## 娴嬭瘯瑕佺偣
+
+### 1. 鐢ㄦ埛鍒涘缓鐨勪换鍔�
+- 鍒涘缓涓�涓换鍔★紝鍒嗛厤缁欏叾浠栦汉
+- 棣栭〉搴旇鑳界湅鍒拌繖涓换鍔�
+
+### 2. 鍒嗛厤缁欑敤鎴风殑浠诲姟
+- 鍏朵粬鐢ㄦ埛鍒涘缓浠诲姟锛屽垎閰嶇粰褰撳墠鐢ㄦ埛
+- 棣栭〉搴旇鑳界湅鍒拌繖涓换鍔�
+
+### 3. 鎵ц浜烘槸鐢ㄦ埛鐨勪换鍔�
+- 浠诲姟鐨勬墽琛屼汉瀛楁锛坄assigneeId`锛夎缃负褰撳墠鐢ㄦ埛
+- 棣栭〉搴旇鑳界湅鍒拌繖涓换鍔�
+
+### 4. 鐘舵�佽繃婊�
+- 宸插畬鎴愮殑浠诲姟涓嶆樉绀�
+- 宸插彇娑堢殑浠诲姟涓嶆樉绀�
+- 鍏朵粬鐘舵�佺殑浠诲姟閮芥樉绀�
+
+## 鐩稿叧鏂囦欢
+
+### 鍓嶇鏂囦欢
+- `app/api/task.js` - 鏂板 `getMyTasks` API鏂规硶
+- `app/pages/index.vue` - 淇敼浠诲姟鍔犺浇閫昏緫
+
+### 鍚庣鏂囦欢
+- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java` - `/task/my` 鎺ュ彛
+- `ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml` - `selectMyTasks` SQL鏌ヨ
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java` - `selectMyTasks` 鏈嶅姟鏂规硶
+
+## 娉ㄦ剰浜嬮」
+
+1. **鎬ц兘鑰冭檻**锛歚/task/my` 鎺ュ彛宸茬粡鍦⊿QL灞傞潰鍋氫簡浼樺寲锛屼娇鐢ㄧ储寮曟煡璇�
+2. **鏁版嵁瀹夊叏**锛氬悗绔嚜鍔ㄨ幏鍙栧綋鍓嶇櫥褰曠敤鎴稩D锛屽墠绔棤娉曠鏀�
+3. **鍚戝悗鍏煎**锛氫繚鐣欎簡鍘熸湁鐨� `listTask` 鏂规硶锛屼笉褰卞搷鍏朵粬椤甸潰浣跨敤
diff --git "a/prd/\351\246\226\351\241\265\347\224\250\346\210\267ID\350\216\267\345\217\226\351\227\256\351\242\230\344\277\256\345\244\215.md" "b/prd/\351\246\226\351\241\265\347\224\250\346\210\267ID\350\216\267\345\217\226\351\227\256\351\242\230\344\277\256\345\244\215.md"
new file mode 100644
index 0000000..46df7e1
--- /dev/null
+++ "b/prd/\351\246\226\351\241\265\347\224\250\346\210\267ID\350\216\267\345\217\226\351\227\256\351\242\230\344\277\256\345\244\215.md"
@@ -0,0 +1,350 @@
+# 棣栭〉鐢ㄦ埛ID鑾峰彇闂淇璇存槑
+
+## 闂鎻忚堪
+
+鍦ㄩ椤电偣鍑�"缁戝畾杞﹁締"鎸夐挳鏃讹紝璋冪敤鎺ュ彛 `/system/vehicle/user/bound/undefined`锛屽鑷� [userId](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\ruoyi-system\src\main\java\com\ruoyi\system\domain\SysUserPost.java#L13-L13) 涓� `undefined`锛屾棤娉曟纭幏鍙栫敤鎴风粦瀹氱殑杞﹁締淇℃伅銆�
+
+## 闂鍒嗘瀽
+
+### 閿欒鍘熷洜
+
+鍦� [`pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue) 涓細
+
+1. **缂哄皯 currentUser 璁$畻灞炴��**
+ ```javascript
+ computed: {
+ ...mapState({
+ userName: state => state.user.name
+ // 鉂� 缂哄皯 currentUser 鏄犲皠
+ })
+ }
+ ```
+
+2. **閿欒浣跨敤 currentUser.userId**
+ ```javascript
+ loadRunningTasks() {
+ const queryParams = {
+ assigneeId: this.currentUser.userId, // 鉂� currentUser 鏈畾涔�
+ }
+ }
+ ```
+
+### 閿欒褰卞搷鑼冨洿
+
+1. 鉁� **宸叉墽琛屼絾鏈夐棶棰樼殑鍔熻兘**锛�
+ - `loadUserProfile()` - 璋冪敤 [getUserProfile](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\ruoyi-system\src\main\java\com\ruoyi\system\service\ISysUserService.java#L34-L34) API锛堜笉闇�瑕� userId 鍙傛暟锛夆渽 姝e父
+ - `loadRunningTasks()` - 浣跨敤 `this.currentUser.userId` 鉂� 鎶ラ敊
+
+2. 鉂� **鍙楀奖鍝嶇殑鎺ュ彛璋冪敤**锛�
+ - 鑾峰彇缁戝畾杞﹁締淇℃伅鏃讹紝闂存帴鍙楀奖鍝嶏紙鍥犱负渚濊禆鐢ㄦ埛鐧诲綍鐘舵�侊級
+ - 鍔犺浇浠诲姟鍒楄〃鏃讹紝鏃犳硶鑾峰彇姝g‘鐨� assigneeId
+
+## 瑙e喅鏂规
+
+### 淇敼鏂囦欢
+**鏂囦欢璺緞**锛歔`app/pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue)
+
+### 鍏蜂綋淇敼
+
+#### 1. 娣诲姞 currentUser 璁$畻灞炴��
+
+**淇敼鍓嶏細**
+```javascript
+computed: {
+ ...mapState({
+ userName: state => state.user.name
+ }),
+ // ... 鍏朵粬璁$畻灞炴��
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+computed: {
+ ...mapState({
+ userName: state => state.user.name,
+ currentUser: state => state.user // 鉁� 娣诲姞 currentUser 鏄犲皠
+ }),
+ // ... 鍏朵粬璁$畻灞炴��
+}
+```
+
+#### 2. 浼樺寲 loadUserProfile() 鏂规硶
+
+**淇敼鍓嶏細**
+```javascript
+loadUserProfile() {
+ getUserProfile().then(response => {
+ const userInfo = response.data || response
+ if (userInfo.boundVehicle) {
+ this.boundVehicle = userInfo.boundVehicle.vehicleNumber
+ this.boundVehicleId = userInfo.boundVehicle.vehicleId
+ }
+ }).catch(error => {
+ console.error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触:', error)
+ })
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+loadUserProfile() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鑾峰彇缁戝畾杞﹁締淇℃伅')
+ return
+ }
+
+ getUserProfile().then(response => {
+ const userInfo = response.data || response
+ if (userInfo.boundVehicle) {
+ this.boundVehicle = userInfo.boundVehicle.vehicleNumber
+ this.boundVehicleId = userInfo.boundVehicle.vehicleId
+ }
+ }).catch(error => {
+ console.error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触:', error)
+ })
+}
+```
+
+**鏀硅繘鐐癸細**
+- 鉁� 娣诲姞鐢ㄦ埛鐧诲綍鐘舵�佹鏌�
+- 鉁� 鎻愬墠杩斿洖锛岄伩鍏嶆棤鏁堢殑 API 璋冪敤
+
+#### 3. 浼樺寲 loadRunningTasks() 鏂规硶
+
+**淇敼鍓嶏細**
+```javascript
+loadRunningTasks() {
+ this.loading = true
+ const queryParams = {
+ pageNum: 1,
+ pageSize: 100,
+ assigneeId: this.currentUser.userId, // 鉂� currentUser 鏈畾涔�
+ taskStatuses: 'PENDING,DEPARTING,ARRIVED,RETURNING,IN_PROGRESS'
+ }
+ // ...
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+loadRunningTasks() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鍔犺浇浠诲姟鍒楄〃')
+ return
+ }
+
+ this.loading = true
+ const queryParams = {
+ pageNum: 1,
+ pageSize: 100,
+ assigneeId: userId, // 鉁� 浣跨敤宸查獙璇佺殑 userId
+ taskStatuses: 'PENDING,DEPARTING,ARRIVED,RETURNING,IN_PROGRESS'
+ }
+ // ...
+}
+```
+
+**鏀硅繘鐐癸細**
+- 鉁� 鎻愬彇 userId 鍒扮嫭绔嬪彉閲�
+- 鉁� 娣诲姞鐢ㄦ埛鐧诲綍鐘舵�佹鏌�
+- 鉁� 鎻愬墠杩斿洖锛岄伩鍏嶆棤鏁堢殑 API 璋冪敤
+- 鉁� 浠g爜鏇存竻鏅版槗璇�
+
+## Vuex 鐘舵�佺鐞�
+
+### state.user 鏁版嵁缁撴瀯
+
+鏍规嵁椤圭洰涓殑 Vuex 閰嶇疆锛宍state.user` 鍖呭惈浠ヤ笅淇℃伅锛�
+
+```javascript
+{
+ userId: 1, // 鐢ㄦ埛ID
+ name: '寮犱笁', // 鐢ㄦ埛鍚�
+ avatar: '', // 澶村儚
+ deptId: 101, // 閮ㄩ棬ID
+ roles: [], // 瑙掕壊鍒楄〃
+ permissions: [] // 鏉冮檺鍒楄〃
+}
+```
+
+### 姝g‘浣跨敤鏂瑰紡
+
+#### 鏂瑰紡1锛氶�氳繃 mapState 鏄犲皠鏁翠釜 user 瀵硅薄
+
+```javascript
+computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+}
+
+// 浣跨敤鏃讹細
+this.currentUser.userId
+this.currentUser.name
+this.currentUser.deptId
+```
+
+#### 鏂瑰紡2锛氶�氳繃 mapState 鏄犲皠鍗曚釜灞炴��
+
+```javascript
+computed: {
+ ...mapState({
+ userId: state => state.user.userId,
+ userName: state => state.user.name,
+ userDeptId: state => state.user.deptId
+ })
+}
+
+// 浣跨敤鏃讹細
+this.userId
+this.userName
+this.userDeptId
+```
+
+**鎺ㄨ崘鏂瑰紡1**锛屽洜涓猴細
+- 鉁� 浠g爜鏇寸畝娲�
+- 鉁� 鏄撲簬鎵╁睍锛堥渶瑕佹柊灞炴�ф椂涓嶇敤淇敼 computed锛�
+- 鉁� 涓庡叾浠栭〉闈繚鎸佷竴鑷达紙濡� [`bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue)锛�
+
+## 鍙傝�冨疄鐜�
+
+### bind-vehicle.vue 鐨勬纭疄鐜�
+
+[`bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) 涓娇鐢ㄤ簡鐩稿悓鐨勬ā寮忥細
+
+```javascript
+computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+},
+
+methods: {
+ loadCurrentBoundVehicle() {
+ const userId = this.currentUser.userId
+ getUserBoundVehicle(userId).then(response => {
+ // ...
+ })
+ }
+}
+```
+
+杩欐槸鏈淇鐨勫弬鑰冩爣鍑嗐��
+
+## 娴嬭瘯楠岃瘉
+
+### 鍔熻兘娴嬭瘯
+
+1. **鐢ㄦ埛鐧诲綍鐘舵��**
+ - 鉁� 宸茬櫥褰曪細姝e父鏄剧ず鐢ㄦ埛鍚嶅拰缁戝畾杞﹁締淇℃伅
+ - 鉁� 鏈櫥褰曪細鎺у埗鍙拌緭鍑洪敊璇俊鎭紝涓嶅彂璧� API 璇锋眰
+
+2. **缁戝畾杞﹁締鍔熻兘**
+ - 鉁� 鐐瑰嚮"缁戝畾杞﹁締"鎸夐挳锛屾纭烦杞埌缁戝畾椤甸潰
+ - 鉁� 缁戝畾鎴愬姛鍚庤繑鍥為椤碉紝鏄剧ず鏇存柊鍚庣殑杞﹁締淇℃伅
+
+3. **浠诲姟鍒楄〃鍔犺浇**
+ - 鉁� 姝g‘鍔犺浇褰撳墠鐢ㄦ埛鐨勪换鍔″垪琛�
+ - 鉁� assigneeId 鍙傛暟姝g‘浼犻��
+
+### API 璋冪敤楠岃瘉
+
+淇鍓嶏細
+```
+GET /system/vehicle/user/bound/undefined 鉂� 閿欒
+```
+
+淇鍚庯細
+```
+GET /system/vehicle/user/bound/1 鉁� 姝g‘
+```
+
+## 棰勯槻鎺柦
+
+### 1. 缁熶竴 Vuex 浣跨敤瑙勮寖
+
+鍦ㄦ墍鏈夐〉闈腑锛岄渶瑕佷娇鐢ㄧ敤鎴蜂俊鎭椂锛岀粺涓�閲囩敤浠ヤ笅鏂瑰紡锛�
+
+```javascript
+export default {
+ computed: {
+ ...mapState({
+ currentUser: state => state.user
+ })
+ },
+
+ methods: {
+ someMethod() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰�')
+ return
+ }
+ // 缁х画涓氬姟閫昏緫
+ }
+ }
+}
+```
+
+### 2. 娣诲姞鐢ㄦ埛鐧诲綍妫�鏌�
+
+鍦ㄦ墍鏈夐渶瑕佺敤鎴蜂俊鎭殑鏂规硶涓紝娣诲姞鐧诲綍鐘舵�佹鏌ワ細
+
+```javascript
+const userId = this.currentUser.userId
+if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鎵ц鎿嶄綔')
+ return
+}
+```
+
+### 3. 浣跨敤 ESLint 瑙勫垯
+
+鍙互娣诲姞 ESLint 瑙勫垯妫�娴嬫湭瀹氫箟鐨勫彉閲忥細
+
+```json
+{
+ "rules": {
+ "no-undef": "error",
+ "no-unused-vars": "warn"
+ }
+}
+```
+
+## 鐩稿叧鏂囦欢
+
+### 鏈淇敼娑夊強鐨勬枃浠�
+- [`app/pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue) - 棣栭〉
+
+### 鐩稿叧鍙傝�冩枃浠�
+- [`app/pages/bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) - 缁戝畾杞﹁締椤甸潰锛堟纭疄鐜扮ず渚嬶級
+- [`app/pages/mine/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\mine\index.vue) - 涓汉涓績锛堟纭疄鐜扮ず渚嬶級
+- [`app/api/vehicle.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js) - 杞﹁締鐩稿叧 API
+
+### 鐩稿叧鏂囨。
+- [杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md](./杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md)
+- [鐢ㄦ埛缁戝畾杞﹁締鍔熻兘璇存槑.md](./鐢ㄦ埛缁戝畾杞﹁締鍔熻兘璇存槑.md)
+
+## 鎬荤粨
+
+鏈淇閫氳繃浠ヤ笅姝ラ瑙e喅浜� userId 涓� undefined 鐨勯棶棰橈細
+
+1. 鉁� 鍦� `computed` 涓坊鍔� `currentUser` 鏄犲皠
+2. 鉁� 鍦� `loadUserProfile()` 涓坊鍔犵敤鎴风櫥褰曟鏌�
+3. 鉁� 鍦� `loadRunningTasks()` 涓彁鍙栧苟楠岃瘉 userId
+4. 鉁� 缁熶竴浣跨敤 `this.currentUser.userId` 鑾峰彇鐢ㄦ埛ID
+
+**鏍稿績鏀硅繘**锛�
+- 浠g爜鏇村仴澹紝澧炲姞浜嗛敊璇鏌�
+- 閬靛惊浜嗛」鐩腑鍏朵粬椤甸潰鐨勬渶浣冲疄璺�
+- 閬垮厤浜嗘棤鏁堢殑 API 璋冪敤
+- 鎻愪緵浜嗘洿濂界殑閿欒鎻愮ず
+
+## 鐗堟湰鍘嗗彶
+
+| 鐗堟湰 | 鏃ユ湡 | 淇敼鍐呭 | 淇敼浜� |
+|------|------|---------|--------|
+| 1.0 | 2025-10-15 | 淇 userId 涓� undefined 鐨勯棶棰� | - |
diff --git "a/prd/\351\246\226\351\241\265\350\275\246\350\276\206\347\273\221\345\256\232\350\207\252\345\212\250\345\210\267\346\226\260\345\212\237\350\203\275.md" "b/prd/\351\246\226\351\241\265\350\275\246\350\276\206\347\273\221\345\256\232\350\207\252\345\212\250\345\210\267\346\226\260\345\212\237\350\203\275.md"
new file mode 100644
index 0000000..b28f553
--- /dev/null
+++ "b/prd/\351\246\226\351\241\265\350\275\246\350\276\206\347\273\221\345\256\232\350\207\252\345\212\250\345\210\267\346\226\260\345\212\237\350\203\275.md"
@@ -0,0 +1,454 @@
+# 棣栭〉杞﹁締缁戝畾鑷姩鍒锋柊鍔熻兘璇存槑
+
+## 闇�姹傝儗鏅�
+
+鐢ㄦ埛鍦ㄧ粦瀹氳溅杈嗛〉闈㈡垚鍔熺粦瀹氳溅杈嗗悗锛岃繑鍥為椤垫椂闇�瑕佽嚜鍔ㄥ埛鏂板苟鏄剧ず鏈�鏂扮殑缁戝畾杞﹁締淇℃伅锛岀‘淇濈敤鎴疯兘澶熺珛鍗崇湅鍒扮粦瀹氱殑杞﹁締淇℃伅銆�
+
+## 闂鍒嗘瀽
+
+### 鍘熸湁瀹炵幇
+
+**鏂囦欢锛�** [`app/pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue)
+
+#### 闂鐐�
+
+1. **鍙湪 onLoad 鏃跺姞杞戒竴娆�**
+ ```javascript
+ onLoad() {
+ this.loadUserProfile() // 鍙湪椤甸潰棣栨鍔犺浇鏃惰皟鐢�
+ this.loadRunningTasks()
+ }
+ ```
+
+2. **onShow 鏈埛鏂拌溅杈嗕俊鎭�**
+ ```javascript
+ onShow() {
+ this.loadRunningTasks() // 鉂� 鍙埛鏂颁换鍔★紝鏈埛鏂拌溅杈�
+ }
+ ```
+
+3. **浣跨敤 getUserProfile 鎺ュ彛**
+ - 璇ユ帴鍙d富瑕佺敤浜庤幏鍙栫敤鎴峰熀鏈俊鎭�
+ - 涓嶆槸涓撻棬鑾峰彇缁戝畾杞﹁締鐨勬帴鍙�
+ - 鍙兘杩斿洖鐨勬暟鎹笉澶熷強鏃�
+
+### 鐢ㄦ埛鎿嶄綔娴佺▼
+
+```mermaid
+graph LR
+ A[棣栭〉] --> B[鐐瑰嚮缁戝畾杞﹁締]
+ B --> C[缁戝畾杞﹁締椤甸潰]
+ C --> D[閫夋嫨杞﹁締]
+ D --> E[缁戝畾鎴愬姛]
+ E --> F[杩斿洖棣栭〉]
+ F --> G{杞﹁締淇℃伅鏇存柊?}
+ G -->|鍘熷疄鐜皘 H[鉂� 涓嶆洿鏂癩
+ G -->|鏂板疄鐜皘 I[鉁� 鑷姩鏇存柊]
+```
+
+## 瑙e喅鏂规
+
+### 1. 瀵煎叆涓撶敤 API
+
+**淇敼鍓嶏細**
+```javascript
+import { mapState } from 'vuex'
+import { listTask, changeTaskStatus } from '@/api/task'
+import { getUserProfile } from '@/api/system/user'
+```
+
+**淇敼鍚庯細**
+```javascript
+import { mapState } from 'vuex'
+import { listTask, changeTaskStatus } from '@/api/task'
+import { getUserProfile } from '@/api/system/user'
+import { getUserBoundVehicle } from '@/api/vehicle' // 鉁� 鏂板涓撶敤API
+```
+
+### 2. 鏂板涓撶敤鏂规硶鑾峰彇缁戝畾杞﹁締
+
+**鏂板鏂规硶锛�** `loadUserVehicle()`
+
+```javascript
+// 鍔犺浇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+loadUserVehicle() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鑾峰彇缁戝畾杞﹁締淇℃伅')
+ this.boundVehicle = ''
+ this.boundVehicleId = null
+ return
+ }
+
+ getUserBoundVehicle(userId).then(response => {
+ if (response.code === 200 && response.data) {
+ const vehicle = response.data
+ this.boundVehicle = vehicle.vehicleNumber || '鏈煡杞︾墝'
+ this.boundVehicleId = vehicle.vehicleId
+ console.log('鐢ㄦ埛缁戝畾杞﹁締:', this.boundVehicle)
+ } else {
+ this.boundVehicle = ''
+ this.boundVehicleId = null
+ }
+ }).catch(error => {
+ console.error('鑾峰彇缁戝畾杞﹁締淇℃伅澶辫触:', error)
+ this.boundVehicle = ''
+ this.boundVehicleId = null
+ })
+}
+```
+
+**浼樺娍锛�**
+- 鉁� 浣跨敤涓撶敤鐨� [`getUserBoundVehicle`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js#L68-L73) API
+- 鉁� 鏁版嵁鏇村噯纭�佹洿鍙婃椂
+- 鉁� 鐙珛鐨勯敊璇鐞�
+- 鉁� 娓呯┖鏃ф暟鎹紝閬垮厤鏄剧ず杩囨湡淇℃伅
+
+### 3. 鏇存柊鐢熷懡鍛ㄦ湡閽╁瓙
+
+**淇敼鍓嶏細**
+```javascript
+onLoad() {
+ this.loadUserProfile() // 浣跨敤閫氱敤鎺ュ彛
+ this.loadRunningTasks()
+},
+onShow() {
+ this.loadRunningTasks() // 鉂� 鍙埛鏂颁换鍔�
+}
+```
+
+**淇敼鍚庯細**
+```javascript
+onLoad() {
+ this.loadUserVehicle() // 鉁� 浣跨敤涓撶敤鏂规硶
+ this.loadRunningTasks()
+},
+onShow() {
+ this.loadUserVehicle() // 鉁� 姣忔鏄剧ず閮藉埛鏂拌溅杈�
+ this.loadRunningTasks() // 鉁� 鍚屾椂鍒锋柊浠诲姟
+}
+```
+
+### 4. 淇濈暀鍘熸湁鏂规硶锛堝吋瀹规�э級
+
+**淇濈暀 `loadUserProfile()` 鏂规硶锛�**
+```javascript
+// 鍔犺浇鐢ㄦ埛淇℃伅锛堜繚鐣欎互鍏煎涔嬪墠鐨勪唬鐮侊級
+loadUserProfile() {
+ const userId = this.currentUser.userId
+ if (!userId) {
+ console.error('鐢ㄦ埛鏈櫥褰曪紝鏃犳硶鑾峰彇鐢ㄦ埛淇℃伅')
+ return
+ }
+
+ getUserProfile().then(response => {
+ const userInfo = response.data || response
+ // 鑾峰彇鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
+ if (userInfo.boundVehicle) {
+ this.boundVehicle = userInfo.boundVehicle.vehicleNumber
+ this.boundVehicleId = userInfo.boundVehicle.vehicleId
+ }
+ }).catch(error => {
+ console.error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触:', error)
+ })
+}
+```
+
+**浣滅敤锛�**
+- 鉁� 淇濇寔鍚戝悗鍏煎
+- 鉁� 濡傞渶鑾峰彇鏇村鐢ㄦ埛淇℃伅鏃跺彲浠ヨ皟鐢�
+
+## 瀹炵幇鏁堟灉
+
+### 鐢ㄦ埛鎿嶄綔娴佺▼
+
+1. **棣栭〉鏄剧ず**
+ ```
+ 鐢ㄦ埛淇℃伅鍖哄煙锛�
+ 鈹斺攢 鐢ㄦ埛鍚�: 寮犱笁
+ 鈹斺攢 鍏宠仈杞︾墝鍙�: 鏈粦瀹氳溅鐗屽彿
+ 鈹斺攢 [缁戝畾杞﹁締] 鎸夐挳
+ ```
+
+2. **鐐瑰嚮缁戝畾杞﹁締**
+ - 璺宠浆鍒� [`bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) 椤甸潰
+
+3. **閫夋嫨骞剁粦瀹氳溅杈�**
+ - 閫夋嫨杞︾墝鍙凤細绮12345
+ - 鐐瑰嚮"纭缁戝畾"
+ - 鏄剧ず锛氳溅杈嗙粦瀹氭垚鍔�
+ - 鑷姩杩斿洖棣栭〉锛�1.5绉掑悗锛�
+
+4. **棣栭〉鑷姩鍒锋柊** 鉁�
+ ```
+ 鐢ㄦ埛淇℃伅鍖哄煙锛�
+ 鈹斺攢 鐢ㄦ埛鍚�: 寮犱笁
+ 鈹斺攢 鍏宠仈杞︾墝鍙�: 绮12345 鈫� 鉁� 鑷姩鏇存柊
+ 鈹斺攢 [鏇存崲杞﹁締] 鎸夐挳 鈫� 鉁� 鎸夐挳鏂囧瓧鍙樺寲
+ ```
+
+### 鏁版嵁娴佺▼鍥�
+
+```mermaid
+sequenceDiagram
+ participant User as 鐢ㄦ埛
+ participant Index as 棣栭〉
+ participant Bind as 缁戝畾椤甸潰
+ participant API as 鍚庣API
+
+ User->>Index: 鎵撳紑棣栭〉
+ Index->>API: getUserBoundVehicle(userId)
+ API-->>Index: 杩斿洖锛氭湭缁戝畾
+ Index-->>User: 鏄剧ず锛氭湭缁戝畾杞︾墝鍙�
+
+ User->>Index: 鐐瑰嚮缁戝畾杞﹁締
+ Index->>Bind: 璺宠浆鍒扮粦瀹氶〉闈�
+
+ User->>Bind: 閫夋嫨杞﹁締锛氱菠A12345
+ User->>Bind: 鐐瑰嚮纭缁戝畾
+ Bind->>API: bindVehicleToUser(userId, vehicleId)
+ API-->>Bind: 杩斿洖锛氱粦瀹氭垚鍔�
+ Bind-->>User: 鎻愮ず锛氳溅杈嗙粦瀹氭垚鍔�
+
+ Bind->>Index: 杩斿洖棣栭〉锛坣avigateBack锛�
+ Note over Index: 瑙﹀彂 onShow()
+ Index->>API: getUserBoundVehicle(userId)
+ API-->>Index: 杩斿洖锛氱菠A12345
+ Index-->>User: 鏄剧ず锛氬叧鑱旇溅鐗屽彿: 绮12345
+```
+
+## 鏍稿績鏀硅繘鐐�
+
+### 1. 瀹炴椂鎬ф彁鍗�
+
+**淇敼鍓嶏細**
+- 鉂� 缁戝畾鎴愬姛鍚庤繑鍥為椤碉紝杞﹁締淇℃伅涓嶆洿鏂�
+- 鉂� 闇�瑕佹墜鍔ㄥ埛鏂伴〉闈㈡墠鑳界湅鍒版渶鏂扮粦瀹�
+
+**淇敼鍚庯細**
+- 鉁� 缁戝畾鎴愬姛鍚庤繑鍥為椤碉紝鑷姩鍒锋柊杞﹁締淇℃伅
+- 鉁� 鐢ㄦ埛浣撻獙娴佺晠锛屾棤闇�浠讳綍棰濆鎿嶄綔
+
+### 2. 鏁版嵁鍑嗙‘鎬�
+
+**淇敼鍓嶏細**
+- 鈿狅笍 浣跨敤 `getUserProfile` 鎺ュ彛
+- 鈿狅笍 鍙兘瀛樺湪缂撳瓨闂
+
+**淇敼鍚庯細**
+- 鉁� 浣跨敤涓撶敤鐨� [`getUserBoundVehicle`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js#L68-L73) 鎺ュ彛
+- 鉁� 鏁版嵁鏇村噯纭�佹洿鍙婃椂
+
+### 3. 閿欒澶勭悊
+
+**鏂板瀹屽杽鐨勯敊璇鐞嗭細**
+```javascript
+.catch(error => {
+ console.error('鑾峰彇缁戝畾杞﹁締淇℃伅澶辫触:', error)
+ this.boundVehicle = '' // 娓呯┖鏃ф暟鎹�
+ this.boundVehicleId = null // 娓呯┖鏃D
+})
+```
+
+- 鉁� 澶辫触鏃舵竻绌烘棫鏁版嵁
+- 鉁� 閬垮厤鏄剧ず杩囨湡淇℃伅
+- 鉁� 璁板綍閿欒鏃ュ織渚夸簬璋冭瘯
+
+### 4. 鐘舵�佸悓姝�
+
+**澶氬満鏅嚜鍔ㄥ埛鏂帮細**
+
+1. **棣栨杩涘叆棣栭〉** 锛坥nLoad锛�
+ - 鉁� 鍔犺浇缁戝畾杞﹁締淇℃伅
+
+2. **浠庡叾浠栭〉闈㈣繑鍥�** 锛坥nShow锛�
+ - 鉁� 鑷姩鍒锋柊缁戝畾杞﹁締淇℃伅
+ - 鉁� 閫傜敤浜庣粦瀹氥�佽В缁戠瓑鎿嶄綔鍚庤繑鍥�
+
+3. **涓嬫媺鍒锋柊** 锛坥nPullDownRefresh锛�
+ - 鉁� 鍒锋柊浠诲姟鍒楄〃
+ - 馃挕 鍙墿灞曪細鍚屾椂鍒锋柊杞﹁締淇℃伅
+
+## 浣跨敤鐨� API 鎺ュ彛
+
+### getUserBoundVehicle
+
+**鏂囦欢锛�** [`app/api/vehicle.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js)
+
+```javascript
+// 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+export function getUserBoundVehicle(userId) {
+ return request({
+ url: '/system/vehicle/user/bound/' + userId,
+ method: 'get'
+ })
+}
+```
+
+**鍚庣鎺ュ彛锛�** `/system/vehicle/user/bound/{userId}`
+
+**鍝嶅簲绀轰緥锛�**
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "vehicleId": 1,
+ "vehicleNumber": "绮12345",
+ "vehicleType": "鏁戞姢杞�",
+ "vehicleBrand": "绂忕壒",
+ "vehicleModel": "鍏ㄩ『"
+ }
+}
+```
+
+**鏃犵粦瀹氭椂锛�**
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": null
+}
+```
+
+## 娴嬭瘯鍦烘櫙
+
+### 鍦烘櫙1锛氶娆$粦瀹氳溅杈�
+
+**姝ラ锛�**
+1. 鏂扮敤鎴烽娆$櫥褰�
+2. 棣栭〉鏄剧ず"鏈粦瀹氳溅鐗屽彿"
+3. 鐐瑰嚮"缁戝畾杞﹁締"鎸夐挳
+4. 閫夋嫨杞︾墝鍙峰苟缁戝畾
+5. 缁戝畾鎴愬姛锛岃繑鍥為椤�
+
+**棰勬湡缁撴灉锛�**
+- 鉁� 棣栭〉鏄剧ず缁戝畾鐨勮溅鐗屽彿
+- 鉁� 鎸夐挳鏂囧瓧鍙樹负"鏇存崲杞﹁締"
+
+### 鍦烘櫙2锛氭洿鎹㈢粦瀹氳溅杈�
+
+**姝ラ锛�**
+1. 鐢ㄦ埛宸茬粦瀹氳溅杈嗭細绮12345
+2. 棣栭〉鏄剧ず"鍏宠仈杞︾墝鍙凤細绮12345"
+3. 鐐瑰嚮"鏇存崲杞﹁締"鎸夐挳
+4. 閫夋嫨鏂拌溅鐗屽彿锛氱菠B67890
+5. 纭寮哄埗缁戝畾
+6. 缁戝畾鎴愬姛锛岃繑鍥為椤�
+
+**棰勬湡缁撴灉锛�**
+- 鉁� 棣栭〉鏄剧ず鏂拌溅鐗屽彿锛氱菠B67890
+- 鉁� 鏃ц溅鐗屽彿淇℃伅琚竻闄�
+
+### 鍦烘櫙3锛氳В缁戣溅杈嗗悗杩斿洖
+
+**姝ラ锛�**
+1. 鐢ㄦ埛宸茬粦瀹氳溅杈嗭細绮12345
+2. 杩涘叆涓汉涓績
+3. 鐐瑰嚮"鍙栨秷缁戝畾杞﹁締"
+4. 瑙g粦鎴愬姛
+5. 杩斿洖棣栭〉
+
+**棰勬湡缁撴灉锛�**
+- 鉁� 棣栭〉鏄剧ず"鏈粦瀹氳溅鐗屽彿"
+- 鉁� 鎸夐挳鏂囧瓧鍙樹负"缁戝畾杞﹁締"
+
+### 鍦烘櫙4锛氱綉缁滃紓甯稿鐞�
+
+**姝ラ锛�**
+1. 鏂紑缃戠粶杩炴帴
+2. 鎵撳紑棣栭〉
+
+**棰勬湡缁撴灉锛�**
+- 鉁� 鎺у埗鍙拌緭鍑洪敊璇棩蹇�
+- 鉁� 杞﹁締淇℃伅涓虹┖锛屼笉鏄剧ず杩囨湡鏁版嵁
+- 鉁� 椤甸潰涓嶅穿婧�
+
+## 鐩稿叧鏂囦欢
+
+### 淇敼鐨勬枃浠�
+1. [`app/pages/index.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\index.vue) - 棣栭〉
+
+### 渚濊禆鐨勬枃浠�
+1. [`app/api/vehicle.js`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js) - 杞﹁締 API
+2. [`app/pages/bind-vehicle.vue`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) - 缁戝畾杞﹁締椤甸潰
+
+### 鐩稿叧鏂囨。
+- [杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md](./杞﹁締缁戝畾瑙g粦鍔熻兘璇存槑.md)
+- [棣栭〉鐢ㄦ埛ID鑾峰彇闂淇.md](./棣栭〉鐢ㄦ埛ID鑾峰彇闂淇.md)
+- [Vuex鐢ㄦ埛鐘舵�佸畬鏁存�т紭鍖�.md](./Vuex鐢ㄦ埛鐘舵�佸畬鏁存�т紭鍖�.md)
+
+## 鍚庣画浼樺寲寤鸿
+
+### 1. 娣诲姞鍔犺浇鐘舵��
+
+鏄剧ず鍔犺浇涓殑鎻愮ず锛屾彁鍗囩敤鎴蜂綋楠岋細
+
+```javascript
+loadUserVehicle() {
+ this.loadingVehicle = true // 鏄剧ず鍔犺浇鐘舵��
+
+ getUserBoundVehicle(userId).then(response => {
+ // 澶勭悊鏁版嵁...
+ }).finally(() => {
+ this.loadingVehicle = false // 闅愯棌鍔犺浇鐘舵��
+ })
+}
+```
+
+### 2. 娣诲姞缂撳瓨鏈哄埗
+
+閬垮厤棰戠箒璇锋眰鐩稿悓鏁版嵁锛�
+
+```javascript
+// 浣跨敤 Vuex 缂撳瓨缁戝畾杞﹁締淇℃伅
+// 鍙湁鍦ㄧ粦瀹�/瑙g粦鎿嶄綔鍚庢墠娓呴櫎缂撳瓨
+```
+
+### 3. 鎵╁睍涓嬫媺鍒锋柊
+
+涓嬫媺鍒锋柊鏃跺悓鏃跺埛鏂拌溅杈嗕俊鎭細
+
+```javascript
+onPullDownRefresh() {
+ this.loadUserVehicle() // 鏂板锛氬埛鏂拌溅杈�
+ this.loadRunningTasks()
+ setTimeout(() => {
+ uni.stopPullDownRefresh()
+ }, 1000)
+}
+```
+
+### 4. 娣诲姞楠ㄦ灦灞�
+
+鍦ㄦ暟鎹姞杞芥椂鏄剧ず楠ㄦ灦灞忥紝鎻愬崌瑙嗚浣撻獙锛�
+
+```vue
+<view v-if="loadingVehicle" class="skeleton">
+ <!-- 楠ㄦ灦灞忓唴瀹� -->
+</view>
+<view v-else class="vehicle-info">
+ {{ boundVehicle || '鏈粦瀹氳溅鐗屽彿' }}
+</view>
+```
+
+## 鎬荤粨
+
+閫氳繃鏈浼樺寲锛屽疄鐜颁簡浠ヤ笅鐩爣锛�
+
+1. 鉁� **瀹炴椂鍚屾**锛氱粦瀹氳溅杈嗘垚鍔熷悗锛岄椤佃嚜鍔ㄦ樉绀烘渶鏂扮粦瀹氫俊鎭�
+2. 鉁� **涓撶敤鎺ュ彛**锛氫娇鐢� [`getUserBoundVehicle`](file://d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\app\api\vehicle.js#L68-L73) 涓撶敤鎺ュ彛锛屾暟鎹洿鍑嗙‘
+3. 鉁� **鐢熷懡鍛ㄦ湡浼樺寲**锛氬湪 `onShow` 涓埛鏂拌溅杈嗕俊鎭紝閫傞厤澶氱鍦烘櫙
+4. 鉁� **閿欒澶勭悊**锛氬畬鍠勭殑閿欒澶勭悊鏈哄埗锛岄伩鍏嶆樉绀鸿繃鏈熸暟鎹�
+5. 鉁� **鍚戝悗鍏煎**锛氫繚鐣欏師鏈夋柟娉曪紝涓嶅奖鍝嶅叾浠栧姛鑳�
+
+**鏍稿績浠峰�硷細**
+- 鎻愬崌鐢ㄦ埛浣撻獙锛屾搷浣滄洿娴佺晠
+- 鏁版嵁瀹炴椂鎬ф洿濂斤紝鏄剧ず鏇村噯纭�
+- 浠g爜缁撴瀯鏇存竻鏅帮紝鏄撲簬缁存姢
+
+## 鐗堟湰鍘嗗彶
+
+| 鐗堟湰 | 鏃ユ湡 | 淇敼鍐呭 | 淇敼浜� |
+|------|------|---------|--------|
+| 1.0 | 2025-10-15 | 瀹炵幇棣栭〉杞﹁締缁戝畾鑷姩鍒锋柊鍔熻兘 | - |
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerDepartmentController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerDepartmentController.java
new file mode 100644
index 0000000..59050ab
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerDepartmentController.java
@@ -0,0 +1,59 @@
+package com.ruoyi.web.controller.sqlserver;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.mapper.DepartmentSyncMapper;
+
+import java.util.List;
+
+/**
+ * SQL Server 閮ㄩ棬鏁版嵁鏌ヨ Controller
+ *
+ * 涓撻棬鐢ㄤ簬浠� SQL Server 鏁版嵁搴撴煡璇㈤儴闂ㄦ暟鎹�
+ * 涓嶆秹鍙婁换浣� MySQL 鏁版嵁搴撴搷浣�
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@RestController
+@RequestMapping("/sqlserver/department")
+@DataSource(DataSourceType.SQLSERVER)
+public class SqlServerDepartmentController extends BaseController
+{
+ @Autowired
+ private DepartmentSyncMapper departmentSyncMapper;
+
+ /**
+ * 鏌ヨ SQL Server 涓悎浣滃崟浣嶄笅鐨勬墍鏈夊垎鍏徃
+ *
+ * 鏁版嵁婧愶細SQL Server (uv_department 瑙嗗浘)
+ *
+ * @return 鍒嗗叕鍙稿垪琛�
+ */
+ @PreAuthorize("@ss.hasPermi('sqlserver:department:list')")
+ @GetMapping("/branch/list")
+ public AjaxResult getBranchDepartments()
+ {
+ try
+ {
+ // 浠� SQL Server 鏌ヨ鏁版嵁
+ // Mapper 涓婄殑 @DataSource(DataSourceType.SQLSERVER) 娉ㄨВ纭繚浣跨敤 SQL Server 鏁版嵁婧�
+ List<DepartmentSyncDTO> list = departmentSyncMapper.selectBranchDepartments();
+
+ return AjaxResult.success("鏌ヨ鎴愬姛", list);
+ }
+ catch (Exception e)
+ {
+ logger.error("鏌ヨ SQL Server 閮ㄩ棬鏁版嵁澶辫触", e);
+ return AjaxResult.error("鏌ヨ SQL Server 閮ㄩ棬鏁版嵁澶辫触锛�" + e.getMessage());
+ }
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerUserController.java
new file mode 100644
index 0000000..c0f67ce
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sqlserver/SqlServerUserController.java
@@ -0,0 +1,56 @@
+package com.ruoyi.web.controller.sqlserver;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.system.domain.UserSyncDTO;
+import com.ruoyi.system.mapper.UserSyncMapper;
+
+import java.util.List;
+
+/**
+ * SQL Server 鐢ㄦ埛鏁版嵁鏌ヨ Controller
+ *
+ * 涓撻棬鐢ㄤ簬浠� SQL Server 鏁版嵁搴撴煡璇㈢敤鎴锋暟鎹�
+ * 涓嶆秹鍙婁换浣� MySQL 鏁版嵁搴撴搷浣�
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@RestController
+@RequestMapping("/sqlserver/user")
+public class SqlServerUserController extends BaseController
+{
+ @Autowired
+ private UserSyncMapper userSyncMapper;
+
+ /**
+ * 鏌ヨ SQL Server 涓殑 OA 鐢ㄦ埛鍒楄〃
+ *
+ * 鏁版嵁婧愶細SQL Server (OA_User 琛�)
+ *
+ * @return OA 鐢ㄦ埛鍒楄〃
+ */
+ @PreAuthorize("@ss.hasPermi('sqlserver:user:list')")
+ @GetMapping("/list")
+ public AjaxResult getOaUsers()
+ {
+ try
+ {
+ // 浠� SQL Server 鏌ヨ鏁版嵁
+ // Mapper 涓婄殑 @DataSource(DataSourceType.SQLSERVER) 娉ㄨВ纭繚浣跨敤 SQL Server 鏁版嵁婧�
+ List<UserSyncDTO> list = userSyncMapper.selectOaUsers();
+
+ return AjaxResult.success("鏌ヨ鎴愬姛", list);
+ }
+ catch (Exception e)
+ {
+ logger.error("鏌ヨ SQL Server 鐢ㄦ埛鏁版嵁澶辫触", e);
+ return AjaxResult.error("鏌ヨ SQL Server 鐢ㄦ埛鏁版嵁澶辫触锛�" + e.getMessage());
+ }
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java
new file mode 100644
index 0000000..9a34b5f
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java
@@ -0,0 +1,87 @@
+package com.ruoyi.web.controller.system;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.domain.UserSyncDTO;
+import com.ruoyi.system.service.IDepartmentSyncService;
+import com.ruoyi.system.service.IUserSyncService;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬鍜岀敤鎴峰悓姝ontroller
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@RestController
+@RequestMapping("/system/dept/sync")
+public class DepartmentSyncController extends BaseController
+{
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+
+
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * 閫傜敤鍦烘櫙锛�
+ * 1. 宸蹭粠鍏朵粬鏉ユ簮鑾峰彇浜嗛儴闂ㄦ暟鎹�
+ * 2. 闇�瑕佸鏁版嵁杩涜棰勫鐞嗗悗鍐嶅悓姝�
+ * 3. 鎵归噺鍚屾澶氫釜鏁版嵁婧�
+ *
+ * @param branchDepts 鍒嗗叕鍙告暟鎹垪琛�
+ * @return 鍚屾缁撴灉
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:sync')")
+ @PostMapping("/branch/data")
+ public AjaxResult syncBranchDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> branchDepts)
+ {
+ return departmentSyncService.syncBranchDepartments(branchDepts);
+ }
+
+ /**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * 鍚屾閫昏緫锛�
+ * 1. 纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ * 2. 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂�
+ *
+ * @param transportDepts 杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:sync')")
+ @PostMapping("/transport/data")
+ public AjaxResult syncTransportDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> transportDepts)
+ {
+ return departmentSyncService.syncTransportDepartments(transportDepts);
+ }
+
+
+
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * 閫傜敤鍦烘櫙锛�
+ * 1. 宸蹭粠鍏朵粬鏉ユ簮鑾峰彇浜嗙敤鎴锋暟鎹�
+ * 2. 闇�瑕佸鏁版嵁杩涜棰勫鐞嗗悗鍐嶅悓姝�
+ * 3. 鎵归噺鍚屾澶氫釜鏁版嵁婧�
+ *
+ * @param oaUsers OA鐢ㄦ埛鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:sync')")
+ @PostMapping("/user/data")
+ public AjaxResult syncOaUsersWithData(@RequestBody List<UserSyncDTO> oaUsers)
+ {
+ return userSyncService.syncOaUsers(oaUsers);
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GeocodeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GeocodeController.java
new file mode 100644
index 0000000..6e3d44d
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GeocodeController.java
@@ -0,0 +1,43 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.dto.GeocodeResult;
+import com.ruoyi.system.service.IGeocodeService;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 鍦扮悊缂栫爜鎺у埗鍣�
+ */
+@RestController
+@RequestMapping("/system/geocode")
+public class GeocodeController extends BaseController {
+
+ @Autowired
+ private IGeocodeService geocodeService;
+
+ /**
+ * 鏍规嵁鍦板潃鑾峰彇GPS鍧愭爣
+ *
+ * @param address 鍦板潃瀛楃涓�
+ * @param city 鍩庡競鍚嶇О锛堝彲閫夛級锛岀敤浜庢彁楂樿В鏋愬噯纭害
+ * @return 鍦扮悊缂栫爜缁撴灉
+ */
+ @GetMapping("/address")
+ public AjaxResult getCoordinatesByAddress(
+ @RequestParam("address") String address,
+ @RequestParam(value = "city", required = false) String city) {
+
+ GeocodeResult result = geocodeService.getCoordinatesByAddress(address, city);
+
+ if (result.getSuccess()) {
+ return AjaxResult.success("鍦扮悊缂栫爜鎴愬姛", result);
+ } else {
+ return AjaxResult.error(result.getErrorMessage());
+ }
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/HospDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/HospDataController.java
new file mode 100644
index 0000000..e8da24b
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/HospDataController.java
@@ -0,0 +1,46 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.HospData;
+import com.ruoyi.system.mapper.HospDataMapper;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 鍖婚櫌鏁版嵁Controller
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+@RestController
+@RequestMapping("/system/hospital")
+public class HospDataController extends BaseController {
+
+ @Autowired
+ private HospDataMapper hospDataMapper;
+
+ /**
+ * 鎼滅储鍖婚櫌
+ * 鏀寔鏍规嵁鍖婚櫌鍚嶇О鎴栧湴鍧�杩涜妯$硦鎼滅储
+ */
+ @GetMapping("/search")
+ public AjaxResult searchHospitals(@RequestParam(value = "keyword", required = false) String keyword) {
+ List<HospData> list = hospDataMapper.searchHospitals(keyword);
+ return success(list);
+ }
+
+ /**
+ * 鏍规嵁ID鑾峰彇鍖婚櫌璇︽儏
+ */
+ @GetMapping("/detail")
+ public AjaxResult getHospitalDetail(@RequestParam("hospId") Integer hospId) {
+ HospData hospital = hospDataMapper.selectHospDataById(hospId);
+ return success(hospital);
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/Icd10Controller.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/Icd10Controller.java
new file mode 100644
index 0000000..e7470de
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/Icd10Controller.java
@@ -0,0 +1,46 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.Icd10;
+import com.ruoyi.system.mapper.Icd10Mapper;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * ICD-10鐤剧梾鍒嗙被Controller
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+@RestController
+@RequestMapping("/system/icd10")
+public class Icd10Controller extends BaseController {
+
+ @Autowired
+ private Icd10Mapper icd10Mapper;
+
+ /**
+ * 鎼滅储ICD-10鐤剧梾
+ * 鏀寔鏍规嵁鐤剧梾鍚嶇О銆佺紪鐮佹垨鍔╄鐮佽繘琛屾ā绯婃悳绱�
+ */
+ @GetMapping("/search")
+ public AjaxResult searchIcd10(@RequestParam(value = "keyword", required = false) String keyword) {
+ List<Icd10> list = icd10Mapper.searchIcd10(keyword);
+ return success(list);
+ }
+
+ /**
+ * 鏍规嵁ID鑾峰彇ICD-10璇︽儏
+ */
+ @GetMapping("/detail")
+ public AjaxResult getIcd10Detail(@RequestParam("id") Integer id) {
+ Icd10 icd10 = icd10Mapper.selectIcd10ById(id);
+ return success(icd10);
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java
index 5c3e134..80726d4 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java
@@ -3,9 +3,13 @@
import java.util.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
+import com.ruoyi.common.config.TencentMapConfig;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -24,6 +28,7 @@
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.http.HttpUtils;
/**
* 杞﹁締GPS鍧愭爣Controller
@@ -51,6 +56,9 @@
@Autowired
private ICmsGpsCollectService cmsGpsCollectService;
+
+ @Autowired
+ private TencentMapConfig tencentMapConfig;
/**
* 鏌ヨ杞﹁締GPS鍧愭爣鍒楄〃
@@ -369,4 +377,97 @@
throw new Error("鏌ヨ杞﹁締杞ㄨ抗澶辫触锛�" + e.getMessage());
}
}
-}
\ No newline at end of file
+
+ /**
+ * 鑵捐鍦板浘鍦板潃鎼滅储鎺ュ彛浠g悊
+ */
+ @Anonymous()
+ @GetMapping("/address/search")
+ public AjaxResult searchAddress(String keyword, String region) {
+ try {
+ // 鏋勫缓鑵捐鍦板浘鎼滅储API URL
+ String url = "https://apis.map.qq.com/ws/place/v1/search";
+ String params = "keyword=" + URLEncoder.encode(keyword, StandardCharsets.UTF_8.toString()) +
+ "&boundary=region(" + (region != null ? region : "骞垮窞") + ")" +
+ "&key=" + tencentMapConfig.getKey();
+
+ // 鍙戦�丠TTP璇锋眰
+ String response = HttpUtils.sendGet(url, params);
+
+ // 杩斿洖缁撴灉
+ return AjaxResult.success("鏌ヨ鎴愬姛", response);
+ } catch (Exception e) {
+ logger.error("鍦板潃鎼滅储澶辫触", e);
+ return AjaxResult.error("鍦板潃鎼滅储澶辫触锛�" + e.getMessage());
+ }
+ }
+
+ /**
+ * 鑵捐鍦板浘閫嗗湴鍧�瑙f瀽鎺ュ彛浠g悊
+ */
+ @Anonymous()
+ @GetMapping("/address/geocoder")
+ public AjaxResult reverseGeocoder(Double lat, Double lng) {
+ try {
+ // 妫�鏌ュ弬鏁�
+ logger.info("閫嗗湴鍧�瑙f瀽璇锋眰鍙傛暟: lat={}, lng={}", lat, lng);
+
+ if (lat == null || lng == null) {
+ logger.warn("鍙傛暟涓嶅畬鏁达紝缂哄皯缁忕含搴﹀潗鏍�: lat={}, lng={}", lat, lng);
+ return AjaxResult.error("鍙傛暟涓嶅畬鏁达紝缂哄皯缁忕含搴﹀潗鏍�");
+ }
+
+ // 妫�鏌ュ弬鏁版湁鏁堟��
+ if (Double.isNaN(lat) || Double.isNaN(lng) ||
+ Double.isInfinite(lat) || Double.isInfinite(lng)) {
+ logger.warn("鍙傛暟鏃犳晥锛岀粡绾害鍧愭爣鍖呭惈闈炴硶鍊�: lat={}, lng={}", lat, lng);
+ return AjaxResult.error("鍙傛暟鏃犳晥锛岀粡绾害鍧愭爣鏍煎紡閿欒");
+ }
+
+ // 鏋勫缓鑵捐鍦板浘閫嗗湴鍧�瑙f瀽API URL
+ String url = "https://apis.map.qq.com/ws/geocoder/v1/";
+ String params = "location=" + lat + "," + lng +
+ "&key=" + tencentMapConfig.getKey() +
+ "&get_poi=1";
+
+ // 鍙戦�丠TTP璇锋眰
+ String response = HttpUtils.sendGet(url, params);
+
+ // 杩斿洖缁撴灉
+ return AjaxResult.success("鏌ヨ鎴愬姛", response);
+ } catch (Exception e) {
+ logger.error("閫嗗湴鍧�瑙f瀽澶辫触: lat={}, lng={}", lat, lng, e);
+ return AjaxResult.error("閫嗗湴鍧�瑙f瀽澶辫触锛�" + e.getMessage());
+ }
+ }
+
+ /**
+ * 鑵捐鍦板浘璺嚎瑙勫垝鎺ュ彛浠g悊锛堣绠椾袱鐐归棿璺濈锛�
+ */
+ @Anonymous()
+ @GetMapping("/route/distance")
+ public AjaxResult calculateDistance(Double fromLat, Double fromLng, Double toLat, Double toLng) {
+ try {
+ // 妫�鏌ュ弬鏁�
+ if (fromLat == null || fromLng == null || toLat == null || toLng == null) {
+ return AjaxResult.error("鍙傛暟涓嶅畬鏁达紝缂哄皯璧风偣鎴栫粓鐐瑰潗鏍�");
+ }
+
+ // 鏋勫缓鑵捐鍦板浘璺嚎瑙勫垝API URL
+ String url = "https://apis.map.qq.com/ws/distance/v1/";
+ String params = "mode=driving" +
+ "&from=" + fromLat + "," + fromLng +
+ "&to=" + toLat + "," + toLng +
+ "&key=" + tencentMapConfig.getKey();
+
+ // 鍙戦�丠TTP璇锋眰
+ String response = HttpUtils.sendGet(url, params);
+
+ // 杩斿洖缁撴灉
+ return AjaxResult.success("璁$畻鎴愬姛", response);
+ } catch (Exception e) {
+ logger.error("璺濈璁$畻澶辫触", e);
+ return AjaxResult.error("璺濈璁$畻澶辫触锛�" + e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleInfoController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleInfoController.java
index b33aea0..d0c6d76 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleInfoController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleInfoController.java
@@ -1,6 +1,8 @@
package com.ruoyi.web.controller.system;
import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -12,9 +14,11 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.service.IVehicleInfoService;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -90,4 +94,88 @@
public AjaxResult remove(@PathVariable Long[] vehicleIds) {
return toAjax(vehicleInfoService.deleteVehicleInfoByIds(vehicleIds));
}
+
+ /**
+ * 缁戝畾杞﹁締鍒扮敤鎴�
+ */
+ @Anonymous
+ @Log(title = "鐢ㄦ埛缁戝畾杞﹁締", businessType = BusinessType.UPDATE)
+ @PostMapping("/bind")
+ public AjaxResult bindVehicle(@RequestBody Map<String, Object> params) {
+ try {
+ Long userId = Long.valueOf(params.get("userId").toString());
+ Long vehicleId = Long.valueOf(params.get("vehicleId").toString());
+
+ // 楠岃瘉杞﹁締鏄惁瀛樺湪
+ VehicleInfo vehicle = vehicleInfoService.selectVehicleInfoById(vehicleId);
+ if (vehicle == null) {
+ return error("杞﹁締涓嶅瓨鍦�");
+ }
+
+ // 楠岃瘉杞﹁締鐘舵�佹槸鍚︽甯�
+ if (!"0".equals(vehicle.getStatus())) {
+ return error("杞﹁締鐘舵�佸紓甯革紝鏃犳硶缁戝畾");
+ }
+
+ // 璋冪敤缁戝畾鏈嶅姟
+ int result = vehicleInfoService.bindVehicleToUser(userId, vehicleId);
+ if (result > 0) {
+ return success("杞﹁締缁戝畾鎴愬姛");
+ } else {
+ return error("杞﹁締缁戝畾澶辫触");
+ }
+ } catch (Exception e) {
+ logger.error("缁戝畾杞﹁締澶辫触", e);
+ return error("缁戝畾杞﹁締澶辫触锛�" + e.getMessage());
+ }
+ }
+
+ /**
+ * 瑙g粦鐢ㄦ埛杞﹁締
+ */
+ @Anonymous
+ @Log(title = "鐢ㄦ埛瑙g粦杞﹁締", businessType = BusinessType.UPDATE)
+ @PostMapping("/unbind")
+ public AjaxResult unbindVehicle(@RequestBody Map<String, Object> params) {
+ try {
+ Long userId = Long.valueOf(params.get("userId").toString());
+ Long vehicleId = Long.valueOf(params.get("vehicleId").toString());
+
+ // 璋冪敤瑙g粦鏈嶅姟
+ int result = vehicleInfoService.unbindVehicleFromUser(userId, vehicleId);
+ if (result > 0) {
+ return success("杞﹁締瑙g粦鎴愬姛");
+ } else {
+ return error("杞﹁締瑙g粦澶辫触");
+ }
+ } catch (Exception e) {
+ logger.error("瑙g粦杞﹁締澶辫触", e);
+ return error("瑙g粦杞﹁締澶辫触锛�" + e.getMessage());
+ }
+ }
+
+ /**
+ * 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+ */
+ @Anonymous
+ @GetMapping("/user/bound/{userId}")
+ public AjaxResult getUserBoundVehicle(@PathVariable("userId") Long userId) {
+ try {
+ VehicleInfo vehicle = vehicleInfoService.getUserBoundVehicle(userId);
+ if (vehicle != null) {
+ Map<String, Object> result = new HashMap<>();
+ result.put("vehicleId", vehicle.getVehicleId());
+ result.put("vehicleNumber", vehicle.getVehicleNo());
+ result.put("vehicleType", vehicle.getVehicleType());
+ result.put("vehicleBrand", vehicle.getVehicleBrand());
+ result.put("vehicleModel", vehicle.getVehicleModel());
+ return success(result);
+ } else {
+ return success(null);
+ }
+ } catch (Exception e) {
+ logger.error("鑾峰彇鐢ㄦ埛缁戝畾杞﹁締澶辫触", e);
+ return error("鑾峰彇鐢ㄦ埛缁戝畾杞﹁締澶辫触锛�" + e.getMessage());
+ }
+ }
}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
index 25cb9ec..f35b74e 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
@@ -17,6 +17,7 @@
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.SysTaskLog;
import com.ruoyi.system.domain.vo.TaskQueryVO;
import com.ruoyi.system.domain.vo.TaskCreateVO;
import com.ruoyi.system.domain.vo.TaskUpdateVO;
@@ -45,6 +46,18 @@
@PreAuthorize("@ss.hasPermi('task:general:query')")
@GetMapping("/list")
public TableDataInfo list(TaskQueryVO queryVO) {
+ // 鍦ㄥ悗绔嚜鍔ㄨ幏鍙栧綋鍓嶇敤鎴蜂俊鎭紝瀹炵幇缁煎悎鏌ヨ
+ // 缁煎悎鏌ヨ锛氬綋鍓嶇敤鎴锋墍鍦ㄦ満鏋勪换鍔� + 褰撳墠鐢ㄦ埛鍒涘缓鐨勪换鍔� + 鍒嗛厤缁欏綋鍓嶇敤鎴风殑浠诲姟
+ Long currentUserId = getUserId();
+ Long currentDeptId = getDeptId();
+
+ // 濡傛灉鍓嶇娌℃湁浼犻�掕繖浜涘弬鏁帮紝鍒欎娇鐢ㄥ綋鍓嶇櫥褰曠敤鎴蜂俊鎭�
+ if (queryVO.getCreatorId() == null && queryVO.getAssigneeId() == null && queryVO.getDeptId() == null) {
+ queryVO.setDeptId(currentDeptId);
+ queryVO.setCreatorId(currentUserId);
+ queryVO.setAssigneeId(currentUserId);
+ }
+
startPage();
List<SysTask> list = sysTaskService.selectSysTaskList(queryVO);
return getDataTable(list);
@@ -122,6 +135,24 @@
if (newStatus == null) {
return error("鏃犳晥鐨勪换鍔$姸鎬�");
}
+
+ // 濡傛灉鍖呭惈GPS浣嶇疆淇℃伅锛屼娇鐢ㄥ甫浣嶇疆鐨勬柟娉�
+ if (request.getLatitude() != null && request.getLongitude() != null) {
+ SysTaskLog locationLog = new SysTaskLog();
+ locationLog.setLatitude(request.getLatitude());
+ locationLog.setLongitude(request.getLongitude());
+ locationLog.setLocationAddress(request.getLocationAddress());
+ locationLog.setLocationProvince(request.getLocationProvince());
+ locationLog.setLocationCity(request.getLocationCity());
+ locationLog.setLocationDistrict(request.getLocationDistrict());
+ locationLog.setGpsAccuracy(request.getGpsAccuracy());
+ locationLog.setAltitude(request.getAltitude());
+ locationLog.setSpeed(request.getSpeed());
+ locationLog.setHeading(request.getHeading());
+
+ return toAjax(sysTaskService.changeTaskStatusWithLocation(taskId, newStatus, request.getRemark(), locationLog));
+ }
+
return toAjax(sysTaskService.changeTaskStatus(taskId, newStatus, request.getRemark()));
}
@@ -185,6 +216,18 @@
public static class ChangeStatusRequest {
private String taskStatus;
private String remark;
+
+ // GPS浣嶇疆淇℃伅瀛楁
+ private Double latitude;
+ private Double longitude;
+ private String locationAddress;
+ private String locationProvince;
+ private String locationCity;
+ private String locationDistrict;
+ private Double gpsAccuracy;
+ private Double altitude;
+ private Double speed;
+ private Double heading;
public String getTaskStatus() {
return taskStatus;
@@ -201,5 +244,85 @@
public void setRemark(String remark) {
this.remark = remark;
}
+
+ public Double getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(Double latitude) {
+ this.latitude = latitude;
+ }
+
+ public Double getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(Double longitude) {
+ this.longitude = longitude;
+ }
+
+ public String getLocationAddress() {
+ return locationAddress;
+ }
+
+ public void setLocationAddress(String locationAddress) {
+ this.locationAddress = locationAddress;
+ }
+
+ public String getLocationProvince() {
+ return locationProvince;
+ }
+
+ public void setLocationProvince(String locationProvince) {
+ this.locationProvince = locationProvince;
+ }
+
+ public String getLocationCity() {
+ return locationCity;
+ }
+
+ public void setLocationCity(String locationCity) {
+ this.locationCity = locationCity;
+ }
+
+ public String getLocationDistrict() {
+ return locationDistrict;
+ }
+
+ public void setLocationDistrict(String locationDistrict) {
+ this.locationDistrict = locationDistrict;
+ }
+
+ public Double getGpsAccuracy() {
+ return gpsAccuracy;
+ }
+
+ public void setGpsAccuracy(Double gpsAccuracy) {
+ this.gpsAccuracy = gpsAccuracy;
+ }
+
+ public Double getAltitude() {
+ return altitude;
+ }
+
+ public void setAltitude(Double altitude) {
+ this.altitude = altitude;
+ }
+
+ public Double getSpeed() {
+ return speed;
+ }
+
+ public void setSpeed(Double speed) {
+ this.speed = speed;
+ }
+
+ public Double getHeading() {
+ return heading;
+ }
+
+ public void setHeading(Double heading) {
+ this.heading = heading;
+ }
}
}
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index ae08b40..aa92707 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -144,3 +144,8 @@
# 姘戣埅鎺ュ彛鍦板潃
min:
apiUrl: http://120.25.98.119:8084/v1/ #娴嬭瘯鐜锛歭ocalhost:8011
+
+# 鑵捐鍦板浘閰嶇疆
+tencent:
+ map:
+ key: 6YVBZ-ZJDLQ-JMY5F-BR7XG-H3TAV-C3FXC
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/TencentMapConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/TencentMapConfig.java
new file mode 100644
index 0000000..93e1a6e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/TencentMapConfig.java
@@ -0,0 +1,25 @@
+package com.ruoyi.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 鑵捐鍦板浘閰嶇疆绫�
+ */
+@Configuration
+@ConfigurationProperties(prefix = "tencent.map")
+public class TencentMapConfig {
+
+ /**
+ * 鑵捐鍦板浘API Key
+ */
+ private String key;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
index fb18c5c..ed86854 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
@@ -52,6 +52,9 @@
/** 鐖堕儴闂ㄥ悕绉� */
private String parentName;
+ /** SQL Server涓殑閮ㄩ棬ID */
+ private Integer departmentId;
+
/** 瀛愰儴闂� */
private List<SysDept> children = new ArrayList<SysDept>();
@@ -181,6 +184,16 @@
this.children = children;
}
+ public Integer getDepartmentId()
+ {
+ return departmentId;
+ }
+
+ public void setDepartmentId(Integer departmentId)
+ {
+ this.departmentId = departmentId;
+ }
+
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -198,6 +211,7 @@
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
+ .append("departmentId", getDepartmentId())
.toString();
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index 714cbe7..8cf153e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -89,6 +89,9 @@
/** 瑙掕壊ID */
private Long roleId;
+ /** SQL Server涓殑OA鐢ㄦ埛ID */
+ private Integer oaUserId;
+
public SysUser()
{
@@ -297,6 +300,16 @@
this.roleId = roleId;
}
+ public Integer getOaUserId()
+ {
+ return oaUserId;
+ }
+
+ public void setOaUserId(Integer oaUserId)
+ {
+ this.oaUserId = oaUserId;
+ }
+
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -319,6 +332,7 @@
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.append("dept", getDept())
+ .append("oaUserId", getOaUserId())
.toString();
}
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
index 8c2c9f4..a255812 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
@@ -38,10 +38,21 @@
public Object around(ProceedingJoinPoint point) throws Throwable
{
DataSource dataSource = getDataSource(point);
+
+ // 璁板綍褰撳墠鏁版嵁婧愶紝鐢ㄤ簬鍒ゆ柇鏄惁闇�瑕佹仮澶�
+ String oldDataSourceType = DynamicDataSourceContextHolder.getDataSourceType();
+ boolean isNewDataSource = false;
if (StringUtils.isNotNull(dataSource))
{
- DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
+ String newDataSourceType = dataSource.value().name();
+ // 鍙湁褰撴暟鎹簮鍙戠敓鍙樺寲鏃舵墠璁剧疆鏂扮殑鏁版嵁婧�
+ if (!newDataSourceType.equals(oldDataSourceType))
+ {
+ DynamicDataSourceContextHolder.setDataSourceType(newDataSourceType);
+ isNewDataSource = true;
+ logger.debug("鍒囨崲鏁版嵁婧�: {} -> {}", oldDataSourceType, newDataSourceType);
+ }
}
try
@@ -50,8 +61,21 @@
}
finally
{
- // 閿�姣佹暟鎹簮 鍦ㄦ墽琛屾柟娉曚箣鍚�
- DynamicDataSourceContextHolder.clearDataSourceType();
+ // 鍙湁褰撴湰娆¤皟鐢ㄦ敼鍙樹簡鏁版嵁婧愭椂锛屾墠闇�瑕佹仮澶�
+ if (isNewDataSource)
+ {
+ // 鎭㈠鍒颁箣鍓嶇殑鏁版嵁婧�
+ if (StringUtils.isNotEmpty(oldDataSourceType))
+ {
+ DynamicDataSourceContextHolder.setDataSourceType(oldDataSourceType);
+ logger.debug("鎭㈠鏁版嵁婧�: {}", oldDataSourceType);
+ }
+ else
+ {
+ DynamicDataSourceContextHolder.clearDataSourceType();
+ logger.debug("娓呴櫎鏁版嵁婧愶紝鎭㈠鍒伴粯璁ゆ暟鎹簮");
+ }
+ }
}
}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/DepartmentSyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/DepartmentSyncTask.java
new file mode 100644
index 0000000..2369fac
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/DepartmentSyncTask.java
@@ -0,0 +1,85 @@
+package com.ruoyi.quartz.task;
+
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.service.IDepartmentSyncDataService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.IDepartmentSyncService;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬鍚屾瀹氭椂浠诲姟
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Component("departmentSyncTask")
+public class DepartmentSyncTask
+{
+ private static final Logger log = LoggerFactory.getLogger(DepartmentSyncTask.class);
+
+ @Autowired
+ private IDepartmentSyncDataService departmentSyncDataService;
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ private List<DepartmentSyncDTO> getDepartment(){
+ return departmentSyncDataService.getBranchDepartments();
+ }
+
+ private List<DepartmentSyncDTO> getTransportDept(){
+ return departmentSyncDataService.getTransportDepartments();
+ }
+
+
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁
+ *
+ * 浣跨敤绀轰緥锛�
+ * - 浠诲姟鍚嶇О锛氬垎鍏徃鍚屾
+ * - 璋冪敤鐩爣锛歞epartmentSyncTask.syncDepartments
+ * - cron琛ㄨ揪寮忥細0 0 2 * * ?锛堟瘡澶╁噷鏅�2鐐规墽琛岋級
+ */
+ public void syncDepartments()
+ {
+ try
+ {
+ log.info("==========寮�濮嬫墽琛岄儴闂ㄥ悓姝ュ畾鏃朵换鍔�==========");
+
+ AjaxResult result = departmentSyncService.syncBranchDepartments(this.getDepartment());
+
+ departmentSyncService.syncTransportDepartments(this.getTransportDept());
+
+ if (result.get("code").equals(200))
+ {
+ log.info("閮ㄩ棬鍚屾鎴愬姛: {}", result.get("msg"));
+ }
+ else
+ {
+ log.error("閮ㄩ棬鍚屾澶辫触: {}", result.get("msg"));
+ }
+
+ log.info("==========閮ㄩ棬鍚屾瀹氭椂浠诲姟鎵ц瀹屾垚==========");
+ }
+ catch (Exception e)
+ {
+ log.error("閮ㄩ棬鍚屾瀹氭椂浠诲姟鎵ц寮傚父", e);
+ }
+ }
+
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堝甫鍙傛暟锛�
+ *
+ * @param params 鍙傛暟锛堥鐣欙紝鏆傛湭浣跨敤锛�
+ */
+ public void syncDepartments(String params)
+ {
+ log.info("閮ㄩ棬鍚屾浠诲姟鍙傛暟: {}", params);
+ syncDepartments();
+ }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/OaSyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/OaSyncTask.java
new file mode 100644
index 0000000..6b9cb51
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/OaSyncTask.java
@@ -0,0 +1,164 @@
+package com.ruoyi.quartz.task;
+
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.domain.UserSyncDTO;
+import com.ruoyi.system.service.IDepartmentSyncDataService;
+import com.ruoyi.system.service.IUserSyncDataService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.IDepartmentSyncService;
+import com.ruoyi.system.service.IUserSyncService;
+
+import java.util.List;
+
+/**
+ * OA鏁版嵁鍚屾瀹氭椂浠诲姟锛堢粍鍚堜换鍔★級
+ * 鍏堝悓姝ラ儴闂紝鍐嶅悓姝ョ敤鎴�
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Component("oaSyncTask")
+public class OaSyncTask
+{
+ private static final Logger log = LoggerFactory.getLogger(OaSyncTask.class);
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+ @Autowired
+ private IDepartmentSyncDataService departmentSyncDataService;
+
+ @Autowired
+ private IUserSyncDataService userSyncDataService;
+
+ private List<DepartmentSyncDTO> getDept(){
+ return departmentSyncDataService.getBranchDepartments();
+ }
+
+
+ private List<UserSyncDTO> getUserData(){
+ return userSyncDataService.getOaUsers();
+ }
+ /**
+ * 鍚屾OA鏁版嵁锛堥儴闂�+鐢ㄦ埛锛�
+ * 鎸夐『搴忔墽琛岋細1. 閮ㄩ棬鍚屾 2. 鐢ㄦ埛鍚屾
+ *
+ * 浣跨敤绀轰緥锛�
+ * - 浠诲姟鍚嶇О锛歄A鏁版嵁鍚屾
+ * - 璋冪敤鐩爣锛歰aSyncTask.syncOaData
+ * - cron琛ㄨ揪寮忥細0 0 2 * * ?锛堟瘡澶╁噷鏅�2鐐规墽琛岋級
+ */
+ public void syncOaData()
+ {
+ try
+ {
+ log.info("##########寮�濮嬫墽琛孫A鏁版嵁鍚屾瀹氭椂浠诲姟##########");
+
+ // 绗竴姝ワ細鍚屾閮ㄩ棬
+ log.info("銆愭楠�1/2銆戝紑濮嬪悓姝ラ儴闂ㄦ暟鎹�...");
+ AjaxResult deptResult = departmentSyncService.syncBranchDepartments(this.getDept());
+
+ if (deptResult.get("code").equals(200))
+ {
+ log.info("銆愭楠�1/2銆戦儴闂ㄥ悓姝ユ垚鍔�: {}", deptResult.get("msg"));
+
+ // 绗簩姝ワ細鍚屾鐢ㄦ埛锛堝彧鏈夐儴闂ㄥ悓姝ユ垚鍔熸墠鎵ц锛�
+ log.info("銆愭楠�2/2銆戝紑濮嬪悓姝ョ敤鎴锋暟鎹�...");
+ AjaxResult userResult = userSyncService.syncOaUsers(this.getUserData());
+
+ if (userResult.get("code").equals(200))
+ {
+ log.info("銆愭楠�2/2銆戠敤鎴峰悓姝ユ垚鍔�: {}", userResult.get("msg"));
+ log.info("##########OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц瀹屾垚##########");
+ log.info("鎬荤粨锛氶儴闂ㄥ悓姝ユ垚鍔燂紝鐢ㄦ埛鍚屾鎴愬姛");
+ }
+ else
+ {
+ log.error("銆愭楠�2/2銆戠敤鎴峰悓姝ュけ璐�: {}", userResult.get("msg"));
+ log.warn("##########OA鏁版嵁鍚屾瀹氭椂浠诲姟閮ㄥ垎瀹屾垚##########");
+ log.warn("鎬荤粨锛氶儴闂ㄥ悓姝ユ垚鍔燂紝鐢ㄦ埛鍚屾澶辫触");
+ }
+ }
+ else
+ {
+ log.error("銆愭楠�1/2銆戦儴闂ㄥ悓姝ュけ璐�: {}", deptResult.get("msg"));
+ log.error("鐢变簬閮ㄩ棬鍚屾澶辫触锛岃烦杩囩敤鎴峰悓姝�");
+ log.error("##########OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц澶辫触##########");
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("OA鏁版嵁鍚屾瀹氭椂浠诲姟鎵ц寮傚父", e);
+ }
+ }
+
+ /**
+ * 鍚屾OA鏁版嵁锛堝甫鍙傛暟锛�
+ *
+ * @param params 鍙傛暟锛堥鐣欙紝鏆傛湭浣跨敤锛�
+ */
+ public void syncOaData(String params)
+ {
+ log.info("OA鏁版嵁鍚屾浠诲姟鍙傛暟: {}", params);
+ syncOaData();
+ }
+
+ /**
+ * 浠呭悓姝ラ儴闂紙鐙珛浠诲姟锛�
+ */
+ public void syncDepartmentsOnly()
+ {
+ try
+ {
+ log.info("==========寮�濮嬫墽琛岄儴闂ㄥ悓姝ヤ换鍔�==========");
+ AjaxResult result = departmentSyncService.syncBranchDepartments(this.getDept());
+
+ if (result.get("code").equals(200))
+ {
+ log.info("閮ㄩ棬鍚屾鎴愬姛: {}", result.get("msg"));
+ }
+ else
+ {
+ log.error("閮ㄩ棬鍚屾澶辫触: {}", result.get("msg"));
+ }
+ log.info("==========閮ㄩ棬鍚屾浠诲姟鎵ц瀹屾垚==========");
+ }
+ catch (Exception e)
+ {
+ log.error("閮ㄩ棬鍚屾浠诲姟鎵ц寮傚父", e);
+ }
+ }
+
+ /**
+ * 浠呭悓姝ョ敤鎴凤紙鐙珛浠诲姟锛�
+ */
+ public void syncUsersOnly()
+ {
+ try
+ {
+ log.info("==========寮�濮嬫墽琛岀敤鎴峰悓姝ヤ换鍔�==========");
+ AjaxResult result = userSyncService.syncOaUsers(this.getUserData());
+
+ if (result.get("code").equals(200))
+ {
+ log.info("鐢ㄦ埛鍚屾鎴愬姛: {}", result.get("msg"));
+ }
+ else
+ {
+ log.error("鐢ㄦ埛鍚屾澶辫触: {}", result.get("msg"));
+ }
+ log.info("==========鐢ㄦ埛鍚屾浠诲姟鎵ц瀹屾垚==========");
+ }
+ catch (Exception e)
+ {
+ log.error("鐢ㄦ埛鍚屾浠诲姟鎵ц寮傚父", e);
+ }
+ }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/UserSyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/UserSyncTask.java
new file mode 100644
index 0000000..c28d43b
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/UserSyncTask.java
@@ -0,0 +1,80 @@
+package com.ruoyi.quartz.task;
+
+import com.ruoyi.system.domain.UserSyncDTO;
+import com.ruoyi.system.service.IUserSyncDataService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.IUserSyncService;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛鍚屾瀹氭椂浠诲姟
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Component("userSyncTask")
+public class UserSyncTask
+{
+ private static final Logger log = LoggerFactory.getLogger(UserSyncTask.class);
+
+ @Autowired
+ private IUserSyncDataService userSyncDataService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+
+ private List<UserSyncDTO> getUserSyncData(){
+ return userSyncDataService.getOaUsers();
+ }
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁
+ *
+ * 浣跨敤绀轰緥锛�
+ * - 浠诲姟鍚嶇О锛歄A鐢ㄦ埛鍚屾
+ * - 璋冪敤鐩爣锛歶serSyncTask.syncUsers
+ * - cron琛ㄨ揪寮忥細0 0 3 * * ?锛堟瘡澶╁噷鏅�3鐐规墽琛岋級
+ *
+ * 娉ㄦ剰锛氬繀椤诲厛鎵ц閮ㄩ棬鍚屾浠诲姟锛�
+ */
+ public void syncUsers()
+ {
+ try
+ {
+ log.info("==========寮�濮嬫墽琛岀敤鎴峰悓姝ュ畾鏃朵换鍔�==========");
+
+ AjaxResult result = userSyncService.syncOaUsers(this.getUserSyncData());
+
+ if (result.get("code").equals(200))
+ {
+ log.info("鐢ㄦ埛鍚屾鎴愬姛: {}", result.get("msg"));
+ }
+ else
+ {
+ log.error("鐢ㄦ埛鍚屾澶辫触: {}", result.get("msg"));
+ }
+
+ log.info("==========鐢ㄦ埛鍚屾瀹氭椂浠诲姟鎵ц瀹屾垚==========");
+ }
+ catch (Exception e)
+ {
+ log.error("鐢ㄦ埛鍚屾瀹氭椂浠诲姟鎵ц寮傚父", e);
+ }
+ }
+
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁锛堝甫鍙傛暟锛�
+ *
+ * @param params 鍙傛暟锛堥鐣欙紝鏆傛湭浣跨敤锛�
+ */
+ public void syncUsers(String params)
+ {
+ log.info("鐢ㄦ埛鍚屾浠诲姟鍙傛暟: {}", params);
+ syncUsers();
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/DepartmentSyncDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DepartmentSyncDTO.java
new file mode 100644
index 0000000..a3ca439
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DepartmentSyncDTO.java
@@ -0,0 +1,73 @@
+package com.ruoyi.system.domain;
+
+/**
+ * 閮ㄩ棬鍚屾DTO瀵硅薄
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+public class DepartmentSyncDTO
+{
+ /** SQL Server涓殑閮ㄩ棬ID */
+ private Integer departmentId;
+
+ /** 閮ㄩ棬鍚嶇О */
+ private String departmentName;
+
+ /** 鐖堕儴闂↖D */
+ private Integer parentId;
+
+ /** 鐖堕儴闂ㄥ悕绉� */
+ private String parentName;
+
+ public Integer getDepartmentId()
+ {
+ return departmentId;
+ }
+
+ public void setDepartmentId(Integer departmentId)
+ {
+ this.departmentId = departmentId;
+ }
+
+ public String getDepartmentName()
+ {
+ return departmentName;
+ }
+
+ public void setDepartmentName(String departmentName)
+ {
+ this.departmentName = departmentName;
+ }
+
+ public Integer getParentId()
+ {
+ return parentId;
+ }
+
+ public void setParentId(Integer parentId)
+ {
+ this.parentId = parentId;
+ }
+
+ public String getParentName()
+ {
+ return parentName;
+ }
+
+ public void setParentName(String parentName)
+ {
+ this.parentName = parentName;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "DepartmentSyncDTO{" +
+ "departmentId=" + departmentId +
+ ", departmentName='" + departmentName + '\'' +
+ ", parentId=" + parentId +
+ ", parentName='" + parentName + '\'' +
+ '}';
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/HospData.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/HospData.java
new file mode 100644
index 0000000..526d27b
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/HospData.java
@@ -0,0 +1,188 @@
+package com.ruoyi.system.domain;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 鍖婚櫌鏁版嵁瀵硅薄 HospData
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+public class HospData extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 鍖婚櫌ID */
+ private Integer hospId;
+
+ /** 鍖婚櫌鍚嶇О */
+ private String hospName;
+
+ /** 鍩庡競ID */
+ private Integer hospCityId;
+
+ /** 鍖婚櫌绠�绉� */
+ private String hospShort;
+
+ /** 鐪佷唤 */
+ private String hopsProvince;
+
+ /** 鍩庡競 */
+ private String hopsCity;
+
+ /** 鍖哄煙 */
+ private String hopsArea;
+
+ /** 鍖婚櫌鍦板潃 */
+ private String hospAddress;
+
+ /** 鍖婚櫌鐢佃瘽 */
+ private String hospTel;
+
+ /** 鍗曚綅ID */
+ private Integer hospUnitId;
+
+ /** 鐘舵�� */
+ private Integer hospState;
+
+ /** OA ID */
+ private String hospOaId;
+
+ /** 浠嬬粛浜篒D */
+ private Integer hospIntroducerId;
+
+ /** 浠嬬粛鏃ユ湡 */
+ private String hospIntroducerDate;
+
+ /** 鍖婚櫌绾у埆 */
+ private Integer hospLevel;
+
+ public Integer getHospId() {
+ return hospId;
+ }
+
+ public void setHospId(Integer hospId) {
+ this.hospId = hospId;
+ }
+
+ public String getHospName() {
+ return hospName;
+ }
+
+ public void setHospName(String hospName) {
+ this.hospName = hospName;
+ }
+
+ public Integer getHospCityId() {
+ return hospCityId;
+ }
+
+ public void setHospCityId(Integer hospCityId) {
+ this.hospCityId = hospCityId;
+ }
+
+ public String getHospShort() {
+ return hospShort;
+ }
+
+ public void setHospShort(String hospShort) {
+ this.hospShort = hospShort;
+ }
+
+ public String getHopsProvince() {
+ return hopsProvince;
+ }
+
+ public void setHopsProvince(String hopsProvince) {
+ this.hopsProvince = hopsProvince;
+ }
+
+ public String getHopsCity() {
+ return hopsCity;
+ }
+
+ public void setHopsCity(String hopsCity) {
+ this.hopsCity = hopsCity;
+ }
+
+ public String getHopsArea() {
+ return hopsArea;
+ }
+
+ public void setHopsArea(String hopsArea) {
+ this.hopsArea = hopsArea;
+ }
+
+ public String getHospAddress() {
+ return hospAddress;
+ }
+
+ public void setHospAddress(String hospAddress) {
+ this.hospAddress = hospAddress;
+ }
+
+ public String getHospTel() {
+ return hospTel;
+ }
+
+ public void setHospTel(String hospTel) {
+ this.hospTel = hospTel;
+ }
+
+ public Integer getHospUnitId() {
+ return hospUnitId;
+ }
+
+ public void setHospUnitId(Integer hospUnitId) {
+ this.hospUnitId = hospUnitId;
+ }
+
+ public Integer getHospState() {
+ return hospState;
+ }
+
+ public void setHospState(Integer hospState) {
+ this.hospState = hospState;
+ }
+
+ public String getHospOaId() {
+ return hospOaId;
+ }
+
+ public void setHospOaId(String hospOaId) {
+ this.hospOaId = hospOaId;
+ }
+
+ public Integer getHospIntroducerId() {
+ return hospIntroducerId;
+ }
+
+ public void setHospIntroducerId(Integer hospIntroducerId) {
+ this.hospIntroducerId = hospIntroducerId;
+ }
+
+ public String getHospIntroducerDate() {
+ return hospIntroducerDate;
+ }
+
+ public void setHospIntroducerDate(String hospIntroducerDate) {
+ this.hospIntroducerDate = hospIntroducerDate;
+ }
+
+ public Integer getHospLevel() {
+ return hospLevel;
+ }
+
+ public void setHospLevel(Integer hospLevel) {
+ this.hospLevel = hospLevel;
+ }
+
+ @Override
+ public String toString() {
+ return "HospData{" +
+ "hospId=" + hospId +
+ ", hospName='" + hospName + '\'' +
+ ", hospAddress='" + hospAddress + '\'' +
+ ", hopsCity='" + hopsCity + '\'' +
+ '}';
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Icd10.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Icd10.java
new file mode 100644
index 0000000..febe31a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Icd10.java
@@ -0,0 +1,123 @@
+package com.ruoyi.system.domain;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * ICD-10鐤剧梾鍒嗙被瀵硅薄 ICD10
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+public class Icd10 extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** ID */
+ private Integer id;
+
+ /** ICD缂栫爜 */
+ private String icdCode;
+
+ /** 搴忓彿 */
+ private Double xh;
+
+ /** 鍒嗙被鐮� */
+ private String fm;
+
+ /** 鐤剧梾鍚嶇О */
+ private String icdName;
+
+ /** 鍔╄鐮� */
+ private String zjm;
+
+ /** 璇存槑 */
+ private String sm;
+
+ /** 涓婃姤鎬ц川 */
+ private String sbxz;
+
+ /** 涓村簥鎬ц川 */
+ private String lxxz;
+
+ /** 鐘舵�� */
+ private Integer icdState;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getIcdCode() {
+ return icdCode;
+ }
+
+ public void setIcdCode(String icdCode) {
+ this.icdCode = icdCode;
+ }
+
+ public Double getXh() {
+ return xh;
+ }
+
+ public void setXh(Double xh) {
+ this.xh = xh;
+ }
+
+ public String getFm() {
+ return fm;
+ }
+
+ public void setFm(String fm) {
+ this.fm = fm;
+ }
+
+ public String getIcdName() {
+ return icdName;
+ }
+
+ public void setIcdName(String icdName) {
+ this.icdName = icdName;
+ }
+
+ public String getZjm() {
+ return zjm;
+ }
+
+ public void setZjm(String zjm) {
+ this.zjm = zjm;
+ }
+
+ public String getSm() {
+ return sm;
+ }
+
+ public void setSm(String sm) {
+ this.sm = sm;
+ }
+
+ public String getSbxz() {
+ return sbxz;
+ }
+
+ public void setSbxz(String sbxz) {
+ this.sbxz = sbxz;
+ }
+
+ public String getLxxz() {
+ return lxxz;
+ }
+
+ public void setLxxz(String lxxz) {
+ this.lxxz = lxxz;
+ }
+
+ public Integer getIcdState() {
+ return icdState;
+ }
+
+ public void setIcdState(Integer icdState) {
+ this.icdState = icdState;
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
index 99c8bad..0cb20ea 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
@@ -120,6 +120,12 @@
/** 鎿嶄綔鏃ュ織鍒楄〃 */
private List<SysTaskLog> operationLogs;
+ /** 鎬ユ晳杞繍鎵╁睍淇℃伅 */
+ private SysTaskEmergency emergencyInfo;
+
+ /** 绂忕杞︽墿灞曚俊鎭� */
+ private SysTaskWelfare welfareInfo;
+
public void setTaskId(Long taskId) {
this.taskId = taskId;
}
@@ -328,6 +334,22 @@
return operationLogs;
}
+ public void setEmergencyInfo(SysTaskEmergency emergencyInfo) {
+ this.emergencyInfo = emergencyInfo;
+ }
+
+ public SysTaskEmergency getEmergencyInfo() {
+ return emergencyInfo;
+ }
+
+ public void setWelfareInfo(SysTaskWelfare welfareInfo) {
+ this.welfareInfo = welfareInfo;
+ }
+
+ public SysTaskWelfare getWelfareInfo() {
+ return welfareInfo;
+ }
+
/**
* 鍒ゆ柇鏄惁鍙互鍙樻洿鐘舵��
*/
@@ -340,11 +362,23 @@
// 鐘舵�佹祦杞鍒�
switch (currentStatus) {
case PENDING:
- return newStatus == TaskStatus.IN_PROGRESS || newStatus == TaskStatus.CANCELLED;
+ // 寰呭鐞� -> 鍑哄彂涓�佸凡鍙栨秷
+ return newStatus == TaskStatus.DEPARTING || newStatus == TaskStatus.CANCELLED;
+ case DEPARTING:
+ // 鍑哄彂涓� -> 宸插埌杈俱�佸凡鍙栨秷
+ return newStatus == TaskStatus.ARRIVED || newStatus == TaskStatus.CANCELLED;
+ case ARRIVED:
+ // 宸插埌杈� -> 杩旂▼涓�
+ return newStatus == TaskStatus.RETURNING;
+ case RETURNING:
+ // 杩旂▼涓� -> 宸插畬鎴�
+ return newStatus == TaskStatus.COMPLETED;
case IN_PROGRESS:
+ // 鍏煎鏃ф暟鎹細浠诲姟涓� -> 宸插畬鎴愩�佸凡鍙栨秷銆佸緟澶勭悊
return newStatus == TaskStatus.COMPLETED || newStatus == TaskStatus.CANCELLED || newStatus == TaskStatus.PENDING;
case COMPLETED:
case CANCELLED:
+ // 宸插畬鎴愩�佸凡鍙栨秷 -> 涓嶅厑璁镐换浣曠姸鎬佸彉鏇�
return false;
default:
return false;
@@ -426,4 +460,4 @@
", deptName='" + deptName + '\'' +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java
new file mode 100644
index 0000000..438a18f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java
@@ -0,0 +1,291 @@
+package com.ruoyi.system.domain;
+
+import java.math.BigDecimal;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅瀵硅薄 sys_task_emergency
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+public class SysTaskEmergency extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 涓婚敭ID */
+ private Long id;
+
+ /** 浠诲姟ID */
+ private Long taskId;
+
+ /** 鎮h�呰仈绯讳汉 */
+ private String patientContact;
+
+ /** 鎮h�呰仈绯荤數璇� */
+ private String patientPhone;
+
+ /** 鎮h�呭鍚� */
+ private String patientName;
+
+ /** 鎮h�呮�у埆 */
+ private String patientGender;
+
+ /** 鎮h�呰韩浠借瘉鍙� */
+ private String patientIdCard;
+
+ /** 鎮h�呯梾鎯呮弿杩� */
+ private String patientCondition;
+
+ /** 杞嚭鍖婚櫌鍚嶇О */
+ private String hospitalOutName;
+
+ /** 杞嚭鍖婚櫌绉戝 */
+ private String hospitalOutDepartment;
+
+ /** 杞嚭鍖婚櫌搴婂彿 */
+ private String hospitalOutBedNumber;
+
+ /** 杞嚭鍖婚櫌鍦板潃 */
+ private String hospitalOutAddress;
+
+ /** 杞嚭鍖婚櫌缁忓害 */
+ private BigDecimal hospitalOutLongitude;
+
+ /** 杞嚭鍖婚櫌绾害 */
+ private BigDecimal hospitalOutLatitude;
+
+ /** 杞叆鍖婚櫌鍚嶇О */
+ private String hospitalInName;
+
+ /** 杞叆鍖婚櫌绉戝 */
+ private String hospitalInDepartment;
+
+ /** 杞叆鍖婚櫌搴婂彿 */
+ private String hospitalInBedNumber;
+
+ /** 杞叆鍖婚櫌鍦板潃 */
+ private String hospitalInAddress;
+
+ /** 杞叆鍖婚櫌缁忓害 */
+ private BigDecimal hospitalInLongitude;
+
+ /** 杞叆鍖婚櫌绾害 */
+ private BigDecimal hospitalInLatitude;
+
+ /** 杞繍鍏噷鏁� */
+ private BigDecimal transferDistance;
+
+ /** 鎴愪氦浠� */
+ private BigDecimal transferPrice;
+
+ /** 涔樺鑱旂郴浜�(绂忕杞�) */
+ private String passengerContact;
+
+ /** 涔樺鑱旂郴鐢佃瘽(绂忕杞�) */
+ private String passengerPhone;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getTaskId() {
+ return taskId;
+ }
+
+ public void setTaskId(Long taskId) {
+ this.taskId = taskId;
+ }
+
+ public String getPatientContact() {
+ return patientContact;
+ }
+
+ public void setPatientContact(String patientContact) {
+ this.patientContact = patientContact;
+ }
+
+ public String getPatientPhone() {
+ return patientPhone;
+ }
+
+ public void setPatientPhone(String patientPhone) {
+ this.patientPhone = patientPhone;
+ }
+
+ public String getPatientName() {
+ return patientName;
+ }
+
+ public void setPatientName(String patientName) {
+ this.patientName = patientName;
+ }
+
+ public String getPatientGender() {
+ return patientGender;
+ }
+
+ public void setPatientGender(String patientGender) {
+ this.patientGender = patientGender;
+ }
+
+ public String getPatientIdCard() {
+ return patientIdCard;
+ }
+
+ public void setPatientIdCard(String patientIdCard) {
+ this.patientIdCard = patientIdCard;
+ }
+
+ public String getPatientCondition() {
+ return patientCondition;
+ }
+
+ public void setPatientCondition(String patientCondition) {
+ this.patientCondition = patientCondition;
+ }
+
+ public String getHospitalOutName() {
+ return hospitalOutName;
+ }
+
+ public void setHospitalOutName(String hospitalOutName) {
+ this.hospitalOutName = hospitalOutName;
+ }
+
+ public String getHospitalOutDepartment() {
+ return hospitalOutDepartment;
+ }
+
+ public void setHospitalOutDepartment(String hospitalOutDepartment) {
+ this.hospitalOutDepartment = hospitalOutDepartment;
+ }
+
+ public String getHospitalOutBedNumber() {
+ return hospitalOutBedNumber;
+ }
+
+ public void setHospitalOutBedNumber(String hospitalOutBedNumber) {
+ this.hospitalOutBedNumber = hospitalOutBedNumber;
+ }
+
+ public String getHospitalOutAddress() {
+ return hospitalOutAddress;
+ }
+
+ public void setHospitalOutAddress(String hospitalOutAddress) {
+ this.hospitalOutAddress = hospitalOutAddress;
+ }
+
+ public BigDecimal getHospitalOutLongitude() {
+ return hospitalOutLongitude;
+ }
+
+ public void setHospitalOutLongitude(BigDecimal hospitalOutLongitude) {
+ this.hospitalOutLongitude = hospitalOutLongitude;
+ }
+
+ public BigDecimal getHospitalOutLatitude() {
+ return hospitalOutLatitude;
+ }
+
+ public void setHospitalOutLatitude(BigDecimal hospitalOutLatitude) {
+ this.hospitalOutLatitude = hospitalOutLatitude;
+ }
+
+ public String getHospitalInName() {
+ return hospitalInName;
+ }
+
+ public void setHospitalInName(String hospitalInName) {
+ this.hospitalInName = hospitalInName;
+ }
+
+ public String getHospitalInDepartment() {
+ return hospitalInDepartment;
+ }
+
+ public void setHospitalInDepartment(String hospitalInDepartment) {
+ this.hospitalInDepartment = hospitalInDepartment;
+ }
+
+ public String getHospitalInBedNumber() {
+ return hospitalInBedNumber;
+ }
+
+ public void setHospitalInBedNumber(String hospitalInBedNumber) {
+ this.hospitalInBedNumber = hospitalInBedNumber;
+ }
+
+ public String getHospitalInAddress() {
+ return hospitalInAddress;
+ }
+
+ public void setHospitalInAddress(String hospitalInAddress) {
+ this.hospitalInAddress = hospitalInAddress;
+ }
+
+ public BigDecimal getHospitalInLongitude() {
+ return hospitalInLongitude;
+ }
+
+ public void setHospitalInLongitude(BigDecimal hospitalInLongitude) {
+ this.hospitalInLongitude = hospitalInLongitude;
+ }
+
+ public BigDecimal getHospitalInLatitude() {
+ return hospitalInLatitude;
+ }
+
+ public void setHospitalInLatitude(BigDecimal hospitalInLatitude) {
+ this.hospitalInLatitude = hospitalInLatitude;
+ }
+
+ public BigDecimal getTransferDistance() {
+ return transferDistance;
+ }
+
+ public void setTransferDistance(BigDecimal transferDistance) {
+ this.transferDistance = transferDistance;
+ }
+
+ public BigDecimal getTransferPrice() {
+ return transferPrice;
+ }
+
+ public void setTransferPrice(BigDecimal transferPrice) {
+ this.transferPrice = transferPrice;
+ }
+
+ public String getPassengerContact() {
+ return passengerContact;
+ }
+
+ public void setPassengerContact(String passengerContact) {
+ this.passengerContact = passengerContact;
+ }
+
+ public String getPassengerPhone() {
+ return passengerPhone;
+ }
+
+ public void setPassengerPhone(String passengerPhone) {
+ this.passengerPhone = passengerPhone;
+ }
+
+ @Override
+ public String toString() {
+ return "SysTaskEmergency{" +
+ "id=" + id +
+ ", taskId=" + taskId +
+ ", patientName='" + patientName + '\'' +
+ ", hospitalOutName='" + hospitalOutName + '\'' +
+ ", hospitalInName='" + hospitalInName + '\'' +
+ ", transferDistance=" + transferDistance +
+ ", transferPrice=" + transferPrice +
+ '}';
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java
index 36c9638..e1140eb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java
@@ -54,6 +54,46 @@
@Excel(name = "IP鍦板潃")
private String ipAddress;
+ /** 绾害 */
+ @Excel(name = "绾害")
+ private Double latitude;
+
+ /** 缁忓害 */
+ @Excel(name = "缁忓害")
+ private Double longitude;
+
+ /** 浣嶇疆鍦板潃 */
+ @Excel(name = "浣嶇疆鍦板潃")
+ private String locationAddress;
+
+ /** 鐪佷唤 */
+ @Excel(name = "鐪佷唤")
+ private String locationProvince;
+
+ /** 鍩庡競 */
+ @Excel(name = "鍩庡競")
+ private String locationCity;
+
+ /** 鍖哄幙 */
+ @Excel(name = "鍖哄幙")
+ private String locationDistrict;
+
+ /** GPS绮惧害锛堢背锛� */
+ @Excel(name = "GPS绮惧害")
+ private Double gpsAccuracy;
+
+ /** 娴锋嫈楂樺害锛堢背锛� */
+ @Excel(name = "娴锋嫈楂樺害")
+ private Double altitude;
+
+ /** 閫熷害锛堢背/绉掞級 */
+ @Excel(name = "閫熷害")
+ private Double speed;
+
+ /** 鏂瑰悜瑙掑害锛�0-360锛� */
+ @Excel(name = "鏂瑰悜瑙掑害")
+ private Double heading;
+
public void setLogId(Long logId) {
this.logId = logId;
}
@@ -134,6 +174,86 @@
return ipAddress;
}
+ public void setLatitude(Double latitude) {
+ this.latitude = latitude;
+ }
+
+ public Double getLatitude() {
+ return latitude;
+ }
+
+ public void setLongitude(Double longitude) {
+ this.longitude = longitude;
+ }
+
+ public Double getLongitude() {
+ return longitude;
+ }
+
+ public void setLocationAddress(String locationAddress) {
+ this.locationAddress = locationAddress;
+ }
+
+ public String getLocationAddress() {
+ return locationAddress;
+ }
+
+ public void setLocationProvince(String locationProvince) {
+ this.locationProvince = locationProvince;
+ }
+
+ public String getLocationProvince() {
+ return locationProvince;
+ }
+
+ public void setLocationCity(String locationCity) {
+ this.locationCity = locationCity;
+ }
+
+ public String getLocationCity() {
+ return locationCity;
+ }
+
+ public void setLocationDistrict(String locationDistrict) {
+ this.locationDistrict = locationDistrict;
+ }
+
+ public String getLocationDistrict() {
+ return locationDistrict;
+ }
+
+ public void setGpsAccuracy(Double gpsAccuracy) {
+ this.gpsAccuracy = gpsAccuracy;
+ }
+
+ public Double getGpsAccuracy() {
+ return gpsAccuracy;
+ }
+
+ public void setAltitude(Double altitude) {
+ this.altitude = altitude;
+ }
+
+ public Double getAltitude() {
+ return altitude;
+ }
+
+ public void setSpeed(Double speed) {
+ this.speed = speed;
+ }
+
+ public Double getSpeed() {
+ return speed;
+ }
+
+ public void setHeading(Double heading) {
+ this.heading = heading;
+ }
+
+ public Double getHeading() {
+ return heading;
+ }
+
@Override
public String toString() {
return "SysTaskLog{" +
@@ -147,6 +267,16 @@
", operatorName='" + operatorName + '\'' +
", operationTime=" + operationTime +
", ipAddress='" + ipAddress + '\'' +
+ ", latitude=" + latitude +
+ ", longitude=" + longitude +
+ ", locationAddress='" + locationAddress + '\'' +
+ ", locationProvince='" + locationProvince + '\'' +
+ ", locationCity='" + locationCity + '\'' +
+ ", locationDistrict='" + locationDistrict + '\'' +
+ ", gpsAccuracy=" + gpsAccuracy +
+ ", altitude=" + altitude +
+ ", speed=" + speed +
+ ", heading=" + heading +
'}';
}
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskWelfare.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskWelfare.java
new file mode 100644
index 0000000..67740b3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskWelfare.java
@@ -0,0 +1,225 @@
+package com.ruoyi.system.domain;
+
+import java.math.BigDecimal;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 绂忕杞︿换鍔℃墿灞曚俊鎭璞� sys_task_welfare
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+public class SysTaskWelfare extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 涓婚敭ID */
+ private Long id;
+
+ /** 浠诲姟ID */
+ private Long taskId;
+
+ /** 涔樺鑱旂郴浜� */
+ private String passengerContact;
+
+ /** 涔樺鑱旂郴鐢佃瘽 */
+ private String passengerPhone;
+
+ /** 涔樺濮撳悕 */
+ private String passengerName;
+
+ /** 涔樺骞撮緞 */
+ private Integer passengerAge;
+
+ /** 涔樺鎬у埆 */
+ private String passengerGender;
+
+ /** 涔樺韬唤璇佸彿 */
+ private String passengerIdCard;
+
+ /** 鐗规畩闇�姹傛弿杩� */
+ private String specialNeeds;
+
+ /** 鏈嶅姟绫诲瀷 */
+ private String serviceType;
+
+ /** 鎺ラ�佸湴鍧� */
+ private String pickupAddress;
+
+ /** 鎺ラ�佸湴鍧�缁忓害 */
+ private BigDecimal pickupLongitude;
+
+ /** 鎺ラ�佸湴鍧�绾害 */
+ private BigDecimal pickupLatitude;
+
+ /** 鐩殑鍦板潃 */
+ private String destinationAddress;
+
+ /** 鐩殑鍦板潃缁忓害 */
+ private BigDecimal destinationLongitude;
+
+ /** 鐩殑鍦板潃绾害 */
+ private BigDecimal destinationLatitude;
+
+ /** 鏈嶅姟鍏噷鏁� */
+ private BigDecimal serviceDistance;
+
+ /** 鏈嶅姟璐圭敤 */
+ private BigDecimal servicePrice;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getTaskId() {
+ return taskId;
+ }
+
+ public void setTaskId(Long taskId) {
+ this.taskId = taskId;
+ }
+
+ public String getPassengerContact() {
+ return passengerContact;
+ }
+
+ public void setPassengerContact(String passengerContact) {
+ this.passengerContact = passengerContact;
+ }
+
+ public String getPassengerPhone() {
+ return passengerPhone;
+ }
+
+ public void setPassengerPhone(String passengerPhone) {
+ this.passengerPhone = passengerPhone;
+ }
+
+ public String getPassengerName() {
+ return passengerName;
+ }
+
+ public void setPassengerName(String passengerName) {
+ this.passengerName = passengerName;
+ }
+
+ public Integer getPassengerAge() {
+ return passengerAge;
+ }
+
+ public void setPassengerAge(Integer passengerAge) {
+ this.passengerAge = passengerAge;
+ }
+
+ public String getPassengerGender() {
+ return passengerGender;
+ }
+
+ public void setPassengerGender(String passengerGender) {
+ this.passengerGender = passengerGender;
+ }
+
+ public String getPassengerIdCard() {
+ return passengerIdCard;
+ }
+
+ public void setPassengerIdCard(String passengerIdCard) {
+ this.passengerIdCard = passengerIdCard;
+ }
+
+ public String getSpecialNeeds() {
+ return specialNeeds;
+ }
+
+ public void setSpecialNeeds(String specialNeeds) {
+ this.specialNeeds = specialNeeds;
+ }
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getPickupAddress() {
+ return pickupAddress;
+ }
+
+ public void setPickupAddress(String pickupAddress) {
+ this.pickupAddress = pickupAddress;
+ }
+
+ public BigDecimal getPickupLongitude() {
+ return pickupLongitude;
+ }
+
+ public void setPickupLongitude(BigDecimal pickupLongitude) {
+ this.pickupLongitude = pickupLongitude;
+ }
+
+ public BigDecimal getPickupLatitude() {
+ return pickupLatitude;
+ }
+
+ public void setPickupLatitude(BigDecimal pickupLatitude) {
+ this.pickupLatitude = pickupLatitude;
+ }
+
+ public String getDestinationAddress() {
+ return destinationAddress;
+ }
+
+ public void setDestinationAddress(String destinationAddress) {
+ this.destinationAddress = destinationAddress;
+ }
+
+ public BigDecimal getDestinationLongitude() {
+ return destinationLongitude;
+ }
+
+ public void setDestinationLongitude(BigDecimal destinationLongitude) {
+ this.destinationLongitude = destinationLongitude;
+ }
+
+ public BigDecimal getDestinationLatitude() {
+ return destinationLatitude;
+ }
+
+ public void setDestinationLatitude(BigDecimal destinationLatitude) {
+ this.destinationLatitude = destinationLatitude;
+ }
+
+ public BigDecimal getServiceDistance() {
+ return serviceDistance;
+ }
+
+ public void setServiceDistance(BigDecimal serviceDistance) {
+ this.serviceDistance = serviceDistance;
+ }
+
+ public BigDecimal getServicePrice() {
+ return servicePrice;
+ }
+
+ public void setServicePrice(BigDecimal servicePrice) {
+ this.servicePrice = servicePrice;
+ }
+
+ @Override
+ public String toString() {
+ return "SysTaskWelfare{" +
+ "id=" + id +
+ ", taskId=" + taskId +
+ ", passengerName='" + passengerName + '\'' +
+ ", pickupAddress='" + pickupAddress + '\'' +
+ ", destinationAddress='" + destinationAddress + '\'' +
+ ", serviceDistance=" + serviceDistance +
+ ", servicePrice=" + servicePrice +
+ '}';
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
new file mode 100644
index 0000000..49345c1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
@@ -0,0 +1,115 @@
+package com.ruoyi.system.domain;
+
+/**
+ * 鐢ㄦ埛鍚屾DTO瀵硅薄
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+public class UserSyncDTO
+{
+ /** SQL Server涓殑OA鐢ㄦ埛ID */
+ private Integer oaUserId;
+
+ /** 鐢ㄦ埛璐﹀彿 */
+ private String userName;
+
+ /** 鐢ㄦ埛鏄电О */
+ private String nickName;
+
+ /** SQL Server涓殑閮ㄩ棬ID */
+ private Integer departmentId;
+
+ /** 鐢ㄦ埛鎬у埆锛�0=鐢�,1=濂�,2=鏈煡锛� */
+ private String sex;
+
+ /** 鐢ㄦ埛閭 */
+ private String email;
+
+ /** 鎵嬫満鍙风爜 */
+ private String phonenumber;
+
+ public Integer getOaUserId()
+ {
+ return oaUserId;
+ }
+
+ public void setOaUserId(Integer oaUserId)
+ {
+ this.oaUserId = oaUserId;
+ }
+
+ public String getUserName()
+ {
+ return userName;
+ }
+
+ public void setUserName(String userName)
+ {
+ this.userName = userName;
+ }
+
+ public String getNickName()
+ {
+ return nickName;
+ }
+
+ public void setNickName(String nickName)
+ {
+ this.nickName = nickName;
+ }
+
+ public Integer getDepartmentId()
+ {
+ return departmentId;
+ }
+
+ public void setDepartmentId(Integer departmentId)
+ {
+ this.departmentId = departmentId;
+ }
+
+ public String getSex()
+ {
+ return sex;
+ }
+
+ public void setSex(String sex)
+ {
+ this.sex = sex;
+ }
+
+ public String getEmail()
+ {
+ return email;
+ }
+
+ public void setEmail(String email)
+ {
+ this.email = email;
+ }
+
+ public String getPhonenumber()
+ {
+ return phonenumber;
+ }
+
+ public void setPhonenumber(String phonenumber)
+ {
+ this.phonenumber = phonenumber;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "UserSyncDTO{" +
+ "oaUserId=" + oaUserId +
+ ", userName='" + userName + '\'' +
+ ", nickName='" + nickName + '\'' +
+ ", departmentId=" + departmentId +
+ ", sex='" + sex + '\'' +
+ ", email='" + email + '\'' +
+ ", phonenumber='" + phonenumber + '\'' +
+ '}';
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/GeocodeResult.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/GeocodeResult.java
new file mode 100644
index 0000000..96cefc6
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/GeocodeResult.java
@@ -0,0 +1,88 @@
+package com.ruoyi.system.domain.dto;
+
+/**
+ * 鍦扮悊缂栫爜缁撴灉DTO
+ */
+public class GeocodeResult {
+
+ /** 绾害 */
+ private Double latitude;
+
+ /** 缁忓害 */
+ private Double longitude;
+
+ /** 鍦板潃 */
+ private String address;
+
+ /** 鏄惁鎴愬姛 */
+ private Boolean success;
+
+ /** 閿欒娑堟伅 */
+ private String errorMessage;
+
+ public GeocodeResult() {
+ }
+
+ public GeocodeResult(Boolean success, String errorMessage) {
+ this.success = success;
+ this.errorMessage = errorMessage;
+ }
+
+ public GeocodeResult(Double latitude, Double longitude, String address) {
+ this.latitude = latitude;
+ this.longitude = longitude;
+ this.address = address;
+ this.success = true;
+ }
+
+ public Double getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(Double latitude) {
+ this.latitude = latitude;
+ }
+
+ public Double getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(Double longitude) {
+ this.longitude = longitude;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public Boolean getSuccess() {
+ return success;
+ }
+
+ public void setSuccess(Boolean success) {
+ this.success = success;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public String toString() {
+ return "GeocodeResult{" +
+ "latitude=" + latitude +
+ ", longitude=" + longitude +
+ ", address='" + address + '\'' +
+ ", success=" + success +
+ ", errorMessage='" + errorMessage + '\'' +
+ '}';
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java
index 9deb1dd..e16b50d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java
@@ -7,17 +7,26 @@
*/
public enum TaskStatus {
- /** 寰呭紑濮� */
- PENDING("PENDING", "寰呭紑濮�"),
+ /** 寰呭鐞� */
+ PENDING("PENDING", "寰呭鐞�"),
- /** 浠诲姟涓� */
- IN_PROGRESS("IN_PROGRESS", "浠诲姟涓�"),
+ /** 鍑哄彂涓� */
+ DEPARTING("DEPARTING", "鍑哄彂涓�"),
+
+ /** 宸插埌杈� */
+ ARRIVED("ARRIVED", "宸插埌杈�"),
+
+ /** 杩旂▼涓� */
+ RETURNING("RETURNING", "杩旂▼涓�"),
/** 宸插畬鎴� */
COMPLETED("COMPLETED", "宸插畬鎴�"),
/** 宸插彇娑� */
- CANCELLED("CANCELLED", "宸插彇娑�");
+ CANCELLED("CANCELLED", "宸插彇娑�"),
+
+ /** 浠诲姟涓� (鍏煎鏃ф暟鎹�) */
+ IN_PROGRESS("IN_PROGRESS", "浠诲姟涓�");
private final String code;
private final String info;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
index 809b5b7..ca29735 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
@@ -51,8 +51,187 @@
/** 鐩殑鍦扮含搴� */
private BigDecimal destinationLatitude;
+ /** 棰勮鍏噷鏁� */
+ private BigDecimal estimatedDistance;
+
+ /** 杞繍鏃堕棿 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date transferTime;
+
+ /** 鎮h�呬俊鎭� */
+ private PatientInfo patient;
+
+ /** 杞嚭鍖婚櫌淇℃伅 */
+ private HospitalInfo hospitalOut;
+
+ /** 杞叆鍖婚櫌淇℃伅 */
+ private HospitalInfo hospitalIn;
+
+ /** 杞繍鍏噷鏁� */
+ private BigDecimal transferDistance;
+
+ /** 鎴愪氦浠� */
+ private BigDecimal price;
+
+ /** 鏈嶅姟鏃堕棿 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date serviceTime;
+
+ /** 涔樺淇℃伅 */
+ private PassengerInfo passenger;
+
+ /** 璧峰鍦板潃 */
+ private String startAddress;
+
+ /** 缁撴潫鍦板潃 */
+ private String endAddress;
+
+ /** 绂忕杞﹀叕閲屾暟 */
+ private BigDecimal distance;
+
/** 杞﹁締ID鍒楄〃 */
private List<Long> vehicleIds;
+
+ // 鎮h�呬俊鎭唴閮ㄧ被
+ public static class PatientInfo {
+ private String contact;
+ private String phone;
+ private String name;
+ private String gender;
+ private String idCard;
+ private String condition;
+
+ // getters and setters
+ public String getContact() {
+ return contact;
+ }
+
+ public void setContact(String contact) {
+ this.contact = contact;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getGender() {
+ return gender;
+ }
+
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+
+ public String getIdCard() {
+ return idCard;
+ }
+
+ public void setIdCard(String idCard) {
+ this.idCard = idCard;
+ }
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public void setCondition(String condition) {
+ this.condition = condition;
+ }
+ }
+
+ // 鍖婚櫌淇℃伅鍐呴儴绫�
+ public static class HospitalInfo {
+ private String name;
+ private String department;
+ private String bedNumber;
+ private String address;
+ private BigDecimal longitude;
+ private BigDecimal latitude;
+
+ // getters and setters
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(String department) {
+ this.department = department;
+ }
+
+ public String getBedNumber() {
+ return bedNumber;
+ }
+
+ public void setBedNumber(String bedNumber) {
+ this.bedNumber = bedNumber;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public BigDecimal getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(BigDecimal longitude) {
+ this.longitude = longitude;
+ }
+
+ public BigDecimal getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(BigDecimal latitude) {
+ this.latitude = latitude;
+ }
+ }
+
+ // 涔樺淇℃伅鍐呴儴绫�
+ public static class PassengerInfo {
+ private String contact;
+ private String phone;
+
+ // getters and setters
+ public String getContact() {
+ return contact;
+ }
+
+ public void setContact(String contact) {
+ this.contact = contact;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+ }
public String getTaskType() {
return taskType;
@@ -150,6 +329,94 @@
this.destinationLatitude = destinationLatitude;
}
+ public BigDecimal getEstimatedDistance() {
+ return estimatedDistance;
+ }
+
+ public void setEstimatedDistance(BigDecimal estimatedDistance) {
+ this.estimatedDistance = estimatedDistance;
+ }
+
+ public Date getTransferTime() {
+ return transferTime;
+ }
+
+ public void setTransferTime(Date transferTime) {
+ this.transferTime = transferTime;
+ }
+
+ public PatientInfo getPatient() {
+ return patient;
+ }
+
+ public void setPatient(PatientInfo patient) {
+ this.patient = patient;
+ }
+
+ public HospitalInfo getHospitalOut() {
+ return hospitalOut;
+ }
+
+ public void setHospitalOut(HospitalInfo hospitalOut) {
+ this.hospitalOut = hospitalOut;
+ }
+
+ public HospitalInfo getHospitalIn() {
+ return hospitalIn;
+ }
+
+ public void setHospitalIn(HospitalInfo hospitalIn) {
+ this.hospitalIn = hospitalIn;
+ }
+
+ public BigDecimal getTransferDistance() {
+ return transferDistance;
+ }
+
+ public void setTransferDistance(BigDecimal transferDistance) {
+ this.transferDistance = transferDistance;
+ }
+
+ public BigDecimal getPrice() {
+ return price;
+ }
+
+ public void setPrice(BigDecimal price) {
+ this.price = price;
+ }
+
+ public Date getServiceTime() {
+ return serviceTime;
+ }
+
+ public void setServiceTime(Date serviceTime) {
+ this.serviceTime = serviceTime;
+ }
+
+ public PassengerInfo getPassenger() {
+ return passenger;
+ }
+
+ public void setPassenger(PassengerInfo passenger) {
+ this.passenger = passenger;
+ }
+
+ public String getStartAddress() {
+ return startAddress;
+ }
+
+ public void setStartAddress(String startAddress) {
+ this.startAddress = startAddress;
+ }
+
+ public String getEndAddress() {
+ return endAddress;
+ }
+
+ public void setEndAddress(String endAddress) {
+ this.endAddress = endAddress;
+ }
+
public List<Long> getVehicleIds() {
return vehicleIds;
}
@@ -157,4 +424,12 @@
public void setVehicleIds(List<Long> vehicleIds) {
this.vehicleIds = vehicleIds;
}
-}
+
+ public BigDecimal getDistance() {
+ return distance;
+ }
+
+ public void setDistance(BigDecimal distance) {
+ this.distance = distance;
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java
new file mode 100644
index 0000000..e8b3e01
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java
@@ -0,0 +1,32 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬鍚屾Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@DataSource(DataSourceType.SQLSERVER)
+public interface DepartmentSyncMapper
+{
+ /**
+ * 鏌ヨ鍚堜綔鍗曚綅涓嬬殑鎵�鏈夊垎鍏徃
+ *
+ * @return 鍒嗗叕鍙稿垪琛�
+ */
+ List<DepartmentSyncDTO> selectBranchDepartments();
+
+ /**
+ * 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+ List<DepartmentSyncDTO> selectTransportDepartments();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/HospDataMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/HospDataMapper.java
new file mode 100644
index 0000000..397a771
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/HospDataMapper.java
@@ -0,0 +1,34 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.system.domain.HospData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 鍖婚櫌鏁版嵁Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+@DataSource(DataSourceType.SQLSERVER)
+public interface HospDataMapper {
+
+ /**
+ * 鏍规嵁鍖婚櫌鍚嶇О鎴栧湴鍧�鎼滅储鍖婚櫌
+ *
+ * @param keyword 鎼滅储鍏抽敭璇�
+ * @return 鍖婚櫌鍒楄〃
+ */
+ List<HospData> searchHospitals(@Param("keyword") String keyword);
+
+ /**
+ * 鏍规嵁鍖婚櫌ID鏌ヨ鍖婚櫌淇℃伅
+ *
+ * @param hospId 鍖婚櫌ID
+ * @return 鍖婚櫌淇℃伅
+ */
+ HospData selectHospDataById(@Param("hospId") Integer hospId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/Icd10Mapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/Icd10Mapper.java
new file mode 100644
index 0000000..a6d1c25
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/Icd10Mapper.java
@@ -0,0 +1,34 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.system.domain.Icd10;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * ICD-10鐤剧梾鍒嗙被Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+@DataSource(DataSourceType.SQLSERVER)
+public interface Icd10Mapper {
+
+ /**
+ * 鏍规嵁鐤剧梾鍚嶇О鎴栫紪鐮佹悳绱CD-10
+ *
+ * @param keyword 鎼滅储鍏抽敭璇�
+ * @return ICD-10鍒楄〃
+ */
+ List<Icd10> searchIcd10(@Param("keyword") String keyword);
+
+ /**
+ * 鏍规嵁ID鏌ヨICD-10淇℃伅
+ *
+ * @param id ICD-10 ID
+ * @return ICD-10淇℃伅
+ */
+ Icd10 selectIcd10ById(@Param("id") Integer id);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
index 384a9b6..17221c5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
@@ -115,4 +115,21 @@
* @return 缁撴灉
*/
public int deleteDeptById(Long deptId);
+
+ /**
+ * 鏍规嵁departmentId鏌ヨ閮ㄩ棬
+ *
+ * @param departmentId SQL Server涓殑閮ㄩ棬ID
+ * @return 閮ㄩ棬淇℃伅
+ */
+ public SysDept selectDeptByDepartmentId(@Param("departmentId") Integer departmentId);
+
+ /**
+ * 鏍规嵁departmentId鍜岀埗閮ㄩ棬ID鏌ヨ閮ㄩ棬
+ *
+ * @param departmentId SQL Server涓殑閮ㄩ棬ID
+ * @param parentId 鐖堕儴闂↖D
+ * @return 閮ㄩ棬淇℃伅
+ */
+ public SysDept selectDeptByDepartmentIdAndParentId(@Param("departmentId") Integer departmentId, @Param("parentId") Long parentId);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java
new file mode 100644
index 0000000..da5919a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java
@@ -0,0 +1,60 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.system.domain.SysTaskEmergency;
+
+/**
+ * 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+public interface SysTaskEmergencyMapper {
+
+ /**
+ * 鏌ヨ鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param id 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅涓婚敭
+ * @return 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ */
+ public SysTaskEmergency selectSysTaskEmergencyById(Long id);
+
+ /**
+ * 閫氳繃浠诲姟ID鏌ヨ鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param taskId 浠诲姟ID
+ * @return 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ */
+ public SysTaskEmergency selectSysTaskEmergencyByTaskId(Long taskId);
+
+ /**
+ * 鏂板鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param sysTaskEmergency 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ * @return 缁撴灉
+ */
+ public int insertSysTaskEmergency(SysTaskEmergency sysTaskEmergency);
+
+ /**
+ * 淇敼鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param sysTaskEmergency 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ * @return 缁撴灉
+ */
+ public int updateSysTaskEmergency(SysTaskEmergency sysTaskEmergency);
+
+ /**
+ * 鍒犻櫎鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param id 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅涓婚敭
+ * @return 缁撴灉
+ */
+ public int deleteSysTaskEmergencyById(Long id);
+
+ /**
+ * 閫氳繃浠诲姟ID鍒犻櫎鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param taskId 浠诲姟ID
+ * @return 缁撴灉
+ */
+ public int deleteSysTaskEmergencyByTaskId(Long taskId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskWelfareMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskWelfareMapper.java
new file mode 100644
index 0000000..39f7145
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskWelfareMapper.java
@@ -0,0 +1,60 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.system.domain.SysTaskWelfare;
+
+/**
+ * 绂忕杞︿换鍔℃墿灞曚俊鎭疢apper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2024-01-16
+ */
+public interface SysTaskWelfareMapper {
+
+ /**
+ * 鏌ヨ绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param id 绂忕杞︿换鍔℃墿灞曚俊鎭富閿�
+ * @return 绂忕杞︿换鍔℃墿灞曚俊鎭�
+ */
+ public SysTaskWelfare selectSysTaskWelfareById(Long id);
+
+ /**
+ * 閫氳繃浠诲姟ID鏌ヨ绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param taskId 浠诲姟ID
+ * @return 绂忕杞︿换鍔℃墿灞曚俊鎭�
+ */
+ public SysTaskWelfare selectSysTaskWelfareByTaskId(Long taskId);
+
+ /**
+ * 鏂板绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param sysTaskWelfare 绂忕杞︿换鍔℃墿灞曚俊鎭�
+ * @return 缁撴灉
+ */
+ public int insertSysTaskWelfare(SysTaskWelfare sysTaskWelfare);
+
+ /**
+ * 淇敼绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param sysTaskWelfare 绂忕杞︿换鍔℃墿灞曚俊鎭�
+ * @return 缁撴灉
+ */
+ public int updateSysTaskWelfare(SysTaskWelfare sysTaskWelfare);
+
+ /**
+ * 鍒犻櫎绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param id 绂忕杞︿换鍔℃墿灞曚俊鎭富閿�
+ * @return 缁撴灉
+ */
+ public int deleteSysTaskWelfareById(Long id);
+
+ /**
+ * 閫氳繃浠诲姟ID鍒犻櫎绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param taskId 浠诲姟ID
+ * @return 缁撴灉
+ */
+ public int deleteSysTaskWelfareByTaskId(Long taskId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
index 76e1c79..6f7e525 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -124,4 +124,12 @@
* @return 缁撴灉
*/
public SysUser checkEmailUnique(String email);
+
+ /**
+ * 鏍规嵁oaUserId鏌ヨ鐢ㄦ埛
+ *
+ * @param oaUserId SQL Server涓殑OA鐢ㄦ埛ID
+ * @return 鐢ㄦ埛淇℃伅
+ */
+ public SysUser selectUserByOaUserId(@Param("oaUserId") Integer oaUserId);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserSyncMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserSyncMapper.java
new file mode 100644
index 0000000..5dcb726
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserSyncMapper.java
@@ -0,0 +1,23 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.system.domain.UserSyncDTO;
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛鍚屾Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@DataSource(DataSourceType.SQLSERVER)
+public interface UserSyncMapper
+{
+ /**
+ * 鏌ヨSQL Server涓殑OA鐢ㄦ埛鍒楄〃
+ *
+ * @return 鐢ㄦ埛鍒楄〃
+ */
+ List<UserSyncDTO> selectOaUsers();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
index f688808..9d04bbf 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.mapper;
import java.util.List;
+import org.apache.ibatis.annotations.Param;
import com.ruoyi.system.domain.VehicleInfo;
/**
@@ -62,4 +63,39 @@
* @return 缁撴灉
*/
public int deleteVehicleInfoByIds(Long[] vehicleIds);
+
+ /**
+ * 缁戝畾杞﹁締鍒扮敤鎴�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param vehicleId 杞﹁締ID
+ * @param bindBy 缁戝畾鎿嶄綔浜�
+ * @return 缁撴灉
+ */
+ public int bindVehicleToUser(@Param("userId") Long userId, @Param("vehicleId") Long vehicleId, @Param("bindBy") String bindBy);
+
+ /**
+ * 瑙g粦鐢ㄦ埛杞﹁締
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param vehicleId 杞﹁締ID
+ * @return 缁撴灉
+ */
+ public int unbindVehicleFromUser(@Param("userId") Long userId, @Param("vehicleId") Long vehicleId);
+
+ /**
+ * 瑙g粦鐢ㄦ埛鐨勬墍鏈夎溅杈�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 缁撴灉
+ */
+ public int unbindAllVehiclesFromUser(@Param("userId") Long userId);
+
+ /**
+ * 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 杞﹁締淇℃伅
+ */
+ public VehicleInfo getUserBoundVehicle(@Param("userId") Long userId);
}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java
new file mode 100644
index 0000000..c131d29
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java
@@ -0,0 +1,34 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import java.util.List;
+
+/**
+ * SQL Server 閮ㄩ棬鏁版嵁鏌ヨ鏈嶅姟鎺ュ彛
+ *
+ * 鑱岃矗锛氫笓闂ㄨ礋璐d粠 SQL Server 鏌ヨ閮ㄩ棬鏁版嵁
+ * 涓嶆秹鍙婁换浣� MySQL 鏁版嵁搴撴搷浣�
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+public interface IDepartmentSyncDataService
+{
+ /**
+ * 浠� SQL Server 鏌ヨ鍚堜綔鍗曚綅涓嬬殑鎵�鏈夊垎鍏徃鏁版嵁
+ *
+ * 鏁版嵁婧愶細SQL Server (uv_department 瑙嗗浘)
+ *
+ * @return 鍒嗗叕鍙稿垪琛�
+ */
+ List<DepartmentSyncDTO> getBranchDepartments();
+
+ /**
+ * 浠� SQL Server 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬鏁版嵁
+ *
+ * 鏁版嵁婧愶細SQL Server (uv_department 瑙嗗浘)
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+ List<DepartmentSyncDTO> getTransportDepartments();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java
new file mode 100644
index 0000000..ed762b3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java
@@ -0,0 +1,42 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import java.util.List;
+
+/**
+ * 閮ㄩ棬鍚屾Service鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+public interface IDepartmentSyncService
+{
+
+
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * 姝ゆ柟娉曟帴鏀跺閮ㄥ凡缁忔煡璇㈠ソ鐨勬暟鎹紝鍙礋璐e啓鍏� MySQL 鏁版嵁搴�
+ * 閫傜敤鍦烘櫙锛�
+ * 1. 鏁版嵁宸蹭粠鍏朵粬鏉ユ簮鑾峰彇
+ * 2. 闇�瑕佸鏁版嵁杩涜棰勫鐞嗗悗鍐嶅悓姝�
+ * 3. 鎵归噺鍚屾澶氫釜鏁版嵁婧�
+ *
+ * @param branchDepts 澶栭儴浼犲叆鐨勫垎鍏徃鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+ AjaxResult syncBranchDepartments(List<DepartmentSyncDTO> branchDepts);
+
+ /**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * 鍚屾閫昏緫锛�
+ * 1. 纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ * 2. 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂紙鐩存帴鍒涘缓锛屾棤闇�瑙f瀽"--"鏍煎紡锛�
+ *
+ * @param transportDepts 澶栭儴浼犲叆鐨勮浆杩愰儴瀛愰儴闂ㄦ暟鎹垪琛�
+ * @return 鍚屾缁撴灉
+ */
+ AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IGeocodeService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IGeocodeService.java
new file mode 100644
index 0000000..eaaf3f6
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IGeocodeService.java
@@ -0,0 +1,26 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.system.domain.dto.GeocodeResult;
+
+/**
+ * 鍦扮悊缂栫爜鏈嶅姟鎺ュ彛
+ */
+public interface IGeocodeService {
+
+ /**
+ * 鏍规嵁鍦板潃鑾峰彇GPS鍧愭爣锛堝湴鐞嗙紪鐮侊級
+ *
+ * @param address 鍦板潃瀛楃涓�
+ * @return 鍦扮悊缂栫爜缁撴灉锛屽寘鍚粡绾害
+ */
+ GeocodeResult getCoordinatesByAddress(String address);
+
+ /**
+ * 鏍规嵁鍦板潃鑾峰彇GPS鍧愭爣锛堝湴鐞嗙紪鐮侊級锛屾敮鎸佹寚瀹氬煄甯�
+ *
+ * @param address 鍦板潃瀛楃涓�
+ * @param city 鍩庡競鍚嶇О锛岀敤浜庢彁楂樿В鏋愬噯纭害
+ * @return 鍦扮悊缂栫爜缁撴灉锛屽寘鍚粡绾害
+ */
+ GeocodeResult getCoordinatesByAddress(String address, String city);
+}
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 c56fa71..362d630 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
@@ -3,6 +3,7 @@
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.SysTaskLog;
import com.ruoyi.system.domain.SysTaskVehicle;
import com.ruoyi.system.domain.SysTaskAttachment;
import com.ruoyi.system.domain.vo.TaskQueryVO;
@@ -80,6 +81,17 @@
public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark);
/**
+ * 鍙樻洿浠诲姟鐘舵�侊紙鍚獹PS浣嶇疆淇℃伅锛�
+ *
+ * @param taskId 浠诲姟ID
+ * @param newStatus 鏂扮姸鎬�
+ * @param remark 澶囨敞
+ * @param locationLog GPS浣嶇疆淇℃伅鏃ュ織瀵硅薄
+ * @return 缁撴灉
+ */
+ public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog);
+
+ /**
* 涓婁紶浠诲姟闄勪欢
*
* @param taskId 浠诲姟ID
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncDataService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncDataService.java
new file mode 100644
index 0000000..a346e49
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncDataService.java
@@ -0,0 +1,25 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.system.domain.UserSyncDTO;
+import java.util.List;
+
+/**
+ * SQL Server 鐢ㄦ埛鏁版嵁鏌ヨ鏈嶅姟鎺ュ彛
+ *
+ * 鑱岃矗锛氫笓闂ㄨ礋璐d粠 SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁
+ * 涓嶆秹鍙婁换浣� MySQL 鏁版嵁搴撴搷浣�
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+public interface IUserSyncDataService
+{
+ /**
+ * 浠� SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁
+ *
+ * 鏁版嵁婧愶細SQL Server (OA_User 琛�)
+ *
+ * @return OA 鐢ㄦ埛鍒楄〃
+ */
+ List<UserSyncDTO> getOaUsers();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncService.java
new file mode 100644
index 0000000..5ad2113
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncService.java
@@ -0,0 +1,30 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.UserSyncDTO;
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛鍚屾Service鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+public interface IUserSyncService
+{
+
+
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * 姝ゆ柟娉曟帴鏀跺閮ㄥ凡缁忔煡璇㈠ソ鐨勬暟鎹紝鍙礋璐e啓鍏� MySQL 鏁版嵁搴�
+ * 閫傜敤鍦烘櫙锛�
+ * 1. 鏁版嵁宸蹭粠鍏朵粬鏉ユ簮鑾峰彇
+ * 2. 闇�瑕佸鏁版嵁杩涜棰勫鐞嗗悗鍐嶅悓姝�
+ * 3. 鎵归噺鍚屾澶氫釜鏁版嵁婧�
+ *
+ * @param oaUsers 澶栭儴浼犲叆鐨凮A鐢ㄦ埛鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+ AjaxResult syncOaUsers(List<UserSyncDTO> oaUsers);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java
index 49da046..cfcbd68 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java
@@ -62,4 +62,30 @@
* @return 缁撴灉
*/
public int deleteVehicleInfoById(Long vehicleId);
+
+ /**
+ * 缁戝畾杞﹁締鍒扮敤鎴�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param vehicleId 杞﹁締ID
+ * @return 缁撴灉
+ */
+ public int bindVehicleToUser(Long userId, Long vehicleId);
+
+ /**
+ * 瑙g粦鐢ㄦ埛杞﹁締
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param vehicleId 杞﹁締ID
+ * @return 缁撴灉
+ */
+ public int unbindVehicleFromUser(Long userId, Long vehicleId);
+
+ /**
+ * 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 杞﹁締淇℃伅
+ */
+ public VehicleInfo getUserBoundVehicle(Long userId);
}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java
new file mode 100644
index 0000000..79ab877
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java
@@ -0,0 +1,103 @@
+package com.ruoyi.system.service.impl;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.mapper.DepartmentSyncMapper;
+import com.ruoyi.system.service.IDepartmentSyncDataService;
+
+import java.util.List;
+
+/**
+ * SQL Server 閮ㄩ棬鏁版嵁鏌ヨ鏈嶅姟瀹炵幇
+ *
+ * 鑱岃矗锛氫笓闂ㄨ礋璐d粠 SQL Server 鏌ヨ閮ㄩ棬鏁版嵁
+ *
+ * 鏁版嵁娴佸悜锛歋QL Server 鈫� 杩斿洖 DTO 鍒楄〃
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Service
+@DataSource(DataSourceType.SQLSERVER)
+public class DepartmentSyncDataServiceImpl implements IDepartmentSyncDataService
+{
+ private static final Logger log = LoggerFactory.getLogger(DepartmentSyncDataServiceImpl.class);
+
+ @Autowired
+ private DepartmentSyncMapper departmentSyncMapper;
+
+ /**
+ * 浠� SQL Server 鏌ヨ鍚堜綔鍗曚綅涓嬬殑鎵�鏈夊垎鍏徃鏁版嵁
+ *
+ * 娉ㄦ剰锛欴epartmentSyncMapper 涓婃湁 @DataSource(DataSourceType.SQLSERVER) 娉ㄨВ
+ * 姝ゆ柟娉曚細鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧愭墽琛屾煡璇�
+ *
+ * @return 鍒嗗叕鍙稿垪琛�
+ */
+ @Override
+ public List<DepartmentSyncDTO> getBranchDepartments()
+ {
+ try
+ {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ鍒嗗叕鍙告暟鎹�...");
+
+ // 璋冪敤 Mapper 鏌ヨ SQL Server 鏁版嵁
+ // @DataSource 娉ㄨВ浼氳嚜鍔ㄥ垏鎹㈡暟鎹簮
+ List<DepartmentSyncDTO> branchDepts = departmentSyncMapper.selectBranchDepartments();
+
+ if (branchDepts == null || branchDepts.isEmpty())
+ {
+ log.warn("鏈粠 SQL Server 鏌ヨ鍒板垎鍏徃鏁版嵁");
+ return branchDepts;
+ }
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉″垎鍏徃鏁版嵁", branchDepts.size());
+ return branchDepts;
+ }
+ catch (Exception e)
+ {
+ log.error("浠� SQL Server 鏌ヨ鍒嗗叕鍙告暟鎹け璐�", e);
+ throw new RuntimeException("鏌ヨ SQL Server 鏁版嵁澶辫触: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 浠� SQL Server 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬鏁版嵁
+ *
+ * 娉ㄦ剰锛欴epartmentSyncMapper 涓婃湁 @DataSource(DataSourceType.SQLSERVER) 娉ㄨВ
+ * 姝ゆ柟娉曚細鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧愭墽琛屾煡璇�
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+ @Override
+ public List<DepartmentSyncDTO> getTransportDepartments()
+ {
+ try
+ {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁...");
+
+ // 璋冪敤 Mapper 鏌ヨ SQL Server 鏁版嵁
+ // @DataSource 娉ㄨВ浼氳嚜鍔ㄥ垏鎹㈡暟鎹簮
+ List<DepartmentSyncDTO> transportDepts = departmentSyncMapper.selectTransportDepartments();
+
+ if (transportDepts == null || transportDepts.isEmpty())
+ {
+ log.warn("鏈粠 SQL Server 鏌ヨ鍒拌浆杩愰儴瀛愰儴闂ㄦ暟鎹�");
+ return transportDepts;
+ }
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹�", transportDepts.size());
+ return transportDepts;
+ }
+ catch (Exception e)
+ {
+ log.error("浠� SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁澶辫触", e);
+ throw new RuntimeException("鏌ヨ SQL Server 鏁版嵁澶辫触: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java
new file mode 100644
index 0000000..30d4f18
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java
@@ -0,0 +1,330 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.mapper.SysDeptMapper;
+import com.ruoyi.system.service.IDepartmentSyncService;
+import com.ruoyi.system.service.IDepartmentSyncDataService;
+
+/**
+ * 閮ㄩ棬鍚屾Service涓氬姟灞傚鐞�
+ *
+ * 鑱岃矗锛氭帴鏀堕儴闂ㄦ暟鎹紝鍐欏叆 MySQL 鏁版嵁搴�
+ * 鏁版嵁鏉ユ簮锛�
+ * 1. 鍐呴儴鏌ヨ锛氳皟鐢� IDepartmentSyncDataService 浠� SQL Server 鏌ヨ
+ * 2. 澶栭儴浼犲叆锛氭帴鏀跺凡鏌ヨ濂界殑鏁版嵁
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Service
+public class DepartmentSyncServiceImpl implements IDepartmentSyncService
+{
+ private static final Logger log = LoggerFactory.getLogger(DepartmentSyncServiceImpl.class);
+
+
+
+ @Autowired
+ private SysDeptMapper sysDeptMapper;
+
+
+
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * 鎵ц娴佺▼锛�
+ * 1. 鎺ユ敹澶栭儴浼犲叆鐨� DepartmentSyncDTO 鍒楄〃
+ * 2. 鍐欏叆 MySQL 鏁版嵁搴擄紙sysDeptMapper 浣跨敤榛樿 MySQL 鏁版嵁婧愶級
+ *
+ * @param branchDepts 澶栭儴浼犲叆鐨勫垎鍏徃鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+ @Override
+ @Transactional
+ public AjaxResult syncBranchDepartments(List<DepartmentSyncDTO> branchDepts)
+ {
+ try
+ {
+ if (branchDepts == null || branchDepts.isEmpty())
+ {
+ return AjaxResult.warn("浼犲叆鐨勯儴闂ㄦ暟鎹负绌�");
+ }
+
+ log.info("寮�濮嬪悓姝� {} 鏉″垎鍏徃鏁版嵁鍒� MySQL 鏁版嵁搴�...", branchDepts.size());
+
+ // 浣跨敤Map鏉ヨ窡韪凡鍒涘缓鐨勫垎鍏徃锛宬ey涓哄垎鍏徃鍚嶇О锛寁alue涓洪儴闂↖D
+ Map<String, Long> branchMap = new HashMap<>();
+ int createdBranch = 0;
+ int updatedBranch = 0;
+ int createdDept = 0;
+ int updatedDept = 0;
+
+ // 澶勭悊姣忎竴鏉″垎鍏徃鏁版嵁
+ for (DepartmentSyncDTO dto : branchDepts)
+ {
+ String fullName = dto.getDepartmentName();
+ if (StringUtils.isEmpty(fullName))
+ {
+ continue;
+ }
+
+ // 瑙f瀽閮ㄩ棬鍚嶇О锛氭箾姹�--鎶ゅ+ -> 鍒嗗叕鍙革細婀涙睙鍒嗗叕鍙革紝閮ㄩ棬锛氭姢澹�
+ String[] parts = fullName.split("--");
+ if (parts.length != 2)
+ {
+ log.warn("閮ㄩ棬鍚嶇О鏍煎紡涓嶆纭紝璺宠繃: {}", fullName);
+ continue;
+ }
+
+ String branchName = parts[0].trim() + "鍒嗗叕鍙�"; // 婀涙睙 -> 婀涙睙鍒嗗叕鍙�
+ String deptName = parts[1].trim(); // 鎶ゅ+
+
+ // 鑾峰彇鎴栧垱寤哄垎鍏徃
+ Long branchDeptId = branchMap.get(branchName);
+ if (branchDeptId == null)
+ {
+ // 妫�鏌ュ垎鍏徃鏄惁宸插瓨鍦紙閫氳繃閮ㄩ棬鍚嶇О鍜宲arent_id=100鏉ユ煡璇級
+ SysDept existingBranch = sysDeptMapper.checkDeptNameUnique(branchName, 100L);
+ if (existingBranch != null)
+ {
+ // 鍒嗗叕鍙稿凡瀛樺湪锛屾洿鏂癲epartment_id
+ branchDeptId = existingBranch.getDeptId();
+ branchMap.put(branchName, branchDeptId);
+ log.info("鍒嗗叕鍙稿凡瀛樺湪: {}, ID: {}", branchName, branchDeptId);
+ }
+ else
+ {
+ // 鍒涘缓鏂扮殑鍒嗗叕鍙�
+ SysDept newBranch = new SysDept();
+ newBranch.setParentId(100L); // 鐖惰妭鐐逛负鑻ヤ緷绉戞妧锛堥粯璁�100锛�
+ newBranch.setDeptName(branchName);
+ newBranch.setAncestors("0,100"); // 绁栫骇鍒楄〃
+ newBranch.setOrderNum(branchMap.size() + 1); // 鎺掑簭
+ newBranch.setStatus("0"); // 姝e父鐘舵��
+ newBranch.setCreateBy("sync");
+
+ sysDeptMapper.insertDept(newBranch);
+ branchDeptId = newBranch.getDeptId();
+ branchMap.put(branchName, branchDeptId);
+ createdBranch++;
+ log.info("鍒涘缓鏂板垎鍏徃: {}, ID: {}", branchName, branchDeptId);
+ }
+ }
+
+ // 鍒涘缓鎴栨洿鏂板瓙閮ㄩ棬
+ // 鍏堟牴鎹甦epartmentId鏌ヨ鏄惁宸插瓨鍦�
+ SysDept existingDept = sysDeptMapper.selectDeptByDepartmentIdAndParentId(
+ dto.getDepartmentId(), branchDeptId);
+
+ if (existingDept != null)
+ {
+ // 閮ㄩ棬宸插瓨鍦紝鏇存柊淇℃伅
+ existingDept.setDeptName(deptName);
+ existingDept.setUpdateBy("sync");
+ sysDeptMapper.updateDept(existingDept);
+ updatedDept++;
+ log.info("鏇存柊閮ㄩ棬: {} -> {}", branchName, deptName);
+ }
+ else
+ {
+ // 妫�鏌ユ槸鍚﹀瓨鍦ㄥ悓鍚嶉儴闂紙鍙兘涔嬪墠鎵嬪姩鍒涘缓鐨勶級
+ SysDept sameName = sysDeptMapper.checkDeptNameUnique(deptName, branchDeptId);
+ if (sameName != null)
+ {
+ // 鍚屽悕閮ㄩ棬宸插瓨鍦紝鏇存柊鍏禿epartment_id
+ sameName.setDepartmentId(dto.getDepartmentId());
+ sameName.setUpdateBy("sync");
+ sysDeptMapper.updateDept(sameName);
+ updatedDept++;
+ log.info("鏇存柊宸插瓨鍦ㄧ殑鍚屽悕閮ㄩ棬: {} -> {}, departmentId: {}",
+ branchName, deptName, dto.getDepartmentId());
+ }
+ else
+ {
+ // 鍒涘缓鏂伴儴闂�
+ SysDept newDept = new SysDept();
+ newDept.setParentId(branchDeptId);
+ newDept.setDeptName(deptName);
+ newDept.setAncestors("0,100," + branchDeptId); // 绁栫骇鍒楄〃
+ newDept.setOrderNum(1); // 鎺掑簭
+ newDept.setStatus("0"); // 姝e父鐘舵��
+ newDept.setDepartmentId(dto.getDepartmentId()); // 璁板綍SQL Server涓殑閮ㄩ棬ID
+ newDept.setCreateBy("sync");
+
+ sysDeptMapper.insertDept(newDept);
+ createdDept++;
+ log.info("鍒涘缓鏂伴儴闂�: {} -> {}, departmentId: {}",
+ branchName, deptName, dto.getDepartmentId());
+ }
+ }
+ }
+
+ String message = String.format("鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: %d, 鏇存柊鍒嗗叕鍙�: %d, 鍒涘缓閮ㄩ棬: %d, 鏇存柊閮ㄩ棬: %d",
+ createdBranch, updatedBranch, createdDept, updatedDept);
+ log.info(message);
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("createdBranch", createdBranch);
+ result.put("updatedBranch", updatedBranch);
+ result.put("createdDept", createdDept);
+ result.put("updatedDept", updatedDept);
+ result.put("totalProcessed", branchDepts.size());
+
+ return AjaxResult.success(message, result);
+ }
+ catch (Exception e)
+ {
+ log.error("鍚屾鍒嗗叕鍙告暟鎹け璐�", e);
+ return AjaxResult.error("鍚屾澶辫触: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * 鎵ц娴佺▼锛�
+ * 1. 纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ * 2. 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂紙鐩存帴鍒涘缓锛屾棤闇�瑙f瀽"--"鏍煎紡锛�
+ * 3. 鍐欏叆 MySQL 鏁版嵁搴擄紙sysDeptMapper 浣跨敤榛樿 MySQL 鏁版嵁婧愶級
+ *
+ * @param transportDepts 澶栭儴浼犲叆鐨勮浆杩愰儴瀛愰儴闂ㄦ暟鎹垪琛�
+ * @return 鍚屾缁撴灉
+ */
+ @Override
+ @Transactional
+ public AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts)
+ {
+ try
+ {
+ if (transportDepts == null || transportDepts.isEmpty())
+ {
+ return AjaxResult.warn("浼犲叆鐨勮浆杩愰儴瀛愰儴闂ㄦ暟鎹负绌�");
+ }
+
+ log.info("寮�濮嬪悓姝� {} 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹埌 MySQL 鏁版嵁搴�...", transportDepts.size());
+
+ // 绗竴姝ワ細纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ Long transportDeptId = null;
+
+ // 鏌ヨ鎬诲叕鍙告槸鍚﹀瓨鍦�
+ SysDept headOffice = sysDeptMapper.selectDeptById(101L);
+ if (headOffice == null)
+ {
+ log.error("鎬诲叕鍙革紙ID=101锛変笉瀛樺湪锛屾棤娉曞悓姝ヨ浆杩愰儴");
+ return AjaxResult.error("鎬诲叕鍙革紙ID=101锛変笉瀛樺湪锛岃鍏堝垱寤烘�诲叕鍙�");
+ }
+
+ // 鏌ヨ杞繍閮ㄦ槸鍚﹀凡瀛樺湪锛堥�氳繃閮ㄩ棬鍚嶇О鍜宲arent_id=101鏉ユ煡璇級
+ SysDept existingTransport = sysDeptMapper.checkDeptNameUnique("杞繍閮�", 101L);
+
+ if (existingTransport != null)
+ {
+ // 杞繍閮ㄥ凡瀛樺湪
+ transportDeptId = existingTransport.getDeptId();
+ log.info("杞繍閮ㄥ凡瀛樺湪: ID={}", transportDeptId);
+ }
+ else
+ {
+ // 鍒涘缓鏂扮殑杞繍閮�
+ SysDept newTransport = new SysDept();
+ newTransport.setParentId(101L); // 鐖惰妭鐐逛负鎬诲叕鍙�
+ newTransport.setDeptName("杞繍閮�");
+ newTransport.setAncestors("0,101"); // 绁栫骇鍒楄〃
+ newTransport.setOrderNum(1); // 鎺掑簭
+ newTransport.setStatus("0"); // 姝e父鐘舵��
+ newTransport.setCreateBy("sync");
+ newTransport.setDepartmentId(150);
+
+
+ sysDeptMapper.insertDept(newTransport);
+ transportDeptId = newTransport.getDeptId();
+ log.info("鍒涘缓鏂拌浆杩愰儴: ID={}", transportDeptId);
+ }
+
+ // 绗簩姝ワ細鍒涘缓鎴栨洿鏂拌浆杩愰儴鐨勫瓙閮ㄩ棬
+ int createdDept = 0;
+ int updatedDept = 0;
+
+ for (DepartmentSyncDTO dto : transportDepts)
+ {
+ String deptName = dto.getDepartmentName();
+ if (StringUtils.isEmpty(deptName))
+ {
+ continue;
+ }
+
+ // 鍏堟牴鎹甦epartmentId鏌ヨ鏄惁宸插瓨鍦�
+ SysDept existingDept = sysDeptMapper.selectDeptByDepartmentIdAndParentId(
+ dto.getDepartmentId(), transportDeptId);
+
+ if (existingDept != null)
+ {
+ // 閮ㄩ棬宸插瓨鍦紝鏇存柊淇℃伅
+ existingDept.setDeptName(deptName);
+ existingDept.setUpdateBy("sync");
+ sysDeptMapper.updateDept(existingDept);
+ updatedDept++;
+ log.info("鏇存柊杞繍閮ㄥ瓙閮ㄩ棬: {}", deptName);
+ }
+ else
+ {
+ // 妫�鏌ユ槸鍚﹀瓨鍦ㄥ悓鍚嶉儴闂紙鍙兘涔嬪墠鎵嬪姩鍒涘缓鐨勶級
+ SysDept sameName = sysDeptMapper.checkDeptNameUnique(deptName, transportDeptId);
+ if (sameName != null)
+ {
+ // 鍚屽悕閮ㄩ棬宸插瓨鍦紝鏇存柊鍏禿epartment_id
+ sameName.setDepartmentId(dto.getDepartmentId());
+ sameName.setUpdateBy("sync");
+ sysDeptMapper.updateDept(sameName);
+ updatedDept++;
+ log.info("鏇存柊宸插瓨鍦ㄧ殑鍚屽悕杞繍閮ㄥ瓙閮ㄩ棬: {}, departmentId: {}",
+ deptName, dto.getDepartmentId());
+ }
+ else
+ {
+ // 鍒涘缓鏂伴儴闂�
+ SysDept newDept = new SysDept();
+ newDept.setParentId(transportDeptId);
+ newDept.setDeptName(deptName);
+ newDept.setAncestors("0,101," + transportDeptId); // 绁栫骇鍒楄〃
+ newDept.setOrderNum(1); // 鎺掑簭
+ newDept.setStatus("0"); // 姝e父鐘舵��
+
+ newDept.setDepartmentId(dto.getDepartmentId()); // 璁板綍SQL Server涓殑閮ㄩ棬ID
+ newDept.setCreateBy("sync");
+
+ sysDeptMapper.insertDept(newDept);
+ createdDept++;
+ log.info("鍒涘缓鏂拌浆杩愰儴瀛愰儴闂�: {}, departmentId: {}",
+ deptName, dto.getDepartmentId());
+ }
+ }
+ }
+
+ String message = String.format("杞繍閮ㄥ悓姝ュ畬鎴愶紒鍒涘缓瀛愰儴闂�: %d, 鏇存柊瀛愰儴闂�: %d",
+ createdDept, updatedDept);
+ log.info(message);
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("transportDeptId", transportDeptId);
+ result.put("createdDept", createdDept);
+ result.put("updatedDept", updatedDept);
+ result.put("totalProcessed", transportDepts.size());
+
+ return AjaxResult.success(message, result);
+ }
+ catch (Exception e)
+ {
+ log.error("鍚屾杞繍閮ㄦ暟鎹け璐�", e);
+ return AjaxResult.error("鍚屾澶辫触: " + e.getMessage());
+ }
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GeocodeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GeocodeServiceImpl.java
new file mode 100644
index 0000000..5403b71
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GeocodeServiceImpl.java
@@ -0,0 +1,115 @@
+package com.ruoyi.system.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.system.domain.dto.GeocodeResult;
+import com.ruoyi.system.service.IGeocodeService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.net.URLEncoder;
+
+/**
+ * 鍦扮悊缂栫爜鏈嶅姟瀹炵幇绫�
+ * 浣跨敤鑵捐鍦板浘WebService API
+ */
+@Service
+public class GeocodeServiceImpl implements IGeocodeService {
+
+ private static final Logger log = LoggerFactory.getLogger(GeocodeServiceImpl.class);
+
+ /**
+ * 鑵捐鍦板浘API瀵嗛挜锛屼粠閰嶇疆鏂囦欢璇诲彇
+ * 闇�瑕佸湪application.yml涓厤缃細tencent.map.key
+ */
+ @Value("${tencent.map.key:}")
+ private String tencentMapKey;
+
+ /**
+ * 鑵捐鍦板浘鍦扮悊缂栫爜API鍦板潃
+ */
+ private static final String GEOCODE_API_URL = "https://apis.map.qq.com/ws/geocoder/v1/";
+
+ private final RestTemplate restTemplate = new RestTemplate();
+
+ @Override
+ public GeocodeResult getCoordinatesByAddress(String address) {
+ return getCoordinatesByAddress(address, null);
+ }
+
+ @Override
+ public GeocodeResult getCoordinatesByAddress(String address, String city) {
+ if (address == null || address.trim().isEmpty()) {
+ return new GeocodeResult(false, "鍦板潃涓嶈兘涓虹┖");
+ }
+
+ // 妫�鏌PI瀵嗛挜鏄惁閰嶇疆
+ if (tencentMapKey == null || tencentMapKey.trim().isEmpty()) {
+ log.error("鑵捐鍦板浘API瀵嗛挜鏈厤缃紝璇峰湪application.yml涓厤缃畉encent.map.key");
+ return new GeocodeResult(false, "鍦板浘API瀵嗛挜鏈厤缃�");
+ }
+
+ try {
+ // 鏋勫缓璇锋眰URL
+ StringBuilder urlBuilder = new StringBuilder(GEOCODE_API_URL);
+ urlBuilder.append("?address=").append(URLEncoder.encode(address, "UTF-8"));
+ urlBuilder.append("&key=").append(tencentMapKey);
+
+ // 濡傛灉鎸囧畾浜嗗煄甯傦紝娣诲姞region鍙傛暟鎻愰珮鍑嗙‘搴�
+ if (city != null && !city.trim().isEmpty()) {
+ urlBuilder.append("®ion=").append(URLEncoder.encode(city, "UTF-8"));
+ }
+
+ String url = urlBuilder.toString();
+ log.info("璋冪敤鑵捐鍦板浘鍦扮悊缂栫爜API: {}", url);
+
+ // 鍙戦�丠TTP GET璇锋眰
+ String response = restTemplate.getForObject(url, String.class);
+ log.info("鑵捐鍦板浘API鍝嶅簲: {}", response);
+
+ // 瑙f瀽JSON鍝嶅簲
+ JSONObject jsonResponse = JSON.parseObject(response);
+ Integer status = jsonResponse.getInteger("status");
+
+ if (status == null || status != 0) {
+ String message = jsonResponse.getString("message");
+ log.error("鍦扮悊缂栫爜澶辫触: status={}, message={}", status, message);
+ return new GeocodeResult(false, "鍦扮悊缂栫爜澶辫触: " + message);
+ }
+
+ // 鎻愬彇鍧愭爣淇℃伅
+ JSONObject result = jsonResponse.getJSONObject("result");
+ if (result == null) {
+ return new GeocodeResult(false, "鏈壘鍒板湴鐞嗙紪鐮佺粨鏋�");
+ }
+
+ JSONObject location = result.getJSONObject("location");
+ if (location == null) {
+ return new GeocodeResult(false, "鏈壘鍒板潗鏍囦俊鎭�");
+ }
+
+ Double lat = location.getDouble("lat");
+ Double lng = location.getDouble("lng");
+
+ if (lat == null || lng == null) {
+ return new GeocodeResult(false, "鍧愭爣鏁版嵁鏍煎紡閿欒");
+ }
+
+ // 鑾峰彇鏍囧噯鍖栧湴鍧�
+ String standardAddress = result.getString("address");
+
+ GeocodeResult geocodeResult = new GeocodeResult(lat, lng, standardAddress);
+ log.info("鍦扮悊缂栫爜鎴愬姛: {}", geocodeResult);
+
+ return geocodeResult;
+
+ } catch (Exception e) {
+ log.error("鍦扮悊缂栫爜鏈嶅姟寮傚父", e);
+ return new GeocodeResult(false, "鍦扮悊缂栫爜鏈嶅姟寮傚父: " + e.getMessage());
+ }
+ }
+}
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 386cf99..baaece3 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
@@ -1,5 +1,6 @@
package com.ruoyi.system.service.impl;
+import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
@@ -21,6 +22,8 @@
import com.ruoyi.system.domain.SysTaskVehicle;
import com.ruoyi.system.domain.SysTaskAttachment;
import com.ruoyi.system.domain.SysTaskLog;
+import com.ruoyi.system.domain.SysTaskEmergency;
+import com.ruoyi.system.domain.SysTaskWelfare;
import com.ruoyi.system.domain.vo.TaskQueryVO;
import com.ruoyi.system.domain.vo.TaskCreateVO;
import com.ruoyi.system.domain.vo.TaskUpdateVO;
@@ -30,6 +33,8 @@
import com.ruoyi.system.mapper.SysTaskVehicleMapper;
import com.ruoyi.system.mapper.SysTaskAttachmentMapper;
import com.ruoyi.system.mapper.SysTaskLogMapper;
+import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
+import com.ruoyi.system.mapper.SysTaskWelfareMapper;
import com.ruoyi.system.mapper.VehicleInfoMapper;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.service.ISysTaskService;
@@ -56,6 +61,12 @@
private SysTaskLogMapper sysTaskLogMapper;
@Autowired
+ private SysTaskEmergencyMapper sysTaskEmergencyMapper;
+
+ @Autowired
+ private SysTaskWelfareMapper sysTaskWelfareMapper;
+
+ @Autowired
private VehicleInfoMapper vehicleInfoMapper;
/**
@@ -66,7 +77,20 @@
*/
@Override
public SysTask selectSysTaskByTaskId(Long taskId) {
- return sysTaskMapper.selectSysTaskByTaskId(taskId);
+ SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
+ if (task != null) {
+ // 鍔犺浇鎬ユ晳杞繍鎵╁睍淇℃伅
+ if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+ SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
+ task.setEmergencyInfo(emergencyInfo);
+ }
+ // 鍔犺浇绂忕杞︽墿灞曚俊鎭�
+ else if ("WELFARE".equals(task.getTaskType())) {
+ SysTaskWelfare welfareInfo = sysTaskWelfareMapper.selectSysTaskWelfareByTaskId(taskId);
+ task.setWelfareInfo(welfareInfo);
+ }
+ }
+ return task;
}
/**
@@ -94,12 +118,6 @@
task.setTaskType(createVO.getTaskType());
task.setTaskStatus(TaskStatus.PENDING.getCode());
task.setTaskDescription(createVO.getTaskDescription());
- task.setDepartureAddress(createVO.getDepartureAddress());
- task.setDestinationAddress(createVO.getDestinationAddress());
- task.setDepartureLongitude(createVO.getDepartureLongitude());
- task.setDepartureLatitude(createVO.getDepartureLatitude());
- task.setDestinationLongitude(createVO.getDestinationLongitude());
- task.setDestinationLatitude(createVO.getDestinationLatitude());
task.setPlannedStartTime(createVO.getPlannedStartTime());
task.setPlannedEndTime(createVO.getPlannedEndTime());
task.setAssigneeId(createVO.getAssigneeId());
@@ -112,8 +130,51 @@
task.setRemark(createVO.getRemark());
task.setDelFlag("0");
- // 璁$畻棰勮鍏噷鏁�
- calculateEstimatedDistance(task);
+ // 璁剧疆閫氱敤鍦板潃鍜屽潗鏍囦俊鎭�
+ if (createVO.getDepartureAddress() != null) {
+ task.setDepartureAddress(createVO.getDepartureAddress());
+ }
+ if (createVO.getDestinationAddress() != null) {
+ task.setDestinationAddress(createVO.getDestinationAddress());
+ }
+ if (createVO.getDepartureLongitude() != null) {
+ task.setDepartureLongitude(createVO.getDepartureLongitude());
+ }
+ if (createVO.getDepartureLatitude() != null) {
+ task.setDepartureLatitude(createVO.getDepartureLatitude());
+ }
+ if (createVO.getDestinationLongitude() != null) {
+ task.setDestinationLongitude(createVO.getDestinationLongitude());
+ }
+ if (createVO.getDestinationLatitude() != null) {
+ task.setDestinationLatitude(createVO.getDestinationLatitude());
+ }
+ if (createVO.getEstimatedDistance() != null) {
+ task.setEstimatedDistance(createVO.getEstimatedDistance());
+ }
+
+ // 璁剧疆鎬ユ晳杞繍鐗瑰畾淇℃伅
+ if (createVO.getTransferTime() != null) {
+ task.setPlannedStartTime(createVO.getTransferTime());
+ }
+ if (createVO.getTransferDistance() != null) {
+ task.setEstimatedDistance(createVO.getTransferDistance());
+ }
+
+ // 璁剧疆绂忕杞︾壒瀹氫俊鎭�
+ if (createVO.getServiceTime() != null) {
+ task.setPlannedStartTime(createVO.getServiceTime());
+ }
+ if (createVO.getStartAddress() != null) {
+ task.setDepartureAddress(createVO.getStartAddress());
+ }
+ if (createVO.getEndAddress() != null) {
+ task.setDestinationAddress(createVO.getEndAddress());
+ }
+ // 璁剧疆绂忕杞﹀叕閲屾暟
+ if (createVO.getDistance() != null) {
+ task.setEstimatedDistance(createVO.getDistance());
+ }
int result = sysTaskMapper.insertSysTask(task);
@@ -133,6 +194,16 @@
sysTaskVehicleMapper.insertSysTaskVehicle(taskVehicle);
}
+ }
+
+ // 淇濆瓨鎬ユ晳杞繍鎵╁睍淇℃伅
+ if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
+ saveEmergencyInfo(task.getTaskId(), createVO);
+ }
+
+ // 淇濆瓨绂忕杞︽墿灞曚俊鎭�
+ if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
+ saveWelfareInfo(task.getTaskId(), createVO);
}
// 璁板綍鎿嶄綔鏃ュ織
@@ -248,6 +319,21 @@
@Override
@Transactional
public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark) {
+ return changeTaskStatusWithLocation(taskId, newStatus, remark, null);
+ }
+
+ /**
+ * 鍙樻洿浠诲姟鐘舵�侊紙鍚獹PS浣嶇疆淇℃伅锛�
+ *
+ * @param taskId 浠诲姟ID
+ * @param newStatus 鏂扮姸鎬�
+ * @param remark 澶囨敞
+ * @param locationLog GPS浣嶇疆淇℃伅鏃ュ織瀵硅薄
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional
+ public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog) {
SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(taskId);
if (oldTask == null) {
throw new RuntimeException("浠诲姟涓嶅瓨鍦�");
@@ -266,20 +352,26 @@
task.setUpdateTime(DateUtils.getNowDate());
// 鏍规嵁鐘舵�佽缃浉搴旂殑鏃堕棿
- if (newStatus == TaskStatus.IN_PROGRESS && oldTask.getActualStartTime() == null) {
+ if (newStatus == TaskStatus.DEPARTING && oldTask.getActualStartTime() == null) {
+ // 鍑哄彂涓細璁剧疆瀹為檯寮�濮嬫椂闂�
+ task.setActualStartTime(DateUtils.getNowDate());
+ } else if (newStatus == TaskStatus.IN_PROGRESS && oldTask.getActualStartTime() == null) {
+ // 鍏煎鏃ф暟鎹細浠诲姟涓姸鎬佷篃璁剧疆瀹為檯寮�濮嬫椂闂�
task.setActualStartTime(DateUtils.getNowDate());
} else if (newStatus == TaskStatus.COMPLETED) {
+ // 宸插畬鎴愶細璁剧疆瀹為檯缁撴潫鏃堕棿
task.setActualEndTime(DateUtils.getNowDate());
}
int result = sysTaskMapper.updateTaskStatus(task);
- // 璁板綍鎿嶄綔鏃ュ織
+ // 璁板綍鎿嶄綔鏃ュ織锛堝惈GPS浣嶇疆淇℃伅锛�
if (result > 0) {
recordTaskLog(taskId, "STATUS_CHANGE", "鐘舵�佸彉鏇�",
"鐘舵�侊細" + oldTaskStatus.getInfo(),
"鐘舵�侊細" + newStatus.getInfo() + "锛屽娉細" + remark,
- SecurityUtils.getUserId(), SecurityUtils.getUsername());
+ SecurityUtils.getUserId(), SecurityUtils.getUsername(),
+ locationLog);
}
return result;
@@ -557,6 +649,16 @@
task.setAttachments(sysTaskAttachmentMapper.selectSysTaskAttachmentByTaskId(taskId));
// 鏌ヨ鎿嶄綔鏃ュ織
task.setOperationLogs(sysTaskLogMapper.selectSysTaskLogByTaskId(taskId));
+ // 鍔犺浇鎬ユ晳杞繍鎵╁睍淇℃伅
+ if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+ SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
+ task.setEmergencyInfo(emergencyInfo);
+ }
+ // 鍔犺浇绂忕杞︽墿灞曚俊鎭�
+ else if ("WELFARE".equals(task.getTaskType())) {
+ SysTaskWelfare welfareInfo = sysTaskWelfareMapper.selectSysTaskWelfareByTaskId(taskId);
+ task.setWelfareInfo(welfareInfo);
+ }
}
return task;
}
@@ -586,7 +688,29 @@
*/
private void recordTaskLog(Long taskId, String operationType, String operationDesc,
String oldValue, String newValue, Long operatorId, String operatorName) {
- SysTaskLog log = new SysTaskLog();
+ recordTaskLog(taskId, operationType, operationDesc, oldValue, newValue,
+ operatorId, operatorName, null);
+ }
+
+ /**
+ * 璁板綍浠诲姟鎿嶄綔鏃ュ織锛堝惈GPS浣嶇疆淇℃伅锛�
+ *
+ * @param taskId 浠诲姟ID
+ * @param operationType 鎿嶄綔绫诲瀷
+ * @param operationDesc 鎿嶄綔鎻忚堪
+ * @param oldValue 鎿嶄綔鍓嶅��
+ * @param newValue 鎿嶄綔鍚庡��
+ * @param operatorId 鎿嶄綔浜篒D
+ * @param operatorName 鎿嶄綔浜哄鍚�
+ * @param log GPS浣嶇疆淇℃伅鏃ュ織瀵硅薄锛堝彲涓簄ull锛�
+ */
+ private void recordTaskLog(Long taskId, String operationType, String operationDesc,
+ String oldValue, String newValue, Long operatorId, String operatorName,
+ SysTaskLog log) {
+ if (log == null) {
+ log = new SysTaskLog();
+ }
+
log.setTaskId(taskId);
log.setOperationType(operationType);
log.setOperationDesc(operationDesc);
@@ -664,4 +788,98 @@
task.setEstimatedDistance(java.math.BigDecimal.ZERO);
}
}
+
+ /**
+ * 淇濆瓨鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅
+ *
+ * @param taskId 浠诲姟ID
+ * @param createVO 浠诲姟鍒涘缓瀵硅薄
+ */
+ private void saveEmergencyInfo(Long taskId, TaskCreateVO createVO) {
+ SysTaskEmergency emergencyInfo = new SysTaskEmergency();
+ emergencyInfo.setTaskId(taskId);
+
+ // 璁剧疆鎮h�呬俊鎭�
+ if (createVO.getPatient() != null) {
+ emergencyInfo.setPatientContact(createVO.getPatient().getContact());
+ emergencyInfo.setPatientPhone(createVO.getPatient().getPhone());
+ emergencyInfo.setPatientName(createVO.getPatient().getName());
+ emergencyInfo.setPatientGender(createVO.getPatient().getGender());
+ emergencyInfo.setPatientIdCard(createVO.getPatient().getIdCard());
+ emergencyInfo.setPatientCondition(createVO.getPatient().getCondition());
+ }
+
+ // 璁剧疆杞嚭鍖婚櫌淇℃伅
+ if (createVO.getHospitalOut() != null) {
+ emergencyInfo.setHospitalOutName(createVO.getHospitalOut().getName());
+ emergencyInfo.setHospitalOutDepartment(createVO.getHospitalOut().getDepartment());
+ emergencyInfo.setHospitalOutBedNumber(createVO.getHospitalOut().getBedNumber());
+ emergencyInfo.setHospitalOutAddress(createVO.getHospitalOut().getAddress());
+ emergencyInfo.setHospitalOutLongitude(createVO.getHospitalOut().getLongitude());
+ emergencyInfo.setHospitalOutLatitude(createVO.getHospitalOut().getLatitude());
+ }
+
+ // 璁剧疆杞叆鍖婚櫌淇℃伅
+ if (createVO.getHospitalIn() != null) {
+ emergencyInfo.setHospitalInName(createVO.getHospitalIn().getName());
+ emergencyInfo.setHospitalInDepartment(createVO.getHospitalIn().getDepartment());
+ emergencyInfo.setHospitalInBedNumber(createVO.getHospitalIn().getBedNumber());
+ emergencyInfo.setHospitalInAddress(createVO.getHospitalIn().getAddress());
+ emergencyInfo.setHospitalInLongitude(createVO.getHospitalIn().getLongitude());
+ emergencyInfo.setHospitalInLatitude(createVO.getHospitalIn().getLatitude());
+ }
+
+ // 璁剧疆璐圭敤淇℃伅
+ emergencyInfo.setTransferDistance(createVO.getTransferDistance());
+ emergencyInfo.setTransferPrice(createVO.getPrice());
+
+ // 绯荤粺瀛楁
+ emergencyInfo.setCreateTime(DateUtils.getNowDate());
+ emergencyInfo.setUpdateTime(DateUtils.getNowDate());
+ emergencyInfo.setCreateBy(SecurityUtils.getUsername());
+ emergencyInfo.setUpdateBy(SecurityUtils.getUsername());
+
+ sysTaskEmergencyMapper.insertSysTaskEmergency(emergencyInfo);
+ }
+
+ /**
+ * 淇濆瓨绂忕杞︿换鍔℃墿灞曚俊鎭�
+ *
+ * @param taskId 浠诲姟ID
+ * @param createVO 浠诲姟鍒涘缓瀵硅薄
+ */
+ private void saveWelfareInfo(Long taskId, TaskCreateVO createVO) {
+ SysTaskWelfare welfareInfo = new SysTaskWelfare();
+ welfareInfo.setTaskId(taskId);
+
+ // 璁剧疆涔樺淇℃伅
+ if (createVO.getPassenger() != null) {
+ welfareInfo.setPassengerContact(createVO.getPassenger().getContact());
+ welfareInfo.setPassengerPhone(createVO.getPassenger().getPhone());
+ }
+
+ // 璁剧疆鍦板潃淇℃伅
+ welfareInfo.setPickupAddress(createVO.getStartAddress());
+ welfareInfo.setDestinationAddress(createVO.getEndAddress());
+
+ // 璁剧疆GPS鍧愭爣
+ welfareInfo.setPickupLongitude(createVO.getDepartureLongitude());
+ welfareInfo.setPickupLatitude(createVO.getDepartureLatitude());
+ welfareInfo.setDestinationLongitude(createVO.getDestinationLongitude());
+ welfareInfo.setDestinationLatitude(createVO.getDestinationLatitude());
+
+ // 璁剧疆璺濈鍜岃垂鐢�
+ // 浼樺厛浣跨敤绂忕杞︿笓鐢ㄧ殑distance瀛楁锛屽鏋滄病鏈夊垯浣跨敤閫氱敤鐨別stimatedDistance
+ BigDecimal serviceDistance = createVO.getDistance() != null ? createVO.getDistance() : createVO.getEstimatedDistance();
+ welfareInfo.setServiceDistance(serviceDistance);
+ welfareInfo.setServicePrice(createVO.getPrice());
+
+ // 绯荤粺瀛楁
+ welfareInfo.setCreateTime(DateUtils.getNowDate());
+ welfareInfo.setUpdateTime(DateUtils.getNowDate());
+ welfareInfo.setCreateBy(SecurityUtils.getUsername());
+ welfareInfo.setUpdateBy(SecurityUtils.getUsername());
+
+ sysTaskWelfareMapper.insertSysTaskWelfare(welfareInfo);
+ }
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskVehicleServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskVehicleServiceImpl.java
index b8e1c76..9cbaeb1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskVehicleServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskVehicleServiceImpl.java
@@ -3,13 +3,17 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.mapper.SysTaskVehicleMapper;
+import com.ruoyi.system.mapper.VehicleInfoMapper;
import com.ruoyi.system.domain.SysTaskVehicle;
+import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.service.ISysTaskVehicleService;
/**
@@ -21,8 +25,13 @@
@Service
public class SysTaskVehicleServiceImpl implements ISysTaskVehicleService {
+ private static final Logger logger = LoggerFactory.getLogger(SysTaskVehicleServiceImpl.class);
+
@Autowired
private SysTaskVehicleMapper sysTaskVehicleMapper;
+
+ @Autowired
+ private VehicleInfoMapper vehicleInfoMapper;
/**
* 鏌ヨ浠诲姟杞﹁締鍏宠仈
@@ -255,29 +264,30 @@
@Override
public List<SysTaskVehicle> getAvailableVehicles(Long deptId, String taskType) {
// 鏌ヨ鎸囧畾閮ㄩ棬涓嬬姸鎬佷负姝e父鐨勮溅杈�
- // 杩欓噷闇�瑕佹牴鎹疄闄呯殑杞﹁締淇℃伅琛ㄧ粨鏋勬潵瀹炵幇
- // 鏆傛椂杩斿洖绌哄垪琛紝瀹為檯瀹炵幇闇�瑕侊細
- // 1. 鏌ヨ tb_vehicle_info 琛ㄤ腑 dept_id = deptId 涓� vehicle_status = '0' 鐨勮溅杈�
- // 2. 鎺掗櫎宸茬粡鍒嗛厤缁欏叾浠栨湭瀹屾垚浠诲姟涓旂姸鎬佷负 ACTIVE 鐨勮溅杈�
- // 3. 鏍规嵁浠诲姟绫诲瀷绛涢�夊悎閫傜殑杞﹁締绫诲瀷
-
List<SysTaskVehicle> availableVehicles = new ArrayList<>();
- // TODO: 瀹炵幇鍏蜂綋鐨勬煡璇㈤�昏緫
- // 绀轰緥浠g爜锛�
- // 1. 鏌ヨ杞﹁締淇℃伅
- // List<TbVehicleInfo> vehicles = vehicleInfoMapper.selectAvailableVehiclesByDept(deptId, taskType);
- //
- // 2. 杞崲涓� SysTaskVehicle 瀵硅薄
- // for (TbVehicleInfo vehicle : vehicles) {
- // SysTaskVehicle taskVehicle = new SysTaskVehicle();
- // taskVehicle.setVehicleId(vehicle.getVehicleId());
- // taskVehicle.setVehicleNo(vehicle.getVehicleNo());
- // taskVehicle.setVehicleType(vehicle.getVehicleType());
- // taskVehicle.setVehicleBrand(vehicle.getVehicleBrand());
- // taskVehicle.setVehicleModel(vehicle.getVehicleModel());
- // availableVehicles.add(taskVehicle);
- // }
+ try {
+ // 鏌ヨ杞﹁締淇℃伅
+ VehicleInfo queryParam = new VehicleInfo();
+ queryParam.setDeptId(deptId);
+ queryParam.setStatus("0"); // 0琛ㄧず姝e父鐘舵��
+
+ List<VehicleInfo> vehicles = vehicleInfoMapper.selectVehicleInfoList(queryParam);
+
+ // 杞崲涓� SysTaskVehicle 瀵硅薄
+ for (VehicleInfo vehicle : vehicles) {
+ SysTaskVehicle taskVehicle = new SysTaskVehicle();
+ taskVehicle.setVehicleId(vehicle.getVehicleId());
+ taskVehicle.setVehicleNo(vehicle.getVehicleNo());
+ taskVehicle.setVehicleType(vehicle.getVehicleType());
+ taskVehicle.setVehicleBrand(vehicle.getVehicleBrand());
+ taskVehicle.setVehicleModel(vehicle.getVehicleModel());
+ taskVehicle.setStatus(vehicle.getStatus());
+ availableVehicles.add(taskVehicle);
+ }
+ } catch (Exception e) {
+ logger.error("鏌ヨ鍙敤杞﹁締澶辫触", e);
+ }
return availableVehicles;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncDataServiceImpl.java
new file mode 100644
index 0000000..eace739
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncDataServiceImpl.java
@@ -0,0 +1,68 @@
+package com.ruoyi.system.service.impl;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.system.domain.UserSyncDTO;
+import com.ruoyi.system.mapper.UserSyncMapper;
+import com.ruoyi.system.service.IUserSyncDataService;
+
+import java.util.List;
+
+/**
+ * SQL Server 鐢ㄦ埛鏁版嵁鏌ヨ鏈嶅姟瀹炵幇
+ *
+ * 鑱岃矗锛氫笓闂ㄨ礋璐d粠 SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁
+ *
+ * 鏁版嵁娴佸悜锛歋QL Server 鈫� 杩斿洖 DTO 鍒楄〃
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Service
+@DataSource(DataSourceType.SQLSERVER)
+public class UserSyncDataServiceImpl implements IUserSyncDataService
+{
+ private static final Logger log = LoggerFactory.getLogger(UserSyncDataServiceImpl.class);
+
+ @Autowired
+ private UserSyncMapper userSyncMapper;
+
+ /**
+ * 浠� SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁
+ *
+ * 娉ㄦ剰锛歎serSyncMapper 涓婃湁 @DataSource(DataSourceType.SQLSERVER) 娉ㄨВ
+ * 姝ゆ柟娉曚細鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧愭墽琛屾煡璇�
+ *
+ * @return OA 鐢ㄦ埛鍒楄〃
+ */
+ @Override
+ public List<UserSyncDTO> getOaUsers()
+ {
+ try
+ {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁...");
+
+ // 璋冪敤 Mapper 鏌ヨ SQL Server 鏁版嵁
+ // @DataSource 娉ㄨВ浼氳嚜鍔ㄥ垏鎹㈡暟鎹簮
+ List<UserSyncDTO> oaUsers = userSyncMapper.selectOaUsers();
+
+ if (oaUsers == null || oaUsers.isEmpty())
+ {
+ log.warn("鏈粠 SQL Server 鏌ヨ鍒� OA 鐢ㄦ埛鏁版嵁");
+ return oaUsers;
+ }
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉� OA 鐢ㄦ埛鏁版嵁", oaUsers.size());
+ return oaUsers;
+ }
+ catch (Exception e)
+ {
+ log.error("浠� SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁澶辫触", e);
+ throw new RuntimeException("鏌ヨ SQL Server 鐢ㄦ埛鏁版嵁澶辫触: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java
new file mode 100644
index 0000000..44e8fa9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java
@@ -0,0 +1,264 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.UserSyncDTO;
+import com.ruoyi.system.mapper.SysDeptMapper;
+import com.ruoyi.system.mapper.SysUserMapper;
+import com.ruoyi.system.service.IUserSyncService;
+import com.ruoyi.system.service.IUserSyncDataService;
+
+/**
+ * 鐢ㄦ埛鍚屾Service涓氬姟灞傚鐞�
+ *
+ * 鑱岃矗锛氭帴鏀剁敤鎴锋暟鎹紝鍐欏叆 MySQL 鏁版嵁搴�
+ * 鏁版嵁鏉ユ簮锛�
+ * 1. 鍐呴儴鏌ヨ锛氳皟鐢� IUserSyncDataService 浠� SQL Server 鏌ヨ
+ * 2. 澶栭儴浼犲叆锛氭帴鏀跺凡鏌ヨ濂界殑鏁版嵁
+ *
+ * @author ruoyi
+ * @date 2025-10-18
+ */
+@Service
+public class UserSyncServiceImpl implements IUserSyncService
+{
+ private static final Logger log = LoggerFactory.getLogger(UserSyncServiceImpl.class);
+
+
+
+ @Autowired
+ private SysUserMapper sysUserMapper;
+
+ @Autowired
+ private SysDeptMapper sysDeptMapper;
+
+
+
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * 鎵ц娴佺▼锛�
+ * 1. 鎺ユ敹澶栭儴浼犲叆鐨� UserSyncDTO 鍒楄〃
+ * 2. 鏌ヨ MySQL 涓殑閮ㄩ棬淇℃伅锛坰ysDeptMapper 浣跨敤榛樿 MySQL 鏁版嵁婧愶級
+ * 3. 鍐欏叆 MySQL 鏁版嵁搴擄紙sysUserMapper 浣跨敤榛樿 MySQL 鏁版嵁婧愶級
+ *
+ * @param oaUsers 澶栭儴浼犲叆鐨凮A鐢ㄦ埛鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+ @Override
+ @Transactional
+ public AjaxResult syncOaUsers(List<UserSyncDTO> oaUsers)
+ {
+ try
+ {
+ if (oaUsers == null || oaUsers.isEmpty())
+ {
+ return AjaxResult.warn("浼犲叆鐨勭敤鎴锋暟鎹负绌�");
+ }
+
+ log.info("寮�濮嬪悓姝� {} 鏉A鐢ㄦ埛鏁版嵁鍒� MySQL 鏁版嵁搴�...", oaUsers.size());
+
+ int createdCount = 0;
+ int updatedCount = 0;
+ int skippedCount = 0;
+ int errorCount = 0;
+
+ // 澶勭悊姣忎竴鏉$敤鎴锋暟鎹�
+ for (UserSyncDTO dto : oaUsers)
+ {
+ try
+ {
+ // 楠岃瘉蹇呭~瀛楁
+ if (StringUtils.isEmpty(dto.getUserName()) || StringUtils.isEmpty(dto.getNickName()))
+ {
+ log.warn("鐢ㄦ埛鏁版嵁涓嶅畬鏁达紝璺宠繃: oaUserId={}", dto.getOaUserId());
+ skippedCount++;
+ continue;
+ }
+
+ // 3. 鏍规嵁 department_id 鏌ユ壘瀵瑰簲鐨� dept_id锛堜粠 MySQL 涓煡璇級
+ Long deptId = null;
+ if (dto.getDepartmentId() != null)
+ {
+ SysDept dept = sysDeptMapper.selectDeptByDepartmentId(dto.getDepartmentId());
+ if (dept != null)
+ {
+ deptId = dept.getDeptId();
+ }
+ else
+ {
+ log.warn("鏈壘鍒板搴旂殑閮ㄩ棬: departmentId={}, 鐢ㄦ埛: {}",
+ dto.getDepartmentId(), dto.getUserName());
+ }
+ }
+
+ // 4. 妫�鏌ョ敤鎴锋槸鍚﹀凡瀛樺湪锛堟牴鎹畂a_user_id锛�
+ SysUser existingUser = sysUserMapper.selectUserByOaUserId(dto.getOaUserId());
+
+ if (existingUser != null)
+ {
+ // 鐢ㄦ埛宸插瓨鍦紝鏇存柊淇℃伅
+ updateExistingUser(existingUser, dto, deptId);
+ updatedCount++;
+ log.info("鏇存柊鐢ㄦ埛: {} ({}), oaUserId: {}",
+ dto.getNickName(), dto.getUserName(), dto.getOaUserId());
+ }
+ else
+ {
+ // 妫�鏌ョ敤鎴峰悕鏄惁宸茶鍗犵敤
+ SysUser userByName = sysUserMapper.checkUserNameUnique(dto.getUserName());
+ if (userByName != null)
+ {
+ // 鐢ㄦ埛鍚嶅凡瀛樺湪锛屾洿鏂板叾oa_user_id
+ userByName.setOaUserId(dto.getOaUserId());
+ userByName.setNickName(dto.getNickName());
+ if (deptId != null)
+ {
+ userByName.setDeptId(deptId);
+ }
+ if (StringUtils.isNotEmpty(dto.getEmail()))
+ {
+ userByName.setEmail(dto.getEmail());
+ }
+ if (StringUtils.isNotEmpty(dto.getPhonenumber()))
+ {
+ userByName.setPhonenumber(dto.getPhonenumber());
+ }
+ if (StringUtils.isNotEmpty(dto.getSex()))
+ {
+ userByName.setSex(dto.getSex());
+ }
+ userByName.setUpdateBy("sync");
+ sysUserMapper.updateUser(userByName);
+ updatedCount++;
+ log.info("鏇存柊宸插瓨鍦ㄧ敤鎴峰悕鐨勭敤鎴�: {} ({}), 璁剧疆oaUserId: {}",
+ dto.getNickName(), dto.getUserName(), dto.getOaUserId());
+ }
+ else
+ {
+ // 鍒涘缓鏂扮敤鎴�
+ createNewUser(dto, deptId);
+ createdCount++;
+ log.info("鍒涘缓鏂扮敤鎴�: {} ({}), oaUserId: {}, deptId: {}",
+ dto.getNickName(), dto.getUserName(), dto.getOaUserId(), deptId);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ errorCount++;
+ log.error("鍚屾鐢ㄦ埛澶辫触: oaUserId={}, userName={}, error: {}",
+ dto.getOaUserId(), dto.getUserName(), e.getMessage(), e);
+ }
+ }
+
+ String message = String.format("鍚屾瀹屾垚锛佸垱寤虹敤鎴�: %d, 鏇存柊鐢ㄦ埛: %d, 璺宠繃: %d, 澶辫触: %d",
+ createdCount, updatedCount, skippedCount, errorCount);
+ log.info(message);
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("created", createdCount);
+ result.put("updated", updatedCount);
+ result.put("skipped", skippedCount);
+ result.put("error", errorCount);
+ result.put("totalProcessed", oaUsers.size());
+
+ return AjaxResult.success(message, result);
+ }
+ catch (Exception e)
+ {
+ log.error("鍚屾鐢ㄦ埛鏁版嵁澶辫触", e);
+ return AjaxResult.error("鍚屾澶辫触: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鏇存柊宸插瓨鍦ㄧ殑鐢ㄦ埛
+ */
+ private void updateExistingUser(SysUser existingUser, UserSyncDTO dto, Long deptId)
+ {
+ existingUser.setNickName(dto.getNickName());
+
+ if (deptId != null)
+ {
+ existingUser.setDeptId(deptId);
+ }
+
+ if (StringUtils.isNotEmpty(dto.getEmail()))
+ {
+ existingUser.setEmail(dto.getEmail());
+ }
+
+ if (StringUtils.isNotEmpty(dto.getPhonenumber()))
+ {
+ existingUser.setPhonenumber(dto.getPhonenumber());
+ }
+
+ if (StringUtils.isNotEmpty(dto.getSex()))
+ {
+ existingUser.setSex(dto.getSex());
+ }
+
+ existingUser.setUpdateBy("sync");
+ sysUserMapper.updateUser(existingUser);
+ }
+
+ /**
+ * 鍒涘缓鏂扮敤鎴�
+ */
+ private void createNewUser(UserSyncDTO dto, Long deptId)
+ {
+ SysUser newUser = new SysUser();
+ newUser.setUserName(dto.getUserName());
+ newUser.setNickName(dto.getNickName());
+ newUser.setOaUserId(dto.getOaUserId());
+
+ if (deptId != null)
+ {
+ newUser.setDeptId(deptId);
+ }
+ else
+ {
+ // 濡傛灉娌℃湁閮ㄩ棬锛岄粯璁よ缃负椤剁骇閮ㄩ棬锛堣嫢渚濈鎶�锛�
+ newUser.setDeptId(100L);
+ }
+
+ if (StringUtils.isNotEmpty(dto.getEmail()))
+ {
+ newUser.setEmail(dto.getEmail());
+ }
+
+ if (StringUtils.isNotEmpty(dto.getPhonenumber()))
+ {
+ newUser.setPhonenumber(dto.getPhonenumber());
+ }
+
+ if (StringUtils.isNotEmpty(dto.getSex()))
+ {
+ newUser.setSex(dto.getSex());
+ }
+ else
+ {
+ newUser.setSex("2"); // 榛樿鏈煡
+ }
+
+ // 璁剧疆榛樿瀵嗙爜锛�123456锛�
+ newUser.setPassword(SecurityUtils.encryptPassword("123456"));
+
+ // 璁剧疆榛樿鐘舵�佷负姝e父
+ newUser.setStatus("0");
+
+ newUser.setCreateBy("sync");
+
+ sysUserMapper.insertUser(newUser);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java
index 42a8c82..d524b96 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java
@@ -1,8 +1,11 @@
package com.ruoyi.system.service.impl;
import java.util.List;
+import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.mapper.VehicleInfoMapper;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.service.IVehicleInfoService;
@@ -91,4 +94,50 @@
public int deleteVehicleInfoById(Long vehicleId) {
return vehicleInfoMapper.deleteVehicleInfoById(vehicleId);
}
+
+ /**
+ * 缁戝畾杞﹁締鍒扮敤鎴�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param vehicleId 杞﹁締ID
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional
+ public int bindVehicleToUser(Long userId, Long vehicleId) {
+ // 鍏堣В缁戠敤鎴风殑鎵�鏈夎溅杈嗭紙涓氬姟閫昏緫锛氫竴涓敤鎴峰悓鏃跺彧鑳界粦瀹氫竴杈嗚溅锛�
+ vehicleInfoMapper.unbindAllVehiclesFromUser(userId);
+
+ // 缁戝畾鏂拌溅杈�
+ String bindBy = "";
+ try {
+ bindBy = SecurityUtils.getUsername();
+ } catch (Exception e) {
+ // 濡傛灉鑾峰彇褰撳墠鐢ㄦ埛澶辫触锛屼娇鐢ㄧ┖瀛楃涓�
+ }
+ return vehicleInfoMapper.bindVehicleToUser(userId, vehicleId, bindBy);
+ }
+
+ /**
+ * 瑙g粦鐢ㄦ埛杞﹁締
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param vehicleId 杞﹁締ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int unbindVehicleFromUser(Long userId, Long vehicleId) {
+ return vehicleInfoMapper.unbindVehicleFromUser(userId, vehicleId);
+ }
+
+ /**
+ * 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 杞﹁締淇℃伅
+ */
+ @Override
+ public VehicleInfo getUserBoundVehicle(Long userId) {
+ return vehicleInfoMapper.getUserBoundVehicle(userId);
+ }
}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java
index b62b5d6..741eec1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java
@@ -18,13 +18,29 @@
private static final Map<TaskStatus, Set<TaskStatus>> ALLOWED_TRANSITIONS = new HashMap<>();
static {
- // PENDING -> IN_PROGRESS, CANCELLED
+ // PENDING -> DEPARTING, CANCELLED
Set<TaskStatus> pendingTransitions = new HashSet<>();
- pendingTransitions.add(TaskStatus.IN_PROGRESS);
+ pendingTransitions.add(TaskStatus.DEPARTING);
pendingTransitions.add(TaskStatus.CANCELLED);
ALLOWED_TRANSITIONS.put(TaskStatus.PENDING, pendingTransitions);
- // IN_PROGRESS -> COMPLETED, CANCELLED, PENDING
+ // DEPARTING -> ARRIVED, CANCELLED
+ Set<TaskStatus> departingTransitions = new HashSet<>();
+ departingTransitions.add(TaskStatus.ARRIVED);
+ departingTransitions.add(TaskStatus.CANCELLED);
+ ALLOWED_TRANSITIONS.put(TaskStatus.DEPARTING, departingTransitions);
+
+ // ARRIVED -> RETURNING
+ Set<TaskStatus> arrivedTransitions = new HashSet<>();
+ arrivedTransitions.add(TaskStatus.RETURNING);
+ ALLOWED_TRANSITIONS.put(TaskStatus.ARRIVED, arrivedTransitions);
+
+ // RETURNING -> COMPLETED
+ Set<TaskStatus> returningTransitions = new HashSet<>();
+ returningTransitions.add(TaskStatus.COMPLETED);
+ ALLOWED_TRANSITIONS.put(TaskStatus.RETURNING, returningTransitions);
+
+ // IN_PROGRESS -> COMPLETED, CANCELLED, PENDING (鍏煎鏃ф暟鎹�)
Set<TaskStatus> inProgressTransitions = new HashSet<>();
inProgressTransitions.add(TaskStatus.COMPLETED);
inProgressTransitions.add(TaskStatus.CANCELLED);
diff --git a/ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml
new file mode 100644
index 0000000..65e76ae
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml
@@ -0,0 +1,44 @@
+<?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.DepartmentSyncMapper">
+
+ <resultMap type="DepartmentSyncDTO" id="DepartmentSyncResult">
+ <result property="departmentId" column="departmentID" />
+ <result property="departmentName" column="departmentName" />
+ <result property="parentId" column="parentID" />
+ <result property="parentName" column="parentName" />
+ </resultMap>
+
+ <!-- 鏌ヨ鍚堜綔鍗曚綅涓嬬殑鎵�鏈夊垎鍏徃 -->
+ <select id="selectBranchDepartments" resultMap="DepartmentSyncResult">
+ <![CDATA[
+ SELECT
+ b.departmentID,
+ b.departmentName,
+ b.parentID,
+ a.departmentName AS parentName
+ FROM uv_department a
+ INNER JOIN uv_department b ON a.departmentID = b.parentID
+ WHERE a.departmentName = N'鍚堜綔鍗曚綅'
+ ORDER BY b.departmentName
+ ]]>
+ </select>
+
+ <!-- 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬 -->
+ <select id="selectTransportDepartments" resultMap="DepartmentSyncResult">
+ <![CDATA[
+ SELECT
+ b.departmentID,
+ b.departmentName,
+ b.parentID,
+ a.departmentName AS parentName
+ FROM uv_department a
+ INNER JOIN uv_department b ON a.departmentID = b.parentID
+ WHERE a.departmentName = N'杞繍閮�'
+ ORDER BY b.departmentName
+ ]]>
+ </select>
+
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/HospDataMapper.xml b/ruoyi-system/src/main/resources/mapper/system/HospDataMapper.xml
new file mode 100644
index 0000000..6be16ba
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/HospDataMapper.xml
@@ -0,0 +1,51 @@
+<?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.HospDataMapper">
+
+ <resultMap type="HospData" id="HospDataResult">
+ <result property="hospId" column="HospID" />
+ <result property="hospName" column="HospName" />
+ <result property="hospCityId" column="HospCityID" />
+ <result property="hospShort" column="HospShort" />
+ <result property="hopsProvince" column="HopsProvince" />
+ <result property="hopsCity" column="HopsCity" />
+ <result property="hopsArea" column="HopsArea" />
+ <result property="hospAddress" column="HospAddress" />
+ <result property="hospTel" column="HospTEL" />
+ <result property="hospUnitId" column="HospUnitID" />
+ <result property="hospState" column="HospState" />
+ <result property="hospOaId" column="HospOAID" />
+ <result property="hospIntroducerId" column="HospIntroducerID" />
+ <result property="hospIntroducerDate" column="HospIntroducerDate" />
+ <result property="hospLevel" column="HospLevel" />
+ </resultMap>
+
+ <select id="searchHospitals" parameterType="String" resultMap="HospDataResult">
+ SELECT TOP 50
+ HospID, HospName, HospCityID, HospShort,
+ HopsProvince, HopsCity, HopsArea, HospAddress,
+ HospTEL, HospUnitID, HospState, HospOAID,
+ HospIntroducerID, HospIntroducerDate, HospLevel
+ FROM HospData
+ WHERE 1=1
+ <if test="keyword != null and keyword != ''">
+ AND (HospName LIKE '%' + #{keyword} + '%'
+ OR HospAddress LIKE '%' + #{keyword} + '%'
+ OR HospShort LIKE '%' + #{keyword} + '%')
+ </if>
+ AND (HospState IS NULL OR HospState = 1)
+ ORDER BY HospName
+ </select>
+
+ <select id="selectHospDataById" parameterType="Integer" resultMap="HospDataResult">
+ SELECT
+ HospID, HospName, HospCityID, HospShort,
+ HopsProvince, HopsCity, HopsArea, HospAddress,
+ HospTEL, HospUnitID, HospState, HospOAID,
+ HospIntroducerID, HospIntroducerDate, HospLevel
+ FROM HospData
+ WHERE HospID = #{hospId}
+ </select>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/Icd10Mapper.xml b/ruoyi-system/src/main/resources/mapper/system/Icd10Mapper.xml
new file mode 100644
index 0000000..37ba9a4
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/Icd10Mapper.xml
@@ -0,0 +1,40 @@
+<?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.Icd10Mapper">
+
+ <resultMap type="Icd10" id="Icd10Result">
+ <result property="id" column="id" />
+ <result property="icdCode" column="icd_code" />
+ <result property="xh" column="xh" />
+ <result property="fm" column="fm" />
+ <result property="icdName" column="icd_name" />
+ <result property="zjm" column="zjm" />
+ <result property="sm" column="sm" />
+ <result property="sbxz" column="sbxz" />
+ <result property="lxxz" column="lxxz" />
+ <result property="icdState" column="ICDState" />
+ </resultMap>
+
+ <select id="searchIcd10" parameterType="String" resultMap="Icd10Result">
+ SELECT TOP 50
+ id, icd_code, xh, fm, icd_name, zjm, sm, sbxz, lxxz, ICDState
+ FROM ICD10
+ WHERE 1=1
+ <if test="keyword != null and keyword != ''">
+ AND (icd_name LIKE '%' + #{keyword} + '%'
+ OR icd_code LIKE '%' + #{keyword} + '%'
+ OR zjm LIKE '%' + #{keyword} + '%')
+ </if>
+ AND (ICDState IS NULL OR ICDState = 1)
+ ORDER BY icd_name
+ </select>
+
+ <select id="selectIcd10ById" parameterType="Integer" resultMap="Icd10Result">
+ SELECT
+ id, icd_code, xh, fm, icd_name, zjm, sm, sbxz, lxxz, ICDState
+ FROM ICD10
+ WHERE id = #{id}
+ </select>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
index cf439f6..b5fab18 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -16,6 +16,7 @@
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="parentName" column="parent_name" />
+ <result property="departmentId" column="department_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@@ -23,7 +24,7 @@
</resultMap>
<sql id="selectDeptVo">
- select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time
+ select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.department_id, d.create_by, d.create_time
from sys_dept d
</sql>
@@ -59,7 +60,7 @@
</select>
<select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
- select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,
+ select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.department_id,
(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
from sys_dept d
where d.dept_id = #{deptId}
@@ -98,6 +99,7 @@
<if test="phone != null and phone != ''">phone,</if>
<if test="email != null and email != ''">email,</if>
<if test="status != null">status,</if>
+ <if test="departmentId != null">department_id,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
create_time
)values(
@@ -110,6 +112,7 @@
<if test="phone != null and phone != ''">#{phone},</if>
<if test="email != null and email != ''">#{email},</if>
<if test="status != null">#{status},</if>
+ <if test="departmentId != null">#{departmentId},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate()
)
@@ -126,6 +129,7 @@
<if test="phone != null">phone = #{phone},</if>
<if test="email != null">email = #{email},</if>
<if test="status != null and status != ''">status = #{status},</if>
+ <if test="departmentId != null">department_id = #{departmentId},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = sysdate()
</set>
@@ -156,4 +160,20 @@
update sys_dept set del_flag = '2' where dept_id = #{deptId}
</delete>
+ <!-- 鏍规嵁departmentId鏌ヨ閮ㄩ棬 -->
+ <select id="selectDeptByDepartmentId" parameterType="Integer" resultMap="SysDeptResult">
+ <include refid="selectDeptVo"/>
+ where d.department_id = #{departmentId} and d.del_flag = '0'
+ limit 1
+ </select>
+
+ <!-- 鏍规嵁departmentId鍜岀埗閮ㄩ棬ID鏌ヨ閮ㄩ棬 -->
+ <select id="selectDeptByDepartmentIdAndParentId" resultMap="SysDeptResult">
+ <include refid="selectDeptVo"/>
+ where d.department_id = #{departmentId}
+ and d.parent_id = #{parentId}
+ and d.del_flag = '0'
+ limit 1
+ </select>
+
</mapper>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
new file mode 100644
index 0000000..081a4e3
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
@@ -0,0 +1,160 @@
+<?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.SysTaskEmergencyMapper">
+
+ <resultMap type="SysTaskEmergency" id="SysTaskEmergencyResult">
+ <result property="id" column="id" />
+ <result property="taskId" column="task_id" />
+ <result property="patientContact" column="patient_contact" />
+ <result property="patientPhone" column="patient_phone" />
+ <result property="patientName" column="patient_name" />
+ <result property="patientGender" column="patient_gender" />
+ <result property="patientIdCard" column="patient_id_card" />
+ <result property="patientCondition" column="patient_condition" />
+ <result property="hospitalOutName" column="hospital_out_name" />
+ <result property="hospitalOutDepartment" column="hospital_out_department" />
+ <result property="hospitalOutBedNumber" column="hospital_out_bed_number" />
+ <result property="hospitalOutAddress" column="hospital_out_address" />
+ <result property="hospitalOutLongitude" column="hospital_out_longitude" />
+ <result property="hospitalOutLatitude" column="hospital_out_latitude" />
+ <result property="hospitalInName" column="hospital_in_name" />
+ <result property="hospitalInDepartment" column="hospital_in_department" />
+ <result property="hospitalInBedNumber" column="hospital_in_bed_number" />
+ <result property="hospitalInAddress" column="hospital_in_address" />
+ <result property="hospitalInLongitude" column="hospital_in_longitude" />
+ <result property="hospitalInLatitude" column="hospital_in_latitude" />
+ <result property="transferDistance" column="transfer_distance" />
+ <result property="transferPrice" column="transfer_price" />
+ <result property="passengerContact" column="passenger_contact" />
+ <result property="passengerPhone" column="passenger_phone" />
+ <result property="createTime" column="create_time" />
+ <result property="updateTime" column="update_time" />
+ <result property="createBy" column="create_by" />
+ <result property="updateBy" column="update_by" />
+ </resultMap>
+
+ <sql id="selectSysTaskEmergencyVo">
+ select id, task_id, patient_contact, patient_phone, patient_name, patient_gender,
+ patient_id_card, patient_condition, hospital_out_name, hospital_out_department,
+ hospital_out_bed_number, hospital_out_address, hospital_out_longitude,
+ hospital_out_latitude, hospital_in_name, hospital_in_department,
+ hospital_in_bed_number, hospital_in_address, hospital_in_longitude,
+ hospital_in_latitude, transfer_distance, transfer_price, passenger_contact,
+ passenger_phone, create_time, update_time, create_by, update_by
+ from sys_task_emergency
+ </sql>
+
+ <select id="selectSysTaskEmergencyById" parameterType="Long" resultMap="SysTaskEmergencyResult">
+ <include refid="selectSysTaskEmergencyVo"/>
+ where id = #{id}
+ </select>
+
+ <select id="selectSysTaskEmergencyByTaskId" parameterType="Long" resultMap="SysTaskEmergencyResult">
+ <include refid="selectSysTaskEmergencyVo"/>
+ where task_id = #{taskId}
+ </select>
+
+ <insert id="insertSysTaskEmergency" parameterType="SysTaskEmergency" useGeneratedKeys="true" keyProperty="id">
+ insert into sys_task_emergency
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="taskId != null">task_id,</if>
+ <if test="patientContact != null">patient_contact,</if>
+ <if test="patientPhone != null">patient_phone,</if>
+ <if test="patientName != null">patient_name,</if>
+ <if test="patientGender != null">patient_gender,</if>
+ <if test="patientIdCard != null">patient_id_card,</if>
+ <if test="patientCondition != null">patient_condition,</if>
+ <if test="hospitalOutName != null">hospital_out_name,</if>
+ <if test="hospitalOutDepartment != null">hospital_out_department,</if>
+ <if test="hospitalOutBedNumber != null">hospital_out_bed_number,</if>
+ <if test="hospitalOutAddress != null">hospital_out_address,</if>
+ <if test="hospitalOutLongitude != null">hospital_out_longitude,</if>
+ <if test="hospitalOutLatitude != null">hospital_out_latitude,</if>
+ <if test="hospitalInName != null">hospital_in_name,</if>
+ <if test="hospitalInDepartment != null">hospital_in_department,</if>
+ <if test="hospitalInBedNumber != null">hospital_in_bed_number,</if>
+ <if test="hospitalInAddress != null">hospital_in_address,</if>
+ <if test="hospitalInLongitude != null">hospital_in_longitude,</if>
+ <if test="hospitalInLatitude != null">hospital_in_latitude,</if>
+ <if test="transferDistance != null">transfer_distance,</if>
+ <if test="transferPrice != null">transfer_price,</if>
+ <if test="passengerContact != null">passenger_contact,</if>
+ <if test="passengerPhone != null">passenger_phone,</if>
+ <if test="createTime != null">create_time,</if>
+ <if test="updateTime != null">update_time,</if>
+ <if test="createBy != null">create_by,</if>
+ <if test="updateBy != null">update_by,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="taskId != null">#{taskId},</if>
+ <if test="patientContact != null">#{patientContact},</if>
+ <if test="patientPhone != null">#{patientPhone},</if>
+ <if test="patientName != null">#{patientName},</if>
+ <if test="patientGender != null">#{patientGender},</if>
+ <if test="patientIdCard != null">#{patientIdCard},</if>
+ <if test="patientCondition != null">#{patientCondition},</if>
+ <if test="hospitalOutName != null">#{hospitalOutName},</if>
+ <if test="hospitalOutDepartment != null">#{hospitalOutDepartment},</if>
+ <if test="hospitalOutBedNumber != null">#{hospitalOutBedNumber},</if>
+ <if test="hospitalOutAddress != null">#{hospitalOutAddress},</if>
+ <if test="hospitalOutLongitude != null">#{hospitalOutLongitude},</if>
+ <if test="hospitalOutLatitude != null">#{hospitalOutLatitude},</if>
+ <if test="hospitalInName != null">#{hospitalInName},</if>
+ <if test="hospitalInDepartment != null">#{hospitalInDepartment},</if>
+ <if test="hospitalInBedNumber != null">#{hospitalInBedNumber},</if>
+ <if test="hospitalInAddress != null">#{hospitalInAddress},</if>
+ <if test="hospitalInLongitude != null">#{hospitalInLongitude},</if>
+ <if test="hospitalInLatitude != null">#{hospitalInLatitude},</if>
+ <if test="transferDistance != null">#{transferDistance},</if>
+ <if test="transferPrice != null">#{transferPrice},</if>
+ <if test="passengerContact != null">#{passengerContact},</if>
+ <if test="passengerPhone != null">#{passengerPhone},</if>
+ <if test="createTime != null">#{createTime},</if>
+ <if test="updateTime != null">#{updateTime},</if>
+ <if test="createBy != null">#{createBy},</if>
+ <if test="updateBy != null">#{updateBy},</if>
+ </trim>
+ </insert>
+
+ <update id="updateSysTaskEmergency" parameterType="SysTaskEmergency">
+ update sys_task_emergency
+ <trim prefix="SET" suffixOverrides=",">
+ <if test="patientContact != null">patient_contact = #{patientContact},</if>
+ <if test="patientPhone != null">patient_phone = #{patientPhone},</if>
+ <if test="patientName != null">patient_name = #{patientName},</if>
+ <if test="patientGender != null">patient_gender = #{patientGender},</if>
+ <if test="patientIdCard != null">patient_id_card = #{patientIdCard},</if>
+ <if test="patientCondition != null">patient_condition = #{patientCondition},</if>
+ <if test="hospitalOutName != null">hospital_out_name = #{hospitalOutName},</if>
+ <if test="hospitalOutDepartment != null">hospital_out_department = #{hospitalOutDepartment},</if>
+ <if test="hospitalOutBedNumber != null">hospital_out_bed_number = #{hospitalOutBedNumber},</if>
+ <if test="hospitalOutAddress != null">hospital_out_address = #{hospitalOutAddress},</if>
+ <if test="hospitalOutLongitude != null">hospital_out_longitude = #{hospitalOutLongitude},</if>
+ <if test="hospitalOutLatitude != null">hospital_out_latitude = #{hospitalOutLatitude},</if>
+ <if test="hospitalInName != null">hospital_in_name = #{hospitalInName},</if>
+ <if test="hospitalInDepartment != null">hospital_in_department = #{hospitalInDepartment},</if>
+ <if test="hospitalInBedNumber != null">hospital_in_bed_number = #{hospitalInBedNumber},</if>
+ <if test="hospitalInAddress != null">hospital_in_address = #{hospitalInAddress},</if>
+ <if test="hospitalInLongitude != null">hospital_in_longitude = #{hospitalInLongitude},</if>
+ <if test="hospitalInLatitude != null">hospital_in_latitude = #{hospitalInLatitude},</if>
+ <if test="transferDistance != null">transfer_distance = #{transferDistance},</if>
+ <if test="transferPrice != null">transfer_price = #{transferPrice},</if>
+ <if test="passengerContact != null">passenger_contact = #{passengerContact},</if>
+ <if test="passengerPhone != null">passenger_phone = #{passengerPhone},</if>
+ <if test="updateTime != null">update_time = #{updateTime},</if>
+ <if test="updateBy != null">update_by = #{updateBy},</if>
+ </trim>
+ where id = #{id}
+ </update>
+
+ <delete id="deleteSysTaskEmergencyById" parameterType="Long">
+ delete from sys_task_emergency where id = #{id}
+ </delete>
+
+ <delete id="deleteSysTaskEmergencyByTaskId" parameterType="Long">
+ delete from sys_task_emergency where task_id = #{taskId}
+ </delete>
+
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml
index 0144d40..71fa476 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml
@@ -15,11 +15,23 @@
<result property="operatorName" column="operator_name" />
<result property="operationTime" column="operation_time" />
<result property="ipAddress" column="ip_address" />
+ <result property="latitude" column="latitude" />
+ <result property="longitude" column="longitude" />
+ <result property="locationAddress" column="location_address" />
+ <result property="locationProvince" column="location_province" />
+ <result property="locationCity" column="location_city" />
+ <result property="locationDistrict" column="location_district" />
+ <result property="gpsAccuracy" column="gps_accuracy" />
+ <result property="altitude" column="altitude" />
+ <result property="speed" column="speed" />
+ <result property="heading" column="heading" />
</resultMap>
<sql id="selectSysTaskLogVo">
select log_id, task_id, operation_type, operation_desc, old_value, new_value,
- operator_id, operator_name, operation_time, ip_address
+ operator_id, operator_name, operation_time, ip_address,
+ latitude, longitude, location_address, location_province,
+ location_city, location_district, gps_accuracy, altitude, speed, heading
from sys_task_log
</sql>
@@ -57,6 +69,16 @@
<if test="operatorName != null and operatorName != ''">operator_name,</if>
<if test="operationTime != null">operation_time,</if>
<if test="ipAddress != null">ip_address,</if>
+ <if test="latitude != null">latitude,</if>
+ <if test="longitude != null">longitude,</if>
+ <if test="locationAddress != null">location_address,</if>
+ <if test="locationProvince != null">location_province,</if>
+ <if test="locationCity != null">location_city,</if>
+ <if test="locationDistrict != null">location_district,</if>
+ <if test="gpsAccuracy != null">gps_accuracy,</if>
+ <if test="altitude != null">altitude,</if>
+ <if test="speed != null">speed,</if>
+ <if test="heading != null">heading,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="taskId != null">#{taskId},</if>
@@ -68,6 +90,16 @@
<if test="operatorName != null and operatorName != ''">#{operatorName},</if>
<if test="operationTime != null">#{operationTime},</if>
<if test="ipAddress != null">#{ipAddress},</if>
+ <if test="latitude != null">#{latitude},</if>
+ <if test="longitude != null">#{longitude},</if>
+ <if test="locationAddress != null">#{locationAddress},</if>
+ <if test="locationProvince != null">#{locationProvince},</if>
+ <if test="locationCity != null">#{locationCity},</if>
+ <if test="locationDistrict != null">#{locationDistrict},</if>
+ <if test="gpsAccuracy != null">#{gpsAccuracy},</if>
+ <if test="altitude != null">#{altitude},</if>
+ <if test="speed != null">#{speed},</if>
+ <if test="heading != null">#{heading},</if>
</trim>
</insert>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
index 599cd7e..c0de83d 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
@@ -33,6 +33,19 @@
<result property="creatorName" column="creator_name" />
<result property="assigneeName" column="assignee_name" />
<result property="deptName" column="dept_name" />
+ <collection property="assignedVehicles" ofType="SysTaskVehicle">
+ <result property="id" column="tv_id" />
+ <result property="taskId" column="tv_task_id" />
+ <result property="vehicleId" column="tv_vehicle_id" />
+ <result property="vehicleNo" column="tv_vehicle_no" />
+ <result property="vehicleType" column="tv_vehicle_type" />
+ <result property="vehicleBrand" column="tv_vehicle_brand" />
+ <result property="vehicleModel" column="tv_vehicle_model" />
+ <result property="assignTime" column="tv_assign_time" />
+ <result property="assignBy" column="tv_assign_by" />
+ <result property="status" column="tv_status" />
+ <result property="remark" column="tv_remark" />
+ </collection>
</resultMap>
<sql id="selectSysTaskVo">
@@ -42,11 +55,18 @@
t.planned_start_time, t.planned_end_time,
t.actual_start_time, t.actual_end_time, t.creator_id, t.assignee_id, t.dept_id,
t.create_time, t.update_time, t.create_by, t.update_by, t.remark, t.del_flag,
- u1.nick_name as creator_name, u2.nick_name as assignee_name, d.dept_name
+ u1.nick_name as creator_name, u2.nick_name as assignee_name, d.dept_name,
+ tv.id as tv_id, tv.task_id as tv_task_id, tv.vehicle_id as tv_vehicle_id,
+ v.vehicle_no as tv_vehicle_no, v.vehicle_type as tv_vehicle_type,
+ v.vehicle_brand as tv_vehicle_brand, v.vehicle_model as tv_vehicle_model,
+ tv.assign_time as tv_assign_time, tv.assign_by as tv_assign_by,
+ tv.status as tv_status, tv.remark as tv_remark
from sys_task t
left join sys_user u1 on t.creator_id = u1.user_id
left join sys_user u2 on t.assignee_id = u2.user_id
left join sys_dept d on t.dept_id = d.dept_id
+ left join sys_task_vehicle tv on t.task_id = tv.task_id
+ left join tb_vehicle_info v on tv.vehicle_id = v.vehicle_id
</sql>
<select id="selectSysTaskList" parameterType="TaskQueryVO" resultMap="SysTaskResult">
@@ -56,16 +76,38 @@
<if test="taskCode != null and taskCode != ''"> and t.task_code like concat('%', #{taskCode}, '%')</if>
<if test="taskType != null and taskType != ''"> and t.task_type = #{taskType}</if>
<if test="taskStatus != null and taskStatus != ''"> and t.task_status = #{taskStatus}</if>
- <if test="creatorId != null "> and t.creator_id = #{creatorId}</if>
- <if test="assigneeId != null "> and t.assignee_id = #{assigneeId}</if>
- <if test="deptId != null "> and t.dept_id = #{deptId}</if>
+ <!-- 缁煎悎鏌ヨ锛氬綋鍓嶇敤鎴锋墍鍦ㄦ満鏋� OR 褰撳墠鐢ㄦ埛鍒涘缓 OR 鍒嗛厤缁欏綋鍓嶇敤鎴� -->
+ <if test="(creatorId != null and creatorId != 0) or (assigneeId != null and assigneeId != 0) or (deptId != null and deptId != 0)">
+ and (
+ <if test="deptId != null and deptId != 0">t.dept_id = #{deptId}</if>
+ <if test="creatorId != null and creatorId != 0">
+ <if test="deptId != null and deptId != 0"> or </if>
+ t.creator_id = #{creatorId}
+ </if>
+ <if test="assigneeId != null and assigneeId != 0">
+ <if test="(deptId != null and deptId != 0) or (creatorId != null and creatorId != 0)"> or </if>
+ t.assignee_id = #{assigneeId}
+ </if>
+ )
+ </if>
<if test="plannedStartTimeBegin != null "> and t.planned_start_time >= #{plannedStartTimeBegin}</if>
<if test="plannedStartTimeEnd != null "> and t.planned_start_time <= #{plannedStartTimeEnd}</if>
<if test="plannedEndTimeBegin != null "> and t.planned_end_time >= #{plannedEndTimeBegin}</if>
<if test="plannedEndTimeEnd != null "> and t.planned_end_time <= #{plannedEndTimeEnd}</if>
<if test="overdue != null and overdue == true"> and t.planned_end_time < now() and t.task_status != 'COMPLETED'</if>
</where>
- order by t.create_time desc
+ order by
+ CASE t.task_status
+ WHEN 'PENDING' THEN 1
+ WHEN 'DEPARTING' THEN 2
+ WHEN 'ARRIVED' THEN 3
+ WHEN 'RETURNING' THEN 4
+ WHEN 'IN_PROGRESS' THEN 5
+ WHEN 'COMPLETED' THEN 6
+ WHEN 'CANCELLED' THEN 7
+ ELSE 8
+ END,
+ t.create_time desc
</select>
<select id="selectSysTaskByTaskId" parameterType="Long" resultMap="SysTaskResult">
@@ -93,7 +135,19 @@
<select id="selectMyTasks" parameterType="Long" resultMap="SysTaskResult">
<include refid="selectSysTaskVo"/>
where t.del_flag = '0' and (t.creator_id = #{userId} or t.assignee_id = #{userId})
- order by t.create_time desc
+ order by
+ CASE t.task_status
+ WHEN 'PENDING' THEN 1
+ WHEN 'DEPARTING' THEN 2
+ WHEN 'ARRIVED' THEN 3
+ WHEN 'RETURNING' THEN 4
+ WHEN 'IN_PROGRESS' THEN 5
+ WHEN 'COMPLETED' THEN 6
+ WHEN 'CANCELLED' THEN 7
+ ELSE 8
+ END,
+ t.update_time desc,
+ t.create_time desc
</select>
<select id="selectTaskStatistics" resultType="TaskStatisticsVO">
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskWelfareMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskWelfareMapper.xml
new file mode 100644
index 0000000..896adf1
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskWelfareMapper.xml
@@ -0,0 +1,134 @@
+<?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.SysTaskWelfareMapper">
+
+ <resultMap type="SysTaskWelfare" id="SysTaskWelfareResult">
+ <result property="id" column="id" />
+ <result property="taskId" column="task_id" />
+ <result property="passengerContact" column="passenger_contact" />
+ <result property="passengerPhone" column="passenger_phone" />
+ <result property="passengerName" column="passenger_name" />
+ <result property="passengerAge" column="passenger_age" />
+ <result property="passengerGender" column="passenger_gender" />
+ <result property="passengerIdCard" column="passenger_id_card" />
+ <result property="specialNeeds" column="special_needs" />
+ <result property="serviceType" column="service_type" />
+ <result property="pickupAddress" column="pickup_address" />
+ <result property="pickupLongitude" column="pickup_longitude" />
+ <result property="pickupLatitude" column="pickup_latitude" />
+ <result property="destinationAddress" column="destination_address" />
+ <result property="destinationLongitude" column="destination_longitude" />
+ <result property="destinationLatitude" column="destination_latitude" />
+ <result property="serviceDistance" column="service_distance" />
+ <result property="servicePrice" column="service_price" />
+ <result property="createTime" column="create_time" />
+ <result property="updateTime" column="update_time" />
+ <result property="createBy" column="create_by" />
+ <result property="updateBy" column="update_by" />
+ </resultMap>
+
+ <sql id="selectSysTaskWelfareVo">
+ select id, task_id, passenger_contact, passenger_phone, passenger_name, passenger_age,
+ passenger_gender, passenger_id_card, special_needs, service_type, pickup_address,
+ pickup_longitude, pickup_latitude, destination_address, destination_longitude,
+ destination_latitude, service_distance, service_price, create_time, update_time,
+ create_by, update_by
+ from sys_task_welfare
+ </sql>
+
+ <select id="selectSysTaskWelfareById" parameterType="Long" resultMap="SysTaskWelfareResult">
+ <include refid="selectSysTaskWelfareVo"/>
+ where id = #{id}
+ </select>
+
+ <select id="selectSysTaskWelfareByTaskId" parameterType="Long" resultMap="SysTaskWelfareResult">
+ <include refid="selectSysTaskWelfareVo"/>
+ where task_id = #{taskId}
+ </select>
+
+ <insert id="insertSysTaskWelfare" parameterType="SysTaskWelfare" useGeneratedKeys="true" keyProperty="id">
+ insert into sys_task_welfare
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="taskId != null">task_id,</if>
+ <if test="passengerContact != null">passenger_contact,</if>
+ <if test="passengerPhone != null">passenger_phone,</if>
+ <if test="passengerName != null">passenger_name,</if>
+ <if test="passengerAge != null">passenger_age,</if>
+ <if test="passengerGender != null">passenger_gender,</if>
+ <if test="passengerIdCard != null">passenger_id_card,</if>
+ <if test="specialNeeds != null">special_needs,</if>
+ <if test="serviceType != null">service_type,</if>
+ <if test="pickupAddress != null">pickup_address,</if>
+ <if test="pickupLongitude != null">pickup_longitude,</if>
+ <if test="pickupLatitude != null">pickup_latitude,</if>
+ <if test="destinationAddress != null">destination_address,</if>
+ <if test="destinationLongitude != null">destination_longitude,</if>
+ <if test="destinationLatitude != null">destination_latitude,</if>
+ <if test="serviceDistance != null">service_distance,</if>
+ <if test="servicePrice != null">service_price,</if>
+ <if test="createTime != null">create_time,</if>
+ <if test="updateTime != null">update_time,</if>
+ <if test="createBy != null">create_by,</if>
+ <if test="updateBy != null">update_by,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="taskId != null">#{taskId},</if>
+ <if test="passengerContact != null">#{passengerContact},</if>
+ <if test="passengerPhone != null">#{passengerPhone},</if>
+ <if test="passengerName != null">#{passengerName},</if>
+ <if test="passengerAge != null">#{passengerAge},</if>
+ <if test="passengerGender != null">#{passengerGender},</if>
+ <if test="passengerIdCard != null">#{passengerIdCard},</if>
+ <if test="specialNeeds != null">#{specialNeeds},</if>
+ <if test="serviceType != null">#{serviceType},</if>
+ <if test="pickupAddress != null">#{pickupAddress},</if>
+ <if test="pickupLongitude != null">#{pickupLongitude},</if>
+ <if test="pickupLatitude != null">#{pickupLatitude},</if>
+ <if test="destinationAddress != null">#{destinationAddress},</if>
+ <if test="destinationLongitude != null">#{destinationLongitude},</if>
+ <if test="destinationLatitude != null">#{destinationLatitude},</if>
+ <if test="serviceDistance != null">#{serviceDistance},</if>
+ <if test="servicePrice != null">#{servicePrice},</if>
+ <if test="createTime != null">#{createTime},</if>
+ <if test="updateTime != null">#{updateTime},</if>
+ <if test="createBy != null">#{createBy},</if>
+ <if test="updateBy != null">#{updateBy},</if>
+ </trim>
+ </insert>
+
+ <update id="updateSysTaskWelfare" parameterType="SysTaskWelfare">
+ update sys_task_welfare
+ <trim prefix="SET" suffixOverrides=",">
+ <if test="passengerContact != null">passenger_contact = #{passengerContact},</if>
+ <if test="passengerPhone != null">passenger_phone = #{passengerPhone},</if>
+ <if test="passengerName != null">passenger_name = #{passengerName},</if>
+ <if test="passengerAge != null">passenger_age = #{passengerAge},</if>
+ <if test="passengerGender != null">passenger_gender = #{passengerGender},</if>
+ <if test="passengerIdCard != null">passenger_id_card = #{passengerIdCard},</if>
+ <if test="specialNeeds != null">special_needs = #{specialNeeds},</if>
+ <if test="serviceType != null">service_type = #{serviceType},</if>
+ <if test="pickupAddress != null">pickup_address = #{pickupAddress},</if>
+ <if test="pickupLongitude != null">pickup_longitude = #{pickupLongitude},</if>
+ <if test="pickupLatitude != null">pickup_latitude = #{pickupLatitude},</if>
+ <if test="destinationAddress != null">destination_address = #{destinationAddress},</if>
+ <if test="destinationLongitude != null">destination_longitude = #{destinationLongitude},</if>
+ <if test="destinationLatitude != null">destination_latitude = #{destinationLatitude},</if>
+ <if test="serviceDistance != null">service_distance = #{serviceDistance},</if>
+ <if test="servicePrice != null">service_price = #{servicePrice},</if>
+ <if test="updateTime != null">update_time = #{updateTime},</if>
+ <if test="updateBy != null">update_by = #{updateBy},</if>
+ </trim>
+ where id = #{id}
+ </update>
+
+ <delete id="deleteSysTaskWelfareById" parameterType="Long">
+ delete from sys_task_welfare where id = #{id}
+ </delete>
+
+ <delete id="deleteSysTaskWelfareByTaskId" parameterType="Long">
+ delete from sys_task_welfare where task_id = #{taskId}
+ </delete>
+
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
index 5b2a7f2..8c40c86 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -18,6 +18,7 @@
<result property="delFlag" column="del_flag" />
<result property="loginIp" column="login_ip" />
<result property="loginDate" column="login_date" />
+ <result property="oaUserId" column="oa_user_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@@ -47,7 +48,7 @@
</resultMap>
<sql id="selectUserVo">
- select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
+ select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.oa_user_id, u.create_by, u.create_time, u.remark,
d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
from sys_user u
@@ -154,6 +155,7 @@
<if test="sex != null and sex != ''">sex,</if>
<if test="password != null and password != ''">password,</if>
<if test="status != null and status != ''">status,</if>
+ <if test="oaUserId != null">oa_user_id,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
@@ -168,6 +170,7 @@
<if test="sex != null and sex != ''">#{sex},</if>
<if test="password != null and password != ''">#{password},</if>
<if test="status != null and status != ''">#{status},</if>
+ <if test="oaUserId != null">#{oaUserId},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
@@ -185,6 +188,7 @@
<if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
<if test="password != null and password != ''">password = #{password},</if>
<if test="status != null and status != ''">status = #{status},</if>
+ <if test="oaUserId != null">oa_user_id = #{oaUserId},</if>
<if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
<if test="loginDate != null">login_date = #{loginDate},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
@@ -216,5 +220,13 @@
#{userId}
</foreach>
</delete>
+
+ <!-- 鏍规嵁oaUserId鏌ヨ鐢ㄦ埛 -->
+ <select id="selectUserByOaUserId" parameterType="Integer" resultMap="SysUserResult">
+ select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.sex, u.status, u.oa_user_id
+ from sys_user u
+ where u.oa_user_id = #{oaUserId} and u.del_flag = '0'
+ limit 1
+ </select>
</mapper>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
new file mode 100644
index 0000000..818d0c5
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
@@ -0,0 +1,37 @@
+<?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.UserSyncMapper">
+
+ <resultMap type="UserSyncDTO" id="UserSyncResult">
+ <result property="oaUserId" column="OA_UserID" />
+ <result property="userName" column="user_name" />
+ <result property="nickName" column="nick_name" />
+ <result property="departmentId" column="department_id" />
+ <result property="sex" column="sex" />
+ <result property="email" column="email" />
+ <result property="phonenumber" column="phonenumber" />
+ </resultMap>
+
+ <!-- 鏌ヨSQL Server涓殑OA鐢ㄦ埛鍒楄〃 -->
+ <select id="selectOaUsers" resultMap="UserSyncResult">
+ <![CDATA[
+ SELECT
+ OA_User_ID AS OA_UserID,
+ OA_User AS user_name,
+ OA_Name AS nick_name,
+ OA_departmentID AS department_id,
+ OA_gender AS sex,
+ OA_email AS email,
+ OA_mobile AS phonenumber
+ FROM OA_User
+ WHERE OA_User IS NOT NULL
+ AND OA_Name IS NOT NULL
+ AND LEN(RTRIM(LTRIM(OA_User))) > 0
+ AND LEN(RTRIM(LTRIM(OA_Name))) > 0
+ ORDER BY OA_User_ID
+ ]]>
+ </select>
+
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
index 885e016..d011369 100644
--- a/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
@@ -114,4 +114,34 @@
#{vehicleId}
</foreach>
</delete>
+
+ <!-- 缁戝畾杞﹁締鍒扮敤鎴� -->
+ <insert id="bindVehicleToUser">
+ INSERT INTO sys_user_vehicle (user_id, vehicle_id, bind_time, bind_by, status, create_by, create_time)
+ VALUES (#{userId}, #{vehicleId}, NOW(), #{bindBy}, '0', #{bindBy}, NOW())
+ </insert>
+
+ <!-- 瑙g粦鐢ㄦ埛杞﹁締 -->
+ <update id="unbindVehicleFromUser">
+ UPDATE sys_user_vehicle
+ SET status = '1', update_time = NOW()
+ WHERE user_id = #{userId} AND vehicle_id = #{vehicleId} AND status = '0'
+ </update>
+
+ <!-- 瑙g粦鐢ㄦ埛鐨勬墍鏈夎溅杈� -->
+ <update id="unbindAllVehiclesFromUser">
+ UPDATE sys_user_vehicle
+ SET status = '1', update_time = NOW()
+ WHERE user_id = #{userId} AND status = '0'
+ </update>
+
+ <!-- 鑾峰彇鐢ㄦ埛褰撳墠缁戝畾鐨勮溅杈� -->
+ <select id="getUserBoundVehicle" resultMap="VehicleInfoResult">
+ SELECT v.*
+ FROM tb_vehicle_info v
+ INNER JOIN sys_user_vehicle uv ON v.vehicle_id = uv.vehicle_id
+ WHERE uv.user_id = #{userId} AND uv.status = '0'
+ ORDER BY uv.bind_time DESC
+ LIMIT 1
+ </select>
</mapper>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/dept/index.vue
index e502b4e..258e90e 100644
--- a/ruoyi-ui/src/views/system/dept/index.vue
+++ b/ruoyi-ui/src/views/system/dept/index.vue
@@ -53,11 +53,18 @@
v-loading="loading"
:data="deptList"
row-key="deptId"
- :default-expand-all="isExpandAll"
+ :default-expand-all="false"
+ :expand-row-keys="expandRowKeys"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column prop="deptName" label="閮ㄩ棬鍚嶇О" width="260"></el-table-column>
- <el-table-column prop="orderNum" label="鎺掑簭" width="200"></el-table-column>
+ <el-table-column prop="departmentId" label="SQL Server閮ㄩ棬ID" width="150" align="center">
+ <template slot-scope="scope">
+ <span v-if="scope.row.departmentId">{{ scope.row.departmentId }}</span>
+ <span v-else style="color: #909399;">-</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="orderNum" label="鎺掑簭" width="150"></el-table-column>
<el-table-column prop="status" label="鐘舵��" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
@@ -115,6 +122,13 @@
<el-col :span="12">
<el-form-item label="鏄剧ず鎺掑簭" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="SQL Server閮ㄩ棬ID" prop="departmentId">
+ <el-input v-model="form.departmentId" placeholder="SQL Server涓殑閮ㄩ棬ID" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
@@ -181,7 +195,9 @@
// 鏄惁鏄剧ず寮瑰嚭灞�
open: false,
// 鏄惁灞曞紑锛岄粯璁ゅ叏閮ㄥ睍寮�
- isExpandAll: true,
+ isExpandAll: false,
+ // 榛樿灞曞紑鐨勮
+ expandRowKeys: [],
// 閲嶆柊娓叉煋琛ㄦ牸鐘舵��
refreshTable: true,
// 鏌ヨ鍙傛暟
@@ -228,6 +244,8 @@
this.loading = true;
listDept(this.queryParams).then(response => {
this.deptList = this.handleTree(response.data, "deptId");
+ // 榛樿鍙睍寮�绗竴灞傦紙鎬诲叕鍙稿強鍏剁洿鎺ュ瓙閮ㄩ棬锛�
+ this.expandRowKeys = this.deptList.map(item => item.deptId);
this.loading = false;
});
},
@@ -253,6 +271,7 @@
deptId: undefined,
parentId: undefined,
deptName: undefined,
+ departmentId: undefined,
orderNum: undefined,
leader: undefined,
phone: undefined,
@@ -286,10 +305,28 @@
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
+ if (this.isExpandAll) {
+ // 灞曞紑鍏ㄩ儴锛氭敹闆嗘墍鏈夐儴闂↖D
+ this.expandRowKeys = this.getAllDeptIds(this.deptList);
+ } else {
+ // 鏀惰捣锛氬彧灞曞紑绗竴灞�
+ this.expandRowKeys = this.deptList.map(item => item.deptId);
+ }
this.$nextTick(() => {
this.refreshTable = true;
});
},
+ /** 鑾峰彇鎵�鏈夐儴闂↖D锛堥�掑綊锛� */
+ getAllDeptIds(depts) {
+ let ids = [];
+ depts.forEach(dept => {
+ ids.push(dept.deptId);
+ if (dept.children && dept.children.length > 0) {
+ ids = ids.concat(this.getAllDeptIds(dept.children));
+ }
+ });
+ return ids;
+ },
/** 淇敼鎸夐挳鎿嶄綔 */
handleUpdate(row) {
this.reset();
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index 1dbc2d1..15fec19 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -9,7 +9,8 @@
<el-input v-model="deptName" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
</div>
<div class="head-container">
- <el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" />
+ <el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id"
+ default-expand-all="false" highlight-current @node-click="handleNodeClick" />
</div>
</el-col>
</pane>
@@ -59,16 +60,22 @@
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="鐢ㄦ埛缂栧彿" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
- <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
- <el-table-column label="鐢ㄦ埛鏄电О" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
- <el-table-column label="閮ㄩ棬" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
- <el-table-column label="鎵嬫満鍙风爜" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
- <el-table-column label="鐘舵��" align="center" key="status" v-if="columns[5].visible">
+ <el-table-column label="OA鐢ㄦ埛ID" align="center" key="oaUserId" prop="oaUserId" v-if="columns[1].visible" width="120">
+ <template slot-scope="scope">
+ <span v-if="scope.row.oaUserId">{{ scope.row.oaUserId }}</span>
+ <span v-else style="color: #909399;">-</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" key="userName" prop="userName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
+ <el-table-column label="鐢ㄦ埛鏄电О" align="center" key="nickName" prop="nickName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
+ <el-table-column label="閮ㄩ棬" align="center" key="deptName" prop="dept.deptName" v-if="columns[4].visible" :show-overflow-tooltip="true" />
+ <el-table-column label="鎵嬫満鍙风爜" align="center" key="phonenumber" prop="phonenumber" v-if="columns[5].visible" width="120" />
+ <el-table-column label="鐘舵��" align="center" key="status" v-if="columns[6].visible">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
- <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" v-if="columns[6].visible" width="160">
+ <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" v-if="columns[7].visible" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
@@ -106,6 +113,13 @@
<el-col :span="12">
<el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="OA鐢ㄦ埛ID" prop="oaUserId">
+ <el-input v-model="form.oaUserId" placeholder="OA绯荤粺鐨勭敤鎴稩D" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
@@ -279,12 +293,13 @@
// 鍒椾俊鎭�
columns: [
{ key: 0, label: `鐢ㄦ埛缂栧彿`, visible: true },
- { key: 1, label: `鐢ㄦ埛鍚嶇О`, visible: true },
- { key: 2, label: `鐢ㄦ埛鏄电О`, visible: true },
- { key: 3, label: `閮ㄩ棬`, visible: true },
- { key: 4, label: `鎵嬫満鍙风爜`, visible: true },
- { key: 5, label: `鐘舵�乣, visible: true },
- { key: 6, label: `鍒涘缓鏃堕棿`, visible: true }
+ { key: 1, label: `OA鐢ㄦ埛ID`, visible: true },
+ { key: 2, label: `鐢ㄦ埛鍚嶇О`, visible: true },
+ { key: 3, label: `鐢ㄦ埛鏄电О`, visible: true },
+ { key: 4, label: `閮ㄩ棬`, visible: true },
+ { key: 5, label: `鎵嬫満鍙风爜`, visible: true },
+ { key: 6, label: `鐘舵�乣, visible: true },
+ { key: 7, label: `鍒涘缓鏃堕棿`, visible: true }
],
// 琛ㄥ崟鏍¢獙
rules: {
@@ -393,6 +408,7 @@
deptId: undefined,
userName: undefined,
nickName: undefined,
+ oaUserId: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
diff --git a/ruoyi-ui/src/views/system/vehicle/index.vue b/ruoyi-ui/src/views/system/vehicle/index.vue
index 4049d3d..30bfde2 100644
--- a/ruoyi-ui/src/views/system/vehicle/index.vue
+++ b/ruoyi-ui/src/views/system/vehicle/index.vue
@@ -301,10 +301,15 @@
this.loading = false;
});
},
- /** 鑾峰彇閮ㄩ棬鍒楄〃 */
+ /** 鑾峰彇閮ㄩ棬鍒楄〃锛堝彧鏄剧ず鍒嗗叕鍙革細parent_id=100锛� */
getDeptList() {
- listDept().then(response => {
- this.deptList = response.data;
+ listDept({ parentId: 100 }).then(response => {
+ // 杩囨护鍑哄垎鍏徃锛坧arent_id=100鐨勯儴闂級
+ if (response.data) {
+ this.deptList = response.data.filter(dept => dept.parentId === 100);
+ } else {
+ this.deptList = [];
+ }
});
},
// 鍙栨秷鎸夐挳
diff --git a/sql/add_department_id_to_sys_dept.sql b/sql/add_department_id_to_sys_dept.sql
new file mode 100644
index 0000000..49af413
--- /dev/null
+++ b/sql/add_department_id_to_sys_dept.sql
@@ -0,0 +1,8 @@
+-- 鍦╯ys_dept琛ㄤ腑娣诲姞department_id瀛楁锛岀敤浜庤褰昐QL Server涓殑departmentID
+-- 璇ュ瓧娈电敤浜庨儴闂ㄥ悓姝ュ姛鑳�
+
+-- 娣诲姞department_id瀛楁
+ALTER TABLE sys_dept ADD COLUMN department_id INT NULL COMMENT 'SQL Server涓殑閮ㄩ棬ID';
+
+-- 涓篸epartment_id瀛楁鍒涘缓绱㈠紩锛屾彁楂樻煡璇㈡晥鐜�
+CREATE INDEX idx_department_id ON sys_dept(department_id);
diff --git a/sql/add_location_fields.sql b/sql/add_location_fields.sql
new file mode 100644
index 0000000..bdc7aa5
--- /dev/null
+++ b/sql/add_location_fields.sql
@@ -0,0 +1,25 @@
+-- 涓轰换鍔℃搷浣滄棩蹇楄〃娣诲姞GPS鍜屼綅缃俊鎭瓧娈�
+-- ----------------------------
+
+USE ruoyi-vue;
+
+-- 娣诲姞GPS鍜屼綅缃俊鎭浉鍏冲瓧娈�
+ALTER TABLE sys_task_log
+ADD COLUMN latitude DECIMAL(10, 6) COMMENT '绾害' AFTER ip_address,
+ADD COLUMN longitude DECIMAL(10, 6) COMMENT '缁忓害' AFTER latitude,
+ADD COLUMN location_address VARCHAR(500) COMMENT '浣嶇疆鍦板潃' AFTER longitude,
+ADD COLUMN location_province VARCHAR(50) COMMENT '鐪佷唤' AFTER location_address,
+ADD COLUMN location_city VARCHAR(50) COMMENT '鍩庡競' AFTER location_province,
+ADD COLUMN location_district VARCHAR(50) COMMENT '鍖哄幙' AFTER location_city,
+ADD COLUMN gps_accuracy DECIMAL(10, 2) COMMENT 'GPS绮惧害锛堢背锛�' AFTER location_district,
+ADD COLUMN altitude DECIMAL(10, 2) COMMENT '娴锋嫈楂樺害锛堢背锛�' AFTER gps_accuracy,
+ADD COLUMN speed DECIMAL(10, 2) COMMENT '閫熷害锛堢背/绉掞級' AFTER altitude,
+ADD COLUMN heading DECIMAL(10, 2) COMMENT '鏂瑰悜瑙掑害锛�0-360锛�' AFTER speed;
+
+-- 娣诲姞绱㈠紩
+ALTER TABLE sys_task_log
+ADD INDEX idx_location (latitude, longitude),
+ADD INDEX idx_operation_time_location (operation_time, latitude, longitude);
+
+-- 娣诲姞娉ㄩ噴
+ALTER TABLE sys_task_log COMMENT='浠诲姟鎿嶄綔鏃ュ織琛紙鍚獹PS瀹氫綅淇℃伅锛�';
diff --git a/sql/add_oa_user_id_to_sys_user.sql b/sql/add_oa_user_id_to_sys_user.sql
new file mode 100644
index 0000000..9c9e539
--- /dev/null
+++ b/sql/add_oa_user_id_to_sys_user.sql
@@ -0,0 +1,8 @@
+-- 鍦╯ys_user琛ㄤ腑娣诲姞oa_user_id瀛楁锛岀敤浜庤褰昐QL Server涓殑OA_User_ID
+-- 璇ュ瓧娈电敤浜庣敤鎴峰悓姝ュ姛鑳�
+
+-- 娣诲姞oa_user_id瀛楁
+ALTER TABLE sys_user ADD COLUMN oa_user_id INT NULL COMMENT 'SQL Server涓殑OA鐢ㄦ埛ID';
+
+-- 涓簅a_user_id瀛楁鍒涘缓绱㈠紩锛屾彁楂樻煡璇㈡晥鐜�
+CREATE INDEX idx_oa_user_id ON sys_user(oa_user_id);
diff --git a/sql/dept_sync_menu.sql b/sql/dept_sync_menu.sql
new file mode 100644
index 0000000..e12c7b8
--- /dev/null
+++ b/sql/dept_sync_menu.sql
@@ -0,0 +1,10 @@
+-- 閮ㄩ棬鍚屾鍔熻兘鑿滃崟SQL
+-- 鍦ㄧ郴缁熺鐞�->閮ㄩ棬绠$悊涓嬫坊鍔犲悓姝ユ寜閽殑鏉冮檺
+
+-- 鏌ヨ閮ㄩ棬绠$悊鐨勮彍鍗旾D锛堝亣璁句负103锛�
+-- 鎻掑叆閮ㄩ棬鍚屾鐨勬寜閽潈闄�
+INSERT INTO sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)
+SELECT '閮ㄩ棬鍚屾', menu_id, 6, '#', 'F', '0', 'system:dept:sync', '#', 'admin', sysdate(), '', NULL, '鍚屾SQL Server鍒嗗叕鍙告暟鎹�'
+FROM sys_menu
+WHERE menu_name = '閮ㄩ棬绠$悊' AND menu_type = 'C'
+LIMIT 1;
diff --git a/sql/icd10.sql b/sql/icd10.sql
new file mode 100644
index 0000000..596268b
--- /dev/null
+++ b/sql/icd10.sql
@@ -0,0 +1,13 @@
+create table ICD10
+(
+id int no 4 10 0 no (n/a) (n/a) NULL
+icd_code nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+xh float no 8 53 NULL yes (n/a) (n/a) NULL
+fm nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+icd_name nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+zjm nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+sm nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+sbxz nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+lxxz nvarchar no 510 yes (n/a) (n/a) Chinese_PRC_CI_AS
+ICDState int no 4 10 0 yes (n/a) (n/a) NULL
+)
\ No newline at end of file
diff --git a/sql/oa_sync_job.sql b/sql/oa_sync_job.sql
new file mode 100644
index 0000000..2132365
--- /dev/null
+++ b/sql/oa_sync_job.sql
@@ -0,0 +1,41 @@
+-- OA鏁版嵁鍚屾瀹氭椂浠诲姟閰嶇疆SQL
+-- 鍦╯ys_job琛ㄤ腑娣诲姞瀹氭椂浠诲姟
+
+-- 1. OA瀹屾暣鍚屾浠诲姟锛堟帹鑽愶級- 鍏堝悓姝ラ儴闂紝鍐嶅悓姝ョ敤鎴�
+INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark)
+VALUES
+('OA鏁版嵁鍚屾', 'DEFAULT', 'oaSyncTask.syncOaData', '0 0 2 * * ?', '3', '1', '1', 'admin', sysdate(),
+'姣忓ぉ鍑屾櫒2鐐硅嚜鍔ㄥ悓姝A閮ㄩ棬鍜岀敤鎴锋暟鎹紙鍏堥儴闂ㄥ悗鐢ㄦ埛锛夈�傞粯璁ゅ仠鐢紝闇�鎵嬪姩鍚敤銆�');
+
+-- 2. 閮ㄩ棬鍚屾浠诲姟锛堢嫭绔嬶級
+INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark)
+VALUES
+('OA閮ㄩ棬鍚屾', 'DEFAULT', 'departmentSyncTask.syncDepartments', '0 0 2 * * ?', '3', '1', '1', 'admin', sysdate(),
+'姣忓ぉ鍑屾櫒2鐐瑰悓姝A閮ㄩ棬鏁版嵁銆傞粯璁ゅ仠鐢紝寤鸿浣跨敤"OA鏁版嵁鍚屾"浠诲姟銆�');
+
+-- 3. 鐢ㄦ埛鍚屾浠诲姟锛堢嫭绔嬶級- 娉ㄦ剰锛氬繀椤诲湪閮ㄩ棬鍚屾涔嬪悗鎵ц
+INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark)
+VALUES
+('OA鐢ㄦ埛鍚屾', 'DEFAULT', 'userSyncTask.syncUsers', '0 0 3 * * ?', '3', '1', '1', 'admin', sysdate(),
+'姣忓ぉ鍑屾櫒3鐐瑰悓姝A鐢ㄦ埛鏁版嵁銆傞粯璁ゅ仠鐢紝寤鸿浣跨敤"OA鏁版嵁鍚屾"浠诲姟銆�');
+
+-- 璇存槑锛�
+-- job_name: 浠诲姟鍚嶇О
+-- job_group: 浠诲姟缁勫悕锛圖EFAULT涓洪粯璁ょ粍锛�
+-- invoke_target: 璋冪敤鐩爣瀛楃涓诧紙Bean鍚嶇О.鏂规硶鍚嶏級
+-- cron_expression: cron琛ㄨ揪寮�
+-- - '0 0 2 * * ?' = 姣忓ぉ鍑屾櫒2鐐规墽琛�
+-- - '0 0 3 * * ?' = 姣忓ぉ鍑屾櫒3鐐规墽琛�
+-- - '0 0 */4 * * ?' = 姣�4灏忔椂鎵ц涓�娆�
+-- - '0 0/30 * * * ?' = 姣�30鍒嗛挓鎵ц涓�娆�
+-- misfire_policy: 閿欒繃鎵ц绛栫暐锛�1=绔嬪嵆鎵ц锛�2=鎵ц涓�娆★紝3=鏀惧純鎵ц锛�
+-- concurrent: 鏄惁骞跺彂锛�0=鍏佽锛�1=绂佹锛�
+-- status: 鐘舵�侊紙0=姝e父锛�1=鏆傚仠锛�
+-- create_by: 鍒涘缓鑰�
+-- create_time: 鍒涘缓鏃堕棿
+-- remark: 澶囨敞璇存槑
+
+-- 浣跨敤寤鸿锛�
+-- 1. 鎺ㄨ崘浣跨敤"OA鏁版嵁鍚屾"浠诲姟锛屽畠浼氭寜姝g‘椤哄簭鎵ц閮ㄩ棬鍜岀敤鎴峰悓姝�
+-- 2. 濡傛灉闇�瑕佸垎鍒帶鍒讹紝鍙互浣跨敤鐙珛鐨勯儴闂ㄥ拰鐢ㄦ埛鍚屾浠诲姟
+-- 3. 纭繚鐢ㄦ埛鍚屾浠诲姟鍦ㄩ儴闂ㄥ悓姝ヤ换鍔′箣鍚庢墽琛岋紙鏃堕棿闂撮殧鑷冲皯5鍒嗛挓锛�
diff --git a/sql/sqlserver_hospdata.sql b/sql/sqlserver_hospdata.sql
new file mode 100644
index 0000000..54d964e
--- /dev/null
+++ b/sql/sqlserver_hospdata.sql
@@ -0,0 +1,19 @@
+CREATE TABLE HospData
+(
+HospID int yes 4 10 0 no (n/a) (n/a) NULL,
+HospID int no 4 10 0 no (n/a) (n/a) NULL
+HospName nvarchar no 200 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HospCityID int no 4 10 0 yes (n/a) (n/a) NULL
+HospShort nvarchar no 200 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HopsProvince nvarchar no 100 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HopsCity nvarchar no 100 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HopsArea nvarchar no 100 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HospAddress nvarchar no 200 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HospTEL nvarchar no 100 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HospUnitID int no 4 10 0 yes (n/a) (n/a) NULL
+HospState int no 4 10 0 yes (n/a) (n/a) NULL
+HospOAID nvarchar no 100 yes (n/a) (n/a) Chinese_PRC_CI_AS
+HospIntroducerID int no 4 10 0 yes (n/a) (n/a) NULL
+HospIntroducerDate datetime no 8 yes (n/a) (n/a) NULL
+HospLevel int no 4 10 0 yes (n/a) (n/a) NULL
+)
\ No newline at end of file
diff --git a/sql/sys_task_emergency.sql b/sql/sys_task_emergency.sql
new file mode 100644
index 0000000..fcbd5b2
--- /dev/null
+++ b/sql/sys_task_emergency.sql
@@ -0,0 +1,54 @@
+-- ----------------------------
+-- 鎬ユ晳杞繍浠诲姟鎵╁睍琛�
+-- 鐢ㄤ簬瀛樺偍鎬ユ晳杞繍鍜岀绁夎溅浠诲姟鐨勪笓灞炲瓧娈�
+-- ----------------------------
+
+DROP TABLE IF EXISTS sys_task_emergency;
+CREATE TABLE sys_task_emergency (
+ id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '涓婚敭ID',
+ task_id BIGINT NOT NULL UNIQUE COMMENT '浠诲姟ID',
+
+ -- 鎮h�呬俊鎭�
+ patient_contact VARCHAR(100) COMMENT '鎮h�呰仈绯讳汉',
+ patient_phone VARCHAR(20) COMMENT '鎮h�呰仈绯荤數璇�',
+ patient_name VARCHAR(100) COMMENT '鎮h�呭鍚�',
+ patient_gender VARCHAR(10) COMMENT '鎮h�呮�у埆:male-鐢�,female-濂�',
+ patient_id_card VARCHAR(18) COMMENT '鎮h�呰韩浠借瘉鍙�',
+ patient_condition TEXT COMMENT '鎮h�呯梾鎯呮弿杩�',
+
+ -- 杞嚭鍖婚櫌淇℃伅
+ hospital_out_name VARCHAR(200) COMMENT '杞嚭鍖婚櫌鍚嶇О',
+ hospital_out_department VARCHAR(100) COMMENT '杞嚭鍖婚櫌绉戝',
+ hospital_out_bed_number VARCHAR(50) COMMENT '杞嚭鍖婚櫌搴婂彿',
+ hospital_out_address VARCHAR(500) COMMENT '杞嚭鍖婚櫌鍦板潃',
+ hospital_out_longitude DECIMAL(10,7) COMMENT '杞嚭鍖婚櫌缁忓害',
+ hospital_out_latitude DECIMAL(10,7) COMMENT '杞嚭鍖婚櫌绾害',
+
+ -- 杞叆鍖婚櫌淇℃伅
+ hospital_in_name VARCHAR(200) COMMENT '杞叆鍖婚櫌鍚嶇О',
+ hospital_in_department VARCHAR(100) COMMENT '杞叆鍖婚櫌绉戝',
+ hospital_in_bed_number VARCHAR(50) COMMENT '杞叆鍖婚櫌搴婂彿',
+ hospital_in_address VARCHAR(500) COMMENT '杞叆鍖婚櫌鍦板潃',
+ hospital_in_longitude DECIMAL(10,7) COMMENT '杞叆鍖婚櫌缁忓害',
+ hospital_in_latitude DECIMAL(10,7) COMMENT '杞叆鍖婚櫌绾害',
+
+ -- 璐圭敤淇℃伅
+ transfer_distance DECIMAL(8,2) COMMENT '杞繍鍏噷鏁�',
+ transfer_price DECIMAL(10,2) COMMENT '鎴愪氦浠�(鍏�)',
+
+ -- 绂忕杞︿笓鐢ㄥ瓧娈�
+ passenger_contact VARCHAR(100) COMMENT '涔樺鑱旂郴浜�',
+ passenger_phone VARCHAR(20) COMMENT '涔樺鑱旂郴鐢佃瘽',
+
+ -- 绯荤粺瀛楁
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ create_by VARCHAR(64) COMMENT '鍒涘缓鑰�',
+ update_by VARCHAR(64) COMMENT '鏇存柊鑰�',
+
+ INDEX idx_task_id (task_id),
+ INDEX idx_patient_name (patient_name),
+ INDEX idx_hospital_out_name (hospital_out_name),
+ INDEX idx_hospital_in_name (hospital_in_name),
+ FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅琛�';
diff --git a/sql/sys_task_welfare.sql b/sql/sys_task_welfare.sql
new file mode 100644
index 0000000..6393e8b
--- /dev/null
+++ b/sql/sys_task_welfare.sql
@@ -0,0 +1,41 @@
+-- ----------------------------
+-- 绂忕杞︿换鍔℃墿灞曡〃
+-- 鐢ㄤ簬瀛樺偍绂忕杞︿换鍔$殑涓撳睘瀛楁
+-- ----------------------------
+
+DROP TABLE IF EXISTS sys_task_welfare;
+CREATE TABLE sys_task_welfare (
+ id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '涓婚敭ID',
+ task_id BIGINT NOT NULL UNIQUE COMMENT '浠诲姟ID',
+
+ -- 涔樺淇℃伅
+ passenger_contact VARCHAR(100) COMMENT '涔樺鑱旂郴浜�',
+ passenger_phone VARCHAR(20) COMMENT '涔樺鑱旂郴鐢佃瘽',
+ passenger_name VARCHAR(100) COMMENT '涔樺濮撳悕',
+ passenger_age INT COMMENT '涔樺骞撮緞',
+ passenger_gender VARCHAR(10) COMMENT '涔樺鎬у埆:male-鐢�,female-濂�',
+ passenger_id_card VARCHAR(18) COMMENT '涔樺韬唤璇佸彿',
+ special_needs TEXT COMMENT '鐗规畩闇�姹傛弿杩�',
+
+ -- 鏈嶅姟淇℃伅
+ service_type VARCHAR(50) COMMENT '鏈嶅姟绫诲瀷:杞鎺ラ�併�佹媴鏋惰浆杩愮瓑',
+ pickup_address VARCHAR(500) COMMENT '鎺ラ�佸湴鍧�',
+ pickup_longitude DECIMAL(10,7) COMMENT '鎺ラ�佸湴鍧�缁忓害',
+ pickup_latitude DECIMAL(10,7) COMMENT '鎺ラ�佸湴鍧�绾害',
+ destination_address VARCHAR(500) COMMENT '鐩殑鍦板潃',
+ destination_longitude DECIMAL(10,7) COMMENT '鐩殑鍦板潃缁忓害',
+ destination_latitude DECIMAL(10,7) COMMENT '鐩殑鍦板潃绾害',
+
+ -- 璐圭敤淇℃伅
+ service_distance DECIMAL(8,2) COMMENT '鏈嶅姟鍏噷鏁�',
+ service_price DECIMAL(10,2) COMMENT '鏈嶅姟璐圭敤(鍏�)',
+
+ -- 绯荤粺瀛楁
+ create_time DATETIME NOT NULL COMMENT '鍒涘缓鏃堕棿',
+ update_time DATETIME NOT NULL COMMENT '鏇存柊鏃堕棿',
+ create_by VARCHAR(64) COMMENT '鍒涘缓鑰�',
+ update_by VARCHAR(64) COMMENT '鏇存柊鑰�',
+
+ INDEX idx_task_id (task_id),
+ FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='绂忕杞︿换鍔℃墿灞曚俊鎭〃';
diff --git a/sql/user_vehicle_bind.sql b/sql/user_vehicle_bind.sql
new file mode 100644
index 0000000..072218b
--- /dev/null
+++ b/sql/user_vehicle_bind.sql
@@ -0,0 +1,24 @@
+-- 鐢ㄦ埛杞﹁締缁戝畾琛�
+CREATE TABLE IF NOT EXISTS sys_user_vehicle (
+ id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ user_id BIGINT(20) NOT NULL COMMENT '鐢ㄦ埛ID',
+ vehicle_id BIGINT(20) NOT NULL COMMENT '杞﹁締ID',
+ bind_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '缁戝畾鏃堕棿',
+ bind_by VARCHAR(64) DEFAULT '' COMMENT '缁戝畾鎿嶄綔浜�',
+ status CHAR(1) DEFAULT '0' COMMENT '缁戝畾鐘舵�侊紙0姝e父 1瑙g粦锛�',
+ remark VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
+ create_by VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ update_by VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ PRIMARY KEY (id),
+ UNIQUE KEY idx_user_vehicle (user_id, vehicle_id) COMMENT '鐢ㄦ埛杞﹁締鍞竴绱㈠紩',
+ KEY idx_user_id (user_id) COMMENT '鐢ㄦ埛ID绱㈠紩',
+ KEY idx_vehicle_id (vehicle_id) COMMENT '杞﹁締ID绱㈠紩'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐢ㄦ埛杞﹁締缁戝畾琛�';
+
+-- 娣诲姞璇存槑
+-- 1. 涓�涓敤鎴峰彲浠ョ粦瀹氬杈嗚溅杈嗭紙瀹為檯涓氬姟涓彲鑳藉彧缁戝畾涓�杈嗭紝閫氳繃涓氬姟閫昏緫鎺у埗锛�
+-- 2. 涓�杈嗚溅杈嗗彲浠ヨ澶氫釜鐢ㄦ埛缁戝畾锛堝鍙告満杞彮锛�
+-- 3. status='0'琛ㄧず褰撳墠缁戝畾鏈夋晥锛�'1'琛ㄧず宸茶В缁�
+-- 4. 閫氳繃 (user_id, vehicle_id) 鍞竴绱㈠紩纭繚鍚屼竴鐢ㄦ埛涓嶄細閲嶅缁戝畾鍚屼竴杞﹁締
diff --git "a/\344\273\273\345\212\241\347\212\266\346\200\201.md" "b/\344\273\273\345\212\241\347\212\266\346\200\201.md"
new file mode 100644
index 0000000..dfd286b
--- /dev/null
+++ "b/\344\273\273\345\212\241\347\212\266\346\200\201.md"
@@ -0,0 +1,13 @@
+鏅�氫换鍔$殑鎿嶄綔鍔熻兘鏃跺簭
+鐘舵�侊細寰呭鐞� ->瀵瑰簲鎸夐挳锛氬嚭鍙戯紝鍙栨秷锛�
+ 鐐瑰嚭鍙戞寜閽細鐘舵�佸彉涓哄嚭鍙戜腑.
+ 鐐瑰彇娑�:寮瑰嚭浜屾纭绐楀彛锛岀‘璁ゅ悗鐘舵�佸彉涓哄凡鍙栨秷锛�
+鐘舵�侊細鍑哄彂涓� ->瀵瑰簲鎸夐挳锛屽凡鍒拌揪锛屽彇娑堬紙寮哄埗缁撴潫锛�
+ 鐐瑰凡鍒拌揪锛氱姸鎬佸彉涓哄凡鍒拌揪锛�
+鐘舵�侊細宸插埌杈� ->瀵瑰簲鎸夐挳锛屽凡杩旂▼锛�
+ 鐐瑰嚮宸茶繑绋嬶細鐘舵�佸氨涓鸿繑绋嬩腑
+鐘舵�侊細杩旂▼涓�->瀵瑰簲鎸夐挳锛屽凡瀹屾垚锛�
+鐘舵�侊細宸插畬鎴�->鏃犳寜閽�
+鐘舵�侊細宸插彇娑�->鏃犳寜閽�
+
+涓嶈鏄剧ず澶氫綑鐨勬寜閽紝鍙樉绀哄彲鐢ㄧ殑鎸夐挳
\ No newline at end of file
diff --git "a/\345\244\232\346\225\260\346\215\256\346\272\220\345\210\207\346\215\242\351\227\256\351\242\230\344\277\256\345\244\215\350\257\264\346\230\216.md" "b/\345\244\232\346\225\260\346\215\256\346\272\220\345\210\207\346\215\242\351\227\256\351\242\230\344\277\256\345\244\215\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..da89348
--- /dev/null
+++ "b/\345\244\232\346\225\260\346\215\256\346\272\220\345\210\207\346\215\242\351\227\256\351\242\230\344\277\256\345\244\215\350\257\264\346\230\216.md"
@@ -0,0 +1,428 @@
+# 澶氭暟鎹簮鍒囨崲闂淇璇存槑
+
+## 闂鎻忚堪
+
+鍦ㄥ悓涓�涓� Service 鏂规硶涓皟鐢ㄥ涓笉鍚屾暟鎹簮鐨� Mapper 鏃讹紝鍑虹幇**鏁版嵁婧愬垏鎹㈠け鏁�**鐨勯棶棰橈細
+
+```java
+@Service
+public class DepartmentSyncServiceImpl {
+ @Autowired
+ private DepartmentSyncMapper departmentSyncMapper; // @DataSource(SQLSERVER)
+
+ @Autowired
+ private SysDeptMapper sysDeptMapper; // 榛樿 MySQL
+
+ @Transactional
+ public AjaxResult syncBranchDepartments() {
+ // 绗竴姝ワ細浠� SQL Server 鏌ヨ鏁版嵁
+ List<DepartmentSyncDTO> data = departmentSyncMapper.selectBranchDepartments();
+ // 鉁� 杩欓噷鑳芥纭煡璇� SQL Server
+
+ // 绗簩姝ワ細鍐欏叆 MySQL
+ sysDeptMapper.insertDept(dept);
+ // 鉂� 闂锛氳繖閲屼篃鍘讳簡 MySQL锛屽洜涓烘暟鎹簮琚竻闄や簡
+ }
+}
+```
+
+**鐜拌薄**锛�
+- 绗竴涓� Mapper 璋冪敤鑳藉姝g‘鍒囨崲鍒� SQL Server
+- 璋冪敤瀹屾垚鍚庯紝鏁版嵁婧愯娓呴櫎
+- 鍚庣画鐨� MySQL Mapper 璋冪敤姝e父
+- **浣嗗鏋滃啀娆¤皟鐢� SQL Server Mapper锛屼細澶辫触锛堜娇鐢ㄤ簡 MySQL 鏁版嵁婧愶級**
+
+---
+
+## 闂鏍瑰洜鍒嗘瀽
+
+### 鍘熷鐨� DataSourceAspect 瀹炵幇
+
+```java
+@Around("dsPointCut()")
+public Object around(ProceedingJoinPoint point) throws Throwable {
+ DataSource dataSource = getDataSource(point);
+
+ if (StringUtils.isNotNull(dataSource)) {
+ // 璁剧疆鏁版嵁婧�
+ DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
+ }
+
+ try {
+ return point.proceed();
+ }
+ finally {
+ // 鉂� 闂锛氭棤璁哄浣曢兘浼氭竻闄ゆ暟鎹簮
+ DynamicDataSourceContextHolder.clearDataSourceType();
+ }
+}
+```
+
+### 闂鐐�
+
+1. **鏃犳潯浠舵竻闄ゆ暟鎹簮**锛�
+ - 姣忔 Mapper 鏂规硶鎵ц瀹屾垚鍚庯紝鍦� `finally` 鍧椾腑閮戒細璋冪敤 `clearDataSourceType()`
+ - 瀵艰嚧鏁版嵁婧愪笂涓嬫枃琚竻绌猴紝鍥炲埌榛樿鏁版嵁婧愶紙MySQL锛�
+
+2. **涓嶆敮鎸佸祵濂楄皟鐢�**锛�
+ - 鍦� Service 鏂规硶涓紝澶氭璋冪敤涓嶅悓鏁版嵁婧愮殑 Mapper
+ - 绗竴涓� Mapper 璋冪敤瀹屾垚鍚庯紝鏁版嵁婧愬氨琚竻闄�
+ - 鍚庣画璋冪敤閮戒娇鐢ㄩ粯璁ゆ暟鎹簮
+
+3. **浜嬪姟杈圭晫闂**锛�
+ - Service 鏂规硶涓婃湁 `@Transactional` 娉ㄨВ
+ - 鍦ㄤ簨鍔″唴澶氭鍒囨崲鏁版嵁婧愶紝鍘熷疄鐜版棤娉曟纭淮鎶ゆ暟鎹簮鐘舵��
+
+---
+
+## 瑙e喅鏂规
+
+### 淇敼鍚庣殑 DataSourceAspect 瀹炵幇
+
+**鏂囦欢璺緞**: `ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java`
+
+```java
+@Around("dsPointCut()")
+public Object around(ProceedingJoinPoint point) throws Throwable {
+ DataSource dataSource = getDataSource(point);
+
+ // 鉁� 鍏抽敭鏀硅繘 1: 璁板綍褰撳墠鏁版嵁婧�
+ String oldDataSourceType = DynamicDataSourceContextHolder.getDataSourceType();
+ boolean isNewDataSource = false;
+
+ if (StringUtils.isNotNull(dataSource)) {
+ String newDataSourceType = dataSource.value().name();
+ // 鉁� 鍏抽敭鏀硅繘 2: 鍙湁褰撴暟鎹簮鍙戠敓鍙樺寲鏃舵墠璁剧疆鏂扮殑鏁版嵁婧�
+ if (!newDataSourceType.equals(oldDataSourceType)) {
+ DynamicDataSourceContextHolder.setDataSourceType(newDataSourceType);
+ isNewDataSource = true;
+ logger.debug("鍒囨崲鏁版嵁婧�: {} -> {}", oldDataSourceType, newDataSourceType);
+ }
+ }
+
+ try {
+ return point.proceed();
+ }
+ finally {
+ // 鉁� 鍏抽敭鏀硅繘 3: 鍙湁褰撴湰娆¤皟鐢ㄦ敼鍙樹簡鏁版嵁婧愭椂锛屾墠闇�瑕佹仮澶�
+ if (isNewDataSource) {
+ // 鎭㈠鍒颁箣鍓嶇殑鏁版嵁婧�
+ if (StringUtils.isNotEmpty(oldDataSourceType)) {
+ DynamicDataSourceContextHolder.setDataSourceType(oldDataSourceType);
+ logger.debug("鎭㈠鏁版嵁婧�: {}", oldDataSourceType);
+ } else {
+ DynamicDataSourceContextHolder.clearDataSourceType();
+ logger.debug("娓呴櫎鏁版嵁婧愶紝鎭㈠鍒伴粯璁ゆ暟鎹簮");
+ }
+ }
+ }
+}
+```
+
+### 鏍稿績鏀硅繘鐐�
+
+#### 1. 璁板綍鏃ф暟鎹簮鐘舵��
+```java
+String oldDataSourceType = DynamicDataSourceContextHolder.getDataSourceType();
+```
+- 鍦ㄥ垏鎹㈡暟鎹簮涔嬪墠锛屽厛淇濆瓨褰撳墠鏁版嵁婧愮被鍨�
+- 鐢ㄤ簬鍚庣画鎭㈠
+
+#### 2. 鏉′欢鎬у垏鎹㈡暟鎹簮
+```java
+if (!newDataSourceType.equals(oldDataSourceType)) {
+ DynamicDataSourceContextHolder.setDataSourceType(newDataSourceType);
+ isNewDataSource = true;
+}
+```
+- 鍙湁褰撴暟鎹簮纭疄闇�瑕佸垏鎹㈡椂鎵嶈繘琛屽垏鎹�
+- 閫氳繃 `isNewDataSource` 鏍囪璁板綍鏄惁杩涜浜嗗垏鎹�
+
+#### 3. 鏅鸿兘鎭㈠鏁版嵁婧�
+```java
+if (isNewDataSource) {
+ if (StringUtils.isNotEmpty(oldDataSourceType)) {
+ // 鎭㈠鍒颁箣鍓嶇殑鏁版嵁婧�
+ DynamicDataSourceContextHolder.setDataSourceType(oldDataSourceType);
+ } else {
+ // 涔嬪墠娌℃湁璁剧疆鏁版嵁婧愶紝娓呴櫎褰撳墠鏁版嵁婧�
+ DynamicDataSourceContextHolder.clearDataSourceType();
+ }
+}
+```
+- 鍙湁鍦ㄦ湰娆¤皟鐢ㄧ‘瀹炴敼鍙樹簡鏁版嵁婧愭椂锛屾墠杩涜鎭㈠
+- 濡傛灉涔嬪墠鏈夋暟鎹簮锛屾仮澶嶅埌涔嬪墠鐨勬暟鎹簮
+- 濡傛灉涔嬪墠鏄粯璁ゆ暟鎹簮锛屾竻闄ゅ綋鍓嶆暟鎹簮
+
+---
+
+## 淇鏁堟灉
+
+### 淇鍓�
+
+```
+Service.syncBranchDepartments() 寮�濮�
+ 鈹溾攢> departmentSyncMapper.selectBranchDepartments()
+ 鈹� 鈹溾攢 鍒囨崲鍒� SQL Server 鉁�
+ 鈹� 鈹溾攢 鎵ц鏌ヨ 鉁�
+ 鈹� 鈹斺攢 娓呴櫎鏁版嵁婧� 鉂� (finally 鍧�)
+ 鈹�
+ 鈹溾攢> sysDeptMapper.checkDeptNameUnique()
+ 鈹� 鈹斺攢 浣跨敤榛樿鏁版嵁婧� MySQL 鉁�
+ 鈹�
+ 鈹溾攢> sysDeptMapper.insertDept()
+ 鈹� 鈹斺攢 浣跨敤榛樿鏁版嵁婧� MySQL 鉁�
+ 鈹�
+ 鈹斺攢> 濡傛灉鍐嶆璋冪敤 departmentSyncMapper
+ 鈹斺攢 浣跨敤榛樿鏁版嵁婧� MySQL 鉂� (搴旇鏄� SQL Server)
+```
+
+### 淇鍚�
+
+```
+Service.syncBranchDepartments() 寮�濮�
+ 鈹溾攢> departmentSyncMapper.selectBranchDepartments()
+ 鈹� 鈹溾攢 褰撳墠鏁版嵁婧�: null (榛樿)
+ 鈹� 鈹溾攢 鍒囨崲鍒� SQL Server 鉁�
+ 鈹� 鈹溾攢 鎵ц鏌ヨ 鉁�
+ 鈹� 鈹斺攢 鎭㈠鍒伴粯璁ゆ暟鎹簮 鉁� (鍥犱负涔嬪墠鏄� null)
+ 鈹�
+ 鈹溾攢> sysDeptMapper.checkDeptNameUnique()
+ 鈹� 鈹溾攢 褰撳墠鏁版嵁婧�: null (榛樿 MySQL)
+ 鈹� 鈹溾攢 鏃犻渶鍒囨崲 鉁�
+ 鈹� 鈹斺攢 鎵ц鏌ヨ 鉁�
+ 鈹�
+ 鈹溾攢> departmentSyncMapper.selectBranchDepartments() (鍐嶆璋冪敤)
+ 鈹� 鈹溾攢 褰撳墠鏁版嵁婧�: null (榛樿)
+ 鈹� 鈹溾攢 鍒囨崲鍒� SQL Server 鉁�
+ 鈹� 鈹溾攢 鎵ц鏌ヨ 鉁�
+ 鈹� 鈹斺攢 鎭㈠鍒伴粯璁ゆ暟鎹簮 鉁�
+ 鈹�
+ 鈹斺攢> sysDeptMapper.insertDept()
+ 鈹溾攢 褰撳墠鏁版嵁婧�: null (榛樿 MySQL)
+ 鈹溾攢 鏃犻渶鍒囨崲 鉁�
+ 鈹斺攢 鎵ц鎻掑叆 鉁�
+```
+
+---
+
+## 鏁版嵁婧愬垏鎹㈢姸鎬佹満
+
+```mermaid
+stateDiagram-v2
+ [*] --> 榛樿鏁版嵁婧�(MySQL)
+
+ 榛樿鏁版嵁婧�(MySQL) --> SQL_Server: departmentSyncMapper璋冪敤
+ SQL_Server --> 榛樿鏁版嵁婧�(MySQL): 鏂规硶鎵ц瀹屾垚,鎭㈠
+
+ 榛樿鏁版嵁婧�(MySQL) --> 榛樿鏁版嵁婧�(MySQL): sysDeptMapper璋冪敤(鏃犲垏鎹�)
+
+ SQL_Server --> SQL_Server: 宓屽璋冪敤SQL_Server_Mapper(鏃犲垏鎹�)
+
+ 榛樿鏁版嵁婧�(MySQL) --> [*]: Service鏂规硶缁撴潫
+```
+
+---
+
+## 鏀寔鐨勫満鏅�
+
+### 鉁� 鍦烘櫙 1: 鍗曟鏁版嵁婧愬垏鎹�
+
+```java
+@Transactional
+public void method1() {
+ // 鍒囨崲鍒� SQL Server
+ List<Data> data = sqlServerMapper.selectData();
+
+ // 鑷姩鎭㈠鍒� MySQL
+ mysqlMapper.insertData(data);
+}
+```
+
+### 鉁� 鍦烘櫙 2: 澶氭浜ゆ浛鍒囨崲
+
+```java
+@Transactional
+public void method2() {
+ // 鍒囨崲鍒� SQL Server
+ List<Data1> data1 = sqlServerMapper.selectData1();
+
+ // 鎭㈠鍒� MySQL
+ mysqlMapper.process(data1);
+
+ // 鍐嶆鍒囨崲鍒� SQL Server
+ List<Data2> data2 = sqlServerMapper.selectData2();
+
+ // 鍐嶆鎭㈠鍒� MySQL
+ mysqlMapper.saveAll(data2);
+}
+```
+
+### 鉁� 鍦烘櫙 3: 宓屽璋冪敤鍚屼竴鏁版嵁婧�
+
+```java
+@Transactional
+public void method3() {
+ // 鍒囨崲鍒� SQL Server
+ List<Dept> depts = sqlServerMapper.selectDepartments();
+
+ for (Dept dept : depts) {
+ // 浠嶇劧鏄� SQL Server (涓嶄細閲嶅鍒囨崲)
+ List<User> users = sqlServerMapper.selectUsersByDept(dept.getId());
+
+ // 鎭㈠鍒� MySQL
+ mysqlMapper.saveUsers(users);
+ }
+}
+```
+
+### 鉁� 鍦烘櫙 4: Service 闂磋皟鐢�
+
+```java
+@Service
+public class ServiceA {
+ @Autowired
+ private ServiceB serviceB;
+
+ @Transactional
+ public void methodA() {
+ // 榛樿 MySQL
+ mysqlMapper.query();
+
+ // 璋冪敤 ServiceB
+ serviceB.methodB();
+
+ // 浠嶇劧鏄� MySQL
+ mysqlMapper.insert();
+ }
+}
+
+@Service
+public class ServiceB {
+ public void methodB() {
+ // 鍒囨崲鍒� SQL Server
+ sqlServerMapper.query();
+
+ // 鏂规硶缁撴潫鍚庢仮澶嶅埌璋冪敤鑰呯殑鏁版嵁婧� (MySQL)
+ }
+}
+```
+
+---
+
+## 璋冭瘯鏃ュ織
+
+淇敼鍚庣殑鍒囬潰浼氳緭鍑鸿缁嗙殑璋冭瘯鏃ュ織锛屽府鍔╄拷韪暟鎹簮鍒囨崲锛�
+
+```log
+2025-10-18 10:00:01.123 DEBUG [DataSourceAspect] 鍒囨崲鏁版嵁婧�: null -> SQLSERVER
+2025-10-18 10:00:01.456 DEBUG [DynamicDataSourceContextHolder] 鍒囨崲鍒癝QLSERVER鏁版嵁婧�
+2025-10-18 10:00:01.789 DEBUG [DataSourceAspect] 娓呴櫎鏁版嵁婧愶紝鎭㈠鍒伴粯璁ゆ暟鎹簮
+
+2025-10-18 10:00:02.123 DEBUG [DataSourceAspect] 鍒囨崲鏁版嵁婧�: null -> SQLSERVER
+2025-10-18 10:00:02.456 DEBUG [DynamicDataSourceContextHolder] 鍒囨崲鍒癝QLSERVER鏁版嵁婧�
+2025-10-18 10:00:02.789 DEBUG [DataSourceAspect] 娓呴櫎鏁版嵁婧愶紝鎭㈠鍒伴粯璁ゆ暟鎹簮
+```
+
+---
+
+## 楠岃瘉鏂规硶
+
+### 1. 娣诲姞璋冭瘯鏃ュ織
+
+鍦� Service 鏂规硶涓坊鍔犳暟鎹簮鐘舵�佹棩蹇楋細
+
+```java
+@Transactional
+public AjaxResult syncBranchDepartments() {
+ log.info("寮�濮嬪悓姝ワ紝褰撳墠鏁版嵁婧�: {}",
+ DynamicDataSourceContextHolder.getDataSourceType());
+
+ // 鏌ヨ SQL Server
+ List<DepartmentSyncDTO> data = departmentSyncMapper.selectBranchDepartments();
+ log.info("鏌ヨ SQL Server 瀹屾垚锛屽綋鍓嶆暟鎹簮: {}",
+ DynamicDataSourceContextHolder.getDataSourceType());
+
+ // 鍐欏叆 MySQL
+ sysDeptMapper.insertDept(dept);
+ log.info("鍐欏叆 MySQL 瀹屾垚锛屽綋鍓嶆暟鎹簮: {}",
+ DynamicDataSourceContextHolder.getDataSourceType());
+}
+```
+
+### 2. 鍗曞厓娴嬭瘯
+
+```java
+@Test
+public void testDataSourceSwitch() {
+ // 娴嬭瘯鏁版嵁婧愬垏鎹�
+ AjaxResult result = departmentSyncService.syncBranchDepartments();
+
+ // 楠岃瘉缁撴灉
+ assertEquals(200, result.get("code"));
+}
+```
+
+### 3. 鎵嬪姩娴嬭瘯
+
+```bash
+# 鎵ц鍚屾鎺ュ彛
+POST http://localhost:8080/system/dept/sync/branch
+
+# 鏌ョ湅鏃ュ織杈撳嚭
+tail -f logs/ruoyi-admin.log | grep -E "鏁版嵁婧恷DataSource"
+```
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+### 鈿狅笍 浜嬪姟绠$悊
+
+- 淇鍚庣殑鍒囬潰鏀寔鍦ㄥ悓涓�涓簨鍔′腑鍒囨崲鏁版嵁婧�
+- 浣嗚娉ㄦ剰锛�**涓嶅悓鏁版嵁婧愮殑鎿嶄綔涓嶅湪鍚屼竴涓垎甯冨紡浜嬪姟涓�**
+- SQL Server 鐨勬煡璇㈠拰 MySQL 鐨勫啓鍏ユ槸**涓や釜鐙珛鐨勬暟鎹簱杩炴帴**
+
+### 鈿狅笍 鎬ц兘褰卞搷
+
+- 姣忔 Mapper 璋冪敤閮戒細缁忚繃 AOP 鍒囬潰
+- 澧炲姞浜嗘暟鎹簮鐘舵�佺殑鍒ゆ柇鍜岃褰�
+- 鎬ц兘褰卞搷鏋佸皬锛堢撼绉掔骇鍒級
+
+### 鈿狅笍 绾跨▼瀹夊叏
+
+- 浣跨敤 `ThreadLocal` 瀛樺偍鏁版嵁婧愮被鍨�
+- 姣忎釜绾跨▼鏈夌嫭绔嬬殑鏁版嵁婧愪笂涓嬫枃
+- 涓嶄細褰卞搷鍏朵粬绾跨▼
+
+---
+
+## 鐩稿叧鏂囦欢
+
+| 鏂囦欢 | 璇存槑 |
+|------|------|
+| `DataSourceAspect.java` | 鏁版嵁婧愬垏鎹㈠垏闈紙宸蹭慨澶嶏級 |
+| `DynamicDataSourceContextHolder.java` | 鏁版嵁婧愪笂涓嬫枃鎸佹湁鑰� |
+| `DepartmentSyncMapper.java` | 閮ㄩ棬鍚屾 Mapper锛堟爣娉� @DataSource锛� |
+| `UserSyncMapper.java` | 鐢ㄦ埛鍚屾 Mapper锛堟爣娉� @DataSource锛� |
+| `DepartmentSyncServiceImpl.java` | 閮ㄩ棬鍚屾 Service锛堜娇鐢ㄥ鏁版嵁婧愶級 |
+
+---
+
+## 鎬荤粨
+
+### 闂鏍瑰洜
+鍘熷瀹炵幇鏃犳潯浠舵竻闄ゆ暟鎹簮锛屽鑷村祵濂楄皟鐢ㄦ椂鏁版嵁婧愮姸鎬佷涪澶便��
+
+### 瑙e喅鏂规
+璁板綍鏃ф暟鎹簮鐘舵�侊紝鏉′欢鎬у垏鎹紝鏅鸿兘鎭㈠鏁版嵁婧愩��
+
+### 淇鏁堟灉
+鉁� 鏀寔鍚屼竴 Service 涓娆″垏鎹㈡暟鎹簮
+鉁� 鏀寔宓屽璋冪敤
+鉁� 鏀寔 Service 闂磋皟鐢�
+鉁� 瀹屽叏鍏煎鍘熸湁鍔熻兘
+
+### 楠岃瘉鐘舵��
+鉁� 浠g爜宸蹭慨鏀�
+鈴� 绛夊緟娴嬭瘯楠岃瘉
diff --git "a/\347\224\250\346\210\267\345\220\214\346\255\245-\345\277\253\351\200\237\345\274\200\345\247\213.md" "b/\347\224\250\346\210\267\345\220\214\346\255\245-\345\277\253\351\200\237\345\274\200\345\247\213.md"
new file mode 100644
index 0000000..9730d8f
--- /dev/null
+++ "b/\347\224\250\346\210\267\345\220\214\346\255\245-\345\277\253\351\200\237\345\274\200\345\247\213.md"
@@ -0,0 +1,189 @@
+# 鐢ㄦ埛鍚屾鍔熻兘 - 蹇�熷紑濮�
+
+## 涓�銆佸姛鑳借鏄�
+浠嶴QL Server鐨凮A_User琛ㄥ悓姝ョ敤鎴锋暟鎹埌鑻ヤ緷绯荤粺锛岄�氳繃`department_id`鑷姩鍏宠仈閮ㄩ棬銆�
+
+## 浜屻�佸墠缃潯浠�
+鈿狅笍 **蹇呴』鍏堝畬鎴愰儴闂ㄥ悓姝ワ紒** 鐢ㄦ埛鍚屾渚濊禆閮ㄩ棬鏁版嵁銆�
+
+## 涓夈�佸畨瑁呮楠�
+
+### 1锔忊儯 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+# 1. 閮ㄩ棬琛ㄦ坊鍔犲瓧娈碉紙濡傛灉鏈墽琛岋級
+mysql -u root -p ry-vue < sql/add_department_id_to_sys_dept.sql
+
+# 2. 鐢ㄦ埛琛ㄦ坊鍔犲瓧娈�
+mysql -u root -p ry-vue < sql/add_oa_user_id_to_sys_user.sql
+```
+
+### 2锔忊儯 缂栬瘧椤圭洰
+```bash
+mvn clean package -DskipTests
+```
+
+### 3锔忊儯 鍚姩鏈嶅姟
+```bash
+cd ruoyi-admin
+java -jar target/ruoyi-admin.jar
+```
+
+## 鍥涖�佷娇鐢ㄦ柟娉�
+
+### 鈿狅笍 閲嶈锛氬繀椤绘寜椤哄簭鎵ц
+
+#### 绗竴姝ワ細鍚屾閮ㄩ棬
+```bash
+POST http://localhost:8080/system/dept/sync/branch
+Headers:
+ Authorization: Bearer {浣犵殑token}
+```
+
+#### 绗簩姝ワ細鍚屾鐢ㄦ埛
+```bash
+POST http://localhost:8080/system/dept/sync/user
+Headers:
+ Authorization: Bearer {浣犵殑token}
+```
+
+## 浜斻�佽繑鍥炵ず渚�
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 15, 鏇存柊鐢ㄦ埛: 5, 璺宠繃: 2, 澶辫触: 0",
+ "data": {
+ "created": 15,
+ "updated": 5,
+ "skipped": 2,
+ "error": 0,
+ "totalProcessed": 22
+ }
+}
+```
+
+## 鍏�侀獙璇佺粨鏋�
+```sql
+-- 鏌ョ湅鍚屾鐨勭敤鎴�
+SELECT
+ u.user_name,
+ u.nick_name,
+ u.oa_user_id,
+ d.dept_name,
+ u.email,
+ u.phonenumber
+FROM sys_user u
+LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
+WHERE u.oa_user_id IS NOT NULL
+ORDER BY u.create_time DESC;
+```
+
+## 涓冦�佹牳蹇冮�昏緫
+
+### 閮ㄩ棬鍏宠仈
+```
+OA_departmentID 鈫� 鏌ヨsys_dept.department_id 鈫� 鑾峰彇dept_id
+```
+
+### 鐢ㄦ埛澶勭悊
+```
+1. 鏍规嵁oa_user_id鏌ヨ
+ 鈹溾攢 瀛樺湪 鈫� 鏇存柊鐢ㄦ埛淇℃伅
+ 鈹斺攢 涓嶅瓨鍦�
+ 鈹溾攢 鐢ㄦ埛鍚嶅瓨鍦� 鈫� 鏇存柊骞惰缃畂a_user_id
+ 鈹斺攢 鐢ㄦ埛鍚嶄笉瀛樺湪 鈫� 鍒涘缓鏂扮敤鎴凤紙瀵嗙爜123456锛�
+```
+
+## 鍏�侀粯璁ゅ�艰鏄�
+鏂板垱寤虹敤鎴风殑榛樿璁剧疆锛�
+- 馃攽 **瀵嗙爜**: `123456`
+- 馃彚 **閮ㄩ棬**: 100锛堣嫢渚濈鎶�锛�- 濡傛灉鎵句笉鍒板搴旈儴闂�
+- 馃懁 **鎬у埆**: 2锛堟湭鐭ワ級
+- 鉁� **鐘舵��**: 0锛堟甯革級
+
+## 涔濄�佹牳蹇冩枃浠舵竻鍗�
+
+### SQL鑴氭湰
+- `sql/add_oa_user_id_to_sys_user.sql` - 娣诲姞瀛楁
+
+### Java鏂囦欢
+- `SysUser.java`锛堜慨鏀癸級 - 娣诲姞oaUserId瀛楁
+- `UserSyncDTO.java` - 鐢ㄦ埛鏁版嵁浼犺緭瀵硅薄
+- `UserSyncMapper.java` + XML - 鏌ヨSQL Server
+- `SysUserMapper.java/XML`锛堟墿灞曪級 - 鎵╁睍鏌ヨ鏂规硶
+- `IUserSyncService.java` - 鏈嶅姟鎺ュ彛
+- `UserSyncServiceImpl.java` - 鏍稿績鍚屾閫昏緫
+- `DepartmentSyncController.java`锛堟墿灞曪級 - 娣诲姞鎺ュ彛
+
+### 鏂囨。
+- `prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md` - 璇︾粏璇存槑
+
+## 鍗併�佸父瑙侀棶棰�
+
+### 鉂� 鐢ㄦ埛閮ㄩ棬涓虹┖锛�
+**鍘熷洜**: 閮ㄩ棬鏈悓姝ユ垨department_id涓嶅尮閰�
+**瑙e喅**: 鍏堟墽琛岄儴闂ㄥ悓姝�
+
+### 鉂� 鐢ㄦ埛鍚嶉噸澶嶏紵
+**澶勭悊**: 鑷姩鏇存柊宸插瓨鍦ㄧ敤鎴风殑oa_user_id锛屼笉浼氭姤閿�
+
+### 鉂� 鏂扮敤鎴峰浣曠櫥褰曪紵
+**璐﹀彿**: OA_User瀛楁鍊�
+**瀵嗙爜**: `123456`
+**寤鸿**: 棣栨鐧诲綍鍚庝慨鏀瑰瘑鐮�
+
+## 鍗佷竴銆佹敞鎰忎簨椤�
+
+鉁� **鎵ц椤哄簭寰堥噸瑕�**
+1. 鍏堝悓姝ラ儴闂�
+2. 鍐嶅悓姝ョ敤鎴�
+
+鉁� **骞傜瓑鎬т繚璇�**
+- 澶氭鍚屾涓嶄細鍒涘缓閲嶅鏁版嵁
+- 宸插瓨鍦ㄧ敤鎴峰彧浼氭洿鏂颁俊鎭�
+
+鉁� **鏉冮檺瑕佹眰**
+- 閮ㄩ棬鍚屾: `system:dept:sync`
+- 鐢ㄦ埛鍚屾: `system:user:sync`
+
+## 鍗佷簩銆佺洃鎺т笌鏃ュ織
+
+### 鏌ョ湅鏃ュ織
+```bash
+tail -f ruoyi-admin/logs/sys-info.log | grep -i "UserSync"
+```
+
+### 鏃ュ織绀轰緥
+```
+INFO UserSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 50 鏉$敤鎴锋暟鎹�
+INFO UserSyncServiceImpl - 鍒涘缓鏂扮敤鎴�: 寮犱笁 (zhangsan), oaUserId: 1001, deptId: 201
+INFO UserSyncServiceImpl - 鏇存柊鐢ㄦ埛: 鏉庡洓 (lisi), oaUserId: 1002
+WARN UserSyncServiceImpl - 鏈壘鍒板搴旂殑閮ㄩ棬: departmentId=9999, 鐢ㄦ埛: test
+INFO UserSyncServiceImpl - 鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 30, 鏇存柊鐢ㄦ埛: 15, 璺宠繃: 3, 澶辫触: 2
+```
+
+## 鍗佷笁銆佷笅涓�姝�
+
+### 鍓嶇闆嗘垚
+鍦ㄧ敤鎴风鐞嗛〉闈㈡坊鍔�"鍚屾"鎸夐挳锛�
+```javascript
+syncUsers() {
+ this.$confirm('纭鍚屾OA鐢ㄦ埛鏁版嵁鍚楋紵', '鎻愮ず', {
+ type: 'warning'
+ }).then(() => {
+ this.$http.post('/system/dept/sync/user').then(res => {
+ this.$message.success(res.msg);
+ this.getList();
+ });
+ });
+}
+```
+
+### 瀹氭椂浠诲姟
+閰嶇疆姣忓ぉ鑷姩鍚屾锛�
+- 浠诲姟鍚嶇О: OA鐢ㄦ埛鍚屾
+- 璋冪敤鐩爣: `userSyncTask.execute`
+- cron琛ㄨ揪寮�: `0 0 3 * * ?` (姣忓ぉ鍑屾櫒3鐐�)
+
+## 鍗佸洓銆佺浉鍏虫枃妗�
+- [鐢ㄦ埛鍚屾璇︾粏璇存槑](prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md)
+- [閮ㄩ棬鍚屾蹇�熷紑濮媇(閮ㄩ棬鍚屾-蹇�熷紑濮�.md)
diff --git "a/\347\224\250\346\210\267\345\220\214\346\255\245\345\212\237\350\203\275\345\274\200\345\217\221\346\200\273\347\273\223.md" "b/\347\224\250\346\210\267\345\220\214\346\255\245\345\212\237\350\203\275\345\274\200\345\217\221\346\200\273\347\273\223.md"
new file mode 100644
index 0000000..ee7208c
--- /dev/null
+++ "b/\347\224\250\346\210\267\345\220\214\346\255\245\345\212\237\350\203\275\345\274\200\345\217\221\346\200\273\347\273\223.md"
@@ -0,0 +1,369 @@
+# 鐢ㄦ埛鍚屾鍔熻兘寮�鍙戞�荤粨
+
+## 馃搵 椤圭洰淇℃伅
+- **寮�鍙戞棩鏈�**: 2025-10-18
+- **鍔熻兘鍚嶇О**: OA鐢ㄦ埛鍚屾
+- **渚濊禆鍔熻兘**: 閮ㄩ棬鍚屾
+- **鎶�鏈爤**: Spring Boot + MyBatis + SQL Server
+
+## 馃幆 闇�姹傛杩�
+浠嶴QL Server鏁版嵁搴撶殑`OA_User`琛ㄤ腑鍚屾鐢ㄦ埛鏁版嵁鍒拌嫢渚濈郴缁熺殑`sys_user`琛紝閫氳繃`department_id`瀛楁鍏宠仈閮ㄩ棬銆�
+
+### 鏁版嵁婧怱QL
+```sql
+SELECT
+ OA_User_ID as OA_UserID,
+ OA_User as user_name,
+ OA_Name as nick_name,
+ OA_departmentID as department_id,
+ OA_gender as sex,
+ OA_email as email,
+ OA_mobile as phonenumber
+FROM OA_User
+WHERE OA_User IS NOT NULL AND OA_Name IS NOT NULL
+```
+
+### 瀛楁鏄犲皠
+- **OA_User_ID** 鈫� oa_user_id锛堝敮涓�鏍囪瘑锛�
+- **OA_User** 鈫� user_name锛堢敤鎴疯处鍙凤級
+- **OA_Name** 鈫� nick_name锛堢敤鎴锋樀绉帮級
+- **OA_departmentID** 鈫� department_id锛堥儴闂ㄥ叧鑱旈敭锛�
+- **OA_gender** 鈫� sex锛堟�у埆锛�
+- **OA_email** 鈫� email锛堥偖绠憋級
+- **OA_mobile** 鈫� phonenumber锛堟墜鏈哄彿锛�
+
+## 馃敤 瀹炵幇鍐呭
+
+### 1. 鏁版嵁搴撲慨鏀�
+
+#### 琛ㄧ粨鏋勫彉鏇�
+```sql
+-- 鍦╯ys_user琛ㄤ腑娣诲姞oa_user_id瀛楁
+ALTER TABLE sys_user ADD COLUMN oa_user_id INT NULL COMMENT 'SQL Server涓殑OA鐢ㄦ埛ID';
+CREATE INDEX idx_oa_user_id ON sys_user(oa_user_id);
+```
+
+**鏂囦欢**: `sql/add_oa_user_id_to_sys_user.sql`
+
+### 2. 瀹炰綋绫讳慨鏀�
+
+#### SysUser瀹炰綋
+**鏂囦欢**: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java`
+
+**淇敼鍐呭**:
+```java
+/** SQL Server涓殑OA鐢ㄦ埛ID */
+private Integer oaUserId;
+
+public Integer getOaUserId() { return oaUserId; }
+public void setOaUserId(Integer oaUserId) { this.oaUserId = oaUserId; }
+```
+
+### 3. 鏂板鏂囦欢
+
+#### DTO灞�
+**鏂囦欢**: `ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java`
+- 鍔熻兘: 鐢ㄦ埛鍚屾鏁版嵁浼犺緭瀵硅薄
+- 瀛楁: oaUserId, userName, nickName, departmentId, sex, email, phonenumber
+
+#### Mapper灞�
+**鏂囦欢**:
+- `ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserSyncMapper.java`
+- `ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml`
+
+**涓昏鏂规硶**:
+- `List<UserSyncDTO> selectOaUsers()` - 鏌ヨSQL Server鐢ㄦ埛鏁版嵁
+
+#### Service灞�
+**鏂囦欢**:
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncService.java`
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java`
+
+**鏍稿績鏂规硶**: `syncOaUsers()`
+
+**鍚屾閫昏緫**:
+1. 浠嶴QL Server鑾峰彇OA_User鏁版嵁
+2. 楠岃瘉鏁版嵁瀹屾暣鎬�
+3. 鏍规嵁department_id鏌ユ壘瀵瑰簲鐨刣ept_id
+4. 妫�鏌ョ敤鎴锋槸鍚﹀凡瀛樺湪锛堟牴鎹畂a_user_id锛�
+5. 宸插瓨鍦ㄥ垯鏇存柊锛屼笉瀛樺湪鍒欏垱寤�
+6. 杩斿洖鍚屾缁熻缁撴灉
+
+#### Controller灞�
+**鏂囦欢**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`锛堟墿灞曪級
+
+**鎺ュ彛**:
+- `POST /system/dept/sync/user` - 鍚屾OA鐢ㄦ埛
+- 鏉冮檺: `system:user:sync`
+
+### 4. Mapper鎵╁睍
+
+#### SysUserMapper
+**鏂囦欢**:
+- `ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java`
+- `ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml`
+
+**鏂板鏂规硶**:
+```java
+// 鏍规嵁oaUserId鏌ヨ鐢ㄦ埛
+SysUser selectUserByOaUserId(@Param("oaUserId") Integer oaUserId);
+```
+
+**淇敼鍐呭**:
+- resultMap涓坊鍔爋a_user_id鏄犲皠
+- selectUserVo涓坊鍔爋a_user_id瀛楁
+- insertUser涓坊鍔爋a_user_id鏀寔
+- updateUser涓坊鍔爋a_user_id鏀寔
+- 鏂板selectUserByOaUserId鏌ヨ鏂规硶
+
+### 5. 鏂囨。
+
+#### 鍔熻兘璇存槑鏂囨。
+**鏂囦欢**: `prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md`
+- 鍔熻兘姒傝堪
+- 鏁版嵁婧愯鏄�
+- 瀛楁鏄犲皠鍏崇郴
+- 鍚屾閫昏緫璇﹁В
+- 鎺ュ彛璇存槑
+- 浣跨敤姝ラ
+- 楠岃瘉鏂规硶
+
+#### 蹇�熷紑濮�
+**鏂囦欢**: `鐢ㄦ埛鍚屾-蹇�熷紑濮�.md`
+- 瀹夎姝ラ
+- 浣跨敤鏂规硶
+- 杩斿洖绀轰緥
+- 鏍稿績閫昏緫
+- 甯歌闂
+
+## 馃搳 鎶�鏈壒鎬�
+
+### 1. 鏅鸿兘閮ㄩ棬鍏宠仈
+- 閫氳繃department_id鑷姩鏌ユ壘瀵瑰簲鐨刣ept_id
+- 鎵句笉鍒伴儴闂ㄦ椂浣跨敤榛樿閮ㄩ棬(100)
+- 璇︾粏璁板綍閮ㄩ棬鍏宠仈鏃ュ織
+
+### 2. 骞傜瓑鎬ц璁�
+- 閫氳繃oa_user_id鍒ゆ柇鐢ㄦ埛鏄惁宸插瓨鍦�
+- 澶氭鎵ц涓嶄細鍒涘缓閲嶅鏁版嵁
+- 宸插瓨鍦ㄧ敤鎴峰彧鏇存柊淇℃伅
+
+### 3. 鏅鸿兘鐢ㄦ埛鍖归厤
+- 浼樺厛鏍规嵁oa_user_id鏌ユ壘鐢ㄦ埛
+- 鐢ㄦ埛鍚嶅凡瀛樺湪鏃舵洿鏂皁a_user_id
+- 閬垮厤鍒涘缓閲嶅鐢ㄦ埛
+
+### 4. 鏁版嵁瀹屾暣鎬ч獙璇�
+- 楠岃瘉蹇呭~瀛楁锛堢敤鎴峰悕銆佹樀绉帮級
+- 璺宠繃涓嶅畬鏁寸殑鏁版嵁
+- 璁板綍璺宠繃鍘熷洜
+
+### 5. 閿欒澶勭悊
+- 鍗曚釜鐢ㄦ埛澶辫触涓嶅奖鍝嶆暣浣撳悓姝�
+- 鎹曡幏骞惰褰曡缁嗛敊璇俊鎭�
+- 杩斿洖瀹屾暣鐨勭粺璁′俊鎭�
+
+### 6. 浜嬪姟淇濇姢
+- 浣跨敤`@Transactional`娉ㄨВ
+- 鍚屾杩囩▼涓嚭閿欒嚜鍔ㄥ洖婊�
+- 淇濊瘉鏁版嵁涓�鑷存��
+
+### 7. 榛樿鍊艰缃�
+- 鏂扮敤鎴烽粯璁ゅ瘑鐮�: `123456`锛堝姞瀵嗗瓨鍌級
+- 榛樿閮ㄩ棬: 100锛堣嫢渚濈鎶�锛�
+- 榛樿鎬у埆: 2锛堟湭鐭ワ級
+- 榛樿鐘舵��: 0锛堟甯革級
+
+## 馃攳 鍚屾娴佺▼
+
+```
+1. 浠嶴QL Server鏌ヨOA_User鏁版嵁
+ 鈫�
+2. 閬嶅巻姣忔潯鐢ㄦ埛鏁版嵁
+ 鈫�
+3. 楠岃瘉鏁版嵁瀹屾暣鎬э紙鐢ㄦ埛鍚嶃�佹樀绉帮級
+ 鈹溾攢 涓嶅畬鏁� 鈫� 璺宠繃
+ 鈹斺攢 瀹屾暣 鈫� 缁х画
+ 鈫�
+4. 鏍规嵁department_id鏌ユ壘dept_id
+ 鈹溾攢 鎵惧埌 鈫� 浣跨敤瀵瑰簲dept_id
+ 鈹斺攢 鏈壘鍒� 鈫� 浣跨敤榛樿dept_id(100)
+ 鈫�
+5. 鏍规嵁oa_user_id鏌ヨ鐢ㄦ埛
+ 鈹溾攢 鎵惧埌 鈫� 鏇存柊鐢ㄦ埛淇℃伅
+ 鈹斺攢 鏈壘鍒� 鈫� 妫�鏌ョ敤鎴峰悕
+ 鈹溾攢 鐢ㄦ埛鍚嶅瓨鍦� 鈫� 鏇存柊骞惰缃畂a_user_id
+ 鈹斺攢 鐢ㄦ埛鍚嶄笉瀛樺湪 鈫� 鍒涘缓鏂扮敤鎴�
+ 鈫�
+6. 杩斿洖缁熻缁撴灉
+```
+
+## 馃搱 鍚屾缁撴灉绀轰緥
+
+### 杈撳叆锛圫QL Server OA_User琛級
+```
+OA_User_ID | OA_User | OA_Name | OA_departmentID | OA_gender | OA_email
+1001 | zhangsan | 寮犱笁 | 1001 | 0 | zhangsan@qq.com
+1002 | lisi | 鏉庡洓 | 1001 | 1 | lisi@qq.com
+1003 | wangwu | 鐜嬩簲 | 1002 | 0 | wangwu@qq.com
+```
+
+### 澶勭悊杩囩▼
+1. **鐢ㄦ埛zhangsan**:
+ - department_id=1001 鈫� 鏌ヨsys_dept 鈫� dept_id=201
+ - oa_user_id=1001涓嶅瓨鍦� 鈫� 鐢ㄦ埛鍚嶄笉瀛樺湪
+ - 鍒涘缓鏂扮敤鎴凤紙瀵嗙爜: 123456锛�
+
+2. **鐢ㄦ埛lisi**:
+ - department_id=1001 鈫� dept_id=201
+ - oa_user_id=1002涓嶅瓨鍦� 鈫� 鐢ㄦ埛鍚嶅凡瀛樺湪
+ - 鏇存柊宸插瓨鍦ㄧ敤鎴凤紝璁剧疆oa_user_id=1002
+
+3. **鐢ㄦ埛wangwu**:
+ - department_id=1002 鈫� dept_id=202
+ - 鍒涘缓鏂扮敤鎴�
+
+### 杈撳嚭锛坰ys_user琛級
+```
+user_id | user_name | nick_name | dept_id | oa_user_id | email
+101 | zhangsan | 寮犱笁 | 201 | 1001 | zhangsan@qq.com
+102 | lisi | 鏉庡洓 | 201 | 1002 | lisi@qq.com
+103 | wangwu | 鐜嬩簲 | 202 | 1003 | wangwu@qq.com
+```
+
+### 鎺ュ彛杩斿洖
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤虹敤鎴�: 2, 鏇存柊鐢ㄦ埛: 1, 璺宠繃: 0, 澶辫触: 0",
+ "data": {
+ "created": 2,
+ "updated": 1,
+ "skipped": 0,
+ "error": 0,
+ "totalProcessed": 3
+ }
+}
+```
+
+## 馃帗 浣跨敤绀轰緥
+
+### 1. 鎵ц椤哄簭锛堥噸瑕侊紒锛�
+```bash
+# 绗竴姝ワ細鍚屾閮ㄩ棬
+POST http://localhost:8080/system/dept/sync/branch
+
+# 绗簩姝ワ細鍚屾鐢ㄦ埛
+POST http://localhost:8080/system/dept/sync/user
+```
+
+### 2. Postman璋冪敤
+```
+POST http://localhost:8080/system/dept/sync/user
+Headers:
+ Authorization: Bearer eyJhbGciOiJIUzUxMiJ9...
+```
+
+### 3. curl鍛戒护
+```bash
+curl -X POST http://localhost:8080/system/dept/sync/user \
+ -H "Authorization: Bearer {token}"
+```
+
+### 4. 鍓嶇璋冪敤
+```javascript
+this.$http.post('/system/dept/sync/user').then(res => {
+ this.$message.success(res.msg);
+ this.getList();
+});
+```
+
+## 鈿欙笍 閰嶇疆璇存槑
+
+### 鍓嶇疆渚濊禆
+**蹇呴』鍏堝畬鎴愰儴闂ㄥ悓姝ワ紒**
+1. 鎵ц `add_department_id_to_sys_dept.sql`
+2. 璋冪敤 `/system/dept/sync/branch` 鍚屾閮ㄩ棬
+3. 鐒跺悗鎵嶈兘鍚屾鐢ㄦ埛
+
+### SQL Server鏁版嵁婧�
+**鏂囦欢**: `ruoyi-admin/src/main/resources/application-dev.yml`
+
+```yaml
+spring:
+ datasource:
+ druid:
+ sqlserver:
+ enabled: true
+ url: jdbc:sqlserver://your-server:1433;DatabaseName=your-db
+ username: your-username
+ password: your-password
+ driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+```
+
+## 馃殌 閮ㄧ讲娓呭崟
+
+### 1. 鏁版嵁搴撴搷浣�
+- [ ] 鎵ц `add_department_id_to_sys_dept.sql`
+- [ ] 鎵ц `add_oa_user_id_to_sys_user.sql`
+
+### 2. 鍚屾鎿嶄綔
+- [ ] 璋冪敤閮ㄩ棬鍚屾鎺ュ彛
+- [ ] 璋冪敤鐢ㄦ埛鍚屾鎺ュ彛
+
+### 3. 楠岃瘉娴嬭瘯
+- [ ] 妫�鏌ュ悓姝ョ敤鎴锋暟閲�
+- [ ] 妫�鏌ラ儴闂ㄥ叧鑱旀儏鍐�
+- [ ] 楠岃瘉鏃ュ織杈撳嚭
+- [ ] 娴嬭瘯鏂扮敤鎴风櫥褰曪紙鐢ㄦ埛鍚�/123456锛�
+
+## 馃摑 鍏抽敭瑕佺偣
+
+### 鎵ц椤哄簭
+```
+1. 閮ㄩ棬鍚屾锛堝繀椤诲厛鎵ц锛�
+2. 鐢ㄦ埛鍚屾锛堜緷璧栭儴闂ㄦ暟鎹級
+```
+
+### 榛樿璁剧疆
+- 馃攽 **鏂扮敤鎴峰瘑鐮�**: `123456`
+- 馃彚 **榛樿閮ㄩ棬**: 100锛堣嫢渚濈鎶�锛�
+- 馃懁 **榛樿鎬у埆**: 2锛堟湭鐭ワ級
+- 鉁� **榛樿鐘舵��**: 0锛堟甯革級
+
+### 骞傜瓑鎬т繚璇�
+- 鉁� 澶氭鍚屾涓嶄細鍒涘缓閲嶅鏁版嵁
+- 鉁� 宸插瓨鍦ㄧ敤鎴峰彧浼氭洿鏂颁俊鎭�
+- 鉁� 鏍规嵁oa_user_id鍞竴鏍囪瘑鐢ㄦ埛
+
+## 馃摎 鍙傝�冭祫鏂�
+- 鑻ヤ緷妗嗘灦鏂囨。: http://doc.ruoyi.vip
+- MyBatis鏂囨。: https://mybatis.org/mybatis-3/zh/
+- Spring Boot鏂囨。: https://spring.io/projects/spring-boot
+
+## 鉁� 鎬荤粨
+
+鏈寮�鍙戝畬鎴愪簡浠嶴QL Server鍒癕ySQL鐨勭敤鎴锋暟鎹悓姝ュ姛鑳斤紝涓昏鐗圭偣锛�
+
+1. **鏅鸿兘閮ㄩ棬鍏宠仈**: 閫氳繃department_id鑷姩鍏宠仈sys_dept琛�
+2. **骞傜瓑鎬т繚璇�**: 鏀寔閲嶅鎵ц锛屼笉浼氬垱寤洪噸澶嶆暟鎹�
+3. **鏅鸿兘鐢ㄦ埛鍖归厤**: 鏍规嵁oa_user_id鍜岀敤鎴峰悕鍙岄噸鍒ゆ柇
+4. **鏁版嵁瀹屾暣鎬�**: 楠岃瘉蹇呭~瀛楁锛岃烦杩囦笉瀹屾暣鏁版嵁
+5. **浜嬪姟瀹夊叏**: 浣跨敤浜嬪姟淇濊瘉鏁版嵁涓�鑷存��
+6. **璇︾粏鏃ュ織**: 璁板綍瀹屾暣鐨勫悓姝ヨ繃绋�
+7. **閿欒澶勭悊**: 鍗曚釜澶辫触涓嶅奖鍝嶆暣浣擄紝璇︾粏璁板綍閿欒
+8. **鏂囨。榻愬叏**: 鎻愪緵鍔熻兘璇存槑銆佸揩閫熷紑濮嬨�佹祴璇曟寚鍗�
+
+鍔熻兘宸插畬鎴愬紑鍙戝拰鑷祴锛屽彲浠ヨ繘鍏ユ祴璇曞拰閮ㄧ讲闃舵銆�
+
+## 馃敆 鐩稿叧鏂囨。
+- [鐢ㄦ埛鍚屾璇︾粏璇存槑](prd/鐢ㄦ埛鍚屾鍔熻兘璇存槑.md)
+- [鐢ㄦ埛鍚屾蹇�熷紑濮媇(鐢ㄦ埛鍚屾-蹇�熷紑濮�.md)
+- [閮ㄩ棬鍚屾鍔熻兘璇存槑](prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md)
+- [閮ㄩ棬鍚屾蹇�熷紑濮媇(閮ㄩ棬鍚屾-蹇�熷紑濮�.md)
+
+## 馃懆鈥嶐煉� 浣滆��
+ruoyi
+
+## 馃搮 鏃ユ湡
+2025-10-18
diff --git "a/\347\224\250\346\210\267\345\220\214\346\255\245\346\234\215\345\212\241\351\207\215\346\236\204\350\257\264\346\230\216.md" "b/\347\224\250\346\210\267\345\220\214\346\255\245\346\234\215\345\212\241\351\207\215\346\236\204\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..36d1b16
--- /dev/null
+++ "b/\347\224\250\346\210\267\345\220\214\346\255\245\346\234\215\345\212\241\351\207\215\346\236\204\350\257\264\346\230\216.md"
@@ -0,0 +1,498 @@
+# 鐢ㄦ埛鍚屾鏈嶅姟閲嶆瀯璇存槑
+
+## 閲嶆瀯姒傝堪
+
+灏嗙敤鎴峰悓姝ュ姛鑳介噸鏋勪负**鏁版嵁鏌ヨ**鍜�**鏁版嵁鍚屾**涓や釜鐙珛鐨勬湇鍔★紝涓庨儴闂ㄥ悓姝ヤ繚鎸佷竴鑷寸殑鏋舵瀯椋庢牸锛屽疄鐜拌亴璐e垎绂诲拰鐏垫椿鎬ф彁鍗囥��
+
+---
+
+## 鏋舵瀯鍙樺寲
+
+### 閲嶆瀯鍓�
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� UserSyncServiceImpl 鈹�
+鈹� 鈹�
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� syncOaUsers() 鈹� 鈹�
+鈹� 鈹� 鈹溾攢 鏌ヨ SQL Server 鈹� 鈹�
+鈹� 鈹� 鈹溾攢 鏌ヨ MySQL 閮ㄩ棬 鈹� 鈹�
+鈹� 鈹� 鈹斺攢 鍐欏叆 MySQL 鐢ㄦ埛 鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+**闂**锛�
+- 鉂� 鏁版嵁鏌ヨ鍜屽悓姝ラ�昏緫鑰﹀悎
+- 鉂� 鏃犳硶浣跨敤澶栭儴鏁版嵁婧�
+- 鉂� 闅句互鎵╁睍鍏朵粬鏁版嵁鏉ユ簮
+
+### 閲嶆瀯鍚�
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� UserSyncDataServiceImpl (鏂板) 鈹�
+鈹� 鑱岃矗锛氫粠 SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁 鈹�
+鈹� 鈹�
+鈹� 鈹溾攢 getOaUsers() 鈹�
+鈹� 鈹斺攢 杩斿洖 List<UserSyncDTO> 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ v
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� UserSyncServiceImpl (閲嶆瀯) 鈹�
+鈹� 鑱岃矗锛氭帴鏀舵暟鎹苟鍐欏叆 MySQL 鈹�
+鈹� 鈹�
+鈹� 鈹溾攢 syncOaUsers() 鈹�
+鈹� 鈹� 鈹斺攢 璋冪敤 UserSyncDataService 鑾峰彇鏁版嵁 鈹�
+鈹� 鈹� 鈹�
+鈹� 鈹斺攢 syncOaUsers(List<UserSyncDTO>) 鈹�
+鈹� 鈹斺攢 鎺ユ敹澶栭儴浼犲叆鐨勬暟鎹繘琛屽悓姝� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+---
+
+## 鏍稿績缁勪欢
+
+### 1. IUserSyncDataService锛堟柊澧烇級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncDataService.java`
+
+**鑱岃矗**: 瀹氫箟浠� SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁鐨勬帴鍙�
+
+```java
+public interface IUserSyncDataService {
+ /**
+ * 浠� SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁
+ *
+ * @return OA 鐢ㄦ埛鍒楄〃
+ */
+ List<UserSyncDTO> getOaUsers();
+}
+```
+
+---
+
+### 2. UserSyncDataServiceImpl锛堟柊澧烇級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncDataServiceImpl.java`
+
+**鑱岃矗**: 涓撻棬璐熻矗浠� SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁
+
+**鍏抽敭鐗规��**:
+```java
+@Service
+public class UserSyncDataServiceImpl implements IUserSyncDataService {
+ @Autowired
+ private UserSyncMapper userSyncMapper; // 甯� @DataSource 娉ㄨВ
+
+ @Override
+ public List<UserSyncDTO> getOaUsers() {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ OA 鐢ㄦ埛鏁版嵁...");
+
+ // 鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧�
+ List<UserSyncDTO> oaUsers = userSyncMapper.selectOaUsers();
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉� OA 鐢ㄦ埛鏁版嵁", oaUsers.size());
+ return oaUsers;
+ }
+}
+```
+
+**鏁版嵁娴�**:
+```
+UserSyncDataServiceImpl
+ 鈫�
+UserSyncMapper (@DataSource(SQLSERVER))
+ 鈫�
+SQL Server 鏁版嵁搴� (OA_User)
+ 鈫�
+杩斿洖 List<UserSyncDTO>
+```
+
+---
+
+### 3. IUserSyncService锛堥噸鏋勶級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IUserSyncService.java`
+
+**鍙樺寲**: 鏂板閲嶈浇鏂规硶锛屾敮鎸佸閮ㄦ暟鎹簮
+
+```java
+public interface IUserSyncService {
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁锛堜粠 SQL Server 鏌ヨ骞跺悓姝ュ埌 MySQL锛�
+ */
+ AjaxResult syncOaUsers();
+
+ /**
+ * 鍚屾OA鐢ㄦ埛鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * @param oaUsers 澶栭儴浼犲叆鐨凮A鐢ㄦ埛鏁版嵁鍒楄〃
+ */
+ AjaxResult syncOaUsers(List<UserSyncDTO> oaUsers);
+}
+```
+
+---
+
+### 4. UserSyncServiceImpl锛堥噸鏋勶級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java`
+
+**鍙樺寲**:
+1. 绉婚櫎瀵� `UserSyncMapper` 鐨勭洿鎺ヤ緷璧�
+2. 娉ㄥ叆 `IUserSyncDataService` 鑾峰彇鏁版嵁
+3. 鏂板 `syncOaUsers(List<UserSyncDTO>)` 鏂规硶
+
+**閲嶆瀯鍚庣殑浠g爜**:
+
+```java
+@Service
+public class UserSyncServiceImpl implements IUserSyncService {
+
+ @Autowired
+ private IUserSyncDataService userSyncDataService; // 鏁版嵁鏌ヨ鏈嶅姟
+
+ @Autowired
+ private SysUserMapper sysUserMapper; // MySQL 鐢ㄦ埛鎿嶄綔
+
+ @Autowired
+ private SysDeptMapper sysDeptMapper; // MySQL 閮ㄩ棬鏌ヨ
+
+ // 鏂规硶 1: 鍐呴儴鏌ヨ + 鍚屾
+ @Override
+ @Transactional
+ public AjaxResult syncOaUsers() {
+ // 璋冪敤鏁版嵁鏌ヨ鏈嶅姟鑾峰彇 SQL Server 鏁版嵁
+ List<UserSyncDTO> oaUsers = userSyncDataService.getOaUsers();
+
+ if (oaUsers == null || oaUsers.isEmpty()) {
+ return AjaxResult.warn("鏈幏鍙栧埌闇�瑕佸悓姝ョ殑鐢ㄦ埛鏁版嵁");
+ }
+
+ // 璋冪敤閲嶈浇鏂规硶鎵ц鍚屾
+ return syncOaUsers(oaUsers);
+ }
+
+ // 鏂规硶 2: 澶栭儴鏁版嵁婧� + 鍚屾锛堟柊澧烇級
+ @Override
+ @Transactional
+ public AjaxResult syncOaUsers(List<UserSyncDTO> oaUsers) {
+ if (oaUsers == null || oaUsers.isEmpty()) {
+ return AjaxResult.warn("浼犲叆鐨勭敤鎴锋暟鎹负绌�");
+ }
+
+ log.info("寮�濮嬪悓姝� {} 鏉A鐢ㄦ埛鏁版嵁鍒� MySQL 鏁版嵁搴�...", oaUsers.size());
+
+ // 鍚屾閫昏緫锛堝彧娑夊強 MySQL 鎿嶄綔锛�
+ // 1. 鏌ヨ MySQL 閮ㄩ棬淇℃伅
+ // 2. 鍒涘缓鎴栨洿鏂扮敤鎴�
+ // ...
+ }
+}
+```
+
+---
+
+### 5. DepartmentSyncController锛堟洿鏂帮級
+
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`
+
+**鍙樺寲**: 鏂板鐢ㄦ埛鍚屾鐨勫閮ㄦ暟鎹簮鎺ュ彛
+
+```java
+@RestController
+@RequestMapping("/system/dept/sync")
+public class DepartmentSyncController {
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+ /**
+ * 鎺ュ彛 1: 鍚屾閮ㄩ棬鏁版嵁锛堜粠 SQL Server 鏌ヨ骞跺悓姝ワ級
+ */
+ @PostMapping("/branch")
+ public AjaxResult syncBranchDepartments() {
+ return departmentSyncService.syncBranchDepartments();
+ }
+
+ /**
+ * 鎺ュ彛 2: 鍚屾閮ㄩ棬鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ */
+ @PostMapping("/branch/data")
+ public AjaxResult syncBranchDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> branchDepts) {
+ return departmentSyncService.syncBranchDepartments(branchDepts);
+ }
+
+ /**
+ * 鎺ュ彛 3: 鍚屾鐢ㄦ埛鏁版嵁锛堜粠 SQL Server 鏌ヨ骞跺悓姝ワ級
+ */
+ @PostMapping("/user")
+ public AjaxResult syncOaUsers() {
+ return userSyncService.syncOaUsers();
+ }
+
+ /**
+ * 鎺ュ彛 4: 鍚屾鐢ㄦ埛鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級猸� 鏂板
+ */
+ @PostMapping("/user/data")
+ public AjaxResult syncOaUsersWithData(@RequestBody List<UserSyncDTO> oaUsers) {
+ return userSyncService.syncOaUsers(oaUsers);
+ }
+}
+```
+
+---
+
+## 浣跨敤鍦烘櫙
+
+### 鍦烘櫙 1: 甯歌鍚屾锛堜粠 SQL Server 鏌ヨ锛�
+
+```bash
+# 鍚屾鐢ㄦ埛鏁版嵁
+POST http://localhost:8080/system/dept/sync/user
+```
+
+**鎵ц娴佺▼**:
+1. Controller 璋冪敤 `userSyncService.syncOaUsers()`
+2. Service 璋冪敤 `userSyncDataService.getOaUsers()`
+3. 鑷姩鍒囨崲鍒� SQL Server 鏌ヨ鏁版嵁
+4. 灏嗘暟鎹啓鍏� MySQL
+
+---
+
+### 鍦烘櫙 2: 浣跨敤澶栭儴鏁版嵁婧�
+
+```bash
+POST http://localhost:8080/system/dept/sync/user/data
+Content-Type: application/json
+
+[
+ {
+ "oaUserId": 1001,
+ "userName": "zhangsan",
+ "nickName": "寮犱笁",
+ "departmentId": 2001,
+ "sex": "0",
+ "email": "zhangsan@example.com",
+ "phonenumber": "13800138000"
+ },
+ {
+ "oaUserId": 1002,
+ "userName": "lisi",
+ "nickName": "鏉庡洓",
+ "departmentId": 2002,
+ "sex": "1",
+ "email": "lisi@example.com",
+ "phonenumber": "13900139000"
+ }
+]
+```
+
+**鎵ц娴佺▼**:
+1. Controller 鎺ユ敹 JSON 鏁版嵁骞惰浆鎹负 `List<UserSyncDTO>`
+2. Controller 璋冪敤 `userSyncService.syncOaUsers(oaUsers)`
+3. Service 鏌ヨ MySQL 閮ㄩ棬淇℃伅
+4. Service 鍒涘缓鎴栨洿鏂扮敤鎴峰埌 MySQL
+
+---
+
+### 鍦烘櫙 3: 鎵归噺鍚屾閮ㄩ棬鍜岀敤鎴�
+
+```java
+@Service
+public class BatchSyncService {
+
+ @Autowired
+ private IDepartmentSyncDataService departmentSyncDataService;
+
+ @Autowired
+ private IUserSyncDataService userSyncDataService;
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+ public void batchSyncAll() {
+ // 1. 浠� SQL Server 鏌ヨ閮ㄩ棬鏁版嵁
+ List<DepartmentSyncDTO> deptData = departmentSyncDataService.getBranchDepartments();
+
+ // 2. 鍚屾閮ㄩ棬鍒� MySQL
+ departmentSyncService.syncBranchDepartments(deptData);
+
+ // 3. 浠� SQL Server 鏌ヨ鐢ㄦ埛鏁版嵁
+ List<UserSyncDTO> userData = userSyncDataService.getOaUsers();
+
+ // 4. 鍚屾鐢ㄦ埛鍒� MySQL锛堢‘淇濋儴闂ㄥ凡鍚屾锛�
+ userSyncService.syncOaUsers(userData);
+ }
+}
+```
+
+---
+
+### 鍦烘櫙 4: 鏁版嵁棰勫鐞嗗悗鍚屾
+
+```java
+@Service
+public class PreprocessSyncService {
+
+ @Autowired
+ private IUserSyncDataService userSyncDataService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+ public void syncWithPreprocess() {
+ // 1. 浠� SQL Server 鏌ヨ鏁版嵁
+ List<UserSyncDTO> rawData = userSyncDataService.getOaUsers();
+
+ // 2. 鏁版嵁棰勫鐞�
+ List<UserSyncDTO> processedData = rawData.stream()
+ .filter(user -> StringUtils.isNotEmpty(user.getEmail())) // 鍙悓姝ユ湁閭鐨勭敤鎴�
+ .peek(user -> {
+ // 缁熶竴閭鍩熷悕
+ if (!user.getEmail().contains("@company.com")) {
+ user.setEmail(user.getUserName() + "@company.com");
+ }
+ })
+ .collect(Collectors.toList());
+
+ // 3. 鍚屾澶勭悊鍚庣殑鏁版嵁
+ userSyncService.syncOaUsers(processedData);
+ }
+}
+```
+
+---
+
+## 鎺ュ彛瀵规瘮
+
+| 鎺ュ彛 | 璺緞 | 鏁版嵁鏉ユ簮 | 閫傜敤鍦烘櫙 |
+|------|------|----------|----------|
+| **閮ㄩ棬鍚屾 1** | `POST /system/dept/sync/branch` | 鍐呴儴鏌ヨ SQL Server | 甯歌瀹氭椂鍚屾 |
+| **閮ㄩ棬鍚屾 2** | `POST /system/dept/sync/branch/data` | 澶栭儴浼犲叆 JSON | 鎵嬪姩鏁版嵁瀵煎叆銆佹暟鎹澶勭悊 |
+| **鐢ㄦ埛鍚屾 1** | `POST /system/dept/sync/user` | 鍐呴儴鏌ヨ SQL Server | 甯歌瀹氭椂鍚屾 |
+| **鐢ㄦ埛鍚屾 2** | `POST /system/dept/sync/user/data` | 澶栭儴浼犲叆 JSON | 鎵嬪姩鏁版嵁瀵煎叆銆佹暟鎹澶勭悊 猸� |
+
+---
+
+## 瀹氭椂浠诲姟鏇存柊
+
+瀹氭椂浠诲姟鍙互缁х画浣跨敤鍘熸湁鏂瑰紡锛屾棤闇�淇敼锛�
+
+```java
+@Component("oaSyncTask")
+public class OaSyncTask {
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ @Autowired
+ private IUserSyncService userSyncService;
+
+ public void syncOaData() {
+ // 绗竴姝ワ細鍚屾閮ㄩ棬
+ AjaxResult deptResult = departmentSyncService.syncBranchDepartments();
+
+ if (deptResult.get("code").equals(200)) {
+ // 绗簩姝ワ細鍚屾鐢ㄦ埛锛堝彧鏈夐儴闂ㄥ悓姝ユ垚鍔熸墠鎵ц锛�
+ AjaxResult userResult = userSyncService.syncOaUsers();
+ log.info("鐢ㄦ埛鍚屾缁撴灉: {}", userResult.get("msg"));
+ }
+ }
+}
+```
+
+---
+
+## 鏂囦欢娓呭崟
+
+### 鏂板鏂囦欢 鉁�
+- 鉁� `IUserSyncDataService.java` - 鐢ㄦ埛鏁版嵁鏌ヨ鏈嶅姟鎺ュ彛
+- 鉁� `UserSyncDataServiceImpl.java` - 鐢ㄦ埛鏁版嵁鏌ヨ鏈嶅姟瀹炵幇
+- 鉁� `鐢ㄦ埛鍚屾鏈嶅姟閲嶆瀯璇存槑.md` - 鏈枃妗�
+
+### 淇敼鏂囦欢 馃敡
+- 鉁� `IUserSyncService.java` - 鏂板閲嶈浇鏂规硶
+- 鉁� `UserSyncServiceImpl.java` - 閲嶆瀯瀹炵幇
+- 鉁� `DepartmentSyncController.java` - 鏂板 `/user/data` 鎺ュ彛
+
+### 鏃犻渶淇敼
+- 鉁� `UserSyncMapper.java` - Mapper 鎺ュ彛涓嶅彉
+- 鉁� `UserSyncMapper.xml` - SQL 鏄犲皠涓嶅彉
+- 鉁� `OaSyncTask.java` - 瀹氭椂浠诲姟涓嶅彉
+
+---
+
+## 浼樺娍鎬荤粨
+
+### 1. 涓庨儴闂ㄥ悓姝ヤ繚鎸佷竴鑷� 鉁�
+- 鐩稿悓鐨勬灦鏋勯鏍�
+- 鐩稿悓鐨勮亴璐e垎绂绘ā寮�
+- 鐩稿悓鐨勬墿灞曟柟寮�
+
+### 2. 鑱岃矗鍒嗙 鉁�
+- **UserSyncDataService**: 鍙礋璐f煡璇㈡暟鎹�
+- **UserSyncService**: 鍙礋璐e悓姝ユ暟鎹�
+
+### 3. 鐏垫椿鎬ф彁鍗� 鉁�
+- 鏀寔浠� SQL Server 鏌ヨ
+- 鏀寔澶栭儴鏁版嵁婧�
+- 鏀寔鏁版嵁棰勫鐞�
+- 鏀寔澶氭簮鏁版嵁鏁村悎
+
+### 4. 鏄撲簬鎵╁睍 鉁�
+```java
+// 鎵╁睍锛氭敮鎸佸叾浠栨暟鎹簮
+public interface IUserSyncDataService {
+ List<UserSyncDTO> getOaUsers(); // SQL Server
+ List<UserSyncDTO> getOaUsersFromLDAP(); // LDAP
+ List<UserSyncDTO> getOaUsersFromAPI(); // HTTP API
+}
+```
+
+### 5. 鏄撲簬娴嬭瘯 鉁�
+```java
+@Test
+public void testSyncWithMockData() {
+ // 鍒涘缓娴嬭瘯鏁版嵁
+ List<UserSyncDTO> testData = createTestUserData();
+
+ // 娴嬭瘯鍚屾閫昏緫
+ AjaxResult result = userSyncService.syncOaUsers(testData);
+
+ // 楠岃瘉缁撴灉
+ assertEquals(200, result.get("code"));
+}
+```
+
+---
+
+## 鎬荤粨
+
+閫氳繃鏈閲嶆瀯锛岀敤鎴峰悓姝ュ姛鑳戒笌閮ㄩ棬鍚屾鍔熻兘淇濇寔浜嗕竴鑷寸殑鏋舵瀯椋庢牸锛�
+
+鉁� **鑱岃矗鍒嗙**: 鏁版嵁鏌ヨ鍜屽悓姝ラ�昏緫瑙h��
+鉁� **鐏垫椿鎬ф彁鍗�**: 鏀寔澶氱鏁版嵁鏉ユ簮
+鉁� **鏄撲簬鎵╁睍**: 鍙交鏉炬坊鍔犳柊鐨勬暟鎹簮
+鉁� **鍚戝悗鍏煎**: 鍘熸湁浠g爜鏃犻渶淇敼
+鉁� **鏄撲簬娴嬭瘯**: 鍙娇鐢� Mock 鏁版嵁杩涜鍗曞厓娴嬭瘯
+鉁� **鏋舵瀯涓�鑷�**: 涓庨儴闂ㄥ悓姝ヤ繚鎸佺浉鍚屾ā寮�
+
+---
+
+## 鐩稿叧鏂囨。
+
+- [閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑.md](閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑.md)
+- [OA鏁版嵁鍚屾澶氭暟鎹簮鏋舵瀯璇存槑.md](OA鏁版嵁鍚屾澶氭暟鎹簮鏋舵瀯璇存槑.md)
+- [澶氭暟鎹簮鍒囨崲闂淇璇存槑.md](澶氭暟鎹簮鍒囨崲闂淇璇存槑.md)
+- [SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md](SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md)
diff --git "a/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275-\344\277\256\346\224\271\346\270\205\345\215\225.md" "b/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275-\344\277\256\346\224\271\346\270\205\345\215\225.md"
new file mode 100644
index 0000000..fe5ce0d
--- /dev/null
+++ "b/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275-\344\277\256\346\224\271\346\270\205\345\215\225.md"
@@ -0,0 +1,549 @@
+# 杞繍閮ㄥ悓姝ュ姛鑳� - 浠g爜淇敼娓呭崟
+
+## 淇敼鏃堕棿
+2025-10-18
+
+## 闇�姹傝鏄�
+鍦ㄧ幇鏈夌殑鍒嗗叕鍙稿悓姝ュ姛鑳藉熀纭�涓婏紝澧炲姞杞繍閮ㄥ悓姝ュ姛鑳姐�傝浆杩愰儴鏄�诲叕鍙革紙ID=101锛変笅鐨勪竴涓儴闂紝闇�瑕佸悓姝ヨ浆杩愰儴鍙婂叾鎵�鏈夊瓙閮ㄩ棬銆�
+
+## 鍏抽敭宸紓
+
+| 椤圭洰 | 鍒嗗叕鍙稿悓姝� | 杞繍閮ㄥ悓姝� |
+|------|-----------|-----------|
+| 鐖堕儴闂� | 鑻ヤ緷绉戞妧锛圛D=100锛� | 鎬诲叕鍙革紙ID=101锛� |
+| SQL Server 鏌ヨ鏉′欢 | `a.departmentName = N'鍚堜綔鍗曚綅'` | `a.departmentName = N'杞繍閮�'` |
+| 鍚嶇О鏍煎紡 | `婀涙睙--鎶ゅ+`锛堥渶瑕佽В鏋�"--"锛� | 鐩存帴浣跨敤 `departmentName` |
+| 鍚屾閫昏緫 | 鍒涘缓鍒嗗叕鍙� + 瀛愰儴闂紙涓ゅ眰锛� | 鍒涘缓杞繍閮� + 瀛愰儴闂紙涓ゅ眰锛� |
+
+## 淇敼鏂囦欢鍒楄〃
+
+### 1. DepartmentSyncMapper.xml 鉁�
+**鏂囦欢璺緞**: `ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml`
+
+**淇敼鍐呭**: 鏂板鏌ヨ鏂规硶 `selectTransportDepartments`
+
+```xml
+<!-- 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬 -->
+<select id="selectTransportDepartments" resultMap="DepartmentSyncResult">
+ <![CDATA[
+ SELECT TOP 500
+ b.departmentID,
+ b.departmentName,
+ b.parentID,
+ a.departmentName AS parentName
+ FROM uv_department a WITH (NOLOCK)
+ INNER JOIN uv_department b WITH (NOLOCK) ON a.departmentID = b.parentID
+ WHERE a.departmentName = N'杞繍閮�'
+ ORDER BY b.departmentName
+ ]]>
+</select>
+```
+
+**鍏抽敭鐐�**:
+- 浣跨敤 `CDATA` 鍖呰9 SQL 閬垮厤 XML 鐗规畩瀛楃闂
+- 浣跨敤 `TOP 500` 闄愬埗杩斿洖鏁版嵁閲�
+- 浣跨敤 `WITH (NOLOCK)` 鎻愰珮骞跺彂鎬ц兘
+- 涓枃瀛楃涓蹭娇鐢� `N` 鍓嶇紑
+
+---
+
+### 2. DepartmentSyncMapper.java 鉁�
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java`
+
+**淇敼鍐呭**: 鏂板鏂规硶澹版槑
+
+```java
+/**
+ * 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+List<DepartmentSyncDTO> selectTransportDepartments();
+```
+
+**淇敼浣嶇疆**: 绗� 23-28 琛岋紙鍦� `selectBranchDepartments()` 鏂规硶鍚庢坊鍔狅級
+
+---
+
+### 3. IDepartmentSyncDataService.java 鉁�
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java`
+
+**淇敼鍐呭**: 鏂板鏂规硶澹版槑
+
+```java
+/**
+ * 浠� SQL Server 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬鏁版嵁
+ *
+ * 鏁版嵁婧愶細SQL Server (uv_department 瑙嗗浘)
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+List<DepartmentSyncDTO> getTransportDepartments();
+```
+
+**淇敼浣嶇疆**: 绗� 24-32 琛岋紙鍦� `getBranchDepartments()` 鏂规硶鍚庢坊鍔狅級
+
+---
+
+### 4. DepartmentSyncDataServiceImpl.java 鉁�
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java`
+
+**淇敼鍐呭**: 鏂板鏂规硶瀹炵幇
+
+```java
+/**
+ * 浠� SQL Server 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬鏁版嵁
+ *
+ * 娉ㄦ剰锛欴epartmentSyncMapper 涓婃湁 @DataSource(DataSourceType.SQLSERVER) 娉ㄨВ
+ * 姝ゆ柟娉曚細鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧愭墽琛屾煡璇�
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+@Override
+public List<DepartmentSyncDTO> getTransportDepartments()
+{
+ try
+ {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁...");
+
+ // 璋冪敤 Mapper 鏌ヨ SQL Server 鏁版嵁
+ // @DataSource 娉ㄨВ浼氳嚜鍔ㄥ垏鎹㈡暟鎹簮
+ List<DepartmentSyncDTO> transportDepts = departmentSyncMapper.selectTransportDepartments();
+
+ if (transportDepts == null || transportDepts.isEmpty())
+ {
+ log.warn("鏈粠 SQL Server 鏌ヨ鍒拌浆杩愰儴瀛愰儴闂ㄦ暟鎹�");
+ return transportDepts;
+ }
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹�", transportDepts.size());
+ return transportDepts;
+ }
+ catch (Exception e)
+ {
+ log.error("浠� SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁澶辫触", e);
+ throw new RuntimeException("鏌ヨ SQL Server 鏁版嵁澶辫触: " + e.getMessage(), e);
+ }
+}
+```
+
+**淇敼浣嶇疆**: 绗� 67-102 琛岋紙鍦� `getBranchDepartments()` 鏂规硶鍚庛�佺被缁撴潫鍓嶆坊鍔狅級
+
+---
+
+### 5. IDepartmentSyncService.java 鉁�
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java`
+
+**淇敼鍐呭**: 鏂板鏂规硶澹版槑
+
+```java
+/**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * 鍚屾閫昏緫锛�
+ * 1. 纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ * 2. 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂紙鐩存帴鍒涘缓锛屾棤闇�瑙f瀽"--"鏍煎紡锛�
+ *
+ * @param transportDepts 澶栭儴浼犲叆鐨勮浆杩愰儴瀛愰儴闂ㄦ暟鎹垪琛�
+ * @return 鍚屾缁撴灉
+ */
+AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts);
+```
+
+**淇敼浣嶇疆**: 绗� 29-40 琛岋紙鍦� `syncBranchDepartments()` 鏂规硶鍚庢坊鍔狅級
+
+---
+
+### 6. DepartmentSyncServiceImpl.java 鉁�
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java`
+
+**淇敼鍐呭**: 鏂板鏂规硶瀹炵幇锛堟牳蹇冨悓姝ラ�昏緫锛�
+
+**瀹屾暣鏂规硶**: 绗� 189-324 琛�
+
+**鍏抽敭閫昏緫**:
+
+1. **妫�鏌ユ�诲叕鍙告槸鍚﹀瓨鍦�**锛堢 197-202 琛岋級
+```java
+SysDept headOffice = sysDeptMapper.selectDeptById(101L);
+if (headOffice == null)
+{
+ log.error("鎬诲叕鍙革紙ID=101锛変笉瀛樺湪锛屾棤娉曞悓姝ヨ浆杩愰儴");
+ return AjaxResult.error("鎬诲叕鍙革紙ID=101锛変笉瀛樺湪锛岃鍏堝垱寤烘�诲叕鍙�");
+}
+```
+
+2. **纭繚杞繍閮ㄥ瓨鍦�**锛堢 204-227 琛岋級
+```java
+SysDept existingTransport = sysDeptMapper.checkDeptNameUnique("杞繍閮�", 101L);
+
+if (existingTransport != null)
+{
+ transportDeptId = existingTransport.getDeptId();
+ log.info("杞繍閮ㄥ凡瀛樺湪: ID={}", transportDeptId);
+}
+else
+{
+ // 鍒涘缓鏂扮殑杞繍閮�
+ SysDept newTransport = new SysDept();
+ newTransport.setParentId(101L);
+ newTransport.setDeptName("杞繍閮�");
+ newTransport.setAncestors("0,101");
+ newTransport.setOrderNum(1);
+ newTransport.setStatus("0");
+ newTransport.setCreateBy("sync");
+
+ sysDeptMapper.insertDept(newTransport);
+ transportDeptId = newTransport.getDeptId();
+ log.info("鍒涘缓鏂拌浆杩愰儴: ID={}", transportDeptId);
+}
+```
+
+3. **鍚屾瀛愰儴闂�**锛堢 229-293 琛岋級
+```java
+for (DepartmentSyncDTO dto : transportDepts)
+{
+ String deptName = dto.getDepartmentName();
+
+ // 鍏堟牴鎹甦epartmentId鏌ヨ鏄惁宸插瓨鍦�
+ SysDept existingDept = sysDeptMapper.selectDeptByDepartmentIdAndParentId(
+ dto.getDepartmentId(), transportDeptId);
+
+ if (existingDept != null)
+ {
+ // 鏇存柊宸插瓨鍦ㄧ殑閮ㄩ棬
+ existingDept.setDeptName(deptName);
+ existingDept.setUpdateBy("sync");
+ sysDeptMapper.updateDept(existingDept);
+ updatedDept++;
+ }
+ else
+ {
+ // 妫�鏌ユ槸鍚﹀瓨鍦ㄥ悓鍚嶉儴闂�
+ SysDept sameName = sysDeptMapper.checkDeptNameUnique(deptName, transportDeptId);
+ if (sameName != null)
+ {
+ // 鏇存柊鍚屽悕閮ㄩ棬鐨� departmentId
+ sameName.setDepartmentId(dto.getDepartmentId());
+ sameName.setUpdateBy("sync");
+ sysDeptMapper.updateDept(sameName);
+ updatedDept++;
+ }
+ else
+ {
+ // 鍒涘缓鏂伴儴闂�
+ SysDept newDept = new SysDept();
+ newDept.setParentId(transportDeptId);
+ newDept.setDeptName(deptName);
+ newDept.setAncestors("0,101," + transportDeptId);
+ newDept.setOrderNum(1);
+ newDept.setStatus("0");
+ newDept.setDepartmentId(dto.getDepartmentId());
+ newDept.setCreateBy("sync");
+
+ sysDeptMapper.insertDept(newDept);
+ createdDept++;
+ }
+ }
+}
+```
+
+**璁捐鐗圭偣**:
+- 鏀寔骞傜瓑鎬э紙鍙噸澶嶆墽琛岋級
+- 鑷姩鍒ゆ柇鍒涘缓杩樻槸鏇存柊
+- 浣跨敤 `@Transactional` 淇濊瘉浜嬪姟涓�鑷存��
+- 璇︾粏鐨勬棩蹇楄褰�
+
+---
+
+### 7. DepartmentSyncController.java 鉁�
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`
+
+**淇敼鍐呭**: 鏂板 REST API 鎺ュ彛
+
+```java
+/**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * 鍚屾閫昏緫锛�
+ * 1. 纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ * 2. 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂�
+ *
+ * @param transportDepts 杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+@PreAuthorize("@ss.hasPermi('system:dept:sync')")
+@PostMapping("/transport/data")
+public AjaxResult syncTransportDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> transportDepts)
+{
+ return departmentSyncService.syncTransportDepartments(transportDepts);
+}
+```
+
+**淇敼浣嶇疆**: 绗� 50-64 琛岋紙鍦� `/branch/data` 鎺ュ彛鍚庢坊鍔狅級
+
+**鎺ュ彛淇℃伅**:
+- URL: `POST /system/dept/sync/transport/data`
+- 鏉冮檺: `system:dept:sync`
+- 璇锋眰浣�: `List<DepartmentSyncDTO>`
+- 鍝嶅簲: `AjaxResult`
+
+---
+
+## 鏂板鏂囨。
+
+### 1. 杞繍閮ㄥ悓姝ュ姛鑳借鏄�.md 鉁�
+**鏂囦欢璺緞**: `杞繍閮ㄥ悓姝ュ姛鑳借鏄�.md`
+
+**鍐呭鍖呮嫭**:
+- 鍔熻兘姒傝堪
+- 鍚屾閫昏緫璇存槑
+- 瀹炵幇鏋舵瀯
+- 鏍稿績绫昏缁嗚鏄�
+- REST API 鎺ュ彛
+- 鏁版嵁娴佺▼鍥�
+- 閮ㄩ棬灞傜骇缁撴瀯
+- 骞傜瓑鎬ц璁�
+- 浜嬪姟绠$悊
+- 鏁版嵁婧愬垏鎹㈡満鍒�
+- 瀹屾暣璋冪敤绀轰緥
+- 娉ㄦ剰浜嬮」
+
+### 2. 杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�.md 鉁�
+**鏂囦欢璺緞**: `杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�.md`
+
+**鍐呭鍖呮嫭**:
+- 娴嬭瘯鐜鍑嗗
+- 娴嬭瘯姝ラ
+- 娴嬭瘯鍦烘櫙锛�5涓満鏅級
+- 瀹屾暣娴嬭瘯娴佺▼锛圝ava 浠g爜锛�
+- 鏃ュ織鐩戞帶
+- 甯歌闂鎺掓煡
+- 鎬ц兘娴嬭瘯
+- 鍥炴粴娴嬭瘯鏁版嵁
+- 娴嬭瘯娓呭崟
+
+---
+
+## 浠g爜缁熻
+
+| 鏂囦欢绫诲瀷 | 鏂板鏂囦欢 | 淇敼鏂囦欢 | 鎬昏 |
+|---------|---------|---------|------|
+| Mapper XML | 0 | 1 | 1 |
+| Java 鎺ュ彛 | 0 | 3 | 3 |
+| Java 瀹炵幇绫� | 0 | 2 | 2 |
+| Controller | 0 | 1 | 1 |
+| 鏂囨。 | 3 | 0 | 3 |
+| **鎬昏** | **3** | **7** | **10** |
+
+## 鏂板浠g爜琛屾暟缁熻
+
+| 鏂囦欢 | 鏂板琛屾暟 |
+|------|---------|
+| DepartmentSyncMapper.xml | 12 琛� |
+| DepartmentSyncMapper.java | 7 琛� |
+| IDepartmentSyncDataService.java | 9 琛� |
+| DepartmentSyncDataServiceImpl.java | 35 琛� |
+| IDepartmentSyncService.java | 12 琛� |
+| DepartmentSyncServiceImpl.java | 138 琛� |
+| DepartmentSyncController.java | 17 琛� |
+| **浠g爜鎬昏** | **230 琛�** |
+| 杞繍閮ㄥ悓姝ュ姛鑳借鏄�.md | 455 琛� |
+| 杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�.md | 411 琛� |
+| 杞繍閮ㄥ悓姝ュ姛鑳�-淇敼娓呭崟.md | 鏈枃妗� |
+| **鏂囨。鎬昏** | **866+ 琛�** |
+
+---
+
+## 鎶�鏈鐐�
+
+### 1. SQL Server 鏌ヨ浼樺寲
+- 鉁� 浣跨敤 `TOP 500` 闄愬埗杩斿洖鏁版嵁閲�
+- 鉁� 浣跨敤 `WITH (NOLOCK)` 鎻愰珮骞跺彂鎬ц兘
+- 鉁� 涓枃瀛楃涓蹭娇鐢� `N` 鍓嶇紑纭繚姝g‘鍖归厤
+- 鉁� 浣跨敤 `<![CDATA[...]]>` 鍖呰9 SQL 閬垮厤 XML 瑙f瀽闂
+
+### 2. 澶氭暟鎹簮鏋舵瀯
+- 鉁� DataService 鏍囨敞 `@DataSource(DataSourceType.SQLSERVER)` 鏌ヨ SQL Server
+- 鉁� SyncService 浣跨敤榛樿鏁版嵁婧愭搷浣� MySQL
+- 鉁� 鏅鸿兘鏁版嵁婧愬垏鎹紙璇﹁锛氬鏁版嵁婧愬垏鎹㈤棶棰樹慨澶嶈鏄�.md锛�
+
+### 3. 骞傜瓑鎬ц璁�
+- 鉁� 浣跨敤 `departmentId` 浣滀负鍞竴鏍囪瘑
+- 鉁� 鍏堟煡璇㈠悗鍐冲畾鎻掑叆鎴栨洿鏂�
+- 鉁� 鏀寔閲嶅鎵ц涓嶄細浜х敓閲嶅鏁版嵁
+
+### 4. 浜嬪姟绠$悊
+- 鉁� 鎵�鏈夊悓姝ユ柟娉曟爣娉� `@Transactional`
+- 鉁� 寮傚父鏃惰嚜鍔ㄥ洖婊�
+- 鉁� 淇濊瘉鏁版嵁涓�鑷存��
+
+### 5. 鑱岃矗鍒嗙
+- 鉁� DataService: 涓撻棬璐熻矗鏌ヨ SQL Server
+- 鉁� SyncService: 涓撻棬璐熻矗鍚屾鍒� MySQL
+- 鉁� Controller: 鎻愪緵 REST API 鎺ュ彛
+
+---
+
+## 娴嬭瘯楠岃瘉
+
+### 缂栬瘧妫�鏌� 鉁�
+鎵�鏈変慨鏀圭殑鏂囦欢鍧囬�氳繃缂栬瘧妫�鏌ワ紝鏃犺娉曢敊璇��
+
+### 鍔熻兘娴嬭瘯
+璇峰弬鑰� `杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�.md` 杩涜浠ヤ笅娴嬭瘯锛�
+
+- [ ] 娴嬭瘯 1: 浠� SQL Server 鏌ヨ杞繍閮ㄦ暟鎹�
+- [ ] 娴嬭瘯 2: 閫氳繃 REST API 鍚屾杞繍閮�
+- [ ] 娴嬭瘯 3: 楠岃瘉 MySQL 涓殑鍚屾缁撴灉
+- [ ] 鍦烘櫙 1: 棣栨鍚屾
+- [ ] 鍦烘櫙 2: 閲嶅鍚屾锛堝箓绛夋�э級
+- [ ] 鍦烘櫙 3: 閮ㄥ垎鏇存柊
+- [ ] 鍦烘櫙 4: 鍚屽悕閮ㄩ棬澶勭悊
+- [ ] 鍦烘櫙 5: 鎬诲叕鍙镐笉瀛樺湪閿欒澶勭悊
+
+---
+
+## 閮ㄧ讲璇存槑
+
+### 1. 鏁版嵁搴撳噯澶�
+纭繚 MySQL 涓瓨鍦ㄦ�诲叕鍙革細
+```sql
+-- 妫�鏌ユ�诲叕鍙告槸鍚﹀瓨鍦�
+SELECT * FROM sys_dept WHERE dept_id = 101;
+
+-- 濡傛灉涓嶅瓨鍦紝鍒涘缓鎬诲叕鍙�
+INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, status, create_by, create_time)
+VALUES (101, 0, '0', '鎬诲叕鍙�', 1, '0', 'admin', NOW());
+```
+
+### 2. 浠g爜閮ㄧ讲
+1. 缂栬瘧椤圭洰锛歚mvn clean package`
+2. 閮ㄧ讲鍒版湇鍔″櫒
+3. 閲嶅惎搴旂敤
+
+### 3. 鏉冮檺閰嶇疆
+纭繚闇�瑕佽皟鐢ㄥ悓姝ユ帴鍙g殑鐢ㄦ埛鎷ユ湁 `system:dept:sync` 鏉冮檺銆�
+
+---
+
+## 璋冪敤绀轰緥
+
+### REST API 璋冪敤
+```bash
+curl -X POST http://localhost:8080/system/dept/sync/transport/data \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer YOUR_TOKEN" \
+ -d '[
+ {
+ "departmentId": 1001,
+ "departmentName": "杞繍闃�",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ },
+ {
+ "departmentId": 1002,
+ "departmentName": "璋冨害涓績",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ }
+ ]'
+```
+
+### Java 浠g爜璋冪敤
+```java
+// 姝ラ 1: 鏌ヨ SQL Server 鏁版嵁
+List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
+
+// 姝ラ 2: 鍚屾鍒� MySQL
+AjaxResult result = departmentSyncService.syncTransportDepartments(transportDepts);
+```
+
+---
+
+## 鍚庣画浼樺寲寤鸿
+
+### 1. 娣诲姞鏌ヨ鎺ュ彛
+鍙互娣诲姞涓�涓� GET 鎺ュ彛鐩存帴杩斿洖 SQL Server 鐨勮浆杩愰儴鏁版嵁锛�
+```java
+@GetMapping("/transport/query")
+public AjaxResult queryTransportDepartments()
+{
+ List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
+ return AjaxResult.success(transportDepts);
+}
+```
+
+### 2. 娣诲姞鍐呴儴鏌ヨ妯″紡
+鍍忓垎鍏徃鍚屾涓�鏍凤紝娣诲姞涓�涓笉闇�瑕佷紶鍙傜殑鍚屾鏂规硶锛�
+```java
+// 鎺ュ彛
+AjaxResult syncTransportDepartments();
+
+// 瀹炵幇
+@Override
+@Transactional
+public AjaxResult syncTransportDepartments()
+{
+ List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
+ return syncTransportDepartments(transportDepts);
+}
+
+// Controller
+@PostMapping("/transport")
+public AjaxResult syncTransportDepartments()
+{
+ return departmentSyncService.syncTransportDepartments();
+}
+```
+
+### 3. 鎵归噺鍚屾
+娣诲姞涓�涓帴鍙e悓鏃跺悓姝ュ垎鍏徃鍜岃浆杩愰儴锛�
+```java
+@PostMapping("/all")
+public AjaxResult syncAllDepartments()
+{
+ // 鍚屾鍒嗗叕鍙�
+ AjaxResult branchResult = syncBranchDepartments();
+
+ // 鍚屾杞繍閮�
+ AjaxResult transportResult = syncTransportDepartments();
+
+ // 鍚堝苟缁撴灉杩斿洖
+ return AjaxResult.success("鍏ㄩ儴鍚屾瀹屾垚",
+ Map.of("branch", branchResult, "transport", transportResult));
+}
+```
+
+---
+
+## 鐩稿叧鏂囨。閾炬帴
+
+1. [杞繍閮ㄥ悓姝ュ姛鑳借鏄�.md](杞繍閮ㄥ悓姝ュ姛鑳借鏄�.md) - 鍔熻兘璇︾粏璇存槑
+2. [杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�.md](杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�.md) - 娴嬭瘯鎸囧崡
+3. [閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑.md](閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑.md) - 鍒嗗叕鍙稿悓姝ユ灦鏋�
+4. [鐢ㄦ埛鍚屾鏈嶅姟閲嶆瀯璇存槑.md](鐢ㄦ埛鍚屾鏈嶅姟閲嶆瀯璇存槑.md) - 鐢ㄦ埛鍚屾鏋舵瀯
+5. [澶氭暟鎹簮鍒囨崲闂淇璇存槑.md](澶氭暟鎹簮鍒囨崲闂淇璇存槑.md) - 鏁版嵁婧愬垏鎹㈡満鍒�
+6. [SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md](SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md) - SQL 浼樺寲
+
+---
+
+## 鐗堟湰淇℃伅
+
+- **鍔熻兘鐗堟湰**: v1.0
+- **寮�鍙戞棩鏈�**: 2025-10-18
+- **寮�鍙戜汉鍛�**: AI Assistant
+- **瀹℃牳鐘舵��**: 寰呮祴璇�
+- **妗嗘灦鐗堟湰**: RuoYi-Vue (Spring Boot 2.5.15)
+
+---
+
+## 鏇存柊鏃ュ織
+
+### v1.0 (2025-10-18)
+- 鉁� 鏂板杞繍閮ㄦ暟鎹煡璇㈠姛鑳�
+- 鉁� 鏂板杞繍閮ㄥ悓姝ュ姛鑳�
+- 鉁� 鏂板 REST API 鎺ュ彛
+- 鉁� 缂栧啓鍔熻兘璇存槑鏂囨。
+- 鉁� 缂栧啓娴嬭瘯鎸囧崡鏂囨。
+- 鉁� 缂栧啓淇敼娓呭崟鏂囨。
diff --git "a/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275\346\265\213\350\257\225\346\214\207\345\215\227.md" "b/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275\346\265\213\350\257\225\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..42f4eee
--- /dev/null
+++ "b/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275\346\265\213\350\257\225\346\214\207\345\215\227.md"
@@ -0,0 +1,410 @@
+# 杞繍閮ㄥ悓姝ュ姛鑳芥祴璇曟寚鍗�
+
+## 娴嬭瘯鐜鍑嗗
+
+### 1. 纭繚鎬诲叕鍙稿瓨鍦�
+鍦� MySQL 鏁版嵁搴撲腑纭鎬诲叕鍙革紙ID=101锛夊凡瀛樺湪锛�
+
+```sql
+SELECT * FROM sys_dept WHERE dept_id = 101;
+```
+
+濡傛灉涓嶅瓨鍦紝闇�瑕佸厛鍒涘缓锛�
+
+```sql
+INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, status, create_by, create_time)
+VALUES (101, 0, '0', '鎬诲叕鍙�', 1, '0', 'admin', NOW());
+```
+
+### 2. 纭繚 SQL Server 杩炴帴姝e父
+娴嬭瘯 SQL Server 鏁版嵁婧愭槸鍚﹀彲鐢紝鏌ョ湅杞繍閮ㄦ暟鎹細
+
+```sql
+-- 鍦� SQL Server 涓墽琛�
+SELECT TOP 10
+ b.departmentID,
+ b.departmentName,
+ b.parentID,
+ a.departmentName AS parentName
+FROM uv_department a WITH (NOLOCK)
+INNER JOIN uv_department b WITH (NOLOCK) ON a.departmentID = b.parentID
+WHERE a.departmentName = N'杞繍閮�'
+ORDER BY b.departmentName
+```
+
+## 娴嬭瘯姝ラ
+
+### 娴嬭瘯 1: 鏌ヨ杞繍閮ㄦ暟鎹紙鍙�夛級
+
+濡傛灉闇�瑕佸崟鐙祴璇曟暟鎹煡璇㈠姛鑳斤紝鍙互鍦ㄤ唬鐮佷腑璋冪敤锛�
+
+```java
+@Autowired
+private IDepartmentSyncDataService departmentSyncDataService;
+
+// 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬
+List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
+System.out.println("鏌ヨ鍒拌浆杩愰儴瀛愰儴闂ㄦ暟閲�: " + transportDepts.size());
+```
+
+### 娴嬭瘯 2: 閫氳繃 REST API 鍚屾杞繍閮�
+
+#### 浣跨敤 Postman 鎴� curl 娴嬭瘯
+
+**璇锋眰 URL**:
+```
+POST http://localhost:8080/system/dept/sync/transport/data
+```
+
+**璇锋眰澶�**:
+```
+Content-Type: application/json
+Authorization: Bearer {your_token}
+```
+
+**璇锋眰浣撶ず渚�**:
+```json
+[
+ {
+ "departmentId": 1001,
+ "departmentName": "杞繍闃�",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ },
+ {
+ "departmentId": 1002,
+ "departmentName": "璋冨害涓績",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ },
+ {
+ "departmentId": 1003,
+ "departmentName": "璁惧缁存姢",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ }
+]
+```
+
+**curl 鍛戒护**:
+```bash
+curl -X POST http://localhost:8080/system/dept/sync/transport/data \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer YOUR_TOKEN" \
+ -d '[
+ {
+ "departmentId": 1001,
+ "departmentName": "杞繍闃�",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ },
+ {
+ "departmentId": 1002,
+ "departmentName": "璋冨害涓績",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ }
+ ]'
+```
+
+**鏈熸湜鍝嶅簲**:
+```json
+{
+ "code": 200,
+ "msg": "杞繍閮ㄥ悓姝ュ畬鎴愶紒鍒涘缓瀛愰儴闂�: 2, 鏇存柊瀛愰儴闂�: 0",
+ "data": {
+ "transportDeptId": 200,
+ "createdDept": 2,
+ "updatedDept": 0,
+ "totalProcessed": 2
+ }
+}
+```
+
+### 娴嬭瘯 3: 楠岃瘉鍚屾缁撴灉
+
+#### 鍦� MySQL 涓獙璇�
+
+```sql
+-- 1. 鏌ヨ杞繍閮ㄦ槸鍚﹀垱寤烘垚鍔�
+SELECT * FROM sys_dept
+WHERE dept_name = '杞繍閮�' AND parent_id = 101;
+
+-- 2. 鏌ヨ杞繍閮ㄧ殑瀛愰儴闂�
+SELECT
+ d.dept_id,
+ d.dept_name,
+ d.department_id AS sql_server_dept_id,
+ d.parent_id,
+ p.dept_name AS parent_name,
+ d.ancestors,
+ d.create_time,
+ d.update_time
+FROM sys_dept d
+LEFT JOIN sys_dept p ON d.parent_id = p.dept_id
+WHERE p.dept_name = '杞繍閮�'
+ORDER BY d.dept_id;
+
+-- 3. 鏌ョ湅瀹屾暣鐨勯儴闂ㄦ爲锛堝寘鎷浆杩愰儴锛�
+SELECT
+ CASE
+ WHEN dept_id = 101 THEN dept_name
+ WHEN parent_id = 101 THEN CONCAT(' 鈹斺攢 ', dept_name)
+ ELSE CONCAT(' 鈹斺攢 ', dept_name)
+ END AS dept_tree,
+ dept_id,
+ department_id,
+ parent_id,
+ status
+FROM sys_dept
+WHERE dept_id = 101
+ OR parent_id = 101
+ OR parent_id IN (SELECT dept_id FROM sys_dept WHERE parent_id = 101)
+ORDER BY ancestors, order_num;
+```
+
+## 娴嬭瘯鍦烘櫙
+
+### 鍦烘櫙 1: 棣栨鍚屾
+**鍓嶇疆鏉′欢**:
+- 鎬诲叕鍙革紙ID=101锛夊瓨鍦�
+- "杞繍閮�"涓嶅瓨鍦�
+- 杞繍閮ㄧ殑瀛愰儴闂ㄩ兘涓嶅瓨鍦�
+
+**鎵ц鎿嶄綔**: 璋冪敤鍚屾鎺ュ彛
+
+**棰勬湡缁撴灉**:
+- 鍒涘缓"杞繍閮�"锛坧arent_id=101锛�
+- 鍒涘缓鎵�鏈夊瓙閮ㄩ棬锛坧arent_id=杞繍閮↖D锛�
+- 鍝嶅簲鏄剧ず锛氬垱寤哄瓙閮ㄩ棬鏁� = 浼犲叆鐨勬暟鎹潯鏁�
+
+### 鍦烘櫙 2: 閲嶅鍚屾锛堝箓绛夋�ф祴璇曪級
+**鍓嶇疆鏉′欢**:
+- 宸插畬鎴愬満鏅� 1 鐨勫悓姝�
+- 鎵�鏈夐儴闂ㄩ兘宸插瓨鍦�
+
+**鎵ц鎿嶄綔**: 浣跨敤鐩稿悓鐨勬暟鎹啀娆¤皟鐢ㄥ悓姝ユ帴鍙�
+
+**棰勬湡缁撴灉**:
+- "杞繍閮�"涓嶄細閲嶅鍒涘缓
+- 瀛愰儴闂ㄤ笉浼氶噸澶嶅垱寤�
+- 宸插瓨鍦ㄧ殑瀛愰儴闂ㄤ俊鎭細琚洿鏂�
+- 鍝嶅簲鏄剧ず锛氭洿鏂板瓙閮ㄩ棬鏁� = 浼犲叆鐨勬暟鎹潯鏁帮紝鍒涘缓瀛愰儴闂ㄦ暟 = 0
+
+### 鍦烘櫙 3: 閮ㄥ垎鏇存柊
+**鍓嶇疆鏉′欢**:
+- 宸插畬鎴愬満鏅� 1 鐨勫悓姝�
+- 閮ㄥ垎瀛愰儴闂ㄥ凡瀛樺湪
+
+**鎵ц鎿嶄綔**: 浼犲叆鍖呭惈鏂伴儴闂ㄥ拰宸插瓨鍦ㄩ儴闂ㄧ殑娣峰悎鏁版嵁
+
+**棰勬湡缁撴灉**:
+- 鏂伴儴闂ㄨ鍒涘缓
+- 宸插瓨鍦ㄧ殑閮ㄩ棬琚洿鏂�
+- 鍝嶅簲鏄剧ず锛氬垱寤哄瓙閮ㄩ棬鏁� + 鏇存柊瀛愰儴闂ㄦ暟 = 浼犲叆鐨勬暟鎹潯鏁�
+
+### 鍦烘櫙 4: 鍚屽悕閮ㄩ棬澶勭悊
+**鍓嶇疆鏉′欢**:
+- 宸叉墜鍔ㄥ垱寤轰簡涓�涓悕涓�"杞繍闃�"鐨勯儴闂紙娌℃湁 department_id锛�
+
+**鎵ц鎿嶄綔**: 鍚屾鍖呭惈"杞繍闃�"鐨勬暟鎹�
+
+**棰勬湡缁撴灉**:
+- 涓嶄細鍒涘缓閲嶅鐨�"杞繍闃�"
+- 宸插瓨鍦ㄧ殑"杞繍闃�"浼氳鏇存柊锛屾坊鍔� department_id
+- 鍝嶅簲鏄剧ず锛氭洿鏂板瓙閮ㄩ棬鏁� = 1
+
+### 鍦烘櫙 5: 鎬诲叕鍙镐笉瀛樺湪
+**鍓嶇疆鏉′欢**:
+- 鎬诲叕鍙革紙ID=101锛変笉瀛樺湪
+
+**鎵ц鎿嶄綔**: 璋冪敤鍚屾鎺ュ彛
+
+**棰勬湡缁撴灉**:
+- 鍚屾澶辫触
+- 杩斿洖閿欒淇℃伅锛�"鎬诲叕鍙革紙ID=101锛変笉瀛樺湪锛岃鍏堝垱寤烘�诲叕鍙�"
+
+## 瀹屾暣娴嬭瘯娴佺▼锛圝ava 浠g爜锛�
+
+```java
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.DepartmentSyncDTO;
+import com.ruoyi.system.service.IDepartmentSyncDataService;
+import com.ruoyi.system.service.IDepartmentSyncService;
+import java.util.List;
+
+@RestController
+@RequestMapping("/test")
+public class TestTransportSyncController
+{
+ @Autowired
+ private IDepartmentSyncDataService departmentSyncDataService;
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ /**
+ * 瀹屾暣娴嬭瘯锛氭煡璇㈠苟鍚屾杞繍閮ㄦ暟鎹�
+ */
+ @GetMapping("/syncTransport")
+ public AjaxResult testSyncTransport()
+ {
+ try
+ {
+ // 姝ラ 1: 浠� SQL Server 鏌ヨ杞繍閮ㄦ暟鎹�
+ System.out.println("===== 寮�濮嬫煡璇� SQL Server 杞繍閮ㄦ暟鎹� =====");
+ List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
+ System.out.println("鏌ヨ鍒� " + transportDepts.size() + " 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹�");
+
+ if (transportDepts.isEmpty())
+ {
+ return AjaxResult.warn("SQL Server 涓病鏈夎浆杩愰儴鏁版嵁");
+ }
+
+ // 鎵撳嵃鏌ヨ鍒扮殑鏁版嵁
+ for (DepartmentSyncDTO dto : transportDepts)
+ {
+ System.out.println(String.format(" 閮ㄩ棬: %s, ID: %d, 鐖剁骇: %s",
+ dto.getDepartmentName(),
+ dto.getDepartmentId(),
+ dto.getParentName()));
+ }
+
+ // 姝ラ 2: 鍚屾鍒� MySQL
+ System.out.println("\n===== 寮�濮嬪悓姝ュ埌 MySQL =====");
+ AjaxResult result = departmentSyncService.syncTransportDepartments(transportDepts);
+
+ System.out.println("鍚屾缁撴灉: " + result.get("msg"));
+ System.out.println("璇︾粏淇℃伅: " + result.get("data"));
+
+ return result;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return AjaxResult.error("娴嬭瘯澶辫触: " + e.getMessage());
+ }
+ }
+}
+```
+
+## 鏃ュ織鐩戞帶
+
+鍚屾杩囩▼涓細杈撳嚭璇︾粏鐨勬棩蹇楋紝鍏虫敞浠ヤ笅鍏抽敭鏃ュ織锛�
+
+### 鏁版嵁鏌ヨ鏃ュ織锛圖epartmentSyncDataServiceImpl锛�
+```
+寮�濮嬩粠 SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁...
+浠� SQL Server 鏌ヨ鍒� 5 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹�
+```
+
+### 鍚屾閫昏緫鏃ュ織锛圖epartmentSyncServiceImpl锛�
+```
+寮�濮嬪悓姝� 5 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹埌 MySQL 鏁版嵁搴�...
+杞繍閮ㄥ凡瀛樺湪: ID=200
+鍒涘缓鏂拌浆杩愰儴瀛愰儴闂�: 杞繍闃�, departmentId: 1001
+鍒涘缓鏂拌浆杩愰儴瀛愰儴闂�: 璋冨害涓績, departmentId: 1002
+鏇存柊杞繍閮ㄥ瓙閮ㄩ棬: 璁惧缁存姢
+杞繍閮ㄥ悓姝ュ畬鎴愶紒鍒涘缓瀛愰儴闂�: 2, 鏇存柊瀛愰儴闂�: 1
+```
+
+### 鏁版嵁婧愬垏鎹㈡棩蹇楋紙DataSourceAspect锛�
+```
+鍒囨崲鏁版嵁婧�: null -> SQLSERVER
+鍒囨崲鏁版嵁婧�: SQLSERVER -> null
+```
+
+## 甯歌闂鎺掓煡
+
+### 闂 1: "鎬诲叕鍙革紙ID=101锛変笉瀛樺湪"
+**鍘熷洜**: 鏁版嵁搴撲腑娌℃湁 ID=101 鐨勯儴闂�
+
+**瑙e喅鏂规**:
+```sql
+INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, status, create_by, create_time)
+VALUES (101, 0, '0', '鎬诲叕鍙�', 1, '0', 'admin', NOW());
+```
+
+### 闂 2: "浠� SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁澶辫触"
+**鍘熷洜**:
+1. SQL Server 鏁版嵁婧愰厤缃敊璇�
+2. uv_department 瑙嗗浘涓嶅瓨鍦�
+3. 缃戠粶杩炴帴闂
+
+**瑙e喅鏂规**:
+1. 妫�鏌� `application.yml` 涓� SQL Server 鏁版嵁婧愰厤缃�
+2. 鍦� SQL Server 涓‘璁よ鍥惧瓨鍦細`SELECT * FROM uv_department WHERE departmentName = N'杞繍閮�'`
+3. 娴嬭瘯鏁版嵁搴撹繛鎺�
+
+### 闂 3: 閮ㄩ棬閲嶅鍒涘缓
+**鍘熷洜**: departmentId 瀛楁娌℃湁姝g‘璁剧疆鎴栧尮閰�
+
+**瑙e喅鏂规**:
+1. 纭繚 DepartmentSyncDTO 涓殑 departmentId 瀛楁姝g‘
+2. 妫�鏌� sys_dept 琛ㄤ腑鐨� department_id 瀛楁鏄惁姝g‘鍏宠仈
+
+### 闂 4: 鏁版嵁婧愬垏鎹㈠け璐�
+**鍘熷洜**: DataSourceAspect 閰嶇疆闂
+
+**瑙e喅鏂规**:
+1. 纭 DataSourceAspect.java 宸叉寜鐓�"澶氭暟鎹簮鍒囨崲闂淇璇存槑.md"杩涜淇
+2. 鏌ョ湅鏃ュ織纭鏁版嵁婧愬垏鎹㈡儏鍐�
+
+## 鎬ц兘娴嬭瘯
+
+### 娴嬭瘯涓嶅悓鏁版嵁閲忕殑鍚屾鎬ц兘
+
+```java
+// 娴嬭瘯 10 鏉℃暟鎹�
+List<DepartmentSyncDTO> data10 = generateTestData(10);
+long start = System.currentTimeMillis();
+departmentSyncService.syncTransportDepartments(data10);
+long time10 = System.currentTimeMillis() - start;
+System.out.println("10 鏉℃暟鎹悓姝ヨ�楁椂: " + time10 + "ms");
+
+// 娴嬭瘯 100 鏉℃暟鎹�
+List<DepartmentSyncDTO> data100 = generateTestData(100);
+start = System.currentTimeMillis();
+departmentSyncService.syncTransportDepartments(data100);
+long time100 = System.currentTimeMillis() - start;
+System.out.println("100 鏉℃暟鎹悓姝ヨ�楁椂: " + time100 + "ms");
+```
+
+## 鍥炴粴娴嬭瘯鏁版嵁
+
+濡傛灉闇�瑕佹竻闄ゆ祴璇曟暟鎹噸鏂版祴璇曪細
+
+```sql
+-- 鍒犻櫎杞繍閮ㄧ殑瀛愰儴闂�
+DELETE FROM sys_dept
+WHERE parent_id IN (
+ SELECT dept_id FROM sys_dept
+ WHERE dept_name = '杞繍閮�' AND parent_id = 101
+);
+
+-- 鍒犻櫎杞繍閮�
+DELETE FROM sys_dept
+WHERE dept_name = '杞繍閮�' AND parent_id = 101;
+```
+
+## 鎬荤粨
+
+瀹屾垚浠ヤ笂娴嬭瘯鍚庯紝纭浠ヤ笅鍔熻兘姝e父锛�
+
+- 鉁� 浠� SQL Server 鏌ヨ杞繍閮ㄦ暟鎹�
+- 鉁� 鍒涘缓杞繍閮紙濡傛灉涓嶅瓨鍦級
+- 鉁� 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂�
+- 鉁� 鏇存柊宸插瓨鍦ㄧ殑瀛愰儴闂�
+- 鉁� 骞傜瓑鎬э紙鍙噸澶嶆墽琛岋級
+- 鉁� 浜嬪姟鍥炴粴锛堝紓甯告椂锛�
+- 鉁� 鏁版嵁婧愯嚜鍔ㄥ垏鎹�
+- 鉁� 鏃ュ織璁板綍瀹屾暣
+
+## 鐩稿叧鏂囨。
+
+- `杞繍閮ㄥ悓姝ュ姛鑳借鏄�.md` - 鍔熻兘璇︾粏璇存槑
+- `閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑.md` - 鏋舵瀯璁捐璇存槑
+- `澶氭暟鎹簮鍒囨崲闂淇璇存槑.md` - 鏁版嵁婧愬垏鎹㈡満鍒�
diff --git "a/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..b2bdd34
--- /dev/null
+++ "b/\350\275\254\350\277\220\351\203\250\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,454 @@
+# 杞繍閮ㄥ悓姝ュ姛鑳借鏄�
+
+## 鍔熻兘姒傝堪
+
+鍦ㄧ幇鏈夌殑鍒嗗叕鍙稿悓姝ュ姛鑳藉熀纭�涓婏紝鏂板杞繍閮ㄥ悓姝ュ姛鑳姐�傝浆杩愰儴鏄�诲叕鍙革紙ID=101锛変笅鐨勪竴涓儴闂紝闇�瑕佸悓姝ヨ浆杩愰儴鍙婂叾瀛愰儴闂ㄦ暟鎹��
+
+## 鍚屾閫昏緫
+
+### 1. 鍒嗗叕鍙稿悓姝�
+- **鐖堕儴闂�**: 鑻ヤ緷绉戞妧锛圛D=100锛�
+- **鏁版嵁婧�**: SQL Server - `uv_department` 瑙嗗浘
+- **鏌ヨ鏉′欢**: `a.departmentName = N'鍚堜綔鍗曚綅'`
+- **鍚嶇О鏍煎紡**: `婀涙睙--鎶ゅ+` 鈫� 鍒嗗叕鍙革細`婀涙睙鍒嗗叕鍙竊锛屽瓙閮ㄩ棬锛歚鎶ゅ+`
+- **鐗圭偣**: 闇�瑕佽В鏋�"--"鍒嗛殧绗︽潵鍒涘缓鍒嗗叕鍙稿拰瀛愰儴闂�
+
+### 2. 杞繍閮ㄥ悓姝ワ紙鏂板锛�
+- **鐖堕儴闂�**: 鎬诲叕鍙革紙ID=101锛�
+- **鏁版嵁婧�**: SQL Server - `uv_department` 瑙嗗浘
+- **鏌ヨ鏉′欢**: `a.departmentName = N'杞繍閮�'`
+- **鍚嶇О鏍煎紡**: 鐩存帴浣跨敤 `departmentName`锛屾棤闇�瑙f瀽
+- **鐗圭偣**: 鐩存帴鍒涘缓杞繍閮ㄧ殑瀛愰儴闂紝涓嶉渶瑕佽В鏋�"--"鏍煎紡
+
+## 瀹炵幇鏋舵瀯
+
+### 鑱岃矗鍒嗙璁捐
+
+```
+Controller (REST API)
+ 鈫�
+Service (鍚屾閫昏緫 - MySQL)
+ 鈫�
+DataService (鏁版嵁鏌ヨ - SQL Server)
+ 鈫�
+Mapper (SQL 鎵ц)
+```
+
+### 鏍稿績绫昏鏄�
+
+#### 1. DepartmentSyncMapper.xml
+**鏂囦欢璺緞**: `ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml`
+
+鏂板鏌ヨ鏂规硶锛�
+```xml
+<!-- 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬 -->
+<select id="selectTransportDepartments" resultMap="DepartmentSyncResult">
+ <![CDATA[
+ SELECT TOP 500
+ b.departmentID,
+ b.departmentName,
+ b.parentID,
+ a.departmentName AS parentName
+ FROM uv_department a WITH (NOLOCK)
+ INNER JOIN uv_department b WITH (NOLOCK) ON a.departmentID = b.parentID
+ WHERE a.departmentName = N'杞繍閮�'
+ ORDER BY b.departmentName
+ ]]>
+</select>
+```
+
+**SQL 浼樺寲瑕佺偣**:
+- 浣跨敤 `TOP 500` 闄愬埗杩斿洖鏁版嵁閲�
+- 浣跨敤 `WITH (NOLOCK)` 鎻愰珮鏌ヨ鎬ц兘
+- 涓枃瀛楃涓蹭娇鐢� `N` 鍓嶇紑纭繚姝g‘鍖归厤
+- 浣跨敤 `<![CDATA[...]]>` 鍖呰9 SQL 閬垮厤 XML 鐗规畩瀛楃闂
+
+#### 2. DepartmentSyncMapper.java
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java`
+
+鏂板鏂规硶锛�
+```java
+/**
+ * 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+List<DepartmentSyncDTO> selectTransportDepartments();
+```
+
+**鐗圭偣**:
+- 鎺ュ彛绾у埆鏍囨敞 `@DataSource(DataSourceType.SQLSERVER)`
+- 鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧�
+
+#### 3. IDepartmentSyncDataService.java
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java`
+
+鏂板鏂规硶锛�
+```java
+/**
+ * 浠� SQL Server 鏌ヨ杞繍閮ㄤ笅鐨勬墍鏈夊瓙閮ㄩ棬鏁版嵁
+ *
+ * 鏁版嵁婧愶細SQL Server (uv_department 瑙嗗浘)
+ *
+ * @return 杞繍閮ㄥ瓙閮ㄩ棬鍒楄〃
+ */
+List<DepartmentSyncDTO> getTransportDepartments();
+```
+
+#### 4. DepartmentSyncDataServiceImpl.java
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java`
+
+鏂板瀹炵幇锛�
+```java
+@Override
+public List<DepartmentSyncDTO> getTransportDepartments()
+{
+ try
+ {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁...");
+
+ List<DepartmentSyncDTO> transportDepts = departmentSyncMapper.selectTransportDepartments();
+
+ if (transportDepts == null || transportDepts.isEmpty())
+ {
+ log.warn("鏈粠 SQL Server 鏌ヨ鍒拌浆杩愰儴瀛愰儴闂ㄦ暟鎹�");
+ return transportDepts;
+ }
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉¤浆杩愰儴瀛愰儴闂ㄦ暟鎹�", transportDepts.size());
+ return transportDepts;
+ }
+ catch (Exception e)
+ {
+ log.error("浠� SQL Server 鏌ヨ杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁澶辫触", e);
+ throw new RuntimeException("鏌ヨ SQL Server 鏁版嵁澶辫触: " + e.getMessage(), e);
+ }
+}
+```
+
+**鐗圭偣**:
+- 绫荤骇鍒爣娉� `@DataSource(DataSourceType.SQLSERVER)`
+- 鍙礋璐f煡璇� SQL Server 鏁版嵁锛屼笉娑夊強 MySQL 鎿嶄綔
+
+#### 5. IDepartmentSyncService.java
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java`
+
+鏂板鏂规硶锛�
+```java
+/**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * 鍚屾閫昏緫锛�
+ * 1. 纭繚鎬诲叕鍙革紙ID=101锛変笅瀛樺湪"杞繍閮�"
+ * 2. 鍒涘缓杞繍閮ㄧ殑瀛愰儴闂紙鐩存帴鍒涘缓锛屾棤闇�瑙f瀽"--"鏍煎紡锛�
+ *
+ * @param transportDepts 澶栭儴浼犲叆鐨勮浆杩愰儴瀛愰儴闂ㄦ暟鎹垪琛�
+ * @return 鍚屾缁撴灉
+ */
+AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts);
+```
+
+#### 6. DepartmentSyncServiceImpl.java
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java`
+
+鏂板瀹炵幇锛堟牳蹇冨悓姝ラ�昏緫锛夛細
+```java
+@Override
+@Transactional
+public AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts)
+{
+ // 1. 妫�鏌ユ�诲叕鍙革紙ID=101锛夋槸鍚﹀瓨鍦�
+ SysDept headOffice = sysDeptMapper.selectDeptById(101L);
+ if (headOffice == null)
+ {
+ return AjaxResult.error("鎬诲叕鍙革紙ID=101锛変笉瀛樺湪锛岃鍏堝垱寤烘�诲叕鍙�");
+ }
+
+ // 2. 纭繚"杞繍閮�"瀛樺湪
+ SysDept existingTransport = sysDeptMapper.checkDeptNameUnique("杞繍閮�", 101L);
+ if (existingTransport == null)
+ {
+ // 鍒涘缓杞繍閮�
+ SysDept newTransport = new SysDept();
+ newTransport.setParentId(101L);
+ newTransport.setDeptName("杞繍閮�");
+ newTransport.setAncestors("0,101");
+ newTransport.setOrderNum(1);
+ newTransport.setStatus("0");
+ newTransport.setCreateBy("sync");
+ sysDeptMapper.insertDept(newTransport);
+ transportDeptId = newTransport.getDeptId();
+ }
+ else
+ {
+ transportDeptId = existingTransport.getDeptId();
+ }
+
+ // 3. 鍒涘缓鎴栨洿鏂拌浆杩愰儴瀛愰儴闂�
+ for (DepartmentSyncDTO dto : transportDepts)
+ {
+ String deptName = dto.getDepartmentName();
+
+ // 妫�鏌ユ槸鍚﹀凡瀛樺湪锛堥�氳繃 departmentId + parentId锛�
+ SysDept existingDept = sysDeptMapper.selectDeptByDepartmentIdAndParentId(
+ dto.getDepartmentId(), transportDeptId);
+
+ if (existingDept != null)
+ {
+ // 鏇存柊宸插瓨鍦ㄧ殑閮ㄩ棬
+ existingDept.setDeptName(deptName);
+ existingDept.setUpdateBy("sync");
+ sysDeptMapper.updateDept(existingDept);
+ }
+ else
+ {
+ // 妫�鏌ユ槸鍚﹀瓨鍦ㄥ悓鍚嶉儴闂�
+ SysDept sameName = sysDeptMapper.checkDeptNameUnique(deptName, transportDeptId);
+ if (sameName != null)
+ {
+ // 鏇存柊鍚屽悕閮ㄩ棬鐨� departmentId
+ sameName.setDepartmentId(dto.getDepartmentId());
+ sameName.setUpdateBy("sync");
+ sysDeptMapper.updateDept(sameName);
+ }
+ else
+ {
+ // 鍒涘缓鏂伴儴闂�
+ SysDept newDept = new SysDept();
+ newDept.setParentId(transportDeptId);
+ newDept.setDeptName(deptName);
+ newDept.setAncestors("0,101," + transportDeptId);
+ newDept.setOrderNum(1);
+ newDept.setStatus("0");
+ newDept.setDepartmentId(dto.getDepartmentId());
+ newDept.setCreateBy("sync");
+ sysDeptMapper.insertDept(newDept);
+ }
+ }
+ }
+}
+```
+
+**鐗圭偣**:
+- 鍙秹鍙� MySQL 鏁版嵁搴撴搷浣�
+- 浣跨敤 `@Transactional` 淇濊瘉浜嬪姟涓�鑷存��
+- 鏀寔骞傜瓑鎬ц璁★紙鍙噸澶嶆墽琛岋級
+
+#### 7. DepartmentSyncController.java
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`
+
+鏂板鎺ュ彛锛�
+```java
+/**
+ * 鍚屾杞繍閮ㄥ拰瀛愰儴闂ㄦ暟鎹紙浣跨敤澶栭儴浼犲叆鐨勬暟鎹簮锛�
+ *
+ * @param transportDepts 杞繍閮ㄥ瓙閮ㄩ棬鏁版嵁鍒楄〃
+ * @return 鍚屾缁撴灉
+ */
+@PreAuthorize("@ss.hasPermi('system:dept:sync')")
+@PostMapping("/transport/data")
+public AjaxResult syncTransportDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> transportDepts)
+{
+ return departmentSyncService.syncTransportDepartments(transportDepts);
+}
+```
+
+## REST API 鎺ュ彛
+
+### 1. 鍚屾鍒嗗叕鍙革紙澶栭儴鏁版嵁婧愶級
+- **URL**: `POST /system/dept/sync/branch/data`
+- **鏉冮檺**: `system:dept:sync`
+- **璇锋眰浣�**: `List<DepartmentSyncDTO>`
+- **璇存槑**: 鎺ユ敹澶栭儴浼犲叆鐨勫垎鍏徃鏁版嵁杩涜鍚屾
+
+### 2. 鍚屾杞繍閮紙澶栭儴鏁版嵁婧愶級
+- **URL**: `POST /system/dept/sync/transport/data`
+- **鏉冮檺**: `system:dept:sync`
+- **璇锋眰浣�**: `List<DepartmentSyncDTO>`
+- **璇存槑**: 鎺ユ敹澶栭儴浼犲叆鐨勮浆杩愰儴瀛愰儴闂ㄦ暟鎹繘琛屽悓姝�
+
+### 3. 鍚屾 OA 鐢ㄦ埛锛堝閮ㄦ暟鎹簮锛�
+- **URL**: `POST /system/dept/sync/user/data`
+- **鏉冮檺**: `system:user:sync`
+- **璇锋眰浣�**: `List<UserSyncDTO>`
+- **璇存槑**: 鎺ユ敹澶栭儴浼犲叆鐨� OA 鐢ㄦ埛鏁版嵁杩涜鍚屾
+
+## 鏁版嵁娴佺▼鍥�
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 澶栭儴绯荤粺/瀹氭椂浠诲姟 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ 鈹� 璋冪敤 REST API
+ 鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncController 鈹�
+鈹� 鈥� /branch/data (鍒嗗叕鍙稿悓姝�) 鈹�
+鈹� 鈥� /transport/data (杞繍閮ㄥ悓姝�) 鈫� 鏂板 鈹�
+鈹� 鈥� /user/data (鐢ㄦ埛鍚屾) 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ 鈹� 浼犻�� DTO 鍒楄〃
+ 鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncServiceImpl (MySQL) 鈹�
+鈹� 鈥� syncBranchDepartments() 鈹�
+鈹� 鈥� syncTransportDepartments() 鈫� 鏂板 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ 鈹� 鍐欏叆 MySQL
+ 鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� SysDeptMapper 鈹�
+鈹� 鈥� 鏌ヨ宸插瓨鍦ㄩ儴闂� 鈹�
+鈹� 鈥� 鎻掑叆鏂伴儴闂� 鈹�
+鈹� 鈥� 鏇存柊閮ㄩ棬淇℃伅 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+## 鏁版嵁鏌ヨ娴佺▼
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 澶栭儴绯荤粺闇�瑕佸厛璋冪敤 DataService 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ 鈹� 璋冪敤鏁版嵁鏌ヨ鏈嶅姟
+ 鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncDataServiceImpl (SQL Server) 鈹�
+鈹� 鈥� getBranchDepartments() (鏌ヨ鍒嗗叕鍙�) 鈹�
+鈹� 鈥� getTransportDepartments() (鏌ヨ杞繍閮�) 鈫� 鏂板 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ 鈹� 鍒囨崲鍒� SQL Server
+ 鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncMapper 鈹�
+鈹� 鈥� selectBranchDepartments() 鈹�
+鈹� 鈥� selectTransportDepartments() 鈫� 鏂板 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ 鈹� 鏌ヨ SQL Server
+ 鈻�
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� SQL Server - uv_department 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+## 閮ㄩ棬灞傜骇缁撴瀯
+
+### 鍒嗗叕鍙哥粨鏋�
+```
+鑻ヤ緷绉戞妧 (ID=100)
+鈹溾攢鈹� 婀涙睙鍒嗗叕鍙�
+鈹� 鈹溾攢鈹� 鎶ゅ+
+鈹� 鈹溾攢鈹� 鍖荤敓
+鈹� 鈹斺攢鈹� ...
+鈹溾攢鈹� 骞垮窞鍒嗗叕鍙�
+鈹� 鈹溾攢鈹� 鎶ゅ+
+鈹� 鈹溾攢鈹� 鍖荤敓
+鈹� 鈹斺攢鈹� ...
+鈹斺攢鈹� ...
+```
+
+### 杞繍閮ㄧ粨鏋勶紙鏂板锛�
+```
+鎬诲叕鍙� (ID=101)
+鈹斺攢鈹� 杞繍閮�
+ 鈹溾攢鈹� 杞繍闃�
+ 鈹溾攢鈹� 璋冨害涓績
+ 鈹溾攢鈹� 璁惧缁存姢
+ 鈹斺攢鈹� ...
+```
+
+## 骞傜瓑鎬ц璁�
+
+鍚屾鎿嶄綔鏀寔閲嶅鎵ц锛岄�氳繃浠ヤ笅鏂瑰紡淇濊瘉骞傜瓑鎬э細
+
+1. **閮ㄩ棬鍞竴鏍囪瘑**: 浣跨敤 `departmentId`锛圫QL Server 閮ㄩ棬 ID锛変綔涓哄敮涓�鏍囪瘑
+2. **鏌ヨ浼樺厛**: 鍏堟煡璇㈡槸鍚﹀凡瀛樺湪锛屽啀鍐冲畾鎻掑叆鎴栨洿鏂�
+3. **鏇存柊鍏煎**: 宸插瓨鍦ㄧ殑鏁版嵁浼氳鏇存柊锛屼笉浼氶噸澶嶆彃鍏�
+
+## 浜嬪姟绠$悊
+
+- 鎵�鏈夊悓姝ユ柟娉曢兘鏍囨敞 `@Transactional`
+- 纭繚鍚屾杩囩▼涓嚭鐜板紓甯告椂鑷姩鍥炴粴
+- 淇濊瘉鏁版嵁涓�鑷存��
+
+## 鏁版嵁婧愬垏鎹㈡満鍒�
+
+### 鏅鸿兘鏁版嵁婧愬垏鎹紙宸蹭慨澶嶏級
+
+閫氳繃淇敼 `DataSourceAspect.java`锛屽疄鐜颁簡鏅鸿兘鏁版嵁婧愬垏鎹細
+
+1. **璁板綍鏃ф暟鎹簮**: 鍦ㄥ垏鎹㈠墠璁板綍褰撳墠鏁版嵁婧愮姸鎬�
+2. **鏉′欢鎬у垏鎹�**: 鍙湁鏁版嵁婧愮‘瀹為渶瑕佸彉鍖栨椂鎵嶅垏鎹�
+3. **鏅鸿兘鎭㈠**: 鍙湁鏈璋冪敤鏀瑰彉浜嗘暟鎹簮鏃舵墠鎭㈠
+
+璇﹁锛歚澶氭暟鎹簮鍒囨崲闂淇璇存槑.md`
+
+## 瀹屾暣璋冪敤绀轰緥
+
+鍋囪闇�瑕佸悓姝ヨ浆杩愰儴鏁版嵁锛屽彲浠ヨ繖鏍疯皟鐢細
+
+### 鏂瑰紡 1: 鍒嗘璋冪敤锛堟帹鑽愶級
+
+```java
+// 姝ラ 1: 璋冪敤 DataService 鏌ヨ SQL Server 鏁版嵁
+List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
+
+// 姝ラ 2: 璋冪敤 SyncService 灏嗘暟鎹悓姝ュ埌 MySQL
+AjaxResult result = departmentSyncService.syncTransportDepartments(transportDepts);
+```
+
+### 鏂瑰紡 2: REST API 璋冪敤
+
+```bash
+# 姝ラ 1: 鏌ヨ SQL Server 鏁版嵁锛堥渶瑕佽嚜琛屽疄鐜拌幏鍙栨帴鍙o級
+curl -X GET http://localhost:8080/system/dept/sync/transport/query
+
+# 姝ラ 2: 鍚屾鏁版嵁鍒� MySQL
+curl -X POST http://localhost:8080/system/dept/sync/transport/data \
+ -H "Content-Type: application/json" \
+ -d '[
+ {
+ "departmentId": 1001,
+ "departmentName": "杞繍闃�",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ },
+ {
+ "departmentId": 1002,
+ "departmentName": "璋冨害涓績",
+ "parentId": 100,
+ "parentName": "杞繍閮�"
+ }
+ ]'
+```
+
+## 娉ㄦ剰浜嬮」
+
+1. **鎬诲叕鍙镐緷璧�**: 鍚屾杞繍閮ㄥ墠蹇呴』纭繚鎬诲叕鍙革紙ID=101锛夊凡瀛樺湪
+2. **鏉冮檺鎺у埗**: 鎵�鏈夊悓姝ユ帴鍙i兘闇�瑕� `system:dept:sync` 鏉冮檺
+3. **鏁版嵁婧愰殧绂�**: DataService 鍙闂� SQL Server锛孲yncService 鍙闂� MySQL
+4. **XML 鐗规畩瀛楃**: 鎵�鏈� SQL 璇彞閮戒娇鐢� `<![CDATA[...]]>` 鍖呰9
+5. **鎬ц兘浼樺寲**: SQL Server 鏌ヨ浣跨敤 `NOLOCK` 鎻愮ず鍜� `TOP` 闄愬埗
+
+## 鐩稿叧鏂囨。
+
+- `閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑.md` - 鍒嗗叕鍙稿悓姝ユ灦鏋勮鏄�
+- `鐢ㄦ埛鍚屾鏈嶅姟閲嶆瀯璇存槑.md` - 鐢ㄦ埛鍚屾鏋舵瀯璇存槑
+- `澶氭暟鎹簮鍒囨崲闂淇璇存槑.md` - 鏁版嵁婧愬垏鎹㈤棶棰樹慨澶�
+- `SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md` - SQL Server 鏌ヨ浼樺寲
+
+## 鏇存柊鏃ュ織
+
+**2025-10-18**
+- 鏂板杞繍閮ㄥ悓姝ュ姛鑳�
+- 鍦� `DepartmentSyncMapper.xml` 涓坊鍔� `selectTransportDepartments` 鏌ヨ
+- 鍦� `IDepartmentSyncDataService` 鍜屽疄鐜扮被涓坊鍔� `getTransportDepartments()` 鏂规硶
+- 鍦� `IDepartmentSyncService` 鍜屽疄鐜扮被涓坊鍔� `syncTransportDepartments()` 鏂规硶
+- 鍦� `DepartmentSyncController` 涓坊鍔� `/transport/data` 鎺ュ彛
+- 鍒涘缓鏈鏄庢枃妗�
diff --git "a/\351\203\250\351\227\250\345\220\214\346\255\245-\345\277\253\351\200\237\345\274\200\345\247\213.md" "b/\351\203\250\351\227\250\345\220\214\346\255\245-\345\277\253\351\200\237\345\274\200\345\247\213.md"
new file mode 100644
index 0000000..4188dcd
--- /dev/null
+++ "b/\351\203\250\351\227\250\345\220\214\346\255\245-\345\277\253\351\200\237\345\274\200\345\247\213.md"
@@ -0,0 +1,146 @@
+# 閮ㄩ棬鍚屾鍔熻兘 - 蹇�熷紑濮�
+
+## 涓�銆佸姛鑳借鏄�
+浠嶴QL Server鏁版嵁搴撳悓姝ュ垎鍏徃鍜岄儴闂ㄦ暟鎹埌鑻ヤ緷绯荤粺銆�
+
+**鏁版嵁鏍煎紡杞崲锛�**
+- SQL Server: `婀涙睙--鎶ゅ+`
+- 杞崲鍚�:
+ - 鍒嗗叕鍙�: `婀涙睙鍒嗗叕鍙竊 (parent_id=100)
+ - 閮ㄩ棬: `鎶ゅ+` (parent_id=鍒嗗叕鍙窱D)
+
+## 浜屻�佸畨瑁呮楠�
+
+### 1锔忊儯 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+# 娣诲姞department_id瀛楁
+mysql -u root -p ry-vue < sql/add_department_id_to_sys_dept.sql
+
+# 娣诲姞鑿滃崟鏉冮檺锛堝彲閫夛級
+mysql -u root -p ry-vue < sql/dept_sync_menu.sql
+```
+
+### 2锔忊儯 缂栬瘧椤圭洰
+```bash
+mvn clean package -DskipTests
+```
+
+### 3锔忊儯 鍚姩鏈嶅姟
+```bash
+cd ruoyi-admin
+java -jar target/ruoyi-admin.jar
+```
+
+## 涓夈�佷娇鐢ㄦ柟娉�
+
+### 鏂瑰紡1: Postman璋冪敤
+```
+POST http://localhost:8080/system/dept/sync/branch
+Headers:
+ Authorization: Bearer {浣犵殑token}
+```
+
+### 鏂瑰紡2: curl鍛戒护
+```bash
+curl -X POST http://localhost:8080/system/dept/sync/branch \
+ -H "Authorization: Bearer {浣犵殑token}"
+```
+
+## 鍥涖�佽繑鍥炵ず渚�
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 12, 鏇存柊閮ㄩ棬: 0",
+ "data": {
+ "createdBranch": 3,
+ "updatedBranch": 0,
+ "createdDept": 12,
+ "updatedDept": 0,
+ "totalProcessed": 12
+ }
+}
+```
+
+## 浜斻�侀獙璇佺粨鏋�
+```sql
+-- 鏌ョ湅鍚屾鐨勫垎鍏徃
+SELECT * FROM sys_dept
+WHERE parent_id = 100 AND dept_name LIKE '%鍒嗗叕鍙�'
+ORDER BY dept_name;
+
+-- 鏌ョ湅鍚屾鐨勯儴闂紙鍚玠epartment_id锛�
+SELECT d1.dept_name AS '鍒嗗叕鍙�', d2.dept_name AS '閮ㄩ棬', d2.department_id
+FROM sys_dept d1
+INNER JOIN sys_dept d2 ON d1.dept_id = d2.parent_id
+WHERE d1.parent_id = 100 AND d1.dept_name LIKE '%鍒嗗叕鍙�'
+ORDER BY d1.dept_name, d2.dept_name;
+```
+
+## 鍏�佹牳蹇冩枃浠舵竻鍗�
+
+### Java鏂囦欢
+- `DepartmentSyncDTO.java` - 鍚屾鏁版嵁浼犺緭瀵硅薄
+- `DepartmentSyncMapper.java` - 鏁版嵁璁块棶鎺ュ彛
+- `DepartmentSyncMapper.xml` - SQL鏄犲皠鏂囦欢
+- `IDepartmentSyncService.java` - 鏈嶅姟鎺ュ彛
+- `DepartmentSyncServiceImpl.java` - 鏈嶅姟瀹炵幇锛堟牳蹇冮�昏緫锛�
+- `DepartmentSyncController.java` - 鎺у埗鍣�
+- `SysDept.java` - 淇敼锛堟坊鍔燿epartmentId瀛楁锛�
+- `SysDeptMapper.java` - 淇敼锛堟坊鍔犳煡璇㈡柟娉曪級
+- `SysDeptMapper.xml` - 淇敼锛堟坊鍔燬QL璇彞锛�
+
+### SQL鏂囦欢
+- `sql/add_department_id_to_sys_dept.sql` - 娣诲姞瀛楁
+- `sql/dept_sync_menu.sql` - 娣诲姞鑿滃崟
+
+### 鏂囨。
+- `prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md` - 璇︾粏璇存槑
+- `閮ㄩ棬鍚屾娴嬭瘯鎸囧崡.md` - 娴嬭瘯鎸囧崡
+
+## 涓冦�佹敞鎰忎簨椤�
+
+鉁� **鏀寔閲嶅鎵ц** - 涓嶄細鍒涘缓閲嶅鏁版嵁
+鉁� **浜嬪姟淇濇姢** - 澶辫触鑷姩鍥炴粴
+鉁� **鏃ュ織璁板綍** - 璇︾粏璁板綍鍚屾杩囩▼
+鈿狅笍 **鏉冮檺瑕佹眰** - 闇�瑕� `system:dept:sync` 鏉冮檺
+
+## 鍏�侀棶棰樻帓鏌�
+
+### 鎺ュ彛杩斿洖500
+1. 妫�鏌� SQL Server 杩炴帴閰嶇疆 (`application-dev.yml`)
+2. 纭鏁版嵁搴撳瓧娈靛凡娣诲姞
+3. 鏌ョ湅鏃ュ織: `tail -f ruoyi-admin/logs/sys-error.log`
+
+### 娌℃湁鏁版嵁鍚屾
+1. 纭 SQL Server 涓湁鏁版嵁
+2. 妫�鏌ユ暟鎹簮閰嶇疆
+3. 鏌ョ湅鍚屾鏃ュ織
+
+## 涔濄�佸悗缁墿灞�
+
+### 鍓嶇娣诲姞鍚屾鎸夐挳
+鍦ㄩ儴闂ㄧ鐞嗛〉闈㈡坊鍔狅細
+```javascript
+// 璋冪敤鍚屾鎺ュ彛
+syncDepartments() {
+ this.$confirm('纭鍚屾鍒嗗叕鍙告暟鎹悧锛�', '鎻愮ず', {
+ type: 'warning'
+ }).then(() => {
+ this.$http.post('/system/dept/sync/branch').then(res => {
+ this.$message.success(res.msg);
+ this.getList(); // 鍒锋柊鍒楄〃
+ });
+ });
+}
+```
+
+### 閰嶇疆瀹氭椂浠诲姟
+鍦ㄧ郴缁熺鐞�->瀹氭椂浠诲姟涓坊鍔狅細
+- 浠诲姟鍚嶇О: 鍒嗗叕鍙稿悓姝�
+- 璋冪敤鐩爣: `departmentSyncTask.execute`
+- cron琛ㄨ揪寮�: `0 0 2 * * ?` (姣忓ぉ鍑屾櫒2鐐�)
+
+## 鍗併�佽仈绯绘柟寮�
+濡傛湁闂锛岃鏌ョ湅锛�
+- 璇︾粏鏂囨。: `prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md`
+- 娴嬭瘯鎸囧崡: `閮ㄩ棬鍚屾娴嬭瘯鎸囧崡.md`
diff --git "a/\351\203\250\351\227\250\345\220\214\346\255\245\345\212\237\350\203\275\345\274\200\345\217\221\346\200\273\347\273\223.md" "b/\351\203\250\351\227\250\345\220\214\346\255\245\345\212\237\350\203\275\345\274\200\345\217\221\346\200\273\347\273\223.md"
new file mode 100644
index 0000000..d635544
--- /dev/null
+++ "b/\351\203\250\351\227\250\345\220\214\346\255\245\345\212\237\350\203\275\345\274\200\345\217\221\346\200\273\347\273\223.md"
@@ -0,0 +1,328 @@
+# 閮ㄩ棬鍚屾鍔熻兘寮�鍙戞�荤粨
+
+## 馃搵 椤圭洰淇℃伅
+- **寮�鍙戞棩鏈�**: 2025-10-18
+- **鍔熻兘鍚嶇О**: 缁勭粐鏈烘瀯鍚屾 - 鍒嗗叕鍙稿悓姝�
+- **鎶�鏈爤**: Spring Boot + MyBatis + SQL Server
+
+## 馃幆 闇�姹傛杩�
+浠嶴QL Server鏁版嵁搴撶殑`uv_department`瑙嗗浘涓悓姝�"鍚堜綔鍗曚綅"涓嬬殑鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁鍒拌嫢渚濈郴缁熺殑`sys_dept`琛ㄣ��
+
+### 鏁版嵁婧怱QL
+```sql
+SELECT b.departmentID, b.departmentName
+FROM uv_department a
+INNER JOIN uv_department b ON a.departmentID = b.parentID
+WHERE a.departmentName = '鍚堜綔鍗曚綅'
+```
+
+### 鏁版嵁鏍煎紡
+SQL Server涓殑閮ㄩ棬鍚嶇О鏍煎紡锛歚鍩庡競--閮ㄩ棬绫诲瀷`
+
+绀轰緥锛�
+- `婀涙睙--鎶ゅ+`
+- `婀涙睙--杞﹂槦`
+- `婀涙睙--瀹㈡湇`
+- `婀涙睙--鍔炲叕瀹
+
+### 杞崲瑙勫垯
+1. 鎻愬彇鍩庡競鍚嶇О锛屽垱寤�"XX鍒嗗叕鍙�"
+2. 鎻愬彇閮ㄩ棬绫诲瀷锛屼綔涓哄垎鍏徃鐨勫瓙閮ㄩ棬
+3. 璁板綍SQL Server鐨刣epartmentID鍒癲epartment_id瀛楁
+
+## 馃敤 瀹炵幇鍐呭
+
+### 1. 鏁版嵁搴撲慨鏀�
+
+#### 琛ㄧ粨鏋勫彉鏇�
+```sql
+-- 鍦╯ys_dept琛ㄤ腑娣诲姞department_id瀛楁
+ALTER TABLE sys_dept ADD COLUMN department_id INT NULL COMMENT 'SQL Server涓殑閮ㄩ棬ID';
+CREATE INDEX idx_department_id ON sys_dept(department_id);
+```
+
+**鏂囦欢**: `sql/add_department_id_to_sys_dept.sql`
+
+#### 鑿滃崟鏉冮檺
+```sql
+-- 娣诲姞閮ㄩ棬鍚屾鐨勬寜閽潈闄�
+INSERT INTO sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, remark)
+SELECT '閮ㄩ棬鍚屾', menu_id, 6, '#', 'F', '0', 'system:dept:sync', '#', 'admin', sysdate(), '鍚屾SQL Server鍒嗗叕鍙告暟鎹�'
+FROM sys_menu WHERE menu_name = '閮ㄩ棬绠$悊' AND menu_type = 'C' LIMIT 1;
+```
+
+**鏂囦欢**: `sql/dept_sync_menu.sql`
+
+### 2. 瀹炰綋绫讳慨鏀�
+
+#### SysDept瀹炰綋
+**鏂囦欢**: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java`
+
+**淇敼鍐呭**:
+```java
+/** SQL Server涓殑閮ㄩ棬ID */
+private Integer departmentId;
+
+public Integer getDepartmentId() { return departmentId; }
+public void setDepartmentId(Integer departmentId) { this.departmentId = departmentId; }
+```
+
+### 3. 鏂板鏂囦欢
+
+#### DTO灞�
+**鏂囦欢**: `ruoyi-system/src/main/java/com/ruoyi/system/domain/DepartmentSyncDTO.java`
+- 鍔熻兘: 閮ㄩ棬鍚屾鏁版嵁浼犺緭瀵硅薄
+- 瀛楁: departmentId, departmentName, parentId, parentName
+
+#### Mapper灞�
+**鏂囦欢**:
+- `ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java`
+- `ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml`
+
+**涓昏鏂规硶**:
+- `List<DepartmentSyncDTO> selectBranchDepartments()` - 鏌ヨSQL Server鍒嗗叕鍙告暟鎹�
+
+#### Service灞�
+**鏂囦欢**:
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java`
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java`
+
+**鏍稿績鏂规硶**: `syncBranchDepartments()`
+
+**鍚屾閫昏緫**:
+1. 浠嶴QL Server鑾峰彇鍒嗗叕鍙告暟鎹�
+2. 瑙f瀽閮ㄩ棬鍚嶇О锛堝煄甯�--閮ㄩ棬绫诲瀷锛�
+3. 鍒涘缓鎴栬幏鍙栧垎鍏徃锛坧arent_id=100锛�
+4. 鍒涘缓鎴栨洿鏂板瓙閮ㄩ棬
+5. 璁板綍department_id瀛楁
+6. 杩斿洖鍚屾缁熻缁撴灉
+
+#### Controller灞�
+**鏂囦欢**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`
+
+**鎺ュ彛**:
+- `POST /system/dept/sync/branch` - 鍚屾鍒嗗叕鍙告暟鎹�
+- 鏉冮檺: `system:dept:sync`
+
+### 4. Mapper鎵╁睍
+
+#### SysDeptMapper
+**鏂囦欢**:
+- `ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java`
+- `ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml`
+
+**鏂板鏂规硶**:
+```java
+// 鏍规嵁departmentId鏌ヨ閮ㄩ棬
+SysDept selectDeptByDepartmentId(@Param("departmentId") Integer departmentId);
+
+// 鏍规嵁departmentId鍜岀埗閮ㄩ棬ID鏌ヨ閮ㄩ棬
+SysDept selectDeptByDepartmentIdAndParentId(@Param("departmentId") Integer departmentId, @Param("parentId") Long parentId);
+```
+
+**淇敼鍐呭**:
+- resultMap涓坊鍔燿epartment_id鏄犲皠
+- selectDeptVo涓坊鍔燿epartment_id瀛楁
+- insertDept涓坊鍔燿epartment_id鏀寔
+- updateDept涓坊鍔燿epartment_id鏀寔
+
+### 5. 鏂囨。
+
+#### 鍔熻兘璇存槑鏂囨。
+**鏂囦欢**: `prd/閮ㄩ棬鍚屾鍔熻兘璇存槑.md`
+- 鍔熻兘姒傝堪
+- 鏁版嵁澶勭悊瑙勫垯
+- 鎺ュ彛璇存槑
+- 浣跨敤姝ラ
+- 鍚屾绀轰緥
+- 娉ㄦ剰浜嬮」
+
+#### 娴嬭瘯鎸囧崡
+**鏂囦欢**: `閮ㄩ棬鍚屾娴嬭瘯鎸囧崡.md`
+- 娴嬭瘯鍓嶅噯澶�
+- 娴嬭瘯姝ラ
+- 楠岃瘉娓呭崟
+- 鏃ュ織鏌ョ湅
+- 闂鎺掓煡
+
+#### 蹇�熷紑濮�
+**鏂囦欢**: `閮ㄩ棬鍚屾-蹇�熷紑濮�.md`
+- 瀹夎姝ラ
+- 浣跨敤鏂规硶
+- 楠岃瘉缁撴灉
+- 鏍稿績鏂囦欢娓呭崟
+
+## 馃搳 鎶�鏈壒鎬�
+
+### 1. 骞傜瓑鎬ц璁�
+- 澶氭鎵ц涓嶄細鍒涘缓閲嶅鏁版嵁
+- 閫氳繃department_id鍜岄儴闂ㄥ悕绉板垽鏂槸鍚﹀凡瀛樺湪
+- 宸插瓨鍦ㄥ垯鏇存柊锛屼笉瀛樺湪鍒欏垱寤�
+
+### 2. 浜嬪姟淇濇姢
+- 浣跨敤`@Transactional`娉ㄨВ
+- 鍚屾杩囩▼涓嚭閿欒嚜鍔ㄥ洖婊�
+- 淇濊瘉鏁版嵁涓�鑷存��
+
+### 3. 鏃ュ織璁板綍
+- 璇︾粏璁板綍鍚屾杩囩▼
+- 璁板綍鍒涘缓/鏇存柊鐨勬瘡涓儴闂�
+- 渚夸簬闂鎺掓煡
+
+### 4. 閿欒澶勭悊
+- 鎹曡幏骞惰繑鍥炲弸濂界殑閿欒淇℃伅
+- 璁板綍閿欒鏃ュ織
+- 閮ㄥ垎鏁版嵁鏍煎紡閿欒涓嶅奖鍝嶆暣浣撳悓姝�
+
+### 5. 鎬ц兘浼樺寲
+- 浣跨敤Map缂撳瓨宸插垱寤虹殑鍒嗗叕鍙�
+- 鍑忓皯鏁版嵁搴撴煡璇㈡鏁�
+- 鎵归噺澶勭悊鎻愰珮鏁堢巼
+
+## 馃攳 鍚屾娴佺▼
+
+```
+1. 浠嶴QL Server鏌ヨ鏁版嵁
+ 鈫�
+2. 閬嶅巻姣忔潯鏁版嵁
+ 鈫�
+3. 瑙f瀽閮ㄩ棬鍚嶇О (鍩庡競--閮ㄩ棬)
+ 鈫�
+4. 妫�鏌�/鍒涘缓鍒嗗叕鍙�
+ 鈹溾攢 宸插瓨鍦� 鈫� 鑾峰彇ID
+ 鈹斺攢 涓嶅瓨鍦� 鈫� 鍒涘缓鏂板垎鍏徃
+ 鈫�
+5. 妫�鏌ュ瓙閮ㄩ棬
+ 鈹溾攢 鏍规嵁department_id鏌ヨ
+ 鈹溾攢 宸插瓨鍦� 鈫� 鏇存柊
+ 鈹斺攢 涓嶅瓨鍦� 鈫� 鍒涘缓
+ 鈫�
+6. 杩斿洖缁熻缁撴灉
+```
+
+## 馃搱 鍚屾缁撴灉绀轰緥
+
+### 杈撳叆锛圫QL Server锛�
+```
+departmentID | departmentName
+1001 | 婀涙睙--鎶ゅ+
+1002 | 婀涙睙--杞﹂槦
+1003 | 婀涙睙--瀹㈡湇
+1004 | 婀涙睙--鍔炲叕瀹�
+```
+
+### 杈撳嚭锛坰ys_dept琛級
+```
+dept_id | parent_id | dept_name | ancestors | department_id
+200 | 100 | 婀涙睙鍒嗗叕鍙� | 0,100 | NULL
+201 | 200 | 鎶ゅ+ | 0,100,200 | 1001
+202 | 200 | 杞﹂槦 | 0,100,200 | 1002
+203 | 200 | 瀹㈡湇 | 0,100,200 | 1003
+204 | 200 | 鍔炲叕瀹� | 0,100,200 | 1004
+```
+
+### 鎺ュ彛杩斿洖
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 1, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 4, 鏇存柊閮ㄩ棬: 0",
+ "data": {
+ "createdBranch": 1,
+ "updatedBranch": 0,
+ "createdDept": 4,
+ "updatedDept": 0,
+ "totalProcessed": 4
+ }
+}
+```
+
+## 馃帗 浣跨敤绀轰緥
+
+### 1. Postman璋冪敤
+```
+POST http://localhost:8080/system/dept/sync/branch
+Headers:
+ Authorization: Bearer eyJhbGciOiJIUzUxMiJ9...
+```
+
+### 2. curl鍛戒护
+```bash
+curl -X POST http://localhost:8080/system/dept/sync/branch \
+ -H "Authorization: Bearer {token}"
+```
+
+### 3. 鍓嶇璋冪敤
+```javascript
+this.$http.post('/system/dept/sync/branch').then(res => {
+ this.$message.success(res.msg);
+ this.getList();
+});
+```
+
+## 鈿欙笍 閰嶇疆璇存槑
+
+### SQL Server鏁版嵁婧�
+**鏂囦欢**: `ruoyi-admin/src/main/resources/application-dev.yml`
+
+```yaml
+spring:
+ datasource:
+ druid:
+ sqlserver:
+ enabled: true
+ url: jdbc:sqlserver://your-server:1433;DatabaseName=your-db
+ username: your-username
+ password: your-password
+ driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+```
+
+## 馃殌 閮ㄧ讲娓呭崟
+
+### 1. 鏁版嵁搴撴搷浣�
+- [ ] 鎵ц `add_department_id_to_sys_dept.sql`
+- [ ] 鎵ц `dept_sync_menu.sql`锛堝彲閫夛級
+
+### 2. 浠g爜閮ㄧ讲
+- [ ] 缂栬瘧椤圭洰: `mvn clean package -DskipTests`
+- [ ] 閮ㄧ讲jar鍖�
+- [ ] 閲嶅惎鏈嶅姟
+
+### 3. 楠岃瘉娴嬭瘯
+- [ ] 璋冪敤鍚屾鎺ュ彛
+- [ ] 妫�鏌ユ暟鎹簱鏁版嵁
+- [ ] 楠岃瘉鏃ュ織杈撳嚭
+
+## 馃摑 寰呬紭鍖栭」
+
+### 1. 鍔熻兘澧炲己
+- [ ] 鍓嶇娣诲姞鍚屾鎸夐挳
+- [ ] 閰嶇疆瀹氭椂浠诲姟鑷姩鍚屾
+- [ ] 娣诲姞鍚屾鍘嗗彶璁板綍
+- [ ] 娣诲姞鍚屾澶辫触閫氱煡
+
+### 2. 鎬ц兘浼樺寲
+- [ ] 鎵归噺鎻掑叆浼樺寲
+- [ ] 澶ф暟鎹噺鍒嗛〉澶勭悊
+- [ ] 寮傛鍚屾鏀寔
+
+### 3. 鐩戞帶鍛婅
+- [ ] 鍚屾澶辫触鍛婅
+- [ ] 鍚屾鏁版嵁閲忕洃鎺�
+- [ ] 鍚屾鑰楁椂鐩戞帶
+
+## 馃摎 鍙傝�冭祫鏂�
+- 鑻ヤ緷妗嗘灦鏂囨。: http://doc.ruoyi.vip
+- MyBatis鏂囨。: https://mybatis.org/mybatis-3/zh/
+- Spring Boot鏂囨。: https://spring.io/projects/spring-boot
+
+## 鉁� 鎬荤粨
+
+鏈寮�鍙戝畬鎴愪簡浠嶴QL Server鍒癕ySQL鐨勫垎鍏徃鏁版嵁鍚屾鍔熻兘锛屼富瑕佺壒鐐癸細
+
+1. **鏁版嵁杞崲鍑嗙‘**: 姝g‘瑙f瀽"鍩庡競--閮ㄩ棬"鏍煎紡锛屽垱寤轰袱绾ч儴闂ㄧ粨鏋�
+2. **骞傜瓑鎬т繚璇�**: 鏀寔閲嶅鎵ц锛屼笉浼氬垱寤洪噸澶嶆暟鎹�
+3. **浜嬪姟瀹夊叏**: 浣跨敤浜嬪姟淇濊瘉鏁版嵁涓�鑷存��
+4. **鏃ュ織瀹屽杽**: 璇︾粏璁板綍鍚屾杩囩▼锛屼究浜庢帓鏌ラ棶棰�
+5. **鏂囨。榻愬叏**: 鎻愪緵鍔熻兘璇存槑銆佹祴璇曟寚鍗椼�佸揩閫熷紑濮嬬瓑鏂囨。
+
+鍔熻兘宸插畬鎴愬紑鍙戝拰鑷祴锛屽彲浠ヨ繘鍏ユ祴璇曞拰閮ㄧ讲闃舵銆�
diff --git "a/\351\203\250\351\227\250\345\220\214\346\255\245\346\234\215\345\212\241\351\207\215\346\236\204\350\257\264\346\230\216.md" "b/\351\203\250\351\227\250\345\220\214\346\255\245\346\234\215\345\212\241\351\207\215\346\236\204\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..cbba6d0
--- /dev/null
+++ "b/\351\203\250\351\227\250\345\220\214\346\255\245\346\234\215\345\212\241\351\207\215\346\236\204\350\257\264\346\230\216.md"
@@ -0,0 +1,497 @@
+# 閮ㄩ棬鍚屾鏈嶅姟閲嶆瀯璇存槑
+
+## 閲嶆瀯姒傝堪
+
+灏嗛儴闂ㄥ悓姝ュ姛鑳介噸鏋勪负**鏁版嵁鏌ヨ**鍜�**鏁版嵁鍚屾**涓や釜鐙珛鐨勬湇鍔★紝瀹炵幇鑱岃矗鍒嗙鍜岀伒娲绘�ф彁鍗囥��
+
+---
+
+## 鏋舵瀯鍙樺寲
+
+### 閲嶆瀯鍓�
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncServiceImpl 鈹�
+鈹� 鈹�
+鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹� 鈹� syncBranchDepartments() 鈹� 鈹�
+鈹� 鈹� 鈹溾攢 鏌ヨ SQL Server 鈹� 鈹�
+鈹� 鈹� 鈹斺攢 鍐欏叆 MySQL 鈹� 鈹�
+鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+**闂**锛�
+- 鉂� 鏁版嵁鏌ヨ鍜屽悓姝ラ�昏緫鑰﹀悎
+- 鉂� 鏃犳硶浣跨敤澶栭儴鏁版嵁婧�
+- 鉂� 闅句互鎵╁睍鍏朵粬鏁版嵁鏉ユ簮
+
+### 閲嶆瀯鍚�
+
+```
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncDataServiceImpl (鏂板) 鈹�
+鈹� 鑱岃矗锛氫粠 SQL Server 鏌ヨ鏁版嵁 鈹�
+鈹� 鈹�
+鈹� 鈹溾攢 getBranchDepartments() 鈹�
+鈹� 鈹斺攢 杩斿洖 List<DepartmentSyncDTO> 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹�
+ v
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� DepartmentSyncServiceImpl (閲嶆瀯) 鈹�
+鈹� 鑱岃矗锛氭帴鏀舵暟鎹苟鍐欏叆 MySQL 鈹�
+鈹� 鈹�
+鈹� 鈹溾攢 syncBranchDepartments() 鈹�
+鈹� 鈹� 鈹斺攢 璋冪敤 DepartmentSyncDataService 鑾峰彇鏁版嵁 鈹�
+鈹� 鈹� 鈹�
+鈹� 鈹斺攢 syncBranchDepartments(List<DepartmentSyncDTO>) 鈹�
+鈹� 鈹斺攢 鎺ユ敹澶栭儴浼犲叆鐨勬暟鎹繘琛屽悓姝� 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+**浼樺娍**锛�
+- 鉁� 鑱岃矗鍗曚竴锛屾槗浜庣淮鎶�
+- 鉁� 鏀寔澶栭儴鏁版嵁婧�
+- 鉁� 鐏垫椿鎬ч珮锛屾槗浜庢墿灞�
+
+---
+
+## 鏍稿績缁勪欢
+
+### 1. IDepartmentSyncDataService锛堟柊澧烇級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java`
+
+**鑱岃矗**: 瀹氫箟浠� SQL Server 鏌ヨ鏁版嵁鐨勬帴鍙�
+
+```java
+public interface IDepartmentSyncDataService {
+ /**
+ * 浠� SQL Server 鏌ヨ鍚堜綔鍗曚綅涓嬬殑鎵�鏈夊垎鍏徃鏁版嵁
+ *
+ * @return 鍒嗗叕鍙稿垪琛�
+ */
+ List<DepartmentSyncDTO> getBranchDepartments();
+}
+```
+
+---
+
+### 2. DepartmentSyncDataServiceImpl锛堟柊澧烇級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java`
+
+**鑱岃矗**: 涓撻棬璐熻矗浠� SQL Server 鏌ヨ閮ㄩ棬鏁版嵁
+
+**鍏抽敭鐗规��**:
+```java
+@Service
+public class DepartmentSyncDataServiceImpl implements IDepartmentSyncDataService {
+ @Autowired
+ private DepartmentSyncMapper departmentSyncMapper; // 甯� @DataSource 娉ㄨВ
+
+ @Override
+ public List<DepartmentSyncDTO> getBranchDepartments() {
+ log.info("寮�濮嬩粠 SQL Server 鏌ヨ鍒嗗叕鍙告暟鎹�...");
+
+ // 鑷姩鍒囨崲鍒� SQL Server 鏁版嵁婧�
+ List<DepartmentSyncDTO> branchDepts = departmentSyncMapper.selectBranchDepartments();
+
+ log.info("浠� SQL Server 鏌ヨ鍒� {} 鏉″垎鍏徃鏁版嵁", branchDepts.size());
+ return branchDepts;
+ }
+}
+```
+
+**鏁版嵁娴�**:
+```
+DepartmentSyncDataServiceImpl
+ 鈫�
+DepartmentSyncMapper (@DataSource(SQLSERVER))
+ 鈫�
+SQL Server 鏁版嵁搴� (uv_department)
+ 鈫�
+杩斿洖 List<DepartmentSyncDTO>
+```
+
+---
+
+### 3. IDepartmentSyncService锛堥噸鏋勶級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java`
+
+**鍙樺寲**: 鏂板閲嶈浇鏂规硶锛屾敮鎸佸閮ㄦ暟鎹簮
+
+```java
+public interface IDepartmentSyncService {
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜粠 SQL Server 鏌ヨ骞跺悓姝ュ埌 MySQL锛�
+ */
+ AjaxResult syncBranchDepartments();
+
+ /**
+ * 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ *
+ * @param branchDepts 澶栭儴浼犲叆鐨勫垎鍏徃鏁版嵁鍒楄〃
+ */
+ AjaxResult syncBranchDepartments(List<DepartmentSyncDTO> branchDepts);
+}
+```
+
+---
+
+### 4. DepartmentSyncServiceImpl锛堥噸鏋勶級
+
+**鏂囦欢璺緞**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java`
+
+**鍙樺寲**:
+1. 绉婚櫎瀵� `DepartmentSyncMapper` 鐨勭洿鎺ヤ緷璧�
+2. 娉ㄥ叆 `IDepartmentSyncDataService` 鑾峰彇鏁版嵁
+3. 鏂板 `syncBranchDepartments(List<DepartmentSyncDTO>)` 鏂规硶
+
+**閲嶆瀯鍚庣殑浠g爜**:
+
+```java
+@Service
+public class DepartmentSyncServiceImpl implements IDepartmentSyncService {
+
+ @Autowired
+ private IDepartmentSyncDataService departmentSyncDataService; // 鏁版嵁鏌ヨ鏈嶅姟
+
+ @Autowired
+ private SysDeptMapper sysDeptMapper; // MySQL 鎿嶄綔
+
+ // 鏂规硶 1: 鍐呴儴鏌ヨ + 鍚屾
+ @Override
+ @Transactional
+ public AjaxResult syncBranchDepartments() {
+ // 璋冪敤鏁版嵁鏌ヨ鏈嶅姟鑾峰彇 SQL Server 鏁版嵁
+ List<DepartmentSyncDTO> branchDepts = departmentSyncDataService.getBranchDepartments();
+
+ if (branchDepts == null || branchDepts.isEmpty()) {
+ return AjaxResult.warn("鏈幏鍙栧埌闇�瑕佸悓姝ョ殑鍒嗗叕鍙告暟鎹�");
+ }
+
+ // 璋冪敤閲嶈浇鏂规硶鎵ц鍚屾
+ return syncBranchDepartments(branchDepts);
+ }
+
+ // 鏂规硶 2: 澶栭儴鏁版嵁婧� + 鍚屾锛堟柊澧烇級
+ @Override
+ @Transactional
+ public AjaxResult syncBranchDepartments(List<DepartmentSyncDTO> branchDepts) {
+ if (branchDepts == null || branchDepts.isEmpty()) {
+ return AjaxResult.warn("浼犲叆鐨勯儴闂ㄦ暟鎹负绌�");
+ }
+
+ log.info("寮�濮嬪悓姝� {} 鏉″垎鍏徃鏁版嵁鍒� MySQL 鏁版嵁搴�...", branchDepts.size());
+
+ // 鍚屾閫昏緫锛堝彧娑夊強 MySQL 鎿嶄綔锛�
+ // ...
+ }
+}
+```
+
+**鏁版嵁娴�**:
+
+#### 娴佺▼ 1: 鍐呴儴鏌ヨ + 鍚屾
+```
+syncBranchDepartments()
+ 鈫�
+璋冪敤 departmentSyncDataService.getBranchDepartments()
+ 鈫�
+鑾峰彇 List<DepartmentSyncDTO>
+ 鈫�
+璋冪敤 syncBranchDepartments(List)
+ 鈫�
+鍐欏叆 MySQL 鏁版嵁搴�
+```
+
+#### 娴佺▼ 2: 澶栭儴鏁版嵁婧� + 鍚屾
+```
+澶栭儴璋冪敤鑰呮彁渚� List<DepartmentSyncDTO>
+ 鈫�
+syncBranchDepartments(List)
+ 鈫�
+鍐欏叆 MySQL 鏁版嵁搴�
+```
+
+---
+
+### 5. DepartmentSyncController锛堟洿鏂帮級
+
+**鏂囦欢璺緞**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java`
+
+**鍙樺寲**: 鏂板鎺ュ彛鏀寔澶栭儴鏁版嵁婧�
+
+```java
+@RestController
+@RequestMapping("/system/dept/sync")
+public class DepartmentSyncController {
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ /**
+ * 鎺ュ彛 1: 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜粠 SQL Server 鏌ヨ骞跺悓姝ワ級
+ */
+ @PostMapping("/branch")
+ public AjaxResult syncBranchDepartments() {
+ return departmentSyncService.syncBranchDepartments();
+ }
+
+ /**
+ * 鎺ュ彛 2: 鍚屾鍒嗗叕鍙稿拰閮ㄩ棬鏁版嵁锛堜娇鐢ㄥ閮ㄤ紶鍏ョ殑鏁版嵁婧愶級
+ */
+ @PostMapping("/branch/data")
+ public AjaxResult syncBranchDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> branchDepts) {
+ return departmentSyncService.syncBranchDepartments(branchDepts);
+ }
+}
+```
+
+---
+
+## 浣跨敤鍦烘櫙
+
+### 鍦烘櫙 1: 甯歌鍚屾锛堜粠 SQL Server 鏌ヨ锛�
+
+```bash
+POST http://localhost:8080/system/dept/sync/branch
+```
+
+**鎵ц娴佺▼**:
+1. Controller 璋冪敤 `departmentSyncService.syncBranchDepartments()`
+2. Service 璋冪敤 `departmentSyncDataService.getBranchDepartments()`
+3. 鑷姩鍒囨崲鍒� SQL Server 鏌ヨ鏁版嵁
+4. 灏嗘暟鎹啓鍏� MySQL
+
+---
+
+### 鍦烘櫙 2: 浣跨敤澶栭儴鏁版嵁婧�
+
+```bash
+POST http://localhost:8080/system/dept/sync/branch/data
+Content-Type: application/json
+
+[
+ {
+ "departmentId": 1001,
+ "departmentName": "婀涙睙--鎶ゅ+",
+ "parentId": 100,
+ "parentName": "鍚堜綔鍗曚綅"
+ },
+ {
+ "departmentId": 1002,
+ "departmentName": "婀涙睙--杞﹂槦",
+ "parentId": 100,
+ "parentName": "鍚堜綔鍗曚綅"
+ }
+]
+```
+
+**鎵ц娴佺▼**:
+1. Controller 鎺ユ敹 JSON 鏁版嵁骞惰浆鎹负 `List<DepartmentSyncDTO>`
+2. Controller 璋冪敤 `departmentSyncService.syncBranchDepartments(branchDepts)`
+3. Service 鐩存帴灏嗘暟鎹啓鍏� MySQL
+
+---
+
+### 鍦烘櫙 3: 浠庡叾浠栫郴缁熻幏鍙栨暟鎹悗鍚屾
+
+```java
+@Service
+public class CustomSyncService {
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ public void syncFromExternalSystem() {
+ // 1. 浠庡叾浠栫郴缁熻幏鍙栨暟鎹紙濡� HTTP API銆佹秷鎭槦鍒楃瓑锛�
+ List<DepartmentSyncDTO> externalData = fetchDataFromExternalSystem();
+
+ // 2. 杩涜鏁版嵁棰勫鐞�
+ List<DepartmentSyncDTO> processedData = preprocessData(externalData);
+
+ // 3. 璋冪敤鍚屾鏈嶅姟
+ AjaxResult result = departmentSyncService.syncBranchDepartments(processedData);
+
+ log.info("鍚屾缁撴灉: {}", result.get("msg"));
+ }
+}
+```
+
+---
+
+### 鍦烘櫙 4: 鎵归噺鍚屾澶氫釜鏁版嵁婧�
+
+```java
+@Service
+public class BatchSyncService {
+
+ @Autowired
+ private IDepartmentSyncDataService departmentSyncDataService;
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ public void batchSync() {
+ // 1. 浠� SQL Server 鑾峰彇鏁版嵁
+ List<DepartmentSyncDTO> sqlServerData = departmentSyncDataService.getBranchDepartments();
+
+ // 2. 浠庡叾浠栨潵婧愯幏鍙栨暟鎹�
+ List<DepartmentSyncDTO> otherData = getDataFromOtherSource();
+
+ // 3. 鍚堝苟鏁版嵁
+ List<DepartmentSyncDTO> allData = new ArrayList<>();
+ allData.addAll(sqlServerData);
+ allData.addAll(otherData);
+
+ // 4. 缁熶竴鍚屾
+ departmentSyncService.syncBranchDepartments(allData);
+ }
+}
+```
+
+---
+
+## 鎺ュ彛瀵规瘮
+
+| 鎺ュ彛 | 璺緞 | 鏁版嵁鏉ユ簮 | 閫傜敤鍦烘櫙 |
+|------|------|----------|----------|
+| **鎺ュ彛 1** | `POST /system/dept/sync/branch` | 鍐呴儴鏌ヨ SQL Server | 甯歌瀹氭椂鍚屾 |
+| **鎺ュ彛 2** | `POST /system/dept/sync/branch/data` | 澶栭儴浼犲叆 JSON | 鎵嬪姩鏁版嵁瀵煎叆銆佹暟鎹澶勭悊銆佸婧愭暣鍚� |
+
+---
+
+## 瀹氭椂浠诲姟鏇存柊
+
+瀹氭椂浠诲姟鍙互缁х画浣跨敤鍘熸湁鏂瑰紡锛屾棤闇�淇敼锛�
+
+```java
+@Component("oaSyncTask")
+public class OaSyncTask {
+
+ @Autowired
+ private IDepartmentSyncService departmentSyncService;
+
+ public void syncOaData() {
+ // 鑷姩浠� SQL Server 鏌ヨ骞跺悓姝�
+ AjaxResult result = departmentSyncService.syncBranchDepartments();
+ log.info("瀹氭椂鍚屾缁撴灉: {}", result.get("msg"));
+ }
+}
+```
+
+---
+
+## 浼樺娍鎬荤粨
+
+### 1. 鑱岃矗鍒嗙 鉁�
+- **DepartmentSyncDataService**: 鍙礋璐f煡璇㈡暟鎹�
+- **DepartmentSyncService**: 鍙礋璐e悓姝ユ暟鎹�
+
+### 2. 鐏垫椿鎬ф彁鍗� 鉁�
+- 鏀寔浠� SQL Server 鏌ヨ
+- 鏀寔澶栭儴鏁版嵁婧�
+- 鏀寔鏁版嵁棰勫鐞�
+- 鏀寔澶氭簮鏁版嵁鏁村悎
+
+### 3. 鏄撲簬鎵╁睍 鉁�
+```java
+// 鎵╁睍锛氭敮鎸佸叾浠栨暟鎹簮
+public interface IDepartmentSyncDataService {
+ List<DepartmentSyncDTO> getBranchDepartments(); // SQL Server
+ List<DepartmentSyncDTO> getBranchDepartmentsFromOracle(); // Oracle
+ List<DepartmentSyncDTO> getBranchDepartmentsFromAPI(); // HTTP API
+}
+```
+
+### 4. 鏄撲簬娴嬭瘯 鉁�
+```java
+@Test
+public void testSyncWithMockData() {
+ // 鍒涘缓娴嬭瘯鏁版嵁
+ List<DepartmentSyncDTO> testData = createTestData();
+
+ // 娴嬭瘯鍚屾閫昏緫
+ AjaxResult result = departmentSyncService.syncBranchDepartments(testData);
+
+ // 楠岃瘉缁撴灉
+ assertEquals(200, result.get("code"));
+}
+```
+
+---
+
+## 杩佺Щ鎸囧崡
+
+### 瀵逛簬鐜版湁浠g爜
+
+**鏃犻渶淇敼**锛佸師鏈夎皟鐢ㄦ柟寮忓畬鍏ㄥ吋瀹癸細
+
+```java
+// 鍘熸湁浠g爜
+departmentSyncService.syncBranchDepartments();
+
+// 浠嶇劧鏈夋晥锛岃涓轰笉鍙�
+```
+
+### 瀵逛簬鏂板姛鑳�
+
+浣跨敤鏂板鐨勯噸杞芥柟娉曪細
+
+```java
+// 鏂板姛鑳斤細浣跨敤澶栭儴鏁版嵁婧�
+List<DepartmentSyncDTO> externalData = getExternalData();
+departmentSyncService.syncBranchDepartments(externalData);
+```
+
+---
+
+## 鏂囦欢娓呭崟
+
+### 鏂板鏂囦欢
+
+| 鏂囦欢 | 璇存槑 |
+|------|------|
+| `IDepartmentSyncDataService.java` | 鏁版嵁鏌ヨ鏈嶅姟鎺ュ彛 |
+| `DepartmentSyncDataServiceImpl.java` | 鏁版嵁鏌ヨ鏈嶅姟瀹炵幇 |
+
+### 淇敼鏂囦欢
+
+| 鏂囦欢 | 鍙樺寲 |
+|------|------|
+| `IDepartmentSyncService.java` | 鏂板閲嶈浇鏂规硶 |
+| `DepartmentSyncServiceImpl.java` | 閲嶆瀯瀹炵幇锛屾敮鎸佸閮ㄦ暟鎹簮 |
+| `DepartmentSyncController.java` | 鏂板鎺ュ彛 `/branch/data` |
+
+### 鏃犻渶淇敼
+
+| 鏂囦欢 | 璇存槑 |
+|------|------|
+| `DepartmentSyncMapper.java` | Mapper 鎺ュ彛涓嶅彉 |
+| `DepartmentSyncMapper.xml` | SQL 鏄犲皠涓嶅彉 |
+| `OaSyncTask.java` | 瀹氭椂浠诲姟涓嶅彉 |
+
+---
+
+## 鎬荤粨
+
+閫氳繃鏈閲嶆瀯锛屽疄鐜颁簡锛�
+
+鉁� **鑱岃矗鍒嗙**: 鏁版嵁鏌ヨ鍜屽悓姝ラ�昏緫瑙h��
+鉁� **鐏垫椿鎬ф彁鍗�**: 鏀寔澶氱鏁版嵁鏉ユ簮
+鉁� **鏄撲簬鎵╁睍**: 鍙交鏉炬坊鍔犳柊鐨勬暟鎹簮
+鉁� **鍚戝悗鍏煎**: 鍘熸湁浠g爜鏃犻渶淇敼
+鉁� **鏄撲簬娴嬭瘯**: 鍙娇鐢� Mock 鏁版嵁杩涜鍗曞厓娴嬭瘯
+
+---
+
+## 鐩稿叧鏂囨。
+
+- [OA鏁版嵁鍚屾澶氭暟鎹簮鏋舵瀯璇存槑.md](OA鏁版嵁鍚屾澶氭暟鎹簮鏋舵瀯璇存槑.md)
+- [澶氭暟鎹簮鍒囨崲闂淇璇存槑.md](澶氭暟鎹簮鍒囨崲闂淇璇存槑.md)
+- [SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md](SQL Server鏁版嵁婧愭煡璇紭鍖栬鏄�.md)
diff --git "a/\351\203\250\351\227\250\345\220\214\346\255\245\346\265\213\350\257\225\346\214\207\345\215\227.md" "b/\351\203\250\351\227\250\345\220\214\346\255\245\346\265\213\350\257\225\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..db42e9c
--- /dev/null
+++ "b/\351\203\250\351\227\250\345\220\214\346\255\245\346\265\213\350\257\225\346\214\207\345\215\227.md"
@@ -0,0 +1,274 @@
+# 閮ㄩ棬鍚屾鍔熻兘娴嬭瘯鎸囧崡
+
+## 娴嬭瘯鍓嶅噯澶�
+
+### 1. 鎵ц鏁版嵁搴撹剼鏈�
+```bash
+# 杩涘叆椤圭洰sql鐩綍
+cd d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master\sql
+
+# 鎵ц娣诲姞department_id瀛楁鐨勮剼鏈�
+mysql -h localhost -u root -p ry-vue < add_department_id_to_sys_dept.sql
+
+# 鎵ц娣诲姞鑿滃崟鏉冮檺鐨勮剼鏈紙鍙�夛級
+mysql -h localhost -u root -p ry-vue < dept_sync_menu.sql
+```
+
+### 2. 纭SQL Server鏁版嵁婧愰厤缃�
+妫�鏌ユ枃浠讹細`ruoyi-admin/src/main/resources/application-dev.yml`
+
+纭繚sqlserver鏁版嵁婧愰厤缃纭細
+```yaml
+spring:
+ datasource:
+ druid:
+ # 涓绘暟鎹簮锛圡ySQL锛�
+ master:
+ url: jdbc:mysql://localhost:3306/ry-vue?...
+ username: root
+ password: password
+
+ # 浠庢暟鎹簮锛圫QL Server锛�
+ sqlserver:
+ enabled: true
+ url: jdbc:sqlserver://your-server:1433;DatabaseName=your-db
+ username: your-username
+ password: your-password
+ driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+```
+
+### 3. 缂栬瘧椤圭洰
+```bash
+cd d:\project\鎬ユ晳杞繍\code\Api\RuoYi-Vue-master
+mvn clean package -DskipTests
+```
+
+### 4. 鍚姩鍚庣鏈嶅姟
+```bash
+cd ruoyi-admin
+java -jar target/ruoyi-admin.jar
+```
+
+## 娴嬭瘯姝ラ
+
+### 娴嬭瘯1: 浣跨敤Postman娴嬭瘯
+
+#### 姝ラ1锛氳幏鍙朤oken
+```
+POST http://localhost:8080/login
+Content-Type: application/json
+
+{
+ "username": "admin",
+ "password": "admin123"
+}
+```
+
+杩斿洖绀轰緥锛�
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "token": "eyJhbGciOiJIUzUxMiJ9..."
+}
+```
+
+#### 姝ラ2锛氳皟鐢ㄥ悓姝ユ帴鍙�
+```
+POST http://localhost:8080/system/dept/sync/branch
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9...
+```
+
+棰勬湡杩斿洖锛�
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 12, 鏇存柊閮ㄩ棬: 0",
+ "data": {
+ "createdBranch": 3,
+ "updatedBranch": 0,
+ "createdDept": 12,
+ "updatedDept": 0,
+ "totalProcessed": 12
+ }
+}
+```
+
+#### 姝ラ3锛氶獙璇佹暟鎹�
+鏌ヨ鏁版嵁搴擄細
+```sql
+-- 鏌ョ湅鏂板垱寤虹殑鍒嗗叕鍙�
+SELECT * FROM sys_dept
+WHERE parent_id = 100
+ AND dept_name LIKE '%鍒嗗叕鍙�'
+ AND del_flag = '0'
+ORDER BY create_time DESC;
+
+-- 鏌ョ湅鏂板垱寤虹殑瀛愰儴闂�
+SELECT d1.dept_name AS '鍒嗗叕鍙�', d2.dept_name AS '閮ㄩ棬', d2.department_id AS 'SQL Server ID'
+FROM sys_dept d1
+INNER JOIN sys_dept d2 ON d1.dept_id = d2.parent_id
+WHERE d1.parent_id = 100
+ AND d1.dept_name LIKE '%鍒嗗叕鍙�'
+ AND d2.del_flag = '0'
+ORDER BY d1.dept_name, d2.dept_name;
+```
+
+### 娴嬭瘯2: 娴嬭瘯骞傜瓑鎬э紙閲嶅鍚屾锛�
+
+#### 姝ラ1锛氳褰曠涓�娆″悓姝ョ粨鏋�
+```
+绗竴娆″悓姝ワ細
+- 鍒涘缓鍒嗗叕鍙�: 3
+- 鍒涘缓閮ㄩ棬: 12
+```
+
+#### 姝ラ2锛氱珛鍗冲啀娆℃墽琛屽悓姝�
+```
+POST http://localhost:8080/system/dept/sync/branch
+Authorization: Bearer {token}
+```
+
+#### 姝ラ3锛氶獙璇佺粨鏋�
+棰勬湡杩斿洖锛�
+```json
+{
+ "code": 200,
+ "msg": "鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 0, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 0, 鏇存柊閮ㄩ棬: 12",
+ "data": {
+ "createdBranch": 0,
+ "updatedBranch": 0,
+ "createdDept": 0,
+ "updatedDept": 12,
+ "totalProcessed": 12
+ }
+}
+```
+
+楠岃瘉锛�
+- 鏁版嵁搴撲腑閮ㄩ棬鏁伴噺涓嶅彉
+- `update_time`瀛楁宸叉洿鏂�
+- 娌℃湁閲嶅鏁版嵁
+
+### 娴嬭瘯3: 娴嬭瘯閿欒澶勭悊
+
+#### 鍦烘櫙1锛歋QL Server杩炴帴澶辫触
+1. 涓存椂鍋滄SQL Server鏈嶅姟
+2. 璋冪敤鍚屾鎺ュ彛
+3. 棰勬湡杩斿洖閿欒淇℃伅
+
+#### 鍦烘櫙2锛氭潈闄愪笉瓒�
+1. 浣跨敤鏅�氱敤鎴风櫥褰曪紙娌℃湁system:dept:sync鏉冮檺锛�
+2. 璋冪敤鍚屾鎺ュ彛
+3. 棰勬湡杩斿洖403鏉冮檺涓嶈冻
+
+## 楠岃瘉娓呭崟
+
+### 鍔熻兘楠岃瘉
+- [ ] 鑳藉鎴愬姛杩炴帴SQL Server鏁版嵁搴�
+- [ ] 鑳藉姝g‘瑙f瀽閮ㄩ棬鍚嶇О锛堝煄甯�--閮ㄩ棬绫诲瀷锛�
+- [ ] 鑳藉鍒涘缓鍒嗗叕鍙革紙parent_id=100锛�
+- [ ] 鑳藉鍒涘缓瀛愰儴闂紙parent_id=鍒嗗叕鍙窱D锛�
+- [ ] department_id瀛楁姝g‘璁板綍SQL Server鐨刣epartmentID
+- [ ] ancestors瀛楁鏍煎紡姝g‘
+- [ ] 閲嶅鍚屾涓嶄細鍒涘缓閲嶅鏁版嵁
+- [ ] 鍚屾鏃ュ織璁板綍瀹屾暣
+
+### 鏁版嵁楠岃瘉
+- [ ] 鍒嗗叕鍙稿悕绉版牸寮忥細{鍩庡競}鍒嗗叕鍙�
+- [ ] 瀛愰儴闂ㄥ悕绉版纭�
+- [ ] 閮ㄩ棬灞傜骇鍏崇郴姝g‘
+- [ ] 鎵�鏈夐儴闂╯tatus='0'锛堟甯哥姸鎬侊級
+- [ ] create_by鍜寀pdate_by涓�'sync'
+
+### 寮傚父楠岃瘉
+- [ ] SQL Server杩炴帴澶辫触鏃舵湁鍙嬪ソ鎻愮ず
+- [ ] 鏃犳潈闄愭椂杩斿洖403
+- [ ] 閮ㄩ棬鍚嶇О鏍煎紡閿欒鏃惰烦杩囧鐞�
+- [ ] 浜嬪姟鍥炴粴姝e父宸ヤ綔
+
+## 鏃ュ織鏌ョ湅
+
+鏌ョ湅鍚屾鏃ュ織锛�
+```bash
+tail -f ruoyi-admin/logs/sys-info.log | grep -i "department"
+```
+
+鍏抽敭鏃ュ織绀轰緥锛�
+```
+2025-10-18 14:30:00 INFO DepartmentSyncServiceImpl - 浠嶴QL Server鑾峰彇鍒� 12 鏉″垎鍏徃鏁版嵁
+2025-10-18 14:30:01 INFO DepartmentSyncServiceImpl - 鍒涘缓鏂板垎鍏徃: 婀涙睙鍒嗗叕鍙�, ID: 200
+2025-10-18 14:30:01 INFO DepartmentSyncServiceImpl - 鍒涘缓鏂伴儴闂�: 婀涙睙鍒嗗叕鍙� -> 鎶ゅ+, departmentId: 1001
+2025-10-18 14:30:01 INFO DepartmentSyncServiceImpl - 鍒涘缓鏂伴儴闂�: 婀涙睙鍒嗗叕鍙� -> 杞﹂槦, departmentId: 1002
+...
+2025-10-18 14:30:02 INFO DepartmentSyncServiceImpl - 鍚屾瀹屾垚锛佸垱寤哄垎鍏徃: 3, 鏇存柊鍒嗗叕鍙�: 0, 鍒涘缓閮ㄩ棬: 12, 鏇存柊閮ㄩ棬: 0
+```
+
+## 甯歌闂鎺掓煡
+
+### 闂1: 鎺ュ彛杩斿洖500閿欒
+**鎺掓煡姝ラ锛�**
+1. 鏌ョ湅鍚庡彴鏃ュ織锛歚tail -f ruoyi-admin/logs/sys-error.log`
+2. 妫�鏌QL Server杩炴帴閰嶇疆
+3. 妫�鏌ユ暟鎹簱瀛楁鏄惁宸叉坊鍔�
+4. 妫�鏌apper XML鏂囦欢鏄惁姝g‘
+
+### 闂2: 娌℃湁鏁版嵁鍚屾
+**鎺掓煡姝ラ锛�**
+1. 纭SQL Server涓湁鏁版嵁锛�
+ ```sql
+ SELECT b.departmentID, b.departmentName
+ FROM uv_department a
+ INNER JOIN uv_department b ON a.departmentID = b.parentID
+ WHERE a.departmentName = '鍚堜綔鍗曚綅'
+ ```
+2. 纭鏁版嵁婧愰厤缃纭�
+3. 鏌ョ湅鍚屾鏃ュ織
+
+### 闂3: 閮ㄩ棬灞傜骇閿欒
+**鎺掓煡姝ラ锛�**
+1. 妫�鏌ncestors瀛楁鏍煎紡
+2. 纭parent_id姝g‘
+3. 鏌ョ湅鍚屾鏃ュ織涓殑鍒嗗叕鍙窱D
+
+## 鎬ц兘娴嬭瘯
+
+### 娴嬭瘯澶ч噺鏁版嵁鍚屾
+濡傛灉SQL Server涓湁澶ч噺鏁版嵁锛屾祴璇曞悓姝ユ�ц兘锛�
+
+```bash
+# 璁板綍寮�濮嬫椂闂�
+date
+
+# 璋冪敤鍚屾鎺ュ彛
+curl -X POST http://localhost:8080/system/dept/sync/branch \
+ -H "Authorization: Bearer {token}"
+
+# 璁板綍缁撴潫鏃堕棿
+date
+```
+
+棰勬湡鎬ц兘鎸囨爣锛�
+- 100鏉℃暟鎹細< 5绉�
+- 500鏉℃暟鎹細< 20绉�
+- 1000鏉℃暟鎹細< 40绉�
+
+## 娴嬭瘯瀹屾垚鏍囧噯
+
+鎵�鏈変互涓嬫潯浠舵弧瓒冲嵆娴嬭瘯閫氳繃锛�
+1. 鉁� 鑳藉鎴愬姛浠嶴QL Server鑾峰彇鏁版嵁
+2. 鉁� 鑳藉姝g‘瑙f瀽閮ㄩ棬鍚嶇О
+3. 鉁� 鑳藉鍒涘缓鍒嗗叕鍙稿拰瀛愰儴闂�
+4. 鉁� department_id瀛楁姝g‘
+5. 鉁� 閲嶅鍚屾涓嶄細鍒涘缓閲嶅鏁版嵁
+6. 鉁� 寮傚父鎯呭喌鏈夊弸濂芥彁绀�
+7. 鉁� 鏃ュ織璁板綍瀹屾暣
+8. 鉁� 鏁版嵁搴撴暟鎹纭�
+
+## 涓嬩竴姝�
+
+娴嬭瘯閫氳繃鍚庯紝鍙互锛�
+1. 鍦ㄥ墠绔儴闂ㄧ鐞嗛〉闈㈡坊鍔�"鍚屾"鎸夐挳
+2. 閰嶇疆瀹氭椂浠诲姟鑷姩鍚屾
+3. 娣诲姞鍚屾鍘嗗彶璁板綍鍔熻兘
+4. 娣诲姞鍚屾澶辫触閫氱煡鍔熻兘
--
Gitblit v1.9.1