fix: 新增列表数据更新,修改数据更新 hook 函数

This commit is contained in:
奔跑的面条 2022-04-02 11:34:54 +08:00
parent 2c2aaaac67
commit 6ae0cd55e6
14 changed files with 210 additions and 135 deletions

View File

@ -3,14 +3,22 @@ import { MockMethod } from 'vite-plugin-mock'
import { RequestHttpEnum } from '@/enums/httpEnum'
// 单个X数据
export const mockDataUrl = '/mock/mockData'
export const chartDataUrl = '/mock/chartData'
export const rankListUrl = '/mock/RankList'
const mockObject: MockMethod[] =[{
// 正则
// url: /\/mock\/mockData(|\?\S*)$/,
url: '/mock/mockData',
method: RequestHttpEnum.GET,
response: () => test.featchMockData
}]
const mockObject: MockMethod[] = [
{
// 正则
// url: /\/mock\/mockData(|\?\S*)$/,
url: '/mock/chartData',
method: RequestHttpEnum.GET,
response: () => test.fetchMockData,
},
{
url: '/mock/rankList',
method: RequestHttpEnum.GET,
response: () => test.fetchRankList,
},
]
export default mockObject
export default mockObject

View File

@ -1,42 +1,62 @@
export default {
// 轮播
featchMockData: {
//
fetchMockData: {
status: 200,
msg: "请求成功",
msg: '请求成功',
data: {
dimensions: ["product", "dataOne", "dataTwo"],
dimensions: ['product', 'dataOne', 'dataTwo'],
source: [
{
'product': '@name',
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
},
{
'product': '@name',
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
},
{
'product': '@name',
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
},
{
'product': '@name',
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
},
{
'product': '@name',
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
},
{
'product': '@name',
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
},
]
}
}
}
],
},
},
// 排名列表
fetchRankList: {
status: 200,
msg: '请求成功',
data: [
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
],
},
}

View File

