Browse Source

v1.0

feat: 新增专题搜索页面;
feat: 新增专题详情页面;
master
yiwei.zhi 2 years ago
parent
commit
9facb5fb52
  1. 8
      README.md
  2. 52
      mock/index.js
  3. 91
      mock/mock-server.js
  4. 682
      mock/peoplePool.js
  5. 25
      mock/utils.js
  6. 5
      package.json
  7. 7
      src/App.vue
  8. 26
      src/api/peoplePool.js
  9. BIN
      src/assets/image/3.png
  10. BIN
      src/assets/image/a1.png
  11. BIN
      src/assets/image/a2.png
  12. BIN
      src/assets/image/a3.png
  13. 23
      src/assets/image/default.svg
  14. BIN
      src/assets/image/down.png
  15. 17
      src/assets/image/down.svg
  16. 21
      src/assets/image/tag1.svg
  17. 21
      src/assets/image/tag2.svg
  18. 159
      src/components/PeoplePoolPage/basic-info.vue
  19. 4
      src/components/PeoplePoolPage/breadcrumb.vue
  20. 125
      src/components/PeoplePoolPage/detailCom.vue
  21. 459
      src/components/PeoplePoolPage/itemCard.vue
  22. 153
      src/components/PeoplePoolPage/itemGroup.vue
  23. 66
      src/components/PeoplePoolPage/nav-left.vue
  24. 336
      src/components/PeoplePoolPage/news.vue
  25. 8
      src/components/PeoplePoolPage/people-descriptive.vue
  26. 8
      src/components/PeoplePoolPage/people-lifetime.vue
  27. 208
      src/components/PeoplePoolPage/people-profile.vue
  28. 98
      src/components/PeoplePoolPage/person-information.vue
  29. 161
      src/components/PeoplePoolPage/photo-video.vue
  30. 129
      src/components/PeoplePoolPage/platform-dynamics.vue
  31. 457
      src/components/PeoplePoolPage/recommendation.vue
  32. 32
      src/components/PeoplePoolPage/relationship.vue
  33. 670
      src/components/PeoplePoolPage/search.vue
  34. 56
      src/components/PeoplePoolPage/social-analysis.vue
  35. 34
      src/components/PeoplePoolPage/tracing-point.vue
  36. 1065
      src/components/graphContainer/Graph.vue
  37. 111
      src/components/graphContainer/GraphIndex.vue
  38. 347
      src/components/graphContainer/Menu.vue
  39. 128
      src/components/graphContainer/README.md
  40. 2
      src/components/graphContainer/eventBus.js
  41. 337
      src/components/graphContainer/extend-dialog.vue
  42. 214
      src/components/graphContainer/graph/bindListener.js
  43. 641
      src/components/graphContainer/graph/common.js
  44. 66
      src/components/graphContainer/graph/dialogData.js
  45. 61
      src/components/graphContainer/graph/directive.js
  46. 24
      src/components/graphContainer/graph/elementPlugin.js
  47. 90
      src/components/graphContainer/graph/globalData.js
  48. 163
      src/components/graphContainer/graph/graph.js
  49. 639
      src/components/graphContainer/graph/menu.js
  50. 65
      src/components/graphContainer/graph/publicFunction.js
  51. 486
      src/components/graphContainer/graph/registerNodeEdge.js
  52. 148
      src/components/graphContainer/graph/request.js
  53. 46
      src/components/graphContainer/graph/snapshot.js
  54. BIN
      src/components/graphContainer/images/empty-graph.png
  55. 2
      src/components/graphContainer/images/graphSearch.svg
  56. 344
      src/components/graphContainer/search.vue
  57. 54
      src/components/graphContainer/store/menu.js
  58. 383
      src/components/graphContainer/styles/g6-contextmenu.less
  59. 35
      src/layout/components/domain.vue
  60. 27
      src/layout/index.vue
  61. 1
      src/layout/layout/appMain.vue
  62. 2
      src/layout/layout/horizontal.vue
  63. 2
      src/layout/layout/vertical.vue
  64. 10
      src/main.js
  65. 45
      src/router/index.js
  66. 3
      src/settings.js
  67. 1
      src/store/getters.js
  68. 12
      src/store/modules/app.js
  69. 103
      src/store/modules/graphAside.js
  70. 54
      src/store/modules/graphMenu.js
  71. 2
      src/store/modules/settings.js
  72. 1
      src/styles/global.less
  73. 16
      src/styles/variable.less
  74. 2
      src/styles/winbox-ui/css/black.css
  75. 2
      src/styles/winbox-ui/css/blue.css
  76. 2
      src/styles/winbox-ui/css/cyan.css
  77. 2
      src/styles/winbox-ui/css/default.css
  78. BIN
      src/styles/winbox-ui/css/iconfont.ttf
  79. BIN
      src/styles/winbox-ui/css/iconfont.woff
  80. BIN
      src/styles/winbox-ui/css/iconfont.woff2
  81. 2
      src/styles/winbox-ui/css/red.css
  82. 2
      src/styles/winbox-ui/css/white.css
  83. 34
      src/utils/common.js
  84. 1
      src/views/demo/form/index.vue
  85. 128
      src/views/detail/index.vue
  86. 70
      src/views/icons/index.vue
  87. 181
      src/views/peoplePool/detail.vue
  88. 162
      src/views/peoplePool/index.vue
  89. 3
      vue.config.js

8
README.md

@ -170,3 +170,11 @@ npm run release
```
更多信息请参考
# 更新日志
## v1.0
### feat: 新增专题搜索页面;
### feat: 新增专题详情页面;

52
mock/index.js

@ -0,0 +1,52 @@
const Mock = require('mockjs')
const { param2Obj } = require('./utils')
const peoplePool = require('./peoplePool')
const mocks = [
...peoplePool
]
function mockXHR() {
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
function XHR2ExpressReqWrap(respond) {
return function(options) {
let result = null
if (respond instanceof Function) {
const { body, type, url } = options
// https://expressjs.com/en/4x/api.html#req
result = respond({
method: type,
body: JSON.parse(body),
query: param2Obj(url)
})
} else {
result = respond
}
return Mock.mock(result)
}
}
for (const i of mocks) {
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
}
}
module.exports = {
mocks,
mockXHR
}

91
mock/mock-server.js

@ -0,0 +1,91 @@
const chokidar = require('chokidar');
const bodyParser = require('body-parser');
const chalk = require('chalk');
const path = require('path');
const Mock = require('mockjs');
const mockDir = path.join(process.cwd(), 'mock');
function registerRoutes(app) {
let mockLastIndex;
const { mocks } = require('./index.js');
const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response);
});
for (const mock of mocksForServer) {
app[mock.type](mock.url, mock.response);
mockLastIndex = app._router.stack.length;
}
const mockRoutesLength = Object.keys(mocksForServer).length;
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength
};
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes(mockDir)) {
delete require.cache[require.resolve(i)];
}
});
}
function randomInRange(min, max) {
const differ = max - min;
return Math.trunc(min + differ * Math.random());
}
// for mock server
const responseFake = (url, type, respond) => {
return {
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
type: type || 'get',
response(req, res) {
console.log('request invoke:' + req.path);
setTimeout(
() => {
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond));
},
(function () {
return randomInRange(500, 1000); // 注意最大值不能超过 request.js 中设置的最长等待时间
})()
);
}
};
};
module.exports = app => {
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
const mockRoutes = registerRoutes(app);
let mockRoutesLength = mockRoutes.mockRoutesLength;
let mockStartIndex = mockRoutes.mockStartIndex;
// watch files, hot reload mock server
chokidar.watch(mockDir, {
ignored: /mock-server/,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
try {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength);
// clear routes cache
unregisterRoutes();
const mockRoutes = registerRoutes(app);
mockRoutesLength = mockRoutes.mockRoutesLength;
mockStartIndex = mockRoutes.mockStartIndex;
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`));
} catch (error) {
console.log(chalk.redBright(error));
}
}
});
};

682
mock/peoplePool.js

@ -0,0 +1,682 @@
const Mock = require('mockjs')
const analysisFilterData = Mock.mock({
'items|3': [{
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E5%86%9B32.glk",
"简介": "张军 (1956年10月-),男,汉族,山东博兴人,中华人民共和国政治人物,副国级领导人。吉林大学法律系毕业,中国人民大学刑法学硕士,武汉大学刑法学博士。中共第十七届中央纪委委员、常委、副书记(2012年11月增选)。第十八届中央纪委委员、常委、副书记,第十九届中央委员。曾任中华人民共和国司法部副部长,最高人民法院副院长(一级大法官),中国共产党第十八届中央纪律检查委员会副书记(正部长级),中华人民共和国司法部部长,党组书记。现任中华人民共和国最高人民检察院检察长,首席大检察官。",
"手机号码": null,
"人物性格": null,
"出生地": "山东博兴",
"对华态度": null,
"活跃等级": null,
"国家地区": "中国",
"性别": "男",
"死亡日期": null,
"现任职务": "中共十九届中央委员,最高人民检察院检察长、党组书记。",
"民族": "汉族",
"所属组织": null,
"出生日期": null,
"毕业院校": "吉林大学法律系(学士)\n中国人民大学刑法学(硕士)\n武汉大学刑法学(博士)",
"name": "张军",
"id": "72860f221138d46fa16e9d6f99af9b38",
"居住地址": null,
"政党派系": "中国共产党"
},
{
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E6%98%A5%E8%B4%A414.glk",
"简介": "张春贤(1953年5月12日-),河南禹州人,中华人民共和国政治人物,副国级领导人,中共第十六、十七、十八、十九届中央委员,第十八届中央政治局委员[1][2]。曾任交通部部长、中共湖南省委书记、中共新疆维吾尔自治区党委书记,现任第十三届全国人大常委会副委员长。",
"手机号码": null,
"人物性格": null,
"出生地": "中华人民共和国河南省禹县",
"对华态度": null,
"活跃等级": null,
"国家地区": "中国",
"性别": "男",
"死亡日期": null,
"现任职务": "全国人民代表大会常务委员会副委员长",
"民族": "汉族",
"所属组织": null,
"出生日期": null,
"毕业院校": "东北重型机械学院、哈尔滨工业大学",
"name": "张春贤",
"id": "faa1329e90c205b9c7e87d9dde4ef990",
"居住地址": null,
"政党派系": "中国共产党"
},
{
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E5%8F%88%E4%BE%A029.glk",
"简介": "张又侠(1950年7月-),男,陕西渭南人,生于北京,中国人民解放军上将,副国级领导人,大专学历。中共十八届中央委员、中央军事委员会委员、原中国人民解放军总装备部部长、中央军委装备发展部原部长。2017年10月25日,当选为中共第十九届中央委员、中央政治局委员、中共中央军委副主席。2018年3月18日,当选为国家军委副主席。",
"手机号码": null,
"人物性格": null,
"出生地": "中国北京市",
"对华态度": null,
"活跃等级": null,
"国家地区": "中国",
"性别": "男",
"死亡日期": null,
"现任职务": "中央政治局委员,中共中央军事委员会副主席,中华人民共和国中央军事委员会副主席,陆军上将军衔",
"民族": "汉族",
"所属组织": null,
"出生日期": null,
"毕业院校": "中国人民解放军军事学院",
"name": "张又侠",
"id": "26ef870b0d6aa11360df494af8415b1f",
"居住地址": null,
"政党派系": "中国共产党"
}],
})
const entityInfoData = Mock.mock({
'items|1': [{
"__oid":"faa1329e90c205b9c7e87d9dde4ef990",
"id":"faa1329e90c205b9c7e87d9dde4ef990",
"name":"张春贤",
"image":"https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E6%98%A5%E8%B4%A414.glk",
"data_status":"NORMAL",
"source_name":"3",
"concept":[
"64082742e4b0f6e105e07aab"
],
"propertyList": [
{
"id": "64084189e4b047daf59229c7",
"name": "别名",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "64082b3be4b047daf5922998",
"name": "简介",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "张春贤(1953年5月12日-),河南禹州人,中华人民共和国政治人物,副国级领导人,中共第十六、十七、十八、十九届中央委员,第十八届中央政治局委员[1][2]。曾任交通部部长、中共湖南省委书记、中共新疆维吾尔自治区党委书记,现任第十三届全国人大常委会副委员长。",
"childrenList": null
},
{
"id": "640843d2e4b047daf59229da",
"name": "人物经历",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "1953年出生在河南省禹县(今禹州市)城关镇一个普通家庭[3]。1970年17岁时,张春贤参加中国人民解放军,任中国人民解放军八一九二部队战士。1973年11月加入中国共产党。1975年,回到河南家乡,任河南省禹县城关公社东关大队干部。1976年12月进入东北重型机械学院(现为燕山大学)机械制造系锻压工艺及设备专业学习。1980年9月毕业后,被分配到第三机械工业部一一六厂十五车间担任技术员[4][5]。\n\n张春贤从一名普通技术员做起。1982年至1985年,历任机械工业部第十设计研究院计划科计划员、助理工程师,设计院党委组织部副部长。1985年至1988年,任机械工业部、国家机械工业委员会、机械电子工业部第十设计研究院党委书记。1988年到1991年,任机械电子工业部第十设计研究院党委书记兼副院长[4][5]。\n\n1991年10月,作为机械电子工业部选拔的优秀年轻干部,张春贤调入中央部委工作。1991年至1992年,任监察部驻机械电子工业部监察局副局长兼机械电子工业部纠风办主任。1992年至1993年,任中国包装和食品机械总公司副总经理。1993年至1995年,任中国包装和食品机械总公司总经理兼党委书记[4][5]。在他出任副总经理时,该公司管理混乱,而在他以总经理兼党委书记的身份离开该公司时,它已变成部里较好的企业[5]。",
"childrenList": null
},
{
"id": "640843ece4b047daf59229db",
"name": "家庭地址",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "TEXT",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "640843fee4b047daf59229dc",
"name": "个人履历",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "TEXT",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "64084c01e4b047daf5922a09",
"name": "描述信息",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "TEXT",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "64084572e4b047daf59229ed",
"name": "活跃等级",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "64084564e4b047daf59229ec",
"name": "人物现状",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "LONG",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "64084578e4b047daf59229ee",
"name": "代表作品",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "TEXT",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
}
],
"parentPropertyList": [
{
"id": "64082b8ae4b047daf5922999",
"name": "人物基本信息",
"alias": null,
"parentid": null,
"groupKey": "",
"group": null,
"data_type": "PARENT",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": [
[
{
"id": "64082bd1e4b047daf592299a",
"name": "性别",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "男",
"childrenList": null
},
{
"id": "640841d4e4b047daf59229c9",
"name": "出生日期",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "DATETIME",
"data_format": "yyyy-MM-dd HH:mm:ss",
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": null,
"childrenList": null
},
{
"id": "64084205e4b047daf59229ca",
"name": "出生地",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "中华人民共和国河南省禹县",
"childrenList": null
},
{
"id": "64084224e4b047daf59229cc",
"name": "国家地区",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "中国",
"childrenList": null
},
{
"id": "640842dee4b047daf59229d1",
"name": "毕业院校",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "东北重型机械学院、哈尔滨工业大学",
"childrenList": null
},
{
"id": "640842efe4b047daf59229d2",
"name": "民族",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "汉族",
"childrenList": null
},
{
"id": "64084325e4b047daf59229d4",
"name": "现任职务",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "全国人民代表大会常务委员会副委员长",
"childrenList": null
},
{
"id": "64084310e4b047daf59229d3",
"name": "政党派系",
"alias": null,
"parentid": "64082b8ae4b047daf5922999",
"groupKey": "64082b8ae4b047daf5922999",
"group": "8d7b96eb1ddf46d8ad95381477d68f03",
"data_type": "STRING",
"data_format": null,
"data_unit": null,
"dataRange": null,
"multi": false,
"propValue": "中国共产党",
"childrenList": null
}
]
]
}
],
"associatedSpecialLibrary": [
{
"id": "7",
"specialCode": "ZYK_SR",
"specialName": "涉日专用库"
},
{
"id": "8",
"specialCode": "ZYK_ST",
"specialName": "涉台专用库"
}
]
}],
})
const anlysisData = Mock.mock({
'items|1': [{
"d3data": {
"nodes": [
{
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E5%86%9B32.glk",
"imageprtcl": null,
"confirm": false,
"concept": "64082742e4b0f6e105e07aab",
"layer": 10,
"name": "张军",
"id": "72860f221138d46fa16e9d6f99af9b38",
"nickName": null,
"domain": "9fdfed3888c1cd3c",
"positionX": null,
"positionY": null,
"source_name": null
},
{
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E6%98%A5%E8%B4%A414.glk",
"imageprtcl": null,
"confirm": false,
"concept": "64082742e4b0f6e105e07aab",
"layer": 10,
"name": "张春贤",
"id": "faa1329e90c205b9c7e87d9dde4ef990",
"nickName": null,
"domain": "9fdfed3888c1cd3c",
"positionX": null,
"positionY": null,
"source_name": null
},
{
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E6%9D%A8%E6%99%93%E6%B8%A130.glk",
"imageprtcl": null,
"confirm": false,
"concept": "64082742e4b0f6e105e07aab",
"layer": 10,
"name": "杨晓渡",
"id": "f18ff88ea3a328d71fd68acabbbce824",
"nickName": null,
"domain": "9fdfed3888c1cd3c",
"positionX": null,
"positionY": null,
"source_name": null
},
{
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E6%9D%8E%E5%85%8B%E5%BC%BA1.glk",
"imageprtcl": null,
"confirm": false,
"concept": "64082742e4b0f6e105e07aab",
"layer": 10,
"name": "李克强",
"id": "3dddc2f34bc6d52be97b990e6af59ee5",
"nickName": null,
"domain": "9fdfed3888c1cd3c",
"positionX": null,
"positionY": null,
"source_name": null
},
{
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E5%BC%A0%E5%8F%88%E4%BE%A029.glk",
"imageprtcl": null,
"confirm": false,
"concept": "64082742e4b0f6e105e07aab",
"layer": 10,
"name": "张又侠",
"id": "26ef870b0d6aa11360df494af8415b1f",
"nickName": null,
"domain": "9fdfed3888c1cd3c",
"positionX": null,
"positionY": null,
"source_name": null
},
{
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": "https://tilake.wenge.com/wos/graphlake/entity-icon/gzdx/%E7%8E%8B%E4%B8%9C%E6%98%8E20.glk",
"imageprtcl": null,
"confirm": false,
"concept": "64082742e4b0f6e105e07aab",
"layer": 10,
"name": "王东明",
"id": "0ae44f4010a1f461964316dbaef2f136",
"nickName": null,
"domain": "9fdfed3888c1cd3c",
"positionX": null,
"positionY": null,
"source_name": null
}
],
"edges": [
{
"source": 0,
"target": 1,
"relation_id": "64083d5ee4b047daf59229a6",
"relation": "同事",
"rid": "64185382e4b0e0eb28ce53ac",
"rids": [
{
"id": "64185382e4b0e0eb28ce53ac",
"name": "同事",
"source": "MANUAL"
}
],
"start": null,
"end": null,
"icon": {
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": null,
"imageprtcl": null
}
},
{
"source": 0,
"target": 2,
"relation_id": "64083d5ee4b047daf59229a6",
"relation": "同事",
"rid": "641853a9e4b0e0eb28ce53ad",
"rids": [
{
"id": "641853a9e4b0e0eb28ce53ad",
"name": "同事",
"source": "MANUAL"
}
],
"start": null,
"end": null,
"icon": {
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": null,
"imageprtcl": null
}
},
{
"source": 0,
"target": 3,
"relation_id": "64083d5ee4b047daf59229a6",
"relation": "同事",
"rid": "64185319e4b0e0eb28ce53aa",
"rids": [
{
"id": "64185319e4b0e0eb28ce53aa",
"name": "同事",
"source": "MANUAL"
}
],
"start": null,
"end": null,
"icon": {
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": null,
"imageprtcl": null
}
},
{
"source": 0,
"target": 4,
"relation_id": "64083d5ee4b047daf59229a6",
"relation": "同事",
"rid": "64185046e4b0e0eb28ce53a9",
"rids": [
{
"id": "64185046e4b0e0eb28ce53a9",
"name": "同事",
"source": "MANUAL"
}
],
"start": null,
"end": null,
"icon": {
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": null,
"imageprtcl": null
}
},
{
"source": 0,
"target": 5,
"relation_id": "64083d5ee4b047daf59229a6",
"relation": "同事",
"rid": "64185340e4b0e0eb28ce53ab",
"rids": [
{
"id": "64185340e4b0e0eb28ce53ab",
"name": "同事",
"source": "MANUAL"
}
],
"start": null,
"end": null,
"icon": {
"shape": null,
"shapecolor": null,
"border": null,
"bordercolor": null,
"image": null,
"imageprtcl": null
}
}
],
"ccount": [
{
"cid": "64082742e4b0f6e105e07aab",
"cname": "人物",
"ccount": 6
}
],
"concepts": {
"64082742e4b0f6e105e07aab": null
},
"conceptsName": {},
"relations": {},
"relationInstance": [],
"rids": []
}}],
})
module.exports = [
{
url: '/knowledge-manage/thematicSearch/analysisFilter',
type: 'get',
response: config => {
const items = analysisFilterData.items
return {
code: 200,
success: true,
meta: {
success: true,
message: "操作成功"
},
total: items.length,
data: {
data: items,
entityData: [],
instances: []
}
}
}
},
{
url: '/knowledge-manage/thematicSearch/entityInfo',
type: 'post',
response: config => {
const items = entityInfoData.items
return {
code: 200,
success: true,
meta: {
success: true,
message: "操作成功"
},
total: items.length,
data: items
}
}
},
{
url: '/knowledge-manage/thematicSearch/anlysis',
type: 'post',
response: config => {
const items = anlysisData.items
return {
code: 200,
success: true,
meta: {
success: true,
message: "操作成功"
},
total: items.length,
data: items
}
}
}
]

25
mock/utils.js

@ -0,0 +1,25 @@
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
module.exports = {
param2Obj
}

5
package.json

