Browse Source

[Feature][UI Next] Add monitor statistics audit log. (#8238)

songjianet 3 years ago
parent
commit
c64c66e7cf

+ 4 - 0
dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts

@@ -208,6 +208,10 @@ export function useDataList() {
               {
                 label: t('menu.statistics'),
                 key: `/monitor/statistics`
+              },
+              {
+                label: t('menu.audit_log'),
+                key: `/monitor/audit-log`
               }
             ]
           }

+ 16 - 0
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@@ -65,6 +65,7 @@ const menu = {
   db: 'DB',
   statistical_manage: 'Statistical Manage',
   statistics: 'Statistics',
+  audit_log: 'Audit Log',
   tenant_manage: 'Tenant Manage',
   user_manage: 'User Manage',
   alarm_group_manage: 'Alarm Group Manage',
@@ -149,6 +150,21 @@ const monitor = {
     failure_command_number: 'Failure Command Number',
     tasks_number_of_waiting_running: 'Tasks Number Of Waiting Running',
     task_number_of_ready_to_kill: 'Task Number Of Ready To Kill'
+  },
+  audit_log: {
+    user_name: 'User Name',
+    resource_type: 'Resource Type',
+    project_name: 'Project Name',
+    operation_type: 'Operation Type',
+    create_time: 'Create Time',
+    start_time: 'Start Time',
+    end_time: 'End Time',
+    user_audit: 'User Audit',
+    project_audit: 'Project Audit',
+    create: 'Create',
+    update: 'Update',
+    delete: 'Delete',
+    read: 'Read'
   }
 }
 

+ 16 - 0
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@@ -65,6 +65,7 @@ const menu = {
   db: 'DB',
   statistical_manage: '统计管理',
   statistics: 'Statistics',
+  audit_log: '审计日志',
   tenant_manage: '租户管理',
   user_manage: '用户管理',
   alarm_group_manage: '告警组管理',
@@ -150,6 +151,21 @@ const monitor = {
     failure_command_number: '执行失败的命令数',
     tasks_number_of_waiting_running: '待运行任务数',
     task_number_of_ready_to_kill: '待杀死任务数'
+  },
+  audit_log: {
+    user_name: '用户名称',
+    resource_type: '资源类型',
+    project_name: '项目名称',
+    operation_type: '操作类型',
+    create_time: '创建时间',
+    start_time: '开始时间',
+    end_time: '结束时间',
+    user_audit: '用户管理审计',
+    project_audit: '项目管理审计',
+    create: '创建',
+    update: '更新',
+    delete: '删除',
+    read: '读取'
   }
 }
 

+ 9 - 0
dolphinscheduler-ui-next/src/router/modules/monitor.ts

@@ -64,6 +64,15 @@ export default {
         title: '统计管理-Statistics',
         showSide: true
       }
+    },
+    {
+      path: '/monitor/audit-log',
+      name: 'statistics-audit-log',
+      component: components['monitor-statistics-audit-log'],
+      meta: {
+        title: '审计日志-AuditLog',
+        showSide: true
+      }
     }
   ]
 }

+ 27 - 0
dolphinscheduler-ui-next/src/service/modules/audit/index.ts

@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { axios } from '@/service/service'
+import type { AuditListReq } from './types'
+
+export function queryAuditLogListPaging(params: AuditListReq): any {
+  return axios({
+    url: '/projects/audit/audit-log-list',
+    method: 'get',
+    params
+  })
+}

+ 48 - 0
dolphinscheduler-ui-next/src/service/modules/audit/types.ts

@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface AuditListReq {
+  pageNo: number
+  pageSize: number
+  endDate?: string
+  moduleType?: string
+  operationType?: string
+  processName?: string
+  projectName?: string
+  resourceType?: string
+  startDate?: string
+  userName?: string
+}
+
+interface AuditItem {
+  userName: string
+  resource: string
+  operation: string
+  time: string
+  resourceName: string
+}
+
+interface AuditListRes {
+  totalList: AuditItem[]
+  total: number
+  totalPage: number
+  pageSize: number
+  currentPage: number
+  start: number
+}
+
+export { AuditListReq, AuditListRes }

