
<template>
  <div style="display: flex;
  height: 100vh;">
    <Menu
        :initial-active="2"
    />
    <div class="medical-qa-container">
      <!-- 标题 -->
      <div style="display: flex;align-items: center;">
        <div class="title-before">
        </div>
        <h2 class="title">医疗问答</h2>
      </div>

      <!-- 搜索框 -->
      <div class="search-box">
        <el-input
            v-model="query"
            placeholder="请输入问题..."
            clearable
        />
        <el-button type="primary" @click="handleSearch" style="    background: #114FE6;">查询</el-button>
      </div>

      <!-- 主内容区 -->
      <div class="content-wrapper">
        <!-- 左侧：问答结果 -->
        <div class="answer-list">
          <div v-if="queryRecord">
            <h2 class="section-title" style="margin-bottom: 10px;margin-top: 0px">问答提问</h2>
            <div class="answer-item" style=" background-color: #165DFF;
  border-color: #0066cc;
  color: #fff;    height: auto;max-height: 3vw">
{{queryRecord}}
            </div>
          </div>
          <h2 class="section-title">问答结果</h2>
          <div v-if="answers.length === 0" class="empty-state">
            请输入问题进行查询...
          </div>
          <div v-else class="answer-items">
            <div
                v-for="(item, index) in answers"
                :key="index"
                class="answer-item"
                @click="selectGraph(index)"
                :class="{ 'highlight': selected === index }"
            >
              {{ item.answer }}
            </div>
          </div>
        </div>

        <!-- 右侧：知识图谱 -->
        <div class="knowledge-graph">
          <div ref="graphContainer" class="graph-container" id="container"></div>
        </div>
      </div>
    </div>

  </div>
</template>

<script>
import Menu from "@/components/Menu.vue";
import {qaAnalyze} from "@/api/qa";
import {Graph} from "@antv/g6";
import {getGraph} from "@/api/graph";


