feat(purchase-order): 增加采购订单流程类型和供应商确认功能

- 在 application.yml 中增加 purchaseOrderApprove 配置项
- 在采购订单详情页增加接收人信息展示
- 增加流程类型选择对话框,支持线上/线下流程
- 实现采购订单撤回功能,允许在特定状态下撤回订单
- 新增发起供应商确认功能,支持供应商在线确认订单
- 更新采购订单实体类,增加流程类型和确认状态字段
- 修改数据库映射文件,支持新字段的读写操作
- 增加供应商确认和撤回相关接口及实现逻辑
- 在前端页面增加撤回和发起供应商确认按钮
- 更新 API 接口文件,增加撤回和供应商确认请求方法
dev_1.0.0
chenhao 2025-11-28 09:08:26 +08:00
parent 3a099795c2
commit b952b9610a
12 changed files with 226 additions and 24 deletions

View File

@ -49,7 +49,8 @@ export function applyPurchaseorder(data) {
return request({
url: '/sip/purchaseorder/apply',
method: 'put',
data: data
data: data,
needLoading: true
})
}
@ -69,7 +70,7 @@ export function getPurchaseOrderHistoryDetail(id) {
})
}
// 删除采购单主表
// 撤回采购订单
export function delPurchaseorder(id) {
return request({
url: '/sip/purchaseorder/' + id,
@ -77,6 +78,21 @@ export function delPurchaseorder(id) {
})
}
// 发起供应商确认
export function vendorConfirmStatus(data) {
return request({
url: '/sip/purchaseorder/vendorConfirmStatus',
method: 'put',
data:data
})
}
export function recallPurchaseorder(id) {
return request({
url: '/sip/purchaseorder/recall/' + id,
method: 'put'
})
}
// 查询已审批采购单主表列表
export function listApprovedPurchaseorder(query) {
return request({

View File

@ -71,6 +71,7 @@
<el-card>
<h4>{{ log.approveOpinion }}</h4>
<p><b>操作人:</b> {{ log.approveUserName }} ({{ log.roleName }})</p>
<p><b>接收人:</b> {{ log.nextAllApproveUserName }} </p>
<p><b>审批状态:</b> <el-tag size="small">{{ getStatusText(log.approveStatus) }}</el-tag></p>
</el-card>
</el-timeline-item>

View File

@ -80,6 +80,7 @@
<el-card>
<h4>{{ log.approveOpinion }}</h4>
<p><b>操作人:</b> {{ log.approveUserName }} ({{ log.roleName }})</p>
<p><b>接收人:</b> {{ log.nextAllApproveUserName }} </p>
<p><b>审批状态:</b> <el-tag size="small">{{ getStatusText(log.approveStatus) }}</el-tag></p>
</el-card>
</el-timeline-item>

View File

@ -76,6 +76,9 @@
<el-form-item label="联系电话" prop="purchaserMobile">
<span>{{ form.purchaserMobile }}</span>
</el-form-item>
</el-col>
<span>{{ form.purchaserMobile }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系邮箱" prop="purchaserEmail">
@ -238,7 +241,7 @@ export default {
status: 0,
approveStatus: 0,
approveNode: null,
confirmStatus: 0,
confirmStatus: null,
omsPurchaseOrderItemList: [
{
productType: null,
@ -464,7 +467,7 @@ export default {
status: 0,
approveStatus: 0,
approveNode: null,
confirmStatus: 0,
confirmStatus: null,
omsPurchaseOrderItemList: [
{
productType: null,

View File

@ -148,7 +148,7 @@
>删除
</el-button>
<el-button
v-if="scope.row.approveStatus === '1'"
v-if="scope.row.approveStatus === '1' || scope.row.approveStatus === '2'"
size="mini"
type="text"
icon="el-icon-view"
@ -156,6 +156,25 @@
v-hasPermi="['sip:purchaseorder:query']"
>查看详情
</el-button>
<!-- 发起供应商确认按钮 -->
<el-button
v-if="scope.row.flowType === 'online' && scope.row.approveStatus==='2' && (!scope.row.confirmStatus || scope.row.confirmStatus === ''|| scope.row.confirmStatus === '2')"
size="mini"
type="text"
icon="el-icon-s-promotion"
@click="handleInitiateVendorConfirmation(scope.row)"
v-hasPermi="['sip:purchaseorder:edit']"
>发起供应商确认
</el-button>
<el-button
v-if="scope.row.approveStatus === '2' && (!scope.row.confirmStatus || scope.row.confirmStatus === '')"
size="mini"
type="text"
icon="el-icon-refresh-left"
@click="handleRecall(scope.row)"
v-hasPermi="['sip:purchaseorder:recall']"
>撤回
</el-button>
</template>
</el-table-column>
</el-table>
@ -181,6 +200,28 @@
</template>
</el-dialog>
<!-- 流程类型选择对话框 -->
<el-dialog
title="选择流程类型"
:visible.sync="openFlowTypeDialog"
width="30%"
append-to-body
>
<el-form :model="{ flowType: selectedFlowType }" ref="flowTypeForm" label-width="80px">
<el-form-item label="流程类型" prop="flowType"
:rules="[{ required: true, message: '请选择流程类型', trigger: 'change' }]">
<el-select v-model="selectedFlowType" placeholder="请选择流程类型" style="width:100%">
<el-option label="线上" value="online"></el-option>
<el-option label="线下" value="offline"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitApplyWithFlowType"> </el-button>
<el-button @click="openFlowTypeDialog = false"> </el-button>
</div>
</el-dialog>
<!-- 订单详情抽屉 -->
<el-drawer
title="订单详情"
@ -227,7 +268,9 @@ import {
updatePurchaseorder,
applyPurchaseorder,
getPurchaseOrderHistory,
getPurchaseOrderHistoryDetail
getPurchaseOrderHistoryDetail,
recallPurchaseorder,
vendorConfirmStatus //
} from "@/api/sip/purchaseorder";
import PurchaseOrderDetail from './components/PurchaseOrderDetail';
import ApproveLayout from "@/views/approve/ApproveLayout.vue";
@ -258,6 +301,9 @@ export default {
currentOrderId: null,
//
currentOrderData: null,
openFlowTypeDialog: false, //
currentApplyingOrder: null, //
selectedFlowType: null, //
//
purchaseorderList: [],
//
@ -385,15 +431,9 @@ export default {
},
/** 申请采购按钮操作 */
handleApply(row) {
this.$modal.confirm('是否确认申请采购编号为"' + row.purchaseNo + '"的数据项?').then(() => {
let form = {...row};
form.approveStatus = '1'; // 1 ()
return applyPurchaseorder(form);
}).then(() => {
this.getList();
this.$modal.msgSuccess("申请采购成功");
}).catch(() => {
});
this.currentApplyingOrder = row; //
this.selectedFlowType = null; //
this.openFlowTypeDialog = true; //
},
/** 查看详情按钮操作 */
handleViewDetails(row) {
@ -410,6 +450,53 @@ export default {
this.showHistoryDetailDrawer = true;
this.showDetailDrawer = false; //
});
},
/** 提交申请采购(带流程类型) */
submitApplyWithFlowType() {
this.$refs.flowTypeForm.validate(valid => {
if (valid) {
let form = {...this.currentApplyingOrder};
form.approveStatus = '1'; // 1 ()
form.flowType = this.selectedFlowType; //
applyPurchaseorder(form).then(() => {
this.openFlowTypeDialog = false; //
this.getList();
this.$modal.msgSuccess("申请采购成功");
}).catch(() => {
this.openFlowTypeDialog = false; //
});
}
});
},
/** 撤回按钮操作 */
handleRecall(row) {
this.$modal.confirm('是否确认撤回采购订单编号为"' + row.purchaseNo + '"的数据项?').then(() => {
recallPurchaseorder(row.id).then(() => {
this.getList();
this.$modal.msgSuccess("撤回成功");
});
this.getList(); //
}).catch(() => {
});
},
/** 发起供应商确认操作 */
handleInitiateVendorConfirmation(row) {
this.$modal.confirm('是否确认发起供应商确认编号为"' + row.purchaseNo + '"的数据项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//
let data = {
id: row.id,
confirmStatus: '0' // 1 ()
};
vendorConfirmStatus(data).then(() => {
this.getList();
this.$modal.msgSuccess("发起供应商确认成功");
});
}).catch(() => {
});
}
}
};

View File

@ -119,6 +119,17 @@ public class OmsPurchaseOrderController extends BaseController
return toAjax(omsPurchaseOrderService.updateOmsPurchaseOrder(omsPurchaseOrder));
}
/**
*
*/
@RequiresPermissions("sip:purchaseorder:edit")
@Log(title = "采购单主表", businessType = BusinessType.UPDATE)
@PutMapping("/vendorConfirmStatus")
public AjaxResult vendorConfirmStatus(@RequestBody OmsPurchaseOrder omsPurchaseOrder)
{
return toAjax(omsPurchaseOrderService.vendorConfirmStatus(omsPurchaseOrder));
}
/**
*
*/
@ -150,6 +161,17 @@ public class OmsPurchaseOrderController extends BaseController
return success(omsPurchaseOrderHistoryService.selectOmsPurchaseOrderHistoryById(id));
}
/**
*
*/
@RequiresPermissions("sip:purchaseorder:recall")
@Log(title = "采购单主表", businessType = BusinessType.UPDATE)
@PutMapping("/recall/{id}")
public AjaxResult recall(@PathVariable("id") Long id)
{
return toAjax(omsPurchaseOrderService.recallPurchaseOrder(id));
}
/**
*
*/

View File

@ -82,8 +82,11 @@ public class OmsPurchaseOrder extends BaseEntity
/** 当前审批节点 */
private String approveNode;
/** 确认状态0待确认 1已确认 */
private Integer confirmStatus;
/** 确认状态(待审批、已确认、或空) */
private String confirmStatus;
/** 流程类型online线上 offline线下 */
private String flowType;
/** 删除标志0正常 1删除 */
private Integer delFlag;

View File

@ -81,10 +81,11 @@ public class OmsPurchaseOrderHistory extends BaseEntity
private String approveNode;
/** 确认状态0待确认 1已确认 */
private Integer confirmStatus;
private String confirmStatus;
/** 删除标志0正常 1删除 */
private Integer delFlag;
private String flowType;
/** 版本号 */
private Integer version;

View File

@ -68,6 +68,22 @@ public interface IOmsPurchaseOrderService
*/
public int deleteOmsPurchaseOrderById(Long id);
/**
*
*
* @param omsPurchaseOrder
* @return
*/
public int vendorConfirmStatus(OmsPurchaseOrder omsPurchaseOrder);
/**
*
*
* @param id
* @return
*/
public int recallPurchaseOrder(Long id);
List<OmsPurchaseOrder> listApprove(OmsPurchaseOrder omsPurchaseOrder);
List<OmsPurchaseOrder> listApproved(OmsPurchaseOrder omsPurchaseOrder);

View File

@ -298,6 +298,49 @@ public class OmsPurchaseOrderServiceImpl implements IOmsPurchaseOrderService, To
}
}
/**
*
*
* @param omsPurchaseOrder
* @return
*/
@Transactional
@Override
public int vendorConfirmStatus(OmsPurchaseOrder omsPurchaseOrder) {
omsPurchaseOrder.setUpdateTime(DateUtils.getNowDate());
return omsPurchaseOrderMapper.updateOmsPurchaseOrder(omsPurchaseOrder);
}
/**
*
*
* @param id
* @return
*/
@Transactional
@Override
public int recallPurchaseOrder(Long id) {
OmsPurchaseOrder omsPurchaseOrder = omsPurchaseOrderMapper.selectOmsPurchaseOrderById(id);
if (omsPurchaseOrder == null) {
throw new ServiceException("采购订单不存在");
}
// 只有审批状态为“已通过”(2) 且 供应商确认状态为空或 null 时才能撤回
if (ApproveStatusEnum.APPROVE_COMPLETE.getCode().equals(omsPurchaseOrder.getApproveStatus()) &&
(StringUtils.isEmpty(omsPurchaseOrder.getConfirmStatus()) || "".equals(omsPurchaseOrder.getConfirmStatus()))) {
// 保存历史记录
saveOrderHistory(omsPurchaseOrder);
omsPurchaseOrder.setApproveStatus(ApproveStatusEnum.WAIT_COMMIT.getCode()); // 设置为待审批(草稿)
omsPurchaseOrder.setApproveTime(null); // 清空审批时间
omsPurchaseOrder.setUpdateTime(DateUtils.getNowDate());
omsPurchaseOrder.setVersion(omsPurchaseOrder.getVersion() + 1); // 版本号 +1
return omsPurchaseOrderMapper.updateOmsPurchaseOrder(omsPurchaseOrder);
} else {
throw new ServiceException("当前订单状态不允许撤回");
}
}
@Override
public boolean multiInstanceApproveCallback(String activityName, ProcessInstance processInstance) {
return TodoCommonTemplate.super.multiInstanceApproveCallback(activityName, processInstance);

View File

@ -75,6 +75,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
<if test="flowType != null">flow_type,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="purchaseId != null">#{purchaseId},</if>
@ -107,6 +108,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">#{remark},</if>
<if test="flowType != null">#{flowType},</if>
</trim>
</insert>

View File

@ -46,7 +46,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectOmsPurchaseOrderVo">
select t1.id, t1.purchase_no, t1.buyer_name, t1.buyer_address, t1.vendor_id, t1.currency, t1.purchaser_id, t1.purchaser_name
, t1.purchaser_mobile, t1.purchaser_email, t1.warehouse_id, t1.pay_method, t1.owner_id, t1.owner_name, t1.remark, t1.total_amount
, t1.status, t1.approve_status, t1.approve_time, t1.approve_node, t1.confirm_status, t1.create_time, t1.update_time, t1.del_flag,t1.version
, t1.status, t1.approve_status, t1.approve_time, t1.approve_node, t1.confirm_status, t1.create_time, t1.update_time, t1.del_flag,t1.version,t1.flow_type
from oms_purchase_order t1
</sql>
<sql id="selectOmsPurchaseOrderItemVo">
@ -67,7 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</sql>
<sql id="selectOmsPurchaseOrderRelationVo">
select t1.id, t1.purchase_no, t1.buyer_name, t1.buyer_address, t1.vendor_id, t1.currency, t1.purchaser_id, t1.purchaser_name
, t1.purchaser_mobile, t1.purchaser_email, t1.warehouse_id, t1.pay_method, t1.owner_id, t1.owner_name, t1.remark, t1.total_amount
, t1.purchaser_mobile, t1.purchaser_email, t1.warehouse_id, t1.pay_method, t1.owner_id, t1.owner_name, t1.remark, t1.total_amount,t1.flow_type
, t1.status, t1.approve_status, t1.approve_time, t1.approve_node, t1.confirm_status, t1.create_time, t1.update_time, t1.del_flag,t1.version
,t2.vendor_name,t2.vendor_user,t2.vendor_phone
from oms_purchase_order t1
@ -99,10 +99,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="listApprove" resultType="com.ruoyi.sip.domain.OmsPurchaseOrder">
select t1.id, t1.purchase_no, t1.buyer_name, t1.buyer_address, t1.vendor_id, t1.currency, t1.purchaser_id, t1.purchaser_name
, t1.purchaser_mobile, t1.purchaser_email, t1.warehouse_id, t1.pay_method, t1.owner_id, t1.owner_name, t1.remark, t1.total_amount
, t1.purchaser_mobile, t1.purchaser_email, t1.warehouse_id, t1.pay_method, t1.owner_id, t1.owner_name, t1.remark, t1.total_amount,t1.flow_type
, t1.status, t1.approve_status, t1.approve_time, t1.approve_node, t1.confirm_status, t1.create_time, t1.update_time, t1.del_flag,t1.version
,t2.vendor_name,t2.vendor_user,t2.vendor_phone
,t3.apply_time,t3.process_key,t3.todo_id,t3.task_id,t3.approve_time as todo_approve_time
,t3.apply_time,t3.process_key,t3.todo_id,t3.task_id
<if test="'bu_todo_completed'.equals(tableName)">
,t3.approve_time as todo_approve_time
</if>
from oms_purchase_order t1
left join oms_vendor_info t2 on t1.vendor_id = t2.vendor_id
inner join ${tableName} t3 on (t3.process_key in ('purchase_order_online') and t3.approve_user=#{entity.approveUser} and t3.task_name!='商务' and t3.business_key=t1.purchase_no)
@ -167,6 +170,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">update_time,</if>
<if test="delFlag != null">del_flag,</if>
<if test="version != null">version,</if>
<if test="flowType != null">flow_type,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="purchaseNo != null">#{purchaseNo},</if>
@ -193,6 +197,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">#{updateTime},</if>
<if test="delFlag != null">#{delFlag},</if>
<if test="version != null">#{version},</if>
<if test="flowType != null">#{flowType},</if>
</trim>
</insert>
@ -223,6 +228,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="version != null">version = #{version},</if>
<if test="flowType != null">flow_type=#{flowType},</if>
</trim>
where id = #{id}
</update>
@ -253,6 +259,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="version != null">version = #{version},</if>
<if test="flowType != null">flow_type=#{flowType},</if>
</trim>
where purchase_no = #{purchaseNo}
</update>