Merge branch 'main' into dev

This commit is contained in:
Chuck1sn
2025-06-03 18:07:02 +08:00
32 changed files with 959 additions and 847 deletions

View File

@@ -1,28 +1,28 @@
<template> <template>
<div id="globalAlert" <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']" :class="['flex space-x-1.5 sm:space-x-2 items-center rounded-lg p-3 text-xs sm:p-4 sm:text-sm mb-4 fixed top-2 right-2 sm:top-4 sm:right-4 md:top-8 md: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"> role="alert">
<svg v-if="alertStore.alertStorage.level==='info'" xmlns="http://www.w3.org/2000/svg" width="24" height="24" <svg v-if="alertStore.alertStorage.level==='info'" xmlns="http://www.w3.org/2000/svg" width="20" height="20"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" 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"> stroke-linejoin="round" class="lucide lucide-info-icon lucide-info">
<circle cx="12" cy="12" r="10" /> <circle cx="12" cy="12" r="10" />
<path d="M12 16v-4" /> <path d="M12 16v-4" />
<path d="M12 8h.01" /> <path d="M12 8h.01" />
</svg> </svg>
<svg v-else-if="alertStore.alertStorage.level === 'warning'" xmlns="http://www.w3.org/2000/svg" width="24" <svg v-else-if="alertStore.alertStorage.level === 'warning'" xmlns="http://www.w3.org/2000/svg" width="20"
height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" height="20" 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"> 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="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 9v4" />
<path d="M12 17h.01" /> <path d="M12 17h.01" />
</svg> </svg>
<svg v-if="alertStore.alertStorage.level === 'success'" xmlns="http://www.w3.org/2000/svg" width="24" <svg v-if="alertStore.alertStorage.level === 'success'" xmlns="http://www.w3.org/2000/svg" width="20"
height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" height="20" 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"> stroke-linejoin="round" class="lucide lucide-circle-check-icon lucide-circle-check">
<circle cx="12" cy="12" r="10" /> <circle cx="12" cy="12" r="10" />
<path d="m9 12 2 2 4-4" /> <path d="m9 12 2 2 4-4" />
</svg> </svg>
<svg v-if="alertStore.alertStorage.level === 'error'" xmlns="http://www.w3.org/2000/svg" width="24" height="24" <svg v-if="alertStore.alertStorage.level === 'error'" xmlns="http://www.w3.org/2000/svg" width="20" height="20"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" 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"> stroke-linejoin="round" class="lucide lucide-circle-x-icon lucide-circle-x">
<circle cx="12" cy="12" r="10" /> <circle cx="12" cy="12" r="10" />

View File

@@ -1,6 +1,6 @@
<template> <template>
<div <div
class="h-[calc(100vh-3.5rem)] flex flex-col box-border p-3 overflow-y-auto w-80 overflow-x-hidden border-gray-200 border-l" class="h-[calc(100vh-3.5rem)] flex flex-col box-border p-3 overflow-y-auto md:w-80 w-full overflow-x-hidden border-gray-200 border-l"
ref="chatContainer"> ref="chatContainer">
<div class="flex flex-col gap-y-5 flex-1 pb-2"> <div class="flex flex-col gap-y-5 flex-1 pb-2">
<li v-for="chatElement in messages" :key="chatElement.content" <li v-for="chatElement in messages" :key="chatElement.content"

View File

@@ -1,10 +1,11 @@
<template> <template>
<nav class="flex mb-5" aria-label="Breadcrumb"> <nav class="flex mb-3 sm:mb-4 md:mb-5" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1 text-sm font-medium md:space-x-2"> <ol class="inline-flex items-center space-x-1 text-xs sm:text-sm font-medium md:space-x-2">
<li class="inline-flex items-center"> <li class="inline-flex items-center">
<RouterLink :to="{name: RouteName.USERVIEW}" <RouterLink :to="{name: RouteName.USERVIEW}"
class="inline-flex items-center text-gray-700 hover:text-primary-600 "> class="inline-flex items-center text-gray-700 hover:text-primary-600">
<svg class="w-5 h-5 mr-2.5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-4 h-4 sm:w-5 sm:h-5 me-1.5 sm:me-2 md:me-2.5" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path <path
d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"> d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z">
</path> </path>
@@ -14,12 +15,13 @@
</li> </li>
<li v-for="name in names" :key="name"> <li v-for="name in names" :key="name">
<div class="flex items-center"> <div class="flex items-center">
<svg class="w-6 h-6 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
</svg> </svg>
<span class="ml-1 text-gray-400 hover:text-primary-600 md:ml-2 ">{{ <span class="ms-1 text-gray-400 hover:text-primary-600 md:ms-2">{{
name }}</span> name }}</span>
</div> </div>
</li> </li>

View File

@@ -1,56 +1,83 @@
<template> <template>
<button :disabled="disabled" @click="handleClick" type="button" :class="{ <button :disabled="disabled" @click="handleClick" type="button" :class="[
'text-white': true, 'text-white',
'focus:ring-4': true, 'focus:ring-4',
'focus:outline-none': true, 'focus:outline-none',
'focus:ring-blue-300': true, 'focus:ring-blue-300',
'font-medium': true, 'font-medium',
'rounded-lg': true, 'rounded-lg',
'text-sm': true, 'text-center',
'px-5': true, 'inline-flex',
'py-2.5': true, 'items-center',
'text-center': true, 'justify-center',
'inline-flex': true, isLoading && !abortable ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-700 hover:bg-blue-800',
'items-center': true, sizeClasses
'bg-blue-700 hover:bg-blue-800': !isLoading, ]">
[loadingStyle]: isLoading <LoadingIcon v-if="isLoading && !abortable" :class="[iconSizeClasses, iconOnly ? '' : 'me-2']" />
}"> <StopIcon v-else-if="isLoading && abortable" :class="[iconSizeClasses, iconOnly ? '' : 'me-2']" />
<LoadingIcon v-if="isLoading && !abortable" /> <slot v-else-if="!isLoading && $slots.icon" name="icon" :iconSizeClasses="iconSizeClasses"></slot>
<StopIcon v-else-if="isLoading && abortable" />
{{isLoading ? loadingContent : submitContent}} <span v-if="iconOnly && isLoading" class="sr-only">{{ loadingContent }}</span>
</button> <span v-else-if="iconOnly && !isLoading && !$slots.icon" class="sr-only">{{ submitContent }}</span>
<template v-else-if="!iconOnly">
{{ isLoading ? loadingContent : submitContent }}
</template>
</button>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from "vue"; import { computed, useSlots } from "vue";
import LoadingIcon from "./icons/LoadingIcon.vue"; import LoadingIcon from "./icons/LoadingIcon.vue";
import StopIcon from "./icons/StopIcon.vue"; import StopIcon from "./icons/StopIcon.vue";
const { const props = defineProps<{
loadingContent,
submitContent,
isLoading = false,
abortable = false,
} = defineProps<{
loadingContent?: string; loadingContent?: string;
submitContent: string; submitContent: string;
isLoading: boolean; isLoading: boolean;
abortable: boolean; abortable: boolean;
handleClick: (event: Event) => void; handleClick: (event: Event) => void;
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
iconOnly?: boolean;
}>(); }>();
const loadingStyle = computed<string>(() => { const slots = useSlots();
switch (true) {
case isLoading && !abortable: const sizeClasses = computed(() => {
return "bg-blue-400 cursor-not-allowed"; if (props.iconOnly && slots.icon) {
case isLoading && abortable: switch (props.size) {
return "bg-blue-700 hover:bg-blue-800"; case 'xs': return 'p-1.5';
case 'sm': return 'p-2';
case 'lg': return 'p-3';
case 'xl': return 'p-3.5';
default: return 'p-2.5';
}
}
switch (props.size) {
case 'xs': return 'text-xs px-2.5 py-1.5';
case 'sm': return 'text-xs px-3 py-2';
case 'lg': return 'text-base px-5 py-3';
case 'xl': return 'text-base px-6 py-3.5';
default: default:
return ""; return 'text-sm px-4 py-2.5';
} }
}); });
const iconSizeClasses = computed(() => {
switch (props.size) {
case 'xs': return 'w-3 h-3';
case 'sm': return 'w-4 h-4';
case 'lg': return 'w-5 h-5';
case 'xl': return 'w-6 h-6';
default:
return 'w-5 h-5';
}
});
const loadingStyle = computed<string>(() => {
return '';
});
const disabled = computed(() => { const disabled = computed(() => {
return !abortable && isLoading; return !props.abortable && props.isLoading;
}); });
</script> </script>

View File

@@ -3,7 +3,7 @@
<Sidebar> <Sidebar>
</Sidebar> </Sidebar>
<div class="flex flex-row h-[calc(100vh-3.5rem)] mt-14"> <div class="flex flex-row h-[calc(100vh-3.5rem)] mt-14">
<article class="flex-1 ml-44 overflow-y-auto"> <article class="flex-1 sm:ml-44 overflow-y-auto">
<RouterView></RouterView> <RouterView></RouterView>
</article> </article>
<Assistant v-if="isAssistantVisible"></Assistant> <Assistant v-if="isAssistantVisible"></Assistant>

View File

@@ -1,18 +1,18 @@
<template> <template>
<!-- Main modal --> <!-- Main modal -->
<div id="user-upsert-modal" tabindex="-1" aria-hidden="true" <div :id="department?.id ? 'department-update-modal' : 'department-create-modal'" tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<!-- Modal content --> <!-- Modal content -->
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<!-- Modal header --> <!-- Modal header -->
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
部门管理 部门管理
</h3> </h3>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center "> class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@@ -22,26 +22,27 @@
</div> </div>
<!-- Modal body --> <!-- Modal body -->
<div class="p-4 md:p-5"> <div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-2"> <div class="grid gap-4 mb-4 grid-cols-1">
<div class="col-span-2"> <div class="col-span-full">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">部门名称</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">部门名称</label>
<input type="text" id="name" v-model="formData.name" <input type="text" id="name" v-model="formData.name"
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 " 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"
required /> required />
</div> </div>
<div class="col-span-2"> <div class="col-span-full">
<label for="category" class="block mb-2 text-sm font-medium text-gray-900 ">上级部门</label> <label for="category" class="block mb-2 text-sm font-medium text-gray-900">上级部门</label>
<select id="category" v-model="formData.parentId" <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 "> 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">
<option v-for="department in availableDepartments" :key="department.id" :value="department.id" <option :value="null"></option>
:selected="department.id === formData.parentId">{{ <option v-for="dept in availableDepartments" :key="dept.id" :value="dept.id"
department.name :selected="dept.id === formData.parentId">{{
dept.name
}}</option> }}</option>
</select> </select>
</div> </div>
</div> </div>
<button type="submit" @click="handleSubmit" <button type="submit" @click="handleSubmit"
class="text-white flex items-center 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 self-start mt-5"> class="w-full sm:w-auto text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center self-start mt-5">
保存 保存
</button> </button>
</div> </div>

View File

@@ -5,7 +5,7 @@
<div class="flex items-center justify-start rtl:justify-end"> <div class="flex items-center justify-start rtl:justify-end">
<button data-drawer-target="logo-sidebar" data-drawer-toggle="logo-sidebar" aria-controls="logo-sidebar" <button data-drawer-target="logo-sidebar" data-drawer-toggle="logo-sidebar" aria-controls="logo-sidebar"
type="button" type="button"
class="inline-flex items-center p-2 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 "> class="inline-flex items-center p-2 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200">
<span class="sr-only">Open sidebar</span> <span class="sr-only">Open sidebar</span>
<svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" <svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"> xmlns="http://www.w3.org/2000/svg">
@@ -14,15 +14,15 @@
</path> </path>
</svg> </svg>
</button> </button>
<a href="https://github.com/ccmjga/zhilu-admin" target="_blank" class="flex ms-2 md:me-24"> <a href="https://github.com/ccmjga/zhilu-admin" target="_blank" class="flex items-center ms-2 md:me-24">
<span class="self-center text-xl font-semibold sm:text-2xl whitespace-nowrap ">知路后台管理</span> <span class="self-center text-lg sm:text-xl md:text-2xl font-semibold whitespace-nowrap">知路后台管理</span>
</a> </a>
</div> </div>
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-2 sm:space-x-3">
<a href="https://github.com/ccmjga/zhilu-admin" target="_blank" <a href="https://github.com/ccmjga/zhilu-admin" target="_blank"
class="flex items-center border rounded-sm border-gray-300"> class="hidden sm:flex items-center border rounded-sm border-gray-300">
<span class=" bg-gray-200 rounded-r-none border-r border-r-gray-300"> <span class="bg-gray-200 rounded-r-none border-r border-r-gray-300">
<svg class="me-0.5 inline pl-1.5 pb-1 w-6 h-6 text-gray-800 bg-gray-200 " aria-hidden="true" <svg class="me-0.5 inline pl-1.5 pb-1 w-6 h-6 text-gray-800 bg-gray-200" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"> xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-width="2" <path stroke="currentColor" stroke-width="2"
d="M11.083 5.104c.35-.8 1.485-.8 1.834 0l1.752 4.022a1 1 0 0 0 .84.597l4.463.342c.9.069 1.255 1.2.556 1.771l-3.33 2.723a1 1 0 0 0-.337 1.016l1.03 4.119c.214.858-.71 1.552-1.474 1.106l-3.913-2.281a1 1 0 0 0-1.008 0L7.583 20.8c-.764.446-1.688-.248-1.474-1.106l1.03-4.119A1 1 0 0 0 6.8 14.56l-3.33-2.723c-.698-.571-.342-1.702.557-1.771l4.462-.342a1 1 0 0 0 .84-.597l1.753-4.022Z" /> d="M11.083 5.104c.35-.8 1.485-.8 1.834 0l1.752 4.022a1 1 0 0 0 .84.597l4.463.342c.9.069 1.255 1.2.556 1.771l-3.33 2.723a1 1 0 0 0-.337 1.016l1.03 4.119c.214.858-.71 1.552-1.474 1.106l-3.913-2.281a1 1 0 0 0-1.008 0L7.583 20.8c-.764.446-1.688-.248-1.474-1.106l1.03-4.119A1 1 0 0 0 6.8 14.56l-3.33-2.723c-.698-.571-.342-1.702.557-1.771l4.462-.342a1 1 0 0 0 .84-.597l1.753-4.022Z" />
@@ -31,13 +31,13 @@
</span> </span>
<span class="text-sm py-0.5 px-2 font-medium">0.1k</span> <span class="text-sm py-0.5 px-2 font-medium">0.1k</span>
</a> </a>
<span class="flex space-x-3"> <span class="flex space-x-2 sm:space-x-3">
<button class="cursor-pointer" @click="changeAssistantVisible"> <button class="cursor-pointer p-1" @click="changeAssistantVisible">
<AiChatIcon class="w-6 h-6 text-gray-600" /> <AiChatIcon class="w-7 h-7 text-gray-600 sm:w-5 sm:h-5" />
</button> </button>
</span> </span>
<div class="flex items-center ms-3"> <div class="flex items-center ms-2 sm:ms-3">
<div> <div>
<button type="button" id="dropdown-button" <button type="button" id="dropdown-button"
class="flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 " aria-expanded="false" class="flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 " aria-expanded="false"

