mirror of
https://github.com/HuLaSpark/HuLa.git
synced 2026-09-01 14:52:48 +08:00
🌻 update(custom): 更新登录页面和多窗口的样式
This commit is contained in:
@@ -2,7 +2,7 @@ use tauri::{Manager, Runtime};
|
||||
use window_shadows::set_shadow;
|
||||
|
||||
pub fn set_window_shadow<R: Runtime>(app: &tauri::App<R>) {
|
||||
let window = app.get_window("home").unwrap();
|
||||
|
||||
set_shadow(&window, true).expect("Unsupported platform!");
|
||||
}
|
||||
for (_, window) in app.windows() {
|
||||
set_shadow(&window, true).expect("Failed to set window shadow");
|
||||
}
|
||||
}
|
||||
@@ -44,15 +44,16 @@
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"label": "home",
|
||||
"label": "login",
|
||||
"url": "/login",
|
||||
"fullscreen": false,
|
||||
"resizable": true,
|
||||
"center": true,
|
||||
"title": "hula-im-tauri",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"width": 320,
|
||||
"height": 448,
|
||||
"skipTaskbar": false,
|
||||
"decorations": false
|
||||
"decorations": false,
|
||||
"transparent":true
|
||||
}
|
||||
],
|
||||
"systemTray": {
|
||||
|
||||
+25
-25
@@ -1,38 +1,37 @@
|
||||
<template>
|
||||
<NaiveProvider :message-max="3" :notific-max="3">
|
||||
<div id="app">
|
||||
<Home />
|
||||
<div class="container" style="transform: scale(1.1)">
|
||||
<ContextMenu
|
||||
class="block"
|
||||
:menu="[{ label: '添加' }, { label: '编辑' }, { label: '删除' }, { label: '查看' }, { label: '复制' }]"
|
||||
@select="choose1 = $event.label">
|
||||
<h2>{{ choose1 }}</h2>
|
||||
</ContextMenu>
|
||||
<ContextMenu
|
||||
class="block"
|
||||
:menu="[{ label: '员工' }, { label: '部门' }, { label: '角色' }, { label: '权限' }, { label: '菜单' }]"
|
||||
@select="choose2 = $event.label">
|
||||
<h2>{{ choose2 }}</h2>
|
||||
<ContextMenu
|
||||
class="block"
|
||||
:menu="[{ label: '菜单1' }, { label: '菜单2' }, { label: '菜单3' }, { label: '菜单4' }]"
|
||||
@select="choose3 = $event.label">
|
||||
<h2>{{ choose3 }}</h2>
|
||||
</ContextMenu>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
<router-view />
|
||||
<!-- <div class="container" style="transform: scale(1.1)">-->
|
||||
<!-- <ContextMenu-->
|
||||
<!-- class="block"-->
|
||||
<!-- :menu="[{ label: '添加' }, { label: '编辑' }, { label: '删除' }, { label: '查看' }, { label: '复制' }]"-->
|
||||
<!-- @select="choose1 = $event.label">-->
|
||||
<!-- <h2>{{ choose1 }}</h2>-->
|
||||
<!-- </ContextMenu>-->
|
||||
<!-- <ContextMenu-->
|
||||
<!-- class="block"-->
|
||||
<!-- :menu="[{ label: '员工' }, { label: '部门' }, { label: '角色' }, { label: '权限' }, { label: '菜单' }]"-->
|
||||
<!-- @select="choose2 = $event.label">-->
|
||||
<!-- <h2>{{ choose2 }}</h2>-->
|
||||
<!-- <ContextMenu-->
|
||||
<!-- class="block"-->
|
||||
<!-- :menu="[{ label: '菜单1' }, { label: '菜单2' }, { label: '菜单3' }, { label: '菜单4' }]"-->
|
||||
<!-- @select="choose3 = $event.label">-->
|
||||
<!-- <h2>{{ choose3 }}</h2>-->
|
||||
<!-- </ContextMenu>-->
|
||||
<!-- </ContextMenu>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</NaiveProvider>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { theme } from '@/stores/theme.ts'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import Home from '@/views/page/Home.vue'
|
||||
|
||||
const choose1 = ref('')
|
||||
const choose2 = ref('')
|
||||
const choose3 = ref('')
|
||||
// const choose1 = ref('')
|
||||
// const choose2 = ref('')
|
||||
// const choose3 = ref('')
|
||||
const themeStore = theme()
|
||||
const { BGC } = storeToRefs(themeStore)
|
||||
</script>
|
||||
@@ -48,6 +47,7 @@ const { BGC } = storeToRefs(themeStore)
|
||||
left: 0;
|
||||
transition: all 0.9s ease;
|
||||
background-color: v-bind(BGC);
|
||||
border-radius: 10px;
|
||||
}
|
||||
.container {
|
||||
display: grid;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="resizable" :style="{ width: width + 'px', backgroundColor: '#4db652' }">
|
||||
中间区域
|
||||
<div class="resize-handle" @mousedown="initDrag"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const minWidth = 160 // 设置最小宽度
|
||||
const maxWidth = 320 // 设置最大宽度
|
||||
const width = ref(240) // 初始化宽度
|
||||
|
||||
const startX = ref()
|
||||
const startWidth = ref()
|
||||
|
||||
const initDrag = (e: MouseEvent) => {
|
||||
startX.value = e.clientX
|
||||
startWidth.value = width.value
|
||||
|
||||
document.addEventListener('mousemove', doDrag, false)
|
||||
document.addEventListener('mouseup', stopDrag, false)
|
||||
}
|
||||
|
||||
const doDrag = (e: MouseEvent) => {
|
||||
const newWidth = startWidth.value + e.clientX - startX.value
|
||||
if (newWidth <= maxWidth && newWidth >= minWidth) {
|
||||
width.value = newWidth
|
||||
} else if (newWidth > maxWidth) {
|
||||
width.value = maxWidth
|
||||
} else if (newWidth < minWidth) {
|
||||
width.value = minWidth
|
||||
}
|
||||
}
|
||||
|
||||
const stopDrag = () => {
|
||||
document.removeEventListener('mousemove', doDrag, false)
|
||||
document.removeEventListener('mouseup', stopDrag, false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resizable {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.resize-handle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
cursor: ew-resize;
|
||||
background-color: #ccc; /* 可以根据需要更改颜色 */
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="flex wh-full">
|
||||
<Left />
|
||||
<Center />
|
||||
<Right />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Center from '@/layout/center/index.vue'
|
||||
import Left from '@/layout/left/index.vue'
|
||||
import Right from '@/layout/right/index.vue'
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div
|
||||
class="w-60px bg-#AA5757FF h-full pt-10px pl-8px pr-8px pb-10px box-border flex justify-center rounded-tl-8px rounded-bl-8px">
|
||||
<img class="border-rounded-50% bg-#000 w-34px h-34px" src="" alt="" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="flex-1 bg-[#f1f1f1ff] h-full rounded-tr-8px rounded-br-8px w-100vw">
|
||||
<div data-tauri-drag-region class="flex justify-end">
|
||||
<div
|
||||
id="titlebar-close"
|
||||
class="w-28px h24px flex-center cursor-pointer color-#606060 hover:bg-#c22b1c hover:color-#fff rounded-tr-6px">
|
||||
X
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
|
||||
onMounted(() => {
|
||||
// document.getElementById('titlebar-minimize')!.addEventListener('click', () => appWindow.minimize())
|
||||
// document.getElementById('titlebar-maximize')!.addEventListener('click', () => appWindow.toggleMaximize())
|
||||
document.getElementById('titlebar-close')!.addEventListener('click', () => appWindow.close())
|
||||
console.log('onMounted------', document.getElementById('titlebar-close'))
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
+2
-1
@@ -2,9 +2,10 @@ import { createApp } from 'vue'
|
||||
import 'uno.css'
|
||||
import '@unocss/reset/eric-meyer.css' // unocss提供的浏览器默认样式重置
|
||||
import { pinia } from '@/stores'
|
||||
import router from '@/router'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import App from '@/App.vue'
|
||||
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
const app = createApp(App)
|
||||
app.use(pinia).mount('#app')
|
||||
app.use(router).use(pinia).mount('#app')
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
||||
|
||||
// const modules = import.meta.glob('../views/page/*.vue')
|
||||
const { VITE_APP_TITLE, VITE_TITLE_SUFFIX, BASE_URL } = import.meta.env
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/page/Login.vue')
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'page',
|
||||
component: () => import('@/layout/index.vue')
|
||||
}
|
||||
]
|
||||
|
||||
// 创建路由
|
||||
const router: any = createRouter({
|
||||
history: createWebHistory(BASE_URL),
|
||||
routes
|
||||
})
|
||||
|
||||
// 注意:刷新页面会导致页面路由重置
|
||||
// export const setRoutes = (menus?: MenuItem[]) => {
|
||||
// if (!menus || !menus.length) {
|
||||
// const manager = localStorage.getItem('localUserInfo')
|
||||
// if (!manager) {
|
||||
// return
|
||||
// }
|
||||
// menus = JSON.parse(manager).loginInfo.menus
|
||||
// }
|
||||
// if (menus?.length) {
|
||||
// /**
|
||||
// * 动态添加路由
|
||||
// * @param routeItem
|
||||
// */
|
||||
// const addDynamicRoute = (routeItem: MenuItem) => {
|
||||
// if (routeItem.page) {
|
||||
// /*添加views文件夹中page文件下面的全部.vue文件*/
|
||||
// router.addRoute('page', {
|
||||
// path: routeItem.path,
|
||||
// name: routeItem.page,
|
||||
// meta: { title: routeItem.name, icon: routeItem.icon, requiresAuth: true, dynamicAdded: true },
|
||||
// component: () => import(`@/views/page/${routeItem.page}.vue`)
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// menus.forEach((item) => {
|
||||
// addDynamicRoute(item)
|
||||
// if (item.children && item.children.length) {
|
||||
// item.children.forEach((sub) => {
|
||||
// addDynamicRoute(sub)
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// setRoutes()
|
||||
|
||||
//重置路由的方法
|
||||
export const resetRouter = () => {
|
||||
// 获得当前路由器所有的路由记录
|
||||
const currentRoutes = router.getRoutes()
|
||||
// 过滤出动态添加的路由记录
|
||||
currentRoutes.forEach((route: any) => {
|
||||
if (route.meta && route.meta.dynamicAdded) {
|
||||
router.removeRoute(route.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 路由前置守卫
|
||||
router.beforeEach(async (to: any, _from: any, next: any) => {
|
||||
/*设置页面标题和标题后缀*/
|
||||
document.title = to.meta.title ? to.meta.title + VITE_TITLE_SUFFIX : VITE_APP_TITLE
|
||||
// 如果要访问的路径不存在(没有匹配的路由记录)
|
||||
if (!to.matched.length) {
|
||||
return next('/:catchAll(.*)') // 重定向到捕获所有路径的路由
|
||||
}
|
||||
// 其他情况,继续路由导航
|
||||
next()
|
||||
})
|
||||
|
||||
export default router
|
||||
Vendored
+51
-1
@@ -1,6 +1,56 @@
|
||||
/// <reference types="vite/client" />
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_BASE_URL: string
|
||||
/** 后端项目地址 */
|
||||
readonly VITE_SERVICE_URL: string
|
||||
/** 项目名称 */
|
||||
readonly VITE_APP_NAME: string
|
||||
/** 项目标题 */
|
||||
readonly VITE_APP_TITLE: string
|
||||
/** 页面标题后缀*/
|
||||
readonly VITE_TITLE_SUFFIX: string
|
||||
/** 项目ICP备案号 */
|
||||
readonly VITE_APP_ICP: string
|
||||
/** 项目描述 */
|
||||
readonly VITE_APP_DESC: string
|
||||
/** 后端服务的环境类型 */
|
||||
readonly VITE_SERVICE_ENV?: ServiceEnvType
|
||||
/**
|
||||
* 权限路由模式:
|
||||
* - static - 前端声明的静态
|
||||
* - dynamic - 后端返回的动态
|
||||
*/
|
||||
readonly VITE_AUTH_ROUTE_MODE: 'static' | 'dynamic'
|
||||
/** 路由首页的路径 */
|
||||
readonly VITE_ROUTE_HOME_PATH: AuthRoute.RoutePath
|
||||
/** iconify图标作为组件的前缀 */
|
||||
readonly VITE_ICON_PREFIX: string
|
||||
/**
|
||||
* 本地SVG图标作为组件的前缀, 请注意一定要包含 VITE_ICON_PREFIX
|
||||
* - 格式 {VITE_ICON_PREFIX}-{本地图标集合名称}
|
||||
* - 例如:icon-local
|
||||
*/
|
||||
readonly VITE_ICON_LOCAL_PREFIX: string
|
||||
/** 开启请求代理 */
|
||||
readonly VITE_HTTP_PROXY?: 'Y' | 'N'
|
||||
/** 是否开启打包文件大小结果分析 */
|
||||
readonly VITE_VISUALIZER?: 'Y' | 'N'
|
||||
/** 是否开启打包压缩 */
|
||||
readonly VITE_COMPRESS?: 'Y' | 'N'
|
||||
/** 压缩算法类型 */
|
||||
readonly VITE_COMPRESS_TYPE?: 'gzip' | 'brotliCompress' | 'deflate' | 'deflateRaw'
|
||||
/** 是否应用pwa */
|
||||
readonly VITE_PWA?: 'Y' | 'N'
|
||||
/**
|
||||
* 是否开启生产模式下的mock
|
||||
* @description 生产模式下会拦截XHR,导致无法获取response,不使用mock请求时设置为N
|
||||
*/
|
||||
readonly VITE_PROD_MOCK?: 'Y' | 'N'
|
||||
/** hash路由模式 */
|
||||
readonly VITE_HASH_ROUTE?: 'Y' | 'N'
|
||||
/** 是否应用自动生成路由的插件 */
|
||||
readonly VITE_SOYBEAN_ROUTE_PLUGIN?: 'Y' | 'N'
|
||||
/** 是否是部署的vercel */
|
||||
readonly VITE_VERCEL?: 'Y' | 'N'
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
||||
@@ -8,14 +8,9 @@
|
||||
</n-space>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
// import { invoke } from "@tauri-apps/api/tauri";
|
||||
const name = ref('')
|
||||
|
||||
const dj = () => {
|
||||
window.$message.success(name.value)
|
||||
}
|
||||
|
||||
// async function greet() {
|
||||
// greetMsg.value = await invoke("greet", { name: name.value });
|
||||
// }
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="flex-center h-full">
|
||||
<n-button @click="loginWin" secondary type="primary">登录</n-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { WebviewWindow } from '@tauri-apps/api/window'
|
||||
|
||||
let close = (label: string) => {
|
||||
const win = WebviewWindow.getByLabel(label)
|
||||
win?.close()
|
||||
}
|
||||
|
||||
let loginWin = async () => {
|
||||
const webview = new WebviewWindow('page', {
|
||||
url: '/',
|
||||
fullscreen: false,
|
||||
resizable: true,
|
||||
center: true,
|
||||
width: 1050,
|
||||
height: 720,
|
||||
skipTaskbar: false,
|
||||
decorations: false,
|
||||
transparent: true
|
||||
})
|
||||
await webview.once('tauri://created', function () {
|
||||
console.log('创建成功')
|
||||
close('login')
|
||||
})
|
||||
await webview.once('tauri://error', function (e) {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user