Commit ed3194e378e5d8016e7f5eb62195daac85a57b6b
Merge branch 'ft' into 'main_dev'
feat(src/packages): 重写信息里的视频组件,支持自定义上传等 See merge request yunteng/thingskit-view!78
Showing
24 changed files
with
511 additions
and
79 deletions
src/assets/external/weather/shower.png
0 → 100644
848 Bytes
src/assets/external/weather/thunderstorm.png
0 → 100644
5.51 KB
@@ -14,7 +14,7 @@ export const enum areaEnum { | @@ -14,7 +14,7 @@ export const enum areaEnum { | ||
14 | export const includes = [] | 14 | export const includes = [] |
15 | 15 | ||
16 | export const option = { | 16 | export const option = { |
17 | - drillingIn:false, | 17 | + drillingIn: false, |
18 | dataset: dataJson, | 18 | dataset: dataJson, |
19 | mapRegion: { | 19 | mapRegion: { |
20 | adcode: 'china', | 20 | adcode: 'china', |
@@ -152,7 +152,7 @@ export const option = { | @@ -152,7 +152,7 @@ export const option = { | ||
152 | shadowOffsetY: 2, | 152 | shadowOffsetY: 2, |
153 | shadowBlur: 10 | 153 | shadowBlur: 10 |
154 | } | 154 | } |
155 | - } | 155 | + }, |
156 | ] | 156 | ] |
157 | } | 157 | } |
158 | export const MapDefaultConfig = { ...option } | 158 | export const MapDefaultConfig = { ...option } |
@@ -27,6 +27,8 @@ import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json' | @@ -27,6 +27,8 @@ import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json' | ||
27 | import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components' | 27 | import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components' |
28 | import cityMap from './mapGeojson/china-main-city-map.json' | 28 | import cityMap from './mapGeojson/china-main-city-map.json' |
29 | 29 | ||
30 | +type historyDataType = { name: string; code: string } | ||
31 | + | ||
30 | const props = defineProps({ | 32 | const props = defineProps({ |
31 | themeSetting: { | 33 | themeSetting: { |
32 | type: Object, | 34 | type: Object, |
@@ -57,6 +59,12 @@ use([ | @@ -57,6 +59,12 @@ use([ | ||
57 | 59 | ||
58 | const saveSelectValue = ref('') | 60 | const saveSelectValue = ref('') |
59 | 61 | ||
62 | +const iconStr = ref( | ||
63 | + 'path://M853.333333 245.333333H245.333333l93.866667-93.866666c12.8-12.8 12.8-34.133333 0-46.933334-12.8-12.8-34.133333-12.8-46.933333 0l-145.066667 145.066667c-12.8 12.8-12.8 34.133333 0 46.933333l145.066667 145.066667c6.4 6.4 14.933333 10.666667 23.466666 10.666667s17.066667-4.266667 23.466667-10.666667c12.8-12.8 12.8-34.133333 0-46.933333L256 311.466667h597.333333c6.4 0 10.666667 4.266667 10.666667 10.666666v426.666667c0 6.4-4.266667 10.666667-10.666667 10.666667H170.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h682.666666c40.533333 0 74.666667-34.133333 74.666667-74.666667V320c0-40.533333-34.133333-74.666667-74.666667-74.666667z' | ||
64 | +) | ||
65 | + | ||
66 | +const historyData = ref<historyDataType[]>([]) | ||
67 | + | ||
60 | const option = reactive({ | 68 | const option = reactive({ |
61 | value: mergeTheme(props.chartConfig.option, props.themeSetting, includes) | 69 | value: mergeTheme(props.chartConfig.option, props.themeSetting, includes) |
62 | }) | 70 | }) |
@@ -68,7 +76,7 @@ const toolBoxOption = { | @@ -68,7 +76,7 @@ const toolBoxOption = { | ||
68 | myFullButton: { | 76 | myFullButton: { |
69 | show: true, | 77 | show: true, |
70 | title: '返回', | 78 | title: '返回', |
71 | - icon: 'path://M853.333333 245.333333H245.333333l93.866667-93.866666c12.8-12.8 12.8-34.133333 0-46.933334-12.8-12.8-34.133333-12.8-46.933333 0l-145.066667 145.066667c-12.8 12.8-12.8 34.133333 0 46.933333l145.066667 145.066667c6.4 6.4 14.933333 10.666667 23.466666 10.666667s17.066667-4.266667 23.466667-10.666667c12.8-12.8 12.8-34.133333 0-46.933333L256 311.466667h597.333333c6.4 0 10.666667 4.266667 10.666667 10.666666v426.666667c0 6.4-4.266667 10.666667-10.666667 10.666667H170.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h682.666666c40.533333 0 74.666667-34.133333 74.666667-74.666667V320c0-40.533333-34.133333-74.666667-74.666667-74.666667z', | 79 | + icon: iconStr.value, |
72 | onclick: () => watchAdcode() | 80 | onclick: () => watchAdcode() |
73 | } | 81 | } |
74 | } | 82 | } |
@@ -79,10 +87,12 @@ props.chartConfig.option = { | @@ -79,10 +87,12 @@ props.chartConfig.option = { | ||
79 | ...{ toolbox: toolBoxOption } | 87 | ...{ toolbox: toolBoxOption } |
80 | } | 88 | } |
81 | 89 | ||
90 | +//地图点击返回 | ||
82 | const watchAdcode = () => { | 91 | const watchAdcode = () => { |
83 | if (props.chartConfig.option.drillingIn) { | 92 | if (props.chartConfig.option.drillingIn) { |
84 | - const findCity = (cityMap as any)[saveSelectValue.value] | ||
85 | - props.chartConfig.option.mapRegion.adcode = 'china' | 93 | + const code = historyData.value.at(-2)?.code |
94 | + props.chartConfig.option.mapRegion.adcode = code ? code : 'china' | ||
95 | + historyData.value.pop() | ||
86 | } | 96 | } |
87 | } | 97 | } |
88 | 98 | ||
@@ -90,12 +100,16 @@ const vChartRef = ref<typeof VChart>() | @@ -90,12 +100,16 @@ const vChartRef = ref<typeof VChart>() | ||
90 | 100 | ||
91 | //动态获取json注册地图 | 101 | //动态获取json注册地图 |
92 | const getGeojson = (regionId: string) => { | 102 | const getGeojson = (regionId: string) => { |
93 | - return new Promise<boolean>(resolve => { | ||
94 | - import(`./mapGeojson/${regionId}.json`).then(data => { | ||
95 | - registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} }) | ||
96 | - resolve(true) | 103 | + try { |
104 | + return new Promise<boolean>(resolve => { | ||
105 | + import(`./mapGeojson/${regionId}.json`).then(data => { | ||
106 | + registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} }) | ||
107 | + resolve(true) | ||
108 | + }) | ||
97 | }) | 109 | }) |
98 | - }) | 110 | + } finally { |
111 | + console.log | ||
112 | + } | ||
99 | } | 113 | } |
100 | 114 | ||
101 | //异步时先注册空的 保证初始化不报错 | 115 | //异步时先注册空的 保证初始化不报错 |
@@ -199,7 +213,12 @@ const handleVChartClick = async (params: any) => { | @@ -199,7 +213,12 @@ const handleVChartClick = async (params: any) => { | ||
199 | const { name } = params | 213 | const { name } = params |
200 | saveSelectValue.value = name | 214 | saveSelectValue.value = name |
201 | const findAdcode = (cityMap as any)[name] | 215 | const findAdcode = (cityMap as any)[name] |
216 | + if (!findAdcode) return | ||
202 | props.chartConfig.option.mapRegion.adcode = findAdcode | 217 | props.chartConfig.option.mapRegion.adcode = findAdcode |
218 | + historyData.value.push({ | ||
219 | + name, | ||
220 | + code: findAdcode | ||
221 | + }) | ||
203 | } | 222 | } |
204 | } | 223 | } |
205 | </script> | 224 | </script> |
1 | <template> | 1 | <template> |
2 | <div class="videoPlay"> | 2 | <div class="videoPlay"> |
3 | - <video crossOrigin="anonymous" ref="videoRef" class="video-js vjs-default-skin vjs-big-play-centered" controls> | 3 | + <video |
4 | + style="object-fit: cover" | ||
5 | + :poster="poster" | ||
6 | + crossOrigin="anonymous" | ||
7 | + ref="videoRef" | ||
8 | + class="video-js vjs-default-skin vjs-big-play-centered" | ||
9 | + controls | ||
10 | + > | ||
4 | <source :src="path" /> | 11 | <source :src="path" /> |
5 | </video> | 12 | </video> |
6 | </div> | 13 | </div> |
7 | </template> | 14 | </template> |
8 | <script lang="ts" setup> | 15 | <script lang="ts" setup> |
9 | -import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue' | 16 | +import { nextTick, onBeforeUnmount, onMounted, ref, watch, toRefs } from 'vue' |
10 | import videojs, { VideoJsPlayer } from 'video.js' | 17 | import videojs, { VideoJsPlayer } from 'video.js' |
11 | import type { VideoJsPlayerOptions } from 'video.js' | 18 | import type { VideoJsPlayerOptions } from 'video.js' |
12 | import 'video.js/dist/video-js.css' | 19 | import 'video.js/dist/video-js.css' |
@@ -17,6 +24,7 @@ const props = withDefaults( | @@ -17,6 +24,7 @@ const props = withDefaults( | ||
17 | path: string | 24 | path: string |
18 | autoPlay?: boolean | 25 | autoPlay?: boolean |
19 | h?: number | 26 | h?: number |
27 | + poster?: string | ||
20 | }>(), | 28 | }>(), |
21 | { autoPlay: false } | 29 | { autoPlay: false } |
22 | ) | 30 | ) |
@@ -33,19 +41,22 @@ const initPlay = async () => { | @@ -33,19 +41,22 @@ const initPlay = async () => { | ||
33 | controls: true, | 41 | controls: true, |
34 | autoplay: props.autoPlay, | 42 | autoplay: props.autoPlay, |
35 | src: props?.path, | 43 | src: props?.path, |
44 | + poster: props?.poster, | ||
36 | language: 'zh-CN', | 45 | language: 'zh-CN', |
37 | - techOrder: ['html5'] | 46 | + techOrder: ['html5'], |
47 | + preload: 'none' | ||
38 | } | 48 | } |
39 | player = videojs(videoRef.value, options, () => { | 49 | player = videojs(videoRef.value, options, () => { |
40 | - videojs.log('播放器已经准备好了!') | 50 | + videojs.log('Video is reading') |
41 | if (props.autoPlay) { | 51 | if (props.autoPlay) { |
42 | player.play() | 52 | player.play() |
43 | } | 53 | } |
44 | player.on('ended', () => { | 54 | player.on('ended', () => { |
45 | - videojs.log('播放结束了!') | 55 | + videojs.log('Play end') |
46 | }) | 56 | }) |
47 | player.on('error', () => { | 57 | player.on('error', () => { |
48 | - videojs.log('播放器解析出错!') | 58 | + player.errorDisplay.close() |
59 | + videojs.log('Play parse error') | ||
49 | }) | 60 | }) |
50 | }) | 61 | }) |
51 | } | 62 | } |
@@ -58,10 +69,10 @@ onMounted(() => { | @@ -58,10 +69,10 @@ onMounted(() => { | ||
58 | watch( | 69 | watch( |
59 | () => props.path, | 70 | () => props.path, |
60 | () => { | 71 | () => { |
61 | - player?.pause() | ||
62 | - player?.src(props.path) | ||
63 | - player?.load() | ||
64 | - if (props.path) { | 72 | + if (props.path && props.autoPlay) { |
73 | + player?.pause() | ||
74 | + player?.load() | ||
75 | + player?.src(props.path) | ||
65 | player?.play() | 76 | player?.play() |
66 | } | 77 | } |
67 | }, | 78 | }, |
@@ -74,11 +85,15 @@ onBeforeUnmount(() => { | @@ -74,11 +85,15 @@ onBeforeUnmount(() => { | ||
74 | player?.dispose() | 85 | player?.dispose() |
75 | }) | 86 | }) |
76 | </script> | 87 | </script> |
88 | +<style> | ||
89 | +.vjs-poster { | ||
90 | + background-size: cover !important; | ||
91 | +} | ||
92 | +</style> | ||
77 | <style lang="scss" scoped> | 93 | <style lang="scss" scoped> |
78 | .videoPlay { | 94 | .videoPlay { |
79 | flex: 1; | 95 | flex: 1; |
80 | height: v-bind('`${h}px`'); | 96 | height: v-bind('`${h}px`'); |
81 | - | ||
82 | .video-js { | 97 | .video-js { |
83 | height: 100%; | 98 | height: 100%; |
84 | width: 100%; | 99 | width: 100%; |
@@ -6,6 +6,7 @@ import cloneDeep from 'lodash/cloneDeep' | @@ -6,6 +6,7 @@ import cloneDeep from 'lodash/cloneDeep' | ||
6 | export const option = { | 6 | export const option = { |
7 | dataset: '', | 7 | dataset: '', |
8 | autoplay: false, | 8 | autoplay: false, |
9 | + poster: '' | ||
9 | } | 10 | } |
10 | 11 | ||
11 | export default class Config extends PublicConfigClass implements CreateComponentType { | 12 | export default class Config extends PublicConfigClass implements CreateComponentType { |
1 | <template> | 1 | <template> |
2 | <CollapseItem name="播放器配置" :expanded="true"> | 2 | <CollapseItem name="播放器配置" :expanded="true"> |
3 | + <setting-item-box name="上传图片" :alone="true"> | ||
4 | + <setting-item> | ||
5 | + <n-card class="upload-box"> | ||
6 | + <n-upload | ||
7 | + :show-file-list="false" | ||
8 | + v-model:file-list="uploadFileListRef" | ||
9 | + :customRequest="customRequest" | ||
10 | + :onBeforeUpload="beforeUploadHandle" | ||
11 | + > | ||
12 | + <n-upload-dragger> | ||
13 | + <img v-if="optionData.poster" class="upload-show" :src="optionData.poster" alt="背景" /> | ||
14 | + <div class="upload-img" v-show="!optionData.poster"> | ||
15 | + <img src="@/assets/images/canvas/noImage.png" /> | ||
16 | + <n-text class="upload-desc" depth="3"> | ||
17 | + 图片需小于 {{ backgroundImageSize }}M ,格式为 png/jpg/gif 的文件 | ||
18 | + </n-text> | ||
19 | + </div> | ||
20 | + </n-upload-dragger> | ||
21 | + </n-upload> | ||
22 | + </n-card> | ||
23 | + </setting-item> | ||
24 | + </setting-item-box> | ||
3 | <setting-item-box name="源地址" :alone="true"> | 25 | <setting-item-box name="源地址" :alone="true"> |
4 | <setting-item> | 26 | <setting-item> |
5 | <n-input-group> | 27 | <n-input-group> |
@@ -16,14 +38,94 @@ | @@ -16,14 +38,94 @@ | ||
16 | </template> | 38 | </template> |
17 | 39 | ||
18 | <script setup lang="ts"> | 40 | <script setup lang="ts"> |
19 | -import { PropType } from 'vue' | 41 | +import { PropType, ref, nextTick } from 'vue' |
20 | import { option } from './config' | 42 | import { option } from './config' |
21 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | 43 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' |
44 | +import { FileTypeEnum } from '@/enums/fileTypeEnum' | ||
45 | +import { uploadFile } from '@/api/external/contentSave/content' | ||
46 | +import { UploadCustomRequestOptions } from 'naive-ui' | ||
47 | +import { backgroundImageSize } from '@/settings/designSetting' | ||
48 | +import { fetchRouteParamsLocation } from '@/utils' | ||
22 | 49 | ||
23 | -defineProps({ | 50 | +const props = defineProps({ |
24 | optionData: { | 51 | optionData: { |
25 | type: Object as PropType<typeof option>, | 52 | type: Object as PropType<typeof option>, |
26 | required: true | 53 | required: true |
27 | } | 54 | } |
28 | }) | 55 | }) |
56 | + | ||
57 | +const uploadFileListRef = ref() | ||
58 | + | ||
59 | +// 上传图片前置处理 | ||
60 | +// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
61 | +//@ts-ignore | ||
62 | +const beforeUploadHandle = async ({ file }) => { | ||
63 | + uploadFileListRef.value = [] | ||
64 | + const type = file.file.type | ||
65 | + const size = file.file.size | ||
66 | + | ||
67 | + if (size > 1024 * 1024 * backgroundImageSize) { | ||
68 | + window['$message'].warning(`图片超出 ${backgroundImageSize}M 限制,请重新上传!`) | ||
69 | + return false | ||
70 | + } | ||
71 | + if (type !== FileTypeEnum.PNG && type !== FileTypeEnum.JPEG && type !== FileTypeEnum.GIF) { | ||
72 | + window['$message'].warning('文件格式不符合,请重新上传!') | ||
73 | + return false | ||
74 | + } | ||
75 | + return true | ||
76 | +} | ||
77 | + | ||
78 | +// 自定义上传操作 | ||
79 | +const customRequest = (options: UploadCustomRequestOptions) => { | ||
80 | + const { file } = options | ||
81 | + nextTick(async () => { | ||
82 | + if (file.file) { | ||
83 | + // 修改名称 | ||
84 | + const newNameFile = new File([file.file], `${fetchRouteParamsLocation()}_index_background.png`, { | ||
85 | + type: file.file.type | ||
86 | + }) | ||
87 | + let uploadParams = new FormData() | ||
88 | + uploadParams.append('file', newNameFile) | ||
89 | + const uploadRes = await uploadFile(uploadParams) | ||
90 | + if (uploadRes) { | ||
91 | + props.optionData.poster = uploadRes?.fileStaticUri | ||
92 | + window['$message'].success('添加图片成功!') | ||
93 | + } | ||
94 | + } else { | ||
95 | + window['$message'].error('添加图片失败,请稍后重试!') | ||
96 | + } | ||
97 | + }) | ||
98 | +} | ||
29 | </script> | 99 | </script> |
100 | +<style lang="scss" scoped> | ||
101 | +$uploadHeight: 193px; | ||
102 | +.upload-box { | ||
103 | + cursor: pointer; | ||
104 | + margin-bottom: 20px; | ||
105 | + @include deep() { | ||
106 | + .n-card__content { | ||
107 | + padding: 0; | ||
108 | + overflow: hidden; | ||
109 | + } | ||
110 | + .n-upload-dragger { | ||
111 | + padding: 5px; | ||
112 | + } | ||
113 | + } | ||
114 | + .upload-show { | ||
115 | + width: -webkit-fill-available; | ||
116 | + height: $uploadHeight; | ||
117 | + border-radius: 5px; | ||
118 | + } | ||
119 | + .upload-img { | ||
120 | + display: flex; | ||
121 | + flex-direction: column; | ||
122 | + align-items: center; | ||
123 | + img { | ||
124 | + height: 150px; | ||
125 | + } | ||
126 | + .upload-desc { | ||
127 | + padding: 10px 0; | ||
128 | + } | ||
129 | + } | ||
130 | +} | ||
131 | +</style> |
1 | <template> | 1 | <template> |
2 | <div> | 2 | <div> |
3 | - <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" /> | 3 | + <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" :poster="option.poster" /> |
4 | </div> | 4 | </div> |
5 | </template> | 5 | </template> |
6 | <script setup lang="ts"> | 6 | <script setup lang="ts"> |
@@ -18,10 +18,11 @@ const props = defineProps({ | @@ -18,10 +18,11 @@ const props = defineProps({ | ||
18 | 18 | ||
19 | const { h } = toRefs(props.chartConfig.attr) | 19 | const { h } = toRefs(props.chartConfig.attr) |
20 | 20 | ||
21 | -const { autoplay, dataset } = toRefs(props.chartConfig.option) | 21 | +const { autoplay, dataset, poster } = toRefs(props.chartConfig.option) |
22 | 22 | ||
23 | const option = shallowReactive({ | 23 | const option = shallowReactive({ |
24 | - dataset: configOption.dataset | 24 | + dataset: configOption.dataset, |
25 | + poster: configOption.poster | ||
25 | }) | 26 | }) |
26 | 27 | ||
27 | watch( | 28 | watch( |
@@ -30,7 +31,17 @@ watch( | @@ -30,7 +31,17 @@ watch( | ||
30 | option.dataset = newData | 31 | option.dataset = newData |
31 | }, | 32 | }, |
32 | { | 33 | { |
33 | - immediate: true, | 34 | + immediate: true |
35 | + } | ||
36 | +) | ||
37 | + | ||
38 | +watch( | ||
39 | + () => poster?.value, | ||
40 | + (newData: string) => { | ||
41 | + option.poster = newData | ||
42 | + }, | ||
43 | + { | ||
44 | + immediate: true | ||
34 | } | 45 | } |
35 | ) | 46 | ) |
36 | </script> | 47 | </script> |
1 | <script lang="ts" setup name="WeatherContent"> | 1 | <script lang="ts" setup name="WeatherContent"> |
2 | -import { toRefs } from 'vue' | 2 | +import { toRefs, PropType, computed } from 'vue' |
3 | import SelectCity from './SelectCity.vue' | 3 | import SelectCity from './SelectCity.vue' |
4 | import { useUtils } from '../hooks/useUtils' | 4 | import { useUtils } from '../hooks/useUtils' |
5 | import weatherBg from '@/assets/external/weather/bg.png' | 5 | import weatherBg from '@/assets/external/weather/bg.png' |
6 | +import { weatherInfoInterface, selectValueType } from '../config' | ||
6 | 7 | ||
7 | const props = defineProps({ | 8 | const props = defineProps({ |
8 | data: { | 9 | data: { |
9 | - type: Array as any | 10 | + type: Array as PropType<weatherInfoInterface[]>, |
11 | + required: true | ||
10 | } | 12 | } |
11 | }) | 13 | }) |
12 | 14 | ||
@@ -16,21 +18,31 @@ const { loadWeatherImg, loadWeatherLevel } = useUtils() | @@ -16,21 +18,31 @@ const { loadWeatherImg, loadWeatherLevel } = useUtils() | ||
16 | 18 | ||
17 | const { casts } = toRefs(props.data[0]) | 19 | const { casts } = toRefs(props.data[0]) |
18 | 20 | ||
19 | -const onHandleSelectValues = (values: any) => { | 21 | +const onHandleSelectValues = (values: selectValueType) => { |
20 | emits('submit', values) | 22 | emits('submit', values) |
21 | } | 23 | } |
24 | + | ||
25 | +const nCardComputed = computed(() => { | ||
26 | + return { | ||
27 | + backgroundImage: `url('${weatherBg}')` | ||
28 | + } | ||
29 | +}) | ||
30 | + | ||
31 | +const segmentedComputed = computed(() => { | ||
32 | + return { | ||
33 | + content: true, | ||
34 | + footer: 'soft' | ||
35 | + } | ||
36 | +}) | ||
37 | + | ||
38 | +const indexMapDayFunc = (index: number) => { | ||
39 | + return index === 0 ? '今天' : index === 1 ? '明天' : index === 2 ? '后天' : '外天' | ||
40 | +} | ||
22 | </script> | 41 | </script> |
23 | 42 | ||
24 | <template> | 43 | <template> |
25 | <div> | 44 | <div> |
26 | - <n-card | ||
27 | - :segmented="{ | ||
28 | - content: true, | ||
29 | - footer: 'soft' | ||
30 | - }" | ||
31 | - :style="{ backgroundImage: `url('${weatherBg}')` }" | ||
32 | - class="n-card" | ||
33 | - > | 45 | + <n-card :segmented="segmentedComputed" :style="nCardComputed" class="n-card"> |
34 | <template #header> | 46 | <template #header> |
35 | <div class="card-header"> | 47 | <div class="card-header"> |
36 | <div class="city-text">{{ data[0]?.city }}</div> | 48 | <div class="city-text">{{ data[0]?.city }}</div> |
@@ -59,7 +71,7 @@ const onHandleSelectValues = (values: any) => { | @@ -59,7 +71,7 @@ const onHandleSelectValues = (values: any) => { | ||
59 | </div> | 71 | </div> |
60 | <template #footer> | 72 | <template #footer> |
61 | <div v-for="(item, index) in casts" :key="index" class="footer-content"> | 73 | <div v-for="(item, index) in casts" :key="index" class="footer-content"> |
62 | - <div>{{ index === 0 ? '今天' : index === 1 ? '明天' : index === 2 ? '后天' : '外天' }}</div> | 74 | + <div>{{ indexMapDayFunc(index) }}</div> |
63 | <div> | 75 | <div> |
64 | <img :src="loadWeatherImg(item?.dayweather)" /> | 76 | <img :src="loadWeatherImg(item?.dayweather)" /> |
65 | </div> | 77 | </div> |
@@ -7,6 +7,8 @@ import clearDay from '@/assets/external/weather/clearDay.png' | @@ -7,6 +7,8 @@ import clearDay from '@/assets/external/weather/clearDay.png' | ||
7 | import cloudy from '@/assets/external/weather/cloudy.png' | 7 | import cloudy from '@/assets/external/weather/cloudy.png' |
8 | import cloudyDay from '@/assets/external/weather/cloudyDay.png' | 8 | import cloudyDay from '@/assets/external/weather/cloudyDay.png' |
9 | import lightRain from '@/assets/external/weather/lightRain.png' | 9 | import lightRain from '@/assets/external/weather/lightRain.png' |
10 | +import thunderstorm from '@/assets/external/weather/thunderstorm.png' | ||
11 | +import shower from '@/assets/external/weather/shower.png' | ||
10 | 12 | ||
11 | //第三方 天气接口key值和api配置(高德) | 13 | //第三方 天气接口key值和api配置(高德) |
12 | export class ThirdPartyWeatherConnfig { | 14 | export class ThirdPartyWeatherConnfig { |
@@ -23,7 +25,7 @@ export const enum areaEnum { | @@ -23,7 +25,7 @@ export const enum areaEnum { | ||
23 | COUNTY = 'COUNTY' | 25 | COUNTY = 'COUNTY' |
24 | } | 26 | } |
25 | 27 | ||
26 | -//天气文字映射图片 | 28 | +//天气文字图片映射 |
27 | export const weatherTextMapImg = [ | 29 | export const weatherTextMapImg = [ |
28 | { | 30 | { |
29 | text: '晴', | 31 | text: '晴', |
@@ -40,10 +42,17 @@ export const weatherTextMapImg = [ | @@ -40,10 +42,17 @@ export const weatherTextMapImg = [ | ||
40 | { | 42 | { |
41 | text: '小雨', | 43 | text: '小雨', |
42 | img: lightRain | 44 | img: lightRain |
45 | + }, | ||
46 | + { | ||
47 | + text: '雷阵雨', | ||
48 | + img: thunderstorm | ||
49 | + }, | ||
50 | + { | ||
51 | + text: '阵雨', | ||
52 | + img: shower | ||
43 | } | 53 | } |
44 | ] | 54 | ] |
45 | 55 | ||
46 | -console.log(clearDay, cloudy) | ||
47 | //风力等级文字映射 | 56 | //风力等级文字映射 |
48 | export const weatherSpeedMapText = [ | 57 | export const weatherSpeedMapText = [ |
49 | { | 58 | { |
@@ -100,6 +109,36 @@ export const weatherSpeedMapText = [ | @@ -100,6 +109,36 @@ export const weatherSpeedMapText = [ | ||
100 | } | 109 | } |
101 | ] | 110 | ] |
102 | 111 | ||
112 | +export type selectValueType = { | ||
113 | + provinceValue: null | ||
114 | + cityValue: string | ||
115 | + countyValue: null | ||
116 | +} | ||
117 | + | ||
118 | +export interface castsInterface { | ||
119 | + date: string | ||
120 | + week: string | ||
121 | + dayweather: string | ||
122 | + nightweather: string | ||
123 | + daytemp: string | ||
124 | + nighttemp: string | ||
125 | + daywind: string | ||
126 | + nightwind: string | ||
127 | + daypower: string | ||
128 | + nightpower: string | ||
129 | + daytemp_float: string | ||
130 | + nighttemp_float: string | ||
131 | +} | ||
132 | +export interface weatherInfoInterface { | ||
133 | + city: string | ||
134 | + adcode: string | ||
135 | + province: string | ||
136 | + reporttime: string | ||
137 | + casts: castsInterface[] | ||
138 | +} | ||
139 | + | ||
140 | +export type weatherTextMapType = { text: string; img: string; level: Fn } | ||
141 | + | ||
103 | export const option = { | 142 | export const option = { |
104 | dataset: { | 143 | dataset: { |
105 | provinceValue: null, | 144 | provinceValue: null, |
@@ -6,6 +6,8 @@ | @@ -6,6 +6,8 @@ | ||
6 | <SettingItem name="颜色"> | 6 | <SettingItem name="颜色"> |
7 | <n-color-picker v-model:value="optionData.weatherCss.backgroundColor" /> | 7 | <n-color-picker v-model:value="optionData.weatherCss.backgroundColor" /> |
8 | </SettingItem> | 8 | </SettingItem> |
9 | + </SettingItemBox> | ||
10 | + <SettingItemBox name="背景"> | ||
9 | <SettingItem> | 11 | <SettingItem> |
10 | <n-button size="small" @click="optionData.weatherCss.backgroundColor = 'transparent'"> 恢复默认颜色 </n-button> | 12 | <n-button size="small" @click="optionData.weatherCss.backgroundColor = 'transparent'"> 恢复默认颜色 </n-button> |
11 | </SettingItem> | 13 | </SettingItem> |
@@ -73,7 +75,7 @@ | @@ -73,7 +75,7 @@ | ||
73 | <script setup lang="ts"> | 75 | <script setup lang="ts"> |
74 | import { PropType } from 'vue' | 76 | import { PropType } from 'vue' |
75 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | 77 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' |
76 | -import { option } from './config' | 78 | +import { option, selectValueType } from './config' |
77 | import SelectCity from './componnets/SelectCity.vue' | 79 | import SelectCity from './componnets/SelectCity.vue' |
78 | 80 | ||
79 | const props = defineProps({ | 81 | const props = defineProps({ |
@@ -83,7 +85,7 @@ const props = defineProps({ | @@ -83,7 +85,7 @@ const props = defineProps({ | ||
83 | } | 85 | } |
84 | }) | 86 | }) |
85 | 87 | ||
86 | -const onHandleSelectValues = (values: any) => { | 88 | +const onHandleSelectValues = (values: selectValueType) => { |
87 | props.optionData.dataset = values | 89 | props.optionData.dataset = values |
88 | } | 90 | } |
89 | </script> | 91 | </script> |
1 | -import { weatherSpeedMapText, weatherTextMapImg } from '../config' | 1 | +import { weatherSpeedMapText, weatherTextMapImg, weatherTextMapType } from '../config' |
2 | import clearDay from '@/assets/external/weather/clearDay.png' | 2 | import clearDay from '@/assets/external/weather/clearDay.png' |
3 | 3 | ||
4 | export const useUtils = () => { | 4 | export const useUtils = () => { |
5 | const loadWeatherImg = (text: string) => { | 5 | const loadWeatherImg = (text: string) => { |
6 | - return weatherTextMapImg.find((item: any) => item.text === text)?.img || clearDay | 6 | + return weatherTextMapImg.find((item: Omit<weatherTextMapType, 'level'>) => item.text === text)?.img || clearDay |
7 | } | 7 | } |
8 | 8 | ||
9 | //风力等级 ≤3 3 | 9 | //风力等级 ≤3 3 |
@@ -14,7 +14,7 @@ export const useUtils = () => { | @@ -14,7 +14,7 @@ export const useUtils = () => { | ||
14 | } else { | 14 | } else { |
15 | handleSpeed = speed | 15 | handleSpeed = speed |
16 | } | 16 | } |
17 | - return weatherSpeedMapText.find((item: any) => item.level(Number(handleSpeed)))?.text | 17 | + return weatherSpeedMapText.find((item: { text: string; level: Fn }) => item.level(Number(handleSpeed)))?.text |
18 | } | 18 | } |
19 | return { | 19 | return { |
20 | loadWeatherImg, | 20 | loadWeatherImg, |
1 | <script lang="ts" setup name="Weather"> | 1 | <script lang="ts" setup name="Weather"> |
2 | import { PropType, toRefs, onMounted, reactive, watch } from 'vue' | 2 | import { PropType, toRefs, onMounted, reactive, watch } from 'vue' |
3 | import { CreateComponentType } from '@/packages/index.d' | 3 | import { CreateComponentType } from '@/packages/index.d' |
4 | -import { option, ThirdPartyWeatherConnfig } from './config' | 4 | +import { option, ThirdPartyWeatherConnfig, selectValueType, weatherInfoInterface } from './config' |
5 | import axios from 'axios' | 5 | import axios from 'axios' |
6 | import WeatherContent from './componnets/WeatherContent.vue' | 6 | import WeatherContent from './componnets/WeatherContent.vue' |
7 | import { useUtils } from './hooks/useUtils' | 7 | import { useUtils } from './hooks/useUtils' |
@@ -19,11 +19,15 @@ const { w, h } = toRefs(props.chartConfig.attr) | @@ -19,11 +19,15 @@ const { w, h } = toRefs(props.chartConfig.attr) | ||
19 | 19 | ||
20 | const { weatherCss } = toRefs(props.chartConfig.option) | 20 | const { weatherCss } = toRefs(props.chartConfig.option) |
21 | 21 | ||
22 | -const weatherInfoValues = reactive<any>({ | 22 | +type weatherInfoValuesType = { |
23 | + weatherInfo: weatherInfoInterface[] | ||
24 | +} | ||
25 | + | ||
26 | +const weatherInfoValues = reactive<weatherInfoValuesType>({ | ||
23 | weatherInfo: [] | 27 | weatherInfo: [] |
24 | }) | 28 | }) |
25 | 29 | ||
26 | -const getWeatherInfos = async (area: any) => { | 30 | +const getWeatherInfos = async (area: selectValueType) => { |
27 | const { cityValue, countyValue } = area || props.chartConfig.option.dataset | 31 | const { cityValue, countyValue } = area || props.chartConfig.option.dataset |
28 | const params = { | 32 | const params = { |
29 | key: ThirdPartyWeatherConnfig.ak, | 33 | key: ThirdPartyWeatherConnfig.ak, |
@@ -52,7 +56,7 @@ watch( | @@ -52,7 +56,7 @@ watch( | ||
52 | } | 56 | } |
53 | ) | 57 | ) |
54 | 58 | ||
55 | -const onHandleSelectValues = (values: any) => { | 59 | +const onHandleSelectValues = (values: selectValueType) => { |
56 | getWeatherInfos(values) | 60 | getWeatherInfos(values) |
57 | } | 61 | } |
58 | </script> | 62 | </script> |
@@ -6,13 +6,17 @@ import cloneDeep from 'lodash/cloneDeep' | @@ -6,13 +6,17 @@ import cloneDeep from 'lodash/cloneDeep' | ||
6 | 6 | ||
7 | export const option = { | 7 | export const option = { |
8 | // 网站路径 | 8 | // 网站路径 |
9 | - dataset: "", | 9 | + dataset: '', |
10 | // 圆角 | 10 | // 圆角 |
11 | - borderRadius: 10 | 11 | + borderRadius: 10, |
12 | + pages: { | ||
13 | + page: 1, | ||
14 | + pageSize: 10 | ||
15 | + }, | ||
16 | + color: 'black' | ||
12 | } | 17 | } |
13 | 18 | ||
14 | -export default class Config extends PublicConfigClass implements CreateComponentType | ||
15 | -{ | 19 | +export default class Config extends PublicConfigClass implements CreateComponentType { |
16 | public key = OverrideILoadConfigurationframeConfig.key | 20 | public key = OverrideILoadConfigurationframeConfig.key |
17 | public attr = { ...chartInitConfig, w: 1200, h: 800, zIndex: -1 } | 21 | public attr = { ...chartInitConfig, w: 1200, h: 800, zIndex: -1 } |
18 | public chartConfig = cloneDeep(OverrideILoadConfigurationframeConfig) | 22 | public chartConfig = cloneDeep(OverrideILoadConfigurationframeConfig) |
@@ -15,16 +15,38 @@ | @@ -15,16 +15,38 @@ | ||
15 | ></n-input-number> | 15 | ></n-input-number> |
16 | </setting-item> | 16 | </setting-item> |
17 | </setting-item-box> | 17 | </setting-item-box> |
18 | + <setting-item-box name="分页"> | ||
19 | + <setting-item name="页码"> | ||
20 | + <n-input-number v-model:value="optionData.pages.page" size="small" :min="1" placeholder="页码"></n-input-number> | ||
21 | + </setting-item> | ||
22 | + <setting-item name="页数"> | ||
23 | + <n-input-number | ||
24 | + disabled | ||
25 | + v-model:value="optionData.pages.pageSize" | ||
26 | + size="small" | ||
27 | + :min="10" | ||
28 | + placeholder="页数" | ||
29 | + ></n-input-number> | ||
30 | + </setting-item> | ||
31 | + </setting-item-box> | ||
32 | + <setting-item-box name="颜色" :alone="true"> | ||
33 | + <SettingItem name="颜色"> | ||
34 | + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.color"></n-color-picker> | ||
35 | + </SettingItem> | ||
36 | + <SettingItem> | ||
37 | + <n-button size="small" @click="optionData.color = 'black'"> 恢复默认 </n-button> | ||
38 | + </SettingItem> | ||
39 | + </setting-item-box> | ||
18 | </collapse-item> | 40 | </collapse-item> |
19 | </template> | 41 | </template> |
20 | 42 | ||
21 | <script setup lang="ts"> | 43 | <script setup lang="ts"> |
22 | -import { PropType, onMounted, ref } from 'vue' | 44 | +import { PropType, onMounted, ref, watch } from 'vue' |
23 | import { option } from './config' | 45 | import { option } from './config' |
24 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | 46 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' |
25 | import { getConfigurationList } from '@/api/external/common/index' | 47 | import { getConfigurationList } from '@/api/external/common/index' |
26 | 48 | ||
27 | -defineProps({ | 49 | +const props = defineProps({ |
28 | optionData: { | 50 | optionData: { |
29 | type: Object as PropType<typeof option>, | 51 | type: Object as PropType<typeof option>, |
30 | required: true | 52 | required: true |
@@ -40,7 +62,18 @@ const getConfigurationOptions = async (params: object) => { | @@ -40,7 +62,18 @@ const getConfigurationOptions = async (params: object) => { | ||
40 | } | 62 | } |
41 | } | 63 | } |
42 | 64 | ||
65 | +watch( | ||
66 | + () => props.optionData.pages, | ||
67 | + (newData: any) => { | ||
68 | + getConfigurationOptions({ page: newData.page, pageSize: newData.pageSize }) | ||
69 | + }, | ||
70 | + { | ||
71 | + deep: true, | ||
72 | + immediate: true | ||
73 | + } | ||
74 | +) | ||
75 | + | ||
43 | onMounted(() => { | 76 | onMounted(() => { |
44 | - getConfigurationOptions({ page: 1, pageSize: 10 }) | 77 | + getConfigurationOptions({ page: props.optionData.pages.page, pageSize: props.optionData.pages.pageSize }) |
45 | }) | 78 | }) |
46 | </script> | 79 | </script> |
@@ -3,9 +3,9 @@ | @@ -3,9 +3,9 @@ | ||
3 | <div v-show="isShowSvg" @click="handleFullScreen" id="fullscreenButton"> | 3 | <div v-show="isShowSvg" @click="handleFullScreen" id="fullscreenButton"> |
4 | <svg | 4 | <svg |
5 | focusable="false" | 5 | focusable="false" |
6 | - class="" | ||
7 | data-icon="fullscreen" | 6 | data-icon="fullscreen" |
8 | width="4vw" | 7 | width="4vw" |
8 | + :style="`color:${color}`" | ||
9 | height="4vh" | 9 | height="4vh" |
10 | fill="currentColor" | 10 | fill="currentColor" |
11 | aria-hidden="true" | 11 | aria-hidden="true" |
@@ -35,8 +35,7 @@ import { useChartDataFetch } from '@/hooks' | @@ -35,8 +35,7 @@ import { useChartDataFetch } from '@/hooks' | ||
35 | import { CreateComponentType } from '@/packages/index.d' | 35 | import { CreateComponentType } from '@/packages/index.d' |
36 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | 36 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
37 | import { useFullScreen } from '@/packages/components/external/Charts/utls/fullScreen' | 37 | import { useFullScreen } from '@/packages/components/external/Charts/utls/fullScreen' |
38 | -import { isDevMode } from '@/utils/external/env'; | ||
39 | - | 38 | +import { isDevMode } from '@/utils/external/env' |
40 | 39 | ||
41 | const props = defineProps({ | 40 | const props = defineProps({ |
42 | chartConfig: { | 41 | chartConfig: { |
@@ -50,7 +49,7 @@ const isShowSvg = ref(false) | @@ -50,7 +49,7 @@ const isShowSvg = ref(false) | ||
50 | const allowfullscreen = ref(false) | 49 | const allowfullscreen = ref(false) |
51 | 50 | ||
52 | const { w, h } = toRefs(props.chartConfig.attr) | 51 | const { w, h } = toRefs(props.chartConfig.attr) |
53 | -const { borderRadius } = toRefs(props.chartConfig.option) | 52 | +const { borderRadius, color } = toRefs(props.chartConfig.option) |
54 | 53 | ||
55 | const option = shallowReactive({ | 54 | const option = shallowReactive({ |
56 | dataset: '' | 55 | dataset: '' |
@@ -63,7 +62,7 @@ const getStyle = (radius: number) => { | @@ -63,7 +62,7 @@ const getStyle = (radius: number) => { | ||
63 | } | 62 | } |
64 | } | 63 | } |
65 | 64 | ||
66 | -const isDev = isDevMode(); | 65 | +const isDev = isDevMode() |
67 | 66 | ||
68 | // 编辑更新 | 67 | // 编辑更新 |
69 | watch( | 68 | watch( |
@@ -72,7 +71,9 @@ watch( | @@ -72,7 +71,9 @@ watch( | ||
72 | const currentHost = window.location.host | 71 | const currentHost = window.location.host |
73 | const currentProtocol = window.location.protocol | 72 | const currentProtocol = window.location.protocol |
74 | //预览 | 73 | //预览 |
75 | - option.dataset = `${currentProtocol}//${currentHost}/thingskit-scada/${isDev ? '?dev=1&' : '?'}configurationId=${newData}&lightbox=1` | 74 | + option.dataset = `${currentProtocol}//${currentHost}/thingskit-scada/${ |
75 | + isDev ? '?dev=1&' : '?' | ||
76 | + }configurationId=${newData}&lightbox=1` | ||
76 | }, | 77 | }, |
77 | { | 78 | { |
78 | immediate: true | 79 | immediate: true |
@@ -6,13 +6,13 @@ import cloneDeep from 'lodash/cloneDeep' | @@ -6,13 +6,13 @@ import cloneDeep from 'lodash/cloneDeep' | ||
6 | 6 | ||
7 | export const option = { | 7 | export const option = { |
8 | // 网站路径 | 8 | // 网站路径 |
9 | - dataset: "https://www.thingskit.com/", | 9 | + dataset: 'https://www.thingskit.com/', |
10 | // 圆角 | 10 | // 圆角 |
11 | - borderRadius: 10 | 11 | + borderRadius: 10, |
12 | + color: 'black' | ||
12 | } | 13 | } |
13 | 14 | ||
14 | -export default class Config extends PublicConfigClass implements CreateComponentType | ||
15 | -{ | 15 | +export default class Config extends PublicConfigClass implements CreateComponentType { |
16 | public key = OverrideIframeConfig.key | 16 | public key = OverrideIframeConfig.key |
17 | public attr = { ...chartInitConfig, w: 1200, h: 800, zIndex: -1 } | 17 | public attr = { ...chartInitConfig, w: 1200, h: 800, zIndex: -1 } |
18 | public chartConfig = cloneDeep(OverrideIframeConfig) | 18 | public chartConfig = cloneDeep(OverrideIframeConfig) |
@@ -15,22 +15,26 @@ | @@ -15,22 +15,26 @@ | ||
15 | ></n-input-number> | 15 | ></n-input-number> |
16 | </setting-item> | 16 | </setting-item> |
17 | </setting-item-box> | 17 | </setting-item-box> |
18 | + <setting-item-box name="颜色" :alone="true"> | ||
19 | + <SettingItem name="颜色"> | ||
20 | + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.color"></n-color-picker> | ||
21 | + </SettingItem> | ||
22 | + <SettingItem> | ||
23 | + <n-button size="small" @click="optionData.color = 'black'"> 恢复默认 </n-button> | ||
24 | + </SettingItem> | ||
25 | + </setting-item-box> | ||
18 | </collapse-item> | 26 | </collapse-item> |
19 | </template> | 27 | </template> |
20 | 28 | ||
21 | <script setup lang="ts"> | 29 | <script setup lang="ts"> |
22 | -import { PropType } from "vue"; | ||
23 | -import { option } from "./config"; | ||
24 | -import { | ||
25 | - CollapseItem, | ||
26 | - SettingItemBox, | ||
27 | - SettingItem, | ||
28 | -} from "@/components/Pages/ChartItemSetting"; | 30 | +import { PropType } from 'vue' |
31 | +import { option } from './config' | ||
32 | +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
29 | 33 | ||
30 | const props = defineProps({ | 34 | const props = defineProps({ |
31 | optionData: { | 35 | optionData: { |
32 | type: Object as PropType<typeof option>, | 36 | type: Object as PropType<typeof option>, |
33 | - required: true, | ||
34 | - }, | ||
35 | -}); | 37 | + required: true |
38 | + } | ||
39 | +}) | ||
36 | </script> | 40 | </script> |
@@ -3,9 +3,9 @@ | @@ -3,9 +3,9 @@ | ||
3 | <div v-show="isShowSvg" @click="handleFullScreen" id="fullscreenButton"> | 3 | <div v-show="isShowSvg" @click="handleFullScreen" id="fullscreenButton"> |
4 | <svg | 4 | <svg |
5 | focusable="false" | 5 | focusable="false" |
6 | - class="" | ||
7 | data-icon="fullscreen" | 6 | data-icon="fullscreen" |
8 | width="4vw" | 7 | width="4vw" |
8 | + :style="`color:${color}`" | ||
9 | height="4vh" | 9 | height="4vh" |
10 | fill="currentColor" | 10 | fill="currentColor" |
11 | aria-hidden="true" | 11 | aria-hidden="true" |
@@ -48,7 +48,7 @@ const isShowSvg = ref(false) | @@ -48,7 +48,7 @@ const isShowSvg = ref(false) | ||
48 | const allowfullscreen = ref(false) | 48 | const allowfullscreen = ref(false) |
49 | 49 | ||
50 | const { w, h } = toRefs(props.chartConfig.attr) | 50 | const { w, h } = toRefs(props.chartConfig.attr) |
51 | -const { borderRadius } = toRefs(props.chartConfig.option) | 51 | +const { borderRadius, color } = toRefs(props.chartConfig.option) |
52 | 52 | ||
53 | const option = shallowReactive({ | 53 | const option = shallowReactive({ |
54 | dataset: '' | 54 | dataset: '' |
1 | +import { PublicConfigClass } from '@/packages/public' | ||
2 | +import { CreateComponentType } from '@/packages/index.d' | ||
3 | +import { OverrideVideoConfig } from './index' | ||
4 | +import cloneDeep from 'lodash/cloneDeep' | ||
5 | +import video from '@/assets/videos/earth.mp4' | ||
6 | + | ||
7 | +export const option = { | ||
8 | + // 视频路径 | ||
9 | + dataset: video, | ||
10 | + // 循环播放 | ||
11 | + loop: true, | ||
12 | + // 静音 | ||
13 | + muted: true, | ||
14 | + // 适应方式 | ||
15 | + fit: 'contain', | ||
16 | + // 圆角 | ||
17 | + borderRadius: 10 | ||
18 | +} | ||
19 | + | ||
20 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
21 | + public key = OverrideVideoConfig.key | ||
22 | + public chartConfig = cloneDeep(OverrideVideoConfig) | ||
23 | + public option = cloneDeep(option) | ||
24 | +} |
1 | +<!-- eslint-disable vue/multi-word-component-names --> | ||
2 | +<!-- eslint-disable vue/no-mutating-props --> | ||
3 | +<template> | ||
4 | + <collapse-item name="视频" expanded> | ||
5 | + <setting-item-box name="源" alone> | ||
6 | + <FileUpload | ||
7 | + :fileSizeConst="fileSizeConst" | ||
8 | + :max="1" | ||
9 | + :threeSupportFileFormat="supportVideoType" | ||
10 | + @fileStaticUri="handleFileStaticUri" | ||
11 | + /> | ||
12 | + </setting-item-box> | ||
13 | + <setting-item-box name="控制"> | ||
14 | + <setting-item> | ||
15 | + <n-checkbox v-model:checked="optionData.loop" size="small">循环播放</n-checkbox> | ||
16 | + </setting-item> | ||
17 | + <setting-item> | ||
18 | + <n-checkbox v-model:checked="optionData.muted" size="small">静音</n-checkbox> | ||
19 | + </setting-item> | ||
20 | + </setting-item-box> | ||
21 | + | ||
22 | + <setting-item-box name="样式"> | ||
23 | + <setting-item name="类型"> | ||
24 | + <n-select v-model:value="optionData.fit" size="small" :options="fitList"></n-select> | ||
25 | + </setting-item> | ||
26 | + </setting-item-box> | ||
27 | + </collapse-item> | ||
28 | +</template> | ||
29 | + | ||
30 | +<script setup lang="ts"> | ||
31 | +import { PropType, ref } from 'vue' | ||
32 | +import { option } from './config' | ||
33 | +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
34 | +import FileUpload from '../../../Composes/Mores/ThreeDimensional/components/FileUpload.vue' | ||
35 | +import type { UploadFileInfo } from 'naive-ui' | ||
36 | + | ||
37 | +//视频类型 | ||
38 | +const supportVideoType = ['mp4'] | ||
39 | + | ||
40 | +const fileSizeConst = ref(100) | ||
41 | + | ||
42 | +// 适应类型 | ||
43 | +const fitList = [ | ||
44 | + { | ||
45 | + value: 'fill', | ||
46 | + label: 'fill' | ||
47 | + }, | ||
48 | + { | ||
49 | + value: 'contain', | ||
50 | + label: 'contain' | ||
51 | + }, | ||
52 | + { | ||
53 | + value: 'cover', | ||
54 | + label: 'cover' | ||
55 | + }, | ||
56 | + { | ||
57 | + value: 'scale-down', | ||
58 | + label: 'scale-down' | ||
59 | + }, | ||
60 | + { | ||
61 | + value: 'none', | ||
62 | + label: 'none' | ||
63 | + } | ||
64 | +] | ||
65 | + | ||
66 | +const props = defineProps({ | ||
67 | + optionData: { | ||
68 | + type: Object as PropType<typeof option>, | ||
69 | + required: true | ||
70 | + } | ||
71 | +}) | ||
72 | + | ||
73 | +const handleFileStaticUri = (value: UploadFileInfo[]) => { | ||
74 | + props.optionData.dataset = value[0]?.url as string | ||
75 | +} | ||
76 | +</script> |
1 | +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' | ||
2 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Informations/index.d' | ||
3 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | ||
4 | + | ||
5 | +const { key, conKey, chartKey } = useWidgetKey('OverrideVideo', true) | ||
6 | + | ||
7 | +export const OverrideVideoConfig: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: '自定义视频', | ||
12 | + category: ChatCategoryEnum.MORE, | ||
13 | + categoryName: ChatCategoryEnumName.MORE, | ||
14 | + package: PackagesCategoryEnum.INFORMATIONS, | ||
15 | + chartFrame: ChartFrameEnum.COMMON, | ||
16 | + image: 'video.png' | ||
17 | +} |
1 | +<!-- eslint-disable vue/multi-word-component-names --> | ||
2 | +<template> | ||
3 | + <!-- 重要:需要设置 crossOrigin="anonymous",否则保存画板缩略图会失败 --> | ||
4 | + <video | ||
5 | + ref="vVideoRef" | ||
6 | + class="go-video" | ||
7 | + preload="auto" | ||
8 | + crossOrigin="anonymous" | ||
9 | + playsinline | ||
10 | + autoplay | ||
11 | + :loop="option.loop" | ||
12 | + :muted="option.muted" | ||
13 | + :width="w" | ||
14 | + :height="h" | ||
15 | + :src="option.dataset" | ||
16 | + controls | ||
17 | + ></video> | ||
18 | +</template> | ||
19 | + | ||
20 | +<script setup lang="ts"> | ||
21 | +import { PropType, toRefs, shallowReactive, watch, ref } from 'vue' | ||
22 | +import { useChartDataFetch } from '@/hooks' | ||
23 | +import { CreateComponentType } from '@/packages/index.d' | ||
24 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
25 | +import { option as configOption } from './config' | ||
26 | + | ||
27 | +const props = defineProps({ | ||
28 | + chartConfig: { | ||
29 | + type: Object as PropType<CreateComponentType>, | ||
30 | + required: true | ||
31 | + } | ||
32 | +}) | ||
33 | + | ||
34 | +const { w, h } = toRefs(props.chartConfig.attr) | ||
35 | +let option = shallowReactive({ ...configOption }) | ||
36 | + | ||
37 | +// 预览更新 | ||
38 | +const vVideoRef = ref(null) | ||
39 | +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => { | ||
40 | + option = newData | ||
41 | +}) | ||
42 | + | ||
43 | +// 编辑更新 | ||
44 | +watch( | ||
45 | + () => props.chartConfig.option, | ||
46 | + (newData: any) => { | ||
47 | + option = newData | ||
48 | + if (!vVideoRef.value) return | ||
49 | + const video: any = vVideoRef.value | ||
50 | + video.loop = option.loop | ||
51 | + video.muted = option.muted | ||
52 | + video.play() | ||
53 | + }, | ||
54 | + { | ||
55 | + immediate: true, | ||
56 | + deep: true | ||
57 | + } | ||
58 | +) | ||
59 | +</script> | ||
60 | + | ||
61 | +<style lang="scss" scoped> | ||
62 | +@include go('video') { | ||
63 | + display: block; | ||
64 | + object-fit: v-bind('option.fit'); | ||
65 | +} | ||
66 | +</style> |
@@ -20,6 +20,7 @@ import { OverrideProcessConfig } from '@/packages/components/external/Charts/Mor | @@ -20,6 +20,7 @@ import { OverrideProcessConfig } from '@/packages/components/external/Charts/Mor | ||
20 | import { OverridePieCircleConfig } from '@/packages/components/external/Charts/Pies/OverridePieCircle' | 20 | import { OverridePieCircleConfig } from '@/packages/components/external/Charts/Pies/OverridePieCircle' |
21 | import { OverrideMapBaseConfig } from '@/packages/components/external/Charts/Maps/OverrideMapBase' | 21 | import { OverrideMapBaseConfig } from '@/packages/components/external/Charts/Maps/OverrideMapBase' |
22 | import { OverrideILoadConfigurationframeConfig } from '@/packages/components/external/Informations/Mores/OverrideILoadConfigurationframe' | 22 | import { OverrideILoadConfigurationframeConfig } from '@/packages/components/external/Informations/Mores/OverrideILoadConfigurationframe' |
23 | +import { OverrideVideoConfig } from '@/packages/components/external/Informations/Mores/OverrideVideo' | ||
23 | 24 | ||
24 | export function useInjectLib(packagesList: EPackagesType) { | 25 | export function useInjectLib(packagesList: EPackagesType) { |
25 | packagesList[EPackagesCategoryEnum.COMPOSES] = ComposesList | 26 | packagesList[EPackagesCategoryEnum.COMPOSES] = ComposesList |
@@ -43,6 +44,7 @@ export function useInjectLib(packagesList: EPackagesType) { | @@ -43,6 +44,7 @@ export function useInjectLib(packagesList: EPackagesType) { | ||
43 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverridePieCircleConfig) | 44 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverridePieCircleConfig) |
44 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideMapBaseConfig) | 45 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideMapBaseConfig) |
45 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideILoadConfigurationframeConfig) | 46 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideILoadConfigurationframeConfig) |
47 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideVideoConfig) | ||
46 | } | 48 | } |
47 | 49 | ||
48 | /** | 50 | /** |