<template>
|
<view
|
style="width: 100%; height: 100%; display: flex; flex-direction: column"
|
>
|
<headNav :idIndex="'6'" text="学术流派" />
|
<!-- 高级搜索 -->
|
<view style="margin-left: 0.6rem; margin-top: 0.1rem; display: flex">
|
<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 }}
|
</li>
|
</ul>
|
</view>
|
</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>
|
<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 {
|
getPersonData,
|
getHotSearch,
|
getPDataStatistics
|
} from "@/api/index.js";
|
import * as echarts from "echarts";
|
export default {
|
data() {
|
return {
|
loading: true,
|
hotAciveIndex: "",
|
currentId: 21682,
|
// echarts数据
|
nodes: [],
|
// echarts两者的关系
|
relationships: [],
|
// 热门搜索
|
hotKeyList: [],
|
searchKey: "",
|
|
// 分类
|
categories: [],
|
// 人物信息
|
infoOfPersons: [],
|
// 学术流派
|
infoOfSchools: [],
|
// 当前人物信息
|
ownInfo: null,
|
detailData: {
|
name: ""
|
},
|
isAdvancedSearch: false
|
};
|
},
|
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,
|
id2: personInfo.id,
|
relationTypeName: ele.relationTypeName,
|
parentName: parent?.NAME[0]?.content1 ?? parent.parentName,
|
name2: personInfo?.NAME[0]?.content1,
|
category: type
|
};
|
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++;
|
this.getPersonInfo(
|
ele["kinList"],
|
"kinList",
|
newArr,
|
order,
|
0,
|
personInfo
|
);
|
}
|
if (ele["teacherStudentList"] && ele["teacherStudentList"]?.length) {
|
order++;
|
this.getPersonInfo(
|
ele["teacherStudentList"],
|
"teacherStudentList",
|
newArr,
|
order,
|
1,
|
personInfo
|
);
|
}
|
if (ele["literatureList"] && ele["literatureList"]?.length) {
|
const data = this.changeLiterature(
|
ele["literatureList"],
|
"literatureList"
|
);
|
order++;
|
this.getPersonInfo(
|
data,
|
"literatureList",
|
newArr,
|
order,
|
2,
|
personInfo
|
);
|
}
|
|
if (ele["socialList"] && ele["socialList"]?.length) {
|
const data = this.changeLiterature(ele["socialList"], "socialList");
|
order++;
|
this.getPersonInfo(
|
data,
|
"socialList",
|
newArr,
|
order,
|
3,
|
personInfo
|
);
|
}
|
if (ele["placeList"] && ele["placeList"]?.length) {
|
const data = this.changeLiterature(ele["placeList"], "placeList");
|
order++;
|
this.getPersonInfo(data, "placeList", newArr, order, 4, personInfo);
|
}
|
if (ele["schoolList"] && ele["schoolList"]?.length) {
|
const data = this.changeLiterature(ele["schoolList"], "schoolList");
|
order++;
|
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[str] && ele[str]?.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 (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) => {
|
this.nodes = [];
|
this.relationships = [];
|
let kinData = [];
|
let teacher = [];
|
let literature = [];
|
let social = [];
|
let place = [];
|
let school = [];
|
if (res && res.success && res.object) {
|
// console.log(res.object);
|
this.infoOfPersons = res.object?.infoOfPersons;
|
this.infoOfSchools = res.object?.infoOfSchools;
|
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];
|
// console.log(literature, "literature");
|
}
|
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
|
];
|
// const k = personData.filter((item) => item.category == 0);
|
// const t = personData.filter((item) => item.category == 1);
|
// const l = personData.filter((item) => item.category == 2);
|
// const o = personData.filter((item) => item.category == 3);
|
// const p = personData.filter((item) => item.category == 4);
|
// const s = personData.filter((item) => item.category == 5);
|
// const nodesList = [...k, ...t, ...l, ...o, ...p, ...s];
|
// console.log(nodesList);
|
personData.forEach((item) => {
|
let exists1 = this.nodes.some(
|
(node) =>
|
node.id === item.parentId && node.name === item.parentName
|
);
|
let exists2 = this.nodes.some(
|
(node) => node.id === item.parentId && node.name === item.name2
|
);
|
// 证明不存在
|
if (item.name1 && exists1 !== true) {
|
this.nodes.push({
|
name: item.parentName,
|
id: item.parentId,
|
...item
|
});
|
}
|
if (item.name2 && exists2 !== true) {
|
this.nodes.push({
|
name: item.name2,
|
id: item.id2,
|
...item
|
});
|
}
|
let obj = {
|
source: item.parentName,
|
target: item.name2,
|
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;
|
|
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.name === 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 = {
|
backgroundColor: {
|
type: "image",
|
image: "/static/image/characterRelationBg.png",
|
size: "100% 100%", // 背景图片的尺寸,可以是百分比或者像素
|
position: "center center" // 背景图片的位置,可以是 top, bottom, middle 或者百分比
|
},
|
tooltip: {},
|
legend: [
|
{
|
left: 20,
|
top: 20,
|
orient: "vertical",
|
data: this.categories.map(function (a) {
|
return a.name;
|
})
|
}
|
],
|
series: [
|
{
|
type: "graph",
|
legendHoverLink: true,
|
layout: "force",
|
symbolSize: 15,
|
data: nodeData,
|
links: links,
|
categories: this.categories,
|
roam: true,
|
label: {
|
show: true,
|
position: "right",
|
formatter: "{b}"
|
},
|
labelLayout: {
|
hideOverlap: true
|
},
|
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) {
|
if (index !== undefined) {
|
this.searchKey = "";
|
this.hotAciveIndex = index;
|
} else {
|
this.hotAciveIndex = "";
|
}
|
this.getData(val.text);
|
},
|
// 点击下面的朝代按钮
|
dynastyBottomClick(item) {
|
this.dynastyColor = item.id;
|
this.onSearch({
|
text: item.name
|
});
|
},
|
// 关系图 点击里面的元素
|
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 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>
|
#relatio {
|
width: 100%;
|
height: 100%;
|
position: relative;
|
}
|
|
.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;
|
}
|
}
|
}
|
</style>
|