Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 02082df525 | |||
| 4c75f328c7 | |||
| 8628df5848 |
@@ -5,6 +5,24 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.35] - 2026-06-12
|
||||||
|
|
||||||
|
### 改进
|
||||||
|
- Debug 版本窗口标题增加 [DEBUG] 后缀,便于与正式安装版区分
|
||||||
|
|
||||||
|
## [1.0.34] - 2026-06-12
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- 修复 macOS 客户端打印时应用卡死、只能强制退出的问题
|
||||||
|
|
||||||
|
### 改进
|
||||||
|
- 「关于我们」中「打开文档」「更新日志」等链接指向新域名 jiu.51yanmei.com
|
||||||
|
|
||||||
|
## [1.0.33] - 2026-06-12
|
||||||
|
|
||||||
|
### 改进
|
||||||
|
- macOS 客户端插件集成从 CocoaPods 迁移至 Swift Package Manager,优化 macOS 构建流程
|
||||||
|
|
||||||
## [1.0.32] - 2026-06-11
|
## [1.0.32] - 2026-06-11
|
||||||
|
|
||||||
### 修复
|
### 修复
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"provider": "岩美技术有限公司",
|
"provider": "岩美技术有限公司",
|
||||||
"website": "https://jiu.yanmei.com",
|
"website": "https://jiu.51yanmei.com",
|
||||||
"email": "yammy2023@163.com",
|
"email": "yammy2023@163.com",
|
||||||
"phone": "",
|
"phone": "",
|
||||||
"wechat": "",
|
"wechat": "",
|
||||||
"terms_url": "https://jiu.yanmei.com/terms/",
|
"terms_url": "https://jiu.51yanmei.com/terms/",
|
||||||
"privacy_url": "https://jiu.yanmei.com/privacy/",
|
"privacy_url": "https://jiu.51yanmei.com/privacy/",
|
||||||
"docs_url": "https://jiu.yanmei.com/docs/"
|
"docs_url": "https://jiu.51yanmei.com/docs/"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io' show Platform;
|
||||||
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../errors/error_reporter.dart';
|
import '../errors/error_reporter.dart';
|
||||||
import 'package:pdf/pdf.dart';
|
import 'package:pdf/pdf.dart';
|
||||||
@@ -198,8 +200,14 @@ Future<void> printProductLabelImpl({
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// 预生成 PDF 字节,避免 macOS NSPrintPanel 打开后再调 doc.save() 导致主线程卡住。
|
||||||
|
final bytes = await doc.save();
|
||||||
|
if (!kIsWeb && Platform.isMacOS) {
|
||||||
|
// 让当前帧完成,再打开 macOS 原生打印面板,防止 sheet 动画与 Flutter 渲染死锁。
|
||||||
|
await Future<void>.delayed(Duration.zero);
|
||||||
|
}
|
||||||
await Printing.layoutPdf(
|
await Printing.layoutPdf(
|
||||||
name: '标签_${_fileTs()}', onLayout: (_) async => doc.save());
|
name: '标签_${_fileTs()}', onLayout: (_) async => bytes);
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
reportError(e, st);
|
reportError(e, st);
|
||||||
throw Exception('打印失败,请检查打印机连接和驱动是否正常。\n详情:$e');
|
throw Exception('打印失败,请检查打印机连接和驱动是否正常。\n详情:$e');
|
||||||
@@ -439,8 +447,12 @@ Future<void> printStockInOrderImpl(StockInOrder order) async {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
final bytes = await doc.save();
|
||||||
|
if (!kIsWeb && Platform.isMacOS) {
|
||||||
|
await Future<void>.delayed(Duration.zero);
|
||||||
|
}
|
||||||
await Printing.layoutPdf(
|
await Printing.layoutPdf(
|
||||||
name: '入库单_${_fileTs()}', onLayout: (_) async => doc.save());
|
name: '入库单_${_fileTs()}', onLayout: (_) async => bytes);
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
reportError(e, st);
|
reportError(e, st);
|
||||||
throw Exception('打印失败,请检查打印机连接和驱动是否正常。\n详情:$e');
|
throw Exception('打印失败,请检查打印机连接和驱动是否正常。\n详情:$e');
|
||||||
@@ -495,8 +507,12 @@ Future<void> printStockOutOrderImpl(StockOutOrder order) async {
|
|||||||
],
|
],
|
||||||
));
|
));
|
||||||
try {
|
try {
|
||||||
|
final bytes = await doc.save();
|
||||||
|
if (!kIsWeb && Platform.isMacOS) {
|
||||||
|
await Future<void>.delayed(Duration.zero);
|
||||||
|
}
|
||||||
await Printing.layoutPdf(
|
await Printing.layoutPdf(
|
||||||
name: '出库单_${_fileTs()}', onLayout: (_) async => doc.save());
|
name: '出库单_${_fileTs()}', onLayout: (_) async => bytes);
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
reportError(e, st);
|
reportError(e, st);
|
||||||
throw Exception('打印失败,请检查打印机连接和驱动是否正常。\n详情:$e');
|
throw Exception('打印失败,请检查打印机连接和驱动是否正常。\n详情:$e');
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -107,7 +108,7 @@ class _JiuAppState extends ConsumerState<JiuApp> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final router = ref.watch(appRouterProvider);
|
final router = ref.watch(appRouterProvider);
|
||||||
return MaterialApp.router(
|
return MaterialApp.router(
|
||||||
title: '岩美',
|
title: kDebugMode ? '岩美 [DEBUG]' : '岩美',
|
||||||
theme: AppTheme.light(),
|
theme: AppTheme.light(),
|
||||||
routerConfig: router,
|
routerConfig: router,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
|
|||||||
@@ -1,46 +1,21 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- file_picker (0.0.1):
|
|
||||||
- FlutterMacOS
|
|
||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
- package_info_plus (0.0.1):
|
|
||||||
- FlutterMacOS
|
|
||||||
- printing (1.0.0):
|
- printing (1.0.0):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- shared_preferences_foundation (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- FlutterMacOS
|
|
||||||
- url_launcher_macos (0.0.1):
|
|
||||||
- FlutterMacOS
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
|
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
|
||||||
- printing (from `Flutter/ephemeral/.symlinks/plugins/printing/macos`)
|
- printing (from `Flutter/ephemeral/.symlinks/plugins/printing/macos`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
|
||||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
file_picker:
|
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
|
|
||||||
FlutterMacOS:
|
FlutterMacOS:
|
||||||
:path: Flutter/ephemeral
|
:path: Flutter/ephemeral
|
||||||
package_info_plus:
|
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
|
||||||
printing:
|
printing:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/printing/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/printing/macos
|
||||||
shared_preferences_foundation:
|
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
|
||||||
url_launcher_macos:
|
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
|
||||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
|
|
||||||
printing: c4cf83c78fd684f9bc318e6aadc18972aa48f617
|
printing: c4cf83c78fd684f9bc318e6aadc18972aa48f617
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
|
||||||
url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
||||||
7CC0DF083710AA9C43B56A42 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B35335B030AEE727449F09D5 /* Pods_Runner.framework */; };
|
7CC0DF083710AA9C43B56A42 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B35335B030AEE727449F09D5 /* Pods_Runner.framework */; };
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
B35335B030AEE727449F09D5 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
B35335B030AEE727449F09D5 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B6FABD6521DBD25CA93F2ABB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
B6FABD6521DBD25CA93F2ABB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
D768E6B98F41FC79E2D5D343 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
D768E6B98F41FC79E2D5D343 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -103,6 +105,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||||
7CC0DF083710AA9C43B56A42 /* Pods_Runner.framework in Frameworks */,
|
7CC0DF083710AA9C43B56A42 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -164,6 +167,7 @@
|
|||||||
33CEB47122A05771004F2AC0 /* Flutter */ = {
|
33CEB47122A05771004F2AC0 /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
|
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
|
||||||
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
|
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
|
||||||
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
|
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
|
||||||
@@ -231,6 +235,9 @@
|
|||||||
productType = "com.apple.product-type.bundle.unit-test";
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
};
|
};
|
||||||
33CC10EC2044A3C60003C045 /* Runner */ = {
|
33CC10EC2044A3C60003C045 /* Runner */ = {
|
||||||
|
packageProductDependencies = (
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
|
);
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
@@ -256,6 +263,9 @@
|
|||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
33CC10E52044A3C60003C045 /* Project object */ = {
|
33CC10E52044A3C60003C045 /* Project object */ = {
|
||||||
|
packageReferences = (
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||||
|
);
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
@@ -796,6 +806,18 @@
|
|||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||||
|
isa = XCLocalSwiftPackageReference;
|
||||||
|
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCLocalSwiftPackageReference section */
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
|
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,24 @@
|
|||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES">
|
||||||
|
<PreActions>
|
||||||
|
<ExecutionAction
|
||||||
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||||
|
<ActionContent
|
||||||
|
title = "Run Prepare Flutter Framework Script"
|
||||||
|
scriptText = ""$FLUTTER_ROOT"/packages/flutter_tools/bin/macos_assemble.sh prepare ">
|
||||||
|
<EnvironmentBuildable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
||||||
|
BuildableName = "jiu_client.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</EnvironmentBuildable>
|
||||||
|
</ActionContent>
|
||||||
|
</ExecutionAction>
|
||||||
|
</PreActions>
|
||||||
<BuildActionEntries>
|
<BuildActionEntries>
|
||||||
<BuildActionEntry
|
<BuildActionEntry
|
||||||
buildForTesting = "YES"
|
buildForTesting = "YES"
|
||||||
|
|||||||
+406
-126
@@ -223,10 +223,10 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
<h1>酒库管理系统 — 项目 TODO</h1>
|
<h1>酒库管理系统 — 项目 TODO</h1>
|
||||||
<div class="header-meta">生成于 2026-06-11 · 真相源 todo/todo.json</div>
|
<div class="header-meta">生成于 2026-06-11 · 真相源 todo/todo.json</div>
|
||||||
<div class="stats">
|
<div class="stats">
|
||||||
<div class="stat-pill"><strong>36</strong>全部</div>
|
<div class="stat-pill"><strong>46</strong>全部</div>
|
||||||
<div class="stat-pill"><strong>5</strong>待开始</div>
|
<div class="stat-pill"><strong>1</strong>待开始</div>
|
||||||
<div class="stat-pill"><strong>0</strong>开发中</div>
|
<div class="stat-pill"><strong>0</strong>开发中</div>
|
||||||
<div class="stat-pill"><strong>17</strong>待验收</div>
|
<div class="stat-pill"><strong>31</strong>待验收</div>
|
||||||
<div class="stat-pill"><strong>14</strong>已验收</div>
|
<div class="stat-pill"><strong>14</strong>已验收</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -260,7 +260,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
<div class="filter-sep"></div>
|
<div class="filter-sep"></div>
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<span class="filter-label">平台 / 标签</span>
|
<span class="filter-label">平台 / 标签</span>
|
||||||
<button class="filter-chip" data-filter-tag="Android">Android</button><button class="filter-chip" data-filter-tag="Web">Web</button><button class="filter-chip" data-filter-tag="Windows">Windows</button><button class="filter-chip" data-filter-tag="iOS">iOS</button><button class="filter-chip" data-filter-tag="mac">mac</button><button class="filter-chip" data-filter-tag="前端">前端</button><button class="filter-chip" data-filter-tag="后端">后端</button><button class="filter-chip" data-filter-tag="安全">安全</button><button class="filter-chip" data-filter-tag="数据库">数据库</button><button class="filter-chip" data-filter-tag="文档">文档</button>
|
<button class="filter-chip" data-filter-tag="Android">Android</button><button class="filter-chip" data-filter-tag="CI/CD">CI/CD</button><button class="filter-chip" data-filter-tag="Web">Web</button><button class="filter-chip" data-filter-tag="Windows">Windows</button><button class="filter-chip" data-filter-tag="iOS">iOS</button><button class="filter-chip" data-filter-tag="mac">mac</button><button class="filter-chip" data-filter-tag="前端">前端</button><button class="filter-chip" data-filter-tag="后端">后端</button><button class="filter-chip" data-filter-tag="安全">安全</button><button class="filter-chip" data-filter-tag="数据库">数据库</button><button class="filter-chip" data-filter-tag="文档">文档</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -269,147 +269,35 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
|
|
||||||
<div class="section-block" id="section-open">
|
<div class="section-block" id="section-open">
|
||||||
<div class="section-title st-open" data-toggle="open">
|
<div class="section-title st-open" data-toggle="open">
|
||||||
📋 待开始 <span class="s-count">5</span>
|
📋 待开始 <span class="s-count">1</span>
|
||||||
<span class="s-arrow">▴ 收起</span>
|
<span class="s-arrow">▴ 收起</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-list-wrap " id="list-wrap-open">
|
<div class="section-list-wrap " id="list-wrap-open">
|
||||||
<ul class="todo-list" id="list-open">
|
<ul class="todo-list" id="list-open">
|
||||||
|
|
||||||
<li class="todo-card s-open"
|
<li class="todo-card s-open"
|
||||||
data-id="2"
|
data-id="50"
|
||||||
data-level="high"
|
data-level="mid"
|
||||||
data-status="open"
|
|
||||||
data-tier=""
|
|
||||||
data-tags="Web">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="item-title">备案号为占位假值</span>
|
|
||||||
<div class="card-badges">
|
|
||||||
<span class="tag status-badge s-open">待开始</span>
|
|
||||||
<span class="tag t-block">高优 · 紧急</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-desc">现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。</div>
|
|
||||||
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="tag-row"><span class="tag t-tag" data-tag="Web">Web</span></div>
|
|
||||||
<div class="item-meta">
|
|
||||||
<span class="meta-date">🕐 2026-06-08</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="todo-card s-open"
|
|
||||||
data-id="23"
|
|
||||||
data-level="low"
|
|
||||||
data-status="open"
|
|
||||||
data-tier=""
|
|
||||||
data-tags="前端,Web">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="item-title">注册/联系入口「发邮件」升级为「加客服微信」并优化文案</span>
|
|
||||||
<div class="card-badges">
|
|
||||||
<span class="tag status-badge s-open">待开始</span>
|
|
||||||
<span class="tag t-low">一般 / 优化</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-desc">当前注册成功页和网站联系支持入口引导用户「发邮件」,体验较弱。升级为扫码加客服微信,同时梳理相关文案措辞,使表达更专业、有亲和力。</div>
|
|
||||||
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
|
||||||
<div class="item-meta">
|
|
||||||
<span class="meta-date">🕐 2026-06-08</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="todo-card s-open"
|
|
||||||
data-id="38"
|
|
||||||
data-level="low"
|
|
||||||
data-status="open"
|
data-status="open"
|
||||||
data-tier="3"
|
data-tier="3"
|
||||||
data-tags="后端">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="item-title">将拼音回填从启动逻辑改为一次性迁移脚本</span>
|
|
||||||
<div class="card-badges">
|
|
||||||
<span class="tag status-badge s-open">待开始</span>
|
|
||||||
<span class="tag t-low">一般 / 优化</span>
|
|
||||||
<span class="tag tier-3">三级</span>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-desc">main.go 每次启动执行 backfillPinyin 全表扫描,数据量大后拖慢启动。改为 go run ./cmd/migrate-pinyin 一次性迁移,后续新数据靠写入时自动生成</div>
|
|
||||||
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
|
||||||
<div class="item-meta">
|
|
||||||
<span class="meta-date">🕐 2026-06-10</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="todo-card s-open"
|
|
||||||
data-id="39"
|
|
||||||
data-level="low"
|
|
||||||
data-status="open"
|
|
||||||
data-tier="3"
|
|
||||||
data-tags="后端">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="item-title">DB 连接池参数(MaxIdleConns/MaxOpenConns)改为可配置项</span>
|
|
||||||
<div class="card-badges">
|
|
||||||
<span class="tag status-badge s-open">待开始</span>
|
|
||||||
<span class="tag t-low">一般 / 优化</span>
|
|
||||||
<span class="tag tier-3">三级</span>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-desc">main.go 中硬编码 MaxIdleConns=10, MaxOpenConns=100,无法运维调优。改为读取 config(viper),并在文档中说明推荐值</div>
|
|
||||||
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
|
||||||
<div class="item-meta">
|
|
||||||
<span class="meta-date">🕐 2026-06-10</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="todo-card s-open"
|
|
||||||
data-id="40"
|
|
||||||
data-level="low"
|
|
||||||
data-status="open"
|
|
||||||
data-tier="2"
|
|
||||||
data-tags="后端,数据库">
|
data-tags="后端,数据库">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="item-title">明确 Inventories 反范式字段语义:是当前值还是入库快照</span>
|
<span class="item-title">License model 的 license_key 索引超 InnoDB 3072 字节限制需改用前缀索引</span>
|
||||||
<div class="card-badges">
|
<div class="card-badges">
|
||||||
<span class="tag status-badge s-open">待开始</span>
|
<span class="tag status-badge s-open">待开始</span>
|
||||||
<span class="tag t-low">一般 / 优化</span>
|
<span class="tag t-high">重要</span>
|
||||||
<span class="tag tier-2">二级</span>
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="item-desc">inventories 表存了 product_name/warehouse_name/supplier_name 等,既可能是冗余(与 products JOIN 重复),也可能是历史快照(入库时锁定)。需明确语义并在 model 注释中说明;若是快照,应只在写入时固定,不随主表变化</div>
|
<div class="item-desc">license.go 的 LicenseKey 是 size:2048+uniqueIndex,utf8mb4 下 8192 字节超 MySQL InnoDB 索引上限,全新环境 AutoMigrate 必失败(线上已手动建 license_key(768) 前缀索引绕过)。需在 model 层固化:缩短列或 GORM 指定索引前缀长度,并同步 schema.sql。</div>
|
||||||
|
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="数据库">数据库</span></div>
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="数据库">数据库</span></div>
|
||||||
<div class="item-meta">
|
<div class="item-meta">
|
||||||
<span class="meta-date">🕐 2026-06-10</span>
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -430,7 +318,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
</div>
|
</div>
|
||||||
<div class="section-block" id="section-done">
|
<div class="section-block" id="section-done">
|
||||||
<div class="section-title st-done" data-toggle="done">
|
<div class="section-title st-done" data-toggle="done">
|
||||||
🔍 待验收 <span class="s-count">17</span>
|
🔍 待验收 <span class="s-count">31</span>
|
||||||
<span class="s-arrow">▴ 收起</span>
|
<span class="s-arrow">▴ 收起</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-list-wrap " id="list-wrap-done">
|
<div class="section-list-wrap " id="list-wrap-done">
|
||||||
@@ -548,6 +436,62 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="41"
|
||||||
|
data-level="high"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">CheckInventoryAvailability Scan错误未检查导致所有商品误报库存不足</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-block">高优 · 紧急</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="41" data-title="CheckInventoryAvailability Scan错误未检查导致所有商品误报库存不足">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">service/stock.go:312 DB查询失败时sums为空,所有商品have=0,合法出库审核被全部拒绝</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="49"
|
||||||
|
data-level="high"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="2"
|
||||||
|
data-tags="CI/CD">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">修复 act_runner→Forgejo 任务状态上报丢失导致构建成功却标失败</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-block">高优 · 紧急</span>
|
||||||
|
<span class="tag tier-2">二级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="49" data-title="修复 act_runner→Forgejo 任务状态上报丢失导致构建成功却标失败">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">v1.0.27~v1.0.32 连续 6 个版本 CI 全部'失败',但日志显示所有 job 实际构建成功(🏁 Job succeeded),是 act_runner 最终状态上报丢失(Failed to write EOT),被 Forgejo 僵尸任务清理标为 failure。生产环境因此停留在 v1.0.26(6/8)。需排查 relay/GOAWAY race 或升级 act_runner/Forgejo。</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="CI/CD">CI/CD</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="todo-card s-done"
|
<li class="todo-card s-done"
|
||||||
data-id="20"
|
data-id="20"
|
||||||
data-level="mid"
|
data-level="mid"
|
||||||
@@ -772,6 +716,118 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="42"
|
||||||
|
data-level="mid"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">finance ListRecords 和 inventory Logs handler 缺 pageSize 上限</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-high">重要</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="42" data-title="finance ListRecords 和 inventory Logs handler 缺 pageSize 上限">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">finance.go:36 和 inventory.go:130 漏加 ValidatePageSize,#37 未覆盖这两个 handler,可被任意用户触发全表扫描</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="43"
|
||||||
|
data-level="mid"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">ReconcileInventory 两条 Scan 错误未检查导致对账误判</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-high">重要</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="43" data-title="ReconcileInventory 两条 Scan 错误未检查导致对账误判">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">admin.go:122-123 invQuery/logQuery Scan错误被丢弃;invQuery失败→差异消失显示全部正常;logQuery失败→所有库存飘红为差异</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="44"
|
||||||
|
data-level="mid"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">license Info 端点 device_count 统计错误且 ListDevices 错误被吞</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-high">重要</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="44" data-title="license Info 端点 device_count 统计错误且 ListDevices 错误被吞">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">handler/license.go:67-70 两个bug:1.devs,_ 错误被_吞掉DB故障时deviceCount=0;2.ListDevices(shopID)包含该店所有license设备而非当前license</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="2"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier=""
|
||||||
|
data-tags="Web">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">备案号为占位假值</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="2" data-title="备案号为占位假值">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="Web">Web</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-08</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="todo-card s-done"
|
<li class="todo-card s-done"
|
||||||
data-id="21"
|
data-id="21"
|
||||||
data-level="low"
|
data-level="low"
|
||||||
@@ -882,6 +938,34 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="23"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier=""
|
||||||
|
data-tags="前端,Web">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">注册/联系入口「发邮件」升级为「加客服微信」并优化文案</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="23" data-title="注册/联系入口「发邮件」升级为「加客服微信」并优化文案">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">当前注册成功页和网站联系支持入口引导用户「发邮件」,体验较弱。升级为扫码加客服微信,同时梳理相关文案措辞,使表达更专业、有亲和力。</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="前端">前端</span> <span class="tag t-tag" data-tag="Web">Web</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-08</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="todo-card s-done"
|
<li class="todo-card s-done"
|
||||||
data-id="24"
|
data-id="24"
|
||||||
data-level="low"
|
data-level="low"
|
||||||
@@ -962,6 +1046,202 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
<div class="item-meta">
|
<div class="item-meta">
|
||||||
<span class="meta-date">🕐 2026-06-08</span>
|
<span class="meta-date">🕐 2026-06-08</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="38"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">将拼音回填从启动逻辑改为一次性迁移脚本</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="38" data-title="将拼音回填从启动逻辑改为一次性迁移脚本">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">main.go 每次启动执行 backfillPinyin 全表扫描,数据量大后拖慢启动。改为 go run ./cmd/migrate-pinyin 一次性迁移,后续新数据靠写入时自动生成</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-10</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="39"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">DB 连接池参数(MaxIdleConns/MaxOpenConns)改为可配置项</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="39" data-title="DB 连接池参数(MaxIdleConns/MaxOpenConns)改为可配置项">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">main.go 中硬编码 MaxIdleConns=10, MaxOpenConns=100,无法运维调优。改为读取 config(viper),并在文档中说明推荐值</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-10</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="40"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="2"
|
||||||
|
data-tags="后端,数据库">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">明确 Inventories 反范式字段语义:是当前值还是入库快照</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-2">二级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="40" data-title="明确 Inventories 反范式字段语义:是当前值还是入库快照">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">inventories 表存了 product_name/warehouse_name/supplier_name 等,既可能是冗余(与 products JOIN 重复),也可能是历史快照(入库时锁定)。需明确语义并在 model 注释中说明;若是快照,应只在写入时固定,不随主表变化</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="数据库">数据库</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-10</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="45"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">license Activate 幂等路径 Update 错误未检查</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="45" data-title="license Activate 幂等路径 Update 错误未检查">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">service/license.go:70 s.db.Model(&existing).Update()失败时仍返回nil error,设备名未更新但调用方不知道</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="46"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">license Verify 加载 license 缺 shop_id 过滤(防御纵深)</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="46" data-title="license Verify 加载 license 缺 shop_id 过滤(防御纵深)">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">service/license.go:102 WHERE id=? AND is_active=1 应加 AND shop_id=? 防御数据异常时跨租户泄露</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="47"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="2"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">util/response.go 的 RespondError 等辅助函数从未被调用(#34 实际未完成)</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-2">二级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="47" data-title="util/response.go 的 RespondError 等辅助函数从未被调用(#34 实际未完成)">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">#34 只创建了util/response.go,没有将任何handler迁移过去,实际错误格式仍不统一,需完成迁移</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="todo-card s-done"
|
||||||
|
data-id="48"
|
||||||
|
data-level="low"
|
||||||
|
data-status="done"
|
||||||
|
data-tier="3"
|
||||||
|
data-tags="后端">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="item-title">清理 ErrDeviceMismatch 死代码(多设备迁移后残留)</span>
|
||||||
|
<div class="card-badges">
|
||||||
|
<span class="tag status-badge s-done">待验收</span>
|
||||||
|
<span class="tag t-low">一般 / 优化</span>
|
||||||
|
<span class="tag tier-3">三级</span>
|
||||||
|
|
||||||
|
<button class="reject-btn" data-id="48" data-title="清理 ErrDeviceMismatch 死代码(多设备迁移后残留)">拒绝验收</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-desc">service/license.go:24 ErrDeviceMismatch定义后从未返回,多设备迁移(#32)后已无单设备约束</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<span class="meta-date">🕐 2026-06-11</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@@ -1521,7 +1801,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const escaped = reason.replace(/\/g, '\\').replace(/"/g, '\"');
|
const escaped = reason.replace(/\/g, '\\').replace(/"/g, '\"');
|
||||||
const cmd = 'node todo/todo.mjs reject ' + rejectId + ' --reason "' + escaped + '"';
|
const cmd = '/todo reject ' + rejectId + ' ' + escaped;
|
||||||
cmdText.textContent = cmd;
|
cmdText.textContent = cmd;
|
||||||
cmdWrap.style.display = 'block';
|
cmdWrap.style.display = 'block';
|
||||||
document.getElementById('reject-confirm-btn').style.display = 'none';
|
document.getElementById('reject-confirm-btn').style.display = 'none';
|
||||||
|
|||||||
+159
-8
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"title": "酒库管理系统 — 项目 TODO",
|
"title": "酒库管理系统 — 项目 TODO",
|
||||||
"updated_at": "2026-06-10T16:38:37.763Z"
|
"updated_at": "2026-06-11T15:52:40.354Z"
|
||||||
},
|
},
|
||||||
"seq": 40,
|
"seq": 50,
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
"id": 2,
|
"id": 2,
|
||||||
"title": "备案号为占位假值",
|
"title": "备案号为占位假值",
|
||||||
"desc": "现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。",
|
"desc": "现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。",
|
||||||
"level": "high",
|
"level": "low",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Web"
|
"Web"
|
||||||
],
|
],
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"done": false,
|
"done": false,
|
||||||
"completed_at": null,
|
"completed_at": null,
|
||||||
"version": null,
|
"version": null,
|
||||||
"status": "open"
|
"status": "done"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
@@ -404,7 +404,7 @@
|
|||||||
"done": false,
|
"done": false,
|
||||||
"completed_at": null,
|
"completed_at": null,
|
||||||
"version": null,
|
"version": null,
|
||||||
"status": "open"
|
"status": "done"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 24,
|
"id": 24,
|
||||||
@@ -613,7 +613,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"后端"
|
"后端"
|
||||||
],
|
],
|
||||||
"status": "open",
|
"status": "done",
|
||||||
"created_at": "2026-06-10T15:31:57.979Z",
|
"created_at": "2026-06-10T15:31:57.979Z",
|
||||||
"done": false,
|
"done": false,
|
||||||
"completed_at": null,
|
"completed_at": null,
|
||||||
@@ -628,7 +628,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"后端"
|
"后端"
|
||||||
],
|
],
|
||||||
"status": "open",
|
"status": "done",
|
||||||
"created_at": "2026-06-10T15:32:00.233Z",
|
"created_at": "2026-06-10T15:32:00.233Z",
|
||||||
"done": false,
|
"done": false,
|
||||||
"completed_at": null,
|
"completed_at": null,
|
||||||
@@ -644,11 +644,162 @@
|
|||||||
"后端",
|
"后端",
|
||||||
"数据库"
|
"数据库"
|
||||||
],
|
],
|
||||||
"status": "open",
|
"status": "done",
|
||||||
"created_at": "2026-06-10T15:32:03.641Z",
|
"created_at": "2026-06-10T15:32:03.641Z",
|
||||||
"done": false,
|
"done": false,
|
||||||
"completed_at": null,
|
"completed_at": null,
|
||||||
"version": null
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 41,
|
||||||
|
"title": "CheckInventoryAvailability Scan错误未检查导致所有商品误报库存不足",
|
||||||
|
"desc": "service/stock.go:312 DB查询失败时sums为空,所有商品have=0,合法出库审核被全部拒绝",
|
||||||
|
"level": "high",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:34.919Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 42,
|
||||||
|
"title": "finance ListRecords 和 inventory Logs handler 缺 pageSize 上限",
|
||||||
|
"desc": "finance.go:36 和 inventory.go:130 漏加 ValidatePageSize,#37 未覆盖这两个 handler,可被任意用户触发全表扫描",
|
||||||
|
"level": "mid",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:46.152Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 43,
|
||||||
|
"title": "ReconcileInventory 两条 Scan 错误未检查导致对账误判",
|
||||||
|
"desc": "admin.go:122-123 invQuery/logQuery Scan错误被丢弃;invQuery失败→差异消失显示全部正常;logQuery失败→所有库存飘红为差异",
|
||||||
|
"level": "mid",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:46.205Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 44,
|
||||||
|
"title": "license Info 端点 device_count 统计错误且 ListDevices 错误被吞",
|
||||||
|
"desc": "handler/license.go:67-70 两个bug:1.devs,_ 错误被_吞掉DB故障时deviceCount=0;2.ListDevices(shopID)包含该店所有license设备而非当前license",
|
||||||
|
"level": "mid",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:46.257Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 45,
|
||||||
|
"title": "license Activate 幂等路径 Update 错误未检查",
|
||||||
|
"desc": "service/license.go:70 s.db.Model(&existing).Update()失败时仍返回nil error,设备名未更新但调用方不知道",
|
||||||
|
"level": "low",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:59.016Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 46,
|
||||||
|
"title": "license Verify 加载 license 缺 shop_id 过滤(防御纵深)",
|
||||||
|
"desc": "service/license.go:102 WHERE id=? AND is_active=1 应加 AND shop_id=? 防御数据异常时跨租户泄露",
|
||||||
|
"level": "low",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:59.066Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 47,
|
||||||
|
"title": "util/response.go 的 RespondError 等辅助函数从未被调用(#34 实际未完成)",
|
||||||
|
"desc": "#34 只创建了util/response.go,没有将任何handler迁移过去,实际错误格式仍不统一,需完成迁移",
|
||||||
|
"level": "low",
|
||||||
|
"tier": 2,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:59.118Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 48,
|
||||||
|
"title": "清理 ErrDeviceMismatch 死代码(多设备迁移后残留)",
|
||||||
|
"desc": "service/license.go:24 ErrDeviceMismatch定义后从未返回,多设备迁移(#32)后已无单设备约束",
|
||||||
|
"level": "low",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-10T23:59:59.168Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 49,
|
||||||
|
"title": "修复 act_runner→Forgejo 任务状态上报丢失导致构建成功却标失败",
|
||||||
|
"desc": "v1.0.27~v1.0.32 连续 6 个版本 CI 全部'失败',但日志显示所有 job 实际构建成功(🏁 Job succeeded),是 act_runner 最终状态上报丢失(Failed to write EOT),被 Forgejo 僵尸任务清理标为 failure。生产环境因此停留在 v1.0.26(6/8)。需排查 relay/GOAWAY race 或升级 act_runner/Forgejo。",
|
||||||
|
"level": "high",
|
||||||
|
"tier": 2,
|
||||||
|
"tags": [
|
||||||
|
"CI/CD"
|
||||||
|
],
|
||||||
|
"status": "done",
|
||||||
|
"created_at": "2026-06-11T13:55:07.388Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 50,
|
||||||
|
"title": "License model 的 license_key 索引超 InnoDB 3072 字节限制需改用前缀索引",
|
||||||
|
"desc": "license.go 的 LicenseKey 是 size:2048+uniqueIndex,utf8mb4 下 8192 字节超 MySQL InnoDB 索引上限,全新环境 AutoMigrate 必失败(线上已手动建 license_key(768) 前缀索引绕过)。需在 model 层固化:缩短列或 GORM 指定索引前缀长度,并同步 schema.sql。",
|
||||||
|
"level": "mid",
|
||||||
|
"tier": 3,
|
||||||
|
"tags": [
|
||||||
|
"后端",
|
||||||
|
"数据库"
|
||||||
|
],
|
||||||
|
"status": "open",
|
||||||
|
"created_at": "2026-06-11T15:52:40.353Z",
|
||||||
|
"done": false,
|
||||||
|
"completed_at": null,
|
||||||
|
"version": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user