add field order

This commit is contained in:
ccmjga
2025-05-18 16:55:50 +08:00
parent 0226e329d4
commit 94a69d999b
11 changed files with 143 additions and 34 deletions

View File

@@ -1,8 +1,10 @@
package com.zl.mjga.dto;
import static com.zl.mjga.utils.StringCaseUtils.convertCamelCaseToSnake;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.name;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -17,11 +19,12 @@ public class PageRequestDto {
public static final String REGEX = "^[a-zA-Z][a-zA-Z0-9_]*$";
public static final String SPACE = " ";
public static final String COLON = ":";
private long page;
private long size;
@Schema(description = "排序字段", example = "name:asc,age:desc", type = "string")
private Map<String, Direction> sortBy = new HashMap<>();
public PageRequestDto(int page, int size) {
@@ -68,10 +71,12 @@ public class PageRequestDto {
}
public List<SortField<Object>> getSortFields() {
List<SortField<Object>> sortFields = sortBy.entrySet().stream()
List<SortField<Object>> sortFields =
sortBy.entrySet().stream()
.map(
(entry) ->
field(name(entry.getKey())).sort(SortOrder.valueOf(entry.getValue().getKeyword())))
(entry) ->
field(name(convertCamelCaseToSnake(entry.getKey())))
.sort(SortOrder.valueOf(entry.getValue().getKeyword())))
.toList();
if (sortFields.isEmpty()) {
return List.of(field(name("id")).sort(SortOrder.ASC));
@@ -108,7 +113,7 @@ public class PageRequestDto {
return result;
}
for (String fieldSpaceDirection : sortBy.split(",")) {
String[] fieldDirectionArray = fieldSpaceDirection.split(SPACE);
String[] fieldDirectionArray = fieldSpaceDirection.split(COLON);
if (fieldDirectionArray.length != 2) {
throw new IllegalArgumentException(
String.format(

View File

@@ -11,8 +11,7 @@ import lombok.NoArgsConstructor;
@Data
public class UserUpsertDto {
private Long id;
@NotEmpty
private String username;
@NotEmpty private String username;
private String password;
@NotNull private Boolean enable;
}

View File

@@ -3,7 +3,6 @@ package com.zl.mjga.repository;
import static org.jooq.generated.mjga.tables.Permission.PERMISSION;
import static org.jooq.generated.mjga.tables.Role.ROLE;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.DSL.noField;
import com.zl.mjga.dto.PageRequestDto;
import com.zl.mjga.dto.urp.PermissionQueryDto;

View File

@@ -2,7 +2,6 @@ package com.zl.mjga.repository;
import static org.jooq.generated.mjga.Tables.*;
import static org.jooq.impl.DSL.noCondition;
import static org.jooq.impl.DSL.noField;
import com.zl.mjga.dto.PageRequestDto;
import com.zl.mjga.dto.position.PositionQueryDto;

View File

@@ -0,0 +1,15 @@
package com.zl.mjga.utils;
public class StringCaseUtils {
public static String convertCamelCaseToSnake(String input) {
StringBuilder result = new StringBuilder();
for (char c : input.toCharArray()) {
if (Character.isUpperCase(c)) {
result.append("_").append(Character.toLowerCase(c));
} else {
result.append(c);
}
}
return result.toString();
}
}

View File

@@ -1219,14 +1219,9 @@
"format": "int64"
},
"sortBy": {
"type": "object",
"additionalProperties": {
"type": "string",
"enum": [
"ASC",
"DESC"
]
}
"type": "string",
"description": "排序字段",
"example": "name:asc,age:desc"
},
"offset": {
"type": "integer",

View File

@@ -544,9 +544,11 @@ export interface components {
page?: number;
/** Format: int64 */
size?: number;
sortBy?: {
[key: string]: "ASC" | "DESC";
};
/**
* @description 排序字段
* @example name:asc,age:desc
*/
sortBy?: string;
/** Format: int64 */
offset?: number;
sortFields?: components["schemas"]["SortFieldObject"][];

View File

@@ -0,0 +1,18 @@
<template>
<span class="ml-1">
<svg class="w-3.5 h-3.5" :class="{'text-blue-700': sortField?.order}" fill="currentColor" viewBox="0 0 24 24">
<path v-if="sortField?.order === 'asc'" d="M8 12l6-6 6 6"/>
<path v-else-if="sortField?.order === 'desc'" d="M8 12l6 6 6-6"/>
<path v-else d="M8 9l6-6 6 6M8 15l6 6 6-6"/>
</svg>
</span>
</template>
<script setup lang="ts">
defineProps<{
sortField?: {
field: string;
order: "asc" | "desc" | undefined;
};
}>();
</script>

View File

@@ -0,0 +1,42 @@
import { computed, ref } from "vue";
export const useSort = () => {
const sortFields = ref<
{
field: string;
order: "asc" | "desc" | undefined;
}[]
>([]);
const getSortField = (field: string) => {
return sortFields.value.find((item) => item.field === field);
};
const sortBy = computed(() => {
return sortFields.value
.map((item) => `${item.field}:${item.order}`)
.join(",");
});
const handleSort = async (field: string) => {
if (sortFields.value?.find((item) => item.field === field)) {
sortFields.value = sortFields.value?.map((item) =>
item.field === field
? { ...item, order: item.order === "asc" ? "desc" : undefined }
: item,
);
} else {
sortFields.value.push({ field, order: "asc" });
}
sortFields.value = sortFields.value?.filter(
(item) => item.order !== undefined,
);
};
return {
sortFields,
sortBy,
handleSort,
getSortField,
};
};

View File

@@ -24,6 +24,7 @@ export const useUserQuery = () => {
},
page = 1,
size = 10,
sortBy = "id:desc",
) => {
const { data } = await client.GET("/iam/users", {
params: {
@@ -31,6 +32,7 @@ export const useUserQuery = () => {
pageRequestDto: {
page,
size,
sortBy,
},
userQueryDto: param,
},

View File

@@ -25,7 +25,7 @@
</form>
<!-- Create Modal toggle -->
<button @click="handleUpsertUserClick(undefined)"
class="flex items-center block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center absolute right-5 bottom-2"
class="flex items-center text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center absolute right-5 bottom-2"
type="button">
新增用户
</button>
@@ -42,7 +42,12 @@
</div>
</th>
<th scope="col" class="px-6 py-3">用户名</th>
<th scope="col" class="px-6 py-3">创建时间</th>
<th scope="col" class="px-6 py-3 cursor-pointer" @click="handleSortClick('createTime')">
<div class="flex items-center">
<span>创建时间</span>
<SortIcon :sortField="getSortField('createTime')" />
</div>
</th>
<th scope="col" class="px-6 py-3">状态</th>
<th scope="col" class="px-6 py-3">分配</th>
<th scope="col" class="px-6 py-3">操作</th>
@@ -147,18 +152,18 @@ import { useRouter } from "vue-router";
import type { components } from "../api/types/schema";
import useAlertStore from "../composables/store/useAlertStore";
import { useUserUpsert } from "../composables/user/useUserUpsert";
import { useSort } from "@/composables/sort";
import SortIcon from "@/components/SortIcon.vue";
const username = ref<string>("");
const selectedUser = ref<components["schemas"]["UserRolePermissionDto"]>();
const userUpsertModal = ref<ModalInterface>();
const userDeleteModal = ref<ModalInterface>();
const router = useRouter();
const { total, users, fetchUsersWith } = useUserQuery();
const { deleteUser } = useUserDelete();
const userUpsert = useUserUpsert();
const { sortFields, sortBy, handleSort, getSortField } = useSort();
const alertStore = useAlertStore();
onMounted(async () => {
@@ -193,9 +198,14 @@ const handleUpsertUserSubmit = async (data: UserUpsertSubmitModel) => {
content: "操作成功",
level: "success",
});
await fetchUsersWith({
username: username.value,
});
await fetchUsersWith(
{
username: username.value,
},
1,
10,
sortBy.value,
);
};
const handleUpsertUserClick = async (
@@ -240,6 +250,18 @@ const handleBindPositionClick = async (
});
};
const handleSortClick = async (field: string) => {
handleSort(field);
await fetchUsersWith(
{
username: username.value,
},
1,
10,
sortBy.value,
);
};
const handleDeleteUserSubmit = async () => {
if (!selectedUser?.value?.id) return;
await deleteUser(selectedUser.value.id);
@@ -248,9 +270,14 @@ const handleDeleteUserSubmit = async () => {
content: "删除成功",
level: "success",
});
await fetchUsersWith({
username: username.value,
});
await fetchUsersWith(
{
username: username.value,
},
1,
10,
sortBy.value,
);
};
const handleDeleteUserClick = async (
@@ -263,9 +290,14 @@ const handleDeleteUserClick = async (
};
const handleSearch = async () => {
await fetchUsersWith({
username: username.value,
});
await fetchUsersWith(
{
username: username.value,
},
1,
10,
sortBy.value,
);
};
const handlePageChange = async (page: number, pageSize: number) => {
@@ -275,6 +307,7 @@ const handlePageChange = async (page: number, pageSize: number) => {
},
page,
pageSize,
sortBy.value,
);
};
</script>