<template>
    <div class="flex flex-pack-center" style="height: 100%;height: 100%;margin-top: 5px;">
        <!--左侧面板-->
        <div class="dev-container dev-left-panel">
            <el-tabs value="name0" :stretch="true" style="width: 100%">
                <template v-for="(tab,cptIndex) in cptList">
                    <el-tab-pane v-if="tab.fdType == 1" :label="tab.fdName" :name="'name' + cptIndex">
                        <template v-for="menu in tab.children">
                            <el-collapse value="itemName">
                                <el-collapse-item v-if="menu.fdType == 2" :title="menu.fdName" name="itemName">
                                    <template slot="title">
                                        <span class="dev-collapse-title">{{ menu.fdName }}</span>
                                    </template>
                                    <template v-for="(item,index) in menu.children">
                                        <div v-if="item.fdType == 3" class="dev-panel-item">
                                            <div class="dev-comp-item" :data-type="item.fdId"
                                                 @click="clickItemEvent(item.fdId)">
                                                <i :class="item.fdIcon"/>&nbsp;{{ item.fdName }}
                                            </div>
                                        </div>
                                    </template>
                                </el-collapse-item>
                            </el-collapse>
                        </template>
                    </el-tab-pane>
                </template>
            </el-tabs>
        </div>
        <ap-split-panel></ap-split-panel>

        <!--中间面板-->
        <div class="flex-1 flex flex-direction-column" style="overflow: auto;">
            <ap-container>
                <ap-header margin="0111" height="40%" style="overflow: auto;">
                    <template v-if="showItem">
                        <!--                        <dynamic-item/>-->
                        <vue-render :options.sync="vueCode"></vue-render>
                    </template>
                    <template v-else>
                        组件加载中...
                    </template>
                </ap-header>
                <ap-main margin="0101" style="overflow: auto;background-color: #f9f2f4;">
                    <div style="position: relative;float: right;">
                        <el-button-group>
                            <el-button icon="el-icon-copy" @click="copyCode($event)">复制</el-button>
                            <el-button icon="el-icon-mokuai3" @click="getDevCptInfo">刷新配置</el-button>
                        </el-button-group>
                    </div>
                    <div class="dev-code">
                        {{ template }}
                    </div>
                </ap-main>
            </ap-container>
        </div>

        <!--右侧面板-->
        <div class="dev-container dev-right-panel flex flex-direction-column">
            <div class="flex-1" style="overflow: auto">
                <el-tabs value="name0" :stretch="true">
                    <template v-for="(tab,paramIndex) in paramTabList">
                        <el-tab-pane :label="tab" :name="'name' + paramIndex" style="padding-left: 10px;">
                            <template v-for="param in paramList">
                                <template v-if="param.fdTab == tab">
                                    <div class="flex-justify-start" v-if="checkShowCondition(param) && (param.fdParentId == null || param.fdParentId == '')">
                                        <div class="param-label">
                                            {{param.fdName}}
                                            <el-tooltip v-if="param.fdTip != null && param.fdTip != ''" effect="dark" :content="param.fdTip" placement="top-end">
                                                <i class="el-icon-wenhao2" />
                                            </el-tooltip>
                                        </div>
                                        <el-input v-if="param.fdShowType == 1" v-model="param.value" :placeholder="param.fdPlaceholder"
                                                  style="width: 280px;" @input="changeEvent(param)"/>

                                        <el-switch v-if="param.fdShowType == 2" v-model="param.value" active-value="1" inactive-value="0"
                                                   @change="changeEvent(param)"/>

                                        <el-select v-if="param.fdShowType == 3" v-model="param.value" @input="changeEvent(param)" clearable >
                                            <template v-for="option in handelOption(param)">
                                                <el-option :label="option.label" :value="option.value"/>
                                            </template>
                                        </el-select>

                                        <div v-if="param.fdShowType == 4">
                                            <el-input :value="param.value"  style="width: 215px;" :readonly="true"/>
                                            <el-button size="mini" type="primary" plain @click="openDialog(param)"
                                                       style="padding: 6px 10px;margin-left: 5px"><i class="el-icon-s-tools"/> 配置
                                            </el-button>
                                        </div>

                                        <el-radio-group v-if="param.fdShowType == 5" v-model="param.value" @change="changeEvent(param)">
                                            <template v-for="option in handelOption(param)">
                                                <el-radio :label="option.value">{{ option.label }}</el-radio>
                                            </template>
                                        </el-radio-group>

                                        <el-input v-if="param.fdShowType == 6" type="textarea" v-model="param.value"
                                                  :placeholder="param.fdPlaceholder" :rows="2" style="width: 280px;"
                                                  @input="changeEvent(param)"/>

                                        <el-input-number v-if="param.fdShowType == 7" v-model="param.value" @change="changeEvent(param)"
                                                         :min="handelOptionObj(param).min"
                                                         :max="handelOptionObj(param).max"
                                                         label="描述文字"></el-input-number>

                                    </div>
                                    <div v-if="param.fdShowLine == 1" class="ap-split-line"/>
                                </template>
                            </template>
                        </el-tab-pane>
                    </template>
                </el-tabs>
            </div>
        </div>

        <!-- 数组参数弹框 -->
        <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="1000px">
            <div style="height: 350px;">
                <ap-table v-if="dialogVisible" ref="tableRef" :options.sync="tableOpts"></ap-table>
            </div>
            <span slot="footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="saveArrayParam">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
