diff --git a/src/components/Apps/AssetSelect/dialog.vue b/src/components/Apps/AssetSelect/dialog.vue index f2b27afe0..1e2af1143 100644 --- a/src/components/Apps/AssetSelect/dialog.vue +++ b/src/components/Apps/AssetSelect/dialog.vue @@ -17,6 +17,7 @@ :table-config="tableConfig" :tree-url="`${baseNodeUrl}children/tree/`" :url="baseUrl" + :tree-setting="treeSetting" class="tree-table" v-bind="$attrs" /> @@ -52,6 +53,10 @@ export default { disabled: { type: [Boolean, Function], default: false + }, + treeSetting: { + type: Object, + default: () => ({}) } }, data() { diff --git a/src/components/Apps/AssetSelect/index.vue b/src/components/Apps/AssetSelect/index.vue index 52f638248..780f55a75 100644 --- a/src/components/Apps/AssetSelect/index.vue +++ b/src/components/Apps/AssetSelect/index.vue @@ -13,6 +13,7 @@ ref="dialog" :base-node-url="baseNodeUrl" :base-url="baseUrl" + :tree-setting="treeSetting" :tree-url-query="treeUrlQuery" :value="value" :visible.sync="dialogVisible" @@ -48,6 +49,10 @@ export default { value: { type: Array, default: () => [] + }, + treeSetting: { + type: Object, + default: () => ({}) } }, data() { diff --git a/src/components/Apps/AssetTreeTable/index.vue b/src/components/Apps/AssetTreeTable/index.vue index 4ba02a04c..5164802a5 100644 --- a/src/components/Apps/AssetTreeTable/index.vue +++ b/src/components/Apps/AssetTreeTable/index.vue @@ -60,6 +60,7 @@ export default { const showAssets = this.treeSetting?.showAssets || this.showAssets const treeUrlQuery = this.setTreeUrlQuery() const assetTreeUrl = `${this.treeUrl}?assets=${showAssets ? '1' : '0'}&${treeUrlQuery}` + const vm = this return { treeTabConfig: { @@ -81,7 +82,13 @@ export default { nodeUrl: this.nodeUrl, treeUrl: assetTreeUrl, callback: { - onSelected: (event, treeNode) => this.getAssetsUrl(treeNode) + onSelected: (event, treeNode) => this.getAssetsUrl(treeNode), + beforeRefresh: () => { + const query = { ...this.$route.query, node_id: '', asset_id: '' } + setTimeout(() => { + vm.$router.replace({ query: query }) + }, 100) + } }, ...this.treeSetting } diff --git a/src/components/Form/AutoDataForm/utils.js b/src/components/Form/AutoDataForm/utils.js index 0a3311edb..346e32eee 100644 --- a/src/components/Form/AutoDataForm/utils.js +++ b/src/components/Form/AutoDataForm/utils.js @@ -5,9 +5,9 @@ import Switcher from '@/components/Form/FormFields/Switcher.vue' import rules from '@/components/Form/DataForm/rules' import BasicTree from '@/components/Form/FormFields/BasicTree.vue' import JsonEditor from '@/components/Form/FormFields/JsonEditor.vue' -import TransferSelect from '@/components/Form/FormFields/TransferSelect.vue' import { assignIfNot } from '@/utils/common' import TagInput from '@/components/Form/FormFields/TagInput.vue' +import TransferSelect from '@/components/Form/FormFields/TransferSelect.vue' export class FormFieldGenerator { constructor(emit) { @@ -45,7 +45,7 @@ export class FormFieldGenerator { break case 'field': type = '' - field.component = TransferSelect + field.component = ObjectSelect2 if (fieldRemoteMeta.required) { field.el.clearable = false } @@ -76,7 +76,7 @@ export class FormFieldGenerator { field.component = ObjectSelect2 break case 'm2m_related_field': - field.component = TransferSelect + field.component = ObjectSelect2 field.el.label = field.label break case 'nested object': @@ -134,6 +134,9 @@ export class FormFieldGenerator { case 'comment': field.el.type = 'textarea' break + case 'users': + field.component = TransferSelect + field.el.label = field.label } return field } diff --git a/src/components/Form/FormFields/WeekCronSelect.vue b/src/components/Form/FormFields/WeekCronSelect.vue index 92becf968..e08efb2db 100644 --- a/src/components/Form/FormFields/WeekCronSelect.vue +++ b/src/components/Form/FormFields/WeekCronSelect.vue @@ -204,7 +204,12 @@ export default { }, formatWeektime(col) { const timeStamp = 1542384000000 // '2018-11-17 00:00:00' - const beginStamp = timeStamp + col * 1800000 // col * 30 * 60 * 1000 + const timezone = 8 + const offsetGMT = new Date().getTimezoneOffset() // 本地时间和格林威治的时间差,单位为分钟 + const nowDate = new Date(timeStamp).getTime() + const targetStamp = new Date(nowDate + offsetGMT * 60 * 1000 + timezone * 60 * 60 * 1000).getTime() + + const beginStamp = targetStamp + col * 1800000 // col * 30 * 60 * 1000 const endStamp = beginStamp + 1800000 const begin = this.formatDate(new Date(beginStamp), 'hh:mm') diff --git a/src/components/Table/AutoDataSearch/index.vue b/src/components/Table/AutoDataSearch/index.vue index 22e686211..b4adcae91 100644 --- a/src/components/Table/AutoDataSearch/index.vue +++ b/src/components/Table/AutoDataSearch/index.vue @@ -3,7 +3,7 @@ - + @@ -68,6 +68,9 @@ export default { }, methods: { handleTagSearch(tags) { + if (_.isEqual(tags, this.tags)) { + return + } this.tags = tags if (tags.length === 0) { this.manualSearch = false diff --git a/src/components/Table/ListTable/TableAction/LeftSide.vue b/src/components/Table/ListTable/TableAction/LeftSide.vue index 0b86f4d4c..48c48d618 100644 --- a/src/components/Table/ListTable/TableAction/LeftSide.vue +++ b/src/components/Table/ListTable/TableAction/LeftSide.vue @@ -104,7 +104,7 @@ export default { title: this.$t('common.BatchUpdate'), name: 'actionUpdateSelected', has: this.hasBulkUpdate, - icon: 'fa fa-refresh', + fa: 'batch-update', can: function({ selectedRows }) { let canBulkUpdate = vm.canBulkUpdate if (typeof canBulkUpdate === 'function') { diff --git a/src/components/Table/ListTable/index.vue b/src/components/Table/ListTable/index.vue index 125203418..2696dd508 100644 --- a/src/components/Table/ListTable/index.vue +++ b/src/components/Table/ListTable/index.vue @@ -173,12 +173,14 @@ export default { this.dataTable.getList() }, search(attrs) { + this.$log.debug('ListTable: search table', attrs) this.$emit('TagSearch', attrs) - return this.dataTable?.search(attrs, true) + this.$refs.dataTable?.$refs.dataTable?.search(attrs, true) }, filter(attrs) { this.$emit('TagFilter', attrs) - this.$refs.dataTable.$refs.dataTable.search(attrs, true) + this.$log.debug('ListTable: found filter change', attrs) + this.search(attrs) }, hasActionPerm(action) { const permRequired = this.permissions[action] diff --git a/src/components/Table/TagSearch/index.vue b/src/components/Table/TagSearch/index.vue index a5ff67bff..9da5bcc5c 100644 --- a/src/components/Table/TagSearch/index.vue +++ b/src/components/Table/TagSearch/index.vue @@ -10,14 +10,14 @@ {{ v.label + ':' }} {{ v.valueLabel }} @@ -27,14 +27,14 @@ @@ -122,6 +122,12 @@ export default { }, deep: true }, + filterTags: { + handler() { + this.$emit('tag-search', this.filterMaps) + }, + deep: true + }, filterValue(newValue, oldValue) { if (newValue === '' && oldValue !== '') { this.emptyCount = 1 @@ -210,11 +216,6 @@ export default { ...asFilterTags, ...routeFilter } - if (Object.keys(this.filterTags).length > 0) { - setTimeout(() => { - return this.$emit('tagSearch', this.filterMaps) - }, 400) - } }, getValueLabel(key, value) { for (const field of this.options) { @@ -252,7 +253,7 @@ export default { if (this.getUrlQuery) { this.checkUrlFields(evt) } - this.$emit('tagSearch', this.filterMaps) + // this.$emit('tagSearch', this.filterMaps) return true }, handleDelete() { @@ -284,7 +285,7 @@ export default { valueLabel: this.valueLabel } this.$set(this.filterTags, this.filterKey, tag) - this.$emit('tagSearch', this.filterMaps) + // this.$emit('tagSearch', this.filterMaps) // 修改查询参数时改变url中保存的参数 if (this.getUrlQuery) { diff --git a/src/components/Tree/DataZTree/components/ZTree/index.vue b/src/components/Tree/DataZTree/components/ZTree/index.vue index dfaadc653..34665402d 100644 --- a/src/components/Tree/DataZTree/components/ZTree/index.vue +++ b/src/components/Tree/DataZTree/components/ZTree/index.vue @@ -167,6 +167,9 @@ export default { }, async refresh() { this.treeSearchValue = '' + if (this.treeSetting?.callback?.beforeRefresh) { + this.treeSetting.callback.beforeRefresh() + } if (this.treeSetting?.callback?.refresh) { await this.treeSetting.callback.refresh() } diff --git a/src/i18n/langs/en.json b/src/i18n/langs/en.json index 507ba31d8..684f73afb 100644 --- a/src/i18n/langs/en.json +++ b/src/i18n/langs/en.json @@ -969,29 +969,30 @@ "LoginCount": "Login count", "LoginOverview": "Sessions overview", "LoginTo": "Login to", - "LoginUsers": "Active accounts", + "ActiveUsers": "Active users", "Monthly": "Monthly", "CurrentConnections": "Current connections", - "TodayFailedConnections": "Connections failed today", + "CurrentConnectionUsers": "Current connection users", + "TodayFailedConnections": "Number of failed sessions today", "OnlineSessions": "Online sessions", "OnlineUserDevices": "Online user devices", "RealTimeData": "Real-time data", - "UserAssetActivity": "Account/Asset activity", - "UserData": "Account data", + "UserAssetActivity": "User/asset activity status", + "UserData": "User data", "LoginUserToday": "Login account today", "AssetData": "Asset data", - "LoginAssetToday": "Active assets today", + "LoginAssetToday": "Active asset today", "WeekAdd": "New this week", "ProportionOfAssetTypes": "Proportion of asset types", "Proportion": "Proportion", - "LoginUserRanking": "Login account ranking", - "ActiveAssetRanking": "Login asset ranking", + "LoginUserRanking": "Session user ranking", + "ActiveAssetRanking": "Session asset Ranking", "AssetName": "Asset name", "NumberOfVisits": "Number of visits", "ranking": "Ranking", "Today": "Today", - "Last7Days": "Last 7 days", - "Last30Days": "Last30 days", + "Last7Days": "Last 7d", + "Last30Days": "Last 30d", "OnlineUsers": "Online accounts", "ConnectUsers": "Connect accounts", "Num": "Num", @@ -1009,13 +1010,14 @@ "BatchCommandNotExecuted": "Batch command not executed", "ExecuteFailedCommand": "Execute failed command", "SessionTrend": "Session trend", + "SessionConnectTrend": "Session connection trends", "UserLoginTrend": "Account login trend", "TimesWeekUnit": "times/week", "TopAssetsOfWeek": "Top assets of week", "TopUsersOfWeek": "Top user of week", "User": "User", "UserRatio": "User Ratio", - "UsersTotal": "Accounts total", + "UsersTotal": "User total", "Weekly": "Weekly", "TotalJobFailed": "Total job failed", "TotalJobRunning": "Total job running", @@ -2002,7 +2004,7 @@ "Account": "Account", "Existing": "Existing", "UserInformation": "User information", - "Authentication": "Account", + "Authentication": "Authentication", "Comment": "Comment", "ConfirmPassword": "Confirm password", "DateExpired": "Date expired", diff --git a/src/i18n/langs/ja.json b/src/i18n/langs/ja.json index ec640a813..28324286d 100644 --- a/src/i18n/langs/ja.json +++ b/src/i18n/langs/ja.json @@ -971,22 +971,23 @@ "LoginCount": "ログイン回数", "LoginOverview": "セッション統計", "LoginTo": "ログインしました", - "LoginUsers": "アクティブなアカウント", + "ActiveUsers": "アクティブユーザー", "Monthly": "月ごと", "CurrentConnections": "現在の接続数", - "TodayFailedConnections": "今日の接続に失敗しました", + "CurrentConnectionUsers": "現在のセッションユーザーの数", + "TodayFailedConnections": "今日の失敗したセッションの数", "OnlineSessions": "オンラインセッション", "RealTimeData": "リアルタイムデータ", - "UserAssetActivity": "アカウント/資産のアクティブ化", - "UserData": "アカウントデータ", - "LoginUserToday": "今日のログインアカウント数", + "UserAssetActivity": "ユーザー/アセットのアクティビティステータス", + "UserData": "ユーザーデータ", + "LoginUserToday": "今日のログインユーザー数", "AssetData": "資産データ", "LoginAssetToday": "今日のアクティブ資産数", "WeekAdd": "今週の追加", "ProportionOfAssetTypes": "資産タイプの割合", "Proportion": "占有率", - "LoginUserRanking": "ログインアカウントランキング", - "ActiveAssetRanking": "ログイン資産ランキング", + "LoginUserRanking": "セッションユーザーランキング", + "ActiveAssetRanking": "セッションアセットランキング", "AssetName": "資産名", "NumberOfVisits": "アクセス回数", "ranking": "ランキング", @@ -1010,13 +1011,14 @@ "BatchCommandNotExecuted": "未実行コマンド", "ExecuteFailedCommand": "失敗コマンドの実行", "SessionTrend": "セッショントレンド", + "SessionConnectTrend": "セッション接続の傾向", "UserLoginTrend": "アカウントログイントレンド", "TimesWeekUnit": "回/週", "TopAssetsOfWeek": "週間資産TOP10", "TopUsersOfWeek": "週ユーザーTOP10", "User": "ユーザー", "UserRatio": "ユーザー比率統計", - "UsersTotal": "アカウント総数", + "UsersTotal": "総ユーザー数", "Weekly": "週ごと" }, "ops": { diff --git a/src/i18n/langs/zh.json b/src/i18n/langs/zh.json index 8e40dd9c7..0742bfca1 100644 --- a/src/i18n/langs/zh.json +++ b/src/i18n/langs/zh.json @@ -960,22 +960,23 @@ "LoginCount": "登录次数", "LoginOverview": "会话统计", "LoginTo": "登录了", - "LoginUsers": "活跃账号", + "ActiveUsers": "活跃用户", "Monthly": "按月", "CurrentConnections": "当前连接数", - "TodayFailedConnections": "今日连接失败数", + "CurrentConnectionUsers": "当前会话用户数", + "TodayFailedConnections": "今日会话失败数", "OnlineSessions": "在线会话数", "RealTimeData": "实时数据", - "UserAssetActivity": "账号/资产活跃情况", - "UserData": "账号数据", - "LoginUserToday": "今日登录账号数", + "UserAssetActivity": "用户/资产活跃情况", + "UserData": "用户数据", + "LoginUserToday": "今日登录用户数", "AssetData": "资产数据", "LoginAssetToday": "今日活跃资产数", "WeekAdd": "本周新增", "ProportionOfAssetTypes": "资产类型占比", "Proportion": "占比", - "LoginUserRanking": "登录账号排名", - "ActiveAssetRanking": "登录资产排名", + "LoginUserRanking": "会话用户排名", + "ActiveAssetRanking": "会话资产排名", "AssetName": "资产名称", "NumberOfVisits": "访问次数", "ranking": "排名", @@ -999,13 +1000,13 @@ "BatchCommandNotExecuted": "未执行批量命令", "ExecuteFailedCommand": "执行失败命令", "SessionTrend": "会话趋势", - "UserLoginTrend": "账号登录趋势", + "SessionConnectTrend": "会话连接趋势", "TimesWeekUnit": "次/周", "TopAssetsOfWeek": "周资产 TOP10", "TopUsersOfWeek": "周用户 TOP10", "User": "用户", "UserRatio": "用户占比统计", - "UsersTotal": "账号总数", + "UsersTotal": "用户总数", "Weekly": "按周" }, "ops": { diff --git a/src/icons/svg/batch-update.svg b/src/icons/svg/batch-update.svg index 1e29b7fca..841d8a769 100644 --- a/src/icons/svg/batch-update.svg +++ b/src/icons/svg/batch-update.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/src/layout/components/Page/index.vue b/src/layout/components/Page/index.vue index 52858e407..61083de04 100644 --- a/src/layout/components/Page/index.vue +++ b/src/layout/components/Page/index.vue @@ -71,6 +71,11 @@ export default { height: calc(100vh - 50px); overflow-y: auto; overflow-x: hidden; + + .el-alert { + margin-top: -10px; + margin-bottom: 10px; + } } .go-back { diff --git a/src/utils/startup.js b/src/utils/startup.js index 8022861ba..6efe9e084 100644 --- a/src/utils/startup.js +++ b/src/utils/startup.js @@ -8,6 +8,8 @@ import orgUtil from '@/utils/org' import orgs from '@/api/orgs' import { getPropView, isViewHasOrgs } from '@/utils/jms' import request from '@/utils/request' +import i18n from '@/i18n/i18n' +import { MessageBox } from 'element-ui' const whiteList = ['/login', process.env.VUE_APP_LOGIN_PATH] // no redirect whitelist @@ -39,12 +41,30 @@ async function checkLogin({ to, from, next }) { return reject('No session mark found in cookie') } else if (sessionExpire === 'close') { let startTime = new Date().getTime() + this.newLoginHasOpen = false const intervalId = setInterval(() => { const endTime = new Date().getTime() const delta = (endTime - startTime) startTime = endTime Vue.$log.debug('Set session expire: ', delta) - if (!isRenewalExpired(120)) { + const currentTimeStamp = Math.floor(endTime / 1000) + const sessionExpireTimestamp = VueCookie.get('jms_session_expire_timestamp') + if (currentTimeStamp >= parseInt(sessionExpireTimestamp, 10)) { + if (!this.newLoginHasOpen) { + this.newLoginHasOpen = true + MessageBox.confirm( + i18n.t('auth.LoginRequiredMsg'), + i18n.t('common.Info'), + { + confirmButtonText: i18n.t('auth.ReLogin'), + cancelButtonText: i18n.t('common.Cancel'), + type: 'warning' + }).finally(() => { + window.location = '/core/auth/logout/' + clearInterval(intervalId) + }) + } + } else if (!isRenewalExpired(120)) { VueCookie.set('jms_session_expire', 'close', { expires: '2m' }) } else { clearInterval(intervalId) diff --git a/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretExecution/AccountChangeSecretExecutionList.vue b/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretExecution/AccountChangeSecretExecutionList.vue index 6c77af0a3..751ff554f 100644 --- a/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretExecution/AccountChangeSecretExecutionList.vue +++ b/src/views/accounts/AccountChangeSecret/AccountChangeSecretDetail/AccountChangeSecretExecution/AccountChangeSecretExecutionList.vue @@ -1,5 +1,5 @@