fix(family-card): 修正管理页面并支持解绑
| | |
| | | }) |
| | | } |
| | | |
| | | export function unbindFamilyCard(id: number | string) { |
| | | return http.patch<FamilyCardApplication, FamilyCardApplication>(`/api/admin/dependent-card-applies/${id}/unbind`) |
| | | } |
| | | |
| | | export function getUpgradeApplications(params: UpgradeApplicationQuery = {}) { |
| | | return http.get<PageResult<UpgradeApplication>, PageResult<UpgradeApplication>>( |
| | | '/api/admin/cards/upgrade-applications', |
| | |
| | | { |
| | | path: 'family-cards/:id', |
| | | name: 'family-card-detail', |
| | | component: () => import('../views/FamilyCardApplicationDetailView.vue'), |
| | | component: () => import('../views/FamilyCardDetailView.vue'), |
| | | meta: { title: '家属卡详情' }, |
| | | }, |
| | | { |
| | |
| | | gap: 24px; |
| | | } |
| | | |
| | | .family-card-detail-page { |
| | | display: grid; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .family-card-detail-panel { |
| | | min-height: 430px; |
| | | padding: 20px 18px 26px; |
| | | background: #ffffff; |
| | | } |
| | | |
| | | .reservation-detail-grid.family-card-owner-grid { |
| | | min-height: 140px; |
| | | align-content: start; |
| | | } |
| | | |
| | | .reservation-detail-grid.family-card-member-grid { |
| | | min-height: 112px; |
| | | align-content: start; |
| | | } |
| | | |
| | | .family-card-detail-actions { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .family-card-unbound-tip { |
| | | color: #909399; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .medical-reservation-detail-page { |
| | | display: grid; |
| | | gap: 24px; |
| | |
| | | } |
| | | |
| | | .family-card-management-page .family-card-filter-form { |
| | | grid-template-columns: minmax(250px, 1.05fr) minmax(230px, 0.9fr) minmax(320px, 1.25fr) 74px; |
| | | grid-template-columns: minmax(250px, 1fr) minmax(280px, 1.1fr) minmax(220px, 0.9fr) 74px; |
| | | gap: 12px 28px; |
| | | } |
| | | |
| | | .family-card-filter-talent { |
| | | grid-column: 1; |
| | | grid-column: 2; |
| | | } |
| | | |
| | | .family-card-filter-date { |
| | |
| | | status?: string | number |
| | | applyStart?: string |
| | | applyEnd?: string |
| | | management?: boolean |
| | | } |
| | | |
| | | export interface ChildCardApplication { |
| New file |
| | |
| | | <script setup lang="ts"> |
| | | import { computed, onMounted, ref } from 'vue' |
| | | import { useRoute } from 'vue-router' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { getFamilyCardApplicationDetail, unbindFamilyCard } from '../api/admin' |
| | | import type { FamilyCardApplication } from '../types/admin' |
| | | |
| | | const route = useRoute() |
| | | const detail = ref<FamilyCardApplication>() |
| | | const loading = ref(false) |
| | | const unbinding = ref(false) |
| | | |
| | | function text(value?: string | number | null) { |
| | | return value === undefined || value === null || value === '' ? '-' : String(value) |
| | | } |
| | | |
| | | function genderText(gender?: number | string) { |
| | | if (gender === 1 || gender === '1') return '男' |
| | | if (gender === 2 || gender === '2') return '女' |
| | | return '-' |
| | | } |
| | | |
| | | const isBound = computed(() => detail.value?.status === 1 || detail.value?.status === '1') |
| | | const cardholderInfo = computed(() => [ |
| | | { label: '持卡人姓名:', value: text(detail.value?.talentName) }, |
| | | { label: '身份证号:', value: text(detail.value?.talentIdCardNo) }, |
| | | { label: '联系方式:', value: text(detail.value?.talentMobile) }, |
| | | { label: '联系地址:', value: text(detail.value?.contactAddress) }, |
| | | { label: '工作地址:', value: text(detail.value?.workAddress) }, |
| | | { label: '性别:', value: genderText(detail.value?.gender) }, |
| | | { label: '人才等级:', value: text(detail.value?.cardLevel) }, |
| | | { label: '当前家属卡数量:', value: `${detail.value?.currentFamilyCardCount ?? 0}/${detail.value?.familyCardLimit ?? 2}` }, |
| | | ]) |
| | | const familyInfo = computed(() => [ |
| | | { label: '家属姓名:', value: text(detail.value?.familyName || detail.value?.dependentName) }, |
| | | { label: '身份证号:', value: text(detail.value?.idCardNo || detail.value?.dependentIdCardNo) }, |
| | | { label: '手机号:', value: text(detail.value?.familyMobile || detail.value?.dependentMobile) }, |
| | | { label: '与持卡人关系:', value: text(detail.value?.relationship || detail.value?.relation) }, |
| | | ]) |
| | | |
| | | async function loadDetail() { |
| | | loading.value = true |
| | | try { |
| | | detail.value = await getFamilyCardApplicationDetail(String(route.params.id)) |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | async function unbind() { |
| | | if (!detail.value) return |
| | | await ElMessageBox.confirm('解除绑定后,该家属卡将无法继续使用。确定解除吗?', '解除绑定', { |
| | | type: 'warning', |
| | | confirmButtonText: '确定解绑', |
| | | cancelButtonText: '取消', |
| | | }) |
| | | unbinding.value = true |
| | | try { |
| | | detail.value = await unbindFamilyCard(detail.value.id) |
| | | ElMessage.success('解除绑定成功') |
| | | } finally { |
| | | unbinding.value = false |
| | | } |
| | | } |
| | | |
| | | onMounted(loadDetail) |
| | | </script> |
| | | |
| | | <template> |
| | | <div v-loading="loading" class="family-card-detail-page"> |
| | | <section class="family-card-detail-panel"> |
| | | <div class="reservation-detail-section"> |
| | | <h3>持卡人信息</h3> |
| | | <div class="reservation-detail-grid family-card-owner-grid"> |
| | | <div v-for="item in cardholderInfo" :key="item.label" class="reservation-detail-item"> |
| | | <span>{{ item.label }}</span><strong>{{ item.value }}</strong> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="reservation-detail-section"> |
| | | <h3>家属信息</h3> |
| | | <div class="reservation-detail-grid family-card-member-grid"> |
| | | <div v-for="item in familyInfo" :key="item.label" class="reservation-detail-item"> |
| | | <span>{{ item.label }}</span><strong>{{ item.value }}</strong> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | <div class="family-card-detail-actions"> |
| | | <el-button v-if="isBound" type="primary" :loading="unbinding" @click="unbind">解除绑定</el-button> |
| | | <span v-else class="family-card-unbound-tip">该家属卡已解绑</span> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | const route = useRoute() |
| | | const router = useRouter() |
| | | const isManagement = computed(() => props.mode === 'management') |
| | | const emptyText = computed(() => '暂无家属卡申请数据') |
| | | const emptyText = computed(() => isManagement.value ? '暂无家属卡数据' : '暂无家属卡申请数据') |
| | | |
| | | const filters = reactive({ |
| | | familyKeyword: '', |
| | |
| | | const loading = ref(false) |
| | | const rows = ref<FamilyCardApplication[]>([]) |
| | | |
| | | const statusOptions = [ |
| | | const applicationStatusOptions = [ |
| | | { label: '待审核', value: 0 }, |
| | | { label: '已通过', value: 1 }, |
| | | { label: '已驳回', value: 2 }, |
| | | { label: '已取消', value: 3 }, |
| | | ] |
| | | const managementStatusOptions = [ |
| | | { label: '正常', value: 1 }, |
| | | { label: '已解绑', value: 3 }, |
| | | ] |
| | | const statusOptions = computed(() => isManagement.value ? managementStatusOptions : applicationStatusOptions) |
| | | |
| | | const cardLevels = ['卓越人才卡', '杰出人才卡', '菁英人才卡', '普通游客'] |
| | | |
| | | function statusText(row: FamilyCardApplication) { |
| | | if (isManagement.value) { |
| | | if (row.status === 1 || row.status === '1') return '正常' |
| | | if (row.status === 3 || row.status === '3') return '已解绑' |
| | | } |
| | | return row.statusText || '-' |
| | | } |
| | | |
| | | function registerTime(row: FamilyCardApplication) { |
| | | if (isManagement.value && row.auditTime) return row.auditTime |
| | | return row.applyTime || row.createdAt || '' |
| | | } |
| | | |
| | |
| | | const result = await getFamilyCardApplications({ |
| | | page: pagination.page, |
| | | size: pagination.size, |
| | | familyKeyword: isManagement.value ? undefined : filters.familyKeyword || undefined, |
| | | familyKeyword: filters.familyKeyword || undefined, |
| | | talentKeyword: filters.talentKeyword || undefined, |
| | | cardLevel: filters.cardLevel || undefined, |
| | | status: filters.status, |
| | | applyStart: filters.applyTime?.[0], |
| | | applyEnd: filters.applyTime?.[1], |
| | | management: isManagement.value || undefined, |
| | | }) |
| | | rows.value = result.records |
| | | pagination.total = result.total |
| | |
| | | const result = await getFamilyCardApplications({ |
| | | page: 1, |
| | | size: 1000, |
| | | familyKeyword: isManagement.value ? undefined : filters.familyKeyword || undefined, |
| | | familyKeyword: filters.familyKeyword || undefined, |
| | | talentKeyword: filters.talentKeyword || undefined, |
| | | cardLevel: filters.cardLevel || undefined, |
| | | status: filters.status, |
| | | applyStart: filters.applyTime?.[0], |
| | | applyEnd: filters.applyTime?.[1], |
| | | management: isManagement.value || undefined, |
| | | }) |
| | | downloadExcel( |
| | | isManagement.value ? '家属卡管理列表' : '家属卡申请列表', |
| | | isManagement.value ? [ |
| | | { title: '申请编号', value: row => row.applicationNo || row.applyNo }, |
| | | { title: '持卡人姓名', value: row => row.talentName }, |
| | | { title: '持卡人手机号', value: row => row.talentMobile }, |
| | | { title: '卡片等级', value: row => row.cardLevel }, |
| | | { title: '编号', value: row => row.id }, |
| | | { title: '家属姓名', value: row => familyName(row) }, |
| | | { title: '家属手机号', value: row => familyMobile(row) }, |
| | | { title: '家属关系', value: row => relationship(row) }, |
| | | { title: '申请时间', value: row => registerTime(row) }, |
| | | { title: '持卡人姓名', value: row => row.talentName }, |
| | | { title: '持卡人手机号', value: row => row.talentMobile }, |
| | | { title: '人才卡号', value: row => row.talentCardNo }, |
| | | { title: '卡片等级', value: row => row.cardLevel }, |
| | | { title: '注册时间', value: row => registerTime(row) }, |
| | | { title: '状态', value: row => statusText(row) }, |
| | | ] : [ |
| | | { title: '申请编号', value: row => row.applicationNo || row.applyNo }, |
| | |
| | | </div> |
| | | |
| | | <el-form class="family-card-filter-form" :model="filters" label-width="84px"> |
| | | <el-form-item v-if="!isManagement" label="家属信息"> |
| | | <el-input v-model="filters.familyKeyword" placeholder="请输入家属姓名、手机号或身份证号" clearable /> |
| | | <el-form-item :label="isManagement ? '家属' : '家属信息'"> |
| | | <el-input v-model="filters.familyKeyword" :placeholder="isManagement ? '家属姓名、手机号' : '请输入家属姓名、手机号或身份证号'" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="持卡人" :class="{ 'family-card-filter-talent': isManagement }"> |
| | | <el-input v-model="filters.talentKeyword" placeholder="持卡人姓名、手机号、卡号" clearable /> |
| | |
| | | </div> |
| | | |
| | | <el-table v-if="isManagement" v-loading="loading" :data="rows" class="family-card-table" :empty-text="emptyText"> |
| | | <el-table-column label="申请编号" min-width="112"> |
| | | <template #default="{ row }">{{ row.applicationNo || row.applyNo || row.id }}</template> |
| | | </el-table-column> |
| | | <el-table-column prop="talentName" label="持卡人名称" min-width="110" /> |
| | | <el-table-column prop="talentMobile" label="持卡人手机号" min-width="130" /> |
| | | <el-table-column prop="cardLevel" label="卡片等级" min-width="106" /> |
| | | <el-table-column prop="id" label="编号" width="82" align="center" /> |
| | | <el-table-column label="家属名称" min-width="106"> |
| | | <template #default="{ row }">{{ familyName(row) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="家属手机号" min-width="130"> |
| | | <template #default="{ row }">{{ familyMobile(row) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="家属关系" min-width="102"> |
| | | <template #default="{ row }">{{ relationship(row) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="申请时间" min-width="150"> |
| | | <el-table-column prop="talentName" label="持卡人名称" min-width="110" /> |
| | | <el-table-column prop="talentMobile" label="持卡人手机号" min-width="130" /> |
| | | <el-table-column prop="talentCardNo" label="人才卡号" min-width="120" /> |
| | | <el-table-column prop="cardLevel" label="卡片等级" min-width="108" /> |
| | | <el-table-column label="注册时间" min-width="150"> |
| | | <template #default="{ row }">{{ registerTime(row) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="状态" min-width="90"> |
| | |
| | | @Parameter(description = "状态:0待审核、1已通过、2已驳回、3已取消") @RequestParam(required = false) Integer status, |
| | | @Parameter(description = "申请开始日期") @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate applyStart, |
| | | @Parameter(description = "申请结束日期") @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate applyEnd, |
| | | @Parameter(description = "是否按家属卡管理范围查询(仅已绑定和已解绑)") @RequestParam(defaultValue = "false") boolean management, |
| | | @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page, |
| | | @Parameter(description = "每页数量,最大100") @RequestParam(defaultValue = "10") int size |
| | | ) { |
| | | return ApiResponse.success(service.page(talentCardId, familyKeyword, talentKeyword, cardLevel, status, applyStart, applyEnd, page, size)); |
| | | return ApiResponse.success(service.page(talentCardId, familyKeyword, talentKeyword, cardLevel, status, applyStart, applyEnd, management, page, size)); |
| | | } |
| | | |
| | | @Operation(summary = "查询家属附属卡申请详情") |
| | |
| | | return ApiResponse.success(service.audit(id, request, operatorId)); |
| | | } |
| | | |
| | | @Operation(summary = "解除家属卡绑定", description = "仅正常状态的家属卡可以解除绑定") |
| | | @PatchMapping("/{id}/unbind") |
| | | public ApiResponse<DependentCardApplyAdminResponse> unbind( |
| | | @PathVariable Long id, |
| | | @RequestAttribute(AdminAuthInterceptor.OPERATOR_ID_ATTRIBUTE) Long operatorId |
| | | ) { |
| | | return ApiResponse.success(service.unbind(id, operatorId)); |
| | | } |
| | | |
| | | @Operation(summary = "查询家属附属卡申请状态记录") |
| | | @GetMapping("/{id}/status-logs") |
| | | public ApiResponse<List<DependentCardApplyStatusLogResponse>> statusLogs(@PathVariable Long id) { |
| | | return ApiResponse.success(service.statusLogs(id)); |
| | | } |
| | | } |
| | | } |
| | |
| | | Integer status, |
| | | LocalDate applyStart, |
| | | LocalDate applyEnd, |
| | | boolean management, |
| | | int page, |
| | | int size |
| | | ) { |
| | | validateStatusFilter(status); |
| | | if (management && status != null |
| | | && status != DependentCardApply.STATUS_APPROVED |
| | | && status != DependentCardApply.STATUS_CANCELLED) { |
| | | throw new BusinessException(ErrorCode.BAD_REQUEST, "家属卡管理状态只能为正常或已解绑"); |
| | | } |
| | | if (applyStart != null && applyEnd != null && applyStart.isAfter(applyEnd)) { |
| | | throw new BusinessException(ErrorCode.BAD_REQUEST, "申请开始时间不能晚于结束时间"); |
| | | } |
| | |
| | | LambdaQueryWrapper<DependentCardApply> query = Wrappers.<DependentCardApply>lambdaQuery() |
| | | .eq(talentCardId != null, DependentCardApply::getTalentCardId, talentCardId) |
| | | .eq(status != null, DependentCardApply::getStatus, status) |
| | | .in(management && status == null, DependentCardApply::getStatus, |
| | | DependentCardApply.STATUS_APPROVED, DependentCardApply.STATUS_CANCELLED) |
| | | .eq(cardLevel != null && !cardLevel.isBlank(), DependentCardApply::getCardLevel, trimToNull(cardLevel)) |
| | | .and(familyKeyword != null && !familyKeyword.isBlank(), wrapper -> wrapper |
| | | .like(DependentCardApply::getDependentName, familyKeyword.trim()) |
| | |
| | | return DependentCardApplyAdminResponse.from(updatedApply, applicationExtra(updatedApply)); |
| | | } |
| | | |
| | | @Transactional |
| | | public DependentCardApplyAdminResponse unbind(Long id, Long operatorId) { |
| | | DependentCardApply apply = mapper.selectByIdForUpdate(id); |
| | | if (apply == null) { |
| | | throw new BusinessException(ErrorCode.NOT_FOUND, "家属卡不存在"); |
| | | } |
| | | if (!Integer.valueOf(DependentCardApply.STATUS_APPROVED).equals(apply.getStatus())) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "仅正常状态的家属卡可以解除绑定"); |
| | | } |
| | | int updated = mapper.update( |
| | | null, |
| | | Wrappers.<DependentCardApply>lambdaUpdate() |
| | | .eq(DependentCardApply::getId, id) |
| | | .eq(DependentCardApply::getStatus, DependentCardApply.STATUS_APPROVED) |
| | | .set(DependentCardApply::getStatus, DependentCardApply.STATUS_CANCELLED) |
| | | ); |
| | | if (updated != 1) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "家属卡状态已变化,请刷新后重试"); |
| | | } |
| | | if (statusLogMapper.insert(new DependentCardApplyStatusLog( |
| | | apply.getId(), |
| | | apply.getApplyNo(), |
| | | DependentCardApply.STATUS_APPROVED, |
| | | DependentCardApply.STATUS_CANCELLED, |
| | | "ADMIN", |
| | | operatorId, |
| | | "管理后台解除绑定" |
| | | )) != 1) { |
| | | throw new BusinessException(ErrorCode.INTERNAL_ERROR, "解绑状态记录保存失败"); |
| | | } |
| | | DependentCardApply updatedApply = mapper.selectById(id); |
| | | return DependentCardApplyAdminResponse.from(updatedApply, applicationExtra(updatedApply)); |
| | | } |
| | | |
| | | private Map<String, Object> applicationExtra(DependentCardApply apply) { |
| | | if (apply == null || apply.getTalentCardId() == null) { |
| | | return Map.of(); |
| New file |
| | |
| | | package com.talentcard.server.service; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | import static org.assertj.core.api.Assertions.assertThatThrownBy; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.ArgumentMatchers.anyString; |
| | | import static org.mockito.ArgumentMatchers.eq; |
| | | import static org.mockito.Mockito.verify; |
| | | import static org.mockito.Mockito.when; |
| | | |
| | | import java.util.List; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.baomidou.mybatisplus.core.MybatisConfiguration; |
| | | import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; |
| | | import com.talentcard.server.common.BusinessException; |
| | | import com.talentcard.server.entity.DependentCardApply; |
| | | import com.talentcard.server.entity.DependentCardApplyStatusLog; |
| | | import com.talentcard.server.mapper.DependentCardApplyMapper; |
| | | import com.talentcard.server.mapper.DependentCardApplyStatusLogMapper; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.junit.jupiter.api.extension.ExtendWith; |
| | | import org.mockito.ArgumentCaptor; |
| | | import org.mockito.Mock; |
| | | import org.mockito.junit.jupiter.MockitoExtension; |
| | | import org.apache.ibatis.builder.MapperBuilderAssistant; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | |
| | | @ExtendWith(MockitoExtension.class) |
| | | class DependentCardApplyAdminServiceTests { |
| | | |
| | | @Mock |
| | | private DependentCardApplyMapper mapper; |
| | | @Mock |
| | | private DependentCardApplyStatusLogMapper statusLogMapper; |
| | | @Mock |
| | | private JdbcTemplate jdbcTemplate; |
| | | |
| | | private DependentCardApplyAdminService service; |
| | | |
| | | @BeforeEach |
| | | void setUp() { |
| | | TableInfoHelper.initTableInfo( |
| | | new MapperBuilderAssistant(new MybatisConfiguration(), "dependent-card-admin-test"), |
| | | DependentCardApply.class |
| | | ); |
| | | service = new DependentCardApplyAdminService(mapper, statusLogMapper, jdbcTemplate); |
| | | } |
| | | |
| | | @Test |
| | | void unbindChangesApprovedCardToCancelledAndRecordsAdminOperator() { |
| | | DependentCardApply approved = applicationWithStatus(DependentCardApply.STATUS_APPROVED); |
| | | DependentCardApply cancelled = applicationWithStatus(DependentCardApply.STATUS_CANCELLED); |
| | | when(mapper.selectByIdForUpdate(77L)).thenReturn(approved); |
| | | when(mapper.update(any(), any(Wrapper.class))).thenReturn(1); |
| | | when(statusLogMapper.insert(any(DependentCardApplyStatusLog.class))).thenReturn(1); |
| | | when(mapper.selectById(77L)).thenReturn(cancelled); |
| | | when(jdbcTemplate.queryForList(anyString(), eq(77L))).thenReturn(List.of()); |
| | | |
| | | var result = service.unbind(77L, 9L); |
| | | |
| | | assertThat(result.status()).isEqualTo(DependentCardApply.STATUS_CANCELLED); |
| | | ArgumentCaptor<DependentCardApplyStatusLog> logCaptor = ArgumentCaptor.forClass(DependentCardApplyStatusLog.class); |
| | | verify(statusLogMapper).insert(logCaptor.capture()); |
| | | DependentCardApplyStatusLog log = logCaptor.getValue(); |
| | | assertThat(log.getFromStatus()).isEqualTo(DependentCardApply.STATUS_APPROVED); |
| | | assertThat(log.getToStatus()).isEqualTo(DependentCardApply.STATUS_CANCELLED); |
| | | assertThat(log.getOperatorType()).isEqualTo("ADMIN"); |
| | | assertThat(log.getOperatorId()).isEqualTo(9L); |
| | | } |
| | | |
| | | @Test |
| | | void unbindRejectsCardThatIsNotApproved() { |
| | | when(mapper.selectByIdForUpdate(77L)).thenReturn(applicationWithStatus(DependentCardApply.STATUS_REJECTED)); |
| | | |
| | | assertThatThrownBy(() -> service.unbind(77L, 9L)) |
| | | .isInstanceOf(BusinessException.class) |
| | | .hasMessageContaining("仅正常状态"); |
| | | } |
| | | |
| | | @Test |
| | | void managementPageRejectsApplicationOnlyStatus() { |
| | | assertThatThrownBy(() -> service.page(null, null, null, null, 0, null, null, true, 1, 10)) |
| | | .isInstanceOf(BusinessException.class) |
| | | .hasMessageContaining("正常或已解绑"); |
| | | } |
| | | |
| | | private DependentCardApply applicationWithStatus(int status) { |
| | | DependentCardApply apply = new DependentCardApply( |
| | | "DCA-001", 1L, 2L, "持卡人", "13900000000", "TC-001", "卓越人才卡", |
| | | "家属", "13800000000", "510105199001011234", "配偶" |
| | | ); |
| | | setField(apply, "id", 77L); |
| | | setField(apply, "status", status); |
| | | return apply; |
| | | } |
| | | |
| | | private void setField(DependentCardApply apply, String name, Object value) { |
| | | try { |
| | | var field = DependentCardApply.class.getDeclaredField(name); |
| | | field.setAccessible(true); |
| | | field.set(apply, value); |
| | | } catch (ReflectiveOperationException exception) { |
| | | throw new AssertionError(exception); |
| | | } |
| | | } |
| | | } |