Initial commit

This commit is contained in:
net 2023-06-02 21:29:46 +08:00
commit 7fd2d8ae2d
235 changed files with 26833 additions and 0 deletions

22
.editorconfig Normal file
View File

@ -0,0 +1,22 @@
# 告诉EditorConfig插件这是根文件不用继续往上查找
root = true
# 匹配全部文件
[*]
# 设置字符集
charset = utf-8
# 缩进风格可选space、tab
indent_style = space
# 缩进的空格数
indent_size = 2
# 结尾换行符可选lf、cr、crlf
end_of_line = lf
# 在文件结尾插入新行
insert_final_newline = true
# 删除一行中的前后空格
trim_trailing_whitespace = true
# 匹配md结尾的文件
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

3
.env Normal file
View File

@ -0,0 +1,3 @@
# 页面标题
VITE_APP_TITLE = '阿尔文科技'

16
.env.development Normal file
View File

@ -0,0 +1,16 @@
# 开发环境配置
ENV = 'development'
VITE_APP_API_HOST = 'http://localhost:8888'
# 开发环境
VITE_APP_BASE_API = '/dev-api'
# 路由前缀
VITE_APP_ROUTER_PREFIX = '/'
# 默认上传地址
VITE_APP_UPLOAD_URL = '/Common/UploadFile'
#socket API
VITE_APP_SOCKET_API = '/msghub'

15
.env.production Normal file
View File

@ -0,0 +1,15 @@
# 生产环境配置
ENV = 'production'
# 生产环境
VITE_APP_BASE_API = '/prod-api'
# 路由前缀
VITE_APP_ROUTER_PREFIX = '/'
# 默认上传地址
VITE_APP_UPLOAD_URL = '/Common/UploadFile'
#socket API
VITE_APP_SOCKET_API = '/msghub'

18
.env.staging Normal file
View File

@ -0,0 +1,18 @@
# 测试环境配置
ENV = 'staging'
# 测试环境
VITE_APP_BASE_API = '/stage-api'
# 路由前缀
VITE_APP_ROUTER_PREFIX = '/'
# 默认上传地址
VITE_APP_UPLOAD_URL = '/Common/UploadFile'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
#socket API
VITE_APP_SOCKET_API = '/msghub'

14
.eslintignore Normal file
View File

@ -0,0 +1,14 @@
# 忽略build目录下类型为js的文件的语法检查
build/*.js
# 忽略src/assets目录下文件的语法检查
src/assets
# 忽略public目录下文件的语法检查
public
# 忽略当前目录下为js的文件的语法检查
# *.js
# 忽略当前目录下为vue的文件的语法检查
# *.vue
/node_modules/
/vite/
.eslintrc.js
.prettierrc.js

199
.eslintrc.js Normal file
View File

@ -0,0 +1,199 @@
// ESlint 检查配置
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline":"off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {"null": "ignore"}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock
/deploy.js

12
.jsbeautifyrc Normal file
View File

@ -0,0 +1,12 @@
{
"brace_style": "none,preserve-inline",
"indent_size": 2,
"indent_char": " ",
"jslint_happy": true,
"unformatted": [
""
],
"css": {
"indent_size": 2
}
}

38
.prettierrc.js Normal file
View File

@ -0,0 +1,38 @@
module.exports = {
// 超过最大值换行
printWidth: 148,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾不需要有分号
semi: false,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>"默认none
trailingComma: 'none',
// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: true,
bracketSameLine: true,
// 箭头函数always只有一个参数的时候也需要括号,'avoid'箭头函数只有一个参数的时候可以忽略括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
endOfLine: 'auto'
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"nuxt.isNuxtApp": false
}

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 791736813@qq.com zr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

89
README.md Normal file
View File

@ -0,0 +1,89 @@
<h2 align="center"> ZRAdmin.NET后台管理系统</h2>
<p align="center">
<a href="https://gitee.com/izory/ZrAdminNetCore"><img src="https://gitee.com/izory/ZrAdminNetCore/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/izory/ZrAdminNetCore/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
## 🍟概述
* 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
* 配套后端代码仓库地址[ZRAdmin.NET](https://gitee.com/izory/ZrAdminNetCore/) 版本。
* 前端采用Vue3.0、Element UI Plus、vite、compisition api、Pinia等。
* 支持加载动态权限菜单,多方式轻松权限控制
* 腾讯云秒杀场:[点我进入](https://curl.qcloud.com/4yEoRquq)。
* 腾讯云优惠券:[点我领取](https://curl.qcloud.com/5J4nag8D)。
* 七牛云通用云产品优惠券:[点我进入](https://s.qiniu.com/FzEfay)。
```
如果对您有帮助,您可以点右上角 “Star” 收藏一下 ,这样作者才有继续免费下去的动力,谢谢!~
```
## 🍿在线体验
- 官方文档http://www.izhaorui.cn/doc
- 体验地址http://www.izhaorui.cn/vue3
- 管理员admin
- 密 码123456
```
由于是个人项目,资金有限,体验服是低配,请大家爱惜,轻戳,不胜感激!!!
```
## 🍁前端运行
```bash
# 克隆项目
git clone https://gitee.com/izory/ZRAdmin-vue.git
# 进入项目目录
cd ZRAdmin-vue
# 安装依赖
yarn --registry=https://registry.npm.taobao.org
# 启动服务
yarn dev
# 构建测试环境 yarn build:stage
# 构建生产环境 yarn build:prod
# 前端访问地址 http://localhost:8887
```
## 🍖内置功能
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现。
3. 岗位管理:配置系统用户所属担任职务。
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。(支持多语言)
5. 角色管理:角色菜单权限分配。
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
7. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
8. 登录日志:系统登录日志记录查询包含登录异常。
9. 系统接口使用swagger生成相关api接口文档。
10. 参数设置:常用参数配置
11. 发送邮件:可以对多个用户进行发送邮件
12. 任务系统基于Quartz.NET可以在线添加、修改、删除、手动执行)任务调度包含执行结果日志。
13. 文章管理:可以写文章记录。
14. 代码生成:可以一键生成前后端代码(.cs、.vue、.js、SQL文件等),支持下载,自定义配置前端展示控件、让开发更快捷高效。
15. 文件管理:可以进行上传文件管理,目前支持上传到本地、阿里云
16. 通知管理:系统通知公告信息发布维护
17. 参数管理:对系统动态配置常用参数。
18. 多语言管理:动态修改多语言翻译
## 🎉优势
1. 前台系统不用编写登录、授权、认证模块;只负责编写业务模块即可
2. 后台系统无需任何二次开发,直接发布即可使用
3. 前台与后台系统分离,分别为不同的系统(域名可独立)
4. 全局异常统一处理
5. 自定义的代码生成功能
6. 国际化
## 💐 特别鸣谢
- 👉Ruoyi.vue[Ruoyi](http://www.ruoyi.vip/)
## 🎀捐赠
如果这个项目对您有所帮助,请扫下方二维码打赏作者喝杯咖啡。
<img src="https://gitee.com/izory/ZrAdminNetCore/raw/master/document/images/pay.jpg"/>
## 源码地址
- [Gitee](https://gitee.com/izory/ZrAdminNetCore/)
- [Github](https://github.com/izhaorui/ZrAdmin.NET/)

12
bat/build.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 打包Web工程生成dist文件。
echo.
%~d0
cd %~dp0
cd ..
yarn build:prod
pause

12
bat/package.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 安装Web工程生成node_modules文件。
echo.
%~d0
cd %~dp0
cd ..
yarn --registry=https://registry.npm.taobao.org
pause

12
bat/run-web.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 使用 Vite 命令运行 Web 工程。
echo.
%~d0
cd %~dp0
cd ..
yarn dev
pause

46
html/ie.html Normal file

File diff suppressed because one or more lines are too long

139
index.html Normal file
View File

@ -0,0 +1,139 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<title>阿尔文科技后台</title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
}
.chromeframe {
margin: 0.2em 0;
background: #ccc;
color: #000;
padding: 0.2em 0;
}
.first-loading-wrp {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 90vh;
min-height: 90vh;
}
.first-loading-wrp>h1 {
font-size: 30px;
font-weight: bolder;
}
.first-loading-wrp .loading-wrp {
display: flex;
align-items: center;
justify-content: center;
padding: 48px;
}
.dot {
position: relative;
box-sizing: border-box;
display: inline-block;
width: 45px;
height: 45px;
font-size: 64px;
transform: rotate(45deg);
animation: antRotate 1.2s infinite linear;
}
.dot i {
position: absolute;
display: block;
width: 16px;
height: 16px;
background-color: #1890ff;
border-radius: 100%;
opacity: 0.3;
transform: scale(0.75);
transform-origin: 50% 50%;
animation: antSpinMove 1s infinite linear alternate;
}
.dot i:nth-child(1) {
top: 0;
left: 0;
}
.dot i:nth-child(2) {
top: 0;
right: 0;
-webkit-animation-delay: 0.4s;
animation-delay: 0.4s;
}
.dot i:nth-child(3) {
right: 0;
bottom: 0;
-webkit-animation-delay: 0.8s;
animation-delay: 0.8s;
}
.dot i:nth-child(4) {
bottom: 0;
left: 0;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
@keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@-webkit-keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antSpinMove {
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div id="app">
<div class="first-loading-wrp">
<div class="loading-wrp">
<span class="dot dot-spin"> <i></i> <i></i> <i></i> <i></i> </span>
</div>
<h5>Loading...</h5>
</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

11
jsconfig.json Normal file
View File

@ -0,0 +1,11 @@
/* vscode使 */
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist", ".vscode"]
}

55
package.json Normal file
View File

