...
 
Commits (29)
......@@ -109,6 +109,24 @@
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!--数据库说明书-->
<!-- https://mvnrepository.com/artifact/cn.smallbun.screw/screw-core -->
<dependency>
<groupId>cn.smallbun.screw</groupId>
<artifactId>screw-core</artifactId>
<version>1.0.5</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/screw-core-1.0.5.jar</systemPath>
</dependency>
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
<build>
......
package com.maintain.web.controller.business;
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.util.ArrayList;
/**
* 数据库说明书
*/
public class ExportMysql {
public static void main(String[] args) {
//数据源
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
hikariConfig.setJdbcUrl("jdbc:mysql://rm-hp3340490n5mw72tcto.mysql.huhehaote.rds.aliyuncs.com:3306/tianmaiweixiu_db?currentSchema=single");
hikariConfig.setUsername("tianmaiweixiu");
hikariConfig.setPassword("7HTx9s@2wcbTQ@r1");
//设置可以获取tables remarks信息
hikariConfig.setMinimumIdle(2);
hikariConfig.setMaximumPoolSize(5);
HikariDataSource dataSource = new HikariDataSource(hikariConfig);
//生成配置
EngineConfig engineConfig = EngineConfig.builder()
//生成文件路径
.fileOutputDir("C:\\Users\\admin\\Desktop")
//打开目录
.openOutputDir(true)
//文件类型
.fileType(EngineFileType.WORD)
//生成模板实现
.produceType(EngineTemplateType.freemarker)
//自定义文件名称
.fileName("维修管理系统数据库说明书").build();
//忽略表
ArrayList<String> ignoreTableName = new ArrayList<>();
// ignoreTableName.add("sys_config");
// ignoreTableName.add("sys_user");
//忽略表前缀
ArrayList<String> ignorePrefix = new ArrayList<>();
// ignorePrefix.add("test_");
//忽略表后缀
ArrayList<String> ignoreSuffix = new ArrayList<>();
// ignoreSuffix.add("_test");
ProcessConfig processConfig = ProcessConfig.builder()
//指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置
//根据名称指定表生成
.designatedTableName(new ArrayList<>())
//根据表前缀生成
.designatedTablePrefix(new ArrayList<>())
//根据表后缀生成
.designatedTableSuffix(new ArrayList<>())
//忽略表名
.ignoreTableName(ignoreTableName)
//忽略表前缀
.ignoreTablePrefix(ignorePrefix)
//忽略表后缀
.ignoreTableSuffix(ignoreSuffix).build();
//配置
Configuration config = Configuration.builder()
//版本
.version("1.0.0")
//描述
.description("数据库设计文档生成")
//数据源
.dataSource(dataSource)
//生成配置
.engineConfig(engineConfig)
//生成配置
.produceConfig(processConfig)
.build();
//执行生成
new DocumentationExecute(config).execute();
}
}
......@@ -180,3 +180,11 @@ sms:
sdkAppId: appid
#地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
territory: ap-guangzhou
pay:
appid: 10037e6f72b586db0172b6ea24ec0000
appkey: 6f7a00170935445fbe25e67a5ce1be48
url: https://test-api-open.chinaums.com/v6/poslink/transaction/pay
merchantCode: 123456789111115
terminalCode: gxrb0001
deviceType: 11
payMode: CODE_SCAN
......@@ -183,3 +183,10 @@ sms:
sdkAppId: appid
#地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
territory: ap-guangzhou
pay:
appid: 8a81c1bd96cf23aa0199cc0a8dcb187c
appkey: 02c4bc73faaf46c89e0c620345a11aec
url: https://api-mop.chinaums.com/v6/poslink/transaction/pay
merchantCode: 898440300005398
deviceType: 11
payMode: CODE_SCAN
......@@ -102,7 +102,7 @@ sa-token:
timeout: 86400
# 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义
# token最低活跃时间 (指定时间无操作就过期) 单位: 秒
active-timeout: 1800
active-timeout: 43200
# 允许动态设置 token 有效期
dynamic-active-timeout: true
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
......@@ -139,9 +139,10 @@ security:
# actuator 监控配置
- /actuator
- /actuator/**
# - /jmreport/**
# - /drag/**
# - /jimubi/**
# 积木报表配置
- /jmreport/**
- /drag/**
- /jimubi/**
# MyBatisPlus配置
# https://baomidou.com/config/
......@@ -312,82 +313,15 @@ spring:
jeecg:
jmreport:
#多租户模式,默认值为空(created:按照创建人隔离、tenant:按照租户隔离) (v1.6.2+ 新增)
saasMode:
saasMode: createDeptId
# 平台上线安全配置(v1.6.2+ 新增)
firewall:
# 数据源安全 (开启后,不允许使用平台数据源、SQL解析加签并且不允许查询数据库)
dataSourceSafe: false
# 低代码开发模式(dev:开发模式, prod:发布模式关闭报表设计,admin或预留角色可设计, prodsf:发布安全模式 彻底关闭报表设计)
# 数据源安全 (开启后,不允许使用平台数据源、SQL解析不允许select * 查询、禁止测试数据源连接是否正确)
# 数据源安全下,预留角色有权限使用 select * 和测试数据源链接
dataSourceSafe: true
# 低代码开发模式(dev:开发模式,prod:发布模式关闭报表设计,预留角色admin、lowdeveloper可设计, prodsf:发布安全模式 彻底关闭报表设计)
lowCodeMode: dev
#是否 禁用导出PDF和图片的按钮 默认为false
exportDisabled: false
# 导出是否开启另存为弹窗 默认为false (v1.7.4+)
enableSaveAsOpen: false
#是否自动保存
autoSave: true
#自动保存间隔时间毫秒
interval: 20000
# 行数(设计页面展示多少行)
row: 100
# 列数(设计页面展示多少列)
col: 100
#自定义项目前缀
customPrePath:
# 自定义API接口的前缀 #{api_base_path}和#{domainURL}的值
apiBasePath: http://localhost:8080/jeecg-boot
#数据源标识(作废参数)
datasource: master
#预览分页自定义
pageSize:
- 10
- 20
- 30
- 40
#打印纸张自定义
printPaper:
- title: A5纸
size:
- 148
- 210
- title: B4纸
size:
- 250
- 353
#接口超时设置(毫秒)
connect-timeout: 300000
#导出超时时间(毫秒,默认600000)
export-timeout: 600000
#Excel导出模式(fast/快、primary/精致模式,默认fast)
export-excel-pattern: fast
#Excel导出数据每个sheet的行数,每个sheet最大1048576行
page-size-number: 10000
#设计页面表格的线是否显示 默认true
line: true
#只看自己创建数据 (v1.6.2+删除)
saas: false
#是否开启租户模式 (v1.6.2+删除)
openTenant: false
#sql数据源不写字典下拉框显示条数 (v1.4.2+删除)
select-show-total: 10
#是否启用签名校验,默认不开启,对执行sql的接口参数校验(v1.6.2+删除)
safeMode: true
# 自动导出 ( v1.7.5+ )
automate:
# python文件目录,绝对路径
py-path: "/usr/bin/python3"
export:
# 非必须,下载的报表的存放目录(服务器上的绝对路径)
download-path: "/home/jimureport-auto-export/downloads/"
# 非必须,积木报表view页面地址
jimu-view-path: "http://???/jmreport/shareView/"
# 使用插件导出必须,插件访问域名 比如: http://127.0.0.1:16065
plugin-domain: "http://127.0.0.1:16065"
# 文件过期时间,单位天,默认:30
expired: 30
# 导出任务使用插件,默认false
job-use-plugin: false
# 开启自动导出( v1.9.6+ ),默认false
enable-auto-export: false
#国际化(v1.9.5+新增)
i18n:
enable: false
# api数据集内网ip白名单,在发布模式下只只能向设置了白名单的内网服务器发送请求。
apiDsIpWhite:
# sql注入检查级别(strict:严格, basic:简单校验, none:不校验)
sqlInjectionLevel: strict
package com.maintain.business.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import com.maintain.business.domain.vo.ErpMaterialPickingExportVo;
import com.maintain.common.utils.poi.SheetPO;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
......@@ -62,8 +65,9 @@ public class ErpMaterialPickingController extends BaseController {
@Log(title = "物料出库", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpMaterialPickingBo bo, HttpServletResponse response) {
List<ErpMaterialPickingVo> list = iErpMaterialPickingService.queryList(bo);
ExcelUtil.exportExcel(list, "物料出库", ErpMaterialPickingVo.class, response);
iErpMaterialPickingService.export(bo,response);
// List<ErpMaterialPickingVo> list = iErpMaterialPickingService.queryList(bo);
// ExcelUtil.exportExcel(list, "物料出库", ErpMaterialPickingVo.class, response);
}
/**
......
......@@ -103,6 +103,17 @@ public class ErpRepairFormProjectDispatchController extends BaseController {
return toAjax(iErpRepairFormProjectDispatchService.updateByBo(bo));
}
/**
* 修改报修单-报修项目-派工
*/
@SaCheckPermission("business:repairFormProjectDispatch:edit")
@Log(title = "报修单-报修项目-派工", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/batch")
public R<Void> edit(@Validated(EditGroup.class) @RequestBody List<ErpRepairFormProjectDispatchBo> bo) {
return toAjax(iErpRepairFormProjectDispatchService.updateBatchByBo(bo));
}
/**
* 删除报修单-报修项目-派工
*
......
......@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;
import com.maintain.business.domain.bo.ErpSettlementMaintainPayBo;
import com.maintain.business.domain.bo.ErpSettlementMaintainRepairFormBo;
import com.maintain.business.domain.vo.ErpSettlementMaintainRepairFormVo;
import com.maintain.business.service.IErpRepairFormService;
......@@ -137,4 +138,16 @@ public class ErpSettlementMaintainController extends BaseController {
public R<Void> receipt(@Validated(EditGroup.class) @RequestBody ErpSettlementMaintainBo bo) {
return toAjax(iErpSettlementMaintainService.receiptByBo(bo));
}
/**
* 结算维修单回执
*
* @param bo
*/
@Log(title = "结算维修单支付", businessType = BusinessType.UPDATE)
@PutMapping("/pay")
public R<Void> pay(@Validated(EditGroup.class) @RequestBody ErpSettlementMaintainPayBo bo) {
return toAjax(iErpSettlementMaintainService.pay(bo));
}
}
......@@ -62,4 +62,19 @@ public class ErpCar extends BaseEntity {
*/
private Long carTypeId;
/**
* 分公司
*/
private String branchOffice;
/**
* 车队
*/
private String motorcade;
/**
* 线路
*/
private String line;
}
......@@ -92,6 +92,10 @@ public class ErpMaterial extends BaseEntity {
* 物资品牌
*/
private String materialBrand;
/**
* 生产厂家
*/
private String manufacturer;
/**
* 采购标的
*/
......
......@@ -110,7 +110,7 @@ public class ErpMaterialPickingInfo extends BaseEntity {
*/
private BigDecimal putawayMoney;
/**
* 状态(1已领料 2已退料)
* 状态(1登记中 2已完成 3已退料)
*/
private Integer state;
......
......@@ -71,9 +71,13 @@ public class ErpSettlementMaintain extends BaseEntity {
*/
private Date settlementTime;
/**
* 支付方式(1支付宝 2微信
* 支付方式(1扫码支付 2手动支付
*/
private Integer paymentMethod;
/**
* 支付单号
*/
private String paymentNumber;
/**
* 付款账号
*/
......@@ -111,7 +115,7 @@ public class ErpSettlementMaintain extends BaseEntity {
*/
private String collectionAccount;
/**
* 收款流水号
* 交易流水号
*/
private String collectionSerialNumber;
/**
......
package com.maintain.business.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maintain.common.core.domain.BaseEntity;
/**
* 银联支付日志记录对象 sys_pay_log
*
* @author liushuai
* @date 2025-11-10
*/
@Data
@TableName("sys_pay_log")
public class SysPayLog implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 结算维修单ID
*/
private Long settlementMaintainId;
/**
* 认证报文
*/
private String authorization;
/**
* 请求参数
*/
private String operParam;
/**
* 返回参数
*/
private String jsonResult;
/**
* 操作状态(0正常 1异常)
*/
private String status;
/**
* 操作时间
*/
private Date operTime;
/**
* 操作用户
*/
private Long operUser;
}
......@@ -82,5 +82,19 @@ public class ErpCarBo extends BaseEntity {
*/
private Date createTime;
/**
* 分公司
*/
private String branchOffice;
/**
* 车队
*/
private String motorcade;
/**
* 线路
*/
private String line;
}
......@@ -114,6 +114,10 @@ public class ErpMaterialBo extends BaseEntity {
* 物资品牌
*/
private String materialBrand;
/**
* 生产厂家
*/
private String manufacturer;
/**
* 采购标的
*/
......
......@@ -131,4 +131,14 @@ public class ErpMaterialPickingBo extends BaseEntity {
private List<ErpMaterialPickingInfoAddBo> materialList;
/**
* 导出IDs
*/
private List<Long> ids;
/**
* 单位IDS
*/
private List<Long> deptIds;
}
......@@ -90,7 +90,6 @@ public class ErpSettlementMaintainBo extends BaseEntity {
/**
* 支付方式(1支付宝 2微信)
*/
@NotNull(message = "支付方式(1支付宝 2微信)不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer paymentMethod;
/**
......@@ -106,7 +105,6 @@ public class ErpSettlementMaintainBo extends BaseEntity {
/**
* 付款凭证
*/
@NotBlank(message = "付款凭证不能为空", groups = { AddGroup.class, EditGroup.class })
private String paymentVoucher;
/**
......
package com.maintain.business.domain.bo;
import com.maintain.common.core.domain.BaseEntity;
import com.maintain.common.core.validate.AddGroup;
import com.maintain.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 结算维修单业务对象 erp_settlement_maintain
*
* @author liushuai
* @date 2025-04-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ErpSettlementMaintainPayBo extends BaseEntity {
/**
* 结算单ID
*/
@NotNull(message = "结算单ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long id;
/**
* 付款码
*/
@NotBlank(message = "付款码不能为空", groups = { AddGroup.class, EditGroup.class })
private String paymentAccount;
}
package com.maintain.business.domain.bo;
import com.maintain.common.core.validate.AddGroup;
import com.maintain.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maintain.common.core.domain.BaseEntity;
/**
* 银联支付日志记录业务对象 sys_pay_log
*
* @author liushuai
* @date 2025-11-10
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SysPayLogBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 结算维修单ID
*/
@NotNull(message = "结算维修单ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long settlementMaintainId;
/**
* 认证报文
*/
@NotBlank(message = "认证报文不能为空", groups = { AddGroup.class, EditGroup.class })
private String authorization;
/**
* 请求参数
*/
@NotBlank(message = "请求参数不能为空", groups = { AddGroup.class, EditGroup.class })
private String operParam;
/**
* 返回参数
*/
@NotBlank(message = "返回参数不能为空", groups = { AddGroup.class, EditGroup.class })
private String jsonResult;
/**
* 操作状态(0正常 1异常)
*/
@NotNull(message = "操作状态(0正常 1异常)不能为空", groups = { AddGroup.class, EditGroup.class })
private Long status;
/**
* 操作时间
*/
@NotNull(message = "操作时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date operTime;
}
......@@ -110,4 +110,22 @@ public class ErpCarVo implements Serializable {
@ColumnWidth(20)
private Date createTime;
/**
* 分公司
*/
@ExcelProperty(value = "分公司")
private String branchOffice;
/**
* 车队
*/
@ExcelProperty(value = "车队")
private String motorcade;
/**
* 线路
*/
@ExcelProperty(value = "线路")
private String line;
}
package com.maintain.business.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.enums.poi.BorderStyleEnum;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import com.alibaba.excel.enums.poi.VerticalAlignmentEnum;
import com.maintain.common.annotation.ExcelDictFormat;
import com.maintain.common.convert.ExcelDictConvert;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* @Author haoxuyang
* @Date 2026/4/2 9:24
*/
@Data
@HeadRowHeight(value = 35)
@ContentRowHeight(value = 22)
/** 金黄表头、黑字、细边框(与 IndexedColors 调色板接近 #FFC107/#FFB800 效果) */
@HeadStyle(
fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND,
fillForegroundColor = 51,
horizontalAlignment = HorizontalAlignmentEnum.CENTER,
verticalAlignment = VerticalAlignmentEnum.CENTER,
borderLeft = BorderStyleEnum.THIN,
borderRight = BorderStyleEnum.THIN,
borderTop = BorderStyleEnum.THIN,
borderBottom = BorderStyleEnum.THIN,
leftBorderColor = 8,
rightBorderColor = 8,
topBorderColor = 8,
bottomBorderColor = 8
)
@HeadFontStyle(color = 8)
public class ErpMaterialPickingExportVo {
/**
* 序号
*/
@ColumnWidth(20)
@ExcelProperty(index = 0, value = {"title", "序号"})
private String index;
/**
* 分公司
*/
@ColumnWidth(20)
@ExcelProperty(index = 1, value = {"title", "分公司"})
private String branchOffice;
/**
* 车间
*/
@ColumnWidth(20)
@ExcelProperty(index = 2, value = {"title", "车间"})
private String workshopName;
/**
* 仓库
*/
@ColumnWidth(20)
@ExcelProperty(index = 3, value = {"title", "仓库"})
private String warehouseName;
/**
* 到货单号
*/
@ColumnWidth(20)
@ExcelProperty(index = 4, value = {"title", "到货单号"})
private String arrivalNumber;
/**
* 领料人
*/
@ColumnWidth(20)
@ExcelProperty(index = 5, value = {"title", "领料人"})
private String receiveUserName;
/**
* 领料时间
*/
@ColumnWidth(25)
@ExcelProperty(index = 6, value = {"title", "领料时间"})
private Date receiveTime;
/**
* 材料编码
*/
@ColumnWidth(20)
@ExcelProperty(index = 7, value = {"title", "材料编码"})
private String materialCode;
/**
* 物资名称
*/
@ColumnWidth(20)
@ExcelProperty(index = 8, value = {"title", "物资名称"})
private String materialName;
/**
* 规格
*/
@ColumnWidth(20)
@ExcelProperty(index = 9, value = {"title", "规格"})
private String materialSpecifications;
/**
* 单位
*/
@ColumnWidth(20)
@ExcelProperty(index = 10, value = {"title", "单位"}, converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "material_unit")
private String materialUnit;
/**
* 入库价格
*/
@ColumnWidth(20)
@ExcelProperty(index = 11, value = {"title", "入库价格"})
private BigDecimal putawayPrice;
/**
* 数量
*/
@ColumnWidth(20)
@ExcelProperty(index = 12, value = {"title", "数量"})
private BigDecimal collectNumber;
/**
* 合计(元)
*/
@ColumnWidth(20)
@ExcelProperty(index = 13, value = {"title", "合计(元)"})
private BigDecimal money;
/**
* 供应商名称
*/
@ColumnWidth(30)
@ExcelProperty(index = 14, value = {"title", "供应商名称"})
private String vendorName;
}
......@@ -122,6 +122,11 @@ public class ErpMaterialVo implements Serializable {
*/
@ExcelProperty(value = "物资品牌")
private String materialBrand;
/**
* 生产厂家
*/
@ExcelProperty(value = "生产厂家")
private String manufacturer;
/**
* 采购标的
*/
......
package com.maintain.business.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.maintain.common.annotation.ExcelDictFormat;
import com.maintain.common.convert.ExcelDictConvert;
import lombok.Data;
import java.util.Date;
import java.io.Serializable;
/**
* 银联支付日志记录视图对象 sys_pay_log
*
* @author liushuai
* @date 2025-11-10
*/
@Data
@ExcelIgnoreUnannotated
public class SysPayLogVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 结算维修单ID
*/
@ExcelProperty(value = "结算维修单ID")
private Long settlementMaintainId;
/**
* 认证报文
*/
@ExcelProperty(value = "认证报文")
private String authorization;
/**
* 请求参数
*/
@ExcelProperty(value = "请求参数")
private String operParam;
/**
* 返回参数
*/
@ExcelProperty(value = "返回参数")
private String jsonResult;
/**
* 操作状态(0正常 1异常)
*/
@ExcelProperty(value = "操作状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=正常,1=异常")
private Long status;
/**
* 操作时间
*/
@ExcelProperty(value = "操作时间")
private Date operTime;
}
......@@ -84,21 +84,21 @@ public class ErpMaterialImportListener extends AnalysisEventListener<ErpMaterial
}
}
/**
* 物资类型
* 物资类型(弃用)
*/
if (StringUtils.isNotEmpty(material.getMaterialTypeName())) {
List<ErpMaterialType> materialTypes = materialTypeMapper.selectList(new LambdaQueryWrapper<ErpMaterialType>().eq(ErpMaterialType::getTypeName, material.getMaterialTypeName()));
if (materialTypes.isEmpty()) {
ErpMaterialType materialType = new ErpMaterialType();
materialType.setTypeName(material.getMaterialTypeName());
materialType.setParentId(1L);
materialType.setAncestors("0,1");
materialTypeMapper.insert(materialType);
material.setMaterialTypeId(materialType.getTypeId());
}else {
material.setMaterialTypeId(materialTypes.get(0).getTypeId());
}
}
// if (StringUtils.isNotEmpty(material.getMaterialTypeName())) {
// List<ErpMaterialType> materialTypes = materialTypeMapper.selectList(new LambdaQueryWrapper<ErpMaterialType>().eq(ErpMaterialType::getTypeName, material.getMaterialTypeName()));
// if (materialTypes.isEmpty()) {
// ErpMaterialType materialType = new ErpMaterialType();
// materialType.setTypeName(material.getMaterialTypeName());
// materialType.setParentId(1L);
// materialType.setAncestors("0,1");
// materialTypeMapper.insert(materialType);
// material.setMaterialTypeId(materialType.getTypeId());
// }else {
// material.setMaterialTypeId(materialTypes.get(0).getTypeId());
// }
// }
/**
* 供应商
*/
......@@ -114,22 +114,22 @@ public class ErpMaterialImportListener extends AnalysisEventListener<ErpMaterial
}
}
/**
* 仓库货位
* 仓库货位(弃用)
*/
if (StringUtils.isNotEmpty(material.getWarehouseLocationType())) {
ErpWarehouseLocation warehouseLocation = warehouseLocationMapper.selectOne(new LambdaQueryWrapper<ErpWarehouseLocation>().eq(ErpWarehouseLocation::getLocationType, material.getWarehouseLocationType()));
if (ObjectUtil.isNull(warehouseLocation)) {
ErpWarehouseLocation location = new ErpWarehouseLocation();
location.setLocationCode(material.getWarehouseLocationType());
location.setLocationType(material.getWarehouseLocationType());
warehouseLocationMapper.insert(location);
material.setWarehouseLocationCode(location.getLocationCode());
material.setWarehouseLocationId(location.getId());
} else {
material.setWarehouseLocationCode(warehouseLocation.getLocationCode());
material.setWarehouseLocationId(warehouseLocation.getId());
}
}
// if (StringUtils.isNotEmpty(material.getWarehouseLocationType())) {
// ErpWarehouseLocation warehouseLocation = warehouseLocationMapper.selectOne(new LambdaQueryWrapper<ErpWarehouseLocation>().eq(ErpWarehouseLocation::getLocationType, material.getWarehouseLocationType()));
// if (ObjectUtil.isNull(warehouseLocation)) {
// ErpWarehouseLocation location = new ErpWarehouseLocation();
// location.setLocationCode(material.getWarehouseLocationType());
// location.setLocationType(material.getWarehouseLocationType());
// warehouseLocationMapper.insert(location);
// material.setWarehouseLocationCode(location.getLocationCode());
// material.setWarehouseLocationId(location.getId());
// } else {
// material.setWarehouseLocationCode(warehouseLocation.getLocationCode());
// material.setWarehouseLocationId(warehouseLocation.getId());
// }
// }
materialMapper.insert(material);
successNum++;
successMsg.append("<br/>").append(successNum).append("、物料 【").append(material.getMaterialName()).append("】 导入成功");
......@@ -141,19 +141,19 @@ public class ErpMaterialImportListener extends AnalysisEventListener<ErpMaterial
/**
* 物资类型
*/
if (StringUtils.isNotEmpty(material.getMaterialTypeName())) {
List<ErpMaterialType> materialTypes = materialTypeMapper.selectList(new LambdaQueryWrapper<ErpMaterialType>().eq(ErpMaterialType::getTypeName, material.getMaterialTypeName()));
if (materialTypes.isEmpty()) {
ErpMaterialType materialType = new ErpMaterialType();
materialType.setTypeName(material.getMaterialTypeName());
materialType.setParentId(1L);
materialType.setAncestors("0,1");
materialTypeMapper.insert(materialType);
material.setMaterialTypeId(materialType.getTypeId());
}else {
material.setMaterialTypeId(materialTypes.get(0).getTypeId());
}
}
// if (StringUtils.isNotEmpty(material.getMaterialTypeName())) {
// List<ErpMaterialType> materialTypes = materialTypeMapper.selectList(new LambdaQueryWrapper<ErpMaterialType>().eq(ErpMaterialType::getTypeName, material.getMaterialTypeName()));
// if (materialTypes.isEmpty()) {
// ErpMaterialType materialType = new ErpMaterialType();
// materialType.setTypeName(material.getMaterialTypeName());
// materialType.setParentId(1L);
// materialType.setAncestors("0,1");
// materialTypeMapper.insert(materialType);
// material.setMaterialTypeId(materialType.getTypeId());
// }else {
// material.setMaterialTypeId(materialTypes.get(0).getTypeId());
// }
// }
/**
* 物资仓库
*/
......@@ -186,18 +186,18 @@ public class ErpMaterialImportListener extends AnalysisEventListener<ErpMaterial
/**
* 仓库货位
*/
if (StringUtils.isNotEmpty(material.getWarehouseLocationType())) {
ErpWarehouseLocation warehouseLocation = warehouseLocationMapper.selectOne(new LambdaQueryWrapper<ErpWarehouseLocation>().eq(ErpWarehouseLocation::getLocationType, material.getWarehouseLocationType()));
if (ObjectUtil.isNull(warehouseLocation)) {
ErpWarehouseLocation location = new ErpWarehouseLocation();
location.setLocationCode(material.getWarehouseLocationType());
location.setLocationType(material.getWarehouseLocationType());
warehouseLocationMapper.insert(location);
material.setWarehouseLocationId(location.getId());
} else {
material.setWarehouseLocationId(warehouseLocation.getId());
}
}
// if (StringUtils.isNotEmpty(material.getWarehouseLocationType())) {
// ErpWarehouseLocation warehouseLocation = warehouseLocationMapper.selectOne(new LambdaQueryWrapper<ErpWarehouseLocation>().eq(ErpWarehouseLocation::getLocationType, material.getWarehouseLocationType()));
// if (ObjectUtil.isNull(warehouseLocation)) {
// ErpWarehouseLocation location = new ErpWarehouseLocation();
// location.setLocationCode(material.getWarehouseLocationType());
// location.setLocationType(material.getWarehouseLocationType());
// warehouseLocationMapper.insert(location);
// material.setWarehouseLocationId(location.getId());
// } else {
// material.setWarehouseLocationId(warehouseLocation.getId());
// }
// }
materialMapper.updateById(material);
successNum++;
successMsg.append("<br/>").append(successNum).append("、物料 ").append(material.getMaterialName()).append(" 更新成功");
......
......@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maintain.business.domain.ErpMaterialPickingInfo;
import com.maintain.business.domain.ErpMaterialReturnsInfo;
import com.maintain.business.domain.bo.ErpMaterialPickingBo;
import com.maintain.business.domain.vo.ErpMaterialPickingExportVo;
import com.maintain.business.domain.vo.ErpMaterialPickingInfoVo;
import com.maintain.business.domain.vo.ErpMaterialReturnsInfoVo;
import com.maintain.common.core.mapper.BaseMapperPlus;
......@@ -35,4 +37,10 @@ public interface ErpMaterialPickingInfoMapper extends BaseMapperPlus<ErpMaterial
*/
List<ErpMaterialPickingInfoVo> customQueryList(@Param(Constants.WRAPPER) Wrapper<ErpMaterialPickingInfo> queryWrapper);
/**
* 获取导出列表
* @param bo 参数
* @return 结果
*/
List<ErpMaterialPickingExportVo> getExportList(ErpMaterialPickingBo bo);
}
package com.maintain.business.mapper;
import com.maintain.business.domain.SysPayLog;
import com.maintain.business.domain.vo.SysPayLogVo;
import com.maintain.common.core.mapper.BaseMapperPlus;
/**
* 银联支付日志记录Mapper接口
*
* @author liushuai
* @date 2025-11-10
*/
public interface SysPayLogMapper extends BaseMapperPlus<SysPayLogMapper, SysPayLog, SysPayLogVo> {
}
......@@ -6,6 +6,7 @@ import com.maintain.business.domain.bo.ErpMaterialPickingBo;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.core.domain.PageQuery;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.List;
......@@ -63,4 +64,9 @@ public interface IErpMaterialPickingService {
* 新增物料出库退料
*/
Boolean insertReturnByBo(ErpMaterialPickingBo bo);
/**
* 导出物料出库列表
*/
void export(ErpMaterialPickingBo bo, HttpServletResponse response);
}
......@@ -47,6 +47,11 @@ public interface IErpRepairFormProjectDispatchService {
*/
Boolean updateByBo(ErpRepairFormProjectDispatchBo bo);
/**
* 修改报修单-报修项目-派工
*/
Boolean updateBatchByBo(List<ErpRepairFormProjectDispatchBo> boList);
/**
* 校验并批量删除报修单-报修项目-派工信息
*/
......
package com.maintain.business.service;
import com.maintain.business.domain.ErpSettlementMaintain;
import com.maintain.business.domain.vo.ErpSettlementMaintainVo;
import com.maintain.business.domain.bo.ErpSettlementMaintainBo;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.business.domain.bo.ErpSettlementMaintainPayBo;
import com.maintain.business.domain.vo.ErpSettlementMaintainVo;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
......@@ -53,4 +53,11 @@ public interface IErpSettlementMaintainService {
* @return
*/
Boolean receiptByBo(ErpSettlementMaintainBo bo);
/**
* 结算维修单支付
* @param bo
* @return
*/
Boolean pay(ErpSettlementMaintainPayBo bo);
}
package com.maintain.business.service;
import com.maintain.business.domain.bo.SysPayLogBo;
import com.maintain.business.domain.vo.SysPayLogVo;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.pay.PayResult;
import java.util.List;
/**
* 银联支付日志记录Service接口
*
* @author liushuai
* @date 2025-11-10
*/
public interface ISysPayLogService {
/**
* 查询银联支付日志记录
*/
SysPayLogVo queryById(Long id);
/**
* 查询银联支付日志记录列表
*/
TableDataInfo<SysPayLogVo> queryPageList(SysPayLogBo bo, PageQuery pageQuery);
/**
* 查询银联支付日志记录列表
*/
List<SysPayLogVo> queryList(SysPayLogBo bo);
/**
* 新增银联支付日志记录
*/
PayResult insertByBo(Long id, PayResult payResult);
}
......@@ -2,14 +2,12 @@ package com.maintain.business.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.maintain.business.domain.ErpMaintainMalfunction;
import com.maintain.business.domain.ErpMalfunctionProject;
import com.maintain.business.domain.ErpProjectType;
import com.maintain.business.domain.*;
import com.maintain.business.domain.bo.ErpMalfunctionProjectBo;
import com.maintain.business.domain.vo.ErpMalfunctionProjectVo;
import com.maintain.business.mapper.ErpMaintainMalfunctionMapper;
import com.maintain.business.mapper.ErpMalfunctionProjectMapper;
import com.maintain.business.mapper.ErpProjectTypeMapper;
import com.maintain.business.domain.vo.ErpRepairFormProjectVo;
import com.maintain.business.mapper.*;
import com.maintain.common.exception.ServiceException;
import com.maintain.common.pinyin.PinyinUtils;
import com.maintain.common.utils.StringUtils;
import com.maintain.common.core.page.TableDataInfo;
......@@ -21,14 +19,13 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.maintain.business.domain.bo.ErpMaintainProjectBo;
import com.maintain.business.domain.vo.ErpMaintainProjectVo;
import com.maintain.business.domain.ErpMaintainProject;
import com.maintain.business.mapper.ErpMaintainProjectMapper;
import com.maintain.business.service.IErpMaintainProjectService;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
/**
......@@ -45,6 +42,7 @@ public class ErpMaintainProjectServiceImpl implements IErpMaintainProjectService
private final ErpProjectTypeMapper projectTypeMapper;
private final ErpMalfunctionProjectMapper malfunctionProjectMapper;
private final ErpMaintainMalfunctionMapper maintainMalfunctionMapper;
private final ErpRepairFormProjectMapper repairFormProjectMapper;
/**
......@@ -176,11 +174,18 @@ public class ErpMaintainProjectServiceImpl implements IErpMaintainProjectService
/**
* 批量删除维修项目
*/
@Transactional
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
List<ErpRepairFormProjectVo> projectVos = repairFormProjectMapper.selectVoList(new LambdaQueryWrapper<ErpRepairFormProject>().in(ErpRepairFormProject::getMaintainId, ids));
if (!projectVos.isEmpty()) {
Set<String> collect = projectVos.stream().map(ErpRepairFormProjectVo::getProjectName).collect(Collectors.toSet());
throw new ServiceException("删除失败,维修项目 "+collect+" 已被使用!");
}
}
maintainMalfunctionMapper.delete(new LambdaQueryWrapper<ErpMaintainMalfunction>().in(ErpMaintainMalfunction::getMaintainId, ids));
return baseMapper.deleteBatchIds(ids) > 0;
}
}
......@@ -87,9 +87,9 @@ public class ErpMaterialInventoryRecordServiceImpl implements IErpMaterialInvent
.eq("t.type", 1)
.like(StringUtils.isNotBlank(bo.getMaterialName()),"t.material_name", bo.getMaterialName())
.like(StringUtils.isNotBlank(bo.getMaterialCode()),"t.material_code", bo.getMaterialCode())
.like(null != bo.getVendorId(),"t.vendor_id", bo.getVendorId())
.eq(null != bo.getVendorId(),"t.vendor_id", bo.getVendorId())
.like(null != bo.getWarehouseId(), "t.warehouse_id", bo.getWarehouseId())
.in(!bo.getWarehouseIdList().isEmpty(), "t.warehouse_id", bo.getWarehouseIdList())
.in(null != bo.getWarehouseIdList(), "t.warehouse_id", bo.getWarehouseIdList())
.ge(null != bo.getInventory(), "t.inventory", bo.getInventory())
.orderByDesc("t.create_time");
Page<ErpMaterialInventoryRecordVo> queryPageList = baseMapper.customQueryPageInventoryList(pageQuery.build(), query);
......
package com.maintain.business.service.impl;
import java.util.Date;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.maintain.business.domain.*;
import com.maintain.business.domain.bo.ErpMaterialPickingInfoAddBo;
import com.maintain.business.domain.bo.ErpMaterialPickingInfoBo;
......@@ -22,6 +24,9 @@ import com.maintain.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.maintain.common.utils.poi.ExcelUtil;
import com.maintain.common.utils.poi.MergeCellModel;
import com.maintain.common.utils.poi.SheetPO;
import com.maintain.common.utils.redis.RedisUtils;
import com.maintain.system.mapper.SysDeptMapper;
import lombok.RequiredArgsConstructor;
......@@ -30,6 +35,7 @@ import com.maintain.business.domain.bo.ErpMaterialPickingBo;
import com.maintain.business.service.IErpMaterialPickingService;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
......@@ -142,7 +148,7 @@ public class ErpMaterialPickingServiceImpl implements IErpMaterialPickingService
lqw.eq(bo.getReceiveTime() != null, ErpMaterialPicking::getReceiveTime, bo.getReceiveTime());
lqw.eq(bo.getState() != null, ErpMaterialPicking::getState, bo.getState());
lqw.in(bo.getStateList() != null, ErpMaterialPicking::getState, bo.getStateList());
lqw.in(!sysDeptList.isEmpty(), ErpMaterialPicking::getCreateDeptId, sysDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()));
lqw.in(bo.getRepairFormId() == null && !sysDeptList.isEmpty(), ErpMaterialPicking::getCreateDeptId, sysDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()));
lqw.orderByDesc(BaseEntity::getCreateTime);
return lqw;
}
......@@ -168,7 +174,7 @@ public class ErpMaterialPickingServiceImpl implements IErpMaterialPickingService
add.setVendorName(materialVendor.getVendorName());
BigDecimal moneyTotal = bo.getMaterialList().stream().map(ErpMaterialPickingInfoAddBo::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
add.setOutMoney(moneyTotal);
add.setCreateDeptId(LoginHelper.getUserId());
add.setCreateDeptId(LoginHelper.getDeptId());
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
......@@ -446,4 +452,58 @@ public class ErpMaterialPickingServiceImpl implements IErpMaterialPickingService
}
return flag;
}
@Override
public void export(ErpMaterialPickingBo bo, HttpServletResponse response) {
String sheetName ="供应商材料消耗明细表";
String title ="供应商铺货结算表";
List<SysDept> sysDeptList = deptMapper.selectChildrenDeptById(LoginHelper.getDeptId(), null);
if (!sysDeptList.isEmpty()){
bo.setDeptIds(sysDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()));
}
List<ErpMaterialPickingExportVo> list = pickingInfoMapper.getExportList(bo);
//生成合并单元格信息
List<MergeCellModel> mergeCellList = new ArrayList<>();
Integer centerMergedAnchorExcelRowIndex = null;
if (CollectionUtils.isNotEmpty(list)){
list.forEach(item -> {
item.setIndex(String.valueOf(list.indexOf(item) + 1));
});
//合计统计
ErpMaterialPickingExportVo erpMaterialPickingExportVo1 = new ErpMaterialPickingExportVo();
// 合计文案须落在合并区域左上角列:index=0 为序号(Integer),合并 0~10 时左上角为空会“吃掉”7、8 列的合计文字
erpMaterialPickingExportVo1.setIndex("合计");
list.add(erpMaterialPickingExportVo1);
// 双行表头:第 0 行为大标题,第 1 行为列名;合计行 Excel 行号 = list.size() + 1
int totalExcelRowIndex = list.size() + 1;
centerMergedAnchorExcelRowIndex = totalExcelRowIndex;
mergeCellList.add(MergeCellModel.createMergeCellModel(sheetName, totalExcelRowIndex, totalExcelRowIndex, 0, 11));
//计算数量总和
BigDecimal collectNumber = list.stream().map(ErpMaterialPickingExportVo::getCollectNumber).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
erpMaterialPickingExportVo1.setCollectNumber(collectNumber);
//计算价格总和
BigDecimal money = list.stream().map(ErpMaterialPickingExportVo::getMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
erpMaterialPickingExportVo1.setMoney(money);
//签名地方
ErpMaterialPickingExportVo erpMaterialPickingExportVo2 = new ErpMaterialPickingExportVo();
erpMaterialPickingExportVo2.setWorkshopName("车间仓库员签名:");
erpMaterialPickingExportVo2.setMaterialSpecifications("车间负责人签名:");
list.add(erpMaterialPickingExportVo2);
}
List<SheetPO> sheetPOList = new ArrayList<>();
SheetPO<ErpMaterialPickingExportVo> sheetPO = new SheetPO<>();
sheetPOList.add(sheetPO);
Map<String, String> titleMap = new HashMap<>();
titleMap.put("title", title);
sheetPO.setData(list);
sheetPO.setTitleMap(titleMap);
sheetPO.setClazz(ErpMaterialPickingExportVo.class);
sheetPO.setSheetNo(1);
sheetPO.setMergeCellList(mergeCellList);
sheetPO.setSheetName(sheetName);
sheetPO.setWhiteFirstHeadRow(true);
sheetPO.setCenterMergedAnchorExcelRowIndex(centerMergedAnchorExcelRowIndex);
ExcelUtil.exportSheetSetTitle(response, title, sheetPOList);
}
}
......@@ -247,6 +247,7 @@ public class ErpMaterialPutawayServiceImpl implements IErpMaterialPutawayService
List<ErpMaterialInventoryRecord> inventoryRecordList = collect.stream().map(item -> {
ErpMaterialInventoryRecord record = new ErpMaterialInventoryRecord();
record.setInfoId(item.getId());
record.setVendorId(item.getVendorId());
record.setMaterialId(item.getMaterialId());
record.setWarehouseId(warehouseVo.getId());
record.setDeptId(warehouseVo.getDeptId());
......
......@@ -3,12 +3,16 @@ package com.maintain.business.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.maintain.business.domain.*;
import com.maintain.business.domain.vo.ErpMaterialInventoryRecordVo;
import com.maintain.business.domain.vo.ErpUserVo;
import com.maintain.business.domain.vo.ErpWarehouseVo;
import com.maintain.business.mapper.*;
import com.maintain.business.service.IErpMaterialService;
import com.maintain.common.enums.InventoryType;
import com.maintain.common.enums.IsEnableStatus;
import com.maintain.common.enums.PickingState;
import com.maintain.common.enums.RepairFormState;
import com.maintain.common.exception.ServiceException;
import com.maintain.common.utils.StringUtils;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.core.domain.PageQuery;
......@@ -44,6 +48,9 @@ public class ErpRepairFormDeliveryServiceImpl implements IErpRepairFormDeliveryS
private final ErpMaterialPickingMapper pickingMapper;
private final ErpMaterialPickingInfoMapper pickingInfoMapper;
private final IErpMaterialService materialService;
private final ErpMaterialInventoryRecordMapper materialInventoryRecordMapper;
private final ErpMaterialPutawayInfoMapper putawayInfoMapper;
private final ErpWarehouseMapper warehouseMapper;
/**
* 查询报修单-交车信息
......@@ -116,15 +123,37 @@ public class ErpRepairFormDeliveryServiceImpl implements IErpRepairFormDeliveryS
pickingInfoLambdaQueryWrapper.eq(ErpMaterialPickingInfo::getRepairFormId, add.getRepairFormId()).eq(ErpMaterialPickingInfo::getState, PickingState.ONE.getCode());
List<ErpMaterialPickingInfo> pickingInfoList = pickingInfoMapper.selectList(pickingInfoLambdaQueryWrapper);
if (!pickingInfoList.isEmpty()) {
for (ErpMaterialPickingInfo pickingInfo : pickingInfoList) {
materialService.modifyMaterialInventory(pickingInfo.getMaterialId(), pickingInfo.getCollectNumber(), false);
}
pickingInfoMapper.updateBatchById(pickingInfoList.stream().map(item -> {
ErpMaterialPickingInfo pickingInfo = new ErpMaterialPickingInfo();
pickingInfo.setId(item.getId());
pickingInfo.setState(PickingState.TWO.getCode());
return pickingInfo;
}).collect(Collectors.toList()));
List<ErpMaterialInventoryRecord> inventoryRecordList = pickingInfoList.stream().map(item -> {
ErpMaterialInventoryRecordVo recordVo = materialInventoryRecordMapper.customQueryInventoryById(item.getRecordId());
if (null == recordVo) {
throw new ServiceException("仓库["+item.getWarehouseName()+"]中物料["+item.getMaterialName()+"]库存异常,请联系管理员!");
}
if (item.getCollectNumber().compareTo(recordVo.getInventory()) > 0) {
throw new ServiceException("仓库["+item.getWarehouseName()+"]中物料["+item.getMaterialName()+"]库存不足,请调整后重试!");
}
/* 记录已出数量 */
ErpMaterialInventoryRecord inventoryRecord = materialInventoryRecordMapper.selectById(item.getRecordId());
if (null == inventoryRecord) {
throw new ServiceException("库存存在异常,请联系管理员!!!");
}
ErpMaterialPutawayInfo putawayInfo = putawayInfoMapper.selectById(inventoryRecord.getInfoId());
putawayInfo.setIssuedNumber(putawayInfo.getIssuedNumber().add(item.getCollectNumber()));
putawayInfoMapper.updateById(putawayInfo);
/* 创建库存记录 */
ErpMaterialInventoryRecord record = new ErpMaterialInventoryRecord();
record.setInfoId(item.getId());
record.setMaterialId(item.getMaterialId());
ErpWarehouseVo warehouseVo = warehouseMapper.selectVoById(item.getWarehouseId());
record.setWarehouseId(warehouseVo.getId());
record.setDeptId(warehouseVo.getDeptId());
record.setVendorId(item.getVendorId());
record.setNumber(item.getCollectNumber());
record.setPrice(item.getPrice());
record.setMoney(item.getMoney());
record.setType(InventoryType.picking.getCode());
return record;
}).collect(Collectors.toList());
materialInventoryRecordMapper.insertBatch(inventoryRecordList);
}
}
return flag;
......
package com.maintain.business.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.maintain.business.domain.ErpRepairFormProject;
import com.maintain.business.domain.bo.ErpRepairFormProjectDispatchBatchBo;
import com.maintain.business.domain.vo.ErpUserVo;
......@@ -23,6 +24,8 @@ import com.maintain.business.service.IErpRepairFormProjectDispatchService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Collection;
......@@ -112,10 +115,22 @@ public class ErpRepairFormProjectDispatchServiceImpl implements IErpRepairFormPr
@Override
public Boolean insertBatchByBo(ErpRepairFormProjectDispatchBatchBo bo) {
ErpRepairFormProject formProject = projectMapper.selectById(bo.getProjectId());
// 删除原有绑定
LambdaQueryWrapper<ErpRepairFormProjectDispatch> lqw = Wrappers.lambdaQuery();
lqw.eq(ErpRepairFormProjectDispatch::getRepairFormProjectId, bo.getProjectId());
BigDecimal totalActualManHour = baseMapper.selectList(lqw)
.stream()
.map(ErpRepairFormProjectDispatch::getActualManHour).reduce(BigDecimal.ZERO, BigDecimal::add);
baseMapper.delete(lqw);
// 汇总原总工时
//总工时均分
BigDecimal hour = formProject.getStandardManHour().divide(
BigDecimal.valueOf(bo.getDispatchIdList().size()), 1, RoundingMode.HALF_DOWN
);
BigDecimal totalHour = hour.multiply(BigDecimal.valueOf(bo.getDispatchIdList().size()));
BigDecimal lostHour = formProject.getStandardManHour().subtract(totalHour);
// 批量新增派工人员列表
List<ErpRepairFormProjectDispatch> collect = bo.getDispatchIdList().stream().map(item -> {
ErpRepairFormProjectDispatch projectDispatch = new ErpRepairFormProjectDispatch();
......@@ -132,15 +147,20 @@ public class ErpRepairFormProjectDispatchServiceImpl implements IErpRepairFormPr
projectDispatch.setMaintainUserName(userVo.getName());
projectDispatch.setMaintainJobNumber(userVo.getJobNumber());
projectDispatch.setMaintainUserState(userVo.getState());
BigDecimal hour = formProject.getStandardManHour().divide(BigDecimal.valueOf(bo.getDispatchIdList().size()));
projectDispatch.setDispatchManHour(hour);
projectDispatch.setActualManHour(hour);
// projectDispatch.setDeductManHour(hour);
// 汇总实际总工时
formProject.setActualTime(formProject.getActualTime().add(hour));
return projectDispatch;
}).collect(Collectors.toList());
//处理最后一个
if (bo.getDispatchIdList().size() > 1) {
ErpRepairFormProjectDispatch projectDispatch = collect.get(collect.size() - 1);
projectDispatch.setDispatchManHour(projectDispatch.getDispatchManHour().add(lostHour));
projectDispatch.setActualManHour(hour);
}
formProject.setIsDispatch(IsEnableStatus.YES.getCode());
formProject.setActualTime(formProject.getStandardManHour());
projectMapper.updateById(formProject);
return baseMapper.insertBatch(collect);
}
......@@ -149,11 +169,43 @@ public class ErpRepairFormProjectDispatchServiceImpl implements IErpRepairFormPr
* 修改报修单-报修项目-派工
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(ErpRepairFormProjectDispatchBo bo) {
ErpRepairFormProjectDispatch projectDispatch = baseMapper.selectById(bo.getId());
projectDispatch.setDispatchManHour(bo.getDispatchManHour());
projectDispatch.setActualManHour(bo.getDispatchManHour().subtract(bo.getDeductManHour()));
projectDispatch.setDeductManHour(bo.getDeductManHour());
return baseMapper.updateById(projectDispatch) > 0;
boolean flag = baseMapper.updateById(projectDispatch) > 0;
updateFormProject(projectDispatch.getRepairFormProjectId());
return flag;
}
@Override
public Boolean updateBatchByBo(List<ErpRepairFormProjectDispatchBo> boList) {
if (CollUtil.isEmpty(boList)){
return false;
}
List<ErpRepairFormProjectDispatch> dispatchList = boList.stream().map(bo -> {
ErpRepairFormProjectDispatch projectDispatch = new ErpRepairFormProjectDispatch();
projectDispatch.setId(bo.getId());
projectDispatch.setDispatchManHour(bo.getDispatchManHour());
projectDispatch.setActualManHour(bo.getDispatchManHour().subtract(bo.getDeductManHour()));
projectDispatch.setDeductManHour(bo.getDeductManHour());
return projectDispatch;
}).collect(Collectors.toList());
baseMapper.updateBatchById(dispatchList);
//计算总工时
BigDecimal reduce = dispatchList.stream().map(ErpRepairFormProjectDispatch::getActualManHour).reduce(BigDecimal.ZERO, BigDecimal::add);
ErpRepairFormProject project = new ErpRepairFormProject();
project.setId(boList.get(0).getRepairFormProjectId());
project.setActualTime(reduce);
projectMapper.updateById(project);
return true;
}
/**
......@@ -167,10 +219,34 @@ public class ErpRepairFormProjectDispatchServiceImpl implements IErpRepairFormPr
* 批量删除报修单-报修项目-派工
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
Iterator<Long> iterator = ids.iterator();
Long id = iterator.hasNext() ? iterator.next() : null;
ErpRepairFormProjectDispatch projectDispatch = baseMapper.selectById(id);
boolean flag = baseMapper.deleteBatchIds(ids) > 0;
updateFormProject(projectDispatch.getRepairFormProjectId());
return flag;
}
/**
* 更新报修单-报修项目实际时间
* @param projectId
*/
private void updateFormProject(Long projectId){
List<ErpRepairFormProjectDispatch> formProjectDispatches = baseMapper.selectList(Wrappers.<ErpRepairFormProjectDispatch>lambdaQuery()
.eq(ErpRepairFormProjectDispatch::getRepairFormProjectId, projectId));
//计算总工时
BigDecimal reduce = formProjectDispatches.stream().map(ErpRepairFormProjectDispatch::getActualManHour).reduce(BigDecimal.ZERO, BigDecimal::add);
ErpRepairFormProject project = new ErpRepairFormProject();
project.setId(projectId);
project.setActualTime(reduce);
projectMapper.updateById(project);
}
}
package com.maintain.business.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maintain.business.domain.*;
import com.maintain.business.domain.bo.ErpRepairFormBo;
import com.maintain.business.domain.vo.ErpGroupVo;
import com.maintain.business.domain.vo.ErpMaterialInventoryRecordVo;
import com.maintain.business.domain.vo.ErpRepairFormDeliveryVo;
import com.maintain.business.domain.vo.ErpRepairFormVo;
import com.maintain.business.mapper.*;
import com.maintain.business.service.IErpMaterialService;
import com.maintain.business.service.IErpRepairFormService;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.domain.entity.SysDept;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.enums.PickingState;
import com.maintain.common.enums.RepairFormState;
import com.maintain.common.helper.LoginHelper;
import com.maintain.common.utils.StringUtils;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.maintain.common.utils.redis.RedisUtils;
import com.maintain.system.mapper.SysDeptMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.maintain.business.domain.bo.ErpRepairFormBo;
import com.maintain.business.domain.vo.ErpRepairFormVo;
import com.maintain.business.service.IErpRepairFormService;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
......@@ -55,6 +56,9 @@ public class ErpRepairFormServiceImpl implements IErpRepairFormService {
private final ErpMaterialPickingInfoMapper pickingInfoMapper;
private final ErpMaterialPickingMapper pickingMapper;
private final IErpMaterialService materialService;
private final ErpMaterialInventoryRecordMapper materialInventoryRecordMapper;
private final ErpMaterialPutawayInfoMapper putawayInfoMapper;
private final ErpWarehouseMapper warehouseMapper;
/**
* 查询报修单
......@@ -289,18 +293,29 @@ public class ErpRepairFormServiceImpl implements IErpRepairFormService {
LambdaQueryWrapper<ErpMaterialPickingInfo> pickingInfoLambdaQueryWrapper = Wrappers.lambdaQuery();
pickingInfoLambdaQueryWrapper.eq(ErpMaterialPickingInfo::getRepairFormId, repairForm.getId()).eq(ErpMaterialPickingInfo::getState, PickingState.TWO.getCode());
List<ErpMaterialPickingInfo> pickingInfoList = pickingInfoMapper.selectList(pickingInfoLambdaQueryWrapper);
for (ErpMaterialPickingInfo pickingInfo : pickingInfoList) {
materialService.modifyMaterialInventory(pickingInfo.getMaterialId(), pickingInfo.getCollectNumber(), true);
}
List<Long> pickingInfoIds = pickingInfoList.stream().map(item -> {
/* 回退入库明细中已出数量 */
ErpMaterialInventoryRecordVo recordVo = materialInventoryRecordMapper.customQueryInventoryById(item.getRecordId());
ErpMaterialPutawayInfo putawayInfo = putawayInfoMapper.selectById(recordVo.getInfoId());
putawayInfo.setIssuedNumber(putawayInfo.getIssuedNumber().subtract(item.getCollectNumber()));
putawayInfoMapper.updateById(putawayInfo);
return item.getId();
}).collect(Collectors.toList());
// 将出库单以及出库明细所有状态全部更新为已退料
LambdaUpdateWrapper<ErpMaterialPicking> pickingLambdaUpdateWrapper = Wrappers.lambdaUpdate();
pickingLambdaUpdateWrapper.eq(ErpMaterialPicking::getRepairFormId, repairForm.getId());
pickingLambdaUpdateWrapper.set(ErpMaterialPicking::getState, PickingState.THREE.getCode());
pickingMapper.update(pickingLambdaUpdateWrapper);
LambdaUpdateWrapper<ErpMaterialPickingInfo> pickingInfoLambdaUpdateWrapper = Wrappers.lambdaUpdate();
pickingInfoLambdaUpdateWrapper.eq(ErpMaterialPickingInfo::getRepairFormId, repairForm.getId());
pickingInfoLambdaUpdateWrapper.set(ErpMaterialPickingInfo::getState, PickingState.THREE.getCode());
pickingInfoMapper.update(pickingInfoLambdaUpdateWrapper);
pickingMapper.delete(
new LambdaUpdateWrapper<ErpMaterialPicking>()
.eq(ErpMaterialPicking::getRepairFormId, repairForm.getId())
);
pickingInfoMapper.delete(
new LambdaUpdateWrapper<ErpMaterialPickingInfo>()
.eq(ErpMaterialPickingInfo::getRepairFormId, repairForm.getId())
);
// 删除库存记录表数据
if (!pickingInfoIds.isEmpty()) {
LambdaUpdateWrapper<ErpMaterialInventoryRecord> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
lambdaUpdateWrapper.in(ErpMaterialInventoryRecord::getInfoId, pickingInfoIds);
materialInventoryRecordMapper.delete(lambdaUpdateWrapper);
}
}
return flag;
}
......
package com.maintain.business.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maintain.business.domain.ErpRepairForm;
import com.maintain.business.domain.ErpSettlementMaintain;
import com.maintain.business.domain.ErpSettlementMaintainRepairForm;
import com.maintain.business.domain.bo.ErpSettlementMaintainRepairFormBo;
import com.maintain.business.domain.bo.ErpSettlementMaintainBo;
import com.maintain.business.domain.bo.ErpSettlementMaintainPayBo;
import com.maintain.business.domain.vo.ErpClientVo;
import com.maintain.business.domain.vo.ErpSettlementMaintainVo;
import com.maintain.business.mapper.ErpClientMapper;
import com.maintain.business.mapper.ErpRepairFormMapper;
import com.maintain.business.mapper.ErpSettlementMaintainMapper;
import com.maintain.business.mapper.ErpSettlementMaintainRepairFormMapper;
import com.maintain.business.service.IErpSettlementMaintainService;
import com.maintain.business.service.ISysPayLogService;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.domain.entity.SysDept;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.enums.RepairFormSettlementState;
import com.maintain.common.enums.SettlementState;
import com.maintain.common.exception.ServiceException;
import com.maintain.common.helper.LoginHelper;
import com.maintain.common.pay.PayResponse;
import com.maintain.common.pay.PayResult;
import com.maintain.common.pay.YinLianPayApi;
import com.maintain.common.utils.StringUtils;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.maintain.common.utils.redis.RedisUtils;
import com.maintain.system.mapper.SysDeptMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.maintain.business.domain.bo.ErpSettlementMaintainBo;
import com.maintain.business.domain.vo.ErpSettlementMaintainVo;
import com.maintain.business.domain.ErpSettlementMaintain;
import com.maintain.business.mapper.ErpSettlementMaintainMapper;
import com.maintain.business.service.IErpSettlementMaintainService;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
......@@ -49,6 +57,12 @@ public class ErpSettlementMaintainServiceImpl implements IErpSettlementMaintainS
private final ErpSettlementMaintainRepairFormMapper settlementMaintainRepairFormMapper;
private final ErpRepairFormMapper repairFormMapper;
private final ErpClientMapper clientMapper;
private final YinLianPayApi yinLianPayApi;
private final SysDeptMapper sysDeptMapper;
private final ISysPayLogService sysPayLogService;
private final SysDeptMapper deptMapper;
@Value("${pay.merchantCode}")
private String merchantCode;
/**
* 查询结算维修单
......@@ -78,6 +92,7 @@ public class ErpSettlementMaintainServiceImpl implements IErpSettlementMaintainS
}
private LambdaQueryWrapper<ErpSettlementMaintain> buildQueryWrapper(ErpSettlementMaintainBo bo) {
List<SysDept> sysDeptList = deptMapper.selectChildrenDeptById(LoginHelper.getDeptId(), null);
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<ErpSettlementMaintain> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getSettlementNumber()), ErpSettlementMaintain::getSettlementNumber, bo.getSettlementNumber());
......@@ -88,7 +103,7 @@ public class ErpSettlementMaintainServiceImpl implements IErpSettlementMaintainS
lqw.eq(bo.getClientCertificateType() != null, ErpSettlementMaintain::getClientCertificateType, bo.getClientCertificateType());
lqw.eq(StringUtils.isNotBlank(bo.getClientCertificateNumber()), ErpSettlementMaintain::getClientCertificateNumber, bo.getClientCertificateNumber());
lqw.eq(bo.getState() != null, ErpSettlementMaintain::getState, bo.getState());
lqw.eq(bo.getCreateDeptId() != null, ErpSettlementMaintain::getCreateDeptId, bo.getCreateDeptId());
lqw.in(ErpSettlementMaintain::getCreateDeptId, sysDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()));
lqw.orderByDesc(ErpSettlementMaintain::getCreateTime);
return lqw;
}
......@@ -204,4 +219,65 @@ public class ErpSettlementMaintainServiceImpl implements IErpSettlementMaintainS
}
return flag;
}
/**
* 结算维修单支付
*
* @param bo
* @return
*/
@Transactional(rollbackFor = Exception.class)
@Override
public Boolean pay(ErpSettlementMaintainPayBo bo) {
ErpSettlementMaintain maintain = baseMapper.selectById(bo.getId());
List<ErpSettlementMaintainRepairForm> maintainRepairForms = settlementMaintainRepairFormMapper.selectList(
new LambdaQueryWrapper<ErpSettlementMaintainRepairForm>()
.eq(ErpSettlementMaintainRepairForm::getSettlementMaintainId, maintain.getId())
);
if (ObjectUtil.isEmpty(maintainRepairForms)) {
throw new ServiceException("当前结算单未绑定维修单,请检查后重试!");
}
ErpSettlementMaintainRepairForm settlementMaintainRepairForm = maintainRepairForms.get(0);
ErpRepairForm repairForm = repairFormMapper.selectById(settlementMaintainRepairForm.getRepairFormId());
if (ObjectUtil.isEmpty(repairForm)) {
throw new ServiceException("报修单不存在,请联系管理员!");
}
SysDept sysDept = sysDeptMapper.selectById(repairForm.getRepairerDeptId());
if (ObjectUtil.isEmpty(sysDept)) {
throw new ServiceException("维修车间不存在,请联系管理员!");
}
if (ObjectUtil.isEmpty(sysDept.getTerminalCode())) {
throw new ServiceException("当前车间未填写终端号,请联系管理员添加!");
}
if (ObjectUtil.isEmpty(maintain)) {
throw new ServiceException("当前支付订单不存在,请刷新后重试!");
}
if (maintain.getState().equals(SettlementState.TWO.getCode())) {
throw new ServiceException("当前结算单已支付,不能重复支付!");
}
// 生成一个时间戳单号
String orderNo = String.valueOf(System.currentTimeMillis());
int money = maintain.getPracticalMoney().movePointRight(2).intValue();
if (money == 0) {
throw new ServiceException("结算单金额为0,无需支付!");
}
// 调用支付API
PayResult payResult = yinLianPayApi.pay(orderNo, money, bo.getPaymentAccount(), sysDept.getTerminalCode());
/* 保存支付调用记录 */
sysPayLogService.insertByBo(maintain.getId(), payResult);
PayResponse payResponse = payResult.getPayResponse();
/* 判断是否支付成功 */
if (!payResponse.getErrCode().equals("00")) {
throw new ServiceException("结算单支付失败:"+ payResponse.getErrInfo());
}
maintain.setCollectionAccount(merchantCode);
maintain.setCollectionSerialNumber(payResponse.getOrderId());
maintain.setCollectionTime(new Date());
maintain.setState(SettlementState.TWO.getCode());
maintain.setPaymentMethod(1);
maintain.setPaymentAccount(bo.getPaymentAccount());
maintain.setPaymentNumber(orderNo);
baseMapper.updateById(maintain);
return true;
}
}
package com.maintain.business.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maintain.business.domain.SysPayLog;
import com.maintain.business.domain.bo.SysPayLogBo;
import com.maintain.business.domain.vo.SysPayLogVo;
import com.maintain.business.mapper.SysPayLogMapper;
import com.maintain.business.service.ISysPayLogService;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.helper.LoginHelper;
import com.maintain.common.pay.PayResult;
import com.maintain.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 银联支付日志记录Service业务层处理
*
* @author liushuai
* @date 2025-11-10
*/
@RequiredArgsConstructor
@Service
public class SysPayLogServiceImpl implements ISysPayLogService {
private final SysPayLogMapper baseMapper;
/**
* 查询银联支付日志记录
*/
@Override
public SysPayLogVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 查询银联支付日志记录列表
*/
@Override
public TableDataInfo<SysPayLogVo> queryPageList(SysPayLogBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<SysPayLog> lqw = buildQueryWrapper(bo);
Page<SysPayLogVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询银联支付日志记录列表
*/
@Override
public List<SysPayLogVo> queryList(SysPayLogBo bo) {
LambdaQueryWrapper<SysPayLog> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<SysPayLog> buildQueryWrapper(SysPayLogBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<SysPayLog> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getSettlementMaintainId() != null, SysPayLog::getSettlementMaintainId, bo.getSettlementMaintainId());
lqw.eq(StringUtils.isNotBlank(bo.getAuthorization()), SysPayLog::getAuthorization, bo.getAuthorization());
lqw.eq(StringUtils.isNotBlank(bo.getOperParam()), SysPayLog::getOperParam, bo.getOperParam());
lqw.eq(StringUtils.isNotBlank(bo.getJsonResult()), SysPayLog::getJsonResult, bo.getJsonResult());
lqw.eq(bo.getStatus() != null, SysPayLog::getStatus, bo.getStatus());
lqw.eq(bo.getOperTime() != null, SysPayLog::getOperTime, bo.getOperTime());
return lqw;
}
/**
* 新增银联支付日志记录
*/
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class, timeout = 30)
public PayResult insertByBo(Long id, PayResult payResult) {
// 保存支付日志
SysPayLog sysPayLog = new SysPayLog();
sysPayLog.setSettlementMaintainId(id);
sysPayLog.setAuthorization(payResult.getAuthorization());
sysPayLog.setOperParam(payResult.getRequestParams());
sysPayLog.setJsonResult(payResult.getResponse());
sysPayLog.setStatus(payResult.getPayResponse().getErrCode());
sysPayLog.setOperTime(new Date());
sysPayLog.setOperUser(LoginHelper.getUserId());
baseMapper.insert(sysPayLog);
return payResult;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(SysPayLog entity){
//TODO 做一些数据校验,如唯一约束
}
}
......@@ -83,58 +83,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) t
</sql>
<sql id="list">
SELECT t.* FROM (SELECT
r.id as recordId,
r.info_id,
r.material_id,
r.warehouse_id,
r.vendor_id,
r.price,
r.type,
r.create_time,
IFNULL(put.put_number, 0) - IFNULL(ret.ret_number, 0) - IFNULL(pic.out_number, 0) + IFNULL(back.back_number, 0) AS inventory,
m.material_code,
m.material_name,
m.material_specifications,
m.material_unit,
m.material_brand,
m.procurement_subject,
m.compatible_with,
m.material_warranty_period,
m.reference_price,
m.selling_price,
m.material_url,
v.vendor_name,
w.name as warehouseName
FROM erp_material_inventory_record r
LEFT JOIN erp_material m ON r.material_id = m.id
LEFT JOIN erp_warehouse w ON r.warehouse_id = w.id
LEFT JOIN erp_material_vendor v ON r.vendor_id = v.id
LEFT JOIN (
SELECT material_id, warehouse_id, vendor_id, SUM(number) AS put_number
FROM erp_material_inventory_record
WHERE type = '1'
GROUP BY material_id, warehouse_id, vendor_id
) put ON r.material_id = put.material_id AND r.warehouse_id = put.warehouse_id AND r.vendor_id = put.vendor_id
LEFT JOIN (
SELECT material_id, warehouse_id, vendor_id, SUM(number) AS ret_number
FROM erp_material_inventory_record
WHERE type = '2'
GROUP BY material_id, warehouse_id, vendor_id
) ret ON r.material_id = ret.material_id AND r.warehouse_id = ret.warehouse_id AND r.vendor_id = ret.vendor_id
LEFT JOIN (
SELECT material_id, warehouse_id, vendor_id, SUM(number) AS out_number
FROM erp_material_inventory_record
WHERE type = '3'
GROUP BY material_id, warehouse_id, vendor_id
) pic ON r.material_id = pic.material_id AND r.warehouse_id = pic.warehouse_id AND r.vendor_id = pic.vendor_id
LEFT JOIN (
SELECT material_id, warehouse_id, vendor_id, SUM(number) AS back_number
FROM erp_material_inventory_record
WHERE type = '4'
GROUP BY material_id, warehouse_id, vendor_id
) back ON r.material_id = back.material_id AND r.warehouse_id = back.warehouse_id AND r.vendor_id = back.vendor_id
) t
SELECT
t.*
FROM
(
SELECT
r.id AS recordId,
r.info_id,
r.material_id,
r.warehouse_id,
r.vendor_id,
r.price,
r.type,
r.create_time,
IFNULL( put.putaway_number, 0 ) - IFNULL( put.issued_number, 0 ) - IFNULL( put.returned_number, 0 ) AS inventory,m.material_code,
m.material_name,
m.material_specifications,
m.material_unit,
m.material_brand,
m.procurement_subject,
m.compatible_with,
m.material_warranty_period,
m.reference_price,
m.selling_price,
m.material_url,
v.vendor_name,
w.NAME AS warehouseName
FROM
erp_material_inventory_record r
LEFT JOIN erp_material m ON r.material_id = m.id
LEFT JOIN erp_warehouse w ON r.warehouse_id = w.id
LEFT JOIN erp_material_vendor v ON r.vendor_id = v.id
LEFT JOIN erp_material_putaway_info put ON r.info_id = put.id
) t
</sql>
<select id="customQueryPageInventoryList" resultType="com.maintain.business.domain.vo.ErpMaterialInventoryRecordVo">
<include refid="list"/>
......
......@@ -49,5 +49,70 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
${ew.getCustomSqlSegment}
</select>
<select id="getExportList" resultType="com.maintain.business.domain.vo.ErpMaterialPickingExportVo">
SELECT
ec.branch_office AS branchOffice,
empi.warehouse_name AS warehouseName,
su.nick_name AS receiveUserName,
emp.receive_time AS receiveTime,
empi.material_code AS materialCode,
empi.material_name AS materialName,
empi.material_specifications AS materialSpecifications,
empi.material_unit AS materialUnit,
empi.putaway_price AS putawayPrice,
empi.collect_number AS collectNumber,
empi.`money` AS money,
erf.repairer_dept_name as workshopName,
empi.vendor_name as vendorName,
empp.arrival_number as arrivalNumber
FROM
erp_material_picking_info empi
LEFT JOIN erp_material_picking emp ON empi.picking_id = emp.id
LEFT JOIN erp_car ec ON ec.id = emp.car_id
left join erp_repair_form erf ON erf.id = empi.repair_form_id
left join sys_user su on su.user_name = emp.receive_user_name
left join erp_material_inventory_record emir ON empi.record_id = emir.id
left join erp_material_putaway_info empii ON empii.id = emir.info_id
left join erp_material_putaway empp ON empii.putaway_id = empp.id
<where>
<if test="repairNumber != null">
and emp.repair_number like CONCAT('%',#{repairNumber},'%')
</if>
<if test="outNumber != null">
and emp.out_number like CONCAT('%',#{outNumber},'%')
</if>
<if test="plateNumber != null">
and emp.plate_number like CONCAT('%',#{plateNumber},'%')
</if>
<if test="settlementState != null">
and emp.settlement_state = #{settlementState}
</if>
<if test="type != null">
and emp.type = #{type}
</if>
<if test="plateNumber != null">
and emp.plate_number like CONCAT('%',#{plateNumber},'%')
</if>
<if test="ids != null and ids.size()>0">
AND emp.id in
<foreach item="id" collection="ids" separator="," open="(" close=")" index="">
#{id}
</foreach>
</if>
<if test="stateList != null and stateList.size()>0">
AND emp.state in
<foreach item="state" collection="stateList" separator="," open="(" close=")" index="">
#{state}
</foreach>
</if>
<if test="deptIds != null and deptIds.size()>0">
AND emp.create_dept_id in
<foreach item="deptId" collection="deptIds" separator="," open="(" close=")" index="">
#{deptId}
</foreach>
</if>
</where>
GROUP BY empi.id
ORDER BY emp.receive_time DESC
</select>
</mapper>
......@@ -170,8 +170,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
GROUP BY repair_form_id
) erfpd ON erf.id = erfpd.repair_form_id
LEFT JOIN (
SELECT repair_form_id, SUM(selling_price * collect_number) AS totalMaterialMoney
SELECT repair_form_id, SUM(money) AS totalMaterialMoney
FROM erp_material_picking_info
WHERE state != 3
GROUP BY repair_form_id
) empi ON erf.id = empi.repair_form_id
</sql>
......
......@@ -85,5 +85,9 @@ public class SysDept extends TreeEntity<SysDept> {
* 类型(1总公司 2分公司 3车队 4车间 5总公司管理部门 6分公司管理部门 7维修点)
*/
private String type;
/**
* 终端号
*/
private String terminalCode;
}
......@@ -10,8 +10,8 @@ import lombok.Getter;
@Getter
public enum SettlementState {
ONE(1, "待确认"),
TWO(2, "已确认");
ONE(1, "待支付"),
TWO(2, "已支付");
private final Integer code;
private final String info;
......
package com.maintain.common.pay;
/**
* PayResponse
*
* @author Liu Shuai
* @date 2025/10/28 14:30
*/
public class PayResponse {
/**
* errCode : 00
* errInfo : 10000成功响应码
* transactionTime : 140747
* transactionDate : 1028
* settlementDate : 1028
* transactionDateWithYear : 20251028
* settlementDateWithYear : 20251028
* retrievalRefNum : 01479200019N
* transactionAmount : 1
* actualTransactionAmount : 1
* amount : 1
* orderId : 20251028140747440012928716
* thirdPartyDiscountInstrution : 微信钱包支付0.01元
* thirdPartyDiscountInstruction : 微信钱包支付0.01元
* thirdPartyName : 微信钱包
* userId : oUpF8uMv_IaPg4f03FtZSQ7TiAiM
* thirdPartyBuyerId : oUpF8uMv_IaPg4f03FtZSQ7TiAiM
* thirdPartyOrderId : 4200002861202510289915715464
* thirdPartyPayInformation : 现金:1
* cardAttr : 91
* mchntName : 测试商户
* chnlType : WXPay
* promotionAmt : 0
* systemTraceNum : 002841
*/
private String errCode;
private String errInfo;
private String transactionTime;
private String transactionDate;
private String settlementDate;
private String transactionDateWithYear;
private String settlementDateWithYear;
private String retrievalRefNum;
private int transactionAmount;
private int actualTransactionAmount;
private int amount;
private String orderId;
private String thirdPartyDiscountInstrution;
private String thirdPartyDiscountInstruction;
private String thirdPartyName;
private String userId;
private String thirdPartyBuyerId;
private String thirdPartyOrderId;
private String thirdPartyPayInformation;
private String cardAttr;
private String mchntName;
private String chnlType;
private String promotionAmt;
private String systemTraceNum;
public String getErrCode() {
return errCode;
}
public void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrInfo() {
return errInfo;
}
public void setErrInfo(String errInfo) {
this.errInfo = errInfo;
}
public String getTransactionTime() {
return transactionTime;
}
public void setTransactionTime(String transactionTime) {
this.transactionTime = transactionTime;
}
public String getTransactionDate() {
return transactionDate;
}
public void setTransactionDate(String transactionDate) {
this.transactionDate = transactionDate;
}
public String getSettlementDate() {
return settlementDate;
}
public void setSettlementDate(String settlementDate) {
this.settlementDate = settlementDate;
}
public String getTransactionDateWithYear() {
return transactionDateWithYear;
}
public void setTransactionDateWithYear(String transactionDateWithYear) {
this.transactionDateWithYear = transactionDateWithYear;
}
public String getSettlementDateWithYear() {
return settlementDateWithYear;
}
public void setSettlementDateWithYear(String settlementDateWithYear) {
this.settlementDateWithYear = settlementDateWithYear;
}
public String getRetrievalRefNum() {
return retrievalRefNum;
}
public void setRetrievalRefNum(String retrievalRefNum) {
this.retrievalRefNum = retrievalRefNum;
}
public int getTransactionAmount() {
return transactionAmount;
}
public void setTransactionAmount(int transactionAmount) {
this.transactionAmount = transactionAmount;
}
public int getActualTransactionAmount() {
return actualTransactionAmount;
}
public void setActualTransactionAmount(int actualTransactionAmount) {
this.actualTransactionAmount = actualTransactionAmount;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getThirdPartyDiscountInstrution() {
return thirdPartyDiscountInstrution;
}
public void setThirdPartyDiscountInstrution(String thirdPartyDiscountInstrution) {
this.thirdPartyDiscountInstrution = thirdPartyDiscountInstrution;
}
public String getThirdPartyDiscountInstruction() {
return thirdPartyDiscountInstruction;
}
public void setThirdPartyDiscountInstruction(String thirdPartyDiscountInstruction) {
this.thirdPartyDiscountInstruction = thirdPartyDiscountInstruction;
}
public String getThirdPartyName() {
return thirdPartyName;
}
public void setThirdPartyName(String thirdPartyName) {
this.thirdPartyName = thirdPartyName;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getThirdPartyBuyerId() {
return thirdPartyBuyerId;
}
public void setThirdPartyBuyerId(String thirdPartyBuyerId) {
this.thirdPartyBuyerId = thirdPartyBuyerId;
}
public String getThirdPartyOrderId() {
return thirdPartyOrderId;
}
public void setThirdPartyOrderId(String thirdPartyOrderId) {
this.thirdPartyOrderId = thirdPartyOrderId;
}
public String getThirdPartyPayInformation() {
return thirdPartyPayInformation;
}
public void setThirdPartyPayInformation(String thirdPartyPayInformation) {
this.thirdPartyPayInformation = thirdPartyPayInformation;
}
public String getCardAttr() {
return cardAttr;
}
public void setCardAttr(String cardAttr) {
this.cardAttr = cardAttr;
}
public String getMchntName() {
return mchntName;
}
public void setMchntName(String mchntName) {
this.mchntName = mchntName;
}
public String getChnlType() {
return chnlType;
}
public void setChnlType(String chnlType) {
this.chnlType = chnlType;
}
public String getPromotionAmt() {
return promotionAmt;
}
public void setPromotionAmt(String promotionAmt) {
this.promotionAmt = promotionAmt;
}
public String getSystemTraceNum() {
return systemTraceNum;
}
public void setSystemTraceNum(String systemTraceNum) {
this.systemTraceNum = systemTraceNum;
}
}
package com.maintain.common.pay;
import lombok.Data;
/**
* PayResult
*
* @author Liu Shuai
* @date 2025/11/10 14:44
*/
@Data
public class PayResult {
// 请求参数
private String requestParams;
// 认证报文
private String authorization;
// 响应结果
private String response;
// 解析后的响应对象
private PayResponse payResponse;
}
package com.maintain.common.pay;
import cn.hutool.json.JSONUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
/**
* 银联支付API
*/
@Component
public class YinLianPayApi {
@Value("${pay.appid}")
private String appid;
@Value("${pay.appkey}")
private String appkey;
@Value("${pay.url}")
private String url;
@Value("${pay.merchantCode}")
private String merchantCode;
@Value("${pay.deviceType}")
private String deviceType;
@Value("${pay.payMode}")
private String payMode;
public static void main(String[] args) throws Exception {
// 1. 组建请求报文
PayBody reqBody = new PayBody();
reqBody.merchantCode = "123456789111115";
reqBody.terminalCode = "gxrb0001";
reqBody.transactionAmount = 1;
reqBody.transactionCurrencyCode = "156";
reqBody.merchantOrderId = "121423534643";
reqBody.merchantRemark = "remark";
reqBody.payMode = "CODE_SCAN";
reqBody.payCode = "134183932097088249";
reqBody.deviceType = "11";
String requestBody = reqBody.toString();
System.out.println("请求参数:\n" + requestBody);
// 2. 获取认证报文
String timestamp = getCurrentTimestamp14();
//2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功
String authorization = getAuthorization("10037e6f72b586db0172b6ea24ec0000","6f7a00170935445fbe25e67a5ce1be48",timestamp,"nonce",reqBody.toString());
System.out.println("认证报文:\n"+authorization);
//3. 发送http请求,并解析返回信息
String response = request("https://test-api-open.chinaums.com/v6/poslink/transaction/pay",authorization,reqBody.toString());
System.out.println("响应参数:\n"+response);
PayResponse payResponse = JSONUtil.toBean(response, PayResponse.class);
System.out.println(payResponse);
}
/**
* 发起支付
* @param merchantOrderId 订单号
* @param transactionAmount 交易金额
* @param payCode 支付码
* @param terminalCode 终端号
* @return 支付结果
*/
public PayResult pay(String merchantOrderId,int transactionAmount, String payCode, String terminalCode) {
PayResult payResult = new PayResult();
// 组建请求报文
PayBody reqBody = new PayBody();
reqBody.merchantCode = merchantCode;
reqBody.terminalCode = terminalCode;
// 交易金额
reqBody.transactionAmount = transactionAmount;
// 交易币种
reqBody.transactionCurrencyCode = "156";
// 订单号
reqBody.merchantOrderId = merchantOrderId;
reqBody.merchantRemark = "remark";
// 支付方式(E_CASH – 电子现金、SOUNDWAVE – 声波、NFC – NFC、CODE_SCAN – 扫码、MANUAL – 手输、FACE_SCAN – 扫脸)
reqBody.payMode = payMode;
// 支付码
reqBody.payCode = payCode;
// 设备类型固定11
reqBody.deviceType = deviceType;
String requestBody = reqBody.toString();
payResult.setRequestParams(requestBody);
System.out.println("请求参数:\n" + requestBody);
// 获取认证报文,timestamp为当前日期
String timestamp = getCurrentTimestamp14();
String authorization;
try {
authorization = getAuthorization(appid,appkey,timestamp,"nonce",reqBody.toString());
payResult.setAuthorization(authorization);
System.out.println("认证报文:\n"+authorization);
}catch (Exception e){
throw new RuntimeException("获取认证报文失败,请检查!");
}
// 发送http请求,并解析返回信息
String response = request(url,authorization,reqBody.toString());
payResult.setResponse(response);
System.out.println("响应参数:\n"+response);
PayResponse payResponse = JSONUtil.toBean(response, PayResponse.class);
payResult.setPayResponse(payResponse);
return payResult;
}
/**
* 获取14位时间戳 (yyyyMMddHHmmss)
*/
static String getCurrentTimestamp14() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置为北京时区
return sdf.format(new Date());
}
/**
* 发送http请求 - 增强错误处理
*/
static String request(String url, String authorization, String reqBody) {
StringBuilder response = new StringBuilder();
PrintWriter out = null;
BufferedReader in = null;
HttpURLConnection httpUrlConnection = null;
try {
URL realUrl = new URL(url);
httpUrlConnection = (HttpURLConnection) realUrl.openConnection();
// 设置请求参数
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
httpUrlConnection.setRequestProperty("authorization", authorization);
httpUrlConnection.setRequestProperty("User-Agent", "Mozilla/5.0");
httpUrlConnection.setConnectTimeout(30000);
httpUrlConnection.setReadTimeout(30000);
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
// 发送请求体
out = new PrintWriter(new OutputStreamWriter(httpUrlConnection.getOutputStream(), "UTF-8"));
out.write(reqBody);
out.flush();
// 获取响应状态
int responseCode = httpUrlConnection.getResponseCode();
System.out.println("HTTP响应码: " + responseCode);
// 读取响应
if (responseCode == HttpURLConnection.HTTP_OK) {
in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream(), "UTF-8"));
} else {
// 读取错误流 - 这是关键!
in = new BufferedReader(new InputStreamReader(httpUrlConnection.getErrorStream(), "UTF-8"));
}
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
// 记录错误详情
if (responseCode != HttpURLConnection.HTTP_OK) {
System.err.println("HTTP错误: " + responseCode);
System.err.println("错误响应内容: " + response.toString());
}
} catch (Exception e) {
System.err.println("请求异常: " + e.getMessage());
e.printStackTrace();
return "HTTP请求异常: " + e.getMessage();
} finally {
try {
if (out != null) out.close();
if (in != null) in.close();
if (httpUrlConnection != null) httpUrlConnection.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return response.toString();
}
/**
* 获取签名头
* @param appid
* @param appkey
* @param timestamp 格式:"yyyyMMddHHmmss"
* @param nonce 随机字符串,
* @param body 请求体
* @return authorization 认证报文
* @throws Exception
*/
static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception {
System.out.println("appid:\n"+appid);
System.out.println("appkey:\n"+appkey);
byte[] data = body.getBytes("utf-8");
InputStream is = new ByteArrayInputStream(data);
String testSH = DigestUtils.sha256Hex(is);
String s1 = appid+timestamp+nonce+testSH;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256"));
byte[] bytes = s1.getBytes("utf-8");
byte[] localSignature = mac.doFinal(bytes);
String localSignatureStr = Base64.encodeBase64String(localSignature);
return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"";
}
static class PayBody {
// 商户号
String merchantCode;
// 终端号
String terminalCode;
// 交易金额
int transactionAmount;
// 交易币种
String transactionCurrencyCode;
// 商户订单号
String merchantOrderId;
// 商户备注
String merchantRemark;
// 支付方式
String payMode;
// 支付码
String payCode;
// 设备类型
String deviceType;
// 终端硬件序列号
String serialNum;
// 加密随机因子
String encryptRandNum;
// 硬件序列号密文数据
String secretText;
// 经度
String longitude;
// 纬度
String latitude;
// 商品信息
List<GoodsItem> goods;
// 商户冗余信息
String srcReserved;
// 门店号
String storeId;
// 是否限制信用卡
String limitCreditCard;
// 操作员编号
String operatorId;
// 业务标识
String bizIdentifier;
// 商品标识
String goodsTag;
String toJson() {
StringBuilder sb = new StringBuilder();
sb.append("{");
appendField(sb, "merchantCode", merchantCode);
appendField(sb, "terminalCode", terminalCode);
appendField(sb, "transactionAmount", transactionAmount, transactionAmount != 0);
appendField(sb, "transactionCurrencyCode", transactionCurrencyCode);
appendField(sb, "merchantOrderId", merchantOrderId);
appendField(sb, "merchantRemark", merchantRemark);
appendField(sb, "payMode", payMode);
appendField(sb, "payCode", payCode);
appendField(sb, "deviceType", deviceType);
appendField(sb, "serialNum", serialNum);
appendField(sb, "encryptRandNum", encryptRandNum);
appendField(sb, "secretText", secretText);
appendField(sb, "longitude", longitude);
appendField(sb, "latitude", latitude);
// 处理商品列表
if (goods != null && !goods.isEmpty()) {
if (sb.charAt(sb.length() - 1) != '{') {
sb.append(",");
}
sb.append("\"goods\":[");
for (int i = 0; i < goods.size(); i++) {
if (i > 0) {
sb.append(",");
}
sb.append(goods.get(i).toJson());
}
sb.append("]");
}
appendField(sb, "srcReserved", srcReserved);
appendField(sb, "storeId", storeId);
appendField(sb, "limitCreditCard", limitCreditCard);
appendField(sb, "operatorId", operatorId);
appendField(sb, "bizIdentifier", bizIdentifier);
appendField(sb, "goodsTag", goodsTag);
// 移除末尾多余的逗号
if (sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("}");
return sb.toString();
}
// 辅助方法:添加字符串字段
private void appendField(StringBuilder sb, String fieldName, String value) {
appendField(sb, fieldName, value, value != null);
}
// 辅助方法:添加整数字段
private void appendField(StringBuilder sb, String fieldName, int value, boolean condition) {
if (condition) {
if (sb.charAt(sb.length() - 1) != '{') {
sb.append(",");
}
sb.append("\"").append(fieldName).append("\":").append(value);
}
}
// 辅助方法:添加字符串字段(带条件)
private void appendField(StringBuilder sb, String fieldName, String value, boolean condition) {
if (condition) {
if (sb.charAt(sb.length() - 1) != '{') {
sb.append(",");
}
sb.append("\"").append(fieldName).append("\":\"").append(escapeJson(value)).append("\"");
}
}
// 转义JSON特殊字符
private String escapeJson(String value) {
if (value == null) return "";
return value.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
public String toString() {
return this.toJson();
}
static class GoodsItem {
// 商品ID
String goodsId;
// 商品名称
String goodsName;
// 商品数量
String quantity;
// 商品单价(分)
String price;
// 商品分类
String goodsCategory;
// 商品说明
String body;
// 商品折扣
String discount;
String toJson() {
StringBuilder sb = new StringBuilder();
sb.append("{");
appendGoodsField(sb, "goodsId", goodsId);
appendGoodsField(sb, "goodsName", goodsName);
appendGoodsField(sb, "quantity", quantity);
appendGoodsField(sb, "price", price);
appendGoodsField(sb, "goodsCategory", goodsCategory);
appendGoodsField(sb, "body", body);
appendGoodsField(sb, "discount", discount);
// 移除末尾多余的逗号
if (sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("}");
return sb.toString();
}
private void appendGoodsField(StringBuilder sb, String fieldName, String value) {
if (value != null) {
if (sb.charAt(sb.length() - 1) != '{') {
sb.append(",");
}
sb.append("\"").append(fieldName).append("\":\"").append(escapeJson(value)).append("\"");
}
}
// 转义JSON特殊字符
private String escapeJson(String value) {
if (value == null) return "";
return value.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
public String toString() {
return this.toJson();
}
}
}
}
package com.maintain.common.utils.poi;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
/**
* 注解工具类
*/
public class AnnotationUtils {
/**
* 变更注解的属性值再处理业务,处理完业务之后恢复类的属性
*
* @param clazz 注解所在的实体类
* @param tClass 注解类
* @param attrName 要修改的注解属性名
* @param attrTypeEnum 要修改的注解属性的类型
* @param valueMap 要设置的属性值
*/
public static <A extends Annotation> void changeAnnotationValueToDealProcess(
Class<?> clazz,
Class<A> tClass,
String attrName,
AttrTypeEnum attrTypeEnum,
Map<String, String> valueMap,
DealProcess dealProcess) {
try {
Map<String, Object> fieldAnnotationValueMap = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
A annotation = field.getAnnotation(tClass);
if (annotation == null) continue;
Object value = setAnnotationValue(annotation, attrName, attrTypeEnum, valueMap);
String fieldName = field.getName();
fieldAnnotationValueMap.put(fieldName, value);
}
// 处理业务逻辑
dealProcess.deal();
// 恢复
for (Field field : fields) {
A annotation = field.getAnnotation(tClass);
String fieldName = field.getName();
if (annotation == null) continue;
Object value = fieldAnnotationValueMap.get(fieldName);
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
Field memberValuesField = handler.getClass().getDeclaredField("memberValues");
memberValuesField.setAccessible(true);
@SuppressWarnings("all")
Map<String, Object> memberValues = (Map) memberValuesField.get(handler);
memberValues.put(attrName, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置注解中的字段值
*
* @param annotation 要修改的注解实例
* @param attrName 要修改的注解属性名
* @param attrTypeEnum 要修改的注解属性的类型
* @param valueMap 替换属性集的map
*/
@SuppressWarnings("all")
private static Object setAnnotationValue(Annotation annotation, String attrName,
AttrTypeEnum attrTypeEnum, Map<String, String> valueMap) throws NoSuchFieldException, IllegalAccessException {
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
Field field = handler.getClass().getDeclaredField("memberValues");
field.setAccessible(true);
Map memberValues = (Map) field.get(handler);
Object value = memberValues.get(attrName);
switch (attrTypeEnum) {
case STRING: {
String oldValue = (String) value;
String newValue = valueMap.get(oldValue);
if (StringUtils.isNotBlank(newValue)) {
memberValues.put(attrName, newValue);
}
}
break;
case STRING_ARR: {
String[] oldValue = (String[]) value;
String[] newValue = new String[oldValue.length];
for (int i = 0; i < oldValue.length; i++) {
String replace = valueMap.get(oldValue[i]);
newValue[i] = replace != null ? replace : oldValue[i];
}
memberValues.put(attrName, newValue);
}
break;
}
return value;
}
public enum AttrTypeEnum {
STRING,
STRING_ARR
}
public interface DealProcess {
void deal() throws Exception;
}
}
package com.maintain.common.utils.poi;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
import java.util.stream.Collectors;
/**
* 自定义合并单元格处理器
* 每次合并需要sheet页名称、指定开始行号、开始列号、结束行号、结束列号
* 支持批量合并单元格
*
* @author weibaoting
*/
public class CustomMergeCellHandler implements SheetWriteHandler {
/**
* 合并单元格信息
*/
private List<MergeCellModel> mergeCellList;
/**
* sheet页名称列表
*/
private List<String> sheetNameList;
public CustomMergeCellHandler(List<MergeCellModel> mergeCellList) {
if (CollUtil.isEmpty(mergeCellList)) {
return;
}
this.mergeCellList = mergeCellList.stream().filter(x ->
StrUtil.isNotBlank(x.getSheetName()) && x.getStartRowIndex() >= 0 && x.getEndRowIndex() >= 0
&& x.getStartColumnIndex() >= 0 && x.getEndColumnIndex() >= 0).collect(Collectors.toList());
List<String> sheetNameList = this.mergeCellList.stream().map(x -> x.getSheetName()).distinct().collect(Collectors.toList());
if (CollUtil.isEmpty(sheetNameList)) {
return;
}
this.sheetNameList = sheetNameList;
}
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
/**
* sheet页创建之后调用
*
* @param writeWorkbookHolder
* @param writeSheetHolder
*/
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Sheet sheet = writeSheetHolder.getSheet();
//不需要合并单元格信息,或者当前sheet页不需要合并单元格信息
if (CollUtil.isEmpty(mergeCellList) || sheetNameList.contains(sheet.getSheetName()) == false) {
return;
}
List<MergeCellModel> sheetMergeCellList = mergeCellList.stream().filter(x ->
StrUtil.equals(x.getSheetName(), sheet.getSheetName())).collect(Collectors.toList());
for (MergeCellModel mergeCellModel : sheetMergeCellList) {
//开始行号
int startRowIndex = mergeCellModel.getStartRowIndex();
//结束行号
int endRowIndex = mergeCellModel.getEndRowIndex();
//开始列号
int startColumnIndex = mergeCellModel.getStartColumnIndex();
//结束列号
int endColumnIndex = mergeCellModel.getEndColumnIndex();
//行号和列号非法(<0)
if (startColumnIndex < 0 || endColumnIndex < 0 || startRowIndex < 0 || endRowIndex < 0) {
continue;
}
//合并单元格区域只有一个单元格时,不合并
if (endRowIndex == startRowIndex && endColumnIndex == startColumnIndex) {
continue;
}
//开始行号大于结束行号,或者开始列号大于结束列号
if (startColumnIndex > endColumnIndex || startRowIndex > endRowIndex) {
continue;
}
//添加合并单元格区域
CellRangeAddress cellRangeAddress = new CellRangeAddress(startRowIndex, endRowIndex, startColumnIndex, endColumnIndex);
sheet.addMergedRegionUnsafe(cellRangeAddress);
}
//删除合并单元格信息
mergeCellList.removeAll(sheetMergeCellList);
sheetNameList = mergeCellList.stream().map(x -> x.getSheetName()).distinct().collect(Collectors.toList());
}
}
......@@ -5,10 +5,15 @@ import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.maintain.common.convert.ExcelBigNumberConvert;
import com.maintain.common.excel.*;
......@@ -16,6 +21,9 @@ import com.maintain.common.utils.StringUtils;
import com.maintain.common.utils.file.FileUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.springframework.http.HttpHeaders;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
......@@ -23,6 +31,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
......@@ -32,6 +43,7 @@ import java.util.Map;
*
* @author Lion Li
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExcelUtil {
......@@ -377,4 +389,54 @@ public class ExcelUtil {
return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
}
/**
* 载Excel格式的数据-带自定义标题
*
* @param response
* @param fileName
* @param sheetPOList
* @param <T>
*/
public static <T> void exportSheetSetTitle(HttpServletResponse response, String fileName, List<SheetPO> sheetPOList) {
//导出
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
try {
// 这里URLEncoder.encode可以防止中文乱码
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
//新建ExcelWriter
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
for (SheetPO sheetPO : sheetPOList) {
AnnotationUtils.changeAnnotationValueToDealProcess(
sheetPO.getClazz(), ExcelProperty.class, "value", AnnotationUtils.AttrTypeEnum.STRING_ARR, sheetPO.getTitleMap(), new AnnotationUtils.DealProcess() {
@Override
public void deal() {
ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetPO.getSheetNo(), sheetPO.getSheetName())
.head(sheetPO.getClazz())
.registerWriteHandler(new CustomMergeCellHandler(sheetPO.getMergeCellList()));
if (Boolean.TRUE.equals(sheetPO.getWhiteFirstHeadRow())) {
sheetBuilder.registerWriteHandler(new HeadTitleRowWhiteStyleHandler());
}
if (sheetPO.getCenterMergedAnchorExcelRowIndex() != null) {
sheetBuilder.registerWriteHandler(
new MergedAnchorCellCenterStyleHandler(sheetPO.getCenterMergedAnchorExcelRowIndex(), 0));
}
WriteSheet mainSheet = sheetBuilder.build();
excelWriter.write(sheetPO.getData(), mainSheet);
}
}
);
}
excelWriter.finish();
log.info("数据导出完成");
} catch (Exception e) {
// 重置response
log.error("文件下载失败" + e.getMessage());
throw new RuntimeException("下载文件失败", e);
}
}
}
package com.maintain.common.utils.poi;
import com.alibaba.excel.constant.OrderConstant;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
/**
* 多行表头时,仅将第一行(大标题行,relativeRowIndex=0)设为白底,其余表头行保持实体类上的 {@code @HeadStyle}。
*/
public class HeadTitleRowWhiteStyleHandler implements CellWriteHandler {
private CellStyle whiteTitleRowStyle;
/**
* 在注解 {@code @HeadStyle} 等样式写入之后再执行(EasyExcel:order 越小越早)。
*/
@Override
public int order() {
return OrderConstant.FILL_STYLE + 10000;
}
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
if (!Boolean.TRUE.equals(context.getHead())) {
return;
}
Integer relativeRowIndex = context.getRelativeRowIndex();
if (relativeRowIndex == null || relativeRowIndex != 0) {
return;
}
Cell cell = context.getCell();
if (cell == null) {
return;
}
Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();
if (whiteTitleRowStyle == null) {
whiteTitleRowStyle = workbook.createCellStyle();
whiteTitleRowStyle.cloneStyleFrom(cell.getCellStyle());
whiteTitleRowStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
whiteTitleRowStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
}
cell.setCellStyle(whiteTitleRowStyle);
}
}
package com.maintain.common.utils.poi;
import lombok.Getter;
/**
* @Author weibaoting
* @Date 2023/2/2 0002 15:53
* @Description
*/
@Getter
public class MergeCellModel {
/**
* sheet名称
*/
private String sheetName;
/**
* 开始行号
*/
private int startRowIndex;
/**
* 开始列号
*/
private int startColumnIndex;
/**
* 结束行号
*/
private int endRowIndex;
/**
* 结束列号
*/
private int endColumnIndex;
private void setSheetName(String sheetName) {
this.sheetName = sheetName;
}
private void setStartRowIndex(int startRowIndex) {
this.startRowIndex = startRowIndex;
}
private void setStartColumnIndex(int startColumnIndex) {
this.startColumnIndex = startColumnIndex;
}
private void setEndRowIndex(int endRowIndex) {
this.endRowIndex = endRowIndex;
}
private void setEndColumnIndex(int endColumnIndex) {
this.endColumnIndex = endColumnIndex;
}
public MergeCellModel() {
}
/**
* 生成合并列单元格信息
*
* @param sheetName sheet页名称
* @param rowIndex 行号
* @param startColumnIndex 开始列号
* @param endColumnIndex 结束列号
* @return
*/
public static MergeCellModel createMergeColumnCellModel(String sheetName, int rowIndex, int startColumnIndex
, int endColumnIndex) {
return createMergeCellModel(sheetName, rowIndex, rowIndex, startColumnIndex, endColumnIndex);
}
/**
* 生成合并单元格信息
*
* @param sheetName sheet页名称
* @param startRowIndex 开始行号
* @param endRowIndex 结束行号
* @param columnIndex 列号
* @return
*/
public static MergeCellModel createMergeRowCellModel(String sheetName, int startRowIndex, int endRowIndex, int columnIndex) {
return createMergeCellModel(sheetName, startRowIndex, endRowIndex, columnIndex, columnIndex);
}
/**
* 生成合并单元格信息
*
* @param sheetName sheet页名称
* @param startRowIndex 开始行号
* @param endRowIndex 结束行号
* @param startColumnIndex 开始列号
* @param endColumnIndex 结束列号
* @return
*/
public static MergeCellModel createMergeCellModel(String sheetName, int startRowIndex, int endRowIndex, int startColumnIndex
, int endColumnIndex) {
MergeCellModel mergeCellModel = new MergeCellModel();
//sheet页名称
mergeCellModel.setSheetName(sheetName);
//开始行号
mergeCellModel.setStartRowIndex(startRowIndex);
//结束行号
mergeCellModel.setEndRowIndex(endRowIndex);
//开始列号
mergeCellModel.setStartColumnIndex(startColumnIndex);
//结束列号
mergeCellModel.setEndColumnIndex(endColumnIndex);
return mergeCellModel;
}
}
package com.maintain.common.utils.poi;
import com.alibaba.excel.constant.OrderConstant;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
/**
* 将指定数据行、指定列(一般为合并区域左上角)的单元格设为水平、垂直居中,用于合并后「合计」等文案居中显示。
*/
public class MergedAnchorCellCenterStyleHandler implements CellWriteHandler {
private final int excelRowIndex;
private final int columnIndex;
public MergedAnchorCellCenterStyleHandler(int excelRowIndex, int columnIndex) {
this.excelRowIndex = excelRowIndex;
this.columnIndex = columnIndex;
}
@Override
public int order() {
return OrderConstant.FILL_STYLE + 15000;
}
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
if (Boolean.TRUE.equals(context.getHead())) {
return;
}
Cell cell = context.getCell();
if (cell == null) {
return;
}
if (cell.getRowIndex() != excelRowIndex || cell.getColumnIndex() != columnIndex) {
return;
}
Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();
CellStyle style = workbook.createCellStyle();
style.cloneStyleFrom(cell.getCellStyle());
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
cell.setCellStyle(style);
}
}
package com.maintain.common.utils.poi;
import lombok.Data;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author weibaoting
* @Date 2023/2/2 0002 17:00
* @Description
*/
@Data
public class SheetPO<T> {
/**
* sheetNo
*/
private Integer sheetNo;
/**
* sheet名称
*/
private String sheetName;
/**
* 标题替换
*/
private Map<String, String> titleMap = new HashMap<>();
/**
* 数据
*/
private List<T> data;
/**
* 表头
*/
private Class<T> clazz;
/**
* 需要合并的数据
*/
private List<MergeCellModel> mergeCellList;
/**
* 多行表头时是否将第一行(大标题行)设为白底;第二行仍用实体类上的表头样式。默认 false。
*/
private Boolean whiteFirstHeadRow;
/**
* 若设置:对该 Excel 行号(0-based)、第 0 列锚点单元格水平垂直居中(用于合并单元格内文字居中,如合计行)。
*/
private Integer centerMergedAnchorExcelRowIndex;
}
......@@ -44,6 +44,16 @@ export function updateRepairFormProjectDispatch(data) {
})
}
// 批量修改报修单-报修项目-派工
export function updateRepairFormProjectDispatchBatch(data) {
return request({
url: '/business/repairFormProjectDispatch/batch',
method: 'put',
data: data
})
}
// 删除报修单-报修项目-派工
export function delRepairFormProjectDispatch(id) {
return request({
......
......@@ -51,3 +51,13 @@ export function receiptSettlementMaintain(data) {
data: data
})
}
// 结算维修单回执
export function paySettlementMaintain(data) {
return request({
url: '/business/settlementMaintain/pay',
method: 'put',
data: data,
timeout: 30000
})
}
......@@ -213,6 +213,24 @@
<el-form-item label="车型ID" prop="carTypeId">
<el-input v-model="form.carTypeId" placeholder="请输入车型ID" />
</el-form-item> -->
<div class="app-title">车队信息</div>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="分公司" prop="branchOffice">
<el-input v-model="form.branchOffice" placeholder="请输入分公司" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="车队" prop="motorcade">
<el-input v-model="form.motorcade" placeholder="请输入车队" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="线路" prop="line">
<el-input v-model="form.line" placeholder="请输入线路" />
</el-form-item>
</el-col>
</el-row>
<div class="app-title">关联车型信息</div>
<el-row :gutter="20">
<el-col :span="8">
......@@ -507,7 +525,7 @@ export default {
handleUpdate(row) {
getCar(row.id).then(res =>{
this.form = res.data
this.form.clientType = row.clientType
this.form.clientType = row.clientType+''
this.open = true;
this.title = "修改车辆信息";
this.getCode()
......
......@@ -38,6 +38,17 @@
v-hasPermi="['business:maintainProject:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['business:maintainProject:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
......@@ -62,7 +73,7 @@
</el-row>
<el-table v-loading="loading" :data="maintainProjectList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" />-->
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" />
<el-table-column label="维修项目类别" align="center" prop="typeName" />
<el-table-column label="维修项目编号" align="center" prop="projectCode" />
......@@ -471,7 +482,7 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除维修项目编号为"' + row.projectCode + '"的数据项?').then(() => {
this.$modal.confirm('是否确认删除维修项目,删除后无法恢复!').then(() => {
this.loading = true;
return delMaintainProject(ids);
}).then(() => {
......
......@@ -34,6 +34,17 @@
v-hasPermi="['business:malfunctionProject:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['business:malfunctionProject:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
......@@ -76,7 +87,7 @@
</el-row>
<el-table v-loading="loading" :data="malfunctionProjectList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" />-->
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index"/>
<el-table-column label="故障类型名称" align="center" prop="typeName" />
<el-table-column label="故障项目编号" align="center" prop="malfunctionCode" />
......@@ -431,7 +442,7 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除故障项目编号为"' + row.malfunctionCode + '"的数据项?').then(() => {
this.$modal.confirm('是否确认删除维修项目,删除后无法恢复!').then(() => {
this.loading = true;
return delMalfunctionProject(ids);
}).then(() => {
......
......@@ -138,27 +138,28 @@
<el-table-column label="物资编码" align="center" fixed="left" prop="materialCode" />
<el-table-column label="物资名称" align="center" fixed="left" prop="materialName" />
<el-table-column label="物资规格" align="center" fixed="left" prop="materialSpecifications" />
<el-table-column label="供应商" align="center" fixed="left" prop="vendorName" show-overflow-tooltip />
<el-table-column label="物资品牌" align="center" fixed="left" prop="materialBrand" />
<el-table-column label="物资单位" align="center" fixed="left" prop="materialUnit">
<el-table-column label="生产厂家" align="center" fixed="left" prop="manufacturer" />
<el-table-column label="采购标的" align="center" prop="procurementSubject" />
<el-table-column label="物资单位" align="center" prop="materialUnit" width="50">
<template slot-scope="scope">
<dict-tag :options="dict.type.material_unit" :value="scope.row.materialUnit" />
</template>
</el-table-column>
<!-- <el-table-column label="所在仓库" align="center" prop="warehouseName" />-->
<!-- <el-table-column label="分类名称" align="center" prop="materialTypeName" />-->
<el-table-column label="供应商" align="center" prop="vendorName" show-overflow-tooltip />
<el-table-column label="采购标的" align="center" prop="procurementSubject" />
<el-table-column label="适用车型" align="center" prop="compatibleWith" />
<el-table-column label="适用车型" align="center" prop="compatibleWith" show-overflow-tooltip/>
<el-table-column label="物资图片" align="center" prop="materialUrl">
<template slot-scope="scope">
<image-preview :src="scope.row.materialUrl" style="width: 50px; height: 50px" />
</template>
</el-table-column>
<el-table-column label="质保期(月)" align="center" prop="materialWarrantyPeriod" />
<el-table-column label="参考价" align="center" prop="referencePrice" />
<el-table-column label="销售价" align="center" prop="sellingPrice" />
<el-table-column label="质保期(月)" align="center" prop="materialWarrantyPeriod" width="60" />
<el-table-column label="参考价" align="center" prop="referencePrice" width="80" />
<el-table-column label="销售价" align="center" prop="sellingPrice" width="80" />
<!-- <el-table-column label="库存" align="center" prop="inventory" />-->
<el-table-column label="是否启用" align="center" prop="isEnable">
<el-table-column label="是否启用" align="center" prop="isEnable" width="50">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_is_enable" :value="scope.row.isEnable"/>
</template>
......@@ -168,7 +169,7 @@
<!-- <dict-tag :options="dict.type.sys_is_enable" :value="String(scope.row.isCheck)"/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="是否通用" align="center" prop="isUniversal">
<el-table-column label="是否通用" align="center" prop="isUniversal" width="50">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_is_enable" :value="scope.row.isUniversal"/>
</template>
......@@ -202,7 +203,7 @@
/>
<!-- 添加或修改物资对话框 -->
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
<el-dialog :title="title" :visible.sync="open" width="60%" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="8">
......@@ -236,14 +237,14 @@
<!-- </el-col>-->
<el-col :span="8">
<el-form-item label="供应商" prop="vendorId">
<el-select v-model="form.vendorId" placeHolder="请选择供应商">
<el-select v-model="form.vendorId" placeHolder="请选择供应商" style="width: 100%" >
<el-option v-for="item in materialVendorList" :key="item.id" :value="item.id" :label="item.vendorName" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="物资单位" prop="materialUnit">
<el-select v-model="form.materialUnit" placeHolder="请选择物资单位">
<el-select v-model="form.materialUnit" placeHolder="请选择物资单位" style="width: 100%" >
<el-option v-for="dict in dict.type.material_unit" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
......@@ -281,10 +282,8 @@
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="8">
<el-form-item label="是否启用" prop="isEnable">
<el-select v-model="form.isEnable" style="width: 100%" placeholder="请选择是否启用">
<el-option v-for="dict in dict.type.sys_is_enable" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
<el-form-item label="生产厂家" prop="manufacturer">
<el-input v-model="form.manufacturer" placeholder="请输入生产厂家" />
</el-form-item>
</el-col>
<el-col :span="8">
......@@ -304,6 +303,13 @@
<!-- <el-input-number v-model="form.inventory" :min="0" style="width: 100%" :disabled="form.id != null" placeholder="请输入库存数量" />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="8">
<el-form-item label="是否启用" prop="isEnable">
<el-select v-model="form.isEnable" style="width: 100%" placeholder="请选择是否启用">
<el-option v-for="dict in dict.type.sys_is_enable" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否通用" prop="isUniversal">
<el-select v-model="form.isUniversal" style="width: 100%" placeholder="请选择是否通用">
......@@ -414,8 +420,7 @@ export default {
materialSpecifications: undefined,
materialUnit: undefined,
materialWarrantyPeriod: undefined,
referencePrice: undefined,
sellingPrice: undefined,
manufacturer: undefined,
inventory: undefined,
isEnable: undefined,
isUniversal: undefined,
......@@ -545,6 +550,7 @@ export default {
materialSpecifications: undefined,
materialUnit: undefined,
materialBrand: undefined,
manufacturer: undefined,
procurementSubject: undefined,
compatibleWith: undefined,
materialUrl: undefined,
......
......@@ -86,7 +86,7 @@
<el-table-column label="库存" align="center" prop="inventory" />
<el-table-column label="领料数量" align="center" prop="collectNumber" width="120px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.collectNumber" @change="collectNumberChange" controls-position="right" size="mini" :min="1" :precision="0" style="width: 100%" placeholder="数量"/>
<el-input-number v-model="scope.row.collectNumber" @change="collectNumberChange" controls-position="right" size="mini" :min="0.00" :precision="2" :max="parseFloat(scope.row.inventory)" style="width: 100%" placeholder="数量"/>
</template>
</el-table-column>
<!-- <el-table-column label="销售单价" align="center" prop="price" width="120px">-->
......@@ -96,7 +96,7 @@
<!-- </el-table-column>-->
<el-table-column label="领料金额" align="center" prop="money" width="120px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.money" disabled controls-position="right" size="mini" :min="0" style="width: 100%" placeholder="金额"/>
<el-input-number v-model="scope.row.money" disabled controls-position="right" size="mini" :precision="2" style="width: 100%" placeholder="金额"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
......@@ -260,7 +260,7 @@ export default {
};
},
created() {
this.form = {...this.$route.query}
this.form = {...this.$route.query, outMoney: undefined}
this.getWarehouseList(this.form.repairerDeptId)
this.getVendorList()
},
......@@ -289,7 +289,9 @@ export default {
},
/** 供应商改变 */
vendorIdChange(vendorId) {
this.queryMaterialParams.vendorId = vendorId;
if (vendorId) {
this.queryMaterialParams.vendorId = vendorId;
}
this.form.pickingInfoList = []
},
/** 打开物料列表 */
......@@ -329,7 +331,7 @@ export default {
this.tempSelection = [];
// 手动设置勾选(匹配外部已选数据)
this.materialList.forEach(row => {
const isSelected = this.form.pickingInfoList.some(item => item.warehouseId === row.warehouseId && item.materialId === row.materialId);
const isSelected = this.form.pickingInfoList.some(item => item.recordId === row.recordId);
this.$refs.selectionTable.toggleRowSelection(row, isSelected);
});
});
......@@ -348,6 +350,7 @@ export default {
item.money = item.collectNumber * item.sellingPrice
return sum + (item.collectNumber * item.sellingPrice);
}, 0)
console.log('outMoney', this.form.outMoney)
},
// 多选框选中数据
handleMaterialSelectionChange(selection) {
......@@ -377,16 +380,26 @@ export default {
this.$modal.msgError('出库明细列表不能为空')
return
}
let isTrue = false
let isUndefined = false
this.form.pickingInfoList.forEach(item =>{
if (!item.collectNumber) {
isTrue = true
if (item.collectNumber === undefined) {
isUndefined = true
}
})
if (isTrue) {
if (isUndefined) {
this.$modal.msgError('领料数量不能为空')
return
}
let isValidNumber = false
this.form.pickingInfoList.forEach(item => {
if (item.collectNumber < 0.01) {
isValidNumber = true
}
})
if (isValidNumber) {
this.$modal.msgError('出库物料数量不能为[0.00]')
return
}
this.form.materialList = this.form.pickingInfoList.map(item =>{
return {
recordId: item.recordId,
......
......@@ -274,7 +274,7 @@
<el-table-column label="库存" align="center" prop="inventory" />
<el-table-column label="领料数量" align="center" prop="collectNumber" width="120px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.collectNumber" @change="collectNumberChange" controls-position="right" size="mini" :min="1" :max="parseInt(scope.row.inventory)" :precision="0" style="width: 100%" placeholder="数量"/>
<el-input-number v-model="scope.row.collectNumber" @change="collectNumberChange" controls-position="right" size="mini" :min="0.00" :precision="2" :max="parseFloat(scope.row.inventory)" style="width: 100%" placeholder="数量"/>
</template>
</el-table-column>
<!-- <el-table-column label="销售单价" align="center" prop="price" width="120px">-->
......@@ -284,7 +284,7 @@
<!-- </el-table-column>-->
<el-table-column label="领料金额" align="center" prop="money" width="120px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.money" disabled controls-position="right" size="mini" :min="0" style="width: 100%" placeholder="金额"/>
<el-input-number v-model="scope.row.money" disabled controls-position="right" size="mini" :precision="2" style="width: 100%" placeholder="金额"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
......@@ -343,7 +343,7 @@
<el-table-column label="物资编码" align="center" prop="materialCode" />
<el-table-column label="物资名称" align="center" prop="materialName" />
<el-table-column label="物资规格" align="center" prop="materialSpecifications" />
<el-table-column label="物资单位" align="center" prop="materialUnit" width="80">
<el-table-column label="物资单位" align="center" prop="materialUnit" width="50">
<template slot-scope="scope">
<dict-tag :options="dict.type.material_unit" :value="scope.row.materialUnit" />
</template>
......@@ -351,7 +351,8 @@
<!-- <el-table-column label="质保期" align="center" prop="materialWarrantyPeriod" />-->
<el-table-column label="参考价" align="center" prop="referencePrice" width="100" />
<el-table-column label="销售价" align="center" prop="sellingPrice" width="100" />
<el-table-column label="库存" align="center" prop="inventory" width="100" />
<el-table-column label="库存" align="center" prop="inventory" width="80" />
<el-table-column label="入库时间" align="center" prop="createTime" width="160" />
</el-table>
<pagination v-show="materialTotal>0" :total="materialTotal" :page.sync="queryMaterialParams.pageNum" :limit.sync="queryMaterialParams.pageSize" @pagination="getMaterialList"/>
<div slot="footer" class="dialog-footer">
......@@ -486,6 +487,7 @@ export default {
queryMaterialParams: {
pageNum: 1,
pageSize: 10,
vendorId: undefined,
vendorName: undefined,
warehouseId: undefined,
warehouseIdList: [],
......@@ -567,11 +569,11 @@ export default {
return
}
this.open1 = true
this.queryMaterialParams.vendorId = this.form.vendorId;
this.getMaterialList()
},
/** 供应商改变 */
vendorIdChange(vendorId) {
this.queryMaterialParams.vendorId = vendorId;
this.form.pickingInfoList = []
},
/** 搜索按钮操作 */
......@@ -581,7 +583,10 @@ export default {
},
/** 重置按钮操作 */
resetMaterialQuery() {
this.resetForm("queryMaterialForm");
this.queryMaterialParams.materialCode = undefined;
this.queryMaterialParams.materialName = undefined;
this.queryMaterialParams.pageNum = 1
this.queryMaterialParams.pageSize = 10
this.handleMaterialQuery();
},
/** 查询物资列表 */
......@@ -597,7 +602,7 @@ export default {
this.tempSelection = [];
// 手动设置勾选(匹配外部已选数据)
this.materialList.forEach(row => {
const isSelected = this.form.pickingInfoList.some(item => item.warehouseId === row.warehouseId && item.materialId === row.materialId);
const isSelected = this.form.pickingInfoList.some(item => item.recordId === row.recordId);
this.$refs.selectionTable.toggleRowSelection(row, isSelected);
});
});
......@@ -612,8 +617,8 @@ export default {
// 入库数量变动
collectNumberChange() {
this.form.outMoney = this.form.pickingInfoList.reduce((sum, item) => {
item.money = item.collectNumber * item.price
return sum + (item.collectNumber * item.price);
item.money = item.collectNumber * item.sellingPrice
return sum + (item.collectNumber * item.sellingPrice);
}, 0)
},
// 多选框选中数据
......@@ -754,6 +759,26 @@ export default {
this.$modal.msgError('出库物料列表不能为空')
return
}
let isUndefined = false
this.form.pickingInfoList.forEach(item =>{
if (item.collectNumber === undefined) {
isUndefined = true
}
})
if (isUndefined) {
this.$modal.msgError('领料数量不能为空')
return
}
let isValidNumber = false
this.form.pickingInfoList.forEach(item => {
if (item.collectNumber < 0.01) {
isValidNumber = true
}
})
if (isValidNumber) {
this.$modal.msgError('出库物料数量不能为[0.00]')
return
}
this.form.materialList = this.form.pickingInfoList.map(item =>{
return {
recordId: item.recordId,
......
......@@ -119,7 +119,7 @@
<el-row>
<el-col :span="6">
<el-form-item label="供应商" prop="vendorId">
<el-select v-model="form.vendorId" placeHolder="请选择供应商" filterable @change="vendorIdChange" style="width: 100%">
<el-select v-model="form.vendorId" placeHolder="请选择供应商" filterable style="width: 100%">
<el-option v-for="item in materialVendorOpt" :key="item.id" :value="item.id" :label="item.vendorName" />
</el-select>
</el-form-item>
......
......@@ -264,19 +264,19 @@
<el-table-column label="质保期(月)" align="center" prop="materialWarrantyPeriod" width="80"/>
<el-table-column label="参考价" align="center" prop="referencePrice" width="80"/>
<el-table-column label="销售价" align="center" prop="sellingPrice" width="80"/>
<el-table-column label="入库数量" align="center" prop="putawayNumber" width="120px">
<el-table-column label="入库数量" align="center" prop="putawayNumber" width="140px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.putawayNumber" @change="putawayChange" controls-position="right" size="mini" :min="1" :precision="0" style="width: 100%" placeholder="数量"/>
<el-input-number v-model="scope.row.putawayNumber" @change="putawayChange" controls-position="right" size="mini" :min="0.01" :precision="2" style="width: 100%" placeholder="数量"/>
</template>
</el-table-column>
<el-table-column label="入库单价" align="center" prop="putawayPrice" width="120px">
<el-table-column label="入库单价" align="center" prop="putawayPrice" width="150px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.putawayPrice" @change="putawayChange" controls-position="right" size="mini" :min="1" :precision="2" style="width: 100%" placeholder="单价"/>
<el-input-number v-model="scope.row.putawayPrice" @change="putawayChange" controls-position="right" size="mini" :min="0.01" :precision="2" style="width: 100%" placeholder="单价"/>
</template>
</el-table-column>
<el-table-column label="入库金额" align="center" prop="putawayMoney" width="120px">
<el-table-column label="入库金额" align="center" prop="putawayMoney" width="150px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.putawayMoney" disabled controls-position="right" size="mini" :min="1" style="width: 100%" placeholder="金额"/>
<el-input-number v-model="scope.row.putawayMoney" disabled controls-position="right" size="mini" :precision="2" style="width: 100%" placeholder="金额"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="50">
......@@ -325,7 +325,7 @@
<el-button icon="el-icon-refresh" size="mini" @click="resetMaterialQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="materialLoading" :data="materialList" ref="selectionTable" max-height="450" @selection-change="handleMaterialSelectionChange">
<el-table v-loading="materialLoading" :data="materialList" ref="selectionTable" max-height="450" row-key="id" @selection-change="handleMaterialSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="分类名称" align="center" prop="materialTypeName" />-->
<!-- <el-table-column label="货位类型" align="center" prop="warehouseLocationType" />-->
......@@ -431,6 +431,7 @@ export default {
total: 0,
// 物料入库表格数据
materialPutawayList: [],
selectedMaterialMap: new Map(),
// 弹出层标题
title: "",
// 是否显示弹出层
......@@ -528,23 +529,6 @@ export default {
vendorChange(id, item) {
let vendor = this.materialVendorList.find(v => v.id === id);
item.vendorName = vendor.vendorName;
},
/**
* 物资类型弃用
*/
getTreeTree(){
typeTree().then(response => {
this.typeOptions = response.data
});
},
// 筛选节点
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
// 节点单击事件
handleNodeClick(data) {
},
/** 查询仓库列表 */
getWarehouseList() {
......@@ -561,18 +545,23 @@ export default {
/** 打开物料列表 */
openMaterialModel() {
this.open1 = true
// 打开对话框时初始化已选数据
this.initializeSelectedMaterials()
this.getMaterialList()
},
/** 搜索按钮操作 */
handleMaterialQuery() {
this.queryMaterialParams.pageNum = 1;
this.getMaterialList();
},
/** 重置按钮操作 */
resetMaterialQuery() {
this.resetForm("queryMaterialForm");
this.handleMaterialQuery();
/** 初始化已选物料数据 */
initializeSelectedMaterials() {
// 将当前入库明细列表中的物料添加到已选Map中
this.selectedMaterialMap.clear()
this.form.putawayInfoList.forEach(item => {
const materialId = item.materialId || item.id
console.log('item' , item)
if (materialId) {
this.selectedMaterialMap.set(materialId, item)
}
})
},
/** 查询物资列表 */
getMaterialList() {
this.materialLoading = true;
......@@ -580,41 +569,122 @@ export default {
this.materialList = response.rows;
this.materialTotal = response.total;
this.materialLoading = false;
}).then(() =>{
}).then(() => {
this.$nextTick(() => {
// 清空临时勾选
this.tempSelection = [];
// 手动设置勾选(匹配外部已选数据)
this.materialList.forEach(row => {
const isSelected = this.form.putawayInfoList.some(item => item.id === row.id || item.materialId === row.id);
this.$refs.selectionTable.toggleRowSelection(row, isSelected);
});
// 恢复选择状态
this.restoreMaterialSelection();
});
})
},
/** 恢复物料选择状态 */
restoreMaterialSelection() {
if (!this.$refs.selectionTable || !this.materialList.length) return;
// 先清空所有选择
this.$refs.selectionTable.clearSelection();
// 获取所有需要选择的物料ID
const selectedIds = new Set();
this.form.putawayInfoList.forEach(item => {
const materialId = item.materialId || item.id;
if (materialId) {
selectedIds.add(materialId);
}
});
// 批量设置选择状态
this.$nextTick(() => {
this.materialList.forEach(row => {
if (selectedIds.has(row.id)) {
this.$refs.selectionTable.toggleRowSelection(row, true);
}
});
});
},
// 多选框选中数据
handleMaterialSelectionChange(selection) {
this.tempSelection = selection
this.tempSelection = selection;
// 更新已选数据的Map
const currentPageIds = new Set(this.materialList.map(row => row.id));
// 移除当前页中取消选择的行
console.log('currentPageIds--------->',currentPageIds);
console.log('this.selectedMaterialMap--------->',this.selectedMaterialMap);
console.log('selection--------->',selection);
for (let id of this.selectedMaterialMap.keys()) {
if (currentPageIds.has(id) && !selection.some(row => row.id === id)) {
console.log('delete-------->', id)
this.selectedMaterialMap.delete(id);
}
}
// 添加当前页中新选择的行
selection.forEach(row => {
// 如果物料已经在入库明细中,保留原有数据
if (this.selectedMaterialMap.has(row.id)) {
const existingItem = this.selectedMaterialMap.get(row.id);
// 保留入库数量、单价等编辑过的数据
this.selectedMaterialMap.set(row.id, {
...row,
putawayNumber: existingItem.putawayNumber || 0.01,
putawayPrice: existingItem.putawayPrice || 0.01,
putawayMoney: existingItem.putawayMoney || 0.01,
vendorId: existingItem.vendorId,
vendorName: existingItem.vendorName
});
} else {
// 新选择的物料,设置默认值
this.selectedMaterialMap.set(row.id, {
...row,
materialId: row.id,
putawayNumber: 0.01,
putawayPrice: 0.01,
putawayMoney: 0.01,
vendorId: row.vendorId,
vendorName: row.vendorName
});
}
});
},
// 将选中物料添加至入库明细列表
confirmSelection() {
// 删除 a 中多余数据 用 filter() + some() 保留 a 中与 b 的 id 匹配的项。
// 添加 b 中新增数据 用 filter() 找出 b 中 id 不在 a 中的项。
// 合并结果使用展开运算符 ... 合并两个数组。
this.form.putawayInfoList = [
...this.form.putawayInfoList.filter(itemA => this.tempSelection.some(itemB => itemB.id === itemA.id || itemA.materialId === itemB.id)),
...this.tempSelection.filter(itemB => !this.form.putawayInfoList.some(itemA => itemA.id === itemB.id || itemA.materialId === itemB.id))
]
this.open1 = false
// 使用Map中的数据更新入库明细列表
this.form.putawayInfoList = Array.from(this.selectedMaterialMap.values());
this.open1 = false;
this.resetMaterialQuery()
// 重新计算总金额
this.putawayChange();
},
/** 搜索按钮操作 */
handleMaterialQuery() {
this.queryMaterialParams.pageNum = 1;
this.getMaterialList();
},
/** 重置按钮操作 */
resetMaterialQuery() {
this.resetForm("queryMaterialForm");
this.handleMaterialQuery();
},
// 入库明细删除
handleRowDelete(row) {
this.form.putawayInfoList = this.form.putawayInfoList.filter(item => item.id !== row.id);
this.putawayChange()
const materialId = row.materialId || row.id;
// 从Map中移除
this.selectedMaterialMap.delete(materialId);
// 更新入库明细列表
this.form.putawayInfoList = this.form.putawayInfoList.filter(item => {
const itemMaterialId = item.materialId || item.id;
return itemMaterialId !== materialId;
});
this.putawayChange();
},
// 取消按钮
// 取消物料选择
cancelMaterial() {
this.open1 = false;
// 可选:清空临时选择,但保留已确认的选择
this.tempSelection = [];
this.resetMaterialQuery()
},
// 入库数量变动
putawayChange() {
......@@ -652,6 +722,7 @@ export default {
createTime: formatDate(new Date().getTime()),
putawayInfoList: []
};
this.selectedMaterialMap.clear();
this.resetForm("form");
},
/** 搜索按钮操作 */
......@@ -677,6 +748,9 @@ export default {
this.title = "添加物料入库";
this.getWarehouseList()
this.getVendorList()
console.log('this.selectedMaterialMap', this.selectedMaterialMap)
console.log('this.form.putawayInfoList', this.form.putawayInfoList)
console.log('this.this.tempSelection', this.tempSelection)
},
/** 详情按钮操作 */
handleDetail(row) {
......@@ -699,6 +773,8 @@ export default {
this.title = "修改物料入库";
this.getWarehouseList()
this.getVendorList()
// 初始化已选物料数据
this.initializeSelectedMaterials();
});
},
/** 提交按钮 */
......@@ -712,6 +788,19 @@ export default {
this.buttonLoading = false;
return
}
let vendorIsNull = false
this.form.putawayInfoList.forEach(item =>{
if (!item.vendorId) {
vendorIsNull = true
}
})
if (vendorIsNull) {
this.$modal.msgError('入库明细列表物料供应商不能为空')
this.buttonLoading = false;
return
}
this.form.putawayInfoList.forEach(item =>{
item.materialId = item.materialId || item.id
})
......@@ -767,7 +856,6 @@ export default {
},
/** 导出按钮操作 */
handleExport() {
console.log('this.queryParams', this.queryParams);
this.download('business/materialPutawayInfo/export', {
...this.queryParams
}, `入库单明细_${new Date().getTime()}.xlsx`)
......
......@@ -242,17 +242,17 @@
</el-table-column>
<el-table-column label="退货数量" align="center" prop="returnsNumber" width="120px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.returnsNumber" @change="returnsNumberChange" controls-position="right" size="mini" :min="0" :max="scope.row.putawayNumber - scope.row.returnedNumber - scope.row.issuedNumber" :precision="0" style="width: 100%" placeholder="数量"/>
<el-input-number v-model="scope.row.returnsNumber" @change="returnsNumberChange" controls-position="right" size="mini" :min="0" :precision="2" :max="parseFloat(scope.row.putawayNumber) - parseFloat(scope.row.returnedNumber) - parseFloat(scope.row.issuedNumber)" style="width: 100%" placeholder="数量"/>
</template>
</el-table-column>
<el-table-column label="退货单价" align="center" prop="returnsPrice" width="120px">
<el-table-column label="退货单价" align="center" prop="returnsPrice" width="160px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.returnsPrice" disabled controls-position="right" size="mini" :min="1" :precision="2" style="width: 100%" placeholder="单价"/>
<el-input-number v-model="scope.row.returnsPrice" disabled controls-position="right" size="mini" :precision="2" style="width: 100%" placeholder="单价"/>
</template>
</el-table-column>
<el-table-column label="退货金额" align="center" prop="returnsMoney" width="120px">
<el-table-column label="退货金额" align="center" prop="returnsMoney" width="160px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.returnsMoney" disabled controls-position="right" size="mini" :min="1" style="width: 100%" placeholder="金额"/>
<el-input-number v-model="scope.row.returnsMoney" disabled controls-position="right" size="mini" :precision="2" style="width: 100%" placeholder="金额"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
......@@ -400,15 +400,15 @@ export default {
// 退货数量更改
returnsNumberChange() {
this.form.returnsMoney = this.materialList.reduce((sum, item) => {
item.returnsMoney = item.returnsNumber * item.returnsPrice
return sum + (item.returnsNumber * item.returnsPrice);
item.returnsMoney = parseFloat(item.returnsNumber) * parseFloat(item.returnsPrice)
return sum + (parseFloat(item.returnsNumber) * parseFloat(item.returnsPrice));
}, 0)
},
// 入库明细删除
handleRowDelete(row) {
this.materialList = this.materialList.filter(item => item.id !== row.id);
this.form.returnsMoney = this.materialList.reduce((sum, item) => {
return sum + (item.returnsNumber * item.returnsPrice);
return sum + (parseFloat(item.returnsNumber) * parseFloat(item.returnsPrice));
}, 0)
},
// 取消按钮
......@@ -513,12 +513,12 @@ export default {
this.form.returnsInfoBoList = this.materialList
let isTrue = false;
this.form.returnsInfoBoList.forEach(item => {
if (item.returnsNumber < 1) {
if (item.returnsNumber < 0.01) {
isTrue = true;
}
})
if (isTrue) {
this.$modal.msgError('退货数量不能小于1')
this.$modal.msgError('退货数量不能小于0.01')
this.buttonLoading = false;
return
}
......
......@@ -58,7 +58,7 @@
</template>
</el-table-column>
<!-- <el-table-column label="采购标的" align="center" prop="procurementSubject" />-->
<el-table-column label="适用车型" align="center" prop="compatibleWith" />
<el-table-column label="适用车型" align="center" prop="compatibleWith" show-overflow-tooltip/>
<el-table-column label="物资图片" align="center" prop="materialUrl">
<template slot-scope="scope">
<image-preview :src="scope.row.materialUrl" style="width: 50px; height: 50px" />
......
......@@ -752,7 +752,7 @@ export default {
});
},
getCarList() {
listCar({ pageNum: 1, pageSize: 99 }).then(res=>{
listCar({ pageNum: 1, pageSize: 9999 }).then(res=>{
this.carList = res.rows
})
},
......
......@@ -404,7 +404,7 @@ export default {
/** 查询维修项目列表 */
getMaintainList() {
this.loading = true;
listMaintainProject({ ...this.queryMaintainParams, notInIdList: this.repairFormProjectList.map(item => item.maintainId) }).then(response => {
listMaintainProject({ ...this.queryMaintainParams }).then(response => {
this.maintainProjectList = response.rows;
this.total = response.total;
this.loading = false;
......@@ -417,7 +417,7 @@ export default {
},
/** 查询人员-人员列表 */
getMaintainUserList() {
listUser({ type: 1, pageNum: 1, pageSize: 1000 }).then(response => {
listUser({ pageNum: 1, pageSize: 1000 }).then(response => {
this.maintainUserList = response.rows;
});
},
......
......@@ -20,7 +20,20 @@
<el-table-column label="人员名称" align="center" prop="maintainUserName" />
<el-table-column label="岗位名称" align="center" prop="postName" />
<!-- <el-table-column label="在岗状态" align="center" prop="state" />-->
<el-table-column label="分配工时" align="center" prop="dispatchManHour" />
<el-table-column label="分配工时" align="center" prop="dispatchManHour">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.dispatchManHour"
@change="handleDispatchManHourChange(scope.row)"
controls-position="right"
size="mini"
:class="{ 'input-error': !isDispatchValid(scope.row) }"
:min="0"
:max="Number(scope.row.standardManHour)"
:precision="1"
style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="扣罚工时" align="center" prop="deductManHour">
<template slot-scope="scope">
<el-input-number v-model="scope.row.deductManHour" @change="submitForm(scope.row)" controls-position="right" size="mini" :min="0" :max="Number(scope.row.dispatchManHour)" :precision="1" style="width: 100%" />
......@@ -28,7 +41,7 @@
</el-table-column>
<el-table-column label="实际工时" align="center" prop="actualManHour">
<template slot-scope="scope">
{{scope.row.actualManHour = Number(scope.row.dispatchManHour) - Number(scope.row.deductManHour).toFixed(1)}}
{{ (Number(scope.row.dispatchManHour) - Number(scope.row.deductManHour)).toFixed(1) }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
......@@ -77,7 +90,8 @@ import {
delRepairFormProjectDispatch,
addRepairFormProjectDispatch,
updateRepairFormProjectDispatch,
addRepairFormProjectDispatchP
addRepairFormProjectDispatchP,
updateRepairFormProjectDispatchBatch
} from '@/api/business/repairFormProjectDispatch'
import user from "../user/index"
......@@ -185,6 +199,16 @@ export default {
}
};
},
computed: {
// 检查总分配工时是否超过标准工时
isTotalExceedStandard() {
if (!this.data.standardManHour) return false;
const totalDispatchManHour = this.repairFormProjectDispatchList.reduce((total, item) => {
return total + (Number(item.dispatchManHour) || 0);
}, 0);
return totalDispatchManHour.toFixed(1) !== Number(this.data.standardManHour).toFixed(1);
}
},
created() {
this.getList();
},
......@@ -262,13 +286,50 @@ export default {
this.title = "修改报修单-报修项目-派工";
});
},
/** 提交按钮 */
// 检查分配工时是否有效
isDispatchValid(row) {
if (!this.data.standardManHour) return true;
const totalDispatchManHour = this.repairFormProjectDispatchList.reduce((total, item) => {
return total + (Number(item.dispatchManHour) || 0);
}, 0);
return totalDispatchManHour.toFixed(1) === Number(this.data.standardManHour).toFixed(1);
},
/** 分配工时变化处理 */
handleDispatchManHourChange(row) {
// 检查总分配工时是否等于标准工时
const totalDispatchManHour = this.repairFormProjectDispatchList.reduce((total, item) => {
return total + (Number(item.dispatchManHour) || 0);
}, 0);
// 如果总分配工时不等于标准工时,显示提示
if (this.data.standardManHour && totalDispatchManHour.toFixed(1) !== Number(this.data.standardManHour).toFixed(1)) {
this.$message.warning(`总分配工时(${totalDispatchManHour.toFixed(1)})不等于项目标准工时(${Number(this.data.standardManHour).toFixed(1)})`);
return false;
}
// 更新实际工时
row.actualManHour = (Number(row.dispatchManHour) - Number(row.deductManHour)).toFixed(1);
// 提交更新所有数据
this.submitAllForm();
},
/** 扣罚工时变化处理 */
submitForm(row) {
// 更新实际工时
row.actualManHour = (Number(row.dispatchManHour) - Number(row.deductManHour)).toFixed(1);
// 提交更新所有数据
this.submitAllForm();
},
/** 提交所有数据 */
submitAllForm() {
this.buttonLoading = true;
updateRepairFormProjectDispatch(row).then(response => {
// 使用批量更新接口提交所有行数据
updateRepairFormProjectDispatchBatch(this.repairFormProjectDispatchList).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(error => {
console.error(error);
this.$modal.msgError("修改失败");
}).finally(() => {
this.buttonLoading = false;
});
......@@ -312,3 +373,9 @@ export default {
}
};
</script>
<style scoped>
.input-error ::v-deep .el-input__inner {
border-color: #f56c6c !important;
}
</style>
\ No newline at end of file
<template>
<i-frame :src="url"/>
</template>
<script>
import { getToken } from '@/utils/auth'
import { getBiUrl } from '@/api/tool/jimu'
import iFrame from '@/components/iFrame/index.vue'
import {getCurrentDeptTree} from "@/api/business/unit";
export default {
name: "orderInfo",
components: {
iFrame
},
data() {
return {
url: ''
}
},
created() {
this.init()
},
methods: {
init() {
getCurrentDeptTree().then(response => {
let deptIds = response.data.map((item) => {
return item.deptId
})
console.log('deptIds',deptIds.join(','))
this.url = `http://${window.location.hostname}:8099/jmreport/view/1174907222744879104?token=Bearer `+ getToken()
console.log('url', this.url)
});
},
}
}
</script>
<template>
<i-frame :src="url"/>
</template>
<script>
import {getToken} from '@/utils/auth'
import iFrame from '@/components/iFrame/index.vue'
import {getCurrentDeptTree} from "@/api/business/unit";
export default {
name: "orderInfo",
components: {
iFrame
},
data() {
return {
url: ''
}
},
created() {
this.init()
},
methods: {
init() {
getCurrentDeptTree().then(response => {
let deptIds = response.data.map((item) => {
return item.deptId
})
console.log('deptIds',deptIds.join(','))
this.url = `http://${window.location.hostname}:8099/jmreport/view/1174586035611238400?deptId=${this.$store.state.user.userInfo.deptId}&deptIds=${deptIds.join(',')}&token=Bearer `+ getToken()
console.log('url', this.url)
});
},
}
}
</script>
......@@ -58,6 +58,8 @@
<el-table-column label="证件号" align="center" prop="clientCertificateNumber" width="100px" show-overflow-tooltip/>
<el-table-column label="工时费优惠" align="center" prop="manHourDiscountMoney" />
<el-table-column label="原料费优惠" align="center" prop="materialDiscountMoney" />
<el-table-column label="应收金额" align="center" prop="receivableMoney" />
<el-table-column label="结算金额" align="center" prop="practicalMoney" />
<el-table-column label="结算时间" align="center" prop="settlementTime" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.settlementTime, '{y}-{m}-{d}') }}</span>
......@@ -269,6 +271,7 @@
<el-form-item label="收款时间" prop="collectionTime">
<el-date-picker clearable
v-model="form.collectionTime"
:disabled="isQrPay"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择收款时间">
......@@ -277,12 +280,12 @@
</el-col>
<el-col :span="6">
<el-form-item label="收款账号" prop="collectionAccount">
<el-input v-model="form.collectionAccount" placeholder="请输入收款账号" />
<el-input v-model="form.collectionAccount" :disabled="isQrPay" placeholder="请输入收款账号" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="收款流水号" prop="collectionSerialNumber">
<el-input v-model="form.collectionSerialNumber" placeholder="请输入收款流水号" />
<el-form-item label="交易流水号" prop="collectionSerialNumber">
<el-input v-model="form.collectionSerialNumber" :disabled="isQrPay" placeholder="请输入交易流水号" />
</el-form-item>
</el-col>
</el-row>
......@@ -303,11 +306,25 @@
</el-form>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="qrOpen">扫码支付</el-button>
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 扫码支付对话框 -->
<el-dialog :title="title" :visible.sync="open2" width="500px" append-to-body>
<el-form ref="payForm" :model="payForm" :rules="payRules" label-width="80px">
<el-form-item label="支付码" prop="paymentAccount">
<el-input ref="payCodeInput" v-model="payForm.paymentAccount" @keydown.enter.native.prevent placeholder="使用设备扫描条形码" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="payButtonLoading" type="primary" @click="paySubmitForm">确认支付</el-button>
<el-button :loading="payButtonLoading" @click="open2 = false"> </el-button>
</div>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog :title="title" :visible.sync="open1" width="80%" append-to-body>
<el-scrollbar style="height: 75vh;">
......@@ -392,7 +409,7 @@
import {
delSettlementMaintain,
getSettlementMaintain,
listSettlementMaintain,
listSettlementMaintain, paySettlementMaintain,
receiptSettlementMaintain
} from '@/api/business/settlementMaintain'
......@@ -403,6 +420,7 @@ export default {
return {
// 按钮loading
buttonLoading: false,
payButtonLoading: false,
// 遮罩层
loading: true,
// 选中数组
......@@ -422,6 +440,8 @@ export default {
// 是否显示弹出层
open: false,
open1: false,
open2: false,
isQrPay: false,
// 查询参数
queryParams: {
pageNum: 1,
......@@ -433,6 +453,10 @@ export default {
},
// 表单参数
form: {},
payForm: {
id: undefined,
paymentAccount: undefined,
},
// 表单校验
rules: {
collectionTime: [
......@@ -444,8 +468,13 @@ export default {
collectionSerialNumber: [
{ required: true, message: "收款流水号不能为空", trigger: "blur" }
],
collectionVoucher: [
{ required: true, message: "收款回执不能为空", trigger: "change" }
// collectionVoucher: [
// { required: true, message: "收款回执不能为空", trigger: "change" }
// ],
},
payRules: {
paymentAccount: [
{ required: true, message: "支付码不能为空", trigger: "blur" }
],
}
};
......@@ -526,6 +555,40 @@ export default {
this.title = "结算维修单详情";
});
},
/** 扫码支付按钮操作 */
qrOpen() {
this.payForm = {
id: this.form.id,
paymentAccount: undefined,
}
this.open2 = true;
this.isQrPay = false;
this.title = "扫码支付";
this.$nextTick(() => {
// 确保输入框存在并获取焦点
if (this.$refs.payCodeInput && this.$refs.payCodeInput.focus) {
this.$refs.payCodeInput.focus()
}
})
},
/** 确认支付按钮操作 */
paySubmitForm() {
this.$refs["payForm"].validate(valid => {
if (valid) {
this.payButtonLoading = true;
paySettlementMaintain(this.payForm).then(response => {
this.$modal.msgSuccess("支付成功");
this.open2 = false;
this.isQrPay = true;
getSettlementMaintain(this.form.id).then(response => {
this.form = response.data;
});
}).finally(() => {
this.payButtonLoading = false;
});
}
});
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
......
......@@ -119,13 +119,13 @@
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="支付方式" prop="paymentMethod">
<el-select v-model="form.paymentMethod" placeholder="请选择支付方式" style="width: 100%">
<el-option v-for="item in dict.type.settlement_payment_method" :key="item.value" :value="parseInt(item.value)" :label="item.label" />
</el-select>
</el-form-item>
</el-col>
<!-- <el-col :span="6">-->
<!-- <el-form-item label="支付方式" prop="paymentMethod">-->
<!-- <el-select v-model="form.paymentMethod" placeholder="请选择支付方式" style="width: 100%">-->
<!-- <el-option v-for="item in dict.type.settlement_payment_method" :key="item.value" :value="parseInt(item.value)" :label="item.label" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="6">
<el-form-item label="结算时间" prop="settlementTime">
<el-date-picker clearable
......@@ -280,9 +280,9 @@ export default {
paymentAccountName: [
{ required: true, message: "账号名称不能为空", trigger: "blur" }
],
paymentVoucher: [
{ required: true, message: "付款凭证不能为空", trigger: "blur" }
],
// paymentVoucher: [
// { required: true, message: "付款凭证不能为空", trigger: "blur" }
// ],
},
};
},
......@@ -378,7 +378,7 @@ export default {
this.buttonLoading = false;
}).finally(() => {
this.buttonLoading = false;
this.$tab.closeOpenPage({path: '/settlement/settlementMaintain?clientType=1'})
this.$tab.closeOpenPage({path: '/settlement/settlementMaintain?clientType=2'})
});
}
});
......
......@@ -43,6 +43,15 @@
v-hasPermi="['business:settlementMaterial:add']"
>结算</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
......@@ -447,6 +456,7 @@ export default {
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
// 如果没有选中任何项,直接禁用按钮
if (selection.length === 0) {
this.multiple = true; // 禁用按钮
......@@ -593,8 +603,9 @@ export default {
/** 导出按钮操作 */
handleExport() {
this.download('business/materialPicking/export', {
...this.queryParams
}, `materialPicking_${new Date().getTime()}.xlsx`)
...this.queryParams,
ids: this.ids
}, `供应商铺货结算.xlsx`)
}
}
};
......
......@@ -19,6 +19,7 @@
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
@input="checkPasswordStrength"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
......@@ -120,6 +121,26 @@ export default {
this.getCookie();
},
methods: {
// 检查密码强度
checkPasswordStrength() {
if (!this.loginForm.password) {
this.isPasswordStrong = false;
return;
}
let strength = 0;
// 长度检查
if (this.loginForm.password.length >= 8) strength++;
// 包含小写字母
if (/[a-z]/.test(this.loginForm.password)) strength++;
// 包含大写字母
if (/[A-Z]/.test(this.loginForm.password)) strength++;
// 包含数字
if (/[0-9]/.test(this.loginForm.password)) strength++;
// 包含特殊字符
if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(this.loginForm.password)) strength++;
// 设置强度等级
this.isPasswordStrong = strength > 4;
},
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.data.captchaEnabled === undefined ? true : res.data.captchaEnabled;
......@@ -142,6 +163,11 @@ export default {
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
// 再次确认密码强度
if (!this.isPasswordStrong) {
this.$message.error("密码强度不足,请确保包含大小写字母、数字和特殊字符");
return;
}
this.loading = true;
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 });
......
......@@ -172,6 +172,11 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.type == 4">
<el-form-item label="终端号" prop="terminalCode">
<el-input v-model="form.terminalCode" placeholder="请输入终端号" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
......@@ -284,7 +289,8 @@ export default {
phone: undefined,
email: undefined,
status: "0",
type: undefined
type: undefined,
terminalCode: undefined,
};
this.resetForm("form");
},
......
......@@ -260,7 +260,7 @@
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password/>
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password @input="checkPasswordStrength"/>
</el-form-item>
</el-col>
</el-row>
......@@ -385,7 +385,30 @@ export default {
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect },
data() {
// 验证密码复杂度
const validatePasswordComplexity = (rule, value, callback) => {
if (!value) {
callback(new Error("新密码不能为空"));
return;
}
// 检查密码复杂度
const hasLowerCase = /[a-z]/.test(value);
const hasUpperCase = /[A-Z]/.test(value);
const hasNumber = /[0-9]/.test(value);
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value);
if (!hasLowerCase || !hasUpperCase || !hasNumber || !hasSpecialChar) {
callback(new Error("密码必须包含大小写字母、数字和特殊字符"));
return;
}
callback();
};
return {
strengthClass: 'weak',
strengthText: '',
isPasswordStrong: false,
// 遮罩层
loading: true,
// 选中数组
......@@ -468,7 +491,8 @@ export default {
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
{ min: 8, message: "密码至少为8个字符,须包含大写字母、小写字母、数字和特殊字符", trigger: "blur" },
{ validator: validatePasswordComplexity, trigger: "blur" }
],
email: [
{
......@@ -501,6 +525,40 @@ export default {
});
},
methods: {
// 检查密码强度
checkPasswordStrength() {
if (!this.form.password) {
this.strengthClass = 'weak';
this.strengthText = '';
this.isPasswordStrong = false;
return;
}
let strength = 0;
// 长度检查
if (this.form.password.length >= 8) strength++;
// 包含小写字母
if (/[a-z]/.test(this.form.password)) strength++;
// 包含大写字母
if (/[A-Z]/.test(this.form.password)) strength++;
// 包含数字
if (/[0-9]/.test(this.form.password)) strength++;
// 包含特殊字符
if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(this.form.password)) strength++;
// 设置强度等级
if (strength <= 2) {
this.strengthClass = 'weak';
this.strengthText = '';
this.isPasswordStrong = false;
} else if (strength <= 4) {
this.strengthClass = 'medium';
this.strengthText = '';
this.isPasswordStrong = false;
} else {
this.strengthClass = 'strong';
this.strengthText = '';
this.isPasswordStrong = true;
}
},
/** 查询用户列表 */
getList() {
this.loading = true;
......@@ -625,13 +683,13 @@ export default {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间"
inputPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,20}$/,
inputErrorMessage: "密码必须为8-20个字符,且包含大写字母、小写字母、数字和特殊字符(@$!%*?&)"
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value);
});
}).catch(() => {});
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value);
});
}).catch(() => {});
},
/** 分配角色操作 */
handleAuthRole: function(row) {
......