<!-- Redis 控制台 -->
<template>
    <el-scrollbar class="vue-box">
        <!-- ------------- 总览 ------------- -->
        <div class="c-card">
            <div class="c-title">
                Redis 控制台
                <span class="f5-pre-btn" @click="f5_pre(false)">刷新</span>
            </div>
            <div style="height: 10px;" />
            <div>
                <div class="card-box" @click="sa.msg('表点我 >_<')">
                    <p class="prop-name">键值总数</p>
                    <p class="prop-value">{{ state.preData.keys_count }}</p>
                </div>
                <div class="card-box" @click="sa.msg('表点我 >_<')">
                    <p class="prop-name">命中次数</p>
                    <p class="prop-value">{{ state.preData.keyspace_hits }}</p>
                </div>
                <div class="card-box" @click="sa.msg('表点我 >_<')">
                    <p class="prop-name">已用内存</p>
                    <p class="prop-value">{{ state.preData.used_memory_human }}</p>
                </div>
                <div class="card-box" @click="sa.msg('表点我 >_<')">
                    <p class="prop-name">内存峰值</p>
                    <p class="prop-value">{{ state.preData.used_memory_peak_human }}</p>
                </div>
                <div class="card-box" @click="sa.msg('表点我 >_<')">
                    <p class="prop-name">启动时间</p>
                    <p class="prop-value">{{ state.preData.uptime_in_seconds_str }}</p>
                </div>
            </div>
        </div>
        <!-- ------------- 检索参数 ------------- -->
        <div class="c-card c-table">
            <div class="c-title">搜索键值</div>
            <el-form :inline="true" class="select-form" @submit.native.prevent @keyup.enter="state.p.pageNo = 1; f5();">
                <in-item>
                    <el-input
                        v-model="state.p.k" class="k-input" :placeholder="state.isLike ? '当前为模糊搜索' : '当前为精确搜索'"
                        style="width: 400px; margin-right: 10px;" @keyup.native.enter="f5()" />
                    <el-button class="btn-13" type="primary" icon="el-icon-Search" @click="f5()">查询</el-button>
                    <el-button class="btn-13" type="success" plain icon="el-icon-Plus" @click="add()">添加</el-button>
                    <el-button class="btn-13" type="danger" plain icon="el-icon-Delete" @click="deleteByKeys()">批量删除</el-button>
                    <el-button class="btn-13" type="info" plain icon="el-icon-Sort" @click="state.isLike = !state.isLike; sa.ok('切换成功')">
                        {{ state.isLike ? '切换为精确搜索' : '切换为模糊搜索' }}
                    </el-button>
                </in-item>
            </el-form>
            <div style="height: 10px;" />
            <el-table ref="data-table" class="data-table" :data="state.dataListShow">
                <!-- <el-table-column label="键"></el-table-column> -->
                <el-table-column type="selection" width="45px" />
                <el-table-column label="键">
                    <template #default="s">
                        <div class="key-div" @click="sa.copyText(s.row.key); sa.msg('复制成功')">{{ s.row.key }}</div>
                    </template>
                </el-table-column>
                <el-table-column label="值">
                    <template #default="s">
                        <div v-if="s.row.is_show === false" class="not-show" @click="get(s.row)">点击加载</div>
                        <div v-if="s.row.is_show === true" class="is-show" @click="sa.copyText(s.row.value); sa.msg('复制成功')">{{ s.row.value }}</div>
                    </template>
                </el-table-column>
                <el-table-column label="TTL (秒)" prop="ttl" width="150px" />
                <el-table-column label="操作" width="250px">
                    <template #default="s">
                        <el-link type="primary" @click="get(s.row)">查询</el-link> &nbsp;
                        <el-link type="primary" @click="updateValue(s.row)">修改值</el-link> &nbsp;
                        <el-link type="primary" @click="updateTTL(s.row)">修改TTL</el-link> &nbsp;
                        <el-link type="primary" @click="del(s.row)">删除</el-link>
                    </template>
                </el-table-column>
            </el-table>
            <!-- ------------- 分页按钮 ------------- -->
            <div class="page-box">
                <el-pagination
                    background layout="total, prev, pager, next, sizes, jumper"
                    v-model:current-page="state.p.pageNo" v-model:page-size="state.p.pageSize" :total="state.dataCount"
                    :page-sizes="[1, 10, 20, 30, 40, 50, 100]"
                    @current-change="f5()" @size-change="f5()">
                </el-pagination>
            </div>
        </div>
    </el-scrollbar>
