提交 6630e6e4 作者: test

Merge branch 'electron' of https://gitlab.yiring.com/basic/basic-vue-admin into electron

......@@ -2,7 +2,7 @@
VITE_PORT = 3100
# spa-title
VITE_GLOB_APP_TITLE = Basic Admin
VITE_GLOB_APP_TITLE = Basic Vue @ Electron
# spa shortname
VITE_GLOB_APP_SHORT_NAME = basci_vue_admin
VITE_GLOB_APP_SHORT_NAME = basci_vue_electron
......@@ -30,6 +30,7 @@ module.exports = {
'@typescript-eslint/no-empty-function': 'off',
'vue/custom-event-name-casing': 'off',
'no-use-before-define': 'off',
'@typescript-eslint/consistent-type-assertions': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
......@@ -75,6 +76,7 @@ module.exports = {
'vue/multi-word-component-names': 'off',
'vue/no-reserved-component-names': 'off',
'vue/no-constant-condition': 'off',
'vue/no-setup-props-destructure': 'off',
'no-console': 'off',
'antfu/if-newline': 'off',
'symbol-description': 'off',
......
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')
const fs = require('node:fs')
const path = require('node:path')
const { execSync } = require('node:child_process')
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
......
......@@ -17,10 +17,8 @@ export default defineConfig({
plugins: [externalizeDepsPlugin()],
envPrefix: ['MAIN_VITE_', 'VITE_', 'ELECTRON_'],
build: {
rollupOptions: {
input: {
index: resolve(__dirname, 'src-electron/main/index.ts'),
},
lib: {
entry: resolve(__dirname, 'src-electron/main/index.ts'),
},
},
}
......@@ -28,10 +26,8 @@ export default defineConfig({
preload: {
plugins: [externalizeDepsPlugin()],
build: {
rollupOptions: {
input: {
index: resolve(__dirname, 'src-electron/preload/index.ts'),
},
lib: {
entry: resolve(__dirname, 'src-electron/preload/index.ts'),
},
},
},
......
......@@ -33,6 +33,7 @@
}
.app-loading {
visibility: hidden;
display: flex;
width: 100%;
height: 100%;
......@@ -95,7 +96,7 @@
height: 20px;
background-color: #0065cc;
border-radius: 100%;
opacity: 30%;
opacity: 0.3;
transform: scale(0.75);
animation: antSpinMove 1s infinite linear alternate;
transform-origin: 50% 50%;
......@@ -123,24 +124,28 @@
left: 0;
animation-delay: 1.2s;
}
@keyframes antRotate {
to {
transform: rotate(405deg);
}
}
@keyframes antRotate {
to {
transform: rotate(405deg);
}
}
@keyframes antSpinMove {
to {
opacity: 100%;
opacity: 1;
}
}
@keyframes antSpinMove {
to {
opacity: 100%;
opacity: 1;
}
}
</style>
......
......@@ -6,7 +6,9 @@ import type { MockMethod } from 'vite-plugin-mock'
* @param path 请求地址
* @returns 拼接 BASE_URL 后的请求地址
*/
export const URL = (path: string): string => `/basic-api${path}`
export function URL(path: string): string {
return `/basic-api${path}`
}
/**
* 通用响应工具类
......
import type { MockMethod } from 'vite-plugin-mock'
import { Response } from '../_util'
const demoList = (keyword, count = 20) => {
function demoList(keyword, count = 20) {
const result = {
list: [] as any[],
}
......
import type { MockMethod } from 'vite-plugin-mock'
import { Response } from '../_util'
const demoTreeList = (keyword) => {
function demoTreeList(keyword) {
const result = {
list: [] as Recordable[],
}
......
......@@ -4,7 +4,7 @@ import qs from 'qs'
import type { MockMethod } from 'vite-plugin-mock'
import { Request, Response } from '../_util'
const parseFormParams = (req: IncomingMessage): Promise<Recordable> => {
function parseFormParams(req: IncomingMessage): Promise<Recordable> {
return new Promise((resolve) => {
let body = ''
req.on('data', function (chunk) {
......
......@@ -66,137 +66,139 @@
"@ant-design/icons-vue": "^6.1.0",
"@electron-toolkit/preload": "^1.0.3",
"@electron-toolkit/utils": "^1.0.2",
"@iconify/iconify": "^3.1.0",
"@logicflow/core": "^1.2.1",
"@logicflow/extension": "^1.2.1",
"@iconify/iconify": "^3.1.1",
"@logicflow/core": "^1.2.10",
"@logicflow/extension": "^1.2.10",
"@purge-icons/generated": "^0.9.0",
"@stomp/stompjs": "^7.0.0",
"@vue/runtime-core": "^3.2.47",
"@vue/shared": "^3.2.47",
"@vueuse/core": "^9.13.0",
"@vueuse/shared": "^9.13.0",
"@vue/runtime-core": "^3.3.4",
"@vue/shared": "^3.3.4",
"@vueuse/core": "^10.3.0",
"@vueuse/electron": "^10.3.0",
"@vueuse/shared": "^10.3.0",
"@zxcvbn-ts/core": "^2.2.1",
"ant-design-vue": "^3.2.16",
"ant-design-vue": "^3.2.20",
"axios": "^0.26.1",
"codemirror": "^6.0.1",
"codemirror": "^5.65.14",
"cropperjs": "^1.5.13",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.7",
"dayjs": "^1.11.9",
"default-passive-events": "^2.0.0",
"echarts": "^5.4.2",
"intro.js": "^6.0.0",
"echarts": "^5.4.3",
"electron-log": "^4.4.8",
"electron-updater": "^5.3.0",
"intro.js": "^7.0.1",
"js-file-download": "^0.4.12",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nanoid": "^4.0.2",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
"pinia": "^2.0.33",
"pinia": "^2.1.6",
"print-js": "^1.6.0",
"qrcode": "^1.5.1",
"qs": "^6.11.1",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^2.1.0",
"sockjs-client": "^1.6.1",
"sortablejs": "^1.15.0",
"stompjs": "^2.3.3",
"tinymce": "^5.10.7",
"vditor": "^3.9.1",
"vue": "^3.2.47",
"vditor": "^3.9.4",
"vue": "^3.3.4",
"vue-i18n": "^9.2.2",
"vue-json-pretty": "^2.2.4",
"vue-router": "^4.1.6",
"vue-types": "^5.0.2",
"vue-router": "^4.2.4",
"vue-types": "^5.1.1",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@antfu/eslint-config": "^0.37.0",
"@commitlint/cli": "^17.5.1",
"@commitlint/config-conventional": "^17.4.4",
"@antfu/eslint-config": "^0.38.6",
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"@electron-toolkit/tsconfig": "^1.0.1",
"@electron/notarize": "^1.2.3",
"@iconify/json": "^2.2.40",
"@types/codemirror": "^5.60.7",
"@electron/notarize": "^2.1.0",
"@iconify/json": "^2.2.100",
"@types/codemirror": "^5.60.8",
"@types/crypto-js": "^4.1.1",
"@types/fs-extra": "^11.0.1",
"@types/inquirer": "^9.0.3",
"@types/intro.js": "^5.1.1",
"@types/lodash": "^4.14.192",
"@types/lodash-es": "^4.17.7",
"@types/lodash": "^4.14.197",
"@types/lodash-es": "^4.17.8",
"@types/mockjs": "^1.0.7",
"@types/node": "^18.15.10",
"@types/node": "^18.17.5",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.0",
"@types/qrcode": "^1.5.1",
"@types/qs": "^6.9.7",
"@types/showdown": "^2.0.0",
"@types/showdown": "^2.0.1",
"@types/sockjs-client": "^1.5.1",
"@types/sortablejs": "^1.15.1",
"@types/stompjs": "^2.3.5",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"@vitejs/plugin-legacy": "^4.0.2",
"@vitejs/plugin-vue": "^4.1.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-legacy": "^4.1.1",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/compiler-dom": "^3.2.47",
"@vue/compiler-sfc": "^3.2.47",
"@vue/test-utils": "^2.3.2",
"@vue/compiler-dom": "^3.3.4",
"@vue/compiler-sfc": "^3.3.4",
"@vue/test-utils": "^2.4.1",
"autoprefixer": "^10.4.14",
"commitizen": "^4.3.0",
"conventional-changelog-cli": "^2.2.2",
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.3.0",
"cz-git": "^1.6.1",
"czg": "^1.6.1",
"dotenv": "^16.0.3",
"electron": "^23.2.0",
"cz-git": "^1.7.1",
"czg": "^1.7.1",
"dotenv": "^16.3.1",
"electron": "^25.5.0",
"electron-builder": "^23.6.0",
"electron-vite": "^1.0.21",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0",
"electron-vite": "^1.0.27",
"eslint": "^8.47.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.10.0",
"eslint-plugin-vue": "^9.17.0",
"esno": "^0.16.3",
"fs-extra": "^11.1.1",
"husky": "^8.0.3",
"inquirer": "^9.1.5",
"less": "^4.1.3",
"lint-staged": "^13.2.0",
"inquirer": "^9.2.10",
"less": "^4.2.0",
"lint-staged": "^13.2.3",
"lodash": "^4.17.21",
"npm-run-all": "^4.1.5",
"picocolors": "^1.0.0",
"pont-engine": "^1.5.7",
"postcss": "^8.4.21",
"pont-engine": "^1.5.12",
"postcss": "^8.4.27",
"postcss-html": "^1.5.0",
"postcss-less": "^6.0.0",
"prettier": "^2.8.7",
"rimraf": "^4.4.1",
"rollup": "^2.79.1",
"rollup-plugin-visualizer": "^5.9.0",
"sort-package-json": "^2.4.1",
"stylelint": "^14.16.1",
"stylelint-config-prettier": "^9.0.5",
"stylelint-config-recommended": "^9.0.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^29.0.0",
"stylelint-order": "^5.0.0",
"terser": "^5.16.8",
"prettier": "^2.8.8",
"rimraf": "^5.0.1",
"rollup": "^3.28.0",
"rollup-plugin-visualizer": "^5.9.2",
"sort-package-json": "^2.5.1",
"stylelint": "^15.10.2",
"stylelint-config-recommended": "^12.0.0",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^33.0.0",
"stylelint-order": "^6.0.3",
"terser": "^5.19.2",
"ts-node": "^10.9.1",
"typescript": "^4.9.5",
"unplugin-auto-import": "^0.12.2",
"vite": "^4.2.1",
"unplugin-auto-import": "^0.16.6",
"vite": "^4.4.9",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0",
"vite-plugin-mkcert": "^1.13.4",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-mkcert": "^1.16.0",
"vite-plugin-mock": "^2.9.8",
"vite-plugin-purge-icons": "^0.9.2",
"vite-plugin-pwa": "^0.14.6",
"vite-plugin-pwa": "^0.16.4",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-theme": "^0.8.6",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vite-plugin-windicss": "^1.8.10",
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.2.0"
"vite-plugin-windicss": "^1.9.0",
"vue-eslint-parser": "^9.3.1",
"vue-tsc": "^1.8.8"
},
"engines": {
"node": ">=14"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,6 +8,7 @@ const API_URL_PREFIX = '/api'
export default class BasicGenerator extends CodeGenerator {
isRequestBody(inter: Interface, paramsCode: string): boolean {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const prettier = require('prettier')
const requestParams = inter.getRequestParams(this.surrounding)
const code = prettier.format(paramsCode, { parser: 'typescript' })
......@@ -23,6 +24,7 @@ export default class BasicGenerator extends CodeGenerator {
let requestParams = inter.getRequestParams(this.surrounding)
let bodyTypeDef = ''
// eslint-disable-next-line @typescript-eslint/no-require-imports
const prettier = require('prettier')
if (prettier.format(paramsCode, { parser: 'typescript' }).includes('{}')) {
if (!requestParams.includes('form')) {
......
import * as path from 'node:path'
import path from 'node:path'
import { BrowserWindow, app, shell } from 'electron'
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
......@@ -14,7 +14,7 @@ function createWindow(): void {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 900,
height: 670,
height: 680,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux'
......
import log from 'electron-log'
import { autoUpdater } from 'electron-updater'
import type { BrowserWindow } from 'electron'
import { ipcMain } from 'electron'
autoUpdater.logger = log
log.info('App starting...')
type MessageType =
| 'checking-for-update'
| 'error'
| 'update-available'
| 'update-not-available'
| 'download-progress'
| 'update-downloaded'
export async function useUpdater(win: BrowserWindow) {
function checkForUpdate() {
autoUpdater.checkForUpdates()
}
function sendUpdateMessageToWindow(body: { type: MessageType; text: string }) {
log.info(`${body.type}: ${body.text}`)
win.webContents.send('updater-message', body)
}
autoUpdater.on('checking-for-update', () => {
sendUpdateMessageToWindow({ type: 'checking-for-update', text: '正在检查更新...' })
})
autoUpdater.on('update-available', (info) => {
sendUpdateMessageToWindow({ type: 'update-available', text: `发现新版本 v${info.version}` })
})
autoUpdater.on('update-not-available', () => {
sendUpdateMessageToWindow({ type: 'update-not-available', text: '当前已是最新版本!' })
})
autoUpdater.on('error', (err) => {
sendUpdateMessageToWindow({ type: 'error', text: err.message })
})
autoUpdater.on('download-progress', (progress) => {
sendUpdateMessageToWindow({
type: 'download-progress',
text: `正在下载新版本 ${Number(progress.percent).toFixed(2)}%`,
})
})
autoUpdater.on('update-downloaded', () => {
sendUpdateMessageToWindow({ type: 'update-downloaded', text: '下载完成' })
setTimeout(() => {
// 退出并安装更新包
autoUpdater.quitAndInstall(false, true)
win.destroy()
}, 1500)
})
// 监听界面发送的检查更新事件
ipcMain.on('checkForUpdate', () => {
checkForUpdate()
})
// 检查更新
checkForUpdate()
}
......@@ -20,3 +20,98 @@ if (process.contextIsolated) {
// @ts-expect-error (define in dts)
window.api = api
}
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
return new Promise((resolve) => {
if (condition.includes(document.readyState)) {
resolve(true)
} else {
document.addEventListener('readystatechange', () => {
if (condition.includes(document.readyState)) {
resolve(true)
}
})
}
})
}
const safeDOM = {
append(parent: HTMLElement, child: HTMLElement) {
if (!Array.from(parent.children).find((e) => e === child)) {
parent.appendChild(child)
}
},
remove(parent: HTMLElement, child: HTMLElement) {
if (Array.from(parent.children).find((e) => e === child)) {
parent.removeChild(child)
}
},
}
/**
* https://tobiasahlin.com/spinkit
* https://connoratherton.com/loaders
* https://projects.lukehaas.me/css-loaders
* https://matejkustec.github.io/SpinThatShit
*/
function useLoading() {
const className = `loaders-css__square-spin`
const styleContent = `
@keyframes square-spin {
25% { transform: perspective(100px) rotateX(180deg) rotateY(0); }
50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
75% { transform: perspective(100px) rotateX(0) rotateY(180deg); }
100% { transform: perspective(100px) rotateX(0) rotateY(0); }
}
.${className} > div {
animation-fill-mode: both;
width: 50px;
height: 50px;
background: #fff;
animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
}
.app-loading-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #282c34;
z-index: 9999;
-webkit-app-region: drag;
cursor: pointer;
}
`
const oStyle = document.createElement('style')
const oDiv = document.createElement('div')
oStyle.id = 'app-loading-style'
oStyle.innerHTML = styleContent
oDiv.className = 'app-loading-wrap'
oDiv.innerHTML = `<div class="${className}"><div></div></div>`
return {
appendLoading() {
safeDOM.append(document.head, oStyle)
safeDOM.append(document.body, oDiv)
},
removeLoading() {
safeDOM.remove(document.head, oStyle)
safeDOM.remove(document.body, oDiv)
},
}
}
// ----------------------------------------------------------------------
const { appendLoading, removeLoading } = useLoading()
domReady().then(appendLoading)
window.onmessage = (ev: any) => {
ev.data.payload === 'loaded' && removeLoading()
}
// setTimeout(removeLoading, 30 * 1000)
......@@ -5,6 +5,7 @@
import { useLocale } from '/@/locales/useLocale'
import 'dayjs/locale/zh-cn'
// support Multi-language
const { getAntdLocale } = useLocale()
......
......@@ -9,4 +9,6 @@ enum Api {
* @description: Trigger ajax error
*/
export const fireErrorApi = () => defHttp.get({ url: Api.Error })
export function fireErrorApi() {
return defHttp.get({ url: Api.Error })
}
......@@ -9,6 +9,6 @@ enum Api {
* @description: Get user menu based on id
*/
export const getMenuList = () => {
export function getMenuList() {
return defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList })
}
import type { RouteMeta } from 'vue-router'
export interface RouteItem {
path: string
component: any
......
body {
display: flex;
flex-direction: column;
font-family: Roboto, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Segoe UI', Oxygen, Ubuntu, Cantarell,
'Open Sans', sans-serif;
color: #86a5b1 !important;
background-color: #2f3241 !important;
}
* {
padding: 0;
margin: 0;
}
ul {
list-style: none;
}
code {
font-weight: 600;
padding: 3px 5px;
border-radius: 2px;
background-color: #26282e;
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
font-size: 85%;
}
a {
color: #9feaf9;
font-weight: 600;
cursor: pointer;
text-decoration: none;
outline: none;
}
a:hover {
border-bottom: 1px solid;
}
#app {
flex: 1;
display: flex;
flex-direction: column;
max-width: 840px;
margin: 0 auto;
padding: 15px 30px 0;
}
.versions {
margin: 0 auto;
float: none;
clear: both;
overflow: hidden;
font-family: Menlo, 'Lucida Console', monospace;
color: #c2f5ff;
line-height: 1;
transition: all 0.3s;
li {
display: block;
float: left;
border-right: 1px solid rgb(194 245 255 / 40%);
padding: 0 20px;
font-size: 13px;
opacity: 0.8;
&:last-child {
border: none;
}
}
}
.hero-logo {
margin-top: -0.4rem;
transition: all 0.3s;
}
@media (max-width: 840px) {
.versions {
display: none;
}
.hero-logo {
margin-top: -1.5rem;
}
}
.hero-text {
font-weight: 400;
color: #c2f5ff;
text-align: center;
margin-top: -0.5rem;
margin-bottom: 10px;
}
@media (max-width: 660px) {
.hero-logo {
display: none;
}
.hero-text {
margin-top: 20px;
}
}
.hero-tagline {
text-align: center;
margin-bottom: 14px;
}
.links {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
font-size: 18px;
font-weight: 500;
a {
font-weight: 500;
}
.link-item {
padding: 0 4px;
}
}
.features {
display: flex;
flex-wrap: wrap;
margin: -6px;
.feature-item {
width: 33.33%;
box-sizing: border-box;
padding: 6px;
}
article {
background-color: rgb(194 245 255 / 10%);
border-radius: 8px;
box-sizing: border-box;
padding: 12px;
height: 100%;
}
span {
color: #d4e8ef;
word-break: break-all;
}
.title {
font-size: 17px;
font-weight: 500;
color: #c2f5ff;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.detail {
font-size: 14px;
font-weight: 500;
line-height: 22px;
margin-top: 6px;
}
}
@media (max-width: 660px) {
.features .feature-item {
width: 50%;
}
}
@media (max-width: 480px) {
.links {
flex-direction: column;
line-height: 32px;
.link-dot {
display: none;
}
}
.features .feature-item {
width: 100%;
}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol id="electron" viewBox="0 0 900 300">
<g fill="none" fill-rule="evenodd">
<g class="hero-apps" style="fill: #71abb7;">
<path d="M15 138l-4.9-.64L8 133l-2.1 4.36L1 138l3.6 3.26-.93 4.74L8 143.67l4.33 2.33-.93-4.74z"></path>
<path d="M897.2 114.0912l-5.2 3.63v-2.72c0-.55-.45-1-1-1h-8c-.55 0-1 .45-1 1v9c0 .55.45 1 1 1h8c.55 0 1-.45 1-1v-2.72l5.2 3.63c.33.23.8 0 .8-.41v-10c0-.41-.47-.64-.8-.41z"></path>
<path d="M65.4 188.625h-1.6c.88 0 1.6-.7313 1.6-1.625v-1.625c0-.8937-.72-1.625-1.6-1.625h-1.6c-.88 0-1.6.7313-1.6 1.625V187c0 .8937.72 1.625 1.6 1.625h-1.6c-.88 0-1.6.7313-1.6 1.625v3.25h1.6v4.875c0 .8937.72 1.625 1.6 1.625h1.6c.88 0 1.6-.7313 1.6-1.625V193.5H67v-3.25c0-.8937-.72-1.625-1.6-1.625zm-3.2-3.25h1.6V187h-1.6v-1.625zm3.2 6.5h-1.6v6.5h-1.6v-6.5h-1.6v-1.625h4.8v1.625zm3.344-5.6875c0-3.2175-2.576-5.8337-5.744-5.8337-3.168 0-5.744 2.6162-5.744 5.8337 0 .455.048.8937.144 1.3162v3.2175c-.976-1.2512-1.6-2.8112-1.6-4.55 0-4.03 3.232-7.3125 7.2-7.3125s7.2 3.2825 7.2 7.3125c0 1.7225-.624 3.2988-1.6 4.55v-3.2175c.096-.4387.144-.8612.144-1.3162zm6.256 0c0 4.68-2.608 8.7425-6.4 10.7738v-1.7063c2.976-1.885 4.944-5.2325 4.944-9.0675 0-5.915-4.72-10.7087-10.544-10.7087-5.824 0-10.544 4.7937-10.544 10.7087 0 3.835 1.968 7.1825 4.944 9.0675v1.7063c-3.792-2.0313-6.4-6.0938-6.4-10.7738C51 179.46 56.376 174 63 174s12 5.46 12 12.1875z"></path>
<path d="M830.7143 142.3333c-.8643 0-1.5714.7125-1.5714 1.5834v3.1666c0 .871.707 1.5834 1.5713 1.5834h12.5714c.8643 0 1.5714-.7125 1.5714-1.5834v-3.1666c0-.871-.707-1.5834-1.5713-1.5834h-12.5714zm12.5714 2.771l-1.9643 1.979h-2.357L837 145.1043l-1.9643 1.979h-2.357l-1.9644-1.979v-1.1876h1.1786l1.964 1.979 1.9644-1.979h2.3572l1.9643 1.979 1.964-1.979h1.1787v1.1875zm-9.4286 5.1457h6.286v1.5833h-6.286V150.25zM837 136c-6.0657 0-11 4.6075-11 10.2917v7.125c0 .8708.707 1.5833 1.5714 1.5833h18.8572c.8643 0 1.5714-.7125 1.5714-1.5833v-7.125C848 140.6075 843.0657 136 837 136zm9.4286 17.4167h-18.8572v-7.125c0-4.8925 4.1486-8.851 9.4286-8.851 5.28 0 9.4286 3.9585 9.4286 8.851v7.125z"></path>
<path d="M75 91.8065V96h4.1935L90.376 84.8174l-4.1934-4.1935L75 91.8064zm4.1935 2.7957h-2.7957v-2.7957h1.398v1.3978h1.3977v1.398zM93.591 81.6024l-1.817 1.817-4.1935-4.1934 1.817-1.817c.5453-.5453 1.426-.5453 1.971 0l2.2226 2.2224c.5453.5452.5453 1.4258 0 1.971z"></path>
<path d="M797 187h4v4h-4v-4zm12-1v19c0 1.1-.9 2-2 2h-20c-1.1 0-2-.9-2-2v-24c0-1.1.9-2 2-2h15l7 7zm-2 1l-6-6h-14v22l6-10 4 8 4-4 6 6v-16z"></path>
<path d="M138 125c-6.62 0-12 5-12 11 0 9.04 12 21 12 21s12-11.96 12-21c0-6-5.38-11-12-11zm0 29.1c-3.72-4.06-10-12.22-10-18.1 0-4.96 4.5-9 10-9 2.68 0 5.22.96 7.12 2.72 1.84 1.72 2.88 3.94 2.88 6.28 0 5.88-6.28 14.04-10 18.1zm4-18.1c0 2.22-1.78 4-4 4-2.22 0-4-1.78-4-4 0-2.22 1.78-4 4-4 2.22 0 4 1.78 4 4z"></path>
<path d="M771 82h8v2h-8v-2zm0 6h8v-2h-8v2zm0 4h8v-2h-8v2zm22-10h-8v2h8v-2zm0 4h-8v2h8v-2zm0 4h-8v2h8v-2zm4-12v18c0 1.1-.9 2-2 2h-11l-2 2-2-2h-11c-1.1 0-2-.9-2-2V78c0-1.1.9-2 2-2h11l2 2 2-2h11c1.1 0 2 .9 2 2zm-16 1l-1-1h-11v18h12V79zm14-1h-11l-1 1v17h12V78z"></path>
<path d="M176 203h-24c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4v7l7-7h13c1.1 0 2-.9 2-2v-16c0-1.1-.9-2-2-2zm0 18h-14l-4 4v-4h-6v-16h24v16z"></path>
<path d="M673 88.921c0 2.18-.9 4.18-2.34 5.66l-1.34-1.34c1.1-1.12 1.78-2.62 1.78-4.32 0-1.7-.68-3.22-1.78-4.32l1.34-1.34c1.44 1.44 2.34 3.44 2.34 5.66zm-8.56-11.48l-7.44 7.44h-4c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h4l7.44 7.44c.94.94 2.56.28 2.56-1.06v-20.76c0-1.34-1.62-2-2.56-1.06zm11.88.16l-1.34 1.34c2.56 2.56 4.12 6.06 4.12 9.96 0 3.88-1.56 7.4-4.12 9.96l1.34 1.34c2.9-2.9 4.68-6.9 4.68-11.32 0-4.44-1.78-8.44-4.68-11.32v.04zm-2.82 2.82l-1.38 1.34c1.84 1.84 2.96 4.38 2.96 7.16 0 2.78-1.12 5.32-2.96 7.12l1.38 1.34c2.16-2.16 3.5-5.16 3.5-8.46 0-3.3-1.34-6.32-3.5-8.5z"></path>
<path d="M226 79h-16c0-1.1-.9-2-2-2h-8c-1.1 0-2 .9-2 2-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h28c1.1 0 2-.9 2-2V81c0-1.1-.9-2-2-2zm-18 4h-8v-2h8v2zm9 14c-3.88 0-7-3.12-7-7s3.12-7 7-7 7 3.12 7 7-3.12 7-7 7zm5-7c0 2.76-2.26 5-5 5s-5-2.26-5-5 2.26-5 5-5 5 2.26 5 5z"></path>
<path d="M725.8393 157h-15.6498c-1.1807 0-1.1807-.82-1.1807-2 0-1.18 0-2 1.1807-2h15.6298C727 153 727 153.82 727 155c0 1.18 0 2-1.1807 2h.02zm-11.6473-10c-1.1807 0-1.1807-.82-1.1807-2 0-1.18 0-2 1.1807-2h11.6273C727 143 727 143.82 727 145c0 1.18 0 2-1.1807 2H714.192zM695 146.82l2.8218-2.6 3.182 3.18 8.185-8.4 2.8218 2.82-11.0068 11-6.0038-6zM710.1895 163h15.6298C727 163 727 163.82 727 165c0 1.18 0 2-1.1807 2h-15.6298c-1.1807 0-1.1807-.82-1.1807-2 0-1.18 0-2 1.1807-2z"></path>
<path d="M223 152v24c0 1.65 1.35 3 3 3h36c1.65 0 3-1.35 3-3v-24c0-1.65-1.35-3-3-3h-36c-1.65 0-3 1.35-3 3zm39 0l-18 15-18-15h36zm-36 4.5l12 9-12 9v-18zm3 19.5l10.5-9 4.5 4.5 4.5-4.5 10.5 9h-30zm33-1.5l-12-9 12-9v18z"></path>
<path d="M648 182h-3v4.5c0 .84-.66 1.5-1.5 1.5h-6c-.84 0-1.5-.66-1.5-1.5V182h-9v4.5c0 .84-.66 1.5-1.5 1.5h-6c-.84 0-1.5-.66-1.5-1.5V182h-3c-1.65 0-3 1.35-3 3v33c0 1.65 1.35 3 3 3h33c1.65 0 3-1.35 3-3v-33c0-1.65-1.35-3-3-3zm0 36h-33v-27h33v27zm-24-33h-3v-6h3v6zm18 0h-3v-6h3v6zm-15 12h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm-24 6h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm-24 6h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm-24 6h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3zm6 0h-3v-3h3v3z"></path>
</g>
<g class="hero-icons" style="fill: #c2f5ff;">
<path d="M441.1132 69.724c7.681 0 13.9075-6.207 13.9075-13.8636 0-7.6565-6.2266-13.8634-13.9075-13.8634-7.681 0-13.9076 6.207-13.9076 13.8634 0 7.6566 6.2266 13.8635 13.9076 13.8635zm0-5.7932c-4.4713 0-8.096-3.6132-8.096-8.0704 0-4.457 3.6247-8.0703 8.096-8.0703 4.4712 0 8.096 3.6133 8.096 8.0704 0 4.4572-3.6248 8.0704-8.096 8.0704z"></path>
<path d="M354.8995 220.2693c7.681 0 13.9075-6.207 13.9075-13.8635s-6.2266-13.8634-13.9075-13.8634c-7.681 0-13.9075 6.207-13.9075 13.8634 0 7.6566 6.2266 13.8635 13.9075 13.8635zm0-5.793c-4.4713 0-8.096-3.6133-8.096-8.0705 0-4.457 3.6247-8.0703 8.096-8.0703s8.096 3.6132 8.096 8.0703c0 4.4572-3.6247 8.0704-8.096 8.0704z"></path>
<path d="M541.0343 206.4058c0-7.6565-6.2266-13.8634-13.9075-13.8634-7.681 0-13.9075 6.207-13.9075 13.8634 0 7.6566 6.2266 13.8635 13.9075 13.8635 7.681 0 13.9075-6.207 13.9075-13.8635zm-5.8115 0c0 4.4572-3.6247 8.0704-8.096 8.0704s-8.096-3.6132-8.096-8.0704c0-4.457 3.6247-8.0703 8.096-8.0703s8.096 3.6132 8.096 8.0703z"></path>
<path d="M397.6943 214.5258c9.7012 27.0033 25.5723 43.629 43.419 43.629 13.0157 0 25.0578-8.8443 34.4482-24.4154.827-1.371.3822-3.1507-.9932-3.975-1.3755-.824-3.1607-.3808-3.9876.9902-8.439 13.9938-18.8052 21.6072-29.4675 21.6072-14.8247 0-28.9803-14.8288-37.9476-39.7892-.541-1.506-2.2044-2.2897-3.7153-1.7504-1.511.5394-2.297 2.1975-1.756 3.7036z"></path>
<path d="M514.124 163.4733c18.5545-21.85 25.033-43.826 16.122-59.2117-6.557-11.321-20.419-17.2982-38.841-17.537-1.6047-.021-2.9225 1.259-2.9434 2.8586-.0208 1.5996 1.263 2.9132 2.8678 2.934 16.5683.2148 28.5106 5.3642 33.8836 14.641 7.4018 12.7797 1.6243 32.3774-15.5247 52.5722-1.037 1.221-.8844 3.0487.3405 4.0822 1.2248 1.0336 3.0584.8817 4.0952-.3393z"></path>
<path d="M411.5672 88.457c-28.3373-5.1448-50.7424.24-59.672 15.6575-6.6635 11.505-4.7588 26.7585 4.6193 43.0637.7982 1.3878 2.574 1.8678 3.966 1.072 1.3923-.7956 1.874-2.5656 1.0756-3.9534-8.4477-14.688-10.0915-27.8524-4.628-37.2857 7.418-12.8074 27.403-17.6105 53.5978-12.8546 1.579.2866 3.092-.7568 3.3794-2.3307.2876-1.5738-.7592-3.082-2.338-3.3687z"></path>
<path d="M486.3075 209.2436c5.022-15.998 7.7194-34.453 7.7194-53.6842 0-47.9875-16.849-89.3545-40.8478-99.977-1.4667-.649-3.1837.0098-3.835 1.472-.6512 1.462.01 3.1735 1.4766 3.8227 21.404 9.474 37.3945 48.7337 37.3945 94.6824 0 18.6574-2.612 36.5297-7.454 51.954-.4794 1.5268.3736 3.1518 1.9052 3.6295s3.1617-.3727 3.641-1.8994z"></path>
<path d="M466.439 89.4215c-16.7763 3.583-34.6332 10.5886-51.7827 20.4585-42.434 24.4216-70.1147 60.4323-66.2703 86.5432.233 1.5828 1.709 2.6776 3.297 2.4453 1.5877-.2323 2.686-1.7037 2.453-3.2865-3.4135-23.1838 22.825-57.3183 63.426-80.685 16.6365-9.5746 33.9267-16.3578 50.0946-19.811 1.5692-.335 2.5687-1.8748 2.2325-3.439-.336-1.5642-1.8807-2.5606-3.45-2.2255z"></path>
<path d="M371.2508 166.997c11.458 12.5516 26.3438 24.3243 43.3203 34.0947 41.106 23.6572 84.866 29.9805 106.4328 15.3217 1.326-.9013 1.668-2.7033.7638-4.025-.904-1.3217-2.712-1.6626-4.0378-.7614-19.302 13.1195-60.871 7.1128-100.253-15.5523-16.469-9.4783-30.8834-20.8782-41.9277-32.9767-1.08-1.1832-2.9178-1.2695-4.1048-.1928-1.187 1.0766-1.2735 2.9086-.1934 4.0918z"></path>
<path d="M443.2374 165.3634c-5.432 1.17-10.7838-2.2712-11.9598-7.686-1.1714-5.415 2.2785-10.7498 7.7106-11.922 5.432-1.17 10.7838 2.2712 11.9598 7.686 1.1737 5.415-2.2785 10.7498-7.7106 11.922z"></path>
</g>
</g>
</symbol>
</svg>
......@@ -2,6 +2,7 @@
import AppSearchKeyItem from './AppSearchKeyItem.vue'
import { useDesign } from '/@/hooks/web/useDesign'
import { useI18n } from '/@/hooks/web/useI18n'
const { prefixCls } = useDesign('app-search-footer')
const { t } = useI18n()
</script>
......
<script lang="ts" setup>
import { Icon } from '/@/components/Icon'
defineProps({
icon: String,
})
......
......@@ -3,6 +3,7 @@
import { SearchOutlined } from '@ant-design/icons-vue'
import AppSearchFooter from './AppSearchFooter.vue'
import Icon from '/@/components/Icon'
// @ts-expect-error
import vClickOutside from '/@/directives/clickOutside'
import { useDesign } from '/@/hooks/web/useDesign'
......@@ -163,7 +164,7 @@
&__item {
&-enter {
opacity: 0% !important;
opacity: 0 !important;
}
}
}
......@@ -249,7 +250,7 @@
background-color: @primary-color;
.@{prefix-cls}-list__item-enter {
opacity: 100%;
opacity: 1;
}
}
......@@ -263,7 +264,7 @@
&-enter {
width: 30px;
opacity: 0%;
opacity: 0;
}
}
}
......
......@@ -8,6 +8,7 @@
import { Button } from '/@/components/Button'
import { isFunction } from '/@/utils/is'
import { grid, useSlider } from './data'
// 组件接收参数
const props = defineProps({
// 请求API的参数
......
import { ref } from 'vue'
// 每行个数
export const grid = ref(12)
// slider属性
export const useSlider = (min = 6, max = 12) => {
export function useSlider(min = 6, max = 12) {
// 每行显示个数滑动条
const getMarks = () => {
const l = {}
......
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
const emit = defineEmits(['mounted', 'clickOutside'])
const wrap = ref<ElRef>(null)
......
......@@ -5,10 +5,12 @@
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'
import CodeMirror from 'codemirror'
import { MODE } from './../typing'
// css
import './codemirror.css'
import 'codemirror/theme/idea.css'
import 'codemirror/theme/material-palenight.css'
// modes
import 'codemirror/mode/javascript/javascript'
import 'codemirror/mode/css/css'
......
......@@ -2,12 +2,14 @@ import CodeMirror from 'codemirror'
import './codemirror.css'
import 'codemirror/theme/idea.css'
import 'codemirror/theme/material-palenight.css'
// import 'codemirror/addon/lint/lint.css';
// modes
import 'codemirror/mode/javascript/javascript'
import 'codemirror/mode/css/css'
import 'codemirror/mode/htmlmixed/htmlmixed'
// addons
// import 'codemirror/addon/edit/closebrackets';
// import 'codemirror/addon/edit/closetag';
......
......@@ -2,14 +2,17 @@
import type { PropType } from 'vue'
import { ref } from 'vue'
import { isNil } from 'lodash-es'
// component
import { Skeleton } from 'ant-design-vue'
import { CollapseTransition } from '/@/components/Transition'
import CollapseHeader from './CollapseHeader.vue'
import { triggerWindowResize } from '/@/utils/event'
import { triggerWindowResize as triggerWindowResizeFn } from '/@/utils/event'
// hook
import { useTimeoutFn } from '/@/hooks/core/useTimeout'
import { useDesign } from '/@/hooks/web/useDesign'
const props = defineProps({
title: { type: String, default: '' },
loading: { type: Boolean },
......@@ -43,7 +46,7 @@
show.value = isNil(val) ? !show.value : val
if (props.triggerWindowResize) {
// 200 milliseconds here is because the expansion has animation,
useTimeoutFn(triggerWindowResize, 200)
useTimeoutFn(triggerWindowResizeFn, 200)
}
}
defineExpose({
......
......@@ -4,6 +4,7 @@
import Icon from '/@/components/Icon'
import { Divider, Menu } from 'ant-design-vue'
import type { Axis, ContextMenuItem, ItemContentProps } from './typing'
const prefixCls = 'context-menu'
const props = {
width: { type: Number, default: 156 },
......
......@@ -8,13 +8,14 @@
import { useI18n } from '/@/hooks/web/useI18n'
import type { ButtonProps } from '/@/components/Button'
import Icon from '/@/components/Icon'
const props = {
width: { type: [String, Number], default: '200px' },
value: { type: String },
showBtn: { type: Boolean, default: true },
btnProps: { type: Object as PropType<ButtonProps> },
btnText: { type: String, default: '' },
uploadApi: { type: Function as PropType<({ file: Blob, name: string }) => Promise<void>> },
uploadApi: { type: Function as PropType<(param: { file: Blob; name: string }) => Promise<void>> },
}
export default defineComponent({
name: 'CropperAvatar',
......@@ -29,7 +30,7 @@
const { t } = useI18n()
const getClass = computed(() => [prefixCls])
const getWidth = computed(() => `${`${props.width}`.replace(/px/, '')}px`)
const getIconWidth = computed(() => `${parseInt(`${props.width}`.replace(/px/, '')) / 2}px`)
const getIconWidth = computed(() => `${Number.parseInt(`${props.width}`.replace(/px/, '')) / 2}px`)
const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }))
const getImageWrapperStyle = computed(
(): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }),
......@@ -110,7 +111,7 @@
}
&-image-mask {
opacity: 0%;
opacity: 0;
position: absolute;
width: inherit;
height: inherit;
......@@ -126,7 +127,7 @@
}
&-image-mask:hover {
opacity: 4000%;
opacity: 40;
}
&-upload-btn {
......
......@@ -11,6 +11,7 @@
import { isFunction } from '/@/utils/is'
import { getSlot } from '/@/utils/helper/tsxHelper'
import { useAttrs } from '/@/hooks/core/useAttrs'
const props = {
useCollapse: { type: Boolean, default: true },
title: { type: String, default: '' },
......
......@@ -4,6 +4,7 @@
import { useDesign } from '/@/hooks/web/useDesign'
import { footerProps } from '../props'
export default defineComponent({
name: 'BasicDrawerFooter',
props: {
......
......@@ -6,6 +6,7 @@
import { useDesign } from '/@/hooks/web/useDesign'
import { propTypes } from '/@/utils/propTypes'
export default defineComponent({
name: 'BasicDrawerHeader',
components: { BasicTitle, ArrowLeftOutlined },
......
import type { PropType } from 'vue'
import { useI18n } from '/@/hooks/web/useI18n'
const { t } = useI18n()
export const footerProps = {
......
......@@ -88,7 +88,7 @@ export function useDrawer(): UseDrawerReturnType {
return [register, methods]
}
export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
export function useDrawerInner(callbackFn?: Fn): UseDrawerInnerReturnType {
const drawerInstanceRef = ref<Nullable<DrawerInstance>>(null)
const currentInstance = getCurrentInstance()
const uidRef = ref<string>('')
......
......@@ -52,7 +52,9 @@
}
})
const getAttr = (key: string | number) => ({ key })
function getAttr(key: string | number) {
return { key }
}
</script>
<template>
......
......@@ -3,6 +3,7 @@
import * as XLSX from 'xlsx'
import { dateUtil } from '/@/utils/dateUtil'
import type { ExcelData } from './typing'
export default defineComponent({
name: 'ImportExcel',
props: {
......
......@@ -10,6 +10,7 @@
import FormAction from './components/FormAction.vue'
import { dateItemType } from './helper'
import { dateUtil } from '/@/utils/dateUtil'
// import { cloneDeep } from 'lodash-es';
import { deepMerge } from '/@/utils'
import { useFormValues } from './hooks/useFormValues'
......@@ -20,6 +21,7 @@
import { useModalContext } from '/@/components/Modal'
import { basicProps } from './props'
import { useDesign } from '/@/hooks/web/useDesign'
export default defineComponent({
name: 'BasicForm',
components: { FormItem, Form, Row, FormAction },
......
......@@ -8,6 +8,7 @@
import { useRuleFormItem } from '/@/hooks/component/useFormItem'
import { LoadingOutlined } from '@ant-design/icons-vue'
import { useI18n } from '/@/hooks/web/useI18n'
interface Option {
value: string
label: string
......
......@@ -11,6 +11,7 @@
import { propTypes } from '/@/utils/propTypes'
import { get, omit } from 'lodash-es'
import { useI18n } from '/@/hooks/web/useI18n'
interface OptionsItem {
label: string
value: string | number | boolean
......
......@@ -9,6 +9,7 @@
import { LoadingOutlined } from '@ant-design/icons-vue'
import { useI18n } from '/@/hooks/web/useI18n'
import { propTypes } from '/@/utils/propTypes'
interface OptionsItem {
label: string
value: string
......
......@@ -6,6 +6,7 @@
import { propTypes } from '/@/utils/propTypes'
import { useI18n } from '/@/hooks/web/useI18n'
import type { TransferDirection, TransferItem } from 'ant-design-vue/lib/transfer'
export default defineComponent({
name: 'ApiTransfer',
components: { Transfer },
......
......@@ -5,6 +5,7 @@
import { get } from 'lodash-es'
import { propTypes } from '/@/utils/propTypes'
import { LoadingOutlined } from '@ant-design/icons-vue'
export default defineComponent({
name: 'ApiTree',
components: { ATree: Tree, LoadingOutlined },
......
......@@ -5,6 +5,7 @@
import { get } from 'lodash-es'
import { propTypes } from '/@/utils/propTypes'
import { LoadingOutlined } from '@ant-design/icons-vue'
export default defineComponent({
name: 'ApiTreeSelect',
components: { ATreeSelect: TreeSelect, LoadingOutlined },
......
<script lang="ts">
import type { ColEx } from '../types/index'
// import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
import type { PropType } from 'vue'
import { computed, defineComponent } from 'vue'
......
......@@ -13,6 +13,7 @@
import { cloneDeep, upperFirst } from 'lodash-es'
import { useItemLabelWidth } from '../hooks/useLabelWidth'
import { useI18n } from '/@/hooks/web/useI18n'
export default defineComponent({
name: 'BasicFormItem',
inheritAttrs: false,
......
......@@ -60,15 +60,15 @@ export default function ({ advanceState, emit, getProps, getSchema, formModel, d
const width = unref(realWidthRef)
const mdWidth =
parseInt(itemCol.md as string) ||
parseInt(itemCol.xs as string) ||
parseInt(itemCol.sm as string) ||
Number.parseInt(itemCol.md as string) ||
Number.parseInt(itemCol.xs as string) ||
Number.parseInt(itemCol.sm as string) ||
(itemCol.span as number) ||
BASIC_COL_LEN
const lgWidth = parseInt(itemCol.lg as string) || mdWidth
const xlWidth = parseInt(itemCol.xl as string) || lgWidth
const xxlWidth = parseInt(itemCol.xxl as string) || xlWidth
const lgWidth = Number.parseInt(itemCol.lg as string) || mdWidth
const xlWidth = Number.parseInt(itemCol.xl as string) || lgWidth
const xxlWidth = Number.parseInt(itemCol.xxl as string) || xlWidth
if (width <= screenEnum.LG) {
itemColSum += mdWidth
} else if (width < screenEnum.XL) {
......
......@@ -2,7 +2,7 @@
import type { CSSProperties, PropType } from 'vue'
import { computed, defineComponent, nextTick, onMounted, ref, unref, watch } from 'vue'
import SvgIcon from './SvgIcon.vue'
import Iconify from '@purge-icons/generated'
import Iconify from '@iconify/iconify/dist/iconify'
import { isString } from '/@/utils/is'
import { propTypes } from '/@/utils/propTypes'
......@@ -57,7 +57,7 @@
const { size, color } = props
let fs = size
if (isString(size)) {
fs = parseInt(size, 10)
fs = Number.parseInt(size, 10)
}
return {
......
......@@ -54,7 +54,7 @@
display: inline-block;
overflow: hidden;
vertical-align: -0.15em;
fill: currentColor;
fill: currentcolor;
}
.svg-icon-spin {
......
......@@ -8,6 +8,7 @@
import { useRootSetting } from '/@/hooks/setting/useRootSetting'
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'
import { getTheme } from './getTheme'
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined
export default defineComponent({
inheritAttrs: false,
......
......@@ -5,6 +5,7 @@
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'
import { useRootSetting } from '/@/hooks/setting/useRootSetting'
import { getTheme } from './getTheme'
const props = defineProps({
value: { type: String },
class: { type: String },
......
......@@ -3,10 +3,10 @@
* @param darkModeVal 深色模式值
* @param themeMode 主题类型——外观(默认), 内容, 代码块
*/
export const getTheme = (
export function getTheme(
darkModeVal: 'light' | 'dark' | string,
themeMode: 'default' | 'content' | 'code' = 'default',
) => {
) {
const isDark = darkModeVal === 'dark'
switch (themeMode) {
case 'default':
......
import type Vditor from 'vditor'
export interface MarkDownActionType {
getVditor: () => Vditor
}
......@@ -4,6 +4,7 @@
import { itemProps } from '../props'
import MenuItemContent from './MenuItemContent.vue'
export default defineComponent({
name: 'BasicMenuItem',
components: { MenuItem: Menu.Item, MenuItemContent },
......
......@@ -5,6 +5,7 @@
import { useI18n } from '/@/hooks/web/useI18n'
import { useDesign } from '/@/hooks/web/useDesign'
import { contentProps } from '../props'
const { t } = useI18n()
export default defineComponent({
......
......@@ -6,6 +6,7 @@ import { ThemeEnum } from '/@/enums/appEnum'
import { propTypes } from '/@/utils/propTypes'
import type { MenuTheme } from 'ant-design-vue'
import type { MenuMode } from 'ant-design-vue/lib/menu/src/interface'
export const basicProps = {
items: {
type: Array as PropType<Menu[]>,
......
......@@ -2,6 +2,7 @@
import { defineComponent } from 'vue'
import { basicProps } from '../props'
export default defineComponent({
name: 'BasicModalFooter',
props: basicProps,
......
......@@ -84,7 +84,7 @@ export function useModal(): UseModalReturnType {
return [register, methods]
}
export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
export function useModalInner(callbackFn?: Fn): UseModalInnerReturnType {
const modalInstanceRef = ref<Nullable<ModalMethods>>(null)
const currentInstance = getCurrentInstance()
const uidRef = ref<string>('')
......
......@@ -2,10 +2,7 @@
overflow: hidden;
.ant-modal {
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
inset: 0 !important;
width: 100% !important;
height: 100%;
......@@ -110,17 +107,20 @@
.ant-modal-confirm .ant-modal-body {
padding: 24px !important;
}
@media screen and (max-height: 600px) {
@media screen and (min-height: 600px) {
.ant-modal {
top: 60px;
}
}
@media screen and (max-height: 540px) {
@media screen and (min-height: 540px) {
.ant-modal {
top: 30px;
}
}
@media screen and (max-height: 480px) {
@media screen and (min-height: 480px) {
.ant-modal {
top: 10px;
}
......
import type { ButtonProps } from 'ant-design-vue/lib/button/buttonTypes'
import type { CSSProperties, ComputedRef, VNodeChild } from 'vue'
/**
* @description: 弹窗对外暴露的方法
*/
......
......@@ -414,10 +414,7 @@
<style lang="less">
.img-preview {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
inset: 0;
z-index: @preview-comp-z-index;
background: rgb(0 0 0 / 50%);
user-select: none;
......
......@@ -3,7 +3,7 @@ import type { QRCodeRenderersOptions } from 'qrcode'
import { cloneDeep } from 'lodash-es'
import type { ContentType, RenderQrCodeParams } from './typing'
export const renderQrCode = ({ canvas, content, width = 0, options: params = {} }: RenderQrCodeParams) => {
export function renderQrCode({ canvas, content, width = 0, options: params = {} }: RenderQrCodeParams) {
const options = cloneDeep(params)
// 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(content)
......
import { isString } from '/@/utils/is'
import type { LogoType, RenderQrCodeParams } from './typing'
export const drawLogo = ({ canvas, logo }: RenderQrCodeParams) => {
export function drawLogo({ canvas, logo }: RenderQrCodeParams) {
if (!logo) {
return new Promise((resolve) => {
resolve((canvas as HTMLCanvasElement).toDataURL())
......
// 参考 qr-code-with-logo 进行ts版本修改
import { toCanvas } from './toCanvas'
export * from './typing'
export { toCanvas }
import { renderQrCode } from './drawCanvas'
import { drawLogo } from './drawLogo'
import type { RenderQrCodeParams } from './typing'
export const toCanvas = (options: RenderQrCodeParams) => {
export function toCanvas(options: RenderQrCodeParams) {
return renderQrCode(options)
.then(() => {
return options
......
......@@ -4,6 +4,7 @@
import { toObject } from './util'
import { computed, defineComponent, nextTick, onBeforeUnmount, onMounted, provide, ref, unref } from 'vue'
import Bar from './bar'
const { scrollbar } = componentSetting
export default defineComponent({
......@@ -142,7 +143,7 @@
display: none;
width: 0;
height: 0;
opacity: 0%;
opacity: 0;
}
}
}
......@@ -168,7 +169,7 @@
bottom: 2px;
z-index: 1;
border-radius: 4px;
opacity: 0%;
opacity: 0;
transition: opacity 80ms ease;
&.is-vertical {
......@@ -194,7 +195,7 @@
.scrollbar:active > .scrollbar__bar,
.scrollbar:focus > .scrollbar__bar,
.scrollbar:hover > .scrollbar__bar {
opacity: 100%;
opacity: 1;
transition: opacity 340ms ease-out;
}
</style>
import type { BarMap } from './types'
export const BAR_MAP: BarMap = {
vertical: {
offset: 'offsetHeight',
......
......@@ -14,6 +14,7 @@
import { openWindow } from '/@/utils'
import { useOpenKeys } from './useOpenKeys'
export default defineComponent({
name: 'SimpleMenu',
components: {
......
......@@ -9,6 +9,7 @@
import { propTypes } from '/@/utils/propTypes'
import { useI18n } from '/@/hooks/web/useI18n'
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
export default defineComponent({
name: 'SimpleSubMenu',
components: {
......
......@@ -17,6 +17,7 @@
import { propTypes } from '/@/utils/propTypes'
import { createSimpleRootMenuContext } from './useSimpleMenuContext'
import mitt from '/@/utils/mitt'
export default defineComponent({
name: 'Menu',
props: {
......
......@@ -6,6 +6,7 @@
import { Tooltip } from 'ant-design-vue'
import { useMenuItem } from './useMenu'
import { useSimpleRootMenuContext } from './useSimpleMenuContext'
export default defineComponent({
name: 'MenuItem',
components: { Tooltip },
......
......@@ -24,6 +24,7 @@
import { basicProps } from './props'
import { isFunction } from '/@/utils/is'
import { warn } from '/@/utils/log'
export default defineComponent({
components: {
Table,
......
<script lang="ts">
import { defineComponent } from 'vue'
import { FormOutlined } from '@ant-design/icons-vue'
export default defineComponent({
name: 'EditTableHeaderIcon',
components: { FormOutlined },
......
......@@ -14,6 +14,7 @@
import { createPlaceholderMessage } from './helper'
import { CellComponent } from './CellComponent'
import type { EditRecordRow } from './index'
export default defineComponent({
name: 'EditableCell',
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, Spin },
......
......@@ -7,6 +7,7 @@
import { ScrollContainer } from '/@/components/Container'
import { useI18n } from '/@/hooks/web/useI18n'
import { useDesign } from '/@/hooks/web/useDesign'
// import { useSortable } from '/@/hooks/web/useSortable';
import { isFunction, isNullAndUnDef } from '/@/utils/is'
import { getPopupContainer as getParentContainer } from '/@/utils'
......@@ -15,6 +16,7 @@
import type Sortable from 'sortablejs'
import { useTableContext } from '../../hooks/useTableContext'
import type { BasicColumn, ColumnChangeParam } from '../../types/table'
interface State {
checkAll: boolean
isInit?: boolean
......
import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'
import type { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip'
import type { RoleEnum } from '/@/enums/roleEnum'
export interface ActionItem extends ButtonProps {
onClick?: Fn
label?: string
......
......@@ -79,7 +79,7 @@
resStr = t('component.time.just')
// Less than or equal to 59 seconds
} else if (diff < ONE_MINUTES) {
resStr = parseInt(diff / ONE_SECONDS) + t('component.time.seconds') + dirStr
resStr = Math.floor(diff / ONE_SECONDS) + t('component.time.seconds') + dirStr
// More than 59 seconds, less than or equal to 59 minutes and 59 seconds
} else if (diff >= ONE_MINUTES && diff < ONE_HOUR) {
resStr = Math.floor(diff / ONE_MINUTES) + t('component.time.minutes') + dirStr
......
......@@ -26,6 +26,7 @@
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/spellchecker'
import 'tinymce/plugins/tabfocus'
// import 'tinymce/plugins/table';
import 'tinymce/plugins/template'
import 'tinymce/plugins/textpattern'
......
......@@ -63,9 +63,11 @@ const validEvents = [
'onVisualAid',
]
const isValidKey = (key: string) => validEvents.includes(key)
function isValidKey(key: string) {
return validEvents.includes(key)
}
export const bindHandlers = (initEvent: Event, listeners: any, editor: any): void => {
export function bindHandlers(initEvent: Event, listeners: any, editor: any): void {
Object.keys(listeners)
.filter(isValidKey)
.forEach((key: string) => {
......
......@@ -15,6 +15,7 @@
import type { CreateContextOptions } from '/@/components/ContextMenu'
import { treeEmits, treeProps } from './types/tree'
import { createBEM } from '/@/utils/bem'
export default defineComponent({
name: 'BasicTree',
inheritAttrs: false,
......@@ -41,7 +42,7 @@
children: 'children',
title: 'title',
key: 'key',
...fieldNames,
...(fieldNames as Recordable),
}
})
const getBindValues = computed(() => {
......@@ -226,7 +227,7 @@
treeDataRef.value = props.treeData as TreeItem[]
})
onMounted(() => {
const level = parseInt(props.defaultExpandLevel)
const level = Number.parseInt(props.defaultExpandLevel as string)
if (level > 0) {
state.expandedKeys = filterByLevel(level)
} else if (props.defaultExpandAll) {
......
......@@ -7,6 +7,7 @@
import { useDebounceFn } from '@vueuse/core'
import { createBEM } from '/@/utils/bem'
import { ToolbarEnum } from '../types/tree'
const props = defineProps({
helpMessage: {
type: [String, Array] as PropType<string | string[]>,
......
......@@ -3,15 +3,18 @@
import { computed, defineComponent, reactive, ref, toRefs, unref } from 'vue'
import { Alert, Upload } from 'ant-design-vue'
import { BasicModal, useModalInner } from '/@/components/Modal'
// import { BasicTable, useTable } from '/@/components/Table';
// hooks
import { useUploadType } from './useUpload'
import { useMessage } from '/@/hooks/web/useMessage'
// types
import type { FileItem } from './typing'
import { UploadResultStatus } from './typing'
import { basicProps } from './props'
import { createActionColumn, createTableColumns } from './data'
// utils
import { checkImgType, getBase64WithFile } from './helper'
import { buildUUID } from '/@/utils/uuid'
......
<script lang="ts">
import { defineComponent, ref, watch } from 'vue'
// import { BasicTable, useTable } from '/@/components/Table';
import FileList from './FileList.vue'
import { BasicModal, useModalInner } from '/@/components/Modal'
......
......@@ -14,7 +14,7 @@ export const basicProps = {
// 最大数量的文件,Infinity不限制
maxNumber: {
type: Number as PropType<number>,
default: Infinity,
default: Number.POSITIVE_INFINITY,
},
// 根据后缀,或者其他
accept: {
......
import type { Ref } from 'vue'
import { computed, unref } from 'vue'
import { useI18n } from '/@/hooks/web/useI18n'
const { t } = useI18n()
export function useUploadType({
acceptRef,
......@@ -52,7 +53,7 @@ export function useUploadType({
}
const maxNumber = unref(maxNumberRef)
if (maxNumber && maxNumber !== Infinity) {
if (maxNumber && maxNumber !== Number.POSITIVE_INFINITY) {
helpTexts.push(t('component.upload.maxNumber', [maxNumber]))
}
return helpTexts.join(',')
......
......@@ -38,7 +38,7 @@
const getActionStyleRef = computed(() => {
const { height, actionStyle } = props
const h = `${parseInt(height as string)}px`
const h = `${Number.parseInt(height as string)}px`
return {
left: 0,
width: h,
......@@ -49,8 +49,8 @@
const getWrapStyleRef = computed(() => {
const { height, width, circle, wrapStyle } = props
const h = parseInt(height as string)
const w = `${parseInt(width as string)}px`
const h = Number.parseInt(height as string)
const w = `${Number.parseInt(width as string)}px`
return {
width: w,
height: `${h}px`,
......@@ -62,7 +62,7 @@
const getBarStyleRef = computed(() => {
const { height, circle, barStyle } = props
const h = parseInt(height as string)
const h = Number.parseInt(height as string)
return {
height: `${h}px`,
borderRadius: circle ? `${h / 2}px 0 0 ${h / 2}px` : 0,
......@@ -72,8 +72,8 @@
const getContentStyleRef = computed(() => {
const { height, width, contentStyle } = props
const h = `${parseInt(height as string)}px`
const w = `${parseInt(width as string)}px`
const h = `${Number.parseInt(height as string)}px`
const w = `${Number.parseInt(width as string)}px`
return {
height: h,
......@@ -110,15 +110,15 @@
const actionEl = unref(actionElRef)
if (!actionEl) return
emit('start', e)
state.moveDistance = getEventPageX(e) - parseInt(actionEl.style.left.replace('px', ''), 10)
state.moveDistance = getEventPageX(e) - Number.parseInt(actionEl.style.left.replace('px', ''), 10)
state.startTime = new Date().getTime()
state.isMoving = true
}
function getOffset(el: HTMLDivElement) {
const actionWidth = parseInt(el.style.width)
const actionWidth = Number.parseInt(el.style.width)
const { width } = props
const widthNum = parseInt(width as string)
const widthNum = Number.parseInt(width as string)
const offset = widthNum - actionWidth - 6
return { offset, widthNum, actionWidth }
}
......@@ -169,7 +169,7 @@
} else {
const contentEl = unref(contentElRef)
if (contentEl) {
contentEl.style.width = `${parseInt(barEl.style.width)}px`
contentEl.style.width = `${Number.parseInt(barEl.style.width)}px`
}
}
}, 0)
......
......@@ -65,7 +65,7 @@
const { imgWidth, height, maxDegree } = props
const { moveX } = data
const currentRotate = Math.ceil(
(moveX / (imgWidth! - parseInt(height as string))) * maxDegree! * unref(getFactorRef),
(moveX / (imgWidth! - Number.parseInt(height as string))) * maxDegree! * unref(getFactorRef),
)
state.currentRotate = currentRotate
state.imgStyle = hackCss('transform', `rotateZ(${state.randomRotate - currentRotate}deg)`)
......@@ -130,7 +130,7 @@
<img
src={src}
onLoad={handleImgOnLoad}
width={parseInt(props.width as string)}
width={Number.parseInt(props.width as string)}
class={imgCls}
style={state.imgStyle}
onClick={() => {
......
......@@ -32,7 +32,7 @@
function convertToUnit(str: string | number | null | undefined, unit = 'px'): string | undefined {
if (str == null || str === '') {
return undefined
} else if (isNaN(+str!)) {
} else if (Number.isNaN(+str!)) {
return String(str)
} else {
return `${Number(str)}${unit}`
......@@ -51,11 +51,11 @@
})
const getBenchRef = computed(() => {
return parseInt(props.bench as string, 10)
return Number.parseInt(props.bench as string, 10)
})
const getItemHeightRef = computed(() => {
return parseInt(props.itemHeight as string, 10)
return Number.parseInt(props.itemHeight as string, 10)
})
const getFirstToRenderRef = computed(() => {
......@@ -99,7 +99,8 @@
if (!wrapEl) {
return 0
}
const height = parseInt(props.height || 0, 10) || wrapEl.clientHeight
// @ts-expect-error
const height = Number.parseInt(props.height || 0, 10) || wrapEl.clientHeight
return first + Math.ceil(height / unref(getItemHeightRef))
}
......
......@@ -17,7 +17,7 @@ function isAuth(el: Element, binding: any) {
}
}
const mounted = (el: Element, binding: DirectiveBinding<any>) => {
function mounted(el: Element, binding: DirectiveBinding<any>) {
isAuth(el, binding)
}
......
import type { Directive } from 'vue'
import './index.less'
export interface RippleOptions {
event: string
transition: number
......@@ -47,7 +48,7 @@ const RippleDirective: Directive & RippleProto = {
}
function rippler({ event, el, zIndex, background }: { event: EventType; el: HTMLElement } & RippleProto) {
const targetBorder = parseInt(getComputedStyle(el).borderWidth.replace('px', ''))
const targetBorder = Number.parseInt(getComputedStyle(el).borderWidth.replace('px', ''))
const clientX = event.clientX || event.touches[0].clientX
const clientY = event.clientY || event.touches[0].clientY
......@@ -172,7 +173,7 @@ function rippler({ event, el, zIndex, background }: { event: EventType; el: HTML
function setProps(modifiers: Recordable, props: Recordable) {
modifiers.forEach((item: Recordable) => {
if (isNaN(Number(item))) props.event = item
if (Number.isNaN(Number(item))) props.event = item
else props.transition = item
})
}
......
export enum PageEnum {
// basic login path
BASE_LOGIN = '/login',
// BASE_LOGIN = '/login',
BASE_LOGIN = '/main',
// basic home path
BASE_HOME = '/dashboard',
BASE_HOME = '/main',
// error page path
ERROR_PAGE = '/exception',
// error log page path
......
import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue'
import type { Ref } from 'vue'
interface Params {
excludeListeners?: boolean
excludeKeys?: string[]
......
import type { IpcRenderer, IpcRendererEvent } from 'electron'
import type { UseIpcRendererReturn } from '@vueuse/electron'
import { useIpcRenderer } from '@vueuse/electron'
const ipc = useIpcRenderer()
export type IpcRendererListener = (event: IpcRendererEvent, ...args: any[]) => void
export interface UserIpcRendererRetrun extends UseIpcRendererReturn {
invokeAsync<T>(channel: string, ...args: any[]): Promise<T | null>
}
export interface UseElectronReturn {
ipcRenderer: UserIpcRendererRetrun
}
export function useElectron(ipcRenderer?: IpcRenderer): UseElectronReturn {
if (!ipcRenderer) ipcRenderer = window?.require('electron').ipcRenderer
if (!ipcRenderer) throw new Error('provide IpcRenderer module or enable nodeIntegration')
return {
ipcRenderer: {
on: ipc.on,
once: ipc.once,
removeListener: ipc.removeListener,
removeAllListeners: ipc.removeAllListeners,
send: ipc.send,
sendSync: ipc.sendSync,
sendTo: ipc.sendTo,
sendToHost: ipc.sendToHost,
postMessage: ipc.postMessage,
invoke: ipc.invoke,
invokeAsync: <T>(channel: string, ...args: any[]): Promise<T> => ipcRenderer.invoke(channel, ...args),
},
}
}
......@@ -8,7 +8,7 @@ export interface ScrollToParams {
callback?: () => any
}
const easeInOutQuad = (t: number, b: number, c: number, d: number) => {
function easeInOutQuad(t: number, b: number, c: number, d: number) {
t /= d / 2
if (t < 1) {
return (c / 2) * t * t + b
......@@ -16,11 +16,11 @@ const easeInOutQuad = (t: number, b: number, c: number, d: number) => {
t--
return (-c / 2) * (t * (t - 2) - 1) + b
}
const move = (el: HTMLElement, amount: number) => {
function move(el: HTMLElement, amount: number) {
el.scrollTop = amount
}
const position = (el: HTMLElement) => {
function position(el: HTMLElement) {
return el.scrollTop
}
export function useScrollTo({ el, to, duration = 500, callback }: ScrollToParams) {
......
......@@ -3,7 +3,7 @@ import type { GlobConfig } from '/#/config'
import { warn } from '/@/utils/log'
import { getAppEnvConfig } from '/@/utils/env'
export const useGlobSetting = (): Readonly<GlobConfig> => {
export function useGlobSetting(): Readonly<GlobConfig> {
const {
VITE_GLOB_APP_TITLE,
VITE_GLOB_API_URL,
......
import { getCurrentInstance, onUnmounted } from 'vue'
import { createContextMenu, destroyContextMenu } from '/@/components/ContextMenu'
import type { ContextMenuItem } from '/@/components/ContextMenu'
export type { ContextMenuItem }
export function useContextMenu(authRemove = true) {
if (getCurrentInstance() && authRemove) {
......
import { ref, watch } from 'vue'
import { isDef } from '/@/utils/is'
interface Options {
target?: HTMLElement
}
......
import { useAppProviderContext } from '/@/components/Application'
// import { computed } from 'vue';
// import { lowerFirst } from 'lodash-es';
export function useDesign(scope: string) {
......
......@@ -7,7 +7,7 @@ import { useRouter } from 'vue-router'
/**
* @description: Full screen display content
*/
export const useFullContent = () => {
export function useFullContent() {
const appStore = useAppStore()
const router = useRouter()
const { currentRoute } = router
......
......@@ -52,4 +52,6 @@ export function useI18n(namespace?: string): {
// 为什么要编写此函数?
// 主要用于配合vscode i18nn ally插件。此功能仅用于路由和菜单。请在其他地方使用useI18n
export const t = (key: string) => key
export function t(key: string) {
return key
}
......@@ -69,7 +69,7 @@ function createConfirm(options: ModalOptionsEx): ConfirmOptions {
return Modal.confirm(opt) as unknown as ConfirmOptions
}
const getBaseOptions = () => {
function getBaseOptions() {
const { t } = useI18n()
return {
okText: t('common.okText'),
......
......@@ -30,7 +30,7 @@ export function useGo(_router?: Router) {
/**
* @description: redo current page
*/
export const useRedo = (_router?: Router) => {
export function useRedo(_router?: Router) {
const { replace, currentRoute } = _router || useRouter()
const { query, params = {}, name, fullPath } = unref(currentRoute.value)
function redo(): Promise<boolean> {
......
......@@ -7,6 +7,7 @@ import { useUserStore } from '/@/store/modules/user'
import { useTabs } from './useTabs'
import { resetRouter, router } from '/@/router'
// import { RootRoute } from '/@/router/routes';
import projectSetting from '/@/settings/projectSetting'
......
......@@ -11,6 +11,7 @@
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
import SessionTimeoutLogin from '/@/views/sys/login/SessionTimeoutLogin.vue'
export default defineComponent({
name: 'LayoutFeatures',
components: {
......
......@@ -4,6 +4,7 @@
import { useI18n } from '/@/hooks/web/useI18n'
import { useFullscreen } from '@vueuse/core'
import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons-vue'
export default defineComponent({
name: 'FullScreen',
components: { FullscreenExitOutlined, FullscreenOutlined, Tooltip },
......
......@@ -8,6 +8,7 @@
import { useUserStore } from '/@/store/modules/user'
import { useLockStore } from '/@/store/modules/lock'
import headerImg from '/@/assets/images/header.jpg'
export default defineComponent({
name: 'LockModal',
components: { BasicModal, BasicForm },
......
......@@ -5,6 +5,7 @@
import { useDesign } from '/@/hooks/web/useDesign'
import { Avatar, List, Tag, Typography } from 'ant-design-vue'
import { isNumber } from '/@/utils/is'
export default defineComponent({
components: {
[Avatar.name]: Avatar,
......
......@@ -13,6 +13,7 @@
import { propTypes } from '/@/utils/propTypes'
import { openWindow } from '/@/utils'
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
type MenuEvent = 'logout' | 'doc' | 'lock'
export default defineComponent({
name: 'UserDropdown',
......
......@@ -190,7 +190,7 @@
&--mobile {
.@{logo-prefix-cls} {
&__title {
opacity: 100%;
opacity: 1;
}
}
}
......
......@@ -242,7 +242,7 @@ export default defineComponent({
event={HandlerEnum.LOCK_TIME}
defaultValue={unref(getLockTime)}
formatter={(value: string) => {
return parseInt(value) === 0
return Number.parseInt(value) === 0
? `0(${t('layout.setting.notAutoScreenLock')})`
: `${value}${t('layout.setting.minute')}`
}}
......@@ -255,7 +255,7 @@ export default defineComponent({
event={HandlerEnum.MENU_WIDTH}
disabled={!unref(getShowMenuRef)}
defaultValue={unref(getMenuWidth)}
formatter={(value: string) => `${parseInt(value)}px`}
formatter={(value: string) => `${Number.parseInt(value)}px`}
/>
</>
)
......
......@@ -6,6 +6,7 @@
import { useDesign } from '/@/hooks/web/useDesign'
import type { menuTypeList } from '../enum'
export default defineComponent({
name: 'MenuTypePicker',
components: { Tooltip },
......
......@@ -79,7 +79,7 @@ export const topMenuAlignOptions = [
},
]
export const getMenuTriggerOptions = (hideTop: boolean) => {
export function getMenuTriggerOptions(hideTop: boolean) {
return [
{
value: TriggerEnum.NONE,
......
......@@ -14,6 +14,7 @@
import { useDesign } from '/@/hooks/web/useDesign'
import DragBar from './DragBar.vue'
export default defineComponent({
name: 'LayoutSideBar',
components: { Sider: Layout.Sider, LayoutMenu, DragBar, LayoutTrigger },
......
......@@ -522,14 +522,14 @@
font-size: 18px;
color: @primary-color;
border-bottom: 1px solid rgb(238 238 238);
opacity: 0%;
opacity: 0;
transition: unset;
align-items: center;
justify-content: space-between;
&.show {
min-width: 130px;
opacity: 100%;
opacity: 1;
transition: all 0.5s ease;
}
......
......@@ -8,6 +8,7 @@
import { useAppInject } from '/@/hooks/web/useAppInject'
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
import { useDesign } from '/@/hooks/web/useDesign'
export default defineComponent({
name: 'SiderWrapper',
components: { Sider, Drawer, MixSider },
......
......@@ -83,6 +83,7 @@ export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>, mix = fals
function handleMouseMove(ele: HTMLElement, wrap: HTMLElement, clientX: number) {
document.onmousemove = function (innerE) {
let iT = (ele as any).left + (innerE.clientX - clientX)
// @ts-expect-error
innerE = innerE || window.event
const maxT = 800
const minT = unref(getMiniWidthNumber)
......@@ -101,7 +102,7 @@ export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>, mix = fals
document.onmousemove = null
document.onmouseup = null
wrap.style.transition = 'width 0.2s'
const width = parseInt(wrap.style.width)
const width = Number.parseInt(wrap.style.width)
if (!mix) {
const miniWidth = unref(getMiniWidthNumber)
......
......@@ -6,6 +6,7 @@
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'
import { getTransitionName } from './transition'
import { useMultipleTabStore } from '/@/store/modules/multipleTab'
export default defineComponent({
name: 'PageLayout',
components: { FrameLayout },
......
export default {
main: 'Home',
}
export default {
main: '主页',
}
......@@ -2,6 +2,7 @@ import 'virtual:windi-base.css'
import 'virtual:windi-components.css'
import '/@/design/index.less'
import 'virtual:windi-utilities.css'
// Register icon sprite
import 'virtual:svg-icons-register'
import { createApp } from 'vue'
......@@ -19,7 +20,7 @@ import { registerGlobComp } from '/@/components/registerGlobComp'
import { isDevMode } from './utils/env'
// fix: Added non-passive event listener to a scroll-blocking 'wheel' event
import 'default-passive-events'
// import 'default-passive-events'
if (isDevMode()) {
import('ant-design-vue/es/style')
......
......@@ -4,17 +4,21 @@ export const PARENT_LAYOUT_NAME = 'ParentLayout'
export const PAGE_NOT_FOUND_NAME = 'PageNotFound'
export const EXCEPTION_COMPONENT = () => import('/@/views/sys/exception/Exception.vue')
export function EXCEPTION_COMPONENT() {
return import('/@/views/sys/exception/Exception.vue')
}
/**
* @description: default layout
*/
export const LAYOUT = () => import('/@/layouts/default/index.vue')
export function LAYOUT() {
return import('/@/layouts/default/index.vue')
}
/**
* @description: parent-layout
*/
export const getParentLayout = (_name?: string) => {
export function getParentLayout(_name?: string) {
return () =>
new Promise((resolve) => {
resolve({
......
......@@ -33,15 +33,15 @@ export function createParamMenuGuard(router: Router) {
})
}
const getPermissionMode = () => {
function getPermissionMode() {
const appStore = useAppStoreWithOut()
return appStore.getProjectConfig.permissionMode
}
const isBackMode = () => {
function isBackMode() {
return getPermissionMode() === PermissionModeEnum.BACK
}
const isRouteMappingMode = () => {
function isRouteMappingMode() {
return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING
}
......@@ -7,7 +7,9 @@ import { warn } from '/@/utils/log'
import { createRouter, createWebHashHistory } from 'vue-router'
export type LayoutMapKey = 'LAYOUT'
const IFRAME = () => import('/@/views/sys/iframe/FrameBlank.vue')
function IFRAME() {
return import('/@/views/sys/iframe/FrameBlank.vue')
}
const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>()
......
......@@ -6,11 +6,12 @@ import { basicRoutes } from './routes'
// 白名单应该包含基本静态路由
const WHITE_NAME_LIST: string[] = []
const getRouteNames = (array: any[]) =>
array.forEach((item) => {
function getRouteNames(array: any[]) {
return array.forEach((item) => {
WHITE_NAME_LIST.push(item.name)
getRouteNames(item.children || [])
})
}
getRouteNames(basicRoutes)
// app router
......
......@@ -24,19 +24,19 @@ Object.keys(modules).forEach((key) => {
// ==========Helper===========
// ===========================
const getPermissionMode = () => {
function getPermissionMode() {
const appStore = useAppStoreWithOut()
return appStore.getProjectConfig.permissionMode
}
const isBackMode = () => {
function isBackMode() {
return getPermissionMode() === PermissionModeEnum.BACK
}
const isRouteMappingMode = () => {
function isRouteMappingMode() {
return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING
}
const isRoleMode = () => {
function isRoleMode() {
return getPermissionMode() === PermissionModeEnum.ROLE
}
......@@ -62,7 +62,7 @@ async function getAsyncMenus() {
return staticMenus
}
export const getMenus = async (): Promise<Menu[]> => {
export async function getMenus(): Promise<Menu[]> {
const menus = await getAsyncMenus()
if (isRoleMode()) {
const routes = router.getRoutes()
......
......@@ -38,6 +38,15 @@ export const LoginRoute: AppRouteRecordRaw = {
},
}
export const MainRoute: AppRouteRecordRaw = {
path: '/main',
name: 'Main',
component: () => import('/@/views/main/index.vue'),
meta: {
title: t('routes.main.main'),
},
}
// Basic routing without permission
// 未经许可的基本路由
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE]
export const basicRoutes = [MainRoute, LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE]
import type { AppRouteModule } from '/@/router/types'
import { LAYOUT } from '/@/router/constant'
import { t } from '/@/hooks/web/useI18n'
const main: AppRouteModule = {
path: '/main',
name: 'Main',
component: LAYOUT,
redirect: '/main/index',
meta: {
orderNo: 10,
icon: 'ion:grid-outline',
title: t('routes.main.main'),
},
children: [
{
path: 'index',
name: 'Index',
component: () => import('/@/views/main/index.vue'),
meta: {
title: t('routes.main.main'),
},
},
],
}
export default main
......@@ -26,7 +26,7 @@ function handleGotoPage(router: Router) {
go(unref(router.currentRoute).path, true)
}
const getToTarget = (tabItem: RouteLocationNormalized) => {
function getToTarget(tabItem: RouteLocationNormalized) {
const { params, path, query } = tabItem
return {
params: params || {},
......
......@@ -5,7 +5,7 @@ import { DEFAULT_CACHE_TIME, enableStorageEncryption } from '/@/settings/encrypt
export type Options = Partial<CreateStorageParams>
const createOptions = (storage: Storage, options: Options = {}): Options => {
function createOptions(storage: Storage, options: Options = {}): Options {
return {
// No encryption in debug mode
hasEncrypt: enableStorageEncryption,
......@@ -17,15 +17,15 @@ const createOptions = (storage: Storage, options: Options = {}): Options => {
export const WebStorage = create(createOptions(sessionStorage))
export const createStorage = (storage: Storage = sessionStorage, options: Options = {}) => {
export function createStorage(storage: Storage = sessionStorage, options: Options = {}) {
return create(createOptions(storage, options))
}
export const createSessionStorage = (options: Options = {}) => {
export function createSessionStorage(options: Options = {}) {
return createStorage(sessionStorage, { ...options, timeout: DEFAULT_CACHE_TIME })
}
export const createLocalStorage = (options: Options = {}) => {
export function createLocalStorage(options: Options = {}) {
return createStorage(localStorage, { ...options, timeout: DEFAULT_CACHE_TIME })
}
......
......@@ -9,14 +9,14 @@ export interface CreateStorageParams extends EncryptionParams {
hasEncrypt: boolean
timeout?: Nullable<number>
}
export const createStorage = ({
export function createStorage({
prefixKey = '',
storage = sessionStorage,
key = cacheCipher.key,
iv = cacheCipher.iv,
timeout = null,
hasEncrypt = true,
}: Partial<CreateStorageParams> = {}) => {
}: Partial<CreateStorageParams> = {}) {
if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) {
throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!')
}
......
......@@ -22,7 +22,7 @@ export function isHexColor(color: string) {
export function rgbToHex(r: number, g: number, b: number) {
// tslint:disable-next-line:no-bitwise
const hex = ((r << 16) | (g << 8) | b).toString(16)
return `#${new Array(Math.abs(hex.length - 7)).join('0')}${hex}`
return `#${Array.from({ length: Math.abs(hex.length - 7) }).join('0')}${hex}`
}
/**
......@@ -42,7 +42,7 @@ export function hexToRGB(hex: string) {
}
const sColorChange: number[] = []
for (let i = 1; i < 7; i += 2) {
sColorChange.push(parseInt(`0x${sHex.slice(i, i + 2)}`))
sColorChange.push(Number.parseInt(`0x${sHex.slice(i, i + 2)}`))
}
return `RGB(${sColorChange.join(',')})`
}
......@@ -96,7 +96,7 @@ export function lighten(color: string, amount: number) {
* @returns {string} The processed part of the color
*/
function addLight(color: string, amount: number) {
const cc = parseInt(color, 16) + amount
const cc = Number.parseInt(color, 16) + amount
const c = cc > 255 ? 255 : cc
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
}
......@@ -142,7 +142,7 @@ export function calculateBestTextColor(hexColor: string) {
* @returns {string} The processed part of the color
*/
function subtractLight(color: string, amount: number) {
const cc = parseInt(color, 16) - amount
const cc = Number.parseInt(color, 16) - amount
const c = cc < 0 ? 0 : cc
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
}
......@@ -169,6 +169,7 @@ export function useRafThrottle<T extends FunctionArgs>(fn: T): T {
locked = true
window.requestAnimationFrame(() => {
// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/no-invalid-this
fn.apply(this, args)
locked = false
})
......
......@@ -12,7 +12,9 @@ const DEFAULT_CONFIG: TreeHelperConfig = {
}
// 获取配置。 Object.assign 从一个或多个源对象复制到目标对象
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config)
function getConfig(config: Partial<TreeHelperConfig>) {
return Object.assign({}, DEFAULT_CONFIG, config)
}
// tree from list
// 列表中的树
......
......@@ -5,7 +5,9 @@ import { isFunction } from '/@/utils/is'
// Used to store the identification and cancellation function of each request
let pendingMap = new Map<string, Canceler>()
export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&')
export function getPendingUrl(config: AxiosRequestConfig) {
return [config.method, config.url].join('&')
}
export class AxiosCanceler {
/**
......
import type { AxiosError, AxiosInstance } from 'axios'
/**
* 请求重试机制
*/
......
import type { ErrorMessageMode } from '/#/axios'
import { useMessage } from '/@/hooks/web/useMessage'
import { useI18n } from '/@/hooks/web/useI18n'
// import router from '/@/router';
// import { PageEnum } from '/@/enums/pageEnum';
import { useUserStoreWithOut } from '/@/store/modules/user'
......
......@@ -5,7 +5,7 @@ import { unref } from 'vue'
import { isObject } from '/@/utils/is'
import { cloneDeep } from 'lodash-es'
export const noop = () => {}
export function noop() {}
/**
* @description: Set ui mount node
......@@ -82,7 +82,7 @@ export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormal
}
}
export const withInstall = <T>(component: T, alias?: string) => {
export function withInstall<T>(component: T, alias?: string) {
const comp = component as any
comp.install = (app: App) => {
app.component(comp.name || comp.displayName, component)
......
......@@ -133,7 +133,7 @@ export function buildProp<
type NativePropType = [((...args: any) => any) | { new (...args: any): any } | undefined | null]
export const buildProps = <
export function buildProps<
O extends {
[K in keyof O]: O[K] extends BuildPropReturn<any, any, any, any, any>
? O[K]
......@@ -145,10 +145,8 @@ export const buildProps = <
: never
: never
},
>(
props: O,
) =>
fromPairs(Object.entries(props).map(([key, option]) => [key, buildProp(option as any, key)])) as unknown as {
>(props: O) {
return fromPairs(Object.entries(props).map(([key, option]) => [key, buildProp(option as any, key)])) as unknown as {
[K in keyof O]: O[K] extends { [propKey]: boolean }
? O[K]
: [O[K]] extends NativePropType
......@@ -157,10 +155,17 @@ export const buildProps = <
? BuildPropReturn<T, O[K]['default'], R, V, C>
: never
}
}
export const definePropType = <T>(val: any) => ({ [wrapperKey]: val } as PropWrapper<T>)
export function definePropType<T>(val: any) {
return { [wrapperKey]: val } as PropWrapper<T>
}
export const keyOf = <T>(arr: T) => Object.keys(arr) as Array<keyof T>
export const mutable = <T extends readonly any[] | Record<string, unknown>>(val: T) => val as Mutable<typeof val>
export function keyOf<T>(arr: T) {
return Object.keys(arr) as Array<keyof T>
}
export function mutable<T extends readonly any[] | Record<string, unknown>>(val: T) {
return val as Mutable<typeof val>
}
export const componentSize = ['large', 'medium', 'small', 'mini'] as const
......@@ -11,11 +11,21 @@ const PROXY_LIST = [
// ['http://192.168.0.100:18100', `https://oss.app.yiring.com`],
]
// 监测是否为开发环境
// FIXED: 使用 try catch 的方式来判断是否为开发环境,因为在 Webview/RenderJS 中无法使用 import.meta.env
function isDevEnv() {
try {
return import.meta.env.MODE === 'development'
} catch (_) {
return false
}
}
/**
* 将内部地址(内网)转换成代理/预览地址(公网)
* @param url 内网地址
*/
export const getExtranetUrl = (url: string): string => {
export function getExtranetUrl(url: string): string {
let uri = url
PROXY_LIST.forEach((proxy) => {
......@@ -28,9 +38,9 @@ export const getExtranetUrl = (url: string): string => {
/**
* 将代理/预览地址(公网)转换成内部地址(内网)
* eg: 主要用于解决内网文件上传后预览,但是实际上传存储时还是内网地址的问题
* @param url 代理/公网地址
* @param url 包含代理/公网地址的内容
*/
export const getIntranetUrl = (url: string): string => {
export function getIntranetUrl(url: string): string {
let uri = url
PROXY_LIST.forEach((proxy) => {
......@@ -45,14 +55,23 @@ export const getIntranetUrl = (url: string): string => {
* @param body 接口返回的内容
* @returns 替换本地链接后的数据结果
*/
export const handleResponseResource = <T>(body: T, options: Recordable) => {
if (options.apiUrl.includes('proxy.yiring.com') && typeof body === 'object') {
let text = JSON.stringify(body)
// 处理内网地址的预览问题
text = getExtranetUrl(text)
export function handleResponseResource<T>(body: T, options: Recordable) {
for (const [intranet, extranet] of PROXY_LIST) {
// 当需要处理内外网资源地址映射时,进行内容处理
const isIntranet = options.apiUrl.includes(intranet)
const isExtranet = isDevEnv() ? true : options.apiUrl.includes(extranet)
if (isIntranet || isExtranet) {
const isString = typeof body === 'string'
const isObject = typeof body === 'object'
return JSON.parse(text) as T
// 处理有效数据
if (isString || isObject) {
let text = isString ? body : JSON.stringify(body)
// 说明: 如果接口地址是内网,就需要将外网链接转换成内网链接,如果是外网接口地址,则需要将内网地址转换成外网链接,来保证无论内外网访问平台资源都是正常的
text = isExtranet ? getExtranetUrl(text) : getIntranetUrl(text)
return (isString ? text : JSON.parse(text)) as T
}
}
}
return body
......
......@@ -33,7 +33,7 @@ export interface Indexable<T> {
export type Hash<T> = Indexable<T>
export type TimeoutHandle = ReturnType<typeof global.setTimeout>
export type TimeoutHandle = ReturnType<typeof setTimeout>
export type ComponentSize = 'large' | 'medium' | 'small' | 'mini'
......
<script setup lang="tsx">
import dayjs from 'dayjs'
import { BasicModal } from '/@/components/Modal'
import { Icon } from '/@/components/Icon'
import { useElectron } from '@/hooks/electron/useElectron'
import { useMessage } from '@/hooks/web/useMessage'
import { getEnvText } from '/@/utils/env'
type MessageType =
| 'checking-for-update'
| 'error'
| 'update-available'
| 'update-not-available'
| 'download-progress'
| 'update-downloaded'
const { ipcRenderer: ipc } = useElectron()
const { createMessage } = useMessage()
const startYear = 2021
const currentYear = dayjs().year()
const yearText = ref<string>(currentYear === startYear ? `${currentYear}` : `${startYear} - ${currentYear}`)
const loading = ref<boolean>(false)
// 监听检查更新事件
let hide = null
ipc.on('updater-message', (_e, body: { type: MessageType; text: string }) => {
console.log('updater-message', body)
const { type, text } = body
if (type === 'checking-for-update' || type === 'download-progress') {
loading.value = true
hide = createMessage.loading({
key: 'updating',
content: text,
duration: 0,
})
} else if (type === 'update-available' || type === 'update-not-available' || type === 'update-downloaded') {
createMessage.success(text)
} else if (type === 'error') {
createMessage.error(text)
}
if (type === 'error' || type === 'update-downloaded' || type === 'update-not-available') {
loading.value = false
hide?.()
}
})
</script>
<template>
<BasicModal v-bind="$attrs" centered :footer="null" :canFullscreen="false">
<!-- 关于信息 -->
<template #title>
<a-space>
<Icon icon="ant-design:info-circle-outlined" :size="22" />
<div class="title-text">关于</div>
</a-space>
</template>
<div class="about-wrap">
<!-- 公司 + 版权信息 -->
<div class="about-app-info-wrap">
<div class="app-icon">
<img src="logo.png" />
</div>
<!-- <div class="app-name">{{ $app.name }}</div> -->
<div class="app-description">{{ $app.description }}</div>
<div class="app-version">
<a-tooltip>
<template #title>
<div class="flex flex-col items-center justify-center">
<div class="version-mode">{{ getEnvText() }}</div>
<div class="update-time">发布时间: {{ $app.lastBuildTime }}</div>
</div>
</template>
<a-button type="text">
<span class="version-text">{{ $app.version }}</span>
</a-button>
</a-tooltip>
</div>
<!-- 检查版本更新按钮 -->
<div class="app-check-update-action">
<a-button type="dashed" :loading="loading" @click="ipc.send('checkForUpdate')">
<Icon icon="ant-design:bulb-outlined" v-show="!loading" />
检查更新
</a-button>
</div>
</div>
<!-- 版本信息 -->
<div class="about-footer">
<div class="company">长沙壹润信息科技发展有限公司</div>
<div class="copyright">
<span>Copyright © {{ yearText }}</span>
<span class="link">
<a target="_blank" href="https://yiring.com">YiRing.com</a>
</span>
</div>
</div>
</div>
</BasicModal>
</template>
<style lang="less" scoped>
.about-wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.about-app-info-wrap {
display: flex;
flex-direction: column;
align-items: center;
> div {
margin-top: 10px;
}
.app-icon {
width: 50px;
}
.app-description {
font-weight: bold;
}
.app-version {
display: flex;
flex-direction: column;
align-items: center;
.version-text::before {
content: 'V';
margin-right: 2px;
}
}
}
.about-footer {
height: 60px;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
color: #898989;
font-size: 13px;
user-select: none;
letter-spacing: 1px;
.company {
letter-spacing: 2px;
}
.link {
margin-left: 5px;
&:hover {
text-decoration: underline;
cursor: pointer;
}
a {
color: #898989;
margin-left: 3px;
}
}
}
</style>
<script setup lang="ts">
import { reactive } from 'vue'
const versions = reactive({ ...window.electron.process.versions })
</script>
<template>
<ul class="versions">
<li class="electron-version">Electron v{{ versions.electron }}</li>
<li class="chrome-version">Chromium v{{ versions.chrome }}</li>
<li class="node-version">Node v{{ versions.node }}</li>
<li class="v8-version">V8 v{{ versions.v8.split('-').shift() }}</li>
</ul>
</template>
<script setup lang="ts">
import Versions from './components/Versions.vue'
onMounted(() => {
postMessage({ payload: 'loaded' }, '*')
})
</script>
<template>
<Versions />
<svg class="hero-logo" viewBox="0 0 900 300">
<use xlink:href="../../assets/icons.svg#electron" />
</svg>
<h2 class="hero-text">You've successfully created an Electron project with Vue and TypeScript</h2>
<p class="hero-tagline">Please try pressing <code>F12</code> to open the devTool</p>
<div class="links">
<div class="link-item">
<a target="_blank" href="https://evite.netlify.app">Documentation</a>
</div>
<div class="link-item link-dot"></div>
<div class="link-item">
<a target="_blank" href="https://github.com/alex8088/electron-vite">Getting Help</a>
</div>
<div class="link-item link-dot"></div>
<div class="link-item">
<a target="_blank" href="https://github.com/alex8088/quick-start/tree/master/packages/create-electron">
create-electron
</a>
</div>
</div>
<div class="features">
<div class="feature-item">
<article>
<h2 class="title">Configuring</h2>
<p class="detail">
Config with <span>electron.vite.config.ts</span> and refer to the
<a target="_blank" href="https://evite.netlify.app/config/">config guide</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">HMR</h2>
<p class="detail">
Edit <span>src/renderer</span> files to test HMR. See
<a target="_blank" href="https://evite.netlify.app/guide/hmr-in-renderer.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Hot Reloading</h2>
<p class="detail">
Run <span>'electron-vite dev --watch'</span> to enable. See
<a target="_blank" href="https://evite.netlify.app/guide/hot-reloading.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Debugging</h2>
<p class="detail">
Check out <span>.vscode/launch.json</span>. See
<a target="_blank" href="https://evite.netlify.app/guide/debugging.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Source Code Protection</h2>
<p class="detail">
Supported via built-in plugin <span>bytecodePlugin</span>. See
<a target="_blank" href="https://evite.netlify.app/guide/source-code-protection.html"> docs </a>
.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Packaging</h2>
<p class="detail">
Use
<a target="_blank" href="https://www.electron.build">electron-builder</a>
and pre-configured to pack your app.
</p>
</article>
</div>
</div>
</template>
<style lang="less">
@import '../../assets/css/styles.less';
</style>
......@@ -13,8 +13,12 @@
const schema: DescItem[] = []
const devSchema: DescItem[] = []
const commonTagRender = (color: string) => (curVal) => h(Tag, { color }, () => curVal)
const commonLinkRender = (text: string) => (href) => h('a', { href, target: '_blank' }, text)
function commonTagRender(color: string) {
return (curVal) => h(Tag, { color }, () => curVal)
}
function commonLinkRender(text: string) {
return (href) => h('a', { href, target: '_blank' }, text)
}
const infoSchema: DescItem[] = [
{
......
......@@ -10,6 +10,7 @@
import { fireErrorApi } from '/@/api/demo/error'
import { getColumns } from './data'
import { cloneDeep } from 'lodash-es'
const rowInfo = ref<ErrorLogInfo>()
const imgList = ref<string[]>([])
const { t } = useI18n()
......
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'FrameBlank',
})
......
......@@ -164,6 +164,7 @@
font-size: 90px;
}
}
@media screen and (min-width: @screen-lg) {
span:not(.meridiem) {
font-size: 220px;
......@@ -175,6 +176,7 @@
font-size: 260px;
}
}
@media screen and (min-width: @screen-2xl) {
span:not(.meridiem) {
font-size: 320px;
......
......@@ -10,6 +10,7 @@
import { useI18n } from '/@/hooks/web/useI18n'
import { useDesign } from '/@/hooks/web/useDesign'
import { useLocaleStore } from '/@/store/modules/locale'
defineProps({
sessionTimeout: {
type: Boolean,
......@@ -80,7 +81,7 @@
background-color: @dark-bg;
&::before {
background-image: url(/@/assets/svg/login-bg-dark.svg);
background-image: url('/@/assets/svg/login-bg-dark.svg');
}
.ant-input,
......@@ -110,6 +111,7 @@
.@{prefix-cls} {
min-height: 100%;
overflow: hidden;
@media (max-width: @screen-xl) {
background-color: #293146;
.@{prefix-cls}-form {
......@@ -124,11 +126,12 @@
width: 100%;
height: 100%;
margin-left: -48%;
background-image: url(/@/assets/svg/login-bg.svg);
background-image: url('/@/assets/svg/login-bg.svg');
background-position: 100%;
background-repeat: no-repeat;
background-size: auto 100%;
content: '';
@media (max-width: @screen-xl) {
display: none;
}
......@@ -179,15 +182,19 @@
input:not([type='checkbox']) {
min-width: 360px;
@media (max-width: @screen-xl) {
min-width: 320px;
}
@media (max-width: @screen-lg) {
min-width: 260px;
}
@media (max-width: @screen-md) {
min-width: 240px;
}
@media (max-width: @screen-sm) {
min-width: 160px;
}
......
......@@ -17,6 +17,7 @@
import { useUserStore } from '/@/store/modules/user'
import { LoginStateEnum, useFormRules, useFormValid, useLoginState } from './useLogin'
import { useDesign } from '/@/hooks/web/useDesign'
// import { onKeyStroke } from '@vueuse/core';
const ACol = Col
......
......@@ -13,7 +13,7 @@
const appStore = useAppStore()
const userId = ref<Nullable<number | string>>(0)
const isBackMode = () => {
function isBackMode() {
return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK
}
......
module.exports = {
root: true,
plugins: ['stylelint-order'],
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
extends: ['stylelint-config-standard'],
customSyntax: 'postcss-html',
rules: {
'function-no-unknown': null,
......@@ -38,12 +38,9 @@ module.exports = {
'no-empty-source': null,
'string-quotes': null,
'named-grid-areas-no-invalid': null,
'unicode-bom': 'never',
'no-descending-specificity': null,
'media-feature-range-notation': null,
'font-family-no-missing-generic-family-keyword': null,
'declaration-colon-space-after': 'always-single-line',
'declaration-colon-space-before': 'never',
// 'declaration-block-trailing-semicolon': 'always',
'rule-empty-line-before': [
'always',
{
......@@ -76,7 +73,7 @@ module.exports = {
overrides: [
{
files: ['*.vue', '**/*.vue', '*.html', '**/*.html'],
extends: ['stylelint-config-recommended', 'stylelint-config-prettier', 'stylelint-config-recommended-vue'],
extends: ['stylelint-config-recommended', 'stylelint-config-recommended-vue'],
rules: {
'keyframes-name-pattern': null,
'selector-pseudo-class-no-unknown': [
......@@ -96,7 +93,7 @@ module.exports = {
{
files: ['*.less', '**/*.less'],
customSyntax: 'postcss-less',
extends: ['stylelint-config-standard', 'stylelint-config-prettier', 'stylelint-config-recommended-vue'],
extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
},
],
}
......@@ -43,6 +43,7 @@
"build/**/*.ts",
"build/**/*.d.ts",
"mock/**/*.ts",
"src-electron/preload/*.d.ts",
"vite.config.ts",
"package.json"
],
......
// Generated by 'unplugin-auto-import'
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-auto-import
export {}
declare global {
const $app: typeof import('@/config/app')['$app']
......@@ -42,13 +45,13 @@ declare global {
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveDirective: typeof import('vue')['resolveDirective']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
......@@ -63,3 +66,8 @@ declare global {
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue'
}
......@@ -25,7 +25,7 @@ declare global {
// }
// vue
declare type PropType<T> = VuePropType<T>
// declare type PropType<T> = VuePropType<T>
declare type VueNode = VNodeChild | JSX.Element
export type Writable<T> = {
......
......@@ -26,7 +26,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
// The boolean type read by loadEnv is a string. This function can be converted to boolean type
const viteEnv = wrapperEnv(env)
const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY, VITE_DROP_CONSOLE } = viteEnv
const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY } = viteEnv
const isBuild = command === 'build'
......@@ -62,17 +62,6 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
build: {
target: 'es2015',
cssTarget: 'chrome80',
minify: 'terser',
/**
* 当 minify=“minify:'terser'” 解开注释
* Uncomment when minify="minify:'terser'"
*/
terserOptions: {
compress: {
keep_infinity: true,
drop_console: VITE_DROP_CONSOLE,
},
},
// Turning off brotliSize display can slightly reduce packaging time
reportCompressedSize: false,
chunkSizeWarningLimit: 2000,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论