mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-03-13 21:27:19 +08:00
v2
This commit is contained in:
@@ -1,7 +1,17 @@
|
||||
<template>
|
||||
<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"
|
||||
ref="chatContainer">
|
||||
<div :class="[
|
||||
'fixed top-0 right-0 h-full z-50 bg-white shadow-lg transform transition-transform duration-300 ease-in-out',
|
||||
'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">
|
||||
<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']">
|
||||
@@ -319,6 +329,16 @@ onMounted(async () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
isVisible: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const closeAssistant = () => {
|
||||
emit('close');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<button :disabled="disabled" @click="handleClick" type="button" :class="[
|
||||
<button :disabled="disabled" @click="handleClick" type="button" :class="[
|
||||
'text-white',
|
||||
'focus:ring-4',
|
||||
'focus:outline-none',
|
||||
@@ -12,18 +12,20 @@
|
||||
isLoading && !abortable ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-700 hover:bg-blue-800',
|
||||
sizeClasses
|
||||
]">
|
||||
<LoadingIcon v-if="isLoading && !abortable" :class="iconSizeClasses" />
|
||||
<StopIcon v-else-if="isLoading && abortable" :class="iconSizeClasses" />
|
||||
<span v-if="iconOnly && isLoading" class="sr-only">{{ loadingContent }}</span>
|
||||
<span v-else-if="iconOnly && !isLoading" class="sr-only">{{ submitContent }}</span>
|
||||
<template v-else>
|
||||
{{ isLoading ? loadingContent : submitContent }}
|
||||
</template>
|
||||
</button>
|
||||
<LoadingIcon v-if="isLoading && !abortable" :class="[iconSizeClasses, iconOnly ? '' : 'me-2']" />
|
||||
<StopIcon v-else-if="isLoading && abortable" :class="[iconSizeClasses, iconOnly ? '' : 'me-2']" />
|
||||
<slot v-else-if="!isLoading && $slots.icon" name="icon" :iconSizeClasses="iconSizeClasses"></slot>
|
||||
|
||||
<span v-if="iconOnly && isLoading" class="sr-only">{{ loadingContent }}</span>
|
||||
<span v-else-if="iconOnly && !isLoading && !$slots.icon" class="sr-only">{{ submitContent }}</span>
|
||||
<template v-else-if="!iconOnly">
|
||||
{{ isLoading ? loadingContent : submitContent }}
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { computed, useSlots } from "vue";
|
||||
import LoadingIcon from "./icons/LoadingIcon.vue";
|
||||
import StopIcon from "./icons/StopIcon.vue";
|
||||
|
||||
@@ -37,8 +39,10 @@ const props = defineProps<{
|
||||
iconOnly?: boolean;
|
||||
}>();
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
const sizeClasses = computed(() => {
|
||||
if (props.iconOnly) {
|
||||
if (props.iconOnly && slots.icon) {
|
||||
switch (props.size) {
|
||||
case 'xs': return 'p-1.5';
|
||||
case 'sm': return 'p-2';
|
||||
@@ -60,11 +64,11 @@ const sizeClasses = computed(() => {
|
||||
const iconSizeClasses = computed(() => {
|
||||
switch (props.size) {
|
||||
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 'xl': return 'w-6 h-6';
|
||||
default:
|
||||
return 'w-4 h-4';
|
||||
return 'w-5 h-5';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<Headbar :changeAssistantVisible="changeAssistantVisible"></Headbar>
|
||||
<Sidebar>
|
||||
</Sidebar>
|
||||
<Sidebar />
|
||||
<div class="flex flex-row h-[calc(100vh-3.5rem)] mt-14">
|
||||
<article class="flex-1 sm:ml-44 overflow-y-auto">
|
||||
<RouterView></RouterView>
|
||||
</article>
|
||||
<Assistant v-if="isAssistantVisible"></Assistant>
|
||||
<!-- Assistant is now fixed positioned and controlled by isAssistantVisible -->
|
||||
</div>
|
||||
|
||||
<Assistant :isVisible="isAssistantVisible" @close="changeAssistantVisible"></Assistant>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<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 "
|
||||
aria-label="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"
|
||||
aria-label="Sidebar" tabindex="-1" data-drawer-backdrop="true">
|
||||
<div class="h-full px-3 pb-4 overflow-y-auto bg-white ">
|
||||
<ul class="space-y-2 font-medium">
|
||||
<li v-for="item in menuItems" :key="item.path">
|
||||
|
||||
@@ -23,11 +23,15 @@
|
||||
@click.prevent="handleSearch">搜索</button>
|
||||
</div>
|
||||
</form>
|
||||
<button @click="handleUpsertDepartmentClick()"
|
||||
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"
|
||||
type="button">
|
||||
新增部门
|
||||
</button>
|
||||
<Button :handleClick="() => handleUpsertDepartmentClick()" :isLoading="false" :abortable="false"
|
||||
submitContent="新增部门" size="sm" class="w-full sm:w-auto">
|
||||
<template #icon>
|
||||
<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">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
<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">
|
||||
@@ -108,6 +112,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import Button from "@/components/Button.vue";
|
||||
import DepartmentUpsertModal from "@/components/DepartmentUpsertModal.vue";
|
||||
import DepartmentDeleteModal from "@/components/PopupModal.vue";
|
||||
import TablePagination from "@/components/TablePagination.vue";
|
||||
|
||||
@@ -24,11 +24,15 @@
|
||||
</div>
|
||||
</form>
|
||||
<!-- Create Modal toggle -->
|
||||
<button @click="handleUpsertPositionClick()"
|
||||
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"
|
||||
type="button">
|
||||
新增岗位
|
||||
</button>
|
||||
<Button :handleClick="() => handleUpsertPositionClick()" :isLoading="false" :abortable="false"
|
||||
submitContent="新增岗位" size="sm" class="w-full sm:w-auto">
|
||||
<template #icon>
|
||||
<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">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||
@@ -105,6 +109,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import Button from "@/components/Button.vue";
|
||||
import PositionDeleteModal from "@/components/PopupModal.vue";
|
||||
import PositionUpsertModal from "@/components/PositionUpsertModal.vue";
|
||||
import TablePagination from "@/components/TablePagination.vue";
|
||||
|
||||
@@ -24,11 +24,15 @@
|
||||
</div>
|
||||
</form>
|
||||
<!-- Create Modal toggle -->
|
||||
<button @click="handleUpsertRoleClick(undefined)"
|
||||
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"
|
||||
type="button">
|
||||
新增角色
|
||||
</button>
|
||||
<Button :handleClick="() => handleUpsertRoleClick(undefined)" :isLoading="false" :abortable="false"
|
||||
submitContent="新增角色" size="sm" class="w-full sm:w-auto">
|
||||
<template #icon>
|
||||
<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">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
<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">
|
||||
@@ -116,6 +120,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import Button from "@/components/Button.vue";
|
||||
import RoleDeleteModal from "@/components/PopupModal.vue";
|
||||
import RoleUpsertModal from "@/components/RoleUpsertModal.vue";
|
||||
import TablePagination from "@/components/TablePagination.vue";
|
||||
|
||||
@@ -24,11 +24,15 @@
|
||||
</div>
|
||||
</form>
|
||||
<!-- Create Modal toggle -->
|
||||
<button @click="handleUpsertUserClick(undefined)"
|
||||
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"
|
||||
type="button">
|
||||
新增用户
|
||||
</button>
|
||||
<Button :handleClick="() => handleUpsertUserClick(undefined)" :isLoading="false" :abortable="false"
|
||||
submitContent="新增用户" size="sm" class="w-full sm:w-auto">
|
||||
<template #icon>
|
||||
<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">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
<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">
|
||||
@@ -150,6 +154,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import Button from "@/components/Button.vue";
|
||||
import UserDeleteModal from "@/components/PopupModal.vue";
|
||||
import SortIcon from "@/components/SortIcon.vue";
|
||||
import TablePagination from "@/components/TablePagination.vue";
|
||||
|
||||
Reference in New Issue
Block a user