</template>

<script setup name="redis-console">
import {getCurrentInstance, onMounted, reactive} from "vue";
const { proxy } = getCurrentInstance();

// ------------------ 数据 ------------------
const state = reactive({
    p: reactive({ // 查询参数
        k: '',
        pageNo: 1,		// 当前页
        pageSize: 10,	// 页大小
        sortType: 0	// 排序方式
    }),
    isLike: true,	// 是否为模糊匹配
    dataCount: 0,
    preData: {
        keys_count: 0, // key 总数
        keyspace_hits: 0,	// 被命中次数
        used_memory_human: 0, // 已经占用内存数量
        used_memory_peak_human: 0, // 内存消耗峰值
        uptime_in_seconds: 0, // redis 已经启动的秒数
        uptime_in_seconds_str: '0', // redis 已经启动的时间
    },
    dataList: [],
    dataListShow: [],
})

// 组件加载时执行函数
onMounted(function (){
    f5_pre();
    auto_f5_run_time();
})

// ------------------ 函数 ------------------
// 根据分页信息显示出来
const f5ByPage = function() {
    const dataListShow2 = [];
    const start = (state.p.pageNo - 1) * state.p.pageSize;
    const end = state.p.pageNo * state.p.pageSize;
    for (let i = start; i < end; i++) {
        if (i >= state.dataList.length) {
            break;
        }
        dataListShow2.push(state.dataList[i]);
    }
    state.dataListShow = dataListShow2;
};
// 查询key列表
const f5 = function() {
    let k = state.p.k;
    if (state.isLike && k !== '') {
        k = '*' + k + '*';
    }
    sa.ajax('/RedisConsole/getKeys', { k: k }, function(res) {
        const dataList2 = [];
        for (let i = 0; i < res.data.length; i++) {
            dataList2.push({
                key: res.data[i],	// key
                value: '',		// value
                is_show: false,	// 是否已经显示详情
                ttl: '未加载',			// 过期时间
            })
        }
        state.dataList = dataList2;
        f5ByPage();
        state.dataCount = state.dataList.length;
    }, {
        success501: function(res) {
            sa.msg(res.msg);
            state.dataList = [];
            f5ByPage();
            state.dataCount = 0;
        }
    });
};
// 刷新预览
const f5_pre = function(is_f5_keys) {
    // 基本预览信息
    sa.ajax('/RedisConsole/getPreInfo', state.p, function(res) {
        res.data.uptime_in_seconds_str = getDuration(parseInt(res.data.uptime_in_seconds) * 1000);
        state.preData = res.data;
        // 如果指定不查询keys列表
        if (is_f5_keys === false) {
            return;
        }
        // 如果超过了最大值，则提示一下
        if (res.data.isGtMax) {
            let tipStr = 'key值数量已达' + state.preData.keys_count + '，为了避免卡顿已取消返回结果列表(您可以增加筛选条件缩短记录总数)';
            tipStr = '<b style="color: red;">' + tipStr + '</b>';
            sa.alert(tipStr);
        } else {
            f5();
        }
    });
};


