feat: 添加屏保用户播放设置和相关功能
- 在 `AndroidScreenSaverCatalogVO` 中添加 `displayDurationSec` 字段 - 移除 `ScreenSaver` 和 `AndroidScreenSaverItemVO` 中的 `displayDurationSec` 字段 - 更新 `ScreenSaverServiceImpl` 以支持用户播放设置 - 添加 `ScreenSaverUserSettings` 实体类和 `ScreenSaverUserSettingsMapper` 映射器 - 更新 `ScreenSaverSelectionResult` 以包含 `displayDurationSec` - 更新数据库表结构以支持新的字段和表 - 更新单元测试以验证新功能的正确性dev_na
parent
ce4743c5ea
commit
940cc8a939
|
|
@ -365,4 +365,62 @@
|
|||
| result_file_path | VARCHAR(500) | | 缁撴灉鏂囦欢鐩稿璺緞 (濡侻D鎬荤粨鏂囦欢) |
|
||||
| status | SMALLINT | | 0:鎺掗槦, 1:澶勭悊涓? 2:鎴愬姛, 3:澶辫触 |
|
||||
|
||||
## 6. 屏保模块
|
||||
|
||||
### 6.1 `biz_screen_savers`(屏保素材表)
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | BIGSERIAL | PK | 屏保ID |
|
||||
| tenant_id | BIGINT | NOT NULL | 租户ID |
|
||||
| scope_type | VARCHAR(32) | NOT NULL, DEFAULT 'PLATFORM' | 作用域:PLATFORM / USER |
|
||||
| owner_user_id | BIGINT | | 当作用域为 USER 时的归属用户 |
|
||||
| name | VARCHAR(128) | NOT NULL | 屏保名称 |
|
||||
| image_url | VARCHAR(512) | NOT NULL | 图片地址 |
|
||||
| description | VARCHAR(255) | | 屏保描述 |
|
||||
| display_duration_sec | INTEGER | NOT NULL, DEFAULT 15 | 旧版素材级展示时长,兼容期保留 |
|
||||
| image_width | INTEGER | | 图片宽度 |
|
||||
| image_height | INTEGER | | 图片高度 |
|
||||
| image_format | VARCHAR(16) | | 图片格式 |
|
||||
| sort_order | INTEGER | NOT NULL, DEFAULT 0 | 排序值 |
|
||||
| created_by | BIGINT | | 创建人ID |
|
||||
| status | SMALLINT | NOT NULL, DEFAULT 1 | 启用状态 |
|
||||
| remark | VARCHAR(255) | | 备注 |
|
||||
| created_at | TIMESTAMP(6) | NOT NULL | 创建时间 |
|
||||
| updated_at | TIMESTAMP(6) | NOT NULL | 更新时间 |
|
||||
| is_deleted | SMALLINT | DEFAULT 0 | 逻辑删除 |
|
||||
|
||||
索引:
|
||||
- `idx_screen_savers_status_sort`: `(status, sort_order)`
|
||||
- `idx_screen_savers_scope_owner_status_sort`: `(scope_type, owner_user_id, status, sort_order)`
|
||||
|
||||
### 6.2 `biz_screen_saver_user_config`(屏保用户状态覆盖表)
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | BIGSERIAL | PK | 配置ID |
|
||||
| tenant_id | BIGINT | NOT NULL | 租户ID |
|
||||
| user_id | BIGINT | NOT NULL | 用户ID |
|
||||
| screen_saver_id | BIGINT | NOT NULL | 屏保素材ID |
|
||||
| status | SMALLINT | NOT NULL, DEFAULT 1 | 用户覆盖启停状态 |
|
||||
| created_at | TIMESTAMP(6) | NOT NULL | 创建时间 |
|
||||
| updated_at | TIMESTAMP(6) | NOT NULL | 更新时间 |
|
||||
| is_deleted | SMALLINT | DEFAULT 0 | 逻辑删除 |
|
||||
|
||||
索引:
|
||||
- `uk_screen_saver_user_cfg_user_item`: `UNIQUE (tenant_id, user_id, screen_saver_id) WHERE is_deleted = 0`
|
||||
- `idx_screen_saver_user_cfg_item`: `(screen_saver_id) WHERE is_deleted = 0`
|
||||
|
||||
### 6.3 `biz_screen_saver_user_settings`(屏保用户播放设置表)
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | BIGSERIAL | PK | 设置ID |
|
||||
| tenant_id | BIGINT | NOT NULL | 租户ID |
|
||||
| user_id | BIGINT | NOT NULL | 用户ID |
|
||||
| display_duration_sec | INTEGER | NOT NULL, DEFAULT 15 | 当前用户统一屏保展示时长(秒) |
|
||||
| created_at | TIMESTAMP(6) | NOT NULL | 创建时间 |
|
||||
| updated_at | TIMESTAMP(6) | NOT NULL | 更新时间 |
|
||||
| is_deleted | SMALLINT | DEFAULT 0 | 逻辑删除 |
|
||||
|
||||
索引:
|
||||
- `uk_screen_saver_user_settings_user`: `UNIQUE (tenant_id, user_id) WHERE is_deleted = 0`
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -563,3 +563,67 @@ INSERT INTO "sys_dict_item" ("dict_item_id", "type_code", "item_label", "item_va
|
|||
INSERT INTO "sys_dict_item" ("dict_item_id", "type_code", "item_label", "item_value", "sort_order", "status", "remark", "created_at", "updated_at") VALUES (40, 'biz_prompt_level', '预置模板', '1', 1, 1, '平台系统预置或租户共享预置', '2026-03-04 10:55:42.163768', '2026-03-04 10:55:42.163768');
|
||||
INSERT INTO "sys_dict_item" ("dict_item_id", "type_code", "item_label", "item_value", "sort_order", "status", "remark", "created_at", "updated_at") VALUES (41, 'biz_prompt_level', '个人模板', '0', 2, 1, '个人私有模板', '2026-03-04 10:55:42.175269', '2026-03-04 10:55:42.175269');
|
||||
|
||||
-- ----------------------------
|
||||
-- 6. 屏保模块
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE biz_screen_savers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||||
scope_type VARCHAR(32) NOT NULL DEFAULT 'PLATFORM',
|
||||
owner_user_id BIGINT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
image_url VARCHAR(512) NOT NULL,
|
||||
description VARCHAR(255),
|
||||
display_duration_sec INTEGER NOT NULL DEFAULT 15,
|
||||
image_width INTEGER,
|
||||
image_height INTEGER,
|
||||
image_format VARCHAR(16),
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
created_by BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
remark VARCHAR(255),
|
||||
created_at TIMESTAMP(6) NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP(6) NOT NULL DEFAULT now(),
|
||||
is_deleted SMALLINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX idx_screen_savers_status_sort
|
||||
ON biz_screen_savers (status, sort_order);
|
||||
|
||||
CREATE INDEX idx_screen_savers_scope_owner_status_sort
|
||||
ON biz_screen_savers (scope_type, owner_user_id, status, sort_order);
|
||||
|
||||
CREATE TABLE biz_screen_saver_user_config (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||||
user_id BIGINT NOT NULL,
|
||||
screen_saver_id BIGINT NOT NULL,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP(6) NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP(6) NOT NULL DEFAULT now(),
|
||||
is_deleted SMALLINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_screen_saver_user_cfg_user_item
|
||||
ON biz_screen_saver_user_config (tenant_id, user_id, screen_saver_id)
|
||||
WHERE is_deleted = 0;
|
||||
|
||||
CREATE INDEX idx_screen_saver_user_cfg_item
|
||||
ON biz_screen_saver_user_config (screen_saver_id)
|
||||
WHERE is_deleted = 0;
|
||||
|
||||
CREATE TABLE biz_screen_saver_user_settings (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||||
user_id BIGINT NOT NULL,
|
||||
display_duration_sec INTEGER NOT NULL DEFAULT 15,
|
||||
created_at TIMESTAMP(6) NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP(6) NOT NULL DEFAULT now(),
|
||||
is_deleted SMALLINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_screen_saver_user_settings_user
|
||||
ON biz_screen_saver_user_settings (tenant_id, user_id)
|
||||
WHERE is_deleted = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public class AndroidScreenSaverController {
|
|||
AndroidScreenSaverCatalogVO vo = new AndroidScreenSaverCatalogVO();
|
||||
vo.setRefreshIntervalSec(300);
|
||||
vo.setPlayMode("SEQUENTIAL");
|
||||
vo.setDisplayDurationSec(selection.getDisplayDurationSec());
|
||||
vo.setSourceScope(selection.getSourceScope());
|
||||
vo.setItems(selection.getItems().stream().map(item -> {
|
||||
AndroidScreenSaverItemVO child = new AndroidScreenSaverItemVO();
|
||||
|
|
@ -51,7 +52,6 @@ public class AndroidScreenSaverController {
|
|||
child.setName(item.getName());
|
||||
child.setImageUrl(item.getImageUrl());
|
||||
child.setDescription(item.getDescription());
|
||||
child.setDisplayDurationSec(item.getDisplayDurationSec());
|
||||
child.setSortOrder(item.getSortOrder());
|
||||
child.setUpdatedAt(item.getUpdatedAt());
|
||||
return child;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.imeeting.controller.android.legacy;
|
||||
|
||||
import com.imeeting.dto.android.legacy.LegacyApiResponse;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverItemResponse;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverCatalogResponse;
|
||||
import com.imeeting.service.android.legacy.LegacyScreenSaverAdapterService;
|
||||
import com.imeeting.support.TaskSecurityContextRunner;
|
||||
import com.unisbase.dto.InternalAuthCheckResponse;
|
||||
|
|
@ -17,8 +17,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "兼容屏保接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/screensavers")
|
||||
|
|
@ -34,19 +32,19 @@ public class LegacyScreenSaverController {
|
|||
|
||||
@Operation(summary = "查询启用的屏保列表")
|
||||
@GetMapping("/active")
|
||||
public LegacyApiResponse<List<LegacyScreenSaverItemResponse>> active(HttpServletRequest request) {
|
||||
public LegacyApiResponse<LegacyScreenSaverCatalogResponse> active(HttpServletRequest request) {
|
||||
LoginUser loginUser = resolveLoginUser(request);
|
||||
return LegacyApiResponse.ok(queryActive(loginUser));
|
||||
}
|
||||
|
||||
private List<LegacyScreenSaverItemResponse> queryActive(LoginUser loginUser) {
|
||||
private LegacyScreenSaverCatalogResponse queryActive(LoginUser loginUser) {
|
||||
if (loginUser == null || loginUser.getUserId() == null || loginUser.getTenantId() == null) {
|
||||
return legacyScreenSaverAdapterService.listActiveScreenSavers(null);
|
||||
return legacyScreenSaverAdapterService.getActiveScreenSavers(null);
|
||||
}
|
||||
return taskSecurityContextRunner.callAsTenantUser(
|
||||
loginUser.getTenantId(),
|
||||
loginUser.getUserId(),
|
||||
() -> legacyScreenSaverAdapterService.listActiveScreenSavers(loginUser.getUserId())
|
||||
() -> legacyScreenSaverAdapterService.getActiveScreenSavers(loginUser.getUserId())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.imeeting.controller.biz;
|
|||
import com.imeeting.dto.biz.ScreenSaverAdminVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverImageUploadVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsVO;
|
||||
import com.imeeting.entity.biz.ScreenSaver;
|
||||
import com.imeeting.service.biz.ScreenSaverService;
|
||||
import com.unisbase.common.ApiResponse;
|
||||
|
|
@ -44,6 +46,20 @@ public class ScreenSaverController {
|
|||
return ApiResponse.ok(screenSaverService.listForAdmin(currentLoginUser(), keyword, status, scopeType, ownerUserId));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询当前用户屏保播放设置")
|
||||
@GetMapping("/my-settings")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public ApiResponse<ScreenSaverUserSettingsVO> getMySettings() {
|
||||
return ApiResponse.ok(screenSaverService.getMySettings(currentLoginUser()));
|
||||
}
|
||||
|
||||
@Operation(summary = "更新当前用户屏保播放设置")
|
||||
@PutMapping("/my-settings")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public ApiResponse<ScreenSaverUserSettingsVO> updateMySettings(@RequestBody ScreenSaverUserSettingsDTO dto) {
|
||||
return ApiResponse.ok(screenSaverService.updateMySettings(dto, currentLoginUser()));
|
||||
}
|
||||
|
||||
@Operation(summary = "新增屏保")
|
||||
@PostMapping
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ public class AndroidScreenSaverCatalogVO {
|
|||
private Integer refreshIntervalSec;
|
||||
@Schema(description = "播放模式")
|
||||
private String playMode;
|
||||
@Schema(description = "当前用户统一屏保展示时长(秒)")
|
||||
private Integer displayDurationSec;
|
||||
@Schema(description = "当前屏保来源范围")
|
||||
private String sourceScope;
|
||||
@Schema(description = "屏保图片项列表")
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ public class AndroidScreenSaverItemVO {
|
|||
private String imageUrl;
|
||||
@Schema(description = "屏保描述")
|
||||
private String description;
|
||||
@Schema(description = "单张展示时长,单位秒")
|
||||
private Integer displayDurationSec;
|
||||
@Schema(description = "排序值")
|
||||
private Integer sortOrder;
|
||||
@Schema(description = "最近更新时间")
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ public class LegacyScreenSaverItemResponse {
|
|||
|
||||
private String description;
|
||||
|
||||
@JsonProperty("display_duration_sec")
|
||||
private Integer displayDurationSec;
|
||||
|
||||
@JsonProperty("sort_order")
|
||||
private Integer sortOrder;
|
||||
|
||||
|
|
@ -42,7 +39,6 @@ public class LegacyScreenSaverItemResponse {
|
|||
response.setName(source.getName());
|
||||
response.setImageUrl(source.getImageUrl());
|
||||
response.setDescription(source.getDescription());
|
||||
response.setDisplayDurationSec(source.getDisplayDurationSec());
|
||||
response.setSortOrder(source.getSortOrder());
|
||||
response.setIsActive(Integer.valueOf(1).equals(source.getStatus()) ? 1 : 0);
|
||||
response.setCreatedAt(source.getCreatedAt());
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ public class ScreenSaverAdminVO {
|
|||
vo.setName(entity.getName());
|
||||
vo.setImageUrl(entity.getImageUrl());
|
||||
vo.setDescription(entity.getDescription());
|
||||
vo.setDisplayDurationSec(entity.getDisplayDurationSec());
|
||||
vo.setImageWidth(entity.getImageWidth());
|
||||
vo.setImageHeight(entity.getImageHeight());
|
||||
vo.setImageFormat(entity.getImageFormat());
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ public class ScreenSaverDTO {
|
|||
private String name;
|
||||
private String imageUrl;
|
||||
private String description;
|
||||
private Integer displayDurationSec;
|
||||
private Integer imageWidth;
|
||||
private Integer imageHeight;
|
||||
private String imageFormat;
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@ import java.util.List;
|
|||
@AllArgsConstructor
|
||||
public class ScreenSaverSelectionResult {
|
||||
private String sourceScope;
|
||||
private Integer displayDurationSec;
|
||||
private List<ScreenSaverAdminVO> items;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@ public class ScreenSaver extends BaseEntity {
|
|||
@Schema(description = "屏保描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "展示时长,单位秒")
|
||||
private Integer displayDurationSec;
|
||||
|
||||
@Schema(description = "图片宽度")
|
||||
private Integer imageWidth;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.imeeting.service.android.legacy;
|
||||
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverItemResponse;
|
||||
|
||||
import java.util.List;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverCatalogResponse;
|
||||
|
||||
public interface LegacyScreenSaverAdapterService {
|
||||
List<LegacyScreenSaverItemResponse> listActiveScreenSavers(Long userId);
|
||||
LegacyScreenSaverCatalogResponse getActiveScreenSavers(Long userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.imeeting.service.android.legacy.impl;
|
||||
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverCatalogResponse;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverItemResponse;
|
||||
import com.imeeting.dto.biz.ScreenSaverSelectionResult;
|
||||
import com.imeeting.service.android.legacy.LegacyScreenSaverAdapterService;
|
||||
|
|
@ -7,8 +8,6 @@ import com.imeeting.service.biz.ScreenSaverService;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LegacyScreenSaverAdapterServiceImpl implements LegacyScreenSaverAdapterService {
|
||||
|
|
@ -16,13 +15,24 @@ public class LegacyScreenSaverAdapterServiceImpl implements LegacyScreenSaverAda
|
|||
private final ScreenSaverService screenSaverService;
|
||||
|
||||
@Override
|
||||
public List<LegacyScreenSaverItemResponse> listActiveScreenSavers(Long userId) {
|
||||
public LegacyScreenSaverCatalogResponse getActiveScreenSavers(Long userId) {
|
||||
ScreenSaverSelectionResult selection = screenSaverService.getActiveSelection(userId);
|
||||
if (selection == null || selection.getItems() == null || selection.getItems().isEmpty()) {
|
||||
return List.of();
|
||||
LegacyScreenSaverCatalogResponse response = new LegacyScreenSaverCatalogResponse();
|
||||
response.setRefreshIntervalSec(300);
|
||||
response.setPlayMode("SEQUENTIAL");
|
||||
if (selection == null) {
|
||||
response.setSourceScope("PLATFORM");
|
||||
response.setDisplayDurationSec(15);
|
||||
response.setItems(java.util.List.of());
|
||||
return response;
|
||||
}
|
||||
return selection.getItems().stream()
|
||||
.map(LegacyScreenSaverItemResponse::from)
|
||||
.toList();
|
||||
response.setSourceScope(selection.getSourceScope());
|
||||
response.setDisplayDurationSec(selection.getDisplayDurationSec());
|
||||
response.setItems(selection.getItems() == null
|
||||
? java.util.List.of()
|
||||
: selection.getItems().stream()
|
||||
.map(LegacyScreenSaverItemResponse::from)
|
||||
.toList());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import com.imeeting.dto.biz.ScreenSaverAdminVO;
|
|||
import com.imeeting.dto.biz.ScreenSaverDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverImageUploadVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverSelectionResult;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsVO;
|
||||
import com.imeeting.entity.biz.ScreenSaver;
|
||||
import com.unisbase.security.LoginUser;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
|
@ -26,4 +28,8 @@ public interface ScreenSaverService extends IService<ScreenSaver> {
|
|||
ScreenSaverImageUploadVO uploadImage(MultipartFile file) throws IOException;
|
||||
|
||||
ScreenSaverSelectionResult getActiveSelection(Long userId);
|
||||
|
||||
ScreenSaverUserSettingsVO getMySettings(LoginUser loginUser);
|
||||
|
||||
ScreenSaverUserSettingsVO updateMySettings(ScreenSaverUserSettingsDTO dto, LoginUser loginUser);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@ import com.imeeting.dto.biz.ScreenSaverAdminVO;
|
|||
import com.imeeting.dto.biz.ScreenSaverDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverImageUploadVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverSelectionResult;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsVO;
|
||||
import com.imeeting.entity.biz.ScreenSaver;
|
||||
import com.imeeting.entity.biz.ScreenSaverUserConfig;
|
||||
import com.imeeting.entity.biz.ScreenSaverUserSettings;
|
||||
import com.imeeting.mapper.biz.ScreenSaverMapper;
|
||||
import com.imeeting.mapper.biz.ScreenSaverUserConfigMapper;
|
||||
import com.imeeting.mapper.biz.ScreenSaverUserSettingsMapper;
|
||||
import com.imeeting.service.biz.ScreenSaverService;
|
||||
import com.unisbase.entity.SysUser;
|
||||
import com.unisbase.mapper.SysUserMapper;
|
||||
|
|
@ -20,6 +24,8 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
|
@ -46,6 +52,9 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
private static final String SCOPE_PLATFORM = "PLATFORM";
|
||||
private static final String SCOPE_USER = "USER";
|
||||
private static final String SCOPE_MIXED = "MIXED";
|
||||
private static final int DEFAULT_DISPLAY_DURATION_SEC = 15;
|
||||
private static final int MIN_DISPLAY_DURATION_SEC = 3;
|
||||
private static final int MAX_DISPLAY_DURATION_SEC = 3600;
|
||||
private static final int REQUIRED_WIDTH = 1280;
|
||||
private static final int REQUIRED_HEIGHT = 800;
|
||||
private static final Set<String> ALLOWED_FORMATS = Set.of("jpg", "jpeg", "png");
|
||||
|
|
@ -54,6 +63,7 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
.thenComparing(ScreenSaver::getId, Comparator.nullsLast(Comparator.reverseOrder()));
|
||||
|
||||
private final ScreenSaverUserConfigMapper userConfigMapper;
|
||||
private final ScreenSaverUserSettingsMapper userSettingsMapper;
|
||||
private final SysUserMapper sysUserMapper;
|
||||
|
||||
@Value("${unisbase.app.upload-path}")
|
||||
|
|
@ -80,8 +90,11 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
wrapper.eq(ScreenSaver::getOwnerUserId, ownerUserId);
|
||||
}
|
||||
List<ScreenSaver> records = this.list(wrapper);
|
||||
Map<Long, Integer> userStatusMap = queryUserStatusMap(loginUser == null ? null : loginUser.getUserId(), extractPlatformIds(records));
|
||||
return toAdminVOs(records, userStatusMap).stream()
|
||||
Long tenantId = loginUser == null ? null : loginUser.getTenantId();
|
||||
Long userId = loginUser == null ? null : loginUser.getUserId();
|
||||
Map<Long, Integer> userStatusMap = queryUserStatusMap(tenantId, userId, extractPlatformIds(records));
|
||||
Integer displayDurationSec = resolveDisplayDurationSec(tenantId, userId);
|
||||
return toAdminVOs(records, userStatusMap, displayDurationSec).stream()
|
||||
.filter(item -> status == null || Objects.equals(item.getStatus(), status))
|
||||
.toList();
|
||||
}
|
||||
|
|
@ -131,6 +144,10 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
}
|
||||
|
||||
if (isPlatformScope(entity)) {
|
||||
if (isAdmin(loginUser)) {
|
||||
entity.setStatus(status);
|
||||
return this.updateById(entity);
|
||||
}
|
||||
return upsertUserStatusConfig(id, status, loginUser);
|
||||
}
|
||||
if (!canManageEntity(entity, loginUser)) {
|
||||
|
|
@ -179,13 +196,50 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
}
|
||||
|
||||
@Override
|
||||
public ScreenSaverSelectionResult getActiveSelection(Long userId) {
|
||||
List<ScreenSaver> platformItems = listActiveByScope(SCOPE_PLATFORM, null);
|
||||
if (userId == null) {
|
||||
return new ScreenSaverSelectionResult(SCOPE_PLATFORM, toAdminVOs(platformItems));
|
||||
public ScreenSaverUserSettingsVO getMySettings(LoginUser loginUser) {
|
||||
if (loginUser == null || loginUser.getUserId() == null) {
|
||||
throw new RuntimeException("login user is required");
|
||||
}
|
||||
return buildUserSettingsVO(loginUser.getUserId(), resolveDisplayDurationSec(loginUser.getTenantId(), loginUser.getUserId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ScreenSaverUserSettingsVO updateMySettings(ScreenSaverUserSettingsDTO dto, LoginUser loginUser) {
|
||||
if (loginUser == null || loginUser.getUserId() == null || loginUser.getTenantId() == null) {
|
||||
throw new RuntimeException("login user is required");
|
||||
}
|
||||
Integer displayDurationSec = dto == null ? null : dto.getDisplayDurationSec();
|
||||
validateDisplayDurationSec(displayDurationSec);
|
||||
|
||||
ScreenSaverUserSettings existing = userSettingsMapper.selectOne(new LambdaQueryWrapper<ScreenSaverUserSettings>()
|
||||
.eq(ScreenSaverUserSettings::getTenantId, loginUser.getTenantId())
|
||||
.eq(ScreenSaverUserSettings::getUserId, loginUser.getUserId())
|
||||
.last("LIMIT 1"));
|
||||
if (existing != null) {
|
||||
existing.setDisplayDurationSec(displayDurationSec);
|
||||
userSettingsMapper.updateById(existing);
|
||||
return buildUserSettingsVO(loginUser.getUserId(), existing.getDisplayDurationSec());
|
||||
}
|
||||
|
||||
Map<Long, Integer> userStatusMap = queryUserStatusMap(userId, extractPlatformIds(platformItems));
|
||||
ScreenSaverUserSettings entity = new ScreenSaverUserSettings();
|
||||
entity.setTenantId(loginUser.getTenantId());
|
||||
entity.setUserId(loginUser.getUserId());
|
||||
entity.setDisplayDurationSec(displayDurationSec);
|
||||
userSettingsMapper.insert(entity);
|
||||
return buildUserSettingsVO(loginUser.getUserId(), entity.getDisplayDurationSec());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenSaverSelectionResult getActiveSelection(Long userId) {
|
||||
Long tenantId = currentTenantId();
|
||||
Integer displayDurationSec = resolveDisplayDurationSec(tenantId, userId);
|
||||
List<ScreenSaver> platformItems = listActiveByScope(SCOPE_PLATFORM, null);
|
||||
if (userId == null) {
|
||||
return new ScreenSaverSelectionResult(SCOPE_PLATFORM, displayDurationSec, toAdminVOs(platformItems, Map.of(), displayDurationSec));
|
||||
}
|
||||
|
||||
Map<Long, Integer> userStatusMap = queryUserStatusMap(tenantId, userId, extractPlatformIds(platformItems));
|
||||
List<ScreenSaver> effectivePlatformItems = platformItems.stream()
|
||||
.filter(item -> effectiveStatus(item, userStatusMap.get(item.getId())) == 1)
|
||||
.toList();
|
||||
|
|
@ -196,7 +250,11 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
selected.addAll(userItems);
|
||||
selected.sort(SCREEN_SAVER_ORDER);
|
||||
|
||||
return new ScreenSaverSelectionResult(resolveSourceScope(effectivePlatformItems, userItems), toAdminVOs(selected, userStatusMap));
|
||||
return new ScreenSaverSelectionResult(
|
||||
resolveSourceScope(effectivePlatformItems, userItems),
|
||||
displayDurationSec,
|
||||
toAdminVOs(selected, userStatusMap, displayDurationSec)
|
||||
);
|
||||
}
|
||||
|
||||
private ScreenSaverDTO normalizeCreateDto(ScreenSaverDTO dto, LoginUser loginUser) {
|
||||
|
|
@ -258,13 +316,17 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
return userConfigMapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
private Map<Long, Integer> queryUserStatusMap(Long userId, List<Long> screenSaverIds) {
|
||||
private Map<Long, Integer> queryUserStatusMap(Long tenantId, Long userId, List<Long> screenSaverIds) {
|
||||
if (userId == null || screenSaverIds == null || screenSaverIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
List<ScreenSaverUserConfig> configs = userConfigMapper.selectList(new LambdaQueryWrapper<ScreenSaverUserConfig>()
|
||||
LambdaQueryWrapper<ScreenSaverUserConfig> wrapper = new LambdaQueryWrapper<ScreenSaverUserConfig>()
|
||||
.eq(ScreenSaverUserConfig::getUserId, userId)
|
||||
.in(ScreenSaverUserConfig::getScreenSaverId, screenSaverIds));
|
||||
.in(ScreenSaverUserConfig::getScreenSaverId, screenSaverIds);
|
||||
if (tenantId != null) {
|
||||
wrapper.eq(ScreenSaverUserConfig::getTenantId, tenantId);
|
||||
}
|
||||
List<ScreenSaverUserConfig> configs = userConfigMapper.selectList(wrapper);
|
||||
|
||||
Map<Long, Integer> statusMap = new HashMap<>();
|
||||
for (ScreenSaverUserConfig config : configs) {
|
||||
|
|
@ -299,10 +361,10 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
}
|
||||
|
||||
private List<ScreenSaverAdminVO> toAdminVOs(List<ScreenSaver> entities) {
|
||||
return toAdminVOs(entities, Map.of());
|
||||
return toAdminVOs(entities, Map.of(), DEFAULT_DISPLAY_DURATION_SEC);
|
||||
}
|
||||
|
||||
private List<ScreenSaverAdminVO> toAdminVOs(List<ScreenSaver> entities, Map<Long, Integer> userStatusMap) {
|
||||
private List<ScreenSaverAdminVO> toAdminVOs(List<ScreenSaver> entities, Map<Long, Integer> userStatusMap, Integer displayDurationSec) {
|
||||
if (entities == null || entities.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
|
@ -312,6 +374,7 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
String creatorName = item.getCreatedBy() == null ? null : creatorNames.get(item.getCreatedBy());
|
||||
ScreenSaverAdminVO vo = ScreenSaverAdminVO.from(item, creatorName);
|
||||
vo.setStatus(effectiveStatus(item, userStatusMap.get(item.getId())));
|
||||
vo.setDisplayDurationSec(displayDurationSec);
|
||||
return vo;
|
||||
})
|
||||
.toList();
|
||||
|
|
@ -379,9 +442,6 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
if (!SCOPE_PLATFORM.equals(resolvedScopeType) && !SCOPE_USER.equals(resolvedScopeType)) {
|
||||
throw new RuntimeException("scopeType only supports PLATFORM or USER");
|
||||
}
|
||||
if (dto.getDisplayDurationSec() != null && (dto.getDisplayDurationSec() < 3 || dto.getDisplayDurationSec() > 3600)) {
|
||||
throw new RuntimeException("displayDurationSec must be between 3 and 3600");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireImageMetadata(ScreenSaverDTO dto) {
|
||||
|
|
@ -427,9 +487,6 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
if (!partial || dto.getDescription() != null) {
|
||||
entity.setDescription(trimToNull(dto.getDescription()));
|
||||
}
|
||||
if (!partial || dto.getDisplayDurationSec() != null) {
|
||||
entity.setDisplayDurationSec(dto.getDisplayDurationSec());
|
||||
}
|
||||
if (!partial || dto.getImageWidth() != null) {
|
||||
entity.setImageWidth(dto.getImageWidth());
|
||||
}
|
||||
|
|
@ -504,12 +561,50 @@ public class ScreenSaverServiceImpl extends ServiceImpl<ScreenSaverMapper, Scree
|
|||
return entity != null && SCOPE_USER.equals(normalizeScopeType(entity.getScopeType()));
|
||||
}
|
||||
|
||||
private Integer resolveDisplayDurationSec(Long tenantId, Long userId) {
|
||||
if (userId == null) {
|
||||
return DEFAULT_DISPLAY_DURATION_SEC;
|
||||
}
|
||||
LambdaQueryWrapper<ScreenSaverUserSettings> wrapper = new LambdaQueryWrapper<ScreenSaverUserSettings>()
|
||||
.eq(ScreenSaverUserSettings::getUserId, userId)
|
||||
.last("LIMIT 1");
|
||||
if (tenantId != null) {
|
||||
wrapper.eq(ScreenSaverUserSettings::getTenantId, tenantId);
|
||||
}
|
||||
ScreenSaverUserSettings settings = userSettingsMapper.selectOne(wrapper);
|
||||
if (settings == null || settings.getDisplayDurationSec() == null) {
|
||||
return DEFAULT_DISPLAY_DURATION_SEC;
|
||||
}
|
||||
return settings.getDisplayDurationSec();
|
||||
}
|
||||
|
||||
private ScreenSaverUserSettingsVO buildUserSettingsVO(Long userId, Integer displayDurationSec) {
|
||||
ScreenSaverUserSettingsVO vo = new ScreenSaverUserSettingsVO();
|
||||
vo.setUserId(userId);
|
||||
vo.setDisplayDurationSec(displayDurationSec == null ? DEFAULT_DISPLAY_DURATION_SEC : displayDurationSec);
|
||||
return vo;
|
||||
}
|
||||
|
||||
private Long currentTenantId() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser loginUser)) {
|
||||
return null;
|
||||
}
|
||||
return loginUser.getTenantId();
|
||||
}
|
||||
|
||||
private void validateStatus(Integer status) {
|
||||
if (status == null || (status != 0 && status != 1)) {
|
||||
throw new RuntimeException("status only supports 0 or 1");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDisplayDurationSec(Integer displayDurationSec) {
|
||||
if (displayDurationSec == null || displayDurationSec < MIN_DISPLAY_DURATION_SEC || displayDurationSec > MAX_DISPLAY_DURATION_SEC) {
|
||||
throw new RuntimeException("displayDurationSec must be between 3 and 3600");
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveAndValidateFormat(String fileName, String contentType) {
|
||||
String extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
|
||||
if (!ALLOWED_FORMATS.contains(extension)) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class AndroidScreenSaverControllerTest {
|
|||
when(taskSecurityContextRunner.callAsTenantUser(eq(9L), eq(88L), any()))
|
||||
.thenAnswer(invocation -> ((Supplier<?>) invocation.getArgument(2)).get());
|
||||
when(screenSaverService.getActiveSelection(88L))
|
||||
.thenReturn(new ScreenSaverSelectionResult("USER", List.of()));
|
||||
.thenReturn(new ScreenSaverSelectionResult("USER", 18, List.of()));
|
||||
|
||||
AndroidScreenSaverController controller =
|
||||
new AndroidScreenSaverController(androidAuthService, screenSaverService, taskSecurityContextRunner);
|
||||
|
|
@ -49,6 +49,7 @@ class AndroidScreenSaverControllerTest {
|
|||
verify(taskSecurityContextRunner).callAsTenantUser(eq(9L), eq(88L), any());
|
||||
verify(screenSaverService).getActiveSelection(88L);
|
||||
assertEquals("USER", response.getData().getSourceScope());
|
||||
assertEquals(18, response.getData().getDisplayDurationSec());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -63,7 +64,7 @@ class AndroidScreenSaverControllerTest {
|
|||
|
||||
when(androidAuthService.authenticateHttp(request)).thenReturn(authContext);
|
||||
when(screenSaverService.getActiveSelection(null))
|
||||
.thenReturn(new ScreenSaverSelectionResult("PLATFORM", List.of()));
|
||||
.thenReturn(new ScreenSaverSelectionResult("PLATFORM", 15, List.of()));
|
||||
|
||||
AndroidScreenSaverController controller =
|
||||
new AndroidScreenSaverController(androidAuthService, screenSaverService, taskSecurityContextRunner);
|
||||
|
|
@ -73,5 +74,6 @@ class AndroidScreenSaverControllerTest {
|
|||
verify(taskSecurityContextRunner, never()).callAsTenantUser(any(), any(), any());
|
||||
verify(screenSaverService).getActiveSelection(null);
|
||||
assertEquals("PLATFORM", response.getData().getSourceScope());
|
||||
assertEquals(15, response.getData().getDisplayDurationSec());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.imeeting.controller.android.legacy;
|
||||
|
||||
import com.imeeting.dto.android.legacy.LegacyApiResponse;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverCatalogResponse;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverItemResponse;
|
||||
import com.imeeting.service.android.legacy.LegacyScreenSaverAdapterService;
|
||||
import com.imeeting.support.TaskSecurityContextRunner;
|
||||
|
|
@ -42,7 +43,10 @@ class LegacyScreenSaverControllerTest {
|
|||
|
||||
LegacyScreenSaverItemResponse item = new LegacyScreenSaverItemResponse();
|
||||
item.setId(1L);
|
||||
when(adapterService.listActiveScreenSavers(55L)).thenReturn(List.of(item));
|
||||
LegacyScreenSaverCatalogResponse catalog = new LegacyScreenSaverCatalogResponse();
|
||||
catalog.setDisplayDurationSec(18);
|
||||
catalog.setItems(List.of(item));
|
||||
when(adapterService.getActiveScreenSavers(55L)).thenReturn(catalog);
|
||||
|
||||
LegacyScreenSaverController controller = new LegacyScreenSaverController(
|
||||
adapterService,
|
||||
|
|
@ -50,11 +54,12 @@ class LegacyScreenSaverControllerTest {
|
|||
taskSecurityContextRunner
|
||||
);
|
||||
|
||||
LegacyApiResponse<List<LegacyScreenSaverItemResponse>> response = controller.active(request);
|
||||
LegacyApiResponse<LegacyScreenSaverCatalogResponse> response = controller.active(request);
|
||||
|
||||
verify(taskSecurityContextRunner).callAsTenantUser(eq(7L), eq(55L), any());
|
||||
verify(adapterService).listActiveScreenSavers(55L);
|
||||
assertEquals(1, response.getData().size());
|
||||
verify(adapterService).getActiveScreenSavers(55L);
|
||||
assertEquals(18, response.getData().getDisplayDurationSec());
|
||||
assertEquals(1, response.getData().getItems().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -67,7 +72,10 @@ class LegacyScreenSaverControllerTest {
|
|||
when(request.getHeader("Authorization")).thenReturn(null);
|
||||
LegacyScreenSaverItemResponse item = new LegacyScreenSaverItemResponse();
|
||||
item.setId(2L);
|
||||
when(adapterService.listActiveScreenSavers(null)).thenReturn(List.of(item));
|
||||
LegacyScreenSaverCatalogResponse catalog = new LegacyScreenSaverCatalogResponse();
|
||||
catalog.setDisplayDurationSec(15);
|
||||
catalog.setItems(List.of(item));
|
||||
when(adapterService.getActiveScreenSavers(null)).thenReturn(catalog);
|
||||
|
||||
LegacyScreenSaverController controller = new LegacyScreenSaverController(
|
||||
adapterService,
|
||||
|
|
@ -75,10 +83,11 @@ class LegacyScreenSaverControllerTest {
|
|||
taskSecurityContextRunner
|
||||
);
|
||||
|
||||
LegacyApiResponse<List<LegacyScreenSaverItemResponse>> response = controller.active(request);
|
||||
LegacyApiResponse<LegacyScreenSaverCatalogResponse> response = controller.active(request);
|
||||
|
||||
verify(taskSecurityContextRunner, never()).callAsTenantUser(any(), any(), any());
|
||||
verify(adapterService).listActiveScreenSavers(null);
|
||||
assertEquals(1, response.getData().size());
|
||||
verify(adapterService).getActiveScreenSavers(null);
|
||||
assertEquals(15, response.getData().getDisplayDurationSec());
|
||||
assertEquals(1, response.getData().getItems().size());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.imeeting.service.android.legacy;
|
||||
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverCatalogResponse;
|
||||
import com.imeeting.dto.android.legacy.LegacyScreenSaverItemResponse;
|
||||
import com.imeeting.dto.biz.ScreenSaverAdminVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverSelectionResult;
|
||||
|
|
@ -16,7 +17,7 @@ import static org.mockito.Mockito.when;
|
|||
class LegacyScreenSaverAdapterServiceImplTest {
|
||||
|
||||
@Test
|
||||
void listActiveScreenSaversShouldMapLegacyFields() {
|
||||
void getActiveScreenSaversShouldMapLegacyFields() {
|
||||
ScreenSaverService screenSaverService = mock(ScreenSaverService.class);
|
||||
|
||||
ScreenSaverAdminVO item = new ScreenSaverAdminVO();
|
||||
|
|
@ -24,7 +25,6 @@ class LegacyScreenSaverAdapterServiceImplTest {
|
|||
item.setName("欢迎屏");
|
||||
item.setImageUrl("/api/static/screen-savers/images/a.jpg");
|
||||
item.setDescription("主大厅欢迎屏");
|
||||
item.setDisplayDurationSec(12);
|
||||
item.setSortOrder(3);
|
||||
item.setStatus(1);
|
||||
item.setCreatedAt("2026-04-17T16:00:00");
|
||||
|
|
@ -33,18 +33,20 @@ class LegacyScreenSaverAdapterServiceImplTest {
|
|||
item.setCreatorUsername("admin");
|
||||
|
||||
when(screenSaverService.getActiveSelection(55L))
|
||||
.thenReturn(new ScreenSaverSelectionResult("PLATFORM", List.of(item)));
|
||||
.thenReturn(new ScreenSaverSelectionResult("PLATFORM", 12, List.of(item)));
|
||||
|
||||
LegacyScreenSaverAdapterServiceImpl service = new LegacyScreenSaverAdapterServiceImpl(screenSaverService);
|
||||
|
||||
List<LegacyScreenSaverItemResponse> result = service.listActiveScreenSavers(55L);
|
||||
LegacyScreenSaverCatalogResponse result = service.getActiveScreenSavers(55L);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(9L, result.get(0).getId());
|
||||
assertEquals("欢迎屏", result.get(0).getName());
|
||||
assertEquals("/api/static/screen-savers/images/a.jpg", result.get(0).getImageUrl());
|
||||
assertEquals(12, result.get(0).getDisplayDurationSec());
|
||||
assertEquals(1, result.get(0).getIsActive());
|
||||
assertEquals("admin", result.get(0).getCreatorUsername());
|
||||
assertEquals(12, result.getDisplayDurationSec());
|
||||
assertEquals("PLATFORM", result.getSourceScope());
|
||||
assertEquals(1, result.getItems().size());
|
||||
LegacyScreenSaverItemResponse first = result.getItems().get(0);
|
||||
assertEquals(9L, first.getId());
|
||||
assertEquals("欢迎屏", first.getName());
|
||||
assertEquals("/api/static/screen-savers/images/a.jpg", first.getImageUrl());
|
||||
assertEquals(1, first.getIsActive());
|
||||
assertEquals("admin", first.getCreatorUsername());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@ package com.imeeting.service.biz.impl;
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.imeeting.dto.biz.ScreenSaverAdminVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverSelectionResult;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsVO;
|
||||
import com.imeeting.entity.biz.ScreenSaver;
|
||||
import com.imeeting.entity.biz.ScreenSaverUserConfig;
|
||||
import com.imeeting.entity.biz.ScreenSaverUserSettings;
|
||||
import com.imeeting.mapper.biz.ScreenSaverUserConfigMapper;
|
||||
import com.imeeting.mapper.biz.ScreenSaverUserSettingsMapper;
|
||||
import com.unisbase.mapper.SysUserMapper;
|
||||
import com.unisbase.security.LoginUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -20,6 +24,7 @@ import static org.mockito.Mockito.doReturn;
|
|||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
|
@ -28,11 +33,13 @@ class ScreenSaverServiceImplTest {
|
|||
@Test
|
||||
void getActiveSelectionShouldMergePlatformAndUserItems() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
when(userConfigMapper.selectList(any())).thenReturn(List.of(userConfig(101L, 77L, 0)));
|
||||
when(userSettingsMapper.selectOne(any())).thenReturn(userSettings(77L, 22));
|
||||
when(sysUserMapper.selectBatchIds(any())).thenReturn(List.of());
|
||||
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, sysUserMapper));
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper));
|
||||
doReturn(List.of(
|
||||
screenSaver(101L, "PLATFORM", null, 1, 2),
|
||||
screenSaver(102L, "PLATFORM", null, 1, 5)
|
||||
|
|
@ -43,18 +50,22 @@ class ScreenSaverServiceImplTest {
|
|||
ScreenSaverSelectionResult result = service.getActiveSelection(77L);
|
||||
|
||||
assertEquals("MIXED", result.getSourceScope());
|
||||
assertEquals(22, result.getDisplayDurationSec());
|
||||
assertEquals(List.of(201L, 102L), result.getItems().stream().map(ScreenSaverAdminVO::getId).toList());
|
||||
assertEquals(List.of(1, 1), result.getItems().stream().map(ScreenSaverAdminVO::getStatus).toList());
|
||||
assertEquals(List.of(22, 22), result.getItems().stream().map(ScreenSaverAdminVO::getDisplayDurationSec).toList());
|
||||
}
|
||||
|
||||
@Test
|
||||
void listForAdminShouldApplyCurrentUserStatusFilter() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
when(userConfigMapper.selectList(any())).thenReturn(List.of(userConfig(101L, 88L, 0)));
|
||||
when(userSettingsMapper.selectOne(any())).thenReturn(userSettings(88L, 18));
|
||||
when(sysUserMapper.selectBatchIds(any())).thenReturn(List.of());
|
||||
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, sysUserMapper));
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper));
|
||||
doReturn(List.of(
|
||||
screenSaver(101L, "PLATFORM", null, 1, 1),
|
||||
screenSaver(201L, "USER", 88L, 1, 2)
|
||||
|
|
@ -65,16 +76,39 @@ class ScreenSaverServiceImplTest {
|
|||
assertEquals(1, result.size());
|
||||
assertEquals(101L, result.get(0).getId());
|
||||
assertEquals(0, result.get(0).getStatus());
|
||||
assertEquals(18, result.get(0).getDisplayDurationSec());
|
||||
}
|
||||
|
||||
@Test
|
||||
void listForAdminShouldFallbackToGlobalStatusWhenNoUserOverrideExists() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
when(userConfigMapper.selectList(any())).thenReturn(List.of());
|
||||
when(userSettingsMapper.selectOne(any())).thenReturn(null);
|
||||
when(sysUserMapper.selectBatchIds(any())).thenReturn(List.of());
|
||||
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper));
|
||||
doReturn(List.of(screenSaver(101L, "PLATFORM", null, 1, 1)))
|
||||
.when(service).list(any(LambdaQueryWrapper.class));
|
||||
|
||||
List<ScreenSaverAdminVO> result = service.listForAdmin(loginUser(88L, 9L, false), null, null, null, null);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(101L, result.get(0).getId());
|
||||
assertEquals(1, result.get(0).getStatus());
|
||||
assertEquals(15, result.get(0).getDisplayDurationSec());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateStatusShouldStoreUserOverrideForPlatformItem() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
when(userConfigMapper.selectOne(any())).thenReturn(null);
|
||||
when(userConfigMapper.insert(any(ScreenSaverUserConfig.class))).thenReturn(1);
|
||||
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, sysUserMapper));
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper));
|
||||
doReturn(screenSaver(101L, "PLATFORM", null, 1, 1)).when(service).getOne(any(LambdaQueryWrapper.class));
|
||||
|
||||
boolean success = service.updateStatus(101L, 0, loginUser(88L, 9L, false));
|
||||
|
|
@ -89,6 +123,61 @@ class ScreenSaverServiceImplTest {
|
|||
assertEquals(0, captor.getValue().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateStatusShouldUpdateGlobalStatusForAdminPlatformItem() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper));
|
||||
doReturn(screenSaver(101L, "PLATFORM", null, 1, 1)).when(service).getOne(any(LambdaQueryWrapper.class));
|
||||
doReturn(true).when(service).updateById(any(ScreenSaver.class));
|
||||
|
||||
boolean success = service.updateStatus(101L, 0, loginUser(88L, 9L, true));
|
||||
|
||||
assertTrue(success);
|
||||
verify(service, times(1)).updateById(any(ScreenSaver.class));
|
||||
verify(userConfigMapper, never()).selectOne(any());
|
||||
verify(userConfigMapper, never()).insert(any(ScreenSaverUserConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMySettingsShouldFallbackToDefaultDuration() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
when(userSettingsMapper.selectOne(any())).thenReturn(null);
|
||||
|
||||
ScreenSaverServiceImpl service = new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper);
|
||||
|
||||
ScreenSaverUserSettingsVO result = service.getMySettings(loginUser(88L, 9L, false));
|
||||
|
||||
assertEquals(88L, result.getUserId());
|
||||
assertEquals(15, result.getDisplayDurationSec());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateMySettingsShouldInsertWhenMissing() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
when(userSettingsMapper.selectOne(any())).thenReturn(null);
|
||||
when(userSettingsMapper.insert(any(ScreenSaverUserSettings.class))).thenReturn(1);
|
||||
|
||||
ScreenSaverServiceImpl service = new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper);
|
||||
|
||||
ScreenSaverUserSettingsDTO dto = new ScreenSaverUserSettingsDTO();
|
||||
dto.setDisplayDurationSec(20);
|
||||
ScreenSaverUserSettingsVO result = service.updateMySettings(dto, loginUser(88L, 9L, false));
|
||||
|
||||
ArgumentCaptor<ScreenSaverUserSettings> captor = ArgumentCaptor.forClass(ScreenSaverUserSettings.class);
|
||||
verify(userSettingsMapper).insert(captor.capture());
|
||||
assertEquals(9L, captor.getValue().getTenantId());
|
||||
assertEquals(88L, captor.getValue().getUserId());
|
||||
assertEquals(20, captor.getValue().getDisplayDurationSec());
|
||||
assertEquals(20, result.getDisplayDurationSec());
|
||||
}
|
||||
|
||||
private ScreenSaver screenSaver(Long id, String scopeType, Long ownerUserId, Integer status, Integer sortOrder) {
|
||||
ScreenSaver entity = new ScreenSaver();
|
||||
entity.setId(id);
|
||||
|
|
@ -109,6 +198,13 @@ class ScreenSaverServiceImplTest {
|
|||
return config;
|
||||
}
|
||||
|
||||
private ScreenSaverUserSettings userSettings(Long userId, Integer displayDurationSec) {
|
||||
ScreenSaverUserSettings settings = new ScreenSaverUserSettings();
|
||||
settings.setUserId(userId);
|
||||
settings.setDisplayDurationSec(displayDurationSec);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private LoginUser loginUser(Long userId, Long tenantId, boolean admin) {
|
||||
LoginUser loginUser = new LoginUser();
|
||||
loginUser.setUserId(userId);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export interface ScreenSaverVO {
|
|||
name: string;
|
||||
imageUrl: string;
|
||||
description?: string;
|
||||
displayDurationSec: number;
|
||||
displayDurationSec?: number;
|
||||
imageWidth?: number;
|
||||
imageHeight?: number;
|
||||
imageFormat?: string;
|
||||
|
|
@ -29,7 +29,6 @@ export interface ScreenSaverDTO {
|
|||
name: string;
|
||||
imageUrl: string;
|
||||
description?: string;
|
||||
displayDurationSec: number;
|
||||
imageWidth: number;
|
||||
imageHeight: number;
|
||||
imageFormat: string;
|
||||
|
|
@ -38,6 +37,15 @@ export interface ScreenSaverDTO {
|
|||
remark?: string;
|
||||
}
|
||||
|
||||
export interface ScreenSaverUserSettingsVO {
|
||||
userId: number;
|
||||
displayDurationSec: number;
|
||||
}
|
||||
|
||||
export interface ScreenSaverUserSettingsDTO {
|
||||
displayDurationSec: number;
|
||||
}
|
||||
|
||||
export interface ScreenSaverUploadResult {
|
||||
imageUrl: string;
|
||||
fileSize: number;
|
||||
|
|
@ -61,6 +69,16 @@ export async function createScreenSaver(payload: ScreenSaverDTO) {
|
|||
return resp.data.data as ScreenSaverVO;
|
||||
}
|
||||
|
||||
export async function getMyScreenSaverSettings() {
|
||||
const resp = await http.get("/api/screen-savers/my-settings");
|
||||
return resp.data.data as ScreenSaverUserSettingsVO;
|
||||
}
|
||||
|
||||
export async function updateMyScreenSaverSettings(payload: ScreenSaverUserSettingsDTO) {
|
||||
const resp = await http.put("/api/screen-savers/my-settings", payload);
|
||||
return resp.data.data as ScreenSaverUserSettingsVO;
|
||||
}
|
||||
|
||||
export async function updateScreenSaver(id: number, payload: Partial<ScreenSaverDTO>) {
|
||||
const resp = await http.put(`/api/screen-savers/${id}`, payload);
|
||||
return resp.data.data as ScreenSaverVO;
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ import type { ColumnsType } from "antd/es/table";
|
|||
import {
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
PictureOutlined,
|
||||
PlusOutlined,
|
||||
ReloadOutlined,
|
||||
SaveOutlined,
|
||||
ScissorOutlined,
|
||||
SearchOutlined,
|
||||
SettingOutlined,
|
||||
TeamOutlined,
|
||||
UploadOutlined,
|
||||
UserOutlined,
|
||||
|
|
@ -42,11 +42,14 @@ import AppPagination from "@/components/shared/AppPagination";
|
|||
import {
|
||||
createScreenSaver,
|
||||
deleteScreenSaver,
|
||||
getMyScreenSaverSettings,
|
||||
listScreenSavers,
|
||||
type ScreenSaverDTO,
|
||||
type ScreenSaverScopeType,
|
||||
type ScreenSaverUserSettingsVO,
|
||||
type ScreenSaverUploadResult,
|
||||
type ScreenSaverVO,
|
||||
updateMyScreenSaverSettings,
|
||||
updateScreenSaver,
|
||||
updateScreenSaverStatus,
|
||||
uploadScreenSaverImage,
|
||||
|
|
@ -74,7 +77,6 @@ type ScreenSaverFormValues = {
|
|||
name: string;
|
||||
imageUrl: string;
|
||||
description?: string;
|
||||
displayDurationSec: number;
|
||||
imageWidth: number;
|
||||
imageHeight: number;
|
||||
imageFormat: string;
|
||||
|
|
@ -83,6 +85,10 @@ type ScreenSaverFormValues = {
|
|||
remark?: string;
|
||||
};
|
||||
|
||||
type ScreenSaverSettingsFormValues = {
|
||||
displayDurationSec: number;
|
||||
};
|
||||
|
||||
type CropModalState = {
|
||||
open: boolean;
|
||||
src: string;
|
||||
|
|
@ -365,12 +371,16 @@ function ScreenSaverCropDialog({ state, onCancel, onConfirm }: CropDialogProps)
|
|||
export default function ScreenSaverManagement() {
|
||||
const { message } = App.useApp();
|
||||
const [form] = Form.useForm<ScreenSaverFormValues>();
|
||||
const [settingsForm] = Form.useForm<ScreenSaverSettingsFormValues>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [settingsSaving, setSettingsSaving] = useState(false);
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<ScreenSaverVO | null>(null);
|
||||
const [records, setRecords] = useState<ScreenSaverVO[]>([]);
|
||||
const [users, setUsers] = useState<SysUser[]>([]);
|
||||
const [mySettings, setMySettings] = useState<ScreenSaverUserSettingsVO>({ userId: 0, displayDurationSec: 15 });
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const [statusFilter, setStatusFilter] = useState<"all" | "enabled" | "disabled">("all");
|
||||
const [scopeFilter, setScopeFilter] = useState<"all" | ScreenSaverScopeType>("all");
|
||||
|
|
@ -399,12 +409,14 @@ export default function ScreenSaverManagement() {
|
|||
const loadData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const [screenSavers, userList] = await Promise.all([
|
||||
const [screenSavers, userList, settings] = await Promise.all([
|
||||
listScreenSavers(),
|
||||
listUsers().catch(() => [] as SysUser[]),
|
||||
getMyScreenSaverSettings().catch(() => ({ userId: currentUserId || 0, displayDurationSec: 15 })),
|
||||
]);
|
||||
setRecords(screenSavers || []);
|
||||
setUsers(userList || []);
|
||||
setMySettings(settings || { userId: currentUserId || 0, displayDurationSec: 15 });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -450,7 +462,6 @@ export default function ScreenSaverManagement() {
|
|||
form.setFieldsValue({
|
||||
scopeType: "USER",
|
||||
ownerUserId: currentUserId || undefined,
|
||||
displayDurationSec: 15,
|
||||
sortOrder: 0,
|
||||
statusEnabled: true,
|
||||
imageWidth: CROP_WIDTH,
|
||||
|
|
@ -472,7 +483,6 @@ export default function ScreenSaverManagement() {
|
|||
name: record.name,
|
||||
imageUrl: record.imageUrl,
|
||||
description: record.description,
|
||||
displayDurationSec: record.displayDurationSec,
|
||||
imageWidth: record.imageWidth || CROP_WIDTH,
|
||||
imageHeight: record.imageHeight || CROP_HEIGHT,
|
||||
imageFormat: record.imageFormat || "jpg",
|
||||
|
|
@ -491,20 +501,20 @@ export default function ScreenSaverManagement() {
|
|||
|
||||
const handleSubmit = async () => {
|
||||
const values = await form.validateFields();
|
||||
const resolvedScopeType = isAdmin ? values.scopeType : "USER";
|
||||
const resolvedScopeType: ScreenSaverScopeType = isAdmin ? values.scopeType : "USER";
|
||||
const resolvedOwnerUserId = resolvedScopeType === "USER" ? currentUserId || null : null;
|
||||
const resolvedStatusEnabled = values.statusEnabled ?? true;
|
||||
const payload: ScreenSaverDTO = {
|
||||
scopeType: resolvedScopeType,
|
||||
ownerUserId: resolvedOwnerUserId,
|
||||
name: values.name.trim(),
|
||||
imageUrl: values.imageUrl.trim(),
|
||||
description: values.description?.trim(),
|
||||
displayDurationSec: values.displayDurationSec,
|
||||
imageWidth: values.imageWidth,
|
||||
imageHeight: values.imageHeight,
|
||||
imageFormat: values.imageFormat.trim().toLowerCase(),
|
||||
sortOrder: values.sortOrder,
|
||||
status: values.statusEnabled ? 1 : 0,
|
||||
status: resolvedStatusEnabled ? 1 : 0,
|
||||
remark: values.remark?.trim(),
|
||||
};
|
||||
|
||||
|
|
@ -573,6 +583,29 @@ export default function ScreenSaverManagement() {
|
|||
await loadData();
|
||||
};
|
||||
|
||||
const openSettingsModal = () => {
|
||||
settingsForm.setFieldsValue({
|
||||
displayDurationSec: mySettings.displayDurationSec,
|
||||
});
|
||||
setSettingsOpen(true);
|
||||
};
|
||||
|
||||
const handleSaveSettings = async () => {
|
||||
const values = await settingsForm.validateFields();
|
||||
setSettingsSaving(true);
|
||||
try {
|
||||
const result = await updateMyScreenSaverSettings({
|
||||
displayDurationSec: values.displayDurationSec,
|
||||
});
|
||||
setMySettings(result);
|
||||
setSettingsOpen(false);
|
||||
message.success("播放设置已更新");
|
||||
await loadData();
|
||||
} finally {
|
||||
setSettingsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ColumnsType<ScreenSaverVO> = [
|
||||
{
|
||||
title: "屏保画面",
|
||||
|
|
@ -614,12 +647,11 @@ export default function ScreenSaverManagement() {
|
|||
),
|
||||
},
|
||||
{
|
||||
title: "播放与状态",
|
||||
title: "排序与状态",
|
||||
key: "status",
|
||||
width: 210,
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical" size={6}>
|
||||
<Text>{record.displayDurationSec} 秒 / 张</Text>
|
||||
<Text type="secondary">排序值:{record.sortOrder ?? 0}</Text>
|
||||
<Switch size="small" checked={record.status === 1} onChange={(checked) => void handleToggleStatus(record, checked)} />
|
||||
</Space>
|
||||
|
|
@ -663,8 +695,8 @@ export default function ScreenSaverManagement() {
|
|||
},
|
||||
];
|
||||
const currentImageUrl = Form.useWatch("imageUrl", form);
|
||||
const currentScopeType = Form.useWatch("scopeType", form) || "PLATFORM";
|
||||
const currentOwnerUserId = Form.useWatch("ownerUserId", form);
|
||||
const watchedScopeType = Form.useWatch("scopeType", form);
|
||||
const currentScopeType: ScreenSaverScopeType = isAdmin ? (watchedScopeType || "PLATFORM") : "USER";
|
||||
const currentWidth = Form.useWatch("imageWidth", form) || CROP_WIDTH;
|
||||
const currentHeight = Form.useWatch("imageHeight", form) || CROP_HEIGHT;
|
||||
|
||||
|
|
@ -708,6 +740,9 @@ export default function ScreenSaverManagement() {
|
|||
<Button icon={<ReloadOutlined />} onClick={() => void loadData()} loading={loading}>
|
||||
刷新
|
||||
</Button>
|
||||
<Button icon={<SettingOutlined />} onClick={openSettingsModal}>
|
||||
播放设置({mySettings.displayDurationSec} 秒/张)
|
||||
</Button>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
|
||||
新增屏保
|
||||
</Button>
|
||||
|
|
@ -758,16 +793,11 @@ export default function ScreenSaverManagement() {
|
|||
>
|
||||
<Form form={form} layout="vertical" className="screen-saver-drawer__form">
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} md={14}>
|
||||
<Col xs={24}>
|
||||
<Form.Item name="name" label="屏保名称" rules={[{ required: true, message: "请输入屏保名称" }]}>
|
||||
<Input placeholder="例如:大厅欢迎屏、品牌发布屏" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={10}>
|
||||
<Form.Item name="displayDurationSec" label="展示时长(秒)" rules={[{ required: true, message: "请输入展示时长" }]}>
|
||||
<InputNumber min={3} max={3600} style={{ width: "100%" }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{isAdmin ? (
|
||||
|
|
@ -887,13 +917,34 @@ export default function ScreenSaverManagement() {
|
|||
</Row>
|
||||
|
||||
{(isAdmin || currentScopeType === "USER") ? (
|
||||
<Form.Item name="statusEnabled" label="启用状态" valuePropName="checked">
|
||||
<Form.Item name="statusEnabled" label="启用状态" valuePropName="checked" preserve>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
) : null}
|
||||
</Form>
|
||||
</Drawer>
|
||||
|
||||
<Modal
|
||||
title="我的屏保播放设置"
|
||||
open={settingsOpen}
|
||||
onCancel={() => setSettingsOpen(false)}
|
||||
onOk={() => void handleSaveSettings()}
|
||||
okText="保存"
|
||||
confirmLoading={settingsSaving}
|
||||
destroyOnHidden
|
||||
>
|
||||
<Form form={settingsForm} layout="vertical">
|
||||
<Form.Item
|
||||
name="displayDurationSec"
|
||||
label="统一展示时长(秒)"
|
||||
rules={[{ required: true, message: "请输入统一展示时长" }]}
|
||||
extra="该时长会应用到你看到的所有屏保图片,包括平台级和个人级素材。"
|
||||
>
|
||||
<InputNumber min={3} max={3600} style={{ width: "100%" }} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<ScreenSaverCropDialog
|
||||
state={cropState}
|
||||
onCancel={() => setCropState((prev) => ({ ...prev, open: false, src: "" }))}
|
||||
|
|
|
|||
Loading…
Reference in New Issue