+ 26 - 0
dolphinscheduler-ui-next/src/views/monitor/statistics/audit-log/index.module.scss

@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.table-card {
+  margin-top: 8px;
+
+  .pagination {
+    margin-top: 20px;
+    display: flex;
+    justify-content: center;
+  }
+}

+ 161 - 0
dolphinscheduler-ui-next/src/views/monitor/statistics/audit-log/index.tsx

@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent, onMounted, toRefs, watch } from 'vue'
+import {
+  NSpace,
+  NInput,
+  NSelect,
+  NDatePicker,
+  NButton,
+  NIcon,
+  NDataTable,
+  NPagination,
+  NCard
+} from 'naive-ui'
+import { SearchOutlined } from '@vicons/antd'
+import { useTable } from './use-table'
+import { useI18n } from 'vue-i18n'
+import Card from '@/components/card'
+import styles from './index.module.scss'
+
+const AuditLog = defineComponent({
+  name: 'audit-log',
+  setup() {
+    const { t, variables, getTableData, createColumns } = useTable()
+
+    const requestTableData = () => {
+      getTableData({
+        pageSize: variables.pageSize,
+        pageNo: variables.page,
+        resourceType: variables.resourceType,
+        operationType: variables.operationType,
+        userName: variables.userName,
+        datePickerRange: variables.datePickerRange
+      })
+    }
+
+    const onUpdatePageSize = () => {
+      variables.page = 1
+      requestTableData()
+    }
+
+    const onSearch = () => {
+      variables.page = 1
+      requestTableData()
+    }
+
+    onMounted(() => {
+      createColumns(variables)
+      requestTableData()
+    })
+
+    watch(useI18n().locale, () => {
+      createColumns(variables)
+    })
+
+    return {
+      t,
+      ...toRefs(variables),
+      requestTableData,
+      onUpdatePageSize,
+      onSearch
+    }
+  },
+  render() {
+    const { t, requestTableData, onUpdatePageSize, onSearch } = this
+
+    return (
+      <>
+        <NCard>
+          <NSpace justify='end'>
+            <NInput
+              v-model={[this.userName, 'value']}
+              size='small'
+              placeholder={t('monitor.audit_log.user_name')}
+              clearable
+            />
+            <NSelect
+              v-model={[this.operationType, 'value']}
+              size='small'
+              options={[
+                { value: 'CREATE', label: t('monitor.audit_log.create') },
+                { value: 'UPDATE', label: t('monitor.audit_log.update') },
+                { value: 'DELETE', label: t('monitor.audit_log.delete') },
+                { value: 'READ', label: t('monitor.audit_log.read') }
+              ]}
+              placeholder={t('monitor.audit_log.operation_type')}
+              style={{ width: '180px' }}
+              clearable
+            />
+            <NSelect
+              v-model={[this.resourceType, 'value']}
+              size='small'
+              options={[
+                {
+                  value: 'USER_MODULE',
+                  label: t('monitor.audit_log.user_audit')
+                },
+                {
+                  value: 'PROJECT_MODULE',
+                  label: t('monitor.audit_log.project_audit')
+                }
+              ]}
+              placeholder={t('monitor.audit_log.resource_type')}
+              style={{ width: '180px' }}
+              clearable
+            />
+            <NDatePicker
+              v-model={[this.datePickerRange, 'value']}
+              type='datetimerange'
+              size='small'
+              start-placeholder={t('monitor.audit_log.start_time')}
+              end-placeholder={t('monitor.audit_log.end_time')}
+              clearable
+            />
+            <NButton size='small' type='primary' onClick={onSearch}>
+              {{
+                icon: () => (
+                  <NIcon>
+                    <SearchOutlined />
+                  </NIcon>
+                )
+              }}
+            </NButton>
+          </NSpace>
+        </NCard>
+        <Card class={styles['table-card']}>
+          <NDataTable columns={this.columns} data={this.tableData} />
+          <div class={styles.pagination}>
+            <NPagination
+              v-model:page={this.page}
+              v-model:page-size={this.pageSize}
+              page-count={this.totalPage}
+              show-size-picker
+              page-sizes={[10, 30, 50]}
+              show-quick-jumper
+              onUpdatePage={requestTableData}
+              onUpdatePageSize={onUpdatePageSize}
+            />
+          </div>
+        </Card>
+      </>
+    )
+  }
+})
+
+export default AuditLog

