feat: 新增数据校验,数据导入导出

This commit is contained in:
mtruning 2022-03-19 23:28:33 +08:00
parent e672b75453
commit 8ee18819c5
11 changed files with 270 additions and 66 deletions

View File

@ -1,16 +1,16 @@
<template>
<div v-show="load">
<div v-show="load" class="go-skeleton">
<div v-show="repeat == 1">
<n-skeleton v-bind="$attrs"></n-skeleton>
</div>
<div v-show="repeat == 2">
<n-skeleton v-bind="$attrs"></n-skeleton>
<n-skeleton v-bind="$attrs" style="width: 60%;"></n-skeleton>
<n-skeleton class="item" v-bind="$attrs" style="width: 60%;"></n-skeleton>
</div>
<div v-show="repeat > 2">
<n-skeleton v-bind="$attrs" :repeat="repeat - 2"></n-skeleton>
<n-skeleton v-bind="$attrs" style="width: 60%;"></n-skeleton>
<n-skeleton v-bind="$attrs" style="width: 50%;"></n-skeleton>
<n-skeleton class="item" v-bind="$attrs" style="width: 60%;"></n-skeleton>
<n-skeleton class="item" v-bind="$attrs" style="width: 50%;"></n-skeleton>
</div>
</div>
</template>
@ -27,3 +27,11 @@ defineProps({
}
})
</script>
<style lang="scss" scoped>
@include go('skeleton') {
.item {
margin-top: 5px;
}
}
</style>

10
src/enums/fileTypeEnum.ts Normal file
View File

@ -0,0 +1,10 @@
// 文件上传时的格式映射
export enum FileTypeEnum {
// 文档
TXT = 'text/plain',
JSON = 'application/json',
// 图片
PNG = 'image/png',
JPEG = 'image/jpeg',
GIF = 'image/gif',
}

View File

