Compare commits

..

236 Commits

Author SHA1 Message Date
Jiangjie.Bai
776090d6ba Merge pull request #2001 from jumpserver/dev
v2.25.0
2022-08-18 16:12:45 +08:00
feng626
2c66bec7c9 Merge pull request #2000 from jumpserver/pr@dev@ticket_translate
fix: 修复工单翻译
2022-08-18 15:10:45 +08:00
feng626
b10f7faf25 fix: 修复工单翻译 2022-08-18 15:09:26 +08:00
feng626
450014ab16 Merge pull request #1999 from jumpserver/pr@dev@batch_command_filter
perf: 批量命令搜索优化
2022-08-18 11:48:22 +08:00
feng626
8ad0d2ac58 perf: 批量命令搜索优化 2022-08-18 11:44:45 +08:00
Jiangjie.Bai
bd41f96df3 fix: 修复属性映射字段值不显示的问题 2022-08-18 11:01:13 +08:00
Jiangjie.Bai
3a37952288 Merge pull request #1996 from jumpserver/dev
v2.25.0-rc4
2022-08-17 16:53:23 +08:00
Jiangjie.Bai
5346eb1ef1 fix: 修复云同步 lan attrs ip_group 必填项问题,gcp 上传文件不显示问题 2022-08-17 16:46:32 +08:00
Jiangjie.Bai
62b8fc0e3b Merge pull request #1994 from jumpserver/dev
v2.25.0-rc3
2022-08-16 19:08:23 +08:00
“huailei000”
f532d624e0 fix: 字段设置为必填项 2022-08-16 16:31:13 +08:00
“huailei000”
4ce6f49b30 fix: 修复应用授权远程应用以外的类型不显示字段说明 2022-08-16 15:55:19 +08:00
Jiangjie.Bai
2fb160b5f7 fix: 修改表单默认值的设置,gcp 的 attrs 字段中是 child 不是 children 2022-08-16 15:53:25 +08:00
“huailei000”
4ed9fb2acc fix: 取消树搜索input自动提示最近输入 2022-08-16 14:25:54 +08:00
“huailei000”
722fc083cb perf: 替换资产树title 2022-08-16 12:24:35 +08:00
Jiangjie.Bai
4356b79ecc perf: 优化 attrs 字段 default 值的返回 2022-08-15 16:23:13 +08:00
feng626
5eff817b05 Merge pull request #1987 from jumpserver/pr@dev@update_TICKET_AUTHORIZE_DEFAULT_TIME
fix: 配置工单授权时间后更新vuex
2022-08-15 11:28:12 +08:00
feng626
4f08fef25a fix: 配置工单授权时间后更新vuex 2022-08-15 11:27:13 +08:00
Jiangjie.Bai
b2028869cb Merge pull request #1986 from jumpserver/dev
v2.25.0-rc2
2022-08-12 18:06:56 +08:00
feng626
325f21f8b5 Merge pull request #1985 from jumpserver/fix_tree_search_url
fix: 资产树默认关闭搜索;调整搜索url携带的参数
2022-08-12 16:53:33 +08:00
“huailei000”
802d6f6cd3 fix: 资产树默认关闭搜索;调整搜索url携带的参数 2022-08-12 16:49:47 +08:00
feng626
f2120521d6 Merge pull request #1984 from jumpserver/pr@dev@ticket_flow
fix: 还原工单流逻辑
2022-08-12 14:27:02 +08:00
feng626
cbdeea9be7 fix: 还原工单流逻辑 2022-08-12 14:21:53 +08:00
“huailei000”
8d2d38327a fix: 添加正则过滤表情符号方法;修复创建云同步名称能输入表情符号问题 2022-08-12 11:33:22 +08:00
“huailei000”
5c564c42dc fix: 修复资产树右键不显示菜单问题 2022-08-12 11:33:00 +08:00
feng626
0c47f8f962 Merge pull request #1981 from jumpserver/pr@dev@ticket_flow
fix:  全局组织下不能修改工单流
2022-08-12 10:44:12 +08:00
feng626
65d625ad3c fix: 全局组织下不能修改工单流 2022-08-12 10:43:20 +08:00
feng626
0e65b7f1be Merge pull request #1979 from jumpserver/pr@dev@actions
fix: 修复授权动作不展示
2022-08-11 18:05:27 +08:00
feng626
22cfaf8665 fix: 修复授权动作不展示 2022-08-11 18:03:30 +08:00
feng626
b3670fe528 fix: 修复系统工具切换时 清空终端信息 2022-08-11 16:26:19 +08:00
Jiangjie.Bai
2f80b66b07 perf: 云同步 LAN 添加测试超时时间选项 2022-08-11 16:25:54 +08:00
Jiangjie.Bai
5277a725f8 Merge pull request #1973 from jumpserver/dev
v2.25.0-rc1
2022-08-11 14:11:59 +08:00
“huailei000”
b400c13965 perf: 优化资产树搜索等待时间 2022-08-11 14:11:29 +08:00
fit2bot
c71f0c17fc feat: 添加树的title显示模块 (#1975)
* feat: 树组件增加搜索功能

* feat: 添加插入节点

* feat: zTree组件增加搜索功能配置、创建根节点配置

* feat: 添加树的title显示模块

Co-authored-by: “huailei000” <2280131253@qq.com>
2022-08-11 13:43:08 +08:00
fit2bot
a952477c3b fix: 修复创建应用工单action (#1971)
* fix: 修复创建应用工单action

* 调整结构

Co-authored-by: feng626 <1304903146@qq.com>
2022-08-10 19:36:22 +08:00
feng626
1153a3b38b fix: 修复翻译 2022-08-10 11:01:56 +08:00
fit2bot
2e69cd86aa feat: 系统工具Ping和Telnet (#1961)
Co-authored-by: halo <wuyihuangw@gmail.com>
Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com>
2022-08-09 17:55:14 +08:00
jiangweidong
a5ea6360bd perf: 优化测试按钮交互 2022-08-09 16:10:39 +08:00
jiangweidong
0639b139d7 feat: 支持CMPPv2.0协议短信网关 2022-08-09 16:10:39 +08:00
ibuler
a8867dee83 perf: aes key 强制最大 16 2022-08-05 14:55:00 +08:00
Jiangjie.Bai
c4d0462362 feat: Cloud 支持局域网 IP 扫描 2022-08-05 14:38:23 +08:00
“huailei000”
db97240ad3 perf: 调整导航栏对齐;替换站内信图标 2022-08-04 14:46:52 +08:00
jiangweidong
5b6f06ac0e feat: 认证方式支持OAuth2.0协议 (#1963)
* feat: 认证方式支持OAuth2.0协议

* 增加scope参数

* perf: 优化 OAuth2 认证逻辑和Logo,支持上传图标

* perf: 优化 OAuth2 认证逻辑和Logo,支持上传图标

Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2022-08-04 14:41:20 +08:00
“huailei000”
51de827c2b fix: 修复浏览器控制台提示icons提示告警问题 2022-08-03 14:24:55 +08:00
ibuler
49566cdae7 perf: 修改头像 2022-08-03 14:24:37 +08:00
“huailei000”
b6786687b6 fix: 修复修改个人信息后点击tip链接跳转失败问题 2022-08-03 14:24:06 +08:00
feng626
c83abe32c6 Merge pull request #1960 from jumpserver/pr@dev@ticket_app_add_action
feat: 应用工单支持选择动作
2022-07-22 16:25:10 +08:00
feng626
1b19e0201d feat: 应用工单支持选择动作 2022-07-22 16:20:48 +08:00
feng626
7681250fff Merge pull request #1959 from jumpserver/pr@dev@ticket_perm_default_time
feat: 添加默认工单授权时间
2022-07-22 15:23:02 +08:00
feng626
9fe4e0b613 feat: 添加默认工单授权时间 2022-07-22 15:21:22 +08:00
Jiangjie.Bai
f137788c1a Merge pull request #1957 from jumpserver/dev
v2.24.0-rc5
2022-07-20 19:06:03 +08:00
“huailei000”
2f09c3f355 fix: 修复会话记录跳转链接颜色问题 2022-07-20 15:03:28 +08:00
“huailei000”
ea047e01d1 fix: 修复element-button类型为danger&plain的颜色问题 2022-07-20 15:02:59 +08:00
Jiangjie.Bai
f7d17c8de7 Merge pull request #1954 from jumpserver/dev
v2.24.0-rc4
2022-07-19 16:18:13 +08:00
“huailei000”
86ead72858 fix: 创建工单-切换组织时清空节点、资产、系统用户 2022-07-19 16:17:53 +08:00
ibuler
48b22edace perf: 修改 org 变量名称 2022-07-19 15:59:10 +08:00
ibuler
ea682a2aaa perf: 优化 dialog footer padding 2022-07-19 15:39:29 +08:00
fit2bot
8b499d8f7f pref: 优化体验 (#1952)
* perf: 修改 padding

* pref: 优化体验

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-19 15:14:45 +08:00
“huailei000”
25c04e9c05 fix: 修复下拉选中项鼠标hover颜色问题 2022-07-19 15:10:44 +08:00
huangzhiwen
5dca562a12 fix: 修改动作选择为默认全展开 2022-07-19 14:58:18 +08:00
“huailei000”
7701bc9b67 fix: 修复从审批工单进入资产授权点击更新后获取不到数据问题 2022-07-18 17:17:30 +08:00
“huailei000”
157bc08f84 fix: 修复右键资产树后点击切换到其他组织不生效问题 2022-07-18 15:15:17 +08:00
Jiangjie.Bai
feea70b0be Merge pull request #1944 from jumpserver/dev
v2.24.0-rc3
2022-07-18 12:05:42 +08:00
“huailei000”
7921f1f9e5 fix: 修复element-ui 字体图标加载不出来问题 2022-07-18 10:59:06 +08:00
“huailei000”
a7252d16d1 fix: 修复element-ui字体图标加载失败问题 2022-07-17 11:20:20 +08:00
Jiangjie.Bai
04696ef3d6 Merge pull request #1940 from jumpserver/dev
v2.24.0-rc2
2022-07-15 18:07:37 +08:00
feng626
cdde3799af Merge pull request #1939 from jumpserver/pr@dev@confirm_css
fix: confirm css
2022-07-15 16:55:40 +08:00
feng626
f0b987ed54 fix: confirm css 2022-07-15 16:55:01 +08:00
jiangweidong
af60fdabda perf: 优化测试邮箱连接等功能时,交互界面优化,显示loading 2022-07-15 14:57:06 +08:00
“huailei000”
af0d6202bb perf: 优化首屏加载速度 2022-07-15 14:19:15 +08:00
feng626
c1e3c23523 Merge pull request #1937 from jumpserver/pr@dev@ticket_org
fix: 修复工单选择资源组织问题
2022-07-15 11:42:17 +08:00
feng626
7232706a7f fix: 修复工单选择资源组织问题 2022-07-15 11:41:06 +08:00
“huailei000”
dd2b76473f fix: 修复站内信链接颜色 2022-07-15 11:07:52 +08:00
“huailei000”
b41c3ac687 fix: 修复默认主题颜色配置不全问题 2022-07-15 11:01:08 +08:00
Jiangjie.Bai
1731f4f788 Merge pull request #1934 from jumpserver/dev
v2.24.0-rc1
2022-07-14 18:27:51 +08:00
feng626
fa74dad83d fix: vuex add notRootWorkbenchOrgs 2022-07-14 18:11:21 +08:00
Jiangjie.Bai
6f25d93909 Merge pull request #1931 from jumpserver/dev
v2.24.0-rc1
2022-07-14 17:51:58 +08:00
feng626
06a09b90e2 Merge pull request #1932 from jumpserver/pr@dev@ticket_title_css
fix: 修改创建更新工单 标题的css
2022-07-14 16:39:46 +08:00
feng626
3c9767b791 fix: 修改创建更新工单 标题的css 2022-07-14 16:38:17 +08:00
Jiangjie.Bai
da66f5e123 perf: 优化命令过滤器页面说明文案 2022-07-14 15:30:59 +08:00
feng626
e4f33cce14 Merge pull request #1928 from jumpserver/pr@dev@ticket_default_org
fix: ticket del global org
2022-07-14 15:14:50 +08:00
feng626
a5b374e524 fix: ticket del global org 2022-07-14 15:13:02 +08:00
Jiangjie.Bai
46461ec324 Merge pull request #1925 from jumpserver/dev
v2.24.0-rc1
2022-07-14 15:12:15 +08:00
Jiangjie.Bai
0dfcf42635 Merge pull request #1927 from jumpserver/pr@dev@fix_mergemaster
fix: merge dev
2022-07-14 15:11:42 +08:00
Jiangjie.Bai
0aa42bc72a fix: merge dev 2022-07-14 15:10:26 +08:00
fit2bot
cbf76c17d5 pref: 系统用户有 key 后,更新显示指纹 (#1906)
Co-authored-by: ibuler <ibuler@qq.com>
2022-07-14 14:54:55 +08:00
“huailei000”
216a2df6da perf:优化默认主题文件格式 2022-07-14 14:53:36 +08:00
“huailei000”
0b2db0615e fix: 系统用户-telnet协议用户名设置为非必填 2022-07-14 14:47:22 +08:00
“huailei000”
3544fe5bfa fix: 修复无痕模式下其他组织创建新用户登录没有权限问题 2022-07-14 14:42:55 +08:00
feng626
2cd30fc9d8 Merge pull request #1921 from jumpserver/pr@dev@del_history_account
perf: 暂时禁用账号历史
2022-07-14 10:40:45 +08:00
feng626
71bbe7b0c5 perf: 暂时禁用账号历史 2022-07-14 10:38:51 +08:00
feng626
29f1523113 Merge pull request #1919 from jumpserver/pr@dev@audit_command_filter
perf: 批量命令添加搜索项
2022-07-13 17:34:24 +08:00
feng626
6b5981e3af perf: 批量命令添加搜索项 2022-07-13 17:33:13 +08:00
Jiangjie.Bai
273a6cbb3b feat: Endpoint 支持 oracle 版本 2022-07-13 16:32:01 +08:00
feng626
6c78f04d12 Merge pull request #1731 from jumpserver/pr@dev@ticket
fix: 工单 bug
2022-07-13 15:50:08 +08:00
feng626
1b86b4e4cd fix: ticket bug 2022-07-13 15:47:36 +08:00
“huailei000”
94d3560410 fix:资产授权-资产节点列表默认显示资产 2022-07-13 14:03:47 +08:00
“huailei000”
897749547d fix: 修复资产账号连续点击查看不触发问题 2022-07-13 14:03:06 +08:00
ibuler
6fb34451d9 perf: 修改主题 btn 颜色 2022-07-13 11:13:23 +08:00
ibuler
3fba41b27b perf: 优化配色 2022-07-13 10:03:11 +08:00
Jiangjie.Bai
6c5f991494 fix: 修改连接令牌 is_valid 字段 2022-07-12 18:33:58 +08:00
ibuler
e80499b7b4 fix: 修复普通用户登录默认 404
perf: 添加注释
2022-07-12 17:12:03 +08:00
feng626
732788ac72 Merge pull request #1905 from jumpserver/pr@dev@confirm
fix: oauth bind confirm url
2022-07-12 16:02:57 +08:00
feng626
5a63cd253d fix: oauth bind confirm url 2022-07-12 15:59:58 +08:00
feng626
bc17b5c504 feat: 工单支持审批时修改资产 2022-07-12 15:29:27 +08:00
feng626
5dfcfd7b71 Merge pull request #1904 from jumpserver/pr@dev@perf_colors
fix: theme colors default
2022-07-12 14:56:21 +08:00
feng626
39766553fa fix: theme colors default 2022-07-12 14:55:02 +08:00
ibuler
b6be60c584 perf: 优化 theme color 2022-07-12 14:15:45 +08:00
fit2bot
a6d9bd1ab3 perf: 优化 btn 颜色 (#1902)
* perf: 修改 theme

* perf: 优化 btn 颜色

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-12 13:43:33 +08:00
ibuler
940a3c50f3 perf: 修改 theme 2022-07-12 13:28:28 +08:00
ibuler
ca45f61c2c perf: remove unused css 2022-07-12 10:29:05 +08:00
fit2bot
7644bffe12 feat: 添加连接令牌页面 (#1891)
* feat: 修改 API Key action 启停->启用/禁用

* feat: 添加连接令牌页面

* feat: 添加连接令牌页面

* feat: 修改敏感字段组件

* feat: 添加help text

Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2022-07-11 19:38:56 +08:00
feng626
ba1923cd21 Merge pull request #1899 from jumpserver/pr@dev@yarn_lock
perf: update yarn lock
2022-07-11 18:23:21 +08:00
feng626
e0dc7ab451 perf: update yarn lock 2022-07-11 18:21:57 +08:00
“huailei000”
3a1f0b6d38 fix: 修复info类型button的样式特殊处理 2022-07-11 18:19:52 +08:00
“huailei000”
13b91a541c fix: 修复el-link边框颜色 2022-07-11 17:06:59 +08:00
“huailei000”
0cd96e1d82 fix: 修复混合颜色方法判断错误问题 2022-07-11 15:55:51 +08:00
ibuler
efe6247dbc perf: 修改 theme color 2022-07-11 15:17:34 +08:00
ibuler
b8b7c73bb1 perf: 修改主题 2022-07-11 11:18:23 +08:00
“huailei000”
3b1ea689d1 perf: 删除没有引用的主题文件 2022-07-11 11:16:35 +08:00
“huailei000”
c5a611af06 perf: 修改淘宝镜像新域名 2022-07-11 11:09:25 +08:00
ibuler
ef41dc809c perf: 修改 demo 2022-07-08 15:38:42 +08:00
“huailei000”
bc0ca617a1 fix: 修复修改密码组件颜色随主题色变化 2022-07-08 15:38:11 +08:00
“huailei000”
d25620ecfe fix: 修复element-ui,link标签hover状态的颜色 2022-07-08 15:37:45 +08:00
“huailei000”
bc9d0aeeb3 fix: 修复工单查看受理人翻译问题、颜色问题;修复button focus状态下颜色问题 2022-07-08 13:34:54 +08:00
“huailei000”
bbd2951496 fix: 修复命令存储默认初始值不准确问题 2022-07-08 11:19:58 +08:00
“huailei000”
0d80eca595 feat: 添加主题预览功能 2022-07-07 19:43:03 +08:00
fit2bot
d8cf5ad553 perf: 修改一些名字 (#1882)
* perf: 修改一些名字

* perf: 修改 colors

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-07 18:34:15 +08:00
“huailei000”
ec9b8f0005 perf: 优化修改主题相关方法传参 2022-07-07 18:07:38 +08:00
feng626
d98c961fd8 Merge pull request #1880 from jumpserver/pr@dev@confirm
fix: 调整confirm
2022-07-07 17:07:28 +08:00
feng626
639122aeca fix: 调整confirm 2022-07-07 17:04:54 +08:00
“huailei000”
45852eb4b9 fix: 修复修改主题颜色以后button hover颜色不一致问题 2022-07-07 15:03:15 +08:00
“huailei000”
24e716df5d fix: 修复修改主题颜色后提交保存页面刷新不生效问题 2022-07-07 12:55:24 +08:00
dependabot[bot]
fbda43b9dd build(deps): bump shell-quote from 1.7.2 to 1.7.3
Bumps [shell-quote](https://github.com/substack/node-shell-quote) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/substack/node-shell-quote/releases)
- [Changelog](https://github.com/substack/node-shell-quote/blob/master/CHANGELOG.md)
- [Commits](https://github.com/substack/node-shell-quote/compare/v1.7.2...1.7.3)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-07 09:35:02 +08:00
“huailei000”
e5f18fa2bb perf: 去掉预览效果 2022-07-06 20:02:42 +08:00
“huailei000”
a3e97cb039 fix: 修复菜单颜色不变化问题 2022-07-06 19:50:28 +08:00
fit2bot
f4292796fc perf: 优化配色 (#1871)
* perf: 优化配色

* perf: 修改 interface

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-06 19:45:44 +08:00
“huailei000”
bc991fe762 perf: 调整主题配置文件结构 2022-07-06 19:43:18 +08:00
“huailei000”
3de65f9a5b fix: 修复仪表盘不随主题颜色变化问题;修复SAML2-link标签颜色;修复select-down显示颜色 2022-07-06 17:49:38 +08:00
“huailei000”
000c8da6ae perf: 优化主题配置文件对象写法 2022-07-06 15:03:48 +08:00
ibuler
bc253c26b9 perf: 修改 css 名称 2022-07-06 11:01:13 +08:00
“huailei000”
abc3738309 perf: 优化css文件命名;删除没用css文件;解决设置主题保存也生效问题 2022-07-06 10:50:01 +08:00
ibuler
c305ca2e22 pref: 还原高度 2022-07-05 20:17:53 +08:00
“huailei000”
6618afc72f fix: 修复倒入组件报错问题 2022-07-05 20:17:17 +08:00
huailei
ab4b4d5230 Feat addtheme (#1864)
* feat: 删除没用的css文件

* feat: 添加修改主题组件

* feat: 设置全局css变量

* feat: 替换修改主题方法

* perf: 修改 bg color

* perf: 修改 left bar css

* perf: 修改 element

* perf: 暂存与喜爱

* feat: 添加颜色转换方法

* perf: 修改一些

* perf: 修改颜色

* feat: 修改默认elemet-ui样式

* feat: 暂存

* feat: 添加切换菜单栏颜色方法

* feat: 调整配置颜色

* feat: 调整主题相关配色
1、修复弹窗出现黑屏问题
2、修复左侧菜单展开、折叠出现白色闪动问题
3、迁移element-ui.scss文件内容到extra.css文件里

* feat: 调整styles下文件结构;升级sass插件修复构建提示语法错误问题

* feat: 拆分主题配置文件;添加设置到基本设置里

* feat: 修复public-fonts目录下文件内容

* fix: 解决冲突

* feat: 修改颜色配置

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-05 20:06:28 +08:00
fit2bot
be842a3e3a perf: 修改颜色 (#1862)
* perf: 修改颜色

* perf: 优化主题

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-05 17:35:05 +08:00
fit2bot
114704f668 perf: 优化主题配色 (#1859)
* perf: 优化主题配色

* perf: 修改主题

* perf: 修改更新 theme

* perf: 修改主题

* perf: 修改 avart

* perf: css

* perf: css

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-05 14:31:50 +08:00
fit2bot
5f8b3f1986 feat: 账号历史信息 (#1841)
* perf: 账号历史信息

* del app

Co-authored-by: feng626 <1304903146@qq.com>
2022-07-04 18:55:46 +08:00
“huailei000”
4b376b65b3 fix: 修复当前用户加入组织后创建工单不显示加入的组织问题 2022-07-04 11:27:54 +08:00
feng626
f5c7abcbd8 perf: confirm 优化 2022-07-04 11:24:25 +08:00
Jiangjie.Bai
bb91fbb327 perf: 会话列表显示终端名称; 2022-07-04 11:22:30 +08:00
fit2bot
c3cc54a2d2 perf: 简单修改配色 (#1857)
* perf: 简单修改配色

* perf: 吸怪透明度

* perf: 默认红色

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-01 16:12:36 +08:00
fit2bot
109b40f3b2 perf: 修改 css (#1856)
* perf: 修改 css

* perf: 菜单颜色

* perf: 修改主题

* perf: 统一颜色 css

* perf: 修改 css

* perf: 修改 css

Co-authored-by: ibuler <ibuler@qq.com>
2022-07-01 15:15:17 +08:00
Jiangjie.Bai
47a3005b6a perf: 创建更新用户和用户列表添加 is_active 字段 2022-06-30 18:28:35 +08:00
ibuler
7c6530d9e8 perf: 修改统一 css 2022-06-30 18:28:17 +08:00
ibuler
8e57d76713 perf: 整理 css 2022-06-30 18:28:17 +08:00
ibuler
8f6c9af3fb perf: 修改主题 2022-06-30 13:07:22 +08:00
ibuler
2719925f8b perf: remove duplicate css 2022-06-30 13:07:22 +08:00
feng626
51c7a3e8cc Merge pull request #1852 from jumpserver/pr@dev@ticket_bug
fix: 修复工单命令复合显示bug
2022-06-30 11:17:46 +08:00
feng626
0946fedce2 fix: 修复工单命令复合显示bug 2022-06-30 11:16:16 +08:00
Jiangjie.Bai
8b11146e44 feat: Endpoint 添加帮助信息 2022-06-29 18:51:05 +08:00
“huailei000”
263ab8c913 fix: 修复进入工单流程设置详情页,页面布局出现遮挡问题 2022-06-29 10:51:43 +08:00
“huailei000”
33b8e7a21b perf: 修复工单-创建应用授权error提示方式 2022-06-29 10:49:21 +08:00
“huailei000”
ccecaf7aae fix: 修复工单页面刷新会返回到工作台问题 2022-06-28 18:14:19 +08:00
feng626
fc8d9b4509 Merge pull request #1844 from jumpserver/pr@dev@fix_ticket_bug
fix: 解决一些工单已知问题
2022-06-28 17:19:54 +08:00
feng626
25999801d5 fix: 解决一些工单已知问题 2022-06-28 17:15:02 +08:00
“huailei000”
763c8338ef fix: 修复终端管理操作不显示问题 2022-06-28 16:32:49 +08:00
“huailei000”
340516297b fix: 修复密码过期组件变量没找到报错问题 2022-06-28 15:55:42 +08:00
ibuler
069ba9cfc4 perf: 修改 msg 2022-06-23 17:28:11 +08:00
ibuler
4c88a331d5 perf: 修改 license 提示 2022-06-23 17:28:11 +08:00
“huailei000”
d7016c5de2 perf: 优化左侧菜单折叠后title修改为显示图标 2022-06-23 15:54:41 +08:00
feng626
3d41215a63 Merge pull request #1780 from jumpserver/pr@dev@refactor_tickiets
perf: 工单重构
2022-06-23 14:38:44 +08:00
feng626
57e5452220 优化一波 2022-06-23 14:31:06 +08:00
“huailei000”
cc94eb6d4e perf: 优化帮助文案 2022-06-22 16:40:51 +08:00
“huailei000”
0b82947e8f fix: 修复左侧菜单英文翻译问题 2022-06-22 16:22:10 +08:00
ibuler
e4507e35fd perf: 优化站内信布局 2022-06-21 14:27:16 +08:00
“huailei000”
40fd62cd2b fix: 修改在更新页面下切换组织,点击浏览器后退操作接口500问题 2022-06-17 19:00:21 +08:00
ibuler
5e8c1b4881 pref: 优化添加批量删除 2022-06-17 18:20:03 +08:00
ibuler
5f984ecbe6 perf: 修改移动设备下的表现 2022-06-17 18:19:30 +08:00
feng626
111d3d56e2 perf: 优化confirm 重新登录翻译 2022-06-16 18:47:37 +08:00
feng626
91c6a4d6b2 perf: 优化confirm 重新登录翻译 2022-06-16 18:32:14 +08:00
Jiangjie.Bai
58ab7139d6 Merge pull request #1817 from jumpserver/dev
v2.23.0 rc6
2022-06-16 18:13:04 +08:00
“huailei000”
81d8cd971c fix: 切换视图提示信息判断移动端不显示 2022-06-16 18:11:20 +08:00
ibuler
ea3e26b92c perf: 修改移动端 table 2022-06-16 18:09:26 +08:00
feng626
a076a277c9 fix: confirm bug 2022-06-16 18:08:40 +08:00
feng626
3c9a3b693b 修啊修 2022-06-16 17:53:50 +08:00
Jiangjie.Bai
79f6bea423 perf: 优化会话加入记录结束状态显示 2022-06-16 16:42:08 +08:00
Jiangjie.Bai
ea8af7deb3 Merge pull request #1810 from jumpserver/dev
v2.23.0 rc5
2022-06-16 15:53:41 +08:00
ibuler
fcfd26c58f perf: 优化 icon 2022-06-16 15:47:49 +08:00
“huailei000”
a6c1e16339 fix: 修复资产列表右击资产搜索框出现空白tag问题 2022-06-16 15:45:08 +08:00
“huailei000”
c899b209d7 fix: 修复全局组织下不能创建判断;平台列表全局组织可以创建、克隆判断 2022-06-16 14:50:34 +08:00
“huailei000”
bba8f8a9a0 fix: 修复终端管理-翻译问题 2022-06-16 14:50:18 +08:00
“huailei000”
d1b620956e perf: 帮助下拉内容与luna保持一致 2022-06-16 14:15:54 +08:00
Jiangjie.Bai
f260979a11 fix: 修复创建、更新用户时need_update_password字段样式 2022-06-16 13:56:34 +08:00
feng626
f3bc6bdd46 Merge pull request #1804 from jumpserver/pr@dev@confirm_bug
fix: confirm bug
2022-06-16 12:44:03 +08:00
feng626
7fe91756c9 fix: confirm bug 2022-06-16 12:39:41 +08:00
feng626
0fa05aaeb4 Merge pull request #1803 from jumpserver/pr@dev@confirm_input_perf
perf: user confirm input
2022-06-16 12:32:02 +08:00
feng626
2183e6bc89 perf: user confirm input 2022-06-16 12:31:03 +08:00
Jiangjie.Bai
1ecc57b21b Merge pull request #1797 from jumpserver/dev
v2.23.0 rc4
2022-06-15 19:35:36 +08:00
feng626
76085f42c5 fix: 修复profile更新 会取消三方绑定账号问题 2022-06-15 19:31:33 +08:00
“huailei000”
ba0a425359 fix: 修复全局组织下克隆权限判断 2022-06-15 19:31:16 +08:00
feng626
c18f712b84 修改一点 2022-06-15 18:59:00 +08:00
“huailei000”
6815d3be13 fix: 修复资产列表自定义搜索显示true问题 2022-06-15 17:46:52 +08:00
ibuler
385e654fbe perf: 搜索下拉 ID 2022-06-15 16:34:08 +08:00
“huailei000”
09010e4e94 fix: 修复创建用户表单翻译问题 2022-06-15 15:36:12 +08:00
ibuler
f347833ea8 perf: 优化 license 报错 2022-06-15 15:35:18 +08:00
“huailei000”
ae9c5c389d fix: 修复任务列表-删除任务名称不一样问题 2022-06-15 15:31:16 +08:00
Jiangjie.Bai
15a53c4b90 Merge pull request #1791 from jumpserver/dev
v2.23.0-rc3
2022-06-13 17:43:21 +08:00
“huailei000”
703898e707 fix: 修复资产树右键-显示资产详情弹窗不显示问题 2022-06-13 17:39:19 +08:00
feng626
fe0d7a7e3f 修改 2022-06-13 16:25:30 +08:00
Jiangjie.Bai
09b6bc1c18 Merge pull request #1789 from jumpserver/dev
v2.23.0-rc1
2022-06-09 17:40:42 +08:00
Jiangjie.Bai
d1a2564359 perf: 优化Su用户提示信息颜色样式 2022-06-09 17:20:47 +08:00
feng626
a3193beabf 改又改 2022-06-09 14:26:08 +08:00
dependabot[bot]
f46a1054ea build(deps): bump async from 2.6.3 to 2.6.4
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-09 10:34:58 +08:00
dependabot[bot]
64813f9cb6 build(deps): bump follow-redirects from 1.13.1 to 1.14.8
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.1 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.1...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-09 10:34:34 +08:00
dependabot[bot]
a6c0207c7e build(deps): bump moment from 2.29.1 to 2.29.2
Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-09 10:33:48 +08:00
dependabot[bot]
bf207285a8 build(deps): bump eventsource from 1.0.7 to 1.1.1
Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.0.7 to 1.1.1.
- [Release notes](https://github.com/EventSource/eventsource/releases)
- [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md)
- [Commits](https://github.com/EventSource/eventsource/compare/v1.0.7...v1.1.1)

---
updated-dependencies:
- dependency-name: eventsource
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-09 10:33:29 +08:00
ibuler
dd026f11ee perf: 修改 tree add 2022-06-09 10:23:08 +08:00
feng626
a58accca4d Merge pull request #1786 from jumpserver/pr@dev@relogin_bug
fix: relogin visible
2022-06-08 19:41:09 +08:00
feng626
bb572a3de9 fix: relogin visible 2022-06-08 19:39:27 +08:00
feng626
8836284b88 Merge pull request #1785 from jumpserver/pr@dev@user_confirm
perf: 统一校验当前用户api
2022-06-07 19:25:58 +08:00
feng626
68d97242cc perf: 统一校验当前用户api 2022-06-07 19:20:50 +08:00
Jiangjie.Bai
1bb3f0a48e feat: 添加组件类型 razor 并替换 XRDP_ENABLED 2022-06-07 13:42:24 +08:00
Jiangjie.Bai
7b566ae46f feat: 创建API增加clone_from查询参数 2022-06-06 16:12:41 +08:00
feng626
9dd89fe7ae fix: 合并后的bug 2022-06-02 15:05:51 +08:00
feng626
db67aa9b39 merge pr@dev@refactor_tickets 2022-06-02 11:39:59 +08:00
feng626
df96ce4112 perf: 工单重构 2022-06-02 10:34:05 +08:00
ibuler
4d27014330 perf: 优化工单 2022-06-02 08:48:53 +08:00
Jiangjie.Bai
1cb10902d5 feat: OIDC 用户添加属性映射值 2022-05-31 16:04:12 +08:00
“huailei000”
b71b602433 fix: 修复删除已绑定用户的角色,重复提示报错问题
1、删除组件内错误提示信息,统一走全局错误提示信息
2022-05-31 15:55:27 +08:00
ibuler
e39c4fc339 perf: 优化 ldap 导入 2022-05-30 11:41:21 +08:00
“huailei000”
9107c6a76a feat: 命令过滤详情添加用户、用户组、应用右侧卡片快捷入口 2022-05-30 10:31:26 +08:00
ibuler
55a83a2064 perf: 速度慢点,为以后优化留下空间 2022-05-30 10:30:43 +08:00
ibuler
92f52b100a perf: 优化动画速度 2022-05-30 10:21:18 +08:00
“huailei000”
5cd3aea0a3 feat: 应用授权详情按钮添加权限控制 2022-05-25 09:50:21 +08:00
ibuler
78b72ec68a perf: bool 使用 switcher 2022-05-20 11:43:21 +08:00
fit2bot
04c0c10d46 perf: remote app, cloud, setting 字段支持加密 (#1763)
* stash: 暂存

* pref: 其它字段也加密

* perf: 设置存储字段支持加密

Co-authored-by: ibuler <ibuler@qq.com>
2022-05-20 11:33:18 +08:00
278 changed files with 4011 additions and 1591 deletions

View File

@@ -1,7 +1,7 @@
FROM node:10 as stage-build
ARG NPM_REGISTRY="https://registry.npm.taobao.org"
ARG NPM_REGISTRY="https://registry.npmmirror.com"
ENV NPM_REGISTY=$NPM_REGISTRY
ARG SASS_BINARY_SITE="https://npm.taobao.org/mirrors/node-sass"
ARG SASS_BINARY_SITE="https://npmmirror.com/mirrors/node-sass"
ENV SASS_BINARY_SITE=$SASS_BINARY_SITE
WORKDIR /data

View File

@@ -26,6 +26,7 @@
"axios-retry": "^3.1.9",
"cron-parser": "^4.0.0",
"crypto-js": "^4.1.1",
"css-color-function": "^1.3.3",
"deepmerge": "^4.2.2",
"echarts": "^4.7.0",
"element-ui": "2.13.2",
@@ -96,7 +97,7 @@
"lint-staged": "^10.1.2",
"mockjs": "1.0.1-beta3",
"runjs": "^4.3.2",
"sass": "^1.26.10",
"sass": "~1.32.6",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",

View File

@@ -9,23 +9,7 @@
<meta http-equiv="Cache" content="no-cache">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title><%= webpackConfig.name %></title>
<style>
::-webkit-scrollbar {
width:14px;
}
::-webkit-scrollbar-track {
border-radius:10px;
}
::-webkit-scrollbar-thumb {
border-radius: 8px;
box-shadow: 8px 10px 20px #C6C6C6 inset;
border: 3px solid rgba(0, 0, 0, 0);
}
::-webkit-scrollbar-thumb:hover {
box-shadow: 8px 10px 20px #878787 inset;
}
</style>
<link rel="stylesheet" href="<%= BASE_URL %>theme/element-ui.css">
</head>
<body>
<noscript>

23
public/theme/README.md Normal file
View File

@@ -0,0 +1,23 @@
# 主题颜色
```
alpha-1: "rgba(64, 158, 255, 0.1)"
alpha-2: "rgba(64, 158, 255, 0.2)"
alpha-3: "rgba(64, 158, 255, 0.3)"
alpha-4: "rgba(64, 158, 255, 0.4)"
alpha-5: "rgba(64, 158, 255, 0.5)"
alpha-6: "rgba(64, 158, 255, 0.6)"
alpha-7: "rgba(64, 158, 255, 0.7)"
alpha-8: "rgba(64, 158, 255, 0.8)"
alpha-9: "rgba(64, 158, 255, 0.9)"
light-1: "#53a8ff"
light-2: "#66b1ff"
light-3: "#79bbff"
light-4: "#8cc5ff"
light-5: "#a0cfff"
light-6: "#b3d8ff"
light-7: "#c6e2ff"
light-8: "#d9ecff"
light-9: "#ecf5ff"
primary: "#409EFF"
```
primary是初始主题颜色其他颜色均属于primary的系列颜色

View File

@@ -1,66 +1,84 @@
// cover some element-ui styles
/* 这里只写element-variables里面改不动的、且和主题系列颜色相关的样式 */
/* 主题相关看该文件夹下的README.md */
/* info type special treatment */
.el-button--info {
background-color: info;
border-color: info;
}
.el-button--text {
padding: 5px
}
.el-button--text:hover {
background-color: rgba(0, 0, 0, .05);
}
.el-button--success {
background-color: success;
border-color: success;
}
.el-alert--info.is-light {
background-color: light-9;
color: light-2;
border: 1px solid;
}
.el-alert--info .el-alert__description {
color: light-2;
}
.el-pagination.is-background .el-pager li:not(.disabled):hover {
color: white;
background-color: primary;
}
.el-pagination.is-background .btn-next,
.el-pagination.is-background .btn-prev,
.el-pagination.is-background .el-pager li {
margin: 0 5px;
background-color: white;
color: #606266;
min-width: 28px;
border-radius: 2px;
border: 1px solid #DCDFE6;
font-size: 12px;
line-height: 26px;
font-weight: 400;
}
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
$--color-primary: #1ab394;
$--color-success: #1c84c6;
$--color-info: #23c6c8;
$--color-warning: #f8ac59;
$--color-danger: #ed5565;
$--color-link: #1c84c6;
$--color-link-highlight: #23527c;
$--color-text-primary: #303133;
/// color|1|Font Color|2
$--color-text-regular: #606266;
.el-upload {
input[type="file"] {
display: none !important;
}
.el-upload input[type="file"] {
display: none !important;
}
.el-upload__input {
display: none;
}
// to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog {
transform: none;
left: 0;
position: relative;
margin: 0 auto;
}
// refine element ui upload
.upload-container {
.el-upload {
.upload-container .el-upload {
width: 100%;
.el-upload-dragger {
width: 100%;
height: 200px;
}
}
}
// dropdown
.el-dropdown-menu {
a {
display: block
}
.upload-container .el-upload .el-upload-dragger {
width: 100%;
height: 200px;
}
.el-dropdown-menu a {
display: block
}
.el-table th > .cell {
color: rgb(104, 106, 108);
}
// to fix el-date-picker css style
.el-range-separator {
box-sizing: content-box;
}
@@ -111,22 +129,6 @@ td .el-button.el-button--mini {
border-left-color: rgb(220, 223, 230);
}
.el-alert--success.is-light {
border: #bce8f1 solid 1px;
}
.el-alert--info.is-light {
border: #bce8f1 solid 1px;
}
.el-alert--warning.is-light {
border: #faebcc solid 1px;
}
.el-alert--error.is-light {
border: #f1dfe2 solid 1px;
}
.el-alert__content {
line-height: 1.5;
}
@@ -140,32 +142,32 @@ td .el-button.el-button--mini {
}
.el-card.primary > .el-card__header {
background-color: $--color-primary;
border-color: $--color-primary;
background-color: primary;
border-color: primary;
color: white;
}
.el-card.success > .el-card__header {
background-color: $--color-success;
border-color: $--color-success;
background-color: success;
border-color: success;
color: #ffffff;
}
.el-card.info > .el-card__header {
background-color: $--color-info;
border-color: $--color-info;
background-color: info;
border-color: info;
color: #ffffff;
}
.el-card.warning > .el-card__header {
background-color: $--color-warning;
border-color: $--color-warning;
background-color: warning;
border-color: warning;
color: #ffffff;
}
.el-card.danger > .el-card__header {
background-color: $--color-danger;
border-color: $--color-danger;
background-color: danger;
border-color: danger;
color: #ffffff;
}
@@ -192,28 +194,14 @@ td .el-button.el-button--mini {
line-height: 34px;
}
.el-select-dropdown__item.selected {
font-weight: 400;
color: $--color-text-primary;
background-color: #ddd;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
color: #606266;
background-color: #ddd;
font-weight: 400;
}
//.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
// color: #606266;
// background-color: #ddd;
// font-weight: 400;
//}
.el-select-dropdown__item.hover, .el-select-dropdown__item:hover {
background-color: $--color-primary;
.el-select-dropdown__item.hover {
background-color: primary;
color: white;
}
@@ -222,27 +210,27 @@ td .el-button.el-button--mini {
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after {
color: $--color-primary;
color: primary;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover {
color: white;
background-color: $--color-primary;
background-color: primary;
}
.el-tag.el-tag--info {
background-color: #f1f1f1;
border-color: #e5e6e7;
color: #333333;
background-color: #f1f1f1!important;
border-color: #e5e6e7!important;
color: #333333!important;
}
.el-tag.el-tag--info .el-tag__close {
color: #333333;
color: #333333!important;
background-color: inherit;
}
.el-tag.el-tag--info.is-hit {
border-color: #e5e6e7;
border-color: #e5e6e7!important;
}
.el-tag.el-tag--info .el-tag__close:hover {
@@ -260,119 +248,61 @@ td .el-button.el-button--mini {
}
.text-danger {
color: $--color-danger;
color: danger;
}
.text-primary {
color: $--color-primary;
color: primary;
}
.text-info {
color: $--color-info;
color: info;
}
.text-warning {
color: $--color-warning;
color: warning;
}
.text-success {
color: $--color-success;
color: success;
}
.el-radio__input.is-checked+.el-radio__label {
color: inherit;
}
.el-radio__input.is-checked .el-radio__inner {
border-color: #409EFF;
background-color: #409EFF;
}
.el-checkbox__input.is-checked .el-checkbox__inner {
border-color: #409EFF;
background-color: #409EFF;
}
.el-radio__inner:hover {
border-color: #409EFF;
}
.el-textarea__inner {
border-radius: 0;
}
.el-checkbox__input.is-checked .el-checkbox__inner, .el-checkbox__input.is-indeterminate .el-checkbox__inner {
border-color: #409EFF;
background-color: #409EFF;
}
.el-checkbox__input.is-checked+.el-checkbox__label {
color: #606266;
}
.el-checkbox__inner:hover {
border-color: #409EFF;
}
.el-checkbox__input.is-focus .el-checkbox__inner {
border-color: #409EFF;
}
.el-pagination.is-background .btn-next, .el-pagination.is-background .btn-prev, .el-pagination.is-background .el-pager li {
margin: 0 5px;
background-color: white;
color: #606266;
min-width: 28px;
border-radius: 2px;
border: 1px solid #DCDFE6;
font-size: 12px;
line-height: 26px;
font-weight: 400;
}
.el-pagination.is-background .el-pager li:not(.disabled):hover {
color: white;
background-color: $--color-primary;
}
.el-pagination.is-background .number {
padding: 0;
}
.el-card.primary .el-card__header {
background-color: primary;
}
.el-card.success .el-card__header {
background-color: success;
}
.el-card.info .el-card__header {
background-color: info;
}
.el-card.warning .el-card__header {
background-color: warning;
}
.el-card.danger .el-card__header {
background-color: danger;
}
.el-message-box__headerbtn .el-message-box__close {
color: #606266;
}
.el-card.primary {
.el-card__header {
background-color: $--color-primary;
}
}
.el-card.success {
.el-card__header {
background-color: $--color-success;
}
}
.el-card.info {
.el-card__header {
background-color: $--color-info;
}
}
.el-card.warning {
.el-card__header {
background-color: $--color-warning;
}
}
.el-card.danger {
.el-card__header {
background-color: $--color-danger;
}
}
.el-tooltip__popper.is-light {
background: #FFF;
border: 1px solid #e7eaec;
@@ -391,21 +321,13 @@ td .el-button.el-button--mini {
border-bottom: 1px solid #e7e7e7 !important;
}
.el-table .cell, .el-table--border td:first-child .cell, .el-table--border th:first-child .cell {
.el-table .cell,
.el-table--border td:first-child .cell,
.el-table--border th:first-child .cell {
padding-left: 10px;
padding-right: 14px;
}
.el-tag--dark.el-tag--info {
background-color: #23c6c8;
border-color: #23c6c8;
color: #fff;
}
a {
color: $--color-link !important;
text-decoration: none;
}
.el-tag--default.el-tag--dark {
background-color: #d1dade;
@@ -417,7 +339,6 @@ a {
color: #676a6c;
}
.el-table__empty-block {
width: 100% !important;
}
@@ -433,62 +354,101 @@ a {
color: #000;
font-size: 22px;
font-weight: 800;
//color: red;
}
.el-tag--default.el-tag--dark {
background-color: #d1dade;
color: #5e5e5e;
border: none;
}
.el-card {
color: #676a6c;
}
.el-table__empty-block {
width: 100% !important;
}
.el-dialog__headerbtn .el-dialog__close {
font-size: 21px;
font-weight: 700;
color: #000;
text-shadow: 0 1px 0 #fff;
}
.el-dialog__headerbtn:focus .el-dialog__close, .el-dialog__headerbtn:hover .el-dialog__close {
color: #000;
font-size: 22px;
font-weight: 800;
}
.el-button--danger.is-plain {
color: $--color-danger;
color: danger;
background: #ffffff;
border-color: $--color-danger;
border-color: danger;
}
.el-button--danger.is-plain.is-disabled,
.el-button--danger.is-plain.is-disabled:active,
.el-button--danger.is-plain.is-disabled:focus,
.el-button--danger.is-plain.is-disabled:hover {
color: white;
}
.el-alert .el-alert__description {
margin: 1px 0 0;
}
.el-input-group__prepend div.el-select .el-input__inner {
color: $--color-text-primary;
}
.el-input-group__prepend div.el-select .el-input__inner:hover {
color: $--color-text-primary;
}
.el-table {
font-size: 13px;
}
.el-table-filter__list-item:hover {
color: $--color-text-primary;
}
.el-dialog {
// 居中弹框
position: absolute;
top: 50%;
left: 50%;
margin: 0 !important;
transform: translate(-50%, -50%);
// 防止超出视窗
max-height: calc(100% - 30px);
max-width: calc(100% - 30px);
//实现body内部滚动
display: flex;
flex-direction: column;
.el-dialog__body {
max-height: 90vh;
overflow: auto;
}
}
.el-button--text {
color: $--color-link;
padding: 5px;
.el-dialog .el-dialog__body {
max-height: 90vh;
overflow: auto;
padding: 30px;
}
.el-button--text:hover {
color: $--color-link-highlight;
background-color: rgba(0,0,0,.05)
.el-dialog .el-dialog__body form {
padding-right: 20px;
}
.el-dialog .el-dialog__footer {
padding: 10px 30px 30px;
}
.el-cascader {
line-height: 34px;
}
.el-input__icon {
line-height: 34px;
}
.el-checkbox__input.is-checked+.el-checkbox__label {
color: #606266;
}
.el-select-dropdown__item.selected {
font-weight: 400;
color: #606266;
background-color: #ddd;
}
.el-input-group__prepend div.el-select .el-input__inner,
.el-input-group__prepend div.el-select .el-input__inner:hover {
color: #303133;
}

File diff suppressed because one or more lines are too long

View File

@@ -9,3 +9,6 @@ export default {
name: 'App'
}
</script>
<style>
</style>

View File

@@ -1,8 +1,8 @@
import request from '@/utils/request'
export function postInterface(formData) {
export function updateInterface(formData) {
return request({
url: '/api/v1/xpack/interface/setting',
url: '/api/v1/xpack/interface/setting/',
method: 'put',
headers: {
'Content-Type': 'multipart/form-data'
@@ -12,15 +12,15 @@ export function postInterface(formData) {
}
export function getInterfaceInfo() {
return request({
url: '/api/v1/xpack/interface/setting',
url: '/api/v1/xpack/interface/setting/',
method: 'get'
})
}
export function restoreInterface() {
return request({
url: '/api/v1/xpack/interface/restore',
method: 'get'
url: '/api/v1/xpack/interface/setting/restore/',
method: 'put'
})
}
@@ -34,3 +34,10 @@ export function importLicense(formData) {
data: formData
})
}
export function previewThemes() {
return request({
url: `/api/v1/xpack/interface/setting/themes/`,
method: 'get'
})
}

View File

@@ -82,7 +82,7 @@ export function getPublicSettings(isOpen) {
}
export function getLogo() {
return request({
url: '/api/v1/xpack/interface/setting',
url: '/api/v1/xpack/interface/setting/',
method: 'get'
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
src/assets/img/header-profile.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,156 @@
<template>
<div>
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" :help-message="title" />
<ShowSecretInfo v-if="showViewSecretDialog" :visible.sync="showViewSecretDialog" :account="account" />
</div>
</template>
<script>
import { ActionsFormatter, DetailFormatter, DisplayFormatter } from '@/components/TableFormatters'
import ShowSecretInfo from '../AccountListTable/ShowSecretInfo'
import { GenericListPage } from '@/layout/components'
export default {
name: 'AccountHistoryTable',
components: {
GenericListPage,
ShowSecretInfo
},
props: {
url: {
type: String,
required: true
},
exportUrl: {
type: String,
default() {
return this.url.replace('/assets/accounts-history/', '/assets/account-history-secrets/')
}
},
hasLeftActions: {
type: Boolean,
default: false
},
otherActions: {
type: Array,
default: null
},
hasClone: {
type: Boolean,
default: false
}
},
data() {
const vm = this
return {
showViewSecretDialog: false,
account: {},
tableConfig: {
url: this.url,
permissions: {
app: 'assets',
resource: 'authbook'
},
columns: [
'hostname', 'ip', 'username', 'version',
'systemuser', 'date_created', 'date_updated', 'actions'
],
columnsShow: {
min: ['username', 'actions'],
default: ['hostname', 'ip', 'username', 'version', 'actions']
},
columnsMeta: {
hostname: {
prop: 'hostname',
label: this.$t('assets.Hostname'),
showOverflowTooltip: true,
formatter: DetailFormatter,
formatterArgs: {
can: this.$hasPerm('assets.view_asset'),
getRoute({ row }) {
return {
name: 'AssetDetail',
params: { id: row.asset }
}
}
}
},
ip: {
width: '120px'
},
username: {
showOverflowTooltip: true
},
systemuser: {
formatter: DisplayFormatter
},
version: {
width: '70px'
},
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value)
hasClone: this.hasClone,
moreActionsTitle: this.$t('common.More'),
extraActions: [
{
name: 'View',
title: this.$t('common.View'),
can: this.$hasPerm('assets.view_assethistoryaccountsecret'),
type: 'primary',
callback: ({ row }) => {
vm.account = row
vm.showViewSecretDialog = true
}
}
]
}
}
}
},
headerActions: {
hasLeftActions: this.hasLeftActions,
hasMoreActions: false,
hasCreate: false,
hasImport: false,
hasExport: this.$hasPerm('assets.view_assethistoryaccountsecret'),
exportOptions: {
url: this.exportUrl,
mfaVerifyRequired: true
},
searchConfig: {
exclude: ['systemuser', 'asset']
},
hasSearch: true
}
}
},
computed: {
title() {
return this.$t('accounts.AccountHistableHelpMessage')
}
},
watch: {
url(iNew) {
this.$set(this.tableConfig, 'url', iNew)
this.$set(this.headerActions.exportOptions, 'url', iNew.replace('/accounts-history/', '/account-history-secrets/'))
}
},
mounted() {
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
},
methods: {
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -1,8 +1,9 @@
<template>
<div>
<MFAVerifyDialog
@MFAVerifyDone="getAuthInfo"
@MFAVerifyCancel="exit"
<UserConfirmDialog
:url="url"
@UserConfirmDone="getAuthInfo"
@UserConfirmCancel="exit"
/>
<Dialog
:title="dialogTitle"
@@ -36,12 +37,12 @@
<script>
import Dialog from '@/components/Dialog'
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
export default {
name: 'ShowSecretInfo',
components: {
Dialog,
MFAVerifyDialog
UserConfirmDialog
},
props: {
account: {
@@ -57,13 +58,13 @@ export default {
return {
dialogTitle: this.$t('common.ViewSecret'),
authInfo: {},
showAuthInfo: false
showAuthInfo: false,
url: `/api/v1/assets/account-secrets/${this.account.id}/`
}
},
methods: {
getAuthInfo() {
const url = `/api/v1/assets/account-secrets/${this.account.id}/`
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
this.authInfo = resp
this.showAuthInfo = true
})

View File

@@ -13,6 +13,7 @@ import ShowSecretInfo from './ShowSecretInfo'
import UpdateSecretInfo from './UpdateSecretInfo'
import { connectivityMeta } from './const'
import { openTaskPage } from '@/utils/jms'
// import i18n from '@/i18n/i18n'
export default {
name: 'AccountListTable',
@@ -109,7 +110,10 @@ export default {
type: 'primary',
callback: ({ row }) => {
vm.account = row
vm.showViewSecretDialog = true
vm.showViewSecretDialog = false
setTimeout(() => {
vm.showViewSecretDialog = true
})
}
},
{
@@ -149,6 +153,17 @@ export default {
})
}
}
// {
// name: 'History',
// title: i18n.t('common.History'),
// can: this.$hasPerm('assets.view_assethistoryaccount') && !this.$store.getters.currentOrgIsRoot,
// callback: ({ row }) => {
// this.$router.push({
// name: 'AssetAccountHistoryList',
// query: { id: row.id }
// })
// }
// }
]
}
}

View File

@@ -12,7 +12,7 @@
<el-link :href="announcement.link" target="_blank" class="link-more">
{{ $t('common.ViewMore') }}
</el-link>
<i class="fa fa-share-square-o" />
<i class="fa fa-external-link" />
</span>
</el-alert>
</template>

View File

@@ -1,8 +1,9 @@
<template>
<div>
<MFAVerifyDialog
@MFAVerifyDone="getAuthInfo"
@MFAVerifyCancel="exit"
<UserConfirmDialog
:url="url"
@UserConfirmDone="getAuthInfo"
@UserConfirmCancel="exit"
/>
<Dialog
:title="dialogTitle"
@@ -33,12 +34,12 @@
<script>
import Dialog from '@/components/Dialog'
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
export default {
name: 'ShowSecretInfo',
components: {
Dialog,
MFAVerifyDialog
UserConfirmDialog
},
props: {
account: {
@@ -54,13 +55,13 @@ export default {
return {
dialogTitle: this.$t('common.ViewSecret'),
authInfo: {},
showAuthInfo: false
showAuthInfo: false,
url: `/api/v1/applications/account-secrets/${this.account.id}/`
}
},
methods: {
getAuthInfo() {
const url = `/api/v1/applications/account-secrets/${this.account.id}/`
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
this.authInfo = resp
this.showAuthInfo = true
})

View File

@@ -75,6 +75,8 @@ export default {
showMenu: false,
showRefresh: true,
showAssets: false,
showSearch: true,
customTreeHeader: true,
url: '/api/v1/assets/assets/?fields_size=mini',
nodeUrl: '/api/v1/assets/nodes/',
// ?assets=0不显示资产. =1显示资产

View File

@@ -78,15 +78,22 @@ export default {
},
_cleanFormValue(form, remoteMeta) {
for (const [k, v] of Object.entries(remoteMeta)) {
if (v.default === undefined) {
continue
let valueSet = form[k]
if (v.type === 'nested object' && v.children) {
// 有一些字段属性时 nested object 类型,但是没有 children没有children的不需要走递归逻辑
// 比如:认证配置中的属性映射字段
if (typeof valueSet !== 'object') {
// 处理一些前端没有设置初始值的情况
valueSet = {}
}
form[k] = valueSet
this._cleanFormValue(valueSet, v.children)
}
const valueSet = form[k]
if (valueSet !== undefined) {
continue
}
if (v.type === 'nested object' && typeof valueSet === 'object') {
this._cleanFormValue(valueSet, v.children)
if (v.default === undefined) {
continue
}
form[k] = v.default
}

View File

@@ -1,6 +1,7 @@
import Vue from 'vue'
import Select2 from '@/components/FormFields/Select2'
import NestedField from '@/components/AutoDataForm/components/NestedField'
import Swicher from '@/components/FormFields/Swicher'
import rules from '@/components/DataForm/rules'
import { assignIfNot } from '@/utils/common'
@@ -45,7 +46,8 @@ export class FormFieldGenerator {
}
break
case 'boolean':
type = 'checkbox'
type = ''
field.component = Swicher
break
case 'nested object':
type = 'nestedField'

View File

@@ -85,6 +85,9 @@ export default {
{ label: i18n.t('common.No'), value: false }
]
}
if (option.value === 'id') {
option.label = 'ID'
}
vm.internalOptions.push(option)
}
},

View File

@@ -18,6 +18,7 @@
<script>
import DataZTree from '../DataZTree'
import $ from '@/utils/jquery-vendor'
import { mapGetters } from 'vuex'
export default {
name: 'AutoDataZTree',
@@ -37,6 +38,10 @@ export default {
showCreate: true,
showDelete: true,
showUpdate: true,
showSearch: false,
// 自定义header
customTreeHeader: false,
customTreeHeaderName: this.$t('assets.AssetTree'),
async: {
enable: true,
url: (process.env.VUE_APP_ENV === 'production') ? (`${this.setting.treeUrl}`) : (`${process.env.VUE_APP_BASE_API}${this.setting.treeUrl}`),
@@ -66,6 +71,9 @@ export default {
}
},
computed: {
...mapGetters([
'currentOrg'
]),
treeSetting() {
this.$log.debug('Settings: ', this.setting)
return _.merge(this.defaultSetting, this.setting)
@@ -82,8 +90,8 @@ export default {
},
methods: {
refreshTree: function() {
const refreshIconRef = $('#tree-refresh')
refreshIconRef.click()
// const refreshIconRef = $('#tree-refresh')
// refreshIconRef.click()
},
editTreeNode: function() {
this.hideRMenu()
@@ -112,16 +120,17 @@ export default {
}
let url = ''
const query = Object.assign({}, this.$route.query)
const objectId = treeNode.meta.data.id
if (treeNode.meta.type === 'node') {
this.currentNode = treeNode
this.currentNodeId = treeNode.meta.data.id
query['node'] = this.currentNodeId
query['asset'] = ''
url = `${this.setting.url}${combinator}node_id=${treeNode.meta.data.id}&show_current_asset=${show_current_asset}`
url = `${this.setting.url}${combinator}node_id=${objectId}&show_current_asset=${show_current_asset}`
} else if (treeNode.meta.type === 'asset') {
query['asset'] = treeNode.meta.data.id
query['node'] = ''
url = `${this.setting.url}${combinator}asset_id=${treeNode.meta.data.id}&show_current_asset=${show_current_asset}`
url = `${this.setting.url}${combinator}asset_id=${objectId}&show_current_asset=${show_current_asset}`
}
this.$router.push({ query })
this.$emit('urlChange', url)
@@ -151,11 +160,12 @@ export default {
url,
{ 'value': treeNode.name }
).then(res => {
let assetsAmount = treeNode.meta.data.assetsAmount
let assetsAmount = treeNode.meta.data['assetsAmount']
if (!assetsAmount) {
assetsAmount = 0
}
treeNode.name = treeNode.name + ' (' + assetsAmount + ')'
treeNode.meta.data = res
this.zTree.updateNode(treeNode)
this.$message.success(this.$t('common.updateSuccessMsg'))
}).finally(() => { this.refreshTree() })
@@ -170,7 +180,7 @@ export default {
const rMenuID = this.$refs.dataztree.$refs.ztree.iRMenuID
const zTreeID = this.$refs.dataztree.$refs.ztree.iZTreeID
const offset = $(`#${zTreeID}`).offset()
const scrollTop = document.querySelector('.treebox').scrollTop
const scrollTop = document.querySelector('.treebox')?.scrollTop
x -= offset.left
// Tmp
y -= (offset.top + scrollTop) / 3 - 10
@@ -190,7 +200,7 @@ export default {
return
}
// 屏蔽收藏资产
if (treeNode.id === '-12') {
if (treeNode?.id === '-12') {
return
}
if (!treeNode && event.target.tagName.toLowerCase() !== 'button' && $(event.target).parents('a').length === 0) {
@@ -227,7 +237,7 @@ export default {
this.$message.success(this.$t('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
}).finally(() => this.refreshTree())
}).finally()
},
createTreeNode: function() {
this.hideRMenu()
@@ -243,13 +253,14 @@ export default {
id: data['key'],
name: data['value'],
pId: parentNode.id,
isParent: true,
meta: {
data: data
data: data,
type: 'node'
}
}
newNode.checked = this.zTree.getSelectedNodes()[0].checked
this.zTree.addNodes(parentNode, 0, newNode)
// vm.$refs.dataztree.refresh()
const node = this.zTree.getNodeByParam('id', newNode.id, parentNode)
this.currentNodeId = node.meta.data.id || newNode.id
this.zTree.editName(node)

View File

@@ -14,7 +14,7 @@
<slot v-for="item in fields" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
<el-form-item v-if="hasButtons" class="form-buttons">
<el-button v-for="button in moreButtons" :key="button.title" size="small" v-bind="button" @click="handleClick(button)">{{ button.title }}</el-button>
<el-button v-for="button in moreButtons" :key="button.title" size="small" v-bind="button" :loading="button.loading" @click="handleClick(button)">{{ button.title }}</el-button>
<el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')">{{ $t('common.Reset') }}</el-button>
<el-button v-if="defaultButton && hasSaveContinue" size="small" @click="submitForm('form', true)">{{ $t('common.SaveAndAddAnother') }}</el-button>
<el-button v-if="defaultButton" size="small" :loading="isSubmitting" type="primary" @click="submitForm('form')">{{ $t('common.Submit') }}</el-button>
@@ -101,7 +101,7 @@ export default {
}
const form = this.$refs['form']
const values = form.getFormValue()
callback(values, form)
callback(values, form, button)
}
}
}
@@ -145,7 +145,7 @@ export default {
line-height: 18px;
}
.el-form ::v-deep .help-block a {
color: #1c84c6;
color: var(--color-primary);
}
.form-buttons {
padding-top: 10px;

View File

@@ -14,10 +14,23 @@ export const EmailCheck = {
trigger: ['blur', 'change']
}
export const specialEmojiCheck = {
validator: (rule, value, callback) => {
value = value.trim()
if (/[\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/.test(value)) {
callback(new Error(i18n.t('common.NotSpecialEmoji')))
} else {
callback()
}
},
trigger: ['blur', 'change']
}
export default {
Required,
RequiredChange,
EmailCheck
EmailCheck,
specialEmojiCheck
}
export const JsonRequired = {

View File

@@ -1,14 +1,50 @@
<template>
<div>
<ul v-show="loading" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
<div v-show="!loading" class="treebox">
<ul :id="iZTreeID" class="ztree">
<div
v-if="treeSetting.customTreeHeader"
class="tree-header treebox"
>
<div class="content">
<span class="title">
{{ treeSetting.customTreeHeaderName }}
</span>
<span class="tree-banner-icon-zone">
<a id="searchIcon" class="tree-search special">
<i
class="fa fa-search tree-banner-icon"
@click.stop="treeSearch"
/>
<input
id="searchInput"
v-model="treeSearchValue"
type="text"
autocomplete="off"
class="tree-input"
>
</a>
<i
class="fa fa-refresh tree-banner-icon"
style="margin-right: 2px;"
@click.stop="refresh"
/>
</span>
</div>
<ul v-show="loading" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
<div v-if="treeSetting.treeUrl===''">
{{ this.$t('common.tree.Empty') }}<a id="tree-refresh"><i class="fa fa-refresh" /></a>
<ul v-show="!loading" :id="iZTreeID" class="ztree" />
<div v-if="treeSetting.treeUrl===''" class="tree-empty">
{{ this.$t('common.tree.Empty') }}
</div>
</div>
<div v-else class="treebox">
<ul v-show="loading" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
<ul v-show="!loading" :id="iZTreeID" class="ztree" />
<div v-if="treeSetting.treeUrl===''" class="tree-empty">
{{ this.$t('common.tree.Empty') }}
<a id="tree-refresh"><i class="fa fa-refresh" /></a>
</div>
</div>
<div :id="iRMenuID" class="rMenu">
@@ -24,6 +60,7 @@
// eslint-disable-next-line no-unused-vars
import $ from '@/utils/jquery-vendor.js'
import '@ztree/ztree_v3/js/jquery.ztree.all.min.js'
import '@ztree/ztree_v3/js/jquery.ztree.exhide.min.js'
import '@/styles/ztree.css'
import axiosRetry from 'axios-retry'
@@ -45,7 +82,8 @@ export default {
zTree: '',
rMenu: '',
init: false,
loading: false
loading: false,
treeSearchValue: ''
}
},
computed: {
@@ -54,8 +92,9 @@ export default {
}
},
mounted() {
window.refresh = this.refresh
window.treeSearch = this.treeSearch
this.initTree()
// $('.treebox').css('height', window.innerHeight - 60)
},
beforeDestroy() {
$.fn.zTree.destroy(this.iZTreeID)
@@ -82,9 +121,7 @@ export default {
retryDelay: () => { return 5000 }
}
}).then(res => {
if (!res) {
res = []
}
if (!res) res = []
if (res.length === 0) {
res.push({
name: this.$t('common.tree.Empty')
@@ -94,15 +131,13 @@ export default {
if (this.init) {
vm.zTree.destroy()
}
this.zTree = $.fn.zTree.init($(`#${this.iZTreeID}`), this.treeSetting, res)
if (!this.treeSetting.customTreeHeader) {
this.rootNodeAddDom(this.zTree)
}
// 手动上报事件, Tree加载完成
this.$emit('TreeInitFinish', this.zTree)
if (this.treeSetting.showRefresh) {
this.rootNodeAddDom(
this.zTree,
this.treeSetting.callback.refresh
)
}
if (this.treeSetting.showMenu) {
this.rMenu = $(`#${this.iRMenuID}`)
@@ -115,43 +150,196 @@ export default {
vm.init = true
})
},
rootNodeAddDom: function(ztree, callback) {
const vm = this
const refreshIcon = "<a id='tree-refresh'><i class='fa fa-refresh'></i></a>"
rootNodeAddDom(ztree) {
const { showSearch, showRefresh } = this.treeSetting
const searchIcon = `<a class="tree-search" id="searchIcon">
<i class='fa fa-search tree-banner-icon' onclick="treeSearch()" /></i>
<input type="text" autocomplete="off" id="searchInput" class="tree-input" />
</a>`
const refreshIcon = "<a id='tree-refresh' onclick='refresh()'><i class='fa fa-refresh'></i></a>"
const treeActions = `${showSearch ? searchIcon : ''}${showRefresh ? refreshIcon : ''}`
const icons = `<span class="">${treeActions}</span>`
const rootNode = ztree.getNodes()[0]
let $rootNodeRef
if (rootNode) {
$rootNodeRef = $('#' + rootNode.tId + '_a')
$rootNodeRef.after(refreshIcon)
} else {
$rootNodeRef = $('#' + ztree.setting.treeId)
$rootNodeRef.html(refreshIcon)
const $rootNodeRef = $('#' + rootNode.tId + '_a')
$rootNodeRef.after(icons)
}
const refreshIconRef = $('#tree-refresh')
refreshIconRef.bind('click', function() {
const result = callback()
if (result && result.then) {
result.finally(() => {
vm.initTree()
})
} else {
vm.initTree()
}
})
},
refresh: function() {
const refreshIconRef = $('#tree-refresh')
refreshIconRef.click()
refresh() {
this.treeSearchValue = ''
const result = this.treeSetting?.callback?.refresh()
if (result && result.then) {
result.finally(() => {
this.initTree()
})
} else {
this.initTree()
}
},
treeSearch() {
const searchIcon = document.getElementById(`searchIcon`)
const searchInput = document.getElementById(`searchInput`)
searchIcon.classList.toggle('active')
searchInput.focus()
searchInput.onclick = (e) => {
e.stopPropagation()
}
searchInput.onblur = (e) => {
e.stopPropagation()
if (!(e.target.value)) {
searchIcon.classList.toggle('active')
}
}
searchInput.oninput = _.debounce((e) => {
e.stopPropagation()
const value = e.target.value || ''
if (this.treeSetting.async.enable) {
this.filterAssetsServer(value)
} else {
this.filterTree(value)
}
}, 600)
},
getCheckedNodes: function() {
return this.zTree.getCheckedNodes(true)
},
recurseParent(node) {
const parentNode = node.getParentNode()
if (parentNode && parentNode.pId) {
return [parentNode, ...this.recurseParent(parentNode)]
} else if (parentNode) {
return [parentNode]
} else {
return []
}
},
recurseChildren(node) {
if (!node.isParent) {
return []
}
const children = node.children
if (!children) {
return []
}
let allChildren = []
children.forEach((n) => {
allChildren = [...children, ...this.recurseChildren(n)]
})
return allChildren
},
groupBy(array, filter) {
const groups = {}
array.forEach(function(o) {
const group = JSON.stringify(filter(o))
groups[group] = groups[group] || []
groups[group].push(o)
})
return Object.keys(groups).map(function(group) {
return groups[group]
})
},
filterTree(keyword, tree = this.zTree) {
if (!this.zTree) return
const searchNode = tree.getNodesByFilter((node) => node.id === 'search')
if (searchNode) tree.removeNode(searchNode[0])
const nodes = tree.transformToArray(tree.getNodes())
if (!keyword) {
tree.showNodes(nodes)
return
}
if (!keyword) {
if (tree.hiddenNodes) {
tree.showNodes(tree.hiddenNodes)
tree.hiddenNodes = null
}
if (tree.expandNodes) {
tree.expandNodes.forEach((node) => {
if (node.id !== nodes[0].id) {
tree.expandNode(node, false)
}
})
tree.expandNodes = null
}
return null
}
let shouldShow = []
const matchedNodes = tree.getNodesByFilter((node) => {
return node.name.toLowerCase().indexOf(keyword.toLowerCase()) > -1
})
if (matchedNodes.length < 1) {
let name = this.$t('common.Search')
const assetsAmount = matchedNodes.length
name = `${name} (${assetsAmount})`
const newNode = { id: 'search', name: name, isParent: false, open: false }
tree.addNodes(null, newNode)
}
matchedNodes.forEach((node) => {
const parents = this.recurseParent(node)
const children = this.recurseChildren(node)
shouldShow = [...shouldShow, ...parents, ...children, node]
})
tree.hiddenNodes = nodes
tree.expandNodes = shouldShow
tree.hideNodes(nodes)
tree.showNodes(shouldShow)
for (const node of shouldShow) {
if (node.isParent) {
tree.expandNode(node, true)
}
}
},
filterAssetsServer(keyword) {
if (!this.zTree) return
let searchNode = this.zTree.getNodesByFilter((node) => node.id === 'search')
if (searchNode) {
this.zTree.removeChildNodes(searchNode[0])
this.zTree.removeNode(searchNode[0])
}
const treeNodes = this.zTree.getNodes()
if (!keyword) {
if (treeNodes.length !== 0) {
this.zTree.showNodes(treeNodes)
}
return
}
if (treeNodes.length !== 0) {
this.zTree.hideNodes(treeNodes)
}
let treeUrl = this.treeSetting.treeUrl
const filterField = treeUrl.includes('?') ? `&search=${keyword}` : `?search=${keyword}`
if (treeUrl.indexOf('assets/nodes/children/tree') > -1) {
treeUrl = treeUrl + '&all=all'
}
const searchUrl = `${treeUrl}${filterField}`
this.$axios.get(searchUrl).then(nodes => {
let name = this.$t('common.Search')
const assetsAmount = nodes.length
name = `${name} (${assetsAmount})`
const newNode = { id: 'search', name: name, isParent: true, open: true, zAsync: true }
searchNode = this.zTree.addNodes(null, newNode)[0]
searchNode.zAsync = true
const nodesGroupByOrg = this.groupBy(nodes, (node) => {
return node.meta.data.org_name
})
for (const item of nodesGroupByOrg) {
this.zTree.addNodes(searchNode, item)
}
searchNode.open = true
})
return
}
}
}
</script>
<style lang='less' scoped>
<style lang='scss' scoped>
div.rMenu {
position: absolute;
visibility: hidden;
@@ -191,7 +379,7 @@ export default {
top: 100%;
z-index: 1000;
}
.ztree ::v-deep .fa-refresh {
.ztree ::v-deep .fa {
font: normal normal normal 14px/1 FontAwesome !important;
}
.dropdown a:hover {
@@ -218,4 +406,106 @@ export default {
height: 80vh;
overflow: auto;
}
::v-deep #tree-refresh {
margin-left: 3px;
}
::v-deep .tree-banner-icon-zone {
position: absolute;
right: 7px;
height: 30px;
overflow: hidden;
.fa {
color: #838385!important;;
&:hover {
color: #606266!important;;
}
}
}
::v-deep .tree-search {
position: relative;
top: -2px;
width: 20px;
height: 20px;
display: inline-block;
border-radius: 12px;
vertical-align: sub;
transition: .25s;
overflow: hidden;
.fa {
width: 13px!important;
}
.fa-search {
padding-top: 1px;
}
}
::v-deep .tree-search .tree-banner-icon {
position: absolute;
top: 1px;
left: 6px;
width: 6px;
height: 6px;
border-radius: 12px;
padding: 10px 6px;
overflow: hidden;
background-color: transparent!important;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
::v-deep .tree-search.active {
width: 160px;
background-color: #ffffff!important;
}
::v-deep .tree-search.active:hover {
border-radius: 12px;
}
::v-deep .tree-search input {
position: relative;
left: 20px;
width: 133px;
height: 100%;
background-color: #ffffff!important;
color: #606266;
display: flex;
justify-content: center;
align-items: center;
border: none;
outline: none;
}
.tree-header {
position: relative;
.title {
font-weight: 500;
}
.content {
height: 30px;
line-height: 30px;
border-bottom: 1px solid #e0e0e0;
border-radius: 3px;
padding: 0 5px;
box-sizing: border-box;
overflow: hidden;
cursor: pointer;
background-color: #D7D8DC;
.rotate {
transition: all .1.8s;
transform: rotate(-90deg);
}
.fa-caret-down {
font-size: 16px;
}
.special {
top: 1px!important;
}
}
}
.tree-empty {
margin-left: 4px;
}
</style>

View File

@@ -105,7 +105,7 @@ export default {
.el-input__inner{
border: 1px solid #dcdee2;
border-radius: 3px;
height: 36px;
height: 32x;
}
.el-date-editor ::v-deep .el-range-separator{
line-height: 28px;

View File

@@ -52,6 +52,7 @@ export default {
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
.json-editor {
&>>> .jsoneditor {
border: 1px solid #e5e6e7;
@@ -66,8 +67,8 @@ export default {
display: none;
}
&>>> .jsoneditor-menu {
background: #1ab394;
border-bottom: 1px solid #1ab394;
background: var(--color-primary);
border-bottom: 1px solid var(--color-primary);
}
}
</style>

View File

@@ -47,17 +47,16 @@ export default {
</script>
<style lang="scss" scoped>
@import "~@/styles/element-variables.scss";
.password-input >>> .Password__badge--error {
background-color: $--color-danger;
background-color: var(--color-danger);
}
.password-input >>> .Password__strength-meter--fill[data-score="4"] {
background: $--color-primary;
background: var(--color-success);
width: 100%;
}
.password-input >>> .Password__badge--success {
background: $--color-primary;
background: var(--color-success);
}
.password-input >>> .Password__strength-meter {

View File

@@ -1,8 +1,8 @@
<template>
<el-switch
v-model="iValue"
:active-color="activeColor"
inactive-color="#dcdfe6"
:class="type"
v-bind="$attrs"
v-on="$listeners"
/>
@@ -26,21 +26,6 @@ export default {
}
},
computed: {
activeColor() {
// $--color-primary: #1ab394;
// $--color-success: #1c84c6;
// $--color-info: #23c6c8;
// $--color-warning: #f8ac59;
// $--color-danger: #ed5565;
switch (this.type) {
case 'primary':
return '#1ab394'
case 'danger':
return '#ed5565'
default:
return '#1ab394'
}
},
iValue: {
set: function(newValue) {
this.$emit('input', newValue)

View File

@@ -1,9 +1,15 @@
<template>
<div class="upload-key">
<input ref="upLoadFile" type="file" style="display: none" @change="onChange">
<el-button size="mini" @click.native.stop="onUpLoad">
<el-button v-if="!fingerprint" size="mini" @click.native.stop="onUpLoad">
{{ this.$t('common.SelectFile') }}
</el-button>
<span v-else>
<el-button type="text" icon="el-icon-edit" @click.native.stop="onUpLoad">
{{ this.$t('common.Update') }}
</el-button>
<span v-if="!fileName" class="fingerprint">{{ fingerprint }}</span>
</span>
<span>{{ fileName }}</span>
<div v-if="tip !== ''">{{ tip }}</div>
</div>
@@ -12,10 +18,6 @@
<script>
export default {
props: {
// value: {
// type: String,
// default: () => ''
// },
tip: {
type: String,
default: () => ''
@@ -23,6 +25,10 @@ export default {
toFormat: {
type: String,
default: () => 'string'
},
fingerprint: {
type: String,
default: ''
}
},
data() {
@@ -58,4 +64,7 @@ export default {
</script>
<style scoped>
.fingerprint {
font-size: 12px
}
</style>

View File

@@ -21,12 +21,13 @@ export default {
}
</script>
<style scoped>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
.hamburger {
display: inline-block;
vertical-align: middle;
font-size: 20px;
color: rgb(167, 177, 194);
color: $menuText;
}
.hamburger.is-active {
transform: rotate(180deg);

View File

@@ -1,9 +1,10 @@
<template>
<div>
<MFAVerifyDialog
<UserConfirmDialog
v-if="mfaDialogShow"
@MFAVerifyDone="showExportDialog"
@MFAVerifyCancel="handleExportCancel"
:url="url"
@UserConfirmDone="showExportDialog"
@UserConfirmCancel="handleExportCancel"
/>
<Dialog
v-if="exportDialogShow"
@@ -31,7 +32,7 @@
<script>
import Dialog from '@/components/Dialog'
import MFAVerifyDialog from '@/components/MFAVerifyDialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
import { createSourceIdCache } from '@/api/common'
import * as queryUtil from '@/components/DataTable/compenents/el-data-table/utils/query'
@@ -39,7 +40,7 @@ export default {
name: 'ExportDialog',
components: {
Dialog,
MFAVerifyDialog
UserConfirmDialog
},
props: {
selectedRows: {

View File

@@ -233,7 +233,7 @@ export default {
</script>
<style lang='scss' scoped>
@import "~@/styles/element-variables.scss";
@import "~@/styles/variables.scss";
.error-msg {
color: $--color-danger;
}

View File

@@ -202,11 +202,14 @@ export default {
}]
for (const item of tableTitles) {
const dataItemLens = tableData.map(d => {
const prop = item[1]
const itemColData = d[prop]
if (!d) {
return 0
}
const prop = item[1]
const itemColData = d[prop]
if (typeof itemColData === 'boolean') {
return 5 // boolean is 5 characters long 并且 boolean.length 是 undefined
}
if (typeof itemColData !== 'number' && (!itemColData || !itemColData.length)) {
return 0
}
@@ -405,7 +408,7 @@ export default {
</script>
<style lang="scss" scoped>
@import "~@/styles/element-variables.scss";
@import "~@/styles/variables.scss";
.summary-item {
padding: 0 10px
}

View File

@@ -27,7 +27,7 @@ export default {
createRoute: {
type: [String, Object, Function],
default: function() {
return this.$route.name.replace('List', 'Create')
return this.$route.name?.replace('List', 'Create')
}
},
createInNewPage: {

View File

@@ -127,6 +127,10 @@ export default {
color: #888;
}
.action-search >>> .el-cascader {
line-height: 32px !important;
}
.right-side-actions {
display: flex;
padding-left: 10px;
@@ -146,17 +150,19 @@ export default {
.datepicker{
margin-left: 10px;
}
.table-header {
line-height: 32px;
}
.left-side {
float: left;
display: block;
line-height: 36px;
}
.right-side {
float: right;
}
.search {
display: flex;
flex-direction: row
flex-direction: row;
}
.mobile .search {
display: inherit;
@@ -171,9 +177,16 @@ export default {
float: right;
}
.mobile .search.right {
float: left;
float: none;
}
.mobile .search.right .action-search {
width: 100%;
}
.mobile .right-side {
padding-top: 5px;
}
.filter-field.right-side-item.action-search {
height: 34px;
}
</style>

View File

@@ -84,15 +84,22 @@ export default {
extraQuery: this.extraQuery
})
const formatterArgs = {
'columnsMeta.actions.formatterArgs.canUpdate': 'change',
'columnsMeta.actions.formatterArgs.canUpdate': () => {
return this.hasActionPerm('change') && !this.currentOrgIsRoot
},
'columnsMeta.actions.formatterArgs.canDelete': 'delete',
'columnsMeta.actions.formatterArgs.canClone': 'add',
'columnsMeta.actions.formatterArgs.canClone': () => {
return this.hasActionPerm('add') && !this.currentOrgIsRoot
},
'columnsMeta.name.formatterArgs.can': 'view'
}
for (const [arg, action] of Object.entries(formatterArgs)) {
const notSet = _.get(config, arg) === undefined
const isFunction = typeof action === 'function'
if (notSet) {
_.set(config, arg, this.hasActionPerm(action))
const hasActionPerm = isFunction ? action() : this.hasActionPerm(action)
_.set(config, arg, hasActionPerm)
}
}
this.$log.debug('Header actions', this.headerActions)

View File

@@ -1,77 +0,0 @@
<template>
<Dialog
:title="$t('common.MFAVerify')"
:width="'50'"
:show-confirm="false"
:show-cancel="false"
:visible.sync="visible"
:destroy-on-close="true"
v-bind="$attrs"
v-on="$listeners"
>
<el-row :gutter="20">
<el-col :md="4" :sm="24">
<div style="line-height: 34px;text-align: center">MFA</div>
</el-col>
<el-col :md="14" :sm="24">
<el-input v-model="MFAToken" />
<span class="help-tips help-block">{{ $t('common.MFARequireForSecurity') }}</span>
</el-col>
<el-col :md="4" :sm="24">
<el-button size="mini" type="primary" style="line-height:20px " @click="verifyMFA">
{{ this.$t('common.Confirm') }}
</el-button>
</el-col>
</el-row>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
export default {
name: 'MFAVerifyDialog',
components: {
Dialog
},
data() {
return {
MFAToken: '',
visible: false
}
},
watch: {
visible(val) {
if (!val) {
this.$emit('MFAVerifyCancel', true)
}
}
},
mounted() {
this.$axios.get('/api/v1/authentication/otp/verify/', { disableFlashErrorMsg: true }).then(() => {
this.$emit('MFAVerifyDone', true)
}).catch(err => {
this.$log.debug('Verify otp code error: ', err)
this.visible = true
})
},
methods: {
verifyMFA() {
if (this.MFAToken.length !== 6) {
return this.$message.error(this.$tc('common.MFAErrorMsg'))
}
this.$axios.post(
`/api/v1/authentication/otp/verify/`, {
code: this.MFAToken
}
).then(res => {
this.$emit('MFAVerifyDone', true)
})
}
}
}
</script>
<style scoped>
</style>

View File

@@ -61,10 +61,6 @@ const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
done()
reload()
this.$message.success(this.$t('common.deleteSuccessMsg'))
} catch (error) {
if (!error.response || !error.response.data || !error.response.data.msg) {
this.$message.error(this.$t('common.deleteErrorMsg') + ' ' + error)
}
} finally {
instance.confirmButtonLoading = false
}
@@ -149,6 +145,7 @@ export default {
v.fa = this.cleanValue(v, 'fa')
v.order = v.order || 100
v.tip = this.cleanValue(v, 'tip')
v.title = this.cleanValue(v, 'title')
return v
})
actions = actions.filter((v) => v.has)

View File

@@ -1,5 +1,12 @@
<template>
<el-link class="detail" :disabled="disabled" :type="col.type || 'success'" @click="goDetail">{{ iTitle }}</el-link>
<el-link
class="detail"
:disabled="disabled"
:type="col.type || 'info'"
@click="goDetail"
>
{{ iTitle }}
</el-link>
</template>
<script>

View File

@@ -106,35 +106,9 @@ export default {
handler(val) {
if (val && val.length > 0) {
const routeFilter = this.checkInTableColumns()
const routerSearch = routeFilter.search || {}
let routerSearchAttrs = []
if (typeof routerSearch?.value === 'string') {
routerSearchAttrs = routerSearch?.value?.split(',') || []
}
for (const attr of routerSearchAttrs) {
routeFilter[`search_${attr}`] = {
...routerSearch,
value: attr
}
}
if (routerSearchAttrs.length !== 0) {
delete routeFilter.search
}
const asFilterTags = _.cloneDeep(this.filterTags)
this.filterTags = {
...asFilterTags,
...routeFilter
}
if (Object.keys(routeFilter).length > 0) {
setTimeout(() => {
return this.$emit('tagSearch', this.filterMaps)
}, 490)
}
this.filterTagSearch(routeFilter)
}
},
immediate: true,
deep: true
}
},
@@ -149,43 +123,90 @@ export default {
methods: {
// 获取url中的查询条件判断是不是包含在当前查询条件里
checkInTableColumns() {
const searchFieldOptions = {}
const queryInfoValues = this.options.map((i) => i.value)
const routeQuery = this.getUrlQuery ? this.$route?.query : {}
const routeQueryKeys = Object.keys(routeQuery)
const routeQueryKeysLength = routeQueryKeys.length
const keys = {}
if (routeQueryKeysLength < 1) {
return keys
}
for (const [key, value] of Object.entries(routeQuery)) {
let valueDecode = decodeURI(value)
const isSearch = key !== 'search'
const curOptions = this.options || []
const routeQueryKeysLength = Object.keys(routeQuery).length
if (routeQueryKeysLength < 1) return searchFieldOptions
for (let k = 0, len = curOptions.length; k < len; k++) {
const cur = curOptions[k]
if (cur?.type === 'boolean') {
for (const [key, value] of Object.entries(routeQuery)) {
const valueDecode = decodeURI(value)
const isSearch = key === 'search'
if (isSearch) {
searchFieldOptions[key] = {
key,
label: '',
value: valueDecode
}
continue
}
if (queryInfoValues.includes(key)) {
searchFieldOptions[key] = this.getInQueryInfoFields(key, value)
}
}
return searchFieldOptions
},
getInQueryInfoFields(key, value) {
let searchFieldOption = {}
let valueDecode = decodeURI(value)
const currentOptions = this.options || []
for (let k = 0, len = currentOptions.length; k < len; k++) {
const current = currentOptions[k]
if (key === current.value) {
const curChildren = current.children || []
if (current?.type === 'boolean') {
valueDecode = !!valueDecode
}
if (key === cur.value || !isSearch) {
const curChildren = cur.children || []
keys[key] = {
...cur,
key,
label: isSearch ? cur.label : '',
value: valueDecode
}
if (isSearch && curChildren.length > 0) {
for (const item of curChildren) {
if (valueDecode === item.value) {
keys[key].valueLabel = item.label
break
}
searchFieldOption = {
...current,
key,
label: current.label,
value: valueDecode
}
if (curChildren.length > 0) {
for (const item of curChildren) {
if (valueDecode === item.value) {
searchFieldOption.valueLabel = item.label
break
}
}
}
break
}
}
return keys
return searchFieldOption
},
filterTagSearch(routeFilter) {
const routerSearch = routeFilter.search || {}
let routerSearchAttrs = []
if (typeof routerSearch?.value === 'string') {
routerSearchAttrs = routerSearch?.value?.split(',') || []
}
for (const attr of routerSearchAttrs) {
routeFilter[`search_${attr}`] = {
...routerSearch,
value: attr
}
}
if (routerSearchAttrs.length !== 0) {
delete routeFilter.search
}
const asFilterTags = _.cloneDeep(this.filterTags)
this.filterTags = {
...asFilterTags,
...routeFilter
}
if (Object.keys(routeFilter).length > 0) {
setTimeout(() => {
return this.$emit('tagSearch', this.filterMaps)
}, 490)
}
},
getValueLabel(key, value) {
for (const field of this.options) {

View File

@@ -113,12 +113,13 @@ export default {
float: right;
text-align: center;
padding: 5px 0;
background-color: #1ab394;
border-color: #1ab394;
background-color: var(--color-primary);
border-color: var(--color-primary);
color: #FFFFFF;
border-radius: 3px;
line-height: 1.428;
cursor:pointer;
height: 30px;
}
.el-tree{
background-color: inherit !important;
@@ -134,5 +135,8 @@ export default {
}
.transition-box.left {
background: #f3f3f3;
border: 1px solid #e0e0e0;
border-radius: 3px;
margin-right: 2px;
}
</style>

View File

@@ -0,0 +1,230 @@
<template>
<Dialog
:title="title"
:width="'36%'"
:show-confirm="false"
:show-cancel="false"
:visible.sync="visible"
:destroy-on-close="true"
v-bind="$attrs"
class="dialog-content"
v-on="$listeners"
>
<div v-if="ConfirmType === 'relogin'">
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24">
<el-alert
:title="this.$t('auth.ReLoginTitle')"
type="info"
center
:closable="false"
style="margin-bottom: 20px;"
/>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24">
<el-button
size="mini"
type="primary"
style="width: 100%; line-height:20px;"
@click="logOut"
>
{{ this.$t('auth.ReLogin') }}
</el-button>
</el-col>
</el-row>
</div>
<div v-else>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :span="24" :md="24" :sm="24" class="add">
<el-select
v-model="Select"
:disabled="ConfirmType === 'password'"
style="width: 100%; margin-bottom: 20px;"
@change="helpText(Select)"
>
<el-option
v-for="(item, i) of Content"
:key="i"
:label="item.display_name"
:value="item.name"
:disabled="item.disabled"
/>
</el-select>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24 - smsWidth" :sm="24">
<el-input v-model="SecretKey" :show-password="showPassword" :placeholder="HelpText" style="margin-bottom: 20px;" />
</el-col>
<el-col v-if="Select === 'sms'" :md="smsWidth" :sm="24">
<el-button
size="mini"
type="primary"
style="line-height:20px; float: right;"
:disabled="smsBtndisabled"
@click="sendChallengeCode"
>
{{ smsBtnText }}
</el-button>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24">
<el-button
size="mini"
type="primary"
style="width: 100%; line-height:20px;"
@click="userConfirm"
>
{{ this.$t('common.Confirm') }}
</el-button>
</el-col>
</el-row>
</div>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
export default {
name: 'UserConfirmDialog',
components: {
Dialog
},
props: {
url: {
type: String,
default: () => ''
}
},
data() {
return {
title: '',
smsWidth: 0,
Select: '',
Level: null,
HelpText: '',
smsBtnText: '',
smsBtndisabled: false,
ConfirmType: '',
Content: null,
SecretKey: '',
visible: false
}
},
computed: {
showPassword() {
if (this.ConfirmType === 'password') {
return true
}
return false
}
},
watch: {
visible(val) {
if (!val) {
this.$emit('UserConfirmCancel', true)
}
}
},
mounted() {
this.smsBtnText = this.$t('common.SendVerificationCode')
this.$axios.get(`${this.url}`, { disableFlashErrorMsg: true }).then(
() => { this.$emit('UserConfirmDone', true) }).catch((err) => {
const confirm_type = err.response.data.code
this.$axios.get('/api/v1/authentication/confirm/', { params: { confirm_type: confirm_type }}).then((data) => {
this.ConfirmType = data.confirm_type
this.Content = data.content
if (this.ConfirmType === 'relogin') {
this.$axios.post(
`/api/v1/authentication/confirm/`,
{
confirm_type: this.ConfirmType,
secret_key: ''
},
{ disableFlashErrorMsg: true },
).then(() => { this.$emit('UserConfirmDone', true) }).catch(() => {
this.title = this.$t('auth.NeedReLogin')
this.visible = true
})
return
}
if (this.ConfirmType === 'mfa') {
this.Select = this.Content.filter(item => !item.disabled)[0].name
if (this.Select === 'sms') {
this.smsWidth = 6
}
this.HelpText = this.Content.filter(item => !item.disabled)[0].placeholder
} else if (this.ConfirmType === 'password') {
this.Select = this.$t('setting.password')
this.HelpText = this.$t('common.PasswordRequireForSecurity')
this.Content = [{ 'name': 'password' }]
}
this.title = this.$t('common.CurrentUserVerify')
this.visible = true
})
})
},
methods: {
helpText(val) {
this.HelpText = this.Content.filter(item => item.name === val)[0]?.placeholder
if (val === 'sms') {
this.smsWidth = 6
} else {
this.smsWidth = 0
}
},
logOut() {
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
},
sendChallengeCode() {
this.$axios.post(
`/api/v1/authentication/mfa/select/`, {
type: 'sms'
}
).then(res => {
this.$message.success(this.$t('common.VerificationCodeSent'))
let time = 60
const interval = setInterval(() => {
this.smsBtnText = this.$t('common.Pending') + `: ${time}`
this.smsBtndisabled = true
time -= 1
if (time === 0) {
this.smsBtnText = this.$t('common.SendVerificationCode')
this.smsBtndisabled = false
clearInterval(interval)
}
}, 1000)
})
},
userConfirm() {
if (this.Select === 'otp' && this.SecretKey.length !== 6) {
return this.$message.error(this.$t('common.MFAErrorMsg'))
}
this.$axios.post(
`/api/v1/authentication/confirm/`, {
confirm_type: this.ConfirmType,
mfa_type: this.ConfirmType === 'password' ? undefined : this.Select,
secret_key: this.SecretKey
}
).then(res => {
this.$emit('UserConfirmDone', true)
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-content >>> .el-dialog__footer{
padding: 0;
}
.dialog-content >>> .el-dialog{
padding: 8px;
}
</style>

View File

@@ -25,6 +25,6 @@ export { default as UploadField } from './FormFields/UploadField'
export { default as AccountListTable } from './AccountListTable/index'
export { default as AppAccountListTable } from './AppAccountListTable'
export { default as AssetRelationCard } from './AssetRelationCard'
export { default as MFAVerifyDialog } from './MFAVerifyDialog'
export { default as UserConfirmDialog } from './UserConfirmDialog'
export { default as Announcement } from './Announcement'
export { default as CronTab } from './CronTab'

View File

@@ -31,7 +31,7 @@ function generateViewRoutesIfChange({ to, from }) {
function setPageTitle() {
const currentRoute = router.currentRoute
const loginTitle = store.getters.publicSettings['LOGIN_TITLE']
const loginTitle = store.getters.publicSettings['INTERFACE']['login_title']
const routeTitle = currentRoute.meta.title
if (routeTitle) {
document.title = routeTitle + ' - ' + loginTitle

View File

@@ -1,6 +1,7 @@
{
"": "",
"accounts": {
"AccountHistableHelpMessage": "Record the historical version of the current account",
"PleaseClickLeftAssetToViewAssetAccount": "Asset account list, please click on the assets on the left to view",
"PleaseClickLeftApplicationToViewApplicationAccount": "Application account list, please click on the application on the left to view",
"PleaseClickLeftAssetToViewGatheredUser": "Gathered user list, please click on the assets on the left to view"
@@ -97,6 +98,7 @@
"Action": "Action",
"ActiveSelected": "Active selected",
"AdminUser": "Admin user",
"AssetTree": "Asset tree",
"ReplaceNodeAssetsAdminUser":"Replace node assets admin user with this",
"AdminUserDetail": "Admin user detail",
"DynamicUsername": "Dynamic username",
@@ -125,7 +127,7 @@
"Charset": "Charset",
"CmdFilter": "CmdFilter",
"CommandFilterDetail": "Command filter detail",
"CommandFilterHelpMessage": "System user bound some command filter, each command filter has some rules, When user login asset with this system user, then run a command, The command will be filter by rules, higher priority rule run first, When a rule matched, if rule action is allow, then allow command execute, else if action is deny, then command with be deny, else match next rule, if none matched, allowed",
"CommandFilterHelpMessage": "The system user supports binding multiple command filters to achieve the effect of prohibiting the input of certain commands; multiple rules can be configured in the filter. When the system user is used to connect to the asset, the input command takes effect according to the priority of the rules configured in the filter. <br>Example: The first matched rule is \"Allow\", the command is executed, the first matched rule is \"Forbidden\", the command execution is prohibited; if the last rule is not matched, it is allowed to be executed.",
"CommandFilterRuleContentHelpText": "One line one command",
"CommandFilterRulePriorityHelpText": "1-100, the higher will be match first",
"CommandFilterRules": "Command filter rules",
@@ -246,10 +248,18 @@
},
"auth": {
"LoginRequiredMsg": "You account has logout, Please login again",
"ReLogin": "Re-Login"
"ReLogin": "Re-Login",
"ReLoginTitle": "The current three-party login user (cas/saml) is not bound to MFA and does not support password verification. Please login again",
"NeedReLogin": "Need Re-Login",
"ReLoginErr": "Login time has exceeded 5 minutes, please login again"
},
"common": {
"NeedAddAppsOrSystemUserErrMsg": "Please add apps or system user",
"VerificationCodeSent": "The verification code has been sent",
"SendVerificationCode": "Send verification code",
"History": "History",
"ChangeViewHelpText": "Click to change view",
"Component": "component",
"PrivateCloud": "Private cloud",
"PublicCloud": "Public cloud",
"Correlation": "Correlation",
@@ -268,6 +278,7 @@
"Database": "Database",
"Params": "Params",
"MFAVerify": "Verify MFA",
"CurrentUserVerify": "Verify Current User",
"ViewSecret": "View secret",
"ConnectWebSocketError": "Connect Websocket failed",
"Nothing": "Nothing",
@@ -421,6 +432,7 @@
"isValid": "Is valid",
"nav": {
"TempPassword": "Temporary password",
"ConnectionToken": "Connection token",
"APIKey": "API Key",
"Workbench": "Workbench",
"Navigation": "Navigation",
@@ -434,6 +446,7 @@
"Logout": "Logout",
"Profile": "Profile",
"Support": "Support",
"Download": "Download",
"UserPage": "User page",
"View": "View",
"EnterpriseEdition": "Enterprise edition"
@@ -503,6 +516,7 @@
},
"Cycle": "Cycle",
"FormatError": "Format error",
"NotSpecialEmoji": "Special emoticons are not allowed",
"WeekCronSelect": {
"Monday": "Monday",
"Tuesday": "Tuesday",
@@ -657,6 +671,7 @@
},
"route": {
"": "",
"AssignedTicketList": "Assigned tickets",
"CreateEndpoint": "Create endpoint",
"UpdateEndpoint": "Update endpoint",
"CreateEndpointRule": "Create endpoint rule",
@@ -675,6 +690,7 @@
"SessionDetail": "SessionDetail",
"Accounts": "Accounts",
"AssetAccount": "Asset Account",
"AssetHistoryAccount": "Asset History Account",
"ApplicationAccount": "Application Account",
"Ticket": "Tickets",
"CommandConfirm": "Command confirm",
@@ -692,7 +708,7 @@
"AssetPermissionUpdate": "Asset permissions update",
"AssetUpdate": "Asset update",
"Assets": "Assets",
"LogsAudits": "Logs audit",
"LogsAudit": "Logs audit",
"SessionsAudit": "Sessions audit",
"SessionList": "Session list",
"BatchCommand": "Batch Command",
@@ -889,7 +905,7 @@
"UseProtocol": "Use protocol",
"SessionState": "Session state",
"Monitor": "Monitor",
"XRDPNotSupport": "RDP Client session not support now",
"RazorNotSupport": "RDP Client session not support now",
"sessionMonitor": "Session Monitor",
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later",
"helpText": {
@@ -899,13 +915,17 @@
}
},
"setting": {
"OAuth2LogoTip": "Tip: Authentication Service Provider (recommended image size: 64px*64px)",
"EndpointListHelpMessage": "The service endpoint is the address (port) for the user to access the service. When the user connects to the asset, the service endpoint will be selected according to the endpoint rules and asset tags, and the connection will be established as the access entry to realize the distributed connection of assets.",
"EndpointRuleListHelpMessage": "For the service endpoint selection strategy, two types are currently supported: <br>1. Specify the endpoint according to the endpoint rule (current page); <br>2. Select the endpoint through the asset tag. The tag name is fixed to endpoint, and the value is the name of the `endpoint`. <br>Two methods preferentially use label matching, because the IP segment may conflict, and the label method exists as a supplement to the rules.",
"EnableKoKoSSHHelpText": "Enabled, connect assets to display SSH Client pull-up method",
"SettingInEndpointHelpText": "Configure the service address and port in System Settings / Terminal Settings / Service Endpoints",
"Feature": "Feature",
"SMSProvider": "SMS provider",
"SMSProvider": "SMS provider / Protocol",
"SMS": "SMS",
"AlibabaCloud": "Alibaba cloud",
"TencentCloud": "Tencent cloud",
"CMPP2": "CMPP v2.0",
"VerifySignTmpl": "Verification code template",
"Radius": "Radius",
"Enable": "Enable",
@@ -959,9 +979,12 @@
"authLdapServerUri": "LDAP server",
"authLdapUserAttrMap": "User attr map",
"authUserAttrMap": "User attr map",
"authUserAttrMapHelpText": "Mapping relationship { idp_key: sp_key}",
"authUserAttrMapHelpText": "The key on the left is the JumpServer user property, and the value on the right is the authenticated platform user property",
"SAML2": "SAML2",
"OAuth2": "OAuth2",
"enableSAML2Auth": "Enable SAML2 Auth",
"enableOAuth2Auth": "Enable OAuth2 Auth",
"tokenHTTPMethod": "Token Obtaining Method",
"SAML2Auth": "SAML2 Auth",
"authSAML2Xml": "IDP metadata XML",
"authSAML2MetadataUrl": "IDP metadata URL",
@@ -997,6 +1020,7 @@
"helpText": {
"TempPassword": "For a while, there is a period of 300 seconds, failure immediately after use",
"ApiKeyList": "The API key is used to sign the request header. The header of each request is different. Please refer to the usage documentation",
"ConnectionTokenList": "The connection token is a kind of authentication information that combines authentication and connection assets. It allows users to log in to assets with one click. Currently supported components include: KoKo, Lion, Magnus, Razor, etc.",
"authLdapSearchFilter": "Choice may be (cn|uid|sAMAccountName)=%(user)s)",
"authLdapSearchOu": "Use | split User OUs",
"authLdapUserAttrMap": "User attr map present how to map LDAP user attr to jumpserver, username, name, email is jumpserver attr",
@@ -1072,6 +1096,7 @@
"LicenseExpired": "License expired",
"LicenseWillBe": "License will expire at ",
"LicenseReachedAssetAmountLimit": "The number of assets has exceeded the license limit",
"LicenseForTest": "Testing license, This license is only for testing",
"Expire": "Expire",
"WeCom": "WeCom",
"DingTalk": "DingTalk",
@@ -1079,9 +1104,14 @@
"weComTest": "Test",
"FeiShu": "FeiShu",
"feiShuTest": "Test",
"setting": "Setting"
"setting": "Setting",
"SystemTools": "System Tools",
"basicTools": "Basic Tools",
"destinationIP": "Destination IP",
"testPort": "Test Port",
"testTools": "Test",
"testHelpText": "Please enter the destination address for testing"
},
"tickets": {
"PermissionName": "Permission name",
"Accept": "Accept",
@@ -1095,6 +1125,7 @@
"OpenTicket": "Open Ticket",
"HandleTicket": "Handle Ticket",
"FinishedTicket": "Finished Ticket",
"CheckViewAcceptor": "Click to view the acceptor",
"Assignees": "Assignees",
"Close": "Close",
"OpenStatus":"Open",
@@ -1286,6 +1317,7 @@
"SMS": "SMS"
},
"xpack": {
"Images": "Images",
"NavHelp": "Navigation Link",
"helpDocument": "Docs link",
"helpSupport": "Support link",
@@ -1380,6 +1412,7 @@
"OpenStack": "OpenStack",
"GCP": "Google Cloud Platform",
"FC": "Fusion Compute",
"LAN": "LAN",
"AWS_China": "AWS(China)",
"AWS_Int": "AWS(International)",
"HuaweiCloud": "Huawei Cloud",
@@ -1508,6 +1541,9 @@
"technologyConsult": "Technology Consult",
"RegularlyPerform": "Regularly perform",
"CyclePerform": "Cycle perform",
"ModifyTheme": "Modify theme",
"ClassicGreen": "Classic green",
"ChinaRed": "China red",
"HelpText": {
"CrontabOfCreateUpdatePage": "For example: every Sunday at 03:05 execute <5 3 * * 0> <br/> Using the 5-bit Linux crontab expression <minute hour day month week> (<a href=\"https://tool.lu/crontab/\" target=\"_blank\"> Online tool </a>) <br/> If both regularly perform and cycle perform execution are set, use regularly perform first",
"IntervalOfCreateUpdatePage": "Unit: hour",

View File

@@ -1,6 +1,7 @@
{
"": "",
"accounts": {
"AccountHistableHelpMessage": "現在のアカウントの履歴バージョンを記録する",
"PleaseClickLeftAssetToViewAssetAccount": "資産のアカウントのリスト、左側の資産をクリックして表示します",
"PleaseClickLeftApplicationToViewApplicationAccount": "アカウントのリストを適用して、左側のアプリケーションをクリックして表示します",
"PleaseClickLeftAssetToViewGatheredUser": "ユーザーリストを収集し、左側の資産をクリックして表示します。"
@@ -108,6 +109,7 @@
"HardwareInfo": "ハードウェア情報",
"AssetDetail": "アセットの詳細",
"AssetList": "アセットリスト",
"AssetTree": "アセットツリー",
"ReplaceNodeAssetsAdminUser": "ノード資産を置換する管理者",
"AssetListHelpMessage": "左側は資産ツリーで、右クリックはツリーノードを新規作成、削除、変更することができ、授権資産もノード方式で組織され、右側はそのノードの下に属する資産である\n",
"TestGatewayTestConnection": "テスト接続ゲートウェイ",
@@ -127,7 +129,7 @@
"Charset": "文字セット",
"CmdFilter": "コマンドフィルタ",
"CommandFilterDetail": "コマンドフィルタの詳細",
"CommandFilterHelpMessage": "システムユーザーはいくつかのコマンドフィルタバインドすることができ、一つのフィルタはいくつかのルールを定義することができます。ユーザーがこのシステムユーザーを使用して資産にログインし、一つのコマンドを実行するには、フィルタをバインドするすべてのルールが一致する必要があります優先度の高いものが先にマッチされ、ルールがマッチしたとき、ルールのアクションが許可されていれば、このコマンドは発行され、ルールのアクションが禁止されていれば、コマンド実行されなくなりますそれ以外の場合は次のルールがマッチし、最後ルールがマッチしない場合実行が許可されます",
"CommandFilterHelpMessage": "Xìtǒng yònghù zhīchí bǎng dìng duō gè mìnglìng guòlǜ qì shíxiàn jìnzhǐ shūrù mǒu xiē mìnglìng de xiàoguǒ; guòlǜ qì zhōng kě pèizhì duō gè guīzé, zài shǐyòng gāi xìtǒng yònghù liánjiē zīchǎn shí, shūrù de mìnglìng ànzhào guòlǜ qì zhōng pèizhì de guīzé yōuxiān jí shēngxiào; lì: Shǒuxiān pǐpèi dào de guīzé shì “yǔnxǔ”, zé gāi mìnglìng zhíxíng, shǒuxiān pǐpèi dào de guīzé wèi “jìnzhǐ”, zé jìnzhǐ gāi mìnglìng zhíxíng; rúguǒ zuìhòu wèi pǐpèi dào guīzé, zé yǔnxǔ zhíxíng.\n展开\n140 / 5,000\n翻译结果\nシステムユーザーは、複数のコマンドフィルターのバインドをサポートして、特定のコマンドの入力を禁止する効果を実現します。フィルターで複数のルールを構成できます。システムユーザーがアセットへの接続に使用される場合、入力コマンドは、フィルタで設定されたルール。<br>例:最初に一致したルールが「許可」の場合、コマンドが実行されます。最初に一致したルールが「禁止」の場合、コマンド実行が禁止されます。最後ルールが一致しない場合実行が許可されます",
"CommandFilterRuleContentHelpText": "各行のコマンド",
"CommandFilterRulePriorityHelpText": "優先度の選択範囲は1-100、1最低優先度、100最高優先度です",
"CommandFilterRules": "コマンドフィルタルール",
@@ -251,10 +253,18 @@
},
"auth": {
"LoginRequiredMsg": "アカウントが終了しました。ログインし直してください",
"ReLogin": "再ログイン"
"ReLogin": "再ログイン",
"ReLoginTitle": "現在、サードパーティのログインユーザーCAS/SAMLは、MFAをバインドしておらず、パスワードチェックをサポートしていません。再ログインしてください。",
"NeedReLogin": "再ログインが必要です",
"ReLoginErr": "ログイン時間が 5 分を超えました。もう一度ログインしてください"
},
"common": {
"NeedAddAppsOrSystemUserErrMsg": "アプリケーションまたはシステムユーザーを追加してください",
"VerificationCodeSent": "検証コードが送信されました",
"SendVerificationCode": "認証コードの送信",
"History": "歴史",
"ChangeViewHelpText": "クリックしてさまざまなビューにアクセス",
"Component": "コンポーネント",
"PrivateCloud": "プライベートクラウド",
"PublicCloud": "パブリッククラウド",
"Correlation": "関連",
@@ -276,6 +286,7 @@
"DateUpdated": "更新日",
"ApprovaLevel": "承認情報",
"MFAVerify": "MFAの検証",
"CurrentUserVerify": "現在のユーザー検証",
"ViewSecret": "パスワードの確認",
"ConnectWebSocketError": "Webソケット接続に失敗しました",
"Action": "アクション",
@@ -433,6 +444,7 @@
"isValid": "有効",
"nav": {
"TempPassword": "一時パスワード",
"ConnectionToken": "接続トークン",
"APIKey": "APIキー",
"Workbench": "作業台",
"Navigation": "ナビゲーション",
@@ -446,6 +458,7 @@
"Logout": "ログインを終了する",
"Profile": "個人情報",
"Support": "サポート",
"Download": "ダウンロード",
"UserPage": "ユーザービュー",
"View": "ビュー",
"EnterpriseEdition": "企業版"
@@ -479,6 +492,7 @@
"InvalidJson": "JSONの合法的ではありません",
"time_period": "時間帯",
"FormatError": "フォーマットエラー",
"NotSpecialEmoji": "特殊な表情記号の入力は許可されていません",
"WeekCronSelect": {
"Monday": "月曜日",
"Tuesday": "火曜日",
@@ -667,6 +681,7 @@
},
"route": {
"": "",
"AssignedTicketList": "割り当て済みワークオーダー",
"CreateEndpoint": "エンドポイントを作成する",
"UpdateEndpoint": "エンドポイントを更新",
"CreateEndpointRule": "エンドポイントルールを作成する",
@@ -687,6 +702,7 @@
"TicketFlowUpdate": "承認フローの更新",
"Accounts": "アカウント管理",
"AssetAccount": "資産アカウント",
"AssetHistoryAccount": "資産履歴",
"ApplicationAccount": "アプリアカウント",
"Ticket": "ワークオーダー",
"SessionDetail": "セッションの詳細",
@@ -910,7 +926,7 @@
"UseProtocol": "使用契約",
"SessionState": "セッションステータス",
"Monitor": "モニタリング",
"XRDPNotSupport": "RDPクライアントセッションは、監視をサポートしていません",
"RazorNotSupport": "RDPクライアントセッションは、監視をサポートしていません",
"sessionMonitor": "モニタリング",
"TerminateTaskSendSuccessMsg": "最終タスクが発行されました。後で更新して確認してください。",
"helpText": {
@@ -920,11 +936,15 @@
}
},
"setting": {
"OAuth2LogoTip": "ヒント: 認証サービス プロバイダー (推奨画像サイズ: 64px*64px)",
"EndpointListHelpMessage": "サービスエンドポイントは、ユーザーがサービスにアクセスするためのアドレス(ポート)です。ユーザーがアセットに接続すると、エンドポイントルールとアセットタグに従ってサービスエンドポイントが選択され、接続がアクセスエントリとして確立されます。資産の分散接続を実現します。",
"EndpointRuleListHelpMessage": "サービスエンドポイント選択戦略では、現在2つのタイプがサポートされています<br> 1. エンドポイントルールに従ってエンドポイントを指定します(現在のページ);<br>2. アセットタグを介してエンドポイントを選択します。タグ名はに固定されていますエンドポイントであり、値はエンドポイントの名前です。 <br> IPセグメントが競合する可能性があるため、2つの方法が優先的にラベル照合を使用し、ラベル方法はルールの補足として存在します。",
"EnableKoKoSSHHelpText": "有効にすると、アセットを接続してSSHクライアントのプルアップ方式を表示します",
"SettingInEndpointHelpText": "[システム設定]/[端末設定]/[サービスエンドポイント]でサービスアドレスとポートを構成します",
"Feature": "機能",
"AlibabaCloud": "Alibaba cloud",
"TencentCloud": "テンセント雲",
"CMPP2": "CMPP v2.0",
"Radius": "Radius",
"VerifySignTmpl": "認証コードメールテンプレート",
"Enable": "有効化",
@@ -982,9 +1002,11 @@
"authLdapServerUri": "LDAPアドレス",
"authLdapUserAttrMap": "ユーザー属性マッピング",
"authUserAttrMap": "ユーザー属性マッピング",
"authUserAttrMapHelpText": "マッピング関係 {idp:sp}",
"SAML2": "SAML2",
"authUserAttrMapHelpText": "左側のキーがJumpServerユーザ属性、右側の値が認証プラットフォームユーザ属性",
"OAuth2": "OAuth2",
"enableSAML2Auth": "SAML2認証をオンにする",
"enableOAuth2Auth": "OAuth2認証をオンにする",
"tokenHTTPMethod": "Token 取得方法",
"SAML2Auth": "SAML2認定",
"authSAML2Xml": "IDPメタデータXML",
"authSAML2MetadataUrl": "IDPメタデータURL",
@@ -1023,6 +1045,7 @@
"helpText": {
"TempPassword": "一時パスワードの有効期間は300秒で、使用後すぐに失効します",
"ApiKeyList": "Api keyを使用してリクエストヘッダに署名します。リクエストのヘッダごとに異なります。使用ドキュメントを参照してください",
"ConnectionTokenList": "接続トークンは、認証アセットと接続アセットを組み合わせた一種の認証情報であり、ユーザーはワンクリックでアセットにログインできます。現在サポートされているコンポーネントには、KoKo、Lion、Magnus、Razorなどがあります。",
"authLdapSearchFilter": "可能なオプションは (cnまたはuidまたはsamaccount tname = %(user)s) です",
"authLdapSearchOu": "| を使用して各OUを区切る",
"authLdapUserAttrMap": "ユーザー属性マッピングは、LDAPのユーザー属性をjumpserverユーザーにマッピングする方法を表します。username、name、emailはjumpserverの属性です",
@@ -1100,6 +1123,7 @@
"LicenseExpired": "ライセンスが期限切れです",
"LicenseWillBe": "ライセンスはまもなく",
"LicenseReachedAssetAmountLimit": "アセットの数がライセンス制限を超えました",
"LicenseForTest": "試験用ライセンス本ライセンスは試験用にのみ使用されます",
"Expire": "期限切れ",
"WeCom": "企業wechat",
"DingTalk": "ホッチキス",
@@ -1109,7 +1133,13 @@
"SMS": "SMS設定",
"feiShuTest": "テスト",
"setting": "設定",
"SMSProvider": "メールサービス業者"
"SystemTools": "システムツール",
"basicTools": "基本的なツール",
"destinationIP": "宛先アドレス",
"testPort": "テストポート",
"testTools": "テスト",
"testHelpText": "テストの宛先アドレスを入力してください",
"SMSProvider": "メールサービス業者 / プロトコル"
},
"tickets": {
"OneAssigneeType": "一次受付者タイプ",
@@ -1151,6 +1181,7 @@
"OpenTicket": "ワークオーダーの作成",
"HandleTicket": "作業指示の処理",
"FinishedTicket": "ワークオーダーの完了",
"CheckViewAcceptor": "クリックして受付人を表示",
"IP": "IP",
"Hostname": "ホスト名",
"Asset": "資産",
@@ -1326,6 +1357,7 @@
"SMS": "Sms"
},
"xpack": {
"Images": "画像",
"NavHelp": "ナビゲーションバーのリンク",
"helpDocument": "ドキュメントリンク",
"helpSupport": "サポートリンク",
@@ -1423,6 +1455,7 @@
"OpenStack": "OpenStack",
"GCP": "Googleクラウド",
"FC": "Fusion Compute",
"LAN": "ローカルエリアネットワーク",
"AWS_China": "AWS(中国)",
"AWS_Int": "AWS (国際)",
"HuaweiCloud": "ファーウェイ雲",
@@ -1554,6 +1587,9 @@
"technologyConsult": "技術コンサルティング",
"RegularlyPerform": "定期的に実行する",
"CyclePerform": "サイクル実行",
"ModifyTheme": "テーマを変更",
"ClassicGreen": "クラシックグリーン",
"ChinaRed": "チャイナレッド",
"HelpText": {
"CrontabOfCreateUpdatePage": "例: 毎週日曜日03:05に <5 3 * * 0> <br/> 5桁のLinux crontab式を使用して、時分割日月曜日> (<a href = \"https://tool.lu/crontab/\" target = \"_ ツール </a>) <br/> 定期実行とサイクル実行を同時に設定している場合は、優先的に定期実行を使って",
"IntervalOfCreateUpdatePage": "単位: 時",

View File

@@ -1,6 +1,7 @@
{
"": "",
"accounts": {
"AccountHistableHelpMessage": "记录当前账号的历史版本",
"PleaseClickLeftAssetToViewAssetAccount": "资产账号列表,点击左侧资产进行查看",
"PleaseClickLeftApplicationToViewApplicationAccount": "应用账号列表,点击左侧应用进行查看",
"PleaseClickLeftAssetToViewGatheredUser": "收集用户列表,点击左侧资产进行查看"
@@ -109,6 +110,7 @@
"AssetDetail": "资产详情",
"AssetList": "资产列表",
"ReplaceNodeAssetsAdminUser":"替换节点资产的管理员",
"AssetTree": "资产树",
"AssetListHelpMessage": "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,右侧是属于该节点下的资产\n",
"TestGatewayTestConnection":"测试连接网关",
"TestGatewayHelpMessage": "如果使用了nat端口映射请设置为ssh真实监听的端口",
@@ -127,7 +129,7 @@
"Charset": "字符集",
"CmdFilter": "命令过滤器",
"CommandFilterDetail": "命令过滤器详情",
"CommandFilterHelpMessage": "系统用户可以绑定一些命令过滤器,一个过滤器可以定义一些规则 当用户使用这个系统用户登录资产,然后执行一个命令 这个命令需要被绑定过滤器的所有规则匹配,高优先级先被匹配, 当一个规则匹配到了,如果规则的动作是允许,这个命令会被放行, 如果规则的动作是禁止,命令将会被禁止执行, 否则就匹配下一个规则,如果最后没有匹配到规则,则允许执行",
"CommandFilterHelpMessage": "系统用户支持绑定多个命令过滤器实现禁止输入某些命令的效果;过滤器中可配置多个规则,在使用该系统用户连接资产时,输入的命令按照过滤器中配置的规则优先级生效。<br>例:首先匹配到的规则是“允许”,则该命令执行,首先匹配到的规则为“禁止”,则禁止该命令执行;如果最后匹配到规则,则允许执行",
"CommandFilterRuleContentHelpText": "每行一个命令",
"CommandFilterRulePriorityHelpText": "优先级可选范围为1-1001最低优先级100最高优先级",
"CommandFilterRules": "命令过滤器规则",
@@ -251,9 +253,16 @@
},
"auth": {
"LoginRequiredMsg": "账号已退出,请重新登录",
"ReLogin": "重新登录"
"ReLogin": "重新登录",
"ReLoginTitle": "当前三方登录用户CAS/SAML未绑定 MFA 且不支持密码校验,请重新登录。",
"NeedReLogin": "需要重新登录",
"ReLoginErr": "登录时长已超过 5 分钟,请重新登录"
},
"common": {
"NeedAddAppsOrSystemUserErrMsg": "需要添加应用或系统用户",
"VerificationCodeSent": "验证码已发送",
"SendVerificationCode": "发送验证码",
"History": "历史",
"ChangeViewHelpText": "点击切换不同视图",
"Component": "组件",
"PrivateCloud": "私有云",
@@ -277,6 +286,7 @@
"DateUpdated": "更新日期",
"ApprovaLevel": "审批信息",
"MFAVerify": "验证 MFA",
"CurrentUserVerify": "验证当前用户",
"ViewSecret": "查看密码",
"ConnectWebSocketError": "连接 WebSocket 失败",
"Action": "动作",
@@ -434,6 +444,7 @@
"isValid": "有效",
"nav": {
"TempPassword": "临时密码",
"ConnectionToken": "连接令牌",
"APIKey": "API Key",
"Workbench": "工作台",
"Navigation": "导航",
@@ -447,6 +458,7 @@
"Logout": "退出登录",
"Profile": "个人信息",
"Support": "支持",
"Download": "下载",
"UserPage": "用户视图",
"View": "视图",
"EnterpriseEdition": "企业版"
@@ -480,6 +492,7 @@
"InvalidJson": "不是合法 JSON",
"time_period": "时段",
"FormatError": "格式错误",
"NotSpecialEmoji": "不允许输入特殊表情符号",
"WeekCronSelect": {
"Monday": "星期一",
"Tuesday": "星期二",
@@ -688,8 +701,11 @@
"TicketFlowUpdate": "更新审批流",
"Accounts": "账号管理",
"AssetAccount": "资产账号",
"AssetHistoryAccount": "资产历史账号",
"ApplicationAccount": "应用账号",
"Ticket":"工单",
"MyTickets": "我的申请",
"AssignedTicketList": "待我审批",
"SessionDetail": "会话详情",
"CommandConfirm": "命令复核",
"AdminUserCreate": "创建管理用户",
@@ -911,7 +927,7 @@
"UseProtocol": "使用协议",
"SessionState": "会话状态",
"Monitor": "监控",
"XRDPNotSupport": "RDP 客户端会话, 暂不支持监控",
"RazorNotSupport": "RDP 客户端会话, 暂不支持监控",
"sessionMonitor": "监控",
"TerminateTaskSendSuccessMsg": "终断任务已下发,请稍后刷新查看",
"helpText": {
@@ -921,11 +937,15 @@
}
},
"setting": {
"OAuth2LogoTip": "提示:认证服务提供商(建议图片大小为: 64px*64px",
"EndpointListHelpMessage": "服务端点是用户访问服务的地址(端口),当用户在连接资产时,会根据端点规则和资产标签选择服务端点,作为访问入口建立连接,实现分布式连接资产",
"EndpointRuleListHelpMessage": "对于服务端点选择策略,目前支持两种:<br>1、根据端点规则指定端点(当前页面)<br>2、通过资产标签选择端点标签名固定是 endpoint值是端点的名称。<br>两种方式优先使用标签匹配,因为 IP 段可能冲突,标签方式是作为规则的补充存在的。",
"EnableKoKoSSHHelpText": "开启时连接资产会显示 SSH Client 拉起方式",
"SettingInEndpointHelpText": "在 系统设置 / 终端设置 / 服务端点 中配置服务地址和端口",
"Feature": "功能",
"AlibabaCloud": "阿里云",
"TencentCloud": "腾讯云",
"CMPP2": "CMPP v2.0",
"Radius": "Radius",
"VerifySignTmpl": "验证码短信模板",
"Enable": "启用",
@@ -983,9 +1003,10 @@
"authLdapServerUri": "LDAP地址",
"authLdapUserAttrMap": "用户属性映射",
"authUserAttrMap": "用户属性映射",
"authUserAttrMapHelpText": "映射关系 {idpsp}",
"SAML2": "SAML2",
"enableSAML2Auth": "开启 SAML2 认证",
"authUserAttrMapHelpText": "左侧的键为 JumpServer 用户属性,右侧的值为认证平台用户属性",
"OAuth2": "OAuth2",
"enableOAuth2Auth": "开启 OAuth2 认证",
"tokenHTTPMethod": "Token 获取方法",
"SAML2Auth": "SAML2 认证",
"authSAML2Xml": "IDP metadata XML",
"authSAML2MetadataUrl": "IDP metadata URL",
@@ -1024,6 +1045,7 @@
"helpText": {
"TempPassword": "临时密码有效期为 300 秒,使用后立刻失效",
"ApiKeyList": "使用api key签名请求头每个请求的头部是不一样的, 请查阅使用文档",
"ConnectionTokenList": "连接令牌是将身份验证和连接资产结合起来使用的一种认证信息支持用户一键登录到资产目前支持的组件包括KoKo、Lion、Magnus、Razor 等",
"authLdapSearchFilter": "可能的选项是(cn或uid或sAMAccountName=%(user)s)",
"authLdapSearchOu": "使用|分隔各OU",
"authLdapUserAttrMap": "用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上username, name,email 是jumpserver的属性",
@@ -1101,6 +1123,7 @@
"LicenseExpired": "许可证已经过期",
"LicenseWillBe": "许可证即将在 ",
"LicenseReachedAssetAmountLimit": "资产数量已经超过许可证数量限制",
"LicenseForTest": "测试用途许可证, 本许可证仅用于 开发、测试PoC和演示",
"Expire": " 过期",
"WeCom": "企业微信",
"DingTalk": "钉钉",
@@ -1110,7 +1133,14 @@
"SMS": "短信设置",
"feiShuTest": "测试",
"setting": "设置",
"SMSProvider": "短信服务商"
"SMSProvider": "短信服务商",
"SystemTools": "系统工具",
"basicTools": "基本工具",
"destinationIP": "目的地址",
"testPort": "端口",
"testTools": "测试",
"testHelpText": "请输入目的地址进行测试",
"SMSProvider": "短信服务商 / 协议"
},
"tickets": {
"OneAssigneeType": "一级受理人类型",
@@ -1132,8 +1162,8 @@
"Assignee": "处理人",
"Assignees": "待处理人",
"Close": "关闭",
"OpenStatus":"开启",
"CloseStatus":"关闭",
"OpenStatus":"审批中",
"CloseStatus":"已完成",
"Comment": "备注",
"MyTickets": "我发起的",
"RequestPerm":"授权申请",
@@ -1152,6 +1182,7 @@
"OpenTicket": "创建工单",
"HandleTicket": "处理工单",
"FinishedTicket": "完成工单",
"CheckViewAcceptor": "点击查看受理人",
"IP": "IP",
"Hostname": "主机名",
"Asset": "资产",
@@ -1327,6 +1358,7 @@
"SMS": "短信"
},
"xpack": {
"Images": "图片",
"NavHelp": "导航栏链接",
"helpDocument": "文档链接",
"helpSupport": "支持链接",
@@ -1424,6 +1456,7 @@
"OpenStack": "OpenStack",
"GCP": "谷歌云",
"FC": "Fusion Compute",
"LAN": "局域网",
"AWS_China": "AWS(中国)",
"AWS_Int": "AWS(国际)",
"HuaweiCloud": "华为云",
@@ -1510,7 +1543,7 @@
"NoLicense": "暂无许可证",
"Node": "节点",
"Organization": {
"AllOrganization": "所有组织",
"AllOrganization": "组织列表",
"OrganizationCreate": "创建组织",
"OrganizationLists": "组织列表",
"OrganizationDetail": "组织详情",
@@ -1555,6 +1588,9 @@
"technologyConsult": "技术咨询",
"RegularlyPerform": "定期执行",
"CyclePerform": "周期执行",
"ModifyTheme": "修改主题",
"ClassicGreen": "经典绿",
"ChinaRed": "中国红",
"HelpText": {
"CrontabOfCreateUpdatePage": "例如:每周日 03:05 执行 <5 3 * * 0> <br/> 使用5位 Linux crontab 表达式 <分 时 日 月 星期> <a href=\"https://tool.lu/crontab/\" target=\"_blank\">在线工具</a> <br/> 如果同时设置了定期执行和周期执行,优先使用定期执行",
"IntervalOfCreateUpdatePage": "单位:时",

View File

@@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1645509697274" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2361" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M867.046319 156.952658 156.952658 156.952658c-49.040926 0-88.317465 39.720653-88.317465 88.76158l-0.444115 532.570501c0 49.040926 39.720653 88.76158 88.76158 88.76158l710.09366 0c49.040926 0 88.76158-39.720653 88.76158-88.76158L955.807898 245.714238C955.808922 196.673311 916.087245 156.952658 867.046319 156.952658zM867.046319 334.476841l-355.047342 221.903949-355.047342-221.903949 0-88.76158 355.047342 221.903949 355.047342-221.903949L867.046319 334.476841z" p-id="2362"></path></svg>
<svg t="1659513943772" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5163" width="200" height="200"><path d="M1024 146.285714v731.428572H0V146.285714h1024z m-149.942857 94.573715L512 602.88l-362.057143-362.057143L98.267429 292.571429 512 706.340571 925.769143 292.571429l-51.748572-51.712z" fill="#7c7e7f" p-id="5164"></path></svg>

Before

Width:  |  Height:  |  Size: 865 B

After

Width:  |  Height:  |  Size: 377 B

View File

@@ -1,11 +1,9 @@
<template>
<div class="footer" :style="style">
<div class="pull-right">
Version <strong> dev </strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
</div>
<div style="padding-left:20px;">
{{ publicSettings.XPACK_LICENSE_INFO.corporation }}
<div class="footer" :class="device" :style="style">
<div class="pull-right version">
Version <strong> dev </strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv3. </span>
</div>
<div>{{ corporation }}</div>
</div>
</template>
<script>
@@ -27,7 +25,10 @@ export default {
if (this.device === 'mobile') {
return ''
}
return this.sidebar.opened ? ('margin-left: 210px;') : ('margin-left: 54px')
return this.sidebar.opened ? ('margin-left: 220px;') : ('margin-left: 54px')
},
corporation() {
return this.publicSettings.XPACK_LICENSE_INFO.corporation
}
}
}
@@ -38,9 +39,9 @@ export default {
height: 35px !important;
}
.pull-right {
float: right!important;
float: right
}
.footer{
.footer {
position: fixed;
bottom: 0;
left: 0;
@@ -55,4 +56,11 @@ export default {
font-size: 13px;
}
}
.mobile.footer {
text-align: center;
}
.mobile.footer .pull-right{
float: none;
display: block;
}
</style>

View File

@@ -89,7 +89,7 @@ export default {
createSuccessNextRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Create', 'List')
const routeName = this.$route.name?.replace('Create', 'List')
return { name: routeName }
}
},
@@ -97,15 +97,14 @@ export default {
updateSuccessNextRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Update', 'List')
const routeName = this.$route.name?.replace('Update', 'List')
return { name: routeName }
}
},
objectDetailRoute: {
type: Object,
default: function() {
const routeName = this.$route.name
.replace('Update', 'Detail')
const routeName = this.$route.name?.replace('Update', 'Detail')
.replace('Create', 'Detail')
return { name: routeName }
}
@@ -138,6 +137,16 @@ export default {
if (params.id) {
url = getUpdateObjURL(url, params.id)
}
const clone_from = this.$route.query['clone_from']
const query = clone_from ? `clone_from=${clone_from}` : ''
if (query) {
if (url.indexOf('?') === -1) {
url = `${url}?${query}`
} else {
url = `${url}&${query}`
}
}
return url
}
},

View File

@@ -197,6 +197,10 @@ export default {
if (typeof route === 'string') {
route = { name: route, params: {}}
}
route = {
...route,
query: this.$route.query || {}
}
route.params.id = id
this.$router.push(route)
},

View File

@@ -16,6 +16,9 @@
<el-dropdown-item v-if="$store.getters.publicSettings.AUTH_TEMP_TOKEN && $hasPerm('authentication.view_temptoken')" icon="el-icon-magic-stick" command="tempPassword">
{{ $t('common.nav.TempPassword') }}
</el-dropdown-item>
<el-dropdown-item v-if="$hasPerm('authentication.view_connectiontoken')" icon="el-icon-place" command="connectionToken">
{{ $t('common.nav.ConnectionToken') }}
</el-dropdown-item>
<el-dropdown-item divided command="logout"><svg-icon icon-class="logout" style="margin-right: 4px" />
{{ $t('common.nav.Logout') }}
</el-dropdown-item>
@@ -57,6 +60,9 @@ export default {
break
case 'tempPassword':
this.$router.push('/profile/temp-password')
break
case 'connectionToken':
this.$router.push('/profile/connection-token')
}
},
logout() {
@@ -67,8 +73,8 @@ export default {
<style scoped>
.header-avatar {
height: 30px;
width: 30px;
height: 24px;
width: 24px;
margin-right: 5px;
vertical-align: middle;
}

View File

@@ -6,6 +6,7 @@
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="docs">{{ $t('common.nav.Docs') }}</el-dropdown-item>
<el-dropdown-item command="support">{{ $t('common.nav.Support') }}</el-dropdown-item>
<el-dropdown-item command="toolsDownload">{{ $t('common.nav.Download') }}</el-dropdown-item>
<el-dropdown-item v-if="!hasLicence" command="enterprise">{{ $t('common.nav.EnterpriseEdition') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@@ -43,6 +44,9 @@ export default {
case 'enterprise':
window.open('https://jumpserver.org/enterprise.html', '_blank')
break
case 'toolsDownload':
window.open('/core/download/', '_blank')
break
default:
window.open(this.URLSite.HELP_DOCUMENT_URL, '_blank')
break

View File

@@ -121,7 +121,7 @@ export default {
</script>
<style lang="scss" scoped>
@import '~@/styles/element-variables.scss';
@import '~@/styles/variables.scss';
.org-select {
padding: 0 10px 0 18px;

View File

@@ -31,18 +31,20 @@
@mouseleave="hoverMsgId = ''"
@click="showMsgDetail(msg)"
>
<div class="msg-item-head">
<span class="msg-item-head-type">
<el-row :gutter="10" class="msg-item-head">
<el-col :span="15" class="msg-item-head-type">
<i :class="msg['has_read'] ? 'fa-envelope-open-o' : 'fa-envelope'" class="fa msg-icon" />
{{ msg.subject }}
</span>
<span v-if="hoverMsgId !== msg.id || msg['has_read']" class="msg-item-head-time">
{{ formatDate(msg.date_created) }}
</span>
<div v-else class="msg-item-read-btn" @click.stop="markAsRead([msg])">
<a>{{ $t('notifications.MarkAsRead') }}</a>
</div>
</div>
</el-col>
<el-col :span="9">
<span v-if="hoverMsgId !== msg.id || msg['has_read']" class="msg-item-head-time">
{{ formatDate(msg.date_created) }}
</span>
<span v-else class="msg-item-read-btn" @click.stop="markAsRead([msg])">
<a>{{ $t('notifications.MarkAsRead') }}</a>
</span>
</el-col>
</el-row>
<div class="msg-item-txt">
<span v-html="msg.message" />
</div>
@@ -96,7 +98,7 @@ export default {
},
computed: {
width() {
return this.$store.state.app.device === 'mobile' ? '70%' : '20%'
return this.$store.state.app.device === 'mobile' ? '70%' : '380px'
}
},
mounted() {
@@ -270,7 +272,7 @@ export default {
.msg-item-head-type {
float: left;
width: 220px;
//width: 220px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
@@ -307,6 +309,9 @@ export default {
.msg-detail-txt {
margin-bottom: 20px;
line-height: 25px;
&>>> a {
color: var(--color-success)!important;
}
}
}

View File

@@ -96,7 +96,7 @@ export default {
if (this.mode !== 'horizontal') {
return false
}
if (this.views.length < 2) {
if (this.views.length < 1) {
return false
}
if (this.tipHasRead) {
@@ -109,6 +109,11 @@ export default {
}
}
},
created() {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile/i.test(navigator.userAgent)) {
this.showTip = false
}
},
methods: {
async handleSelectView(key, keyPath) {
const routeName = this.viewsMapper[key] || '/'

View File

@@ -87,20 +87,27 @@ export default {
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
$header-height: 55px;
.navbar {
position: relative;
height: 55px;
height: $header-height;
line-height: $header-height;
overflow: hidden;
background: #f3f3f4;
.navbar-left {
float: left;
.left-item {
line-height: 55px;
line-height: $header-height;
display: inline-block;
vertical-align: middle;
&>>> .el-submenu__title {
font-family: "open sans","Helvetica Neue",Helvetica,Arial,sans-serif;
padding: 0 14px;
padding: 0 8px;
line-height: $header-height;
height: $header-height;
}
&>>> .org-select {
padding: 0;
@@ -110,15 +117,17 @@ export default {
.navbar-right {
float: right;
margin-right: 10px;
height: 55px;
line-height: 55px;
.header-hover {
line-height: 56px!important;
&:hover {
background-color: #e6e6e6;
}
}
.header-item {
line-height: 55px;
line-height: $header-height;
display: inline-block;
padding-right: 10px;
padding-left: 10px;
@@ -156,8 +165,8 @@ export default {
padding: 0 10px!important;
line-height: 30px;
border-radius: 4px;
border-color: #1ab394;
background-color: #1ab394;
border-color: $--color-primary;
background-color: $--color-primary;
color: #fff;
cursor: pointer;
transition: .2s;

View File

@@ -31,10 +31,10 @@ export default {
]),
// eslint-disable-next-line vue/return-in-computed-property
logoTextSrc() {
return this.publicSettings.LOGO_URLS.logo_index
return this.publicSettings['INTERFACE']['logo_index']
},
logoSrc() {
return this.publicSettings.LOGO_URLS.logo_logout
return this.publicSettings['INTERFACE']['logo_logout']
}
},
created() {

View File

@@ -6,13 +6,26 @@
</div>
<div class="active-mobile">
<ViewSwitcher mode="vertical" class="mobile-view-switch" />
<Organization class="organization" />
<Organization v-if="$hasLicense()" class="organization" />
</div>
<div class="nav-title" :class="{'collapsed': isCollapse}">
{{ isTitle }}
<svg-icon
v-if="isRouteMeta.view === 'settings'"
icon-class="setting-fill"
style="margin-right: 0;"
/>
<i
v-else
class="fa"
:class="isRouteMeta.icon"
/>
<span
v-show="!isCollapse"
style="margin-left: 3px;"
>{{ isRouteMeta.title || '' }}</span>
</div>
</div>
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-scrollbar class="menu-wrap" wrap-class="scrollbar-wrapper">
<el-menu
class="left-menu"
:default-active="activeMenu"
@@ -45,10 +58,10 @@
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'
import Hamburger from '@/components/Hamburger'
import ViewSwitcher from '../NavHeader/ViewSwitcher'
import Organization from '../NavHeader/Organization'
import variables from '@/styles/variables.scss'
export default {
components: {
@@ -98,8 +111,8 @@ export default {
isCollapse() {
return !this.sidebar.opened
},
isTitle() {
return this.currentViewRoute.meta?.title || ''
isRouteMeta() {
return this.currentViewRoute.meta || {}
}
},
methods: {
@@ -110,8 +123,10 @@ export default {
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
.nav-header {
background-image: url('~@/assets/img/header-profile.png');
overflow: hidden;
background: $subMenuBg url('~@/assets/img/header-profile.png') no-repeat center center;
}
.nav-logo {
@@ -120,16 +135,17 @@ export default {
.nav-title {
box-sizing: border-box;
height: 55px;
padding: 17px 0 17px 22px;
margin: 17px 0 17px 20px;
font-size: 15px;
font-weight: 460;
color: #fff;
//background: #293846;
overflow: hidden;
white-space: nowrap;
cursor: pointer;
}
.collapsed {
padding: 6px 12px!important;
text-align: left;
}
.organizations {
@@ -140,7 +156,7 @@ export default {
display: block;
width: 100%;
height: 40px;
background-color: #293846;
background-color: $subMenuBg;
.toggle-bar {
width: 55px;
@@ -155,7 +171,7 @@ export default {
}
.toggle-bar:hover {
background-color: rgb(59, 76, 91);
background-color: $subMenuHover;
}
.hamburger-container {

View File

@@ -1,10 +1,10 @@
<template>
<div v-if="!loading">
<el-alert v-if="isExpire" type="error">
{{ isExpire }}
</el-alert>
<el-alert v-if="reachedAssetAmountLimit" type="error">
{{ reachedAssetAmountLimit }}
<el-alert v-if="licenseMsg" type="error">
{{ licenseMsg }} !
<router-link :to="{ name: 'License' }" style="padding-left: 5px">
{{ $t('common.View') }} <i class="fa fa-external-link" />
</router-link>
</el-alert>
</div>
</template>
@@ -26,8 +26,15 @@ export default {
'publicSettings',
'currentUser'
]),
isExpire() {
if (!this.publicSettings.XPACK_ENABLED || !this.$hasPerm('settings.change_license')) {
licenseMsg() {
if (this.expireMsg) {
return this.expireMsg
} else {
return this.reachLimitsMsg
}
},
expireMsg() {
if (!this.publicSettings['XPACK_ENABLED'] || !this.$hasPerm('settings.change_license')) {
return false
}
const intervalDays = this.getIntervalDays(this.licenseData.date_expired)
@@ -39,10 +46,13 @@ export default {
}
return false
},
reachedAssetAmountLimit() {
if (!this.publicSettings.XPACK_ENABLED || !this.$hasPerm('settings.change_license')) {
reachLimitsMsg() {
if (!this.publicSettings['XPACK_ENABLED'] || !this.$hasPerm('settings.change_license')) {
return false
}
if (this.licenseData.corporation === 'FIT2CLOUD') {
return this.$t('setting.LicenseForTest')
}
if (this.licenseData['current_asset_count'] > this.licenseData.asset_count) {
return this.$t('setting.LicenseReachedAssetAmountLimit')
}
@@ -50,7 +60,7 @@ export default {
}
},
mounted() {
if (this.publicSettings.XPACK_ENABLED && this.$hasPerm('settings.change_license')) {
if (this.publicSettings['XPACK_ENABLED'] && this.$hasPerm('settings.change_license')) {
this.$axios.get('/api/v1/xpack/license/detail').then(res => {
this.licenseData = res
}).finally(() => {

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-alert v-if="isExpire" type="error">
{{ isExpire }}
<el-alert v-if="expireMsg" type="error">
{{ expireMsg }}
</el-alert>
</div>
</template>
@@ -22,7 +22,7 @@ export default {
'publicSettings',
'currentUser'
]),
isExpire() {
expireMsg() {
// 用户来源不是Local时不显示密码过期提示
if (this.currentUser.source !== 'local') {
return false
@@ -33,7 +33,9 @@ export default {
return this.$t('users.passwordExpired')
}
if (securityPasswordExpirationTime - intervalTime <= 5) {
return this.$t('users.passwordWillExpiredPrefixMsg') + (securityPasswordExpirationTime - intervalTime) + this.$t('users.passwordWillExpiredSuffixMsg')
return this.$t('users.passwordWillExpiredPrefixMsg') +
(securityPasswordExpirationTime - intervalTime) +
this.$t('users.passwordWillExpiredSuffixMsg')
}
return false
}

View File

@@ -200,6 +200,7 @@ export default {
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
.tags-view-container {
height: 34px;
width: 100%;
@@ -228,9 +229,9 @@ export default {
margin-right: 15px;
}
&.active {
background-color: #1AB394;
background-color: $--color-primary;
color: #fff;
border-color: #1AB394;
border-color: $--color-primary;
&::before {
content: "";
background: #fff;

View File

@@ -3,9 +3,7 @@ import Vue from 'vue'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'elementCss'
import locale from 'elementLocale'
import '@/styles/index.scss' // global css
import App from './App'

View File

@@ -21,6 +21,16 @@ export default [
app: 'assets',
permissions: ['assets.view_authbook']
}
},
{
path: 'history',
name: 'AssetAccountHistoryList',
component: () => import('@/views/accounts/AssetAccount/AssetAccountHistoryList'),
hidden: true,
meta: {
title: i18n.t('route.AssetHistoryAccount'),
permissions: ['assets.view_assethistoryaccount']
}
}
]
},

View File

@@ -62,7 +62,18 @@ export default {
title: i18n.t('common.nav.TempPassword'),
icon: 'magic',
hidden: ({ settings }) => !settings['AUTH_TEMP_TOKEN'],
permissions: ['authentication.view_temptoken']
permissions: ['authentication.view_temptoken'],
activeMenu: '/profile/temp-password'
}
},
{
path: '/profile/connection-token',
component: () => import('@/views/profile/ConnectionToken'),
name: 'ConnectionToken',
meta: {
title: i18n.t('common.nav.ConnectionToken'),
icon: 'map-pin',
permissions: ['authentication.view_connectiontoken']
}
}
]

View File

@@ -295,6 +295,16 @@ export default {
permissions: ['settings.change_other']
}
},
{
path: '/settings/tools',
name: 'Tools',
component: () => import('@/views/settings/Tools'),
meta: {
title: i18n.t('setting.SystemTools'),
icon: 'wrench',
permissions: ['settings.view_setting']
}
},
{
path: '/settings/license',
name: 'License',

View File

@@ -4,11 +4,11 @@ import i18n from '@/i18n/i18n'
export default {
path: '/tickets',
redirect: '/tickets/tickets',
redirect: '/tickets/my-tickets',
component: Layout,
meta: {
title: i18n.t('route.Tickets'),
icon: 'check-square-o',
icon: 'fa-check-square-o',
view: 'tickets',
type: 'view',
showNavSwitcher: false,
@@ -17,26 +17,40 @@ export default {
permissions: ['tickets.view_ticket']
},
children: [
{
path: '/tickets/my-tickets',
name: 'MyTicketList',
component: () => import('@/views/tickets/MyTicketList'),
meta: {
title: i18n.t('tickets.MyTickets'),
icon: 'file-text-o',
showOrganization: false,
permissions: []
}
},
{
path: '/tickets/assigned-tickets',
name: 'AssignedTicketList',
component: () => import('@/views/tickets/AssignedTicketList'),
meta: {
title: i18n.t('route.AssignedTicketList'),
icon: 'check-square-o',
showOrganization: false,
permissions: []
}
},
{
path: '/tickets/tickets',
redirect: '',
component: empty,
hidden: true,
meta: {
title: i18n.t('route.Tickets'),
icon: 'file-text-o',
showOrganization: false
},
children: [
{
path: '',
name: 'TicketList',
component: () => import('@/views/tickets'),
meta: {
title: i18n.t('route.Tickets'),
icon: 'file-text-o',
permissions: ['tickets.view_ticket']
}
},
{
path: 'request-asset-perm/create',
name: 'RequestAssetPermTicketCreateUpdate',
@@ -67,6 +81,16 @@ export default {
},
hidden: true
},
{
path: 'login-confirm/:id',
name: 'LoginTicketDetail',
component: () => import('@/views/tickets/LoginConfirm/Detail'),
meta: {
title: i18n.t('route.TicketDetail'),
permissions: ['tickets.view_ticket']
},
hidden: true
},
{
path: 'request-application-perm/create',
name: 'RequestApplicationPermTicketCreateUpdate',

View File

@@ -7,6 +7,7 @@ const getters = {
consoleOrgs: state => state.users.consoleOrgs,
auditOrgs: state => state.users.auditOrgs,
workbenchOrgs: state => state.users.workbenchOrgs,
noRootWorkbenchOrgs: state => state.users.noRootWorkbenchOrgs,
usingOrgs: state => state.users.usingOrgs,
currentOrg: state => state.users.currentOrg,
currentOrgIsDefault: state => state.users.currentOrg['is_default'],

View File

@@ -1,5 +1,7 @@
import defaultSettings from '@/settings'
import { getPublicSettings } from '@/api/settings'
import { changeElementColor, changeThemeColors } from '@/utils/theme/index'
import { changeMenuColor } from '@/utils/theme/color'
const { showSettings, fixedHeader, sidebarLogo, tagsView } = defaultSettings
@@ -9,7 +11,8 @@ const state = {
sidebarLogo: sidebarLogo,
tagsView: tagsView,
publicSettings: null,
hasValidLicense: false
hasValidLicense: false,
themeColors: JSON.parse(localStorage.getItem('themeColors')) || {}
}
const mutations = {
@@ -20,10 +23,15 @@ const mutations = {
},
SET_PUBLIC_SETTINGS: (state, settings) => {
state.publicSettings = settings
state.themeColors = settings?.INTERFACE?.theme_info?.colors || {}
if (settings['XPACK_ENABLED']) {
state.hasValidLicense = settings['XPACK_LICENSE_IS_VALID']
}
},
setTheme(state, data) {
state.themeColors = data
localStorage.setItem('themeColors', JSON.stringify(data))
}
}
@@ -37,7 +45,7 @@ const actions = {
getPublicSettings(isOpen).then(response => {
const data = response || {}
if (isOpen) {
const faviconURL = data['LOGO_URLS']?.favicon
const faviconURL = data['INTERFACE']?.favicon
let link = document.querySelector("link[rel*='icon']")
if (!link) {
link = document.createElement('link')
@@ -49,14 +57,21 @@ const actions = {
link.href = faviconURL
}
// 动态修改Title
document.title = data['LOGIN_TITLE']
document.title = data['INTERFACE']['login_title']
}
const themeColors = data?.INTERFACE?.theme_info?.colors || {}
commit('SET_PUBLIC_SETTINGS', data)
changeThemeColors(themeColors)
resolve(response)
}).catch(error => {
reject(error)
})
})
},
changeThemeStyle({ commit }, themeColors) {
changeMenuColor(themeColors)
changeElementColor(themeColors)
commit('setTheme', themeColors)
}
}

View File

@@ -6,6 +6,7 @@ import {
} from '@/utils/auth'
import { resetRouter } from '@/router'
import Vue from 'vue'
const _ = require('lodash')
const getDefaultState = () => {
return {
@@ -16,6 +17,7 @@ const getDefaultState = () => {
auditOrgs: [],
consoleOrgs: [],
workbenchOrgs: [],
noRootWorkbenchOrgs: [],
usingOrgs: [],
perms: [],
MFAVerifyAt: null,
@@ -41,6 +43,9 @@ const mutations = {
state.perms = profile.perms
state.consoleOrgs = profile['console_orgs']
state.workbenchOrgs = profile['workbench_orgs']
state.noRootWorkbenchOrgs = profile['workbench_orgs'].filter(item => {
return item.id !== '00000000-0000-0000-0000-000000000000'
})
state.auditOrgs = profile['audit_orgs']
state.currentOrg = getCurrentOrgLocal(profile.username)
},
@@ -64,6 +69,9 @@ const mutations = {
},
SET_MFA_VERIFY(state) {
state.MFAVerifyAt = (new Date()).valueOf()
},
ADD_WORKBENCH_ORGS(state, org) {
state.workbenchOrgs.push(org)
}
}
@@ -109,6 +117,16 @@ const actions = {
setCurrentOrg({ commit }, data) {
commit('SET_CURRENT_ORG', data)
},
currentUserJoinNewOrg({ state, commit }, users) {
const { profile, currentOrg, workbenchOrgs } = state
if (users.includes(profile.id)) {
const currentOrgInfo = { id: currentOrg.id, name: currentOrg.name }
const notExistInWorkbenchOrgs = _.find(workbenchOrgs, currentOrgInfo)
if (!notExistInWorkbenchOrgs) {
commit('ADD_WORKBENCH_ORGS', currentOrg)
}
}
},
setMFAVerify({ commit }) {
commit('SET_MFA_VERIFY')
},

View File

@@ -0,0 +1,29 @@
:root {
--color-primary: #1ab394;
--color-success: #2793d7;
--color-info: #1c84c6;
--color-warning: #f8ac59;
--color-danger: #ed5565;
--menu-bg: #2f4050;
--menu-text: #a7b1c2;
--menu-hover: #293846;
--submenu-bg: #1f2d3d;
--submenu-hover: #001528;
--menu-active-text: white;
--menu-active-left: #1ab394;
}
:export {
--color-primary: #1ab394;
--color-success: #2793d7;
--color-info: #1c84c6;
--color-warning: #f8ac59;
--color-danger: #ed5565;
--menu-bg: #2f4050;
--menu-text: #a7b1c2;
--menu-hover: #293846;
--submenu-bg: #1f2d3d;
--submenu-hover: #001528;
--menu-active-text: white;
--menu-active-left: #1ab394;
}

View File

@@ -992,3 +992,6 @@ $--breakpoints-spec: (
'lg-and-down': (max-width: $--xl - 1),
'xl-only' : (min-width: $--xl),
);
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";

View File

@@ -1,20 +1,29 @@
@import './variables.scss';
@import './mixin.scss';
@import './transition.scss';
@import './sidebar.scss';
@import './element-variables.scss';
@import './element-ui.scss';
@import './theme/index.css';
@import './menu.scss';
@import './font-awesome/font-awesome.min.css';
@import './fonts/font-awesome.min.css';
::-webkit-scrollbar {
width:14px;
}
::-webkit-scrollbar-track {
border-radius:10px;
}
::-webkit-scrollbar-thumb {
border-radius: 8px;
box-shadow: 8px 10px 20px #C6C6C6 inset;
border: 3px solid rgba(0, 0, 0, 0);
}
::-webkit-scrollbar-thumb:hover {
box-shadow: 8px 10px 20px #878787 inset;
}
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: auto;
//text-rendering: optimizeLegibility;
color: #676a6c;
//font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
line-height: 1.428;
@@ -177,4 +186,4 @@ input[type=file] {
.el-pagination {
overflow: auto;
}
}

View File

@@ -1,15 +1,46 @@
@import "./variables";
.left-menu.el-menu {
.el-menu--inline {
background-color: $subMenuBg;
}
.el-menu-item, .el-submenu {
font-weight: 600;
}
.el-submenu, .el-menu-item.submenu-title-noDropdown {
background-color: $menuBg;
.el-submenu__title {
color: $menuText;
&:hover {
color: $menuActiveText;
}
i {
color: $menuText;
}
}
}
.el-menu-item, .el-submenu-sidebar .el-menu-item {
background-color: $subMenuBg;
color: $menuText;
&.is-active{
color: $menuActiveText;
}
&:hover {
background-color: $subMenuHover;
color: $menuActiveText;
}
i {
color: $menuText;
}
}
i.fa {
width: 13px;
margin-right: 10px;
margin-right: 10px;
width: 13px;
}
.is-active i.fa {
color: white;
color: $menuActiveText;
}
.el-submenu .el-menu-item {
@@ -48,16 +79,20 @@
}
li.is-active {
border-left: 4px solid #19aa8d;
border-left: 4px solid $menuActiveLeft;
}
.el-submenu-sidebar .el-menu-item {
background-color: $subMenuBg ;
}
.el-submenu.is-opened {
background-color: #1f2d3d ;
background-color: $subMenuBg ;
.el-submenu__title {
background-color: #1f2d3d!important;
background-color: $subMenuBg!important;
}
& .nest-menu {
background-color: #1f2d3d;
background-color: $subMenuBg;
}
}

View File

@@ -1,3 +1,4 @@
@import "./variables";
#app {
.main-container {
min-height: 100%;
@@ -12,7 +13,7 @@
background-color: $menuBg;
height: 100%;
position: fixed;
font-size: 0px;
font-size: 0;
top: 0;
bottom: 0;
left: 0;
@@ -29,7 +30,7 @@
}
.el-scrollbar__bar.is-vertical {
right: 0px;
right: 0;
}
.el-scrollbar {
@@ -71,7 +72,7 @@
}
.is-active>.el-submenu__title {
color: $subMenuActiveText !important;
color: $menuActiveText !important;
}
& .nest-menu .el-submenu-sidebar>.el-submenu__title,
@@ -100,7 +101,6 @@
.el-tooltip {
// padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
@@ -145,7 +145,7 @@
// mobile responsive
.mobile {
.main-container {
margin-left: 0px;
margin-left: 0;
}
.sidebar-container {
@@ -163,7 +163,6 @@
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
@@ -182,7 +181,6 @@
.nest-menu .el-submenu-sidebar>.el-submenu__title,
.el-menu-item {
&:hover {
// you can use $subMenuHover
background-color: $menuHover !important;
}
}

View File

@@ -1 +0,0 @@
.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#e8f3f9;color:#1c84c6}.el-alert--success.is-light .el-alert__description{color:#1c84c6}.el-alert--success.is-dark{background-color:#1c84c6;color:#FFF}.el-alert--info.is-light{background-color:#e9f9fa;color:#23c6c8}.el-alert--info.is-dark{background-color:#23c6c8;color:#FFF}.el-alert--info .el-alert__description{color:#23c6c8}.el-alert--warning.is-light{background-color:#fef7ee;color:#f8ac59}.el-alert--warning.is-light .el-alert__description{color:#f8ac59}.el-alert--warning.is-dark{background-color:#f8ac59;color:#FFF}.el-alert--error.is-light{background-color:#fdeef0;color:#ed5565}.el-alert--error.is-light .el-alert__description{color:#ed5565}.el-alert--error.is-dark{background-color:#ed5565;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-alert-fade-enter,.el-alert-fade-leave-active{opacity:0}

View File

@@ -1 +0,0 @@
.el-aside{overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.el-avatar{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}

View File

@@ -1 +0,0 @@
.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;color:#1ab394;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}

View File

@@ -1 +0,0 @@
.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#ed5565;border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#1ab394}.el-badge__content--success{background-color:#1c84c6}.el-badge__content--warning{background-color:#f8ac59}.el-badge__content--info{background-color:#23c6c8}.el-badge__content--danger{background-color:#ed5565}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#1ab394;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.el-card{border-radius:4px;border:1px solid #EBEEF5;background-color:#FFF;overflow:hidden;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}

View File

@@ -1 +0,0 @@
.el-carousel__item,.el-carousel__mask{position:absolute;height:100%;top:0;left:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}

View File

@@ -1 +0,0 @@
.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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