shizhongqi 1 月之前
父节点
当前提交
3ddd3c2dbe
共有 21 个文件被更改,包括 845 次插入9 次删除
  1. 46 0
      AI/Codex/选中代码 + 提需求.md
  2. 11 0
      front_end/前端项目文档/1--多余文件或接口清理.md
  3. 0 0
      front_end/前端项目文档/SVG 说明.md
  4. 55 0
      front_end/前端项目文档/笔记/登录优化.md
  5. 13 6
      server/帐号数据.md
  6. 8 3
      server/有用的账号信息.md
  7. 5 0
      任务小笔记/26年/04-18:零售满减与折扣.md
  8. 18 0
      任务小笔记/26年/04-21:红包功能优化变动.md
  9. 9 0
      任务小笔记/26年/04-30:小功能需求.md
  10. 6 0
      任务小笔记/26年/05-03:花掌柜界面设计.md
  11. 47 0
      任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/birthday_gift.md
  12. 46 0
      任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/hdApp - mallApp 会员折扣开关与下单计价.md
  13. 350 0
      任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/hdApp 客户生日赠礼管理 — 开发计划.md
  14. 18 0
      任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/问题.md
  15. 21 0
      任务小笔记/26年/05-28:库存与特价、限购、满减.md
  16. 60 0
      任务小笔记/26年/05-28:库存并发复现/1-app-ghs 库存并发复现脚本--AI plan.md
  17. 65 0
      任务小笔记/26年/05-28:库存并发复现/2-app-ghs 库存并发企业级修复方案.md
  18. 54 0
      任务小笔记/26年/05-28:库存并发复现/3-纳入更多库存接口.md
  19. 6 0
      任务小笔记/26年/06-01:拉卡拉进件/关键信息.md
  20. 6 0
      任务小笔记/给客户进件的流程.md
  21. 1 0
      多项目开发让Codex理解说明.md

+ 46 - 0
AI/Codex/选中代码 + 提需求.md

@@ -0,0 +1,46 @@
+产品:ghsApp / ghsPad / hdApp / hdPad / mallApp
+
+位置:
+/Users/shishao/dnmp/www/front-end/xxx.vue 第 xx-xx 行
+ 或 
+ 直接粘贴代码
+ ```
+ code
+ ```
+
+需求:  
+希望这段代码改成……
+
+现象 / 问题:  
+现在会……
+
+期望结果:  
+改完后应该……
+
+接口 / 后端:  
+如果涉及接口,写接口路径,比如 /api/xxx/yyy
+
+限制:  
+不要影响…… / 字段名保持…… / 兼容旧逻辑……
+
+
+### 对比实现功能搬运
+
+
+### 技巧
+
+有个疑问:我的需求是在 understand-project 中发起,还是要在本项目下发起
+
+----
+建议按需求类型分:
+
+如果只是改这个后端仓库本身,比如 `app-ghs`、`app-hd`、`app-mall` 的接口、业务逻辑、数据库查询,就在当前项目 `/Users/shishao/dnmp/www/huahuibao` 下发起最合适。
+
+如果是前后端联动需求,比如要从 `ghsApp` 页面一路改到后端接口,或不确定某个页面/API 对应哪个仓库,就可以在 `/Users/shishao/dnmp/www/understand-project` 发起。它更像“全栈知识层/协调入口”,适合先定位跨项目关系、同步改多个仓库。
+
+简单说:
+
+- 只改后端:在 `huahuibao`
+- 前后端联动、不确定归属、需要跨仓库理解:在 `understand-project`
+
+你现在这个仓库的 `AGENTS.md` 也说了:遇到前后端联动需求时,先读 `understand-project/AGENTS.md`,所以即使你在 `huahuibao` 发起,我也会按规则去那边取上下文。

+ 11 - 0
front_end/前端项目文档/1--多余文件或接口清理.md

@@ -0,0 +1,11 @@
+### === 1 ===
+经过全局搜索和分析,`ghsApp/src/pagesOrder/select.vue` 这个文件目前已经没有被使用了。
+
+以下是判断依据:
+
+1. 未在路由中注册:在 `ghsApp/src/pages.json` 配置文件中,既没有找到 `pagesOrder/select` 的页面注册信息,也没有找到任何关于 `pagesOrder` 分包的配置。
+2. 无代码引用或跳转:在整个 `ghsApp` 项目代码中全局搜索 `pagesOrder` 或 `select.vue`,都没有找到任何相关的引用(如 `import` 引入)或页面跳转(如 `uni.navigateTo({ url: '/pagesOrder/select' })`)。
+
+综上所述,这个文件(甚至可能整个 `pagesOrder` 目录)属于项目中的废弃代码或遗留文件,当前并没有在项目中实际运行。
+
+### === 2 ===

+ 0 - 0
front_end/前端项目文档/SVG.md → front_end/前端项目文档/SVG 说明.md


+ 55 - 0
front_end/前端项目文档/笔记/登录优化.md

@@ -0,0 +1,55 @@
+commit: c603a6e2fb90b54e0162bd98adcaa21590e7ab61
+
+### 第一个
+问题:@mallApp/src/pages/login/account.vue:59 小程序重新编译刷新后,登录状态会丢失,请查查哪儿有问题 @mallApp/src/pages/home/recent.vue:226-246 
+
+问题定位到了,确实在你标注的两处链路上:
+
+- `recent.vue` 的 `watch/onShow` 完全依赖 `vuex` 里的 `loginInfo` 来决定 `loginStyle`。
+- `account.vue` 登录成功后只 `commit('setLoginInfo', user)`,但原来的 `mallApp/src/store/modules/login.js` 只是内存赋值,没有持久化。
+- 小程序“重新编译/刷新”会重建运行时,`vuex` 内存被清空,`loginInfo` 变 `{}`,所以页面就判定成未登录。
+
+我已经修复了 `mallApp/src/store/modules/login.js`,做了两件事:
+
+- `state.loginInfo` 初始化时从本地缓存读取(`uni.getStorageSync`)。
+- `setLoginInfo` 时同步写入缓存;当传入空对象时移除缓存,避免脏数据残留。
+
+这样登录后即使重新编译刷新,`loginInfo` 也会恢复,`recent.vue` 的登录态判断会保持正确。
+
+建议你本地验证这 3 步:
+
+1. 登录一次(账号密码或手机号都行)。
+2. 在开发者工具里重新编译/刷新小程序。
+3. 回到首页看 `recent` 页是否仍保持已登录样式与逻辑。
+
+如果你愿意,我可以再顺手把 `token` 和 `loginInfo` 的 key 命名在 `mallApp` 里统一一下,避免后续多人维护时混用。
+
+
+### 第二个
+把 token 和 loginInfo 的 key 命名在 mallApp 里统一一下
+
+已统一完成,`mallApp` 里 `token` 和 `loginInfo` 的缓存 key 现在都走同一套命名与常量。
+
+- 新增统一常量文件:`mallApp/src/constant/storageKeys.js`
+  - `TOKEN_STORAGE_KEY = "mallToken"`
+  - `LOGIN_INFO_STORAGE_KEY = "mallLoginInfo"`
+  - `LEGACY_TOKEN_STORAGE_KEY = "token"`(用于兼容迁移)
+- `loginInfo` 持久化继续使用同一常量:`mallApp/src/store/modules/login.js`
+  - 初始化从 `LOGIN_INFO_STORAGE_KEY` 读取
+  - `setLoginInfo` 同步写入/清空该 key
+- `token` 读写点全部替换为 `TOKEN_STORAGE_KEY`,覆盖了:
+  - `mallApp/src/pages/login/account.vue`
+  - `mallApp/src/pages/login/index.vue`
+  - `mallApp/src/components/wangCg.vue`
+  - `mallApp/src/pages/home/recent.vue`
+  - `mallApp/src/plugins/luch-request_0.0.7/request.js`
+  - `mallApp/src/utils/util.js`
+  - `mallApp/src/mixins/globalMixins.js`
+  - `mallApp/src/utils/auth.js`
+  - `mallApp/src/App.vue`
+- 在 `mallApp/src/App.vue` 增加了旧 key 迁移逻辑:
+  - 启动时若存在旧 `token` 且新 `mallToken` 不存在,会自动迁移到新 key 并删除旧 key,避免老用户掉登录。
+
+补充说明:
+- linter 里有一个现存错误在 `mallApp/src/pages/home/recent.vue`(`@click=""` 空绑定),这不是这次改动引入的。  
+- 如果你要,我下一步可以把 `recent.vue` 这个报错顺手修掉。