export default {
  name: 'GraghQA',
  components: {Menu},
  data() {
    return {
      query:"",
      answers:[],
      selected:0,
      // 节点样式
      nodeShowLabel: true,
      nodeFontSize: 12,
      nodeFontColor: '#fff',
      nodeShape: 'circle',
      nodeSize: 50,
      nodeFill: '#9FD5FF',
      nodeStroke: '#5B8FF9',
      nodeLineWidth: 2,
      nodeFontFamily: 'Microsoft YaHei, sans-serif',

      // 边样式
      edgeShowLabel: true,
      edgeFontSize: 10,
      edgeFontColor: '#666666',
      edgeType: 'quadratic',
      edgeLineWidth: 2,
      edgeStroke: '#b6b2b2',
      edgeEndArrow: true,
      edgeFontFamily: 'Microsoft YaHei, sans-serif',


      queryRecord:""

    };
  },
  methods: {
    selectGraph(index){
      this.selected=index
      this.formatData(this.answers[index].result)
    },
    handleSearch(){
      this.answers=[]
      let data={
        text:this.query
      }
      this.queryRecord=this.query
      this.query=""
      // this.answers=[{"answer":"糖尿病患者应避免高糖食物，如糖果、甜点、含糖饮料等，以防止血糖波动。",
      //   "result":{"nodes":[{"id":"e0a8410b-c5ee-47d4-acbe-b7ae5f111fd4","label":"糖尿病","type":"疾病"},{"id":"89f9498b-7a83-4361-889b-f96dfdfb802c","label":"血糖波动","type":"症状"},{"id":"03201620-ba9f-4957-b7d3-f89c5a115e37","label":"高糖食物","type":"其他类型"},{"id":"b0bace0a-eedc-485c-90d3-0a5378dc5556","label":"糖果","type":"其他类型"},{"id":"ffc12d7b-60e5-4ffa-a945-a0769f6e1047","label":"甜点","type":"其他类型"},{"id":"a7e94ee7-072b-456f-bc0c-354545851c38","label":"含糖饮料","type":"其他类型"}],"edges":[{"source":"e0a8410b-c5ee-47d4-acbe-b7ae5f111fd4","target":"03201620-ba9f-4957-b7d3-f89c5a115e37","label":"关联"},{"source":"e0a8410b-c5ee-47d4-acbe-b7ae5f111fd4","target":"b0bace0a-eedc-485c-90d3-0a5378dc5556","label":"关联"},{"source":"e0a8410b-c5ee-47d4-acbe-b7ae5f111fd4","target":"ffc12d7b-60e5-4ffa-a945-a0769f6e1047","label":"关联"},{"source":"e0a8410b-c5ee-47d4-acbe-b7ae5f111fd4","target":"a7e94ee7-072b-456f-bc0c-354545851c38","label":"关联"},{"source":"e0a8410b-c5ee-47d4-acbe-b7ae5f111fd4","target":"89f9498b-7a83-4361-889b-f96dfdfb802c","label":"导致"}]}}]
      // this.initGraph(this.answers[0].result)
      // this.formatData(this.answers[0].result)
      qaAnalyze(data).then(res=>{
        this.answers=res
        if(this.answers.length>0){
          this.initGraph(this.answers[0].result)
        }
      })
    },
    formatData(data){
      this._graph.stopLayout();
      this.clearGraphState();
      const updatedEdges = data.edges.map(edge => ({
        ...edge,
        type:  this.edgeType,
        style: {
          endArrow: this.edgeEndArrow,
          stroke: this.edgeStroke,
          lineWidth: this.edgeLineWidth,
          label: this.edgeShowLabel,
          labelFontSize: this.edgeFontSize,
          labelFontFamily: this.edgeFontFamily,
          labelFill: this.edgeFontColor,

        },
      }))
      const updatedNodes = data.nodes.map(node => ({
        ...node,
        type: this.nodeShape,
        style:{
          size: this.nodeSize,
          lineWidth: this.nodeLineWidth,
          label: this.nodeShowLabel,
          labelFontSize: this.nodeFontSize,
          labelFontFamily: this.nodeFontFamily,
          labelFill: this.nodeFontColor,
          opacity: 1,
        }
      }))
      const updatedData = {
        nodes: updatedNodes,
        edges: updatedEdges
      }

      this.updateGraph(updatedData)
    },
    updateGraph(data) {
      if (!this._graph) return
      this._graph.setData(data)
      this._graph.render()
    },
    initGraph(data) {
      if (this._graph!=null){
        this._graph.destroy()
        this._graph = null;
      }
      const updatedEdges = data.edges.map(edge => ({
        ...edge,
        type:  this.edgeType,
        style: {
          endArrow: this.edgeEndArrow,
          stroke: this.edgeStroke,
          lineWidth: this.edgeLineWidth,
          label: this.edgeShowLabel,
          labelFontSize: this.edgeFontSize,
          labelFontFamily: this.edgeFontFamily,
          labelFill: this.edgeFontColor,

        },
      }))
      const updatedNodes = data.nodes.map(node => ({
        ...node,
        type: this.nodeShape,
        style:{
          size: this.nodeSize,
          lineWidth: this.nodeLineWidth,
          label: this.nodeShowLabel,
          labelFontSize: this.nodeFontSize,
          labelFontFamily: this.nodeFontFamily,
          labelFill: this.nodeFontColor,
          opacity: 1,
        }
      }))
      const updatedData = {
        nodes: updatedNodes,
        edges: updatedEdges
      }
      const container = this.$refs.graphContainer;
      console.log(container)
      if (container!=null){
        const width = container.clientWidth || 800;
        const height = container.clientHeight || 600;
        console.log(width)
        console.log(height)
        const graph = new Graph({
          container,
          width,
          height,
          layout: {
            type: 'force', // 力导向布局
            gravity: 0.3,   // 重力系数，控制节点聚集程度
            repulsion: 500, // 排斥力
            attraction: 20,  // 吸引力
            preventOverlap: true // 防止节点重叠


          },
          behaviors: [ 'zoom-canvas', 'drag-element',
            'click-select','focus-element', {
              type: 'hover-activate',
              degree: 1,
            },
            {
              type: 'drag-canvas',
              enable: (event) => event.shiftKey === false,
            },
            {
              type: 'brush-select',
            },
          ],

          node: {
            style: {
              fill: (d) => {
                const label = d?.type;
                if (label === 'Disease') return '#EF4444';   // 红
                if (label === 'Drug') return '#91cc75';      // 绿
                if (label === 'Symptom') return '#fac858';   // 橙
                if (label === 'Check') return '#336eee';   // 橙
                return '#59d1d4';                            // 默认灰蓝
              },
              stroke: (d) => {
                const label = d?.type;
                if (label === 'Disease') return '#B91C1C';
                if (label === 'Drug') return '#047857';
                if (label === 'Check') return '#1D4ED8';   // 橙
                if (label === 'Symptom') return '#B45309';
                return '#40999b';
              },
              labelText: (d) => d.label,
              labelPlacement: 'center',
              labelWordWrap: true,
              labelMaxWidth: '150%',
              labelMaxLines: 3,
              labelTextOverflow: 'ellipsis',
              labelTextAlign: 'center',
              opacity: 1
            },
            state: {
              active: {
                lineWidth: 2,
                shadowColor: '#ffffff',
                shadowBlur: 10,
                opacity: 1
              },
              inactive: {
                opacity: 0.3
              },
              normal:{
                opacity: 1
              }


            },
          },
          edge: {
            style: {
              labelText: (d) => d.label,
              stroke: (d) => {
                // 获取 target 节点的 label
                // const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID
                // // 根据 target 节点类型返回对应浅色
                // if (targetLabel === 'Disease') return 'rgba(239,68,68,0.5)';
                // if (targetLabel === 'Drug') return 'rgba(145,204,117,0.5)';
                // if (targetLabel === 'Symptom') return 'rgba(250,200,88,0.5)';
                // if (targetLabel === 'Check') return 'rgba(51,110,238,0.5)';   // 橙
                return 'rgba(89,209,212,0.5)'; // default
              },
              // labelFill: (d) => {
              //   // 获取 target 节点的 label
              //   const targetLabel = this._nodeLabelMap.get(d.target); // d.target 是目标节点 ID
              //   // 根据 target 节点类型返回对应浅色
              //
              //   if (targetLabel === 'Disease') return '#ff4444';
              //   if (targetLabel === 'Drug') return '#2f9b70';
              //   if (targetLabel === 'Symptom') return '#f89775';
              //   return '#6b91ff'; // default
              // }

            },
            state: {
              selected: {
                stroke: '#1890FF',
                lineWidth: 2,
              },
              highlight: {
                halo: true,
                haloStroke: '#1890FF',
                haloLineWidth: 6,
                haloStrokeOpacity: 0.3,
                lineWidth: 3,
                opacity: 1
              },
              inactive: {
                opacity: 0.3
              },
              normal:{
                opacity: 1
              }

            },

          },
          data:updatedData,


        });

        graph.render();
        this._graph = graph
        this._graph?.fitView()
      }


    },
  },

};
</script>
<style scoped>


