<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>数据库管理</title>
    <link rel="stylesheet" href="{{ asset('CmsProUi/component/pear/css/pear.css') }}">
    <link rel="stylesheet" href="{{ asset('CmsProUi/font-awesome/4.7.0/css/font-awesome.min.css') }}">
    <link rel="stylesheet" href="{{ asset('Admin/css/admin.css') }}">
    <link rel="stylesheet" href="{{ asset('Admin/css/variables.css') }}">
    <link rel="stylesheet" href="{{ asset('Admin/css/reset.css') }}">
    <style>
    .layui-btn+.layui-btn { margin-left: 0; }
    .empty-placeholder { text-align: center; padding: 60px 0; color: #999; }
    .empty-placeholder i { font-size: 60px; color: #dce0e6; display: block; margin-bottom: 10px; }
</style>
    @include('admin.partials.permission-script')
</head>
<body>
<div class="pear-container">
    <div class="layui-row layui-col-space10">
        <div class="layui-col-md7">
            <div class="layui-card">
                <div class="layui-card-body">
                    <fieldset class="layui-elem-field layui-field-title" style="margin:5px 0;">
                        <legend>数据库管理</legend>
                    </fieldset>
                    <table id="tableList" lay-filter="tableList"></table>
                </div>
            </div>
        </div>
        <div class="layui-col-md5">
            <div class="layui-card">
                <div class="layui-card-body">
                    <div id="emptyPlaceholder" class="empty-placeholder">
                        <i class="layui-icon layui-icon-template-1"></i>
                        <p>请选择左侧数据表查看结构</p>
                    </div>
                    <fieldset id="structureTitle" class="layui-elem-field layui-field-title" style="display:none;margin:10px 0 0;">
                        <legend id="structureLegend">表结构</legend>
                    </fieldset>
                    <table id="structureTable" lay-filter="structureTable"></table>
                </div>
            </div>
        </div>
    </div>

    @verbatim
    <script type="text/html" id="table-toolbar">
        <button class="layui-btn layui-btn-sm" lay-event="Add" data-permission="admin.database.add-table">
            <i class="layui-icon layui-icon-add-1"></i> 创建表
        </button>
        <button class="layui-btn layui-btn-sm" lay-event="Backup" data-permission="admin.database.backup" style="position:absolute!important;right:200px;top:10px;">
            <i class="fa fa-cubes"></i> 备份
        </button>
        <button class="layui-btn layui-btn-sm" lay-event="Recover" data-permission="admin.database.recover" style="position:absolute!important;right:100px;top:10px;">
            <i class="fa fa-cube"></i> 恢复
        </button>
    </script>

    <script type="text/html" id="table-row-bar">
        <button class="layui-btn layui-btn-xs" lay-event="details" data-permission="admin.database.structure"><i class="fa fa-table"></i></button>
        <button class="layui-btn layui-btn-xs" lay-event="datalist" data-permission="admin.database.check"><i class="fa fa-database"></i></button>
        <a class="layui-btn layui-btn-xs" lay-event="more">操作 <i class="layui-icon layui-icon-down"></i></a>
    </script>

    <script type="text/html" id="structure-toolbar">
        <button class="layui-btn layui-btn-xs" lay-event="AddField" data-permission="admin.database.add-fields">
            <i class="layui-icon layui-icon-add-1"></i> 添加字段
        </button>
        <button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="DeleteFields" data-permission="admin.database.delete-field">
            <i class="layui-icon layui-icon-delete"></i> 删除
        </button>
        <button class="layui-btn layui-btn-xs" lay-event="ViewTableData" data-permission="admin.database.check">
            <i class="fa fa-database"></i> 查看数据
        </button>
    </script>

    <script type="text/html" id="field-row-bar">
        <a class="layui-btn layui-btn-xs" lay-event="more">操作 <i class="layui-icon layui-icon-down"></i></a>
    </script>
    @endverbatim
</div>
<script src="{{ asset('CmsProUi/component/layui/layui.js') }}"></script>
<script src="{{ asset('CmsProUi/component/pear/pear.js') }}"></script>
<script>
    layui.use(['table', 'element', 'form', 'jquery', 'dropdown'], function() {
        var table = layui.table;
        var form = layui.form;
        var $ = layui.jquery;
        var dropdown = layui.dropdown;

        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': '{{ csrf_token() }}'
            },
            statusCode: {
                401: function() {
                    layer.msg('登录已过期，请重新登录', {icon: 2, time: 1500}, function() {
                        window.location.href = '/admin/login?redirect=' + encodeURIComponent(window.location.pathname + window.location.search);
                    });
                }
            }
        });

        // 根据权限隐藏工具栏按钮
        var hidePermButtons = function() {
            $('button[data-permission]').each(function() {
                if (!window.hasPermission || !window.hasPermission($(this).data('permission'))) {
                    $(this).hide();
                }
            });
        };
        hidePermButtons();

        var API = '/api/admin/database';
        var currentTable = '';

        table.render({
            elem: '#tableList',
            url: API + '/list',
            page: false,
            cols: [[
                { field: 'Name', title: '数据表', sort: true, width: 280 },
                { field: 'Comment', title: '备注' },
                { field: 'Rows', title: '行数', width: 60, align: 'center' },
                { field: 'Index_length', title: '大小', width: 90, align: 'center', templet: function(d) { return formatSize(d.Index_length); } },
                { field: 'Data_free', title: '冗余', width: 90, align: 'center', templet: function(d) { return formatSize(d.Data_free); } },
                { fixed: 'right', title: '操作', toolbar: '#table-row-bar', align: 'center', width: 164 }
            ]],
            height: 'full-148',
            toolbar: '#table-toolbar',
            defaultToolbar: [{ title: '刷新', layEvent: 'Refresh', icon: 'layui-icon-refresh' }, 'filter'],
            parseData: function(res) {
                return { "code": res.code, "msg": res.message, "data": res.data || [] };
            },
            done: function() {
                hidePermButtons();
            }
        });

        table.on('toolbar(tableList)', function(obj) {
            if (obj.event === 'Add') { addTable(); }
            else if (obj.event === 'Refresh') { table.reload('tableList'); }
            else if (obj.event === 'Backup') { allBackup(); }
            else if (obj.event === 'Recover') { allRecover(); }
        });

        table.on('tool(tableList)', function(obj) {
            if (obj.event === 'details') { renderStructure(obj.data.Name); }
            else if (obj.event === 'datalist') { checkData(obj.data.Name); }
            else if (obj.event === 'more') {
                dropdown.render({
                    elem: this,
                    show: true,
                    align: 'right',
                    data: [
                        { title: '编辑', id: 'Edit', permission: 'admin.database.edit-table' },
                        { title: '复制', id: 'Copy', permission: 'admin.database.copy-table' },
                        { title: '查看数据', id: 'Check', permission: 'admin.database.check' },
                        { title: '表结构', id: 'Structure', permission: 'admin.database.structure' },
                        { title: '优化', id: 'Optimize', permission: 'admin.database.optimize' },
                        { title: '修复', id: 'Repair', permission: 'admin.database.repair' },
                        { title: '备份', id: 'Backup', permission: 'admin.database.backup' },
                        { title: '恢复', id: 'Recover', permission: 'admin.database.recover' },
                        { title: '删除', id: 'Delete', permission: 'admin.database.delete-table' }
                    ].filter(function(item) {
                        return !item.permission || !window.hasPermission || window.hasPermission(item.permission);
                    }),
                    click: function(menuData) {
                        switch(menuData.id) {
                            case 'Edit': editTable(obj); break;
                            case 'Copy': copyTable(obj.data.Name); break;
                            case 'Check': checkData(obj.data.Name); break;
                            case 'Structure': renderStructure(obj.data.Name); break;
                            case 'Optimize': optimizeTable(obj); break;
                            case 'Repair': repairTable(obj); break;
                            case 'Backup': backupTable(obj); break;
                            case 'Recover': recoverTable(obj); break;
                            case 'Delete': deleteTable(obj); break;
                        }
                    }
                });
            }
        });

        function renderStructure(tableName) {
            currentTable = tableName;
            $('#emptyPlaceholder').hide();
            $('#structureTitle').show();
            $('#structureLegend').text(tableName + ' - 表结构');
            table.render({
                elem: '#structureTable',
                url: API + '/' + tableName + '/structure',
                page: false,
                cols: [[
                    { type: 'checkbox' },
                    { field: 'Field', title: '字段', width: 100, sort: true, align: 'center' },
                    { field: 'Comment', title: '别名', align: 'center' },
                    { field: 'Type', title: '类型', width: 120, align: 'center' },
                    { field: 'Null', title: '允许空', width: 70, align: 'center' },
                    { field: 'Default', title: '默认值', width: 80, align: 'center' },
                    { title: '操作', toolbar: '#field-row-bar', align: 'center', width: 120 }
                ]],
                height: 'full-148',
                toolbar: '#structure-toolbar',
                defaultToolbar: [{ title: '刷新', layEvent: 'refresh', icon: 'layui-icon-refresh' }, 'filter', 'print', 'exports'],
                parseData: function(res) {
                    return { "code": res.code, "msg": res.message, "data": res.data || [] };
                }
            });
        }

        table.on('toolbar(structureTable)', function(obj) {
            if (obj.event === 'AddField') { addFields(); }
            else if (obj.event === 'refresh') { if (currentTable) renderStructure(currentTable); }
            else if (obj.event === 'ViewTableData') { checkData(currentTable); }
            else if (obj.event === 'DeleteFields') { deleteFields(obj); }
        });

        table.on('tool(structureTable)', function(obj) {
            if (obj.event === 'more') {
                dropdown.render({
                    elem: this,
                    show: true,
                    align: 'right',
                    data: [
                        { title: '编辑', id: 'Edit', permission: 'admin.database.edit-field' },
                        { title: '添加索引', id: 'FieldIndex', permission: 'admin.database.field-index' },
                        { title: '删除', id: 'Delete', permission: 'admin.database.delete-field' }
                    ].filter(function(item) {
                        return !item.permission || !window.hasPermission || window.hasPermission(item.permission);
                    }),
                    click: function(menuData) {
                        if (menuData.id === 'Edit') { editField(obj); }
                        else if (menuData.id === 'FieldIndex') { fieldIndex(obj); }
                        else if (menuData.id === 'Delete') { fieldDelete(obj); }
                    }
                });
            }
        });

        function addTable() {
            layer.open({
                type: 1,
                title: '创建数据表',
                content: '<div style="padding:20px;">' +
                    '<div class="layui-form-item"><label class="layui-form-label" style="text-align:left;">表名：</label><div class="layui-input-block"><input type="text" id="newTable" name="Table" placeholder="请输入表名" class="layui-input"></div></div>' +
                    '<div class="layui-form-item"><label class="layui-form-label" style="text-align:left;">备注：</label><div class="layui-input-block"><input type="text" id="newName" name="Name" placeholder="请输入备注" class="layui-input"></div></div>' +
                    '</div>',
                btn: ['确定', '取消'],
                yes: function(index, layero) {
                    var t = layero.find('#newTable').val();
                    var n = layero.find('#newName').val();
                    if (!t || !n) { layer.msg('表名和备注不能为空', {icon:2}); return; }
                    $.post(API + '/add-table', { table: t, name: n, _token: '{{ csrf_token() }}' }, function(res) {
                        if (res.code === 0) { layer.close(index); layer.msg(res.message, {icon:1}); table.reload('tableList'); }
                        else { layer.msg(res.message, {icon:2}); }
                    });
                }
            });
        }

        function editTable(obj) {
            if (obj.data.is_system) { layer.msg('系统表禁止编辑', {icon:2}); return; }
            layer.open({
                type: 1,
                title: '编辑数据表',
                content: '<div style="padding:20px;">' +
                    '<input type="hidden" id="oldTable" value="' + obj.data.Name + '">' +
                    '<div class="layui-form-item"><label class="layui-form-label" style="text-align:left;">表名：</label><div class="layui-input-block"><input type="text" id="editTable" value="' + obj.data.Name + '" class="layui-input"></div></div>' +
                    '<div class="layui-form-item"><label class="layui-form-label" style="text-align:left;">备注：</label><div class="layui-input-block"><input type="text" id="editName" value="' + obj.data.Comment + '" class="layui-input"></div></div>' +
                    '</div>',
                btn: ['确定', '取消'],
                yes: function(index, layero) {
                    var ot = layero.find('#oldTable').val();
                    var t = layero.find('#editTable').val();
                    var n = layero.find('#editName').val();
                    if (!t || !n) { layer.msg('表名和备注不能为空', {icon:2}); return; }
                    $.post(API + '/edit-table', { old_table: ot, table: t, name: n, _token: '{{ csrf_token() }}' }, function(res) {
                        if (res.code === 0) { layer.close(index); layer.msg(res.message, {icon:1}); table.reload('tableList'); }
                        else { layer.msg(res.message, {icon:2}); }
                    });
                }
            });
        }

        function copyTable(name) {
            layer.open({
                type: 1,
                title: '复制数据表 - ' + name,
                content: '<div style="padding:20px;">' +
                    '<div class="layui-form-item"><label class="layui-form-label" style="text-align:left;">源表：</label><div class="layui-input-block"><input type="text" id="srcTable" value="' + name + '" readonly class="layui-input layui-disabled"></div></div>' +
                    '<div class="layui-form-item"><label class="layui-form-label" style="text-align:left;">新表名：</label><div class="layui-input-block"><input type="text" id="newTableName" placeholder="请输入新表名" class="layui-input"></div></div>' +
                    '</div>',
                btn: ['确定', '取消'],
                yes: function(index, layero) {
                    var s = layero.find('#srcTable').val();
                    var n = layero.find('#newTableName').val();
                    if (!n) { layer.msg('新表名不能为空', {icon:2}); return; }
                    $.post(API + '/copy-table', { source_table: s, new_table: n, _token: '{{ csrf_token() }}' }, function(res) {
                        if (res.code === 0) { layer.close(index); layer.msg(res.message, {icon:1}); table.reload('tableList'); }
                        else { layer.msg(res.message, {icon:2}); }
                    });
                }
            });
        }

        function deleteTable(obj) {
            if (obj.data.is_system) { layer.msg('系统表禁止删除', {icon:2}); return; }
            layer.confirm('确定要删除数据表 <b>' + obj.data.Name + '</b> 吗？此操作不可恢复！', {
                icon: 3, title: '操作提示', btn: ['确定', '取消']
            }, function() {
                $.post(API + '/delete-table', { table: obj.data.Name, _token: '{{ csrf_token() }}' }, function(res) {
                    if (res.code === 0) { layer.msg(res.message, {icon:1}); table.reload('tableList'); }
                    else { layer.msg(res.message, {icon:2}); }
                });
            });
        }

        function optimizeTable(obj) {
            $.post(API + '/optimize', { table: obj.data.Name, _token: '{{ csrf_token() }}' }, function(res) {
                if (res.code === 0) { layer.msg(res.message, {icon:1}); setTimeout(function(){table.reload('tableList');},1000); }
                else { layer.msg(res.message, {icon:2}); }
            });
        }

        function repairTable(obj) {
            $.post(API + '/repair', { table: obj.data.Name, _token: '{{ csrf_token() }}' }, function(res) {
                if (res.code === 0) { layer.msg(res.message, {icon:1}); setTimeout(function(){table.reload('tableList');},1000); }
                else { layer.msg(res.message, {icon:2}); }
            });
        }

        function backupTable(obj) {
            showBackupDialog('备份「' + obj.data.Name + '」', function(volumeSize) {
                var loadIdx = layer.load();
                $.ajax({
                    url: API + '/backup',
                    type: 'POST',
                    data: { table: obj.data.Name, volume_size: volumeSize },
                    dataType: 'json',
                    success: function(res) {
                        layer.close(loadIdx);
                        if (res.code === 0) { layer.msg(res.message, {icon:1}); }
                        else { layer.msg(res.message, {icon:2}); }
                    },
                    error: function() {
                        layer.close(loadIdx);
                        layer.msg('备份失败', {icon:2});
                    }
                });
            });
        }

        function recoverTable(obj) {
            layer.open({
                type: 2, maxmin: true,
                title: '恢复 - ' + obj.data.Name,
                shade: 0.1, area: ['80%', '80%'],
                content: '/admin/database/recover/' + obj.data.Name
            });
        }

        function checkData(tableName) {
            layer.open({
                type: 2, maxmin: true,
                title: '查看数据 - ' + tableName,
                shade: 0.1, area: ['98%', '98%'],
                content: '/admin/database/check/' + tableName
            });
        }

        function allBackup() {
            showBackupDialog('全量备份', function(volumeSize) {
                var loadIdx = layer.load();
                $.ajax({
                    url: API + '/backup',
                    type: 'POST',
                    data: { volume_size: volumeSize },
                    dataType: 'json',
                    success: function(res) {
                        layer.close(loadIdx);
                        if (res.code === 0) { layer.msg(res.message, {icon:1}); setTimeout(function(){table.reload('tableList');},1000); }
                        else { layer.msg(res.message, {icon:2}); }
                    },
                    error: function() {
                        layer.close(loadIdx);
                        layer.msg('备份失败', {icon:2});
                    }
                });
            });
        }

        function showBackupDialog(title, callback) {
            layer.open({
                type: 1,
                title: title,
                area: ['460px', 'auto'],
                content: '<div style="padding:20px;">'
                    + '<div style="margin-bottom:16px;font-size:13px;color:#666;">请设置分卷大小后开始备份</div>'
                    + '<div class="layui-form-item" style="margin-bottom:16px;">'
                    + '<label style="font-size:13px;color:#333;display:block;margin-bottom:6px;">分卷大小（MB）</label>'
                    + '<input type="number" id="dlgVolumeSize" class="layui-input" value="2" min="1" max="100" style="width:120px;">'
                    + '<div style="font-size:12px;color:#999;margin-top:6px;line-height:1.6;">'
                    + '分卷越小单次操作越稳定；分卷越大效率越高。建议值：虚拟主机 1-5MB，云服务器 10-50MB。'
                    + '</div></div>'
                    + '<div style="text-align:right;padding-top:10px;border-top:1px solid #f0f0f0;">'
                    + '<button type="button" class="layui-btn layui-btn-primary" id="dlgBtnCancel">取消</button> '
                    + '<button type="button" class="layui-btn" id="dlgBtnConfirm"><i class="fa fa-database"></i> 开始备份</button>'
                    + '</div></div>',
                success: function(layero) {
                    layero.find('#dlgBtnCancel').on('click', function() { layer.closeAll(); });
                    layero.find('#dlgBtnConfirm').on('click', function() {
                        var vs = parseInt(layero.find('#dlgVolumeSize').val()) || 2;
                        if (vs < 1) vs = 1;
                        if (vs > 100) vs = 100;
                        layer.closeAll();
                        if (callback) callback(vs);
                    });
                }
            });
        }

        function allRecover() {
            layer.open({
                type: 2, maxmin: true,
                title: '恢复 - 全部数据表',
                shade: 0.1, area: ['80%', '80%'],
                content: '/admin/database/recover/All'
            });
        }

        function addFields() {
            if (!currentTable) { layer.msg('请先选择数据表', {icon:2}); return; }
            layer.open({
                type: 2, maxmin: true,
                title: '添加字段 - ' + currentTable,
                shade: 0.1, area: ['90%', '90%'],
                content: '/admin/database/add-fields/' + currentTable,
                end: function() { if (currentTable) renderStructure(currentTable); }
            });
        }

        function editField(obj) {
            if (!currentTable) return;
            var typeStr = obj.data.Type || '';
            var type = typeStr, length = '';
            var match = typeStr.match(/(\w+)\((\d+)\)/);
            if (match) { type = match[1]; length = match[2]; }
            var defaultType = 'NONE', defaultVal = '';
            if (obj.data.Null === 'NO' && obj.data.Default !== null) { defaultType = 'USER_DEFINED'; defaultVal = obj.data.Default || ''; }
            else if (obj.data.Null === 'YES') { defaultType = 'NULL'; }

            layer.open({
                type: 2, maxmin: true,
                title: '编辑字段 - ' + currentTable + ' - ' + obj.data.Field,
                shade: 0.1, area: ['90%', '90%'],
                content: '/admin/database/edit-field/' + currentTable,
                success: function(layero, index) {
                    var iframe = layero.find('iframe').contents();
                    iframe.find('#Name').val(obj.data.Field);
                    iframe.find('#OldName').val(obj.data.Field);
                    iframe.find('#Type').val(type);
                    iframe.find('#Type').siblings('div.layui-form-select').find('dd[lay-value=' + type + ']').click();
                    iframe.find('#Length').val(length);
                    iframe.find('#Default').val(defaultType);
                    iframe.find('#Default').siblings('div.layui-form-select').find('dd[lay-value=' + defaultType + ']').click();
                    iframe.find('#Remark').val(obj.data.Comment || '');
                    iframe.find('#DefaultVal').val(defaultVal);
                },
                end: function() { if (currentTable) renderStructure(currentTable); }
            });
        }

        function fieldIndex(obj) {
            if (!currentTable) return;
            $.post(API + '/' + currentTable + '/field-index', { field: obj.data.Field, _token: '{{ csrf_token() }}' }, function(res) {
                if (res.code === 0) { layer.msg(res.message, {icon:1}); if (currentTable) renderStructure(currentTable); }
                else { layer.msg(res.message, {icon:2}); }
            });
        }

        function fieldDelete(obj) {
            if (!currentTable) return;
            layer.confirm('确定要删除字段 <b>' + obj.data.Field + '</b> 吗？', {
                icon: 3, title: '操作提示', btn: ['确定', '取消']
            }, function(index) {
                layer.close(index);
                $.post(API + '/' + currentTable + '/delete-field', { field: obj.data.Field, _token: '{{ csrf_token() }}' }, function(res) {
                    if (res.code === 0) { layer.msg(res.message, {icon:1}); obj.del(); }
                    else { layer.msg(res.message, {icon:2}); }
                });
            });
        }

        function deleteFields(obj) {
            if (!currentTable) return;
            var checkData = table.checkStatus('structureTable').data;
            if (checkData.length === 0) { layer.msg('请选择要删除的字段', {icon:3}); return; }
            var hasId = checkData.some(function(d) { return d.Field.toLowerCase() === 'id'; });
            if (hasId) { layer.msg('ID字段禁止删除', {icon:3}); return; }
            var fields = checkData.map(function(d) { return d.Field; });
            layer.confirm('确定要删除选中的 <b>' + fields.length + '</b> 个字段吗？', {
                icon: 3, title: '操作提示', btn: ['确定', '取消']
            }, function(index) {
                layer.close(index);
                $.ajax({
                    url: API + '/' + currentTable + '/delete-fields',
                    type: 'POST',
                    data: JSON.stringify({ fields: fields, _token: '{{ csrf_token() }}' }),
                    contentType: 'application/json',
                    headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
                    success: function(res) {
                        if (res.code === 0) { layer.msg(res.message, {icon:1}); if (currentTable) renderStructure(currentTable); }
                        else { layer.msg(res.message, {icon:2}); }
                    }
                });
            });
        }

        function formatSize(bytes) {
            if (!bytes || bytes === 0) return '0 B';
            var kb = bytes / 1024, mb = kb / 1024, gb = mb / 1024;
            if (gb >= 1) return gb.toFixed(2) + ' GB';
            if (mb >= 1) return mb.toFixed(2) + ' MB';
            if (kb >= 1) return kb.toFixed(2) + ' KB';
            return bytes + ' B';
        }
    });
</script>
</body>
</html>