View File

@@ -1,20 +1,25 @@
<template> <template>
<form class="max-w-xs mb-4"> <form class="w-full sm: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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="bindInput" <input type="search" id="default-search" v-model="bindInput" :class="[
:class="['block w-full ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500', size === 'sm' ? 'p-2.5' : size === 'md' ? 'p-3' : 'p-4']" 'block w-full ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500',
:placeholder="placeholder" required /> size === 'sm' ? 'p-2.5 text-xs' : size === 'md' ? 'p-3 text-sm' : 'p-4 text-base'
<button type="submit" ]" :placeholder="placeholder" required />
:class="['text-white absolute end-2.5 font-medium rounded-lg text-sm', size === 'sm' ? 'text-xs px-1.5 py-1.5 bottom-2' : size === 'md' ? 'text-sm px-4 py-2 bottom-2.5' : 'text-base px-4 py-2', bgColor] " <button type="submit" :class="[
@click.prevent="handleSubmitClick(bindInput)">{{ content }}</button> 'text-white absolute end-2.5 font-medium rounded-lg',
size === 'sm' ? 'text-xs px-2.5 py-1.5 bottom-2' :
size === 'md' ? 'text-sm px-3 py-2 bottom-2.5' :
'text-base px-4 py-2.5 bottom-3',
bgColor
]" @click.prevent="handleSubmitClick(bindInput)">{{ content }}</button>
</div> </div>
</form> </form>
</template> </template>

View File

@@ -1,17 +1,17 @@
<template> <template>
<!-- Main modal --> <!-- Main modal -->
<div id="user-upsert-modal" tabindex="-1" aria-hidden="true" <div :id="llm?.id ? 'llm-update-modal' : 'llm-create-modal'" tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-sm sm:max-w-md max-h-full">
<!-- Modal content --> <!-- Modal content -->
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<!-- Modal header --> <!-- Modal header -->
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
大模型管理 大模型管理
</h3> </h3>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center "> class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@@ -21,56 +21,56 @@
</div> </div>
<!-- Modal body --> <!-- Modal body -->
<form class="p-4 md:p-5"> <form class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-2"> <div class="grid gap-4 mb-4 grid-cols-1 sm:grid-cols-2">
<div class="col-span-2"> <div class="col-span-full sm:col-span-2">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">名称</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">名称</label>
<input type="text" name="名称" id="name" v-model="formData.name" <input type="text" name="名称" id="name" v-model="formData.name"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 " class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5"
required="true"> required="true">
</div> </div>
<div class="col-span-2"> <div class="col-span-full sm:col-span-2">
<label for="modelName" class="block mb-2 text-sm font-medium autocomplete text-gray-900 ">模型名称</label> <label for="modelName" class="block mb-2 text-sm font-medium autocomplete text-gray-900">模型名称</label>
<input type="text" id="modelName" autocomplete="new-password" v-model="formData.modelName" <input type="text" id="modelName" autocomplete="new-password" v-model="formData.modelName"
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 " 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"
required /> required />
</div> </div>
<div class="col-span-2 sm:col-span-1"> <div class="col-span-full sm:col-span-1">
<label for="type" class="block mb-2 text-sm font-medium text-gray-900 ">类型</label> <label for="type" class="block mb-2 text-sm font-medium text-gray-900">类型</label>
<select id="type" v-model="formData.type" <select id="type" v-model="formData.type"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5"> class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5">
<option :value="'CHAT'">聊天</option> <option :value="'CHAT'">聊天</option>
<option :value="'EMBEDDING'">嵌入</option> <option :value="'EMBEDDING'">嵌入</option>
</select> </select>
</div> </div>
<div class="col-span-2"> <div class="col-span-full sm:col-span-1">
<label for="apiKey" class="block mb-2 text-sm font-medium autocomplete text-gray-900 ">apiKey</label> <label for="status" class="block mb-2 text-sm font-medium text-gray-900">状态</label>
<input type="text" id="apiKey" autocomplete="new-password" v-model="formData.apiKey"
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"
required />
</div>
<div class="col-span-2">
<label for="url" class="block mb-2 text-sm font-medium text-gray-900 ">url</label>
<input type="text" id="url" autocomplete="new-password" v-model="formData.url"
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 "
required />
</div>
<div class="col-span-2 sm:col-span-1">
<label for="status" class="block mb-2 text-sm font-medium text-gray-900 ">状态</label>
<select id="status" v-model="formData.enable" <select id="status" v-model="formData.enable"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5"> class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5">
<option :value=true>启用</option> <option :value=true>启用</option>
<option :value=false>禁用</option> <option :value=false>禁用</option>
</select> </select>
</div> </div>
<div class="col-span-2"> <div class="col-span-full sm:col-span-2">
<label for="priority" class="block mb-2 text-sm font-medium autocomplete text-gray-900 ">优先级</label> <label for="apiKey" class="block mb-2 text-sm font-medium autocomplete text-gray-900">apiKey</label>
<input type="text" id="apiKey" autocomplete="new-password" v-model="formData.apiKey"
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"
required />
</div>
<div class="col-span-full sm:col-span-2">
<label for="url" class="block mb-2 text-sm font-medium text-gray-900">url</label>
<input type="text" id="url" autocomplete="new-password" v-model="formData.url"
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"
required />
</div>
<div class="col-span-full sm:col-span-2">
<label for="priority" class="block mb-2 text-sm font-medium autocomplete text-gray-900">优先级</label>
<input type="number" id="priority" autocomplete="new-password" v-model="formData.priority" <input type="number" id="priority" autocomplete="new-password" v-model="formData.priority"
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" 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"
required /> required />
</div> </div>
</div> </div>
<button type="submit" @click.prevent="handleSubmit" <button type="submit" @click.prevent="handleSubmit"
class="text-white flex items-center 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 self-start mt-5"> class="w-full sm:w-auto text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center self-start mt-5">
保存 保存
</button> </button>
</form> </form>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div :id tabindex="-1" aria-hidden="true" <div :id tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
权限管理 权限管理
</h3> </h3>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
@@ -17,22 +17,22 @@
</button> </button>
</div> </div>
<div class="p-4 md:p-5"> <div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-2"> <div class="grid gap-4 mb-4 grid-cols-1">
<div class="col-span-2"> <div class="col-span-full">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">权限名称</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">权限名称</label>
<input type="text" name="权限名称" id="name" v-model="formData.name" <input type="text" name="权限名称" id="name" v-model="formData.name"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5"
required="true"> required="true">
</div> </div>
<div class="col-span-2"> <div class="col-span-full">
<label for="code" class="block mb-2 text-sm font-medium text-gray-900 ">权限编码</label> <label for="code" class="block mb-2 text-sm font-medium text-gray-900">权限编码</label>
<input type="text" id="code" v-model="formData.code" <input type="text" id="code" v-model="formData.code"
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" 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"
required /> required />
</div> </div>
</div> </div>
<button type="submit" @click.prevent="handleSubmit" <button type="submit" @click.prevent="handleSubmit"
class="text-white flex items-center 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 self-start mt-5"> class="w-full sm:w-auto text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center self-start mt-5">
保存 保存
</button> </button>
</div> </div>

View File

@@ -1,33 +1,33 @@
<template> <template>
<div :id tabindex="-1" <div :id tabindex="-1"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center "> class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
</svg> </svg>
<span class="sr-only">Close modal</span> <span class="sr-only">Close modal</span>
</button> </button>
<div class="p-4 md:p-5 text-center flex flex-col items-center gap-y-3"> <div class="p-4 md:p-5 text-center flex flex-col items-center gap-y-3 sm:gap-y-4">
<svg class="w-16 h-16 mx-auto text-red-600 mt-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" <svg class="w-12 h-12 sm:w-16 sm:h-16 mx-auto text-red-600 mt-4 sm:mt-5" fill="none" stroke="currentColor"
xmlns="http://www.w3.org/2000/svg"> viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg> </svg>
<h3 class="mb-3 text-lg font-normal text-gray-500 "> <h3 class="mb-2 sm:mb-3 text-base sm:text-lg font-normal text-gray-500">
{{ title }} {{ title }}
</h3> </h3>
<span> <div class="flex flex-col sm:flex-row sm:justify-center gap-2 w-full sm:w-auto">
<button type="button" @click="onSubmit" <button type="button" @click="onSubmit"
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center"> class="w-full sm:w-auto text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center">
</button> </button>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
class="py-2.5 px-5 ms-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 "></button> class="w-full sm:w-auto py-2 sm:py-2.5 px-4 sm:px-5 text-xs sm:text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100"></button>
</span> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,17 +1,17 @@
<template> <template>
<!-- Main modal --> <!-- Main modal -->
<div :id tabindex="-1" aria-hidden="true" <div :id tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<!-- Modal content --> <!-- Modal content -->
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<!-- Modal header --> <!-- Modal header -->
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
岗位管理 岗位管理
</h3> </h3>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center "> class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@@ -21,17 +21,17 @@
</div> </div>
<!-- Modal body --> <!-- Modal body -->
<div class="p-4 md:p-5"> <div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-2"> <div class="grid gap-4 mb-4 grid-cols-1">
<div class="col-span-2"> <div class="col-span-full">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">岗位名称</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">岗位名称</label>
<input type="text" id="name" v-model="formData.name" <input type="text" id="name" v-model="formData.name"
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 " 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"
required /> required />
</div> </div>
</div> </div>
<button type="submit" @click="handleSubmit" <button type="submit" @click="handleSubmit"
class="text-white flex items-center 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 self-start mt-5"> class="w-full sm:w-auto text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center self-start mt-5">
保存 保存
</button> </button>
</div> </div>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div id="role-upsert-modal" tabindex="-1" aria-hidden="true" <div id="role-upsert-modal" tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
角色管理 角色管理
</h3> </h3>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
@@ -17,22 +17,22 @@
</button> </button>
</div> </div>
<div class="p-4 md:p-5"> <div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-2"> <div class="grid gap-4 mb-4 grid-cols-1">
<div class="col-span-2"> <div class="col-span-full">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">角色名称</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">角色名称</label>
<input type="text" name="角色名称" id="name" v-model="formData.name" <input type="text" name="角色名称" id="name" v-model="formData.name"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5"
required="true"> required="true">
</div> </div>
<div class="col-span-2"> <div class="col-span-full">
<label for="code" class="block mb-2 text-sm font-medium text-gray-900 ">角色代码</label> <label for="code" class="block mb-2 text-sm font-medium text-gray-900">角色代码</label>
<input type="text" id="code" v-model="formData.code" <input type="text" id="code" v-model="formData.code"
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" 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"
required /> required />
</div> </div>
</div> </div>
<button type="submit" @click.prevent="handleSubmit" <button type="submit" @click.prevent="handleSubmit"
class="text-white flex items-center 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 self-start mt-5"> class="w-full sm:w-auto text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center self-start mt-5">
保存 保存
</button> </button>
</div> </div>

View File

@@ -1,14 +1,14 @@
<template> <template>
<div :id tabindex="-1" aria-hidden="true" <div :id tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<div class="relative bg-white rounded-lg shadow "> <div class="relative bg-white rounded-lg shadow">
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
{{ '更新表达式' }} {{ '更新表达式' }}
</h3> </h3>
<button @click="closeModal" type="button" <button @click="closeModal" type="button"
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center "> class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@@ -16,15 +16,15 @@
</button> </button>
</div> </div>
<form @submit.prevent="handleSubmit" class="p-4 md:p-5"> <form @submit.prevent="handleSubmit" class="p-4 md:p-5">
<div class="grid gap-4 mb-4"> <div class="mb-4">
<div> <div>
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">Cron 表达式</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">Cron 表达式</label>
<input type="text" v-model="formData.cronExpression" name="name" id="name" <input type="text" v-model="formData.cronExpression" name="name" id="name"
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"> 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">
</div> </div>
</div> </div>
<button type="submit" <button type="submit"
class="text-white inline-flex items-center 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"> class="w-full sm:w-auto text-white inline-flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center">
提交 提交
</button> </button>
</form> </form>

