<template>
    <div class="head-img p-rtv c-s-p" @click="editCropper()">
        <slot>
            <HAvatar :size="82" :src="(options.img as string)" :name="options.name" :defSrc="defSrc" :fit="fit" :shape="shape"></HAvatar>
            <div v-if="isIcon" class="icon-edit">
                <el-icon><EditPen /></el-icon>
            </div>
        </slot>
        <el-dialog :title="title" v-model="open" width="800px" custom-class="custom-dialog" append-to-body @opened="modalOpened" @close="closeDialog">
            <el-row>
                <el-col :xs="24" :md="12" :style="{ height: '350px' }">
                    <vue-cropper ref="cropper" :img="options.img" :info="true" :autoCrop="options.autoCrop" :maxImgSize="4000" :fixedBox="options.fixedBox" :autoCropWidth="300" :autoCropHeight="300" :full="true" :outputType="options.outputType" @realTime="realTime" v-if="visible" />
                </el-col>
                <el-col :xs="24" :md="12" class="d-flex j-c a-c" :style="{ height: '350px' }">
                    <div class="avatar-upload-preview" :class="{ 'square':  shapeImg === 'square'}">
                        <img :src="options.previews.url" :style="options.previews.img" />
                    </div>
                </el-col>
            </el-row>
            <br />
            <el-row>
                <el-col :lg="2" :md="2">
                    <el-upload action="#" :http-request="requestUpload" :show-file-list="false" accept=".png,.jpg,.jpeg,.bmp" :before-upload="beforeUpload">
                        <el-button>
                            选择
                            <el-icon class="el-icon--right">
                                <Upload />
                            </el-icon>
                        </el-button>
                    </el-upload>
                </el-col>
                <el-col :lg="{ span: 1, offset: 2 }" :md="2">
                    <el-button icon="Plus" @click="changeScale(1)"></el-button>
                </el-col>
                <el-col :lg="{ span: 1, offset: 1 }" :md="2">
                    <el-button icon="Minus" @click="changeScale(-1)"></el-button>
                </el-col>
                <el-col :lg="{ span: 1, offset: 1 }" :md="2">
                    <el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
                </el-col>
                <el-col :lg="{ span: 1, offset: 1 }" :md="2">
                    <el-button icon="RefreshRight" @click="rotateRight()"></el-button>
                </el-col>
                <el-col :lg="{ span: 2, offset: 6 }" :md="2">
                    <el-button type="primary" @click="uploadImg()">提 交</el-button>
                </el-col>
            </el-row>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
import 'vue-cropper/dist/index.css';
import { VueCropper } from 'vue-cropper';
import useUserStore from '@/store/modules/user';
import { propTypes } from '@/utils/propTypes';
import { uploadFile } from '@/api/system/oss';

interface Options {
    img: string | ArrayBuffer | null; // 裁剪图片的地址
    autoCrop: boolean; // 是否默认生成截图框
    name: string; // 是否默认生成截图框
    // autoCropWidth: number; // 默认生成截图框宽度
    // autoCropHeight: number; // 默认生成截图框高度
    fixedBox: boolean; // 固定截图框大小 不允许改变
    fileName: string;
    previews: any; // 预览数据
    outputType: string;
    visible: boolean;
}
const props = defineProps({
    title: propTypes.string.def('修改头像'),
    modelValue: propTypes.any.def(null),
    name: propTypes.string.def(''),
    defSrc: propTypes.string.def(''),
    isIcon: propTypes.bool.def(true),
    fit: propTypes.any.def('cover'),
    shape: propTypes.any.def('circle'),
    isObject: propTypes.bool.def(false),
    shapeImg: propTypes.any.def('circle')
});

const userStore = useUserStore();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;

const open = ref(false);
const visible = ref(false);
const cropper = ref<any>({});
//图片裁剪数据
const options = reactive<Options>({
    img: '',
    name: '',
    autoCrop: true,
    fixedBox: true,
    outputType: 'jpeg',
    fileName: '',
    previews: {},
    visible: false
});

/** 编辑头像 */
const editCropper = () => {
    open.value = true;
};
/** 打开弹出层结束时的回调 */
const modalOpened = () => {
    visible.value = true;
};
/** 覆盖默认上传行为 */
const requestUpload = (): any => {};
/** 向左旋转 */
const rotateLeft = () => {
    cropper.value.rotateLeft();
};
/** 向右旋转 */
const rotateRight = () => {
    cropper.value.rotateRight();
};
/** 图片缩放 */
const changeScale = (num: number) => {
    num = num || 1;
    cropper.value.changeScale(num);
};
/** 上传预处理 */
const beforeUpload = (file: any) => {
    if (file.type.indexOf('image/') == -1) {
        proxy?.$modal.msgError('文件格式错误，请上传图片类型,如：JPG，PNG后缀的文件。');
    } else {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
            options.img = reader.result;
            // 获取图片后缀名
            const suffix = file.name.split('.').pop();
            if (suffix === 'png') {
                options.outputType = 'png';
            } else {
                options.outputType = 'jpeg';
            }
            options.fileName = file.name;
        };
    }
};
const emit = defineEmits(['update:modelValue', 'change']);
/** 上传图片 */
const uploadImg = async () => {
    cropper.value.getCropBlob(async (data: any) => {
        let formData = new FormData();
        formData.append('file', data, options.fileName);
        const res = await uploadFile(formData);
        if (!res || res.code !== 200) return;
        if (props.isObject) {
            emit('update:modelValue', { url: res.data.url, fileName: options.fileName });
            emit('change', { url: res.data.url, fileName: options.fileName });
        } else {
            emit('update:modelValue', res.data.url);
            emit('change', res.data.url);
        }

        open.value = false;
    });
};
/** 实时预览 */
const realTime = (data: any) => {
    options.previews = data;
};
/** 关闭窗口 */
const closeDialog = () => {
    options.visible = false;
};
watch(
    () => props.modelValue,
    async (val) => {
        if (val) {
            if (props.isObject) {
                options.img = val?.url as string;
                options.fileName = val?.fileName as string;
                // 获取图片后缀名
                const suffix = val?.url?.split('.').pop();
                if (suffix === 'png') {
                    options.outputType = 'png';
                } else {
                    options.outputType = 'jpeg';
                }
            } else {
                options.img = val as string;
                const suffix = val?.split('.').pop();
                if (suffix === 'png') {
                    options.outputType = 'png';
                } else {
                    options.outputType = 'jpeg';
                }
            }
        }
    },
    { deep: true, immediate: true }
);
watch(
    () => props.name,
    async (val) => {
        if (val) {
            options.name = val as string;
        }
    },
    { deep: true, immediate: true }
);
</script>

<style lang="scss" scoped>
.user-info-head {
    position: relative;
    display: inline-block;
    height: 120px;
}

.user-info-head:hover:after {
    content: '+';
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    color: #eee;
    background: rgba(0, 0, 0, 0.5);
    font-size: 24px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    cursor: pointer;
    line-height: 110px;
    border-radius: 50%;
}
.icon-edit {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 20px;
    height: 20px;
    color: #fff;
    line-height: 20px;
    text-align: center;
    font-size: 14px;
    background: radial-gradient(70% 0% at 0% 0%, #0fd2a8 0%, #01e093 100%), #ffffff;
    border-radius: 50%;
}
.avatar-upload-preview.square {
    border-radius: 2px;
}
.avatar-upload-preview {
    width: 300px;
    height: 300px;
    border-radius: 50%;
    margin: auto;
    box-shadow: 0 0 4px #ccc;
    overflow: hidden;
}
</style>
