5 changed files with 468 additions and 2 deletions
			
			
		@ -0,0 +1,370 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div ref="containerRef" :class="`${prefixCls}-container`"> | 
				
			||||||
 | 
					    <Upload | 
				
			||||||
 | 
					      :headers="headers" | 
				
			||||||
 | 
					      :multiple="multiple" | 
				
			||||||
 | 
					      :action="(uploadUrl as any)" | 
				
			||||||
 | 
					      :fileList="fileList" | 
				
			||||||
 | 
					      :disabled="disabled" | 
				
			||||||
 | 
					      v-bind="bindProps" | 
				
			||||||
 | 
					      @remove="onRemove" | 
				
			||||||
 | 
					      @change="onFileChange" | 
				
			||||||
 | 
					      @preview="onFilePreview" | 
				
			||||||
 | 
					    > | 
				
			||||||
 | 
					      <template v-if="isImageMode"> | 
				
			||||||
 | 
					        <div v-if="!isMaxCount"> | 
				
			||||||
 | 
					          <Icon icon="ant-design:plus-outlined" /> | 
				
			||||||
 | 
					          <div class="ant-upload-text">{{ text }}</div> | 
				
			||||||
 | 
					        </div> | 
				
			||||||
 | 
					      </template> | 
				
			||||||
 | 
					      <a-button v-else-if="buttonVisible" :disabled="isMaxCount || disabled"> | 
				
			||||||
 | 
					        <Icon icon="ant-design:upload-outlined" /> | 
				
			||||||
 | 
					        <span>{{ text }}</span> | 
				
			||||||
 | 
					      </a-button> | 
				
			||||||
 | 
					    </Upload> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts" setup name="FileUpload"> | 
				
			||||||
 | 
					import { Upload } from 'ant-design-vue' | 
				
			||||||
 | 
					import { ref, reactive, computed, watch, unref } from 'vue' | 
				
			||||||
 | 
					import { Icon } from '@/components/Icon' | 
				
			||||||
 | 
					import { getAccessToken, getTenantId } from '@/utils/auth' | 
				
			||||||
 | 
					import { propTypes } from '@/utils/propTypes' | 
				
			||||||
 | 
					import { useMessage } from '@/hooks/web/useMessage' | 
				
			||||||
 | 
					import { createImgPreview } from '@/components/Preview/index' | 
				
			||||||
 | 
					import { useAttrs } from '@/hooks/core/useAttrs' | 
				
			||||||
 | 
					import { useDesign } from '@/hooks/web/useDesign' | 
				
			||||||
 | 
					import { useGlobSetting } from '@/hooks/setting' | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { createMessage, createConfirm } = useMessage() | 
				
			||||||
 | 
					const { prefixCls } = useDesign('upload') | 
				
			||||||
 | 
					const attrs = useAttrs() | 
				
			||||||
 | 
					const emit = defineEmits(['change', 'update:value']) | 
				
			||||||
 | 
					const props = defineProps({ | 
				
			||||||
 | 
					  value: propTypes.oneOfType([propTypes.string, propTypes.array]), | 
				
			||||||
 | 
					  text: propTypes.string.def('上传'), | 
				
			||||||
 | 
					  fileType: propTypes.oneOf(['all', 'image', 'file']).def('all'), | 
				
			||||||
 | 
					  // eslint-disable-next-line vue/valid-define-props | 
				
			||||||
 | 
					  uploadUrl: propTypes.string.def(useGlobSetting().uploadUrl), | 
				
			||||||
 | 
					  /*这个属性用于控制文件上传的业务路径*/ | 
				
			||||||
 | 
					  bizPath: propTypes.string.def('temp'), | 
				
			||||||
 | 
					  /** | 
				
			||||||
 | 
					   * 是否返回url, | 
				
			||||||
 | 
					   * true:仅返回url | 
				
			||||||
 | 
					   * false:返回fileName filePath fileSize | 
				
			||||||
 | 
					   */ | 
				
			||||||
 | 
					  returnUrl: propTypes.bool.def(true), | 
				
			||||||
 | 
					  // 最大上传数量 | 
				
			||||||
 | 
					  maxCount: propTypes.number.def(0), | 
				
			||||||
 | 
					  buttonVisible: propTypes.bool.def(true), | 
				
			||||||
 | 
					  multiple: propTypes.bool.def(true), | 
				
			||||||
 | 
					  // 是否显示左右移动按钮 | 
				
			||||||
 | 
					  mover: propTypes.bool.def(true), | 
				
			||||||
 | 
					  // 是否显示下载按钮 | 
				
			||||||
 | 
					  download: propTypes.bool.def(true), | 
				
			||||||
 | 
					  // 删除时是否显示确认框 | 
				
			||||||
 | 
					  removeConfirm: propTypes.bool.def(false), | 
				
			||||||
 | 
					  beforeUpload: propTypes.func, | 
				
			||||||
 | 
					  disabled: propTypes.bool.def(false) | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const headers = reactive({ | 
				
			||||||
 | 
					  Authorization: 'Bearer ' + getAccessToken(), | 
				
			||||||
 | 
					  'tenant-id': getTenantId() | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					const fileList = ref<any[]>([]) | 
				
			||||||
 | 
					const uploadGoOn = ref<boolean>(true) | 
				
			||||||
 | 
					// refs | 
				
			||||||
 | 
					const containerRef = ref() | 
				
			||||||
 | 
					// 是否达到了最大上传数量 | 
				
			||||||
 | 
					const isMaxCount = computed(() => props.maxCount > 0 && fileList.value.length >= props.maxCount) | 
				
			||||||
 | 
					// 当前是否是上传图片模式 | 
				
			||||||
 | 
					const isImageMode = computed(() => props.fileType === 'image') | 
				
			||||||
 | 
					// 合并 props 和 attrs | 
				
			||||||
 | 
					const bindProps = computed(() => { | 
				
			||||||
 | 
					  //update-begin-author:liusq date:20220411 for: [issue/455]上传组件传入accept限制上传文件类型无效 | 
				
			||||||
 | 
					  const bind: any = Object.assign({}, props, unref(attrs)) | 
				
			||||||
 | 
					  //update-end-author:liusq date:20220411 for: [issue/455]上传组件传入accept限制上传文件类型无效 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bind.name = 'file' | 
				
			||||||
 | 
					  bind.listType = isImageMode.value ? 'picture-card' : 'text' | 
				
			||||||
 | 
					  bind.class = [bind.class, { 'upload-disabled': props.disabled }] | 
				
			||||||
 | 
					  bind.data = { biz: props.bizPath, ...bind.data } | 
				
			||||||
 | 
					  //update-begin-author:taoyan date:20220407 for: 自定义beforeUpload return false,并不能中断上传过程 | 
				
			||||||
 | 
					  if (!bind.beforeUpload) { | 
				
			||||||
 | 
					    bind.beforeUpload = onBeforeUpload | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  //update-end-author:taoyan date:20220407 for: 自定义beforeUpload return false,并不能中断上传过程 | 
				
			||||||
 | 
					  // 如果当前是图片上传模式,就只能上传图片 | 
				
			||||||
 | 
					  if (isImageMode.value && !bind.accept) { | 
				
			||||||
 | 
					    bind.accept = 'image/*' | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  return bind | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					watch( | 
				
			||||||
 | 
					  () => props.value, | 
				
			||||||
 | 
					  (val) => { | 
				
			||||||
 | 
					    if (Array.isArray(val)) { | 
				
			||||||
 | 
					      if (props.returnUrl) { | 
				
			||||||
 | 
					        parsePathsValue(val.join(',')) | 
				
			||||||
 | 
					      } else { | 
				
			||||||
 | 
					        parseArrayValue(val) | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } else { | 
				
			||||||
 | 
					      parsePathsValue(val) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  { immediate: true } | 
				
			||||||
 | 
					) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 解析数据库存储的逗号分割 | 
				
			||||||
 | 
					function parsePathsValue(paths) { | 
				
			||||||
 | 
					  if (!paths || paths.length == 0) { | 
				
			||||||
 | 
					    fileList.value = [] | 
				
			||||||
 | 
					    return | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  let list: any[] = [] | 
				
			||||||
 | 
					  for (const item of paths.split(',')) { | 
				
			||||||
 | 
					    list.push({ | 
				
			||||||
 | 
					      uid: uidGenerator(), | 
				
			||||||
 | 
					      name: getFileName(item), | 
				
			||||||
 | 
					      status: 'done', | 
				
			||||||
 | 
					      url: item, | 
				
			||||||
 | 
					      response: { status: 'history', message: item } | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  fileList.value = list | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 解析数组值 | 
				
			||||||
 | 
					function parseArrayValue(array) { | 
				
			||||||
 | 
					  if (!array || array.length == 0) { | 
				
			||||||
 | 
					    fileList.value = [] | 
				
			||||||
 | 
					    return | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  let list: any[] = [] | 
				
			||||||
 | 
					  for (const item of array) { | 
				
			||||||
 | 
					    list.push({ | 
				
			||||||
 | 
					      uid: uidGenerator(), | 
				
			||||||
 | 
					      name: item.fileName, | 
				
			||||||
 | 
					      url: item.filePath, | 
				
			||||||
 | 
					      status: 'done', | 
				
			||||||
 | 
					      response: { status: 'history', message: item.filePath } | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  fileList.value = list | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 文件上传之前的操作 | 
				
			||||||
 | 
					function onBeforeUpload(file) { | 
				
			||||||
 | 
					  uploadGoOn.value = true | 
				
			||||||
 | 
					  if (isImageMode.value) { | 
				
			||||||
 | 
					    if (file.type.indexOf('image') < 0) { | 
				
			||||||
 | 
					      createMessage.warning('请上传图片') | 
				
			||||||
 | 
					      uploadGoOn.value = false | 
				
			||||||
 | 
					      return false | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  // 扩展 beforeUpload 验证 | 
				
			||||||
 | 
					  if (typeof props.beforeUpload === 'function') { | 
				
			||||||
 | 
					    return props.beforeUpload(file) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  return true | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 删除处理事件 | 
				
			||||||
 | 
					function onRemove() { | 
				
			||||||
 | 
					  if (props.removeConfirm) { | 
				
			||||||
 | 
					    return new Promise((resolve) => { | 
				
			||||||
 | 
					      createConfirm({ | 
				
			||||||
 | 
					        title: '删除', | 
				
			||||||
 | 
					        content: `确定要删除这${isImageMode.value ? '张图片' : '个文件'}吗?`, | 
				
			||||||
 | 
					        iconType: 'warning', | 
				
			||||||
 | 
					        onOk: () => resolve(true), | 
				
			||||||
 | 
					        onCancel: () => resolve(false) | 
				
			||||||
 | 
					      }) | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  return true | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// upload组件change事件 | 
				
			||||||
 | 
					function onFileChange(info) { | 
				
			||||||
 | 
					  if (!info.file.status && uploadGoOn.value === false) { | 
				
			||||||
 | 
					    info.fileList.pop() | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  let fileListTemp = info.fileList | 
				
			||||||
 | 
					  // 限制最大上传数 | 
				
			||||||
 | 
					  if (props.maxCount > 0) { | 
				
			||||||
 | 
					    let count = fileListTemp.length | 
				
			||||||
 | 
					    if (count >= props.maxCount) { | 
				
			||||||
 | 
					      let diffNum = props.maxCount - fileListTemp.length | 
				
			||||||
 | 
					      if (diffNum >= 0) { | 
				
			||||||
 | 
					        fileListTemp = fileListTemp.slice(-props.maxCount) | 
				
			||||||
 | 
					      } else { | 
				
			||||||
 | 
					        return | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  if (info.file.status === 'done') { | 
				
			||||||
 | 
					    if (info.file.response.success) { | 
				
			||||||
 | 
					      fileListTemp = fileListTemp.map((file) => { | 
				
			||||||
 | 
					        if (file.response) { | 
				
			||||||
 | 
					          let reUrl = file.response.message | 
				
			||||||
 | 
					          file.url = reUrl | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					        return file | 
				
			||||||
 | 
					      }) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } else if (info.file.status === 'error') { | 
				
			||||||
 | 
					    createMessage.error(`${info.file.name} 上传失败.`) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  fileList.value = fileListTemp | 
				
			||||||
 | 
					  if (info.file.status === 'done' || info.file.status === 'removed') { | 
				
			||||||
 | 
					    //returnUrl为true时仅返回文件路径 | 
				
			||||||
 | 
					    if (props.returnUrl) { | 
				
			||||||
 | 
					      handlePathChange() | 
				
			||||||
 | 
					    } else { | 
				
			||||||
 | 
					      //returnUrl为false时返回文件名称、文件路径及文件大小 | 
				
			||||||
 | 
					      let newFileList: any[] = [] | 
				
			||||||
 | 
					      for (const item of fileListTemp) { | 
				
			||||||
 | 
					        if (item.status === 'done') { | 
				
			||||||
 | 
					          let fileJson = { | 
				
			||||||
 | 
					            fileName: item.name, | 
				
			||||||
 | 
					            filePath: item.response.message, | 
				
			||||||
 | 
					            fileSize: item.size | 
				
			||||||
 | 
					          } | 
				
			||||||
 | 
					          newFileList.push(fileJson) | 
				
			||||||
 | 
					        } else { | 
				
			||||||
 | 
					          return | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					      emitValue(newFileList) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function handlePathChange() { | 
				
			||||||
 | 
					  let uploadFiles = fileList.value | 
				
			||||||
 | 
					  let path = '' | 
				
			||||||
 | 
					  if (!uploadFiles || uploadFiles.length == 0) { | 
				
			||||||
 | 
					    path = '' | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  let pathList: string[] = [] | 
				
			||||||
 | 
					  for (const item of uploadFiles) { | 
				
			||||||
 | 
					    if (item.status === 'done') { | 
				
			||||||
 | 
					      pathList.push(item.response.data) | 
				
			||||||
 | 
					    } else { | 
				
			||||||
 | 
					      return | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  if (pathList.length > 0) { | 
				
			||||||
 | 
					    path = pathList.join(',') | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  emitValue(path) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 预览文件、图片 | 
				
			||||||
 | 
					function onFilePreview(file) { | 
				
			||||||
 | 
					  if (isImageMode.value) { | 
				
			||||||
 | 
					    createImgPreview({ imageList: [file.url], maskClosable: true }) | 
				
			||||||
 | 
					  } else { | 
				
			||||||
 | 
					    window.open(file.url) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function emitValue(value) { | 
				
			||||||
 | 
					  emit('change', value) | 
				
			||||||
 | 
					  emit('update:value', value) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function uidGenerator() { | 
				
			||||||
 | 
					  return '-' + parseInt(Math.random() * 10000 + 1, 10) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getFileName(path) { | 
				
			||||||
 | 
					  if (path.lastIndexOf('\\') >= 0) { | 
				
			||||||
 | 
					    let reg = new RegExp('\\\\', 'g') | 
				
			||||||
 | 
					    path = path.replace(reg, '/') | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  return path.substring(path.lastIndexOf('/') + 1) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					</script> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="less"> | 
				
			||||||
 | 
					//noinspection LessUnresolvedVariable | 
				
			||||||
 | 
					@prefix-cls: ~'@{namespace}-upload'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.@{prefix-cls} { | 
				
			||||||
 | 
					  &-container { | 
				
			||||||
 | 
					    position: relative; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .upload-disabled { | 
				
			||||||
 | 
					      .ant-upload-list-item { | 
				
			||||||
 | 
					        .anticon-close { | 
				
			||||||
 | 
					          display: none; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .anticon-delete { | 
				
			||||||
 | 
					          display: none; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /* update-begin-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全 */ | 
				
			||||||
 | 
					      .upload-download-handler { | 
				
			||||||
 | 
					        right: 6px !important; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /* update-end-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全 */ | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .ant-upload-list-item { | 
				
			||||||
 | 
					      .upload-actions-container { | 
				
			||||||
 | 
					        position: absolute; | 
				
			||||||
 | 
					        top: -31px; | 
				
			||||||
 | 
					        left: -18px; | 
				
			||||||
 | 
					        z-index: 11; | 
				
			||||||
 | 
					        width: 84px; | 
				
			||||||
 | 
					        height: 84px; | 
				
			||||||
 | 
					        line-height: 28px; | 
				
			||||||
 | 
					        text-align: center; | 
				
			||||||
 | 
					        pointer-events: none; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        a { | 
				
			||||||
 | 
					          opacity: 0.9; | 
				
			||||||
 | 
					          margin: 0 5px; | 
				
			||||||
 | 
					          cursor: pointer; | 
				
			||||||
 | 
					          transition: opacity 0.3s; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          .anticon { | 
				
			||||||
 | 
					            color: #fff; | 
				
			||||||
 | 
					            font-size: 16px; | 
				
			||||||
 | 
					          } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          &:hover { | 
				
			||||||
 | 
					            opacity: 1; | 
				
			||||||
 | 
					          } | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .upload-mover-handler, | 
				
			||||||
 | 
					        .upload-download-handler { | 
				
			||||||
 | 
					          position: absolute; | 
				
			||||||
 | 
					          pointer-events: auto; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .upload-mover-handler { | 
				
			||||||
 | 
					          width: 100%; | 
				
			||||||
 | 
					          bottom: 0; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .upload-download-handler { | 
				
			||||||
 | 
					          top: -4px; | 
				
			||||||
 | 
					          right: -4px; | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					</style> | 
				
			||||||
@ -0,0 +1,90 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div v-show="download" class="upload-download-handler"> | 
				
			||||||
 | 
					    <a class="download" title="下载" @click="onDownload"> | 
				
			||||||
 | 
					      <Icon icon="ant-design:download" /> | 
				
			||||||
 | 
					    </a> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					  <div v-show="mover && list.length > 1" class="upload-mover-handler"> | 
				
			||||||
 | 
					    <a title="向前移动" @click="onMoveForward"> | 
				
			||||||
 | 
					      <Icon icon="ant-design:arrow-left" /> | 
				
			||||||
 | 
					    </a> | 
				
			||||||
 | 
					    <a title="向后移动" @click="onMoveBack"> | 
				
			||||||
 | 
					      <Icon icon="ant-design:arrow-right" /> | 
				
			||||||
 | 
					    </a> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts" setup> | 
				
			||||||
 | 
					import { unref, computed } from 'vue' | 
				
			||||||
 | 
					import { Icon } from '@/components/Icon' | 
				
			||||||
 | 
					import { useMessage } from '@/hooks/web/useMessage' | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { createMessage } = useMessage() | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps({ | 
				
			||||||
 | 
					  element: { type: HTMLElement, required: true }, | 
				
			||||||
 | 
					  fileList: { type: Object, required: true }, | 
				
			||||||
 | 
					  mover: { type: Boolean, required: true }, | 
				
			||||||
 | 
					  download: { type: Boolean, required: true }, | 
				
			||||||
 | 
					  emitValue: { type: Function, required: true } | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					const list = computed(() => unref(props.fileList)) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 向前移动图片 | 
				
			||||||
 | 
					function onMoveForward() { | 
				
			||||||
 | 
					  let index = getIndexByUrl() | 
				
			||||||
 | 
					  if (index === -1) { | 
				
			||||||
 | 
					    createMessage.warn('移动失败:' + index) | 
				
			||||||
 | 
					    return | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  if (index === 0) { | 
				
			||||||
 | 
					    doSwap(index, unref(list).length - 1) | 
				
			||||||
 | 
					    return | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  doSwap(index, index - 1) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 向后移动图片 | 
				
			||||||
 | 
					function onMoveBack() { | 
				
			||||||
 | 
					  let index = getIndexByUrl() | 
				
			||||||
 | 
					  if (index === -1) { | 
				
			||||||
 | 
					    createMessage.warn('移动失败:' + index) | 
				
			||||||
 | 
					    return | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  if (index == unref(list).length - 1) { | 
				
			||||||
 | 
					    doSwap(index, 0) | 
				
			||||||
 | 
					    return | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  doSwap(index, index + 1) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function doSwap(oldIndex, newIndex) { | 
				
			||||||
 | 
					  if (oldIndex !== newIndex) { | 
				
			||||||
 | 
					    let array: any[] = [...(unref(list) as Array<any>)] | 
				
			||||||
 | 
					    let temp = array[oldIndex] | 
				
			||||||
 | 
					    array[oldIndex] = array[newIndex] | 
				
			||||||
 | 
					    array[newIndex] = temp | 
				
			||||||
 | 
					    props.emitValue(array.map((i) => i.url).join(',')) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getIndexByUrl() { | 
				
			||||||
 | 
					  const url = props.element?.getElementsByTagName('img')[0]?.src | 
				
			||||||
 | 
					  if (url) { | 
				
			||||||
 | 
					    const fileList: any = unref(list) | 
				
			||||||
 | 
					    for (let i = 0; i < fileList.length; i++) { | 
				
			||||||
 | 
					      let current = fileList[i].url | 
				
			||||||
 | 
					      const replace = url.replace(window.location.origin, '') | 
				
			||||||
 | 
					      if (current === replace || encodeURI(current) === replace) { | 
				
			||||||
 | 
					        return i | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					  return -1 | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function onDownload() { | 
				
			||||||
 | 
					  const url = props.element?.getElementsByTagName('img')[0]?.src | 
				
			||||||
 | 
					  window.open(url) | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					</script> | 
				
			||||||
		Reference in new issue