@ -15,11 +15,11 @@
"release": "standard-version"
},
"dependencies": {
"@coolbox/we-design": "^0.0.24",
"@antv/g6": "^4.8.7",
"@coolbox/we-design": "0.0.30",
"axios": "0.24.0",
"core-js": "3.6.5",
"echarts": "^5.3.3",
"eslint": "^7.32.0",
"js-cookie": "3.0.1",
"less-to-json-loader": "^1.1.0",
"moment": "^2.29.1",
@ -54,6 +54,7 @@
"html-webpack-plugin": "3.2.0",
"less": "^4.1.2",
"less-loader": "^7.3.0",
"mockjs": "^1.1.0",
"prettier": "^2.4.1",
"runjs": "4.3.2",
"script-ext-html-webpack-plugin": "^2.1.5",

7
src/App.vue

@ -15,12 +15,9 @@ export default {
name: 'App',
created() {
const theme = localStorage.getItem('theme') || 'default';
const fontSizeType = localStorage.getItem('fontSizeType') || 'default';
this.$store.dispatch('app/toggleTheme', theme);
this.$store.dispatch('app/toggleFontSizeType', fontSizeType);
}
};
</script>
<style>
.layout-vertical .w-container .w-main{
padding: 15px !important;
}
</style>

26
src/api/peoplePool.js

@ -0,0 +1,26 @@
import request from '@/utils/request';
export function getList(params) {
return request({
url: '/knowledge-manage/thematicSearch/analysisFilter',
method: 'get',
params
});
}
export function getDetails(data) {
return request({
url: '/knowledge-manage/thematicSearch/entityInfo',
method: 'post',
data
});
}
export function getAnlysis(data) {
return request({
url: '/knowledge-manage/thematicSearch/anlysis',
method: 'post',
data
});
}

BIN
src/assets/image/3.png

After

Width: 1441  |  Height: 1124  |  Size: 242 KiB

BIN
src/assets/image/a1.png

After

Width: 220  |  Height: 297  |  Size: 126 KiB

BIN
src/assets/image/a2.png

After

Width: 812  |  Height: 456  |  Size: 682 KiB

BIN
src/assets/image/a3.png

After

Width: 536  |  Height: 589  |  Size: 394 KiB

23
src/assets/image/default.svg

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="130px" height="130px" viewBox="0 0 130 130" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>默认头像</title>
<g id="优化-0322" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="全球人物库-展开搜索条件" transform="translate(-271.000000, -713.000000)">
<g id="默认头像" transform="translate(271.000000, 713.000000)">
<path d="M5.19999994,0 L124.8,0 C128.266667,0 130,1.73319466 130,5.19958397 L130,124.790017 C130,128.256406 128.266667,129.989601 124.8,129.989601 L5.19999994,129.989601 C1.73333331,129.989601 0,128.256406 0,124.790017 L0,5.19958397 C0,1.73319466 1.73333331,0 5.19999994,0 Z" id="路径" fill="#EDEEF5" fill-rule="nonzero"></path>
<path d="M50.704056,70.85 C50.873056,71.3231622 54.604368,78.5863687 54.604368,81.25 C54.604368,84.5 53.339,88.387729 53.339,88.387729 C53.339,88.387729 60.6502,97.5467962 64.2356,98.786897 C64.1784,98.8388929 65.156,98.5295176 65.2418,98.6907048 C65.2453687,98.7007978 65.2453687,98.7118092 65.2418,98.7219022 C73.6475999,95.5345573 81.906552,89.05 81.906552,89.05 C81.906552,89.05 79.061996,81.1041517 79.956396,78 C80.588196,75.8109751 84.187012,69.3912047 85.156812,66.95 C86.001812,64.8259699 49.1700559,66.6357372 50.704056,70.85 Z" id="路径" fill="#E3DCDB" fill-rule="nonzero"></path>
<path d="M87.9000314,53.5652 C87.7960231,59.3528 86.781942,64.3292 85.0554039,68.393 C94.5019595,65.7514 96.7355382,44.7278 87.9000314,53.5652 L87.9000314,53.5652 Z" id="路径" fill="#E3DCDB" fill-rule="nonzero"></path>
<path d="M47.066365,52.2652 C47.1703733,58.0528 48.1844544,63.0292 49.9109925,67.093 C40.4644369,64.4514 38.2308582,43.4278 47.066365,52.2652 L47.066365,52.2652 Z" id="路径" fill="#E3DCDB" fill-rule="nonzero"></path>
<path d="M64.6152,99.1612671 C64.5944,99.1014719 65.3354,98.5893128 65.3848,98.4229261 L65.2157999,98.4853212 C65.2157999,98.6153108 64.6151999,99.0312775 64.6152,99.1612671 L64.6152,99.1612671 Z" id="路径" fill="#BDBDBD" fill-rule="nonzero"></path>
<polygon id="路径-2" fill="#EDEEF5" points="89.707176 94.25 83.206656 88.4 81.906552 88.4 64.355148 98.8 53.304264 87.75 50.054004 89.05 49.403952 91 48.7539 92.95 48.7539 130 92.307384 130"></polygon>
<path d="M49.933,89.0948725 L49.933,90.7925366 C50.3828,96.0935126 51.0458,100.445564 50.7988,106.042917 C50.4504001,113.925486 49.6574,122.437205 50.8975999,129.992201 L5.19999994,129.989601 C4.72679992,129.989601 4.2692,129.927206 3.83239997,129.807615 C6.23219999,118.529718 4.37839998,114.853612 9.31320003,110.280578 C17.0222001,103.141549 34.6320001,96.8032557 49.933,89.0948725 Z" id="路径" fill="#86909C" fill-rule="nonzero"></path>
<path d="M63.1618,99.1170706 C63.2294,99.2288617 63.7624001,99.12487 63.7624,99.2652588 C64.48,99.3432526 65.1534,99.3432526 65.8112,99.3172546 L67.7664,99.2132629 C68.4242,99.1872649 69.095,99.1872649 69.8126,99.2652588 C72.1188,99.5174386 71.5442,100.708143 71.5442,100.957723 L67.223,108.585513 C69.173,115.082393 71.2166001,122.187625 72.4984,129.989601 L54.5948,129.989601 C55.0628,123.900888 56.0274,119.340853 57.6862,114.479242 C57.8837999,113.896888 58.422,113.059755 59.0121999,112.199224 L59.527,111.463483 C60.4708,110.12199 61.3522,108.884489 61.074,108.645308 C58.11,106.113111 57.486,103.37813 56.8464,100.957723 C58.9992001,99.9828013 61.4094,99.2808576 62.8966,99.2678586 C63.0838,99.2652588 63.2216,99.3094553 63.1618,99.1170706 L63.1618,99.1170706 Z" id="路径" fill="#86909C" fill-rule="nonzero"></path>
<path d="M85.046156,89.4822414 C85.3997559,89.9294056 85.5219559,89.9190065 85.8911559,90.3141748 C96.590156,98.0095592 111.802756,102.689185 120.614156,110.311775 C124.456956,113.636909 124.859956,120.544557 125.970156,129.989601 L76.8769559,130 C78.800956,116.436885 81.208556,101.49588 82.973956,88.3929286 C83.616156,88.3929286 84.598956,88.9128869 85.046156,89.4822414 Z" id="路径" fill="#86909C" fill-rule="nonzero"></path>
<polygon id="路径-2" fill="#FFFFFF" points="83.206656 91 83.206656 88.4 81.906552 88.4 64.355148 98.8 64.355148 100.1 67.605408 100.1 73.455876 109.85 81.906552 95.55"></polygon>
<polygon id="路径-2备份" fill="#FFFFFF" transform="translate(56.879550, 98.475000) scale(-1, 1) translate(-56.879550, -98.475000) " points="64.355148 89.05 60.454836 87.75 49.403952 98.8 49.403952 100.1 52.00416 99.45 61.104888 109.2 64.355148 92.3"></polygon>
<path d="M83.1260495,39.8528 C64.742579,44.018 57.1239695,35.5888 53.3640688,33.0486 C47.3731895,37.8222 48.7955033,48.893 46.8635488,50.9236 C46.5593244,50.518 46.2551001,50.1098 45.9508758,49.6028 C44.3257458,95.5084 88.3056638,92.3598 87.9000314,52.0416 C83.9373144,45.9472 84.6497714,45.8458 83.1260495,39.8528 Z" id="路径" fill="#F7EDEB" fill-rule="nonzero"></path>
<path d="M53.304264,35.75 C57.0641647,38.2876 64.7399788,43.9166 83.1260495,39.7514 C83.9325528,42.7758678 84.0282238,44.8545562 84.4414829,46.9757628 C84.8609543,49.1288558 87.106968,51.35 87.75702,54.6 C88.0776797,54.7139444 88.9091277,52.2120388 89.3125433,51.6708075 C92.8673638,46.901582 97.9132912,19.340691 74.105928,15.6 C60.5220851,13.5068373 50.5891683,18.3225086 46.153692,24.7 C40.4737627,32.8668117 41.7063798,49.7183132 46.153692,55.25 C46.7536132,54.6509342 48.6433677,51.1551207 48.7539,48.75 C48.99932,43.4097967 50.054004,39.65 53.304264,35.75 Z" id="路径" fill="#86909C" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

BIN
src/assets/image/down.png

Before

Width: 22  |  Height: 22  |  Size: 601 B

17
src/assets/image/down.svg

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>标题ICON</title>
<g id="优化-0322" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="标题ICON">
<rect id="矩形" x="0" y="0" width="22" height="22"></rect>
<g id="组-2880" transform="translate(2.444444, 0.000000)" fill="#2055F4" fill-rule="nonzero">
<g id="编组" transform="translate(4.715580, 10.677568) rotate(-79.000000) translate(-4.715580, -10.677568) translate(-5.618525, 7.882474)">
<path d="M-1.38950579e-13,0 C-1.38950579e-13,0 15.9232672,1.54989997 15.9232672,1.54989997 C18.2683776,1.77816219 20.3927845,3.58706327 20.6682109,5.59018768 C20.6682109,5.59018768 4.74499204,4.04029993 4.74499204,4.04029993 C2.39988161,3.81203771 0.27547588,2.00313663 -1.38950579e-13,0 C-1.38950579e-13,0 -1.38950579e-13,0 -1.38950579e-13,0 Z" id="路径"></path>
</g>
<g id="编组" transform="translate(11.622068, 10.677568) rotate(-79.000000) translate(-11.622068, -10.677568) translate(1.287963, 7.882474)">
<path d="M0,0 C0,0 15.9232672,1.54989997 15.9232672,1.54989997 C18.2683776,1.77816219 20.3927845,3.58706327 20.6682109,5.59018768 C20.6682109,5.59018768 4.74499204,4.04029993 4.74499204,4.04029993 C2.39988161,3.81203771 0.27547588,2.00313663 0,0 C0,0 0,0 0,0 Z" id="路径"></path>
</g>
</g>
</g>
</g>
</svg>

21
src/assets/image/tag1.svg

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>涉H备份</title>
<defs>
<linearGradient x1="50%" y1="1.98897782%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#FF9090" offset="0%"></stop>
<stop stop-color="#FF0000" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="1.98897782%" x2="50%" y2="100%" id="linearGradient-2">
<stop stop-color="#FFFFFF" offset="0%"></stop>
<stop stop-color="#FFBDBD" offset="100%"></stop>
</linearGradient>
</defs>
<g id="优化-0322" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="涉H备份">
<polygon id="路径" points="0 0 22 0 22 22 0 22"></polygon>
<path d="M3.71775,2.67383333 L11.25,1 L18.78225,2.67383333 C19.2015714,2.76704721 19.5,3.13894294 19.5,3.5685 L19.5,12.72325 C19.5,14.5621295 18.580748,16.2792848 17.0506667,17.29925 L11.25,21.1666667 L5.44933333,17.29925 C3.91952217,16.279465 3.00044003,14.5627214 3,12.7241667 L3,3.5685 C3,3.13894294 3.29842859,2.76704721 3.71775,2.67383333 Z" id="路径" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
<polygon id="路径" fill="url(#linearGradient-2)" fill-rule="nonzero" points="11.2056385 13.2107863 14.4231719 14.9022083 13.8090051 11.3201159 16.411277 8.78243555 12.8138578 8.25913477 11.2056385 5 9.59632439 8.25913477 6 8.78243555 8.60227186 11.3201159 7.98919982 14.9022083"></polygon>
</g>
</g>
</svg>

21
src/assets/image/tag2.svg

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>重点任务备份</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#FFE4A9" offset="0%"></stop>
<stop stop-color="#FFBB2D" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-2">
<stop stop-color="#FFFFFF" offset="0%"></stop>
<stop stop-color="#FFEABD" offset="100%"></stop>
</linearGradient>
</defs>
<g id="优化-0322" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="重点任务备份">
<polygon id="路径" points="0 0 22 0 22 22 0 22"></polygon>
<path d="M3.71775,2.67383333 L11.25,1 L18.78225,2.67383333 C19.2015714,2.76704721 19.5,3.13894294 19.5,3.5685 L19.5,12.72325 C19.5,14.5621295 18.580748,16.2792848 17.0506667,17.29925 L11.25,21.1666667 L5.44933333,17.29925 C3.91952217,16.279465 3.00044003,14.5627214 3,12.7241667 L3,3.5685 C3,3.13894294 3.29842859,2.76704721 3.71775,2.67383333 Z" id="路径" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
<path d="M11.2209945,4.8 C8.32044199,4.8 6,7.21379311 6,10.2310345 C6,12.1017241 6.98618784,13.912069 8.55248618,14.8775862 L9.13259668,15.2396552 L10.4088398,11.8603448 L10.0607735,11.6189655 C9.65469613,11.2568965 9.48066298,10.7741379 9.48066298,10.2310345 C9.48066298,9.20517242 10.2348066,8.42068966 11.2209945,8.42068966 C12.2071823,8.42068966 12.961326,9.20517242 12.961326,10.2310345 C12.961326,10.7741379 12.7292818,11.2568965 12.3812155,11.6189655 L12.0911602,11.9206897 L13.3674033,15.3 L13.9475138,14.937931 C15.5138121,13.9724138 16.5,12.162069 16.5,10.2913793 C16.4419889,7.21379311 14.121547,4.8 11.2209945,4.8 Z" id="路径" fill="url(#linearGradient-2)" fill-rule="nonzero"></path>
</g>
</g>
</svg>

159
src/components/PeoplePoolPage/basic-info.vue

@ -0,0 +1,159 @@
<template>
<div class="basic">
<div class="top">
<div style="display: flex;align-items: center;">
<div class="image">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
人物简介
</div>
</div>
<div class="edit">
<w-button style="width: 80px;color:#303133;border: 1px solid #DDDFE8; border-radius: 2px;">
<template #default>
<CoolEditLine size="15" color="#303133" style="margin-right: 3px;" />编辑
</template>
</w-button>
</div>
</div>
<div class="content">
<div class="avatar">
<img v-if="basicInfo.image" :src="basicInfo.image" alt="">
<img v-else src="../../assets/image/default.svg" alt="" />
<div class="" style="color: #909399; text-align: center; line-height: 24px;margin-top: 8px;">
蔡英文相关概述图
<div>
2
</div>
</div>
</div>
<div class="introduction">
<div class="peo_row">
<div class="item">
<span class="left">姓名</span>
<span class="right">{{ basicInfo.name }}</span>
</div>
</div>
<div v-for="(item, index) in parentPropertyList" :key="index" class="peo_row">
<div class="item">
<span class="left">{{ item.name }}</span>
<!-- <span class="right">{{ item.propValue }}</span> -->
<span class="right">
<w-text-ellipsis :text="item.propValue" more="..." :height="40" :width="220" use-tooltip placement="bottom">
</w-text-ellipsis>
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// import bus from '@/utils/EventBus';
// import { getDetails } from '@/api/peoplePool';
export default {
name: 'BasicInfo',
props: {
parentPropertyList: Array,
basicInfo: Object
},
data() {
return {
};
},
methods: {
},
created() {
},
mounted() {
}
};
</script>
<style lang='less' scoped>
.basic {
width: 100%;
margin-top: 16px;
color: #303133;
font-size: var(--font-size-default);
background: #fff;
padding: 24px;
border-radius: 4px;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
.image {
width: 18px;
height: 18px;
margin-right: 9px;
img {
width: 100%;
}
}
.title {
font-size: var(--font-size-medium);
line-height: 26px;
font-weight: 500;
}
}
.content {
padding-top: 16px;
display: flex;
.avatar {
width: 130px;
img {
width: 130px;
height: 156px;
object-fit: cover;
}
}
.introduction {
margin-left: 25px;
flex: 1;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-rows: 25px 25px;
grid-gap: 20px 20px;
.peo_row {
width: 100%;
height: 24px;
line-height: 24px;
.item {
display: flex;
.left {
display: block;
width: 90px;
color: #909399;
margin-right: 0px;
}
.right {
width: 70%;
display: block;
}
}
}
}
}
</style>

4
src/components/PeoplePoolPage/breadcrumb.vue

@ -2,7 +2,7 @@
<w-breadcrumb separator="/">
<w-breadcrumb-item :to="{ path: '' }" style="color: #909399;" class="item">首页</w-breadcrumb-item>
<w-breadcrumb-item :to="{ path: '' }" style="color: #303133;" class="item">全球人物库</w-breadcrumb-item>
<w-breadcrumb-item v-if="content" style="color: #303133;" class="item">{{ content }}</w-breadcrumb-item>
<w-breadcrumb-item v-if="message" style="color: #303133;" class="item">{{ message }}</w-breadcrumb-item>
</w-breadcrumb>
</template>
@ -10,7 +10,7 @@
export default {
name: '',
props: {
content: String
message: String
},
data() {
return {

125
src/components/PeoplePoolPage/detailCom.vue

@ -0,0 +1,125 @@
<template>
<div>
<div id="content-item0" class="part" style="background: transparent;border-radius: 0px;">
<PersonInformation :offsettop="offsettop" :title="name" :job="job" :introduction="introduction"></PersonInformation>
<basicInfo :parentPropertyList="parentPropertyList" :basicInfo="basicInfo"></basicInfo>
</div>
<PhotoVideo id="content-item1" class="part"></PhotoVideo>
<News id="content-item2" class="part"></News>
<PeopleDescriptive id="content-item3" class="part"></PeopleDescriptive>
<PeopleLifetime id="content-item4" class="part"></PeopleLifetime>
<SocialAnalysis id="content-item5" class="part"></SocialAnalysis>
<PlatformDynamics id="content-item6" class="part"></PlatformDynamics>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
import PhotoVideo from './photo-video.vue';
import News from './news.vue';
import PeopleDescriptive from './people-descriptive.vue';
import PeopleLifetime from './people-lifetime.vue';
import SocialAnalysis from './social-analysis.vue';
import PlatformDynamics from './platform-dynamics.vue';
import basicInfo from './basic-info.vue';
import PersonInformation from './person-information.vue';
import { getDetails } from '@/api/peoplePool';
export default {
name: 'Detail',
components: {
PersonInformation,
basicInfo,
PhotoVideo,
News,
PeopleDescriptive,
PeopleLifetime,
SocialAnalysis,
PlatformDynamics
},
props: {
offsettop: Number
},
data() {
return {
loading: true,
isShow1: false,
job: '',
basicInfo: {},
name: '',
introduction: '',
parentPropertyList: []
};
},
methods: {
getdeatilInfo() {
getDetails().then(res => {
this.basicInfo = res.data;
res.data.parentPropertyList.forEach(item => {
if (item.name === '人物基本信息') {
this.parentPropertyList = item.childrenList[0];
}
});
this.parentPropertyList.forEach(m => {
if (m.name === '现任职务') {
// bus.$emit('job', m.propValue);
this.job = m.propValue;
} else if (m.name === '政党派系') {
// bus.$emit('introduction', m.propValue);
this.introduction = m.propValue;
}
});
this.name = this.basicInfo.name;
bus.$emit('load2', false);
// bus.$emit('show', true);
this.$emit('show', true);
});
}
},
watch: {
// screenWidth() {
// if (this.screenWidth < 1480) {
// document.querySelector('.detailGlobal').style.marginRight = '160px';
// document.querySelector('.detailGlobal').style.marginLeft = '160px';
// } else {
// // document.querySelector('.tabList').style.display = 'block';
// document.querySelector('.detailGlobal').style.marginRight = 'calc((100vw - 1200px) / 2)';
// document.querySelector('.detailGlobal').style.marginLeft = 'calc(50vw - 600px)';
// }
// if (this.screenWidth < 1300) {
// document.querySelector('.tabList').style.display = 'none';
// } else {
// document.querySelector('.tabList').style.display = 'block';
// }
// }
},
created() {
},
mounted() {
this.getdeatilInfo();
// this.target = document.documentElement;
this.screenWidth = document.body.clientWidth;
window.onresize = () => {
return (() => {
this.screenWidth = document.body.clientWidth;
})();
};
}
};
</script>
<style lang="less" scoped>
.part {
width: 100%;
border-radius: 4px;
background: #fff;
margin-bottom: 16px;
}
</style>

459
src/components/PeoplePoolPage/itemCard.vue

@ -1,109 +1,173 @@
<template>
<div class="itemCard">
<w-card v-for="(item, index) in cardList" :key="index" shadow="always" class="card" >
<div class="card-top" @click="goDetail" >
<div class="avatar">
<w-avatar shape="square" :size="130" fit="contain"
src="http://winbox.wenge.com/static/external_images/212516-15666531161ade.jpg"></w-avatar>
</div>
<div class="card-info">
<div class="name">
<span style="font-size: 18px;margin-right: 16px;">{{ item.name }}</span>
<span style="font-size: 12px;line-height: 22px;color:#909399;">
印度
</span>
</div>
<div class="blurb">
2005年他被美国宣布为恐怖分子联合国把他的名字列在极少数的同塔同塔利2002005年他被美国宣布为恐怖分子联合国把他的名字列在极少数的同塔同塔利2005年他被美国宣布为恐怖分子联合国把他的名字列在极少数的同塔同塔利班5年他被美国宣布为恐怖分子联合国把他的名字列在极少数的同塔同塔利班
</div>
<div class="organize">
<div class="organize-info">
<span style="color: #909399 ;">组织</span>
<span style="color: #2055F4;">卡里姆拉拉团伙</span>
<div>
<div v-if="isclick" class="itemCard">
<div v-for="(item, index) in cardList" :key="index" @click="goDetail(item.id, item)">
<w-card shadow="hover" class="card">
<div class="card-top">
<div class="avatar">
<img v-if="item.image" :src="item.image" alt="" />
<img v-else src="../../assets/image/default.svg" alt="" />
</div>
<div class="active-level">
<span style="color: #909399 ;">活跃等级</span>
<div :class="[item.num >= 80 ? 'level-num2' : item.num >= 60 ? 'level-num1' : 'level-num']">
{{ item.num >= 80 ? '高' : item.num >= 60 ? '中' : '低' }}({{ item.num }})
<div class="card-info">
<div class="name">
<span class="surname">{{ item.name }}</span>
<div class="nationality">
{{ item['国家地区'] }}
</div>
<div v-if="index === 2" style="margin-left: 18px;display: flex;align-items: center;">
<w-tooltip content="涉H" placement="top">
<img src="../../assets/image/tag1.svg" alt="" style="width: 16px;margin-right: 10px;">
</w-tooltip>
<w-tooltip content="重点人物" placement="top">
<img src="../../assets/image/tag2.svg" alt="" style="width: 16px;">
</w-tooltip>
<!-- <img src="../../assets/image/tag1.svg" alt="" style="width: 16px;margin-right: 10px;">
<img src="../../assets/image/tag2.svg" alt="" style="width: 16px;"> -->
</div>
</div>
<div class="blurb">
{{ item['简介'] }}
</div>
<div class="organize">
<div class="organize-info">
<span style="color: #909399">组织</span>
<span style="color: #0081ff">{{ item['政党派系'] }}</span>
</div>
<div class="active-level">
<span style="color: #909399">活跃等级</span>
<div :class="[index === 2 ? 'level-num2' : index === 1 ? 'level-num1' : 'level-num']">
{{ index === 2 ? '高' : index === 1 ? '中' : '低' }}({{ index === 2 ? 90 : index === 1 ? 60 : 30 }})
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="item.num >= 80" class="logo">
<CoolShieldUserFill size="16" color="#FF0000" />
<!-- <div v-if="index === 2" class="logo">
<CoolShieldUserFill size="16" color="#FF0000" />
</div> -->
<w-divider class="line"></w-divider>
<div class="card-bottom">
<div v-if="index === 0" class="content" style="justify-content: center">设为重点人物</div>
<div v-else-if="index === 1" class="content">
<div class="content-left">监控分析</div>
<w-divider direction="vertical"></w-divider>
<div class="content-left">设为重点人物</div>
</div>
<div v-else-if="index === 2" class="content">
<div class="content-left">监控分析</div>
<w-divider direction="vertical"></w-divider>
<div class="content-left" style="color: #272a31">取消重点人物</div>
</div>
<div v-else class="content" style="justify-content: center">设为重点人物</div>
</div>
</w-card>
</div>
<w-divider class="line"></w-divider>
<div class="card-bottom">
<div v-if="item.num < 60" class="content" style="justify-content: center;">
设为重点人物
</div>
</div>
<div v-if="!isclick" class="itemList">
<div v-for="(item, index) in cardList" :key="index" @click="goDetail(item.id, item)">
<div class="card-top">
<div class="avatar">
<img v-if="item.image" :src="item.image" alt="" />
<img v-else src="../../assets/image/default.svg" alt="" />
<div v-else-if="item.num >= 80" class="content">
<div class="content-left">
监控分析
</div>
<w-divider direction="vertical"></w-divider>
<div class="content-left" style="color: #272A31;">
取消重点人物
</div>
</div>
<div v-else class="content">
<div class="content-left">
监控分析
<div class="card-info">
<div class="name">
<span class="surname">{{ item.name }}</span>
<div class="nationality">
{{ item['国家地区'] }}
</div>
<div v-if="index === 2" style="margin-left: 18px;display: flex;align-items: center;">
<w-tooltip content="涉H" placement="top">
<img src="../../assets/image/tag1.svg" alt="" style="width: 16px;margin-right: 10px;">
</w-tooltip>
<w-tooltip content="重点人物" placement="top">
<img src="../../assets/image/tag2.svg" alt="" style="width: 16px;">
</w-tooltip>
</div>
</div>
<div class="blurb">
{{ item['简介'] }}
</div>
<div class="organize">
<div class="organize-info">
<span style="color: #909399">组织</span>
<span style="color: #0081ff">{{ item['政党派系'] }}</span>
</div>
<div class="active-level">
<span style="color: #909399">活跃等级</span>
<div :class="[index === 2 ? 'level-num2' : index === 1 ? 'level-num1' : 'level-num']">
{{ index === 2 ? '高' : index === 1 ? '中' : '低' }}({{ index === 2 ? 90 : index === 1 ? 60 : 30 }})
</div>
</div>
</div>
</div>
<w-divider direction="vertical"></w-divider>
<div class="content-left">
设为重点人物
<div class="card-bottom">
<div v-if="index === 0" class="content" style="justify-content: center">设为重点人物</div>
<div v-else-if="index === 1" class="content">
<div class="content-left">监控分析</div>
<w-divider direction="vertical"></w-divider>
<div class="content-right">设为重点人物</div>
</div>
<div v-else-if="index === 2" class="content">
<div class="content-left">监控分析</div>
<w-divider direction="vertical"></w-divider>
<div class="content-right" style="color: #272a31">取消重点人物</div>
</div>
<div v-else class="content" style="justify-content: center">设为重点人物</div>
</div>
</div>
<w-divider class="line"></w-divider>
</div>
</w-card>
</div>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
export default {
name: 'ItemCard',
props: {
cardList: Array,
isclick: Boolean
},
data() {
return {
cardList: [
{
name: '达乌德·易卜拉欣',
num: 29.6
},
{
name: '达乌德·易卜拉欣11',
num: 65
},
{
name: '达乌德·易卜拉欣2',
num: 86
}
]
number: 0
};
},
methods: {
goDetail() {
goDetail(id, item) {
bus.$emit('detail', false);
// this.$router.push('/detail');
document.getElementsByClassName('contentRight')[0].scrollTop = 0;
const { href } = this.$router.resolve({
path: `/peoplePoolDeatil/${id}`
});
window.open(href, '_blank');
}
},
mounted() {
this.cardList.forEach((item, index) => {
if (index == 0) {
this.number = 30;
} else if (index == 1) {
this.number = 60;
} else if (index == 2) {
this.number = 90;
}
});
}
};
</script>
<style lang='less' scoped>
.itemCard {
display: flex;
justify-content: space-between;
// flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(440px, 1fr));
grid-gap: 16px;
width: 100%;
color: #303133;
cursor: pointer;
.card-top {
display: flex;
@ -113,7 +177,13 @@ export default {
width: 130px;
height: 130px;
margin-right: 12px;
// background-color: red;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.card-info {
@ -124,12 +194,28 @@ export default {
.name {
display: flex;
align-items: center;
.surname {
font-size: var(--font-size-medium);
margin-right: 16px;
font-weight: 500;
}
.nationality {
font-size: 12px;
line-height: 22px;
color: #909399;
height: 22px;
background-color: #f8f8f8;
text-align: center;
padding: 0 5px;
}
}
.blurb {
height: 48px;
line-height: 24px;
font-size: 16px;
font-size: var(--font-size-default);
word-break: break-all;
overflow: hidden;
display: -webkit-box;
@ -143,16 +229,27 @@ export default {
align-items: center;
justify-content: space-between;
margin-top: 21px;
font-size: var(--font-size-small);
.organize-info {
width: 45%;
line-height: 18px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.active-level {
width: 50%;
text-align: right;
white-space: nowrap;
}
.level-num {
border: 1px solid #77C79B;
background-color: #EEFFF7;
border: 1px solid #77c79b;
background-color: #eefff7;
border-radius: 2px;
color: #28C76F;
color: #28c76f;
font-size: 13px;
text-align: center;
width: 70px;
@ -162,10 +259,10 @@ export default {
}
.level-num1 {
border: 1px solid #FBE690;
background-color: #FDF9EA;
border: 1px solid #fbe690;
background-color: #fdf9ea;
border-radius: 2px;
color: #FFAE02;
color: #ffae02;
font-size: 13px;
text-align: center;
width: 70px;
@ -175,10 +272,10 @@ export default {
}
.level-num2 {
border: 1px solid #FFD1CF;
background-color: #FFEEF0;
border: 1px solid #ffd1cf;
background-color: #ffeef0;
border-radius: 2px;
color: #FF565D;
color: #ff565d;
font-size: 13px;
text-align: center;
width: 70px;
@ -193,12 +290,11 @@ export default {
.logo {
width: 46px;
height: 46px;
background-color: #FFEEF0;
background-color: #ffeef0;
position: absolute;
right: 0;
top: 0;
border-radius: 0px 4px 0px;
;
-webkit-clip-path: polygon(0px 0px, 46px 0px, 46px 46px);
text-align: right;
padding-right: 6px;
@ -211,8 +307,8 @@ export default {
justify-content: center;
align-items: center;
height: 48px;
color: #2055F4;
font-size: 14px;
color: #2055f4;
font-size: var(--font-size-small);
.content {
display: flex;
@ -235,15 +331,196 @@ export default {
}
.card {
width: 33%;
width: 100%;
position: relative;
cursor: pointer;
::v-deep.w-card__body {
padding: 0 16px !important;
color: #303133;
}
::v-deep.w-card {
color: #303133;
}
}
}
.itemList {
width: 100%;
color: #303133;
cursor: pointer;
.card-top {
display: flex;
padding: 16px 0;
align-items: center;
.avatar {
width: 130px;
height: 130px;
margin-right: 12px;
// background-color: red;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.card-info {
flex: 1;
display: flex;
flex-direction: column;
.name {
display: flex;
align-items: center;
.surname {
font-size: var(--font-size-medium);
margin-right: 16px;
font-weight: 500;
}
.nationality {
font-size: 12px;
line-height: 22px;
color: #909399;
height: 22px;
background-color: #f8f8f8;
text-align: center;
padding: 0 5px;
}
}
.blurb {
width: 1000px;
height: 48px;
line-height: 24px;
font-size: var(--font-size-default);
word-break: break-all;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin-top: 16px;
}
.organize {
display: flex;
align-items: center;
margin-top: 21px;
font-size: var(--font-size-small);
.organize-info {
line-height: 18px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 78px;
}
.active-level {
// width: 50%;
text-align: right;
white-space: nowrap;
}
.level-num {
border: 1px solid #77c79b;
background-color: #eefff7;
border-radius: 2px;
color: #28c76f;
font-size: 13px;
text-align: center;
width: 70px;
height: 22px;
line-height: 22px;
display: inline-block;
}
.level-num1 {
border: 1px solid #fbe690;
background-color: #fdf9ea;
border-radius: 2px;
color: #ffae02;
font-size: 13px;
text-align: center;
width: 70px;
height: 22px;
line-height: 22px;
display: inline-block;
}
.level-num2 {
border: 1px solid #ffd1cf;
background-color: #ffeef0;
border-radius: 2px;
color: #ff565d;
font-size: 13px;
text-align: center;
width: 70px;
height: 22px;
line-height: 22px;
display: inline-block;
}
}
}
}
// .logo {
// width: 46px;
// height: 46px;
// background-color: #ffeef0;
// position: absolute;
// right: 0;
// top: 0;
// border-radius: 0px 4px 0px;
// -webkit-clip-path: polygon(0px 0px, 46px 0px, 46px 46px);
// text-align: right;
// padding-right: 6px;
// line-height: 36px;
// }
.card-bottom {
display: flex;
justify-content: center;
align-items: center;
color: #2055f4;
font-size: var(--font-size-small);
padding-right: 20px;
.content {
display: flex;
align-items: center;
cursor: pointer;
height: 22px;
line-height: 22px;
.content-left {
display: flex;
align-items: center;
justify-content: center;
margin-right: 30px;
}
.content-right {
display: flex;
align-items: center;
justify-content: center;
margin-left: 30px;
}
}
}
.line {
margin: 0;
}
}
::v-deep.w-card.is-always-shadow {
box-shadow: 0 2px 10px 0 rgb(0 0 0 / 12%);
}
@ -251,4 +528,6 @@ export default {
::v-deep.w-card {
border-radius: 4px;
border: none;
}</style>
box-shadow: 0 2px 10px 0 rgb(0 0 0 / 12%);
}
</style>

153
src/components/PeoplePoolPage/itemGroup.vue

@ -1,41 +1,58 @@
<template>
<div class="people-list">
<div class="itemGroup">
<div class="left">
<div class="image">
<img src="../../assets/image/down.png" alt="">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
{{ name }}
</div>
</div>
<div class="sort">
<div class="img">
<CoolOrderPlayLine size="16" color="#303133"/>
<div style="display: flex;">
<div class="sort">
<div class="img">
<CoolSortDesc size="16" color="#303133" />
</div>
<w-dropdown style="cursor: pointer;" @command="handleCommand">
<span class="w-dropdown-link">
<span style="margin-right: 15px;">{{ sortValue }}</span>
<i class="w-icon-arrow-down"></i>
</span>
<w-dropdown-menu slot="dropdown" class="dropdownSize">
<w-dropdown-item v-for="(item, index) in sortlist" :key="index" :command='item'>{{ item }}</w-dropdown-item>
</w-dropdown-menu>
</w-dropdown>
</div>
<w-dropdown>
<span class="w-dropdown-link">
<span style="margin-right: 15px;">综合排序</span>
<i class="w-icon-arrow-down"></i>
</span>
</w-dropdown>
<div class="change">
<div class="change-card" :style="{background:isclick?'#FFFFFF':'transparent'}" @click="handleChange(1)">
<CoolDashboardFill size="15" color="#8A909A" />
</div>
<div class="change-list" :style="{background:!isclick?'#FFFFFF':'transparent'}" @click="handleChange(2)">
<CoolListCheck size="15" color="#8A909A" />
</div>
</div>
</div>
</div>
<w-divider class="line"></w-divider>
<itemCard></itemCard>
<w-pagination
class="pagination"
layout="total,prev, pager, next,jumper"
:total="50"
>
</w-pagination>
<div v-loading="loading" style="min-height: 100px;">
<div v-if="cardList.length">
<itemCard :cardList="cardList" :isclick="isclick"></itemCard>
<w-pagination class="pagination" layout="total,prev, pager, next,jumper" :total="total">
</w-pagination>
</div>
</div>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
import { getList } from '@/api/peoplePool';
import itemCard from '@/components/PeoplePoolPage/itemCard';
export default {
name: 'ItemGroup',
@ -44,16 +61,58 @@ export default {
},
data() {
return {
name: '全球人物'
name: '全球人物',
sortlist: ['综合排序', '时间排序', '时间倒序'],
total: 50,
sortValue: '综合排序',
cardList: [],
loading: true,
isclick: true
};
},
methods: {
handleCommand(m) {
this.sortValue = m;
},
handleChange(num){
if (num === 1){
this.isclick = true;
} else if (num === 2){
this.isclick = false;
}
}
},
computed: {
},
mounted() {
bus.$on('params', val => {
this.name = val;
getList().then(response => {
this.loading = false;
if (!this.loading) {
this.cardList = response.data.data;
}
});
bus.$on('isEmpty', val => {
if (val) {
this.cardList = [];
}
});
bus.$on('loading', val => {
this.loading = val;
console.log(this.loading);
});
bus.$on('load', val => {
this.loading = val;
console.log(this.loading);
});
bus.$on('list', val => {
this.cardList = val;
});
}
};
</script>
@ -64,7 +123,6 @@ export default {
background-color: #FFFFFF;
padding: 24px 16px;
margin-top: 20px;
font-size: 14px;
.itemGroup {
display: flex;
@ -76,8 +134,8 @@ export default {
align-items: center;
.image {
width: 22px;
height: 22px;
width: 18px;
height: 18px;
margin-right: 4px;
img {
@ -86,7 +144,8 @@ export default {
}
.title {
font-size: 16px;
font-size: var(--font-size-medium);
font-weight: 500;
line-height: 22px;
color: #303133;
}
@ -95,6 +154,7 @@ export default {
.sort {
display: flex;
align-items: center;
margin-right: 40px;
.img {
width: 16px;
@ -106,6 +166,40 @@ export default {
}
}
.sort-content {
width: 56px;
display: flex;
align-items: center;
}
}
.change {
width: 108px;
height: 36px;
border-radius: 2px;
background-color: #E5E6E7;
padding: 2px;
display: flex;
align-items: center;
.change-card {
width: 52px;
height: 32px;
border-radius: 2px;
text-align: center;
line-height: 32px;
cursor: pointer;
}
.change-list{
width: 52px;
height: 32px;
border-radius: 2px;
text-align: center;
line-height: 32px;
cursor: pointer;
}
}
}
@ -114,14 +208,13 @@ export default {
margin: 16px 0;
}
.card {
// display: flex;
// justify-content: space-between;
// flex-wrap: wrap;
}
.pagination{
.pagination {
text-align: right;
margin-top: 48px;
}
::v-deep .w-dropdown {
font-size:var(--font-size-small) ;
}
}
</style>

66
src/components/PeoplePoolPage/nav-left.vue

@ -1,32 +1,18 @@
<template>
<div>
<div style="width: 100%">
<div class="con-left">
<div role="tree" class="w-tree w-tree--highlight-current">
<div v-for="(item, index) in list" :key="index" role="treeitem" tabindex="-1" aria-disabled="" draggable="false"
class="w-tree-node is-focusable" :class="{ 'is-current': index === activeIndex }"
@click="onClick(item.name, index)">
<div class="w-tree-node__content" style="padding-left: 0px;"><span
class="is-leaf w-tree-node__expand-icon w-icon-triangle-right"></span>
class="w-tree-node is-focusable" :class="{ 'is-current': index === activeIndex }" @click="onClick(index)">
<div class="w-tree-node__content" style="padding-left: 0px">
<span class="is-leaf w-tree-node__expand-icon w-icon-triangle-right"></span>
<span class="theme">
<span style="margin-right: 13.5px;line-height: 11px;" v-html="item.html"></span>
<span id="color" style="margin-right: 13.5px; line-height: 11px" v-html="item.html"></span>
<span>{{ item.name }}</span>
</span>
</div>
</div>
</div>
<!-- <w-button type='primary' class="createTheme" @click="dialogVisible = true">新建主题</w-button>
<w-dialog title="新建主题" :visible.sync="dialogVisible" width="30%" top='15vh'>
<w-form ref="form" :model="sizeForm" label-width="80px" :size="size" class='demo-form-size'
style="margin: 40px 0;">
<w-form-item label="主题名称">
<w-input v-model="sizeForm.name" placeholder="请输入主题名称"></w-input>
</w-form-item>
</w-form>
<span slot="footer">
<w-button @click="dialogVisible = false"> </w-button>
<w-button type="primary" @click="dialogVisible = false"> </w-button>
</span>
</w-dialog> -->
</div>
</div>
</template>
@ -34,27 +20,25 @@
import bus from '@/utils/EventBus';
export default {
name: 'NavLeft',
components: {
},
components: {},
data() {
return {
str: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M14 12v1.3H2V12h12zm-2.6-9.6 3.3 3.3L11.4 9V2.4zM8 7.3v1.3H2V7.3h6zm0-4.6V4H2V2.7h6z" fill="rgba(48,49,51,1)" data-follow-fill="#333"></path></svg>',
list: [
{
name: '全球人物',
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M8 14.7A6.7 6.7 0 1 1 8 1.3a6.7 6.7 0 0 1 0 13.4zm-1.5-1.6c-.7-1.4-1-2.9-1.1-4.4H2.7c.3 2.1 1.7 3.8 3.8 4.4zm.2-4.4c.1 1.6.6 3.2 1.3 4.5.8-1.4 1.2-2.9 1.3-4.5H6.7zm6.6 0h-2.6c-.1 1.5-.5 3-1.1 4.4 2-.6 3.4-2.3 3.7-4.4zM2.7 7.3h2.6c.1-1.5.5-3 1.1-4.4-2 .6-3.4 2.3-3.7 4.4zm4 0h2.6C9.2 5.8 8.8 4.2 8 2.8c-.8 1.4-1.2 3-1.3 4.5zm2.8-4.4c.7 1.4 1 2.9 1.1 4.4h2.6c-.2-2.1-1.6-3.8-3.7-4.4z" fill="rgba(48,49,51,1)" data-follow-fill="#333"></path></svg>'
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M8 14.7A6.7 6.7 0 1 1 8 1.3a6.7 6.7 0 0 1 0 13.4zm-1.5-1.6c-.7-1.4-1-2.9-1.1-4.4H2.7c.3 2.1 1.7 3.8 3.8 4.4zm.2-4.4c.1 1.6.6 3.2 1.3 4.5.8-1.4 1.2-2.9 1.3-4.5H6.7zm6.6 0h-2.6c-.1 1.5-.5 3-1.1 4.4 2-.6 3.4-2.3 3.7-4.4zM2.7 7.3h2.6c.1-1.5.5-3 1.1-4.4-2 .6-3.4 2.3-3.7 4.4zm4 0h2.6C9.2 5.8 8.8 4.2 8 2.8c-.8 1.4-1.2 3-1.3 4.5zm2.8-4.4c.7 1.4 1 2.9 1.1 4.4h2.6c-.2-2.1-1.6-3.8-3.7-4.4z" fill="#2055F4" data-follow-fill="#333"></path></svg>'
},
{
name: '重点人物',
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path opacity=".01" fill="none" d="M0 0h16v16H0z"></path><path d="M8 9.3v1.3c-2.2 0-4 1.8-4 4H2.7c0-2.9 2.4-5.3 5.3-5.3zm0-.6c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4zm0-1.4c1.5 0 2.7-1.2 2.7-2.7S9.5 2 8 2 5.3 3.2 5.3 4.7 6.5 7.3 8 7.3zm1.7 5.2c-.1-.4-.1-.7 0-1.1L9 11l.7-1.2.7.4c.3-.3.6-.4.9-.5V9h1.3v.8c.4.1.7.3.9.5l.7-.4.7 1.2-.7.4c.1.4.1.7 0 1.1l.7.4-.7 1.2-.7-.4c-.3.3-.6.4-.9.5v.7h-1.3v-.8c-.4-.1-.7-.3-.9-.5l-.7.4-.7-1.2c.1 0 .7-.4.7-.4zm2.3.5c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z" fill="rgba(48,49,51,1)" data-follow-fill="#333"></path></svg>'
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path opacity=".01" fill="none" d="M0 0h16v16H0z"></path><path d="M8 9.3v1.3c-2.2 0-4 1.8-4 4H2.7c0-2.9 2.4-5.3 5.3-5.3zm0-.6c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4zm0-1.4c1.5 0 2.7-1.2 2.7-2.7S9.5 2 8 2 5.3 3.2 5.3 4.7 6.5 7.3 8 7.3zm1.7 5.2c-.1-.4-.1-.7 0-1.1L9 11l.7-1.2.7.4c.3-.3.6-.4.9-.5V9h1.3v.8c.4.1.7.3.9.5l.7-.4.7 1.2-.7.4c.1.4.1.7 0 1.1l.7.4-.7 1.2-.7-.4c-.3.3-.6.4-.9.5v.7h-1.3v-.8c-.4-.1-.7-.3-.9-.5l-.7.4-.7-1.2c.1 0 .7-.4.7-.4zm2.3.5c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z" fill="#303133" data-follow-fill="#333"></path></svg>'
},
{
name: '台湾地区人物',
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M2 3.3C2 2.6 2.6 2 3.3 2h9.3c.8 0 1.4.6 1.4 1.3v9.3c0 .7-.6 1.3-1.3 1.3H3.3c-.7.1-1.3-.5-1.3-1.2V3.3zm1.3 0v9.3h9.3V3.3H3.3zm2 8.8c-.4-.2-.8-.4-1.2-.7.9-1.3 2.4-2.1 4-2.1s3 .8 3.9 2c-.4.3-.7.5-1.1.7-.6-.9-1.6-1.4-2.7-1.4-1.3.1-2.3.6-2.9 1.5zM8 8.7c-1.3 0-2.3-1-2.3-2.3S6.7 4 8 4s2.3 1 2.3 2.3-1 2.4-2.3 2.4zm0-1.4c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z" fill="rgba(48,49,51,1)" data-follow-fill="#333"></path></svg>'
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M2 3.3C2 2.6 2.6 2 3.3 2h9.3c.8 0 1.4.6 1.4 1.3v9.3c0 .7-.6 1.3-1.3 1.3H3.3c-.7.1-1.3-.5-1.3-1.2V3.3zm1.3 0v9.3h9.3V3.3H3.3zm2 8.8c-.4-.2-.8-.4-1.2-.7.9-1.3 2.4-2.1 4-2.1s3 .8 3.9 2c-.4.3-.7.5-1.1.7-.6-.9-1.6-1.4-2.7-1.4-1.3.1-2.3.6-2.9 1.5zM8 8.7c-1.3 0-2.3-1-2.3-2.3S6.7 4 8 4s2.3 1 2.3 2.3-1 2.4-2.3 2.4zm0-1.4c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z" fill="#303133" data-follow-fill="#333"></path></svg>'
},
{
name: '涉H人物',
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M1.3 14.7c0-2.9 2.4-5.3 5.3-5.3s5.3 2.4 5.3 5.3h-1.3c0-2.2-1.8-4-4-4s-4 1.8-4 4H1.3zm5.4-6c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4zm0-1.4c1.5 0 2.7-1.2 2.7-2.7S8.1 2 6.7 2 4 3.2 4 4.7s1.2 2.6 2.7 2.6zm5.5 2.5c1.9.9 3.1 2.8 3.1 4.9H14c0-1.6-.9-3-2.4-3.6l.6-1.3zm-.5-7.5c1.4.5 2.3 1.9 2.3 3.4 0 1.9-1.4 3.5-3.3 3.7V8c1.3-.2 2.2-1.4 2-2.6-.1-.8-.6-1.4-1.3-1.8l.3-1.3z" fill="rgba(48,49,51,1)" data-follow-fill="#333"></path></svg>'
html: '<svg xml:space="preserve" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" width="18" height="18"><path d="M0 0h16v16H0V0z" opacity=".01" fill="none"></path><path d="M1.3 14.7c0-2.9 2.4-5.3 5.3-5.3s5.3 2.4 5.3 5.3h-1.3c0-2.2-1.8-4-4-4s-4 1.8-4 4H1.3zm5.4-6c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4zm0-1.4c1.5 0 2.7-1.2 2.7-2.7S8.1 2 6.7 2 4 3.2 4 4.7s1.2 2.6 2.7 2.6zm5.5 2.5c1.9.9 3.1 2.8 3.1 4.9H14c0-1.6-.9-3-2.4-3.6l.6-1.3zm-.5-7.5c1.4.5 2.3 1.9 2.3 3.4 0 1.9-1.4 3.5-3.3 3.7V8c1.3-.2 2.2-1.4 2-2.6-.1-.8-.6-1.4-1.3-1.8l.3-1.3z" fill="#303133" data-follow-fill="#333"></path></svg>'
}
],
activeIndex: 0,
@ -66,30 +50,40 @@ export default {
};
},
methods: {
onClick(item, index) {
onClick(index) {
this.activeIndex = index;
bus.$emit('params', item);
bus.$emit('detail', true);
this.list.forEach((item, idx) => {
if (idx === this.activeIndex) {
this.list[idx].html = this.list[index].html.replace('fill="#303133"', 'fill="#2055F4"');
} else {
item.html = item.html.replace('fill="#2055F4"', 'fill="#303133"');
}
});
bus.$emit('detail', true);
}
}
},
mounted() { }
};
</script>
<style lang='less' scoped>
.con-left {
background-color: #fff;
height: 100vh;
font-size: 14px;
font-size: var(--font-size-small) ;
.w-tree {
border-radius: 2px;
color: #303133;
}
.w-tree-node__content {
height: 48px;
border-left: 6px solid transparent;
border-radius: 0px 2px 2px 0px;
.w-icon-file {
.w-icrgb(177, 191, 220) {
margin-right: 13.5px;
}
}
@ -98,9 +92,6 @@ export default {
color: #2055f4;
background-color: #f4f8fe;
border-left: 6px solid #2055f4;
margin-left: -4px;
border-radius: 0px 2px 2px 0px;
;
}
.createTheme {
@ -108,7 +99,8 @@ export default {
top: 85%;
left: 90px;
}
.theme{
.theme {
display: flex;
align-items: center;
}

336
src/components/PeoplePoolPage/news.vue

@ -2,7 +2,7 @@
<div class="news">
<div class="top">
<div class="image">
<img src="../../assets/image/down.png" alt="">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
新闻资讯
@ -11,177 +11,276 @@
</div>
<div class="content">
<w-tabs v-model="activeName" class="tabs" @tab-click="handleClick">
<w-tab-pane label="全部(200)" name="first">全部X</w-tab-pane>
<w-tab-pane label="网站(100)" name="second">
<w-tab-pane label="全部 (300)" name="first">
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number">
1
</div>
<div style="line-height: 20px;">
台媒蔡英文办公室发言人张惇涵确诊新冠这几天有和蔡英文跑行程
<div class="list-left">
<div class="title">
<div class="number">
1
</div>
<div style="line-height: 20px;">
台媒蔡英文办公室发言人张惇涵确诊新冠这几天有和蔡英文跑行程
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源央视新闻</span>
<span style="margin-right: 15px;">发布时间2022-12-23</span>
<div class="attitude">
<CoolEmotionUnhappyFill size="15" color="#ED6363" style="margin-right: 3px;" />
<span>负面</span>
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源央视新闻</span>
<span style="margin-right: 15px;">发布时间2022-12-23</span>
<div class="attitude">
<CoolEmotionUnhappyFill size="15" color="#ED6363" style="margin-right: 3px;"/>
<span>负面</span>
</div>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
</div>
<w-divider class="line"></w-divider>
<w-divider class="line"></w-divider>
</div>
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number">
2
</div>
<div style="line-height: 20px;">
批蔡英文冷血后赵少康再发声蔡英文还是没为团团说一句话
<div class="list-left">
<div class="title">
<div class="number">
2
</div>
<div style="line-height: 20px;">
批蔡英文冷血后赵少康再发声蔡英文还是没为团团说一句话
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;" />
<span>中立</span>
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;"/>
<span>中立</span>
</div>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
</div>
<w-divider class="line"></w-divider>
<w-divider class="line"></w-divider>
</div>
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number">
3
<div class="list-left">
<div class="title">
<div class="number">
3
</div>
<div style="line-height: 20px;">
台媒蔡英文办公室发言人张惇涵确诊新冠这几天有和蔡英文跑行程
</div>
</div>
<div style="line-height: 20px;">
台媒蔡英文办公室发言人张惇涵确诊新冠这几天有和蔡英文跑行程
<div class="list-info">
<span style="margin-right: 15px;">来源央视新闻</span>
<span style="margin-right: 15px;">发布时间2022-12-23</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;" />
<span>中立</span>
</div>
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源央视新闻</span>
<span style="margin-right: 15px;">发布时间2022-12-23</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;"/>
</div>
</div>
<w-divider class="line"></w-divider>
</div>
</w-tab-pane>
<w-tab-pane label="网站 (100)" name="second">
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number">
1
</div>
<div style="line-height: 20px;">
台媒蔡英文办公室发言人张惇涵确诊新冠这几天有和蔡英文跑行程
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源央视新闻</span>
<span style="margin-right: 15px;">发布时间2022-12-23</span>
<div class="attitude">
<CoolEmotionUnhappyFill size="15" color="#ED6363" style="margin-right: 3px;" />
<span>负面</span>
</div>
<span>中立</span>
</div>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
</div>
<w-divider class="line"></w-divider>
<w-divider class="line"></w-divider>
</div>
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number" style="background-color: #F0A431 ;">
4
<div class="list-left">
<div class="title">
<div class="number">
2
</div>
<div style="line-height: 20px;">
批蔡英文冷血后赵少康再发声蔡英文还是没为团团说一句话
</div>
</div>
<div style="line-height: 20px;">
蔡英文再拿抗中保台牌拉找选票 国台办台湾民众早已看惯了看腻了
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;" />
<span>中立</span>
</div>
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;"/>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
<w-divider class="line"></w-divider>
</div>
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number">
3
</div>
<div style="line-height: 20px;">
台媒蔡英文办公室发言人张惇涵确诊新冠这几天有和蔡英文跑行程
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源央视新闻</span>
<span style="margin-right: 15px;">发布时间2022-12-23</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;" />
<span>中立</span>
</div>
<span>中立</span>
</div>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
</div>
<w-divider class="line"></w-divider>
<w-divider class="line"></w-divider>
</div>
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number" style="background-color: #9DA3AC;">
5
<div class="list-left">
<div class="title">
<div class="number" style="background-color: #F0A431 ;">
4
</div>
<div style="line-height: 20px;">
蔡英文再拿抗中保台牌拉找选票 国台办台湾民众早已看惯了看腻了
</div>
</div>
<div style="line-height: 20px;">
蔡英文为陈时中站台首都守住台湾更安全
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;" />
<span>中立</span>
</div>
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;"/>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
<w-divider class="line"></w-divider>
</div>
<div>
<div class="list">
<div class="list-left">
<div class="title">
<div class="number" style="background-color: #9DA3AC;">
5
</div>
<div style="line-height: 20px;">
蔡英文为陈时中站台首都守住台湾更安全
</div>
</div>
<div class="list-info">
<span style="margin-right: 15px;">来源环球网 </span>
<span style="margin-right: 15px;">发布时间2022-11-22</span>
<div class="attitude" style="color:#F0A431;background-color: #FDF9EA ;">
<CoolEmotionNormalFill size="15" color="#F0A431" style="margin-right: 3px;" />
<span>中立</span>
</div>
<span>中立</span>
</div>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
<div class="list-right">
<span style="margin-right: 15px;">详情</span>
<span>溯源</span>
</div>
</div>
</div>
<w-divider class="line"></w-divider>
<w-divider class="line"></w-divider>
</div>
</w-tab-pane>
<w-tab-pane label="APP(30)" name="third">APPX</w-tab-pane>
<w-tab-pane label="头条(20)" name="fourth">头条X</w-tab-pane>
<w-tab-pane label="微博(40)" name="fifth">微博X</w-tab-pane>
<w-tab-pane label="其他(40)" name="sixth">其他X</w-tab-pane>
<w-tab-pane label="APP (30)" name="third">APP(X)</w-tab-pane>
<w-tab-pane label="头条 (20)" name="fourth">头条(X)</w-tab-pane>
<w-tab-pane label="微博 (40)" name="fifth">微博(X)</w-tab-pane>
<w-tab-pane label="其他 (40)" name="sixth">其他(X)</w-tab-pane>
</w-tabs>
</div>
</div>
@ -196,7 +295,6 @@ export default {
},
methods: {
handleClick(tab, event) {
console.log(tab, event);
}
}
};
@ -204,9 +302,8 @@ export default {
<style lang='less' scoped>
.news {
width: 100%;
// margin-top: 16px;
color: #303133;
font-size: 16px;
font-size: var(--font-size-default);
padding: 24px;
.top {
@ -224,8 +321,9 @@ export default {
}
.title {
font-size: 18px;
font-size: var(--font-size-medium);;
line-height: 26px;
font-weight: 500;
}
}
@ -245,9 +343,11 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
white-space: nowrap;
.list-left {
width: 80%;
max-width: 80%;
.title {
display: flex;
@ -261,15 +361,14 @@ export default {
border-radius: 2px;
margin-right: 8px;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
line-height: 21px;
}
}
.list-info {
color: #909399;
font-size: 14px;
font-size: var(--font-size-small);
line-height: 18px;
display: flex;
align-items: center;
@ -291,7 +390,7 @@ export default {
.list-right {
width: 10%;
color: #2055F4;
font-size: 14px;
font-size: var(--font-size-small);
cursor: pointer;
line-height: 22px;
text-align: right;
@ -300,8 +399,13 @@ export default {
.line {
margin: 14px 0 !important;
background-color: #EBECF1 !important;
}
::v-deep.w-tabs__item {
font-size: var(--font-size-small);
}
}
}
}

8
src/components/PeoplePoolPage/people-descriptive.vue

@ -2,7 +2,7 @@
<div class="descriptive">
<div class="top">
<div class="image">
<img src="../../assets/image/down.png" alt="">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
描述
@ -24,9 +24,8 @@ export default {
<style lang='less' scoped>
.descriptive {
width: 100%;
// margin-top: 16px;
color: #606266;
font-size: 18px;
font-size: var(--font-size-default);
padding: 24px;
.top {
@ -44,9 +43,10 @@ export default {
}
.title {
font-size: 18px;
font-size: var(--font-size-medium);
line-height: 26px;
color: #303133 ;
font-weight: 500;
}
}

8
src/components/PeoplePoolPage/people-lifetime.vue

@ -2,7 +2,7 @@
<div class="descriptive">
<div class="top">
<div class="image">
<img src="../../assets/image/down.png" alt="">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
人物生平
@ -53,9 +53,8 @@ export default {
<style lang='less' scoped>
.descriptive {
width: 100%;
// margin-top: 16px;
color: #606266;
font-size: 18px;
font-size: var(--font-size-default);
padding: 24px;
.top {
@ -73,9 +72,10 @@ export default {
}
.title {
font-size: 18px;
font-size: var(--font-size-medium);
line-height: 26px;
color: #303133;
font-weight: 500;
}
}

208
src/components/PeoplePoolPage/people-profile.vue

@ -1,208 +1,32 @@
<template>
<div class="profile">
<div class="info">
<div class="name">
<div style="display: flex;align-items: center;margin-bottom: 8px;">
<div class="title">蔡英文</div>
<div class="address">台湾地区领导人</div>
</div>
<div class="identity">
台湾地区政治人物民主进步党籍现任台湾地区领导人
</div>
</div>
<div class="edit">
<w-button style="margin-right: 16px;">
<template #default> <CoolEditLine size="15" color="#303133" style="margin-right: 5px;"/>编辑</template>
</w-button>
<w-button>
<template #icon>
<icon-delete />
</template>
<template #default><CoolArrowLeftSLine size="15" color="#303133" style="margin-right: 5px;"/>返回</template>
</w-button>
</div>
</div>
<div class="content">
<div class="avart">
<w-avatar shape="square" :size="130" fit="contain"
src="http://winbox.wenge.com/static/external_images/212516-15666531161ade.jpg"></w-avatar>
<div class="" style="color: #909399; text-align: center; line-height: 24px;margin-top: 8px;">
蔡英文相关概述图
<div>
2
</div>
</div>
</div>
<div class="introduction">
<div class="peo_row">
<div class="item">
<span class="left">姓名</span>
<span class="right">蔡英文</span>
</div>
<div class="item">
<span class="left">外文名</span>
<span class="right">Tsai Ing-wen</span>
</div>
<div class="item">
<span class="left">出生年月</span>
<span class="right">1956年8月31日</span>
</div>
<div class="item">
<span class="left">出生地</span>
<span class="right">台北市中山区</span>
</div>
</div>
<div class="peo_row">
<div class="item">
<span class="left">国家/地区</span>
<span class="right">中国</span>
</div>
<div class="item">
<span class="left">民族</span>
<span class="right">汉族</span>
</div>
<div class="item">
<span class="left">所属组织</span>
<span class="right">民主进步党</span>
</div>
<div class="item">
<span class="left">组织职位</span>
<span class="right">前党主席</span>
</div>
</div>
<div class="peo_row">
<div class="item" style="width: 50%;">
<span class="left">毕业院校</span>
<span class="right">台湾大学康乃尔大学伦敦政治经济学院</span>
</div>
<div class="item" style="width: 50%;">
<span class="left">代表作品</span>
<span class="right">英派点亮台湾的这一哩路</span>
</div>
</div>
<div class="peo_row">
<div class="item" style="width: 100%;">
<span class="left">社交账号</span>
<span class="right">
<span style="margin-right: 30px;">Facebook: xxxxxxxxxx</span>
<span style="margin-right: 30px;">Twitter:xxxxxxxxxxxx</span>
<span style="margin-right: 30px;">Youtube:xxxXXXX</span>
<span style="margin-right: 30dpx;">Instagram:XXXXXXXX</span>
<span>TikTok:xXXXXXXX</span>
</span>
</div>
</div>
<div class="peo_row">
<div class="item" style="width: 100%;">
<span class="left">人物履历</span>
<div class="right">
<div style="margin-bottom: 8px;">2020年1月11日蔡英文当选连任台湾地区领导人</div>
<div style="margin-bottom: 8px;">2020年1月11日蔡英文当选连任台湾地区领导人</div>
<div>2020年1月11日蔡英文当选连任台湾地区领导人</div>
</div>
</div>
</div>
</div>
</div>
<PersonInformation :offsettop="56"></PersonInformation>
<basicInfo></basicInfo>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
import basicInfo from './basic-info.vue';
import PersonInformation from './person-information.vue';
export default {
name: 'Profile'
name: 'Profile',
components: {
PersonInformation,
basicInfo
},
methods: {
goBack() {
bus.$emit('detail', true);
}
}
};
</script>
<style lang='less' scoped>
.profile {
width: 100%;
// min-height: 350px !important;
margin-top: 16px;
color: #303133;
font-size: 16px;
.info {
display: flex;
justify-content: space-between;
width: 100%;
padding: 24px;
background: url(../../assets/image/detail_title_bg.a6a1e552.png) no-repeat;
.name {
.title {
font-size: 30px;
width: 90px;
height: 38px;
line-height: 38px;
margin-right: 8px;
}
.address {
width: 198px;
height: 24px;
font-size: 22px;
line-height: 24px;
color: #8A909A;
}
.identity {
width: 400px;
height: 24px;
line-height: 24px;
color: #272A31;
}
}
.edit {}
}
.content {
padding: 24px;
display: flex;
.avart {}
.introduction {
margin-left: 25px;
flex: 1;
.peo_row {
display: flex;
justify-content: space-between;
align-items: center;
// min-height: 36px;
line-height: 24px;
margin-bottom: 16px;
.item {
width: 25%;
display: flex;
.left {
display: block;
width: 100px;
color: #909399;
}
.right {
width: 70%;
display: block;
}
}
}
}
}
font-size: var(--font-size-default);
}
</style>

98
src/components/PeoplePoolPage/person-information.vue

@ -0,0 +1,98 @@
<template>
<div>
<w-affix :offset-top="offsettop">
<div class="info">
<div class="name">
<div style="display: flex;align-items: center;margin-bottom: 8px;">
<div class="title">{{ title }}</div>
<div class="address">{{ job }}</div>
</div>
<div class="identity">
{{ introduction }}现任{{ job }}
</div>
</div>
</div>
</w-affix>
</div>
</template>
<script>
export default {
name: 'PersonInformation',
props: {
offsettop: Number,
title: String,
job: String,
introduction: String
},
data() {
return {
};
},
methods: {
},
created() {
},
mounted() {
// bus.$on('name', val => {
// this.name = val;
// });
// bus.$on('job', val => {
// this.job = val;
// });
// bus.$on('introduction', val => {
// this.introduction = val;
// });
}
};
</script>
<style lang='less' scoped>
.info {
display: flex;
justify-content: space-between;
width: 100%;
padding: 14px 24px;
background: url(../../assets/image/detail_title_bg.a6a1e552.png) no-repeat;
border-radius: 4px;
.name {
.title {
font-size: 30px;
height: 38px;
line-height: 38px;
margin-right: 8px;
color: #303133;
}
.address {
width: 600px;
height: 24px;
font-size: 22px;
line-height: 24px;
color: #8A909A;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.identity {
width: 600px;
height: 24px;
line-height: 24px;
color: #272A31;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: var(--font-size-default);
}
}
}
.w-affix__fixed .info{
box-shadow: 0 2px 10px 0 rgb(0 0 0 / 12%);
}
</style>

161
src/components/PeoplePoolPage/photo-video.vue

@ -1,84 +1,29 @@
<template>
<div class="PhotoVideo">
<div class="top">
<div class="image">
<img src="../../assets/image/down.png" alt="">
</div>
<div class="title">
图册视频
</div>
</div>
<div class="video">
<div class="item">
<div class="item-video">
<video src="http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4" controls="controls" width="100%" height="100%"></video>
<div style="display: flex;align-items: center;">
<div class="image">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="video-title">
[中国新闻]民进党大败 蔡英
<div class="title">
图册视频
</div>
<div class="time">
<span style="margin-right: 24px;">央视网</span>
<span>2022-11-27</span>
</div>
</div>
<div class="item">
<div class="item-video">
<video src="http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4" controls="controls" width="100%" height="100%"></video>
</div>
<div class="video-title">
[中国新闻]民进党大败 蔡英
</div>
<div class="time">
<span style="margin-right: 24px;">央视网</span>
<span>2022-11-27</span>
</div>
</div>
<div class="item">
<div class="item-video">
<video src="http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4" controls="controls" width="100%" height="100%"></video>
</div>
<div class="video-title">
[中国新闻]民进党大败 蔡英
</div>
<div class="time">
<span style="margin-right: 24px;">央视网</span>
<span>2022-11-27</span>
</div>
</div>
<div class="item">
</div>
<div class="video">
<div v-for="(item, index) in videolist" :key="index" class="item">
<div class="item-video">
<video src="http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4" controls="controls" width="100%" height="100%"></video>
<video :src="item.url" controls="controls" width="100%" height="100%"></video>
</div>
<div class="video-title">
[中国新闻]民进党大败 蔡英
{{ item.title }}
</div>
<div class="time">
<span style="margin-right: 24px;">央视网</span>
<span>2022-11-27</span>
</div>
<span style="margin-right: 24px;"> {{ item.source }}</span>
<span> {{ item.time }}</span>
</div>
<div class="item">
<div class="item-video">
<video src="http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4" controls="controls" width="100%" height="100%"></video>
</div>
<div class="video-title">
[中国新闻]民进党大败 蔡英
</div>
<div class="time">
<span style="margin-right: 24px;">央视网</span>
<span>2022-11-27</span>
</div>
</div>
@ -88,21 +33,68 @@
</template>
<script>
export default {
name: 'PhotoVideo'
name: 'PhotoVideo',
data() {
return {
videolist: [
{
url: 'http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4',
title: '[中国新闻]民进党大败 蔡蔡英蔡英蔡英',
source: '央视网',
time: '2022-11-27'
},
{
url: 'http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4',
title: '[中国新闻]民进党大败 蔡蔡英蔡英蔡英',
source: '央视网',
time: '2022-11-27'
},
{
url: 'http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4',
title: '[中国新闻]民进党大败 蔡蔡英蔡英蔡英',
source: '央视网',
time: '2022-11-27'
},
{
url: 'http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4',
title: '[中国新闻]民进党大败 蔡蔡英蔡英蔡英',
source: '央视网',
time: '2022-11-27'
},
{
url: 'http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4',
title: '[中国新闻]民进党大败 蔡蔡英蔡英蔡英',
source: '央视网',
time: '2022-11-27'
},
{
url: 'http://qscloudhongqi.wengegroup.com:8387/bucketeducation/63b4288ff0567a70f00965d1.mp4',
title: '[中国新闻]民进党大败 蔡蔡英蔡英蔡英',
source: '央视网',
time: '2022-11-27'
}
]
};
},
mounted() {
if (this.$route.path.includes('peoplePoolDeatil')) {
this.videolist = this.videolist.splice(0, 5);
}
}
};
</script>
<style lang='less' scoped>
.PhotoVideo {
width: 100%;
// min-height: 350px !important;
// margin-top: 16px;
color: #303133;
font-size: 16px;
font-size: var(--font-size-default);
padding: 24px;
.top {
display: flex;
align-items: center;
justify-content: space-between;
.image {
width: 18px;
@ -115,28 +107,29 @@ export default {
}
.title {
font-size: 18px;
font-size: var(--font-size-medium);
line-height: 26px;
font-weight: 500;
}
}
.video {
padding: 24px 30px 0px 30px;
display: flex;
justify-content: space-between;
padding: 24px 20px 0px 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 12px;
// grid-auto-flow: column;
.item {
width: 216px;
// height: 200px;
// background-color: red;
width: 100%;
.item-video {
width: 100%;
height: 120px;
border-radius: 4px;
// background-color: aqua;
margin-bottom: 16px;
video{
video {
border-radius: 4px;
}
}
@ -150,12 +143,14 @@ export default {
white-space: nowrap;
margin-bottom: 6px;
}
.time{
.time {
color: #909399;
font-size: 14px;
font-size: var(--font-size-small);
line-height: 18px;
}
}
}
}</style>
}
</style>

129
src/components/PeoplePoolPage/platform-dynamics.vue

@ -2,7 +2,7 @@
<div class="PlatformDynamics">
<div class="top">
<div class="image">
<img src="../../assets/image/down.png" alt="">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
社交平台发文动态
@ -11,16 +11,79 @@
</div>
<div class="content">
<w-tabs v-model="activeName" class="tabs" @tab-click="handleClick">
<w-tab-pane label="全部(300)" name="first">全部X</w-tab-pane>
<w-tab-pane label="Facebook(150)" name="second">
<w-tab-pane label="全部 (300)" name="first">
<w-timeline style="padding-left: 135px;">
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
<div class="item-bottom">
已经慰问过凃明诚和曹瑞杰家属相当不舍同时也已经指示行政机构和相关部会加速警械使用条例修法
</div>
</div>
</w-timeline-item>
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
<div class="item-bottom">
欢迎美国好朋友来访台湾当天上午接见了窜访团窜访团是美国国会的重量级议员是重要的好朋友
</div>
</div>
</w-timeline-item>
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
<div class="item-bottom">
Now it is my turn to extend congratulations to JoeBiden
</div>
</div>
</w-timeline-item>
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
<div class="item-bottom">
50.4万剂辉瑞儿童疫苗已到货截至当日已有超百万人次5到11岁儿童接种了第一剂疫苗大家继续一起努力疫情定会逐渐趋缓
</div>
</div>
</w-timeline-item>
</w-timeline>
</w-tab-pane>
<w-tab-pane label="Facebook (150)" name="second">
<w-timeline style="padding-left: 135px;">
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div>
<span style="font-size: 14px;color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="font-size: 14px;color: #909399 ;">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
@ -32,9 +95,10 @@
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div>
<span style="font-size: 14px;color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="font-size: 14px;color: #909399 ;">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
@ -46,9 +110,10 @@
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div>
<span style="font-size: 14px;color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="font-size: 14px;color: #909399 ;">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
@ -60,9 +125,10 @@
<w-timeline-item class="timeline">
<div class="item">
<div class="item-top">
<div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div>
<span style="font-size: 14px;color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="font-size: 14px;color: #909399 ;">
<!-- <div style="margin-right: 11px;"><CoolAspectRatioLine size="15" color="#2055F4"/></div> -->
<span style="color: #2055F4;margin-right: 30px;">蔡英文</span>
<div style="color: #909399 ;">
互动量2150
</div>
</div>
@ -73,10 +139,10 @@
</w-timeline-item>
</w-timeline>
</w-tab-pane>
<w-tab-pane label="Twitter(50)" name="third">TwitterX</w-tab-pane>
<w-tab-pane label="Youtube(20)" name="fourth">YoutubeX</w-tab-pane>
<w-tab-pane label="Instagram(30)" name="fifth">InstagramX</w-tab-pane>
<w-tab-pane label="TikTok(100)" name="sixth">TikTokX</w-tab-pane>
<w-tab-pane label="Twitter (50)" name="third">Twitter(X)</w-tab-pane>
<w-tab-pane label="Youtube (20)" name="fourth">Youtube(X)</w-tab-pane>
<w-tab-pane label="Instagram (30)" name="fifth">Instagram(X)</w-tab-pane>
<w-tab-pane label="TikTok (100)" name="sixth">TikTok(X)</w-tab-pane>
</w-tabs>
</div>
</div>
@ -91,7 +157,6 @@ export default {
},
methods: {
handleClick(tab, event) {
console.log(tab, event);
}
}
};
@ -99,10 +164,9 @@ export default {
<style lang='less' scoped>
.PlatformDynamics {
width: 100%;
// margin-top: 16px;
color: #303133;
font-size: 16px;
padding: 24px;
min-height: 500px;
.top {
display: flex;
@ -119,8 +183,9 @@ export default {
}
.title {
font-size: 18px;
font-size: var(--font-size-medium);
line-height: 26px;
font-weight: 500;
}
}
@ -129,11 +194,12 @@ export default {
.tabs {
::v-deep.w-tabs__header {
margin: 0 0 24px !important;
margin: 0 0 20px !important;
}
::v-deep.w-tabs__content {
padding: 0 10px 0 20px;
padding: 5px 10px 0 20px;
overflow: none;
}
.timeline {
@ -142,15 +208,19 @@ export default {
display: flex;
align-items: center;
margin-bottom: 4px;
font-size: var(--font-size-small);
}
.item-bottom{
width: 100%;
height: 41px;
line-height: 41px;
border: 1px solid #DDDFE8 ;
border-radius: 4px;
font-size: 16px;
padding-left: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-color: #F6F7F9;
font-size: var(--font-size-default);
}
}
}
@ -160,10 +230,13 @@ export default {
position: absolute;
top: -5px;
left: -140px;
font-size: 16px;
font-size: var(--font-size-default);
color: #909399;
}
}
::v-deep.w-tabs__item {
font-size: var(--font-size-small);
}
}
}
</style>

457
src/components/PeoplePoolPage/recommendation.vue

@ -0,0 +1,457 @@
<template>
<div class="recommendation">
<!-- <div class="top">
{{ content }}
</div> -->
<w-tabs v-model="content" type="card" class="tablist">
<w-tab-pane label="智能推荐" name="智能推荐">
<div class="intelligent">
<w-card class="card">
<div class="card-content">
<div class="name">
<w-avatar src='http://winbox.wenge.com/static/external_images/212516-15666531161ade.jpg'
:size="32"></w-avatar>
<span style="color:#2055F4; line-height: 24px;margin-left: 10px;">阿利娅·加尼姆</span>
</div>
<div style="margin-bottom: 16px;">
<span style="color:#909399;margin-right: 15px;">扩线依据</span>
<span>基于组织</span>
</div>
<div class="cause">
<span style="color:#909399;margin-right: 15px;">原因分析</span>
<div>阿利娅·加尼姆与当前目标同属一个组织<br><span style="color:#2055F4;">基地组织</span></div>
</div>
</div>
</w-card>
<w-card class="card">
<div class="card-content">
<div class="name">
<w-avatar src='http://winbox.wenge.com/static/external_images/212516-15666531161ade.jpg'
:size="32"></w-avatar>
<span style="color:#2055F4; line-height: 24px;margin-left: 10px;">法赫德·库索</span>
</div>
<div style="margin-bottom: 16px;">
<span style="color:#909399;margin-right: 15px;">扩线依据</span>
<span>基于事件</span>
</div>
<div class="cause">
<span style="color:#909399;margin-right: 15px;">原因分析</span>
<div>法赫德·库索与当前目标共同参与过事件<br><span style="color:#2055F4;">拉子市恐怖袭击事件</span></div>
</div>
</div>
</w-card>
</div>
</w-tab-pane>
<w-tab-pane label="实体统计" name="实体统计">
<div class="thing">
<w-card class="card" style="margin-bottom: 16px;">
<div class="content">
<div class="title">
<CoolArrowDownSLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name">实体</div>
</div>
<div class="num">
85
</div>
</div>
<div class="item">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name">人物</div>
</div>
<div class="num">
50
</div>
</div>
<div class="item">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name">组织机构</div>
</div>
<div class="num">
15
</div>
</div>
<div class="item">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name" style="color: #909399;">事件</div>
</div>
<div class="num">
10
</div>
</div>
<div class="content">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name" style="color: #909399;">社交账号</div>
</div>
<div class="num">
10
</div>
</div>
</w-card>
<w-card class="card">
<div class="content">
<div class="title">
<CoolArrowDownSLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name">实体</div>
</div>
<div class="num">
85
</div>
</div>
<div class="item">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name">人物</div>
</div>
<div class="num">
50
</div>
</div>
<div class="item">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name">组织机构</div>
</div>
<div class="num">
15
</div>
</div>
<div class="item">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name" style="color: #909399;">事件</div>
</div>
<div class="num">
10
</div>
</div>
<div class="content">
<div class="title">
<CoolEyeLine size="15" color="#5A606B " style="margin-right: 8px;" />
<div class="name" style="color: #909399;">社交账号</div>
</div>
<div class="num">
10
</div>
</div>
</w-card>
</div>
</w-tab-pane>
<w-tab-pane label="节点信息" name="节点信息">
<div class="information">
<w-card class="card">
<div class="card-content">
<div class="name">
<w-avatar src='http://winbox.wenge.com/static/external_images/212516-15666531161ade.jpg'
:size="32"></w-avatar>
<span style="color:#2055F4; line-height: 24px;margin-left: 10px;">阿利娅·加尼姆</span>
</div>
<div v-for="(item, index) in infoList" :key="index" class="item">
<div class="title">{{ item.title }}</div>
<div class="info" :style="{ color: item.title === 'KB组织' ? '#2055F4' : '#303133 ' }">{{ item.contenet }}
</div>
</div>
</div>
</w-card>
</div>
</w-tab-pane>
</w-tabs>
</div>
</template>
<script>
export default {
name: 'Recommendation',
components: {
},
data() {
return {
content: '智能推荐',
infoList: [
{
title: '扩线依据',
contenet: '基于组织'
},
{
title: '姓名',
contenet: '阿尔祖玛'
},
{
title: '外文名',
contenet: 'Oaeda.*.:'
},
{
title: '别名',
contenet: '别名'
},
{
title: '信仰',
contenet: '伊斯兰教-逊尼派-瓦哈比派'
},
{
title: '国籍',
contenet: '美国'
},
{
title: 'KB组织',
contenet: '基地组织'
},
{
title: '出生日期',
contenet: '1959年4月9日'
},
{
title: '出生地',
contenet: '伊拉克'
}
]
};
}
};
</script>
<style lang='less' scoped>
.recommendation {
width: 100%;
// border: 1px solid #DDDFE8;
min-height: 570px;
border-right: none;
background-color: #F9FAFB;
padding: 12px;
.tablist {
width: 100%;
.intelligent {
.card {
margin-bottom: 16px;
.card-content {
font-size: var(--font-size-small);
color: #303133;
.name {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.cause {
display: flex;
line-height: 24px;
}
}
}
}
.thing {
font-size: var(--font-size-small);
.content {
display: flex;
align-items: center;
margin-bottom: 16px;
.title {
display: flex;
align-items: center;
margin-right: 16px;
.name {
width: 56px;
height: 24px;
line-height: 24px;
}
}
.num {
width: 56px;
height: 24px;
line-height: 24px;
text-align: center;
border-radius: 2px;
border: 1px solid #DDDFE8;
background-color: #FFFFFF;
color: #272A31;
}
}
.item {
display: flex;
align-items: center;
margin-bottom: 16px;
.title {
display: flex;
align-items: center;
margin-right: 16px;
.name {
width: 56px;
height: 24px;
line-height: 24px;
color: #909399;
}
}
.num {
width: 56px;
height: 24px;
line-height: 24px;
text-align: center;
border-radius: 2px;
border: 1px solid #DDDFE8;
background-color: #FFFFFF;
color: #272A31;
}
}
}
.information {
font-size: var(--font-size-small);
.card-content {
color: #303133;
.name {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.item {
display: flex;
align-items: center;
margin-bottom: 16px;
.title {
color: #909399;
width: 56px;
height: 24px;
line-height: 24px;
margin-right: 15px;
}
.info {
height: 24px;
line-height: 24px;
}
}
.cause {
display: flex;
line-height: 24px;
}
}
}
::v-deep.w-tabs__nav {
width: 100%;
display: flex;
align-items: center;
}
// // ::v-deep.w-tabs__item {
// // writing-mode: vertical-lr;
// // min-height: 184px;
// // padding: 0 !important;
// // text-align: center;
// // background-color: #FFFFFF;
// font-size: var(--font-size-default);
// // }
// ::v-deep.w-tabs__content {
// padding: 16px 0px 16px 16px;
// overflow-y: auto;
// max-height: 550px;
// }
}
}
::v-deep.w-tabs--card>.w-tabs__header .w-tabs__item {
border: none !important;
width: 100%;
min-width: 25%;
max-width: 100%;
text-align: center;
background: #F0F6FF;
color: #2055F4;
margin-left: 0px;
border-radius:0;
font-size: var(--font-size-default);
}
::v-deep.w-tabs--card>.w-tabs__header .w-tabs__item:first-child{
border-radius: 2px 0 0 2px;
}
::v-deep.w-tabs--card>.w-tabs__header .w-tabs__item:last-child{
border-radius: 0px 2px 2px 0px;
}
::v-deep.w-tabs--card>.w-tabs__header .w-tabs__item.is-active{
background-color: #2055F4;
color: #FFFFFF;
}
// ::v-deep.w-tabs--right .w-tabs__header.is-right{
// margin-left: 16px;
// }
// ::v-deep.w-tabs--card>.w-tabs__header .w-tabs__item {
// margin-left: 0px;
// border-radius: 0px !important;
// }
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__nav {
// border-bottom: none;
// }
::v-deep.w-tabs--card>.w-tabs__header {
border-bottom: none;
}
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__item.is-right {
// border: 1px solid #DDDFE8;
// border-bottom: 1px solid #DDDFE8;
// border-top: none;
// }
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__item.is-right:last-child {
// border-bottom: none;
// }
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__item.is-right:first-child {
// border-left: 1px solid #DDDFE8;
// }
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__item.is-right.is-active:first-child {
// border: 1px solid #2055F4;
// }
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__item.is-right.is-active {
// border: 1px solid #2055F4;
// border-bottom: 1px solid #2055F4;
// background-color: #F0F6FF;
// }
// ::v-deep.w-tabs--right.w-tabs--card .w-tabs__item.is-right.is-active:last-child {
// border-bottom: 1px solid #2055F4;
// // background-color: #F0F6FF;
// }
::v-deep.w-card {
border-radius: 4px;
border: none;
// box-shadow: 0 2px 10px 0 rgb(0 0 0 / 12%);
}
</style>

32
src/components/PeoplePoolPage/relationship.vue

@ -0,0 +1,32 @@
<template>
<div>
<GraphIndex :d3-data="d3data"
:graph-type="['gForce', 'dagreLR', 'dagreRL', 'dagreTB', 'grid', 'gridRows', 'gridCols', 'concentric']"
:select-type="['brushSelect', 'lassoSelect']" />
</div>
</template>
<script>
import GraphIndex from '@/components/graphContainer/GraphIndex.vue';
import { getAnlysis } from '@/api/peoplePool';
export default {
components: {
GraphIndex
},
data() {
return {
d3data: {}
};
},
methods: {
getData(){
getAnlysis().then(res => {
this.d3data = res.data.d3data;
});
}
},
mounted() {
this.getData();
}
};
</script>

670
src/components/PeoplePoolPage/search.vue

@ -9,64 +9,91 @@
<w-input v-model="input" placeholder="请输入关键字"></w-input>
</div>
<div class="btnGroup">
<w-button type='primary' style="width: 80px;">搜索</w-button>
<w-button type='primary' style="width: 80px;" @click="search">搜索</w-button>
<w-button style="width: 80px;">重置</w-button>
<w-button style="width: 112px;">保存主题</w-button>
</div>
</div>
<div class="inputBox searchBox" :style="{ display: isFold ? 'block' : 'none' }">
<span class="outInfo">
<span class="leftInfo">地区</span>
<span class="rightInfo">全球</span>
</span>
<span class="outInfo">
<span class="leftInfo">国家</span>
<span class="rightInfo">全部</span>
</span>
</div>
<div :style="{ display: isFold ? 'none' : 'block' }">
<div class="checkBox">
<div class="searchName">
入库时间
</div>
<div class="content">
<div v-for="(item, index) in timeList" :key="index" class="singleCtn"
:class="{ 'actvCss': index === timeIndex }" @click="handleCheckTime(item, index)">
{{ item }}
</div>
</div>
<div class="date">
<w-date-picker v-model="value" style="width: 284px;height: 32px;" type="datetimerange" start-placeholder="开始日期" end-placeholder="结束日期">
</w-date-picker>
</div>
<div class="options">
<div class="inputBox searchBox">
<span class="outInfo">
<span class="leftInfo">地区</span>
<span class="rightInfo">全球</span>
</span>
<span class="outInfo">
<span class="leftInfo">国家</span>
<span class="rightInfo">全部</span>
</span>
</div>
<div v-for="(item, index) in searchList" :key="index" class="checkBox">
<div class="searchName">
{{ item.type }}
<div :style="{ opacity: isFold ? 0 : 1 }">
<div class="formData">
<div class="searchName">
入库时间
</div>
<div class="content">
<div v-for="(item, index) in timeList" :key="index" class="singleCtn"
:class="{ 'actvCss': index === timeIndex }" @click="handleCheckTime(item, index)">
{{ item }}
</div>
</div>
<div class="date">
<w-date-picker v-model="value" style="height: 32px;" type="datetimerange" start-placeholder="开始日期"
end-placeholder="结束日期" @change="onChange">
</w-date-picker>
</div>
</div>
<div class="content">
<div v-for="(m, idx) in item.content" :key="idx" class="singleCtn" :class="{ 'actvCss': m.active }"
@click="handle(item.content, m)">
{{ m.name }}
<div v-for="(item, index) in searchList" :key="index" class="formData">
<div class="searchName">
{{ item.label }}
</div>
<div v-if="item.range.type === 'checkbox'" class="content">
<div :id="'item_' + index" class="singleCtn " :class="{ actvCss: !item.propertyValue.length }"
@click="clickAll(index)">
全部
</div>
<w-checkbox-group v-model="item.propertyValue" size="small" @change="handleChange">
<w-checkbox-button v-for="(m, idx) in item.range.data" :key="idx" :label="m.name">{{
m.name }}</w-checkbox-button>
</w-checkbox-group>
</div>
<div v-if="item.range.type === 'radio'" class="content">
<div :id="'item_' + index" class="singleCtn " :class="{ actvCss: !item.propertyValue.length }"
@click="clickAll(index)">
全部
</div>
<w-radio-group v-model="item.propertyValue" size='small' @change="radioChange">
<w-radio-button v-for="(m, idx) in item.range.data" :key="idx" l :label="m.name">{{ m.name
}}</w-radio-button>
</w-radio-group>
</div>
</div>
</div>
</div>
<div class="foldBtn" @click="handleFold">
<CoolArrowUpDLine v-if="!isFold" size="15" color="#2055f4"/>
<CoolArrowDownDLine v-if="isFold" size="15" color="#2055f4"/>
<span style="cursor: pointer;">{{ isFold ? '展开检索条件' : '收起检索条件' }}</span>
<!-- <svg data-v-fe646246="" data-v-27ca5bc2="" aria-hidden="true" class="svg-icon">
<use data-v-fe646246="" xlink:href="#icon-iconexpand"></use>
</svg> -->
<div class="foldBtn">
<div style="display: flex;align-items: center;" @click="handleFold">
<div style="display: flex;align-items: center;">
<CoolArrowUpDLine v-if="!isFold" size="15" color="#2055f4" />
<CoolArrowDownDLine v-if="isFold" size="15" color="#2055f4" />
</div>
<span style="cursor: pointer;">{{ isFold ? '展开检索条件' : '收起检索条件' }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
import common from '@/utils/common';
import { getList } from '@/api/peoplePool';
export default {
name: 'Search',
components: {
@ -74,233 +101,298 @@ export default {
},
data() {
return {
radio1: '',
input: '',
timeIndex: 0,
timeList: ['全部', '近三天', '近一周', '近一月', '近三月'],
searchList: [
{
type: '人物类型',
content: [
{
name: '全部',
active: !0,
id: ''
},
{
name: '社交博主',
active: !1,
id: 1
}, {
name: '记者',
active: !1,
id: 2
}, {
name: '政要',
active: !1,
id: 3
}, {
name: '导演',
active: !1,
id: 4
}, {
name: '编剧',
active: !1,
id: 5
}, {
name: '其他',
active: !1,
id: 6
}
]
label: '人物类型',
range: {
type: 'checkbox',
data: [
{
name: '社交博主',
id: 1
}, {
name: '记者',
id: 2
}, {
name: '政要',
id: 3
}, {
name: '导演',
id: 4
}, {
name: '编剧',
id: 5
}, {
name: '其他',
id: 6
}
]
},
propertyValue: [],
id: '65773e4da1500c9fc697c32e84785a27',
name: '类型',
data_type: 'STRING',
data_range: null,
isConcept: false
},
{
type: '所属国籍',
content: [
{
name: '全部',
active: !0,
id: ''
}, {
name: '中国',
active: !1,
id: 1
}, {
name: '美国',
active: !1,
id: 2
}, {
name: '韩国',
active: !1,
id: 3
}, {
name: '日本',
active: !1,
id: 4
}, {
name: '朝鲜',
active: !1,
id: 5
}, {
name: '缅甸',
active: !1,
id: 6
}, {
name: '印度',
active: !1,
id: 7
}, {
name: '老挝',
active: !1,
id: 8
}, {
name: '越南',
active: !1,
id: 9
}, {
name: '阿富汗',
active: !1,
id: 10
}
]
label: '所属国籍',
range: {
type: 'radio',
data: [
{
name: '中国',
id: 1
}, {
name: '美国',
id: 2
}, {
name: '韩国',
id: 3
}, {
name: '日本',
id: 4
}, {
name: '朝鲜',
id: 5
}, {
name: '缅甸',
id: 6
}, {
name: '印度',
id: 7
}, {
name: '老挝',
id: 8
}, {
name: '越南',
id: 9
}, {
name: '阿富汗',
id: 10
}
]
},
propertyValue: '',
id: '04cfca4b13b96ea7c677a9f9f939cd86',
name: '国家地区',
data_type: 'TEXT',
data_range: null,
isConcept: false
},
{
type: '所属组织',
content: [
{
name: '全部',
active: !0,
id: ''
}, {
name: '台湾民众党',
active: !1,
id: 1
}, {
name: '民主进步党',
active: !1,
id: 2
}, {
name: '中国国民党',
active: !1,
id: 3
}, {
name: '美国民主党',
active: !1,
id: 4
}, {
name: '日本自由民主党',
active: !1,
id: 5
}, {
name: '韩国国民力量党',
active: !1,
id: 6
}
]
label: '所属组织',
range: {
type: 'checkbox',
data: [
{
name: '台湾民众党',
id: 1
}, {
name: '民主进步党',
id: 2
}, {
name: '中国国民党',
id: 3
}, {
name: '美国民主党',
id: 4
}, {
name: '日本自由民主党',
id: 5
}, {
name: '韩国国民力量党',
id: 6
}
]
},
propertyValue: [],
id: 'd0c0aad66c1f148868d6fca7588afa05',
name: '所属组织',
data_type: 'TEXT',
data_range: null,
isConcept: false
},
{
type: '活跃等级',
content: [
{
name: '全部',
active: !0,
id: ''
}, {
name: '高',
active: !1,
id: 1
}, {
name: '中',
active: !1,
id: 2
}, {
name: '低',
active: !1,
id: 3
}
]
label: '活跃等级',
range: {
type: 'checkbox',
data: [
{
name: '高',
id: 1
}, {
name: '中',
id: 2
}, {
name: '低',
id: 3
}
]
},
propertyValue: [],
id: 'edbcfc54ca1f151244382ef7d0980b42',
name: '风险等级',
data_type: 'LONG',
data_range: null,
isConcept: false
},
{
type: '对华态度',
content: [
{
name: '全部',
active: !0,
id: ''
}, {
name: '对华友好',
active: !1,
id: 1
}, {
name: '对华强硬',
active: !1,
id: 2
}, {
name: '对华模糊',
active: !1,
id: 3
}, {
name: '无法判断',
active: !1,
id: 4
}
]
label: '对华态度',
range: {
type: 'checkbox',
data: [
{
name: '对华友好',
id: 1
}, {
name: '对华强硬',
id: 2
}, {
name: '对华模糊',
id: 3
}, {
name: '无法判断',
id: 4
}
]
},
propertyValue: [],
id: '5a718b22c323073e65f75192f74e0802',
name: '对华态度',
data_type: 'STRING',
data_range: null,
isConcept: false
},
{
type: '人物现状',
content: [
{
name: '全部',
active: !0,
id: ''
}, {
name: '在世',
active: !1,
id: 1
}, {
name: '死亡',
active: !1,
id: 2
}
]
label: '人物现状',
range: {
type: 'checkbox',
data: [
{
name: '在世',
id: 1
}, {
name: '死亡',
id: 2
}
]
},
propertyValue: [],
id: '217b42036ef15d085ae3a5e77c4faf3a',
name: '人物现状',
data_type: 'LONG',
data_range: null,
isConcept: false
}
],
isFold: false,
value: '',
systemDate: this.$moment().format('YYYY-MM-DD HH:mm:ss')
systemDate: this.$moment().format('YYYY-MM-DD HH:mm:ss'),
searchForm: {
startDate: '',
endDate: '',
entityFilter: [
],
keyWord: '',
type: 'exact',
pageSize: 10,
pageNum: 1
},
checkList: [],
peoplelist: []
};
},
methods: {
handleChange(e) {
},
radioChange(e) {
},
clickAll(i) {
this.searchList[i].propertyValue = [];
},
search() {
bus.$emit('isEmpty', true);
bus.$emit('loading', true);
this.searchForm.keyWord = this.input;
this.checkList = this.searchList;
const result = [];
this.checkList.forEach((item, index) => {
if (item.propertyValue.length) {
result.push(this.checkList[index]);
}
});
result.forEach((item1, index1) => {
const newObj = JSON.parse(JSON.stringify(item1, ['label', 'range', 'propertyValue', 'id', 'name', 'data_type', 'data_range', 'isConcept']));
delete newObj.label;
delete newObj.range;
// const newObj = {};
// for (const key in item1) {
// if (key !== 'range' && key !== 'label') {
// newObj[key] = item1[key];
// }
// }
result[index1] = newObj;
});
this.searchForm.entityFilter = result;
console.log(this.searchForm);
getList().then(response => {
this.peoplelist = response.data.data;
bus.$emit('load', false);
bus.$emit('list', this.peoplelist);
});
},
handleCheckTime(m, i) {
this.timeIndex = i;
if (m == '全部'){
if (m == '全部') {
this.value = [];
} else if (m == '近三天'){
this.searchForm.startDate = '';
this.searchForm.endDate = '';
} else if (m == '近三天') {
this.value = [this.$moment().day(this.$moment().day() - 3).format('YYYY-MM-DD HH:mm:ss'), this.systemDate];
} else if (m == '近一周'){
this.searchForm.startDate = this.value[0];
this.searchForm.endDate = this.value[1];
} else if (m == '近一周') {
this.value = [this.$moment().day(this.$moment().day() - 6).format('YYYY-MM-DD HH:mm:ss'), this.systemDate];
} else if (m == '近一月'){
this.searchForm.startDate = this.value[0];
this.searchForm.endDate = this.value[1];
} else if (m == '近一月') {
this.value = [this.$moment(new Date()).subtract(1, 'months').format('YYYY-MM-DD HH:mm:ss'), this.systemDate];
this.searchForm.startDate = this.value[0];
this.searchForm.endDate = this.value[1];
} else {
this.value = [this.$moment(new Date()).subtract(3, 'months').format('YYYY-MM-DD HH:mm:ss'), this.systemDate];
this.searchForm.startDate = this.value[0];
this.searchForm.endDate = this.value[1];
}
},
handle(e, i) {
i.active = !i.active;
if (i.name == '全部') {
e.forEach(item => {
item.active = !1;
});
e[0].active = !0;
handleFold() {
this.isFold = !this.isFold;
const optionsNode = document.querySelector('.options');
const dom = document.querySelector('.searchBox');
if (this.isFold) {
optionsNode.classList.add('unfold');
dom.classList.add('block');
dom.classList.add('visible');
} else {
e[0].active = 0;
optionsNode.classList.remove('unfold');
dom.classList.remove('visible');
dom.classList.remove('block');
}
},
handleFold() {
this.isFold = !this.isFold;
onChange(e) {
this.searchForm.startDate = common.formatDate(e[0]);
this.searchForm.endDate = common.formatDate(e[1]);
}
}
};
@ -308,41 +400,53 @@ export default {
<style lang='less' scoped>
.searchCondition {
background: url(../../assets/image/search_bg.95a43f86.png) no-repeat top;
background-color: linear-gradient(#FFFFFF 0%, #FFFFFF 44%, #FFFFFF 100%);
background-position-y: -2px;
background-position-x: -2px;
background-size: cover;
// background-position-y: -2px;
// background-position-x: -2px;
margin-top: 10px;
border-radius: 4px;
font-size: 14px;
font-size:var(--font-size-small);
color: #606266;
border: 2px solid;
border-image: linear-gradient(#FFFFFF 100%, #FFFFFF 0%);
.searchContent {
padding: 40px 32px 24px 32px;
border-radius: 4px;
overflow: hidden;
.options {
transition: all .3s;
max-height: 350px;
overflow: hidden;
}
.unfold {
max-height: 40px;
}
.inputBox {
display: flex;
align-items: center;
justify-content: space-between;
// justify-content: space-between;
margin-bottom: 16px;
white-space: nowrap;
.inputBoxLf {
display: flex;
align-items: center;
width: 77%;
// margin-right: 3%;
margin-right: 24px;
.searchName {
width: 75px;
flex-shrink: 0;
margin-right: 19px;
letter-spacing: 1px;
}
}
.btnGroup {
.w-button {
font-size: var(--font-size-small);
margin-right: 24px;
}
@ -354,6 +458,8 @@ export default {
.searchBox {
margin: 18px 0 10px 95px;
display: none;
opacity: 0;
.outInfo {
background: rgba(32, 85, 244, .05);
@ -367,14 +473,25 @@ export default {
}
}
.checkBox {
.block {
display: block;
}
.visible {
opacity: 1;
transition: opacity 1s ease;
}
.formData {
display: flex;
align-items: center;
// margin-top: 20px;
height: 48px;
white-space: nowrap;
.searchName {
margin-right: 24px
margin-right: 24px;
letter-spacing: 1px;
}
.content {
@ -389,17 +506,80 @@ export default {
.actvCss {
background: rgba(32, 85, 244, .05);
color: #2055f4;
color: #2055f4 !important;
}
}
::v-deep .w-checkbox-button--small .w-checkbox-button__inner {
border: none !important;
padding: 0 10px;
border-radius: 4px;
margin-right: 24px;
cursor: pointer;
height: 26px;
display: flex;
align-items: center;
color: #606266;
font-size: var(--font-size-small);
}
::v-deep .w-checkbox-button__inner:hover {
color: #606266;
}
::v-deep.w-checkbox-button.is-checked .w-checkbox-button__inner {
background: rgba(32, 85, 244, .05);
color: #2055f4;
box-shadow: none;
}
::v-deep .w-radio-button--small .w-radio-button__inner {
border: none !important;
padding: 0 10px;
border-radius: 4px;
margin-right: 24px;
cursor: pointer;
height: 26px;
display: flex;
align-items: center;
color: #606266;
font-size: var(--font-size-small);
}
::v-deep .w-radio-button__inner:hover {
color: #606266;
}
::v-deep.w-radio-button__orig-radio:checked+.w-radio-button__inner {
background: rgba(32, 85, 244, .05);
color: #2055f4;
box-shadow: none;
}
}
.foldBtn {
color: #2055f4;
text-align: center;
margin-top: 16px;
display: flex;
align-items: center;
justify-content: center;
}
}
::v-deep.cool-icon {
display: flex;
align-items: center;
}
}
::v-deep .w-button+.w-button {
margin-left: 0px;
color: #606266;
font-size: var(--font-size-small);
}
</style>

56
src/components/PeoplePoolPage/social-analysis.vue

@ -1,28 +1,52 @@
<template>
<div class="SocialAnalysis">
<div class="top">
<div class="top" style="margin-bottom: 16px;">
<div class="image">
<img src="../../assets/image/down.png" alt="">
<img src="../../assets/image/down.svg" alt="">
</div>
<div class="title">
社交分析与扩线
</div>
</div>
<div style="color: #303133 ;font-size: 13px;">
<w-radio v-model="radio" label="1">已认定为恐怖势力</w-radio>
<w-radio v-model="radio" label="2">网络社交账号</w-radio>
<w-radio v-model="radio" label="3">其他</w-radio>
</div>
<div class="content">
<div class="left">
<relationship></relationship>
</div>
<div class="right">
<recommendation></recommendation>
</div>
</div>
</div>
</template>
<script>
import recommendation from './recommendation.vue';
import relationship from './relationship.vue';
export default {
name: 'SocialAnalysis'
name: 'SocialAnalysis',
components: {
relationship,
recommendation
},
data() {
return {
radio: '1'
};
}
};
</script>
<style lang='less' scoped>
.SocialAnalysis{
.SocialAnalysis {
width: 100%;
// margin-top: 16px;
color: #303133;
font-size: 16px;
padding: 24px;
.top {
display: flex;
align-items: center;
@ -38,10 +62,26 @@ export default {
}
.title {
font-size: 18px;
font-size: var(--font-size-medium);
line-height: 26px;
font-weight: 500;
}
}
}
.content {
padding-top: 16px;
display: flex;
justify-content: space-between;
.left {
width: 59%;
margin-right: 16px;
}
.right {
// max-width: 39%;
flex: 1;
}
}
}
</style>

34
src/components/PeoplePoolPage/tracing-point.vue

@ -0,0 +1,34 @@
<template>
<w-anchor :offset-top="size" :get-container='getContainer' :target-offset="targetOffset" @click="handleClick">
<w-anchor-link href="#content-item0" title="人物简介"></w-anchor-link>
<w-anchor-link href="#content-item1" title="图册视频"></w-anchor-link>
<w-anchor-link href="#content-item2" title="新闻资讯"></w-anchor-link>
<w-anchor-link href="#content-item3" title="描述"></w-anchor-link>
<w-anchor-link href="#content-item4" title="人物生平"></w-anchor-link>
<w-anchor-link href="#content-item5" title="社交分析与扩线"></w-anchor-link>
<w-anchor-link href="#content-item6" title="社交平台发文动态"></w-anchor-link>
</w-anchor>
</template>
<script>
export default {
name: 'TracingPoint',
props: {
size: Number,
getContainer: Function
},
data() {
return {
targetOffset: undefined
};
},
methods: {
handleClick(e, link) {
e.preventDefault();
}
},
mounted() {
this.targetOffset = window.innerHeight / 2.15;
}
};
</script>

1065
src/components/graphContainer/Graph.vue
File diff suppressed because it is too large
View File

111
src/components/graphContainer/GraphIndex.vue

@ -0,0 +1,111 @@
<template>
<div class="graphOuter">
<!-- top menu -->
<graph-menu :graph-type="graphType" :select-type="selectType" @downloadFullImage="downloadFullImage" />
<!-- graph content -->
<graph ref="graph" />
</div>
</template>
<script>
import { EventBus } from './eventBus';
import GraphMenu from './Menu';
import Graph from './Graph';
export default {
components: { GraphMenu, Graph },
props: {
graphType: {
type: Array,
default: function () {
return ['gForce'];
}
},
selectType: {
type: Array,
default: function () {
return [];
}
},
alllowExportPNG: {
type: Boolean,
default: true
},
allowDelSelect: {
type: Boolean,
default: true
},
allowMinimap: {
type: Boolean,
default: true
},
allowSearch: {
type: Boolean,
default: true
},
allowZoom: {
type: Boolean,
default: true
},
allowFullScreen: {
type: Boolean,
default: true
},
d3Data: {
type: Object,
default: function () {
return {};
}
},
graphStyle: {
type: Object,
default: function () {
return {
labelTextColor: '#E8E9EA',
backgroundColor: '#F5F6F7',
borderColor: '#4E596C'
};
}
}
},
watch: {
graphStyle: {
handler: function (val, oldVal) {
if (val) {
const mewData = JSON.parse(JSON.stringify(val));
this.$refs.graph.getStyle(mewData);
}
},
deep: true
},
d3Data: {
handler: function (val, oldVal) {
if (val) {
const mewData = JSON.parse(JSON.stringify(val));
this.$nextTick(() => {
this.$refs.graph.beginDraw(mewData);
});
}
},
deep: true
}
},
mounted() {
EventBus.$off('clickNodes');
EventBus.$on('clickNodes', (obj) => {
this.$emit('clickNode', obj);
});
},
methods: {
// png
downloadFullImage(type) {
this.$refs.graph.downloadFullImage(type);
}
}
};
</script>
<style lang="less" scoped>
.graphOuter {
// background: #f4f7fc;
width: 100%;
height: 100%;
}
</style>

347
src/components/graphContainer/Menu.vue

@ -0,0 +1,347 @@
<template>
<div class="menu">
<!-- 左侧操作菜单栏 -->
<div class="left-handle-menu">
<w-tooltip v-if="graphType.includes('gForce')" effect="dark" content="力导向布局" placement="bottom">
<!-- <i class="iconfont icon-a-1" @click="switchLayout('gForce')" /> -->
<w-button type="text" size="small" @click="switchLayout('gForce')">
<CoolFlowChart v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<!-- <el-dropdown placement="bottom" popper-class="menuPopOverStyle">
<span class="el-dropdown-link">
<i class="iconfont icon-shangxiashuxing" />
</span>
<el-dropdown-menu slot="dropdown" class="layout-dropdown">
<el-dropdown-item v-if="graphType.includes('dagreTB')" :class="{'active': dagreType === 'TB'}" @click.native="switchLayout('dagre', 'TB')"><i class="iconfont icon-shangxiashuxing" />上下树形</el-dropdown-item>
<el-dropdown-item v-if="graphType.includes('dagreLR')" :class="{'active': dagreType === 'LR'}" @click.native="switchLayout('dagre', 'LR')"><i class="iconfont icon-zuoceshuxing" />左侧树形</el-dropdown-item>
<el-dropdown-item v-if="graphType.includes('dagreRL')" :class="{'active': dagreType === 'RL'}" @click.native="switchLayout('dagre', 'RL')"><i class="iconfont icon-youceshuxing" />右侧树形</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
<w-tooltip v-if="graphType.includes('dagreTB')" effect="dark" content="上下树形" placement="bottom">
<!-- <i class="iconfont icon-shangxiashuxing" @click="switchLayout('dagre', 'TB')" /> -->
<!-- <w-button @click="switchLayout('dagre', 'TB')">111</w-button> -->
<w-button type="text" size="small" @click="switchLayout('dagre', 'TB')">
<CoolOrganizationChart v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<w-tooltip v-if="graphType.includes('grid')" effect="dark" content="网格布局" placement="bottom">
<!-- <i class="iconfont icon-a-31" @click="switchLayout('grid')" /> -->
<w-button type="text" size="small" @click="switchLayout('grid')">
<CoolGridFill v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<w-tooltip v-if="graphType.includes('concentric')" effect="dark" content="同心圆布局" placement="bottom">
<!-- <i class="iconfont icon-a-4" @click="switchLayout('concentric')" /> -->
<w-button type="text" size="small" @click="switchLayout('concentric')">
<CoolMovie_2Fill v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<!-- <w-tooltip v-if="graphType.includes('gridRows')" effect="dark" content="横向布局" placement="bottom" popper-class="menuPopOverStyle">
<i class="iconfont icon-hengxiang" @click="switchLayout('grid', 'rows')" />
</w-tooltip>
<w-tooltip v-if="graphType.includes('gridCols')" effect="dark" content="纵向布局" placement="bottom" popper-class="menuPopOverStyle">
<i class="iconfont icon-zongxiang" @click="switchLayout('grid', 'cols')" />
</w-tooltip> -->
<span class="split-line" />
<!-- <w-divider direction="vertical"></w-divider> -->
<!-- <w-tooltip v-if="selectType.includes('brushSelect')" effect="dark" content="框选" placement="bottom" popper-class="menuPopOverStyle">
<i class="iconfont icon-kuangxuan" @click="setMode('brushSelect')" />
</w-tooltip>
<w-tooltip v-if="selectType.includes('lassoSelect')" effect="dark" content="不规则选择" placement="bottom" popper-class="menuPopOverStyle">
<i class="iconfont icon-buguizexuanzhong" @click="setMode('lassoSelect')" />
</w-tooltip>
<i class="iconfont icon-buquanguanxi disabled" />
<span class="split-line" /> -->
<!-- <i class="iconfont icon-xiazai disabled" /> -->
<!-- <el-dropdown placement="bottom" popper-class="menuPopOverStyle">
<i class="iconfont icon-jietu" />
<el-dropdown-menu slot="dropdown" class="layout-dropdown">
<el-dropdown-item @click.native="downloadFullImage(2)">
<span style="font-size:12px;">全屏快照</span>
</el-dropdown-item>
<el-dropdown-item @click.native="downloadFullImage(3)">
<span style="font-size:12px;">选取快照</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
<w-tooltip v-if="alllowExportPNG" effect="dark" content="导出图片" placement="bottom" popper-class="menuPopOverStyle">
<!-- <iconpark-icon name="image-add-line" size="22" @click="downloadFullImage(1)" /> -->
<w-button type="text" size="small" @click="downloadFullImage(1)">
<CoolImageLine v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<w-tooltip v-if="allowDelSelect" effect="dark" content="删除选中" placement="bottom" popper-class="menuPopOverStyle">
<!-- <i :class="{ disabled: focusNodesArr && focusNodesArr.length === 0 }" class="iconfont icon-shanchu" @click="deleteSelected" /> -->
<w-button type="text" size="small" :disabled="focusNodesArr && focusNodesArr.length === 0 " @click="deleteSelected">
<CoolDeleteBinThreeFill v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<!-- <w-tooltip v-if="allowMinimap" effect="dark" content="缩略图" placement="bottom" popper-class="menuPopOverStyle">
<i class="iconfont icon-suolvetu" @click="handleMinimap" />
</w-tooltip> -->
<!-- <span class="split-line" />
<i class="iconfont icon-shangyibu1 disabled" />
<i class="iconfont icon-xiayibu1 disabled" /> -->
</div>
<div class="footer">
<div class="right-menu">
<search v-if="allowSearch" />
<span class="split-line" />
<w-tooltip effect="dark" content="缩小" placement="bottom">
<w-button type="text" size="small" @click="handleZoom('small')">
<CoolSubtractLine v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<span class="percentage">{{ parseInt(zoom) }}%</span>
<w-tooltip effect="dark" content="放大" placement="bottom">
<w-button type="text" size="small" @click="handleZoom('big')">
<CoolAddLine v-if="allowZoom" size="24" color="#909399" />
</w-button>
</w-tooltip>
<!-- <span class="split-line" /> -->
<!-- <w-tooltip v-if="allowFullScreen" effect="dark" content="全屏" placement="top">
<i class="iconfont icon-quanjufangda disabled" />
</w-tooltip> -->
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { EventBus } from './eventBus';
import search from './search.vue';
export default {
name: 'GraphMenu',
components: { search },
props: {
graphType: {
type: Array,
default: ['gForce']
},
selectType: {
type: Array,
default: []
},
alllowExportPNG: {
type: Boolean,
default: true
},
allowDelSelect: {
type: Boolean,
default: true
},
allowMinimap: {
type: Boolean,
default: true
},
allowSearch: {
type: Boolean,
default: true
},
allowZoom: {
type: Boolean,
default: true
},
allowFullScreen: {
type: Boolean,
default: true
}
},
data() {
return {
zoom: 100,
dagreType: ''
};
},
created() {
},
computed: {
...mapState({
focusNodesArr: (state) => state.graphMenu.focusNodesArr,
curZoom: (state) => state.graphMenu.zoom
})
},
watch: {
curZoom(val) {
const newVal = val * 100;
this.zoom = newVal;
}
},
methods: {
fullSnapShot() {
const data = graph.toDataURL();
},
partSnapShot() {
const data = graph.toDataURL();
},
handleZoom(type) {
EventBus.$emit('zoom', type);
},
switchLayout(type, direction) {
if (direction === 'TB' || direction === 'LR' || direction === 'RL') {
this.dagreType = direction;
} else {
this.dagreType = '';
}
EventBus.$emit('switchLayout', type, direction || '');
},
downloadFullImage(type) {
this.$emit('downloadFullImage', type);
},
deleteSelected() {
EventBus.$emit('deleteSelected');
},
//
handleMinimap() {
const dom = document.getElementById('minimap');
if (dom.style.display === 'none') {
document.getElementById('minimap').style.display = 'block';
} else {
document.getElementById('minimap').style.display = 'none';
}
},
setMode(mode) {
EventBus.$emit('setMode', mode);
}
}
};
</script>
<style lang="less">
.menuPopOverStyle[x-placement^='bottom'] {
// color: #000 !important;
// background: rgba(255, 255, 255, 0.8) !important;
}
.menuPopOverStyle[x-placement^='bottom'] .popper__arrow::after {
border-bottom-color: rgba(255, 255, 255, 0.8);
}
.menuPopOverStyle[x-placement^='bottom'] .popper__arrow {
border-bottom-color: rgba(255, 255, 255, 0.8);
}
</style>
<style lang="less" scoped>
::v-deep.w-button{
background-color:#F3F4F5;
}
.layout-dropdown.el-dropdown-menu {
background: #2d3648;
border-radius: 2px;
border: none;
top: 68px !important;
padding: 4px 0 !important;
.el-dropdown-menu__item {
padding: 0 12px;
line-height: 32px;
color: #ffffff;
&:hover {
color: #0081ff;
}
&:hover,
&.active {
background: rgba(26, 34, 50, 0.5);
}
i {
margin-right: 7px;
}
.iconfont {
font-size: 14px;
}
}
::v-deep .popper__arrow {
display: none;
}
}
.menu {
display: flex;
justify-content: space-between;
background: #F3F4F5;
padding: 0 12px;
overflow: hidden;
margin-bottom: 2px;
iconpark-icon {
cursor: pointer;
margin-left: 6px;
position: relative;
top: 8px;
color: #b7c9df;
&.disabled {
cursor: not-allowed;
color: rgba(152, 167, 185, 0.5);
}
&:hover {
color: #0081ff;
}
}
.iconfont {
display: inline-block;
font-size: 20px;
color: #b7c9df !important;
margin: 11.5px 12px;
vertical-align: middle;
cursor: pointer;
&.disabled {
cursor: not-allowed;
color: rgba(152, 167, 185, 0.5);
}
}
.left-handle-menu {
height: 48px;
display: flex;
align-items: center;
i {
color: #b7c9df;
&:hover {
color: #0081ff;
}
}
.split-line {
width: 1px;
height: 20px;
display: inline-block;
background: rgba(152, 167, 185, 0.3);
vertical-align: middle;
margin: 0 12px;
}
}
}
.footer {
height: 48px;
.iconfont {
display: inline-block;
font-size: 20px;
color: #b7c9df;
margin: 11.5px 12px;
vertical-align: middle;
cursor: pointer;
&.disabled {
cursor: not-allowed;
color: rgba(152, 167, 185, 0.5);
}
}
.right-menu {
width: fit-content;
height: 100%;
display: flex;
align-items: center;
.percentage {
font-size: 14px;
color: #98a7b9;
line-height: 48px;
display: inline-block;
width: 46px;
text-align: center;
}
.split-line {
width: 1px;
height: 20px;
display: inline-block;
background: rgba(152, 167, 185, 0.3);
vertical-align: middle;
margin: 0 12px;
}
}
}
</style>

128
src/components/graphContainer/README.md

@ -0,0 +1,128 @@
## 绘图组件
# 依赖 @antv/g6 vuex qs sass element-ui
# 配合Vuex modules 使用, 需在store/index => import chartExplore\component\store\menu注入
# 安装axios
## 功能配置项
<!-- Attributes start -->
# d3Data 绘图数据 必填
默认值:{}
类型:object
# graphType 绘图类型可选项 可选
默认值:['gForce']
类型:array
可选值:
gForce(力导向布局)
dagreTB(层级布局-上下树形)
dagreLR(层级布局-左侧树形)
dagreRL(层级布局-右侧树形)
grid(网格布局)
gridRows(横向布局)
gridCols(纵向布局)
concentric(同心圆布局)
# selectType 选择类型可选项 可选
默认值:无
类型:array
可选值:
brushSelect(框选)
lassoSelect(不规则选择)
# alllowExportPNG 是否允许导出图片 可选
默认值:true
类型:boolean
可选值:
true
false
# allowDelSelect 是否允许选中删除 可选
默认值:true
类型:boolean
可选值:
true
false
# allowMinimap 是否允许显示缩略图 可选
默认值:true
类型:boolean
可选值:
true
false
# allowSearch 搜索功能 可选
默认值:true
类型:boolean
可选值:
true
false
# allowZoom 是否允许缩放 可选
默认值:true
类型:boolean
可选值:
true
false
# allowFullScreen 是否允许全屏 可选
默认值:true
类型:boolean
可选值:
true
false
# graphStyle 样式配置 可选
# labelTextColor 节点文本颜色
# backgroundColor 背景色
# borderColor 链接线颜色
默认值:{
'labelTextColor':'#E8E9EA',
'backgroundColor':'#1A2232',
'borderColor':'#4E596C',
}
类型:Object
<!-- Attributes end -->
<!-- Events start -->
# 事件名称 clickNode
# 回调参数 类型:(object)
# 参数描述:节点信息
<!-- 方法 end -->

2
src/components/graphContainer/eventBus.js

@ -0,0 +1,2 @@
import Vue from 'vue'
export const EventBus = new Vue()

337
src/components/graphContainer/extend-dialog.vue

@ -0,0 +1,337 @@
<template>
<div class="extend-dialog">
<el-dialog
v-if="nodeExtendD"
:close-on-click-modal="false"
:title="nodeExtendD.title"
:visible.sync="dialogVisible"
:width="nodeExtendD.width ? nodeExtendD.width : '30%'"
@close="handleCancel('form')"
>
<el-form ref="form" :model="nodeExtendD.formData" :rules="nodeExtendD.rules" label-width="80px">
<el-form-item v-for="(item, index) in nodeExtendD.data" :key="index" :label="item.label" :prop="item.field">
<el-select
v-if="item.inputType === 'select'"
v-model="nodeExtendD.formData[item.field]"
:filterable="item.filterable ? item.filterable : false"
:placeholder="item.placeholder"
:popper-append-to-body="false"
:multiple="item.multiple ? item.multiple : false"
no-data-text="暂无数据"
:class="item.width"
>
<el-option
v-for="option in item.options"
:key="item.optionType ? option[item.optionType.value] : option"
:label="item.optionType ? option[item.optionType.label] : option"
:value="item.optionType ? option[item.optionType.value] : option"
/>
</el-select>
<w-tree-select
v-if="item.inputType === 'tree' && dialogVisible"
v-model="nodeExtendD.formData[item.field]"
lazy
:load="loadNode"
:tree-props="{ label: 'name' }"
:popper-append-to-body="false"
value-key="id"
clearable
collapse-tags
:tree-attributes="{ accordion: true, checkOnClickNode: true }"
empty-text="暂无数据"
:class="item.width"
:multiple="item.multiple ? item.multiple : false"
:placeholder="item.placeholder"
:tree-data="nodeExtendD.data[1].options"
/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleCancel('form')"> </el-button>
<el-button type="primary" @click="handleOk('form')"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getOntConceptList, getOntRelationList, getRelationType, getOntRelationQuery } from './graph/graph';
import { EventBus } from './eventBus';
import { globalV } from './graph/globalData';
import commonUtils from './graph/common';
import menuHandle from './graph/menu';
export default {
data() {
return {
dialogVisible: false,
nodeExtendD: null,
nodeId: null,
graphNodeInfo: null
};
},
mounted() {
EventBus.$on('currentNodeInfo', (obj) => {
this.dialogVisible = obj.dialogVisible;
this.$nextTick(() => {
this.nodeExtendD = obj.extendData;
this.nodeId = obj.nodeId;
this.graphNodeInfo = obj;
if (obj.type === 'extend') {
this.getOntConceptList(obj.expandType);
} else if (obj.type === 'path') {
this.pathExplorer();
}
});
});
//
EventBus.$on('resetForm', () => {
this.resetForm('form');
this.dialogVisible = false;
});
},
beforeDestroy() {
EventBus.$off(['currentNodeInfo', 'resetForm']);
},
methods: {
//
getOntConceptList(type) {
const params = {
graphId: this.$route.query.graphId,
domain: this.$route.query.domain,
maxdist: 1,
eid: this.nodeId,
force: false
};
if (type === 'node') {
getOntConceptList(params).then((res) => {
this.nodeExtendD.data[0].options = res;
this.nodeExtendD.data[0].optionType = {
label: 'name',
value: 'id'
};
this.$forceUpdate();
});
} else if (type === 'edge') {
getOntRelationList(params).then((res) => {
this.nodeExtendD.data[0].options = res;
this.nodeExtendD.data[0].optionType = {
label: 'name',
value: 'id'
};
this.$forceUpdate();
});
}
},
//
extendFormSubmit(formName) {
menuHandle
.getNeighborMixedGraph(
this.graphNodeInfo.model,
1,
this.graphNodeInfo.data,
this.graphNodeInfo.clusteredData,
this.graphNodeInfo.currentUnproccessedData,
globalV.nodeMap,
globalV.aggregatedNodeMap,
10,
this.graphNodeInfo.expandType,
this.nodeExtendD.formData
)
.then((res) => {
this.resetForm(formName);
this.dialogVisible = false;
const mixedGraphData = res;
commonUtils.updateDataStatistics(res);
if (mixedGraphData) {
globalV.cachePositions = commonUtils.cacheNodePositions(this.graphNodeInfo.graph.getNodes());
this.graphNodeInfo.currentUnproccessedData = mixedGraphData;
commonUtils.handleRefreshGraph(
this.graphNodeInfo.graph,
this.graphNodeInfo.currentUnproccessedData,
globalV.CANVAS_WIDTH,
globalV.CANVAS_HEIGHT,
globalV.largeGraphMode,
true,
false,
true
);
}
commonUtils.setFocusNodes(this.graphNodeInfo.graph);
});
},
//
pathExplorer() {
const data = {
graphId: this.$route.query.graphId,
domain: this.$route.query.domain,
projectId: this.$route.query.projectId,
pageNo: 1,
pageSize: 100
};
getRelationType(data).then((res) => {
this.nodeExtendD.data[1].options = res.instances ? res.instances : [];
});
},
loadNode(node, resolve) {
if (node.level === 1) {
const data = {
domain: this.$route.query.domain,
pageNo: 1,
pageSize: 1000,
id: node.data.id
};
getOntRelationQuery(data).then((res) => {
resolve(res.instances ? res.instances : []);
});
} else {
resolve([]);
}
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
handleCancel(formName) {
this.resetForm(formName);
this.dialogVisible = false;
},
handleOk(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
if (this.graphNodeInfo.type === 'extend') {
this.extendFormSubmit(formName);
} else if (this.graphNodeInfo.type === 'path') {
EventBus.$emit('shortestPath', this.graphNodeInfo);
}
} else {
console.log('error submit!!');
}
});
}
}
};
</script>
<style lang="less" scoped>
::v-deep.el-select-dropdown__list {
background-color: #2d3648;
}
.extend-dialog {
::v-deep.el-dialog__header {
background-color: #2d3648;
.el-dialog__title {
color: #fff;
}
}
::v-deep.el-dialog__body {
background-color: #222c3f;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
.el-form-item__label {
color: #fff;
}
.el-input__inner {
background-color: #1a2232;
border: 1px solid #333e51;
color: #ffffff;
&:hover {
border-color: #0081ff;
}
}
.w-tree-select {
.w-tag {
background: #0081ff;
color: #fff;
}
.w-tree-select-dropdown {
border: 1px solid #333e51;
}
.w-checkbox__input.is-checked .w-checkbox__inner {
background-color: #0081ff;
border-color: #0081ff;
}
.w-checkbox__inner:hover {
border-color: #0081ff;
}
.w-tree-node__expand-icon {
color: #fff;
}
.w-scrollbar {
background-color: #1a2232;
.w-tree {
background-color: #1a2232;
.w-tree-node__content {
background-color: #1a2232;
color: #fff;
&:hover {
background-color: #5caeff;
}
}
}
}
.w-input__inner {
background-color: #1a2232;
border: 1px solid #333e51;
color: #ffffff;
}
&.width90 {
width: 90%;
}
}
.el-select {
width: 100%;
&.width50 {
width: 50%;
}
&.width90 {
width: 90%;
}
.el-select__input {
color: #ffffff;
}
.el-tag.el-tag--info {
background-color: #272f3e;
border-color: #272f3e;
color: #ffffff;
.el-tag__close.el-icon-close {
background-color: transparent;
}
}
}
}
::v-deep.el-dialog__footer {
background-color: #222c3f;
.el-button--default {
background-color: #384152;
color: #fff;
border-color: #384152;
}
}
::v-deep .el-select-dropdown {
background-color: #2d3648;
border: none;
border-radius: 2px;
.el-scrollbar__thumb {
background: rgb(74, 82, 96);
&:hover {
background: rgb(74, 82, 96);
}
}
.el-select-dropdown__item {
height: 28px;
line-height: 28px;
color: #ffffff;
font-weight: normal;
}
.el-select-dropdown__item.selected {
color: #ffffff;
background: #0081ff;
}
.el-select-dropdown__item.hover,
.el-select-dropdown__item:hover {
background: rgba(0, 129, 255, 1);
}
}
::v-deep .el-popper .popper__arrow {
display: none;
}
}
</style>

214
src/components/graphContainer/graph/bindListener.js

@ -0,0 +1,214 @@
import { globalV } from './globalData';
import commonUtils from './common';
import menuHandle from './menu';
import store from '@/store';
import { EventBus } from '../eventBus';
const BindListener = class BindListener {
constructor(shiftKeydown, largeGraphMode) {
this.shiftKeydown = shiftKeydown;
this.largeGraphMode = largeGraphMode;
}
bindEvent(graph, data, clusteredData, currentUnproccessedData, nodeMap) {
graph.on('keydown', (evt) => {
const code = evt.key;
if (!code) {
return;
}
if (code.toLowerCase() === 'shift') {
this.shiftKeydown = true;
} else {
this.shiftKeydown = false;
}
// ctrl+A全选功能 暂时注释
// if (evt.ctrlKey && code.toLowerCase() === 'a') {// ctrl+A全选节点
// menuHandle.selectAll(graph)
// }
});
graph.on('keyup', (evt) => {
const code = evt.key;
if (!code) {
return;
}
if (code.toLowerCase() === 'shift') {
this.shiftKeydown = false;
}
if (code.toLowerCase() === 'delete') {
// menuHandle.deleteFocusNodes(graph)
}
});
graph.on('contextmenu', (evt) => {
const g6ContextMenu = document.getElementsByClassName('g6-component-contextmenu')[0];
g6ContextMenu.style.cssText += ';padding: 10px 8px;border: 1px solid #e2e2e2';
const { item } = evt;
if (!item) return;
const itemType = item.getType();
const model = item.getModel();
if (itemType && model) {
if (itemType === 'node' && model.level === 0) {
const { x, y } = model; // 获得该节点的位置,对应 pointX/pointY 坐标
const canvasXY = graph.getCanvasByPoint(x, y);
g6ContextMenu.style.cssText += `;position: absolute;left: ${canvasXY.x}px;top: ${
canvasXY.y
}px;transform: scale(${evt.currentTarget.getZoom()});transform-origin: left center;padding: 0;border: none;`;
}
}
});
graph.on('wheelzoom', (e) => {
e.stopPropagation();
// 这里的 className 根据实际情况而定,默认是 g6-component-tooltip
const contextmenu = Array.from(document.getElementsByClassName('g6-component-contextmenu'));
contextmenu.forEach((contextmenu) => {
if (contextmenu && contextmenu.style) {
globalV.zoom = graph.getZoom();
store.commit('graphMenu/SET_ZOOM', globalV.zoom);
contextmenu.style.transform = `scale(${graph.getZoom()})`;
}
});
const g6ContextMenu = document.getElementsByClassName('g6-component-contextmenu')[0];
g6ContextMenu.style.cssText += 'visibility: hidden';
});
graph.on('node:mouseenter', (evt) => {
const { item } = evt;
graph.setItemState(item, 'hover', true);
item.toFront();
});
graph.on('node:mouseleave', (evt) => {
const { item } = evt;
graph.setItemState(item, 'hover', false);
});
graph.on('edge:mouseenter', (evt) => {
const { item } = evt;
const model = item.getModel();
const currentLabel = model.label;
item.update({
label: model.oriLabel
});
model.oriLabel = currentLabel;
// item.toFront()
// item.getSource().toFront()
// item.getTarget().toFront()
});
graph.on('edge:mouseleave', (evt) => {
const { item } = evt;
const model = item.getModel();
const currentLabel = model.label;
item.update({
label: model.oriLabel
});
model.oriLabel = currentLabel;
});
// click node to show the detail drawer
graph.on('node:click', (evt) => {
commonUtils.stopLayout();
if (!this.shiftKeydown) commonUtils.clearFocusItemState(graph);
else commonUtils.clearFocusEdgeState(graph);
const { item } = evt;
// highlight the clicked node, it is down by click-select
if (item.hasState('focus')) {
graph.setItemState(item, 'focus', false);
} else {
graph.setItemState(item, 'focus', true);
}
if (!this.shiftKeydown) {
// 将相关边也高亮
const relatedEdges = item.getEdges();
relatedEdges.forEach((edge) => {
graph.setItemState(edge, 'focus', true);
});
}
// 获取当前被点击节点的基本信息
const model = item.getModel();
EventBus.$emit('clickNodes', model);
if (model.isReal) {
// 真实节点才显示当前节点信息
// 点击节点,将右侧弹窗信息切换到节点信息
commonUtils.dispatchDetail(model, true);
}
commonUtils.setFocusNodes(graph);
EventBus.$emit('GraphEvent', { graph, evt, model, type: 'node:click' });
});
// 双击
graph.on('node:dblclick', (evt) => {
const model = evt.item && evt.item.getModel();
if (!model.isReal) return false;
menuHandle
.getNeighborMixedGraph(
model,
1,
globalV.basicData,
globalV.clusteredData,
globalV.currentUnproccessedData,
globalV.nodeMap,
globalV.aggregatedNodeMap,
10
)
.then((res) => {
const mixedGraphData = res;
commonUtils.updateDataStatistics(res);
if (mixedGraphData) {
globalV.cachePositions = commonUtils.cacheNodePositions(graph.getNodes());
globalV.currentUnproccessedData = mixedGraphData;
commonUtils.handleRefreshGraph(
graph,
globalV.currentUnproccessedData,
globalV.CANVAS_WIDTH,
globalV.CANVAS_HEIGHT,
globalV.largeGraphMode,
true,
false,
true
);
}
commonUtils.setFocusNodes(graph);
EventBus.$emit('GraphEvent', { graph, evt, model, type: 'node:dblclick' });
});
});
// click edge to show the detail of integrated edge drawer
graph.on('edge:click', (evt) => {
commonUtils.stopLayout();
if (!this.shiftKeydown) commonUtils.clearFocusItemState(graph);
const { item } = evt;
// highlight the clicked edge
graph.setItemState(item, 'focus', true);
const model = item.getModel();
if (model.isReal) {
// 真实关系才显示当前关系信息
// 点击关系,将右侧弹窗信息切换到关系信息
commonUtils.dispatchDetail(model, false);
}
commonUtils.setFocusNodes(graph);
EventBus.$emit('clickEdges', model);
EventBus.$emit('GraphEvent', { graph, evt, model, type: 'edge:click' });
});
// click canvas to cancel all the focus state
graph.on('canvas:click', (evt) => {
commonUtils.clearFocusItemState(graph);
// console.log(graph.getGroup(), graph.getGroup().getBBox(), graph.getGroup().getCanvasBBox())
commonUtils.setFocusNodes(graph);
EventBus.$emit('GraphEvent', { graph, evt, type: 'canvas:click' });
EventBus.$emit('clickCavans', true);
});
graph.on('canvas:dragstart', (evt) => {
const mode = graph.getCurrentMode();
if (mode === 'brushSelect' || mode === 'lassoSelect') {
commonUtils.clearFocusItemState(graph);
commonUtils.setFocusNodes(graph);
}
});
graph.on('nodeselectchange', (evt) => {
graph.setMode('default');
commonUtils.setFocusNodes(graph);
});
}
};
const bindListener = new BindListener(false, globalV.largeGraphMode);
export default bindListener;

641
src/components/graphContainer/graph/common.js

@ -0,0 +1,641 @@
import G6 from '@antv/g6';
import qs from 'qs';
import { globalV } from './globalData';
import store from '@/store';
import { getQueryString, sub } from './publicFunction';
const { labelPropagation } = G6.Algorithm; // 图算法
const colorSets = G6.Util.getColorSetsBySubjectColors(globalV.subjectColors, globalV.darkBackColor, globalV.theme, globalV.disableColor);
const { uniqueId } = G6.Util;
const CommonUtils = class CommonUtils {
cloneObjectFn(obj) {
return JSON.parse(JSON.stringify(obj));
}
// 截断长文本。length 为文本截断后长度,elipsis 是后缀
formatText(text, length = 5, elipsis = '...') {
if (!text) return '';
if (text.length > length) {
return `${text.substr(0, length)}${elipsis}`;
}
return text;
}
labelFormatter(text, minLength = 10) {
if (text && text.split('').length > minLength) return `${text.substr(0, minLength)}...`;
return text;
}
descendCompare(p) {
// 这是比较函数
return function (m, n) {
const a = m[p];
const b = n[p];
return b - a; // 降序
};
}
// 格式化nodes和edges的数据(处理成所需要的格式)
formatData(data) {
const g6Data = data;
if (g6Data.edges && g6Data.edges.length) {
g6Data.edges = g6Data.edges.map((item) => {
item.sourceNum = item.source;
item.targetNum = item.target;
item.source = g6Data.nodes[item.source].id;
item.target = g6Data.nodes[item.target].id;
return item;
});
}
if (g6Data.nodes && g6Data.nodes.length) {
g6Data.nodes = g6Data.nodes.map((item) => {
item.x = item.positionX ? Number(item.positionX) : null;
item.y = item.positionY ? Number(item.positionY) : null;
item.name = item.name || '';
delete item.layer;
return item;
});
}
return g6Data;
}
// 停止布局
stopLayout() {
globalV.layout.instance.stop();
}
// 隐藏hiddenItemIds里的元素
hideItems(graph) {
globalV.hiddenItemIds.forEach((id) => {
graph.hideItem(id);
graph.clearItemStates(id);
});
}
showItems(graph) {
graph.getNodes().forEach((node) => {
if (!node.isVisible()) graph.showItem(node);
});
graph.getEdges().forEach((edge) => {
if (!edge.isVisible()) edge.show();
});
globalV.hiddenItemIds = [];
this.updateDataStatistics();
}
// 清除图元素focus状态及相应样式
clearFocusItemState(graph) {
if (!graph) return;
this.clearFocusNodeState(graph);
this.clearFocusEdgeState(graph);
}
// 清除图上所有节点的 focus 状态及相应样式
clearFocusNodeState(graph) {
const focusNodes = graph.findAllByState('node', 'focus');
focusNodes.forEach((fnode) => {
graph.setItemState(fnode, 'focus', false); // false
});
}
// 清除图上所有边的 focus 状态及相应样式
clearFocusEdgeState(graph) {
const focusEdges = graph.findAllByState('edge', 'focus');
focusEdges.forEach((fedge) => {
graph.setItemState(fedge, 'focus', false);
});
}
// 存入当前状态为focus的节点
setFocusNodes(graph) {
const nodes = graph.findAllByState('node', 'focus');
store.commit('graphMenu/SET_FOCUSNODESARR', nodes);
}
getForceLayoutConfig(graph, largeGraphMode, configSettings) {
const { linkDistance, edgeStrength, nodeStrength, nodeSpacing, preventOverlap, nodeSize, collideStrength, alpha, alphaDecay, alphaMin } =
configSettings || { preventOverlap: true };
// if (!linkDistance && linkDistance !== 0) linkDistance = 225
// if (!edgeStrength && edgeStrength !== 0) edgeStrength = 50
// if (!nodeStrength && nodeStrength !== 0) nodeStrength = 200
// if (!nodeSpacing && nodeSpacing !== 0) nodeSpacing = 5
const config = {
type: 'gForce',
// kr: 50,
// mode: 'linlog',
// minMovement: 0.01,
maxIteration: 3,
maxSpeed: 10000,
preventOverlap,
// barnesHut: true,
// damping: 0.99,
// // 边长度
// linkDistance: (d) => {
// let dist = linkDistance
// const sourceNode = globalV.nodeMap[d.source] || globalV.aggregatedNodeMap[d.source]
// const targetNode = globalV.nodeMap[d.target] || globalV.aggregatedNodeMap[d.target]
// // // 两端都是聚合点
// // if (sourceNode.level && targetNode.level) dist = linkDistance * 3;
// // // 一端是聚合点,一端是真实节点
// // else if (sourceNode.level || targetNode.level) dist = linkDistance * 1.5;
// if (!sourceNode.level && !targetNode.level) dist = linkDistance * 0.3
// return dist
// },
// // 边的作用力(引力)大小
// edgeStrength: (d) => {
// const sourceNode = globalV.nodeMap[d.source] || globalV.aggregatedNodeMap[d.source]
// const targetNode = globalV.nodeMap[d.target] || globalV.aggregatedNodeMap[d.target]
// // 聚合节点之间的引力小
// if (sourceNode.level && targetNode.level) return edgeStrength / 2
// // 聚合节点与真实节点之间引力大
// if (sourceNode.level || targetNode.level) return edgeStrength
// return edgeStrength
// },
// // 节点作用力
// nodeStrength: (d) => {
// // 给离散点引力,让它们聚集
// if (d.degree === 0) return 30
// // 聚合点的斥力大
// if (d.level) return nodeStrength * 2
// return nodeStrength
// },
nodeSize: (d) => {
if (!nodeSize && d.size) return d.size;
return 50;
},
// nodeSpacing: (d) => {
// if (d.degree === 0) return nodeSpacing * 2
// if (d.level) return nodeSpacing
// return nodeSpacing
// },
onLayoutEnd: () => {
graph.fitCenter();
// if (largeGraphMode) {
// graph.getEdges().forEach((edge) => {
// if (!edge.oriLabel) return
// edge.update({
// label: this.labelFormatter(edge.oriLabel, globalV.labelMaxLength)
// })
// })
// }
},
tick: () => {
graph.refreshPositions();
}
};
// if (nodeSize) config['nodeSize'] = nodeSize
// if (collideStrength) config['collideStrength'] = collideStrength
// if (alpha) config['alpha'] = alpha
// if (alphaDecay) config['alphaDecay'] = alphaDecay
// if (alphaMin) config['alphaMin'] = alphaMin
return config;
}
cacheNodePositions(nodes) {
const positionMap = {};
const nodeLength = nodes.length;
for (let i = 0; i < nodeLength; i++) {
const node = nodes[i].getModel();
positionMap[node.id] = {
x: node.x,
y: node.y,
level: node.level
};
}
return positionMap;
}
handleRefreshGraph(graph, graphData, width, height, largeGraphMode, edgeLabelVisible, isNewGraph, isExtendHighlight) {
if (!graphData || !graph) return;
this.clearFocusItemState(graph);
// reset the filtering
graph.getNodes().forEach((node) => {
if (!node.isVisible()) node.show();
});
graph.getEdges().forEach((edge) => {
if (!edge.isVisible()) edge.show();
});
let nodes = [];
let edges = [];
nodes = graphData.nodes;
const processRes = this.processNodesEdges(nodes, graphData.edges || [], width, height, largeGraphMode, edgeLabelVisible, isNewGraph);
edges = processRes.edges;
graph.changeData({ nodes, edges });
this.hideItems(graph);
graph.getNodes().forEach((node) => {
node.toFront();
});
// layout.instance.stop();
// force 需要使用不同 id 的对象才能进行全新的布局,否则会使用原来的引用。因此复制一份节点和边作为 force 的布局数据
globalV.layout.instance.init({
nodes: graphData.nodes,
edges
});
// globalV.layout.instance.minMovement = 0.0001
// layout.instance.getCenter = d => {
// const cachePosition = cachePositions[d.id];
// if (!cachePosition && (d.x || d.y)) return [d.x, d.y, 10];
// else if (cachePosition) return [cachePosition.x, cachePosition.y, 10];
// return [width / 2, height / 2, 10];
// }
globalV.layout.instance.getMass = (d) => {
const cachePosition = globalV.cachePositions[d.id];
if (cachePosition) return 5;
return 1;
};
globalV.layout.instance.execute();
if (isExtendHighlight) {
// 将扩展出来的节点和边进行高亮
const extendArr = store.state.menu.extendData;
extendArr.nodes.forEach((node) => {
graph.setItemState(node.id, 'focus', true);
});
extendArr.edges.forEach((edge) => {
graph.setItemState(edge.id, 'focus', true);
});
store.commit('graphMenu/SET_EXTENDDATA', { nodes: [], edges: [] });
}
return { nodes, edges };
}
processNodesEdges(nodes, edges, width, height, largeGraphMode, edgeLabelVisible, isNewGraph = false) {
if (!nodes || nodes.length === 0) return {};
const currentNodeMap = {}; // 当前节点的map集合,key为节点id,value为节点对象
let maxNodeCount = -Infinity;
const paddingRatio = 0.3;
const paddingLeft = paddingRatio * width;
const paddingTop = paddingRatio * height;
nodes.forEach((node) => {
node.type = node.level === 0 ? 'real-node' : 'aggregated-node';
node.isReal = node.level === 0;
if (node.isReal) {
const concepts = globalV.basicData.concepts;
// 节点的形状、中央图片等显示逻辑(优先级:nodes > concepts > 默认)
if (node.image) {
// 节点有图片
if (node.imageprtcl == 'file' || node.imageprtcl == 'fs') {
// node.img = `${process.env.VUE_APP_BASE_API}/media/${node['imageprtcl']}/${node.image}`
node.img = `${process.env.VUE_APP_BASE_API}/media/file/${node.image}`;
} else if (node.imageprtcl == 'https' || node.imageprtcl == 'http' || node.imageprtcl == 'ftp' || node.imageprtcl == 'base64') {
node.img = node.image;
} else {
node.img = node.image;
}
} else if (concepts[node.concept] && concepts[node.concept].image) {
// 关系有图片
if (concepts[node.concept].imageprtcl == 'file' || concepts[node.concept].imageprtcl == 'fs') {
// node.img = `${process.env.VUE_APP_BASE_API}/media/${concepts[node.concept]['imageprtcl']}/${concepts[node.concept].image}`
node.img = `${process.env.VUE_APP_BASE_API}/media/file/${concepts[node.concept].image}`;
} else if (
concepts[node.concept].imageprtcl == 'https' ||
concepts[node.concept].imageprtcl == 'http' ||
concepts[node.concept].imageprtcl == 'ftp' ||
concepts[node.concept].imageprtcl == 'base64'
) {
node.img = concepts[node.concept].image;
}
} else {
// 默认图片
node.img = './static/defaultNode.png';
}
node.shapeStyle = {
// border、shape优先级逻辑
border: node.border || (concepts[node.concept] && concepts[node.concept].border) || globalV.defaultShapeStyle.border,
shape: node.shape || (concepts[node.concept] && concepts[node.concept].shape) || globalV.defaultShapeStyle.shape,
shapecolor: node.shapecolor || (concepts[node.concept] && concepts[node.concept].shapecolor) || globalV.defaultShapeStyle.shapecolor,
bordercolor: node.bordercolor || (concepts[node.concept] && concepts[node.concept].bordercolor) || globalV.defaultShapeStyle.bordercolor
};
}
const nodeArr = globalV.basicData.nodes.filter((item) => {
return item.id === node.id;
});
node.label = nodeArr.length ? nodeArr[0].name : node.id;
node.oriLabel = node.label;
// node.label = this.formatText(node.label, globalV.labelMaxLength, '...')
node.label = sub(node.label, globalV.labelMaxLength);
node.degree = 0;
node.inDegree = 0;
node.outDegree = 0;
if (currentNodeMap[node.id]) {
console.warn('node exists already!', node.id);
node.id = `${node.id}${Math.random()}`;
}
currentNodeMap[node.id] = node;
if (node.count > maxNodeCount) maxNodeCount = node.count;
const cachePosition = globalV.cachePositions ? globalV.cachePositions[node.id] : undefined;
if (cachePosition) {
node.x = cachePosition.x;
node.y = cachePosition.y;
node.new = false;
} else {
node.new = !isNewGraph;
if (globalV.manipulatePosition && !node.x && !node.y) {
node.x = globalV.manipulatePosition.x + 30 * Math.cos(Math.random() * Math.PI * 2);
node.y = globalV.manipulatePosition.y + 30 * Math.sin(Math.random() * Math.PI * 2);
}
}
});
let maxCount = -Infinity;
let minCount = Infinity;
// let maxCount = 0;
edges.forEach((edge) => {
// to avoid the dulplicated id to nodes
if (!edge.id) edge.id = `edge-${uniqueId()}`;
// else if (edge.id.split('-')[0] !== 'edge') edge.id = `edge-${edge.id}`;
// TODO: delete the following line after the queried data is correct
if (!currentNodeMap[edge.source] || !currentNodeMap[edge.target]) {
console.warn('edge source target does not exist', edge.source, edge.target, edge.id);
return;
}
const sourceNode = currentNodeMap[edge.source];
const targetNode = currentNodeMap[edge.target];
if (!sourceNode || !targetNode) {
console.warn('source or target is not defined!!!', edge, sourceNode, targetNode);
}
// calculate the degree
sourceNode.degree++;
targetNode.degree++;
sourceNode.outDegree++;
targetNode.inDegree++;
if (edge.count > maxCount) maxCount = edge.count;
if (edge.count < minCount) minCount = edge.count;
});
nodes.sort(this.descendCompare(globalV.NODESIZEMAPPING));
const maxDegree = nodes[0].degree || 1;
const descreteNodes = [];
nodes.forEach((node, i) => {
// assign the size mapping to the outDegree
const countRatio = node.count / maxNodeCount;
const isRealNode = node.level === 0;
node.size = isRealNode ? globalV.DEFAULTNODESIZE : globalV.DEFAULTAGGREGATEDNODESIZE;
node.isReal = isRealNode;
node.labelCfg = {
position: 'bottom',
offset: 5,
style: {
fill: globalV.global.node.labelCfg.style.fill,
// fontSize: 6 + countRatio * 6 || 12
fontSize: 12
}
};
if (!node.degree) {
descreteNodes.push(node);
}
});
const countRange = maxCount - minCount;
const minEdgeSize = 1;
const maxEdgeSize = 7;
const edgeSizeRange = maxEdgeSize - minEdgeSize;
edges.forEach((edge) => {
// set edges' style
const targetNode = currentNodeMap[edge.target];
const size = ((edge.count - minCount) / countRange) * edgeSizeRange + minEdgeSize || 1;
edge.size = size;
const arrowWidth = Math.max(size / 2 + 2, 3);
const arrowLength = 10;
const arrowBeging = targetNode.size + arrowLength;
let arrowPath = `M ${arrowBeging},0 L ${arrowBeging + arrowLength},-${arrowWidth} L ${arrowBeging + arrowLength},${arrowWidth} Z`;
const d = targetNode.size / 2 + arrowLength;
if (edge.source === edge.target) {
edge.type = 'loop';
arrowPath = undefined;
}
const sourceNode = currentNodeMap[edge.source];
const isRealEdge = targetNode.isReal && sourceNode.isReal;
edge.isReal = isRealEdge;
const stroke = isRealEdge ? globalV.global.edge.style.realEdgeStroke : globalV.global.edge.style.stroke;
const opacity = isRealEdge ? globalV.global.edge.style.realEdgeOpacity : globalV.global.edge.style.strokeOpacity;
const dash = Math.max(size, 2);
const lineDash = isRealEdge ? undefined : [dash, dash];
edge.style = {
lineWidth: 1,
stroke,
strokeOpacity: opacity,
cursor: 'pointer',
lineAppendWidth: Math.max(edge.size || 5, 5),
fillOpacity: 1,
lineDash,
endArrow: arrowPath
? {
path: arrowPath,
d,
fill: stroke,
strokeOpacity: 0
}
: false
};
edge.labelCfg = {
autoRotate: true,
style: {
fill: globalV.global.edge.labelCfg.style.fill,
fontSize: 10,
lineAppendWidth: 10
// 边上的文本背景
// background: {
// fill: 'rgb(26, 34, 50)',
// padding: [2, 5, 2, 5]
// }
}
};
if (!edge.oriLabel) edge.oriLabel = edge.label;
if (largeGraphMode || !edgeLabelVisible) edge.label = '';
else {
// edge.label = this.labelFormatter(edge.label, globalV.labelMaxLength)
edge.label = sub(edge.label, globalV.labelMaxLength);
}
// arrange the other nodes around the hub
const sourceDis = sourceNode.size / 2 + 20;
const targetDis = targetNode.size / 2 + 20;
if (sourceNode.x && !targetNode.x) {
targetNode.x = sourceNode.x + sourceDis * Math.cos(Math.random() * Math.PI * 2);
}
if (sourceNode.y && !targetNode.y) {
targetNode.y = sourceNode.y + sourceDis * Math.sin(Math.random() * Math.PI * 2);
}
if (targetNode.x && !sourceNode.x) {
sourceNode.x = targetNode.x + targetDis * Math.cos(Math.random() * Math.PI * 2);
}
if (targetNode.y && !sourceNode.y) {
sourceNode.y = targetNode.y + targetDis * Math.sin(Math.random() * Math.PI * 2);
}
if (!sourceNode.x && !sourceNode.y && globalV.manipulatePosition) {
sourceNode.x = globalV.manipulatePosition.x + 30 * Math.cos(Math.random() * Math.PI * 2);
sourceNode.y = globalV.manipulatePosition.y + 30 * Math.sin(Math.random() * Math.PI * 2);
}
if (!targetNode.x && !targetNode.y && globalV.manipulatePosition) {
targetNode.x = globalV.manipulatePosition.x + 30 * Math.cos(Math.random() * Math.PI * 2);
targetNode.y = globalV.manipulatePosition.y + 30 * Math.sin(Math.random() * Math.PI * 2);
}
});
const descreteNodeCenter = {
x: width - paddingLeft,
y: height - paddingTop
};
descreteNodes.forEach((node) => {
if (!node.x && !node.y) {
node.x = descreteNodeCenter.x + 30 * Math.cos(Math.random() * Math.PI * 2);
node.y = descreteNodeCenter.y + 30 * Math.sin(Math.random() * Math.PI * 2);
}
});
G6.Util.processParallelEdges(edges, 12.5, 'custom-quadratic', 'custom-line');
return {
maxDegree,
edges
};
}
dispatchDetail(model, isNode) {
if (isNode) {
const params = {
eid: model.id,
domain: getQueryString('domain')
};
store.dispatch('graphAside/NODE_DETAIL_ACTIONS', qs.stringify(params));
} else {
const params = {
rids: model.id,
domain: getQueryString('domain')
};
store.dispatch('graphAside/EDGE_DETAIL_ACTIONS', qs.stringify(params));
}
}
graphDataActions(res) {
// 临时用来去重
let newData = res.nodes.concat(); // 深拷贝
const set = new Set();
newData = newData.filter((item) => {
if (set.has(item.concept)) {
return false;
} else {
set.add(item.concept);
return true;
}
});
const arr = newData.map((item) => {
return item.concept;
});
const params2 = {
concepts: arr.join(),
graphId: getQueryString('graphId'),
domain: getQueryString('domain')
};
store.dispatch('graphAside/SET_GRAPH_DATA_ACTIONS', qs.stringify(params2));
}
// 更新右侧统计
updateDataStatistics(data) {
store.commit('graphAside/SET_GRAPH_DATA', data || globalV.basicData);
this.graphDataActions(data || globalV.basicData);
}
processClusteredData(data, isNewGraph, graph) {
globalV.basicData = data;
globalV.clusteredData = labelPropagation(globalV.basicData, false, 'weight');
const aggregatedData = { nodes: [], edges: [] }; // 聚合节点数据
const realData = [];
globalV.clusteredData.clusters.forEach((cluster, i) => {
// 真实节点
cluster.nodes.forEach((node) => {
node.level = 0;
node.type = '';
node.colorSet = colorSets[i];
globalV.nodeMap[node.id] = node;
realData.push(node);
});
// 聚合节点
const cnode = {
id: cluster.id,
type: 'aggregated-node',
count: cluster.nodes.length,
level: 1,
label: cluster.id,
colorSet: colorSets[i],
idx: i
};
globalV.aggregatedNodeMap[cluster.id] = cnode;
aggregatedData.nodes.push(cnode);
});
// 聚合节点的连线
globalV.clusteredData.clusterEdges.forEach((clusterEdge) => {
const cedge = {
...clusterEdge,
size: Math.log(clusterEdge.count),
label: '',
id: `edge-${uniqueId()}`
};
if (cedge.source === cedge.target) {
cedge.type = 'loop';
cedge.loopCfg = {
dist: 20
};
} else cedge.type = 'line';
aggregatedData.edges.push(cedge);
});
// 真实节点的连线
globalV.basicData.edges.forEach((edge) => {
edge.label = `${edge.relation || edge.label}`;
edge.id = `${edge.rid || edge.id}`;
edge.relation_id = `${edge.relation_id}`;
});
globalV.currentUnproccessedData = {
nodes: realData,
edges: globalV.basicData.edges
};
if (!isNewGraph) {
globalV.cachePositions = commonUtils.cacheNodePositions(graph.getNodes());
}
const { edges: processedRealEdges } = this.processNodesEdges(
realData,
globalV.basicData.edges,
globalV.CANVAS_WIDTH,
globalV.CANVAS_HEIGHT,
globalV.largeGraphMode,
true,
isNewGraph
);
return { realData, processedRealEdges };
}
// 子图布局
subLayout(focusNodes, configObj, graph, type) {
const edges = globalV.basicData.edges;
const newNodes = [];
const newEdges = [];
const newNodeMap = new Map();
// add the nodes which should be re-layout
focusNodes.forEach((item, i) => {
const model = item.getModel();
newNodes.push(model);
newNodeMap.set(model.id, i);
});
// add related edges
edges.forEach(function (edge) {
const sourceId = edge.source;
const targetId = edge.target;
if (newNodeMap.get(sourceId) !== undefined && newNodeMap.get(targetId) !== undefined) {
newEdges.push(edge);
}
});
const subForceLayout = new G6.Layout[type]({
...configObj,
center: [newNodes[0].x, newNodes[0].y], // 力导向和同心圆布局使用center
begin: [newNodes[0].x, newNodes[0].y], // 层级和网格和横纵向使用begin
onLayoutEnd: () => {
graph.refreshPositions();
},
tick: function tick() {
// the tick function to show the animation of layout process
graph.refreshPositions();
}
});
subForceLayout.init({
nodes: newNodes,
edges: newEdges
});
subForceLayout.execute();
}
};
const commonUtils = new CommonUtils();
export default commonUtils;

66
src/components/graphContainer/graph/dialogData.js

@ -0,0 +1,66 @@
// 节点扩展
export const nodeExtendData = {
title: '实体扩展',
data: [{
label: '实体类型',
inputType: 'select',
placeholder: '请选择实体类型',
field: 'conceptId',
multiple: true,
filterable: true
}],
formData: {
conceptId: []
},
rules: {
conceptId: { required: true, message: '请选择实体类型', trigger: 'change' }
}
}
// 边扩展
export const edgeExtendData = {
title: '关系扩展',
data: [{
label: '关系定义',
inputType: 'select',
placeholder: '请选择关系定义',
field: 'relationId',
multiple: true,
filterable: true
}],
formData: {
relationId: []
},
rules: {
relationId: { required: true, message: '请选择关系定义', trigger: 'change' }
}
}
// 最短路径探寻
export const customPathData = {
width: '50%',
title: '自定义路径探寻',
data: [{
label: '路径度数',
inputType: 'select',
placeholder: '请选择',
field: 'parthDegree',
options: [2, 3, 4, 5, 6],
width: 'width50'
}, {
label: '关系定义',
inputType: 'tree',
placeholder: '请选择',
field: 'relType',
multiple: true,
filterable: true,
options: [],
width: 'width90'
}],
formData: {
parthDegree: '',
relType: []
},
rules: {
parthDegree: { required: true, message: '请选择路径度数', trigger: 'change' }
// relType: { required: true, message: '请选择关系类型', trigger: 'change' }
}
}

61
src/components/graphContainer/graph/directive.js

@ -0,0 +1,61 @@
/**
* 鼠标拖拽指令
* 1.v-drag 该方式将移动作用在指令绑定的dom元素上
* 2.v-drag="{dom: '需要移动的dom元素的id'}" 该方式将移动所传参数指定的dom元素
*/
export const drag = {
// 当被绑定的元素插入到 DOM 中时……
inserted(el, binding) {
const customDom = binding.value ? binding.value.dom : null
let customDomEl
if (customDom) customDomEl = document.getElementById(customDom)
const gap = 10 // 缝隙:小于缝隙时,则吸附
const parent = customDom ? document.querySelector('#graph-layout') : el.offsetParent
const container = document.querySelector('#graph-layout')
el.onmousedown = function(event) {
const eleEvent = event || window.event // event的兼容,同时得到clientX,clientY的值
const x = customDom ? eleEvent.clientX - customDomEl.offsetLeft : eleEvent.clientX - el.offsetLeft
const y = customDom ? eleEvent.clientY - customDomEl.offsetTop : eleEvent.clientY - el.offsetTop
let left = 0
let top = 0
const elParentW = customDom ? customDomEl.offsetWidth : el.offsetWidth
const elParentH = customDom ? customDomEl.offsetHeight : el.offsetHeight
container.onmousemove = function(eve) {
left = eve.clientX - x
top = eve.clientY - y
// 左
if (left <= gap) {
left = 0
}
// 右
if (left >= parent.offsetWidth - elParentW - gap) { // 大于整个盒子的宽度-小盒子的宽度
left = parent.offsetWidth - elParentW
}
// 上
if (top <= gap) {
top = 0
}
// 下
if (top >= parent.offsetHeight - elParentH - gap) {
top = parent.offsetHeight - elParentH
}
if (customDom) {
customDomEl.style.left = left + 'px'
customDomEl.style.top = top + 'px'
} else {
el.style.left = left + 'px'
el.style.top = top + 'px'
}
}
container.onmouseup = function(e) {
container.onmousemove = null
container.onmouseup = null
}
document.onmouseup = function() {
container.onmousemove = null
container.onmouseup = null
}
}
}
}

24
src/components/graphContainer/graph/elementPlugin.js

@ -0,0 +1,24 @@
import Vue from 'vue'
let loadingInstance
/**
* element的loading组件(开启loading)
* @param {target: 作用的dom元素} opt
*/
export const openLoading = (opt) => {
const { target } = opt
loadingInstance = Vue.prototype.$loading({
lock: true,
target,
text: '拼命加载中',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.8)'
})
}
/**
* element的loading组件(关闭loading)
*/
export const closeLoading = () => {
if (loadingInstance) {
loadingInstance.close()
}
}

90
src/components/graphContainer/graph/globalData.js

@ -0,0 +1,90 @@
class GlobalGraphData {
constructor() {
this.NODESIZEMAPPING = 'degree' // 节点大小匹配条件
this.labelMaxLength = 10 // label文本显示的最大长度
this.DEFAULTNODESIZE = 30 // 真实节点的默认大小
this.DEFAULTAGGREGATEDNODESIZE = 53 // 聚合节点的默认大小
this.NODE_LIMIT = 40 // TODO: find a proper number for maximum node number on the canvas(画布上显示真实节点的最大数量限制)
// 默认节点的样式
this.defaultShapeStyle = {
border: 'solid',
bordercolor: '#5F95FF',
shape: 'circle',
shapecolor: '#2B384E'
}
this.duration = 2000
this.animateOpacity = 1 // 连线focus状态下线的透明度
this.virtualEdgeOpacity = 1 // 虚拟边的透明度
this.realEdgeOpacity = 1 // 真实边的透明度
this.darkBackColor = 'rgb(43, 47, 51)'
this.disableColor = '#777'
this.theme = 'dark'
this.subjectColors = [
'#5F95FF', // blue
'#61DDAA',
'#65789B',
'#F6BD16',
'#7262FD',
'#78D3F8',
'#9661BC',
'#F6903D',
'#008685',
'#F08BB4'
]
// 图元素的全局样式
this.global = {
node: {
style: {
fill: '#2B384E'
},
labelCfg: {
style: {
fill: '#000'// label颜色
}
},
stateStyles: {
focus: {
fill: '#2B384E'
}
}
},
edge: {
style: {
stroke: '#8A909A', // 聚合节点的线的颜色
realEdgeStroke: '#8A909A', // 真实节点的线的颜色
realEdgeOpacity: this.realEdgeOpacity,
strokeOpacity: this.realEdgeOpacity
},
labelCfg: {
style: {
fill: '#8A909A'
}
},
stateStyles: {
focus: {
stroke: '#fff'
}
}
}
}
this.largeGraphMode = false // 边上文字的显隐,true:默认不显示;false:默认显示;
this.aggregatedNodeMap = {}
this.clusteredData = {}
this.currentUnproccessedData = { nodes: [], edges: [] }
this.cachePositions = {}
this.CANVAS_WIDTH = 800 // canvas的宽度
this.CANVAS_HEIGHT = 800 // canvas的高度
this.zoom = 1 // canvas缩放比例
this.layout = {
type: '',
instance: null,
destroyed: true
}
this.hiddenItemIds = [] // 隐藏的元素 id 数组
this.nodeMap = {}
this.manipulatePosition = null
this.basicData = [] // 接口返回的原始数据(该变量会根据操作变化)
}
}
export const globalV = new GlobalGraphData()

163
src/components/graphContainer/graph/graph.js

@ -0,0 +1,163 @@
import request from './request'
// 关系图接口
export function getGraphData(data) {
return request({
url: '/graphApi/anlysis/analytic',
method: 'post',
data
})
}
// 获取中心节点
export function getCenterGraphData(params) {
return request({
url: '/graphApi/anlysis/getNodeDatasByGraphId',
method: 'get',
params
})
}
// 保存中心节点
export function graphCentraNodeSave(params) {
return request({
url: '/graphApi/anlysis/graphCentraNodeSave',
method: 'get',
params
})
}
// 根据关键词搜索实体
export function searchEntityByKeyword(params) {
return request({
url: '/graphApi/anlysis/ir',
method: 'get',
params
})
}
// 节点扩展
export function getOntConceptList(params) {
return request({
url: '/graphApi/anlysis/getOntConceptList',
method: 'get',
params
})
}
// 边扩展
export function getOntRelationList(params) {
return request({
url: '/graphApi/anlysis/getOntRelationList',
method: 'get',
params
})
}
// 根据节点的节点类型获取一度关联数据
export function expandByNodeType(params) {
return request({
url: '/graphApi/anlysis/expandByNodeType',
method: 'get',
params
})
}
// 根据节点的边类型获取一度关联数据
export function expandByEdgeType(params) {
return request({
url: '/graphApi/anlysis/expandByEdgeType',
method: 'get',
params
})
}
// 路径探寻
export function pathToExplore(data) {
return request({
url: '/graphApi/anlysis/pathToExplore',
method: 'post',
data
})
}
// 自定义路径探寻中的关系类型列表
export function categoryRelTree(data) {
return request({
url: '/graphApi/anlysis/categoryRelTree',
method: 'post',
data
})
}
// 自定义路径探寻中的关系父级类型列表
export function getRelationType(data) {
return request({
url: '/graphApi/anlysis/getRelationType',
method: 'post',
data
})
}
// 自定义路径探寻中的关系子级类型列表
export function getOntRelationQuery(data) {
return request({
url: '/graphApi/anlysis/getOntRelationQuery',
method: 'post',
data
})
}
// 时序分析
export function timingAnalysis(data) {
return request({
url: '/graphApi/anlysis/timingAnalysis',
method: 'post',
data
})
}
// 删除节点
export function deleteEntityByGraphId(data) {
return request({
url: '/graphApi/anlysis/deleteEntityByGraphId',
method: 'post',
data
})
}
// 删除关系
export function deleteEntityRelation(data) {
return request({
url: '/graphApi/project/deleteEntityRelation',
method: 'post',
data
})
}
// 概念id和name的映射接口
export function conceptAnalytic(data) {
return request({
url: '/graphApi/anlysis/conceptAnalytic',
method: 'post',
data
})
}
// 获取单个节点详情的接口
export function entityInfo(data) {
return request({
url: '/graphApi/anlysis/entityInfo',
method: 'post',
data
})
}
// 获取单个关系详情的接口
export function entity_relation_byrids(data) {
return request({
url: '/graphApi/anlysis/entityRelationByrids',
method: 'post',
data
})
}

639
src/components/graphContainer/graph/menu.js

@ -0,0 +1,639 @@
import { Message } from 'winbox-ui';
import qs from 'qs';
import { globalV } from './globalData';
import { getGraphData, expandByNodeType, expandByEdgeType } from './graph';
import commonUtils from './common';
import store from '@/store';
import { EventBus } from '../eventBus';
import { getQueryString } from './publicFunction';
import { openLoading, closeLoading } from './elementPlugin';
import { deleteEntityByGraphId, deleteEntityRelation } from './graph';
import G6 from '@antv/g6';
const { labelPropagation } = G6.Algorithm; // 图算法
const colorSets = G6.Util.getColorSetsBySubjectColors(globalV.subjectColors, globalV.darkBackColor, globalV.theme, globalV.disableColor);
const { uniqueId } = G6.Util;
class MenuHandle {
async getNeighborMixedGraph(
centerNodeModel,
step,
originData,
clusteredData,
currentData,
nodeMap,
aggregatedNodeMap,
maxNeighborNumPerNode = 5,
expandType,
formData
) {
try {
// update the manipulate position for center gravity of the new nodes
globalV.manipulatePosition = { x: centerNodeModel.x, y: centerNodeModel.y };
// the neighborSubGraph does not include the centerNodeModel. the elements are all generated new nodes and edges
// const neighborSubGraph = generateNeighbors(centerNodeModel, step, maxNeighborNumPerNode);
const neighborSubGraph = {
nodes: [],
edges: []
};
const tempNeighborSubGraph = await this.generateNeighbors(centerNodeModel, step, maxNeighborNumPerNode, expandType, formData);
setTimeout(() => {
EventBus.$emit('timeaxis', true);
}, 200);
tempNeighborSubGraph.nodes.forEach((item) => {
const nodeArr = originData.nodes.filter((oriItem) => {
return oriItem.id === item.id;
});
if (!nodeArr.length) neighborSubGraph.nodes.push(item);
});
tempNeighborSubGraph.edges.forEach((item) => {
const edgeArr = originData.edges.filter((oriItem) => {
return item.source === oriItem.source && item.target === oriItem.target;
});
if (!edgeArr.length) neighborSubGraph.edges.push(item);
});
// update the origin data
originData.nodes = originData.nodes.concat(neighborSubGraph.nodes);
originData.edges = originData.edges.concat(neighborSubGraph.edges);
// update the origin nodeMap
neighborSubGraph.nodes.forEach((node) => {
nodeMap[node.id] = node;
});
// 扩展如果没有新的数据,提示无数据
if (currentData.nodes.length === globalV.basicData.nodes.length && currentData.edges.length === globalV.basicData.edges.length) {
// 将扩展新增的节点和边存储起来,用于扩展后高亮这些节点和边
store.commit('graphMenu/SET_EXTENDDATA', tempNeighborSubGraph);
Message({
message: '当前节点没有可扩展的数据!',
type: 'warning',
duration: 5000
});
return currentData;
} else {
// 将扩展新增的节点和边存储起来,用于扩展后高亮这些节点和边
store.commit('graphMenu/SET_EXTENDDATA', neighborSubGraph);
}
// update the clusteredData
const clusterId = centerNodeModel.clusterId;
clusteredData.clusters.forEach((cluster) => {
if (cluster.id !== clusterId) return;
cluster.nodes = cluster.nodes.concat(neighborSubGraph.nodes);
cluster.sumTot += neighborSubGraph.edges.length;
});
// update the count
aggregatedNodeMap[clusterId].count += neighborSubGraph.nodes.length;
currentData.nodes = currentData.nodes.concat(neighborSubGraph.nodes);
currentData.edges = currentData.edges.concat(neighborSubGraph.edges);
return currentData;
} catch (error) {
console.log(error);
}
}
generateNeighbors(centerNodeModel, step, maxNeighborNumPerNode = 5, expandType, formData) {
if (step <= 0) return undefined;
const nodes = [];
const edges = [];
const clusterId = centerNodeModel.clusterId;
const centerId = centerNodeModel.id;
return new Promise((resolve, reject) => {
openLoading({ target: '.chart-explore-container' });
if (expandType === 'node') {
const params = {
graphId: getQueryString('graphId'),
domain: getQueryString('domain'),
conceptId: formData.conceptId ? formData.conceptId.join() : '',
maxdist: 1,
eid: centerId,
force: false,
direction: formData.direction ? formData.direction : '',
flag: formData.flag
};
if (!params.flag) {
delete params.flag;
}
expandByNodeType(params).then((res) => {
const obj = this.processNeighbors(res, clusterId, centerNodeModel, nodes, edges, centerId);
resolve(obj);
});
} else if (expandType === 'edge') {
const params = {
graphId: getQueryString('graphId'),
domain: getQueryString('domain'),
relationId: formData.relationId.join(),
maxdist: 1,
eid: centerId,
force: false
};
expandByEdgeType(params).then((res) => {
const obj = this.processNeighbors(res, clusterId, centerNodeModel, nodes, edges, centerId);
resolve(obj);
});
} else {
const params = {
graphId: getQueryString('graphId'),
domain: getQueryString('domain'),
eid: centerId,
maxdist: 1,
force: false
};
getGraphData(qs.stringify(params)).then((data) => {
const obj = this.processNeighbors(data, clusterId, centerNodeModel, nodes, edges, centerId);
// resolve({ nodes, edges })
resolve(obj);
});
}
});
}
processNeighbors(data, clusterId, centerNodeModel, nodes, edges, centerId) {
closeLoading();
let g6Data = {
nodes: [],
edges: []
};
if (JSON.stringify(data) !== '{}') g6Data = data.d3data;
g6Data.nodes.forEach((item) => {
const neighborNode = {
id: item.id,
clusterId,
level: 0,
name: item.name,
colorSet: centerNodeModel.colorSet,
concept: item.concept
};
nodes.push(neighborNode);
});
g6Data.edges.forEach((item) => {
const source = g6Data.nodes[item.source].id === centerId ? centerId : g6Data.nodes[item.source].id;
const target = g6Data.nodes[item.target].id === centerId ? centerId : g6Data.nodes[item.target].id;
const neighborEdge = {
id: item.rid,
source,
target,
label: `${item.relation}`,
relation_id: item.relation_id,
relation: item.relation,
rid: item.rid,
rids: item.rids,
sourceNum: item.source,
targetNum: item.target
};
edges.push(neighborEdge);
});
for (const key in g6Data.concepts) {
if (globalV.basicData.concepts[key] === undefined) {
globalV.basicData.concepts[key] = g6Data.concepts[key];
}
}
return { nodes, edges };
}
examAncestors(model, expandedArray, length, keepTags) {
for (let i = 0; i < length; i++) {
const expandedNode = expandedArray[i];
if (!keepTags[i] && model.parentId === expandedNode.id) {
keepTags[i] = true; // 需要被保留
this.examAncestors(expandedNode, expandedArray, length, keepTags);
break;
}
}
}
manageExpandCollapseArray(nodeNumber, model, collapseArray, expandArray, graph) {
globalV.manipulatePosition = { x: model.x, y: model.y };
// 维护 expandArray,若当前画布节点数高于上限,移出 expandedArray 中非 model 祖先的节点)
if (nodeNumber > globalV.NODE_LIMIT) {
// 若 keepTags[i] 为 true,则 expandedArray 的第 i 个节点需要被保留
const keepTags = {};
const expandLen = expandArray.length;
// 检查 X 的所有祖先并标记 keepTags
this.examAncestors(model, expandArray, expandLen, keepTags);
// 寻找 expandedArray 中第一个 keepTags 不为 true 的点
let shiftNodeIdx = -1;
for (let i = 0; i < expandLen; i++) {
if (!keepTags[i]) {
shiftNodeIdx = i;
break;
}
}
// 如果有符合条件的节点,将其从 expandedArray 中移除
if (shiftNodeIdx !== -1) {
let foundNode = expandArray[shiftNodeIdx];
if (foundNode.level === 2) {
let foundLevel1 = false;
// 找到 expandedArray 中 parentId = foundNode.id 且 level = 1 的第一个节点
for (let i = 0; i < expandLen; i++) {
const eNode = expandArray[i];
if (eNode.parentId === foundNode.id && eNode.level === 1) {
foundLevel1 = true;
foundNode = eNode;
expandArray.splice(i, 1);
break;
}
}
// 若未找到,则 foundNode 不变, 直接删去 foundNode
if (!foundLevel1) expandArray.splice(shiftNodeIdx, 1);
} else {
// 直接删去 foundNode
expandArray.splice(shiftNodeIdx, 1);
}
// const removedNode = expandedArray.splice(shiftNodeIdx, 1); // splice returns an array
const idSplits = foundNode.id.split('-');
let collapseNodeId;
// 去掉最后一个后缀
for (let i = 0; i < idSplits.length - 1; i++) {
const str = idSplits[i];
if (collapseNodeId) collapseNodeId = `${collapseNodeId}-${str}`;
else collapseNodeId = str;
}
const collapseNode = {
id: collapseNodeId,
parentId: foundNode.id,
level: foundNode.level - 1
};
collapseArray.push(collapseNode);
}
}
const currentNode = {
id: model.id,
level: model.level,
parentId: model.parentId
};
// 加入当前需要展开的节点
expandArray.push(currentNode);
graph.get('canvas').setCursor('default');
return { expandArray, collapseArray };
}
// 反选
selectInvert(graph, model) {
graph.getNodes().forEach((node) => {
const nodeModel = node.getModel();
if (!node.hasState('focus') && nodeModel.id !== model.id) {
graph.setItemState(node, 'focus', true);
} else {
graph.setItemState(node, 'focus', false);
}
});
commonUtils.setFocusNodes(graph);
}
// 反选删除(支持单个节点和多节点)
selectInvertDelete(graph, item, model) {
const nodes = [];
graph.getNodes().forEach((node) => {
const nodeModel = node.getModel();
if ((nodeModel.id !== model.id && !item.hasState('focus')) || (item.hasState('focus') && !node.hasState('focus'))) {
nodes.push(node);
}
});
this.deleteNodes(nodes, graph);
}
// 选择一度
selectOneDegree(graph, item) {
const itemHaveFocus = item.hasState('focus');
commonUtils.clearFocusItemState(graph);
const data = {
nodes: [],
edges: []
};
item.getEdges().forEach((edge) => {
data.edges.push(edge.getModel());
});
var neighborNodes;
if (itemHaveFocus) {
// 选中状态
neighborNodes = item.getNeighbors().concat(item);
} else {
neighborNodes = item.getNeighbors();
}
neighborNodes.forEach((node) => {
graph.setItemState(node, 'focus', true);
data.nodes.push(node.getModel());
});
// store.commit('aside/SET_GRAPH_DATA', data)
commonUtils.setFocusNodes(graph);
}
// 全选节点
selectAll(graph) {
graph.getNodes().forEach((node) => {
if (!node.hasState('focus')) {
graph.setItemState(node, 'focus', true);
}
});
commonUtils.setFocusNodes(graph);
}
// 高亮节点
highlightSomeNodes(graph, ids) {
graph.getNodes().forEach((node) => {
const nodeModel = node.getModel();
if (ids.indexOf(nodeModel.id) > -1) {
graph.setItemState(node, 'focus', true);
} else {
graph.setItemState(node, 'focus', false);
}
});
commonUtils.setFocusNodes(graph);
}
// 高亮边
highlightSomeEdges(graph, ids) {
graph.getEdges().forEach((edge) => {
const edgeModel = edge.getModel();
if (ids.indexOf(edgeModel.id) > -1) {
graph.setItemState(edge, 'focus', true);
} else {
graph.setItemState(edge, 'focus', false);
}
});
}
// 清除所有节点和边的状态
clearNodesEdgesState(graph) {
graph.getNodes().forEach((node) => {
graph.clearItemStates(node);
});
graph.getEdges().forEach((edge) => {
graph.clearItemStates(edge);
});
}
// 清除多个节点和边的状态
clearMultipleNodesEdgesState(graph, nodes) {
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
graph.setItemState(nodeModel, 'focus', false);
const relatedEdges = nodeModel.getEdges();
relatedEdges.forEach((edge) => {
graph.setItemState(edge, 'focus', false);
});
});
}
// 清除多个边状态
clearMultipleEdgesState(graph, edges) {
(edges || []).forEach((edge) => {
const edgeModel = graph.findById(edge.id);
graph.setItemState(edgeModel, 'focus', false);
});
}
// 删除关系
deleteEdges(graph, data) {
openLoading({ target: '.chart-explore-container' });
deleteEntityRelation(data).then((res) => {
closeLoading();
if (res && res.status == 'SUCCESS') {
EventBus.$emit('deleteRelation', false);
store.commit('graphAside/SET_RELATION_SHIP', '');
Message({
message: '删除成功!',
type: 'success',
offset: 100,
duration: 2000
});
globalV.basicData.edges.forEach((edge, index) => {
if (data.id == edge.id) {
globalV.basicData.edges.splice(index, 1);
}
});
globalV.currentUnproccessedData.edges.forEach((edge, index) => {
if (data.id == edge.id) {
globalV.currentUnproccessedData.edges.splice(index, 1);
}
});
const edgeModel = graph.findById(data.id);
graph.removeItem(edgeModel);
globalV.clusteredData = labelPropagation(globalV.basicData, false, 'weight');
globalV.clusteredData.clusters.forEach((cluster, i) => {
// 聚合节点
const cnode = {
id: cluster.id,
type: 'aggregated-node',
count: cluster.nodes.length,
level: 1,
label: cluster.id,
colorSet: colorSets[i],
idx: i
};
globalV.aggregatedNodeMap[cluster.id] = cnode;
});
// 聚合节点的连线
globalV.clusteredData.clusterEdges.forEach((clusterEdge) => {
const cedge = {
...clusterEdge,
size: Math.log(clusterEdge.count),
label: '',
id: `edge-${uniqueId()}`
};
if (cedge.source === cedge.target) {
cedge.type = 'loop';
cedge.loopCfg = {
dist: 20
};
} else cedge.type = 'line';
});
commonUtils.setFocusNodes(graph);
commonUtils.updateDataStatistics();
} else {
EventBus.$emit('deleteRelation', false);
Message({
message: '删除失败!',
type: 'error'
});
}
});
}
// 删除节点
deleteNodes(nodes, graph) {
openLoading({ target: '.chart-explore-container' });
const delIds = nodes.map((item) => {
const model = item.getModel();
return model.id;
});
const delEdges = [];
deleteEntityByGraphId({ eids: delIds, graphId: getQueryString('graphId'), projectId: getQueryString('projectId') }).then((res) => {
closeLoading();
if (!res) {
Message({
message: '删除成功!',
type: 'success',
offset: 100,
duration: 2000
});
nodes.forEach((node) => {
const edges = node.getEdges();
const nodeModel = node.getModel();
if (globalV.nodeMap[nodeModel.id]) {
delete globalV.nodeMap[nodeModel.id];
}
edges.forEach((edge) => {
const edgeModel = edge.getModel();
delEdges.push(edgeModel.id);
});
graph.removeItem(node);
});
globalV.basicData.nodes = globalV.basicData.nodes.filter((node) => {
return node && delIds.indexOf(node.id) === -1;
});
globalV.basicData.edges = globalV.basicData.edges.filter((edge) => {
return edge && delEdges.indexOf(edge.id) === -1;
});
globalV.currentUnproccessedData.nodes = globalV.currentUnproccessedData.nodes.filter((node) => {
return node && delIds.indexOf(node.id) === -1;
});
globalV.currentUnproccessedData.edges = globalV.currentUnproccessedData.edges.filter((edge) => {
return edge && delEdges.indexOf(edge.id) === -1;
});
globalV.clusteredData = labelPropagation(globalV.basicData, false, 'weight');
globalV.clusteredData.clusters.forEach((cluster, i) => {
// 聚合节点
const cnode = {
id: cluster.id,
type: 'aggregated-node',
count: cluster.nodes.length,
level: 1,
label: cluster.id,
colorSet: colorSets[i],
idx: i
};
globalV.aggregatedNodeMap[cluster.id] = cnode;
});
// 聚合节点的连线
globalV.clusteredData.clusterEdges.forEach((clusterEdge) => {
const cedge = {
...clusterEdge,
size: Math.log(clusterEdge.count),
label: '',
id: `edge-${uniqueId()}`
};
if (cedge.source === cedge.target) {
cedge.type = 'loop';
cedge.loopCfg = {
dist: 20
};
} else cedge.type = 'line';
});
commonUtils.setFocusNodes(graph);
commonUtils.updateDataStatistics();
} else {
Message({
message: '删除失败!',
type: 'error'
});
}
});
}
// 删除选中的节点
deleteFocusNodes(graph) {
const nodes = graph.findAllByState('node', 'focus');
if (!nodes.length) {
Message({
message: '当前没有选中的节点!',
type: 'warning',
duration: 2000
});
return false;
}
this.deleteNodes(nodes, graph);
}
// 节点隐藏
hideNodes(graph, nodes) {
(nodes || []).forEach((node) => {
graph.hideItem(node.id);
graph.clearItemStates(node.id);
});
}
// 边隐藏
hideEdges(graph, nodes) {
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
nodeModel.hide(nodeModel);
});
}
// 边、节点取消高亮
cancleHighLightEdgesNodes(graph, nodes) {
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
graph.setItemState(nodeModel, 'focus', false);
});
}
// 节点显示
showFocusNodesAndShowEdges(graph, nodes) {
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
graph.showItem(node.id);
graph.setItemState(nodeModel, 'focus', true);
});
}
// 节点显示
showNodes(graph, nodes) {
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
graph.showItem(node.id);
graph.setItemState(nodeModel, 'focus', true);
const relatedEdges = nodeModel.getEdges();
relatedEdges.forEach((edge) => {
graph.setItemState(edge, 'focus', true);
});
});
}
// 边显示
showEdges(graph, nodes) {
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
nodeModel.show(nodeModel);
graph.setItemState(nodeModel, 'focus', true);
});
}
// 查看节点或边的显示或隐藏状态
edgeOrNodesIsVisible(type, graph, nodes) {
var resultStatus;
(nodes || []).forEach((node) => {
const nodeModel = graph.findById(node.id);
if (type == 1) {
// 判断是否全显示
if (!nodeModel.isVisible(nodeModel)) {
resultStatus = false;
} else {
resultStatus = true;
}
} else if (type == 2) {
// 判断全隐藏
if (!nodeModel.isVisible(nodeModel)) {
resultStatus = false;
} else {
resultStatus = true;
}
}
});
return resultStatus;
}
// 缩放
zoom(graph, type) {
const ratio = type === 'big' ? 0.1 : -0.1;
if ((globalV.zoom >= 0.2 && type === 'small') || (globalV.zoom <= 9.9 && type === 'big')) {
// 使用+和-进行缩放时,比例是10的倍数
const fixedOneBit = Math.round(globalV['zoom'] * 10) / 10; // 四舍五入
globalV.zoom = Number((fixedOneBit + ratio).toFixed(1));
graph.zoomTo(globalV.zoom, { x: globalV.CANVAS_WIDTH / 2, y: globalV.CANVAS_HEIGHT / 2 });
store.commit('graphMenu/SET_ZOOM', globalV.zoom);
}
}
// 通过搜索框添加节点使该节点高亮并且移动到画布中心
moveNodeCenter(graph, addNodeId) {
graph.setItemState(addNodeId, 'focus', true);
graph.focusItem(addNodeId, true);
}
// 显示并高亮元素(param:元素的id)
showHighItem(arr, graph) {
(arr || []).forEach((id) => {
const model = graph.findById(id);
if (!model.isVisible()) {
model.show();
}
if (!model.hasState('focus')) {
graph.setItemState(id, 'focus', true);
}
});
}
}
const menuHandle = new MenuHandle();
export default menuHandle;

65
src/components/graphContainer/graph/publicFunction.js

@ -0,0 +1,65 @@
export const getQueryString = function(name){//获取带#的url参数
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
if(window.location.hash.indexOf("?") < 0){
return null;
}
let r = window.location.hash.split("?")[1].match(reg);
if (r != null) return decodeURIComponent(r[2]);
return null;
}
/**
* 截取字符串(通过substring实现并支持中英文混合)
* @param str
* @param n 需要截取的长度
* @returns {*}
*/
export const sub = function (str, n) {
if (!str) return str
const r = /[^\x00-\xff]/g
if (str.replace(r, '**').length <= n) { return str }
const m = Math.floor(n / 2)
for (let i = m; i < str.length; i++) {
if (str.substr(0, i).replace(r, '**').length >= n) {
return str.substr(0, i) + '...'
}
}
return str
}
// 防抖
export const _debounce = function(fn, delay) {
var delay = delay || 200
var timer
return function() {
var th = this
var args = arguments
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
timer = null
fn.apply(th, args)
}, delay)
}
}
// 节流
export const _throttle = function(fn, interval) {
var last
var timer
var interval = interval || 200
return function() {
var th = this
var args = arguments
var now = +new Date()
if (last && now - last < interval) {
clearTimeout(timer)
timer = setTimeout(function() {
last = now
fn.apply(th, args)
}, interval)
} else {
last = now
fn.apply(th, args)
}
}
}

486
src/components/graphContainer/graph/registerNodeEdge.js

@ -0,0 +1,486 @@
import G6 from '@antv/g6'
import { globalV } from './globalData'
const ExploreGraph = class ExploreGraph {
constructor() {
this.colorSets = G6.Util.getColorSetsBySubjectColors(
globalV.subjectColors,
globalV.darkBackColor,
globalV.theme,
globalV.disableColor
)
}
// 自定义节点和边
registerNodeEdge() {
this.registerAggregatedNode()
this.registerRealNode()
this.registerQuadraticEdge()
this.registerCustomEdge()
}
registerAggregatedNode() {
const that = this
// Custom super node
// 自定义聚合节点
G6.registerNode(
'aggregated-node',
{
draw(cfg, group) {
const width = 53
const height = 27
const style = cfg.style || {}
const colorSet = cfg.colorSet || that.colorSets[0]
// halo for hover(hover状态时的光晕)
group.addShape('rect', {
attrs: {
x: -width * 0.55,
y: -height * 0.6,
width: width * 1.1,
height: height * 1.2,
fill: colorSet.mainFill,
opacity: 0.9,
lineWidth: 0,
radius: (height / 2 || 13) * 1.2
},
name: 'halo-shape',
visible: false
})
// focus stroke for hover(hover状态时的描边)
group.addShape('rect', {
attrs: {
x: -width * 0.55,
y: -height * 0.6,
width: width * 1.1,
height: height * 1.2,
fill: colorSet.mainFill, // '#3B4043',
stroke: '#AAB7C4',
lineWidth: 1,
lineOpacty: 0.85,
radius: (height / 2 || 13) * 1.2
},
name: 'stroke-shape',
visible: false
})
const keyShape = group.addShape('rect', {
attrs: {
...style,
x: -width / 2,
y: -height / 2,
width,
height,
fill: colorSet.mainFill, // || '#3B4043',
stroke: colorSet.mainStroke,
lineWidth: 2,
cursor: 'pointer',
radius: height / 2 || 13,
lineDash: [2, 2]
},
name: 'aggregated-node-keyShape'
})
let labelStyle = {} // eslint-disable-line no-unused-vars
if (cfg.labelCfg) {
labelStyle = Object.assign(labelStyle, cfg.labelCfg.style)
}
// 聚合节点包含的真实节点的数量text
group.addShape('text', {
attrs: {
text: `${cfg.count}`,
x: 0,
y: 0,
textAlign: 'center',
textBaseline: 'middle',
cursor: 'pointer',
fontSize: 12,
fill: '#fff',
opacity: 0.85,
fontWeight: 400
},
name: 'count-shape',
className: 'count-shape',
draggable: true
})
return keyShape
},
setState: (name, value, item) => {
const group = item.get('group')
if (name === 'layoutEnd' && value) {
const labelShape = group.find((e) => e.get('name') === 'text-shape')
if (labelShape) labelShape.set('visible', true)
} else if (name === 'hover') {
if (item.hasState('focus')) {
return
}
const halo = group.find((e) => e.get('name') === 'halo-shape')
const keyShape = item.getKeyShape()
const colorSet = item.getModel().colorSet || that.colorSets[0]
if (value) {
halo && halo.show()
keyShape.attr('fill', colorSet.activeFill)
} else {
halo && halo.hide()
keyShape.attr('fill', colorSet.mainFill)
}
} else if (name === 'focus') {
const stroke = group.find((e) => e.get('name') === 'stroke-shape')
const keyShape = item.getKeyShape()
const colorSet = item.getModel().colorSet || that.colorSets[0]
if (value) {
stroke && stroke.show()
keyShape.attr('fill', colorSet.selectedFill)
} else {
stroke && stroke.hide()
keyShape.attr('fill', colorSet.mainFill)
}
}
},
update: undefined
},
'single-node'
)
}
registerRealNode() {
// Custom real node
// 自定义真实节点
G6.registerNode(
'real-node',
{
draw(cfg, group) {
const style = cfg.style || {}
// 选中节点的边框
group.addShape('circle', {
attrs: {
x: 0,
y: 0,
r: (cfg.size / 2) * 1.8,
fill: '#rgba(255,255,255,.4)',
// stroke: cfg.shapeStyle.bordercolor,
opacity: 1,
lineWidth: 6
// lineDash:[2,2,2,2],//边框虚线
},
name: 'selected-shape',
visible: false
})
const keyShape = group.addShape('circle', {
attrs: {
...style,
width: cfg.size,
height: cfg.size,
r: cfg.size / 2,
fill: cfg.shapeStyle.bordercolor,
// stroke: cfg.shapeStyle.bordercolor,
// strokeOpacity: 0.8,
lineWidth: 2,
cursor: 'pointer'
},
name: 'bg-node-keyShape',
draggable: true
})
let point = -cfg.size * 7 / 20
let wh = cfg.size * 7 / 10
if (cfg.img.includes('/static/defaultNode.png')) {
point = -cfg.size / 2
wh = cfg.size
}
group.addShape('image', {
attrs: {
...style,
x: point,
y: point,
img: cfg.img,
width: wh,
height: wh,
cursor: 'pointer'
},
name: 'aggregated-node-keyShape',
draggable: true
})
let labelStyle = {} // eslint-disable-line no-unused-vars
if (cfg.labelCfg) {
labelStyle = Object.assign(labelStyle, cfg.labelCfg.style)
}
if (cfg.label) {
const text = cfg.label
let labelStyle = {}
if (cfg.labelCfg) {
labelStyle = Object.assign(labelStyle, cfg.labelCfg.style)
}
const fontSize = labelStyle.fontSize < 8 ? 8 : labelStyle.fontSize
group.addShape('text', {
attrs: {
text,
// x: cfg.size / 2,
// y: cfg.size + cfg.labelCfg.style.fontSize + 5,
y: cfg.size / 2 + cfg.labelCfg.style.fontSize + 5,
textAlign: 'center',
textBaseLine: 'alphabetic',
cursor: 'pointer',
fontsize:20,
fill: cfg.labelCfg.style.fill,
fontWeight: 100,
fontFamily: 'Microsoft YaHei'
},
name: 'text-shape',
className: 'text-shape'
})
}
return keyShape
},
setState: (name, value, item) => {
const model = item.getModel()
const group = item.get('group')
const textShape = group.find((ele) => ele.get('name') === 'text-shape')
if (name === 'layoutEnd' && value) {
const labelShape = group.find((e) => e.get('name') === 'text-shape')
if (labelShape) labelShape.set('visible', true)
} else if (name === 'hover') {
// if (item.hasState('focus')) {
// return
// }
const labelShape = group.find((e) => e.get('name') === 'text-shape')
// if (value) {
// labelShape.attr('text', item.getModel().oriLabel)
// } else {
// labelShape.attr('text', item.getModel().label)
// }
item.getModel().label && labelShape.attr('text', item.getModel().label)
} else if (name === 'focus') {
const selected = group.find((e) => e.get('name') === 'selected-shape')
// const label = group.find((e) => e.get('name') === 'text-shape')
const bgNode = group.find((e) => e.get('name') === 'bg-node-keyShape')
if (value) {
if (item.getModel().label) {
textShape.attr({
fill: '#000',
fontWeight: 'bold',
fontsize:20,
})
}
selected && selected.show()
// label && label.attr('fontWeight', 800)
bgNode && bgNode.attr('lineWidth', 0)
} else {
if (item.getModel().label) {
textShape.attr({
fill: '#000',
fontWeight: 100
})
}
selected && selected.hide()
// label && label.attr('fontWeight', 400)
bgNode && bgNode.attr('lineWidth', 2)
}
}
},
afterDraw(cfg, group) {
const shape = group.get('children')[0]
shape.animate(
{
opacity: 0
},
{
repeat: true,
duration: 2000,
easing: 'easeCubic'
}
)
shape.animate(
{
fill: '#2F6BFF'
},
{
repeat: true,
duration: 2000,
easing: 'easeCubic'
}
)
shape.animate(
(ratio) => {
const diff = ratio <= 0.5 ? ratio * 25 : (1 - ratio) * 25
let radius = cfg.size
if (isNaN(radius)) radius = radius[0]
return {
r: radius / 2 + diff
}
},
{
repeat: true,
duration: 2000,
easing: 'easeCubic'
}
)
},
update: undefined
},
'aggregated-node'
) // 这样可以继承 aggregated-node 的 setState
}
registerQuadraticEdge() {
// Custom the quadratic edge for multiple edges between one node pair
G6.registerEdge(
'custom-quadratic',
{
setState: (name, value, item) => {
const group = item.get('group')
const model = item.getModel()
if (name === 'focus') {
const keyShape = group.find((ele) => ele.get('name') === 'edge-shape')
const textShape = group.find((ele) => ele.get('name') === 'text-shape')
const arrow = model.style.endArrow
textShape.attr({
fill: '#0081ff',
fontWeight: 'bold'
})
if (value) {
keyShape.attr({
strokeOpacity: globalV.animateOpacity,
opacity: globalV.animateOpacity,
stroke: '#0081ff',
endArrow: {
...arrow,
stroke: '#0081ff',
fill: '#0081ff'
}
})
} else {
textShape.attr({
fill: '#98A7B9',
fontWeight: 100
})
const stroke = '#4E596C'
const opacity = model.isReal ? globalV.realEdgeOpacity : globalV.virtualEdgeOpacity
keyShape.attr({
stroke,
strokeOpacity: opacity,
opacity,
endArrow: {
...arrow,
stroke,
fill: stroke
}
})
}
} else {
textShape.attr({
fill: '#98A7B9',
fontWeight: 100
})
}
// const lineDash = [4, 2, 1, 2];
// // 获得该边的第一个图形,这里是边的 path
// const shape = group.get('children')[0];
// if(shape.cfg&&shape.cfg.animating==true){
// shape.stopAnimate();
// shape.attr('lineDash', null);
// }else{
// let index = 0;
// // 边 path 图形的动画
// shape.animate(
// () => {
// index++;
// if (index > 9) {
// index = 0;
// }
// const res = {
// lineDash,
// lineDashOffset: -index,
// };
// // 返回需要修改的参数集,这里修改了 lineDash,lineDashOffset
// return res;
// },
// {
// repeat: true, // 动画重复
// duration: 3000, // 一次动画的时长为 3000
// },
// );
// }
}
},
'quadratic'
)
}
registerCustomEdge() {
// Custom the line edge for single edge between one node pair
G6.registerEdge(
'custom-line',
{
setState: (name, value, item) => {
const group = item.get('group')
const model = item.getModel()
if (name === 'focus') {
const keyShape = group.find((ele) => ele.get('name') === 'edge-shape')
const textShape = group.find((ele) => ele.get('name') === 'text-shape')
textShape.attr({
fill: '#0081ff',
fontWeight: 'bold'
})
const arrow = model.style.endArrow
if (value) {
keyShape.attr({
strokeOpacity: globalV.animateOpacity,
opacity: globalV.animateOpacity,
stroke: '#0081ff',
endArrow: {
...arrow,
stroke: '#0081ff',
fill: '#0081ff'
}
})
} else {
textShape.attr({
fill: '#98A7B9',
fontWeight: 100
})
const stroke = '#4E596C'
const opacity = model.isReal ? globalV.realEdgeOpacity : globalV.virtualEdgeOpacity
keyShape.attr({
stroke,
strokeOpacity: opacity,
opacity,
endArrow: {
...arrow,
stroke,
fill: stroke
}
})
}
} else {
textShape.attr({
fill: '#98A7B9',
fontWeight: 100
})
}
// const lineDash = [4, 2, 1, 2];
// // 获得该边的第一个图形,这里是边的 path
// const shape = group.get('children')[0];
// if(shape.cfg&&shape.cfg.animating==true){
// shape.stopAnimate();
// shape.attr('lineDash', null);
// }else{
// let index = 0;
// // 边 path 图形的动画
// shape.animate(
// () => {
// index++;
// if (index > 9) {
// index = 0;
// }
// const res = {
// lineDash,
// lineDashOffset: -index,
// };
// // 返回需要修改的参数集,这里修改了 lineDash,lineDashOffset
// return res;
// },
// {
// repeat: true, // 动画重复
// duration: 3000, // 一次动画的时长为 3000
// },
// );
// }
}
},
'single-edge'
)
}
}
const exploreGraph = new ExploreGraph()
export default exploreGraph

148
src/components/graphContainer/graph/request.js

@ -0,0 +1,148 @@
import axios from 'axios';
import {
MessageBox,
Message
// Loading
} from 'winbox-ui';
import store from '@/store';
// let loading
// const option = {
// lock: true,
// text: '加载中……',
// background: 'rgba(251, 251, 251, 0.8)'
// }
// create an axios instance
const service = axios.create({
// baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
baseURL: '',
// withCredentials: true, // send cookies when cross-domain requests
timeout: 900000 // request timeout
});
// request interceptor
service.interceptors.request.use(
(config) => {
// do something before request is sent
// loading = Loading.service(option)
if (config.url.includes('/auth/api/')) {
config.baseURL = '';
} else {
config.baseURL = process.env.VUE_APP_BASE_API;
}
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
}
return config;
},
(error) => {
// do something with request error
console.log(error); // for debug
return Promise.reject(error);
}
);
// response interceptor
function arrayOrObjNotHaveValue(params) {
if (params === null || params === undefined) return false;
if (typeof params === 'object') {
if (Object.keys(params).length) {
return true;
} else {
return false;
}
} else if (Array.isArray(params)) {
if (params.length) {
return true;
} else {
return false;
}
} else if (typeof params === 'string' || typeof params === 'number' || typeof params === 'boolean') {
return true;
} else if (typeof params === 'function') {
return true;
} else {
return false;
}
}
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
(response) => {
if (response.data.code == '000400') {
// 请求未认证跳转登录
// Message({
// type: 'warning',
// message: response.data.msg
// })
window.localStorage.removeItem('userInfo');
if (getCookie('redirectUrl') && process.env.NODE_ENV === 'production') {
// window.location.href = getCookie('redirectUrl')
}
} else if (response.data.code == '-1') {
return response.data;
} else {
if (response.config.url.includes('/auth/api/')) {
return response;
} else {
return response.data.data;
}
}
// const res = response.data
// loading.close()
// if the custom code is not 20000, it is judged as an error.
// if (response.status !== 200) {
// Message({
// message: res.message || 'Error',
// type: 'error',
// duration: 5 * 1000
// })
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// // to re-login
// MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
// confirmButtonText: 'Re-Login',
// cancelButtonText: 'Cancel',
// type: 'warning'
// }).then(() => {
// store.dispatch('user/resetToken').then(() => {
// location.reload()
// })
// })
// }
// NProgress.done()
// return Promise.reject(new Error(res.message || 'Error'))
// } else {
// NProgress.done()
// if (res.code === '-1') {
// return res
// } else {
// return res.data
// }
// }
},
(error) => {
// loading.close()
console.log('err' + error); // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
});
return Promise.reject(error);
}
);
export default service;

46
src/components/graphContainer/graph/snapshot.js

@ -0,0 +1,46 @@
import request from './request'
// 创建快照
export function createSnapShot(data) {
return request({
url: '/anlysis/createGraphSnapshot',
method: 'post',
data
})
}
// 删除快照
export function delSnapshot(data) {
return request({
url: '/anlysis/delGraphSnapshot',
method: 'post',
data
})
}
// 查询快照数据
export function findSnapShot(data) {
return request({
url: '/anlysis/findGraphSnapshot',
method: 'post',
data
})
}
// 恢复快照数据到d3data
export function recoverSnapshot(data) {
return request({
url: '/anlysis/recoverSnapshot',
method: 'post',
data
})
}
// 快照数据对比
export function recoverSnapshotData(data) {
return request({
url: '/anlysis/snapshotComparison',
method: 'post',
data
})
}

BIN
src/components/graphContainer/images/empty-graph.png

After

Width: 742  |  Height: 378  |  Size: 52 KiB

2
src/components/graphContainer/images/graphSearch.svg

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1652778936406" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4027" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M469.3504 85.3504c211.968 0 384 172.032 384 384 0 211.968-172.032 384-384 384-211.968 0-384-172.032-384-384 0-211.968 172.032-384 384-384z m0 682.6496A298.5984 298.5984 0 0 0 768 469.3504a298.5984 298.5984 0 0 0-298.6496-298.7008 298.5472 298.5472 0 0 0-298.7008 298.7008A298.5984 298.5984 0 0 0 469.3504 768z m361.984 3.072l120.7296 120.6272-60.416 60.3648-120.6272-120.6784 60.3648-60.3648z" fill="#909399" p-id="4028"></path></svg>

344
src/components/graphContainer/search.vue

@ -0,0 +1,344 @@
<template>
<div class="menu-search">
<w-autocomplete
v-model="keyword"
v-scrollLoad="loadMore"
clearable
popper-class="graph-autocomplete"
:fetch-suggestions="querySearch"
placeholder="请输入"
:trigger-on-focus="false"
:popper-append-to-body="false"
@select="queryChange"
>
<!-- <i slot="prefix" class="iconfont icon-sousuo" /> -->
<template slot-scope="{ item }">
<div class="name" v-html="highlightKeyword(item.name, keyword)" />
<w-tag v-show="item.concept" size="mini">{{ item.concept }}</w-tag>
<div v-show="item.contentKey" class="content">{{ item.contentKey }}:{{ item.contentVal }}</div>
</template>
</w-autocomplete>
<img class="iconfont" src="./images/graphSearch.svg" @click="showSearch" />
</div>
</template>
<script>
import { EventBus } from './eventBus';
import { searchEntityByKeyword, graphCentraNodeSave } from './graph/graph';
import { globalV } from './graph/globalData';
import { _debounce } from './graph/publicFunction';
export default {
data() {
return {
searchShow: false,
keyword: '',
graph: {},
pageNum: 1,
callbackFun: ''
};
},
mounted() {
EventBus.$off('Graph');
EventBus.$on('Graph', (object) => {
this.graph = object;
});
},
beforeDestroy() {
EventBus.$off('Graph');
},
directives: {
scrollLoad: {
bind(el, binding, vnode) {
let wrapDom = el.querySelector('.w-autocomplete-suggestion__wrap');
let listDom = el.querySelector('.w-autocomplete-suggestion__wrap .w-autocomplete-suggestion__list');
wrapDom.addEventListener(
'scroll',
_debounce((e) => {
let condition = wrapDom.offsetHeight + wrapDom.scrollTop + 20 - listDom.offsetHeight;
if (condition > 0 && !vnode.context.loading) {
binding.value();
}
}, false),
500
);
}
}
},
methods: {
loadMore() {
this.pageNum = this.pageNum + 1;
this.querySearch();
},
highlightKeyword(name, keyword) {
if (!keyword) return name;
const result = name.replace(new RegExp(keyword, 'g'), `<span class="primary_title">${keyword}</span>`);
return result;
},
showSearch() {
this.searchShow = !this.searchShow;
this.keyword = '';
if (!this.searchShow) {
document.querySelector('.menu-search .w-autocomplete .w-input .w-input__inner').style.width = '0';
} else {
document.querySelector('.menu-search .w-autocomplete .w-input .w-input__inner').style.width = '170px';
}
},
querySearch(queryString, cb) {
if (cb) {
this.callbackFun = cb;
}
const results = [];
const params = {
max: this.pageNum * 10,
keyword: this.keyword,
domain: this.$route.query.domain,
pageNum: 1
};
searchEntityByKeyword(params).then((res) => {
(res || []).forEach((item) => {
const obj = {
name: item.name,
id: item.id
};
if (item.description) {
obj.contentKey = '描述';
obj.contentVal = item.description;
} else if (item.property.length) {
const name = item.property[0].name;
const valueKey = 'value_' + item.property[0].data_type.toLowerCase();
if (name && item.property[0][valueKey]) {
obj.contentKey = name;
obj.contentVal = item.property[0][valueKey].join();
} else {
obj.contentKey = '';
obj.contentVal = '';
}
} else {
obj.contentKey = '';
obj.contentVal = '';
}
if (JSON.stringify(item.concepts_) !== '{}') {
const tempConcept = Object.values(item.concepts_);
obj.concept = tempConcept[0];
}
results.push(obj);
});
this.callbackFun(results);
});
},
queryChange(item) {
let nodeisExist = false;
if (typeof globalV.basicData === 'object') {
globalV.basicData.nodes.forEach((ele) => {
if (ele.id === item.id) {
this.$message({
message: `${item.name}】在当前图谱已存在!`,
type: 'warning'
});
nodeisExist = true;
this.graph.setItemState(item.id, 'focus', true);
return;
}
});
if (!nodeisExist) {
const params = {
graphId: this.$route.query.graphId,
entityId: item.id
};
graphCentraNodeSave(params).then((res) => {
this.$nextTick(() => {
// EventBus.$emit('RefreshGraph')
EventBus.$emit('subGraph', res);
});
});
}
}
}
}
};
</script>
<style lang="less" scoped>
.menu-search {
position: relative;
display: inline-block;
// background: #fff;
margin: 4px 8px 4px 0;
vertical-align: middle;
.iconfont {
width: 20px;
height: 20px;
position: absolute;
top: 6px;
right: 0;
cursor: pointer;
}
::v-deep .w-input__inner {
padding: 0;
background-color: transparent;
border: none;
border-bottom: 1px solid #fff;
height: 34px;
border-radius: 0;
width: 200px;
font-size: 14px;
color: #8a909a;
}
::v-deep .w-input__prefix {
left: 16px;
.w-input__icon {
width: 16px;
// line-height: 40px;
position: absolute;
top: 0;
right: 5px;
}
.w-icon-search:before {
font-size: 16px;
}
}
::v-deep .w-input__suffix {
top: -1px;
right: 25px;
.w-input__icon {
width: 16px;
line-height: 34px;
}
.w-icon-circle-close:before {
font-size: 16px;
font-family: 'iconfont';
content: '\e6f3';
color: rgba(152, 167, 185, 0.5);
}
}
/* - Chrome 56,
- Safari 5-10.0
- iOS Safari 4.2-10.2
- Opera 15-43
- Opera Mobile >12
- Android Browser 2.1-4.4.4
- Samsung Internet
- UC Browser for Android
- QQ Browser */
::-webkit-input-placeholder {
color: #98a7b9;
font-weight: 400;
}
/* Firefox 4-18 */
:-moz-placeholder {
color: #98a7b9;
font-weight: 400;
}
/* Firefox 19-50 */
::-moz-placeholder {
color: #98a7b9;
font-weight: 400;
}
/* - Internet Explorer 1011
- Internet Explorer Mobile 10-11 */
:-ms-input-placeholder {
color: #98a7b9 !important;
font-weight: 400 !important;
}
/* Edge (also supports ::-webkit-input-placeholder) */
::-ms-input-placeholder {
color: #98a7b9;
font-weight: 400;
}
/* CSS Working Draft */
::placeholder {
color: #98a7b9;
font-weight: 400;
}
.w-autocomplete {
display: flex;
align-items: center;
}
}
</style>
<style lang="less">
.menu-search {
.w-autocomplete {
.w-input {
.w-input__inner {
width: 0;
transition: 1s width ease-out;
border-bottom: 1px solid #8a909a;
}
}
}
.graph-autocomplete {
background: #fff;
border: none;
width: 170px !important;
border-radius: 2px;
top: 26px !important;
left: 0 !important;
li {
padding: 6px 20px;
line-height: 1;
.name,
.content {
color: #ffffff;
line-height: 1.6;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.name {
color: #0081ff;
display: inline-block;
vertical-align: middle;
max-width: 58%;
margin-right: 6px;
.primary_title {
color: #0081ff;
}
}
.content {
font-size: 12px;
}
.w-tag {
background: rgba(0, 129, 255, 0.1);
border-radius: 2px;
border: 1px solid rgba(0, 129, 255, 0.2);
max-width: 36%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
color: #0081ff;
}
&.highlighted,
&:hover {
background: rgba(26, 34, 50, 0.5);
.primary_title {
color: #f00;
}
}
}
.popper__arrow {
display: none;
}
.w-autocomplete-suggestion__wrap {
padding: 0;
}
.w-scrollbar__bar.is-vertical {
width: 4px;
}
.w-scrollbar__thumb {
background: rgba(0, 0, 0, 0.1);
&:hover {
background: #1a2232;
}
}
}
}
</style>

54
src/components/graphContainer/store/menu.js

@ -0,0 +1,54 @@
const getDefaultState = () => {
return {
zoom: '',
graph: null,
focusNodesArr: [],
graphId: null,
extendData: {nodes: [], edges: []}
}
}
const state = getDefaultState()
const mutations = {
SET_ZOOM: (state, zoom) => {
state.zoom = zoom
},
SET_GRAPH: (state, graph) => {
state.graph = graph
},
SET_FOCUSNODESARR: (state, focusNodesArr) => {
state.focusNodesArr = focusNodesArr
},
SET_GRAPHID: (state, graphId) => {
state.graphId = graphId
},
SET_EXTENDDATA: (state, extendData) => {
state.extendData = extendData
}
}
const actions = {
SET_ZOOM_ACTIONS(context, payload) {
context.commit('SET_ZOOM', payload)
},
SET_GRAPH_ACTIONS(context, payload) {
context.commit('SET_GRAPH', payload)
},
SET_FOCUSNODESARR_ACTIONS(context, payload) {
context.commit('SET_FOCUSNODESARR', payload)
},
SET_GRAPHID_ACTIONS(context, payload) {
context.commit('SET_GRAPHID', payload)
},
SET_EXTENDDATA_ACTIONS(context, payload) {
context.commit('SET_EXTENDDATA', payload)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}

383
src/components/graphContainer/styles/g6-contextmenu.less

@ -0,0 +1,383 @@
.graph-layout {
.g6-component-contextmenu {
position: absolute;
z-index: 2;
list-style-type: none;
background-color: gray;
box-shadow: none;
border-radius: 6px;
font-size: 14px;
color: hsla(0, 0%, 100%, 0.85);
width: fit-content;
transition: opacity 0.2s;
text-align: center;
border: 0px;
ul {
padding-left: 0px;
margin: 0;
li {
cursor: pointer;
list-style-type: none;
list-style: none;
margin-left: 0;
line-height: 38px;
&:hover {
color: #aaaaaa;
}
}
}
// 菜单第一圈
.menu-layout {
width: 180px;
height: 180px;
position: absolute;
left: -90px;
top: -90px;
clip-path: circle(50%);
-webkit-clip-path: circle(50%);
z-index: 999;
&::before {
content: '';
width: 100%;
height: 100%;
position: absolute;
z-index: -1;
right: 0;
background: linear-gradient(180deg, rgba(30, 36, 43, 0.68) 0%, rgba(90, 109, 137, 0.27) 100%);
box-shadow: inset -2px -2px 10px 0px rgba(255, 255, 255, 0.1);
border-image: linear-gradient(137deg, rgba(255, 255, 255, 0.28), rgba(253, 255, 232, 0.26), rgba(255, 255, 255, 0)) 2 2;
backdrop-filter: blur(15px);
}
// 菜单中心的节点样式
.node-default {
position: absolute;
border-radius: 50%;
z-index: 99;
border: 15px solid #232C3F;
box-sizing: content-box;
background: #6093FF;
.node-in {
width: 100%;
height: 100%;
background: #2B384E;
border-radius: 50%;
}
}
.node {
position: absolute;
border-radius: 50%;
z-index: 99;
border: 15px solid #232C3F;
box-sizing: content-box;
.node-in {
width: 100%;
height: 100%;
background: #2B384E;
border-radius: 50%;
overflow: hidden;
img {
width: 70%;
height: 70%;
display: block;
transform: translate(-50%, -50%);
margin-top: 50%;
margin-left: 50%;
}
}
}
.item-list {
width: 100%;
height: 100%;
clip-path: circle(50%);
-webkit-clip-path: circle(50%);
cursor: pointer;
.item {
width: 50%;
height: 50%;
position: absolute;
transform-origin: 100% 100%;
left: 0px;
top: 0;
&.item-1 {
transform: rotate(60deg) skew(30deg);
}
&.item-2 {
transform: rotate(120deg) skew(30deg);
}
&.item-3 {
transform: rotate(180deg) skew(30deg);
}
&.item-4 {
transform: rotate(240deg) skew(30deg);
}
&.item-5 {
transform: rotate(300deg) skew(30deg);
}
&.item-6 {
transform: rotate(0deg) skew(30deg);
}
&:hover {
background: linear-gradient(117deg, #1357FF 0%, #4E93FF 100%);
opacity: 0.89;
}
}
.item-text {
position: absolute;
font-size: 14px;
color: #000;
transform: scale(0.8);
pointer-events: none;
&.disabled {
color: rgba(255, 255, 255, .3);
}
.iconfont {
display: block;
}
&.item-text-1 {
left: 35%;
top: 6%;
}
&.item-text-2 {
left: 72%;
top: 22%;
}
&.item-text-3 {
left: 64%;
top: 55%;
}
&.item-text-4 {
left: 42%;
top: 73%;
}
&.item-text-5 {
left: 14%;
top: 56%;
}
&.item-text-6 {
left: 5%;
top: 22%;
}
}
}
}
// 不可点击的选项
.text-disabled {
color: rgba(0,0,0,.5) !important;
cursor: not-allowed;
}
// 菜单第二圈
#second-menu-wrapper, #second-menu-wrapper-1, #second-menu-wrapper-2, #second-menu-wrapper-3 {
width: 300px;
height: 300px;
position: absolute;
left: -150px;
top: -150px;
opacity: 1;
clip-path: circle(50%);
-webkit-clip-path: circle(50%);
display: none;
.sector {
position: absolute;
top: 50%;
left: 50%;
overflow: hidden;
margin-top: -150px;
margin-left: -150px;
width: 150px;
height: 150px;
transform: rotate(105deg);
transform-origin: 100% 100%;
background: linear-gradient(180deg, rgba(176, 196, 222, 0.68) 0%, rgba(176, 196, 222, 0.27) 100%);
backdrop-filter: blur(15px);
}
.text {
color: #000;
font-size: 14px;
position: absolute;
width: 30px;
transform: scale(0.8);
cursor: pointer;
pointer-events: none;
}
.text-1 {
right: 25%;
top: 9%
}
.text-2 {
right: 11%;
top: 24%;
}
.text-3 {
right: 5%;
top: 44%;
}
.arc {
position: absolute;
top: 50%;
left: 50%;
overflow: hidden;
margin-top: -150px;
margin-left: -150px;
width: 150px;
height: 150px;
transform: rotate(137deg) skew(60deg);
transform-origin: 100% 100%;
cursor: pointer;
background: transparent;
&.active {
background: linear-gradient(117deg, #1357FF 0%, #4E93FF 100%);
backdrop-filter: none;
}
&:hover {
background: linear-gradient(117deg, #1357FF 0%, #4E93FF 100%);
backdrop-filter: none;
}
}
.arc-1 {
transform: rotate(104.8deg) skew(60deg);
}
.arc-2 {
transform: rotate(134.8deg) skew(60deg);
}
.arc-3 {
transform: rotate(164.8deg) skew(60deg);
}
}
#second-menu-wrapper-1 {
.arc-4 {
transform: rotate(255deg) skew(60deg);
background: linear-gradient(180deg, rgba(70, 130, 180, 0.68) 0%, rgba(70, 130, 180, 0.27) 100%);
backdrop-filter: blur(15px);
}
.text-4 {
width: auto;
right: 40%;
bottom: 8%;
}
}
#second-menu-wrapper-2 {
.sector {
transform: rotate(60deg) skew(30deg);
}
.arc-5 {
transform: rotate(60deg) skew(60deg);
}
.arc-6 {
transform: rotate(90deg) skew(60deg);
}
.text-5 {
top: 6%;
right: 55%;
}
.text-6 {
top: 6%;
right: 30%;
width: 18%;
}
}
#second-menu-wrapper-3 {
.sector {
transform: rotate(-60deg) skew(30deg);
}
.arc-7 {
transform: rotate(-30deg) skew(60deg);
}
.arc-8 {
transform: rotate(-60deg) skew(60deg);
}
.text-7 {
bottom: 37%;
left: 7%;
}
.text-8 {
bottom: 19%;
left: 16%;
}
}
#second-menu-mask-wrapper, #second-menu-mask-wrapper-1, #second-menu-mask-wrapper-2, #second-menu-mask-wrapper-3 {
width: 180px;
height: 180px;
position: absolute;
left: -90px;
top: -90px;
opacity: 1;
clip-path: circle(50%);
-webkit-clip-path: circle(50%);
display: none;
.arc-mask {
position: absolute;
top: 50%;
left: 50%;
overflow: hidden;
margin-top: -150px;
margin-left: -150px;
width: 150px;
height: 150px;
font-size: 1.5em;
transform-origin: 100% 100%;
background: rgba(30, 36, 43, 0.9);
}
.arc-mask-1 {
transform: rotate(104deg) skew(60deg);
}
.arc-mask-2 {
transform: rotate(135deg) skew(60deg);
}
.arc-mask-3 {
transform: rotate(165deg) skew(60deg);
}
.arc-mask-4 {
transform: rotate(255deg) skew(60deg);
}
.arc-mask-5 {
transform: rotate(60deg) skew(60deg);
}
.arc-mask-6 {
transform: rotate(90deg) skew(60deg);
}
.arc-mask-7 {
transform: rotate(-30deg) skew(60deg);
}
.arc-mask-8 {
transform: rotate(-60deg) skew(60deg);
}
}
}
#minimap {
width: 200px;
height: 150px;
position: absolute;
right: 0;
bottom: 0;
border-radius: 8px;
border: 1px solid rgba(0, 129, 255, 0.5);
background-color: #222D3D;
.icon-guanbi {
font-size: 16px;
color: #5F6A7A;
position: absolute;
right: 6px;
top: 6px;
z-index: 1;
cursor: pointer;
}
.rect {
width: 25px;
height: 25px;
position: absolute;
left: 0;
top: 0;
cursor: pointer;
background: #FFFFFF;
z-index: 1;
img {
display: block;
width: 100%;
height: 100%;
pointer-events: none;
}
}
}
}

35
src/layout/components/domain.vue

@ -4,6 +4,13 @@
-->
<template>
<div class="domain-wrapper">
<w-dropdown placement='bottom' @command="handleFontSize">
<i class="svg-icon"><CoolFontSizeTwo size="18" color="#fff"/></i>
<w-dropdown-menu slot="dropdown" :visible-arrow='true'>
<w-dropdown-item command="default" :disabled="fontSizeType === 'default'">默认</w-dropdown-item>
<w-dropdown-item command="large" :disabled="fontSizeType === 'large'">大型</w-dropdown-item>
</w-dropdown-menu>
</w-dropdown>
<w-tooltip content="主题设置" placement="top" :enterable="false">
<svg-icon v-if="showSettings" name="settings" @click="handleSetting"></svg-icon>
</w-tooltip>
@ -12,16 +19,21 @@
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'DoMain',
computed: {
...mapGetters(['fontSizeType']),
showSettings() {
return this.$store.getters.settings.showSettings;
}
},
},
methods: {
handleSetting() {
this.$store.dispatch('app/toggleVisible', true);
},
handleFontSize(comment){
this.$store.dispatch('app/toggleFontSizeType', comment);
}
}
};
@ -35,13 +47,16 @@ export default {
color: @layoutHeaderColor;
.svg-icon {
height: 56px;
display: inline-block;
line-height: 56px;
font-size: 18px;
cursor: pointer;
margin-right: 16px;
margin: 0 8px;
&:hover {
color: @themeColor;
}
// &:hover {
// color: @themeColor;
// }
}
}
@ -50,10 +65,14 @@ export default {
.svg-icon {
color: @layoutColor;
&:hover {
color: @themeColor;
}
// &:hover {
// color: @themeColor;
// }
}
}
}
.w-avatar{
margin-left: 10px;
}
</style>

27
src/layout/index.vue

@ -26,6 +26,25 @@ export default {
openSidebar: this.sidebar.opened
};
}
},
methods: {
watchRoute() {
if (this.$route.path.includes('peoplePool')) {
document.getElementsByClassName('w-main')[0].classList.add('peoplePool-w-main');
document.getElementsByClassName('w-container')[0].classList.add('peoplePool-w-container');
} else {
document.getElementsByClassName('w-main')[0].classList.remove('peoplePool-w-main');
document.getElementsByClassName('w-container')[0].classList.remove('peoplePool-w-container');
}
}
},
mounted() {
this.watchRoute();
},
watch: {
'$route.path'() {
this.watchRoute();
}
}
};
</script>
@ -38,3 +57,11 @@ export default {
.clearfix();
}
</style>
<style lang="less">
.peoplePool-w-main {
padding: 0 !important;
}
.peoplePool-w-container {
overflow: hidden;
}
</style>

1
src/layout/layout/appMain.vue

@ -11,7 +11,6 @@ export default {
name: 'AppMain',
computed: {
key() {
console.log(this.$route.path);
return this.$route.path;
}
}

2
src/layout/layout/horizontal.vue

@ -11,7 +11,7 @@
</div>
<do-main />
</w-header>
<w-main id="fatherScroll">
<w-main>
<app-main />
</w-main>
</w-container>

2
src/layout/layout/vertical.vue

@ -15,7 +15,7 @@
<hamburger />
<do-main />
</w-header>
<w-main id="fatherScroll">
<w-main>
<app-main />
</w-main>
</w-container>

10
src/main.js

@ -6,12 +6,20 @@ import store from './store';
import router from './router';
import './plugins';
import * as echarts from 'echarts';
import * as CoolBoxIcons from '@coolbox/we-design';
import * as CoolBoxIcons from '@coolbox/we-design/dist/vue2/es.js';
import '@coolbox/we-design/style/index.css';
if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock')
mockXHR()
}
// 需要挂载到Vue原型上
Vue.prototype.$echarts = echarts;
Vue.config.productionTip = false;
Vue.use(WinboxUI);
for (const [key, component] of Object.entries(CoolBoxIcons)) {
Vue.component(key, component);

45
src/router/index.js

@ -16,6 +16,11 @@ export const constantRoutes = [
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/peoplePoolDeatil/:id',
name: 'peoplePoolDeatil',
component: () => import('@/views/peoplePool/detail')
}
];
@ -35,28 +40,29 @@ export const asyncRoutes = [
{
path: '/peoplePool',
component: Layout,
meta: { title: '列表', icon: 'icon-mn_gongneng', hoverIcon: 'icon-gongnengguanli' },
meta: { title: '专题列表', icon: 'icon-mn_gongneng', hoverIcon: 'icon-gongnengguanli' },
children: [
{
path: 'index',
name: 'index',
component: () => import('@/views/peoplePool/index'),
meta: { title: '列表' }
meta: { title: '专题列表' }
}
]
},
{
path: '/icon',
component: Layout,
meta: { title: '图标', icon: 'icon-mn_gongneng', hoverIcon: 'icon-gongnengguanli' },
children: [
{
path: 'index',
name: 'index',
component: () => import('@/views/icons/index'),
meta: { title: '图标' }
}
]
},
// {
// path: '/detail',
// component: Layout,
// // redirect: '/peoplePoolDetail',
// children: [
// {
// path: 'detail',
// component: () => import('@/views/detail')
// // meta: { title: '首页', icon: 'icon-home' }
// }
// ]
// },
{
path: '/demo',
component: Layout,
@ -121,11 +127,12 @@ export const asyncRoutes = [
}
];
const createRouter = () => new Router({
mode: 'hash', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes.concat(asyncRoutes)
});
const createRouter = () =>
new Router({
mode: 'hash', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes.concat(asyncRoutes)
});
const router = createRouter();

3
src/settings.js

@ -5,6 +5,9 @@ module.exports = {
*/
showSettings: true,
fontSizeType: 'default',
/**
* @type {boolean} true | false
* @description Whether fix the header

1
src/store/getters.js

@ -5,6 +5,7 @@ const getters = {
theme: state => state.app.theme,
themeColor: state => state.app.themeColor,
settingDrawer: state => state.app.settingDrawer,
fontSizeType: state => state.app.fontSizeType,
// settings
settings: state => state.settings.settings,
// user

12
src/store/modules/app.js

@ -8,7 +8,8 @@ const state = {
},
layoutMode: localStorage.getItem('layoutMode') || 'horizontal', // 当前布局
theme: localStorage.getItem('theme') || 'default', // 当前主题
settingDrawer: false // 主题抽屉显隐
settingDrawer: false, // 主题抽屉显隐
fontSizeType: localStorage.getItem('fontSizeType') || 'default',
};
const mutations = {
@ -32,6 +33,12 @@ const mutations = {
},
TOGGLE_VISIBLE: (state, visible) => {
state.settingDrawer = visible;
},
TOGGLE_FONTSIZETYPE: (state, visible) => {
localStorage.setItem('fontSizeType', visible);
state.fontSizeType = visible;
common.toggleFontSizeType(document.body, visible);
}
};
@ -47,6 +54,9 @@ const actions = {
},
toggleVisible({ commit }, visible) {
commit('TOGGLE_VISIBLE', visible);
},
toggleFontSizeType({ commit }, visible) {
commit('TOGGLE_FONTSIZETYPE', visible);
}
};

103
src/store/modules/graphAside.js

@ -0,0 +1,103 @@
// import { conceptAnalytic, entityInfo, entity_relation_byrids } from '@/api/graph';
// import { EventBus } from '@/components/graphContainer/eventBus.js';
const getDefaultState = () => {
return {
toggleShowState: true,
graphData: {}, // 真实名称
graphIds: [], // 真实姓名id
conceptName: [], // 概念名称
showNode: null, // 展示节点/ 边
nodeDetail: {}, // 节点详情
relationShip: {} // 关系详情
};
};
const state = getDefaultState();
const mutations = {
SET_SHOW_STATE: (state, payload) => {
state.toggleShowState = payload;
},
// 真实名称
SET_GRAPH_DATA: (state, payload) => {
// state.graphIds = payload.graphIds
state.graphData = payload;
},
// 概念名称 - 对应名称
SET_CONCEPT_ANALYTIC: (state, payload) => {
state.conceptName = payload;
},
// 节点详情
SET_NODE_DETAIL: (state, payload) => {
state.showNode = true;
state.nodeDetail = payload;
},
// 关系详情
SET_RELATION_SHIP: (state, payload) => {
state.showNode = false;
state.relationShip = payload;
},
// 单独修改showNode
SET_SHOW_NODE: (state, payload) => {
state.showNode = payload;
},
RESET_STATE: (state) => {
// Object.assign(state, getDefaultState())
state.graphData = { nodes: [], edges: [], ccount: [], concepts: {}, relationInstance: null, rids: null };
}
};
const actions = {
conceptAnalyticAction(context, payload) {
context.commit('SET_GRAPH_DATA', payload);
},
SET_GRAPH_DATA_ACTIONS(context, payload) {
// 初始化name ,然后提交
console.log('SET_GRAPH_DATA_ACTIONS:', payload);
// conceptAnalytic(payload).then((res) => {
// const arr = (res || []).map((item) => {
// // 返回来的无法序列化,使用循环处理
// return item;
// });
// context.commit('SET_CONCEPT_ANALYTIC', arr);
// });
},
// 单个节点详情
NODE_DETAIL_ACTIONS(context, payload) {
// 初始化name ,
const eid = payload.split('&eid=')[1];
if (eid && context.state.nodeDetail.entity) {
if (eid === context.state.nodeDetail.entity.id) {
context.state.showNode = true;
return;
}
}
console.log(('单个节点详情:', payload));
// entityInfo(payload).then((res) => {
// context.commit('SET_NODE_DETAIL', res);
// });
},
// 单个边详情
EDGE_DETAIL_ACTIONS(context, payload) {
// 初始化name
const rids = payload.split('rids=')[1];
if (rids && context.state.relationShip) {
if (Number(rids) === context.state.relationShip.id) {
context.state.showNode = false;
return;
}
}
console.log('单个边详情:', payload);
// entity_relation_byrids(payload).then((res) => {
// EventBus.$emit('relationDyData', res && res[0] ? res[0] : '');
// context.commit('SET_RELATION_SHIP', res && res[0] ? res[0] : '');
// });
}
};
export default {
namespaced: true,
state,
mutations,
actions
};

54
src/store/modules/graphMenu.js

@ -0,0 +1,54 @@
const getDefaultState = () => {
return {
zoom: '',
graph: null,
focusNodesArr: [],
graphId: null,
extendData: { nodes: [], edges: [] }
};
};
const state = getDefaultState();
const mutations = {
SET_ZOOM: (state, zoom) => {
state.zoom = zoom;
},
SET_GRAPH: (state, graph) => {
state.graph = graph;
},
SET_FOCUSNODESARR: (state, focusNodesArr) => {
state.focusNodesArr = focusNodesArr;
},
SET_GRAPHID: (state, graphId) => {
state.graphId = graphId;
},
SET_EXTENDDATA: (state, extendData) => {
state.extendData = extendData;
}
};
const actions = {
SET_ZOOM_ACTIONS(context, payload) {
context.commit('SET_ZOOM', payload);
},
SET_GRAPH_ACTIONS(context, payload) {
context.commit('SET_GRAPH', payload);
},
SET_FOCUSNODESARR_ACTIONS(context, payload) {
context.commit('SET_FOCUSNODESARR', payload);
},
SET_GRAPHID_ACTIONS(context, payload) {
context.commit('SET_GRAPHID', payload);
},
SET_EXTENDDATA_ACTIONS(context, payload) {
context.commit('SET_EXTENDDATA', payload);
}
};
export default {
namespaced: true,
state,
mutations,
actions
};

2
src/store/modules/settings.js

@ -2,6 +2,7 @@ import defaultSettings from '@/settings';
const {
showSettings,
fontSizeType,
fixedHeader,
sidebarLogo,
title,
@ -11,6 +12,7 @@ const {
const state = {
settings: {
showSettings: showSettings,
fontSizeType: fontSizeType,
fixedHeader: fixedHeader,
sidebarLogo: sidebarLogo,
title: title,

1
src/styles/global.less

@ -9,6 +9,7 @@ body {
font-size: 14px;
font-weight: 400;
font-family: Arial, '微软雅黑', 'Microsoft YaHei';
background: #eff2f5;
}
label {

16
src/styles/variable.less

@ -1,6 +1,22 @@
/* Subject variable
-------------------------- */
@primary-text-color: #303133;
@regular-text-color: #606266;
@secondary-text-color: #303133;
@placeholder-text-color: #606266;
// 禁用颜色
@disabled-font-color: #97a3b9;
@disabled-background-color: #171d3f;
@disabled-border-color: #727f95;
@disabled-placeholder-color: #97a3b9;
@themeColor: var(--themeColor);
@themeTransparent: var(--themeTransparent);

2
src/styles/winbox-ui/css/black.css
File diff suppressed because it is too large
View File

2
src/styles/winbox-ui/css/blue.css
File diff suppressed because it is too large
View File

2
src/styles/winbox-ui/css/cyan.css
File diff suppressed because it is too large
View File

2
src/styles/winbox-ui/css/default.css
File diff suppressed because it is too large
View File

BIN
src/styles/winbox-ui/css/iconfont.ttf

BIN
src/styles/winbox-ui/css/iconfont.woff

BIN
src/styles/winbox-ui/css/iconfont.woff2

2
src/styles/winbox-ui/css/red.css
File diff suppressed because it is too large
View File

2
src/styles/winbox-ui/css/white.css
File diff suppressed because it is too large
View File

34
src/utils/common.js

@ -13,6 +13,21 @@ const common = {
if (!element || !className) return;
element.className = className;
},
toggleFontSizeType(element, className) {
if (!element || !className) return;
if(className === 'large'){
document.body.style.setProperty('--font-size-medium-bold', '24px');
document.body.style.setProperty('--font-size-medium', '22px');
document.body.style.setProperty('--font-size-default', '19px');
document.body.style.setProperty('--font-size-small', '17px');
}else{
document.body.style.setProperty('--font-size-medium-bold', '20px');
document.body.style.setProperty('--font-size-medium', '18px');
document.body.style.setProperty('--font-size-default', '16px');
document.body.style.setProperty('--font-size-small', '14px');
}
},
/**
* @description: 获取主题对应色值(仅限于variable.less文件)
@ -26,7 +41,26 @@ const common = {
const currentVars = require(`../styles/themes/${currentTheme}.less`);
const filterVar = lessVar.replace(/[(|)]/g, '').replace('var', '');
return currentVars[filterVar];
},
// 时间转换
formatDate (d) {
const date = new Date(d);
const YY = date.getFullYear() + '-';
const MM =
(date.getMonth() + 1 < 10
? '0' + (date.getMonth() + 1)
: date.getMonth() + 1) + '-';
const DD = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
const hh =
(date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
const mm =
(date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) +
':';
const ss =
date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
return YY + MM + DD + ' ' + hh + mm + ss;
}
};
export default common;

1
src/views/demo/form/index.vue

@ -69,6 +69,7 @@ export default {
background: @pageBg;
height: 100%;
padding: 20px;
.demo-form {
width: 480px;

128
src/views/detail/index.vue

@ -1,128 +0,0 @@
<template>
<div class="peoplePool">
<w-row :gutter="16" type="flex">
<w-col :span="3">
<NavLeft></NavLeft>
</w-col>
<w-col :span="21">
<div v-if="isShow" class="con-right">
<BreadCrumb></BreadCrumb>
<Search></Search>
<!-- <ItemGroup></ItemGroup> -->
</div>
<div v-else class="detailGlobal">
<div id="detailContent" class="detailContent">
<BreadCrumb content="人物分析"></BreadCrumb>
<Profile id="content-item0" class="part"></Profile>
<PhotoVideo id="content-item1" class="part"></PhotoVideo>
<News id="content-item2" class="part"></News>
<PeopleDescriptive id="content-item3" class="part"></PeopleDescriptive>
<PeopleLifetime id="content-item4" class="part"></PeopleLifetime>
<SocialAnalysis id="content-item5" class="part"></SocialAnalysis>
<PlatformDynamics id="content-item6" class="part"></PlatformDynamics>
</div>
<div class="tabList">
<w-anchor :offset-top="10" :get-container='getContainer'
@click="handleClick">
<w-anchor-link href="#content-item0" title="基本信息"></w-anchor-link>
<w-anchor-link href="#content-item1" title="图册视频"></w-anchor-link>
<w-anchor-link href="#content-item2" title="新闻资讯"></w-anchor-link>
<w-anchor-link href="#content-item3" title="描述"></w-anchor-link>
<w-anchor-link href="#content-item4" title="人物生平"></w-anchor-link>
<w-anchor-link href="#content-item5" title="社交分析与扩线"></w-anchor-link>
<w-anchor-link href="#content-item6" title="社交平台发文动态"></w-anchor-link>
</w-anchor>
</div>
</div>
</w-col>
</w-row>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
import Search from '@/components/PeoplePoolPage/search';
import NavLeft from '@/components/PeoplePoolPage/nav-left.vue';
import BreadCrumb from '@/components/PeoplePoolPage/breadcrumb.vue';
import ItemGroup from '@/components/PeoplePoolPage/itemGroup.vue';
import Profile from '@/components/PeoplePoolPage/people-profile.vue';
import PhotoVideo from '@/components/PeoplePoolPage/photo-video.vue';
import News from '@/components/PeoplePoolPage/news.vue';
import PeopleDescriptive from '@/components/PeoplePoolPage/people-descriptive.vue';
import PeopleLifetime from '@/components/PeoplePoolPage/people-lifetime.vue';
import SocialAnalysis from '@/components/PeoplePoolPage/social-analysis.vue';
import PlatformDynamics from '@/components/PeoplePoolPage/platform-dynamics.vue';
export default {
name: 'PeoplePool',
components: {
Search,
NavLeft,
BreadCrumb,
ItemGroup,
Profile,
PhotoVideo,
News,
PeopleDescriptive,
PeopleLifetime,
SocialAnalysis,
PlatformDynamics
},
data() {
return {
isShow: true,
list: ['基本信息', '图册视频', '新闻资讯', '描述', '人物生平', '社交分析与扩线', '社交平台发文动态']
};
},
methods: {
getContainer() {
return this.scrollContainer;
},
handleClick(e, link) {
e.preventDefault();
}
},
mounted() {
this.scrollContainer = document.getElementsByClassName('w-main')[0];
bus.$on('detail', val => {
this.isShow = val;
});
}
};
</script>
<style lang='less' scoped>
.peoplePool {
color: @fontColor;
background-color: @mainBg;
.detailGlobal {
display: flex;
.detailContent {
width: 87.5%;
margin-top: 16px;
margin-right: 1%;
// overflow-y: auto;
height: 845px;
padding-right: 5px;
.part {
width: 100%;
border-radius: 4px;
background: #fff;
margin-bottom: 16px;
}
}
.tabList {
width: 10%;
margin-top: 50px;
::v-deep.w-anchor-wrapper {
background-color: transparent !important;
}
}
}
}
</style>

70
src/views/icons/index.vue

@ -0,0 +1,70 @@
<template>
<div class="icons-container">
<w-card>
<w-tabs v-model="activeName" type="card">
<w-tab-pane v-for="item of iconsList" :key="item.name + item.id" :label="item.name" :name="item.name + item.id">
<w-row>
<w-col v-for="o in item.icons" :key="item.id + o.name" :span="3">
<div class="icon-item">
<component :is="`Cool${PascalName(o.name)}`" :size="30"></component>
<span style="font-size: 14px; color: #666">{{ o.name_zh }}</span>
<span style="font-size: 14px">
{{ generateIconCode(o.name) }}
</span>
</div>
</w-col>
</w-row>
</w-tab-pane>
</w-tabs>
</w-card>
</div>
</template>
<script>
import iconsList from '@coolbox/we-design/icons.json';
export default {
name: 'Icons',
data() {
return {
iconsList,
activeName: iconsList[0].name + iconsList[0].id
};
},
methods: {
PascalName(str) {
const strArr = str.split('-');
const reg = /\d/;
for (let i = 0; i < strArr.length; i++) {
if (reg.test(strArr[i].charAt(0))) {
strArr[i] = '_' + strArr[i];
} else {
strArr[i] = strArr[i].charAt(0).toUpperCase() + strArr[i].substring(1);
}
}
return strArr.join('');
},
generateIconCode(symbol) {
return `<Cool${this.PascalName(symbol)} />`;
}
}
};
</script>
<style lang="less" scoped>
.icons-container {
overflow: hidden;
.icon-item {
height: 100px;
text-align: center;
font-size: 30px;
color: #24292e;
}
span {
display: block;
font-size: 16px;
margin-top: 10px;
}
}
</style>

181
src/views/peoplePool/detail.vue

@ -0,0 +1,181 @@
<template>
<div v-loading="loading" style="min-height: 100vh;">
<div v-if="isShow1" class="deatil">
<div style="width: 100%;height: 100%;">
<div class="detailGlobal">
<div id="detailContent" class="detailContent">
<detailCom ref="mySon" :offsettop="0"></detailCom>
</div>
<div class="tabList">
<TracingPoint :size="10"></TracingPoint>
<div>
<w-backtop style="right: initial;">
<div class="goback">
<CoolUploadLine size="16" color="#ffffff" />
<div style="font-size: 14px; color: #ffffff; margin-top: 2px">回顶</div>
</div>
</w-backtop>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import bus from '@/utils/EventBus';
import TracingPoint from '@/components/PeoplePoolPage/tracing-point.vue';
import detailCom from '@/components/PeoplePoolPage/detailCom.vue';
export default {
name: 'Detail',
components: {
TracingPoint,
detailCom
},
data() {
return {
isShow: true,
list: ['人物简介', '图册视频', '新闻资讯', '描述', '人物生平', '社交分析与扩线', '社交平台发文动态'],
screenWidth: '',
loading: true,
isShow1: true
};
},
methods: {
},
watch: {
// screenWidth() {
// if (this.screenWidth < 1480) {
// document.querySelector('.detailGlobal').style.marginRight = '160px';
// document.querySelector('.detailGlobal').style.marginLeft = '160px';
// } else {
// // document.querySelector('.tabList').style.display = 'block';
// document.querySelector('.detailGlobal').style.marginRight = 'calc((100vw - 1200px) / 2)';
// document.querySelector('.detailGlobal').style.marginLeft = 'calc(50vw - 600px)';
// }
// if (this.screenWidth < 1300) {
// document.querySelector('.tabList').style.display = 'none';
// } else {
// document.querySelector('.tabList').style.display = 'block';
// }
// }
},
created() {
// this.getdeatilInfo();
bus.$on('load2', val => {
this.loading = val;
});
this.$refs.mySon.$on('show', this.ShowName);
},
mounted() {
// bus.$on('load2', val => {
// this.loading = val;
// });
this.screenWidth = document.body.clientWidth;
window.onresize = () => {
return (() => {
this.screenWidth = document.body.clientWidth;
})();
};
}
};
</script>
<style lang='less' scoped>
.deatil {
background-color: @mainBg;
width: 100%;
height: 100%;
// position: relative;
.detailGlobal {
position: relative;
height: 100%;
width: 1200px;
margin-left: auto;
margin-right: auto;
padding-bottom: 16px;
// min-width: 1000px;
// margin: 0 calc(50vw - 600px) 0 calc((100vw - 1200px) / 2);
// background-color: red;
.detailContent {
width: 100%;
margin-top: 16px;
margin-right: 1%;
// overflow-y: auto;
padding-right: 5px;
.part {
width: 100%;
border-radius: 4px;
background: #fff;
margin-bottom: 16px;
}
}
}
.tabList {
margin-top: 50px;
margin-left: 50px;
position: absolute;
right: -154px;
top: -49px;
z-index: 1000;
::v-deep.w-anchor-wrapper {
background-color: transparent !important;
}
}
.goback {
text-align: center;
height: 55px;
display: flex;
flex-direction: column;
justify-content: center;
}
::v-deep .w-backtop {
width: 55px;
height: 55px;
background-color: #2055f4;
border-radius: 8px;
}
::v-deep .w-backtop:hover {
background-color: #2055f4;
}
.w-anchor-link {
>a {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
</style>
<style lang="less">
.deatil {
.w-anchor-link-title {
color: #000000;
}
.w-anchor-link {
>a {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
</style>

162
src/views/peoplePool/index.vue

@ -1,43 +1,39 @@
<template>
<div class="peoplePool">
<w-row :gutter="16" type="flex">
<w-col :span="3">
<div class="contentFather">
<div class="contentLeft">
<NavLeft></NavLeft>
</w-col>
<w-col :span="21">
</div>
<div class="contentRight">
<div v-if="isShow" class="con-right">
<BreadCrumb></BreadCrumb>
<Search></Search>
<ItemGroup></ItemGroup>
</div>
<div v-else class="detailGlobal">
<div v-else v-loading="false" class="detailGlobal" style="min-height: 100vh;">
<div id="detailContent" class="detailContent">
<BreadCrumb content="人物分析"></BreadCrumb>
<Profile id="content-item0" class="part"></Profile>
<!-- <BreadCrumb message="人物分析"></BreadCrumb>
<Profile id="content-item0" class="part" style="background: transparent;border-radius: 0px;"></Profile>
<PhotoVideo id="content-item1" class="part"></PhotoVideo>
<News id="content-item2" class="part"></News>
<PeopleDescriptive id="content-item3" class="part"></PeopleDescriptive>
<PeopleLifetime id="content-item4" class="part"></PeopleLifetime>
<SocialAnalysis id="content-item5" class="part"></SocialAnalysis>
<PlatformDynamics id="content-item6" class="part"></PlatformDynamics>
<PlatformDynamics id="content-item6" class="part"></PlatformDynamics> -->
<detailCom :offsettop="56"></detailCom>
</div>
<div class="tabList">
<w-anchor :offset-top="10" :get-container='getContainer'
@click="handleClick">
<w-anchor-link href="#content-item0" title="基本信息"></w-anchor-link>
<w-anchor-link href="#content-item1" title="图册视频"></w-anchor-link>
<w-anchor-link href="#content-item2" title="新闻资讯"></w-anchor-link>
<w-anchor-link href="#content-item3" title="描述"></w-anchor-link>
<w-anchor-link href="#content-item4" title="人物生平"></w-anchor-link>
<w-anchor-link href="#content-item5" title="社交分析与扩线"></w-anchor-link>
<w-anchor-link href="#content-item6" title="社交平台发文动态"></w-anchor-link>
</w-anchor>
<TracingPoint :size="10" :get-container="getContainer"></TracingPoint>
</div>
</div>
</w-col>
</w-row>
</div>
</div>
<w-backtop v-if="isShow === false" target=".contentRight" style="right: 140px">
<div class="goback">
<CoolUploadLine size="16" color="#ffffff" />
<div style="font-size: 14px; color: #ffffff; margin-top: 2px">回顶</div>
</div>
</w-backtop>
</div>
</template>
<script>
@ -46,14 +42,16 @@ import Search from '@/components/PeoplePoolPage/search';
import NavLeft from '@/components/PeoplePoolPage/nav-left.vue';
import BreadCrumb from '@/components/PeoplePoolPage/breadcrumb.vue';
import ItemGroup from '@/components/PeoplePoolPage/itemGroup.vue';
import Profile from '@/components/PeoplePoolPage/people-profile.vue';
import PhotoVideo from '@/components/PeoplePoolPage/photo-video.vue';
import News from '@/components/PeoplePoolPage/news.vue';
import PeopleDescriptive from '@/components/PeoplePoolPage/people-descriptive.vue';
import PeopleLifetime from '@/components/PeoplePoolPage/people-lifetime.vue';
import SocialAnalysis from '@/components/PeoplePoolPage/social-analysis.vue';
import PlatformDynamics from '@/components/PeoplePoolPage/platform-dynamics.vue';
// import DetailCom from '@/components/PeoplePoolPage/detailCom.vue';
// import Profile from '@/components/PeoplePoolPage/people-profile.vue';
// import PhotoVideo from '@/components/PeoplePoolPage/photo-video.vue';
// import News from '@/components/PeoplePoolPage/news.vue';
// import PeopleDescriptive from '@/components/PeoplePoolPage/people-descriptive.vue';
// import PeopleLifetime from '@/components/PeoplePoolPage/people-lifetime.vue';
// import SocialAnalysis from '@/components/PeoplePoolPage/social-analysis.vue';
// import PlatformDynamics from '@/components/PeoplePoolPage/platform-dynamics.vue';
import TracingPoint from '@/components/PeoplePoolPage/tracing-point.vue';
import detailCom from '@/components/PeoplePoolPage/detailCom.vue';
export default {
name: 'PeoplePool',
components: {
@ -61,50 +59,83 @@ export default {
NavLeft,
BreadCrumb,
ItemGroup,
Profile,
PhotoVideo,
News,
PeopleDescriptive,
PeopleLifetime,
SocialAnalysis,
PlatformDynamics
// Profile,
// PhotoVideo,
// News,
// PeopleDescriptive,
// PeopleLifetime,
// SocialAnalysis,
// PlatformDynamics,
TracingPoint,
detailCom
},
data() {
return {
isShow: true,
list: ['基本信息', '图册视频', '新闻资讯', '描述', '人物生平', '社交分析与扩线', '社交平台发文动态']
list: ['人物简介', '图册视频', '新闻资讯', '描述', '人物生平', '社交分析与扩线', '社交平台发文动态'],
loading: true
};
},
methods: {
getContainer() {
return this.scrollContainer;
},
handleClick(e, link) {
e.preventDefault();
}
},
mounted() {
this.scrollContainer = document.getElementsByClassName('w-main')[0];
bus.$on('detail', val => {
this.scrollContainer = document.getElementsByClassName('contentRight')[0];
bus.$on('detail', (val) => {
this.isShow = val;
});
}
bus.$on('load2', (val) => {
this.loading = val;
});
},
beforeDestroy() { }
};
</script>
<style lang='less' scoped>
.peoplePool {
color: @fontColor;
background-color: @mainBg;
.contentFather {
display: flex;
height: calc(100vh - 56px);
.contentLeft {
background: #ffffff;
padding-right: 0px;
padding-top: 16px;
width: 220px;
flex-shrink: 0;
height: 100%;
}
.contentRight {
height: 100%;
overflow: auto;
flex-grow: 1;
padding-left: 20px;
padding-right: 20px;
padding-bottom: 20px;
.con-right {
min-width: 1200px;
}
}
}
.con-right {
padding-top: 16px;
}
.detailGlobal {
display: flex;
min-width: 1200px;
.detailContent {
width: 87.5%;
margin-top: 16px;
margin-right: 1%;
// overflow-y: auto;
margin-right: 24px;
height: 845px;
padding-right: 5px;
@ -119,10 +150,45 @@ export default {
.tabList {
width: 10%;
margin-top: 50px;
::v-deep.w-anchor-wrapper {
background-color: transparent !important;
}
}
}
.goback {
text-align: center;
height: 55px;
display: flex;
flex-direction: column;
justify-content: center;
}
}
::v-deep .w-backtop {
width: 55px;
height: 55px;
background-color: #2055f4;
border-radius: 8px;
}
::v-deep .w-backtop:hover {
background-color: #2055f4;
}
</style>
<style lang="less">
.contentRight {
.w-anchor-link-title {
color: #000000;
}
.w-anchor-link {
>a {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
</style>

3
vue.config.js

@ -24,7 +24,8 @@ module.exports = {
overlay: { // 编译错误或警告时,在浏览器中显示全屏
warnings: false,
errors: true
}
},
before: require('./mock/mock-server.js')
},
configureWebpack: {
name: name,

Loading…
Cancel
Save