@ -2,8 +2,9 @@ import { echartOptionProfixHandle, publicConfig } from '@/packages/public'
import { BarCommonConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = ['legend', 'xAxis', 'yAxis', 'dataset']
export const includes = ['legend', 'xAxis', 'yAxis']
export const option = {
tooltip: {
@ -25,6 +26,7 @@ export const option = {
show: true,
type: 'value'
},
dataset: { ...dataJson },
series: [
{
type: 'bar',

View File

@ -43,6 +43,7 @@ use([
])
const option = computed(() => {
return setData(mergeTheme(props.chartConfig.option, props.themeSetting, includes), dataJson)
// TODO dataset
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
</script>

View File

@ -69,7 +69,9 @@ import {
AlignVerticalTop as AlignVerticalTopIcon,
AlignHorizontalCenter as AlignHorizontalCenterIcon,
AlignHorizontalRight as AlignHorizontalRightIcon,
AlignVerticalBottom as AlignVerticalBottomIcon
AlignVerticalBottom as AlignVerticalBottomIcon,
DocumentAdd as DocumentAddIcon,
DocumentDownload as DocumentDownloadIcon,
} from '@vicons/carbon'
const ionicons5 = {
@ -205,7 +207,11 @@ const carbon = {
AlignVerticalTopIcon,
AlignHorizontalCenterIcon,
AlignHorizontalRightIcon,
AlignVerticalBottomIcon
AlignVerticalBottomIcon,
// 添加文件
DocumentAddIcon,
// 下载文件
DocumentDownloadIcon
}
// https://www.xicons.org/#/ 还有很多

View File

@ -7,6 +7,7 @@ import {
NH2,
NH3,
NH4,
NCode,
NText,
NTime,
NEllipsis,
@ -101,6 +102,7 @@ const naive = create({
NH2,
NH3,
NH4,
NCode,
NText,
NTime,
NEllipsis,

View File

@ -2,7 +2,7 @@ import { CreateComponentType } from '@/packages/index.d'
import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
import type {
ChartColorsNameType,
GlobalThemeJsonType
GlobalThemeJsonType,
} from '@/settings/chartThemes/index'
// 编辑画布属性
@ -13,7 +13,7 @@ export enum EditCanvasTypeEnum {
SCALE = 'scale',
USER_SCALE = 'userScale',
LOCK_SCALE = 'lockScale',
IS_DRAG = 'isDrag'
IS_DRAG = 'isDrag',
}
// 编辑区域
@ -46,7 +46,7 @@ export enum EditCanvasConfigEnum {
CHART_THEME_SETTING = 'chartThemeSetting',
BACKGROUND = 'background',
BACKGROUND_IAMGE = 'backgroundImage',
SELECT_COLOR = 'selectColor'
SELECT_COLOR = 'selectColor',
}
export interface EditCanvasConfigType {
@ -80,7 +80,7 @@ export enum EditCanvasTypeEnum {
START_X = 'startX',
START_Y = 'startY',
X = 'x',
Y = 'y'
Y = 'y',
}
// 鼠标位置
@ -118,15 +118,15 @@ export enum ChartEditStoreEnum {
// 以下需要存储
EDIT_CANVAS_CONFIG = 'editCanvasConfig',
REQUEST_CONFIG = 'requestConfig',
COMPONENT_LIST = 'componentList'
COMPONENT_LIST = 'componentList',
}
// 数据相关
export enum RequestDataTypeEnum {
// 静态数据
STATIC,
STATIC = 0,
// 请求数据
AJAX
AJAX = 1,
}
// 数据配置

43
src/utils/file.ts Normal file
View File

@ -0,0 +1,43 @@
/**
* *
* @param { File } file
*/
export const readFile = (file: File) => {
return new Promise((resolve: Function) => {
try {
const reader = new FileReader()
reader.onload = (evt: ProgressEvent<FileReader>) => {
if (evt.target) {
resolve(evt.target.result)
}
}
reader.readAsText(file)
} catch (error) {
window['$message'].error('文件读取失败!')
}
})
}
/**
*
* @param { string } content
* @param { ?string } filename
* @param { ?string } fileSuffix
*/
export const downloadFile = (
content: string,
filename = new Date().getDate().toString(),
fileSuffix?: string
) => {
const ele = document.createElement('a') // 创建下载链接
ele.download = `${filename}.${fileSuffix}` //设置下载的名称
ele.style.display = 'none' // 隐藏的可下载链接
// 字符内容转变成blob地址
const blob = new Blob([content])
ele.href = URL.createObjectURL(blob)
// 绑定点击时间
document.body.appendChild(ele)
ele.click()
// 然后移除
document.body.removeChild(ele)
}

View File

@ -5,4 +5,5 @@ export * from '@/utils/storage'
export * from '@/utils/style'
export * from '@/utils/plugin'
export * from '@/utils/componets'
export * from '@/utils/type'
export * from '@/utils/type'
export * from '@/utils/file'

View File

@ -0,0 +1,19 @@
import { RequestDataTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
// 匹配结果
export enum DataResultEnum {
NULL = 0,
SUCCESS = 1,
FAILURE = 2,
}
export enum SelcetOptionsLableEnum {
STATIC = '静态数据',
AJAX = '动态请求',
}
export interface SelectOptionsType {
label: SelcetOptionsLableEnum
value: RequestDataTypeEnum
disabled?: boolean
}

View File

@ -1,33 +1,33 @@
<template>
<div class="go-chart-configurations-data">
<setting-item-box v-if="targetData" name="请求方式" :alone="true">
<div class="go-chart-configurations-data" v-if="targetData">
<setting-item-box name="请求方式" :alone="true">
<n-select
v-model:value="targetData.data.requestDataType"
:options="selcetOpeions"
@on-update="updateHandle"
:options="selectOptions"
@on-update="selectHandle"
/>
</setting-item-box>
<n-timeline>
<n-timeline-item type="info" title="数据结构">
<n-timeline-item type="info" title="数据映射">
<n-table striped>
<thead>
<tr>
<th>字段</th>
<th>映射</th>
<th>状态</th>
<th v-for="item in tableTitle" :key="item">{{ item }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in dataStructure" :key="index">
<go-skeleton :repeat="3" :load="tableLoad" style="width: 300px;"></go-skeleton>
<tbody v-show="!tableLoad">
<tr v-for="(item, index) in getDimensionsAndSource" :key="index">
<td>{{ item.field }}</td>
<td>{{ item.mapping }}</td>
<td>
<n-space>
<n-badge
dot
:type="item.result ? 'success' : 'error'"
></n-badge>
<n-text>匹配{{ item.result ? '成功' : '失败' }}</n-text>
<n-space v-if="item.result === 0">
<n-badge dot type="success"></n-badge>
<n-text></n-text>
</n-space>
<n-space v-else>
<n-badge dot :type="item.result === 1 ? 'success' : 'error'"></n-badge>
<n-text>匹配{{ item.result === 1 ? '成功' : '失败' }}</n-text>
</n-space>
</td>
</tr>
@ -35,60 +35,172 @@
</n-table>
</n-timeline-item>
<n-timeline-item type="success" title="静态数据">
<n-code
v-for="(item, index) in code"
:key="index"
:code="item.data"
language="json"
></n-code>
<n-space vertical>
<n-space class="source-btn-box">
<n-upload
v-model:file-list="uploadFileListRef"
:show-file-list="false"
:customRequest="customRequest"
@before-upload="beforeUpload"
>
<n-button class="sourceBtn-item">
<template #icon>
<n-icon>
<document-add-icon />
</n-icon>
</template>
导入json / txt
</n-button>
</n-upload>
<n-button class="sourceBtn-item" @click="download">
<template #icon>
<n-icon>
<document-download-icon />
</n-icon>
</template>
下载
</n-button>
</n-space>
<n-card>
<n-code :code="getSource" language="json"></n-code>
</n-card>
</n-space>
</n-timeline-item>
</n-timeline>
</div>
</template>
<script setup lang="ts">
import { ref, toRaw } from 'vue'
import { ref, toRefs, computed, watch, nextTick } from 'vue'
import { SettingItemBox } from '@/components/ChartItemSetting/index'
import { RequestDataTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { useTargetData } from '../hooks/useTargetData.hook'
import { UploadCustomRequestOptions } from 'naive-ui'
import { FileTypeEnum } from '@/enums/fileTypeEnum'
import { readFile, downloadFile } from '@/utils'
import { DataResultEnum, SelcetOptionsLableEnum, SelectOptionsType } from './index.d'
import { icon } from '@/plugins'
const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon
const uploadFileListRef = ref()
const { targetData } = useTargetData()
const source = ref()
const dimensions = ref()
const code = toRaw((targetData.value.option as any).series)
const selcetOpeions = [
//
const tableTitle = ['字段', '映射', '状态']
//
const selectOptions: SelectOptionsType[] = [
{
label: '静态数据',
label: SelcetOptionsLableEnum.STATIC,
value: RequestDataTypeEnum.STATIC
},
{
label: '动态请求',
value: RequestDataTypeEnum.AJAX
label: SelcetOptionsLableEnum.AJAX,
value: RequestDataTypeEnum.AJAX,
disabled: true,
}
]
const dataStructure = ref([
{
//
field: 'x',
//
mapping: 'xData',
//
result: true
},
{
//
field: 'y',
//
mapping: 'yData',
//
result: true
}
])
const updateHandle = (value: any) => {
console.log(value)
//
const getSource = computed(() => {
return JSON.stringify(source.value)
})
watch(() => targetData.value?.option?.dataset, (newData) => {
if (newData) {
source.value = newData.source
dimensions.value = newData.dimensions
}
}, {
immediate: true
})
//
const matchingHandle = (mapping: string) => {
for (let i = 0; i < source.value.length; i++) {
let res = DataResultEnum.FAILURE
if (source.value[i][mapping] !== undefined) {
return DataResultEnum.SUCCESS
}
return res
}
return DataResultEnum.SUCCESS
}
//
const getDimensionsAndSource = computed(() => {
//
return dimensions.value.map((item: string, index: number) => {
return index === 0 ?
{
//
field: '通用标识',
//
mapping: item,
//
result: DataResultEnum.NULL
} : {
field: `数据项-${index}`,
mapping: item,
result: matchingHandle(item)
}
})
})
//
const tableLoad = computed(() => {
return !getDimensionsAndSource.value || getDimensionsAndSource.value.length === 0
})
//
const selectHandle = () => { }
//@ts-ignore
const beforeUpload = ({ file }) => {
uploadFileListRef.value = []
const type = file.file.type
if (type !== FileTypeEnum.JSON && type !== FileTypeEnum.TXT) {
window['$message'].warning('仅支持上传 【JSON】 格式文件,请重新上传!')
return false
}
return true
}
//
const customRequest = (options: UploadCustomRequestOptions) => {
const { file } = options
nextTick(() => {
if (file.file) {
readFile(file.file).then((fileData: any) => {
targetData.value.option.dataset = JSON.parse(fileData)
});
} else {
window['$message'].error('导入数据失败,请稍后重试或联系管理员!')
}
})
}
//
const download = () => {
window['$message'].success('正在下载文件...')
downloadFile(getSource.value, undefined, 'json')
}
</script>
<style lang="scss" scoped></style>
<style>
</style>
<style lang="scss" scoped>
@include go("chart-configurations-data") {
@include deep() {
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
}
.source-btn-box {
margin-top: 10px !important;
}
}
</style>