home.html 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>知识图谱系统</title>
  7. <script src="./js/vue.js"></script>
  8. <link rel="stylesheet" href="./elementUI/theme-chalk/index.css">
  9. <script src="./elementUI/index.js"></script>
  10. <script src="./js/axios.js"></script>
  11. <!-- 引入 Day.js 库 -->
  12. <script src="./js/dayjs/dayjs.min.js"></script>
  13. <!-- 引入中文语言包 -->
  14. <script src="./js/dayjs/zh-cn.js"></script>
  15. <!-- 引入插件 localeData 用于获取星期几 -->
  16. <script src="./js/dayjs/localeData.js"></script>
  17. <!-- 引入jquery -->
  18. <!-- <script type="module" src="./js/home.js"></script> -->
  19. <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  20. <!-- 引入echarts -->
  21. <script src="./js/echarts.min.js"></script>
  22. <script src="https://udify.app/embed.min.js" id="H0Nrc4d1ldWJpJaJ" defer>
  23. </script>
  24. <style>
  25. /*vue未加载好使隐藏页面*/
  26. [v-cloak] {
  27. display: none;
  28. }
  29. #dify-chatbot-bubble-button {
  30. background-color: #1C64F2 !important;
  31. }
  32. #dify-chatbot-bubble-window {
  33. width: 24rem !important;
  34. height: 40rem !important;
  35. }
  36. </style>
  37. <script>
  38. window.difyChatbotConfig = {
  39. token: 'H0Nrc4d1ldWJpJaJ'
  40. }
  41. </script>
  42. </head>
  43. <body>
  44. <div id="app" v-cloak>
  45. <el-container v-cloak>
  46. <el-header>
  47. <div class="logo" contenteditable="false">知识图谱系统</div>
  48. <div class="time">{{nowDate}}</div>
  49. <div class="user-area">
  50. <span class="icon-avatar"></span>
  51. <span class="user-identity">管理员</span>
  52. <span class="icon-dropdown-down"></span>
  53. </div>
  54. </el-header>
  55. <el-container>
  56. <el-aside :width="isCollapse?'69px':'268px'">
  57. <div :class="isCollapse? 'collapse-sign collapse-sign-open': 'collapse-sign collapse-sign-close'"
  58. @click="isCollapse=!isCollapse"></div>
  59. <el-menu :default-active="currentPage.id" :collapse-transition="false" :collapse="isCollapse"
  60. background-color="#D5E9FE" text-color="#000000" active-text-color="#FFFFFF">
  61. <el-submenu v-for="menu in menuData" :key="menu.id" :index="menu.id">
  62. <template slot="title">
  63. <i class="menu-label"><img :src="menu.label" alt="图标"></i>
  64. <span class="menu-title-text">{{menu.title}}</span>
  65. </template>
  66. <el-menu-item v-for="i in menu.children" @click="menuSelect(i)" class="submenu" :key="i.id" :index="i.id">
  67. <span class="submenu-text">{{i.title}}</span>
  68. </el-menu-item>
  69. </el-submenu>
  70. </el-menu>
  71. </el-aside>
  72. <el-main>
  73. <div class="tags">
  74. <el-tabs v-model="editableTabsValue" @tab-click="tabClick" type="card" :editable="false">
  75. <el-tab-pane :key="item.name" v-for="(item, index) in editableTabs" :closable="false" :label="item.title"
  76. :name="item.name">
  77. <span slot="label">
  78. {{item.title}}
  79. <i :class="item.name==currentPage.id?'icon-close-blue':'icon-close-gray'"
  80. @click.stop="removeTab(index)"></i>
  81. </span>
  82. </el-tab-pane>
  83. </el-tabs>
  84. <div class="padding"></div>
  85. </div>
  86. <div class="content">
  87. <iframe ref="iframe" v-show="currentPage.url" :src="currentPage.url" frameborder="0"></iframe>
  88. <el-empty v-show="!currentPage.url" description="这里什么都没有"></el-empty>
  89. </div>
  90. </el-main>
  91. </el-container>
  92. </el-container>
  93. <!-- 对话框 -->
  94. <el-dialog :title="dialogData.title" :visible.sync="dialogVisible" ref="dialogRef"
  95. :width="dialogData.width?dialogData.width:'686px'" height="491px" :center="false" :close-on-click-modal="false">
  96. <template #default>
  97. <div v-if="dialogData.opType=='addEntity'" class="addEntity">
  98. <div class="tools">
  99. <span>导出模板</span>
  100. <span>导入</span>
  101. <span @click="addEntityAddRow" class="add-row add-row"><span class="icon-add"></span>新增行</span>
  102. </div>
  103. <div class="content">
  104. <el-table border :data="tableData" style="width: 100%" height="230">
  105. <el-table-column type="index" label="序号" width="73"></el-table-column>
  106. <el-table-column prop="name" label="实体名称">
  107. <template slot-scope="scope">
  108. <el-input type="text" v-model="tableData[scope.$index].name" placeholder="请输入实体名称">
  109. </template>
  110. </el-table-column>
  111. <el-table-column prop="label" label="实体类型" width="152">
  112. <template slot-scope="scope">
  113. <el-select v-model="tableData[scope.$index].label" placeholder="请选择">
  114. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  115. </el-option>
  116. </el-select>
  117. </template>
  118. </el-table-column>
  119. <el-table-column label="操作" width="103">
  120. <template slot-scope="scope">
  121. <el-button @click.native.prevent="deleteRow(scope.$index,tableData)" type="text" size="small">
  122. 删除
  123. </el-button>
  124. </template>
  125. </el-table-column>
  126. </el-table>
  127. </div>
  128. </div>
  129. <div v-if="dialogData.opType=='modifyEntityName-dropdown'" class="modifyEntityName-dropdown">
  130. <div class="tools">
  131. <el-select v-model="selectedName" placeholder="请选择">
  132. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  133. </el-option>
  134. </el-select>
  135. <el-input v-model="searchInp" placeholder="请输入实体名称"></el-input>
  136. <el-button type="primary" @click="getNode">搜索</el-button>
  137. </div>
  138. <div class="content">
  139. <el-table border :data="nodeTable" style="width: 100%" height="230">
  140. <el-table-column type="index" label="序号" width="73"></el-table-column>
  141. <el-table-column prop="oldName" label="原实体名称"></el-table-column>
  142. <el-table-column prop="name" label="实体名称" width="152">
  143. <template slot-scope="scope">
  144. <el-input type="text" v-model="scope.row.name" placeholder="请输入实体名称">
  145. </template>
  146. </el-table-column>
  147. <el-table-column prop="type" label="实体类型"></el-table-column>
  148. <el-table-column label="操作" width="103">
  149. <template slot-scope="scope">
  150. <el-button @click.native.prevent="updateEntityName([scope.row],scope.$index)" type="text"
  151. size="small">
  152. 确认
  153. </el-button>
  154. <el-button @click.native.prevent="deleteRow(scope.$index,nodeTable)" type="text" size="small">
  155. 删除
  156. </el-button>
  157. </template>
  158. </el-table-column>
  159. </el-table>
  160. </div>
  161. </div>
  162. <!-- 下拉框删除实体 -->
  163. <div v-if="dialogData.opType=='deleteEntity-dropdown'" class="modifyEntityName-dropdown">
  164. <div class="tools">
  165. <el-select v-model="selectedName" placeholder="请选择">
  166. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  167. </el-option>
  168. </el-select>
  169. <el-input v-model.trim="searchInp" placeholder="请输入实体名称"></el-input>
  170. <el-button type="primary" @click="getNode">搜索</el-button>
  171. </div>
  172. <div class="content">
  173. <el-table border :data="nodeTable" style="width: 100%" height="230">
  174. <el-table-column type="index" label="序号" width="73"></el-table-column>
  175. <el-table-column prop="oldName" label="实体名称"></el-table-column>
  176. <el-table-column label="操作" width="160">
  177. <template slot-scope="scope">
  178. <el-button @click.native.prevent="deleteEntityFunc([scope.row.nodeId],scope.$index)" type="text"
  179. size="small">
  180. 删除
  181. </el-button>
  182. </template>
  183. </el-table-column>
  184. </el-table>
  185. </div>
  186. </div>
  187. <!-- 下拉新增关系 -->
  188. <div v-if="dialogData.opType=='addRelationship-dropdown'" class="addEntity">
  189. <div class="tools">
  190. <span>导出模板</span>
  191. <span>导入</span>
  192. <span @click="addRelationshipDropdownAddRow" class="add-row"><span class="icon-add"></span>新增行</span>
  193. </div>
  194. <div class="content">
  195. <el-table border :data="addRelationshipDropdown" style="width: 100%" height="250">
  196. <el-table-column type="index" label="序号" width="70"></el-table-column>
  197. <el-table-column label="起始实体类型">
  198. <template slot-scope="scope">
  199. <el-select v-model="scope.row.startLabel" placeholder="请选择">
  200. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  201. </el-option>
  202. </el-select>
  203. </template>
  204. </el-table-column>
  205. <el-table-column prop="startName" label="起始实体名称" width="150">
  206. <template slot-scope="scope">
  207. <el-autocomplete v-model.trim="scope.row.startName"
  208. :fetch-suggestions="(queryString,cb)=>{querySearchAsync(queryString,cb,scope.row.startLabel)}"
  209. @select="handleSelect($event, scope.row,'start')" placeholder="请选择起始实体"
  210. :popper-append-to-body="false"></el-autocomplete>
  211. </template>
  212. </el-table-column>
  213. <el-table-column label="目标实体类型">
  214. <template slot-scope="scope">
  215. <el-select v-model="scope.row.endLabel" placeholder="请选择">
  216. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  217. </el-option>
  218. </el-select>
  219. </template>
  220. </el-table-column>
  221. <el-table-column prop="endName" label="目标实体名称" width="150">
  222. <template slot-scope="scope">
  223. <el-autocomplete v-model.trim="scope.row.endName" placeholder="请选择起目标实体"
  224. :fetch-suggestions="((queryString,cb)=>{querySearchAsync(queryString,cb,scope.row.endLabel)})"
  225. @select="handleSelect($event, scope.row,'end')"></el-autocomplete>
  226. </template>
  227. </el-table-column>
  228. <el-table-column prop="relationshipType" width="170" label="关系名称">
  229. <template slot-scope="scope">
  230. <el-input type="text" v-model="scope.row.relationshipType" placeholder="请输入关系(边)名称">
  231. </template>
  232. </el-table-column>
  233. <el-table-column label="操作" width="100">
  234. <template slot-scope="scope">
  235. <el-button @click.native.prevent="deleteRow(scope.$index,addRelationshipDropdown)" type="text"
  236. size="small">
  237. 删除
  238. </el-button>
  239. </template>
  240. </el-table-column>
  241. </el-table>
  242. </div>
  243. </div>
  244. <div v-if="dialogData.opType=='modifyRelationshipName-dropdown'" class="modifyEntityName-dropdown">
  245. <div class="tools">
  246. <el-input v-model.trim="searchRelationshipName" placeholder="请输入关系名称"></el-input>
  247. <el-button type="primary" @click="findRelationshipType">搜索</el-button>
  248. </div>
  249. <div class="content">
  250. <el-table border :data="modifyRelationshipNameDropdown" style="width: 100%" height="230">
  251. <el-table-column type="index" label="序号" width="73"></el-table-column>
  252. <el-table-column prop="oldRelationshipType" label="原关系名称"></el-table-column>
  253. <el-table-column prop="newRelationshipType" label="修改为">
  254. <template slot-scope="scope">
  255. <el-input type="text" v-model="scope.row.newRelationshipType" placeholder="请输入关系名称">
  256. </template>
  257. </el-table-column>
  258. <el-table-column label="操作" width="103">
  259. <template slot-scope="scope">
  260. <el-button @click.native.prevent="updateRelationshipType(modifyRelationshipNameDropdown,scope.$index)"
  261. type="text" size="small">
  262. 确认
  263. </el-button>
  264. </template>
  265. </el-table-column>
  266. </el-table>
  267. </div>
  268. </div>
  269. <!-- 下拉属性新增 -->
  270. <div v-if="dialogData.opType=='addProperty-dropdown'" class="modifyEntityName-dropdown">
  271. <div class="tools-2">
  272. <div class="tools-2-up">
  273. <div class="left">
  274. <span>实体类型:</span>
  275. <el-select v-model="addPropertyDropdown.label" placeholder="请选择">
  276. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  277. </el-option>
  278. </el-select>
  279. <span style="margin-left: 10px;">实体名称:</span>
  280. <!-- <el-autocomplete v-model.trim="addPropertyDropdown.name"
  281. :fetch-suggestions="((queryString,cb)=>{querySearchAsync(queryString,cb,addPropertyDropdown.label)})"
  282. @select="handleSelect($event,addPropertyDropdown,'addProperty-dropdown')"
  283. placeholder="请输入实体名称"></el-autocomplete> -->
  284. <el-select class="select-entity-name" v-model.trim="addPropertyDropdown.nodeId" filterable remote
  285. placeholder="请输入实体名称" @change="addPropertyDropdownValueChange"
  286. :remote-method="((query)=>addPropertyDropdownRemoteMethod(query,addPropertyDropdown.label))"
  287. :loading="false">
  288. <el-option v-for="item in addPropertyDropdownOptions" :key="item.nodeId" :label="item.name"
  289. :value="item.nodeId">
  290. </el-option>
  291. </el-select>
  292. </div>
  293. <div class="right">
  294. <span class="blue">导出模板</span>
  295. <span class="blue">导出</span>
  296. <span @click="addPropertyDropdownAddRow()" class="blue add-row"><span class="icon-add"></span>新增行</span>
  297. </div>
  298. </div>
  299. <div class="tools-2-down"> <span>请添加实体:<span class="blue">{{addPropertyDropdown.name}}</span> 相关的属性值</span>
  300. </div>
  301. </div>
  302. <div class="content">
  303. <el-table border :data="addPropertyDropdown.property" style="width: 100%" height="230">
  304. <el-table-column type="index" label="序号" width="73"></el-table-column>
  305. <el-table-column prop="key" label="属性名称">
  306. <template slot-scope="scope">
  307. <el-input type="text" v-model="scope.row.key" placeholder="请输入属性名称">
  308. </template>
  309. </el-table-column>
  310. <el-table-column prop="value" label="属性值">
  311. <template slot-scope="scope">
  312. <el-input type="text" v-model="scope.row.value" placeholder="请输入关系名称">
  313. </template>
  314. </el-table-column>
  315. <el-table-column label="操作" width="103">
  316. <template slot-scope="scope">
  317. <el-button @click.native.prevent="deleteRow(scope.$index,addPropertyDropdown.property)" type="text"
  318. size="small">
  319. 删除
  320. </el-button>
  321. </template>
  322. </el-table-column>
  323. </el-table>
  324. </div>
  325. </div>
  326. <!-- 右键属性新增 -->
  327. <div v-if="dialogData.opType=='addProperty'" class="modifyEntityName-dropdown">
  328. <div class="tools-2">
  329. <div class="tools-2-up">
  330. <div class="left">
  331. <span>实体名称:{{addProperty.name}}</span>
  332. </div>
  333. <div class="right">
  334. <span @click="addPropertyAddRow()" class="blue add-row"><span class="icon-add"></span>新增行</span>
  335. </div>
  336. </div>
  337. <div class="tools-2-down"></div>
  338. </div>
  339. <div class="content">
  340. <el-table border :data="addProperty.property" style="width: 100%" height="230">
  341. <el-table-column type="index" label="序号" width="73"></el-table-column>
  342. <el-table-column prop="key" label="属性名称">
  343. <template slot-scope="scope">
  344. <el-input type="text" v-model="scope.row.key" placeholder="请输入属性名称">
  345. </template>
  346. </el-table-column>
  347. <el-table-column prop="value" label="属性值">
  348. <template slot-scope="scope">
  349. <el-input type="text" v-model="scope.row.value" placeholder="请输入关系名称">
  350. </template>
  351. </el-table-column>
  352. <el-table-column label="操作" width="103">
  353. <template slot-scope="scope">
  354. <el-button @click.native.prevent="deleteRow(scope.$index,addProperty.property)" type="text"
  355. size="small">
  356. 删除
  357. </el-button>
  358. </template>
  359. </el-table-column>
  360. </el-table>
  361. </div>
  362. </div>
  363. <!-- 删除关系 -->
  364. <div v-if="dialogData.opType=='deleteRelationship'" class="deleteRelationship">
  365. <div class="content">
  366. 是否确认删除{{deleteRelationship.startName}}(起始节点)→{{deleteRelationship.endName}}(目标节点)之间的关系:{{deleteRelationship.relationshipType}}
  367. ?
  368. </div>
  369. </div>
  370. <!-- 修改关系 -->
  371. <div v-if="dialogData.opType=='modifyRelationship'" class="modifyRelationship">
  372. <div class="content">
  373. <div class="up">原关系名称:{{modifyRelationship.oldVal}}</div>
  374. <div class="down">修改为:<el-input v-model.trim="modifyRelationship.newVal"></el-input></div>
  375. </div>
  376. </div>
  377. <!-- 修改关系实体名称-右键 -->
  378. <div v-if="dialogData.opType=='modifyEntityName'" class="modifyEntityName">
  379. <div class="content">
  380. <div class="up">原实体名称:{{modifyEntityName.oldName}}</div>
  381. <div class="center">实体名称:<el-input v-model.trim="modifyEntityName.name"></el-input></div>
  382. <div class="down">实体类型:
  383. <el-select v-model="modifyEntityName.label" placeholder="请选择">
  384. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  385. </el-option>
  386. </el-select>
  387. </div>
  388. </div>
  389. </div>
  390. <!-- 右键删除实体 -->
  391. <div v-if="dialogData.opType=='deleteEntity'" class="deleteRelationship">
  392. <div class="content">
  393. 删除实体节点提交保存后会将数据库中节点所有一层以内的关系及属性一同删除。是否确认删除实体-{{deleteEntity.name}} ?
  394. </div>
  395. </div>
  396. <!-- 右键删除实体属性 -->
  397. <div v-if="dialogData.opType=='deleteProperty'" class="deleteRelationship">
  398. <div class="content">
  399. 是否确认删除实体{{deleteProperty.name}}的属性-{{deleteProperty.propertyName}} ?
  400. </div>
  401. </div>
  402. <!-- //右键新增关系-->
  403. <div v-if="dialogData.opType=='addRelationship'" class="modifyEntityName">
  404. <div class="content">
  405. <div class="up">起始实体名称:{{addRelationship.startName}}</div>
  406. <div class="center">
  407. 目标实体类型:<el-select v-model="addRelationship.endLabel" placeholder="请选择">
  408. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  409. </el-option>
  410. </el-select>
  411. </div>
  412. <div class="center">
  413. 目标实体名称: <el-autocomplete v-model.trim="addRelationship.endName"
  414. :fetch-suggestions="((queryString,cb)=>{querySearchAsync(queryString,cb,addRelationship.endLabel)})"
  415. @select="handleSelect($event, addRelationship,'addRelationship')"
  416. placeholder="请输入实体名称"></el-autocomplete>
  417. </div>
  418. <div class="down">关系名称:<el-input v-model.trim="addRelationship.relationshipType"
  419. placeholder="请输入关系名称"></el-input>
  420. </div>
  421. </div>
  422. </div>
  423. <div v-if="dialogData.opType=='modifyProperty-dropdown'" class="modifyProperty-dropdown">
  424. <div class="tools">
  425. <el-select v-model="modifyPropertyDropdown.label" placeholder="请选择">
  426. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
  427. </el-option>
  428. </el-select>
  429. <el-autocomplete v-model="modifyPropertyDropdown.name" :fetch-suggestions="querySearchAsync2"
  430. @select="handleSelect($event, modifyPropertyDropdown.properties,'modifyProperty-dropdown')"
  431. placeholder="请输入实体名称">
  432. </el-autocomplete>
  433. </div>
  434. <div class="content">
  435. <el-table border :data="modifyPropertyDropdown.properties" style="width: 100%" height="230">
  436. <el-table-column type="index" label="序号" width="73"></el-table-column>
  437. <el-table-column label="原属性名称" prop="oldPropertyName"></el-table-column>
  438. <el-table-column prop="key" label="属性名称" width="130">
  439. <template slot-scope="scope">
  440. <el-input type="text" v-model="scope.row.newPropertyName" placeholder="请输入属性名称">
  441. </template>
  442. </el-table-column>
  443. <el-table-column label="原属性值" prop="oldPropertyValue"></el-table-column>
  444. <el-table-column prop="value" label="属性值">
  445. <template slot-scope="scope">
  446. <el-input type="text" v-model="scope.row.newPropertyValue" placeholder="请输入属性值">
  447. </template>
  448. </el-table-column>
  449. <el-table-column label="操作" width="103">
  450. <template slot-scope="scope">
  451. <el-button
  452. @click.native.prevent="modifyPropertyDropdownConfirm(scope.$index,modifyPropertyDropdown.properties)"
  453. type="text" size="small">
  454. 确定
  455. </el-button>
  456. </template>
  457. </el-table-column>
  458. </el-table>
  459. </div>
  460. </div>
  461. <!-- 右键修改实体属性 -->
  462. <div v-if="dialogData.opType=='modifyProperty'" class="modifyEntityName">
  463. <div class="content">
  464. <div class="up">
  465. <span>原属性名称:{{modifyProperty.oldPropertyName}}</span>
  466. <span>原属性值:{{modifyProperty.oldPropertyValue}}</span>
  467. </div>
  468. <div class="center">
  469. 属性名称:<el-input v-model.trim="modifyProperty.newPropertyName" placeholder="请输入属性名称"></el-input>
  470. 属性值:<el-input v-model.trim="modifyProperty.newPropertyValue" placeholder="请输入属性值"></el-input>
  471. </div>
  472. <!-- <div class="down">
  473. 属性类型:<el-input v-model.trim="addRelationship.relationshipType"
  474. placeholder="请输入关系名称"></el-input>
  475. </div> -->
  476. </div>
  477. </div>
  478. <div v-if="dialogData.opType=='merge-entity'" class="merge-entity">
  479. <div class="content">
  480. <div class="text">
  481. 确认实体-{{mergeEntity.firstName}}、实体-{{mergeEntity.secondName}}是否需要合并,合并后实体的关系及属性一同合并。
  482. </div>
  483. <div class="input">
  484. 合并后的名称:<el-input v-model.trim="mergeEntity.newName" placeholder="请输入实体名称"></el-input>
  485. </div>
  486. </div>
  487. </div>
  488. <div v-show="dialogData.opType==='entityLink'" class="entityLink" id="entityLink">
  489. </div>
  490. </template>
  491. <span slot="footer" class="dialog-footer" v-show="dialogData.showFooter">
  492. <el-button @click="dialogVisible = false" class="cancel">取 消</el-button>
  493. <el-button type="primary" @click="dialogSubmit" class="confirm">确 定</el-button>
  494. </span>
  495. </el-dialog>
  496. </div>
  497. </body>
  498. <script>
  499. let myChart = null
  500. let timer = null //计时器标志
  501. const api = {
  502. createEntity: "/entity/createEntity",//批量新增实体
  503. getNode: "/kg/getNode",
  504. updateEntityName: "/entity/updateEntityName",
  505. deleteEntity: "/entity/deleteEntity",
  506. createRelationship: "/relationship/createRelationship",
  507. findRelationshipType: "/relationship/findRelationshipType", //根据名称模糊查询关系
  508. updateRelationshipType: "/relationship/updateRelationshipType",
  509. createEntityProperty: "/property/createEntityProperty", //批量新增实体属性
  510. deleteRelationship: "/relationship/deleteRelationship",//批量删除关系
  511. findEntityListByName: "/entity/findEntityListByName", //实体列表查询(根据标签和名字模糊查询实体)
  512. updateEntityProperty: "/property/updateEntityProperty", //更新实体属性
  513. deleteEntityProperty: "/property/deleteEntityProperty", //删除实体属性
  514. mergeEntity: "/entity/mergeEntity",//实体合并
  515. }
  516. const vm = new Vue({
  517. el: "#app",
  518. name: "home",
  519. data() {
  520. return {
  521. mergeEntity: { //实体合并的数据
  522. "firstId": -1,
  523. "firstLabel": "",
  524. "firstName": "",
  525. "newLabel": "",
  526. "newName": "",
  527. "secondId": -1,
  528. "secondLabel": "",
  529. "secondName": ""
  530. },
  531. dialogVisible: false,
  532. dialogData: { title: "提示", opType: "", showFooter: true, width: "" },
  533. modifyProperty: { //右键修改属性
  534. "label": "",
  535. "newPropertyName": "",
  536. "newPropertyValue": "",
  537. "nodeId": -1,
  538. "oldPropertyName": "",
  539. "oldPropertyValue": "",
  540. },
  541. modifyPropertyDropdown: { //下拉框修改属性
  542. name: "",
  543. label: "疾病",
  544. properties: []
  545. },
  546. deleteProperty: {//右键删除属性
  547. "label": "",
  548. "nodeId": -1,
  549. "name": "",
  550. "propertyName": ""
  551. },
  552. addRelationship: {//右键新增关系
  553. "endId": null,
  554. "endLabel": "疾病",
  555. "endName": "",
  556. "property": {},
  557. "relationshipType": "",
  558. "startId": null,
  559. "startLabel": "",
  560. "startName": ""
  561. },
  562. modifyEntityName: { // 修改关系实体名称-右键 的值
  563. "oldName": "",
  564. "name": "",
  565. "nodeId": -1,
  566. "label": "",
  567. },
  568. deleteEntity: { name: "", nodeId: "" },//右键删除实体
  569. deleteRelationship: {
  570. "endId": null,
  571. "endLabel": "",
  572. "endName": "",
  573. "property": {},
  574. "relationshipType": "",
  575. "startId": null,
  576. "startLabel": "",
  577. "startName": "",
  578. },
  579. entityLink: { //实体链接数据
  580. nodes: [],
  581. links: []
  582. },
  583. modifyRelationship: { oldVal: "", newVal: "" },//右键修改关系名称
  584. tableData: [
  585. { "label": "疾病", "name": "" }
  586. ],
  587. options: [
  588. { "label": "疾病", "value": "疾病" },
  589. { "label": "药品", "value": "药品" },
  590. { "label": "症状", "value": "症状" },
  591. // { "label": "手术和操作", "value": "手术和操作" },
  592. { "label": "实验室检查", "value": "实验室检查" },
  593. { "label": "辅助检查", "value": "辅助检查" },
  594. ],
  595. addPropertyDropdown: {
  596. "label": "疾病",
  597. "nodeId": null,
  598. "name": "",
  599. "property": [{ key: "", value: "" }]
  600. },
  601. addPropertyDropdownOptions: [],
  602. addProperty: { //右键属性新增的数据
  603. "label": "",
  604. "nodeId": -1,
  605. "name": "",
  606. "property": [{ key: "", value: "" }]
  607. },
  608. addRelationshipDropdown: [{ //下拉框添加关系
  609. "endId": null,
  610. "endName": "",
  611. "endLabel": "疾病",
  612. "property": {},
  613. "relationshipType": "",
  614. "startId": null,
  615. "startName": "",
  616. "startLabel": "疾病"
  617. }],
  618. modifyRelationshipNameDropdown: [],//下拉框的修改关系名称
  619. searchRelationshipName: "",
  620. selectedName: "",
  621. searchInp: "",
  622. nodeTable: [],
  623. nowDate: "", //当前的日期时间
  624. isCollapse: false,
  625. editableTabsValue: 'knowledgeGraph',
  626. editableTabs: [
  627. {
  628. title: '知识图谱查询',
  629. name: 'knowledgeGraph',
  630. content: './knowledgeGraph.html'
  631. },
  632. ],
  633. currentPage: {
  634. id: "knowledgeGraph",
  635. url: "./knowledgeGraph.html",
  636. title: "知识图谱查询",
  637. children: null
  638. },
  639. menuData: [
  640. {
  641. id: "1",
  642. url: "",
  643. title: "知识图谱查询",
  644. label: "/images/layer8@2x.png",
  645. children: [
  646. {
  647. id: "knowledgeGraph",
  648. url: "./knowledgeGraph.html",
  649. title: "知识图谱查询",
  650. children: null
  651. }
  652. ]
  653. },
  654. {
  655. id: "2",
  656. url: "",
  657. title: "图谱知识管理",
  658. label: "./images/layer9@2x.png",
  659. children: [
  660. {
  661. id: "knowledgeUpdate",
  662. url: "./knowledgeUpdate.html",
  663. title: "知识更新",
  664. children: null
  665. }
  666. ]
  667. },
  668. {
  669. id: "3",
  670. url: "",
  671. title: "系统管理",
  672. label: "./images/layer10@2x.png",
  673. children: [
  674. {
  675. id: "userManage",
  676. url: "",
  677. title: "用户管理",
  678. children: null
  679. },
  680. {
  681. id: "permissionManage",
  682. url: "",
  683. title: "权限管理",
  684. children: null
  685. }
  686. ]
  687. },
  688. {
  689. id: "4",
  690. url: "",
  691. title: "统计分析",
  692. label: "./images/layer11@2x.png",
  693. children: [
  694. {
  695. id: "graphDataStatistics",
  696. url: "./graphDataStatistics.html",
  697. title: "图谱数据统计",
  698. children: null
  699. },
  700. {
  701. id: "operationLog",
  702. url: "",
  703. title: "操作日志",
  704. children: null
  705. },
  706. ]
  707. },
  708. ]
  709. }
  710. },
  711. methods: {
  712. menuSelect: function (item) {
  713. this.currentPage = { ...item }
  714. const { id, title, url } = item
  715. this.editableTabsValue = id
  716. const isExist = this.editableTabs.some((el) => {
  717. if (el.name == id) return true;
  718. })
  719. if (!isExist) {
  720. this.editableTabs.push({
  721. name: id,
  722. title: title,
  723. content: url,
  724. })
  725. }
  726. },
  727. removeTab(tabIndex) {
  728. //console.log("removeTab", tabIndex)
  729. //判断删除的是否是当前页面
  730. const isActiveTab = this.editableTabs[tabIndex].name === this.editableTabsValue
  731. this.editableTabs.splice(tabIndex, 1)//删除当前tab页
  732. if (this.editableTabs.length === 0) {
  733. this.currentPage = {}
  734. return;
  735. }
  736. if (!isActiveTab) return; //不是当前页面直接结束
  737. if (tabIndex > 0) {
  738. const { title, name, content } = this.editableTabs[tabIndex - 1]
  739. this.currentPage.id = name
  740. this.currentPage.title = title
  741. this.currentPage.url = content
  742. this.editableTabsValue = name
  743. } else {
  744. const { title, name, content } = this.editableTabs[0]
  745. this.currentPage.id = name
  746. this.currentPage.title = title
  747. this.currentPage.url = content
  748. this.editableTabsValue = name
  749. }
  750. },
  751. tabClick(tabElement) {
  752. //console.log("tabClick", tabElement)
  753. const index = tabElement.index
  754. const { title, name, content } = this.editableTabs[index]
  755. this.currentPage.id = name
  756. this.currentPage.title = title
  757. this.currentPage.url = content
  758. this.editableTabsValue = name
  759. },
  760. getNowDate() {
  761. // 获取当前时间并格式化为 2024年12月10日/星期二/15:23 的格式
  762. const formattedDate = dayjs().format('YYYY年MM月DD日/星期dd/HH:mm');
  763. return formattedDate
  764. },
  765. sendChildWindowMessage: function (operation, data) {
  766. const iframe = this.$refs.iframe
  767. if (operation == "update-graph") {
  768. setTimeout(() => {
  769. iframe.contentWindow.postMessage({ operation, data }, "*")
  770. }, 1000)
  771. } else {
  772. iframe.contentWindow.postMessage({ operation, data }, "*")
  773. }
  774. },
  775. receiveIframeMsg() {
  776. const iframe = this.$refs.iframe
  777. window.addEventListener("message", (event) => {
  778. //console.log("receiveIframeMsg", event)
  779. const { opType } = event.data
  780. if (opType) {
  781. this.dialogData.title = event.data.title
  782. this.dialogData.opType = opType
  783. this.dialogData.showFooter = event.data.showFooter
  784. this.dialogData.width = event.data.width
  785. this.dialogVisible = event.data.dialogVisible
  786. if (opType == 'modifyEntityName-dropdown') {
  787. this.selectedName = event.data.data.selectedName
  788. this.searchInp = event.data.data.searchInp
  789. } else if (opType == 'deleteEntity-dropdown') {
  790. this.selectedName = event.data.data.selectedName
  791. this.searchInp = event.data.data.searchInp
  792. } else if (opType == 'deleteRelationship') {
  793. this.deleteRelationship = event.data.data
  794. } else if (opType == "modifyRelationship") {//右键修改关系名称
  795. this.modifyRelationship.oldVal = event.data.data.relationshipType
  796. } else if (opType == "modifyEntityName") { //右键修改实体名称
  797. this.modifyEntityName.oldName = event.data.data.properties.name
  798. this.modifyEntityName.nodeId = event.data.data.nodeId
  799. this.modifyEntityName.label = event.data.data.type
  800. } else if (opType == "deleteEntity") { //右键删除实体
  801. this.deleteEntity.name = event.data.data.properties.name
  802. this.deleteEntity.nodeId = event.data.data.nodeId
  803. } else if (opType == 'addRelationship') { //右键新增关系
  804. this.addRelationship.startId = event.data.data.nodeId
  805. this.addRelationship.startName = event.data.data.properties.name
  806. this.addRelationship.startLabel = event.data.data.type
  807. } else if (opType == 'addProperty') { //右键新增属性
  808. this.addProperty.nodeId = event.data.data.nodeId
  809. this.addProperty.name = event.data.data.properties.name
  810. this.addProperty.label = event.data.data.type
  811. } else if (opType == 'deleteProperty') { //右键删除属性
  812. this.deleteProperty.nodeId = event.data.data.nodeId
  813. this.deleteProperty.label = event.data.data.type
  814. this.deleteProperty.name = event.data.data.properties.parentName
  815. this.deleteProperty.propertyName = event.data.data.properties.name
  816. } else if (opType === 'modifyProperty') { //右键修改属性
  817. this.modifyProperty.label = event.data.data.type
  818. this.modifyProperty.oldPropertyName = event.data.data.properties.name
  819. this.modifyProperty.oldPropertyValue = event.data.data.properties.value
  820. this.modifyProperty.nodeId = event.data.data.nodeId
  821. } else if (opType === 'merge-entity') { //实体合并
  822. this.mergeEntity = { ...event.data.data }
  823. } else if (opType == 'entityLink') { //实体链接
  824. this.entityLink = { ...this.$options.data().entityLink }
  825. this.entityLink.categories = event.data.data.categories
  826. event.data.data.entityNode.forEach((el, index) => {
  827. el.name = index
  828. el.symbolSize = 80
  829. el.symbol = 'circle'
  830. el.itemStyle = {}
  831. this.entityLink.nodes.push(el)
  832. })
  833. this.$nextTick(() => {
  834. this.drawGraph()
  835. })
  836. } else if (opType == "addRelationship-dropdown") {
  837. this.dialogData.width = '900px'
  838. } else if (opType == "addProperty-dropdown") {
  839. this.dialogData.width = '800px'
  840. }
  841. }
  842. })
  843. },
  844. addEntityAddRow() {
  845. this.tableData.push({ "label": "疾病", "name": "" })
  846. },
  847. deleteRow(index, tableData) {
  848. tableData.splice(index, 1)
  849. },
  850. dialogSubmit() {
  851. switch (this.dialogData.opType) {
  852. case "addEntity":
  853. axios.post("/api" + api.createEntity, this.tableData).then((res) => {
  854. //console.log("createEntity", res.data)
  855. if (res.data.code == '0') {
  856. //重置this.tableData的数据
  857. this.tableData = [...this.$options.data().tableData]
  858. this.dialogVisible = false
  859. this.sendChildWindowMessage("update-graph", "")
  860. }
  861. }).catch(err => {
  862. console.log("createEntity接口出错", err)
  863. })
  864. break
  865. case "modifyEntityName-dropdown":
  866. this.updateEntityName(this.nodeTable, -1)
  867. break
  868. case "addRelationship-dropdown":
  869. axios.post("/api" + api.createRelationship, this.addRelationshipDropdown).then(res => {
  870. const { msg, code, data } = res.data
  871. if (res.data.code == '0') {
  872. this.addRelationshipDropdown = [...this.$options.data().addRelationshipDropdown]
  873. //console.log("addRelationshipDropdown", this.$options.data().addRelationshipDropdown)
  874. this.dialogVisible = false
  875. this.sendChildWindowMessage("update-graph", "")
  876. }
  877. }).catch(err => {
  878. console.log("createRelationship接口错误", err)
  879. })
  880. break
  881. case 'addProperty-dropdown':
  882. const data = [
  883. {
  884. "label": "string",
  885. "nodeId": 0,
  886. "property": {}
  887. }
  888. ]
  889. data[0].label = this.addPropertyDropdown.label
  890. data[0].nodeId = this.addPropertyDropdown.nodeId
  891. this.addPropertyDropdown.property.forEach(el => {
  892. data[0].property[el.key] = el.value
  893. })
  894. axios.post("/api" + api.createEntityProperty, data).then(res => {
  895. const { msg, code, data } = res.data
  896. if (res.data.code == '0') {
  897. //this.addPropertyDropdown.property = []
  898. //this.dialogVisible = false
  899. this.addPropertyDropdown = { ...this.$options.data().addPropertyDropdown }
  900. this.sendChildWindowMessage("update-graph", "")
  901. }
  902. }).catch(err => {
  903. console.log("createEntityProperty接口错误", err)
  904. })
  905. break
  906. case 'deleteRelationship': //删除关系
  907. axios.post("/api" + api.deleteRelationship, [this.deleteRelationship]).then(res => {
  908. const { msg, code, data } = res.data
  909. if (res.data.code == '0') {
  910. this.dialogVisible = false
  911. this.sendChildWindowMessage("update-graph", "")
  912. }
  913. }).catch(err => {
  914. console.log("createEntityProperty接口错误", err)
  915. })
  916. break
  917. case "modifyRelationship": //右键修改关系
  918. axios.post("/api" + api.updateRelationshipType, [{
  919. "newRelationshipType": this.modifyRelationship.newVal,
  920. "oldRelationshipType": this.modifyRelationship.oldVal
  921. }]).then(res => {
  922. const { data, msg, code } = res.data
  923. if (code == '0') {
  924. this.modifyRelationship = { ...this.$options.data().modifyRelationship }
  925. //this.tableData.splice(index, 1)
  926. this.sendChildWindowMessage("update-graph", "")
  927. this.dialogVisible = false
  928. }
  929. }).catch(err => {
  930. console.log("updateRelationshipType接口出错", err)
  931. })
  932. break
  933. case "modifyEntityName":
  934. axios.post("/api" + api.updateEntityName, [this.modifyEntityName]).then(res => {
  935. const { data, msg, code } = res.data
  936. if (code == '0') {
  937. this.dialogVisible = false
  938. this.modifyEntityName = { ...this.$options.data().modifyEntityName }
  939. this.sendChildWindowMessage("update-graph", "")
  940. }
  941. }).catch(err => {
  942. console.log("updateEntityName接口出错", err)
  943. })
  944. break
  945. case "deleteEntity":
  946. axios.post("/api" + api.deleteEntity, [this.deleteEntity.nodeId]).then(res => {
  947. const { data, msg, code } = res.data
  948. if (code == '0') {
  949. this.deleteEntity = { ...this.$options.data().deleteEntity }
  950. this.dialogVisible = false
  951. this.sendChildWindowMessage("update-graph", "")
  952. }
  953. }).catch(err => {
  954. console.log("deleteEntity接口出错", err)
  955. })
  956. break
  957. case "addRelationship": //右键新增关系
  958. axios.post("/api" + api.createRelationship, [this.addRelationship]).then(res => {
  959. const { msg, code, data } = res.data
  960. if (res.data.code == '0') {
  961. this.addRelationship = { ...this.$options.data().addRelationship }
  962. this.dialogVisible = false
  963. this.sendChildWindowMessage("update-graph", "")
  964. }
  965. }).catch(err => {
  966. console.log("createRelationship接口错误", err)
  967. })
  968. break
  969. case "addProperty":
  970. const addPropertyTemp = [
  971. {
  972. "label": "string",
  973. "nodeId": 0,
  974. "property": {}
  975. }
  976. ]
  977. addPropertyTemp[0].label = this.addProperty.label
  978. addPropertyTemp[0].nodeId = this.addProperty.nodeId
  979. this.addProperty.property.forEach(el => {
  980. addPropertyTemp[0].property[el.key] = el.value
  981. })
  982. axios.post("/api" + api.createEntityProperty, addPropertyTemp).then(res => {
  983. const { msg, code, data } = res.data
  984. if (res.data.code == '0') {
  985. this.addProperty.property = [{ kye: "", value: "" }]
  986. this.dialogVisible = false
  987. this.sendChildWindowMessage("update-graph", "")
  988. }
  989. }).catch(err => {
  990. console.log("createEntityProperty接口错误", err)
  991. })
  992. break
  993. case "deleteProperty":
  994. axios.post("/api" + api.deleteEntityProperty, [this.deleteProperty]).then(res => {
  995. const { msg, code, data } = res.data
  996. if (res.data.code == '0') {
  997. this.deleteProperty = {}
  998. this.dialogVisible = false
  999. this.sendChildWindowMessage("update-graph", "")
  1000. }
  1001. }).catch(err => {
  1002. console.log("deleteEntityProperty接口错误", err)
  1003. })
  1004. break
  1005. case "modifyProperty"://右键修改属性
  1006. axios.post("/api" + api.updateEntityProperty, this.modifyProperty).then(res => {
  1007. const { data, msg, code } = res.data
  1008. if (code == '0') {
  1009. this.dialogVisible = false
  1010. this.sendChildWindowMessage("update-graph", "")
  1011. }
  1012. }).catch(err => {
  1013. console.log("updateEntityProperty接口出错", err)
  1014. })
  1015. break
  1016. case "merge-entity":
  1017. axios.post("/api" + api.mergeEntity, this.mergeEntity).then(res => {
  1018. const { data, msg, code } = res.data
  1019. if (code == '0') {
  1020. this.dialogVisible = false
  1021. this.sendChildWindowMessage("update-graph", "")
  1022. }
  1023. }).catch(err => {
  1024. console.log("mergeEntity接口出错", err)
  1025. })
  1026. break
  1027. case "entityLink":
  1028. const relationshipList = []
  1029. this.entityLink.links.forEach((el) => {
  1030. relationshipList.push({
  1031. "endId": this.entityLink.nodes[el.target].nodeId,
  1032. "endLabel": this.entityLink.nodes[el.target].type,
  1033. "property": {},
  1034. "relationshipType": el.value,
  1035. "startId": this.entityLink.nodes[el.source].nodeId,
  1036. "startLabel": this.entityLink.nodes[el.source].type
  1037. })
  1038. })
  1039. axios.post("/api" + api.createRelationship, relationshipList).then(res => {
  1040. const { msg, code, data } = res.data
  1041. if (res.data.code == '0') {
  1042. this.dialogVisible = false
  1043. this.sendChildWindowMessage("update-graph", "")
  1044. return
  1045. }
  1046. }).catch(err => {
  1047. console.log("createRelationship接口错误", err)
  1048. })
  1049. break
  1050. default:
  1051. this.dialogVisible = false
  1052. this.sendChildWindowMessage("update-graph", "")
  1053. }
  1054. },
  1055. addPropertyDropdownValueChange(value) {
  1056. for (let i = 0; i < this.addPropertyDropdownOptions.length; i++) {
  1057. const option = this.addPropertyDropdownOptions[i]
  1058. if (option.nodeId === value) {
  1059. this.addPropertyDropdown.name = option.name
  1060. break
  1061. }
  1062. }
  1063. // this.addPropertyDropdownOptions
  1064. },
  1065. addPropertyDropdownRemoteMethod(name, label) {
  1066. axios.post("/api" + api.getNode, {
  1067. "inputStr": name,
  1068. "labelName": label
  1069. }).then(res => {
  1070. const { msg, code, data } = res.data
  1071. if (code == '0') {
  1072. this.addPropertyDropdownOptions = data
  1073. // data.forEach((el, index) => {
  1074. // this.addPropertyDropdownOptions.push(
  1075. // { oldName: el.name, name: "", nodeId: el.nodeId, type: el.label })
  1076. // })
  1077. }
  1078. }).catch(err => {
  1079. console.log("addPropertyDropdownRemoteMethod的getNode接口出错了", err)
  1080. })
  1081. },
  1082. getNode() {
  1083. axios.post("/api" + api.getNode, {
  1084. "inputStr": this.searchInp,
  1085. "labelName": this.selectedName
  1086. }).then(res => {
  1087. const { msg, code, data } = res.data
  1088. if (code == '0') {
  1089. this.nodeTable = []
  1090. data.forEach((el, index) => {
  1091. this.nodeTable.push(
  1092. { oldName: el.name, name: "", nodeId: el.nodeId, type: el.label })
  1093. })
  1094. }
  1095. }).catch(err => {
  1096. console.log("getNode接口出错了", err)
  1097. })
  1098. },
  1099. updateEntityName(data, index) {
  1100. this.$confirm("确定修改实体名称吗?", "修改实体名称提示", {
  1101. confirmButtonText: '确定',
  1102. cancelButtonText: '取消',
  1103. type: 'warning'
  1104. }).then(() => {
  1105. axios.post("/api" + api.updateEntityName, data).then(res => {
  1106. const { data, msg, code } = res.data
  1107. if (code == '0') {
  1108. if (index >= 0) {
  1109. this.nodeTable.splice(index, 1)
  1110. } else {
  1111. //this.nodeTable = []
  1112. this.nodeTable.splice(0, this.nodeTable.length)
  1113. }
  1114. this.sendChildWindowMessage("update-graph", "")
  1115. }
  1116. }).catch(err => {
  1117. console.log("updateEntityName接口出错", err)
  1118. })
  1119. }).catch(err => {
  1120. })
  1121. },
  1122. deleteEntityFunc(data, index) {
  1123. this.$confirm('确定删除该实体吗?', '删除实体提示', {
  1124. confirmButtonText: '确定',
  1125. cancelButtonText: '取消',
  1126. type: 'warning'
  1127. }).then(() => {
  1128. axios.post("/api" + api.deleteEntity, data).then(res => {
  1129. const { data, msg, code } = res.data
  1130. if (code == '0') {
  1131. if (index >= 0) {
  1132. this.nodeTable.splice(index, 1)
  1133. } else {
  1134. this.nodeTable.splice(0, this.nodeTable.length)
  1135. }
  1136. this.sendChildWindowMessage("update-graph", "")
  1137. }
  1138. }).catch(err => {
  1139. console.log("deleteEntity接口出错", err)
  1140. })
  1141. }).catch(err => {
  1142. })
  1143. },
  1144. addRelationshipDropdownAddRow() {
  1145. this.addRelationshipDropdown.push(this.$options.data().addRelationshipDropdown[0])
  1146. },
  1147. querySearchAsync(queryString, cb, label) {
  1148. //console.log("label", label)
  1149. axios.post("/api" + api.getNode, {
  1150. "inputStr": queryString,
  1151. "labelName": label || "疾病"
  1152. }).then(res => {
  1153. const { msg, code, data } = res.data
  1154. if (code == '0') {
  1155. var restaurants = []
  1156. data.forEach((el, index) => {
  1157. restaurants.push(
  1158. { value: el.name, nodeId: el.nodeId, label: el.label })
  1159. })
  1160. cb(restaurants)
  1161. }
  1162. }).catch(err => {
  1163. console.log("querySearchAsync的getNode接口出错了", err)
  1164. })
  1165. },
  1166. querySearchAsync2(query, cb) {
  1167. if (!query) {
  1168. cb([])
  1169. return
  1170. }
  1171. axios.post("/api" + api.findEntityListByName, {
  1172. "label": this.modifyPropertyDropdown.label,
  1173. "name": query
  1174. }).then(res => {
  1175. const { msg, code, data } = res.data
  1176. if (code == '0') {
  1177. var restaurants = []
  1178. data.forEach((el, index) => {
  1179. restaurants.push(
  1180. { value: el.properties.name, nodeId: el.id, label: el.labels[0], properties: el.properties })
  1181. })
  1182. cb(restaurants)
  1183. }
  1184. }).catch(err => {
  1185. console.log("findEntityListByName的getNode接口出错了", err)
  1186. })
  1187. },
  1188. handleSelect(item, row, flag) {
  1189. if (flag == 'start') {
  1190. row.startId = item.nodeId
  1191. row.startLabel = item.label
  1192. } else if (flag == 'end') {
  1193. row.endId = item.nodeId
  1194. row.endLabel = item.label
  1195. } else if (flag == 'addProperty-dropdown') { //下拉框新增属性
  1196. row.label = item.label
  1197. row.nodeId = item.nodeId
  1198. this.addPropertyDropdown.property = []
  1199. this.addPropertyDropdownAddRow()
  1200. } else if (flag == 'addRelationship') {
  1201. row.endLabel = item.label
  1202. row.endId = item.nodeId
  1203. } else if (flag == 'modifyProperty-dropdown') { //下拉修改属性
  1204. row.splice(0, row.length)
  1205. for (let i in item.properties) {
  1206. if (i == 'name' || i == 'is_deleted') continue;
  1207. const property = {
  1208. "label": item.label,
  1209. "name": item.value,
  1210. "newPropertyName": "",
  1211. "newPropertyValue": "",
  1212. "nodeId": item.nodeId,
  1213. "oldPropertyName": i,
  1214. "oldPropertyValue": item.properties[i],
  1215. }
  1216. row.push(property)
  1217. }
  1218. }
  1219. //console.log("handleSelect-2", item, row, flag);
  1220. },
  1221. findRelationshipType() {
  1222. axios.post("/api" + api.findRelationshipType, { "relationshipType": this.searchRelationshipName }).then(res => {
  1223. const { data, msg, code } = res.data
  1224. if (code === '0') {
  1225. this.modifyRelationshipNameDropdown = []
  1226. data.forEach((el, index) => {
  1227. this.modifyRelationshipNameDropdown.push({
  1228. "newRelationshipType": "",
  1229. "oldRelationshipType": el
  1230. })
  1231. })
  1232. }
  1233. }).catch(err => {
  1234. console.log("findRelationshipType接口出错了", err)
  1235. })
  1236. },
  1237. updateRelationshipType(tableData, index) {
  1238. this.$confirm('确定修改此关系名称吗?', '提示', {
  1239. confirmButtonText: '确定',
  1240. cancelButtonText: '取消',
  1241. type: 'warning'
  1242. }).then(() => {
  1243. axios.post("/api" + api.updateRelationshipType, [tableData[index]]).then(res => {
  1244. const { data, msg, code } = res.data
  1245. if (code == '0') {
  1246. tableData.splice(index, 1)
  1247. this.sendChildWindowMessage("update-graph", "")
  1248. }
  1249. }).catch(err => {
  1250. console.log("updateRelationshipType接口出错", err)
  1251. })
  1252. }).catch(() => {
  1253. });
  1254. },
  1255. addPropertyDropdownAddRow() {
  1256. this.addPropertyDropdown.property.push(this.$options.data().addPropertyDropdown.property[0])
  1257. },
  1258. addPropertyAddRow() {
  1259. this.addProperty.property.push({ key: "", value: "" })
  1260. },
  1261. modifyPropertyDropdownConfirm(index, tableData) {
  1262. this.$confirm('确定修改此属性吗?', '提示', {
  1263. confirmButtonText: '确定',
  1264. cancelButtonText: '取消',
  1265. type: 'warning'
  1266. }).then(() => {
  1267. axios.post("/api" + api.updateEntityProperty, tableData[index]).then(res => {
  1268. const { data, msg, code } = res.data
  1269. if (code == '0') {
  1270. tableData.splice(index, 1)
  1271. this.sendChildWindowMessage("update-graph", "")
  1272. }
  1273. }).catch(err => {
  1274. console.log("updateEntityProperty接口出错")
  1275. })
  1276. }).catch(() => {
  1277. });
  1278. },
  1279. drawGraph() {
  1280. if (myChart) {
  1281. myChart.dispose();
  1282. myChart = null
  1283. }
  1284. myChart = echarts.init(document.getElementById("entityLink"));
  1285. const options = {
  1286. color: ['#dd7172', '#E57373', '#0EB1EE', '#9D96F5', '#ACC68E', '#EDAA77', '#14BBB3', '#538FFF', '#1390FB', '#C7B02E',],
  1287. grid: {
  1288. containLabel: true, // 保证标签和内容在图表区域内
  1289. //top: 1000
  1290. },
  1291. tooltip: {
  1292. formatter: function (x) {
  1293. return x.data.label;
  1294. }
  1295. },
  1296. series: [{
  1297. categories: this.entityLink.categories,
  1298. type: 'graph',
  1299. layout: 'circular',
  1300. roam: 'none',
  1301. force: {
  1302. repulsion: 1000,
  1303. edgeLength: [50, 150],
  1304. layoutAnimation: true
  1305. },
  1306. //center: ['50%', '50%'],
  1307. //radius: ['30%', '50%'],
  1308. edgeSymbol: ['none', 'arrow'],
  1309. edgeSymbolSize: 10,
  1310. data: this.entityLink.nodes,
  1311. links: this.entityLink.links,
  1312. lineStyle: {
  1313. normal: {
  1314. color: 'target',
  1315. cursor: 'default',
  1316. width: 2,
  1317. curveness: 0.3 // 设置弯曲度,避免重叠
  1318. },
  1319. },
  1320. edgeLabel: {
  1321. normal: {
  1322. show: true,
  1323. formatter: function (x) {
  1324. return x.data.value; //横线关系
  1325. }
  1326. }
  1327. },
  1328. label: {
  1329. normal: {
  1330. show: true,
  1331. textStyle: {
  1332. cursor: 'pointer',
  1333. },
  1334. color: '#000', //label字体颜色
  1335. formatter: function (x) {
  1336. var tmp = x.data.label;
  1337. if (tmp.length >= 12) {
  1338. tmp = tmp.substring(0, 12);
  1339. tmp = tmp + "...";
  1340. }
  1341. return tmp;
  1342. }
  1343. }
  1344. },
  1345. }]
  1346. }
  1347. myChart.setOption(options)
  1348. var startNode = null;
  1349. myChart.on('mousedown', (params) => {
  1350. //console.log('mousedown', params)
  1351. if (params && params.dataType === 'node') {
  1352. startNode = { ...params }; // 记录开始拖动的节点
  1353. }
  1354. });
  1355. // 监听鼠标移动事件
  1356. myChart.getDom().addEventListener('mousemove', (event) => {
  1357. //console.log("mousemove-event", event)
  1358. if (startNode) {
  1359. var rect = myChart.getDom().getBoundingClientRect();
  1360. var mouseX = event.clientX - rect.left;
  1361. var mouseY = event.clientY - rect.top;
  1362. // 动态更新光标位置的线条
  1363. myChart.setOption({
  1364. graphic: [
  1365. {
  1366. type: 'line',
  1367. shape: {
  1368. x1: startNode.event.offsetX, // 节点的 x 坐标
  1369. y1: startNode.event.offsetY, // 节点的 y 坐标
  1370. x2: mouseX, // 光标的 x 坐标
  1371. y2: mouseY // 光标的 y 坐标
  1372. },
  1373. style: {
  1374. stroke: '#FF0000', // 线条颜色
  1375. lineWidth: 2 // 线条宽度
  1376. }
  1377. }
  1378. ]
  1379. }, false);
  1380. }
  1381. });
  1382. myChart.getDom().addEventListener('mouseup', (event) => {
  1383. //console.log("mouseup-event", event)
  1384. startNode = null
  1385. const option = myChart.getOption()
  1386. myChart.setOption({
  1387. graphic: [
  1388. {
  1389. style: {
  1390. lineWidth: 0 // 线条宽度
  1391. }
  1392. }
  1393. ]
  1394. }, false)
  1395. })
  1396. myChart.getDom().addEventListener('mouseleave', (event) => {
  1397. //console.log("mouseup-event", event)
  1398. startNode = null
  1399. const option = myChart.getOption()
  1400. myChart.setOption({
  1401. graphic: [
  1402. {
  1403. style: {
  1404. lineWidth: 0 // 线条宽度
  1405. }
  1406. }
  1407. ]
  1408. }, false)
  1409. })
  1410. myChart.on('dblclick', (event) => {
  1411. //console.log("dblclick", event)
  1412. if (event && event.dataType === 'edge') {
  1413. this.$prompt('输入关系名', '关系修改提示', {
  1414. confirmButtonText: '确定',
  1415. cancelButtonText: '取消',
  1416. inputValue: event.data.value,
  1417. type: 'warning'
  1418. }).then(({ value }) => {
  1419. this.entityLink.links[event.dataIndex].value = value
  1420. // 更新图表
  1421. myChart.setOption({
  1422. series: [{
  1423. type: 'graph',
  1424. links: this.entityLink.links
  1425. }]
  1426. }, false);
  1427. }).catch((err) => {
  1428. console.log("修改关系错误", err)
  1429. })
  1430. }
  1431. });
  1432. myChart.on('mouseup', (params) => {
  1433. //console.log('mouseup', params)
  1434. params.event.event.stopPropagation()
  1435. if (startNode && params && params.dataType === 'node' && params.data.nodeId !== startNode.data.nodeId) {
  1436. let isReverseLink = false //是否有相反方向的线
  1437. let isLink = false //是否存在连线
  1438. this.entityLink.links.forEach(el => {
  1439. if (el.source === params.data.name && el.target === startNode.data.name) {
  1440. isReverseLink = true
  1441. }
  1442. if (el.source === startNode.data.name && el.target === params.data.name) {
  1443. isLink = true
  1444. }
  1445. })
  1446. if (isLink) { //存在连线直接跳过
  1447. myChart.setOption({ //销毁连线
  1448. graphic: [
  1449. {
  1450. style: {
  1451. lineWidth: 0 // 线条宽度
  1452. }
  1453. }
  1454. ],
  1455. }, false);
  1456. startNode = null
  1457. return
  1458. }
  1459. this.$prompt('请输入关系', '连接关系', {
  1460. confirmButtonText: '确定',
  1461. cancelButtonText: '取消',
  1462. type: 'info'
  1463. }).then(({ value }) => {
  1464. // 创建正式的连线
  1465. //console.log("输入的关系", value)
  1466. this.entityLink.links.push({
  1467. source: startNode.data.name,
  1468. target: params.data.name,
  1469. value: value,
  1470. lineStyle: {
  1471. curveness: isReverseLink ? 0.3 : -0.3,
  1472. }
  1473. });
  1474. // 更新图表,移除临时连线
  1475. myChart.setOption({
  1476. graphic: [
  1477. {
  1478. style: {
  1479. lineWidth: 0 // 线条宽度
  1480. }
  1481. }
  1482. ],
  1483. series: [{
  1484. type: 'graph',
  1485. data: this.entityLink.nodes,
  1486. links: this.entityLink.links
  1487. }]
  1488. }, false);
  1489. }).catch((err) => {
  1490. console.log("连线报错", err)
  1491. myChart.setOption({
  1492. graphic: [
  1493. {
  1494. style: {
  1495. lineWidth: 0 // 线条宽度
  1496. }
  1497. }
  1498. ],
  1499. }, false);
  1500. }).finally(() => {
  1501. // 重置
  1502. startNode = null;
  1503. })
  1504. } else {
  1505. myChart.setOption({ //隐藏连接线
  1506. graphic: [
  1507. {
  1508. style: {
  1509. lineWidth: 0 // 线条宽度
  1510. }
  1511. }
  1512. ]
  1513. }, false)
  1514. startNode = null;
  1515. }
  1516. });
  1517. }
  1518. },
  1519. watch: {
  1520. isCollapse: {
  1521. handler(newVal, oldVal) {
  1522. setTimeout(() => {
  1523. this.sendChildWindowMessage("left-collapse", this.isCollapse)
  1524. }, 200)
  1525. }
  1526. },
  1527. "searchInp": {
  1528. handler() {
  1529. this.getNode()
  1530. }
  1531. },
  1532. "selectedName": {
  1533. handler() {
  1534. this.getNode()
  1535. }
  1536. },
  1537. searchRelationshipName(newVal) {
  1538. if (newVal) {
  1539. this.findRelationshipType()
  1540. }
  1541. },
  1542. },
  1543. computed: {
  1544. },
  1545. created() {
  1546. // 使用 day.js 插件
  1547. dayjs.extend(dayjs_plugin_localeData);
  1548. dayjs.locale('zh-cn'); // 设置为中文
  1549. timer = setInterval(() => {
  1550. this.nowDate = this.getNowDate()
  1551. }, 1000)
  1552. this.receiveIframeMsg()
  1553. },
  1554. mounted() {
  1555. //console.log("jquery", $)
  1556. },
  1557. destroyed() {
  1558. //销毁定时器
  1559. clearInterval(timer)
  1560. }
  1561. })
  1562. </script>
  1563. </html>