refactor(company): 重构公司列表查询逻辑,支持动态操作符和分页大小调整

重构了公司列表的查询逻辑,支持动态操作符(如=、like、>、<)进行过滤,并增加了分页大小的调整功能。同时,优化了后端查询接口,使其更灵活和高效。
This commit is contained in:
user 2025-03-19 23:22:34 +08:00
parent a1b799674f
commit f9602b1e85
5 changed files with 114 additions and 29 deletions

View File

@ -3,15 +3,19 @@ package com.vxnet.pms.repository;
import com.vxnet.pms.domain.Company;
import java.util.Map;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Repository
public interface CompanyRepository extends R2dbcRepository<Company, Long> {
public interface CompanyRepository extends R2dbcRepository<Company, Long>, CompanyRepositoryInternal {
@Query(
"SELECT * FROM jhi_company WHERE (:#{#organization} = '*' OR organization = :#{#organization}) " +
"AND (:#{#params['number']} IS NULL OR number = :#{#params['number']}) " +
@ -57,3 +61,16 @@ public interface CompanyRepository extends R2dbcRepository<Company, Long> {
@Query("DELETE FROM jhi_company WHERE id = :id")
Mono<Void> deleteByIdWithTableName(@Param("id") Long id);
}
interface CompanyRepositoryInternal {
Mono<Long> countRows(String organization, String table, Map<String, Object> params);
Flux<Map<String, Object>> getRows(String organization, String table, Map<String, Object> params, Pageable pageable);
}
@Component
class CompanyRepositoryInternalImpl extends BaseRepository implements CompanyRepositoryInternal {
public CompanyRepositoryInternalImpl(DatabaseClient db, R2dbcEntityTemplate r2dbcEntityTemplate, R2dbcConverter r2dbcConverter) {
super(db, r2dbcEntityTemplate, r2dbcConverter);
}
}

View File

@ -90,11 +90,15 @@ public class CompanyService {
* @return the list of entities.
*/
@Transactional(readOnly = true)
public Flux<Company> getCompanies(Map<String, Object> params, Pageable pageable) {
log.info("Pageable Sort: " + pageable.getSort().toString().replace(':', ' '));
public Mono<Long> countCompanies(String table, Map<String, Object> params) {
return SecurityUtils.getCurrentOrganization().flatMap(organization -> companyRepository.countRows(organization, table, params));
}
@Transactional(readOnly = true)
public Flux<Map<String, Object>> getCompanies(String table, Map<String, Object> params, Pageable pageable) {
return SecurityUtils.getCurrentOrganization()
.map(organization -> companyRepository.findCompanies(organization, params, pageable))
.flatMapMany(companys -> companys);
.map(organization -> companyRepository.getRows(organization, table, params, pageable))
.flatMapMany(companies -> companies);
}
/**

View File

@ -41,7 +41,7 @@ public class CompanyResource {
"property",
"remark",
"status",
"sortNo",
"sort_no",
"createdBy",
"createdDate",
"updatedBy",
@ -90,14 +90,21 @@ public class CompanyResource {
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of companies in body.
*/
@GetMapping("/companies")
public Mono<ResponseEntity<Flux<Company>>> getCompanies(
public Mono<ResponseEntity<Flux<Map<String, Object>>>> getCompanies(
@RequestParam Map<String, Object> params,
@org.springdoc.core.annotations.ParameterObject Pageable pageable
) {
if (!onlyContainsAllowedProperties(pageable)) {
return Mono.just(ResponseEntity.badRequest().build());
}
return Mono.just(ResponseEntity.ok().body(companyService.getCompanies(params, pageable)));
String table = "jhi_company";
return companyService
.countCompanies(table, params)
.map(total ->
ResponseEntity.ok()
.header("X-Total-Count", String.valueOf(total))
.body(companyService.getCompanies(table, params, pageable))
);
}
/**

View File

@ -32,9 +32,9 @@ export default defineComponent({
// 过滤参数
const filterParams = ref({
number: null,
name: null,
licenseNo: null,
number: { op: '=', value: null },
name: { op: '=', value: null },
licenseNo: { op: '=', value: null },
});
const openDialog = () => {
@ -67,20 +67,22 @@ export default defineComponent({
try {
isFetching.value = true;
const processedParams = showFilter.value
? Object.entries(filterParams.value).reduce((acc, [key, value]) => {
acc[key] = value === '' ? null : value;
? Object.entries(filterParams.value).reduce((acc, [key, { op, value }]) => {
if (value !== null && value !== '') {
acc[key] = { op, value };
}
return acc;
}, {})
: {};
const companyRes = await axios.get('api/companies', {
params: {
const companyRes = await axios.get(
`api/companies?${buildPaginationQuery({
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
...processedParams,
},
});
})}`,
);
companies.value = companyRes.data;
totalItems.value = companyRes.headers['x-total-count'] || companyRes.data.length;
} catch (err) {
@ -123,6 +125,11 @@ export default defineComponent({
loadAll();
};
const handlePageSizeChange = () => {
page.value = 1; // 重置页码
loadAll();
};
const changeOrder = (prop: string): void => {
propOrder.value = prop;
reverse.value = !reverse.value;

View File

@ -28,15 +28,39 @@
<div class="form-section">
<div class="form-group">
<label class="form-control-label" for="filter-number">{{ $t('jewpmsApp.company.number') }}</label>
<input type="text" class="form-control" id="filter-number" v-model="filterParams.number" />
<div class="d-flex">
<select class="form-control w-auto mr-2" v-model="filterParams.number.op">
<option value="=">=</option>
<option value="like">like</option>
<option value=">">></option>
<option value="<"><</option>
</select>
<input type="text" class="form-control" id="filter-number" v-model="filterParams.number.value" />
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="filter-name">{{ $t('jewpmsApp.company.name') }}</label>
<input type="text" class="form-control" id="filter-name" v-model="filterParams.name" />
<div class="d-flex">
<select class="form-control w-auto mr-2" v-model="filterParams.name.op">
<option value="=">=</option>
<option value="like">like</option>
<option value=">">></option>
<option value="<"><</option>
</select>
<input type="text" class="form-control" id="filter-name" v-model="filterParams.name.value" />
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="filter-licenseNo">{{ $t('jewpmsApp.company.licenseNo') }}</label>
<input type="text" class="form-control" id="filter-licenseNo" v-model="filterParams.licenseNo" />
<div class="d-flex">
<select class="form-control w-auto mr-2" v-model="filterParams.licenseNo.op">
<option value="=">=</option>
<option value="like">like</option>
<option value=">">></option>
<option value="<"><</option>
</select>
<input type="text" class="form-control" id="filter-licenseNo" v-model="filterParams.licenseNo.value" />
</div>
</div>
</div>
</div>
@ -49,12 +73,30 @@
<table class="table table-striped" aria-describedby="companies">
<thead>
<tr>
<th scope="row"><span v-text="$t('global.field.id')"></span></th>
<th scope="row"><span v-text="$t('jewpmsApp.company.number')"></span></th>
<th scope="row"><span v-text="$t('jewpmsApp.company.name')"></span></th>
<th scope="row"><span v-text="$t('jewpmsApp.company.address')"></span></th>
<th scope="row"><span v-text="$t('jewpmsApp.company.licenseNo')"></span></th>
<th scope="row"><span v-text="$t('jewpmsApp.company.licenseExpire')"></span></th>
<th scope="row" @click="changeOrder('id')">
<span v-text="$t('global.field.id')"></span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
</th>
<th scope="row" @click="changeOrder('number')">
<span v-text="$t('jewpmsApp.company.number')"></span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'number'"></jhi-sort-indicator>
</th>
<th scope="row" @click="changeOrder('name')">
<span v-text="$t('jewpmsApp.company.name')"></span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'name'"></jhi-sort-indicator>
</th>
<th scope="row" @click="changeOrder('address')">
<span v-text="$t('jewpmsApp.company.address')"></span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'address'"></jhi-sort-indicator>
</th>
<th scope="row" @click="changeOrder('licenseNo')">
<span v-text="$t('jewpmsApp.company.licenseNo')"></span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'licenseNo'"></jhi-sort-indicator>
</th>
<th scope="row" @click="changeOrder('licenseExpire')">
<span v-text="$t('jewpmsApp.company.licenseExpire')"></span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'licenseExpire'"></jhi-sort-indicator>
</th>
<th scope="row"></th>
</tr>
</thead>
@ -88,18 +130,26 @@
<!-- 分页组件 -->
<div class="row justify-content-center" v-if="totalItems > 0">
<div class="col-sm-4">
<div class="col-sm-2">
<select class="form-control" v-model="itemsPerPage" @change="handlePageSizeChange">
<option :value="10">{{ $t('entity.action.perpage', { itemsPerPage: 10 }) }}</option>
<option :value="20">{{ $t('entity.action.perpage', { itemsPerPage: 20 }) }}</option>
<option :value="50">{{ $t('entity.action.perpage', { itemsPerPage: 50 }) }}</option>
<option :value="0">{{ $t('entity.action.all') }}</option>
</select>
</div>
<div class="col-sm-3">
<div class="info jhi-item-count">
{{
$t('global.item-count', {
first: (page - 1) * itemsPerPage + 1,
second: page * itemsPerPage < totalItems ? page * itemsPerPage : totalItems,
second: itemsPerPage > 0 && page * itemsPerPage < totalItems ? page * itemsPerPage : totalItems,
total: totalItems,
})
}}
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-7">
<b-pagination
v-model="page"
:total-rows="totalItems"