import VueRender from './../base/VueRender'
import clipboard from 'ap-util/util/ClipboardUtil'
import {convertToTreeData} from 'ap-util/util/DataUtil'


export default {
    name: 'ComponentsPanel',
    components: {
        VueRender: VueRender
    },
    data() {
        return {
            showItem: true,
            vueCode: '',
            cptList: [], // 组件清单列表
            cptInfo: {}, // 组件信息
            baseInfo: {}, // 组件基础模板信息
            cptTemplateList: [], // 组件模板列表
            cptTemplateObj: {}, // 组件模板对象
            paramTabList: [], // 参数页签列表
            paramList: [], // 参数列表
            paramObj: {}, // 参数对象
            paramTemplateList: [], // 参数模板列表
            paramTemplateObj: {}, // 参数模板对象
            template: '', // 代码

            dialogTitle: '',
            dialogVisible: false,
            tableOpts: {},
            currentArrayParam: {}, // 当前数组参数
        }
    },
    computed: {},
    created() {
        this.getDevCpt();
    },
    methods: {
        getDevCpt() {
            this.$request({
                url: '/apd/TDevCpt/getCptList',
                method: 'post',
                data: {}
            }).then(response => {
                this.cptList = convertToTreeData(response.data, {
                    idKey: 'fdId',
                    parentKey: 'fdParentId',
                    childrenKey: 'children'
                });
            })
        },
        clickItemEvent(id) {
            this.currentCptId = id;
            this.getDevCptInfo();
        },
        getDevCptInfo() {
            this.$request({
                url: '/apd/TDevCpt/getDevCptInfo',
                method: 'post',
                data: {
                    id: this.currentCptId
                }
            }).then(response => {
                let data = response.data;
                this.getParamTabList(data.paramList);
                this.cptInfo = data.cptInfo;
                this.baseInfo = data.baseInfo;
                this.paramList = data.paramList;
                this.paramTemplateList = data.paramTemplateList;
                this.cptTemplateList = data.cptTemplateList;
                this.initParam();
                this.renderTemplate();
            })
        },
        getParamTabList(list) {
            let tabNameList = [];
            for (let i = 0; i < list.length; i++) {
                tabNameList.push(list[i].fdTab);
            }
            this.paramTabList = Array.from(new Set(tabNameList));
        },
        // 参数选项值转为数组
        handelOption(param) {
            let options = param.fdOption;
            if (options == null || options == "") {
                return [];
            }
            let res = eval(options);
            return res;
        },
        // 参数选项值转为对象
        handelOptionObj(param) {
            let options = param.fdOption;
            if (options == null || options == "") {
                return {};
            }
            let res = {};
            eval("res = " + options)
            return res;
        },
        // 初始化参数信息：value
        initParam() {
            let paramList = this.paramList;
            // 处理参数的value 默认赋值fdValue
            for (let i = 0; i < paramList.length; i++) {
                paramList[i].value = paramList[i].fdValue;
            }
        },
        // 判定是否显示参数
        checkShowCondition(param) {
            let showCondition = param.fdShowCondition;
            if (showCondition == null || showCondition == "") {
                return true;
            }
            let condition = this.replaceTemplateParam(showCondition);
            return eval(condition);
        },
        // 判定是否添加参数到代码
        checkAddCondition(addCondition) {
            if (addCondition == null || addCondition == "") {
                return true;
            }
            let condition = this.replaceTemplateParam(addCondition);
            return eval(condition);
        },
        // 判定是否使用默认参数
        checkDefaultCondition(defaultCondition) {
            if (defaultCondition == null || defaultCondition == "") {
                return false;
            }
            let condition = this.replaceTemplateParam(defaultCondition);
            return eval(condition);
        },
        // 模板赋值 -> type:1参数模板 2组件模板
        handleTemplate(template, type) {
            let res = "";

            // 判断是否添加模板
            if (!this.checkAddCondition(template.fdAddCondition)) {
                return "";
            }

            // 判断是否使用默认模板
            if (this.checkDefaultCondition(template.fdDefaultCondition)) {
                res = template.fdDefault;
            } else {
                res = template.fdTemplate;
            }

            // 处理左侧空格
            let letfSpace = template.fdLeftSpace;
            if (letfSpace != null && letfSpace > 0) {
                let str = "";
                for (let i = 0; i < letfSpace; i++) {
                    str += " ";
                }
                res = str + res;
                res = res.replaceAll("\n", "\n" + str);
            }

            // 参数模板
            if (type == 1) {
                return this.replaceTemplateParam(res);
            }

            // 组件模板
            if (type == 2) {
                return this.replaceTemplateCpt(res);
            }

        },
        changeEvent(param) {
            this.renderTemplate();
        },
        // 渲染代码
        renderTemplate() {
            // 设定参数对象
            this.initParamObj();

            // 设定参数模板
            this.initParamTemplate();

            // 设定参数对象 - 数组形式
            this.initParamObjForArr();

            // 设定参数模板 -> 补充数组参数模板
            this.initParamTemplate();

            // 设定组件模板
            this.initCptTemplate();

            // 设定组件基础模板
            this.initBaseTemplate();
        },
        // 设定参数对象
        initParamObj() {
            let paramList = this.paramList;
            // 设定参数对象
            let param = {};
            for (let i = 0; i < paramList.length; i++) {
                param[paramList[i].fdCode] = {
                    value: paramList[i].value,
                    defaultCondition: paramList[i].fdDefaultCondition,
                }
            }
            this.paramObj = param;
            console.log("paramObj: 参数对象");
            console.log(param);
        },
        // 替换模板中的参数
        replaceTemplateParam(template) {
            if (template == null) {
                return "";
            }
            // 正则参数：例：${InputChangeEvent.value}
            let reg = new RegExp(/\${\w*\.\w*}/g);
            let paramArr = template.match(reg);
            if (paramArr == null) {
                return template;
            }
            for (let j = 0; j < paramArr.length; j++) {
                let pTemp = paramArr[j].substring(2, paramArr[j].length - 1).split(".");
                // 参数实际值
                let paramValue = this.paramObj[pTemp[0]];
                let replaceStr = "";
                if (paramValue == null) {
                    replaceStr = `###error: 获取参数对象为空 ${paramArr[j]}###`;
                } else {
                    let value = paramValue[pTemp[1]];
                    if (value == null || value == "") {
                        replaceStr = "";
                    } else {
                        replaceStr = value;
                    }
                }
                template = template.replaceAll(paramArr[j], replaceStr);
            }
            return template;
        },
        // 设定参数对象 - 数组形式
        initParamObjForArr() {
            let paramList = this.paramList;
            // 处理参数的value 默认赋值fdValue
            for (let i = 0; i < paramList.length; i++) {
                let param = paramList[i];
                // 字符串形式不处理
                if (param.fdShowType != 4) {
                    continue;
                }

                // 数组形式：第一次需要赋值，编辑修改。无需再次赋值
                let fdValue = param.fdValue;
                if (param.arrValue == null) {
                    if (fdValue == null || fdValue == "") {
                        param.arrValue = [];
                        param.value = "";
                        continue;
                    }
                    param.arrValue = eval(param.fdValue);
                }
                let pv = this.getArrayParamValue(param);
                param.value = pv;
                // 设定参数对象
                this.paramObj[param.fdCode].value = pv;
            }
        },
        // 替换组件模板的参数
        replaceTemplateCpt(template) {
            if (template == null) {
                return "";
            }

            // 正则参数：例：${attrs}
            let reg = new RegExp(/\${\w*}/g);
            // 正则参数：例：${attrs#,}
            let regCustom = new RegExp(/\${\w*#[^$]*}/g);

            // 参数赋值：数组默认拼接
            let paramArr = template.match(reg);
            if (paramArr != null) {
                for (let j = 0; j < paramArr.length; j++) {
                    // 参数实际值
                    let attrName = paramArr[j].substring(2, paramArr[j].length - 1);
                    let valueObj = this.paramTemplateObj[attrName];
                    if (valueObj == null) {
                        // 不存在参数数组，替换为空
                        template = template.replaceAll(paramArr[j], "");
                    } else {
                        template = template.replaceAll(paramArr[j], valueObj.join(" "));
                    }

                }
            }

            // 参数赋值：数组自定义拼接
            let paramArr2 = template.match(regCustom);
            if (paramArr2 != null) {
                for (let j = 0; j < paramArr2.length; j++) {
                    // 参数实际值
                    let attrName = paramArr2[j].substring(2, paramArr2[j].length - 1).split("#");
                    let valueObj = this.paramTemplateObj[attrName[0]];
                    if (valueObj == null) {
                        // 不存在参数数组，替换为空
                        template = template.replaceAll(paramArr2[j], "");
                    } else {
                        let splitStr = attrName[1].replaceAll("\\n", "\n")
                        template = template.replaceAll(paramArr2[j], valueObj.join(splitStr));
                    }
                }
            }

            return template;
        },
        // 设定参数模板
        initParamTemplate() {
            let templates = this.paramTemplateList;

            for (let i = 0; i < templates.length; i++) {
                templates[i].template = this.handleTemplate(templates[i], 1);
            }

            // 参数模板对象
            let templateObj = {};
            for (let i = 0; i < templates.length; i++) {
                let paramName = templates[i].fdParamName;
                if (templateObj[paramName] == null) {
                    templateObj[paramName] = [];
                }
                let tmp = templates[i].template;
                if (tmp != null && tmp != "") {
                    templateObj[paramName].push(templates[i].template);
                }
            }

            this.paramTemplateObj = templateObj;
            // console.log("paramTemplateObj: 参数模板对象");
            // console.log(templateObj);
        },
        // 设定组件模板
        initCptTemplate() {
            let templates = this.cptTemplateList;
            for (let i = 0; i < templates.length; i++) {
                templates[i].template = this.handleTemplate(templates[i], 2);
            }

            // 组件模板对象
            let templateObj = {};
            for (let i = 0; i < templates.length; i++) {
                let paramName = templates[i].fdParamName;
                if (templateObj[paramName] == null) {
                    templateObj[paramName] = [];
                }
                let tmp = templates[i].template;
                if (tmp != null && tmp != "") {
                    templateObj[paramName].push(templates[i].template);
                }
            }

            this.cptTemplateObj = templateObj;
            // console.log("cptTemplateObj: 组件模板");
            // console.log(this.cptTemplateObj);
        },
        handleTemplateLeftSpace(template){
            let res = [];
            let lines = template.split("\n");
            let reg = new RegExp(/\s+\${/g);
            for (let i = 0; i < lines.length; i++) {
                let line = lines[i];
                let lineTemp = line.match(reg);
                if (lineTemp != null && lineTemp.length > 0) {
                    line = line.trimLeft();
                }
                res.push(line);
            }
            return res.join("\n");
        },
        // 设定组件基础模板
        initBaseTemplate() {
            let baseInfo = this.baseInfo;
            let cptTemplateObj = this.cptTemplateObj;
            // 正则参数：例：${attrs}
            let reg = new RegExp(/\${\w*}/g);
            // 正则参数：例：${attrs#,}
            let regCustom = new RegExp(/\${\w*#[^}]*}/g);
            let template = this.baseInfo.fdTemplate;
            if (template == null) {
                template = "组件的基础模板不存在";
                return;
            }
            template = this.handleTemplateLeftSpace(template);

            // 参数赋值：数组默认拼接
            let paramArr = template.match(reg);
            if (paramArr != null) {
                for (let j = 0; j < paramArr.length; j++) {
                    // 参数实际值
                    let attrName = paramArr[j].substring(2, paramArr[j].length - 1);
                    let valueObj = cptTemplateObj[attrName];
                    if (valueObj == null) {
                        // 不存在参数数组，替换为空
                        template = template.replaceAll(paramArr[j], "");
                    } else {
                        template = template.replaceAll(paramArr[j], valueObj.join(" "));
                    }
                }
            }

            // 参数赋值：数组自定义拼接
            let paramArr2 = template.match(regCustom);
            if (paramArr2 != null) {
                for (let j = 0; j < paramArr2.length; j++) {
                    // 参数实际值
                    let attrName = paramArr2[j].substring(2, paramArr2[j].length - 1).split("#");
                    let valueObj = cptTemplateObj[attrName[0]];
                    if (valueObj == null) {
                        // 不存在参数数组，替换为空
                        template = template.replaceAll(paramArr2[j], "");
                    } else {
                        template = template.replaceAll(paramArr2[j], valueObj.join(attrName[1]));
                    }
                }
            }
            this.template = template;

            // console.log("cptTemplateObj: 组件模板对象");
            // console.log(this.cptTemplateObj);
            this.vueCode = this.template;
        },
        renderCode() {
            this.vueCode = this.template;
        },
        copyCode(event) {
            clipboard(this.vueCode, event)
        },
        initDialogTableOpts() {
            let paramList = this.paramList;
            let columns = [];
            for (let i = 0; i < paramList.length; i++) {
                let param = paramList[i];
                if (param.fdParentId == this.currentArrayParam.fdId) {
                    let col = {
                        prop: param.fdCode,
                        label: param.fdName,
                    };
                    // 显示:1input2开关3下拉单选4数组5单选6text7计数
                    switch (param.fdShowType) {
                        case 1:
                        case 6:
                            col.type = "input";
                            break;
                        case 7:
                            col.type = "inputNumber";
                            col.inputNumberMin = this.handelOptionObj(param).min;
                            col.inputNumberMax = this.handelOptionObj(param).max;
                            break;
                        case 2:
                        case 3:
                        case 5:
                            col.selectOptions = eval(param.fdOption)
                            col.type = "select";
                            break;
                    }

                    columns.push(col);
                }
            }
            let tempData = eval(this.currentArrayParam.fdValue);
            let localData = tempData;
            let tableOpt = {
                title: "数组列表",
                columns: columns,
                localData: localData,
                toolbarBtn: ["add", "edit", "del"],
                initData: true, // 默认false
                pagination: {pageSizes: [100],pageSize: 100}
            };

            this.tableOpts = tableOpt;
        },
        openDialog(param) {
            this.dialogTitle = param.fdName;
            this.dialogVisible = true;
            this.currentArrayParam = param;
            this.initDialogTableOpts();
        },
        // 当前数组参数对象
        initFullObj(arrParam) {
            let fullObj = {};
            for (let i = 0; i < arrParam.length; i++) {
                fullObj[arrParam[i].fdCode] = null;
            }
            return fullObj;
        },
        // 返回当前数组参数的子参数值
        getArrayParamValue(currentParam) {
            // 获取当前数组参数的子参数
            let id = currentParam.fdId;
            let arrParam = [];
            let paramList = this.paramList;
            for (let i = 0; i < paramList.length; i++) {
                if (paramList[i].fdParentId == id) {
                    arrParam.push(paramList[i]);
                }
            }
            let arrValue = currentParam.arrValue;
            if (arrParam == null || arrParam.length < 1) {
                return "";
            }
            let allTemplate = [];
            let templates = this.paramTemplateList;

            for (let i = 0; i < arrValue.length; i++) {
                // 设定数组参数信息
                let fullObj = this.initFullObj(arrParam)
                let item = arrValue[i];
                for(let key in item ){
                    fullObj[key] = item[key];
                }
                // 修改数组参数对应的参数对象
                for(let key in fullObj){
                    let temp = this.paramObj[key];
                    if (temp != null && temp != undefined) {
                        temp.value = fullObj[key]
                    }
                }

                let templateArr = [];
                for (let j = 0; j < arrParam.length; j++) {
                    for (let k = 0; k < templates.length; k++) {
                        if (templates[k].fdParamId == arrParam[j].fdId) {
                            let tmp = this.handleTemplate(templates[k], 1);
                            if (tmp != null && tmp != "") {
                                templateArr.push(tmp);
                            }
                        }
                    }
                }
                allTemplate.push(templateArr);
            }

            if (allTemplate.length < 1) {
                return "";
            }

            let templateStr = [];
            for (let i = 0; i < allTemplate.length; i++) {
                let item = allTemplate[i];
                if (item.length == 1) {
                    if (item.indexOf(": ") > -1) {
                        // 对象参数
                        templateStr.push(`{ ${item[0]} } `);
                    } else {
                        // 非对象类型
                        templateStr.push(item[0]);
                    }
                }

                if (item.length > 1) {
                    // 对象参数
                    templateStr.push(`{ ${item.join(",")} } `);
                }

            }
            return `[ ${templateStr.join(", ")} ]`;
        },
        // 保存数组参数
        saveArrayParam() {
            let datas = this.$refs.tableRef.getData();
            for (let i = 0; i < datas.length; i++) {
                delete datas[i].changeArr;
                delete datas[i].dataIdx;
                delete datas[i].isAdd;
                delete datas[i].isEdit;
            }
            this.currentArrayParam.arrValue = datas
            this.currentArrayParam.value = this.getArrayParamValue(this.currentArrayParam);
            this.renderTemplate();
        }
    }


}
</script>

<style scoped>
.dev-container {
    height: 100%;
    background-color: white;
}

.dev-left-panel {
    width: 270px;
}

.dev-right-panel {
    width: 450px;
}

.dev-right-panel /deep/ .el-form-item {
    margin-bottom: 12px;
}

.dev-left-panel /deep/ .el-tabs__header {
    margin: 0px;
}

.dev-main-panel {
    height: 100%;
    width: 100%;
}

.dev-collapse-title {
    font-weight: bold;
    font-size: 13px;
    padding: 0px 8px;
}

.dev-comp-item {
    padding: 5px 8px;
    background: #f6f7ff;
    font-size: 12px;
    cursor: pointer;
    border: 1px solid #f6f7ff;
    border-radius: 3px;
    width: 44%;
    margin-left: 4%;
    float: left;
}

.dev-comp-item:hover {
    border: 1px solid #787be8;
    color: #787be8;
}

.dev-code {
    color: #c7254e;
    border-radius: 4px;
    padding: 5px;
    white-space: pre;
    width: fit-content;
}
.param-label {
    width: 120px;
    font-weight: bold;
    line-height: 34px;
    font-size: 14px;
}
</style>
