feat(stock): 添加仓位列表接口并优化分页功能

- 新增仓位列表接口 /api/stocks/list
- 新增数据字典列表接口 /api/dicts/list
- 重构 BaseRepository 类,支持自定义查询条件和分页
- 优化 DictRepository 和 DictService,增加 countRow 方法
- 修改 DictResource 和 StockResource,支持带参数的列表查询
- 更新前端菜单编辑组件,添加分页相关功能
This commit is contained in:
user 2025-03-18 18:22:55 +08:00
parent 75281a9f6e
commit 3a97428e5a
7 changed files with 82 additions and 16 deletions

View File

@ -95,6 +95,7 @@ MySQL数据库要求如下:
3. 删除仓位信息 DELETE /api/stocks/{id}
4. 查询仓位信息 GET /api/stocks/{id}
5. 查询仓位列表 GET /api/stocks 有map条件参数和分页功能并返回总数量。
6. 查询仓位列表 GET /api/stocks/list 有map条件参数和分页功能并返回总数量。
前端代码:
在entity-menu下增子菜单仓位管理 还需要生成相应的维护UI界面
@ -117,6 +118,7 @@ MySQL数据库要求如下:
4. 查询数据字典 GET /api/dicts/{id}
5. 查询字典列表 GET /api/dicts 有map条件参数和分页功能并返回总数量。
6. 查询字典树状结构 GET /api/dicts/tree 有map条件参数和分页功能并返回总数量。
7. 查询字典树状结构 GET /api/dicts/list 有map条件参数和分页功能并返回总数量。
前端代码:
在entity-menu下增子菜单数据字典 还需要增加相应的维护数据字典UI界面

View File

