diff --git a/.env b/.env index 3c2b7310..733a8577 100644 --- a/.env +++ b/.env @@ -2,10 +2,10 @@ VITE_DEV_PORT = '8001' # development path -VITE_DEV_PATH = / +VITE_DEV_PATH = '/' # production path -VITE_PRO_PATH = / +VITE_PRO_PATH = '/' # spa-title VITE_GLOB_APP_TITLE = GoView diff --git a/src/api/http.ts b/src/api/http.ts index 8984d137..2738217f 100644 --- a/src/api/http.ts +++ b/src/api/http.ts @@ -1,34 +1,35 @@ import axiosInstance from './axios' import { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum' -// 缓存处理 -const filterUrl = (url: string) => { - return url.indexOf('?') !== -1 ? `${url}&time=${new Date().getTime()}` : `${url}?time=${new Date().getTime()}` -} - -export const get = (params: object, url: string) => { +export const get = (url: string, params: object) => { return axiosInstance({ - url: filterUrl(url), + url: url, method: RequestEnum.GET, - params + params, }) } -export const post = (params: object, url: string, headersType: string) => { +export const post = (url: string, params: object, headersType: string) => { return axiosInstance({ url: url, method: RequestEnum.POST, data: params, headers: { - 'Content-Type': headersType || ContentTypeEnum.JSON - } + 'Content-Type': headersType || ContentTypeEnum.JSON, + }, }) } -export const del = (params: object, url: string) => { +export const del = (url: string, params: object) => { return axiosInstance({ - url: filterUrl(url), + url: url, method: RequestEnum.DELETE, - params + params, }) -} \ No newline at end of file +} + +export default { + get, + post, + del, +} diff --git a/src/api/mock/index.js b/src/api/mock/index.js new file mode 100644 index 00000000..084afc54 --- /dev/null +++ b/src/api/mock/index.js @@ -0,0 +1,13 @@ +import Mock from 'mockjs' +import test from './test.mock' +Mock.setup({ + timeout: '300-600' +}) + +// 单个X数据 +const featchMockData = '/api/mockData' +Mock.mock(/\/api\/test(|\?\S*)$/, 'get', test.featchMockData) + +export { + featchMockData +} \ No newline at end of file diff --git a/src/api/mock/test.mock.js b/src/api/mock/test.mock.js new file mode 100644 index 00000000..71be5933 --- /dev/null +++ b/src/api/mock/test.mock.js @@ -0,0 +1,42 @@ +export default { + // 轮播图 + featchMockData: { + status: 200, + msg: "请求成功", + data: { + dimensions: ["product", "data1", "data2"], + source: [ + { + 'product': '@name', + 'data1|100-900': 3, + 'data2|100-900': 3, + }, + { + 'product': '@name', + 'data1|100-900': 3, + 'data2|100-900': 3, + }, + { + 'product': '@name', + 'data1|100-900': 3, + 'data2|100-900': 3, + }, + { + 'product': '@name', + 'data1|100-900': 3, + 'data2|100-900': 3, + }, + { + 'product': '@name', + 'data1|100-900': 3, + 'data2|100-900': 3, + }, + { + 'product': '@name', + 'data1|100-900': 3, + 'data2|100-900': 3, + }, + ] + } + } +} \ No newline at end of file diff --git a/src/components/GoSkeleton/index.vue b/src/components/GoSkeleton/index.vue index 3e3826da..394e6b03 100644 --- a/src/components/GoSkeleton/index.vue +++ b/src/components/GoSkeleton/index.vue @@ -1,14 +1,14 @@ <template> <div v-show="load" class="go-skeleton"> <div v-show="repeat == 1"> - <n-skeleton v-bind="$attrs"></n-skeleton> + <n-skeleton class="item" v-bind="$attrs"></n-skeleton> </div> <div v-show="repeat == 2"> - <n-skeleton v-bind="$attrs"></n-skeleton> + <n-skeleton class="item" v-bind="$attrs"></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 class="item" v-bind="$attrs" :repeat="repeat - 2"></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> @@ -29,9 +29,11 @@ defineProps({ </script> <style lang="scss" scoped> -@include go('skeleton') { +@include go("skeleton") { .item { margin-top: 5px; + margin-left: 5px; } + padding-bottom: 5px; } </style> \ No newline at end of file diff --git a/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataAjax/index.ts b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataAjax/index.ts new file mode 100644 index 00000000..73e38fa1 --- /dev/null +++ b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataAjax/index.ts @@ -0,0 +1,3 @@ +import ChartDataAjax from './index.vue' + +export { ChartDataAjax } diff --git a/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataAjax/index.vue b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataAjax/index.vue new file mode 100644 index 00000000..c1549717 --- /dev/null +++ b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataAjax/index.vue @@ -0,0 +1,11 @@ +<template> + <div>ajax</div> +</template> + +<script setup lang="ts"> + + +</script> + +<style lang="scss" scoped> +</style> \ No newline at end of file diff --git a/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMatchingAndShow/index.ts b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMatchingAndShow/index.ts new file mode 100644 index 00000000..79652bab --- /dev/null +++ b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMatchingAndShow/index.ts @@ -0,0 +1,3 @@ +import ChartDataMatchingAndShow from './index.vue' + +export { ChartDataMatchingAndShow } diff --git a/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMatchingAndShow/index.vue b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMatchingAndShow/index.vue new file mode 100644 index 00000000..9a1da35b --- /dev/null +++ b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMatchingAndShow/index.vue @@ -0,0 +1,195 @@ +<template> + <n-timeline class="go-chart-configurations-timeline"> + <n-timeline-item type="info" :title="TimelineTitleEnum.MAPPING"> + <n-table striped> + <thead> + <tr> + <th v-for="item in tableTitle" :key="item">{{ item }}</th> + </tr> + </thead> + <tbody v-show="!tableLoad"> + <go-skeleton :repeat="3" :load="tableLoad" style="width: 200px;"></go-skeleton> + <tr v-for="(item, index) in tableData" :key="index"> + <td>{{ item.field }}</td> + <td>{{ item.mapping }}</td> + <td> + <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> + </tbody> + </n-table> + </n-timeline-item> + <n-timeline-item type="success" :title="TimelineTitleEnum.CONTENT"> + <n-space vertical> + <n-text depth="3">数据需要符合 ECharts-setdata 规范</n-text> + <n-space class="source-btn-box"> + <n-upload + v-model:file-list="uploadFileListRef" + :show-file-list="false" + :customRequest="customRequest" + @before-upload="beforeUpload" + > + <n-space> + <n-button class="sourceBtn-item"> + <template #icon> + <n-icon> + <document-add-icon /> + </n-icon> + </template> + 导入(json / txt) + </n-button> + </n-space> + </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> +</template> + +<script setup lang="ts"> +import { ref, computed, watch, nextTick, PropType } from 'vue' +import { UploadCustomRequestOptions } from 'naive-ui' +import { FileTypeEnum } from '@/enums/fileTypeEnum' +import { readFile, downloadFile } from '@/utils' +import { icon } from '@/plugins' +import { DataResultEnum, TimelineTitleEnum } from '../../index.d' + +const props = defineProps({ + tableData: { + type: Object, + required: true + } +}) + +const tableLoad = ref(true) + +// 表格标题 +const tableTitle = ['字段', '映射', '状态'] + +// 表格数据加载 +watch(() => props.tableData.value, (newData: object[]) => { + if (!(newData && newData.length !== 0)) { + tableLoad.value = false + } +}, { + immediate: true +}) + +const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon +const uploadFileListRef = ref() +const source = ref() +const dimensions = ref() + +// 获取数据 +const getSource = computed(() => { + return JSON.stringify(source.value) +}) + +watch(() => props.targetData?.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) + } + }) +}) + +//@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) => { + props.targetData.option.dataset = JSON.parse(fileData) + }); + } else { + window['$message'].error('导入数据失败,请稍后重试或联系管理员!') + } + }) +} + +// 下载文件 +const download = () => { + try { + window['$message'].success('正在下载文件!') + downloadFile(JSON.stringify(props.targetData?.option?.dataset), undefined, 'json') + } catch (error) { + window['$message'].success('下载失败,数据错误!') + } +} +</script> + +<style lang="scss" scoped> +@include go("chart-configurations-data-static") { + @include deep() { + pre { + white-space: pre-wrap; + word-wrap: break-word; + } + } + .source-btn-box { + margin-top: 10px !important; + } +} +</style> diff --git a/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataStatic/index.ts b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataStatic/index.ts new file mode 100644 index 00000000..1edd8371 --- /dev/null +++ b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataStatic/index.ts @@ -0,0 +1,3 @@ +import ChartDataStatic from './index.vue' + +export { ChartDataStatic } diff --git a/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataStatic/index.vue b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataStatic/index.vue new file mode 100644 index 00000000..8813fee7 --- /dev/null +++ b/src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataStatic/index.vue @@ -0,0 +1,33 @@ +<template> + <div class="go-chart-configurations-data-static" v-if="targetData"> + <ChartDataMatchingAndShow :tableData="targetData"></ChartDataMatchingAndShow> + </div> +</template> + +<script setup lang="ts"> +import { PropType } from 'vue' +import { CreateComponentType } from '@/packages/index.d' +import { ChartDataMatchingAndShow } from '../ChartDataMatchingAndShow' + +const props = defineProps({ + targetData: { + type: Object as PropType<CreateComponentType>, + required: true + } +}) + +</script> + +<style lang="scss" scoped> +@include go("chart-configurations-data-static") { + @include deep() { + pre { + white-space: pre-wrap; + word-wrap: break-word; + } + } + .source-btn-box { + margin-top: 10px !important; + } +} +</style> diff --git a/src/views/chart/ContentConfigurations/components/ChartData/index.vue b/src/views/chart/ContentConfigurations/components/ChartData/index.vue index ce81b219..c4970f56 100644 --- a/src/views/chart/ContentConfigurations/components/ChartData/index.vue +++ b/src/views/chart/ContentConfigurations/components/ChartData/index.vue @@ -1,98 +1,28 @@ <template> <div class="go-chart-configurations-data" v-if="targetData"> <setting-item-box name="请求方式" :alone="true"> - <n-select - v-model:value="targetData.data.requestDataType" - :options="selectOptions" - @on-update="selectHandle" - /> + <n-select v-model:value="targetData.data.requestDataType" :options="selectOptions" /> </setting-item-box> - <n-timeline> - <n-timeline-item type="info" :title="TimelineTitleEnum.MAPPING"> - <n-table striped> - <thead> - <tr> - <th v-for="item in tableTitle" :key="item">{{ item }}</th> - </tr> - </thead> - <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 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> - </tbody> - </n-table> - </n-timeline-item> - <n-timeline-item type="success" :title="TimelineTitleEnum.CONTENT"> - <n-space vertical> - <n-text depth="3">数据需要符合 ECharts-setdata 规范</n-text> - <n-space class="source-btn-box"> - <n-upload - v-model:file-list="uploadFileListRef" - :show-file-list="false" - :customRequest="customRequest" - @before-upload="beforeUpload" - > - <n-space> - <n-button class="sourceBtn-item"> - <template #icon> - <n-icon> - <document-add-icon /> - </n-icon> - </template> - 导入(json / txt) - </n-button> - </n-space> - </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> + <!-- 静态 --> + <chart-data-static + v-if="targetData.data.requestDataType === RequestDataTypeEnum.STATIC" + :targetData="targetData" + ></chart-data-static> + <!-- 动态 --> + <chart-data-ajax v-else></chart-data-ajax> </div> </template> <script setup lang="ts"> -import { ref, 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, TimelineTitleEnum, SelcetOptionsLableEnum, SelectOptionsType } from './index.d' -import { icon } from '@/plugins' +import { ChartDataStatic } from './components/ChartDataStatic/index' +import { ChartDataAjax } from './components/ChartDataAjax/index' +import { SelectOptionsType, SelcetOptionsLableEnum } from './index.d' -const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon - -const uploadFileListRef = ref() const { targetData } = useTargetData() -const source = ref() -const dimensions = ref() -// 表格标题 -const tableTitle = ['字段', '映射', '状态'] // 选项 const selectOptions: SelectOptionsType[] = [ { @@ -102,111 +32,14 @@ const selectOptions: SelectOptionsType[] = [ { label: SelcetOptionsLableEnum.AJAX, value: RequestDataTypeEnum.AJAX, - disabled: true, } ] -// 获取数据 -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 = () => { - try { - window['$message'].success('正在下载文件!') - downloadFile(JSON.stringify(targetData.value?.option?.dataset), undefined, 'json') - } catch (error) { - window['$message'].success('下载失败,数据错误!') - } -} </script> <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>