feat(stock): 增加库存列表筛选和排序功能

- 为过滤参数添加操作符选择(等于、模糊匹配、大于、小于)
- 实现多条件筛选功能
- 添加每页显示条数选择
- 优化排序逻辑,固定 ID 列为第二排序条件
- 修复分页显示逻辑,适应每页显示全部的场景
- 优化 SQL 查询语句生成逻辑
This commit is contained in:
user 2025-03-19 16:15:39 +08:00
parent 1abc943e01
commit ac2f1292f0
6 changed files with 62 additions and 16 deletions

View File

@ -101,7 +101,7 @@ public abstract class BaseRepository {
public Flux<Map<String, Object>> getRows(String organization, String table, Map<String, Object> params, Pageable pageable) {
params = preprocessParams(params);
String orderBy = pageable.getSort().isEmpty()
? "1"
? ""
: pageable.getSort().stream().map(order -> order.getProperty() + " " + order.getDirection()).collect(Collectors.joining(", "));
long page = pageable.getPageNumber();
long size = pageable.getPageSize();
@ -157,7 +157,8 @@ public abstract class BaseRepository {
sql.append(fields.isEmpty() ? " * " : fields.toString());
sql.append(String.format(" FROM %s ", table));
sql.append(wheres.toString());
sql.append(String.format(" ORDER BY %s", orderBy));
// 使用与RegionRepository和DictRepository一致的排序处理方式
if (!orderBy.isEmpty()) sql.append(" ORDER BY ").append(orderBy);
if (size > 0) sql.append(String.format(" LIMIT %d OFFSET %d", size, page * size));
DatabaseClient.GenericExecuteSpec executeSpec = db.sql(sql.toString()).bind("organization", organization);

View File

@ -37,9 +37,9 @@ export default defineComponent({
// 过滤参数
const filterParams = ref({
number: null,
name: null,
property: null,
number: { op: '=', value: null },
name: { op: '=', value: null },
property: { op: '=', value: null },
});
const handleFilter = () => {
@ -50,6 +50,9 @@ export default defineComponent({
const sort = () => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
@ -57,9 +60,10 @@ export default defineComponent({
isFetching.value = true;
try {
const processedParams = showFilter.value
? Object.entries(filterParams.value).reduce((acc, [key, value]) => {
// 将空字符串转换为null确保查询条件不生效
acc[key] = value === '' ? null : value;
? Object.entries(filterParams.value).reduce((acc, [key, { op, value }]) => {
if (value !== null && value !== '') {
acc[key] = { op, value };
}
return acc;
}, {})
: {};
@ -110,6 +114,11 @@ export default defineComponent({
handleSyncList();
};
const handlePageSizeChange = () => {
page.value = 1; // 重置页码
handleSyncList();
};
handleSyncList();
return {
@ -126,6 +135,7 @@ export default defineComponent({
handleSyncList,
handleFilter,
handlePageChange,
handlePageSizeChange,
prepareDelete,
deleteStock,
changeOrder,

View File

@ -28,15 +28,39 @@
<div class="form-section">
<div class="form-group">
<label class="form-control-label" for="filter-number">{{ $t('jewpmsApp.stock.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.stock.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-property">{{ $t('jewpmsApp.stock.property') }}</label>
<input type="text" class="form-control" id="filter-property" v-model="filterParams.property" />
<div class="d-flex">
<select class="form-control w-auto mr-2" v-model="filterParams.property.op">
<option value="=">=</option>
<option value="like">like</option>
<option value=">">></option>
<option value="<"><</option>
</select>
<input type="text" class="form-control" id="filter-property" v-model="filterParams.property.value" />
</div>
</div>
</div>
</div>
@ -98,18 +122,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"

View File

@ -35,7 +35,7 @@ export const useDateFormat = ({ entityRef }: { entityRef?: Ref<Record<string, an
: {};
const i18n = useI18n();
const formatDateI18N = (date, format = 'short') => (date ? i18n.d(Date.parse(date), format) : null);
const formatDateI18N = (date, format = 'short') => (date ? i18n.d(dayjs(date).toDate(), format) : null);
const i18nUtils = {
formatDateI18N,
formatDateLong: date => formatDateI18N(date, 'long'),

View File

@ -118,10 +118,11 @@
"ribbon": {
"dev": "开发环境"
},
"item-count": "显示第 { first } - { second } 条,共 { total } 条"
"item-count": "显示第 { first } - { second } 行,共 { total } 行"
},
"entity": {
"action": {
"all": "全部",
"actions": "操作",
"addblob": "增加 BLOB",
"addimage": "增加图片",
@ -150,6 +151,7 @@
"upload": "上传",
"view": "查看",
"tree": "树形",
"perpage": "每页{ itemsPerPage }行",
"page": "分页",
"show": "显示 { otherEntity }",
"select": "(选择)",

View File

@ -44,6 +44,7 @@ const config = defineConfig({
'@': fileURLToPath(new URL('./src/main/webapp/app/', import.meta.url)),
'@content': fileURLToPath(new URL('./src/main/webapp/content/', import.meta.url)),
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
define: {
I18N_HASH: '"generated_hash"',