Commit c09bf9d9c11fabd1112bdcaaafe6279b818f777f

Authored by fengwotao
1 parent 5e6df27d

feat(src/packages): 优化封装上传图片组件,移除重复代码

  1 +import TKUpload from './index.vue';
  2 +
  3 +export { TKUpload };
  1 +<template>
  2 + <n-upload
  3 + v-model:file-list="fileList"
  4 + :show-file-list="true"
  5 + :customRequest="customRequest"
  6 + :onBeforeUpload="beforeUploadHandle"
  7 + :onRemove="remove"
  8 + >
  9 + <n-upload-dragger>
  10 + <img v-if="uploadImageUrl" class="upload-show" :src="uploadImageUrl" alt="上传的图片" />
  11 + <div class="upload-img" v-show="!uploadImageUrl">
  12 + <img src="@/assets/images/canvas/noImage.png" />
  13 + <n-text class="upload-desc" depth="3">
  14 + 上传文件需小于 {{ uploadSizeFormat.size }}M ,格式为 {{ uploadSizeFormat.format }} 的文件
  15 + </n-text>
  16 + </div>
  17 + </n-upload-dragger>
  18 + </n-upload>
  19 +</template>
  20 +
  21 +<script lang="ts" setup name="TKUpload">
  22 +import { ref, PropType, nextTick } from 'vue'
  23 +import type { UploadCustomRequestOptions, UploadFileInfo } from 'naive-ui'
  24 +import { fetchRouteParamsLocation } from '@/utils'
  25 +import { uploadFile } from '@/api/external/contentSave/content'
  26 +import { FileTypeEnum } from '@/enums/external/fileTypeEnum'
  27 +
  28 +interface uploadSizeFormatIF {
  29 + size: number
  30 + format: string
  31 +}
  32 +
  33 +const props = defineProps({
  34 + uploadImageUrl: {
  35 + type: String as PropType<string>,
  36 + default: ''
  37 + },
  38 + uploadSizeFormat: {
  39 + type: Object as PropType<uploadSizeFormatIF>,
  40 + default: () => ({
  41 + size: 5,
  42 + format: 'png/jpg/jpeg/gif'
  43 + })
  44 + }
  45 +})
  46 +
  47 +const emit = defineEmits(['sendFile', 'removeFile'])
  48 +
  49 +const fileList = ref<UploadFileInfo[]>()
  50 +
  51 +// 自定义上传操作
  52 +const customRequest = (options: UploadCustomRequestOptions) => {
  53 + const { file } = options
  54 + nextTick(async () => {
  55 + if (file.file) {
  56 + const newNameFile = new File([file.file], `${fetchRouteParamsLocation()}_index_upload.png`, {
  57 + type: file.file.type
  58 + })
  59 + let uploadParams = new FormData()
  60 + uploadParams.append('file', newNameFile)
  61 + const uploadRes = await uploadFile(uploadParams)
  62 + if (!uploadRes) return
  63 + emit('sendFile', uploadRes?.fileStaticUri)
  64 + window['$message'].success('上传文件成功!')
  65 + } else {
  66 + window['$message'].error('上传文件失败,请稍后重试!')
  67 + }
  68 + })
  69 +}
  70 +
  71 +// 文件上传前置处理
  72 +const beforeUploadHandle = (file: UploadFileInfo) => {
  73 + fileList.value = []
  74 + const type = file.file?.type
  75 + const size = file.file?.size as number
  76 + const typeSuffix = type?.split('/')?.at(-1)?.toUpperCase() as keyof typeof FileTypeEnum
  77 + if (size > 1024 * 1024 * props.uploadSizeFormat.size) {
  78 + window['$message'].warning(`文件超出 ${props.uploadSizeFormat.size}M限制,请重新上传!`)
  79 + return false
  80 + }
  81 + if (!FileTypeEnum[typeSuffix]) {
  82 + window['$message'].warning('文件格式不符合,请重新上传!')
  83 + return false
  84 + }
  85 + return true
  86 +}
  87 +
  88 +//单个点击删除
  89 +const remove = () => {
  90 + fileList.value = []
  91 + emit('removeFile', true)
  92 +}
  93 +</script>
  94 +
  95 +<style lang="scss" scoped>
  96 +$uploadHeight: 193px;
  97 +@include deep() {
  98 + .n-card__content {
  99 + padding: 0;
  100 + overflow: hidden;
  101 + }
  102 + .n-upload-dragger {
  103 + padding: 5px;
  104 + }
  105 +}
  106 +.upload-show {
  107 + width: -webkit-fill-available;
  108 + height: $uploadHeight;
  109 + border-radius: 5px;
  110 +}
  111 +.upload-img {
  112 + display: flex;
  113 + flex-direction: column;
  114 + align-items: center;
  115 + img {
  116 + height: 150px;
  117 + }
  118 + .upload-desc {
  119 + padding: 10px 0;
  120 + }
  121 +}
  122 +</style>
  1 +// 文件上传时的格式映射
  2 +export enum FileTypeEnum {
  3 + // 文档
  4 + TXT = 'text/plain',
  5 + JSON = 'application/json',
  6 + // 图片
  7 + PNG = 'image/png',
  8 + JPEG = 'image/jpeg',
  9 + JPG = 'image/jpg',
  10 + GIF = 'image/gif',
  11 +}