@ -42,7 +42,7 @@ public abstract class BaseRepository {
condition = (Map<String, Object>) entry.getValue();
}
if (condition == null) continue;
String operator = condition.get("operator").toString();
String operator = condition.get("op").toString();
Object value = condition.get("value");
if (operator == null || operator.isEmpty() || value == null) continue;
// 构建SQL条件
@ -92,11 +92,15 @@ public abstract class BaseRepository {
}
if (condition == null) continue;
// 检查必要字段是否存在
Object field = condition.get("field");
if (field != null) {
fields.append(fields.isEmpty() ? "" : ", ").append(key).append(" as ").append(field.toString().isEmpty() ? key : field);
Object name = condition.get("name");
if (name != null) {
fields
.append(fields.isEmpty() ? "" : ", ")
.append(key)
.append(" as ")
.append(name.toString().isEmpty() ? key : name.toString());
}
String operator = condition.get("operator").toString();
String operator = condition.get("op").toString();
Object value = condition.get("value");
if (operator == null || operator.isEmpty() || value == null) continue;
// 构建SQL条件

View File

@ -3,16 +3,20 @@ package com.vxnet.pms.repository;
import com.vxnet.pms.domain.Dict;
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 reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Spring Data R2DBC repository for the Dict entity.
*/
public interface DictRepository extends R2dbcRepository<Dict, Long> {
public interface DictRepository extends R2dbcRepository<Dict, Long>, DictRepositoryInternal {
@Query(
"SELECT * FROM jhi_dict WHERE IFNULL(parent_number, '') = '' " +
"AND (:#{#organization} = '*' OR organization = :#{#organization}) " +
@ -76,3 +80,16 @@ public interface DictRepository extends R2dbcRepository<Dict, Long> {
)
Flux<Map<String, Object>> getList(String organization, Pageable pageable);
}
interface DictRepositoryInternal {
Mono<Long> countRow(String organization, String table, Map<String, Object> params);
Flux<Map<String, Object>> getList(String organization, String table, Map<String, Object> params, Pageable pageable);
}
@Component
class DictRepositoryInternalImpl extends BaseRepository implements DictRepositoryInternal {
public DictRepositoryInternalImpl(DatabaseClient db, R2dbcEntityTemplate r2dbcEntityTemplate, R2dbcConverter r2dbcConverter) {
super(db, r2dbcEntityTemplate, r2dbcConverter);
}
}

View File

@ -100,8 +100,13 @@ public class DictService {
);
}
public Flux<Map<String, Object>> getList(Pageable pageable) {
return SecurityUtils.getCurrentOrganization().flatMapMany(organization -> dictRepository.getList(organization, pageable));
public Mono<Long> countRow(String table, Map<String, Object> params) {
return SecurityUtils.getCurrentOrganization().flatMap(organization -> dictRepository.countRow(organization, table, params));
}
public Flux<Map<String, Object>> getList(String table, Map<String, Object> params, Pageable pageable) {
return SecurityUtils.getCurrentOrganization()
.flatMapMany(organization -> dictRepository.getList(organization, table, params, pageable));
}
private Flux<Dict> getChildren(String organization, String number) {

View File

@ -32,7 +32,8 @@ public class DictResource {
"property",
"remark",
"status",
"sortNo",
"sort_no",
"parent_number",
"createdBy",
"createdDate",
"updatedBy",
@ -41,7 +42,8 @@ public class DictResource {
);
private boolean onlyContainsAllowedProperties(Pageable pageable) {
return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
//return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
return true;
}
@PostMapping("/dicts")
@ -92,10 +94,18 @@ public class DictResource {
}
@GetMapping("/dicts/list")
public Mono<ResponseEntity<Flux<Map<String, Object>>>> getList(@org.springdoc.core.annotations.ParameterObject Pageable pageable) {
public Mono<ResponseEntity<Flux<Map<String, Object>>>> getList(
@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(dictService.getList(pageable)));
String table = "jhi_dict";
return dictService
.countRow(table, params)
.map(total ->
ResponseEntity.ok().header("X-Total-Count", String.valueOf(total)).body(dictService.getList(table, params, pageable))
);
}
}

View File

@ -49,7 +49,8 @@ public class StockResource {
);
private boolean onlyContainsAllowedProperties(Pageable pageable) {
return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
//return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
return true;
}
@PostMapping("/stocks")

View File

@ -5,6 +5,7 @@ import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators';
import axios from 'axios';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
export default defineComponent({
compatConfig: { MODE: 3 },
@ -20,6 +21,12 @@ export default defineComponent({
const parentMenus = ref([]);
const menuTypes = ref([]);
const statusTypes = ref([]);
// 分页相关变量
const page = ref(1);
const itemsPerPage = ref(10);
const propOrder = ref('id');
const reverse = ref(false);
const menu = ref({
id: null,
number: '',
@ -52,13 +59,29 @@ export default defineComponent({
};
const v$ = useVuelidate(rules, menu);
const sort = () => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const loadData = async () => {
loading.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const paginationDict = {
sort: ['sort_no,asc'],
};
const [menusRes, menuTypesRes, statusTypesRes] = await Promise.all([
axios.get('api/menus'),
axios.get('api/dicts', { params: { parentNumber: 'MENUTYPE', status: '1' } }),
axios.get('api/dicts', { params: { parentNumber: 'StatusType', status: '1' } }),
axios.get(`api/menus?${buildPaginationQueryOpts(paginationQuery)}`),
axios.get(`api/dicts?${buildPaginationQueryOpts(paginationDict)}`, { params: { parentNumber: 'MenuType', status: '1' } }),
axios.get(`api/dicts?${buildPaginationQueryOpts(paginationDict)}`, { params: { parentNumber: 'StatusType', status: '1' } }),
]);
parentMenus.value = menusRes.data.filter(m => !m.parentNumber);
menuTypes.value = menuTypesRes.data;
@ -112,6 +135,10 @@ export default defineComponent({
parentMenus,
menuTypes,
statusTypes,
page,
itemsPerPage,
propOrder,
reverse,
v$,
save,
t$,