Merge branch 'master-fetch-dev' into master-fetch

This commit is contained in:
奔跑的面条 2023-09-18 10:52:18 +08:00
commit 0cf5e175cf
20 changed files with 572 additions and 277 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ dist
dist-ssr
*.local
.vscode
.idea

View File

@ -41,7 +41,7 @@
"three": "^0.145.0",
"vue": "^3.2.31",
"vue-demi": "^0.13.1",
"vue-i18n": "^9.2.2",
"vue-i18n": "9.2.2",
"vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta",
"vue3-sketch-ruler": "^1.3.3",

View File

@ -11,7 +11,10 @@ export const option = {
dataset: dataJson,
mapRegion: {
adcode: 'china',
showHainanIsLands: true
showHainanIsLands: true,
enter: false,
backSize: 20,
backColor: '#ffffff'
},
tooltip: {
show: true,
@ -103,19 +106,19 @@ export const option = {
borderColor: 'rgba(147, 235, 248, 0.8)',
textStyle: {
color: '#FFFFFF',
fontSize: 12,
fontSize: 12
}
},
label: {
show: false,
color: '#FFFFFF',
fontSize: 12,
fontSize: 12
},
emphasis: {
disabled: false,
label: {
color: '#FFFFFF',
fontSize: 12,
fontSize: 12
},
itemStyle: {
areaColor: '#389BB7',
@ -148,6 +151,26 @@ export const option = {
shadowOffsetY: 2,
shadowBlur: 10
}
},
{
type: 'lines',
zlevel: 2,
effect: {
show: true,
period: 4, //箭头指向速度,值越小速度越快
trailLength: 0.4, //特效尾迹长度[0,1]值越大,尾迹越长重
symbol: 'arrow', //箭头图标
symbolSize: 7 //图标大小
},
lineStyle: {
normal: {
color: '#4fb6d2',
width: 1, //线条宽度
opacity: 0.1, //尾迹线条透明度
curveness: 0.3 //尾迹线条曲直度
}
},
data: []
}
]
}

View File

@ -69,11 +69,7 @@
</n-space>
</SettingItem>
<SettingItem name="字体颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="seriesList[1].label.color"
></n-color-picker>
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[1].label.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
@ -129,7 +125,7 @@
></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="悬浮弹窗">
<SettingItem name="显示">
<n-space>
@ -180,6 +176,22 @@
<SettingItem>
<n-checkbox v-model:checked="mapRegion.showHainanIsLands" size="small">显示南海群岛</n-checkbox>
</SettingItem>
<SettingItem v-if="seriesList[2]">
<n-checkbox v-model:checked="mapRegion.enter" size="small">点击进入下级</n-checkbox>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="返回图标" v-if="mapRegion.enter">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="mapRegion.backColor"></n-color-picker>
</SettingItem>
<SettingItem name="大小">
<n-input-number
v-model:value="mapRegion.backSize"
:min="1"
size="small"
placeholder="请输入字体大小"
></n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
<CollapseItem name="标记" :expanded="true">
@ -191,7 +203,7 @@
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="文本">
<SettingItem name="显示">
<n-space>
@ -223,6 +235,47 @@
</SettingItem>
</SettingItemBox>
</CollapseItem>
<CollapseItem v-if="seriesList[2]" name="飞线" :expanded="true">
<SettingItemBox name="箭头">
<SettingItem name="速度">
<n-tooltip trigger="hover">
<template #trigger>
<n-input-number v-model:value="seriesList[2].effect.period" size="small" :min="0"></n-input-number>
</template>
值越小速度越快
</n-tooltip>
</SettingItem>
<SettingItem name="尾迹">
<n-tooltip trigger="hover">
<template #trigger>
<n-input-number
v-model:value="seriesList[2].effect.trailLength"
size="small"
:min="0"
:max="1"
></n-input-number>
</template>
特效尾迹长度[0,1]值越大尾迹越长重
</n-tooltip>
</SettingItem>
<SettingItem name="大小">
<n-input-number v-model:value="seriesList[2].effect.symbolSize" size="small" :min="0"></n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="配置">
<SettingItem name="颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="seriesList[2].lineStyle.normal.color"
></n-color-picker>
</SettingItem>
<SettingItem name="宽度">
<n-input-number v-model:value="seriesList[2].lineStyle.normal.width" size="small" :min="1"></n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">

View File

@ -21,6 +21,32 @@
"value": [126.642464, 45.756967, 101]
}
],
"line": [
{
"coords": [
[113.665412, 34.757975],
[116.405285, 39.904989]
]
},
{
"coords": [
[101.778916, 36.623178],
[116.405285, 39.904989]
]
},
{
"coords": [
[106.278179, 38.46637],
[116.405285, 39.904989]
]
},
{
"coords": [
[126.642464, 45.756967],
[116.405285, 39.904989]
]
}
],
"map": [
{
"name": "北京市",

View File

@ -1,156 +1,256 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option.value" :manual-update="isPreview()" autoresize>
</v-chart>
</template>
<script setup lang="ts">
import { PropType, reactive, watch, ref, nextTick } from 'vue'
import config, { includes } from './config'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use, registerMap } from 'echarts/core'
import { EffectScatterChart, MapChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import { useChartDataFetch } from '@/hooks'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([
MapChart,
DatasetComponent,
CanvasRenderer,
GridComponent,
TooltipComponent,
GeoComponent,
EffectScatterChart,
VisualMapComponent
])
const option = reactive({
value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const vChartRef = ref<typeof VChart>()
//json
const getGeojson = (regionId: string) => {
return new Promise<boolean>(resolve => {
import(`./mapGeojson/${regionId}.json`).then(data => {
registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} })
resolve(true)
})
})
}
//
registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any, specialAreas: {} })
// china
const registerMapInitAsync = async () => {
await nextTick()
const adCode = `${props.chartConfig.option.mapRegion.adcode}`;
if (adCode !== 'china') {
await getGeojson(adCode)
} else {
await hainanLandsHandle(props.chartConfig.option.mapRegion.showHainanIsLands)
}
vEchartsSetOption()
}
registerMapInitAsync()
//
const vEchartsSetOption = () => {
option.value = props.chartConfig.option
setOption(vChartRef.value, props.chartConfig.option)
}
//
const dataSetHandle = async (dataset: any) => {
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'effectScatter' && dataset.point) item.data = dataset.point
else if (item.type === 'map' && dataset.map) item.data = dataset.map
})
if (dataset.pieces) props.chartConfig.option.visualMap.pieces = dataset.pieces
isPreview() && vEchartsSetOption()
}
//
const hainanLandsHandle = async (newData: boolean) => {
if (newData) {
await getGeojson('china')
} else {
registerMap('china', { geoJSON: mapJsonWithoutHainanIsLands as any, specialAreas: {} })
}
}
// dataset
watch(
() => props.chartConfig.option.dataset,
newData => {
dataSetHandle(newData)
},
{
immediate: true,
deep: false
}
)
//
watch(
() => props.chartConfig.option.mapRegion.showHainanIsLands,
async newData => {
try {
await hainanLandsHandle(newData)
vEchartsSetOption()
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
//
watch(
() => `${props.chartConfig.option.mapRegion.adcode}`,
async newData => {
try {
await getGeojson(newData)
props.chartConfig.option.geo.map = newData
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'map') item.map = newData
})
vEchartsSetOption()
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
//
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
dataSetHandle(newData)
})
</script>
<template>
<div>
<div class="back-icon" v-if="(enter && levelHistory.length !== 0) || (enter && !isPreview())" @click="backLevel">
<n-icon :color="backColor" :size="backSize * 1.1">
<ArrowBackIcon />
</n-icon>
<span
:style="{
'font-weight': 200,
color: backColor,
'font-size': `${backSize}px`
}"
>
返回上级
</span>
</div>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option.value"
:manual-update="isPreview()"
autoresize
@click="chartPEvents"
>
</v-chart>
</div>
</template>
<script setup lang="ts">
import { PropType, reactive, watch, ref, nextTick, toRefs } from 'vue'
import config, { includes } from './config'
import VChart from 'vue-echarts'
import { icon } from '@/plugins'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use, registerMap } from 'echarts/core'
import { EffectScatterChart, MapChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import { useChartDataFetch } from '@/hooks'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
import mapChinaJson from './mapGeojson/china.json'
import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const { ArrowBackIcon } = icon.ionicons5
let levelHistory: any = ref([])
const { backColor, backSize, enter } = toRefs(props.chartConfig.option.mapRegion)
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([
MapChart,
DatasetComponent,
CanvasRenderer,
GridComponent,
TooltipComponent,
GeoComponent,
EffectScatterChart,
VisualMapComponent
])
const option = reactive({
value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const vChartRef = ref<typeof VChart>()
//json
const getGeojson = (regionId: string) => {
return new Promise<boolean>(resolve => {
import(`./mapGeojson/${regionId}.json`).then(data => {
registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} })
resolve(true)
})
})
}
//
registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any, specialAreas: {} })
// china
const registerMapInitAsync = async () => {
await nextTick()
const adCode = `${props.chartConfig.option.mapRegion.adcode}`
if (adCode !== 'china') {
await getGeojson(adCode)
} else {
await hainanLandsHandle(props.chartConfig.option.mapRegion.showHainanIsLands)
}
vEchartsSetOption()
}
registerMapInitAsync()
//
const vEchartsSetOption = () => {
option.value = props.chartConfig.option
setOption(vChartRef.value, props.chartConfig.option)
}
//
const dataSetHandle = async (dataset: any) => {
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'effectScatter' && dataset.point) item.data = dataset.point
else if (item.type === 'lines' && dataset.line) {
item.data = dataset.line.map((it: any) => {
return {
...it,
lineStyle: {
color: props.chartConfig.option.series[2].lineStyle.normal.color
}
}
})
} else if (item.type === 'map' && dataset.map) item.data = dataset.map
})
if (dataset.pieces) props.chartConfig.option.visualMap.pieces = dataset.pieces
isPreview() && vEchartsSetOption()
}
//
const hainanLandsHandle = async (newData: boolean) => {
if (newData) {
await getGeojson('china')
} else {
registerMap('china', { geoJSON: mapJsonWithoutHainanIsLands as any, specialAreas: {} })
}
}
//
const chartPEvents = (e: any) => {
if (e.seriesType !== 'map') return
if (!props.chartConfig.option.mapRegion.enter) {
return
}
mapChinaJson.features.forEach(item => {
var pattern = new RegExp(e.name)
if (pattern.test(item.properties.name)) {
let code = String(item.properties.adcode)
levelHistory.value.push(code)
checkOrMap(code)
}
})
}
//
const backLevel = () => {
levelHistory.value = []
if (levelHistory.value.length > 1) {
levelHistory.value.pop()
const code = levelHistory[levelHistory.value.length - 1]
checkOrMap(code)
} else {
checkOrMap('china')
}
}
//
const checkOrMap = async (newData: string) => {
await getGeojson(newData)
props.chartConfig.option.geo.map = newData
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'map') item.map = newData
})
vEchartsSetOption()
}
// dataset
watch(
() => props.chartConfig.option.dataset,
newData => {
dataSetHandle(newData)
},
{
immediate: true,
deep: false
}
)
// 线
if (props.chartConfig.option.series[2] && !isPreview()) {
watch(
() => props.chartConfig.option.series[2].lineStyle.normal.color,
() => {
dataSetHandle(props.chartConfig.option.dataset)
},
{
deep: false
}
)
}
//
if (!isPreview()) {
watch(
() => props.chartConfig.option.mapRegion.showHainanIsLands,
async newData => {
try {
await hainanLandsHandle(newData)
vEchartsSetOption()
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
}
//
watch(
() => `${props.chartConfig.option.mapRegion.adcode}`,
newData => {
try {
checkOrMap(newData)
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
//
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
dataSetHandle(newData)
})
</script>
<style scope lang="scss">
.back-icon {
z-index: 50;
cursor: pointer;
position: absolute;
display: flex;
align-items: center;
top: 0;
left: 0;
gap: 2px;
}
</style>

View File

@ -9,7 +9,8 @@ export const includes = []
// 关系图布局
export const GraphLayout = [
{ label: '无', value: 'none' },
{ label: '环形', value: 'circular' }
{ label: '环形', value: 'circular' },
{ label: '力引导', value: 'force' }
]
// 标签开关
@ -24,44 +25,57 @@ export const LabelPosition = [
{ label: '右侧', value: 'right' },
{ label: '顶部', value: 'top' },
{ label: '底部', value: 'bottom' },
{ label: '内部', value: 'inside' },
{ label: '内部', value: 'inside' }
]
// 图-迭代动画
export const LayoutAnimation = [
{ label: '开启', value: 1 },
{ label: '关闭', value: 0 }
]
export const option = {
dataset: { ...dataJson },
tooltip: {},
legend:{
show:true,
textStyle:{
color:"#eee",
fontSize: 14 ,
},
data: dataJson.categories.map(function (a) {
return a.name;
})
dataset: { ...dataJson },
tooltip: {},
legend: {
show: true,
textStyle: {
color: '#eee',
fontSize: 14
},
series: [
{
type: 'graph',
layout: 'none', // none circular环形布局
data: dataJson.nodes,
links: dataJson.links,
categories: dataJson.categories,
label: { // 标签
show: 1,
position: 'right',
formatter: '{b}'
},
labelLayout: {
hideOverlap: true
},
lineStyle: {
color: 'source', // 线条颜色
curveness: 0.2 // 线条卷曲程度
}
data: dataJson.categories.map(function (a) {
return a.name
})
},
series: [
{
type: 'graph',
layout: 'none', // none circular环形布局
data: dataJson.nodes,
links: dataJson.links,
categories: dataJson.categories,
label: {
show: 1,
position: 'right',
formatter: '{b}'
},
labelLayout: {
hideOverlap: true
},
lineStyle: {
color: 'source', // 线条颜色
curveness: 0.2 // 线条卷曲程度
},
force: {
repulsion: 100,
gravity: 0.1,
edgeLength: 30,
layoutAnimation: 1,
friction: 0.6
}
]
};
}
]
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = GraphConfig.key

View File

@ -16,14 +16,14 @@
</SettingItemBox>
<SettingItemBox name="线条">
<SettingItem name="弧线">
<!-- 需要输入两位的小数才会变化 -->
<!-- 需要输入两位的小数才会变化 -->
<n-input-number
v-model:value="optionData.series[0].lineStyle.curveness"
:min="0"
:step="0.01"
placeholder="弯曲程度"
size="small"
></n-input-number>
v-model:value="optionData.series[0].lineStyle.curveness"
:min="0"
:step="0.01"
placeholder="弯曲程度"
size="small"
></n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="图例">
@ -32,10 +32,61 @@
size="small"
:modes="['hex']"
v-model:value="optionData.legend.textStyle.color"
></n-color-picker>
></n-color-picker>
</SettingItem>
<SettingItem name="文本">
<n-input-number v-model:value="optionData.legend.textStyle.fontSize" :min="0" :step="1" size="small" placeholder="文字大小">
<n-input-number
v-model:value="optionData.legend.textStyle.fontSize"
:min="0"
:step="1"
size="small"
placeholder="文字大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="力引导" v-if="optionData.series[0].force && graphConfig.layout == 'force'">
<SettingItem name="斥力因子" v-if="optionData.series[0].force.repulsion">
<n-input-number
v-model:value="optionData.series[0].force.repulsion"
:min="0"
:step="1"
size="small"
placeholder="斥力因子大小"
>
</n-input-number>
</SettingItem>
<SettingItem name="引力因子" v-if="optionData.series[0].force.gravity">
<n-input-number
v-model:value="optionData.series[0].force.gravity"
:min="0"
:step="0.1"
size="small"
placeholder="引力因子"
>
</n-input-number>
</SettingItem>
<SettingItem name="节点距离">
<n-input-number
v-model:value="optionData.series[0].force.edgeLength"
:min="0"
:step="1"
size="small"
placeholder="节点距离"
>
</n-input-number>
</SettingItem>
<SettingItem name="迭代动画">
<n-select v-model:value="graphConfig.force.layoutAnimation" :options="LayoutAnimation" size="small" />
</SettingItem>
<SettingItem name="节点速度">
<n-input-number
v-model:value="optionData.series[0].force.friction"
:min="0"
:step="0.1"
size="small"
placeholder="节点速度"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
@ -46,7 +97,7 @@
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option, GraphLayout, LabelSwitch, LabelPosition } from './config'
import { option, GraphLayout, LabelSwitch, LabelPosition, LayoutAnimation } from './config'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
@ -56,7 +107,7 @@ const props = defineProps({
}
})
const graphConfig = computed<typeof option.series[0]>(() => {
const graphConfig = computed<(typeof option.series)[0]>(() => {
return props.optionData.series[0]
})
</script>

View File

@ -1,5 +1,12 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
autoresize
></v-chart>
</template>
<script setup lang="ts">

View File

@ -8,4 +8,14 @@ import { DialConfig } from './Dial/index'
import { SankeyConfig } from './Sankey/index'
import { GraphConfig } from './Graph/index'
export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig, GraphConfig, SankeyConfig, DialConfig]
export default [
ProcessConfig,
RadarConfig,
FunnelConfig,
HeatmapConfig,
WaterPoloConfig,
TreeMapConfig,
GraphConfig,
SankeyConfig,
DialConfig
]

View File

@ -26,6 +26,16 @@ export let packagesList: PackagesType = {
[PackagesCategoryEnum.ICONS]: IconList
}
// 组件缓存, 可以大幅度提升组件加载速度
const componentCacheMap = new Map<string, any>()
const loadConfig = (packageName: string, categoryName: string, keyName: string) => {
const key = packageName + categoryName + keyName
if (!componentCacheMap.has(key)) {
componentCacheMap.set(key, import(`./components/${packageName}/${categoryName}/${keyName}/config.ts`))
}
return componentCacheMap.get(key)
}
/**
* *
* @param targetData
@ -35,10 +45,10 @@ export const createComponent = async (targetData: ConfigType) => {
// redirectComponent 是给图片组件库和图标组件库使用的
if (redirectComponent) {
const [packageName, categoryName, keyName] = redirectComponent.split('/')
const redirectChart = await import(`./components/${packageName}/${categoryName}/${keyName}/config.ts`)
const redirectChart = await loadConfig(packageName, categoryName, keyName)
return new redirectChart.default()
}
const chart = await import(`./components/${targetData.package}/${category}/${key}/config.ts`)
const chart = await loadConfig(targetData.package, category, key)
return new chart.default()
}
@ -84,7 +94,7 @@ export const fetchImages = async (targetData?: ConfigType) => {
// 正则判断图片是否为 url是则直接返回该 url
if (/^(http|https):\/\/([\w.]+\/?)\S*/.test(targetData.image)) return targetData.image
// 新数据动态处理
const { image, package: targetDataPackage } = targetData
const { image } = targetData
// 兼容旧数据
if (image.includes('@') || image.includes('base64')) return image

View File

@ -182,20 +182,16 @@ export const useChartEditStore = defineStore({
},
getComponentList(): Array<CreateComponentType | CreateComponentGroupType> {
return this.componentList
},
// 获取需要存储的数据项
}
},
actions: {
// * 获取需要存储的数据项
getStorageInfo(): ChartEditStorage {
return {
[ChartEditStoreEnum.EDIT_CANVAS_CONFIG]: this.getEditCanvasConfig,
[ChartEditStoreEnum.COMPONENT_LIST]: this.getComponentList,
[ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: this.getRequestGlobalConfig
}
}
},
actions: {
// * 设置 peojectInfo 数据项
setProjectInfo<T extends keyof ProjectInfoType, K extends ProjectInfoType[T]>(key: T, value: K) {
this.projectInfo[key] = value
},
// * 设置 editCanvas 数据项
setEditCanvas<T extends keyof EditCanvasType, K extends EditCanvasType[T]>(key: T, value: K) {

View File

@ -20,14 +20,14 @@ export const syncData = () => {
onPositiveCallback: async () => {
window['$message'].success('正在同步编辑器...')
dataSyncUpdate && (await dataSyncUpdate())
dispatchEvent(new CustomEvent(SavePageEnum.CHART, { detail: chartEditStore.getStorageInfo }))
dispatchEvent(new CustomEvent(SavePageEnum.CHART, { detail: chartEditStore.getStorageInfo() }))
}
})
}
// 同步数据到预览页
export const syncDataToPreview = () => {
dispatchEvent(new CustomEvent(SavePageEnum.CHART_TO_PREVIEW, { detail: chartEditStore.getStorageInfo }))
dispatchEvent(new CustomEvent(SavePageEnum.CHART_TO_PREVIEW, { detail: chartEditStore.getStorageInfo() }))
}
// 侦听器更新

View File

@ -158,7 +158,7 @@ const editHandle = () => {
// SessionStorage 便
const updateToSession = (id: string) => {
const storageInfo = chartEditStore.getStorageInfo
const storageInfo = chartEditStore.getStorageInfo()
const sessionStorageInfo = getLocalStorage(StorageEnum.GO_CHART_STORAGE_LIST) || []
if (sessionStorageInfo?.length) {

View File

@ -1,41 +1,41 @@
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { canvasCut, downloadTextFile, JSONStringify } from '@/utils'
const chartEditStore = useChartEditStore()
// 导出
export const exportHandle = () => {
// 取消选中
chartEditStore.setTargetSelectChart(undefined)
// 导出数据
downloadTextFile(
JSONStringify(chartEditStore.getStorageInfo || []),
undefined,
'json'
)
// 导出图片
const range = document.querySelector('.go-edit-range') as HTMLElement
const watermark = document.getElementById('go-edit-watermark')
// 隐藏边距线
if (!range || !watermark) {
window['$message'].error('导出失败!')
return
}
// 记录缩放比例
const scaleTemp = chartEditStore.getEditCanvas.scale
// 百分百展示页面
chartEditStore.setScale(1, true)
// 展示水印
watermark.style.display = 'block'
setTimeout(() => {
canvasCut(range, () => {
// 隐藏水印
if (watermark) watermark.style.display = 'none'
// 还原页面大小
chartEditStore.setScale(scaleTemp, true)
})
}, 600)
}
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { canvasCut, downloadTextFile, JSONStringify } from '@/utils'
const chartEditStore = useChartEditStore()
// 导出
export const exportHandle = () => {
// 取消选中
chartEditStore.setTargetSelectChart(undefined)
// 导出数据
downloadTextFile(
JSONStringify(chartEditStore.getStorageInfo() || []),
undefined,
'json'
)
// 导出图片
const range = document.querySelector('.go-edit-range') as HTMLElement
const watermark = document.getElementById('go-edit-watermark')
// 隐藏边距线
if (!range || !watermark) {
window['$message'].error('导出失败!')
return
}
// 记录缩放比例
const scaleTemp = chartEditStore.getEditCanvas.scale
// 百分百展示页面
chartEditStore.setScale(1, true)
// 展示水印
watermark.style.display = 'block'
setTimeout(() => {
canvasCut(range, () => {
// 隐藏水印
if (watermark) watermark.style.display = 'none'
// 还原页面大小
chartEditStore.setScale(scaleTemp, true)
})
}, 600)
}

View File

@ -94,7 +94,7 @@ const previewHandle = () => {
const { id } = routerParamsInfo.params
// id
const previewId = typeof id === 'string' ? id : id[0]
const storageInfo = chartEditStore.getStorageInfo
const storageInfo = chartEditStore.getStorageInfo()
const sessionStorageInfo = getLocalStorage(StorageEnum.GO_CHART_STORAGE_LIST) || []
if (sessionStorageInfo?.length) {

View File

@ -209,9 +209,7 @@ export const useSync = () => {
chartHistoryStore.clearForwardStack()
}
}
} else {
// 非组件(顺便排除脏数据)
if (key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return
} else if (key === ChartEditStoreEnum.EDIT_CANVAS_CONFIG || key === ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG) {
componentMerge(chartEditStore[key], projectData[key], true)
}
}

View File

@ -6,8 +6,8 @@
:key="item.id"
:style="{
...getComponentAttrStyle(item.attr, groupIndex),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles),
...getFilterStyle(groupData.styles),
...getTransformStyle(groupData.styles),
...getStatusStyle(item.status),
...getPreviewConfigStyle(item.preview),
...getBlendModeStyle(item.styles) as any
@ -19,7 +19,11 @@
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{ ...getSizeStyle(item.attr) }"
:style="{
...getSizeStyle(item.attr),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles)
}"
v-on="useLifeHandler(item)"
></component>
</div>

View File

@ -47,6 +47,7 @@ setTitle(`预览-${chartEditStore.editCanvasConfig.projectName}`)
const previewRefStyle = computed(() => {
return {
overflow: 'hidden',
...getEditCanvasConfigStyle(chartEditStore.editCanvasConfig),
...getFilterStyle(chartEditStore.editCanvasConfig)
}

View File

@ -16,6 +16,7 @@ let key = ref(Date.now())
// ->
;[SavePageEnum.JSON, SavePageEnum.CHART_TO_PREVIEW].forEach((saveEvent: string) => {
if (!window.opener) return
if(!(window.opener === window)) return
window.opener.addEventListener(saveEvent, async (e: any) => {
const localStorageInfo: ChartEditStorageType = await getSessionStorageInfo() as unknown as ChartEditStorageType
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, [{ ...e.detail, id: localStorageInfo.id }])