@ -0,0 +1,55 @@
{
"name": "arw.admin",
"version": "3.8.2",
"description": "阿尔文后台管理系统",
"author": "Aerwen",
"license": "MIT",
"scripts": {
"dev": "vite",
"build:prod": "vite build",
"build:stage": "vite build --mode staging",
"preview": "vite preview"
},
"repository": {
"type": "git",
"url": "https://gitee.com/izory/ZrAdminNetCore"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@element-plus/icons-vue": "^0.2.7",
"@microsoft/signalr": "^6.0.5",
"@vueuse/core": "^8.9.4",
"@wangeditor/editor": "^5.1.1",
"@wangeditor/editor-for-vue": "^5.1.11",
"axios": "^0.27.2",
"countup.js": "^2.1.0",
"echarts": "5.2.2",
"element-plus": "^2.3.2",
"file-saver": "2.0.5",
"fuse.js": "6.4.6",
"highlight.js": "^11.5.1",
"js-cookie": "3.0.1",
"js-md5": "^0.7.3",
"jsencrypt": "3.2.1",
"md-editor-v3": "^1.11.11",
"nprogress": "0.2.0",
"pinia": "^2.0.33",
"qs": "^6.11.0",
"sortablejs": "^1.15.0",
"vue": "^3.2.47",
"vue-clipboard3": "^2.0.0",
"vue-cropper": "1.0.2",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"@vue/compiler-sfc": "^3.2.47",
"sass": "1.45.0",
"unplugin-auto-import": "0.5.3",
"vite": "^4.2.1",
"vite-plugin-compression": "^0.3.6",
"vite-plugin-svg-icons": "1.0.5",
"vite-plugin-vue-setup-extend": "^0.4.0"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
public/logo_500.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

56
src/App.vue Normal file
View File

@ -0,0 +1,56 @@
<template>
<el-config-provider :locale="locale" :size="size">
<router-view />
</el-config-provider>
</template>
<script setup>
import useUserStore from './store/modules/user'
import useAppStore from './store/modules/app'
import { ElConfigProvider } from 'element-plus'
import zh from 'element-plus/lib/locale/lang/zh-cn' //
import en from 'element-plus/lib/locale/lang/en' //
import tw from 'element-plus/lib/locale/lang/zh-tw' //
import defaultSettings from '@/settings'
const { proxy } = getCurrentInstance()
const token = computed(() => {
return useUserStore().userId
})
const lang = computed(() => {
return useAppStore().lang
})
const locale = ref(zh)
const size = ref(defaultSettings.defaultSize)
size.value = useAppStore().size
watch(
token,
(val) => {
if (val) {
proxy.signalr.start()
}
},
{
immediate: true,
deep: true
}
)
watch(
lang,
(val) => {
if (val == 'zh-cn') {
locale.value = zh
} else if (val == 'en') {
locale.value = en
} else if (val == 'zh-tw') {
locale.value = tw
} else {
locale.value = zh
}
},
{
immediate: true
}
)
</script>

View File

@ -0,0 +1,37 @@
import request from '@/utils/request'
// 小程序客户分页查询列表
export function customerList(query) {
return request({
url: '/business/Customer/getCustomerList',
method: 'get',
params: query
})
}
// 小程序客户新增或修改
export function addOrUpdateCustomer(data) {
return request({
url: '/business/Customer/addOrUpdateCustomer',
method: 'post',
data: data,
})
}
// 小程序客户删除
export function delCustomer(ids) {
return request({
url: '/business/Customer/'+ ids,
method: 'delete'
})
}
// 小程序客户导出
export function exportCustomer(query) {
return request({
url: 'business/Customer/export',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,37 @@
import request from '@/utils/request'
// 支付订单分页查询列表
export function paymentList(query) {
return request({
url: '/business/Payment/getPaymentList',
method: 'get',
params: query
})
}
// 支付订单新增或修改
export function addOrUpdatePayment(data) {
return request({
url: '/business/Payment/addOrUpdatePayment',
method: 'post',
data: data,
})
}
// 支付订单删除
export function delPayment(ids) {
return request({
url: '/business/Payment/'+ ids,
method: 'delete'
})
}
// 支付订单导出
export function exportPayment(query) {
return request({
url: 'business/Payment/export',
method: 'get',
params: query
})
}

23
src/api/common.js Normal file
View File

@ -0,0 +1,23 @@
import request from '@/utils/request'
export function upload(data) {
return request({
url: '/common/UploadFile',
method: 'POST',
data: data,
headers: { "Content-Type": "multipart/form-data" },
})
}
/**
* 发送邮件
* @param {*} data
* @returns
*/
export function sendEmail(data) {
return request({
url: '/common/SendEmail',
method: 'POST',
data: data,
})
}

9
src/api/monitor/cache.js Normal file
View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
// 查询缓存详细
export function getCache() {
return request({
url: '/monitor/cache',
method: 'get'
})
}

114
src/api/monitor/job.js Normal file
View File

@ -0,0 +1,114 @@
import request from '@/utils/request'
export function queryTasks(data) {
return request({
url: '/system/tasks/list',
method: 'get',
params: data
})
}
export function getTasks(id) {
return request({
url: '/system/tasks/get?id=' + id,
method: 'get'
})
}
/**
*
* 获取所有任务
* @returns
*/
export function getAllTasks() {
return request({
url: '/system/tasks/getAll',
method: 'get'
})
}
/**
* 创建任务
* @param {*} data
* @returns
*/
export function createTasks(data) {
return request({
url: '/system/tasks/create',
method: 'post',
data
})
}
/**
* 更新任务
* @param {*} data
* @returns
*/
export function updateTasks(data) {
return request({
url: '/system/tasks/update',
method: 'post',
data
})
}
/**
* 删除任务
* @param {*} id
* @returns
*/
export function deleteTasks(id) {
return request({
url: '/system/tasks/delete?id=' + id,
method: 'delete'
})
}
/**
* 启动任务
* @param {*} id
* @returns
*/
export function startTasks(id) {
return request({
url: '/system/tasks/start?id=' + id,
method: 'get'
})
}
/**
* 停止任务
* @param {*} id
* @returns
*/
export function stopTasks(id) {
return request({
url: '/system/tasks/stop?id=' + id,
method: 'get'
})
}
/**
* 运行一次
* @param {*} id
* @returns
*/
export function runTasks(id) {
return request({
url: '/system/tasks/run?id=' + id,
method: 'get'
})
}
/**
* 导出
* @returns
*/
export function exportTasks() {
return request({
url: '/system/tasks/export',
method: 'get'
})
}
export default { queryTasks, getTasks, getAllTasks, createTasks, updateTasks, deleteTasks, startTasks, stopTasks, runTasks, exportTasks }

35
src/api/monitor/jobLog.js Normal file
View File

@ -0,0 +1,35 @@
import request from '@/utils/request'
// 查询调度日志列表
export function listJobLog(query) {
return request({
url: '/monitor/jobLog/list',
method: 'get',
params: query
})
}
// 删除调度日志
export function delJobLog(jobLogId) {
return request({
url: '/monitor/jobLog/' + jobLogId,
method: 'delete'
})
}
// 清空调度日志
export function cleanJobLog() {
return request({
url: '/monitor/jobLog/clean',
method: 'delete'
})
}
// 导出调度日志
export function exportJobLog(query) {
return request({
url: '/monitor/jobLog/export',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,35 @@
import request from '@/utils/request'
// 查询登录日志列表
export function list(query) {
return request({
url: '/monitor/logininfor/list',
method: 'get',
params: query
})
}
// 删除登录日志
export function delLogininfor(infoId) {
return request({
url: '/monitor/logininfor/' + infoId,
method: 'delete'
})
}
// 清空登录日志
export function cleanLogininfor() {
return request({
url: '/monitor/logininfor/clean',
method: 'delete'
})
}
// 导出登录日志
export function exportLogininfor(query) {
return request({
url: '/monitor/logininfor/export',
method: 'get',
params: query
})
}

18
src/api/monitor/online.js Normal file
View File

@ -0,0 +1,18 @@
import request from '@/utils/request'
// 查询在线用户列表
export function listOnline(query) {
return request({
url: '/monitor/online/list',
method: 'get',
params: query
})
}
// 强退用户
export function forceLogout(tokenId) {
return request({
url: '/monitor/online/' + tokenId,
method: 'delete'
})
}

View File

@ -0,0 +1,35 @@
import request from '@/utils/request'
// 查询操作日志列表
export function list(query) {
return request({
url: '/monitor/operlog/list',
method: 'get',
params: query
})
}
// 删除操作日志
export function delOperlog(operId) {
return request({
url: '/monitor/operlog/' + operId,
method: 'delete'
})
}
// 清空操作日志
export function cleanOperlog() {
return request({
url: '/monitor/operlog/clean',
method: 'delete'
})
}
// 导出操作日志
export function exportOperlog(query) {
return request({
url: '/monitor/operlog/export',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
// 查询服务器详细
export function getServer() {
return request({
url: '/monitor/server',
method: 'get'
})
}

View File

@ -0,0 +1,89 @@
import request from '@/utils/request'
/**
* 多语言配置分页查询
* @param {查询条件} data
*/
export function listCommonLang(query) {
return request({
url: 'system/CommonLang/list',
method: 'get',
params: query,
})
}
/**
* 多语言配置查询
* @param {查询条件} data
*/
export function listLangByLocale(locale) {
return request({
url: 'system/CommonLang/list/' + locale,
method: 'get',
})
}
/**
* 新增多语言配置
* @param data
*/
export function addCommonLang(data) {
return request({
url: 'system/CommonLang',
method: 'post',
data: data,
})
}
/**
* 修改多语言配置
* @param data
*/
export function updateCommonLang(data) {
return request({
url: 'system/CommonLang',
method: 'PUT',
data: data,
})
}
/**
* 获取多语言配置详情
* @param {Id}
*/
export function getCommonLang(id) {
return request({
url: 'system/CommonLang/' + id,
method: 'get'
})
}
/**
* 获取多语言配置详情
* @param {key}
*/
export function getCommonLangByKey(key) {
return request({
url: 'system/CommonLang/key/' + key,
method: 'get'
})
}
/**
* 删除多语言配置
* @param {主键} pid
*/
export function delCommonLang(pid) {
return request({
url: 'system/CommonLang/' + pid,
method: 'delete'
})
}
// 导出多语言配置
export function exportCommonLang(query) {
return request({
url: 'system/CommonLang/export',
method: 'get',
params: query
})
}

69
src/api/system/config.js Normal file
View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
// 查询参数列表
export function listConfig(query) {
return request({
url: '/system/config/list',
method: 'get',
params: query
})
}
// 查询参数详细
export function getConfig(configId) {
return request({
url: '/system/config/' + configId,
method: 'get'
})
}
// 根据参数键名查询参数值
export function getConfigKey(configKey) {
return request({
url: '/system/config/configKey/' + configKey,
method: 'get'
})
}
// 新增参数配置
export function addConfig(data) {
return request({
url: '/system/config',
method: 'post',
data: data
})
}
// 修改参数配置
export function updateConfig(data) {
return request({
url: '/system/config',
method: 'put',
data: data
})
}
// 删除参数配置
export function delConfig(configId) {
return request({
url: '/system/config/' + configId,
method: 'delete'
})
}
// 刷新参数缓存
export function refreshCache() {
return request({
url: '/system/config/refreshCache',
method: 'delete'
})
}
// 导出参数
// export function exportConfig(query) {
// return request({
// url: '/system/config/export',
// method: 'get',
// params: query
// })
// }

68
src/api/system/dept.js Normal file
View File

@ -0,0 +1,68 @@
import request from '@/utils/request'
// 查询部门列表
export function listDept(query) {
return request({
url: '/system/dept/list',
method: 'get',
params: query
})
}
// 查询部门列表(排除节点)
export function listDeptExcludeChild(deptId) {
return request({
url: '/system/dept/list/exclude/' + deptId,
method: 'get'
})
}
// 查询部门详细
export function getDept(deptId) {
return request({
url: '/system/dept/' + deptId,
method: 'get'
})
}
// 查询部门下拉树结构
export function treeselect() {
return request({
url: '/system/dept/treeselect',
method: 'get'
})
}
// 根据角色ID查询部门树结构
export function roleDeptTreeselect(roleId) {
return request({
url: '/system/dept/roleDeptTreeselect/' + roleId,
method: 'get'
})
}
// 新增部门
export function addDept(data) {
return request({
url: '/system/dept',
method: 'post',
data: data
})
}
// 修改部门
export function updateDept(data) {
return request({
url: '/system/dept',
method: 'put',
data: data
})
}
// 删除部门
export function delDept(deptId) {
return request({
url: '/system/dept/' + deptId,
method: 'delete'
})
}

View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
// 查询字典数据列表
export function listData(query) {
return request({
url: '/system/dict/data/list',
method: 'get',
params: query
})
}
// 查询字典数据详细
export function getData(dictCode) {
return request({
url: '/system/dict/data/info/' + dictCode,
method: 'get'
})
}
// 根据字典类型查询字典数据信息
export function getDicts(dictType) {
if (typeof (dictType) === "object") {
return request({
url: '/system/dict/data/types',
data: dictType,
method: 'post'
})
} else {
return request({
url: '/system/dict/data/type/' + dictType,
method: 'get'
})
}
}
// 新增字典数据
export function addData(data) {
return request({
url: '/system/dict/data',
method: 'post',
data: data
})
}
// 修改字典数据
export function updateData(data) {
return request({
url: '/system/dict/data',
method: 'put',
data: data
})
}
// 删除字典数据
export function delData(dictCode) {
return request({
url: '/system/dict/data/' + dictCode,
method: 'delete'
})
}
// 导出字典数据
export function exportData(query) {
return request({
url: '/system/dict/data/export',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
// 查询字典类型列表
export function listType(query) {
return request({
url: '/system/dict/type/list',
method: 'get',
params: query
})
}
// 查询字典类型详细
export function getType(dictId) {
return request({
url: '/system/dict/type/' + dictId,
method: 'get'
})
}
// 新增字典类型
export function addType(data) {
return request({
url: '/system/dict/type/edit',
method: 'post',
data: data
})
}
// 修改字典类型
export function updateType(data) {
return request({
url: '/system/dict/type/edit',
method: 'put',
data: data
})
}
// 删除字典类型
export function delType(dictId) {
return request({
url: '/system/dict/type/' + dictId,
method: 'delete'
})
}
// 清理参数缓存
export function clearCache() {
return request({
url: '/system/dict/type/clearCache',
method: 'delete'
})
}
// 导出字典类型
export function exportType(query) {
return request({
url: '/system/dict/type/export',
method: 'get',
params: query
})
}
// 获取字典选择框列表
export function optionselect() {
return request({
url: '/system/dict/type/optionselect',
method: 'get'
})
}

69
src/api/system/login.js Normal file
View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
// 登录方法
export function login(username, password, code, uuid) {
const data = {
username,
password,
code,
uuid
}
return request({
url: '/login',
method: 'POST',
data: data,
headers: {
userName: username
}
})
}
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
method: 'get'
})
}
// 退出方法
export function logout() {
return request({
url: '/LogOut',
method: 'POST'
})
}
// 获取验证码
export function getCodeImg() {
return request({
url: '/captchaImage',
method: 'get'
})
}
/**
* 注册
* @returns
*/
export function register(data) {
return request({
url: '/register',
method: 'post',
data: data
})
}
/**
* 三方授权回调
* @param {*} data
* @param {*} params
* @returns
*/
export function oauthCallback(data, params) {
return request({
url: '/auth/callback',
method: 'post',
data: data,
params: params
})
}

84
src/api/system/menu.js Normal file
View File

@ -0,0 +1,84 @@
import request from '@/utils/request'
// 查询菜单列表
export function listMenu(query) {
return request({
url: '/system/menu/list',
method: 'get',
params: query
})
}
// 查询菜单列表
export function listMenuById(menuId) {
return request({
url: '/system/menu/list/' + menuId,
method: 'get',
})
}
// 查询菜单详细
export function getMenu(menuId) {
return request({
url: '/system/menu/' + menuId,
method: 'get',
})
}
// 查询菜单下拉树结构
export function treeselect() {
return request({
url: '/system/Menu/treeSelect',
method: 'get'
})
}
// 根据角色ID查询菜单下拉树结构
export function roleMenuTreeselect(roleId) {
return request({
url: '/system/menu/roleMenuTreeselect/' + roleId,
method: 'get',
})
}
// 新增菜单
export const addMenu = (data) => {
return request({
url: '/system/menu/add',
method: 'put',
data: data,
})
}
// 修改菜单
export function updateMenu(data) {
return request({
url: '/system/Menu/edit',
method: 'post',
data: data
})
}
// 删除菜单
export function delMenu(menuId) {
return request({
url: '/system/Menu/' + menuId,
method: 'delete'
})
}
//排序
export function changeMenuSort(data) {
return request({
url: '/system/Menu/ChangeSort',
method: 'GET',
params: data
})
}
// 获取路由
export const getRouters = (query) => {
return request({
url: '/getRouters',
method: 'get',
params: query
})
}

61
src/api/system/notice.js Normal file
View File

@ -0,0 +1,61 @@
import request from '@/utils/request'
// 导航栏查询公告列表
export function queryNotice(query) {
return request({
url: '/system/notice/queryNotice',
method: 'get',
params: query
})
}
// 查询公告列表
export function listNotice(query) {
return request({
url: '/system/notice/list',
method: 'get',
params: query
})
}
// 查询公告详细
export function getNotice(noticeId) {
return request({
url: '/system/notice/' + noticeId,
method: 'get'
})
}
// 新增公告
export function addNotice(data) {
return request({
url: '/system/notice',
method: 'post',
data: data
})
}
// 修改公告
export function updateNotice(data) {
return request({
url: '/system/notice',
method: 'put',
data: data
})
}
// 删除公告
export function delNotice(noticeId) {
return request({
url: '/system/notice/' + noticeId,
method: 'delete'
})
}
// 发送通知公告
export function sendNotice(noticeId) {
return request({
url: '/system/notice/send/' + noticeId,
method: 'PUT'
})
}

54
src/api/system/post.js Normal file
View File

@ -0,0 +1,54 @@
import request from '@/utils/request'
import { downFile } from '@/utils/request'
// 查询岗位列表
export function listPost(query) {
return request({
url: '/system/post/list',
method: 'get',
params: query
})
}
// 查询岗位详细
export function getPost(postId) {
return request({
url: '/system/post/' + postId,
method: 'get'
})
}
// 新增岗位
export function addPost(data) {
return request({
url: '/system/post',
method: 'post',
data: data
})
}
// 修改岗位
export function updatePost(data) {
return request({
url: '/system/post',
method: 'put',
data: data
})
}
// 删除岗位
export function delPost(postId) {
return request({
url: '/system/post/' + postId,
method: 'delete'
})
}
// 导出岗位
export async function exportPost(query) {
// return request({
// url: '/system/post/export',
// method: 'get',
// params: query
// })
await downFile('/system/post/export', query)
}

75
src/api/system/role.js Normal file
View File

@ -0,0 +1,75 @@
import request from '@/utils/request'
// 查询角色列表
export function listRole(query) {
return request({
url: '/system/role/list',
method: 'get',
params: query
})
}
// 查询角色详细
export function getRole(roleId) {
return request({
url: '/system/role/' + roleId,
method: 'get'
})
}
// 新增角色
export const addRole = (data) => {
return request({
url: '/system/role/edit',
method: 'post',
data: data,
})
}
// 修改角色
export function updateRole(data) {
return request({
url: '/system/role/edit',
method: 'put',
data: data
})
}
// 角色数据权限
export function dataScope(data) {
return request({
url: '/system/role/dataScope',
method: 'put',
data: data
})
}
// 角色状态修改
export function changeRoleStatus(roleId, status) {
const data = {
roleId,
status
}
return request({
url: '/system/role/changeStatus',
method: 'put',
data: data
})
}
// 删除角色
export function delRole(roleId) {
return request({
url: '/system/role/' + roleId,
method: 'delete'
})
}
// 导出角色
export function exportRole(query) {
return request({
url: '/system/role/export',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,70 @@
import request from '@/utils/request'
/**
* 三方账号绑定分页查询
* @param {查询条件} data
*/
export function listThirdAccount(query) {
return request({
url: 'system/ThirdAccount/list',
method: 'get',
params: query,
})
}
/**
* 新增三方账号绑定
* @param data
*/
export function addThirdAccount(data) {
return request({
url: 'system/ThirdAccount',
method: 'post',
data: data,
})
}
/**
* 修改三方账号绑定
* @param data
*/
export function updateThirdAccount(data) {
return request({
url: 'system/ThirdAccount',
method: 'PUT',
data: data,
})
}
/**
* 获取三方账号绑定详情
* @param {Id}
*/
export function getThirdAccount(id) {
return request({
url: 'system/ThirdAccount/' + id,
method: 'get'
})
}
/**
* 删除三方账号绑定
* @param {主键} pid
*/
export function delThirdAccount(pid) {
return request({
url: 'system/ThirdAccount/' + pid,
method: 'delete'
})
}
// 导出三方账号绑定
export function exportThirdAccount(query) {
return request({
url: 'system/ThirdAccount/export',
method: 'get',
params: query
})
}

130
src/api/system/user.js Normal file
View File

@ -0,0 +1,130 @@
import request from '@/utils/request'
import { praseStrZero } from '@/utils/ruoyi'
import { downFile } from '@/utils/request'
// 查询用户列表
export function listUser(query) {
return request({
url: '/system/user/list',
method: 'get',
params: query
})
}
// 查询用户详细
export function getUser(userId) {
return request({
url: '/system/user/' + praseStrZero(userId),
method: 'get'
})
}
// 新增用户
export function addUser(data) {
return request({
url: '/system/user/edit',
method: 'post',
data: data
})
}
// 修改用户
export function updateUser(data) {
return request({
url: '/system/user/edit',
method: 'put',
data: data
})
}
// 删除用户
export function delUser(userId) {
return request({
url: '/system/user/' + userId,
method: 'delete'
})
}
// 导出用户
export async function exportUser(query) {
// return request({
// url: '/system/User/export',
// method: 'get',
// params: query
// })
await downFile('/system/user/export', { ...query })
}
// 用户密码重置
export function resetUserPwd(userId, password) {
const data = {
userId,
password
}
return request({
url: '/system/user/resetPwd',
method: 'put',
data: data
})
}
// 用户状态修改
export function changeUserStatus(userId, status) {
const data = {
userId,
status
}
return request({
url: '/system/user/changeStatus',
method: 'put',
data: data
})
}
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/Profile',
method: 'get'
})
}
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
method: 'put',
data: data
})
}
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
const data = {
oldPassword,
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
params: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return request({
url: '/system/user/profile/avatar',
method: 'post',
data: data
})
}
// 下载用户导入模板
export function importTemplate() {
return request({
url: '/system/user/importTemplate',
method: 'get',
responseType: 'blob' //1.首先设置responseType对象格式为 blob:
})
}

View File

@ -0,0 +1,37 @@
import request from '@/utils/request'
// 查询角色用户
export function getRoleUsers(query) {
return request({
url: '/system/userRole/list',
method: 'get',
params: query,
})
}
// 添加角色用户
export function createRoleUsers(data) {
return request({
url: '/system/userRole/create',
method: 'post',
data
})
}
// 删除角色用户
export function deleteRoleUsers(data) {
return request({
url: '/system/userRole/delete',
method: 'post',
data
})
}
// 查询角色未添加用户列表
export function getExcludeUsers(query) {
return request({
url: '/system/userRole/getExcludeUsers',
method: 'get',
params: query,
})
}
// export default { getRoleUsers, getExcludeUsers }

69
src/api/tool/file.js Normal file
View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
/**
* 文件存储分页查询
* @param {查询条件} data
*/
export function listSysfile(query) {
return request({
url: 'tool/file/list',
method: 'get',
params: query,
})
}
/**
* 新增文件存储
* @param data
*/
export function addSysfile(data) {
return request({
url: 'tool/file',
method: 'post',
data: data,
})
}
/**
* 修改文件存储
* @param data
*/
export function updateSysfile(data) {
return request({
url: 'tool/file',
method: 'PUT',
data: data,
})
}
/**
* 获取文件存储详情
* @param {Id}
*/
export function getSysfile(id) {
return request({
url: 'tool/file/' + id,
method: 'get'
})
}
/**
* 删除文件存储
* @param {主键} pid
*/
export function delSysfile(pid) {
return request({
url: 'tool/file/' + pid,
method: 'delete'
})
}
// 导出文件存储
export function exportSysfile(query) {
return request({
url: 'tool/file/export',
method: 'get',
params: query
})
}

114
src/api/tool/gen.js Normal file
View File

@ -0,0 +1,114 @@
import request from '@/utils/request';
/**
* 获取数据库
*/
export function codeGetDBList() {
return request({
url: 'tool/gen/getDbList',
method: 'get',
})
}
/**
* 获取数据库表
*/
export function listDbTable(data) {
return request({
url: 'tool/gen/getTableList',
method: 'get',
params: data,
})
}
/**
* 生成代码
*/
export async function codeGenerator(data) {
return await request({
url: 'tool/gen/genCode',
method: 'POST',
data: data,
})
}
/**
* 前端接口
*/
export async function codeGeneratorApi(data) {
return await request({
url: 'tool/gen/genCodeApi',
method: 'POST',
data: data,
})
}
/**
* 获取表格列信息
* @param {*} data
* @returns
*/
export function queryColumnInfo(tableId) {
return request({
url: 'tool/gen/Column/' + tableId,
method: 'GET',
})
}
// 查询生成表数据
export function listTable(params) {
return request({
url: 'tool/gen/list',
method: 'get',
params: params
})
}
// 查询表详细信息
export function getGenTable(tableId) {
return request({
url: '/tool/gen/' + tableId,
method: 'get'
})
}
// 导入表
export function importTable(data) {
return request({
url: '/tool/gen/importTable',
method: 'post',
params: data
})
}
// 删除表数据
export function delTable(tableId) {
return request({
url: '/tool/gen/' + tableId,
method: 'delete'
})
}
// 修改代码生成表信息
export function updateGenTable(data) {
return request({
url: '/tool/gen/',
method: 'put',
data: data
})
}
// 预览生成代码
export function previewTable(tableId, data) {
return request({
url: '/tool/gen/preview/' + tableId,
method: 'post',
params: data
})
}
// 同步数据库
export function synchDb(tableId, data) {
return request({
url: '/tool/gen/synchDb/' + tableId,
method: 'get',
params: data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,391 @@
@font-face {
font-family: "iconfont"; /* Project id 4017520 */
src: url('iconfont.woff2?t=1681548759797') format('woff2'),
url('iconfont.woff?t=1681548759797') format('woff'),
url('iconfont.ttf?t=1681548759797') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-tree-table:before {
content: "\e637";
}
.icon-unlock:before {
content: "\e654";
}
.icon-zujian:before {
content: "\e655";
}
.icon-theme:before {
content: "\e659";
}
.icon-swagger:before {
content: "\e65c";
}
.icon-star:before {
content: "\e661";
}
.icon-time:before {
content: "\e662";
}
.icon-upload:before {
content: "\e663";
}
.icon-weixin:before {
content: "\e664";
}
.icon-system:before {
content: "\e667";
}
.icon-web:before {
content: "\e668";
}
.icon-tree:before {
content: "\e669";
}
.icon-user:before {
content: "\e66a";
}
.icon-tool:before {
content: "\e66b";
}
.icon-zip:before {
content: "\e66c";
}
.icon-link:before {
content: "\e636";
}
.icon-list:before {
content: "\e638";
}
.icon-international:before {
content: "\e639";
}
.icon-language:before {
content: "\e63a";
}
.icon-index:before {
content: "\e63b";
}
.icon-ipvisits:before {
content: "\e63c";
}
.icon-money:before {
content: "\e63d";
}
.icon-message:before {
content: "\e63e";
}
.icon-login:before {
content: "\e63f";
}
.icon-lock:before {
content: "\e640";
}
.icon-menu:before {
content: "\e641";
}
.icon-log:before {
content: "\e643";
}
.icon-logininfor:before {
content: "\e644";
}
.icon-mnt:before {
content: "\e645";
}
.icon-password:before {
content: "\e646";
}
.icon-peoples:before {
content: "\e647";
}
.icon-post:before {
content: "\e648";
}
.icon-permission:before {
content: "\e649";
}
.icon-phone:before {
content: "\e64a";
}
.icon-people:before {
content: "\e64b";
}
.icon-online:before {
content: "\e64d";
}
.icon-pdf:before {
content: "\e64f";
}
.icon-redis:before {
content: "\e650";
}
.icon-size:before {
content: "\e651";
}
.icon-search:before {
content: "\e652";
}
.icon-server:before {
content: "\e653";
}
.icon-select:before {
content: "\e656";
}
.icon-question:before {
content: "\e657";
}
.icon-rate:before {
content: "\e658";
}
.icon-monitor:before {
content: "\e65a";
}
.icon-source:before {
content: "\e65b";
}
.icon-role:before {
content: "\e65d";
}
.icon-shopping:before {
content: "\e65e";
}
.icon-skill:before {
content: "\e65f";
}
.icon-number:before {
content: "\e660";
}
.icon-a-404:before {
content: "\e622";
}
.icon-email:before {
content: "\e623";
}
.icon-example:before {
content: "\e624";
}
.icon-error:before {
content: "\e625";
}
.icon-excel:before {
content: "\e626";
}
.icon-education:before {
content: "\e627";
}
.icon-eye-open:before {
content: "\e628";
}
.icon-eye:before {
content: "\e629";
}
.icon-github:before {
content: "\e62b";
}
.icon-guide:before {
content: "\e62c";
}
.icon-gonggao:before {
content: "\e62d";
}
.icon-icon1:before {
content: "\e62e";
}
.icon-fullscreen:before {
content: "\e62f";
}
.icon-icon:before {
content: "\e630";
}
.icon-image:before {
content: "\e631";
}
.icon-form:before {
content: "\e632";
}
.icon-job:before {
content: "\e635";
}
.icon-cascader:before {
content: "\e603";
}
.icon-alipay:before {
content: "\e604";
}
.icon-anq:before {
content: "\e605";
}
.icon-backup:before {
content: "\e606";
}
.icon-bug:before {
content: "\e607";
}
.icon-button:before {
content: "\e609";
}
.icon-chain:before {
content: "\e60b";
}
.icon-chart:before {
content: "\e60c";
}
.icon-checkbox:before {
content: "\e60d";
}
.icon-clipboard:before {
content: "\e60e";
}
.icon-codeConsole:before {
content: "\e60f";
}
.icon-code:before {
content: "\e610";
}
.icon-color:before {
content: "\e611";
}
.icon-database:before {
content: "\e612";
}
.icon-component:before {
content: "\e613";
}
.icon-dashboard:before {
content: "\e614";
}
.icon-date:before {
content: "\e615";
}
.icon-deploy:before {
content: "\e616";
}
.icon-develop:before {
content: "\e617";
}
.icon-dept:before {
content: "\e619";
}
.icon-dictionary:before {
content: "\e61a";
}
.icon-documentation:before {
content: "\e61b";
}
.icon-doc:before {
content: "\e61c";
}
.icon-download:before {
content: "\e61d";
}
.icon-dict:before {
content: "\e61e";
}
.icon-edit:before {
content: "\e620";
}
.icon-app:before {
content: "\e602";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,667 @@
{
"id": "4017520",
"name": "admin",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "35076965",
"name": "tree-table",
"font_class": "tree-table",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "35076967",
"name": "unlock",
"font_class": "unlock",
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "35076968",
"name": "zujian",
"font_class": "zujian",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "35076969",
"name": "theme",
"font_class": "theme",
"unicode": "e659",
"unicode_decimal": 58969
},
{
"icon_id": "35076970",
"name": "swagger",
"font_class": "swagger",
"unicode": "e65c",
"unicode_decimal": 58972
},
{
"icon_id": "35076971",
"name": "star",
"font_class": "star",
"unicode": "e661",
"unicode_decimal": 58977
},
{
"icon_id": "35076972",
"name": "time",
"font_class": "time",
"unicode": "e662",
"unicode_decimal": 58978
},
{
"icon_id": "35076973",
"name": "upload",
"font_class": "upload",
"unicode": "e663",
"unicode_decimal": 58979
},
{
"icon_id": "35076974",
"name": "weixin",
"font_class": "weixin",
"unicode": "e664",
"unicode_decimal": 58980
},
{
"icon_id": "35076977",
"name": "system",
"font_class": "system",
"unicode": "e667",
"unicode_decimal": 58983
},
{
"icon_id": "35076979",
"name": "web",
"font_class": "web",
"unicode": "e668",
"unicode_decimal": 58984
},
{
"icon_id": "35076980",
"name": "tree",
"font_class": "tree",
"unicode": "e669",
"unicode_decimal": 58985
},
{
"icon_id": "35076981",
"name": "user",
"font_class": "user",
"unicode": "e66a",
"unicode_decimal": 58986
},
{
"icon_id": "35076982",
"name": "tool",
"font_class": "tool",
"unicode": "e66b",
"unicode_decimal": 58987
},
{
"icon_id": "35076986",
"name": "zip",
"font_class": "zip",
"unicode": "e66c",
"unicode_decimal": 58988
},
{
"icon_id": "35076492",
"name": "link",
"font_class": "link",
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "35076494",
"name": "list",
"font_class": "list",
"unicode": "e638",
"unicode_decimal": 58936
},
{
"icon_id": "35076495",
"name": "international",
"font_class": "international",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "35076496",
"name": "language",
"font_class": "language",
"unicode": "e63a",
"unicode_decimal": 58938
},
{
"icon_id": "35076497",
"name": "index",
"font_class": "index",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "35076498",
"name": "ipvisits",
"font_class": "ipvisits",
"unicode": "e63c",
"unicode_decimal": 58940
},
{
"icon_id": "35076499",
"name": "money",
"font_class": "money",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "35076500",
"name": "message",
"font_class": "message",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "35076501",
"name": "login",
"font_class": "login",
"unicode": "e63f",
"unicode_decimal": 58943
},
{
"icon_id": "35076502",
"name": "lock",
"font_class": "lock",
"unicode": "e640",
"unicode_decimal": 58944
},
{
"icon_id": "35076503",
"name": "menu",
"font_class": "menu",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "35076505",
"name": "log",
"font_class": "log",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "35076506",
"name": "logininfor",
"font_class": "logininfor",
"unicode": "e644",
"unicode_decimal": 58948
},
{
"icon_id": "35076507",
"name": "mnt",
"font_class": "mnt",
"unicode": "e645",
"unicode_decimal": 58949
},
{
"icon_id": "35076509",
"name": "password",
"font_class": "password",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "35076510",
"name": "peoples",
"font_class": "peoples",
"unicode": "e647",
"unicode_decimal": 58951
},
{
"icon_id": "35076511",
"name": "post",
"font_class": "post",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "35076512",
"name": "permission",
"font_class": "permission",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "35076513",
"name": "phone",
"font_class": "phone",
"unicode": "e64a",
"unicode_decimal": 58954
},
{
"icon_id": "35076514",
"name": "people",
"font_class": "people",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "35076516",
"name": "online",
"font_class": "online",
"unicode": "e64d",
"unicode_decimal": 58957
},
{
"icon_id": "35076518",
"name": "pdf",
"font_class": "pdf",
"unicode": "e64f",
"unicode_decimal": 58959
},
{
"icon_id": "35076519",
"name": "redis",
"font_class": "redis",
"unicode": "e650",
"unicode_decimal": 58960
},
{
"icon_id": "35076520",
"name": "size",
"font_class": "size",
"unicode": "e651",
"unicode_decimal": 58961
},
{
"icon_id": "35076521",
"name": "search",
"font_class": "search",
"unicode": "e652",
"unicode_decimal": 58962
},
{
"icon_id": "35076522",
"name": "server",
"font_class": "server",
"unicode": "e653",
"unicode_decimal": 58963
},
{
"icon_id": "35076525",
"name": "select",
"font_class": "select",
"unicode": "e656",
"unicode_decimal": 58966
},
{
"icon_id": "35076526",
"name": "question",
"font_class": "question",
"unicode": "e657",
"unicode_decimal": 58967
},
{
"icon_id": "35076527",
"name": "rate",
"font_class": "rate",
"unicode": "e658",
"unicode_decimal": 58968
},
{
"icon_id": "35076529",
"name": "monitor",
"font_class": "monitor",
"unicode": "e65a",
"unicode_decimal": 58970
},
{
"icon_id": "35076530",
"name": "source",
"font_class": "source",
"unicode": "e65b",
"unicode_decimal": 58971
},
{
"icon_id": "35076532",
"name": "role",
"font_class": "role",
"unicode": "e65d",
"unicode_decimal": 58973
},
{
"icon_id": "35076533",
"name": "shopping",
"font_class": "shopping",
"unicode": "e65e",
"unicode_decimal": 58974
},
{
"icon_id": "35076534",
"name": "skill",
"font_class": "skill",
"unicode": "e65f",
"unicode_decimal": 58975
},
{
"icon_id": "35076535",
"name": "number",
"font_class": "number",
"unicode": "e660",
"unicode_decimal": 58976
},
{
"icon_id": "35076366",
"name": "404",
"font_class": "a-404",
"unicode": "e622",
"unicode_decimal": 58914
},
{
"icon_id": "35076470",
"name": "email",
"font_class": "email",
"unicode": "e623",
"unicode_decimal": 58915
},
{
"icon_id": "35076471",
"name": "example",
"font_class": "example",
"unicode": "e624",
"unicode_decimal": 58916
},
{
"icon_id": "35076472",
"name": "error",
"font_class": "error",
"unicode": "e625",
"unicode_decimal": 58917
},
{
"icon_id": "35076473",
"name": "excel",
"font_class": "excel",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "35076474",
"name": "education",
"font_class": "education",
"unicode": "e627",
"unicode_decimal": 58919
},
{
"icon_id": "35076475",
"name": "eye-open",
"font_class": "eye-open",
"unicode": "e628",
"unicode_decimal": 58920
},
{
"icon_id": "35076476",
"name": "eye",
"font_class": "eye",
"unicode": "e629",
"unicode_decimal": 58921
},
{
"icon_id": "35076480",
"name": "github",
"font_class": "github",
"unicode": "e62b",
"unicode_decimal": 58923
},
{
"icon_id": "35076481",
"name": "guide",
"font_class": "guide",
"unicode": "e62c",
"unicode_decimal": 58924
},
{
"icon_id": "35076482",
"name": "gonggao",
"font_class": "gonggao",
"unicode": "e62d",
"unicode_decimal": 58925
},
{
"icon_id": "35076483",
"name": "icon1",
"font_class": "icon1",
"unicode": "e62e",
"unicode_decimal": 58926
},
{
"icon_id": "35076484",
"name": "fullscreen",
"font_class": "fullscreen",
"unicode": "e62f",
"unicode_decimal": 58927
},
{
"icon_id": "35076485",
"name": "icon",
"font_class": "icon",
"unicode": "e630",
"unicode_decimal": 58928
},
{
"icon_id": "35076486",
"name": "image",
"font_class": "image",
"unicode": "e631",
"unicode_decimal": 58929
},
{
"icon_id": "35076487",
"name": "form",
"font_class": "form",
"unicode": "e632",
"unicode_decimal": 58930
},
{
"icon_id": "35076491",
"name": "job",
"font_class": "job",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "35076284",
"name": "cascader",
"font_class": "cascader",
"unicode": "e603",
"unicode_decimal": 58883
},
{
"icon_id": "35076315",
"name": "alipay",
"font_class": "alipay",
"unicode": "e604",
"unicode_decimal": 58884
},
{
"icon_id": "35076316",
"name": "anq",
"font_class": "anq",
"unicode": "e605",
"unicode_decimal": 58885
},
{
"icon_id": "35076317",
"name": "backup",
"font_class": "backup",
"unicode": "e606",
"unicode_decimal": 58886
},
{
"icon_id": "35076318",
"name": "bug",
"font_class": "bug",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "35076321",
"name": "button",
"font_class": "button",
"unicode": "e609",
"unicode_decimal": 58889
},
{
"icon_id": "35076323",
"name": "chain",
"font_class": "chain",
"unicode": "e60b",
"unicode_decimal": 58891
},
{
"icon_id": "35076324",
"name": "chart",
"font_class": "chart",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "35076325",
"name": "checkbox",
"font_class": "checkbox",
"unicode": "e60d",
"unicode_decimal": 58893
},
{
"icon_id": "35076326",
"name": "clipboard",
"font_class": "clipboard",
"unicode": "e60e",
"unicode_decimal": 58894
},
{
"icon_id": "35076327",
"name": "codeConsole",
"font_class": "codeConsole",
"unicode": "e60f",
"unicode_decimal": 58895
},
{
"icon_id": "35076328",
"name": "code",
"font_class": "code",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "35076329",
"name": "color",
"font_class": "color",
"unicode": "e611",
"unicode_decimal": 58897
},
{
"icon_id": "35076330",
"name": "database",
"font_class": "database",
"unicode": "e612",
"unicode_decimal": 58898
},
{
"icon_id": "35076331",
"name": "component",
"font_class": "component",
"unicode": "e613",
"unicode_decimal": 58899
},
{
"icon_id": "35076332",
"name": "dashboard",
"font_class": "dashboard",
"unicode": "e614",
"unicode_decimal": 58900
},
{
"icon_id": "35076333",
"name": "date",
"font_class": "date",
"unicode": "e615",
"unicode_decimal": 58901
},
{
"icon_id": "35076334",
"name": "deploy",
"font_class": "deploy",
"unicode": "e616",
"unicode_decimal": 58902
},
{
"icon_id": "35076335",
"name": "develop",
"font_class": "develop",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "35076337",
"name": "dept",
"font_class": "dept",
"unicode": "e619",
"unicode_decimal": 58905
},
{
"icon_id": "35076340",
"name": "dictionary",
"font_class": "dictionary",
"unicode": "e61a",
"unicode_decimal": 58906
},
{
"icon_id": "35076341",
"name": "documentation",
"font_class": "documentation",
"unicode": "e61b",
"unicode_decimal": 58907
},
{
"icon_id": "35076342",
"name": "doc",
"font_class": "doc",
"unicode": "e61c",
"unicode_decimal": 58908
},
{
"icon_id": "35076343",
"name": "download",
"font_class": "download",
"unicode": "e61d",
"unicode_decimal": 58909
},
{
"icon_id": "35076344",
"name": "dict",
"font_class": "dict",
"unicode": "e61e",
"unicode_decimal": 58910
},
{
"icon_id": "35076351",
"name": "edit",
"font_class": "edit",
"unicode": "e620",
"unicode_decimal": 58912
},
{
"icon_id": "35075963",
"name": "app",
"font_class": "app",
"unicode": "e602",
"unicode_decimal": 58882
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -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="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>

After

Width:  |  Height:  |  Size: 954 B

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M49.217 41.329l-.136-35.24c-.06-2.715-2.302-4.345-5.022-4.405h-3.65c-2.712-.06-4.866 2.303-4.806 5.016l.152 19.164-24.151-23.79a6.698 6.698 0 0 0-9.499 0 6.76 6.76 0 0 0 0 9.526l23.93 23.713-18.345.074c-2.712-.069-5.228 1.813-5.64 5.02v3.462c.069 2.721 2.31 4.97 5.022 5.03l35.028-.207c.052.005.087.025.133.025l2.457.054a4.626 4.626 0 0 0 3.436-1.38c.88-.874 1.205-2.096 1.169-3.462l-.262-2.465c0-.048.182-.081.182-.136h.002zm52.523 51.212l18.32-.073c2.713.06 5.224-1.609 5.64-4.815v-3.462c-.068-2.722-2.317-4.97-5.021-5.04l-34.58.21c-.053 0-.086-.021-.138-.021l-2.451-.06a4.64 4.64 0 0 0-3.445 1.381c-.885.868-1.201 2.094-1.174 3.46l.27 2.46c.005.06-.177.095-.177.141l.141 34.697c.069 2.713 2.31 4.338 5.022 4.397l3.45.006c2.705.062 4.867-2.31 4.8-5.026l-.153-18.752 24.151 23.946a6.69 6.69 0 0 0 9.494 0 6.747 6.747 0 0 0 0-9.523L101.74 92.54v.001zM48.125 80.662a4.636 4.636 0 0 0-3.437-1.382l-2.457.06c-.05 0-.082.022-.137.022l-35.025-.21c-2.712.07-4.957 2.318-5.022 5.04v3.462c.409 3.206 2.925 4.874 5.633 4.814l18.554.06-24.132 23.928c-2.62 2.626-2.62 6.89 0 9.524a6.694 6.694 0 0 0 9.496 0l24.155-23.79-.155 18.866c-.06 2.722 2.094 5.093 4.801 5.025h3.65c2.72-.069 4.962-1.685 5.022-4.406l.141-34.956c0-.05-.182-.082-.182-.136l.262-2.46c.03-1.366-.286-2.592-1.166-3.46h-.001zM80.08 47.397a4.62 4.62 0 0 0 3.443 1.374l2.45-.054c.055 0 .088-.02.143-.028l35.08.21c2.712-.062 4.953-2.312 5.021-5.033l.009-3.463c-.417-3.211-2.937-5.084-5.64-5.025l-18.615-.073 23.917-23.715c2.63-2.623 2.63-6.879.008-9.513a6.691 6.691 0 0 0-9.494 0L92.251 26.016l.155-19.312c.065-2.713-2.097-5.085-4.802-5.025h-3.45c-2.713.069-4.954 1.693-5.022 4.406l-.139 35.247c0 .054.18.088.18.136l-.267 2.465c-.028 1.366.288 2.588 1.174 3.463v.001z"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -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="1682510872430" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1825" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M512 1024C229.222 1024 0 794.778 0 512S229.222 0 512 0s512 229.222 512 512-229.222 512-512 512z m259.149-568.883h-290.74a25.293 25.293 0 0 0-25.292 25.293l-0.026 63.206c0 13.952 11.315 25.293 25.267 25.293h177.024c13.978 0 25.293 11.315 25.293 25.267v12.646a75.853 75.853 0 0 1-75.853 75.853h-240.23a25.293 25.293 0 0 1-25.267-25.293V417.203a75.853 75.853 0 0 1 75.827-75.853h353.946a25.293 25.293 0 0 0 25.267-25.292l0.077-63.207a25.293 25.293 0 0 0-25.268-25.293H417.152a189.62 189.62 0 0 0-189.62 189.645V771.15c0 13.977 11.316 25.293 25.294 25.293h372.94a170.65 170.65 0 0 0 170.65-170.65V480.384a25.293 25.293 0 0 0-25.293-25.267z" fill="#C71D23" p-id="1826"></path></svg>

After

Width:  |  Height:  |  Size: 1010 B

View File

@ -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="1569580729849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1939" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M513.3 958.5c-142.2 0-397.9-222.1-401.6-440.5V268c1.7-39.6 31.7-72.3 71.1-77.3 49-4.6 97.1-16.5 142.7-35.3 47.8-14 91.9-38.3 129.4-71.1 30.3-24.4 72.9-26.3 105.3-4.6 39.9 30.7 83.8 55.9 130.5 74.6 48.6 14.7 98.2 25.9 148.4 33.7 38.5 7.6 67.1 40.3 69.5 79.5 3.3 84.9 2.5 169.9-2.6 254.7-33.7 281.6-253.7 436.4-392.7 436.3z m-0.1-813.7c-7.2-0.2-14.3 2-20 6.4-39.7 35.2-86.8 61.1-137.7 75.7-46.8 19.2-96.2 31-146.6 35.2-11 3.2-18.8 13-19.5 24.4v230.1c3.5 180.3 223.3 361 323.9 361s287.3-120.2 317.6-360.5c7.3-142.7 0-228.6 0-229.6-1.3-13.3-11-24.3-24-27.3-49.6-7.7-98.6-19-146.5-33.7-46.3-19.5-89.7-45.3-129-76.7-5.8-3.8-12.7-5.5-19.5-4.9l1.3-0.1z" fill="#C6CCDA" p-id="1940"></path><path d="M750.1 428L490.7 673.2c-11.7 11.1-29.5 12.9-43.1 4.2l-6.8-5.8-141.2-149.4c-9.3-9.3-12.7-22.9-9-35.5 3.8-12.6 14.1-22.1 27-24.8 12.9-2.7 26.1 1.9 34.6 11.9L469 597.5l233.7-221c14.6-12.8 36.8-11.6 49.9 2.7 13.2 14.2 11.5 35.3-2.5 48.8" fill="#C6CCDA" p-id="1941"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
<g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
<g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
<rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
<g id="Group-8" transform="translate(1167.000000, 0.000000)">
<g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
src/assets/logo/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
src/assets/logo/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,99 @@
@import './variables.module.scss';
@mixin colorBtn($color) {
background: $color;
&:hover {
color: $color;
&:before,
&:after {
background: $color;
}
}
}
.blue-btn {
@include colorBtn($blue)
}
.light-blue-btn {
@include colorBtn($light-blue)
}
.red-btn {
@include colorBtn($red)
}
.pink-btn {
@include colorBtn($pink)
}
.green-btn {
@include colorBtn($green)
}
.tiffany-btn {
@include colorBtn($tiffany)
}
.yellow-btn {
@include colorBtn($yellow)
}
.pan-btn {
font-size: 14px;
color: #fff;
padding: 14px 36px;
border-radius: 8px;
border: none;
outline: none;
transition: 600ms ease all;
position: relative;
display: inline-block;
&:hover {
background: #fff;
&:before,
&:after {
width: 100%;
transition: 600ms ease all;
}
}
&:before,
&:after {
content: '';
position: absolute;
top: 0;
right: 0;
height: 2px;
width: 0;
transition: 400ms ease all;
}
&::after {
right: inherit;
top: inherit;
left: 0;
bottom: 0;
}
}
.custom-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
color: #fff;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: 0;
margin: 0;
padding: 10px 15px;
font-size: 14px;
border-radius: 4px;
}

View File

@ -0,0 +1,130 @@
// cover some element-ui styles
.el-upload__input {
display: none;
}
.cell {
.el-tag {
margin-right: 0px;
}
}
// table 里面操作按钮样式覆盖
.el-table__cell .cell {
.el-button.is-text {
padding: 8px 5px;
}
}
.status-col {
.cell {
padding: 0 10px;
text-align: center;
.el-tag {
margin-right: 0px;
}
}
}
// fix 2.2.0 版本label标签不居中
// .el-form-item--small .el-form-item__label {
// line-height: 32px !important;
// }
// element ui 移动端组件适配
.el-icon {
vertical-align: middle;
}
.el-header {
--el-header-padding: 0 0px !important;
// --el-header-height: 50px !important;
}
// el 2.2.0 text button
.el-button.is-text {
color: var(--el-color-primary) !important;
}
@media screen and (max-width: 500px) {
.el-message {
min-width: 300px !important;
}
}
@media screen and (max-width: 500px) {
.el-message-box {
width: 300px !important;
}
.el-pagination__jump {
display: none !important;
}
.el-pagination__sizes {
display: none !important;
}
}
// dialog
@media screen and (max-width: 700px) {
.el-dialog {
--el-dialog-width: 100% !important;
// --el-dialog-margin-top: 0 !important;
}
// .el-dialog:not(.is-fullscreen) {
// margin-top: 0 !important;
// }
.el-drawer {
width: 85% !important;
}
}
/** 表格更多操作下拉样式 */
.el-table .el-dropdown-link {
cursor: pointer;
color: #409eff;
margin-left: 5px;
}
.el-table .el-dropdown,
.el-icon-arrow-down {
font-size: 12px;
}
//适配完毕
// 隐藏picture-card 上传按钮
.hide .el-upload--picture-card {
display: none;
}
// 禁止菜单选中
.el-sub-menu .el-sub-menu__title span,
.el-menu .el-menu-item {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
// fix 侧边栏二级导航缩小图标消失问题
.el-sub-menu__title {
padding-right: unset !important;
}
// fix 顶部导航更多样式问题
.el-menu--horizontal .el-sub-menu .el-sub-menu__icon-arrow {
right: calc(0px - var(--el-menu-base-level-padding)) !important;
}
// 弹出搜索框
.header-search-select {
.el-select-dropdown__item {
height: unset !important;
line-height: unset !important;
margin-bottom: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
}

View File

@ -0,0 +1,276 @@
@import './variables.module.scss';
@import './mixin.scss';
@import './transition.scss';
@import './element-ui.scss';
@import './sidebar.scss';
@import './btn.scss';
@import './waves.scss';
html,
body,
#app {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
background-color: var(--base-bg-main);
// overflow: hidden;
position: relative;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
.no-padding {
padding: 0 !important;
}
.padding-content {
padding: 4px 0;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
.fr {
float: right;
}
.fl {
float: left;
}
.pr-5 {
padding-right: 5px;
}
.pl-5 {
padding-left: 5px;
}
.block {
display: block;
}
.pointer {
cursor: pointer;
}
.inlineBlock {
display: block;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: ' ';
clear: both;
height: 0;
}
}
.text-center {
text-align: center;
}
.link-type,
.link-type:focus {
color: var(--el-color-primary);
cursor: pointer;
&:hover {
// color: rgb(32, 160, 255);
opacity: 0.3;
}
}
/** 基础通用 **/
.pt5 {
padding-top: 5px;
}
.pr5 {
padding-right: 5px;
}
.pb5 {
padding-bottom: 5px;
}
.pb20 {
padding-bottom: 20px;
}
.mt5 {
margin-top: 5px;
}
.mr5 {
margin-right: 5px;
}
.mb5 {
margin-bottom: 5px;
}
.mb8 {
margin-bottom: 8px;
}
.ml5 {
margin-left: 5px;
}
.mt10 {
margin-top: 10px;
}
.mr10 {
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px;
}
.ml10 {
margin-left: 10px;
}
.mt20 {
margin-top: 20px;
}
.mr20 {
margin-right: 20px;
}
.mb20 {
margin-bottom: 20px;
}
.ml20 {
margin-left: 20px;
}
.ml {
margin-left: auto;
}
.mr {
margin-right: auto;
}
.mt {
margin-top: auto;
}
.mb {
margin-bottom: auto;
}
.w20 {
width: 20%;
}
.w100 {
width: 100%;
}
.pull-right {
float: right !important;
}
/* text color */
.text-navy {
color: #1ab394;
}
.text-pink {
color: pink;
}
.text-primary {
color: inherit;
}
.text-success {
color: #1c84c6;
}
.text-info {
color: #23c6c8;
}
.text-warning {
color: #f8ac59;
}
.text-danger {
color: #ff0000;
}
.text-muted {
color: #888888;
}
.text-orange {
color: #ff7d00;
}
.text-hotpink {
color: hotpink;
}
.text-green {
color: green;
}
.text-greenyellow {
color: greenyellow;
}
.text-purple {
color: #ff00ff;
}
/* image */
.img-circle {
border-radius: 50%;
}
.card-box {
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px;
}
.icon {
width: 100px;
}
.table-td-thumb {
width: 56px;
}
.flex-center {
flex-direction: column;
overflow: hidden;
}

View File

@ -0,0 +1,73 @@
.login {
background: radial-gradient(220% 105% at top center, #1b2947 10%, #4b76a7 40%, #81acae 65%, #f7f7b6);
background-attachment: fixed;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
// background-image: url('@/assets/images/login-bg.jpg');
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
// color: #fff;
}
.login-form {
border-radius: 6px;
background: #ffffff;
// background-color: hsla(0, 0%, 100%, 0.3);
width: var(--base-login-width);
padding: 25px 15px 5px 15px;
position: relative;
.input-icon {
height: 39px;
width: 14px;
margin-left: 0px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 40px;
float: right;
img {
width: 100%;
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 40px;
padding-left: 12px;
}
.langSet {
position: absolute;
right: 20px;
top: 10px;
}

View File

@ -0,0 +1,66 @@
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
@mixin scrollBar {
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}
@mixin pct($pct) {
width: #{$pct};
position: relative;
margin: 0 auto;
}
@mixin triangle($width, $height, $color, $direction) {
$width: $width/2;
$color-border-style: $height solid $color;
$transparent-border-style: $width solid transparent;
height: 0;
width: 0;
@if $direction==up {
border-bottom: $color-border-style;
border-left: $transparent-border-style;
border-right: $transparent-border-style;
}
@else if $direction==right {
border-left: $color-border-style;
border-top: $transparent-border-style;
border-bottom: $transparent-border-style;
}
@else if $direction==down {
border-top: $color-border-style;
border-left: $transparent-border-style;
border-right: $transparent-border-style;
}
@else if $direction==left {
border-right: $color-border-style;
border-top: $transparent-border-style;
border-bottom: $transparent-border-style;
}
}

View File

@ -0,0 +1,106 @@
#app {
.sidebar {
position: relative;
overflow-y: hidden;
z-index: 1001;
transition: width 0.28s ease;
background-color: var(--base-menu-background);
height: 100%;
display: flex;
flex-direction: column;
-webkit-box-shadow: 2px 0 14px rgb(0 21 41 / 10%);
box-shadow: 2px 0 14px rgb(0 21 41 / 10%);
.el-scrollbar__bar.is-vertical {
right: 0px;
}
// 去掉el-menu边框
.el-menu {
border: none;
}
[class^='el-icon'] {
width: 1em;
height: 1em;
font-size: unset;
}
}
// 展开sidebar状态设置svg-icon边距
.openSidebar {
.sidebar {
transform: translate(0);
}
.sidebar .svg-icon {
margin-right: 5px;
}
}
// 隐藏侧边栏样式
.hideSidebar {
.el-aside {
--el-aside-width: 60px;
}
// 隐藏箭头
.el-sub-menu {
overflow: hidden;
& > .el-sub-menu__title {
.el-sub-menu__icon-arrow {
display: none;
}
}
}
// 折叠状态下
.el-menu--collapse {
[class^='el-icon'] {
width: auto;
font-size: medium;
margin-right: 0;
}
.el-sub-menu {
& > .el-sub-menu__title {
& > span {
height: 3000px;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
}
}
}
}
// mobile responsive
.mobile {
.main-container {
margin-left: 0px;
}
.sidebar {
transition: transform 0.28s;
position: fixed;
// background: var(--base-menu-background, #fff);
}
&.hideSidebar {
.sidebar {
display: none;
}
}
}
}
// when menu collapsed
.el-menu--vertical {
// the scroll bar appears when the subMenu is too long
> .el-menu--popup {
max-height: 100vh;
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
}
}

View File

@ -0,0 +1,48 @@
// global transition css
/* fade */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.28s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all .5s;
}
.fade-transform-enter {
opacity: 0;
transform: translateX(-30px);
}
.fade-transform-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* breadcrumb transition */
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all .5s;
}
.breadcrumb-enter,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-move {
transition: all .5s;
}
.breadcrumb-leave-active {
position: absolute;
}

View File

@ -0,0 +1,45 @@
// base color
$blue: #324157;
$light-blue: #3a71a8;
$red: #c03639;
$pink: #e65d6e;
$green: #30b08f;
$tiffany: #4ab7bd;
$yellow: #fec171;
$panGreen: #30b08f;
// 默认菜单主题风格
:root {
--base-text-color-rgba: rgba(0, 0, 0, 0.85);
--base-sidebar-width: 220px;
// 左侧菜单宽度
--el-aside-width: 220px;
//底部高度
--base-footer-height: 30px;
--base-tags-height: 34px;
--base-header-height: 50px;
//登录框宽度
--base-login-width: 280px;
}
/***侧边栏深色配置***/
[data-theme='theme-dark'] {
--base-menu-background: #324157;
--base-logo-title-color: #ffffff;
// // el-ement ui 设置
// --el-fill-color-blank: #304156;
--el-text-color-primary: #e5eaf3;
--el-menu-text-color: var(--el-text-color-primary);
}
html.dark {
/* custom dark bg color */
// --el-bg-color: #141414;
--base-color-white: #ffffff;
--base-text-color-rgba: #ffffff;
}
html.cafe {
filter: sepia(0.9) hue-rotate(315deg) brightness(0.9);
}
html.contrast {
filter: contrast(2);
}

View File

@ -0,0 +1,101 @@
/* Waves v0.6.0
* http://fian.my.id/Waves
*
* Copyright 2014 Alfiana E. Sibuea and other contributors
* Released under the MIT license
* https://github.com/fians/Waves/blob/master/LICENSE
*/
.waves-effect {
position: relative;
cursor: pointer;
display: inline-block;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
vertical-align: middle;
z-index: 1;
will-change: opacity, transform;
transition: all 0.3s ease-out;
}
.waves-effect .waves-ripple {
position: absolute;
border-radius: 50%;
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: -10px;
opacity: 0;
background: rgba(0, 0, 0, 0.2);
transition: all 0.7s ease-out;
transition-property: opacity, -webkit-transform;
transition-property: transform, opacity;
transition-property: transform, opacity, -webkit-transform;
-webkit-transform: scale(0);
transform: scale(0);
pointer-events: none;
}
.waves-effect.waves-light .waves-ripple {
background-color: rgba(255, 255, 255, 0.45);
}
.waves-effect.waves-red .waves-ripple {
background-color: rgba(244, 67, 54, 0.7);
}
.waves-effect.waves-yellow .waves-ripple {
background-color: rgba(255, 235, 59, 0.7);
}
.waves-effect.waves-orange .waves-ripple {
background-color: rgba(255, 152, 0, 0.7);
}
.waves-effect.waves-purple .waves-ripple {
background-color: rgba(156, 39, 176, 0.7);
}
.waves-effect.waves-green .waves-ripple {
background-color: rgba(76, 175, 80, 0.7);
}
.waves-effect.waves-teal .waves-ripple {
background-color: rgba(0, 150, 136, 0.7);
}
.waves-effect input[type='button'],
.waves-effect input[type='reset'],
.waves-effect input[type='submit'] {
border: 0;
font-style: normal;
font-size: inherit;
text-transform: inherit;
background: none;
}
.waves-notransition {
transition: none !important;
}
.waves-circle {
-webkit-transform: translateZ(0);
transform: translateZ(0);
-webkit-mask-image: -webkit-radial-gradient(circle, #fff 100%, #000 100%);
}
.waves-input-wrapper {
border-radius: 0.2em;
vertical-align: bottom;
}
.waves-input-wrapper .waves-button-input {
position: relative;
top: 0;
left: 0;
z-index: 1;
}
.waves-circle {
text-align: center;
width: 2.5em;
height: 2.5em;
line-height: 2.5em;
border-radius: 50%;
-webkit-mask-image: none;
}
.waves-block {
display: block;
}
a.waves-effect .waves-ripple {
z-index: -1;
}

64
src/auto-import.d.ts vendored Normal file
View File

@ -0,0 +1,64 @@
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
declare global {
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createPinia: typeof import('pinia')['createPinia']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
}
export {}

View File

@ -0,0 +1,72 @@
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<!-- <transition-group name="breadcrumb"> -->
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
<span v-else @click.prevent="handleLink(item)" style="cursor: pointer">
{{ item.meta.title }}
</span>
</el-breadcrumb-item>
<!-- </transition-group> -->
</el-breadcrumb>
</template>
<script setup>
const route = useRoute()
const router = useRouter()
const levelList = ref([])
function getBreadcrumb() {
// only show routes with meta.title
let matched = route.matched.filter((item) => item.meta && item.meta.title)
const first = matched[0]
//
if (!isDashboard(first)) {
matched = [{ path: '/index', meta: { title: '首页' } }].concat(matched)
}
levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}
function isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim() === 'Index'
}
function handleLink(item) {
const { redirect, path } = item
if (redirect) {
router.push(redirect)
return
}
router.push(path)
}
watchEffect(() => {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
getBreadcrumb()
})
getBreadcrumb()
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
.mobile .app-breadcrumb.el-breadcrumb {
display: none;
}
</style>

View File

@ -0,0 +1,172 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model="radioValue" :label="1"> 允许的通配符[, - * ? / L W] </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2"> 不指定 </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
周期从
<el-input-number v-model="cycle01" :min="1" :max="30" /> - <el-input-number v-model="cycle02" :min="cycle01 + 1" :max="31" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="4">
<el-input-number v-model="average01" :min="1" :max="30" /> 号开始
<el-input-number v-model="average02" :min="1" :max="31 - average01" /> 日执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="5">
每月
<el-input-number v-model="workday" :min="1" :max="31" /> 号最近的那个工作日
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="6"> 本月最后一天 </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="7">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 31" :key="item" :label="item" :value="item" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const radioValue = ref(1)
const cycle01 = ref(1)
const cycle02 = ref(2)
const average01 = ref(1)
const average02 = ref(1)
const workday = ref(1)
const checkboxList = ref([])
const checkCopy = ref([1])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, 1, 30)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, 31)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, 1, 30)
average02.value = props.check(average02.value, 1, 31 - average01.value)
return average01.value + '/' + average02.value
})
const workdayTotal = computed(() => {
workday.value = props.check(workday.value, 1, 31)
return workday.value + 'W'
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.day,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, workdayTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '*') {
radioValue.value = 1
} else if (value === '?') {
radioValue.value = 2
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 3
} else if (value.indexOf('/') > -1) {
const indexArr = value.split('/')
average01.value = Number(indexArr[0])
average02.value = Number(indexArr[1])
radioValue.value = 4
} else if (value.indexOf('W') > -1) {
const indexArr = value.split('W')
workday.value = Number(indexArr[0])
radioValue.value = 5
} else if (value === 'L') {
radioValue.value = 6
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 7
}
}
//
function onRadioChange() {
if (radioValue.value === 2 && props.cron.week === '?') {
emit('update', 'week', '*', 'day')
}
if (radioValue.value !== 2 && props.cron.week !== '?') {
emit('update', 'week', '?', 'day')
}
switch (radioValue.value) {
case 1:
emit('update', 'day', '*', 'day')
break
case 2:
emit('update', 'day', '?', 'day')
break
case 3:
emit('update', 'day', cycleTotal.value, 'day')
break
case 4:
emit('update', 'day', averageTotal.value, 'day')
break
case 5:
emit('update', 'day', workdayTotal.value, 'day')
break
case 6:
emit('update', 'day', 'L', 'day')
break
case 7:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'day', checkboxString.value, 'day')
break
}
}
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.2rem;
}
.el-select,
.el-select--small {
width: 18.8rem;
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model="radioValue" :label="1"> 小时允许的通配符[, - * /] </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2">
周期从
<el-input-number v-model="cycle01" :min="0" :max="22" /> - <el-input-number v-model="cycle02" :min="cycle01 + 1" :max="23" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
<el-input-number v-model="average01" :min="0" :max="22" /> 时开始
<el-input-number v-model="average02" :min="1" :max="23 - average01" /> 小时执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 24" :key="item" :label="item - 1" :value="item - 1" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const radioValue = ref(1)
const cycle01 = ref(0)
const cycle02 = ref(1)
const average01 = ref(0)
const average02 = ref(1)
const checkboxList = ref([])
const checkCopy = ref([0])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, 0, 22)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, 23)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, 0, 22)
average02.value = props.check(average02.value, 1, 23 - average01.value)
return average01.value + '/' + average02.value
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.hour,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '*') {
radioValue.value = 1
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 2
} else if (value.indexOf('/') > -1) {
const indexArr = value.split('/')
average01.value = Number(indexArr[0])
average02.value = Number(indexArr[1])
radioValue.value = 3
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 4
}
}
function onRadioChange() {
switch (radioValue.value) {
case 1:
emit('update', 'hour', '*', 'hour')
break
case 2:
emit('update', 'hour', cycleTotal.value, 'hour')
break
case 3:
emit('update', 'hour', averageTotal.value, 'hour')
break
case 4:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'hour', checkboxString.value, 'hour')
break
}
}
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.2rem;
}
.el-select,
.el-select--small {
width: 18.8rem;
}
</style>

View File

@ -0,0 +1,280 @@
<template>
<div>
<el-tabs type="border-card">
<el-tab-pane label="秒" v-if="shouldHide('second')">
<CrontabSecond @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronsecond" />
</el-tab-pane>
<el-tab-pane label="分钟" v-if="shouldHide('min')">
<CrontabMin @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronmin" />
</el-tab-pane>
<el-tab-pane label="小时" v-if="shouldHide('hour')">
<CrontabHour @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronhour" />
</el-tab-pane>
<el-tab-pane label="日" v-if="shouldHide('day')">
<CrontabDay @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronday" />
</el-tab-pane>
<el-tab-pane label="月" v-if="shouldHide('month')">
<CrontabMonth @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronmonth" />
</el-tab-pane>
<el-tab-pane label="周" v-if="shouldHide('week')">
<CrontabWeek @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronweek" />
</el-tab-pane>
<el-tab-pane label="年" v-if="shouldHide('year')">
<CrontabYear @update="updateCrontabValue" :check="checkNumber" :cron="crontabValueObj" ref="cronyear" />
</el-tab-pane>
</el-tabs>
<div class="popup-main">
<div class="popup-result">
<p class="title">时间表达式</p>
<table>
<thead>
<th v-for="item of tabTitles" :key="item">{{ item }}</th>
<th>Cron 表达式</th>
</thead>
<tbody>
<td>
<span v-if="crontabValueObj.second.length < 10">{{ crontabValueObj.second }}</span>
<el-tooltip v-else :content="crontabValueObj.second" placement="top"
><span>{{ crontabValueObj.second }}</span></el-tooltip
>
</td>
<td>
<span v-if="crontabValueObj.min.length < 10">{{ crontabValueObj.min }}</span>
<el-tooltip v-else :content="crontabValueObj.min" placement="top"
><span>{{ crontabValueObj.min }}</span></el-tooltip
>
</td>
<td>
<span v-if="crontabValueObj.hour.length < 10">{{ crontabValueObj.hour }}</span>
<el-tooltip v-else :content="crontabValueObj.hour" placement="top"
><span>{{ crontabValueObj.hour }}</span></el-tooltip
>
</td>
<td>
<span v-if="crontabValueObj.day.length < 10">{{ crontabValueObj.day }}</span>
<el-tooltip v-else :content="crontabValueObj.day" placement="top"
><span>{{ crontabValueObj.day }}</span></el-tooltip
>
</td>
<td>
<span v-if="crontabValueObj.month.length < 10">{{ crontabValueObj.month }}</span>
<el-tooltip v-else :content="crontabValueObj.month" placement="top"
><span>{{ crontabValueObj.month }}</span></el-tooltip
>
</td>
<td>
<span v-if="crontabValueObj.week.length < 10">{{ crontabValueObj.week }}</span>
<el-tooltip v-else :content="crontabValueObj.week" placement="top"
><span>{{ crontabValueObj.week }}</span></el-tooltip
>
</td>
<td>
<span v-if="crontabValueObj.year.length < 10">{{ crontabValueObj.year }}</span>
<el-tooltip v-else :content="crontabValueObj.year" placement="top"
><span>{{ crontabValueObj.year }}</span></el-tooltip
>
</td>
<td class="result">
<span v-if="crontabValueString.length < 90">{{ crontabValueString }}</span>
<el-tooltip v-else :content="crontabValueString" placement="top"
><span>{{ crontabValueString }}</span></el-tooltip
>
</td>
</tbody>
</table>
</div>
<CrontabResult :ex="crontabValueString"></CrontabResult>
<div class="pop_btn">
<el-button type="primary" @click="submitFill">确定</el-button>
<el-button type="warning" @click="clearCron">重置</el-button>
<el-button @click="hidePopup">取消</el-button>
</div>
</div>
</div>
</template>
<script setup>
import CrontabSecond from './second.vue'
import CrontabMin from './min.vue'
import CrontabHour from './hour.vue'
import CrontabDay from './day.vue'
import CrontabMonth from './month.vue'
import CrontabWeek from './week.vue'
import CrontabYear from './year.vue'
import CrontabResult from './result.vue'
const { proxy } = getCurrentInstance()
const emit = defineEmits(['hide', 'fill'])
const props = defineProps({
hideComponent: {
type: Array,
default: () => []
},
expression: {
type: String,
default: ''
}
})
const tabTitles = ref(['秒', '分钟', '小时', '日', '月', '周', '年'])
const tabActive = ref(0)
const hideComponent = ref([])
const expression = ref('')
const crontabValueObj = ref({
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
})
const crontabValueString = computed(() => {
const obj = crontabValueObj.value
return obj.second + ' ' + obj.min + ' ' + obj.hour + ' ' + obj.day + ' ' + obj.month + ' ' + obj.week + (obj.year === '' ? '' : ' ' + obj.year)
})
watch(expression, () => resolveExp())
function shouldHide(key) {
return !(hideComponent.value && hideComponent.value.includes(key))
}
function resolveExp() {
//
if (expression.value) {
const arr = expression.value.split(/\s+/)
if (arr.length >= 6) {
//6
let obj = {
second: arr[0],
min: arr[1],
hour: arr[2],
day: arr[3],
month: arr[4],
week: arr[5],
year: arr[6] ? arr[6] : ''
}
crontabValueObj.value = {
...obj
}
}
} else {
//
clearCron()
}
}
// tab
function tabCheck(index) {
tabActive.value = index
}
//
function updateCrontabValue(name, value, from) {
crontabValueObj.value[name] = value
}
// -props
function checkNumber(value, minLimit, maxLimit) {
//
value = Math.floor(value)
if (value < minLimit) {
value = minLimit
} else if (value > maxLimit) {
value = maxLimit
}
return value
}
//
function hidePopup() {
emit('hide')
}
//
function submitFill() {
emit('fill', crontabValueString.value)
hidePopup()
}
function clearCron() {
//
crontabValueObj.value = {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
}
onMounted(() => {
expression.value = props.expression
hideComponent.value = props.hideComponent
})
</script>
<style lang="scss" scoped>
.pop_btn {
text-align: center;
margin-top: 20px;
}
.popup-main {
position: relative;
margin: 10px auto;
background: #fff;
border-radius: 5px;
font-size: 12px;
overflow: hidden;
}
.popup-title {
overflow: hidden;
line-height: 34px;
padding-top: 6px;
background: #f2f2f2;
}
.popup-result {
box-sizing: border-box;
line-height: 24px;
margin: 25px auto;
padding: 15px 10px 10px;
border: 1px solid #ccc;
position: relative;
}
.popup-result .title {
position: absolute;
top: -28px;
left: 50%;
width: 140px;
font-size: 14px;
margin-left: -70px;
text-align: center;
line-height: 30px;
background: #fff;
}
.popup-result table {
text-align: center;
width: 100%;
margin: 0 auto;
}
.popup-result table td:not(.result) {
width: 3.5rem;
min-width: 3.5rem;
max-width: 3.5rem;
}
.popup-result table span {
display: block;
width: 100%;
font-family: arial;
line-height: 30px;
height: 30px;
white-space: nowrap;
overflow: hidden;
border: 1px solid #e8e8e8;
}
.popup-result-scroll {
font-size: 12px;
line-height: 24px;
height: 10em;
overflow-y: auto;
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model="radioValue" :label="1"> 分钟允许的通配符[, - * /] </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2">
周期从
<el-input-number v-model="cycle01" :min="0" :max="58" /> - <el-input-number v-model="cycle02" :min="cycle01 + 1" :max="59" /> 分钟
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
<el-input-number v-model="average01" :min="0" :max="58" /> 分钟开始
<el-input-number v-model="average02" :min="1" :max="59 - average01" /> 分钟执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 60" :key="item" :label="item - 1" :value="item - 1" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const radioValue = ref(1)
const cycle01 = ref(0)
const cycle02 = ref(1)
const average01 = ref(0)
const average02 = ref(1)
const checkboxList = ref([])
const checkCopy = ref([0])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, 0, 58)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, 59)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, 0, 58)
average02.value = props.check(average02.value, 1, 59 - average01.value)
return average01.value + '/' + average02.value
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.min,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '*') {
radioValue.value = 1
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 2
} else if (value.indexOf('/') > -1) {
const indexArr = value.split('/')
average01.value = Number(indexArr[0])
average02.value = Number(indexArr[1])
radioValue.value = 3
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 4
}
}
function onRadioChange() {
switch (radioValue.value) {
case 1:
emit('update', 'min', '*', 'min')
break
case 2:
emit('update', 'min', cycleTotal.value, 'min')
break
case 3:
emit('update', 'min', averageTotal.value, 'min')
break
case 4:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'min', checkboxString.value, 'min')
break
}
}
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.2rem;
}
.el-select,
.el-select--small {
width: 19.8rem;
}
</style>

