mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-03-19 08:53:46 +08:00
fix bugs
This commit is contained in:
@@ -1,11 +1,36 @@
|
||||
<template>
|
||||
<div id="globalAlert" :class="['flex space-x-2 items-center rounded-lg p-4 mb-4 text-sm fixed top-8 right-5 transition-all duration-200 ease-out z-50', alertStore.levelClassName, alertStore.alertStorage.isShow ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-full']" role="alert">
|
||||
<svg v-if="alertStore.alertStorage.level==='info'" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info-icon lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
||||
<svg v-else-if="alertStore.alertStorage.level === 'warning'" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-triangle-alert-icon lucide-triangle-alert"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
|
||||
<svg v-if="alertStore.alertStorage.level === 'success'" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check-icon lucide-circle-check"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
|
||||
<svg v-if="alertStore.alertStorage.level === 'error'" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-x-icon lucide-circle-x"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
|
||||
<span class="font-medium">{{ alertStore.alertStorage.content }}</span>
|
||||
</div>
|
||||
<div id="globalAlert"
|
||||
:class="['flex space-x-2 items-center rounded-lg p-4 mb-4 text-sm fixed top-8 right-5 transition-all duration-200 ease-out z-50', alertStore.levelClassName, alertStore.alertStorage.isShow ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-full']"
|
||||
role="alert">
|
||||
<svg v-if="alertStore.alertStorage.level==='info'" xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-info-icon lucide-info">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M12 16v-4" />
|
||||
<path d="M12 8h.01" />
|
||||
</svg>
|
||||
<svg v-else-if="alertStore.alertStorage.level === 'warning'" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-triangle-alert-icon lucide-triangle-alert">
|
||||
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
|
||||
<path d="M12 9v4" />
|
||||
<path d="M12 17h.01" />
|
||||
</svg>
|
||||
<svg v-if="alertStore.alertStorage.level === 'success'" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-circle-check-icon lucide-circle-check">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>
|
||||
<svg v-if="alertStore.alertStorage.level === 'error'" xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-circle-x-icon lucide-circle-x">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m15 9-6 6" />
|
||||
<path d="m9 9 6 6" />
|
||||
</svg>
|
||||
<span class="font-medium">{{ alertStore.alertStorage.content }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<label for="category" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">上级部门</label>
|
||||
<select id="category" v-model="formData.parentId"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
||||
<option v-for="department in allDepartments" :key="department.id" :value="department.id"
|
||||
<option v-for="department in availableDepartments" :key="department.id" :value="department.id"
|
||||
:selected="department.id === formData.parentId">{{
|
||||
department.name
|
||||
}}</option>
|
||||
@@ -61,26 +61,23 @@ import type { DepartmentUpsertModel } from "../types/department";
|
||||
|
||||
const alertStore = useAlertStore();
|
||||
|
||||
const { department, allDepartments, onSubmit } = defineProps<{
|
||||
const { department, availableDepartments, onSubmit } = defineProps<{
|
||||
department?: components["schemas"]["Department"];
|
||||
allDepartments: components["schemas"]["Department"][];
|
||||
availableDepartments?: components["schemas"]["Department"][];
|
||||
closeModal: () => void;
|
||||
onSubmit: (department: DepartmentUpsertModel) => Promise<void>;
|
||||
}>();
|
||||
|
||||
const formData = ref();
|
||||
|
||||
watch(
|
||||
() => department,
|
||||
(newDepartment) => {
|
||||
formData.value = {
|
||||
id: newDepartment?.id,
|
||||
name: newDepartment?.name,
|
||||
parentId: newDepartment?.parentId,
|
||||
};
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
const updateFormData = (newDepartment: typeof department) => {
|
||||
formData.value = {
|
||||
id: newDepartment?.id,
|
||||
name: newDepartment?.name,
|
||||
parentId: newDepartment?.parentId,
|
||||
};
|
||||
};
|
||||
watch(() => department, updateFormData, { immediate: true });
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const schema = z.object({
|
||||
@@ -90,12 +87,14 @@ const handleSubmit = async () => {
|
||||
.string({
|
||||
message: "部门名称不能为空",
|
||||
})
|
||||
.min(2, "部门名称至少2个字符"),
|
||||
.min(2, "部门名称至少2个字符")
|
||||
.max(15, "部门名称最多15个字符"),
|
||||
});
|
||||
|
||||
try {
|
||||
const validatedData = schema.parse(formData.value);
|
||||
await onSubmit(validatedData);
|
||||
updateFormData(undefined);
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
alertStore.showAlert({
|
||||
|
||||
@@ -60,17 +60,15 @@ const alertStore = useAlertStore();
|
||||
|
||||
const formData = ref();
|
||||
|
||||
watch(
|
||||
() => permission,
|
||||
(newPermission) => {
|
||||
formData.value = {
|
||||
id: newPermission?.id,
|
||||
name: newPermission?.name,
|
||||
code: newPermission?.code,
|
||||
};
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
const updateFormData = (newPermission: typeof permission) => {
|
||||
formData.value = {
|
||||
id: newPermission?.id,
|
||||
name: newPermission?.name,
|
||||
code: newPermission?.code,
|
||||
};
|
||||
};
|
||||
|
||||
watch(() => permission, updateFormData, { immediate: true });
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const permissionSchema = z.object({
|
||||
@@ -79,17 +77,20 @@ const handleSubmit = async () => {
|
||||
.string({
|
||||
message: "权限名称不能为空",
|
||||
})
|
||||
.min(2, "权限名称至少2个字符"),
|
||||
.min(2, "权限名称至少2个字符")
|
||||
.max(15, "权限名称最多15个字符"),
|
||||
code: z
|
||||
.string({
|
||||
message: "权限代码不能为空",
|
||||
})
|
||||
.min(2, "权限代码至少2个字符"),
|
||||
.min(2, "权限代码至少2个字符")
|
||||
.max(15, "权限代码最多15个字符"),
|
||||
});
|
||||
|
||||
try {
|
||||
const validatedData = permissionSchema.parse(formData.value);
|
||||
await onSubmit(validatedData);
|
||||
updateFormData(undefined);
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
alertStore.showAlert({
|
||||
|
||||
@@ -48,7 +48,6 @@ import { onMounted, ref, watch } from "vue";
|
||||
import { z } from "zod";
|
||||
import type { components } from "../api/types/schema";
|
||||
import type { PositionUpsertModel } from "../types/position";
|
||||
import { tr } from "@faker-js/faker";
|
||||
|
||||
const alertStore = useAlertStore();
|
||||
|
||||
@@ -60,17 +59,14 @@ const { id, position, onSubmit } = defineProps<{
|
||||
}>();
|
||||
|
||||
const formData = ref();
|
||||
const updateFormData = (newPosition: typeof position) => {
|
||||
formData.value = {
|
||||
id: newPosition?.id,
|
||||
name: newPosition?.name,
|
||||
};
|
||||
};
|
||||
|
||||
watch(
|
||||
() => position,
|
||||
(newPosition) => {
|
||||
formData.value = {
|
||||
id: newPosition?.id,
|
||||
name: newPosition?.name,
|
||||
};
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
watch(() => position, updateFormData, { immediate: true });
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const schema = z.object({
|
||||
@@ -79,12 +75,14 @@ const handleSubmit = async () => {
|
||||
.string({
|
||||
message: "岗位名称不能为空",
|
||||
})
|
||||
.min(2, "岗位名称至少2个字符"),
|
||||
.min(2, "岗位名称至少2个字符")
|
||||
.max(15, "岗位名称最多15个字符"),
|
||||
});
|
||||
|
||||
try {
|
||||
const validatedData = schema.parse(formData.value);
|
||||
await onSubmit(validatedData);
|
||||
updateFormData(undefined);
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
alertStore.showAlert({
|
||||
|
||||
@@ -60,17 +60,15 @@ const { role, onSubmit } = defineProps<{
|
||||
|
||||
const formData = ref();
|
||||
|
||||
watch(
|
||||
() => role,
|
||||
(newRole) => {
|
||||
formData.value = {
|
||||
id: newRole?.id,
|
||||
name: newRole?.name,
|
||||
code: newRole?.code,
|
||||
};
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
const updateFormData = (newRole: typeof role) => {
|
||||
formData.value = {
|
||||
id: newRole?.id,
|
||||
name: newRole?.name,
|
||||
code: newRole?.code,
|
||||
};
|
||||
};
|
||||
|
||||
watch(() => role, updateFormData, { immediate: true });
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const roleSchema = z.object({
|
||||
@@ -79,17 +77,20 @@ const handleSubmit = async () => {
|
||||
.string({
|
||||
message: "角色名称不能为空",
|
||||
})
|
||||
.min(2, "角色名称至少2个字符"),
|
||||
.min(2, "角色名称至少2个字符")
|
||||
.max(15, "角色名称最多15个字符"),
|
||||
code: z
|
||||
.string({
|
||||
message: "角色代码不能为空",
|
||||
})
|
||||
.min(2, "角色代码至少2个字符"),
|
||||
.min(2, "角色代码至少2个字符")
|
||||
.max(15, "角色代码最多15个字符"),
|
||||
});
|
||||
|
||||
try {
|
||||
const validatedData = roleSchema.parse(formData.value);
|
||||
await onSubmit(validatedData);
|
||||
updateFormData(undefined);
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
alertStore.showAlert({
|
||||
|
||||
@@ -54,9 +54,9 @@ const formData = ref();
|
||||
watch(
|
||||
() => job,
|
||||
(newJob) => {
|
||||
formData.value = {
|
||||
cronExpression: newJob?.cronExpression,
|
||||
};
|
||||
formData.value = {
|
||||
cronExpression: newJob?.cronExpression,
|
||||
};
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
@@ -4,130 +4,13 @@
|
||||
aria-label="Sidebar">
|
||||
<div class="h-full px-3 pb-4 overflow-y-auto bg-white dark:bg-gray-800">
|
||||
<ul class="space-y-2 font-medium">
|
||||
<!-- <li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.OVERVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide shrink-0 text-gray-600 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white lucide-chart-pie-icon lucide-chart-pie">
|
||||
<path
|
||||
d="M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z" />
|
||||
<path d="M21.21 15.89A10 10 0 1 1 8 2.83" />
|
||||
</svg>
|
||||
<span>
|
||||
总览
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li> -->
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.USERVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-users-icon lucide-users shrink-0 text-gray-700 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="9" cy="7" r="4" />
|
||||
<path d="M22 21v-2a4 4 0 0 0-3-3.87" />
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
||||
</svg>
|
||||
<span>
|
||||
用户管理
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.ROLEVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-shield-user-icon lucide-shield-user shrink-0 text-gray-700 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white">
|
||||
<path
|
||||
d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" />
|
||||
<path d="M6.376 18.91a6 6 0 0 1 11.249.003" />
|
||||
<circle cx="12" cy="11" r="4" />
|
||||
</svg>
|
||||
<span>
|
||||
角色管理
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.PERMISSIONVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-key-round-icon lucide-key-round shrink-0 text-gray-700 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white">
|
||||
<path
|
||||
d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z" />
|
||||
<circle cx="16.5" cy="7.5" r=".5" fill="currentColor" />
|
||||
</svg>
|
||||
<span>
|
||||
权限管理
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.DEPARTMENTVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg class=" text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 15v3c0 .5523.44772 1 1 1h4v-4m-5 0v-4m0 4h5m-5-4V6c0-.55228.44772-1 1-1h16c.5523 0 1 .44772 1 1v1.98935M3 11h5v4m9.4708 4.1718-.8696-1.4388-2.8164-.235-2.573-4.2573 1.4873-2.8362 1.4441 2.3893c.3865.6396 1.2183.8447 1.8579.4582.6396-.3866.8447-1.2184.4582-1.858l-1.444-2.38925h3.1353l2.6101 4.27715-1.0713 2.5847.8695 1.4388" />
|
||||
</svg>
|
||||
|
||||
<span>
|
||||
部门管理
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.POSITIONVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M14.6144 7.19994c.3479.48981.5999 1.15357.5999 1.80006 0 1.6569-1.3432 3-3 3-1.6569 0-3.00004-1.3431-3.00004-3 0-.67539.22319-1.29865.59983-1.80006M6.21426 6v4m0-4 6.00004-3 6 3-6 2-2.40021-.80006M6.21426 6l3.59983 1.19994M6.21426 19.8013v-2.1525c0-1.6825 1.27251-3.3075 2.95093-3.6488l3.04911 2.9345 3-2.9441c1.7026.3193 3 1.9596 3 3.6584v2.1525c0 .6312-.5373 1.1429-1.2 1.1429H7.41426c-.66274 0-1.2-.5117-1.2-1.1429Z" />
|
||||
</svg>
|
||||
|
||||
<span>
|
||||
岗位管理
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.SETTINGS}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-user-cog-icon lucide-user-cog shrink-0 text-gray-700 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white">
|
||||
<circle cx="18" cy="15" r="3" />
|
||||
<circle cx="9" cy="7" r="4" />
|
||||
<path d="M10 15H6a4 4 0 0 0-4 4v2" />
|
||||
<path d="m21.7 16.4-.9-.3" />
|
||||
<path d="m15.2 13.9-.9-.3" />
|
||||
<path d="m16.6 18.7.3-.9" />
|
||||
<path d="m19.1 12.2.3-.9" />
|
||||
<path d="m19.6 18.7-.4-1" />
|
||||
<path d="m16.8 12.3-.4-1" />
|
||||
<path d="m14.3 16.6 1-.4" />
|
||||
<path d="m20.7 13.8 1-.4" />
|
||||
</svg>
|
||||
<span>
|
||||
个人中心
|
||||
</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.SCHEDULERVIEW}`"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
<span>
|
||||
定时任务
|
||||
</span>
|
||||
<li v-for="item in menuItems" :key="item.path">
|
||||
<RouterLink :to="item.path"
|
||||
class="flex items-center p-2 gap-x-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group"
|
||||
:class="{ 'bg-gray-100 dark:bg-gray-700': isActive(item.path) }">
|
||||
<component :is="item.icon"
|
||||
class="shrink-0 text-gray-700 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span>{{ item.title }}</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -139,7 +22,62 @@
|
||||
import { RoutePath } from "@/router/constants";
|
||||
import { initFlowbite } from "flowbite";
|
||||
import { onMounted } from "vue";
|
||||
import { RouterLink } from "vue-router";
|
||||
import { RouterLink, useRoute } from "vue-router";
|
||||
|
||||
import DepartmentIcon from "./icons/DepartmentIcon.vue";
|
||||
import PermissionIcon from "./icons/PermissionIcon.vue";
|
||||
import PositionIcon from "./icons/PositionIcon.vue";
|
||||
import RoleIcon from "./icons/RoleIcon.vue";
|
||||
import SchedulerIcon from "./icons/SchedulerIcon.vue";
|
||||
import SettingsIcon from "./icons/SettingsIcon.vue";
|
||||
// 导入图标组件
|
||||
import UsersIcon from "./icons/UsersIcon.vue";
|
||||
|
||||
// 菜单配置
|
||||
const menuItems = [
|
||||
{
|
||||
title: "用户管理",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.USERVIEW}`,
|
||||
icon: UsersIcon,
|
||||
},
|
||||
{
|
||||
title: "角色管理",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.ROLEVIEW}`,
|
||||
icon: RoleIcon,
|
||||
},
|
||||
{
|
||||
title: "权限管理",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.PERMISSIONVIEW}`,
|
||||
icon: PermissionIcon,
|
||||
},
|
||||
{
|
||||
title: "部门管理",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.DEPARTMENTVIEW}`,
|
||||
icon: DepartmentIcon,
|
||||
},
|
||||
{
|
||||
title: "岗位管理",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.POSITIONVIEW}`,
|
||||
icon: PositionIcon,
|
||||
},
|
||||
{
|
||||
title: "个人中心",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.SETTINGS}`,
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
title: "定时任务",
|
||||
path: `${RoutePath.DASHBOARD}/${RoutePath.SCHEDULERVIEW}`,
|
||||
icon: SchedulerIcon,
|
||||
},
|
||||
];
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
// 判断当前路由是否激活
|
||||
const isActive = (path: string) => {
|
||||
return route.path === path;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initFlowbite();
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
class="block mb-2 text-sm font-medium autocompletetext-gray-900 dark:text-white">密码</label>
|
||||
<input type="password" id="password" autocomplete="new-password" v-model="formData.password"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||
placeholder="非必填" required />
|
||||
placeholder="编辑时非必填" required />
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label for="confirm_password"
|
||||
@@ -42,7 +42,7 @@
|
||||
<input type="password" id="confirm_password" autocomplete="new-password"
|
||||
v-model="formData.confirmPassword"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||
required placeholder="非必填" />
|
||||
required placeholder="编辑时非必填" />
|
||||
</div>
|
||||
<div class="col-span-2 sm:col-span-1">
|
||||
<label for="category" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">状态</label>
|
||||
@@ -81,21 +81,19 @@ const { user, onSubmit } = defineProps<{
|
||||
|
||||
const formData = ref();
|
||||
|
||||
watch(
|
||||
() => user,
|
||||
(newUser) => {
|
||||
formData.value = {
|
||||
id: newUser?.id,
|
||||
username: newUser?.username,
|
||||
password: undefined,
|
||||
enable: newUser?.enable,
|
||||
confirmPassword: undefined,
|
||||
};
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
const updateFormData = (newUser: typeof user) => {
|
||||
formData.value = {
|
||||
id: newUser?.id,
|
||||
username: newUser?.username,
|
||||
password: undefined,
|
||||
enable: newUser?.enable,
|
||||
confirmPassword: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
watch(() => user, updateFormData, {
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const userSchema = z
|
||||
@@ -105,19 +103,22 @@ const handleSubmit = async () => {
|
||||
.string({
|
||||
message: "用户名不能为空",
|
||||
})
|
||||
.min(4, "用户名至少4个字符"),
|
||||
.min(4, "用户名至少4个字符")
|
||||
.max(15, "用户名最多15个字符"),
|
||||
enable: z.boolean(),
|
||||
password: z
|
||||
.string({
|
||||
message: "密码不能为空",
|
||||
})
|
||||
.min(5, "密码至少5个字符")
|
||||
.max(20, "密码最多20个字符")
|
||||
.optional(),
|
||||
confirmPassword: z
|
||||
.string({
|
||||
message: "密码不能为空",
|
||||
})
|
||||
.min(5, "密码至少5个字符")
|
||||
.max(20, "密码最多20个字符")
|
||||
.optional(),
|
||||
})
|
||||
.refine(
|
||||
@@ -133,6 +134,7 @@ const handleSubmit = async () => {
|
||||
try {
|
||||
const validatedData = userSchema.parse(formData.value);
|
||||
await onSubmit(validatedData);
|
||||
updateFormData(undefined);
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
alertStore.showAlert({
|
||||
|
||||
7
frontend/src/components/icons/DepartmentIcon.vue
Normal file
7
frontend/src/components/icons/DepartmentIcon.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg class="text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 15v3c0 .5523.44772 1 1 1h4v-4m-5 0v-4m0 4h5m-5-4V6c0-.55228.44772-1 1-1h16c.5523 0 1 .44772 1 1v1.98935M3 11h5v4m9.4708 4.1718-.8696-1.4388-2.8164-.235-2.573-4.2573 1.4873-2.8362 1.4441 2.3893c.3865.6396 1.2183.8447 1.8579.4582.6396-.3866.8447-1.2184.4582-1.858l-1.444-2.38925h3.1353l2.6101 4.27715-1.0713 2.5847.8695 1.4388" />
|
||||
</svg>
|
||||
</template>
|
||||
9
frontend/src/components/icons/PermissionIcon.vue
Normal file
9
frontend/src/components/icons/PermissionIcon.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-key-round-icon lucide-key-round">
|
||||
<path
|
||||
d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z" />
|
||||
<circle cx="16.5" cy="7.5" r=".5" fill="currentColor" />
|
||||
</svg>
|
||||
</template>
|
||||
7
frontend/src/components/icons/PositionIcon.vue
Normal file
7
frontend/src/components/icons/PositionIcon.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M14.6144 7.19994c.3479.48981.5999 1.15357.5999 1.80006 0 1.6569-1.3432 3-3 3-1.6569 0-3.00004-1.3431-3.00004-3 0-.67539.22319-1.29865.59983-1.80006M6.21426 6v4m0-4 6.00004-3 6 3-6 2-2.40021-.80006M6.21426 6l3.59983 1.19994M6.21426 19.8013v-2.1525c0-1.6825 1.27251-3.3075 2.95093-3.6488l3.04911 2.9345 3-2.9441c1.7026.3193 3 1.9596 3 3.6584v2.1525c0 .6312-.5373 1.1429-1.2 1.1429H7.41426c-.66274 0-1.2-.5117-1.2-1.1429Z" />
|
||||
</svg>
|
||||
</template>
|
||||
10
frontend/src/components/icons/RoleIcon.vue
Normal file
10
frontend/src/components/icons/RoleIcon.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-shield-user-icon lucide-shield-user">
|
||||
<path
|
||||
d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" />
|
||||
<path d="M6.376 18.91a6 6 0 0 1 11.249.003" />
|
||||
<circle cx="12" cy="11" r="4" />
|
||||
</svg>
|
||||
</template>
|
||||
7
frontend/src/components/icons/SchedulerIcon.vue
Normal file
7
frontend/src/components/icons/SchedulerIcon.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
</template>
|
||||
16
frontend/src/components/icons/SettingsIcon.vue
Normal file
16
frontend/src/components/icons/SettingsIcon.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user-cog-icon lucide-user-cog">
|
||||
<circle cx="18" cy="15" r="3" />
|
||||
<circle cx="9" cy="7" r="4" />
|
||||
<path d="M10 15H6a4 4 0 0 0-4 4v2" />
|
||||
<path d="m21.7 16.4-.9-.3" />
|
||||
<path d="m15.2 13.9-.9-.3" />
|
||||
<path d="m16.6 18.7.3-.9" />
|
||||
<path d="m19.1 12.2.3-.9" />
|
||||
<path d="m19.6 18.7-.4-1" />
|
||||
<path d="m16.8 12.3-.4-1" />
|
||||
<path d="m14.3 16.6 1-.4" />
|
||||
<path d="m20.7 13.8 1-.4" />
|
||||
</svg>
|
||||
</template>
|
||||
9
frontend/src/components/icons/UsersIcon.vue
Normal file
9
frontend/src/components/icons/UsersIcon.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users-icon lucide-users">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="9" cy="7" r="4" />
|
||||
<path d="M22 21v-2a4 4 0 0 0-3-3.87" />
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
||||
</svg>
|
||||
</template>
|
||||
Reference in New Issue
Block a user