+ 105 - 0
dolphinscheduler-ui-next/src/views/monitor/statistics/audit-log/use-table.ts

@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { useI18n } from 'vue-i18n'
+import { reactive, ref } from 'vue'
+import { useAsyncState } from '@vueuse/core'
+import { queryAuditLogListPaging } from '@/service/modules/audit'
+import { format } from 'date-fns'
+import type { AuditListRes } from '@/service/modules/audit/types'
+
+export function useTable() {
+  const { t } = useI18n()
+
+  const variables = reactive({
+    columns: [],
+    tableData: [],
+    page: ref(1),
+    pageSize: ref(10),
+    resourceType: ref(null),
+    operationType: ref(null),
+    userName: ref(null),
+    datePickerRange: ref(null),
+    totalPage: ref(1)
+  })
+
+  const createColumns = (variables: any) => {
+    variables.columns = [
+      {
+        title: '#',
+        key: 'index'
+      },
+      {
+        title: t('monitor.audit_log.user_name'),
+        key: 'userName'
+      },
+      {
+        title: t('monitor.audit_log.resource_type'),
+        key: 'resource'
+      },
+      {
+        title: t('monitor.audit_log.project_name'),
+        key: 'resourceName'
+      },
+      {
+        title: t('monitor.audit_log.operation_type'),
+        key: 'operation'
+      },
+      {
+        title: t('monitor.audit_log.create_time'),
+        key: 'time'
+      }
+    ]
+  }
+
+  const getTableData = (params: any) => {
+    const data = {
+      pageSize: params.pageSize,
+      pageNo: params.pageNo,
+      resourceType: params.resourceType,
+      operationType: params.operationType,
+      userName: params.userName,
+      startDate: params.datePickerRange
+        ? format(new Date(params.datePickerRange[0]), 'yyyy-MM-dd HH:mm:ss')
+        : '',
+      endDate: params.datePickerRange
+        ? format(new Date(params.datePickerRange[1]), 'yyyy-MM-dd HH:mm:ss')
+        : ''
+    }
+
+    const { state } = useAsyncState(
+      queryAuditLogListPaging(data).then((res: AuditListRes) => {
+        variables.tableData = res.totalList.map((item, index) => {
+          return {
+            index: index + 1,
+            ...item
+          }
+        }) as any
+      }),
+      {}
+    )
+
+    return state
+  }
+
+  return {
+    t,
+    variables,
+    getTableData,
+    createColumns
+  }
+}

+ 87 - 87
dolphinscheduler-ui-next/src/views/projects/workflow/relation/index.tsx