View File

@ -0,0 +1,143 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model="radioValue" :label="1"> 允许的通配符[, - * /] </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2">
周期从
<el-input-number v-model="cycle01" :min="1" :max="11" /> - <el-input-number v-model="cycle02" :min="cycle01 + 1" :max="12" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
<el-input-number v-model="average01" :min="1" :max="11" /> 月开始
<el-input-number v-model="average02" :min="1" :max="12 - average01" /> 月月执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="8">
<el-option v-for="item in monthList" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const radioValue = ref(1)
const cycle01 = ref(1)
const cycle02 = ref(2)
const average01 = ref(1)
const average02 = ref(1)
const checkboxList = ref([])
const checkCopy = ref([1])
const monthList = ref([
{ key: 1, value: '一月' },
{ key: 2, value: '二月' },
{ key: 3, value: '三月' },
{ key: 4, value: '四月' },
{ key: 5, value: '五月' },
{ key: 6, value: '六月' },
{ key: 7, value: '七月' },
{ key: 8, value: '八月' },
{ key: 9, value: '九月' },
{ key: 10, value: '十月' },
{ key: 11, value: '十一月' },
{ key: 12, value: '十二月' }
])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, 1, 11)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, 12)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, 1, 11)
average02.value = props.check(average02.value, 1, 12 - average01.value)
return average01.value + '/' + average02.value
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.month,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '*') {
radioValue.value = 1
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 2
} else if (value.indexOf('/') > -1) {
const indexArr = value.split('/')
average01.value = Number(indexArr[0])
average02.value = Number(indexArr[1])
radioValue.value = 3
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 4
}
}
function onRadioChange() {
switch (radioValue.value) {
case 1:
emit('update', 'month', '*', 'month')
break
case 2:
emit('update', 'month', cycleTotal.value, 'month')
break
case 3:
emit('update', 'month', averageTotal.value, 'month')
break
case 4:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'month', checkboxString.value, 'month')
break
}
}
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.2rem;
}
.el-select,
.el-select--small {
width: 18.8rem;
}
</style>

