<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <th:block th:include="include :: header('呼入记录列表')" />

    <th:block th:include="include :: video-js-css" />
    <th:block th:include="include :: video-js" />
    <style>
        #audio-modal {
            display: none;
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 1000;
        }
        #audio-modal-content {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            width: 640px; /* 设置模态框内容的宽度 */
        }
        /* 隐藏video.js默认的关闭按钮 */
        .vjs-big-play-button {
            display: none !important;
        }

        /*!* 新增对话框样式 *!*/
        /*#dialog-modal {*/
        /*    display: none;*/
        /*    position: fixed;*/
        /*    left: 0;*/
        /*    top: 0;*/
        /*    width: 100%;*/
        /*    height: 100%;*/
        /*    background-color: rgba(0, 0, 0, 0.5);*/
        /*    z-index: 1000;*/
        /*}*/
        /*#dialog-modal-content {*/
        /*    position: absolute;*/
        /*    left: 50%;*/
        /*    top: 50%;*/
        /*    transform: translate(-50%, -50%);*/
        /*    background-color: #fff;*/
        /*    padding: 20px;*/
        /*    border-radius: 5px;*/
        /*    width: 950px; !* 设置对话框内容的宽度 *!*/
        /*    overflow: auto;*/
        /*}*/

        #dialog-content {
            margin-top: 20px;
            max-height: 500px;
            overflow-y: auto;
            padding-right: 6px;          /* 预留滚动条空间 */
        }

        #audio-modal-close{
            position: absolute;
            top: 8px;           /* 离顶部 8px，可自行微调 */
            right: 8px;         /* 离右侧 8px，可自行微调 */
            font-size: 24px;    /* × 大小 */
            line-height: 1;
            color: #666;        /* 图标颜色 */
            cursor: pointer;
            background: none;   /* 去掉背景 */
            border: none;       /* 去掉边框 */
            border-radius: 0;   /* 去掉圆角 */
            padding: 0;         /* 去掉内边距 */
        }

        #video-modal{
            display:none;
            position:fixed;
            left:0;top:0;
            width:100%;height:100%;
            background:rgba(0,0,0,.5);
            z-index:1000;
        }
        #video-modal-content{
            position:absolute;
            left:50%;top:50%;
            transform:translate(-50%,-50%);
            background:#fff;
            padding:20px;
            border-radius:5px;
            width:680px;
        }
        #video-modal-close{ /* 同 #modal-close */
            position:absolute;
            top:-5px;right:-5px;
            font-size:24px;
            color:#666;
            cursor:pointer;
            background:none;border:none;
        }

        /* 悬停加深一点 */
        #audio-modal-close:hover,
        #dialog-modal-close:hover {
            color: #000;
        }

        /* 追加到已有样式表末尾即可 */
        #audio-modal-content,
        #video-modal-content {
            max-height: 90vh;   /* 可视区域 90% 高度，可按需要改 */
            overflow-y: auto;   /* 纵向滚动条 */
        }

        /* 每条气泡占整行 */
        .dialog-item {
            display: flex;
            align-items: center;
            margin-bottom: 12px;
            /* 左或右对齐靠下面的子元素控制 */
        }

        /* 真正的气泡：内容自适应宽度 */
        .bubble {
            display: inline-block;          /* 随内容宽 */
            max-width: 70%;                 /* 可选上限，防止超长 */
            padding: 10px 14px;
            border-radius: 12px;
            box-shadow: 0 2px 6px rgba(0,0,0,.06);
            border: 1px solid transparent;
            border-image: linear-gradient(to bottom,
            rgba(0,0,0,.08) 0%,
            rgba(0,0,0,0) 100%) 1;
            word-break: break-word;
        }

        /* 客户（右侧） */
        .dialog-item.user {
            justify-content: flex-end;      /* 整条靠右 */
        }
        .dialog-item.user .bubble {
            background: linear-gradient(135deg,#e3f2fd 0%,#bbdefb 100%);
            text-align: right;
        }

        /* AI（左侧） */
        .dialog-item.assistant {
            justify-content: flex-start;    /* 整条靠左 */
        }
        .dialog-item.assistant .bubble {
            background: linear-gradient(135deg,#e3f2fd 0%,#bbdefb 100%);
        }

        /* 坐席（左侧） */
        .dialog-item.agent {
            justify-content: flex-start;    /* 整条靠左 */
        }
        .dialog-item.agent .bubble {
            background: linear-gradient(135deg,#e3f2fd 0%,#bbdefb 100%);
        }

        /* 知识库（左侧） */
        .dialog-item.kb {
            justify-content: flex-start;
        }
        .dialog-item.kb .bubble {
            background: linear-gradient(135deg,#e3f2fd 0%,#bbdefb 100%);
        }

        /* 文本内容区 */
        .content-text {
            flex: 1;
            word-break: break-word;
            line-height: 1.6;
            color: #263238;
            font-size: 14px;
        }

        /* 更多/收起按钮 */
        .more-text {
            margin-left: 6px;
            color: #1976d2;
            cursor: pointer;
            font-size: 13px;
            white-space: nowrap;
        }

        /* 客户（右侧）整体右对齐 */
        .dialog-item.user {
            justify-content: flex-end;   /* 让图标在文字右侧 */
            text-align: right;           /* 文本右对齐 */
        }

        /* 客户内容区右对齐并微调间距 */
        .dialog-item.user .content-text {
            text-align: right;
            margin-right: 8px;           /* 与图标留一点空隙，可自行调整 */
        }

        /* 强制换行 */
        #bootstrap-table td {
            word-break: break-all;
            white-space: normal;
        }

        .my-audio-player{background:#fff;border-radius:8px;padding:12px 16px;display:flex;align-items:center;gap:8px;font-size:14px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto}
        .my-audio-player button{border:none;background:none;font-size:18px;cursor:pointer}
        .my-audio-player input[type=range]{flex:1;cursor:pointer}

        /* 添加到 <style> 标签中任意位置（建议第200行后） */
        .hangup-cause-cell {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            cursor: pointer;
            max-width: 100%;
            padding: 2px 0;
        }
    </style>

</head>
<body class="gray-bg">
<div class="container-div">
    <div class="row">
        <div class="col-sm-12 search-collapse">
            <form id="formId">
                <div class="select-list">
                    <ul>
                        <li>
                            <label th:text="#{inboundcdr.query.uuid}"></label>
                            <input type="text" name="uuid"/>
                        </li>
                        <li>
                            <label th:text="#{inboundcdr.query.caller}"></label>
                            <input type="text" name="caller"/>
                        </li>
                        <li>
                            <label th:text="#{inboundcdr.query.extnum}"></label>
                            <input type="text" name="extnum"/>
                        </li>
                        <li>
                            <label style="width: 105px" th:text="#{inboundcdr.query.timeLen}"></label>
                            <input type="number" id="timeLenStart" style="width: 150px" th:placeholder="#{inboundcdr.query.placeholder.timeLenStart}" name="params[timeLenStart]"/>
                            <span>-</span>
                            <input type="number" id="timeLenEnd" style="width: 150px" th:placeholder="#{inboundcdr.query.placeholder.timeLenEnd}" name="params[timeLenEnd]"/>

                        </li>
                        <li class="select-time">
                            <label th:text="#{inboundcdr.query.inboundTime}"> </label>
                            <input type="text" style="width:150px" class="time-input" data-type="datetime" data-format="yyyy-MM-dd HH:mm:ss" id="inboundTimeStart" th:placeholder="#{inboundcdr.query.placeholder.startTime}" name="params[inboundTimeStart]"/>
                            <span>-</span>
                            <input type="text" style="width:150px" class="time-input" data-type="datetime" data-format="yyyy-MM-dd HH:mm:ss" id="inboundTimeEnd" th:placeholder="#{inboundcdr.query.placeholder.endTime}" name="params[inboundTimeEnd]"/>
                        </li>
                        <li class="select-time">
                            <label th:text="#{inboundcdr.query.answeredTime}"> </label>
                            <input type="text" style="width:150px" class="time-input" data-type="datetime" data-format="yyyy-MM-dd HH:mm:ss" id="answeredTimeStart" th:placeholder="#{inboundcdr.query.placeholder.startTime}" name="params[answeredTimeStart]"/>
                            <span>-</span>
                            <input type="text" style="width:150px" class="time-input" data-type="datetime" data-format="yyyy-MM-dd HH:mm:ss" id="answeredTimeEnd" th:placeholder="#{inboundcdr.query.placeholder.endTime}" name="params[answeredTimeEnd]"/>
                        </li>
                        <li class="select-time">
                            <label th:text="#{inboundcdr.query.hangupTime}"> </label>
                            <input type="text" style="width:150px" class="time-input" data-type="datetime" data-format="yyyy-MM-dd HH:mm:ss" id="hangupTimeStart" th:placeholder="#{inboundcdr.query.placeholder.startTime}" name="params[hangupTimeStart]"/>
                            <span>-</span>
                            <input type="text" style="width:150px" class="time-input" data-type="datetime" data-format="yyyy-MM-dd HH:mm:ss" id="hangupTimeEnd" th:placeholder="#{inboundcdr.query.placeholder.endTime}" name="params[hangupTimeEnd]"/>
                        </li>
                        <li>
                            <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;<span th:text="#{btn.search}"></span></a>
                            <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;<span th:text="#{btn.reset}"></span></a>
                        </li>
                    </ul>
                </div>
            </form>
        </div>

        <div class="col-sm-12 select-table table-striped">
            <table id="bootstrap-table" style="table-layout: fixed;"></table>
        </div>

        <!-- 音频模态框 -->
        <div id="audio-modal">
            <div id="audio-modal-content">
                <button id="audio-modal-close">&times;</button>
                <div id="chatAudioPlayer" style="display:none;margin-bottom:12px;">
                    <!-- 样式 -->
                    <style>
                        .my-audio-player{background:#f7f7f7;border-radius:6px;padding:8px 12px;display:flex;align-items:center;gap:6px;font-size:14px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto}
                        .my-audio-player button{border:none;background:none;font-size:18px;cursor:pointer}
                        .my-audio-player input[type=range]{flex:1;cursor:pointer}
                    </style>

                    <!-- 控件 -->
                    <div class="my-audio-player">
                        <button id="chatPlayBtn">▶️</button>
                        <span id="chatCurT">0:00</span>
                        <input type="range" id="chatBar" value="0" step="0.1">
                        <span id="chatTotT">0:00</span>
                        <select id="chatRate">
                            <option value="1">1×</option>
                            <option value="1.5">1.5×</option>
                            <option value="2">2×</option>
                        </select>
                        <!-- 真正 audio 标签（隐藏） -->
                        <audio id="chatAudio" preload="metadata"></audio>
                    </div>
                </div>
            </div>
        </div>

        <!-- 视频模态框 -->
        <div id="video-modal">
            <div id="video-modal-content">
                <button id="video-modal-close">&times;</button>
                <video id="videoPlayer" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="640" height="360">
                    <source src="" type="audio/mpeg">
                    Your browser does not support the audio tag.
                </video>
            </div>
        </div>
    </div>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javascript">
    var linstenFlag = [[${@permission.hasPermi('cc:inboundcdr:listen')}]];
    var downloadFlag = [[${@permission.hasPermi('cc:inboundcdr:download')}]];
    var prefix = ctx + "cc/inboundcdr";

    $(function() {
        var options = {
            url: prefix + "/list",
            createUrl: prefix + "/add",
            updateUrl: prefix + "/edit/{id}",
            removeUrl: prefix + "/remove",
            exportUrl: prefix + "/export",
            modalName: i18n('inboundcdr.modalName'),
            columns: [{
                checkbox: true
            },
            {
                field: 'id',
                title: '${comment}',
                visible: false
            },
            {
                field: 'uuid',
                title: i18n('inboundcdr.table.uuid'),
                width: 100
            },
            {
                field: 'caller',
                title: i18n('inboundcdr.table.caller'),
                width: 80
            },
            {
                field: 'wavFile',
                title: i18n('inboundcdr.table.wavFile'),
                width: 80,
                formatter: function(value, row, index, field) {
                    // 获取文件后缀
                    const extension = value.split('.').pop().toLowerCase();
                    // 判断文件类型
                    if (['wav', 'mp3', 'aac'].includes(extension)) {
                        return i18n('outboundcdr.table.audio');
                    } else if (['mp4', 'avi', 'mov'].includes(extension)) {
                        return i18n('outboundcdr.table.video');
                    } else {
                        return i18n('outboundcdr.table.none');
                    }
                }
            },
            {
                field: 'inboundTime',
                title: i18n('inboundcdr.table.inboundTime'),
                width: 100,
                formatter: function(value, row, index, field) {
                    if (value > 0) {
                        // 假设value是时间戳，单位是毫秒
                        var date = new Date(Number(value));
                        // 格式化日期为年-月-日 时:分:秒
                        var year = date.getFullYear();
                        var month = (date.getMonth() + 1).toString().padStart(2, '0');
                        var day = date.getDate().toString().padStart(2, '0');
                        var hour = date.getHours().toString().padStart(2, '0');
                        var minute = date.getMinutes().toString().padStart(2, '0');
                        var second = date.getSeconds().toString().padStart(2, '0');
                        return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
                    } else {
                        return "-"
                    }
                }
            },
            {
                field: 'answeredTime',
                title: i18n('inboundcdr.table.answeredTime'),
                width: 100,
                formatter: function(value, row, index, field) {
                    if (value > 0) {
                        // 假设value是时间戳，单位是毫秒
                        var date = new Date(Number(value));
                        // 格式化日期为年-月-日 时:分:秒
                        var year = date.getFullYear();
                        var month = (date.getMonth() + 1).toString().padStart(2, '0');
                        var day = date.getDate().toString().padStart(2, '0');
                        var hour = date.getHours().toString().padStart(2, '0');
                        var minute = date.getMinutes().toString().padStart(2, '0');
                        var second = date.getSeconds().toString().padStart(2, '0');
                        return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
                    } else {
                        return "-"
                    }
                }
            },
            {
                field: 'extnum',
                width: 80,
                title: i18n('inboundcdr.table.extnum'),
            },
            {
                field: 'opnum',
                width: 80,
                title: i18n('inboundcdr.table.opnum'),
            },
            {
                field: 'hangupTime',
                title: i18n('inboundcdr.table.hangupTime'),
                width: 100,
                formatter: function(value, row, index, field) {
                    if (value > 0) {
                        // 假设value是时间戳，单位是毫秒
                        var date = new Date(Number(value));
                        // 格式化日期为年-月-日 时:分:秒
                        var year = date.getFullYear();
                        var month = (date.getMonth() + 1).toString().padStart(2, '0');
                        var day = date.getDate().toString().padStart(2, '0');
                        var hour = date.getHours().toString().padStart(2, '0');
                        var minute = date.getMinutes().toString().padStart(2, '0');
                        var second = date.getSeconds().toString().padStart(2, '0');
                        return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
                    } else {
                        return "-"
                    }
                }
            },
            {
                field: 'groupName',
                width: 80,
                title: i18n('inboundcdr.table.groupName')
            },
            {
                field: 'timeLen',
                width: 80,
                title: i18n('inboundcdr.table.timeLen'),
                formatter: function(value, row, index, field) {
                    // 计算分钟数，向下取整
                    var timeLen = Math.ceil(value / 1000);
                    const minutes = Math.floor(timeLen / 60);
                    // 计算剩余的秒数，取余数
                    const seconds = timeLen % 60;
                    // 返回格式化后的时间字符串
                    if (minutes > 0) {
                        return `${minutes}` + i18n("common.time.minute") + `${seconds}` + i18n("common.time.second");
                    } else {
                        return `${seconds}`  + i18n("common.time.second");
                    }
                }
            },
                {
                    field: 'hangupCause',
                    title: i18n('inboundcdr.table.hangupCause'),
                    width: 120,
                    formatter: function(value, row, index) {
                        if (!value) return '-';
                        return `<div class="hangup-cause-cell" data-toggle="tooltip" data-placement="top" title="${value}" data-full-text="${value}">${value}</div>`;
                    }
                },
            {
                title: i18n('inboundcdr.table.opra'),
                align: 'center',
                width: 120,
                formatter: function(value, row, index) {
                    var actions = [];
                    if (row.wavFileUrl) {
                        // 获取文件后缀
                        const extension = row.wavFileUrl.split('.').pop().toLowerCase();
                        // 判断文件类型
                        if (['wav', 'mp3', 'aac'].includes(extension)) {
                            actions.push('<a class="btn btn-success btn-xs ' + linstenFlag + '" href="javascript:void(0)" onclick="openModal(\'' + row.wavFileUrl + '\',\'' + escape(JSON.stringify(row.chatContent)) + '\')"><i class="fa fa-volume-up"></i>' + i18n('btn.record.audio.play') + '</a> ');
                            actions.push('<a class="btn btn-success btn-xs ' + downloadFlag + '" href="javascript:void(0)" onclick="checkFileExistence(\'' + row.wavFileUrl + '\')"><i class="fa fa-download"></i>' + i18n('btn.record.audio.download') + '</a>');
                        } else if (['mp4', 'avi', 'mov'].includes(extension)) {
                            actions.push('<a class="btn btn-success btn-xs ' + linstenFlag + '" href="javascript:void(0)" onclick="openModal(\'' + row.wavFileUrl + '\',\'' + escape(JSON.stringify(row.chatContent)) + '\')"><i class="fa fa-volume-up"></i>' + i18n('btn.record.video.play') + '</a> ');
                            actions.push('<a class="btn btn-success btn-xs ' + downloadFlag + '" href="javascript:void(0)" onclick="checkFileExistence(\'' + row.wavFileUrl + '\')"><i class="fa fa-download"></i>' + i18n('btn.record.video.download') + '</a>');
                        }
                    }
                    return actions.join('');
                }
            }]
        };
        $.table.init(options);

        // 添加到 $.table.init(options); 之后（第463行后）
        $('#bootstrap-table').on('post-body.bs.table', function () {
            // 初始化tooltip
            $('[data-toggle="tooltip"]').tooltip({
                container: 'body',
                boundary: 'window'
            });

            // 双击复制功能
            $('.hangup-cause-cell').off('dblclick').on('dblclick', function () {
                const text = $(this).data('full-text');

                // 1. 优先使用 ClipboardAPI（HTTPS 或 localhost）
                if (navigator.clipboard && window.isSecureContext) {
                    navigator.clipboard.writeText(text)
                        .then(() => $.modal.msgSuccess(i18n('common.msg.copy.success')))
                        .catch(() => fallbackCopy(text));
                } else {
                    // 2. 降级方案
                    fallbackCopy(text);
                }

                function fallbackCopy(txt) {
                    const textArea = document.createElement('textarea');
                    textArea.value = txt;
                    textArea.style.position = 'fixed';
                    textArea.style.left = '-9999px';
                    document.body.appendChild(textArea);
                    textArea.focus();
                    textArea.select();
                    try {
                        document.execCommand('copy');
                        $.modal.msgSuccess(i18n("common.msg.copy.success"));
                    } catch (err) {
                        $.modal.msgError(i18n("common.msg.copy.fail"));
                    }
                    document.body.removeChild(textArea);
                }
            });
        });
    });

    var videoPlayer; // 定义一个全局变量来存储播放器实例
    function openModal(url, escapedDialogContent){
        const type = getMediaType(url);
        console.log(type);
        // 关闭所有弹框
        $('#audio-modal, #video-modal').hide();
        const el = document.getElementById('dialog-content');
        if (el) {
            el.remove(); // 彻底从 DOM 中移除
        }
        // 暂停其他播放器
        if(videoPlayer) videoPlayer.pause();
        if(type === 'audio'){
            $('#audio-modal').show();
            window.loadChatAudio(url);
            var dialogContent = document.createElement('div');
            dialogContent.id = 'dialog-content';
            $('#audio-modal-content').append(dialogContent);
            if (escapedDialogContent) {
                openDialog(escapedDialogContent);
            }
        }else if(type === 'video'){

            var source = document.querySelector('#videoPlayer source');
            source.src = url;
            source.type = 'audio/mpeg'; // 确保类型正确

            // 初始化或更新播放器
            if (videoPlayer) {
                videoPlayer.src({ type: 'audio/mpeg', src: url });
            } else {
                videoPlayer = videojs('videoPlayer');
            }
            $('#video-modal').show();
            videoPlayer.play(); // 自动播放

            var dialogContent = document.createElement('div');
            dialogContent.id = 'dialog-content';
            $('#video-modal-content').append(dialogContent);
            if (escapedDialogContent) {
                openDialog(escapedDialogContent);
            }
        }else{
            $.modal.msgError(i18n("common.msg.unknown.media"));
        }
    }

    // 关闭模态框
    $(document).on('click', '#audio-modal-close', function() {
        $('#audio-modal').hide();
    });

    // 点击模态框外部区域关闭模态框
    $(document).on('click', '#audio-modal', function(e) {
        if (e.target.id === 'audio-modal') {
            $('#audio-modal').hide();
        }
    });

    $(document).on('click', '#video-modal-close', () => {
        $('#video-modal').hide();
        videoPlayer.pause();
    });

    $(document).on('click', '#video-modal', function(e){
        if(e.target.id === 'video-modal'){
            $('#video-modal').hide();
            videoPlayer.pause();
        }
    });

    function checkFileExistence(url) {
        fetch(url, { method: 'HEAD' })
            .then(response => {
                if (response.status === 200) {
                    // 文件存在，可以下载
                    window.location.href = url;
                } else {
                    // 文件不存在，显示错误消息
                    $.modal.msgError(i18n("common.msg.file.notexists"));
                }
            })
            .catch(() => {
                // 网络错误或文件不存在
                $.modal.msgError(i18n("common.msg.file.notexists"));
            });
    }

    // 新增查看对话功能
    function openDialog(escapedDialogContent) {

        // 解码字符串
        var dialogContent = unescape(escapedDialogContent);
        if (!dialogContent) {
            return;
        }
        // 清空对话框内容
        $('#dialog-content').empty();
        // 解析对话内容
        var dialogItems = JSON.parse((JSON.parse(dialogContent)));
        if (!dialogItems) {
            return;
        }
        dialogItems.forEach(function(item) {
            var role = item.role;
            var roleClass = '';
            var roleIcon = '';
            if (role === 'user') {
                roleClass = 'user';
                roleIcon = '<i class="fa fa-user"></i>'
            } else if (role === 'assistant') {
                roleClass = 'assistant'
                roleIcon = '<i class="fa fa-tv"></i>'
            } else if (role === 'agent') {
                roleClass = 'agent'
                roleIcon = '<i class="fa fa-user"></i>'
            } else {
                console.log("没有对应的role，不展示！");
                return
            }
            var content = item.content;
            // 使用正则表达式匹配 JSON 部分
            if (containsJson(content)) {
                console.log("包含json")
                roleClass = 'kb'
                role = 'kb'
                roleIcon = '<i class="fa fa-envelope-o"></i>'
                // var conJson = extractJson(content);
                while (containsJson(content)) {
                    content = removeJson(content);
                }
                if (!content) {
                    return;
                }
                // content = "知识库查询" + content;
            }


            // 创建对话内容容器
            var contentDiv = document.createElement('div');
            contentDiv.className = 'dialog-item ' + roleClass;
            var bubble = document.createElement('div');
            bubble.className = 'bubble';

            // 创建内容段落
            var contentSpan = document.createElement('span');
            contentSpan.className = 'content-text';
            contentSpan.textContent = content;

            // 检查内容是否超过75个字符
            var moreText = document.createElement('span');
            if (content.length > 75) {
                moreText.className = 'more-text';
                moreText.textContent = '[更多]';
                moreText.style.cursor = 'pointer';
                moreText.onclick = function() {
                    if (moreText.textContent === '[更多]') {
                        contentSpan.textContent = content;
                        moreText.textContent = '[收起]';
                        contentSpan.appendChild(moreText);
                    } else {
                        contentSpan.textContent = content.substring(0, 75) + '...';
                        moreText.textContent = '[更多]';
                        contentSpan.appendChild(moreText);
                    }
                };
                contentSpan.textContent = content.substring(0, 75) + '...';
                contentSpan.appendChild(moreText);
            }

            // 将图标字符串转换为 DOM 节点
            var roleIconElement = document.createElement('span');
            roleIconElement.innerHTML = roleIcon;
            roleIconElement = roleIconElement.firstChild;

            // 将图标字符串转换为 DOM 节点
            var roleElement = document.createElement('span');

            // 根据角色决定图标的位置
            if (role === 'user') {
                bubble.appendChild(contentSpan);
                contentDiv.appendChild(bubble);
                roleIconElement.style.paddingLeft = "12px";
                contentDiv.appendChild(roleIconElement);
                roleElement.textContent = i18n("tips.role.cust");
                contentDiv.appendChild(roleElement);
            } else if (role === 'assistant') {
                contentDiv.appendChild(roleIconElement);
                roleElement.textContent = "AI";
                roleElement.style.paddingRight = "12px";
                contentDiv.appendChild(roleElement);
                bubble.appendChild(contentSpan);
                contentDiv.appendChild(bubble);
            } else if (role === 'agent') {
                contentDiv.appendChild(roleIconElement);
                roleElement.textContent = i18n("tips.role.agent");
                roleElement.style.paddingRight = "12px";
                contentDiv.appendChild(roleElement);
                bubble.appendChild(contentSpan);
                contentDiv.appendChild(bubble);
            } else {
                contentDiv.appendChild(roleIconElement);
                roleElement.textContent = i18n("tips.role.kb");
                roleElement.style.paddingRight = "12px";
                contentDiv.appendChild(roleElement);
                bubble.appendChild(contentSpan);
                contentDiv.appendChild(bubble);
            }

            $('#dialog-content').append(contentDiv);
        });
    }

    function containsJson(input) {
        // 正则表达式匹配 JSON 格式的子串
        const jsonRegex = /{.*?}/s;

        // 检查字符串是否包含 JSON 格式的子串
        return jsonRegex.test(input);
    }

    // 提取json串
    function extractJson(input) {
        const jsonRegex = /{.*}/s;
        const match = input.match(jsonRegex);
        return match ? match[0] : null;
    }

    // 移除 JSON 部分
    function removeJson(input) {
        // 正则表达式匹配 JSON 格式的子串
        const jsonRegex = /{[^{}]*}/s;

        // 使用正则表达式替换 JSON 部分为空字符串
        return input.replace(jsonRegex, '').trim();
    }

    function getMediaType(url){
        console.log(url)
        if(!url) return 'none';
        const ext = url.split('.').pop().toLowerCase();
        console.log(ext)
        if(['wav','mp3','aac','m4a'].includes(ext)) return 'audio';
        if(['mp4','avi','mov','mkv','webm'].includes(ext)) return 'video';
        return 'none';
    }


    /* ===== 对话弹框音频播放器 ===== */
    (() => {
        const a   = document.getElementById('chatAudio');
        const p   = document.getElementById('chatPlayBtn');
        const bar = document.getElementById('chatBar');
        const cur = document.getElementById('chatCurT');
        const tot = document.getElementById('chatTotT');
        const rat = document.getElementById('chatRate');
        const wrap= document.getElementById('chatAudioPlayer');

        const fmt = t => `${Math.floor(t/60)}:${('0'+Math.floor(t%60)).slice(-2)}`;

        /* 供 openDialog 调用 */
        window.loadChatAudio = src => {
            a.src = src;
            a.load();
            wrap.style.display = 'block';
            p.textContent = '▶️';
            a.play();
            p.textContent='⏸️'
        };

        p.onclick   = () => { a.paused ? (a.play(), p.textContent='⏸️') : (a.pause(), p.textContent='▶️'); };
        a.ontimeupdate = () => { bar.value = a.currentTime; cur.textContent = fmt(a.currentTime); };
        a.onloadedmetadata = () => { bar.max = a.duration; tot.textContent = fmt(a.duration); };
        bar.oninput = () => a.currentTime = bar.value;
        rat.onchange = () => a.playbackRate = rat.value;

        /* 关闭弹框时停止音频 */
        $(document).on('click', '#audio-modal, #audio-modal-close', function(e){
            console.log(e.target.id);
            if(e.target === this || e.target.id === 'audio-modal-close'){
                a.pause();
                a.currentTime = 0;
                wrap.style.display = 'none';
            }
        });
    })();
</script>
</body>
</html>