1
QYF-GitLab1
2024-07-23 12d99c9a0dc366df61e10101b3e0821e1add6adb
src/pages/academicSchools/index.vue
@@ -1,19 +1,950 @@
<template>
  <view>
    <headNav :idIndex="6" text="学术流派" />
  <view
    style="width: 100%; height: 100%; display: flex; flex-direction: column"
  >
    <headNav :idIndex="'6'" text="学术流派" />
    <!-- 高级搜索 -->
    <view
      style="
        padding-left: 0.6rem;
        margin-top: 0.1rem;
        display: flex;
        position: relative;
      "
    >
      <advancedSearch
        @onSearch="onSearch"
        placehold="请输入关键字"
        :isAvancedTrue="false"
        :keyword="searchKey"
      />
      <view
        @click="isAvancedClick"
        style="
          color: #244a7b;
          cursor: pointer;
          font-size: 0.12rem;
          margin-left: 0.35rem;
          line-height: 0.58rem;
        "
        >高级搜索 {{ isAdvancedSearch ? "∧" : "∨" }}</view
      >
      <!-- 热门搜索 -->
      <view class="flex flex-center hotSearch" style="margin-left: 2rem">
        热门搜索:
        <ul class="flex" style="margin-right: 10rpx">
          <li
            @click="onSearch({ text: item }, index)"
            :class="{ cursor: true, active: hotAciveIndex === index }"
            v-for="(item, index) in hotKeyList"
            :key="item"
          >
            {{ item.name }}
          </li>
        </ul>
      </view>
      <view v-if="isAdvancedSearch" class="searchDialog">
        <h3 style="margin-bottom: 0.2rem">高级搜索</h3>
        <el-form  label-width="100px" :model="formData" size="mini">
          <el-row>
            <el-col :span="8">
              <el-form-item label="姓名/别名:">
                <el-input v-model="formData.name"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="活动地:">
                <el-select
                  style="width: 100%"
                  v-model="formData.actively"
                  placeholder="请选择活动地"
                >
                  <!-- <el-option label="区域一" value="shanghai"></el-option> -->
                  <!-- <el-option label="区域二" value="beijing"></el-option> -->
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="作品:">
                <el-input v-model="formData.works"></el-input>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="8">
              <el-form-item label="人物标签:">
                <el-select
                  style="width: 100%"
                  v-model="formData.personTags"
                  placeholder="请选择人物标签"
                >
                  <!-- <el-option label="区域一" value="shanghai"></el-option> -->
                  <!-- <el-option label="区域二" value="beijing"></el-option> -->
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="社会身份:">
                <el-select
                  style="width: 100%"
                  v-model="formData.socialIdentity"
                  placeholder="请选择社会身份"
                >
                  <!-- <el-option label="区域一" value="shanghai"></el-option> -->
                  <!-- <el-option label="区域二" value="beijing"></el-option> -->
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="时期:">
                <el-select
                  style="width: 100%"
                  v-model="formData.period"
                  placeholder="请选择时期"
                >
                  <!-- <el-option label="区域一" value="shanghai"></el-option> -->
                  <!-- <el-option label="区域二" value="beijing"></el-option> -->
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
        <div style="text-align: right">
          <el-button type="primary" size="mini">搜索</el-button>
          <el-button size="mini">重置</el-button>
        </div>
      </view>
      <div v-if="showPerson" class="personDialog">
        <i
          class="el-icon-circle-close closeBtn"
          @click="
            () => {
              showPerson = false;
            }
          "
        ></i>
        <el-table :data="personList" style="width: 100%">
          <el-table-column prop="name" label="姓名">
            <template slot-scope="scope">
              <span
                style="color: #409eff; cursor: pointer"
                @click="
                  () => {
                    currentId = scope.row.id;
                    getData();
                  }
                "
                >{{ scope.row.name }}</span
              >
            </template>
          </el-table-column>
          <el-table-column prop="age" label="时代"> </el-table-column>
          <el-table-column prop="nativePlace" label="籍贯"> </el-table-column>
          <el-table-column prop="alias" label="别名"> </el-table-column>
          <el-table-column prop="division" label="医学分科"> </el-table-column>
        </el-table>
      </div>
    </view>
    <!-- 关系表地图 -->
    <div
      id="relation"
      style="margin-top: 0.1rem; flex: 1; width: 100%; position: relative"
    >
      <div
        v-if="!loading && relationships.length == 0"
        style="
          position: absolute;
          top: 30%;
          left: 0;
          right: 0;
          text-align: center;
          font-size: 0.2rem;
          color: #666;
        "
      >
        暂无相关数据
      </div>
      <div
        v-if="loading"
        v-loading="loading"
        style="
          position: absolute;
          top: 30%;
          left: 0;
          right: 0;
          text-align: center;
          font-size: 0.2rem;
          color: #666;
        "
      ></div>
    </div>
    <div id="customDialog" class="customDialog">
      <div class="title">
        <span>{{ detailData.name }}</span>
        <span @click="closeDom">关闭</span>
      </div>
      <div class="content">
        <p>姓名:{{ detailData.name }}</p>
        <p>别名:{{ detailData.alias }}</p>
        <p>籍贯:{{ detailData.nativePlace }}</p>
        <p>医学分科: {{ detailData.medicalBranch }}</p>
        <p>小传:{{ detailData.biography }}</p>
      </div>
      <div class="btn" @click="spaceTimeArr(detailData.id)">查看更多>>></div>
    </div>
  </view>
