提交 d43a33ee 作者: xiao0558

123

上级 f0c41576
# 告诉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
# 页面标题 # 页面标题
VUE_APP_TITLE = 若依管理系统 VITE_APP_TITLE = 若依管理系统
# 开发环境配置 # 开发环境配置
ENV = 'development' VITE_APP_ENV = 'development'
# 若依管理系统/开发环境 # 若依管理系统/开发环境
VUE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
# 页面标题 # 页面标题
VUE_APP_TITLE = 若依管理系统 VITE_APP_TITLE = 若依管理系统
# 生产环境配置 # 生产环境配置
ENV = 'production' VITE_APP_ENV = 'production'
# 若依管理系统/生产环境 # 若依管理系统/生产环境
VUE_APP_BASE_API = '/prod-api' VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
# 页面标题 # 页面标题
VUE_APP_TITLE = 若依管理系统 VITE_APP_TITLE = 若依管理系统
BABEL_ENV = production # 生产环境配置
VITE_APP_ENV = 'staging'
NODE_ENV = production # 若依管理系统/生产环境
VITE_APP_BASE_API = '/stage-api'
# 测试环境配置 # 是否在打包时开启压缩,支持 gzip 和 brotli
ENV = 'staging' VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
# 若依管理系统/测试环境
VUE_APP_BASE_API = '/stage-api'
# 忽略build目录下类型为js的文件的语法检查
build/*.js
# 忽略src/assets目录下文件的语法检查
src/assets
# 忽略public目录下文件的语法检查
public
# 忽略当前目录下为js的文件的语法检查
*.js
# 忽略当前目录下为vue的文件的语法检查
*.vue
\ No newline at end of file
// 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']
}
}
.DS_Store .DS_Store
node_modules/ node_modules/
dist/ dist/
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
**/*.log **/*.log
tests/**/coverage/ tests/**/coverage/
tests/e2e/reports tests/e2e/reports
selenium-debug.log selenium-debug.log
# Editor directories and files # Editor directories and files
.idea .idea
.vscode .vscode
*.suo *.suo
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.local *.local
package-lock.json package-lock.json
yarn.lock yarn.lock
/.project
The MIT License (MIT)
Copyright (c) 2018 RuoYi
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.
\ No newline at end of file
## 开发 <p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.8</h1>
<h4 align="center">基于SpringBoot+Vue3前后端分离的Java快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.8-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue/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) 版本。
* 配套后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast) 版本。
* 前端技术栈([Vue2](https://cn.vuejs.org) + [Element](https://github.com/ElemeFE/element) + [Vue CLI](https://cli.vuejs.org/zh)),请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui)
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)&nbsp;&nbsp;
## 前端运行
```bash ```bash
# 克隆项目 # 克隆项目
git clone https://gitee.com/y_project/RuoYi-Vue git clone https://github.com/yangzongzhuan/RuoYi-Vue3.git
# 进入项目目录 # 进入项目目录
cd ruoyi-ui cd RuoYi-Vue3
# 安装依赖 # 安装依赖
npm install yarn --registry=https://registry.npmmirror.com
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npmmirror.com
# 启动服务 # 启动服务
npm run dev yarn dev
# 构建测试环境 yarn build:stage
# 构建生产环境 yarn build:prod
# 前端访问地址 http://localhost:80
``` ```
浏览器访问 http://localhost:80 ## 内置功能
## 发布 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
3. 岗位管理:配置系统用户所属担任职务。
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
7. 参数管理:对系统动态配置常用参数。
8. 通知公告:系统通知公告信息发布维护。
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
10. 登录日志:系统登录日志记录查询包含登录异常。
11. 在线用户:当前系统中活跃用户状态监控。
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
14. 系统接口:根据业务代码自动生成相关的api接口文档。
15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
16. 缓存监控:对系统的缓存信息查询,命令统计等。
17. 在线构建器:拖动表单元素生成相应的HTML代码。
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
```bash ## 在线体验
# 构建测试环境
npm run build:stage - admin/admin123
- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
演示地址:http://vue.ruoyi.vip
文档地址:http://doc.ruoyi.vip
## 演示图
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
</tr>
</table>
## 若依前后端分离交流群
# 构建生产环境 QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/已满-174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [![加入QQ群](https://img.shields.io/badge/已满-161281055-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [![加入QQ群](https://img.shields.io/badge/已满-138988063-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [![加入QQ群](https://img.shields.io/badge/151450850-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) 点击按钮入群。
npm run build:prod \ No newline at end of file
```
\ No newline at end of file
module.exports = {
presets: [
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
'@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
'plugins': ['dynamic-import-node']
}
}
}
\ No newline at end of file
@echo off @echo off
echo. echo.
echo [信息] 打包Web工程,生成dist文件。 echo [信息] 打包Web工程,生成dist文件。
echo. echo.
%~d0 %~d0
cd %~dp0 cd %~dp0
cd .. cd ..
npm run build:prod yarn build:prod
pause pause
\ No newline at end of file
...@@ -7,6 +7,6 @@ echo. ...@@ -7,6 +7,6 @@ echo.
cd %~dp0 cd %~dp0
cd .. cd ..
npm install --registry=https://registry.npmmirror.com yarn --registry=https://registry.npmmirror.com
pause pause
\ No newline at end of file
@echo off @echo off
echo. echo.
echo [信息] 使用 Vue CLI 命令运行 Web 工程。 echo [信息] 使用 Vite 命令运行 Web 工程。
echo. echo.
%~d0 %~d0
cd %~dp0 cd %~dp0
cd .. cd ..
npm run dev yarn dev
pause pause
\ No newline at end of file
const { run } = require('runjs')
const chalk = require('chalk')
const config = require('../vue.config.js')
const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
const report = rawArgv.includes('--report')
run(`vue-cli-service build ${args}`)
const port = 9526
const publicPath = config.publicPath
var connect = require('connect')
var serveStatic = require('serve-static')
const app = connect()
app.use(
publicPath,
serveStatic('./dist', {
index: ['index.html', '/']
})
)
app.listen(port, function () {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
}
})
} else {
run(`vue-cli-service build ${args}`)
}
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<meta charset="utf-8"> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta charset="utf-8">
<meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="renderer" content="webkit">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title><%= webpackConfig.name %></title> <link rel="icon" href="/favicon.ico">
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]--> <title>若依管理系统</title>
<style> <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>
html, html,
body, body,
#app { #app {
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
} }
.chromeframe { .chromeframe {
margin: 0.2em 0; margin: 0.2em 0;
background: #ccc; background: #ccc;
...@@ -92,6 +94,7 @@ ...@@ -92,6 +94,7 @@
-ms-transform: rotate(0deg); -ms-transform: rotate(0deg);
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
-webkit-transform: rotate(360deg); -webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg); -ms-transform: rotate(360deg);
...@@ -105,6 +108,7 @@ ...@@ -105,6 +108,7 @@
-ms-transform: rotate(0deg); -ms-transform: rotate(0deg);
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
-webkit-transform: rotate(360deg); -webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg); -ms-transform: rotate(360deg);
...@@ -194,15 +198,18 @@ ...@@ -194,15 +198,18 @@
opacity: 0.5; opacity: 0.5;
} }
</style> </style>
</head> </head>
<body>
<div id="app"> <body>
<div id="loader-wrapper"> <div id="app">
<div id="loader"></div> <div id="loader-wrapper">
<div class="loader-section section-left"></div> <div id="loader"></div>
<div class="loader-section section-right"></div> <div class="loader-section section-left"></div>
<div class="load_title">正在加载系统资源,请耐心等待</div> <div class="loader-section section-right"></div>
</div> <div class="load_title">正在加载系统资源,请耐心等待</div>
</div> </div>
</body> </div>
</html> <script type="module" src="/src/main.js"></script>
</body>
</html>
\ No newline at end of file
...@@ -4,88 +4,45 @@ ...@@ -4,88 +4,45 @@
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
"type": "module",
"scripts": { "scripts": {
"dev": "vue-cli-service serve", "dev": "vite",
"build:prod": "vue-cli-service build", "build:prod": "vite build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vite build --mode staging",
"preview": "node build/index.js --preview", "preview": "vite preview"
"lint": "eslint --ext .js,.vue src"
}, },
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://gitee.com/y_project/RuoYi-Vue.git" "url": "https://gitee.com/y_project/RuoYi-Vue.git"
}, },
"dependencies": { "dependencies": {
"@riophae/vue-treeselect": "0.4.0", "@element-plus/icons-vue": "2.3.1",
"@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.11.0",
"axios": "0.28.1", "axios": "0.28.1",
"clipboard": "2.0.8", "clipboard": "2.0.11",
"core-js": "3.37.1", "echarts": "5.5.1",
"echarts": "5.4.0", "element-plus": "2.7.6",
"element-ui": "2.15.14",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"fuse.js": "6.4.3", "fuse.js": "6.6.2",
"highlight.js": "9.18.5", "js-beautify": "1.14.11",
"js-beautify": "1.13.0", "js-cookie": "3.0.5",
"js-cookie": "3.0.1", "jsencrypt": "3.3.2",
"jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "2.0.2", "pinia": "2.1.7",
"screenfull": "5.0.2", "splitpanes": "3.1.5",
"sortablejs": "1.10.2", "vue": "3.4.31",
"splitpanes": "2.4.1", "vue-cropper": "1.1.1",
"vue": "2.6.12", "vue-router": "4.4.0",
"vue-count-to": "1.0.13", "vuedraggable": "4.1.0"
"vue-cropper": "0.5.5",
"vue-meta": "2.4.0",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "4.4.6", "@vitejs/plugin-vue": "5.0.5",
"@vue/cli-plugin-eslint": "4.4.6", "sass": "1.77.5",
"@vue/cli-service": "4.4.6", "unplugin-auto-import": "0.17.6",
"babel-eslint": "10.1.0", "unplugin-vue-setup-extend-plus": "1.0.1",
"babel-plugin-dynamic-import-node": "2.3.3", "vite": "5.3.2",
"chalk": "4.1.0", "vite-plugin-compression": "0.5.1",
"compression-webpack-plugin": "6.1.2", "vite-plugin-svg-icons": "2.0.1"
"connect": "3.6.6", }
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5",
"svg-sprite-loader": "5.1.1",
"vue-template-compiler": "2.6.12"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
} }
User-agent: *
Disallow: /
\ No newline at end of file
<template> <template>
<div id="app"> <router-view />
<router-view />
<theme-picker />
</div>
</template> </template>
<script> <script setup>
import ThemePicker from "@/components/ThemePicker"; import useSettingsStore from '@/store/modules/settings'
import { handleThemeStyle } from '@/utils/theme'
export default { onMounted(() => {
name: "App", nextTick(() => {
components: { ThemePicker }, // 初始化主题样式
metaInfo() { handleThemeStyle(useSettingsStore().theme)
return { })
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title, })
titleTemplate: title => {
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
}
}
}
};
</script> </script>
<style scoped>
#app .theme-picker {
display: none;
}
</style>
import request from '@/utils/request' import request from '@/utils/request'
// 查询定时任务调度列表 // 查询定时任务调度列表
export function listJob(query) { export function listJob(query) {
return request({ return request({
url: '/monitor/job/list', url: '/monitor/job/list',
method: 'get', method: 'get',
params: query params: query
}) })
} }
// 查询定时任务调度详细 // 查询定时任务调度详细
export function getJob(jobId) { export function getJob(jobId) {
return request({ return request({
url: '/monitor/job/' + jobId, url: '/monitor/job/' + jobId,
method: 'get' method: 'get'
}) })
} }
// 新增定时任务调度 // 新增定时任务调度
export function addJob(data) { export function addJob(data) {
return request({ return request({
url: '/monitor/job', url: '/monitor/job',
method: 'post', method: 'post',
data: data data: data
}) })
} }
// 修改定时任务调度 // 修改定时任务调度
export function updateJob(data) { export function updateJob(data) {
return request({ return request({
url: '/monitor/job', url: '/monitor/job',
method: 'put', method: 'put',
data: data data: data
}) })
} }
// 删除定时任务调度 // 删除定时任务调度
export function delJob(jobId) { export function delJob(jobId) {
return request({ return request({
url: '/monitor/job/' + jobId, url: '/monitor/job/' + jobId,
method: 'delete' method: 'delete'
}) })
} }
// 任务状态修改 // 任务状态修改
export function changeJobStatus(jobId, status) { export function changeJobStatus(jobId, status) {
const data = { const data = {
jobId, jobId,
status status
} }
return request({ return request({
url: '/monitor/job/changeStatus', url: '/monitor/job/changeStatus',
method: 'put', method: 'put',
data: data data: data
}) })
} }
// 定时任务立即执行一次 // 定时任务立即执行一次
export function runJob(jobId, jobGroup) { export function runJob(jobId, jobGroup) {
const data = { const data = {
jobId, jobId,
jobGroup jobGroup
} }
return request({ return request({
url: '/monitor/job/run', url: '/monitor/job/run',
method: 'put', method: 'put',
data: data data: data
}) })
} }
\ No newline at end of file
import request from '@/utils/request' import request from '@/utils/request'
// 查询调度日志列表 // 查询调度日志列表
export function listJobLog(query) { export function listJobLog(query) {
return request({ return request({
url: '/monitor/jobLog/list', url: '/monitor/jobLog/list',
method: 'get', method: 'get',
params: query params: query
}) })
} }
// 删除调度日志 // 删除调度日志
export function delJobLog(jobLogId) { export function delJobLog(jobLogId) {
return request({ return request({
url: '/monitor/jobLog/' + jobLogId, url: '/monitor/jobLog/' + jobLogId,
method: 'delete' method: 'delete'
}) })
} }
// 清空调度日志 // 清空调度日志
export function cleanJobLog() { export function cleanJobLog() {
return request({ return request({
url: '/monitor/jobLog/clean', url: '/monitor/jobLog/clean',
method: 'delete' method: 'delete'
}) })
} }
...@@ -57,4 +57,4 @@ export function optionselect() { ...@@ -57,4 +57,4 @@ export function optionselect() {
url: '/system/dict/type/optionselect', url: '/system/dict/type/optionselect',
method: 'get' method: 'get'
}) })
} }
\ No newline at end of file
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component
// register globally
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
<?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="1733303018722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M368.832 67.2c51.328-16.384 89.216 34.112 75.712 76.416a346.816 346.816 0 0 0 435.84 435.84c42.304-13.44 92.8 24.384 76.48 75.712A467.968 467.968 0 1 1 368.832 67.2z m-35.776 122.688a368.832 368.832 0 1 0 501.056 501.056 445.952 445.952 0 0 1-501.056-501.056z" p-id="1448"></path></svg>
\ No newline at end of file
<?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="1733303115132" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12397" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 890.432c18.432 0 33.408 14.976 33.408 33.408v66.752a33.408 33.408 0 0 1-66.816 0v-66.752c0-18.432 14.976-33.408 33.408-33.408z m-267.52-110.848a33.408 33.408 0 0 1 0 47.232l-47.296 47.232a33.408 33.408 0 0 1-47.232-47.232l47.232-47.232a33.408 33.408 0 0 1 47.232 0z m582.336 0l47.232 47.232a33.408 33.408 0 0 1-47.232 47.232l-47.232-47.232a33.408 33.408 0 1 1 47.232-47.232zM512 200.32a311.68 311.68 0 1 1 0 623.296 311.68 311.68 0 0 1 0-623.36z m0 66.752a244.864 244.864 0 1 0 0 489.728 244.864 244.864 0 0 0 0-489.728zM100.16 478.592a33.408 33.408 0 1 1 0 66.816H33.408a33.408 33.408 0 0 1 0-66.816h66.752z m890.432 0a33.408 33.408 0 0 1 0 66.816h-66.752a33.408 33.408 0 1 1 0-66.816h66.752zM197.184 149.952l47.232 47.232a33.408 33.408 0 1 1-47.232 47.232l-47.232-47.232a33.408 33.408 0 0 1 47.232-47.232z m676.864 0a33.408 33.408 0 0 1 0 47.232l-47.232 47.232a33.408 33.408 0 1 1-47.232-47.232l47.232-47.232a33.408 33.408 0 0 1 47.232 0zM512 0c18.432 0 33.408 14.976 33.408 33.408v66.752a33.408 33.408 0 1 1-66.816 0V33.408C478.592 14.976 493.568 0 512 0z" p-id="12398"></path></svg>
\ No newline at end of file
# replace default config
# multipass: true
# full: true
plugins:
# - name
#
# or:
# - name: false
# - name: true
#
# or:
# - name:
# param1: 1
# param2: 2
- removeAttrs:
attrs:
- 'fill'
- 'fill-rule'
@import './variables.scss'; @import './variables.module.scss';
@mixin colorBtn($color) { @mixin colorBtn($color) {
background: $color; background: $color;
......
// cover some element-ui styles // cover some element-ui styles
.el-breadcrumb__inner, .el-breadcrumb__inner,
.el-breadcrumb__inner a { .el-breadcrumb__inner a {
font-weight: 400 !important; font-weight: 400 !important;
} }
.el-upload { .el-upload {
input[type="file"] { input[type="file"] {
display: none !important; display: none !important;
} }
} }
.el-upload__input { .el-upload__input {
display: none; display: none;
} }
.cell { .cell {
.el-tag { .el-tag {
margin-right: 0px; margin-right: 0px;
} }
} }
.small-padding { .small-padding {
.cell { .cell {
padding-left: 5px; padding-left: 5px;
padding-right: 5px; padding-right: 5px;
} }
} }
.fixed-width { .fixed-width {
.el-button--mini { .el-button--mini {
padding: 7px 10px; padding: 7px 10px;
width: 60px; width: 60px;
} }
} }
.status-col { .status-col {
.cell { .cell {
padding: 0 10px; padding: 0 10px;
text-align: center; text-align: center;
.el-tag { .el-tag {
margin-right: 0px; margin-right: 0px;
} }
} }
} }
// to fixed https://github.com/ElemeFE/element/issues/2461 // to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog { .el-dialog {
transform: none; transform: none;
left: 0; left: 0;
position: relative; position: relative;
margin: 0 auto; margin: 0 auto;
} }
// refine element ui upload // refine element ui upload
.upload-container { .upload-container {
.el-upload { .el-upload {
width: 100%; width: 100%;
.el-upload-dragger { .el-upload-dragger {
width: 100%; width: 100%;
height: 200px; height: 200px;
} }
} }
} }
// dropdown // dropdown
.el-dropdown-menu { .el-dropdown-menu {
a { a {
display: block display: block
} }
} }
// fix date-picker ui bug in filter-item // fix date-picker ui bug in filter-item
.el-range-editor.el-input__inner { .el-range-editor.el-input__inner {
display: inline-flex !important; display: inline-flex !important;
} }
// to fix el-date-picker css style // to fix el-date-picker css style
.el-range-separator { .el-range-separator {
box-sizing: content-box; box-sizing: content-box;
} }
.el-menu--collapse .el-menu--collapse
> div > div
> .el-submenu > .el-submenu
> .el-submenu__title > .el-submenu__title
.el-submenu__icon-arrow { .el-submenu__icon-arrow {
display: none; display: none;
}
.el-dropdown .el-dropdown-link{
color: var(--el-color-primary) !important;
} }
\ No newline at end of file
/**
* I think element-ui's default theme color is too light for long-term use.
* So I modified the default color and you can modify it to your liking.
**/
/* theme color */
$--color-primary: #1890ff;
$--color-success: #13ce66;
$--color-warning: #ffba00;
$--color-danger: #ff4949;
// $--color-info: #1E1E1E;
$--button-font-weight: 400;
// $--color-text-regular: #1f2d3d;
$--border-color-light: #dfe4ed;
$--border-color-lighter: #e6ebf5;
$--table-border: 1px solid #dfe6ec;
/* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
theme: $--color-primary;
}
@import './variables.scss'; @import './variables.module.scss';
@import './mixin.scss'; @import './mixin.scss';
@import './transition.scss'; @import './transition.scss';
@import './element-ui.scss'; @import './element-ui.scss';
@import './sidebar.scss'; @import './sidebar.scss';
@import './btn.scss'; @import './btn.scss';
@import './ruoyi.scss';
body {
height: 100%; body {
-moz-osx-font-smoothing: grayscale; height: 100%;
-webkit-font-smoothing: antialiased; margin: 0;
text-rendering: optimizeLegibility; -moz-osx-font-smoothing: grayscale;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; -webkit-font-smoothing: antialiased;
} text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
label { }
font-weight: 700;
} label {
font-weight: 700;
html { }
height: 100%;
box-sizing: border-box; html {
} height: 100%;
box-sizing: border-box;
#app { }
height: 100%;
} #app {
height: 100%;
*, }
*:before,
*:after { *,
box-sizing: inherit; *:before,
} *:after {
box-sizing: inherit;
.no-padding { }
padding: 0px !important;
} .no-padding {
padding: 0px !important;
.padding-content { }
padding: 4px 0;
} .padding-content {
padding: 4px 0;
a:focus, }
a:active {
outline: none; a:focus,
} a:active {
outline: none;
a, }
a:focus,
a:hover { a,
cursor: pointer; a:focus,
color: inherit; a:hover {
text-decoration: none; cursor: pointer;
} color: inherit;
text-decoration: none;
div:focus { }
outline: none;
} div:focus {
outline: none;
.fr { }
float: right;
} .fr {
float: right;
.fl { }
float: left;
} .fl {
float: left;
.pr-5 { }
padding-right: 5px;
} .pr-5 {
padding-right: 5px;
.pl-5 { }
padding-left: 5px;
} .pl-5 {
padding-left: 5px;
.block { }
display: block;
} .block {
display: block;
.pointer { }
cursor: pointer;
} .pointer {
cursor: pointer;
.inlineBlock { }
display: block;
} .inlineBlock {
display: block;
.clearfix { }
&:after {
visibility: hidden; .clearfix {
display: block; &:after {
font-size: 0; visibility: hidden;
content: " "; display: block;
clear: both; font-size: 0;
height: 0; content: " ";
} clear: both;
} height: 0;
}
aside { }
background: #eef1f6;
padding: 8px 24px; aside {
margin-bottom: 20px; background: #eef1f6;
border-radius: 2px; padding: 8px 24px;
display: block; margin-bottom: 20px;
line-height: 32px; border-radius: 2px;
font-size: 16px; display: block;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; line-height: 32px;
color: #2c3e50; font-size: 16px;
-webkit-font-smoothing: antialiased; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-moz-osx-font-smoothing: grayscale; color: #2c3e50;
-webkit-font-smoothing: antialiased;
a { -moz-osx-font-smoothing: grayscale;
color: #337ab7;
cursor: pointer; a {
color: #337ab7;
&:hover { cursor: pointer;
color: rgb(32, 160, 255);
} &:hover {
} color: rgb(32, 160, 255);
} }
}
//main-container全局样式 }
.app-container {
padding: 20px; //main-container全局样式
} .app-container {
padding: 20px;
.components-container { }
margin: 30px 50px;
position: relative; .components-container {
} margin: 30px 50px;
position: relative;
.pagination-container { }
margin-top: 30px;
} .pagination-container {
margin-top: 30px;
.text-center { }
text-align: center
} .text-center {
text-align: center
.sub-navbar { }
height: 50px;
line-height: 50px; .sub-navbar {
position: relative; height: 50px;
width: 100%; line-height: 50px;
text-align: right; position: relative;
padding-right: 20px; width: 100%;
transition: 600ms ease position; text-align: right;
background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); padding-right: 20px;
transition: 600ms ease position;
.subtitle { background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
font-size: 20px;
color: #fff; .subtitle {
} font-size: 20px;
color: #fff;
&.draft { }
background: #d0d0d0;
} &.draft {
background: #d0d0d0;
&.deleted { }
background: #d0d0d0;
} &.deleted {
} background: #d0d0d0;
}
.link-type, }
.link-type:focus {
color: #337ab7; .link-type,
cursor: pointer; .link-type:focus {
color: #337ab7;
&:hover { cursor: pointer;
color: rgb(32, 160, 255);
} &:hover {
} color: rgb(32, 160, 255);
}
.filter-container { }
padding-bottom: 10px;
.filter-container {
.filter-item { padding-bottom: 10px;
display: inline-block;
vertical-align: middle; .filter-item {
margin-bottom: 10px; display: inline-block;
} vertical-align: middle;
} margin-bottom: 10px;
}
}
/** /**
* 通用css样式布局处理 * 通用css样式布局处理
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
*/ */
/** 基础通用 **/ /** 基础通用 **/
.pt5 { .pt5 {
padding-top: 5px; padding-top: 5px;
} }
.pr5 {
.pr5 { padding-right: 5px;
padding-right: 5px; }
} .pb5 {
padding-bottom: 5px;
.pb5 { }
padding-bottom: 5px; .mt5 {
} margin-top: 5px;
}
.mt5 { .mr5 {
margin-top: 5px; margin-right: 5px;
} }
.mb5 {
.mr5 { margin-bottom: 5px;
margin-right: 5px; }
} .mb8 {
margin-bottom: 8px;
.mb5 { }
margin-bottom: 5px; .ml5 {
} margin-left: 5px;
}
.mb8 { .mt10 {
margin-bottom: 8px; margin-top: 10px;
} }
.mr10 {
.ml5 { margin-right: 10px;
margin-left: 5px; }
} .mb10 {
margin-bottom: 10px;
.mt10 { }
margin-top: 10px; .ml10 {
} margin-left: 10px;
}
.mr10 { .mt20 {
margin-right: 10px; margin-top: 20px;
} }
.mr20 {
.mb10 { margin-right: 20px;
margin-bottom: 10px; }
} .mb20 {
.ml10 { margin-bottom: 20px;
margin-left: 10px; }
} .ml20 {
margin-left: 20px;
.mt20 { }
margin-top: 20px;
} .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
font-family: inherit;
.mr20 { font-weight: 500;
margin-right: 20px; line-height: 1.1;
} color: inherit;
}
.mb20 {
margin-bottom: 20px; .el-form .el-form-item__label {
} font-weight: 700;
.ml20 { }
margin-left: 20px; .el-dialog:not(.is-fullscreen) {
} margin-top: 6vh !important;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
font-family: inherit; .el-dialog.scrollbar .el-dialog__body {
font-weight: 500; overflow: auto;
line-height: 1.1; overflow-x: hidden;
color: inherit; max-height: 70vh;
} padding: 10px 20px 0;
}
.el-message-box__status + .el-message-box__message{
word-break: break-word; .el-table {
} .el-table__header-wrapper, .el-table__fixed-header-wrapper {
th {
.el-dialog:not(.is-fullscreen) { word-break: break-word;
margin-top: 6vh !important; background-color: #f8f8f9 !important;
} color: #515a6e;
height: 40px !important;
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { font-size: 13px;
overflow: auto; }
overflow-x: hidden; }
max-height: 70vh; .el-table__body-wrapper {
padding: 10px 20px 0; .el-button [class*="el-icon-"] + span {
} margin-left: 1px;
}
.el-table { }
.el-table__header-wrapper, .el-table__fixed-header-wrapper { }
th {
word-break: break-word; /** 表单布局 **/
background-color: #f8f8f9; .form-header {
color: #515a6e; font-size:15px;
height: 40px; color:#6379bb;
font-size: 13px; border-bottom:1px solid #ddd;
} margin:8px 10px 25px 10px;
} padding-bottom:5px
}
.el-table__body-wrapper {
.el-button [class*="el-icon-"] + span { /** 表格布局 **/
margin-left: 1px; .pagination-container {
} position: relative;
} height: 25px;
} margin-bottom: 10px;
margin-top: 15px;
/** 表单布局 **/ padding: 10px 20px !important;
.form-header { background-color: transparent !important;
font-size: 15px; }
color: #6379bb;
border-bottom: 1px solid #ddd; /* 分页器定位 */
margin: 8px 10px 25px 10px; .pagination-container .el-pagination {
padding-bottom: 5px position: absolute;
} right: 0;
top: 0;
/** 表格布局 **/ }
.pagination-container {
position: relative; /* 弹窗中的分页器 */
height: 32px; .el-dialog .pagination-container {
margin-bottom: 10px; position: static !important;
margin-top: 15px; margin: 10px 0 0 0;
padding: 10px 20px !important; padding: 0 !important;
}
.el-pagination {
/* tree border */ position: static;
.tree-border { }
margin-top: 5px; }
border: 1px solid #e5e6e7;
background: #FFFFFF none; /* 移动端适配 */
border-radius: 4px; @media (max-width: 768px) {
} .pagination-container {
.el-pagination {
.pagination-container .el-pagination { > .el-pagination__jump {
right: 0; display: none !important;
position: absolute; }
} > .el-pagination__sizes {
display: none !important;
@media (max-width: 768px) { }
.pagination-container .el-pagination > .el-pagination__jump { }
display: none !important; }
} }
.pagination-container .el-pagination > .el-pagination__sizes {
display: none !important; /* tree border */
} .tree-border {
} margin-top: 5px;
border: 1px solid var(--el-border-color-light, #e5e6e7);
.el-table .fixed-width .el-button--mini { background: var(--el-bg-color, #FFFFFF) none;
padding-left: 0; border-radius:4px;
padding-right: 0; width: 100%;
width: inherit; }
}
.el-table .fixed-width .el-button--small {
/** 表格更多操作下拉样式 */ padding-left: 0;
.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { padding-right: 0;
cursor: pointer; width: inherit;
margin-left: 5px; }
}
/** 表格更多操作下拉样式 */
.el-table .el-dropdown, .el-icon-arrow-down { .el-table .el-dropdown-link {
font-size: 12px; cursor: pointer;
} color: #409EFF;
margin-left: 10px;
.el-tree-node__content > .el-checkbox { }
margin-right: 8px;
} .el-table .el-dropdown, .el-icon-arrow-down {
font-size: 12px;
.list-group-striped > .list-group-item { }
border-left: 0;
border-right: 0; .el-tree-node__content > .el-checkbox {
border-radius: 0; margin-right: 8px;
padding-left: 0; }
padding-right: 0;
} .list-group-striped > .list-group-item {
border-left: 0;
.list-group { border-right: 0;
padding-left: 0px; border-radius: 0;
list-style: none; padding-left: 0;
} padding-right: 0;
}
.list-group-item {
border-bottom: 1px solid #e7eaec; .list-group {
border-top: 1px solid #e7eaec; padding-left: 0px;
margin-bottom: -1px; list-style: none;
padding: 11px 0px; }
font-size: 13px;
} .list-group-item {
border-bottom: 1px solid #e7eaec;
.pull-right { border-top: 1px solid #e7eaec;
float: right !important; margin-bottom: -1px;
} padding: 11px 0px;
font-size: 13px;
.el-card__header { }
padding: 14px 15px 7px;
min-height: 40px; .pull-right {
} float: right !important;
}
.el-card__body {
padding: 15px 20px 20px 20px; .el-card__header {
} padding: 14px 15px 7px !important;
min-height: 40px;
.card-box { }
padding-right: 15px;
padding-left: 15px; .el-card__body {
margin-bottom: 10px; padding: 15px 20px 20px 20px !important;
} }
/* button color */ .card-box {
.el-button--cyan.is-active, padding-right: 15px;
.el-button--cyan:active { padding-left: 15px;
background: #20B2AA; margin-bottom: 10px;
border-color: #20B2AA; }
color: #FFFFFF;
} /* button color */
.el-button--cyan.is-active,
.el-button--cyan:focus, .el-button--cyan:active {
.el-button--cyan:hover { background: #20B2AA;
background: #48D1CC; border-color: #20B2AA;
border-color: #48D1CC; color: #FFFFFF;
color: #FFFFFF; }
}
.el-button--cyan:focus,
.el-button--cyan { .el-button--cyan:hover {
background-color: #20B2AA; background: #48D1CC;
border-color: #20B2AA; border-color: #48D1CC;
color: #FFFFFF; color: #FFFFFF;
} }
/* text color */ .el-button--cyan {
.text-navy { background-color: #20B2AA;
color: #1ab394; border-color: #20B2AA;
} color: #FFFFFF;
}
.text-primary {
color: inherit; /* text color */
} .text-navy {
color: #1ab394;
.text-success { }
color: #1c84c6;
} .text-primary {
color: inherit;
.text-info { }
color: #23c6c8;
} .text-success {
color: #1c84c6;
.text-warning { }
color: #f8ac59;
} .text-info {
color: #23c6c8;
.text-danger { }
color: #ed5565;
} .text-warning {
color: #f8ac59;
.text-muted { }
color: #888888;
} .text-danger {
color: #ed5565;
/* image */ }
.img-circle {
border-radius: 50%; .text-muted {
} color: #888888;
}
.img-lg {
width: 120px; /* image */
height: 120px; .img-circle {
} border-radius: 50%;
}
.avatar-upload-preview {
position: relative; .img-lg {
top: 50%; width: 120px;
left: 50%; height: 120px;
transform: translate(-50%, -50%); }
width: 200px;
height: 200px; .avatar-upload-preview {
border-radius: 50%; position: absolute;
box-shadow: 0 0 4px #ccc; top: 50%;
overflow: hidden; transform: translate(50%, -50%);
} width: 200px;
height: 200px;
/* 拖拽列样式 */ border-radius: 50%;
.sortable-ghost { box-shadow: 0 0 4px #ccc;
opacity: .8; overflow: hidden;
color: #fff !important; }
background: #42b983 !important;
} /* 拖拽列样式 */
.sortable-ghost{
.top-right-btn { opacity: .8;
position: relative; color: #fff!important;
float: right; background: #42b983!important;
} }
/* 分割面板样式 */ /* 表格右侧工具栏样式 */
.splitpanes.default-theme .splitpanes__pane { .top-right-btn {
background-color: #fff!important; margin-left: auto;
} }
/* 分割面板样式 */
.splitpanes.default-theme .splitpanes__pane {
background-color: var(--splitpanes-default-bg) !important;
}
#app { #app {
.main-container { .main-container {
height: 100%; min-height: 100%;
transition: margin-left .28s; transition: margin-left .28s;
margin-left: $base-sidebar-width; margin-left: $base-sidebar-width;
position: relative; position: relative;
...@@ -12,10 +12,8 @@ ...@@ -12,10 +12,8 @@
} }
.sidebar-container { .sidebar-container {
-webkit-transition: width .28s;
transition: width 0.28s; transition: width 0.28s;
width: $base-sidebar-width !important; width: $base-sidebar-width !important;
background-color: $base-menu-background;
height: 100%; height: 100%;
position: fixed; position: fixed;
font-size: 0px; font-size: 0px;
...@@ -70,26 +68,30 @@ ...@@ -70,26 +68,30 @@
width: 100% !important; width: 100% !important;
} }
.el-menu-item, .el-submenu__title { .el-menu-item, .menu-title {
overflow: hidden !important; overflow: hidden !important;
text-overflow: ellipsis !important; text-overflow: ellipsis !important;
white-space: nowrap !important; white-space: nowrap !important;
} }
.el-menu-item .el-menu-tooltip__trigger {
display: inline-block !important;
}
// menu hover // menu hover
.submenu-title-noDropdown, .sub-menu-title-noDropdown,
.el-submenu__title { .el-sub-menu__title {
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.06) !important; background-color: rgba(0, 0, 0, 0.06) !important;
} }
} }
& .theme-dark .is-active > .el-submenu__title { & .theme-dark .is-active > .el-sub-menu__title {
color: $base-menu-color-active !important; color: $base-menu-color-active !important;
} }
& .nest-menu .el-submenu>.el-submenu__title, & .nest-menu .el-sub-menu>.el-sub-menu__title,
& .el-submenu .el-menu-item { & .el-sub-menu .el-menu-item {
min-width: $base-sidebar-width !important; min-width: $base-sidebar-width !important;
&:hover { &:hover {
...@@ -97,9 +99,9 @@ ...@@ -97,9 +99,9 @@
} }
} }
& .theme-dark .nest-menu .el-submenu>.el-submenu__title, & .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
& .theme-dark .el-submenu .el-menu-item { & .theme-dark .el-sub-menu .el-menu-item {
background-color: $base-sub-menu-background !important; background-color: $base-sub-menu-background;
&:hover { &:hover {
background-color: $base-sub-menu-hover !important; background-color: $base-sub-menu-hover !important;
...@@ -116,7 +118,7 @@ ...@@ -116,7 +118,7 @@
margin-left: 54px; margin-left: 54px;
} }
.submenu-title-noDropdown { .sub-menu-title-noDropdown {
padding: 0 !important; padding: 0 !important;
position: relative; position: relative;
...@@ -129,10 +131,10 @@ ...@@ -129,10 +131,10 @@
} }
} }
.el-submenu { .el-sub-menu {
overflow: hidden; overflow: hidden;
&>.el-submenu__title { &>.el-sub-menu__title {
padding: 0 !important; padding: 0 !important;
.svg-icon { .svg-icon {
...@@ -143,8 +145,8 @@ ...@@ -143,8 +145,8 @@
} }
.el-menu--collapse { .el-menu--collapse {
.el-submenu { .el-sub-menu {
&>.el-submenu__title { &>.el-sub-menu__title {
&>span { &>span {
height: 0; height: 0;
width: 0; width: 0;
...@@ -152,12 +154,19 @@ ...@@ -152,12 +154,19 @@
visibility: hidden; visibility: hidden;
display: inline-block; display: inline-block;
} }
&>i {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
} }
} }
} }
} }
.el-menu--collapse .el-menu .el-submenu { .el-menu--collapse .el-menu .el-sub-menu {
min-width: $base-sidebar-width !important; min-width: $base-sidebar-width !important;
} }
...@@ -198,15 +207,15 @@ ...@@ -198,15 +207,15 @@
} }
} }
.nest-menu .el-submenu>.el-submenu__title, .nest-menu .el-sub-menu>.el-sub-menu__title,
.el-menu-item { .el-menu-item {
&:hover { &:hover {
// you can use $subMenuHover // you can use $sub-menuHover
background-color: rgba(0, 0, 0, 0.06) !important; background-color: rgba(0, 0, 0, 0.06) !important;
} }
} }
// the scroll bar appears when the subMenu is too long // the scroll bar appears when the sub-menu is too long
>.el-menu--popup { >.el-menu--popup {
max-height: 100vh; max-height: 100vh;
overflow-y: auto; overflow-y: auto;
......
// base color
$blue: #324157;
$light-blue: #333c46;
$red: #C03639;
$pink: #E65D6E;
$green: #30B08F;
$tiffany: #4AB7BD;
$yellow: #FEC171;
$panGreen: #30B08F;
// 默认主题变量
$menuText: #bfcbd9;
$menuActiveText: #409eff;
$menuBg: #304156;
$menuHover: #263445;
// 浅色主题theme-light
$menuLightBg: #ffffff;
$menuLightHover: #f0f1f5;
$menuLightText: #303133;
$menuLightActiveText: #409EFF;
// 基础变量
$base-sidebar-width: 200px;
$sideBarWidth: 200px;
// 菜单暗色变量
$base-menu-color: #bfcbd9;
$base-menu-color-active: #f4f4f5;
$base-menu-background: #304156;
$base-sub-menu-background: #1f2d3d;
$base-sub-menu-hover: #001528;
// 组件变量
$--color-primary: #409EFF;
$--color-success: #67C23A;
$--color-warning: #E6A23C;
$--color-danger: #F56C6C;
$--color-info: #909399;
:export {
menuText: $menuText;
menuActiveText: $menuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
menuLightBg: $menuLightBg;
menuLightHover: $menuLightHover;
menuLightText: $menuLightText;
menuLightActiveText: $menuLightActiveText;
sideBarWidth: $sideBarWidth;
// 导出基础颜色
blue: $blue;
lightBlue: $light-blue;
red: $red;
pink: $pink;
green: $green;
tiffany: $tiffany;
yellow: $yellow;
panGreen: $panGreen;
// 导出组件颜色
colorPrimary: $--color-primary;
colorSuccess: $--color-success;
colorWarning: $--color-warning;
colorDanger: $--color-danger;
colorInfo: $--color-info;
}
// CSS变量定义
:root {
/* 亮色模式变量 */
--sidebar-bg: #{$menuBg};
--sidebar-text: #{$menuText};
--menu-hover: #{$menuHover};
--navbar-bg: #ffffff;
--navbar-text: #303133;
/* splitpanes default-theme 变量 */
--splitpanes-default-bg: #ffffff;
}
// 暗黑模式变量
html.dark {
/* 默认通用 */
--el-bg-color: #141414;
--el-bg-color-overlay: #1d1e1f;
--el-text-color-primary: #ffffff;
--el-text-color-regular: #d0d0d0;
--el-border-color: #434343;
--el-border-color-light: #434343;
/* 侧边栏 */
--sidebar-bg: #141414;
--sidebar-text: #ffffff;
--menu-hover: #2d2d2d;
--menu-active-text: #{$menuActiveText};
/* 顶部导航栏 */
--navbar-bg: #141414;
--navbar-text: #ffffff;
--navbar-hover: #141414;
/* 标签栏 */
--tags-bg: #141414;
--tags-item-bg: #1d1e1f;
--tags-item-border: #303030;
--tags-item-text: #d0d0d0;
--tags-item-hover: #2d2d2d;
--tags-close-hover: #64666a;
/* splitpanes 组件暗黑模式变量 */
--splitpanes-bg: #141414;
--splitpanes-border: #303030;
--splitpanes-splitter-bg: #1d1e1f;
--splitpanes-splitter-hover-bg: #2d2d2d;
/* blockquote 暗黑模式变量 */
--blockquote-bg: #1d1e1f;
--blockquote-border: #303030;
--blockquote-text: #d0d0d0;
/* Cron 时间表达式 模式变量 */
--cron-border: #303030;
/* splitpanes default-theme 暗黑模式变量 */
--splitpanes-default-bg: #141414;
/* 侧边栏菜单覆盖 */
.sidebar-container {
.el-menu-item, .menu-title {
color: var(--el-text-color-regular);
}
& .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
& .theme-dark .el-sub-menu .el-menu-item {
background-color: var(--el-bg-color) !important;
}
}
/* 顶部栏栏菜单覆盖 */
.el-menu--horizontal {
.el-menu-item {
&:not(.is-disabled) {
&:hover,
&:focus {
background-color: var(--navbar-hover) !important;
}
}
}
}
/* 分割窗格覆盖 */
.splitpanes {
background-color: var(--splitpanes-bg);
.splitpanes__pane {
background-color: var(--splitpanes-bg);
border-color: var(--splitpanes-border);
}
.splitpanes__splitter {
background-color: var(--splitpanes-splitter-bg);
border-color: var(--splitpanes-border);
&:hover {
background-color: var(--splitpanes-splitter-hover-bg);
}
&:before,
&:after {
background-color: var(--splitpanes-border);
}
}
}
/* 表格样式覆盖 */
.el-table {
--el-table-header-bg-color: var(--el-bg-color-overlay) !important;
--el-table-header-text-color: var(--el-text-color-regular) !important;
--el-table-border-color: var(--el-border-color-light) !important;
--el-table-row-hover-bg-color: var(--el-bg-color-overlay) !important;
.el-table__header-wrapper, .el-table__fixed-header-wrapper {
th {
background-color: var(--el-bg-color-overlay, #f8f8f9) !important;
color: var(--el-text-color-regular, #515a6e);
}
}
}
/* 树组件高亮样式覆盖 */
.el-tree {
.el-tree-node.is-current > .el-tree-node__content {
background-color: var(--el-bg-color-overlay) !important;
color: var(--el-color-primary);
}
.el-tree-node__content:hover {
background-color: var(--el-bg-color-overlay);
}
}
/* 下拉菜单样式覆盖 */
.el-dropdown-menu__item:not(.is-disabled):focus, .el-dropdown-menu__item:not(.is-disabled):hover{
background-color: var(--navbar-hover) !important;
}
/* blockquote样式覆盖 */
blockquote {
background-color: var(--blockquote-bg) !important;
border-left-color: var(--blockquote-border) !important;
color: var(--blockquote-text) !important;
}
/* 时间表达式标题样式覆盖 */
.popup-result .title {
background: var(--cron-border);
}
}
// base color
$blue:#324157;
$light-blue:#3A71A8;
$red:#C03639;
$pink: #E65D6E;
$green: #30B08F;
$tiffany: #4AB7BD;
$yellow:#FEC171;
$panGreen: #30B08F;
// 默认菜单主题风格
$base-menu-color:#bfcbd9;
$base-menu-color-active:#f4f4f5;
$base-menu-background:#304156;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background:#1f2d3d;
$base-sub-menu-hover:#001528;
// 自定义暗色菜单风格
/**
$base-menu-color:hsla(0,0%,100%,.65);
$base-menu-color-active:#fff;
$base-menu-background:#001529;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
$base-sidebar-width: 200px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
menuColor: $base-menu-color;
menuLightColor: $base-menu-light-color;
menuColorActive: $base-menu-color-active;
menuBackground: $base-menu-background;
menuLightBackground: $base-menu-light-background;
subMenuBackground: $base-sub-menu-background;
subMenuHover: $base-sub-menu-hover;
sideBarWidth: $base-sidebar-width;
logoTitleColor: $base-logo-title-color;
logoLightTitleColor: $base-logo-light-title-color
}
<template> <template>
<el-breadcrumb class="app-breadcrumb" separator="/"> <el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb"> <transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path"> <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-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item> </el-breadcrumb-item>
</transition-group> </transition-group>
</el-breadcrumb> </el-breadcrumb>
</template> </template>
<script> <script setup>
export default { import usePermissionStore from '@/store/modules/permission'
data() {
return { const route = useRoute()
levelList: null const router = useRouter()
} const permissionStore = usePermissionStore()
}, const levelList = ref([])
watch: {
$route(route) { function getBreadcrumb() {
// if you go to the redirect page, do not update the breadcrumbs // only show routes with meta.title
if (route.path.startsWith('/redirect/')) { let matched = []
return const pathNum = findPathNum(route.path)
} // multi-level menu
this.getBreadcrumb() if (pathNum > 2) {
} const reg = /\/\w+/gi
}, const pathList = route.path.match(reg).map((item, index) => {
created() { if (index !== 0) item = item.slice(1)
this.getBreadcrumb() return item
}, })
methods: { getMatched(pathList, permissionStore.defaultRoutes, matched)
getBreadcrumb() { } else {
// only show routes with meta.title matched = route.matched.filter((item) => item.meta && item.meta.title)
let matched = [] }
const router = this.$route // 判断是否为首页
const pathNum = this.findPathNum(router.path) if (!isDashboard(matched[0])) {
// multi-level menu matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched)
if (pathNum > 2) { }
const reg = /\/\w+/gi levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
const pathList = router.path.match(reg).map((item, index) => { }
if (index !== 0) item = item.slice(1) function findPathNum(str, char = "/") {
return item let index = str.indexOf(char)
}) let num = 0
this.getMatched(pathList, this.$store.getters.defaultRoutes, matched) while (index !== -1) {
} else { num++
matched = router.matched.filter(item => item.meta && item.meta.title) index = str.indexOf(char, index + 1)
} }
// 判断是否为首页 return num
if (!this.isDashboard(matched[0])) { }
matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched) function getMatched(pathList, routeList, matched) {
} let data = routeList.find(item => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0])
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) if (data) {
}, matched.push(data)
findPathNum(str, char = "/") { if (data.children && pathList.length) {
let index = str.indexOf(char) pathList.shift()
let num = 0 getMatched(pathList, data.children, matched)
while (index !== -1) { }
num++ }
index = str.indexOf(char, index + 1) }
} function isDashboard(route) {
return num const name = route && route.name
}, if (!name) {
getMatched(pathList, routeList, matched) { return false
let data = routeList.find(item => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0]) }
if (data) { return name.trim() === 'Index'
matched.push(data) }
if (data.children && pathList.length) { function handleLink(item) {
pathList.shift() const { redirect, path } = item
this.getMatched(pathList, data.children, matched) if (redirect) {
} router.push(redirect)
} return
}, }
isDashboard(route) { router.push(path)
const name = route && route.name }
if (!name) {
return false watchEffect(() => {
} // if you go to the redirect page, do not update the breadcrumbs
return name.trim() === 'Index' if (route.path.startsWith('/redirect/')) {
}, return
handleLink(item) { }
const { redirect, path } = item getBreadcrumb()
if (redirect) { })
this.$router.push(redirect) getBreadcrumb()
return </script>
}
this.$router.push(path) <style lang='scss' scoped>
} .app-breadcrumb.el-breadcrumb {
} display: inline-block;
} font-size: 14px;
</script> line-height: 50px;
margin-left: 8px;
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb { .no-redirect {
display: inline-block; color: #97a8be;
font-size: 14px; cursor: text;
line-height: 50px; }
margin-left: 8px; }
.no-redirect { </style>
color: #97a8be; \ No newline at end of file
cursor: text;
}
}
</style>
<template> <template>
<el-form size="small"> <el-form>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="1"> <el-radio v-model='radioValue' :value="1">
日,允许的通配符[, - * ? / L W] 日,允许的通配符[, - * ? / L W]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="2"> <el-radio v-model='radioValue' :value="2">
不指定 不指定
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="3"> <el-radio v-model='radioValue' :value="3">
周期从 周期从
<el-input-number v-model='cycle01' :min="1" :max="30" /> - <el-input-number v-model='cycle01' :min="1" :max="30" /> -
<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="31" /> <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="31" />
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="4"> <el-radio v-model='radioValue' :value="4">
<el-input-number v-model='average01' :min="1" :max="30" /> 号开始,每 <el-input-number v-model='average01' :min="1" :max="30" /> 号开始,每
<el-input-number v-model='average02' :min="1" :max="31 - average01 || 1" /> 日执行一次 <el-input-number v-model='average02' :min="1" :max="31 - average01" /> 日执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="5"> <el-radio v-model='radioValue' :value="5">
每月 每月
<el-input-number v-model='workday' :min="1" :max="31" /> 号最近的那个工作日 <el-input-number v-model='workday' :min="1" :max="31" /> 号最近的那个工作日
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="6"> <el-radio v-model='radioValue' :value="6">
本月最后一天 本月最后一天
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="7"> <el-radio v-model='radioValue' :value="7">
指定 指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%"> <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 31" :key="item" :value="item">{{item}}</el-option> <el-option v-for="item in 31" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script setup>
<script> const emit = defineEmits(['update'])
export default { const props = defineProps({
data() { cron: {
return { type: Object,
radioValue: 1, default: {
workday: 1, second: "*",
cycle01: 1, min: "*",
cycle02: 2, hour: "*",
average01: 1, day: "*",
average02: 1, month: "*",
checkboxList: [], week: "?",
checkNum: this.$options.propsData.check year: "",
} }
}, },
name: 'crontab-day', check: {
props: ['check', 'cron'], type: Function,
methods: { default: () => {
// 单选按钮值变化时 }
radioChange() { }
('day rachange'); })
if (this.radioValue !== 2 && this.cron.week !== '?') { const radioValue = ref(1)
this.$emit('update', 'week', '?', 'day') const cycle01 = ref(1)
} const cycle02 = ref(2)
const average01 = ref(1)
switch (this.radioValue) { const average02 = ref(1)
case 1: const workday = ref(1)
this.$emit('update', 'day', '*'); const checkboxList = ref([])
break; const checkCopy = ref([1])
case 2: const cycleTotal = computed(() => {
this.$emit('update', 'day', '?'); cycle01.value = props.check(cycle01.value, 1, 30)
break; cycle02.value = props.check(cycle02.value, cycle01.value + 1, 31)
case 3: return cycle01.value + '-' + cycle02.value
this.$emit('update', 'day', this.cycleTotal); })
break; const averageTotal = computed(() => {
case 4: average01.value = props.check(average01.value, 1, 30)
this.$emit('update', 'day', this.averageTotal); average02.value = props.check(average02.value, 1, 31 - average01.value)
break; return average01.value + '/' + average02.value
case 5: })
this.$emit('update', 'day', this.workday + 'W'); const workdayTotal = computed(() => {
break; workday.value = props.check(workday.value, 1, 31)
case 6: return workday.value + 'W'
this.$emit('update', 'day', 'L'); })
break; const checkboxString = computed(() => {
case 7: return checkboxList.value.join(',')
this.$emit('update', 'day', this.checkboxString); })
break; watch(() => props.cron.day, value => changeRadioValue(value))
} watch([radioValue, cycleTotal, averageTotal, workdayTotal, checkboxString], () => onRadioChange())
('day rachange end'); function changeRadioValue(value) {
}, if (value === "*") {
// 周期两个值变化时 radioValue.value = 1
cycleChange() { } else if (value === "?") {
if (this.radioValue == '3') { radioValue.value = 2
this.$emit('update', 'day', this.cycleTotal); } else if (value.indexOf("-") > -1) {
} const indexArr = value.split('-')
}, cycle01.value = Number(indexArr[0])
// 平均两个值变化时 cycle02.value = Number(indexArr[1])
averageChange() { radioValue.value = 3
if (this.radioValue == '4') { } else if (value.indexOf("/") > -1) {
this.$emit('update', 'day', this.averageTotal); const indexArr = value.split('/')
} average01.value = Number(indexArr[0])
}, average02.value = Number(indexArr[1])
// 最近工作日值变化时 radioValue.value = 4
workdayChange() { } else if (value.indexOf("W") > -1) {
if (this.radioValue == '5') { const indexArr = value.split("W")
this.$emit('update', 'day', this.workdayCheck + 'W'); workday.value = Number(indexArr[0])
} radioValue.value = 5
}, } else if (value === "L") {
// checkbox值变化时 radioValue.value = 6
checkboxChange() { } else {
if (this.radioValue == '7') { checkboxList.value = [...new Set(value.split(',').map(item => Number(item)))]
this.$emit('update', 'day', this.checkboxString); radioValue.value = 7
} }
} }
}, // 单选按钮值变化时
watch: { function onRadioChange() {
'radioValue': 'radioChange', if (radioValue.value === 2 && props.cron.week === '?') {
'cycleTotal': 'cycleChange', emit('update', 'week', '*', 'day')
'averageTotal': 'averageChange', }
'workdayCheck': 'workdayChange', if (radioValue.value !== 2 && props.cron.week !== '?') {
'checkboxString': 'checkboxChange', emit('update', 'week', '?', 'day')
}, }
computed: { switch (radioValue.value) {
// 计算两个周期值 case 1:
cycleTotal: function () { emit('update', 'day', '*', 'day')
const cycle01 = this.checkNum(this.cycle01, 1, 30) break
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 31, 31) case 2:
return cycle01 + '-' + cycle02; emit('update', 'day', '?', 'day')
}, break
// 计算平均用到的值 case 3:
averageTotal: function () { emit('update', 'day', cycleTotal.value, 'day')
const average01 = this.checkNum(this.average01, 1, 30) break
const average02 = this.checkNum(this.average02, 1, 31 - average01 || 0) case 4:
return average01 + '/' + average02; emit('update', 'day', averageTotal.value, 'day')
}, break
// 计算工作日格式 case 5:
workdayCheck: function () { emit('update', 'day', workdayTotal.value, 'day')
const workday = this.checkNum(this.workday, 1, 31) break
return workday; case 6:
}, emit('update', 'day', 'L', 'day')
// 计算勾选的checkbox值合集 break
checkboxString: function () { case 7:
let str = this.checkboxList.join(); if (checkboxList.value.length === 0) {
return str == '' ? '*' : str; checkboxList.value.push(checkCopy.value[0])
} } else {
} checkCopy.value = checkboxList.value
} }
</script> 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>
\ No newline at end of file
<template> <template>
<el-form size="small"> <el-form>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="1"> <el-radio v-model='radioValue' :value="1">
小时,允许的通配符[, - * /] 小时,允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="2"> <el-radio v-model='radioValue' :value="2">
周期从 周期从
<el-input-number v-model='cycle01' :min="0" :max="22" /> - <el-input-number v-model='cycle01' :min="0" :max="22" /> -
<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="23" /> 小时 <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="23" />
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="3"> <el-radio v-model='radioValue' :value="3">
<el-input-number v-model='average01' :min="0" :max="22" /> 小时开始,每 <el-input-number v-model='average01' :min="0" :max="22" /> 时开始,每
<el-input-number v-model='average02' :min="1" :max="23 - average01 || 0" /> 小时执行一次 <el-input-number v-model='average02' :min="1" :max="23 - average01" /> 小时执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="4"> <el-radio v-model='radioValue' :value="4">
指定 指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%"> <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 24" :key="item" :value="item-1">{{item-1}}</el-option> <el-option v-for="item in 24" :key="item" :label="item - 1" :value="item - 1" />
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script> <script setup>
export default { const emit = defineEmits(['update'])
data() { const props = defineProps({
return { cron: {
radioValue: 1, type: Object,
cycle01: 0, default: {
cycle02: 1, second: "*",
average01: 0, min: "*",
average02: 1, hour: "*",
checkboxList: [], day: "*",
checkNum: this.$options.propsData.check month: "*",
} week: "?",
}, year: "",
name: 'crontab-hour', }
props: ['check', 'cron'], },
methods: { check: {
// 单选按钮值变化时 type: Function,
radioChange() { default: () => {
if (this.cron.min === '*') { }
this.$emit('update', 'min', '0', 'hour'); }
} })
if (this.cron.second === '*') { const radioValue = ref(1)
this.$emit('update', 'second', '0', 'hour'); const cycle01 = ref(0)
} const cycle02 = ref(1)
switch (this.radioValue) { const average01 = ref(0)
case 1: const average02 = ref(1)
this.$emit('update', 'hour', '*') const checkboxList = ref([])
break; const checkCopy = ref([0])
case 2: const cycleTotal = computed(() => {
this.$emit('update', 'hour', this.cycleTotal); cycle01.value = props.check(cycle01.value, 0, 22)
break; cycle02.value = props.check(cycle02.value, cycle01.value + 1, 23)
case 3: return cycle01.value + '-' + cycle02.value
this.$emit('update', 'hour', this.averageTotal); })
break; const averageTotal = computed(() => {
case 4: average01.value = props.check(average01.value, 0, 22)
this.$emit('update', 'hour', this.checkboxString); average02.value = props.check(average02.value, 1, 23 - average01.value)
break; return average01.value + '/' + average02.value
} })
}, const checkboxString = computed(() => {
// 周期两个值变化时 return checkboxList.value.join(',')
cycleChange() { })
if (this.radioValue == '2') { watch(() => props.cron.hour, value => changeRadioValue(value))
this.$emit('update', 'hour', this.cycleTotal); watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
} function changeRadioValue(value) {
}, if (props.cron.min === '*') {
// 平均两个值变化时 emit('update', 'min', '0', 'hour');
averageChange() { }
if (this.radioValue == '3') { if (props.cron.second === '*') {
this.$emit('update', 'hour', this.averageTotal); emit('update', 'second', '0', 'hour');
} }
}, if (value === '*') {
// checkbox值变化时 radioValue.value = 1
checkboxChange() { } else if (value.indexOf('-') > -1) {
if (this.radioValue == '4') { const indexArr = value.split('-')
this.$emit('update', 'hour', this.checkboxString); cycle01.value = Number(indexArr[0])
} cycle02.value = Number(indexArr[1])
} radioValue.value = 2
}, } else if (value.indexOf('/') > -1) {
watch: { const indexArr = value.split('/')
'radioValue': 'radioChange', average01.value = Number(indexArr[0])
'cycleTotal': 'cycleChange', average02.value = Number(indexArr[1])
'averageTotal': 'averageChange', radioValue.value = 3
'checkboxString': 'checkboxChange' } else {
}, checkboxList.value = [...new Set(value.split(',').map(item => Number(item)))]
computed: { radioValue.value = 4
// 计算两个周期值 }
cycleTotal: function () { }
const cycle01 = this.checkNum(this.cycle01, 0, 22) function onRadioChange() {
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 23) switch (radioValue.value) {
return cycle01 + '-' + cycle02; case 1:
}, emit('update', 'hour', '*', 'hour')
// 计算平均用到的值 break
averageTotal: function () { case 2:
const average01 = this.checkNum(this.average01, 0, 22) emit('update', 'hour', cycleTotal.value, 'hour')
const average02 = this.checkNum(this.average02, 1, 23 - average01 || 0) break
return average01 + '/' + average02; case 3:
}, emit('update', 'hour', averageTotal.value, 'hour')
// 计算勾选的checkbox值合集 break
checkboxString: function () { case 4:
let str = this.checkboxList.join(); if (checkboxList.value.length === 0) {
return str == '' ? '*' : str; checkboxList.value.push(checkCopy.value[0])
} } else {
} checkCopy.value = checkboxList.value
} }
</script> 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>
\ No newline at end of file
<template> <template>
<el-form size="small"> <el-form>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="1"> <el-radio v-model='radioValue' :value="1">
分钟,允许的通配符[, - * /] 分钟,允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="2"> <el-radio v-model='radioValue' :value="2">
周期从 周期从
<el-input-number v-model='cycle01' :min="0" :max="58" /> - <el-input-number v-model='cycle01' :min="0" :max="58" /> -
<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> 分钟 <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="59" /> 分钟
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="3"> <el-radio v-model='radioValue' :value="3">
<el-input-number v-model='average01' :min="0" :max="58" /> 分钟开始,每 <el-input-number v-model='average01' :min="0" :max="58" /> 分钟开始, 每
<el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 分钟执行一次 <el-input-number v-model='average02' :min="1" :max="59 - average01" /> 分钟执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
<el-form-item>
<el-radio v-model='radioValue' :value="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> </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>
<script> <style lang="scss" scoped>
export default { .el-input-number--small, .el-select, .el-select--small {
data() { margin: 0 0.2rem;
return { }
radioValue: 1, .el-select, .el-select--small {
cycle01: 1, width: 19.8rem;
cycle02: 2,
average01: 0,
average02: 1,
checkboxList: [],
checkNum: this.$options.propsData.check
}
},
name: 'crontab-min',
props: ['check', 'cron'],
methods: {
// 单选按钮值变化时
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'min', '*', 'min');
break;
case 2:
this.$emit('update', 'min', this.cycleTotal, 'min');
break;
case 3:
this.$emit('update', 'min', this.averageTotal, 'min');
break;
case 4:
this.$emit('update', 'min', this.checkboxString, 'min');
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'min', this.cycleTotal, 'min');
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'min', this.averageTotal, 'min');
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'min', this.checkboxString, 'min');
}
},
},
watch: {
'radioValue': 'radioChange',
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'checkboxString': 'checkboxChange',
},
computed: {
// 计算两个周期值
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 58)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 58)
const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
return average01 + '/' + average02;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
} }
</script> </style>
\ No newline at end of file \ No newline at end of file
<template> <template>
<el-form size='small'> <el-form>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="1"> <el-radio v-model='radioValue' :value="1">
月,允许的通配符[, - * /] 月,允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="2"> <el-radio v-model='radioValue' :value="2">
周期从 周期从
<el-input-number v-model='cycle01' :min="1" :max="11" /> - <el-input-number v-model='cycle01' :min="1" :max="11" /> -
<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="12" /> <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="12" />
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="3"> <el-radio v-model='radioValue' :value="3">
<el-input-number v-model='average01' :min="1" :max="11" /> 月开始,每 <el-input-number v-model='average01' :min="1" :max="11" /> 月开始,每
<el-input-number v-model='average02' :min="1" :max="12 - average01 || 0" /> 月月执行一次 <el-input-number v-model='average02' :min="1" :max="12 - average01" /> 月月执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="4"> <el-radio v-model='radioValue' :value="4">
指定 指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%"> <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="8">
<el-option v-for="item in 12" :key="item" :value="item">{{item}}</el-option> <el-option v-for="item in monthList" :key="item.key" :label="item.value" :value="item.key" />
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script> <script setup>
export default { const emit = defineEmits(['update'])
data() { const props = defineProps({
return { cron: {
radioValue: 1, type: Object,
cycle01: 1, default: {
cycle02: 2, second: "*",
average01: 1, min: "*",
average02: 1, hour: "*",
checkboxList: [], day: "*",
checkNum: this.check month: "*",
} week: "?",
}, year: "",
name: 'crontab-month', }
props: ['check', 'cron'], },
methods: { check: {
// 单选按钮值变化时 type: Function,
radioChange() { default: () => {
switch (this.radioValue) { }
case 1: }
this.$emit('update', 'month', '*'); })
break; const radioValue = ref(1)
case 2: const cycle01 = ref(1)
this.$emit('update', 'month', this.cycleTotal); const cycle02 = ref(2)
break; const average01 = ref(1)
case 3: const average02 = ref(1)
this.$emit('update', 'month', this.averageTotal); const checkboxList = ref([])
break; const checkCopy = ref([1])
case 4: const monthList = ref([
this.$emit('update', 'month', this.checkboxString); {key: 1, value: '一月'},
break; {key: 2, value: '二月'},
} {key: 3, value: '三月'},
}, {key: 4, value: '四月'},
// 周期两个值变化时 {key: 5, value: '五月'},
cycleChange() { {key: 6, value: '六月'},
if (this.radioValue == '2') { {key: 7, value: '七月'},
this.$emit('update', 'month', this.cycleTotal); {key: 8, value: '八月'},
} {key: 9, value: '九月'},
}, {key: 10, value: '十月'},
// 平均两个值变化时 {key: 11, value: '十一月'},
averageChange() { {key: 12, value: '十二月'}
if (this.radioValue == '3') { ])
this.$emit('update', 'month', this.averageTotal); const cycleTotal = computed(() => {
} cycle01.value = props.check(cycle01.value, 1, 11)
}, cycle02.value = props.check(cycle02.value, cycle01.value + 1, 12)
// checkbox值变化时 return cycle01.value + '-' + cycle02.value
checkboxChange() { })
if (this.radioValue == '4') { const averageTotal = computed(() => {
this.$emit('update', 'month', this.checkboxString); average01.value = props.check(average01.value, 1, 11)
} average02.value = props.check(average02.value, 1, 12 - average01.value)
} return average01.value + '/' + average02.value
}, })
watch: { const checkboxString = computed(() => {
'radioValue': 'radioChange', return checkboxList.value.join(',')
'cycleTotal': 'cycleChange', })
'averageTotal': 'averageChange', watch(() => props.cron.month, value => changeRadioValue(value))
'checkboxString': 'checkboxChange' watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
}, function changeRadioValue(value) {
computed: { if (value === '*') {
// 计算两个周期值 radioValue.value = 1
cycleTotal: function () { } else if (value.indexOf('-') > -1) {
const cycle01 = this.checkNum(this.cycle01, 1, 11) const indexArr = value.split('-')
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12) cycle01.value = Number(indexArr[0])
return cycle01 + '-' + cycle02; cycle02.value = Number(indexArr[1])
}, radioValue.value = 2
// 计算平均用到的值 } else if (value.indexOf('/') > -1) {
averageTotal: function () { const indexArr = value.split('/')
const average01 = this.checkNum(this.average01, 1, 11) average01.value = Number(indexArr[0])
const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0) average02.value = Number(indexArr[1])
return average01 + '/' + average02; radioValue.value = 3
}, } else {
// 计算勾选的checkbox值合集 checkboxList.value = [...new Set(value.split(',').map(item => Number(item)))]
checkboxString: function () { radioValue.value = 4
let str = this.checkboxList.join(); }
return str == '' ? '*' : str; }
} function onRadioChange() {
} switch (radioValue.value) {
} case 1:
</script> 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>
\ No newline at end of file
<template> <template>
<el-form size="small"> <el-form>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="1"> <el-radio v-model='radioValue' :value="1">
秒,允许的通配符[, - * /] 秒,允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="2"> <el-radio v-model='radioValue' :value="2">
周期从 周期从
<el-input-number v-model='cycle01' :min="0" :max="58" /> - <el-input-number v-model='cycle01' :min="0" :max="58" /> -
<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="59" />
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="3"> <el-radio v-model='radioValue' :value="3">
<el-input-number v-model='average01' :min="0" :max="58" /> 秒开始,每 <el-input-number v-model='average01' :min="0" :max="58" /> 秒开始,每
<el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 秒执行一次 <el-input-number v-model='average02' :min="1" :max="59 - average01" /> 秒执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model='radioValue' :label="4"> <el-radio v-model='radioValue' :value="4">
指定 指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%"> <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option> <el-option v-for="item in 60" :key="item" :label="item - 1" :value="item - 1" />
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script> <script setup>
export default { const emit = defineEmits(['update'])
data() { const props = defineProps({
return { cron: {
radioValue: 1, type: Object,
cycle01: 1, default: {
cycle02: 2, second: "*",
average01: 0, min: "*",
average02: 1, hour: "*",
checkboxList: [], day: "*",
checkNum: this.$options.propsData.check month: "*",
} week: "?",
}, year: "",
name: 'crontab-second', }
props: ['check', 'radioParent'], },
methods: { check: {
// 单选按钮值变化时 type: Function,
radioChange() { default: () => {
switch (this.radioValue) { }
case 1: }
this.$emit('update', 'second', '*', 'second'); })
break; const radioValue = ref(1)
case 2: const cycle01 = ref(0)
this.$emit('update', 'second', this.cycleTotal); const cycle02 = ref(1)
break; const average01 = ref(0)
case 3: const average02 = ref(1)
this.$emit('update', 'second', this.averageTotal); const checkboxList = ref([])
break; const checkCopy = ref([0])
case 4: const cycleTotal = computed(() => {
this.$emit('update', 'second', this.checkboxString); cycle01.value = props.check(cycle01.value, 0, 58)
break; cycle02.value = props.check(cycle02.value, cycle01.value + 1, 59)
} return cycle01.value + '-' + cycle02.value
}, })
// 周期两个值变化时 const averageTotal = computed(() => {
cycleChange() { average01.value = props.check(average01.value, 0, 58)
if (this.radioValue == '2') { average02.value = props.check(average02.value, 1, 59 - average01.value)
this.$emit('update', 'second', this.cycleTotal); return average01.value + '/' + average02.value
} })
}, const checkboxString = computed(() => {
// 平均两个值变化时 return checkboxList.value.join(',')
averageChange() { })
if (this.radioValue == '3') { watch(() => props.cron.second, value => changeRadioValue(value))
this.$emit('update', 'second', this.averageTotal); watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
} function changeRadioValue(value) {
}, if (value === '*') {
// checkbox值变化时 radioValue.value = 1
checkboxChange() { } else if (value.indexOf('-') > -1) {
if (this.radioValue == '4') { const indexArr = value.split('-')
this.$emit('update', 'second', this.checkboxString); cycle01.value = Number(indexArr[0])
} cycle02.value = Number(indexArr[1])
} radioValue.value = 2
}, } else if (value.indexOf('/') > -1) {
watch: { const indexArr = value.split('/')
'radioValue': 'radioChange', average01.value = Number(indexArr[0])
'cycleTotal': 'cycleChange', average02.value = Number(indexArr[1])
'averageTotal': 'averageChange', radioValue.value = 3
'checkboxString': 'checkboxChange', } else {
radioParent() { checkboxList.value = [...new Set(value.split(',').map(item => Number(item)))]
this.radioValue = this.radioParent radioValue.value = 4
} }
}, }
computed: { // 单选按钮值变化时
// 计算两个周期值 function onRadioChange() {
cycleTotal: function () { switch (radioValue.value) {
const cycle01 = this.checkNum(this.cycle01, 0, 58) case 1:
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59) emit('update', 'second', '*', 'second')
return cycle01 + '-' + cycle02; break
}, case 2:
// 计算平均用到的值 emit('update', 'second', cycleTotal.value, 'second')
averageTotal: function () { break
const average01 = this.checkNum(this.average01, 0, 58) case 3:
const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0) emit('update', 'second', averageTotal.value, 'second')
return average01 + '/' + average02; break
}, case 4:
// 计算勾选的checkbox值合集 if (checkboxList.value.length === 0) {
checkboxString: function () { checkboxList.value.push(checkCopy.value[0])
let str = this.checkboxList.join(); } else {
return str == '' ? '*' : str; checkCopy.value = checkboxList.value
} }
} emit('update', 'second', checkboxString.value, 'second')
} break
</script> }
}
</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>
\ No newline at end of file
<template> <template>
<el-form size="small"> <el-form>
<el-form-item> <el-form-item>
<el-radio :label="1" v-model='radioValue'> <el-radio :value="1" v-model='radioValue'>
不填,允许的通配符[, - * /] 不填,允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio :label="2" v-model='radioValue'> <el-radio :value="2" v-model='radioValue'>
每年 每年
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio :label="3" v-model='radioValue'> <el-radio :value="3" v-model='radioValue'>
周期从 周期从
<el-input-number v-model='cycle01' :min='fullYear' :max="2098" /> - <el-input-number v-model='cycle01' :min='fullYear' :max="2098"/> -
<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : fullYear + 1" :max="2099" /> <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : fullYear + 1" :max="2099"/>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio :label="4" v-model='radioValue'> <el-radio :value="4" v-model='radioValue'>
<el-input-number v-model='average01' :min='fullYear' :max="2098"/> 年开始,每 <el-input-number v-model='average01' :min='fullYear' :max="2098"/> 年开始,每
<el-input-number v-model='average02' :min="1" :max="2099 - average01 || fullYear" /> 年执行一次 <el-input-number v-model='average02' :min="1" :max="2099 - average01 || fullYear"/> 年执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio :label="5" v-model='radioValue'> <el-radio :value="5" v-model='radioValue'>
指定 指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple> <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-option v-for="item in 9" :key="item" :value="item - 1 + fullYear" :label="item -1 + fullYear" />
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script> <script setup>
export default { const emit = defineEmits(['update'])
data() { const props = defineProps({
return { cron: {
fullYear: 0, type: Object,
radioValue: 1, default: {
cycle01: 0, second: "*",
cycle02: 0, min: "*",
average01: 0, hour: "*",
average02: 1, day: "*",
checkboxList: [], month: "*",
checkNum: this.$options.propsData.check week: "?",
} year: ""
}, }
name: 'crontab-year', },
props: ['check', 'month', 'cron'], check: {
methods: { type: Function,
// 单选按钮值变化时 default: () => {
radioChange() { }
switch (this.radioValue) { }
case 1: })
this.$emit('update', 'year', ''); const fullYear = ref(0)
break; const maxFullYear = ref(0)
case 2: const radioValue = ref(1)
this.$emit('update', 'year', '*'); const cycle01 = ref(0)
break; const cycle02 = ref(0)
case 3: const average01 = ref(0)
this.$emit('update', 'year', this.cycleTotal); const average02 = ref(1)
break; const checkboxList = ref([])
case 4: const checkCopy = ref([])
this.$emit('update', 'year', this.averageTotal); const cycleTotal = computed(() => {
break; cycle01.value = props.check(cycle01.value, fullYear.value, maxFullYear.value - 1)
case 5: cycle02.value = props.check(cycle02.value, cycle01.value + 1, maxFullYear.value)
this.$emit('update', 'year', this.checkboxString); return cycle01.value + '-' + cycle02.value
break; })
} const averageTotal = computed(() => {
}, average01.value = props.check(average01.value, fullYear.value, maxFullYear.value - 1)
// 周期两个值变化时 average02.value = props.check(average02.value, 1, 10)
cycleChange() { return average01.value + '/' + average02.value
if (this.radioValue == '3') { })
this.$emit('update', 'year', this.cycleTotal); const checkboxString = computed(() => {
} return checkboxList.value.join(',')
}, })
// 平均两个值变化时 watch(() => props.cron.year, value => changeRadioValue(value))
averageChange() { watch([radioValue, cycleTotal, averageTotal, checkboxString], () => onRadioChange())
if (this.radioValue == '4') { function changeRadioValue(value) {
this.$emit('update', 'year', this.averageTotal); if (value === '') {
} radioValue.value = 1
}, } else if (value === "*") {
// checkbox值变化时 radioValue.value = 2
checkboxChange() { } else if (value.indexOf("-") > -1) {
if (this.radioValue == '5') { const indexArr = value.split('-')
this.$emit('update', 'year', this.checkboxString); cycle01.value = Number(indexArr[0])
} cycle02.value = Number(indexArr[1])
} radioValue.value = 3
}, } else if (value.indexOf("/") > -1) {
watch: { const indexArr = value.split('/')
'radioValue': 'radioChange', average01.value = Number(indexArr[1])
'cycleTotal': 'cycleChange', average02.value = Number(indexArr[0])
'averageTotal': 'averageChange', radioValue.value = 4
'checkboxString': 'checkboxChange' } else {
}, checkboxList.value = [...new Set(value.split(',').map(item => Number(item)))]
computed: { radioValue.value = 5
// 计算两个周期值 }
cycleTotal: function () { }
const cycle01 = this.checkNum(this.cycle01, this.fullYear, 2098) function onRadioChange() {
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : this.fullYear + 1, 2099) switch (radioValue.value) {
return cycle01 + '-' + cycle02; case 1:
}, emit('update', 'year', '', 'year')
// 计算平均用到的值 break
averageTotal: function () { case 2:
const average01 = this.checkNum(this.average01, this.fullYear, 2098) emit('update', 'year', '*', 'year')
const average02 = this.checkNum(this.average02, 1, 2099 - average01 || this.fullYear) break
return average01 + '/' + average02; case 3:
}, emit('update', 'year', cycleTotal.value, 'year')
// 计算勾选的checkbox值合集 break
checkboxString: function () { case 4:
let str = this.checkboxList.join(); emit('update', 'year', averageTotal.value, 'year')
return str; break
} case 5:
}, if (checkboxList.value.length === 0) {
mounted: function () { checkboxList.value.push(checkCopy.value[0])
// 仅获取当前年份 } else {
this.fullYear = Number(new Date().getFullYear()); checkCopy.value = checkboxList.value
this.cycle01 = this.fullYear }
this.average01 = this.fullYear emit('update', 'year', checkboxString.value, 'year')
} break
} }
</script> }
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>
\ No newline at end of file
import Vue from 'vue'
import store from '@/store'
import DataDict from '@/utils/dict'
import { getDicts as getDicts } from '@/api/system/dict/data'
function searchDictByKey(dict, key) {
if (key == null && key == "") {
return null
}
try {
for (let i = 0; i < dict.length; i++) {
if (dict[i].key == key) {
return dict[i].value
}
}
} catch (e) {
return null
}
}
function install() {
Vue.use(DataDict, {
metas: {
'*': {
labelField: 'dictLabel',
valueField: 'dictValue',
request(dictMeta) {
const storeDict = searchDictByKey(store.getters.dict, dictMeta.type)
if (storeDict) {
return new Promise(resolve => { resolve(storeDict) })
} else {
return new Promise((resolve, reject) => {
getDicts(dictMeta.type).then(res => {
store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data })
resolve(res.data)
}).catch(error => {
reject(error)
})
})
}
},
},
},
})
}
export default {
install,
}
\ No newline at end of file
<template> <template>
<div> <div>
<template v-for="(item, index) in options"> <template v-for="(item, index) in options">
<template v-if="values.includes(item.value)"> <template v-if="values.includes(item.value)">
<span <span
v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)" v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)"
:key="item.value" :key="item.value"
:index="index" :index="index"
:class="item.raw.cssClass" :class="item.elTagClass"
>{{ item.label + ' ' }}</span >{{ item.label + " " }}</span>
> <el-tag
<el-tag v-else
v-else :disable-transitions="true"
:disable-transitions="true" :key="item.value + ''"
:key="item.value" :index="index"
:index="index" :type="item.elTagType"
:type="item.raw.listClass == 'primary' ? '' : item.raw.listClass" :class="item.elTagClass"
:class="item.raw.cssClass" >{{ item.label + " " }}</el-tag>
> </template>
{{ item.label + ' ' }} </template>
</el-tag> <template v-if="unmatch && showValue">
</template> {{ unmatchArray | handleArray }}
</template> </template>
<template v-if="unmatch && showValue"> </div>
{{ unmatchArray | handleArray }} </template>
</template>
</div> <script setup>
</template> // 记录未匹配的项
const unmatchArray = ref([]);
<script>
export default { const props = defineProps({
name: "DictTag", // 数据
props: { options: {
options: { type: Array,
type: Array, default: null,
default: null, },
}, // 当前的值
value: [Number, String, Array], value: [Number, String, Array],
// 当未找到匹配的数据时,显示value // 当未找到匹配的数据时,显示value
showValue: { showValue: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
separator: { separator: {
type: String, type: String,
default: "," default: ",",
} }
}, });
data() {
return { const values = computed(() => {
unmatchArray: [], // 记录未匹配的项 if (props.value === null || typeof props.value === 'undefined' || props.value === '') return [];
} return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator);
}, });
computed: {
values() { const unmatch = computed(() => {
if (this.value === null || typeof this.value === 'undefined' || this.value === '') return [] unmatchArray.value = [];
return Array.isArray(this.value) ? this.value.map(item => '' + item) : String(this.value).split(this.separator) // 没有value不显示
}, if (props.value === null || typeof props.value === 'undefined' || props.value === '' || !Array.isArray(props.options) || props.options.length === 0) return false
unmatch() { // 传入值为数组
this.unmatchArray = [] let unmatch = false // 添加一个标志来判断是否有未匹配项
// 没有value不显示 values.value.forEach(item => {
if (this.value === null || typeof this.value === 'undefined' || this.value === '' || this.options.length === 0) return false if (!props.options.some(v => v.value === item)) {
// 传入值为数组 unmatchArray.value.push(item)
let unmatch = false // 添加一个标志来判断是否有未匹配项 unmatch = true // 如果有未匹配项,将标志设置为true
this.values.forEach(item => { }
if (!this.options.some(v => v.value === item)) { })
this.unmatchArray.push(item) return unmatch // 返回标志的值
unmatch = true // 如果有未匹配项,将标志设置为true });
}
}) function handleArray(array) {
return unmatch // 返回标志的值 if (array.length === 0) return "";
}, return array.reduce((pre, cur) => {
return pre + " " + cur;
}, });
filters: { }
handleArray(array) { </script>
if (array.length === 0) return '';
return array.reduce((pre, cur) => { <style scoped>
return pre + ' ' + cur; .el-tag + .el-tag {
}) margin-left: 10px;
}, }
} </style>
};
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论