<template>
	<div class="sc-upload-file">
		<el-upload ref="uploader"
			:class="hideAdd && 'el-upload-hide-add'"
			v-model:file-list="defaultFileList"
			action=""
			:accept="accept"
			:limit="limit"
			:multiple="multiple"
			:disabled="disabled"
			show-file-list
			:http-request="request"
			:before-upload="before"
			:before-remove="beforeRemove"
			:on-success="success"
			:on-error="error"
			:on-preview="handlePreview"
			:on-exceed="handleExceed">
			<slot>
				<el-button type="primary" :disabled="disabled">Click to upload</el-button>
			</slot>
			<template #tip>
				<div v-if="tip" class="el-upload__tip">{{ tip }}</div>
			</template>
		</el-upload>
		<span style="display: none!important;"><el-input v-model="value"></el-input></span>
	</div>

	<sc-image-viewer :showViewer="showPictureViewer" :imageList="previewImageList" teleported @close="showPictureViewer = false"></sc-image-viewer>
	<sc-video-viewer v-if="showVideoViewer" :videoUrl="previewVideoUrl" hideOnModal @close="showVideoViewer = false"></sc-video-viewer>
</template>

<script>
  	import { defineAsyncComponent } from "vue";
	import config from "@/config/upload";

	export default {
		components: {
			scImageViewer: defineAsyncComponent(() => import("@/components/scUpload/imageViewer")),
			scVideoViewer: defineAsyncComponent(() => import("@/components/scUpload/videoViewer"))
		},
		props: {
			modelValue: { type: Array, default: () => [] },
			tip: { type: String, default: "" },
			accept: { type: String, default: "" },
			maxSize: { type: Number, default: 50 },
			limit: { type: Number, default: 0 },
			multiple: { type: Boolean, default: true },
			disabled: { type: Boolean, default: false },
			hideAdd: { type: Boolean, default: false },
			onSuccess: { type: Function, default: () => { return true } }
		},

		data() {
			return {
				value: "",
				defaultFileList: [],
				
				showPictureViewer: false,
				showVideoViewer: false,

				previewImageList: [],
				previewVideoUrl: ""
			}
		},

		watch: {
			modelValue(val) {
				if (JSON.stringify(val) != JSON.stringify(this.formatArr(this.defaultFileList))) {
					this.defaultFileList = val;
					this.value = val;
				}
			},

			defaultFileList: {
				deep: true,
				handler(val) {
					this.$emit("update:modelValue", this.formatArr(val));
					this.value = val.map(v => v.path).join(",");
				}
			}
		},

		mounted() {
			this.defaultFileList = this.modelValue;
			this.value = this.modelValue;
		},

		methods: {
			// 格式化数组值
			formatArr(arr) {
				return arr.map(item => ({ id: item.id, name: item.name, mineType: item.mineType, path: item.path }));
			},

			before(file) {
				const maxSize = file.size / 1024 / 1024 < this.maxSize;
				if (!maxSize) {
					this.$message.warning(`上传文件大小不能超过 ${this.maxSize}MB!`);
					return false;
				}
			},

			success(res, file) {
				let os = this.onSuccess(res, file);
				if (os != undefined && os == false) return false;
				
				file.name = res.fileName;
				file.path = res.path;
				file.mineType = res.mineType;
			},

			error(message) {
				this.$notify.error({ title: "上传文件未成功", message });
			},

			beforeRemove({ id, name, path }) { // id, name, path, size
				return this.$confirm(`是否移除 ${name}? 此操作不可逆!`, "提示", {
					type: "warning",
					confirmButtonText: "移除"
				}).then(() => {
					const entityID = id || path;
					this.$API.common.folder.rm(entityID).then(res => {
						if (res.code == 200) return true;
						else return false;
					}).catch(() => {
						return false;
					});
				}).catch(() => {
					return false;
				});
			},

			handleExceed() {
				this.$message.warning(`当前设置最多上传 ${this.limit} 个文件，请移除后上传!`);
			},

			async handlePreview(uploadFile) {
				if (config.imageIncludes(uploadFile.mineType)) {
					this.showPictureViewer = true;
					this.previewImageList = ["/zcxt/folder/" + uploadFile.path];
				} else if (config.videoIncludes(uploadFile.mineType)) {
					this.showVideoViewer = true;
					this.previewVideoUrl = "/zcxt/folder/" + uploadFile.path;
				} else {
					const res = await this.$API.common.folder.get(uploadFile.path);
					const a = document.createElement("a");
					a.href = URL.createObjectURL(res);
					a.download = uploadFile.name;
					a.click();
				}
			},

			request(param) {
				const data = new FormData();
				data.append(param.filename, param.file);
				this.$API.common.folder.up(data, {
					onUploadProgress: e => {
						const percent = parseInt(((e.loaded / e.total) * 100) | 0, 10);
						param.onProgress({ percent });
					}
				}).then(res => {
					if (res.code == 200) param.onSuccess({ path: res.expands.file, fileName: param.file.name, mineType: param.file.type })
					else param.onError(res.message || "未知错误");
				}).catch(err => param.onError(err));
			}
		}
	}
</script>

<style lang="scss" scoped>
.el-form-item.is-error .sc-upload-file:deep(.el-upload-dragger) {
  border-color: var(--el-color-danger);
}

.sc-upload-file {
  width: 100%;

  :deep(.el-upload-list__item) {
    transition: none !important;
  }

  .el-upload-hide-add {
    :deep(.el-upload) {
      display: none;
    }

    :deep(.el-upload-list) {
      margin-top: 0;

      .el-upload-list__item {
        &:hover {
          background-color: transparent;
        }

        .el-upload-list__item-info {
          width: 100%;
        }

        .el-upload-list__item-status-label {
          display: none;
        }
      }
    }
  }
}
</style>