// 加载详情
const get = function(data) {
    sa.ajax('/RedisConsole/getByKey?key=' + data.key, function(res) {
        data.value = res.data.value;
        data.ttl = res.data.ttl;
        data.is_show = true;
    });
};
// 删除
const del = function(data) {
    sa.confirm('是否删除，此操作不可撤销', function() {
        sa.ajax('/RedisConsole/del?key=' + data.key, function(res) {
            sa.arrayDelete(state.dataListShow, data);
            sa.ok2('删除成功');
        })
    });
};
// 修改键值
const updateValue = function(data) {
    sa.layer.prompt({
        title: '修改键值',
        // shadeClose: true,	// 点击遮罩关闭
        formType: 2,		// 多行输入
        maxlength: 9999999999,	// 最大输入字符长度
        area: ['600px', '400px'],	// 弹窗尺寸
    }, function(pass, index, elem){
        layer.close(index); // 如果设定了yes回调，需进行手工关闭
        sa.ajax('/RedisConsole/updateValue', { key: data.key, value: pass }, function(res){
            data.value = pass;
            layer.msg('修改成功');
        })
    });
};
// 修改ttl
const updateTTL = function(data) {
    sa.prompt('修改TTL', function(pass, index){
        if (isNaN(pass)) {
            return sa.error('请输入一个数值');
        }
        sa.ajax('/RedisConsole/updateTtl', { key: data.key, ttl: pass }, function(res){
            data.ttl = pass;
            sa.ok('修改成功');
        })
    });
};
// 添加
const add = function() {
    sa.showModel('添加键值', () => import('./redis-key-add'));
};
// 根据id列表删除
const deleteByKeys = function() {
    // 获取选中元素的id列表
    let selection = proxy.$refs['data-table'].getSelectionRows();
    let keys = sa.getArrayField(selection, 'key');
    if(selection.length === 0) {
        return sa.msg('请至少选择一条数据');
    }
    // 提交删除
    sa.confirm(`是否删除选中的 ${selection.length} 条数据？此操作不可撤销`, function() {
        sa.ajax('/RedisConsole/deleteByKeys', { keys: keys }, function(res) {
            sa.arrayDelete(state.dataListShow, selection);
            sa.ok('删除成功');
        })
    });
};
// 刷新秒数
const auto_f5_run_time = function() {
    setInterval(function() {
        if (state.preData.uptime_in_seconds <= 0 || state.preData.uptime_in_seconds > 60 * 60 * 24) {
            return;
        }
        state.preData.uptime_in_seconds++;
        state.preData.uptime_in_seconds_str = getDuration(parseInt(state.preData.uptime_in_seconds) * 1000);
    }, 1000);
};
// 获取时间的格式化显示
const getDuration = function(my_time) {
    var days = my_time / 1000 / 60 / 60 / 24;
    var daysRound = Math.floor(days);
    var hours = my_time / 1000 / 60 / 60 - (24 * daysRound);
    var hoursRound = Math.floor(hours);
    var minutes = my_time / 1000 / 60 - (24 * 60 * daysRound) - (60 * hoursRound);
    var minutesRound = Math.floor(minutes);
    var seconds = my_time / 1000 - (24 * 60 * 60 * daysRound) - (60 * 60 * hoursRound) - (60 * minutesRound);
    seconds = parseInt(seconds);
    // console.log('转换时间:', daysRound + '天', hoursRound + '时', minutesRound + '分', seconds + '秒');
    // var time = hoursRound + ':' + minutesRound + ':' + seconds
    // return time;
    if (daysRound >= 1) {
        return daysRound + '天' + hoursRound + '小时';
    } else if (hoursRound >= 1) {
        return hoursRound + '小时' + hoursRound + '分';
    } else if (minutesRound >= 1) {
        return minutesRound + '分' + seconds + '秒';
    } else {
        return seconds + '秒';
    }
};

defineExpose({f5, state})

</script>

<style scoped lang="scss">
.card-box {
    min-width: 230px;
    margin-right: 10px;
    margin-bottom: 10px;
    display: inline-block;
    background-color: #f5f5f5;
    cursor: pointer;
    transition: all 0.3s;
}
.card-box:hover{box-shadow: 0 0 20px #999;}

.card-box .prop-name {
    padding-left: 14px;
    padding-top: 14px;
    color: #666;
}

.card-box .prop-value {
    /* border: 1px #000 solid; */
    padding-left: 14px;
    height: 40px;
    line-height: 40px;
    padding-top: 10px;
    padding-bottom: 10px;
    font-size: 26px;
    color: green;
    -webkit-box-sizing: unset;
}

.f5-pre-btn:hover{cursor: pointer; text-decoration: underline;}

.key-div{color: green; cursor: pointer;font-weight: bold;}
.not-show,.is-show{padding: 5px 10px; background-color: #eee; cursor: pointer; }
.is-show{background-color: rgba(0,0,0,0);}

</style>
