<template>
    <div class="app-mob-file-upload">
        <ion-item-group v-if="files.length > 0" class="app-mob-file-upload__group">
        <ion-item v-for="file in files" :key="file.id" class="app-mob-file-upload__item">
            <ion-label><a  @click="onDownload(file)">{{file.name}}</a></ion-label>
            <app-mob-icon class="app-mob-file-upload__icon" name="close-outline" @onClick="onDelete(file, null)"></app-mob-icon>
        </ion-item>
        </ion-item-group>
        <div class="app-mob-file-upload__container">
            <van-uploader 
                accept="*"
                :class="singleChoiceBtnState" 
                multiple="false" 
                :disabled="state" 
                :result-type="resultType"
                :before-read="beforeRead" 
                :after-read="afterRead">
                <app-mob-icon  name="add-outline" style="font-size: 20px;"></app-mob-icon>
            </van-uploader>
        </div>
    </div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Provide, Watch } from 'vue-property-decorator';
import { Environment } from '@/environments/environment';
import { Subject, Unsubscribable } from 'rxjs';
import qs from 'qs';
import { Uploader } from 'vant';
import { Http, ViewTool } from 'ibiz-core';

Vue.use(Uploader);
@Component({
    i18n: {
        messages: {
            'ZH-CN': {
                one_doc: '该功能只支持单个文件上传',
                upload_failed: '上传失败!',
            },
            'EN-US': {
                one_doc: 'This function only supports single file upload',
                upload_failed: 'Upload failed!',
            }
        }
    },
})
export default class AppMobFileUpload extends Vue {
    // MOB LOGIC BEGIN
    /**
     * 单选按钮状态
     *
     * @readonly
     * @type {Array<string>}
     * @memberof AppMobFileUpload
     */
    get singleChoiceBtnState(): Array<string> {
        return [
            this.files.length > 0 ? 'app-mob-file-upload__filelist' : '',
            !this.multiple && this.files.length === 1 ? 'app-mob-file-upload__hiddenbutton' : '',
        ];
    }

    /**
     * 编辑器状态
     *
     * @readonly
     * @type {boolean}
     * @memberof AppMobFileUpload
     */
    get state(): boolean {
        // 禁用
        if (this.disabled) {
            return true;
        }
        // 单选
        if (!this.multiple && this.files.length === 1) {
            return true;
        }
        return false;
    }

    /**
     * 开发模式文件数组
     *
     * @private
     * @type {Array<any>}
     * @memberof AppMobFileUpload
     */
    private devFiles: Array<any> = [];

    /**
     * 文件上传模式
     *
     * @type {string}
     * @memberof AppMobFileUpload
     */
    public resultType: string = process.env.NODE_ENV === 'development' ? 'dataUrl' : 'file';

    /**
     * 文件删除
     *
     * @param {*} file 文件信息
     * @param {*} detail 详情
     * @memberof AppMobFileUpload
     */
    public onDelete(file: any, detail: any): void {
        this.onRemove({ id: file.id,name: file.name}, this.files);
    }

    /**
     * 上传之前
     *
     * @param {*} file
     * @param {*} detail
     * @returns {boolean}
     * @memberof AppMobFileUpload
     */
    public beforeRead(file: any, detail: any): boolean {
        this.dataProcess();
        if (file && Array.isArray(file)) {
            this.$Notice.warning(`${this.$t('one_doc')}`);
            return false;
        }
        return true;
    }

    /**
     * 文件选择完成
     *
     * @public
     * @param {*} file 文件信息
     * @param {*} detail 详情
     * @memberof AppMobFileUpload
     */
     public afterRead(file: any, detail: any): void {
        const params = new FormData()
        params.append('file', file.file, file.file.name)
        const config = {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        }
        Http.getHttp().post(this.uploadUrl, params, config).then((response: any) => {
            if (response && response.data && response.status === 200) {
                let data: any = response.data;
                if (process.env.NODE_ENV === 'development') {
                    this.devFiles.push(Object.assign({}, data, {
                        url: file.content
                    }));
                }
                this.onSuccess(data, file, this.files);
            } else {
                this.onError(response, file, this.files);
            }
        }).catch((response: any) => {
            this.onError(response, file, this.files);
        });
    }

    /**
     * 是否支持多个上传
     *
     * @type {boolean}
     * @memberof AppMobFileUpload
     */
    @Prop({ default: true }) public multiple?: boolean;

    /**
     * 表单状态
     *
     * @type {Subject<any>}
     * @memberof AppMobFileUpload
     */
    @Prop() public formState?: Subject<any>

    /**
     * 是否忽略表单项书香值变化
     *
     * @type {boolean}
     * @memberof AppMobFileUpload
     */
    @Prop() public ignorefieldvaluechange?: boolean;

    /**
     * 表单状态事件
     *
     * @private
     * @type {(Unsubscribable | undefined)}
     * @memberof AppMobFileUpload
     */
    private formStateEvent: Unsubscribable | undefined;

