feat(api): add list endpoints and dashboard stats

This commit is contained in:
2026-07-07 15:12:05 +08:00
parent dfce1be9b2
commit ee82e6e447
12 changed files with 158 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
package com.sino.mci.admin.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sino.mci.admin.dto.DashboardStatsResponse;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.channel.entity.ChannelAccount;
import com.sino.mci.channel.entity.ChannelSubject;
import com.sino.mci.channel.entity.Conversation;
import com.sino.mci.channel.repository.ChannelAccountMapper;
import com.sino.mci.channel.repository.ChannelSubjectMapper;
import com.sino.mci.channel.repository.ConversationMapper;
import com.sino.mci.send.entity.SendRecord;
import com.sino.mci.send.repository.SendRecordMapper;
import com.sino.mci.shared.web.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
@RestController
@RequestMapping("/api/v1/dashboard")
@RequiredArgsConstructor
public class DashboardController {
private final ChannelSubjectMapper subjectMapper;
private final ChannelAccountMapper accountMapper;
private final ConversationMapper conversationMapper;
private final SendRecordMapper sendRecordMapper;
@GetMapping("/stats")
public ApiResponse<DashboardStatsResponse> stats() {
String tenantCode = AuthContext.currentTenantCode();
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
DashboardStatsResponse response = new DashboardStatsResponse();
response.setSubjectCount(subjectMapper.selectCount(
new LambdaQueryWrapper<ChannelSubject>()
.eq(ChannelSubject::getTenantCode, tenantCode)
.eq(ChannelSubject::getStatus, 1)));
response.setAccountCount(accountMapper.selectCount(
new LambdaQueryWrapper<ChannelAccount>()
.eq(ChannelAccount::getTenantCode, tenantCode)
.eq(ChannelAccount::getStatus, 1)));
response.setConversationCount(conversationMapper.selectCount(
new LambdaQueryWrapper<Conversation>()
.eq(Conversation::getTenantCode, tenantCode)
.eq(Conversation::getStatus, 1)));
response.setSentToday(sendRecordMapper.selectCount(
new LambdaQueryWrapper<SendRecord>()
.eq(SendRecord::getTenantCode, tenantCode)
.ge(SendRecord::getSendTime, startOfDay)
.le(SendRecord::getSendTime, endOfDay)));
return ApiResponse.ok(response);
}
}

View File

@@ -0,0 +1,12 @@
package com.sino.mci.admin.dto;
import lombok.Data;
@Data
public class DashboardStatsResponse {
private Long subjectCount;
private Long accountCount;
private Long conversationCount;
private Long sentToday;
}

View File

@@ -1,13 +1,17 @@
package com.sino.mci.channel.controller;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.channel.dto.ChannelAccountInitRequest;
import com.sino.mci.channel.dto.CreateChannelAccountRequest;
import com.sino.mci.channel.entity.ChannelAccount;
import com.sino.mci.channel.service.ChannelAccountService;
import com.sino.mci.shared.web.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/channel-account")
@RequiredArgsConstructor
@@ -28,4 +32,9 @@ public class ChannelAccountController {
@Valid @RequestBody ChannelAccountInitRequest request) {
return ApiResponse.ok(accountService.initAccount(tenantCode, request));
}
@GetMapping("/list")
public ApiResponse<List<ChannelAccount>> listAccounts() {
return ApiResponse.ok(accountService.listAccounts(AuthContext.currentTenantCode()));
}
}

View File

@@ -1,12 +1,16 @@
package com.sino.mci.channel.controller;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.channel.dto.CreateChannelSubjectRequest;
import com.sino.mci.channel.entity.ChannelSubject;
import com.sino.mci.channel.service.ChannelSubjectService;
import com.sino.mci.shared.web.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/channel-subject")
@RequiredArgsConstructor
@@ -20,4 +24,9 @@ public class ChannelSubjectController {
@Valid @RequestBody CreateChannelSubjectRequest request) {
return ApiResponse.ok(subjectService.createSubject(tenantCode, request));
}
@GetMapping("/list")
public ApiResponse<List<ChannelSubject>> listSubjects() {
return ApiResponse.ok(subjectService.listSubjects(AuthContext.currentTenantCode()));
}
}

View File