@@ -2,24 +2,11 @@ @@ -2,24 +2,11 @@
2 <collapse-item name="属性" :expanded="true"> 2 <collapse-item name="属性" :expanded="true">
3 <setting-item-box name="上传图片" :alone="true"> 3 <setting-item-box name="上传图片" :alone="true">
4 <setting-item> 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.dataset" class="upload-show" :src="optionData.dataset" alt="背景" />  
14 - <div class="upload-img" v-show="!optionData.dataset">  
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> 5 + <TKUpload
  6 + :uploadImageUrl="props.optionData.dataset"
  7 + @sendFile="handleSendFile"
  8 + @removeFile="handleRemoveFile"
  9 + />
23 </setting-item> 10 </setting-item>
24 </setting-item-box> 11 </setting-item-box>
25 <setting-item-box name="样式"> 12 <setting-item-box name="样式">
@@ -39,14 +26,10 @@ @@ -39,14 +26,10 @@
39 </template> 26 </template>
40 27
41 <script setup lang="ts"> 28 <script setup lang="ts">
42 -import { PropType, ref, nextTick } from 'vue' 29 +import { PropType } from 'vue'
43 import { option } from './config' 30 import { option } from './config'
44 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' 31 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
45 -import { FileTypeEnum } from '@/enums/fileTypeEnum'  
46 -import { uploadFile } from '@/api/external/contentSave/content'  
47 -import { UploadCustomRequestOptions } from 'naive-ui'  
48 -import { backgroundImageSize } from '@/settings/designSetting'  
49 -import { fetchRouteParamsLocation } from '@/utils' 32 +import { TKUpload } from '@/components/external/Common/TKUpload'
50 33
51 const props = defineProps({ 34 const props = defineProps({
52 optionData: { 35 optionData: {
@@ -55,48 +38,12 @@ const props = defineProps({ @@ -55,48 +38,12 @@ const props = defineProps({
55 } 38 }
56 }) 39 })
57 40
58 -const uploadFileListRef = ref()  
59 -  
60 -// 上传图片前置处理  
61 -// eslint-disable-next-line @typescript-eslint/ban-ts-comment  
62 -//@ts-ignore  
63 -const beforeUploadHandle = async ({ file }) => {  
64 - uploadFileListRef.value = []  
65 - const type = file.file.type  
66 - const size = file.file.size  
67 -  
68 - if (size > 1024 * 1024 * backgroundImageSize) {  
69 - window['$message'].warning(`图片超出 ${backgroundImageSize}M 限制,请重新上传!`)  
70 - return false  
71 - }  
72 - if (type !== FileTypeEnum.PNG && type !== FileTypeEnum.JPEG && type !== FileTypeEnum.GIF) {  
73 - window['$message'].warning('文件格式不符合,请重新上传!')  
74 - return false  
75 - }  
76 - return true 41 +const handleSendFile = (file: string) => {
  42 + if (!file) return
  43 + props.optionData.dataset = file
77 } 44 }
78 45
79 -// 自定义上传操作  
80 -const customRequest = (options: UploadCustomRequestOptions) => {  
81 - const { file } = options  
82 - nextTick(async () => {  
83 - if (file.file) {  
84 - // 修改名称  
85 - const newNameFile = new File([file.file], `${fetchRouteParamsLocation()}_index_background.png`, {  
86 - type: file.file.type  
87 - })  
88 - let uploadParams = new FormData()  
89 - uploadParams.append('file', newNameFile)  
90 - const uploadRes = await uploadFile(uploadParams)  
91 - if (uploadRes) {  
92 - props.optionData.dataset = uploadRes?.fileStaticUri  
93 - window['$message'].success('添加图片成功!')  
94 - }  
95 - } else {  
96 - window['$message'].error('添加图片失败,请稍后重试!')  
97 - }  
98 - })  
99 -} 46 +const handleRemoveFile = (status: boolean) => (status ? (props.optionData.dataset = '') : null)
100 47
101 // 适应类型 48 // 适应类型
102 const fitList = [ 49 const fitList = [
@@ -122,35 +69,3 @@ const fitList = [ @@ -122,35 +69,3 @@ const fitList = [
122 } 69 }
123 ] 70 ]
124 </script> 71 </script>
125 -<style lang="scss" scoped>  
126 -$uploadHeight: 193px;  
127 -.upload-box {  
128 - cursor: pointer;  
129 - margin-bottom: 20px;  
130 - @include deep() {  
131 - .n-card__content {  
132 - padding: 0;  
133 - overflow: hidden;  
134 - }  
135 - .n-upload-dragger {  
136 - padding: 5px;  
137 - }  
138 - }  
139 - .upload-show {  
140 - width: -webkit-fill-available;  
141 - height: $uploadHeight;  
142 - border-radius: 5px;  
143 - }  
144 - .upload-img {  
145 - display: flex;  
146 - flex-direction: column;  
147 - align-items: center;  
148 - img {  
149 - height: 150px;  
150 - }  
151 - .upload-desc {  
152 - padding: 10px 0;  
153 - }  
154 - }  
155 -}  
156 -</style>  
@@ -58,9 +58,7 @@ const isRtspProtocol = (url: string) => { @@ -58,9 +58,7 @@ const isRtspProtocol = (url: string) => {
58 const getVideoTypeByUrl = (url = '') => { 58 const getVideoTypeByUrl = (url = '') => {
59 try { 59 try {
60 const { protocol, pathname } = new URL(url) 60 const { protocol, pathname } = new URL(url)
61 -  
62 if (protocol.startsWith('rtsp:')) return VideoPlayerType.flv 61 if (protocol.startsWith('rtsp:')) return VideoPlayerType.flv
63 -  
64 const reg = /[^.]\w*$/ 62 const reg = /[^.]\w*$/
65 const mathValue = pathname.match(reg) || [] 63 const mathValue = pathname.match(reg) || []
66 const ext = (mathValue[0] as keyof typeof VideoPlayerType) || 'webm' 64 const ext = (mathValue[0] as keyof typeof VideoPlayerType) || 'webm'
@@ -112,11 +110,9 @@ const { getResult } = useFingerprint() @@ -112,11 +110,9 @@ const { getResult } = useFingerprint()
112 async function getSource() { 110 async function getSource() {
113 fingerprintResult.value = await getResult() 111 fingerprintResult.value = await getResult()
114 let src = props.sourceSrc || '' 112 let src = props.sourceSrc || ''
115 -  
116 if (isRtspProtocol(props.sourceSrc!)) { 113 if (isRtspProtocol(props.sourceSrc!)) {
117 src = getOpenFlvPlayUrl(src, unref(fingerprintResult)?.visitorId || '') 114 src = getOpenFlvPlayUrl(src, unref(fingerprintResult)?.visitorId || '')
118 } 115 }
119 -  
120 return [ 116 return [
121 { 117 {
122 type: getVideoTypeByUrl(props.sourceSrc), 118 type: getVideoTypeByUrl(props.sourceSrc),
@@ -2,29 +2,12 @@ @@ -2,29 +2,12 @@
2 <CollapseItem name="播放器配置" :expanded="true"> 2 <CollapseItem name="播放器配置" :expanded="true">
3 <setting-item-box name="上传图片" :alone="true"> 3 <setting-item-box name="上传图片" :alone="true">
4 <setting-item> 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> 5 + <TKUpload :uploadImageUrl="optionData.poster" @sendFile="handleSendFile" @removeFile="handleRemoveFile" />
23 </setting-item> 6 </setting-item>
24 </setting-item-box> 7 </setting-item-box>
25 <setting-item-box name="源类型" :alone="true"> 8 <setting-item-box name="源类型" :alone="true">
26 <setting-item> 9 <setting-item>
27 - <n-radio-group @change="handleChecked" v-model:value="optionData.sourceType" name="radiogroup"> 10 + <n-radio-group @update:value="handleChecked" v-model:value="optionData.sourceType" name="radiogroup">
28 <n-space> 11 <n-space>
29 <n-radio v-for="(item, index) in sourceTypes" :key="item.value" :value="item.value"> 12 <n-radio v-for="(item, index) in sourceTypes" :key="item.value" :value="item.value">
30 {{ item.label }} 13 {{ item.label }}
@@ -55,7 +38,12 @@ @@ -55,7 +38,12 @@
55 </setting-item-box> 38 </setting-item-box>
56 <setting-item-box v-if="optionData.sourceType === sourceTypeEnum.PLATFORM" name="视频" :alone="true"> 39 <setting-item-box v-if="optionData.sourceType === sourceTypeEnum.PLATFORM" name="视频" :alone="true">
57 <setting-item> 40 <setting-item>
58 - <n-select @update:value="handleSelect" v-model:value="optionData.dataset" :options="videoOptions" /> 41 + <n-select
  42 + @update:value="handleSelect"
  43 + v-model:value="optionData.dataset"
  44 + :options="videoOptions"
  45 + placeholder="请选择视频地址"
  46 + />
59 </setting-item> 47 </setting-item>
60 </setting-item-box> 48 </setting-item-box>
61 <setting-item-box name="自动播放"> 49 <setting-item-box name="自动播放">
@@ -67,15 +55,21 @@ @@ -67,15 +55,21 @@
67 </template> 55 </template>
68 56
69 <script setup lang="ts"> 57 <script setup lang="ts">
70 -import { PropType, ref, nextTick, onMounted } from 'vue' 58 +import { PropType, ref, onMounted } from 'vue'
71 import { option, sourceTypeEnum } from './config' 59 import { option, sourceTypeEnum } from './config'
72 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' 60 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
73 -import { FileTypeEnum } from '@/enums/fileTypeEnum'  
74 -import { uploadFile } from '@/api/external/contentSave/content'  
75 -import { UploadCustomRequestOptions, NTreeSelect } from 'naive-ui'  
76 -import { backgroundImageSize } from '@/settings/designSetting'  
77 -import { fetchRouteParamsLocation } from '@/utils' 61 +import { NTreeSelect } from 'naive-ui'
78 import { getOrganizationList, getVideoList, getVideoUrl } from '@/api/external/common/index' 62 import { getOrganizationList, getVideoList, getVideoUrl } from '@/api/external/common/index'
  63 +import { TKUpload } from '@/components/external/Common/TKUpload'
  64 +
  65 +interface videoListIF {
  66 + name: string
  67 + accessMode: number
  68 + id: string
  69 + videoUrl: string
  70 + label: string
  71 + value: string
  72 +}
79 73
80 const props = defineProps({ 74 const props = defineProps({
81 optionData: { 75 optionData: {
@@ -84,8 +78,6 @@ const props = defineProps({ @@ -84,8 +78,6 @@ const props = defineProps({
84 } 78 }
85 }) 79 })
86 80
87 -const uploadFileListRef = ref()  
88 -  
89 const sourceTypes = [ 81 const sourceTypes = [
90 { 82 {
91 value: 'custom', 83 value: 'custom',
@@ -99,7 +91,7 @@ const sourceTypes = [ @@ -99,7 +91,7 @@ const sourceTypes = [
99 91
100 const originationOption = ref([]) 92 const originationOption = ref([])
101 93
102 -const videoOptions = ref([]) 94 +const videoOptions = ref<videoListIF[]>([])
103 95
104 const getOriginationList = async () => { 96 const getOriginationList = async () => {
105 const res = await getOrganizationList() 97 const res = await getOrganizationList()
@@ -113,7 +105,8 @@ const handleUpdateTreeValue = (value: string) => { @@ -113,7 +105,8 @@ const handleUpdateTreeValue = (value: string) => {
113 105
114 const getVideoLists = async (organizationId: string) => { 106 const getVideoLists = async (organizationId: string) => {
115 const res = await getVideoList({ organizationId }) 107 const res = await getVideoList({ organizationId })
116 - videoOptions.value = res?.data?.map((item: any) => ({ 108 + if (!res) return
  109 + videoOptions.value = res?.data?.map((item: videoListIF) => ({
117 label: item.name, 110 label: item.name,
118 value: item.accessMode === 1 ? item.id : item.videoUrl, 111 value: item.accessMode === 1 ? item.id : item.videoUrl,
119 id: item.id, 112 id: item.id,
@@ -128,16 +121,16 @@ const getVideoUrlById = async (id: string) => { @@ -128,16 +121,16 @@ const getVideoUrlById = async (id: string) => {
128 props.optionData.url = url 121 props.optionData.url = url
129 } 122 }
130 123
131 -const handleChecked = ({ target }: any) => { 124 +const handleChecked = (value: string) => {
132 props.optionData.dataset = '' 125 props.optionData.dataset = ''
133 - const { value } = target  
134 if (value === sourceTypeEnum.PLATFORM) { 126 if (value === sourceTypeEnum.PLATFORM) {
135 getOriginationList() 127 getOriginationList()
136 } 128 }
137 } 129 }
138 130
139 -const handleSelect = (value: string, e: any) => { 131 +const handleSelect = (_: string, e: videoListIF) => {
140 const { accessMode, id } = e 132 const { accessMode, id } = e
  133 + //1表示,需要从服务端调取接口换取播放的地址,0则不需要
141 if (accessMode === 1) { 134 if (accessMode === 1) {
142 getVideoUrlById(id) 135 getVideoUrlById(id)
143 } else { 136 } else {
@@ -154,76 +147,10 @@ onMounted(() => { @@ -154,76 +147,10 @@ onMounted(() => {
154 } 147 }
155 }) 148 })
156 149
157 -// 上传图片前置处理  
158 -// eslint-disable-next-line @typescript-eslint/ban-ts-comment  
159 -//@ts-ignore  
160 -const beforeUploadHandle = async ({ file }) => {  
161 - uploadFileListRef.value = []  
162 - const type = file.file.type  
163 - const size = file.file.size  
164 -  
165 - if (size > 1024 * 1024 * backgroundImageSize) {  
166 - window['$message'].warning(`图片超出 ${backgroundImageSize}M 限制,请重新上传!`)  
167 - return false  
168 - }  
169 - if (type !== FileTypeEnum.PNG && type !== FileTypeEnum.JPEG && type !== FileTypeEnum.GIF) {  
170 - window['$message'].warning('文件格式不符合,请重新上传!')  
171 - return false  
172 - }  
173 - return true 150 +const handleSendFile = (file: string) => {
  151 + if (!file) return
  152 + props.optionData.poster = file
174 } 153 }
175 154
176 -// 自定义上传操作  
177 -const customRequest = (options: UploadCustomRequestOptions) => {  
178 - const { file } = options  
179 - nextTick(async () => {  
180 - if (file.file) {  
181 - // 修改名称  
182 - const newNameFile = new File([file.file], `${fetchRouteParamsLocation()}_index_background.png`, {  
183 - type: file.file.type  
184 - })  
185 - let uploadParams = new FormData()  
186 - uploadParams.append('file', newNameFile)  
187 - const uploadRes = await uploadFile(uploadParams)  
188 - if (uploadRes) {  
189 - props.optionData.poster = uploadRes?.fileStaticUri  
190 - window['$message'].success('添加图片成功!')  
191 - }  
192 - } else {  
193 - window['$message'].error('添加图片失败,请稍后重试!')  
194 - }  
195 - })  
196 -} 155 +const handleRemoveFile = (status: boolean) => (status ? (props.optionData.poster = '') : null)
197 </script> 156 </script>
198 -<style lang="scss" scoped>  
199 -$uploadHeight: 193px;  
200 -.upload-box {  
201 - cursor: pointer;  
202 - margin-bottom: 20px;  
203 - @include deep() {  
204 - .n-card__content {  
205 - padding: 0;  
206 - overflow: hidden;  
207 - }  
208 - .n-upload-dragger {  
209 - padding: 5px;  
210 - }  
211 - }  
212 - .upload-show {  
213 - width: -webkit-fill-available;  
214 - height: $uploadHeight;  
215 - border-radius: 5px;  
216 - }  
217 - .upload-img {  
218 - display: flex;  
219 - flex-direction: column;  
220 - align-items: center;  
221 - img {  
222 - height: 150px;  
223 - }  
224 - .upload-desc {  
225 - padding: 10px 0;  
226 - }  
227 - }  
228 -}  
229 -</style>