fix dayjs

This commit is contained in:
Chuck1sn
2025-05-19 11:01:18 +08:00
parent 225c7fb350
commit dd3c92172e
11 changed files with 59 additions and 38 deletions

View File

@@ -23,7 +23,6 @@ public class UserRolePermissionDto {
private Boolean enable; private Boolean enable;
@Builder.Default private List<RoleDto> roles = new LinkedList<>(); @Builder.Default private List<RoleDto> roles = new LinkedList<>();
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private OffsetDateTime createTime; private OffsetDateTime createTime;
public Set<PermissionRespDto> getPermissions() { public Set<PermissionRespDto> getPermissions() {

View File

@@ -58,21 +58,21 @@ public class JacksonAnnotationMvcTest {
.andExpect(jsonPath("$.data[0].password").doesNotExist()); .andExpect(jsonPath("$.data[0].password").doesNotExist());
} }
@Test // @Test
@WithMockUser // @WithMockUser
void dateFieldWithFormatAnnotation_whenResponseIncludeField_fieldShouldBeExpectDataFormat() // void dateFieldWithFormatAnnotation_whenResponseIncludeField_fieldShouldBeExpectDataFormat()
throws Exception { // throws Exception {
OffsetDateTime stubCreateDateTime = // OffsetDateTime stubCreateDateTime =
OffsetDateTime.of(2023, 12, 2, 1, 1, 1, 0, OffsetDateTime.now().getOffset()); // OffsetDateTime.of(2023, 12, 2, 1, 1, 1, 0, OffsetDateTime.now().getOffset());
UserRolePermissionDto stubUserRolePermissionDto = new UserRolePermissionDto(); // UserRolePermissionDto stubUserRolePermissionDto = new UserRolePermissionDto();
stubUserRolePermissionDto.setCreateTime(stubCreateDateTime); // stubUserRolePermissionDto.setCreateTime(stubCreateDateTime);
when(identityAccessService.pageQueryUser(any(PageRequestDto.class), any(UserQueryDto.class))) // when(identityAccessService.pageQueryUser(any(PageRequestDto.class), any(UserQueryDto.class)))
.thenReturn(new PageResponseDto<>(1, List.of(stubUserRolePermissionDto))); // .thenReturn(new PageResponseDto<>(1, List.of(stubUserRolePermissionDto)));
mockMvc // mockMvc
.perform( // .perform(
get(String.format("/iam/users?page=1&size=5&username=%s", "7bF3mcNVTj6P6v2")) // get(String.format("/iam/users?page=1&size=5&username=%s", "7bF3mcNVTj6P6v2"))
.contentType(MediaType.APPLICATION_FORM_URLENCODED)) // .contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(jsonPath("$.data[0].createTime").value("2023-12-02 01:01:01")); // .andExpect(jsonPath("$.data[0].createTime").value("2023-12-02 01:01:01"));
} // }
} }

View File

@@ -11,6 +11,7 @@
"@tailwindcss/vite": "^4.0.14", "@tailwindcss/vite": "^4.0.14",
"@vueuse/core": "^13.0.0", "@vueuse/core": "^13.0.0",
"apexcharts": "^3.46.0", "apexcharts": "^3.46.0",
"dayjs": "^1.11.13",
"flowbite": "^3.1.2", "flowbite": "^3.1.2",
"openapi-fetch": "^0.13.5", "openapi-fetch": "^0.13.5",
"pinia": "^3.0.1", "pinia": "^3.0.1",
@@ -3200,6 +3201,12 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "http://mirrors.tencent.com/npm/dayjs/-/dayjs-1.11.13.tgz",
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
"license": "MIT"
},
"node_modules/de-indent": { "node_modules/de-indent": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",

View File

@@ -21,6 +21,7 @@
"@tailwindcss/vite": "^4.0.14", "@tailwindcss/vite": "^4.0.14",
"@vueuse/core": "^13.0.0", "@vueuse/core": "^13.0.0",
"apexcharts": "^3.46.0", "apexcharts": "^3.46.0",
"dayjs": "^1.11.13",
"flowbite": "^3.1.2", "flowbite": "^3.1.2",
"openapi-fetch": "^0.13.5", "openapi-fetch": "^0.13.5",
"pinia": "^3.0.1", "pinia": "^3.0.1",
@@ -50,6 +51,8 @@
"vue-tsc": "^2.2.8" "vue-tsc": "^2.2.8"
}, },
"msw": { "msw": {
"workerDirectory": ["public"] "workerDirectory": [
"public"
]
} }
} }

View File

@@ -0,0 +1,11 @@
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import timezone from "dayjs/plugin/timezone";
import "dayjs/locale/zh-cn";
dayjs.extend(localizedFormat);
dayjs.locale("zh-cn");
dayjs.extend(timezone);
dayjs.tz.setDefault("Asia/Shanghai");
export default dayjs;

View File

@@ -5,7 +5,7 @@
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">部门管理</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">部门管理</h1>
</div> </div>
<div class="relative"> <div class="relative">
<form class="max-w-sm mb-4"> <form class="max-w-xs mb-4">
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label> <label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none"> <div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">

View File

