feat(hjc): 汇吉采标书购买后端 阶段0/1 - 领域表/实体与接口 + 一站式双向对接

- 新增 com.gxwebsoft.hjc 包(entity/param/mapper/service/controller/dto/util)
- 实体:HjcBidProject(项目即标书单表)/HjcEnterprise/HjcEnterpriseMaterial/HjcOrder/HjcOrderPushLog
- CRUD 控制器:标书项目(公开列表+后台维护)、企业资质(提交/我的/审核)、订单(下单/我的订单/后台)
- 入向:POST /api/hjc/push/project 一站式推送(对称鉴权 appKey+timestamp+sign) 按 projectNo upsert
- 出向:createPurchaseDetails 推送客户端(MD5签名+推送日志+30min重试),手动触发端点
- SecurityConfig 放行 /api/hjc/push/project;application.yml 增加 hjc.one-stop 配置
- DDL:src/main/resources/sql/hjc_init.sql
This commit is contained in:
2026-09-08 20:27:28 +08:00
parent 1bcb805d65
commit b2f310b81d
43 changed files with 2227 additions and 1 deletions
@@ -79,7 +79,8 @@ public class SecurityConfig {
"/api/shop/getShopInfo", "/api/shop/getShopInfo",
"/api/shop/shop-order/test", "/api/shop/shop-order/test",
"/api/qr-code/**", "/api/qr-code/**",
"/api/shop/order-delivery/notify" "/api/shop/order-delivery/notify",
"/api/hjc/push/project"
) )
.permitAll() .permitAll()
.anyRequest() .anyRequest()
@@ -0,0 +1,85 @@
package com.gxwebsoft.hjc.controller;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.param.HjcBidProjectParam;
import com.gxwebsoft.hjc.service.HjcBidProjectService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 汇吉采标书项目(C端浏览 + 管理后台维护)
*/
@Tag(name = "汇吉采-标书项目")
@RestController
@RequestMapping("/api/hjc/bid-project")
public class HjcBidProjectController extends BaseController {
@Resource
private HjcBidProjectService hjcBidProjectService;
@Operation(summary = "分页查询(后台)")
@GetMapping("/page")
public ApiResult<PageResult<HjcBidProject>> page(HjcBidProjectParam param) {
return success(hjcBidProjectService.pageRel(param));
}
@Operation(summary = "在售列表(C端,仅上架)")
@GetMapping("/list")
public ApiResult<PageResult<HjcBidProject>> list(HjcBidProjectParam param) {
param.setStatus(1);
return success(hjcBidProjectService.pageRel(param));
}
@Operation(summary = "详情")
@GetMapping("/{id}")
public ApiResult<?> detail(@PathVariable("id") Integer id) {
HjcBidProject project = hjcBidProjectService.getById(id);
if (project == null) {
return fail("标书项目不存在");
}
return success(project);
}
@Operation(summary = "新增(后台)")
@PostMapping()
public ApiResult<?> save(@RequestBody HjcBidProject project) {
project.setId(null);
if (project.getTenantId() == null) {
project.setTenantId(getTenantId());
}
if (project.getStatus() == null) {
project.setStatus(1);
}
if (project.getDataSource() == null) {
project.setDataSource("MANUAL");
}
if (project.getSaleCount() == null) {
project.setSaleCount(0);
}
hjcBidProjectService.save(project);
return success("保存成功", project.getId());
}
@Operation(summary = "更新(后台)")
@PutMapping()
public ApiResult<?> update(@RequestBody HjcBidProject project) {
if (project.getId() == null) {
return fail("ID不能为空");
}
hjcBidProjectService.updateById(project);
return success("更新成功");
}
@Operation(summary = "删除/下架(后台)")
@DeleteMapping("/{id}")
public ApiResult<?> delete(@PathVariable("id") Integer id) {
hjcBidProjectService.removeById(id);
return success("删除成功");
}
}
@@ -0,0 +1,131 @@
package com.gxwebsoft.hjc.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial;
import com.gxwebsoft.hjc.param.HjcEnterpriseParam;
import com.gxwebsoft.hjc.service.HjcEnterpriseMaterialService;
import com.gxwebsoft.hjc.service.HjcEnterpriseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 汇吉采企业账号与资质
*/
@Tag(name = "汇吉采-企业资质")
@RestController
@RequestMapping("/api/hjc/enterprise")
public class HjcEnterpriseController extends BaseController {
@Resource
private HjcEnterpriseService hjcEnterpriseService;
@Resource
private HjcEnterpriseMaterialService hjcEnterpriseMaterialService;
@Operation(summary = "当前登录企业的资料")
@GetMapping("/my")
public ApiResult<?> my() {
Integer userId = getLoginUserId();
if (userId == null) {
return fail("用户未登录");
}
HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId);
if (enterprise != null) {
enterprise.setMaterials(listMaterials(enterprise.getId()));
enterprise.setMobile(getLoginUser().getMobile());
}
return success(enterprise);
}
@Operation(summary = "提交/更新企业资质(信息+证件),提交后回到待审核")
@PostMapping("/save")
@Transactional(rollbackFor = Exception.class)
public ApiResult<?> save(@RequestBody HjcEnterprise enterprise) {
Integer userId = getLoginUserId();
if (userId == null) {
return fail("用户未登录");
}
HjcEnterprise exist = hjcEnterpriseService.getByUserId(userId);
boolean isNew = exist == null;
if (isNew) {
enterprise.setId(null);
enterprise.setUserId(userId);
enterprise.setAuthStatus(0);
if (enterprise.getTenantId() == null) {
enterprise.setTenantId(getTenantId());
}
hjcEnterpriseService.save(enterprise);
} else {
enterprise.setId(exist.getId());
enterprise.setUserId(userId);
enterprise.setAuthStatus(0);
hjcEnterpriseService.updateById(enterprise);
}
Integer enterpriseId = isNew ? enterprise.getId() : exist.getId();
// 替换证件材料:先删旧再插新
hjcEnterpriseMaterialService.remove(new LambdaQueryWrapper<HjcEnterpriseMaterial>()
.eq(HjcEnterpriseMaterial::getEnterpriseId, enterpriseId));
List<HjcEnterpriseMaterial> materials = enterprise.getMaterials();
if (materials != null) {
for (HjcEnterpriseMaterial m : materials) {
if (StrUtil.isBlank(m.getFileUrl())) {
continue;
}
m.setId(null);
m.setEnterpriseId(enterpriseId);
if (m.getTenantId() == null) {
m.setTenantId(getTenantId());
}
hjcEnterpriseMaterialService.save(m);
}
}
return success("提交成功,等待审核", enterpriseId);
}
@Operation(summary = "后台-企业资质分页")
@GetMapping("/page")
public ApiResult<PageResult<HjcEnterprise>> page(HjcEnterpriseParam param) {
return success(hjcEnterpriseService.pageRel(param));
}
@Operation(summary = "后台-资质详情")
@GetMapping("/{id}")
public ApiResult<?> detail(@PathVariable("id") Integer id) {
HjcEnterprise enterprise = hjcEnterpriseService.getById(id);
if (enterprise == null) {
return fail("企业不存在");
}
enterprise.setMaterials(listMaterials(id));
return success(enterprise);
}
@Operation(summary = "后台-审核:通过/驳回")
@PutMapping("/auth")
public ApiResult<?> audit(@RequestBody HjcEnterprise param) {
if (param.getId() == null || param.getAuthStatus() == null) {
return fail("审核参数不完整");
}
HjcEnterprise enterprise = new HjcEnterprise();
enterprise.setId(param.getId());
enterprise.setAuthStatus(param.getAuthStatus());
enterprise.setRejectReason(param.getRejectReason());
hjcEnterpriseService.updateById(enterprise);
return success("审核完成");
}
private List<HjcEnterpriseMaterial> listMaterials(Integer enterpriseId) {
return hjcEnterpriseMaterialService.list(new LambdaQueryWrapper<HjcEnterpriseMaterial>()
.eq(HjcEnterpriseMaterial::getEnterpriseId, enterpriseId)
.orderByAsc(HjcEnterpriseMaterial::getId));
}
}
@@ -0,0 +1,139 @@
package com.gxwebsoft.hjc.controller;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.dto.CreateOrderRequest;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.entity.HjcOrder;
import com.gxwebsoft.hjc.param.HjcOrderParam;
import com.gxwebsoft.hjc.service.HjcBidProjectService;
import com.gxwebsoft.hjc.service.HjcEnterpriseService;
import com.gxwebsoft.hjc.service.HjcOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
* 汇吉采标书订单(下单 + 我的订单 + 后台订单)
*/
@Tag(name = "汇吉采-标书订单")
@RestController
@RequestMapping("/api/hjc/order")
public class HjcOrderController extends BaseController {
private static final DateTimeFormatter ORDER_NO_FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
@Resource
private HjcOrderService hjcOrderService;
@Resource
private HjcBidProjectService hjcBidProjectService;
@Resource
private HjcEnterpriseService hjcEnterpriseService;
@Operation(summary = "下单(创建待支付订单)")
@PostMapping("/create")
public ApiResult<?> create(@RequestBody CreateOrderRequest request) {
Integer userId = getLoginUserId();
if (userId == null) {
return fail("用户未登录");
}
HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId);
if (enterprise == null) {
return fail("请先完善企业信息");
}
if (enterprise.getAuthStatus() == null || enterprise.getAuthStatus() != 1) {
return fail("企业资质未通过审核,暂无权限购买");
}
if (request.getProjectId() == null) {
return fail("标书项目ID不能为空");
}
HjcBidProject project = hjcBidProjectService.getById(request.getProjectId());
if (project == null) {
return fail("标书项目不存在");
}
if (project.getStatus() == null || project.getStatus() != 1) {
return fail("该项目未在售");
}
int quantity = request.getQuantity() == null || request.getQuantity() < 1 ? 1 : request.getQuantity();
BigDecimal unitPrice = project.getTenderPrice() == null ? BigDecimal.ZERO : project.getTenderPrice();
String orderNo = "HJC" + ORDER_NO_FMT.format(LocalDateTime.now()) + RandomUtil.randomNumbers(4);
HjcOrder order = new HjcOrder();
order.setOrderNo(orderNo);
order.setProjectId(project.getId());
order.setProjectNo(project.getProjectNo());
order.setProjectName(project.getProjectName());
order.setEnterpriseId(enterprise.getId());
order.setEnterpriseName(enterprise.getName());
order.setContactName(firstNotBlank(request.getContactName(), enterprise.getAgentName()));
order.setContactPhone(firstNotBlank(request.getContactPhone(), enterprise.getAgentPhone()));
order.setContactEmail(firstNotBlank(request.getContactEmail(), enterprise.getAgentEmail()));
order.setQuantity(quantity);
order.setUnitPrice(unitPrice);
order.setTotalAmount(unitPrice.multiply(BigDecimal.valueOf(quantity)));
order.setPayMethod("WECHAT_NATIVE");
order.setPayStatus(0);
order.setOrderStatus(0);
order.setInvoiceStatus(0);
order.setTenantId(enterprise.getTenantId());
order.setDeleted(0);
hjcOrderService.save(order);
// 购买数量累加
HjcBidProject up = new HjcBidProject();
up.setId(project.getId());
up.setSaleCount((project.getSaleCount() == null ? 0 : project.getSaleCount()) + quantity);
hjcBidProjectService.updateById(up);
return success("下单成功", order);
}
@Operation(summary = "我的订单")
@GetMapping("/my")
public ApiResult<?> my() {
Integer userId = getLoginUserId();
if (userId == null) {
return fail("用户未登录");
}
HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId);
if (enterprise == null) {
return fail("企业不存在");
}
List<HjcOrder> list = hjcOrderService.list(new LambdaQueryWrapper<HjcOrder>()
.eq(HjcOrder::getEnterpriseId, enterprise.getId())
.orderByDesc(HjcOrder::getId));
return success(list);
}
@Operation(summary = "订单详情")
@GetMapping("/{id}")
public ApiResult<?> detail(@PathVariable("id") Integer id) {
HjcOrder order = hjcOrderService.getById(id);
if (order == null) {
return fail("订单不存在");
}
order.setProject(hjcBidProjectService.getById(order.getProjectId()));
return success(order);
}
@Operation(summary = "后台-订单分页")
@GetMapping("/page")
public ApiResult<PageResult<HjcOrder>> page(HjcOrderParam param) {
return success(hjcOrderService.pageRel(param));
}
private String firstNotBlank(String a, String b) {
return a != null && !a.trim().isEmpty() ? a : b;
}
}
@@ -0,0 +1,61 @@
package com.gxwebsoft.hjc.controller;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.hjc.dto.HjcOneStopProjectPush;
import com.gxwebsoft.hjc.entity.HjcOrder;
import com.gxwebsoft.hjc.service.HjcBizService;
import com.gxwebsoft.hjc.service.HjcOrderService;
import com.gxwebsoft.hjc.util.HjcOneStopAuthUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 汇吉采一站式平台双向对接
*
* 入向:POST /api/hjc/push/project —— 一站式推送标书/中标公告,对称鉴权
* 出向:手动/定时触发 createPurchaseDetails 推送订单
*/
@Tag(name = "汇吉采-一站式对接")
@RestController
@RequestMapping("/api/hjc/push")
public class HjcPushController extends BaseController {
@Resource
private HjcBizService hjcBizService;
@Resource
private HjcOrderService hjcOrderService;
@Operation(summary = "入向:接收一站式推送的标书/中标公告")
@PostMapping("/project")
public ApiResult<?> receiveProject(@RequestHeader(value = "appKey", required = false) String appKey,
@RequestHeader(value = "timestamp", required = false) String timestamp,
@RequestHeader(value = "sign", required = false) String sign,
@RequestBody HjcOneStopProjectPush push) {
if (!HjcOneStopAuthUtil.verify(appKey, timestamp, sign)) {
return fail("鉴权失败");
}
if (push == null || push.getProjectNo() == null) {
return fail("项目编号不能为空");
}
Integer tenantId = getTenantId();
if (tenantId == null) {
return fail("租户ID不能为空");
}
return success("接收成功", hjcBizService.upsertFromPush(push, tenantId));
}
@Operation(summary = "出向:手动触发订单推送(createPurchaseDetails)")
@PostMapping("/order/{orderNo}")
public ApiResult<?> triggerPush(@PathVariable("orderNo") String orderNo) {
HjcOrder order = hjcOrderService.getByOrderNo(orderNo);
if (order == null) {
return fail("订单不存在");
}
hjcBizService.pushOrderToOneStop(order);
return success("已触发推送");
}
}
@@ -0,0 +1,27 @@
package com.gxwebsoft.hjc.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 汇吉采下单请求
*/
@Data
@Schema(name = "CreateOrderRequest", description = "汇吉采下单请求")
public class CreateOrderRequest {
@Schema(description = "标书项目ID", required = true)
private Integer projectId;
@Schema(description = "购买数量", required = true)
private Integer quantity = 1;
@Schema(description = "购买联系人")
private String contactName;
@Schema(description = "购买联系电话")
private String contactPhone;
@Schema(description = "购买联系邮箱")
private String contactEmail;
}
@@ -0,0 +1,65 @@
package com.gxwebsoft.hjc.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 汇吉采 → 一站式平台:POST /api/biz/createPurchaseDetails 请求体(Q9 字段表)。
*/
@Data
@Schema(name = "CreatePurchaseDetails", description = "标书购买记录/订单推送体")
public class CreatePurchaseDetails {
@Schema(description = "幂等键")
private String idempotencyKey;
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "项目编号")
private String projectNo;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "标书单价(信息服务费)")
private BigDecimal tenderPrice;
@Schema(description = "购买数量")
private Integer quantity;
@Schema(description = "订单总额")
private BigDecimal totalAmount;
@Schema(description = "购买企业")
private Buyer buyer;
@Schema(description = "支付时间,yyyy-MM-dd HH:mm:ss")
private String paidAt;
@Schema(description = "支付方式:WECHAT_MP/ALIPAY")
private String payMethod;
@Schema(description = "状态:PAID/REFUNDED")
private String status;
@Schema(description = "开票状态:NONE/APPLIED/ISSUED")
private String invoiceStatus;
@Data
@Schema(name = "CreatePurchaseDetails.Buyer", description = "购买企业信息")
public static class Buyer {
@Schema(description = "企业名称")
private String enterpriseName;
@Schema(description = "统一社会信用代码")
private String creditCode;
@Schema(description = "经办人姓名")
private String contactName;
@Schema(description = "经办人手机号")
private String contactPhone;
@Schema(description = "经办人邮箱")
private String contactEmail;
}
}
@@ -0,0 +1,58 @@
package com.gxwebsoft.hjc.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 一站式平台 → 汇吉采:中标公告/标书推送报文。
* 对应需求字段:projectNo/projectName/tenderPrice/files/tenderOnsaleTime/tenderOffsaleTime/
* bulletinName/customerName/supplierName/bidAmount/content/fileList/needSellTender/sellingMethod
*/
@Data
@Schema(name = "HjcOneStopProjectPush", description = "一站式标书/中标公告推送报文")
public class HjcOneStopProjectPush {
@Schema(description = "是否卖标书,needSellTender")
private Integer needSellTender;
@Schema(description = "售卖方式:1公司财务 2公众号 3交易中心 4政采云")
private Integer sellingMethod;
@Schema(description = "项目编号")
private String projectNo;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "标书价格")
private BigDecimal tenderPrice;
@Schema(description = "标书附件(数组JSON或逗号分隔)")
private String files;
@Schema(description = "开售时间,yyyy-MM-dd HH:mm:ss")
private String tenderOnsaleTime;
@Schema(description = "截止时间/停售时间,yyyy-MM-dd HH:mm:ss")
private String tenderOffsaleTime;
@Schema(description = "公告标题")
private String bulletinName;
@Schema(description = "招标人")
private String customerName;
@Schema(description = "中标公司")
private String supplierName;
@Schema(description = "中标金额")
private BigDecimal bidAmount;
@Schema(description = "公告正文")
private String content;
@Schema(description = "公告附件(数组JSON或逗号分隔)")
private String fileList;
}
@@ -0,0 +1,108 @@
package com.gxwebsoft.hjc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 汇吉采标书项目(项目即标书,单表;甲方确认一个项目一本标书)
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "HjcBidProject对象", description = "汇吉采标书项目(项目即标书)")
public class HjcBidProject implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "项目编号(upsert键,一站式推送用)")
private String projectNo;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "项目分类:服务类/工程类/货物类")
private String category;
@Schema(description = "发布时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime publishTime;
@Schema(description = "投标截止时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime deadlineTime;
@Schema(description = "招标人(customerName)")
private String tenderer;
@Schema(description = "中标公司(supplierName)")
private String winnerSupplier;
@Schema(description = "中标金额(bidAmount)")
private BigDecimal bidAmount;
@Schema(description = "公告标题(bulletinName)")
private String bulletinTitle;
@Schema(description = "公告正文(content)")
private String bulletinContent;
@Schema(description = "公告附件(fileList, JSON数组字符串)")
private String bulletinFileList;
@Schema(description = "标书价格/信息服务费(tenderPrice)")
private BigDecimal tenderPrice;
@Schema(description = "标书附件(files, JSON数组字符串)")
private String tenderFile;
@Schema(description = "开售时间(tenderOnsaleTime)")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime onsaleTime;
@Schema(description = "停售时间(tenderOffsaleTime)")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime offsaleTime;
@Schema(description = "售卖方式:1公司财务 2公众号 3交易中心 4政采云")
private Integer sellingMethod;
@Schema(description = "是否卖标书(needSellTender)0否 1是")
private Integer needSell;
@Schema(description = "状态:1上架(onsale) 0下架/停售(ended)")
private Integer status;
@Schema(description = "来源:PUSH一站式推送 / MANUAL后台手工")
private String dataSource;
@Schema(description = "已售数量")
private Integer saleCount;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,90 @@
package com.gxwebsoft.hjc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
* 汇吉采企业账号与资质(关联 common.system.User
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "HjcEnterprise对象", description = "汇吉采企业账号与资质")
public class HjcEnterprise implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "关联登录用户ID(common user)")
private Integer userId;
@Schema(description = "企业名称")
private String name;
@Schema(description = "纳税人识别号/统一社会信用代码")
private String creditCode;
@Schema(description = "企业联系电话")
private String contactPhone;
@Schema(description = "企业邮箱")
private String contactEmail;
@Schema(description = "企业地址")
private String address;
@Schema(description = "经办人姓名")
private String agentName;
@Schema(description = "经办人邮箱")
private String agentEmail;
@Schema(description = "经办人手机号")
private String agentPhone;
@Schema(description = "授权委托书到期时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime authorizeExpire;
@Schema(description = "资质状态:0待审核 1已通过 2已驳回")
private Integer authStatus;
@Schema(description = "驳回原因")
private String rejectReason;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@Schema(description = "资质证件材料")
@TableField(exist = false)
private List<HjcEnterpriseMaterial> materials;
@Schema(description = "登录用户手机号(脱敏, 非DB)")
@TableField(exist = false)
private String mobile;
}
@@ -0,0 +1,55 @@
package com.gxwebsoft.hjc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 汇吉采企业资质证件材料
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "HjcEnterpriseMaterial对象", description = "汇吉采企业资质证件材料")
public class HjcEnterpriseMaterial implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "企业ID")
private Integer enterpriseId;
@Schema(description = "材料类型:idcard_front/idcard_back/handbook/license")
private String materialType;
@Schema(description = "材料名称")
private String materialName;
@Schema(description = "文件地址")
private String fileUrl;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,101 @@
package com.gxwebsoft.hjc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 汇吉采标书订单
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "HjcOrder对象", description = "汇吉采标书订单")
public class HjcOrder implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "标书项目ID")
private Integer projectId;
@Schema(description = "项目编号(冗余)")
private String projectNo;
@Schema(description = "项目名称(冗余)")
private String projectName;
@Schema(description = "购买企业ID")
private Integer enterpriseId;
@Schema(description = "购买企业名称(冗余)")
private String enterpriseName;
@Schema(description = "购买联系人")
private String contactName;
@Schema(description = "购买联系电话")
private String contactPhone;
@Schema(description = "购买联系邮箱")
private String contactEmail;
@Schema(description = "购买数量")
private Integer quantity;
@Schema(description = "单价(信息服务费)")
private BigDecimal unitPrice;
@Schema(description = "订单总额")
private BigDecimal totalAmount;
@Schema(description = "支付方式:WECHAT_NATIVE/ALIPAY")
private String payMethod;
@Schema(description = "支付时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime payTime;
@Schema(description = "支付状态:0待支付 1支付成功 2支付失败 3已退款")
private Integer payStatus;
@Schema(description = "订单状态:0待支付 1已完成 2已取消")
private Integer orderStatus;
@Schema(description = "开票状态:0未开票 1已申请 2已开票")
private Integer invoiceStatus;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@Schema(description = "标书项目")
@TableField(exist = false)
private HjcBidProject project;
}
@@ -0,0 +1,71 @@
package com.gxwebsoft.hjc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 汇吉采一站式订单推送日志(幂等+重试)
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "HjcOrderPushLog对象", description = "汇吉采一站式订单推送日志")
public class HjcOrderPushLog implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "订单ID")
private Integer orderId;
@Schema(description = "订单号(一站式幂等键)")
private String orderNo;
@Schema(description = "推送请求体(JSON)")
private String payload;
@Schema(description = "推送状态:0待推送 1成功 2失败")
private Integer pushStatus;
@Schema(description = "一站式HTTP状态码")
private Integer httpCode;
@Schema(description = "一站式返回内容")
private String responseBody;
@Schema(description = "失败原因")
private String errorMsg;
@Schema(description = "已尝试次数")
private Integer attemptCount;
@Schema(description = "下次重试时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime nextRetryTime;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,23 @@
package com.gxwebsoft.hjc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.param.HjcBidProjectParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface HjcBidProjectMapper extends BaseMapper<HjcBidProject> {
List<HjcBidProject> selectPageRel(@Param("page") IPage<HjcBidProject> page, @Param("param") HjcBidProjectParam param);
List<HjcBidProject> selectListRel(@Param("param") HjcBidProjectParam param);
/**
* 按项目编号取标书项目(忽略租户隔离,用于一站式推送 upsert)
*/
@InterceptorIgnore(tenantLine = "true")
HjcBidProject getByProjectNo(@Param("projectNo") String projectNo);
}
@@ -0,0 +1,23 @@
package com.gxwebsoft.hjc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.param.HjcEnterpriseParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface HjcEnterpriseMapper extends BaseMapper<HjcEnterprise> {
List<HjcEnterprise> selectPageRel(@Param("page") IPage<HjcEnterprise> page, @Param("param") HjcEnterpriseParam param);
List<HjcEnterprise> selectListRel(@Param("param") HjcEnterpriseParam param);
/**
* 按登录用户ID取企业(忽略租户隔离,用于登录后取企业资料)
*/
@InterceptorIgnore(tenantLine = "true")
HjcEnterprise getByUserId(@Param("userId") Integer userId);
}
@@ -0,0 +1,16 @@
package com.gxwebsoft.hjc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial;
import com.gxwebsoft.hjc.param.HjcEnterpriseMaterialParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface HjcEnterpriseMaterialMapper extends BaseMapper<HjcEnterpriseMaterial> {
List<HjcEnterpriseMaterial> selectPageRel(@Param("page") IPage<HjcEnterpriseMaterial> page, @Param("param") HjcEnterpriseMaterialParam param);
List<HjcEnterpriseMaterial> selectListRel(@Param("param") HjcEnterpriseMaterialParam param);
}
@@ -0,0 +1,23 @@
package com.gxwebsoft.hjc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.gxwebsoft.hjc.entity.HjcOrder;
import com.gxwebsoft.hjc.param.HjcOrderParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface HjcOrderMapper extends BaseMapper<HjcOrder> {
List<HjcOrder> selectPageRel(@Param("page") IPage<HjcOrder> page, @Param("param") HjcOrderParam param);
List<HjcOrder> selectListRel(@Param("param") HjcOrderParam param);
/**
* 按订单号取订单(忽略租户隔离,用于支付回调)
*/
@InterceptorIgnore(tenantLine = "true")
HjcOrder getByOrderNo(@Param("orderNo") String orderNo);
}
@@ -0,0 +1,16 @@
package com.gxwebsoft.hjc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.hjc.entity.HjcOrderPushLog;
import com.gxwebsoft.hjc.param.HjcOrderPushLogParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface HjcOrderPushLogMapper extends BaseMapper<HjcOrderPushLog> {
List<HjcOrderPushLog> selectPageRel(@Param("page") IPage<HjcOrderPushLog> page, @Param("param") HjcOrderPushLogParam param);
List<HjcOrderPushLog> selectListRel(@Param("param") HjcOrderPushLogParam param);
}
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.hjc.mapper.HjcBidProjectMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM hjc_bid_project a
<where>
<if test="param.id != null">
AND a.id = #{param.id}
</if>
<if test="param.projectNo != null">
AND a.project_no = #{param.projectNo}
</if>
<if test="param.projectName != null">
AND a.project_name LIKE CONCAT('%', #{param.projectName}, '%')
</if>
<if test="param.category != null">
AND a.category = #{param.category}
</if>
<if test="param.status != null">
AND a.status = #{param.status}
</if>
<if test="param.sellingMethod != null">
AND a.selling_method = #{param.sellingMethod}
</if>
<if test="param.needSell != null">
AND a.need_sell = #{param.needSell}
</if>
<if test="param.dataSource != null">
AND a.data_source = #{param.dataSource}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.keywords != null">
AND a.project_name LIKE CONCAT('%', #{param.keywords}, '%')
</if>
</where>
</sql>
<select id="selectPageRel" resultType="com.gxwebsoft.hjc.entity.HjcBidProject">
<include refid="selectSql"></include>
</select>
<select id="selectListRel" resultType="com.gxwebsoft.hjc.entity.HjcBidProject">
<include refid="selectSql"></include>
</select>
<select id="getByProjectNo" resultType="com.gxwebsoft.hjc.entity.HjcBidProject">
SELECT a.*
FROM hjc_bid_project a
WHERE a.project_no = #{projectNo}
LIMIT 1
</select>
</mapper>
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.hjc.mapper.HjcEnterpriseMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM hjc_enterprise a
<where>
<if test="param.id != null">
AND a.id = #{param.id}
</if>
<if test="param.userId != null">
AND a.user_id = #{param.userId}
</if>
<if test="param.name != null">
AND a.name LIKE CONCAT('%', #{param.name}, '%')
</if>
<if test="param.creditCode != null">
AND a.credit_code = #{param.creditCode}
</if>
<if test="param.authStatus != null">
AND a.auth_status = #{param.authStatus}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.keywords != null">
AND a.name LIKE CONCAT('%', #{param.keywords}, '%')
</if>
</where>
</sql>
<select id="selectPageRel" resultType="com.gxwebsoft.hjc.entity.HjcEnterprise">
<include refid="selectSql"></include>
</select>
<select id="selectListRel" resultType="com.gxwebsoft.hjc.entity.HjcEnterprise">
<include refid="selectSql"></include>
</select>
<select id="getByUserId" resultType="com.gxwebsoft.hjc.entity.HjcEnterprise">
SELECT a.*
FROM hjc_enterprise a
WHERE a.user_id = #{userId}
LIMIT 1
</select>
</mapper>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.hjc.mapper.HjcEnterpriseMaterialMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM hjc_enterprise_material a
<where>
<if test="param.id != null">
AND a.id = #{param.id}
</if>
<if test="param.enterpriseId != null">
AND a.enterprise_id = #{param.enterpriseId}
</if>
<if test="param.materialType != null">
AND a.material_type = #{param.materialType}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
</where>
</sql>
<select id="selectPageRel" resultType="com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial">
<include refid="selectSql"></include>
</select>
<select id="selectListRel" resultType="com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial">
<include refid="selectSql"></include>
</select>
</mapper>
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.hjc.mapper.HjcOrderMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM hjc_order a
<where>
<if test="param.id != null">
AND a.id = #{param.id}
</if>
<if test="param.orderNo != null">
AND a.order_no = #{param.orderNo}
</if>
<if test="param.projectId != null">
AND a.project_id = #{param.projectId}
</if>
<if test="param.projectNo != null">
AND a.project_no = #{param.projectNo}
</if>
<if test="param.enterpriseId != null">
AND a.enterprise_id = #{param.enterpriseId}
</if>
<if test="param.projectName != null">
AND a.project_name LIKE CONCAT('%', #{param.projectName}, '%')
</if>
<if test="param.payStatus != null">
AND a.pay_status = #{param.payStatus}
</if>
<if test="param.orderStatus != null">
AND a.order_status = #{param.orderStatus}
</if>
<if test="param.payMethod != null">
AND a.pay_method = #{param.payMethod}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.keywords != null">
AND a.project_name LIKE CONCAT('%', #{param.keywords}, '%')
</if>
</where>
</sql>
<select id="selectPageRel" resultType="com.gxwebsoft.hjc.entity.HjcOrder">
<include refid="selectSql"></include>
</select>
<select id="selectListRel" resultType="com.gxwebsoft.hjc.entity.HjcOrder">
<include refid="selectSql"></include>
</select>
<select id="getByOrderNo" resultType="com.gxwebsoft.hjc.entity.HjcOrder">
SELECT a.*
FROM hjc_order a
WHERE a.order_no = #{orderNo}
LIMIT 1
</select>
</mapper>
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.hjc.mapper.HjcOrderPushLogMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM hjc_order_push_log a
<where>
<if test="param.id != null">
AND a.id = #{param.id}
</if>
<if test="param.orderId != null">
AND a.order_id = #{param.orderId}
</if>
<if test="param.orderNo != null">
AND a.order_no = #{param.orderNo}
</if>
<if test="param.pushStatus != null">
AND a.push_status = #{param.pushStatus}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
</where>
</sql>
<select id="selectPageRel" resultType="com.gxwebsoft.hjc.entity.HjcOrderPushLog">
<include refid="selectSql"></include>
</select>
<select id="selectListRel" resultType="com.gxwebsoft.hjc.entity.HjcOrderPushLog">
<include refid="selectSql"></include>
</select>
</mapper>
@@ -0,0 +1,45 @@
package com.gxwebsoft.hjc.param;
import com.gxwebsoft.common.core.annotation.QueryField;
import com.gxwebsoft.common.core.annotation.QueryType;
import com.gxwebsoft.common.core.web.BaseParam;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 汇吉采标书项目查询参数
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(name = "HjcBidProjectParam对象", description = "汇吉采标书项目查询参数")
public class HjcBidProjectParam extends BaseParam {
@QueryField(type = QueryType.EQ)
private Integer id;
@QueryField(type = QueryType.EQ)
private String projectNo;
@QueryField(type = QueryType.LIKE)
private String projectName;
@QueryField(type = QueryType.EQ)
private String category;
@QueryField(type = QueryType.EQ)
private Integer status;
@QueryField(type = QueryType.EQ)
private Integer sellingMethod;
@QueryField(type = QueryType.EQ)
private Integer needSell;
@QueryField(type = QueryType.EQ)
private String dataSource;
}
@@ -0,0 +1,30 @@
package com.gxwebsoft.hjc.param;
import com.gxwebsoft.common.core.annotation.QueryField;
import com.gxwebsoft.common.core.annotation.QueryType;
import com.gxwebsoft.common.core.web.BaseParam;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 汇吉采企业资质证件材料查询参数
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(name = "HjcEnterpriseMaterialParam对象", description = "汇吉采企业资质证件材料查询参数")
public class HjcEnterpriseMaterialParam extends BaseParam {
@QueryField(type = QueryType.EQ)
private Integer id;
@QueryField(type = QueryType.EQ)
private Integer enterpriseId;
@QueryField(type = QueryType.EQ)
private String materialType;
}
@@ -0,0 +1,36 @@
package com.gxwebsoft.hjc.param;
import com.gxwebsoft.common.core.annotation.QueryField;
import com.gxwebsoft.common.core.annotation.QueryType;
import com.gxwebsoft.common.core.web.BaseParam;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 汇吉采企业账号与资质查询参数
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(name = "HjcEnterpriseParam对象", description = "汇吉采企业账号与资质查询参数")
public class HjcEnterpriseParam extends BaseParam {
@QueryField(type = QueryType.EQ)
private Integer id;
@QueryField(type = QueryType.EQ)
private Integer userId;
@QueryField(type = QueryType.LIKE)
private String name;
@QueryField(type = QueryType.EQ)
private String creditCode;
@QueryField(type = QueryType.EQ)
private Integer authStatus;
}
@@ -0,0 +1,48 @@
package com.gxwebsoft.hjc.param;
import com.gxwebsoft.common.core.annotation.QueryField;
import com.gxwebsoft.common.core.annotation.QueryType;
import com.gxwebsoft.common.core.web.BaseParam;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 汇吉采标书订单查询参数
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(name = "HjcOrderParam对象", description = "汇吉采标书订单查询参数")
public class HjcOrderParam extends BaseParam {
@QueryField(type = QueryType.EQ)
private Integer id;
@QueryField(type = QueryType.EQ)
private String orderNo;
@QueryField(type = QueryType.EQ)
private Integer projectId;
@QueryField(type = QueryType.EQ)
private String projectNo;
@QueryField(type = QueryType.EQ)
private Integer enterpriseId;
@QueryField(type = QueryType.LIKE)
private String projectName;
@QueryField(type = QueryType.EQ)
private Integer payStatus;
@QueryField(type = QueryType.EQ)
private Integer orderStatus;
@QueryField(type = QueryType.EQ)
private String payMethod;
}
@@ -0,0 +1,33 @@
package com.gxwebsoft.hjc.param;
import com.gxwebsoft.common.core.annotation.QueryField;
import com.gxwebsoft.common.core.annotation.QueryType;
import com.gxwebsoft.common.core.web.BaseParam;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 汇吉采一站式订单推送日志查询参数
*
* @author WebSoft
*/
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(name = "HjcOrderPushLogParam对象", description = "汇吉采一站式订单推送日志查询参数")
public class HjcOrderPushLogParam extends BaseParam {
@QueryField(type = QueryType.EQ)
private Integer id;
@QueryField(type = QueryType.EQ)
private Integer orderId;
@QueryField(type = QueryType.EQ)
private String orderNo;
@QueryField(type = QueryType.EQ)
private Integer pushStatus;
}
@@ -0,0 +1,17 @@
package com.gxwebsoft.hjc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.param.HjcBidProjectParam;
import java.util.List;
public interface HjcBidProjectService extends IService<HjcBidProject> {
PageResult<HjcBidProject> pageRel(HjcBidProjectParam param);
List<HjcBidProject> listRel(HjcBidProjectParam param);
HjcBidProject getByProjectNo(String projectNo);
}
@@ -0,0 +1,23 @@
package com.gxwebsoft.hjc.service;
import com.gxwebsoft.hjc.dto.HjcOneStopProjectPush;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.entity.HjcOrder;
public interface HjcBizService {
/**
* 入向:一站式推送标书/中标公告 → 按 projectNo upsert 标书项目
*/
HjcBidProject upsertFromPush(HjcOneStopProjectPush push, Integer tenantId);
/**
* 出向:推送订单到一站式 createPurchaseDetails,写推送日志(幂等+重试)
*/
void pushOrderToOneStop(HjcOrder order);
/**
* 重试失败的推送(幂等)
*/
void retryPendingPush();
}
@@ -0,0 +1,15 @@
package com.gxwebsoft.hjc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial;
import com.gxwebsoft.hjc.param.HjcEnterpriseMaterialParam;
import java.util.List;
public interface HjcEnterpriseMaterialService extends IService<HjcEnterpriseMaterial> {
PageResult<HjcEnterpriseMaterial> pageRel(HjcEnterpriseMaterialParam param);
List<HjcEnterpriseMaterial> listRel(HjcEnterpriseMaterialParam param);
}
@@ -0,0 +1,17 @@
package com.gxwebsoft.hjc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.param.HjcEnterpriseParam;
import java.util.List;
public interface HjcEnterpriseService extends IService<HjcEnterprise> {
PageResult<HjcEnterprise> pageRel(HjcEnterpriseParam param);
List<HjcEnterprise> listRel(HjcEnterpriseParam param);
HjcEnterprise getByUserId(Integer userId);
}
@@ -0,0 +1,15 @@
package com.gxwebsoft.hjc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcOrderPushLog;
import com.gxwebsoft.hjc.param.HjcOrderPushLogParam;
import java.util.List;
public interface HjcOrderPushLogService extends IService<HjcOrderPushLog> {
PageResult<HjcOrderPushLog> pageRel(HjcOrderPushLogParam param);
List<HjcOrderPushLog> listRel(HjcOrderPushLogParam param);
}
@@ -0,0 +1,17 @@
package com.gxwebsoft.hjc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcOrder;
import com.gxwebsoft.hjc.param.HjcOrderParam;
import java.util.List;
public interface HjcOrderService extends IService<HjcOrder> {
PageResult<HjcOrder> pageRel(HjcOrderParam param);
List<HjcOrder> listRel(HjcOrderParam param);
HjcOrder getByOrderNo(String orderNo);
}
@@ -0,0 +1,34 @@
package com.gxwebsoft.hjc.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.mapper.HjcBidProjectMapper;
import com.gxwebsoft.hjc.param.HjcBidProjectParam;
import com.gxwebsoft.hjc.service.HjcBidProjectService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class HjcBidProjectServiceImpl extends ServiceImpl<HjcBidProjectMapper, HjcBidProject> implements HjcBidProjectService {
@Override
public PageResult<HjcBidProject> pageRel(HjcBidProjectParam param) {
PageParam<HjcBidProject, HjcBidProjectParam> page = new PageParam<>(param);
page.setDefaultOrder("id desc");
List<HjcBidProject> list = baseMapper.selectPageRel(page, param);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<HjcBidProject> listRel(HjcBidProjectParam param) {
return baseMapper.selectListRel(param);
}
@Override
public HjcBidProject getByProjectNo(String projectNo) {
return baseMapper.getByProjectNo(projectNo);
}
}
@@ -0,0 +1,228 @@
package com.gxwebsoft.hjc.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gxwebsoft.hjc.dto.CreatePurchaseDetails;
import com.gxwebsoft.hjc.dto.HjcOneStopProjectPush;
import com.gxwebsoft.hjc.entity.HjcBidProject;
import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.entity.HjcOrder;
import com.gxwebsoft.hjc.entity.HjcOrderPushLog;
import com.gxwebsoft.hjc.service.HjcBidProjectService;
import com.gxwebsoft.hjc.service.HjcBizService;
import com.gxwebsoft.hjc.service.HjcEnterpriseService;
import com.gxwebsoft.hjc.service.HjcOrderService;
import com.gxwebsoft.hjc.service.HjcOrderPushLogService;
import com.gxwebsoft.hjc.util.HjcOneStopAuthUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
* 汇吉采一站式双向对接业务
*/
@Service
public class HjcBizServiceImpl implements HjcBizService {
private static final DateTimeFormatter DT_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final String STATUS_PAID = "PAID";
private static final String STATUS_REFUNDED = "REFUNDED";
@Value("${hjc.one-stop.base-url:}")
private String oneStopBaseUrl;
@Value("${hjc.one-stop.create-purchase-details-path:/api/biz/createPurchaseDetails}")
private String createPurchaseDetailsPath;
@Resource
private HjcBidProjectService hjcBidProjectService;
@Resource
private HjcEnterpriseService hjcEnterpriseService;
@Resource
private HjcOrderService hjcOrderService;
@Resource
private HjcOrderPushLogService hjcOrderPushLogService;
@Resource
private RestTemplate restTemplate;
@Resource
private ObjectMapper objectMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public HjcBidProject upsertFromPush(HjcOneStopProjectPush push, Integer tenantId) {
HjcBidProject project = hjcBidProjectService.getByProjectNo(push.getProjectNo());
boolean isNew = project == null;
if (isNew) {
project = new HjcBidProject();
project.setProjectNo(push.getProjectNo());
project.setTenantId(tenantId);
project.setSaleCount(0);
project.setDataSource("PUSH");
project.setStatus(1);
}
project.setProjectName(push.getProjectName());
project.setTenderer(push.getCustomerName());
project.setWinnerSupplier(push.getSupplierName());
project.setBidAmount(push.getBidAmount());
project.setBulletinTitle(push.getBulletinName());
project.setBulletinContent(push.getContent());
project.setBulletinFileList(push.getFileList());
project.setTenderPrice(push.getTenderPrice());
project.setTenderFile(push.getFiles());
project.setOnsaleTime(parseDateTime(push.getTenderOnsaleTime()));
project.setOffsaleTime(parseDateTime(push.getTenderOffsaleTime()));
project.setSellingMethod(push.getSellingMethod());
project.setNeedSell(push.getNeedSellTender());
project.setDataSource("PUSH");
if (isNew) {
hjcBidProjectService.save(project);
} else {
hjcBidProjectService.updateById(project);
}
return project;
}
@Override
public void pushOrderToOneStop(HjcOrder order) {
if (order == null || StrUtil.isBlank(order.getOrderNo())) {
return;
}
HjcOrderPushLog logEntity = new HjcOrderPushLog();
logEntity.setOrderId(order.getId());
logEntity.setOrderNo(order.getOrderNo());
logEntity.setTenantId(order.getTenantId());
logEntity.setPushStatus(0);
logEntity.setAttemptCount(0);
hjcOrderPushLogService.save(logEntity);
doPush(order, logEntity);
}
@Override
public void retryPendingPush() {
List<HjcOrderPushLog> pending = hjcOrderPushLogService.list(new LambdaQueryWrapper<HjcOrderPushLog>()
.in(HjcOrderPushLog::getPushStatus, 0, 2)
.and(w -> w.isNull(HjcOrderPushLog::getNextRetryTime)
.or().le(HjcOrderPushLog::getNextRetryTime, LocalDateTime.now()))
.last("limit 50"));
for (HjcOrderPushLog logEntity : pending) {
HjcOrder order = hjcOrderService.getByOrderNo(logEntity.getOrderNo());
if (order != null) {
doPush(order, logEntity);
}
}
}
private void doPush(HjcOrder order, HjcOrderPushLog logEntity) {
try {
CreatePurchaseDetails body = buildCreatePurchaseDetails(order);
String payload = objectMapper.writeValueAsString(body);
String ts = HjcOneStopAuthUtil.timestamp();
String sign = HjcOneStopAuthUtil.sign(ts);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("appKey", HjcOneStopAuthUtil.APP_KEY);
headers.set("timestamp", ts);
headers.set("sign", sign);
String url = oneStopBaseUrl + createPurchaseDetailsPath;
ResponseEntity<String> resp = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), String.class);
logEntity.setPayload(payload);
logEntity.setAttemptCount(logEntity.getAttemptCount() + 1);
logEntity.setHttpCode(resp.getStatusCode().value());
logEntity.setResponseBody(limitStr(resp.getBody(), 3000));
if (resp.getStatusCode().is2xxSuccessful()) {
logEntity.setPushStatus(1);
logEntity.setErrorMsg(null);
logEntity.setNextRetryTime(null);
} else {
logEntity.setPushStatus(2);
logEntity.setErrorMsg("HTTP " + resp.getStatusCode().value());
logEntity.setNextRetryTime(LocalDateTime.now().plusMinutes(30));
}
} catch (Exception e) {
logEntity.setAttemptCount(logEntity.getAttemptCount() + 1);
logEntity.setPushStatus(2);
logEntity.setErrorMsg(limitStr(e.getMessage(), 1000));
logEntity.setNextRetryTime(LocalDateTime.now().plusMinutes(30));
}
hjcOrderPushLogService.updateById(logEntity);
}
private CreatePurchaseDetails buildCreatePurchaseDetails(HjcOrder order) {
CreatePurchaseDetails body = new CreatePurchaseDetails();
body.setIdempotencyKey("HJC_ORD_" + order.getOrderNo());
body.setOrderNo(order.getOrderNo());
body.setProjectNo(order.getProjectNo());
body.setProjectName(order.getProjectName());
body.setTenderPrice(order.getUnitPrice());
body.setQuantity(order.getQuantity());
body.setTotalAmount(order.getTotalAmount());
body.setPaidAt(order.getPayTime() == null ? null : order.getPayTime().format(DT_FMT));
body.setPayMethod(order.getPayMethod());
body.setStatus(order.getPayStatus() != null && order.getPayStatus() == 3 ? STATUS_REFUNDED : STATUS_PAID);
body.setInvoiceStatus(invoiceStatus(order.getInvoiceStatus()));
CreatePurchaseDetails.Buyer buyer = new CreatePurchaseDetails.Buyer();
buyer.setEnterpriseName(order.getEnterpriseName());
buyer.setContactName(order.getContactName());
buyer.setContactPhone(order.getContactPhone());
buyer.setContactEmail(order.getContactEmail());
if (order.getEnterpriseId() != null) {
HjcEnterprise enterprise = hjcEnterpriseService.getById(order.getEnterpriseId());
if (enterprise != null) {
buyer.setCreditCode(enterprise.getCreditCode());
}
}
body.setBuyer(buyer);
return body;
}
private String invoiceStatus(Integer invoiceStatus) {
if (invoiceStatus == null) {
return "NONE";
}
switch (invoiceStatus) {
case 1: return "APPLIED";
case 2: return "ISSUED";
default: return "NONE";
}
}
private LocalDateTime parseDateTime(String text) {
if (StrUtil.isBlank(text)) {
return null;
}
String t = text.trim();
try {
if (t.length() == 14) {
return LocalDateTime.parse(t, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
if (t.contains("T")) {
return LocalDateTime.parse(t);
}
return LocalDateTime.parse(t, DT_FMT);
} catch (Exception e) {
return null;
}
}
private String limitStr(String s, int max) {
if (s == null) {
return null;
}
return s.length() > max ? s.substring(0, max) : s;
}
}
@@ -0,0 +1,29 @@
package com.gxwebsoft.hjc.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial;
import com.gxwebsoft.hjc.mapper.HjcEnterpriseMaterialMapper;
import com.gxwebsoft.hjc.param.HjcEnterpriseMaterialParam;
import com.gxwebsoft.hjc.service.HjcEnterpriseMaterialService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class HjcEnterpriseMaterialServiceImpl extends ServiceImpl<HjcEnterpriseMaterialMapper, HjcEnterpriseMaterial> implements HjcEnterpriseMaterialService {
@Override
public PageResult<HjcEnterpriseMaterial> pageRel(HjcEnterpriseMaterialParam param) {
PageParam<HjcEnterpriseMaterial, HjcEnterpriseMaterialParam> page = new PageParam<>(param);
page.setDefaultOrder("id desc");
List<HjcEnterpriseMaterial> list = baseMapper.selectPageRel(page, param);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<HjcEnterpriseMaterial> listRel(HjcEnterpriseMaterialParam param) {
return baseMapper.selectListRel(param);
}
}
@@ -0,0 +1,34 @@
package com.gxwebsoft.hjc.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.mapper.HjcEnterpriseMapper;
import com.gxwebsoft.hjc.param.HjcEnterpriseParam;
import com.gxwebsoft.hjc.service.HjcEnterpriseService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class HjcEnterpriseServiceImpl extends ServiceImpl<HjcEnterpriseMapper, HjcEnterprise> implements HjcEnterpriseService {
@Override
public PageResult<HjcEnterprise> pageRel(HjcEnterpriseParam param) {
PageParam<HjcEnterprise, HjcEnterpriseParam> page = new PageParam<>(param);
page.setDefaultOrder("id desc");
List<HjcEnterprise> list = baseMapper.selectPageRel(page, param);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<HjcEnterprise> listRel(HjcEnterpriseParam param) {
return baseMapper.selectListRel(param);
}
@Override
public HjcEnterprise getByUserId(Integer userId) {
return baseMapper.getByUserId(userId);
}
}
@@ -0,0 +1,29 @@
package com.gxwebsoft.hjc.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcOrderPushLog;
import com.gxwebsoft.hjc.mapper.HjcOrderPushLogMapper;
import com.gxwebsoft.hjc.param.HjcOrderPushLogParam;
import com.gxwebsoft.hjc.service.HjcOrderPushLogService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class HjcOrderPushLogServiceImpl extends ServiceImpl<HjcOrderPushLogMapper, HjcOrderPushLog> implements HjcOrderPushLogService {
@Override
public PageResult<HjcOrderPushLog> pageRel(HjcOrderPushLogParam param) {
PageParam<HjcOrderPushLog, HjcOrderPushLogParam> page = new PageParam<>(param);
page.setDefaultOrder("id desc");
List<HjcOrderPushLog> list = baseMapper.selectPageRel(page, param);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<HjcOrderPushLog> listRel(HjcOrderPushLogParam param) {
return baseMapper.selectListRel(param);
}
}
@@ -0,0 +1,34 @@
package com.gxwebsoft.hjc.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.hjc.entity.HjcOrder;
import com.gxwebsoft.hjc.mapper.HjcOrderMapper;
import com.gxwebsoft.hjc.param.HjcOrderParam;
import com.gxwebsoft.hjc.service.HjcOrderService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class HjcOrderServiceImpl extends ServiceImpl<HjcOrderMapper, HjcOrder> implements HjcOrderService {
@Override
public PageResult<HjcOrder> pageRel(HjcOrderParam param) {
PageParam<HjcOrder, HjcOrderParam> page = new PageParam<>(param);
page.setDefaultOrder("id desc");
List<HjcOrder> list = baseMapper.selectPageRel(page, param);
return new PageResult<>(list, page.getTotal());
}
@Override
public List<HjcOrder> listRel(HjcOrderParam param) {
return baseMapper.selectListRel(param);
}
@Override
public HjcOrder getByOrderNo(String orderNo) {
return baseMapper.getByOrderNo(orderNo);
}
}
@@ -0,0 +1,53 @@
package com.gxwebsoft.hjc.util;
import cn.hutool.crypto.SecureUtil;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* 汇吉采 → 一站式平台 推送鉴权工具。
* 规则:sign = MD5(appKey + password + timestamp)timestamp = yyyyMMddHHmm(北京时)。
* 详见 mp-java/docs/一站式平台推送-接口鉴权规范.md
*/
public final class HjcOneStopAuthUtil {
public static final String APP_KEY = "HJC_Official_Website";
public static final String PASSWORD = "vQ8$kR3#mW6@xP2!nF";
private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
private HjcOneStopAuthUtil() {
}
/** 当前北京时间,yyyyMMddHHmm */
public static String timestamp() {
return LocalDateTime.now().format(FMT);
}
/** 计算签名 sign = MD5(appKey + password + timestamp),小写 32 位 */
public static String sign(String timestamp) {
return SecureUtil.md5(APP_KEY + PASSWORD + timestamp);
}
/** 校验请求头中的 sign 是否符合 appKey/password/timestamp 约定 */
public static boolean verify(String appKey, String timestamp, String sign) {
if (appKey == null || timestamp == null || sign == null) {
return false;
}
if (!APP_KEY.equals(appKey)) {
return false;
}
// 时间窗口 ±10 分钟,防重放
LocalDateTime ts;
try {
ts = LocalDateTime.parse(timestamp, FMT);
} catch (Exception e) {
return false;
}
if (Math.abs(java.time.Duration.between(ts, LocalDateTime.now()).toMinutes()) > 10) {
return false;
}
return sign.equalsIgnoreCase(sign(timestamp));
}
}
+7
View File
@@ -182,3 +182,10 @@ house:
url: "https://mcp.amap.com/mcp?key=7fb25e6f0dbf19ff947ba6366b11a478" url: "https://mcp.amap.com/mcp?key=7fb25e6f0dbf19ff947ba6366b11a478"
timeout-ms: 20000 timeout-ms: 20000
tool-cache-ttl-ms: 300000 tool-cache-ttl-ms: 300000
# 汇吉采一站式平台对接
hjc:
one-stop:
# 一站式平台地址(+ path = 最终推送地址)。base-url 为空时推送不会发起,部署时需配置。
base-url: ""
create-purchase-details-path: /api/biz/createPurchaseDetails
+137
View File
@@ -0,0 +1,137 @@
-- ============================================================
-- 汇吉采标书购买平台 初始化 DDL (mp-api / com.gxwebsoft.hjc)
-- 约定:engine=InnoDB, charset=utf8mb4, 主键 id int 自增
-- 公共列 tenant_id / deleted / create_time / update_time
-- 说明:项目与标书为同一实体(甲方确认一个项目一本标书),单表 hjc_bid_project。
-- ============================================================
-- ---------- 项目/标书(单一实体:项目即标书) ----------
CREATE TABLE `hjc_bid_project` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`project_no` varchar(64) NOT NULL COMMENT '项目编号(upsert 键,一站式推送用)',
`project_name` varchar(255) NOT NULL COMMENT '项目名称',
`category` varchar(32) DEFAULT NULL COMMENT '项目分类:服务类/工程类/货物类',
`publish_time` datetime DEFAULT NULL COMMENT '发布时间',
`deadline_time` datetime DEFAULT NULL COMMENT '投标截止时间',
`tenderer` varchar(128) DEFAULT NULL COMMENT '招标人(customerName)',
`winner_supplier` varchar(128) DEFAULT NULL COMMENT '中标公司(supplierName)',
`bid_amount` decimal(18,2) DEFAULT NULL COMMENT '中标金额(bidAmount)',
`bulletin_title` varchar(255) DEFAULT NULL COMMENT '公告标题(bulletinName)',
`bulletin_content` text COMMENT '公告正文(content)',
`bulletin_file_list` text COMMENT '公告附件(fileList, JSON数组字符串)',
`tender_price` decimal(18,2) DEFAULT NULL COMMENT '标书价格/信息服务费(tenderPrice)',
`tender_file` text COMMENT '标书附件(files, JSON数组字符串)',
`onsale_time` datetime DEFAULT NULL COMMENT '开售时间(tenderOnsaleTime)',
`offsale_time` datetime DEFAULT NULL COMMENT '停售时间(tenderOffsaleTime)',
`selling_method` tinyint(4) DEFAULT NULL COMMENT '售卖方式:1公司财务 2公众号 3交易中心 4政采云',
`need_sell` tinyint(1) DEFAULT 0 COMMENT '是否卖标书(needSellTender)0否 1是',
`status` tinyint(4) DEFAULT 1 COMMENT '状态:1上架(onsale) 0下架/停售(ended)',
`data_source` varchar(16) DEFAULT 'MANUAL' COMMENT '来源:PUSH一站式推送 / MANUAL后台手工',
`sale_count` int(11) DEFAULT 0 COMMENT '已售数量',
`tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
`deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_hjc_bp_project_no` (`project_no`),
KEY `idx_hjc_bp_status` (`status`),
KEY `idx_hjc_bp_category` (`category`),
KEY `idx_hjc_bp_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采标书项目(项目即标书,单表)';
-- ---------- 企业账号(关联 common.system.user ----------
CREATE TABLE `hjc_enterprise` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int(11) NOT NULL COMMENT '关联登录用户ID(common user)',
`name` varchar(255) NOT NULL COMMENT '企业名称',
`credit_code` varchar(64) DEFAULT NULL COMMENT '纳税人识别号/统一社会信用代码',
`contact_phone` varchar(32) DEFAULT NULL COMMENT '企业联系电话',
`contact_email` varchar(128) DEFAULT NULL COMMENT '企业邮箱',
`address` varchar(255) DEFAULT NULL COMMENT '企业地址',
`agent_name` varchar(64) DEFAULT NULL COMMENT '经办人姓名',
`agent_email` varchar(128) DEFAULT NULL COMMENT '经办人邮箱',
`agent_phone` varchar(32) DEFAULT NULL COMMENT '经办人手机号',
`authorize_expire` datetime DEFAULT NULL COMMENT '授权委托书到期时间',
`auth_status` tinyint(4) DEFAULT 0 COMMENT '资质状态:0待审核 1已通过 2已驳回',
`reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因',
`tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
`deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_hjc_ent_user` (`user_id`),
KEY `idx_hjc_ent_credit` (`credit_code`),
KEY `idx_hjc_ent_auth` (`auth_status`),
KEY `idx_hjc_ent_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采企业账号与资质';
-- ---------- 企业资质证件材料 ----------
CREATE TABLE `hjc_enterprise_material` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`enterprise_id` int(11) NOT NULL COMMENT '企业ID',
`material_type` varchar(32) NOT NULL COMMENT '材料类型:idcard_front/idcard_back/handbook/license',
`material_name` varchar(128) DEFAULT NULL COMMENT '材料名称',
`file_url` varchar(500) NOT NULL COMMENT '文件地址',
`tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
`deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_hjc_entm_ent` (`enterprise_id`),
KEY `idx_hjc_entm_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采企业资质证件材料';
-- ---------- 标书订单 ----------
CREATE TABLE `hjc_order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_no` varchar(64) NOT NULL COMMENT '订单号',
`project_id` int(11) NOT NULL COMMENT '标书项目ID',
`project_no` varchar(64) DEFAULT NULL COMMENT '项目编号(冗余)',
`project_name` varchar(255) DEFAULT NULL COMMENT '项目名称(冗余)',
`enterprise_id` int(11) NOT NULL COMMENT '购买企业ID',
`enterprise_name` varchar(255) DEFAULT NULL COMMENT '购买企业名称(冗余)',
`contact_name` varchar(64) DEFAULT NULL COMMENT '购买联系人',
`contact_phone` varchar(32) DEFAULT NULL COMMENT '购买联系电话',
`contact_email` varchar(128) DEFAULT NULL COMMENT '购买联系邮箱',
`quantity` int(11) DEFAULT 1 COMMENT '购买数量',
`unit_price` decimal(18,2) DEFAULT NULL COMMENT '单价(信息服务费)',
`total_amount` decimal(18,2) DEFAULT NULL COMMENT '订单总额',
`pay_method` varchar(32) DEFAULT NULL COMMENT '支付方式:WECHAT_NATIVE/ALIPAY',
`pay_time` datetime DEFAULT NULL COMMENT '支付时间',
`pay_status` tinyint(4) DEFAULT 0 COMMENT '支付状态:0待支付 1支付成功 2支付失败 3已退款',
`order_status` tinyint(4) DEFAULT 0 COMMENT '订单状态:0待支付 1已完成 2已取消',
`invoice_status` tinyint(4) DEFAULT 0 COMMENT '开票状态:0未开票 1已申请 2已开票',
`tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
`deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_hjc_order_no` (`order_no`),
KEY `idx_hjc_order_user` (`enterprise_id`),
KEY `idx_hjc_order_project` (`project_id`),
KEY `idx_hjc_order_pay` (`pay_status`),
KEY `idx_hjc_order_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采标书订单';
-- ---------- 一站式出向推送日志(幂等+重试) ----------
CREATE TABLE `hjc_order_push_log` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_id` int(11) NOT NULL COMMENT '订单ID',
`order_no` varchar(64) NOT NULL COMMENT '订单号(一站式幂等键)',
`payload` text COMMENT '推送请求体(JSON)',
`push_status` tinyint(4) DEFAULT 0 COMMENT '推送状态:0待推送 1成功 2失败',
`http_code` int(11) DEFAULT NULL COMMENT '一站式HTTP状态码',
`response_body` text COMMENT '一站式返回内容',
`error_msg` varchar(1000) DEFAULT NULL COMMENT '失败原因',
`attempt_count` int(11) DEFAULT 0 COMMENT '已尝试次数',
`next_retry_time` datetime DEFAULT NULL COMMENT '下次重试时间',
`tenant_id` int(11) DEFAULT NULL COMMENT '租户ID',
`deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_hjc_push_order` (`order_id`),
KEY `idx_hjc_push_order_no` (`order_no`),
KEY `idx_hjc_push_status` (`push_status`),
KEY `idx_hjc_push_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采一站式订单推送日志';