增加客户
This commit is contained in:
parent
877b451f4b
commit
e99bf68869
|
|
@ -1,5 +1,10 @@
|
|||
package cn.hangtag.module.oms.controller.admin.customer;
|
||||
|
||||
import cn.hangtag.framework.common.util.collection.MapUtils;
|
||||
import cn.hangtag.framework.ip.core.utils.AreaUtils;
|
||||
import cn.hangtag.module.system.api.dept.dto.DeptRespDTO;
|
||||
import cn.hangtag.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
|
@ -13,6 +18,7 @@ import javax.validation.*;
|
|||
import javax.servlet.http.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import cn.hangtag.framework.common.pojo.PageParam;
|
||||
import cn.hangtag.framework.common.pojo.PageResult;
|
||||
|
|
@ -24,6 +30,7 @@ import cn.hangtag.framework.excel.core.util.ExcelUtils;
|
|||
|
||||
import cn.hangtag.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import static cn.hangtag.framework.apilog.core.enums.OperateTypeEnum.*;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import cn.hangtag.module.oms.controller.admin.customer.vo.*;
|
||||
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerDO;
|
||||
|
|
@ -39,6 +46,8 @@ public class CustomerController {
|
|||
@Resource
|
||||
private CustomerService customerService;
|
||||
|
||||
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建客户")
|
||||
@PreAuthorize("@ss.hasPermission('oms:customer:create')")
|
||||
|
|
@ -72,6 +81,24 @@ public class CustomerController {
|
|||
return success(BeanUtils.toBean(customer, CustomerRespVO.class));
|
||||
}
|
||||
|
||||
private CustomerRespVO buildClueDetail(CustomerDO clue) {
|
||||
if (clue == null) {
|
||||
return null;
|
||||
}
|
||||
return buildDetailList(singletonList(clue)).get(0);
|
||||
}
|
||||
|
||||
|
||||
private List<CustomerRespVO> buildDetailList(List<CustomerDO> list) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 2. 转换成 VO
|
||||
return BeanUtils.toBean(list, CustomerRespVO.class, customerVO -> {
|
||||
customerVO.setAreaName(AreaUtils.format(customerVO.getAreaId()));
|
||||
});
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得客户分页")
|
||||
@PreAuthorize("@ss.hasPermission('oms:customer:query')")
|
||||
|
|
@ -103,4 +130,8 @@ public class CustomerController {
|
|||
return success(customerService.getCustomerAddressListByCustomerId(customerId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -34,9 +34,13 @@ public class CustomerRespVO {
|
|||
@ExcelProperty("联系人手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "所属地区")
|
||||
@Schema(description = "所属地区", example = "1024")
|
||||
@ExcelProperty("所属地区")
|
||||
private String district;
|
||||
private Integer areaId;
|
||||
|
||||
@Schema(description = "地区名称", example = "北京市")
|
||||
@ExcelProperty("地区名称")
|
||||
private String areaName;
|
||||
|
||||
@Schema(description = "类型", example = "2")
|
||||
@ExcelProperty("类型")
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class CustomerSaveReqVO {
|
|||
private String phone;
|
||||
|
||||
@Schema(description = "所属地区")
|
||||
private String district;
|
||||
private Integer areaId;
|
||||
|
||||
@Schema(description = "数据状态", example = "2")
|
||||
private String status;
|
||||
|
|
|
|||
|
|
@ -39,18 +39,10 @@ public class CustomerAddressDO extends BaseDO {
|
|||
* 联系电话
|
||||
*/
|
||||
private String phone;
|
||||
/**
|
||||
* 省份
|
||||
*/
|
||||
private String province;
|
||||
/**
|
||||
* 城市
|
||||
*/
|
||||
private String city;
|
||||
/**
|
||||
* 区/县
|
||||
*/
|
||||
private String district;
|
||||
private Integer areaId;
|
||||
/**
|
||||
* 详细地址
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class CustomerDO extends BaseDO {
|
|||
/**
|
||||
* 所属地区
|
||||
*/
|
||||
private String district;
|
||||
private Integer areaId;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
package cn.hangtag.module.oms.service.customer;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import cn.hangtag.framework.test.core.ut.BaseDbUnitTest;
|
||||
|
||||
import cn.hangtag.module.oms.controller.admin.customer.vo.*;
|
||||
import cn.hangtag.module.oms.dal.dataobject.customer.CustomerDO;
|
||||
import cn.hangtag.module.oms.dal.mysql.customer.CustomerMapper;
|
||||
import cn.hangtag.framework.common.pojo.PageResult;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.*;
|
||||
import static cn.hangtag.module.oms.enums.ErrorCodeConstants.*;
|
||||
import static cn.hangtag.framework.test.core.util.AssertUtils.*;
|
||||
import static cn.hangtag.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.hangtag.framework.common.util.date.LocalDateTimeUtils.*;
|
||||
import static cn.hangtag.framework.common.util.object.ObjectUtils.*;
|
||||
import static cn.hangtag.framework.common.util.date.DateUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* {@link CustomerServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author wwb
|
||||
*/
|
||||
@Import(CustomerServiceImpl.class)
|
||||
public class CustomerServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private CustomerServiceImpl customerService;
|
||||
|
||||
@Resource
|
||||
private CustomerMapper customerMapper;
|
||||
|
||||
@Test
|
||||
public void testCreateCustomer_success() {
|
||||
// 准备参数
|
||||
CustomerSaveReqVO createReqVO = randomPojo(CustomerSaveReqVO.class).setId(null);
|
||||
|
||||
// 调用
|
||||
Long customerId = customerService.createCustomer(createReqVO);
|
||||
// 断言
|
||||
assertNotNull(customerId);
|
||||
// 校验记录的属性是否正确
|
||||
CustomerDO customer = customerMapper.selectById(customerId);
|
||||
assertPojoEquals(createReqVO, customer, "id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateCustomer_success() {
|
||||
// mock 数据
|
||||
CustomerDO dbCustomer = randomPojo(CustomerDO.class);
|
||||
customerMapper.insert(dbCustomer);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
CustomerSaveReqVO updateReqVO = randomPojo(CustomerSaveReqVO.class, o -> {
|
||||
o.setId(dbCustomer.getId()); // 设置更新的 ID
|
||||
});
|
||||
|
||||
// 调用
|
||||
customerService.updateCustomer(updateReqVO);
|
||||
// 校验是否更新正确
|
||||
CustomerDO customer = customerMapper.selectById(updateReqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(updateReqVO, customer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateCustomer_notExists() {
|
||||
// 准备参数
|
||||
CustomerSaveReqVO updateReqVO = randomPojo(CustomerSaveReqVO.class);
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> customerService.updateCustomer(updateReqVO), CUSTOMER_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteCustomer_success() {
|
||||
// mock 数据
|
||||
CustomerDO dbCustomer = randomPojo(CustomerDO.class);
|
||||
customerMapper.insert(dbCustomer);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
Long id = dbCustomer.getId();
|
||||
|
||||
// 调用
|
||||
customerService.deleteCustomer(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(customerMapper.selectById(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteCustomer_notExists() {
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> customerService.deleteCustomer(id), CUSTOMER_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
|
||||
public void testGetCustomerPage() {
|
||||
// mock 数据
|
||||
CustomerDO dbCustomer = randomPojo(CustomerDO.class, o -> { // 等会查询到
|
||||
o.setId(null);
|
||||
o.setName(null);
|
||||
o.setType(null);
|
||||
o.setStatus(null);
|
||||
});
|
||||
customerMapper.insert(dbCustomer);
|
||||
// 测试 id 不匹配
|
||||
customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setId(null)));
|
||||
// 测试 name 不匹配
|
||||
customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setName(null)));
|
||||
// 测试 type 不匹配
|
||||
customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setType(null)));
|
||||
// 测试 status 不匹配
|
||||
customerMapper.insert(cloneIgnoreId(dbCustomer, o -> o.setStatus(null)));
|
||||
// 准备参数
|
||||
CustomerPageReqVO reqVO = new CustomerPageReqVO();
|
||||
reqVO.setId(null);
|
||||
reqVO.setName(null);
|
||||
reqVO.setType(null);
|
||||
reqVO.setStatus(null);
|
||||
|
||||
// 调用
|
||||
PageResult<CustomerDO> pageResult = customerService.getCustomerPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbCustomer, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,52 +1,53 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 客户 VO
|
||||
export interface CustomerVO {
|
||||
name: string // 名称
|
||||
email: string // 邮箱
|
||||
contacts: string // 联系人
|
||||
phone: string // 联系人手机号
|
||||
district: string // 所属地区
|
||||
type: string // 类型
|
||||
remarks: string // 备注
|
||||
}
|
||||
|
||||
// 客户 API
|
||||
export const CustomerApi = {
|
||||
// 查询客户分页
|
||||
getCustomerPage: async (params: any) => {
|
||||
return await request.get({ url: `/oms/customer/page`, params })
|
||||
},
|
||||
|
||||
// 查询客户详情
|
||||
getCustomer: async (id: number) => {
|
||||
return await request.get({ url: `/oms/customer/get?id=` + id })
|
||||
},
|
||||
|
||||
// 新增客户
|
||||
createCustomer: async (data: CustomerVO) => {
|
||||
return await request.post({ url: `/oms/customer/create`, data })
|
||||
},
|
||||
|
||||
// 修改客户
|
||||
updateCustomer: async (data: CustomerVO) => {
|
||||
return await request.put({ url: `/oms/customer/update`, data })
|
||||
},
|
||||
|
||||
// 删除客户
|
||||
deleteCustomer: async (id: number) => {
|
||||
return await request.delete({ url: `/oms/customer/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 导出客户 Excel
|
||||
exportCustomer: async (params) => {
|
||||
return await request.download({ url: `/oms/customer/export-excel`, params })
|
||||
},
|
||||
|
||||
// ==================== 子表(用户地址) ====================
|
||||
|
||||
// 获得用户地址列表
|
||||
getCustomerAddressListByCustomerId: async (customerId) => {
|
||||
return await request.get({ url: `/oms/customer/customer-address/list-by-customer-id?customerId=` + customerId })
|
||||
},
|
||||
}
|
||||
import request from '@/config/axios'
|
||||
|
||||
// 客户 VO
|
||||
export interface CustomerVO {
|
||||
name: string // 名称
|
||||
email: string // 邮箱
|
||||
contacts: string // 联系人
|
||||
phone: string // 联系人手机号
|
||||
areaId: number // 所在地
|
||||
areaName?: string // 所在地名称
|
||||
type: string // 类型
|
||||
remarks: string // 备注
|
||||
}
|
||||
|
||||
// 客户 API
|
||||
export const CustomerApi = {
|
||||
// 查询客户分页
|
||||
getCustomerPage: async (params: any) => {
|
||||
return await request.get({ url: `/oms/customer/page`, params })
|
||||
},
|
||||
|
||||
// 查询客户详情
|
||||
getCustomer: async (id: number) => {
|
||||
return await request.get({ url: `/oms/customer/get?id=` + id })
|
||||
},
|
||||
|
||||
// 新增客户
|
||||
createCustomer: async (data: CustomerVO) => {
|
||||
return await request.post({ url: `/oms/customer/create`, data })
|
||||
},
|
||||
|
||||
// 修改客户
|
||||
updateCustomer: async (data: CustomerVO) => {
|
||||
return await request.put({ url: `/oms/customer/update`, data })
|
||||
},
|
||||
|
||||
// 删除客户
|
||||
deleteCustomer: async (id: number) => {
|
||||
return await request.delete({ url: `/oms/customer/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 导出客户 Excel
|
||||
exportCustomer: async (params) => {
|
||||
return await request.download({ url: `/oms/customer/export-excel`, params })
|
||||
},
|
||||
|
||||
// ==================== 子表(用户地址) ====================
|
||||
|
||||
// 获得用户地址列表
|
||||
getCustomerAddressListByCustomerId: async (customerId) => {
|
||||
return await request.get({ url: `/oms/customer/customer-address/list-by-customer-id?customerId=` + customerId })
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
<el-form-item label="联系人手机号" prop="phone">
|
||||
<el-input v-model="formData.phone" placeholder="请输入联系人手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="所属地区" prop="district">
|
||||
<el-form-item label="所属地区" prop="areaId">
|
||||
<el-cascader
|
||||
v-model="formData.district"
|
||||
v-model="formData.areaId"
|
||||
:options="areaList"
|
||||
:props="defaultProps"
|
||||
class="w-1/1"
|
||||
|
|
@ -81,7 +81,7 @@ const formData = ref({
|
|||
email: undefined,
|
||||
contacts: undefined,
|
||||
phone: undefined,
|
||||
district: undefined,
|
||||
areaId: undefined,
|
||||
status: undefined,
|
||||
type: undefined,
|
||||
remarks: undefined,
|
||||
|
|
@ -171,7 +171,7 @@ const resetForm = () => {
|
|||
email: undefined,
|
||||
contacts: undefined,
|
||||
phone: undefined,
|
||||
district: undefined,
|
||||
areaId: undefined,
|
||||
status: '1',
|
||||
type: undefined,
|
||||
remarks: undefined,
|
||||
|
|
|
|||
|
|
@ -23,14 +23,23 @@
|
|||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="省份" min-width="150">
|
||||
<el-table-column label="请选择地区" min-width="150">
|
||||
<template #default="{ row, $index }">
|
||||
<el-form-item :prop="`${$index}.province`" :rules="formRules.province" class="mb-0px!">
|
||||
<el-input v-model="row.province" placeholder="请输入省份" />
|
||||
<el-form-item :prop="`${$index}.areaId`" :rules="formRules.areaId" class="mb-0px!">
|
||||
<el-cascader
|
||||
v-model="row.areaId"
|
||||
:options="areaList"
|
||||
:props="defaultProps"
|
||||
class="w-1/1"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择地区"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="城市" min-width="150">
|
||||
|
||||
<!-- <el-table-column label="城市" min-width="150">
|
||||
<template #default="{ row, $index }">
|
||||
<el-form-item :prop="`${$index}.city`" :rules="formRules.city" class="mb-0px!">
|
||||
<el-input v-model="row.city" placeholder="请输入城市" />
|
||||
|
|
@ -39,15 +48,15 @@
|
|||
</el-table-column>
|
||||
<el-table-column label="区/县" min-width="150">
|
||||
<template #default="{ row, $index }">
|
||||
<el-form-item :prop="`${$index}.district`" :rules="formRules.district" class="mb-0px!">
|
||||
<el-input v-model="row.district" placeholder="请输入区/县" />
|
||||
<el-form-item :prop="`${$index}.areaId`" :rules="formRules.areaId" class="mb-0px!">
|
||||
<el-input v-model="row.areaId" placeholder="请输入区/县" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>-->
|
||||
<el-table-column label="详细地址" min-width="150">
|
||||
<template #default="{ row, $index }">
|
||||
<el-form-item :prop="`${$index}.address`" :rules="formRules.address" class="mb-0px!">
|
||||
<el-input v-model="row.address" placeholder="请输入详细地址" />
|
||||
<el-input v-model="row.address" placeholder="请输入详细地址" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
|
@ -74,6 +83,8 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { CustomerApi } from '@/api/oms/customer'
|
||||
import {defaultProps} from "@/utils/tree";
|
||||
import * as AreaApi from "@/api/system/area";
|
||||
|
||||
const props = defineProps<{
|
||||
customerId: undefined // 关联到客户的ID,外键指向客户表(主表的关联字段)
|
||||
|
|
@ -84,14 +95,13 @@ const formRules = reactive({
|
|||
customerId: [{ required: true, message: '关联到客户的ID,外键指向客户表不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '收货人姓名不能为空', trigger: 'blur' }],
|
||||
phone: [{ required: true, message: '联系电话不能为空', trigger: 'blur' }],
|
||||
province: [{ required: true, message: '省份不能为空', trigger: 'blur' }],
|
||||
city: [{ required: true, message: '城市不能为空', trigger: 'blur' }],
|
||||
district: [{ required: true, message: '区/县不能为空', trigger: 'blur' }],
|
||||
areaId: [{ required: true, message: '地区不能为空', trigger: 'blur' }],
|
||||
address: [{ required: true, message: '详细地址不能为空', trigger: 'blur' }],
|
||||
isDefault: [{ required: true, message: '默认地址不能为空', trigger: 'blur' }],
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
const changeFlag = ref(true) // 是否开启change事件
|
||||
const areaList = ref([]) // 地区列表
|
||||
|
||||
/** 监听主表的关联字段的变化,加载对应的子表数据 */
|
||||
watch(
|
||||
|
|
@ -120,9 +130,7 @@ const handleAdd = () => {
|
|||
customerId: undefined,
|
||||
name: undefined,
|
||||
phone: undefined,
|
||||
province: undefined,
|
||||
city: undefined,
|
||||
district: undefined,
|
||||
areaId: undefined,
|
||||
address: undefined,
|
||||
isDefault: [],
|
||||
}
|
||||
|
|
@ -146,7 +154,7 @@ const getData = () => {
|
|||
return formData.value
|
||||
}
|
||||
|
||||
defineExpose({ validate, getData })
|
||||
defineExpose({ validate, getData})
|
||||
|
||||
|
||||
const handleSwitchChange = async (index: number, value?: string) => {
|
||||
|
|
@ -163,5 +171,10 @@ const handleSwitchChange = async (index: number, value?: string) => {
|
|||
formData.value[index].isDefault = true
|
||||
}
|
||||
}
|
||||
/** 初始化 **/
|
||||
onMounted(async() => {
|
||||
// 获得地区列表
|
||||
areaList.value = await AreaApi.getAreaTree()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@
|
|||
<el-table-column label="邮箱" align="center" prop="email" />
|
||||
<el-table-column label="联系人" align="center" prop="contacts" />
|
||||
<el-table-column label="联系人手机号" align="center" prop="phone" />
|
||||
<el-table-column label="所属地区" align="center" prop="district" />
|
||||
<el-table-column label="所属地区" align="center" prop="areaId" />
|
||||
<el-table-column label="类型" align="center" prop="type" />
|
||||
<el-table-column label="数据状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
|
|
|
|||
Loading…
Reference in New Issue