diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/customer/CustomerController.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/customer/CustomerController.java index 537272b..b97c107 100644 --- a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/customer/CustomerController.java +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/customer/CustomerController.java @@ -8,6 +8,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -20,6 +21,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; + /** * 客户 API。{@code DELETE /{id}} 为软删除:将 {@code status} 置为 {@code INACTIVE}(可重复调用)。 */ @@ -53,6 +56,11 @@ public class CustomerController { return customerService.getById(id); } + @GetMapping("/{id}/summary") + public ResponseEntity> getSummary(@PathVariable Long id) { + return ResponseEntity.ok(customerService.getCustomerSummary(id)); + } + @PutMapping("/{id}") public CustomerResponse update( @PathVariable("id") long id, @Valid @RequestBody CustomerRequest request) { diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/CustomerService.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/CustomerService.java index 86a7326..d97a238 100644 --- a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/CustomerService.java +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/CustomerService.java @@ -3,6 +3,8 @@ package cn.craftlabs.platform.api.service; import cn.craftlabs.platform.api.domain.CustomerStatus; import cn.craftlabs.platform.api.persistence.customer.PlatformCustomer; import cn.craftlabs.platform.api.persistence.customer.PlatformCustomerMapper; +import cn.craftlabs.platform.api.persistence.project.PlatformProject; +import cn.craftlabs.platform.api.persistence.project.PlatformProjectMapper; import cn.craftlabs.platform.api.web.dto.CustomerRequest; import cn.craftlabs.platform.api.web.dto.CustomerResponse; import cn.craftlabs.platform.api.web.dto.PageResponse; @@ -18,15 +20,18 @@ import org.springframework.web.server.ResponseStatusException; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Service public class CustomerService { private final PlatformCustomerMapper customerMapper; + private final PlatformProjectMapper projectMapper; - public CustomerService(PlatformCustomerMapper customerMapper) { + public CustomerService(PlatformCustomerMapper customerMapper, PlatformProjectMapper projectMapper) { this.customerMapper = customerMapper; + this.projectMapper = projectMapper; } @Transactional(readOnly = true) @@ -113,6 +118,18 @@ public class CustomerService { customerMapper.updateById(c); } + @Transactional(readOnly = true) + public Map getCustomerSummary(Long customerId) { + Map result = new java.util.LinkedHashMap<>(); + var projectQuery = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper(); + projectQuery.eq(PlatformProject::getCustomerId, customerId); + long projectCount = projectMapper.selectCount(projectQuery); + result.put("projectCount", projectCount); + result.put("contractCount", 0); + result.put("snCount", 0); + return result; + } + @Transactional(readOnly = true) public void requireExists(long id) { if (customerMapper.selectById(id) == null) { diff --git a/web/delivery-platform-ui/src/api/platform.js b/web/delivery-platform-ui/src/api/platform.js index f26fb57..1947a66 100644 --- a/web/delivery-platform-ui/src/api/platform.js +++ b/web/delivery-platform-ui/src/api/platform.js @@ -38,6 +38,10 @@ export function deleteProject(id) { return axios.delete(`/api/v1/projects/${id}`); } +export function getCustomerSummary(id) { + return axios.get(`/api/v1/customers/${id}/summary`); +} + export function getProjectPhaseDictionary() { return axios.get("/api/v1/dictionaries/PROJECT_PHASE"); } diff --git a/web/delivery-platform-ui/src/router/index.js b/web/delivery-platform-ui/src/router/index.js index f5b1722..d9bc90d 100644 --- a/web/delivery-platform-ui/src/router/index.js +++ b/web/delivery-platform-ui/src/router/index.js @@ -14,6 +14,12 @@ const routes = [ component: () => import("../views/HomeView.vue"), meta: { roles: ["SYS_ADMIN", "DEVELOPER", "OPS"] }, }, + { + path: "customers/:id", + name: "customer-detail", + component: () => import("../views/CustomerDetailView.vue"), + meta: { roles: ["SYS_ADMIN", "DEVELOPER"], title: "客户详情" }, + }, { path: "customers", name: "customers", diff --git a/web/delivery-platform-ui/src/views/CustomerDetailView.vue b/web/delivery-platform-ui/src/views/CustomerDetailView.vue new file mode 100644 index 0000000..400e7be --- /dev/null +++ b/web/delivery-platform-ui/src/views/CustomerDetailView.vue @@ -0,0 +1,60 @@ + + + + + ← 客户列表 + 客户详情 #{{ customerId }} + + + + + 关联项目 + {{ summary?.projectCount ?? '—' }} + + + + + 在履约合同 + {{ summary?.contractCount ?? '—' }} + + + + + 在途 SN + {{ summary?.snCount ?? '—' }} + + + + + diff --git a/web/delivery-platform-ui/src/views/CustomersView.vue b/web/delivery-platform-ui/src/views/CustomersView.vue index 342065a..5e221a9 100644 --- a/web/delivery-platform-ui/src/views/CustomersView.vue +++ b/web/delivery-platform-ui/src/views/CustomersView.vue @@ -20,12 +20,13 @@ - - - 编辑 - 删除 - - + + + 详情 + 编辑 + 删除 + + @@ -73,11 +74,13 @@