package com.tcm.training.admin.app.home.service; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.symmetric.SymmetricCrypto; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.tcm.training.admin.agent.entity.ProvincialAgent; import com.tcm.training.admin.agent.mapper.ProvincialAgentMapper; import com.tcm.training.admin.app.home.vo.AppVzanLiveEntryVO; import com.tcm.training.admin.app.user.service.AppUserCenterService; import com.tcm.training.admin.app.user.vo.AppUserCenterVO; import com.tcm.training.admin.live.entity.Clinic; import com.tcm.training.admin.live.mapper.ClinicMapper; import com.tcm.training.admin.live.service.LiveRoomSettingService; import com.tcm.training.admin.live.vo.LiveRoomSettingVO; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; import java.nio.charset.StandardCharsets; @Slf4j @Service public class AppVzanLiveEntryService { private static final String VZAN_AUTH_SECRET = "2b4fefe91d8cba50"; private final LiveRoomSettingService liveRoomSettingService; private final AppUserCenterService appUserCenterService; private final ClinicMapper clinicMapper; private final ProvincialAgentMapper provincialAgentMapper; public AppVzanLiveEntryService(LiveRoomSettingService liveRoomSettingService, AppUserCenterService appUserCenterService, ClinicMapper clinicMapper, ProvincialAgentMapper provincialAgentMapper) { this.liveRoomSettingService = liveRoomSettingService; this.appUserCenterService = appUserCenterService; this.clinicMapper = clinicMapper; this.provincialAgentMapper = provincialAgentMapper; } public AppVzanLiveEntryVO createEntry() { LiveRoomSettingVO setting = liveRoomSettingService.current(); String liveRoomUrl = setting == null ? null : StrUtil.trim(setting.getLiveRoomUrl()); validateLiveRoomUrl(liveRoomUrl); AppUserCenterVO user = appUserCenterService.getCurrentUserCenter(); String followPhone = resolveFollowPhone(user.getClinicId()); JSONObject payload = new JSONObject(); payload.set("tuid", user.getId()); payload.set("followPhone", followPhone); payload.set("third_ts", System.currentTimeMillis()); payload.set("avatar", StrUtil.trim(user.getAvatar())); log.info("微赞入口参数已生成,tuid={}, third_ts={}", user.getId(), payload.get("third_ts")); SymmetricCrypto sm4 = SmUtil.sm4(VZAN_AUTH_SECRET.getBytes(StandardCharsets.UTF_8)); String encryptedData = sm4.encryptBase64(payload.toString(), StandardCharsets.UTF_8); String entryUrl = UriComponentsBuilder.fromHttpUrl(liveRoomUrl) .replaceQueryParam("data", encryptedData) .build() .encode(StandardCharsets.UTF_8) .toUriString(); log.info("微赞直播生成URL: {}", entryUrl); return new AppVzanLiveEntryVO(entryUrl); } private String resolveFollowPhone(Long clinicId) { if (clinicId == null) { throw new IllegalArgumentException("当前用户未绑定诊所"); } Clinic clinic = clinicMapper.selectById(clinicId); if (clinic == null || clinic.getAgentId() == null) { throw new IllegalArgumentException("当前诊所未绑定代理"); } ProvincialAgent agent = provincialAgentMapper.selectById(clinic.getAgentId()); String contactInfo = agent == null ? null : StrUtil.trim(agent.getContactInfo()); if (StrUtil.isBlank(contactInfo)) { throw new IllegalArgumentException("所属代理未配置联系电话"); } return contactInfo; } private void validateLiveRoomUrl(String liveRoomUrl) { if (StrUtil.isBlank(liveRoomUrl)) { throw new IllegalArgumentException("直播间地址暂未配置"); } try { URI uri = URI.create(liveRoomUrl); if (!"https".equalsIgnoreCase(uri.getScheme()) || StrUtil.isBlank(uri.getHost())) { throw new IllegalArgumentException("直播间地址必须为有效的HTTPS地址"); } } catch (IllegalArgumentException ex) { throw new IllegalArgumentException("直播间地址必须为有效的HTTPS地址", ex); } } }