mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-04-06 21:37:35 +00:00
v2
This commit is contained in:
@@ -1,7 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="[
|
||||||
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"
|
'fixed top-0 right-0 h-full z-50 bg-white shadow-lg transform transition-transform duration-300 ease-in-out',
|
||||||
ref="chatContainer">
|
'flex flex-col box-border overflow-y-auto w-full sm:w-96',
|
||||||
|
isVisible ? 'translate-x-0' : 'translate-x-full'
|
||||||
|
]" ref="chatContainer">
|
||||||
|
<div class="flex items-center justify-between p-3 border-b">
|
||||||
|
<h2 class="text-lg font-semibold text-gray-900">助手</h2>
|
||||||
|
<button @click="closeAssistant" class="text-gray-500 hover:text-gray-700">
|
||||||
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<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"
|
||||||
:class="['flex items-start gap-2.5', chatElement.isUser ? 'flex-row-reverse max-w-full break-words' : 'flex-row']">
|
:class="['flex items-start gap-2.5', chatElement.isUser ? 'flex-row-reverse max-w-full break-words' : 'flex-row']">
|
||||||
@@ -319,6 +329,16 @@ onMounted(async () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
isVisible: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const closeAssistant = () => {
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="css">
|
<style lang="css">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<button :disabled="disabled" @click="handleClick" type="button" :class="[
|
<button :disabled="disabled" @click="handleClick" type="button" :class="[
|
||||||
'text-white',
|
'text-white',
|
||||||
'focus:ring-4',
|
'focus:ring-4',
|
||||||
'focus:outline-none',
|
'focus:outline-none',
|
||||||
@@ -12,18 +12,20 @@
|
|||||||
isLoading && !abortable ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-700 hover:bg-blue-800',
|
isLoading && !abortable ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-700 hover:bg-blue-800',
|
||||||
sizeClasses
|
sizeClasses
|
||||||
]">
|
]">
|
||||||
<LoadingIcon v-if="isLoading && !abortable" :class="iconSizeClasses" />
|
<LoadingIcon v-if="isLoading && !abortable" :class="[iconSizeClasses, iconOnly ? '' : 'me-2']" />
|
||||||
<StopIcon v-else-if="isLoading && abortable" :class="iconSizeClasses" />
|
<StopIcon v-else-if="isLoading && abortable" :class="[iconSizeClasses, iconOnly ? '' : 'me-2']" />
|
||||||
<span v-if="iconOnly && isLoading" class="sr-only">{{ loadingContent }}</span>
|
<slot v-else-if="!isLoading && $slots.icon" name="icon" :iconSizeClasses="iconSizeClasses"></slot>
|
||||||
<span v-else-if="iconOnly && !isLoading" class="sr-only">{{ submitContent }}</span>
|
|
||||||
<template v-else>
|
<span v-if="iconOnly && isLoading" class="sr-only">{{ loadingContent }}</span>
|
||||||
{{ isLoading ? loadingContent : submitContent }}
|
<span v-else-if="iconOnly && !isLoading && !$slots.icon" class="sr-only">{{ submitContent }}</span>
|
||||||
</template>
|
<template v-else-if="!iconOnly">
|
||||||
</button>
|
{{ 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";
|
||||||
|
|
||||||
@@ -37,8 +39,10 @@ const props = defineProps<{
|
|||||||
iconOnly?: boolean;
|
iconOnly?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const slots = useSlots();
|
||||||
|
|
||||||
const sizeClasses = computed(() => {
|
const sizeClasses = computed(() => {
|
||||||
if (props.iconOnly) {
|
if (props.iconOnly && slots.icon) {
|
||||||
switch (props.size) {
|
switch (props.size) {
|
||||||
case 'xs': return 'p-1.5';
|
case 'xs': return 'p-1.5';
|
||||||
case 'sm': return 'p-2';
|
case 'sm': return 'p-2';
|
||||||
@@ -60,11 +64,11 @@ const sizeClasses = computed(() => {
|
|||||||
const iconSizeClasses = computed(() => {
|
const iconSizeClasses = computed(() => {
|
||||||
switch (props.size) {
|
switch (props.size) {
|
||||||
case 'xs': return 'w-3 h-3';
|
case 'xs': return 'w-3 h-3';
|
||||||
case 'sm': return 'w-3.5 h-3.5';
|
case 'sm': return 'w-4 h-4';
|
||||||
case 'lg': return 'w-5 h-5';
|
case 'lg': return 'w-5 h-5';
|
||||||
case 'xl': return 'w-6 h-6';
|
case 'xl': return 'w-6 h-6';
|
||||||
default:
|
default:
|
||||||
return 'w-4 h-4';
|
return 'w-5 h-5';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<Headbar :changeAssistantVisible="changeAssistantVisible"></Headbar>
|
<Headbar :changeAssistantVisible="changeAssistantVisible"></Headbar>
|
||||||
<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 sm: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 is now fixed positioned and controlled by isAssistantVisible -->
|
||||||
</div>
|
</div>
|
||||||
|
<Assistant :isVisible="isAssistantVisible" @close="changeAssistantVisible"></Assistant>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -23,11 +23,15 @@
|
|||||||
@click.prevent="handleSearch">搜索</button>
|
@click.prevent="handleSearch">搜索</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<button @click="handleUpsertDepartmentClick()"
|
<Button :handleClick="() => handleUpsertDepartmentClick()" :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"
|
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 shadow-md sm:rounded-lg">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500">
|
<table class="w-full text-sm text-left rtl:text-right text-gray-500">
|
||||||
@@ -108,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";
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<!-- Create Modal toggle -->
|
<!-- Create Modal toggle -->
|
||||||
<button @click="handleUpsertPositionClick()"
|
<Button :handleClick="() => handleUpsertPositionClick()" :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"
|
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 shadow-md sm:rounded-lg">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||||
@@ -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";
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
</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 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"
|
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 shadow-md sm:rounded-lg">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500">
|
<table class="w-full text-sm text-left rtl:text-right text-gray-500">
|
||||||
@@ -116,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";
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
</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"
|
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 shadow-md sm:rounded-lg">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500">
|
<table class="w-full text-sm text-left rtl:text-right text-gray-500">
|
||||||
@@ -150,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";
|
||||||
|
|||||||
Reference in New Issue
Block a user