From 1f87eb67609d52fa0d5cf780e406572458b17836 Mon Sep 17 00:00:00 2001
From: songjianet <1778651752@qq.com>
Date: Thu, 3 Feb 2022 15:20:56 +0800
Subject: [PATCH] [Feature][UI Next] Add task result. (#8277)
---
.../src/layouts/content/index.tsx | 3 +-
.../src/layouts/content/use-dataList.ts | 17 +-
.../src/locales/modules/en_US.ts | 39 +++-
.../src/locales/modules/zh_CN.ts | 39 +++-
.../src/router/modules/data-quality.ts | 42 ++++
dolphinscheduler-ui-next/src/router/routes.ts | 4 +-
.../src/service/modules/data-quality/index.ts | 35 +++
.../src/service/modules/data-quality/types.ts | 74 +++++++
.../task-result/index.module.scss | 26 +++
.../views/data-quality/task-result/index.tsx | 177 +++++++++++++++
.../data-quality/task-result/use-table.ts | 201 ++++++++++++++++++
11 files changed, 650 insertions(+), 7 deletions(-)
create mode 100644 dolphinscheduler-ui-next/src/router/modules/data-quality.ts
create mode 100644 dolphinscheduler-ui-next/src/service/modules/data-quality/index.ts
create mode 100644 dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts
create mode 100644 dolphinscheduler-ui-next/src/views/data-quality/task-result/index.module.scss
create mode 100644 dolphinscheduler-ui-next/src/views/data-quality/task-result/index.tsx
create mode 100644 dolphinscheduler-ui-next/src/views/data-quality/task-result/use-table.ts
diff --git a/dolphinscheduler-ui-next/src/layouts/content/index.tsx b/dolphinscheduler-ui-next/src/layouts/content/index.tsx
index dfb2ca4c48..a8dbf2e97b 100644
--- a/dolphinscheduler-ui-next/src/layouts/content/index.tsx
+++ b/dolphinscheduler-ui-next/src/layouts/content/index.tsx
@@ -61,7 +61,8 @@ const Content = defineComponent({
const getSideMenu = (state: any) => {
const key = menuStore.getMenuKey
state.sideMenuOptions =
- state.menuOptions.filter((menu: { key: string }) => menu.key === key)[0]?.children || state.menuOptions
+ state.menuOptions.filter((menu: { key: string }) => menu.key === key)[0]
+ ?.children || state.menuOptions
state.isShowSide = menuStore.getShowSideStatus
}
diff --git a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
index cffa40cedf..76ee66294d 100644
--- a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
+++ b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
@@ -42,7 +42,9 @@ import {
EnvironmentOutlined,
KeyOutlined,
SafetyOutlined,
- GroupOutlined
+ GroupOutlined,
+ ContainerOutlined,
+ ApartmentOutlined
} from '@vicons/antd'
import { useMenuStore } from '@/store/menu/menu'
@@ -172,6 +174,19 @@ export function useDataList() {
}
]
},
+ {
+ label: t('menu.data_quality'),
+ key: 'data-quality',
+ icon: renderIcon(ContainerOutlined),
+ isShowSide: true,
+ children: [
+ {
+ label: t('menu.task_result'),
+ key: `/data-quality/task-result`,
+ icon: renderIcon(ApartmentOutlined)
+ }
+ ]
+ },
{
label: t('menu.datasource'),
key: 'datasource',
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 4800632443..db1fb23ca9 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -76,7 +76,9 @@ const menu = {
token_manage: 'Token Manage',
task_group_manage: 'Task Group Manage',
task_group_option: 'Task Group Option',
- task_group_queue: 'Task Group Queue'
+ task_group_queue: 'Task Group Queue',
+ data_quality: 'Data Quality',
+ task_result: 'Task Result'
}
const home = {
@@ -715,6 +717,38 @@ const datasource = {
user_password_tips: 'Please enter your password'
}
+const data_quality = {
+ task_result: {
+ task_name: 'Task Name',
+ workflow_instance: 'Workflow Instance',
+ rule_type: 'Rule Type',
+ rule_name: 'Rule Name',
+ state: 'State',
+ actual_value: 'Actual Value',
+ excepted_value: 'Excepted Value',
+ check_type: 'Check Type',
+ operator: 'Operator',
+ threshold: 'Threshold',
+ failure_strategy: 'Failure Strategy',
+ excepted_value_type: 'Excepted Value Type',
+ error_output_path: 'Error Output Path',
+ username: 'Username',
+ create_time: 'Create Time',
+ update_time: 'Update Time',
+ undone: 'Undone',
+ success: 'Success',
+ failure: 'Failure',
+ single_table: 'Single Table',
+ single_table_custom_sql: 'Single Table Custom Sql',
+ multi_table_accuracy: 'Multi Table Accuracy',
+ multi_table_comparison: 'Multi Table Comparison',
+ expected_and_actual_or_expected: '(Expected - Actual) / Expected x 100%',
+ expected_and_actual: 'Expected - Actual',
+ actual_and_expected: 'Actual - Expected',
+ actual_or_expected: 'Actual / Expected x 100%'
+ }
+}
+
export default {
login,
modal,
@@ -728,5 +762,6 @@ export default {
resource,
project,
security,
- datasource
+ datasource,
+ data_quality
}
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index fecc01b87a..20c41a870f 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -76,7 +76,9 @@ const menu = {
token_manage: '令牌管理',
task_group_manage: '任务组管理',
task_group_option: '任务组配置',
- task_group_queue: '任务组队列'
+ task_group_queue: '任务组队列',
+ data_quality: '数据质量',
+ task_result: '任务结果'
}
const home = {
@@ -708,6 +710,38 @@ const datasource = {
user_password_tips: '请输入密码'
}
+const data_quality = {
+ task_result: {
+ task_name: '任务名称',
+ workflow_instance: '工作流实例',
+ rule_type: '规则类型',
+ rule_name: '规则名称',
+ state: '状态',
+ actual_value: '实际值',
+ excepted_value: '期望值',
+ check_type: '检测类型',
+ operator: '操作符',
+ threshold: '阈值',
+ failure_strategy: '失败策略',
+ excepted_value_type: '期望值类型',
+ error_output_path: '错误数据路径',
+ username: '用户名',
+ create_time: '创建时间',
+ update_time: '更新时间',
+ undone: '未完成',
+ success: '成功',
+ failure: '失败',
+ single_table: '单表检测',
+ single_table_custom_sql: '自定义SQL',
+ multi_table_accuracy: '多表准确性',
+ multi_table_comparison: '两表值对比',
+ expected_and_actual_or_expected: '(期望值-实际值)/实际值 x 100%',
+ expected_and_actual: '期望值-实际值',
+ actual_and_expected: '实际值-期望值',
+ actual_or_expected: '实际值/期望值 x 100%'
+ }
+}
+
export default {
login,
modal,
@@ -721,5 +755,6 @@ export default {
resource,
project,
security,
- datasource
+ datasource,
+ data_quality
}
diff --git a/dolphinscheduler-ui-next/src/router/modules/data-quality.ts b/dolphinscheduler-ui-next/src/router/modules/data-quality.ts
new file mode 100644
index 0000000000..fe4c106807
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/router/modules/data-quality.ts
@@ -0,0 +1,42 @@
+/*
+ * 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 type { Component } from 'vue'
+import utils from '@/utils'
+
+// All TSX files under the views folder automatically generate mapping relationship
+const modules = import.meta.glob('/src/views/**/**.tsx')
+const components: { [key: string]: Component } = utils.mapping(modules)
+
+export default {
+ path: '/data-quality',
+ name: 'data-quality',
+ meta: { title: 'data-quality' },
+ redirect: { name: 'task-result' },
+ component: () => import('@/layouts/content'),
+ children: [
+ {
+ path: '/data-quality/task-result',
+ name: 'task-result',
+ component: components['data-quality-task-result'],
+ meta: {
+ title: '数据质量-task-result',
+ showSide: true
+ }
+ }
+ ]
+}
diff --git a/dolphinscheduler-ui-next/src/router/routes.ts b/dolphinscheduler-ui-next/src/router/routes.ts
index a821f23b41..2c2506a8c8 100644
--- a/dolphinscheduler-ui-next/src/router/routes.ts
+++ b/dolphinscheduler-ui-next/src/router/routes.ts
@@ -23,6 +23,7 @@ import resourcesPage from './modules/resources'
import datasourcePage from './modules/datasource'
import monitorPage from './modules/monitor'
import securityPage from './modules/security'
+import dataQualityPage from './modules/data-quality'
// All TSX files under the views folder automatically generate mapping relationship
const modules = import.meta.glob('/src/views/**/**.tsx')
@@ -68,7 +69,8 @@ const basePage: RouteRecordRaw[] = [
resourcesPage,
datasourcePage,
monitorPage,
- securityPage
+ securityPage,
+ dataQualityPage
]
/**
diff --git a/dolphinscheduler-ui-next/src/service/modules/data-quality/index.ts b/dolphinscheduler-ui-next/src/service/modules/data-quality/index.ts
new file mode 100644
index 0000000000..2250b633a1
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/service/modules/data-quality/index.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 { RuleListReq, ResultListReq } from './types'
+
+export function queryRuleListPaging(params: RuleListReq): any {
+ return axios({
+ url: '/data-quality/rule/page',
+ method: 'get',
+ params
+ })
+}
+
+export function queryExecuteResultListPaging(params: ResultListReq): any {
+ return axios({
+ url: '/data-quality/result/page',
+ method: 'get',
+ params
+ })
+}
diff --git a/dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts b/dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts
new file mode 100644
index 0000000000..9ad447c193
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts
@@ -0,0 +1,74 @@
+/*
+ * 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 ListReq {
+ pageNo: number
+ pageSize: number
+ searchVal?: string
+}
+
+interface RuleListReq extends ListReq {
+ endDate?: string
+ startDate?: string
+ ruleType?: string
+}
+
+interface ResultListReq extends ListReq {
+ endDate?: string
+ startDate?: string
+ ruleType?: string
+ state?: string
+}
+
+interface ResultItem {
+ id: number
+ processDefinitionId: number
+ processDefinitionName: string
+ processDefinitionCode: number
+ processInstanceId: number
+ processInstanceName: string
+ projectCode: number
+ taskInstanceId: number
+ taskName: string
+ ruleType: number
+ ruleName: string
+ statisticsValue: number
+ comparisonValue: number
+ comparisonType: number
+ comparisonTypeName: string
+ checkType: number
+ threshold: number
+ operator: number
+ failureStrategy: number
+ userId: number
+ userName: string
+ state: number
+ errorOutputPath: string
+ createTime: string
+ updateTime: string
+}
+
+interface ResultListRes {
+ totalList: ResultItem[]
+ total: number
+ totalPage: number
+ pageSize: number
+ currentPage: number
+ start: number
+}
+
+export { RuleListReq, ResultListReq, ResultItem, ResultListRes }
diff --git a/dolphinscheduler-ui-next/src/views/data-quality/task-result/index.module.scss b/dolphinscheduler-ui-next/src/views/data-quality/task-result/index.module.scss
new file mode 100644
index 0000000000..e6b0dfe014
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/data-quality/task-result/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;
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/views/data-quality/task-result/index.tsx b/dolphinscheduler-ui-next/src/views/data-quality/task-result/index.tsx
new file mode 100644
index 0000000000..3ac5311a1f
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/data-quality/task-result/index.tsx
@@ -0,0 +1,177 @@
+/*
+ * 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 TaskResult = defineComponent({
+ name: 'task-result',
+ setup() {
+ const { t, variables, getTableData, createColumns } = useTable()
+
+ const requestTableData = () => {
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ ruleType: variables.ruleType,
+ state: variables.state,
+ searchVal: variables.searchVal,
+ 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 (
+ <>
+
+
+
+
+
+
+
+ {{
+ icon: () => (
+
+
+
+ )
+ }}
+
+
+
+
+
+
+
+ >
+ )
+ }
+})
+
+export default TaskResult
diff --git a/dolphinscheduler-ui-next/src/views/data-quality/task-result/use-table.ts b/dolphinscheduler-ui-next/src/views/data-quality/task-result/use-table.ts
new file mode 100644
index 0000000000..04157d1c7f
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/data-quality/task-result/use-table.ts
@@ -0,0 +1,201 @@
+/*
+ * 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 { queryExecuteResultListPaging } from '@/service/modules/data-quality'
+import { format } from 'date-fns'
+import type {
+ ResultItem,
+ ResultListRes
+} from '@/service/modules/data-quality/types'
+
+export function useTable() {
+ const { t } = useI18n()
+
+ const variables = reactive({
+ columns: [],
+ tableData: [],
+ page: ref(1),
+ pageSize: ref(10),
+ ruleType: ref(null),
+ state: ref(null),
+ searchVal: ref(null),
+ datePickerRange: ref(null),
+ totalPage: ref(1)
+ })
+
+ const createColumns = (variables: any) => {
+ variables.columns = [
+ {
+ title: '#',
+ key: 'index'
+ },
+ {
+ title: t('data_quality.task_result.task_name'),
+ key: 'userName'
+ },
+ {
+ title: t('data_quality.task_result.workflow_instance'),
+ key: 'processInstanceName'
+ },
+ {
+ title: t('data_quality.task_result.rule_type'),
+ key: 'ruleType',
+ render: (row: ResultItem) => {
+ if (row.ruleType === 0) {
+ return t('data_quality.task_result.single_table')
+ } else if (row.ruleType === 1) {
+ return t('data_quality.task_result.single_table_custom_sql')
+ } else if (row.ruleType === 2) {
+ return t('data_quality.task_result.multi_table_accuracy')
+ } else if (row.ruleType === 3) {
+ return t('data_quality.task_result.multi_table_comparison')
+ }
+ }
+ },
+ {
+ title: t('data_quality.task_result.rule_name'),
+ key: 'ruleName'
+ },
+ {
+ title: t('data_quality.task_result.state'),
+ key: 'state',
+ render: (row: ResultItem) => {
+ if (row.state === 0) {
+ return t('data_quality.task_result.undone')
+ } else if (row.state === 1) {
+ return t('data_quality.task_result.success')
+ } else if (row.state === 2) {
+ return t('data_quality.task_result.failure')
+ }
+ }
+ },
+ {
+ title: t('data_quality.task_result.actual_value'),
+ key: 'statisticsValue'
+ },
+ {
+ title: t('data_quality.task_result.excepted_value'),
+ key: 'comparisonValue'
+ },
+ {
+ title: t('data_quality.task_result.check_type'),
+ key: 'checkType',
+ render: (row: ResultItem) => {
+ if (row.checkType === 0) {
+ return t('data_quality.task_result.expected_and_actual')
+ } else if (row.checkType === 1) {
+ return t('data_quality.task_result.actual_and_expected')
+ } else if (row.checkType === 2) {
+ return t('data_quality.task_result.actual_or_expected')
+ } else if (row.checkType === 3) {
+ return t('data_quality.task_result.expected_and_actual_or_expected')
+ }
+ }
+ },
+ {
+ title: t('data_quality.task_result.operator'),
+ key: 'operator',
+ render: (row: ResultItem) => {
+ if (row.operator === 0) {
+ return '='
+ } else if (row.operator === 1) {
+ return '<'
+ } else if (row.operator === 2) {
+ return '<='
+ } else if (row.operator === 3) {
+ return '>'
+ } else if (row.operator === 4) {
+ return '>='
+ } else if (row.operator === 5) {
+ return '!='
+ }
+ }
+ },
+ {
+ title: t('data_quality.task_result.threshold'),
+ key: 'threshold'
+ },
+ {
+ title: t('data_quality.task_result.failure_strategy'),
+ key: 'failureStrategy'
+ },
+ {
+ title: t('data_quality.task_result.excepted_value_type'),
+ key: 'comparisonTypeName'
+ },
+ {
+ title: t('data_quality.task_result.error_output_path'),
+ key: 'errorOutputPath',
+ render: (row: ResultItem) => {
+ return row.errorOutputPath ? row : '-'
+ }
+ },
+ {
+ title: t('data_quality.task_result.username'),
+ key: 'userName'
+ },
+ {
+ title: t('data_quality.task_result.create_time'),
+ key: 'createTime'
+ },
+ {
+ title: t('data_quality.task_result.update_time'),
+ key: 'updateTime'
+ }
+ ]
+ }
+
+ const getTableData = (params: any) => {
+ const data = {
+ pageSize: params.pageSize,
+ pageNo: params.pageNo,
+ ruleType: params.ruleType,
+ state: params.state,
+ searchVal: params.searchVal,
+ 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(
+ queryExecuteResultListPaging(data).then((res: ResultListRes) => {
+ variables.tableData = res.totalList.map((item, index) => {
+ return {
+ index: index + 1,
+ ...item
+ }
+ }) as any
+ }),
+ {}
+ )
+
+ return state
+ }
+
+ return {
+ t,
+ variables,
+ getTableData,
+ createColumns
+ }
+}