@@ -5,7 +5,7 @@
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">权限管理</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">权限管理</h1>
</div> </div>
<div class="relative"> <div class="relative">
<form class="max-w-sm mb-4"> <form class="max-w-xs mb-4">
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label> <label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none"> <div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">

View File

@@ -5,7 +5,7 @@
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">岗位管理</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">岗位管理</h1>
</div> </div>
<div class="relative"> <div class="relative">
<form class="max-w-sm mb-4 "> <form class="max-w-xs mb-4 ">
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label> <label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none"> <div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">

View File

@@ -5,7 +5,7 @@
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">角色管理</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">角色管理</h1>
</div> </div>
<div class="relative"> <div class="relative">
<form class="max-w-sm mb-4"> <form class="max-w-xs mb-4">
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label> <label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none"> <div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">

View File

@@ -5,7 +5,7 @@
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">任务管理</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">任务管理</h1>
</div> </div>
<div class="relative"> <div class="relative">
<form class="max-w-sm mb-4 "> <form class="max-w-xs mb-4 ">
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label> <label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none"> <div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
@@ -59,22 +59,21 @@
<label :for="'checkbox-table-search-' + job.triggerName" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + job.triggerName" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap ">{{ <td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis font-medium text-gray-900 whitespace-nowrap ">{{
`${job.name}:${job.group}` }}</td> `${job.name}:${job.group}` }}</td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ <td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{
`${job.triggerName}:${job.triggerGroup}` }} `${job.triggerName}:${job.triggerGroup}` }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ new <td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{
Date(job.startTime!).toLocaleString() }} dayjs(job.startTime!).format("llll") }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ job.endTime ? new <td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ job.endTime ?
Date(job.endTime).toLocaleString() : undefined }}</td> dayjs(job.endTime).format("llll") : undefined }}</td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ job.nextFireTime ? new <td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ job.nextFireTime ?
Date(job.nextFireTime).toLocaleString() : undefined}}</td> dayjs(job.nextFireTime).format("llll") : undefined}}</td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ job.previousFireTime && <td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ job.previousFireTime &&
job.previousFireTime job.previousFireTime
> 0 ? new > 0 ? dayjs(job.previousFireTime).format("llll") :
Date(job.previousFireTime).toLocaleString() :
undefined undefined
}} }}
</td> </td>
@@ -138,6 +137,7 @@ import { useJobControl } from "@/composables/job/useJobControl";
import { useJobsPaginationQuery } from "@/composables/job/useJobQuery"; import { useJobsPaginationQuery } from "@/composables/job/useJobQuery";
import { useJobUpdate } from "@/composables/job/useJobUpdate"; import { useJobUpdate } from "@/composables/job/useJobUpdate";
import useAlertStore from "@/composables/store/useAlertStore"; import useAlertStore from "@/composables/store/useAlertStore";
import dayjs from "@/utils/dateUtil";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, ref } from "vue"; import { nextTick, onMounted, ref } from "vue";
import type { components } from "../api/types/schema"; import type { components } from "../api/types/schema";

View File

@@ -5,7 +5,7 @@
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">用户管理</h1> <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl ">用户管理</h1>
</div> </div>
<div class="relative"> <div class="relative">
<form class="max-w-sm mb-4 "> <form class="max-w-xs mb-4 ">
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label> <label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only ">Search</label>
<div class="relative"> <div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none"> <div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
@@ -72,7 +72,7 @@
{{ user.username }} {{ user.username }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">
{{ user.createTime }} {{ dayjs(user.createTime).format("llll") }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center"> <div class="flex items-center">
@@ -145,20 +145,21 @@
<script setup lang="ts"> <script setup lang="ts">
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import UserDeleteModal from "@/components/PopupModal.vue"; import UserDeleteModal from "@/components/PopupModal.vue";
import SortIcon from "@/components/SortIcon.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";
import UserUpsertModal from "@/components/UserUpsertModal.vue"; import UserUpsertModal from "@/components/UserUpsertModal.vue";
import { useSort } from "@/composables/sort";
import useUserDelete from "@/composables/user/useUserDelete"; import useUserDelete from "@/composables/user/useUserDelete";
import { useUserQuery } from "@/composables/user/useUserQuery"; import { useUserQuery } from "@/composables/user/useUserQuery";
import { RouteName } from "@/router/constants"; import { RouteName } from "@/router/constants";
import type { UserUpsertSubmitModel } from "@/types/user"; import type { UserUpsertSubmitModel } from "@/types/user";
import dayjs from "@/utils/dateUtil";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, ref } from "vue"; import { nextTick, onMounted, ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import type { components } from "../api/types/schema"; import type { components } from "../api/types/schema";
import useAlertStore from "../composables/store/useAlertStore"; import useAlertStore from "../composables/store/useAlertStore";
import { useUserUpsert } from "../composables/user/useUserUpsert"; import { useUserUpsert } from "../composables/user/useUserUpsert";
import { useSort } from "@/composables/sort";
import SortIcon from "@/components/SortIcon.vue";
const username = ref<string>(""); const username = ref<string>("");
const selectedUser = ref<components["schemas"]["UserRolePermissionDto"]>(); const selectedUser = ref<components["schemas"]["UserRolePermissionDto"]>();