View File

@@ -1,7 +1,7 @@
<template> <template>
<aside id="logo-sidebar" <aside id="logo-sidebar"
class="fixed top-0 left-0 z-30 px-1 w-44 min-h-screen overflow-y-auto pt-20 transition-transform -translate-x-full bg-white border-r border-gray-200 sm:translate-x-0 " class="fixed top-0 left-0 z-30 px-1 w-44 min-h-screen overflow-y-auto pt-20 transition-transform -translate-x-full bg-white border-r border-gray-200 sm:translate-x-0"
aria-label="Sidebar"> aria-label="Sidebar" tabindex="-1" data-drawer-backdrop="true">
<div class="h-full px-3 pb-4 overflow-y-auto bg-white "> <div class="h-full px-3 pb-4 overflow-y-auto bg-white ">
<ul class="space-y-2 font-medium"> <ul class="space-y-2 font-medium">
<li v-for="item in menuItems" :key="item.path"> <li v-for="item in menuItems" :key="item.path">
@@ -31,7 +31,6 @@ import RoleIcon from "./icons/RoleIcon.vue";
import SchedulerIcon from "./icons/SchedulerIcon.vue"; import SchedulerIcon from "./icons/SchedulerIcon.vue";
import SettingsIcon from "./icons/SettingsIcon.vue"; import SettingsIcon from "./icons/SettingsIcon.vue";
import UsersIcon from "./icons/UsersIcon.vue"; import UsersIcon from "./icons/UsersIcon.vue";
import AiChatIcon from "./icons/AiChatIcon.vue";
import LlmConfigIcon from "./icons/LlmConfigIcon.vue"; import LlmConfigIcon from "./icons/LlmConfigIcon.vue";
// 菜单配置 // 菜单配置

View File

@@ -1,33 +1,33 @@
<template> <template>
<nav class="flex items-center flex-column flex-wrap md:flex-row justify-between pt-4 px-5 pb-5" <nav class="flex items-center flex-col md:flex-row flex-wrap justify-between py-3 sm:py-4 px-3 sm:px-5"
aria-label="Table navigation"> aria-label="Table navigation">
<span class="text-sm font-normal text-gray-500 mb-4 md:mb-0 block w-full md:inline md:w-auto"> <span class="text-xs sm:text-sm font-normal text-gray-500 mb-3 md:mb-0 block w-full md:inline md:w-auto">
显示 显示
<span class="font-semibold text-gray-900 "> <span class="font-semibold text-gray-900">
{{ displayRange.start }}-{{ displayRange.end }} {{ displayRange.start }}-{{ displayRange.end }}
</span> </span>
<span class="font-semibold text-gray-900 ">{{ total }}</span> <span class="font-semibold text-gray-900">{{ total }}</span>
</span> </span>
<ul class="inline-flex -space-x-px rtl:space-x-reverse text-sm h-8"> <ul class="inline-flex -space-x-px rtl:space-x-reverse text-xs sm:text-sm">
<li> <li>
<a href="#" @click.prevent="handlePageChangeClick(currentPage - 1)" :class="[ <a href="#" @click.prevent="handlePageChangeClick(currentPage - 1)" :class="[
'flex items-center justify-center px-3 h-8 ms-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700 ', 'flex items-center justify-center px-2.5 h-7 sm:px-3 sm:h-8 ms-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700',
{ 'opacity-50 cursor-not-allowed': isFirstPage } { 'opacity-50 cursor-not-allowed': isFirstPage }
]">上一页</a> ]">上一页</a>
</li> </li>
<li v-for="page in pageNumbers" :key="page"> <li v-for="page in pageNumbers" :key="page">
<button @click.prevent="handlePageChangeClick(page)" :class="[ <button @click.prevent="handlePageChangeClick(page)" :class="[
'flex items-center justify-center px-3 h-8 leading-tight border border-gray-300 hover:bg-gray-100 hover:text-gray-700 ', 'flex items-center justify-center px-2.5 h-7 sm:px-3 sm:h-8 leading-tight border border-gray-300 hover:bg-gray-100 hover:text-gray-700',
currentPage === page currentPage === page
? 'text-blue-600 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 ' ? 'text-blue-600 bg-blue-50 hover:bg-blue-100 hover:text-blue-700'
: 'text-gray-500 bg-white ' : 'text-gray-500 bg-white'
]">{{ page }}</button> ]">{{ page }}</button>
</li> </li>
<li> <li>
<button @click.prevent="handlePageChangeClick(currentPage + 1)" :class="[ <button @click.prevent="handlePageChangeClick(currentPage + 1)" :class="[
'flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700 ', 'flex items-center justify-center px-2.5 h-7 sm:px-3 sm:h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700',
{ 'opacity-50 cursor-not-allowed': isLastPage } { 'opacity-50 cursor-not-allowed': isLastPage }
]">下一页</button> ]">下一页</button>
</li> </li>

View File

@@ -1,17 +1,17 @@
<template> <template>
<!-- Main modal --> <!-- Main modal -->
<div id="user-upsert-modal" tabindex="-1" aria-hidden="true" <div id="user-upsert-modal" tabindex="-1" aria-hidden="true"
class="bg-gray-900/50 /80 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
<!-- Modal content --> <!-- Modal content -->
<div class="relative bg-white rounded-lg shadow-sm "> <div class="relative bg-white rounded-lg shadow-sm">
<!-- Modal header --> <!-- Modal header -->
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200"> <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
<h3 class="text-lg font-semibold text-gray-900 "> <h3 class="text-base sm:text-lg font-semibold text-gray-900">
用户管理 用户管理
</h3> </h3>
<button type="button" @click="closeModal" <button type="button" @click="closeModal"
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center "> class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@@ -21,28 +21,28 @@
</div> </div>
<!-- Modal body --> <!-- Modal body -->
<form class="p-4 md:p-5"> <form class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-2"> <div class="grid gap-4 mb-4 grid-cols-1 sm:grid-cols-2">
<div class="col-span-2"> <div class="col-span-full sm:col-span-2">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 ">用户名</label> <label for="name" class="block mb-2 text-sm font-medium text-gray-900">用户名</label>
<input type="text" name="用户名" id="name" v-model="formData.username" <input type="text" name="用户名" id="name" v-model="formData.username"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 " class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5"
required="true"> required="true">
</div> </div>
<div class="col-span-2"> <div class="col-span-full sm:col-span-2">
<label for="password" class="block mb-2 text-sm font-medium autocompletetext-gray-900 ">密码</label> <label for="password" class="block mb-2 text-sm font-medium autocompletetext-gray-900">密码</label>
<input type="password" id="password" autocomplete="new-password" v-model="formData.password" <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 " 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"
placeholder="编辑时非必填" required /> placeholder="编辑时非必填" required />
</div> </div>
<div class="col-span-2"> <div class="col-span-full sm:col-span-2">
<label for="confirm_password" class="block mb-2 text-sm font-medium text-gray-900 ">确认密码</label> <label for="confirm_password" class="block mb-2 text-sm font-medium text-gray-900">确认密码</label>
<input type="password" id="confirm_password" autocomplete="new-password" <input type="password" id="confirm_password" autocomplete="new-password"
v-model="formData.confirmPassword" 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 " 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"
required placeholder="编辑时非必填" /> required placeholder="编辑时非必填" />
</div> </div>
<div class="col-span-2 sm:col-span-1"> <div class="col-span-full sm:col-span-1">
<label for="status" class="block mb-2 text-sm font-medium text-gray-900 ">状态</label> <label for="status" class="block mb-2 text-sm font-medium text-gray-900">状态</label>
<select id="status" v-model="formData.enable" <select id="status" v-model="formData.enable"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5"> class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5">
<option :value=true>启用</option> <option :value=true>启用</option>
@@ -51,7 +51,7 @@
</div> </div>
</div> </div>
<button type="submit" @click.prevent="handleSubmit" <button type="submit" @click.prevent="handleSubmit"
class="text-white flex items-center 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 self-start mt-5"> class="w-full sm:w-auto text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center self-start mt-5">
保存 保存
</button> </button>
</form> </form>

View File

@@ -1,37 +1,37 @@
<template> <template>
<div class="relative overflow-x-auto px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['部门分配']" /> <Breadcrumbs :names="['部门分配']" />
<h1 class="text-xl mb-2 font-semibold text-gray-900 sm:text-2xl ">部门分配</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">部门分配</h1>
</div> </div>
<div class="relative"> <div class="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-sm mb-4 grid grid-cols-5 gap-y-4"> <form class="w-full sm:w-auto flex flex-col xs:flex-row gap-2 xs:gap-3 items-stretch xs:items-center">
<div class="col-span-3"> <div class="flex-grow">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="departmentName" <input type="search" id="default-search" v-model="departmentName"
class="block p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-2.5 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="部门名称" required /> placeholder="部门名称" required />
</div> </div>
</div> </div>
<select id="countries" v-model="bindState" <select id="countries" v-model="bindState"
class="col-span-2 block bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 "> class="w-full xs:w-auto bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5">
<option value="BIND">已绑定</option> <option value="BIND">已绑定</option>
<option value="UNBIND">未绑定</option> <option value="UNBIND">未绑定</option>
<option value="ALL">全部</option> <option value="ALL">全部</option>
</select> </select>
<button type="submit" <button type="submit"
class="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-4 py-2 " class="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-4 py-2.5"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</form> </form>
<div class="flex items-center justify-end gap-2 absolute right-5 bottom-2"> <div class="flex items-center justify-end gap-2">
<button @click="() => { <button @click="() => {
if (checkedDepartmentIds.length === 0) { if (checkedDepartmentIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
@@ -42,7 +42,7 @@
departmentBindModal?.show(); departmentBindModal?.show();
} }
}" }"
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" 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-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
绑定 绑定
</button> </button>
@@ -56,55 +56,57 @@
departmentUnbindModal?.show(); departmentUnbindModal?.show();
} }
}" }"
class="flex items-center block text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center" class="flex items-center text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
解绑 解绑
</button> </button>
</div> </div>
</div> </div>
<table class="w-full text-sm text-left rtl:text-right text-gray-500 "> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<thead class="text-xs uppercase bg-gray-50 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<tr> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<th scope="col" class="p-4"> <tr>
<div class="flex items-center"> <th scope="col" class="p-2 sm:p-4 w-4">
<input id="checkbox-all-search" type="checkbox" v-model="allChecked" <div class="flex items-center">
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> <input id="checkbox-all-search" type="checkbox" v-model="allChecked"
<label for="checkbox-all-search" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</th> </div>
<th scope="col" class="px-6 py-3">上级部门</th> </th>
<th scope="col" class="px-6 py-3">部门名称</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">上级部门</th>
<th scope="col" class="px-6 py-3">绑定状态</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">部门名称</th>
</tr> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">绑定状态</th>
</thead> </tr>
<tbody> </thead>
<tr v-for="department in departments" :key="department.id" <tbody>
class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="department in departments" :key="department.id"
<td class="w-4 p-4"> class="bg-white border-b border-gray-200 hover:bg-gray-50">
<div class="flex items-center"> <td class="w-4 p-2 sm:p-4">
<input :id="'checkbox-table-search-' + department.id" :value="department.id" type="checkbox" <div class="flex items-center">
v-model="checkedDepartmentIds" <input :id="'checkbox-table-search-' + department.id" :value="department.id" type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> v-model="checkedDepartmentIds"
<label :for="'checkbox-table-search-' + department.id" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label :for="'checkbox-table-search-' + department.id" class="sr-only">checkbox</label>
</td> </div>
<td scope="row" class="px-6 py-4whitespace-nowrap "> </td>
{{ !department.parentName ? '无' : department.parentName }} <td scope="row" class="px-3 py-2 md:px-4 md:py-3 whitespace-nowrap">
</td> {{ !department.parentName ? '无' : department.parentName }}
<td scope="row" class="px-6 py-4whitespace-nowrap font-medium text-gray-900 "> </td>
{{ department.name }} <td scope="row" class="px-3 py-2 md:px-4 md:py-3 whitespace-nowrap font-medium text-gray-900">
</td> {{ department.name }}
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> </td>
<div class="flex items-center"> <td class="px-3 py-2 md:px-4 md:py-3 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="department.isBound ? 'bg-green-500' : 'bg-red-500'"> <div class="flex items-center">
</div> {{ <div class="h-2.5 w-2.5 rounded-full me-2" :class="department.isBound ? 'bg-green-500' : 'bg-red-500'">
department.isBound === true ? "已绑定" : "未绑定" }} </div> {{
</div> department.isBound === true ? "已绑定" : "未绑定" }}
</td> </div>
</tr> </td>
</tbody> </tr>
</table> </tbody>
</table>
</div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>

View File

