Commit Graph

383 Commits

Author SHA1 Message Date
weicw1996 0bc66b5808 feat(hjc): 已支付订单下发标书附件,并堵住项目接口的标书地址泄露
「购买后才能下载标书」此前在服务端从未成立:`GET /api/hjc/bid-project/{id}` 与 `/list`
匿名即可拿到 `tenderFile`,订单详情也会回带 `project.tenderFile`;而订单列表接口
(`/hjc/order/my`)根本不带附件,PC 端连下载入口都没有。

- 新增 `HjcTenderFileUtil` + `HjcTenderFileVo`:把 `tender_file`(一站式推的 `files`:
  JSON 字符串数组 / 对象数组 / 逗号分隔)解析成 `{name,url}`;坏数据只丢弃、不抛异常
- `HjcOrder` 加非表字段 `tenderFiles`;`/hjc/order/my` 与 `/hjc/order/{id}` **只有
  `payStatus == 1`** 才附带(列表整批一次 `listByIds`,不 N+1;其余订单保持 null)
- 订单详情的 `project.tenderFile` 恒置 null:订单路径不留第二条地址来源
- `/hjc/bid-project/list` 一律不下发 `tenderFile`;`/hjc/bid-project/{id}` 仅 hjc 管理员
  (后台编辑表单要回填)或已为本项目付过款的买家可见,其余置 null,且**不返回 401**
  (详情对未登录是正常可用页面)
- 单测:`HjcTenderFileUtilTest`(12)、`HjcOrderControllerTenderFilesTest`(8)、
  `HjcBidProjectControllerDetailTest` 扩展 5 条(含既有 favorited/buyerCount 不回归)
  → `com.gxwebsoft.hjc.**` 共 147 条全通过

规格与验收:`.scratch/hjc-tender-download/`;两端前端同批改动见 hjc-web 2e847b5、hjc-h5 5412485
2026-09-17 18:09:50 +08:00
weicw1996 6d8185cc70 feat(hjc): 标书项目收藏:详情页收藏态 + 我的收藏
收藏归属**企业账号**(hjc_enterprise.id,全企业共享一份,ADR 0011),
且**不需要资质**——未认证/待审核/已驳回的企业都能收藏,资质只卡购买。

- 新表 hjc_project_favorite(enterprise_id, project_id, tenant_id, create_time,
  update_time),唯一键 (enterprise_id, project_id) 保证幂等;
  **没有 deleted 列**:取消收藏即物理删除(ADR 0012,先例 project_collection)。
- 接口:POST /api/hjc/project-favorite(幂等,并发撞唯一键按成功处理)、
  DELETE /{projectId}(幂等)、GET /page(我的收藏,收藏时间倒序)。
- 我的收藏每条由后端算好 saleState(onsale / ended / removed)与 purchased,
  口径只写一份;项目被下架或删除后**条目仍在**(LEFT JOIN 上刻意不加 b.deleted = 0),
  以「已下架」呈现而不是让收藏凭空消失。
- 标书详情内联 favorited(非表字段,未登录恒 false,不返回 401);
  purchased 复用「购买人数」的已付款口径。
- 排序:客户端排序**一律丢弃**。已在 dev 库实测:放行 ?sort=tenantId / ?sort=updateTime
  会得到「Column 'tenant_id' in order clause is ambiguous」的 500;而放行 ?sort=id
  更隐蔽——它不报错,只是把收藏时间倒序悄悄换成按 a.id 排。
- 单测 35 项:展示态判定、详情内联(未登录不得 401)、幂等、排序覆盖、
  越权覆盖(param.enterpriseId 强制覆盖)。
2026-09-17 04:07:36 +08:00
weicw1996 13cb08621f feat(hjc): 买家可取消待支付订单;标书详情「购买人数」改实时统计
取消订单(POST /api/hjc/order/cancel,幂等):
- 先向微信查单。SUCCESS 则**拒绝取消**并就地 markPaid 自愈(ADR 0009 的「以微信侧为准」);
  这是唯一能挡住「其实已付款、只是前端没送达」的时机
- 否则条件更新 order_status=2:
  UPDATE ... WHERE order_no=? AND pay_status=0 AND order_status=0
  靠**影响行数**保证幂等与安全,故新增 XML <update>——updateById 那条路拿不到行数
- 再尽力 closeOrder 关掉微信侧那张支付单,避免「已取消却仍能付款」;失败只记日志、不回滚
- 查单异常时仍放行取消,但响应带 verified=false,如实告知「未与微信核对」,不替微信下结论
- 响应恒 code=0 + 结构化 data{cancelled,paid,verified,payStatus,orderStatus}:
  「其实已经付了」不是错误,不该让前端靠 message 字符串判定
- 结果以**重新读到的状态**为准,不以条件更新返回值为准(并发重复取消 / 期间被支付)
- **不推送一站式**。出向状态只有 PAID/REFUNDED,且 buildCreatePurchaseDetails 对非退款单
  恒发 PAID——在取消路径误调会造出一条假的「已支付」采购记录。未支付订单从未被推送过