+ 13 - 6
server/帐号数据.md

@@ -1,13 +1,20 @@
 ### 测试账号
-小米手机 ---- 17189513228
-vivo手机 ----  
-华为手机 ---- 17187822038    用户名:奥斯
-荣耀手机 ---- 17187822032    
+华为手机 ---- 17187822038    用户名:
+荣耀手机 ---- 17187822032    用户名:
 
-17189512989
+| 手机品牌    | mobile                  | dev环境 | 销花宝             | 花掌柜             | 花卉宝                         |
+| ------- | ----------------------- | ----- | --------------- | --------------- | --------------------------- |
+| 我主号     | 18259179840             |       |                 |                 | shishao(原先为空)<br>uid -- 151 |
+| vivo手机  | 13306006935             |       | 未注册             | 未注册             | 尾号6935<br>370               |
+| 华为手机    | 17187822038             |       | 奥斯<br>36843     | 奥斯<br>36755     | 2038<br>97                  |
+| 荣耀手机    | 17187822032             |       | 京海鲜花批发<br>36957 | 京海鲜花批发<br>36956 | 尾号2032<br>253               |
+| 苹果XsMax | 17189512989<br>(此账号不能删) |       | 微升漫花<br>36846   | 微升漫花<br>36749   | 石头<br>113                   |
+| 新小米     | 18559200768             |       | 未注册             | 未注册             | 尾号0768<br>371               |
+| 小米手机    | 17189513228             |       | 台北鲜花批发<br>36959 | 台北鲜花批发<br>36958 | 大骨头<br>108                  |
+| 少华主号    | 15280215347             |       | 好运鲜花批发<br>36523 | 好运鲜花<br>36524   | 中华<br>301                   |
 
-### 配置
 
+### 配置
 小票机
 520543315
 daxht6jf

+ 8 - 3
server/有用的信息.md → server/有用的账号信息.md

@@ -5,7 +5,7 @@
 - **正式服务上的 mysql 数据库连接**
 	url: rm-bp1ek0z5b055t571jlo.mysql.rds.aliyuncs.com
 	用户: readonly
-	密码: zhhb123aw*678x
+	密码: Zhh3531673
 
 - **管理后台**
 	网址:http://pt.hzghd.com/