@@ -1,38 +1,38 @@
<template> <template>
<div class="relative overflow-x-auto px-4 pt-6 xl:grid-cols-3 xl:gap-4 rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['绑定权限']" /> <Breadcrumbs :names="['绑定权限']" />
<h1 class="text-xl mb-2 font-semibold text-gray-900 sm:text-2xl "> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">
绑定权限</h1> 绑定权限</h1>
</div> </div>
<div class="relative"> <div class="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-sm mb-4 grid grid-cols-5 gap-y-4"> <form class="w-full sm:w-auto flex flex-col xs:flex-row gap-2 xs:gap-3 items-stretch xs:items-center">
<div class="col-span-3"> <div class="flex-grow">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="permissionName" <input type="search" id="default-search" v-model="permissionName"
class="block p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-2.5 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="权限名" required /> placeholder="权限名" required />
</div> </div>
</div> </div>
<select id="countries" v-model="bindState" <select id="countries" v-model="bindState"
class="col-span-2 block bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 "> class="w-full xs:w-auto bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5">
<option value="BIND">已绑定</option> <option value="BIND">已绑定</option>
<option value="UNBIND">未绑定</option> <option value="UNBIND">未绑定</option>
<option value="ALL">全部</option> <option value="ALL">全部</option>
</select> </select>
<button type="submit" <button type="submit"
class="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-4 py-2 " class="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-4 py-2.5"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</form> </form>
<div class="flex items-center justify-end gap-2 absolute right-5 bottom-2"> <div class="flex items-center justify-end gap-2">
<button @click="() => { <button @click="() => {
if (checkedPermissionIds.length === 0) { if (checkedPermissionIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
@@ -43,7 +43,7 @@
permissionBindModal?.show(); permissionBindModal?.show();
} }
}" }"
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" 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-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
绑定 绑定
</button> </button>
@@ -57,55 +57,58 @@
permissionUnbindModal?.show(); permissionUnbindModal?.show();
} }
}" }"
class="flex items-center block text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center" class="flex items-center text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
解绑 解绑
</button> </button>
</div> </div>
</div> </div>
<table class="w-full text-sm text-left rtl:text-right text-gray-500 "> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<tr> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<th scope="col" class="p-4"> <tr>
<div class="flex items-center"> <th scope="col" class="p-2 sm:p-4 w-4">
<input id="checkbox-all-search" type="checkbox" v-model="allChecked" <div class="flex items-center">
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> <input id="checkbox-all-search" type="checkbox" v-model="allChecked"
<label for="checkbox-all-search" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</th> </div>
<th scope="col" class="px-6 py-3">权限编码</th> </th>
<th scope="col" class="px-6 py-3">权限名称</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3 hidden md:table-cell">权限编码</th>
<th scope="col" class="px-6 py-3">绑定状态</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">权限名称</th>
</tr> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">绑定状态</th>
</thead> </tr>
<tbody> </thead>
<tr v-for="permission in permissions" :key="permission.id" <tbody>
class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="permission in permissions" :key="permission.id"
<td class="w-4 p-4"> class="bg-white border-b border-gray-200 hover:bg-gray-50">
<div class="flex items-center"> <td class="w-4 p-2 sm:p-4">
<input :id="'checkbox-table-search-' + permission.id" :value="permission.id" type="checkbox" <div class="flex items-center">
v-model="checkedPermissionIds" <input :id="'checkbox-table-search-' + permission.id" :value="permission.id" type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> v-model="checkedPermissionIds"
<label :for="'checkbox-table-search-' + permission.id" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label :for="'checkbox-table-search-' + permission.id" class="sr-only">checkbox</label>
</td> </div>
<td scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap "> </td>
{{ permission.code }} <td scope="row"
</td> class="px-3 py-2 md:px-4 md:py-3 font-medium text-gray-900 whitespace-nowrap hidden md:table-cell">
<td scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap "> {{ permission.code }}
{{ permission.name }} </td>
</td> <td scope="row" class="px-3 py-2 md:px-4 md:py-3 font-medium text-gray-900 whitespace-nowrap">
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> {{ permission.name }}
<div class="flex items-center"> </td>
<div class="h-2.5 w-2.5 rounded-full me-2" :class="permission.isBound ? 'bg-green-500' : 'bg-red-500'"> <td class="px-3 py-2 md:px-4 md:py-3 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
</div> {{ <div class="flex items-center">
permission.isBound === true ? "已绑定" : "未绑定" }} <div class="h-2.5 w-2.5 rounded-full me-2" :class="permission.isBound ? 'bg-green-500' : 'bg-red-500'">
</div> </div> {{
</td> permission.isBound === true ? "已绑定" : "未绑定" }}
</tr> </div>
</tbody> </td>
</table> </tr>
</tbody>
</table>
</div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>

View File

@@ -1,37 +1,37 @@
<template> <template>
<div class="relative overflow-x-auto px-4 pt-6 xl:grid-cols-3 xl:gap-4 rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['岗位分配']" /> <Breadcrumbs :names="['岗位分配']" />
<h1 class="text-xl mb-2 font-semibold text-gray-900 sm:text-2xl ">岗位分配</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">岗位分配</h1>
</div> </div>
<div class="relative"> <div class="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-sm mb-4 grid grid-cols-5 gap-y-4"> <form class="w-full sm:w-auto flex flex-col xs:flex-row gap-2 xs:gap-3 items-stretch xs:items-center">
<div class="col-span-3"> <div class="flex-grow">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="positionName" <input type="search" id="default-search" v-model="positionName"
class="block p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-2.5 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="岗位名称" required /> placeholder="岗位名称" required />
</div> </div>
</div> </div>
<select id="countries" v-model="bindState" <select id="countries" v-model="bindState"
class="col-span-2 block bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 "> class="w-full xs:w-auto bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5">
<option value="BIND">已绑定</option> <option value="BIND">已绑定</option>
<option value="UNBIND">未绑定</option> <option value="UNBIND">未绑定</option>
<option value="ALL">全部</option> <option value="ALL">全部</option>
</select> </select>
<button type="submit" <button type="submit"
class="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-4 py-2 " class="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-4 py-2.5"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</form> </form>
<div class="flex items-center justify-end gap-2 absolute right-5 bottom-2"> <div class="flex items-center justify-end gap-2">
<button @click="() => { <button @click="() => {
if (checkedPositionIds.length === 0) { if (checkedPositionIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
@@ -42,7 +42,7 @@
positionBindModal?.show(); positionBindModal?.show();
} }
}" }"
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" 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-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
绑定 绑定
</button> </button>
@@ -56,52 +56,53 @@
positionUnbindModal?.show(); positionUnbindModal?.show();
} }
}" }"
class="flex items-center block text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center" class="flex items-center text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
解绑 解绑
</button> </button>
</div> </div>
</div> </div>
<table class="w-full text-sm text-left rtl:text-right text-gray-500 "> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<thead class="text-xs uppercase bg-gray-50 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<tr> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<th scope="col" class="p-4"> <tr>
<div class="flex items-center"> <th scope="col" class="p-2 sm:p-4 w-4">
<input id="checkbox-all-search" type="checkbox" v-model="allChecked" <div class="flex items-center">
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> <input id="checkbox-all-search" type="checkbox" v-model="allChecked"
<label for="checkbox-all-search" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</th> </div>
<th scope="col" class="px-6 py-3">岗位名称</th> </th>
<th scope="col" class="px-6 py-3">绑定状态</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">岗位名称</th>
</tr> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">绑定状态</th>
</thead> </tr>
<tbody> </thead>
<tr v-for="position in positions" :key="position.id" <tbody>
class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="position in positions" :key="position.id"
<td class="w-4 p-4"> class="bg-white border-b border-gray-200 hover:bg-gray-50">
<div class="flex items-center"> <td class="w-4 p-2 sm:p-4">
<input :id="'checkbox-table-search-' + position.id" :value="position.id" type="checkbox" <div class="flex items-center">
v-model="checkedPositionIds" <input :id="'checkbox-table-search-' + position.id" :value="position.id" type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> v-model="checkedPositionIds"
<label :for="'checkbox-table-search-' + position.id" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label :for="'checkbox-table-search-' + position.id" class="sr-only">checkbox</label>
</td> </div>
</td>
<td scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap "> <td scope="row" class="px-3 py-2 md:px-4 md:py-3 font-medium text-gray-900 whitespace-nowrap">
{{ position.name }} {{ position.name }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 md:px-4 md:py-3 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="position.isBound ? 'bg-green-500' : 'bg-red-500'"> <div class="h-2.5 w-2.5 rounded-full me-2" :class="position.isBound ? 'bg-green-500' : 'bg-red-500'">
</div> {{ </div> {{
position.isBound === true ? "已绑定" : "未绑定" }} position.isBound === true ? "已绑定" : "未绑定" }}
</div> </div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>

View File

@@ -1,37 +1,37 @@
<template> <template>
<div class="relative overflow-x-auto px-4 pt-6 xl:grid-cols-3 xl:gap-4 rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['角色分配']" /> <Breadcrumbs :names="['角色分配']" />
<h1 class="text-xl mb-2 font-semibold text-gray-900 sm:text-2xl ">角色分配</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">角色分配</h1>
</div> </div>
<div class="relative"> <div class="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-sm mb-4 grid grid-cols-5 gap-y-4"> <form class="w-full sm:w-auto flex flex-col xs:flex-row gap-2 xs:gap-3 items-stretch xs:items-center">
<div class="col-span-3"> <div class="flex-grow">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="roleName" <input type="search" id="default-search" v-model="roleName"
class="block p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-2.5 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="角色名" required /> placeholder="角色名" required />
</div> </div>
</div> </div>
<select id="countries" v-model="bindState" <select id="countries" v-model="bindState"
class="col-span-2 block bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 "> class="w-full xs:w-auto bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5">
<option value="BIND">已绑定</option> <option value="BIND">已绑定</option>
<option value="UNBIND">未绑定</option> <option value="UNBIND">未绑定</option>
<option value="ALL">全部</option> <option value="ALL">全部</option>
</select> </select>
<button type="submit" <button type="submit"
class="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-4 py-2 " class="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-4 py-2.5"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</form> </form>
<div class="flex items-center justify-end gap-2 absolute right-5 bottom-2"> <div class="flex items-center justify-end gap-2">
<button @click="() => { <button @click="() => {
if (checkedRoleIds.length === 0) { if (checkedRoleIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
@@ -42,7 +42,7 @@
roleBindModal?.show(); roleBindModal?.show();
} }
}" }"
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" 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-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
绑定 绑定
</button> </button>
@@ -56,53 +56,55 @@
roleUnbindModal?.show(); roleUnbindModal?.show();
} }
}" }"
class="flex items-center block text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center" class="flex items-center text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-2 sm:px-4 sm:py-2.5 text-center"
type="button"> type="button">
解绑 解绑
</button> </button>
</div> </div>
</div> </div>
<table class="w-full text-sm text-left rtl:text-right text-gray-500 "> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<thead class="text-xs uppercase bg-gray-50 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<tr> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<th scope="col" class="p-4"> <tr>
<div class="flex items-center"> <th scope="col" class="p-2 sm:p-4 w-4">
<input id="checkbox-all-search" type="checkbox" v-model="allChecked" <div class="flex items-center">
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> <input id="checkbox-all-search" type="checkbox" v-model="allChecked"
<label for="checkbox-all-search" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</th> </div>
<th scope="col" class="px-6 py-3">角色编码</th> </th>
<th scope="col" class="px-6 py-3">角色名称</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3 hidden md:table-cell">角色编码</th>
<th scope="col" class="px-6 py-3">绑定状态</th> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">角色名称</th>
</tr> <th scope="col" class="px-3 py-2 md:px-4 md:py-3">绑定状态</th>
</thead> </tr>
<tbody> </thead>
<tr v-for="role in roles" :key="role.id" class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tbody>
<td class="w-4 p-4"> <tr v-for="role in roles" :key="role.id" class="bg-white border-b border-gray-200 hover:bg-gray-50">
<div class="flex items-center"> <td class="w-4 p-2 sm:p-4">
<input :id="'checkbox-table-search-' + role.id" :value="role.id" type="checkbox" v-model="checkedRoleIds" <div class="flex items-center">
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> <input :id="'checkbox-table-search-' + role.id" :value="role.id" type="checkbox" v-model="checkedRoleIds"
<label :for="'checkbox-table-search-' + role.id" class="sr-only">checkbox</label> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
</div> <label :for="'checkbox-table-search-' + role.id" class="sr-only">checkbox</label>
</td> </div>
<td scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap "> </td>
{{ role.code }} <td scope="row" class="px-3 py-2 md:px-4 md:py-3 font-medium text-gray-900 whitespace-nowrap hidden md:table-cell">
</td> {{ role.code }}
<td scope="row" class="px-6 py-4 whitespace-nowrap "> </td>
{{ role.name }} <td scope="row" class="px-3 py-2 md:px-4 md:py-3 whitespace-nowrap">
</td> {{ role.name }}
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> </td>
<div class="flex items-center"> <td class="px-3 py-2 md:px-4 md:py-3 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="role.isBound ? 'bg-green-500' : 'bg-red-500'"> <div class="flex items-center">
</div> {{ <div class="h-2.5 w-2.5 rounded-full me-2" :class="role.isBound ? 'bg-green-500' : 'bg-red-500'">
role.isBound === true ? "已绑定" : "未绑定" }} </div> {{
</div> role.isBound === true ? "已绑定" : "未绑定" }}
</td> </div>
</tr> </td>
</tbody> </tr>
</table> </tbody>
</table>
</div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>

View File

