<template>
    <ap-container>
        <ap-aside margin="1111" style="width: 450px">
            <div class="layout-aside-header ">
                <div class="layout-aside-header-title">{{ headerName }}</div>
                <div class="layout-aside-header-icon">
                    <i class="el-icon-plus" @click="addTable"/>
                    <i class="el-icon-edit-outline" @click="editTable"/>
                    <i class="el-icon-delete" @click="deleteTable"/>
                </div>
            </div>
            <div>
                <el-input v-model="filterText" placeholder="关键字过滤"/>
            </div>
            <div v-loading="loadingTreeFlag" class="layout-aside-content">

                <el-tree
                    ref="typeTree"
                    class="filter-tree"
                    node-key="tableName"
                    :data="typeTreeList"
                    :props="defaultProps"
                    default-expand-all
                    :highlight-current="true"
                    :expand-on-click-node="false"
                    :filter-node-method="filterNode"
                    :indent="10"
                    @node-click="nodeClickEvent">
                    <div slot-scope="{ node, data }" style="width: 100%">
                        <div class="dev-tree-node-left ap-ellipse">
                            {{ data.tableName }}
                        </div>
                        <div style="font-size: 12px;">{{ data.tableComment }}</div>
                    </div>
                </el-tree>
            </div>
        </ap-aside>
        <ap-split-panel/>
        <ap-main margin="1110">
            <ap-table ref="devDbTableGrid" :options.sync="tableOpt"/>
        </ap-main>

        <!--表添加-->
        <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="400px">
            <el-form ref="dialogForm" :model="dialogForm" :rules="dialogFormRules" label-width="100px">
                <el-form-item label="数据库">
                    <el-input v-model="tableSchema" :readonly="true" :disabled="true"/>
                </el-form-item>
                <el-form-item label="表名" prop="tableName">
                    <el-input v-model="dialogForm.tableName"/>
                </el-form-item>
                <el-form-item label="表注释" prop="tableComment">
                    <el-input v-model="dialogForm.tableComment"/>
                </el-form-item>
            </el-form>

            <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="saveTable">确 定</el-button>
            </span>
        </el-dialog>

        <!--选择字段-->
        <el-dialog title="选择字段" :visible.sync="fieldDialogVisible" width="60%">
            <dev-db-table-dialog @dataChange="dataChangeEvent" style="height: 400px"/>

            <span slot="footer" class="dialog-footer">
                <el-button @click="fieldDialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="selectField">确 定</el-button>
           </span>
        </el-dialog>
    </ap-container>
</template>

<script>
import DevDbTableDialog from './DevDbTableDialog'
import {convertToTreeData} from 'ap-util/util/DataUtil'
import {getUserConfig} from './../dev/DevUtil'

