mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-12-12 12:15:54 +08:00
Rafactor UI for dataset (#708)
This commit is contained in:
commit
0663a001b2
@ -26,6 +26,7 @@
|
||||
"echarts": "^5.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-vue-next": "^0.356.0",
|
||||
"md-editor-v3": "^4.12.1",
|
||||
"radix-vue": "^1.5.2",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {createI18n} from 'vue-i18n'
|
||||
import messages from '@/i18n/langs'
|
||||
|
||||
const language = (navigator.language || 'en').toLocaleLowerCase();
|
||||
const language = (navigator.language || 'en').toLocaleLowerCase()
|
||||
|
||||
const i18n = createI18n({
|
||||
fallbackLocale: 'zh_cn',
|
||||
@ -15,6 +15,6 @@ const i18n = createI18n({
|
||||
missingWarn: false,
|
||||
locale: localStorage.getItem('lang') || language.split('-')[0] || 'en',
|
||||
messages
|
||||
});
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
@ -53,4 +53,18 @@ export default {
|
||||
value: 'Value',
|
||||
alias: 'Alias',
|
||||
sort: 'Sort',
|
||||
count: 'Count',
|
||||
content: 'Content',
|
||||
feedback: 'Feedback',
|
||||
selectLanguage: 'Select Language',
|
||||
region: {
|
||||
asia: {
|
||||
common: 'Asia',
|
||||
chineseSimple: 'Simple Chinese'
|
||||
},
|
||||
northAmerica: {
|
||||
common: 'North America',
|
||||
english: 'English'
|
||||
}
|
||||
}
|
||||
}
|
@ -45,7 +45,6 @@ export default {
|
||||
syncModeTiming: 'Timing synchronization',
|
||||
syncModeOutSync: 'Out Sync',
|
||||
rebuild: 'Rebuild',
|
||||
rebuildProgress: 'Rebuilding will only progress unfinished',
|
||||
complete: 'Complete',
|
||||
failed: 'Failed',
|
||||
stateOfStart: 'Start',
|
||||
@ -54,8 +53,6 @@ export default {
|
||||
stateOfCreateTable: 'Create Table State',
|
||||
modifyNotSupportDataPreview: 'Data preview is not supported to modify',
|
||||
syncData: 'Sync Data',
|
||||
syncDataTip: 'The data synchronization schedule will run in the background, see the logs for the specific synchronization results',
|
||||
adhocDndTip: 'Drag the indicator dimension on the left to the corresponding position to query and render the data',
|
||||
visualType: 'Visual Type',
|
||||
visualTypeTable: 'Table',
|
||||
visualTypeLine: 'Line',
|
||||
@ -98,17 +95,24 @@ export default {
|
||||
columnExpressionLessThan: 'Less Than',
|
||||
columnExpressionLessThanOrEquals: 'Less Than Or Equals',
|
||||
columnExpressionIsNotContains: 'Is Not Contains',
|
||||
validatorSamplingTip: 'The order by key must contain a sampling key',
|
||||
customFunction: 'Custom Function',
|
||||
clearDataTip: 'Clear data will not be able to rollback, clear operation will run in the background, please be patient',
|
||||
lifeCycleTip: 'Data set life cycle will be calculated according to the specified list expression',
|
||||
lifeCycleMonth: 'Month',
|
||||
lifeCycleWeek: 'Week',
|
||||
lifeCycleDay: 'Day',
|
||||
lifeCycleHour: 'Hour',
|
||||
notSpecifiedTitle: 'Not Specified',
|
||||
history: 'Sync History',
|
||||
clearData: 'Clear Data',
|
||||
error: 'View Error',
|
||||
info: 'View Info',
|
||||
},
|
||||
tip: {
|
||||
selectExpressionTip: 'Please select the expression',
|
||||
selectExpression: 'Please select the expression',
|
||||
syncData: 'The data synchronization schedule will run in the background, see the logs for the specific synchronization results',
|
||||
clearData: 'Clear data will not be able to rollback, clear operation will run in the background, please be patient',
|
||||
lifeCycle: 'Data set life cycle will be calculated according to the specified list expression',
|
||||
validatorSampling: 'The order by key must contain a sampling key',
|
||||
adhocDnd: 'Drag the indicator dimension on the left to the corresponding position to query and render the data',
|
||||
rebuildProgress: 'Rebuilding will only progress unfinished',
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import role from '@/i18n/langs/zhCn/role'
|
||||
import schedule from '@/i18n/langs/en/schedule'
|
||||
import dashboard from '@/i18n/langs/en/dashboard'
|
||||
import dataset from '@/i18n/langs/en/dataset'
|
||||
import state from '@/i18n/langs/en/state'
|
||||
|
||||
export default {
|
||||
common: common,
|
||||
@ -11,5 +12,6 @@ export default {
|
||||
role: role,
|
||||
schedule: schedule,
|
||||
dashboard: dashboard,
|
||||
dataset: dataset
|
||||
dataset: dataset,
|
||||
state: state
|
||||
}
|
||||
|
11
core/datacap-ui/src/i18n/langs/en/state.ts
Normal file
11
core/datacap-ui/src/i18n/langs/en/state.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export default {
|
||||
common: {
|
||||
create: 'Created',
|
||||
running: 'Running',
|
||||
success: 'Success',
|
||||
failure: 'Failure',
|
||||
stop: 'Stopped',
|
||||
timeout: 'Timeout',
|
||||
queue: 'Queue'
|
||||
}
|
||||
}
|
@ -53,4 +53,18 @@ export default {
|
||||
value: '值',
|
||||
alias: '别名',
|
||||
sort: '排序',
|
||||
count: '总数',
|
||||
content: '内容',
|
||||
feedback: '反馈',
|
||||
selectLanguage: '选择语言',
|
||||
region: {
|
||||
asia: {
|
||||
common: '亚洲',
|
||||
chineseSimple: '简体中文'
|
||||
},
|
||||
northAmerica: {
|
||||
common: '北美洲',
|
||||
english: '英语'
|
||||
}
|
||||
}
|
||||
}
|
@ -44,8 +44,7 @@ export default {
|
||||
syncModeManual: '手动',
|
||||
syncModeTiming: '定时同步',
|
||||
syncModeOutSync: '不同步',
|
||||
rebuild: '重建',
|
||||
rebuildProgress: '重建只会进行未完成进度',
|
||||
rebuild: '重新构建',
|
||||
complete: '完成',
|
||||
failed: '失败',
|
||||
stateOfStarted: '已启动',
|
||||
@ -54,8 +53,6 @@ export default {
|
||||
stateOfCreateTable: '创建表状态',
|
||||
modifyNotSupportDataPreview: '修改暂不支持数据预览',
|
||||
syncData: '同步数据',
|
||||
syncDataTip: '数据同步计划将在后台运行,具体同步结果请参考日志',
|
||||
adhocDndTip: '拖拽左侧指标|维度到相应位置即可查询并渲染数据',
|
||||
visualType: '可视化类型',
|
||||
visualTypeTable: '表格',
|
||||
visualTypeLine: '折线图',
|
||||
@ -98,17 +95,24 @@ export default {
|
||||
columnExpressionGreaterThanOrEquals: '大于等于',
|
||||
columnExpressionLessThan: '小于',
|
||||
columnExpressionLessThanOrEquals: '小于等于',
|
||||
validatorSamplingTip: '排序键中必须包含抽样键',
|
||||
customFunction: '自定义函数',
|
||||
clearDataTip: '清除数据后无法进行回滚,清除操作将在后台运行,请耐心等待',
|
||||
lifeCycleTip: '数据集生命周期会根据指定列表达式进行计算',
|
||||
lifeCycleMonth: '月',
|
||||
lifeCycleWeek: '周',
|
||||
lifeCycleDay: '天',
|
||||
lifeCycleHour: '小时',
|
||||
notSpecifiedTitle: '未指定'
|
||||
notSpecifiedTitle: '未指定',
|
||||
history: '同步历史',
|
||||
clearData: '清除数据',
|
||||
error: '查看错误',
|
||||
info: '查看详情',
|
||||
},
|
||||
tip: {
|
||||
selectExpressionTip: '请选择表达式'
|
||||
selectExpression: '请选择表达式',
|
||||
syncData: '数据同步计划将在后台运行,具体同步结果请参考日志',
|
||||
clearData: '清除数据后无法进行回滚,清除操作将在后台运行,请耐心等待',
|
||||
lifeCycle: '数据集生命周期会根据指定列表达式进行计算',
|
||||
validatorSampling: '排序键中必须包含抽样键',
|
||||
adhocDnd: '拖拽左侧指标|维度到相应位置即可查询并渲染数据',
|
||||
rebuildProgress: '重建只会进行未完成进度',
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import role from '@/i18n/langs/zhCn/role'
|
||||
import schedule from '@/i18n/langs/zhCn/schedule'
|
||||
import dashboard from '@/i18n/langs/zhCn/dashboard'
|
||||
import dataset from '@/i18n/langs/zhCn/dataset'
|
||||
import state from '@/i18n/langs/zhCn/state'
|
||||
|
||||
export default {
|
||||
common: common,
|
||||
@ -11,5 +12,6 @@ export default {
|
||||
role: role,
|
||||
schedule: schedule,
|
||||
dashboard: dashboard,
|
||||
dataset: dataset
|
||||
dataset: dataset,
|
||||
state: state
|
||||
}
|
||||
|
11
core/datacap-ui/src/i18n/langs/zhCn/state.ts
Normal file
11
core/datacap-ui/src/i18n/langs/zhCn/state.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export default {
|
||||
common: {
|
||||
create: '已创建',
|
||||
running: '运行中',
|
||||
success: '运行成功',
|
||||
failure: '运行失败',
|
||||
stop: '已停止',
|
||||
timeout: '运行超时',
|
||||
queue: '排队中'
|
||||
}
|
||||
}
|
19
core/datacap-ui/src/model/dataset.ts
Normal file
19
core/datacap-ui/src/model/dataset.ts
Normal file
@ -0,0 +1,19 @@
|
||||
export interface DatasetModel {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
query: string
|
||||
syncMode: string
|
||||
expression: string
|
||||
state: Array<string>
|
||||
message: string
|
||||
tableName: string
|
||||
code: string
|
||||
scheduler: string
|
||||
executor: string
|
||||
totalRows: number
|
||||
totalSize: string
|
||||
lifeCycle: string
|
||||
lifeCycleColumn: string
|
||||
lifeCycleType: string
|
||||
}
|
@ -118,6 +118,15 @@ const createAdminRouter = (router: any) => {
|
||||
},
|
||||
component: () => import('@/views/pages/admin/dataset/DatasetHome.vue')
|
||||
},
|
||||
{
|
||||
path: 'dataset/info/:code?',
|
||||
layout: LayoutContainer,
|
||||
meta: {
|
||||
title: 'common.dataset',
|
||||
isRoot: false
|
||||
},
|
||||
component: () => import('@/views/pages/admin/dataset/DatasetInfo.vue')
|
||||
},
|
||||
{
|
||||
path: 'dataset/adhoc/:code',
|
||||
layout: LayoutContainer,
|
||||
@ -126,6 +135,15 @@ const createAdminRouter = (router: any) => {
|
||||
isRoot: false
|
||||
},
|
||||
component: () => import('@/views/pages/admin/dataset/DatasetAdhoc.vue')
|
||||
},
|
||||
{
|
||||
path: 'dataset/adhoc/:code/:id',
|
||||
layout: LayoutContainer,
|
||||
meta: {
|
||||
title: 'common.dataset',
|
||||
isRoot: false
|
||||
},
|
||||
component: () => import('@/views/pages/admin/dataset/DatasetAdhoc.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ResponseModel } from '@/model/response'
|
||||
import { BaseService } from '@/services/base'
|
||||
import { HttpUtils } from '@/utils/http'
|
||||
import { FilterModel } from '@/model/filter'
|
||||
|
||||
const DEFAULT_PATH = '/api/v1/dataset'
|
||||
|
||||
@ -34,6 +35,51 @@ export class DatasetService
|
||||
{
|
||||
return new HttpUtils().get(`${DEFAULT_PATH}/columns/${code}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the specified item identified by the given ID.
|
||||
*
|
||||
* @param {number} id - the ID of the item to be rebuilt
|
||||
* @return {Promise<ResponseModel>} a Promise that resolves with the response from the rebuild request
|
||||
*/
|
||||
rebuild(id: number): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().put(`${DEFAULT_PATH}/rebuild/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the history for a given code using the provided pagination model.
|
||||
*
|
||||
* @param {string} code - The code for which to retrieve the history.
|
||||
* @param {FilterModel} configure - The file model to use for the request.
|
||||
* @return {Promise<ResponseModel>} A promise that resolves with the response model containing the history data.
|
||||
*/
|
||||
getHistory(code: string, configure: FilterModel): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().post(`${DEFAULT_PATH}/history/${code}`, configure)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync data with the server using the provided id.
|
||||
*
|
||||
* @param {number} id - The id of the data to sync
|
||||
* @return {Promise<ResponseModel>} A promise that resolves with the response from the server
|
||||
*/
|
||||
syncData(id: number): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().put(`${DEFAULT_PATH}/syncData/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the data associated with the given code.
|
||||
*
|
||||
* @param {string} code - the code for which data needs to be cleared
|
||||
* @return {Promise<ResponseModel>} a Promise that resolves with the response from the server
|
||||
*/
|
||||
clearData(code: string): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().put(`${DEFAULT_PATH}/clearData/${code}`)
|
||||
}
|
||||
}
|
||||
|
||||
export default new DatasetService()
|
||||
|
@ -11,9 +11,64 @@ const getCurrentUserId = (): number => {
|
||||
return JSON.parse(localStorage.getItem(token) || '{}').id
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the text based on the given origin value.
|
||||
*
|
||||
* @param {any} i18n - the internationalization object
|
||||
* @param {string} origin - the origin value to determine the text to retrieve
|
||||
* @return {string} the text based on the origin value
|
||||
*/
|
||||
const getText = (i18n: any, origin: string): string => {
|
||||
switch (origin) {
|
||||
case 'CREATED':
|
||||
return i18n.t('state.common.create')
|
||||
case 'RUNNING':
|
||||
return i18n.t('state.common.running')
|
||||
case 'SUCCESS':
|
||||
return i18n.t('state.common.success')
|
||||
case 'FAILURE':
|
||||
return i18n.t('state.common.failure')
|
||||
case 'STOPPED':
|
||||
return i18n.t('state.common.stop')
|
||||
case 'TIMEOUT':
|
||||
return i18n.t('state.common.timeout')
|
||||
case 'QUEUE':
|
||||
return i18n.t('state.common.queue')
|
||||
default:
|
||||
return origin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color based on the origin.
|
||||
*
|
||||
* @param {string} origin - The origin value.
|
||||
* @return {string} The color based on the origin.
|
||||
*/
|
||||
const getColor = (origin: string): string => {
|
||||
switch (origin) {
|
||||
case 'CREATED':
|
||||
return 'hsl(220.9 39.3% 11%)'
|
||||
case 'RUNNING':
|
||||
return 'hsl(221.2 83.2% 53.3%)'
|
||||
case 'SUCCESS':
|
||||
return 'hsl(142.1 76.2% 36.3%)'
|
||||
case 'FAILURE':
|
||||
return 'hsl(346.8 77.2% 49.8%)'
|
||||
case 'STOPPED':
|
||||
return '#17233d'
|
||||
case 'TIMEOUT':
|
||||
return 'hsl(47.9 95.8% 53.1%)'
|
||||
default:
|
||||
return 'hsl(24.6 95% 53.1%)'
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
token: token,
|
||||
menu: menu,
|
||||
getCurrentUserId: getCurrentUserId,
|
||||
userEditorConfigure: userEditorConfigure
|
||||
userEditorConfigure: userEditorConfigure,
|
||||
getText: getText,
|
||||
getColor: getColor
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<AlertDialog :default-open="visible">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle class="border-b -mt-4 pb-2">{{ $t('common.content') }}</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<MdPreview v-if="content" :modelValue="content" style="padding: 0"/>
|
||||
<AlertDialogFooter class="-mb-4 border-t pt-2">
|
||||
<Button variant="outline" @click="handlerCancel">{{ $t('common.cancel') }}</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { AlertDialog, AlertDialogContent, AlertDialogFooter, AlertDialogHeader } from '@/components/ui/alert-dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { MdPreview } from 'md-editor-v3'
|
||||
import 'md-editor-v3/lib/style.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MarkdownPreview',
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AlertDialogFooter, Button, AlertDialogHeader, AlertDialogContent, AlertDialog,
|
||||
MdPreview
|
||||
},
|
||||
methods: {
|
||||
handlerCancel()
|
||||
{
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.md-editor-preview-wrapper) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.default-theme pre) {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<Alert v-if="configuration?.headers.length === 0 && !configuration?.message" class="mt-20">
|
||||
<AlertDescription>
|
||||
{{ $t('dataset.common.adhocDndTip') }}
|
||||
{{ $t('dataset.tip.adhocDnd') }}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert v-else-if="configuration?.message" variant="destructive" class="mt-20">
|
||||
|
@ -53,6 +53,7 @@ export default defineComponent({
|
||||
x2Field: this.configuration.chartConfigure?.x2Axis,
|
||||
yField: this.configuration.chartConfigure?.yAxis
|
||||
}
|
||||
console.log(options)
|
||||
if (!reset) {
|
||||
instance = new VChart(options, {dom: this.$refs.content as HTMLElement})
|
||||
instance.renderAsync()
|
||||
|
@ -45,12 +45,16 @@ export default defineComponent({
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (this.configuration) {
|
||||
let outerRadius = 0.8
|
||||
if (this.configuration.chartConfigure?.outerRadius) {
|
||||
outerRadius = this.configuration.chartConfigure?.outerRadius[0]
|
||||
}
|
||||
const options = {
|
||||
type: 'pie',
|
||||
data: [{values: this.configuration.columns}],
|
||||
categoryField: this.configuration.chartConfigure?.xAxis,
|
||||
valueField: this.configuration.chartConfigure?.yAxis,
|
||||
outerRadius: this.configuration.chartConfigure?.outerRadius[0]
|
||||
outerRadius: outerRadius
|
||||
}
|
||||
if (!reset) {
|
||||
instance = new VChart(options, {dom: this.$refs.content as HTMLElement})
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="hidden flex-col md:flex">
|
||||
<LayoutHeader></LayoutHeader>
|
||||
<LayoutHeader @changeLanguage="setLangCondition($event)"></LayoutHeader>
|
||||
<LayoutBreadcrumb></LayoutBreadcrumb>
|
||||
<div class="flex-1 space-y-4 pl-8 pr-8">
|
||||
<RouterView></RouterView>
|
||||
@ -11,14 +11,70 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent} from 'vue'
|
||||
import LayoutHeader from '@/views/layouts/common/components/LayoutHeader.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import LayoutBreadcrumb from '@/views/layouts/common/components/LayoutBreadcrumb.vue';
|
||||
import { defineComponent } from 'vue'
|
||||
import LayoutHeader from '@/views/layouts/common/components/LayoutHeader.vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import LayoutBreadcrumb from '@/views/layouts/common/components/LayoutBreadcrumb.vue'
|
||||
import { TokenUtils } from '@/utils/token'
|
||||
import { ObjectUtils } from '@/utils/object'
|
||||
import { HttpUtils } from '@/utils/http'
|
||||
import UserService from '@/services/user'
|
||||
import CommonUtils from '@/utils/common'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutContainer',
|
||||
components: {LayoutBreadcrumb, AvatarFallback, AvatarImage, Avatar, Button, LayoutHeader}
|
||||
components: {LayoutBreadcrumb, AvatarFallback, AvatarImage, Avatar, Button, LayoutHeader},
|
||||
beforeUnmount()
|
||||
{
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
setup()
|
||||
{
|
||||
const {locale} = useI18n()
|
||||
const setLangCondition = (language: string) => {
|
||||
const prefix = 'language_'
|
||||
if (language.startsWith(prefix)) {
|
||||
locale.value = language.substring(prefix.length)
|
||||
}
|
||||
else {
|
||||
locale.value = language
|
||||
}
|
||||
}
|
||||
return {
|
||||
setLangCondition
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
timer: null as any
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
},
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
const user = TokenUtils.getAuthUser()
|
||||
if (ObjectUtils.isNotEmpty(user)) {
|
||||
this.timer = setInterval(() => {
|
||||
const runTime = new Date().toLocaleTimeString()
|
||||
console.log(`[DataCap] refresh on time ${runTime}`)
|
||||
const client = new HttpUtils().getAxios()
|
||||
client.all([UserService.getMenus(), UserService.getInfo()])
|
||||
.then(client.spread((fetchMenu, fetchInfo) => {
|
||||
if (fetchMenu.status && fetchInfo.status) {
|
||||
localStorage.setItem(CommonUtils.menu, JSON.stringify(fetchMenu.data))
|
||||
localStorage.setItem(CommonUtils.userEditorConfigure, JSON.stringify(fetchInfo.data.editorConfigure))
|
||||
}
|
||||
}))
|
||||
}, 1000 * 60)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -37,6 +37,21 @@
|
||||
</div>
|
||||
<!-- Controller -->
|
||||
<div class="flex items-center">
|
||||
<div class="mr-3 mt-1.5">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<a target="_blank" href="https://github.com/devlive-community/datacap/issues/new/choose">
|
||||
<CircleHelp :size="20"/>
|
||||
</a>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ $t('common.feedback') }}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
<div class="ml-3 mr-5 mt-0.5">
|
||||
<LanguageSwitcher @changeLanguage="handlerChangeLanguage($event)"/>
|
||||
</div>
|
||||
<div v-if="isLoggedIn" class="flex gap-x-2">
|
||||
<RouterLink to="/auth/signin">
|
||||
<Button size="sm" variant="outline">{{ $t('user.common.signin') }}</Button>
|
||||
@ -114,7 +129,9 @@ import {
|
||||
navigationMenuTriggerStyle
|
||||
} from '@/components/ui/navigation-menu'
|
||||
import NavigationMenuListItem from '@/views/layouts/common/components/components/NavigationMenuListItem.vue'
|
||||
import { LogOut, User } from 'lucide-vue-next'
|
||||
import { CircleHelp, LogOut, User } from 'lucide-vue-next'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import LanguageSwitcher from '@/views/layouts/common/components/components/LanguageSwitcher.vue'
|
||||
|
||||
interface NavigationItem
|
||||
{
|
||||
@ -157,14 +174,23 @@ export default defineComponent({
|
||||
logout
|
||||
}
|
||||
},
|
||||
methods: {navigationMenuTriggerStyle, cn},
|
||||
components: {
|
||||
LanguageSwitcher,
|
||||
TooltipContent, Tooltip, TooltipTrigger, TooltipProvider,
|
||||
NavigationMenuLink, NavigationMenuContent, NavigationMenuTrigger, NavigationMenuItem, NavigationMenuList, NavigationMenu,
|
||||
DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuItem, DropdownMenuShortcut, DropdownMenuContent, DropdownMenuTrigger, DropdownMenu,
|
||||
AvatarFallback, AvatarImage, Avatar,
|
||||
NavigationMenuListItem,
|
||||
Button,
|
||||
LogOut, User
|
||||
CircleHelp, LogOut, User
|
||||
},
|
||||
methods: {
|
||||
navigationMenuTriggerStyle,
|
||||
cn,
|
||||
handlerChangeLanguage(language: string)
|
||||
{
|
||||
this.$emit('changeLanguage', language)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<Select v-model="language" @update:modelValue="handlerChangeLang">
|
||||
<SelectTrigger class="w-[150px]">
|
||||
<SelectValue :placeholder="$t('common.selectLanguage')"/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>{{ $t('common.region.asia.common') }}</SelectLabel>
|
||||
<SelectItem class="pl-6" value="language_zh">{{ $t('common.region.asia.chineseSimple') }}</SelectItem>
|
||||
<SelectLabel>{{ $t('common.region.northAmerica.common') }}</SelectLabel>
|
||||
<SelectItem class="pl-6" value="language_en">{{ $t('common.region.northAmerica.english') }}</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LanguageSwitcher',
|
||||
components: {
|
||||
Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
language: 'language_zh'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlerChangeLang()
|
||||
{
|
||||
this.$emit('changeLanguage', this.language)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
113
core/datacap-ui/src/views/pages/admin/dataset/DatasetClear.vue
Normal file
113
core/datacap-ui/src/views/pages/admin/dataset/DatasetClear.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div>
|
||||
<AlertDialog :default-open="visible">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle class="border-b -mt-4 pb-2">
|
||||
{{ `[ ${info?.name} ] ${$t('dataset.common.clearData')}` }}
|
||||
</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<Alert variant="destructive">
|
||||
<AlertTitle>{{ $t('dataset.tip.clearData') }}</AlertTitle>
|
||||
</Alert>
|
||||
<div class="flex">
|
||||
<Card class="left text-center w-1/2">
|
||||
<CardHeader class="border-b p-4">
|
||||
<CardTitle>{{ $t('dataset.common.totalRows') }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="mt-3">
|
||||
<p>{{ info?.totalRows }}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card class="ml-3 right text-center w-1/2">
|
||||
<CardHeader class="border-b p-4">
|
||||
<CardTitle>{{ $t('dataset.common.totalSize') }}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="mt-3">
|
||||
<p>{{ info?.totalSize }}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<AlertDialogFooter class="-mb-4 border-t pt-2">
|
||||
<Button variant="outline" @click="handlerCancel">{{ $t('common.cancel') }}</Button>
|
||||
<Button :disabled="loading" @click="handlerSubmit">
|
||||
<Loader2 v-if="loading" class="w-full justify-center animate-spin"/>
|
||||
{{ $t('dataset.common.clearData') }}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import DatasetService from '@/services/dataset'
|
||||
import { DatasetModel } from '@/model/dataset'
|
||||
import { ToastUtils } from '@/utils/toast'
|
||||
import { AlertDialog, AlertDialogContent, AlertDialogFooter, AlertDialogHeader } from '@/components/ui/alert-dialog'
|
||||
import { Alert, AlertTitle } from '@/components/ui/alert'
|
||||
import { Loader2 } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatasetClear',
|
||||
components: {
|
||||
CardContent, CardTitle, CardHeader, Card,
|
||||
Button,
|
||||
Loader2,
|
||||
AlertDialogFooter, AlertDialogHeader, AlertTitle, Alert, AlertDialog, AlertDialogContent
|
||||
},
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
info: {
|
||||
type: Object as () => DatasetModel | null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlerSubmit()
|
||||
{
|
||||
if (this.info) {
|
||||
this.loading = true
|
||||
DatasetService.clearData(this.info.code)
|
||||
.then((response: { status: boolean; }) => {
|
||||
if (response.status) {
|
||||
ToastUtils.success(`${this.$t('dataset.common.clearData')} [ ${this.info?.name} ] ${this.$t('common.successfully')}`)
|
||||
this.handlerCancel()
|
||||
}
|
||||
else {
|
||||
ToastUtils.error(`${this.$t('dataset.common.clearData')} [ ${this.info?.name} ] ${this.$t('common.fail')}`)
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
}
|
||||
},
|
||||
handlerCancel()
|
||||
{
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
134
core/datacap-ui/src/views/pages/admin/dataset/DatasetHistory.vue
Normal file
134
core/datacap-ui/src/views/pages/admin/dataset/DatasetHistory.vue
Normal file
@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<Dialog :open="isVisible" persistent @update:open="handlerCancel">
|
||||
<DialogContent class="min-w-[60%]">
|
||||
<DialogHeader class="border-b">
|
||||
<DialogTitle class="pb-3.5">
|
||||
{{ `[ ${info?.name} ] ${$t('dataset.common.history')}` }}
|
||||
</DialogTitle>
|
||||
<DialogDescription></DialogDescription>
|
||||
</DialogHeader>
|
||||
<CardContent class="grid gap-4">
|
||||
<TableCommon :loading="loading" :columns="headers" :data="data" :pagination="pagination" @changePage="handlerChangePage">
|
||||
<template #state="{ row }">
|
||||
<Badge :style="{backgroundColor: Common.getColor(row?.state)}">
|
||||
<HoverCard v-if="row?.state === 'FAILURE'">
|
||||
<HoverCardTrigger as-child>
|
||||
<Button variant="link">
|
||||
{{ getStateText(row?.state) }}
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent class="w-full">
|
||||
{{ row?.message }}
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
<span v-else>{{ getStateText(row?.state) }}</span>
|
||||
</Badge>
|
||||
</template>
|
||||
</TableCommon>
|
||||
</CardContent>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { CardContent } from '@/components/ui/card'
|
||||
import { Dialog, DialogContent, DialogHeader } from '@/components/ui/dialog'
|
||||
import TableCommon from '@/views/components/table/TableCommon.vue'
|
||||
import { FilterModel } from '@/model/filter'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { createHistoryHeaders } from './DatasetUtils'
|
||||
import { PaginationModel, PaginationRequest } from '@/model/pagination'
|
||||
import DatasetService from '@/services/dataset'
|
||||
import { DatasetModel } from '@/model/dataset'
|
||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import Common from '@/utils/common'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatasetHistory',
|
||||
components: {
|
||||
Badge,
|
||||
TableCommon,
|
||||
DialogHeader, Dialog, CardContent, DialogContent,
|
||||
HoverCard, HoverCardContent, HoverCardTrigger
|
||||
},
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
info: {
|
||||
type: Object as () => DatasetModel | null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
Common()
|
||||
{
|
||||
return Common
|
||||
},
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
setup()
|
||||
{
|
||||
const i18n = useI18n()
|
||||
const filter: FilterModel = new FilterModel()
|
||||
const headers = createHistoryHeaders(i18n)
|
||||
|
||||
return {
|
||||
i18n,
|
||||
filter,
|
||||
headers
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loading: false,
|
||||
data: [],
|
||||
pagination: {} as PaginationModel
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
},
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
this.loading = true
|
||||
DatasetService.getHistory(this.info?.code as string, this.filter)
|
||||
.then((response) => {
|
||||
if (response.status) {
|
||||
this.data = response.data.content
|
||||
this.pagination = PaginationRequest.of(response.data)
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
},
|
||||
handlerChangePage(value: PaginationModel)
|
||||
{
|
||||
this.filter.page = value.currentPage
|
||||
this.filter.size = value.pageSize
|
||||
this.handlerInitialize()
|
||||
},
|
||||
handlerCancel()
|
||||
{
|
||||
this.visible = false
|
||||
},
|
||||
getStateText(origin: string): string
|
||||
{
|
||||
return Common.getText(this.i18n, origin)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -41,12 +41,41 @@
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<RouterLink :to="`/admin/dataset/info/${row?.code}`" target="_blank" class="flex items-center">
|
||||
<Info class="mr-2 h-4 w-4"/>
|
||||
<span>{{ $t('dataset.common.info') }}</span>
|
||||
</RouterLink>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem :disabled="!isSuccess(row?.state)">
|
||||
<RouterLink :to="`/admin/dataset/adhoc/${row?.code}`" target="_blank" class="flex items-center">
|
||||
<BarChart2 class="mr-2 h-4 w-4"/>
|
||||
<span>{{ $t('dataset.common.adhoc') }}</span>
|
||||
</RouterLink>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator/>
|
||||
<DropdownMenuItem :disabled="!isSuccess(row?.state)" style="cursor: pointer;" @click="handlerSyncData(row, true)">
|
||||
<RefreshCcw class="mr-2 h-4 w-4"/>
|
||||
<span>{{ $t('dataset.common.syncData') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem style="cursor: pointer;" @click="handlerHistory(row, true)">
|
||||
<History class="mr-2 h-4 w-4"/>
|
||||
<span>{{ $t('dataset.common.history') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator/>
|
||||
<DropdownMenuItem :disabled="isSuccess(row?.state)" style="cursor: pointer;" @click="handlerError(row, true)">
|
||||
<TriangleAlert class="mr-2 h-4 w-4"/>
|
||||
<span>{{ $t('dataset.common.error') }}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem :disabled="isSuccess(row?.state)" style="cursor: pointer;" @click="handlerRebuild(row, true)">
|
||||
<CirclePlay v-if="row?.state === 'SUCCESS'" class="mr-2 h-4 w-4"/>
|
||||
<CircleStop v-else class="mr-2 h-4 w-4"/>
|
||||
{{ $t('dataset.common.rebuild') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem :disabled="!(row?.totalRows > 0)" style="cursor: pointer;" @click="handlerClearData(row, true)">
|
||||
<SquareX class="mr-2 h-4 w-4"/>
|
||||
{{ $t('dataset.common.clearData') }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
@ -54,6 +83,11 @@
|
||||
</TableCommon>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<DatasetRebuild v-if="rebuildVisible" :is-visible="rebuildVisible" :data="contextData" @close="handlerRebuild(null, false)"/>
|
||||
<DatasetHistory v-if="historyVisible" :is-visible="historyVisible" :info="contextData" @close="handlerHistory(null, false)"/>
|
||||
<DatasetSync v-if="syncDataVisible" :is-visible="syncDataVisible" :info="contextData" @close="handlerSyncData(null, false)"/>
|
||||
<DatasetClear v-if="clearDataVisible" :is-visible="clearDataVisible" :info="contextData" @close="handlerClearData(null, false)"/>
|
||||
<MarkdownPreview v-if="errorVisible && contextData" :is-visible="errorVisible" :content="'```java\n' + contextData.message + '\n```'" @close="handlerError(null, false)"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -71,7 +105,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import DatasetState from '@/views/pages/admin/dataset/components/DatasetState.vue'
|
||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
|
||||
import { BarChart2, Cog } from 'lucide-vue-next'
|
||||
import { BarChart2, CirclePlay, CircleStop, Cog, History, Info, RefreshCcw, SquareX, TriangleAlert } from 'lucide-vue-next'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@ -81,10 +115,21 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { DatasetModel } from '@/model/dataset'
|
||||
import DatasetRebuild from '@/views/pages/admin/dataset/DatasetRebuild.vue'
|
||||
import DatasetHistory from '@/views/pages/admin/dataset/DatasetHistory.vue'
|
||||
import DatasetSync from '@/views/pages/admin/dataset/DatasetSync.vue'
|
||||
import DatasetClear from '@/views/pages/admin/dataset/DatasetClear.vue'
|
||||
import MarkdownPreview from '@/views/components/markdown/MarkdownView.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatasetHome',
|
||||
components: {
|
||||
MarkdownPreview,
|
||||
DatasetClear,
|
||||
DatasetSync,
|
||||
DatasetHistory,
|
||||
DatasetRebuild,
|
||||
DropdownMenuItem, DropdownMenuGroup, DropdownMenuSeparator, DropdownMenuLabel, DropdownMenuContent, DropdownMenuTrigger, DropdownMenu,
|
||||
HoverCardContent, HoverCardTrigger, HoverCard,
|
||||
DatasetState,
|
||||
@ -93,7 +138,7 @@ export default defineComponent({
|
||||
TooltipTrigger, TooltipProvider, TooltipContent, Tooltip,
|
||||
TableCommon,
|
||||
CardContent, CardHeader, CardTitle, Card,
|
||||
Cog, BarChart2
|
||||
Cog, BarChart2, CirclePlay, CircleStop, History, RefreshCcw, SquareX, TriangleAlert, Info
|
||||
},
|
||||
setup()
|
||||
{
|
||||
@ -110,7 +155,13 @@ export default defineComponent({
|
||||
return {
|
||||
loading: false,
|
||||
data: [],
|
||||
pagination: {} as PaginationModel
|
||||
pagination: {} as PaginationModel,
|
||||
contextData: null as DatasetModel | null,
|
||||
rebuildVisible: false,
|
||||
historyVisible: false,
|
||||
syncDataVisible: false,
|
||||
clearDataVisible: false,
|
||||
errorVisible: false
|
||||
}
|
||||
},
|
||||
created()
|
||||
@ -136,6 +187,43 @@ export default defineComponent({
|
||||
this.filter.size = value.pageSize
|
||||
this.handlerInitialize()
|
||||
},
|
||||
handlerRebuild(record: DatasetModel | null, opened: boolean)
|
||||
{
|
||||
if (record && this.isSuccess(record.state)) {
|
||||
return
|
||||
}
|
||||
this.rebuildVisible = opened
|
||||
this.contextData = record
|
||||
},
|
||||
handlerHistory(record: DatasetModel | null, opened: boolean)
|
||||
{
|
||||
this.contextData = record
|
||||
this.historyVisible = opened
|
||||
},
|
||||
handlerSyncData(record: DatasetModel | null, opened: boolean)
|
||||
{
|
||||
if (record && !this.isSuccess(record.state)) {
|
||||
return
|
||||
}
|
||||
this.contextData = record
|
||||
this.syncDataVisible = opened
|
||||
},
|
||||
handlerClearData(record: DatasetModel | null, opened: boolean)
|
||||
{
|
||||
if (record && !(record.totalRows > 0)) {
|
||||
return
|
||||
}
|
||||
this.contextData = record
|
||||
this.clearDataVisible = opened
|
||||
if (!opened) {
|
||||
this.handlerInitialize()
|
||||
}
|
||||
},
|
||||
handlerError(record: DatasetModel | null, opened: boolean)
|
||||
{
|
||||
this.errorVisible = opened
|
||||
this.contextData = record
|
||||
},
|
||||
getState(state: Array<any> | null): string | null
|
||||
{
|
||||
if (state && state.length > 0) {
|
||||
|
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatasetInfo'
|
||||
});
|
||||
</script>
|
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div>
|
||||
<AlertDialog :default-open="visible">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle class="border-b -mt-4 pb-2">
|
||||
{{ $t('dataset.common.rebuild') + ' [ ' + data?.name + ' ]' }}
|
||||
</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<Alert>
|
||||
<AlertTitle>{{ $t('dataset.common.rebuildProgress') }}</AlertTitle>
|
||||
</Alert>
|
||||
<AlertDialogFooter class="-mb-4 border-t pt-2">
|
||||
<Button :disabled="loading" @click="handlerRebuild">
|
||||
<Loader2 v-if="loading" class="w-full justify-center animate-spin"/>
|
||||
{{ $t('dataset.common.rebuild') }}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import DatasetService from '@/services/dataset'
|
||||
import { ToastUtils } from '@/utils/toast'
|
||||
import { DatasetModel } from '@/model/dataset'
|
||||
import { AlertDialog, AlertDialogContent, AlertDialogFooter, AlertDialogHeader } from '@/components/ui/alert-dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Alert, AlertTitle } from '@/components/ui/alert';
|
||||
import { Loader2 } from 'lucide-vue-next';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatasetRebuild',
|
||||
components: {Loader2, AlertTitle, Alert, AlertDialogContent, AlertDialogFooter, Button, AlertDialogHeader, AlertDialog},
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
data: {
|
||||
type: Object as () => DatasetModel | null
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlerRebuild()
|
||||
{
|
||||
if (this.data) {
|
||||
this.loading = true
|
||||
DatasetService.rebuild(this.data.id)
|
||||
.then((response) => {
|
||||
if (response.status) {
|
||||
ToastUtils.success(`${this.$t('dataset.common.rebuild')} [ ${this.data?.name} ] ${this.$t('common.successfully')}`)
|
||||
this.handlerCancel()
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
handlerCancel()
|
||||
{
|
||||
this.visible = false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div>
|
||||
<AlertDialog :default-open="visible">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle class="border-b -mt-4 pb-2">
|
||||
{{ `[ ${info?.name} ] ${$t('dataset.common.syncData')}` }}
|
||||
</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<Alert>
|
||||
<AlertTitle>
|
||||
{{ $t('dataset.tip.syncData') }}
|
||||
</AlertTitle>
|
||||
</Alert>
|
||||
<AlertDialogFooter class="-mb-4 border-t pt-2">
|
||||
<Button variant="outline" @click="handlerCancel">{{ $t('common.cancel') }}</Button>
|
||||
<Button :disabled="loading" @click="handlerSubmit">
|
||||
<Loader2 v-if="loading" class="w-full justify-center animate-spin"/>
|
||||
{{ $t('dataset.common.syncData') }}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import DatasetService from '@/services/dataset'
|
||||
import { DatasetModel } from '@/model/dataset'
|
||||
import { ToastUtils } from '@/utils/toast'
|
||||
import { AlertDialog, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Loader2 } from 'lucide-vue-next'
|
||||
import { Alert, AlertTitle } from '@/components/ui/alert'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatasetSync',
|
||||
components: {
|
||||
AlertTitle, Alert,
|
||||
Loader2,
|
||||
Button,
|
||||
AlertDialog, AlertDialogContent, AlertDialogTitle, AlertDialogFooter, AlertDialogHeader
|
||||
},
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
info: {
|
||||
type: Object as () => DatasetModel | null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlerSubmit()
|
||||
{
|
||||
if (this.info) {
|
||||
this.loading = true
|
||||
DatasetService.syncData(this.info.id)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
ToastUtils.success(`${this.$t('dataset.common.syncData')} [ ${this.info?.name} ] ${this.$t('common.successfully')}`)
|
||||
this.handlerCancel()
|
||||
}
|
||||
else {
|
||||
ToastUtils.error(`${this.$t('dataset.common.syncData')} [ ${this.info?.name} ] ${this.$t('common.fail')}`)
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
}
|
||||
},
|
||||
handlerCancel()
|
||||
{
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -22,6 +22,18 @@ const createHeaders = (i18n: any) => {
|
||||
]
|
||||
}
|
||||
|
||||
export {
|
||||
createHeaders
|
||||
const createHistoryHeaders = (i18n: any) => {
|
||||
return [
|
||||
{key: 'id', hidden: true, header: i18n.t('common.id'), width: 80, class: 'text-center'},
|
||||
{key: 'elapsed', hidden: true, header: i18n.t('common.elapsed'), width: 80, class: 'text-center'},
|
||||
{key: 'count', hidden: true, header: i18n.t('common.count'), width: 80, class: 'text-center'},
|
||||
{key: 'createTime', hidden: true, header: i18n.t('common.createTime'), class: 'text-center'},
|
||||
{key: 'updateTime', hidden: true, header: i18n.t('common.updateTime'), class: 'text-center'},
|
||||
{key: 'state', hidden: true, header: i18n.t('common.state'), slot: 'state', width: 100, class: 'text-center'}
|
||||
]
|
||||
}
|
||||
|
||||
export {
|
||||
createHeaders,
|
||||
createHistoryHeaders
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
<FormControl>
|
||||
<Select v-model="formState.expression">
|
||||
<SelectTrigger class="w-full">
|
||||
<SelectValue :placeholder="$t('dataset.tip.selectExpressionTip')"/>
|
||||
<SelectValue :placeholder="$t('dataset.tip.selectExpression')"/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="Expression.IS_NULL">{{ $t('dataset.common.columnExpressionIsNull') }}</SelectItem>
|
||||
@ -59,7 +59,7 @@
|
||||
<FormControl>
|
||||
<Select v-model="formState.expression">
|
||||
<SelectTrigger class="w-full">
|
||||
<SelectValue :placeholder="$t('dataset.tip.selectExpressionTip')"/>
|
||||
<SelectValue :placeholder="$t('dataset.tip.selectExpression')"/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-if="formState.type === ColumnType.NUMBER" :value="Expression.SUM"> {{ $t('dataset.common.columnExpressionSum') }}</SelectItem>
|
||||
|
Loading…
Reference in New Issue
Block a user