<!--
 * @Author: PoJun
 * @Date: 2023-10-09 15:51:12
 * @LastEditors: PoJun
 * @LastEditTime: 2024-01-05 15:30:22
 * @Message: 表单
-->
<template>
    <uv-form :labelPosition="labelPosition" :labelWidth="labelWidth" :labelStyle="labelStyle">
        <block v-for="(item, index) in dataList" :key="index">
            <!-- 输入框 -->
            <uv-form-item
                v-if="item.type == 'input' && item.canShow"
                :label="item.label"
                :required="item.required"
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                borderBottom
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <uv-input
                    :readonly="!item.canEdit"
                    :value="item.sv"
                    :placeholder="item.canEdit ? (item.placeholder ? item.placeholder : '请输入') : '暂无'"
                    @input="inputChange($event, item)"
                    inputAlign="right"
                    fontSize="14px"
                    border="none"
                    :suffixIcon="item.canEdit ? 'edit-pen' : ''"
                    :suffixIconStyle="suffixIconStyle"
                    :type="item.inputType ? item.inputType : 'input'"
                ></uv-input>
            </uv-form-item>
            <!-- 文本域 -->
            <uv-form-item
                v-else-if="item.type == 'textarea' && item.canShow"
                :label="item.label"
                :required="item.required"
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                borderBottom
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <uv-textarea
                    :value="item.sv"
                    :placeholder="item.canEdit ? (item.placeholder ? item.placeholder : '请输入') : '暂无'"
                    border="none"
                    @input="inputChange($event, item)"
                    :autoHeight="true"
                    :textStyle="{ fontSize: '14px', textAlign: 'right' }"
                    :readonly="!item.canEdit"
                    :disabled="!item.canEdit"
                ></uv-textarea>
            </uv-form-item>
            <!-- 日期时间 -->
            <uv-form-item
                v-else-if="item.type == 'datetime' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                @click="item.canEdit && openTimePicker(item)"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <uv-input
                    inputAlign="right"
                    fontSize="14px"
                    border="none"
                    :value="item.sv"
                    :placeholder="item.canEdit ? (item.placeholder ? item.placeholder : '请选择时间') : '暂无'"
                    readonly
                    :suffixIcon="item.canEdit ? 'arrow-down' : ''"
                    :suffixIconStyle="suffixIconStyle"
                ></uv-input>
            </uv-form-item>
            <!-- 单选 -->
            <uv-form-item
                v-else-if="item.type == 'radio' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                @click="item.canEdit && openRadioPicker(item)"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <uv-input
                    inputAlign="right"
                    fontSize="14px"
                    border="none"
                    :value="item.sv"
                    :placeholder="item.canEdit ? (item.placeholder ? item.placeholder : '请选择') : '暂无'"
                    readonly
                    :suffixIcon="item.canEdit ? 'arrow-down' : ''"
                    :suffixIconStyle="suffixIconStyle"
                ></uv-input>
            </uv-form-item>
            <!-- 多选 -->
            <uv-form-item
                v-else-if="item.type == 'multiple' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                @click="item.canEdit && openMultiplePicker(item)"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <uv-input
                    inputAlign="right"
                    fontSize="14px"
                    border="none"
                    :value="item.sv"
                    :placeholder="item.canEdit ? (item.placeholder ? item.placeholder : '请选择') : '暂无'"
                    readonly
                    :suffixIcon="item.canEdit ? 'arrow-down' : ''"
                    :suffixIconStyle="suffixIconStyle"
                ></uv-input>
            </uv-form-item>
            <!-- 选人 -->
            <uv-form-item
                v-else-if="item.type == 'person' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                @click="item.canEdit && selectPerson(item)"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <uv-input
                    inputAlign="right"
                    fontSize="14px"
                    border="none"
                    :value="item.sv"
                    :placeholder="item.canEdit ? (item.placeholder ? item.placeholder : '请选择') : '暂无'"
                    readonly
                    :suffixIcon="item.canEdit ? 'arrow-down' : ''"
                    :suffixIconStyle="suffixIconStyle"
                ></uv-input>
            </uv-form-item>
            <!-- 二维码 -->
            <uv-form-item
                v-else-if="item.type == 'qrCode' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <view v-if="item.rv" class="uv-flex-1 uv-flex uv-row-right">
                    <uv-qrcode :loading="false" ref="qrcodeDom" size="120px" :value="getQrcodeUrl(item)"></uv-qrcode>
                </view>
                <uv-input
                    v-else
                    inputAlign="right"
                    fontSize="14px"
                    border="none"
                    placeholder="暂无"
                    readonly
                ></uv-input>
            </uv-form-item>
            <!-- 开关 -->
            <uv-form-item
                v-else-if="item.type == 'switch' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <view class="uv-flex uv-flex-1 uv-row-right">
                    <uv-switch
                        :disabled="!item.canEdit"
                        v-model="item.rv"
                        size="15"
                        @change="switchChange($event, item)"
                        activeValue="true"
                        inactiveValue="false"
                    ></uv-switch>
                </view>
            </uv-form-item>
            <!-- 无标题的图片上传 -->
            <uv-form-item v-else-if="item.type == 'imgUpload' && item.canShow">
                <uv-upload
                    :fileList="getFileList(item.sv)"
                    :name="item.code"
                    :maxCount="item.maxCount"
                    @afterRead="afterRead($event, item)"
                    @delete="deletePic($event, item)"
                    :uploadText="item.uploadText"
                    :width="item.width"
                    :height="item.height"
                ></uv-upload>
            </uv-form-item>
            <!-- 带标题的图片上传 -->
            <uv-form-item
                v-else-if="item.type == 'images' && item.canShow"
                :label="item.label"
                :required="item.required"
                borderBottom
                :leftIcon="item.showIcon ? FormIcon : ''"
                :leftIconStyle="leftIconStyle"
                :customStyle="item.customStyle"
                :labelWidth="item.labelWidth ? item.labelWidth : 150"
            >
                <view class="pj-upload uv-flex uv-flex-1 uv-row-right">
                    <uv-upload
                        :fileList="getFileList(item.sv)"
                        :name="item.code"
                        :maxCount="item.maxCount"
                        @afterRead="afterRead($event, item)"
                        @delete="deletePic($event, item)"
                        :width="item.width"
                        :height="item.height"
                        :disabled="!item.canEdit"
                        :deletable="item.canEdit"
                    ></uv-upload>
                </view>
            </uv-form-item>
            <!-- 附加字段,在某些场景下需要,如安全措施说明 -->
            <slot :name="item.type + '_' + item.code"></slot>
        </block>

        <!-- 日期时间选择器 -->
        <uv-datetime-picker
            ref="datetimePicker"
            :value="dataTimeObj.value"
            :mode="dataTimeObj.mode"
            @confirm="datetimeConfirm"
        ></uv-datetime-picker>

        <!-- 下拉选择器(单选) -->
        <uv-picker ref="picker" :columns="radioObj.columns" @confirm="radioPickerConfirm" keyName="name"></uv-picker>

        <!-- 下拉多选 -->
        <kirin-multiple
            ref="multiplePicker"
            :columns="multipleObj.columns"
            :defaultValue="multipleObj.defaultValue"
            @confirm="multiplePickerConfirm"
        ></kirin-multiple>
    </uv-form>