@@ -18,7 +18,12 @@
 	[https://open.weixin.qq.com](https://open.weixin.qq.com/)微信开放平台
 
 
-### gitLab
+### gitLab超管账号
 git.huaml.com
 zhh 
-xhb*2025
+xhb*2025
+
+
+http://pms.huaml.com
+shizq 
+Shizq20260428

+ 5 - 0
任务小笔记/26年/04-18:零售满减与折扣.md

@@ -0,0 +1,5 @@
+照搬批发端的满减与折扣
+
+### SQL
+ALTER TABLE xhOrder ADD COLUMN `orderReachDiscountPrice` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '整单满减' AFTER discountAmount;
+

+ 18 - 0
任务小笔记/26年/04-21:红包功能优化变动.md

@@ -0,0 +1,18 @@
+1. 花掌柜后台,要一眼让老板方便看出来,客户有几个红包。
+
+2. 花掌柜后台,要使用红包时,只能使用余额,其他付款方式不支持,这个先后台限制,后面再考虑前端,因为不清楚,是不是所有店都要这样
+	1. xhShop表: `rechargeWeal` tinyint(4) NOT NULL DEFAULT '0' COMMENT '充值赠送 0未设置 1设置了,充值送钱,2设置了,充值送红包',
+
+3. 成为VIP会员后在客户列表增加标识(花掌柜收银端客户列表也要增加标识)
+
+### SQL--新增字段
+```
+ALTER TABLE xhShopExt ADD COLUMN `reachVip` decimal(9,2) NOT NULL DEFAULT '0.00' COMMENT '单比充值金额达到成为VIP,0.00 表示没开启充值成为VIP会员' AFTER needWork;
+
+
+ALTER TABLE `xhShop` MODIFY COLUMN `rechargeWeal` tinyint(4) NOT NULL DEFAULT '0' COMMENT '充值赠送 0未设置,1充值送钱,2充值送红包--红包非余额支付可用,3充值送红包--红包非余额支付不可用';
+
+
+ALTER TABLE xhCustom ADD COLUMN `vip` smallint(4) NOT NULL DEFAULT '0' COMMENT 'VIP会员: 0不是,1是' AFTER inviteNum;
+```
+

+ 9 - 0
任务小笔记/26年/04-30:小功能需求.md

@@ -0,0 +1,9 @@
+- ➕  ➖号  --(前端)
+- ~~一键退款~~
+- 折扣设置
+- 菜单优化 --(前端)
+- VIP 需求变动
+	 1、改成非余额消费1元,增加一个成长值;充值1元,增加一个成长值。(积分也是这样的情况)
+	 2、已经有消费和充值的,要把等级重新刷新一下,特别是虎门店,只要根据门店id来刷新
+     3、手动开启和关闭会员资格; 充值触发;
+     4、客户列表,VIP 改成 会员,只列 vip开启的状态(非vip 不显示)   --(前端)

+ 6 - 0
任务小笔记/26年/05-03:花掌柜界面设计.md

@@ -0,0 +1,6 @@
+这是我开发的应用“花掌柜”的店铺页面,请帮忙做美化设计: 
+1. 设计新的一套 icon 图标(把icon图标颜色统一为与界面美观至的绿色,当然有些 icon 不适合绿色就不要绿色)。
+2. 合理设计布局 
+3. 当前应用偏向「鲜花/批发/店铺管理」场景,要商业实用性。能面向真实开发落地(非纯概念设计)
+
+当前是比较简陋,没到“可商用产品级 UI”,例如做成类似「支付宝商家版 + 美团商家 + 有赞」的感觉。可以的话,设计出以下多版本:iOS风 / 支付宝风 / 轻拟物 / 双色渐变等

+ 47 - 0
任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/birthday_gift.md

@@ -0,0 +1,47 @@
+-- hdApp 客户生日赠礼模块
+-- 执行前请备份相关表
+
+-- 1. 会员等级扩展:折扣、生日权益、权益说明
+```
+ALTER TABLE `xhMemberLevel`
+  ADD COLUMN `discount` decimal(4,2) NOT NULL DEFAULT 10.00 COMMENT '折扣,如9.5表示9.5折' AFTER `amount`,
+  ADD COLUMN `birthdayBenefit` varchar(50) NOT NULL DEFAULT '' COMMENT '生日权益/礼品名称' AFTER `discount`,
+  ADD COLUMN `benefitDesc` varchar(500) NOT NULL DEFAULT '' COMMENT '会员权益说明' AFTER `birthdayBenefit`;
+```
+
+-- 2. 生日赠礼流水(门店+客户+自然年唯一)
+```
+CREATE TABLE `xhBirthdayGift` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `mainId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '商家主账号',
+  `shopId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '门店',
+  `customId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '客户',
+  `hdId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '花店关系',
+  `userId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '用户',
+  `year` smallint(4) unsigned NOT NULL DEFAULT '0' COMMENT '活动年份',
+  `status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0未填写 1待通知 2待领取 3领取中 4已领取 5超时放弃',
+  `member` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '会员等级',
+  `memberName` varchar(32) NOT NULL DEFAULT '' COMMENT '等级名称',
+  `giftName` varchar(50) NOT NULL DEFAULT '' COMMENT '礼品名称快照',
+  `birthdayMonth` tinyint(2) unsigned NOT NULL DEFAULT '0',
+  `birthdayDate` tinyint(2) unsigned NOT NULL DEFAULT '0',
+  `lunar` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `birthdayDisplay` varchar(32) NOT NULL DEFAULT '' COMMENT '展示用生日',
+  `notifyTime` datetime DEFAULT NULL COMMENT '短信通知时间',
+  `expireTime` datetime DEFAULT NULL COMMENT '领取截止时间',
+  `pickupTime` datetime DEFAULT NULL COMMENT '预约到店时间',
+  `collectTime` datetime DEFAULT NULL COMMENT '确认领取时间',
+  `abandonTime` datetime DEFAULT NULL COMMENT '超时放弃时间',
+  `claimToken` varchar(64) NOT NULL DEFAULT '' COMMENT '领取短链token',
+  `shortLink` varchar(255) NOT NULL DEFAULT '' COMMENT '微信短链',
+  `orderSn` varchar(32) NOT NULL DEFAULT '' COMMENT '小票订单号',
+  `smsSent` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否已发短信',
+  `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_custom_shop_year` (`customId`,`shopId`,`year`),
+  UNIQUE KEY `uk_claim_token` (`claimToken`),
+  KEY `idx_uid_year` (`userId`,`year`),
+  KEY `idx_shop_year_status` (`shopId`,`year`,`status`)
+) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COMMENT='生日赠礼记录';
+```

+ 46 - 0
任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/hdApp - mallApp 会员折扣开关与下单计价.md

@@ -0,0 +1,46 @@
+**Summary**
+- 在 `hdApp` 会员等级设置页给每个等级增加折扣开启/关闭开关。
+- 后端会员等级接口不改默认逻辑,继续允许空折扣补成 `10`。
+- 业务含义调整为:`discount=10` 表示关闭折扣/原价,`discount<10` 表示开启折扣。
+
+**Key Changes**
+- 前端 `front-end/hdApp/src/admin/member/level.vue`:
+  - 折扣列增加 `switch` 开关。
+  - 初始化时:`discount < 10` 视为开启;`discount == 10` 或空值视为关闭。
+  - 关闭时把 `item.discount` 设为 `10`,禁用折扣输入。
+  - 开启时折扣必填,校验为数字且 `0 < discount < 10`。
+  - 提交仍只发送现有 `discount` 字段,不新增接口字段。
+
+- 后端会员等级接口:
+  - `app-hd/controllers/MemberLevelController.php` 不改变空值补 `10` 的现有行为。
+  - 可仅补充必要校验:`discount` 必须为数字且 `0 < discount <= 10`;`10` 合法,代表原价/关闭折扣。
+
+- 后端下单折扣:
+  - 在 `biz-hd/order/services/OrderService.php::createHdOrder` 统一读取客户等级折扣。
+  - 如果客户 `discount < 10`,在当前应付价基础上继续打折:`最终价 = 当前应付价 * discount / 10`。
+  - 如果客户 `discount >= 10`、为空或无等级,跳过会员折扣,按当前价/原价计算。
+  - 继续沿用现有 `discountType=discount` 和 `discountAmount` 记录总优惠差额。
+  - 因 `hdApp /order/create-order`、`mallApp /order/create-order` 花束下单、`mallApp /order/buy-item` 都最终调用 `createHdOrder`,折扣逻辑集中在服务层;`mallApp /order/order-relate` 只是下单前信息接口,不做计价修改。
+
+- 客户等级同步:
+  - 检查 `biz-hd/custom/classes/CustomClass.php` 的等级刷新逻辑,确保等级配置变更后客户侧 `discount` 能同步到最新值。
+  - 若当前批量刷新只同步等级和名称,则补上 `discount` 字段同步。
+
+**Test Plan**
+- 前端:
+  - `discount=10` 显示为关闭,输入禁用。
+  - 开启后不填或填 `10` 提交,提示需要填写小于 `10` 的折扣。
+  - 开启填 `9.5` 保存成功。
+  - 关闭后提交保存 `discount=10`。
+
+- 后端:
+  - `php -l` 检查修改过的 PHP 文件。
+  - 客户 `discount=10` 调用 `hdApp /order/create-order`,不产生会员折扣。
+  - 客户 `discount=9.5` 调用 `hdApp /order/create-order`,当前应付价继续打 95 折。
+  - 同样验证 `mallApp /order/create-order` 花束下单与 `mallApp /order/buy-item` 花材下单。
+  - 有红包或已有 `modifyPrice` 时,先保留已有价,再继续叠加会员折扣。
+
+**Assumptions**
+- 折扣单位沿用“几折”:`9.5` 为 95 折,`10` 为原价。
+- 已确认:已有 `modifyPrice` 时继续叠加会员等级折扣。
+- 不运行 `npm run build:mp-weixin`,除非后续明确要求。

+ 350 - 0
任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/hdApp 客户生日赠礼管理 — 开发计划.md

@@ -0,0 +1,350 @@
+---
+name: hdApp 生日赠礼模块
+overview: 在 hdApp + mallApp + biz-hd/biz-mall 全栈实现客户生日赠礼管理:工作台摘要栏、生日看板、赠礼统计、明日一键短信、mallApp 短链领取、云小票打印,并扩展会员等级页的生日权益配置。新建业务表 xhBirthdayGift;24h 过期用 RabbitMQ x-delay 延时队列(复用 limitBuyDelayExchange),不用 console 扫表。
+todos:
+  - id: sql-schema
+    content: 编写 xhBirthdayGift CREATE TABLE 与 xhMemberLevel ALTER SQL
+    status: completed
+  - id: biz-hd-birthday
+    content: 实现 BirthdayGiftClass + BirthdayGiftController(摘要/看板/统计/通知/MQ延时过期/打印)
+    status: completed
+  - id: member-level-api
+    content: 扩展 MemberLevelController 与 level.vue 卡片化(discount/birthdayBenefit/benefitDesc)
+    status: completed
+  - id: hdapp-ui
+    content: mall-home-panel 最近生日栏 + board + giftStats 页面与 API
+    status: completed
+  - id: biz-mall-claim
+    content: mall 端 token 领取 API + 领取后触发云打印
+    status: completed
+  - id: mallapp-page
+    content: mallApp birthdayGift 领取页三态 UI + pages.json
+    status: completed
+  - id: mq-delay-expire
+    content: RabbitMQ 延时队列(x-delay 24h)触发超时自动放弃
+    status: completed
+  - id: index-validate
+    content: npm run index + 端到端联调验证
+    status: completed
+isProject: false
+---
+
+# hdApp 客户生日赠礼管理 — 开发计划
+
+## 范围与约定
+
+| 项 | 约定 |
+|---|---|
+| 产品 | hdApp(商家端)+ mallApp(C 端领取)+ `app-hd` / `app-mall` / `biz-hd` / `biz-mall` |
+| 参与客户 | **member > 0** 且对应 `xhMemberLevel` 已配置非空 **生日权益**(`birthdayBenefit`) |
+| 过期 | **短信发送后 24 小时**内须完成预约领取;超时由 **RabbitMQ 延时消息** 精确触发「超时放弃」(不用 console 扫表) |
+| 不改动 | hdPad、ghs 系列、app-pt |
+
+```mermaid
+flowchart TB
+  subgraph hdApp [hdApp 商家端]
+    WB[workbench 最近生日栏]
+    BD[生日看板]
+    GS[赠礼统计]
+    ML[会员等级设置]
+    WB --> BD
+    BD --> GS
+    BD -->|一键通知 明日| SMS
+  end
+  subgraph mallApp [mallApp C端]
+    CL[会员福利领取页]
+  end
+  subgraph backend [后端]
+    SMS[短信+短链]
+    BG[xhBirthdayGift]
+    PRINT[飞鹅云小票]
+  end
+  SMS --> CL
+  CL -->|确认领取| BG
+  BG --> PRINT
+  ML -->|birthdayBenefit| BG
+```
+
+---
+
+## 一、数据库(SQL 交付物)
+
+### 1. 扩展 `xhMemberLevel`
+
+当前 [`MemberLevelController`](file:///Users/shishao/dnmp/www/huahuibao/app-hd/controllers/MemberLevelController.php) 仅读写 `name/level/levelSn/amount`;[`CustomClass::levelChange`](file:///Users/shishao/dnmp/www/huahuibao/biz-hd/custom/classes/CustomClass.php) 已读取 `discount` 但前端未维护。
+
+```sql
+ALTER TABLE `xhMemberLevel`
+  ADD COLUMN `discount` decimal(4,2) NOT NULL DEFAULT 10.00 COMMENT '折扣,如9.5表示9.5折' AFTER `amount`,
+  ADD COLUMN `birthdayBenefit` varchar(50) NOT NULL DEFAULT '' COMMENT '生日权益/礼品名称' AFTER `discount`,
+  ADD COLUMN `benefitDesc` varchar(500) NOT NULL DEFAULT '' COMMENT '会员权益说明' AFTER `birthdayBenefit`;
+```
+
+### 2. 新建 `xhBirthdayGift`(核心流水表)
+
+按 **门店 + 客户 + 自然年** 唯一(一年一条活动记录):
+
+| 字段 | 说明 |
+|------|------|
+| `mainId`, `shopId`, `customId`, `hdId`, `userId` | 关联 |
+| `year` | 如 2026 |
+| `status` | `0未填写` / `1待通知` / `2待领取` / `3已领取` / `4超时放弃` |
+| `member`, `memberName`, `giftName` | 通知时快照等级与礼品名 |
+| `birthdayMonth`, `birthdayDate`, `lunar`, `birthdayDisplay` | 展示用 |
+| `notifyTime`, `expireTime` | 短信时间与 24h 截止 |
+| `pickupTime` | 客户预约到店时间 |
+| `collectTime` | 确认领取时间 |
+| `claimToken` | 短链 token(唯一) |
+| `shortLink` | 微信 ShortLink 缓存 |
+| `orderSn` | 打印用小票编号 |
+| `smsSent` | 是否已发短信 |
+
+索引建议:`(shopId, year, status)`、`(claimToken)`、`(customId, shopId, year)` UNIQUE。
+
+实现时提供完整 `CREATE TABLE` + 迁移说明文档(放在 huahuibao 或 understand-project 的 `sql/` 目录,按你们现有习惯)。
+
+---
+
+## 二、后端 biz-hd(`biz-hd/birthday/` 新模块)
+
+参考现有分层:[`RechargeController`](file:///Users/shishao/dnmp/www/huahuibao/app-hd/controllers/RechargeController.php) + [`WxMiniClass::getShortLink`](file:///Users/shishao/dnmp/www/huahuibao/biz-mall/wx/classes/WxMiniClass.php)。
+
+### 核心类 `BirthdayGiftClass`
+
+| 方法                                      | 职责                                                                                                                        |
+| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
+| `getWorkbenchSummary(shopId)`           | 今日/明日/近一周人数(member>0 + 有 birthdayBenefit + 生日落在区间)                                                                        |
+| `ensureYearRecords(shopId, range)`      | 看板打开时懒创建当年记录                                                                                                              |
+| `getBoardList(filters)`                 | 时间区间 + 状态 Tab + 搜索                                                                                                        |
+| `getStatusCounts(filters)`              | 图2 顶部六类计数                                                                                                                 |
+| `getGiftStats(period)`                  | 图3 按 `giftName` 分组统计待领取/已领取                                                                                               |
+| `batchNotifyTomorrow(shopId)`           | 筛 **明天生日** + status=待通知 → 发短信 + 生成 token/短链 + status→待领取 + **投递 24h 延时消息**                                                |
+| `scheduleExpireDelay(giftId, expireAt)` | 向 RabbitMQ 发布延时任务(见下文)                                                                                                    |
+| `expireById(giftId)`                    | 消费者回调:status=待领取 且未过期领取 → 置「超时放弃」(幂等)                                                                                     |
+| `printReceipt(gift)`                    | 仿 [`OrderClass::onlinePrint`](file:///Users/shishao/dnmp/www/huahuibao/biz-hd/order/classes/OrderClass.php),独立 ESC 模板(图9) |
+
+### 生日匹配逻辑
+
+- 复用现有 `birthdayMonth/birthdayDate/lunar` + cron [`actionUpdateBirthday`](file:///Users/shishao/dnmp/www/huahuibao/console/controllers/CustomController.php) 维护的 `birthdayTime`。
+- 「今日/明日/近一周」:对农历客户用当年公历 `birthday` 字段比对月日;对未填生日客户归入看板 **未填写**(`birthdayTime=0`),工作台计数可不含或单独统计(与图1「今日5人」一致:只统计已填生日且落在区间内的会员)。
+
+### 短信模板(图4)
+
+```
+{门店名称}:亲爱的会员您好,明天就是您生日啦!这边有份您的vip生日福利礼包{会员生日赠礼说明},请您24小时内点击下方链接免费领取{短链}逾期无效、感谢您的配合!祝您生活愉快!天天开心!
+```
+
+- 发送:[`sms::merchantSend`](file:///Users/shishao/dnmp/www/huahuibao/common/components/sms.php)(扣商家短信余额)。
+- 短链页面:`pages/member/birthdayGift?account={shopId}&token={claimToken}`(与充值短链同模式 [`actionGetMallRechargeShortLink`](file:///Users/shishao/dnmp/www/huahuibao/app-hd/controllers/RechargeController.php))。
+- 记录写入 `xhSms`(现有 [`SmsClass`](file:///Users/shishao/dnmp/www/huahuibao/biz-hd/message/classes/SmsClass.php))。
+
+### hdApp 新 Controller `BirthdayGiftController`(`app-hd`)
+
+| Action                        | 用途           |
+| ----------------------------- | ------------ |
+| `workbench-summary`           | 工作台栏数据       |
+| `board-list` / `board-counts` | 看板列表与 Tab 计数 |
+| `gift-stats`                  | 赠礼统计         |
+| `notify-tomorrow`             | 一键通知         |
+| `print`                       | 看板内手动补打(可选)  |
+
+扩展 [`MemberLevelController`](file:///Users/shishao/dnmp/www/huahuibao/app-hd/controllers/MemberLevelController.php):`get-init-data` / `modify` 增加 `discount`、`birthdayBenefit`、`benefitDesc` 读写与校验(benefit 50 字、desc 500 字、amount 递增逻辑保留)。
+
+### RabbitMQ 延时过期(替代 console cron)
+
+复用项目已有 **`x-delayed-message`** 能力(与花材限购清空相同模式,见 [`ProductClass::createLimitBuyCache`](file:///Users/shishao/dnmp/www/huahuibao/biz-hd/product/classes/ProductClass.php) L703–723 与 [`common/config/rabbitMQ.php`](file:///Users/shishao/dnmp/www/huahuibao/common/config/rabbitMQ.php) 中 `limitBuyDelayExchange`)。
+
+**为何不用 cron 扫表:** 每条记录在「发短信」时即可投递 **精确 24h** 延时消息,到期才处理,无全表轮询、无时间窗口误差,与消费者进程常驻即可。
+
+#### 配置扩展(`common/config/rabbitMQ.php`)
+
+在现有 `limitBuyDelayExchange` 上**新增绑定**(共用同一延时交换器,无需再建 exchange 类型):
+
+| 项 | 值 |
+|---|---|
+| 队列 | `birthdayGiftQueue`(durable) |
+| 交换器 | `limitBuyDelayExchange`(已有 `x-delayed-message`) |
+| routing key | `birthdayGiftDelayRoute` |
+| 生产者 | 复用 `notifyProducer`(或 `customProducer`) |
+| 消费者 | 新建 `birthdayGiftConsumer` → 绑定 `birthdayGiftQueue` |
+
+> 与 `limitBuyQueue` 分离队列,避免 `stockConsumer` 承担无关业务;仅共享延时交换器插件。
+
+#### 投递时机(`batchNotifyTomorrow` 单条成功后)
+
+```php
+// 伪代码,与限购 delay 发布一致
+$delayMs = max(1000, ($gift->expireTime - time()) * 1000);
+$producer->publish(serialize([
+    'type' => 'birthday_gift_expire',
+    'giftId' => $gift->id,
+]), 'limitBuyDelayExchange', 'birthdayGiftDelayRoute', [
+    'delivery_mode' => 2,
+    'content_type' => 'application/octet-stream',
+    'application_headers' => new AMQPTable(['x-delay' => $delayMs]),
+]);
+```
+
+- `expireTime = notifyTime + 86400`,`x-delay` 按剩余秒数计算(支持补发/重试时以 DB `expireTime` 为准重算 delay)。
+- 可选:表字段 `expireMsgId` 或 Redis key 记录已投递,防止重复通知重复过期(重发时先 ACK 旧逻辑,以最新 `expireTime` 再投一条)。
+
+#### 消费逻辑(`common/components/rabbitmq/birthdayGiftConsumer.php`)
+
+```php
+switch ($data['type']) {
+    case 'birthday_gift_expire':
+        BirthdayGiftClass::expireById($data['giftId']);
+        break;
+}
+```
+
+`expireById` 规则(幂等):
+
+1. 记录不存在 → ACK
+2. `status != 待领取(2)`(已领取/已放弃/未通知)→ ACK,不覆盖
+3. `status == 待领取` 且 `now >= expireTime` → 更新为 **超时放弃(4)**,写 `abandonTime`
+4. 异常 → 记日志 + `noticeUtil`,ACK(与 `stockConsumer` 一致,避免死信堆积)
+
+#### 兜底(可选,非主路径)
+
+仅保留极轻量补偿:console 每日一次扫描「`expireTime` 已过 1 小时仍为待领取」的漏投记录(MQ 宕机场景),不作为主过期机制。默认**不实现**;若上线后观测有漏单再加。
+
+```mermaid
+sequenceDiagram
+  participant HD as hdApp一键通知
+  participant BG as BirthdayGiftClass
+  participant MQ as limitBuyDelayExchange
+  participant C as birthdayGiftConsumer
+  HD->>BG: batchNotifyTomorrow
+  BG->>BG: 发短信 status=待领取
+  BG->>MQ: publish x-delay=24h giftId
+  Note over MQ: 24小时后投递
+  MQ->>C: birthday_gift_expire
+  C->>BG: expireById
+  BG->>BG: status=超时放弃
+```
+
+---
+
+## 三、后端 biz-mall(C 端领取)
+
+新建 `app-mall/controllers/BirthdayGiftController.php`:
+
+| Action | guest | 说明 |
+|--------|-------|------|
+| `info` | 是 | token 查礼品、门店地址、状态(可领/已领/过期) |
+| `claim` | 是 | 提交 `pickupTime`,校验未过期、status=待领取 |
+| `claim` 成功后 | — | 调 `biz-hd` 侧更新状态 + **触发云打印**(商家无需手点) |
+
+> mall 端用 **token 鉴权**,不要求用户登录,与 [`OrderController::fast-pay`](file:///Users/shishao/dnmp/www/huahuibao/app-mall/controllers/OrderController.php) _guest 模式一致。
+
+---
+
+## 四、hdApp 前端
+
+根目录:[`/Users/shishao/dnmp/www/front-end/hdApp/src`](file:///Users/shishao/dnmp/www/front-end/hdApp/src)
+
+### 1. 工作台「最近生日」栏(需求1)
+
+文件:[`mall-home-panel.vue`](file:///Users/shishao/dnmp/www/front-end/hdApp/src/admin/home/components/mall-home-panel.vue)
+
+- 在 **花束** `home-card`(约 L96)**上方**插入可点击行(复用 `news-list` 行样式:左 icon + 标题 + 三段时间统计 + 右箭头)。
+- 临时 icon:本地 `static` 占位蛋糕图(后续你可替换)。
+- `onShow`/`init` 调 `GET /birthday-gift/workbench-summary`。
+- 点击 → `/admin/birthday/board`。
+
+### 2. 生日看板(需求2)
+
+- 新页:`admin/birthday/board.vue` + 子组件 `components/birthday-custom-card.vue`。
+- 注册 [`pages.json`](file:///Users/shishao/dnmp/www/front-end/hdApp/src/pages.json) subpackage `admin/birthday`。
+- UI 对齐图2:顶部「一键通知」「赠礼统计」、搜索、时间区间 + 今日/明日/近一周 pill、六状态 Tab、客户卡片(状态色、预约时间行)。
+- 「未填写」卡片点「点击填写生日」→ 跳转现有 [`/admin/member/detail`](file:///Users/shishao/dnmp/www/front-end/hdApp/src/admin/member/detail.vue) 生日弹窗逻辑。
+- API 模块:新建 `api/birthday/index.js`。
+
+### 3. 赠礼统计(需求3)
+
+- `admin/birthday/giftStats.vue`(modal 或独立页,与项目其他 stat 弹层风格一致)。
+- 时间周期切换 + 双表格(待领取 / 已领取)。
+
+### 4. 会员等级页改造(需求8 / 图6)
+
+文件:[`admin/member/level.vue`](file:///Users/shishao/dnmp/www/front-end/hdApp/src/admin/member/level.vue)
+
+- 由表格改为 **卡片列表**(参考设计图:图标、等级名、消费金额、折扣、生日权益 0/50、权益说明 0/500)。
+- 提交字段扩展,与后端 `modify` 同步。
+- 样式沿用页面现有绿色主题(`#f0f9f0`、`admin-button-com`)。
+
+---
+
+## 五、mallApp 前端
+
+根目录:[`/Users/shishao/dnmp/www/front-end/mallApp/src`](file:///Users/shishao/dnmp/www/front-end/mallApp/src)
+
+### 会员福利领取页(需求5–7)
+
+- 新页:`pages/member/birthdayGift.vue`(标题「会员福利领取」)。
+- 注册 `pages.json`;[`launchScene.js`](file:///Users/shishao/dnmp/www/front-end/mallApp/src/utils/launchScene.js) 无需改 scene 映射(query 直传 `account` + `token`)。
+- 三态 UI:
+  - **可领取**:礼品卡 + 到店时间 picker + 门店地址 + 「到这去」+ 底部「返回/确认领取」。
+  - **已领取**(图7):展示已选时间,隐藏确认按钮。
+  - **已过期**(图8):中间提示「领取时间已过,已自动放弃权益」。
+- API:`api/birthday/index.js` → `info` / `claim`。
+- 时间选择:复用项目现有 datetime picker 组件(若无则用 `uni-datetime-picker` 与 recharge 等页一致)。
+
+---
+
+## 六、小票打印(需求7 / 图9)
+
+在 `BirthdayGiftClass::buildPrintContent()` 组装飞鹅 `<BR>` 模板,字段:
+
+- 标题「生日赠礼订单」
+- `pickupTime` + 「到店自取」
+- 取花人姓名、尾号、手机号
+- 礼品名(加粗行)
+- 会员等级、账户余额、订单日期、订单编号(`orderSn`)
+
+触发点:**mallApp `claim` 成功** → 调 hd 侧打印(`printUtil` + `ShopExt.printSn`),与 [`onlinePrintOrder`](file:///Users/shishao/dnmp/www/front-end/hdApp/src/api/order/index.js) 同打印机。
+
+---
+
+## 七、状态机(实现对照图2)
+
+```mermaid
+stateDiagram-v2
+  [*] --> NoBirthday: 未填生日
+  NoBirthday --> PendingNotify: 填写生日后进入当年池
+  PendingNotify --> PendingClaim: 一键通知发短信
+  PendingClaim --> Collected: mallApp确认领取
+  PendingClaim --> Expired: MQ延时24h到期
+  Collected --> [*]
+  Expired --> [*]
+```
+
+| status | 展示 |
+|--------|------|
+| 未填写 | 橙色,引导填生日 |
+| 待通知 | 红色角标,明日一键通知目标 |
+| 待领取 | 蓝色,显示预约时间 |
+| 已领取 | 灰色,显示领取时间 |
+| 超时放弃 | 深灰,显示自动放弃文案 |
+
+---
+
+## 八、知识库与验证
+
+- 实现后于 understand-project 运行 `npm run index` 刷新索引。
+- 手工测试路径:
+  1. 配置某等级生日权益 → 客户设明天生日 → 工作台数字 → 看板 → 一键通知
+  2. 打开短链 → mallApp 预约 → 商家小票机出票
+  3. 通知后等待 MQ 延时(或测试环境将 delay 改为 60s)验证图8 过期态
+  4. 赠礼统计数字与列表一致
+
+---
+
+## 主要改动文件清单
+
+| 仓库 | 新增/修改 |
+|------|-----------|
+| huahuibao | `sql/birthday_gift.sql`;`biz-hd/birthday/*`;`app-hd/controllers/BirthdayGiftController.php`;扩展 `MemberLevelController`;`app-mall/controllers/BirthdayGiftController.php`;`biz-mall/birthday/*`;`common/config/rabbitMQ.php`(birthdayGiftQueue/绑定/消费者);`common/components/rabbitmq/birthdayGiftConsumer.php` |
+| hdApp | `mall-home-panel.vue`;`admin/birthday/*`;`admin/member/level.vue`;`api/birthday/index.js`;`pages.json` |
+| mallApp | `pages/member/birthdayGift.vue`;`api/birthday/index.js`;`pages.json` |

+ 18 - 0
任务小笔记/26年/05-26:hdApp 客户生日赠礼管理/问题.md

@@ -0,0 +1,18 @@
+1. 同一个客户,多个门店给他发了生日赠礼 ---- 一个短信回复解决不了
+	   - 用带门店id的方法,能做到吗  -- 都领取下???
+2. 没有生日的,客户自己设置了生日(或者花店给客户设置生日)-- 是否能正常变更到 xhBirthdayGift (只修改当前年份的,不修改过去年份的)
+3. ALTER TABLE `xhMemberLevel`
+  ADD COLUMN `discount` decimal(4,2) NOT NULL DEFAULT 10.00 COMMENT '折扣,如9.5表示9.5折' AFTER `amount` ---- 对应折扣要应用上???
+4. “尾号2032 ”进行超时放弃设置 -- 请不要删除数据,直到有测试结果
+
+
+### 优化
+1. 到店自取 --- 字体大小加大、加粗
+2. 
+   
+   
+   
+### 上线注意点
+1. 要重启rabbitmq  --- supervisorctl restart all
+2. 对应数据表要先上线
+3. 

+ 21 - 0
任务小笔记/26年/05-28:库存与特价、限购、满减.md

@@ -0,0 +1,21 @@
+### 库存相关接口
+1. 销花宝 -- 花材修改
+	https://api.shop.hzghd.com/product/update
+	
+2. 销花宝 -- 修改库存
+	https://api.shop.hzghd.com/check-order/create-order
+
+3. 销花宝 -- 采购订单下单
+   https://api.shop.hzghd.com/purchase-order/create-order
+
+4. 销花宝 -- 采购订单的下一步----入库
+   https://api.shop.hzghd.com/purchase-order/confirm-put-in?id=1628
+
+
+调拨出库与入库
+1. 出库
+https://api.shop.hzghd.com/stock-out/create-order
+
+2. 入库
+
+

+ 60 - 0
任务小笔记/26年/05-28:库存并发复现/1-app-ghs 库存并发复现脚本--AI plan.md

@@ -0,0 +1,60 @@
+# app-ghs 库存并发复现脚本
+
+## Summary
+新增一个本地测试脚本,用你提供的两组 curl 请求并发调用:
+
+- `POST http://api.shop.hzghd.com/order/create-order`
+- `POST http://api.shop.hzghd.com/stock-out/create-order`
+
+脚本运行后读取 `xhGhsItem.stock` 的前后值,按请求商品数量计算预期库存,并输出“实际结果是否等于预期结果”,用于确认两个接口并发执行时是否存在库存覆盖问题。
+
+## Key Changes
+- 在 `scripts/` 下新增一个 PHP CLI 脚本,例如 `scripts/test_ghs_stock_concurrency.php`。
+- 脚本内置你提供的 `baseUrl`、headers、token、account 和两个接口请求体。
+- 使用 `curl_multi` 同时发起两类请求,默认每类接口各发 1 次,也支持通过 CLI 参数提高并发量:
+  - `--order=1`
+  - `--stock-out=1`
+  - `--rounds=1`
+- 每轮执行前后读取商品库存:
+  - 商品 `27286`
+  - 商品 `27282`
+- 库存预期变化:
+  - `order/create-order`:每次扣减 `27286: 2`、`27282: 2`
+  - `stock-out/create-order`:每次扣减 `27286: 1`、`27282: 1`
+  - 默认一轮预期每个商品共扣减 `3`
+- 输出内容包含:
+  - 每轮开始库存
+  - 每轮结束库存
+  - 预期结束库存
+  - 差异值
+  - 每个请求的 HTTP 状态码、耗时、响应摘要
+  - 最终 PASS/FAIL
+
+## Implementation Notes
+- 脚本通过 Yii console bootstrap 读取数据库连接,直接查询 `xhGhsItem`,不额外配置数据库账号。
+- 不自动回滚库存、不删除订单、不清理出库单,避免脚本擅自修改业务数据;它只通过这两个真实接口制造并发并读取结果。
+- 因为 `OrderController::actionCreateOrder` 有 `checkRepeatCommit`,并发多次同类下单可能被重复提交限制拦截;默认每类接口各 1 次,后续需要更高并发时再用参数调大并观察响应。
+- 当前代码里 `ProductClass::decreaseStock()` 已调用 `util::lock()`,但 `util::lock()` 使用 Redis `setex` 而不是 `SET NX`,脚本的目标是用业务结果验证该锁是否实际有效。
+
+## Test Plan
+- 运行默认测试:
+  - `php scripts/test_ghs_stock_concurrency.php`
+- 观察输出:
+  - 如果实际库存等于预期库存,脚本输出 PASS。
+  - 如果实际库存高于预期库存,说明存在并发覆盖导致扣减丢失,脚本输出 FAIL 并打印差异。
+  - 如果接口被重复提交、库存不足、业务校验等拦截,脚本输出对应响应摘要,当前轮不作为有效并发结论。
+- 可重复运行多轮提高复现概率:
+  - `php scripts/test_ghs_stock_concurrency.php --rounds=10`
+
+## Assumptions
+- 按你的选择,脚本会内置这次 curl 的生产域名、token、account 和请求体。
+- 运行脚本会真实创建订单/出库单并真实扣减库存。
+- 本阶段只新增并发测试脚本,不修改锁机制;等你执行脚本确认问题后,再进入库存锁修复方案。
+  
+  
+### 运行命令
+```
+php scripts/test_ghs_stock_concurrency.php
+php scripts/test_ghs_stock_concurrency.php --rounds=10
+php scripts/test_ghs_stock_concurrency.php --order=2 --stock-out=2 --rounds=3
+```

+ 65 - 0
任务小笔记/26年/05-28:库存并发复现/2-app-ghs 库存并发企业级修复方案.md

@@ -0,0 +1,65 @@
+# app-ghs 库存并发企业级修复方案
+
+## commits
+455681448a037c025f3b15f5b296c3fc219bd834
+cbd44c03f9a177fdb705d6569ac8651a6a03fad4
+
+## Summary
+修复方向不是继续依赖当前 Redis `util::lock()`。当前实现用 `setex`,没有 `NX` 语义,多个请求会同时“拿到锁”;同时库存更新发生在长事务内,两个接口并发更新同一批 `xhGhsItem` 时会出现死锁或覆盖风险。
+
+企业级方案采用数据库行级锁作为库存一致性的主保障,按固定商品 ID 顺序锁定库存行,并把库存读改写集中到 `ProductClass` 的库存方法内。Redis 锁只作为可选降载保护,不作为正确性依赖。
+
+## Key Changes
+- 重构 `ProductClass` 库存增减方法:
+  - `addStock()`
+  - `addStockByItemNum()`
+  - `decreaseStock()`
+  - `decreaseStockByItemNum()`
+  - `addOnStockByItemNum()`
+  - `decreaseOnStockByItemNum()`
+- 库存方法内部统一使用 `ProductClass::getLockById($productId)`,即 `SELECT ... FOR UPDATE`,确保同一商品库存读写在数据库事务内串行化。
+- 去掉库存正确性对 `util::lock(lock_stock_*)` 的依赖;库存计算必须基于已锁定行的当前值。
+- 在批量库存变更入口统一商品处理顺序:
+  - `OrderItemClass::replaceItem()` 按 `productId ASC` 处理商品。
+  - `StockOutOrderClass::addOrder()` / `cancelOrder()` 按 `productId ASC` 处理商品。
+  - `StockInOrderClass::confirmOrder()` 按 `productId ASC` 处理商品。
+- 库存更新必须在同一个事务内完成:
+  - 已有外层事务时复用外层事务。
+  - 没有外层事务时,库存方法自身不单独开启事务,仍要求调用方负责事务边界;对没有事务的调用入口补齐事务或确认其只改单行。
+- 保留并改进 Redis 锁工具:
+  - 新增安全锁方法,例如 `util::tryLock($key, $expire, $waitTime)` 返回 token。
+  - 新增 `util::releaseLock($key, $token)`,用 Lua 校验 token 后释放。
+  - 不直接破坏旧 `util::lock()/unlock()` 的调用兼容性,但库存路径不再依赖旧锁。
+
+## Failure Handling
+- 对 MySQL `1213 Deadlock found` 和 `1205 Lock wait timeout exceeded` 增加统一重试包装:
+  - 仅包裹完整业务事务入口,不在库存方法内部局部重试。
+  - 默认最多重试 2 次,短暂随机退避。
+  - 重试失败后返回明确业务错误:`系统繁忙中,请稍后再试`,同时写入错误日志。
+- 库存不足仍使用现有业务提示,例如 `xxx 只剩 n 扎`。
+- 所有库存流水继续记录 `oldStock/newStock/itemNum`,值来自锁定后的真实库存。
+
+## Test Plan
+- 先跑语法检查:
+  - `php -l biz-ghs/product/classes/ProductClass.php`
+  - `php -l biz-ghs/order/classes/OrderItemClass.php`
+  - `php -l biz-ghs/order/classes/StockOutOrderClass.php`
+  - `php -l biz-ghs/order/classes/StockInOrderClass.php`
+- 再运行已新增并发脚本:
+  - `php scripts/test_ghs_stock_concurrency.php`
+  - `php scripts/test_ghs_stock_concurrency.php --rounds=10`
+- 验收标准:
+  - 两个接口都成功时,`xhGhsItem.stock` 必须等于预期扣减值。
+  - 不应再出现 `Deadlock found` / `Serialization failure`。
+  - 库存流水的 `oldStock/newStock` 必须连续,不允许出现跳变或覆盖。
+- 回归关键场景:
+  - 正常开单扣库存。
+  - 调拨出库扣库存。
+  - 调拨确认入库加库存。
+  - 取消出库加回库存。
+  - 库存不足拦截。
+
+## Assumptions
+- 不新增数据库表,不做结构迁移。
+- `xhGhsItem.id` 是库存行的唯一串行化维度。
+- 本次只修复 app-ghs 的库存并发一致性,不顺手改采购、盘点、预订等其他业务流程;但会避免破坏它们已调用的公共库存方法。

+ 54 - 0
任务小笔记/26年/05-28:库存并发复现/3-纳入更多库存接口.md

@@ -0,0 +1,54 @@
+请把其它与库存相关的接口都纳入 scripts/test_ghs_stock_concurrency.php 测试中,如果有接口没做并发报错重试的,请加上
+
+### AI实现
+已补齐两部分:
+
+测试脚本 [scripts/test_ghs_stock_concurrency.php](/Users/shishao/dnmp/www/huahuibao/scripts/test_ghs_stock_concurrency.php) 现在纳入更多库存接口:
+
+```sh
+php scripts/test_ghs_stock_concurrency.php --rounds=1
+```
+
+默认会并发测试:
+
+- `order/create-order` 扣库存
+- `stock-out/create-order` 扣库存
+- `wastage/create-order` 扣库存
+
+也支持依赖已有单据的参数化场景:
+
+```sh
+php scripts/test_ghs_stock_concurrency.php --order=0 --stock-out=0 --wastage=0 --stock-in-confirm=入库单号
+php scripts/test_ghs_stock_concurrency.php --order=0 --stock-out=0 --wastage=0 --stock-out-cancel=出库单号
+php scripts/test_ghs_stock_concurrency.php --order=0 --stock-out=0 --wastage=0 --purchase-put-in=采购单ID
+```
+
+并发重试已补到这些库存相关入口:
+
+- `order/create-order`
+- `stock-out/create-order`
+- `stock-out/confirm-order`
+- `stock-out/cancel-order`
+- `stock-in/confirm-order`
+- `stock-in/cancel-order`
+- `wastage/create-order`
+- `purchase-order/create-order`
+- `purchase-order/confirm-put-in`
+- `purchase-order/cancel`
+- `refund/create-order`
+
+同时对相关批量库存处理补了 `productId ASC` 排序,包括报损和采购入库/取消路径,减少多商品交叉锁死锁。
+
+已跑语法检查,覆盖脚本和改动文件,均通过。建议先跑:
+
+```sh
+php scripts/test_ghs_stock_concurrency.php --rounds=1
+```
+
+`--rounds=2` 仍可能触发业务重复提交保护,出现“请稍等几秒再试”,这不是库存并发结论。
+
+### 采购单ID获取
+采购菜单进行采购获取
+
+### 
+

+ 6 - 0
任务小笔记/26年/06-01:拉卡拉进件/关键信息.md

@@ -0,0 +1,6 @@
+- 微信群:拉卡拉-厦门中花汇
+- 进件接口文档地址https://o.lakala.com/p/#/user/login
+	登录名为15221581207,密码为MQ6k1cAt
+	有个word文件,看微信群
+	如果有上传图片要保存的,单独建一个oss目录
+- 123 

+ 6 - 0
任务小笔记/给客户进件的流程.md

@@ -1,5 +1,11 @@
 ### 花店手续费是0.38,不是批发店的0.33,要区分哦~
 
+### 开户需要的资料
+门店门头照片、门店收银台照片、门店内景照片各一张
+营业执照照片
+身份证正面与反面照片
+营业执照法人的银行卡照片
+
 ### 1. 给客户的信息
 开户资料审核通过了,已经绑定到您的系统。接着需要您按下面的视频进行认证开通收款账户,认证完后,系统就可以用了。
 

+ 1 - 0
多项目开发让Codex理解说明.md

@@ -0,0 +1 @@
+建立AI理解的前后项目关系与指导如何做自动化工作项目 /Users/shishao/dnmp/www/understan-project。项目目的是:让 Codex 明白两个git库(前端库:`/Users/shishao/dnmp/www/front-end` ,后端库 `/Users/shishao/dnmp/www/huahuibao`)里的前后端项目之间的映射关系,从而当开发者发来一个需求时,Codex 能从整体上进行分析与实现修改