@@ -1,73 +1,77 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 col-span-full">
<Breadcrumbs :names="['部门管理']" /> <Breadcrumbs :names="['部门管理']" />
<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="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-xs mb-4"> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="name" <input type="search" id="default-search" v-model="name"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="部门名称" required /> placeholder="部门名称" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle --> <Button :handleClick="() => handleUpsertDepartmentClick()" :isLoading="false" :abortable="false"
<button @click="handleUpsertDepartmentClick()" submitContent="新增部门" size="sm" class="w-full sm:w-auto">
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" <template #icon>
type="button"> <svg class="w-4 h-4 me-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
新增部门 viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
</button> <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</template>
</Button>
</div> </div>
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<thead class="text-xs uppercase bg-gray-50 "> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">上级部门</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">上级部门</th>
<th scope="col" class="px-6 py-3">部门名称</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">部门名称</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="department in departments" :key="department.id" <tr v-for="department in departments" :key="department.id"
class="bg-white border-b border-gray-200 hover:bg-gray-50 "> class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + department.id" type="checkbox" disabled <input :id="'checkbox-table-search-' + department.id" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label :for="'checkbox-table-search-' + department.id" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + department.id" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
{{ !department.parentName ? '无' : department.parentName }} {{ !department.parentName ? '无' : department.parentName }}
</td> </td>
<td class="px-6 py-4 font-medium text-gray-900 "> <td class="px-3 py-2 sm:px-6 sm:py-4 font-medium text-gray-900">
{{ department.name }} {{ department.name }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center gap-x-2"> <div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button @click="handleUpsertDepartmentClick(department)" <button @click="handleUpsertDepartmentClick(department)"
class="flex items-center justify-center whitespace-nowrap gap-x-1 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 " class="flex items-center justify-center whitespace-nowrap gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
@@ -76,11 +80,10 @@
<span>编辑</span> <span>编辑</span>
</button> </button>
<button <button
class="flex items-center justify-center whitespace-nowrap gap-x-1 class="flex items-center justify-center whitespace-nowrap gap-x-1 bg-red-700 hover:bg-red-800 focus:ring-red-300 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
bg-red-700 hover:bg-red-800
focus:ring-red-500 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5"
@click="handleDeleteDepartmentClick(department)" type="button"> @click="handleDeleteDepartmentClick(department)" type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
@@ -109,6 +112,7 @@
<script setup lang="ts"> <script setup lang="ts">
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import Button from "@/components/Button.vue";
import DepartmentUpsertModal from "@/components/DepartmentUpsertModal.vue"; import DepartmentUpsertModal from "@/components/DepartmentUpsertModal.vue";
import DepartmentDeleteModal from "@/components/PopupModal.vue"; import DepartmentDeleteModal from "@/components/PopupModal.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";

View File

@@ -1,89 +1,100 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 col-span-full">
<Breadcrumbs :names="['大模型管理']" /> <Breadcrumbs :names="['大模型管理']" />
<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="mb-4">
<form class="max-w-xs mb-4 "> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="name" <input type="search" id="default-search" v-model="name"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="模型名称" required /> placeholder="模型名称" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle -->
</div> </div>
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table <table class="w-full whitespace-nowrap text-sm text-left rtl:text-right text-gray-500">
class="w-full whitespace-nowrap text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 overflow-x-auto"> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<thead class="text-xs uppercase bg-gray-50 ">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">名称</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">名称</th>
<th scope="col" class="px-6 py-3">模型名称</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">模型名称</th>
<th scope="col" class="px-6 py-3">类型</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden md:table-cell">类型</th>
<th scope="col" class="px-6 py-3">apiKey</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden lg:table-cell">apiKey</th>
<th scope="col" class="px-6 py-3">url</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden lg:table-cell">url</th>
<th scope="col" class="px-6 py-3">状态</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">状态</th>
<th scope="col" class="px-6 py-3">优先级</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden md:table-cell">优先级</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="llm in llms" :key="llm.id" class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="llm in llms" :key="llm.id" class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + llm.id" type="checkbox" disabled <input :id="'checkbox-table-search-' + llm.id" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label :for="'checkbox-table-search-' + llm.id" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + llm.id" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis font-medium text-gray-900"> <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[100px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis font-medium text-gray-900">
{{ {{
`${llm.name}` }}</td> `${llm.name}` }}</td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[120px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis">
{{
`${llm.modelName}` }} `${llm.modelName}` }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[80px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
{{
llm.type === 'CHAT' ? '聊天' : '嵌入' }} llm.type === 'CHAT' ? '聊天' : '嵌入' }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[150px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden lg:table-cell">
{{
llm.apiKey }} llm.apiKey }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ llm.url }}</td> <td
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[150px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden lg:table-cell">
{{ llm.url }}</td>
<td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[80px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="llm.enable ? 'bg-blue-500' : 'bg-red-500'"></div> {{ <div class="h-2.5 w-2.5 rounded-full me-2" :class="llm.enable ? 'bg-blue-500' : 'bg-red-500'"></div> {{
llm.enable === true ? "启用" : "禁用" }} llm.enable === true ? "启用" : "禁用" }}
</div> </div>
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ llm.priority }} <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[80px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
{{ llm.priority }}
</td> </td>
<td class="px-6 py-4 "> <td class="px-3 py-2 sm:px-4 md:px-6 sm:py-4">
<div class="flex items-center gap-x-2"> <div class="flex items-center gap-x-2">
<button @click="handleLlmUpdateClick(llm)" <button @click="handleLlmUpdateClick(llm)"
:class="['flex items-center justify-center gap-x-1 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 ']" class="flex items-center justify-center whitespace-nowrap gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"

View File

@@ -1,22 +1,22 @@
<template> <template>
<div class="flex flex-col items-center justify-center h-screen bg-gray-100 "> <div class="flex flex-col items-center justify-center h-screen bg-gray-100">
<div class="w-full max-w-sm p-4 bg-white border border-gray-200 rounded-lg shadow-sm sm:p-6 md:p-8 "> <div class="w-full max-w-xs sm:max-w-sm p-4 bg-white border border-gray-200 rounded-lg shadow-sm sm:p-6 md:p-8">
<form class="flex flex-col gap-y-4" action="#"> <form class="flex flex-col gap-y-4 sm:gap-y-5" action="#">
<h5 class="text-xl font-medium text-gray-900 ">知路管理后台</h5> <h5 class="text-xl sm:text-2xl font-medium text-gray-900">知路管理后台</h5>
<div> <div>
<label for="username" class="block mb-2 text-sm font-medium text-gray-900 ">用户名</label> <label for="username" class="block mb-2 text-sm font-medium text-gray-900">用户名</label>
<input type="text" name="email" id="username" v-model="username" <input type="text" name="email" id="username" v-model="username"
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 " 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"
placeholder="输入任意值" required /> placeholder="输入任意值" required />
</div> </div>
<div> <div>
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 ">密码</label> <label for="password" class="block mb-2 text-sm font-medium text-gray-900">密码</label>
<input type="password" name="password" id="password" v-model="password" placeholder="••••••••" <input type="password" name="password" id="password" v-model="password" placeholder="••••••••"
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 " 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"
required /> required />
</div> </div>
<button type="submit" <button type="submit"
class="w-full 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 " class="w-full 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 sm:text-base px-5 py-2.5 sm:py-3 text-center"
@click.prevent="handleLogin">登录</button> @click.prevent="handleLogin">登录</button>
</form> </form>
</div> </div>

View File

@@ -3,11 +3,12 @@ import { RoutePath } from "../router/constants";
</script> </script>
<template> <template>
<main class="grid min-h-full place-items-center bg-white px-6 py-24 sm:py-32 lg:px-8"> <main class="grid min-h-full place-items-center bg-white px-4 sm:px-6 lg:px-8 py-16 sm:py-24 md:py-32">
<div class="text-center"> <div class="text-center">
<p class="text-base font-semibold text-blue-700">404</p> <p class="text-lg sm:text-xl md:text-2xl font-semibold text-blue-700">404</p>
<h1 class="mt-4 text-5xl font-semibold tracking-tight text-balance text-gray-900 sm:text-7xl">Page not found</h1> <h1 class="mt-4 text-3xl sm:text-5xl md:text-7xl font-semibold tracking-tight text-balance text-gray-900">Page not
<p class="mt-6 text-lg font-medium text-pretty text-gray-500 sm:text-xl/8">您访问的资源未找到请点击浏览器后退按钮返回</p> found</h1>
<p class="mt-6 text-base sm:text-lg font-medium text-pretty text-gray-500">您访问的资源未找到请点击浏览器后退按钮返回</p>
<div class="mt-10 flex items-center justify-center gap-x-6"> <div class="mt-10 flex items-center justify-center gap-x-6">
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.OVERVIEW}`" <RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.OVERVIEW}`"
class="rounded-md px-3.5 py-2.5 text-sm font-semibold bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 text-white shadow-xs focus-visible:outline-2 focus-visible:outline-offset-2"> class="rounded-md px-3.5 py-2.5 text-sm font-semibold bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 text-white shadow-xs focus-visible:outline-2 focus-visible:outline-offset-2">

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="grid grid-cols-5 gap-4 p-4 "> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-2 sm:gap-4 p-2 sm:p-4">
<div class="col-span-3 bg-white rounded-lg shadow-sm p-4 md:p-6"> <div class="lg:col-span-3 md:col-span-2 col-span-1 bg-white rounded-lg shadow-sm p-3 sm:p-4 md:p-6">
<div class="flex justify-between pb-4 mb-4 border-b border-gray-200 "> <div class="flex flex-col sm:flex-row sm:justify-between pb-4 mb-4 border-b border-gray-200 gap-y-3 sm:gap-y-0">
<div class="flex items-center"> <div class="flex items-center">
<div class="w-12 h-12 rounded-lg bg-gray-100 flex items-center justify-center me-3"> <div class="w-10 h-10 sm:w-12 sm:h-12 rounded-lg bg-gray-100 flex items-center justify-center me-3">
<svg class="w-6 h-6 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" <svg class="w-5 h-5 sm:w-6 sm:h-6 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
fill="currentColor" viewBox="0 0 20 19"> fill="currentColor" viewBox="0 0 20 19">
<path <path
d="M14.5 0A3.987 3.987 0 0 0 11 2.1a4.977 4.977 0 0 1 3.9 5.858A3.989 3.989 0 0 0 14.5 0ZM9 13h2a4 4 0 0 1 4 4v2H5v-2a4 4 0 0 1 4-4Z" /> d="M14.5 0A3.987 3.987 0 0 0 11 2.1a4.977 4.977 0 0 1 3.9 5.858A3.989 3.989 0 0 0 14.5 0ZM9 13h2a4 4 0 0 1 4 4v2H5v-2a4 4 0 0 1 4-4Z" />
@@ -13,15 +13,15 @@
</svg> </svg>
</div> </div>
<div> <div>
<h5 class="leading-none text-2xl font-bold text-gray-900 pb-1">3.4k</h5> <h5 class="leading-none text-xl sm:text-2xl font-bold text-gray-900 pb-1">3.4k</h5>
<p class="text-sm font-normal text-gray-500 ">Leads generated per week</p> <p class="text-xs sm:text-sm font-normal text-gray-500">Leads generated per week</p>
</div> </div>
</div> </div>
<div> <div>
<span <span
class="bg-green-100 text-green-800 text-xs font-medium inline-flex items-center px-2.5 py-1 rounded-md "> class="bg-green-100 text-green-800 text-xs font-medium inline-flex items-center px-2 py-0.5 sm:px-2.5 sm:py-1 rounded-md">
<svg class="w-2.5 h-2.5 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-2 h-2 sm:w-2.5 sm:h-2.5 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 10 14"> fill="none" viewBox="0 0 10 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M5 13V1m0 0L1 5m4-4 4 4" /> d="M5 13V1m0 0L1 5m4-4 4 4" />
</svg> </svg>
@@ -30,34 +30,35 @@
</div> </div>
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-0">
<dl class="flex items-center"> <dl class="flex items-center">
<dt class="text-gray-500 text-sm font-normal me-1">Money spent:</dt> <dt class="text-gray-500 text-xs sm:text-sm font-normal me-1">Money spent:</dt>
<dd class="text-gray-900 text-sm font-semibold">$3,232</dd> <dd class="text-gray-900 text-xs sm:text-sm font-semibold">$3,232</dd>
</dl> </dl>
<dl class="flex items-center justify-end"> <dl class="flex items-center sm:justify-end">
<dt class="text-gray-500 text-sm font-normal me-1">Conversion rate:</dt> <dt class="text-gray-500 text-xs sm:text-sm font-normal me-1">Conversion rate:</dt>
<dd class="text-gray-900 text-sm font-semibold">1.2%</dd> <dd class="text-gray-900 text-xs sm:text-sm font-semibold">1.2%</dd>
</dl> </dl>
</div> </div>
<div id="column-chart"></div> <div id="column-chart" class="my-3 sm:my-4"></div>
<div class="grid grid-cols-1 items-center border-gray-200 border-t justify-between"> <div class="grid grid-cols-1 items-center border-gray-200 border-t justify-between">
<div class="flex justify-between items-center pt-5"> <div class="flex flex-col sm:flex-row justify-between items-center pt-3 sm:pt-5 gap-y-2 sm:gap-y-0">
<!-- Button --> <!-- Button -->
<button id="dropdownDefaultButton" data-dropdown-toggle="lastDaysdropdown" data-dropdown-placement="bottom" <button id="dropdownDefaultButton" data-dropdown-toggle="lastDaysdropdown" data-dropdown-placement="bottom"
class="text-sm font-medium text-gray-500 hover:text-gray-900 text-center inline-flex items-center " class="text-xs sm:text-sm font-medium text-gray-500 hover:text-gray-900 text-center inline-flex items-center"
type="button"> type="button">
Last 7 days Last 7 days
<svg class="w-2.5 m-2.5 ms-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-2 h-2 sm:w-2.5 m-2.5 ms-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 10 6"> viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 4 4 4-4" /> d="m1 1 4 4 4-4" />
</svg> </svg>
</button> </button>
<!-- Dropdown menu --> <!-- Dropdown menu -->
<div id="lastDaysdropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 "> <div id="lastDaysdropdown"
<ul class="py-2 text-sm text-gray-700 " aria-labelledby="dropdownDefaultButton"> class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-36 sm:w-44">
<ul class="py-2 text-xs sm:text-sm text-gray-700" aria-labelledby="dropdownDefaultButton">
<li> <li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Yesterday</a> <a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Yesterday</a>
</li> </li>
@@ -90,111 +91,117 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-span-1 bg-white border border-gray-200 rounded-lg shadow-sm sm:p-8 "> <div
class="lg:col-span-2 md:col-span-1 col-span-1 bg-white border border-gray-200 rounded-lg shadow-sm p-3 sm:p-4 md:p-6">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<h5 class="text-xl font-bold leading-none text-gray-900 ">Latest Customers</h5> <h5 class="text-lg sm:text-xl font-bold leading-none text-gray-900">Latest Customers</h5>
<a href="#" class="text-sm font-medium text-blue-600 hover:underline "> <a href="#" class="text-xs sm:text-sm font-medium text-blue-600 hover:underline">
View all View all
</a> </a>
</div> </div>
<div class="flow-root"> <div class="flow-root">
<ul role="list" class="divide-y divide-gray-200 "> <ul role="list" class="divide-y divide-gray-200">
<li class="py-3 sm:py-4"> <li class="py-2 sm:py-3 md:py-4">
<div class="flex items-center"> <div class="flex items-center">
<div class="shrink-0"> <div class="shrink-0">
<img src="/trump.jpg" class="w-8 h-8 rounded-full" </div> <img src="/trump.jpg" class="w-6 h-6 sm:w-8 sm:h-8 rounded-full" alt="Neil image" />
<div class="flex-1 min-w-0 ms-4">
<p class="text-sm font-medium text-gray-900 truncate ">
Neil Sims
</p>
<p class="text-sm text-gray-500 truncate ">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-base font-semibold text-gray-900 ">
$320
</div>
</div> </div>
</li> <div class="flex-1 min-w-0 ms-3 sm:ms-4">
<li class="py-3 sm:py-4"> <p class="text-xs sm:text-sm font-medium text-gray-900 truncate">
<div class="flex items-center "> Neil Sims
<div class="shrink-0"> </p>
<img src="/trump.jpg" class="w-8 h-8 rounded-full" </div> <p class="text-xs hidden xs:block sm:text-sm text-gray-500 truncate">
<div class="flex-1 min-w-0 ms-4"> email@windster.com
<p class="text-sm font-medium text-gray-900 truncate "> </p>
Bonnie Green
</p>
<p class="text-sm text-gray-500 truncate ">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-base font-semibold text-gray-900 ">
$3467
</div>
</div> </div>
<div class="inline-flex items-center text-sm sm:text-base font-semibold text-gray-900">
$320
</div>
</div>
</li> </li>
<li class="py-3 sm:py-4"> <li class="py-2 sm:py-3 md:py-4">
<div class="flex items-center"> <div class="flex items-center">
<div class="shrink-0"> <div class="shrink-0">
<img src="/trump.jpg" class="w-8 h-8 rounded-full" </div> <img src="/trump.jpg" class="w-6 h-6 sm:w-8 sm:h-8 rounded-full" alt="Bonnie image" />
<div class="flex-1 min-w-0 ms-4">
<p class="text-sm font-medium text-gray-900 truncate ">
Michael Gough
</p>
<p class="text-sm text-gray-500 truncate ">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-base font-semibold text-gray-900 ">
$67
</div>
</div> </div>
<div class="flex-1 min-w-0 ms-3 sm:ms-4">
<p class="text-xs sm:text-sm font-medium text-gray-900 truncate">
Bonnie Green
</p>
<p class="text-xs hidden xs:block sm:text-sm text-gray-500 truncate">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-sm sm:text-base font-semibold text-gray-900">
$3467
</div>
</div>
</li> </li>
<li class="py-3 sm:py-4"> <li class="py-2 sm:py-3 md:py-4">
<div class="flex items-center "> <div class="flex items-center">
<div class="shrink-0"> <div class="shrink-0">
<img src="/trump.jpg" class="w-8 h-8 rounded-full" </div> <img src="/trump.jpg" class="w-6 h-6 sm:w-8 sm:h-8 rounded-full" alt="Michael image" />
<div class="flex-1 min-w-0 ms-4">
<p class="text-sm font-medium text-gray-900 truncate ">
Lana Byrd
</p>
<p class="text-sm text-gray-500 truncate ">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-base font-semibold text-gray-900 ">
$367
</div>
</div> </div>
<div class="flex-1 min-w-0 ms-3 sm:ms-4">
<p class="text-xs sm:text-sm font-medium text-gray-900 truncate">
Michael Gough
</p>
<p class="text-xs hidden xs:block sm:text-sm text-gray-500 truncate">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-sm sm:text-base font-semibold text-gray-900">
$67
</div>
</div>
</li> </li>
<li class="pt-3 pb-0 sm:pt-4"> <li class="py-2 sm:py-3 md:py-4">
<div class="flex items-center "> <div class="flex items-center">
<div class="shrink-0"> <div class="shrink-0">
<img src="/trump.jpg" class="w-8 h-8 rounded-full" </div> <img src="/trump.jpg" class="w-6 h-6 sm:w-8 sm:h-8 rounded-full" alt="Lana image" />
<div class="flex-1 min-w-0 ms-4">
<p class="text-sm font-medium text-gray-900 truncate ">
Thomes Lean
</p>
<p class="text-sm text-gray-500 truncate ">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-base font-semibold text-gray-900 ">
$2367
</div>
</div> </div>
<div class="flex-1 min-w-0 ms-3 sm:ms-4">
<p class="text-xs sm:text-sm font-medium text-gray-900 truncate">
Lana Byrd
</p>
<p class="text-xs hidden xs:block sm:text-sm text-gray-500 truncate">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-sm sm:text-base font-semibold text-gray-900">
$367
</div>
</div>
</li>
<li class="pt-2 sm:pt-3 md:pt-4 pb-0">
<div class="flex items-center">
<div class="shrink-0">
<img src="/trump.jpg" class="w-6 h-6 sm:w-8 sm:h-8 rounded-full" alt="Thomas image" />
</div>
<div class="flex-1 min-w-0 ms-3 sm:ms-4">
<p class="text-xs sm:text-sm font-medium text-gray-900 truncate">
Thomes Lean
</p>
<p class="text-xs hidden xs:block sm:text-sm text-gray-500 truncate">
email@windster.com
</p>
</div>
<div class="inline-flex items-center text-sm sm:text-base font-semibold text-gray-900">
$2367
</div>
</div>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="col-span-2 max-w-sm w-full bg-white rounded-lg shadow-sm p-4 md:p-6"> <div class="lg:col-span-2 md:col-span-2 col-span-1 bg-white rounded-lg shadow-sm p-3 sm:p-4 md:p-6">
<div class="flex justify-between items-start w-full"> <div class="flex flex-col sm:flex-row justify-between items-start w-full gap-y-3 sm:gap-y-0">
<div class="flex-col items-center"> <div class="flex-col items-center">
<div class="flex items-center mb-1"> <div class="flex items-center mb-1">
<h5 class="text-xl font-bold leading-none text-gray-900 me-1">Website traffic</h5> <h5 class="text-lg sm:text-xl font-bold leading-none text-gray-900 me-1">Website traffic</h5>
<svg data-popover-target="chart-info" data-popover-placement="bottom" <svg data-popover-target="chart-info" data-popover-placement="bottom"
class="w-3.5 h-3.5 text-gray-500 hover:text-gray-900 cursor-pointer ms-1" aria-hidden="true" class="w-3 h-3 sm:w-3.5 sm:h-3.5 text-gray-500 hover:text-gray-900 cursor-pointer ms-1" aria-hidden="true"
xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"> xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<path <path
d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm0 16a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm1-5.034V12a1 1 0 0 1-2 0v-1.418a1 1 0 0 1 1.038-.999 1.436 1.436 0 0 0 1.488-1.441 1.501 1.501 0 1 0-3-.116.986.986 0 0 1-1.037.961 1 1 0 0 1-.96-1.037A3.5 3.5 0 1 1 11 11.466Z" /> d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm0 16a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm1-5.034V12a1 1 0 0 1-2 0v-1.418a1 1 0 0 1 1.038-.999 1.436 1.436 0 0 0 1.488-1.441 1.501 1.501 0 1 0-3-.116.986.986 0 0 1-1.037.961 1 1 0 0 1-.96-1.037A3.5 3.5 0 1 1 11 11.466Z" />
@@ -222,15 +229,15 @@
</div> </div>
<button id="dateRangeButton" data-dropdown-toggle="dateRangeDropdown" <button id="dateRangeButton" data-dropdown-toggle="dateRangeDropdown"
data-dropdown-ignore-click-outside-class="datepicker" type="button" data-dropdown-ignore-click-outside-class="datepicker" type="button"
class="inline-flex items-center text-blue-700 font-medium hover:underline">31 Nov - 31 class="inline-flex items-center text-blue-700 font-medium hover:underline text-xs sm:text-sm">31 Nov - 31
Dev <svg class="w-3 h-3 ms-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" Dev <svg class="w-2.5 h-2.5 sm:w-3 sm:h-3 ms-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 10 6"> fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 4 4 4-4" /> d="m1 1 4 4 4-4" />
</svg> </svg>
</button> </button>
<div id="dateRangeDropdown" <div id="dateRangeDropdown"
class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-80 lg:w-96 "> class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-80 lg:w-96">
<div class="p-3" aria-labelledby="dateRangeButton"> <div class="p-3" aria-labelledby="dateRangeButton">
<div date-rangepicker datepicker-autohide class="flex items-center"> <div date-rangepicker datepicker-autohide class="flex items-center">
<div class="relative"> <div class="relative">
@@ -265,15 +272,15 @@
<div class="flex justify-end items-center"> <div class="flex justify-end items-center">
<button id="widgetDropdownButton" data-dropdown-toggle="widgetDropdown" data-dropdown-placement="bottom" <button id="widgetDropdownButton" data-dropdown-toggle="widgetDropdown" data-dropdown-placement="bottom"
type="button" type="button"
class="inline-flex items-center justify-center text-gray-500 w-8 h-8 hover:bg-gray-100 focus:outline-none focus:ring-4 focus:ring-gray-200 rounded-lg text-sm"><svg class="inline-flex items-center justify-center text-gray-500 w-7 h-7 sm:w-8 sm:h-8 hover:bg-gray-100 focus:outline-none focus:ring-4 focus:ring-gray-200 rounded-lg text-sm">
class="w-3.5 h-3.5 text-gray-800 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" <svg class="w-3 h-3 sm:w-3.5 sm:h-3.5 text-gray-800" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
fill="currentColor" viewBox="0 0 16 3"> fill="currentColor" viewBox="0 0 16 3">
<path <path
d="M2 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm6.041 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM14 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z" /> d="M2 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm6.041 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM14 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z" />
</svg><span class="sr-only">Open dropdown</span> </svg><span class="sr-only">Open dropdown</span>
</button> </button>
<div id="widgetDropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 "> <div id="widgetDropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44">
<ul class="py-2 text-sm text-gray-700 " aria-labelledby="widgetDropdownButton"> <ul class="py-2 text-sm text-gray-700" aria-labelledby="widgetDropdownButton">
<li> <li>
<a href="#" class="flex items-center px-4 py-2 hover:bg-gray-100 "><svg class="w-3 h-3 me-2" <a href="#" class="flex items-center px-4 py-2 hover:bg-gray-100 "><svg class="w-3 h-3 me-2"
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 21 21"> aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 21 21">
@@ -314,48 +321,48 @@
</div> </div>
<!-- Line Chart --> <!-- Line Chart -->
<div class="py-6" id="pie-chart"></div> <div class="py-4 sm:py-6" id="pie-chart"></div>
<div class="grid grid-cols-1 items-center border-gray-200 border-t justify-between"> <div class="grid grid-cols-1 items-center border-gray-200 border-t justify-between">
<div class="flex justify-between items-center pt-5"> <div class="flex flex-col sm:flex-row justify-between items-center pt-3 sm:pt-5 gap-y-2 sm:gap-y-0">
<!-- Button --> <!-- Button -->
<button id="dropdownDefaultButton" data-dropdown-toggle="lastDaysdropdown" data-dropdown-placement="bottom" <button id="dropdownDefaultButton" data-dropdown-toggle="lastDaysdropdown" data-dropdown-placement="bottom"
class="text-sm font-medium text-gray-500 hover:text-gray-900 text-center inline-flex items-center " class="text-xs sm:text-sm font-medium text-gray-500 hover:text-gray-900 text-center inline-flex items-center"
type="button"> type="button">
Last 7 days Last 7 days
<svg class="w-2.5 m-2.5 ms-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-2 h-2 sm:w-2.5 sm:h-2.5 m-2.5 ms-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 10 6"> fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 1 4 4 4-4" /> d="m1 1 4 4 4-4" />
</svg> </svg>
</button> </button>
<div id="lastDaysdropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 "> <div id="lastDaysdropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44">
<ul class="py-2 text-sm text-gray-700 " aria-labelledby="dropdownDefaultButton"> <ul class="py-2 text-xs sm:text-sm text-gray-700" aria-labelledby="dropdownDefaultButton">
<li> <li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Yesterday</a> <a href="#" class="block px-4 py-2 hover:bg-gray-100">Yesterday</a>
</li> </li>
<li> <li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Today</a> <a href="#" class="block px-4 py-2 hover:bg-gray-100">Today</a>
</li> </li>
<li> <li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Last <a href="#" class="block px-4 py-2 hover:bg-gray-100">Last
7 days</a> 7 days</a>
</li> </li>
<li> <li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Last <a href="#" class="block px-4 py-2 hover:bg-gray-100">Last
30 days</a> 30 days</a>
</li> </li>
<li> <li>
<a href="#" class="block px-4 py-2 hover:bg-gray-100 ">Last <a href="#" class="block px-4 py-2 hover:bg-gray-100">Last
90 days</a> 90 days</a>
</li> </li>
</ul> </ul>
</div> </div>
<a href="#" <a href="#"
class="uppercase text-sm font-semibold inline-flex items-center rounded-lg text-blue-600 hover:text-blue-700 hover:bg-gray-100 px-3 py-2"> class="uppercase text-xs sm:text-sm font-semibold inline-flex items-center rounded-lg text-blue-600 hover:text-blue-700 hover:bg-gray-100 px-3 py-2">
Traffic analysis Traffic analysis
<svg class="w-2.5 h-2.5 ms-1.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" <svg class="w-2 h-2 sm:w-2.5 sm:h-2.5 ms-1.5 rtl:rotate-180" aria-hidden="true"
fill="none" viewBox="0 0 6 10"> xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m1 9 4-4-4-4" /> d="m1 9 4-4-4-4" />
</svg> </svg>