export default {
    name: 'DevDbTable',
    components: {DevDbTableDialog},
    data() {
        const columns = [
            {
                prop: 'columnName',
                label: '字段名',
                type: 'input',
                minWidth: '150',
                edit: false,
                resizable: false
            }, {
                prop: 'dataType',
                label: '类型',
                type: 'select',
                width: '150',
                selectOptions: [
                    {
                        label: '常用',
                        options: [
                            {label: 'char', value: 'char'},
                            {label: 'varchar', value: 'varchar'},
                            {label: 'tinyint', value: 'tinyint'},
                            {label: 'datetime', value: 'datetime'}
                        ]
                    },
                    {
                        label: '字符串',
                        options: [
                            {label: 'char', value: 'char'},
                            {label: 'varchar', value: 'varchar'},
                            {label: 'text', value: 'text'},
                            {label: 'mediumtext', value: 'mediumtext'},
                            {label: 'longtext', value: 'longtext'},

                        ]
                    },
                    {
                        label: '整型数值',
                        options: [
                            {label: 'tinyint', value: 'tinyint'},
                            {label: 'smallint', value: 'smallint'},
                            {label: 'mediumint', value: 'mediumint'},
                            {label: 'int', value: 'int'},
                            {label: 'bigint', value: 'bigint'}
                        ]
                    },
                    {
                        label: '浮点数值',
                        options: [
                            {label: 'float', value: 'float'},
                            {label: 'double', value: 'double'},
                            {label: 'decimal', value: 'decimal'}
                        ]
                    },
                    {
                        label: '日期时间',
                        options: [
                            {label: 'date', value: 'date'},
                            {label: 'time', value: 'time'},
                            {label: 'year', value: 'year'},
                            {label: 'datetime', value: 'datetime'},
                            {label: 'timestamp', value: 'timestamp'}
                        ]
                    },
                    {
                        label: '二进制:图片/文件',
                        options: [
                            {label: 'blob', value: 'blob'},
                            {label: 'mediumblob', value: 'mediumblob'},
                            {label: 'longblob', value: 'longblob'},
                        ]
                    }
                ],
                selectFilterable: true,
                selectIsGroup: true,
                selectPlaceholder: '选择数据类型',
                rules: [
                    {required: true, message: '数据类型必选'}
                ]
            }, {
                prop: 'length',
                label: '长度/精度',
                type: 'inputNumber',
                width: '80',
                edit: (rowData) => {
                    // 不允许编辑长度的类型
                    const arr = ['tinyint', 'smallint', 'mediumint', 'int', 'bigint', 'date', 'time', 'year', 'datetime', 'timestamp',
                        'text', 'mediumtext', 'longtext', 'blob', 'mediumblob', 'longblob']

                    return arr.indexOf(rowData.dataType) < 0
                }
            }, {
                prop: 'numericScale',
                label: '小数点',
                type: 'inputNumber',
                width: '60',
                edit: (rowData) => {
                    // 浮点数
                    const arr = ['float', 'double', 'decimal']
                    if (arr.indexOf(rowData.dataType) >= 0) {
                        return true
                    } else {
                        return false
                    }
                }
            }, {
                prop: 'isNullable',
                label: '非空',
                type: 'select',
                width: '60',
                selectOptions: [{label: '否', value: 'YES'}, {label: '是', value: 'NO'}],
                align: 'center',
                html: function (value, row) {
                    return value == 'NO' ? "<div class='ap-tag-success'>是</div>" : '否'
                }
            }, {
                prop: 'keyName',
                label: '索引',
                type: 'input',
                minWidth: '120',
                edit: false,
                resizable: false,
                html: function (value, row) {
                    if (value == null || value == '') {
                        return ''
                    }
                    const names = value.split(',')
                    let res = ''
                    for (let i = 0; i < names.length; i++) {
                        if (names[i] == 'PRIMARY') {
                            res += "<span style='color: #409eff;padding: 2px;'>主键</span>"
                        } else if (names[i].startsWith('idx_pk_single') || names[i].startsWith('idx_pk_multi')) {
                            res += "<span style='color: #67c23a;padding: 2px;'>" + names[i] + '</span>'
                        } else {
                            res += "<span style='color: #909399;padding: 2px;'>" + names[i] + '</span>'
                        }
                    }
                    return res
                }
            }, {
                prop: 'nonUnique',
                label: '唯一',
                type: 'input',
                width: '60',
                edit: false,
                add: false,
                html: function (value, row) {
                    const a = value === 0 ? "<div class='ap-tag-success'>是</div>" : ''
                    return a
                }
            }, {
                prop: 'columnDefault',
                label: '默认值',
                type: 'input',
                minWidth: '80'
            }, {
                prop: 'columnComment',
                label: '注释',
                type: 'input',
                minWidth: '200',
                rules: [
                    {required: true, message: '请输入字注释'},
                    {min: 1, max: 100, message: '长度在 1 到 100 个字符'}
                ]
            }]
        const toolBar = [
            {
                btnType: 'primary',
                text: '添加',
                icon: 'el-icon-plus',
                onClick: () => {
                    this.fieldDialogVisible = true
                }
            },
            'edit', 'del', 'refresh', 'save', 'separator',
            {
                btnType: 'primary',
                text: '上移',
                icon: 'el-icon-top',
                onClick: () => {
                    this.colSortBefore()
                }
            }, {
                btnType: 'primary',
                text: '下移',
                icon: 'el-icon-bottom',
                onClick: () => {
                    this.colSortAfter()
                }
            },
            'separator',
            {
                btnType: 'primary',
                text: '主键',
                icon: 'el-icon-key',
                onClick: () => {
                    this.setIndex('primary')
                }
            }, {
                btnType: 'primary',
                text: '普通索引',
                icon: 'el-icon-collection-tag',
                onClick: () => {
                    this.setIndex('index')
                }
            }, {
                btnType: 'primary',
                text: '唯一索引',
                icon: 'el-icon-collection-tag',
                onClick: () => {
                    this.setIndex('unique')
                }
            }, {
                btnType: 'danger',
                text: '删除索引',
                icon: 'el-icon-collection-tag',
                onClick: () => {
                    this.dropIndex()
                }
            }, {
                btnType: 'info',
                text: '帮助',
                icon: 'el-icon-question',
                onClick: () => {
                    this.openHelp()
                }
            }]
        const tableOpt = {
            title: '表结构设计',
            columns: columns,
            pagination: {pageSizes: [100, 200, 300], pageSize: 100},
            dataUrl: '/apd/db/DevDbTable/getDevDbTableGridList',
            saveUrl: '/apd/db/DevDbTable/modifyColumn',
            editPk: 'columnName,dataType,length,numericScale,columnComment,columnDefault,tableName,tableSchema',
            deletePk: 'tableSchema,tableName,columnName',
            deleteUrl: '/apd/db/DevDbTable/dropColumns',
            toolbarBtn: toolBar,
            initData: false,
            rowKey: 'columnName',
            params: () => {
                return this.selectedTable
            }
        }
        return {
            // ----- 左侧树 -----
            headerName: '表',
            loadingTreeFlag: false,
            filterText: '',
            typeTreeList: [],
            defaultProps: {
                children: 'children',
                label: 'tableName'
            },
            selectedTable: {
                tableName: '',
                sourceId: getUserConfig().fdSourceId
            },
            tableSchema: '',
            // ----- dialog -----
            dialogVisible: false,
            dialogTitle: '', // dialog标题
            isAddDialog: true, // 添加类型dialog
            dialogForm: {
                tableName: '',
                tableComment: ''
            },
            oldTableName: '',
            dialogFormRules: {
                tableName: [
                    {required: true, message: '必填'},
                    {min: 1, max: 30, message: '长度在 1 到 30 个字符'}
                ],
                tableComment: [
                    {required: true, message: '必填'},
                    {min: 1, max: 30, message: '长度在 1 到 100 个字符'}
                ]
            },
            // ----- 表格 -----
            tableOpt: tableOpt,
            // ----- 添加列dialog -----
            fieldDialogVisible: false,
            selectedFields: [],

            userConfig: getUserConfig()
        }
    },
    watch: {
        filterText(val) {
            this.$refs.typeTree.filter(val)
        },
    },
    created() {
        this.getSchema();
        this.loadTreeData();
    },
    methods: {
        getSchema() {
            this.$request({
                url: '/apd/db/DevDbTable/getSchema',
                method: 'post',
                data: {
                    sourceId: this.userConfig.fdSourceId
                }
            }).then(response => {
                this.tableSchema = response.data;
                this.headerName = "[" + response.data + "] - 表";
            })
        },
        // 左侧树：加载数据
        loadTreeData() {
            this.loadingTreeFlag = true
            this.$request({
                url: '/apd/db/DevDbTable/getTableList',
                method: 'post',
                data: {
                    sourceId: this.userConfig.fdSourceId
                }
            }).then(response => {
                this.typeTreeList = convertToTreeData(response.data, {
                    idKey: "tableName",
                    parentKey: "fdParentId",
                    childrenKey: "children",
                });
            }).finally(() => {
                this.loadingTreeFlag = false
            })
        },
        // 左侧树：初始化数据
        initTreeData() {
            // 重置当前选择节点
            this.$refs.typeTree.setCurrentKey()
            this.loadTreeData()
        },
        // 左侧树：过滤节点
        filterNode(value, data) {
            if (!value) return true
            if (data.tableName.indexOf(value) !== -1) {
                return true
            }
            if (data.tableComment != null && data.tableComment.indexOf(value) !== -1) {
                return true
            }
            return false
        },
        // 选择事件
        nodeClickEvent(data, node, comp) {
            // dialog参数设定
            this.dialogForm = {
                tableName: data.tableName,
                tableComment: data.tableComment,
            }

            // 分类直接返回
            if (data.fdType == 0) {
                return
            }
            const tableName = data.tableSchema + '.' + data.tableName
            this.tableOpt.title = '表结构设计(' + tableName + ')'
            // 点击表，刷新左侧表格
            this.selectedTable.tableSchema = data.tableSchema
            this.selectedTable.tableName = data.tableName
            this.$refs.devDbTableGrid.refresh()
        },
        // 左侧树：转换成tree要求的数据格式
        handelTreeData(data) {
            const newList = []
            for (let i = 0; i < data.length; i++) {
                const fdParentId = data[i].fdParentId
                // 根节点
                if (!fdParentId) {
                    newList.push(data[i])
                } else {
                    // 子节点
                    for (let j = 0; j < data.length; j++) {
                        // 查找父节点
                        if (data[j].fdId == fdParentId) {
                            if (!data[j].children) {
                                data[j].children = []
                            }
                            data[j].children.push(data[i])
                        }
                    }
                }
            }
            return newList
        },
        // dialog：重置表单
        resetDialogForm() {
            this.dialogForm = {
                tableName: '',
                tableComment: ''
            }
        },
        getCurrentNode() {
            return this.$refs.typeTree.getCurrentNode() || {}
        },
        // dialog：添加数据
        addTable() {
            this.resetDialogForm()
            this.dialogVisible = true
            this.dialogTitle = '添加表'
            this.isAddDialog = true
        },
        // dialog：编辑数据
        editTable() {
            let tableName = this.getCurrentNode().tableName
            if (!tableName) {
                this.$message.error('请选择需要编辑的数据！')
                return
            }
            this.dialogForm.tableName = tableName;
            this.dialogForm.tableComment = this.getCurrentNode().tableComment;
            this.dialogVisible = true
            this.dialogTitle = '编辑表'
            this.isAddDialog = false
            this.oldTableName = tableName;
        },
        // 左侧树：删除数据
        deleteTable() {
            let tableName = this.getCurrentNode().tableName
            if (!tableName) {
                this.$message.error('请选择需要删除的数据！')
                return
            }

            this.$confirm(`确定要删除【${this.tableSchema}.${tableName}】?`, '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                this.$request({
                    url: '/apd/db/DevDbTable/deleteTable',
                    method: 'post',
                    data: {
                        tableName: tableName,
                        tableSchema: this.tableSchema,
                        sourceId: this.userConfig.fdSourceId
                    }
                }).then(response => {
                    this.$message.success(`删除成功！`)
                    this.initTreeData()
                })
            })
        },
        checkTypeSort() {
            const currentNode = this.getCurrentNode()
            if (currentNode == null) {
                this.$message.error(`请选择需要操作的节点！`)
                return null
            }
            return currentNode
        },
        // dialog：保存类型数据
        saveTable() {
            // 校验
            this.$refs.dialogForm.validate(valid => {
                if (!valid) {
                    this.$message.error(`数据校验失败，请重新填写信息！`)
                    return false
                }

                let param = this.dialogForm;
                param.sourceId = this.userConfig.fdSourceId;
                param.tableSchema = this.tableSchema;
                param.oldTableName = this.oldTableName;
                if (this.isAddDialog) {
                    // 添加数据
                    this.$request({
                        url: '/apd/db/DevDbTable/insertTable',
                        method: 'post',
                        data: param
                    }).then(response => {
                        this.$message.success(`添加成功！`)
                        this.dialogVisible = false
                        this.initTreeData()
                    })
                } else {
                    // 更新数据
                    this.$request({
                        url: '/apd/db/DevDbTable/updateTable',
                        method: 'post',
                        params: param
                    }).then(response => {
                        this.$message.success(`更新成功！`)
                        this.dialogVisible = false
                        this.initTreeData()
                    })
                }
            })
        },
        // 添加行：数据类型默认值
        addDefaultValueFn() {
            return this.getCurrentNode().fdId
        },
        // 添加列dialog：选择修改
        dataChangeEvent(fields) {
            this.selectedFields = fields
        },
        // 添加列dialog：确认选择
        selectField() {
            const fields = this.selectedFields
            console.log(fields)
            this.fieldDialogVisible = false

            if (fields == null) {
                return
            }
            const list = []
            for (let i = 0; i < fields.length; i++) {
                list.push({
                    columnName: fields[i].fdName,
                    columnComment: fields[i].fdComment,
                    dataType: fields[i].fdDataType
                })
            }

            // 添加列
            this.$request({
                url: '/apd/db/DevDbTable/addColumns',
                method: 'post',
                data: {
                    tableSchema: this.selectedTable.tableSchema,
                    tableName: this.selectedTable.tableName,
                    columns: JSON.stringify(list),
                    sourceId: this.userConfig.fdSourceId
                }
            }).then(response => {
                this.$message.success(`添加成功！已添加${response.data}条数据！`)
                this.$refs.devDbTableGrid.refresh()
            })
        },
        // 修改列顺序
        doColSortChange(col, afterColumnName) {
            col.afterColumnName = afterColumnName
            let param = col;
            param.sourceId = this.userConfig.fdSourceId;
            // 添加数据
            this.$request({
                url: '/apd/db/DevDbTable/modifyColumnSort',
                method: 'post',
                data: param
            }).then(response => {
                this.$message.success(`修改成功！`)
                this.$refs.devDbTableGrid.refresh()
            })
        },
        checkColSort() {
            const selection = this.$refs.devDbTableGrid.getSelection()
            if (selection.length == 0) {
                this.$message.error(`请选择需要操作的行！`)
                return null
            } else if (selection.length > 1) {
                this.$message.error(`只能选择一行！`)
                return null
            }
            return selection[0]
        },
        // 列顺序调整：向上
        colSortBefore() {
            const rowData = this.checkColSort()
            if (rowData == null) {
                return
            }
            const dataIdx = rowData.dataIdx
            if (dataIdx == 1) {
                this.$message.success(`字段已经是第一个啦！`)
                return
            }

            let afterColumnName = ''
            if (dataIdx == 2) {
                // 调整到第一个
                afterColumnName = ''
            } else {
                afterColumnName = this.tableOpt.data[dataIdx - 3].columnName
            }

            this.doColSortChange(rowData, afterColumnName)
        },
        // 列顺序调整：向下
        colSortAfter() {
            const rowData = this.checkColSort()
            if (rowData == null) {
                return
            }
            const dataIdx = rowData.dataIdx
            if (dataIdx >= this.tableOpt.data.length) {
                this.$message.success(`字段已经是最后一个啦！`)
                return
            }
            const afterColumnName = this.tableOpt.data[dataIdx].columnName
            this.doColSortChange(rowData, afterColumnName)
        },
        setIndex(type) {
            const selection = this.$refs.devDbTableGrid.getSelectionKeys()
            if (selection.length == 0) {
                this.$message.error(`请选择需要操作的行！`)
                return
            }
            this.$request({
                url: '/apd/db/DevDbTable/setIndex',
                method: 'post',
                data: {
                    tableSchema: this.selectedTable.tableSchema,
                    tableName: this.selectedTable.tableName,
                    columnName: selection.join(),
                    type: type,
                    sourceId: this.userConfig.fdSourceId
                }
            }).then(response => {
                this.$message.success(`修改成功！`)
                this.$refs.devDbTableGrid.refresh()
            })
        },
        dropIndex() {
            const selection = this.$refs.devDbTableGrid.getSelection()
            if (selection.length == 0) {
                this.$message.error(`请选择需要操作的行！`)
                return
            } else if (selection.length > 1) {
                this.$message.error(`只能选择一行！`)
                return
            }
            const arr = []
            for (let i = 0; i < selection.length; i++) {
                arr.push(selection[i].keyName)
            }
            const indexNames = arr.join()
            if (indexNames.length < 1) {
                this.$message.error(`当前字段无索引！`)
                return
            }
            this.$request({
                url: '/apd/db/DevDbTable/dropIndex',
                method: 'post',
                data: {
                    tableSchema: this.selectedTable.tableSchema,
                    tableName: this.selectedTable.tableName,
                    indexNames: indexNames,
                    sourceId: this.userConfig.fdSourceId
                }
            }).then(response => {
                this.$message.success(`修改成功！`)
                this.$refs.devDbTableGrid.refresh()
            })
        },
        openHelp() {
            const msg = `
                <b>一、主键索引：</b><br>
                1、索引的值必须唯一，且不为NULL。<br>
                2、一个表只能有一个主键索引，可以选择多个字段组成联合主键索引。<br>
                <b>二、普通索引：</b><br>
                1、单字段：索引的值可出现多次。("idx_single"开头)<br>
                2、多字段：选择多个字段组成联合索引。("idx_multi"开头)<br>
                <b>三、唯一索引：</b><br>
                1、单字段：索引的值必须唯一，NULL可以出现多次。("idx_pk_single"开头)<br>
                2、多字段：选择多个字段组成联合唯一索引。("idx_pk_multi"开头)<br>
                `
            this.$alert(msg, '索引说明', {dangerouslyUseHTMLString: true})
        }
    }
}
</script>

<style scoped>
.dev-tree-node-left {
    font-size: 15px;
    width: 60%;
    float: left;
}
</style>