标书详情新增 buyerCount(非表字段,实时统计的已付款订单数):
原「购买人数」取自 saleCount——下单即加、从不回退,dev 实测项目 4 的 16 里 11 张根本没付款。
saleCount 字段与下单累加未动(已无展示用途),**零 DDL**。

/order/pay 失败响应带 data.wechatCode:从 PaymentException 的 cause 链取
ServiceException.getErrorCode()(SDK 原样挂在 cause 上,中途各级 catch 全是 throw e),
供前端识别跨端 OUT_TRADE_NO_USED。**公共支付层与 core 一行未改。**

测试:HjcOrderCancelUtilTest(9) + HjcOrderControllerCancelTest(12,含推送禁区回归守卫)
2026-09-17 03:39:53 +08:00
weicw1996 fdff54a6cf chore(hjc): 一站式出向推送联调探测脚本
与已入库的 scripts/hjc_test_push.py(入向:一站式 → 官网 /api/hjc/push/project)互为反向,
一条命令回答「出向对接通没通、卡在哪一层」:

- 按文档约定的签名方案(sign = MD5(appKey + password + timestamp))发起真实推送;
- 额外遍历若干鉴权头变体,用于区分「签名不对」与「根本没校验签名」;
- 用对照探测把失败定位到具体一层:登录过滤器 / 路由不存在 / 验签失败 / 网络不可达。

默认参数直接从仓库的 application.yml 读取,避免脚本与配置脱节。
2026-09-17 02:35:18 +08:00
weicw1996 6e475bea03 fix(core): 基础设施故障不再伪装成凭据失效
鉴权过滤器里除了「token 无效」,还有两次外部依赖调用——核心实例的 /auth/user 与 Redis 的域名
白名单读。此前它们抛出的异常与「token 无效」一起被兜底成 401「请退出重新登录」,于是线上出现
这样的报文:

  {"code":401,"message":"请退出重新登录","error":"...RedisException: SocketException: Connection reset"}

用户照着这句话去重新登录什么也解决不了——Redis 连接被重置跟他手里的 token 毫无关系;真正的故障
被「登录态异常」这层皮盖住,排查方向从一开始就被带偏;而且重新登录会把一份**完全有效**的凭据丢掉,
把一次秒级抖动放大成用户的重复劳动。

- 新增 AuthFailureUtil.isInfrastructureFailure(e):沿 cause 链找基础设施异常。必须沿链找,因为真实
  异常是套娃的(RedisSystemException → io.lettuce.core.RedisException → SocketException;
  IORuntimeException → ConnectException),只看最外层会漏判;凭据类异常
  (MalformedJwtException / SignatureException / UsernameNotFoundException)的 cause 链里不会出现
  这些类型。带遍历深度上限,防御自引用环。
- Constants 加 SERVICE_UNAVAILABLE_CODE(503) 与 SERVICE_UNAVAILABLE_MSG。
- JwtAuthenticationFilter:命中基础设施故障时返回 503 +「服务暂不可用,请稍后重试」,
  其余异常仍按凭据失效处理。
- 补 AuthFailureUtilTest / JwtAuthenticationFilterTest(tokenKey 运行时用 JwtUtil.randomKey() 生成,
  不含任何真实凭据)。

只改变「异常如何归类与报出」,不触碰正常路径与既有错误码。
2026-09-17 02:35:13 +08:00
weicw1996 a3c54249dc feat(hjc): 密码找回与修改密码(材料审核制 + 双因子)
密码找回(匿名接口,见 ADR 0008「密码重置由平台运维人工执行」)
- POST /api/hjc/auth/password/apply:企业名称 + 纳税人识别号 + 新密码 + 授权委托书。
  用双要素定位企业而不是只用企业名称——hjc_enterprise.name 没有唯一索引(hjc_init.sql 里只有
  user_id 唯一),只用名称会把 A 企业的密码重置落到 B 账号上;加上同样有索引的 credit_code 后
  歧义天然消失,命中多条时告警并拒绝。企业不存在与信息不匹配返回同一句话且 data 为 null,
  避免企业注册状态被枚举;同企业 24h 内二次提交返回已存在那条。
- GET /api/hjc/auth/password/apply/status:同样双要素查进度。
- 状态 0 待审核 / 1 已通过(待重置) / 2 已驳回 / 3 已重置。「已通过」≠「已重置」是刻意的:
  核心实例没有任何 hjc 可用的代改密码通道,最后由运维照单在核心实例后台手工重置,再回后台标记。
- 新表 hjc_password_apply:hjc_init.sql 加建表语句,另给幂等的 hjc_password_apply.sql 作发布步骤
  (只增表,不动任何既有表,对共用本库的其他项目无影响)。新密码明文存储供运维照单重置,
  是 ADR 0008 已显式接受的风险,列注释里写明。

修改密码(登录态,双因子:旧密码 + 账号绑定手机号的短信验证码)
- POST /api/hjc/auth/password/sms 与 PUT /api/hjc/auth/password/change。短信发到**账号绑定手机号**
  (后端从登录态取),前端不能指定号码。
