diff --git a/orion-visor-ui/src/api/statistics/asset-statistics.ts b/orion-visor-ui/src/api/statistics/asset-statistics.ts new file mode 100644 index 00000000..4a904af8 --- /dev/null +++ b/orion-visor-ui/src/api/statistics/asset-statistics.ts @@ -0,0 +1,26 @@ +import type { LineSingleChartData } from '@/types/global'; +import type { TerminalConnectLogQueryResponse } from '@/api/asset/terminal-connect-log'; +import type { ExecLogQueryResponse } from '@/api/exec/exec-log'; +import axios from 'axios'; + +/** + * 资产模块工作台响应 + */ +export interface AssetWorkplaceStatisticsResponse { + execJobCount: number; + todayTerminalConnectCount: number; + todayExecCommandCount: number; + weekTerminalConnectCount: number; + weekExecCommandCount: number; + execCommandChart: LineSingleChartData; + terminalConnectChart: LineSingleChartData; + terminalConnectList: Array; + execLogList: Array; +} + +/** + * 查询资产模块工作台统计信息 + */ +export function getAssetWorkplaceStatisticsData() { + return axios.get('/asset/statistics/get-workplace'); +} diff --git a/orion-visor-ui/src/api/statistics/infra-statistics.ts b/orion-visor-ui/src/api/statistics/infra-statistics.ts new file mode 100644 index 00000000..5954f08f --- /dev/null +++ b/orion-visor-ui/src/api/statistics/infra-statistics.ts @@ -0,0 +1,24 @@ +import type { LineSingleChartData } from '@/types/global'; +import type { LoginHistoryQueryResponse } from '@/api/user/user'; +import axios from 'axios'; + +/** + * 基建模块工作台响应 + */ +export interface InfraWorkplaceStatisticsResponse { + userId: number; + username: string; + nickname: string; + unreadMessageCount: number; + lastLoginTime: number; + userSessionCount: number; + operatorChart: LineSingleChartData; + loginHistoryList: Array; +} + +/** + * 查询基建模块工作台统计信息 + */ +export function getInfraWorkplaceStatisticsData() { + return axios.get('/infra/statistics/get-workplace'); +} diff --git a/orion-visor-ui/src/hooks/chart-option.ts b/orion-visor-ui/src/hooks/chart-option.ts index dd14b572..cdd85775 100644 --- a/orion-visor-ui/src/hooks/chart-option.ts +++ b/orion-visor-ui/src/hooks/chart-option.ts @@ -1,25 +1,34 @@ import type { EChartsOption } from 'echarts'; import { computed } from 'vue'; -import { useAppStore } from '@/store'; +import useThemes from '@/hooks/themes'; -// for code hints -// import { SeriesOption } from 'echarts'; -// Because there are so many configuration items, this provides a relatively convenient code hint. -// When using vue, pay attention to the reactive issues. It is necessary to ensure that corresponding functions can be triggered, TypeScript does not report errors, and code writing is convenient. -interface optionsFn { - (isDark: boolean): EChartsOption; +// 配置生成 +interface OptionsFn { + (isDark: boolean, themeTextColor: string, themeLineColor: string): EChartsOption; } -export default function useChartOption(sourceOption: optionsFn) { - const appStore = useAppStore(); - const isDark = computed(() => { - return appStore.theme === 'dark'; - }); - // echarts support https://echarts.apache.org/zh/theme-builder.html - // It's not used here +// 亮色文本色 +const lightTextColor = '#4E5969'; + +// 暗色文本色 +const darkTextColor = 'rgba(255, 255, 255, 0.7)'; + +// 亮色线色 +const lightLineColor = '#F2F3F5'; + +// 暗色线色 +const darkLineColor = '#2E2E30'; + +export default function useChartOption(sourceOption: OptionsFn) { + const { isDark } = useThemes(); + + // 配置 const chartOption = computed(() => { - return sourceOption(isDark.value); + return sourceOption(isDark.value, + isDark.value ? darkTextColor : lightTextColor, + isDark.value ? darkLineColor : lightLineColor); }); + return { chartOption, }; diff --git a/orion-visor-ui/src/types/chart.ts b/orion-visor-ui/src/types/chart.ts new file mode 100644 index 00000000..352f92bb --- /dev/null +++ b/orion-visor-ui/src/types/chart.ts @@ -0,0 +1,88 @@ +import type { LineSeriesOption } from 'echarts'; + +/** + * 折线图系列定义 + */ +export interface LineSeriesColor { + lineColor: string; + itemBorderColor: string; +} + +/** + * 折线图系列常量 + */ +export const LineSeriesColors: Record = { + BLUE: { + lineColor: '#4263EB', + itemBorderColor: '#DBE4FF', + }, + CYAN: { + lineColor: '#1098AD', + itemBorderColor: '#C5F6FA', + }, + GREEN: { + lineColor: '#37B24D', + itemBorderColor: '#D3F9D8', + }, + PURPLE: { + lineColor: '#AE3EC9', + itemBorderColor: '#F3D9FA', + }, + ORANGE: { + lineColor: '#F76707', + itemBorderColor: '#FFF3BF', + }, + VIOLET: { + lineColor: '#7048E8', + itemBorderColor: '#E5DBFF', + }, + YELLOW: { + lineColor: '#F59F00', + itemBorderColor: '#FFF3BF', + }, + TEAL: { + lineColor: '#0CA678', + itemBorderColor: '#C3FAE8', + }, + RED: { + lineColor: '#F03E3E', + itemBorderColor: '#FFE3E3', + } +}; + +/** + * 生成折线图系列 + */ +export const createLineSeries = (name: string, + lineColor: string, + itemBorderColor: string, + data: number[]): LineSeriesOption => { + return { + name, + data, + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 10, + itemStyle: { + color: lineColor, + }, + emphasis: { + focus: 'series', + itemStyle: { + color: lineColor, + borderWidth: 2, + borderColor: itemBorderColor, + }, + }, + lineStyle: { + width: 2, + color: lineColor, + }, + showSymbol: data.length === 1, + areaStyle: { + opacity: 0.1, + color: lineColor, + }, + }; +}; diff --git a/orion-visor-ui/src/types/global.ts b/orion-visor-ui/src/types/global.ts index d859fb8d..268f8800 100644 --- a/orion-visor-ui/src/types/global.ts +++ b/orion-visor-ui/src/types/global.ts @@ -46,3 +46,8 @@ export interface DataGrid { } export type TimeRanger = [string, string]; + +export interface LineSingleChartData { + x: string[]; + data: Array; +} diff --git a/orion-visor-ui/src/views/asset-audit/connect-log/components/connect-log-table.vue b/orion-visor-ui/src/views/asset-audit/connect-log/components/connect-log-table.vue index ee7000c4..0517cb3a 100644 --- a/orion-visor-ui/src/views/asset-audit/connect-log/components/connect-log-table.vue +++ b/orion-visor-ui/src/views/asset-audit/connect-log/components/connect-log-table.vue @@ -211,11 +211,12 @@ import { deleteTerminalConnectLog, getTerminalConnectLogPage, hostForceOffline } from '@/api/asset/terminal-connect-log'; import { connectStatusKey, connectTypeKey, TerminalConnectStatus } from '../types/const'; import { useTablePagination, useRowSelection } from '@/hooks/table'; - import { useDictStore } from '@/store'; + import { useDictStore, useUserStore } from '@/store'; import { Message } from '@arco-design/web-vue'; import columns from '../types/table.columns'; import useLoading from '@/hooks/loading'; import { copy } from '@/hooks/copy'; + import { useRoute } from 'vue-router'; import { dateFormat } from '@/utils'; import { openNewRoute } from '@/router'; import UserSelector from '@/components/user/user/selector/index.vue'; @@ -223,6 +224,7 @@ const emits = defineEmits(['openClear', 'openDetail']); + const route = useRoute(); const pagination = useTablePagination(); const rowSelection = useRowSelection(); const { loading, setLoading } = useLoading(); @@ -316,6 +318,16 @@ }; onMounted(() => { + // 当前用户 + const action = route.query.action as string; + if (action === 'self') { + formModel.userId = useUserStore().id; + } + // id + const id = route.query.id as string; + if (id) { + formModel.id = Number.parseInt(id); + } fetchTableData(); }); diff --git a/orion-visor-ui/src/views/asset/host-list/components/host-card-list.vue b/orion-visor-ui/src/views/asset/host-list/components/host-card-list.vue index ae788bf4..4c4ee4ba 100644 --- a/orion-visor-ui/src/views/asset/host-list/components/host-card-list.vue +++ b/orion-visor-ui/src/views/asset/host-list/components/host-card-list.vue @@ -198,7 +198,7 @@ SSH @@ -206,7 +206,7 @@ SFTP diff --git a/orion-visor-ui/src/views/asset/host-list/components/host-table.vue b/orion-visor-ui/src/views/asset/host-list/components/host-table.vue index 02334649..f1eb85af 100644 --- a/orion-visor-ui/src/views/asset/host-list/components/host-table.vue +++ b/orion-visor-ui/src/views/asset/host-list/components/host-table.vue @@ -234,7 +234,7 @@ SSH @@ -242,7 +242,7 @@ SFTP diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/banner.vue b/orion-visor-ui/src/views/dashboard/workplace/components/banner.vue deleted file mode 100644 index 85abea08..00000000 --- a/orion-visor-ui/src/views/dashboard/workplace/components/banner.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - - - diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/batch-exec-table.vue b/orion-visor-ui/src/views/dashboard/workplace/components/batch-exec-table.vue new file mode 100644 index 00000000..bb85b424 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/components/batch-exec-table.vue @@ -0,0 +1,68 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/docs.vue b/orion-visor-ui/src/views/dashboard/workplace/components/docs.vue deleted file mode 100644 index 993d4491..00000000 --- a/orion-visor-ui/src/views/dashboard/workplace/components/docs.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - - - diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/operator-log-chart.vue b/orion-visor-ui/src/views/dashboard/workplace/components/operator-log-chart.vue new file mode 100644 index 00000000..fd99a1d4 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/components/operator-log-chart.vue @@ -0,0 +1,99 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/quick-operation.vue b/orion-visor-ui/src/views/dashboard/workplace/components/quick-operation.vue index 7aee3ad6..a7552267 100644 --- a/orion-visor-ui/src/views/dashboard/workplace/components/quick-operation.vue +++ b/orion-visor-ui/src/views/dashboard/workplace/components/quick-operation.vue @@ -1,22 +1,26 @@ diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/terminal-connect-table.vue b/orion-visor-ui/src/views/dashboard/workplace/components/terminal-connect-table.vue new file mode 100644 index 00000000..d7f13189 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/components/terminal-connect-table.vue @@ -0,0 +1,82 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/user-login-table.vue b/orion-visor-ui/src/views/dashboard/workplace/components/user-login-table.vue new file mode 100644 index 00000000..80c2eec6 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/components/user-login-table.vue @@ -0,0 +1,60 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/workplace-header.vue b/orion-visor-ui/src/views/dashboard/workplace/components/workplace-header.vue new file mode 100644 index 00000000..70403a15 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/components/workplace-header.vue @@ -0,0 +1,76 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/components/workplace-statistics.vue b/orion-visor-ui/src/views/dashboard/workplace/components/workplace-statistics.vue new file mode 100644 index 00000000..df218a77 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/components/workplace-statistics.vue @@ -0,0 +1,279 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/index.vue b/orion-visor-ui/src/views/dashboard/workplace/index.vue index d4439021..f46531cc 100644 --- a/orion-visor-ui/src/views/dashboard/workplace/index.vue +++ b/orion-visor-ui/src/views/dashboard/workplace/index.vue @@ -1,127 +1,118 @@ - - + + diff --git a/orion-visor-ui/src/views/dashboard/workplace/types/const.ts b/orion-visor-ui/src/views/dashboard/workplace/types/const.ts new file mode 100644 index 00000000..0bdcb085 --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/types/const.ts @@ -0,0 +1,18 @@ +import type { InfraWorkplaceStatisticsResponse } from '@/api/statistics/infra-statistics'; +import type { AssetWorkplaceStatisticsResponse } from '@/api/statistics/asset-statistics'; +import { execHostStatusKey } from '@/components/exec/log/const'; + +// 工作台统计数据 +export interface WorkplaceStatisticsData { + infra: InfraWorkplaceStatisticsResponse; + asset: AssetWorkplaceStatisticsResponse; +} + +// 终端连接类型 字典项 +export const terminalConnectTypeKey = 'terminalConnectType'; + +// 操作日志结果 字典项 +export const operatorLogResultKey = 'operatorLogResult'; + +// 加载的字典值 +export const dictKeys = [terminalConnectTypeKey, execHostStatusKey, operatorLogResultKey]; diff --git a/orion-visor-ui/src/views/dashboard/workplace/types/table.columns.ts b/orion-visor-ui/src/views/dashboard/workplace/types/table.columns.ts new file mode 100644 index 00000000..323e054e --- /dev/null +++ b/orion-visor-ui/src/views/dashboard/workplace/types/table.columns.ts @@ -0,0 +1,93 @@ +import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'; +import { dateFormat } from '@/utils'; + +// 终端日志列 +export const terminalLogColumns = [ + { + title: '连接主机', + dataIndex: 'hostName', + slotName: 'hostName', + align: 'left', + ellipsis: true, + }, { + title: '类型', + dataIndex: 'type', + slotName: 'type', + width: 88, + align: 'left', + }, { + title: '连接时间', + dataIndex: 'startTime', + slotName: 'startTime', + align: 'center', + width: 180, + render: ({ record }) => { + return dateFormat(new Date(record.startTime)); + }, + }, { + title: '操作', + slotName: 'handle', + width: 92, + align: 'center', + fixed: 'right', + }, +] as TableColumnData[]; + +// 批量执行列 +export const batchExecColumns = [ + { + title: '执行描述', + dataIndex: 'description', + slotName: 'description', + align: 'left', + ellipsis: true, + tooltip: true, + }, { + title: '执行状态', + dataIndex: 'status', + slotName: 'status', + align: 'left', + width: 108, + }, { + title: '执行时间', + dataIndex: 'startTime', + slotName: 'startTime', + align: 'center', + width: 180, + render: ({ record }) => { + return dateFormat(new Date(record.startTime)); + }, + }, { + title: '操作', + slotName: 'handle', + width: 92, + align: 'center', + fixed: 'right', + }, +] as TableColumnData[]; + +// 用户登录日志列 +export const userLoginColumns = [ + { + title: '登录设备', + dataIndex: 'content', + slotName: 'content', + ellipsis: true, + tooltip: true, + }, { + title: '登录结果', + dataIndex: 'result', + slotName: 'result', + align: 'center', + width: 90, + }, { + title: '登录时间', + dataIndex: 'createTime', + slotName: 'createTime', + align: 'center', + width: 180, + render: ({ record }) => { + return dateFormat(new Date(record.createTime)); + }, + }, +] as TableColumnData[]; diff --git a/orion-visor-ui/src/views/exec/exec-command-log/components/exec-command-log-table.vue b/orion-visor-ui/src/views/exec/exec-command-log/components/exec-command-log-table.vue index 5b0fe94d..58fb190b 100644 --- a/orion-visor-ui/src/views/exec/exec-command-log/components/exec-command-log-table.vue +++ b/orion-visor-ui/src/views/exec/exec-command-log/components/exec-command-log-table.vue @@ -217,11 +217,12 @@ getExecCommandLogStatus } from '@/api/exec/exec-command-log'; import { Message } from '@arco-design/web-vue'; + import { useRoute } from 'vue-router'; import useLoading from '@/hooks/loading'; import { tableColumns } from '../types/table.columns'; import { ExecStatus, execStatusKey } from '@/components/exec/log/const'; import { useExpandable, useTablePagination, useRowSelection } from '@/hooks/table'; - import { useDictStore } from '@/store'; + import { useDictStore, useUserStore } from '@/store'; import { dateFormat, formatDuration } from '@/utils'; import { reExecCommand } from '@/api/exec/exec-command'; import { interruptExecCommand } from '@/api/exec/exec-command-log'; @@ -230,6 +231,7 @@ const emits = defineEmits(['viewCommand', 'viewParams', 'viewLog', 'openClear']); + const route = useRoute(); const pagination = useTablePagination(); const rowSelection = useRowSelection(); const expandable = useExpandable(); @@ -406,6 +408,11 @@ }); onMounted(() => { + // 当前用户 + const action = route.query.action as string; + if (action === 'self') { + formModel.userId = useUserStore().id; + } // 加载数据 fetchTableData(); // 注册状态轮询 diff --git a/orion-visor-ui/src/views/exec/exec-command-log/index.vue b/orion-visor-ui/src/views/exec/exec-command-log/index.vue index 6869de2e..faad5f6e 100644 --- a/orion-visor-ui/src/views/exec/exec-command-log/index.vue +++ b/orion-visor-ui/src/views/exec/exec-command-log/index.vue @@ -32,7 +32,6 @@ import { ref, onBeforeMount } from 'vue'; import { useDictStore } from '@/store'; import { dictKeys } from '@/components/exec/log/const'; - import { useRouter } from 'vue-router'; import { openNewRoute } from '@/router'; import ExecCommandLogTable from './components/exec-command-log-table.vue'; import ExecCommandLogClearModal from './components/exec-command-log-clear-modal.vue'; @@ -40,8 +39,6 @@ import ShellEditorModal from '@/components/view/shell-editor/modal/index.vue'; import ExecLogPanelModal from '@/components/exec/log/panel-modal/index.vue'; - const router = useRouter(); - const render = ref(false); const tableRef = ref(); const logModal = ref(); diff --git a/orion-visor-ui/src/views/user/info/index.vue b/orion-visor-ui/src/views/user/info/index.vue index 31dd3056..f3e774a6 100644 --- a/orion-visor-ui/src/views/user/info/index.vue +++ b/orion-visor-ui/src/views/user/info/index.vue @@ -1,6 +1,7 @@