Compare commits

...

5 Commits

Author SHA1 Message Date
奔跑的面条
d6f15b48c7 perf: 优化顶部展示 2023-03-04 17:31:49 +08:00
奔跑的面条
3bd87d7b25 perf: 优化轮播组件 2023-03-04 17:05:07 +08:00
奔跑的面条
c16c9c6593 !131 feat: 新增轮播图组件
Merge pull request !131 from Ryker/dev
2023-03-04 17:02:56 +08:00
奔跑的面条
aac377fe6d !133 解决adcode类型不正确可能导致的问题
Merge pull request !133 from wallellen/master-fetch-dev
2023-03-04 16:18:08 +08:00
奔跑的面条
62e3d92ed5 perf: 优化 JSONParse 过滤函数值表达式写法 2023-03-04 14:18:17 +08:00
10 changed files with 344 additions and 18 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -7,15 +7,15 @@ export enum BaseEvent {
// 移入
ON_MOUSE_ENTER = 'mouseenter',
// 移出
ON_MOUSE_LEAVE = 'mouseleave',
ON_MOUSE_LEAVE = 'mouseleave'
}
// vue3 生命周期事件
export enum EventLife {
export enum EventLife {
// 渲染之后
VNODE_MOUNTED = 'vnodeMounted',
// 渲染之前
VNODE_BEFORE_MOUNT = 'vnodeBeforeMount',
VNODE_BEFORE_MOUNT = 'vnodeBeforeMount'
}
// 内置字符串函数对象列表
@ -28,4 +28,9 @@ export const excludeParseEventKeyList = [
BaseEvent.ON_MOUSE_LEAVE,
//过滤器
'filter'
]
]
// 内置字符串函数键值列表
export const excludeParseEventValueList = [
// 请求里的函数语句
'javascript:'
]

View File

@ -1,6 +1,6 @@
<template>
<n-layout-header bordered class="go-header">
<header class="go-header-box">
<header class="go-header-box" :class="{ 'is-project': isProject }">
<div class="header-item left">
<n-space>
<slot name="left"></slot>
@ -23,9 +23,18 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { GoThemeSelect } from '@/components/GoThemeSelect'
import { GoLangSelect } from '@/components/GoLangSelect'
import { ThemeColorSelect } from '@/components/Pages/ThemeColorSelect'
import { PageEnum } from '@/enums/pageEnum'
const route = useRoute()
const isProject = computed(() => {
return route.fullPath === PageEnum.BASE_HOME_ITEMS
})
</script>
<style lang="scss" scoped>
@ -33,7 +42,10 @@ $min-width: 520px;
@include go(header) {
&-box {
display: grid;
grid-template-columns: repeat(3, 33.33%);
grid-template-columns: repeat(3, 33%);
&.is-project {
grid-template-columns: none;
}
.header-item {
display: flex;
align-items: center;
@ -49,7 +61,7 @@ $min-width: 520px;
}
}
height: $--header-height;
padding: 0 60px;
padding: 0 20px 0 60px;
}
}
</style>

View File

