doum
3 天以前 c5c4f201eedfcf374008238dce7afc84f8200ea4
代码初始化
已添加11个文件
已修改11个文件
1333 ■■■■■ 文件已修改
admin/src/api/business/refund.js 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaRefundWindow.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/orders.vue 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/refund.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/db/RefundPermissions.sql 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/java/com/doumee/api/business/RefundController.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/allinpay/syb/lib/DoumeeTLUtil.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/allinpay/syb/model/PayOrderNotifyParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/allinpay/syb/model/PayOrderParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/allinpay/syb/model/PayOrderRefundResponse.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/allinpay/syb/model/PayOrderResponse.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/allinpay/syb/model/PayPublicModel.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/biz/system/SystemDictDataBiz.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/biz/system/impl/SystemDictDataBizImpl.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/RefundMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Orders.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Refund.java 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/RefundService.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/RefundServiceImpl.java 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web/pages/success/success.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/refund.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/business/refund/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/business/refund/exportExcel', data, {
    download: true,
    trim: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/business/refund/create', data)
}
export function updateByPayStatus (data) {
  return request.post('/business/refund/updateByPayStatus', data)
}
export function cancel (id) {
  return request.get(`/business/refund/cancel?id=${id}`)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/business/refund/updateById', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/business/refund/delete/${id}`)
}
// åˆ é™¤
export function getById (id) {
  return request.get(`/business/refund/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/business/refund/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/components/business/OperaRefundWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
<template>
  <GlobalWindow
    :title="title"
    width="60%"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <div class="header">
      <div  class="header-b">订单信息</div>
      <div class="info-item"  >
        <div class="info-item-a">订单金额:<span class="orange"> ï¿¥{{((form.order.money||0)/100).toFixed(2)}}元</span></div>
        <div class="info-item-a">订单编号:<span>{{form.order.id }}</span></div>
        <div class="info-item-a">付款人:<span>{{form.order.name +'-' + form.order.phone}}</span></div>
      </div>
    </div>
    <el-form :model="form" ref="form" :rules="rules">
      <p class="tip-warn" ><i class="el-icon-warning"></i>说明:操作当前可退金额<span class="red">ï¿¥{{((form.balance||0)/100).toFixed(2)}}元</span>,请谨慎操作!</p>
      <el-form-item label="退款金额" prop="money">
        <el-input v-model="form.money" type="number" placeholder="退款金额" v-trim><template s></template></el-input>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" v-trim/>
      </el-form-item>
    </el-form>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'OperaOrdersWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        money: '',
        remark: '',
        orderId: '',
        balance: 0,
        order:{}
      },
      // éªŒè¯è§„则
      rules: {
        money: [{ required: true, message: '请输入退款金额' }]
      }
    }
  },
  created () {
    this.config({
      api: '/business/refund',
      'field.id': 'id'
    })
  }
}
</script>
<style scoped  lang="scss">
.table-pagination{
  position: fixed !important;
  bottom: 50px;
}
.header-b{
  display: inline-block;
  font-size: 16px;
  font-weight: bold;
}
.header-red-btn{
  display: inline-block;
  font-size: 12px;
  background-color:  red;
  padding: 2px 10px 3px 10px;
  margin-left: 20px;
  color: white;
  cursor: pointer;
  border-radius: 5px ;
}
.header-blue-btn{
  display: inline-block;
  font-size: 12px;
  background-color:  #216EEE;
  padding: 2px 10px 3px 10px;
  margin-left: 20px;
  color: white;
  cursor: pointer;
  border-radius: 5px ;
}
.header-grey{
  display: inline-block;
  font-size: 12px;
  border: 1px solid grey;
  padding: 2px 10px;
  margin-left: 20px;
  color: grey;
  border-radius: 5px ;
}
.header-orange{
  display: inline-block;
  font-size: 12px;
  border: 1px solid orange;
  padding: 2px 10px;
  margin-left: 20px;
  color: orange;
  border-radius: 5px ;
}
.header-btn{
  display: inline-block;
  border: none;
  padding: 2px 10px;
  margin-left: 20px;
}
.info-item{
  display: flex;
  width: 100%;
  margin: 15px;
}
.info-item-a{
  flex: 1;
  font-size: 14px;
}
.info-item-a span{
}
.info-item-a  .btn{
  font-size: 12px !important;
  cursor: pointer !important;
}
</style>
admin/src/views/business/orders.vue
@@ -84,18 +84,25 @@
            <span v-if="row.type==1">延期款</span>
          </template>
        </el-table-column>
        <el-table-column prop="money" label="已退款金额(元)" min-width="150px">
          <template slot-scope="{row}">
            <span class="red">{{((row.refundMoney || 0)/100).toFixed(2)}}</span>
          </template>
        </el-table-column>
        <el-table-column prop="remark" label="订单备注"  width="200px"  ></el-table-column>
        <el-table-column prop="userRealname" label="收款人姓名"  width="100px"  ></el-table-column>
        <el-table-column prop="username" label="负责人账号"  width="120px"  ></el-table-column>
        <el-table-column prop="createTime" label="创建时间" min-width="150px"></el-table-column>
        <el-table-column prop="payDate" label="付款时间" min-width="150px"></el-table-column>
        <el-table-column prop="cancelDate" label="取消时间" min-width="150px"></el-table-column>
  <el-table-column
       <el-table-column
          label="操作"
          align="center"
          min-width="100"
          min-width="180"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" v-if="row.status==1&&(row.money-(row.refundMoney||0)) >1"  @click="sendRefund(row)" icon="el-icon-edit" v-permissions="['business:refund:create']">退款</el-button>
            <el-button type="text"   @click="payStatus(row)" icon="el-icon-refresh" v-permissions="['business:orders:update']">同步状态</el-button>
          </template>
        </el-table-column>
@@ -109,6 +116,7 @@
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaOrderDetailWindow ref="OperaOrderDetailWindow" @success="handlePageChange"/>
    <OperaRefundWindow ref="OperaRefundWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
@@ -117,11 +125,12 @@
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaOrderDetailWindow from '@/components/business/OperaOrderDetailWindow'
import OperaRefundWindow from '@/components/business/OperaRefundWindow'
import { cancel } from '@/api/business/orders'
export default {
  name: 'Orders',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaOrderDetailWindow },
  components: { TableLayout, Pagination, OperaOrderDetailWindow, OperaRefundWindow },
  data () {
    return {
      // æœç´¢
@@ -168,11 +177,19 @@
            })
        })
    },
    sendRefund (row) {
      var balance = row.money - (row.refundMoney || 0)
      if (balance < 1) {
        this.$message.error('该订单已无可退款余额')
        return
      }
      this.$refs.OperaRefundWindow.open('发起退款', { orderId: row.id, balance: balance ,order:row})
    },
    payStatus (row) {
      this.$dialog.actionConfirm('您确认【同步】该订单最新状态吗?', '操作确认')
        .then(() => {
          this.dealing = true
          this.api.updateByPayStatus({id:row.id})
          this.api.updateByPayStatus({ id: row.id })
            .then(res => {
              this.$tip.apiSuccess('操作成功')
              this.search()
admin/src/views/business/refund.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,179 @@
<template>
  <TableLayout :permissions="['business:refund:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="" prop="id">
        <el-input v-model="searchForm.id"    clearable placeholder="订单号" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="" prop="memberName">
        <el-input v-model="searchForm.memberName"    clearable placeholder="付款人姓名" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="" prop="memberPhone">
        <el-input v-model="searchForm.memberPhone"    clearable placeholder="付款人手机号" @keypress.enter.native="search"></el-input>
      </el-form-item>
<!--      <el-form-item label="" prop="username">
        <el-input v-model="searchForm.username"  clearable placeholder="负责人账号" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="" prop="userRealname">
        <el-input v-model="searchForm.userRealname"   clearable placeholder="负责人姓名" @keypress.enter.native="search"></el-input>
      </el-form-item>-->
      <el-form-item label="" prop="orderType">
        <el-select v-model="searchForm.orderType"    @change="search"  clearable placeholder="付款事由">
          <el-option label="车款" :value="0"></el-option>
          <el-option label="延期款" :value="1"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="" prop="status">
        <el-select v-model="searchForm.status"  @change="search" clearable placeholder="状态">
        <el-option label="处理中" :value="0"></el-option>
        <el-option label="成功" :value="1"></el-option>
        <el-option label="失败" :value="2"></el-option>
        </el-select>
      </el-form-item>
        <el-form-item label=""   prop="starttime"  label-width="100px" >
          <el-date-picker type="datetime"    v-model="searchForm.starttime" clearable value-format="yyyy-MM-dd HH:mm:ss"
                          placeholder="开始(创建)时间" /> -
        </el-form-item>
        <el-form-item label="" prop="endtime"   label-width="0px" >
          <el-date-picker type="datetime"   v-model="searchForm.endtime" clearable value-format="yyyy-MM-dd HH:mm:ss"
                          placeholder="结束(创建)时间" />
        </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
<!--
        <el-button type="primary" :loading="isWorking.export" @click="exportExcel">导出</el-button>
-->
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
<!--      <ul class="toolbar" v-permissions="['business:refund:create', 'business:refund:delete']">
        <li><el-button type="primary" @click="$refs.operaOrdersWindow.open('新建订单信息记录')" icon="el-icon-plus" v-permissions="['business:refund:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:refund:delete']">删除</el-button></li>
      </ul>-->
      <el-table
         :height="tableHeightNew"
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        @selection-change="handleSelectionChange"
      >
        <el-table-column prop="id" label="退款单号" width="120px" fixed="left">
          <template slot-scope="{row}">
            <span class="blue"   @click="openDetail(row)">{{row.id}}</span>
          </template>
        </el-table-column>
        <el-table-column prop="orderId" label="支付订单号"  width="100px" :show-overflow-tooltip='true'></el-table-column>
        <el-table-column prop="memberName" label="付款人姓名"  width="100px" :show-overflow-tooltip='true'></el-table-column>
        <el-table-column prop="memberPhone" label="付款人手机号"  width="120px" :show-overflow-tooltip='true'></el-table-column>
        <el-table-column prop="money" label="支付金额(元)" min-width="150px">
          <template slot-scope="{row}">
            <span class="yellowstate">{{((row.money || 0)/100).toFixed(2)}}</span>
          </template>
        </el-table-column>
        <el-table-column prop="statusName" label="退款状态" min-width="100px"  >
          <template slot-scope="{row}">
          <span v-if="row.status == 0" class="blue">处理中</span>
          <span v-if="row.status == 1" class="green">成功</span>
          <span v-if="row.status == 2" class="grey">失败</span>
          </template>
        </el-table-column>
        <el-table-column prop="orderType" label="付款事由" min-width="100px">
          <template slot-scope="{row}">
            <span v-if="row.orderType==0">车款</span>
            <span v-if="row.orderType==1">延期款</span>
          </template>
        </el-table-column>
        <el-table-column prop="money" label="退款金额(元)" min-width="150px">
          <template slot-scope="{row}">
            <span class="red">{{((row.money || 0)/100).toFixed(2)}}</span>
          </template>
        </el-table-column>
        <el-table-column prop="remark" label="退款备注"  width="200px"  ></el-table-column>
        <el-table-column prop="memberName" label="收款人姓名"  width="100px"  ></el-table-column>
        <el-table-column prop="memberPhone" label="负责人账号"  width="120px"  ></el-table-column>
        <el-table-column prop="createTime" label="创建时间" min-width="150px"></el-table-column>
        <el-table-column prop="payDate" label="完成时间" min-width="150px"></el-table-column>
       <el-table-column
          label="操作"
          align="center"
          min-width="180"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text"   @click="payStatus(row)" icon="el-icon-refresh" v-permissions="['business:refund:update']">同步状态</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaOrderDetailWindow ref="OperaOrderDetailWindow" @success="handlePageChange"/>
    <OperaRefundWindow ref="OperaRefundWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaOrderDetailWindow from '@/components/business/OperaOrderDetailWindow'
import OperaRefundWindow from '@/components/business/OperaRefundWindow'
import { cancel } from '@/api/business/orders'
export default {
  name: 'Orders',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaOrderDetailWindow, OperaRefundWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        id: null,
        status: null,
        type: null,
        starttime: null,
        endtime: null,
        memberName: null,
        memberPhone: null,
        orderId: null
      }
    }
  },
  created () {
    this.config({
      module: '退款信息记录',
      api: '/business/refund',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
    openDetail (row) {
    },
    payStatus (row) {
      this.$dialog.actionConfirm('您确认【同步】该退款最新状态吗?', '操作确认')
        .then(() => {
          this.dealing = true
          this.api.updateByPayStatus({ id: row.id })
            .then(res => {
              this.$tip.apiSuccess('操作成功')
              this.search()
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.dealing = false
            })
        })
    }
  }
}
</script>
server/admin/db/RefundPermissions.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `MODULE`) VALUES ('business:refund:create', '新建订单退款信息表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0,'订单退款信息表');
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `MODULE`) VALUES ('business:refund:delete', '删除订单退款信息表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0,'订单退款信息表');
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `MODULE`) VALUES ('business:refund:update', '修改订单退款信息表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0,'订单退款信息表');
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `MODULE`) VALUES ('business:refund:query', '查询订单退款信息表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0,'订单退款信息表');
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`, `MODULE`) VALUES ('business:refund:exportExcel', '导出订单退款信息表(Excel)', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0,'订单退款信息表');
server/admin/src/main/java/com/doumee/api/business/RefundController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
package com.doumee.api.business;
import com.doumee.core.annotation.excel.ExcelExporter;
import com.doumee.core.annotation.pr.PreventRepeat;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Orders;
import com.doumee.dao.business.model.Refund;
import com.doumee.core.utils.Utils;
import com.doumee.service.business.RefundService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import  com.doumee.api.BaseController;
/**
 * è®¢å•退款信息表Controller定义
 * @author doumee
 * @date 2026-02-06 11:35:16
 */
@Api(tags = "refund接口")
@RestController
@RequestMapping("/business/refund")
public class RefundController extends BaseController {
    @Autowired
    private RefundService refundService;
    @PreventRepeat
    @ApiOperation("新建")
    @PostMapping("/create")
    @RequiresPermissions("business:refund:create")
    public ApiResponse create(@RequestBody Refund refund) {
        return ApiResponse.success(refundService.create(refund));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @RequiresPermissions("business:refund:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
        refundService.deleteById(id);
        return ApiResponse.success(null);
    }
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @RequiresPermissions("business:refund:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
        refundService.deleteByIdInBatch(this.getIdList(ids));
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID查询交易流水信息更新最新交易状态")
    @PostMapping("/updateByPayStatus")
    @RequiresPermissions("business:refund:update")
    public ApiResponse updateByPayStatus(@RequestBody Refund orders) {
        refundService.updateByPayStatus(orders);
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @RequiresPermissions("business:refund:update")
    public ApiResponse updateById(@RequestBody Refund refund) {
        refundService.updateById(refund);
        return ApiResponse.success(null);
    }
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @RequiresPermissions("business:refund:query")
    public ApiResponse<PageData<Refund>> findPage (@RequestBody PageWrap<Refund> pageWrap) {
        return ApiResponse.success(refundService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @RequiresPermissions("business:refund:exportExcel")
    public void exportExcel (@RequestBody PageWrap<Refund> pageWrap, HttpServletResponse response) {
        ExcelExporter.build(Refund.class).export(refundService.findPage(pageWrap).getRecords(), "订单退款信息表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @RequiresPermissions("business:refund:query")
    public ApiResponse findById(@PathVariable Integer id) {
        return ApiResponse.success(refundService.findById(id));
    }
}
server/admin/src/main/resources/application.yml
@@ -8,7 +8,7 @@
spring:
  profiles:
    active: pro
    active: dev
  # JSON返回配置
  jackson:
    # é»˜è®¤æ—¶åŒº
server/services/src/main/java/com/allinpay/syb/lib/DoumeeTLUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
package com.allinpay.syb.lib;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.allinpay.syb.model.PayOrderNotifyParam;
import com.allinpay.syb.model.PayOrderRefundResponse;
import com.allinpay.syb.model.PayPublicModel;
import com.doumee.core.utils.HttpsUtil;
import com.doumee.dao.business.model.Orders;
import com.doumee.dao.business.model.Refund;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
@Slf4j
@Data
public class DoumeeTLUtil {
    public static final String SUCCESS_CODE = "SUCCESS";
    public static final String FAIL_CODE = "FAIL";
    private PayPublicModel publicModel;
    private String appkey;
    private String pubKey;
    public DoumeeTLUtil(PayPublicModel model){
        this.publicModel = model;
    }
    public  static  String REFUND_SN_PREFIX = "refund_";
    public PayOrderRefundResponse sendRefundOrder(String reqsn, String oldReqsn, String money, String remark)    {
            TreeMap<String, String> params = new TreeMap<String, String>();
            params.put("cusid", publicModel.getCusid());
            params.put("appid", publicModel.getAppid());
            params.put("version", publicModel.getVersion());
            params.put("trxid", "");
            params.put("randomstr", SybUtil.getValidatecode(8));
            params.put("signtype", publicModel.getSigntype());
            params.put("notify_url",publicModel.getNotifyUrl());
            params.remove("sign");
            params.put("reqsn",REFUND_SN_PREFIX+reqsn);
            params.put("oldreqsn",oldReqsn);
            params.put("trxamt",money);
            params.put("remark",remark);
            return  sendRequest(params,publicModel.getUrl()+"/tranx/refund",publicModel.getAppkey(),publicModel.getAppPubkey(),new TypeReference<PayOrderRefundResponse>(){});
    }
    public  PayOrderNotifyParam   sendQueryOrder(String reqsn  )  {
            TreeMap<String, String> params = new TreeMap<String, String>();
            params.put("cusid", publicModel.getCusid());
            params.put("appid", publicModel.getAppid());
            params.put("version", publicModel.getVersion());
            params.put("trxid", "");
            params.put("randomstr", SybUtil.getValidatecode(8));
            params.put("signtype", publicModel.getSigntype());
            params.remove("sign");
            params.put("reqsn",reqsn);
           return  sendRequest(params,publicModel.getUrl()+"/tranx/query",publicModel.getAppkey(),publicModel.getAppPubkey(),new TypeReference<PayOrderNotifyParam>(){});
    }
    public static <T> T sendRequest(TreeMap<String,String> params, String url, String appkey, String pubKey, TypeReference<T> typeReference )  {
        try {
            params.put("sign", SybUtil.unionSign(params,appkey,params.get("signtype")));
            String data =getHttpParamsStr(params);
            log.error("订单交易数据请求================{}",data);
            String result =  HttpsUtil.post(url,data,"application/x-www-form-urlencoded",true);
            log.error("订单查交据返回================{}",result);
            T map = handleResult(result,pubKey,params.get("signtype"),typeReference);
            return map;
        }catch (Exception e){
            log.error("通联订单查询异常================{}",e);
        }
        return  null;
    }
    public static String getHttpParamsStr(Map<String, String> params ) throws IOException {
        StringBuilder outBuf = new StringBuilder();
        boolean isNotFirst = false;
        for (Map.Entry<String, String> entry: params.entrySet()){
            if (isNotFirst)
                outBuf.append('&');
            isNotFirst = true;
            outBuf
                    .append(entry.getKey())
                    .append('=')
                    .append(URLEncoder.encode(StringUtils.defaultString(entry.getValue(),""), "UTF-8"));
        }
        System.out.println("参数:"+outBuf.toString());
        return outBuf.toString();
    }
    public static <T> T  handleResult(String result,String pubKey,String signType, TypeReference<T> typeReference ) throws Exception{
        log.error("返回数据返回================{}",result);
        Map map = SybUtil.json2ObjMap(result);
        if(map == null){
            log.error("返回数据返回错误================{}",result);
            throw new Exception("返回数据错误");
        }
        if("SUCCESS".equals(map.get("retcode"))){
            TreeMap tmap = new TreeMap();
            tmap.putAll(map);
            if(SybUtil.validSign(tmap, pubKey, signType)){
                T param = JSONObject.parseObject(result,typeReference.getType());
                return param;
            }
        }
        return null;
    }
    public static  TreeMap<String, String> getParams(HttpServletRequest request){
        TreeMap<String, String> map = new TreeMap<String, String>();
        Map reqMap = request.getParameterMap();
        for(Object key:reqMap.keySet()){
            String value = ((String[])reqMap.get(key))[0];
            System.out.println(key+";"+value);
            map.put(key.toString(),value);
        }
        return map;
    }
}
server/services/src/main/java/com/allinpay/syb/model/PayOrderNotifyParam.java
@@ -4,7 +4,7 @@
import lombok.Data;
/**
 * å‘˜å·¥ä¿¡æ¯å¯¼å…¥è¡¨
 * è®¢å•支付参数异步通知返回
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
server/services/src/main/java/com/allinpay/syb/model/PayOrderParam.java
@@ -4,7 +4,7 @@
import lombok.Data;
/**
 * å‘˜å·¥ä¿¡æ¯å¯¼å…¥è¡¨
 * è®¢å•支付参数
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
server/services/src/main/java/com/allinpay/syb/model/PayOrderRefundResponse.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.allinpay.syb.model;
import io.swagger.annotations.ApiModel;
import lombok.Data;
/**
 * è®¢å•退款返回对象
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
@Data
@ApiModel("订单退款返回对象")
public class PayOrderRefundResponse {
    private String  cusid    ;//商户号    å¹³å°åˆ†é…çš„商户号    å¦    15
    private String appid    ;//应用ID    å¹³å°åˆ†é…çš„APPID    å¦    8
    private String trxid    ;//交易单号    æ”¶é“¶å®å¹³å°çš„退款交易流水号    å¦    20
    private String reqsn    ;//商户订单号    å•†æˆ·çš„退款交易订单号    å¦    32
    private String  trxstatus    ;//交易状态    äº¤æ˜“的状态    å¦    4    è§é™„录交易返回码说明
    private String  fintime    ;//交易完成时间    yyyyMMddHHmmss    æ˜¯    14
    private String  errmsg;//    é”™è¯¯åŽŸå›     å¤±è´¥çš„原因说明    æ˜¯    100
    private String fee    ;//手续费         æ˜¯    15
    private String  trxcode    ;//交易类型         æ˜¯    8    è§é™„录交易类型说明
    private String  randomstr    ;//随机字符串    éšæœºç”Ÿæˆçš„字符串    å¦    32
    private String    chnltrxid    ;//渠道流水号    å¦‚支付宝,微信平台订单号    æ˜¯    64
    private String   chnldata;//    æ¸ é“信息         æ˜¯    -
    private String bankcode;//    æ‰€å±žé“¶è¡Œ         æ˜¯
    private String  sign    ;//签名         å¦    32    è¯¦è§å®‰å…¨è§„范
   private String retcode;//    string    å¦    æ”¶é“¶å®APPID    8
   private String retmsg;//    string    å¦    æ”¶é“¶å®APPID    8
}
server/services/src/main/java/com/allinpay/syb/model/PayOrderResponse.java
@@ -4,7 +4,7 @@
import lombok.Data;
/**
 * å‘˜å·¥ä¿¡æ¯å¯¼å…¥è¡¨
 * è®¢å•支付参数返回
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
server/services/src/main/java/com/allinpay/syb/model/PayPublicModel.java
@@ -4,7 +4,7 @@
import lombok.Data;
/**
 * å‘˜å·¥ä¿¡æ¯å¯¼å…¥è¡¨
 * é€šè”公共配置参数
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
@@ -19,6 +19,7 @@
    private String appkey;
    private String url;
    private String appPubkey;
    private String notifyUrl;
}
server/services/src/main/java/com/doumee/biz/system/SystemDictDataBiz.java
@@ -1,5 +1,6 @@
package com.doumee.biz.system;
import com.allinpay.syb.model.PayPublicModel;
import com.doumee.dao.common.dto.UpdateSortDTO;
import com.doumee.dao.system.model.SystemDictData;
@@ -34,7 +35,7 @@
     */
    void sort(UpdateSortDTO dto);
    PayPublicModel initPayPublicModel();
    void updateByIdNew(SystemDictData systemDictData);
    SystemDictData queryByCode(String dicCode, String label);
    String  queryCodeById(Integer id);
server/services/src/main/java/com/doumee/biz/system/impl/SystemDictDataBizImpl.java
@@ -1,5 +1,6 @@
package com.doumee.biz.system.impl;
import com.allinpay.syb.model.PayPublicModel;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.Constants;
import com.doumee.core.exception.BusinessException;
@@ -50,6 +51,20 @@
    public void updateById(SystemDictData systemDictData) {
        systemDictDataService.updateById(systemDictData);
    }
    @Override
    public PayPublicModel initPayPublicModel() {
        PayPublicModel model = new PayPublicModel();
        model.setUrl( queryByCode(Constants.SYSTEM,Constants.PAY_SYB_CUSID).getCode());
        model.setCusid( queryByCode(Constants.SYSTEM,Constants.PAY_SYB_CUSID).getCode());
        model.setAppid(queryByCode(Constants.SYSTEM,Constants.PAY_SYB_APPID).getCode());
        model.setVersion(queryByCode(Constants.SYSTEM,Constants.PAY_VERSION).getCode());
        model.setSigntype( queryByCode(Constants.SYSTEM,Constants.PAY_SIGN_TYPE).getCode());
        model.setAppkey(queryByCode(Constants.SYSTEM,Constants.PAY_APPKEY).getCode());
        model.setUrl(queryByCode(Constants.SYSTEM,Constants.PAY_SYB_APIURL).getCode());
        model.setNotifyUrl(queryByCode(Constants.SYSTEM,Constants.PAY_NOTIFY_URL).getCode());
        model.setAppPubkey( queryByCode(Constants.SYSTEM,Constants.PAY_SYB_RSATLPUBKEY).getCode());
        return model;
    }
    @Override
    public void sort(UpdateSortDTO dto) {
@@ -75,9 +90,7 @@
            }
            SystemDictData preDictData = dictDataList.remove(index - 1);
            dictDataList.add(index, preDictData);
        }
        // ä¸‹ç§»
        else {
        }else {
            if (index + 1 > dictDataList.size() - 1) {
                return;
            }
server/services/src/main/java/com/doumee/dao/business/RefundMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.doumee.dao.business;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.doumee.dao.business.model.Refund;
import com.github.yulichang.base.MPJBaseMapper;
/**
 * è®¢å•退款信息表Mapper定义
 * @author doumee
 * @date 2026-02-06 11:35:16
 */
public interface RefundMapper extends MPJBaseMapper<Refund> {
}
server/services/src/main/java/com/doumee/dao/business/model/Orders.java
@@ -130,4 +130,7 @@
    @ApiModelProperty("统计量")
    @TableField(exist = false)
    private Long num;
    @ApiModelProperty("已退款金额")
    @TableField(exist = false)
    private BigDecimal refundMoney;
}
server/services/src/main/java/com/doumee/dao/business/model/Refund.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,111 @@
package com.doumee.dao.business.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
import java.math.BigDecimal;
/**
 * è®¢å•退款信息表Model定义
 * @author doumee
 * @date 2026-02-06 11:35:16
 */
@Data
@TableName("refund")
@ApiModel(value = "Refund å®žä½“ç±»")
public class Refund  {
    @ApiModelProperty("支付状态:0=未支付;1=已支付")
    @ExcelColumn(name="支付状态:0=未支付;1=已支付",index=1 ,width=10)
    @TableId(type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty("是否已删除 0未删除 1已删除")
    @ExcelColumn(name="是否已删除 0未删除 1已删除",index=2 ,width=10)
    private Integer deleted;
    @ApiModelProperty("创建人编码")
    @ExcelColumn(name="创建人编码",index=3 ,width=10)
    private Integer createUser;
    @ApiModelProperty("创建时间")
    @ExcelColumn(name="创建时间",index=4 ,width=10)
    private Date createTime;
    @ApiModelProperty("更新人编码")
    @ExcelColumn(name="更新人编码",index=5 ,width=10)
    private Integer updateUser;
    @ApiModelProperty("更新时间")
    @ExcelColumn(name="更新时间",index=6 ,width=10)
    private Date updateTime;
    @ApiModelProperty("备注")
    @ExcelColumn(name="备注",index=7 ,width=10)
    private String remark;
    @ApiModelProperty("状态:0=处理中;1=成功;2=失败")
    @ExcelColumn(name="状态:0=处理中;1=成功;2=失败",index=8 ,width=10)
    private Integer status;
    @ApiModelProperty("说明")
    @ExcelColumn(name="说明",index=9 ,width=10)
    private String detail;
    @ApiModelProperty("列表图")
    @ExcelColumn(name="列表图",index=10 ,width=10)
    private String imgurl;
    @ApiModelProperty("排序码(升序使用)")
    @ExcelColumn(name="排序码(升序使用)",index=11 ,width=10)
    private Integer sortnum;
    @ApiModelProperty("金额(分)")
    @ExcelColumn(name="金额(分)",index=12 ,width=10)
    private BigDecimal money;
    @ApiModelProperty("当前余额(分)")
    @ExcelColumn(name="当前余额(分)",index=13 ,width=10)
    private BigDecimal banlance;
    @ApiModelProperty("通联交易流水号")
    @ExcelColumn(name="通联交易流水号",index=14 ,width=10)
    private String payOrderId;
    @ApiModelProperty("通联交易流水(微信支付宝等平台交易流水好)")
    @ExcelColumn(name="通联交易流水(微信支付宝等平台交易流水好)",index=15 ,width=10)
    private String payThirdOrderId;
    @ApiModelProperty("支付结果说明")
    @ExcelColumn(name="支付结果说明",index=16 ,width=10)
    private String payInfo;
    @ApiModelProperty("通联交易渠道数据")
    @ExcelColumn(name="通联交易渠道数据",index=17 ,width=10)
    private String payThirdOrderData;
    @ApiModelProperty("通联交易手续费(分)")
    @ExcelColumn(name="通联交易手续费(分)",index=18 ,width=10)
    private String payFee;
    @ApiModelProperty("通联交易平台编号")
    @ExcelColumn(name="通联交易平台编号",index=19 ,width=10)
    private String payCode;
    @ApiModelProperty("订单编码(关联orders)")
    @ExcelColumn(name="订单编码(关联orders)",index=20 ,width=10)
    private Integer orderId;
    @ApiModelProperty("完成时间")
    @ExcelColumn(name="完成时间",index=20 ,width=10)
    private Date payDate;
    @ApiModelProperty("开始时间")
    @TableField(exist = false)
    private Date starttime;
    @ApiModelProperty("截止时间")
    @TableField(exist = false)
    private Date endtime;
    @ApiModelProperty("付款人姓名")
    @TableField(exist = false)
    private String memberName;
    @ApiModelProperty("付款人姓名")
    @TableField(exist = false)
    private String memberPhone;
    @ApiModelProperty("负责人登陆")
    @TableField(exist = false)
    private String username;
    @ApiModelProperty("负责人姓名")
    @TableField(exist = false)
    private String userRealname;
    @ApiModelProperty("付款事由")
    @TableField(exist = false)
    private Integer orderType;
}
server/services/src/main/java/com/doumee/service/business/RefundService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
package com.doumee.service.business;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Refund;
import java.util.List;
/**
 * è®¢å•退款信息表Service定义
 * @author doumee
 * @date 2026-02-06 11:35:16
 */
public interface RefundService {
    /**
     * åˆ›å»º
     *
     * @param model å®žä½“对象
     * @return Integer
     */
    Integer create(Refund model);
    /**
     * ä¸»é”®åˆ é™¤
     *
     * @param id ä¸»é”®
     */
    void deleteById(Integer id);
    /**
     * åˆ é™¤
     *
     * @param model å®žä½“对象
     */
    void delete(Refund model);
    /**
     * æ‰¹é‡ä¸»é”®åˆ é™¤
     *
     * @param ids ä¸»é”®é›†
     */
    void deleteByIdInBatch(List<Integer> ids);
    /**
     * ä¸»é”®æ›´æ–°
     *
     * @param model å®žä½“对象
     */
    void updateById(Refund model);
    /**
     * æ‰¹é‡ä¸»é”®æ›´æ–°
     *
     * @param model å®žä½“集
     */
    void updateByIdInBatch(List<Refund> model);
    /**
     * ä¸»é”®æŸ¥è¯¢
     *
     * @param id ä¸»é”®
     * @return model
     */
    Refund findById(Integer id);
    /**
     * æ¡ä»¶æŸ¥è¯¢å•条记录
     *
     * @param model å®žä½“对象
     * @return Refund
     */
    Refund findOne(Refund model);
    /**
     * æ¡ä»¶æŸ¥è¯¢
     *
     * @param model å®žä½“对象
     * @return List<Refund>
     */
    List<Refund> findList(Refund model);
    /**
     * åˆ†é¡µæŸ¥è¯¢
     *
     * @param pageWrap åˆ†é¡µå¯¹è±¡
     * @return PageData<Refund>
     */
    PageData<Refund> findPage(PageWrap<Refund> pageWrap);
    /**
     * æ¡ä»¶ç»Ÿè®¡
     *
     * @param model å®žä½“对象
     * @return long
     */
    long count(Refund model);
    void updateByPayStatus(Refund orders);
}
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -3,6 +3,7 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.allinpay.syb.lib.DoumeeTLUtil;
import com.allinpay.syb.lib.SybConstants;
import com.allinpay.syb.lib.SybUtil;
import com.allinpay.syb.model.PayPublicModel;
@@ -18,9 +19,11 @@
import com.allinpay.syb.model.PayOrderNotifyParam;
import com.allinpay.syb.model.PayOrderParam;
import com.allinpay.syb.model.PayOrderResponse;
import com.doumee.dao.business.RefundMapper;
import com.doumee.dao.business.model.Orders;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.OrdersMapper;
import com.doumee.dao.business.model.Refund;
import com.doumee.dao.system.SystemUserMapper;
import com.doumee.dao.system.model.SystemUser;
import com.doumee.dao.vo.IndexOrderCountVO;
@@ -56,6 +59,8 @@
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private RefundMapper refundMapper;
    @Autowired
    private SystemUserMapper systemUserMapper;
    @Autowired
@@ -207,6 +212,7 @@
        IPage<Orders> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        MPJLambdaWrapper<Orders> queryWrapper = new MPJLambdaWrapper<>();
        queryWrapper.selectAll(Orders.class)
                .select("(select sum(r.money) from refund r where r.deleted=0 and r.status in(0,1) and r.order_id=t.id)",Orders::getRefundMoney)
                .selectAs(SystemUser::getRealname,Orders::getUserRealname)
                .selectAs(SystemUser::getUsername,Orders::getUsername)
                .leftJoin(SystemUser.class,SystemUser::getId,Orders::getUserId);
@@ -357,7 +363,7 @@
                .eq(Orders::getStatus,Constants.ZERO)
                .apply("TIMESTAMPDIFF(MINUTE, create_time ,now()) > "+time));
        if(orderList !=null && orderList.size()>0){
            PayPublicModel publicModel = initPayPublicModel();
            PayPublicModel publicModel =systemDictDataBiz.initPayPublicModel();
            Date date = new Date();
            for(Orders model : orderList){
                queryPayOrderDetailBiz(model,publicModel,date,time);
@@ -373,26 +379,15 @@
        }
        Orders  model =  ordersMapper.selectById(param.getId());
        if(model !=null ){
            PayPublicModel publicModel = initPayPublicModel();
            PayPublicModel publicModel =systemDictDataBiz.initPayPublicModel();
            Date date = new Date();
            queryPayOrderDetailBiz(model,publicModel,date,time);
        }
    }
    private void queryPayOrderDetailBiz(Orders model, PayPublicModel publicModel, Date date,int time) {
        TreeMap<String,String> params = new TreeMap<String,String>();
        params.put("cusid",publicModel.getCusid());
        params.put("appid",publicModel.getAppid());
        params.put("version",publicModel.getVersion());
        params.put("trxid", "");
        params.put("randomstr", SybUtil.getValidatecode(8));
        params.put("signtype", publicModel.getSigntype());
        String appkey = publicModel.getAppkey();
        String url =  publicModel.getUrl();
        String appPubkey = publicModel.getAppPubkey();
        params.remove("sign");
        params.put("reqsn", model.getId()+"");
        PayOrderNotifyParam map = query(params,url,appkey,appPubkey);
        DoumeeTLUtil doumeeTLUtil = new DoumeeTLUtil(publicModel);
        PayOrderNotifyParam map = doumeeTLUtil.sendQueryOrder(model.getId()+"");
        int status = Constants.TWO;
        if(map!=null){
            String info = SybUtil.getPayInfoByStatus(map);
@@ -406,7 +401,7 @@
                    status = Constants.ONE;
                } else if (StringUtils.equals(map.getTrxstatus(),"2000") || StringUtils.equals(map.getTrxstatus(),"2008")) {
                    //如果交易未支付,并且未超过半小时,不处理
                    if(date.getTime() - model.getCreateTime().getTime() < 30*60*1000){
                    if(date.getTime() - model.getCreateTime().getTime() < time*60*1000){
                        return;
                    }
                }
@@ -429,66 +424,8 @@
        ordersMapper.updateById(model) ;
    }
    private PayPublicModel initPayPublicModel() {
        PayPublicModel model = new PayPublicModel();
        model.setUrl(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_SYB_CUSID).getCode());
        model.setCusid( systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_SYB_CUSID).getCode());
        model.setAppid(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_SYB_APPID).getCode());
        model.setVersion(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_VERSION).getCode());
        model.setSigntype( systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_SIGN_TYPE).getCode());
        model.setAppkey(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_APPKEY).getCode());
        model.setUrl(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_SYB_APIURL).getCode());
        model.setAppPubkey( systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_SYB_RSATLPUBKEY).getCode());
        return model;
    }
    public  PayOrderNotifyParam query( TreeMap<String,String> params,String url,String appkey,String pubKey )  {
        try {
            params.put("sign", SybUtil.unionSign(params,appkey,SybConstants.SIGN_TYPE));
            String data =getHttpParamsStr(params);
            log.error("订单查询数据请求================{}",data);
            String result =  HttpsUtil.post(url+"/tranx/query",data,"application/x-www-form-urlencoded",true);
            log.error("订单查询数据返回================{}",result);
            PayOrderNotifyParam map = handleResult(result,pubKey,params.get("signtype"));
            return map;
        }catch (Exception e){
            log.error("通联订单查询异常================{}",e);
        }
        return  null;
    }
    public String getHttpParamsStr(Map<String, String> params ) throws IOException {
        StringBuilder outBuf = new StringBuilder();
        boolean isNotFirst = false;
        for (Map.Entry<String, String> entry: params.entrySet()){
            if (isNotFirst)
                outBuf.append('&');
            isNotFirst = true;
            outBuf
                    .append(entry.getKey())
                    .append('=')
                    .append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }
        System.out.println("参数:"+outBuf.toString());
        return outBuf.toString();
    }
    public static PayOrderNotifyParam handleResult(String result,String pubKey,String signType) throws Exception{
        log.error("返回数据返回================{}",result);
        Map map = SybUtil.json2ObjMap(result);
        if(map == null){
            log.error("返回数据返回错误================{}",result);
            throw new Exception("返回数据错误");
        }
        if("SUCCESS".equals(map.get("retcode"))){
            TreeMap tmap = new TreeMap();
            tmap.putAll(map);
            if(SybUtil.validSign(tmap, pubKey, signType)){
                PayOrderNotifyParam param = JSONObject.toJavaObject(JSONObject.parseObject(result),PayOrderNotifyParam.class);
                return param;
            }
        }
        return null;
    }
    @Override
    public void returnPage(PayOrderParam param, HttpServletResponse response) throws IOException {
//        String url =systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_RETURN_WEB_URL).getCode();
@@ -512,46 +449,24 @@
                    r ="支付结果异常,如有疑问请联系客服人员";
                    return;
                }
                Orders model = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda()
                        .eq(Orders::getId,Integer.parseInt(map.getCusorderid()))
                );
                if(model ==null){
                    log.error("支付处理失败======未找到交易订单"+map.getCusorderid());
                    r ="支付结果异常,订单查询失败,如有疑问请联系客服人员";
                    return;
                }
                 if(Constants.equalsInteger(model.getPayStatus(),Constants.ONE)){
                    log.error("支付处理======订单已支付"+map.getCusorderid());
                    return;
                }
                String info = SybUtil.getPayInfoByStatus(map);
                if(StringUtils.equals(map.getTrxcode(),"VSP501")
                    ||StringUtils.equals(map.getTrxcode(),"VSP511")
                    ||StringUtils.equals(map.getTrxcode(),"VSP551")){
                    //交易类型是 å¾®ä¿¡æ”¯ä»˜ ã€æ”¯ä»˜å®æ”¯ä»˜æˆ–者银联扫码支付,记录支付状态
                    if(StringUtils.equals(map.getTrxstatus(),"0000")){
                        //交易成功
                        model.setPayStatus(Constants.ONE);
                        model.setStatus(Constants.ONE);
                    }else{
                        //交易失败
                        model.setStatus(Constants.TWO);
                    }
                }else{
                    model.setStatus(Constants.TWO);
                    dealOrdersResultBiz(info,map,r);
                }else  if(StringUtils.equals(map.getTrxcode(),"VSP503")
                        ||StringUtils.equals(map.getTrxcode(),"VSP513")
                        ||StringUtils.equals(map.getTrxcode(),"VSP553")){
                    //交易类型是 å¾®ä¿¡t退款 ã€æ”¯ä»˜å®æ”¯ä»˜é€€æ¬¾æˆ–者银联扫码退货,记录支付状态
                    dealRefunResultBiz(info,map,r);//处理退款
                }else {
                  //其他类型不通知
                }
                model.setPayFee(map.getFee());
                model.setPayDate(DateUtil.fromStringToDate("yyyyMMddHHmmss",map.getPaytime()));
                model.setPayOrderId(map.getSrctrxid());//通联订单号
                model.setPayThirdOrderId(map.getChnltrxid());//支付宝微信订单号
                model.setPayThirdOrderData(map.getChnldata());//三方交易渠道数据
                model.setPayInfo(info);
                model.setPayCode(map.getTrxcode());
                ordersMapper.updateById(model);
            }else{
                log.error("支付验签失败======");
                r ="支付失败,如有疑问请联系客服人员";
                return;
            }
            //验签完毕进行业务处理
        } catch (Exception e) {//处理异常
@@ -565,18 +480,66 @@
        }
    }
    public   TreeMap<String, String> getParams(HttpServletRequest request){
        TreeMap<String, String> map = new TreeMap<String, String>();
        Map reqMap = request.getParameterMap();
        for(Object key:reqMap.keySet()){
            String value = ((String[])reqMap.get(key))[0];
            System.out.println(key+";"+value);
            map.put(key.toString(),value);
    private String dealRefunResultBiz(String info, PayOrderNotifyParam map, String r) {
        Refund model = refundMapper.selectOne(new QueryWrapper<Refund>().lambda()
                .eq(Refund::getId,Integer.parseInt(map.getCusorderid().replace(DoumeeTLUtil.REFUND_SN_PREFIX,"")))
        );
        if(model ==null){
            log.error("支付处理失败======未找到交易订单"+map.getCusorderid());
            return "支付结果异常,订单查询失败,如有疑问请联系客服人员";
        }
        return map;
        if(Constants.equalsInteger(model.getStatus(),Constants.ONE)){
            log.error("支付处理======订单已支付"+map.getCusorderid());
            return  "订单已支付";
        }
        if(StringUtils.equals(map.getTrxstatus(),"0000")){
            //交易成功
            model.setStatus(Constants.ONE);
        }else{
            //交易失败
            model.setStatus(Constants.TWO);
        }
        model.setPayFee(map.getFee());
        model.setPayDate(DateUtil.fromStringToDate("yyyyMMddHHmmss",map.getPaytime()));
        model.setPayOrderId(map.getTrxid());//通联订单号
        model.setPayThirdOrderId(map.getChnltrxid());//支付宝微信订单号
        model.setPayThirdOrderData(map.getChnldata());//三方交易渠道数据
        model.setPayInfo(info);
        model.setPayCode(map.getTrxcode());
        refundMapper.updateById(model);
        return  r;
    }
    private String dealOrdersResultBiz(String info, PayOrderNotifyParam map,String r) {
        Orders model = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda()
                .eq(Orders::getId,Integer.parseInt(map.getCusorderid()))
        );
        if(model ==null){
            log.error("支付处理失败======未找到交易订单"+map.getCusorderid());
            return "支付结果异常,订单查询失败,如有疑问请联系客服人员";
        }
        if(Constants.equalsInteger(model.getPayStatus(),Constants.ONE)){
            log.error("支付处理======订单已支付"+map.getCusorderid());
            return  "订单已支付";
        }
        if(StringUtils.equals(map.getTrxstatus(),"0000")){
            //交易成功
            model.setPayStatus(Constants.ONE);
            model.setStatus(Constants.ONE);
        }else{
            //交易失败
            model.setStatus(Constants.TWO);
        }
        model.setPayFee(map.getFee());
        model.setPayDate(DateUtil.fromStringToDate("yyyyMMddHHmmss",map.getPaytime()));
        model.setPayOrderId(map.getTrxid());//通联订单号
        model.setPayThirdOrderId(map.getChnltrxid());//支付宝微信订单号
        model.setPayThirdOrderData(map.getChnldata());//三方交易渠道数据
        model.setPayInfo(info);
        model.setPayCode(map.getTrxcode());
        ordersMapper.updateById(model);
        return  r;
    }
}
server/services/src/main/java/com/doumee/service/business/impl/RefundServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,246 @@
package com.doumee.service.business.impl;
import com.allinpay.syb.lib.DoumeeTLUtil;
import com.allinpay.syb.lib.SybUtil;
import com.allinpay.syb.model.PayOrderNotifyParam;
import com.allinpay.syb.model.PayOrderRefundResponse;
import com.allinpay.syb.model.PayPublicModel;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.Constants;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.DateUtil;
import com.doumee.dao.business.OrdersMapper;
import com.doumee.dao.business.model.Orders;
import com.doumee.dao.business.model.Refund;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.RefundMapper;
import com.doumee.dao.system.model.SystemUser;
import com.doumee.service.business.RefundService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.sql.Ref;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;
/**
 * è®¢å•退款信息表Service实现
 * @author doumee
 * @date 2026-02-06 11:35:16
 */
