Compare commits

...

3 Commits

Author SHA1 Message Date
wangjia b6223b3816 chore: release v1.0.2
Deploy / deploy (push) Successful in 1m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:25:05 +08:00
wangjia 117cec431b docs(claude): 补充发版流程、异常上报、拼音搜索规范
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:09:21 +08:00
wangjia d8295d14da chore: 添加 /release 本地发版 slash command
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:52:54 +08:00
5 changed files with 150 additions and 7 deletions
+66
View File
@@ -0,0 +1,66 @@
执行本地发版流程,版本号为 $ARGUMENTS。
按以下步骤顺序执行,任意步骤失败立即停止并报告错误。
## 1. 检查工作区
检查是否有未提交的改动(`git status`)。如果有,列出文件并询问用户是否继续。
## 2. 本地构建
```bash
export PATH="/opt/homebrew/bin:$PATH"
cd backend && go build ./...
```
## 3. 运行测试
```bash
export PATH="/opt/homebrew/bin:$PATH"
cd backend && go test ./...
cd client && flutter analyze --no-fatal-infos --no-fatal-warnings
```
## 4. 更新 CHANGELOG.md
检查 CHANGELOG.md 中是否已有 `## [$ARGUMENTS]` 版本节。
- **已有**:直接使用,不修改。
- **没有**:读取 `git log` 从上一个 tag 到 HEAD 的提交记录,自动生成一个版本节插入到文件顶部(位于已有版本节之前),格式如下:
```
## [$ARGUMENTS] - <今天日期>
### 新功能
- ...
### 改进
- ...
### 修复
- ...
```
只保留有内容的分类(新功能/改进/修复),根据 commit message 的类型(feat/fix/refactor 等)归类。
## 5. 提交代码
将所有改动(包括 CHANGELOG.md)用以下格式提交到 main
```
chore: release v$ARGUMENTS
```
## 6. 打 tag
```bash
git tag v$ARGUMENTS
```
## 7. 推送
```bash
git push ssh://git@git.51yanmei.com:2222/wangjia/jiu.git main v$ARGUMENTS
```
推送成功后提示用户:CI/CD 已触发,等待 Telegram 通知。
+8
View File
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.2] - 2026-05-25
### 改进
- 添加 /release 本地发版 slash command,一键完成构建、测试、打 tag 和推送
### 修复
- Web 版打印弹窗被浏览器拦截时,由静默失败改为给出明确提示,并自动上报错误
## [1.0.1] - 2026-05-25
### 改进
+52
View File
@@ -251,3 +251,55 @@ cd client && flutter test
tx.Set("gorm:query_option", "FOR UPDATE").Where(...).First(&model)
```
- 适用场景:单号生成(`number_rules`)、库存扣减(`inventories`)、任何 check-then-act 模式
### 发版流程
使用 `/release <version>` slash command
```
/release 1.0.2
```
执行顺序:本地 build → test → 更新 CHANGELOG.md → git commit → tag → push main+tag。
CI/CDForgejo)收到 tag 后自动:编译 → 测试 → 创建 Release → 部署 EC2 → Telegram 通知。
**CHANGELOG 格式**Keep a Changelog):
```markdown
## [1.0.2] - YYYY-MM-DD
### 新功能
- ...
### 改进
- ...
### 修复
- ...
```
只保留有内容的分类。`/release` 会检查 CHANGELOG 是否已有该版本节,没有则从 git log 自动生成。
### 异常上报
客户端异常已在两处统一捕获,**无需**在每个业务层重复处理:
- `main.dart``FlutterError.onError` + `runZonedGuarded` 捕获所有未处理异常
- `api_client.dart`:Dio 拦截器自动上报所有 HTTP 5xx 错误
需要**手动调用** `reportError(e, st)` 的场景:
- 技术性异常(JSON 解析失败、第三方 SDK 崩溃等)
- **不需要**上报:`AppException` 及其子类(已知业务错误)
```dart
} catch (e, st) {
reportError(e, st); // 一行,fire-and-forget
rethrow;
}
```
### 搜索实现(拼音)
商品名搜索同时支持汉字、全拼、首字母:
- `products` 表有 `name_pinyin`(全拼)和 `name_initials`(首字母)两列
- Create / Update / FindOrCreate 写入时自动调用 `util.ToPinyin()` 生成,**无需手动维护**
- 启动时对 `name_pinyin = ''` 的存量数据自动回填(`backfillPinyin`
- 库存搜索 SQL 同时 LIKE 匹配 name、code、name_pinyin、name_initials
- 新增其他需要拼音搜索的实体时,复用 `backend/internal/util/pinyin.go` 的 `ToPinyin()`
+1 -1
View File
@@ -15,7 +15,7 @@ migration:
- platform: root
create_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
base_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
- platform: web
- platform: android
create_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
base_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
+23 -6
View File
@@ -4,13 +4,15 @@ import 'dart:typed_data';
import 'package:web/web.dart' as web;
import '../../models/stock_in.dart';
import '../../models/stock_out.dart';
import '../errors/error_reporter.dart';
void _openPrintWindow(String html) {
final win = web.window.open('', '_blank');
if (win != null) {
win.document.write(html.toJS);
win.document.close();
if (win == null) {
throw Exception('浏览器已拦截弹窗,请在地址栏允许弹窗后重试');
}
win.document.write(html.toJS);
win.document.close();
}
Future<void> printProductLabelImpl({
@@ -187,7 +189,12 @@ body { width: 4in; height: 2in; overflow: hidden; background: #fff; }
</body>
</html>''';
_openPrintWindow(html);
try {
_openPrintWindow(html);
} catch (e, st) {
reportError(e, st);
rethrow;
}
}
// ── 入库单 ──────────────────────────────────────────────────────────────────
@@ -293,7 +300,12 @@ Future<void> printStockInOrderImpl(StockInOrder order) async {
</body>
</html>''';
_openPrintWindow(html);
try {
_openPrintWindow(html);
} catch (e, st) {
reportError(e, st);
rethrow;
}
}
// ── 出库单 ──────────────────────────────────────────────────────────────────
@@ -396,5 +408,10 @@ Future<void> printStockOutOrderImpl(StockOutOrder order) async {
</body>
</html>''';
_openPrintWindow(html);
try {
_openPrintWindow(html);
} catch (e, st) {
reportError(e, st);
rethrow;
}
}