View File

@@ -1,71 +1,78 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 col-span-full">
<Breadcrumbs :names="['权限管理']" /> <Breadcrumbs :names="['权限管理']" />
<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="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-xs mb-4"> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="permissionName" <input type="search" id="default-search" v-model="permissionName"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="权限名" required /> placeholder="权限名" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle --> <!-- Create Modal toggle -->
<button @click="handleUpsertPermissionClick(undefined)" <Button :handleClick="() => handleUpsertPermissionClick(undefined)" :isLoading="false" :abortable="false"
class="flex items-center block gap-x-1 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" submitContent="新增权限" size="sm" class="w-full sm:w-auto">
type="button"> <template #icon>
新增权限 <svg class="w-4 h-4 me-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
</button> viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</template>
</Button>
</div> </div>
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<thead class="text-xs uppercase bg-gray-50 "> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">权限名称</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">权限名称</th>
<th scope="col" class="px-6 py-3">权限编码</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3 hidden md:table-cell">权限编码</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="permission in permissions" :key="permission.id" <tr v-for="permission in permissions" :key="permission.id"
class="bg-white border-b border-gray-200 hover:bg-gray-50 "> class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + permission.id" type="checkbox" disabled <input :id="'checkbox-table-search-' + permission.id" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label :for="'checkbox-table-search-' + permission.id" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + permission.id" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap "> <td scope="row" class="px-3 py-2 sm:px-6 sm:py-4 font-medium text-gray-900 whitespace-nowrap">
{{ permission.name }} {{ permission.name }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ permission.code }}</td> <td
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
<div class="flex items-center gap-x-2"> {{ permission.code }}</td>
<td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button @click="handleUpsertPermissionClick(permission)" <button @click="handleUpsertPermissionClick(permission)"
class="flex items-center justify-center whitespace-nowrap gap-x-1 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 " class="flex items-center justify-center whitespace-nowrap gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
@@ -74,11 +81,10 @@
<span>编辑</span> <span>编辑</span>
</button> </button>
<button <button
class="flex items-center justify-center whitespace-nowrap gap-x-1 class="flex items-center justify-center whitespace-nowrap gap-x-1 bg-red-700 hover:bg-red-800 focus:outline-none focus:ring-red-300 text-white focus:ring-4 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
bg-red-700 hover:bg-red-800 focus:outline-none
focus:ring-red-500 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 "
@click="handleDeletePermissionClick(permission)" type="button"> @click="handleDeletePermissionClick(permission)" type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
@@ -92,7 +98,6 @@
</table> </table>
</div> </div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>
@@ -106,6 +111,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Button from "@/components/Button.vue";
import PermissionUpsertModal from "@/components/PermissionUpsertModal.vue"; import PermissionUpsertModal from "@/components/PermissionUpsertModal.vue";
import PermissionDeleteModal from "@/components/PopupModal.vue"; import PermissionDeleteModal from "@/components/PopupModal.vue";
import usePermissionDelete from "@/composables/permission/usePermissionDelete"; import usePermissionDelete from "@/composables/permission/usePermissionDelete";