View File

@ -0,0 +1,560 @@
<template>
<div class="popup-result">
<p class="title">最近5次运行时间</p>
<ul class="popup-result-scroll">
<template v-if="isShow">
<li v-for="item in resultList" :key="item">{{ item }}</li>
</template>
<li v-else>计算结果中...</li>
</ul>
</div>
</template>
<script setup>
const props = defineProps({
ex: {
type: String,
default: ''
}
})
const dayRule = ref('')
const dayRuleSup = ref('')
const dateArr = ref([])
const resultList = ref([])
const isShow = ref(false)
watch(
() => props.ex,
() => expressionChange()
)
//
function expressionChange() {
// -
isShow.value = false
// [0123456]
let ruleArr = props.ex.split(' ')
//
let nums = 0
//
let resultArr = []
// []
let nTime = new Date()
let nYear = nTime.getFullYear()
let nMonth = nTime.getMonth() + 1
let nDay = nTime.getDate()
let nHour = nTime.getHours()
let nMin = nTime.getMinutes()
let nSecond = nTime.getSeconds()
// 100
getSecondArr(ruleArr[0])
getMinArr(ruleArr[1])
getHourArr(ruleArr[2])
getDayArr(ruleArr[3])
getMonthArr(ruleArr[4])
getWeekArr(ruleArr[5])
getYearArr(ruleArr[6], nYear)
// -便使
let sDate = dateArr.value[0]
let mDate = dateArr.value[1]
let hDate = dateArr.value[2]
let DDate = dateArr.value[3]
let MDate = dateArr.value[4]
let YDate = dateArr.value[5]
//
let sIdx = getIndex(sDate, nSecond)
let mIdx = getIndex(mDate, nMin)
let hIdx = getIndex(hDate, nHour)
let DIdx = getIndex(DDate, nDay)
let MIdx = getIndex(MDate, nMonth)
let YIdx = getIndex(YDate, nYear)
// ()
const resetSecond = function () {
sIdx = 0
nSecond = sDate[sIdx]
}
const resetMin = function () {
mIdx = 0
nMin = mDate[mIdx]
resetSecond()
}
const resetHour = function () {
hIdx = 0
nHour = hDate[hIdx]
resetMin()
}
const resetDay = function () {
DIdx = 0
nDay = DDate[DIdx]
resetHour()
}
const resetMonth = function () {
MIdx = 0
nMonth = MDate[MIdx]
resetDay()
}
//
if (nYear !== YDate[YIdx]) {
resetMonth()
}
//
if (nMonth !== MDate[MIdx]) {
resetDay()
}
//
if (nDay !== DDate[DIdx]) {
resetHour()
}
//
if (nHour !== hDate[hIdx]) {
resetMin()
}
//
if (nMin !== mDate[mIdx]) {
resetSecond()
}
//
goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
let YY = YDate[Yi]
//
if (nMonth > MDate[MDate.length - 1]) {
resetMonth()
continue
}
//
goMonth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
// 便
let MM = MDate[Mi]
MM = MM < 10 ? '0' + MM : MM
//
if (nDay > DDate[DDate.length - 1]) {
resetDay()
if (Mi === MDate.length - 1) {
resetMonth()
continue goYear
}
continue
}
//
goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
// 便
let DD = DDate[Di]
let thisDD = DD < 10 ? '0' + DD : DD
//
if (nHour > hDate[hDate.length - 1]) {
resetHour()
if (Di === DDate.length - 1) {
resetDay()
if (Mi === MDate.length - 1) {
resetMonth()
continue goYear
}
continue goMonth
}
continue
}
//
if (
checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true &&
dayRule.value !== 'workDay' &&
dayRule.value !== 'lastWeek' &&
dayRule.value !== 'lastDay'
) {
resetDay()
continue goMonth
}
//
if (dayRule.value === 'lastDay') {
//
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--
thisDD = DD < 10 ? '0' + DD : DD
}
}
} else if (dayRule.value === 'workDay') {
// 230
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--
thisDD = DD < 10 ? '0' + DD : DD
}
}
// X
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
//
if (thisWeek === 1) {
//
DD++
thisDD = DD < 10 ? '0' + DD : DD
//
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD -= 3
}
} else if (thisWeek === 7) {
// 61
if (dayRuleSup.value !== 1) {
DD--
} else {
DD += 2
}
}
} else if (dayRule.value === 'weekDay') {
//
//
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
// dayRuleSup
if (dayRuleSup.value.indexOf(thisWeek) < 0) {
//
if (Di === DDate.length - 1) {
resetDay()
if (Mi === MDate.length - 1) {
resetMonth()
continue goYear
}
continue goMonth
}
continue
}
} else if (dayRule.value === 'assWeek') {
//
// 1
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
if (dayRuleSup.value[1] >= thisWeek) {
DD = (dayRuleSup.value[0] - 1) * 7 + dayRuleSup.value[1] - thisWeek + 1
} else {
DD = dayRuleSup.value[0] * 7 + dayRuleSup.value[1] - thisWeek + 1
}
} else if (dayRule.value === 'lastWeek') {
//
// 230
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--
thisDD = DD < 10 ? '0' + DD : DD
}
}
//
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
//
if (dayRuleSup.value < thisWeek) {
DD -= thisWeek - dayRuleSup.value
} else if (dayRuleSup.value > thisWeek) {
DD -= 7 - (dayRuleSup.value - thisWeek)
}
}
// 1005
DD = DD < 10 ? '0' + DD : DD
//
goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
let hh = hDate[hi] < 10 ? '0' + hDate[hi] : hDate[hi]
//
if (nMin > mDate[mDate.length - 1]) {
resetMin()
if (hi === hDate.length - 1) {
resetHour()
if (Di === DDate.length - 1) {
resetDay()
if (Mi === MDate.length - 1) {
resetMonth()
continue goYear
}
continue goMonth
}
continue goDay
}
continue
}
// ""
goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi]
//
if (nSecond > sDate[sDate.length - 1]) {
resetSecond()
if (mi === mDate.length - 1) {
resetMin()
if (hi === hDate.length - 1) {
resetHour()
if (Di === DDate.length - 1) {
resetDay()
if (Mi === MDate.length - 1) {
resetMonth()
continue goYear
}
continue goMonth
}
continue goDay
}
continue goHour
}
continue
}
// ""
goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si]
//
if (MM !== '00' && DD !== '00') {
resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
nums++
}
// 退
if (nums === 5) break goYear
//
if (si === sDate.length - 1) {
resetSecond()
if (mi === mDate.length - 1) {
resetMin()
if (hi === hDate.length - 1) {
resetHour()
if (Di === DDate.length - 1) {
resetDay()
if (Mi === MDate.length - 1) {
resetMonth()
continue goYear
}
continue goMonth
}
continue goDay
}
continue goHour
}
continue goMin
}
} //goSecond
} //goMin
} //goHour
} //goDay
} //goMonth
}
// 100
if (resultArr.length === 0) {
resultList.value = ['没有达到条件的结果!']
} else {
resultList.value = resultArr
if (resultArr.length !== 5) {
resultList.value.push('最近100年内只有上面' + resultArr.length + '条结果!')
}
}
// -
isShow.value = true
}
//
function getIndex(arr, value) {
if (value <= arr[0] || value > arr[arr.length - 1]) {
return 0
} else {
for (let i = 0; i < arr.length - 1; i++) {
if (value > arr[i] && value <= arr[i + 1]) {
return i + 1
}
}
}
}
// ""
function getYearArr(rule, year) {
dateArr.value[5] = getOrderArr(year, year + 100)
if (rule !== undefined) {
if (rule.indexOf('-') >= 0) {
dateArr.value[5] = getCycleArr(rule, year + 100, false)
} else if (rule.indexOf('/') >= 0) {
dateArr.value[5] = getAverageArr(rule, year + 100)
} else if (rule !== '*') {
dateArr.value[5] = getAssignArr(rule)
}
}
}
// ""
function getMonthArr(rule) {
dateArr.value[4] = getOrderArr(1, 12)
if (rule.indexOf('-') >= 0) {
dateArr.value[4] = getCycleArr(rule, 12, false)
} else if (rule.indexOf('/') >= 0) {
dateArr.value[4] = getAverageArr(rule, 12)
} else if (rule !== '*') {
dateArr.value[4] = getAssignArr(rule)
}
}
// ""-
function getWeekArr(rule) {
//
if (dayRule.value === '' && dayRuleSup.value === '') {
if (rule.indexOf('-') >= 0) {
dayRule.value = 'weekDay'
dayRuleSup.value = getCycleArr(rule, 7, false)
} else if (rule.indexOf('#') >= 0) {
dayRule.value = 'assWeek'
let matchRule = rule.match(/[0-9]{1}/g)
dayRuleSup.value = [Number(matchRule[1]), Number(matchRule[0])]
dateArr.value[3] = [1]
if (dayRuleSup.value[1] === 7) {
dayRuleSup.value[1] = 0
}
} else if (rule.indexOf('L') >= 0) {
dayRule.value = 'lastWeek'
dayRuleSup.value = Number(rule.match(/[0-9]{1,2}/g)[0])
dateArr.value[3] = [31]
if (dayRuleSup.value === 7) {
dayRuleSup.value = 0
}
} else if (rule !== '*' && rule !== '?') {
dayRule.value = 'weekDay'
dayRuleSup.value = getAssignArr(rule)
}
}
}
// ""-
function getDayArr(rule) {
dateArr.value[3] = getOrderArr(1, 31)
dayRule.value = ''
dayRuleSup.value = ''
if (rule.indexOf('-') >= 0) {
dateArr.value[3] = getCycleArr(rule, 31, false)
dayRuleSup.value = 'null'
} else if (rule.indexOf('/') >= 0) {
dateArr.value[3] = getAverageArr(rule, 31)
dayRuleSup.value = 'null'
} else if (rule.indexOf('W') >= 0) {
dayRule.value = 'workDay'
dayRuleSup.value = Number(rule.match(/[0-9]{1,2}/g)[0])
dateArr.value[3] = [dayRuleSup.value]
} else if (rule.indexOf('L') >= 0) {
dayRule.value = 'lastDay'
dayRuleSup.value = 'null'
dateArr.value[3] = [31]
} else if (rule !== '*' && rule !== '?') {
dateArr.value[3] = getAssignArr(rule)
dayRuleSup.value = 'null'
} else if (rule === '*') {
dayRuleSup.value = 'null'
}
}
// ""
function getHourArr(rule) {
dateArr.value[2] = getOrderArr(0, 23)
if (rule.indexOf('-') >= 0) {
dateArr.value[2] = getCycleArr(rule, 24, true)
} else if (rule.indexOf('/') >= 0) {
dateArr.value[2] = getAverageArr(rule, 23)
} else if (rule !== '*') {
dateArr.value[2] = getAssignArr(rule)
}
}
// ""
function getMinArr(rule) {
dateArr.value[1] = getOrderArr(0, 59)
if (rule.indexOf('-') >= 0) {
dateArr.value[1] = getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
dateArr.value[1] = getAverageArr(rule, 59)
} else if (rule !== '*') {
dateArr.value[1] = getAssignArr(rule)
}
}
// ""
function getSecondArr(rule) {
dateArr.value[0] = getOrderArr(0, 59)
if (rule.indexOf('-') >= 0) {
dateArr.value[0] = getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
dateArr.value[0] = getAverageArr(rule, 59)
} else if (rule !== '*') {
dateArr.value[0] = getAssignArr(rule)
}
}
// min-max
function getOrderArr(min, max) {
let arr = []
for (let i = min; i <= max; i++) {
arr.push(i)
}
return arr
}
//
function getAssignArr(rule) {
let arr = []
let assiginArr = rule.split(',')
for (let i = 0; i < assiginArr.length; i++) {
arr[i] = Number(assiginArr[i])
}
arr.sort(compare)
return arr
}
//
function getAverageArr(rule, limit) {
let arr = []
let agArr = rule.split('/')
let min = Number(agArr[0])
let step = Number(agArr[1])
while (min <= limit) {
arr.push(min)
min += step
}
return arr
}
//
function getCycleArr(rule, limit, status) {
// status--01
let arr = []
let cycleArr = rule.split('-')
let min = Number(cycleArr[0])
let max = Number(cycleArr[1])
if (min > max) {
max += limit
}
for (let i = min; i <= max; i++) {
let add = 0
if (status === false && i % limit === 0) {
add = limit
}
arr.push(Math.round((i % limit) + add))
}
arr.sort(compare)
return arr
}
// Array.sort
function compare(value1, value2) {
if (value2 - value1 > 0) {
return -1
} else {
return 1
}
}
// 2017-9-19 18:04:33
function formatDate(value, type) {
//
let time = typeof value == 'number' ? new Date(value) : value
let Y = time.getFullYear()
let M = time.getMonth() + 1
let D = time.getDate()
let h = time.getHours()
let m = time.getMinutes()
let s = time.getSeconds()
let week = time.getDay()
// type
if (type === undefined) {
return (
Y +
'-' +
(M < 10 ? '0' + M : M) +
'-' +
(D < 10 ? '0' + D : D) +
' ' +
(h < 10 ? '0' + h : h) +
':' +
(m < 10 ? '0' + m : m) +
':' +
(s < 10 ? '0' + s : s)
)
} else if (type === 'week') {
// quartz 1
return week + 1
}
}
//
function checkDate(value) {
let time = new Date(value)
let format = formatDate(time)
return value === format
}
onMounted(() => {
expressionChange()
})
</script>