@ -1,10 +1,10 @@
import type { App } from 'vue'
import LoadingComponent from './index.vue'
import GoLoading from './index.vue'
import AsyncLoading from './index.vue'
import AsyncSkeletonLoading from './LoadingSkeleton.vue'
// 正常组件
export { LoadingComponent }
export { GoLoading }
// 异步
AsyncLoading.install = (app: App): void => {

View File

@ -1,51 +1,76 @@
import { ref, toRefs, watchEffect, nextTick } from 'vue'
import type VChart from 'vue-echarts'
import { http } from '@/api/http'
import { CreateComponentType } from '@/packages/index.d'
import { CreateComponentType, PackagesCategoryEnum } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { isPreview } from '@/utils'
// 获取类型
type ChartEditStoreType = typeof useChartEditStore
/**
* setdata
* @param chartConfig
* setdata
* @param targetComponent
* @param useChartEditStore
* @param updateCallback
*/
export const useChartDataFetch = (chartConfig: CreateComponentType, useChartEditStore: ChartEditStoreType) => {
export const useChartDataFetch = (
targetComponent: CreateComponentType,
useChartEditStore: ChartEditStoreType,
updateCallback?: (...args: any) => any
) => {
const vChartRef = ref<typeof VChart | null>(null)
let fetchInterval: any = 0
isPreview() && watchEffect(() => {
clearInterval(fetchInterval)
isPreview() &&
watchEffect(() => {
clearInterval(fetchInterval)
const chartEditStore = useChartEditStore()
const { requestOriginUrl, requestInterval } = toRefs(
chartEditStore.getRequestGlobalConfig
)
const { requestDataType, requestHttpType, requestUrl } = toRefs(
chartConfig.data
)
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
// 处理地址
if (requestUrl?.value && requestInterval.value > 0) {
// requestOriginUrl 允许为空
const completePath =
requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
const chartEditStore = useChartEditStore()
const { requestOriginUrl, requestInterval } = toRefs(
chartEditStore.getRequestGlobalConfig
)
const { requestDataType, requestHttpType, requestUrl } = toRefs(
targetComponent.data
)
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
// 处理地址
if (requestUrl?.value && requestInterval.value > 0) {
// requestOriginUrl 允许为空
const completePath =
requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
fetchInterval = setInterval(async () => {
const res = await http(requestHttpType.value)(completePath || '', {})
if (res.data) {
nextTick(() => {
if(vChartRef.value) {
vChartRef.value.setOption({dataset: res.data})
fetchInterval = setInterval(async () => {
const res:any = await http(requestHttpType.value)(completePath || '', {})
if (res.data) {
// 是否是 Echarts
const isECharts =
targetComponent.chartConfig.package ===
PackagesCategoryEnum.CHARTS
try {
if (isECharts) {
nextTick(() => {
if (vChartRef.value) {
vChartRef.value.setOption({ dataset: res.data })
}
})
} else {
// 若遵守规范使用 datase 作为数据 key则省自动赋值数据
targetComponent.option.dataset = res.data
}
if (updateCallback) {
updateCallback(res.data)
}
} catch (error) {
console.error(error)
}
})
}
}, requestInterval.value * 1000)
}
})
}
}, requestInterval.value * 1000)
}
})
return { vChartRef }
}

View File

@ -5,7 +5,8 @@ import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const option = {
data: dataJson,
// 数据
dataset: dataJson,
// 表行数
rowNum: 5,
// 轮播时间
@ -15,7 +16,7 @@ export const option = {
// 自动排序
sort: true,
color: '#1370fb',
textColor: '#ffffff',
textColor: '#CDD2F8FF',
borderColor: '#1370fb80',
carousel: 'single',
// 格式化

View File

@ -24,12 +24,6 @@
placeholder="数值单位"
></n-input>
</SettingItem>
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.sort" size="small" />
<n-text>自动排序</n-text>
</n-space>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="样式">

View File

@ -15,11 +15,14 @@
? status.mergedConfig.valueFormatter(item)
: item.value
}}
{{unit}}
{{ unit }}
</div>
</div>
<div class="ranking-column" :style="`border-color: ${borderColor}`">
<div class="inside-column" :style="`width: ${item.percent}%;background-color: ${color}`">
<div
class="inside-column"
:style="`width: ${item.percent}%;background-color: ${color}`"
>
<div class="shine" />
</div>
</div>
@ -32,6 +35,8 @@ import { PropType, onUnmounted, reactive, ref, toRefs, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import merge from 'lodash/merge'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
const props = defineProps({
chartConfig: {
@ -39,9 +44,10 @@ const props = defineProps({
required: true,
},
})
const { w, h } = toRefs(props.chartConfig.attr)
const { rowNum, unit, color, textColor, borderColor } = toRefs(props.chartConfig.option)
const { rowNum, unit, color, textColor, borderColor } = toRefs(
props.chartConfig.option
)
const status = reactive({
mergedConfig: props.chartConfig.option,
@ -53,41 +59,15 @@ const status = reactive({
updater: 0,
})
const onResize = () => {
if (!status.mergedConfig) return
stopAnimation()
calcHeights(true)
animation(true)
}
watch(
() => w.value,
() => {
onResize()
}
)
watch(
() => h.value,
() => {
onResize()
}
)
watch(
() => rowNum.value,
() => {
onResize()
}
)
const calcRowsData = () => {
let { data, rowNum, sort } = status.mergedConfig
let { dataset, rowNum, sort } = status.mergedConfig
sort &&
data.sort(({ value: a }, { value: b }) => {
dataset.sort(({ value: a }, { value: b }) => {
if (a > b) return -1
if (a < b) return 1
if (a === b) return 0
})
const value = data.map(({ value }) => value)
const value = dataset.map(({ value }) => value)
const min = Math.min(...value) || 0
// abs of min
const minAbs = Math.abs(min)
@ -95,25 +75,25 @@ const calcRowsData = () => {
// abs of max
const maxAbs = Math.abs(max)
const total = max + minAbs
data = data.map((row, i) => ({
dataset = dataset.map((row, i) => ({
...row,
ranking: i + 1,
percent: ((row.value + minAbs) / total) * 100,
}))
const rowLength = data.length
const rowLength = dataset.length
if (rowLength > rowNum && rowLength < 2 * rowNum) {
data = [...data, ...data]
dataset = [...dataset, ...dataset]
}
data = data.map((d, i) => ({ ...d, scroll: i }))
status.rowsData = data
status.rows = data
dataset = dataset.map((d, i) => ({ ...d, scroll: i }))
status.rowsData = dataset
status.rows = dataset
}
const calcHeights = (onresize = false) => {
const { rowNum, data } = status.mergedConfig
const { rowNum, dataset } = status.mergedConfig
const avgHeight = h.value / rowNum
status.avgHeight = avgHeight
if (!onresize) status.heights = new Array(data.length).fill(avgHeight)
if (!onresize) status.heights = new Array(dataset.length).fill(avgHeight)
}
const animation = async (start = false) => {
@ -147,13 +127,46 @@ const stopAnimation = () => {
clearTimeout(status.animationHandler)
}
const init = () => {
const onRestart = async () => {
if (!status.mergedConfig) return
stopAnimation()
calcRowsData()
calcHeights()
calcHeights(true)
animation(true)
}
init()
onRestart()
watch(
() => w.value,
() => {
onRestart()
}
)
watch(
() => h.value,
() => {
onRestart()
}
)
watch(
() => rowNum.value,
() => {
onRestart()
}
)
//
watch(
() => props.chartConfig.option.dataset,
() => {
onRestart()
}
)
useChartDataFetch(props.chartConfig, useChartEditStore)
onUnmounted(() => {
stopAnimation()

View File

@ -1,6 +1,6 @@
import type { App } from 'vue'
import { GoSkeleton } from '@/components/GoSkeleton'
import { LoadingComponent } from '@/components/LoadingComponent'
import { GoLoading } from '@/components/GoLoading'
import { SketchRule } from 'vue3-sketch-ruler'
/**
@ -9,6 +9,6 @@ import { SketchRule } from 'vue3-sketch-ruler'
*/
export function setupCustomComponents(app: App) {
app.component('GoSkeleton', GoSkeleton)
app.component('LoadingComponent', LoadingComponent)
app.component('GoLoading', GoLoading)
app.component('SketchRule', SketchRule)
}

View File

@ -78,8 +78,5 @@
"color": "#B9B8CE"
}
},
"dataset": {
"dimensions": [""],
"source": [{}]
}
"dataset": null
}

View File

@ -1,5 +1,5 @@
import { defineAsyncComponent, AsyncComponentLoader } from 'vue'
import { AsyncLoading, AsyncSkeletonLoading } from '@/components/LoadingComponent'
import { AsyncLoading, AsyncSkeletonLoading } from '@/components/GoLoading'
/**
* *

View File

@ -20,13 +20,15 @@
<help-outline-icon></help-outline-icon>
</n-icon>
</template>
<span>
开发环境使用 mock 数据请输入
<n-text type="info">
{{ mockDataUrl }}
</n-text>
</span>
<ul>
开发环境使用 mock 数据请输入
<li>
<n-text type="info"> 图表{{ chartDataUrl }} </n-text>
</li>
<li>
<n-text type="info"> 表格{{ rankListUrl }} </n-text>
</li>
</ul>
</n-tooltip>
</template>
<n-input
@ -63,7 +65,7 @@ import { ref, toRefs } from 'vue'
import { icon } from '@/plugins'
import { SettingItemBox } from '@/components/ChartItemSetting/index'
import { RequestHttpEnum } from '@/enums/httpEnum'
import { mockDataUrl } from '@/api/mock'
import { chartDataUrl, rankListUrl } from '@/api/mock'
import { http } from '@/api/http'
import { SelectHttpType } from '../../index.d'
import { ChartDataMatchingAndShow } from '../ChartDataMatchingAndShow'
@ -82,12 +84,12 @@ const showMatching = ref(false)
const selectOptions: SelectHttpType[] = [
{
label: RequestHttpEnum.GET,
value: RequestHttpEnum.GET
value: RequestHttpEnum.GET,
},
{
label: RequestHttpEnum.POST,
value: RequestHttpEnum.POST
}
value: RequestHttpEnum.POST,
},
]
//

View File

@ -1,6 +1,10 @@
<template>
<n-timeline class="go-chart-configurations-timeline">
<n-timeline-item type="info" :title="TimelineTitleEnum.MAPPING">
<n-timeline-item
v-if="isCharts"
type="info"
:title="TimelineTitleEnum.MAPPING"
>
<n-table striped>
<thead>
<tr>
@ -17,7 +21,10 @@
<n-text></n-text>
</n-space>
<n-space v-else>
<n-badge dot :type="item.result === 1 ? 'success' : 'error'"></n-badge>
<n-badge
dot
:type="item.result === 1 ? 'success' : 'error'"
></n-badge>
<n-text>匹配{{ item.result === 1 ? '成功' : '失败' }}</n-text>
</n-space>
</td>
@ -27,7 +34,7 @@
</n-timeline-item>
<n-timeline-item type="success" :title="TimelineTitleEnum.CONTENT">
<n-space vertical>
<n-text depth="3">数据需要符合 ECharts-setdata 规范</n-text>
<n-text depth="3">ECharts 图表需符合 ECharts-setdata 数据规范</n-text>
<n-space class="source-btn-box">
<n-upload
v-model:file-list="uploadFileListRef"
@ -65,7 +72,7 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { CreateComponentType, PackagesCategoryEnum } from '@/packages/index.d'
import { icon } from '@/plugins'
import { DataResultEnum, TimelineTitleEnum } from '../../index.d'
import { useFile } from '../../hooks/useFile.hooks'
@ -89,6 +96,11 @@ const dimensionsAndSource = ref()
const { uploadFileListRef, customRequest, beforeUpload, download} = useFile(targetData)
//
const isCharts = computed(()=> {
return targetData.value.chartConfig.package === PackagesCategoryEnum.CHARTS
})
//
const getSource = computed(() => {
return JSON.stringify(source.value)
@ -128,17 +140,20 @@ const dimensionsAndSourceHandle = () => {
watch(() => targetData.value?.option?.dataset, (newData) => {
if (newData) {
source.value = newData.source
dimensions.value = newData.dimensions
dimensionsAndSource.value = dimensionsAndSourceHandle()
// Echarts
source.value = isCharts.value ? newData.source : newData
if(isCharts.value) {
dimensions.value = newData.dimensions
dimensionsAndSource.value = dimensionsAndSourceHandle()
}
}
}, {
},{
immediate: true
})
</script>
<style lang="scss" scoped>
@include go("chart-configurations-timeline") {
@include go('chart-configurations-timeline') {
@include deep() {
pre {
white-space: pre-wrap;