    /**
     * 表单数据
     *
     * @type {string}
     * @memberof AppMobFileUpload
     */
    @Prop() public data!: string;

    /**
     * 初始化值
     *
     * @type {*}
     * @memberof AppMobFileUpload
     */
    @Prop() public value?: any;

    /**
     * 数据值变化
     *
     * @param {*} newval
     * @param {*} val
     * @returns
     * @memberof AppMobFileUpload
     */
    @Watch('value')
    onValueChange(newval: any, val: any) {
        if (this.ignorefieldvaluechange) {
            return;
        }
        if (newval) {
            this.files = JSON.parse(newval);
            this.dataProcess();
        } else {
            this.files = [];
        }
    }

    /**
     * 所属表单项名称
     *
     * @type {string}
     * @memberof AppMobFileUpload
     */
    @Prop() public name!: string;

    /**
     * 是否禁用
     *
     * @type {boolean}
     * @memberof AppMobFileUpload
     */
    @Prop() public disabled?: boolean;

    /**
     * 视图上下文
     *
     * @type {*}
     * @memberof AppMobFileUpload
     */
    @Prop({ default: {} }) context: any;

    /**
     * 视图参数
     *
     * @type {*}
     * @memberof AppMobFileUpload
     */
    @Prop({ default: {} }) viewparams: any;

    /**
     * 上传参数
     *
     * @type {*}
     * @memberof AppMobFileUpload
     */
    @Prop({ default: ()=>{} }) uploadParam: any;

    /**
     * 下载参数
     *
     * @type {*}
     * @memberof AppMobFileUpload
     */
    @Prop({ default: ()=>{} }) exportParam: any;

    /**
     * 上传文件路径
     *
     * @memberof AppMobFileUpload
     */
    public uploadUrl =  Environment.UploadFile;

    /**
     * 下载文件路径
     *
     * @memberof AppMobFileUpload
     */
    public downloadUrl = Environment.ExportFile;

    /**
     * 文件列表
     *
     * @memberof AppMobFileUpload
     */
    @Provide() public files: Array<any> = [];

    /**
     * 应用参数
     *
     * @type {*}
     * @memberof AppMobFileUpload
     */
    public appData: any = "";

    /**
     * 数据处理
     *
     * @private
     * @memberof AppMobFileUpload
     */
    private dataProcess(): void {
        const { context: uploadContext, param: uploadParam } = ViewTool.formatNavigateParam(this.uploadParam, {}, this.context, this.viewparams, JSON.parse(this.data));
        const { context: exportContext, param: exportParam } = ViewTool.formatNavigateParam(this.exportParam, {}, this.context, this.viewparams, JSON.parse(this.data));
        let _uploadUrl = `${Environment.UploadFile}`;
        const uploadContextStr: string = qs.stringify(uploadContext, { delimiter: '&' });
        const uploadParamStr: string = qs.stringify(uploadParam, { delimiter: '&' });
        if (!Object.is(uploadContextStr, '') || !Object.is(uploadParamStr, '')) {
            _uploadUrl = `${_uploadUrl}?${uploadContextStr}&${uploadParamStr}`;
        }
        this.uploadUrl = _uploadUrl;
        this.files.forEach((file: any) => {
            if (process.env.NODE_ENV === 'development') {
                let index = this.devFiles.findIndex((devFile: any) => Object.is(devFile.id, file.id));
                if (index !== -1) {
                    file.url = this.devFiles[index].url;
                    file.isImage = true;
                }
                // return;
            }
            let _downloadUrl = `${this.downloadUrl}/${file.id}`;
            const exportContextStr: string = qs.stringify(exportContext, { delimiter: '&' });
            const exportParamStr: string = qs.stringify(exportParam, { delimiter: '&' });
            if (!Object.is(exportContextStr, '') || !Object.is(exportParamStr, '')) {
                _downloadUrl = `${_downloadUrl}?${exportContextStr}&${exportParamStr}`;
            }
            file.url = _downloadUrl;
        });
    }

    /**
     * vue 生命周期
     *
     * @memberof AppMobFileUpload
     */
    public created() {
        if (this.formState) {
            this.formStateEvent = this.formState.subscribe(($event: any) => {
                // 表单加载完成
                if (Object.is($event.type, 'load')) {
                    if (this.value) {
                        this.files = JSON.parse(this.value);
                    }
                    this.dataProcess();
                }
                // 表单保存完成 和 表单项更新
                if (Object.is($event.type, "save") || Object.is($event.type, "updateformitem")) {
                    this.dataProcess();
                }
            });
        }
    }

    /**
     * vue 生命周期
     *
     * @memberof AppMobFileUpload
     */
    public mounted() {
        this.appData = this.$store.getters.getAppData();
        if (this.value) {
            this.files = JSON.parse(this.value);
        }
        this.dataProcess();
        this.changeLabelStyle();
    }

