xy 2 years ago
parent bbbe403277
commit 3e7868ff70

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -1,8 +1,8 @@
{
"name": "electron-vue-admin",
"name": "sqhj-workbench-pc",
"version": "0.0.1",
"author": "sky <https://github.com/umbrella22>",
"description": "An electron-vue project",
"author": "langye",
"description": "sqhj-workbench-pc",
"license": "MIT",
"main": "./dist/electron/main.js",
"scripts": {
@ -27,8 +27,12 @@
"url": "http://127.0.0.1"
}
],
"productName": "electron-vue-admin",
"appId": "org.Sky.electron-vue",
"productName": "内控信息化系统",
"appId": "org.langye.sqhj-workbench-pc",
"nsis": {
"guid": "org.langye.sqhj-workbench-pc",
"include": "build/installer.nsh"
},
"directories": {
"output": "build"
},

@ -14,5 +14,6 @@ if (process.env.NODE_ENV !== 'development') {
export const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:${process.env.PORT}` : `file://${__dirname}/index.html`
export const loadingURL = process.env.NODE_ENV === 'development' ? `http://localhost:${process.env.PORT}/static/loader.html` : `file://${__static}/loader.html`
export const libPath = process.env.libPath
export const adminWebUri = process.env.NODE_ENV === 'development' ? "http://contract-sqhj-test.ali251.langye.net/admin_test/#/" : "http://contract-sqhj.ali251.langye.net/admin/#/"
export const remindURL = 'development' ? `http://localhost:${process.env.PORT}/#/remind` : `file://${__dirname}/index.html/#/remind`
//export const adminWebUri = process.env.NODE_ENV === 'development' ? "http://contract-sqhj-test.ali251.langye.net/admin_test/#/" : "http://contract-sqhj.ali251.langye.net/admin/#/"
export const adminWebUri = "http://contract-sqhj-test.ali251.langye.net/admin_test/#/"

@ -9,10 +9,6 @@ const menu = [
label: '快速重启',
accelerator: 'F5',
role: 'reload'
}, {
label: '退出',
accelerator: 'CmdOrCtrl+F4',
role: 'close'
}]
},
{
@ -54,6 +50,14 @@ const menu = [
info()
}
}]
},
{
type: "separator"
},
{
label: '退出',
accelerator: 'CmdOrCtrl+F4',
role: 'close'
}]
function info() {
dialog.showMessageBox({

@ -1,12 +1,14 @@
'use strict'
import { app } from 'electron'
import { initWindow } from './services/windowManager'
import { initWindow, initTrayIcon, tray } from './services/windowManager'
import DisableButton from './config/DisableButton'
import electronDevtoolsInstaller, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import { init } from "./services/notices"
function onAppReady () {
initWindow()
initTrayIcon()
init()
DisableButton.Disablef12()
if (process.env.NODE_ENV === 'development') {
electronDevtoolsInstaller(VUEJS_DEVTOOLS)
@ -24,6 +26,9 @@ app.isReady() ? onAppReady() : app.on('ready', onAppReady)
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
tray.destroy();
}
// 所有平台均为所有窗口关闭就退出软件
app.quit()
})

@ -4,11 +4,53 @@ import { winURL } from '../config/StaticPath'
import downloadFile from './downloadFile'
import Update from './checkupdate'
import { updater } from './HotUpdater'
import { createAdminWindow, toggleMainWindowResizable, mainWindowResize } from "./windowManager"
import { createNotification } from "./notices"
import {
createAdminWindow,
toggleMainWindowResizable,
mainWindowResize,
setAdminViewBounds,
hideAdminView,
adminView,
setAdminCookie,
setTrayTitle,
destroyAdminView,
createAdminView,
remindWindow
} from "./windowManager"
export default {
Mainfunc(IsUseSysTitle) {
const allUpdater = new Update();
ipcMain.handle('create-notice', async (event, args) => {
const { title,body } = args
createNotification(title,body)
})
ipcMain.handle('remind-win-toggle', async (event,status) => {
status ? remindWindow.show() : remindWindow.hide()
})
ipcMain.handle("set-tray-title",async (event, title) => {
setTrayTitle(title)
})
ipcMain.handle('set-admin-cookie', async (event, _) => {
setAdminCookie()
})
ipcMain.handle('exec-admin-view-js',(event, js) => {
adminView?.webContents.executeJavaScript(js,true)
})
ipcMain.handle('create-admin-view',async (event, _) => {
await createAdminView()
})
ipcMain.handle('destroy-admin-view', async (event, _) => {
await destroyAdminView()
})
ipcMain.handle('hide-admin-view', async (event, _) => {
await hideAdminView()
})
ipcMain.handle('set-admin-view-bounds', (event, args) => {
const { x,y,width,height } = args
setAdminViewBounds(x,y,width,height)
})
ipcMain.handle('main-window-resize', (event, arg) => {
mainWindowResize(arg.width, arg.height)
})

@ -1,4 +1,16 @@
import { Notification } from "electron";
let notification = null;
export function init () {
notification = new Notification()
}
export function createNotification(title,body) {
if (Notification.isSupported()) {
notification.title = title;
notification.body = body;
notification.silent=true
notification.show();
} else {
console.log('notification 不支持')
}
}

@ -1,21 +1,84 @@
import { BrowserWindow, Menu, app, session } from 'electron'
import { BrowserWindow, Menu, app, session, BrowserView, Tray, screen } from 'electron'
import { platform } from "os"
import menuconfig from '../config/menu'
import { openDevTools, IsUseSysTitle, UseStartupChart } from '../config/const'
import setIpc from './ipcMain'
import { winURL, loadingURL, adminWebUri } from '../config/StaticPath'
import { winURL, loadingURL, adminWebUri, libPath, remindURL } from '../config/StaticPath'
import { createNotification } from "./notices"
import path from "path"
var loadWindow = null
var mainWindow = null
setIpc.Mainfunc(IsUseSysTitle)
var adminWindow = null
var tray = null
var adminView = null
var remindWindow = null
export function toggleMainWindowResizable (status) {
mainWindow.setResizable(status)
}
export function mainWindowResize (w,h) {
mainWindow.setSize(w,h)
}
export function setAdminViewBounds (x,y,width,height) {
adminView.setBounds({x,y,width,height})
}
export async function hideAdminView () {
await adminView.setBounds({
x: 0,
y: 0,
width: 0,
height: 0
})
}
function destroyAdminView () {
adminView.destroy()
adminView = null
}
function createAdminView () {
if (adminView) {
setAdminCookie()
return
}
adminView = new BrowserView()
mainWindow.setBrowserView(adminView)
mainWindow?.webContents.executeJavaScript("window.localStorage.getItem('token')",true).then((token) => {
session.defaultSession.cookies.set({
url: adminWebUri,
name: "sqhj_workerbench_web_token",
value: token
}).then(_ => {
adminView.webContents.loadURL(adminWebUri)
})
})
adminView.webContents.on('dom-ready', () => {
adminView.webContents.executeJavaScript("window.hideTopBar()",true).then(r => {}).catch(err => {
console.log(err,'err')
})
adminView.setAutoResize({
width: true,
height: true,
horizontal: true,
vertical: false
})
})
if (process.env.NODE_ENV === 'development' || openDevTools) {
adminView.webContents.on('console-message', (e, level, message, line, sourceId) => {
console.log(`Message: ${JSON.stringify(message)}, Line: ${line}, Source Id: ${sourceId}`);
});
}
}
export function setAdminCookie () {
mainWindow?.webContents.executeJavaScript("window.localStorage.getItem('token')",true).then((token) => {
session.defaultSession.cookies.set({
url: adminWebUri,
name: "sqhj_workerbench_web_token",
value: token
}).then(_ => {
adminView?.webContents.reload()
})
})
}
function createAdminWindow() {
adminWindow = new BrowserWindow({
height: 800,
@ -49,6 +112,8 @@ function createAdminWindow() {
adminWindow.webContents.once('dom-ready', () => {
adminWindow.show()
mainWindow.setBrowserView(adminWindow)
if (process.env.NODE_ENV === 'development' || openDevTools) adminWindow.webContents.openDevTools(true)
})
adminWindow.on('maximize', () => {
@ -60,18 +125,48 @@ function createAdminWindow() {
adminWindow.on('closed', () => {
adminWindow.destroy()
adminWindow = null
mainWindow.show()
})
}
function initTrayIcon () {
tray = new Tray(path.join(__static,"./ico.png"))
tray.setToolTip("江苏省宿迁环境监测中心")
const menu = Menu.buildFromTemplate(menuconfig)
tray.setContextMenu(menu)
tray.on('click', () => {
app.show()
})
}
let trayTimer = null;
const blankPng = path.join(__static,"./blank.png")
const noticePng = path.join(__static,"./notice.png")
function noticeFlash () {
clearInterval(trayTimer)
let temp = false;
trayTimer = setInterval(() => {
if (temp) {
tray.setImage(blankPng)
} else {
tray.setImage(noticePng)
}
temp = !temp;
},800)
}
function setTrayTitle (title) {
if (process.platform === "darwin") {
tray.setTitle(title.toString())
} else {
noticeFlash()
}
}
function createMainWindow() {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
height: 504,
height: 800,
useContentSize: true,
width: 302,
resizable: false,
width: 1200,
resizable: true,
show: false,
frame: IsUseSysTitle,
titleBarStyle: platform().includes('win32') ? 'default' : 'hidden',
@ -107,11 +202,11 @@ function createMainWindow() {
Menu.setApplicationMenu(menu)
mainWindow.loadURL(winURL)
mainWindow.webContents.once('dom-ready', () => {
mainWindow.show()
if (process.env.NODE_ENV === 'development' || openDevTools) mainWindow.webContents.openDevTools(true)
if (UseStartupChart) loadWindow.destroy()
createAdminView()
})
mainWindow.on('maximize', () => {
mainWindow.webContents.send("w-max", true)
@ -121,10 +216,34 @@ function createMainWindow() {
})
mainWindow.on('closed', () => {
mainWindow = null
adminView = null
remindWindow = null
app.quit();
})
}
function createRemindWindow () {
remindWindow = new BrowserWindow({
width: 240,
height: 160,
frame: false,
backgroundColor: '#222',
skipTaskbar: true,
transparent: true,
resizable: false,
show: false,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
webSecurity: false,
experimentalFeatures: true,
devTools: process.env.NODE_ENV === 'development' || openDevTools, }
})
remindWindow.loadURL(remindURL)
const screenSize = screen.getPrimaryDisplay().workAreaSize;
// 计算窗口的位置,使其显示在右下角
remindWindow.setPosition(screenSize.width - 200, screenSize.height - 200);
}
function loadingWindow() {
loadWindow = new BrowserWindow({
width: 400,
@ -157,7 +276,15 @@ function initWindow() {
return createMainWindow()
}
}
export {
initWindow,
createAdminWindow
createAdminWindow,
adminView,
initTrayIcon,
tray,
setTrayTitle,
destroyAdminView,
createAdminView,
remindWindow
}

@ -9,7 +9,14 @@
<script setup>
import CHeader from "./components/title";
import { useNoticeStore } from "@/store/notice";
import { onUnmounted } from "vue";
const noticeStore = useNoticeStore()
noticeStore.startNoticeTimer()
onUnmounted(() => {
noticeStore.destroyNoticeTimer()
})
</script>
<style>

@ -0,0 +1,26 @@
import request from '@/utils/request'
export function save(data) {
return request({
url: '/api/admin/admin/save',
method: 'post',
data
})
}
export function index(params) {
return request({
url: '/api/admin/admin',
method: 'get',
params:params
})
}
export function del(data) {
return request({
url: '/api/admin/admin/delete',
method: 'post',
data
})
}

@ -39,3 +39,10 @@ export function logout() {
method: 'post'
})
}
export function getOaToken () {
return request({
method: "get",
url: "/api/admin/oa/get-oa-token"
})
}

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getNewNotice(params) {
return request({
url: '/api/admin/notice/new-notice',
method: 'get',
params
})
}

@ -73,6 +73,7 @@ export default {
display: flex;
-webkit-app-region: drag;
position: fixed;
background: transparent;
top: 0;
z-index: 99999;
.title {
@ -113,4 +114,4 @@ export default {
}
}
}
</style>
</style>

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715760516138" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15061" width="200" height="200"><path d="M499.328 56L481.92 49.152 312 3.84c-32.32-8.448-52.992 3.264-61.504 35.2L48.192 879.808c-8.512 32.768 3.2 53.376 35.584 62.272l169.92 45.312c32.768 8.896 53.44-3.328 61.952-36.032l202.368-840.32c6.912-25.856 0.768-44.096-18.688-55.04z m-82.56 292.48a38.464 38.464 0 0 1-12.096 19.456 18.944 18.944 0 0 1-16.512 4.48h-1.344l-154.112-41.664c-6.016-1.6-10.112-5.568-12.544-12.544a35.456 35.456 0 0 1-1.216-22.272 32.064 32.064 0 0 1 12.16-18.624c5.248-5.248 11.328-6.848 17.408-5.248l154.112 41.664h0.832c1.024 0.32 1.728 1.216 2.688 1.792a21.632 21.632 0 0 1 9.472 11.136 29.696 29.696 0 0 1 2.496 10.368 38.4 38.4 0 0 1-1.216 11.52l-0.128-0.064z m25.984-101.696c-0.192 2.24-0.192 4.352-0.896 6.656a33.28 33.28 0 0 1-7.936 14.08c-1.344 1.536-2.56 3.264-4.224 4.544-1.6 1.472-3.264 2.176-4.992 3.008a16.064 16.064 0 0 1-11.136 2.24h-0.832l-154.112-41.216a21.632 21.632 0 0 1-13.376-13.376 30.912 30.912 0 0 1-1.536-15.488c0.192-2.112 0.192-4.16 0.768-6.4 0.704-2.304 1.792-4.16 2.816-6.208a35.008 35.008 0 0 1 9.344-12.864c5.76-4.864 11.776-6.464 17.792-4.416l154.112 41.28h0.768c3.52 1.28 6.144 4.032 8.384 7.232 1.28 1.664 2.432 3.264 3.392 5.312 1.408 3.456 2.176 7.04 2.304 10.752 0.128 1.6-0.448 3.264-0.64 4.992v-0.128z m287.232-160.512c-3.264 7.68-4.864 16.512-4.864 26.688v871.936c0 10.496 1.6 19.52 4.864 26.752 3.648 7.168 8.128 10.88 13.376 10.88s9.344-3.712 12.864-10.88a57.6 57.6 0 0 0 5.632-26.752V112.96a61.376 61.376 0 0 0-5.632-26.688c-3.584-7.36-7.616-11.008-12.864-11.008s-9.728 3.584-13.376 11.008z m-22.208 26.688c0-10.112-1.536-19.008-4.864-26.688-4.032-7.296-8.512-10.88-13.76-10.88s-9.28 3.584-12.864 10.88a61.568 61.568 0 0 0-5.632 26.688v871.936c0 10.432 1.984 19.52 5.632 26.752 3.712 7.168 7.616 10.88 12.864 10.88s9.728-3.712 13.76-10.88c3.328-7.232 4.864-16.32 4.864-26.752V112.96z m238.72-26.688c-3.264 7.68-4.864 16.512-4.864 26.688v871.936c0 10.496 1.6 19.52 4.864 26.752 3.648 7.168 8 10.88 13.248 10.88 5.376 0 9.344-3.712 12.992-10.88a59.328 59.328 0 0 0 5.504-26.752V112.96a61.376 61.376 0 0 0-5.504-26.688c-3.648-7.36-7.616-11.008-12.992-11.008-5.248 0-9.6 3.584-13.248 11.008z m-22.272 26.688c0-10.112-1.6-19.008-4.992-26.688-4.032-7.296-8.512-10.88-13.632-10.88-5.248 0-9.344 3.584-12.992 10.88a61.568 61.568 0 0 0-5.632 26.688v871.936c0 10.432 1.984 19.52 5.632 26.752 3.648 7.168 7.744 10.88 12.992 10.88 5.12 0 9.536-3.712 13.632-10.88a63.36 63.36 0 0 0 4.992-26.752V112.96z m-296.576-33.216a37.376 37.376 0 0 0-26.752-10.944 37.568 37.568 0 0 0-27.008 10.944 36.608 36.608 0 0 0-10.88 26.688v878.08c0 10.432 3.648 19.392 10.88 26.688a36.672 36.672 0 0 0 27.008 11.328 36.48 36.48 0 0 0 26.752-11.328 36.224 36.224 0 0 0 11.008-26.688V106.432a36.224 36.224 0 0 0-11.008-26.688z m170.752 0a36.48 36.48 0 0 0-10.88 26.688v878.08c0 10.432 3.648 19.392 10.88 26.688a36.48 36.48 0 0 0 26.752 11.328 37.12 37.12 0 0 0 27.136-11.328 36.608 36.608 0 0 0 10.88-26.688V106.432a36.48 36.48 0 0 0-10.88-26.688 38.08 38.08 0 0 0-27.136-10.944 37.312 37.312 0 0 0-26.752 10.944z" fill="#2c2c2c" p-id="15062"></path></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715760441488" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14053" width="200" height="200"><path d="M545.28 712.192l49.664-11.264-61.44-37.888z" p-id="14054"></path><path d="M882.688 177.152l-138.24-122.88c-5.632-6.144-13.824-9.728-22.528-10.24H174.592c-17.92 0-32.256 15.36-32.256 34.304v788.992c0 9.216 3.584 18.432 9.728 25.088l96.768 88.576c16.896 13.312 35.328 5.632 44.544 0l98.816-89.6 102.4 93.184c18.944 12.288 28.16 9.728 44.544 0l102.4-93.184 102.4 93.184c9.216 6.656 14.336 9.728 22.528 9.728 8.192 0 14.336-3.584 22.528-9.728l92.672-84.48c6.144-6.656 9.728-15.36 9.728-24.576V201.728c1.024-9.216-2.56-17.92-8.704-24.576z m-397.824 403.456h-15.872c-127.488 0-146.944-40.448-146.944-40.448v80.896c0 9.728 10.752 34.816 108.032 40.448 11.776 0.512 20.992 10.752 20.992 22.016 0 12.8-11.264 23.04-24.064 22.016-76.288-5.12-145.408-20.992-152.064-67.072V334.848c28.672-105.472 359.936-104.96 379.904 0.512 6.656 34.816-29.696 59.392-29.696 59.392s-33.792 36.864-161.28 36.864-141.824-35.328-141.824-35.328v70.144c0 11.264 13.312 61.952 146.944 61.44h15.872c14.336 0 26.112 11.264 26.112 25.6v0.512c0 14.848-11.776 26.624-26.112 26.624z m279.552-97.28l-148.48 238.592-89.6 20.992-20.992-89.088 148.48-238.592c1.536-2.56 4.096-4.096 7.168-5.12 3.072-0.512 5.632 0 8.192 1.536l91.648 56.832c2.56 1.536 4.096 4.096 5.12 6.656 0.512 2.56 0 5.632-1.536 8.192z" p-id="14055"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1 @@
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1564902100209" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="840" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300"><defs><style type="text/css"></style></defs><path d="M615.6 123.6h165.5L512 589.7 242.9 123.6H63.5L512 900.4l448.5-776.9z" fill="#41B883" p-id="841"></path><path d="M781.1 123.6H615.6L512 303 408.4 123.6H242.9L512 589.7z" fill="#34495E" p-id="842"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715745172723" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7557" width="200" height="200"><path d="M512 1024C229.205 1024 0 794.795 0 512S229.205 0 512 0s512 229.205 512 512-229.205 512-512 512z m0-496.47a170.667 170.667 0 1 0 0-341.333 170.667 170.667 0 0 0 0 341.334z m263.765 263.723a263.765 263.765 0 1 0-527.53 0h527.53z" p-id="7558"></path></svg>

Before

Width:  |  Height:  |  Size: 584 B

After

Width:  |  Height:  |  Size: 544 B

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715745354182" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11014" width="200" height="200"><path d="M940.8 499.4L772 330.6c-1.6-1.6-3.2-2.8-5.2-4-1.8-1.2-3.8-2.2-5.8-3s-4.2-1.4-6.2-1.8c-2.2-0.4-4.4-0.6-6.4-0.6-2.2 0-4.4 0.2-6.4 0.8-2.2 0.4-4.2 1-6.2 2-2 0.8-4 1.8-5.8 3-1.8 1.2-3.4 2.6-5 4.2s-3 3.2-4.2 5c-1.2 1.8-2.2 3.8-3 5.8-0.8 2-1.4 4-2 6.2-0.4 2.2-0.6 4.2-0.8 6.4 0 2.2 0.2 4.4 0.6 6.4 0.4 2.2 1 4.2 1.8 6.2s1.8 4 3 5.8c1.2 1.8 2.6 3.6 4 5.2l111.2 111.2h-188.6v67.4h188.6L724.4 668l-2.4 2.4c-0.8 0.8-1.4 1.8-2 2.6-0.6 1-1.2 1.8-1.8 2.8-0.6 1-1 2-1.4 3-0.4 1-0.8 2-1.2 3.2-0.4 1-0.6 2.2-0.8 3.2-0.2 1-0.4 2.2-0.6 3.4-0.2 1.2-0.2 2.2-0.2 3.4s0 2.2 0.2 3.4c0 1.2 0.2 2.2 0.4 3.4 0.2 1.2 0.4 2.2 0.8 3.2s0.6 2.2 1.2 3.2c0.4 1 0.8 2 1.4 3 0.6 1 1 2 1.8 2.8 0.6 1 1.2 1.8 2 2.8 0.8 0.8 1.4 1.8 2.2 2.4 0.8 0.8 1.6 1.6 2.4 2.2 0.8 0.8 1.8 1.4 2.8 2s2 1.2 2.8 1.8c1 0.6 2 1 3 1.4 1 0.4 2 0.8 3.2 1.2 1 0.4 2.2 0.6 3.2 0.8 1.2 0.2 2.2 0.4 3.4 0.4 1.2 0 2.2 0.2 3.4 0.2s2.2 0 3.4-0.2c1.2-0.2 2.2-0.4 3.4-0.6 1-0.2 2.2-0.6 3.2-0.8 1-0.4 2.2-0.8 3.2-1.2 1-0.4 2-1 3-1.4 1-0.6 2-1.2 2.8-1.8 1-0.6 1.8-1.4 2.6-2l2.4-2.4 168.8-168.8c0.8-0.8 1.6-1.6 2.2-2.4s1.4-1.8 2-2.6c0.6-1 1.2-1.8 1.8-2.8 0.6-1 1-2 1.4-3 0.4-1 0.8-2 1.2-3.2 0.4-1 0.6-2.2 0.8-3.2 0.2-1 0.4-2.2 0.4-3.2 0.2-1 0.2-2.2 0.2-3.4 0-1.2 0-2.2-0.2-3.4-0.2-1-0.2-2.2-0.4-3.2s-0.4-2.2-0.8-3.2-0.6-2-1.2-3.2c-0.4-1-0.8-2-1.4-3-0.6-1-1-2-1.8-2.8-0.6-1-1.2-1.8-2-2.6l-2.4-2.4z m-631.2 23.8c0-1.2 0-2.2 0.2-3.4 0.2-1.2 0.2-2.2 0.4-3.2s0.4-2.2 0.8-3.2 0.6-2 1.2-3.2c0.4-1 0.8-2 1.4-3 0.6-1 1-2 1.8-2.8 0.6-1 1.2-1.8 2-2.6s1.4-1.6 2.2-2.4c0.8-0.8 1.6-1.6 2.4-2.2 0.8-0.8 1.8-1.4 2.6-2 1-0.6 1.8-1.2 2.8-1.8 1-0.6 2-1 3-1.4 1-0.4 2-0.8 3.2-1.2s2.2-0.6 3.2-0.8c1-0.2 2.2-0.4 3.2-0.4 1.2-0.2 2.2-0.2 3.4-0.2h303.8V270c0-67.6-71.2-118.2-135-118.2H191.4c-3.8 0-7.8 0.2-11.6 0.6-3.8 0.4-7.6 1-11.4 1.8-3.8 0.8-7.6 1.6-11.2 2.8s-7.4 2.4-11 4c-3.6 1.4-7 3.2-10.4 5-3.4 1.8-6.8 3.8-10 6s-6.4 4.4-9.4 7-5.8 5-8.6 7.8-5.4 5.6-7.8 8.6c-2.4 3-4.8 6-7 9.4s-4.2 6.6-6 10c-1.8 3.4-3.4 7-5 10.4-1.4 3.6-2.8 7.2-4 11-1.2 3.8-2 7.4-2.8 11.2-0.8 3.8-1.4 7.6-1.8 11.4s-0.6 7.8-0.6 11.6v506.2c0 3.8 0.2 7.8 0.6 11.6s1 7.6 1.8 11.4 1.6 7.6 2.8 11.2c1.2 3.8 2.4 7.4 4 11 1.4 3.6 3.2 7 5 10.4 1.8 3.4 3.8 6.8 6 10s4.4 6.4 7 9.4c2.4 3 5 5.8 7.8 8.6s5.6 5.4 8.6 7.8c3 2.4 6 4.8 9.4 7 3.2 2.2 6.6 4.2 10 6 3.4 1.8 7 3.4 10.4 5 3.6 1.4 7.2 2.8 11 4s7.4 2 11.2 2.8c3.8 0.8 7.6 1.4 11.4 1.8s7.8 0.6 11.6 0.6h337.6c3.8 0 7.8-0.2 11.6-0.6 3.8-0.4 7.6-1 11.4-1.8 3.8-0.8 7.6-1.6 11.2-2.8 3.8-1.2 7.4-2.4 11-4 3.6-1.4 7-3.2 10.4-5s6.8-3.8 10-6 6.4-4.4 9.4-7c3-2.4 5.8-5 8.6-7.8s5.4-5.6 7.8-8.6c2.4-3 4.8-6 7-9.4 2.2-3.2 4.2-6.6 6-10 1.8-3.4 3.4-7 5-10.4 1.4-3.6 2.8-7.2 4-11s2-7.4 2.8-11.2 1.4-7.6 1.8-11.4 0.6-7.8 0.6-11.6V557H343.2c-1.2 0-2.2 0-3.4-0.2-1.2-0.2-2.2-0.2-3.2-0.4s-2.2-0.4-3.2-0.8-2-0.6-3.2-1.2c-1-0.4-2-0.8-3-1.4-1-0.6-2-1-2.8-1.8-1-0.6-1.8-1.2-2.6-2s-1.6-1.4-2.4-2.2c-0.8-0.8-1.6-1.6-2.2-2.4-0.8-0.8-1.4-1.8-2-2.6-0.6-1-1.2-1.8-1.8-2.8-0.6-1-1-2-1.4-3-0.4-1-0.8-2-1.2-3.2-0.4-1-0.6-2.2-0.8-3.2s-0.4-2.2-0.4-3.2v-3.4z" p-id="11015"></path></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715760315771" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12148" width="200" height="200"><path d="M563.2 699.728c11.376-11.36 96.704-96.704 227.552-17.056 0 0-51.2-85.344-170.656-51.2-51.2 11.36-79.648 45.504-79.648 51.2a160.944 160.944 0 0 0-34.144-17.072L512 745.248l79.648-17.072c-11.376-11.376-17.072-22.752-28.448-28.448z m227.552 39.84l-79.648 17.056c5.696 11.376 11.392 22.752 22.768 28.448-11.376 11.36-96.72 96.704-227.568 17.056 0 0 51.2 85.344 170.672 51.2 45.52-11.36 73.952-45.504 79.648-51.2a160.944 160.944 0 0 0 34.128 17.072v-79.648z m-438.048-347.04h187.744c11.36 0 22.752-11.36 22.752-22.752 0-11.376-11.376-22.752-22.752-22.752H352.704c-11.36 0-22.752 11.376-22.752 22.752s11.376 22.752 22.752 22.752z m256 79.648c0-11.376-11.36-22.752-22.752-22.752H352.704c-11.36 0-22.752 11.376-22.752 22.752s11.376 22.752 22.752 22.752h233.248c11.376 0 22.752-11.36 22.752-22.752zM705.44 159.296H324.272c-62.576 0-108.096 51.2-108.096 108.08v585.952c0 62.576 51.2 108.096 108.096 108.096h472.16c62.592 0 108.096-51.2 108.096-108.096V358.4C910.24 341.328 722.496 159.296 705.44 159.296zM733.872 256c28.432 22.752 56.88 56.896 85.328 79.648h-28.448c-28.448 0-56.88-22.752-56.88-56.896V256z m62.56 654.224h-472.16c-28.448 0-56.896-22.752-56.896-56.896V273.072c0-28.448 22.752-56.896 56.896-56.896h358.4v68.272c0 62.56 51.2 108.08 108.08 108.08h62.576v460.8c0 34.144-22.752 56.896-56.88 56.896zM483.568 113.76C500.64 113.776 512 102.4 512 85.328c0-17.056-11.376-28.432-28.448-28.432H233.248c-62.576 0-119.472 56.88-119.472 119.456v614.4c0 17.072 11.376 28.448 28.448 28.448 17.072 0 28.448-11.376 28.448-28.448v-614.4c0-34.128 28.432-62.56 62.56-62.56h250.32z" fill="#000000" p-id="12149" class="custom-cursor-on-hover"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -1,14 +1,17 @@
<template>
<section class="app-main">
<transition name="fade" mode="out-in">
<router-view />
<router-view :key="key"/>
</transition>
</section>
</template>
<script setup>
import { defineComponent } from "vue";
import { useRoute } from "@/hooks/use-router";
import { defineComponent, computed } from "vue";
defineComponent({
name: "AppMain"
});
const $route = useRoute();
const key = computed(() => $route.fullPath + new Date().valueOf())
</script>

@ -2,37 +2,47 @@
<el-menu :class="'navbar-header-fixed' + (isMac ? ' dragTitle' : '')" mode="horizontal">
<div class="top-right">
<div class="hb-bd">
<hamburger class="hamburger-container" @toggle-click="toggleSideBar" :isActive="sidebarComp.opened"></hamburger>
<!-- <hamburger class="hamburger-container" @toggle-click="toggleSideBar" :isActive="sidebarComp.opened"></hamburger>-->
<breadcrumb></breadcrumb>
</div>
<div class="top-select">
<div class="go-index">{{ time }}</div>
<div class="select-right">
<el-dropdown trigger="click">
<div>
<el-image :src="userImage" class="avatar">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<div class="el-dropdown-link">
尊敬的 {{ userName }}
<i class="el-icon-arrow-down el-icon--right"></i>
</div>
<div class="select-right__content">
<!-- <el-image :src="userImage" class="avatar">-->
<!-- <div slot="error" class="image-slot">-->
<!-- <i class="el-icon-picture-outline"></i>-->
<!-- </div>-->
<!-- </el-image>-->
<div class="el-dropdown-link">
尊敬的 {{ userName }}
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/">
<el-dropdown-item>返回首页</el-dropdown-item>
</router-link>
<el-dropdown-item @click.native="logout">
<span>切换账号</span>
</el-dropdown-item>
<el-dropdown-item @click.native="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<!-- <el-dropdown trigger="click">-->
<!-- <div>-->
<!-- <el-image :src="userImage" class="avatar">-->
<!-- <div slot="error" class="image-slot">-->
<!-- <i class="el-icon-picture-outline"></i>-->
<!-- </div>-->
<!-- </el-image>-->
<!-- <div class="el-dropdown-link">-->
<!-- 尊敬的 {{ userName }}-->
<!-- <i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>-->
<!-- </div>-->
<!-- </div>-->
<!-- <el-dropdown-menu slot="dropdown">-->
<!-- <router-link to="/">-->
<!-- <el-dropdown-item>返回首页</el-dropdown-item>-->
<!-- </router-link>-->
<!-- <el-dropdown-item @click.native="logout">-->
<!-- <span>切换账号</span>-->
<!-- </el-dropdown-item>-->
<!-- <el-dropdown-item @click.native="logout">-->
<!-- <span>退出登录</span>-->
<!-- </el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </el-dropdown>-->
</div>
</div>
</div>
@ -59,8 +69,8 @@ const isMac = process.platform === "darwin"
let timer = null
onMounted(() => {
timer = setInterval(() => {
time.value = format(new Date(), "yyyy/MM/dd HH:mm");
}, 60000);
time.value = format(new Date(), "yyyy/MM/dd HH:mm:ss");
}, 1000);
})
onUnmounted(() => {
clearInterval(timer);
@ -69,22 +79,11 @@ onUnmounted(() => {
const { ToggleSideBar, sidebarStatus } = useAppStore()
const sidebarComp = computed(() => sidebarStatus)
const toggleSideBar = () => {
ToggleSideBar()
}
const { logOut, name } = useUserStore()
const userStore = useUserStore()
const router = useRouter()
const userName = computed(() => name)
const logout = () => {
logOut().then(() => {
Message({
message: "退出成功",
type: "success"
});
router.push('/login')
})
}
const userName = computed(() => userStore.name)
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@ -98,6 +97,18 @@ const logout = () => {
z-index: 1002;
height: 62px;
&::before {
content: "";
background: #fff;
height: 30px;
width: 100%;
position: absolute;
top: -30px;
left: 0;
right: 0;
}
.hamburger-container {
-webkit-app-region: no-drag;
line-height: 58px;
@ -164,6 +175,10 @@ const logout = () => {
display: flex;
align-items: center;
}
&__content {
display: flex;
align-items: center;
}
}
}
}

@ -14,7 +14,14 @@
<router-link v-if="hasOneShowingChild(item.children) && !onlyOneChild.children && !item.alwaysShow"
:to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
<svg-icon v-if="onlyOneChild.meta && onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"></svg-icon>
<template v-if="onlyOneChild.meta && onlyOneChild.meta.showBadge">
<el-badge :value="noticeStore.noticeLength(onlyOneChild.name)" :is-dot="noticeStore.noticeLength(onlyOneChild.name)>99">
<svg-icon v-if="onlyOneChild.meta && onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"></svg-icon>
</el-badge>
</template>
<template v-else>
<svg-icon v-if="onlyOneChild.meta && onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"></svg-icon>
</template>
<span v-if="onlyOneChild.meta && onlyOneChild.meta.title" slot="title">{{ onlyOneChild.meta.title }}</span>
</el-menu-item>
</router-link>
@ -94,6 +101,12 @@ export default {
}
};
</script>
<script setup>
import { ref,computed,onUnmounted } from "vue";
import { useNoticeStore } from "@/store/notice";
const noticeStore = useNoticeStore();
</script>
<style lang="scss" scoped>
.menu-wrapper {
@ -107,4 +120,8 @@ export default {
padding: 0 20px 0 12px;
}
}
</style>
::v-deep .el-badge__content.is-fixed {
top: 8px;
right: 8px;
}
</style>

@ -1,15 +1,14 @@
<template>
<scroll-bar>
<el-menu mode="vertical" :show-timeout="200" :default-active="$route.path" :collapse="isCollapse">
<Logo :collapse="isCollapse" />
<sidebar-item v-for="route in routes_list" :key="route.name" :item="route" :base-path="route.path"
:collapse="isCollapse"></sidebar-item>
<el-menu-item @click="toAdmin">
<svg-icon icon-class="adminManage"></svg-icon>
<span>后台管理</span>
</el-menu-item>
</el-menu>
</scroll-bar>
<div>
<scroll-bar>
<el-menu mode="vertical" :show-timeout="200" :default-active="$route.path" :collapse="isCollapse">
<Logo :collapse="isCollapse" />
<sidebar-item v-for="route in routes_list" :key="route.name" :item="route" :base-path="route.path"
:collapse="isCollapse"></sidebar-item>
</el-menu>
</scroll-bar>
<svg-icon class="logout" icon-class="logout" @click.native="logout"></svg-icon>
</div>
</template>
<script setup>
@ -21,6 +20,9 @@ import Logo from "./logo";
import { useAppStore } from "@/store/app"
import { usePermissionStore } from "@/store/permission"
import { constantRouterMap } from "@/router"
import SvgIcon from "@/components/SvgIcon";
import { useRouter } from "@/hooks/use-router";
import { useUserStore } from "@/store/user"
defineComponent({
name: 'Sidebar'
})
@ -31,8 +33,14 @@ const routes_list = computed(() => constantRouterMap)
const isCollapse = computed(() => !sidebarStatus.opened)
const toAdmin = () => {
ipcRenderer.invoke("create-admin-window")
const { logOut } = useUserStore()
const router = useRouter()
const logout = async () => {
await ipcRenderer.invoke("hide-admin-view")
logOut().then(() => {
router.push('/login')
})
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@ -58,4 +66,14 @@ const toAdmin = () => {
overflow: hidden;
width: 180px;
}
.logout {
cursor: pointer;
width: 22px;
height: 22px;
transform: translateX(-50%);
position: absolute;
bottom: 50px;
left: 50%;
margin-left: 2px!important;
}
</style>

@ -1,11 +1,11 @@
<template>
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to>
<svg-icon icon-class="logo" class-name="sidebar-logo"></svg-icon>
<div class="sidebar-title">{{ title }}</div>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<router-link v-else key="expand" class="sidebar-logo-link" to>
<svg-icon icon-class="logo" class-name="sidebar-logo"></svg-icon>
<div class="sidebar-title">{{ title }}</div>
</router-link>

@ -57,7 +57,7 @@ const classObj = computed(() => {
}
.NoUseSysTitle {
top: 38px
top: 30px;
}
.sidebar-container {
-webkit-app-region: no-drag;

@ -5,8 +5,19 @@ import { useUserStore } from "@/store/user"
import { ipcRenderer } from "electron"
export function usePermission() {
let end = null
const whiteList = ['/login'] // 不重定向白名单
const whiteList = ['/login','/remind'] // 不重定向白名单
router.beforeEach(async (to, from, next) => {
if (to.path === '/login') {
await ipcRenderer.invoke("toggle-main-window-resizable",false)
await ipcRenderer.invoke("main-window-resize",{
width: 320,
height: 504
})
} else {
if (to.meta.toUrl) {
ipcRenderer.invoke("exec-admin-view-js",`window.routerTo['${to.meta.toUrl}']()`)
}
}
const { GenerateRoutes, routers } = usePermissionStore()
const { getUserInfo, token, roles, logOut } = useUserStore()
end = Performance.startExecute(`${from.path} => ${to.path} 路由耗时`) /// 路由性能监控
@ -20,11 +31,6 @@ export function usePermission() {
if (whiteList.includes(to.path)) {
next()
} else {
await ipcRenderer.invoke("toggle-main-window-resizable",false)
await ipcRenderer.invoke("main-window-resize",{
width: 320,
height: 504
})
next('/login')
}
}

@ -23,44 +23,4 @@ import Layout from '@/layout'
icon: 'svg-name' 当你在svg文件夹内加入了你的图标,那么在这里填写图标名他就会显示在侧栏
}
**/
export default [
{
path: '/form',
component: Layout,
meta: { title: '表单', icon: 'form', roles: ['admin', 'edit'] },
children: [
{
path: 'index',
name: 'Form',
component: () => import('@/views/form/index'),
meta: { title: '表单', icon: 'form' }
}
]
},
{
path: '/table',
component: Layout,
meta: { roles: ['admin', 'edit'] },
children: [
{
path: 'index',
name: '表格',
component: () => import('@/views/table/index'),
meta: { title: '表格', icon: 'table' }
}
]
},
{
path: '/permission',
component: Layout,
meta: { roles: ['admin'] },
children: [
{
path: 'index',
name: '权限',
component: () => import('@/views/permission/index'),
meta: { title: '权限', icon: 'table' }
}
]
},
]
export default []

@ -4,44 +4,79 @@ import Layout from '@/layout'
import asyncRouterMap from './constantRouterMap'
export const constantRouterMap = [{
path: '/',
path: '',
component: Layout,
redirect: '/dashboard',
name: '主页',
hidden: true,
name: 'dashboard',
children: [{
path: 'dashboard',
name: '总览',
component: () => import('@/components/LandingPage')
component: () => import('@/views/admin/index'),
meta: { title: '总览', icon: 'dashboard', toUrl: '/worker' }
}]
},{
path: '/addressBook',
component: Layout,
meta: { title: '通讯录', icon: 'addressBook', roles: ['admin'] },
children: [
{
path: 'index',
name: 'Form',
name: 'addressBook',
component: () => import('@/views/addressBook/index'),
meta: { title: '通讯录', icon: 'addressBook' }
}
]
},{
path: '/notice',
component: Layout,
meta: { title: '通知', icon: 'notice', roles: ['admin'] },
component: Layout,
children: [
{
path: 'index',
name: 'Form',
name: 'notice',
component: () => import('@/views/notice/index'),
meta: { title: '通知', icon: 'notice' }
meta: { title: '通知', icon: 'notice', showBadge: true }
}
]
},{
path: '/contract',
component: Layout,
children: [
{
path: 'index',
name: 'contract',
component: () => import('@/views/admin/index'),
meta: { title: '项目预算管理', icon: 'contract', toUrl: '/contract' }
}
]
},{
path: '/oa',
component: Layout,
children: [
{
path: 'index',
name: 'oa',
component: () => import('@/views/admin/index'),
meta: { title: '工作流转', icon: 'oa', toUrl: '/old' }
}
]
},{
path: '/book',
component: Layout,
children: [
{
path: 'index',
name: 'book',
component: () => import('@/views/admin/index'),
meta: { title: '图书管理', icon: 'book', toUrl: '/asset' }
}
]
}, {
path: '/login',
component: () => import('@/views/login'),
hidden: true
},{
path: '/remind',
component: () => import('@/views/remind'),
hidden: true
},{
path: '*',
component: () => import('@/views/404'),
@ -59,5 +94,4 @@ export function resetRouter() {
router.matcher = newRouter.matcher
}
const router = createRouter()
export default router

@ -2,7 +2,7 @@ import { defineStore } from "pinia"
const state = () => ({
sidebarStatus: {
opened: !+localStorage.getItem('sidebarStatus'),
opened: false,
withoutAnimation: false
},
device: 'desktop'
@ -26,4 +26,4 @@ export const useAppStore = defineStore({
this.sidebarStatus.withoutAnimation = withoutAnimation
}
}
})
})

@ -0,0 +1,72 @@
import { defineStore } from 'pinia'
import { getNewNotice } from "@/api/notice"
import { ipcRenderer } from "electron";
import { useUserStore } from "./user";
let timer = null;
function getHtmlPlainText(html_str) {
//提取字符串中的文字
let re = new RegExp('<[^<>]+>', 'g')
return html_str.replace(re, '')
//或
//var text = html_str.replace(/<[^<>]+>/g, "");
}
export const useNoticeStore = defineStore({
id: "notice",
state:() => ({
notice: {
notice: []
},
newNotices: []
}),
getters: {
noticeLength (state) {
return function (key) {
return state.notice[key]?.length || 0
}
},
token () {
return useUserStore().token
}
},
actions: {
setNotice(key,data) {
this.notice[key] = data
},
setNewNotices(data) {
this.newNotices = data.filter(item => !(this.notice['notice'].find(old => (old.id === item.id && old.data === item.data))))
let body = ""
this.newNotices.forEach((item,index) => {
const splitText = getHtmlPlainText(item.remark)
body += (++index).toString() + ". " + splitText
})
if (this.newNotices.length > 0) {
ipcRenderer.invoke("create-notice",{
title: "通知",
body
})
}
},
startNoticeTimer () {
if (this.token) {
getNewNotice().then(res => {
this.setNotice('notice', res.list)
ipcRenderer.invoke("set-tray-title", res.list?.length ?? 0)
})
}
timer = setInterval(() => {
if (!this.token) {
return
}
getNewNotice().then(res => {
this.setNotice('notice', res.list)
ipcRenderer.invoke("set-tray-title", res.list?.length ?? 0)
this.setNewNotices(res.list)
})
}, 1000 * 10)
},
destroyNoticeTimer () {
clearInterval(timer)
timer = null
}
}
})

@ -1,10 +1,9 @@
import { defineStore } from 'pinia'
import { resetRouter } from '@/router'
import { usePermissionStore } from './permission'
import { login, getInfo, logout } from "@/api/login"
import { login, getInfo, logout, getOaToken } from "@/api/login"
import { ipcRenderer } from "electron"
const store = () => ({
token: JSON.parse(localStorage.getItem('token')),
name: JSON.parse(localStorage.getItem('name')),
roles: [],
info: {},
})
@ -14,6 +13,9 @@ export const useUserStore = defineStore({
store,
state: () => ({
isLogin: false,
token: localStorage.getItem('token'),
authToken: localStorage.getItem('authToken'),
name: localStorage.getItem('name'),
}),
actions: {
login(data) {
@ -23,11 +25,16 @@ export const useUserStore = defineStore({
this.token = access_token
localStorage.setItem("token", access_token);
ipcRenderer.invoke("set-admin-cookie")
this.getUserInfo().then(r => {
resolve(r)
}).catch(err => {
reject(err)
})
getOaToken().then(t => {
this.authToken = t.auth_token
localStorage.setItem("authToken", t.auth_token);
})
}).catch(err => {
reject(err)
})
@ -40,9 +47,11 @@ export const useUserStore = defineStore({
localStorage.setItem("token", "");
localStorage.setItem("roles", JSON.stringify([]));
localStorage.setItem("name", "");
localStorage.setItem("authToken", "");
this.token = ""
this.name = ""
this.roles = []
this.authToken = ""
this.info = {}
this.isLogin = false
resolve(res)
@ -58,6 +67,7 @@ export const useUserStore = defineStore({
this.info = res
this.isLogin = true
this.roles = ['admin']
this.name = res.name
localStorage.setItem("roles", JSON.stringify(this.roles));
localStorage.setItem("name", res.name);
resolve(res)

@ -66,4 +66,8 @@ a:hover {
.app-container {
padding: 20px;
}
}
a[data-url] {
color: #2b86c5;
}

@ -1,11 +1,72 @@
<template>
<div>
<el-table :data="users"
v-loading="loading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)" >
<el-table-column type="index" width="40"></el-table-column>
<el-table-column align="center" v-for="item in table" :key="item.prop" :label="item.label" :prop="item.prop"></el-table-column>
</el-table>
<div style="padding: 10px;">
<el-pagination
@current-change="e => {
select.page = e;
getUsers();
}"
:current-page.sync="select.page"
:page-size="select.page_size"
layout="prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script setup>
import {} from 'vue'
import { index } from "@/api/addressBook";
import { ref,reactive } from 'vue';
const select = reactive({
page: 1,
page_size: 15
})
const table = [
{
prop: "name",
label: "姓名"
},
{
prop: "position",
label: "职位"
},
{
prop: "mobile",
label: "手机"
},
{
prop: "department.name",
label: "部门"
}
]
const total = ref(0)
const users = ref([])
const loading = ref(false)
const getUsers = async () => {
loading.value = true
try {
const res = await index(select)
users.value = res.data
total.value = res.total
loading.value = false
} catch (e) {
loading.value = false
}
}
getUsers()
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,40 @@
<template>
<div>
</div>
</template>
<script setup>
import { useRoute } from "@/hooks/use-router"
import { onMounted, onUnmounted, watch } from 'vue';
import { ipcRenderer } from "electron";
const $route = useRoute()
let resizeTimer = null;
const showAdminView = () => {
ipcRenderer.invoke("set-admin-view-bounds",{
x: 60,
y: 92,
width: window.innerWidth - 60,
height: window.innerHeight - 92
})
}
onMounted(() => {
showAdminView()
// window.onresize = () => {
// if (resizeTimer) {
// clearTimeout(resizeTimer);
// }
// resizeTimer = setTimeout(() => {
// showAdminView()
// }, 500)
// }
})
onUnmounted(() => {
ipcRenderer.invoke("hide-admin-view")
window.onresize = null;
})
</script>
<style scoped lang="scss">
</style>

@ -1,10 +1,55 @@
<template>
<div>
<el-table :data="notices"
ref="table"
v-loading="loading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)" >
<el-table-column type="index" width="40"></el-table-column>
<el-table-column prop="title" label="内容">
<template #default="{ row }">
<div v-html=row.remark></div>
</template>
</el-table-column>
<el-table-column align="center" width="240" label="下发时间" prop="created_at"></el-table-column>
</el-table>
<!-- <div style="padding: 10px;">-->
<!-- <el-pagination-->
<!-- @current-change="e => {-->
<!-- select.page = e;-->
<!-- getUsers();-->
<!-- }"-->
<!-- :current-page.sync="select.page"-->
<!-- :page-size="select.page_size"-->
<!-- layout="prev, pager, next, jumper"-->
<!-- :total="total">-->
<!-- </el-pagination>-->
<!-- </div>-->
</div>
</template>
<script setup>
import {} from 'vue'
import { useUserStore } from "@/store/user"
import { useNoticeStore } from "@/store/notice"
import { ref,reactive,computed,onMounted,nextTick } from 'vue';
const userStore = useUserStore()
const noticeStore = useNoticeStore()
const total = ref(0)
const notices = computed(() => noticeStore.notice['notice'])
const loading = ref(false)
const table = ref(null)
onMounted(async () => {
await nextTick()
table.value.$el.querySelectorAll("[data-url]").forEach(el => {
el.addEventListener('click', () => {
console.log(`${el.getAttribute('data-url')}?auth_token=${userStore.authToken}`)
window.open(`${el.getAttribute('data-url')}?auth_token=${userStore.authToken}`,'_blank')
})
})
})
</script>
<style scoped lang="scss">

@ -0,0 +1,12 @@
<template>
<div>
remind
</div>
</template>
<script setup>
import {} from 'vue'
</script>
<style scoped lang="scss">
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Loading…
Cancel
Save