Browse Source

[Feature][UI Next] Add task result. (#8277)

3.0.0/version-upgrade
songjianet 3 years ago committed by GitHub
parent
commit
1f87eb6760
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      dolphinscheduler-ui-next/src/layouts/content/index.tsx
  2. 17
      dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
  3. 39
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  4. 39
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  5. 42
      dolphinscheduler-ui-next/src/router/modules/data-quality.ts
  6. 4
      dolphinscheduler-ui-next/src/router/routes.ts
  7. 35
      dolphinscheduler-ui-next/src/service/modules/data-quality/index.ts
  8. 74
      dolphinscheduler-ui-next/src/service/modules/data-quality/types.ts
  9. 26
      dolphinscheduler-ui-next/src/views/data-quality/task-result/index.module.scss
  10. 177
      dolphinscheduler-ui-next/src/views/data-quality/task-result/index.tsx
  11. 201
      dolphinscheduler-ui-next/src/views/data-quality/task-result/use-table.ts

3
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
}

17
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',

39
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
}

39
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
}

42
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
}
}
]
}

4
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
]
/**

35
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
})
}

74
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 }

26
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;
}
}

177
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 (
<>
<NCard>
<NSpace justify='end'>
<NInput
v-model={[this.searchVal, 'value']}
size='small'
placeholder={t('data_quality.task_result.task_name')}
clearable
/>
<NSelect
v-model={[this.ruleType, 'value']}
size='small'
options={[
{
value: 0,
label: t('data_quality.task_result.single_table')
},
{
value: 1,
label: t('data_quality.task_result.single_table_custom_sql')
},
{
value: 2,
label: t('data_quality.task_result.multi_table_accuracy')
},
{
value: 3,
label: t('data_quality.task_result.multi_table_comparison')
}
]}
placeholder={t('data_quality.task_result.rule_type')}
style={{ width: '180px' }}
clearable
/>
<NSelect
v-model={[this.state, 'value']}
size='small'
options={[
{
value: 0,
label: t('data_quality.task_result.undone')
},
{
value: 1,
label: t('data_quality.task_result.success')
},
{
value: 2,
label: t('data_quality.task_result.failure')
}
]}
placeholder={t('data_quality.task_result.state')}
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 TaskResult

201
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
}
}
Loading…
Cancel
Save