Compare commits

...

128 Commits

Author SHA1 Message Date
ibuler
1e471d0d22 perf: usign draw to create 2024-04-25 10:01:12 +08:00
ibuler
907e3ba729 perf: 优化自定义平台 2024-04-24 15:47:14 +08:00
ibuler
afa1a9fd9f perf: 修改 font 2024-04-23 19:00:45 +08:00
ibuler
07afdbe0f8 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-04-23 17:27:14 +08:00
ibuler
dcd59ca69f perf: 修改 labels 组件 2024-04-23 17:27:00 +08:00
zhaojisen
98ae943db0 fix: 修复侧边栏激活时文字右移的问题 2024-04-23 17:26:36 +08:00
ibuler
8e06dde724 perf: 修改一些 table 宽度 2024-04-22 15:10:08 +08:00
ibuler
71ca5a87f1 perf: 优化菜单 2024-04-19 19:13:34 +08:00
ibuler
c9b1d2fb5b perf: 修改 table 显示 2024-04-18 21:25:15 +08:00
ibuler
981fe00c5f perf: 优化修改 table label 2024-04-18 13:14:56 +08:00
ibuler
373661d35a perf: 优化 labels 宽度 2024-04-17 20:01:42 +08:00
ibuler
1be5f23204 perf: 修改 view hover 支持切换 2024-04-17 16:03:32 +08:00
ibuler
723123fa50 perf: 优化菜单展开 2024-04-17 14:10:35 +08:00
ibuler
7bf1c2056c perf: 优化菜单 2024-04-16 19:40:31 +08:00
ibuler
74c0a562e9 perf: 修改翻译和 ztree 高度 2024-04-15 16:28:10 +08:00
ibuler
65856db131 perf: 支持拖动 2024-04-15 11:23:08 +08:00
ibuler
5d67012121 perf: 优化 chat gpt 2024-04-12 14:21:00 +08:00
ibuler
573cf454ce perf: 修改 chat ai 2024-04-11 18:45:08 +08:00
ibuler
0d81b7839b perf: 修改一些布局 2024-04-11 14:56:00 +08:00
ibuler
5b00ab795d perf: 修改 ztree style 2024-04-11 13:47:22 +08:00
ibuler
86709e3604 perf: asset tree style 2024-04-10 18:58:12 +08:00
ibuler
38a9468fd2 perf: 修改 acls 和 automations 布局 2024-04-09 16:01:21 +08:00
ibuler
cf3ba419f4 perf: 修改自动化 2024-04-08 14:31:17 +08:00
ibuler
c94fad4145 perf: app 迁移位置 2024-04-08 11:11:08 +08:00
ibuler
f371a968b7 perf: 优化 page margin 2024-04-07 19:27:52 +08:00
ibuler
e163318c5a perf: deep 优化写法 2024-04-07 19:03:40 +08:00
ibuler
bb6be97bee perf: 兼容之前的 help message,更名 help tip 2024-04-07 18:06:07 +08:00
ibuler
cb454d83a1 perf: 修改样式 2024-04-07 17:46:24 +08:00
ibuler
6b5d13e8b8 perf: 统一 css 2024-04-07 17:03:05 +08:00
ibuler
5f9b124a7b perf: 优化 page help, tab help 2024-04-07 16:53:03 +08:00
ibuler
f7a48c04b8 perf: help tip and help text 2024-04-02 11:33:12 +08:00
ibuler
9315dab053 perf: form help tip style 2024-04-01 19:24:28 +08:00
ibuler
274d14d905 perf: account push and change secret 2024-04-01 17:51:55 +08:00
ibuler
9625dbf3ed perf: asset tree 2024-04-01 17:51:37 +08:00
ibuler
eef16080d4 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-03-29 18:59:57 +08:00
ibuler
66cf423598 perf: input with unit component 2024-03-29 18:59:44 +08:00
ibuler
53187cb8aa perf: cron tab better 2024-03-29 17:57:50 +08:00
老广
a8cdbc0b22 Merge pull request #3807 from jumpserver/pr@v4@fix_account_add_default_asset
fix: 修复创建账号时,资产没有默认值的问题
2024-03-28 18:15:25 +08:00
ibuler
7845a1901b perf: 修改账号相关的一些内容 2024-03-28 18:14:58 +08:00
ibuler
e3d8476396 fix: 修复创建账号时,资产没有默认值的问题 2024-03-28 07:11:18 +00:00
ibuler
88d9238c17 perf: 修改 table 布局 2024-03-28 14:47:48 +08:00
ibuler
fdb35eafc1 perf: 修改布局 2024-03-27 17:50:28 +08:00
ibuler
2bbd785ada perf: 优化 sub form 缩进 2024-03-26 19:18:07 +08:00
ibuler
f30294c2ae perf: 优化子表单 2024-03-26 18:30:18 +08:00
ibuler
95267a5581 perf: 修改 ztree 2024-03-26 14:52:36 +08:00
ibuler
a860cf1a13 perf: 优化布局 2024-03-25 18:17:37 +08:00
ibuler
f2cf4fb4a0 perf: 修改 tab page 2024-03-21 19:12:37 +08:00
ibuler
3323a39767 perf: 修改 tab page 2024-03-21 16:42:29 +08:00
ibuler
9ed323321a perf: form hidden 改成 v-if 2024-03-21 14:43:50 +08:00
ibuler
968089201a Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-03-20 18:09:23 +08:00
ibuler
d232d61350 perf: 优化翻译和布局 2024-03-20 18:09:03 +08:00
wangruidong
3cc2be8874 fix: 快捷命令布局问题 2024-03-19 18:06:16 +08:00
ibuler
cd1d0c3746 perf: 修改 icon 大小 2024-03-19 17:53:51 +08:00
ibuler
780c55e99e perf: 优化 detail card 2024-03-15 19:19:05 +08:00
老广
2b9e508a5c Merge pull request #3785 from jumpserver/pr@v4@perf_asset_tree
perf: 优化资产树 root 节点宽度
2024-03-15 14:43:03 +08:00
ibuler
a68328ae83 perf: 优化资产树 root 节点宽度 2024-03-15 14:38:10 +08:00
ibuler
f9cd35ac74 perf: 修改 applet detail 2024-03-15 14:24:30 +08:00
ibuler
06cfed009a perf: 优化表单 2024-03-15 10:45:02 +08:00
ibuler
dc94ff58c3 perf: 修改 accounts 创建 2024-03-13 18:53:19 +08:00
ibuler
6b87a2ad31 perf: 修改翻译 2024-03-11 19:20:32 +08:00
ibuler
9c7606e59b perf: 修改 tab 变量 2024-03-11 17:09:29 +08:00
ibuler
5f0fdf326b perf: 修改 action 组件 2024-03-11 14:33:37 +08:00
ibuler
cd550054d8 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-03-07 18:32:29 +08:00
ibuler
cb634bea1e perf: 修改翻译 2024-03-07 18:32:21 +08:00
Bai
3d93f708be perf: i18n settings-tools not done. 2024-03-07 16:14:53 +08:00
Bai
6c315e1669 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-03-06 17:07:36 +08:00
Bai
0fee313f18 perf: 优化界面设置页面主题Logo预览的背景颜色 2024-03-06 17:07:16 +08:00
feng626
bcb817b30d Merge pull request #3770 from jumpserver/pr@v4@translate
perf: translate and width
2024-03-06 16:51:19 +08:00
ibuler
33c75915ca perf: 修改文案 2024-03-06 16:50:20 +08:00
feng
89ed35815c perf: translate and width 2024-03-06 16:44:26 +08:00
ibuler
69d244b227 perf: 修改文案 2024-03-05 19:01:24 +08:00
ibuler
047ed5a6f8 perf: 修改 detail 中的一些宽度 2024-03-05 16:23:31 +08:00
ibuler
61acec17ee Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-03-04 19:08:53 +08:00
ibuler
2438c2fd04 perf: 优化菜单显示 2024-03-04 19:08:45 +08:00
feng626
5f06b7bde9 Merge pull request #3765 from jumpserver/pr@v4@jpb
fix: job management route jump and translate
2024-03-04 14:44:36 +08:00
feng
59bb23232f fix: job management route jump and translate 2024-03-04 14:41:26 +08:00
ibuler
64eacb5237 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-03-01 17:14:15 +08:00
ibuler
7804d741a0 perf: 修改 asset tree 2024-03-01 17:13:58 +08:00
feng626
31b9158e3d Merge pull request #3762 from jumpserver/pr@v4@translate
perf: translate
2024-03-01 15:42:36 +08:00
feng
a5bd2965d0 perf: translate 2024-03-01 15:40:15 +08:00
wangruidong
191143fb17 perf:drag files tips add padding 2024-02-28 20:52:32 +08:00
feng626
8be48c87a8 Merge pull request #3754 from jumpserver/pr@v4@translate
perf: account translate
2024-02-28 17:32:37 +08:00
feng
5aeb57fb61 perf: account translate 2024-02-28 17:26:05 +08:00
ibuler
b0ae5d4299 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-28 17:05:30 +08:00
ibuler
fb6ac84fb3 perf: 修改布局 2024-02-28 17:05:21 +08:00
wangruidong
e32c44aaa3 perf: tab name capitalize first letter with / 2024-02-28 10:00:43 +08:00
ibuler
4baf71d8dc Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-27 19:37:00 +08:00
ibuler
8b0d7bb422 perf: 修改布局 2024-02-27 19:36:47 +08:00
feng626
80e44e302f Merge pull request #3753 from jumpserver/pr@v4@translate
perf: account translate
2024-02-27 19:17:25 +08:00
feng
009770bb04 perf: account translate 2024-02-27 19:16:21 +08:00
Bai
e2d7d8edd8 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-27 14:59:41 +08:00
Bai
2d9b4ddd0b perf: i18n settings-Storage done. 2024-02-27 14:59:32 +08:00
ibuler
a58ed5e1a9 perf: 优化布局 2024-02-27 14:57:15 +08:00
ibuler
2595b8bc8e perf: 优化 label 宽度 2024-02-26 19:34:36 +08:00
ibuler
ee270f419c Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-26 16:54:36 +08:00
ibuler
4b6c9d7705 perf: 优化布局 2024-02-26 16:54:07 +08:00
Bai
445eb31db1 perf: i18n settings-Features done. 2024-02-26 15:47:12 +08:00
Bai
c8151d94ba Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-23 18:01:21 +08:00
Bai
8dd5ca8bc8 perf: i18n settings-notifications done. 2024-02-23 18:01:13 +08:00
feng626
8a6f0b57d4 Merge pull request #3744 from jumpserver/pr@v4@translate
perf: 修改工作台相关翻译
2024-02-23 17:21:34 +08:00
feng
7b91c26689 perf: 修改工作台相关翻译 2024-02-23 17:20:59 +08:00
ibuler
6083a2a9aa Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-23 15:17:42 +08:00
ibuler
31608ce4ee perf: 美化 nav header 2024-02-23 15:17:32 +08:00
Bai
5e36cddca3 perf: i18n settings-org done. 2024-02-23 15:16:39 +08:00
wangruidong
56bae6ee84 perf: permissions table col modify 2024-02-22 18:34:34 +08:00
feng626
0d870b62de Merge pull request #3741 from jumpserver/pr@v4@translate
perf: 翻译
2024-02-22 17:45:57 +08:00
feng
c453134fa3 perf: 翻译 2024-02-22 17:44:45 +08:00
ibuler
8012a5783e perf: 修改按钮字体 2024-02-22 16:45:37 +08:00
ibuler
c9d231f8f4 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-22 11:35:41 +08:00
ibuler
97b182f06e perf: 修改字体 2024-02-22 11:34:49 +08:00
wangruidong
82b33b5ab4 perf: table col modify 2024-02-22 10:42:04 +08:00
ibuler
2f7d5336e2 perf: 修改 sql query counter 2024-02-21 15:22:30 +08:00
ibuler
f425da1555 Merge branch 'v4' of github.com:jumpserver/lina into v4 2024-02-20 19:02:07 +08:00
ibuler
2d5278aa80 perf: 修改翻译 2024-02-20 19:01:52 +08:00
ibuler
ed91112531 perf: 修改 ai chat 的位置 2024-02-06 17:58:52 +08:00
ibuler
e224f30de6 perf: 修改图标 2024-02-06 15:34:26 +08:00
老广
bb66fe6e98 Merge pull request #3724 from jumpserver/pr@v4@perf_i18n
perf: 修改翻译
2024-02-05 14:19:08 +08:00
ibuler
9d096dd994 perf: 修改翻译 2024-02-05 14:13:53 +08:00
ibuler
c0d4ec7dba merge: with dev 2024-02-05 10:06:15 +08:00
ibuler
b91287a974 perf: 优化菜单 2024-02-05 09:52:58 +08:00
ibuler
94bf737584 perf: 优化 i18n 2024-02-04 10:24:52 +08:00
fit2bot
6960ff471c perf: 整理了一遍翻译 (#3718)
* stash

* perf: 修改 i18n 支持

* perf: 修改翻译

* perf: 修改 i18n

* perf: 整理了一遍翻译

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-02-01 16:02:57 +08:00
wangruidong
5bad1f397d fix: capitalizeFirst error 2024-01-15 19:35:16 +08:00
ibuler
327ebeaa53 perf: set default colunms width 2024-01-15 16:39:14 +08:00
ibuler
ea87c9d148 perf: 优化授权的资产 2024-01-12 18:14:50 +08:00
ibuler
2853b48144 perf: 优化搞定远端翻译 2024-01-11 14:37:19 +08:00
ibuler
3eb113a5cb perf: 修改翻译方式 2024-01-10 18:31:38 +08:00
ibuler
1b60735808 perf: 修改翻译不规范 2024-01-10 17:08:26 +08:00
593 changed files with 17314 additions and 22823 deletions

View File

@@ -25,6 +25,7 @@
}, },
"dependencies": { "dependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.13.12", "@babel/plugin-proposal-optional-chaining": "^7.13.12",
"@fontsource/open-sans": "^5.0.24",
"@traptitech/markdown-it-katex": "^3.6.0", "@traptitech/markdown-it-katex": "^3.6.0",
"@ztree/ztree_v3": "3.5.44", "@ztree/ztree_v3": "3.5.44",
"axios": "0.21.1", "axios": "0.21.1",

View File

@@ -21,13 +21,13 @@
} }
.el-alert--info.is-light { .el-alert--info.is-light {
background-color: light-9; background-color: rgba(255, 255, 255, 0.5);
color: light-2; color: info;
border: 1px solid; border: 1px solid;
} }
.el-alert--info .el-alert__description { .el-alert--info .el-alert__description {
color: light-2; color: info;
} }
.el-pagination.is-background .el-pager li:not(.disabled):hover { .el-pagination.is-background .el-pager li:not(.disabled):hover {
@@ -45,7 +45,6 @@
border-radius: 2px; border-radius: 2px;
border: 1px solid #DCDFE6; border: 1px solid #DCDFE6;
font-size: 12px; font-size: 12px;
line-height: 26px;
font-weight: 400; font-weight: 400;
} }
@@ -85,8 +84,12 @@
td .el-button.el-button--mini { td .el-button.el-button--mini {
padding: 1px 5px; padding: 2px 4px;
line-height: 1.5; line-height: 1.5;
.el-icon--right {
margin-bottom: 2px;
}
} }
.el-tabs__item.is-active, .el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active { .el-tabs__item.is-active, .el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active {
@@ -191,7 +194,7 @@ td .el-button.el-button--mini {
} }
.el-input--small .el-input__icon { .el-input--small .el-input__icon {
line-height: 34px; line-height: 30px;
} }
.option-group .el-select-dropdown__item.hover, .option-group .el-select-dropdown__item.selected { .option-group .el-select-dropdown__item.hover, .option-group .el-select-dropdown__item.selected {
@@ -313,11 +316,11 @@ td .el-button.el-button--mini {
.el-tooltip__popper.is-light { .el-tooltip__popper.is-light {
background: #FFF; background: #FFF;
max-width: 500px;
border: 1px solid #e7eaec; border: 1px solid #e7eaec;
} box-shadow: 0 1.6px 3.6px 0 rgba(0, 0, 0, .132), 0 .3px .9px 0 rgba(0, 0, 0, .108);
line-height: 1.5;
.el-tooltip__popper.is-light .popper__arrow { padding: 10px;
border-bottom-color: #e7eaec !important;
} }
.el-dialog__headerbtn .el-dialog__close { .el-dialog__headerbtn .el-dialog__close {

View File

@@ -4,6 +4,7 @@
<script> <script>
import DataActions from '@/components/DataActions' import DataActions from '@/components/DataActions'
export default { export default {
name: 'ActionsGroup', name: 'ActionsGroup',
components: { components: {
@@ -24,9 +25,7 @@ export default {
}, },
moreActionsTitle: { moreActionsTitle: {
type: String, type: String,
default() { default: ''
return this.$t('common.MoreActions')
}
}, },
moreActionsPlacement: { moreActionsPlacement: {
type: String, type: String,
@@ -45,8 +44,9 @@ export default {
iMoreAction() { iMoreAction() {
const defaultBtn = { const defaultBtn = {
name: 'moreActions', name: 'moreActions',
title: this.$t('common.MoreActions'), title: '',
type: 'primary', type: 'primary',
icon: 'el-icon-more',
plain: true plain: true
} }
const btn = { const btn = {

View File

@@ -10,7 +10,7 @@ export const accountFieldsMeta = (vm) => {
assets: { assets: {
rules: [Required], rules: [Required],
component: AssetSelect, component: AssetSelect,
label: vm.$t('assets.Asset'), label: vm.$t('Asset'),
el: { el: {
multiple: false multiple: false
}, },
@@ -36,14 +36,15 @@ export const accountFieldsMeta = (vm) => {
}, },
on_invalid: { on_invalid: {
rules: [Required], rules: [Required],
label: vm.$t('accounts.AccountPolicy'), label: vm.$t('AccountPolicy'),
helpText: vm.$t('accounts.BulkCreateStrategy'), helpText: vm.$t('AccountPolicyHelpText'),
helpTextAsTip: true,
hidden: () => { hidden: () => {
return vm.platform || vm.asset return vm.platform || vm.asset
} }
}, },
name: { name: {
label: vm.$t('common.Name'), label: vm.$t('Name'),
rules: [RequiredChange], rules: [RequiredChange],
on: { on: {
input: ([value], updateForm) => { input: ([value], updateForm) => {
@@ -82,7 +83,7 @@ export const accountFieldsMeta = (vm) => {
} }
}, },
privileged: { privileged: {
label: vm.$t('assets.Privileged'), label: vm.$t('Privileged'),
hidden: () => { hidden: () => {
return vm.addTemplate return vm.addTemplate
} }
@@ -104,43 +105,42 @@ export const accountFieldsMeta = (vm) => {
} }
}, },
su_from_username: { su_from_username: {
label: vm.$t('assets.UserSwitchFrom'), label: vm.$t('UserSwitchFrom'),
hidden: (formValue) => { hidden: (formValue) => {
return vm.platform || vm.asset || vm.addTemplate return vm.platform || vm.asset || vm.addTemplate
} }
}, },
password: { password: {
label: vm.$t('assets.Password'), label: vm.$t('Password'),
component: UpdateToken, component: UpdateToken,
hidden: (formValue) => { hidden: (formValue) => {
console.log('formValue: ', formValue)
return formValue.secret_type !== 'password' || vm.addTemplate return formValue.secret_type !== 'password' || vm.addTemplate
} }
}, },
ssh_key: { ssh_key: {
label: vm.$t('assets.PrivateKey'), label: vm.$t('PrivateKey'),
component: UploadSecret, component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'ssh_key' || vm.addTemplate hidden: (formValue) => formValue.secret_type !== 'ssh_key' || vm.addTemplate
}, },
passphrase: { passphrase: {
label: vm.$t('assets.Passphrase'), label: vm.$t('Passphrase'),
component: UpdateToken, component: UpdateToken,
hidden: (formValue) => formValue.secret_type !== 'ssh_key' || vm.addTemplate hidden: (formValue) => formValue.secret_type !== 'ssh_key' || vm.addTemplate
}, },
token: { token: {
label: vm.$t('assets.Token'), label: vm.$t('Token'),
component: UploadSecret, component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'token' || vm.addTemplate hidden: (formValue) => formValue.secret_type !== 'token' || vm.addTemplate
}, },
access_key: { access_key: {
id: 'access_key', id: 'access_key',
label: vm.$t('assets.AccessKey'), label: vm.$t('AccessKey'),
component: UploadSecret, component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'access_key' || vm.addTemplate hidden: (formValue) => formValue.secret_type !== 'access_key' || vm.addTemplate
}, },
api_key: { api_key: {
id: 'api_key', id: 'api_key',
label: vm.$t('assets.ApiKey'), label: vm.$t('ApiKey'),
component: UploadSecret, component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'api_key' || vm.addTemplate hidden: (formValue) => formValue.secret_type !== 'api_key' || vm.addTemplate
}, },
@@ -152,7 +152,7 @@ export const accountFieldsMeta = (vm) => {
} }
}, },
push_now: { push_now: {
helpText: vm.$t('accounts.AccountPush.WindowsPushHelpText'), helpText: vm.$t('WindowsPushHelpText'),
hidden: (formValue) => { hidden: (formValue) => {
const automation = vm.iPlatform.automation || {} const automation = vm.iPlatform.automation || {}
return !automation.push_account_enabled || return !automation.push_account_enabled ||
@@ -163,7 +163,7 @@ export const accountFieldsMeta = (vm) => {
} }
}, },
params: { params: {
label: vm.$t('assets.PushParams'), label: vm.$t('PushParams'),
component: AutomationParamsForm, component: AutomationParamsForm,
el: { el: {
method: vm.asset?.auto_config?.push_account_method method: vm.asset?.auto_config?.push_account_method
@@ -179,10 +179,10 @@ export const accountFieldsMeta = (vm) => {
} }
}, },
is_active: { is_active: {
label: vm.$t('common.IsActive') label: vm.$t('IsActive')
}, },
comment: { comment: {
label: vm.$t('common.Comment'), label: vm.$t('Comment'),
hidden: () => { hidden: () => {
return vm.addTemplate return vm.addTemplate
} }

View File

@@ -2,6 +2,7 @@
<AutoDataForm <AutoDataForm
v-if="!loading" v-if="!loading"
ref="AutoDataForm" ref="AutoDataForm"
:class="addTemplate? '': 'account-add'"
v-bind="$data" v-bind="$data"
@submit="confirm" @submit="confirm"
/> />
@@ -58,14 +59,13 @@ export default {
form: Object.assign({ 'on_invalid': 'error' }, this.account || {}), form: Object.assign({ 'on_invalid': 'error' }, this.account || {}),
encryptedFields: ['secret'], encryptedFields: ['secret'],
fields: [ fields: [
[this.$t('assets.Asset'), ['assets']], [this.$t('AccountTemplate'), ['template']],
[this.$t('accounts.AccountTemplate'), ['template']], [this.$t('Basic'), ['assets', 'name', 'username', 'privileged', 'su_from', 'su_from_username']],
[this.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from', 'su_from_username']], [this.$t('Secret'), [
[this.$t('assets.Secret'), [
'secret_type', 'password', 'ssh_key', 'token', 'secret_type', 'password', 'ssh_key', 'token',
'access_key', 'passphrase', 'api_key' 'access_key', 'passphrase', 'api_key'
]], ]],
[this.$t('common.Other'), ['push_now', 'params', 'on_invalid', 'is_active', 'comment']] [this.$t('Other'), ['push_now', 'params', 'on_invalid', 'is_active', 'comment']]
], ],
fieldsMeta: accountFieldsMeta(this), fieldsMeta: accountFieldsMeta(this),
hasSaveContinue: false hasSaveContinue: false
@@ -75,11 +75,18 @@ export default {
try { try {
await this.getPlatform() await this.getPlatform()
this.setSecretTypeOptions() this.setSecretTypeOptions()
this.getDefaultAssets()
} finally { } finally {
this.loading = false this.loading = false
} }
}, },
methods: { methods: {
async getDefaultAssets() {
const assetId = this.$route.query.asset_id
if (assetId && !this.form.name) {
this.form.assets = [assetId]
}
},
async getPlatform() { async getPlatform() {
if (this.platform) { if (this.platform) {
this.iPlatform = this.platform this.iPlatform = this.platform
@@ -93,23 +100,23 @@ export default {
setSecretTypeOptions() { setSecretTypeOptions() {
const choices = [ const choices = [
{ {
label: this.$t('assets.Password'), label: this.$t('Password'),
value: 'password' value: 'password'
}, },
{ {
label: this.$t('assets.SSHKey'), label: this.$t('SSHKey'),
value: 'ssh_key' value: 'ssh_key'
}, },
{ {
label: this.$t('assets.Token'), label: this.$t('Token'),
value: 'token' value: 'token'
}, },
{ {
label: this.$t('assets.AccessKey'), label: this.$t('AccessKey'),
value: 'access_key' value: 'access_key'
}, },
{ {
label: this.$t('assets.ApiKey'), label: this.$t('ApiKey'),
value: 'api_key' value: 'api_key'
} }
] ]
@@ -145,5 +152,21 @@ export default {
} }
</script> </script>
<style scoped> <style lang='scss' scoped>
.account-add {
>>> .el-form-item {
margin-bottom: 5px;
.help-block {
margin-bottom: 5px;
}
}
>>> .form-group-header {
.hr-line-dashed {
margin: 5px 0;
}
h3 {
margin-bottom: 10px;
}
}
}
</style> </style>

View File

@@ -8,6 +8,7 @@
:title="title" :title="title"
:visible.sync="iVisible" :visible.sync="iVisible"
v-bind="$attrs" v-bind="$attrs"
width="900px"
v-on="$listeners" v-on="$listeners"
> >
<AccountCreateUpdateForm <AccountCreateUpdateForm
@@ -52,7 +53,7 @@ export default {
title: { title: {
type: String, type: String,
default: function() { default: function() {
return this.$t('assets.AddAccount') return this.$t('AddAccount')
} }
} }
}, },
@@ -91,7 +92,7 @@ export default {
data = formValue data = formValue
url = `/api/v1/accounts/accounts/bulk/` url = `/api/v1/accounts/accounts/bulk/`
if (data.assets.length === 0) { if (data.assets.length === 0) {
this.$message.error(this.$tc('assets.PleaseSelectAsset')) this.$message.error(this.$tc('PleaseSelectAsset'))
return return
} }
} }
@@ -113,7 +114,7 @@ export default {
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, data).then(() => { this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, data).then(() => {
this.iVisible = false this.iVisible = false
this.$emit('add', true) this.$emit('add', true)
this.$message.success(this.$tc('common.updateSuccessMsg')) this.$message.success(this.$tc('UpdateSuccessMsg'))
}).catch(error => this.setFieldError(error)) }).catch(error => this.setFieldError(error))
}, },
handleResult(resp, error) { handleResult(resp, error) {
@@ -126,7 +127,7 @@ export default {
} }
if (!bulkCreate) { if (!bulkCreate) {
if (!error) { if (!error) {
this.$message.success(this.$tc('common.createSuccessMsg')) this.$message.success(this.$tc('CreateSuccessMsg'))
} else { } else {
this.setFieldError(error) this.setFieldError(error)
} }

View File

@@ -27,7 +27,7 @@
:account="account" :account="account"
:add-template="true" :add-template="true"
:asset="iAsset" :asset="iAsset"
:title="accountCreateUpdateTitle" :title="accountCreateByTemplateTitle"
:visible.sync="showAddTemplateDialog" :visible.sync="showAddTemplateDialog"
@add="addAccountSuccess" @add="addAccountSuccess"
@bulk-create-done="showBulkCreateResult($event)" @bulk-create-done="showBulkCreateResult($event)"
@@ -118,8 +118,7 @@ export default {
columnsDefault: { columnsDefault: {
type: Array, type: Array,
default: () => ([ default: () => ([
'name', 'username', 'asset', 'privileged', 'name', 'username', 'asset', 'date_updated'
'secret_type', 'is_active', 'date_updated'
]) ])
}, },
headerExtraActions: { headerExtraActions: {
@@ -140,7 +139,8 @@ export default {
showAddDialog: false, showAddDialog: false,
showAddTemplateDialog: false, showAddTemplateDialog: false,
createAccountResults: [], createAccountResults: [],
accountCreateUpdateTitle: this.$t('assets.AddAccount'), accountCreateUpdateTitle: this.$t('AddAccount'),
accountCreateByTemplateTitle: this.$t('AddAccountByTemplate'),
iAsset: this.asset, iAsset: this.asset,
account: {}, account: {},
secretUrl: '', secretUrl: '',
@@ -158,6 +158,7 @@ export default {
}, },
columnsMeta: { columnsMeta: {
name: { name: {
width: '120px',
formatter: function(row) { formatter: function(row) {
const to = { const to = {
name: 'AssetAccountDetail', name: 'AssetAccountDetail',
@@ -171,7 +172,6 @@ export default {
} }
}, },
asset: { asset: {
label: this.$t('assets.Asset'),
formatter: function(row) { formatter: function(row) {
const to = { const to = {
name: 'AssetDetail', name: 'AssetDetail',
@@ -184,8 +184,10 @@ export default {
} }
} }
}, },
username: {
width: '120px'
},
secret_type: { secret_type: {
width: '100px',
formatter: function(row) { formatter: function(row) {
return row.secret_type.label return row.secret_type.label
} }
@@ -196,13 +198,12 @@ export default {
} }
}, },
has_secret: { has_secret: {
width: '100px', width: '120px',
formatterArgs: { formatterArgs: {
showFalse: false showFalse: false
} }
}, },
privileged: { privileged: {
label: this.$t('assets.Privileged'),
width: '120px', width: '120px',
formatterArgs: { formatterArgs: {
showText: false, showText: false,
@@ -216,11 +217,11 @@ export default {
hasUpdate: false, // can set function(row, value) hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value) hasDelete: false, // can set function(row, value)
hasClone: this.hasClone, hasClone: this.hasClone,
moreActionsTitle: this.$t('common.More'), moreActionsTitle: this.$t('More'),
extraActions: [ extraActions: [
{ {
name: 'View', name: 'View',
title: this.$t('common.View'), title: this.$t('View'),
can: this.$hasPerm('accounts.view_accountsecret'), can: this.$hasPerm('accounts.view_accountsecret'),
type: 'primary', type: 'primary',
callback: ({ row }) => { callback: ({ row }) => {
@@ -234,22 +235,26 @@ export default {
} }
}, },
{ {
name: 'ClearSecret', name: 'Update',
title: this.$t('common.ClearSecret'), title: this.$t('Edit'),
can: this.$hasPerm('accounts.change_account'), can: this.$hasPerm('accounts.change_account') && !this.$store.getters.currentOrgIsRoot,
type: 'primary',
callback: ({ row }) => { callback: ({ row }) => {
this.$axios.patch( const data = {
`/api/v1/accounts/accounts/clear-secret/`, ...this.asset,
{ account_ids: [row.id] } ...row.asset
).then(() => { }
this.$message.success(this.$tc('common.ClearSuccessMsg')) vm.account = row
vm.iAsset = data
vm.showAddDialog = false
vm.accountCreateUpdateTitle = this.$t('UpdateAccount')
setTimeout(() => {
vm.showAddDialog = true
}) })
} }
}, },
{ {
name: 'Test', name: 'Test',
title: this.$t('accounts.Test'), title: this.$t('Test'),
can: ({ row }) => can: ({ row }) =>
!this.$store.getters.currentOrgIsRoot && !this.$store.getters.currentOrgIsRoot &&
this.$hasPerm('accounts.change_account') && this.$hasPerm('accounts.change_account') &&
@@ -265,20 +270,16 @@ export default {
} }
}, },
{ {
name: 'Update', name: 'ClearSecret',
title: this.$t('common.Update'), title: this.$t('ClearSecret'),
can: this.$hasPerm('accounts.change_account') && !this.$store.getters.currentOrgIsRoot, can: this.$hasPerm('accounts.change_account'),
type: 'primary',
callback: ({ row }) => { callback: ({ row }) => {
const data = { this.$axios.patch(
...this.asset, `/api/v1/accounts/accounts/clear-secret/`,
...row.asset { account_ids: [row.id] }
} ).then(() => {
vm.account = row this.$message.success(this.$tc('ClearSuccessMsg'))
vm.iAsset = data
vm.showAddDialog = false
vm.accountCreateUpdateTitle = this.$t('assets.UpdateAccount')
setTimeout(() => {
vm.showAddDialog = true
}) })
} }
} }
@@ -305,7 +306,7 @@ export default {
exportOptions: { exportOptions: {
url: this.exportUrl, url: this.exportUrl,
mfaVerifyRequired: true, mfaVerifyRequired: true,
tips: this.$t('accounts.AccountExportTips') tips: this.$t('AccountExportTips')
}, },
importOptions: { importOptions: {
canImportCreate: this.$hasPerm('accounts.add_account'), canImportCreate: this.$hasPerm('accounts.add_account'),
@@ -314,8 +315,9 @@ export default {
extraActions: [ extraActions: [
{ {
name: 'add', name: 'add',
title: this.$t('common.Add'), title: this.$t('Create'),
type: 'primary', type: 'primary',
icon: 'plus',
can: () => { can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
}, },
@@ -324,14 +326,13 @@ export default {
setTimeout(() => { setTimeout(() => {
vm.iAsset = this.asset vm.iAsset = this.asset
vm.account = {} vm.account = {}
vm.accountCreateUpdateTitle = this.$t('assets.AddAccount')
vm.showAddDialog = true vm.showAddDialog = true
}) })
} }
}, },
{ {
name: 'add-template', name: 'add-template',
title: this.$t('common.TemplateAdd'), title: this.$t('TemplateAdd'),
has: !(this.platform || this.asset), has: !(this.platform || this.asset),
can: () => { can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
@@ -341,7 +342,6 @@ export default {
setTimeout(() => { setTimeout(() => {
vm.iAsset = this.asset vm.iAsset = this.asset
vm.account = {} vm.account = {}
vm.accountCreateUpdateTitle = this.$t('assets.AddAccount')
vm.showAddTemplateDialog = true vm.showAddTemplateDialog = true
}) })
} }
@@ -350,10 +350,10 @@ export default {
], ],
extraMoreActions: [ extraMoreActions: [
{ {
name: 'BulkVerify', name: 'BatchTest',
title: this.$t('accounts.BulkVerify'), title: this.$t('BatchTest'),
type: 'primary', type: 'primary',
fa: 'fa-handshake-o', icon: 'fa-handshake-o',
can: ({ selectedRows }) => { can: ({ selectedRows }) => {
return selectedRows.length > 0 return selectedRows.length > 0
}, },
@@ -364,15 +364,15 @@ export default {
{ action: 'verify', accounts: ids }).then(res => { { action: 'verify', accounts: ids }).then(res => {
openTaskPage(res['task']) openTaskPage(res['task'])
}).catch(err => { }).catch(err => {
this.$message.error(this.$tc('common.bulkVerifyErrorMsg' + ' ' + err)) this.$message.error(this.$tc('BulkVerifyErrorMsg' + ' ' + err))
}) })
}.bind(this) }.bind(this)
}, },
{ {
name: 'ClearSecrets', name: 'BatchClearSecret',
title: this.$t('common.ClearSecret'), title: this.$t('ClearSecret'),
type: 'primary', type: 'primary',
fa: 'clean', icon: 'clean',
can: ({ selectedRows }) => { can: ({ selectedRows }) => {
return selectedRows.length > 0 && vm.$hasPerm('accounts.change_account') return selectedRows.length > 0 && vm.$hasPerm('accounts.change_account')
}, },
@@ -381,16 +381,16 @@ export default {
this.$axios.patch( this.$axios.patch(
'/api/v1/accounts/accounts/clear-secret/', '/api/v1/accounts/accounts/clear-secret/',
{ account_ids: ids }).then(() => { { account_ids: ids }).then(() => {
this.$message.success(this.$tc('common.ClearSuccessMsg')) this.$message.success(this.$tc('ClearSuccessMsg'))
}).catch(err => { }).catch(err => {
this.$message.error(this.$tc('common.bulkClearErrorMsg' + ' ' + err)) this.$message.error(this.$tc('BatchClearErrorMsg' + ' ' + err))
}) })
}.bind(this) }.bind(this)
}, },
{ {
name: 'actionUpdateSelected', name: 'BatchUpdate',
title: this.$t('accounts.AccountBatchUpdate'), title: this.$t('BatchUpdate'),
fa: 'batch-update', icon: 'batch-update',
can: ({ selectedRows }) => { can: ({ selectedRows }) => {
return selectedRows.length > 0 && return selectedRows.length > 0 &&
!this.$store.getters.currentOrgIsRoot && !this.$store.getters.currentOrgIsRoot &&
@@ -436,12 +436,12 @@ export default {
this.tableConfig.columnsMeta.actions.formatterArgs.extraActions.push( this.tableConfig.columnsMeta.actions.formatterArgs.extraActions.push(
{ {
name: 'Delete', name: 'Delete',
title: this.$t('common.Delete'), title: this.$t('Delete'),
can: this.$hasPerm('accounts.delete_account'), can: this.$hasPerm('accounts.delete_account'),
type: 'primary', type: 'primary',
callback: ({ row }) => { callback: ({ row }) => {
const msg = this.$t('accounts.AccountDeleteConfirmMsg') const msg = this.$t('AccountDeleteConfirmMsg')
this.$confirm(msg, this.$tc('common.Info'), { this.$confirm(msg, this.$tc('Info'), {
type: 'warning', type: 'warning',
confirmButtonClass: 'el-button--danger', confirmButtonClass: 'el-button--danger',
beforeClose: async(action, instance, done) => { beforeClose: async(action, instance, done) => {
@@ -449,7 +449,7 @@ export default {
this.$axios.delete(`/api/v1/accounts/accounts/${row.id}/`).then(() => { this.$axios.delete(`/api/v1/accounts/accounts/${row.id}/`).then(() => {
done() done()
this.$refs.ListTable.reloadTable() this.$refs.ListTable.reloadTable()
this.$message.success(this.$tc('common.deleteSuccessMsg')) this.$message.success(this.$tc('DeleteSuccessMsg'))
}) })
} }
}) })

View File

@@ -30,11 +30,11 @@ export default {
} }
}, },
data() { data() {
const errorProp = this.$t('common.Error') const errorProp = this.$t('Error')
const stateMap = { const stateMap = {
'created': this.$tc('common.Created'), 'created': this.$tc('Created'),
'updated': this.$tc('common.Updated'), 'updated': this.$tc('Updated'),
'skipped': this.$tc('common.Skipped') 'skipped': this.$tc('Skipped')
} }
const stateClsMap = { const stateClsMap = {
'created': 'color-primary', 'created': 'color-primary',
@@ -42,16 +42,16 @@ export default {
'skipped': 'color-default' 'skipped': 'color-default'
} }
return { return {
title: this.$t('accounts.AddAccountResult'), title: this.$t('AddAccountResult'),
config: { config: {
columns: [ columns: [
{ {
prop: 'asset', prop: 'asset',
label: this.$t('assets.Asset') label: this.$t('Asset')
}, },
{ {
prop: 'state', prop: 'state',
label: this.$t('common.Status'), label: this.$t('Status'),
width: '200px', width: '200px',
formatter: (row) => { formatter: (row) => {
if (row.error) { if (row.error) {
@@ -71,11 +71,11 @@ export default {
computed: { computed: {
summary() { summary() {
const labels = { const labels = {
total: this.$tc('common.Total'), total: this.$tc('Total'),
created: this.$tc('common.Created'), created: this.$tc('Created'),
updated: this.$tc('common.Updated'), updated: this.$tc('Updated'),
skipped: this.$tc('common.Skipped'), skipped: this.$tc('Skipped'),
error: this.$tc('common.Error') error: this.$tc('Error')
} }
const grouped = _.groupBy(this.result, 'state') const grouped = _.groupBy(this.result, 'state')
const groupedLength = _.mapValues(grouped, 'length') const groupedLength = _.mapValues(grouped, 'length')

View File

@@ -23,7 +23,7 @@ export default {
data() { data() {
return { return {
config: { config: {
title: this.$t('accounts.HistoryPassword'), title: this.$t('HistoryPassword'),
visible: false, visible: false,
width: '60%', width: '60%',
tableConfig: { tableConfig: {
@@ -32,7 +32,7 @@ export default {
columns: ['secret', 'version', 'history_date'], columns: ['secret', 'version', 'history_date'],
columnsMeta: { columnsMeta: {
secret: { secret: {
label: this.$t('assets.Password'), label: this.$t('Password'),
formatter: ShowKeyCopyFormatter, formatter: ShowKeyCopyFormatter,
formatterArgs: { formatterArgs: {
hasDownload: false, hasDownload: false,
@@ -40,7 +40,7 @@ export default {
} }
}, },
history_date: { history_date: {
label: this.$t('accounts.HistoryDate') label: this.$t('HistoryDate')
}, },
secret_type: { secret_type: {
width: '200px' width: '200px'

View File

@@ -65,7 +65,7 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.item-textarea > > > .el-textarea__inner { .item-textarea >>> .el-textarea__inner {
height: 110px; height: 110px;
} }
@@ -78,12 +78,12 @@ export default {
border-bottom: none; border-bottom: none;
} }
> > > .el-form-item__label { >>> .el-form-item__label {
padding-right: 20px; padding-right: 20px;
line-height: 30px; line-height: 30px;
} }
> > > .el-form-item__content { >>> .el-form-item__content {
line-height: 30px; line-height: 30px;
pre { pre {

View File

@@ -1,7 +1,7 @@
<template> <template>
<Dialog <Dialog
:destroy-on-close="true" :destroy-on-close="true"
:title="$tc('assets.UpdateAssetUserToken')" :title="$tc('UpdateAssetUserToken')"
:visible.sync="visible" :visible.sync="visible"
width="50" width="50"
@cancel="handleCancel()" @cancel="handleCancel()"
@@ -9,19 +9,19 @@
v-on="$listeners" v-on="$listeners"
> >
<el-form label-position="right" label-width="90px"> <el-form label-position="right" label-width="90px">
<el-form-item :label="$tc('assets.Name')"> <el-form-item :label="$tc('Name')">
<el-input v-model="account['asset_name']" readonly /> <el-input v-model="account['asset_name']" readonly />
</el-form-item> </el-form-item>
<el-form-item :label="$tc('assets.Username')"> <el-form-item :label="$tc('Username')">
<el-input v-model="account['username']" readonly /> <el-input v-model="account['username']" readonly />
</el-form-item> </el-form-item>
<el-form-item :label="$tc('assets.Password')"> <el-form-item :label="$tc('Password')">
<UpdateToken v-model="authInfo.password" /> <UpdateToken v-model="authInfo.password" />
</el-form-item> </el-form-item>
<el-form-item :label="$tc('assets.SSHSecretKey')"> <el-form-item :label="$tc('SSHSecretKey')">
<UploadKey @input="getFile" /> <UploadKey @input="getFile" />
</el-form-item> </el-form-item>
<el-form-item :label="$tc('assets.Passphrase')"> <el-form-item :label="$tc('Passphrase')">
<UpdateToken v-model="authInfo.passphrase" /> <UpdateToken v-model="authInfo.passphrase" />
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -75,12 +75,12 @@ export default {
{ disableFlashErrorMsg: true } { disableFlashErrorMsg: true }
).then(res => { ).then(res => {
this.authInfo = { password: '', private_key: '' } this.authInfo = { password: '', private_key: '' }
this.$message.success(this.$tc('common.updateSuccessMsg')) this.$message.success(this.$tc('UpdateSuccessMsg'))
this.$emit('updateAuthDone', res) this.$emit('updateAuthDone', res)
this.$emit('update:visible', false) this.$emit('update:visible', false)
}).catch(err => { }).catch(err => {
const errMsg = Object.values(err.response.data).join(', ') const errMsg = Object.values(err.response.data).join(', ')
this.$message.error(this.$tc('common.updateErrorMsg') + ' ' + errMsg) this.$message.error(this.$tc('UpdateErrorMsg') + ' ' + errMsg)
this.$emit('update:visible', true) this.$emit('update:visible', true)
}) })
}, },

View File

@@ -11,10 +11,10 @@
v-on="$listeners" v-on="$listeners"
> >
<el-form :model="secretInfo" class="password-form" label-position="right" label-width="100px"> <el-form :model="secretInfo" class="password-form" label-position="right" label-width="100px">
<el-form-item :label="$tc('assets.Name')"> <el-form-item :label="$tc('Name')">
<span>{{ account['name'] }}</span> <span>{{ account['name'] }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="$tc('assets.Username')"> <el-form-item :label="$tc('Username')">
<span>{{ account['username'] }}</span> <span>{{ account['username'] }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="secretTypeLabel"> <el-form-item :label="secretTypeLabel">
@@ -27,16 +27,16 @@
@input="onShowKeyCopyFormatterChange" @input="onShowKeyCopyFormatterChange"
/> />
</el-form-item> </el-form-item>
<el-form-item v-if="secretType === 'ssh_key'" :label="$tc('assets.sshKeyFingerprint')"> <el-form-item v-if="secretType === 'ssh_key'" :label="$tc('SshKeyFingerprint')">
<span>{{ sshKeyFingerprint }}</span> <span>{{ sshKeyFingerprint }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="$tc('common.DateCreated')"> <el-form-item :label="$tc('DateCreated')">
<span>{{ account['date_created'] | date }}</span> <span>{{ account['date_created'] | date }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="$tc('common.DateUpdated')"> <el-form-item :label="$tc('DateUpdated')">
<span>{{ account['date_updated'] | date }}</span> <span>{{ account['date_updated'] | date }}</span>
</el-form-item> </el-form-item>
<el-form-item v-if="showPasswordRecord" v-perms="'accounts.view_accountsecret'" :label="$tc('accounts.PasswordRecord')"> <el-form-item v-if="showPasswordRecord" v-perms="'accounts.view_accountsecret'" :label="$tc('PasswordRecord')">
<el-link <el-link
:underline="false" :underline="false"
type="success" type="success"
@@ -86,7 +86,7 @@ export default {
title: { title: {
type: String, type: String,
default: function() { default: function() {
return this.$tc('assets.AccountDetail') return this.$tc('Detail')
} }
}, },
showPasswordRecord: { showPasswordRecord: {
@@ -137,7 +137,7 @@ export default {
secret: encryptPassword(this.modifiedSecret) secret: encryptPassword(this.modifiedSecret)
} }
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, params).then(() => { this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, params).then(() => {
this.$message.success(this.$tc('common.updateSuccessMsg')) this.$message.success(this.$tc('UpdateSuccessMsg'))
}) })
}, },
showSecretDialog() { showSecretDialog() {

View File

@@ -1,8 +1,6 @@
import i18n from '@/i18n/i18n'
import { ChoicesFormatter } from '@/components/Table/TableFormatters' import { ChoicesFormatter } from '@/components/Table/TableFormatters'
export const connectivityMeta = { export const connectivityMeta = {
label: i18n.t('assets.Connectivity'),
formatter: ChoicesFormatter, formatter: ChoicesFormatter,
formatterArgs: { formatterArgs: {
faChoices: { faChoices: {
@@ -22,5 +20,5 @@ export const connectivityMeta = {
} }
} }
}, },
width: '100px' width: '130px'
} }

View File

@@ -8,7 +8,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<el-button :disabled="disabled" :type="type" size="small" @click="addObjects">{{ $t('common.Add') }}</el-button> <el-button :disabled="disabled" :type="type" size="small" @click="addObjects">{{ $t('Add') }}</el-button>
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -1,7 +1,7 @@
<template> <template>
<Dialog <Dialog
:close-on-click-modal="false" :close-on-click-modal="false"
:title="$tc('assets.Assets')" :title="$tc('Assets')"
custom-class="asset-select-dialog" custom-class="asset-select-dialog"
top="2vh" top="2vh"
v-bind="$attrs" v-bind="$attrs"
@@ -16,9 +16,9 @@
:header-actions="headerActions" :header-actions="headerActions"
:node-url="baseNodeUrl" :node-url="baseNodeUrl"
:table-config="tableConfig" :table-config="tableConfig"
:tree-setting="treeSetting"
:tree-url="`${baseNodeUrl}children/tree/`" :tree-url="`${baseNodeUrl}children/tree/`"
:url="baseUrl" :url="baseUrl"
:tree-setting="treeSetting"
class="tree-table" class="tree-table"
v-bind="$attrs" v-bind="$attrs"
/> />
@@ -73,17 +73,17 @@ export default {
columns: [ columns: [
{ {
prop: 'name', prop: 'name',
label: this.$t('assets.Name'), label: this.$t('Name'),
sortable: true sortable: true
}, },
{ {
prop: 'address', prop: 'address',
label: this.$t('assets.ipDomain'), label: this.$t('IpDomain'),
sortable: 'custom' sortable: 'custom'
}, },
{ {
prop: 'platform', prop: 'platform',
label: this.$t('assets.Platform'), label: this.$t('Platform'),
sortable: true, sortable: true,
formatter: function(row) { formatter: function(row) {
return row.platform.name return row.platform.name

View File

@@ -136,16 +136,22 @@ export default {
.tree-table { .tree-table {
.left { .left {
padding: 5px; padding: 5px 0;
.ztree { .ztree {
min-height: 500px; height: 100%;
height: inherit !important; }
}
.right {
.transition-box {
padding-left: 0;
} }
} }
.mini { .mini {
padding-top: 8px; padding-top: 8px;
width: 1px;
} }
.transition-box { .transition-box {

View File

@@ -2,9 +2,9 @@
<TreeTable <TreeTable
ref="TreeList" ref="TreeList"
:active-menu.sync="treeTableConfig.activeMenu" :active-menu.sync="treeTableConfig.activeMenu"
:component="treeComponent"
:table-config="tableConfig" :table-config="tableConfig"
:tree-tab-config="treeTableConfig" :tree-tab-config="treeTableConfig"
component="TabTree"
v-bind="$attrs" v-bind="$attrs"
v-on="$listeners" v-on="$listeners"
> >
@@ -63,12 +63,14 @@ export default {
const vm = this const vm = this
return { return {
treeComponent: 'TabTree',
treeTabConfig: { treeTabConfig: {
activeMenu: 'CustomTree', activeMenu: 'CustomTree',
submenu: [ submenu: [
{ {
title: this.$t('assets.AssetTree'), title: this.$t('AssetTree'),
name: 'CustomTree', name: 'CustomTree',
icon: 'fa-tree',
treeSetting: { treeSetting: {
showAssets, showAssets,
showMenu: false, showMenu: false,
@@ -94,13 +96,14 @@ export default {
} }
}, },
{ {
title: this.$t('assets.BuiltinTree'), title: this.$t('TypeTree'),
icon: 'fa-list-ul',
name: 'BuiltinTree', name: 'BuiltinTree',
treeSetting: { treeSetting: {
showRefresh: true, showRefresh: true,
showAssets: false, showAssets: false,
showSearch: false, showSearch: false,
customTreeHeaderName: this.$t('assets.BuiltinTree'), customTreeHeaderName: this.$t('TypeTree'),
url: '/api/v1/assets/nodes/category/tree/', url: '/api/v1/assets/nodes/category/tree/',
nodeUrl: this.treeSetting?.nodeUrl || this.nodeUrl, nodeUrl: this.treeSetting?.nodeUrl || this.nodeUrl,
treeUrl: `/api/v1/assets/nodes/category/tree/?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`, treeUrl: `/api/v1/assets/nodes/category/tree/?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`,

View File

@@ -7,7 +7,7 @@
type="primary" type="primary"
@click="onOpenDialog" @click="onOpenDialog"
> >
{{ $tc('common.Setting') }} {{ $tc('Setting') }}
</el-button> </el-button>
</div> </div>
<Dialog <Dialog
@@ -50,7 +50,7 @@ export default {
title: { title: {
type: String, type: String,
default: function() { default: function() {
return this.$t('assets.PushParams') return this.$t('PushParams')
} }
}, },
assets: { assets: {

View File

@@ -1,5 +1,5 @@
<template> <template>
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" /> <ListTable ref="ListTable" :header-actions="headerActions" :table-config="tableConfig" />
</template> </template>
<script> <script>
@@ -27,7 +27,7 @@ export default {
], ],
columnsMeta: { columnsMeta: {
ip: { ip: {
label: this.$t('assets.ip') label: this.$t('Ip')
}, },
actions: { actions: {
formatterArgs: { formatterArgs: {
@@ -37,7 +37,7 @@ export default {
extraActions: [ extraActions: [
{ {
name: 'UnlockIP', name: 'UnlockIP',
title: this.$t('setting.Unblock'), title: this.$t('Unblock'),
can: this.$hasPerm('settings.change_security'), can: this.$hasPerm('settings.change_security'),
type: 'primary', type: 'primary',
callback: ({ row }) => { callback: ({ row }) => {
@@ -45,7 +45,7 @@ export default {
'/api/v1/settings/security/unlock-ip/', '/api/v1/settings/security/unlock-ip/',
{ ips: [row.ip] } { ips: [row.ip] }
).then(() => { ).then(() => {
vm.$message.success(this.$tc('common.UnlockSuccessMsg')) vm.$message.success(this.$tc('UnlockSuccessMsg'))
vm.$refs.ListTable.reloadTable() vm.$refs.ListTable.reloadTable()
}) })
} }
@@ -68,7 +68,7 @@ export default {
extraMoreActions: [ extraMoreActions: [
{ {
name: 'UnlockSelected', name: 'UnlockSelected',
title: this.$t('setting.BulkUnblock'), title: this.$t('BatchUnblock'),
type: 'primary', type: 'primary',
can: ({ selectedRows }) => { can: ({ selectedRows }) => {
return selectedRows.length > 0 return selectedRows.length > 0
@@ -80,7 +80,7 @@ export default {
ips: selectedRows.map(v => { return v.ip }) ips: selectedRows.map(v => { return v.ip })
} }
).then(res => { ).then(res => {
vm.$message.success(vm.$tc('common.UnlockSuccessMsg')) vm.$message.success(vm.$tc('UnlockSuccessMsg'))
vm.$refs.ListTable.reloadTable() vm.$refs.ListTable.reloadTable()
}) })
} }

View File

@@ -6,18 +6,18 @@
type="primary" type="primary"
@click="onOpenDialog" @click="onOpenDialog"
> >
{{ $tc('common.View') }} {{ $tc('View') }}
<span>({{ $tc('setting.LockedIP', ipCounts ) }})</span> <span>({{ $tc('LockedIP', ipCounts ) }})</span>
</el-button> </el-button>
</div> </div>
<Dialog <Dialog
:visible.sync="visible" :destroy-on-close="true"
:title="title"
width="40%"
:show-cancel="false" :show-cancel="false"
:show-confirm="false" :show-confirm="false"
:destroy-on-close="true" :title="title"
:visible.sync="visible"
v-bind="$attrs" v-bind="$attrs"
width="40%"
v-on="$listeners" v-on="$listeners"
> >
<BlockedIPList /> <BlockedIPList />
@@ -43,7 +43,7 @@ export default {
title: { title: {
type: String, type: String,
default: function() { default: function() {
return this.$t('setting.BlockedIPS') return this.$t('BlockedIPS')
} }
}, },
url: { url: {

View File

@@ -1,42 +1,33 @@
<template> <template>
<div class="container"> <div class="container">
<div class="chat-action">
<Select2
v-model="select.value"
:disabled="isLoading || isSelectDisabled"
v-bind="select"
@change="onSelectChange"
/>
</div>
<div class="chat-input"> <div class="chat-input">
<el-input <el-input
v-model="inputValue" v-model="inputValue"
:disabled="isLoading" :disabled="isLoading"
:placeholder="$tc('common.InputMessage')" :placeholder="$tc('InputMessage')"
:rows="expanded ? 3 :2"
type="textarea" type="textarea"
@compositionend="isIM = false" @compositionend="isIM = false"
@compositionstart="isIM = true" @compositionstart="isIM = true"
@keypress.native="onKeyEnter" @keypress.native="onKeyEnter"
/> />
<div class="input-action">
<span class="right">
<i :class="{'active': inputValue }" class="fa fa-send" @click="onSendHandle" />
</span>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import Select2 from '../../../../Form/FormFields/Select2.vue'
import { useChat } from '../../useChat.js' import { useChat } from '../../useChat.js'
const { setLoading } = useChat() const { setLoading } = useChat()
export default { export default {
components: { Select2 }, components: { },
props: { props: {
expanded: {
type: Boolean,
default: false
}
}, },
data() { data() {
return { return {
@@ -46,7 +37,7 @@ export default {
url: '/api/v1/settings/chatai-prompts/', url: '/api/v1/settings/chatai-prompts/',
value: '', value: '',
multiple: false, multiple: false,
placeholder: this.$t('common.Prompt'), placeholder: this.$t('Prompt'),
ajax: { ajax: {
transformOption: (item) => { transformOption: (item) => {
return { label: item.name, value: item.content } return { label: item.name, value: item.content }
@@ -109,7 +100,7 @@ export default {
} }
} }
.el-input__icon { .el-input__icon {
line-height: 0px; line-height: 0;
} }
} }
} }
@@ -117,20 +108,14 @@ export default {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border: 1px solid #DCDFE6;
border-radius: 12px; border-radius: 12px;
&:has(.el-textarea__inner:focus) {
border: 1px solid var(--color-primary);
}
&>>> .el-textarea { &>>> .el-textarea {
height: 100%; height: 100%;
.el-textarea__inner { .el-textarea__inner {
height: 100%; height: 100%;
padding: 8px 10px; padding: 8px 10px;
border: none;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
resize: none; resize: none;
border-radius: 5px;
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 12px; width: 12px;
} }
@@ -143,21 +128,6 @@ export default {
cursor: no-drop; cursor: no-drop;
} }
} }
.input-action {
overflow: hidden;
padding: 0 16px 15px;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
.right {
float: right;
.active {
color: var(--color-primary);
}
i {
cursor: pointer;
}
}
}
} }
} }
</style> </style>

View File

@@ -21,7 +21,7 @@
<div class="action"> <div class="action">
<el-tooltip <el-tooltip
v-if="isSystemError && isLoading" v-if="isSystemError && isLoading"
:content="$tc('common.Reconnect')" :content="$tc('Reconnect')"
effect="dark" effect="dark"
placement="top" placement="top"
> >
@@ -69,7 +69,7 @@ export default {
dropdownOptions: [ dropdownOptions: [
{ {
action: 'copy', action: 'copy',
label: this.$t('common.Copy') label: this.$t('Copy')
} }
] ]
} }

View File

@@ -22,8 +22,8 @@
round round
size="small" size="small"
@click="onStopHandle" @click="onStopHandle"
>{{ $tc('common.Stop') }}</el-button> >{{ $tc('Stop') }}</el-button>
<ChatInput ref="chatInput" @send="onSendHandle" @select-prompt="onSelectPromptHandle" /> <ChatInput ref="chatInput" :expanded="expanded" @send="onSendHandle" @select-prompt="onSelectPromptHandle" />
</div> </div>
</div> </div>
</template> </template>
@@ -52,6 +52,10 @@ export default {
ChatMessage ChatMessage
}, },
props: { props: {
expanded: {
type: Boolean,
default: false
}
}, },
data() { data() {
return { return {
@@ -60,14 +64,6 @@ export default {
currentConversationId: '', currentConversationId: '',
showIntroduction: false, showIntroduction: false,
introduction: [ introduction: [
{
title: this.$t('common.introduction.ConceptTitle'),
content: this.$t('common.introduction.ConceptContent')
},
{
title: this.$t('common.introduction.IdeaTitle'),
content: this.$t('common.introduction.IdeaContent')
}
] ]
} }
}, },
@@ -102,7 +98,7 @@ export default {
this.$refs.chatInput.select.value = '' this.$refs.chatInput.select.value = ''
const chat = { const chat = {
message: { message: {
content: this.$t('common.ChatHello'), content: this.$t('ChatHello'),
role: 'assistant', role: 'assistant',
create_time: new Date() create_time: new Date()
} }
@@ -164,7 +160,7 @@ export default {
} else { } else {
const chat = { const chat = {
message: { message: {
content: this.$t('common.ConnectionDropped'), content: this.$t('ConnectionDropped'),
role: 'assistant', role: 'assistant',
create_time: new Date() create_time: new Date()
}, },
@@ -252,10 +248,10 @@ export default {
} }
.input-box { .input-box {
position: relative; position: relative;
height: 160px; //height: 60px;
padding: 0 15px; padding: 0 15px;
margin-bottom: 15px; margin-bottom: 15px;
border-top: 1px solid #ececec; //border-top: 1px solid #ececec;
} }
.stop { .stop {
position: absolute; position: absolute;

View File

@@ -3,15 +3,12 @@
<div class="close-sidebar"> <div class="close-sidebar">
<i v-if="hasClose" class="el-icon-close" @click="onClose" /> <i v-if="hasClose" class="el-icon-close" @click="onClose" />
</div> </div>
<el-tabs v-model="active" :tab-position="'right'" @tab-click="handleClick"> <div v-if="!expanded" class="close-sidebar">
<el-tab-pane v-for="(item) in submenu" :key="item.name" :name="item.name"> <i class="fa fa-expand" style="font-weight: 200" @click="$emit('expand')" />
<span slot="label"> </div>
<el-tooltip effect="dark" placement="left" :content="item.label"> <div v-if="expanded" class="close-sidebar">
<svg-icon :icon-class="item.icon" /> <i class="fa fa-compress" style="font-weight: 200" @click="$emit('compress')" />
</el-tooltip> </div>
</span>
</el-tab-pane>
</el-tabs>
</div> </div>
</template> </template>
@@ -29,6 +26,10 @@ export default {
submenu: { submenu: {
type: Array, type: Array,
default: () => [] default: () => []
},
expanded: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@@ -36,11 +37,11 @@ export default {
} }
}, },
methods: { methods: {
handleClick(tab, event) {
this.$emit('tab-click', tab)
},
onClose() { onClose() {
this.$parent.onClose() this.$emit('close')
},
handleExpand() {
this.$emit('expand-full')
} }
} }
} }
@@ -51,17 +52,23 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: #f0f1f5; background-color: #f0f1f5;
.close-sidebar { .close-sidebar {
height: 48px; height: 48px;
padding: 12px 0; padding: 12px 0;
text-align: center; text-align: center;
font-size: 14px; font-size: 16px;
cursor: pointer; cursor: pointer;
i { i {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
padding: 4px; padding: 4px;
}
i, .svg{
border-radius: 2px; border-radius: 2px;
&:hover { &:hover {
color: var(--color-primary); color: var(--color-primary);
background: var(--menu-hover); background: var(--menu-hover);
@@ -71,8 +78,8 @@ export default {
} }
>>> .el-tabs { >>> .el-tabs {
.el-tabs__item { .el-tabs__item {
padding: 0 13px; padding: 0 10px;
font-size: 15px; font-size: 14px;
:hover { :hover {
color: #7b8085; color: #7b8085;
} }

View File

@@ -1,26 +1,36 @@
<template> <template>
<div class="chat"> <DrawerPanel ref="drawer" :expanded="expanded" :height="height" :icon="robotUrl" :modal="false" @toggle="onToggle">
<div class="container"> <div class="chat">
<div class="header"> <div class="container">
<div class="left"> <div ref="header" class="header" @mousedown="handleMoveMouseDown" @mouseup="handleMouseMoveUp">
<img :src="robotUrl" alt=""> <div class="left">
<span class="title">{{ title }}</span> <img :src="robotUrl" alt="">
<span class="title">{{ title }}</span>
</div>
<span class="new" @click="onNewChat">
<i class="el-icon-plus" />
<span>{{ $tc('NewChat') }}</span>
</span>
</div>
<div class="content">
<keep-alive>
<component :is="active" ref="component" :expanded="expanded" />
</keep-alive>
</div> </div>
<span class="new" @click="onNewChat">
<i class="el-icon-plus" />
<span>{{ $tc('common.NewChat') }}</span>
</span>
</div> </div>
<div class="content"> <div class="sidebar">
<keep-alive> <Sidebar
<component :is="active" ref="component" /> :active.sync="active"
</keep-alive> :expanded="expanded"
v-bind="$attrs"
@close="onClose"
@compress="compress"
@expand="expandFull"
v-on="$listeners"
/>
</div> </div>
</div> </div>
<div class="sidebar"> </DrawerPanel>
<Sidebar v-bind="$attrs" :active.sync="active" :submenu="submenu" />
</div>
</div>
</template> </template>
<script> <script>
@@ -28,9 +38,11 @@ import Sidebar from './components/Sidebar/index.vue'
import Chat from './components/ChitChat/index.vue' import Chat from './components/ChitChat/index.vue'
import { getInputFocus } from './useChat.js' import { getInputFocus } from './useChat.js'
import { ws } from '@/utils/socket' import { ws } from '@/utils/socket'
import DrawerPanel from '@/components/Apps/DrawerPanel/index.vue'
export default { export default {
components: { components: {
DrawerPanel,
Chat, Chat,
Sidebar Sidebar
}, },
@@ -38,7 +50,7 @@ export default {
title: { title: {
type: String, type: String,
default: function() { default: function() {
return this.$t('setting.ChatAI') return this.$t('ChatAI')
} }
}, },
drawerPanelVisible: { drawerPanelVisible: {
@@ -49,29 +61,39 @@ export default {
data() { data() {
return { return {
active: 'chat', active: 'chat',
robotUrl: require('../../../assets/img/robot-assistant.png'), robotUrl: require('@/assets/img/robot-assistant.png'),
submenu: [ height: '400px',
{ expanded: false,
name: 'chat', clientOffset: {}
label: this.$t('common.Chat'),
icon: 'chat'
}
]
} }
}, },
watch: { watch: {
drawerPanelVisible(value) { },
if (value && !ws) { mounted() {
this.initWebSocket()
}
}
}, },
methods: { methods: {
handleMoveMouseDown(event) {
console.log('Event: ', event)
this.$refs.drawer.handleHeaderMoveDown(event)
},
handleMouseMoveUp(event) {
this.$refs.drawer.handleHeaderMoveUp(event)
},
initWebSocket() { initWebSocket() {
this.$refs.component?.init() if (!ws) {
this.$refs.component?.init()
}
}, },
onClose() { onClose() {
this.$parent.show = false this.$refs.drawer.show = false
},
expandFull() {
this.height = '100%'
this.expanded = true
},
compress() {
this.height = '400px'
this.expanded = false
}, },
onNewChat() { onNewChat() {
this.active = 'chat' this.active = 'chat'
@@ -79,6 +101,12 @@ export default {
this.$refs.component?.onNewChat() this.$refs.component?.onNewChat()
getInputFocus() getInputFocus()
}) })
},
onToggle(status) {
this.initWebSocket()
if (status) {
getInputFocus()
}
} }
} }
} }
@@ -89,12 +117,15 @@ export default {
display: flex; display: flex;
width: 100%; width: 100%;
height: 100%; height: 100%;
.container { .container {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
.header { .header {
background: linear-gradient(90deg, #ebf1ff 24.34%, #e5fbf8 56.18%, #f2ebfe 90.18%);;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
height: 48px; height: 48px;

View File

@@ -1,7 +1,7 @@
<template> <template>
<div ref="drawer" :class="{show: show}" class="drawer"> <div ref="drawer" :class="{show: show}" class="drawer">
<div :style="{'background-color': modal ? 'rgba(0, 0, 0, .3)' : 'transparent'}" class="modal" /> <div v-if="modal" :style="{'background-color': modal ? 'rgba(0, 0, 0, .3)' : 'transparent'}" class="modal" />
<div :style="{'width': width}" class="drawer-panel"> <div ref="panel" :style="{width: width, height: height }" class="drawer-panel">
<div v-show="!show" ref="dragBox" class="handle-button"> <div v-show="!show" ref="dragBox" class="handle-button">
<i v-if="icon.startsWith('fa') || icon.startsWith('el')" :class="show ? 'el-icon-close': icon" /> <i v-if="icon.startsWith('fa') || icon.startsWith('el')" :class="show ? 'el-icon-close': icon" />
<img v-else :src="icon" alt=""> <img v-else :src="icon" alt="">
@@ -12,7 +12,6 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
@@ -26,6 +25,10 @@ export default {
type: String, type: String,
default: '440px' default: '440px'
}, },
height: {
type: String,
default: '400px'
},
modal: { modal: {
type: Boolean, type: Boolean,
default: true default: true
@@ -33,11 +36,16 @@ export default {
clickNotClose: { clickNotClose: {
type: Boolean, type: Boolean,
default: false default: false
},
expanded: {
type: Boolean,
default: false
} }
}, },
data() { data() {
return { return {
show: false show: false,
clientOffset: {}
} }
}, },
watch: { watch: {
@@ -46,6 +54,14 @@ export default {
this.addEventClick() this.addEventClick()
} }
this.$emit('toggle', this.show) this.$emit('toggle', this.show)
},
expanded(value) {
if (value) {
this.$refs.panel.style.top = '0px'
} else {
this.$refs.panel.style.top = 'auto'
this.$refs.panel.style.bottom = '2px'
}
} }
}, },
mounted() { mounted() {
@@ -55,49 +71,66 @@ export default {
beforeDestroy() { beforeDestroy() {
const element = this.$refs.drawer const element = this.$refs.drawer
element.remove() element.remove()
window.removeEventListener('click', this.closeSidebar) // window.removeEventListener('click', this.closeSidebar)
}, },
methods: { methods: {
handleHeaderMoveUp(event) {
this.handleMouseMoveUp(event)
},
handleHeaderMoveDown(event) {
this.handleMoveMouseDown(event, true)
},
handleMoveMouseDown(event, isHeader = false) {
const dragBox = this.$refs.dragBox
const vm = this
const rect = dragBox.getBoundingClientRect()
const parentRect = dragBox.parentElement.getBoundingClientRect()
const clientOffset = this.clientOffset
clientOffset.clientX = event.clientX
clientOffset.clientY = event.clientY
const handleOnMouseMove = _.debounce(function(event) {
const diffY = rect.top - parentRect.top
const maxY = window.innerHeight - parentRect.height
let parentY = event.clientY - diffY
// 这个是拖动的 header, 不是 bar
if (isHeader) {
parentY = event.clientY - rect.height / 2
}
if (parentY < 0) {
parentY = 0
} else if (parentY > maxY) {
parentY = maxY
}
if (vm.$refs.panel) {
vm.$refs.panel.style.top = parentY + 'px'
}
})
document.onmousemove = handleOnMouseMove
document.onmouseup = function() {
document.removeEventListener('mousemove', handleOnMouseMove)
setTimeout(() => {
document.onmousemove = null
document.onmouseup = null
}, 0)
}
},
handleMouseMoveUp(event) {
const clientOffset = this.clientOffset
const clientX = event.clientX
const clientY = event.clientY
if (this.isDifferenceWithinThreshold(clientX, clientOffset.clientX) &&
this.isDifferenceWithinThreshold(clientY, clientOffset.clientY)) {
this.show = !this.show
}
},
init() { init() {
this.$nextTick(() => { this.$nextTick(() => {
const dragBox = this.$refs.dragBox const dragBox = this.$refs.dragBox
const clientOffset = {} dragBox.addEventListener('mousedown', this.handleMoveMouseDown, false)
dragBox.addEventListener('mousedown', (event) => { dragBox.addEventListener('mouseup', this.handleMouseMoveUp, false)
const offsetX = dragBox.getBoundingClientRect().left
const offsetY = dragBox.getBoundingClientRect().top
const innerX = event.clientX - offsetX
const innerY = event.clientY - offsetY
clientOffset.clientX = event.clientX
clientOffset.clientY = event.clientY
document.onmousemove = function(event) {
dragBox.style.left = event.clientX - innerX + 'px'
dragBox.style.top = event.clientY - innerY + 'px'
const dragDivTop = window.innerHeight - dragBox.getBoundingClientRect().height
const dragDivLeft = window.innerWidth - dragBox.getBoundingClientRect().width
dragBox.style.left = dragDivLeft + 'px'
dragBox.style.left = '-48px'
if (dragBox.getBoundingClientRect().top <= 0) {
dragBox.style.top = '0px'
}
if (dragBox.getBoundingClientRect().top >= dragDivTop) {
dragBox.style.top = dragDivTop + 'px'
}
event.preventDefault()
event.stopPropagation()
}
document.onmouseup = function() {
document.onmousemove = null
document.onmouseup = null
}
}, false)
dragBox.addEventListener('mouseup', (event) => {
const clientX = event.clientX
const clientY = event.clientY
if (this.isDifferenceWithinThreshold(clientX, clientOffset.clientX) && this.isDifferenceWithinThreshold(clientY, clientOffset.clientY)) {
this.show = !this.show
}
})
}) })
}, },
isDifferenceWithinThreshold(num1, num2, threshold = 5) { isDifferenceWithinThreshold(num1, num2, threshold = 5) {
@@ -105,7 +138,7 @@ export default {
return difference <= threshold return difference <= threshold
}, },
addEventClick() { addEventClick() {
window.addEventListener('click', this.closeSidebar) // window.addEventListener('click', this.closeSidebar)
}, },
closeSidebar(evt) { closeSidebar(evt) {
const parent = evt.target.closest('.drawer-panel') const parent = evt.target.closest('.drawer-panel')
@@ -135,11 +168,10 @@ export default {
.drawer-panel { .drawer-panel {
position: fixed; position: fixed;
top: 0; bottom: 1px;
right: 0; right: -1px;
width: 100%; width: 100%;
min-width: 260px; min-width: 260px;
height: 100vh;
user-select: none; user-select: none;
transition: transform .25s cubic-bezier(.7, .3, .1, 1); transition: transform .25s cubic-bezier(.7, .3, .1, 1);
box-shadow: 0 0 8px 4px #00000014; box-shadow: 0 0 8px 4px #00000014;
@@ -174,7 +206,7 @@ export default {
.handle-button { .handle-button {
position: absolute; position: absolute;
top: 30%; bottom: 20%;
left: -48px; left: -48px;
width: 48px; width: 48px;
height: 45px; height: 45px;
@@ -191,19 +223,21 @@ export default {
cursor: pointer; cursor: pointer;
&:hover { &:hover {
left: -50px !important; left: -51px !important;
width: 50px !important; width: 50px !important;
transform: scale(1.06); transform: scale(1.01);
} }
i { i {
font-size: 20px; font-size: 20px;
line-height: 45px; line-height: 45px;
pointer-events: none;
} }
img { img {
width: 22px; width: 22px;
height: 22px; height: 22px;
transform: translateY(10%); transform: translateY(10%);
margin-left: 3px; margin-left: 3px;
pointer-events: none;
} }
} }
</style> </style>

View File

@@ -4,18 +4,18 @@
:destroy-on-close="true" :destroy-on-close="true"
:show-cancel="false" :show-cancel="false"
:show-confirm="false" :show-confirm="false"
:title="$tc('assets.TestGatewayTestConnection')" :title="$tc('TestGatewayTestConnection')"
:visible.sync="iVisible" :visible.sync="iVisible"
top="35vh" top="35vh"
width="40%" width="40%"
> >
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :md="4" :sm="24"> <el-col :md="4" :sm="24">
<div style="line-height: 34px">{{ $t('assets.SSHPort') }}</div> <div style="line-height: 34px">{{ $t('SSHPort') }}</div>
</el-col> </el-col>
<el-col :md="14" :sm="24"> <el-col :md="14" :sm="24">
<el-input v-model="port" /> <el-input v-model="port" />
<span class="help-tips help-block">{{ $t('assets.TestGatewayHelpMessage') }}</span> <span class="help-tips help-block">{{ $t('TestGatewayHelpMessage') }}</span>
</el-col> </el-col>
<el-col :md="4" :sm="24"> <el-col :md="4" :sm="24">
<el-button <el-button
@@ -25,7 +25,7 @@
type="primary" type="primary"
@click="dialogConfirm" @click="dialogConfirm"
> >
{{ this.$t('common.Confirm') }} {{ this.$t('Confirm') }}
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
@@ -75,7 +75,7 @@ export default {
methods: { methods: {
dialogConfirm() { dialogConfirm() {
if (isNaN(this.port)) { if (isNaN(this.port)) {
return this.$message.error(this.$tc('common.TestPortErrorMsg')) return this.$message.error(this.$tc('TestPortErrorMsg'))
} }
this.$axios.post( this.$axios.post(
`/api/v1/assets/gateways/${this.cell}/test-connective/`, `/api/v1/assets/gateways/${this.cell}/test-connective/`,

View File

@@ -37,7 +37,7 @@ export default {
], ],
columnsMeta: { columnsMeta: {
name: { name: {
label: this.$t('assets.Asset'), label: this.$t('Asset'),
formatter: (row) => { formatter: (row) => {
const to = { const to = {
name: 'AssetDetail', name: 'AssetDetail',

View File

@@ -18,7 +18,8 @@ export default {
props: { props: {
object: { object: {
type: Object, type: Object,
default: () => {} default: () => {
}
} }
}, },
data() { data() {
@@ -38,7 +39,8 @@ export default {
], ],
columnsMeta: { columnsMeta: {
name: { name: {
label: this.$t('common.Name'), label: this.$t('Name'),
width: 90,
formatter: (row) => { formatter: (row) => {
const to = { const to = {
name: 'UserDetail', name: 'UserDetail',
@@ -52,7 +54,7 @@ export default {
} }
}, },
system_roles: { system_roles: {
label: this.$t('users.SystemRoles'), label: this.$t('SystemRoles'),
formatter: (row) => { formatter: (row) => {
return row['system_roles'].map(item => item['display_name']).join(', ') || '-' return row['system_roles'].map(item => item['display_name']).join(', ') || '-'
}, },
@@ -60,7 +62,7 @@ export default {
columnKey: 'system_roles' columnKey: 'system_roles'
}, },
org_roles: { org_roles: {
label: this.$t('users.OrgRoles'), label: this.$t('OrgRoles'),
formatter: (row) => { formatter: (row) => {
return row['org_roles'].map(item => item['display_name']).join(', ') || '-' return row['org_roles'].map(item => item['display_name']).join(', ') || '-'
}, },

View File

@@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :md="12" :sm="24"> <el-col :md="16" :sm="24">
<IBox :title="title" class="block" v-bind="$attrs"> <IBox :title="title" class="block" v-bind="$attrs">
<el-timeline> <el-timeline>
<el-timeline-item <el-timeline-item
@@ -18,14 +18,14 @@
type="primary" type="primary"
@click.native="onClick(activity)" @click.native="onClick(activity)"
> >
{{ $tc('common.Detail') }} {{ $tc('Detail') }}
</el-link> </el-link>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</IBox> </IBox>
</el-col> </el-col>
</el-row> </el-row>
<DiffDetail ref="DetailDialog" :title="$tc('route.OperateLog')" /> <DiffDetail ref="DetailDialog" :title="$tc('OperateLog')" />
</div> </div>
</template> </template>
@@ -49,10 +49,10 @@ export default {
data() { data() {
return { return {
activityUrl: `/api/v1/audits/activities/?resource_id=${this.object.id}`, activityUrl: `/api/v1/audits/activities/?resource_id=${this.object.id}`,
title: `${this.$t('common.Activity')} - ${this.$t('common.Last30')}`, title: `${this.$t('Activity')} - ${this.$t('Last30')}`,
activities: [ activities: [
{ {
content: this.$t('common.Now'), content: this.$t('Now'),
timestamp: this.$moment().format('YYYY-MM-DD HH:mm:ss'), timestamp: this.$moment().format('YYYY-MM-DD HH:mm:ss'),
type: 'primary' type: 'primary'
} }

View File

@@ -16,7 +16,7 @@
<el-row :gutter="24" style="margin: 0 auto;"> <el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24"> <el-col :md="24" :sm="24">
<el-alert <el-alert
:title="$tc('auth.ReLoginTitle')" :title="$tc('ReLoginTitle')"
center center
style="margin-bottom: 20px;" style="margin-bottom: 20px;"
type="error" type="error"
@@ -26,7 +26,7 @@
<el-row :gutter="24" style="margin: 0 auto;"> <el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24"> <el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="logout"> <el-button class="confirm-btn" size="mini" type="primary" @click="logout">
{{ this.$t('auth.ReLogin') }} {{ this.$t('ReLogin') }}
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
@@ -73,7 +73,7 @@
<el-row :gutter="24" style="margin: 10px auto;"> <el-row :gutter="24" style="margin: 10px auto;">
<el-col :md="24" :sm="24"> <el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="handleConfirm"> <el-button class="confirm-btn" size="mini" type="primary" @click="handleConfirm">
{{ this.$t('common.Confirm') }} {{ this.$t('Confirm') }}
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
@@ -100,11 +100,11 @@ export default {
}, },
data() { data() {
return { return {
title: this.$t('common.CurrentUserVerify'), title: this.$t('CurrentUserVerify'),
smsWidth: 0, smsWidth: 0,
subTypeSelected: '', subTypeSelected: '',
inputPlaceholder: '', inputPlaceholder: '',
smsBtnText: this.$t('common.SendVerificationCode'), smsBtnText: this.$t('SendVerificationCode'),
smsBtnDisabled: false, smsBtnDisabled: false,
confirmTypeRequired: '', confirmTypeRequired: '',
subTypeChoices: [], subTypeChoices: [],
@@ -146,7 +146,7 @@ export default {
this.callback() this.callback()
this.visible = false this.visible = false
}).catch(() => { }).catch(() => {
this.title = this.$t('auth.NeedReLogin') this.title = this.$t('NeedReLogin')
this.visible = true this.visible = true
}) })
return return
@@ -158,7 +158,7 @@ export default {
this.visible = true this.visible = true
}).catch((err) => { }).catch((err) => {
const data = err.response?.data const data = err.response?.data
const msg = data?.error || data?.detail || data?.msg || this.$t('common.GetConfirmTypeFailed') const msg = data?.error || data?.detail || data?.msg || this.$t('GetConfirmTypeFailed')
this.$message.error(msg) this.$message.error(msg)
this.cancel(err) this.cancel(err)
}).finally(() => { }).finally(() => {
@@ -170,11 +170,11 @@ export default {
}, },
sendSMSCode() { sendSMSCode() {
this.$axios.post(`/api/v1/authentication/mfa/select/`, { type: 'sms' }).then(res => { this.$axios.post(`/api/v1/authentication/mfa/select/`, { type: 'sms' }).then(res => {
this.$message.success(this.$tc('common.VerificationCodeSent')) this.$message.success(this.$tc('VerificationCodeSent'))
let time = 60 let time = 60
const interval = setInterval(() => { const interval = setInterval(() => {
const originText = this.smsBtnText const originText = this.smsBtnText
this.smsBtnText = this.$t('common.Pending') + `: ${time}` this.smsBtnText = this.$t('Pending') + `: ${time}`
this.smsBtnDisabled = true this.smsBtnDisabled = true
time -= 1 time -= 1
@@ -191,7 +191,7 @@ export default {
return this.logout() return this.logout()
} }
if (this.subTypeSelected === 'otp' && this.secretValue.length !== 6) { if (this.subTypeSelected === 'otp' && this.secretValue.length !== 6) {
return this.$message.error(this.$tc('common.MFAErrorMsg')) return this.$message.error(this.$tc('MFAErrorMsg'))
} }
const data = { const data = {
confirm_type: this.confirmTypeRequired, confirm_type: this.confirmTypeRequired,

View File

@@ -47,9 +47,9 @@ export default {
methods: { methods: {
toChoicesDisplay(value) { toChoicesDisplay(value) {
if (!value) { if (!value) {
return this.$t('common.No') return this.$t('No')
} }
return this.$t('common.Yes') return this.$t('Yes')
}, },
isDatetime(value) { isDatetime(value) {
if (typeof value !== 'string') { if (typeof value !== 'string') {
@@ -92,7 +92,7 @@ export default {
) )
} }
return ( return (
<span>{this.displayValue}</span> <span title={this.displayValue}>{this.displayValue}</span>
) )
} }
} }

View File

@@ -1,14 +1,18 @@
<template> <template>
<DetailCard v-if="!loading && hasObject && items.length > 0" :items="items" v-bind="$attrs" /> <IBox v-if="loading" style="width: 100%; height: 200px" />
<div v-else>
<DetailCard v-if="hasObject && items.length > 0" :items="items" :loading="loading" v-bind="$attrs" />
</div>
</template> </template>
<script> <script>
import DetailCard from './index.vue' import DetailCard from './index.vue'
import { copy, toSafeLocalDateStr } from '@/utils/common' import { copy, toSafeLocalDateStr } from '@/utils/common'
import IBox from '@/components/IBox/index.vue'
export default { export default {
name: 'AutoDetailCard', name: 'AutoDetailCard',
components: { DetailCard }, components: { IBox, DetailCard },
props: { props: {
object: { object: {
type: Object, type: Object,
@@ -69,7 +73,7 @@ export default {
if (val === '-') { if (val === '-') {
return <span>{'-'}</span> return <span>{'-'}</span>
} }
return (<span style={{ cursor: 'pointer' }} onClick={() => copy(val)}> return (<span style={{ cursor: 'pointer' }} onClick={() => copy(val)} title={val}>
{val} {val}
</span>) </span>)
} }
@@ -104,48 +108,58 @@ export default {
let value = this.iObject[name] let value = this.iObject[name]
const label = fieldMeta.label const label = fieldMeta.label
const formatter = this.formatters[name]
if (formatter) {
this.items.push({
key: label,
value: value,
formatter: formatter
})
continue
}
if (Array.isArray(value)) { if (Array.isArray(value)) {
if (typeof value[0] === 'object') { const tp = typeof value[0]
value.forEach(item => { for (const [index, item] of value.entries()) {
let object = {}
if (tp === 'object') {
const fieldName = `${name}.${item.name}` const fieldName = `${name}.${item.name}`
if (excludes.includes(fieldName)) { if (excludes.includes(fieldName)) {
return continue
} }
this.items.push({ object = {
key: item.label, key: item.label,
value: item.value value: item.value
})
})
} else if (typeof value[0] === 'string') {
value.forEach((item, index) => {
let data = {}
if (index === 0) {
data = {
key: label,
value: value[index]
}
} else {
data = {
value: value[index]
}
} }
this.items.push(data) } else if (tp === 'string') {
}) object = {
value: value[index]
}
if (index === 0) {
object['key'] = label
}
}
if (index !== value.length - 1) {
object['class'] = 'array-item'
}
this.items.push(object)
} }
continue continue
} }
if (value === null || value === '') { if (value === null || value === '') {
value = '-' value = '-'
} else if (value === 0) {
value = 0
} else if (fieldMeta.type === 'datetime') { } else if (fieldMeta.type === 'datetime') {
value = toSafeLocalDateStr(value) value = toSafeLocalDateStr(value)
} else if (fieldMeta.type === 'labeled_choice') { } else if (fieldMeta.type === 'labeled_choice') {
value = value?.['label'] value = value?.['label']
} else if (fieldMeta.type === 'related_field' || fieldMeta.type === 'nested object') { } else if (fieldMeta.type === 'related_field' || fieldMeta.type === 'nested object' || value?.name) {
value = value?.['name'] value = value?.['name']
} else if (fieldMeta.type === 'm2m_related_field') { } else if (fieldMeta.type === 'm2m_related_field') {
value = value?.map(item => item['name']).join(', ') value = value?.map(item => item['name']).join(', ')
} else if (fieldMeta.type === 'boolean') { } else if (fieldMeta.type === 'boolean') {
value = value ? this.$t('common.Yes') : this.$t('common.No') value = value ? this.$t('Yes') : this.$t('No')
} }
if (value === undefined) { if (value === undefined) {
@@ -159,7 +173,7 @@ export default {
const item = { const item = {
key: label, key: label,
value: value, value: value,
formatter: this.formatters[name] || defaultFormatter[name] formatter: defaultFormatter[name]
} }
this.items.push(item) this.items.push(item)
} }

View File

@@ -1,7 +1,8 @@
<template> <template>
<IBox :fa="fa" :title="title"> <IBox :fa="fa" :title="title">
<el-form class="content" label-position="left" label-width="25%"> <el-form :label-width="labelWidth" class="content" label-position="left">
<el-form-item v-for="item in items" :key="item.key" :label="item.key"> <el-form-item v-for="item in items" :key="item.key" :class="item.class" :label="item.key">
<span slot="label"> {{ formateLabel(item.key) }}</span>
<ItemValue :value="item.value" class="item-value" v-bind="item" /> <ItemValue :value="item.value" class="item-value" v-bind="item" />
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -20,7 +21,7 @@ export default {
title: { title: {
type: String, type: String,
default() { default() {
return this.$t('common.BasicInfo') return this.$t('BasicInfo')
} }
}, },
fa: { fa: {
@@ -34,6 +35,18 @@ export default {
align: { align: {
type: String, type: String,
default: 'left' default: 'left'
},
labelWidth: {
type: String,
default: '25%'
}
},
methods: {
formateLabel(label) {
if (!label) {
return label
}
return label.replace(' amount', '').replace('数量', '')
} }
} }
} }
@@ -53,14 +66,31 @@ export default {
border-bottom: none; border-bottom: none;
} }
&.array-item {
border-bottom: none;
>>> .el-form-item__content {
border-bottom: 1px dashed #EBEEF5
}
>>> .el-form-item__label:last-child {
border: 1px dashed #EBEEF5;
}
}
&:hover { &:hover {
} }
>>> .el-form-item__label { >>> .el-form-item__label {
padding-right: 8%; padding-right: 8%;
white-space: nowrap; //white-space: nowrap;
text-overflow: ellipsis; //text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
span {
display: inline-block;
line-height: 1.5;
}
} }
>>> .el-form-item__content { >>> .el-form-item__content {

View File

@@ -3,14 +3,14 @@
<table class="CardTable" style="width: 100%;table-layout:fixed;"> <table class="CardTable" style="width: 100%;table-layout:fixed;">
<tr> <tr>
<td colspan="2"> <td colspan="2">
<Select2 ref="select2" v-model="select2.value" :disabled="iDisabled" v-bind="select2" /> <Select2 ref="select2" v-model="select2.value" :disabled="iDisabled" show-select-all v-bind="select2" />
</td> </td>
</tr> </tr>
<slot /> <slot />
<tr> <tr>
<td colspan="2"> <td colspan="2">
<el-button :disabled="iDisabled" :loading="submitLoading" :type="type" size="small" @click="addObjects"> <el-button :disabled="iDisabled" :loading="submitLoading" :type="type" size="small" @click="addObjects">
{{ $t('common.Add') }} {{ $t('Add') }}
</el-button> </el-button>
</td> </td>
</tr> </tr>
@@ -32,7 +32,7 @@
<td colspan="2"> <td colspan="2">
<el-button :disabled="iDisabled" :type="type" size="small" style="width: 100%" @click="loadMore"> <el-button :disabled="iDisabled" :type="type" size="small" style="width: 100%" @click="loadMore">
<i class="fa fa-arrow-down" /> <i class="fa fa-arrow-down" />
{{ $t('common.More') }} {{ $t('More') }}
</el-button> </el-button>
</td> </td>
</tr> </tr>
@@ -119,7 +119,7 @@ export default {
this.$log.debug('disabled values remove index: ', i) this.$log.debug('disabled values remove index: ', i)
that.select2.disabledValues.splice(i, 1) that.select2.disabledValues.splice(i, 1)
} }
that.$message.success(that.$t('common.RemoveSuccessMsg')) that.$message.success(that.$t('RemoveSuccessMsg'))
} }
}, },
onDeleteFail: { onDeleteFail: {
@@ -142,13 +142,17 @@ export default {
type: Function, type: Function,
default: (objects, that) => {} default: (objects, that) => {}
}, },
showAddAll: {
type: Boolean,
default: false
},
onAddSuccess: { onAddSuccess: {
type: Function, type: Function,
default(objects, that) { default(objects, that) {
that.$log.debug('Select value', that.select2.value) that.$log.debug('Select value', that.select2.value)
that.iHasObjects = [...that.iHasObjects, ...objects] that.iHasObjects = [...that.iHasObjects, ...objects]
that.$refs.select2.clearSelected() that.$refs.select2.clearSelected()
that.$message.success(that.$t('common.AddSuccessMsg')) that.$message.success(that.$t('AddSuccessMsg'))
} }
}, },
getHasObjects: { getHasObjects: {
@@ -161,6 +165,7 @@ export default {
iHasObjects: this.hasObjects || [], iHasObjects: this.hasObjects || [],
totalHasObjectsLength: 0, totalHasObjectsLength: 0,
submitLoading: false, submitLoading: false,
selectAllDisabled: false,
params: { params: {
page: 1, page: 1,
hasMore: false, hasMore: false,
@@ -253,11 +258,13 @@ export default {
} }
}) })
data = this.iAjax.processResults.bind(this)(data) data = this.iAjax.processResults.bind(this)(data)
data.results && data.results.forEach((v) => { if (data.results) {
if (!this.hasObjects.find((item) => item.value === v.value)) { data.results.forEach((v) => {
this.iHasObjects.push(v) if (!this.iHasObjects.find((item) => item.value === v.value)) {
} this.iHasObjects.push(v)
}) }
})
}
// 如果还有其它页,继续获取, 如果没有就停止 // 如果还有其它页,继续获取, 如果没有就停止
this.params.hasMore = !!data.pagination this.params.hasMore = !!data.pagination
this.totalHasObjectsLength = data.total this.totalHasObjectsLength = data.total
@@ -292,6 +299,13 @@ export default {
this.performAdd(objects, this).then( this.performAdd(objects, this).then(
() => this.onAddSuccess(objects, this) () => this.onAddSuccess(objects, this)
) )
},
async selectAll() {
this.selectAllDisabled = true
this.disabled = true
await this.$refs.select2.selectAll()
this.selectAllDisabled = false
this.disabled = false
} }
} }
} }

View File

@@ -6,12 +6,18 @@
v-show="action.dropdown.length > 0" v-show="action.dropdown.length > 0"
:key="action.name" :key="action.name"
class="action-item" class="action-item"
trigger="click"
placement="bottom-start" placement="bottom-start"
trigger="click"
@command="handleDropdownCallback" @command="handleDropdownCallback"
> >
<el-button class="more-action" :size="size" v-bind="cleanButtonAction(action)"> <el-button :size="size" class="more-action" v-bind="cleanButtonAction(action)">
{{ action.title }}<i class="el-icon-arrow-down el-icon--right" /> <span v-if="action.icon && !action.icon.startsWith('el-')" class="pre-icon">
<i v-if="action.icon.startsWith('fa')" :class="'fa fa-fw ' + action.icon" />
<svg-icon v-else :icon-class="action.icon" />
</span>
<span v-if="action.title">
{{ action.title }}<i class="el-icon-arrow-down el-icon--right" />
</span>
</el-button> </el-button>
<el-dropdown-menu slot="dropdown" style="overflow: auto;max-height: 60vh"> <el-dropdown-menu slot="dropdown" style="overflow: auto;max-height: 60vh">
<template v-for="option in action.dropdown"> <template v-for="option in action.dropdown">
@@ -26,11 +32,12 @@
<el-dropdown-item <el-dropdown-item
:key="option.name" :key="option.name"
:command="[option, action]" :command="[option, action]"
v-bind="option" class="dropdown-item"
v-bind="{...option, icon: ''}"
> >
<span v-if="option.fa"> <span v-if="option.icon" class="pre-icon">
<i v-if="option.fa.startsWith('fa-')" :class="'fa ' + option.fa" /> <i v-if="option.icon.startsWith('fa')" :class="'fa fa-fw ' + option.icon" />
<svg-icon v-else :icon-class="option.fa" style="font-size: 14px; margin-right: 2px; margin-left: -2px;" /> <svg-icon v-else :icon-class="option.icon" />
</span> </span>
{{ option.title }} {{ option.title }}
</el-dropdown-item> </el-dropdown-item>
@@ -42,15 +49,15 @@
v-else v-else
:key="action.name" :key="action.name"
:size="size" :size="size"
v-bind="cleanButtonAction(action)"
class="action-item" class="action-item"
v-bind="{...cleanButtonAction(action), icon: action.icon && action.icon.startsWith('el-') ? action.icon : ''}"
@click="handleClick(action)" @click="handleClick(action)"
> >
<el-tooltip :disabled="!action.tip" :content="action.tip" placement="top"> <el-tooltip :content="action.tip" :disabled="!action.tip" placement="top">
<span> <span>
<span v-if="action.fa" style="vertical-align: initial;"> <span v-if="action.icon && !action.icon.startsWith('el-')" style="vertical-align: initial">
<i v-if="action.fa.startsWith('fa-')" :class="'fa ' + action.fa" /> <i v-if="action.icon.startsWith('fa')" :class="'fa ' + action.icon" />
<svg-icon v-else :icon-class="action.fa" style="font-size: 14px;" /> <svg-icon v-else :icon-class="action.icon" />
</span> </span>
{{ action.title }} {{ action.title }}
</span> </span>
@@ -61,6 +68,7 @@
</template> </template>
<script> <script>
import { toSentenceCase } from '@/utils/common'
export default { export default {
name: 'DataActions', name: 'DataActions',
@@ -88,6 +96,16 @@ export default {
} }
}, },
methods: { methods: {
hasIcon(action, type = '') {
const icon = action.icon
if (!icon) {
return false
}
if (type) {
return icon.startsWith(type)
}
return true
},
handleDropdownCallback(command) { handleDropdownCallback(command) {
const [option, dropdown] = command const [option, dropdown] = command
const defaultCallback = () => this.$log.debug('No callback found: ', option, dropdown) const defaultCallback = () => this.$log.debug('No callback found: ', option, dropdown)
@@ -100,6 +118,9 @@ export default {
} }
return callback(option) return callback(option)
}, },
toSentenceCase(s) {
return toSentenceCase(s)
},
handleClick(action) { handleClick(action) {
if (action && action.callback) { if (action && action.callback) {
action.callback(action) action.callback(action)
@@ -135,7 +156,7 @@ export default {
if (!v) { if (!v) {
continue continue
} }
const action = Object.assign({}, v) const action = { ...v }
// 是否拥有这个action // 是否拥有这个action
const has = this.checkItem(action, 'has') const has = this.checkItem(action, 'has')
delete action['has'] delete action['has']
@@ -150,7 +171,6 @@ export default {
action.disabled = !can action.disabled = !can
if (action.dropdown) { if (action.dropdown) {
// const dropdown = this.cleanActions(action.dropdown)
action.dropdown = this.cleanActions(action.dropdown) action.dropdown = this.cleanActions(action.dropdown)
} }
cleanedActions.push(action) cleanedActions.push(action)
@@ -167,6 +187,25 @@ export default {
justify-content: center; justify-content: center;
} }
.dropdown-item {
.pre-icon {
width: 17px;
display: inline-block;
}
>>> i.fa {
font-size: 13px;
height: 13px;
width: 13px;
margin-right: 0;
}
>>> .svg-icon {
font-size: 13px;
height: 13px;
width: 13px;
}
}
.dropdown-menu-title { .dropdown-menu-title {
text-align: left; text-align: left;
font-size: 12px; font-size: 12px;
@@ -184,6 +223,11 @@ export default {
.el-button-ungroup .action-item { .el-button-ungroup .action-item {
margin-left: 4px; margin-left: 4px;
line-height: 1;
}
.action-item.el-dropdown {
font-size: 11px;
} }
.el-button-ungroup .action-item:first-child { .el-button-ungroup .action-item:first-child {

View File

@@ -8,7 +8,7 @@
> >
<div> <div>
<div v-if="isEmpty()" style="text-align: center"> <div v-if="isEmpty()" style="text-align: center">
{{ this.$tc('common.NoContent') }} {{ this.$tc('NoContent') }}
</div> </div>
<div v-else> <div v-else>
<el-table <el-table
@@ -16,18 +16,18 @@
class="diffTable" class="diffTable"
> >
<el-table-column <el-table-column
:label="$tc('audits.ChangeField')" :label="$tc('ChangeField')"
:prop="fieldName" :prop="fieldName"
show-overflow-tooltip show-overflow-tooltip
width="100" width="150"
/> />
<el-table-column <el-table-column
:label="$tc('audits.BeforeChange')" :label="$tc('BeforeChange')"
:prop="leftKeyName" :prop="leftKeyName"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column <el-table-column
:label="$tc('audits.AfterChange')" :label="$tc('AfterChange')"
:prop="rightKeyName" :prop="rightKeyName"
show-overflow-tooltip show-overflow-tooltip
/> />

View File

@@ -12,8 +12,8 @@
<slot /> <slot />
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<slot name="footer"> <slot name="footer">
<el-button v-if="showCancel && showButtons" @click="onCancel">{{ cancelTitle }}</el-button> <el-button v-if="showCancel && showButtons" size="small" @click="onCancel">{{ cancelTitle }}</el-button>
<el-button v-if="showConfirm && showButtons" :loading="loadingStatus" type="primary" @click="onConfirm"> <el-button v-if="showConfirm && showButtons" :loading="loadingStatus" size="small" type="primary" @click="onConfirm">
{{ confirmTitle }} {{ confirmTitle }}
</el-button> </el-button>
</slot> </slot>
@@ -44,7 +44,7 @@ export default {
confirmTitle: { confirmTitle: {
type: String, type: String,
default() { default() {
return this.$t('common.Confirm') return this.$t('Confirm')
} }
}, },
showCancel: { showCancel: {
@@ -54,7 +54,7 @@ export default {
cancelTitle: { cancelTitle: {
type: String, type: String,
default() { default() {
return this.$t('common.Cancel') return this.$t('Cancel')
} }
}, },
showButtons: { showButtons: {
@@ -94,6 +94,18 @@ export default {
border-radius: 0.3em; border-radius: 0.3em;
max-width: 1500px; max-width: 1500px;
.form-group-header {
margin-left: 20px;
}
//.el-form-item__label {
// width: 30% !important;
//}
//
//.el-form-item__content {
// margin-left: 30% !important;
//}
.el-icon-circle-check { .el-icon-circle-check {
display: none; display: none;
} }
@@ -122,6 +134,6 @@ export default {
.dialog-footer >>> button.el-button { .dialog-footer >>> button.el-button {
font-size: 13px; font-size: 13px;
padding: 10px 20px; padding: 8px 12px;
} }
</style> </style>

View File

@@ -0,0 +1,31 @@
<!-- DrawerComponent.vue -->
<template>
<el-drawer
:modal="false"
:visible.sync="drawerVisible"
append-to-body
size="600px"
title="Create Resource"
@close="closeDrawer"
>
<router-view /> <!-- 这里展示创建页面的路由组件 -->
</el-drawer>
</template>
<script>
export default {
data() {
return {
drawerVisible: true
}
},
methods: {
openDrawer() {
this.drawerVisible = true
},
closeDrawer() {
this.drawerVisible = false
}
}
}
</script>

View File

@@ -4,7 +4,7 @@
:disabled="disabled" :disabled="disabled"
:fields="iFields" :fields="iFields"
:form="value" :form="value"
style="margin-left: -26%;margin-right: -6%" class="sub-form"
v-bind="kwargs" v-bind="kwargs"
@change="updateValue($event)" @change="updateValue($event)"
@input="updateValue($event)" @input="updateValue($event)"
@@ -106,5 +106,9 @@ export default {
</script> </script>
<style scoped> <style scoped>
.sub-form {
margin-left: -33%;
margin-right: 10px;
}
</style> </style>

View File

@@ -5,9 +5,10 @@ import Switcher from '@/components/Form/FormFields/Switcher.vue'
import rules from '@/components/Form/DataForm/rules' import rules from '@/components/Form/DataForm/rules'
import BasicTree from '@/components/Form/FormFields/BasicTree.vue' import BasicTree from '@/components/Form/FormFields/BasicTree.vue'
import JsonEditor from '@/components/Form/FormFields/JsonEditor.vue' import JsonEditor from '@/components/Form/FormFields/JsonEditor.vue'
import { assignIfNot } from '@/utils/common' import { assignIfNot, toSentenceCase } from '@/utils/common'
import TagInput from '@/components/Form/FormFields/TagInput.vue' import TagInput from '@/components/Form/FormFields/TagInput.vue'
import TransferSelect from '@/components/Form/FormFields/TransferSelect.vue' import TransferSelect from '@/components/Form/FormFields/TransferSelect.vue'
import i18n from '@/i18n/i18n'
export class FormFieldGenerator { export class FormFieldGenerator {
constructor(emit) { constructor(emit) {
@@ -103,6 +104,7 @@ export class FormFieldGenerator {
field.el.filterable = true field.el.filterable = true
} }
} }
field.type = type field.type = type
return field return field
} }
@@ -158,12 +160,24 @@ export class FormFieldGenerator {
return field return field
} }
afterGenerateField(field) {
field.label = toSentenceCase(field.label)
if (field.helpText) {
field.helpText = toSentenceCase(field.helpText)
}
if ((!field.helpTip && field.helpText && field.helpTextAsTip) || field.component === Switcher) {
field.helpTip = field.helpText
field.helpText = ''
}
return field
}
generateField(name, fieldsMeta, remoteFieldsMeta) { generateField(name, fieldsMeta, remoteFieldsMeta) {
let field = { id: name, prop: name, el: {}, attrs: {}, rules: [] } let field = { id: name, prop: name, el: {}, attrs: {}, rules: [] }
const remoteFieldMeta = remoteFieldsMeta[name] || {} const remoteFieldMeta = remoteFieldsMeta[name] || {}
const fieldMeta = fieldsMeta[name] || {} const fieldMeta = fieldsMeta[name] || {}
field.label = remoteFieldMeta.label field.label = remoteFieldMeta.label
field.helpText = remoteFieldMeta['help_text'] field.helpText = toSentenceCase(remoteFieldMeta['help_text'])
field = this.generateFieldByType(remoteFieldMeta.type, field, fieldMeta, remoteFieldMeta) field = this.generateFieldByType(remoteFieldMeta.type, field, fieldMeta, remoteFieldMeta)
field = this.generateFieldByName(name, field) field = this.generateFieldByName(name, field)
field = this.generateFieldByOther(field, fieldMeta, remoteFieldMeta) field = this.generateFieldByOther(field, fieldMeta, remoteFieldMeta)
@@ -172,8 +186,23 @@ export class FormFieldGenerator {
field = Object.assign(field, fieldMeta) field = Object.assign(field, fieldMeta)
field.el = el field.el = el
field.rules = rules field.rules = rules
field = this.setPlaceholder(field, remoteFieldMeta)
field = this.afterGenerateField(field)
_.set(field, 'attrs.error', '') _.set(field, 'attrs.error', '')
// Vue.$log.debug('Generate field: ', name, field) Vue.$log.debug('Generate field: ', name, field)
return field
}
setPlaceholder(field, remoteFieldMeta) {
const label = field.label
if (!label) {
return field
}
if (field.type === 'select' || [ObjectSelect2].indexOf(field.component) > -1) {
field.el.placeholder = i18n.t('Please select ') + label.toLowerCase()
} else if (field.type === 'input') {
field.el.placeholder = field.label
}
return field return field
} }

View File

@@ -2,7 +2,7 @@
<template> <template>
<div> <div>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane v-if="shouldHide('min')" :label="$tc('common.CronTab.min')" class="crontab-panel"> <el-tab-pane v-if="shouldHide('min')" :label="$tc('Min')" class="crontab-panel">
<CrontabMin <CrontabMin
ref="cronmin" ref="cronmin"
:check="checkNumber" :check="checkNumber"
@@ -11,7 +11,7 @@
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="shouldHide('hour')" :label="$tc('common.CronTab.hour')"> <el-tab-pane v-if="shouldHide('hour')" :label="$tc('Hour')">
<CrontabHour <CrontabHour
ref="cronhour" ref="cronhour"
:check="checkNumber" :check="checkNumber"
@@ -20,7 +20,7 @@
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="shouldHide('day')" :label="$tc('common.CronTab.day')"> <el-tab-pane v-if="shouldHide('day')" :label="$tc('Day')">
<CrontabDay <CrontabDay
ref="cronday" ref="cronday"
:check="checkNumber" :check="checkNumber"
@@ -29,7 +29,7 @@
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="shouldHide('month')" :label="$tc('common.CronTab.month')"> <el-tab-pane v-if="shouldHide('month')" :label="$tc('Month')">
<CrontabMonth <CrontabMonth
ref="cronmonth" ref="cronmonth"
:check="checkNumber" :check="checkNumber"
@@ -38,7 +38,7 @@
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="shouldHide('week')" :label="$tc('common.CronTab.week')"> <el-tab-pane v-if="shouldHide('week')" :label="$tc('Week')">
<CrontabWeek <CrontabWeek
ref="cronweek" ref="cronweek"
:check="checkNumber" :check="checkNumber"
@@ -50,7 +50,7 @@
<div class="popup-main"> <div class="popup-main">
<div class="popup-result"> <div class="popup-result">
<p class="title">{{ this.$t('common.CronTab.timeExpression') }}</p> <p class="title">{{ this.$t('TimeExpression') }}</p>
<table> <table>
<thead> <thead>
<th v-for="item of tabTitles" :key="item" width="40">{{ item }}</th> <th v-for="item of tabTitles" :key="item" width="40">{{ item }}</th>
@@ -95,26 +95,22 @@
</td> </td>
</tbody> </tbody>
</table> </table>
<div style="margin: 0 auto; text-align: center"> <CrontabResult :ex="contabValueString" @crontabDiffChange="crontabDiffChangeHandle" />
<div style="font-size: 13px;">{{ this.$t('common.CronTab.cronExpression') }}</div>
<div style="font-size: 13px;">{{ contabValueString }}</div>
</div>
</div> </div>
<CrontabResult :ex="contabValueString" @crontabDiffChange="crontabDiffChangeHandle" />
<div class="pop_btn"> <div class="pop_btn">
<el-button <el-button
size="small" size="small"
@click="clearCron" @click="clearCron"
> >
{{ this.$t('common.Reset') }} {{ this.$t('Reset') }}
</el-button> </el-button>
<el-button <el-button
size="small" size="small"
type="primary" type="primary"
@click="submitFill" @click="submitFill"
> >
{{ this.$t('common.Confirm') }} {{ this.$t('Confirm') }}
</el-button> </el-button>
</div> </div>
</div> </div>
@@ -155,7 +151,7 @@ export default {
}, },
data() { data() {
return { return {
tabTitles: [this.$t('common.CronTab.min'), this.$t('common.CronTab.hour'), this.$t('common.CronTab.day'), this.$t('common.CronTab.month'), this.$t('common.CronTab.week')], tabTitles: [this.$t('Min'), this.$t('Hour'), this.$t('Day'), this.$t('Month'), this.$t('Week')],
tabActive: 0, tabActive: 0,
myindex: 0, myindex: 0,
contabValueObj: { contabValueObj: {
@@ -367,7 +363,7 @@ export default {
submitFill() { submitFill() {
const crontabDiffMin = this.crontabDiff / 1000 / 60 const crontabDiffMin = this.crontabDiff / 1000 / 60
if (crontabDiffMin > 0 && crontabDiffMin < 10) { if (crontabDiffMin > 0 && crontabDiffMin < 10) {
const msg = this.$tc('common.crontabDiffError') const msg = this.$tc('CrontabDiffError')
this.$message.error(msg) this.$message.error(msg)
return return
} }
@@ -398,7 +394,7 @@ export default {
<style lang='scss' scoped> <style lang='scss' scoped>
.pop_btn { .pop_btn {
float: right; float: right;
margin-top: 20px; margin-top: 10px;
} }
.popup-main { .popup-main {
@@ -424,7 +420,6 @@ export default {
margin: 17px auto; margin: 17px auto;
padding: 10px 10px 10px; padding: 10px 10px 10px;
border: 1px solid #dcdfe6; border: 1px solid #dcdfe6;
box-shadow: 0 2px 4px 0 rgb(0 0 0 / 12%), 0 0 6px 0 rgb(0 0 0 / 4%);
} }
.popup-result .title { .popup-result .title {
@@ -448,12 +443,10 @@ export default {
.popup-result table span { .popup-result table span {
display: block; display: block;
width: 100%; width: 100%;
font-family: arial;
line-height: 30px; line-height: 30px;
height: 30px; height: 30px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
border: 1px solid #e8e8e8;
} }
.popup-result-scroll { .popup-result-scroll {
@@ -463,14 +456,14 @@ export default {
overflow-y: auto; overflow-y: auto;
} }
.crontab-panel { >>> {
> > > .el-input-number { .el-form-item--mini.el-form-item,
.el-form-item--small.el-form-item {
margin-bottom: 5px;
}
.el-input-number {
margin: 0 5px margin: 0 5px
} }
} }
.el-form-item--mini.el-form-item,
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
</style> </style>

View File

@@ -3,31 +3,31 @@
<el-form size="small"> <el-form size="small">
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="1"> <el-radio v-model="radioValue" :label="1">
{{ this.$t('common.CronTab.day') }}{{ this.$t('common.CronTab.wildcardsAllowed') }}[, - * /] {{ this.$t('Day') }}{{ this.$t('WildcardsAllowed') }}[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="3"> <el-radio v-model="radioValue" :label="3">
{{ this.$t('common.CronTab.from') }} {{ this.$t('From') }}
<el-input-number v-model="cycle01" :max="31" :min="0" size="mini" /> - <el-input-number v-model="cycle01" :max="31" :min="0" size="mini" /> -
<el-input-number v-model="cycle02" :max="31" :min="0" size="mini" /> {{ this.$t('common.CronTab.day') }} <el-input-number v-model="cycle02" :max="31" :min="0" size="mini" /> {{ this.$t('Day') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="4"> <el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.every') }} {{ this.$t('Every') }}
<el-input-number v-model="average02" :max="31" :min="1" size="mini" /> {{ this.$t('common.CronTab.day') }}{{ this.$t('common.CronTab.executeOnce') }} <el-input-number v-model="average02" :max="31" :min="1" size="mini" /> {{ this.$t('Day') }} {{ this.$t('ExecuteOnce') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="7"> <el-radio v-model="radioValue" :label="7">
{{ this.$t('common.CronTab.appoint') }} {{ this.$t('Appoint') }}
<el-select <el-select
v-model="checkboxList" v-model="checkboxList"
:placeholder="$tc('common.CronTab.manyChoose')" :placeholder="$tc('ManyChoose')"
clearable clearable
multiple multiple
style="width:100%" style="width:100%"
@@ -190,7 +190,5 @@ export default {
</script> </script>
<style scoped> <style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
</style> </style>

View File

@@ -3,31 +3,31 @@
<el-form size="small"> <el-form size="small">
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="1"> <el-radio v-model="radioValue" :label="1">
{{ this.$t('common.CronTab.hour') }}{{ this.$t('common.CronTab.wildcardsAllowed') }}[, - * /] {{ this.$t('Hour') }}{{ this.$t('WildcardsAllowed') }}[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="2"> <el-radio v-model="radioValue" :label="2">
{{ this.$t('common.CronTab.from') }} {{ this.$t('From') }}
<el-input-number v-model="cycle01" :max="60" :min="0" size="mini" /> - <el-input-number v-model="cycle01" :max="60" :min="0" size="mini" /> -
<el-input-number v-model="cycle02" :max="60" :min="0" size="mini" /> {{ this.$t('common.CronTab.hour') }} <el-input-number v-model="cycle02" :max="60" :min="0" size="mini" /> {{ this.$t('Hour') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="3"> <el-radio v-model="radioValue" :label="3">
{{ this.$t('common.CronTab.every') }} {{ this.$t('Every') }}
<el-input-number v-model="average02" :max="60" :min="1" size="mini" /> {{ this.$t('common.CronTab.hour') }}{{ this.$t('common.CronTab.executeOnce') }} <el-input-number v-model="average02" :max="60" :min="1" size="mini" /> {{ this.$t('Hour') }} {{ this.$t('ExecuteOnce') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="4"> <el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.appoint') }} {{ this.$t('Appoint') }}
<el-select <el-select
v-model="checkboxList" v-model="checkboxList"
:placeholder="$tc('common.CronTab.manyChoose')" :placeholder="$tc('ManyChoose')"
clearable clearable
multiple multiple
style="width:100%" style="width:100%"
@@ -159,7 +159,5 @@ export default {
</script> </script>
<style scoped> <style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px
}
</style> </style>

View File

@@ -3,31 +3,31 @@
<el-form size="small"> <el-form size="small">
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="1" size="mini"> <el-radio v-model="radioValue" :label="1" size="mini">
{{ this.$t('common.CronTab.min') }}{{ this.$t('common.CronTab.wildcardsAllowed') }}[, - * /] {{ this.$t('Minute') }}{{ this.$t('WildcardsAllowed') }}[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="2"> <el-radio v-model="radioValue" :label="2">
{{ this.$t('common.CronTab.from') }} {{ this.$t('From') }}
<el-input-number v-model="cycle01" :max="60" :min="0" size="mini" /> - <el-input-number v-model="cycle01" :max="60" :min="0" size="mini" /> -
<el-input-number v-model="cycle02" :max="60" :min="0" size="mini" /> {{ this.$t('common.CronTab.min') }} <el-input-number v-model="cycle02" :max="60" :min="0" size="mini" /> {{ this.$t('Minute') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="3"> <el-radio v-model="radioValue" :label="3">
{{ this.$t('common.CronTab.from') }} {{ this.$t('From') }}
<el-input-number v-model="average02" :max="60" :min="1" size="mini" /> {{ this.$t('common.CronTab.min') }}{{ this.$t('common.CronTab.executeOnce') }} <el-input-number v-model="average02" :max="60" :min="1" size="mini" /> {{ this.$t('Minute') }} {{ this.$t('ExecuteOnce') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="4"> <el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.appoint') }} {{ this.$t('Appoint') }}
<el-select <el-select
v-model="checkboxList" v-model="checkboxList"
:placeholder="$tc('common.CronTab.manyChoose')" :placeholder="$tc('ManyChoose')"
clearable clearable
multiple multiple
size="small" size="small"
@@ -158,7 +158,5 @@ export default {
</script> </script>
<style scoped> <style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
</style> </style>

View File

@@ -3,31 +3,31 @@
<el-form size="small"> <el-form size="small">
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="1"> <el-radio v-model="radioValue" :label="1">
{{ this.$t('common.CronTab.month') }}{{ this.$t('common.CronTab.wildcardsAllowed') }}[, - * /] {{ this.$t('Month') }}{{ this.$t('WildcardsAllowed') }}[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="2"> <el-radio v-model="radioValue" :label="2">
{{ this.$t('common.CronTab.from') }} {{ this.$t('From') }}
<el-input-number v-model="cycle01" :max="12" :min="1" size="mini" /> - <el-input-number v-model="cycle01" :max="12" :min="1" size="mini" /> -
<el-input-number v-model="cycle02" :max="12" :min="1" size="mini" /> {{ this.$t('common.CronTab.month') }} <el-input-number v-model="cycle02" :max="12" :min="1" size="mini" /> {{ this.$t('Month') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="3"> <el-radio v-model="radioValue" :label="3">
{{ this.$t('common.CronTab.every') }} {{ this.$t('Every') }}
<el-input-number v-model="average02" :max="12" :min="1" size="mini" /> {{ this.$t('common.CronTab.month') }}{{ this.$t('common.CronTab.executeOnce') }} <el-input-number v-model="average02" :max="12" :min="1" size="mini" /> {{ this.$t('Month') }} {{ this.$t('ExecuteOnce') }}
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="4"> <el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.appoint') }} {{ this.$t('Appoint') }}
<el-select <el-select
v-model="checkboxList" v-model="checkboxList"
:placeholder="$tc('common.CronTab.manyChoose')" :placeholder="$tc('ManyChoose')"
clearable clearable
multiple multiple
style="width:100%" style="width:100%"
@@ -164,7 +164,5 @@ export default {
</script> </script>
<style scoped> <style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
</style> </style>

View File

@@ -1,12 +1,12 @@
/* eslint-disable */ /* eslint-disable */
<template> <template>
<div class="popup-result"> <div class="popup-result-time">
<p class="title">{{ this.$t('common.CronTab.runningTimes') }}</p> <p class="title">{{ this.$t('RunningTimes') }}</p>
<ul class="popup-result-scroll"> <ul class="popup-result-scroll">
<template v-if="isShow"> <template v-if="isShow">
<li v-for="item in resultList" :key="item">{{ item }}</li> <li v-for="item in resultList" :key="item">{{ item }}</li>
</template> </template>
<li v-else>{{ this.$t('common.CronTab.calculationResults') }}</li> <li v-else>{{ this.$t('CalculationResults') }}</li>
</ul> </ul>
</div> </div>
</template> </template>
@@ -65,3 +65,12 @@ export default {
} }
</script> </script>
<style lang='scss' scoped>
.popup-result-time {
margin-top: 10px;
}
.title {
margin-bottom: 0;
}
</style>

View File

@@ -3,13 +3,13 @@
<el-form size="small"> <el-form size="small">
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="1"> <el-radio v-model="radioValue" :label="1">
{{ this.$t('common.CronTab.week') }}{{ this.$t('common.CronTab.wildcardsAllowed') }}[, - * /] {{ this.$t('Week') }}{{ this.$t('WildcardsAllowed') }}[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="3"> <el-radio v-model="radioValue" :label="3">
{{ this.$t('common.CronTab.cycleFromWeek') }} {{ this.$t('CycleFromWeek') }}
<el-input-number v-model="cycle01" :max="7" :min="1" size="mini" /> - <el-input-number v-model="cycle01" :max="7" :min="1" size="mini" /> -
<el-input-number v-model="cycle02" :max="7" :min="1" size="mini" /> <el-input-number v-model="cycle02" :max="7" :min="1" size="mini" />
</el-radio> </el-radio>
@@ -17,10 +17,10 @@
<el-form-item> <el-form-item>
<el-radio v-model="radioValue" :label="6"> <el-radio v-model="radioValue" :label="6">
{{ this.$t('common.CronTab.appoint') }} {{ this.$t('Appoint') }}
<el-select <el-select
v-model="checkboxList" v-model="checkboxList"
:placeholder="$tc('common.CronTab.manyChoose')" :placeholder="$tc('ManyChoose')"
clearable clearable
multiple multiple
style="width:100%" style="width:100%"
@@ -60,7 +60,7 @@ export default {
average01: 1, average01: 1,
average02: 1, average02: 1,
checkboxList: [], checkboxList: [],
weekList: [this.$t('common.CronTab.Monday'), this.$t('common.CronTab.Tuesday'), this.$t('common.CronTab.Wednesday'), this.$t('common.CronTab.Thursday'), this.$t('common.CronTab.Friday'), this.$t('common.CronTab.Saturday'), this.$t('common.CronTab.Sunday')], weekList: [this.$t('Monday'), this.$t('Tuesday'), this.$t('Wednesday'), this.$t('Thursday'), this.$t('Friday'), this.$t('Saturday'), this.$t('Sunday')],
checkNum: this.$options.propsData.check checkNum: this.$options.propsData.check
} }
}, },
@@ -181,7 +181,5 @@ export default {
</script> </script>
<style scoped> <style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
</style> </style>

View File

@@ -3,8 +3,9 @@
<div class="box"> <div class="box">
<el-input v-model="input" clearable @clear="onClear" @focus="showDialog" /> <el-input v-model="input" clearable @clear="onClear" @focus="showDialog" />
</div> </div>
<el-dialog <Dialog
:title="$tc('common.CronTab.newCron')" :show-buttons="false"
:title="$tc('NewCron')"
:visible.sync="showCron" :visible.sync="showCron"
append-to-body append-to-body
top="8vh" top="8vh"
@@ -15,15 +16,16 @@
@fill="crontabFill" @fill="crontabFill"
@hide="showCron = false" @hide="showCron = false"
/> />
</el-dialog> </Dialog>
</div> </div>
</template> </template>
<script> <script>
import Crontab from './Crontab.vue' import Crontab from './Crontab.vue'
import Dialog from '@/components/Dialog/index.vue'
export default { export default {
components: { Crontab }, components: { Crontab, Dialog },
props: { props: {
value: { value: {
type: String, type: String,
@@ -55,8 +57,9 @@ export default {
} }
</script> </script>
<style scoped> <style lang='scss' scoped>
.el-dialog__body { .el-dialog__body {
padding: 12px 16px; padding: 12px 16px;
} }
</style> </style>

View File

@@ -1,17 +1,18 @@
<template> <template>
<el-form-item <el-form-item
v-show="_show" v-if="_show"
:prop="prop" :class="classes"
:label="data.label" :label="data.label"
:prop="prop"
:rules="_show && Array.isArray(data.rules) ? data.rules : []" :rules="_show && Array.isArray(data.rules) ? data.rules : []"
v-bind="data.attrs" v-bind="data.attrs"
> >
<template v-if="data.helpTips" #label> <template v-if="data.label" #label>
{{ data.label }} <el-tooltip v-if="data.helpTip" effect="light" placement="top" popper-class="help-tips">
<el-tooltip placement="top" effect="light" popper-class="help-tips"> <div slot="content" v-html="data.helpTip" />
<div slot="content" v-html="data.helpTips" /> <i class="el-icon-warning-outline help-tip-icon" />
<i class="fa fa-question-circle-o" />
</el-tooltip> </el-tooltip>
<span>{{ data.label }}</span>
</template> </template>
<template v-if="readonly && hasReadonlyContent"> <template v-if="readonly && hasReadonlyContent">
<div <div
@@ -33,9 +34,9 @@
<custom-component <custom-component
v-else v-else
:component="data.component || `el-${data.type}`" :component="data.component || `el-${data.type}`"
v-bind="componentProps"
:value="itemValue"
:disabled="disabled || componentProps.disabled || readonly" :disabled="disabled || componentProps.disabled || readonly"
:value="itemValue"
v-bind="componentProps"
v-on="listeners" v-on="listeners"
> >
<template v-for="opt in options"> <template v-for="opt in options">
@@ -47,8 +48,8 @@
<el-checkbox-button <el-checkbox-button
v-else-if="data.type === 'checkbox-group' && data.style === 'button'" v-else-if="data.type === 'checkbox-group' && data.style === 'button'"
:key="opt.value" :key="opt.value"
v-bind="opt"
:label="'value' in opt ? opt.value : opt.label" :label="'value' in opt ? opt.value : opt.label"
v-bind="opt"
> >
{{ opt.label }} {{ opt.label }}
</el-checkbox-button> </el-checkbox-button>
@@ -56,8 +57,8 @@
<el-checkbox <el-checkbox
v-else-if="data.type === 'checkbox-group' && data.style !== 'button'" v-else-if="data.type === 'checkbox-group' && data.style !== 'button'"
:key="opt.value" :key="opt.value"
v-bind="opt"
:label="'value' in opt ? opt.value : opt.label" :label="'value' in opt ? opt.value : opt.label"
v-bind="opt"
> >
{{ opt.label }} {{ opt.label }}
</el-checkbox> </el-checkbox>
@@ -66,8 +67,8 @@
<el-radio <el-radio
v-else-if="data.type === 'radio-group'" v-else-if="data.type === 'radio-group'"
:key="opt.label" :key="opt.label"
v-bind="opt"
:label="'value' in opt ? opt.value : opt.label" :label="'value' in opt ? opt.value : opt.label"
v-bind="opt"
>{{ opt.label }} >{{ opt.label }}
</el-radio> </el-radio>
</template> </template>
@@ -125,8 +126,7 @@ export default {
data() { data() {
return { return {
propsInner: {}, propsInner: {},
isBlurTrigger: isBlurTrigger: this.data.rules &&
this.data.rules &&
this.data.rules.some(rule => { this.data.rules.some(rule => {
return rule.required && rule.trigger === 'blur' return rule.required && rule.trigger === 'blur'
}) })
@@ -145,6 +145,9 @@ export default {
_show() { _show() {
return !this.hiddenStatus && this.enableWhenStatus return !this.hiddenStatus && this.enableWhenStatus
}, },
classes() {
return 'el-form-item-' + this.data.prop + ' ' + (this.data.attrs?.class || '')
},
listeners() { listeners() {
const { const {
data: { data: {
@@ -279,3 +282,10 @@ export default {
} }
} }
</script> </script>
<style lang='scss'>
.help-tip-icon {
&:hover {
cursor: pointer;
}
}
</style>

View File

@@ -1,16 +1,16 @@
<template> <template>
<el-form ref="elForm" v-bind="$attrs" :model="value" class="el-form-renderer"> <el-form ref="elForm" :model="value" class="el-form-renderer" v-bind="$attrs">
<template v-for="item in innerContent"> <template v-for="item in innerContent">
<slot v-if="!isHidden(item)" :name="`id:${item.id}`" /> <slot v-if="!isHidden(item)" :name="`id:${item.id}`" />
<component <component
:is="item.type === GROUP ? 'render-form-group' : 'render-form-item'" :is="item.type === GROUP ? 'render-form-group' : 'render-form-item'"
:key="item.id" :key="item.id"
:data="item" :data="item"
:value="value"
:item-value="value[item.id]"
:disabled="disabled || item.disabled" :disabled="disabled || item.disabled"
:readonly="readonly || item.readonly" :item-value="value[item.id]"
:options="options[item.id]" :options="options[item.id]"
:readonly="readonly || item.readonly"
:value="value"
@updateValue="updateValue" @updateValue="updateValue"
/> />
<slot v-if="!isHidden(item)" :name="`$id:${item.id}`" /> <slot v-if="!isHidden(item)" :name="`$id:${item.id}`" />
@@ -25,13 +25,7 @@ import _clonedeep from 'lodash.clonedeep'
import RenderFormGroup from './components/render-form-group.vue' import RenderFormGroup from './components/render-form-group.vue'
import RenderFormItem from './components/render-form-item.vue' import RenderFormItem from './components/render-form-item.vue'
import transformContent from './util/transform-content' import transformContent from './util/transform-content'
import { import { collect, correctValue, mergeValue, transformInputValue, transformOutputValue } from './util/utils'
collect,
mergeValue,
transformOutputValue,
transformInputValue,
correctValue
} from './util/utils'
const GROUP = 'group' const GROUP = 'group'

View File

@@ -5,7 +5,7 @@
:content="fields" :content="fields"
:form="basicForm" :form="basicForm"
:label-position="labelPosition" :label-position="labelPosition"
label-width="20%" label-width="25%"
v-bind="$attrs" v-bind="$attrs"
v-on="$listeners" v-on="$listeners"
> >
@@ -25,14 +25,14 @@
{{ button.title }} {{ button.title }}
</el-button> </el-button>
<el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')"> <el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')">
{{ $t('common.Reset') }} {{ $t('Reset') }}
</el-button> </el-button>
<el-button <el-button
v-if="defaultButton && hasSaveContinue" v-if="defaultButton && hasSaveContinue"
size="small" size="small"
@click="submitForm('form', true)" @click="submitForm('form', true)"
> >
{{ $t('common.SaveAndAddAnother') }} {{ $t('SaveAndAddAnother') }}
</el-button> </el-button>
<el-button <el-button
v-if="defaultButton" v-if="defaultButton"
@@ -80,7 +80,7 @@ export default {
submitBtnText: { submitBtnText: {
type: String, type: String,
default() { default() {
return this.$t('common.Submit') return this.$t('Submit')
} }
}, },
hasSaveContinue: { hasSaveContinue: {
@@ -155,12 +155,16 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.el-form {
margin-right: 80px;
}
.el-form ::v-deep .el-form-item { .el-form ::v-deep .el-form-item {
margin-bottom: 12px; margin-bottom: 10px;
} }
.el-form ::v-deep .el-form-item__content { .el-form ::v-deep .el-form-item__content {
width: 75%; width: 75%;
line-height: 32px;
} }
.mobile.el-form ::v-deep .el-form-item__content { .mobile.el-form ::v-deep .el-form-item__content {
@@ -169,6 +173,7 @@ export default {
.el-form ::v-deep .el-form-item__label { .el-form ::v-deep .el-form-item__label {
padding: 0 30px 0 0; padding: 0 30px 0 0;
line-height: 32px;
} }
.el-form ::v-deep .el-form-item__error { .el-form ::v-deep .el-form-item__error {
@@ -183,15 +188,6 @@ export default {
margin-left: 0; margin-left: 0;
} }
.el-form ::v-deep .help-block {
display: block;
margin-top: 5px;
margin-bottom: 10px;
color: #999;
font-size: 12px;
line-height: 18px;
}
.el-form ::v-deep .help-block a { .el-form ::v-deep .help-block a {
color: var(--color-primary); color: var(--color-primary);
} }

View File

@@ -1,16 +1,16 @@
import i18n from '@/i18n/i18n' import i18n from '@/i18n/i18n'
export const Required = { export const Required = {
required: true, message: i18n.t('common.fieldRequiredError'), trigger: 'blur' required: true, message: i18n.t('FieldRequiredError'), trigger: 'blur'
} }
export const RequiredChange = { export const RequiredChange = {
required: true, message: i18n.t('common.fieldRequiredError'), trigger: 'change' required: true, message: i18n.t('FieldRequiredError'), trigger: 'change'
} }
export const EmailCheck = { export const EmailCheck = {
type: 'email', type: 'email',
message: i18n.t('common.InputEmailAddress'), message: i18n.t('InputEmailAddress'),
trigger: ['blur', 'change'] trigger: ['blur', 'change']
} }
@@ -22,7 +22,7 @@ export const IpCheck = {
if (urlRegExp.test(value)) { if (urlRegExp.test(value)) {
callback() callback()
} else { } else {
callback(new Error(i18n.t('common.FormatError'))) callback(new Error(i18n.t('FormatError')))
} }
}, },
trigger: ['blur', 'change'] trigger: ['blur', 'change']
@@ -32,7 +32,7 @@ export const specialEmojiCheck = {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
value = value?.trim() value = value?.trim()
if (/[\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/.test(value)) { if (/[\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/.test(value)) {
callback(new Error(i18n.t('common.NotSpecialEmoji'))) callback(new Error(i18n.t('NotSpecialEmoji')))
} else { } else {
callback() callback()
} }
@@ -45,7 +45,7 @@ export const matchAlphanumericUnderscore = {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
value = value?.trim() value = value?.trim()
if (!/^[a-zA-Z0-9_]+$/.test(value)) { if (!/^[a-zA-Z0-9_]+$/.test(value)) {
callback(new Error(i18n.t('common.notAlphanumericUnderscore'))) callback(new Error(i18n.t('notAlphanumericUnderscore')))
} else { } else {
callback() callback()
} }
@@ -58,7 +58,7 @@ export const MatchExcludeParenthesis = {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
value = value?.trim() value = value?.trim()
if (!/^[^()]*$/.test(value)) { if (!/^[^()]*$/.test(value)) {
callback(new Error(i18n.t('common.notParenthesis'))) callback(new Error(i18n.t('notParenthesis')))
} else { } else {
callback() callback()
} }
@@ -84,7 +84,7 @@ export const JsonRequired = {
typeof value === 'string' ? JSON.parse(value) : value typeof value === 'string' ? JSON.parse(value) : value
callback() callback()
} catch (e) { } catch (e) {
callback(new Error(i18n.t('common.InvalidJson'))) callback(new Error(i18n.t('InvalidJson')))
} }
} }
} }
@@ -97,11 +97,11 @@ export const JsonRequiredUserNameMapped = {
const v = typeof value === 'string' ? JSON.parse(value) : value const v = typeof value === 'string' ? JSON.parse(value) : value
const hasUserName = _.map(v, (value) => value) const hasUserName = _.map(v, (value) => value)
if (!hasUserName.includes('username')) { if (!hasUserName.includes('username')) {
callback(new Error(i18n.t('common.requiredHasUserNameMapped'))) callback(new Error(i18n.t('requiredHasUserNameMapped')))
} }
callback() callback()
} catch (e) { } catch (e) {
callback(new Error(i18n.t('common.InvalidJson'))) callback(new Error(i18n.t('InvalidJson')))
} }
} }
} }

View File

@@ -33,8 +33,8 @@ export default {
return { return {
type: 'all', // all, selected type: 'all', // all, selected
types: [ types: [
{ name: 'all', label: this.$t('common.All') }, { name: 'all', label: this.$t('All') },
{ name: 'spec', label: this.$t('common.Spec') + this.$t('common.WordSep') + this.resource } { name: 'spec', label: this.$t('Spec') + this.$t('WordSep') + this.resource }
], ],
selected: [] selected: []
} }

View File

@@ -14,13 +14,13 @@ export default {
trueText: { trueText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('common.Yes') return this.$t('Yes')
} }
}, },
falseText: { falseText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('common.No') return this.$t('No')
} }
} }

View File

@@ -19,12 +19,12 @@
<el-autocomplete <el-autocomplete
v-if="item.type === 'input' &&item.el && item.el.autoComplete" v-if="item.type === 'input' &&item.el && item.el.autoComplete"
v-model="item.value" v-model="item.value"
:placeholder="item.placeholder"
:fetch-suggestions="item.el.query" :fetch-suggestions="item.el.query"
:placeholder="item.placeholder"
class="inline-input" class="inline-input"
size="mini" size="mini"
@select="item.callback(item.value)"
@change="item.callback(item.value)" @change="item.callback(item.value)"
@select="item.callback(item.value)"
/> />
<el-input <el-input
v-else-if="item.type==='input'" v-else-if="item.type==='input'"
@@ -94,10 +94,10 @@
</div> </div>
<div v-if="toolbar.hasOwnProperty('fold')" class="fold"> <div v-if="toolbar.hasOwnProperty('fold')" class="fold">
<el-tooltip :content="$tc('common.MoreActions')" placement="top"> <el-tooltip :content="$tc('MoreActions')" placement="top">
<i <i
class="fa"
:class="[isFold ? 'fa-angle-double-right': 'fa-angle-double-down']" :class="[isFold ? 'fa-angle-double-right': 'fa-angle-double-down']"
class="fa"
@click="onChangeFold" @click="onChangeFold"
/> />
</el-tooltip> </el-tooltip>
@@ -238,15 +238,15 @@ export default {
} }
} }
> > > .CodeMirror pre.CodeMirror-line, >>> .CodeMirror pre.CodeMirror-line,
> > > .CodeMirror-linenumber.CodeMirror-gutter-elt { >>> .CodeMirror-linenumber.CodeMirror-gutter-elt {
line-height: 18px !important; line-height: 18px !important;
} }
.runas-input { .runas-input {
height: 28px; height: 28px;
> > > { >>> {
.el-select { .el-select {
width: 100px; width: 100px;
} }
@@ -258,8 +258,8 @@ export default {
border: none; border: none;
padding: 2px; padding: 2px;
font-size: 14px; font-size: 14px;
width: 26px; width: 28px;
height: 26px; height: 28px;
color: #888; color: #888;
background-color: transparent; background-color: transparent;
margin-left: 2px; margin-left: 2px;
@@ -270,16 +270,16 @@ export default {
min-width: 100px; min-width: 100px;
} }
.autoWidth-select > > > .el-input__prefix { .autoWidth-select >>> .el-input__prefix {
position: relative; position: relative;
left: 0px; left: 0;
box-sizing: border-box; box-sizing: border-box;
height: 28px; height: 30px;
line-height: 28px; line-height: 30px;
visibility: hidden; visibility: hidden;
} }
.autoWidth-select > > > input { .autoWidth-select >>> input {
position: absolute; position: absolute;
padding-left: 0px; padding-left: 0px;
border: none; border: none;
@@ -290,7 +290,7 @@ export default {
line-height: 27px; line-height: 27px;
} }
> > > .el-select { >>> .el-select {
top: -1px; top: -1px;
.el-input .el-select__caret { .el-input .el-select__caret {
@@ -298,7 +298,7 @@ export default {
} }
} }
> > > .el-button.el-button--default { >>> .el-button.el-button--default {
background-color: #e6e6e6; background-color: #e6e6e6;
} }

View File

@@ -1,15 +1,15 @@
<template> <template>
<el-date-picker <el-date-picker
v-model="value" v-model="value"
type="datetimerange"
:range-separator="$tc('common.To')"
:start-placeholder="$tc('common.DateStart')"
:end-placeholder="$tc('common.DateEnd')"
size="small"
:clearable="false" :clearable="false"
class="datepicker"
:picker-options="pickerOptions"
:default-time="['00:00:01', '23:59:59']" :default-time="['00:00:01', '23:59:59']"
:end-placeholder="$tc('DateEnd')"
:picker-options="pickerOptions"
:range-separator="$tc('To')"
:start-placeholder="$tc('DateStart')"
class="datepicker"
size="small"
type="datetimerange"
v-bind="$attrs" v-bind="$attrs"
@change="handleDateChange" @change="handleDateChange"
v-on="$listeners" v-on="$listeners"
@@ -40,23 +40,23 @@ export default {
pickerOptions: { pickerOptions: {
shortcuts: [ shortcuts: [
{ {
text: this.$t('common.DateLast24Hours'), text: this.$t('DateLast24Hours'),
onClick: (picker) => this.onShortcutClick(picker, 1) onClick: (picker) => this.onShortcutClick(picker, 1)
}, },
{ {
text: this.$t('common.DateLastWeek'), text: this.$t('DateLastWeek'),
onClick: (picker) => this.onShortcutClick(picker, 7) onClick: (picker) => this.onShortcutClick(picker, 7)
}, { }, {
text: this.$t('common.DateLastMonth'), text: this.$t('DateLastMonth'),
onClick: (picker) => this.onShortcutClick(picker, 30) onClick: (picker) => this.onShortcutClick(picker, 30)
}, { }, {
text: this.$t('common.DateLast3Months'), text: this.$t('DateLast3Months'),
onClick: (picker) => this.onShortcutClick(picker, 90) onClick: (picker) => this.onShortcutClick(picker, 90)
}, { }, {
text: this.$t('common.DateLastHarfYear'), text: this.$t('DateLastHarfYear'),
onClick: (picker) => this.onShortcutClick(picker, 183) onClick: (picker) => this.onShortcutClick(picker, 183)
}, { }, {
text: this.$t('common.DateLastYear'), text: this.$t('DateLastYear'),
onClick: (picker) => this.onShortcutClick(picker, 365) onClick: (picker) => this.onShortcutClick(picker, 365)
} }
] ]
@@ -87,11 +87,6 @@ export default {
.datepicker { .datepicker {
width: 233px; width: 233px;
& >>> .el-range__icon {
margin-top: 2px;
margin-right: 3px;
}
& >>> .el-range-input { & >>> .el-range-input {
width: 49%; width: 49%;
} }

View File

@@ -0,0 +1,45 @@
<template>
<el-input v-bind="$attrs" v-on="$listeners">
<template slot="append">{{ iUnit }}</template>
</el-input>
</template>
<script>
export default {
name: 'InputWithUnit',
props: {
unit: {
type: String,
default: ''
}
},
data() {
return {
displayMapper: {
'second': this.$t('Second'), // 'sec' is the default value of 'unit
'min': this.$t('Minute'), // 'min' is the default value of 'unit
'hour': this.$t('Hour'), // 'hour' is the default value of 'unit
'day': this.$t('Day'), // 'day' is the default value of 'unit
'week': this.$t('Week'), // 'week' is the default value of 'unit
'month': this.$t('Month'), // 'month' is the default value of 'unit
'year': this.$t('Year') // 'year' is the default value of 'unit
}
}
},
computed: {
iUnit() {
console.log('Unit is:', this.unit)
return this.displayMapper[this.unit] || this.unit
}
}
}
</script>
<style scoped>
>>> .el-input-group__append {
color: inherit;
padding: 0 15px;
}
</style>

View File

@@ -2,7 +2,7 @@
<Dialog <Dialog
:destroy-on-close="true" :destroy-on-close="true"
:show-buttons="false" :show-buttons="false"
:title="$tc('common.SelectAttrs')" :title="$tc('SelectAttrs')"
v-bind="$attrs" v-bind="$attrs"
v-on="$listeners" v-on="$listeners"
> >
@@ -51,7 +51,7 @@ export default {
fields: [ fields: [
{ {
id: 'name', id: 'name',
label: this.$t('common.AttrName'), label: this.$t('AttrName'),
type: 'select', type: 'select',
options: this.attrs.map(attr => { options: this.attrs.map(attr => {
let disabled = this.attrsAdded.includes(attr.name) && this.form.name !== attr.name let disabled = this.attrsAdded.includes(attr.name) && this.form.name !== attr.name
@@ -74,7 +74,7 @@ export default {
}, },
{ {
id: 'match', id: 'match',
label: this.$t('common.Match'), label: this.$t('Match'),
type: 'select', type: 'select',
options: attrMatchOptions, options: attrMatchOptions,
on: { on: {
@@ -88,7 +88,7 @@ export default {
}, },
{ {
id: 'value', id: 'value',
label: this.$t('common.AttrValue'), label: this.$t('AttrValue'),
component: ValueField, component: ValueField,
el: { el: {
match: attrMatchOptions[0].value, match: attrMatchOptions[0].value,

View File

@@ -2,7 +2,7 @@
<Dialog <Dialog
:destroy-on-close="true" :destroy-on-close="true"
:show-buttons="false" :show-buttons="false"
:title="$tc('common.MatchResult')" :title="$tc('MatchResult')"
:v-bind="$attrs" :v-bind="$attrs"
:v-on="$listeners" :v-on="$listeners"
:visible.sync="iVisible" :visible.sync="iVisible"

View File

@@ -10,10 +10,10 @@
<DataTable :config="tableConfig" class="attr-list" /> <DataTable :config="tableConfig" class="attr-list" />
<div class="actions"> <div class="actions">
<el-button size="mini" type="primary" @click="handleAttrAdd"> <el-button size="mini" type="primary" @click="handleAttrAdd">
{{ $t('common.Add') }} {{ $t('Add') }}
</el-button> </el-button>
<span style="padding-left: 10px; font-size: 13px"> <span style="padding-left: 10px; font-size: 13px">
<span class="help-tips; ">{{ $t('common.MatchedCount') }}:</span> <span class="help-tips; ">{{ $t('MatchedCount') }}:</span>
<a class="text-link" style="padding: 0 5px;" @click="showAttrMatchTable">{{ attrMatchCount }}</a> <a class="text-link" style="padding: 0 5px;" @click="showAttrMatchTable">{{ attrMatchCount }}</a>
</span> </span>
</div> </div>
@@ -101,16 +101,16 @@ export default {
ids: this.value.ids || [], ids: this.value.ids || [],
editIndex: -1, editIndex: -1,
types: [ types: [
{ name: 'all', label: this.$t('common.All') + this.resource }, { name: 'all', label: this.$t('All') + ' ' + this.resource },
{ name: 'ids', label: this.$t('common.Spec') + this.resource }, { name: 'ids', label: this.$t('Spec') + ' ' + this.resource },
{ name: 'attrs', label: this.$t('common.SelectByAttr') } { name: 'attrs', label: this.$t('SelectByAttr') }
], ],
tableConfig: { tableConfig: {
columns: [ columns: [
{ prop: 'name', label: this.$t('common.AttrName'), formatter: tableFormatter('name') }, { prop: 'name', label: this.$t('AttrName'), formatter: tableFormatter('name') },
{ prop: 'match', label: this.$t('common.Match'), formatter: tableFormatter('match') }, { prop: 'match', label: this.$t('Match'), formatter: tableFormatter('match') },
{ prop: 'value', label: this.$t('common.AttrValue'), formatter: ValueFormatter, formatterArgs: { attrs: this.attrs }}, { prop: 'value', label: this.$t('AttrValue'), formatter: ValueFormatter, formatterArgs: { attrs: this.attrs }},
{ prop: 'action', label: this.$t('common.Action'), align: 'center', width: '120px', formatter: (row, col, cellValue, index) => { { prop: 'action', label: this.$t('Action'), align: 'center', width: '120px', formatter: (row, col, cellValue, index) => {
return ( return (
<div className='input-button'> <div className='input-button'>
<el-button <el-button

View File

@@ -2,9 +2,9 @@
<div class="json-editor"> <div class="json-editor">
<JsonEditor <JsonEditor
v-model="resultInfo" v-model="resultInfo"
:class="{resize: resize === 'vertical'}"
:mode="'code'" :mode="'code'"
:show-btns="false" :show-btns="false"
:class="{resize: resize === 'vertical'}"
@json-change="onJsonChange" @json-change="onJsonChange"
@json-save="onJsonSave" @json-save="onJsonSave"
@has-error="onError" @has-error="onError"
@@ -53,7 +53,7 @@ export default {
}, 500) }, 500)
}, },
onError: _.debounce(function(value) { onError: _.debounce(function(value) {
this.$message.error(this.$tc('common.FormatError')) this.$message.error(this.$tc('FormatError'))
}, 1500) }, 1500)
} }
} }
@@ -64,28 +64,28 @@ export default {
.json-editor { .json-editor {
.resize { .resize {
& > > > .jsoneditor { & >>> .jsoneditor {
resize: vertical; resize: vertical;
cursor: s-resize; cursor: s-resize;
} }
} }
& > > > .jsoneditor { & >>> .jsoneditor {
border: 1px solid #e5e6e7; border: 1px solid #e5e6e7;
} }
& > > > .jsoneditor-compact { & >>> .jsoneditor-compact {
display: none; display: none;
} }
& > > > .jsoneditor-modes { & >>> .jsoneditor-modes {
display: none; display: none;
} }
& > > > .jsoneditor-poweredBy { & >>> .jsoneditor-poweredBy {
display: none; display: none;
} }
& > > > .jsoneditor-menu { & >>> .jsoneditor-menu {
background: var(--color-primary); background: var(--color-primary);
border-bottom: 1px solid var(--color-primary); border-bottom: 1px solid var(--color-primary);
} }

View File

@@ -1,11 +1,11 @@
<template> <template>
<div style="display: block"> <div style="display: block">
<el-button size="mini" type="primary" @click="visible=true"> <el-button size="mini" type="primary" @click="visible=true">
{{ $t('common.Setting') }} {{ $t('Setting') }}
</el-button> </el-button>
<Dialog <Dialog
:destroy-on-close="true" :destroy-on-close="true"
:title="$tc('common.PasswordRule')" :title="$tc('PasswordRule')"
:visible.sync="visible" :visible.sync="visible"
width="600px" width="600px"
@cancel="handleCancel" @cancel="handleCancel"
@@ -44,7 +44,7 @@ export default {
fields: [ fields: [
{ {
id: 'length', id: 'length',
label: this.$t('common.Length'), label: this.$t('Length'),
type: 'input-number', type: 'input-number',
el: { el: {
min: 8, min: 8,
@@ -53,27 +53,27 @@ export default {
}, },
{ {
id: 'uppercase', id: 'uppercase',
label: this.$t('common.Uppercase'), label: this.$t('Uppercase'),
type: 'switch' type: 'switch'
}, },
{ {
id: 'lowercase', id: 'lowercase',
label: this.$t('common.Lowercase'), label: this.$t('Lowercase'),
type: 'switch' type: 'switch'
}, },
{ {
id: 'digit', id: 'digit',
label: this.$t('common.Digit'), label: this.$t('Digit'),
type: 'switch' type: 'switch'
}, },
{ {
id: 'symbol', id: 'symbol',
label: this.$t('common.SpecialSymbol'), label: this.$t('SpecialSymbol'),
type: 'switch' type: 'switch'
}, },
{ {
id: 'exclude_symbols', id: 'exclude_symbols',
label: this.$t('common.ExcludeSymbol'), label: this.$t('ExcludeSymbol'),
type: 'input' type: 'input'
} }
] ]

View File

@@ -1,10 +1,10 @@
<template> <template>
<div> <div>
<el-input v-model="rawValue.phone" :placeholder="$tc('users.inputPhone')" @input="OnInputChange"> <el-input v-model="rawValue.phone" :placeholder="$tc('InputPhone')" @input="OnInputChange">
<el-select <el-select
slot="prepend" slot="prepend"
:placeholder="$tc('Select')"
:value="rawValue.code" :value="rawValue.code"
:placeholder="$tc('common.Select')"
style="width: 90px;" style="width: 90px;"
@change="OnChange" @change="OnChange"
> >

View File

@@ -5,16 +5,16 @@
:destroy-on-close="true" :destroy-on-close="true"
:show-cancel="false" :show-cancel="false"
:show-confirm="false" :show-confirm="false"
:title="$tc('assets.PlatformProtocolConfig') + '' + protocol.name" :title="$tc('PlatformProtocolConfig') + '' + protocol.name"
class="setting-dialog" class="setting-dialog"
v-bind="$attrs" v-bind="$attrs"
width="800px" width="800px"
v-on="$listeners" v-on="$listeners"
> >
<el-alert v-if="disabled && platformDetail" style="margin-bottom: 10px" type="success"> <el-alert v-if="disabled && platformDetail" style="margin-bottom: 10px" type="success">
{{ $t('assets.InheritPlatformConfig') }} {{ $t('InheritPlatformConfig') }}
<el-link :href="platformDetail" class="link-more" target="_blank"> <el-link :href="platformDetail" class="link-more" target="_blank">
{{ $t('common.View') }} {{ $t('View') }}
</el-link> </el-link>
<i class="fa fa-external-link" /> <i class="fa fa-external-link" />
</el-alert> </el-alert>
@@ -60,10 +60,10 @@ export default {
hasButtons: !this.disabled, hasButtons: !this.disabled,
url: '/api/v1/assets/protocol-settings/?name=' + this.protocol.name, url: '/api/v1/assets/protocol-settings/?name=' + this.protocol.name,
fields: [ fields: [
[vm.$t('common.Basic'), [ [vm.$t('Basic'), [
'primary', 'required', 'default', 'public' 'primary', 'required', 'default', 'public'
]], ]],
[vm.$t('common.Advanced'), ['setting']] [vm.$t('Advanced'), ['setting']]
], ],
fieldsMeta: { fieldsMeta: {
setting: { setting: {
@@ -107,12 +107,12 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.data-form > > > .el-form-item.form-buttons { .data-form >>> .el-form-item.form-buttons {
padding-top: 10px; padding-top: 10px;
margin-bottom: 0; margin-bottom: 0;
} }
.setting-dialog > > > .el-dialog__body { .setting-dialog >>> .el-dialog__body {
padding-top: 10px; padding-top: 10px;
} }

View File

@@ -129,9 +129,9 @@ export default {
}, },
portPlaceholder() { portPlaceholder() {
if (this.settingReadonly) { if (this.settingReadonly) {
return this.$t('applications.port') return this.$t('Port')
} else { } else {
return this.$t('assets.DefaultPort') return this.$t('DefaultPort')
} }
}, },
iChoices() { iChoices() {
@@ -348,7 +348,7 @@ export default {
} }
.input-button { .input-button {
margin-top: 4px; margin-top: 2px;
display: flex; display: flex;
margin-left: 20px margin-left: 20px
} }

View File

@@ -6,19 +6,21 @@
:clearable="clearable" :clearable="clearable"
:collapse-tags="collapseTags" :collapse-tags="collapseTags"
:disabled="!!selectDisabled" :disabled="!!selectDisabled"
:filterable="true"
:loading="!initialized" :loading="!initialized"
:multiple="multiple" :multiple="multiple"
:options="iOptions" :options="iOptions"
:remote="remote" :remote="remote"
:remote-method="filterOptions" :remote-method="filterOptions"
class="select2" class="select2"
filterable
popper-append-to-body popper-append-to-body
v-bind="$attrs"
@change="onChange" @change="onChange"
v-on="$listeners" v-on="$listeners"
@visible-change="onVisibleChange" @visible-change="onVisibleChange"
> >
<div v-if="showSelectAll" class="el-select-dropdown__header">
<el-checkbox v-model="allSelected" @change="handleSelectAllChange">{{ $t('SelectAll') }}</el-checkbox>
</div>
<el-option <el-option
v-for="item in iOptions" v-for="item in iOptions"
:key="item.value" :key="item.value"
@@ -26,6 +28,7 @@
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
</template> </template>
@@ -95,6 +98,10 @@ export default {
collapseTagsCount: { collapseTagsCount: {
type: Number, type: Number,
default: 10 default: 10
},
showSelectAll: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@@ -126,7 +133,8 @@ export default {
params: _.cloneDeep(defaultParams), params: _.cloneDeep(defaultParams),
iOptions: this.options || [], iOptions: this.options || [],
initialOptions: [], initialOptions: [],
remote: true remote: true,
allSelected: false
} }
}, },
computed: { computed: {
@@ -376,6 +384,25 @@ export default {
this.$log.debug('Visible change, refresh select2') this.$log.debug('Visible change, refresh select2')
} }
this.$emit('visible-change', visible) this.$emit('visible-change', visible)
},
async loadAll() {
if (!this.iAjax.url) {
return
}
while (this.params.hasMore) {
await this.loadMore()
}
},
async selectAll() {
await this.loadAll()
this.iValue = this.iOptions.map((v) => v.value)
},
handleSelectAllChange(checked) {
if (checked) {
this.selectAll()
} else {
this.iValue = []
}
} }
} }
} }
@@ -391,4 +418,13 @@ export default {
height: auto; height: auto;
white-space: normal; white-space: normal;
} }
.select2 >>> input::placeholder {
padding-left: 2px;
}
.el-select-dropdown__header {
padding: 10px 20px;
border-bottom: solid 1px #ebeef5;
}
</style> </style>

View File

@@ -17,12 +17,12 @@
ref="SearchInput" ref="SearchInput"
v-model.trim="filterValue" v-model.trim="filterValue"
:fetch-suggestions="autocomplete" :fetch-suggestions="autocomplete"
:placeholder="this.$t('common.EnterToContinue')" :placeholder="this.$t('EnterToContinue')"
:type="inputType" :type="inputType"
class="search-input" class="search-input"
@blur="focus = false" @blur="focus = false"
@focus="focus = true"
@change="handleChange" @change="handleChange"
@focus="focus = true"
@select="handleSelect" @select="handleSelect"
@keyup.enter.native="handleConfirm" @keyup.enter.native="handleConfirm"
/> />
@@ -53,7 +53,7 @@ export default {
}, },
placeholder: { placeholder: {
type: String, type: String,
default: () => i18n.t('perms.Input') default: () => i18n.t('Input')
}, },
autocomplete: { autocomplete: {
type: Function, type: Function,
@@ -153,7 +153,7 @@ export default {
border: 1px solid #dcdee2; border: 1px solid #dcdee2;
border-radius: 1px; border-radius: 1px;
background-color: #fff; background-color: #fff;
line-height: 32px; line-height: 30px;
&:hover { &:hover {
border-color: #C0C4CC; border-color: #C0C4CC;
@@ -165,7 +165,7 @@ export default {
} }
&>>> .el-autocomplete { &>>> .el-autocomplete {
height: 30px; height: 28px;
} }
} }
@@ -184,7 +184,7 @@ export default {
} }
.filter-field >>> .el-input__inner { .filter-field >>> .el-input__inner {
height: 29px; height: 28px;
} }
.show-password { .show-password {

View File

@@ -1,6 +1,6 @@
<template> <template>
<div :class="bolder ? 'bolder' : ''" class="input-text"> <div :class="bolder ? 'bolder' : ''" class="input-text">
{{ value.toString() || text }} {{ text || value.toString() }}
</div> </div>
</template> </template>
@@ -8,7 +8,7 @@
export default { export default {
props: { props: {
value: { value: {
type: [String, Boolean], type: [String, Boolean, Object, Array],
default: '' default: ''
}, },
text: { text: {

View File

@@ -11,9 +11,9 @@
/> />
<Dialog <Dialog
v-if="showTransfer" v-if="showTransfer"
:close-on-click-modal="false"
:title="label" :title="label"
:visible.sync="showTransfer" :visible.sync="showTransfer"
:close-on-click-modal="false"
width="730px" width="730px"
@cancel="handleTransCancel" @cancel="handleTransCancel"
@confirm="handleTransConfirm" @confirm="handleTransConfirm"
@@ -100,6 +100,7 @@ export default {
filterable: true, filterable: true,
async: true, async: true,
dataList: [], dataList: [],
transferOnCheck: true,
getPageData: function(pageIndex, pageSize) { getPageData: function(pageIndex, pageSize) {
return getPageData({ pageIndex, pageSize }) return getPageData({ pageIndex, pageSize })
}, },

View File

@@ -1,15 +1,15 @@
<template> <template>
<div> <div>
<el-button v-show="!isShow" type="text" icon="el-icon-edit" @click="isShow=true"> <el-button v-show="!isShow" icon="el-icon-edit" type="text" @click="isShow=true">
{{ text }} {{ text }}
</el-button> </el-button>
<el-input <el-input
v-show="isShow" v-show="isShow"
v-model.trim="curValue" v-model.trim="curValue"
show-password :placeholder="placeholder"
:type="type" :type="type"
autocomplete="new-password" autocomplete="new-password"
:placeholder="placeholder" show-password
@change="onChange" @change="onChange"
/> />
</div> </div>
@@ -29,7 +29,7 @@ export default {
text: { text: {
type: String, type: String,
default() { default() {
return this.$t('common.Update') return this.$t('Update')
} }
}, },
showInput: { showInput: {

View File

@@ -2,13 +2,13 @@
<div> <div>
<input ref="upLoadFile" :accept="accept" style="display: none" type="file" @change="Onchange"> <input ref="upLoadFile" :accept="accept" style="display: none" type="file" @change="Onchange">
<el-button size="mini" @click.native.stop="onUpLoad"> <el-button size="mini" @click.native.stop="onUpLoad">
{{ this.$t('common.SelectFile') }} {{ this.$t('SelectFile') }}
</el-button> </el-button>
<span>{{ fileName }}</span> <span>{{ fileName }}</span>
<div v-if="tip !== ''" class="help-block">{{ tip }}</div> <div v-if="tip !== ''" class="help-block">{{ tip }}</div>
<input v-model="value" hidden type="text" v-on="$listeners"> <input v-model="value" hidden type="text" v-on="$listeners">
<div> <div>
<img :src="preview" v-bind="$attrs"> <img :class="showBG ? 'show-bg' : ''" :src="preview" v-bind="$attrs">
</div> </div>
</div> </div>
</template> </template>
@@ -27,6 +27,10 @@ export default {
accept: { accept: {
type: String, type: String,
default: '*' default: '*'
},
showBG: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@@ -74,6 +78,8 @@ export default {
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
.show-bg {
background-color: var(--banner-bg);
}
</style> </style>

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class="upload-key"> <div class="upload-key">
<input ref="upLoadFile" type="file" style="display: none" @change="onChange"> <input ref="upLoadFile" style="display: none" type="file" @change="onChange">
<el-button v-if="!fingerprint" size="mini" @click.native.stop="onUpLoad"> <el-button v-if="!fingerprint" size="mini" @click.native.stop="onUpLoad">
{{ this.$t('common.SelectFile') }} {{ this.$t('SelectFile') }}
</el-button> </el-button>
<span v-else> <span v-else>
<el-button type="text" icon="el-icon-edit" @click.native.stop="onUpLoad"> <el-button icon="el-icon-edit" type="text" @click.native.stop="onUpLoad">
{{ this.$t('common.Update') }} {{ this.$t('Update') }}
</el-button> </el-button>
<span v-if="!fileName" class="fingerprint">{{ fingerprint }}</span> <span v-if="!fileName" class="fingerprint">{{ fingerprint }}</span>
</span> </span>

View File

@@ -2,21 +2,21 @@
<div class=""> <div class="">
<el-input <el-input
v-model="iValue" v-model="iValue"
type="textarea"
:rows="rows"
:placeholder="placeholder" :placeholder="placeholder"
:rows="rows"
type="textarea"
/> />
<el-upload <el-upload
ref="upload" ref="upload"
class="upload-secret"
:action="''"
:accept="accept" :accept="accept"
:action="''"
:auto-upload="false" :auto-upload="false"
:file-list="fileList"
:limit="limit" :limit="limit"
v-bind="$attrs"
:on-change="handleChange" :on-change="handleChange"
:on-remove="handleRemove" :on-remove="handleRemove"
:file-list="fileList" class="upload-secret"
v-bind="$attrs"
> >
<el-button size="mini" type="primary"> <el-button size="mini" type="primary">
{{ btnText }} {{ btnText }}
@@ -38,7 +38,7 @@ export default {
btnText: { btnText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('common.SelectFile') return this.$t('SelectFile')
} }
}, },
rows: { rows: {

View File

@@ -1,7 +1,7 @@
<template> <template>
<PasswordInput <PasswordInput
:value="value"
:attrs="attrs" :attrs="attrs"
:value="value"
@input="handleInput" @input="handleInput"
/> />
</template> </template>
@@ -33,17 +33,17 @@ export default {
} }
const patterns = [] const patterns = []
if (passwordRule['SECURITY_PASSWORD_UPPER_CASE']) { if (passwordRule['SECURITY_PASSWORD_UPPER_CASE']) {
patterns.push([/[A-Z]/, i18n.t('common.password.UPPER_CASE_REQUIRED')]) patterns.push([/[A-Z]/, i18n.t('UPPER_CASE_REQUIRED')])
} }
if (passwordRule['SECURITY_PASSWORD_LOWER_CASE']) { if (passwordRule['SECURITY_PASSWORD_LOWER_CASE']) {
patterns.push([/[a-z]/, i18n.t('common.password.LOWER_CASE_REQUIRED')]) patterns.push([/[a-z]/, i18n.t('LOWER_CASE_REQUIRED')])
} }
if (passwordRule['SECURITY_PASSWORD_NUMBER']) { if (passwordRule['SECURITY_PASSWORD_NUMBER']) {
patterns.push([/\d/, i18n.t('common.password.NUMBER_REQUIRED')]) patterns.push([/\d/, i18n.t('NUMBER_REQUIRED')])
} }
if (passwordRule['SECURITY_PASSWORD_SPECIAL_CHAR']) { if (passwordRule['SECURITY_PASSWORD_SPECIAL_CHAR']) {
const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~@#¥……&*()——|{}【】‘;:”“'。,、?]") const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~@#¥……&*()——|{}【】‘;:”“'。,、?]")
patterns.push([pattern, i18n.t('common.password.SPECIAL_CHAR_REQUIRED')]) patterns.push([pattern, i18n.t('SPECIAL_CHAR_REQUIRED')])
} }
for (const [pattern, msg] of patterns) { for (const [pattern, msg] of patterns) {
if (!pattern.test(value)) { if (!pattern.test(value)) {
@@ -55,7 +55,7 @@ export default {
secureLength = passwordRule ? passwordRule.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH : 7 secureLength = passwordRule ? passwordRule.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH : 7
} }
if (value.length < secureLength) { if (value.length < secureLength) {
return callback(new Error(i18n.t('common.password.MIN_LENGTH_ERROR', [secureLength]))) return callback(new Error(i18n.t('MIN_LENGTH_ERROR', [secureLength])))
} }
callback() callback()
} }

View File

@@ -5,7 +5,7 @@
<table :class="{'c-min-table': colspan < 2}" class="c-weektime-table"> <table :class="{'c-min-table': colspan < 2}" class="c-weektime-table">
<thead class="c-weektime-head"> <thead class="c-weektime-head">
<tr> <tr>
<th class="week-td" rowspan="8">{{ this.$t('common.WeekCronSelect.WeekOrTime') }}</th> <th class="week-td" rowspan="8">{{ this.$t('WeekOrTime') }}</th>
<th :colspan="12 * colspan">00:00 - 12:00</th> <th :colspan="12 * colspan">00:00 - 12:00</th>
<th :colspan="12 * colspan">12:00 - 24:00</th> <th :colspan="12 * colspan">12:00 - 24:00</th>
</tr> </tr>
@@ -31,9 +31,9 @@
<tr> <tr>
<td class="c-weektime-preview" colspan="49"> <td class="c-weektime-preview" colspan="49">
<div class="g-clearfix c-weektime-con"> <div class="g-clearfix c-weektime-con">
<span class="g-pull-left">{{ this.$t('common.WeekCronSelect.CanDragSelect') }}</span> <span class="g-pull-left">{{ this.$t('CanDragSelect') }}</span>
<a class="g-pull-right" @click.prevent="clearWeektime">{{ this.$t('common.WeekCronSelect.ClearSelection') }}</a> <a class="g-pull-right" @click.prevent="clearWeektime">{{ this.$t('ClearSelection') }}</a>
<a class="g-pull-right g-pull-margin" @click.prevent="selectAll">{{ this.$t('common.WeekCronSelect.SelectAll') }}</a> <a class="g-pull-right g-pull-margin" @click.prevent="selectAll">{{ this.$t('SelectAll') }}</a>
</div> </div>
</td> </td>
</tr> </tr>
@@ -92,13 +92,13 @@ export default {
col: 0, col: 0,
theadArr: [], theadArr: [],
weekArr: [ weekArr: [
this.$t('common.WeekCronSelect.Monday'), this.$t('Monday'),
this.$t('common.WeekCronSelect.Tuesday'), this.$t('Tuesday'),
this.$t('common.WeekCronSelect.Wednesday'), this.$t('Wednesday'),
this.$t('common.WeekCronSelect.Thursday'), this.$t('Thursday'),
this.$t('common.WeekCronSelect.Friday'), this.$t('Friday'),
this.$t('common.WeekCronSelect.Saturday'), this.$t('Saturday'),
this.$t('common.WeekCronSelect.Sunday') this.$t('Sunday')
], ],
weektimeData: [], weektimeData: [],
timeRange: [] // 格式化之后数据 timeRange: [] // 格式化之后数据

View File

@@ -5,7 +5,7 @@
:async="async" :async="async"
:async-search-flag="asyncSearchFlag" :async-search-flag="asyncSearchFlag"
:data-show-list="notSelectDataList" :data-show-list="notSelectDataList"
:filter-placeholder="filterPlaceholder[0] || $tc('common.Search')" :filter-placeholder="filterPlaceholder[0] || $tc('Search')"
:filterable="filterable" :filterable="filterable"
:highlight-color="highlightColor" :highlight-color="highlightColor"
:is-highlight="isHighlight" :is-highlight="isHighlight"
@@ -14,7 +14,7 @@
:page-size="pageSize" :page-size="pageSize"
:page-texts="pageTexts" :page-texts="pageTexts"
:show-clear-btn="showClearBtn" :show-clear-btn="showClearBtn"
:title="boxTitle[0] || $tc('common.Selection')" :title="boxTitle[0] || $tc('Selection')"
@check-district="noCheckSelect" @check-district="noCheckSelect"
@search-word="searchWord" @search-word="searchWord"
@check-disable="checkDisable" @check-disable="checkDisable"
@@ -42,7 +42,7 @@
<krry-box <krry-box
ref="hasSelect" ref="hasSelect"
:data-show-list="checkedData" :data-show-list="checkedData"
:filter-placeholder="filterPlaceholder[1] || $tc('common.Search')" :filter-placeholder="filterPlaceholder[1] || $tc('Search')"
:filterable="filterable" :filterable="filterable"
:highlight-color="highlightColor" :highlight-color="highlightColor"
:is-highlight="isHighlight" :is-highlight="isHighlight"
@@ -50,7 +50,7 @@
:page-size="pageSize" :page-size="pageSize"
:page-texts="pageTexts" :page-texts="pageTexts"
:show-clear-btn="showClearBtn" :show-clear-btn="showClearBtn"
:title="boxTitle[1] || $tc('common.Selected')" :title="boxTitle[1] || $tc('Selected')"
@check-district="hasCheckSelect" @check-district="hasCheckSelect"
@search-word="searchWord" @search-word="searchWord"
@check-disable="checkDisable" @check-disable="checkDisable"
@@ -70,7 +70,7 @@ export default {
props: { props: {
boxTitle: { boxTitle: {
type: Array, type: Array,
// default: () => [this.$tc('common.Selection'), this.$tc('common.Selected')] // default: () => [this.$tc('Selection'), this.$tc('Selected')]
default: () => ['', ''] default: () => ['', '']
}, },
pageSize: { pageSize: {
@@ -92,12 +92,12 @@ export default {
filterPlaceholder: { filterPlaceholder: {
type: Array, type: Array,
default: () => ['', ''] default: () => ['', '']
// default: () => [this.$tc('common.Search'), this.$tc('common.Search')] // default: () => [this.$tc('Search'), this.$tc('Search')]
}, },
pageTexts: { pageTexts: {
type: Array, type: Array,
default: () => ['', ''] default: () => ['', '']
// default: () => ['< ' + this.$tc('common.PagePrev'), this.$tc('common.PageNext') + ' >'] // default: () => ['< ' + this.$tc('PagePrev'), this.$tc('PageNext') + ' >']
}, },
sort: { sort: {
type: Boolean, type: Boolean,
@@ -126,6 +126,10 @@ export default {
showClearBtn: { showClearBtn: {
type: Boolean, type: Boolean,
default: () => false default: () => false
},
transferOnCheck: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@@ -259,10 +263,14 @@ export default {
// 未选中区域的选泽 // 未选中区域的选泽
noCheckSelect(val) { noCheckSelect(val) {
this.noCheckData = val this.noCheckData = val
if (this.transferOnCheck) {
setTimeout(() => this.addData(), 300)
}
}, },
// 已选中区域的选泽 // 已选中区域的选泽
hasCheckSelect(val) { hasCheckSelect(val) {
this.hasCheckData = val this.hasCheckData = val
setTimeout(() => this.deleteData(), 300)
}, },
// 关键把未选择的数据当做已选择的过滤数组把已选择的数据当做未选择的过滤数组在全局data进行过滤最后进行一次搜索 // 关键把未选择的数据当做已选择的过滤数组把已选择的数据当做未选择的过滤数组在全局data进行过滤最后进行一次搜索
// 添加至已选 // 添加至已选
@@ -418,8 +426,5 @@ export default {
padding: 5px; padding: 5px;
} }
} }
.el-transfer-panel__filter .el-input__inner {
border-radius: 0;
}
</style> </style>

View File

@@ -50,7 +50,7 @@
<span v-html="isHighlight ? filterHighlight(item.label) : item.label" /> <span v-html="isHighlight ? filterHighlight(item.label) : item.label" />
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
<p v-else class="no-data">{{ this.$t('common.NoData') }}</p> <p v-else class="no-data">{{ this.$t('NoData') }}</p>
</div> </div>
<div class="vip-footer"> <div class="vip-footer">
<el-button :disabled="disabledPre" class="v-page" plain small @click="prev"> <el-button :disabled="disabledPre" class="v-page" plain small @click="prev">
@@ -131,8 +131,8 @@ export default {
asyncSearch: false, // 要执行异步搜索的标记 asyncSearch: false, // 要执行异步搜索的标记
asyncPageIndex: 1, // 异步分页的 pageIndex asyncPageIndex: 1, // 异步分页的 pageIndex
asyncSearchPageIndex: 1, // 异步搜索的 pageIndex, asyncSearchPageIndex: 1, // 异步搜索的 pageIndex,
defaultPrev: '< ' + this.$tc('common.PagePrev'), defaultPrev: '< ' + this.$tc('PagePrev'),
defaultNext: this.$tc('common.PageNext') + ' >' defaultNext: this.$tc('PageNext') + ' >'
} }
}, },
watch: { watch: {
@@ -307,6 +307,10 @@ export default {
margin: 6px 14px; margin: 6px 14px;
line-height: 0; line-height: 0;
.el-input__inner {
height: 30px;
}
.showClear { .showClear {
padding-right: 30px; padding-right: 30px;
border-radius: 0; border-radius: 0;

View File

@@ -1,12 +1,12 @@
<template> <template>
<tr> <tr>
<td>{{ action.title }}:</td> <td>{{ getActionTitle(action) }}:</td>
<td> <td>
<el-popover <el-popover
:content="action.attrs.tip"
:disabled="!action.attrs.showTip"
placement="left-end" placement="left-end"
trigger="hover" trigger="hover"
:disabled="!action.attrs.showTip"
:content="action.attrs.tip"
> >
<span slot="reference"> <span slot="reference">
<component <component
@@ -27,6 +27,7 @@
import Switcher from '@/components/Form/FormFields/Switcher' import Switcher from '@/components/Form/FormFields/Switcher'
import Select2 from '@/components/Form/FormFields/Select2' import Select2 from '@/components/Form/FormFields/Select2'
import UpdateSelect from '@/components/Form/FormFields/UpdateSelect' import UpdateSelect from '@/components/Form/FormFields/UpdateSelect'
import { toSentenceCase } from '@/utils/common'
class Action { class Action {
constructor() { constructor() {
@@ -84,6 +85,11 @@ export default {
} }
return wrappers return wrappers
} }
},
methods: {
getActionTitle(action) {
return toSentenceCase(action.title)
}
} }
} }
</script> </script>

View File

@@ -1,5 +1,5 @@
<template> <template>
<IBox :fa="fa" :title="title" v-bind="$attrs"> <IBox :fa="fa" :title="$tc('QuickUpdate')" v-bind="$attrs">
<div v-for="action of actions" :key="action.title" class="quick-actions"> <div v-for="action of actions" :key="action.title" class="quick-actions">
<table> <table>
<ActionItem v-if="action.has === undefined || action.has" :action="action" /> <ActionItem v-if="action.has === undefined || action.has" :action="action" />
@@ -27,7 +27,7 @@ export default {
title: { title: {
type: String, type: String,
default() { default() {
return this.$t('common.QuickUpdate') return this.$t('QuickUpdate')
} }
}, },
actions: { actions: {

View File

@@ -3,7 +3,14 @@
<el-button v-if="shouldFold" circle class="search-btn" size="mini" @click="handleManualSearch"> <el-button v-if="shouldFold" circle class="search-btn" size="mini" @click="handleManualSearch">
<svg-icon icon-class="search" /> <svg-icon icon-class="search" />
</el-button> </el-button>
<TagSearch v-else :options="iOption" v-bind="$attrs" v-on="$listeners" @tag-search="handleTagSearch" /> <TagSearch
v-show="!shouldFold"
:options="iOption"
v-bind="$attrs"
@blur="handleBlur"
v-on="$listeners"
@tag-search="handleTagSearch"
/>
</span> </span>
</template> </template>
@@ -50,7 +57,7 @@ export default {
return _.uniqWith(options, _.isEqual) return _.uniqWith(options, _.isEqual)
}, },
shouldFold() { shouldFold() {
return this.fold && this.tags.length === 0 && !this.manualSearch return this.fold && (!this.tags || this.tags.length === 0) && !this.manualSearch
} }
}, },
watch: { watch: {
@@ -71,12 +78,15 @@ export default {
if (_.isEqual(tags, this.tags)) { if (_.isEqual(tags, this.tags)) {
return return
} }
this.tags = tags this.tags = (tags || [])
if (tags.length === 0) { if (tags.length === 0) {
this.manualSearch = false this.manualSearch = false
} }
this.$emit('tagSearch', tags) this.$emit('tagSearch', tags)
}, },
handleBlur() {
this.manualSearch = false
},
handleManualSearch() { handleManualSearch() {
this.manualSearch = true this.manualSearch = true
}, },
@@ -111,8 +121,8 @@ export default {
} }
if (field.type === 'boolean') { if (field.type === 'boolean') {
option.children = [ option.children = [
{ label: i18n.t('common.Yes'), value: true }, { label: i18n.t('Yes'), value: true },
{ label: i18n.t('common.No'), value: false } { label: i18n.t('No'), value: false }
] ]
} }
if (option.value === 'id') { if (option.value === 'id') {
@@ -131,7 +141,7 @@ export default {
<style lang='less' scoped> <style lang='less' scoped>
.search-btn { .search-btn {
margin-top: 4px; margin-top: 1px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: #409eff; color: #409eff;

View File

@@ -1,27 +1,26 @@
<template> <template>
<Dialog <Dialog
v-if="showColumnSettingPopover" v-if="showColumnSettingPopover"
:cancel-title="$tc('common.RestoreDefault')" :cancel-title="$tc('RestoreDefault')"
:destroy-on-close="true" :destroy-on-close="true"
:title="$tc('common.CustomCol')" :title="$tc('TableSetting')"
:visible.sync="showColumnSettingPopover" :visible.sync="showColumnSettingPopover"
top="10%" top="10%"
width="50%" width="50%"
@cancel="restoreDefault()" @cancel="restoreDefault()"
@confirm="handleColumnConfirm()" @confirm="handleColumnConfirm()"
> >
<el-alert type="success"> <label>{{ this.$t('TableColSetting') }}</label>
{{ this.$t('common.TableColSettingInfo') }}
</el-alert>
<el-checkbox-group <el-checkbox-group
v-model="iCurrentColumns" v-model="iCurrentColumns"
class="column-setting"
> >
<el-row> <el-row>
<el-col <el-col
v-for="item in totalColumnsList" v-for="item in totalColumnsList"
:key="item.prop" :key="item.prop"
:span="8" :span="8"
style="margin-top:5px;" class="col-item"
> >
<el-checkbox <el-checkbox
:disabled="item.prop==='actions' || minColumns.indexOf(item.prop)!==-1" :disabled="item.prop==='actions' || minColumns.indexOf(item.prop)!==-1"
@@ -88,5 +87,29 @@ export default {
} }
</script> </script>
<style lang='less' scoped> <style lang='scss' scoped>
.column-setting {
margin-left: 10px;
.col-item {
margin-top: 5px;
>>> .el-checkbox {
width: 100%;
.el-checkbox__input {
line-height: 16px
}
.el-checkbox__label {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
width: calc(100% - 20px); // 20px is the width of the checkbox
line-height: 16px;
vertical-align: text-top;
}
}
}
}
</style> </style>

View File

@@ -26,7 +26,7 @@ import {
ObjectRelatedFormatter ObjectRelatedFormatter
} from '@/components/Table/TableFormatters' } from '@/components/Table/TableFormatters'
import i18n from '@/i18n/i18n' import i18n from '@/i18n/i18n'
import { newURL, replaceAllUUID } from '@/utils/common' import { newURL, replaceAllUUID, toSentenceCase } from '@/utils/common'
import ColumnSettingPopover from './components/ColumnSettingPopover.vue' import ColumnSettingPopover from './components/ColumnSettingPopover.vue'
import LabelsFormatter from '@/components/Table/TableFormatters/LabelsFormatter.vue' import LabelsFormatter from '@/components/Table/TableFormatters/LabelsFormatter.vue'
@@ -105,24 +105,26 @@ export default {
col.formatter = DetailFormatter col.formatter = DetailFormatter
col.sortable = 'custom' col.sortable = 'custom'
col.showOverflowTooltip = true col.showOverflowTooltip = true
col.minWidth = '150px'
break break
case 'actions': case 'actions':
col = { col = {
prop: 'actions', prop: 'actions',
label: i18n.t('common.Actions'), label: i18n.t('Actions'),
align: 'center', align: 'center',
width: '150px', width: '100px',
formatter: ActionsFormatter, formatter: ActionsFormatter,
fixed: 'right',
formatterArgs: {} formatterArgs: {}
} }
break break
case 'is_valid': case 'is_valid':
col.label = i18n.t('common.Validity') col.label = i18n.t('Valid')
col.formatter = ChoicesFormatter col.formatter = ChoicesFormatter
col.formatterArgs = { col.formatterArgs = {
textChoices: { textChoices: {
true: i18n.t('common.Yes'), true: i18n.t('Yes'),
false: i18n.t('common.No') false: i18n.t('No')
} }
} }
col.width = '80px' col.width = '80px'
@@ -131,11 +133,11 @@ export default {
col.formatter = ChoicesFormatter col.formatter = ChoicesFormatter
col.formatterArgs = { col.formatterArgs = {
textChoices: { textChoices: {
true: i18n.t('common.Active'), true: i18n.t('Active'),
false: i18n.t('common.Inactive') false: i18n.t('Inactive')
} }
} }
col.width = '80px' col.width = '100px'
break break
case 'datetime': case 'datetime':
case 'date_start': case 'date_start':
@@ -143,6 +145,7 @@ export default {
break break
case 'labels': case 'labels':
col.formatter = LabelsFormatter col.formatter = LabelsFormatter
col.width = '200px'
break break
case 'comment': case 'comment':
col.showOverflowTooltip = true col.showOverflowTooltip = true
@@ -165,7 +168,7 @@ export default {
break break
case 'datetime': case 'datetime':
col.formatter = DateFormatter col.formatter = DateFormatter
col.width = '160px' col.width = '175px'
break break
case 'object_related_field': case 'object_related_field':
col.formatter = ObjectRelatedFormatter col.formatter = ObjectRelatedFormatter
@@ -186,16 +189,16 @@ export default {
// this.$log.debug('Field: ', type, col.prop, col) // this.$log.debug('Field: ', type, col.prop, col)
return col return col
}, },
addHelpTipsIfNeed(col) { addHelpTipIfNeed(col) {
const helpTips = col.helpTips const helpTip = col.helpTip
if (!helpTips) { if (!helpTip) {
return col return col
} }
col.renderHeader = (h, { column, $index }) => { col.renderHeader = (h, { column, $index }) => {
return ( return (
<span>{column.label} <span>{column.label}
<el-tooltip placement='bottom' effect='light' popperClass='help-tips'> <el-tooltip placement='bottom' effect='light' popperClass='help-tips'>
<div slot='content' domPropsInnerHTML={helpTips}/> <div slot='content' domPropsInnerHTML={helpTip}/>
<el-button style='padding: 0'> <el-button style='padding: 0'>
<i class='fa fa-info-circle'/> <i class='fa fa-info-circle'/>
</el-button> </el-button>
@@ -213,8 +216,8 @@ export default {
} }
if (column.type === 'boolean') { if (column.type === 'boolean') {
col.filters = [ col.filters = [
{ text: i18n.t('common.Yes'), value: true }, { text: i18n.t('Yes'), value: true },
{ text: i18n.t('common.No'), value: false } { text: i18n.t('No'), value: false }
] ]
col.sortable = false col.sortable = false
col['column-key'] = col.prop col['column-key'] = col.prop
@@ -261,19 +264,45 @@ export default {
} }
return col return col
}, },
setDefaultWidthIfNeed(col) {
const lang = this.$i18n.locale
let factor = 10
if (lang === 'zh') {
factor = 20
}
if (col && !col.width && col.label && !col.minWidth) {
col.minWidth = `${col.label.length * factor + 30}px`
}
return col
},
generateColumn(name) { generateColumn(name) {
const colMeta = this.meta[name] || {} const colMeta = this.meta[name] || {}
const customMeta = this.config.columnsMeta ? this.config.columnsMeta[name] : {} const customMeta = this.config.columnsMeta ? this.config.columnsMeta[name] : {}
let col = { prop: name, label: colMeta.label, showOverflowTooltip: true } let col = { prop: name, label: colMeta.label, showOverflowTooltip: true }
col = this.generateColumnByName(name, col)
col = this.generateColumnByType(colMeta.type, col, colMeta) col = this.generateColumnByType(colMeta.type, col, colMeta)
col = this.generateColumnByName(name, col)
col = this.setDefaultFormatterIfNeed(col) col = this.setDefaultFormatterIfNeed(col)
col = Object.assign(col, customMeta) col = Object.assign(col, customMeta)
col = this.addHelpTipsIfNeed(col) col = this.addHelpTipIfNeed(col)
col = this.addFilterIfNeed(col) col = this.addFilterIfNeed(col)
col = this.addOrderingIfNeed(col) col = this.addOrderingIfNeed(col)
col = this.updateLabelIfNeed(col)
col = this.setDefaultWidthIfNeed(col)
return col
},
updateLabelIfNeed(col) {
if (!col.label) {
return col
}
col.label = col.label
.replace(' Amount', '')
.replace(' amount', '')
.replace('数量', '')
if (col.label.startsWith('Is ')) {
col.label = col.label.replace('Is ', '')
}
col.label = toSentenceCase(col.label)
return col return col
}, },
generateTotalColumns() { generateTotalColumns() {
@@ -315,11 +344,31 @@ export default {
} }
return has return has
}) })
columns = this.orderingColumns(columns)
// 第一次初始化时记录 totalColumns // 第一次初始化时记录 totalColumns
this.totalColumns = columns this.totalColumns = columns
config.columns = columns config.columns = columns
this.iConfig = config this.iConfig = config
}, },
orderingColumns(columns) {
const cols = _.cloneDeep(this.config.columns)
const defaults = _.get(this.config, 'columnsShow.default')
const ordering = (cols || defaults || []).map(item => {
let prop = item
if (typeof item === 'object') {
prop = item.prop
}
return prop
})
return _.sortBy(columns, (item) => {
if (item.prop === 'actions') {
return 1000
}
const i = ordering.indexOf(item.prop)
return i === -1 ? 999 : i
})
},
// 生成给子组件使用的TotalColList // 生成给子组件使用的TotalColList
cleanColumnsShow() { cleanColumnsShow() {
const totalColumnsNames = this.totalColumns.map(obj => obj.prop) const totalColumnsNames = this.totalColumns.map(obj => obj.prop)

View File

@@ -8,41 +8,51 @@
/> />
<div style="padding-top: 15px"> <div style="padding-top: 15px">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col v-for="(d, index) in totalData" :key="index" :span="6"> <el-col v-for="(d, index) in totalData" :key="index" :span="8">
<el-card <el-card
:body-style="{ 'text-align': 'center', 'padding': '20px' }" :body-style="{ 'text-align': 'center', 'padding': '20px' }"
class="my-card" class="my-card"
shadow="hover" shadow="hover"
@click.native="onView(d)" @click.native="onView(d)"
> >
<span v-if="d.edition === 'enterprise'" class="enterprise"> <slot :index="index" :item="d">
{{ $t('common.Enterprise') }} <span v-if="d.edition === 'enterprise'" class="enterprise">
</span> {{ $t('Enterprise') }}
<el-row :gutter="20"> </span>
<el-col :span="8"> <el-row :gutter="20">
<img :src="d.icon" class="image"> <el-col v-if="d.icon" :span="8" class="image">
</el-col> <img
<el-col :span="16" style="text-align: left; padding: 5px 0"> v-if="d.icon.startsWith('/') || d.icon.startsWith('data:')"
<div class="one-line"> :alt="d.display_name"
<b>{{ d.display_name }}</b> :src="d.icon"
<el-tag size="mini" style="margin-left: 5px"> >
{{ d.version }} <Icon v-else :icon="d.icon" />
</el-tag> </el-col>
</div> <el-col :span="16" class="text-zone">
<el-divider class="my-divider" /> <div class="one-line">
<div class="comment"> <b>{{ d.display_name }}</b>
{{ d.comment }} <el-tag v-if="d.version" size="mini" style="margin-left: 5px">
</div> {{ d.version }}
<el-tag v-for="tag of d.tags" :key="tag" size="mini"> </el-tag>
{{ capitalize(tag) }} </div>
</el-tag> <el-divider class="my-divider" />
</el-col> <div class="comment">
</el-row> {{ d.comment }}
</div>
<div class="tag-zone">
<el-tag v-for="tag of d.tags" :key="tag" size="mini">
{{ capitalize(tag) }}
</el-tag>
</div>
</el-col>
</el-row>
</slot>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
<Pagination <Pagination
v-if="pagination"
ref="pagination" ref="pagination"
v-bind="$data" v-bind="$data"
@currentSizeChange="handleCurrentChange" @currentSizeChange="handleCurrentChange"
@@ -54,7 +64,7 @@
<script> <script>
import TableAction from '@/components/Table/ListTable/TableAction' import TableAction from '@/components/Table/ListTable/TableAction'
import { Pagination } from '@/components' import { Pagination } from '@/components'
import { toSafeLocalDateStr } from '@/utils/common' import Icon from '@/components/Widgets/Icon/index.vue'
const defaultFirstPage = 1 const defaultFirstPage = 1
@@ -62,7 +72,8 @@ export default {
name: 'CardTable', name: 'CardTable',
components: { components: {
TableAction, TableAction,
Pagination Pagination,
Icon
}, },
props: { props: {
// table // table
@@ -73,6 +84,10 @@ export default {
headerActions: { headerActions: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
pagination: {
type: Boolean,
default: true
} }
}, },
data() { data() {
@@ -112,13 +127,15 @@ export default {
} }
return `<i class="fa ${iconClass}" />` return `<i class="fa ${iconClass}" />`
}, },
convertData(data) {
return toSafeLocalDateStr(data)
},
getPageQuery(currentPage, pageSize) { getPageQuery(currentPage, pageSize) {
return this.$refs.pagination.getPageQuery(currentPage, pageSize) return this.$refs.pagination.getPageQuery(currentPage, pageSize)
}, },
getList() { getList() {
if (this.tableConfig.totalData) {
this.totalData = this.tableConfig.totalData
this.total = this.totalData.length
return
}
if (!this.tableUrl) { if (!this.tableUrl) {
return return
} }
@@ -176,8 +193,8 @@ export default {
viewFunc(obj) viewFunc(obj)
}, },
onDelete(obj) { onDelete(obj) {
const msg = `${this.$t('common.deleteWarningMsg')} "${obj.name}" ?` const msg = `${this.$t('DeleteWarningMsg')} "${obj.name}" ?`
this.$confirm(msg, this.$tc('common.Info'), { this.$confirm(msg, this.$tc('Info'), {
type: 'warning', type: 'warning',
confirmButtonClass: 'el-button--danger', confirmButtonClass: 'el-button--danger',
beforeClose: async(action, instance, done) => { beforeClose: async(action, instance, done) => {
@@ -186,7 +203,7 @@ export default {
await deleteFunc(obj) await deleteFunc(obj)
done() done()
this.reloadTable() this.reloadTable()
this.$message.success(this.$tc('common.deleteSuccessMsg')) this.$message.success(this.$tc('DeleteSuccessMsg'))
} }
}).catch(() => { }).catch(() => {
/* 取消*/ /* 取消*/
@@ -207,10 +224,16 @@ export default {
} }
.image { .image {
width: 60px; img, span {
height: 60px; width: 60px;
display: block; height: 60px;
margin: 50% auto; display: block;
margin: 50% auto;
}
span {
font-size: 36px;
color: black;
}
} }
.one-line { .one-line {
@@ -225,6 +248,7 @@ export default {
height: 50px; height: 50px;
overflow: hidden; overflow: hidden;
margin-bottom: 10px; margin-bottom: 10px;
padding-right: 5px;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 3; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
@@ -260,4 +284,17 @@ export default {
border-radius: 3px 3px 3px 10px; border-radius: 3px 3px 3px 10px;
} }
.tag-zone {
margin-top: 20px;
.el-tag {
margin-right: 3px;
}
}
.text-zone {
text-align: left;
height: 100%;
}
</style> </style>

View File

@@ -99,8 +99,12 @@
:filter-multiple="false" :filter-multiple="false"
:filters="col.filters || null" :filters="col.filters || null"
:formatter="typeof col.formatter === 'function' ? col.formatter : null" :formatter="typeof col.formatter === 'function' ? col.formatter : null"
:title="col.label"
v-bind="{align: columnsAlign, ...col}" v-bind="{align: columnsAlign, ...col}"
> >
<template #header>
<span :title="col.label">{{ col.label }}</span>
</template>
<template v-if="col.formatter && typeof col.formatter !== 'function'" v-slot:default="{row, column, index}"> <template v-if="col.formatter && typeof col.formatter !== 'function'" v-slot:default="{row, column, index}">
<div <div
:is="col.formatter" :is="col.formatter"
@@ -362,7 +366,7 @@ export default {
newText: { newText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('ops.Add') return this.$t('Add')
} }
}, },
/** /**
@@ -371,7 +375,7 @@ export default {
editText: { editText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('ops.Modify') return this.$t('Modify')
} }
}, },
/** /**
@@ -380,7 +384,7 @@ export default {
viewText: { viewText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('ops.View') return this.$t('View')
} }
}, },
/** /**
@@ -389,7 +393,7 @@ export default {
deleteText: { deleteText: {
type: String, type: String,
default: function() { default: function() {
return this.$t('ops.Delete') return this.$t('Delete')
} }
}, },
/** /**
@@ -400,7 +404,7 @@ export default {
deleteMessage: { deleteMessage: {
type: Function, type: Function,
default() { default() {
return this.$t('ops.Confirm') + this.deleteText + '?' return this.$t('Confirm') + this.deleteText + '?'
} }
}, },
/** /**
@@ -459,7 +463,7 @@ export default {
onSuccess: { onSuccess: {
type: Function, type: Function,
default() { default() {
return this.$message.success(this.$t('ops.SuccessfulOperation')) return this.$message.success(this.$t('SuccessfulOperation'))
} }
}, },
/** /**
@@ -1167,7 +1171,7 @@ export default {
* @param {object|object[]} - 要删除的数据对象或数组 * @param {object|object[]} - 要删除的数据对象或数组
*/ */
onDefaultDelete(data) { onDefaultDelete(data) {
this.$confirm(this.deleteMessage(data), this.$t('common.Info'), { this.$confirm(this.deleteMessage(data), this.$t('Info'), {
type: 'warning', type: 'warning',
confirmButtonClass: 'el-button--danger', confirmButtonClass: 'el-button--danger',
beforeClose: async(action, instance, done) => { beforeClose: async(action, instance, done) => {

View File

@@ -168,4 +168,10 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.el-data-table {
>>> .el-pagination.is-background .el-pager li {
margin: 0 1px;
padding: 0 2px;
}
}
</style> </style>

View File

@@ -3,7 +3,7 @@
<Dialog <Dialog
v-if="exportDialogShow" v-if="exportDialogShow"
:destroy-on-close="true" :destroy-on-close="true"
:title="$tc('common.Export')" :title="$tc('Export')"
:visible.sync="exportDialogShow" :visible.sync="exportDialogShow"
width="700px" width="700px"
@cancel="handleExportCancel()" @cancel="handleExportCancel()"
@@ -13,7 +13,7 @@
{{ tips }} {{ tips }}
</el-alert> </el-alert>
<el-form label-position="left" style="padding-left: 20px"> <el-form label-position="left" style="padding-left: 20px">
<el-form-item :label="$tc('common.fileType' )" :label-width="'100px'"> <el-form-item :label="$tc('FileType' )" :label-width="'100px'">
<el-radio-group v-model="exportTypeOption"> <el-radio-group v-model="exportTypeOption">
<el-radio <el-radio
v-for="option of exportTypeOptions" v-for="option of exportTypeOptions"
@@ -26,7 +26,7 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="$tc('common.imExport.ExportRange')" :label-width="'100px'" class="export-form"> <el-form-item :label="$tc('ExportRange')" :label-width="'100px'" class="export-form">
<el-radio-group v-model="exportOption"> <el-radio-group v-model="exportOption">
<el-radio <el-radio
v-for="option of exportOptions" v-for="option of exportOptions"
@@ -138,17 +138,17 @@ export default {
exportOptions() { exportOptions() {
return [ return [
{ {
label: this.$t('common.imExport.ExportAll'), label: this.$t('ExportAll'),
value: 'all', value: 'all',
can: this.canExportAll && !this.tableHasQuery can: this.canExportAll && !this.tableHasQuery
}, },
{ {
label: this.$t('common.imExport.ExportOnlySelectedItems'), label: this.$t('ExportOnlySelectedItems'),
value: 'selected', value: 'selected',
can: this.selectedRows.length > 0 && this.canExportSelected can: this.selectedRows.length > 0 && this.canExportSelected
}, },
{ {
label: this.$t('common.imExport.ExportOnlyFiltered'), label: this.$t('ExportOnlyFiltered'),
value: 'filtered', value: 'filtered',
can: this.tableHasQuery && this.canExportFiltered can: this.tableHasQuery && this.canExportFiltered
} }

View File

@@ -12,12 +12,12 @@
@close="handleImportCancel" @close="handleImportCancel"
> >
<el-form v-if="!showTable" label-position="left" style="padding-left: 20px"> <el-form v-if="!showTable" label-position="left" style="padding-left: 20px">
<el-form-item :label="$tc('common.Import' )" :label-width="'100px'"> <el-form-item :label="$tc('Import' )" :label-width="'100px'">
<el-radio v-if="canImportCreate" v-model="importOption" class="export-item" label="create"> <el-radio v-if="canImportCreate" v-model="importOption" class="export-item" label="create">
{{ this.$t('common.Create') }} {{ this.$t('Create') }}
</el-radio> </el-radio>
<el-radio v-if="canImportUpdate" v-model="importOption" class="export-item" label="update"> <el-radio v-if="canImportUpdate" v-model="importOption" class="export-item" label="update">
{{ this.$t('common.Update') }} {{ this.$t('Update') }}
</el-radio> </el-radio>
<div style="line-height: 1.5"> <div style="line-height: 1.5">
<span class="el-upload__tip"> <span class="el-upload__tip">
@@ -27,7 +27,7 @@
</span> </span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item :label="$tc('common.Upload' )" :label-width="'100px'" class="file-uploader"> <el-form-item :label="$tc('Upload' )" :label-width="'100px'" class="file-uploader">
<el-upload <el-upload
ref="upload" ref="upload"
:auto-upload="false" :auto-upload="false"
@@ -41,11 +41,11 @@
> >
<i class="el-icon-upload" /> <i class="el-icon-upload" />
<div class="el-upload__text"> <div class="el-upload__text">
{{ $t('common.imExport.dragUploadFileInfo') }} {{ $t('DragUploadFileInfo') }}
</div> </div>
<div slot="tip" class="el-upload__tip"> <div slot="tip" class="el-upload__tip">
<span :class="{'hasError': hasFileFormatOrSizeError }"> <span :class="{'hasError': hasFileFormatOrSizeError }">
{{ $t('common.imExport.uploadCsvLth10MHelpText') }} {{ $t('UploadCsvLth10MHelpText') }}
</span> </span>
<div v-if="renderError" class="hasError">{{ renderError }}</div> <div v-if="renderError" class="hasError">{{ renderError }}</div>
</div> </div>
@@ -122,16 +122,16 @@ export default {
}, },
downloadTemplateTitle() { downloadTemplateTitle() {
if (this.importOption === 'create') { if (this.importOption === 'create') {
return this.$t('common.imExport.downloadImportTemplateMsg') return this.$t('DownloadImportTemplateMsg')
} else { } else {
return this.$t('common.imExport.downloadUpdateTemplateMsg') return this.$t('DownloadUpdateTemplateMsg')
} }
}, },
importTitle() { importTitle() {
if (this.importOption === 'create') { if (this.importOption === 'create') {
return this.$t('common.Import') + this.$t('common.Create') return this.$t('Import') + this.$t('Create')
} else { } else {
return this.$t('common.Import') + this.$t('common.Update') return this.$t('Import') + this.$t('Update')
} }
} }
}, },

View File

@@ -4,18 +4,18 @@
<el-col :md="8" :sm="24"> <el-col :md="8" :sm="24">
<div class="tableFilter"> <div class="tableFilter">
<el-radio-group v-model="importStatusFilter" size="small"> <el-radio-group v-model="importStatusFilter" size="small">
<el-radio-button label="all">{{ $t('common.Total') }}</el-radio-button> <el-radio-button label="all">{{ $t('Total') }}</el-radio-button>
<el-radio-button label="ok">{{ $t('common.Success') }}</el-radio-button> <el-radio-button label="ok">{{ $t('Success') }}</el-radio-button>
<el-radio-button label="error">{{ $t('common.Failed') }}</el-radio-button> <el-radio-button label="error">{{ $t('Failed') }}</el-radio-button>
<el-radio-button label="pending">{{ $t('common.Pending') }}</el-radio-button> <el-radio-button label="pending">{{ $t('Pending') }}</el-radio-button>
</el-radio-group> </el-radio-group>
</div> </div>
</el-col> </el-col>
<el-col :md="8" :sm="24" style="text-align: center"> <el-col :md="8" :sm="24" style="text-align: center">
<span class="summary-item summary-total"> {{ $t('common.Total') }}: {{ totalCount }}</span> <span class="summary-item summary-total"> {{ $t('Total') }}: {{ totalCount }}</span>
<span class="summary-item summary-success"> {{ $t('common.Success') }}: {{ successCount }}</span> <span class="summary-item summary-success"> {{ $t('Success') }}: {{ successCount }}</span>
<span class="summary-item summary-failed"> {{ $t('common.Failed') }}: {{ failedCount }}</span> <span class="summary-item summary-failed"> {{ $t('Failed') }}: {{ failedCount }}</span>
<span class="summary-item summary-pending"> {{ $t('common.Pending') }}: {{ pendingCount }}</span> <span class="summary-item summary-pending"> {{ $t('Pending') }}: {{ pendingCount }}</span>
</el-col> </el-col>
</el-row> </el-row>
<div class="row"> <div class="row">
@@ -24,7 +24,7 @@
<DataTable v-if="tableGenDone" id="importTable" ref="dataTable" :config="tableConfig" class="importTable" /> <DataTable v-if="tableGenDone" id="importTable" ref="dataTable" :config="tableConfig" class="importTable" />
<div class="row" style="padding-top: 20px"> <div class="row" style="padding-top: 20px">
<div style="float: right"> <div style="float: right">
<el-button size="small" @click="performCancel">{{ $t('common.Cancel') }}</el-button> <el-button size="small" @click="performCancel">{{ $t('Cancel') }}</el-button>
<el-button size="small" type="primary" @click="performImportAction">{{ importActionTitle }}</el-button> <el-button size="small" type="primary" @click="performImportAction">{{ importActionTitle }}</el-button>
</div> </div>
</div> </div>
@@ -81,10 +81,10 @@ export default {
hasImport: false, hasImport: false,
hasContinueButton: false, hasContinueButton: false,
importActions: { importActions: {
import: this.$t('common.Import'), import: this.$t('Import'),
continue: this.$t('common.Continue'), continue: this.$t('Continue'),
stop: this.$t('common.Stop'), stop: this.$t('Stop'),
finished: this.$t('common.Finished') finished: this.$t('Finished')
} }
} }
}, },
@@ -173,7 +173,7 @@ export default {
const vm = this const vm = this
const columns = [{ const columns = [{
prop: '@status', prop: '@status',
label: vm.$t('common.Status'), label: vm.$t('Status'),
width: '80px', width: '80px',
align: 'center', align: 'center',
formatter: StatusFormatter, formatter: StatusFormatter,
@@ -191,9 +191,9 @@ export default {
}, },
getTip(val) { getTip(val) {
if (val === 'ok') { if (val === 'ok') {
return vm.$t('common.Success') return vm.$t('Success')
} else if (val === 'pending') { } else if (val === 'pending') {
return vm.$t('common.Pending') return vm.$t('Pending')
} else if (val && val.name === 'error') { } else if (val && val.name === 'error') {
return val.error return val.error
} }
@@ -366,7 +366,7 @@ export default {
this.importTaskStatus = 'done' this.importTaskStatus = 'done'
} }
if (this.failedCount > 0) { if (this.failedCount > 0) {
this.$message.error(this.$tc('common.imExport.hasImportErrorItemMsg') + '') this.$message.error(this.$tc('HasImportErrorItemMsg') + '')
} }
}, },
async performUpdateObject(item) { async performUpdateObject(item) {

View File

@@ -7,7 +7,6 @@
@click="showSearchSelect" @click="showSearchSelect"
> >
<svg-icon icon-class="tag" /> <svg-icon icon-class="tag" />
<span>{{ $t('common.Label') }}</span>
</el-button> </el-button>
<el-cascader <el-cascader
v-else v-else
@@ -45,7 +44,7 @@ export default {
}, },
labelOptions: [], labelOptions: [],
labelValue: [], labelValue: [],
placeholder: this.$t('labels.SelectLabelFilter') placeholder: this.$t('SelectLabelFilter')
} }
}, },
watch: { watch: {
@@ -92,18 +91,22 @@ export default {
this.setSearchFocus() this.setSearchFocus()
}, },
handleCascaderVisibleChange(visible) { handleCascaderVisibleChange(visible) {
const input = this.$refs.labelCascader.$el
.getElementsByClassName('el-input--suffix')[0]
.querySelector('input')
if (visible) { if (visible) {
setTimeout(() => { setTimeout(() => {
this.$refs.labelCascader.updateStyle() this.$refs.labelCascader.updateStyle()
input.style.height = '30px'
},) },)
return return
} else { } else {
const input = this.$refs.labelCascader.$el.getElementsByClassName('el-input--suffix')[0].querySelector('input') input.style.height = '30px'
input.style.height = '34px'
} }
if (this.labelValue.length === 0) { if (this.labelValue.length === 0) {
this.showLabelSearch = false this.showLabelSearch = false
} }
this.$emit('showLabelSearch', this.showLabelSearch)
}, },
getLabelOptions() { getLabelOptions() {
if (this.labelOptions.length > 0) { if (this.labelOptions.length > 0) {
@@ -114,7 +117,7 @@ export default {
const groupedLabelOptions = _.groupBy(data, 'name') const groupedLabelOptions = _.groupBy(data, 'name')
const labelOptions = [] const labelOptions = []
for (const [key, labels] of Object.entries(groupedLabelOptions)) { for (const [key, labels] of Object.entries(groupedLabelOptions)) {
const all = { value: '*', label: this.$t('common.All') } const all = { value: '*', label: this.$t('All') }
const children = _.sortBy(labels, 'value').map(label => ({ const children = _.sortBy(labels, 'value').map(label => ({
value: label.value, value: label.value,
label: label.value label: label.value
@@ -151,7 +154,7 @@ export default {
} }
.label-button { .label-button {
padding: 10px 13px 10px 12px; //padding: 10px 13px 10px 12px;
} }
.label-select { .label-select {
@@ -159,11 +162,12 @@ export default {
.label-cascader { .label-cascader {
width: 300px; width: 300px;
>>> .el-input--suffix.el-input { height: 30px;
input {
height: 34px; >>> .el-input input {
} height: 30px;
} }
>>> .el-input__inner { >>> .el-input__inner {
font-size: 13px; font-size: 13px;
} }

View File

@@ -27,6 +27,7 @@ export default {
createRoute: { createRoute: {
type: [String, Object, Function], type: [String, Object, Function],
default() { default() {
console.log('This: ', this.$route)
return this.$route.name?.replace('List', 'Create') return this.$route.name?.replace('List', 'Create')
} }
}, },
@@ -83,7 +84,7 @@ export default {
}, },
createTitle: { createTitle: {
type: String, type: String,
default: () => i18n.t('common.Create') default: () => i18n.t('Create')
} }
}, },
data() { data() {
@@ -91,7 +92,7 @@ export default {
return { return {
defaultMoreActions: [ defaultMoreActions: [
{ {
title: this.$t('common.BatchDelete'), title: this.$t('DeleteSelected'),
name: 'actionDeleteSelected', name: 'actionDeleteSelected',
has: this.hasBulkDelete, has: this.hasBulkDelete,
icon: 'fa fa-trash-o', icon: 'fa fa-trash-o',
@@ -101,10 +102,10 @@ export default {
callback: this.defaultBulkDeleteCallback callback: this.defaultBulkDeleteCallback
}, },
{ {
title: this.$t('common.BatchUpdate'), title: this.$t('UpdateSelected'),
name: 'actionUpdateSelected', name: 'actionUpdateSelected',
has: this.hasBulkUpdate, has: this.hasBulkUpdate,
fa: 'batch-update', icon: 'batch-update',
can: function({ selectedRows }) { can: function({ selectedRows }) {
let canBulkUpdate = vm.canBulkUpdate let canBulkUpdate = vm.canBulkUpdate
if (typeof canBulkUpdate === 'function') { if (typeof canBulkUpdate === 'function') {
@@ -114,36 +115,22 @@ export default {
}, },
callback: this.handleBulkUpdate callback: this.handleBulkUpdate
} }
] ],
} defaultActions: [
},
computed: {
defaultActions() {
const defaultActions = [
{ {
name: 'actionCreate', name: 'actionCreate',
title: this.createTitle, title: this.createTitle,
type: 'primary', type: 'primary',
has: this.hasCreate && !this.moreCreates, has: this.hasCreate && !this.moreCreates,
can: this.canCreate, can: this.canCreate,
icon: 'plus',
callback: this.onCreate || this.handleCreate callback: this.onCreate || this.handleCreate
} }
] ]
if (this.moreCreates) { }
const defaultMoreCreate = { },
name: 'actionMoreCreate', computed: {
title: this.createTitle,
type: 'primary',
has: true,
can: this.canCreate,
dropdown: [],
callback: this.onCreate || this.handleCreate
}
const createCreateAction = Object.assign(defaultMoreCreate, this.moreCreates)
defaultActions.push(createCreateAction)
}
return defaultActions
},
iActions() { iActions() {
return [...this.actions, this.moreAction] return [...this.actions, this.moreAction]
}, },
@@ -161,7 +148,7 @@ export default {
const invariantActions = [ const invariantActions = [
{ {
name: 'batch', name: 'batch',
title: this.$t('common.BatchProcessing', { 'Number': this.selectedRows.length }), title: this.$t('BatchProcessing', { 'Number': this.selectedRows.length }),
divided: true, divided: true,
has: function({ selectedRows }) { has: function({ selectedRows }) {
return selectedRows.length > 0 return selectedRows.length > 0
@@ -177,7 +164,7 @@ export default {
}) })
return { return {
name: 'moreActions', name: 'moreActions',
title: this.moreActionsTitle || this.$t('common.MoreActions'), title: this.moreActionsTitle || this.$t('MoreActions'),
dropdown: dropdown dropdown: dropdown
} }
}, },
@@ -187,6 +174,11 @@ export default {
}, },
methods: { methods: {
handleCreate() { handleCreate() {
// this.$router.push({
// name: 'UserCreate'
// })
// return
console.log('This: ', this.$router)
let route let route
if (typeof this.createRoute === 'string') { if (typeof this.createRoute === 'string') {
route = { name: this.createRoute } route = { name: this.createRoute }
@@ -196,7 +188,7 @@ export default {
} else if (typeof this.createRoute === 'object') { } else if (typeof this.createRoute === 'object') {
route = this.createRoute route = this.createRoute
} }
this.$log.debug('handle create') this.$log.debug('handle create: ', route, this.createRoute)
if (this.createInNewPage) { if (this.createInNewPage) {
const { href } = this.$router.resolve(route) const { href } = this.$router.resolve(route)
window.open(href, '_blank') window.open(href, '_blank')
@@ -205,8 +197,8 @@ export default {
} }
}, },
defaultBulkDeleteCallback({ selectedRows, reloadTable }) { defaultBulkDeleteCallback({ selectedRows, reloadTable }) {
const msg = this.$t('common.deleteWarningMsg') + ' ' + selectedRows.length + ' ' + this.$t('common.rows') + ' ?' const msg = this.$t('DeleteWarningMsg') + ' ' + selectedRows.length + ' ' + this.$t('Rows') + ' ?'
const title = this.$tc('common.Info') const title = this.$tc('Info')
const performDelete = this.performBulkDelete || this.defaultPerformBulkDelete const performDelete = this.performBulkDelete || this.defaultPerformBulkDelete
this.$alert(msg, title, { this.$alert(msg, title, {
type: 'warning', type: 'warning',
@@ -219,9 +211,9 @@ export default {
await performDelete(selectedRows) await performDelete(selectedRows)
done() done()
reloadTable() reloadTable()
this.$message.success(this.$tc('common.bulkDeleteSuccessMsg')) this.$message.success(this.$tc('BulkDeleteSuccessMsg'))
} catch (error) { } catch (error) {
this.$message.error(this.$tc('common.bulkDeleteErrorMsg') + error.message) this.$message.error(this.$tc('BulkDeleteErrorMsg') + error.message)
} finally { } finally {
instance.confirmButtonLoading = false instance.confirmButtonLoading = false
} }

View File

@@ -94,10 +94,10 @@ export default {
data() { data() {
return { return {
defaultRightSideActions: [ defaultRightSideActions: [
{ name: 'actionColumnSetting', fa: 'system-setting', tip: this.$t('common.CustomCol'), has: this.hasColumnSetting, callback: this.handleTableSettingClick.bind(this) }, { name: 'actionSetting', icon: 'system-setting', tip: this.$t('TableSetting'), has: this.hasColumnSetting, callback: this.handleTableSettingClick.bind(this) },
{ name: 'actionImport', fa: 'upload', tip: this.$t('common.Import'), has: this.hasImport, callback: this.handleImportClick.bind(this) }, { name: 'actionImport', icon: 'upload', tip: this.$t('Import'), has: this.hasImport, callback: this.handleImportClick.bind(this) },
{ name: 'actionExport', fa: 'download', tip: this.$t('common.Export'), has: this.hasExport, callback: this.handleExportClick.bind(this) }, { name: 'actionExport', icon: 'download', tip: this.$t('Export'), has: this.hasExport, callback: this.handleExportClick.bind(this) },
{ name: 'actionRefresh', fa: 'refresh', tip: this.$t('common.Refresh'), has: this.hasRefresh, callback: this.handleRefreshClick.bind(this) } { name: 'actionRefresh', icon: 'refresh', tip: this.$t('Refresh'), has: this.hasRefresh, callback: this.handleRefreshClick.bind(this) }
], ],
dialogExportVisible: false dialogExportVisible: false
} }
@@ -146,15 +146,12 @@ export default {
} }
.right-side-item { .right-side-item {
padding-top: 4px;
} }
.right-side-actions >>> .el-button { .right-side-actions >>> .el-button {
border: none; border: none;
padding: 5px; padding: 5px;
font-size: 14px; font-size: 14px;
width: 26px;
height: 26px;
color: #888; color: #888;
background-color: transparent; background-color: transparent;
} }
@@ -178,6 +175,8 @@ export default {
padding-left: 10px; padding-left: 10px;
align-items: center; align-items: center;
justify-content:center; justify-content:center;
height: 30px;
line-height: 30px;
} }
.table-action-right-side { .table-action-right-side {

View File

@@ -144,119 +144,138 @@ export default {
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
$headerHeight: 30px;
$innerHeight: 28px;
.table-header { .table-header {
/*display: flex;*/ >>> {
/*flex-direction: row;*/ .el-cascader {
/*justify-content: space-between;*/ line-height: $innerHeight;
.el-input.el-input--suffix {
.el-input__inner {
height: calc(#{$headerHeight} - 3px);
}
}
}
.el-input__inner {
height: $innerHeight;
}
.el-button.el-button--primary {
border-color: #DCDFE6;
}
.el-input__suffix {
height: $innerHeight;
line-height: $innerHeight;
}
.el-input__icon {
line-height: $innerHeight;
}
.el-range-editor--small {
.el-input__icon, .el-range-separator {
line-height: 22px;
}
}
}
} }
.right-side-item { .right-side-item {
} }
.right-side-actions >>> .el-button {
border: none;
padding: 5px;
font-size: 14px;
width: 26px;
height: 26px;
color: #888;
background-color: transparent;
}
.right-side-actions >>> .fa {
height: 16px;
width: 16px;
}
.right-side-actions >>> .el-button:hover {
background-color: rgb(0, 0, 0, 0.05);
}
.action-search >>> .el-input__suffix i {
font-weight: 500;
color: #888;
}
.action-search >>> .el-cascader {
line-height: 32px !important;
}
.right-side-actions { .right-side-actions {
display: flex; display: flex;
padding-left: 10px; padding-left: 10px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} height: $headerHeight;
.table-action-right-side { >>> .fa {
display: flex; height: 16px;
justify-content: center; width: 16px;
} }
.export-item { >>> .el-button:hover {
display: block; background-color: rgb(0, 0, 0, 0.05);
padding: 5px 20px;
}
.datepicker {
margin-left: 10px;
}
.table-header {
line-height: 32px;
}
.left-side {
float: left;
display: block;
&>>> .action-item.el-dropdown {
height: 33px;
&> .el-button {
height: 100%;
}
} }
} }
.right-side { .action-search >>> .el-input__suffix i {
float: right; font-weight: 500;
} color: #888;
}
.search { .action-search >>> .el-cascader {
display: flex; line-height: $innerHeight !important;
flex-direction: row; }
}
.mobile .search { .table-action-right-side {
display: inherit; display: flex;
} justify-content: center;
}
.mobile .search .datepicker { .export-item {
margin-left: 0; display: block;
} padding: 5px 20px;
}
.search.left { .datepicker {
float: left; margin-left: 10px;
padding: 0 !important; }
}
.search.right { .left-side {
float: right; float: left;
} display: block;
&>>> .action-item.el-dropdown {
&> .el-button {
height: 100%;
}
}
>>> .el-button {
}
}
.mobile .search.right { .right-side {
float: none; float: right;
} }
.mobile .search.right .action-search { .search {
width: 100%; display: flex;
} flex-direction: row;
}
.mobile .right-side { .mobile .search {
padding-top: 5px; display: inherit;
} }
.filter-field.right-side-item.action-search { .mobile .search .datepicker {
height: 34px; margin-left: 0;
} }
.search.left {
float: left;
padding: 0 !important;
}
.search.right {
float: right;
}
.mobile .search.right {
float: none;
}
.mobile .search.right .action-search {
width: 100%;
}
.mobile .right-side {
padding-top: 5px;
}
.filter-field.right-side-item.action-search {
height: 30px;
}
</style> </style>

View File

@@ -222,27 +222,29 @@ export default {
.table-content { .table-content {
margin-top: 10px; margin-top: 10px;
& > > > .el-card__body { >>> {
padding: 0; .el-card__body {
} padding: 0;
}
& > > > .el-table__header thead > tr > th { .el-table__header thead > tr > th {
background-color: white; background-color: white;
} }
& > > > .el-table__row .cell { .el-table__row .cell {
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
& > > > .el-table__expanded-cell pre { .el-table__expanded-cell pre {
max-height: 500px; max-height: 500px;
overflow-y: scroll; overflow-y: scroll;
} }
& > > > .el-button-ungroup .el-dropdown > .more-action { .el-button-ungroup .el-dropdown > .more-action {
height: 24.6px; //height: 24.6px;
}
} }
} }

View File

@@ -15,9 +15,9 @@
:label-content="item.labelContent" :label-content="item.labelContent"
:name="item.name" :name="item.name"
> >
<span slot="label"> <span slot="label" class="tab-container">
<i v-if="item.icon" :class="item.icon" class="fa " /> <i v-if="item.icon && !showText" :class="item.icon" class="tab-icon fa " />
{{ item.title }} <span v-if="showText" class="tab-text">{{ item.title }}</span>
<slot :tab="item.name" name="badge" /> <slot :tab="item.name" name="badge" />
</span> </span>
</el-tab-pane> </el-tab-pane>
@@ -67,7 +67,9 @@ export default {
return { return {
flag: false, flag: false,
componentKey: 1, componentKey: 1,
activeTreeSetting: {} activeTreeSetting: {},
showText: true,
keyMap: {}
} }
}, },
computed: { computed: {
@@ -99,10 +101,21 @@ export default {
async mounted() { async mounted() {
this.iActiveMenu = await this.getPropActiveTab() this.iActiveMenu = await this.getPropActiveTab()
this.$eventBus.$on('treeComponentKey', () => { this.$eventBus.$on('treeComponentKey', () => {
this.componentKey += 1 this.componentKey += '1'
}) })
this.hiddenTextIfNeed()
}, },
methods: { methods: {
hiddenTextIfNeed() {
const vm = this
const hideOverflowingText = _.debounce(function() {
const tabs = document.querySelector('.tree-tab .el-tabs__nav-wrap.is-scrollable')
vm.showText = !tabs
}, 800)
hideOverflowingText()
window.addEventListener('resize', hideOverflowingText)
},
hideRMenu() { hideRMenu() {
this.$refs.AutoDataZTree?.hideRMenu() this.$refs.AutoDataZTree?.hideRMenu()
}, },
@@ -119,7 +132,10 @@ export default {
this.$emit('urlChange', url) this.$emit('urlChange', url)
}, },
handleTabClick(tab) { handleTabClick(tab) {
this.componentKey += 1 this.componentKey = this.keyMap[tab.name]
if (!this.componentKey) {
this.componentKey = this.$route.name + '_' + tab.name
}
this.$emit('tab-click', tab) this.$emit('tab-click', tab)
this.$emit('update:activeMenu', tab.name) this.$emit('update:activeMenu', tab.name)
this.$cookie.set(ACTIVE_TREE_TAB_KEY, tab.name, 1) this.$cookie.set(ACTIVE_TREE_TAB_KEY, tab.name, 1)
@@ -171,19 +187,14 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
>>> .ztree, >>> .data-z-tree {
>>> .ztree li,
>>> .ztree li ul,
.tree-tab {
}
>>> .ztree {
padding: 0; padding: 0;
} }
.page-submenu >>> .el-tabs__nav-wrap { .page-submenu >>> .el-tabs__nav-wrap {
position: static; position: static;
.el-tabs__item {
.el-tabs__item.is-active { padding-right: 0;
color: var(--menu-text-active); padding-left: 0;
} }
} }
.only-submenu { .only-submenu {
@@ -195,4 +206,9 @@ export default {
padding: 0 20px; padding: 0 20px;
} }
} }
>>> {
.ztree {
padding: 0;
}
}
</style> </style>

View File

@@ -5,6 +5,7 @@
:more-actions="moreActions" :more-actions="moreActions"
:more-actions-title="moreActionsTitle" :more-actions-title="moreActionsTitle"
:size="'mini'" :size="'mini'"
class="table-actions"
/> />
</template> </template>
@@ -51,13 +52,13 @@ const defaultCloneCallback = function({ row, col }) {
} }
const defaultDeleteCallback = function({ row, col, cellValue, reload }) { const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
let msg = this.$t('common.deleteWarningMsg') let msg = this.$t('DeleteWarningMsg')
const name = row.name || row.hostname const name = row.name || row.hostname
if (name) { if (name) {
msg += ` "${name}" ` msg += ` "${name}" `
} }
msg += ' ?' msg += ' ?'
const title = this.$t('common.Info') const title = this.$t('Info')
const performDelete = this.colActions.performDelete const performDelete = this.colActions.performDelete
this.$alert(msg, title, { this.$alert(msg, title, {
type: 'warning', type: 'warning',
@@ -70,7 +71,7 @@ const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
await performDelete.bind(this)({ row: row, col: col }) await performDelete.bind(this)({ row: row, col: col })
done() done()
reload() reload()
this.$message.success(this.$tc('common.deleteSuccessMsg')) this.$message.success(this.$tc('DeleteSuccessMsg'))
} finally { } finally {
instance.confirmButtonLoading = false instance.confirmButtonLoading = false
} }
@@ -95,8 +96,8 @@ export default {
canDelete: true, canDelete: true,
hasClone: true, hasClone: true,
canClone: true, canClone: true,
updateRoute: this.$route.name.replace('List', 'Update'), updateRoute: 'UserUpdate',
cloneRoute: this.$route.name.replace('List', 'Create'), cloneRoute: 'UserCreate',
performDelete: defaultPerformDelete, performDelete: defaultPerformDelete,
onUpdate: defaultUpdateCallback, onUpdate: defaultUpdateCallback,
onDelete: defaultDeleteCallback, onDelete: defaultDeleteCallback,
@@ -111,7 +112,7 @@ export default {
const defaultActions = [ const defaultActions = [
{ {
name: 'update', name: 'update',
title: this.$t('common.Update'), title: this.$t('Edit'),
type: 'primary', type: 'primary',
has: colActions.hasUpdate, has: colActions.hasUpdate,
can: colActions.canUpdate, can: colActions.canUpdate,
@@ -120,7 +121,7 @@ export default {
}, },
{ {
name: 'delete', name: 'delete',
title: this.$t('common.Delete'), title: this.$t('Delete'),
type: 'danger', type: 'danger',
has: colActions.hasDelete, has: colActions.hasDelete,
can: colActions.canDelete, can: colActions.canDelete,
@@ -129,7 +130,7 @@ export default {
}, },
{ {
name: 'clone', name: 'clone',
title: this.$t('common.Clone'), title: this.$t('Clone'),
type: 'info', type: 'info',
has: colActions.hasClone, has: colActions.hasClone,
can: colActions.canClone, can: colActions.canClone,
@@ -141,7 +142,8 @@ export default {
colActions: colActions, colActions: colActions,
defaultActions: defaultActions, defaultActions: defaultActions,
extraActions: colActions.extraActions, extraActions: colActions.extraActions,
moreActionsTitle: colActions.moreActionsTitle || this.$t('common.More') moreActionsTitle: ''
// moreActionsTitle: colActions.moreActionsTitle || null
} }
}, },
computed: { computed: {
@@ -152,7 +154,7 @@ export default {
v.has = this.cleanBoolean(v, 'has', true) v.has = this.cleanBoolean(v, 'has', true)
v.can = this.cleanBoolean(v, 'can', true) v.can = this.cleanBoolean(v, 'can', true)
v.callback = this.cleanCallback(v, 'callback') v.callback = this.cleanCallback(v, 'callback')
v.fa = this.cleanValue(v, 'fa') v.icon = this.cleanValue(v, 'icon')
v.order = v.order || 100 v.order = v.order || 100
v.tip = this.cleanValue(v, 'tip') v.tip = this.cleanValue(v, 'tip')
v.title = this.cleanValue(v, 'title') v.title = this.cleanValue(v, 'title')
@@ -216,5 +218,10 @@ export default {
</script> </script>
<style scoped> <style scoped>
.table-actions >>> {
.el-icon-arrow-down {
display: none;
}
}
</style> </style>

View File

@@ -11,7 +11,7 @@
@show="getAsyncItems" @show="getAsyncItems"
> >
<div class="detail-content"> <div class="detail-content">
<div v-for="item of items" :key="getKey(item)" class="detail-item"> <div v-for="[index, item] of Object.entries(items)" :key="getKey(item, index)" class="detail-item">
<span class="detail-item-name">{{ item }}</span> <span class="detail-item-name">{{ item }}</span>
</div> </div>
</div> </div>
@@ -62,7 +62,7 @@ export default {
}, },
items() { items() {
if (this.formatterArgs.async && !this.asyncGetDone) { if (this.formatterArgs.async && !this.asyncGetDone) {
return [this.$t('common.tree.Loading') + '...'] return [this.$t('Loading') + '...']
} }
const getItem = this.formatterArgs.getItem || (item => item.name) const getItem = this.formatterArgs.getItem || (item => item.name)
let data = this.data.map(item => getItem(item)) || [] let data = this.data.map(item => getItem(item)) || []
@@ -77,9 +77,8 @@ export default {
this.amount = this.formatterArgs.async ? this.cellValue : (this.cellValue || []).length this.amount = this.formatterArgs.async ? this.cellValue : (this.cellValue || []).length
}, },
methods: { methods: {
getKey(item) { getKey(item, index) {
const id = Math.random().toString(36).substring(16) return index + item
return id + item
}, },
getDefaultUrl() { getDefaultUrl() {
const url = new URL(this.url, location.origin) const url = new URL(this.url, location.origin)

View File

@@ -31,8 +31,8 @@ export default {
false: 'text-danger' false: 'text-danger'
}, },
textChoices: { textChoices: {
true: this.$t('common.Yes'), true: this.$t('Yes'),
false: this.$t('common.No') false: this.$t('No')
}, },
getKey({ row, cellValue }) { getKey({ row, cellValue }) {
return (cellValue && typeof cellValue === 'object') ? cellValue.value : cellValue return (cellValue && typeof cellValue === 'object') ? cellValue.value : cellValue

View File

@@ -2,6 +2,7 @@
<el-button <el-button
ref="deleteButton" ref="deleteButton"
:disabled="iDisabled" :disabled="iDisabled"
:title="$t('Remove')"
size="mini" size="mini"
type="danger" type="danger"
@click="onDelete(col, row, cellValue, reload)" @click="onDelete(col, row, cellValue, reload)"
@@ -35,10 +36,10 @@ export default {
defaultOnDelete(col, row, cellValue, reload) { defaultOnDelete(col, row, cellValue, reload) {
const url = col.deleteUrl + cellValue const url = col.deleteUrl + cellValue
this.$axios.delete(url).then(res => { this.$axios.delete(url).then(res => {
this.$message.success(this.$tc('common.deleteSuccessMsg')) this.$message.success(this.$tc('DeleteSuccessMsg'))
reload() reload()
}).catch(error => { }).catch(error => {
this.$message.error(this.$tc('common.deleteErrorMsg') + ' ' + error) this.$message.error(this.$tc('DeleteErrorMsg') + ' ' + error)
}) })
}, },
onDelete(col, row, cellValue, reload) { onDelete(col, row, cellValue, reload) {

View File

@@ -25,7 +25,7 @@ export default {
type: Object, type: Object,
default() { default() {
return { return {
route: this.$route.name.replace('List', 'Detail'), route: 'abc',
getRoute: null, getRoute: null,
routeQuery: null, routeQuery: null,
can: true, can: true,

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