@Service
public class RefundServiceImpl implements RefundService {
    @Autowired
    private RefundMapper refundMapper;
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private OrdersMapper ordersMapper;
    @Override
    @Transactional
    public Integer create(Refund model) {
        if(model.getOrderId()==null
                ||model.getMoney()==null
                ||model.getMoney().compareTo(new BigDecimal("0.01")) < 0){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"请按照要求填写信息!");
        }
        model.setMoney(model.getMoney().multiply(new BigDecimal(100)));//单位分
        Orders order = ordersMapper.selectById(model.getOrderId());
        if(order==null){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"订单信息不存在!");
        }
        if(!Constants.equalsInteger(order.getStatus(),Constants.ONE)){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"订单未交易成功,不支持退款操作!");
        }
        if( Constants.formatBigDecimal(model.getMoney()).compareTo(Constants.formatBigDecimal(order.getMoney())) >=0){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"退款金额不能超过订单金额!");
        }
        Refund sum = refundMapper.selectOne(new QueryWrapper<Refund>().select("sum(money) as money").lambda()
                .eq(Refund::getDeleted,Constants.ZERO)
                .eq(Refund::getOrderId,model.getOrderId())
                .in(Refund::getStatus,Constants.ZERO,Constants.ONE)
        );
        if(sum!=null && Constants.formatBigDecimal(sum.getMoney()).compareTo(Constants.formatBigDecimal(order.getMoney())) >=0){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"该订单退款总额已达上限!");
        }
        Date date = new Date();
        model.setCreateTime(date);
        model.setStatus(Constants.ZERO);
        model.setDeleted(Constants.ZERO);
        model.setBanlance(Constants.formatBigDecimal(order.getMoney()).subtract(Constants.formatBigDecimal( model.getMoney())));
        if(sum!=null){
            model.setBanlance(Constants.formatBigDecimal(model.getBanlance()).subtract(Constants.formatBigDecimal( sum.getMoney())));//当前还可提现余额
        }
        refundMapper.insert(model);
        DoumeeTLUtil doumeeTLUtil = new DoumeeTLUtil(systemDictDataBiz.initPayPublicModel());
        PayOrderRefundResponse map = doumeeTLUtil.sendRefundOrder(model.getId()+"",model.getOrderId()+"", model.getMoney().intValue()+"",model.getRemark());
        if(map ==null || !StringUtils.equals(map.getRetcode(),DoumeeTLUtil.SUCCESS_CODE) || !StringUtils.equals(map.getTrxstatus(),"0000")){
            throw  new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),"对不起,发起退款失败,"+(map!=null?map.getErrmsg():""));
        }
        return model.getId();
    }
    @Override
    public void deleteById(Integer id) {
        refundMapper.deleteById(id);
    }
    @Override
    public void delete(Refund refund) {
        UpdateWrapper<Refund> deleteWrapper = new UpdateWrapper<>(refund);
        refundMapper.delete(deleteWrapper);
    }
    @Override
    public void deleteByIdInBatch(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        refundMapper.deleteBatchIds(ids);
    }
    @Override
    public void updateById(Refund refund) {
        refundMapper.updateById(refund);
    }
    @Override
    public void updateByIdInBatch(List<Refund> refunds) {
        if (CollectionUtils.isEmpty(refunds)) {
            return;
        }
        for (Refund refund: refunds) {
            this.updateById(refund);
        }
    }
    @Override
    public Refund findById(Integer id) {
        return refundMapper.selectById(id);
    }
    @Override
    public Refund findOne(Refund refund) {
        QueryWrapper<Refund> wrapper = new QueryWrapper<>(refund).last("limit 1");
        return refundMapper.selectOne(wrapper);
    }
    @Override
    public List<Refund> findList(Refund refund) {
        QueryWrapper<Refund> wrapper = new QueryWrapper<>(refund);
        return refundMapper.selectList(wrapper);
    }
    @Override
    public  void updateByPayStatus(Refund param) {
        int time = 30;
        try {
            time = Integer.parseInt(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PAY_VALID_TIME).getCode());
        }catch (Exception e){
        }
        Refund  model =  refundMapper.selectById(param.getId());
        if(model !=null ){
            PayPublicModel publicModel =systemDictDataBiz.initPayPublicModel();
            Date date = new Date();
            queryPayOrderDetailBiz(model,publicModel,date,time);
        }
    }
    private void queryPayOrderDetailBiz(Refund model, PayPublicModel publicModel, Date date,int time) {
        DoumeeTLUtil doumeeTLUtil = new DoumeeTLUtil(publicModel);
        PayOrderNotifyParam map = doumeeTLUtil.sendQueryOrder(DoumeeTLUtil.REFUND_SN_PREFIX+model.getId()+"");
        int status = Constants.TWO;
        if(map!=null){
            String info = SybUtil.getPayInfoByStatus(map);
            if(StringUtils.equals(map.getTrxcode(),"VSP503")
                    ||StringUtils.equals(map.getTrxcode(),"VSP513")
                    ||StringUtils.equals(map.getTrxcode(),"VSP553")){
                // //交易类型是 å¾®ä¿¡t退款 ã€æ”¯ä»˜å®æ”¯ä»˜é€€æ¬¾æˆ–者银联扫码退货,记录支付状态
                if(StringUtils.equals(map.getTrxstatus(),"0000")){
                    //交易成功
                    status = Constants.ONE;
                } else if (StringUtils.equals(map.getTrxstatus(),"2000") || StringUtils.equals(map.getTrxstatus(),"2008")) {
                    //如果交易未支付,并且未超过半小时,不处理
                    if(date.getTime() - model.getCreateTime().getTime() < time*60*1000){
                        return;
                    }
                }
            }
            model.setPayFee(map.getFee());
            model.setStatus(status);
            model.setPayDate(DateUtil.fromStringToDate("yyyyMMddHHmmss",map.getPaytime()));
            model.setPayOrderId(map.getSrctrxid());//通联订单号
            model.setPayThirdOrderId(map.getChnltrxid());//支付宝微信订单号
            model.setPayThirdOrderData(map.getChnldata());//三方交易渠道数据
            model.setPayInfo(info);
            model.setPayCode(map.getTrxcode());
        }else{
            model.setPayInfo("超时无结果,自动取消");
            model.setStatus(Constants.TWO);
        }
        model.setUpdateTime(date);
        refundMapper.updateById(model) ;
    }
    @Override
    public PageData<Refund> findPage(PageWrap<Refund> pageWrap) {
        IPage<Refund> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        MPJLambdaWrapper<Refund> queryWrapper = new MPJLambdaWrapper<>();
        queryWrapper.selectAll(Refund.class)
                .selectAs(SystemUser::getRealname,Refund::getUserRealname)
                .selectAs(SystemUser::getUsername,Refund::getUsername)
                .selectAs(Orders::getName,Refund::getMemberName)
                .selectAs(Orders::getPhone,Refund::getMemberPhone)
                .leftJoin(Orders.class,Orders::getId,Refund::getOrderId)
                .leftJoin(SystemUser.class,SystemUser::getId,Refund::getCreateUser);
        Utils.MP.blankToNull(pageWrap.getModel());
        pageWrap.getModel().setDeleted(Constants.ZERO);
        queryWrapper.eq(pageWrap.getModel().getId() != null,Refund::getId, pageWrap.getModel().getId());
        queryWrapper.eq(pageWrap.getModel().getDeleted() != null,Refund::getDeleted, pageWrap.getModel().getDeleted());
        queryWrapper.eq(pageWrap.getModel().getCreateUser() != null,Refund::getCreateUser, pageWrap.getModel().getCreateUser());
        queryWrapper.eq(pageWrap.getModel().getUpdateUser() != null,Refund::getUpdateUser, pageWrap.getModel().getUpdateUser());
        queryWrapper.eq(pageWrap.getModel().getRemark() != null,Refund::getRemark, pageWrap.getModel().getRemark());
        queryWrapper.eq(pageWrap.getModel().getStatus() != null,Refund::getStatus, pageWrap.getModel().getStatus());
        queryWrapper.eq(pageWrap.getModel().getDetail() != null,Refund::getDetail, pageWrap.getModel().getDetail());
        queryWrapper.eq(pageWrap.getModel().getImgurl() != null,Refund::getImgurl, pageWrap.getModel().getImgurl());
        queryWrapper.eq(pageWrap.getModel().getSortnum() != null,Refund::getSortnum, pageWrap.getModel().getSortnum());
        queryWrapper.eq(pageWrap.getModel().getMoney() != null,Refund::getMoney, pageWrap.getModel().getMoney());
        queryWrapper.eq(pageWrap.getModel().getBanlance() != null,Refund::getBanlance, pageWrap.getModel().getBanlance());
        queryWrapper.eq(pageWrap.getModel().getPayOrderId() != null,Refund::getPayOrderId, pageWrap.getModel().getPayOrderId());
        queryWrapper.eq(pageWrap.getModel().getPayThirdOrderId() != null,Refund::getPayThirdOrderId, pageWrap.getModel().getPayThirdOrderId());
        queryWrapper.eq(pageWrap.getModel().getPayInfo() != null,Refund::getPayInfo, pageWrap.getModel().getPayInfo());
        queryWrapper.eq(pageWrap.getModel().getPayThirdOrderData() != null,Refund::getPayThirdOrderData, pageWrap.getModel().getPayThirdOrderData());
        queryWrapper.eq(pageWrap.getModel().getPayFee() != null,Refund::getPayFee, pageWrap.getModel().getPayFee());
        queryWrapper.eq(pageWrap.getModel().getPayCode() != null,Refund::getPayCode, pageWrap.getModel().getPayCode());
        queryWrapper.eq(pageWrap.getModel().getOrderType() != null,Orders::getType, pageWrap.getModel().getOrderType());
        queryWrapper.eq(pageWrap.getModel().getOrderId() != null,Refund::getOrderId, pageWrap.getModel().getOrderId());
        queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getMemberPhone() ) ,Orders::getName, pageWrap.getModel().getMemberPhone());
        queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getMemberName() ) ,Orders::getName, pageWrap.getModel().getMemberName());
        queryWrapper.ge(pageWrap.getModel().getStarttime()!=null,Refund::getCreateTime , pageWrap.getModel().getStarttime());
        queryWrapper.le(pageWrap.getModel().getEndtime()!=null,Refund::getCreateTime , pageWrap.getModel().getEndtime());
        queryWrapper.orderByDesc(Refund::getId);
        return PageData.from(refundMapper.selectJoinPage(page,Refund.class, queryWrapper));
    }
    @Override
    public long count(Refund refund) {
        QueryWrapper<Refund> wrapper = new QueryWrapper<>(refund);
        return refundMapper.selectCount(wrapper);
    }
}
web/pages/success/success.vue
@@ -3,8 +3,7 @@
        <template>
            <image v-if="info.status ==1" src="/static/ic_paysuccess@2x.png" mode="widthFix" class="icon"></image>
            <image v-else-if="info.status ==2" src="/static/ic_payfail.png" mode="widthFix" class="icon"></image>
            <image v-else src="/static/ic_paysuccess@2x.png" mode="widthFix" class="icon"></image>
            <image v-else src="/static/ic_paysuccess@2x.png" mode="widthFix" class="icon"></image>
        </template>
        <view class="title" v-if="info.id">{{info.status==0?'等待支付':(info.status==1?'支付成功':'支付失败')}}</view> 
        <view class="title" v-if="!info.id">查询中</view>