View File

@ -0,0 +1,130 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model="radioValue" :label="1"> 允许的通配符[, - * /] </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2">
周期从
<el-input-number v-model="cycle01" :min="0" :max="58" /> - <el-input-number v-model="cycle02" :min="cycle01 + 1" :max="59" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
<el-input-number v-model="average01" :min="0" :max="58" /> 秒开始
<el-input-number v-model="average02" :min="1" :max="59 - average01" /> 秒执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 60" :key="item" :label="item - 1" :value="item - 1" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const radioValue = ref(1)
const cycle01 = ref(0)
const cycle02 = ref(1)
const average01 = ref(0)
const average02 = ref(1)
const checkboxList = ref([])
const checkCopy = ref([0])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, 0, 58)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, 59)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, 0, 58)
average02.value = props.check(average02.value, 1, 59 - average01.value)
return average01.value + '/' + average02.value
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.second,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '*') {
radioValue.value = 1
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 2
} else if (value.indexOf('/') > -1) {
const indexArr = value.split('/')
average01.value = Number(indexArr[0])
average02.value = Number(indexArr[1])
radioValue.value = 3
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 4
}
}
//
function onRadioChange() {
switch (radioValue.value) {
case 1:
emit('update', 'second', '*', 'second')
break
case 2:
emit('update', 'second', cycleTotal.value, 'second')
break
case 3:
emit('update', 'second', averageTotal.value, 'second')
break
case 4:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'second', checkboxString.value, 'second')
break
}
}
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.2rem;
}
.el-select,
.el-select--small {
width: 18.8rem;
}
</style>

