Compare commits

..

4 Commits

Author SHA1 Message Date
wangjia 5725e84971 fix(nginx): 增加上传文件大小限制至 20MB
Deploy / deploy (push) Successful in 1m16s
默认 1MB 导致 Excel 文件上传返回 413。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:03:21 +08:00
wangjia 86baaf3a1c fix(model): users 唯一索引改为 (shop_id, username) 复合索引
Deploy / deploy (push) Successful in 1m13s
原来 uniqueIndex:uk_shop_username 只在 Username 字段上,导致用户名全局唯一。
S002/S003 的 admin 用户与 S001 冲突,INSERT 被静默跳过,无法登录。

将 User 的 TenantBase 改为直接定义 ShopID,使其参与复合唯一索引。
需要 Reset DB 使新索引生效。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:50:34 +08:00
wangjia fcf92675b1 fix(seeds): 修复 clear_shop.sql collation 冲突
Deploy / deploy (push) Successful in 1m13s
用 BINARY 比较绕过 utf8mb4_unicode_ci 与 utf8mb4_0900_ai_ci 的冲突。
shop code 均为纯 ASCII,BINARY 比较结果完全一致。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:34:14 +08:00
wangjia d81b2d1fac fix(seed.yml): 两步走避免 S001 因 id 冲突被跳过
Deploy / deploy (push) Successful in 1m17s
清空和写入分两个独立循环:先清空所有门店,再依次写入。
避免 S001(硬编码 id=1) 在 S002 尚未清除时被 INSERT IGNORE 跳过。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:30:46 +08:00
7 changed files with 25 additions and 16 deletions
+15 -6
View File
@@ -33,6 +33,21 @@ jobs:
SHOPS: ${{ github.event.inputs.shops }}
CLEAR: ${{ github.event.inputs.clear }}
run: |
# 第一步:若需要清空,先把所有门店都清掉再写入
# 避免 S001(id=1 硬编码) 因 S002 占用 id=1 而被 INSERT IGNORE 跳过
if [ "$CLEAR" = "true" ]; then
echo "=== 清空阶段 ==="
for SHOP in $(echo "$SHOPS" | tr ',' ' '); do
echo " 清空 ${SHOP}..."
printf "SET @shop_code='%s';\n" "$SHOP" | cat - backend/seeds/clear_shop.sql | \
ssh -i ~/.ssh/ec2_deploy.pem ${EC2_USER}@${EC2_HOST} \
"docker exec -i jiu_mysql mysql -uroot -p${DB_PASSWORD} --default-character-set=utf8mb4 jiu_db"
done
echo "✓ 清空完成"
fi
# 第二步:依次写入所有门店
echo "=== 写入阶段 ==="
for SHOP in $(echo "$SHOPS" | tr ',' ' '); do
FILE="backend/seeds/${SHOP}.sql"
if [ ! -f "$FILE" ]; then
@@ -40,12 +55,6 @@ jobs:
continue
fi
echo "→ Seeding $SHOP ..."
if [ "$CLEAR" = "true" ]; then
echo " 清空 ${SHOP} 数据..."
printf "SET @shop_code='%s';\n" "$SHOP" | cat - backend/seeds/clear_shop.sql | \
ssh -i ~/.ssh/ec2_deploy.pem ${EC2_USER}@${EC2_HOST} \
"docker exec -i jiu_mysql mysql -uroot -p${DB_PASSWORD} --default-character-set=utf8mb4 jiu_db"
fi
ssh -i ~/.ssh/ec2_deploy.pem ${EC2_USER}@${EC2_HOST} \
"docker exec -i jiu_mysql mysql -uroot -p${DB_PASSWORD} --default-character-set=utf8mb4 jiu_db" \
< "$FILE"
+3 -3
View File
@@ -132,21 +132,21 @@ func main() {
hash := mustHash("password123")
admin := upsert(db, &model.User{}, "shop_id = ? AND username = ?", shop.ID, "admin", func() any {
return &model.User{
TenantBase: model.TenantBase{ShopID: shop.ID},
ShopID: shop.ID,
Username: "admin", PasswordHash: hash, RealName: "张三(管理员)",
Phone: "13800000001", Role: "admin", IsActive: true,
}
}).(model.User)
operator := upsert(db, &model.User{}, "shop_id = ? AND username = ?", shop.ID, "operator", func() any {
return &model.User{
TenantBase: model.TenantBase{ShopID: shop.ID},
ShopID: shop.ID,
Username: "operator", PasswordHash: hash, RealName: "李四(操作员)",
Phone: "13800000002", Role: "operator", IsActive: true,
}
}).(model.User)
upsert(db, &model.User{}, "shop_id = ? AND username = ?", shop.ID, "test", func() any {
return &model.User{
TenantBase: model.TenantBase{ShopID: shop.ID},
ShopID: shop.ID,
Username: "test", PasswordHash: hash, RealName: "王五(只读)",
Phone: "13800000003", Role: "readonly", IsActive: true,
}
+1 -1
View File
@@ -52,7 +52,7 @@ func (h *UserHandler) Create(c *gin.Context) {
role = "operator"
}
u := model.User{
TenantBase: model.TenantBase{ShopID: shopID},
ShopID: shopID,
Username: req.Username,
PasswordHash: string(hash),
RealName: req.RealName,
+2 -1
View File
@@ -1,7 +1,8 @@
package model
type User struct {
TenantBase
Base
ShopID uint64 `gorm:"not null;index;uniqueIndex:uk_shop_username" json:"shop_id"`
Username string `gorm:"size:50;uniqueIndex:uk_shop_username" json:"username"`
PasswordHash string `gorm:"size:255" json:"-"`
RealName string `gorm:"size:50" json:"real_name"`
+1 -1
View File
@@ -4,7 +4,7 @@
-- 或由脚本拼接:
-- echo "SET @shop_code='S001';" | cat - clear_shop.sql | mysql ...
SET @sid = (SELECT id FROM shops WHERE code = @shop_code LIMIT 1);
SET @sid = (SELECT id FROM shops WHERE BINARY code = BINARY @shop_code LIMIT 1);
SET FOREIGN_KEY_CHECKS = 0;
+1 -4
View File
@@ -349,10 +349,7 @@ func hashPassword(plain string) string {
func CreateTestUser(db *gorm.DB, shopID uint64, username, password, role string) *model.User {
hash := hashPassword(password)
user := &model.User{
TenantBase: model.TenantBase{
Base: model.Base{},
ShopID: shopID,
},
ShopID: shopID,
Username: username,
PasswordHash: hash,
RealName: "Test User " + username,
+2
View File
@@ -7,6 +7,8 @@ server {
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 20m;
# 商品图片静态文件
location ^~ /images/ {
alias /opt/jiu/images/;