@@ -25,98 +25,98 @@ import Card from '@/components/card'
 import Graph from './components/Graph'
 
 const workflowRelation = defineComponent({
-	name: 'workflow-relation',
-	setup() {
-		const { t, locale } = useI18n()
-		const route = useRoute()
-		const { variables, getWorkflowName, getOneWorkflow, getWorkflowList } =
-			useRelation()
+  name: 'workflow-relation',
+  setup() {
+    const { t, locale } = useI18n()
+    const route = useRoute()
+    const { variables, getWorkflowName, getOneWorkflow, getWorkflowList } =
+      useRelation()
 
-		onMounted(() => {
-			getWorkflowList(Number(route.params.projectCode))
-			getWorkflowName(Number(route.params.projectCode))
-		})
+    onMounted(() => {
+      getWorkflowList(Number(route.params.projectCode))
+      getWorkflowName(Number(route.params.projectCode))
+    })
 
-		const handleResetDate = () => {
-			variables.seriesData = []
-			variables.workflow && variables.workflow !== 0
-				? getOneWorkflow(
-					Number(variables.workflow),
-					Number(route.params.projectCode)
-				)
-				: getWorkflowList(Number(route.params.projectCode))
-		}
+    const handleResetDate = () => {
+      variables.seriesData = []
+      variables.workflow && variables.workflow !== 0
+        ? getOneWorkflow(
+            Number(variables.workflow),
+            Number(route.params.projectCode)
+          )
+        : getWorkflowList(Number(route.params.projectCode))
+    }
 
-		watch(
-			() => [variables.workflow, variables.labelShow, locale.value],
-			() => {
-				handleResetDate()
-			}
-		)
+    watch(
+      () => [variables.workflow, variables.labelShow, locale.value],
+      () => {
+        handleResetDate()
+      }
+    )
 
-		return { t, handleResetDate, ...toRefs(variables) }
-	},
-	render() {
-		const { t, handleResetDate } = this
+    return { t, handleResetDate, ...toRefs(variables) }
+  },
+  render() {
+    const { t, handleResetDate } = this
 
-		return (
-			<Card title={t('project.workflow.workflow_relation')}>
-				{{
-					default: () =>
-						Object.keys(this.seriesData).length > 0 && (
-							<Graph seriesData={this.seriesData} labelShow={this.labelShow} />
-						),
-					'header-extra': () => (
-						<NSpace>
-							<NSelect
-								clearable
-								style={{ width: '300px' }}
-								placeholder={t('project.workflow.workflow_name')}
-								options={this.workflowOptions}
-								v-model={[this.workflow, 'value']}
-							/>
-							<NTooltip trigger={'hover'}>
-								{{
-									default: () => t('project.workflow.refresh'),
-									trigger: () => (
-										<NButton
-											strong
-											secondary
-											circle
-											type='info'
-											onClick={handleResetDate}
-										>
-											<NIcon>
-												<ReloadOutlined />
-											</NIcon>
-										</NButton>
-									)
-								}}
-							</NTooltip>
-							<NTooltip trigger={'hover'}>
-								{{
-									default: () => t('project.workflow.show_hide_label'),
-									trigger: () => (
-										<NButton
-											strong
-											secondary
-											circle
-											type='info'
-											onClick={() => (this.labelShow = !this.labelShow)}
-										>
-											<NIcon>
-												<EyeOutlined />
-											</NIcon>
-										</NButton>
-									)
-								}}
-							</NTooltip>
-						</NSpace>
-					)
-				}}
-			</Card>
-		)
-	}
+    return (
+      <Card title={t('project.workflow.workflow_relation')}>
+        {{
+          default: () =>
+            Object.keys(this.seriesData).length > 0 && (
+              <Graph seriesData={this.seriesData} labelShow={this.labelShow} />
+            ),
+          'header-extra': () => (
+            <NSpace>
+              <NSelect
+                clearable
+                style={{ width: '300px' }}
+                placeholder={t('project.workflow.workflow_name')}
+                options={this.workflowOptions}
+                v-model={[this.workflow, 'value']}
+              />
+              <NTooltip trigger={'hover'}>
+                {{
+                  default: () => t('project.workflow.refresh'),
+                  trigger: () => (
+                    <NButton
+                      strong
+                      secondary
+                      circle
+                      type='info'
+                      onClick={handleResetDate}
+                    >
+                      <NIcon>
+                        <ReloadOutlined />
+                      </NIcon>
+                    </NButton>
+                  )
+                }}
+              </NTooltip>
+              <NTooltip trigger={'hover'}>
+                {{
+                  default: () => t('project.workflow.show_hide_label'),
+                  trigger: () => (
+                    <NButton
+                      strong
+                      secondary
+                      circle
+                      type='info'
+                      onClick={() => (this.labelShow = !this.labelShow)}
+                    >
+                      <NIcon>
+                        <EyeOutlined />
+                      </NIcon>
+                    </NButton>
+                  )
+                }}
+              </NTooltip>
+            </NSpace>
+          )
+        }}
+      </Card>
+    )
+  }
 })
 
 export default workflowRelation