View File

@ -0,0 +1,190 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model="radioValue" :label="1"> 允许的通配符[, - * ? / L #] </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="2"> 不指定 </el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="3">
周期从
<el-select clearable v-model="cycle01">
<el-option v-for="(item, index) of weekList" :key="index" :label="item.value" :value="item.key" :disabled="item.key === 7">{{
item.value
}}</el-option>
</el-select>
-
<el-select clearable v-model="cycle02">
<el-option v-for="(item, index) of weekList" :key="index" :label="item.value" :value="item.key" :disabled="item.key <= cycle01">{{
item.value
}}</el-option>
</el-select>
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="4">
<el-input-number v-model="average01" :min="1" :max="4" /> 周的
<el-select clearable v-model="average02">
<el-option v-for="item in weekList" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="5">
本月最后一个
<el-select clearable v-model="weekday">
<el-option v-for="item in weekList" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model="radioValue" :label="6">
指定
<el-select class="multiselect" clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="6">
<el-option v-for="item in weekList" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const radioValue = ref(2)
const cycle01 = ref(2)
const cycle02 = ref(3)
const average01 = ref(1)
const average02 = ref(2)
const weekday = ref(2)
const checkboxList = ref([])
const checkCopy = ref([2])
const weekList = ref([
{ key: 1, value: '星期日' },
{ key: 2, value: '星期一' },
{ key: 3, value: '星期二' },
{ key: 4, value: '星期三' },
{ key: 5, value: '星期四' },
{ key: 6, value: '星期五' },
{ key: 7, value: '星期六' }
])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, 1, 6)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, 7)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, 1, 4)
average02.value = props.check(average02.value, 1, 7)
return average02.value + '#' + average01.value
})
const weekdayTotal = computed(() => {
weekday.value = props.check(weekday.value, 1, 7)
return weekday.value + 'L'
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.week,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, weekdayTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '*') {
radioValue.value = 1
} else if (value === '?') {
radioValue.value = 2
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 3
} else if (value.indexOf('#') > -1) {
const indexArr = value.split('#')
average01.value = Number(indexArr[1])
average02.value = Number(indexArr[0])
radioValue.value = 4
} else if (value.indexOf('L') > -1) {
const indexArr = value.split('L')
weekday.value = Number(indexArr[0])
radioValue.value = 5
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 6
}
}
function onRadioChange() {
if (radioValue.value === 2 && props.cron.day === '?') {
emit('update', 'day', '*', 'week')
}
if (radioValue.value !== 2 && props.cron.day !== '?') {
emit('update', 'day', '?', 'week')
}
switch (radioValue.value) {
case 1:
emit('update', 'week', '*', 'week')
break
case 2:
emit('update', 'week', '?', 'week')
break
case 3:
emit('update', 'week', cycleTotal.value, 'week')
break
case 4:
emit('update', 'week', averageTotal.value, 'week')
break
case 5:
emit('update', 'week', weekdayTotal.value, 'week')
break
case 6:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'week', checkboxString.value, 'week')
break
}
}
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.5rem;
}
.el-select,
.el-select--small {
width: 8rem;
}
.el-select.multiselect,
.el-select--small.multiselect {
width: 17.8rem;
}
</style>