View File

@@ -1,70 +1,75 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 col-span-full">
<Breadcrumbs :names="['岗位管理']" /> <Breadcrumbs :names="['岗位管理']" />
<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="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-xs mb-4 "> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="name" <input type="search" id="default-search" v-model="name"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="岗位名称" required /> placeholder="岗位名称" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle --> <!-- Create Modal toggle -->
<button @click="handleUpsertPositionClick()" <Button :handleClick="() => handleUpsertPositionClick()" :isLoading="false" :abortable="false"
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" submitContent="新增岗位" size="sm" class="w-full sm:w-auto">
type="button"> <template #icon>
新增岗位 <svg class="w-4 h-4 me-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
</button> viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</template>
</Button>
</div> </div>
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 "> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">岗位名称</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">岗位名称</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="position in positions" :key="position.id" <tr v-for="position in positions" :key="position.id"
class="bg-white border-b border-gray-200 hover:bg-gray-50 "> class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + position.id" type="checkbox" disabled <input :id="'checkbox-table-search-' + position.id" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label :for="'checkbox-table-search-' + position.id" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + position.id" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td class="px-6 py-4 font-medium text-gray-900 "> <td class="px-3 py-2 sm:px-6 sm:py-4 font-medium text-gray-900">
{{ position.name }} {{ position.name }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center gap-x-2"> <div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button @click="handleUpsertPositionClick(position)" <button @click="handleUpsertPositionClick(position)"
class="flex items-center justify-center whitespace-nowrap gap-x-1 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 " class="flex items-center justify-center whitespace-nowrap gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
@@ -73,11 +78,10 @@
<span>编辑</span> <span>编辑</span>
</button> </button>
<button <button
class="flex items-center justify-center whitespace-nowrap gap-x-1 class="flex items-center justify-center whitespace-nowrap gap-x-1 bg-red-700 hover:bg-red-800 focus:ring-red-300 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5 text-center"
bg-red-700 hover:bg-red-800
focus:ring-red-500 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 text-center"
@click="handleDeletePositionClick(position)" type="button"> @click="handleDeletePositionClick(position)" type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
@@ -105,6 +109,7 @@
<script setup lang="ts"> <script setup lang="ts">
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import Button from "@/components/Button.vue";
import PositionDeleteModal from "@/components/PopupModal.vue"; import PositionDeleteModal from "@/components/PopupModal.vue";
import PositionUpsertModal from "@/components/PositionUpsertModal.vue"; import PositionUpsertModal from "@/components/PositionUpsertModal.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";

View File

@@ -1,80 +1,87 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 col-span-full">
<Breadcrumbs :names="['角色管理']" /> <Breadcrumbs :names="['角色管理']" />
<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="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-xs mb-4"> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="roleName" <input type="search" id="default-search" v-model="roleName"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="角色名" required /> placeholder="角色名" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle --> <!-- Create Modal toggle -->
<button @click="handleUpsertRoleClick(undefined)" <Button :handleClick="() => handleUpsertRoleClick(undefined)" :isLoading="false" :abortable="false"
class="flex items-center block gap-x-1 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" submitContent="新增角色" size="sm" class="w-full sm:w-auto">
type="button"> <template #icon>
新增角色 <svg class="w-4 h-4 me-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
</button> viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</template>
</Button>
</div> </div>
<div class="relative overflow-x-auto "> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<thead class="text-xs uppercase bg-gray-50 "> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">角色名称</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">角色名称</th>
<th scope="col" class="px-6 py-3">角色编码</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3 hidden md:table-cell">角色编码</th>
<th scope="col" class="px-6 py-3">分配</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">分配</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="role in roles" :key="role.id" class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="role in roles" :key="role.id" class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + role.id" type="checkbox" disabled <input :id="'checkbox-table-search-' + role.id" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label :for="'checkbox-table-search-' + role.id" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + role.id" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap "> <td scope="row" class="px-3 py-2 sm:px-6 sm:py-4 font-medium text-gray-900 whitespace-nowrap">
{{ role.name }} {{ role.name }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ role.code }}</td> <td
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
{{ role.code }}</td>
<td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div> <div>
<button <button
class="flex itmes-center justify-center min-w-min text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-4 py-2.5 " class="flex items-center justify-center min-w-min text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5 whitespace-nowrap"
@click="handleBindPermissionClick(role)" type="button"> @click="handleBindPermissionClick(role)" type="button">
<span>分配权限</span> <span>分配权限</span>
</button> </button>
</div> </div>
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center gap-x-2"> <div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button @click="handleUpsertRoleClick(role)" <button @click="handleUpsertRoleClick(role)"
class="flex items-center justify-center whitespace-nowrap gap-x-1 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 " class="flex items-center justify-center whitespace-nowrap gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
@@ -83,11 +90,10 @@
<span>编辑</span> <span>编辑</span>
</button> </button>
<button <button
class="flex items-center justify-center whitespace-nowrap block gap-x-1 class="flex items-center justify-center whitespace-nowrap gap-x-1 bg-red-700 hover:bg-red-800 focus:outline-none focus:ring-red-300 text-white focus:ring-4 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
bg-red-700 hover:bg-red-800 focus:outline-none
focus:ring-red-500 block text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5"
@click="handleDeleteRoleClick(role)" type="button"> @click="handleDeleteRoleClick(role)" type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
@@ -114,6 +120,7 @@
<script setup lang="ts"> <script setup lang="ts">
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import Button from "@/components/Button.vue";
import RoleDeleteModal from "@/components/PopupModal.vue"; import RoleDeleteModal from "@/components/PopupModal.vue";
import RoleUpsertModal from "@/components/RoleUpsertModal.vue"; import RoleUpsertModal from "@/components/RoleUpsertModal.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";

View File

