<template>
    <div class="app-container">
        <el-card shadow="never" v-loading="loading">
            <div slot="header" class="clearfix">
                <span>{{ detail.ypwjName || '会议详情' }}</span>
                <el-button style="float: right; padding: 3px 0" type="text" @click="$router.back()">返回</el-button>
            </div>

            <el-row :gutter="20">
                <el-col :span="16">
                    <el-card shadow="never"
                        body-style="padding: 12px; height: calc(100vh - 220px); overflow: hidden; display: flex; flex-direction: column;background-color:#f6f8fa  ">
                        <div style="font-weight: 600; margin-bottom: 8px;">转录文本</div>
                        <div class="transcript-area flex-scroll" style="margin-left: 10px;">
                            <div style="padding-bottom: 10px;">
                                <div v-for="(segment, index) in transcriptList" :key="index" placement="top" style="margin-bottom: 15px;">
                                    <!-- start: 发言人头部信息 -->
                                    <div class="seg-header">
                                        <span class="speaker-name">{{ segment.speaker }}</span>
                                        <span class="time-badge time-start">
                                            <i class="el-icon-time"></i>
                                            <span class="time-value">{{ segment.timestamp || segment.time }}</span>
                                        </span>
                                        <span v-if="segment.realTime" class="time-badge time-end">
                                            <i class="el-icon-time"></i>
                                            <span class="time-value">{{ segment.realTime }}</span>
                                        </span>
                                    </div>
                                    <!-- end: 发言人头部信息 -->
                                    <div class="seg-body">
                                        <el-avatar :class="getAvatarClass(getSpeakerIndex(segment.speaker))">
                                            <img :src="getSpeakerIcon(getSpeakerIndex(segment.speaker))"
                                                class="avatar-img" alt="avatar" />
                                        </el-avatar>
                                        <div :class="['seg-bubble', { 'is-active': activeIndex === index }]">
                                            <div :class="['seg-content', { 'is-active': activeIndex === index }]"
                                                style="border-color: #ffffff;" @click="onSegmentClick(index, segment)"
                                                title="点击跳转到该时间播放">{{
                                                    segment.content
                                                    || segment.text }}</div>
                                            <!-- start: 图片展示区域 -->
                                            <div v-if="segment.file && segment.file.length > 0" class="seg-images">
                                                <el-image
                                                    v-for="(imgUrl, imgIndex) in segment.file"
                                                    :key="imgIndex"
                                                    :src="getImageUrl(imgUrl)"
                                                    :preview-src-list="getPreviewImageList(segment.file)"
                                                    :initial-index="imgIndex"
                                                    fit="cover"
                                                    class="seg-image-item"
                                                    lazy>
                                                </el-image>
                                            </div>
                                            <!-- end: 图片展示区域 -->
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="audio-footer">
                            <audio ref="audio" :src="getAudioUrl(detail.ypwj)" controls />
                        </div>
                    </el-card>
                </el-col>
                <el-col :span="8">
                    <el-card shadow="never" body-style="padding: 12px; height: calc(100vh - 220px); overflow: auto;">
                        <div
                            style="display:flex; align-items:center; justify-content: space-between; margin-bottom: 12px;">
                            <div style="font-weight: 600;">纪要</div>
                        </div>
                        <div class="summary" v-html="detail.hyjy"></div>
                    </el-card>
                </el-col>
            </el-row>
        </el-card>
    </div>

</template>

<script>
import { getHyjyxx } from '@/api/hyjyxx/hyjyxx'
import icon1 from '@/assets/images/个人1.svg'
import icon2 from '@/assets/images/个人2.svg'
import icon3 from '@/assets/images/个人3.svg'
import icon4 from '@/assets/images/个人4.svg'
import icon5 from '@/assets/images/个人5.svg'
import icon6 from '@/assets/images/个人6.svg'
import icon7 from '@/assets/images/个人7.svg'
import icon8 from '@/assets/images/个人8.svg'
import icon9 from '@/assets/images/个人9.svg'
import icon10 from '@/assets/images/个人10.svg'
import icon11 from '@/assets/images/个人11.svg'

