mirror of
https://gitee.com/dromara/go-view.git
synced 2026-02-10 00:03:02 +08:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7ab632a92 | ||
|
|
1681513d68 | ||
|
|
bd53c68ee2 | ||
|
|
40673dddb3 | ||
|
|
460aa47ee5 | ||
|
|
1237e16142 | ||
|
|
1565249e2a | ||
|
|
ffd4e165e5 | ||
|
|
9ce042cc8a | ||
|
|
60c7c36800 | ||
|
|
186538afc9 | ||
|
|
a400526108 | ||
|
|
2a8d0717f8 | ||
|
|
76f0183acc | ||
|
|
a6194b8fa9 | ||
|
|
de681dbcd4 | ||
|
|
2e74522cc3 | ||
|
|
2d8e99bed6 | ||
|
|
59b9ca0569 | ||
|
|
c930e3433f | ||
|
|
8e1731354c | ||
|
|
93f398d5a7 | ||
|
|
0f61ee728b | ||
|
|
afd42fb1fe | ||
|
|
980b91401b | ||
|
|
8ef4ab8175 | ||
|
|
ba1868eb8b | ||
|
|
82f026a1b5 | ||
|
|
5213ea0273 | ||
|
|
0308004a61 | ||
|
|
d030f89895 | ||
|
|
db7a4801d8 | ||
|
|
47d1dcbc04 | ||
|
|
9fd408e8ef | ||
|
|
77a5f47e82 | ||
|
|
4915f9e077 | ||
|
|
ce46f609ec | ||
|
|
ba425d44cc | ||
|
|
e6338f89dd | ||
|
|
24361e63c2 | ||
|
|
5effb94b1d | ||
|
|
f68aee1f3a | ||
|
|
233f3210c6 | ||
|
|
ab52fcaaf9 | ||
|
|
99eadd96af | ||
|
|
480e328306 | ||
|
|
bd52c4454c | ||
|
|
6b87618622 | ||
|
|
4e9f96505a | ||
|
|
dde03274c2 | ||
|
|
41444026f9 | ||
|
|
8b76f6e219 | ||
|
|
5ed3e4e8b1 | ||
|
|
55221ff756 | ||
|
|
b534619649 | ||
|
|
421ea3dc84 | ||
|
|
4bb3c34bc2 | ||
|
|
2cbb851948 | ||
|
|
0f93b0285b |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "go-view",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
},
|
||||
@@ -75,7 +75,7 @@
|
||||
"sass": "^1.49.11",
|
||||
"sass-loader": "^12.6.0",
|
||||
"typescript": "4.6.3",
|
||||
"vite": "2.9.9",
|
||||
"vite": "4.2.1",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-importer": "^0.2.5",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
|
||||
2831
pnpm-lock.yaml
generated
2831
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ axiosInstance.interceptors.response.use(
|
||||
}
|
||||
const { code } = res.data as { code: number }
|
||||
|
||||
if (code === undefined || code === null) return Promise.resolve(res)
|
||||
if (code === undefined || code === null) return Promise.resolve(res.data)
|
||||
|
||||
// 成功
|
||||
if (code === ResultEnum.SUCCESS) {
|
||||
|
||||
100
src/api/mock/graph.json
Normal file
100
src/api/mock/graph.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "0",
|
||||
"name": "Myriel",
|
||||
"symbolSize": "@integer(0, 50)",
|
||||
"x": -266.82776,
|
||||
"y": 299.6904,
|
||||
"value": "@integer(0, 50)",
|
||||
"category": 3
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Napoleon",
|
||||
"symbolSize": "@integer(0, 50)",
|
||||
"x": -418.08344,
|
||||
"y": 446.8853,
|
||||
"value": "@integer(0, 50)",
|
||||
"category": 5
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "MlleBaptistine",
|
||||
"symbolSize": "@integer(0, 50)",
|
||||
"x": -212.76357,
|
||||
"y": 245.29176,
|
||||
"value": "@integer(0, 50)",
|
||||
"category": 1
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "MmeMagloire",
|
||||
"symbolSize": "@integer(0, 50)",
|
||||
"x": -242.82404,
|
||||
"y": 235.26283,
|
||||
"value": "@integer(0, 50)",
|
||||
"category": 1
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"name": "CountessDeLo",
|
||||
"symbolSize": "@integer(0, 50)",
|
||||
"x": -379.30386,
|
||||
"y": 429.06424,
|
||||
"value": "@integer(0, 50)",
|
||||
"category": 0
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"source": "1",
|
||||
"target": "@integer(2, 4)"
|
||||
},
|
||||
{
|
||||
"source": "2",
|
||||
"target": "@integer(3, 4)"
|
||||
},
|
||||
{
|
||||
"source": "3",
|
||||
"target": "@integer(0, 2)"
|
||||
},
|
||||
{
|
||||
"source": "3",
|
||||
"target": "@integer(0, 1)"
|
||||
},
|
||||
{
|
||||
"source": "4",
|
||||
"target": "@integer(0, 3)"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "A"
|
||||
},
|
||||
{
|
||||
"name": "B"
|
||||
},
|
||||
{
|
||||
"name": "C"
|
||||
},
|
||||
{
|
||||
"name": "D"
|
||||
},
|
||||
{
|
||||
"name": "E"
|
||||
},
|
||||
{
|
||||
"name": "F"
|
||||
},
|
||||
{
|
||||
"name": "G"
|
||||
},
|
||||
{
|
||||
"name": "H"
|
||||
},
|
||||
{
|
||||
"name": "I"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -19,6 +19,8 @@ export const capsuleUrl = '/mock/capsule'
|
||||
export const wordCloudUrl = '/mock/wordCloud'
|
||||
export const treemapUrl = '/mock/treemap'
|
||||
export const threeEarth01Url = '/mock/threeEarth01Data'
|
||||
export const sankeyUrl = '/mock/sankey'
|
||||
export const graphUrl = '/mock/graphData'
|
||||
|
||||
const mockObject: MockMethod[] = [
|
||||
{
|
||||
@@ -103,6 +105,16 @@ const mockObject: MockMethod[] = [
|
||||
method: RequestHttpEnum.GET,
|
||||
response: () => test.threeEarth01Data
|
||||
},
|
||||
{
|
||||
url: sankeyUrl,
|
||||
method: RequestHttpEnum.GET,
|
||||
response: () => test.fetchSankey
|
||||
},
|
||||
{
|
||||
url: graphUrl,
|
||||
method: RequestHttpEnum.GET,
|
||||
response: () => test.graphData
|
||||
},
|
||||
]
|
||||
|
||||
export default mockObject
|
||||
|
||||
86
src/api/mock/sankey.json
Normal file
86
src/api/mock/sankey.json
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"label": [
|
||||
{
|
||||
"name": "a"
|
||||
},
|
||||
{
|
||||
"name": "b"
|
||||
},
|
||||
{
|
||||
"name": "a1"
|
||||
},
|
||||
{
|
||||
"name": "a2"
|
||||
},
|
||||
{
|
||||
"name": "b1"
|
||||
},
|
||||
{
|
||||
"name": "b2"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"source": "a",
|
||||
"target": "a1",
|
||||
"value": "@integer(0, 10)"
|
||||
},
|
||||
{
|
||||
"source": "a",
|
||||
"target": "a2",
|
||||
"value": "@integer(0, 10)"
|
||||
},
|
||||
{
|
||||
"source": "b",
|
||||
"target": "b1",
|
||||
"value": "@integer(0, 10)"
|
||||
},
|
||||
{
|
||||
"source": "a",
|
||||
"target": "b1",
|
||||
"value": "@integer(0, 10)"
|
||||
},
|
||||
{
|
||||
"source": "b1",
|
||||
"target": "a1",
|
||||
"value": "@integer(0, 10)"
|
||||
},
|
||||
{
|
||||
"source": "b1",
|
||||
"target": "b2",
|
||||
"value": "@integer(0, 10)"
|
||||
}
|
||||
],
|
||||
"levels": [
|
||||
{
|
||||
"depth": 0,
|
||||
"itemStyle": {
|
||||
"color": "#decbe4"
|
||||
},
|
||||
"lineStyle": {
|
||||
"color": "source",
|
||||
"opacity": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"depth": 1,
|
||||
"itemStyle": {
|
||||
"color": "#b3cde3"
|
||||
},
|
||||
"lineStyle": {
|
||||
"color": "source",
|
||||
"opacity": 0.6
|
||||
}
|
||||
},
|
||||
{
|
||||
"depth": 2,
|
||||
"itemStyle": {
|
||||
"color": "#ccebc5"
|
||||
},
|
||||
"lineStyle": {
|
||||
"color": "source",
|
||||
"opacity": 0.6
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import heatmapJson from './heatMapData.json'
|
||||
import scatterJson from './scatter.json'
|
||||
import mapJson from './map.json'
|
||||
import tTreemapJson from './treemap.json'
|
||||
import sankeyJson from './sankey.json'
|
||||
import graphDataJson from './graph.json'
|
||||
|
||||
export default {
|
||||
// 单图表
|
||||
@@ -219,5 +221,19 @@ export default {
|
||||
'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// 桑基图
|
||||
fetchSankey: {
|
||||
code: 0,
|
||||
status: 200,
|
||||
msg: '请求成功',
|
||||
data: sankeyJson
|
||||
},
|
||||
// 关系图
|
||||
graphData: {
|
||||
code: 0,
|
||||
status: 200,
|
||||
msg: '请求成功',
|
||||
data: graphDataJson
|
||||
},
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ export const uploadFile = async (data: object) => {
|
||||
/**
|
||||
* 文件地址
|
||||
*/
|
||||
fileName: string
|
||||
fileName: string,
|
||||
fileurl: string,
|
||||
}>(`${ModuleTypeEnum.PROJECT}/upload`, data, ContentTypeEnum.FORM_DATA)
|
||||
return res
|
||||
} catch {
|
||||
|
||||
BIN
src/assets/images/chart/charts/dial.png
Normal file
BIN
src/assets/images/chart/charts/dial.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
src/assets/images/chart/charts/graph.png
Normal file
BIN
src/assets/images/chart/charts/graph.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 377 KiB |
BIN
src/assets/images/chart/charts/sankey.png
Normal file
BIN
src/assets/images/chart/charts/sankey.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -12,6 +12,7 @@ export enum DragKeyEnum {
|
||||
// 不同页面保存操作
|
||||
export enum SavePageEnum {
|
||||
CHART = 'SaveChart',
|
||||
CHART_TO_PREVIEW = 'ChartToPreview',
|
||||
JSON = 'SaveJSON',
|
||||
CLOSE = 'close'
|
||||
}
|
||||
|
||||
@@ -1,122 +1,123 @@
|
||||
import { ref, toRefs, toRaw, watch } from 'vue'
|
||||
import type VChart from 'vue-echarts'
|
||||
import { customizeHttp } from '@/api/http'
|
||||
import { useChartDataPondFetch } from '@/hooks/'
|
||||
import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
import { RequestDataTypeEnum } from '@/enums/httpEnum'
|
||||
import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
|
||||
import { setOption } from '@/packages/public/chart'
|
||||
|
||||
// 获取类型
|
||||
type ChartEditStoreType = typeof useChartEditStore
|
||||
|
||||
/**
|
||||
* setdata 数据监听与更改
|
||||
* @param targetComponent
|
||||
* @param useChartEditStore 若直接引会报错,只能动态传递
|
||||
* @param updateCallback 自定义更新函数
|
||||
*/
|
||||
export const useChartDataFetch = (
|
||||
targetComponent: CreateComponentType,
|
||||
useChartEditStore: ChartEditStoreType,
|
||||
updateCallback?: (...args: any) => any
|
||||
) => {
|
||||
const vChartRef = ref<typeof VChart | null>(null)
|
||||
let fetchInterval: any = 0
|
||||
|
||||
// 数据池
|
||||
const { addGlobalDataInterface } = useChartDataPondFetch()
|
||||
|
||||
// 组件类型
|
||||
const { chartFrame } = targetComponent.chartConfig
|
||||
|
||||
// eCharts 组件配合 vChart 库更新方式
|
||||
const echartsUpdateHandle = (dataset: any) => {
|
||||
if (chartFrame === ChartFrameEnum.ECHARTS) {
|
||||
if (vChartRef.value) {
|
||||
setOption(vChartRef.value, { dataset: dataset })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const requestIntervalFn = () => {
|
||||
const chartEditStore = useChartEditStore()
|
||||
|
||||
// 全局数据
|
||||
const {
|
||||
requestOriginUrl,
|
||||
requestIntervalUnit: globalUnit,
|
||||
requestInterval: globalRequestInterval
|
||||
} = toRefs(chartEditStore.getRequestGlobalConfig)
|
||||
|
||||
// 目标组件
|
||||
const {
|
||||
requestDataType,
|
||||
requestUrl,
|
||||
requestIntervalUnit: targetUnit,
|
||||
requestInterval: targetInterval
|
||||
} = toRefs(targetComponent.request)
|
||||
|
||||
// 非请求类型
|
||||
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
|
||||
|
||||
try {
|
||||
// 处理地址
|
||||
// @ts-ignore
|
||||
if (requestUrl?.value) {
|
||||
// requestOriginUrl 允许为空
|
||||
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
|
||||
if (!completePath) return
|
||||
|
||||
clearInterval(fetchInterval)
|
||||
|
||||
const fetchFn = async () => {
|
||||
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
|
||||
if (res) {
|
||||
try {
|
||||
const filter = targetComponent.filter
|
||||
echartsUpdateHandle(newFunctionHandle(res?.data, res, filter))
|
||||
// 更新回调函数
|
||||
if (updateCallback) {
|
||||
updateCallback(newFunctionHandle(res?.data, res, filter))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 普通初始化与组件交互处理监听
|
||||
watch(
|
||||
() => targetComponent.request,
|
||||
() => {
|
||||
fetchFn()
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
// 定时时间
|
||||
const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
|
||||
// 单位
|
||||
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
|
||||
// 开启轮询
|
||||
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
if (isPreview()) {
|
||||
// 判断是否是数据池类型
|
||||
targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
|
||||
? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
|
||||
: requestIntervalFn()
|
||||
}
|
||||
return { vChartRef }
|
||||
}
|
||||
import { ref, toRefs, toRaw, watch } from 'vue'
|
||||
import type VChart from 'vue-echarts'
|
||||
import { customizeHttp } from '@/api/http'
|
||||
import { useChartDataPondFetch } from '@/hooks/'
|
||||
import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
import { RequestDataTypeEnum } from '@/enums/httpEnum'
|
||||
import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
|
||||
import { setOption } from '@/packages/public/chart'
|
||||
|
||||
// 获取类型
|
||||
type ChartEditStoreType = typeof useChartEditStore
|
||||
|
||||
/**
|
||||
* setdata 数据监听与更改
|
||||
* @param targetComponent
|
||||
* @param useChartEditStore 若直接引会报错,只能动态传递
|
||||
* @param updateCallback 自定义更新函数
|
||||
*/
|
||||
export const useChartDataFetch = (
|
||||
targetComponent: CreateComponentType,
|
||||
useChartEditStore: ChartEditStoreType,
|
||||
updateCallback?: (...args: any) => any
|
||||
) => {
|
||||
const vChartRef = ref<typeof VChart | null>(null)
|
||||
let fetchInterval: any = 0
|
||||
|
||||
// 数据池
|
||||
const { addGlobalDataInterface } = useChartDataPondFetch()
|
||||
|
||||
// 组件类型
|
||||
const { chartFrame } = targetComponent.chartConfig
|
||||
|
||||
// eCharts 组件配合 vChart 库更新方式
|
||||
const echartsUpdateHandle = (dataset: any) => {
|
||||
if (chartFrame === ChartFrameEnum.ECHARTS) {
|
||||
if (vChartRef.value) {
|
||||
setOption(vChartRef.value, { dataset: dataset })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const requestIntervalFn = () => {
|
||||
const chartEditStore = useChartEditStore()
|
||||
|
||||
// 全局数据
|
||||
const {
|
||||
requestOriginUrl,
|
||||
requestIntervalUnit: globalUnit,
|
||||
requestInterval: globalRequestInterval
|
||||
} = toRefs(chartEditStore.getRequestGlobalConfig)
|
||||
|
||||
// 目标组件
|
||||
const {
|
||||
requestDataType,
|
||||
requestUrl,
|
||||
requestIntervalUnit: targetUnit,
|
||||
requestInterval: targetInterval
|
||||
} = toRefs(targetComponent.request)
|
||||
|
||||
// 非请求类型
|
||||
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
|
||||
|
||||
try {
|
||||
// 处理地址
|
||||
// @ts-ignore
|
||||
if (requestUrl?.value) {
|
||||
// requestOriginUrl 允许为空
|
||||
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
|
||||
if (!completePath) return
|
||||
|
||||
clearInterval(fetchInterval)
|
||||
|
||||
const fetchFn = async () => {
|
||||
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
|
||||
if (res) {
|
||||
try {
|
||||
const filter = targetComponent.filter
|
||||
const { data } = res
|
||||
echartsUpdateHandle(newFunctionHandle(data, res, filter))
|
||||
// 更新回调函数
|
||||
if (updateCallback) {
|
||||
updateCallback(newFunctionHandle(data, res, filter))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 普通初始化与组件交互处理监听
|
||||
watch(
|
||||
() => targetComponent.request,
|
||||
() => {
|
||||
fetchFn()
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
// 定时时间
|
||||
const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
|
||||
// 单位
|
||||
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
|
||||
// 开启轮询
|
||||
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
if (isPreview()) {
|
||||
// 判断是否是数据池类型
|
||||
targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
|
||||
? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
|
||||
: requestIntervalFn()
|
||||
}
|
||||
return { vChartRef }
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
<template>
|
||||
<router-view>
|
||||
<template #default="{ Component, route }">
|
||||
<component
|
||||
v-if="route.noKeepAlive"
|
||||
:is="Component"
|
||||
:key="route.fullPath"
|
||||
></component>
|
||||
<component v-if="route.meta.noKeepAlive" :is="Component"></component>
|
||||
<keep-alive v-else>
|
||||
<component :is="Component" :key="route.fullPath"></component>
|
||||
<component :is="Component"></component>
|
||||
</keep-alive>
|
||||
</template>
|
||||
</router-view>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<router-view #default="{ Component, route }">
|
||||
<transition name="fade" mode="out-in" appear>
|
||||
<component
|
||||
v-if="route.noKeepAlive"
|
||||
:is="Component"
|
||||
:key="route.fullPath"
|
||||
></component>
|
||||
<keep-alive v-else>
|
||||
<component :is="Component" :key="route.fullPath"></component>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</template>
|
||||
<template>
|
||||
<router-view #default="{ Component, route }">
|
||||
<transition name="fade" mode="out-in" appear>
|
||||
<component
|
||||
v-if="route.meta.noKeepAlive"
|
||||
:is="Component"
|
||||
:key="route.fullPath"
|
||||
></component>
|
||||
<keep-alive v-else>
|
||||
<component :is="Component" :key="route.fullPath"></component>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
<template>
|
||||
<v-chart
|
||||
ref="vChartRef"
|
||||
:init-options="initOptions"
|
||||
:theme="themeColor"
|
||||
:option="option"
|
||||
:manual-update="isPreview()"
|
||||
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()"
|
||||
:update-options="{
|
||||
replaceMerge: replaceMergeArr
|
||||
}"
|
||||
autoresize
|
||||
></v-chart>
|
||||
}" autoresize></v-chart>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -27,6 +20,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
|
||||
import { isPreview } from '@/utils'
|
||||
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||
import isObject from 'lodash/isObject'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
const props = defineProps({
|
||||
themeSetting: {
|
||||
@@ -61,11 +55,23 @@ watch(
|
||||
if (!isObject(newData) || !('dimensions' in newData)) return
|
||||
if (Array.isArray(newData?.dimensions)) {
|
||||
const seriesArr = []
|
||||
for (let i = 0; i < newData.dimensions.length - 1; i++) {
|
||||
seriesArr.push(seriesItem)
|
||||
// 对oldData进行判断,防止传入错误数据之后对旧维度判断产生干扰
|
||||
// 此处计算的是dimensions的Y轴维度,若是dimensions.length为0或1,则默认为1,排除X轴维度干扰
|
||||
const oldDimensions = Array.isArray(oldData?.dimensions)&&oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1;
|
||||
const newDimensions = newData.dimensions.length >= 1 ? newData.dimensions.length : 1;
|
||||
const dimensionsGap = newDimensions - oldDimensions;
|
||||
if (dimensionsGap < 0) {
|
||||
props.chartConfig.option.series.splice(newDimensions - 1)
|
||||
} else if (dimensionsGap > 0) {
|
||||
if(!oldData || !oldData?.dimensions || !Array.isArray(oldData?.dimensions) || !oldData?.dimensions.length ) {
|
||||
props.chartConfig.option.series=[]
|
||||
}
|
||||
for (let i = 0; i < dimensionsGap; i++) {
|
||||
seriesArr.push(cloneDeep(seriesItem))
|
||||
}
|
||||
props.chartConfig.option.series.push(...seriesArr)
|
||||
}
|
||||
replaceMergeArr.value = ['series']
|
||||
props.chartConfig.option.series = seriesArr
|
||||
nextTick(() => {
|
||||
replaceMergeArr.value = []
|
||||
})
|
||||
|
||||
@@ -26,6 +26,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
|
||||
import { isPreview } from '@/utils'
|
||||
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||
import isObject from 'lodash/isObject'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
const props = defineProps({
|
||||
themeSetting: {
|
||||
@@ -61,7 +62,7 @@ watch(
|
||||
if (Array.isArray(newData?.dimensions)) {
|
||||
const seriesArr = []
|
||||
for (let i = 0; i < newData.dimensions.length - 1; i++) {
|
||||
seriesArr.push(seriesItem)
|
||||
seriesArr.push(cloneDeep(seriesItem))
|
||||
}
|
||||
replaceMergeArr.value = ['series']
|
||||
props.chartConfig.option.series = seriesArr
|
||||
|
||||
91
src/packages/components/Charts/Mores/Dial/config.ts
Normal file
91
src/packages/components/Charts/Mores/Dial/config.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
|
||||
import { DialConfig } from './index'
|
||||
import { CreateComponentType } from '@/packages/index.d'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
export const includes = []
|
||||
const option = {
|
||||
backgroundColor: '#0E1327',
|
||||
dataset:70,
|
||||
series: [{
|
||||
type: "gauge",
|
||||
data: [{
|
||||
value: 70,
|
||||
itemStyle: { // 指针样式
|
||||
color: '#2AF4FF'
|
||||
}
|
||||
}],
|
||||
min: 0, //最小刻度
|
||||
max: 100, //最大刻度
|
||||
splitNumber: 10, //刻度数量
|
||||
center: ['50%', '55%'],
|
||||
radius: '80%',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: [
|
||||
[0, 'rgba(0,212,230,0.5)'],
|
||||
[1, 'rgba(28,128,245,0)']
|
||||
],
|
||||
width: 170
|
||||
}
|
||||
},
|
||||
axisLabel: { // 文字样式
|
||||
color: '#eee',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
detail: {
|
||||
show: false,
|
||||
},
|
||||
pointer: {
|
||||
length: '80%',
|
||||
width: 4
|
||||
},
|
||||
animationDuration: 2000,
|
||||
},
|
||||
{
|
||||
name: '外部刻度',
|
||||
type: 'gauge',
|
||||
center: ['50%', '55%'],
|
||||
radius: '90%',
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 25,
|
||||
color: [ // 表盘外部颜色
|
||||
[0, '#1369E380'],
|
||||
[1, '#1369E380']
|
||||
],
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
show:false,
|
||||
},
|
||||
axisTick: {
|
||||
splitNumber: 5,
|
||||
lineStyle: { //刻度颜色
|
||||
color: '#42E5FB',
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
length: 15,
|
||||
lineStyle: {
|
||||
color: '#42E5FB',
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
export default class Config extends PublicConfigClass implements CreateComponentType {
|
||||
public key: string = DialConfig.key
|
||||
public chartConfig = cloneDeep(DialConfig)
|
||||
// 图表配置项
|
||||
public option = echartOptionProfixHandle(option, includes)
|
||||
}
|
||||
84
src/packages/components/Charts/Mores/Dial/config.vue
Normal file
84
src/packages/components/Charts/Mores/Dial/config.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<!-- 遍历 seriesList -->
|
||||
<CollapseItem :name="`圆环`" :expanded="true">
|
||||
<SettingItemBox name="数据">
|
||||
<SettingItem name="数值">
|
||||
<n-input-number v-model:value="config.dataset" :min="dialConfig.min" :max="dialConfig.max" :step="1" size="small" placeholder="数值">
|
||||
</n-input-number>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
<!-- Echarts 全局设置 -->
|
||||
<!-- 表盘刻度字体 -->
|
||||
<SettingItemBox name="字体">
|
||||
<SettingItem name="颜色">
|
||||
<n-color-picker size="small" :modes="['hex']" v-model:value="dialConfig.axisLabel.color"></n-color-picker>
|
||||
</SettingItem>
|
||||
<SettingItem name="字体大小">
|
||||
<n-input-number
|
||||
v-model:value="dialConfig.axisLabel.fontSize"
|
||||
:min="0"
|
||||
:step="1"
|
||||
size="small"
|
||||
placeholder="字体大小"
|
||||
>
|
||||
</n-input-number>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
<!-- 表盘 -->
|
||||
<SettingItemBox name="表盘外部">
|
||||
<SettingItem name="颜色" >
|
||||
<n-color-picker size="small" :modes="['hex']" v-model:value="config.series[1].axisLine.lineStyle.color[1][1]"></n-color-picker>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
<!-- 指针 -->
|
||||
<SettingItemBox name="指针">
|
||||
<SettingItem name="颜色" >
|
||||
<n-color-picker size="small" :modes="['hex']" v-model:value="dialConfig.data[0].itemStyle.color"></n-color-picker>
|
||||
</SettingItem>
|
||||
<SettingItem name="宽度">
|
||||
<n-input-number v-model:value="dialConfig.pointer.width" :min="0" :step="1" size="small" placeholder="数值">
|
||||
</n-input-number>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
<SettingItemBox name="刻度">
|
||||
<SettingItem name="最小值">
|
||||
<n-input-number v-model:value="dialConfig.min" :min="0" :step="1" size="small" placeholder="数值">
|
||||
</n-input-number>
|
||||
</SettingItem>
|
||||
<SettingItem name="最大值">
|
||||
<n-input-number v-model:value="dialConfig.max" :min="0" :step="1" size="small" placeholder="数值">
|
||||
</n-input-number>
|
||||
</SettingItem>
|
||||
<SettingItem name="颜色" >
|
||||
<n-color-picker size="small" :modes="['hex']" v-model:value="config.series[1].axisTick.lineStyle.color" @update:value="updateClick"></n-color-picker>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
|
||||
</CollapseItem>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType, computed } from 'vue'
|
||||
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
|
||||
import { GlobalThemeJsonType } from '@/settings/chartThemes'
|
||||
|
||||
const props = defineProps({
|
||||
optionData: {
|
||||
type: Object as PropType<GlobalThemeJsonType>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const config = computed(() => {
|
||||
return props.optionData
|
||||
})
|
||||
|
||||
const dialConfig = computed(() => {
|
||||
return props.optionData.series[0]
|
||||
})
|
||||
|
||||
const updateClick = (val: any) => {
|
||||
props.optionData.series[1].splitLine.lineStyle.color=val
|
||||
}
|
||||
</script>
|
||||
|
||||
14
src/packages/components/Charts/Mores/Dial/index.ts
Normal file
14
src/packages/components/Charts/Mores/Dial/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
|
||||
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
|
||||
|
||||
export const DialConfig: ConfigType = {
|
||||
key: 'Dial',
|
||||
chartKey: 'VDial',
|
||||
conKey: 'VCDial',
|
||||
title: '表盘',
|
||||
category: ChatCategoryEnum.MORE,
|
||||
categoryName: ChatCategoryEnumName.MORE,
|
||||
package: PackagesCategoryEnum.CHARTS,
|
||||
chartFrame: ChartFrameEnum.COMMON,
|
||||
image:'dial.png'
|
||||
}
|
||||
69
src/packages/components/Charts/Mores/Dial/index.vue
Normal file
69
src/packages/components/Charts/Mores/Dial/index.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<v-chart :theme="themeColor" :init-options="initOptions" :option="option.value" autoresize> </v-chart>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType, reactive, watch } from 'vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import { mergeTheme } from '@/packages/public/chart'
|
||||
import config, { includes } from './config'
|
||||
import { useChartDataFetch } from '@/hooks'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent, TitleComponent } 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([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent, TitleComponent])
|
||||
|
||||
const option = reactive({
|
||||
value: {}
|
||||
})
|
||||
|
||||
const dataHandle = (newData: any) => {
|
||||
let config = props.chartConfig.option
|
||||
config.series[0].data[0].value = newData
|
||||
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
|
||||
option.value = props.chartConfig.option
|
||||
}
|
||||
|
||||
// 配置时
|
||||
watch(
|
||||
() => props.chartConfig.option.dataset,
|
||||
newData => {
|
||||
try {
|
||||
dataHandle(newData)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: false
|
||||
}
|
||||
)
|
||||
|
||||
// 预览时
|
||||
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
|
||||
// @ts-ignore
|
||||
option.value.series[0].data[0].value = resData
|
||||
})
|
||||
</script>
|
||||
71
src/packages/components/Charts/Mores/Graph/config.ts
Normal file
71
src/packages/components/Charts/Mores/Graph/config.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
|
||||
import { GraphConfig } from './index'
|
||||
import { CreateComponentType } from '@/packages/index.d'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import dataJson from './data.json'
|
||||
|
||||
export const includes = []
|
||||
|
||||
// 关系图布局
|
||||
export const GraphLayout = [
|
||||
{ label: '无', value: 'none' },
|
||||
{ label: '环形', value: 'circular' }
|
||||
]
|
||||
|
||||
// 标签开关
|
||||
export const LabelSwitch = [
|
||||
{ label: '开启', value: 1 },
|
||||
{ label: '关闭', value: 0 }
|
||||
]
|
||||
|
||||
// 标签位置
|
||||
export const LabelPosition = [
|
||||
{ label: '左侧', value: 'left' },
|
||||
{ label: '右侧', value: 'right' },
|
||||
{ label: '顶部', value: 'top' },
|
||||
{ label: '底部', value: 'bottom' },
|
||||
{ label: '内部', value: 'inside' },
|
||||
]
|
||||
|
||||
export const option = {
|
||||
dataset: { ...dataJson },
|
||||
tooltip: {},
|
||||
legend:{
|
||||
show:true,
|
||||
textStyle:{
|
||||
color:"#eee",
|
||||
fontSize: 14 ,
|
||||
},
|
||||
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 // 线条卷曲程度
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default class Config extends PublicConfigClass implements CreateComponentType {
|
||||
public key = GraphConfig.key
|
||||
public chartConfig = cloneDeep(GraphConfig)
|
||||
// 图表配置项
|
||||
public option = echartOptionProfixHandle(option, includes)
|
||||
}
|
||||
62
src/packages/components/Charts/Mores/Graph/config.vue
Normal file
62
src/packages/components/Charts/Mores/Graph/config.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div>
|
||||
<CollapseItem name="关系图" :expanded="true">
|
||||
<SettingItemBox name="样式">
|
||||
<setting-item name="布局">
|
||||
<n-select v-model:value="graphConfig.layout" :options="GraphLayout" size="small" />
|
||||
</setting-item>
|
||||
</SettingItemBox>
|
||||
<SettingItemBox name="标签">
|
||||
<setting-item name="展示">
|
||||
<n-select v-model:value="graphConfig.label.show" :options="LabelSwitch" size="small" />
|
||||
</setting-item>
|
||||
<setting-item name="位置">
|
||||
<n-select v-model:value="graphConfig.label.position" :options="LabelPosition" size="small" />
|
||||
</setting-item>
|
||||
</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>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
<SettingItemBox name="图例">
|
||||
<SettingItem name="颜色">
|
||||
<n-color-picker
|
||||
size="small"
|
||||
:modes="['hex']"
|
||||
v-model:value="optionData.legend.textStyle.color"
|
||||
></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>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
</CollapseItem>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<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 { GlobalThemeJsonType } from '@/settings/chartThemes/index'
|
||||
|
||||
const props = defineProps({
|
||||
optionData: {
|
||||
type: Object as PropType<typeof option & GlobalThemeJsonType>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const graphConfig = computed<typeof option.series[0]>(() => {
|
||||
return props.optionData.series[0]
|
||||
})
|
||||
</script>
|
||||
1744
src/packages/components/Charts/Mores/Graph/data.json
Normal file
1744
src/packages/components/Charts/Mores/Graph/data.json
Normal file
File diff suppressed because it is too large
Load Diff
14
src/packages/components/Charts/Mores/Graph/index.ts
Normal file
14
src/packages/components/Charts/Mores/Graph/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
|
||||
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
|
||||
|
||||
export const GraphConfig: ConfigType = {
|
||||
key: 'Graph',
|
||||
chartKey: 'VGraph',
|
||||
conKey: 'VCGraph',
|
||||
title: '关系图',
|
||||
category: ChatCategoryEnum.MORE,
|
||||
categoryName: ChatCategoryEnumName.MORE,
|
||||
package: PackagesCategoryEnum.CHARTS,
|
||||
chartFrame: ChartFrameEnum.COMMON,
|
||||
image: 'graph.png'
|
||||
}
|
||||
80
src/packages/components/Charts/Mores/Graph/index.vue
Normal file
80
src/packages/components/Charts/Mores/Graph/index.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, PropType, watch } from 'vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
|
||||
import dataJson from './data.json'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { RadarChart } from 'echarts/charts'
|
||||
import { includes } from './config'
|
||||
import { mergeTheme, setOption } from '@/packages/public/chart'
|
||||
import { useChartDataFetch } from '@/hooks'
|
||||
import { CreateComponentType } from '@/packages/index.d'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
import { isPreview } from '@/utils'
|
||||
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||
|
||||
const props = defineProps({
|
||||
themeSetting: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
themeColor: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
chartConfig: {
|
||||
type: Object as PropType<CreateComponentType>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
|
||||
|
||||
use([DatasetComponent, CanvasRenderer, RadarChart, GridComponent, TooltipComponent, LegendComponent])
|
||||
|
||||
const vChartRef = ref<typeof VChart>()
|
||||
|
||||
const option = computed(() => {
|
||||
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
|
||||
})
|
||||
|
||||
const dataSetHandle = (dataset: typeof dataJson) => {
|
||||
if (dataset.nodes) {
|
||||
props.chartConfig.option.series[0].data = dataset.nodes
|
||||
}
|
||||
if (dataset.links) {
|
||||
props.chartConfig.option.series[0].links = dataset.links
|
||||
}
|
||||
if (dataset.categories) {
|
||||
props.chartConfig.option.series[0].categories = dataset.categories
|
||||
// @ts-ignore
|
||||
props.chartConfig.option.legend.data = dataset.categories.map((i: { name: string }) => i.name)
|
||||
}
|
||||
if (vChartRef.value && isPreview()) {
|
||||
setOption(vChartRef.value, props.chartConfig.option)
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.chartConfig.option.dataset,
|
||||
newData => {
|
||||
try {
|
||||
dataSetHandle(newData)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: false
|
||||
}
|
||||
)
|
||||
|
||||
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
|
||||
dataSetHandle(newData)
|
||||
})
|
||||
</script>
|
||||
43
src/packages/components/Charts/Mores/Sankey/config.ts
Normal file
43
src/packages/components/Charts/Mores/Sankey/config.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
|
||||
import { SankeyConfig } from './index'
|
||||
import { CreateComponentType } from '@/packages/index.d'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import dataJson from './data.json'
|
||||
|
||||
export const includes = ['legend']
|
||||
|
||||
// 图表方向
|
||||
export const orientList = [
|
||||
{ label: '水平', value: 'horizontal' },
|
||||
{ label: '垂直', value: 'vertical' }
|
||||
]
|
||||
|
||||
// 标签展示
|
||||
export const toolTipSwitch = [
|
||||
{ label: '开启', value: 1 },
|
||||
{ label: '关闭', value: 0 }
|
||||
]
|
||||
|
||||
export const option = {
|
||||
dataset: { ...dataJson },
|
||||
tooltip: {
|
||||
show: 1,
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove'
|
||||
},
|
||||
series: {
|
||||
type: 'sankey',
|
||||
layout: 'none',
|
||||
orient:'horizontal',
|
||||
data: dataJson.label,
|
||||
links: dataJson.links,
|
||||
levels: dataJson.levels
|
||||
}
|
||||
};
|
||||
|
||||
export default class Config extends PublicConfigClass implements CreateComponentType {
|
||||
public key = SankeyConfig.key
|
||||
public chartConfig = cloneDeep(SankeyConfig)
|
||||
// 图表配置项
|
||||
public option = echartOptionProfixHandle(option, includes)
|
||||
}
|
||||
43
src/packages/components/Charts/Mores/Sankey/config.vue
Normal file
43
src/packages/components/Charts/Mores/Sankey/config.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div>
|
||||
<CollapseItem name="桑基图" :expanded="true">
|
||||
<SettingItemBox name="样式">
|
||||
<SettingItem name="方向">
|
||||
<n-select
|
||||
v-model:value="sankeyConfig.orient"
|
||||
size="small"
|
||||
:options="orientList"
|
||||
placeholder="选择方向"
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem name="提示标签">
|
||||
<n-select
|
||||
v-model:value="optionData.tooltip.show"
|
||||
size="small"
|
||||
:options="toolTipSwitch"
|
||||
placeholder="是否开启"
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingItemBox>
|
||||
</CollapseItem>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType, computed } from 'vue'
|
||||
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
|
||||
import { option, orientList, toolTipSwitch } from './config'
|
||||
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
|
||||
|
||||
const props = defineProps({
|
||||
optionData: {
|
||||
type: Object as PropType<typeof option & GlobalThemeJsonType>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const sankeyConfig = computed<typeof option.series>(() => {
|
||||
return props.optionData.series
|
||||
})
|
||||
|
||||
</script>
|
||||
86
src/packages/components/Charts/Mores/Sankey/data.json
Normal file
86
src/packages/components/Charts/Mores/Sankey/data.json
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"label": [
|
||||
{
|
||||
"name": "a"
|
||||
},
|
||||
{
|
||||
"name": "b"
|
||||
},
|
||||
{
|
||||
"name": "a1"
|
||||
},
|
||||
{
|
||||
"name": "a2"
|
||||
},
|
||||
{
|
||||
"name": "b1"
|
||||
},
|
||||
{
|
||||
"name": "b2"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"source": "a",
|
||||
"target": "a1",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"source": "a",
|
||||
"target": "a2",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"source": "b",
|
||||
"target": "b1",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"source": "a",
|
||||
"target": "b1",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"source": "b1",
|
||||
"target": "a1",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"source": "b1",
|
||||
"target": "b2",
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"levels": [
|
||||
{
|
||||
"depth": 0,
|
||||
"itemStyle": {
|
||||
"color": "#decbe4"
|
||||
},
|
||||
"lineStyle": {
|
||||
"color": "source",
|
||||
"opacity": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"depth": 1,
|
||||
"itemStyle": {
|
||||
"color": "#b3cde3"
|
||||
},
|
||||
"lineStyle": {
|
||||
"color": "source",
|
||||
"opacity": 0.6
|
||||
}
|
||||
},
|
||||
{
|
||||
"depth": 2,
|
||||
"itemStyle": {
|
||||
"color": "#ccebc5"
|
||||
},
|
||||
"lineStyle": {
|
||||
"color": "source",
|
||||
"opacity": 0.6
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
14
src/packages/components/Charts/Mores/Sankey/index.ts
Normal file
14
src/packages/components/Charts/Mores/Sankey/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
|
||||
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
|
||||
|
||||
export const SankeyConfig: ConfigType = {
|
||||
key: 'Sankey',
|
||||
chartKey: 'VSankey',
|
||||
conKey: 'VCSankey',
|
||||
title: '桑基图',
|
||||
category: ChatCategoryEnum.MORE,
|
||||
categoryName: ChatCategoryEnumName.MORE,
|
||||
package: PackagesCategoryEnum.CHARTS,
|
||||
chartFrame: ChartFrameEnum.COMMON,
|
||||
image: 'sankey.png'
|
||||
}
|
||||
78
src/packages/components/Charts/Mores/Sankey/index.vue
Normal file
78
src/packages/components/Charts/Mores/Sankey/index.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, PropType, watch } from 'vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
|
||||
import dataJson from './data.json'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { RadarChart } from 'echarts/charts'
|
||||
import { includes } from './config'
|
||||
import { mergeTheme, setOption } from '@/packages/public/chart'
|
||||
import { useChartDataFetch } from '@/hooks'
|
||||
import { CreateComponentType } from '@/packages/index.d'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
import { isPreview } from '@/utils'
|
||||
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||
|
||||
const props = defineProps({
|
||||
themeSetting: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
themeColor: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
chartConfig: {
|
||||
type: Object as PropType<CreateComponentType>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
|
||||
|
||||
use([DatasetComponent, CanvasRenderer, RadarChart, GridComponent, TooltipComponent, LegendComponent])
|
||||
|
||||
const vChartRef = ref<typeof VChart>()
|
||||
|
||||
const option = computed(() => {
|
||||
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
|
||||
})
|
||||
|
||||
const dataHandle = (dataset: typeof dataJson) => {
|
||||
if (dataset.label) {
|
||||
props.chartConfig.option.series.data = dataset.label
|
||||
}
|
||||
if (dataset.links) {
|
||||
props.chartConfig.option.series.links = dataset.links
|
||||
}
|
||||
if (dataset.levels) {
|
||||
props.chartConfig.option.series.levels = dataset.levels
|
||||
}
|
||||
if (vChartRef.value && isPreview()) {
|
||||
setOption(vChartRef.value, props.chartConfig.option)
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.chartConfig.option.dataset,
|
||||
newData => {
|
||||
try {
|
||||
dataHandle(newData)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
|
||||
dataHandle(newData)
|
||||
})
|
||||
</script>
|
||||
@@ -4,5 +4,8 @@ import { FunnelConfig } from './Funnel/index'
|
||||
import { HeatmapConfig } from './Heatmap/index'
|
||||
import { WaterPoloConfig } from './WaterPolo/index'
|
||||
import { TreeMapConfig } from './TreeMap/index'
|
||||
import { DialConfig } from './Dial/index'
|
||||
import { SankeyConfig } from './Sankey/index'
|
||||
import { GraphConfig } from './Graph/index'
|
||||
|
||||
export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig]
|
||||
export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig, GraphConfig, SankeyConfig, DialConfig]
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
/**
|
||||
* 资源文件
|
||||
* 把模型和图片分开进行加载
|
||||
*/
|
||||
|
||||
interface ITextures {
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface IResources {
|
||||
textures?: ITextures[]
|
||||
}
|
||||
|
||||
const fileSuffix = ['earth', 'gradient', 'redCircle', 'label', 'aperture', 'glow', 'light_column', 'aircraft']
|
||||
const textures: ITextures[] = []
|
||||
|
||||
const modules = import.meta.globEager("../../images/earth/*");
|
||||
|
||||
for(let item in modules) {
|
||||
const n = item.split('/').pop()
|
||||
if(n) {
|
||||
textures.push({
|
||||
name: n.split('.')[0],
|
||||
url: modules[item].default
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const resources: IResources = {
|
||||
textures
|
||||
}
|
||||
|
||||
export { resources }
|
||||
/**
|
||||
* 资源文件
|
||||
* 把模型和图片分开进行加载
|
||||
*/
|
||||
|
||||
interface ITextures {
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface IResources {
|
||||
textures?: ITextures[]
|
||||
}
|
||||
|
||||
const fileSuffix = ['earth', 'gradient', 'redCircle', 'label', 'aperture', 'glow', 'light_column', 'aircraft']
|
||||
const textures: ITextures[] = []
|
||||
|
||||
const modules: Record<string, { default: string }> = import.meta.glob("../../images/earth/*", { eager: true })
|
||||
|
||||
for(let item in modules) {
|
||||
const n = item.split('/').pop()
|
||||
if(n) {
|
||||
textures.push({
|
||||
name: n.split('.')[0],
|
||||
url: modules[item].default
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const resources: IResources = {
|
||||
textures
|
||||
}
|
||||
|
||||
export { resources }
|
||||
|
||||
@@ -1,81 +1,87 @@
|
||||
import { ChartList } from '@/packages/components/Charts/index'
|
||||
import { DecorateList } from '@/packages/components/Decorates/index'
|
||||
import { InformationList } from '@/packages/components/Informations/index'
|
||||
import { TableList } from '@/packages/components/Tables/index'
|
||||
import { PackagesCategoryEnum, PackagesType, ConfigType, FetchComFlagType } from '@/packages/index.d'
|
||||
|
||||
const configModules = import.meta.globEager('./components/**/config.vue')
|
||||
const indexModules = import.meta.globEager('./components/**/index.vue')
|
||||
const imagesModules = import.meta.globEager('../assets/images/chart/**')
|
||||
|
||||
// * 所有图表
|
||||
export let packagesList: PackagesType = {
|
||||
[PackagesCategoryEnum.CHARTS]: ChartList,
|
||||
[PackagesCategoryEnum.INFORMATIONS]: InformationList,
|
||||
[PackagesCategoryEnum.TABLES]: TableList,
|
||||
[PackagesCategoryEnum.DECORATES]: DecorateList
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取目标组件配置信息
|
||||
* @param targetData
|
||||
*/
|
||||
export const createComponent = async (targetData: ConfigType) => {
|
||||
const { category, key } = targetData
|
||||
const chart = await import(`./components/${targetData.package}/${category}/${key}/config.ts`)
|
||||
return new chart.default()
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取组件
|
||||
* @param {string} chartName 名称
|
||||
* @param {FetchComFlagType} flag 标识 0为展示组件, 1为配置组件
|
||||
*/
|
||||
const fetchComponent = (chartName: string, flag: FetchComFlagType) => {
|
||||
const module = flag === FetchComFlagType.VIEW ? indexModules : configModules
|
||||
for (const key in module) {
|
||||
const urlSplit = key.split('/')
|
||||
if (urlSplit[urlSplit.length - 2] === chartName) {
|
||||
return module[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取展示组件
|
||||
* @param {ConfigType} dropData 配置项
|
||||
*/
|
||||
export const fetchChartComponent = (dropData: ConfigType) => {
|
||||
const { key } = dropData
|
||||
return fetchComponent(key, FetchComFlagType.VIEW)?.default
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取配置组件
|
||||
* @param {ConfigType} dropData 配置项
|
||||
*/
|
||||
export const fetchConfigComponent = (dropData: ConfigType) => {
|
||||
const { key } = dropData
|
||||
return fetchComponent(key, FetchComFlagType.CONFIG)?.default
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取图片内容
|
||||
* @param {ConfigType} targetData 配置项
|
||||
*/
|
||||
export const fetchImages = async (targetData?: ConfigType) => {
|
||||
if (!targetData) return ''
|
||||
// 新数据动态处理
|
||||
const { image, package: targetDataPackage } = targetData
|
||||
// 兼容旧数据
|
||||
if (image.includes('@') || image.includes('base64')) return image
|
||||
|
||||
const imageName = image.substring(image.lastIndexOf('/') + 1)
|
||||
for (const key in imagesModules) {
|
||||
const urlSplit = key.split('/')
|
||||
if (urlSplit[urlSplit.length - 1] === imageName) {
|
||||
return imagesModules[key]?.default
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
import { ChartList } from '@/packages/components/Charts/index'
|
||||
import { DecorateList } from '@/packages/components/Decorates/index'
|
||||
import { InformationList } from '@/packages/components/Informations/index'
|
||||
import { TableList } from '@/packages/components/Tables/index'
|
||||
import { PackagesCategoryEnum, PackagesType, ConfigType, FetchComFlagType } from '@/packages/index.d'
|
||||
|
||||
const configModules: Record<string, { default: string }> = import.meta.glob('./components/**/config.vue', {
|
||||
eager: true
|
||||
})
|
||||
const indexModules: Record<string, { default: string }> = import.meta.glob('./components/**/index.vue', {
|
||||
eager: true
|
||||
})
|
||||
const imagesModules: Record<string, { default: string }> = import.meta.glob('../assets/images/chart/**', {
|
||||
eager: true
|
||||
})
|
||||
|
||||
// * 所有图表
|
||||
export let packagesList: PackagesType = {
|
||||
[PackagesCategoryEnum.CHARTS]: ChartList,
|
||||
[PackagesCategoryEnum.INFORMATIONS]: InformationList,
|
||||
[PackagesCategoryEnum.TABLES]: TableList,
|
||||
[PackagesCategoryEnum.DECORATES]: DecorateList
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取目标组件配置信息
|
||||
* @param targetData
|
||||
*/
|
||||
export const createComponent = async (targetData: ConfigType) => {
|
||||
const { category, key } = targetData
|
||||
const chart = await import(`./components/${targetData.package}/${category}/${key}/config.ts`)
|
||||
return new chart.default()
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取组件
|
||||
* @param {string} chartName 名称
|
||||
* @param {FetchComFlagType} flag 标识 0为展示组件, 1为配置组件
|
||||
*/
|
||||
const fetchComponent = (chartName: string, flag: FetchComFlagType) => {
|
||||
const module = flag === FetchComFlagType.VIEW ? indexModules : configModules
|
||||
for (const key in module) {
|
||||
const urlSplit = key.split('/')
|
||||
if (urlSplit[urlSplit.length - 2] === chartName) {
|
||||
return module[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取展示组件
|
||||
* @param {ConfigType} dropData 配置项
|
||||
*/
|
||||
export const fetchChartComponent = (dropData: ConfigType) => {
|
||||
const { key } = dropData
|
||||
return fetchComponent(key, FetchComFlagType.VIEW)?.default
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取配置组件
|
||||
* @param {ConfigType} dropData 配置项
|
||||
*/
|
||||
export const fetchConfigComponent = (dropData: ConfigType) => {
|
||||
const { key } = dropData
|
||||
return fetchComponent(key, FetchComFlagType.CONFIG)?.default
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取图片内容
|
||||
* @param {ConfigType} targetData 配置项
|
||||
*/
|
||||
export const fetchImages = async (targetData?: ConfigType) => {
|
||||
if (!targetData) return ''
|
||||
// 新数据动态处理
|
||||
const { image, package: targetDataPackage } = targetData
|
||||
// 兼容旧数据
|
||||
if (image.includes('@') || image.includes('base64')) return image
|
||||
|
||||
const imageName = image.substring(image.lastIndexOf('/') + 1)
|
||||
for (const key in imagesModules) {
|
||||
const urlSplit = key.split('/')
|
||||
if (urlSplit[urlSplit.length - 1] === imageName) {
|
||||
return imagesModules[key]?.default
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -1,77 +1,83 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ChartLayoutType, LayerModeEnum, ChartModeEnum } from './chartLayoutStore.d'
|
||||
import { setLocalStorage, getLocalStorage } from '@/utils'
|
||||
import { StorageEnum } from '@/enums/storageEnum'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
|
||||
const chartEditStore = useChartEditStore()
|
||||
|
||||
const { GO_CHART_LAYOUT_STORE } = StorageEnum
|
||||
|
||||
const storageChartLayout: Partial<ChartLayoutType> = getLocalStorage(GO_CHART_LAYOUT_STORE)
|
||||
|
||||
// 编辑区域布局和静态设置
|
||||
export const useChartLayoutStore = defineStore({
|
||||
id: 'useChartLayoutStore',
|
||||
state: (): ChartLayoutType => ({
|
||||
// 图层控制
|
||||
layers: true,
|
||||
// 图表组件
|
||||
charts: true,
|
||||
// 详情设置(收缩为true)
|
||||
details: false,
|
||||
// 组件列表展示类型(默认单列)
|
||||
chartType: ChartModeEnum.SINGLE,
|
||||
// 图层类型(默认图片)
|
||||
layerType: LayerModeEnum.THUMBNAIL,
|
||||
// 当前加载数量
|
||||
percentage: 0,
|
||||
// 是否重置当前画布位置
|
||||
rePositionCanvas: false,
|
||||
// 防止值不存在
|
||||
...storageChartLayout
|
||||
}),
|
||||
getters: {
|
||||
getLayers(): boolean {
|
||||
return this.layers
|
||||
},
|
||||
getCharts(): boolean {
|
||||
return this.charts
|
||||
},
|
||||
getDetails(): boolean {
|
||||
return this.details
|
||||
},
|
||||
getChartType(): ChartModeEnum {
|
||||
return this.chartType
|
||||
},
|
||||
getLayerType(): LayerModeEnum {
|
||||
return this.layerType
|
||||
},
|
||||
getPercentage(): number {
|
||||
return this.percentage
|
||||
},
|
||||
getRePositionCanvas(): boolean {
|
||||
return this.rePositionCanvas
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setItem<T extends keyof ChartLayoutType, K extends ChartLayoutType[T]>(key: T, value: K): void {
|
||||
this.$patch(state => {
|
||||
state[key] = value
|
||||
})
|
||||
// 存储本地
|
||||
setLocalStorage(GO_CHART_LAYOUT_STORE, this.$state)
|
||||
// 这里需要标记重置画布位置
|
||||
this.rePositionCanvas = true;
|
||||
// 重新计算拖拽区域缩放比例
|
||||
setTimeout(() => {
|
||||
chartEditStore.computedScale()
|
||||
}, 500)
|
||||
},
|
||||
setItemUnHandle<T extends keyof ChartLayoutType, K extends ChartLayoutType[T]>(key: T, value: K): void {
|
||||
this.$patch(state => {
|
||||
state[key] = value
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
import { defineStore } from 'pinia'
|
||||
import { ChartLayoutType, LayerModeEnum, ChartModeEnum } from './chartLayoutStore.d'
|
||||
import { setLocalStorage, getLocalStorage } from '@/utils'
|
||||
import { StorageEnum } from '@/enums/storageEnum'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
|
||||
const chartEditStore = useChartEditStore()
|
||||
|
||||
const { GO_CHART_LAYOUT_STORE } = StorageEnum
|
||||
|
||||
const storageChartLayout: Partial<ChartLayoutType> = getLocalStorage(GO_CHART_LAYOUT_STORE)
|
||||
|
||||
// 编辑区域布局和静态设置
|
||||
export const useChartLayoutStore = defineStore({
|
||||
id: 'useChartLayoutStore',
|
||||
state: (): ChartLayoutType => ({
|
||||
// 图层控制
|
||||
layers: true,
|
||||
// 图表组件
|
||||
charts: true,
|
||||
// 详情设置(收缩为true)
|
||||
details: false,
|
||||
// 组件列表展示类型(默认单列)
|
||||
chartType: ChartModeEnum.SINGLE,
|
||||
// 图层类型(默认图片)
|
||||
layerType: LayerModeEnum.THUMBNAIL,
|
||||
// 当前加载数量
|
||||
percentage: 0,
|
||||
// 是否重置当前画布位置
|
||||
rePositionCanvas: false,
|
||||
// 防止值不存在
|
||||
...storageChartLayout
|
||||
}),
|
||||
getters: {
|
||||
getLayers(): boolean {
|
||||
return this.layers
|
||||
},
|
||||
getCharts(): boolean {
|
||||
return this.charts
|
||||
},
|
||||
getDetails(): boolean {
|
||||
return this.details
|
||||
},
|
||||
getChartType(): ChartModeEnum {
|
||||
return this.chartType
|
||||
},
|
||||
getLayerType(): LayerModeEnum {
|
||||
return this.layerType
|
||||
},
|
||||
getPercentage(): number {
|
||||
return this.percentage
|
||||
},
|
||||
getRePositionCanvas(): boolean {
|
||||
return this.rePositionCanvas
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setItem<T extends keyof ChartLayoutType, K extends ChartLayoutType[T]>(
|
||||
key: T,
|
||||
value: K,
|
||||
computedScale = true
|
||||
): void {
|
||||
this.$patch(state => {
|
||||
state[key] = value
|
||||
})
|
||||
// 存储本地
|
||||
setLocalStorage(GO_CHART_LAYOUT_STORE, this.$state)
|
||||
// 这里需要标记重置画布位置
|
||||
this.rePositionCanvas = true;
|
||||
// 重新计算拖拽区域缩放比例
|
||||
if (computedScale) {
|
||||
setTimeout(() => {
|
||||
chartEditStore.computedScale()
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
setItemUnHandle<T extends keyof ChartLayoutType, K extends ChartLayoutType[T]>(key: T, value: K): void {
|
||||
this.$patch(state => {
|
||||
state[key] = value
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,92 +1,92 @@
|
||||
import { shallowReactive, ref } from 'vue'
|
||||
import { icon } from '@/plugins'
|
||||
import { renderLang, renderIcon } from '@/utils'
|
||||
import { themeColor, setItem, getCharts } from './useLayout.hook'
|
||||
import { PackagesCategoryEnum, PackagesCategoryName, PackagesType } from '@/packages/index.d'
|
||||
// 图表
|
||||
import { usePackagesStore } from '@/store/modules/packagesStore/packagesStore'
|
||||
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
|
||||
// 图标
|
||||
const { BarChartIcon } = icon.ionicons5
|
||||
const {
|
||||
TableSplitIcon,
|
||||
RoadmapIcon,
|
||||
SpellCheckIcon,
|
||||
GraphicalDataFlowIcon,
|
||||
} = icon.carbon
|
||||
|
||||
|
||||
// 图表
|
||||
export type MenuOptionsType = {
|
||||
key: string
|
||||
icon: ReturnType<typeof renderIcon>
|
||||
label: ReturnType<typeof renderLang>
|
||||
list: PackagesType
|
||||
}
|
||||
|
||||
const { getPackagesList } = usePackagesStore()
|
||||
const menuOptions: MenuOptionsType[] = []
|
||||
|
||||
const packagesListObj = {
|
||||
[PackagesCategoryEnum.CHARTS]: {
|
||||
icon: renderIcon(RoadmapIcon),
|
||||
label: PackagesCategoryName.CHARTS,
|
||||
},
|
||||
[PackagesCategoryEnum.INFORMATIONS]: {
|
||||
icon: renderIcon(SpellCheckIcon),
|
||||
label: PackagesCategoryName.INFORMATIONS,
|
||||
},
|
||||
[PackagesCategoryEnum.TABLES]: {
|
||||
icon: renderIcon(TableSplitIcon),
|
||||
label: PackagesCategoryName.TABLES,
|
||||
},
|
||||
[PackagesCategoryEnum.DECORATES]: {
|
||||
icon: renderIcon(GraphicalDataFlowIcon),
|
||||
label: PackagesCategoryName.DECORATES,
|
||||
},
|
||||
}
|
||||
|
||||
// 处理列表
|
||||
const handlePackagesList = () => {
|
||||
for (const val in getPackagesList) {
|
||||
menuOptions.push({
|
||||
key: val,
|
||||
// @ts-ignore
|
||||
icon: packagesListObj[val].icon,
|
||||
// @ts-ignore
|
||||
label: packagesListObj[val].label,
|
||||
// @ts-ignore
|
||||
list: getPackagesList[val],
|
||||
})
|
||||
}
|
||||
}
|
||||
handlePackagesList()
|
||||
|
||||
// 记录选中值
|
||||
let beforeSelect: string = menuOptions[0]['key']
|
||||
const selectValue = ref<string>(menuOptions[0]['key'])
|
||||
|
||||
// 选中的对象值
|
||||
const selectOptions = ref(menuOptions[0])
|
||||
|
||||
// 点击 item
|
||||
const clickItemHandle = (key: string, item: any) => {
|
||||
selectOptions.value = item
|
||||
// 处理折叠
|
||||
if (beforeSelect === key) {
|
||||
setItem(ChartLayoutStoreEnum.CHARTS, !getCharts.value)
|
||||
} else {
|
||||
setItem(ChartLayoutStoreEnum.CHARTS, true)
|
||||
}
|
||||
beforeSelect = key
|
||||
}
|
||||
|
||||
export {
|
||||
getCharts,
|
||||
BarChartIcon,
|
||||
themeColor,
|
||||
selectOptions,
|
||||
selectValue,
|
||||
clickItemHandle,
|
||||
menuOptions,
|
||||
}
|
||||
import { shallowReactive, ref } from 'vue'
|
||||
import { icon } from '@/plugins'
|
||||
import { renderLang, renderIcon } from '@/utils'
|
||||
import { themeColor, setItem, getCharts } from './useLayout.hook'
|
||||
import { PackagesCategoryEnum, PackagesCategoryName, PackagesType } from '@/packages/index.d'
|
||||
// 图表
|
||||
import { usePackagesStore } from '@/store/modules/packagesStore/packagesStore'
|
||||
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
|
||||
// 图标
|
||||
const { BarChartIcon } = icon.ionicons5
|
||||
const {
|
||||
TableSplitIcon,
|
||||
RoadmapIcon,
|
||||
SpellCheckIcon,
|
||||
GraphicalDataFlowIcon,
|
||||
} = icon.carbon
|
||||
|
||||
|
||||
// 图表
|
||||
export type MenuOptionsType = {
|
||||
key: string
|
||||
icon: ReturnType<typeof renderIcon>
|
||||
label: ReturnType<typeof renderLang>
|
||||
list: PackagesType
|
||||
}
|
||||
|
||||
const { getPackagesList } = usePackagesStore()
|
||||
const menuOptions: MenuOptionsType[] = []
|
||||
|
||||
const packagesListObj = {
|
||||
[PackagesCategoryEnum.CHARTS]: {
|
||||
icon: renderIcon(RoadmapIcon),
|
||||
label: PackagesCategoryName.CHARTS,
|
||||
},
|
||||
[PackagesCategoryEnum.INFORMATIONS]: {
|
||||
icon: renderIcon(SpellCheckIcon),
|
||||
label: PackagesCategoryName.INFORMATIONS,
|
||||
},
|
||||
[PackagesCategoryEnum.TABLES]: {
|
||||
icon: renderIcon(TableSplitIcon),
|
||||
label: PackagesCategoryName.TABLES,
|
||||
},
|
||||
[PackagesCategoryEnum.DECORATES]: {
|
||||
icon: renderIcon(GraphicalDataFlowIcon),
|
||||
label: PackagesCategoryName.DECORATES,
|
||||
},
|
||||
}
|
||||
|
||||
// 处理列表
|
||||
const handlePackagesList = () => {
|
||||
for (const val in getPackagesList) {
|
||||
menuOptions.push({
|
||||
key: val,
|
||||
// @ts-ignore
|
||||
icon: packagesListObj[val].icon,
|
||||
// @ts-ignore
|
||||
label: packagesListObj[val].label,
|
||||
// @ts-ignore
|
||||
list: getPackagesList[val],
|
||||
})
|
||||
}
|
||||
}
|
||||
handlePackagesList()
|
||||
|
||||
// 记录选中值
|
||||
let beforeSelect: string = menuOptions[0]['key']
|
||||
const selectValue = ref<string>(menuOptions[0]['key'])
|
||||
|
||||
// 选中的对象值
|
||||
const selectOptions = ref(menuOptions[0])
|
||||
|
||||
// 点击 item
|
||||
const clickItemHandle = (key: string, item: any) => {
|
||||
selectOptions.value = item
|
||||
// 处理折叠
|
||||
if (beforeSelect === key) {
|
||||
setItem(ChartLayoutStoreEnum.CHARTS, !getCharts.value, false)
|
||||
} else {
|
||||
setItem(ChartLayoutStoreEnum.CHARTS, true, false)
|
||||
}
|
||||
beforeSelect = key
|
||||
}
|
||||
|
||||
export {
|
||||
getCharts,
|
||||
BarChartIcon,
|
||||
themeColor,
|
||||
selectOptions,
|
||||
selectValue,
|
||||
clickItemHandle,
|
||||
menuOptions,
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ import { loadAsyncComponent, fetchRouteParamsLocation } from '@/utils'
|
||||
import { PreviewScaleEnum } from '@/enums/styleEnum'
|
||||
import { ResultEnum } from '@/enums/httpEnum'
|
||||
import { icon } from '@/plugins'
|
||||
import { uploadFile} from '@/api/path'
|
||||
import { uploadFile } from '@/api/path'
|
||||
|
||||
const { ColorPaletteIcon } = icon.ionicons5
|
||||
const { ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon
|
||||
@@ -273,24 +273,26 @@ const customRequest = (options: UploadCustomRequestOptions) => {
|
||||
nextTick(async () => {
|
||||
if (file.file) {
|
||||
// 修改名称
|
||||
const newNameFile = new File(
|
||||
[file.file],
|
||||
`${fetchRouteParamsLocation()}_index_background.png`,
|
||||
{ type: file.file.type }
|
||||
)
|
||||
const newNameFile = new File([file.file], `${fetchRouteParamsLocation()}_index_background.png`, {
|
||||
type: file.file.type
|
||||
})
|
||||
let uploadParams = new FormData()
|
||||
uploadParams.append('object', newNameFile)
|
||||
const uploadRes = await uploadFile(uploadParams)
|
||||
|
||||
if(uploadRes && uploadRes.code === ResultEnum.SUCCESS) {
|
||||
chartEditStore.setEditCanvasConfig(
|
||||
EditCanvasConfigEnum.BACKGROUND_IMAGE,
|
||||
`${systemStore.getFetchInfo.OSSUrl}${uploadRes.data.fileName}?time=${new Date().getTime()}`
|
||||
)
|
||||
chartEditStore.setEditCanvasConfig(
|
||||
EditCanvasConfigEnum.SELECT_COLOR,
|
||||
false
|
||||
)
|
||||
if (uploadRes && uploadRes.code === ResultEnum.SUCCESS) {
|
||||
if (uploadRes.data.fileurl) {
|
||||
chartEditStore.setEditCanvasConfig(
|
||||
EditCanvasConfigEnum.BACKGROUND_IMAGE,
|
||||
`${uploadRes.data.fileurl}?time=${new Date().getTime()}`
|
||||
)
|
||||
} else {
|
||||
chartEditStore.setEditCanvasConfig(
|
||||
EditCanvasConfigEnum.BACKGROUND_IMAGE,
|
||||
`${systemStore.getFetchInfo.OSSUrl || ''}${uploadRes.data.fileName}?time=${new Date().getTime()}`
|
||||
)
|
||||
}
|
||||
chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.SELECT_COLOR, false)
|
||||
return
|
||||
}
|
||||
window['$message'].error('添加图片失败,请稍后重试!')
|
||||
|
||||
@@ -1,196 +1,197 @@
|
||||
<template>
|
||||
<div class="go-chart-configurations-data-ajax">
|
||||
<n-card class="n-card-shallow">
|
||||
<setting-item-box name="请求配置">
|
||||
<setting-item name="类型">
|
||||
<n-tag :bordered="false" type="primary" style="border-radius: 5px">
|
||||
{{ targetData.request.requestContentType === RequestContentTypeEnum.DEFAULT ? '普通请求' : 'SQL请求' }}
|
||||
</n-tag>
|
||||
</setting-item>
|
||||
|
||||
<setting-item name="方式">
|
||||
<n-input size="small" :placeholder="targetData.request.requestHttpType || '暂无'" :disabled="true"></n-input>
|
||||
</setting-item>
|
||||
|
||||
<setting-item name="组件间隔">
|
||||
<n-input size="small" :placeholder="`${targetData.request.requestInterval || '暂无'}`" :disabled="true">
|
||||
<template #suffix> {{ SelectHttpTimeNameObj[targetData.request.requestIntervalUnit] }} </template>
|
||||
</n-input>
|
||||
</setting-item>
|
||||
|
||||
<setting-item name="全局间隔(默认)">
|
||||
<n-input size="small" :placeholder="`${GlobalRequestInterval || '暂无'} `" :disabled="true">
|
||||
<template #suffix> {{ SelectHttpTimeNameObj[GlobalRequestIntervalUnit] }} </template>
|
||||
</n-input>
|
||||
</setting-item>
|
||||
</setting-item-box>
|
||||
|
||||
<setting-item-box name="源地址" :alone="true">
|
||||
<n-input size="small" :placeholder="requestOriginUrl || '暂无'" :disabled="true">
|
||||
<template #prefix>
|
||||
<n-icon :component="PulseIcon" />
|
||||
</template>
|
||||
</n-input>
|
||||
</setting-item-box>
|
||||
|
||||
<setting-item-box name="组件地址" :alone="true">
|
||||
<n-input size="small" :placeholder="targetData.request.requestUrl || '暂无'" :disabled="true">
|
||||
<template #prefix>
|
||||
<n-icon :component="FlashIcon" />
|
||||
</template>
|
||||
</n-input>
|
||||
</setting-item-box>
|
||||
|
||||
<div class="edit-text" @click="requestModelHandle">
|
||||
<div class="go-absolute-center">
|
||||
<n-button type="primary" secondary>编辑配置</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<setting-item-box :alone="true">
|
||||
<template #name>
|
||||
测试
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="21" :depth="3">
|
||||
<help-outline-icon></help-outline-icon>
|
||||
</n-icon>
|
||||
</template>
|
||||
默认赋值给 dataset 字段
|
||||
</n-tooltip>
|
||||
</template>
|
||||
<n-button type="primary" ghost @click="sendHandle">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<flash-icon />
|
||||
</n-icon>
|
||||
</template>
|
||||
发送请求
|
||||
</n-button>
|
||||
</setting-item-box>
|
||||
|
||||
<!-- 底部数据展示 -->
|
||||
<chart-data-matching-and-show :show="showMatching && !loading" :ajax="true"></chart-data-matching-and-show>
|
||||
|
||||
<!-- 骨架图 -->
|
||||
<go-skeleton :load="loading" :repeat="3"></go-skeleton>
|
||||
|
||||
<!-- 请求配置model -->
|
||||
<chart-data-request
|
||||
v-model:modelShow="requestShow"
|
||||
:targetData="targetData"
|
||||
@sendHandle="sendHandle"
|
||||
></chart-data-request>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, toRefs, computed, onBeforeUnmount, watchEffect, toRaw } from 'vue'
|
||||
import { icon } from '@/plugins'
|
||||
import { useDesignStore } from '@/store/modules/designStore/designStore'
|
||||
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
|
||||
import { ChartDataRequest } from '../ChartDataRequest/index'
|
||||
import { RequestHttpEnum, ResultEnum, SelectHttpTimeNameObj, RequestContentTypeEnum } from '@/enums/httpEnum'
|
||||
import { chartDataUrl, rankListUrl, scrollBoardUrl, numberFloatUrl, numberIntUrl, textUrl, imageUrl } from '@/api/mock'
|
||||
import { http, customizeHttp } from '@/api/http'
|
||||
import { SelectHttpType } from '../../index.d'
|
||||
import { ChartDataMatchingAndShow } from '../ChartDataMatchingAndShow'
|
||||
import { useTargetData } from '../../../hooks/useTargetData.hook'
|
||||
import { newFunctionHandle } from '@/utils'
|
||||
|
||||
const { HelpOutlineIcon, FlashIcon, PulseIcon } = icon.ionicons5
|
||||
const { targetData, chartEditStore } = useTargetData()
|
||||
|
||||
const {
|
||||
requestOriginUrl,
|
||||
requestInterval: GlobalRequestInterval,
|
||||
requestIntervalUnit: GlobalRequestIntervalUnit
|
||||
} = toRefs(chartEditStore.getRequestGlobalConfig)
|
||||
const designStore = useDesignStore()
|
||||
|
||||
// 是否展示数据分析
|
||||
const loading = ref(false)
|
||||
const requestShow = ref(false)
|
||||
const showMatching = ref(false)
|
||||
|
||||
let firstFocus = 0
|
||||
let lastFilter: any = undefined
|
||||
|
||||
// 请求配置 model
|
||||
const requestModelHandle = () => {
|
||||
requestShow.value = true
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
const sendHandle = async () => {
|
||||
if (!targetData.value?.request) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.getRequestGlobalConfig))
|
||||
loading.value = false
|
||||
if (res) {
|
||||
if (!res?.data && !targetData.value.filter) window['$message'].warning('您的数据不符合默认格式,请配置过滤器!')
|
||||
targetData.value.option.dataset = newFunctionHandle(res?.data, res, targetData.value.filter)
|
||||
showMatching.value = true
|
||||
return
|
||||
}
|
||||
window['$message'].warning('没有拿到返回值,请检查接口!')
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
loading.value = false
|
||||
window['$message'].warning('数据异常,请检查参数!')
|
||||
}
|
||||
}
|
||||
|
||||
// 颜色
|
||||
const themeColor = computed(() => {
|
||||
return designStore.getAppTheme
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
const filter = targetData.value?.filter
|
||||
if (lastFilter !== filter && firstFocus) {
|
||||
lastFilter = filter
|
||||
sendHandle()
|
||||
}
|
||||
firstFocus++
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
lastFilter = null
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@include go('chart-configurations-data-ajax') {
|
||||
.n-card-shallow {
|
||||
&.n-card {
|
||||
@extend .go-background-filter;
|
||||
@include deep() {
|
||||
.n-card__content {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-text {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 325px;
|
||||
height: 270px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: all 0.3s;
|
||||
@extend .go-background-filter;
|
||||
backdrop-filter: blur(2px) !important;
|
||||
}
|
||||
&:hover {
|
||||
border-color: v-bind('themeColor');
|
||||
.edit-text {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="go-chart-configurations-data-ajax">
|
||||
<n-card class="n-card-shallow">
|
||||
<setting-item-box name="请求配置">
|
||||
<setting-item name="类型">
|
||||
<n-tag :bordered="false" type="primary" style="border-radius: 5px">
|
||||
{{ targetData.request.requestContentType === RequestContentTypeEnum.DEFAULT ? '普通请求' : 'SQL请求' }}
|
||||
</n-tag>
|
||||
</setting-item>
|
||||
|
||||
<setting-item name="方式">
|
||||
<n-input size="small" :placeholder="targetData.request.requestHttpType || '暂无'" :disabled="true"></n-input>
|
||||
</setting-item>
|
||||
|
||||
<setting-item name="组件间隔">
|
||||
<n-input size="small" :placeholder="`${targetData.request.requestInterval || '暂无'}`" :disabled="true">
|
||||
<template #suffix> {{ SelectHttpTimeNameObj[targetData.request.requestIntervalUnit] }} </template>
|
||||
</n-input>
|
||||
</setting-item>
|
||||
|
||||
<setting-item name="全局间隔(默认)">
|
||||
<n-input size="small" :placeholder="`${GlobalRequestInterval || '暂无'} `" :disabled="true">
|
||||
<template #suffix> {{ SelectHttpTimeNameObj[GlobalRequestIntervalUnit] }} </template>
|
||||
</n-input>
|
||||
</setting-item>
|
||||
</setting-item-box>
|
||||
|
||||
<setting-item-box name="源地址" :alone="true">
|
||||
<n-input size="small" :placeholder="requestOriginUrl || '暂无'" :disabled="true">
|
||||
<template #prefix>
|
||||
<n-icon :component="PulseIcon" />
|
||||
</template>
|
||||
</n-input>
|
||||
</setting-item-box>
|
||||
|
||||
<setting-item-box name="组件地址" :alone="true">
|
||||
<n-input size="small" :placeholder="targetData.request.requestUrl || '暂无'" :disabled="true">
|
||||
<template #prefix>
|
||||
<n-icon :component="FlashIcon" />
|
||||
</template>
|
||||
</n-input>
|
||||
</setting-item-box>
|
||||
|
||||
<div class="edit-text" @click="requestModelHandle">
|
||||
<div class="go-absolute-center">
|
||||
<n-button type="primary" secondary>编辑配置</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<setting-item-box :alone="true">
|
||||
<template #name>
|
||||
测试
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="21" :depth="3">
|
||||
<help-outline-icon></help-outline-icon>
|
||||
</n-icon>
|
||||
</template>
|
||||
默认赋值给 dataset 字段
|
||||
</n-tooltip>
|
||||
</template>
|
||||
<n-button type="primary" ghost @click="sendHandle">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<flash-icon />
|
||||
</n-icon>
|
||||
</template>
|
||||
发送请求
|
||||
</n-button>
|
||||
</setting-item-box>
|
||||
|
||||
<!-- 底部数据展示 -->
|
||||
<chart-data-matching-and-show :show="showMatching && !loading" :ajax="true"></chart-data-matching-and-show>
|
||||
|
||||
<!-- 骨架图 -->
|
||||
<go-skeleton :load="loading" :repeat="3"></go-skeleton>
|
||||
|
||||
<!-- 请求配置model -->
|
||||
<chart-data-request
|
||||
v-model:modelShow="requestShow"
|
||||
:targetData="targetData"
|
||||
@sendHandle="sendHandle"
|
||||
></chart-data-request>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, toRefs, computed, onBeforeUnmount, watchEffect, toRaw } from 'vue'
|
||||
import { icon } from '@/plugins'
|
||||
import { useDesignStore } from '@/store/modules/designStore/designStore'
|
||||
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
|
||||
import { ChartDataRequest } from '../ChartDataRequest/index'
|
||||
import { RequestHttpEnum, ResultEnum, SelectHttpTimeNameObj, RequestContentTypeEnum } from '@/enums/httpEnum'
|
||||
import { chartDataUrl, rankListUrl, scrollBoardUrl, numberFloatUrl, numberIntUrl, textUrl, imageUrl } from '@/api/mock'
|
||||
import { http, customizeHttp } from '@/api/http'
|
||||
import { SelectHttpType } from '../../index.d'
|
||||
import { ChartDataMatchingAndShow } from '../ChartDataMatchingAndShow'
|
||||
import { useTargetData } from '../../../hooks/useTargetData.hook'
|
||||
import { newFunctionHandle } from '@/utils'
|
||||
|
||||
const { HelpOutlineIcon, FlashIcon, PulseIcon } = icon.ionicons5
|
||||
const { targetData, chartEditStore } = useTargetData()
|
||||
|
||||
const {
|
||||
requestOriginUrl,
|
||||
requestInterval: GlobalRequestInterval,
|
||||
requestIntervalUnit: GlobalRequestIntervalUnit
|
||||
} = toRefs(chartEditStore.getRequestGlobalConfig)
|
||||
const designStore = useDesignStore()
|
||||
|
||||
// 是否展示数据分析
|
||||
const loading = ref(false)
|
||||
const requestShow = ref(false)
|
||||
const showMatching = ref(false)
|
||||
|
||||
let firstFocus = 0
|
||||
let lastFilter: any = undefined
|
||||
|
||||
// 请求配置 model
|
||||
const requestModelHandle = () => {
|
||||
requestShow.value = true
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
const sendHandle = async () => {
|
||||
if (!targetData.value?.request) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.getRequestGlobalConfig))
|
||||
loading.value = false
|
||||
if (res) {
|
||||
const { data } = res
|
||||
if (!data && !targetData.value.filter) window['$message'].warning('您的数据不符合默认格式,请配置过滤器!')
|
||||
targetData.value.option.dataset = newFunctionHandle(data, res, targetData.value.filter)
|
||||
showMatching.value = true
|
||||
return
|
||||
}
|
||||
window['$message'].warning('没有拿到返回值,请检查接口!')
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
loading.value = false
|
||||
window['$message'].warning('数据异常,请检查参数!')
|
||||
}
|
||||
}
|
||||
|
||||
// 颜色
|
||||
const themeColor = computed(() => {
|
||||
return designStore.getAppTheme
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
const filter = targetData.value?.filter
|
||||
if (lastFilter !== filter && firstFocus) {
|
||||
lastFilter = filter
|
||||
sendHandle()
|
||||
}
|
||||
firstFocus++
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
lastFilter = null
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@include go('chart-configurations-data-ajax') {
|
||||
.n-card-shallow {
|
||||
&.n-card {
|
||||
@extend .go-background-filter;
|
||||
@include deep() {
|
||||
.n-card__content {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-text {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 325px;
|
||||
height: 270px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: all 0.3s;
|
||||
@extend .go-background-filter;
|
||||
backdrop-filter: blur(2px) !important;
|
||||
}
|
||||
&:hover {
|
||||
border-color: v-bind('themeColor');
|
||||
.edit-text {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,215 +1,215 @@
|
||||
<template>
|
||||
<template v-if="targetData.filter">
|
||||
<n-card>
|
||||
<p><span class="func-keyword">function</span> filter(data, res) {</p>
|
||||
<!-- 函数体 -->
|
||||
<div class="go-ml-4">
|
||||
<n-code :code="targetData.filter" language="typescript"></n-code>
|
||||
</div>
|
||||
<p>}</p>
|
||||
<template #footer>
|
||||
<n-space justify="end">
|
||||
<n-button type="primary" tertiary size="small" @click="addFilter">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<filter-edit-icon />
|
||||
</n-icon>
|
||||
</template>
|
||||
编辑
|
||||
</n-button>
|
||||
<n-button tertiary size="small" @click="delFilter"> 删除 </n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-card>
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-button class="go-ml-3" @click="addFilter">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<filter-icon />
|
||||
</n-icon>
|
||||
</template>
|
||||
新增过滤器
|
||||
</n-button>
|
||||
</template>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<n-modal class="go-chart-data-monaco-editor" v-model:show="showModal" :mask-closable="false" :closeOnEsc="false">
|
||||
<n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1000px; height: 600px">
|
||||
<template #header>
|
||||
<n-space>
|
||||
<n-text>过滤器函数编辑器</n-text>
|
||||
</n-space>
|
||||
</template>
|
||||
<template #header-extra> </template>
|
||||
<n-space size="small" vertical>
|
||||
<n-space justify="space-between">
|
||||
<div>
|
||||
<n-space vertical>
|
||||
<n-tag type="info">
|
||||
<span class="func-keyword">function</span> filter(data, res) {
|
||||
</n-tag>
|
||||
<monaco-editor v-model:modelValue="filter" width="460px" height="380px" language="javascript" />
|
||||
<n-tag type="info">}</n-tag>
|
||||
</n-space>
|
||||
</div>
|
||||
<n-divider vertical style="height: 480px" />
|
||||
<n-scrollbar style="max-height: 480px">
|
||||
<n-space :size="15" vertical>
|
||||
<div class="editor-data-show">
|
||||
<n-space>
|
||||
<n-text depth="3">默认过滤数据(data):</n-text>
|
||||
<n-code :code="toString(sourceData?.data) || '暂无'" language="json" :word-wrap="true"></n-code>
|
||||
</n-space>
|
||||
</div>
|
||||
<div class="editor-data-show">
|
||||
<n-space>
|
||||
<n-text depth="3">接口返回数据(res):</n-text>
|
||||
<n-code :code="toString(sourceData) || '暂无'" language="json" :word-wrap="true"></n-code>
|
||||
</n-space>
|
||||
</div>
|
||||
<div class="editor-data-show">
|
||||
<n-space>
|
||||
<n-text depth="3">过滤器结果:</n-text>
|
||||
<n-code :code="filterRes || '暂无'" language="json" :word-wrap="true"></n-code>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-space>
|
||||
</n-scrollbar>
|
||||
</n-space>
|
||||
</n-space>
|
||||
<template #action>
|
||||
<n-space justify="space-between">
|
||||
<div class="go-flex-items-center">
|
||||
<n-tag :bordered="false" type="primary">
|
||||
<template #icon>
|
||||
<n-icon :component="DocumentTextIcon" />
|
||||
</template>
|
||||
规则
|
||||
</n-tag>
|
||||
<n-text class="go-ml-2" depth="2">过滤器默认处理接口返回值的「data」字段</n-text>
|
||||
</div>
|
||||
|
||||
<n-space>
|
||||
<n-button size="medium" @click="closeFilter">取消</n-button>
|
||||
<n-button size="medium" type="primary" @click="saveFilter">保存</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, toRef, toRefs, toRaw, reactive } from 'vue'
|
||||
import { useTargetData } from '../../../hooks/useTargetData.hook'
|
||||
import { MonacoEditor } from '@/components/Pages/MonacoEditor'
|
||||
import { icon } from '@/plugins'
|
||||
import { goDialog, toString } from '@/utils'
|
||||
import { customizeHttp } from '@/api/http'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
const { DocumentTextIcon } = icon.ionicons5
|
||||
const { FilterIcon, FilterEditIcon } = icon.carbon
|
||||
const { targetData, chartEditStore } = useTargetData()
|
||||
const { requestDataType } = toRefs(targetData.value.request)
|
||||
const { requestOriginUrl } = toRefs(chartEditStore.getRequestGlobalConfig)
|
||||
|
||||
// 受控弹窗
|
||||
const showModal = ref(false)
|
||||
// filter 函数模板
|
||||
const filter = ref(targetData.value.filter || `return data`)
|
||||
// 过滤错误标识
|
||||
const errorFlag = ref(false)
|
||||
// 目标静态/接口数据
|
||||
const sourceData = ref<any>('')
|
||||
|
||||
// 动态获取数据
|
||||
const fetchTargetData = async () => {
|
||||
try {
|
||||
const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.getRequestGlobalConfig))
|
||||
if (res) {
|
||||
sourceData.value = res
|
||||
return
|
||||
}
|
||||
window['$message'].warning('没有拿到返回值,请检查接口!')
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
window['$message'].warning('数据异常,请检查参数!')
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤结果
|
||||
const filterRes = computed(() => {
|
||||
try {
|
||||
const fn = new Function('data', 'res', filter.value)
|
||||
const response = cloneDeep(sourceData.value)
|
||||
const res = fn(response?.data, response)
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
errorFlag.value = false
|
||||
return toString(res)
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
errorFlag.value = true
|
||||
return `过滤函数错误,日志:${error}`
|
||||
}
|
||||
})
|
||||
|
||||
// 新增过滤器
|
||||
const addFilter = () => {
|
||||
showModal.value = true
|
||||
}
|
||||
|
||||
// 删除过滤器
|
||||
const delFilter = () => {
|
||||
goDialog({
|
||||
message: '是否删除过滤器',
|
||||
onPositiveCallback: () => {
|
||||
targetData.value.filter = undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭过滤器
|
||||
const closeFilter = () => {
|
||||
showModal.value = false
|
||||
}
|
||||
|
||||
// 新增过滤器
|
||||
const saveFilter = () => {
|
||||
if (errorFlag.value) {
|
||||
window['$message'].error('过滤函数错误,无法进行保存')
|
||||
return
|
||||
}
|
||||
targetData.value.filter = filter.value
|
||||
closeFilter()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => showModal.value,
|
||||
(newData: boolean) => {
|
||||
if (newData) {
|
||||
fetchTargetData()
|
||||
filter.value = targetData.value.filter || `return data`
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.func-keyword {
|
||||
color: #b478cf;
|
||||
}
|
||||
@include go('chart-data-monaco-editor') {
|
||||
&.n-card.n-modal,
|
||||
.n-card {
|
||||
@extend .go-background-filter;
|
||||
}
|
||||
.editor-data-show {
|
||||
@include fetch-bg-color('filter-color');
|
||||
width: 420px;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<template v-if="targetData.filter">
|
||||
<n-card>
|
||||
<p><span class="func-keyword">function</span> filter(data, res) {</p>
|
||||
<!-- 函数体 -->
|
||||
<div class="go-ml-4">
|
||||
<n-code :code="targetData.filter" language="typescript"></n-code>
|
||||
</div>
|
||||
<p>}</p>
|
||||
<template #footer>
|
||||
<n-space justify="end">
|
||||
<n-button type="primary" tertiary size="small" @click="addFilter">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<filter-edit-icon />
|
||||
</n-icon>
|
||||
</template>
|
||||
编辑
|
||||
</n-button>
|
||||
<n-button tertiary size="small" @click="delFilter"> 删除 </n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-card>
|
||||
</template>
|
||||
<template v-else>
|
||||
<n-button class="go-ml-3" @click="addFilter">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<filter-icon />
|
||||
</n-icon>
|
||||
</template>
|
||||
新增过滤器
|
||||
</n-button>
|
||||
</template>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<n-modal class="go-chart-data-monaco-editor" v-model:show="showModal" :mask-closable="false" :closeOnEsc="false">
|
||||
<n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 1000px; height: 600px">
|
||||
<template #header>
|
||||
<n-space>
|
||||
<n-text>过滤器函数编辑器</n-text>
|
||||
</n-space>
|
||||
</template>
|
||||
<template #header-extra> </template>
|
||||
<n-space size="small" vertical>
|
||||
<n-space justify="space-between">
|
||||
<div>
|
||||
<n-space vertical>
|
||||
<n-tag type="info">
|
||||
<span class="func-keyword">function</span> filter(data, res) {
|
||||
</n-tag>
|
||||
<monaco-editor v-model:modelValue="filter" width="460px" height="380px" language="javascript" />
|
||||
<n-tag type="info">}</n-tag>
|
||||
</n-space>
|
||||
</div>
|
||||
<n-divider vertical style="height: 480px" />
|
||||
<n-scrollbar style="max-height: 480px">
|
||||
<n-space :size="15" vertical>
|
||||
<div class="editor-data-show">
|
||||
<n-space>
|
||||
<n-text depth="3">默认过滤数据(data):</n-text>
|
||||
<n-code :code="toString(sourceData?.data) || '暂无'" language="json" :word-wrap="true"></n-code>
|
||||
</n-space>
|
||||
</div>
|
||||
<div class="editor-data-show">
|
||||
<n-space>
|
||||
<n-text depth="3">接口返回数据(res):</n-text>
|
||||
<n-code :code="toString(sourceData) || '暂无'" language="json" :word-wrap="true"></n-code>
|
||||
</n-space>
|
||||
</div>
|
||||
<div class="editor-data-show">
|
||||
<n-space>
|
||||
<n-text depth="3">过滤器结果:</n-text>
|
||||
<n-code :code="filterRes || '暂无'" language="json" :word-wrap="true"></n-code>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-space>
|
||||
</n-scrollbar>
|
||||
</n-space>
|
||||
</n-space>
|
||||
<template #action>
|
||||
<n-space justify="space-between">
|
||||
<div class="go-flex-items-center">
|
||||
<n-tag :bordered="false" type="primary">
|
||||
<template #icon>
|
||||
<n-icon :component="DocumentTextIcon" />
|
||||
</template>
|
||||
规则
|
||||
</n-tag>
|
||||
<n-text class="go-ml-2" depth="2">过滤器默认处理接口返回值的「data」字段</n-text>
|
||||
</div>
|
||||
|
||||
<n-space>
|
||||
<n-button size="medium" @click="closeFilter">取消</n-button>
|
||||
<n-button size="medium" type="primary" @click="saveFilter">保存</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, toRef, toRefs, toRaw, reactive } from 'vue'
|
||||
import { useTargetData } from '../../../hooks/useTargetData.hook'
|
||||
import { MonacoEditor } from '@/components/Pages/MonacoEditor'
|
||||
import { icon } from '@/plugins'
|
||||
import { goDialog, toString } from '@/utils'
|
||||
import { customizeHttp } from '@/api/http'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
const { DocumentTextIcon } = icon.ionicons5
|
||||
const { FilterIcon, FilterEditIcon } = icon.carbon
|
||||
const { targetData, chartEditStore } = useTargetData()
|
||||
const { requestDataType } = toRefs(targetData.value.request)
|
||||
const { requestOriginUrl } = toRefs(chartEditStore.getRequestGlobalConfig)
|
||||
|
||||
// 受控弹窗
|
||||
const showModal = ref(false)
|
||||
// filter 函数模板
|
||||
const filter = ref(targetData.value.filter || `return data`)
|
||||
// 过滤错误标识
|
||||
const errorFlag = ref(false)
|
||||
// 目标静态/接口数据
|
||||
const sourceData = ref<any>('')
|
||||
|
||||
// 动态获取数据
|
||||
const fetchTargetData = async () => {
|
||||
try {
|
||||
const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.getRequestGlobalConfig))
|
||||
if (res) {
|
||||
sourceData.value = res
|
||||
return
|
||||
}
|
||||
window['$message'].warning('没有拿到返回值,请检查接口!')
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
window['$message'].warning('数据异常,请检查参数!')
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤结果
|
||||
const filterRes = computed(() => {
|
||||
try {
|
||||
const fn = new Function('data', 'res', filter.value)
|
||||
const response = cloneDeep(sourceData.value)
|
||||
const res = fn(response?.data, response)
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
errorFlag.value = false
|
||||
return toString(res)
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
errorFlag.value = true
|
||||
return `过滤函数错误,日志:${error}`
|
||||
}
|
||||
})
|
||||
|
||||
// 新增过滤器
|
||||
const addFilter = () => {
|
||||
showModal.value = true
|
||||
}
|
||||
|
||||
// 删除过滤器
|
||||
const delFilter = () => {
|
||||
goDialog({
|
||||
message: '是否删除过滤器',
|
||||
onPositiveCallback: () => {
|
||||
targetData.value.filter = undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭过滤器
|
||||
const closeFilter = () => {
|
||||
showModal.value = false
|
||||
}
|
||||
|
||||
// 新增过滤器
|
||||
const saveFilter = () => {
|
||||
if (errorFlag.value) {
|
||||
window['$message'].error('过滤函数错误,无法进行保存')
|
||||
return
|
||||
}
|
||||
targetData.value.filter = filter.value
|
||||
closeFilter()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => showModal.value,
|
||||
(newData: boolean) => {
|
||||
if (newData) {
|
||||
fetchTargetData()
|
||||
filter.value = targetData.value.filter || `return data`
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.func-keyword {
|
||||
color: #b478cf;
|
||||
}
|
||||
@include go('chart-data-monaco-editor') {
|
||||
&.n-card.n-modal,
|
||||
.n-card {
|
||||
@extend .go-background-filter;
|
||||
}
|
||||
.editor-data-show {
|
||||
@include fetch-bg-color('filter-color');
|
||||
width: 420px;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -65,6 +65,7 @@ import { RequestHeader } from '../RequestHeader'
|
||||
import { isDev } from '@/utils'
|
||||
import { icon } from '@/plugins'
|
||||
import {
|
||||
graphUrl,
|
||||
chartDataUrl,
|
||||
chartSingleDataUrl,
|
||||
rankListUrl,
|
||||
@@ -80,7 +81,8 @@ import {
|
||||
capsuleUrl,
|
||||
wordCloudUrl,
|
||||
treemapUrl,
|
||||
threeEarth01Url
|
||||
threeEarth01Url,
|
||||
sankeyUrl
|
||||
} from '@/api/mock'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -142,6 +144,12 @@ const apiList = [
|
||||
},
|
||||
{
|
||||
value: `【三维地球】${threeEarth01Url}`
|
||||
},
|
||||
{
|
||||
value: `【桑基图】${sankeyUrl}`
|
||||
},
|
||||
{
|
||||
value: `【关系图】${graphUrl}`
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
@@ -25,6 +25,11 @@ export const syncData = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 同步数据到预览页
|
||||
export const syncDataToPreview = () => {
|
||||
dispatchEvent(new CustomEvent(SavePageEnum.CHART_TO_PREVIEW, { detail: chartEditStore.getStorageInfo }))
|
||||
}
|
||||
|
||||
// 侦听器更新
|
||||
const useSyncUpdateHandle = () => {
|
||||
// 定义侦听器变量
|
||||
@@ -49,8 +54,8 @@ const useSyncUpdateHandle = () => {
|
||||
// document.hasFocus() && syncData()
|
||||
// }, editToJsonInterval)
|
||||
|
||||
// 失焦同步数据(暂不开启)
|
||||
// addEventListener('blur', syncData)
|
||||
// 失焦同步数据
|
||||
addEventListener('blur', syncDataToPreview)
|
||||
|
||||
// 监听编辑器保存事件 刷新工作台图表
|
||||
addEventListener(SavePageEnum.JSON, updateFn)
|
||||
@@ -62,7 +67,7 @@ const useSyncUpdateHandle = () => {
|
||||
// 关闭侦听
|
||||
const unUse = () => {
|
||||
// clearInterval(timer)
|
||||
// removeEventListener('blur', syncData)
|
||||
removeEventListener('blur', syncDataToPreview)
|
||||
removeEventListener(SavePageEnum.JSON, updateFn)
|
||||
}
|
||||
|
||||
|
||||
@@ -322,6 +322,15 @@ $asideBottom: 70px;
|
||||
border-radius: 25px;
|
||||
}
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
bottom: -10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
/* 最小化 */
|
||||
&.isMini {
|
||||
@@ -348,6 +357,7 @@ $asideBottom: 70px;
|
||||
50% {
|
||||
opacity: 0;
|
||||
bottom: calc(#{$dockMiniBottom} - 10px);
|
||||
pointer-events: none;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
@@ -362,15 +372,6 @@ $asideBottom: 70px;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
bottom: -20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<!-- 模块展示按钮 -->
|
||||
<n-tooltip v-for="item in btnList" :key="item.key" placement="bottom" trigger="hover">
|
||||
<template #trigger>
|
||||
<n-button size="small" ghost :type="styleHandle(item)" @click="clickHandle(item)">
|
||||
<n-button size="small" ghost :type="styleHandle(item)" :focusable="false" @click="clickHandle(item)">
|
||||
<component :is="item.icon"></component>
|
||||
</n-button>
|
||||
</template>
|
||||
|
||||
@@ -294,10 +294,17 @@ export const useSync = () => {
|
||||
const uploadRes = await uploadFile(uploadParams)
|
||||
// 保存预览图
|
||||
if(uploadRes && uploadRes.code === ResultEnum.SUCCESS) {
|
||||
await updateProjectApi({
|
||||
id: fetchRouteParamsLocation(),
|
||||
indexImage: `${systemStore.getFetchInfo.OSSUrl}${uploadRes.data.fileName}`
|
||||
})
|
||||
if (uploadRes.data.fileurl) {
|
||||
await updateProjectApi({
|
||||
id: fetchRouteParamsLocation(),
|
||||
indexImage: `${uploadRes.data.fileurl}`
|
||||
})
|
||||
} else {
|
||||
await updateProjectApi({
|
||||
id: fetchRouteParamsLocation(),
|
||||
indexImage: `${systemStore.getFetchInfo.OSSUrl}${uploadRes.data.fileName}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
<n-form-item path="username">
|
||||
<n-input
|
||||
v-model:value="formInline.username"
|
||||
type="text"
|
||||
maxlength="16"
|
||||
:placeholder="$t('global.form_account')"
|
||||
>
|
||||
<template #prefix>
|
||||
@@ -72,6 +74,7 @@
|
||||
<n-input
|
||||
v-model:value="formInline.password"
|
||||
type="password"
|
||||
maxlength="16"
|
||||
show-password-on="click"
|
||||
:placeholder="$t('global.form_password')"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
:class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`"
|
||||
>
|
||||
<div :class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`">
|
||||
<template v-if="showEntity">
|
||||
<!-- 实体区域 -->
|
||||
<div ref="entityRef" class="go-preview-entity">
|
||||
@@ -31,38 +29,32 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { PreviewRenderList } from './components/PreviewRenderList'
|
||||
import { getFilterStyle, routerTurnByName, setTitle } from '@/utils'
|
||||
import { getFilterStyle, setTitle } from '@/utils'
|
||||
import { getEditCanvasConfigStyle, getSessionStorageInfo } from './utils'
|
||||
import { PageEnum } from '@/enums/pageEnum'
|
||||
import { useComInstall } from './hooks/useComInstall.hook'
|
||||
import { useScale } from './hooks/useScale.hook'
|
||||
import { useStore } from './hooks/useStore.hook'
|
||||
import { PreviewScaleEnum } from '@/enums/styleEnum'
|
||||
import { useComInstall } from './hooks/useComInstall.hook'
|
||||
import type { ChartEditStorageType } from './index.d'
|
||||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||
|
||||
// const localStorageInfo: ChartEditStorageType = getSessionStorageInfo() as ChartEditStorageType
|
||||
|
||||
await getSessionStorageInfo()
|
||||
const chartEditStore = useChartEditStore() as unknown as ChartEditStorageType
|
||||
|
||||
setTitle(`预览-${chartEditStore.editCanvasConfig.projectName}`)
|
||||
|
||||
// @ts-ignore
|
||||
if(chartEditStore.isRelease === false) {
|
||||
routerTurnByName(PageEnum.REDIRECT_UN_PUBLISH_NAME, true, false)
|
||||
}
|
||||
|
||||
const previewRefStyle = computed(() => {
|
||||
return {
|
||||
...getEditCanvasConfigStyle(chartEditStore.editCanvasConfig),
|
||||
...getFilterStyle(chartEditStore.editCanvasConfig.filterShow ? chartEditStore.editCanvasConfig : undefined),
|
||||
...getFilterStyle(chartEditStore.editCanvasConfig)
|
||||
}
|
||||
})
|
||||
|
||||
const showEntity = computed(() => {
|
||||
const type = chartEditStore.editCanvasConfig.previewScaleType
|
||||
return (
|
||||
type === PreviewScaleEnum.SCROLL_Y || type === PreviewScaleEnum.SCROLL_X
|
||||
)
|
||||
return type === PreviewScaleEnum.SCROLL_Y || type === PreviewScaleEnum.SCROLL_X
|
||||
})
|
||||
|
||||
useStore(chartEditStore)
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
<template>
|
||||
<preview :key="key"></preview>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getSessionStorageInfo } from './utils'
|
||||
import type { ChartEditStorageType } from './index.d'
|
||||
import { SavePageEnum } from '@/enums/editPageEnum'
|
||||
import { setSessionStorage } from '@/utils'
|
||||
import { StorageEnum } from '@/enums/storageEnum'
|
||||
import { ref } from 'vue'
|
||||
import Preview from './index.vue'
|
||||
|
||||
let key = ref(Date.now())
|
||||
|
||||
// 数据变更 -> 组件销毁重建
|
||||
;[SavePageEnum.JSON, SavePageEnum.CHART].forEach((saveEvent: string) => {
|
||||
if (!window.opener) 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 }])
|
||||
key.value = Date.now()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<preview :key="key"></preview>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getSessionStorageInfo } from './utils'
|
||||
import type { ChartEditStorageType } from './index.d'
|
||||
import { SavePageEnum } from '@/enums/editPageEnum'
|
||||
import { setSessionStorage } from '@/utils'
|
||||
import { StorageEnum } from '@/enums/storageEnum'
|
||||
import { ref } from 'vue'
|
||||
import Preview from './index.vue'
|
||||
|
||||
let key = ref(Date.now())
|
||||
|
||||
// 数据变更 -> 组件销毁重建
|
||||
;[SavePageEnum.JSON, SavePageEnum.CHART_TO_PREVIEW].forEach((saveEvent: string) => {
|
||||
if (!window.opener) 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 }])
|
||||
key.value = Date.now()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -124,22 +124,6 @@ const selectOptions = ref([
|
||||
key: 'preview',
|
||||
icon: renderIcon(BrowsersOutlineIcon)
|
||||
},
|
||||
{
|
||||
label: renderLang('global.r_copy'),
|
||||
key: 'copy',
|
||||
icon: renderIcon(CopyIcon),
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
label: renderLang('global.r_rename'),
|
||||
key: 'rename',
|
||||
icon: renderIcon(PencilIcon),
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
key: 'd1'
|
||||
},
|
||||
{
|
||||
label: props.cardData?.release
|
||||
? renderLang('global.r_unpublish')
|
||||
@@ -147,15 +131,9 @@ const selectOptions = ref([
|
||||
key: 'release',
|
||||
icon: renderIcon(SendIcon)
|
||||
},
|
||||
{
|
||||
label: renderLang('global.r_download'),
|
||||
key: 'download',
|
||||
icon: renderIcon(DownloadIcon),
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
key: 'd2'
|
||||
key: 'd1'
|
||||
},
|
||||
{
|
||||
label: renderLang('global.r_delete'),
|
||||
|
||||
@@ -45,8 +45,7 @@ const collapsed = ref<boolean>(false)
|
||||
const { getAsideCollapsedWidth } = toRefs(useSettingStore())
|
||||
|
||||
const route = useRoute()
|
||||
const routeRame = computed(() => route.name)
|
||||
const menuValue = ref(routeRame)
|
||||
const menuValue = computed(() => route.name)
|
||||
|
||||
const menuOptions = menuOptionsInit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user