@ -59,13 +59,14 @@ const getGeojson = (regionId: string) => {
}
//
registerMap(props.chartConfig.option.mapRegion.adcode, { geoJSON: {} as any, specialAreas: {} })
registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any, specialAreas: {} })
// china
const registerMapInitAsync = async () => {
await nextTick()
if (props.chartConfig.option.mapRegion.adcode != 'china') {
await getGeojson(props.chartConfig.option.mapRegion.adcode)
const adCode = `${props.chartConfig.option.mapRegion.adcode}`;
if (adCode !== 'china') {
await getGeojson(adCode)
} else {
await hainanLandsHandle(props.chartConfig.option.mapRegion.showHainanIsLands)
}
@ -127,7 +128,7 @@ watch(
//
watch(
() => props.chartConfig.option.mapRegion.adcode,
() => `${props.chartConfig.option.mapRegion.adcode}`,
async newData => {
try {
await getGeojson(newData)

View File

@ -0,0 +1,44 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { ImageCarouselConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
import logo from '@/assets/logo.png'
export const option = {
// 图片资源列表
dataset: [
'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg',
'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel2.jpeg',
'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel3.jpeg',
],
// 自动播放
autoplay: true,
// 自动播放的间隔(豪秒)
interval: 5000,
// 每页显示的图片数量
slidesPerview: 1,
// 轮播方向
direction: "horizontal",
// 拖曳切换
draggable: true,
// 居中显示
centeredSlides: false,
// 过渡效果
effect: "slide",
// 是否显示指示点
showDots: true,
// 指示器样式
dotType: "dot",
// 指示器位置
dotPlacement: "bottom",
// 显示箭头
showArrow: false,
// 图片样式
fit: "contain",
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = ImageCarouselConfig.key
public chartConfig = cloneDeep(ImageCarouselConfig)
public option = cloneDeep(option)
}

View File

@ -0,0 +1,168 @@
<template>
<collapse-item name="路径" :expanded="true">
<setting-item v-for="(item, index) in optionData.dataset" :key="index">
<n-input-group>
<n-input v-model:value="optionData.dataset[index]" size="small" placeholder="请输入图片地址"></n-input>
<n-button ghost @click="optionData.dataset.splice(index, 1)"> - </n-button>
</n-input-group>
</setting-item>
<setting-item>
<n-button size="small" @click="optionData.dataset.push('')"> + 新增</n-button>
</setting-item>
</collapse-item>
<collapse-item name="轮播属性" :expanded="true">
<setting-item-box name="播放器">
<setting-item>
<n-space>
<n-switch v-model:value="optionData.autoplay" size="small" />
<n-text>自动播放</n-text>
</n-space>
</setting-item>
<!-- 开启自动播放时设置间隔时间 -->
<setting-item name="间隔时间">
<n-input-number v-model:value="optionData.interval" size="small" placeholder="">
<template #suffix> 毫秒 </template>
</n-input-number>
</setting-item>
<setting-item name="轮播方向">
<n-select v-model:value="optionData.direction" :options="directions" placeholder="选择方向" />
</setting-item>
<setting-item name="过渡效果">
<n-select v-model:value="optionData.effect" :options="effects" placeholder="效果" />
</setting-item>
<setting-item name="每页数量">
<n-input-number v-model:value="optionData.slidesPerview" size="small" placeholder=""></n-input-number>
</setting-item>
<setting-item>
<n-space>
<n-switch v-model:value="optionData.centeredSlides" size="small" />
<n-text>居中显示</n-text>
</n-space>
</setting-item>
<setting-item name="图片样式">
<n-select v-model:value="optionData.fit" :options="fitList" placeholder="样式" />
</setting-item>
</setting-item-box>
<setting-item-box name="指示器">
<setting-item name="样式">
<n-select v-model:value="optionData.dotType" :options="dotTypes" placeholder="选择样式" />
</setting-item>
<setting-item name="位置">
<n-select v-model:value="optionData.dotPlacement" :options="dotPlacements" placeholder="选择位置" />
</setting-item>
<setting-item>
<n-space>
<n-switch v-model:value="optionData.showDots" size="small" />
<n-text>显示</n-text>
</n-space>
</setting-item>
<setting-item>
<n-space>
<n-switch v-model:value="optionData.showArrow" size="small" />
<n-text>箭头</n-text>
</n-space>
</setting-item>
<setting-item>
<n-space>
<n-switch v-model:value="optionData.draggable" size="small" />
<n-text>拖曳切换</n-text>
</n-space>
</setting-item>
</setting-item-box>
</collapse-item>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { option } from './config'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true
}
})
//
const dotTypes = [
{
label: '点',
value: 'dot'
},
{
label: '线',
value: 'line'
}
]
const directions = [
{
label: '水平方向',
value: 'horizontal'
},
{
label: '垂直方向',
value: 'vertical'
}
]
const effects = [
{
label: 'slide',
value: 'slide'
},
{
label: 'fade',
value: 'fade'
},
{
label: 'card',
value: 'card'
},
{
label: 'custom',
value: 'custom'
}
]
const dotPlacements = [
{
label: '上边',
value: 'top'
},
{
label: '下边',
value: 'bottom'
},
{
label: '左边',
value: 'left'
},
{
label: '右边',
value: 'right'
}
]
//
const fitList = [
{
value: 'fill',
label: 'fill'
},
{
value: 'contain',
label: 'contain'
},
{
value: 'cover',
label: 'cover'
},
{
value: 'scale-down',
label: 'scale-down'
},
{
value: 'none',
label: 'none'
}
]
</script>

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const ImageCarouselConfig: ConfigType = {
key: 'ImageCarousel',
chartKey: 'VImageCarousel',
conKey: 'VCImageCarousel',
title: '轮播图',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.INFORMATIONS,
chartFrame: ChartFrameEnum.NAIVE_UI,
image: 'photo_carousel.png'
}

View File

@ -0,0 +1,78 @@
<template>
<div>
<n-carousel
:autoplay="autoplay"
:interval="interval"
:centered-slides="centeredSlides"
:direction="direction"
:dot-placement="dotPlacement"
:dot-type="dotType"
:draggable="draggable"
:effect="effect"
:slides-per-view="slidesPerview"
:show-arrow="showArrow"
:show-dots="showDots"
>
<n-image
v-for="(url, index) in option.dataset"
preview-disabled
:key="index"
:object-fit="fit"
:src="url"
:fallback-src="requireErrorImg()"
:width="w"
:height="h"
></n-image>
</n-carousel>
</div>
</template>
<script setup lang="ts">
import { PropType, toRefs, shallowReactive, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { requireErrorImg } from '@/utils'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { option as configOption } from './config'
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const option = shallowReactive({
dataset: configOption.dataset
})
const { w, h } = toRefs(props.chartConfig.attr)
const {
autoplay,
interval,
slidesPerview,
direction,
draggable,
centeredSlides,
effect,
dotType,
dotPlacement,
showArrow,
showDots,
fit
} = toRefs(props.chartConfig.option)
watch(
() => props.chartConfig.option.dataset,
(newData: any) => {
option.dataset = newData
},
{
immediate: true,
deep: false
}
)
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
option.dataset = newData
})
</script>

View File

@ -1,6 +1,7 @@
import { ImageConfig } from './Image/index'
import { ImageCarouselConfig } from './ImageCarousel/index'
import { IframeConfig } from './Iframe/index'
import { VideoConfig } from './Video/index'
import { WordCloudConfig } from './WordCloud/index'
export default [WordCloudConfig, ImageConfig, VideoConfig, IframeConfig]
export default [ImageConfig, ImageCarouselConfig, VideoConfig, IframeConfig, WordCloudConfig]

View File

@ -10,7 +10,7 @@ import cloneDeep from 'lodash/cloneDeep'
import { WinKeyboard } from '@/enums/editPageEnum'
import { RequestHttpIntervalEnum, RequestParamsObjType } from '@/enums/httpEnum'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { excludeParseEventKeyList } from '@/enums/eventEnum'
import { excludeParseEventKeyList, excludeParseEventValueList } from '@/enums/eventEnum'
/**
* *
@ -320,14 +320,17 @@ export const JSONStringify = <T>(data: T) => {
*/
export const JSONParse = (data: string) => {
return JSON.parse(data, (k, v) => {
// 过滤函数字符串
if (excludeParseEventKeyList.includes(k)) return v
if(typeof v === 'string' && v.indexOf('javascript:') > -1){
//动态请求json中'javascript:'内容会影响模板content解析直接返回
return v
// 过滤函数值表达式
if (typeof v === 'string') {
const someValue = excludeParseEventValueList.some(excludeValue => v.indexOf(excludeValue) > -1)
if (someValue) return v
}
// 还原函数值
if (typeof v === 'string' && v.indexOf && (v.indexOf('function') > -1 || v.indexOf('=>') > -1)) {
return eval(`(function(){return ${v}})()`)
} else if (typeof v === 'string' && v.indexOf && (v.indexOf('return ') > -1)) {
} else if (typeof v === 'string' && v.indexOf && v.indexOf('return ') > -1) {
const baseLeftIndex = v.indexOf('(')
if (baseLeftIndex > -1) {
const newFn = `function ${v.substring(baseLeftIndex)}`
@ -344,4 +347,4 @@ export const JSONParse = (data: string) => {
*/
export const setTitle = (title?: string) => {
title && (document.title = title)
}
}