From 847a7773ef1a8ad418c6934d35b5f205a97c04d0 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期六, 06 十二月 2025 17:03:24 +0800
Subject: [PATCH] fix:在任务状态更新时,需要更新日志到旧系统
---
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 6
app/pagesTask/components/DepartmentSelector.vue | 230 ++++++
ruoyi-ui/src/views/system/user/index.vue | 13
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java | 14
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java | 40
app/pagesTask/edit-emergency.vue | 76 ++
ruoyi-system/src/main/java/com/ruoyi/system/event/TaskStatusChangedEvent.java | 38 +
ruoyi-system/src/main/java/com/ruoyi/system/listener/DispatchOrdRunningListener.java | 195 +++++
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 | 11
ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml | 7
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java | 8
ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml | 39
ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java | 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java | 91 ++
app/pagesTask/create-emergency.vue | 168 ++--
app/pagesTask/components/AttachmentUpload.vue | 4
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java | 110 ++
app/pages/task/index.vue | 83 ++
ruoyi-admin/src/main/resources/application.yml | 2
sql/add_can_view_all_consult_to_sys_user.sql | 12
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java | 97 ++
/dev/null | 0
app/utils/taskValidator.js | 226 ++++++
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java | 12
ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml | 37
prd/转运任务状态变更记录同步功能说明.md | 397 ++++++++++
sql/DispatchRunning.sql | 10
app/pagesTask/components/HospitalSelector.vue | 111 --
app/pagesTask/detail.vue | 122 ++-
ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java | 22
31 files changed, 1,889 insertions(+), 308 deletions(-)
diff --git a/app/pages/task/index.vue b/app/pages/task/index.vue
index 99f61b6..cf1dbff 100644
--- a/app/pages/task/index.vue
+++ b/app/pages/task/index.vue
@@ -221,6 +221,7 @@
import { listTask, changeTaskStatus } from '@/api/task'
import { mapState } from 'vuex'
import { formatDateTime } from '@/utils/common'
+ import { checkTaskCanDepart } from '@/utils/taskValidator'
export default {
components: {
@@ -461,13 +462,87 @@
},
// 澶勭悊浠诲姟鎿嶄綔
- handleTaskAction(task, action) {
+ async handleTaskAction(task, action) {
switch (action) {
case 'depart':
// 鍑哄彂 -> 鐘舵�佸彉涓哄嚭鍙戜腑
- this.$modal.confirm('纭畾瑕佸嚭鍙戝悧锛�').then(() => {
- this.updateTaskStatus(task.taskId, 'DEPARTING', '浠诲姟宸插嚭鍙�')
- }).catch(() => {});
+ // 鏄剧ず鍔犺浇鎻愮ず
+ uni.showLoading({
+ title: '妫�鏌ヤ换鍔$姸鎬�...'
+ });
+
+ try {
+ // 璋冪敤宸ュ叿绫绘鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙戯紙鍖呭惈鍩烘湰鏍¢獙鍜屽啿绐佹鏌ワ級
+ const checkResult = await checkTaskCanDepart(task)
+
+ uni.hideLoading();
+
+ console.log('鍑哄彂妫�鏌ョ粨鏋�:', checkResult);
+ console.log('valid:', checkResult.valid);
+ console.log('conflicts:', checkResult.conflicts);
+
+ if (!checkResult.valid) {
+ // 鏍¢獙澶辫触锛屾樉绀烘彁绀轰俊鎭苟鎻愪緵璺宠浆閫夐」
+ const conflicts = checkResult.conflicts || [];
+ const conflictInfo = conflicts.length > 0 ? conflicts[0] : null;
+
+ console.log('鍐茬獊淇℃伅:', conflictInfo);
+
+ // 濡傛灉鏈夊啿绐佷换鍔′俊鎭紝鎻愪緵璺宠浆鎸夐挳
+ if (conflictInfo && conflictInfo.taskId) {
+ console.log('鏄剧ず甯﹁烦杞寜閽殑寮圭獥锛屼换鍔D:', conflictInfo.taskId);
+
+ const conflictTaskId = conflictInfo.taskId;
+ const message = checkResult.message || conflictInfo.message || '瀛樺湪鍐茬獊浠诲姟';
+
+ uni.showModal({
+ title: '鎻愮ず',
+ content: message,
+ confirmText: '鍘诲鐞�',
+ cancelText: '鐭ラ亾浜�',
+ success: function(res) {
+ console.log('寮圭獥鐐瑰嚮缁撴灉:', res);
+ if (res.confirm) {
+ // 鐢ㄦ埛鐐瑰嚮"鐜板湪鍘诲鐞�"锛岃烦杞埌鍐茬獊浠诲姟璇︽儏椤�
+ console.log('鍑嗗璺宠浆鍒颁换鍔¤鎯呴〉:', conflictTaskId);
+ uni.navigateTo({
+ url: `/pagesTask/detail?id=${conflictTaskId}`
+ });
+ }
+ },
+ fail: function(err) {
+ console.error('鏄剧ず寮圭獥澶辫触:', err);
+ }
+ });
+ } else {
+ // 娌℃湁鍐茬獊浠诲姟ID锛屽彧鏄剧ず鎻愮ず
+ console.log('鏄剧ず鏅�氭彁绀哄脊绐�');
+ uni.showModal({
+ title: '鎻愮ず',
+ content: checkResult.message || '浠诲姟鏍¢獙澶辫触',
+ showCancel: false,
+ confirmText: '鐭ラ亾浜�',
+ fail: function(err) {
+ console.error('鏄剧ず寮圭獥澶辫触:', err);
+ }
+ });
+ }
+ return;
+ }
+
+ // 鎵�鏈夋鏌ラ�氳繃锛屽彲浠ュ嚭鍙�
+ this.$modal.confirm('纭畾瑕佸嚭鍙戝悧锛�').then(() => {
+ this.updateTaskStatus(task.taskId, 'DEPARTING', '浠诲姟宸插嚭鍙�')
+ }).catch(() => {});
+
+ } catch (error) {
+ uni.hideLoading();
+ console.error('妫�鏌ヤ换鍔$姸鎬佸け璐�:', error);
+ // 妫�鏌ュけ璐ユ椂锛屼粛鐒跺厑璁稿嚭鍙�
+ this.$modal.confirm('妫�鏌ヤ换鍔$姸鎬佸け璐ワ紝鏄惁缁х画鍑哄彂锛�').then(() => {
+ this.updateTaskStatus(task.taskId, 'DEPARTING', '浠诲姟宸插嚭鍙�')
+ }).catch(() => {});
+ }
break;
case 'cancel':
diff --git a/app/pagesTask/components/AttachmentUpload.vue b/app/pagesTask/components/AttachmentUpload.vue
index 2f319d3..ab60409 100644
--- a/app/pagesTask/components/AttachmentUpload.vue
+++ b/app/pagesTask/components/AttachmentUpload.vue
@@ -50,7 +50,7 @@
<view class="form-label">閫夋嫨鍥剧墖</view>
<button class="choose-image-btn" @click="chooseImage">
<uni-icons type="image" size="20"></uni-icons>
- <text>鐐瑰嚮閫夋嫨</text>
+ <text class="btn-text">鐐瑰嚮閫夋嫨</text>
</button>
</view>
<view class="preview-area" v-if="tempImagePath">
@@ -506,7 +506,7 @@
color: #666;
font-size: 28rpx;
- text {
+ .btn-text {
margin-left: 10rpx;
}
}
diff --git a/app/pagesTask/components/DepartmentSelector.vue b/app/pagesTask/components/DepartmentSelector.vue
new file mode 100644
index 0000000..3e2b5ef
--- /dev/null
+++ b/app/pagesTask/components/DepartmentSelector.vue
@@ -0,0 +1,230 @@
+<template>
+ <view class="form-item">
+ <view class="form-label" :class="{ required: required }">{{ label }}</view>
+ <picker
+ v-if="!isHome && departmentOptions.length > 0"
+ mode="selector"
+ :range="departmentOptions"
+ range-key="text"
+ :value="selectedIndex"
+ @change="onDepartmentChange"
+ >
+ <view class="form-input picker-input">
+ {{ displayText }}
+ <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
+ </view>
+ </picker>
+ <input
+ v-else-if="!isHome"
+ class="form-input"
+ placeholder="璇疯緭鍏ョ瀹�"
+ :value="value"
+ @input="onDepartmentInput"
+ />
+ <view v-else class="form-input picker-input disabled">
+ 鍏跺畠
+ </view>
+ </view>
+</template>
+
+<script>
+import { getHospitalDepartments } from "@/api/dictionary"
+
+export default {
+ name: 'DepartmentSelector',
+ props: {
+ // 鏍囩鏂囨湰
+ label: {
+ type: String,
+ default: '绉戝'
+ },
+ // 鏄惁蹇呭~
+ required: {
+ type: Boolean,
+ default: false
+ },
+ // 褰撳墠閫変腑鐨勭瀹ゅ悕绉�
+ value: {
+ type: String,
+ default: ''
+ },
+ // 褰撳墠閫変腑鐨勭瀹D
+ departmentId: {
+ type: [Number, String],
+ default: null
+ },
+ // 鏄惁涓�"瀹朵腑"锛堝鏋滄槸瀹朵腑锛屾樉绀�"鍏跺畠"涓斾笉鍙�夋嫨锛�
+ isHome: {
+ type: Boolean,
+ default: false
+ },
+ // 鍗犱綅绗�
+ placeholder: {
+ type: String,
+ default: '璇烽�夋嫨绉戝'
+ }
+ },
+ data() {
+ return {
+ departmentOptions: [], // 绉戝閫夐」鍒楄〃
+ selectedIndex: -1
+ }
+ },
+ computed: {
+ displayText() {
+ if (this.selectedIndex >= 0 && this.selectedIndex < this.departmentOptions.length) {
+ return this.departmentOptions[this.selectedIndex].text
+ }
+ return this.value || this.placeholder
+ }
+ },
+ watch: {
+ value: {
+ immediate: true,
+ handler(newVal) {
+ if (newVal) {
+ this.updateSelectedIndex(newVal)
+ } else {
+ this.selectedIndex = -1
+ }
+ }
+ },
+ departmentId: {
+ immediate: true,
+ handler(newVal) {
+ if (newVal) {
+ this.updateSelectedIndexById(newVal)
+ }
+ }
+ },
+ departmentOptions: {
+ immediate: true,
+ handler() {
+ if (this.value) {
+ this.updateSelectedIndex(this.value)
+ } else if (this.departmentId) {
+ this.updateSelectedIndexById(this.departmentId)
+ }
+ }
+ }
+ },
+ mounted() {
+ this.loadDepartments()
+ },
+ methods: {
+ // 鍔犺浇绉戝鏁版嵁
+ loadDepartments() {
+ getHospitalDepartments().then(response => {
+ const list = response.data || []
+ this.departmentOptions = list.map(item => ({
+ id: item.vID,
+ text: item.vtext,
+ dictValue: item.vtext
+ }))
+ }).catch(error => {
+ console.error('鍔犺浇绉戝鏁版嵁澶辫触:', error)
+ this.departmentOptions = []
+ })
+ },
+
+ // 鏍规嵁绉戝鍚嶇О鏇存柊閫変腑绱㈠紩
+ updateSelectedIndex(departmentName) {
+ if (!departmentName || this.departmentOptions.length === 0) {
+ this.selectedIndex = -1
+ return
+ }
+
+ const index = this.departmentOptions.findIndex(d => d.text === departmentName)
+ this.selectedIndex = index !== -1 ? index : -1
+ },
+
+ // 鏍规嵁绉戝ID鏇存柊閫変腑绱㈠紩
+ updateSelectedIndexById(departmentId) {
+ if (!departmentId || this.departmentOptions.length === 0) {
+ this.selectedIndex = -1
+ return
+ }
+
+ const index = this.departmentOptions.findIndex(d => d.id == departmentId)
+ this.selectedIndex = index !== -1 ? index : -1
+ },
+
+ // 绉戝閫夋嫨鍙樺寲锛坧icker锛�
+ onDepartmentChange(e) {
+ const index = e.detail.value
+
+ // 瀹夊叏妫�鏌ワ細纭繚绱㈠紩鏈夋晥涓旈�夐」瀛樺湪
+ if (index < 0 || index >= this.departmentOptions.length) {
+ console.warn('绉戝閫夋嫨绱㈠紩瓒婄晫:', index, '鏁扮粍闀垮害:', this.departmentOptions.length)
+ return
+ }
+
+ const selected = this.departmentOptions[index]
+
+ // 浜屾妫�鏌ワ細纭繚閫変腑椤瑰瓨鍦ㄤ笖鏈塼ext灞炴��
+ if (!selected || !selected.text) {
+ console.warn('绉戝閫夐」鏁版嵁寮傚父:', selected)
+ return
+ }
+
+ this.selectedIndex = index
+
+ this.$emit('input', selected.text)
+ this.$emit('change', {
+ department: selected.text,
+ departmentId: selected.id
+ })
+ },
+
+ // 绉戝杈撳叆锛堟墜鍔ㄨ緭鍏ワ級
+ onDepartmentInput(e) {
+ const department = e.detail.value
+ this.$emit('input', department)
+ this.$emit('change', {
+ department: department,
+ departmentId: null
+ })
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.form-item {
+ margin-bottom: 40rpx;
+
+ .form-label {
+ font-size: 28rpx;
+ margin-bottom: 15rpx;
+ color: #333;
+
+ &.required::before {
+ content: '*';
+ color: #ff0000;
+ margin-right: 5rpx;
+ }
+ }
+
+ .form-input {
+ width: 100%;
+ height: 70rpx;
+ padding: 0 20rpx;
+ border: 1rpx solid #eee;
+ border-radius: 10rpx;
+ font-size: 28rpx;
+ box-sizing: border-box;
+
+ &.picker-input {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ &.disabled {
+ background-color: #f5f5f5;
+ color: #999;
+ }
+ }
+}
+</style>
+
diff --git a/app/pagesTask/components/HospitalSelector.vue b/app/pagesTask/components/HospitalSelector.vue
index 5f3c420..b82dc5b 100644
--- a/app/pagesTask/components/HospitalSelector.vue
+++ b/app/pagesTask/components/HospitalSelector.vue
@@ -27,42 +27,6 @@
</view>
</view>
- <view class="form-item" v-if="showDepartment">
- <view class="form-label" :class="{ required: departmentRequired }">绉戝</view>
- <picker
- v-if="selectedHospitalName !== '瀹朵腑' && departmentOptions.length > 0"
- mode="selector"
- :range="departmentOptions"
- range-key="text"
- @change="onDepartmentChange"
- >
- <view class="form-input picker-input">
- {{ departmentValue || '璇烽�夋嫨绉戝' }}
- <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
- </view>
- </picker>
- <input
- v-else-if="selectedHospitalName !== '瀹朵腑'"
- class="form-input"
- placeholder="璇疯緭鍏ョ瀹�"
- :value="departmentValue"
- @input="onDepartmentInput"
- />
- <view v-else class="form-input picker-input disabled">
- 鍏跺畠
- </view>
- </view>
-
- <view class="form-item" v-if="showBedNumber">
- <view class="form-label">搴婂彿</view>
- <input
- class="form-input"
- placeholder="璇疯緭鍏ュ簥鍙�"
- :value="bedNumberValue"
- @input="onBedNumberInput"
- />
- </view>
-
<view class="form-item">
<view class="form-label" :class="{ required: required }">{{ addressLabel }}</view>
<view class="address-input-container" v-if="selectedHospitalName === '瀹朵腑'">
@@ -136,26 +100,6 @@
address: ''
})
},
- // 鏄惁鏄剧ず绉戝
- showDepartment: {
- type: Boolean,
- default: true
- },
- // 绉戝鏄惁蹇呭~
- departmentRequired: {
- type: Boolean,
- default: false
- },
- // 绉戝閫夐」鍒楄〃锛堢敤浜� picker锛�
- departmentOptions: {
- type: Array,
- default: () => []
- },
- // 鏄惁鏄剧ず搴婂彿
- showBedNumber: {
- type: Boolean,
- default: true
- },
// 閮ㄩ棬ID锛堢敤浜庡尯鍩熻繃婊わ級
deptId: {
type: [Number, String],
@@ -186,12 +130,6 @@
computed: {
addressValue() {
return this.value.address || ''
- },
- departmentValue() {
- return this.value.department || ''
- },
- bedNumberValue() {
- return this.value.bedNumber || ''
}
},
watch: {
@@ -292,16 +230,7 @@
const hospitalData = {
id: hospital.hospId,
name: hospital.hospName,
- department: this.value.department || '',
- departmentId: this.value.departmentId || null,
- bedNumber: this.value.bedNumber || '',
address: hospital.hospName === '瀹朵腑' ? '' : this.buildFullAddress(hospital)
- }
-
- // 濡傛灉閫夋嫨鐨勬槸"瀹朵腑"锛岀瀹よ缃负"鍏跺畠"
- if (hospital.hospName === '瀹朵腑') {
- hospitalData.department = '鍏跺畠'
- hospitalData.departmentId = null
}
this.showResults = false
@@ -388,45 +317,13 @@
...this.value,
address: fullAddress
})
+ this.$emit('address-selected', {
+ address: fullAddress,
+ location: item.location
+ })
this.showAddressSuggestions = false
this.addressSuggestions = []
- },
-
- // 绉戝閫夋嫨鍙樺寲锛坧icker锛�
- onDepartmentChange(e) {
- const index = e.detail.value
- const selected = this.departmentOptions[index]
- const updatedValue = {
- ...this.value,
- department: selected.text,
- departmentId: selected.id
- }
- this.$emit('input', updatedValue)
- this.$emit('department-change', {
- department: selected.text,
- departmentId: selected.id
- })
- },
-
- // 绉戝杈撳叆锛堟墜鍔ㄨ緭鍏ワ級
- onDepartmentInput(e) {
- const department = e.detail.value
- this.$emit('input', {
- ...this.value,
- department: department
- })
- this.$emit('department-change', department)
- },
-
- // 搴婂彿杈撳叆
- onBedNumberInput(e) {
- const bedNumber = e.detail.value
- this.$emit('input', {
- ...this.value,
- bedNumber: bedNumber
- })
- this.$emit('bed-number-change', bedNumber)
}
}
}
diff --git a/app/pagesTask/create-emergency.vue b/app/pagesTask/create-emergency.vue
index a752eda..e2b1d05 100644
--- a/app/pagesTask/create-emergency.vue
+++ b/app/pagesTask/create-emergency.vue
@@ -144,28 +144,60 @@
label="鍖婚櫌鍚嶇О"
address-label="杞嚭鍦板潃"
:required="true"
- :department-required="true"
+ :show-department="false"
v-model="taskForm.hospitalOut"
:dept-id="selectedOrganizationId"
:region="selectedRegion"
- :department-options="departmentOptions"
@change="onHospitalOutChange"
@address-selected="onHospitalOutAddressSelected"
/>
+ <DepartmentSelector
+ label="杞嚭绉戝"
+ :required="true"
+ v-model="taskForm.hospitalOut.department"
+ :department-id="taskForm.hospitalOut.departmentId"
+ :is-home="taskForm.hospitalOut.name === '瀹朵腑'"
+ @change="onHospitalOutDepartmentChange"
+ />
+
+ <view class="form-item">
+ <view class="form-label">搴婂彿</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ュ簥鍙�"
+ v-model="taskForm.hospitalOut.bedNumber"
+ />
+ </view>
<view class="form-section-title">杞叆鍖婚櫌淇℃伅</view>
<HospitalSelector
label="鍖婚櫌鍚嶇О"
address-label="杞叆鍦板潃"
:required="true"
- :department-required="true"
+ :show-department="false"
v-model="taskForm.hospitalIn"
:dept-id="selectedOrganizationId"
:region="selectedRegion"
- :department-options="departmentOptions"
@change="onHospitalInChange"
@address-selected="onHospitalInAddressSelected"
/>
+ <DepartmentSelector
+ label="杞叆绉戝"
+ :required="true"
+ v-model="taskForm.hospitalIn.department"
+ :department-id="taskForm.hospitalIn.departmentId"
+ :is-home="taskForm.hospitalIn.name === '瀹朵腑'"
+ @change="onHospitalInDepartmentChange"
+ />
+
+ <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 required">杞繍鍏噷鏁�</view>
@@ -245,13 +277,14 @@
import { checkVehicleActiveTasks } from "@/api/task"
import { getDicts } from "@/api/dict"
-import { getServiceOrdAreaTypes, getServiceOrderTypes, getHospitalDepartments } from "@/api/dictionary"
+import { getServiceOrdAreaTypes, getServiceOrderTypes } from "@/api/dictionary"
import { listBranchCompany, getDept } from "@/api/system/dept"
import MapSelector from './components/map-selector.vue'
import OrganizationSelector from './components/OrganizationSelector.vue'
import HospitalSelector from './components/HospitalSelector.vue'
import DiseaseSelector from './components/DiseaseSelector.vue'
import StaffSelector from './components/StaffSelector.vue'
+import DepartmentSelector from './components/DepartmentSelector.vue'
export default {
components: {
@@ -262,7 +295,8 @@
HospitalSelector,
DiseaseSelector,
DepartureSelector,
- StaffSelector
+ StaffSelector,
+ DepartmentSelector
},
data() {
return {
@@ -320,7 +354,6 @@
emergencyTaskTypeOptions: [], // 浠诲姟绫诲瀷閫夐」锛堢敤浜巔icker鏄剧ず锛�
documentTypes: [], // 鍗曟嵁绫诲瀷鍒楄〃
documentTypeOptions: [], // 鍗曟嵁绫诲瀷閫夐」锛堢敤浜巔icker鏄剧ず锛�
- departmentOptions: [], // 绉戝瀛楀吀鏁版嵁
loading: false,
// 鏅鸿兘璇嗗埆鐩稿叧
rawText: '',
@@ -357,8 +390,6 @@
this.getAvailableVehicles().then(() => {
this.getUserBoundVehicleInfo()
})
- // 鍔犺浇绉戝瀛楀吀鏁版嵁
- this.loadDepartments()
// 鍔犺浇浠诲姟绫诲瀷鏁版嵁
this.loadEmergencyTaskTypes()
// 鍔犺浇鍗曟嵁绫诲瀷鏁版嵁
@@ -468,22 +499,6 @@
}
},
- // 鍔犺浇绉戝鏁版嵁锛堜粠 SQL Server 鍔ㄦ�佸姞杞斤級
- loadDepartments() {
- getHospitalDepartments().then(response => {
- const list = response.data || [];
- this.departmentOptions = list.map(item => ({
- id: item.vID,
- text: item.vtext,
- dictValue: item.vtext // 涓轰簡淇濇寔鍏煎鎬э紝淇濈暀dictValue瀛楁
- }));
- // console.log('绉戝鏁版嵁鍔犺浇鎴愬姛:', this.departmentOptions);
- }).catch(error => {
- console.error('鍔犺浇绉戝鏁版嵁澶辫触:', error)
- this.departmentOptions = []
- })
- },
-
// 鍔犺浇浠诲姟绫诲瀷鏁版嵁锛堜粠 SQL Server锛�
loadEmergencyTaskTypes() {
getServiceOrderTypes().then(response => {
@@ -552,6 +567,12 @@
console.log('杞嚭鍖婚櫌鍙樺寲:', hospitalData)
// 缁勪欢宸茬粡閫氳繃 v-model 鏇存柊浜� taskForm.hospitalOut
+ // 濡傛灉閫夋嫨鐨勬槸"瀹朵腑"锛岃嚜鍔ㄨ缃瀹や负"鍏跺畠"
+ if (hospitalData.name === '瀹朵腑') {
+ this.taskForm.hospitalOut.department = '鍏跺畠'
+ this.taskForm.hospitalOut.departmentId = null
+ }
+
// 濡傛灉杞叆鍦板潃宸插~鍐�,鑷姩璁$畻璺濈
if (this.taskForm.hospitalIn.address) {
// 濡傛灉涓や釜閮戒笉鏄�"瀹朵腑",浣跨敤鍖婚櫌璺濈璁$畻
@@ -576,6 +597,12 @@
console.log('杞叆鍖婚櫌鍙樺寲:', hospitalData)
// 缁勪欢宸茬粡閫氳繃 v-model 鏇存柊浜� taskForm.hospitalIn
+ // 濡傛灉閫夋嫨鐨勬槸"瀹朵腑"锛岃嚜鍔ㄨ缃瀹や负"鍏跺畠"
+ if (hospitalData.name === '瀹朵腑') {
+ this.taskForm.hospitalIn.department = '鍏跺畠'
+ this.taskForm.hospitalIn.departmentId = null
+ }
+
// 濡傛灉杞嚭鍦板潃宸插~鍐�,鑷姩璁$畻璺濈
if (this.taskForm.hospitalOut.address) {
// 濡傛灉涓や釜閮戒笉鏄�"瀹朵腑",浣跨敤鍖婚櫌璺濈璁$畻
@@ -592,6 +619,28 @@
onHospitalInAddressSelected(data) {
if (this.taskForm.hospitalOut.address) {
this.calculateDistanceByManualAddress()
+ }
+ },
+
+ // 杞嚭绉戝鍙樺寲
+ onHospitalOutDepartmentChange(data) {
+ if (data && typeof data === 'object') {
+ this.taskForm.hospitalOut.department = data.department
+ this.taskForm.hospitalOut.departmentId = data.departmentId
+ } else {
+ this.taskForm.hospitalOut.department = data
+ this.taskForm.hospitalOut.departmentId = null
+ }
+ },
+
+ // 杞叆绉戝鍙樺寲
+ onHospitalInDepartmentChange(data) {
+ if (data && typeof data === 'object') {
+ this.taskForm.hospitalIn.department = data.department
+ this.taskForm.hospitalIn.departmentId = data.departmentId
+ } else {
+ this.taskForm.hospitalIn.department = data
+ this.taskForm.hospitalIn.departmentId = null
}
},
@@ -1002,20 +1051,14 @@
if (result.phone) this.taskForm.patient.phone = result.phone
if (result.price) this.taskForm.price = result.price
- // 搴旂敤绉戝淇℃伅锛堝尮閰� departmentOptions 涓殑鏁版嵁锛�
+ // 搴旂敤绉戝淇℃伅锛堥�氳繃 DepartmentSelector 缁勪欢澶勭悊锛�
if (result.departmentOut) {
- const deptOut = this.matchDepartment(result.departmentOut)
- if (deptOut) {
- this.taskForm.hospitalOut.department = deptOut.text
- this.taskForm.hospitalOut.departmentId = deptOut.id
- }
+ this.taskForm.hospitalOut.department = result.departmentOut
+ // 绉戝ID浼氬湪 DepartmentSelector 缁勪欢涓嚜鍔ㄥ尮閰�
}
if (result.departmentIn) {
- const deptIn = this.matchDepartment(result.departmentIn)
- if (deptIn) {
- this.taskForm.hospitalIn.department = deptIn.text
- this.taskForm.hospitalIn.departmentId = deptIn.id
- }
+ this.taskForm.hospitalIn.department = result.departmentIn
+ // 绉戝ID浼氬湪 DepartmentSelector 缁勪欢涓嚜鍔ㄥ尮閰�
}
// 澶勭悊鍖婚櫌鍚嶇О 鈫� 绮剧‘鍖归厤鍖婚櫌骞惰ˉ鍏ㄥ湴鍧�涓嶪D锛堜笉闄愬埗鍒嗗叕鍙稿尯鍩燂級
@@ -1161,40 +1204,6 @@
return ''
},
- // 鍖归厤绉戝锛堜紭鍏堜娇鐢� departmentOptions 涓殑鏁版嵁锛�
- matchDepartment(deptName) {
- if (!deptName || !this.departmentOptions || this.departmentOptions.length === 0) {
- return null
- }
-
- const normalized = deptName.trim().toUpperCase()
-
- // 1. 绮剧‘鍖归厤锛堜笉鍖哄垎澶у皬鍐欙級
- let matched = this.departmentOptions.find(d =>
- d.text.toUpperCase() === normalized
- )
- if (matched) return matched
-
- // 2. 鍖呭惈鍖归厤锛堢瀹ゅ悕鍖呭惈璇嗗埆鍒扮殑鍏抽敭璇嶏級
- matched = this.departmentOptions.find(d =>
- d.text.toUpperCase().includes(normalized) ||
- normalized.includes(d.text.toUpperCase())
- )
- if (matched) return matched
-
- // 3. 妯$硦鍖归厤锛堝幓闄�"绉�"銆�"瀹�"绛夊悗缂�鍐嶅尮閰嶏級
- const cleanedInput = normalized.replace(/[绉戝閮╙/g, '')
- matched = this.departmentOptions.find(d => {
- const cleanedDept = d.text.toUpperCase().replace(/[绉戝閮╙/g, '')
- return cleanedDept === cleanedInput ||
- cleanedDept.includes(cleanedInput) ||
- cleanedInput.includes(cleanedDept)
- })
- if (matched) return matched
-
- return null
- },
-
// 鎻愬彇绉戝淇℃伅
extractDepartment(text, type) {
// 甯歌绉戝鍏抽敭璇嶏紙浣滀负鍏滃簳鏂规锛�
@@ -1210,24 +1219,7 @@
'妫�楠岀', '鐥呯悊绉�', '鑽墏绉�', '钀ュ吇绉�'
]
- // 浼樺厛灏濊瘯浠� departmentOptions 涓尮閰�
- if (this.departmentOptions && this.departmentOptions.length > 0) {
- // 鏋勫缓 departmentOptions 鐨勫尮閰嶆ā寮忥紙鎸夐暱搴﹀�掑簭锛�
- const optionTexts = this.departmentOptions.map(d => d.text).sort((a, b) => b.length - a.length)
- const optionPattern = optionTexts.map(t => t.replace(/[()锛堬級]/g, '\\$&')).join('|')
-
- if (optionPattern) {
- const regex = new RegExp(`(${optionPattern})`, 'gi')
- const matches = text.match(regex)
-
- if (matches && matches.length > 0) {
- // 濡傛灉鏄浆鍑猴紝鍙栫涓�涓瀹わ紱濡傛灉鏄浆鍏ワ紝鍙栨渶鍚庝竴涓瀹�
- return type === 'out' ? matches[0] : matches[matches.length - 1]
- }
- }
- }
-
- // 鍏滃簳锛氫娇鐢ㄩ粯璁ょ瀹ゅ垪琛ㄥ尮閰�
+ // 浣跨敤榛樿绉戝鍒楄〃鍖归厤
const sortedDepts = departments.sort((a, b) => b.length - a.length)
const deptPattern = sortedDepts.join('|')
diff --git a/app/pagesTask/detail.vue b/app/pagesTask/detail.vue
index bffcfea..277d825 100644
--- a/app/pagesTask/detail.vue
+++ b/app/pagesTask/detail.vue
@@ -37,7 +37,7 @@
<view
class="assignee-item"
v-for="(assignee, index) in taskDetail.assignees"
- :key="assignee.userId || index"
+ :key="'assignee-' + (assignee.userId || assignee.userName || index)"
>
<view class="assignee-index">{{ index + 1 }}</view>
<view class="assignee-info">
@@ -131,12 +131,12 @@
</view>
</view>
- <view class="detail-section" v-if="taskDetail.taskDescription">
+ <view class="detail-section" v-if="taskDetail.taskDescription && taskDetail.taskType !== 'EMERGENCY_TRANSFER'">
<view class="section-title">浠诲姟鎻忚堪</view>
<view class="description">{{ taskDetail.taskDescription }}</view>
</view>
- <view class="detail-section" v-if="taskDetail.remark">
+ <view class="detail-section" v-if="taskDetail.remark && taskDetail.taskType !== 'EMERGENCY_TRANSFER'">
<view class="section-title">澶囨敞淇℃伅</view>
<view class="description">{{ taskDetail.remark }}</view>
</view>
@@ -250,8 +250,8 @@
<view class="section-title">鏀粯璁板綍</view>
<view
class="payment-record-item"
- v-for="payment in paymentInfo.paidPayments"
- :key="payment.id"
+ v-for="(payment, index) in paymentInfo.paidPayments"
+ :key="'payment-' + (payment.id || index)"
>
<view class="payment-header">
<view
@@ -449,6 +449,7 @@
import { checkVehicleActiveTasks } from '@/api/task'
import { getPaymentInfo } from '@/api/payment'
import { formatDateTime } from '@/utils/common'
+ import { validateTaskForDepart, validateTaskForSettlement, getTaskVehicleId, checkTaskCanDepart } from '@/utils/taskValidator'
import AttachmentUpload from './components/AttachmentUpload.vue'
export default {
@@ -752,6 +753,15 @@
// 澶勭悊缁撶畻
handleSettlement() {
+ // 鏍¢獙浠诲姟鏄惁鍙互缁撶畻
+ const validation = validateTaskForSettlement(this.taskDetail)
+ if (!validation.valid) {
+ this.$modal.confirm(`${validation.message}锛岄渶瑕佸厛淇敼浠诲姟鍚庢墠鑳界粨绠椼�傛槸鍚︾幇鍦ㄥ幓淇敼锛焋).then(() => {
+ this.handleEdit()
+ }).catch(() => {})
+ return
+ }
+
uni.navigateTo({
url: '/pagesTask/settlement?taskId=' + this.taskId
})
@@ -803,68 +813,84 @@
},
// 妫�鏌ヨ溅杈嗙姸鎬佸苟鍑哄彂
- checkVehicleAndDepart() {
- // 妫�鏌ュ嚭鍙戞椂闂存槸鍚︿负绌烘垨1900骞达紙淇锛氶槻姝㈡棤鏁堟椂闂达級
- if (!this.taskDetail.plannedStartTime || this.taskDetail.plannedStartTime.startsWith('1900')) {
- this.$modal.confirm('浠诲姟鐨勮浆杩愭椂闂存湭璁剧疆鎴栨棤鏁堬紝闇�瑕佸厛淇敼浠诲姟琛ュ厖杞繍鏃堕棿鍚庢墠鑳藉嚭鍙戙�傛槸鍚︾幇鍦ㄥ幓淇敼锛�').then(() => {
- this.handleEdit()
- }).catch(() => {})
- return
- }
-
- // 鑾峰彇浠诲姟杞﹁締ID
- const vehicleId = this.getVehicleId();
- if (!vehicleId) {
- this.$modal.showToast('鏈壘鍒颁换鍔¤溅杈嗕俊鎭�');
- return;
- }
-
+ async checkVehicleAndDepart() {
// 鏄剧ず鍔犺浇鎻愮ず
uni.showLoading({
- title: '妫�鏌ヨ溅杈嗙姸鎬�...'
+ title: '妫�鏌ヤ换鍔$姸鎬�...'
});
- checkVehicleActiveTasks(vehicleId).then(response => {
+ try {
+ // 璋冪敤宸ュ叿绫绘鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙戯紙鍖呭惈鍩烘湰鏍¢獙鍜屽啿绐佹鏌ワ級
+ const checkResult = await checkTaskCanDepart(this.taskDetail)
+
uni.hideLoading();
- const activeTasks = response.data || [];
+ console.log('鍑哄彂妫�鏌ョ粨鏋�:', checkResult);
+ console.log('valid:', checkResult.valid);
+ console.log('conflicts:', checkResult.conflicts);
- // 杩囨护鎺夊綋鍓嶄换鍔℃湰韬紙淇锛氶槻姝� activeTasks 涓� null锛�
- const otherActiveTasks = (activeTasks && Array.isArray(activeTasks)) ? activeTasks.filter(task => task.taskId !== this.taskId) : [];
-
- if (otherActiveTasks.length > 0) {
- // 杞﹁締鏈夊叾浠栨鍦ㄨ繘琛屼腑鐨勪换鍔�
- const task = otherActiveTasks[0];
- const taskStatus = this.getStatusText(task.taskStatus);
- const message = `璇ヨ溅杈嗗凡鏈夋鍦ㄨ浆杩愪腑鐨勪换鍔★紒
-
-浠诲姟鍗曞彿锛�${task.taskCode}
-浠诲姟鐘舵�侊細${taskStatus}
-
-璇峰厛瀹屾垚褰撳墠浠诲姟鍚庡啀鍑哄彂鏂颁换鍔°�俙;
+ if (!checkResult.valid) {
+ // 鏍¢獙澶辫触锛屾樉绀烘彁绀轰俊鎭苟鎻愪緵璺宠浆閫夐」
+ const conflicts = checkResult.conflicts || [];
+ const conflictInfo = conflicts.length > 0 ? conflicts[0] : null;
- uni.showModal({
- title: '鎻愮ず',
- content: message,
- showCancel: false,
- confirmText: '鎴戠煡閬撲簡'
- });
+ console.log('鍐茬獊淇℃伅:', conflictInfo);
+
+ // 濡傛灉鏈夊啿绐佷换鍔′俊鎭紝鎻愪緵璺宠浆鎸夐挳
+ if (conflictInfo && conflictInfo.taskId) {
+ console.log('鏄剧ず甯﹁烦杞寜閽殑寮圭獥锛屼换鍔D:', conflictInfo.taskId);
+
+ const conflictTaskId = conflictInfo.taskId;
+ const message = checkResult.message || conflictInfo.message || '瀛樺湪鍐茬獊浠诲姟';
+
+ uni.showModal({
+ title: '鎻愮ず',
+ content: message,
+ confirmText: '鍘诲鐞�',
+ cancelText: '鐭ラ亾浜�',
+ success: function(res) {
+ console.log('寮圭獥鐐瑰嚮缁撴灉:', res);
+ if (res.confirm) {
+ // 鐢ㄦ埛鐐瑰嚮"鐜板湪鍘诲鐞�"锛岃烦杞埌鍐茬獊浠诲姟璇︽儏椤�
+ console.log('鍑嗗璺宠浆鍒颁换鍔¤鎯呴〉:', conflictTaskId);
+ uni.redirectTo({
+ url: `/pagesTask/detail?id=${conflictTaskId}`
+ });
+ }
+ },
+ fail: function(err) {
+ console.error('鏄剧ず寮圭獥澶辫触:', err);
+ }
+ });
+ } else {
+ // 娌℃湁鍐茬獊浠诲姟ID锛屽彧鏄剧ず鎻愮ず
+ console.log('鏄剧ず鏅�氭彁绀哄脊绐�');
+ uni.showModal({
+ title: '鎻愮ず',
+ content: checkResult.message || '浠诲姟鏍¢獙澶辫触',
+ showCancel: false,
+ confirmText: '鐭ラ亾浜�',
+ fail: function(err) {
+ console.error('鏄剧ず寮圭獥澶辫触:', err);
+ }
+ });
+ }
return;
}
- // 杞﹁締娌℃湁鍏朵粬姝e湪杩涜涓殑浠诲姟锛屽彲浠ュ嚭鍙�
+ // 鎵�鏈夋鏌ラ�氳繃锛屽彲浠ュ嚭鍙�
this.$modal.confirm('纭畾瑕佸嚭鍙戝悧锛�').then(() => {
this.updateTaskStatus('DEPARTING', '浠诲姟宸插嚭鍙�')
}).catch(() => {});
- }).catch(error => {
+ } catch (error) {
uni.hideLoading();
- console.error('妫�鏌ヨ溅杈嗙姸鎬佸け璐�:', error);
+ console.error('妫�鏌ヤ换鍔$姸鎬佸け璐�:', error);
// 妫�鏌ュけ璐ユ椂锛屼粛鐒跺厑璁稿嚭鍙�
- this.$modal.confirm('妫�鏌ヨ溅杈嗙姸鎬佸け璐ワ紝鏄惁缁х画鍑哄彂锛�').then(() => {
+ this.$modal.confirm('妫�鏌ヤ换鍔$姸鎬佸け璐ワ紝鏄惁缁х画鍑哄彂锛�').then(() => {
this.updateTaskStatus('DEPARTING', '浠诲姟宸插嚭鍙�')
}).catch(() => {});
- });
+ }
},
// 鑾峰彇浠诲姟杞﹁締ID
diff --git a/app/pagesTask/edit-emergency.vue b/app/pagesTask/edit-emergency.vue
index eefd5df..4790118 100644
--- a/app/pagesTask/edit-emergency.vue
+++ b/app/pagesTask/edit-emergency.vue
@@ -119,25 +119,61 @@
<view class="form-section-title">杞嚭鍖婚櫌淇℃伅</view>
<HospitalSelector
- label="鍖洪櫌鍚嶇О"
+ label="鍖婚櫌鍚嶇О"
address-label="杞嚭鍦板潃"
:required="true"
+ :show-department="false"
v-model="taskForm.hospitalOut"
:dept-id="selectedOrganizationId"
@change="onHospitalOutChange"
@address-selected="onHospitalOutAddressSelected"
/>
+ <DepartmentSelector
+ label="杞嚭绉戝"
+ :required="true"
+ v-model="taskForm.hospitalOut.department"
+ :department-id="taskForm.hospitalOut.departmentId"
+ :is-home="taskForm.hospitalOut.name === '瀹朵腑'"
+ @change="onHospitalOutDepartmentChange"
+ />
+
+ <view class="form-item">
+ <view class="form-label">搴婂彿</view>
+ <input
+ class="form-input"
+ placeholder="璇疯緭鍏ュ簥鍙�"
+ v-model="taskForm.hospitalOut.bedNumber"
+ />
+ </view>
<view class="form-section-title">杞叆鍖婚櫌淇℃伅</view>
<HospitalSelector
label="鍖婚櫌鍚嶇О"
address-label="杞叆鍦板潃"
:required="true"
+ :show-department="false"
v-model="taskForm.hospitalIn"
:dept-id="selectedOrganizationId"
@change="onHospitalInChange"
@address-selected="onHospitalInAddressSelected"
/>
+ <DepartmentSelector
+ label="杞叆绉戝"
+ :required="true"
+ v-model="taskForm.hospitalIn.department"
+ :department-id="taskForm.hospitalIn.departmentId"
+ :is-home="taskForm.hospitalIn.name === '瀹朵腑'"
+ @change="onHospitalInDepartmentChange"
+ />
+
+ <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>
@@ -204,6 +240,7 @@
import DiseaseSelector from './components/DiseaseSelector.vue'
import DepartureSelector from './components/DepartureSelector.vue'
import StaffSelector from './components/StaffSelector.vue'
+import DepartmentSelector from './components/DepartmentSelector.vue'
import distanceCalculator from '@/mixins/distanceCalculator.js'
export default {
@@ -216,7 +253,8 @@
HospitalSelector,
DiseaseSelector,
DepartureSelector,
- StaffSelector
+ StaffSelector,
+ DepartmentSelector
},
mixins: [distanceCalculator],
data() {
@@ -526,6 +564,12 @@
console.log('杞嚭鍖婚櫌鍙樺寲:', hospitalData)
// 缁勪欢宸茬粡閫氳繃 v-model 鏇存柊浜� taskForm.hospitalOut
+ // 濡傛灉閫夋嫨鐨勬槸"瀹朵腑"锛岃嚜鍔ㄨ缃瀹や负"鍏跺畠"
+ if (hospitalData.name === '瀹朵腑') {
+ this.taskForm.hospitalOut.department = '鍏跺畠'
+ this.taskForm.hospitalOut.departmentId = null
+ }
+
// 濡傛灉杞叆鍦板潃宸插~鍐�,鑷姩璁$畻璺濈
if (this.taskForm.hospitalIn.address) {
// 濡傛灉涓や釜閮戒笉鏄�"瀹朵腑",浣跨敤鍖婚櫌璺濈璁$畻
@@ -550,6 +594,12 @@
console.log('杞叆鍖婚櫌鍙樺寲:', hospitalData)
// 缁勪欢宸茬粡閫氳繃 v-model 鏇存柊浜� taskForm.hospitalIn
+ // 濡傛灉閫夋嫨鐨勬槸"瀹朵腑"锛岃嚜鍔ㄨ缃瀹や负"鍏跺畠"
+ if (hospitalData.name === '瀹朵腑') {
+ this.taskForm.hospitalIn.department = '鍏跺畠'
+ this.taskForm.hospitalIn.departmentId = null
+ }
+
// 濡傛灉杞嚭鍦板潃宸插~鍐�,鑷姩璁$畻璺濈
if (this.taskForm.hospitalOut.address) {
// 濡傛灉涓や釜閮戒笉鏄�"瀹朵腑",浣跨敤鍖婚櫌璺濈璁$畻
@@ -569,6 +619,28 @@
}
},
+ // 杞嚭绉戝鍙樺寲
+ onHospitalOutDepartmentChange(data) {
+ if (data && typeof data === 'object') {
+ this.taskForm.hospitalOut.department = data.department
+ this.taskForm.hospitalOut.departmentId = data.departmentId
+ } else {
+ this.taskForm.hospitalOut.department = data
+ this.taskForm.hospitalOut.departmentId = null
+ }
+ },
+
+ // 杞叆绉戝鍙樺寲
+ onHospitalInDepartmentChange(data) {
+ if (data && typeof data === 'object') {
+ this.taskForm.hospitalIn.department = data.department
+ this.taskForm.hospitalIn.departmentId = data.departmentId
+ } else {
+ this.taskForm.hospitalIn.department = data
+ this.taskForm.hospitalIn.departmentId = null
+ }
+ },
+
// 鐥呮儏鍙樺寲
onDiseaseChange(diseases) {
console.log('鐥呮儏鍙樺寲:', diseases)
diff --git a/app/utils/taskValidator.js b/app/utils/taskValidator.js
new file mode 100644
index 0000000..c52bc0c
--- /dev/null
+++ b/app/utils/taskValidator.js
@@ -0,0 +1,226 @@
+/**
+ * 浠诲姟鏍¢獙宸ュ叿绫�
+ * 鐢ㄤ簬缁熶竴绠$悊浠诲姟鐩稿叧鐨勫墠缃牎楠岄�昏緫
+ */
+
+import request from '@/utils/request'
+
+/**
+ * 鏍¢獙浠诲姟鏄惁鍙互鎵ц鎿嶄綔锛堝嚭鍙戙�佺粨绠楃瓑锛�
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @param {Object} options - 鏍¢獙閫夐」
+ * @param {Boolean} options.checkAssignees - 鏄惁妫�鏌ユ墽琛屼汉鍛橈紝榛樿true
+ * @param {Boolean} options.checkVehicles - 鏄惁妫�鏌ヨ溅杈嗭紝榛樿true
+ * @param {Boolean} options.checkPlannedTime - 鏄惁妫�鏌ラ绾︽椂闂达紝榛樿true
+ * @returns {Object} { valid: Boolean, message: String, field: String }
+ */
+export function validateTaskForAction(task, options = {}) {
+ const {
+ checkAssignees = true,
+ checkVehicles = true,
+ checkPlannedTime = true
+ } = options
+
+ // 1. 妫�鏌ユ墽琛屼汉鍛�
+ if (checkAssignees) {
+ const assigneeResult = validateAssignees(task)
+ if (!assigneeResult.valid) {
+ return assigneeResult
+ }
+ }
+
+ // 2. 妫�鏌ヨ溅杈�
+ if (checkVehicles) {
+ const vehicleResult = validateVehicles(task)
+ if (!vehicleResult.valid) {
+ return vehicleResult
+ }
+ }
+
+ // 3. 妫�鏌ラ绾︽椂闂�
+ if (checkPlannedTime) {
+ const timeResult = validatePlannedTime(task)
+ if (!timeResult.valid) {
+ return timeResult
+ }
+ }
+
+ return { valid: true, message: '', field: '' }
+}
+
+/**
+ * 妫�鏌ヤ换鍔℃槸鍚﹀凡鍒嗛厤鎵ц浜哄憳
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Object} { valid: Boolean, message: String, field: String }
+ */
+export function validateAssignees(task) {
+ if (!task.assignees || task.assignees.length === 0) {
+ return {
+ valid: false,
+ message: '浠诲姟鏈垎閰嶆墽琛屼汉鍛�',
+ field: 'assignees'
+ }
+ }
+ return { valid: true, message: '', field: '' }
+}
+
+/**
+ * 妫�鏌ヤ换鍔℃槸鍚﹀凡鍒嗛厤杞﹁締
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Object} { valid: Boolean, message: String, field: String }
+ */
+export function validateVehicles(task) {
+ // 鏀寔涓ょ瀛楁鍚嶏細vehicleList 鍜� assignedVehicles
+ const vehicles = task.vehicleList || task.assignedVehicles
+
+ if (!vehicles || vehicles.length === 0) {
+ return {
+ valid: false,
+ message: '浠诲姟鏈垎閰嶈溅杈�',
+ field: 'vehicles'
+ }
+ }
+ return { valid: true, message: '', field: '' }
+}
+
+/**
+ * 妫�鏌ヤ换鍔¢绾︽椂闂存槸鍚︽湁鏁�
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Object} { valid: Boolean, message: String, field: String }
+ */
+export function validatePlannedTime(task) {
+ if (!task.plannedStartTime) {
+ return {
+ valid: false,
+ message: '浠诲姟鐨勮浆杩愭椂闂存湭璁剧疆',
+ field: 'plannedStartTime'
+ }
+ }
+
+ // 妫�鏌ユ槸鍚︿负鏃犳晥鏃堕棿锛�1900骞达級
+ if (task.plannedStartTime.startsWith('1900')) {
+ return {
+ valid: false,
+ message: '浠诲姟鐨勮浆杩愭椂闂存棤鏁�',
+ field: 'plannedStartTime'
+ }
+ }
+
+ return { valid: true, message: '', field: '' }
+}
+
+/**
+ * 鑾峰彇浠诲姟鐨勮溅杈咺D
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Number|null} 杞﹁締ID锛屾湭鎵惧埌杩斿洖null
+ */
+export function getTaskVehicleId(task) {
+ if (!task) {
+ return null
+ }
+
+ // 浠庤溅杈嗗垪琛ㄤ腑鑾峰彇绗竴涓溅杈嗙殑ID
+ const vehicles = task.assignedVehicles || task.vehicleList
+ if (vehicles && vehicles.length > 0) {
+ return vehicles[0].vehicleId
+ }
+
+ // 鎴栬�呬粠鍗曚釜杞﹁締瀵硅薄鑾峰彇
+ if (task.vehicleId) {
+ return task.vehicleId
+ }
+
+ return null
+}
+
+/**
+ * 鏍¢獙浠诲姟鏄惁鍙互鍑哄彂
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Object} { valid: Boolean, message: String, field: String }
+ */
+export function validateTaskForDepart(task) {
+ return validateTaskForAction(task, {
+ checkAssignees: true,
+ checkVehicles: true,
+ checkPlannedTime: true
+ })
+}
+
+/**
+ * 鏍¢獙浠诲姟鏄惁鍙互缁撶畻
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Object} { valid: Boolean, message: String, field: String }
+ */
+export function validateTaskForSettlement(task) {
+ return validateTaskForAction(task, {
+ checkAssignees: true,
+ checkVehicles: true,
+ checkPlannedTime: true
+ })
+}
+
+/**
+ * 妫�鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙戯紙璋冪敤鍚庣鎺ュ彛锛�
+ * 妫�鏌ワ細
+ * 1. 鍩烘湰鏍¢獙锛氳溅杈嗐�佹墽琛屼汉鍛樸�侀绾︽椂闂�
+ * 2. 杞﹁締鍐茬獊妫�鏌ワ細鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ * 3. 浜哄憳鍐茬獊妫�鏌ワ細鎵ц浜烘槸鍚︽湁鏈畬鎴愮殑浠诲姟
+ *
+ * @param {Object} task - 浠诲姟瀵硅薄
+ * @returns {Promise<Object>} { valid: Boolean, message: String, conflicts: Array }
+ */
+export async function checkTaskCanDepart(task) {
+ // 1. 鍏堣繘琛屽熀鏈牎楠�
+ const basicValidation = validateTaskForDepart(task)
+ if (!basicValidation.valid) {
+ return {
+ ...basicValidation,
+ conflicts: [] // 纭繚杩斿洖鐨勫璞″寘鍚玞onflicts瀛楁
+ }
+ }
+
+ // 2. 璋冪敤鍚庣鎺ュ彛妫�鏌ヨ溅杈嗗拰浜哄憳鍐茬獊
+ try {
+ const response = await request({
+ url: `/task/${task.taskId}/check-depart`,
+ method: 'get'
+ })
+
+ console.log('鍚庣杩斿洖鐨勫師濮嬫暟鎹�:', response)
+
+ if (response.code === 200 && response.data) {
+ const { valid, conflicts } = response.data
+
+ console.log('valid:', valid)
+ console.log('conflicts:', conflicts)
+
+ if (!valid && conflicts && conflicts.length > 0) {
+ // 鏈夊啿绐侊紝杩斿洖绗竴涓啿绐佷俊鎭�
+ return {
+ valid: false,
+ message: conflicts[0].message,
+ conflicts: conflicts
+ }
+ }
+
+ return { valid: true, message: '', conflicts: [] }
+ }
+
+ return { valid: false, message: '妫�鏌ュけ璐ワ紝璇烽噸璇�', conflicts: [] }
+ } catch (error) {
+ console.error('妫�鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙戝け璐�:', error)
+ // 鎺ュ彛澶辫触鏃讹紝鍙繘琛屽熀鏈牎楠岋紝鍏佽鍑哄彂
+ return { valid: true, message: '', conflicts: [] }
+ }
+}
+
+export default {
+ validateTaskForAction,
+ validateAssignees,
+ validateVehicles,
+ validatePlannedTime,
+ getTaskVehicleId,
+ validateTaskForDepart,
+ validateTaskForSettlement,
+ checkTaskCanDepart
+}
diff --git "a/prd/\350\275\254\350\277\220\344\273\273\345\212\241\347\212\266\346\200\201\345\217\230\346\233\264\350\256\260\345\275\225\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\350\275\254\350\277\220\344\273\273\345\212\241\347\212\266\346\200\201\345\217\230\346\233\264\350\256\260\345\275\225\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..8205519
--- /dev/null
+++ "b/prd/\350\275\254\350\277\220\344\273\273\345\212\241\347\212\266\346\200\201\345\217\230\346\233\264\350\256\260\345\275\225\345\220\214\346\255\245\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,397 @@
+# 杞繍浠诲姟鐘舵�佸彉鏇磋褰曞悓姝ュ埌鏃х郴缁熷姛鑳借鏄�
+
+## 涓�銆佸姛鑳芥杩�
+
+鏈姛鑳藉疄鐜颁簡鍦ㄨ浆杩愪换鍔$姸鎬佸彂鐢熷彉鏇存椂锛岃嚜鍔ㄥ皢鐘舵�佸彉鏇磋褰曞悓姝ュ埌SQL Server鏃х郴缁熺殑 `DispatchOrd_Running` 琛ㄤ腑銆傝鍔熻兘閫氳繃Spring浜嬩欢鐩戝惉鏈哄埗瀹炵幇锛岀‘淇濈姸鎬佸彉鏇寸殑瀹屾暣璁板綍鍜岃拷韪��
+
+## 浜屻�佹牳蹇冪粍浠�
+
+### 1. 鏁版嵁搴撹〃缁撴瀯
+
+**鏃х郴缁熻〃锛欴ispatchOrd_Running**锛圫QL Server锛�
+
+```sql
+create table DispatchOrd_Running(
+ id int comment "鑷涓婚敭",
+ DispatchOrdIDDt bigint comment '璋冨害鍗旾D',
+ DispatchOrdState int comment '鐘舵��',
+ DispatchOrdStartDate datetime comment '鐘舵�佹椂闂�',
+ DispatchOrdStartOA int comment '鎿嶄綔鐘舵�佺殑OA鐢ㄦ埛ID',
+ OA_latitude float comment '鏇存柊鐘舵�佹椂鐨勭含搴�',
+ OA_longitude float comment '鏇存柊鐘舵�佹椂鐨勭粡搴�',
+ OA_address nvarchar(400) comment '鏇存柊鐘舵�佹椂鐨勫湴鍧�'
+)
+```
+
+### 2. Mapper鎺ュ彛
+
+**LegacyTransferSyncMapper.java**
+
+鏂板鏂规硶锛�
+```java
+/**
+ * 鎻掑叆璋冨害鍗曠姸鎬佸彉鏇磋褰曞埌 DispatchOrd_Running 琛�
+ *
+ * @param dispatchOrdID 璋冨害鍗旾D
+ * @param dispatchOrdState 鐘舵�佺爜
+ * @param dispatchOrdStartDate 鐘舵�佹椂闂�
+ * @param dispatchOrdStartOA 鎿嶄綔鐘舵�佺殑OA鐢ㄦ埛ID
+ * @param oaLatitude 鏇存柊鐘舵�佹椂鐨勭含搴�
+ * @param oaLongitude 鏇存柊鐘舵�佹椂鐨勭粡搴�
+ * @param oaAddress 鏇存柊鐘舵�佹椂鐨勫湴鍧�
+ * @return 褰卞搷琛屾暟
+ */
+int insertDispatchOrdRunning(
+ @Param("dispatchOrdID") Long dispatchOrdID,
+ @Param("dispatchOrdState") Integer dispatchOrdState,
+ @Param("dispatchOrdStartDate") java.util.Date dispatchOrdStartDate,
+ @Param("dispatchOrdStartOA") Long dispatchOrdStartOA,
+ @Param("oaLatitude") Double oaLatitude,
+ @Param("oaLongitude") Double oaLongitude,
+ @Param("oaAddress") String oaAddress
+);
+```
+
+### 3. Mapper XML閰嶇疆
+
+**LegacyTransferSyncMapper.xml**
+
+```xml
+<!-- 鎻掑叆璋冨害鍗曠姸鎬佸彉鏇磋褰曞埌 DispatchOrd_Running 琛� -->
+<insert id="insertDispatchOrdRunning">
+ INSERT INTO DispatchOrd_Running (
+ DispatchOrdIDDt,
+ DispatchOrdState,
+ DispatchOrdStartDate,
+ DispatchOrdStartOA,
+ OA_latitude,
+ OA_longitude,
+ OA_address
+ ) VALUES (
+ #{dispatchOrdID},
+ #{dispatchOrdState},
+ #{dispatchOrdStartDate},
+ #{dispatchOrdStartOA},
+ #{oaLatitude},
+ #{oaLongitude},
+ #{oaAddress}
+ )
+</insert>
+```
+
+### 4. 浜嬩欢鐩戝惉鍣�
+
+**DispatchOrdRunningListener.java**
+
+- **浣嶇疆**: `ruoyi-system/src/main/java/com/ruoyi/system/listener/`
+- **鍔熻兘**: 鐩戝惉浠诲姟鐘舵�佸彉鏇翠簨浠讹紙TaskStatusChangedEvent锛夛紝鑷姩鍚屾鐘舵�佸彉鏇磋褰曞埌鏃х郴缁�
+- **鐗规��**:
+ - 鉁� **寮傛澶勭悊**: 浣跨敤 `@Async` 娉ㄨВ锛屼笉闃诲涓讳笟鍔℃祦绋�
+ - 鉁� **浜嬩欢鐩戝惉**: 浣跨敤 `@EventListener` 娉ㄨВ鐩戝惉鐘舵�佸彉鏇翠簨浠�
+ - 鉁� **鏅鸿兘杩囨护**: 鍙鐞嗘�ユ晳杞繍浠诲姟涓斿凡鍚屾鍒版棫绯荤粺鐨勪换鍔�
+ - 鉁� **鐘舵�佽浆鎹�**: 鑷姩灏嗘柊绯荤粺鐘舵�佽浆鎹负鏃х郴缁熺姸鎬佺爜
+ - 鉁� **GPS璁板綍**: 璁板綍鐘舵�佸彉鏇存椂鐨凣PS浣嶇疆鍜屽湴鍧�淇℃伅
+ - 鉁� **瀹归敊澶勭悊**: 寮傚父涓嶅奖鍝嶄富涓氬姟娴佺▼
+
+## 涓夈�佸伐浣滄祦绋�
+
+```mermaid
+graph TB
+ A[杞繍浠诲姟鐘舵�佸彉鏇碷 --> B[SysTaskServiceImpl.changeTaskStatus]
+ B --> C[鍙戝竷TaskStatusChangedEvent浜嬩欢]
+ C --> D[DispatchOrdRunningListener鐩戝惉]
+ D --> E{鏄惁鍚敤鏃х郴缁熷悓姝�?}
+ E -->|鍚 F[璺宠繃鍚屾]
+ E -->|鏄瘄 G{鏄惁鎬ユ晳杞繍浠诲姟?}
+ G -->|鍚 F
+ G -->|鏄瘄 H{璋冨害鍗曟槸鍚﹀凡鍚屾?}
+ H -->|鍚 F
+ H -->|鏄瘄 I[杞崲鐘舵�佺爜]
+ I --> J{鐘舵�侀渶瑕佸悓姝�?}
+ J -->|鍚 F
+ J -->|鏄瘄 K[鎻掑叆DispatchOrd_Running琛╙
+ K --> L[璁板綍鏃ュ織]
+```
+
+## 鍥涖�佺姸鎬佹槧灏勫叧绯�
+
+鏂扮郴缁熺姸鎬� 鈫� 鏃х郴缁熺姸鎬佺爜鏄犲皠锛�
+
+| 鏂扮郴缁熺姸鎬� | TaskStatus鏋氫妇 | 鏃х郴缁熺姸鎬佺爜 | 鏃х郴缁熺姸鎬佹弿杩� |
+|-----------|---------------|-------------|---------------|
+| 鍑哄彂涓� | DEPARTING | 4 | 宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛� |
+| 浠诲姟涓� | IN_PROGRESS | 6 | 宸插嚭杞︼紙鏈嶅姟涓級 |
+| 杩旂▼涓� | RETURNING | 7 | 宸查�佽揪锛堝洖绋嬩腑锛� |
+| 宸插畬鎴� | COMPLETED | 8 | 宸茶繑鍥� |
+| 宸插彇娑� | CANCELLED | 10 | 鍙栨秷 |
+| 寰呭鐞� | PENDING | - | 涓嶅悓姝� |
+| 宸插埌杈� | ARRIVED | - | 涓嶅悓姝� |
+
+## 浜斻�佸悓姝ユ潯浠�
+
+婊¤冻浠ヤ笅**鎵�鏈夋潯浠�**鏃舵墠浼氬悓姝ョ姸鎬佸彉鏇磋褰曪細
+
+1. 鉁� 鏃х郴缁熷悓姝ュ姛鑳藉凡鍚敤锛坄legacy.system.enabled=true`锛�
+2. 鉁� 浠诲姟绫诲瀷涓烘�ユ晳杞繍锛坄EMERGENCY_TRANSFER`锛�
+3. 鉁� 浠诲姟宸插悓姝ュ埌鏃х郴缁燂紙`legacy_dispatch_ord_id` 涓嶄负绌猴級
+4. 鉁� 鏂扮姸鎬侀渶瑕佸悓姝ュ埌鏃х郴缁燂紙鍙傝鐘舵�佹槧灏勮〃锛�
+
+## 鍏�佷娇鐢ㄧず渚�
+
+### 1. 鑷姩瑙﹀彂锛堟帹鑽愶級
+
+褰撹浆杩愪换鍔$姸鎬佸彂鐢熷彉鏇存椂锛岀郴缁熶細鑷姩瑙﹀彂鍚屾锛�
+
+```java
+// 鍦⊿ysTaskServiceImpl涓彉鏇寸姸鎬�
+sysTaskService.changeTaskStatus(taskId, TaskStatus.DEPARTING, "鍙告満宸插嚭鍙�");
+
+// 绯荤粺鑷姩锛�
+// 1. 鍙戝竷TaskStatusChangedEvent浜嬩欢
+// 2. DispatchOrdRunningListener鐩戝惉骞跺鐞�
+// 3. 鎻掑叆璁板綍鍒癉ispatchOrd_Running琛�
+```
+
+### 2. 鏃ュ織绀轰緥
+
+**鎴愬姛鍚屾鐨勬棩蹇�**锛�
+```
+2025-12-05 14:30:15 INFO DispatchOrdRunningListener - 鏀跺埌浠诲姟鐘舵�佸彉鏇翠簨浠讹紝鍑嗗鍚屾鍒癉ispatchOrd_Running锛屼换鍔D锛�1001锛屾棫鐘舵�侊細PENDING锛屾柊鐘舵�侊細DEPARTING
+2025-12-05 14:30:15 INFO DispatchOrdRunningListener - 寮�濮嬪悓姝ョ姸鎬佸彉鏇磋褰曞埌DispatchOrd_Running锛孌ispatchOrdID: 12345, 鐘舵�佺爜: 4, 鐘舵�佹弿杩�: 宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛�
+2025-12-05 14:30:15 INFO DispatchOrdRunningListener - 鐘舵�佸彉鏇磋褰曞凡鍚屾鍒癉ispatchOrd_Running锛孌ispatchOrdID: 12345, 鐘舵�佺爜: 4 (宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛�), GPS: [113.264385, 23.12911], 鍦板潃: 骞垮窞甯傝秺绉�鍖篨X璺疿X鍙�
+```
+
+**璺宠繃鍚屾鐨勬棩蹇�**锛�
+```
+2025-12-05 14:30:15 DEBUG DispatchOrdRunningListener - 璋冨害鍗曟湭鍚屾鍒版棫绯荤粺锛岃烦杩嘍ispatchOrd_Running鍚屾锛屼换鍔D: 1001
+```
+
+## 涓冦�佹暟鎹褰曞唴瀹�
+
+姣忔鐘舵�佸彉鏇翠細璁板綍浠ヤ笅淇℃伅锛�
+
+| 瀛楁 | 璇存槑 | 鏁版嵁鏉ユ簮 |
+|-----|------|---------|
+| DispatchOrdIDDt | 璋冨害鍗旾D | sys_task_emergency.legacy_dispatch_ord_id |
+| DispatchOrdState | 鐘舵�佺爜 | 浠庢柊绯荤粺TaskStatus杞崲鑰屾潵 |
+| DispatchOrdStartDate | 鐘舵�佹椂闂� | 褰撳墠鏃堕棿 |
+| DispatchOrdStartOA | 鎿嶄綔浜篒D | TaskStatusChangedEvent.creatorId |
+| OA_latitude | 绾害 | TaskStatusChangedEvent.latitude |
+| OA_longitude | 缁忓害 | TaskStatusChangedEvent.longitude |
+| OA_address | 鍦板潃 | TaskStatusChangedEvent.address |
+
+## 鍏�佺洃鎺у拰璋冭瘯
+
+### 1. 鏌ョ湅鐘舵�佸彉鏇磋褰�
+
+```sql
+-- SQL Server涓煡璇㈡渶杩戠殑鐘舵�佸彉鏇磋褰�
+SELECT TOP 20
+ DispatchOrdIDDt,
+ DispatchOrdState,
+ DispatchOrdStartDate,
+ DispatchOrdStartOA,
+ OA_latitude,
+ OA_longitude,
+ OA_address
+FROM DispatchOrd_Running
+ORDER BY DispatchOrdStartDate DESC
+```
+
+### 2. 鏌ヨ鐗瑰畾璋冨害鍗曠殑鐘舵�佸彉鏇村巻鍙�
+
+```sql
+-- 鏌ヨ鏌愪釜璋冨害鍗曠殑鎵�鏈夌姸鎬佸彉鏇磋褰�
+SELECT
+ DispatchOrdState,
+ DispatchOrdStartDate,
+ OA_latitude,
+ OA_longitude,
+ OA_address
+FROM DispatchOrd_Running
+WHERE DispatchOrdIDDt = 12345
+ORDER BY DispatchOrdStartDate DESC
+```
+
+### 3. 缁熻浠婃棩鐘舵�佸彉鏇存鏁�
+
+```sql
+-- 缁熻浠婃棩鍚勭姸鎬佺殑鍙樻洿娆℃暟
+SELECT
+ DispatchOrdState,
+ CASE DispatchOrdState
+ WHEN 4 THEN '宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛�'
+ WHEN 6 THEN '宸插嚭杞︼紙鏈嶅姟涓級'
+ WHEN 7 THEN '宸查�佽揪锛堝洖绋嬩腑锛�'
+ WHEN 8 THEN '宸茶繑鍥�'
+ WHEN 10 THEN '鍙栨秷'
+ ELSE '鍏朵粬'
+ END AS StateName,
+ COUNT(*) AS ChangeCount
+FROM DispatchOrd_Running
+WHERE CONVERT(DATE, DispatchOrdStartDate) = CONVERT(DATE, GETDATE())
+GROUP BY DispatchOrdState
+ORDER BY DispatchOrdState
+```
+
+## 涔濄�佹灦鏋勪紭鍔�
+
+### 1. 瀹屽叏瑙h��
+- 涓氬姟閫昏緫涓庡悓姝ラ�昏緫鍒嗙
+- 鐘舵�佸彉鏇翠笉渚濊禆鏃х郴缁熷悓姝ョ粨鏋�
+- 鍙嫭绔嬫祴璇曞拰缁存姢
+
+### 2. 寮傛澶勭悊
+- 涓嶉樆濉炰富涓氬姟娴佺▼
+- 鎻愰珮绯荤粺鍝嶅簲閫熷害
+- 瀹归敊鑳藉姏寮�
+
+### 3. 鑷姩鍖�
+- 鏃犻渶鎵嬪姩瑙﹀彂
+- 瀹炴椂鍚屾鐘舵�佸彉鏇�
+- 鍑忓皯浜哄伐鎿嶄綔
+
+### 4. 鍙拷婧��
+- 瀹屾暣璁板綍姣忔鐘舵�佸彉鏇�
+- 鍖呭惈GPS浣嶇疆淇℃伅
+- 渚夸簬闂鎺掓煡鍜屽璁�
+
+## 鍗併�佹敞鎰忎簨椤�
+
+### 1. 鏁版嵁婧愰厤缃�
+
+纭繚 `LegacyTransferSyncMapper` 浣跨敤SQL Server鏁版嵁婧愶細
+```java
+@DataSource(DataSourceType.SQLSERVER)
+public interface LegacyTransferSyncMapper {
+ // ...
+}
+```
+
+### 2. 寮傛绾跨▼姹�
+
+寮傛澶勭悊渚濊禆绾跨▼姹犻厤缃紙AsyncConfig.java锛夛細
+```java
+@Configuration
+@EnableAsync
+public class AsyncConfig {
+ @Bean(name = "taskExecutor")
+ public Executor taskExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(5);
+ executor.setMaxPoolSize(10);
+ executor.setQueueCapacity(100);
+ // ...
+ }
+}
+```
+
+### 3. 寮傚父澶勭悊
+
+鐩戝惉鍣ㄤ腑鐨勫紓甯镐笉浼氬奖鍝嶄富涓氬姟锛�
+- 璁板綍璇︾粏鏃ュ織
+- 涓嶆姏鍑哄紓甯�
+- 涓嶅奖鍝嶇姸鎬佸彉鏇存搷浣�
+
+### 4. 鎬ц兘浼樺寲
+
+- 浣跨敤 `@Async` 寮傛澶勭悊
+- 鍙悓姝ュ繀瑕佺殑鐘舵�佸彉鏇�
+- 鏅鸿兘杩囨护涓嶉渶瑕佸悓姝ョ殑浠诲姟
+
+## 鍗佷竴銆佹祴璇曢獙璇�
+
+### 1. 娴嬭瘯姝ラ
+
+**姝ラ1锛氬垱寤哄苟鍚屾杞繍浠诲姟**
+```java
+// 鍒涘缓鎬ユ晳杞繍浠诲姟
+Long taskId = sysTaskService.insertSysTask(createVO);
+
+// 纭繚浠诲姟宸插悓姝ュ埌鏃х郴缁�
+legacySystemSyncService.syncDispatchOrderToLegacy(taskId);
+```
+
+**姝ラ2锛氬彉鏇翠换鍔$姸鎬�**
+```java
+// 鍙樻洿鐘舵�佷负"鍑哄彂涓�"
+sysTaskService.changeTaskStatus(taskId, TaskStatus.DEPARTING, "鍙告満宸插嚭鍙�");
+```
+
+**姝ラ3锛氶獙璇丼QL Server璁板綍**
+```sql
+-- 鏌ヨDispatchOrd_Running琛�
+SELECT * FROM DispatchOrd_Running
+WHERE DispatchOrdIDDt = (
+ SELECT legacy_dispatch_ord_id
+ FROM sys_task_emergency
+ WHERE task_id = ?
+)
+ORDER BY DispatchOrdStartDate DESC
+```
+
+### 2. 棰勬湡缁撴灉
+
+| 娴嬭瘯鍦烘櫙 | 棰勬湡缁撴灉 |
+|---------|---------|
+| 鎬ユ晳杞繍浠诲姟鐘舵�佸彉鏇� | 鎻掑叆璁板綍鍒癉ispatchOrd_Running |
+| 闈炴�ユ晳杞繍浠诲姟鐘舵�佸彉鏇� | 涓嶆彃鍏ヨ褰� |
+| 鏈悓姝ョ殑浠诲姟鐘舵�佸彉鏇� | 涓嶆彃鍏ヨ褰� |
+| 涓嶉渶瑕佸悓姝ョ殑鐘舵�侊紙PENDING锛� | 涓嶆彃鍏ヨ褰� |
+| 鏃х郴缁熷悓姝ュ凡绂佺敤 | 涓嶆彃鍏ヨ褰� |
+
+## 鍗佷簩銆佺浉鍏虫枃浠舵竻鍗�
+
+### 鏂板鏂囦欢
+- `DispatchOrdRunningListener.java` - 鐘舵�佸彉鏇寸洃鍚櫒
+
+### 淇敼鏂囦欢
+- `LegacyTransferSyncMapper.java` - 娣诲姞insertDispatchOrdRunning鏂规硶
+- `LegacyTransferSyncMapper.xml` - 娣诲姞鎻掑叆SQL
+
+### 渚濊禆鏂囦欢锛堟棤闇�淇敼锛�
+- `SysTaskServiceImpl.java` - 鍙戝竷鐘舵�佸彉鏇翠簨浠�
+- `TaskStatusChangedEvent.java` - 鐘舵�佸彉鏇翠簨浠�
+- `TaskStatusPushConverter.java` - 鐘舵�佽浆鎹㈠伐鍏�
+- `DispatchRunning.sql` - 鏁版嵁搴撹〃缁撴瀯瀹氫箟
+
+## 鍗佷笁銆佹晠闅滄帓鏌�
+
+### 闂1锛氱姸鎬佸彉鏇存病鏈夊悓姝ュ埌鏃х郴缁�
+
+**鎺掓煡姝ラ**锛�
+1. 妫�鏌ユ棫绯荤粺鍚屾鏄惁鍚敤锛歚legacy.system.enabled=true`
+2. 妫�鏌ヤ换鍔℃槸鍚︿负鎬ユ晳杞繍浠诲姟
+3. 妫�鏌ヨ皟搴﹀崟鏄惁宸插悓姝ワ細`legacy_dispatch_ord_id` 涓嶄负绌�
+4. 鏌ョ湅鏃ュ織纭鏄惁鏈夊紓甯�
+5. 妫�鏌ョ姸鎬佹槸鍚﹂渶瑕佸悓姝ワ紙鍙傝�冪姸鎬佹槧灏勮〃锛�
+
+### 闂2锛氭棩蹇椾腑鍑虹幇寮傚父
+
+**甯歌鍘熷洜**锛�
+- SQL Server杩炴帴澶辫触
+- 鏁版嵁婧愰厤缃敊璇�
+- 瀛楁绫诲瀷涓嶅尮閰�
+
+**瑙e喅鏂规硶**锛�
+- 妫�鏌ユ暟鎹簮閰嶇疆
+- 楠岃瘉SQL Server杩炴帴
+- 鏌ョ湅璇︾粏閿欒鏃ュ織
+
+### 闂3锛氭�ц兘闂
+
+**浼樺寲寤鸿**锛�
+- 璋冩暣绾跨▼姹犻厤缃�
+- 妫�鏌QL Server鎬ц兘
+- 浼樺寲鏁版嵁搴撶储寮�
+
+## 鍗佸洓銆佹�荤粨
+
+鏈姛鑳介�氳繃Spring浜嬩欢椹卞姩鏈哄埗锛屽疄鐜颁簡杞繍浠诲姟鐘舵�佸彉鏇磋褰曞埌鏃х郴缁熺殑鑷姩鍚屾锛屽叿鏈変互涓嬬壒鐐癸細
+
+- 鉁� **鑷姩鍖�**锛氱姸鎬佸彉鏇磋嚜鍔ㄥ悓姝ワ紝鏃犻渶鎵嬪姩鎿嶄綔
+- 鉁� **瑙h��**锛氫笟鍔¢�昏緫涓庡悓姝ラ�昏緫瀹屽叏鍒嗙
+- 鉁� **寮傛**锛氫笉褰卞搷涓讳笟鍔℃�ц兘
+- 鉁� **瀹屾暣**锛氳褰旼PS浣嶇疆绛夎缁嗕俊鎭�
+- 鉁� **鍙潬**锛氬閿欏鐞嗭紝寮傚父涓嶅奖鍝嶄富娴佺▼
+- 鉁� **鍙拷婧�**锛氬畬鏁寸殑鐘舵�佸彉鏇村巻鍙茶褰�
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 30081ad..fb8d9c0 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
@@ -1,7 +1,11 @@
package com.ruoyi.web.controller.task;
import java.util.List;
+import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.system.service.*;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -16,6 +20,8 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.SysTask;
import com.ruoyi.system.domain.SysTaskLog;
@@ -25,10 +31,9 @@
import com.ruoyi.system.domain.vo.TaskUpdateVO;
import com.ruoyi.system.domain.vo.TaskStatisticsVO;
import com.ruoyi.system.domain.enums.TaskStatus;
-import com.ruoyi.system.service.ISysTaskService;
-import com.ruoyi.system.service.IVehicleInfoService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.StringUtils;
/**
* 浠诲姟绠$悊Controller
@@ -45,6 +50,17 @@
@Autowired
private IVehicleInfoService vehicleInfoService;
+
+ @Autowired
+ private ISysUserService userService;
+
+ @Autowired
+ private ISysDeptService deptService;
+
+
+ @Autowired
+ @Qualifier("tiandituMapService")
+ private IMapService mapService;
/**
* 鏌ヨ浠诲姟绠$悊鍒楄〃锛堝悗鍙扮鐞嗙锛�
@@ -60,21 +76,52 @@
/**
* 鏌ヨ浠诲姟鍒楄〃锛圓PP绔級
- * 浠呮樉绀哄綋鍓嶇敤鎴风浉鍏崇殑浠诲姟锛�
- * 1. 褰撳墠鐢ㄦ埛鎵�鍦ㄦ満鏋勭殑浠诲姟
- * 2. 褰撳墠鐢ㄦ埛鍒涘缓鐨勪换鍔�
- * 3. 鍒嗛厤缁欏綋鍓嶇敤鎴风殑浠诲姟
+ * 鏍规嵁鐢ㄦ埛鏉冮檺杩斿洖涓嶅悓鑼冨洿鐨勪换鍔★細
+ * 1. 鏈夋煡鐪嬫墍鏈夊挩璇㈠崟鏉冮檺锛坈anViewAllConsult='1'锛夛細杩斿洖璇ョ敤鎴风鐞嗘墍鏈夊垎鍏徃涓嬬殑鎵�鏈変换鍔″崟
+ * 2. 鏃犳潈闄愶紙canViewAllConsult='0'锛夛細鍙繑鍥炲垎閰嶇粰璇ョ敤鎴风殑鍗曟垨璇ョ敤鎴峰垱寤虹殑鍗�
*/
@GetMapping("/list")
public TableDataInfo appList(TaskQueryVO queryVO) {
- // 鍦ㄥ悗绔嚜鍔ㄨ幏鍙栧綋鍓嶇敤鎴蜂俊鎭紝瀹炵幇缁煎悎鏌ヨ
+ // 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅
Long currentUserId = getUserId();
- Long currentDeptId = getDeptId();
+ SysUser currentUser = userService.selectUserById(currentUserId);
- // APP绔己鍒朵娇鐢ㄥ綋鍓嶇櫥褰曠敤鎴蜂俊鎭繘琛岃繃婊�
- queryVO.setDeptId(currentDeptId);
- queryVO.setCreatorId(currentUserId);
- queryVO.setAssigneeId(currentUserId);
+ if (currentUser == null) {
+ return getDataTable(new java.util.ArrayList<>());
+ }
+
+ // 鍒ゆ柇鐢ㄦ埛鏄惁鏈夋煡鐪嬫墍鏈夊挩璇㈠崟鐨勬潈闄�
+ String canViewAllConsult = currentUser.getCanViewAllConsult();
+
+ if ("1".equals(canViewAllConsult)) {
+ // 鏈夋潈闄愶細杩斿洖璇ョ敤鎴风鐞嗘墍鏈夊垎鍏徃涓嬬殑鎵�鏈変换鍔″崟
+ // 1. 鑾峰彇鐢ㄦ埛绠$悊鐨勫垎鍏徃鍒楄〃
+ List<SysDept> branchCompanies = deptService.computeBranchCompaniesForUser(currentUser);
+
+ if (branchCompanies != null && !branchCompanies.isEmpty()) {
+ // 2. 鎻愬彇鎵�鏈夊垎鍏徃ID
+ List<Long> deptIds = new java.util.ArrayList<>();
+ for (SysDept dept : branchCompanies) {
+ deptIds.add(dept.getDeptId());
+ }
+
+ // 3. 璁剧疆鏌ヨ鏉′欢涓哄垎鍏徃ID鍒楄〃锛圫QL浼氳嚜鍔ㄥ寘鍚墍鏈夊瓙閮ㄩ棬锛�
+ queryVO.setDeptIds(deptIds);
+ // 娓呯┖鍒涘缓浜哄拰鎵ц浜鸿繃婊ゆ潯浠讹紝杩斿洖杩欎簺鍒嗗叕鍙镐笅鐨勬墍鏈変换鍔�
+ queryVO.setCreatorId(null);
+ queryVO.setAssigneeId(null);
+ } else {
+ // 濡傛灉娌℃湁鎵惧埌鍒嗗叕鍙革紝杩斿洖绌哄垪琛�
+ return getDataTable(new java.util.ArrayList<>());
+ }
+ } else {
+ // 鏃犳潈闄愶細鍙繑鍥炲垎閰嶇粰璇ョ敤鎴风殑鍗曟垨璇ョ敤鎴峰垱寤虹殑鍗�
+ // 娓呯┖deptId鍜宒eptIds锛屼娇鐢╟reatorId鍜宎ssigneeId杩涜OR鏌ヨ
+ queryVO.setDeptId(null);
+ queryVO.setDeptIds(null);
+ queryVO.setCreatorId(currentUserId);
+ queryVO.setAssigneeId(currentUserId);
+ }
startPage();
List<SysTask> list = sysTaskService.selectSysTaskList(queryVO);
@@ -214,6 +261,8 @@
// 濡傛灉鍖呭惈GPS浣嶇疆淇℃伅锛屼娇鐢ㄥ甫浣嶇疆鐨勬柟娉�
if (request.getLatitude() != null && request.getLongitude() != null) {
+ String address= mapService.reverseGeocoding(request.getLongitude(), request.getLatitude());
+ request.setLocationAddress(address);
SysTaskLog locationLog = new SysTaskLog();
locationLog.setLatitude(request.getLatitude());
locationLog.setLongitude(request.getLongitude());
@@ -225,10 +274,10 @@
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()));
}
@@ -290,6 +339,20 @@
}
/**
+ * 妫�鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙戯紙APP绔級
+ * 妫�鏌ワ細
+ * 1. 杞﹁締鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ * 2. 鎵ц浜哄憳鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ *
+ * @param taskId 浠诲姟ID
+ * @return 鏍¢獙缁撴灉
+ */
+ @GetMapping("/{taskId}/check-depart")
+ public AjaxResult checkTaskCanDepart(@PathVariable Long taskId) {
+ return sysTaskService.checkTaskCanDepart(taskId);
+ }
+
+ /**
* 鍒嗛厤浠诲姟璇锋眰瀵硅薄
*/
public static class AssignTaskRequest {
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index b039b84..8ab857f 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -58,7 +58,7 @@
basename: i18n/messages
profiles:
# 鐜 dev|test|prod
- active: prod
+ active: dev
# 鏂囦欢涓婁紶
servlet:
multipart:
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 c2c48c6..b08d680 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
@@ -103,6 +103,10 @@
/** 寰俊鏄电О */
private String wechatNickname;
+
+ /** 鏄惁鍙煡鐪嬫墍鏈夊挩璇㈠崟锛�0鍚� 1鏄級 */
+ @Excel(name = "鍙煡鐪嬫墍鏈夊挩璇㈠崟", readConverterExp = "0=鍚�,1=鏄�")
+ private String canViewAllConsult;
@@ -364,6 +368,15 @@
this.wechatNickname = wechatNickname;
}
+ public String getCanViewAllConsult()
+ {
+ return canViewAllConsult;
+ }
+
+ public void setCanViewAllConsult(String canViewAllConsult)
+ {
+ this.canViewAllConsult = canViewAllConsult;
+ }
@Override
@@ -393,6 +406,7 @@
.append("openId", getOpenId())
.append("unionId", getUnionId())
.append("wechatNickname", getWechatNickname())
+ .append("canViewAllConsult", getCanViewAllConsult())
.toString();
}
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
index 79db005..d0d840c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
@@ -22,6 +22,9 @@
/** 鐢ㄦ埛鍙敤鍒嗗叕鍙哥紪鐮佸垪琛紙鏉ユ簮浜嶰A_User.OA_OrderClass锛� */
private String oaOrderClass;
+
+ /** 鏄惁鍙煡鐪嬫墍鏈夊挩璇㈠崟锛�0鍚� 1鏄級 */
+ private String canViewAllConsult;
/** 鐢ㄦ埛鎬у埆锛�0=鐢�,1=濂�,2=鏈煡锛� */
private String sex;
@@ -111,6 +114,16 @@
{
this.oaOrderClass = oaOrderClass;
}
+
+ public String getCanViewAllConsult()
+ {
+ return canViewAllConsult;
+ }
+
+ public void setCanViewAllConsult(String canViewAllConsult)
+ {
+ this.canViewAllConsult = canViewAllConsult;
+ }
@Override
public String toString()
@@ -124,6 +137,7 @@
", email='" + email + '\'' +
", phonenumber='" + phonenumber + '\'' +
", oaOrderClass='" + oaOrderClass + '\'' +
+ ", canViewAllConsult='" + canViewAllConsult + '\'' +
'}';
}
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java
index 6736fee..d899481 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.domain.vo;
import java.util.Date;
+import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
@@ -33,6 +34,9 @@
/** 褰掑睘閮ㄩ棬ID */
private Long deptId;
+
+ /** 褰掑睘閮ㄩ棬ID鍒楄〃锛堢敤浜庢煡璇㈠涓垎鍏徃鐨勪换鍔★級 */
+ private List<Long> deptIds;
/** 璁″垝寮�濮嬫椂闂�-寮�濮� */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@@ -108,6 +112,14 @@
public void setDeptId(Long deptId) {
this.deptId = deptId;
}
+
+ public List<Long> getDeptIds() {
+ return deptIds;
+ }
+
+ public void setDeptIds(List<Long> deptIds) {
+ this.deptIds = deptIds;
+ }
public Date getPlannedStartTimeBegin() {
return plannedStartTimeBegin;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskStatusChangedEvent.java b/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskStatusChangedEvent.java
index 81708b8..1df49e3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskStatusChangedEvent.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskStatusChangedEvent.java
@@ -1,5 +1,8 @@
package com.ruoyi.system.event;
+import lombok.Data;
+
+import java.math.BigDecimal;
import java.util.List;
/**
@@ -8,6 +11,7 @@
* @author ruoyi
* @date 2025-10-25
*/
+
public class TaskStatusChangedEvent extends TaskEvent {
private static final long serialVersionUID = 1L;
@@ -30,10 +34,18 @@
/** 鍒涘缓浜篒D */
private Long creatorId;
+ private Double longitude;
+
+ /** 绾害 */
+ private Double latitude;
+
+ private String address;
+
public TaskStatusChangedEvent(Object source, Long taskId, String taskCode,
String oldStatus, String newStatus,
String oldStatusDesc, String newStatusDesc,
- List<Long> assigneeIds, Long creatorId) {
+ List<Long> assigneeIds, Long creatorId,Long operationId, Double longitude,
+ Double latitude,String address) {
super(source, taskId, taskCode);
this.oldStatus = oldStatus;
this.newStatus = newStatus;
@@ -41,8 +53,32 @@
this.newStatusDesc = newStatusDesc;
this.assigneeIds = assigneeIds;
this.creatorId = creatorId;
+ this.longitude = longitude;
+ this.latitude = latitude;
+ this.address = address;
+ this.setOperatorId(operationId);
}
+
+
+ public Double getLongitude() {
+ return longitude;
+ }
+ public void setLongitude(Double longitude) {
+ this.longitude = longitude;
+ }
+ public Double getLatitude() {
+ return latitude;
+ }
+ public void setLatitude(Double latitude) {
+ this.latitude = latitude;
+ }
+ public String getAddress() {
+ return address;
+ }
+ public void setAddress(String address) {
+ this.address = address;
+ }
public String getOldStatus() {
return oldStatus;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/listener/DispatchOrdRunningListener.java b/ruoyi-system/src/main/java/com/ruoyi/system/listener/DispatchOrdRunningListener.java
new file mode 100644
index 0000000..861d5a9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/listener/DispatchOrdRunningListener.java
@@ -0,0 +1,195 @@
+package com.ruoyi.system.listener;
+
+import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.SysTaskEmergency;
+import com.ruoyi.system.domain.enums.TaskStatus;
+import com.ruoyi.system.event.TaskStatusChangedEvent;
+import com.ruoyi.system.mapper.LegacyTransferSyncMapper;
+import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
+import com.ruoyi.system.mapper.SysTaskMapper;
+import com.ruoyi.system.mapper.SysUserMapper;
+import com.ruoyi.system.utils.TaskStatusPushConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+
+/**
+ * 璋冨害鍗曠姸鎬佸彉鏇磋褰曠洃鍚櫒
+ * 鐩戝惉浠诲姟鐘舵�佸彉鏇翠簨浠讹紝骞跺皢鐘舵�佸彉鏇磋褰曞悓姝ュ埌SQL Server鐨凞ispatchOrd_Running琛�
+ *
+ * @author ruoyi
+ * @date 2025-12-05
+ */
+@Component
+public class DispatchOrdRunningListener {
+
+ private static final Logger log = LoggerFactory.getLogger(DispatchOrdRunningListener.class);
+
+ @Autowired
+ private LegacySystemConfig legacyConfig;
+
+ @Autowired
+ private SysTaskMapper sysTaskMapper;
+
+ @Autowired
+ private SysTaskEmergencyMapper sysTaskEmergencyMapper;
+
+ @Autowired
+ private LegacyTransferSyncMapper legacyTransferSyncMapper;
+
+ @Autowired
+ private SysUserMapper sysUserMapper;
+
+ /**
+ * 鐩戝惉浠诲姟鐘舵�佸彉鏇翠簨浠�
+ *
+ * @param event 浠诲姟鐘舵�佸彉鏇翠簨浠�
+ */
+ @Async
+ @EventListener
+ public void handleTaskStatusChangedEvent(TaskStatusChangedEvent event) {
+ try {
+ log.info("鏀跺埌浠诲姟鐘舵�佸彉鏇翠簨浠讹紝鍑嗗鍚屾鍒癉ispatchOrd_Running锛屼换鍔D锛歿}锛屾棫鐘舵�侊細{}锛屾柊鐘舵�侊細{}",
+ event.getTaskId(), event.getOldStatus(), event.getNewStatus());
+
+ // 妫�鏌ユ棫绯荤粺鍚屾鏄惁鍚敤
+ if (!legacyConfig.isEnabled()) {
+ log.debug("鏃х郴缁熷悓姝ュ凡绂佺敤锛岃烦杩嘍ispatchOrd_Running鍚屾锛屼换鍔D: {}", event.getTaskId());
+ return;
+ }
+
+ // 鏌ヨ浠诲姟淇℃伅
+ SysTask task = sysTaskMapper.selectSysTaskByTaskId(event.getTaskId());
+ if (task == null) {
+ log.error("浠诲姟涓嶅瓨鍦紝浠诲姟ID: {}", event.getTaskId());
+ return;
+ }
+
+ // 鍙鐞嗘�ユ晳杞繍浠诲姟
+ if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+ log.debug("闈炴�ユ晳杞繍浠诲姟锛岃烦杩嘍ispatchOrd_Running鍚屾锛屼换鍔D: {}", event.getTaskId());
+ return;
+ }
+
+ // 鏌ヨ鎬ユ晳杞繍鎵╁睍淇℃伅
+ SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(event.getTaskId());
+ if (emergency == null) {
+ log.error("鎬ユ晳杞繍鎵╁睍淇℃伅涓嶅瓨鍦紝浠诲姟ID: {}", event.getTaskId());
+ return;
+ }
+
+ // 蹇呴』宸茬粡鍚屾杩囪皟搴﹀崟
+ if (emergency.getLegacyDispatchOrdId() == null || emergency.getLegacyDispatchOrdId() <= 0) {
+ log.debug("璋冨害鍗曟湭鍚屾鍒版棫绯荤粺锛岃烦杩嘍ispatchOrd_Running鍚屾锛屼换鍔D: {}", event.getTaskId());
+ return;
+ }
+
+ // 鑾峰彇鏂扮郴缁熺姸鎬�
+ TaskStatus newTaskStatus = TaskStatus.getByCode(event.getNewStatus());
+ if (newTaskStatus == null) {
+ log.error("鏃犳晥鐨勪换鍔$姸鎬侊紝浠诲姟ID: {}, 鐘舵�佺爜: {}", event.getTaskId(), event.getNewStatus());
+ return;
+ }
+
+ SysUser user= sysUserMapper.selectUserById(event.getOperatorId());
+ if(user==null){
+ log.error("鎿嶄綔浜轰笉瀛樺湪锛屼换鍔D: {}, 鎿嶄綔浜篒D: {}", event.getTaskId(), event.getOperatorId());
+ return;
+ }
+ Integer oaUserId=user.getOaUserId();
+
+ // 杞崲涓烘棫绯荤粺鐘舵�佺爜
+ Integer legacyStatusCode = TaskStatusPushConverter.convertToLegacyStatus(newTaskStatus);
+ if (legacyStatusCode == null) {
+ log.debug("浠诲姟鐘舵�佷笉闇�瑕佸悓姝ュ埌鏃х郴缁燂紝浠诲姟ID: {}, 鐘舵��: {}",
+ event.getTaskId(), newTaskStatus.getInfo());
+ return;
+ }
+
+ // 鎻掑叆鐘舵�佸彉鏇磋褰曞埌DispatchOrd_Running琛�
+ syncDispatchOrdRunning(
+ emergency.getLegacyDispatchOrdId(),
+ legacyStatusCode,
+ new Date(), // 浣跨敤褰撳墠鏃堕棿浣滀负鐘舵�佸彉鏇存椂
+ oaUserId.longValue(),
+ event.getLatitude(),
+ event.getLongitude(),
+ event.getAddress()
+ );
+
+ } catch (Exception e) {
+ log.error("澶勭悊浠诲姟鐘舵�佸彉鏇翠簨浠跺苟鍚屾鍒癉ispatchOrd_Running澶辫触锛屼换鍔D: {}", event.getTaskId(), e);
+ // 涓嶆姏鍑哄紓甯革紝閬垮厤褰卞搷涓绘祦绋�
+ }
+ }
+
+ /**
+ * 鍚屾鐘舵�佸彉鏇磋褰曞埌DispatchOrd_Running琛�
+ *
+ * @param dispatchOrdId 璋冨害鍗旾D
+ * @param statusCode 鐘舵�佺爜
+ * @param statusTime 鐘舵�佹椂闂�
+ * @param operatorId 鎿嶄綔浜篒D
+ * @param latitude 绾害
+ * @param longitude 缁忓害
+ * @param address 鍦板潃
+ */
+ private void syncDispatchOrdRunning(Long dispatchOrdId, Integer statusCode,
+ Date statusTime, Long operatorId,
+ Double latitude, Double longitude, String address) {
+ try {
+ // 鍒ゆ柇鏄惁鏈塆PS淇℃伅
+ boolean hasGps = (latitude != null && longitude != null);
+ if (hasGps) {
+ log.info("寮�濮嬪悓姝ョ姸鎬佸彉鏇磋褰曞埌DispatchOrd_Running锛孌ispatchOrdID: {}, 鐘舵�佺爜: {} ({}), GPS: [{}, {}]",
+ dispatchOrdId, statusCode, TaskStatusPushConverter.getLegacyStatusDescription(statusCode),
+ latitude, longitude);
+ } else {
+ log.info("寮�濮嬪悓姝ョ姸鎬佸彉鏇磋褰曞埌DispatchOrd_Running锛孌ispatchOrdID: {}, 鐘舵�佺爜: {} ({}), 鏃燝PS淇℃伅",
+ dispatchOrdId, statusCode, TaskStatusPushConverter.getLegacyStatusDescription(statusCode));
+ }
+
+ // 璋冪敤Mapper鎻掑叆璁板綍
+ int rows = legacyTransferSyncMapper.insertDispatchOrdRunning(
+ dispatchOrdId,
+ statusCode,
+ statusTime,
+ operatorId,
+ latitude,
+ longitude,
+ address
+ );
+
+ if (rows > 0) {
+ if (hasGps) {
+ log.info("鐘舵�佸彉鏇磋褰曞凡鍚屾鍒癉ispatchOrd_Running锛孌ispatchOrdID: {}, 鐘舵�佺爜: {} ({}), GPS: [{}, {}], 鍦板潃: {}",
+ dispatchOrdId,
+ statusCode,
+ TaskStatusPushConverter.getLegacyStatusDescription(statusCode),
+ latitude,
+ longitude,
+ address != null ? address : "鏃�");
+ } else {
+ log.info("鐘舵�佸彉鏇磋褰曞凡鍚屾鍒癉ispatchOrd_Running锛孌ispatchOrdID: {}, 鐘舵�佺爜: {} ({}), 鏃燝PS淇℃伅",
+ dispatchOrdId,
+ statusCode,
+ TaskStatusPushConverter.getLegacyStatusDescription(statusCode));
+ }
+ } else {
+ log.warn("鍚屾鐘舵�佸彉鏇磋褰曞け璐ワ紝鏈彃鍏ユ暟鎹紝DispatchOrdID: {}", dispatchOrdId);
+ }
+
+ } catch (Exception e) {
+ log.error("鍚屾鐘舵�佸彉鏇磋褰曞埌DispatchOrd_Running寮傚父锛孌ispatchOrdID: {}, 鐘舵�佺爜: {}",
+ dispatchOrdId, statusCode, e);
+ // 涓嶆姏鍑哄紓甯革紝閬垮厤褰卞搷涓绘祦绋�
+ }
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java b/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
index 87a04f4..c46d1d8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
@@ -92,6 +92,8 @@
}
}
+
+
/**
* 鐩戝惉浠诲姟鍒嗛厤浜嬩欢
*
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
index 4112657..89fa80b 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
@@ -73,4 +73,26 @@
* @return 绉戝鍚嶇О
*/
String selectDepartmentNameByDeptID(@Param("deptID") String deptID);
+
+ /**
+ * 鎻掑叆璋冨害鍗曠姸鎬佸彉鏇磋褰曞埌 DispatchOrd_Running 琛�
+ *
+ * @param dispatchOrdID 璋冨害鍗旾D
+ * @param dispatchOrdState 鐘舵�佺爜
+ * @param dispatchOrdStartDate 鐘舵�佹椂闂�
+ * @param dispatchOrdStartOA 鎿嶄綔鐘舵�佺殑OA鐢ㄦ埛ID
+ * @param oaLatitude 鏇存柊鐘舵�佹椂鐨勭含搴�
+ * @param oaLongitude 鏇存柊鐘舵�佹椂鐨勭粡搴�
+ * @param oaAddress 鏇存柊鐘舵�佹椂鐨勫湴鍧�
+ * @return 褰卞搷琛屾暟
+ */
+ int insertDispatchOrdRunning(
+ @Param("dispatchOrdID") Long dispatchOrdID,
+ @Param("dispatchOrdState") Integer dispatchOrdState,
+ @Param("dispatchOrdStartDate") java.util.Date dispatchOrdStartDate,
+ @Param("dispatchOrdStartOA") Long dispatchOrdStartOA,
+ @Param("oaLatitude") Double oaLatitude,
+ @Param("oaLongitude") Double oaLongitude,
+ @Param("oaAddress") String oaAddress
+ );
}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
index 9fbe692..d0630b0 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
@@ -273,4 +273,15 @@
*/
public boolean existsByLegacyDispatchOrdId(Long legacyDispatchOrdId);
+ /**
+ * 妫�鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙�
+ * 妫�鏌ワ細
+ * 1. 杞﹁締鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ * 2. 鎵ц浜哄憳鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ *
+ * @param taskId 浠诲姟ID
+ * @return AjaxResult 鏍¢獙缁撴灉锛屽寘鍚� valid 鍜� conflicts 淇℃伅
+ */
+ public com.ruoyi.common.core.domain.AjaxResult checkTaskCanDepart(Long taskId);
+
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
index 4646829..4413acb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
@@ -89,6 +89,8 @@
@Autowired
private ITaskAttachmentService taskAttachmentService;
+
+
/**
* 鍚屾鎬ユ晳杞繍浠诲姟鍒版棫绯荤粺
@@ -342,8 +344,70 @@
return null;
}
-
-
+ // ====== 鍓嶇疆鏍¢獙锛氱‘淇濅换鍔℃暟鎹畬鏁� ======
+
+ // 1. 妫�鏌ユ槸鍚﹀凡鍒嗛厤杞﹁締
+ List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId);
+ if (taskVehicles == null || taskVehicles.isEmpty()) {
+ log.warn("浠诲姟鏈垎閰嶈溅杈嗭紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ // 2. 妫�鏌ユ槸鍚﹀凡鍒嗛厤鎵ц浜哄憳
+ List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId);
+ if (taskAssignees == null || taskAssignees.isEmpty()) {
+ log.warn("浠诲姟鏈垎閰嶆墽琛屼汉鍛橈紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ // 3. 妫�鏌ラ绾︽椂闂存槸鍚︽湁鏁堬紙蹇呴』澶т簬1970骞达級
+ if (task.getPlannedStartTime() == null) {
+ log.warn("浠诲姟鏈缃绾︽椂闂达紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ // 妫�鏌ラ绾︽椂闂存槸鍚﹀ぇ浜�1970-01-01锛堟椂闂存埑0瀵瑰簲1970-01-01 00:00:00锛�
+ long timestamp1970 = 0L;
+ if (task.getPlannedStartTime().getTime() <= timestamp1970) {
+ log.warn("浠诲姟棰勭害鏃堕棿鏃犳晥锛堝皬浜庣瓑浜�1970骞达級锛岃烦杩囪皟搴﹀崟鍚屾锛屼换鍔D: {}, 棰勭害鏃堕棿: {}",
+ taskId, task.getPlannedStartTime());
+ return null;
+ }
+
+ // 4. 妫�鏌ヨ浆鍑哄尰闄俊鎭�
+ if (StringUtils.isEmpty(emergency.getHospitalOutName())) {
+ log.warn("浠诲姟鏈缃浆鍑哄尰闄紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ if (StringUtils.isEmpty(emergency.getHospitalOutAddress())) {
+ log.warn("浠诲姟鏈缃浆鍑哄尰闄㈠湴鍧�锛岃烦杩囪皟搴﹀崟鍚屾锛屼换鍔D: {}", taskId);
+ return null;
+ }
+
+ // 5. 妫�鏌ヨ浆鍏ュ尰闄俊鎭�
+ if (StringUtils.isEmpty(emergency.getHospitalInName())) {
+ log.warn("浠诲姟鏈缃浆鍏ュ尰闄紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ if (StringUtils.isEmpty(emergency.getHospitalInAddress())) {
+ log.warn("浠诲姟鏈缃浆鍏ュ尰闄㈠湴鍧�锛岃烦杩囪皟搴﹀崟鍚屾锛屼换鍔D: {}", taskId);
+ return null;
+ }
+
+ // 6. 妫�鏌ユ偅鑰呭熀鏈俊鎭�
+ if (StringUtils.isEmpty(emergency.getPatientName())) {
+ log.warn("浠诲姟鏈缃偅鑰呭鍚嶏紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ if (StringUtils.isEmpty(emergency.getPatientPhone())) {
+ log.warn("浠诲姟鏈缃偅鑰呯數璇濓紝璺宠繃璋冨害鍗曞悓姝ワ紝浠诲姟ID: {}", taskId);
+ return null;
+ }
+
+ log.info("浠诲姟鏁版嵁鏍¢獙閫氳繃锛屽紑濮嬪悓姝ヨ皟搴﹀崟锛屼换鍔D: {}", taskId);
// 鏇存柊鍚屾鐘舵�佷负鍚屾涓�
emergency.setDispatchSyncStatus(1);
@@ -1181,7 +1245,47 @@
return false;
}
- log.info("寮�濮嬮噸鏂板悓姝ヨ皟搴﹀崟锛屼换鍔D: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId());
+ // ====== 鍓嶇疆鏍¢獙锛氱‘淇濅换鍔℃暟鎹畬鏁� ======
+
+ // 1. 妫�鏌ユ槸鍚﹀凡鍒嗛厤杞﹁締
+ List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId);
+ if (taskVehicles == null || taskVehicles.isEmpty()) {
+ log.warn("浠诲姟鏈垎閰嶈溅杈嗭紝璺宠繃璋冨害鍗曢噸鏂板悓姝ワ紝浠诲姟ID: {}", taskId);
+ return false;
+ }
+
+ // 2. 妫�鏌ユ槸鍚﹀凡鍒嗛厤鎵ц浜哄憳
+ List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId);
+ if (taskAssignees == null || taskAssignees.isEmpty()) {
+ log.warn("浠诲姟鏈垎閰嶆墽琛屼汉鍛橈紝璺宠繃璋冨害鍗曢噸鏂板悓姝ワ紝浠诲姟ID: {}", taskId);
+ return false;
+ }
+
+ // 3. 妫�鏌ラ绾︽椂闂存槸鍚︽湁鏁�
+ if (task.getPlannedStartTime() == null || task.getPlannedStartTime().getTime() <= 0L) {
+ log.warn("浠诲姟棰勭害鏃堕棿鏃犳晥锛岃烦杩囪皟搴﹀崟閲嶆柊鍚屾锛屼换鍔D: {}", taskId);
+ return false;
+ }
+
+ // 4. 妫�鏌ヨ浆鍑哄尰闄俊鎭�
+ if (StringUtils.isEmpty(emergency.getHospitalOutName()) || StringUtils.isEmpty(emergency.getHospitalOutAddress())) {
+ log.warn("浠诲姟杞嚭鍖婚櫌淇℃伅涓嶅畬鏁达紝璺宠繃璋冨害鍗曢噸鏂板悓姝ワ紝浠诲姟ID: {}", taskId);
+ return false;
+ }
+
+ // 5. 妫�鏌ヨ浆鍏ュ尰闄俊鎭�
+ if (StringUtils.isEmpty(emergency.getHospitalInName()) || StringUtils.isEmpty(emergency.getHospitalInAddress())) {
+ log.warn("浠诲姟杞叆鍖婚櫌淇℃伅涓嶅畬鏁达紝璺宠繃璋冨害鍗曢噸鏂板悓姝ワ紝浠诲姟ID: {}", taskId);
+ return false;
+ }
+
+ // 6. 妫�鏌ユ偅鑰呭熀鏈俊鎭�
+ if (StringUtils.isEmpty(emergency.getPatientName()) || StringUtils.isEmpty(emergency.getPatientPhone())) {
+ log.warn("浠诲姟鎮h�呬俊鎭笉瀹屾暣锛岃烦杩囪皟搴﹀崟閲嶆柊鍚屾锛屼换鍔D: {}", taskId);
+ return false;
+ }
+
+ log.info("浠诲姟鏁版嵁鏍¢獙閫氳繃锛屽紑濮嬮噸鏂板悓姝ヨ皟搴﹀崟锛屼换鍔D: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId());
// 鏋勫缓璇锋眰鍙傛暟锛堜娇鐢ㄧ浉鍚岀殑鍙傛暟鏋勫缓鏂规硶锛�
Map<String, String> params = buildDispatchOrderParams(task, emergency);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
index c2b98b1..7bdf7ab 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
@@ -170,22 +170,24 @@
log.error("鏈嶅姟鍗旾D涓嶈兘涓虹┖");
return false;
}
-
+ // 鐩存帴鏌ヨ鎸囧畾鐨勮浆杩愬崟淇℃伅
+ List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrdersByIDs(serviceOrdID, dispatchOrdID);
+
+ Map<String, Object> order = transferOrders.get(0);
+
// 妫�鏌ユ槸鍚﹀凡鍚屾
if (isTransferOrderSynced(serviceOrdID, dispatchOrdID)) {
log.info("杞繍鍗曞凡鍚屾锛岃烦杩�: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
+ updateTransferOrder(serviceOrdID, dispatchOrdID, order);
return true;
}
- // 鐩存帴鏌ヨ鎸囧畾鐨勮浆杩愬崟淇℃伅
- List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrdersByIDs(serviceOrdID, dispatchOrdID);
-
+
if (transferOrders == null || transferOrders.isEmpty()) {
log.error("鏈煡璇㈠埌瀵瑰簲鐨勮浆杩愬崟淇℃伅: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
return false;
}
-
- Map<String, Object> order = transferOrders.get(0);
+
// 鍚屾鍗曚釜杞繍鍗�
return syncSingleTransferOrder(serviceOrdID, dispatchOrdID, order);
@@ -294,7 +296,10 @@
String serviceOrdClass = getStringValue(order,"ServiceOrdClass");
String serviceOrdNo = getStringValue(order,"ServiceOrdNo");
- Integer oauserId=getIntegerValue(order,"ServiceOrd_NS_ID");
+ /**
+ * 鍒涘缓浜篒D
+ */
+ Integer oauserId=getIntegerValue(order,"ServiceOrd_CC_ID");
SysUser sysUser=sysUserService.selectUserByOaUserId(oauserId);
Long taskCreatorId=sysUser==null?null:sysUser.getUserId();
String createUserName=sysUser==null?"system":sysUser.getUserName();
@@ -495,9 +500,9 @@
hospitalInInfo.setName(hospitalInName);
}
}
- String DispatchOrdTraEnd = getStringValue(order, "DispatchOrdTraEnd");
- if(DispatchOrdTraEnd!= null){
- hospitalInInfo.setAddress(DispatchOrdTraEnd);
+ String serviceOrdTraEnd = getStringValue(order, "ServiceOrdTraEnd");
+ if(serviceOrdTraEnd!= null){
+ hospitalInInfo.setAddress(serviceOrdTraEnd);
}
//杞叆搴婁綅
String serviceOrdPtInServices =getStringValue(order, "ServiceOrdPtInServices");
@@ -523,14 +528,15 @@
// 璁剧疆浠锋牸鍜岃窛绂讳俊鎭�
createTaskVo.setPrice(getBigDecimalValue(order, "ServiceOrdTraTxnPrice"));
// 璺濈淇℃伅闇�瑕佷粠鍏朵粬瀛楁璁$畻鎴栬幏鍙�
-
- // 璁剧疆鎵ц浜轰俊鎭�
- List<TaskCreateVO.AssigneeInfo> assignees = queryAssignees(dispatchOrdID);
- createTaskVo.setAssignees(assignees);
- if(!assignees.isEmpty()){
- createTaskVo.setAssigneeId(assignees.get(0).getUserId());
+
+ if(dispatchOrdID!=null) {
+ // 璁剧疆鎵ц浜轰俊鎭�
+ List<TaskCreateVO.AssigneeInfo> assignees = queryAssignees(dispatchOrdID);
+ createTaskVo.setAssignees(assignees);
+ if (!assignees.isEmpty()) {
+ createTaskVo.setAssigneeId(assignees.get(0).getUserId());
+ }
}
-
// 璁剧疆杞﹁締淇℃伅
// 杞﹁締ID闇�瑕佹牴鎹瓺ispatchOrdCarID鏌ヨ鑾峰彇
String carID = getStringValue(order, "DispatchOrdCarID");
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 a04871a..b983222 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
@@ -1024,7 +1024,6 @@
* @return 缁撴灉
*/
@Override
- @Transactional
public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark) {
return changeTaskStatusWithLocation(taskId, newStatus, remark, null);
}
@@ -1039,7 +1038,6 @@
* @return 缁撴灉
*/
@Override
- @Transactional
public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog) {
SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(taskId);
if (oldTask == null) {
@@ -1091,7 +1089,10 @@
.map(SysTaskAssignee::getUserId)
.collect(Collectors.toList());
}
-
+ Long userId=SecurityUtils.getUserId();
+ Double lng=locationLog==null?null: locationLog.getLongitude();
+ Double lat=locationLog==null?null: locationLog.getLatitude();
+ String address=locationLog==null?null: locationLog.getLocationAddress();
eventPublisher.publishEvent(new TaskStatusChangedEvent(
this,
oldTask.getTaskId(),
@@ -1101,7 +1102,11 @@
oldTaskStatus.getInfo(),
newStatus.getInfo(),
assigneeIds,
- oldTask.getCreatorId()
+ oldTask.getCreatorId(),
+ userId,
+ lng, lat,
+ address
+
));
}
@@ -2262,5 +2267,89 @@
}
}
+ /**
+ * 妫�鏌ヤ换鍔℃槸鍚﹀彲浠ュ嚭鍙�
+ * 妫�鏌ワ細
+ * 1. 杞﹁締鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ * 2. 鎵ц浜哄憳鏄惁鏈夋湭瀹屾垚鐨勪换鍔�
+ *
+ * @param taskId 浠诲姟ID
+ * @return AjaxResult 鏍¢獙缁撴灉
+ */
+ @Override
+ public com.ruoyi.common.core.domain.AjaxResult checkTaskCanDepart(Long taskId) {
+ // 鑾峰彇浠诲姟璇︽儏
+ SysTask task = this.getTaskDetail(taskId);
+ if (task == null) {
+ return com.ruoyi.common.core.domain.AjaxResult.error("浠诲姟涓嶅瓨鍦�");
+ }
+
+ List<Map<String, Object>> conflicts = new ArrayList<>();
+
+ // 1. 妫�鏌ヨ溅杈嗘槸鍚︽湁鏈畬鎴愮殑浠诲姟
+ List<SysTaskVehicle> taskVehicles = task.getAssignedVehicles();
+ if (taskVehicles != null && !taskVehicles.isEmpty()) {
+ for (SysTaskVehicle taskVehicle : taskVehicles) {
+ Long vehicleId = taskVehicle.getVehicleId();
+ List<SysTask> vehicleActiveTasks = this.checkVehicleActiveTasks(vehicleId);
+
+ // 杩囨护鎺夊綋鍓嶄换鍔℃湰韬�
+ vehicleActiveTasks = vehicleActiveTasks.stream()
+ .filter(t -> !t.getTaskId().equals(taskId))
+ .collect(Collectors.toList());
+
+ if (!vehicleActiveTasks.isEmpty()) {
+ for (SysTask activeTask : vehicleActiveTasks) {
+ Map<String, Object> conflict = new HashMap<>();
+ conflict.put("type", "vehicle");
+ conflict.put("vehicleNo", taskVehicle.getVehicleNo());
+ conflict.put("taskId", activeTask.getTaskId());
+ conflict.put("taskCode", activeTask.getTaskCode());
+ conflict.put("taskStatus", activeTask.getTaskStatus());
+ conflict.put("message", String.format("杞﹁締 %s 灏氭湁鏈畬鎴愮殑浠诲姟 %s锛岃鍏堝畬鎴�",
+ taskVehicle.getVehicleNo(), activeTask.getTaskCode()));
+ conflicts.add(conflict);
+ }
+ }
+ }
+ }
+
+ // 2. 妫�鏌ユ墽琛屼汉鍛樻槸鍚︽湁鏈畬鎴愮殑浠诲姟
+ List<SysTaskAssignee> assignees = task.getAssignees();
+ if (assignees != null && !assignees.isEmpty()) {
+ for (SysTaskAssignee assignee : assignees) {
+ Long userId = assignee.getUserId();
+
+ // 鏌ヨ璇ユ墽琛屼汉鐨勬墍鏈夋鍦ㄨ繘琛屼腑鐨勪换鍔★紙鎺掗櫎PENDING銆丆OMPLETED銆丆ANCELLED锛�
+ List<SysTask> userActiveTasks = this.selectMyTasks(userId).stream()
+ .filter(t -> !TaskStatus.PENDING.getCode().equals(t.getTaskStatus())
+ && !TaskStatus.COMPLETED.getCode().equals(t.getTaskStatus())
+ && !TaskStatus.CANCELLED.getCode().equals(t.getTaskStatus())
+ && !t.getTaskId().equals(taskId)) // 杩囨护鎺夊綋鍓嶄换鍔�
+ .collect(Collectors.toList());
+
+ if (!userActiveTasks.isEmpty()) {
+ for (SysTask activeTask : userActiveTasks) {
+ Map<String, Object> conflict = new HashMap<>();
+ conflict.put("type", "assignee");
+ conflict.put("userName", assignee.getUserName());
+ conflict.put("taskId", activeTask.getTaskId());
+ conflict.put("taskCode", activeTask.getTaskCode());
+ conflict.put("taskStatus", activeTask.getTaskStatus());
+ conflict.put("message", String.format("鎵ц浜� %s 灏氭湁姝e湪杩涜涓殑浠诲姟 %s锛岃鍏堝畬鎴�",
+ assignee.getUserName(), activeTask.getTaskCode()));
+ conflicts.add(conflict);
+ }
+ }
+ }
+ }
+
+ // 杩斿洖缁撴灉
+ Map<String, Object> result = new HashMap<>();
+ result.put("valid", conflicts.isEmpty());
+ result.put("conflicts", conflicts);
+
+ return com.ruoyi.common.core.domain.AjaxResult.success(result);
+ }
}
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
index ecadd20..97e49ae 100644
--- 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
@@ -223,6 +223,10 @@
{
existingUser.setOaOrderClass(dto.getOaOrderClass());
}
+ if (StringUtils.isNotEmpty(dto.getCanViewAllConsult()))
+ {
+ existingUser.setCanViewAllConsult(dto.getCanViewAllConsult());
+ }
sysUserMapper.updateUser(existingUser);
}
@@ -239,6 +243,10 @@
{
newUser.setOaOrderClass(dto.getOaOrderClass());
}
+ if (StringUtils.isNotEmpty(dto.getCanViewAllConsult()))
+ {
+ newUser.setCanViewAllConsult(dto.getCanViewAllConsult());
+ }
if (deptId != null)
{
diff --git a/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
index 8000982..906b028 100644
--- a/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
@@ -43,6 +43,7 @@
<result property="Old_ServiceOrdID_TXT" column="Old_ServiceOrdID_TXT" />
<result property="ServiceOrdTraDistance" column="ServiceOrdTraDistance" />
<result property="ServiceOrdApptDate" column="ServiceOrdApptDate" />
+ <result property="DispatchOrdState" column="DispatchOrdState" />
</resultMap>
<!-- 鎵ц浜虹粨鏋滄槧灏� -->
@@ -87,16 +88,17 @@
b.DispatchOrdActualDate,
b.DispatchOrdReturnDate,
b.DispatchOrdTraEnd,
+ b.DispatchOrdState,
b.DispatchOrdID,
b.DispatchOrdCarID,
a.ServiceOrdPtServices,
a.ServiceOrdPtInServices,
a.ServiceOrdPtName
FROM ServiceOrder as a
- INNER JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
- WHERE a.ServiceOrdState = 3
+ left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
+ WHERE a.ServiceOrdState <= 3
AND a.ServiceOrd_CC_Time > #{startDate}
- AND b.DispatchOrdState != 0
+
</select>
<!-- 鏍规嵁鏈嶅姟鍗旾D鍜岃皟搴﹀崟ID鏌ヨ杞繍鍗曟暟鎹� -->
@@ -137,13 +139,13 @@
b.DispatchOrdCarID,
a.ServiceOrdPtServices,
a.ServiceOrdPtInServices,
- a.ServiceOrdPtName
+ a.ServiceOrdPtName,
+ b.DispatchOrdState
FROM ServiceOrder as a
- INNER JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
+ left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
WHERE a.ServiceOrdID = #{serviceOrdID}
- AND b.DispatchOrdID = #{dispatchOrdID}
- AND a.ServiceOrdState = 3
- AND b.DispatchOrdState != 0
+ AND a.ServiceOrdState <=3
+
</select>
<!-- 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鐥呮儏淇℃伅 -->
@@ -184,4 +186,25 @@
WHERE vID = #{deptID} AND vtitle = 'HospitalDepartment'
</select>
+ <!-- 鎻掑叆璋冨害鍗曠姸鎬佸彉鏇磋褰曞埌 DispatchOrd_Running 琛� -->
+ <insert id="insertDispatchOrdRunning">
+ INSERT INTO DispatchOrd_Running (
+ DispatchOrdIDDt,
+ DispatchOrdState,
+ DispatchOrdStartDate,
+ DispatchOrdStartOA
+ <if test="oaLatitude != null">,OA_latitude</if>
+ <if test="oaLongitude != null">,OA_longitude</if>
+ <if test="oaAddress != null and oaAddress != ''">,OA_address</if>
+ ) VALUES (
+ #{dispatchOrdID},
+ #{dispatchOrdState},
+ #{dispatchOrdStartDate},
+ #{dispatchOrdStartOA}
+ <if test="oaLatitude != null">,#{oaLatitude}</if>
+ <if test="oaLongitude != null">,#{oaLongitude}</if>
+ <if test="oaAddress != null and oaAddress != ''">,#{oaAddress}</if>
+ )
+ </insert>
+
</mapper>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
index d8abfba..a7efd95 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
@@ -88,16 +88,36 @@
<if test="taskStatus != null and taskStatus != ''"> and t.task_status = #{taskStatus}</if>
<if test="vehicleNo != null and vehicleNo != ''"> and v.vehicle_no like concat('%', #{vehicleNo}, '%')</if>
<!-- 缁煎悎鏌ヨ锛氬綋鍓嶇敤鎴锋墍鍦ㄦ満鏋� OR 褰撳墠鐢ㄦ埛鍒涘缓 OR 鍒嗛厤缁欏綋鍓嶇敤鎴� -->
- <if test="(creatorId != null and creatorId != 0) or (assigneeId != null and assigneeId != 0) or (deptId != null and deptId != 0)">
+ <if test="(creatorId != null and creatorId != 0) or (assigneeId != null and assigneeId != 0) or (deptId != null and deptId != 0) or (deptIds != null and deptIds.size() > 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">
+ (t.dept_id = #{deptId} OR t.dept_id IN (
+ SELECT dept_id FROM sys_dept
+ WHERE del_flag = '0' AND find_in_set(#{deptId}, ancestors)
+ ))
+ </if>
+ <!-- 鏌ヨ澶氫釜鍒嗗叕鍙稿強鍏舵墍鏈夊瓙閮ㄩ棬鐨勪换鍔� -->
+ <if test="deptIds != null and deptIds.size() > 0">
<if test="deptId != null and deptId != 0"> or </if>
+ (
+ <foreach collection="deptIds" item="branchDeptId" separator=" OR ">
+ (t.dept_id = #{branchDeptId} OR t.dept_id IN (
+ SELECT dept_id FROM sys_dept
+ WHERE del_flag = '0' AND find_in_set(#{branchDeptId}, ancestors)
+ ))
+ </foreach>
+ )
+ </if>
+ <if test="creatorId != null and creatorId != 0">
+ <if test="(deptId != null and deptId != 0) or (deptIds != null and deptIds.size() > 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 test="(deptId != null and deptId != 0) or (deptIds != null and deptIds.size() > 0) or (creatorId != null and creatorId != 0)"> or </if>
+ t.task_id IN (
+ SELECT task_id FROM sys_task_assignee WHERE user_id = #{assigneeId}
+ )
</if>
)
</if>
@@ -145,7 +165,12 @@
<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})
+ where t.del_flag = '0' and (
+ t.creator_id = #{userId}
+ OR t.task_id IN (
+ SELECT task_id FROM sys_task_assignee WHERE user_id = #{userId}
+ )
+ )
order by
CASE t.task_status
WHEN 'PENDING' THEN 1
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
index a1f910a..f5fab34 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -28,6 +28,7 @@
<result property="openId" column="open_id" />
<result property="unionId" column="union_id" />
<result property="wechatNickname" column="wechat_nickname" />
+ <result property="canViewAllConsult" column="can_view_all_consult" />
<association property="dept" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
</resultMap>
@@ -52,7 +53,7 @@
</resultMap>
<sql id="selectUserVo">
- select u.user_id, u.dept_id, u.user_name,u.oa_user_id, u.oa_order_class, 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,u.open_id,u.union_id,u.wechat_nickname,
+ select u.user_id, u.dept_id, u.user_name,u.oa_user_id, u.oa_order_class, 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,u.open_id,u.union_id,u.wechat_nickname,u.can_view_all_consult,
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
@@ -169,6 +170,7 @@
<if test="status != null and status != ''">status,</if>
<if test="oaUserId != null">oa_user_id,</if>
<if test="oaOrderClass != null and oaOrderClass != ''">oa_order_class,</if>
+ <if test="canViewAllConsult != null and canViewAllConsult != ''">can_view_all_consult,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
@@ -185,6 +187,7 @@
<if test="status != null and status != ''">#{status},</if>
<if test="oaUserId != null">#{oaUserId},</if>
<if test="oaOrderClass != null and oaOrderClass != ''">#{oaOrderClass},</if>
+ <if test="canViewAllConsult != null and canViewAllConsult != ''">#{canViewAllConsult},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
@@ -204,6 +207,7 @@
<if test="status != null and status != ''">status = #{status},</if>
<if test="oaUserId != null">oa_user_id = #{oaUserId},</if>
<if test="oaOrderClass != null">oa_order_class = #{oaOrderClass},</if>
+ <if test="canViewAllConsult != null and canViewAllConsult != ''">can_view_all_consult = #{canViewAllConsult},</if>
<if test="openId != null and openId != ''">open_id = #{openId},</if>
<if test="unionId != null and unionId != ''">union_id = #{unionId},</if>
<if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
diff --git a/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
index f96ef3c..420e03e 100644
--- a/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
@@ -13,6 +13,7 @@
<result property="email" column="email" />
<result property="phonenumber" column="phonenumber" />
<result property="oaOrderClass" column="OA_OrderClass" />
+ <result property="canViewAllConsult" column="can_view_all_consult" />
</resultMap>
<!-- 鏌ヨSQL Server涓殑OA鐢ㄦ埛鍒楄〃 -->
@@ -26,7 +27,11 @@
OA_gender AS sex,
OA_email AS email,
OA_mobile AS phonenumber,
- OA_OrderClass AS OA_OrderClass
+ OA_OrderClass AS OA_OrderClass,
+ CASE
+ WHEN OA_Power LIKE '%,020112,%' THEN '1'
+ ELSE '0'
+ END AS can_view_all_consult
FROM OA_User
WHERE OA_User IS NOT NULL
AND OA_Name IS NOT NULL
diff --git a/ruoyi-system/src/test/java/com/ruoyi/system/mapper/SysDeptMapperTest.java b/ruoyi-system/src/test/java/com/ruoyi/system/mapper/SysDeptMapperTest.java
deleted file mode 100644
index e69de29..0000000
--- a/ruoyi-system/src/test/java/com/ruoyi/system/mapper/SysDeptMapperTest.java
+++ /dev/null
diff --git a/ruoyi-system/src/test/java/com/ruoyi/system/service/LegacySystemHttpsTest.java b/ruoyi-system/src/test/java/com/ruoyi/system/service/LegacySystemHttpsTest.java
deleted file mode 100644
index 24d0af8..0000000
--- a/ruoyi-system/src/test/java/com/ruoyi/system/service/LegacySystemHttpsTest.java
+++ /dev/null
@@ -1,260 +0,0 @@
-package com.ruoyi.system.service;
-
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 鏃х郴缁烪TTPS鎺ュ彛娴嬭瘯
- * 娴嬭瘯admin_save_19.gds鎺ュ彛璋冪敤
- *
- * @author ruoyi
- * @date 2025-11-09
- */
-public class LegacySystemHttpsTest {
-
- private static final Logger log = LoggerFactory.getLogger(LegacySystemHttpsTest.class);
-
- /**
- * 娴嬭瘯璋冪敤admin_save_19.gds鎺ュ彛锛堝垱寤烘湇鍔″崟锛�
- */
- @Test
- public void testCreateServiceOrder() {
- try {
- String url = "https://sys.966120.com.cn/admin_save_19.gds";
-
- // 鏋勫缓璇锋眰鍙傛暟
- Map<String, String> params = buildTestParams();
-
- // 鍙戦�佽姹�
- String response = sendHttpsPost(url, params);
-
- // 杈撳嚭鍝嶅簲
- log.info("鎺ュ彛鍝嶅簲锛歿}", response);
- System.out.println("鎺ュ彛鍝嶅簲锛�" + response);
-
- // 瑙f瀽鍝嶅簲
- if (response != null && response.startsWith("OK:")) {
- String serviceOrdId = response.substring(3).trim();
- log.info("鏈嶅姟鍗曞垱寤烘垚鍔燂紝ServiceOrdID: {}", serviceOrdId);
- System.out.println("鉁� 鏈嶅姟鍗曞垱寤烘垚鍔燂紝ServiceOrdID: " + serviceOrdId);
- } else {
- log.error("鏈嶅姟鍗曞垱寤哄け璐ワ紝鍝嶅簲: {}", response);
- System.out.println("鉂� 鏈嶅姟鍗曞垱寤哄け璐ワ紝鍝嶅簲: " + response);
- }
-
- } catch (Exception e) {
- log.error("娴嬭瘯寮傚父", e);
- e.printStackTrace();
- }
- }
-
- /**
- * 鏋勫缓娴嬭瘯鍙傛暟
- */
- private Map<String, String> buildTestParams() {
- Map<String, String> params = new HashMap<>();
-
- // 鍩虹淇℃伅
- params.put("adminID", "1312");
- params.put("ServiceOrdClass", "BF");
- params.put("ServiceOrdAreaType", "1");
- params.put("ServiceOrdType", "20");
- params.put("ServiceOrdState", "2");
- params.put("ServiceOrdStartDate", "2025-11-09");
-
- // 棰勭害鏃堕棿
- params.put("ServiceOrdApptDate", "2025-11-09 16:56:31");
-
- // 鑱旂郴浜轰俊鎭�
- params.put("ServiceOrdCoName", "鏉庢祴璇�11");
- params.put("ServiceOrdCoPhone", "13602220102");
- params.put("ServiceOrdCoTies", "");
-
- // 鎮h�呬俊鎭�
- params.put("ServiceOrdPtName", "鏉庢祴璇�21");
- params.put("ServiceOrdPtAge", "");
- params.put("ServiceOrdPtKG", "");
- params.put("ServiceOrdPtSex", "");
- params.put("ServiceOrdPtNat", "");
- params.put("ServiceOrdPtIDCard", "");
-
- // 鍖婚櫌淇℃伅
- params.put("ServiceOrdPtOutHosp", "骞夸笢鐪佺浜屼汉姘戝尰闄㈠ぉ娌冲尰闄�(骞夸笢鐕曞箔鍖婚櫌)");
- params.put("ServiceOrdPtOutHospID", "310");
- params.put("ServiceOrdPtInHosp", "瀹朵腑");
- params.put("ServiceOrdPtInHospID", "153");
-
- // 绉戝淇℃伅
- params.put("ServiceOrdPtServices", "鍏朵粬");
- params.put("ServiceOrdPtServicesID", "22");
- params.put("ServiceOrdPtInServices", "鍏朵粬");
- params.put("ServiceOrdPtInServicesID", "0");
-
- // 鐥呮儏淇℃伅
- params.put("ServiceOrdPtDiagnosis", "");
- params.put("ServiceOrdPtCondition", "");
- params.put("ServiceOrdTaskRemarks", "");
- params.put("ServiceOrdPtDoctor", "");
- params.put("ServiceOrdPtDoctorPhone", "");
-
- // 鍦板潃淇℃伅
- params.put("province", "");
- params.put("city", "");
- params.put("ServiceOrdTraStreet", "骞夸笢鐪佸箍宸炲競澶╂渤鍖烘瀹夎矾533鍙�");
- params.put("ServiceOrdTraStreetCoo", "");
- params.put("ServiceOrdTraEnd", "澶╂渤鍖哄箍宸炲競-澶╂渤鍖�-鏌忓痉璺�101鍙�");
- params.put("ServiceOrdTraEndCoo", "");
- params.put("ServiceOrdTraVia", "");
-
- // 璺濈鍜屼环鏍间俊鎭�
- params.put("ServiceOrdViaDistance", "0");
- params.put("ServiceOrdTraDistance", "10.70");
- params.put("ServiceOrdTraDuration", "");
- params.put("ServiceOrdTraUnitPrice", "0");
- params.put("ServiceOrdTraOfferPrice", "154.00");
- params.put("ServiceOrdTraTxnPrice", "154.00");
- params.put("ServiceOrdTraPrePayment", "0");
- params.put("SettlementPrice", "0");
- params.put("ServiceOrdTraPriceReason", "");
-
- // 鍏朵粬淇℃伅
- params.put("Phone", "13602220102");
- params.put("TEL_Time", "2025-11-09 16:58:21");
- params.put("TEL_Remarks", "鏂扮郴缁熷悓姝�");
- params.put("TransferModeID", "");
- params.put("ServiceOrdVIP", "0");
- params.put("ServiceOrd_CC_ID", "");
- params.put("ServiceOrd_Sale_ID", "");
- params.put("ServiceOrdIntroducer", "");
- params.put("ServiceOrd_work_ID", "");
- params.put("ServiceOrd_work_IDs", "");
- params.put("ServiceOrd_work_is", "0");
- params.put("CommissionScenarioID", "0");
- params.put("ServiceOrdOperationRemarks", "鏂扮郴缁熷悓姝ュ垱寤�");
- params.put("ServiceOrdEstimatedOrderDate", "");
- params.put("ServiceOrdSource", "10");
- params.put("OrderLevel", "0");
- params.put("ServiceOrdDepartureType", "1");
- params.put("ConditionLevel", "0");
- params.put("DirectionType", "0");
- params.put("ServiceOrd_m", "1");
- params.put("FromHQ2_is", "0");
- params.put("OrderPrice_Auto", "0");
-
- return params;
- }
-
- /**
- * 鍙戦�丠TTPS POST璇锋眰锛堝拷鐣SL璇佷功楠岃瘉锛�
- */
- private String sendHttpsPost(String urlString, Map<String, String> params) throws Exception {
- URL url = new URL(urlString);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
- // 濡傛灉鏄疕TTPS璇锋眰锛岄厤缃甋SL淇′换鎵�鏈夎瘉涔�
- if (conn instanceof HttpsURLConnection) {
- HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
- httpsConn.setSSLSocketFactory(createTrustAllSSLContext().getSocketFactory());
- httpsConn.setHostnameVerifier((hostname, session) -> true);
- log.info("閰嶇疆HTTPS杩炴帴锛屼俊浠绘墍鏈塖SL璇佷功");
- }
-
- try {
- // 璁剧疆杩炴帴灞炴��
- conn.setRequestMethod("POST");
- conn.setConnectTimeout(30000);
- conn.setReadTimeout(60000);
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setUseCaches(false);
- conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=GBK");
- conn.setRequestProperty("Accept-Charset", "GBK");
- conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
-
- // 鏋勫缓POST鏁版嵁
- StringBuilder postData = new StringBuilder();
- for (Map.Entry<String, String> entry : params.entrySet()) {
- if (postData.length() > 0) {
- postData.append("&");
- }
- postData.append(URLEncoder.encode(entry.getKey(), "GBK"));
- postData.append("=");
- postData.append(URLEncoder.encode(entry.getValue(), "GBK"));
- }
-
- log.info("璇锋眰URL: {}", urlString);
- log.info("璇锋眰鍙傛暟闀垮害: {}", postData.length());
-
- // 鍙戦�丳OST鏁版嵁
- try (OutputStream os = conn.getOutputStream()) {
- os.write(postData.toString().getBytes("GBK"));
- os.flush();
- }
-
- // 璇诲彇鍝嶅簲
- int responseCode = conn.getResponseCode();
- log.info("鍝嶅簲鐮�: {}", responseCode);
-
- if (responseCode == HttpURLConnection.HTTP_OK) {
- try (BufferedReader reader = new BufferedReader(
- new InputStreamReader(conn.getInputStream(), "GBK"))) {
- StringBuilder response = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- response.append(line);
- }
- return response.toString().trim();
- }
- } else {
- log.error("璇锋眰澶辫触锛屽搷搴旂爜: {}", responseCode);
- throw new Exception("HTTPS璇锋眰澶辫触锛屽搷搴旂爜: " + responseCode);
- }
-
- } finally {
- conn.disconnect();
- }
- }
-
- /**
- * 鍒涘缓淇′换鎵�鏈塖SL璇佷功鐨凷SLContext
- */
- private SSLContext createTrustAllSSLContext() throws Exception {
- TrustManager[] trustAllCerts = new TrustManager[] {
- new X509TrustManager() {
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] certs, String authType) {
- // 淇′换鎵�鏈夊鎴风璇佷功
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] certs, String authType) {
- // 淇′换鎵�鏈夋湇鍔″櫒璇佷功
- }
- }
- };
-
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
- return sslContext;
- }
-}
diff --git a/ruoyi-system/src/test/java/com/ruoyi/system/service/SysDeptServiceTest.java b/ruoyi-system/src/test/java/com/ruoyi/system/service/SysDeptServiceTest.java
deleted file mode 100644
index e69de29..0000000
--- a/ruoyi-system/src/test/java/com/ruoyi/system/service/SysDeptServiceTest.java
+++ /dev/null
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index f479f46..ed3749d 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -172,6 +172,16 @@
</el-row>
<el-row>
<el-col :span="12">
+ <el-form-item label="鏌ョ湅鎵�鏈夊挩璇㈠崟">
+ <el-radio-group v-model="form.canViewAllConsult">
+ <el-radio label="0">鍚�</el-radio>
+ <el-radio label="1">鏄�</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
<el-form-item label="宀椾綅">
<el-select v-model="form.postIds" multiple placeholder="璇烽�夋嫨宀椾綅">
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option>
@@ -451,7 +461,8 @@
status: "0",
remark: undefined,
postIds: [],
- roleIds: []
+ roleIds: [],
+ canViewAllConsult: "0"
};
this.resetForm("form");
},
diff --git a/sql/DispatchRunning.sql b/sql/DispatchRunning.sql
new file mode 100644
index 0000000..73c7bed
--- /dev/null
+++ b/sql/DispatchRunning.sql
@@ -0,0 +1,10 @@
+create table DispatchOrd_Running(
+ id int comment "鑷涓婚敭",
+DispatchOrdIDDt bigint comment '璋冨害鍗旾D',
+DispatchOrdState int comment '鐘舵��',
+DispatchOrdStartDate datetime comment '鐘舵�佹椂闂�',
+DispatchOrdStartOA int comment '鎿嶄綔鐘舵�佺殑OA鐢ㄦ埛ID',
+OA_latitude float comment '鏇存柊鐘舵�佹椂鐨勭含搴�',
+OA_longitude float comment '鏇存柊鐘舵�佹椂鐨勭粡搴�',
+OA_address nvarchar(400) comment '鏇存柊鐘舵�佹椂鐨勫湴鍧�'
+)
\ No newline at end of file
diff --git a/sql/add_can_view_all_consult_to_sys_user.sql b/sql/add_can_view_all_consult_to_sys_user.sql
new file mode 100644
index 0000000..6ce673b
--- /dev/null
+++ b/sql/add_can_view_all_consult_to_sys_user.sql
@@ -0,0 +1,12 @@
+-- 娣诲姞sys_user琛ㄥ瓧娈碉細鏄惁鍙互鏌ョ湅绠$悊閮ㄩ棬鐨勬墍鏈夊挩璇㈠崟
+-- 鎵ц鏃堕棿: 2025-12-04
+-- 鍔熻兘璇存槑: 鐢ㄤ簬鏍囪瘑鐢ㄦ埛鏄惁鎷ユ湁鏌ョ湅鍏剁鐞嗛儴闂ㄦ墍鏈夊挩璇㈠崟鐨勬潈闄�
+
+-- 娣诲姞瀛楁
+ALTER TABLE `sys_user` ADD COLUMN `can_view_all_consult` CHAR(1) DEFAULT '0' COMMENT '鏄惁鍙煡鐪嬫墍鏈夊挩璇㈠崟锛�0鍚� 1鏄級' AFTER `wechat_nickname`;
+
+-- 璇存槑
+-- 1. can_view_all_consult: 鏍囪瘑鐢ㄦ埛鏄惁鍙互鏌ョ湅绠$悊閮ㄩ棬鐨勬墍鏈夊挩璇㈠崟
+-- 2. 榛樿鍊间负 '0'锛堝惁锛夛紝琛ㄧず鏅�氱敤鎴�
+-- 3. 鍊间负 '1'锛堟槸锛夎〃绀鸿鐢ㄦ埛鏈夋煡鐪嬫墍鏈夊挩璇㈠崟鐨勬潈闄�
+-- 4. 璇ユ潈闄愪笌OA绯荤粺涓殑OA_Power瀛楁鍏宠仈锛屽寘鍚�',020112,'琛ㄧず鎷ユ湁璇ユ潈闄�
--
Gitblit v1.9.1