.medical-qa-container {
  padding: 25px;
  background-color: #F6F9FF;
  flex: 1;
  overflow: auto;
  height: 100vh;
  margin: 0 auto;
}

.title {
  font-size: 22px;
  margin-bottom: 20px;
  position: relative;
  display: flex;
  align-items: center;
  color: #165DFF;
  margin-left: 11px;
}

.title-before {
  content: '';
  width: 8px;
  height: 22px;
  background-color: #165DFF;
  border-radius: 5px;
}

.search-box {
  display: flex;
  gap: 20px;
  margin-bottom: 30px;
  align-items: center;

}

.search-box .el-input {
  flex: 1;
  max-width: 94%;
  margin-right: 5px;
}

.content-wrapper {
  display: flex;
  gap: 20px;
  height: 37vw;
}

.answer-list {
  flex: 1;
  background-color: white;
  border-radius: 33px;
  padding: 25px;
  box-shadow: 3px 1px 12px 7px #ECF2FF;
  max-width: 32%;
}

.section-title {
  font-size: 16px;
  color: #165DFF;
  margin-bottom: 15px;
  padding-left: 12px;
  position: relative;
  display: flex;
  align-items: center;
  font-weight: 900;
}

.section-title::before {
  content: '';
  width: 6px;
  height: 16px;
  background-color: #165DFF;
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  border-radius: 5px;
}

.answer-items {
  max-height: 25vw;
  overflow-y: auto;
  padding-right: 10px;
  cursor: pointer;

}
.answer-items::-webkit-scrollbar {
  width: 6px; /* 滚动条宽度 */
}

.answer-items::-webkit-scrollbar-track {
  background: #fff; /* 轨道背景 */
  border-radius: 4px;
}

.answer-items::-webkit-scrollbar-thumb {
  background: #B8C2D9; /* 滑块颜色 */
  border-radius: 4px;
  transition: background 0.2s ease;

}

.answer-items::-webkit-scrollbar-thumb:hover {
  background: #B8C2D9; /* 悬停时滑块颜色 */
}
.answer-item {
  padding: 12px;
  border: 1px solid #165DFF;
  border-radius: 15px;
  background-color: #f9f9f9;
  line-height: 1.5;
  word-wrap: break-word;
  color: #a2a5a7;
  font-weight: 400;
  font-size: 13px;
  text-align: left;
  height: 4.5vw;
  margin-bottom: 12px;
}

.answer-item.highlight {
  background-color: #165DFF;
  border-color: #0066cc;
  color: #fff;
}
.answer-item:hover {
  background-color: #165DFF;
  border-color: #0066cc;
  color: #fff;
}
.empty-state {
  text-align: center;
  color: #fff;
  padding: 40px 0;
  font-size: 14px;
}

.knowledge-graph {
  flex: 1;
  background-color: white;
  border-radius: 16px;
  padding: 20px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
/deep/.el-input__wrapper{
  background-color: #EFF4FF;
  border: 1px solid #165DFF;
  border-radius: 8px;
}

</style>