Browse Source

[Feature][UI Next] Add task state statistics table. (#7760)

3.0.0/version-upgrade
songjianet 3 years ago committed by GitHub
parent
commit
4514eaeb8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      dolphinscheduler-ui-next/src/components/chart/modules/Pie.tsx
  2. 5
      dolphinscheduler-ui-next/src/layouts/content/components/sidebar/index.tsx
  3. 1
      dolphinscheduler-ui-next/src/layouts/content/index.tsx
  4. 12
      dolphinscheduler-ui-next/src/service/modules/projects-analysis/types.ts
  5. 58
      dolphinscheduler-ui-next/src/views/home/definition-card.tsx
  6. 78
      dolphinscheduler-ui-next/src/views/home/index.tsx
  7. 83
      dolphinscheduler-ui-next/src/views/home/state-card.tsx
  8. 29
      dolphinscheduler-ui-next/src/views/home/types.ts
  9. 21
      dolphinscheduler-ui-next/src/views/home/use-process-definition.ts
  10. 2
      dolphinscheduler-ui-next/src/views/home/use-process-state.ts
  11. 2
      dolphinscheduler-ui-next/src/views/home/use-table.ts
  12. 31
      dolphinscheduler-ui-next/src/views/home/use-task-state.ts
  13. 36
      dolphinscheduler-ui-next/src/views/login/index.tsx

7
dolphinscheduler-ui-next/src/components/chart/modules/Pie.tsx

@ -55,13 +55,6 @@ const PieChart = defineComponent({
show: false, show: false,
position: 'center', position: 'center',
}, },
emphasis: {
label: {
show: true,
fontSize: '40',
fontWeight: 'bold',
},
},
labelLine: { labelLine: {
show: false, show: false,
}, },

5
dolphinscheduler-ui-next/src/layouts/content/components/sidebar/index.tsx

@ -22,7 +22,7 @@ import { useI18n } from 'vue-i18n'
import { useLanguageStore } from '@/store/language/language' import { useLanguageStore } from '@/store/language/language'
interface Props { interface Props {
sideMenuOptions: Array<any>, sideMenuOptions: Array<any>
isShowSide: boolean isShowSide: boolean
} }
@ -45,7 +45,8 @@ const Sidebar = (props: Props) => {
const refreshOptionsRef = ref() const refreshOptionsRef = ref()
return ( return (
<NLayoutSider style={{display: props.isShowSide ? 'block' : 'none'}} <NLayoutSider
style={{ display: props.isShowSide ? 'block' : 'none' }}
bordered bordered
nativeScrollbar={false} nativeScrollbar={false}
show-trigger='bar' show-trigger='bar'

1
dolphinscheduler-ui-next/src/layouts/content/index.tsx

@ -23,7 +23,6 @@ import { useDataList } from './use-dataList'
import { useLanguageStore } from '@/store/language/language' import { useLanguageStore } from '@/store/language/language'
const Content = () => { const Content = () => {
const { state, getHeaderMenuOptions } = useDataList() const { state, getHeaderMenuOptions } = useDataList()
const headerMenuOptions = getHeaderMenuOptions(state.menuOptions) const headerMenuOptions = getHeaderMenuOptions(state.menuOptions)

12
dolphinscheduler-ui-next/src/service/modules/projects-analysis/types.ts

@ -30,9 +30,19 @@ interface UserList {
count: number count: number
} }
interface TaskCountDto {
count: number
taskStateType: string
}
interface ProcessDefinitionRes { interface ProcessDefinitionRes {
count: number count: number
userList: UserList[] userList: UserList[]
} }
export { CodeReq, StateReq, ProcessDefinitionRes } interface TaskStateRes {
totalCount: number
taskCountDtos: TaskCountDto[]
}
export { CodeReq, StateReq, ProcessDefinitionRes, TaskStateRes }

58
dolphinscheduler-ui-next/src/views/home/definition-card.tsx

@ -0,0 +1,58 @@
/*
* 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, PropType } from 'vue'
import { useProcessDefinition } from './use-process-definition'
import BarChart from '@/components/chart/modules/Bar'
import Card from '@/components/card'
const props = {
title: {
type: String as PropType<string>,
},
}
const DefinitionCard = defineComponent({
name: 'DefinitionCard',
props,
setup() {
const { getProcessDefinition } = useProcessDefinition()
const processDefinition = getProcessDefinition()
return { processDefinition }
},
render() {
const { title, processDefinition } = this
return (
<Card title={title}>
{{
default: () =>
processDefinition.xAxisData.length > 0 &&
processDefinition.seriesData.length > 0 && (
<BarChart
xAxisData={processDefinition.xAxisData}
seriesData={processDefinition.seriesData}
/>
),
}}
</Card>
)
},
})
export default DefinitionCard

78
dolphinscheduler-ui-next/src/views/home/index.tsx

@ -15,75 +15,57 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineComponent } from 'vue' import { defineComponent, Ref, onMounted, ref, watch } from 'vue'
import { NGrid, NGi, NDataTable } from 'naive-ui' import { NGrid, NGi } from 'naive-ui'
import { startOfToday, getTime } from 'date-fns'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useTable } from './use-table' import { useTaskState } from './use-task-state'
import { useProcessDefinition } from './use-process-definition' import StateCard from './state-card'
import Card from '@/components/card' import DefinitionCard from './definition-card'
import PieChart from '@/components/chart/modules/Pie'
import BarChart from '@/components/chart/modules/Bar'
import styles from './index.module.scss' import styles from './index.module.scss'
import type { ProcessDefinitionRes } from '@/service/modules/projects-analysis/types'
export default defineComponent({ export default defineComponent({
name: 'home', name: 'home',
setup() { setup() {
const { t } = useI18n() const { t } = useI18n()
const { getProcessDefinition, formatProcessDefinition } = const dateRef = ref([getTime(startOfToday()), Date.now()])
useProcessDefinition() const { getTaskState } = useTaskState()
const processDefinition = getProcessDefinition() let taskStateRef: Ref<any> = ref([])
return { t, processDefinition, formatProcessDefinition } onMounted(() => {
taskStateRef.value = getTaskState(dateRef.value)
})
const handleTaskDate = (val: any) => {
taskStateRef.value = getTaskState(val)
}
return { t, dateRef, handleTaskDate, taskStateRef }
}, },
render() { render() {
const { columnsRef } = useTable() const { t, dateRef, handleTaskDate } = this
const { t, processDefinition, formatProcessDefinition } = this
const chartData =
Object.keys(processDefinition).length > 0 &&
formatProcessDefinition(processDefinition as ProcessDefinitionRes)
return ( return (
<div> <div>
<NGrid x-gap={12} cols={2}> <NGrid x-gap={12} cols={2}>
<NGi> <NGi>
<Card title={t('home.task_state_statistics')}> <StateCard
{{ title={t('home.task_state_statistics')}
default: () => ( date={dateRef}
<div class={styles['card-table']}> tableData={this.taskStateRef.value}
<PieChart /> onUpdateDatePickerValue={handleTaskDate}
<NDataTable columns={columnsRef} /> />
</div>
),
}}
</Card>
</NGi> </NGi>
<NGi class={styles['card-table']}> <NGi class={styles['card-table']}>
<Card title={t('home.process_state_statistics')}> <StateCard
{{ title={t('home.process_state_statistics')}
default: () => ( date={dateRef}
<div class={styles['card-table']}> />
<PieChart />
<NDataTable columns={columnsRef} />
</div>
),
}}
</Card>
</NGi> </NGi>
</NGrid> </NGrid>
<NGrid cols={1} style='margin-top: 12px;'> <NGrid cols={1} style='margin-top: 12px;'>
<NGi> <NGi>
<Card title={t('home.process_definition_statistics')}> <DefinitionCard title={t('home.process_definition_statistics')} />
{{
default: () =>
chartData && (
<BarChart
xAxisData={chartData.xAxisData}
seriesData={chartData.seriesData}
/>
),
}}
</Card>
</NGi> </NGi>
</NGrid> </NGrid>
</div> </div>

83
dolphinscheduler-ui-next/src/views/home/state-card.tsx

@ -0,0 +1,83 @@
/*
* 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, PropType } from 'vue'
import { useTable } from './use-table'
import styles from '@/views/home/index.module.scss'
import PieChart from '@/components/chart/modules/Pie'
import { NDataTable, NDatePicker } from 'naive-ui'
import Card from '@/components/card'
const props = {
title: {
type: String as PropType<string>,
},
date: {
type: Array as PropType<Array<any>>,
},
tableData: {
type: [Array, Boolean] as PropType<Array<any> | false>,
},
}
const StateCard = defineComponent({
name: 'StateCard',
props,
emits: ['updateDatePickerValue'],
setup(props, ctx) {
const onUpdateDatePickerValue = (val: any) => {
ctx.emit('updateDatePickerValue', val)
}
return { onUpdateDatePickerValue }
},
render() {
const { title, date, tableData, onUpdateDatePickerValue } = this
const { columnsRef } = useTable()
return (
<Card title={title}>
{{
default: () => (
<div class={styles['card-table']}>
<PieChart />
{tableData && (
<NDataTable
columns={columnsRef}
data={tableData}
striped
size={'small'}
/>
)}
</div>
),
'header-extra': () => (
<NDatePicker
default-value={date}
onUpdateValue={onUpdateDatePickerValue}
size='small'
type='datetimerange'
clearable
/>
),
}}
</Card>
)
},
})
export default StateCard

29
dolphinscheduler-ui-next/src/views/home/types.ts

@ -0,0 +1,29 @@
/*
* 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 ChartData {
xAxisData: Array<string>
seriesData: Array<number>
}
interface TaskStateTableData {
id: number
number: number
state: string
}
export { ChartData, TaskStateTableData }

21
dolphinscheduler-ui-next/src/views/home/use-process-definition.ts

@ -18,22 +18,23 @@
import { useAsyncState } from '@vueuse/core' import { useAsyncState } from '@vueuse/core'
import { countDefinitionByUser } from '@/service/modules/projects-analysis' import { countDefinitionByUser } from '@/service/modules/projects-analysis'
import type { ProcessDefinitionRes } from '@/service/modules/projects-analysis/types' import type { ProcessDefinitionRes } from '@/service/modules/projects-analysis/types'
import type { ChartData } from './types'
export function useProcessDefinition() { export function useProcessDefinition() {
const getProcessDefinition = () => { const getProcessDefinition = () => {
const { state } = useAsyncState( const { state } = useAsyncState(
countDefinitionByUser({ projectCode: 0 }), countDefinitionByUser({ projectCode: 0 }).then(
{} (res: ProcessDefinitionRes): ChartData => {
) const xAxisData = res.userList.map((item) => item.userName)
return state const seriesData = res.userList.map((item) => item.count)
}
const formatProcessDefinition = (data: ProcessDefinitionRes) => {
const xAxisData: Array<string> = data.userList.map((item) => item.userName)
const seriesData: Array<number> = data.userList.map((item) => item.count)
return { xAxisData, seriesData } return { xAxisData, seriesData }
} }
),
{ xAxisData: [], seriesData: [] }
)
return state
}
return { getProcessDefinition, formatProcessDefinition } return { getProcessDefinition }
} }

2
dolphinscheduler-ui-next/src/views/home/use-process-state.ts

@ -14,3 +14,5 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { useAsyncState } from '@vueuse/core'

2
dolphinscheduler-ui-next/src/views/home/use-table.ts

@ -22,7 +22,7 @@ export function useTable() {
const { t } = useI18n() const { t } = useI18n()
const columnsRef: TableColumns<any> = [ const columnsRef: TableColumns<any> = [
{ title: '#', key: '#' }, { title: '#', key: 'id' },
{ title: t('home.number'), key: 'number' }, { title: t('home.number'), key: 'number' },
{ title: t('home.state'), key: 'state' }, { title: t('home.state'), key: 'state' },
] ]

31
dolphinscheduler-ui-next/src/views/home/use-task-state.ts

@ -14,3 +14,34 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { useAsyncState } from '@vueuse/core'
import { format } from 'date-fns'
import { countTaskState } from '@/service/modules/projects-analysis'
import type { TaskStateRes } from '@/service/modules/projects-analysis/types'
import type { TaskStateTableData } from './types'
export function useTaskState() {
const getTaskState = (date: Array<number>) => {
const { state } = useAsyncState(
countTaskState({
startDate: format(date[0], 'yyyy-MM-dd HH:mm:ss'),
endDate: format(date[1], 'yyyy-MM-dd HH:mm:ss'),
projectCode: 0,
}).then((res: TaskStateRes): Array<TaskStateTableData> => {
return res.taskCountDtos.map((item, index) => {
return {
id: index + 1,
state: item.taskStateType,
number: item.count,
}
})
}),
[]
)
return state
}
return { getTaskState }
}

36
dolphinscheduler-ui-next/src/views/login/index.tsx

@ -15,25 +15,30 @@
* limitations under the License. * limitations under the License.
*/ */
import { withKeys } from 'vue' import { defineComponent, toRefs, withKeys } from 'vue'
import styles from './index.module.scss' import styles from './index.module.scss'
import { NInput, NButton, NSwitch, NForm, NFormItem } from 'naive-ui' import { NInput, NButton, NSwitch, NForm, NFormItem } from 'naive-ui'
import { useValidate } from './use-validate' import { useValidate } from './use-validate'
import { useTranslate } from './use-translate' import { useTranslate } from './use-translate'
import { useLogin } from './use-login' import { useLogin } from './use-login'
const login = () => { const login = defineComponent({
name: 'login',
setup() {
const { state, t, locale } = useValidate() const { state, t, locale } = useValidate()
const { handleChange } = useTranslate(locale) const { handleChange } = useTranslate(locale)
const { handleLogin } = useLogin(state) const { handleLogin } = useLogin(state)
return { t, handleChange, handleLogin, ...toRefs(state) }
},
render() {
return ( return (
<div class={styles.container}> <div class={styles.container}>
<div class={styles['language-switch']}> <div class={styles['language-switch']}>
<NSwitch <NSwitch
onUpdateValue={handleChange} onUpdateValue={this.handleChange}
checked-value='en_US' checked-value='en_US'
unchecked-value='zh_CN' unchecked-value='zh_CN'
> >
@ -48,32 +53,32 @@ const login = () => {
<div class={styles['logo-img']} /> <div class={styles['logo-img']} />
</div> </div>
<div class={styles['form-model']}> <div class={styles['form-model']}>
<NForm rules={state.rules} ref='loginFormRef'> <NForm rules={this.rules} ref='loginFormRef'>
<NFormItem <NFormItem
label={t('login.userName')} label={this.t('login.userName')}
label-style={{ color: 'black' }} label-style={{ color: 'black' }}
path='userName' path='userName'
> >
<NInput <NInput
type='text' type='text'
size='large' size='large'
v-model={[state.loginForm.userName, 'value']} v-model={[this.loginForm.userName, 'value']}
placeholder={t('login.userName_tips')} placeholder={this.t('login.userName_tips')}
autofocus autofocus
onKeydown={withKeys(handleLogin, ['enter'])} onKeydown={withKeys(this.handleLogin, ['enter'])}
/> />
</NFormItem> </NFormItem>
<NFormItem <NFormItem
label={t('login.userPassword')} label={this.t('login.userPassword')}
label-style={{ color: 'black' }} label-style={{ color: 'black' }}
path='userPassword' path='userPassword'
> >
<NInput <NInput
type='password' type='password'
size='large' size='large'
v-model={[state.loginForm.userPassword, 'value']} v-model={[this.loginForm.userPassword, 'value']}
placeholder={t('login.userPassword_tips')} placeholder={this.t('login.userPassword_tips')}
onKeydown={withKeys(handleLogin, ['enter'])} onKeydown={withKeys(this.handleLogin, ['enter'])}
/> />
</NFormItem> </NFormItem>
</NForm> </NForm>
@ -81,14 +86,15 @@ const login = () => {
round round
type='info' type='info'
style={{ width: '100%' }} style={{ width: '100%' }}
onClick={handleLogin} onClick={this.handleLogin}
> >
{t('login.login')} {this.t('login.login')}
</NButton> </NButton>
</div> </div>
</div> </div>
</div> </div>
) )
} },
})
export default login export default login

Loading…
Cancel
Save