@@ -1,14 +1,18 @@
package com.sino.mci.channel.controller;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.channel.dto.BindConversationAccountRequest;
import com.sino.mci.channel.dto.BindConversationTagsRequest;
import com.sino.mci.channel.dto.CreateConversationRequest;
import com.sino.mci.channel.entity.Conversation;
import com.sino.mci.channel.service.ConversationService;
import com.sino.mci.shared.web.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/conversation")
@RequiredArgsConstructor
@@ -23,6 +27,11 @@ public class ConversationController {
return ApiResponse.ok(conversationService.createConversation(tenantCode, request));
}
@GetMapping("/list")
public ApiResponse<List<Conversation>> listConversations() {
return ApiResponse.ok(conversationService.listConversations(AuthContext.currentTenantCode()));
}
@GetMapping("/{conversation_id}")
public ApiResponse<?> getConversation(
@RequestHeader("X-Tenant-Code") String tenantCode,

View File

@@ -12,6 +12,8 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ChannelAccountService {
@@ -19,6 +21,14 @@ public class ChannelAccountService {
private final ChannelAccountMapper accountMapper;
private final ChannelSubjectMapper subjectMapper;
public List<ChannelAccount> listAccounts(String tenantCode) {
return accountMapper.selectList(
new LambdaQueryWrapper<ChannelAccount>()
.eq(ChannelAccount::getTenantCode, tenantCode)
.eq(ChannelAccount::getStatus, 1)
.orderByDesc(ChannelAccount::getId));
}
@Transactional
public ChannelAccount createAccount(String tenantCode, CreateChannelAccountRequest request) {
if (request.getSubjectId() != null) {

View File

@@ -9,12 +9,22 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ChannelSubjectService {
private final ChannelSubjectMapper subjectMapper;
public List<ChannelSubject> listSubjects(String tenantCode) {
return subjectMapper.selectList(
new LambdaQueryWrapper<ChannelSubject>()
.eq(ChannelSubject::getTenantCode, tenantCode)
.eq(ChannelSubject::getStatus, 1)
.orderByDesc(ChannelSubject::getId));
}
@Transactional
public ChannelSubject createSubject(String tenantCode, CreateChannelSubjectRequest request) {
ChannelSubject existing = subjectMapper.selectOne(

View File

@@ -31,6 +31,14 @@ public class ConversationService {
private final ConversationTagBindingMapper conversationTagBindingMapper;
private final TagMapper tagMapper;
public List<Conversation> listConversations(String tenantCode) {
return conversationMapper.selectList(
new LambdaQueryWrapper<Conversation>()
.eq(Conversation::getTenantCode, tenantCode)
.eq(Conversation::getStatus, 1)
.orderByDesc(Conversation::getId));
}
@Transactional
public Conversation createConversation(String tenantCode, CreateConversationRequest request) {
Conversation existing = conversationMapper.selectOne(

View File

@@ -1,14 +1,18 @@
package com.sino.mci.crm.controller;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.crm.dto.BindTagsRequest;
import com.sino.mci.crm.dto.CreateIdentityRequest;
import com.sino.mci.crm.dto.CreatePersonRequest;
import com.sino.mci.crm.entity.Person;
import com.sino.mci.crm.service.PersonService;
import com.sino.mci.shared.web.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/person")
@RequiredArgsConstructor
@@ -23,6 +27,11 @@ public class PersonController {
return ApiResponse.ok(personService.createPerson(tenantCode, request));
}
@GetMapping("/list")
public ApiResponse<List<Person>> listPersons() {
return ApiResponse.ok(personService.listPersons(AuthContext.currentTenantCode()));
}
@GetMapping("/{person_id}")
public ApiResponse<?> getPerson(
@RequestHeader("X-Tenant-Code") String tenantCode,

View File

@@ -31,6 +31,14 @@ public class PersonService {
private final PersonTagBindingMapper personTagBindingMapper;
private final TagMapper tagMapper;
public List<Person> listPersons(String tenantCode) {
return personMapper.selectList(
new LambdaQueryWrapper<Person>()
.eq(Person::getTenantCode, tenantCode)
.eq(Person::getStatus, 1)
.orderByDesc(Person::getId));
}
@Transactional
public Person createPerson(String tenantCode, CreatePersonRequest request) {
Person person = new Person();

View File

@@ -1,5 +1,6 @@
package com.sino.mci.send.controller;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.send.dto.SendRecordResponse;
import com.sino.mci.send.dto.SendRequest;
import com.sino.mci.send.dto.SendResponse;
@@ -39,4 +40,9 @@ public class SendController {
@PathVariable("task_id") String taskId) {
return ApiResponse.ok(sendService.listRecords(tenantCode, taskId));
}
@GetMapping("/list")
public ApiResponse<List<SendRecordResponse>> listRecentRecords() {
return ApiResponse.ok(sendService.listRecentRecords(AuthContext.currentTenantCode()));
}
}

View File

@@ -101,6 +101,14 @@ public class SendService {
return records.stream().map(this::toResponse).collect(Collectors.toList());
}
public List<SendRecordResponse> listRecentRecords(String tenantCode) {
List<SendRecord> records = sendRecordMapper.selectList(
new LambdaQueryWrapper<SendRecord>()
.eq(SendRecord::getTenantCode, tenantCode)
.orderByDesc(SendRecord::getId));
return records.stream().limit(50).map(this::toResponse).collect(Collectors.toList());
}
private String generateTaskId() {
return "SND" + UUID.randomUUID().toString().replace("-", "").toUpperCase();
}