- HjcCoreAuthClient 加两条调用,且两条的认证姿态刻意相反,各自的「为什么与类注释相反」都写在注释里:
  verifyOldPassword 必须转发买家 Authorization(核心实例 PUT /auth/password 按登录态识别改谁),
  resetPassword 必须剥掉 Authorization 且带 userId + tenantId——不传 userId 时核心实例会按手机号
  查出**所有租户**下的账号并逐个改密(其 SQL 无 tenant_id 条件),那会连带改掉同一手机号在其它
  平台的账号密码。

访问控制
- SecurityConfig 只把匿名的 apply 加进 permitAll(status 走既有 GET /** 放行);sms 与 change
  **必须**保持登录态,故刻意不入名单。

后台端点(配套 hjc-vue 的审核页)
- /api/hjc/password-apply 的 page / detail / audit / mark-reset 四个管理员端点。列表不带明文新密码,
  只有详情给(运维要照单重置)。

未验:端到端需真实环境(核心实例授权、审核人、运维重置),见 .scratch/hjc-password/issues/06。
2026-09-17 02:35:02 +08:00
weicw1996 2cd60270b9 feat(mp-java): hjc 小程序接入链、微信接入自检、首页轮播与一站式出向推送
hjc 包的进展(按 AGENTS.md 约定,改动集中在 hjc 包内):

- HjcWechatController 新增三接口:
  - GET  /api/hjc/wechat/readiness  管理员自检,逐项报告小程序/公众号/支付/serverUrl
    是否配好、支付 appId 与小程序 appId 是否一致;?probe=true 实调微信验证 appSecret
    (失败只记日志、不抛异常)。appId 与商户号在 detail 里打码,appSecret 永不输出。
  - GET  /api/hjc/wechat/mp-appid   只回 appId,供 H5 渲染开放标签(不含密钥)。
  - POST /api/hjc/wechat/mp-login   uni.login 的 code 换小程序 openid/unionid;匿名放行,
    租户取 HjcAuthProperties 的配置值而非可伪造的请求头。
  配套 HjcWechatReadinessUtil(含单测)与 HjcWechatController 的两套配置读取:
  公众号 cache{t}:setting:wx-official、小程序 mp-weixin:{t} → setting:mp-weixin:{t} →
  跨库回源 gxwebsoft_core.sys_setting。
- HjcBannerController / Service / ServiceImpl / Mapper(+XML) / HjcBannerVo:只读
  GET /api/hjc/banner/list,按租户 + position + 启用状态 + 生效时间窗口过滤 CMS
  轮播组并扁平化;租户隔离交给 MyBatis-Plus 租户拦截器,不改 cms 及其他项目代码。
  配套 HjcBannerApiTest(最小上下文 MockMvc,含不串租户与位置过滤)。
- 一站式出向推送:CreatePurchaseDetails 补退款字段,HjcOrder 补 refund_time /
  refund_reason(配套 hjc_order_add_refund.sql 与 hjc_init.sql),HjcBizServiceImpl
  在 REFUNDED 时把退款时间与原因一并推送;配套推送报文单测。
- 共享文件 SecurityConfig.java 仅追加一行:匿名放行 /api/hjc/wechat/mp-login
  (注册页证件上传与 OCR 早先已放行)。这是本包唯一改到 common 的地方。
- 文档:CONTEXT.md、docs/一站式平台对接-接口文档.md。

**不含** scripts/hjc_test_push_out.py:该联调探针脚本内含与 HjcOneStopAuthUtil.java
相同的 APP_KEY / PASSWORD 明文,按此前排查记录「不得提交」处理,保留在工作区未跟踪。
2026-09-14 19:01:47 +08:00
weicw1996 b2b1a1bdf9 fix(payment): 微信支付改用公钥模式,修「无可用的平台证书」404
商户 1116982020 已在商户平台申请使用微信支付公钥,/v3/certificates 对这类
商户返回 RESOURCE_NOT_EXISTS(404)「无可用的平台证书」;而 WxPayConfigService
无条件使用 RSAAutoCertificateConfig(构造时即下载平台证书),因此创建支付
配置必然失败,Native/JSAPI 下单、查询、退款全部不可用。

- 数据库配置了 pub_key_id 时改用 RSAPublicKeyConfig(不请求平台证书):
  dev 取 classpath dev/wechat/{租户}/pub_key.pem,prod 取证书卷路径 pubKey
- 配了公钥ID但公钥文件缺失时抛出明确错误(含预期路径),
  不再退回平台证书自动下载后抛出难以定位的 404
- application-dev.yml 公钥文件名 wechatpay_cert.pem → pub_key.pem,
  与仓库内实际文件一致(shop 下单流程的 dev 公钥分支同受益)
- clearConfigCache 同时清 Redis Payment:1:{tenantId}:此前库中改了公钥ID
  也要等最长 24 小时缓存过期才生效
- 测试控制器 /api/test/clear-payment-cache 清的键不对(Payment:0:*),
  改为调用 clearConfigCache
- 新增 WxPayConfigServicePublicKeyTest 回归测试(3 个用例)

验证:/api/payment/query 由「创建微信支付配置对象失败: Wrong HttpStatusCode[404]
无可用的平台证书」变为微信业务应答 ORDER_NOT_EXIST;并用真实响应头验证
Wechatpay-Serial=PUB_KEY_ID_… 的公钥签名校验 PASS。
2026-09-12 18:47:59 +08:00
weicw1996 da1f9a64d4 fix(hjc): 短信验证码发送成功却报「服务暂不可用」——data 不是对象时解析就炸
CoreResult.of 用 json.getJSONObject("data") 取 data。fastjson 见到 String 值会
当成 JSON 再解析一次,而核心实例 ApiResult.data 是 Object,/sendSmsCaptcha 成功
时给的就是阿里云返回的字符串 "OK"(core 的 MainController 是
success("发送成功", result.get("Message"))),解析 "OK" 抛 JSONException。

该异常发生在 of() 内部,不在那个只包住 parseObject(raw) 的 try 里,于是逃到
execute() 的兜底 catch,被改写成 code=-1「认证服务暂不可用,请稍后重试」。
实际后果是短信已经发出去了,用户和前端看到的却是发送失败:核心实例侧验证码已
写入 Redis、60 秒重发限制与当日 10 条计数均已消耗,用户一重试就撞上
「发送过于频繁」,看起来更像坏了。login/register/captcha 的 data 都是对象,
所以只有发送短信这一条路坏。

- data 改为只接受对象,取不到即 null,绝不抛异常(toObjectData 保留 Map 分支,
  兼容 fastjson 桥接层给出的普通 Map);调用方本就只按 code 判成败,明细读 raw
- 新增 HjcCoreAuthClientResultTest:用日志里的真实响应体走完整调用链
  (sendSmsCaptcha → post → execute → of,只打桩 doExecute 出口)。
  改前该用例复现出逐字相同的异常(栈同在 of(HjcCoreAuthClient.java:93)),改后绿
- 用例同时锁住:data 为对象(登录/验证码)、业务失败无 data 键、data 为数字/数组、
  响应根本不是 JSON(网关 HTML)四种情形
- application.yml:hjc.one-stop.base-url 由空串改为 http://180.141.88.21:8810
  (base-url 为空时一站式推送不会发起,此前上线一直缺这项配置)
- 未改动核心实例代码,改动面限于 hjc 包与上述配置
2026-09-11 01:07:34 +08:00
weicw1996 27dbea9b6f fix(hjc): 买家接口未登录统一返回 401,越权返回 403(此前与业务失败同为 code=1)
共享 SecurityConfig 里 GET /** 放行,未登录的 GET 会进到 controller 由 controller
自行判登录态;此前这些地方返回 fail("用户未登录") 即 code=1,与业务失败同码,
前端无法据此判定登录失效——PC 端会把它显示成一句错误提示,而不是清凭据回登录页。

- 新增 HjcAuthResponses:unauthorized() → 401「请先登录」,
  forbidden(msg) → 403;复用平台既有常量 Constants.UNAUTHENTICATED_CODE/_MSG
  (这两个常量本就为此准备,此前唯一引用处是被注释掉的代码),不新造码值
- 7 处未登录返回改为 401:enterprise/my、enterprise/save、
  order/create、order/pay、order/mark-paid、order/my、order/{id}
- 订单详情的「无权查看该订单」改为 403,与 @PreAuthorize 的 AccessDeniedException
  归为同一个码,前端只需记一套规则(401 清凭据跳登录、403 只提示)
- 新增 HjcAuthResponsesTest 锁定契约(实测把码值改回 1 则测试红)
- 未改动共享 BaseController 与 SecurityConfig,改动面限于 hjc 包
2026-09-11 00:03:32 +08:00
weicw1996 ce1d0a2a8a feat(hjc): 登录认证重做——账号复用核心实例,企业语义自持;后台接口鉴权收口
汇吉采企业账号原由 hjc 自行写入 sys_user,注册与登录从未跑通:UserMapper 的
LEFT JOIN shop_user_oauth 既漏库名又是 core 2023 年的旧表名(打到不存在的
modules.shop_user_oauth),saveUser 因实体缺 schema 打到不存在的
modules.sys_user;即便修好,token 经共享过滤器远程回核心实例取用户时也必然 401。
本次按 ADR-0006(取代 ADR-0005)切分:账号归核心实例,企业归汇吉采。

- 账号本体是核心实例 sys_user 的一条零企业语义普通账号(type=0,不写
  shop_name/audit_status/company_id);注册/登录/图形验证码/短信 全部代理核心实例
- 企业主体、资质、经办人、证件、授权仍只存 hjc_enterprise / hjc_enterprise_material
- 新增 HjcCoreAuthClient:必带 TenantId 头(缺它 core 会拼 tenant_id=NULL,查重
  静默失效、登录永不匹配);剥掉 Authorization(否则短信码 Redis 前缀错位);
  不转发邮箱(core 会把明文密码邮件发给客户);登录不传 isSuperAdmin、发短信不传 scene
- 新增 HjcAuthProperties(hjc.tenant-id) 与 HjcAdminGuard:按 principal 的角色 +
  租户判定 hjc 管理员(core 权限串无 hjc 命名空间且本仓对 core 只有 SELECT)
- 鉴权收口(此前 hjc 包 @PreAuthorize 0 处):后台接口补权限校验,
  enterprise/page 等 GET 此前匿名可读、审核/退款仅需登录不校验角色;
  订单详情补归属校验,并先判身份再判存在(否则匿名可枚举订单 ID)
- 修复:注册在 core 建号成功后,因反序列化 UserDetails 多余字段
  (enabled/accountNonExpired/... 及 Role.sortNumber) 失败而被误报「注册失败」,
  造成「账号已存在但用户被告知失败、重试撞手机号已存在」的孤儿账号。
  改为忽略未知字段,且注册流程只取 userId、不再依赖整个 User 能否解析;
  并加回归测试(用真实失败响应体,反射读控制器真实的 ObjectMapper)
- 未改动核心实例代码,未触碰共用 mapper 的陈旧缺陷(仅 hjc 包与 SecurityConfig
  的 hjc 白名单为改动面)
2026-09-10 23:44:02 +08:00
weicw1996 5d88684820 fix(hjc): 证件上传改为存入 OSS(此前只写本地盘、返回的地址打不开)
问题:上传接口只把文件写进本地磁盘,再把地址拼成 {bucketDomain}{path} 或
{file-server}/api/file{path}——文件从未进过 OSS;前者指向桶里不存在的对象,
后者该前缀在文件服务主机上是 nginx 404。两条分支给出的地址都打不开,
证件预览坏、OCR 取图也必然失败。

做法(照后台 hjc-vue 的姿势):新增 HjcOssUploadUtil,把文件转交统一 OSS 上传服务
POST {config.server-url}/oss/upload(multipart file + tenantId 头,匿名可用),
取 data.path(原图,避开 data.url 的 x-oss-process 缩略参数)作为地址。
- 不转发调用方的 Authorization:hjc 的 JWT 与核心后端不是同一套签名,转过去会被判 401
- part 的 Content-Type 保留为图片类型(否则 OSS 存成 octet-stream,浏览器变下载、
  且 OCR 取图的 image/* 校验会拒掉自家上传的图)
- 上传失败即整个上传失败,不再回退成打不开的地址
- 未改动 common 的 FileController(多项目共用代码)

新增打桩单测 10 个(请求形状、path 优先、缩略参数剥离、失败码/非 JSON/无地址、类型嗅探)。
2026-09-10 14:47:06 +08:00
weicw1996 1e2ec82c18 feat(hjc): 证件OCR改用百度云(身份证/营业执照识别)
- 新增 com.gxwebsoft.hjc.ocr:HjcBaiduOcrClient(access_token 进程内缓存+提前刷新、
  两个接口调用、error_code/log_id 解析)、HjcOcrImageFetcher(取回 fileUrl 字节,
  要求 HTTP 200 且 Content-Type 为 image/*)、HjcOcrException(正数=百度云错误码,负数=本方错误码)
- HjcOcrServiceImpl 重写:材料类型路由(国徽面/授权委托书提前返回)、中文 key 映射、
  未识别哨兵值「无」过滤、图片大小与最短边前置校验(不合规不调百度云,身份证失败也计费)、
  失败按 error_code 打结构化日志(不记录识别出的值)
- pom 移除 aliyun-java-sdk-ocr;配置 aliyun.ocr.* 改为 baidu.ocr.api-key/secret-key(占位空值)
- 新增打桩单测 28 个(token 缓存与刷新、字段映射、「无」过滤、错误码、超限、正反面传错)

背景:阿里云 OCR 的 AK 一直是空占位,从未开通、链路从未跑通;甲方要求改用百度云。
接口契约不变(POST /api/hjc/ocr/recognize,前端零改动)。
2026-09-10 14:47:00 +08:00
weicw1996 08138f1f04 feat(hjc): 企业注册一站式——证件材料同事务入库 + 阿里云OCR识别 + 匿名注册上传
- HjcEnterprise 新增 idCardNo(经办人身份证号),配套迁移:
  src/main/resources/sql/hjc_enterprise_add_id_card_no.sql(需在目标库执行)
- HjcAuthRequest 新增 idCardNo / materials;/hjc/auth/register 同事务保存 4 类证件材料,
  并按「企业联系电话、企业地址选填,其余必填」补充后端校验
- 新增 POST /hjc/auth/upload:注册页登录前的匿名证件上传(复用 FileServerUtil,
  按 setting:upload 决定自建文件服 / OSS 域名;不写 file_record 表)
- 新增 POST /hjc/ocr/recognize:阿里云文字识别 OCR(aliyun-java-sdk-ocr 1.0.6)
  · idcard_front → agentName / idCardNo
  · license → creditCode / address(企业名称与法定代表人仅返回,供前端只读核对)
  · AK 走 aliyun.ocr.*,当前为占位空值;未配置时返回失败,由前端提示手动填写、不阻断注册
- SecurityConfig:/hjc/auth/upload 与 /hjc/ocr/recognize 匿名放行(与后台 /file/upload 隔离)
2026-09-10 13:12:10 +08:00
weicw1996 9d188d304b refactor(hjc): 发布时间/投标截止与开售/截止同义,仅保留 tenderOnsaleTime/tenderOffsaleTime 映射入库
- 撤销 HjcOneStopProjectPush 新增的 publishTime/deadlineTime 字段
- upsert 时 publishTime=tenderOnsaleTime, deadlineTime=tenderOffsaleTime(同一语义直接映射)
2026-09-09 17:10:17 +08:00
weicw1996 1aa8b8d4e4 fix(hjc): 入向推送补写发布时间/投标截止时间(无显式字段时取开售/截止时间兜底)
- HjcOneStopProjectPush 新增可选 publishTime/deadlineTime
- upsertFromPush: publishTime=显式publishTime||tenderOnsaleTime, deadlineTime=显式deadlineTime||tenderOffsaleTime
2026-09-09 17:04:41 +08:00
weicw1996 32a41bde6d feat(hjc): 支持公众号H5 JSAPI支付 + 微信网页授权/JS-SDK签名
- 新增 WechatJsapiStrategy(WECHAT):wechatpay-java JsapiServiceExtension.prepayWithRequestPayment
  返回 wx.chooseWXPay 所需参数;带 openid 走 JSAPI,否则回退 Native 扫码
- PaymentServiceImpl.getPaymentStrategy:WECHAT 按 openid 有无分流 JSAPI/Native
- HjcOrderController.pay:读取 openid,改用 WECHAT 类型
- 新增 HjcWechatController:/authorize 生成公众号授权地址、/oauth/callback code换openid回跳、
  /jsapi-sign 生成 wx.config 签名(jsapi_ticket,公众号配置存 redis cache{tenantId}:setting:wx-official)
- ADR 0003 记录 JSAPI 决策
2026-09-09 16:38:16 +08:00
weicw1996 9b050c9dc5 test(hjc): 一站式入向推送测试脚本(POST /api/hjc/push/project,appKey+timestamp+sign 鉴权) 2026-09-09 10:59:00 +08:00
weicw1996 32a3d1918c docs(hjc): 一站式平台对接接口文档(入向接收 + 出向推送 + 鉴权/字段映射/配置/待确认) 2026-09-09 10:48:59 +08:00
weicw1996 ab2f615067 feat(hjc): 后台订单退款接口 - POST /api/hjc/order/refund(置已退款+推送REFUNDED) 2026-09-08 23:19:52 +08:00
weicw1996 10099a1d5a feat(hjc): 网站企业账号+密码 注册/登录(JWT签发)
- POST /api/hjc/auth/register:创建 common.system.User(用户名=企业名称, BCrypt密码)+ 角色 + hjc_enterprise(待审核),签发 token(LoginResult)
- POST /api/hjc/auth/login:校验企业名称+密码,签发 token
- 复用 JwtUtil/JwtSubject/userService 与 wx-login 同一套签发;SecurityConfig 放行 /api/hjc/auth/register|login
2026-09-08 22:39:07 +08:00
weicw1996 4cbd925544 feat(hjc): 阶段2 订单支付闭环 - 下单后发起微信Native支付并回推一站式
- HjcOrderController: POST /api/hjc/order/pay(复用 payment.createPayment 取codeUrl)、PUT /api/hjc/order/mark-paid(幂等置已付+触发一站式推送)
- HjcBizService.markPaid: 置 payStatus=1/orderStatus=1/payTime,支付成功即 pushOrderToOneStop
- 出向推送在 base-url 未配置时不发起HTTP,仅记日志待重试
2026-09-08 20:54:01 +08:00
weicw1996 b2f310b81d 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
2026-09-08 20:27:28 +08:00
weicw1996 1bcb805d65 docs(hjc): 甲方确认项目与标书为同一实体(一个项目一本标书),单表建模 2026-09-08 20:11:25 +08:00
weicw1996 770aeff4d7 docs(hjc): 汇吉采标书购买领域词表、推送鉴权规范与ADR 2026-09-08 20:09:41 +08:00
weicw1996 79666898c5 feat(ai-house): 解除房源与资料库强绑定 2026-08-08 06:48:09 +08:00
weicw1996 e362291d6e feat(house): 重构AI找房匹配能力 2026-08-08 03:12:57 +08:00
weicw1996 37f1fa263e feat(house): 重构AI找房匹配能力 2026-07-31 20:21:08 +08:00
weicw1996 7fe8fe47c8 feat(house): 重构AI找房近似推荐 2026-07-31 00:37:31 +08:00
b2894lxlx 70354148b4 新增房产AI 2026-07-30 15:43:44 +08:00
gxwebsoft e6736d41ff refactor(import): 优化批量导入功能提升性能
- 在多个控制器中引入 BatchImportSupport 工具类
- 实现分块处理机制,每批次处理 500 条记录
- 使用 persistChunkWithFallback 方法替代逐条保存
- 保持原有的数据校验和去重逻辑不变
- 显著提升大量数据导入时的执行效率
- 减少数据库操作次数降低系统负载
2026-01-16 00:55:49 +08:00
gxwebsoft e0e15cdd45 feat(mapper): 添加公司关联查询和关键词搜索功能
- 在多个Mapper XML文件中添加LEFT JOIN credit_company表关联
- 扩展关键词搜索范围,支持通过公司名称进行搜索匹配
- 更新CreditNearbyCompany相关功能,支持按公司ID筛选和导入
- 修改CreditNearbyCompanyParam中companyId字段类型为String
- 暂时注释掉纳税人识别号相关的搜索条件
- 统一各信用数据映射文件中的关键词搜索逻辑
2026-01-15 23:58:18 +08:00
gxwebsoft 2116856167 feat(mapper): 添加公司关联查询和关键词搜索功能
- 在多个Mapper XML文件中添加LEFT JOIN credit_company表关联
- 扩展关键词搜索范围,支持通过公司名称进行搜索匹配
- 更新CreditNearbyCompany相关功能,支持按公司ID筛选和导入
- 修改CreditNearbyCompanyParam中companyId字段类型为String
- 暂时注释掉纳税人识别号相关的搜索条件
- 统一各信用数据映射文件中的关键词搜索逻辑
2026-01-15 23:33:42 +08:00
gxwebsoft e810136fbb feat(credit): 添加企业ID字段支持精确查询
- 在CreditNearbyCompany实体中新增companyId字段
- 更新CreditNearbyCompanyMapper.xml添加公司ID查询条件
- 在CreditNearbyCompanyParam参数类中添加companyId查询字段
- 实现基于企业ID的精确筛选功能
2026-01-15 22:42:07 +08:00
gxwebsoft 45828ad95c feat(car): 更新车辆查询支持组织ID列表筛选
- 添加 organizationIds 参数支持多组织ID筛选
- 实现 IN 查询逻辑替代原有的单个组织ID匹配
- 保留原有 organizationId 单值查询作为备选条件
- 添加 foreach 循环处理组织ID集合
- 优化查询条件避免参数冲突
2026-01-13 15:27:30 +08:00
gxwebsoft f0cd200e21 feat(HjmCarParam): 添加组织ID集查询功能
- 引入java.util.Set导入支持
- 新增organizationIds字段用于组织ID集合查询
- 添加@Schema注解描述组织ID集功能
- 配置@QueryField注解支持IN查询类型
2026-01-13 15:22:24 +08:00
gxwebsoft 4d7f871aad feat(credit): 添加被执行人历史功能模块
- 在CreditJudgmentDebtor实体中增加historyId和historyName字段用于关联历史数据
- 新增CreditJudgmentDebtorHistory实体类用于存储被执行人历史记录
- 创建CreditJudgmentDebtorHistoryController提供完整的CRUD和批量导入导出接口
- 实现CreditJudgmentDebtorHistoryService及其实现类处理业务逻辑
- 添加CreditJudgmentDebtorHistoryMapper及XML映射文件支持数据库操作
- 新增CreditJudgmentDebtorHistoryParam和CreditJudgmentDebtorHistoryImportParam参数类
- 修改CreditJudgmentDebtorMapper.xml添加与历史表的关联查询
- 更新CreditUserMapper.xml在关键词搜索中加入历史被执行人名称匹配
2026-01-12 09:17:15 +08:00
gxwebsoft c766f2879d feat(house): 添加租金和面积单位字段
- 为租金字段添加rentUnit单位属性
- 为月租金字段添加monthlyRentUnit单位属性
- 为面积字段添加extentUnit单位属性
- 更新实体类HouseInfo的数据结构定义
2026-01-09 19:08:48 +08:00
gxwebsoft 6eeadd7ec3 feat(credit): 支持指定工作表索引导入信用用户数据
- 添加 ExcelImportSupport.findSheetIndex 方法查找特定工作表
- 修改 tryImport 方法支持传入工作表索引参数
- 更新导入配置循环使用指定工作表索引
- 修改 readNameHyperlinks 方法使用正确的工作表索引读取超链接
- 设置 ImportParams 的起始工作表索引为动态获取的索引值
2026-01-09 10:13:56 +08:00
gxwebsoft 0de588321f feat(excel): 优化Excel导入功能支持动态工作表查找
- 添加findSheetIndex方法支持根据工作表名称查找索引
- 实现精确匹配、前缀匹配和包含匹配的查找逻辑
- 在各个控制器中使用动态工作表索引替换固定索引
- 优化CreditCompanyController中的必填字段验证逻辑
- 移除对code字段的必填验证要求
- 添加工作表名称标准化处理功能
2026-01-08 18:29:27 +08:00
gxwebsoft 3434f4d8e6 feat(excel): 优化Excel导入功能支持动态工作表查找
- 添加findSheetIndex方法支持根据工作表名称查找索引
- 实现精确匹配、前缀匹配和包含匹配的查找逻辑
- 在各个控制器中使用动态工作表索引替换固定索引
- 优化CreditCompanyController中的必填字段验证逻辑
- 移除对code字段的必填验证要求
- 添加工作表名称标准化处理功能
2026-01-08 18:16:44 +08:00
gxwebsoft abbcd992a4 feat(credit): 添加批量导入功能和下载模板功能
- 为行政许可控制器添加批量导入和下载模板功能
- 为破产重整控制器添加批量导入和下载模板功能
- 为分支机构控制器添加批量导入和下载模板功能
- 为历史法定代表人控制器添加批量导入和下载模板功能
- 为附近企业控制器添加批量导入和下载模板功能
- 实现Excel导入数据验证和错误处理机制
- 添加导入参数实体类和转换方法
- 实现超链接读取和数据映射功能
- 添加导入模板生成和下载功能
2026-01-07 14:37:59 +08:00
gxwebsoft 947d1190a9 feat(credit): 添加行政许可、破产重整和分支机构管理功能
- 创建了CreditAdministrativeLicense实体类及对应的Controller、Service、Mapper和XML映射文件
- 创建了CreditBankruptcy实体类及对应的Controller、Service、Mapper和XML映射文件
- 创建了CreditBranch实体类及对应的Controller、Service、Mapper和XML映射文件
- 实现了分页查询、列表查询、详情查询、新增、修改、删除等基础CRUD功能
- 添加了批量操作功能包括批量新增、批量修改和批量删除
- 集成了权限控制和操作日志功能
- 实现了关联查询和排序功能
- 添加了完整的参数验证和查询条件支持
2026-01-07 13:59:30 +08:00
gxwebsoft 3ed457d7d6 feat(credit): 添加企业名称关联查询功能
- 在多个实体类中添加companyName字段用于显示企业名称
- 为CreditBreachOfTrust、CreditCaseFiling等实体添加TableField注解
- 修改CreditCompetitor实体的字段名称为mainCompanyName
- 在各个Mapper.xml文件中添加LEFT JOIN关联查询企业名称
- 更新查询SQL语句以包含企业名称字段
- 添加必要的TableField导入依赖
2026-01-05 15:21:59 +08:00
gxwebsoft 064d3b168e feat(import): 批量导入功能增加公司ID参数支持
- 为所有批量导入接口增加可选的companyId参数
- 在导入过程中将companyId设置到实体对象中
- 修复客户导入时的租户ID冲突处理逻辑
- 添加数据完整性验证异常处理机制
- 实现字符串字段的标准化处理功能
- 优化重复数据检测和更新逻辑
2026-01-05 14:30:46 +08:00
gxwebsoft bb3cf97cc9 feat(credit): 添加企业ID字段支持
- 在多个信用实体类中添加companyId字段,包括CreditBreachOfTrust、CreditCaseFiling、CreditCompetitor等
- 更新对应的Mapper XML文件,添加基于companyId的查询条件
- 在各个参数类中添加companyId参数支持
- 为CreditJudicialImportParam添加缺失的Schema注解
- 实现基于企业ID的数据过滤功能,提升数据查询的准确性
2026-01-05 13:01:53 +08:00
gxwebsoft 2f39bd4e0b feat(import): 添加Excel导入时超链接解析功能
- 在CreditCompany和CreditJudgmentDebtor实体中添加url字段
- 实现ExcelImportSupport工具类的超链接读取功能
- 支持通过表头名称定位列并提取超链接地址
- 在企业信息导入时自动解析原文件和匹配名称的超链接
- 在执行人信息导入时解析案号和被执行人名称的超链接
- 移除多余的import语句和调试输出代码
- 扩展ImportResult类以支持工作表索引信息
2026-01-03 22:31:05 +08:00
gxwebsoft ce01afcfb0 feat(controller): 增加被执行人批量导入支持ZIP和多sheet解析
- 支持ZIP文件批量导入多个Excel文件
- 增加对多sheet Excel文件的自动识别和解析
- 实现表头配置自动匹配和最优结果选择
- 添加导入结果统计和错误信息汇总
- 优化Excel导入的错误处理和字符编码支持
- 增加对被执行人工作表名称的智能识别
- 实现导入过程中的数据验证和重复检查机制
2026-01-03 22:01:35 +08:00
gxwebsoft 0dce41f2db fix(credit): 修复执行标的字段类型错误
- 将CreditJudgmentDebtor实体类中的amount字段类型从BigDecimal改为String
- 将CreditJudgmentDebtorParam参数类中的amount字段类型从BigDecimal改为String
- 在导入处理中移除对amount字段的BigDecimal解析
- 添加对name1字段的空值检查
- 调整债务人名称赋值逻辑,优先使用name字段,为空时使用name1字段
- 添加调试日志输出导入数据大小
2026-01-03 19:57:17 +08:00
gxwebsoft 4f1a931006 feat(credit): 扩展信用公司搜索功能并添加被执行人字段
- 修改CreditCompanyMapper.xml中的搜索条件,增加名称和匹配名称的模糊搜索
- 添加对信用代码的精确搜索功能
- 在CreditJudgmentDebtor实体中新增name1字段用于存储被执行人信息
- 为name1字段添加数据导入参数映射配置
- 更新数据库查询逻辑以支持多字段搜索匹配
2026-01-03 19:22:16 +08:00