refactor(page): refactor dataset --> adhoc

This commit is contained in:
qianmoQ 2024-11-17 09:45:38 +08:00
parent 5d3be6ffa5
commit 7065f72998
16 changed files with 1182 additions and 1105 deletions

View File

@ -40,7 +40,7 @@
"radix-vue": "^1.5.2", "radix-vue": "^1.5.2",
"uuid": "^9.0.1", "uuid": "^9.0.1",
"vaul-vue": "^0.1.0", "vaul-vue": "^0.1.0",
"view-shadcn-ui": "2024.4.0-alpha.1731599028", "view-shadcn-ui": "2024.4.0-alpha.1731720972",
"view-ui-plus": "^1.3.16", "view-ui-plus": "^1.3.16",
"vue": "^3.4.21", "vue": "^3.4.21",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",

View File

@ -1,8 +1,8 @@
<template> <template>
<div> <div>
<Button class="p-0 w-full"> <ShadcnButton class="p-0 w-full">
<Input ref="uploadInput" type="file" accept="image/jpg, image/jpeg, image/png, image/gif" @change="selectFile"/> <input ref="uploadInput" type="file" accept="image/jpg, image/jpeg, image/png, image/gif" @change="selectFile"/>
</Button> </ShadcnButton>
</div> </div>
<div v-if="result.blobURL || pic" class="pt-2 grid place-items-center"> <div v-if="result.blobURL || pic" class="pt-2 grid place-items-center">
@ -11,44 +11,42 @@
</div> </div>
</div> </div>
<Dialog v-if="isShowModal" :is-visible="isShowModal" :title="$t('common.cropper')" @close="isShowModal = $event"> <ShadcnModal v-if="isShowModal"
:is-visible="isShowModal"
:title="$t('common.cropper')"
@close="isShowModal = $event">
<div class="p-0"> <div class="p-0">
<VuePictureCropper style="max-height: 400px" :boxStyle="{ width: '100%', height: '100%', backgroundColor: '#f8f8f8', margin: 'auto' }" <VuePictureCropper style="max-height: 400px"
:options="{ viewMode: 1, dragMode: 'crop', }" :img="pic" @ready="ready"/> :boxStyle="{ width: '100%', height: '100%', backgroundColor: '#f8f8f8', margin: 'auto' }"
:options="{ viewMode: 1, dragMode: 'crop', }"
:img="pic"
@ready="ready"/>
</div> </div>
<template #footer> <template #footer>
<div class="space-x-2"> <div class="space-x-2">
<Button class="btn" size="sm" @click="isShowModal = false"> <ShadcnButton size="small" @click="isShowModal = false">
{{ $t('common.cancel') }} {{ $t('common.cancel') }}
</Button> </ShadcnButton>
<Button class="btn" size="sm" variant="destructive" @click="clear"> <ShadcnButton size="small" type="error" @click="clear">
{{ $t('common.clear') }} {{ $t('common.clear') }}
</Button> </ShadcnButton>
<Button class="btn" size="sm" variant="destructive" @click="reset"> <ShadcnButton size="small" type="error" @click="reset">
{{ $t('common.reset') }} {{ $t('common.reset') }}
</Button> </ShadcnButton>
<Button class="btn primary" size="sm" @click="getResult"> <ShadcnButton size="small" @click="getResult">
{{ $t('common.cropper') }} {{ $t('common.cropper') }}
</Button> </ShadcnButton>
</div> </div>
</template> </template>
</Dialog> </ShadcnModal>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref } from 'vue' import { defineComponent, reactive, ref } from 'vue'
import VuePictureCropper, { cropper } from 'vue-picture-cropper' import VuePictureCropper, { cropper } from 'vue-picture-cropper'
import Button from '@/views/ui/button'
import { Input } from '@/components/ui/input'
import Dialog from '@/views/ui/dialog'
export default defineComponent({ export default defineComponent({
components: { components: { VuePictureCropper },
Dialog,
Input,
VuePictureCropper,
Button
},
props: { props: {
pic: { pic: {
type: String type: String

View File

@ -1,227 +1,224 @@
<template> <template>
<ShadcnCard :border="false"> <ShadcnRow :gutter="8">
<div class="relative"> <ShadcnCol span="10">
<ShadcnLayout> <div class="relative">
<ShadcnLayoutWrapper> <ShadcnSpin v-if="loading" fixed/>
<ShadcnLayoutContent>
<ShadcnSpin v-if="loading" fixed/>
<ShadcnAlert v-if="configuration?.headers.length === 0 && !configuration?.message" class="mt-20" :title="$t('dataset.tip.adhocDnd')"/> <ShadcnAlert v-if="configuration?.headers.length === 0 && !configuration?.message" class="mt-20" :title="$t('dataset.tip.adhocDnd')"/>
<ShadcnAlert v-else-if="configuration?.message" class="mt-20" :title="configuration.message" type="error"/> <ShadcnAlert v-else-if="configuration?.message" class="mt-20" :title="configuration.message" type="error"/>
<div v-else> <div v-else>
<VisualTable v-if="configuration?.type === Type.TABLE" :configuration="configuration" @change="handlerCommit"/> <VisualTable v-if="configuration?.type === Type.TABLE" :configuration="configuration" @change="handlerCommit"/>
<VisualLine v-else-if="configuration?.type === Type.LINE" :configuration="configuration" @change="handlerCommit"/> <VisualLine v-else-if="configuration?.type === Type.LINE" :configuration="configuration" @change="handlerCommit"/>
<VisualBar v-else-if="configuration?.type === Type.BAR" :configuration="configuration" @change="handlerCommit"/> <VisualBar v-else-if="configuration?.type === Type.BAR" :configuration="configuration" @change="handlerCommit"/>
<VisualArea v-else-if="configuration?.type === Type.AREA" :configuration="configuration" @change="handlerCommit"/> <VisualArea v-else-if="configuration?.type === Type.AREA" :configuration="configuration" @change="handlerCommit"/>
<VisualPie v-else-if="configuration?.type === Type.PIE" :configuration="configuration" @change="handlerCommit"/> <VisualPie v-else-if="configuration?.type === Type.PIE" :configuration="configuration" @change="handlerCommit"/>
<VisualHistogram v-else-if="configuration?.type === Type.HISTOGRAM" :configuration="configuration" @change="handlerCommit"/> <VisualHistogram v-else-if="configuration?.type === Type.HISTOGRAM" :configuration="configuration" @change="handlerCommit"/>
<VisualWordCloud v-else-if="configuration?.type === Type.WORDCLOUD" :configuration="configuration" @change="handlerCommit"/> <VisualWordCloud v-else-if="configuration?.type === Type.WORDCLOUD" :configuration="configuration" @change="handlerCommit"/>
<VisualScatter v-else-if="configuration?.type === Type.SCATTER" :configuration="configuration" @change="handlerCommit"/> <VisualScatter v-else-if="configuration?.type === Type.SCATTER" :configuration="configuration" @change="handlerCommit"/>
<VisualRadar v-else-if="configuration?.type === Type.RADAR" :configuration="configuration" @change="handlerCommit"/> <VisualRadar v-else-if="configuration?.type === Type.RADAR" :configuration="configuration" @change="handlerCommit"/>
<VisualFunnel v-else-if="configuration?.type === Type.FUNNEL" :configuration="configuration" @change="handlerCommit"/> <VisualFunnel v-else-if="configuration?.type === Type.FUNNEL" :configuration="configuration" @change="handlerCommit"/>
<VisualGauge v-else-if="configuration?.type === Type.GAUGE" :configuration="configuration" @change="handlerCommit"/> <VisualGauge v-else-if="configuration?.type === Type.GAUGE" :configuration="configuration" @change="handlerCommit"/>
<VisualRose v-else-if="configuration?.type === Type.ROSE" :configuration="configuration" @change="handlerCommit"/> <VisualRose v-else-if="configuration?.type === Type.ROSE" :configuration="configuration" @change="handlerCommit"/>
</div> </div>
</ShadcnLayoutContent> </div>
<ShadcnLayoutSider> </ShadcnCol>
<ShadcnCard :title="$t('dataset.common.visualType')">
<div class="relative p-2 flex items-center">
<ShadcnSpin v-if="loading" fixed/>
<div v-if="configuration"> <ShadcnCol span="2">
<ShadcnRadioGroup v-model="configuration.type"> <ShadcnCard :title="$t('dataset.common.visualType')">
<ShadcnSpace class="items-center" wrap> <div class="relative p-2 flex items-center">
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.TABLE"> <ShadcnSpin v-if="localLoading" fixed/>
<ShadcnTooltip :content="$t('dataset.common.visualTypeTable')">
<ShadcnIcon icon="Table" size="20"/>
</ShadcnTooltip>
</ShadcnRadio>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.LINE"> <div v-if="configuration">
<ShadcnTooltip :content="$t('dataset.common.visualTypeLine')"> <ShadcnToggleGroup v-model="configuration.type" @on-change="onChangeType">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="lineChart" <ShadcnSpace class="items-center" wrap>
style="width: 24px;"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.TABLE">
<path d="M4 4.5V18.5C4 19.0523 4.44772 19.5 5 19.5H20" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> <ShadcnTooltip :content="$t('dataset.common.visualTypeTable')">
<path d="M8 14.5L12.4982 9.91029C12.5716 9.83537 12.6889 9.82567 12.7737 9.88752L15.812 12.1051C15.8933 12.1644 16.0051 12.1582 16.0793 12.0903L20 8.5" <ShadcnIcon icon="Table" size="20"/>
stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> </ShadcnTooltip>
</svg> </ShadcnToggle>
</ShadcnTooltip>
</ShadcnRadio>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.BAR"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.LINE">
<ShadcnTooltip :content="$t('dataset.common.visualTypeBar')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeLine')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="barChart" <svg xmlns="http://www.w3.org/2000/svg" width="30" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="lineChart"
style="width: 24px;"> style="width: 24px;">
<path d="M4 4.5V18.5C4 19.0523 4.44772 19.5 5 19.5H20" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> <path d="M4 4.5V18.5C4 19.0523 4.44772 19.5 5 19.5H20" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
<path d="M13 7V16" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> <path d="M8 14.5L12.4982 9.91029C12.5716 9.83537 12.6889 9.82567 12.7737 9.88752L15.812 12.1051C15.8933 12.1644 16.0051 12.1582 16.0793 12.0903L20 8.5"
<path d="M8.5 10V16" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
<path d="M17.5 12V16" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> </svg>
</svg> </ShadcnTooltip>
</ShadcnTooltip> </ShadcnToggle>
</ShadcnRadio>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.AREA"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.BAR">
<ShadcnTooltip :content="$t('dataset.common.visualTypeArea')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeBar')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="areaChart" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="barChart"
style="width: 24px;"> style="width: 24px;">
<path <path d="M4 4.5V18.5C4 19.0523 4.44772 19.5 5 19.5H20" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
d="M18 20H6C4.89543 20 4 19.1046 4 18V9L8.71327 5.70071C8.88543 5.5802 9.11457 5.5802 9.28673 5.70071L13.7201 8.8041C13.8889 8.92223 14.1128 8.92478 14.2842 8.81051L19.2226 5.51823C19.5549 5.29672 20 5.53491 20 5.93426V18C20 19.1046 19.1046 20 18 20Z" <path d="M13 7V16" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
stroke="#21252C" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M8.5 10V16" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
<path d="M20 11L14 14.5L9 11L4 14.5" stroke="#21252C" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M17.5 12V16" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
</svg> </svg>
</ShadcnTooltip> </ShadcnTooltip>
</ShadcnRadio> </ShadcnToggle>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.PIE"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.AREA">
<ShadcnTooltip :content="$t('dataset.common.visualTypePie')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeArea')">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none" class="vchart-dropdown-content-item-icon" id="pieChart" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="areaChart"
style="width: 24px;"> style="width: 24px;">
<path <path
d="M6.26599 3.38867C3.46047 4.60563 1.5 7.38359 1.5 10.6159C1.5 14.97 5.0576 18.4998 9.44612 18.4998C12.6024 18.4998 15.3288 16.674 16.6111 14.0288" d="M18 20H6C4.89543 20 4 19.1046 4 18V9L8.71327 5.70071C8.88543 5.5802 9.11457 5.5802 9.28673 5.70071L13.7201 8.8041C13.8889 8.92223 14.1128 8.92478 14.2842 8.81051L19.2226 5.51823C19.5549 5.29672 20 5.53491 20 5.93426V18C20 19.1046 19.1046 20 18 20Z"
stroke="#21252C" stroke-opacity="0.9" stroke-width="1.8" stroke-linecap="round"></path> stroke="#21252C" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path>
<path <path d="M20 11L14 14.5L9 11L4 14.5" stroke="#21252C" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path>
d="M18.4993 9.88932C18.4405 5.28275 14.7173 1.55949 10.1107 1.50071C10.0498 1.49993 10 1.54934 10 1.61021V9.44897C10 9.7533 10.2467 10 10.551 10H18.3898C18.4507 10 18.5001 9.95018 18.4993 9.88932Z" </svg>
stroke="#21252C" stroke-opacity="0.9" stroke-width="1.8"></path> </ShadcnTooltip>
</svg> </ShadcnToggle>
</ShadcnTooltip>
</ShadcnRadio>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.HISTOGRAM"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.PIE">
<ShadcnTooltip :content="$t('dataset.common.visualTypeHistogram')"> <ShadcnTooltip :content="$t('dataset.common.visualTypePie')">
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none" class="vchart-dropdown-content-item-icon" id="pieChart"
<g clip-path="url(#clip0_1700_69225)"> style="width: 24px;">
<path <path
d="M11.1663 3.33331H9.83301C9.28072 3.33331 8.83301 3.78103 8.83301 4.33331V15.6666C8.83301 16.2189 9.28072 16.6666 9.83301 16.6666H11.1663C11.7186 16.6666 12.1663 16.2189 12.1663 15.6666V4.33331C12.1663 3.78103 11.7186 3.33331 11.1663 3.33331Z" d="M6.26599 3.38867C3.46047 4.60563 1.5 7.38359 1.5 10.6159C1.5 14.97 5.0576 18.4998 9.44612 18.4998C12.6024 18.4998 15.3288 16.674 16.6111 14.0288"
stroke="#21252C" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path> stroke="#21252C" stroke-opacity="0.9" stroke-width="1.8" stroke-linecap="round"></path>
<path <path
d="M5.33333 7.5H4C3.44772 7.5 3 7.94772 3 8.5V15.6667C3 16.219 3.44771 16.6667 4 16.6667H5.33333C5.88562 16.6667 6.33333 16.2189 6.33333 15.6667V8.5C6.33333 7.94772 5.88562 7.5 5.33333 7.5Z" d="M18.4993 9.88932C18.4405 5.28275 14.7173 1.55949 10.1107 1.50071C10.0498 1.49993 10 1.54934 10 1.61021V9.44897C10 9.7533 10.2467 10 10.551 10H18.3898C18.4507 10 18.5001 9.95018 18.4993 9.88932Z"
stroke="#21252C" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path> stroke="#21252C" stroke-opacity="0.9" stroke-width="1.8"></path>
<path </svg>
d="M17.0003 9.16669H15.667C15.1147 9.16669 14.667 9.6144 14.667 10.1667V15.6667C14.667 16.219 15.1147 16.6667 15.667 16.6667H17.0003C17.5526 16.6667 18.0003 16.219 18.0003 15.6667V10.1667C18.0003 9.6144 17.5526 9.16669 17.0003 9.16669Z" </ShadcnTooltip>
stroke="#21252C" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path> </ShadcnToggle>
</g>
<defs>
<clipPath id="clip0_1700_69225">
<rect width="20" height="20" fill="white" transform="translate(0.5)"></rect>
</clipPath>
</defs>
</svg>
</ShadcnTooltip>
</ShadcnRadio>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.WORDCLOUD"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.HISTOGRAM">
<ShadcnTooltip :content="$t('dataset.common.visualTypeWordCloud')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeHistogram')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="wordCloud" <svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20" fill="none">
style="width: 24px;"> <g clip-path="url(#clip0_1700_69225)">
<path d="M5.81563 7V8.77143H3.92339V15H2.39681V8.77143H0.5V7H5.81563Z" fill="#21252C"></path> <path
<path d="M11.4096 13.28V15H6.50986V7H11.3913V8.72H8.03645V10.1029H11.1947V11.8171H8.03645V13.28H11.4096Z" fill="#21252C"></path> d="M11.1663 3.33331H9.83301C9.28072 3.33331 8.83301 3.78103 8.83301 4.33331V15.6666C8.83301 16.2189 9.28072 16.6666 9.83301 16.6666H11.1663C11.7186 16.6666 12.1663 16.2189 12.1663 15.6666V4.33331C12.1663 3.78103 11.7186 3.33331 11.1663 3.33331Z"
<path d="M17.972 7L15.9015 10.96L17.9948 15H16.2443L14.9645 12.4L13.6847 15H11.9525L14.0458 10.96L11.9799 7H13.7304L14.9828 9.54857L16.2351 7H17.972Z" stroke="#21252C" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path>
fill="#21252C"></path> <path
<path d="M23.5 7V8.77143H21.6078V15H20.0812V8.77143H18.1844V7H23.5Z" fill="#21252C"></path> d="M5.33333 7.5H4C3.44772 7.5 3 7.94772 3 8.5V15.6667C3 16.219 3.44771 16.6667 4 16.6667H5.33333C5.88562 16.6667 6.33333 16.2189 6.33333 15.6667V8.5C6.33333 7.94772 5.88562 7.5 5.33333 7.5Z"
<path stroke="#21252C" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path>
d="M4.94095 17.8V18.73H3.69895V22H2.69695V18.73H1.45195V17.8H4.94095ZM8.61263 21.097V22H5.39663V17.8H8.60063V18.703H6.39863V19.429H8.47163V20.329H6.39863V21.097H8.61263ZM12.92 17.8L11.561 19.879L12.935 22H11.786L10.946 20.635L10.106 22H8.96897L10.343 19.879L8.98697 17.8H10.136L10.958 19.138L11.78 17.8H12.92ZM16.5484 17.8V18.73H15.3064V22H14.3044V18.73H13.0594V17.8H16.5484Z" <path
fill="#21252C"></path> d="M17.0003 9.16669H15.667C15.1147 9.16669 14.667 9.6144 14.667 10.1667V15.6667C14.667 16.219 15.1147 16.6667 15.667 16.6667H17.0003C17.5526 16.6667 18.0003 16.219 18.0003 15.6667V10.1667C18.0003 9.6144 17.5526 9.16669 17.0003 9.16669Z"
<path stroke="#21252C" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path>
d="M13.6175 1.5V2.275H12.5825V5H11.7475V2.275H10.71V1.5H13.6175ZM16.6772 4.2475V5H13.9972V1.5H16.6672V2.2525H14.8322V2.8575H16.5597V3.6075H14.8322V4.2475H16.6772ZM20.2666 1.5L19.1341 3.2325L20.2791 5H19.3216L18.6216 3.8625L17.9216 5H16.9741L18.1191 3.2325L16.9891 1.5H17.9466L18.6316 2.615L19.3166 1.5H20.2666ZM23.2903 1.5V2.275H22.2553V5H21.4203V2.275H20.3828V1.5H23.2903Z" </g>
fill="#21252C"></path> <defs>
</svg> <clipPath id="clip0_1700_69225">
</ShadcnTooltip> <rect width="20" height="20" fill="white" transform="translate(0.5)"></rect>
</ShadcnRadio> </clipPath>
</defs>
</svg>
</ShadcnTooltip>
</ShadcnToggle>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.SCATTER"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.WORDCLOUD">
<ShadcnTooltip :content="$t('dataset.common.visualTypeScatter')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeWordCloud')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="scatterChart" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="wordCloud"
style="width: 24px;"> style="width: 24px;">
<path d="M4 4.5V18.5C4 19.0523 4.44772 19.5 5 19.5H20" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path> <path d="M5.81563 7V8.77143H3.92339V15H2.39681V8.77143H0.5V7H5.81563Z" fill="#21252C"></path>
<circle cx="8.5" cy="15.5" r="1.5" fill="#21252C"></circle> <path d="M11.4096 13.28V15H6.50986V7H11.3913V8.72H8.03645V10.1029H11.1947V11.8171H8.03645V13.28H11.4096Z" fill="#21252C"></path>
<circle cx="16" cy="7" r="2" fill="#21252C"></circle> <path d="M17.972 7L15.9015 10.96L17.9948 15H16.2443L14.9645 12.4L13.6847 15H11.9525L14.0458 10.96L11.9799 7H13.7304L14.9828 9.54857L16.2351 7H17.972Z"
<circle cx="18" cy="15" r="2" fill="#21252C"></circle> fill="#21252C"></path>
<circle cx="12.75" cy="12.25" r="2.25" fill="#21252C"></circle> <path d="M23.5 7V8.77143H21.6078V15H20.0812V8.77143H18.1844V7H23.5Z" fill="#21252C"></path>
</svg> <path
</ShadcnTooltip> d="M4.94095 17.8V18.73H3.69895V22H2.69695V18.73H1.45195V17.8H4.94095ZM8.61263 21.097V22H5.39663V17.8H8.60063V18.703H6.39863V19.429H8.47163V20.329H6.39863V21.097H8.61263ZM12.92 17.8L11.561 19.879L12.935 22H11.786L10.946 20.635L10.106 22H8.96897L10.343 19.879L8.98697 17.8H10.136L10.958 19.138L11.78 17.8H12.92ZM16.5484 17.8V18.73H15.3064V22H14.3044V18.73H13.0594V17.8H16.5484Z"
</ShadcnRadio> fill="#21252C"></path>
<path
d="M13.6175 1.5V2.275H12.5825V5H11.7475V2.275H10.71V1.5H13.6175ZM16.6772 4.2475V5H13.9972V1.5H16.6672V2.2525H14.8322V2.8575H16.5597V3.6075H14.8322V4.2475H16.6772ZM20.2666 1.5L19.1341 3.2325L20.2791 5H19.3216L18.6216 3.8625L17.9216 5H16.9741L18.1191 3.2325L16.9891 1.5H17.9466L18.6316 2.615L19.3166 1.5H20.2666ZM23.2903 1.5V2.275H22.2553V5H21.4203V2.275H20.3828V1.5H23.2903Z"
fill="#21252C"></path>
</svg>
</ShadcnTooltip>
</ShadcnToggle>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.RADAR"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.SCATTER">
<ShadcnTooltip :content="$t('dataset.common.visualTypeRadar')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeScatter')">
<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="scatterChart"
<path style="width: 24px;">
d="M1.57045 8.16646L10.3949 1.45986C10.7525 1.18808 11.2475 1.18808 11.6051 1.45986L20.4296 8.16646C20.7706 8.42565 20.9087 8.87328 20.7729 9.27956L17.4187 19.3169C17.2824 19.7249 16.9004 20 16.4703 20H5.52971C5.09956 20 4.7176 19.7249 4.58127 19.3169L1.22709 9.27956C1.09132 8.87328 1.2294 8.42565 1.57045 8.16646Z" <path d="M4 4.5V18.5C4 19.0523 4.44772 19.5 5 19.5H20" stroke="#21252C" stroke-width="1.8" stroke-linecap="round"></path>
stroke="#21252C" stroke-width="1.7" stroke-linecap="round"></path> <circle cx="8.5" cy="15.5" r="1.5" fill="#21252C"></circle>
<path <circle cx="16" cy="7" r="2" fill="#21252C"></circle>
d="M6.11243 9.82863L10.8826 6.2478C10.951 6.19642 11.0446 6.19428 11.1153 6.24249L16.3379 9.80252C16.4279 9.8639 16.4522 9.98606 16.3926 10.0773L13.5468 14.4281C13.5169 14.4739 13.4696 14.5054 13.4158 14.5153L7.91428 15.5328C7.81444 15.5513 7.71661 15.492 7.68675 15.395L6.04134 10.0474C6.01654 9.96678 6.04498 9.87927 6.11243 9.82863Z" <circle cx="18" cy="15" r="2" fill="#21252C"></circle>
stroke="#21252C" stroke-width="1.7" stroke-linecap="round"></path> <circle cx="12.75" cy="12.25" r="2.25" fill="#21252C"></circle>
</svg> </svg>
</ShadcnTooltip> </ShadcnTooltip>
</ShadcnRadio> </ShadcnToggle>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.FUNNEL"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.RADAR">
<ShadcnTooltip :content="$t('dataset.common.visualTypeFunnel')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeRadar')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="funnelChart" <svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
style="width: 24px;"> <path
<path d="M1.57045 8.16646L10.3949 1.45986C10.7525 1.18808 11.2475 1.18808 11.6051 1.45986L20.4296 8.16646C20.7706 8.42565 20.9087 8.87328 20.7729 9.27956L17.4187 19.3169C17.2824 19.7249 16.9004 20 16.4703 20H5.52971C5.09956 20 4.7176 19.7249 4.58127 19.3169L1.22709 9.27956C1.09132 8.87328 1.2294 8.42565 1.57045 8.16646Z"
d="M10.7172 18.1334C11.3011 19.0968 12.6989 19.0968 13.2828 18.1334L20.6197 6.02745C21.2256 5.0278 20.5058 3.75 19.3369 3.75H4.66307C3.49415 3.75 2.77442 5.02779 3.38027 6.02745L10.7172 18.1334Z" stroke="#21252C" stroke-width="1.7" stroke-linecap="round"></path>
stroke="#21252C" stroke-width="1.8"></path> <path
<path d="M4.52637 8.25H19.5264" stroke="#21252C" stroke-width="1.8"></path> d="M6.11243 9.82863L10.8826 6.2478C10.951 6.19642 11.0446 6.19428 11.1153 6.24249L16.3379 9.80252C16.4279 9.8639 16.4522 9.98606 16.3926 10.0773L13.5468 14.4281C13.5169 14.4739 13.4696 14.5054 13.4158 14.5153L7.91428 15.5328C7.81444 15.5513 7.71661 15.492 7.68675 15.395L6.04134 10.0474C6.01654 9.96678 6.04498 9.87927 6.11243 9.82863Z"
<path d="M7.52637 12.25H16.5264" stroke="#21252C" stroke-width="1.8"></path> stroke="#21252C" stroke-width="1.7" stroke-linecap="round"></path>
</svg> </svg>
</ShadcnTooltip> </ShadcnTooltip>
</ShadcnRadio> </ShadcnToggle>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.GAUGE"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.FUNNEL">
<ShadcnTooltip :content="$t('dataset.common.visualTypeGauge')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeFunnel')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="gauge" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="funnelChart"
style="width: 24px;"> style="width: 24px;">
<circle cx="12" cy="12" r="9.5" stroke="#21252C" stroke-width="1.8"></circle> <path
<circle cx="12" cy="16" r="2" stroke="#21252C" stroke-width="1.8"></circle> d="M10.7172 18.1334C11.3011 19.0968 12.6989 19.0968 13.2828 18.1334L20.6197 6.02745C21.2256 5.0278 20.5058 3.75 19.3369 3.75H4.66307C3.49415 3.75 2.77442 5.02779 3.38027 6.02745L10.7172 18.1334Z"
<path d="M12.9 7C12.9 6.50294 12.4971 6.1 12 6.1C11.5029 6.1 11.1 6.50294 11.1 7H12.9ZM11.1 7V14H12.9V7H11.1Z" fill="#21252C"></path> stroke="#21252C" stroke-width="1.8"></path>
</svg> <path d="M4.52637 8.25H19.5264" stroke="#21252C" stroke-width="1.8"></path>
</ShadcnTooltip> <path d="M7.52637 12.25H16.5264" stroke="#21252C" stroke-width="1.8"></path>
</ShadcnRadio> </svg>
</ShadcnTooltip>
</ShadcnToggle>
<ShadcnRadio :disabled="configuration.headers.length === 0" :value="Type.ROSE"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.GAUGE">
<ShadcnTooltip :content="$t('dataset.common.visualTypeRose')"> <ShadcnTooltip :content="$t('dataset.common.visualTypeGauge')">
<svg width="23" height="19" viewBox="0 0 23 19" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" class="vchart-dropdown-content-item-icon" id="gauge"
<path style="width: 24px;">
d="M14.2891 4.34061C12.6163 4.34061 11.1033 5.02518 10.0152 6.12945M9.28906 13.6584C10.364 15.2751 12.2021 16.3406 14.2891 16.3406C14.623 16.3406 14.9507 16.3133 15.2698 16.2608M19.9477 12.3406C20.1688 11.715 20.2891 11.0419 20.2891 10.3406C20.2891 9.29406 20.0211 8.3101 19.5501 7.45357" <circle cx="12" cy="12" r="9.5" stroke="#21252C" stroke-width="1.8"></circle>
stroke="#21252C" stroke-width="1.6"></path> <circle cx="12" cy="16" r="2" stroke="#21252C" stroke-width="1.8"></circle>
<path <path d="M12.9 7C12.9 6.50294 12.4971 6.1 12 6.1C11.5029 6.1 11.1 6.50294 11.1 7H12.9ZM11.1 7V14H12.9V7H11.1Z" fill="#21252C"></path>
d="M21.1403 5.56187C20.0934 2.84561 17.0299 1.28508 14.2419 2.112C14.1199 2.1482 14.0412 2.265 14.0476 2.39211L14.4231 9.83589C14.4343 10.0576 14.6835 10.182 14.8674 10.0576L21.0342 5.8887C21.1407 5.81671 21.1865 5.68182 21.1403 5.56187Z" </svg>
stroke="#21252C" stroke-width="1.6"></path> </ShadcnTooltip>
<path </ShadcnToggle>
d="M15.5303 18.0445C18.321 18.3698 20.8099 16.1368 21.3718 13.3596C21.3983 13.2288 21.3249 13.0997 21.2012 13.0499L14.9075 10.5185C14.7075 10.4381 14.4941 10.6001 14.5179 10.8143L15.2918 17.7994C15.3059 17.9266 15.4033 18.0297 15.5303 18.0445Z"
stroke="#21252C" stroke-width="1.6"></path>
<path
d="M6.11156 3.00092C2.12443 6.01236 1.38079 11.9577 4.17682 16.11C4.25866 16.2316 4.42097 16.267 4.54805 16.194L14.0167 10.759C14.1817 10.6643 14.2094 10.4377 14.072 10.3061L6.47293 3.02416C6.37404 2.92939 6.22086 2.91837 6.11156 3.00092Z"
stroke="#21252C" stroke-width="1.6"></path>
</svg>
</ShadcnTooltip>
</ShadcnRadio>
</ShadcnSpace>
</ShadcnRadioGroup>
</div>
</div>
</ShadcnCard>
<ShadcnCard class="mt-1"> <ShadcnToggle :disabled="configuration.headers.length === 0" :value="Type.ROSE">
<template #title>{{ $t('dataset.common.visualConfigure') }}</template> <ShadcnTooltip :content="$t('dataset.common.visualTypeRose')">
<svg width="23" height="19" viewBox="0 0 23 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M14.2891 4.34061C12.6163 4.34061 11.1033 5.02518 10.0152 6.12945M9.28906 13.6584C10.364 15.2751 12.2021 16.3406 14.2891 16.3406C14.623 16.3406 14.9507 16.3133 15.2698 16.2608M19.9477 12.3406C20.1688 11.715 20.2891 11.0419 20.2891 10.3406C20.2891 9.29406 20.0211 8.3101 19.5501 7.45357"
stroke="#21252C" stroke-width="1.6"></path>
<path
d="M21.1403 5.56187C20.0934 2.84561 17.0299 1.28508 14.2419 2.112C14.1199 2.1482 14.0412 2.265 14.0476 2.39211L14.4231 9.83589C14.4343 10.0576 14.6835 10.182 14.8674 10.0576L21.0342 5.8887C21.1407 5.81671 21.1865 5.68182 21.1403 5.56187Z"
stroke="#21252C" stroke-width="1.6"></path>
<path
d="M15.5303 18.0445C18.321 18.3698 20.8099 16.1368 21.3718 13.3596C21.3983 13.2288 21.3249 13.0997 21.2012 13.0499L14.9075 10.5185C14.7075 10.4381 14.4941 10.6001 14.5179 10.8143L15.2918 17.7994C15.3059 17.9266 15.4033 18.0297 15.5303 18.0445Z"
stroke="#21252C" stroke-width="1.6"></path>
<path
d="M6.11156 3.00092C2.12443 6.01236 1.38079 11.9577 4.17682 16.11C4.25866 16.2316 4.42097 16.267 4.54805 16.194L14.0167 10.759C14.1817 10.6643 14.2094 10.4377 14.072 10.3061L6.47293 3.02416C6.37404 2.92939 6.22086 2.91837 6.11156 3.00092Z"
stroke="#21252C" stroke-width="1.6"></path>
</svg>
</ShadcnTooltip>
</ShadcnToggle>
</ShadcnSpace>
</ShadcnToggleGroup>
</div>
</div>
</ShadcnCard>
<div class="relative p-2"> <ShadcnCard class="mt-1">
<ShadcnSpin v-model="loading"/> <template #title>{{ $t('dataset.common.visualConfigure') }}</template>
<div v-if="configuration" class="flex items-center justify-center"> <div class="relative p-2">
<ShadcnAlert v-if="configuration.type === Type.TABLE" :title="$t('dataset.common.visualConfigureNotSpecified')"/> <ShadcnSpin v-model="localLoading" fixed/>
<ShadcnButton v-else @click="configureVisible = true">{{ $t('common.configure') }}</ShadcnButton> <div v-if="configuration" class="flex items-center justify-center">
</div> <ShadcnAlert v-if="configuration.type === Type.TABLE" :title="$t('dataset.common.visualConfigureNotSpecified')"/>
</div>
</ShadcnCard> <ShadcnButton v-else @click="configureVisible = true">{{ $t('common.configure') }}</ShadcnButton>
</ShadcnLayoutSider> </div>
</ShadcnLayoutWrapper> </div>
</ShadcnLayout> </ShadcnCard>
</div> </ShadcnCol>
</ShadcnCard> </ShadcnRow>
<VisualConfigure v-if="configureVisible && configuration" <VisualConfigure v-if="configureVisible && configuration"
:is-visible="configureVisible" :is-visible="configureVisible"
@ -232,7 +229,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, PropType } from 'vue' import { defineComponent, PropType, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { Type } from '@/views/components/visual/Type' import { Type } from '@/views/components/visual/Type'
import VisualWordCloud from '@/views/components/visual/components/VisualWordCloud.vue' import VisualWordCloud from '@/views/components/visual/components/VisualWordCloud.vue'
@ -272,12 +269,16 @@ export default defineComponent({
type: Object as PropType<Configuration | null> type: Object as PropType<Configuration | null>
} }
}, },
setup() setup(props)
{ {
const i18n = useI18n() const i18n = useI18n()
const localLoading = ref(props.loading)
watch(() => props.loading, () => localLoading.value = props.loading)
return { return {
i18n i18n,
localLoading
} }
}, },
data() data()
@ -287,6 +288,12 @@ export default defineComponent({
} }
}, },
methods: { methods: {
onChangeType(type: any[])
{
if (this.configuration) {
this.configuration.type = type[0]
}
},
handlerCommit(value: any) handlerCommit(value: any)
{ {
this.$emit('commitOptions', value) this.$emit('commitOptions', value)

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="relative"> <div class="relative h-full w-full">
<ShadcnSpin v-model="loading"/> <ShadcnSpin v-model="loading" fixed style="margin-top: 100px;"/>
<div v-if="localConfiguration"> <div v-if="localConfiguration && !loading">
<div v-if="localConfiguration.message" class="p-4"> <div v-if="localConfiguration.message" class="p-4">
<ShadcnAlert type="error" :title="localConfiguration.message"/> <ShadcnAlert type="error" :title="localConfiguration.message"/>
</div> </div>

View File

@ -1,10 +1,11 @@
<template> <template>
<ShadcnDrawer v-model="visible" <ShadcnForm v-model="formState" class="mt-2" @on-submit="onSubmit">
width="40%" <ShadcnDrawer v-model="visible"
:title="$t('common.configure')" width="40%"
@close="onCancel"> style="margin-right: -1rem;"
:title="$t('common.configure')"
@close="onCancel">
<div v-if="configuration && formState" style="margin-right: -1rem">
<ShadcnTab v-model="activeGroup" direction="vertical" position="right"> <ShadcnTab v-model="activeGroup" direction="vertical" position="right">
<ShadcnTabItem v-for="group in fieldGroup" <ShadcnTabItem v-for="group in fieldGroup"
class="space-y-4" class="space-y-4"
@ -45,19 +46,19 @@
</ShadcnFormItem> </ShadcnFormItem>
</ShadcnTabItem> </ShadcnTabItem>
</ShadcnTab> </ShadcnTab>
</div>
<template #footer> <template #footer>
<ShadcnSpace> <ShadcnSpace>
<ShadcnButton type="default" @click="onCancel"> <ShadcnButton type="default" @click="onCancel">
{{ $t('common.cancel') }} {{ $t('common.cancel') }}
</ShadcnButton> </ShadcnButton>
<ShadcnButton @click="onSubmit"> <ShadcnButton submit>
{{ $t('common.apply') }} {{ $t('common.apply') }}
</ShadcnButton> </ShadcnButton>
</ShadcnSpace> </ShadcnSpace>
</template> </template>
</ShadcnDrawer> </ShadcnDrawer>
</ShadcnForm>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -1,73 +1,75 @@
<template> <template>
<div class="w-full"> <ShadcnCard :title="$t('dashboard.common.list')">
<DataCapCard> <template #extra>
<template #title>{{ $t('dashboard.common.list') }}</template> <ShadcnTooltip :content="$t('dashboard.common.create')">
<template #extra> <ShadcnLink link="/admin/dashboard/info">
<Button size="sm" to="/admin/dashboard/info"> <ShadcnButton circle size="small">
{{ $t('dashboard.common.create') }} <ShadcnIcon icon="Plus" size="15"/>
</Button> </ShadcnButton>
</template> </ShadcnLink>
<template #content> </ShadcnTooltip>
<div class="mb-3"> </template>
<Loader2 v-if="loading" class="w-full justify-center animate-spin"/>
<div v-else class="hidden flex-col md:flex"> <template #content>
<div class="flex-1 space-y-4 pt-6"> <div class="mb-3">
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-6"> <Loader2 v-if="loading" class="w-full justify-center animate-spin"/>
<DataCapCard v-for="item in data"> <div v-else class="hidden flex-col md:flex">
<template #title> <div class="flex-1 space-y-4 pt-6">
<div class="flex space-x-1"> <div class="grid gap-4 md:grid-cols-2 lg:grid-cols-6">
<div> <DataCapCard v-for="item in data">
<RouterLink :to="`/admin/dashboard/preview/${item.code}`" target="_blank">{{ item.name }}</RouterLink> <template #title>
</div> <div class="flex space-x-1">
<div> <div>
<Tooltip :content="item.description"> <RouterLink :to="`/admin/dashboard/preview/${item.code}`" target="_blank">{{ item.name }}</RouterLink>
<Info :size="18" class="cursor-pointer"/> </div>
</Tooltip> <div>
</div> <Tooltip :content="item.description">
<Info :size="18" class="cursor-pointer"/>
</Tooltip>
</div> </div>
</template>
<template #extra>
<DropdownMenu class="justify-items-end">
<DropdownMenuTrigger>
<Cog :size="20"/>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem class="cursor-pointer">
<RouterLink :to="`/admin/dashboard/info/${item.code}`" target="_blank" class="flex items-center">
<Pencil :size="15" class="mr-1"/>
{{ $t('dashboard.common.modify') }}
</RouterLink>
</DropdownMenuItem>
<DropdownMenuItem class="cursor-pointer" @click="handlerDelete(true, item)">
<Trash :size="15" class="mr-1"/>
{{ $t('dashboard.common.delete') }}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</template>
<div class="shadow-blackA7 w-full overflow-hidden rounded-md">
<AspectRatio :ratio="16 / 11">
<img class="h-full w-full object-cover" :src="`${item.avatar?.path ? item.avatar.path : '/static/images/dashboard.png'}`" :alt="item.name"/>
</AspectRatio>
</div> </div>
<template #footer> </template>
<p class="text-xs text-muted-foreground text-right">{{ item.createTime }}</p> <template #extra>
</template> <DropdownMenu class="justify-items-end">
</DataCapCard> <DropdownMenuTrigger>
</div> <Cog :size="20"/>
<div v-if="data.length === 0" class="text-center"> </DropdownMenuTrigger>
{{ $t('common.noData') }} <DropdownMenuContent>
</div> <DropdownMenuItem class="cursor-pointer">
<div> <RouterLink :to="`/admin/dashboard/info/${item.code}`" target="_blank" class="flex items-center">
<Pagination v-if="pagination && !loading && data.length > 0" :pagination="pagination" @changePage="handlerChangePage"/> <Pencil :size="15" class="mr-1"/>
</div> {{ $t('dashboard.common.modify') }}
</RouterLink>
</DropdownMenuItem>
<DropdownMenuItem class="cursor-pointer" @click="handlerDelete(true, item)">
<Trash :size="15" class="mr-1"/>
{{ $t('dashboard.common.delete') }}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</template>
<div class="shadow-blackA7 w-full overflow-hidden rounded-md">
<AspectRatio :ratio="16 / 11">
<img class="h-full w-full object-cover" :src="`${item.avatar?.path ? item.avatar.path : '/static/images/dashboard.png'}`" :alt="item.name"/>
</AspectRatio>
</div>
<template #footer>
<p class="text-xs text-muted-foreground text-right">{{ item.createTime }}</p>
</template>
</DataCapCard>
</div>
<div v-if="data.length === 0" class="text-center">
{{ $t('common.noData') }}
</div>
<div>
<Pagination v-if="pagination && !loading && data.length > 0" :pagination="pagination" @changePage="handlerChangePage"/>
</div> </div>
</div> </div>
</div> </div>
</template> </div>
</DataCapCard> </template>
<DashboardDelete v-if="deleteVisible" :is-visible="deleteVisible" :data="dataInfo" @close="handlerDelete(false, null)"></DashboardDelete> </ShadcnCard>
</div> <!-- <DashboardDelete v-if="deleteVisible" :is-visible="deleteVisible" :data="dataInfo" @close="handlerDelete(false, null)"></DashboardDelete>-->
</template> </template>
<script lang="ts"> <script lang="ts">
@ -76,24 +78,9 @@ import DashboardService from '@/services/dashboard'
import { FilterModel } from '@/model/filter' import { FilterModel } from '@/model/filter'
import { PaginationModel, PaginationRequest } from '@/model/pagination' import { PaginationModel, PaginationRequest } from '@/model/pagination'
import { DashboardModel } from '@/model/dashboard' import { DashboardModel } from '@/model/dashboard'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import DashboardDelete from '@/views/pages/admin/dashboard/DashboardDelete.vue'
import Pagination from '@/views/ui/pagination'
import Button from '@/views/ui/button'
import { TableCaption } from '@/components/ui/table'
import Tooltip from '@/views/ui/tooltip'
import { AspectRatio } from 'radix-vue'
import { DataCapCard } from '@/views/ui/card'
export default defineComponent({ export default defineComponent({
name: 'DashboardHome', name: 'DashboardHome',
components: {
DataCapCard,
AspectRatio,
Button, Tooltip, TableCaption, Pagination,
DashboardDelete,
DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel, DropdownMenuContent, DropdownMenuTrigger, DropdownMenu,
},
setup() setup()
{ {
const filter: FilterModel = new FilterModel() const filter: FilterModel = new FilterModel()

View File

@ -1,24 +1,21 @@
<template> <template>
<div class="w-full"> <div class="relative">
<CircularLoading v-if="loading" :show="loading" class="mt-20"></CircularLoading> <ShadcnSpin v-model="loading" fixed/>
<div v-else>
<DashboardEditor :info="dataInfo"/> <DashboardEditor :info="dataInfo"/>
</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import DashboardService from '@/services/dashboard' import DashboardService from '@/services/dashboard'
import { ToastUtils } from '@/utils/toast'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { DashboardModel } from '@/model/dashboard' import { DashboardModel } from '@/model/dashboard'
import DashboardEditor from '@/views/pages/admin/dashboard/components/DashboardEditor.vue' import DashboardEditor from '@/views/pages/admin/dashboard/components/DashboardEditor.vue'
export default defineComponent({ export default defineComponent({
name: 'DashboardInfo', name: 'DashboardInfo',
components: { DashboardEditor, CircularLoading }, components: { DashboardEditor },
data() data()
{ {
return { return {
@ -29,14 +26,14 @@ export default defineComponent({
}, },
created() created()
{ {
this.handlerInitialize() this.handleInitialize()
}, },
methods: { methods: {
handlerInitialize() handleInitialize()
{ {
const router = useRouter() const router = useRouter()
const params = router.currentRoute.value.params const params = router.currentRoute.value.params
const code = params['code'] as string const code = String(params['code'])
if (code) { if (code) {
this.loading = true this.loading = true
DashboardService.getByCode(code) DashboardService.getByCode(code)
@ -45,7 +42,10 @@ export default defineComponent({
this.dataInfo = response.data this.dataInfo = response.data
} }
else { else {
ToastUtils.error(response.message) this.$Message.error({
content: response.message,
showIcon: true
})
} }
}) })
.finally(() => this.loading = false) .finally(() => this.loading = false)

View File

@ -1,68 +1,76 @@
<template> <template>
<Dialog :is-visible="visible" :title="$t('report.common.list')" width="60%"> <ShadcnModal v-model="visible"
<CircularLoading v-if="loading" :show="loading"/> width="60%"
<div class="p-2" v-else> height="80%"
<FormField type="radio" name="theme"> :title="$t('report.common.list')"
<FormItem class="space-y-1"> @on-close="onCancel">
<FormMessage/>
<RadioGroup v-model="report" class="grid w-full grid-cols-4 gap-8 pt-2"> <div class="relative w-full h-full">
<FormItem v-for="item of data" :key="item.id"> <ShadcnSpin v-model="loading"/>
<FormLabel class="[&:has([data-state=checked])>div]:border-primary">
<FormControl> <div v-if="!loading" class="p-2">
<RadioGroupItem :value="item.id as unknown as string" class="sr-only"/> <FormField type="radio" name="theme">
</FormControl> <FormItem class="space-y-1">
<div class="items-center rounded-md border-4 border-muted p-1 hover:border-accent cursor-pointer text-center"> <FormMessage/>
<VisualView width="200px" height="100px" :code="item.dataset?.code as string" :configuration="JSON.parse(item.configure as string)" <RadioGroup v-model="report" class="grid w-full grid-cols-4 gap-8 pt-2">
:type="item.type" :query="item.type === 'DATASET' ? JSON.parse(item.query as string) : item.query" :original="item?.source?.id"/> <FormItem v-for="item of data" :key="item.id">
</div> <FormLabel class="[&:has([data-state=checked])>div]:border-primary">
<span class="block w-full p-2 text-center font-normal">{{ item.name }}</span> <FormControl>
</FormLabel> <RadioGroupItem :value="item.id as unknown as string" class="sr-only"/>
</FormItem> </FormControl>
</RadioGroup> <div class="items-center rounded-md border-4 border-muted p-1 hover:border-accent cursor-pointer text-center">
</FormItem> <VisualView width="200px" height="100px" :code="item.dataset?.code as string" :configuration="JSON.parse(item.configure as string)"
</FormField> :type="item.type" :query="item.type === 'DATASET' ? JSON.parse(item.query as string) : item.query" :original="item?.source?.id"/>
<div v-if="data.length === 0" class="flex w-full items-center"> </div>
{{ $t('common.noData') }} <span class="block w-full p-2 text-center font-normal">{{ item.name }}</span>
</FormLabel>
</FormItem>
</RadioGroup>
</FormItem>
</FormField>
<div v-if="data.length === 0" class="flex w-full items-center">
{{ $t('common.noData') }}
</div>
</div> </div>
<Pagination v-if="pagination && !loading && data.length > 0" :pagination="pagination" @changePage="handlerChangePage"/>
</div> </div>
<ShadcnPagination v-if="data.length > 0"
v-model="pageIndex"
class="py-2"
show-total
show-sizer
:page-size="pageSize"
:total="dataCount"
:sizerOptions="[10, 20, 50]"
@on-change="onPageChange"
@on-prev="onPrevChange"
@on-next="onNextChange"
@on-change-size="onSizeChange"/>
<template #footer> <template #footer>
<div class="space-x-5"> <ShadcnSpace>
<Button variant="destructive" size="sm" @click="handlerCancel"> <ShadcnButton type="default" @click="onCancel">
{{ $t('common.cancel') }} {{ $t('common.cancel') }}
</Button> </ShadcnButton>
<Button size="sm" @click="handlerSave()">
<ShadcnButton @click="onSubmit()">
{{ $t('common.save') }} {{ $t('common.save') }}
</Button> </ShadcnButton>
</div> </ShadcnSpace>
</template> </template>
</Dialog> </ShadcnModal>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import Dialog from '@/views/ui/dialog'
import ReportService from '@/services/report.ts' import ReportService from '@/services/report.ts'
import { FilterModel } from '@/model/filter.ts' import { FilterModel } from '@/model/filter.ts'
import { ReportModel } from '@/model/report.ts' import { ReportModel } from '@/model/report.ts'
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
import VisualView from '@/views/components/visual/VisualView.vue' import VisualView from '@/views/components/visual/VisualView.vue'
import Button from '@/views/ui/button'
import { toNumber } from 'lodash' import { toNumber } from 'lodash'
import Pagination from '@/views/ui/pagination'
import { PaginationModel, PaginationRequest } from '@/model/pagination.ts'
export default defineComponent({ export default defineComponent({
name: 'ChartContainer', name: 'ChartContainer',
components: { components: { VisualView },
Pagination,
VisualView,
Dialog,
RadioGroup, RadioGroupItem,
Button
},
computed: { computed: {
visible: { visible: {
get(): boolean get(): boolean
@ -91,7 +99,7 @@ export default defineComponent({
}, },
created() created()
{ {
this.handlerInitialize() this.handleInitialize()
}, },
data() data()
{ {
@ -99,35 +107,56 @@ export default defineComponent({
loading: false, loading: false,
data: [] as ReportModel[], data: [] as ReportModel[],
report: '', report: '',
pagination: {} as PaginationModel pageIndex: 1,
pageSize: 10,
dataCount: 0
} }
}, },
methods: { methods: {
handlerInitialize() handleInitialize()
{ {
this.loading = true this.loading = true
ReportService.getAll(this.filter) ReportService.getAll(this.filter)
.then(response => { .then(response => {
if (response.status) { if (response.status) {
this.data = response.data.content this.data = response.data.content
this.pagination = PaginationRequest.of(response.data) this.dataCount = response.data.total
this.pageSize = response.data.size
this.pageIndex = response.data.page
} }
}) })
.finally(() => this.loading = false) .finally(() => this.loading = false)
}, },
handlerChangePage(value: PaginationModel) fetchData(value: number)
{ {
this.filter.page = value.currentPage this.filter.page = value
this.filter.size = value.pageSize this.filter.size = this.pageSize
this.handlerInitialize() this.handleInitialize()
}, },
handlerSave() onPageChange(value: number)
{
this.fetchData(value)
},
onPrevChange(value: number)
{
this.fetchData(value)
},
onNextChange(value: number)
{
this.fetchData(value)
},
onSizeChange(value: number)
{
this.pageSize = value
this.fetchData(this.pageIndex)
},
onSubmit()
{ {
const node = this.data.find(item => item.id === toNumber(this.report)) const node = this.data.find(item => item.id === toNumber(this.report))
this.$emit('change', node) this.$emit('change', node)
this.handlerCancel() this.onCancel()
}, },
handlerCancel() onCancel()
{ {
this.visible = false this.visible = false
} }

View File

@ -1,76 +1,80 @@
<template> <template>
<div class="layout"> <ShadcnCard :title="title">
<DataCapCard> <template #extra>
<template #title>{{ title }}</template> <ShadcnSpace>
<template #extra> <ShadcnButton type="default" @click="visibleAddReport(true)">
<div class="space-x-5"> {{ $t('dashboard.common.addReport') }}
<Button size="sm" @click="handlerAddReport(true)"> </ShadcnButton>
{{ $t('dashboard.common.addReport') }}
</Button> <ShadcnButton @click="visibleSave(true)">
<Button size="sm" @click="handlerSaveVisible(true)"> {{ $t('common.save') }}
{{ $t('common.save') }} </ShadcnButton>
</Button> </ShadcnSpace>
</div> </template>
</template>
<div id="content"> <!-- <div id="content">-->
<GridLayout ref="refLayout" :layout="layouts" :responsive="true" :col-num="12" :row-height="30" :is-draggable="true" :is-resizable="true" :vertical-compact="true" <!-- <GridLayout ref="refLayout" :layout="layouts" :responsive="true" :col-num="12" :row-height="30" :is-draggable="true" :is-resizable="true" :vertical-compact="true"-->
:use-css-transforms="true"> <!-- :use-css-transforms="true">-->
<GridItem v-for="item in layouts" :ref="el => set$Children(el)" :key="item.i" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" :min-h="3" :min-w="3" <!-- <GridItem v-for="item in layouts" :ref="el => set$Children(el)" :key="item.i" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" :min-h="3" :min-w="3"-->
@resized="handlerResize"> <!-- @resized="onResize">-->
<DataCapCard :style="{width: item.width, height: item.height}"> <!-- <DataCapCard :style="{width: item.width, height: item.height}">-->
<template #title>{{ item.title ? item.title : $t('dataset.common.notSpecifiedTitle') }}</template> <!-- <template #title>{{ item.title ? item.title : $t('dataset.common.notSpecifiedTitle') }}</template>-->
<template #extra> <!-- <template #extra>-->
<Button size="icon" class="w-6 h-6 rounded-full bg-color-error" @click="handlerRemove(item.i)"> <!-- <Button size="icon" class="w-6 h-6 rounded-full bg-color-error" @click="onRemove(item.i)">-->
<Trash :size="15"/> <!-- <Trash :size="15"/>-->
</Button> <!-- </Button>-->
</template> <!-- </template>-->
<VisualView v-if="item.original" class="-ml-3" :width="item.width.replace('px', '') - 20 + 'px'" :height="item.height.replace('px', '') - 48 + 'px'" <!-- <VisualView v-if="item.original" class="-ml-3" :width="item.width.replace('px', '') - 20 + 'px'" :height="item.height.replace('px', '') - 48 + 'px'"-->
:code="item.node.code" :configuration="JSON.parse(item.node.configure)" :type="item.original?.type" <!-- :code="item.node.code" :configuration="JSON.parse(item.node.configure)" :type="item.original?.type"-->
:query="item.original.type === 'DATASET' ? JSON.parse(item.original.query as string) : item.original.query" :original="item?.original?.source?.id"/> <!-- :query="item.original.type === 'DATASET' ? JSON.parse(item.original.query as string) : item.original.query" :original="item?.original?.source?.id"/>-->
<VisualView v-else class="-ml-3" :width="item.width.replace('px', '') - 20 + 'px'" :height="item.height.replace('px', '') - 48 + 'px'" <!-- <VisualView v-else class="-ml-3" :width="item.width.replace('px', '') - 20 + 'px'" :height="item.height.replace('px', '') - 48 + 'px'"-->
:code="item.node.code" :configuration="JSON.parse(item.node.configure)" :query="JSON.parse(item.node.query)"/> <!-- :code="item.node.code" :configuration="JSON.parse(item.node.configure)" :query="JSON.parse(item.node.query)"/>-->
</DataCapCard> <!-- </DataCapCard>-->
</GridItem> <!-- </GridItem>-->
</GridLayout> <!-- </GridLayout>-->
</div> <!-- </div>-->
</DataCapCard> </ShadcnCard>
<Dialog :is-visible="configureVisible" :title="$t('common.configure')">
<div v-if="formState" class="pl-3 pr-4"> <!-- <Dialog :is-visible="configureVisible" :title="$t('common.configure')">-->
<FormField name="name"> <!-- <div v-if="formState" class="pl-3 pr-4">-->
<FormItem class="space-y-2"> <!-- <FormField name="name">-->
<FormLabel>{{ $t('common.name') }}</FormLabel> <!-- <FormItem class="space-y-2">-->
<FormMessage/> <!-- <FormLabel>{{ $t('common.name') }}</FormLabel>-->
<Input v-model="formState.name"/> <!-- <FormMessage/>-->
</FormItem> <!-- <Input v-model="formState.name"/>-->
</FormField> <!-- </FormItem>-->
<FormField name="description"> <!-- </FormField>-->
<FormItem class="space-y-2"> <!-- <FormField name="description">-->
<FormLabel>{{ $t('common.description') }}</FormLabel> <!-- <FormItem class="space-y-2">-->
<FormMessage/> <!-- <FormLabel>{{ $t('common.description') }}</FormLabel>-->
<Textarea v-model="formState.description"/> <!-- <FormMessage/>-->
</FormItem> <!-- <Textarea v-model="formState.description"/>-->
</FormField> <!-- </FormItem>-->
<FormField name="avatar"> <!-- </FormField>-->
<FormItem class="space-y-2"> <!-- <FormField name="avatar">-->
<FormLabel>{{ $t('common.avatar') }}</FormLabel> <!-- <FormItem class="space-y-2">-->
<FormMessage/> <!-- <FormLabel>{{ $t('common.avatar') }}</FormLabel>-->
<CropperHome :pic="formState?.avatar?.path" @update:value="handlerCropper"/> <!-- <FormMessage/>-->
</FormItem> <!-- <CropperHome :pic="formState?.avatar?.path" @update:value="handlerCropper"/>-->
</FormField> <!-- </FormItem>-->
</div> <!-- </FormField>-->
<template #footer> <!-- </div>-->
<div class="space-x-5"> <!-- <template #footer>-->
<Button variant="outline" size="sm" @click="configureVisible = false"> <!-- <div class="space-x-5">-->
{{ $t('common.cancel') }} <!-- <Button variant="outline" size="sm" @click="configureVisible = false">-->
</Button> <!-- {{ $t('common.cancel') }}-->
<Button :loading="loading" :disabled="loading" size="sm" @click="handlerSave"> <!-- </Button>-->
{{ $t('common.save') }} <!-- <Button :loading="loading" :disabled="loading" size="sm" @click="handlerSave">-->
</Button> <!-- {{ $t('common.save') }}-->
</div> <!-- </Button>-->
</template> <!-- </div>-->
</Dialog> <!-- </template>-->
</div> <!-- </Dialog>-->
<ChartContainer v-if="dataReportVisible" :is-visible="dataReportVisible" @change="handlerChange" @close="handlerAddReport(false)"/>
<ChartContainer v-if="dataReportVisible"
:is-visible="dataReportVisible"
@change="onChange"
@close="visibleAddReport(false)"/>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -80,30 +84,14 @@ import DashboardService from '@/services/dashboard'
import { ReportModel } from '@/model/report.ts' import { ReportModel } from '@/model/report.ts'
import VisualView from '@/views/components/visual/VisualView.vue' import VisualView from '@/views/components/visual/VisualView.vue'
import { DashboardModel, DashboardRequest } from '@/model/dashboard.ts' import { DashboardModel, DashboardRequest } from '@/model/dashboard.ts'
import { DataCapCard } from '@/views/ui/card'
import ChartContainer from '@/views/pages/admin/dashboard/components/ChartContainer.vue'
import { ToastUtils } from '@/utils/toast.ts'
import Dialog from '@/views/ui/dialog'
import Button from '@/views/ui/button'
import { Input } from '@/components/ui/input'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { Textarea } from '@/components/ui/textarea'
import CropperHome from '@/views/components/cropper/CropperHome.vue' import CropperHome from '@/views/components/cropper/CropperHome.vue'
import UploadService from '@/services/upload' import UploadService from '@/services/upload'
import ChartContainer from '@/views/pages/admin/dashboard/components/ChartContainer.vue'
export default defineComponent({ export default defineComponent({
name: 'DashboardEditor', name: 'DashboardEditor',
components: { components: { ChartContainer, CropperHome, VisualView, GridItem, GridLayout },
CropperHome,
Textarea,
Input,
ChartContainer,
VisualView,
GridItem, GridLayout,
DataCapCard,
Button,
Dialog,
},
props: { props: {
info: { info: {
type: Object as () => DashboardModel | null type: Object as () => DashboardModel | null
@ -125,38 +113,34 @@ export default defineComponent({
}, },
created() created()
{ {
this.handlerInitialize() this.handleInitialize()
}, },
methods: { methods: {
handlerInitialize() handleInitialize()
{ {
setTimeout(() => { setTimeout(() => {
this.title = this.$t('dashboard.common.create') this.title = this.$t('dashboard.common.create')
if (this.info) { if (this.info) {
this.title = this.$t('dashboard.common.modifyInfo').replace('$VALUE', this.info.name as string) this.title = this.$t('dashboard.common.modifyInfo').replace('$VALUE', String(this.info.name))
this.formState = cloneDeep(this.info) this.formState = cloneDeep(this.info)
this.layouts = JSON.parse(this.info?.configure as string) this.layouts = JSON.parse(String(this.info?.configure))
} }
else { else {
this.formState = DashboardRequest.of() this.formState = DashboardRequest.of()
} }
}, 300) }, 300)
}, },
handlerResize(i: string | number, w: number, h: number, x: number, y: number) onResize(i: string | number, w: number, h: number, x: number, y: number)
{ {
console.debug(w, h) console.debug(w, h)
const node = this.layouts.find((obj: { i: string; }) => obj.i === i) const node = this.layouts.find((obj: { i: string; }) => obj.i === i)
node.width = `${ y }px` node.width = `${ y }px`
node.height = `${ x }px` node.height = `${ x }px`
}, },
handlerRemove(i: string | number) onRemove(i: string | number)
{ {
this.layouts = this.layouts.filter((obj: { i: string; }) => obj.i !== i) this.layouts = this.layouts.filter((obj: { i: string; }) => obj.i !== i)
}, },
handlerSaveVisible(opened: boolean)
{
this.configureVisible = opened
},
handlerCropper(value: any) handlerCropper(value: any)
{ {
const configure = { const configure = {
@ -170,42 +154,21 @@ export default defineComponent({
if (this.formState) { if (this.formState) {
this.formState.avatar = response.data this.formState.avatar = response.data
} }
ToastUtils.success(this.$t('common.successfully'))
this.$Message.success({
content: this.$t('common.successfully'),
showIcon: true
})
} }
else { else {
ToastUtils.error(response.message) this.$Message.error({
content: response.message,
showIcon: true
})
} }
}) })
}, },
handlerSave() onChange(node: ReportModel)
{
if (this.formState) {
this.formState.configure = JSON.stringify(this.layouts)
this.layouts.forEach((item: { node: { id: any; }; }) => this.formState?.reports?.push({ id: item.node.id }))
this.loading = true
DashboardService.saveOrUpdate(this.formState)
.then(response => {
if (response.status) {
ToastUtils.success(this.$t('dashboard.tip.publishSuccess').replace('$VALUE', <string>this.formState?.name))
if (response.data) {
this.$router.push(`/admin/dashboard/preview/${ response.data?.code }`)
}
else {
this.$router.push('/console/dashboard')
}
}
else {
ToastUtils.error(response.message)
}
})
.finally(() => this.loading = false)
}
},
handlerAddReport(opened: boolean)
{
this.dataReportVisible = opened
},
handlerChange(node: ReportModel)
{ {
const newItem = { const newItem = {
x: 0, x: 0,
@ -226,6 +189,45 @@ export default defineComponent({
} }
this.layouts.push(newItem) this.layouts.push(newItem)
}, },
onSubmit()
{
if (this.formState) {
this.formState.configure = JSON.stringify(this.layouts)
this.layouts.forEach((item: { node: { id: any; }; }) => this.formState?.reports?.push({ id: item.node.id }))
this.loading = true
DashboardService.saveOrUpdate(this.formState)
.then(response => {
if (response.status) {
this.$Message.success({
content: this.$t('dashboard.tip.publishSuccess').replace('$VALUE', this.formState?.name),
showIcon: true
})
if (response.data) {
this.$router.push(`/admin/dashboard/preview/${ response.data?.code }`)
}
else {
this.$router.push('/console/dashboard')
}
}
else {
this.$Message.error({
content: response.message,
showIcon: true
})
}
})
.finally(() => this.loading = false)
}
},
visibleSave(opened: boolean)
{
this.configureVisible = opened
},
visibleAddReport(opened: boolean)
{
this.dataReportVisible = opened
},
set$Children(vm: any) set$Children(vm: any)
{ {
if (vm && vm.i) { if (vm && vm.i) {

View File

@ -1,170 +1,227 @@
<template> <template>
<div class="hidden space-y-6 pb-16 w-full h-full md:block"> <ShadcnRow gutter="8">
<div class="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0"> <ShadcnCol span="2">
<aside class="-mx-4 w-[200px] space-y-5"> <ShadcnSpace wrap>
<DataCapCard> <ShadcnCard class="w-full h-full">
<template #title>{{ $t('dataset.common.columnModeMetric') }}</template> <template #title>
<CircularLoading v-if="initialize" :show="initialize"/> <span class="text-sm font-semibold">{{ $t('dataset.common.columnModeMetric') }}</span>
<div v-else> </template>
<Draggable item-key="id" :group="{ name: 'metrics', pull: 'clone', put: false }" :list="originalMetrics" :clone="handlerClone"
@start="handlerHighlight(true, ColumnType.METRIC)" @end="handlerHighlight(false, ColumnType.METRIC)"> <div class="relative p-1" style="min-height: 200px;">
<template #item="{ element }"> <ShadcnSpin v-model="initialize" fixed/>
<Badge variant="outline" class="cursor-pointer mr-1" @dblclick="handlerClone(element)">
{{ element.aliasName ? element.aliasName : element.name }} <div v-if="!initialize">
</Badge> <Draggable item-key="id"
:group="{ name: 'metrics', pull: 'clone', put: false }"
:list="originalMetrics"
:clone="onClone"
@start="visibleHighlight(true, ColumnType.METRIC)"
@end="visibleHighlight(false, ColumnType.METRIC)">
<template #item="{ element }">
<ShadcnTag class="my-1 mx-0.5 cursor-pointer" :text="element.aliasName ? element.aliasName : element.name" @dblclick="onClone(element)"/>
</template>
</Draggable>
</div>
</div>
</ShadcnCard>
<ShadcnCard class="w-full">
<template #title>
<span class="text-sm font-semibold">{{ $t('dataset.common.columnModeDimension') }}</span>
</template>
<div class="relative p-1" style="min-height: 200px;">
<ShadcnSpin v-model="initialize" fixed/>
<div v-if="!initialize">
<Draggable item-key="id"
:group="{ name: 'dimensions', pull: 'clone', put: false }"
:list="originalDimensions"
:clone="onClone"
@start="visibleHighlight(true, ColumnType.DIMENSION)"
@end="visibleHighlight(false, ColumnType.DIMENSION)">
<template #item="{ element }">
<ShadcnTag class="my-1 mx-0.5 cursor-pointer" :text="element.aliasName ? element.aliasName : element.name" @dblclick="onClone(element)"/>
</template>
</Draggable>
</div>
</div>
</ShadcnCard>
</ShadcnSpace>
</ShadcnCol>
<ShadcnCol span="10">
<div class="relative">
<ShadcnSpin v-model="loading" fixed/>
<div class="flex items-center space-x-2 text-sm">
<div>{{ $t('dataset.common.columnModeMetric') }}:</div>
<div :class="cn('w-full flex-1 p-1',
(highlight.active && highlight.type === ColumnType.METRIC) && 'border-2 border-green-400 rounded-sm min-h-8'
)">
<Draggable group="metrics"
item-key="id"
:list="metrics"
class="flex flex-wrap gap-2">
<template #item="{ element, index }">
<ShadcnTag class="inline-flex items-center whitespace-nowrap">
<span class="flex items-center">
<DatasetColumnMetric :element="element"/>
</span>
<span class="ml-2 flex items-center space-x-1">
<ShadcnTooltip :content="$t('common.configure')">
<ShadcnIcon class="cursor-pointer hover:text-primary"
icon="Cog"
size="15"
@click="onColumnConfigure(true, element, ColumnType.METRIC)"/>
</ShadcnTooltip>
<ShadcnTooltip :content="$t('common.remove')">
<ShadcnIcon class="cursor-pointer text-red-400 hover:text-red-500"
icon="Trash"
size="15"
@click="onRemove(index, metrics)"/>
</ShadcnTooltip>
</span>
</ShadcnTag>
</template> </template>
</Draggable> </Draggable>
</div> </div>
</DataCapCard>
<DataCapCard>
<template #title>{{ $t('dataset.common.columnModeDimension') }}</template>
<CircularLoading v-if="initialize" :show="initialize"/>
<div v-else>
<Draggable item-key="id" :group="{ name: 'dimensions', pull: 'clone', put: false }" :list="originalDimensions" :clone="handlerClone"
@start="handlerHighlight(true, ColumnType.DIMENSION)" @end="handlerHighlight(false, ColumnType.DIMENSION)">
<template #item="{ element }">
<Badge variant="outline" class="cursor-pointer mr-1 mt-1">
{{ element.aliasName ? element.aliasName : element.name }}
</Badge>
</template>
</Draggable>
</div>
</DataCapCard>
</aside>
<div class="flex-1">
<div class="space-y-6">
<div class="flex items-center space-x-4 text-sm">
<div class="min-w-12">{{ $t('dataset.common.columnModeMetric') }}:</div>
<div :class="cn(`w-full`, (highlight.active && highlight.type === ColumnType.METRIC) && 'border-2 border-primary rounded-sm min-h-8')">
<Draggable group="metrics" item-key="id" :list="metrics">
<template #item="{ element, index }">
<Badge variant="outline" class="cursor-pointer mr-1 mt-1">
<DatasetColumnMetric :element="element"/> &nbsp;
<Tooltip :content="$t('common.configure')">
<Cog class="pointer" :size="15" @click="handlerColumnConfigure(true, element, ColumnType.METRIC)"/>
</Tooltip>
<Tooltip :content="$t('common.remove')">
<Trash class="point ml-1" :size="15" @click="handlerRemove(index, metrics)"/>
</Tooltip>
</Badge>
</template>
</Draggable>
</div>
</div>
<Separator class="p-0" style="margin-top: 8px;"/>
<div class="flex h-5 items-center space-x-4 text-sm" style="margin-top: 8px;">
<div class="min-w-12">{{ $t('dataset.common.columnModeDimension') }}:</div>
<div :class="cn(`w-full`, (highlight.active && highlight.type === ColumnType.DIMENSION) && 'border-2 border-primary rounded-sm min-h-8')">
<Draggable group="dimensions" item-key="id" :list="dimensions" class="space-x-1">
<template #item="{ element, index}">
<Badge variant="outline" class="cursor-pointer">
{{ element.aliasName ? element.aliasName : element.name }} &nbsp;
<Tooltip :content="$t('common.configure')">
<Cog class="pointer" :size="15" @click="handlerColumnConfigure(true, element, ColumnType.DIMENSION)"/>
</Tooltip>
<Tooltip :content="$t('common.remove')">
<Trash class="point ml-1" :size="15" @click="handlerRemove(index, dimensions)"/>
</Tooltip>
</Badge>
</template>
</Draggable>
</div>
</div>
<Separator class="p-0" style="margin-top: 8px;"/>
<div class="flex h-5 items-center space-x-4 text-sm" style="margin-top: 8px;">
<div class="min-w-12">{{ $t('dataset.common.columnModeFilter') }}:</div>
<div :class="cn(`w-full`, (highlight.active && highlight.type === ColumnType.DIMENSION) && 'border-2 border-primary rounded-sm min-h-8')">
<Draggable group="dimensions" item-key="id" :list="filters" class="space-x-1">
<template #item="{ element, index}">
<Badge variant="outline" class="cursor-pointer mr-1 mt-1">
{{ element.aliasName ? element.aliasName : element.name }} &nbsp;
<Tooltip :content="$t('common.configure')">
<Cog class="pointer" :size="15" @click="handlerColumnConfigure(true, element, ColumnType.FILTER)"/>
</Tooltip>
<Tooltip :content="$t('common.remove')">
<Trash class="point ml-1" :size="15" @click="handlerRemove(index, filters)"/>
</Tooltip>
</Badge>
</template>
</Draggable>
</div>
</div>
<Separator class="p-0" style="margin-top: 8px;"/>
<div class="flex justify-between items-center h-5" style="margin-top: 20px;">
<div class="flex items-center">
<span>{{ $t('dataset.common.showPageSize') }}</span>
<Input type="number" class="w-20 ml-1" v-model="configure.limit" min="1"/>
</div>
<div class="flex items-center space-x-4 text-sm">
<Button size="sm" :disabled="loading" class="pl-3 pr-3" @click="handlerApplyAdhoc">
<Loader2 v-if="loading" class="w-full justify-center animate-spin"/>
<CirclePlay v-else/>
</Button>
<Button size="sm" class="pl-3 pr-3" variant="outline" :disabled="!showSql.content || loading" @click="handlerShowSql(true)">
<Eye/>
</Button>
<Button size="sm" :disabled="!isPublish || loading" @click="formState.visible = true">
{{ $t('common.publish') }}
</Button>
</div>
</div>
<Separator class="p-0" style="margin-top: 20px;"/>
</div> </div>
<!-- Result -->
<VisualEditor :loading="loading" :configuration="configuration" @commitOptions="handlerCommitOptions"/> <ShadcnDivider class="my-2"/>
<div class="flex items-center space-x-2 text-sm">
<div>{{ $t('dataset.common.columnModeDimension') }}:</div>
<div :class="cn('w-full flex-1 p-1',
(highlight.active && highlight.type === ColumnType.DIMENSION) && 'border-2 border-blue-400 rounded-sm min-h-8')
">
<Draggable group="dimensions"
item-key="id"
:list="dimensions"
class="flex flex-wrap gap-2">
<template #item="{ element, index}">
<ShadcnTag class="inline-flex items-center whitespace-nowrap">
<span class="flex items-center">
{{ element.aliasName ? element.aliasName : element.name }}
</span>
<span class="ml-2 flex items-center space-x-1">
<ShadcnTooltip :content="$t('common.configure')">
<ShadcnIcon class="cursor-pointer hover:text-primary"
icon="Cog"
size="15"
@click="onColumnConfigure(true, element, ColumnType.DIMENSION)"/>
</ShadcnTooltip>
<ShadcnTooltip :content="$t('common.remove')">
<ShadcnIcon class="cursor-pointer text-red-400 hover:text-red-500"
icon="Trash"
size="15"
@click="onRemove(index, dimensions)"/>
</ShadcnTooltip>
</span>
</ShadcnTag>
</template>
</Draggable>
</div>
</div>
<ShadcnDivider class="my-2"/>
<div class="flex items-center space-x-2 text-sm">
<div>{{ $t('dataset.common.columnModeFilter') }}:</div>
<div :class="cn('w-full flex-1 p-1',
(highlight.active && highlight.type === ColumnType.DIMENSION) && 'border-2 border-yellow-400 rounded-sm min-h-8')
">
<Draggable group="dimensions"
item-key="id"
:list="filters"
class="flex flex-wrap gap-2">
<template #item="{ element, index}">
<ShadcnTag class="inline-flex items-center whitespace-nowrap">
<span class="flex items-center">
{{ element.aliasName ? element.aliasName : element.name }}
</span>
<span class="ml-2 flex items-center space-x-1">
<ShadcnTooltip :content="$t('common.configure')">
<ShadcnIcon class="cursor-pointer hover:text-primary"
icon="Cog"
size="15"
@click="onColumnConfigure(true, element, ColumnType.FILTER)"/>
</ShadcnTooltip>
<ShadcnTooltip :content="$t('common.remove')">
<ShadcnIcon class="cursor-pointer text-red-400 hover:text-red-500"
icon="Trash"
size="15"
@click="onRemove(index, filters)"/>
</ShadcnTooltip>
</span>
</ShadcnTag>
</template>
</Draggable>
</div>
</div>
<ShadcnDivider class="my-2"/>
<div class="flex justify-between items-center">
<div class="flex items-center space-x-4">
<span>{{ $t('dataset.common.showPageSize') }}</span>
<ShadcnNumber v-model="configure.limit" min="1"/>
</div>
<div class="flex items-center space-x-4 text-sm">
<ShadcnButton :disabled="loading" :loading="loading" @click="onApplyAdhoc">
<ShadcnIcon icon="CirclePlay"/>
</ShadcnButton>
<ShadcnButton type="default" :disabled="!showSql.content || loading" @click="visibleShowSql(true)">
<template #icon>
<ShadcnIcon icon="Eye"/>
</template>
</ShadcnButton>
<ShadcnButton @click="publishVisible = true">
{{ $t('common.publish') }}
</ShadcnButton>
</div>
</div>
<ShadcnDivider class="my-2"/>
</div> </div>
</div>
</div> <VisualEditor :loading="loading" :configuration="configuration" @commitOptions="visibleCommitOptions"/>
<SqlInfo v-if="showSql.visible" :is-visible="showSql.visible" :content="showSql.content" @close="handlerShowSql(false)"/> </ShadcnCol>
<DatasetColumnConfigure v-if="columnContent.visible" :is-visible="columnContent.visible" :column-type="columnContent.type" :content="columnContent.content" </ShadcnRow>
:configure="columnContent.configure" @close="handlerColumnConfigure(false, null, null)" @commit="handlerCommitColumnConfigure"/>
<AlertDialog v-if="formState.visible" :default-open="formState.visible"> <SqlInfo v-if="showSql.visible"
<AlertDialogContent> :is-visible="showSql.visible"
<AlertDialogHeader> :content="showSql.content"
<AlertDialogTitle class="border-b -mt-4 pb-2">{{ $t('common.configure') }}</AlertDialogTitle> @close="visibleShowSql(false)"/>
</AlertDialogHeader>
<div class="space-y-2"> <DatasetColumnConfigure v-if="columnContent.visible"
<FormField name="name"> :is-visible="columnContent.visible"
<FormItem> :column-type="columnContent.type"
<FormLabel class="mr-1 w-20 text-right"> :content="columnContent.content"
{{ $t('common.name') }} :configure="columnContent.configure"
</FormLabel> @close="onColumnConfigure(false, null, null)"
<FormControl> @commit="onCommitColumnConfigure"/>
<Input v-model="formState.name"/>
</FormControl> <DatasetReport v-if="publishVisible"
</FormItem> :info="dataInfo as any"
</FormField> :id="Number(id)"
<FormField name="description"> :dimension="originalDimensions[0] as any"
<FormItem> :visible="publishVisible"
<FormLabel class="mr-1 w-20 text-right"> :commit-options="commitOptions as any"
{{ $t('common.description') }} :configure="configure as any"
</FormLabel> @close="visiblePublish(false)"/>
<FormControl>
<Textarea v-model="formState.description"/>
</FormControl>
</FormItem>
</FormField>
<FormField name="build">
<FormItem>
<FormLabel>
{{ $t('dataset.common.continuousBuild') }}
<br/>
</FormLabel>
<FormControl>
<Switch :value="formState.build" @changeValue="formState.build = $event"/>
</FormControl>
</FormItem>
</FormField>
</div>
<AlertDialogFooter class="-mb-4 border-t pt-2">
<Button variant="destructive" @click="formState.visible = false">{{ $t('common.cancel') }}</Button>
<Button :disabled="!formState.name || published" @click="handlerPublish">
<Loader2 v-if="published" class="w-full justify-center animate-spin"/>
{{ $t('common.publish') }}
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -174,27 +231,14 @@ import { Type } from '@/views/components/visual/Type'
import { Type as ColumnType } from './Type' import { Type as ColumnType } from './Type'
import ReportService from '@/services/report' import ReportService from '@/services/report'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import router from '@/router'
import { Configuration } from '@/views/components/visual/Configuration' import { Configuration } from '@/views/components/visual/Configuration'
import VisualEditor from '@/views/components/visual/VisualEditor.vue' import VisualEditor from '@/views/components/visual/VisualEditor.vue'
import DatasetColumnMetric from '@/views/pages/admin/dataset/components/adhoc/DatasetColumnMetric.vue' import DatasetColumnMetric from '@/views/pages/admin/dataset/components/adhoc/DatasetColumnMetric.vue'
import DatasetColumnConfigure from '@/views/pages/admin/dataset/components/adhoc/DatasetColumnConfigure.vue' import DatasetColumnConfigure from '@/views/pages/admin/dataset/components/adhoc/DatasetColumnConfigure.vue'
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { Badge } from '@/components/ui/badge'
import { DataCapCard } from '@/views/ui/card'
import Tooltip from '@/views/ui/tooltip'
import { Separator } from '@/components/ui/separator'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Alert, AlertTitle } from '@/components/ui/alert'
import { ToastUtils } from '@/utils/toast'
import SqlInfo from '@/views/components/sql/SqlInfo.vue' import SqlInfo from '@/views/components/sql/SqlInfo.vue'
import { AlertDialog, AlertDialogContent, AlertDialogFooter, AlertDialogHeader } from '@/components/ui/alert-dialog'
import { Select } from '@/components/ui/select'
import Switch from '@/views/ui/switch'
import { Textarea } from '@/components/ui/textarea'
import { cn } from '@/lib/utils.ts' import { cn } from '@/lib/utils.ts'
import DatasetReport from '@/views/pages/admin/dataset/components/DatasetReport.vue'
export default defineComponent({ export default defineComponent({
name: 'DatasetAdhoc', name: 'DatasetAdhoc',
@ -208,25 +252,7 @@ export default defineComponent({
return ColumnType return ColumnType
} }
}, },
components: { components: { DatasetReport, SqlInfo, DatasetColumnMetric, DatasetColumnConfigure, Draggable, VisualEditor },
DataCapCard,
Textarea,
Switch,
Select,
AlertDialogFooter, AlertDialogHeader, AlertDialog, AlertDialogContent,
SqlInfo,
AlertTitle, Alert,
Button,
Input,
Tooltip,
Separator,
Badge,
DatasetColumnMetric,
DatasetColumnConfigure,
Draggable,
VisualEditor,
},
setup() setup()
{ {
return { return {
@ -260,29 +286,23 @@ export default defineComponent({
content: [] as never[], content: [] as never[],
configure: null as any | null configure: null as any | null
}, },
isPublish: false,
commitOptions: null, commitOptions: null,
formState: { publishVisible: false,
visible: false,
name: '',
description: '',
build: false
},
published: false,
initialize: false, initialize: false,
highlight: { highlight: {
active: false, active: false,
type: 'METRIC' type: 'METRIC'
} },
dataInfo: { name: null as string | null, description: null as string | null }
} }
}, },
created() created()
{ {
this.configuration = new Configuration() this.configuration = new Configuration()
this.handlerInitialize() this.handleInitialize()
}, },
methods: { methods: {
handlerInitialize() handleInitialize()
{ {
setTimeout(() => { setTimeout(() => {
this.initialize = true this.initialize = true
@ -300,8 +320,8 @@ export default defineComponent({
ReportService.getById(this.id as number) ReportService.getById(this.id as number)
.then(response => { .then(response => {
if (response.status) { if (response.status) {
this.formState.name = response.data.name this.dataInfo.name = response.data.name
this.formState.description = response.data.description this.dataInfo.description = response.data.description
const query = JSON.parse(response.data.query) const query = JSON.parse(response.data.query)
this.mergeColumns(query.columns, this.metrics, ColumnType.METRIC) this.mergeColumns(query.columns, this.metrics, ColumnType.METRIC)
this.mergeColumns(query.columns, this.dimensions, ColumnType.DIMENSION) this.mergeColumns(query.columns, this.dimensions, ColumnType.DIMENSION)
@ -309,28 +329,30 @@ export default defineComponent({
this.configure.columns = query.columns this.configure.columns = query.columns
this.configure.limit = query.limit this.configure.limit = query.limit
this.configuration = JSON.parse(response.data.configure) this.configuration = JSON.parse(response.data.configure)
this.handlerApplyAdhoc() this.onApplyAdhoc()
} }
}) })
} }
} }
else { else {
ToastUtils.error(response.message) this.$Message.error({
content: response.message,
showIcon: true
})
} }
}) })
.finally(() => this.initialize = false) .finally(() => this.initialize = false)
}, 0) }, 0)
}, },
handlerApplyAdhoc() onApplyAdhoc()
{ {
// Set the mode to: FILTER // Set the mode to: FILTER
this.filters.forEach((item: { mode: ColumnType; }) => item.mode = ColumnType.FILTER) this.filters.forEach((item: { mode: ColumnType; }) => item.mode = ColumnType.FILTER)
this.configure.columns = [...this.splitColumns(this.metrics), ...this.splitColumns(this.dimensions), ...this.splitColumns(this.filters)] this.configure.columns = [...this.splitColumns(this.metrics), ...this.splitColumns(this.dimensions), ...this.splitColumns(this.filters)]
this.handlerAdhoc() this.onAdhoc()
}, },
handlerAdhoc() onAdhoc()
{ {
this.isPublish = true
this.loading = true this.loading = true
DatasetService.adhoc(this.code as string, this.configure) DatasetService.adhoc(this.code as string, this.configure)
.then(response => { .then(response => {
@ -350,31 +372,30 @@ export default defineComponent({
} }
} }
else { else {
ToastUtils.error(response.message) this.$Message.error({
content: response.message,
showIcon: true
})
} }
}) })
.finally(() => this.loading = false) .finally(() => this.loading = false)
}, },
handlerClone(value: any) onClone(value: any)
{ {
return cloneDeep(value) return cloneDeep(value)
}, },
handlerRemove(index: number, array: never[]) onRemove(index: number, array: never[])
{ {
array.splice(index, 1) array.splice(index, 1)
this.handlerApplyAdhoc() this.onApplyAdhoc()
}, },
handlerCommit(value: any) onCommit(value: any)
{ {
if (this.configuration) { if (this.configuration) {
this.configuration.chartConfigure = value this.configuration.chartConfigure = value
} }
}, },
handlerShowSql(opened: boolean) onColumnConfigure(opened: boolean, record: any, type: ColumnType | null)
{
this.showSql.visible = opened
},
handlerColumnConfigure(opened: boolean, record: any, type: ColumnType | null)
{ {
this.columnContent.visible = opened this.columnContent.visible = opened
this.columnContent.type = type this.columnContent.type = type
@ -394,7 +415,7 @@ export default defineComponent({
this.columnContent.configure = null this.columnContent.configure = null
} }
}, },
handlerCommitColumnConfigure(value: any) onCommitColumnConfigure(value: any)
{ {
const clonedValue = cloneDeep(value) const clonedValue = cloneDeep(value)
if (clonedValue.mode === ColumnType.METRIC) { if (clonedValue.mode === ColumnType.METRIC) {
@ -406,48 +427,25 @@ export default defineComponent({
else if (clonedValue.mode === ColumnType.FILTER) { else if (clonedValue.mode === ColumnType.FILTER) {
this.replaceColumn(this.filters, clonedValue) this.replaceColumn(this.filters, clonedValue)
} }
this.handlerApplyAdhoc() this.onApplyAdhoc()
}, },
handlerCommitOptions(value: any) visibleShowSql(opened: boolean)
{
this.showSql.visible = opened
},
visibleCommitOptions(value: any)
{ {
this.commitOptions = value this.commitOptions = value
}, },
handlerPublish() visibleHighlight(opened: boolean, type: any)
{
this.published = true
const obj = this.originalDimensions[0] as any
const configure = {
id: 0,
name: this.formState.name,
realtime: true,
type: 'DATASET',
configure: JSON.stringify(this.commitOptions),
dataset: {
id: obj.dataset.id
},
query: JSON.stringify(this.configure),
description: this.formState.description
}
if (this.id) {
configure.id = this.id
}
ReportService.saveOrUpdate(configure)
.then(response => {
if (response.status) {
ToastUtils.success(this.$t('report.tip.publishSuccess').replace('$VALUE', this.formState.name))
this.formState.visible = false
if (!this.formState.build) {
router.push('/admin/report')
}
}
})
.finally(() => this.published = false)
},
handlerHighlight(opened: boolean, type: any)
{ {
this.highlight.active = opened this.highlight.active = opened
this.highlight.type = type this.highlight.type = type
}, },
visiblePublish(opened: boolean)
{
this.publishVisible = opened
},
mergeColumns(originalColumns: any[], array: any[], type?: ColumnType) mergeColumns(originalColumns: any[], array: any[], type?: ColumnType)
{ {
originalColumns.filter((item: { mode: ColumnType; id: number; }) => { originalColumns.filter((item: { mode: ColumnType; id: number; }) => {

View File

@ -1,111 +1,120 @@
<template> <template>
<div class="w-full"> <ShadcnCard>
<DataCapCard> <template #title>
<template #title>{{ $t('dataset.common.list') }}</template> <div class="ml-2 font-normal text-sm">{{ $t('dataset.common.list') }}</div>
<template #content> </template>
<TableCommon :loading="loading" :columns="headers" :data="data" :pagination="pagination" @changePage="handlerChangePage">
<template #source="{row}"> <div class="relative">
<Tooltip :content="row?.source.type"> <ShadcnSpin v-if="loading" fixed/>
<Avatar :size="'sm'" :src="'/static/images/plugin/' + row?.source.type + '.png'" :alt="row?.source.type" class="cursor-pointer"/>
</Tooltip> <ShadcnTable size="small" :columns="headers" :data="data">
</template> <template #source="{row}">
<template #syncMode="{ row }"> <ShadcnTooltip :content="row?.source.type">
<Badge v-if="row?.syncMode === 'MANUAL'">{{ $t('dataset.common.syncModeManual') }}</Badge> <ShadcnAvatar size="small" :src="'/static/images/plugin/' + row?.source.type + '.png'" :alt="row?.source.type"/>
<Badge v-else-if="row?.syncMode === 'TIMING'">{{ $t('dataset.common.syncModeTiming') }}</Badge> </ShadcnTooltip>
<Badge v-else-if="row?.syncMode === 'OUT_SYNC'">{{ $t('dataset.common.syncModeOutSync') }}</Badge> </template>
</template>
<template #state="{ row }"> <template #syncMode="{ row }">
<HoverCard> <ShadcnBadge v-if="row?.syncMode === 'MANUAL'" :text=" $t('dataset.common.syncModeManual')"/>
<HoverCardTrigger>{{ getState(row?.state) }}</HoverCardTrigger> <ShadcnBadge v-else-if="row?.syncMode === 'TIMING'" :text="$t('dataset.common.syncModeTiming')"/>
<HoverCardContent> <ShadcnBadge v-else-if="row?.syncMode === 'OUT_SYNC'" :text="$t('dataset.common.syncModeOutSync')"/>
<DatasetState class="mt-[25px]" :states="row?.state"/> </template>
</HoverCardContent>
</HoverCard> <template #state="{ row }">
</template> <ShadcnHoverCard>
<template #action="{row}"> <template #content>
<DropdownMenu> <DatasetState :states="row?.state"/>
<DropdownMenuTrigger as-child> </template>
<Button variant="outline"> {{ getState(row?.state) }}
<Cog class="w-full justify-center" :size="20"/> </ShadcnHoverCard>
</Button> </template>
</DropdownMenuTrigger>
<DropdownMenuContent> <template #action="{ row }">
<DropdownMenuGroup> <ShadcnSpace>
<DropdownMenuItem> <ShadcnTooltip :content="$t('dataset.common.adhoc')">
<RouterLink :to="`/admin/dataset/info/${row?.code}`" target="_blank" class="flex items-center"> <ShadcnLink :link="`/admin/dataset/adhoc/${row?.code}`" target="_blank">
<Info class="mr-2 h-4 w-4"/> <ShadcnButton circle size="small" :disabled="!isSuccess(row?.state)">
<span>{{ $t('dataset.common.info') }}</span> <ShadcnIcon icon="BarChart2" size="15"/>
</RouterLink> </ShadcnButton>
</DropdownMenuItem> </ShadcnLink>
<DropdownMenuItem :disabled="!isSuccess(row?.state)"> </ShadcnTooltip>
<RouterLink :to="`/admin/dataset/adhoc/${row?.code}`" target="_blank" class="flex items-center">
<BarChart2 class="mr-2 h-4 w-4"/> <ShadcnDropdown trigger="click" position="right">
<span>{{ $t('dataset.common.adhoc') }}</span> <template #trigger>
</RouterLink> <ShadcnButton circle size="small">
</DropdownMenuItem> <ShadcnIcon icon="Cog" size="15"/>
<DropdownMenuSeparator/> </ShadcnButton>
<DropdownMenuItem :disabled="!isSuccess(row?.state)" style="cursor: pointer;" @click="handlerSyncData(row, true)"> </template>
<RefreshCcw class="mr-2 h-4 w-4"/>
<span>{{ $t('dataset.common.syncData') }}</span> <ShadcnDropdownItem>
</DropdownMenuItem> <RouterLink :to="`/admin/dataset/info/${row?.code}`" target="_blank" class="flex items-center">
<DropdownMenuItem style="cursor: pointer;" @click="handlerHistory(row, true)"> <ShadcnIcon icon="Info" size="15"/>
<History class="mr-2 h-4 w-4"/> <span class="ml-2">{{ $t('dataset.common.info') }}</span>
<span>{{ $t('dataset.common.history') }}</span> </RouterLink>
</DropdownMenuItem> </ShadcnDropdownItem>
<DropdownMenuSeparator/> </ShadcnDropdown>
<DropdownMenuItem :disabled="isSuccess(row?.state)" style="cursor: pointer;" @click="handlerError(row, true)"> </ShadcnSpace>
<TriangleAlert class="mr-2 h-4 w-4"/> </template>
<span>{{ $t('dataset.common.error') }}</span> </ShadcnTable>
</DropdownMenuItem>
<DropdownMenuItem :disabled="isSuccess(row?.state)" style="cursor: pointer;" @click="handlerRebuild(row, true)"> <ShadcnPagination v-if="data?.length > 0"
<CirclePlay v-if="row?.state === 'SUCCESS'" class="mr-2 h-4 w-4"/> v-model="pageIndex"
<CircleStop v-else class="mr-2 h-4 w-4"/> class="py-2"
{{ $t('dataset.common.rebuild') }} show-total
</DropdownMenuItem> show-sizer
<DropdownMenuItem :disabled="!(row?.totalRows > 0)" style="cursor: pointer;" @click="handlerClearData(row, true)"> :page-size="pageSize"
<SquareX class="mr-2 h-4 w-4"/> :total="dataCount"
{{ $t('dataset.common.clearData') }} :sizerOptions="[10, 20, 50]"
</DropdownMenuItem> @on-change="onPageChange"
</DropdownMenuGroup> @on-prev="onPrevChange"
</DropdownMenuContent> @on-next="onNextChange"
</DropdownMenu> @on-change-size="onSizeChange"/>
</template> </div>
</TableCommon> <!-- <DropdownMenuGroup>-->
</template> <!-- <DropdownMenuSeparator/>-->
</DataCapCard> <!-- <DropdownMenuItem :disabled="!isSuccess(row?.state)" style="cursor: pointer;" @click="handlerSyncData(row, true)">-->
<DatasetRebuild v-if="rebuildVisible" :is-visible="rebuildVisible" :data="contextData" @close="handlerRebuild(null, false)"/> <!-- <RefreshCcw class="mr-2 h-4 w-4"/>-->
<DatasetHistory v-if="historyVisible" :is-visible="historyVisible" :info="contextData" @close="handlerHistory(null, false)"/> <!-- <span>{{ $t('dataset.common.syncData') }}</span>-->
<DatasetSync v-if="syncDataVisible" :is-visible="syncDataVisible" :info="contextData" @close="handlerSyncData(null, false)"/> <!-- </DropdownMenuItem>-->
<DatasetClear v-if="clearDataVisible" :is-visible="clearDataVisible" :info="contextData" @close="handlerClearData(null, false)"/> <!-- <DropdownMenuItem style="cursor: pointer;" @click="handlerHistory(row, true)">-->
<MarkdownPreview v-if="errorVisible && contextData" :is-visible="errorVisible" :content="'```java\n' + contextData.message + '\n```'" @close="handlerError(null, false)"/> <!-- <History class="mr-2 h-4 w-4"/>-->
</div> <!-- <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>-->
</ShadcnCard>
<!-- <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)"/>-->
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { FilterModel } from '@/model/filter' import { FilterModel } from '@/model/filter'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { PaginationModel, PaginationRequest } from '@/model/pagination'
import { createHeaders } from './DatasetUtils' import { createHeaders } from './DatasetUtils'
import DatasetService from '@/services/dataset' import DatasetService from '@/services/dataset'
import DatasetState from '@/views/pages/admin/dataset/components/DatasetState.vue'
import { DatasetModel } from '@/model/dataset' import { DatasetModel } from '@/model/dataset'
import DatasetRebuild from '@/views/pages/admin/dataset/DatasetRebuild.vue' import DatasetState from '@/views/pages/admin/dataset/components/DatasetState.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({ export default defineComponent({
name: 'DatasetHome', name: 'DatasetHome',
components: { components: { DatasetState },
DataCapCard,
DatasetClear, DatasetSync, DatasetHistory, DatasetRebuild, DatasetState,
DropdownMenuItem, DropdownMenuGroup, DropdownMenuSeparator, DropdownMenuLabel, DropdownMenuContent, DropdownMenuTrigger, DropdownMenu,
HoverCardContent, HoverCardTrigger, HoverCard,
Badge, Avatar, Tooltip,
MarkdownPreview, TableCommon,
},
setup() setup()
{ {
const filter: FilterModel = new FilterModel() const filter: FilterModel = new FilterModel()
@ -121,7 +130,9 @@ export default defineComponent({
return { return {
loading: false, loading: false,
data: [], data: [],
pagination: {} as PaginationModel, pageIndex: 1,
pageSize: 10,
dataCount: 0,
contextData: null as DatasetModel | null, contextData: null as DatasetModel | null,
rebuildVisible: false, rebuildVisible: false,
historyVisible: false, historyVisible: false,
@ -132,26 +143,45 @@ export default defineComponent({
}, },
created() created()
{ {
this.handlerInitialize() this.handleInitialize()
}, },
methods: { methods: {
handlerInitialize() handleInitialize()
{ {
this.loading = true this.loading = true
DatasetService.getAll(this.filter) DatasetService.getAll(this.filter)
.then((response) => { .then((response) => {
if (response.status) { if (response.status) {
this.data = response.data.content this.data = response.data.content
this.pagination = PaginationRequest.of(response.data) this.dataCount = response.data.total
this.pageSize = response.data.size
this.pageIndex = response.data.page
} }
}) })
.finally(() => this.loading = false) .finally(() => this.loading = false)
}, },
handlerChangePage(value: PaginationModel) fetchData(value: number)
{ {
this.filter.page = value.currentPage this.filter.page = value
this.filter.size = value.pageSize this.filter.size = this.pageSize
this.handlerInitialize() this.handleInitialize()
},
onPageChange(value: number)
{
this.fetchData(value)
},
onPrevChange(value: number)
{
this.fetchData(value)
},
onNextChange(value: number)
{
this.fetchData(value)
},
onSizeChange(value: number)
{
this.pageSize = value
this.fetchData(this.pageIndex)
}, },
handlerRebuild(record: DatasetModel | null, opened: boolean) handlerRebuild(record: DatasetModel | null, opened: boolean)
{ {

View File

@ -6,30 +6,30 @@
*/ */
const createHeaders = (i18n: any) => { const createHeaders = (i18n: any) => {
return [ return [
{key: 'id', hidden: true, header: i18n.t('common.id'), width: 80}, { key: 'id', label: i18n.t('common.id') },
{key: 'name', hidden: true, header: i18n.t('common.name'), width: 150}, { key: 'name', label: i18n.t('common.name') },
{key: 'description', hidden: true, header: i18n.t('common.description'), width: 250}, { key: 'description', label: i18n.t('common.description') },
{key: 'source', hidden: true, header: i18n.t('common.source'), slot: 'source', width: 100}, { key: 'source', label: i18n.t('common.source'), slot: 'source' },
{key: 'syncMode', hidden: true, header: i18n.t('dataset.common.syncMode'), slot: 'syncMode', width: 90}, { key: 'syncMode', label: i18n.t('dataset.common.syncMode'), slot: 'syncMode' },
{key: 'scheduler', hidden: true, header: i18n.t('common.scheduler'), width: 80}, { key: 'scheduler', label: i18n.t('common.scheduler') },
{key: 'executor', hidden: true, header: i18n.t('common.executor'), width: 80}, { key: 'executor', label: i18n.t('common.executor') },
{key: 'state', hidden: true, header: i18n.t('common.state'), slot: 'state', width: 80, class: 'text-center'}, { key: 'state', label: i18n.t('common.state'), slot: 'state' },
{key: 'totalRows', hidden: true, header: i18n.t('dataset.common.totalRows')}, { key: 'totalRows', label: i18n.t('dataset.common.totalRows') },
{key: 'totalSize', hidden: true, header: i18n.t('dataset.common.totalSize')}, { key: 'totalSize', label: i18n.t('dataset.common.totalSize') },
{key: 'createTime', hidden: true, header: i18n.t('common.createTime')}, { key: 'createTime', label: i18n.t('common.createTime') },
{key: 'updateTime', hidden: true, header: i18n.t('common.updateTime')}, { key: 'updateTime', label: i18n.t('common.updateTime') },
{key: 'action', hidden: true, header: i18n.t('common.action'), slot: 'action', width: 80, class: 'text-center'} { key: 'action', label: i18n.t('common.action'), slot: 'action' }
] ]
} }
const createHistoryHeaders = (i18n: any) => { const createHistoryHeaders = (i18n: any) => {
return [ return [
{key: 'id', hidden: true, header: i18n.t('common.id'), width: 80, class: 'text-center'}, { key: 'id', label: i18n.t('common.id') },
{key: 'elapsed', hidden: true, header: i18n.t('common.elapsed'), width: 80, class: 'text-center'}, { key: 'elapsed', label: i18n.t('common.elapsed') },
{key: 'count', hidden: true, header: i18n.t('common.count'), width: 80, class: 'text-center'}, { key: 'count', label: i18n.t('common.count') },
{key: 'createTime', hidden: true, header: i18n.t('common.createTime'), class: 'text-center'}, { key: 'createTime', label: i18n.t('common.createTime') },
{key: 'updateTime', hidden: true, header: i18n.t('common.updateTime'), class: 'text-center'}, { key: 'updateTime', label: i18n.t('common.updateTime') },
{key: 'state', hidden: true, header: i18n.t('common.state'), slot: 'state', width: 100, class: 'text-center'} { key: 'state', label: i18n.t('common.state'), slot: 'state' }
] ]
} }

View File

@ -0,0 +1,94 @@
<template>
<ShadcnModal v-model="localVisible" :title="$t('common.configure')" @on-close="onCancel">
<ShadcnForm v-model="formState" @on-error="console.log($event)" @on-submit="onSubmit">
<ShadcnSpace wrap>
<ShadcnFormItem name="name"
class="w-full"
:label="$t('common.name')"
:rules="[{ required: true, message: $t('common.name') }]">
<ShadcnInput v-model="formState.name" name="name"/>
</ShadcnFormItem>
<ShadcnFormItem class="w-full" name="description" :label="$t('common.description')">
<ShadcnInput v-model="formState.description" type="textarea" name="description"/>
</ShadcnFormItem>
<ShadcnFormItem class="w-full" name="build" :label="$t('dataset.common.continuousBuild')">
<ShadcnSwitch v-model="formState.build" name="build"/>
</ShadcnFormItem>
</ShadcnSpace>
<ShadcnSpace>
<ShadcnButton type="default" @click="onCancel">
{{ $t('common.cancel') }}
</ShadcnButton>
<ShadcnButton submit :disabled="published" :loading="published">
{{ $t('common.publish') }}
</ShadcnButton>
</ShadcnSpace>
</ShadcnForm>
</ShadcnModal>
</template>
<script setup lang="ts">
import { getCurrentInstance, ref } from 'vue'
import router from '@/router'
import ReportService from '@/services/report.ts'
const emit = defineEmits(['close'])
const { proxy } = getCurrentInstance()!
const props = defineProps<{
visible: boolean,
info?: { name: string, description: string, build: boolean }
id?: number
dimension?: any
commitOptions?: any
configure?: any
}>()
const localVisible = ref(props.visible)
const published = ref(false)
const formState = ref(props.info || { name: undefined, description: undefined, build: false })
const onSubmit = () => {
published.value = true
const obj = props.dimension
const configure = {
id: 0,
name: formState.value.name,
realtime: true,
type: 'DATASET',
configure: JSON.stringify(props.commitOptions),
dataset: {
id: obj.dataset.id
},
query: JSON.stringify(props.configure),
description: formState.value.description
}
if (props.id) {
configure.id = props.id
}
ReportService.saveOrUpdate(configure)
.then(response => {
if (response.status) {
proxy?.$Message.success({
content: proxy.$t('report.tip.publishSuccess').replace('$VALUE', formState.value.name),
showIcon: true
})
if (formState.value.build) {
router.push('/admin/report')
}
onCancel()
}
})
.finally(() => published.value = false)
}
const onCancel = () => {
emit('close', !props.visible)
}
</script>

View File

@ -1,53 +1,41 @@
<template> <template>
<div v-for="state in states"> <div v-for="state in states" class="p-2">
<Alert class="flex items-center" v-if="(state as string) === 'START'"> <ShadcnAlert v-if="String(state) === 'START'">
<AlertTitle class="flex-grow"> <span>{{ $t('dataset.common.stateOfStarted') }}</span>
{{ $t('dataset.common.stateOfStarted') }} <span>{{ $t('dataset.complete') }}</span>
</AlertTitle> </ShadcnAlert>
<AlertDescription class="ml-4">
{{ $t('dataset.complete') }} <ShadcnAlert v-else-if="String(state).startsWith('METADATA_')">
</AlertDescription> <span>{{ $t('dataset.common.stateOfMetadata') }}</span>
</Alert> <span v-if="String(state).endsWith('SUCCESS')">
<Alert class="flex items-center mt-2" v-else-if="(state as string).startsWith('METADATA_')"> {{ $t('dataset.common.complete') }}
<AlertTitle class="flex-grow"> </span>
{{ $t('dataset.common.stateOfMetadata') }} <span v-else-if="String(state).endsWith('FAILED')">
</AlertTitle> {{ $t('dataset.common.failed') }}
<AlertDescription class="ml-4"> </span>
<span v-if="(state as string).endsWith('SUCCESS')" class="content"> </ShadcnAlert>
{{ $t('dataset.common.complete') }}
</span> <ShadcnAlert v-else-if="String(state).startsWith('TABLE_')">
<span v-else-if="(state as string).endsWith('FAILED')" class="content"> <span>{{ $t('dataset.common.stateOfCreateTable') }}</span>
{{ $t('dataset.common.failed') }} <span v-if="String(state).endsWith('SUCCESS')">
</span> {{ $t('dataset.common.complete') }}
</AlertDescription> </span>
</Alert> <span v-else-if="String(state).endsWith('FAILED')">
<Alert class="flex items-center mt-2" v-else-if="(state as string).startsWith('TABLE_')"> {{ $t('dataset.common.failed') }}
<AlertTitle class="flex-grow"> </span>
{{ $t('dataset.common.stateOfCreateTable') }} </ShadcnAlert>
</AlertTitle>
<AlertDescription class="ml-4">
<span v-if="(state as string).endsWith('SUCCESS')" class="content">
{{ $t('dataset.common.complete') }}
</span>
<span v-else-if="(state as string).endsWith('FAILED')" class="content">
{{ $t('dataset.common.failed') }}
</span>
</AlertDescription>
</Alert>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { Alert, AlertTitle } from '@/components/ui/alert'
export default defineComponent({ export default defineComponent({
name: 'DatasetState', name: 'DatasetState',
components: {AlertTitle, Alert},
props: { props: {
states: { states: {
type: Array type: Array
} }
} }
}); })
</script> </script>

View File

@ -1,127 +1,86 @@
<template> <template>
<div> <ShadcnModal v-model="visible"
<AlertDialog :default-open="visible"> height="300"
<AlertDialogContent> :title="title"
<AlertDialogHeader> @on-close="onCancel">
<AlertDialogTitle class="border-b -mt-4 pb-2">{{ title }}</AlertDialogTitle> <ShadcnForm v-model="formState" @on-submit="onCommit">
</AlertDialogHeader> <div v-if="String(columnType) === 'FILTER'">
<div v-if="formState"> <ShadcnFormItem name="expression" :label="$t('common.expression')">
<div v-if="columnType === 'FILTER'"> <ShadcnSelect v-model="formState.expression" :placeholder="$t('dataset.tip.selectExpression')">
<FormField class="flex items-center" name="expression"> <template #options>
<FormItem class="flex-1"> <ShadcnSelectOption :value="Expression.IS_NULL" :label="$t('dataset.common.columnExpressionIsNull')"/>
<div class="flex items-center"> <ShadcnSelectOption :value="Expression.IS_NOT_NULL" :label="$t('dataset.common.columnExpressionIsNotNull')"/>
<FormLabel class="mr-1 w-40 text-right"> <ShadcnSelectOption :value="Expression.IS_LIKE" :label="$t('dataset.common.columnExpressionIsLike')"/>
{{ $t('common.expression') }} <ShadcnSelectOption :value="Expression.IS_NOT_LIKE" :label="$t('dataset.common.columnExpressionIsNotLike')"/>
</FormLabel> <ShadcnSelectOption :value="Expression.EQ" :label="$t('dataset.common.columnExpressionEquals')"/>
<FormControl> <ShadcnSelectOption :value="Expression.NE" :label="$t('dataset.common.columnExpressionNotEquals')"/>
<Select v-model="formState.expression"> <ShadcnSelectOption :value="Expression.GT" :label="$t('dataset.common.columnExpressionGreaterThan')"/>
<SelectTrigger class="w-full"> <ShadcnSelectOption :value="Expression.GTE" :label="$t('dataset.common.columnExpressionGreaterThanOrEquals')"/>
<SelectValue :placeholder="$t('dataset.tip.selectExpression')"/> <ShadcnSelectOption :value="Expression.LT" :label="$t('dataset.common.columnExpressionLessThan')"/>
</SelectTrigger> <ShadcnSelectOption :value="Expression.LTE" :label="$t('dataset.common.columnExpressionLessThanOrEquals')"/>
<SelectContent> </template>
<SelectItem :value="Expression.IS_NULL">{{ $t('dataset.common.columnExpressionIsNull') }}</SelectItem> </ShadcnSelect>
<SelectItem :value="Expression.IS_NOT_NULL">{{ $t('dataset.common.columnExpressionIsNotNull') }}</SelectItem> </ShadcnFormItem>
<SelectItem :value="Expression.IS_LIKE">{{ $t('dataset.common.columnExpressionIsLike') }}</SelectItem>
<SelectItem :value="Expression.IS_NOT_LIKE">{{ $t('dataset.common.columnExpressionIsNotLike') }}</SelectItem> <ShadcnFormItem v-if="formState.expression && formState.expression !== Expression.IS_NULL && formState.expression !== Expression.IS_NOT_NULL"
<SelectItem :value="Expression.EQ">{{ $t('dataset.common.columnExpressionEquals') }}</SelectItem> name="value"
<SelectItem :value="Expression.NE">{{ $t('dataset.common.columnExpressionNotEquals') }}</SelectItem> :label="$t('common.value')">
<SelectItem :value="Expression.GT">{{ $t('dataset.common.columnExpressionGreaterThan') }}</SelectItem> <ShadcnInput v-model="formState.value"/>
<SelectItem :value="Expression.GTE">{{ $t('dataset.common.columnExpressionGreaterThanOrEquals') }}</SelectItem> </ShadcnFormItem>
<SelectItem :value="Expression.LT">{{ $t('dataset.common.columnExpressionLessThan') }}</SelectItem> </div>
<SelectItem :value="Expression.LTE">{{ $t('dataset.common.columnExpressionLessThanOrEquals') }}</SelectItem>
</SelectContent> <div v-else>
</Select> <ShadcnSpace wrap>
</FormControl> <ShadcnFormItem v-if="String(columnType) === 'METRIC'"
</div> class="w-full"
</FormItem> name="expression"
</FormField> :label="$t('common.expression')">
<FormField v-if="formState.expression && formState.expression !== Expression.IS_NULL && formState.expression !== Expression.IS_NOT_NULL" class="flex items-center" <ShadcnSelect v-model="formState.expression" :placeholder="$t('dataset.tip.selectExpression')" @on-change="onUpdateAlias">
name="value"> <template #options>
<FormItem class="flex-1 mt-3"> <ShadcnSelectOption v-if="formState.type === ColumnType.NUMBER" :value="Expression.SUM" :label="$t('dataset.common.columnExpressionSum')"/>
<div class="flex items-center"> <ShadcnSelectOption :value="Expression.COUNT" :label="$t('dataset.common.columnExpressionCount')"/>
<FormLabel class="mr-1 w-40 text-right"> <ShadcnSelectOption :value="Expression.MAX" :label="$t('dataset.common.columnExpressionMax')"/>
{{ $t('common.value') }} <ShadcnSelectOption :value="Expression.MIN" :label="$t('dataset.common.columnExpressionMin')"/>
</FormLabel> <ShadcnSelectOption v-if="formState.type === ColumnType.NUMBER" :value="Expression.AVG" :label="$t('dataset.common.columnExpressionAvg') "/>
<FormControl> </template>
<Input v-model="formState.value"/> </ShadcnSelect>
</FormControl> </ShadcnFormItem>
</div>
</FormItem> <ShadcnFormItem class="w-full" name="alias" :label="$t('common.alias')">
</FormField> <ShadcnInput v-model="formState.alias"/>
</div> </ShadcnFormItem>
<div v-else>
<FormField v-if="columnType === 'METRIC'" class="flex items-center" name="expression"> <ShadcnFormItem class="w-full" name="order" :label="$t('common.sort')">
<FormItem class="flex-1"> <ShadcnToggleGroup v-model="formState.order" @onChange="onChangeToggle">
<div class="flex items-center"> <ShadcnToggle class="w-10 h-10" value="">{{ $t('dataset.common.columnSortNone') }}</ShadcnToggle>
<FormLabel class="mr-1 w-40 text-right"> <ShadcnToggle class="w-10 h-10" value="ASC">{{ $t('dataset.common.columnOrderAsc') }}</ShadcnToggle>
{{ $t('common.expression') }} <ShadcnToggle class="w-10 h-10" value="DESC">{{ $t('dataset.common.columnOrderDesc') }}</ShadcnToggle>
</FormLabel> </ShadcnToggleGroup>
<FormControl> </ShadcnFormItem>
<Select v-model="formState.expression" @update:modelValue="handlerUpdateAlias">
<SelectTrigger class="w-full"> <ShadcnFormItem v-if="String(columnType) === 'DIMENSION'"
<SelectValue :placeholder="$t('dataset.tip.selectExpression')"/> class="w-full"
</SelectTrigger> name="function"
<SelectContent> :label="$t('dataset.common.customFunction')">
<SelectItem v-if="formState.type === ColumnType.NUMBER" :value="Expression.SUM"> {{ $t('dataset.common.columnExpressionSum') }}</SelectItem> <ShadcnInput v-model="formState.function"/>
<SelectItem :value="Expression.COUNT">{{ $t('dataset.common.columnExpressionCount') }}</SelectItem> </ShadcnFormItem>
<SelectItem :value="Expression.MAX">{{ $t('dataset.common.columnExpressionMax') }}</SelectItem> </ShadcnSpace>
<SelectItem :value="Expression.MIN">{{ $t('dataset.common.columnExpressionMin') }}</SelectItem> </div>
<SelectItem v-if="formState.type === ColumnType.NUMBER" :value="Expression.AVG">{{ $t('dataset.common.columnExpressionAvg') }}</SelectItem>
</SelectContent>
</Select> <div class="flex justify-end">
</FormControl> <ShadcnSpace>
</div> <ShadcnButton type="default" @click="onCancel">
</FormItem> {{ $t('common.cancel') }}
</FormField> </ShadcnButton>
<FormField class="flex items-center" name="alias">
<FormItem class="flex-1 mt-3"> <ShadcnButton submit>
<div class="flex items-center"> {{ $t('common.save') }}
<FormLabel class="mr-1 w-40 text-right"> </ShadcnButton>
{{ $t('common.alias') }} </ShadcnSpace>
</FormLabel> </div>
<FormControl> </ShadcnForm>
<Input v-model="formState.alias"/> </ShadcnModal>
</FormControl>
</div>
</FormItem>
</FormField>
<FormField class="flex items-center" name="order">
<FormItem class="flex-1 mt-3">
<div class="flex items-center">
<FormLabel class="mr-1 w-[25%] text-right">
{{ $t('common.sort') }}
</FormLabel>
<FormControl>
<ToggleGroup v-model="formState.order" type="single">
<ToggleGroupItem value="">{{ $t('dataset.common.columnSortNone') }}</ToggleGroupItem>
<ToggleGroupItem value="ASC">{{ $t('dataset.common.columnOrderAsc') }}</ToggleGroupItem>
<ToggleGroupItem value="DESC">{{ $t('dataset.common.columnOrderDesc') }}</ToggleGroupItem>
</ToggleGroup>
</FormControl>
</div>
</FormItem>
</FormField>
<FormField v-if="columnType === 'DIMENSION'" class="flex items-center" name="function">
<FormItem class="flex-1 mt-3">
<div class="flex items-center">
<FormLabel class="mr-1 w-40 text-right">
{{ $t('dataset.common.customFunction') }}
</FormLabel>
<FormControl>
<Input v-model="formState.function"/>
</FormControl>
</div>
</FormItem>
</FormField>
</div>
</div>
<AlertDialogFooter class="-mb-4 border-t pt-2">
<Button variant="secondary" @click="handlerCancel">{{ $t('common.cancel') }}</Button>
<Button @click="handlerCommit">{{ $t('common.save') }}</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -129,32 +88,10 @@ import { defineComponent, PropType } from 'vue'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { ColumnType, Type } from '@/views/pages/admin/dataset/Type' import { ColumnType, Type } from '@/views/pages/admin/dataset/Type'
import { Expression } from '@/views/pages/admin/dataset/Expression' import { Expression } from '@/views/pages/admin/dataset/Expression'
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger
} from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Input } from '@/components/ui/input'
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
import { Model } from '../../model/model' import { Model } from '../../model/model'
export default defineComponent({ export default defineComponent({
name: 'DatasetColumnConfigure', name: 'DatasetColumnConfigure',
components: {
ToggleGroup, ToggleGroupItem,
Input,
Button,
AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,
SelectGroup, SelectTrigger, SelectContent, SelectItem, Select, SelectLabel, SelectValue,
},
props: { props: {
isVisible: { isVisible: {
type: Boolean, type: Boolean,
@ -196,15 +133,15 @@ export default defineComponent({
{ {
return { return {
title: '', title: '',
formState: null as Model | null formState: {} as Model
} }
}, },
created() created()
{ {
this.handlerInitialize() this.handleInitialize()
}, },
methods: { methods: {
handlerInitialize() handleInitialize()
{ {
this.formState = {} as Model this.formState = {} as Model
if (this.formState) { if (this.formState) {
@ -225,7 +162,7 @@ export default defineComponent({
} }
} }
}, },
handlerUpdateAlias() onUpdateAlias()
{ {
let prefix = `${ this.$t('dataset.common.columnModeMetric') }` let prefix = `${ this.$t('dataset.common.columnModeMetric') }`
if (this.columnType === Type.DIMENSION) { if (this.columnType === Type.DIMENSION) {
@ -256,15 +193,20 @@ export default defineComponent({
} }
} }
}, },
handlerCommit() onCommit()
{ {
if (this.formState) { if (this.formState) {
this.formState.mode = this.columnType as unknown as string this.formState.mode = String(this.columnType)
this.$emit('commit', this.formState) this.$emit('commit', this.formState)
this.handlerCancel()
this.onCancel()
} }
}, },
handlerCancel() onChangeToggle(value: any)
{
this.formState.order = value[0]
},
onCancel()
{ {
this.visible = false this.visible = false
} }

View File

@ -1,12 +1,13 @@
<template> <template>
<ShadcnModal v-model="visible" <ShadcnModal v-model="visible"
width="60%" width="60%"
height="80%" height="60%"
:title="title" :title="title"
@on-close="onCancel"> @on-close="onCancel">
<div class="relative w-full h-full items-center"> <div class="relative w-full h-full justify-center items-center">
<div v-if="info"> <div v-if="info">
<VisualView :code="info.dataset?.code" <VisualView class="h-full"
:code="info.dataset?.code"
:type="info.type" :type="info.type"
:configuration="JSON.parse(info.configure as string)" :configuration="JSON.parse(info.configure as string)"
:query="info.type === 'DATASET' ? JSON.parse(info.query as string) : info.query" :query="info.type === 'DATASET' ? JSON.parse(info.query as string) : info.query"