@@ -1,91 +1,109 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4 col-span-full">
<Breadcrumbs :names="['任务管理']" /> <Breadcrumbs :names="['任务管理']" />
<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="mb-4">
<form class="max-w-xs mb-4 "> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="jobName" <input type="search" id="default-search" v-model="jobName"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="任务名称" required /> placeholder="任务名称" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle -->
</div> </div>
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 overflow-x-auto"> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<thead class="text-xs uppercase bg-gray-50 "> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">任务</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">任务</th>
<th scope="col" class="px-6 py-3">触发器</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden lg:table-cell">触发器</th>
<th scope="col" class="px-6 py-3">开始</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden lg:table-cell">开始</th>
<th scope="col" class="px-6 py-3">结束</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden lg:table-cell">结束</th>
<th scope="col" class="px-6 py-3">下次执行</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden md:table-cell">下次执行</th>
<th scope="col" class="px-6 py-3">上次执行</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden lg:table-cell">上次执行</th>
<th scope="col" class="px-6 py-3">类型</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden md:table-cell">类型</th>
<th scope="col" class="px-6 py-3">Cron</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden md:table-cell">Cron</th>
<th scope="col" class="px-6 py-3">状态</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">状态</th>
<th scope="col" class="px-6 py-3">编辑</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3 hidden sm:table-cell">编辑</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-4 md:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="job in jobs" :key="job.triggerName" class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="job in jobs" :key="job.triggerName" class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4 hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + job.triggerName" type="checkbox" disabled <input :id="'checkbox-table-search-' + job.triggerName" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<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 max-w-sm overflow-hidden text-ellipsis font-medium text-gray-900 whitespace-nowrap ">{{ <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[120px] sm:max-w-xs md: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-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[120px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden lg:table-cell">
{{
`${job.triggerName}:${job.triggerGroup}` }} `${job.triggerName}:${job.triggerGroup}` }}
</td> </td>
<td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 min-w-[150px] sm:min-w-3xs max-w-sm overflow-hidden text-ellipsis hidden lg:table-cell">
{{
dayjs(job.startTime!).format("llll") }} dayjs(job.startTime!).format("llll") }}
</td> </td>
<td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ job.endTime ? <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 min-w-[150px] sm:min-w-3xs max-w-sm overflow-hidden text-ellipsis hidden lg:table-cell">
{{ job.endTime ?
dayjs(job.endTime).format("llll") : undefined }}</td> dayjs(job.endTime).format("llll") : undefined }}</td>
<td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ job.nextFireTime ? <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 min-w-[150px] sm:min-w-3xs max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
{{ job.nextFireTime ?
dayjs(job.nextFireTime).format("llll") : undefined}}</td> dayjs(job.nextFireTime).format("llll") : undefined}}</td>
<td class="px-6 py-4 min-w-3xs max-w-sm overflow-hidden text-ellipsis">{{ job.previousFireTime && <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 min-w-[150px] sm:min-w-3xs max-w-sm overflow-hidden text-ellipsis hidden lg:table-cell">
{{ job.previousFireTime &&
job.previousFireTime job.previousFireTime
> 0 ? dayjs(job.previousFireTime).format("llll") : > 0 ? dayjs(job.previousFireTime).format("llll") :
undefined undefined
}} }}
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ job.schedulerType }}</td> <td
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ job.cronExpression }}</td> class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[80px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis">{{ job.triggerState }}</td> {{ job.schedulerType }}</td>
<td class="px-6 py-4 whitespace-nowrap"> <td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[100px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis hidden md:table-cell">
{{ job.cronExpression }}</td>
<td
class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 max-w-[80px] sm:max-w-xs md:max-w-sm overflow-hidden text-ellipsis">
{{ job.triggerState }}</td>
<td class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 whitespace-nowrap hidden sm:table-cell">
<div class="flex items-center gap-x-2"> <div class="flex items-center gap-x-2">
<button @click="handleCronUpdateClick(job)" :disabled="job.schedulerType !== 'CRON'" <button @click="handleCronUpdateClick(job)" :disabled="job.schedulerType !== 'CRON'"
:class="['flex items-center justify-center gap-x-1 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 ' , { 'opacity-50 cursor-not-allowed': job.schedulerType !== 'CRON' }]" :class="['flex items-center justify-center gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5' , { 'opacity-50 cursor-not-allowed': job.schedulerType !== 'CRON' }]"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
@@ -95,15 +113,15 @@
</button> </button>
</div> </div>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-3 py-2 sm:px-4 md:px-6 sm:py-4 whitespace-nowrap">
<div class="flex items-center justify-center gap-x-2"> <div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button <button
:class="['text-white bg-green-700 hover:bg-green-800 focus:ring-green-300 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 text-center']" :class="['text-white bg-green-700 hover:bg-green-800 focus:ring-green-300 focus:ring-4 focus:outline-none font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5 text-center']"
@click="handleResumeJobClick(job)" type="button"> @click="handleResumeJobClick(job)" type="button">
<span>恢复</span> <span>恢复</span>
</button> </button>
<button <button
:class="['bg-red-700 hover:bg-red-800 focus:ring-red-300 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 text-center']" :class="['bg-red-700 hover:bg-red-800 focus:ring-red-300 text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5 text-center']"
@click="handlePauseJobClick(job)" type="button"> @click="handlePauseJobClick(job)" type="button">
<span>暂停</span> <span>暂停</span>
</button> </button>

View File

@@ -1,53 +1,53 @@
<template> <template>
<div class="grid grid-cols-1 px-4 pt-6 xl:grid-cols-3 xl:gap-4 "> <div class="grid grid-cols-1 px-2 sm:px-4 pt-6 xl:grid-cols-3 xl:gap-4">
<div class="mb-4 col-span-full xl:mb-2"> <div class="mb-4 col-span-full xl:mb-2">
<Breadcrumbs :names="['用户设置']" /> <Breadcrumbs :names="['用户设置']" />
<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>
<!-- Right Content --> <!-- Right Content -->
<div class="col-span-full xl:col-auto"> <div class="col-span-full xl:col-auto">
<!-- Placeholder for potential right content -->
</div> </div>
<div class="col-span-1 row-start-3"> <div class="col-span-full xl:col-span-1 xl:row-start-2">
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 sm:p-6 "> <div class="p-4 sm:p-6 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm">
<h3 class="mb-4 text-xl font-semibold ">个人信息</h3> <h3 class="mb-4 text-xl font-semibold">个人信息</h3>
<form action="#"> <form action="#">
<div class="grid grid-cols-6 gap-6"> <div class="grid grid-cols-1 sm:grid-cols-6 gap-4 sm:gap-6">
<div class="col-span-6 "> <div class="col-span-1 sm:col-span-6">
<label for="current-username" class="block mb-2 text-sm font-medium text-gray-900 ">用户名</label> <label for="current-username" class="block mb-2 text-sm font-medium text-gray-900">用户名</label>
<input type="text" name="current-username" id="current-username" v-model="userForm.username" <input type="text" name="current-username" id="current-username" v-model="userForm.username"
class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 " class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5"
required> required>
</div> </div>
<div class="col-span-6 "> <div class="col-span-1 sm:col-span-6">
<label for="current-password" class="block mb-2 text-sm font-medium text-gray-900 ">密码</label> <label for="current-password" class="block mb-2 text-sm font-medium text-gray-900">密码</label>
<input type="password" name="current-password" id="current-password" v-model="userForm.password" <input type="password" name="current-password" id="current-password" v-model="userForm.password"
class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 " class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5"
placeholder="非必填" required> placeholder="非必填" required>
</div> </div>
<div class="col-span-6 "> <div class="col-span-1 sm:col-span-6">
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 ">确认密码</label> <label for="password" class="block mb-2 text-sm font-medium text-gray-900">确认密码</label>
<input type="password" id="password" v-model="userForm.confirmPassword" <input type="password" id="password" v-model="userForm.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 " 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"
placeholder="非必填" required> placeholder="非必填" required>
</div> </div>
<div class="col-span-6 "> <div class="col-span-1 sm:col-span-6">
<label for="category" class="block mb-2 text-sm font-medium text-gray-900 ">状态</label> <label for="category" class="block mb-2 text-sm font-medium text-gray-900">状态</label>
<select id="category" disabled v-model="userForm.enable" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 <select id="category" disabled v-model="userForm.enable" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5
opacity-50 cursor-not-allowed "> opacity-50 cursor-not-allowed">
<option :value=true>启用</option> <option :value=true>启用</option>
<option :value=false>禁用</option> <option :value=false>禁用</option>
</select> </select>
</div> </div>
<div class="col-span-6 sm:col-full"> <div class="col-span-1 sm:col-span-6">
<button <button
class="text-white bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center " class="text-white bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center w-full sm:w-auto"
@click.prevent="handleUpdateClick" type="submit">保存</button> @click.prevent="handleUpdateClick" type="submit">保存</button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1,111 +1,119 @@
<template> <template>
<div class="px-4 pt-6 xl:grid-cols-3 xl:gap-4 sm:rounded-lg "> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 col-span-full"> <div class="mb-4">
<Breadcrumbs :names="['用户管理']" /> <Breadcrumbs :names="['用户管理']" />
<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="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 gap-y-3 sm:gap-y-0">
<form class="max-w-xs mb-4 "> <form class="w-full sm:max-w-xs">
<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">
<svg class="w-4 h-4 text-gray-500 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" <svg class="w-4 h-4 text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg> </svg>
</div> </div>
<input type="search" id="default-search" v-model="username" <input type="search" id="default-search" v-model="username"
class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 " class="block w-full p-3 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
placeholder="用户名" required /> placeholder="用户名" required />
<button type="submit" <button type="submit"
class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 " class="text-white absolute end-1.5 bottom-1.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 sm:px-4 sm:py-2"
@click.prevent="handleSearch">搜索</button> @click.prevent="handleSearch">搜索</button>
</div> </div>
</form> </form>
<!-- Create Modal toggle --> <!-- Create Modal toggle -->
<button @click="handleUpsertUserClick(undefined)" <Button :handleClick="() => handleUpsertUserClick(undefined)" :isLoading="false" :abortable="false"
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" submitContent="新增用户" size="sm" class="w-full sm:w-auto">
type="button"> <template #icon>
新增用户 <svg class="w-4 h-4 me-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
</button> viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</template>
</Button>
</div> </div>
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right shadow-lg rounded-lg text-gray-500 "> <table class="w-full text-sm text-left rtl:text-right text-gray-500">
<thead class="text-xs uppercase bg-gray-50 "> <thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr> <tr>
<th scope="col" class="p-4"> <th scope="col" class="p-2 sm:p-4">
<div class="flex items-center"> <div class="flex items-center">
<input id="checkbox-all-search" disabled type="checkbox" <input id="checkbox-all-search" disabled type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label for="checkbox-all-search" class="sr-only">checkbox</label> <label for="checkbox-all-search" class="sr-only">checkbox</label>
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3 cursor-pointer" @click="handleSortClick('username')"> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3 cursor-pointer" @click="handleSortClick('username')">
<div class="flex items-center"> <div class="flex items-center">
<span>用户名</span> <span>用户名</span>
<SortIcon :sortField="getSortField('username')" /> <SortIcon :sortField="getSortField('username')" />
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3 cursor-pointer" @click="handleSortClick('createTime')"> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3 cursor-pointer hidden md:table-cell"
@click="handleSortClick('createTime')">
<div class="flex items-center"> <div class="flex items-center">
<span>创建时间</span> <span>创建时间</span>
<SortIcon :sortField="getSortField('createTime')" /> <SortIcon :sortField="getSortField('createTime')" />
</div> </div>
</th> </th>
<th scope="col" class="px-6 py-3">状态</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3 hidden sm:table-cell">状态</th>
<th scope="col" class="px-6 py-3">分配</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">分配</th>
<th scope="col" class="px-6 py-3">操作</th> <th scope="col" class="px-3 py-2 sm:px-6 sm:py-3">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="user in users" :key="user.id" class="bg-white border-b border-gray-200 hover:bg-gray-50 "> <tr v-for="user in users" :key="user.id" class="bg-white border-b border-gray-200 hover:bg-gray-50">
<td class="w-4 p-4"> <td class="w-4 p-2 sm:p-4">
<div class="flex items-center"> <div class="flex items-center">
<input :id="'checkbox-table-search-' + user.id" type="checkbox" disabled <input :id="'checkbox-table-search-' + user.id" type="checkbox" disabled
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2 "> class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 focus:ring-2">
<label :for="'checkbox-table-search-' + user.id" class="sr-only">checkbox</label> <label :for="'checkbox-table-search-' + user.id" class="sr-only">checkbox</label>
</div> </div>
</td> </td>
<td scope="row" <td scope="row"
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap max-w-sm overflow-hidden text-ellipsis"> class="px-3 py-2 sm:px-6 sm:py-4 font-medium text-gray-900 whitespace-nowrap max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
{{ user.username }} {{ user.username }}
</td> </td>
<td class="px-6 py-4 max-w-sm whitespace-nowrap overflow-hidden text-ellipsis"> <td
class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm whitespace-nowrap overflow-hidden text-ellipsis hidden md:table-cell">
{{ dayjs(user.createTime).format("llll") }} {{ dayjs(user.createTime).format("llll") }}
</td> </td>
<td class="px-6 py-4 max-w-sm whitespace-nowrap overflow-hidden text-ellipsis"> <td
class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm whitespace-nowrap overflow-hidden text-ellipsis hidden sm:table-cell">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="user.enable ? 'bg-blue-500' : 'bg-red-500'"></div> {{ <div class="h-2.5 w-2.5 rounded-full me-2" :class="user.enable ? 'bg-blue-500' : 'bg-red-500'"></div> {{
user.enable === true ? "启用" : "禁用" }} user.enable === true ? "启用" : "禁用" }}
</div> </div>
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<div class="flex items-center gap-x-2"> <div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button <button
class="text-gray-900 bg-white border whitespace-nowrap border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-4 py-2.5 " class="text-gray-900 bg-white border whitespace-nowrap border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
@click="handleBindRoleClick(user)" type="button"> @click="handleBindRoleClick(user)" type="button">
分配角色 分配角色
</button> </button>
<button <button
class="text-gray-900 bg-white border whitespace-nowrap border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-4 py-2.5 " class="text-gray-900 bg-white border whitespace-nowrap border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
@click="handleBindPositionClick(user)" type="button"> @click="handleBindPositionClick(user)" type="button">
分配岗位 分配岗位
</button> </button>
<button <button
class="text-gray-900 bg-white border whitespace-nowrap border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-4 py-2.5 " class="text-gray-900 bg-white border whitespace-nowrap border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
@click="handleBindDepartmentClick(user)" type="button"> @click="handleBindDepartmentClick(user)" type="button">
分配部门 分配部门
</button> </button>
</div> </div>
</td> </td>
<td class="px-6 py-4 max-w-sm overflow-hidden text-ellipsis"> <td class="px-3 py-2 sm:px-6 sm:py-4 max-w-xs sm:max-w-sm overflow-hidden text-ellipsis">
<!-- Edit Modal toggle --> <!-- Edit Modal toggle -->
<div class="flex items-center gap-x-2"> <div class="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-y-0 sm:gap-x-2">
<button @click="handleUpsertUserClick(user)" <button @click="handleUpsertUserClick(user)"
class="flex items-center justify-center whitespace-nowrap gap-x-1 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-4 py-2.5 " class="flex items-center justify-center whitespace-nowrap gap-x-1 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
type="button"> type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path>
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
@@ -113,11 +121,13 @@
</svg> </svg>
<span>编辑</span> <span>编辑</span>
</button> </button>
<button class="flex items-center justify-center whitespace-nowrap gap-x-1 <button
bg-red-700 hover:bg-red-800 focus:ring-red-300 class="flex items-center justify-center whitespace-nowrap gap-x-1
text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-4 py-2.5" bg-red-700 hover:bg-red-800 focus:ring-red-300
text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-xs sm:text-sm px-3 py-1.5 sm:px-4 sm:py-2.5"
@click="handleDeleteUserClick(user)" type="button"> @click="handleDeleteUserClick(user)" type="button">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg class="w-3 h-3 sm:w-4 sm:h-4" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" <path fill-rule="evenodd"
d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
clip-rule="evenodd"></path> clip-rule="evenodd"></path>
@@ -144,6 +154,7 @@
<script setup lang="ts"> <script setup lang="ts">
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import Button from "@/components/Button.vue";
import UserDeleteModal from "@/components/PopupModal.vue"; import UserDeleteModal from "@/components/PopupModal.vue";
import SortIcon from "@/components/SortIcon.vue"; import SortIcon from "@/components/SortIcon.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";