Commit ed3194e378e5d8016e7f5eb62195daac85a57b6b

Authored by xp.Huang
2 parents 6e66512c 5fa02845

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
... ... @@ -14,7 +14,7 @@ export const enum areaEnum {
14 14 export const includes = []
15 15
16 16 export const option = {
17   - drillingIn:false,
  17 + drillingIn: false,
18 18 dataset: dataJson,
19 19 mapRegion: {
20 20 adcode: 'china',
... ... @@ -152,7 +152,7 @@ export const option = {
152 152 shadowOffsetY: 2,
153 153 shadowBlur: 10
154 154 }
155   - }
  155 + },
156 156 ]
157 157 }
158 158 export const MapDefaultConfig = { ...option }
... ...
... ... @@ -27,6 +27,8 @@ import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
27 27 import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
28 28 import cityMap from './mapGeojson/china-main-city-map.json'
29 29
  30 +type historyDataType = { name: string; code: string }
  31 +
30 32 const props = defineProps({
31 33 themeSetting: {
32 34 type: Object,
... ... @@ -57,6 +59,12 @@ use([
57 59
58 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 68 const option = reactive({
61 69 value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
62 70 })
... ... @@ -68,7 +76,7 @@ const toolBoxOption = {
68 76 myFullButton: {
69 77 show: true,
70 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 80 onclick: () => watchAdcode()
73 81 }
74 82 }
... ... @@ -79,10 +87,12 @@ props.chartConfig.option = {
79 87 ...{ toolbox: toolBoxOption }
80 88 }
81 89
  90 +//地图点击返回
82 91 const watchAdcode = () => {
83 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 100
91 101 //动态获取json注册地图
92 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 213 const { name } = params
200 214 saveSelectValue.value = name
201 215 const findAdcode = (cityMap as any)[name]
  216 + if (!findAdcode) return
202 217 props.chartConfig.option.mapRegion.adcode = findAdcode
  218 + historyData.value.push({
  219 + name,
  220 + code: findAdcode
  221 + })
203 222 }
204 223 }
205 224 </script>
... ...
1 1 <template>
2 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 11 <source :src="path" />
5 12 </video>
6 13 </div>
7 14 </template>
8 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 17 import videojs, { VideoJsPlayer } from 'video.js'
11 18 import type { VideoJsPlayerOptions } from 'video.js'
12 19 import 'video.js/dist/video-js.css'
... ... @@ -17,6 +24,7 @@ const props = withDefaults(
17 24 path: string
18 25 autoPlay?: boolean
19 26 h?: number
  27 + poster?: string
20 28 }>(),
21 29 { autoPlay: false }
22 30 )
... ... @@ -33,19 +41,22 @@ const initPlay = async () => {
33 41 controls: true,
34 42 autoplay: props.autoPlay,
35 43 src: props?.path,
  44 + poster: props?.poster,
36 45 language: 'zh-CN',
37   - techOrder: ['html5']
  46 + techOrder: ['html5'],
  47 + preload: 'none'
38 48 }
39 49 player = videojs(videoRef.value, options, () => {
40   - videojs.log('播放器已经准备好了!')
  50 + videojs.log('Video is reading')
41 51 if (props.autoPlay) {
42 52 player.play()
43 53 }
44 54 player.on('ended', () => {
45   - videojs.log('播放结束了!')
  55 + videojs.log('Play end')
46 56 })
47 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 69 watch(
59 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 76 player?.play()
66 77 }
67 78 },
... ... @@ -74,11 +85,15 @@ onBeforeUnmount(() => {
74 85 player?.dispose()
75 86 })
76 87 </script>
  88 +<style>
  89 +.vjs-poster {
  90 + background-size: cover !important;
  91 +}
  92 +</style>
77 93 <style lang="scss" scoped>
78 94 .videoPlay {
79 95 flex: 1;
80 96 height: v-bind('`${h}px`');
81   -
82 97 .video-js {
83 98 height: 100%;
84 99 width: 100%;
... ...
... ... @@ -6,6 +6,7 @@ import cloneDeep from 'lodash/cloneDeep'
6 6 export const option = {
7 7 dataset: '',
8 8 autoplay: false,
  9 + poster: ''
9 10 }
10 11
11 12 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
1 1 <template>
2 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 25 <setting-item-box name="源地址" :alone="true">
4 26 <setting-item>
5 27 <n-input-group>
... ... @@ -16,14 +38,94 @@
16 38 </template>
17 39
18 40 <script setup lang="ts">
19   -import { PropType } from 'vue'
  41 +import { PropType, ref, nextTick } from 'vue'
20 42 import { option } from './config'
21 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 51 optionData: {
25 52 type: Object as PropType<typeof option>,
26 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 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 1 <template>
2 2 <div>
3   - <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" />
  3 + <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" :poster="option.poster" />
4 4 </div>
5 5 </template>
6 6 <script setup lang="ts">
... ... @@ -18,10 +18,11 @@ const props = defineProps({
18 18
19 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 23 const option = shallowReactive({
24   - dataset: configOption.dataset
  24 + dataset: configOption.dataset,
  25 + poster: configOption.poster
25 26 })
26 27
27 28 watch(
... ... @@ -30,7 +31,17 @@ watch(
30 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 47 </script>
... ...
1 1 <script lang="ts" setup name="WeatherContent">
2   -import { toRefs } from 'vue'
  2 +import { toRefs, PropType, computed } from 'vue'
3 3 import SelectCity from './SelectCity.vue'
4 4 import { useUtils } from '../hooks/useUtils'
5 5 import weatherBg from '@/assets/external/weather/bg.png'
  6 +import { weatherInfoInterface, selectValueType } from '../config'
6 7
7 8 const props = defineProps({
8 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 18
17 19 const { casts } = toRefs(props.data[0])
18 20
19   -const onHandleSelectValues = (values: any) => {
  21 +const onHandleSelectValues = (values: selectValueType) => {
20 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 41 </script>
23 42
24 43 <template>
25 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 46 <template #header>
35 47 <div class="card-header">
36 48 <div class="city-text">{{ data[0]?.city }}</div>
... ... @@ -59,7 +71,7 @@ const onHandleSelectValues = (values: any) => {
59 71 </div>
60 72 <template #footer>
61 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 75 <div>
64 76 <img :src="loadWeatherImg(item?.dayweather)" />
65 77 </div>
... ...
... ... @@ -7,6 +7,8 @@ import clearDay from '@/assets/external/weather/clearDay.png'
7 7 import cloudy from '@/assets/external/weather/cloudy.png'
8 8 import cloudyDay from '@/assets/external/weather/cloudyDay.png'
9 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 13 //第三方 天气接口key值和api配置(高德)
12 14 export class ThirdPartyWeatherConnfig {
... ... @@ -23,7 +25,7 @@ export const enum areaEnum {
23 25 COUNTY = 'COUNTY'
24 26 }
25 27
26   -//天气文字映射图片
  28 +//天气文字图片映射
27 29 export const weatherTextMapImg = [
28 30 {
29 31 text: '晴',
... ... @@ -40,10 +42,17 @@ export const weatherTextMapImg = [
40 42 {
41 43 text: '小雨',
42 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 57 export const weatherSpeedMapText = [
49 58 {
... ... @@ -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 142 export const option = {
104 143 dataset: {
105 144 provinceValue: null,
... ...
... ... @@ -6,6 +6,8 @@
6 6 <SettingItem name="颜色">
7 7 <n-color-picker v-model:value="optionData.weatherCss.backgroundColor" />
8 8 </SettingItem>
  9 + </SettingItemBox>
  10 + <SettingItemBox name="背景">
9 11 <SettingItem>
10 12 <n-button size="small" @click="optionData.weatherCss.backgroundColor = 'transparent'"> 恢复默认颜色 </n-button>
11 13 </SettingItem>
... ... @@ -73,7 +75,7 @@
73 75 <script setup lang="ts">
74 76 import { PropType } from 'vue'
75 77 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
76   -import { option } from './config'
  78 +import { option, selectValueType } from './config'
77 79 import SelectCity from './componnets/SelectCity.vue'
78 80
79 81 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 89 props.optionData.dataset = values
88 90 }
89 91 </script>
... ...
1   -import { weatherSpeedMapText, weatherTextMapImg } from '../config'
  1 +import { weatherSpeedMapText, weatherTextMapImg, weatherTextMapType } from '../config'
2 2 import clearDay from '@/assets/external/weather/clearDay.png'
3 3
4 4 export const useUtils = () => {
5 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 9 //风力等级 ≤3 3
... ... @@ -14,7 +14,7 @@ export const useUtils = () => {
14 14 } else {
15 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 19 return {
20 20 loadWeatherImg,
... ...
1 1 <script lang="ts" setup name="Weather">
2 2 import { PropType, toRefs, onMounted, reactive, watch } from 'vue'
3 3 import { CreateComponentType } from '@/packages/index.d'
4   -import { option, ThirdPartyWeatherConnfig } from './config'
  4 +import { option, ThirdPartyWeatherConnfig, selectValueType, weatherInfoInterface } from './config'
5 5 import axios from 'axios'
6 6 import WeatherContent from './componnets/WeatherContent.vue'
7 7 import { useUtils } from './hooks/useUtils'
... ... @@ -19,11 +19,15 @@ const { w, h } = toRefs(props.chartConfig.attr)
19 19
20 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 27 weatherInfo: []
24 28 })
25 29
26   -const getWeatherInfos = async (area: any) => {
  30 +const getWeatherInfos = async (area: selectValueType) => {
27 31 const { cityValue, countyValue } = area || props.chartConfig.option.dataset
28 32 const params = {
29 33 key: ThirdPartyWeatherConnfig.ak,
... ... @@ -52,7 +56,7 @@ watch(
52 56 }
53 57 )
54 58
55   -const onHandleSelectValues = (values: any) => {
  59 +const onHandleSelectValues = (values: selectValueType) => {
56 60 getWeatherInfos(values)
57 61 }
58 62 </script>
... ...
... ... @@ -6,13 +6,17 @@ import cloneDeep from 'lodash/cloneDeep'
6 6
7 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 20 public key = OverrideILoadConfigurationframeConfig.key
17 21 public attr = { ...chartInitConfig, w: 1200, h: 800, zIndex: -1 }
18 22 public chartConfig = cloneDeep(OverrideILoadConfigurationframeConfig)
... ...
... ... @@ -15,16 +15,38 @@
15 15 ></n-input-number>
16 16 </setting-item>
17 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 40 </collapse-item>
19 41 </template>
20 42
21 43 <script setup lang="ts">
22   -import { PropType, onMounted, ref } from 'vue'
  44 +import { PropType, onMounted, ref, watch } from 'vue'
23 45 import { option } from './config'
24 46 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
25 47 import { getConfigurationList } from '@/api/external/common/index'
26 48
27   -defineProps({
  49 +const props = defineProps({
28 50 optionData: {
29 51 type: Object as PropType<typeof option>,
30 52 required: true
... ... @@ -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 76 onMounted(() => {
44   - getConfigurationOptions({ page: 1, pageSize: 10 })
  77 + getConfigurationOptions({ page: props.optionData.pages.page, pageSize: props.optionData.pages.pageSize })
45 78 })
46 79 </script>
... ...
... ... @@ -3,9 +3,9 @@
3 3 <div v-show="isShowSvg" @click="handleFullScreen" id="fullscreenButton">
4 4 <svg
5 5 focusable="false"
6   - class=""
7 6 data-icon="fullscreen"
8 7 width="4vw"
  8 + :style="`color:${color}`"
9 9 height="4vh"
10 10 fill="currentColor"
11 11 aria-hidden="true"
... ... @@ -35,8 +35,7 @@ import { useChartDataFetch } from '@/hooks'
35 35 import { CreateComponentType } from '@/packages/index.d'
36 36 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
37 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 40 const props = defineProps({
42 41 chartConfig: {
... ... @@ -50,7 +49,7 @@ const isShowSvg = ref(false)
50 49 const allowfullscreen = ref(false)
51 50
52 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 54 const option = shallowReactive({
56 55 dataset: ''
... ... @@ -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 68 watch(
... ... @@ -72,7 +71,9 @@ watch(
72 71 const currentHost = window.location.host
73 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 79 immediate: true
... ...
... ... @@ -6,13 +6,13 @@ import cloneDeep from 'lodash/cloneDeep'
6 6
7 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 16 public key = OverrideIframeConfig.key
17 17 public attr = { ...chartInitConfig, w: 1200, h: 800, zIndex: -1 }
18 18 public chartConfig = cloneDeep(OverrideIframeConfig)
... ...
... ... @@ -15,22 +15,26 @@
15 15 ></n-input-number>
16 16 </setting-item>
17 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 26 </collapse-item>
19 27 </template>
20 28
21 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 34 const props = defineProps({
31 35 optionData: {
32 36 type: Object as PropType<typeof option>,
33   - required: true,
34   - },
35   -});
  37 + required: true
  38 + }
  39 +})
36 40 </script>
... ...
... ... @@ -3,9 +3,9 @@
3 3 <div v-show="isShowSvg" @click="handleFullScreen" id="fullscreenButton">
4 4 <svg
5 5 focusable="false"
6   - class=""
7 6 data-icon="fullscreen"
8 7 width="4vw"
  8 + :style="`color:${color}`"
9 9 height="4vh"
10 10 fill="currentColor"
11 11 aria-hidden="true"
... ... @@ -48,7 +48,7 @@ const isShowSvg = ref(false)
48 48 const allowfullscreen = ref(false)
49 49
50 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 53 const option = shallowReactive({
54 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 20 import { OverridePieCircleConfig } from '@/packages/components/external/Charts/Pies/OverridePieCircle'
21 21 import { OverrideMapBaseConfig } from '@/packages/components/external/Charts/Maps/OverrideMapBase'
22 22 import { OverrideILoadConfigurationframeConfig } from '@/packages/components/external/Informations/Mores/OverrideILoadConfigurationframe'
  23 +import { OverrideVideoConfig } from '@/packages/components/external/Informations/Mores/OverrideVideo'
23 24
24 25 export function useInjectLib(packagesList: EPackagesType) {
25 26 packagesList[EPackagesCategoryEnum.COMPOSES] = ComposesList
... ... @@ -43,6 +44,7 @@ export function useInjectLib(packagesList: EPackagesType) {
43 44 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverridePieCircleConfig)
44 45 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideMapBaseConfig)
45 46 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideILoadConfigurationframeConfig)
  47 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideVideoConfig)
46 48 }
47 49
48 50 /**
... ...