export default {
    name: 'HyjyxxDetail',
    data() {
        return {
            id: null,
            detail: {},
            transcriptList: [],
            activeIndex: null,
            _loadedId: null,
            _inFlightId: null,
            _loadTimer: null,
            loading: false,
            speakerIcons: [icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, icon9, icon10, icon11]
        }
    },
    created() {
        // 不在 created/activated/watch 里多点触发，统一由路由钩子调用
    },
    activated() {
        // 组件从 keep-alive 恢复时，若路由参数变化，需刷新
        const newId = this.$route && this.$route.params && this.$route.params.id
        if (newId && newId !== this.id) {
            this.id = newId
            this.load()
        }
    },
    watch: {
        '$route.params.id'(val) {
            if (val && val !== this.id) {
                this.id = val
                this.load()
            }
        }
    },
    beforeRouteEnter(to, from, next) {
        next(vm => {
            vm.id = to.params.id
            vm.load()
        })
    },
    beforeRouteUpdate(to, from, next) {
        this.id = to.params.id
        this.load()
        next()
    },
    methods: {
        // 去掉去抖函数，改为仅从路由钩子触发，天然 1 次/次导航
        onSegmentClick(index, segment) {
            this.activeIndex = index
            const t = segment && (segment.timestamp || segment.time)
            this.seekTo(t)
        },
        getSpeakerIndex(speaker) {
            // 解析“发言人X”中的数字X；若未解析到则使用哈希映射到1-11
            const m = String(speaker || '').match(/(\d{1,2})/)
            if (m) {
                const idx = parseInt(m[1], 10)
                if (idx >= 1 && idx <= 11) return idx
            }
            // 简单哈希到 1..11
            const s = String(speaker || '')
            let hash = 0
            for (let i = 0; i < s.length; i++) hash = (hash * 31 + s.charCodeAt(i)) >>> 0
            return (hash % 11) + 1
        },
        getAvatarClass(idx) {
            return `avatar-color-${idx}`
        },
        getSpeakerIcon(idx) {
            const n = Number(idx)
            if (!n || n < 1) return this.speakerIcons[0]
            if (n > 11) return this.speakerIcons[10]
            return this.speakerIcons[n - 1]
        },
        getAvatarText(speaker) {
            // 头像内显示发言人序号或首字
            const m = String(speaker || '').match(/(\d{1,2})/)
            if (m) return m[1]
            const s = String(speaker || '').trim()
            return s ? s[0] : '发'
        },
        normalizeText(str) {
            if (str == null) return ''
            return String(str)
                .replace(/\r/g, '')
                .replace(/\s+/g, ' ')
                .trim()
        },
        getAudioUrl(path) {
            if (!path) return ''
            // 绝对地址直接返回，相对地址补全网关前缀
            if (/^https?:\/\//i.test(path)) return path
            const base = process.env.VUE_APP_BASE_API || ''
            return `${base}${path}`
        },
        /**
         * 获取图片完整URL
         * @param {string} path - 图片路径
         * @returns {string} 完整URL
         */
        getImageUrl(path) {
            if (!path) return ''
            // 绝对地址直接返回，相对地址补全网关前缀
            if (/^https?:\/\//i.test(path)) return path
            const base = process.env.VUE_APP_BASE_API || ''
            return `${base}${path}`
        },
        /**
         * 获取预览图片列表（用于图片预览功能）
         * @param {Array} fileList - 文件路径数组
         * @returns {Array} 完整URL数组
         */
        getPreviewImageList(fileList) {
            if (!Array.isArray(fileList) || fileList.length === 0) return []
            return fileList.map(path => this.getImageUrl(path))
        },
        load() {
            if (!this.id) return
            if (this._loadedId === this.id) {
                // 避免重复加载导致的展示重复
                return
            }
            // 先清空旧数据，避免短时显示上一条内容
            this.detail = {}
            this.transcriptList = []
            this.activeIndex = null
            const currentId = this.id
            if (this._inFlightId === currentId) {
                // 已有同一个ID的请求在进行，直接跳过
                return
            }
            // 标记进行中的请求，后到的旧响应将被忽略
            this._inFlightId = currentId
            this.loading = true
            getHyjyxx(currentId).then(res => {
                if (this._inFlightId !== currentId) return
                this.detail = res.data || {}
                // 优先使用后端标准字段 detail.ywBzh（数组：{ speaker, timestamp, content }）
                let bzh = this.detail.ywBzh
                console.log('ywBzh (raw):', bzh)
                // 兼容后端把数组以字符串返回的情况
                if (typeof bzh === 'string') {
                    try {
                        const parsed = JSON.parse(bzh)
                        if (Array.isArray(parsed)) bzh = parsed
                    } catch (e) {
                        console.warn('Failed to parse ywBzh string:', e)
                    }
                }
                if (Array.isArray(bzh)) {
                    // 不做去重与规范化，按后端返回原样展示
                    this.transcriptList = bzh
                    this._loadedId = currentId
                } else {
                    // 不再使用 detail.yw 的回退解析，避免展示超出接口返回的内容
                    this.transcriptList = []
                    this._loadedId = currentId
                }
            }).finally(() => {
                if (this._inFlightId === currentId) {
                    this.loading = false
                    this._inFlightId = null
                }
            })
        },
        parseTranscript(raw) {
            if (!raw) return []
            // 简单解析：支持形如 “发言人A 00:00:25：内容...” 的行
            const lines = String(raw).split(/\n+/)
            return lines.filter(Boolean).map(line => {
                const m = line.match(/^(.*?)(\d{2}:\d{2}:\d{2})[:：]\s*(.*)$/)
                if (m) {
                    return { speaker: m[1].trim() || '发言人', time: m[2], text: m[3] }
                }
                return { speaker: '发言', time: '', text: line }
            })
        },
        /**
         * 将时间表达（如 "01:02:03"、"12:34"、"90"）解析为秒
         */
        parseTimeToSeconds(timeLike) {
            if (timeLike == null || timeLike === '') return null
            const s = String(timeLike).trim()
            // 纯数字视为秒
            if (/^\d+(?:\.\d+)?$/.test(s)) return parseFloat(s)
            // 支持 HH:MM:SS 或 MM:SS
            const parts = s.split(':').map(n => parseFloat(n))
            if (parts.some(isNaN)) return null
            let seconds = 0
            if (parts.length === 3) {
                seconds = parts[0] * 3600 + parts[1] * 60 + parts[2]
            } else if (parts.length === 2) {
                seconds = parts[0] * 60 + parts[1]
            } else if (parts.length === 1) {
                seconds = parts[0]
            } else {
                return null
            }
            return seconds
        },
        /**
         * 跳转到指定时间并播放
         */
        seekTo(timeLike) {
            const audio = this.$refs.audio
            if (!audio) return
            const seconds = this.parseTimeToSeconds(timeLike)
            if (seconds == null || !isFinite(seconds)) return
            try {
                // 边界保护
                const target = Math.max(0, seconds)
                audio.currentTime = target
                audio.play && audio.play()
            } catch (e) {
                // 忽略设置失败
            }
        },
        playAudio() {
            const el = this.$refs.audio
            if (el) el.play()
        },
        reload() {
            this.load()
        }
    }
}
</script>

<style scoped>
/* 全局字体（该组件内） */
.app-container {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
        "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC",
        "Source Han Sans SC", sans-serif;
}

::v-deep .el-timeline-item {
    padding-bottom: 10px !important;
}

.summary {
    white-space: pre-wrap;
    line-height: 1.8;
}

/* 头部（发言人 + 时间）同一行展示 */
.seg-header {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

/* 发言人名称样式 */
.speaker-name {
    color: #303133;
    font-weight: 600;
    font-size: 14px;
    margin-right: 4px;
}

/* 时间标签容器 */
.time-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    line-height: 1;
    transition: all 0.3s;
    margin-left: -4px;
}

/* 开始时间样式 */
.time-start {
    background-color: #ecf5ff;
    color: #409eff;
    border: 1px solid #b3d8ff;
}

.time-start i {
    font-size: 12px;
}

.time-start .time-label {
    color: #66b1ff;
    font-weight: 500;
}

.time-start .time-value {
    color: #409eff;
    font-weight: 600;
}

/* 结束时间样式 */
.time-end {
    background-color: #f0f9ff;
    /* color: #67c23a;
    border: 1px solid #c2e7b0; */
    color: #ff0000;
    border: 1px solid #e7b0b0;
}

.time-end i {
    font-size: 12px;
}

.time-end .time-label {
    color: #f47777;
    /* color: #85ce61; */
    font-weight: 500;
}

.time-end .time-value {
    color: #ec5656;
    /* color: #67c23a; */
    font-weight: 600;
}

/* 时间标签悬浮效果 */
.time-badge:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* 下方头像 + 内容布局 */
.seg-body {
    display: flex;
    align-items: flex-start;
}

.seg-content {
    margin-left: 10px;
    cursor: pointer;
}

.seg-content.is-active {
    color: #409EFF;
    /* Element 主色 */
}

.avatar-text {
    font-size: 12px;
}

/* 替换为SVG图标时，确保图标适配头像大小 */
.seg-body .el-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: transparent;
    width: 35px;
    height: 35px;
    min-width: 35px;
    min-height: 35px;
}

.avatar-img {
    width: 35px;
    height: 35px;
    object-fit: contain;
    display: block;
}

/* 文本气泡容器：与头像分离的一块背景 */
.seg-bubble {
    background-color: #ffffff;
    border: 1px solid #ebeef5;
    border-radius: 8px;
    padding: 8px 10px;
    margin-left:22px;
    flex: 1 1 auto;
}

.seg-bubble.is-active {
    border-color: #409EFF;
    background-color: #f0f8ff;
}

/* 图片展示区域 */
.seg-images {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.seg-image-item {
    width: 35px;
    height: 35px;
    border-radius: 4px;
    overflow: hidden;
    cursor: pointer;
    border: 1px solid #ebeef5;
    transition: all 0.3s;
}

.seg-image-item:hover {
    border-color: #409EFF;
    transform: scale(1.02);
}

/* 11种可区分的颜色，按发言人编号映射 */
.avatar-color-1 {
    color: #14a1ff;
}

.avatar-color-2 {
    color: #52c41a;
}

.avatar-color-3 {
    color: #fa8c16;
}

.avatar-color-4 {
    color: #ff4d4f;
}

.avatar-color-5 {
    color: #909399;
}

.avatar-color-6 {
    color: #00B8A9;
}

.avatar-color-7 {
    color: #8E54E9;
}

.avatar-color-8 {
    color: #2D9CDB;
}

.avatar-color-9 {
    color: #27AE60;
}

.avatar-color-10 {
    color: #EB5757;
}

.avatar-color-11 {
    color: #F2994A;
}

/* 左侧：上方可滚动，下方固定播放器 */
.flex-scroll {
    flex: 1 1 auto;
    overflow: auto;
}

.audio-footer {
    flex: 0 0 auto;
    padding-top: 12px;
    border-top: 1px solid #ebeef5;
    box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.04);

}

.audio-footer audio {
    width: 100%;
}
</style>
