From 656d6f8029f8bf9b2daa9dcc89101a879a70b860 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期三, 03 十二月 2025 23:10:05 +0800
Subject: [PATCH] feat:优先添加执行人
---
dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/ThirdPartyConfig.java | 17
dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentController.java | 96 +++
app/pagesTask/components/StaffSelector.vue | 41 -
dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentNotifyService.java | 274 +++++++++++
dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentService.java | 307 ++++++++++++
dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/AlipayConfig.java | 2
app/pagesTask/edit-emergency.vue | 392 ---------------
app/pagesTask/create-emergency.vue | 166 ------
dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentNotifyController.java | 103 ++++
dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/WechatPayConfig.java | 6
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskPaymentServiceImpl.java | 1
ruoyi-admin/src/main/resources/application.yml | 12
12 files changed, 834 insertions(+), 583 deletions(-)
diff --git a/app/pagesTask/components/StaffSelector.vue b/app/pagesTask/components/StaffSelector.vue
index 6cc7446..55c5391 100644
--- a/app/pagesTask/components/StaffSelector.vue
+++ b/app/pagesTask/components/StaffSelector.vue
@@ -6,11 +6,6 @@
<view class="staff-item" v-for="(staff, index) in selectedStaff" :key="staff.userId">
<view class="staff-info">
<text class="staff-name">{{ staff.nickName }}</text>
- <view class="staff-roles">
- <text class="staff-role" v-for="(roleType, idx) in staff.types" :key="idx">
- {{ getUserTypeName(roleType) }}
- </text>
- </view>
</view>
<uni-icons
v-if="canRemove(index)"
@@ -56,11 +51,6 @@
<view class="staff-filter">
<view
class="filter-item"
- :class="{ active: staffFilterType === 'all' }"
- @click="filterStaff('all')"
- >鍏ㄩ儴</view>
- <view
- class="filter-item"
:class="{ active: staffFilterType === 'driver' }"
@click="filterStaff('driver')"
>鍙告満</view>
@@ -90,16 +80,6 @@
</view>
<view class="staff-detail-row">
<text class="staff-dept">{{ staff.deptName }}</text>
- <view class="staff-types">
- <text
- class="type-tag"
- :class="'type-' + type"
- v-for="(type, idx) in staff.types"
- :key="idx"
- >
- {{ getUserTypeName(type) }}
- </text>
- </view>
</view>
</view>
<uni-icons
@@ -169,7 +149,7 @@
allStaffList: [],
filteredStaffList: [],
staffSearchKeyword: '',
- staffFilterType: 'all'
+ staffFilterType: 'driver' // 榛樿閫変腑鍙告満
}
},
computed: {
@@ -304,7 +284,7 @@
closeStaffSelector() {
this.$refs.staffPopup.close()
this.staffSearchKeyword = ''
- this.staffFilterType = 'all'
+ this.staffFilterType = 'driver' // 閲嶇疆涓洪粯璁ゅ徃鏈�
},
// 浜哄憳鎼滅储
@@ -323,11 +303,6 @@
filterStaffList() {
let list = [...this.allStaffList]
- // 鎸夌被鍨嬭繃婊わ紙鏀寔澶氱被鍨嬶級
- if (this.staffFilterType !== 'all') {
- list = list.filter(staff => staff.types.includes(this.staffFilterType))
- }
-
// 鎸夊叧閿瘝鎼滅储
if (this.staffSearchKeyword && this.staffSearchKeyword.trim() !== '') {
const keyword = this.staffSearchKeyword.trim().toLowerCase()
@@ -336,6 +311,16 @@
(staff.phonenumber && staff.phonenumber.includes(keyword))
})
}
+
+ // 鏍规嵁閫変腑鐨勭被鍨嬶紝灏嗘湁璇ヨ韩浠界殑浜烘帓鍦ㄥ墠闈�
+ list.sort((a, b) => {
+ const aHasType = a.types.includes(this.staffFilterType)
+ const bHasType = b.types.includes(this.staffFilterType)
+
+ if (aHasType && !bHasType) return -1 // a鏈夎韬唤锛屾帓鍓嶉潰
+ if (!aHasType && bHasType) return 1 // b鏈夎韬唤锛屾帓鍓嶉潰
+ return 0 // 閮芥湁鎴栭兘娌℃湁锛屼繚鎸佸師椤哄簭
+ })
this.filteredStaffList = list
},
@@ -354,7 +339,7 @@
this.selectedStaff.splice(index, 1)
} else {
// 鏈�変腑锛屾坊鍔�
- this.selectedStaff.push(staff)
+ this.selectedStaff.push({ ...staff })
}
},
diff --git a/app/pagesTask/create-emergency.vue b/app/pagesTask/create-emergency.vue
index 8fb53ae..5f557c7 100644
--- a/app/pagesTask/create-emergency.vue
+++ b/app/pagesTask/create-emergency.vue
@@ -1690,172 +1690,6 @@
}
}
-// 浜哄憳閫夋嫨寮圭獥鏍峰紡
-.staff-selector-popup {
- background-color: white;
- border-radius: 20rpx 20rpx 0 0;
- max-height: 80vh;
- display: flex;
- flex-direction: column;
-
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
- flex-shrink: 0;
-
- .popup-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
-
- .popup-close {
- padding: 10rpx;
- }
- }
-
- .search-box {
- display: flex;
- align-items: center;
- margin: 20rpx 30rpx;
- padding: 15rpx 20rpx;
- background-color: #f5f5f5;
- border-radius: 10rpx;
- flex-shrink: 0;
-
- .search-input {
- flex: 1;
- margin-left: 10rpx;
- font-size: 28rpx;
- }
- }
-
- .staff-filter {
- display: flex;
- padding: 0 30rpx 20rpx;
- gap: 20rpx;
- flex-shrink: 0;
-
- .filter-item {
- flex: 1;
- text-align: center;
- padding: 15rpx 0;
- background-color: #f5f5f5;
- border-radius: 10rpx;
- font-size: 28rpx;
- color: #666;
-
- &.active {
- background-color: #007AFF;
- color: white;
- }
- }
- }
-
- .staff-list-popup {
- flex: 1;
- overflow-y: auto;
- padding: 0 30rpx;
-
- .staff-item-popup {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 25rpx 20rpx;
- border-bottom: 1rpx solid #f0f0f0;
-
- &:active {
- background-color: #f5f5f5;
- }
-
- .staff-info {
- flex: 1;
-
- .staff-name-row {
- display: flex;
- align-items: center;
- margin-bottom: 10rpx;
-
- .staff-name {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- margin-right: 20rpx;
- }
-
- .staff-phone {
- font-size: 24rpx;
- color: #999;
- }
- }
-
- .staff-detail-row {
- display: flex;
- align-items: center;
-
- .staff-dept {
- font-size: 24rpx;
- color: #666;
- margin-right: 20rpx;
- }
-
- .staff-post {
- font-size: 24rpx;
- color: #007AFF;
- }
- }
- }
-
- .checkbox-empty {
- width: 40rpx;
- height: 40rpx;
- border: 2rpx solid #ddd;
- border-radius: 50%;
- }
- }
-
- .no-data {
- text-align: center;
- padding: 100rpx 0;
- color: #999;
-
- text {
- display: block;
- margin-top: 20rpx;
- font-size: 28rpx;
- }
- }
- }
-
- .popup-footer {
- display: flex;
- padding: 20rpx 30rpx;
- border-top: 1rpx solid #f0f0f0;
- gap: 20rpx;
- flex-shrink: 0;
-
- button {
- flex: 1;
- height: 80rpx;
- border-radius: 10rpx;
- font-size: 30rpx;
- }
-
- .cancel-btn {
- background-color: #f5f5f5;
- color: #666;
- }
-
- .confirm-btn {
- background-color: #007AFF;
- color: white;
- }
- }
-}
-
// 鏅鸿兘璇嗗埆寮圭獥鏍峰紡
.smart-parse-popup {
background-color: white;
diff --git a/app/pagesTask/edit-emergency.vue b/app/pagesTask/edit-emergency.vue
index 4b133bf..67c10f4 100644
--- a/app/pagesTask/edit-emergency.vue
+++ b/app/pagesTask/edit-emergency.vue
@@ -47,27 +47,14 @@
/>
</view>
- <view class="form-item">
- <view class="form-label">鎵ц浠诲姟浜哄憳</view>
- <view class="staff-list">
- <view class="staff-item" v-for="(staff, index) in selectedStaff" :key="staff.userId">
- <view class="staff-info">
- <text class="staff-name">{{ staff.nickName }}</text>
- <text class="staff-role">({{ getUserTypeName(staff.type) || '鏈煡鑱屼綅' }})</text>
- </view>
- <uni-icons
- type="closeempty"
- size="20"
- color="#ff4d4f"
- @click="removeStaff(index)"
- ></uni-icons>
- </view>
- <view class="add-staff" @click="showStaffSelector">
- <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
- <text>娣诲姞浜哄憳</text>
- </view>
- </view>
- </view>
+ <StaffSelector
+ v-model="selectedStaff"
+ label="鎵ц浠诲姟浜哄憳"
+ :required="false"
+ :auto-add-current-user="false"
+ :current-user-removable="true"
+ @change="onStaffChange"
+ />
<view class="form-section-title">鎮h�呬俊鎭�</view>
<view class="form-item">
@@ -198,80 +185,6 @@
></map-selector>
</view>
</uni-popup>
-
- <!-- 浜哄憳閫夋嫨鍣ㄥ脊绐� -->
- <uni-popup ref="staffPopup" type="bottom" :mask-click="false">
- <view class="staff-popup-container">
- <view class="popup-header">
- <view class="popup-title">閫夋嫨鎵ц浜哄憳</view>
- <view class="close-btn" @click="closeStaffSelector">
- <uni-icons type="closeempty" size="20" color="#999"></uni-icons>
- </view>
- </view>
-
- <view class="search-bar">
- <input
- class="search-input"
- placeholder="鎼滅储濮撳悕鎴栫數璇�"
- v-model="staffSearchKeyword"
- @input="onStaffSearch"
- />
- </view>
-
- <view class="filter-tabs">
- <view
- class="filter-tab"
- :class="{ active: staffFilterType === 'driver' }"
- @click="filterStaff('driver')"
- >
- 鍙告満
- </view>
- <view
- class="filter-tab"
- :class="{ active: staffFilterType === 'doctor' }"
- @click="filterStaff('doctor')"
- >
- 鍖荤敓
- </view>
- <view
- class="filter-tab"
- :class="{ active: staffFilterType === 'nurse' }"
- @click="filterStaff('nurse')"
- >
- 鎶ゅ+
- </view>
- </view>
-
- <scroll-view class="staff-list-scroll" scroll-y="true">
- <view
- class="staff-list-item"
- v-for="staff in filteredStaffList"
- :key="staff.userId"
- @click="toggleStaffSelection(staff)"
- >
- <view class="staff-item-info">
- <text class="staff-item-name">{{ staff.nickName }}</text>
- <text class="staff-item-dept">{{ staff.deptName }}</text>
- </view>
- <view class="staff-item-check">
- <uni-icons
- v-if="isStaffSelected(staff.userId)"
- type="checkmarkempty"
- size="24"
- color="#007AFF"
- ></uni-icons>
- </view>
- </view>
- <view v-if="filteredStaffList.length === 0" class="empty-tip">
- 鏆傛棤浜哄憳鏁版嵁
- </view>
- </scroll-view>
-
- <view class="popup-footer">
- <button class="confirm-btn" @click="confirmStaffSelection">纭畾(宸查�墈{ selectedStaff.length }})</button>
- </view>
- </view>
- </uni-popup>
</scroll-view>
</template>
@@ -280,7 +193,6 @@
import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
import { getTask, updateTask } from "@/api/task"
-import { listBranchUsers } from "@/api/system/user"
import { baiduDistanceByAddress } from "@/api/map"
import { calculateTransferPrice } from "@/api/price"
import MapSelector from './components/map-selector.vue'
@@ -289,6 +201,7 @@
import HospitalSelector from './components/HospitalSelector.vue'
import DiseaseSelector from './components/DiseaseSelector.vue'
import DepartureSelector from './components/DepartureSelector.vue'
+import StaffSelector from './components/StaffSelector.vue'
import distanceCalculator from '@/mixins/distanceCalculator.js'
export default {
@@ -300,7 +213,8 @@
OrganizationSelector,
HospitalSelector,
DiseaseSelector,
- DepartureSelector
+ DepartureSelector,
+ StaffSelector
},
mixins: [distanceCalculator],
data() {
@@ -325,10 +239,6 @@
departureLatitude: null,
selectedDiseases: [], // 宸查�夋嫨鐨勭梾鎯呭垪琛紙纭繚鍒濆鍖栦负绌烘暟缁勶級
selectedStaff: [], // 宸查�夋嫨鐨勪汉鍛樺垪琛紙纭繚鍒濆鍖栦负绌烘暟缁勶級
- allStaffList: [], // 鎵�鏈変汉鍛樺垪琛�
- filteredStaffList: [], // 杩囨护鍚庣殑浜哄憳鍒楄〃
- staffSearchKeyword: '', // 浜哄憳鎼滅储鍏抽敭璇�
- staffFilterType: 'driver', // 浜哄憳绛涢�夌被鍨�
taskForm: {
transferTime: '',
patient: {
@@ -375,7 +285,6 @@
if (options.id) {
this.taskId = options.id
this.loadTaskDetail()
- this.loadDeptStaff() // 鍔犺浇浜哄憳鍒楄〃
} else {
this.$modal.showToast('浠诲姟ID涓嶈兘涓虹┖')
setTimeout(() => {
@@ -627,154 +536,10 @@
// 缁勪欢宸茬粡閫氳繃 v-model 鏇存柊浜� selectedDiseases
},
- // 鍔犺浇褰撳墠鐢ㄦ埛鎵�鍦ㄥ垎鍏徃鐨勬墍鏈変汉鍛�
- loadDeptStaff() {
- console.log('寮�濮嬪姞杞戒汉鍛樺垪琛�')
-
- listBranchUsers().then(response => {
- console.log('浜哄憳鍒楄〃API鍝嶅簲:', response)
- const userList = response.data || []
- console.log('瑙f瀽鍑虹殑鐢ㄦ埛鍒楄〃:', userList, '鏁伴噺:', userList.length)
-
- this.allStaffList = userList.map(user => ({
- userId: user.userId,
- nickName: user.nickName,
- phonenumber: user.phonenumber,
- deptName: user.dept?.deptName || '',
- postName: user.posts && user.posts.length > 0 ? user.posts[0].postName : '',
- roleName: user.roles && user.roles.length > 0 ? user.roles[0].roleName : '',
- type: this.getUserType(user)
- }))
-
- console.log('澶勭悊鍚庣殑浜哄憳鍒楄〃:', this.allStaffList, '鏁伴噺:', this.allStaffList.length)
-
- this.filterStaffList()
- }).catch(error => {
- console.error('鍔犺浇浜哄憳鍒楄〃澶辫触:', error)
- this.$modal.showToast('鍔犺浇浜哄憳鍒楄〃澶辫触')
- })
- },
-
- // 鏍规嵁鐢ㄦ埛鐨勫矖浣嶆垨瑙掕壊鍒ゆ柇绫诲瀷
- getUserType(user) {
- const postName = user.posts && user.posts.length > 0 ? user.posts[0].postName : ''
- const roleName = user.roles && user.roles.length > 0 ? user.roles[0].roleName : ''
- const deptName = user.dept?.deptName || ''
-
- if (postName.includes('鍙告満') || roleName.includes('鍙告満') || deptName.includes('杞﹂槦') || deptName.includes('鍙告満')) {
- return 'driver'
- }
- if (postName.includes('鎶ゅ+') || roleName.includes('鎶ゅ+') || deptName.includes('鎶ゅ+')) {
- return 'nurse'
- }
- if (postName.includes('鍖荤敓') || roleName.includes('鍖荤敓') || deptName.includes('鍖荤敓')) {
- return 'doctor'
- }
- if (deptName.includes('鍖绘姢')) {
- return 'doctor'
- }
-
- return 'driver'
- },
-
- getUserTypeName(staffType) {
- switch(staffType) {
- case 'nurse':
- return '鎶ゅ+'
- case 'doctor':
- return '鍖荤敓'
- case 'driver':
- return '鍙告満'
- default:
- return '鍙告満'
- }
- },
-
- // 鏄剧ず浜哄憳閫夋嫨寮圭獥
- showStaffSelector() {
- this.$refs.staffPopup.open()
- this.filterStaffList()
- },
-
- // 鍏抽棴浜哄憳閫夋嫨寮圭獥
- closeStaffSelector() {
- this.$refs.staffPopup.close()
- this.staffSearchKeyword = ''
- this.staffFilterType = 'driver'
- },
-
- // 浜哄憳鎼滅储
- onStaffSearch(e) {
- this.staffSearchKeyword = e.detail.value
- this.filterStaffList()
- },
-
- // 绛涢�変汉鍛樼被鍨�
- filterStaff(type) {
- this.staffFilterType = type
- this.filterStaffList()
- },
-
- // 杩囨护浜哄憳鍒楄〃
- filterStaffList() {
- console.log('寮�濮嬭繃婊や汉鍛樺垪琛紝鍘熷鏁伴噺:', this.allStaffList.length)
- let list = [...this.allStaffList]
-
- // 鎸夌被鍨嬭繃婊�
- if (this.staffFilterType === 'driver') {
- list = list.filter(staff => staff.type === 'driver')
- } else if (this.staffFilterType === 'doctor') {
- list = list.filter(staff => staff.type === 'doctor')
- } else if (this.staffFilterType === 'nurse') {
- list = list.filter(staff => staff.type === 'nurse')
- }
-
- console.log('鎸夌被鍨嬭繃婊ゅ悗:', this.staffFilterType, '鏁伴噺:', list.length)
-
- // 鎸夊叧閿瘝鎼滅储
- if (this.staffSearchKeyword && this.staffSearchKeyword.trim() !== '') {
- const keyword = this.staffSearchKeyword.trim().toLowerCase()
- list = list.filter(staff => {
- return staff.nickName.toLowerCase().includes(keyword) ||
- (staff.phonenumber && staff.phonenumber.includes(keyword))
- })
- }
-
- console.log('鎸夊叧閿瘝杩囨护鍚庯紝鏁伴噺:', list.length)
-
- this.filteredStaffList = list
- },
-
- // 鍒囨崲浜哄憳閫変腑鐘舵��
- toggleStaffSelection(staff) {
- const index = this.selectedStaff.findIndex(s => s.userId === staff.userId)
-
- if (index > -1) {
- // 宸查�変腑锛岀Щ闄�
- this.selectedStaff.splice(index, 1)
- } else {
- // 鏈�変腑锛屾坊鍔�
- this.selectedStaff.push(staff)
- }
- },
-
- // 鍒ゆ柇浜哄憳鏄惁宸查�変腑
- isStaffSelected(userId) {
- return this.selectedStaff.some(staff => staff.userId === userId)
- },
-
- // 纭浜哄憳閫夋嫨
- confirmStaffSelection() {
- if (this.selectedStaff.length === 0) {
- this.$modal.showToast('璇疯嚦灏戦�夋嫨涓�鍚嶄汉鍛�')
- return
- }
- this.closeStaffSelector()
- },
-
- // 绉婚櫎浜哄憳
- removeStaff(index) {
- this.selectedStaff.splice(index, 1)
+ // 浜哄憳鍙樺寲
+ onStaffChange(staff) {
+ console.log('閫変腑浜哄憳鍙樺寲:', staff)
+ // 缁勪欢宸茬粡閫氳繃 v-model 鏇存柊浜� selectedStaff
},
// 瑙f瀽鐥呮儏淇℃伅锛堜粠瀛楃涓茶В鏋愬嚭ICD-10鐤剧梾鍒楄〃锛�- 淇锛氫笌鍒涘缓鐣岄潰淇濇寔涓�鑷�
@@ -1451,133 +1216,6 @@
display: flex;
align-items: center;
justify-content: center;
- }
- }
- }
-
- .staff-popup-container {
- height: 80vh;
- background-color: white;
- border-top-left-radius: 20rpx;
- border-top-right-radius: 20rpx;
- display: flex;
- flex-direction: column;
-
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
-
- .popup-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
-
- .close-btn {
- width: 50rpx;
- height: 50rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- }
-
- .search-bar {
- padding: 20rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
-
- .search-input {
- height: 70rpx;
- padding: 0 20rpx;
- background-color: #f5f5f5;
- border-radius: 10rpx;
- font-size: 28rpx;
- }
- }
-
- .filter-tabs {
- display: flex;
- padding: 20rpx 30rpx;
- gap: 20rpx;
- border-bottom: 1rpx solid #f0f0f0;
-
- .filter-tab {
- flex: 1;
- height: 60rpx;
- line-height: 60rpx;
- text-align: center;
- background-color: #f5f5f5;
- border-radius: 10rpx;
- font-size: 28rpx;
- color: #666;
-
- &.active {
- background-color: #007AFF;
- color: white;
- }
- }
- }
-
- .staff-list-scroll {
- flex: 1;
- padding: 20rpx 30rpx;
-
- .staff-list-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20rpx;
- margin-bottom: 15rpx;
- background-color: #f8f8f8;
- border-radius: 10rpx;
-
- .staff-item-info {
- flex: 1;
-
- .staff-item-name {
- display: block;
- font-size: 30rpx;
- color: #333;
- margin-bottom: 8rpx;
- }
-
- .staff-item-dept {
- display: block;
- font-size: 24rpx;
- color: #999;
- }
- }
-
- .staff-item-check {
- width: 50rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- }
-
- .empty-tip {
- text-align: center;
- padding: 100rpx 0;
- color: #999;
- font-size: 28rpx;
- }
- }
-
- .popup-footer {
- padding: 20rpx 30rpx;
- border-top: 1rpx solid #f0f0f0;
-
- .confirm-btn {
- width: 100%;
- height: 80rpx;
- background-color: #007AFF;
- color: white;
- border-radius: 10rpx;
- font-size: 32rpx;
}
}
}
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentNotifyService.java b/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentNotifyService.java
index c4a8ff4..506f6f5 100644
--- a/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentNotifyService.java
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentNotifyService.java
@@ -62,7 +62,7 @@
// 閫氫俊鎴愬姛涓斾笟鍔℃垚鍔�
if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
// 鏌ヨ璁㈠崟鍜屼氦鏄擄紙浣跨敤涓氬姟璁㈠崟鍙锋煡璇級
- PaymentOrder order = paymentOrderMapper.selectByBizOrderIdAndChannel(outTradeNo, "WECHAT");
+ PaymentOrder order = paymentOrderMapper.selectById(Long.parseLong(outTradeNo));
if (order == null) {
log.error("璁㈠崟涓嶅瓨鍦�: {}", outTradeNo);
updateNotifyLog(notifyLog.getId(), false, "璁㈠崟涓嶅瓨鍦�");
@@ -134,7 +134,7 @@
// 浜ゆ槗鎴愬姛
if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
// 鏌ヨ璁㈠崟鍜屼氦鏄擄紙浣跨敤涓氬姟璁㈠崟鍙锋煡璇級
- PaymentOrder order = paymentOrderMapper.selectByBizOrderIdAndChannel(outTradeNo, "ALIPAY");
+ PaymentOrder order = paymentOrderMapper.selectById(Long.parseLong(outTradeNo));
if (order == null) {
log.error("璁㈠崟涓嶅瓨鍦�: {}", outTradeNo);
updateNotifyLog(notifyLog.getId(), false, "璁㈠崟涓嶅瓨鍦�");
@@ -183,6 +183,276 @@
}
/**
+ * 澶勭悊绗笁鏂规敮浠樺疂鍥炶皟
+ * 绗笁鏂规敮浠樺疂閫氳繃GET鏂瑰紡鍥炶皟锛屽弬鏁伴�氳繃URL浼犻��
+ *
+ * 鍙傛暟鏍煎紡锛�
+ * method: 鏂规硶鍚�
+ * APPID: 搴旂敤ID
+ * PaidMoneyType: 鏀粯绫诲瀷
+ * PaidMoney: 鏀粯閲戦锛堝垎锛�
+ * PaidRemarks: 鏀粯澶囨敞锛堝寘鍚玹ransaction_id锛�
+ * UnixTime: 鏃堕棿鎴�
+ * Sign: 绛惧悕
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void processAlipayThirdPartyNotify(Map<String, String> params) {
+ String method = params.get("method"); // 鏂规硶鍚�
+ String appId = params.get("APPID"); // 搴旂敤ID
+ String paidMoneyType = params.get("PaidMoneyType"); // 鏀粯绫诲瀷
+ String paidMoney = params.get("PaidMoney"); // 鏀粯閲戦锛堝垎锛�
+ String paidRemarks = params.get("PaidRemarks"); // 鏀粯澶囨敞锛堝彲鑳藉寘鍚鍗曞彿鍜屼氦鏄撳彿锛�
+ String unixTime = params.get("UnixTime"); // 鏃堕棿鎴�
+ String sign = params.get("Sign"); // 绛惧悕
+
+ log.info("澶勭悊绗笁鏂规敮浠樺疂鍥炶皟锛宮ethod: {}, APPID: {}, PaidMoneyType: {}, PaidMoney: {}, PaidRemarks: {}, UnixTime: {}, Sign: {}",
+ method, appId, paidMoneyType, paidMoney, paidRemarks, unixTime, sign);
+ log.info("绗笁鏂规敮浠樺疂鍥炶皟瀹屾暣鍙傛暟: {}", params);
+
+ // 浠嶱aidRemarks涓彁鍙栬鍗曞彿锛坥ut_trade_no锛�
+ // PaidRemarks鏍煎紡鍙兘鏄�: "璁㈠崟鍙�+浜ゆ槗鍙�" 鎴栧叾浠栨牸寮忥紝闇�瑕佽В鏋�
+ String outTradeNo = extractOutTradeNo(paidRemarks);
+ String transactionId = extractTransactionId(paidRemarks);
+
+ if (outTradeNo == null || outTradeNo.isEmpty()) {
+ log.error("鏃犳硶浠嶱aidRemarks涓彁鍙栬鍗曞彿: {}", paidRemarks);
+ return;
+ }
+
+ log.info("瑙f瀽鍑鸿鍗曞彿: {}, 浜ゆ槗鍙�: {}", outTradeNo, transactionId);
+
+ // 妫�鏌ュ箓绛夋�э紙浣跨敤璁㈠崟鍙锋垨绛惧悕锛�
+ String notifyId = transactionId != null ? transactionId : sign;
+ if (isNotifyProcessed("ALIPAY_THIRD_PARTY", notifyId)) {
+ log.info("绗笁鏂规敮浠樺疂鍥炶皟宸插鐞嗚繃锛屾爣璇�: {}", notifyId);
+ return;
+ }
+
+ // 璁板綍鍥炶皟鏃ュ織
+ NotifyLog notifyLog = saveNotifyLog("ALIPAY_THIRD_PARTY", notifyId, JSON.toJSONString(params), true);
+
+ try {
+ // 绗笁鏂规敮浠樺疂鎴愬姛鐨勫垽鏂潯浠讹紙鏍规嵁瀹為檯鎯呭喌璋冩暣锛�
+ // 閫氬父鍙鑳芥敹鍒板洖璋冨氨琛ㄧず鏀粯鎴愬姛
+ if (paidMoney != null && Integer.parseInt(paidMoney) > 0) {
+ // 鏌ヨ璁㈠崟锛堜娇鐢ㄥ晢鎴疯鍗曞彿锛岃繖閲岀殑outTradeNo瀹為檯鏄垜浠殑璁㈠崟ID锛�
+ PaymentOrder order = paymentOrderMapper.selectById(Long.valueOf(outTradeNo));
+ if (order == null) {
+ log.error("璁㈠崟涓嶅瓨鍦�: {}", outTradeNo);
+ updateNotifyLog(notifyLog.getId(), false, "璁㈠崟涓嶅瓨鍦�");
+ return;
+ }
+
+ // 楠岃瘉閲戦鏄惁鍖归厤
+ if (!order.getAmount().equals(Integer.parseInt(paidMoney))) {
+ log.error("璁㈠崟閲戦涓嶅尮閰嶏紝璁㈠崟閲戦: {}, 鍥炶皟閲戦: {}", order.getAmount(), paidMoney);
+ updateNotifyLog(notifyLog.getId(), false, "閲戦涓嶅尮閰�");
+ return;
+ }
+
+ // 鏌ヨ寰呮敮浠樹氦鏄�
+ PaymentTransaction transaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
+ if (transaction == null) {
+ // 濡傛灉娌℃湁寰呮敮浠樹氦鏄擄紝灏濊瘯鏌ヨ鏈�鏂颁氦鏄�
+ transaction = paymentTransactionMapper.selectLatestByOrderId(order.getId());
+ if (transaction == null || "SUCCEEDED".equals(transaction.getStatus())) {
+ log.warn("浜ゆ槗宸插畬鎴愭垨涓嶅瓨鍦紝璁㈠崟ID: {}", order.getId());
+ updateNotifyLog(notifyLog.getId(), true, "浜ゆ槗宸插畬鎴�");
+ return;
+ }
+ }
+
+ // 鏇存柊浜ゆ槗鐘舵��
+ transaction.setStatus("SUCCEEDED");
+ if (transactionId != null) {
+ transaction.setChannelTradeNo(transactionId);
+ }
+ transaction.setPaidAt(LocalDateTime.now());
+ transaction.setResponseSnapshot(JSON.toJSONString(params));
+ paymentTransactionMapper.update(transaction);
+
+ // 鏇存柊璁㈠崟鐘舵��
+ order.setStatus("SUCCEEDED");
+ if (transactionId != null) {
+ order.setChannelTradeNo(transactionId);
+ }
+ order.setPaidAt(LocalDateTime.now());
+ order.setLatestTransactionId(transaction.getId());
+ paymentOrderMapper.update(order);
+
+ // 鏇存柊閫氱煡鏃ュ織
+ notifyLog.setOrderId(order.getId());
+ notifyLog.setTransactionId(transaction.getId());
+ updateNotifyLog(notifyLog.getId(), true, "澶勭悊鎴愬姛");
+
+ // 瑙﹀彂涓氬姟鍥炶皟
+ bizCallbackService.triggerCallback(order, transaction);
+
+ log.info("绗笁鏂规敮浠樺疂鍥炶皟澶勭悊鎴愬姛锛岃鍗旾D: {}, 浜ゆ槗ID: {}", order.getId(), transaction.getId());
+ } else {
+ log.warn("绗笁鏂规敮浠樺疂鏀粯閲戦寮傚父: {}", paidMoney);
+ updateNotifyLog(notifyLog.getId(), true, "閲戦寮傚父: " + paidMoney);
+ }
+ } catch (Exception e) {
+ log.error("澶勭悊绗笁鏂规敮浠樺疂鍥炶皟寮傚父", e);
+ updateNotifyLog(notifyLog.getId(), false, "澶勭悊寮傚父: " + e.getMessage());
+ throw e;
+ }
+ }
+
+ /**
+ * 浠嶱aidRemarks涓彁鍙栬鍗曞彿
+ * PaidRemarks鍙兘鍖呭惈璁㈠崟鍙峰拰浜ゆ槗鍙凤紝闇�瑕佽В鏋�
+ */
+ private String extractOutTradeNo(String paidRemarks) {
+ if (paidRemarks == null || paidRemarks.isEmpty()) {
+ return null;
+ }
+
+ // 鍋囪PaidRemarks鏍煎紡: "璁㈠崟鍙�+浜ゆ槗鍙�" 鎴� "璁㈠崟鍙�"
+ // 鏍规嵁瀹為檯鏍煎紡璋冩暣瑙f瀽閫昏緫
+ // 杩欓噷鍋囪璁㈠崟鍙峰湪鏈�鍓嶉潰锛屽彲鑳界敤鏌愪釜鍒嗛殧绗﹀垎闅�
+
+ // 灏濊瘯鎻愬彇绾暟瀛椾綔涓鸿鍗旾D
+ String[] parts = paidRemarks.split("[^0-9]+");
+ for (String part : parts) {
+ if (part.length() > 10) { // 璁㈠崟ID閫氬父鏄暱鏁村瀷锛岄暱搴﹁緝闀�
+ return part;
+ }
+ }
+
+ // 濡傛灉娌℃湁鎵惧埌锛岃繑鍥炴暣涓瓧绗︿覆鐨勬暟瀛楅儴鍒�
+ return paidRemarks.replaceAll("[^0-9]", "");
+ }
+
+ /**
+ * 浠嶱aidRemarks涓彁鍙栦氦鏄撳彿
+ */
+ private String extractTransactionId(String paidRemarks) {
+ if (paidRemarks == null || paidRemarks.isEmpty()) {
+ return null;
+ }
+
+ // 濡傛灉PaidRemarks鍖呭惈鏀粯瀹濅氦鏄撳彿锛堥�氬父浠�2寮�澶寸殑28浣嶆暟瀛楋級
+ // 杩欓噷绠�鍗曡繑鍥瀗ull锛屽彲浠ユ牴鎹疄闄呮牸寮忚皟鏁�
+ return null;
+ }
+
+ /**
+ * 澶勭悊绗笁鏂瑰井淇″洖璋�
+ * 绗笁鏂瑰井淇¢�氳繃GET鏂瑰紡鍥炶皟锛屽弬鏁伴�氳繃URL浼犻��
+ *
+ * 鍙傛暟鏍煎紡锛�
+ * method: 鏂规硶鍚�
+ * APPID: 搴旂敤ID
+ * PaidMoneyType: 鏀粯绫诲瀷
+ * PaidMoney: 鏀粯閲戦锛堝垎锛�
+ * PaidRemarks: 鏀粯澶囨敞锛堝寘鍚玹ransaction_id锛�
+ * UnixTime: 鏃堕棿鎴�
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void processWechatThirdPartyNotify(Map<String, String> params) {
+ String method = params.get("method"); // 鏂规硶鍚�
+ String appId = params.get("APPID"); // 搴旂敤ID
+ String paidMoneyType = params.get("PaidMoneyType"); // 鏀粯绫诲瀷
+ String paidMoney = params.get("PaidMoney"); // 鏀粯閲戦锛堝垎锛�
+ String paidRemarks = params.get("PaidRemarks"); // 鏀粯澶囨敞锛堝彲鑳藉寘鍚鍗曞彿鍜屼氦鏄撳彿锛�
+ String unixTime = params.get("UnixTime"); // 鏃堕棿鎴�
+
+ log.info("澶勭悊绗笁鏂瑰井淇″洖璋冿紝method: {}, APPID: {}, PaidMoneyType: {}, PaidMoney: {}, PaidRemarks: {}, UnixTime: {}",
+ method, appId, paidMoneyType, paidMoney, paidRemarks, unixTime);
+ log.info("绗笁鏂瑰井淇″洖璋冨畬鏁村弬鏁�: {}", params);
+
+ // 浠嶱aidRemarks涓彁鍙栬鍗曞彿锛坥ut_trade_no锛�
+ String outTradeNo = extractOutTradeNo(paidRemarks);
+ String transactionId = extractTransactionId(paidRemarks);
+
+ if (outTradeNo == null || outTradeNo.isEmpty()) {
+ log.error("鏃犳硶浠嶱aidRemarks涓彁鍙栬鍗曞彿: {}", paidRemarks);
+ return;
+ }
+
+ log.info("瑙f瀽鍑鸿鍗曞彿: {}, 浜ゆ槗鍙�: {}", outTradeNo, transactionId);
+
+ // 妫�鏌ュ箓绛夋�э紙浣跨敤璁㈠崟鍙锋垨鏃堕棿鎴筹級
+ String notifyId = transactionId != null ? transactionId : (outTradeNo + "_" + unixTime);
+ if (isNotifyProcessed("WECHAT_THIRD_PARTY", notifyId)) {
+ log.info("绗笁鏂瑰井淇″洖璋冨凡澶勭悊杩囷紝鏍囪瘑: {}", notifyId);
+ return;
+ }
+
+ // 璁板綍鍥炶皟鏃ュ織
+ NotifyLog notifyLog = saveNotifyLog("WECHAT_THIRD_PARTY", notifyId, JSON.toJSONString(params), true);
+
+ try {
+ // 绗笁鏂瑰井淇℃垚鍔熺殑鍒ゆ柇鏉′欢锛堥�氬父鍙鑳芥敹鍒板洖璋冨氨琛ㄧず鏀粯鎴愬姛锛�
+ if (paidMoney != null && Integer.parseInt(paidMoney) > 0) {
+ // 鏌ヨ璁㈠崟锛堜娇鐢ㄥ晢鎴疯鍗曞彿锛岃繖閲岀殑outTradeNo瀹為檯鏄垜浠殑璁㈠崟ID锛�
+ PaymentOrder order = paymentOrderMapper.selectById(Long.valueOf(outTradeNo));
+ if (order == null) {
+ log.error("璁㈠崟涓嶅瓨鍦�: {}", outTradeNo);
+ updateNotifyLog(notifyLog.getId(), false, "璁㈠崟涓嶅瓨鍦�");
+ return;
+ }
+
+ // 楠岃瘉閲戦鏄惁鍖归厤
+ if (!order.getAmount().equals(Integer.parseInt(paidMoney))) {
+ log.error("璁㈠崟閲戦涓嶅尮閰嶏紝璁㈠崟閲戦: {}, 鍥炶皟閲戦: {}", order.getAmount(), paidMoney);
+ updateNotifyLog(notifyLog.getId(), false, "閲戦涓嶅尮閰�");
+ return;
+ }
+
+ // 鏌ヨ寰呮敮浠樹氦鏄�
+ PaymentTransaction transaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
+ if (transaction == null) {
+ // 濡傛灉娌℃湁寰呮敮浠樹氦鏄擄紝灏濊瘯鏌ヨ鏈�鏂颁氦鏄�
+ transaction = paymentTransactionMapper.selectLatestByOrderId(order.getId());
+ if (transaction == null || "SUCCEEDED".equals(transaction.getStatus())) {
+ log.warn("浜ゆ槗宸插畬鎴愭垨涓嶅瓨鍦紝璁㈠崟ID: {}", order.getId());
+ updateNotifyLog(notifyLog.getId(), true, "浜ゆ槗宸插畬鎴�");
+ return;
+ }
+ }
+
+ // 鏇存柊浜ゆ槗鐘舵��
+ transaction.setStatus("SUCCEEDED");
+ if (transactionId != null) {
+ transaction.setChannelTradeNo(transactionId);
+ }
+ transaction.setPaidAt(LocalDateTime.now());
+ transaction.setResponseSnapshot(JSON.toJSONString(params));
+ paymentTransactionMapper.update(transaction);
+
+ // 鏇存柊璁㈠崟鐘舵��
+ order.setStatus("SUCCEEDED");
+ if (transactionId != null) {
+ order.setChannelTradeNo(transactionId);
+ }
+ order.setPaidAt(LocalDateTime.now());
+ order.setLatestTransactionId(transaction.getId());
+ paymentOrderMapper.update(order);
+
+ // 鏇存柊閫氱煡鏃ュ織
+ notifyLog.setOrderId(order.getId());
+ notifyLog.setTransactionId(transaction.getId());
+ updateNotifyLog(notifyLog.getId(), true, "澶勭悊鎴愬姛");
+
+ // 瑙﹀彂涓氬姟鍥炶皟
+ bizCallbackService.triggerCallback(order, transaction);
+
+ log.info("绗笁鏂瑰井淇″洖璋冨鐞嗘垚鍔燂紝璁㈠崟ID: {}, 浜ゆ槗ID: {}", order.getId(), transaction.getId());
+ } else {
+ log.warn("绗笁鏂瑰井淇℃敮浠橀噾棰濆紓甯�: {}", paidMoney);
+ updateNotifyLog(notifyLog.getId(), true, "閲戦寮傚父: " + paidMoney);
+ }
+ } catch (Exception e) {
+ log.error("澶勭悊绗笁鏂瑰井淇″洖璋冨紓甯�", e);
+ updateNotifyLog(notifyLog.getId(), false, "澶勭悊寮傚父: " + e.getMessage());
+ throw e;
+ }
+ }
+
+ /**
* 妫�鏌ラ�氱煡鏄惁宸插鐞嗭紙骞傜瓑鎬э級
*/
private boolean isNotifyProcessed(String channel, String notifyId) {
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentService.java b/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentService.java
index 3b44a9b..98f9c28 100644
--- a/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentService.java
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/application/service/PaymentService.java
@@ -12,6 +12,7 @@
import com.ruoyi.payment.infrastructure.channel.wechat.WxPayV2Client;
import com.ruoyi.payment.infrastructure.config.AlipayConfig;
import com.ruoyi.payment.infrastructure.config.QrCodeConfig;
+import com.ruoyi.payment.infrastructure.config.WechatPayConfig;
import com.ruoyi.payment.infrastructure.persistence.mapper.PaymentOrderMapper;
import com.ruoyi.payment.infrastructure.persistence.mapper.PaymentTransactionMapper;
import com.ruoyi.payment.infrastructure.util.QrCodeUtil;
@@ -60,6 +61,9 @@
@Autowired
private AlipayConfig alipayConfig;
+ @Autowired
+ private WechatPayConfig wechatPayConfig;
+
/**
* 鍙戣捣寰俊Native鏀粯
*/
@@ -99,6 +103,7 @@
requestParams.put("bizOrderId", request.getBizOrderId());
requestParams.put("amount", request.getAmount());
requestParams.put("subject", request.getSubject());
+ requestParams.put("notifyUrl",wechatPayConfig.getNotifyUrl());
transaction.setRequestParams(JSON.toJSONString(requestParams));
paymentTransactionMapper.insert(transaction);
@@ -150,6 +155,7 @@
requestParams.put("bizOrderId", request.getBizOrderId());
requestParams.put("amount", request.getAmount());
requestParams.put("subject", request.getSubject());
+ requestParams.put("notifyUrl",alipayConfig.getNotifyUrl());
transaction.setRequestParams(JSON.toJSONString(requestParams));
paymentTransactionMapper.insert(transaction);
@@ -202,6 +208,7 @@
requestParams.put("amount", request.getAmount());
requestParams.put("subject", request.getSubject());
requestParams.put("thirdParty", true);
+ requestParams.put("notifyUrl",alipayConfig.getThirdParty().getDefaultNotifyUrl());
transaction.setRequestParams(JSON.toJSONString(requestParams));
paymentTransactionMapper.insert(transaction);
@@ -283,11 +290,11 @@
private String callAlipayThirdPartyPrecreate(PaymentOrder order, PaymentRequest request) {
try {
// 浣跨敤AlipayConfig涓厤缃殑鍥炶皟鍦板潃
- String notifyUrl = alipayConfig.getNotifyUrl();
+ String notifyUrl = alipayConfig.getThirdParty().getDefaultNotifyUrl();
String outTradeNo = String.valueOf(order.getId());
Integer totalFee = order.getAmount(); // 鍗曚綅锛氬垎
String serviceOrdId = request.getBizOrderId(); // 涓氬姟璁㈠崟ID
-
+
return alipayThirdPartyClient.createQrCodeUrl(notifyUrl, outTradeNo, totalFee, serviceOrdId);
} catch (Exception e) {
log.error("璋冪敤绗笁鏂规敮浠樺疂鎺ュ彛澶辫触", e);
@@ -335,4 +342,298 @@
throw new RuntimeException("鏌ヨ浜ゆ槗鐘舵�佸け璐�: " + e.getMessage(), e);
}
}
-}
+
+ /**
+ * 杞鏌ヨ鏀粯鐘舵�侊紙鐢ㄤ簬鍥炶皟澶辫触鐨勮ˉ鍋挎満鍒讹級
+ * 鏀寔寰俊鍜屾敮浠樺疂
+ *
+ * @param orderId 璁㈠崟ID
+ * @return 杞缁撴灉锛堝寘鍚鍗曠姸鎬佸拰浜ゆ槗鐘舵�侊級
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public Map<String, Object> pollPaymentStatus(Long orderId) {
+ log.info("寮�濮嬭疆璇㈡煡璇㈡敮浠樼姸鎬侊紝璁㈠崟ID: {}", orderId);
+
+ Map<String, Object> result = new HashMap<>();
+
+ // 1. 鏌ヨ璁㈠崟淇℃伅
+ PaymentOrder order = paymentOrderMapper.selectById(orderId);
+ if (order == null) {
+ log.error("璁㈠崟涓嶅瓨鍦紝璁㈠崟ID: {}", orderId);
+ throw new RuntimeException("璁㈠崟涓嶅瓨鍦�");
+ }
+
+ // 濡傛灉璁㈠崟宸茬粡鏄垚鍔熺姸鎬侊紝鐩存帴杩斿洖
+ if (OrderStatus.SUCCEEDED.getCode().equals(order.getStatus())) {
+ log.info("璁㈠崟宸叉垚鍔燂紝鏃犻渶杞锛岃鍗旾D: {}", orderId);
+ result.put("orderStatus", order.getStatus());
+ result.put("needPoll", false);
+ result.put("message", "璁㈠崟宸叉垚鍔�");
+ return result;
+ }
+
+ // 2. 鏌ヨ鏈�鏂颁氦鏄撹褰�
+ PaymentTransaction transaction = paymentTransactionMapper.selectLatestByOrderId(orderId);
+ if (transaction == null) {
+ log.error("鏈壘鍒颁氦鏄撹褰曪紝璁㈠崟ID: {}", orderId);
+ throw new RuntimeException("鏈壘鍒颁氦鏄撹褰�");
+ }
+
+ // 濡傛灉浜ゆ槗宸叉垚鍔燂紝浣嗚鍗曠姸鎬佹湭鏇存柊锛屾洿鏂拌鍗曠姸鎬�
+ if (TransactionStatus.SUCCEEDED.getCode().equals(transaction.getStatus())) {
+ log.info("浜ゆ槗宸叉垚鍔燂紝鍚屾璁㈠崟鐘舵�侊紝璁㈠崟ID: {}", orderId);
+ order.setStatus(OrderStatus.SUCCEEDED.getCode());
+ order.setUpdatedAt(LocalDateTime.now());
+ paymentOrderMapper.update(order);
+
+ result.put("orderStatus", OrderStatus.SUCCEEDED.getCode());
+ result.put("transactionStatus", transaction.getStatus());
+ result.put("needPoll", false);
+ result.put("message", "鏀粯鎴愬姛");
+ return result;
+ }
+
+ // 3. 鏍规嵁鏀粯娓犻亾璋冪敤鐩稿簲鐨勬煡璇㈡帴鍙�
+ String channel = order.getChannel();
+ boolean paymentSuccess = false;
+ String tradeStatus = null;
+
+ try {
+ if (PayChannel.WECHAT.getCode().equals(channel)) {
+ // 鏌ヨ寰俊鏀粯鐘舵��
+ paymentSuccess = queryWechatPaymentStatus(order, transaction);
+ tradeStatus = paymentSuccess ? "SUCCESS" : "NOTPAY";
+ result.put("paymethod","WECHAT");
+ } else if (PayChannel.ALIPAY.getCode().equals(channel)) {
+ // 鍒ゆ柇鏄惁涓虹涓夋柟鏀粯瀹�
+ boolean isThirdParty = isThirdPartyAlipay(transaction);
+ result.put("paymethod","ALIPAY");
+ if (isThirdParty) {
+ // 鏌ヨ绗笁鏂规敮浠樺疂鐘舵��
+ tradeStatus = queryAlipayThirdPartyTradeStatus(orderId);
+ paymentSuccess = "SUCCESS".equals(tradeStatus);
+ } else {
+ // 鏌ヨ瀹樻柟鏀粯瀹濈姸鎬�
+ paymentSuccess = queryAlipayPaymentStatus(order, transaction);
+ tradeStatus = paymentSuccess ? "TRADE_SUCCESS" : "WAIT_BUYER_PAY";
+ }
+ } else {
+ log.error("涓嶆敮鎸佺殑鏀粯娓犻亾: {}", channel);
+ throw new RuntimeException("涓嶆敮鎸佺殑鏀粯娓犻亾");
+ }
+ } catch (Exception e) {
+ log.error("鏌ヨ鏀粯鐘舵�佸紓甯革紝璁㈠崟ID: {}", orderId, e);
+ result.put("orderStatus", order.getStatus());
+ result.put("transactionStatus", transaction.getStatus());
+ result.put("needPoll", true);
+ result.put("error", e.getMessage());
+ result.put("message", "鏌ヨ寮傚父锛岃绋嶅悗閲嶈瘯");
+ return result;
+ }
+
+ // 4. 濡傛灉鏀粯鎴愬姛锛屾洿鏂拌鍗曞拰浜ゆ槗鐘舵��
+ if (paymentSuccess) {
+ log.info("杞鏌ヨ鍙戠幇鏀粯鎴愬姛锛岃鍗旾D: {}, 浜ゆ槗鐘舵��: {}", orderId, tradeStatus);
+
+ // 鏇存柊浜ゆ槗鐘舵��
+ transaction.setStatus(TransactionStatus.SUCCEEDED.getCode());
+ transaction.setPaidAt(LocalDateTime.now());
+ paymentTransactionMapper.update(transaction);
+
+ // 鏇存柊璁㈠崟鐘舵��
+ order.setStatus(OrderStatus.SUCCEEDED.getCode());
+ order.setUpdatedAt(LocalDateTime.now());
+ paymentOrderMapper.update(order);
+
+ result.put("orderStatus", OrderStatus.SUCCEEDED.getCode());
+ result.put("transactionStatus", TransactionStatus.SUCCEEDED.getCode());
+ result.put("tradeStatus", tradeStatus);
+ result.put("needPoll", false);
+ result.put("message", "鏀粯鎴愬姛");
+
+ log.info("杞鏌ヨ澶勭悊瀹屾垚锛岃鍗曞拰浜ゆ槗鐘舵�佸凡鏇存柊锛岃鍗旾D: {}", orderId);
+ } else {
+ log.info("杞鏌ヨ锛屾敮浠樺皻鏈畬鎴愶紝璁㈠崟ID: {}, 浜ゆ槗鐘舵��: {}", orderId, tradeStatus);
+ result.put("orderStatus", order.getStatus());
+ result.put("transactionStatus", transaction.getStatus());
+ result.put("tradeStatus", tradeStatus);
+ result.put("needPoll", true);
+ result.put("message", "鏀粯灏氭湭瀹屾垚锛岃缁х画杞");
+ }
+
+ return result;
+ }
+
+ /**
+ * 鏌ヨ寰俊鏀粯鐘舵��
+ */
+ private boolean queryWechatPaymentStatus(PaymentOrder order, PaymentTransaction transaction) throws Exception {
+ log.info("鏌ヨ寰俊鏀粯鐘舵�侊紝璁㈠崟ID: {}", order.getId());
+
+ String outTradeNo = String.valueOf(order.getId());
+ Map<String, String> queryResult = wxPayV2Client.queryOrder(outTradeNo);
+
+ // 妫�鏌ヤ笟鍔$粨鏋�
+ if (!"SUCCESS".equals(queryResult.get("result_code"))) {
+ log.warn("寰俊璁㈠崟鏌ヨ涓氬姟澶辫触: {}", queryResult.get("err_code_des"));
+ return false;
+ }
+
+ // 妫�鏌ヤ氦鏄撶姸鎬�
+ String tradeState = queryResult.get("trade_state");
+ log.info("寰俊璁㈠崟鐘舵��: {}", tradeState);
+
+ return "SUCCESS".equals(tradeState);
+ }
+
+ /**
+ * 鏌ヨ鏀粯瀹濇敮浠樼姸鎬侊紙瀹樻柟鎺ュ彛锛�
+ */
+ private boolean queryAlipayPaymentStatus(PaymentOrder order, PaymentTransaction transaction) throws Exception {
+ log.info("鏌ヨ鏀粯瀹濇敮浠樼姸鎬侊紝璁㈠崟ID: {}", order.getId());
+
+ String outTradeNo = String.valueOf(order.getId());
+ com.alipay.api.response.AlipayTradeQueryResponse queryResult = alipayF2FClient.queryOrder(outTradeNo);
+
+ // 妫�鏌ヤ氦鏄撶姸鎬�
+ String tradeStatus = queryResult.getTradeStatus();
+ log.info("鏀粯瀹濊鍗曠姸鎬�: {}", tradeStatus);
+ log.info("鏀粯瀹濊鍗曟煡璇㈢粨鏋�: {}", queryResult.getBody());
+ // TRADE_SUCCESS 鎴� TRADE_FINISHED 琛ㄧず鏀粯鎴愬姛
+ return "TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus);
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁涓虹涓夋柟鏀粯瀹�
+ */
+ private boolean isThirdPartyAlipay(PaymentTransaction transaction) {
+ if (transaction.getRequestParams() == null) {
+ return false;
+ }
+ try {
+ Map<String, Object> params = JSON.parseObject(transaction.getRequestParams(), Map.class);
+ return params.containsKey("thirdParty") && Boolean.TRUE.equals(params.get("thirdParty"));
+ } catch (Exception e) {
+ log.warn("瑙f瀽浜ゆ槗璇锋眰鍙傛暟澶辫触", e);
+ return false;
+ }
+ }
+
+ /**
+ * 鏍规嵁浜ゆ槗鍗曞彿鏌ヨ寰俊鏀粯鐘舵��
+ *
+ * @param outTradeNo 鍟嗘埛璁㈠崟鍙凤紙浜ゆ槗鍗曞彿锛�
+ * @return 浜ゆ槗鐘舵�佷俊鎭�
+ */
+ public Map<String, Object> queryWechatTradeByOutTradeNo(String outTradeNo) {
+ log.info("鏍规嵁浜ゆ槗鍗曞彿鏌ヨ寰俊鏀粯鐘舵�侊紝鍟嗘埛璁㈠崟鍙�: {}", outTradeNo);
+
+ Map<String, Object> result = new HashMap<>();
+
+ try {
+ Map<String, String> queryResult = wxPayV2Client.queryOrder(outTradeNo);
+
+ // 妫�鏌ヨ皟鐢ㄦ槸鍚︽垚鍔�
+ if (!"SUCCESS".equals(queryResult.get("return_code"))) {
+ result.put("success", false);
+ result.put("message", "寰俊鏌ヨ鎺ュ彛璋冪敤澶辫触: " + queryResult.get("return_msg"));
+ return result;
+ }
+
+ // 妫�鏌ヤ笟鍔$粨鏋�
+ if (!"SUCCESS".equals(queryResult.get("result_code"))) {
+ result.put("success", false);
+ result.put("message", "寰俊璁㈠崟鏌ヨ涓氬姟澶辫触: " + queryResult.get("err_code_des"));
+ result.put("errorCode", queryResult.get("err_code"));
+ return result;
+ }
+
+ // 杩斿洖浜ゆ槗淇℃伅
+ result.put("success", true);
+ result.put("tradeState", queryResult.get("trade_state")); // 浜ゆ槗鐘舵��
+ result.put("tradeStateDesc", queryResult.get("trade_state_desc")); // 浜ゆ槗鐘舵�佹弿杩�
+ result.put("outTradeNo", queryResult.get("out_trade_no")); // 鍟嗘埛璁㈠崟鍙�
+ result.put("transactionId", queryResult.get("transaction_id")); // 寰俊鏀粯璁㈠崟鍙�
+ result.put("totalFee", queryResult.get("total_fee")); // 璁㈠崟閲戦锛堝垎锛�
+ result.put("timeEnd", queryResult.get("time_end")); // 鏀粯瀹屾垚鏃堕棿
+ result.put("openid", queryResult.get("openid")); // 鐢ㄦ埛鏍囪瘑
+
+ // 鍒ゆ柇鏄惁鏀粯鎴愬姛
+ boolean isPaid = "SUCCESS".equals(queryResult.get("trade_state"));
+ result.put("isPaid", isPaid);
+ result.put("message", isPaid ? "鏀粯鎴愬姛" : "鏀粯鏈畬鎴�");
+
+ log.info("寰俊浜ゆ槗鏌ヨ鎴愬姛锛屼氦鏄撶姸鎬�: {}", queryResult.get("trade_state"));
+
+ } catch (Exception e) {
+ log.error("鏌ヨ寰俊浜ゆ槗鐘舵�佸紓甯革紝鍟嗘埛璁㈠崟鍙�: {}", outTradeNo, e);
+ result.put("success", false);
+ result.put("message", "鏌ヨ寮傚父: " + e.getMessage());
+ }
+
+ return result;
+ }
+
+ /**
+ * 鏍规嵁浜ゆ槗鍗曞彿鏌ヨ鏀粯瀹濇敮浠樼姸鎬�
+ *
+ * @param outTradeNo 鍟嗘埛璁㈠崟鍙凤紙浜ゆ槗鍗曞彿锛�
+ * @return 浜ゆ槗鐘舵�佷俊鎭�
+ */
+ public Map<String, Object> queryAlipayTradeByOutTradeNo(String outTradeNo) {
+ log.info("鏍规嵁浜ゆ槗鍗曞彿鏌ヨ鏀粯瀹濇敮浠樼姸鎬侊紝鍟嗘埛璁㈠崟鍙�: {}", outTradeNo);
+
+ Map<String, Object> result = new HashMap<>();
+
+ try {
+ com.alipay.api.response.AlipayTradeQueryResponse queryResult = alipayF2FClient.queryOrder(outTradeNo);
+
+ // 妫�鏌ヨ皟鐢ㄦ槸鍚︽垚鍔�
+ if (!queryResult.isSuccess()) {
+ result.put("success", false);
+ result.put("message", "鏀粯瀹濇煡璇㈠け璐�: " + queryResult.getSubMsg());
+ result.put("errorCode", queryResult.getSubCode());
+ return result;
+ }
+
+ // 杩斿洖浜ゆ槗淇℃伅
+ result.put("success", true);
+ result.put("tradeStatus", queryResult.getTradeStatus()); // 浜ゆ槗鐘舵��
+ result.put("outTradeNo", queryResult.getOutTradeNo()); // 鍟嗘埛璁㈠崟鍙�
+ result.put("tradeNo", queryResult.getTradeNo()); // 鏀粯瀹濅氦鏄撳彿
+ result.put("totalAmount", queryResult.getTotalAmount()); // 璁㈠崟閲戦锛堝厓锛�
+ result.put("buyerPayAmount", queryResult.getBuyerPayAmount()); // 涔板瀹為檯鏀粯閲戦
+ result.put("sendPayDate", queryResult.getSendPayDate()); // 浜ゆ槗鏀粯鏃堕棿
+ result.put("buyerLogonId", queryResult.getBuyerLogonId()); // 涔板鏀粯瀹濊处鍙�
+
+ // 鍒ゆ柇鏄惁鏀粯鎴愬姛
+ String tradeStatus = queryResult.getTradeStatus();
+ boolean isPaid = "TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus);
+ result.put("isPaid", isPaid);
+
+ // 鐘舵�佽鏄�
+ String message;
+ if ("TRADE_SUCCESS".equals(tradeStatus)) {
+ message = "浜ゆ槗鏀粯鎴愬姛";
+ } else if ("TRADE_FINISHED".equals(tradeStatus)) {
+ message = "浜ゆ槗缁撴潫锛屼笉鍙��娆�";
+ } else if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
+ message = "浜ゆ槗鍒涘缓锛岀瓑寰呬拱瀹朵粯娆�";
+ } else if ("TRADE_CLOSED".equals(tradeStatus)) {
+ message = "鏈粯娆句氦鏄撹秴鏃跺叧闂紝鎴栨敮浠樺畬鎴愬悗鍏ㄩ閫�娆�";
+ } else {
+ message = "鏈煡鐘舵��: " + tradeStatus;
+ }
+ result.put("message", message);
+
+ log.info("鏀粯瀹濅氦鏄撴煡璇㈡垚鍔燂紝浜ゆ槗鐘舵��: {}", tradeStatus);
+
+ } catch (Exception e) {
+ log.error("鏌ヨ鏀粯瀹濅氦鏄撶姸鎬佸紓甯革紝鍟嗘埛璁㈠崟鍙�: {}", outTradeNo, e);
+ result.put("success", false);
+ result.put("message", "鏌ヨ寮傚父: " + e.getMessage());
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/AlipayConfig.java b/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/AlipayConfig.java
index 1a22b6f..8252f42 100644
--- a/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/AlipayConfig.java
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/AlipayConfig.java
@@ -48,7 +48,7 @@
/** 绗笁鏂规帴鍙RL */
private String url = "https://sys.966120.com.cn/alipay_pay_QR_NotifyUrl.php";
/** 榛樿鍥炶皟鍦板潃 */
- private String defaultNotifyUrl = "https://dsp.966120.com.cn/alipay/pay_notify";
+ private String defaultNotifyUrl = "https://api.966120.com.cn/alipay/DspNotifyUrl.php";
/** 瓒呮椂鏃堕棿锛堟绉掞級 */
private int timeout = 30000;
}
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/ThirdPartyConfig.java b/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/ThirdPartyConfig.java
new file mode 100644
index 0000000..3d29e76
--- /dev/null
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/ThirdPartyConfig.java
@@ -0,0 +1,17 @@
+package com.ruoyi.payment.infrastructure.config;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ThirdPartyConfig implements Serializable {
+ /** 鏄惁鍚敤 */
+ private boolean enabled = false;
+ /** 绗笁鏂规帴鍙RL */
+ private String url = "https://sys.966120.com.cn/alipay_pay_QR_NotifyUrl.php";
+ /** 榛樿鍥炶皟鍦板潃 */
+ private String defaultNotifyUrl = "https://api.966120.com.cn/alipay/DspNotifyUrl.php";
+ /** 瓒呮椂鏃堕棿锛堟绉掞級 */
+ private int timeout = 30000;
+}
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/WechatPayConfig.java b/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/WechatPayConfig.java
index 7232142..c5fe88d 100644
--- a/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/WechatPayConfig.java
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/infrastructure/config/WechatPayConfig.java
@@ -33,4 +33,10 @@
/** 绛惧悕绫诲瀷 */
private String signType = "MD5";
+
+ /**
+ * 绗笁鏂规敮浠橀厤缃�
+ */
+ private ThirdPartyConfig thirdParty = new ThirdPartyConfig();
+
}
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentController.java b/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentController.java
index 311f0bd..e84292f 100644
--- a/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentController.java
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentController.java
@@ -33,6 +33,7 @@
/**
* 鍙戣捣寰俊Native鏀粯
*/
+ @Anonymous()
@PostMapping("/wechat/native")
public AjaxResult createWechatNativePayment(@Validated @RequestBody PaymentRequest request) {
try {
@@ -47,6 +48,7 @@
/**
* 鍙戣捣鏀粯瀹濆綋闈粯
*/
+ @Anonymous()
@PostMapping("/alipay/precreate")
public AjaxResult createAlipayPrecreate(@Validated @RequestBody PaymentRequest request) {
try {
@@ -61,6 +63,7 @@
/**
* 鍙戣捣鏀粯瀹濆綋闈粯锛堢涓夋柟鎺ュ彛锛�
*/
+ @Anonymous()
@PostMapping("/alipay/thirdparty/precreate")
public AjaxResult createAlipayThirdPartyPrecreate(@Validated @RequestBody PaymentRequest request) {
try {
@@ -75,6 +78,7 @@
/**
* 鏌ヨ璁㈠崟
*/
+ @Anonymous()
@GetMapping("/orders/{orderId}")
public AjaxResult getOrder(@PathVariable Long orderId) {
try {
@@ -92,6 +96,7 @@
/**
* 鏌ヨ鏈�鏂颁氦鏄�
*/
+ @Anonymous()
@GetMapping("/orders/{orderId}/transactions/latest")
public AjaxResult getLatestTransaction(@PathVariable Long orderId) {
try {
@@ -109,6 +114,7 @@
/**
* 鏌ヨ鏀粯瀹濈涓夋柟浜ゆ槗鐘舵��
*/
+ @Anonymous()
@GetMapping("/alipay/thirdparty/query/{orderId}")
public AjaxResult queryAlipayThirdPartyTradeStatus(@PathVariable Long orderId) {
try {
@@ -119,4 +125,92 @@
return AjaxResult.error("鏌ヨ澶辫触: " + e.getMessage());
}
}
-}
+
+ /**
+ * 杞鏌ヨ鏀粯鐘舵�侊紙鐢ㄤ簬鍥炶皟澶辫触鐨勮ˉ鍋挎満鍒讹級
+ * <p>
+ * 杩欎釜鎺ュ彛鐢ㄤ簬鍦ㄦ敮浠樺洖璋冩湭鎴愬姛鏃讹紝涓诲姩杞鏌ヨ鏀粯鐘舵�併��
+ * 鏀寔寰俊鍜屾敮浠樺疂锛堝寘鎷涓夋柟鏀粯瀹濓級銆�
+ * <p>
+ * 杩斿洖缁撴灉鍖呭惈锛�
+ * - orderStatus: 璁㈠崟鐘舵��
+ * - transactionStatus: 浜ゆ槗鐘舵��
+ * - tradeStatus: 绗笁鏂逛氦鏄撶姸鎬�
+ * - needPoll: 鏄惁闇�瑕佺户缁疆璇�
+ * - message: 鎻愮ず淇℃伅
+ * <p>
+ * 寤鸿杞绛栫暐锛�
+ * 1. 棣栨杞锛氱珛鍗宠疆璇�
+ * 2. 鍚庣画杞锛氶棿闅�3-5绉�
+ * 3. 鏈�澶氳疆璇�20娆★紝绾�100绉掑悗鍋滄
+ * 4. 濡傛灉 needPoll=false锛岃〃绀烘敮浠樺凡瀹屾垚鎴栫‘璁ゅけ璐ワ紝鏃犻渶缁х画杞
+ */
+ @Anonymous()
+ @GetMapping("/poll/{orderId}")
+ public AjaxResult pollPaymentStatus(@PathVariable Long orderId) {
+ try {
+ java.util.Map<String, Object> result = paymentService.pollPaymentStatus(orderId);
+ return AjaxResult.success(result);
+ } catch (Exception e) {
+ log.error("杞鏌ヨ鏀粯鐘舵�佸け璐�", e);
+ return AjaxResult.error("鏌ヨ澶辫触: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鏍规嵁浜ゆ槗鍗曞彿鏌ヨ寰俊鏀粯鐘舵��
+ * <p>
+ * 璇ユ帴鍙g敤浜庨�氳繃鍟嗘埛璁㈠崟鍙凤紙浜ゆ槗鍗曞彿锛夌洿鎺ユ煡璇㈠井淇℃敮浠樼姸鎬併��
+ * <p>
+ * 杩斿洖缁撴灉鍖呭惈锛�
+ * - success: 鏌ヨ鏄惁鎴愬姛
+ * - isPaid: 鏄惁宸叉敮浠�
+ * - tradeState: 浜ゆ槗鐘舵�侊紙SUCCESS-鏀粯鎴愬姛锛孨OTPAY-鏈敮浠橈紝CLOSED-宸插叧闂瓑锛�
+ * - transactionId: 寰俊鏀粯璁㈠崟鍙�
+ * - totalFee: 璁㈠崟閲戦锛堝垎锛�
+ * - timeEnd: 鏀粯瀹屾垚鏃堕棿
+ * - message: 鎻愮ず淇℃伅
+ *
+ * @param outTradeNo 鍟嗘埛璁㈠崟鍙凤紙浜ゆ槗鍗曞彿锛�
+ */
+ @Anonymous()
+ @GetMapping("/wechat/query/{outTradeNo}")
+ public AjaxResult queryWechatTrade(@PathVariable String outTradeNo) {
+ try {
+ java.util.Map<String, Object> result = paymentService.queryWechatTradeByOutTradeNo(outTradeNo);
+ return AjaxResult.success(result);
+ } catch (Exception e) {
+ log.error("鏌ヨ寰俊浜ゆ槗鐘舵�佸け璐ワ紝浜ゆ槗鍗曞彿: {}", outTradeNo, e);
+ return AjaxResult.error("鏌ヨ澶辫触: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 鏍规嵁浜ゆ槗鍗曞彿鏌ヨ鏀粯瀹濇敮浠樼姸鎬�
+ * <p>
+ * 璇ユ帴鍙g敤浜庨�氳繃鍟嗘埛璁㈠崟鍙凤紙浜ゆ槗鍗曞彿锛夌洿鎺ユ煡璇㈡敮浠樺疂鏀粯鐘舵�併��
+ * <p>
+ * 杩斿洖缁撴灉鍖呭惈锛�
+ * - success: 鏌ヨ鏄惁鎴愬姛
+ * - isPaid: 鏄惁宸叉敮浠�
+ * - tradeStatus: 浜ゆ槗鐘舵�侊紙TRADE_SUCCESS-鏀粯鎴愬姛锛學AIT_BUYER_PAY-绛夊緟浠樻锛孴RADE_CLOSED-宸插叧闂瓑锛�
+ * - tradeNo: 鏀粯瀹濅氦鏄撳彿
+ * - totalAmount: 璁㈠崟閲戦锛堝厓锛�
+ * - sendPayDate: 浜ゆ槗鏀粯鏃堕棿
+ * - buyerLogonId: 涔板鏀粯瀹濊处鍙�
+ * - message: 鎻愮ず淇℃伅
+ *
+ * @param outTradeNo 鍟嗘埛璁㈠崟鍙凤紙浜ゆ槗鍗曞彿锛�
+ */
+ @Anonymous()
+ @GetMapping("/alipay/query/{outTradeNo}")
+ public AjaxResult queryAlipayTrade(@PathVariable String outTradeNo) {
+ try {
+ java.util.Map<String, Object> result = paymentService.queryAlipayTradeByOutTradeNo(outTradeNo);
+ return AjaxResult.success(result);
+ } catch (Exception e) {
+ log.error("鏌ヨ鏀粯瀹濅氦鏄撶姸鎬佸け璐ワ紝浜ゆ槗鍗曞彿: {}", outTradeNo, e);
+ return AjaxResult.error("鏌ヨ澶辫触: " + e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentNotifyController.java b/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentNotifyController.java
index c8721a8..0a29962 100644
--- a/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentNotifyController.java
+++ b/dryad-payment/src/main/java/com/ruoyi/payment/interfaces/controller/PaymentNotifyController.java
@@ -37,7 +37,7 @@
* 寰俊鏀粯鍥炶皟
*/
@Anonymous
- @PostMapping("/wechat")
+ @PostMapping("/wechat/notify")
public String wechatNotify(HttpServletRequest request) {
try {
log.info("鎺ユ敹鍒板井淇℃敮浠樺洖璋�");
@@ -78,7 +78,7 @@
* 鏀粯瀹濆洖璋�
*/
@Anonymous
- @PostMapping("/alipay")
+ @PostMapping("/alipay/notify")
public String alipayNotify(HttpServletRequest request) {
try {
log.info("鎺ユ敹鍒版敮浠樺疂鍥炶皟");
@@ -113,6 +113,105 @@
}
/**
+ * 绗笁鏂规敮浠樺疂鍥炶皟锛圙ET璇锋眰锛�
+ * <p>
+ * 绗笁鏂规敮浠樺疂閫氳繃GET鏂瑰紡鍥炶皟锛屽弬鏁伴�氳繃URL浼犻��
+ * <p>
+ * 鍙傛暟鏍煎紡锛�
+ * method=xxx&APPID=xxx&PaidMoneyType=xxx&PaidMoney=xxx&PaidRemarks=xxx&UnixTime=xxx&Sign=xxx
+ * <p>
+ * 鍙傛暟璇存槑锛�
+ * - method: 鏂规硶鍚�
+ * - APPID: 搴旂敤ID
+ * - PaidMoneyType: 鏀粯绫诲瀷
+ * - PaidMoney: 鏀粯閲戦锛堝崟浣嶏細鍒嗭級
+ * - PaidRemarks: 鏀粯澶囨敞锛堝寘鍚鍗曞彿鍜屼氦鏄撳彿淇℃伅锛�
+ * - UnixTime: 鏃堕棿鎴�
+ * - Sign: 绛惧悕
+ * <p>
+ * 绀轰緥锛�
+ * GET /api/pay/notify/alipay/thirdparty?method=alipay.pay&APPID=123456&PaidMoneyType=alipay&PaidMoney=100&PaidRemarks=1234567890&UnixTime=1638360000&Sign=abc123
+ */
+ @Anonymous
+ @GetMapping("/alipay/thirdparty")
+ public String alipayThirdPartyNotify(HttpServletRequest request) {
+ try {
+ log.info("鎺ユ敹鍒扮涓夋柟鏀粯瀹濆洖璋冿紙GET璇锋眰锛�");
+
+ // 1. 鑾峰彇鎵�鏈夊弬鏁�
+ Map<String, String> params = new HashMap<>();
+ Enumeration<String> parameterNames = request.getParameterNames();
+ while (parameterNames.hasMoreElements()) {
+ String name = parameterNames.nextElement();
+ params.put(name, request.getParameter(name));
+ }
+
+ log.info("绗笁鏂规敮浠樺疂鍥炶皟鍙傛暟: {}", params);
+
+ // 2. 绗笁鏂规敮浠樺疂涓嶉渶瑕侀獙绛撅紝鎴栬�呮牴鎹涓夋柟骞冲彴鐨勭鍚嶈鍒欒繘琛岄獙璇�
+ // 杩欓噷鐩存帴澶勭悊锛屽鏋滈渶瑕侀獙绛惧彲浠ュ湪Service灞傛坊鍔�
+
+ // 3. 澶勭悊鍥炶皟锛堟洿鏂拌鍗曠姸鎬併�佽Е鍙戜笟鍔″洖璋冿級
+ paymentNotifyService.processAlipayThirdPartyNotify(params);
+
+ // 4. 杩斿洖绗笁鏂规敮浠樺疂瑕佹眰鐨勫簲绛�
+ return "success";
+ } catch (Exception e) {
+ log.error("澶勭悊绗笁鏂规敮浠樺疂鍥炶皟澶辫触", e);
+ return "fail";
+ }
+ }
+
+ /**
+ * 绗笁鏂瑰井淇″洖璋冿紙GET璇锋眰锛�
+ * <p>
+ * 绗笁鏂瑰井淇¢�氳繃GET鏂瑰紡鍥炶皟锛屽弬鏁伴�氳繃URL浼犻��
+ * <p>
+ * 鍙傛暟鏍煎紡锛�
+ * method=xxx&APPID=xxx&PaidMoneyType=xxx&PaidMoney=xxx&PaidRemarks=xxx&UnixTime=xxx
+ * <p>
+ * 鍙傛暟璇存槑锛�
+ * - method: 鏂规硶鍚�
+ * - APPID: 搴旂敤ID
+ * - PaidMoneyType: 鏀粯绫诲瀷
+ * - PaidMoney: 鏀粯閲戦锛堝崟浣嶏細鍒嗭級
+ * - PaidRemarks: 鏀粯澶囨敞锛堝寘鍚鍗曞彿鍜屼氦鏄撳彿淇℃伅锛�
+ * - UnixTime: 鏃堕棿鎴�
+ * <p>
+ * 绀轰緥锛�
+ * GET /api/pay/notify/wechat/thirdparty?method=wechat.pay&APPID=123456&PaidMoneyType=wechat&PaidMoney=100&PaidRemarks=1234567890&UnixTime=1638360000
+ */
+ @Anonymous
+ @GetMapping("/wechat/thirdparty")
+ public String wechatThirdPartyNotify(HttpServletRequest request) {
+ try {
+ log.info("鎺ユ敹鍒扮涓夋柟寰俊鍥炶皟锛圙ET璇锋眰锛�");
+
+ // 1. 鑾峰彇鎵�鏈夊弬鏁�
+ Map<String, String> params = new HashMap<>();
+ Enumeration<String> parameterNames = request.getParameterNames();
+ while (parameterNames.hasMoreElements()) {
+ String name = parameterNames.nextElement();
+ params.put(name, request.getParameter(name));
+ }
+
+ log.info("绗笁鏂瑰井淇″洖璋冨弬鏁�: {}", params);
+
+ // 2. 绗笁鏂瑰井淇′笉闇�瑕侀獙绛撅紝鎴栬�呮牴鎹涓夋柟骞冲彴鐨勭鍚嶈鍒欒繘琛岄獙璇�
+ // 杩欓噷鐩存帴澶勭悊锛屽鏋熼渶瑕侀獙绛惧彲浠ュ湪Service灞傛坊鍔�
+
+ // 3. 澶勭悊鍥炶皟锛堟洿鏂拌鍗曠姸鎬併�佽Е鍙戜笟鍔″洖璋冿級
+ paymentNotifyService.processWechatThirdPartyNotify(params);
+
+ // 4. 杩斿洖绗笁鏂瑰井淇¤姹傜殑搴旂瓟
+ return "success";
+ } catch (Exception e) {
+ log.error("澶勭悊绗笁鏂瑰井淇″洖璋冨け璐�", e);
+ return "fail";
+ }
+ }
+
+ /**
* 璇诲彇璇锋眰浣�
*/
private String readRequestBody(HttpServletRequest request) throws Exception {
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 21b8d9b..8ab857f 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -205,9 +205,14 @@
mchId: 1573728151
appName: 姘戣埅鍖荤枟蹇嚎
mchKey: Xz0ClPK3f5sCeT6SGTaha1vpVmyUFcbp
- notifyUrl: https://dsp.966120.com/api/pay/notify/wechat
+ notifyUrl: https://dsp.966120.com.cn/api/pay/notify/wechat/notify
signType: MD5
checkSign: false
+ thirdParty:
+ enabled: false
+ url: https://sys.966120.com.cn/alipay_pay_QR_NotifyUrl.php
+ defaultNotifyUrl: https://api.966120.com.cn/weixin/DspNotifyUrl.asp
+ timeout: 30000
# 鏀粯瀹濋厤缃�
alipay:
@@ -215,7 +220,7 @@
privateKey: MIIEpgIBAAKCAQEArt273bWTEPXPjCsUYwFx7CNjhcQlm1NtbNjfeIsZ2g9sbFCQP9qpyufp6zkBv6eq+6WEztkC1KwSsuDjP5LvgY/1pmGFlr8r7cjeZI4bTeIe9jG5UaHolnzbdXUlSoInzgWRvbYXxuQZciwVpokwviW27YK9wPIzz9OTiRquL8b3YWPZLO7xK0gBMa2KfFfUXxCB8gHJtidQ+FjjYXb2WpnScKLJdKfWcGWFnyGiZOknyFR9kI8cm0cYPNHtecQId0bQ1ee7YDLD8dBPd2Pd/JBC4Wn6HuOvZOLqZvIpIj+8q0zGXjUUns6MsjNL3MUKuhKy6hQGwP5sGrPcVcwqiwIDAQABAoIBAQCTeW9iSSsRx61VUlOsN+DDPQlHHCh3OcH0ZWb6e52+2Pkg1EUDhT9jX3lZJsfBwf8iofJCnKSVhdVzRNSCnkIdq7KJsn9+phW/QYPFnE+MvKJOEZtwLDNDD2PqSHS9xM0bJHlIXNTqqR6IuoM740HXa2k+H+A2ZE2r/YzUuUqkASwAYPKYzWa1wivg4CZrvoPZ5bXvYOHoV0jZEtyUQB9dHuCz+bghbR+28vGkYwEGInLsOCe6Gl5D61F0l2qAXRQky3P0jXxIPXPFmhBYutAAUufLpryruQgL3MDDm5dhBJpwp89qwFDjc8fWVS/FFYJ0KDQOpAxAI800YHgaJ4VBAoGBAOdCcoYS49Q9Iula7gFGVXeto7QSUsP0CnQZM/tsAU6TiX3XG5pxBYoVmYSIQPylgagRTBZHD5t/LGa+I+KYMHSVAH/kndPdgTO7EiwfUCzi1DmGZVWs7XJ2zRfTmYRVdsElPy3Z8Pm802jd7mhffw/5p6y9pzNJqOjmGOUbYGrrAoGBAMGS1CGHkK4nD2BsIWJoKW2Lxph3Bq5hN1iaE8ZjOAvFT9drNqfwRa6BVGyfYEXPZTvUT0FUNMdukcTCM6O3FRU8EABJIcVue2QA+BvkfwPEU3JxMA8DrWHO7IcgtG9wjbxretDsf+SZmkQgK0ZUPod5ZZSycFxM3/GiXDQjGhbhAoGBAL/Y/+j6AscvcKbmKEwmbQC7q/LWwJKPAZ0Oy3DoSK1G9+jNarjUyiOjh5fK8R6mrskekGBq0yfMeKlDU8HHP2t3sNJodgYs2+JubsTrtTeHdUfDlo1cyB8NL1d00wZVYA8bNy5yftavLzLv6bfsgRxfoBpNu0dw9A9B06U88N/BAoGBAKCN/nEJFlG8iB570Xzj1GjOJJzVLK96ZwOQWJKWPShWMhEFFkJZIhLJppKp5ppAmUD0qgAPre80oKdIRLin5E7GkKcMAXzWVHXv79qCvW8MagJkK25oqGiVzs2NrNs5yfXcV/PuFW4wkSmsXPhqa6rGYCDjmBqWkLDE8CE2dC9BAoGBAJ2+QfAAvB27mr48+vY4HxZyPRrCBA1YkokraWQ0IlfD0MKsFw0Af4Iu3oy7V6NlE2GwL/AcObyHeGZt7DLbViAQOgmb9BpUrjUZ4bXSBuGPfRe11HCu6j6W67qa76TAoy3A0Dfm0OE/m9r4H99NaLzeBm1KluySKkfYXoqyueQw
alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl8BjXYaudmGT+sEos0AXEUrKl6+wyw6++hBoJDdY7P+P7poa34GN4YSkkavTA/HplmRM1wTLcY+NqhxhLpNrcgy08AbC/GGcLM2wxQGFa+L+DQLz34uBAShXDK8yN6O49UdbbJ2RRaJSAb+nW4ZVCPMGtMu4S3lXTymQgizM1IYo9L92U5QPRzZRSP8+AmQPzwofRqEgvkO02s66xU2G5AAdkVg5BQm34eM0Io2CmcWF9jSoWQTJdyd7tw3oec9NqD7x3CfcsN3NAJOQLz4+bWWqDWelyviyAr2reeH6AuBVjaWwAvAJx3yuLevKMXTzPC95Ja7w4XYSB9Fg2+aKmwIDAQAB
serverUrl: https://openapi.alipay.com/gateway.do
- notifyUrl: https://dsp.966120.com/api/pay/notify/alipay
+ notifyUrl: https://dsp.966120.com.cn/api/pay/notify/alipay/notify
signType: RSA2
checkSign: false
# 鏀粯鏂瑰紡: OFFICIAL(瀹樻柟鏀粯瀹�) 鎴� THIRD_PARTY(绗笁鏂规敮浠樺疂)
@@ -224,7 +229,8 @@
thirdParty:
enabled: true
url: https://sys.966120.com.cn/alipay_pay_QR_NotifyUrl.php
- defaultNotifyUrl: https://dsp.966120.com.cn/alipay/pay_notify
+# defaultNotifyUrl: https://api.966120.com.cn/alipay/DspNotifyUrl.php
+ defaultNotifyUrl: https://dsp.966120.com.cn/api/pay/notify/alipay/notify
timeout: 30000
# 涓氬姟鍥炶皟閰嶇疆
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskPaymentServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskPaymentServiceImpl.java
index d527724..51c9d44 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskPaymentServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskPaymentServiceImpl.java
@@ -262,6 +262,7 @@
// 鐢熸垚鍥炶皟鍦板潃
String callbackUrl = callbackBaseUrl + "/payment/callback/" + provider.toLowerCase();
+
payment.setCallbackUrl(callbackUrl);
try {
--
Gitblit v1.9.1