工作时间支持自定义时段
设置页每日可选休息/全天/自定义时间范围(TimePicker),后端校验并规范化 HH:MM-HH:MM,补充跨午夜判定测试。
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"kefu-cloud/server/internal/model"
|
||||
)
|
||||
|
||||
func TestNormalizeWorkHourSlot(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{"", "", false},
|
||||
{" 休息 ", "", false},
|
||||
{"全天", "全天", false},
|
||||
{"09:00-18:00", "09:00-18:00", false},
|
||||
{" 9:30 - 18:05 ", "09:30-18:05", false},
|
||||
{"22:00-06:00", "22:00-06:00", false},
|
||||
{"全天营业", "", true},
|
||||
{"09:00", "", true},
|
||||
{"25:00-26:00", "", true},
|
||||
{"09:00-18:00-extra", "", true},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
got, err := normalizeWorkHourSlot(tc.in)
|
||||
if tc.wantErr {
|
||||
if err == nil {
|
||||
t.Fatalf("normalizeWorkHourSlot(%q) 期望错误,got=%q", tc.in, got)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("normalizeWorkHourSlot(%q) 意外错误: %v", tc.in, err)
|
||||
}
|
||||
if got != tc.want {
|
||||
t.Fatalf("normalizeWorkHourSlot(%q)=%q, want %q", tc.in, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlotCoversLocal(t *testing.T) {
|
||||
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 2026-03-16 周一
|
||||
mk := func(h, m int) time.Time {
|
||||
return time.Date(2026, 3, 16, h, m, 0, 0, loc)
|
||||
}
|
||||
|
||||
if !slotCoversLocal("全天", mk(3, 0), loc) {
|
||||
t.Fatal("全天应覆盖任意时刻")
|
||||
}
|
||||
if slotCoversLocal("", mk(10, 0), loc) {
|
||||
t.Fatal("空应视为休息")
|
||||
}
|
||||
if slotCoversLocal("休息", mk(10, 0), loc) {
|
||||
t.Fatal("休息应不覆盖")
|
||||
}
|
||||
// 09:00-18:00 半开区间 [start, end)
|
||||
if !slotCoversLocal("09:00-18:00", mk(9, 0), loc) {
|
||||
t.Fatal("09:00 应在工作时间内")
|
||||
}
|
||||
if !slotCoversLocal("09:00-18:00", mk(17, 59), loc) {
|
||||
t.Fatal("17:59 应在工作时间内")
|
||||
}
|
||||
if slotCoversLocal("09:00-18:00", mk(18, 0), loc) {
|
||||
t.Fatal("18:00 不应在工作时间内(半开)")
|
||||
}
|
||||
if slotCoversLocal("09:00-18:00", mk(8, 59), loc) {
|
||||
t.Fatal("08:59 不应在工作时间内")
|
||||
}
|
||||
// 跨午夜 22:00-06:00
|
||||
if !slotCoversLocal("22:00-06:00", mk(23, 0), loc) {
|
||||
t.Fatal("23:00 应在跨午夜时段内")
|
||||
}
|
||||
if !slotCoversLocal("22:00-06:00", mk(5, 0), loc) {
|
||||
t.Fatal("05:00 应在跨午夜时段内")
|
||||
}
|
||||
if slotCoversLocal("22:00-06:00", mk(12, 0), loc) {
|
||||
t.Fatal("12:00 不应在跨午夜时段内")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsWithinWorkHoursCustomRange(t *testing.T) {
|
||||
setting := &model.TenantSetting{
|
||||
Timezone: "Asia/Shanghai",
|
||||
WorkHoursJSON: `{
|
||||
"monday":"09:30-12:00",
|
||||
"tuesday":"全天",
|
||||
"wednesday":"",
|
||||
"thursday":"22:00-06:00",
|
||||
"friday":"全天",
|
||||
"saturday":"休息",
|
||||
"sunday":""
|
||||
}`,
|
||||
}
|
||||
loc, _ := time.LoadLocation("Asia/Shanghai")
|
||||
|
||||
// 周一 10:00 → 在 09:30-12:00
|
||||
mon := time.Date(2026, 3, 16, 10, 0, 0, 0, loc)
|
||||
if !isWithinWorkHours(setting, mon) {
|
||||
t.Fatal("周一 10:00 应在自定义时段内")
|
||||
}
|
||||
// 周一 14:00 → 不在
|
||||
monPM := time.Date(2026, 3, 16, 14, 0, 0, 0, loc)
|
||||
if isWithinWorkHours(setting, monPM) {
|
||||
t.Fatal("周一 14:00 不应在工作时间")
|
||||
}
|
||||
// 周三休息
|
||||
wed := time.Date(2026, 3, 18, 10, 0, 0, 0, loc)
|
||||
if isWithinWorkHours(setting, wed) {
|
||||
t.Fatal("周三应休息")
|
||||
}
|
||||
// 周四跨午夜 23:00
|
||||
thu := time.Date(2026, 3, 19, 23, 0, 0, 0, loc)
|
||||
if !isWithinWorkHours(setting, thu) {
|
||||
t.Fatal("周四 23:00 应在跨午夜时段")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user