</template>
<script>
// import * as echarts from "echarts";
// import axios from "axios";
import {
  getPersonData,
  getHotSearch,
  getPDataStatistics,
  academicSearch,
} from "@/api/index.js";
import * as echarts from "echarts";
export default {
  data() {
    return {};
    return {
      loading: true,
      hotAciveIndex: "",
      currentId: 21682,
      // echarts数据
      nodes: [],
      // echarts两者的关系
      relationships: [],
      // 热门搜索
      hotKeyList: [],
      searchKey: "",
      // 分类
      categories: [],
      // 人物信息
      infoOfPersons: [],
      // 学术流派
      infoOfSchools: [],
      // 当前人物信息
      ownInfo: null,
      detailData: {
        name: "",
      },
      isAdvancedSearch: false,
      formData: {
        name: "",
        actively: "",
        works: "",
        personTags: "",
        socialIdentity: "",
        period: ""
      },
      showPerson: false,
      personList: [],
      personPageInfo: {
        totalCount: 0,
        page: 1,
        limit: 10,
      },
    };
  },
  onLoad(options) {},
  methods: {}
  mounted() {
    this.getData();
    // this.echartsArr();
    this.hotSearch();
    // 监听窗口大小变化
    window.addEventListener("resize", this.relation);
  },
  onLoad(options) {
    this.searchKey = options.keyword;
  },
  methods: {
    // 获取人物关系
    getPersonInfo(arr, str, newArr, order, type, parent) {
      for (let i = 0; i < arr.length; i++) {
        const ele = arr[i];
        const personInfo = this.infoOfPersons.find(
          (item) => item.id == ele.personId
        );
        if (personInfo?.id) {
          const obj = {
            personId: ele.personId,
            parentId: parent.id,
            relationTypeName: ele.relationTypeName,
            parentName: parent?.NAME[0]?.content1 ?? parent.parentName,
            name: personInfo?.NAME[0]?.content1,
            category: type,
            symbolSize: 15,
          };
          if (order > 80) {
            order = 80;
          }
          if (str == "literatureList") {
            obj.relationTypeName = ele.literatureName;
          }
          if (str == "schoolList") {
            const nameData = this.infoOfSchools?.find(
              (i) => i.schoolId == ele.schoolId
            );
            obj.relationTypeName = nameData?.name[0];
          }
          if (str == "placeList") {
            obj.relationTypeName = ele.ancientName ?? ele.currentName;
          }
          newArr.push(obj);
          if (ele["kinList"] && ele["kinList"]?.length) {
            order += 15;
            this.getPersonInfo(
              ele["kinList"],
              "kinList",
              newArr,
              order,
              0,
              personInfo
            );
          }
          if (ele["teacherStudentList"] && ele["teacherStudentList"]?.length) {
            order += 15;
            this.getPersonInfo(
              ele["teacherStudentList"],
              "teacherStudentList",
              newArr,
              order,
              1,
              personInfo
            );
          }
          if (ele["literatureList"] && ele["literatureList"]?.length) {
            const data = this.changeLiterature(
              ele["literatureList"],
              "literatureList"
            );
            order += 15;
            this.getPersonInfo(
              data,
              "literatureList",
              newArr,
              order,
              2,
              personInfo
            );
          }
          if (ele["socialList"] && ele["socialList"]?.length) {
            const data = this.changeLiterature(ele["socialList"], "socialList");
            order += 15;
            this.getPersonInfo(
              data,
              "socialList",
              newArr,
              order,
              3,
              personInfo
            );
          }
          if (ele["placeList"] && ele["placeList"]?.length) {
            const data = this.changeLiterature(ele["placeList"], "placeList");
            order += 15;
            this.getPersonInfo(data, "placeList", newArr, order, 4, personInfo);
          }
          if (ele["schoolList"] && ele["schoolList"]?.length) {
            const data = this.changeLiterature(ele["schoolList"], "schoolList");
            order += 15;
            this.getPersonInfo(
              data,
              "schoolList",
              newArr,
              order,
              5,
              personInfo
            );
          }
        }
      }
    },
    // 处理数据
    changeLiterature(arr, str) {
      for (let i = 0; i < arr.length; i++) {
        const ele = arr[i];
        if (!ele.personId && ele.personList?.length) {
          ele.literatureList = [];
          ele.personId = this.ownInfo.id;
          if (ele["personList"] && ele["personList"]?.length) {
            for (let j = 0; j < ele["personList"].length; j++) {
              const item = ele["personList"][j];
              const data = item[str]?.map((e) => {
                return {
                  ...e,
                  personId: item.personId,
                };
              });
              if (ele[str] && data?.length) {
                ele[str].push(...data);
              }
            }
          }
        }
      }
      return arr;
    },
    // 文献
    //数组去重
    deduplicateArray(arr, idKey) {
      // 使用一个辅助对象来跟踪已经见过的ID
      const seen = {};
      // 使用filter方法过滤数组
      const deduplicatedArray = arr.filter((item) => {
        // 获取当前对象的ID
        const id = item[idKey];
        // 如果ID在辅助对象中不存在,则将其添加到对象并返回true
        if (!seen[id]) {
          seen[id] = true;
          return true;
        }
        // 如果ID已经存在,返回false
        return false;
      });
      return deduplicatedArray;
    },
    // 查询详情
    getData() {
      this.loading = true;
      getPersonData(this.currentId).then((res) => {
        console.log(res,'res')
        this.nodes = [];
        this.relationships = [];
        let kinData = [];
        let teacher = [];
        let literature = [];
        let social = [];
        let place = [];
        let school = [];
        if (res && res.success && res.object) {
          this.infoOfPersons = res.object?.infoOfPersons;
          this.infoOfSchools = res.object?.infoOfSchools;
          console.log(res.object);
          if (res.object?.personChain) {
            this.ownInfo = this.infoOfPersons.find(
              (item) => item.id == res.object?.personChain.personId
            );
            const obj = res.object?.personChain;
            if (obj.kinList?.length) {
              let newArr = [];
              this.categories.push({ name: "亲属关系" });
              this.getPersonInfo(
                obj.kinList,
                "kinList",
                newArr,
                1,
                0,
                this.ownInfo
              );
              kinData = [...newArr];
            }
            if (obj.teacherStudentList?.length) {
              this.categories.push({ name: "师承关系" });
              let newArr = [];
              this.getPersonInfo(
                obj.teacherStudentList,
                "teacherStudentList",
                newArr,
                1,
                1,
                this.ownInfo
              );
              teacher = [...newArr];
            }
            if (obj.literatureList?.length) {
              this.categories.push({ name: "文献作品" });
              let newArr = [];
              const data = this.changeLiterature(
                obj.literatureList,
                "literatureList"
              );
              this.getPersonInfo(
                data,
                "literatureList",
                newArr,
                1,
                2,
                this.ownInfo
              );
              literature = [...newArr];
            }
            if (obj.socialList?.length) {
              let newArr = [];
              this.categories.push({ name: "社会关系" });
              const data = this.changeLiterature(obj.socialList, "socialList");
              this.getPersonInfo(
                data,
                "socialList",
                newArr,
                1,
                3,
                this.ownInfo
              );
              social = [...newArr];
            }
            if (obj.placeList?.length) {
              this.categories.push({ name: "活动地" });
              let newArr = [];
              const data = this.changeLiterature(obj.placeList, "placeList");
              this.getPersonInfo(data, "placeList", newArr, 1, 4, this.ownInfo);
              place = [...newArr];
            }
            if (obj.schoolList?.length) {
              this.categories.push({ name: "学术流派" });
              let newArr = [];
              const data = this.changeLiterature(obj.schoolList, "schoolList");
              this.getPersonInfo(
                data,
                "schoolList",
                newArr,
                1,
                5,
                this.ownInfo
              );
              school = [...newArr];
            }
          }
          const personData = [
            ...kinData,
            ...teacher,
            ...literature,
            ...social,
            ...place,
            ...school,
          ];
          personData.forEach((item) => {
            this.nodes.push({
              name: item.name,
              id: item.personId,
              ...item,
            });
            let obj = {
              source: item.parentName,
              target: item.name,
              relation: item.relationTypeName || "", // 如果存在 relationName 字段则使用,否则为空字符串
            };
            this.relationships.push(obj);
          });
        }
        this.loading = false;
        this.relation();
      });
    },
    // 关系图谱
    relation() {
      var chartDom = document.getElementById("relation");
      var myChart = echarts.init(chartDom);
      // 假设您有节点名称和它们之间的关系数据
      var nodes = this.deduplicateArray(this.nodes, "id");
      var relationships = this.relationships;
      nodes = nodes.map((item) => {
        let size = item.symbolSize;
        for (let i = 0; i < relationships.length; i++) {
          const linkItem = relationships[i];
          if (linkItem.source == item.parentName) {
            size += 5;
          }
          if (linkItem.target == item.parentName) {
            size += 5;
          }
        }
        return {
          ...item,
          symbolSize: size > 80 ? 80 : size,
        };
      });
      let FontSize = 12; // 字体大小
      let BorderWidth = 2; // 边框大小
      let SymbolSize = 80; // 尺寸距离
      let Distance = 10;
      // 不同尺寸下修改echarts的字体
      if (window.innerWidth > 2560 && window.innerWidth <= 3840) {
        FontSize = 20;
        BorderWidth = 5;
        SymbolSize = 90;
        Distance = 33;
      } else if (window.innerWidth > 1920 && window.innerWidth <= 2560) {
        FontSize = 18;
        BorderWidth = 4;
        SymbolSize = 80;
        Distance = 22;
      } else if (window.innerWidth >= 1366 && window.innerWidth <= 1920) {
        FontSize = 14;
        BorderWidth = 4;
        SymbolSize = 70;
        Distance = 22;
      }
      // 根据关系数据生成连接线
      var links = [];
      relationships.forEach((relationship, i) => {
        var sourceIndex = nodes.findIndex(
          (node) => node.parentName === relationship.source
        );
        var targetIndex = nodes.findIndex(
          (node) => node.name === relationship.target
        );
        if (relationship.relation) {
          if (sourceIndex !== -1 && targetIndex !== -1) {
            links.push({
              source: sourceIndex,
              target: targetIndex,
              label: {
                show: true,
                formatter: function (params) {
                  // 使用函数动态生成标签内容
                  // return relationships.find(rel => rel.source === nodes[params.data
                  //       .source] && rel.target === nodes[params.data.target])
                  //    .relation;
                  return relationship.relation;
                }, // 设置关系标签内容为"Child-Parent"
                color: "#2C2C2C",
                fontSize: FontSize - 2,
                backgroundColor: "rgba(255, 255, 255, 1)",
                padding: [3, 8],
                borderRadius: 30,
                position: "middle", // 设置标签文本在线的中间位置上居中显示
                // z: -1, // 设置标签的z轴高度,使其比连接线更高
                distance: -10, // 将标签放置在连接线上
              },
            });
          }
        }
      });
      // 根据nodes动态生成节点数据
      var nodeData = nodes;
      var option;
      option = {
        legend: [
          {
            left: 20,
            top: 20,
            orient: "vertical",
            data: this.categories.map(function (a) {
              return a.name;
            }),
          },
        ],
        series: [
          {
            type: "graph",
            legendHoverLink: false,
            layout: "force",
            symbolSize: 15,
            data: nodeData,
            links: links,
            categories: this.categories,
            roam: true,
            label: {
              show: true,
              position: "right",
              formatter: "{b}",
            },
            scaleLimit: {
              min: 0.4,
              max: 2,
            },
            lineStyle: {
              color: "source",
              curveness: 0.2,
            },
            emphasis: {
              focus: "adjacency",
              lineStyle: {
                width: 5,
              },
            },
            force: {
              repulsion: 600,
              edgeLength: 300,
            },
          },
        ],
      };
      // 设置点击事件监听
      myChart.off("click");
      myChart.on("click", (params) => {
        if (params.dataType === "node") {
          this.creatDom(params);
        }
      });
      myChart.setOption(option);
    },
    creatDom(params) {
      const e = params.event;
      const div = document.getElementById("customDialog");
      div.style.display = "block";
      div.style.left = e.offsetX + 50 + "px";
      div.style.top = e.offsetY - 50 + "px";
      const data = this.infoOfPersons?.find(
        (i) => i.id == params.data.personId
      );
      const obj = {
        id: params.data.id,
        name:
          data?.NAME?.map((e, i) => {
            i += 1;
            return e["content" + i];
          }).join("、") ?? "",
        alias:
          data?.ALIAS?.map((e, i) => {
            i += 1;
            return e["content" + i];
          }).join("、") ?? "",
        nativePlace:
          data?.NATIVE_PLACE?.map((e, i) => {
            i += 1;
            return e["content" + i];
          }).join("、") ?? "",
        medicalBranch:
          data?.MEDICAL_BRANCH?.map((e, i) => {
            i += 1;
            return e["content" + i];
          }).join("、") ?? "",
        biography: data?.BIOGRAPHY ?? "",
      };
      this.detailData = obj;
    },
    closeDom() {
      const div = document.getElementById("customDialog");
      div.style.display = "none";
    },
    // 基础搜索
    onSearch(val, index) {
      console.log(val);
      if (index !== undefined) {
        // 热门搜索关键字,直接查询数据
        this.searchKey = "";
        this.hotAciveIndex = index;
        this.currentId = val.text.id;
        this.getData();
      } else {
        this.hotAciveIndex = "";
        // 搜索先显示人物列表
        this.personPageInfo.page = 1;
        this.searchPerson(val.text);
      }
    },
    // 根据关键字检索人物
    searchPerson(key) {
      academicSearch({
        keyword: key,
        page: this.personPageInfo.page,
        pageSize: this.personPageInfo.limit,
      }).then((res) => {
        this.personList = res.list.map((item) => {
          return {
            id: item.personId,
            name: item.name,
            age:
              item.periodList && item.periodList.length
                ? item.periodList[0].content2
                : "-",
            nativePlace:
              item.nativePlaceList && item.nativePlaceList.length
                ? item.nativePlaceList[0].content1
                : "-",
            alias:
              item.aliasList && item.aliasList.length
                ? item.aliasList[0].content2
                : "-",
            division:
              item.medicalBranchList && item.medicalBranchList.length
                ? item.medicalBranchList[0].content1
                : "-",
          };
        });
        this.showPerson = true;
      });
    },
    // 关系图 点击里面的元素
    spaceTimeArr(id) {
      // 关系图的数据
      uni.navigateTo({
        url: "/pages/character/detail?id=" + id,
      });
    },
    // 获取朝代echarts的数据
    echartsArr() {
      getDataStatistics().then((res) => {
        res.object.dynastyStatistic.details.map((item, index) => {
          // this.dynasty.id = item.dynastyId
          // this.dynasty.name = item.dynastyName
          // this.dynasty.coord = item.count
          this.dynasty[index].id = item.dynastyId;
          this.dynasty[index].name = item.dynastyName;
          this.dynasty[index].coord = item.count;
        });
      });
    },
    // 热门搜索
    hotSearch() {
      getHotSearch().then((res) => {
        const indexList = Object.keys(res.object);
        indexList.sort((a, b) => parseInt(b) - parseInt(a));
        this.hotKeyList = indexList.map((item) => {
          return {
            id: item,
            name: res.object[item],
          };
        });
      });
    },
    isAvancedClick() {
      this.isAdvancedSearch = !this.isAdvancedSearch;
      // this.$nextTick(() => {
      //   var box1Height = document.querySelector(".fbox").offsetHeight;
      //   // let box2Height= document.querySelector('.fbox1').style.height = box1Height + 'px';
      //   let box2Height = document.querySelector(".fbox1").offsetHeight;
      //   if (box1Height <= box2Height) {
      //     document.querySelector(".fbox1").style.height = box1Height + "px";
      //   }
      // });
    },
  },
};
</script>
<style></style>
<style>
#relation {
  width: 100%;
  height: 100%;
  position: relative;
  background-image: url("../../static/image/characterRelationBg.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
  background-position: center;
}
.customDialog {
  width: 300px;
  min-height: 240px;
  display: none;
  position: fixed;
  z-index: 99999999;
  border-radius: 2px;
  background: #fff;
}
.customDialog .title {
  width: 100%;
  height: 35px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  box-sizing: border-box;
  background-color: rgb(221, 232, 246);
  font-size: 14px;
}
.customDialog .title span:nth-child(1) {
  font-size: 16px;
  font-weight: 600;
}
.customDialog .title span:nth-child(2) {
  color: rgb(95, 127, 168);
  cursor: pointer;
}
.customDialog .content {
  padding: 15px;
  box-sizing: border-box;
}
.customDialog .content p {
  margin-bottom: 5px;
  display: -webkit-box; /* 显示多行文本容器 */
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; /*显示行数*/
  overflow: hidden; /*隐藏多出部分文字*/
  text-overflow: ellipsis; /*用省略号代替多出部分文字*/
}
.customDialog .btn {
  display: flex;
  justify-content: center;
  align-items: center;
  color: rgb(95, 127, 168);
  cursor: pointer;
  font-size: 14px;
  height: 35px;
}
@media screen and (min-width: 2560px) and (max-width: 3840px) {
}
@media screen and (min-width: 1366px) and (max-width: 1920px) {
}
::v-deep .uni-input-placeholder {
  line-height: 1;
  font-size: 0.12rem;
}
::v-deep .ffff {
  border-radius: 0.5rem;
}
::v-deep .widget_button {
  border-radius: 0.5rem;
  margin: 0.02rem;
}
.hotSearch {
  font-size: 0.12rem;
  color: #2c2c2c;
  li {
    color: #244a7b;
    margin: 0 0.1rem;
    color: #244a7b;
    &.active {
      color: #027edc;
      font-weight: bold;
    }
  }
}
.searchDialog {
  position: absolute;
  top: 0.68rem;
  left: 0;
  right: 0;
  z-index: 999;
  padding: 0.1rem 0.4rem;
  background: #fff;
  min-height: 2rem;
}
.personDialog {
  position: absolute;
  top: 0.68rem;
  z-index: 999;
  padding: 0.1rem;
  background: #fff;
  border-radius: 6px;
  box-shadow: 0 0 10px -3px #000;
  .closeBtn {
    position: absolute;
    right: -10px;
    top: -10px;
    width: 24px;
    height: 24px;
    font-size: 24px;
    background-color: #fff;
    border-radius: 50%;
    color: #f56c6c;
    cursor: pointer;
  }
}
</style>