实现租户系统设置落库:欢迎语、工作时间与通知开关

- 新增 TenantSetting 模型与 /api/settings 读写接口
- 设置页接通基本资料、自动回复、工作时间、通知偏好
- Widget 初始化使用欢迎语/离线提示,非工作时间不自动分配
- 补充设置持久化与 Widget 提示集成测试
This commit is contained in:
yml2213
2026-07-15 11:27:15 +08:00
parent b5203f7cbd
commit 318ba8a563
9 changed files with 686 additions and 97 deletions
@@ -682,3 +682,67 @@ func TestAdminTenantLifecycleAndPlanToggle(t *testing.T) {
t.Fatalf("套餐状态未更新: %+v", updatedPlan)
}
}
func TestTenantSettingsPersistAndAffectWidgetPrompt(t *testing.T) {
router := setupRouter(t)
tenant := createTenant(t, "设置租户", "normal")
admin := createUser(t, tenant.ID, "settings-admin", "admin")
channel := model.Channel{
TenantID: tenant.ID, Type: "web", Name: "网页", Status: "enabled",
ScriptCode: `<script data-id="WK_set_001"></script>`,
}
if err := model.DB.Create(&channel).Error; err != nil {
t.Fatalf("创建渠道失败: %v", err)
}
// 保存欢迎语与离线提示
saveRec := httptest.NewRecorder()
saveBody := `{"welcome_message":"定制欢迎语ABC","offline_prompt":"定制离线提示XYZ","work_hours":{"monday":"全天","tuesday":"全天","wednesday":"全天","thursday":"全天","friday":"全天","saturday":"全天","sunday":"全天"}}`
router.ServeHTTP(saveRec, bearerRequest(t, http.MethodPut, "/api/settings", []byte(saveBody), admin))
if saveRec.Code != http.StatusOK {
t.Fatalf("保存设置失败: %s", saveRec.Body.String())
}
getRec := httptest.NewRecorder()
router.ServeHTTP(getRec, bearerRequest(t, http.MethodGet, "/api/settings", nil, admin))
if getRec.Code != http.StatusOK {
t.Fatalf("读取设置失败: %s", getRec.Body.String())
}
var getResp struct {
Data struct {
WelcomeMessage string `json:"welcome_message"`
OfflinePrompt string `json:"offline_prompt"`
} `json:"data"`
}
if err := json.Unmarshal(getRec.Body.Bytes(), &getResp); err != nil {
t.Fatalf("解析设置失败: %v", err)
}
if getResp.Data.WelcomeMessage != "定制欢迎语ABC" || getResp.Data.OfflinePrompt != "定制离线提示XYZ" {
t.Fatalf("设置未持久化: %+v", getResp.Data)
}
// 无在线客服时 init 应返回定制离线提示
initRec := httptest.NewRecorder()
initReq := httptest.NewRequest(http.MethodPost, "/api/widget/init", bytes.NewBufferString(`{"channel_key":"WK_set_001"}`))
initReq.Header.Set("Content-Type", "application/json")
router.ServeHTTP(initRec, initReq)
if initRec.Code != http.StatusOK {
t.Fatalf("widget init 失败: %s", initRec.Body.String())
}
var initResp struct {
Data struct {
WelcomeMessage string `json:"welcome_message"`
OfflinePrompt string `json:"offline_prompt"`
AgentsOnline bool `json:"agents_online"`
} `json:"data"`
}
if err := json.Unmarshal(initRec.Body.Bytes(), &initResp); err != nil {
t.Fatalf("解析 init 失败: %v", err)
}
if initResp.Data.AgentsOnline {
t.Fatalf("无客服时应离线")
}
if initResp.Data.WelcomeMessage != "定制欢迎语ABC" || initResp.Data.OfflinePrompt != "定制离线提示XYZ" {
t.Fatalf("widget 未使用租户设置: %+v", initResp.Data)
}
}