add:合同导出功能

This commit is contained in:
zhangzq
2026-02-04 16:24:30 +08:00
parent 36a20f3ddc
commit f85db46bd5
24 changed files with 2019 additions and 1959 deletions

View File

@@ -77,6 +77,26 @@
<version>2.2.6</version>
</dependency>
<!--Excel-->
<!-- PDFBox for PDF to Image conversion -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.29</version>
</dependency>
<!-- OpenPDF for Excel to PDF conversion -->
<dependency>
<groupId>com.github.librepdf</groupId>
<artifactId>openpdf</artifactId>
<version>1.3.30</version>
</dependency>
<!-- 图像处理 -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>3.9.4</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>

View File

@@ -29,6 +29,7 @@ import com.deepoove.poi.data.Tables;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -198,7 +199,8 @@ public class ContractController {
com.deepoove.poi.config.Configure config = com.deepoove.poi.config.Configure.builder()
.bind("goods", new LoopRowTableRenderPolicy()) // 绑定rows标签使用循环行策略
.build();
InputStream templateStream = new java.io.FileInputStream("/Users/mima0000/Desktop/合同.docx");
ClassPathResource pathResource = new ClassPathResource("static/model/报价单样式.xls");// 根目录
InputStream templateStream = new java.io.FileInputStream(pathResource.getPath());
XWPFTemplate template = XWPFTemplate.compile(templateStream, config).render(dataMap);
// 6. 设置响应头
String fileName = "合同_" + contract.getContractCode() + ".docx";

View File

@@ -72,7 +72,7 @@ public class FlwInstanceController {
* 提交审批
*/
@PostMapping("/completeFlow2")
public R completeFlow2(@RequestBody Map<String, Object> params){
public R completeFlow2(@RequestBody FlowProcessParam params){
R r = instanceService.completeTaskById(params);
return r;
}

View File

@@ -43,6 +43,7 @@ public class ActHiProcessinfoEntity implements Serializable {
/**
* 最后更新人
*/
private Long createId;
private String createName;
/**
* 最后更新时间

View File

@@ -13,7 +13,6 @@ public interface FlwInstanceService {
R getTodoTaskList(Map<String, Object> params);
R completeTaskById(Map<String, Object> id);
R completeTaskById(FlowProcessParam param);

View File

@@ -2,6 +2,8 @@ package com.boge.modules.flow.service.impl;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.boge.common.exception.RRException;
import com.boge.common.utils.Constant;
@@ -19,6 +21,7 @@ import com.boge.modules.flow.service.ActHiProcessinfoService;
import com.boge.modules.flow.service.FlwInstanceService;
import com.boge.modules.sys.entity.SysUserEntity;
import com.boge.modules.sys.service.SysRoleService;
import com.boge.modules.sys.service.SysUserRoleService;
import com.boge.modules.sys.service.SysUserService;
import com.boge.modules.sys.service.impl.SysUserServiceImpl;
import com.boge.modules.tickets.dao.TicketsDao;
@@ -68,6 +71,9 @@ public class FlwInstanceServiceImpl extends FlowServiceNoFactory implements FlwI
private SysUserServiceImpl sysUserService;
@Autowired
private TicketsService ticketsService;
@Autowired
private SysUserRoleService sysUserRoleService;
@Autowired
private ActHiProcessinfoService actHiProcessinfoService;
@Value("${ProcessInstance.defId}")
@@ -93,7 +99,7 @@ public class FlwInstanceServiceImpl extends FlowServiceNoFactory implements FlwI
SysUserEntity loginUser = ShiroUtils.getUserEntity();
// 获取需要发起的流程信息
// String ticketsId = (String) params.get("ticketsId");
Long userId = Long.valueOf((String) params.get("user1"));
Long userId = Long.valueOf((String) params.get("userId"));
Map<String, Object> variable = new HashMap<>();
// 结合传递过来的数据动态的绑定流程变量
Set<String> keys = params.keySet();
@@ -335,63 +341,6 @@ public class FlwInstanceServiceImpl extends FlowServiceNoFactory implements FlwI
return R.ok("操作成功").put("page", pageUtils);
}
@Override
public R completeTaskById(Map<String, Object> params) {
String processInstance = (String) params.get("processInstance");
Integer ticketsId = (Integer) params.get("ticketsId");
String result = (String) params.get("result");
String opinion = (String) params.get("opinion");
String processName = ticketsDao.selectByProcessInstance(processInstance);
if (StringUtils.isBlank(processInstance)) {
return R.error("流程Id不能为空");
}
if (StringUtils.isBlank(processInstance)) {
return R.error("流程Id不能为空");
}
Task secondTask = taskService.createTaskQuery()
.processInstanceId(processInstance)
.singleResult();
Map<String, Object> secondApprovalVars = new HashMap<>();
TicketsEntity ticketsEntity = new TicketsEntity();
// 完结流程
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("完结")) {
secondApprovalVars.put("approvalResult", true);
ticketsEntity.setStatus(TicketsStatusEnums.FINISH.getCode());
ticketsEntity.setFinishTime(new Date());
ticketsEntity.setAssignUserId(TicketUserEnums.SPECIALIST.getCode());
taskService.complete(secondTask.getId(), secondApprovalVars);
}
// 继续流程
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("同意")) {
secondApprovalVars.put("approvalResult", false);
ticketsEntity.setAssignUserId(TicketUserEnums.MANAGER.getCode());
taskService.complete(secondTask.getId(), secondApprovalVars);
}
// 指派处理人
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("指派")) {
String userId = String.valueOf(params.get("userId"));
Map<String, Object> startVars = new HashMap<>();
startVars.put("user1",userId);
ticketsEntity.setAssignUserId(Long.valueOf(userId));
taskService.complete(secondTask.getId(), startVars);
}
// 继续流程
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("提交")) {
ticketsEntity.setAssignUserId(TicketUserEnums.SPECIALIST.getCode());
taskService.complete(secondTask.getId(), secondApprovalVars);
}
if (StringUtils.isNotBlank(processName)&& processName.contains("完结")){
ticketsEntity.setStatus(TicketsStatusEnums.FINISH.getCode());
}
//更新工单审批id
ticketsEntity.setTicketsId(Long.valueOf(ticketsId));
ticketsEntity.setUpdateTime(new Date());
ticketsService.updateById(ticketsEntity);
return R.ok("操作成功");
}
@Override
@Transactional
public R completeTaskById(FlowProcessParam params) {
@@ -406,6 +355,10 @@ public class FlwInstanceServiceImpl extends FlowServiceNoFactory implements FlwI
if (StringUtils.isBlank(processInstance)) {
return R.error("流程Id不能为空");
}
if (StringUtils.isBlank(result)) {
return R.error("审批结果不能为空");
}
Task secondTask = taskService.createTaskQuery()
.processInstanceId(processInstance)
.singleResult();
@@ -416,32 +369,43 @@ public class FlwInstanceServiceImpl extends FlowServiceNoFactory implements FlwI
secondApprovalVars.put("approvalResult", true);
ticketsEntity.setStatus(TicketsStatusEnums.FINISH.getCode());
ticketsEntity.setFinishTime(new Date());
ticketsEntity.setAssignUserId(TicketUserEnums.SPECIALIST.getCode());
ticketsEntity.setAssignUserId(ShiroUtils.getUserEntity().getCreateUserId());
taskService.complete(secondTask.getId(), secondApprovalVars);
}
// 继续流程
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("同意")) {
secondApprovalVars.put("approvalResult", false);
ticketsEntity.setAssignUserId(TicketUserEnums.MANAGER.getCode());
//指定角色为售后经理
List<Long> users = sysUserRoleService.queryRoleIdList(TicketUserEnums.MANAGER.getCode());
if (CollectionUtils.isEmpty(users)){
throw new RRException("未配置售后经理角色用户");
}
ticketsEntity.setAssignUserId(users.get(0));
taskService.complete(secondTask.getId(), secondApprovalVars);
}
// 指派处理人
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("指派")) {
String userId = params.getUserId();
String userId = String.valueOf(params.getUserId());
ticketsEntity.setAssignUserId(Long.valueOf(userId));
Map<String, Object> startVars = new HashMap<>();
startVars.put("user1",userId);
ticketsEntity.setAssignUserId(Long.valueOf(userId));
taskService.complete(secondTask.getId(), startVars);
}
// 继续流程
if (Objects.nonNull(secondTask) && StrUtil.isNotEmpty(result) && result.equals("提交")) {
ticketsEntity.setAssignUserId(TicketUserEnums.SPECIALIST.getCode());
//技术员提交-售后处理:谁创建谁终结
List<ActHiProcessinfoEntity> list = actHiProcessinfoService.list(new LambdaQueryWrapper<ActHiProcessinfoEntity>()
.eq(ActHiProcessinfoEntity::getProcInstId, processInstance)
.orderByAsc(ActHiProcessinfoEntity::getCreateTime).last("limit 1"));
ActHiProcessinfoEntity actHiProcessinfo = list.get(0);
ticketsEntity.setAssignUserId(actHiProcessinfo.getCreateId());
taskService.complete(secondTask.getId(), secondApprovalVars);
}
if (StringUtils.isNotBlank(processName)&& processName.contains("完结")){
ticketsEntity.setStatus(TicketsStatusEnums.FINISH.getCode());
}
//更新工单审批id
ticketsEntity.setTicketsId(Long.valueOf(ticketsId));
ticketsEntity.setUpdateTime(new Date());
@@ -453,6 +417,7 @@ public class FlwInstanceServiceImpl extends FlowServiceNoFactory implements FlwI
actHiProcessinfoEntity.setProcName(processName);
actHiProcessinfoEntity.setCreateTime(new Date());
actHiProcessinfoEntity.setCreateName(username);
actHiProcessinfoEntity.setCreateId(ShiroUtils.getUserEntity().getCreateUserId());
actHiProcessinfoService.save(actHiProcessinfoEntity);
return R.ok("操作成功");
}

View File

@@ -129,7 +129,7 @@ public class PriceController {
}
/**
* 审核
* 打印服务
*/
@RequestMapping("/export")
//@RequiresPermissions("flow:contract:delete")
@@ -140,4 +140,17 @@ public class PriceController {
localStorageService.downloadExcelModel(pathResource.getPath(),response,(JSONObject)JSON.toJSON(contract),JSONArray.parseArray(materialJson));
return R.ok();
}
/**
* 打印服务2
*/
@RequestMapping("/export2")
//@RequiresPermissions("flow:contract:delete")
public R export2(Integer priceId, HttpServletResponse response){
PriceEntity contract = priceService.getById(priceId);
ClassPathResource pathResource = new ClassPathResource("static/model/报价单样式.xls");// 根目录
String materialJson = contract.getMaterialJson();
localStorageService.downloadExcelModel(pathResource.getPath(),response,(JSONObject)JSON.toJSON(contract),JSONArray.parseArray(materialJson));
return R.ok();
}
}

View File

@@ -0,0 +1,19 @@
package com.boge.modules.screen;
import com.boge.common.utils.R;
import com.boge.modules.price.entity.PriceEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("screen")
public class ScreenController {
@RequestMapping("/info")
//@RequiresPermissions("flow:contract:info")
public R info(){
return R.ok();
}
}

View File

@@ -0,0 +1,34 @@
package com.boge.modules.screen.dto;
import com.boge.modules.knowledge.service.dto.KnowledgeVO;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
public class ScreenDto {
YearTicket yearTicket;
List<WeekTicket> weekTickets;
FlowData flowData;
List<KnowledgeVO> knowledgeVOS;
}
@Data
class YearTicket{
//年度工单情况
public Integer finish;
public Integer undo;
}
@Data
class WeekTicket{
//日期-工单数
public Date finish;
public Integer total;
}
@Data
class FlowData{
public Integer myStart;
public Integer myDo;
public Integer myfinish;
}

View File

@@ -11,6 +11,7 @@ package com.boge.modules.sys.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.boge.modules.sys.entity.SysUserRoleEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@@ -26,6 +27,8 @@ public interface SysUserRoleDao extends BaseMapper<SysUserRoleEntity> {
* 根据用户ID获取角色ID列表
*/
List<Long> queryRoleIdList(Long userId);
@Select("select user_id from sys_user_role where role_id = #{userId}")
List<Long> queryUserIdList(Long userId);
/**

View File

@@ -28,6 +28,7 @@ public interface SysUserRoleService extends IService<SysUserRoleEntity> {
* 根据用户ID获取角色ID列表
*/
List<Long> queryRoleIdList(Long userId);
List<Long> queryUserIdList(Long roleId);
/**
* 根据角色ID数组批量删除

View File

@@ -51,6 +51,12 @@ public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleDao, SysUserR
return baseMapper.queryRoleIdList(userId);
}
@Override
public List<Long> queryUserIdList(Long roleId) {
return baseMapper.queryRoleIdList(roleId);
}
@Override
public int deleteBatch(Long[] roleIds){
return baseMapper.deleteBatch(roleIds);

View File

@@ -88,7 +88,7 @@ file:
avatarMaxSize: 5
ProcessInstance:
defId: Process_1:9:70cda2de-bb83-11f0-a10e-e60d36456f41
defId: Process_1:10:e094f528-fe81-11f0-a80d-96bcd39f3c5b

View File

@@ -19,8 +19,8 @@ module.exports = {
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
// allow during development
'no- ': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
global:{
PubSub:true

View File

@@ -99,7 +99,7 @@ export default {
var formdata = new FormData()
formdata.append('file', this.file1.raw)
// excelImport请求接口 formdata传递参数
debugger
this.$http({
url: this.$http.adornUrl(this.urlApi),
method: 'post',

View File

@@ -509,7 +509,7 @@ export default {
})
},
reLoad (row) {
debugger
let price = JSON.parse(row.data)
this.dataForm.priceType = String(price.priceType)
this.dataForm.contractCode = price.contractCode
@@ -670,7 +670,7 @@ export default {
this.$refs.upload.submit();
},
submitPrice () {
debugger
if (this.fileList.length > 0) {
this.fileList.forEach(a => {
if (a.size > 10 * 1024 * 1024) {

View File

@@ -414,7 +414,7 @@ export default {
})
},
reLoad (row) {
debugger
let price = JSON.parse(row.data)
this.dataForm.priceType = String(price.priceType)
this.dataForm.fileNo = price.fileNo

View File

@@ -407,7 +407,7 @@ export default {
})
},
reLoad (row) {
debugger
let price = JSON.parse(row.data)
this.dataForm.priceType = String(price.priceType)
this.dataForm.fileNo = price.fileNo

View File

@@ -144,7 +144,7 @@
</el-input>
<!-- 外层容器控制对齐方式 -->
<div v-if= "ticketsData.processInstanceUser === '销售经理'" style="text-align: left; margin: 4px 0;"> <!-- 左对齐 + 更紧凑间距 -->
<div v-if= "ticketsData.processInstanceUser.includes('经理')" style="text-align: left; margin: 4px 0;"> <!-- 左对齐 + 更紧凑间距 -->
<el-button type="text" size="small"
class="custom-assign-btn"
@click="startFlowUser()"
@@ -155,23 +155,16 @@
<div v-if="assignedUsername" class="assigned-username">
指派{{ assignedUsername }}
</div>
<el-radio-group v-if= "ticketsData.processInstanceUser === '销售专员'" v-model="approvalForm.result">
<el-radio label="同意" border size="small">同意</el-radio>
<el-radio-group v-if= "ticketsData.processInstanceUser.includes('专员线上') ||ticketsData.processInstanceUser.includes('专员确认')" v-model="approvalForm.result">
<el-radio label="同意" border size="small">提交</el-radio>
<el-radio label="完结" border size="small">完结</el-radio>
</el-radio-group>
<!-- 附加选项 -->
<div class="approval-options">
<el-checkbox v-model="approvalForm.hideOpinion">意见隐藏</el-checkbox>
<div class="option-item">
<el-checkbox v-model="approvalForm.track">跟踪</el-checkbox>
</div>
</div>
<!-- 底部操作按钮固定在底部 -->
<div class="approval-actions">
<el-button size="small" @click="saveAsDraft">存为草稿</el-button>
<el-button size="small" @click="saveForLater">暂存待办</el-button>
<div v-if ="!ticketsData.processInstanceUser.includes('完结')" class="approval-actions">
<el-button type="primary" size="small" @click="submitApproval">提交</el-button>
</div>
<div v-if= "ticketsData.processInstanceUser.includes('完结')" class="approval-actions">
<el-button type="primary" size="small" @click="submitApproval">完结</el-button>
</div>
</div>
</div>
</div>
@@ -254,7 +247,7 @@ export default {
assignedUsername: '',
// 审批表单数据
approvalForm: {
result: '指派', // 默认为同意
result: '', // 默认为同意
remark: '', // 处理意见
hideOpinion: false, // 意见隐藏
track: false, // 跟踪
@@ -409,9 +402,14 @@ export default {
this.ticketsData = data.tickets;
}
const user = this.ticketsData.processInstanceUser;
if (user && (user.includes('指派') || user.includes('完结'))) {
this.approvalForm.result = '提交'; // 自动选中“同意”
if (user.includes('完结')) {
this.approvalForm.result = '提交' // 自动选中“同意”
} else if (user.includes('指派')) {
this.approvalForm.result = '指派' // 自动选中“同意”
}else if (user.includes('技术员')|| user.includes('维修员')) {
this.approvalForm.result = '提交' // 自动选中“同意”
}
this.$http({
url: this.$http.adornUrl(`/flw/instance/flowProcessList`),
method: 'get',
@@ -423,7 +421,6 @@ export default {
},
// 提交审批
submitApproval() {
debugger
if (!this.approvalForm.remark && this.approvalForm.result === '完结') {
this.$message.warning('完结时请填写处理意见');
return;
@@ -434,7 +431,7 @@ export default {
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
debugger
var formdata = new FormData()
this.fileList.forEach(a => {
formdata.append('file', a.raw)

View File

@@ -144,7 +144,7 @@
</el-input>
<!-- 外层容器控制对齐方式 -->
<div v-if= "ticketsData.processInstanceUser === '销售经理'" style="text-align: left; margin: 4px 0;"> <!-- 左对齐 + 更紧凑间距 -->
<div v-if= "ticketsData.processInstanceUser === '销售经理指派人员对接'" style="text-align: left; margin: 4px 0;"> <!-- 左对齐 + 更紧凑间距 -->
<el-button type="text" size="small"
class="custom-assign-btn"
@click="startFlowUser()"
@@ -155,8 +155,8 @@
<div v-if="assignedUsername" class="assigned-username">
指派{{ assignedUsername }}
</div>
<el-radio-group v-if= "ticketsData.processInstanceUser === '销售专员'" v-model="approvalForm.result">
<el-radio label="同意" border size="small">同意</el-radio>
<el-radio-group v-if= "ticketsData.processInstanceUser === '售后专员线上处理'" v-model="approvalForm.result">
<el-radio label="同意" border size="small">提交</el-radio>
<el-radio label="完结" border size="small">完结</el-radio>
</el-radio-group>
<!-- 附加选项 -->
@@ -423,7 +423,7 @@ export default {
},
// 提交审批
submitApproval() {
debugger
if (!this.approvalForm.remark && this.approvalForm.result === '完结') {
this.$message.warning('完结时请填写处理意见');
return;
@@ -434,7 +434,7 @@ export default {
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
debugger
var formdata = new FormData()
this.fileList.forEach(a => {
formdata.append('file', a.raw)

View File

@@ -4414,12 +4414,12 @@ vjs.SeekBar.prototype.onMouseMove = function(event){
};
vjs.SeekBar.prototype.onMouseUp = function(event){
debugger
vjs.Slider.prototype.onMouseUp.call(this, event);
this.player_.scrubbing = false;
if (this.videoWasPlaying) {
debugger
this.player_.play();
}
};

View File

@@ -4007,7 +4007,7 @@
// this.flashExec( 'Image', 'init', options );
// owner.on( 'load', function() {
// debugger;
// ;
// });
// },

View File

@@ -6553,7 +6553,7 @@
// this.flashExec( 'Image', 'init', options );
// owner.on( 'load', function() {
// debugger;
// ;
// });
// },