</template>

<script>
export default {
    props: {
        // { type: "类型", label: "标题", code: "控制唯一名", sv: "展示值", rv: "存储值" },
        list: {
            type: Array,
            default: function () {
                return [];
            },
        },
        labelPosition: {
            type: String,
            default: "left",
        },
        labelWidth: {
            type: String,
            default: "150",
        },
    },
    data() {
        return {
            dataList: [], //表单渲染
            FormIcon: "order",
            leftIconStyle: {
                width: "14px",
                height: "14px",
                top: "1px",
            },
            suffixIconStyle: { "font-size": "12px", color: "#909399", top: "1px" },
            labelStyle: { "font-size": "14px", color: "#676767" },
            // 时间类对象管理,后续增加
            dataTimeObj: {
                value: Number(new Date()),
                mode: "datetime",
                code: "", //对应的展示字段
            },
            // 时间类型格式化定义
            formatRules: {
                date: "yyyy-mm-dd",
                datetime: "yyyy-mm-dd hh:MM",
            },
            // 单选类对象管理, 后续增加
            radioObj: {
                columns: [],
                code: "",
            },
            // 多选类对象管理
            multipleObj: {
                columns: [],
                code: "",
                defaultValue: [],
            },
        };
    },
    methods: {
        /**
         * @description: 获取表单提交数据,做前端校验,不配合uv-ui组件库
         * @return {*}
         */
        getFormData() {
            let data = {};
            let isok = true;
            for (let i = 0, len = this.dataList.length; i < len; i++) {
                const item = this.dataList[i];
                // 必填、可见  可编辑先不放出来
                if (item.required && item.canEdit) {
                    if ((item.rv !== undefined && item.rv != null && item.rv != "") || item.rv == "0") {
                        data[item.code] = item.rv;
                    } else {
                        uni.$uv.toast(item.label + "不能为空");
                        isok = false;
                        break;
                    }
                } else {
                    data[item.code] = item.rv;
                }
            }
            return isok ? data : null;
        },
        /**
         * @description: 获取表定义和数据
         */
        getFormElements() {
            return this.dataList;
        },
        /**
         * @description: 输入框值改变
         * @param {*} value   值
         * @param {*} item    控件对象
         */
        inputChange(value, item) {
            item.sv = item.rv = value;
        },
        /**
         * @description: 日期时间打开事件
         * @param {*} value    值
         * @param {*} code     表单字段属性名
         * @param {*} mode     日期类型,
         */
        openTimePicker({ rv, code, mode }) {
            if (rv) {
                this.dataTimeObj.value = new Date(rv).getTime();
            }
            this.dataTimeObj.code = code;
            if (mode) {
                this.dataTimeObj.mode = mode;
            }
            this.$refs.datetimePicker.open();
        },
        /**
         * @description: 日期时间确认事件
         * @param {*} value
         */
        datetimeConfirm({ value }) {
            const formattedValue = uni.$uv.timeFormat(value, this.formatRules[this.dataTimeObj.mode]);
            const item = this.getItemFromList(this.dataTimeObj.code);
            // 时间类需要做毕竟,由于机制问题必须在表单类完成
            if (item.compare) {
                const targetItem = this.getItemFromList(item.compare.code);
                const targetTime = new Date(targetItem.rv).getTime();
                if (item.compare.condition == "less") {
                    if (value > targetTime && targetTime != 0) {
                        uni.$uv.toast(`${targetItem.label}不能小于${item.label}`);
                    } else {
                        this.$set(item, "sv", formattedValue);
                        this.$set(item, "rv", formattedValue);
                    }
                } else if (item.compare.condition == "greater") {
                    if (value < targetTime && targetTime != 0) {
                        uni.$uv.toast(`${item.label}不能大于${targetItem.label}`);
                    } else {
                        this.$set(item, "sv", formattedValue);
                        this.$set(item, "rv", formattedValue);
                    }
                }
            } else {
                this.$set(item, "sv", formattedValue);
                this.$set(item, "rv", formattedValue);
            }
        },
        /**
         * @description: 页面单选弹窗
         * @param {*} item       表单字段对象
         */
        async openRadioPicker({ rv, code, dictCode, options }) {
            this.radioObj.code = code;
            let columns = null;
            // 使用vuex的缓存数据 或者自带的选项
            if (options) {
                columns = options;
            } else {
                columns = this.vuex_dict[dictCode];
            }
            this.radioObj.columns = [columns];
            this.$refs.picker.open();
            const index = columns.findIndex(item => item.key == rv);
            this.$refs.picker.setIndexs(index == -1 ? [0] : [index], true);
        },
        /**
         * @description: 页面单选确认
         * @param {*} value
         */
        radioPickerConfirm({ value }) {
            const item = this.getItemFromList(this.radioObj.code);
            this.$set(item, "sv", value[0].name);
            this.$set(item, "rv", value[0].key);
            // 选择事件后续扩展, 由json数据定义死
            if (item.ext) {
                const otherItem = this.getItemFromList(item.ext.code);
                this.$set(otherItem, "canShow", value[0].key == "9999");
            }
        },
        /**
         * @description: 页面多选弹窗
         * @param {*} item       表单字段对象
         */
        openMultiplePicker({ rv, code, dictCode }) {
            this.multipleObj.code = code;
            this.multipleObj.defaultValue = rv ? rv.split(",") : [];
            const columns = this.vuex_dict[dictCode];
            this.multipleObj.columns = columns;
            this.$refs.multiplePicker.open();
        },
        /**
         * @description: 页面多选确认
         * @param {*} value
         */
        multiplePickerConfirm({ sv, rv }) {
            const item = this.getItemFromList(this.multipleObj.code);
            this.$set(item, "sv", sv);
            this.$set(item, "rv", rv);
        },
        /**
         * @description: 跳转选人界面, 并携带参数
         * @param {*} item    表单字段对象
         */
        selectPerson(item) {
            uni.navigateTo({
                url: "/subpkg/common/select-person/index?type=" + item.selectType + "&roleCode=" + item.roleCode,
                events: {
                    acceptDataFromOpenedPage: data => {
                        // 小程序对象赋值不会触发到源属组,
                        const element = this.getItemFromList(item.code);
                        this.$set(element, "sv", data.sv);
                        this.$set(element, "rv", data.rv);
                    },
                },
                success: res => {
                    res.eventChannel.emit("acceptDataFromOpenerPage", { id: item.rv });
                },
            });
        },
        /**
         * @description: 获取图片展示
         * @param {*} id   图片id
         */
        getImageUrl(id) {
            return id ? process.env.VUE_APP_BASE_API + `/files/${id}/show_image` : "";
        },
        /**
         * @description: 通过code从源数据列表获取当前需要操作的对象.注:小程序对引用对象的定义有问题.md
         * @param {*} code    控件字段
         */
        getItemFromList(code) {
            const item = this.dataList.find(data => data.code == code);
            return item;
        },
        /**
         * @description: 开关切换,表单外部需要对数据做处理,但是时间问题没做,所以这里直接自定义
         * @param {*} value
         * @param {*} item
         */
        switchChange(value, item) {
            item.sv = value;
            // item里面增加扩展参数,用于在切换的时候开关某些字段,后续所有的布尔值都用字符串表达
            const list = this.dataList.filter(data => item.showHide.includes(data.code));
            list.forEach(data => {
                this.$set(data, "canShow", value == "true" ? true : false);
            });
        },
        /**
         * @description: 获取二维码展示的的url
         * @param {*} item
         */
        getQrcodeUrl(item) {
            return `${process.env.VUE_APP_BASE_URL}/hdzy/huiqian?tokenid=${item.rv}&restype=${item.resType}`;
        },
        /**
         * @description: 上传图片, h5目前不支持上传
         * @param {*} event
         * @param {*} item
         */
        async afterRead(event, item) {
            const vuex_token = uni.getStorageSync("vuex_token");
            uni.uploadFile({
                url: process.env.VUE_APP_BASE_API + "/files/upload",
                filePath: event.file.url,
                name: "files",
                header: { satoken: vuex_token },
                success: res => {
                    let trueRes = JSON.parse(res.data);
                    if (trueRes.code == 200) {
                        const id = trueRes.data[0].id;
                        const val = item.rv ? item.rv + "," + id : id;
                        this.$set(item, "sv", val);
                        this.$set(item, "rv", val);
                    } else {
                        uni.$uv.toast("上传失败");
                    }
                },
                fail: function () {
                    uni.$uv.toast("上传失败");
                },
            });
        },
        /**
         * @description: 删除图片
         * @param {*} event
         * @param {*} item
         */
        deletePic(event, item) {
            let arr = item.rv ? item.rv.split(",") : [];
            arr.splice(event.index, 1);
            this.$set(item, "sv", arr.join(","));
            this.$set(item, "rv", arr.join(","));
        },
        /**
         * @description: 图片展示
         * @param {*} ids
         * @return {*}
         */
        getFileList(ids) {
            if (!ids) {
                return [];
            }
            let arr = ids.split(",");
            return arr.map(id => {
                return { url: process.env.VUE_APP_BASE_API + `/files/${id}/show_image` };
            });
        },
    },
    watch: {
        list: {
            deep: true,
            immediate: true,
            handler: function (val) {
                if (val && val.length) {
                    this.dataList = JSON.parse(JSON.stringify(val));
                }
            },
        },
    },
};
</script>

<style lang="scss" scoped></style>