    /**
     * 修改label默认样式
     * @memberof AppMobFileUpload
     */
    public changeLabelStyle() {
        document.querySelectorAll(".app-mobile-file-upload").forEach((element: any) => {
            let prev = this.getNearEle(element, 1);
            if (prev) {
                prev.style.transform = 'none';
            }
        })
    }

    /**
     * 查找相邻前一个元素
     * 
     *  @memberof AppMobFileUpload
     */
    public getNearEle(ele: any, type: any) {
        type = type == 1 ? "previousSibling" : "nextSibling";
        var nearEle = ele[type];
        while (nearEle) {
            if (nearEle.nodeType === 1) {
                return nearEle;
            }
            nearEle = nearEle[type];
            if (!nearEle) {
                break;
            }
        }
        return null;
    }

    /**
     * 组件销毁
     *
     * @memberof AppMobFileUpload
     */
    public destroyed(): void {
        if (this.formStateEvent) {
            this.formStateEvent.unsubscribe();
        }
    }

    /**
     * 上传成功回调
     *
     * @param {*} response
     * @param {*} file
     * @param {*} fileList
     * @returns
     * @memberof AppMobFileUpload
     */
    public onSuccess(response: any, file: any, fileList: any) {
        if (!response) {
            return;
        }
        const data = { name: response.name, id: response.id };
        let arr: Array<any> = [];
        this.files.forEach((_file: any) => {
            arr.push({ name: _file.name, id: _file.id });
        });
        arr.push(data);

        let value: any = arr.length > 0 ? JSON.stringify(arr) : null;
        this.$emit('formitemvaluechange', { name: this.name, value: value });
    }

    /**
     * 上传失败回调
     *
     * @param {*} error
     * @param {*} file
     * @param {*} fileList
     * @memberof AppMobFileUpload
     */
    public onError(error: any, file: any, fileList: any) {
        this.$Notice.error(`${this.$t('upload_failed')}`);
    }

    /**
     * 删除文件
     *
     * @param {*} file
     * @param {*} fileList
     * @memberof AppMobFileUpload
     */
    public onRemove(file: any, fileList: any) {
        let arr: Array<any> = [];
        fileList.forEach((f: any) => {
            if (f.id != file.id) {
                arr.push({ name: f.name, id: f.id });
            }
        });
        let value: any = arr.length > 0 ? JSON.stringify(arr) : null;
        this.$emit('formitemvaluechange', { name: this.name, value: value });
    }

    /**
     * 下载文件
     *
     * @param {*} file
     * @memberof AppMobFileUpload
     */
    public onDownload(file: any) {
        this.dataProcess();
        this.DownloadFile(file.url, file);        
    }

    /**
     * 下载文件
     *
     * @param item AppMobFileList
     * @memberof DiskFileUpload
     */
    public DownloadFile(url: string,file: any) {
        // 发送get请求
        Http.getHttp()({
            method: 'get',
            url: url,
            responseType: 'blob'
        }).then((response: any) => {
            if (!response || response.status != 200) {
                return;
            }
            // 请求成功,后台返回的是一个文件流
            if (response.data) {
                // 获取文件名
                const filename = file.name;
                const ext = '.' + filename.split('.').pop();
                let filetype = this.calcFilemime(ext);
                // 用blob对象获取文件流
                let blob = new Blob([response.data], {type: filetype});
                // 通过文件流创建下载链接
                var href = URL.createObjectURL(blob);
                // 创建一个a元素并设置相关属性
                let a = document.createElement('a');
                a.href = href;
                a.download = filename;
                // 添加a元素到当前网页
                document.body.appendChild(a);
                // 触发a元素的点击事件,实现下载
                a.click();
                // 从当前网页移除a元素
                document.body.removeChild(a);
                // 释放blob对象
                URL.revokeObjectURL(href);
            } else {
                this.$Notice.error(response)
            }
        }).catch((error: any) => {
            console.error(error);
        });
    }

    /**
     * 计算文件mime类型
     *
     * @param filetype 文件后缀
     * @memberof AppMobFileList
     */
    public calcFilemime(filetype: string): string {
        let mime = "image/png";
        switch(filetype) {
            case ".wps":
            mime = "application/kswps";
            break;
            case ".doc":
            mime = "application/msword";
            break;
            case ".docx":
            mime = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            break;
            case ".txt":
            mime = "text/plain";
            break;
            case ".zip":
            mime = "application/zip";
            break;
            case ".png":
            mime = "imgage/png";
            break;
            case ".gif":
            mime = "image/gif";
            break;
            case ".jpeg":
            mime = "image/jpeg";
            break;
            case ".jpg":
            mime = "image/jpeg";
            break;
            case ".rtf":
            mime = "application/rtf";
            break;
            case ".avi": 
            mime = "video/x-msvideo";
            break;
            case ".gz": 
            mime = "application/x-gzip";
            break;
            case ".tar": 
            mime = "application/x-tar";
            break;
        }
        return mime; 
    }

}
</script>