View File

@ -0,0 +1,149 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio :label="1" v-model="radioValue"> 不填允许的通配符[, - * /] </el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="2" v-model="radioValue"> 每年 </el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="3" v-model="radioValue">
周期从
<el-input-number v-model="cycle01" :min="fullYear" :max="maxFullYear - 1" /> -
<el-input-number v-model="cycle02" :min="cycle01 + 1" :max="maxFullYear" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="4" v-model="radioValue">
<el-input-number v-model="average01" :min="fullYear" :max="maxFullYear - 1" /> 年开始
<el-input-number v-model="average02" :min="1" :max="10" /> 年执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="5" v-model="radioValue">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="8">
<el-option v-for="item in 9" :key="item" :value="item - 1 + fullYear" :label="item - 1 + fullYear" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script setup>
const emit = defineEmits(['update'])
const props = defineProps({
cron: {
type: Object,
default: {
second: '*',
min: '*',
hour: '*',
day: '*',
month: '*',
week: '?',
year: ''
}
},
check: {
type: Function,
default: () => {}
}
})
const fullYear = ref(0)
const maxFullYear = ref(0)
const radioValue = ref(1)
const cycle01 = ref(0)
const cycle02 = ref(0)
const average01 = ref(0)
const average02 = ref(1)
const checkboxList = ref([])
const checkCopy = ref([])
const cycleTotal = computed(() => {
cycle01.value = props.check(cycle01.value, fullYear.value, maxFullYear.value - 1)
cycle02.value = props.check(cycle02.value, cycle01.value + 1, maxFullYear.value)
return cycle01.value + '-' + cycle02.value
})
const averageTotal = computed(() => {
average01.value = props.check(average01.value, fullYear.value, maxFullYear.value - 1)
average02.value = props.check(average02.value, 1, 10)
return average01.value + '/' + average02.value
})
const checkboxString = computed(() => {
return checkboxList.value.join(',')
})
watch(
() => props.cron.year,
(value) => changeRadioValue(value)
)
watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
function changeRadioValue(value) {
if (value === '') {
radioValue.value = 1
} else if (value === '*') {
radioValue.value = 2
} else if (value.indexOf('-') > -1) {
const indexArr = value.split('-')
cycle01.value = Number(indexArr[0])
cycle02.value = Number(indexArr[1])
radioValue.value = 3
} else if (value.indexOf('/') > -1) {
const indexArr = value.split('#')
average01.value = Number(indexArr[1])
average02.value = Number(indexArr[0])
radioValue.value = 4
} else {
checkboxList.value = [...new Set(value.split(',').map((item) => Number(item)))]
radioValue.value = 5
}
}
function onRadioChange() {
switch (radioValue.value) {
case 1:
emit('update', 'year', '', 'year')
break
case 2:
emit('update', 'year', '*', 'year')
break
case 3:
emit('update', 'year', cycleTotal.value, 'year')
break
case 4:
emit('update', 'year', averageTotal.value, 'year')
break
case 5:
if (checkboxList.value.length === 0) {
checkboxList.value.push(checkCopy.value[0])
} else {
checkCopy.value = checkboxList.value
}
emit('update', 'year', checkboxString.value, 'year')
break
}
}
onMounted(() => {
fullYear.value = Number(new Date().getFullYear())
maxFullYear.value = fullYear.value + 10
cycle01.value = fullYear.value
cycle02.value = cycle01.value + 1
average01.value = fullYear.value
checkCopy.value = [fullYear.value]
})
</script>
<style lang="scss" scoped>
.el-input-number--small,
.el-select,
.el-select--small {
margin: 0 0.2rem;
}
.el-select,
.el-select--small {
width: 18.8rem;
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<template v-for="(item, index) in props.options">
<template v-if="values.includes(item.dictValue)">
<span v-if="item.listClass == 'default' || item.listClass == ''" :key="item.dictValue" :index="index" :class="item.cssClass">
{{ item.dictLabel }} <i v-if="showValue">#{{ item.dictValue }}</i>
</span>
<el-tag
size="small"
v-else
:disable-transitions="true"
:index="index"
:type="item.listClass == 'primary' ? '' : item.listClass"
:class="item.cssClass">
{{ item.dictLabel }}
<i v-if="showValue">#{{ item.dictValue }}</i>
</el-tag>
</template>
</template>
</template>
<script setup>
const props = defineProps({
//
options: {
type: Array,
default: null,
},
//
value: [Number, String, Array, Boolean],
showValue: false,
})
const values = computed(() => {
if (props.value !== null && typeof props.value !== 'undefined') {
return Array.isArray(props.value) ? props.value : [String(props.value)]
} else {
return []
}
})
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
</style>

View File

@ -0,0 +1,90 @@
<template>
<div ref="chartRef" :class="className" :style="{ height: height, width: width }" />
</template>
<script setup>
import * as echarts from 'echarts'
// import("echarts/theme/macarons"); // echarts theme
// import { debounce } from '@/utils'
import { useDebounceFn } from '@vueuse/core'
const { proxy } = getCurrentInstance()
const props = defineProps({
name: {
type: String,
default: '',
},
min: {
type: [Object, Number],
default: 0,
},
max: {
type: [Object, Number],
default: 0,
},
data: {
type: Array,
default: () => [
{
value: '',
name: '占比',
},
],
},
className: {
type: String,
default: 'chart',
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: '300px',
},
})
let chart = null
const chartRef = ref()
//
const resizeHandler = () => {
chart.resize()
}
function initChart() {
chart = echarts.init(proxy.$refs.chartRef, 'macarons')
chart.setOption({
tooltip: {
formatter: '{a} <br/>{b} : {c}',
},
series: [
{
name: props.name,
type: 'gauge',
min: props.min,
max: props.max,
detail: {
formatter: '{value}%',
},
data: props.data,
},
],
})
}
const debouncedFn = useDebounceFn(() => {
// do something
resizeHandler()
}, 500)
document.addEventListener('resize', debouncedFn)
onMounted(() => {
initChart()
})
onBeforeUnmount(() => {
window.removeEventListener('resize', debouncedFn)
})
</script>

View File

@ -0,0 +1,135 @@
<template>
<div style="border: 1px solid #ccc">
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
<Editor
style="height: 300px; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
@onChange="handleChange" />
</div>
</template>
<script>
import '@wangeditor/editor/dist/css/style.css' // css
import { onBeforeUnmount, ref, shallowRef } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { getToken } from '@/utils/auth'
import useUserStore from '@/store/modules/user'
export default {
components: { Editor, Toolbar },
props: {
placeholder: {
type: String,
default: () => '请输入内容',
},
modelValue: String,
},
setup(props, { emit }) {
const editorRef = shallowRef()
const valueHtml = ref(props.modelValue)
const toolbarConfig = {}
const editorConfig = {
MENU_CONF: {},
placeholder: props.placeholder,
}
//
editorConfig.MENU_CONF['uploadImage'] = {
server: import.meta.env.VITE_APP_BASE_API + '/common/UploadFile',
// form-data fieldName 'wangeditor-uploaded-image'
fieldName: 'file',
// 2M
maxFileSize: 1 * 1024 * 1024, // 1M
// 100
maxNumberOfFiles: 10,
// ['image/*'] []
allowedFileTypes: ['image/*'],
// meta url false
metaWithUrl: false,
// http header
headers: {
Authorization: 'Bearer ' + getToken(),
userid: useUserStore().userId,
},
// cookie false
withCredentials: true,
// 10
timeout: 5 * 1000, // 5
//
customInsert(res, insertFn) {
;-(
// res url alt href
insertFn(res.data.url)
)
},
}
//
editorConfig.MENU_CONF['uploadVideo'] = {
server: import.meta.env.VITE_APP_BASE_API + '/common/UploadFile',
// form-data fieldName 'wangeditor-uploaded-video'
fieldName: 'file',
// 10M
maxFileSize: 5 * 1024 * 1024, // 5M
// 5
maxNumberOfFiles: 3,
// ['video/*'] []
allowedFileTypes: ['video/*'],
// meta url false
metaWithUrl: false,
// http header
headers: {
Authorization: 'Bearer ' + getToken(),
userid: useUserStore().userId,
},
// cookie false
withCredentials: true,
// 30
timeout: 15 * 1000, // 15
//
customInsert(res, insertFn) {
;-(
// res url alt href
insertFn(res.data.url)
)
},
}
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleCreated = (editor) => {
editorRef.value = editor
}
const handleChange = (editor) => {
emit('update:modelValue', editor.getHtml())
}
watch(
() => props.modelValue,
(value) => {
const editor = editorRef.value
if (value == undefined) {
editor.clear()
return
}
valueHtml.value = value;
},
)
return {
editorRef,
valueHtml,
mode: 'default',
toolbarConfig,
editorConfig,
handleCreated,
handleChange,
}
},
}
</script>

View File

@ -0,0 +1,254 @@
<template>
<div class="upload-file">
<el-upload
multiple
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
v-model:file-list="fileList"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:data="uploadData"
:drag="drag"
:headers="headers"
:auto-upload="autoUpload"
class="upload-file-uploader"
ref="fileUpload">
<!-- 拖拽上传 -->
<template v-if="drag">
<el-icon class="el-icon--upload">
<upload-filled />
</el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</template>
<!-- 上传按钮 -->
<el-button type="primary" icon="upload" v-if="!drag">选取文件</el-button>
<!-- 上传提示 -->
<template #tip>
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType && fileType.length > 0">
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
</template>
的文件
</div>
</template>
</el-upload>
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
<el-link :href="`${file.url}`" :underline="false" target="_blank">
<svg-icon class-name="doc-icon" name="documentation" />
{{ file.name }}
</el-link>
<div class="ele-upload-list__item-content-action">
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
</div>
</li>
</transition-group>
</div>
</template>
<script setup>
import { getToken } from '@/utils/auth'
const props = defineProps({
modelValue: [String, Object, Array],
//
limit: {
type: Number,
default: 5
},
// (MB)
fileSize: {
type: Number,
default: 5
},
// , ['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ['doc', 'xls', 'ppt', 'txt', 'pdf']
},
//
isShowTip: {
type: Boolean,
default: true
},
//
drag: {
type: Boolean,
default: false
},
//
autoUpload: {
type: Boolean,
default: true
},
//
data: {
type: Object
}
})
const { proxy } = getCurrentInstance()
const emit = defineEmits()
const number = ref(0)
const uploadList = ref([])
const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadFileUrl = ref(baseUrl + import.meta.env.VITE_APP_UPLOAD_URL) //
const headers = ref({ Authorization: 'Bearer ' + getToken() })
const fileList = ref([])
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
const uploadData = computed(() => props.data)
watch(
() => props.modelValue,
(val) => {
if (val) {
let temp = 1
//
const list = Array.isArray(val) ? val : props.modelValue.split(',')
//
fileList.value = list.map((item) => {
var fileName = item.slice(item.lastIndexOf('/') + 1)
if (typeof item === 'string') {
item = { name: fileName, url: item }
}
item.uid = item.uid || new Date().getTime() + temp++
return item
})
} else {
fileList.value = []
return []
}
},
{ deep: true, immediate: true }
)
//
function handleBeforeUpload(file) {
//
if (props.fileType.length) {
let fileExtension = ''
if (file.name.lastIndexOf('.') > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
}
const isTypeOk = props.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true
if (fileExtension && fileExtension.indexOf(type) > -1) return true
return false
})
if (!isTypeOk) {
proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
return false
}
}
//
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize
if (!isLt) {
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`)
return false
}
}
proxy.$modal.loading('正在上传文件,请稍候...')
number.value++
return true
}
//
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`)
}
//
function handleUploadError(err) {
proxy.$modal.msgError('上传失败')
proxy.$modal.closeLoading()
}
//
function handleUploadSuccess(response, uploadFile) {
if (response.code != 200) {
fileList.value = []
proxy.$modal.msgError(`上传失败,原因:${response.msg}!`)
proxy.$modal.closeLoading()
return
}
const { fileName, url, fileId } = response.data
const tempFile = { name: fileName, url: url }
uploadList.value.push(tempFile)
if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value)
uploadList.value = []
number.value = 0
emit('update:modelValue', listToString(fileList.value))
emit('success', listToString(fileList.value))
proxy.$modal.closeLoading()
}
}
//
function handleDelete(index) {
fileList.value.splice(index, 1)
//emit('update:modelValue', listToString(fileList.value))
}
//
function getFileName(name) {
if (name.lastIndexOf('/') > -1) {
return name.slice(name.lastIndexOf('/') + 1).toLowerCase()
} else {
return ''
}
}
//
function listToString(list, separator) {
let strs = ''
separator = separator || ','
list.forEach((element) => {
if (element) {
strs += element.url + separator
}
})
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
//
function submitUpload() {
proxy.$refs.fileUpload.submit()
}
defineExpose({
submitUpload
})
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
.doc-icon {
margin: 0 10px;
}
</style>

View File

@ -0,0 +1,42 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script setup>
defineProps({
isActive: {
type: Boolean,
default: false
}
})
const emit = defineEmits()
const toggleClick = () => {
emit('toggleClick');
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
fill: var(--base-color-white);
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<div class="header-search">
<svg-icon class-name="search-icon" name="search" @click.stop="click" />
<el-dialog v-model="open" width="500" @close="close">
<el-select
style="width: 100%"
ref="headerSearchSelectRef"
size="large"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
popper-class="header-search-select"
placement="bottom"
placeholder="菜单搜索支持标题、URL模糊查询"
@change="change">
<template #prefix>
<el-icon color="#409EFC" class="no-inherit">
<Search />
</el-icon>
</template>
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')">
<span style="float: left">
<div>
{{ option.item.title.join(' > ') }}
<div class="path">{{ option.item.path }}</div>
</div>
</span>
<span style="float: right" @click.stop="handleLove(option.item)"> <svg-icon color="#ccc" name="star" /></span>
</el-option>
</el-select>
</el-dialog>
</div>
</template>
<script setup>
import Fuse from 'fuse.js'
import { getNormalPath } from '@/utils/ruoyi'
import { isHttp } from '@/utils/validate'
import usePermissionStore from '@/store/modules/permission'
import { findItem, color16 } from '@/utils/ruoyi'
const { proxy } = getCurrentInstance()
const search = ref('')
const options = ref([])
const searchPool = ref([])
const show = ref(false)
const open = ref(false)
const fuse = ref(undefined)
const headerSearchSelectRef = ref(null)
const router = useRouter()
const routes = computed(() => usePermissionStore().routes)
function click() {
open.value = !open.value
show.value = !show.value
if (open.value) {
setTimeout(() => {
headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
}, 1)
}
}
function close() {
headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
options.value = []
show.value = false
open.value = false
}
function change(val) {
const path = val.path
if (isHttp(path)) {
// http(s)://
const pindex = path.indexOf('http')
window.open(path.substr(pindex, path.length), '_blank')
} else {
router.push(path)
}
search.value = ''
options.value = []
nextTick(() => {
show.value = false
open.value = false
})
}
function initFuse(list) {
fuse.value = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
minMatchCharLength: 1,
keys: [
{
name: 'title',
weight: 0.7
},
{
name: 'path',
weight: 0.3
}
]
})
}
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
function generateRoutes(routes, basePath = '', prefixTitle = []) {
let res = []
for (const r of routes) {
// skip hidden router
if (r.hidden) {
continue
}
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path
const data = {
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
title: [...prefixTitle],
icon: 'menu',
menuTitle: ''
}
if (r.meta && r.meta.title) {
data.title = [...data.title, r.meta.title]
data.icon = r.meta.icon
data.menuTitle = r.meta.title
if (r.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data)
}
}
// recursive child routes
if (r.children) {
const tempRoutes = generateRoutes(r.children, data.path, data.title)
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes]
}
}
}
return res
}
function querySearch(query) {
if (query !== '') {
options.value = fuse.value.search(query)
} else {
options.value = []
}
}
/**
* 添加快捷菜单
* @param {*} item
*/
function handleLove(item) {
var arraryObjectLocal = proxy.$cache.local.getJSON('commonlyUseMenu') || []
var len = 12
if (arraryObjectLocal.length >= len) {
proxy.$modal.msgError(`最多可添加${len}个常用菜单`)
return
}
let index = findItem(arraryObjectLocal, 'path', item.path)
if (index <= -1) {
arraryObjectLocal.push({ ...item, color: color16() })
proxy.$cache.local.setJSON('commonlyUseMenu', arraryObjectLocal)
proxy.$modal.msgSuccess('添加成功')
usePermissionStore().setCommonlyUsedRoutes()
} else {
proxy.$modal.msgError('该菜单已存在')
}
}
onMounted(() => {
searchPool.value = generateRoutes(routes.value)
})
watchEffect(() => {
searchPool.value = generateRoutes(routes.value)
})
watch(show, (value) => {
if (value) {
document.body.addEventListener('click', close)
} else {
document.body.removeEventListener('click', close)
}
})
watch(searchPool, (list) => {
initFuse(list)
})
</script>
<style lang="scss" scoped>
.header-search {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
:deep(.el-dialog) {
.el-dialog__header {
display: none !important;
}
--el-dialog-bg-color: #00000;
.el-dialog__body {
padding: 0;
}
}
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
}
.path {
color: #ccc;
font-size: 10px;
}
</style>

View File

@ -0,0 +1,101 @@
<template>
<div class="icon-body">
<el-input v-model="iconName" style="position: relative" clearable placeholder="请输入图标名称" @clear="filterIcons" @input="filterIcons">
<template #prefix>
<el-icon class="el-input__icon">
<search />
</el-icon>
</template>
<template #suffix>
<el-icon class="el-input__icon" @click="selectedIcon('')">
<delete />
</el-icon>
</template>
</el-input>
<el-tabs v-model="activeName">
<el-tab-pane label="svg-icon" name="1">
<div class="icon-list">
<div class="icon-item mb10" v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item, '')">
<svg-icon :name="item" style="height: 30px; width: 16px" />
<div class="name">{{ item }}</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="Element-UI Icons" name="2">
<div class="icon-list">
<div class="icon-item mb10" v-for="item of elementIcons" :key="item" @click="selectedIcon(item, 'ele-')">
<svg-icon :name="'ele-' + item" style="height: 30px; width: 16px" />
<div class="name">{{ item }}</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import icons from './requireIcons'
import * as elIcons from '@element-plus/icons-vue'
const elementIcons = ref([])
for (const key in elIcons) {
elementIcons.value.push(key)
}
const iconName = ref('')
const iconList = ref(icons)
const activeName = ref('1')
const emit = defineEmits(['selected'])
function filterIcons() {
iconList.value = icons
if (iconName.value) {
iconList.value = icons.filter((item) => item.indexOf(iconName.value) !== -1)
}
}
function selectedIcon(name, prefix) {
const iconName = prefix != undefined ? prefix + name : name
console.log(iconName)
emit('selected', iconName)
document.body.click()
}
function reset() {
iconName.value = ''
iconList.value = icons
}
defineExpose({
reset,
})
</script>
<style lang="scss" scoped>
.icon-body {
width: 100%;
padding: 10px;
.icon-list {
overflow-y: scroll;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
height: 200px;
.icon-item {
// height: 30px;
// line-height: 30px;
// margin-bottom: -5px;
cursor: pointer;
width: 19%;
text-align: center;
// float: left;
}
.name {
// display: inline-block;
// vertical-align: -0.15em;
// fill: currentColor;
// overflow: hidden;
}
}
}
</style>

View File

@ -0,0 +1,14 @@
let icons = []
const modules = import.meta.glob('./../../assets/icons/svg/*.svg')
for (const path in modules) {
const p = path.split('assets/icons/svg/')[1].split('.svg')[0]
icons.push(p)
}
// iconfont
import iconList from '@/assets/iconfont/iconfont.json'
iconList.glyphs.forEach((element) => {
icons.push(element.name)
})
export default icons

View File

@ -0,0 +1,85 @@
<template>
<el-image
:src="`${realSrc}`"
fit="cover"
:style="`width:${realWidth};height:${realHeight};`"
:preview-src-list="realSrcList"
>
<template #error>
<div class="image-slot">
<el-icon><picture-filled /></el-icon>
</div>
</template>
</el-image>
</template>
<script setup>
import { isExternal } from "@/utils/validate";
const props = defineProps({
src: {
type: String,
required: true
},
width: {
type: [Number, String],
default: ""
},
height: {
type: [Number, String],
default: ""
}
});
const realSrc = computed(() => {
let real_src = props.src.split(",")[0];
if (isExternal(real_src)) {
return real_src;
}
return import.meta.env.VITE_APP_BASE_API + real_src;
});
const realSrcList = computed(() => {
let real_src_list = props.src.split(",");
let srcList = [];
real_src_list.forEach(item => {
if (isExternal(item)) {
return srcList.push(item);
}
return srcList.push(import.meta.env.VITE_APP_BASE_API + item);
});
return srcList;
});
const realWidth = computed(() =>
typeof props.width == "string" ? props.width : `${props.width}px`
);
const realHeight = computed(() =>
typeof props.height == "string" ? props.height : `${props.height}px`
);
</script>
<style lang="scss" scoped>
.el-image {
border-radius: 5px;
background-color: #ebeef5;
box-shadow: 0 0 5px 1px #ccc;
:deep(.el-image__inner) {
transition: all 0.3s;
cursor: pointer;
&:hover {
transform: scale(1.2);
}
}
:deep(.image-slot) {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: #909399;
font-size: 30px;
}
}
</style>

View File

@ -0,0 +1,196 @@
<template>
<div class="component-upload-image">
<el-upload multiple :action="uploadImgUrl" list-type="picture-card" :on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed"
name="file" :data="data" :drag="drag" :on-remove="handleRemove" :show-file-list="true" :headers="headers"
v-model:file-list="fileList" :on-preview="handlePictureCardPreview" :class="{ hide: fileList.length >= limit }">
<el-icon class="avatar-uploader-icon">
<plus />
</el-icon>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
</template>
的文件
</div>
<el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from '@/utils/auth'
const props = defineProps({
modelValue: [String, Object, Array],
//
limit: {
type: Number,
default: 5,
},
// (MB)
fileSize: {
type: Number,
default: 5,
},
// , ['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ['png', 'jpg', 'jpeg'],
},
//
isShowTip: {
type: Boolean,
default: true,
},
//
data: {
type: Object,
},
//
drag: {
type: Boolean,
},
})
const { proxy } = getCurrentInstance()
const emit = defineEmits()
const number = ref(0)
const uploadList = ref([])
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadImgUrl = ref(baseUrl + import.meta.env.VITE_APP_UPLOAD_URL) //
const headers = ref({ Authorization: 'Bearer ' + getToken() })
const fileList = ref([])
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
watch(
() => props.modelValue,
(val) => {
if (val) {
//
const list = Array.isArray(val) ? val : props.modelValue.split(',')
//
fileList.value = list.map((item) => {
if (typeof item === 'string') {
// if (item.indexOf(baseUrl) === -1) {
// item = { name: baseUrl + item, url: baseUrl + item }
// } else {
item = { name: item, url: item }
// }
}
return item
})
} else {
fileList.value = []
return []
}
},
{ deep: true, immediate: true },
)
//
function handleRemove(file, files) {
emit('update:modelValue', listToString(fileList.value))
}
//
function handleUploadSuccess(res) {
if (res.code != 200) {
proxy.$modal.msgError(`上传失败,原因:${res.msg}!`)
proxy.$modal.closeLoading()
fileList.value = fileList.value.slice(0, fileList.value.length - 1)
return
}
uploadList.value.push({ name: res.data.fileName, url: res.data.url })
if (uploadList.value.length === number.value) {
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value)
uploadList.value = []
number.value = 0
emit('update:modelValue', listToString(fileList.value))
}
proxy.$modal.closeLoading()
}
// loading
function handleBeforeUpload(file) {
let isImg = false
if (props.fileType.length) {
let fileExtension = ''
if (file.name.lastIndexOf('.') > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
}
isImg = props.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true
if (fileExtension && fileExtension.indexOf(type) > -1) return true
return false
})
} else {
isImg = file.type.indexOf('image') > -1
}
if (!isImg) {
proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`)
return false
}
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize
if (!isLt) {
proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`)
return false
}
}
proxy.$modal.loading('正在上传图片,请稍候...')
number.value++
}
//
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`)
}
//
function handleUploadError() {
proxy.$modal.msgError('上传图片失败')
proxy.$modal.closeLoading()
}
//
function handlePictureCardPreview(file) {
dialogImageUrl.value = file.url
dialogVisible.value = true
}
//
function listToString(list, separator) {
let strs = ''
separator = separator || ','
for (let i in list) {
if (undefined !== list[i].url && list[i].url.indexOf('blob:') !== 0) {
strs += list[i].url + separator
}
}
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
</script>
<style lang="scss" scoped>
:deep(.hide .el-upload--picture-card) {
display: none !important;
}
:deep(.el-upload-dragger) {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>

Some files were not shown because too many files have changed in this diff Show More