1
This commit is contained in:
parent
203fd7c18d
commit
9b09a6b54a
BIN
src/assets/images/groupEvolution/graph-title.png
Normal file
BIN
src/assets/images/groupEvolution/graph-title.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
BIN
src/assets/images/groupEvolution/post-prefix.png
Normal file
BIN
src/assets/images/groupEvolution/post-prefix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -15,6 +15,7 @@
|
||||||
<div class="progress-bar" :style="trackStyle"></div>
|
<div class="progress-bar" :style="trackStyle"></div>
|
||||||
<div class="active-sign">
|
<div class="active-sign">
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
|
v-if="cursor"
|
||||||
:content="TansTimestamp(cursor, 'YYYY.MM.DD HH:mm:ss')"
|
:content="TansTimestamp(cursor, 'YYYY.MM.DD HH:mm:ss')"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
effect="light"
|
effect="light"
|
||||||
|
|
@ -30,7 +31,7 @@
|
||||||
<div
|
<div
|
||||||
class="timeLine-point"
|
class="timeLine-point"
|
||||||
@pointerdown.stop="handlePointPointerDown"
|
@pointerdown.stop="handlePointPointerDown"
|
||||||
:style="{ left: `${currentPosition}px` }"
|
:style="{ left: `${currentPosition - 9}px` }"
|
||||||
></div>
|
></div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -66,7 +67,7 @@ const props = defineProps({
|
||||||
cursor: {
|
cursor: {
|
||||||
//初始时,游标标出指定的时间
|
//初始时,游标标出指定的时间
|
||||||
type: Date,
|
type: Date,
|
||||||
default: new Date("2024-05-23 10:16:56")
|
default: null
|
||||||
},
|
},
|
||||||
isAutoPlay: {
|
isAutoPlay: {
|
||||||
//创建组件后,是否自动播放
|
//创建组件后,是否自动播放
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,13 @@ export function getGroupEvolutionGroupList(time) {
|
||||||
export function getGroupEvolutionGroupScaleChart() {
|
export function getGroupEvolutionGroupScaleChart() {
|
||||||
return http.get(`/groupEvolution/identify/group_scale`)
|
return http.get(`/groupEvolution/identify/group_scale`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//群体识别发现页面时间轴
|
||||||
|
export function getGroupEvolutionTimeLine() {
|
||||||
|
return http.get(`/groupEvolution/identify/timeline`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//群体识别发现页面贴文列表
|
||||||
|
export function getPostByUtcTime(utcTime) {
|
||||||
|
return http.get(`/groupEvolution/identify/posts?date=${utcTime}`)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,17 @@ import defaultAvatar from "@/assets/images/avatar/default.png"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getGroupEvolutionGroupList,
|
getGroupEvolutionGroupList,
|
||||||
getGroupEvolutionGroupScaleChart
|
getGroupEvolutionGroupScaleChart,
|
||||||
|
getGroupEvolutionTimeLine,
|
||||||
|
getPostByUtcTime
|
||||||
} from "@/service/api/groupEvolution"
|
} from "@/service/api/groupEvolution"
|
||||||
import { TansTimestamp } from "@/utils/transform"
|
import { TansTimestamp } from "@/utils/transform"
|
||||||
|
|
||||||
export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
groupList: [],
|
groupList: [],
|
||||||
chartData: {},
|
chartData: {},
|
||||||
|
timeList: [],
|
||||||
chartsData: {
|
chartsData: {
|
||||||
topSelfMedia: {
|
topSelfMedia: {
|
||||||
xAxis: [
|
xAxis: [
|
||||||
|
|
@ -133,122 +137,7 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
||||||
{ text: "原则", top: 77.5, left: 264.5, width: 49, height: 19, fontSize: 12, opacity: 0.7 },
|
{ text: "原则", top: 77.5, left: 264.5, width: 49, height: 19, fontSize: 12, opacity: 0.7 },
|
||||||
{ text: "台湾", top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
|
{ text: "台湾", top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
|
||||||
],
|
],
|
||||||
posts: [
|
posts: []
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
timestamp: "2024-01-04 0:03:16",
|
|
||||||
author: "十八子91221",
|
|
||||||
influence: 2,
|
|
||||||
highlighted: false,
|
|
||||||
like: 1,
|
|
||||||
comment: 1,
|
|
||||||
transmit: 0,
|
|
||||||
content:
|
|
||||||
"转发微博【#南部战区南海海域例行巡航#】1月3日至4日,中国人民解放军@南部战区 组织海空兵力位南海海域进行例行巡航。战区部队全时保持高度戒备,坚决捍卫国家主权安全和海洋权益,任何搅局南海、制造热点的军事活动尽在掌握之中。 "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
timestamp: "2024-02-03 12:58:53",
|
|
||||||
author: "中国海警",
|
|
||||||
influence: 6636,
|
|
||||||
highlighted: false,
|
|
||||||
like: 5013,
|
|
||||||
comment: 247,
|
|
||||||
transmit: 1376,
|
|
||||||
content: `【#中国海警发声# 】2月2日,菲方1艘小型民船对其非法"坐滩" 仁爱礁军舰运送生活物资,中国海警全程跟监管控。中国对包括仁爱礁在内的南沙群岛及其附近海域拥有无可争辩的主权,中国海警依法在中国管辖海域持续开展维权执法活动。`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
timestamp: "2024-02-22 17:13:44",
|
|
||||||
author: "外贸发布BBS",
|
|
||||||
influence: 6919,
|
|
||||||
like: 5354,
|
|
||||||
comment: 155,
|
|
||||||
transmit: 1410,
|
|
||||||
highlighted: false,
|
|
||||||
content: "所以,这算张冠李戴,还是指桑骂槐?#南海救助局寻获2名罹难者遗体#"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
timestamp: "2024-02-23 17:54:46",
|
|
||||||
author: "什么时候有江西舰",
|
|
||||||
influence: 1670,
|
|
||||||
like: 1310,
|
|
||||||
comment: 60,
|
|
||||||
transmit: 300,
|
|
||||||
highlighted: false,
|
|
||||||
content:
|
|
||||||
"转发微博【#中国海警局新闻发言人就菲律宾侵闯黄岩岛发表谈话# 】中国海警局新闻发言人甘羽表示,2月22日至23日,菲律宾渔业和水产资源局3002船不顾中方一再劝阻和警告,执意侵闯中国黄岩岛邻近海域。"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
timestamp: "2024-03-14 09:58:12",
|
|
||||||
author: "新浪军事",
|
|
||||||
influence: 5292,
|
|
||||||
highlighted: false,
|
|
||||||
like: 2827,
|
|
||||||
comment: 1350,
|
|
||||||
transmit: 1115,
|
|
||||||
content: `#大陆渔船金门外海翻覆2人不幸罹难#【又有大陆渔船在金门海域翻覆,已致两人遇难!两岸联合搜救】3月14日,南都记者从金门海巡队获悉,当日清晨一艘大陆渔船"闽龙渔61222"在金门海域遭浪袭翻覆,船上6名船员落海行踪不明。据悉,目前落海的6名船员已全部寻获,4人送医、2人不幸罹难`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
timestamp: "2024-03-23 21:20:40",
|
|
||||||
author: "空天砺剑",
|
|
||||||
influence: 150,
|
|
||||||
highlighted: false,
|
|
||||||
like: 130,
|
|
||||||
comment: 10,
|
|
||||||
transmit: 10,
|
|
||||||
content:
|
|
||||||
"#菲律宾船对中国海警举白旗# 菲律宾人这是感谢帮它们洗船挥手致谢,既然人家这么客气,那就加大水压吧!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
timestamp: "2024-03-23 21:42:36",
|
|
||||||
author: "大侠啊啊啊啊",
|
|
||||||
influence: 2473,
|
|
||||||
highlighted: false,
|
|
||||||
like: 1923,
|
|
||||||
comment: 124,
|
|
||||||
transmit: 426,
|
|
||||||
content: "#菲律宾船对中国海警举白旗#大快人心"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
timestamp: "2024-04-06 18:17:30",
|
|
||||||
author: "人民日报",
|
|
||||||
influence: 8345,
|
|
||||||
highlighted: false,
|
|
||||||
like: 6238,
|
|
||||||
comment: 409,
|
|
||||||
transmit: 1698,
|
|
||||||
content: `【#中方正告菲方任何侵权伎俩都是徒劳#】中国海警局新闻发言人甘羽表示,4月4日,菲方组织多艘船只非法位中国南沙群岛鲎藤礁邻近海域活动,中国海警依法依规处置,现场操作专业规范。中国对包括鲎藤礁在内的南沙群岛及其邻近海域拥有无可争辩的主权,菲公务船打着所谓"护渔"幌子非法侵权挑衅,组织媒体蓄意煽炒误导,持续破坏南海稳定。我们正告菲方,任何侵权伎俩都是徒劳。中国海警将依法在中国管辖海域常态维权执法,坚决维护领土主权和海洋权益。`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
timestamp: "2024-04-06 19:19:50",
|
|
||||||
author: "如皋老猫",
|
|
||||||
influence: 433,
|
|
||||||
highlighted: false,
|
|
||||||
like: 355,
|
|
||||||
comment: 67,
|
|
||||||
transmit: 11,
|
|
||||||
content:
|
|
||||||
"#中国海警回应菲律宾侵闯鲎藤礁#马科斯已经吃了秤砣铁了心当美狗了,所以,希望中国海警除了文字回应外,也该用行动予以坚决回应了!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
timestamp: "2024-05-16 00:22:18",
|
|
||||||
author: "环球网",
|
|
||||||
influence: 2889,
|
|
||||||
highlighted: false,
|
|
||||||
like: 1786,
|
|
||||||
comment: 362,
|
|
||||||
transmit: 741,
|
|
||||||
content: `【#环球时报社评#:#中方对菲律宾的善意和耐心不是无止境的#】在菲律宾近来不断公开否认"君子协定"、后被中方以铁证打脸之后,马尼拉又开始了新的政治表演。15日,5艘商业渔船上约200人从菲律宾高调驶向黄岩岛海域"维权",预计16日到达黄岩岛。菲律宾官方派出海岸警卫队的船为这支所谓"民间船队"护航,一些西方媒体也迅速跟进。这一套配合相当熟练的操作,我们此前已经在菲方于南海生事的好几次事件当中看到。`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async initializeGroupList(time = "2024-05-16 16:56:04") {
|
async initializeGroupList(time = "2024-05-16 16:56:04") {
|
||||||
|
|
@ -282,8 +171,21 @@ export const useGroupDiscoveryStore = defineStore("groupDiscovery", {
|
||||||
Object.entries(res.data.data).forEach(([key, list]) => {
|
Object.entries(res.data.data).forEach(([key, list]) => {
|
||||||
resultObj["seriesList"].push({ name: key, themeColor: themeMap[key], data: list })
|
resultObj["seriesList"].push({ name: key, themeColor: themeMap[key], data: list })
|
||||||
})
|
})
|
||||||
|
|
||||||
this.chartData = resultObj
|
this.chartData = resultObj
|
||||||
|
},
|
||||||
|
|
||||||
|
async initialGraphTimestamp() {
|
||||||
|
const res = await getGroupEvolutionTimeLine()
|
||||||
|
if (res.code != 200) return
|
||||||
|
this.timeList = res.data
|
||||||
|
},
|
||||||
|
|
||||||
|
async initialGraphByUtcTime() {},
|
||||||
|
|
||||||
|
async initialPostByUtcTime(utcTime) {
|
||||||
|
const res = await getPostByUtcTime(utcTime)
|
||||||
|
if (res.code != 200) return
|
||||||
|
this.posts = res.data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persist: true // 开启持久化
|
persist: true // 开启持久化
|
||||||
|
|
@ -678,18 +580,18 @@ export const useGroupMemberStore = defineStore("groupMember", {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
value: [10, 5, 15, 5],
|
value: [10, 5, 15, 5],
|
||||||
symbol: 'circle',
|
symbol: "circle",
|
||||||
symbolSize: 5,
|
symbolSize: 5,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#01D7DA', // 圆点颜色
|
color: "#01D7DA" // 圆点颜色
|
||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: 'rgba(87, 196, 255, 0.3)' // 区域填充
|
color: "rgba(87, 196, 255, 0.3)" // 区域填充
|
||||||
},
|
},
|
||||||
// 点之间的连线
|
// 点之间的连线
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#0374FE',
|
color: "#0374FE",
|
||||||
type: 'dashed',
|
type: "dashed",
|
||||||
width: 1
|
width: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -707,17 +609,17 @@ export const useGroupMemberStore = defineStore("groupMember", {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
value: [10, 20, 15, 5],
|
value: [10, 20, 15, 5],
|
||||||
symbol: 'circle',
|
symbol: "circle",
|
||||||
symbolSize: 5,
|
symbolSize: 5,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#01D7DA', // 圆点颜色
|
color: "#01D7DA" // 圆点颜色
|
||||||
},
|
},
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: 'rgba(87, 196, 255, 0.3)' // 区域填充
|
color: "rgba(87, 196, 255, 0.3)" // 区域填充
|
||||||
},
|
},
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#0374FE',
|
color: "#0374FE",
|
||||||
type: 'dashed',
|
type: "dashed",
|
||||||
width: 1
|
width: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -760,8 +662,8 @@ export const useGroupMemberStore = defineStore("groupMember", {
|
||||||
width: 1 // 设置线条宽度为3像素
|
width: 1 // 设置线条宽度为3像素
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#0A1A2F',
|
color: "#0A1A2F",
|
||||||
borderColor: '#2AB8FD',
|
borderColor: "#2AB8FD",
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
},
|
},
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
|
|
@ -776,8 +678,8 @@ export const useGroupMemberStore = defineStore("groupMember", {
|
||||||
width: 1 // 设置线条宽度为3像素
|
width: 1 // 设置线条宽度为3像素
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#0A1A2F',
|
color: "#0A1A2F",
|
||||||
borderColor: '#01D7DA',
|
borderColor: "#01D7DA",
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
},
|
},
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
|
|
@ -793,8 +695,8 @@ export const useGroupMemberStore = defineStore("groupMember", {
|
||||||
width: 1 // 设置线条宽度为3像素
|
width: 1 // 设置线条宽度为3像素
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#0A1A2F',
|
color: "#0A1A2F",
|
||||||
borderColor: '#FFDA09',
|
borderColor: "#FFDA09",
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
},
|
},
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
|
|
@ -810,8 +712,8 @@ export const useGroupMemberStore = defineStore("groupMember", {
|
||||||
width: 1 // 设置线条宽度为3像素
|
width: 1 // 设置线条宽度为3像素
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#0A1A2F',
|
color: "#0A1A2F",
|
||||||
borderColor: '#EB57B0',
|
borderColor: "#EB57B0",
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
},
|
},
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
|
|
@ -1355,7 +1257,8 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
|
||||||
//
|
//
|
||||||
mutualCommentCount: 3,
|
mutualCommentCount: 3,
|
||||||
// 评论内容
|
// 评论内容
|
||||||
content: "在我国海域偷运軍械彈藥是應該依法拘捕送交法院睿理判刑,而且在中国的裹服刑的!难道外国人特权?更何况是這千点小国!#中国海警首次登检菲律宾运补船只# #外交部回应中国海警缴获菲士兵枪支#",
|
content:
|
||||||
|
"在我国海域偷运軍械彈藥是應該依法拘捕送交法院睿理判刑,而且在中国的裹服刑的!难道外国人特权?更何况是這千点小国!#中国海警首次登检菲律宾运补船只# #外交部回应中国海警缴获菲士兵枪支#",
|
||||||
// 点赞数
|
// 点赞数
|
||||||
likeCount: "4.8w",
|
likeCount: "4.8w",
|
||||||
// 评论数
|
// 评论数
|
||||||
|
|
@ -1372,8 +1275,8 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
|
||||||
name: "社团组一",
|
name: "社团组一",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#2AB8FD',
|
color: "#2AB8FD",
|
||||||
borderColor: '#2AB8FD',
|
borderColor: "#2AB8FD",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: [4, 4, 0, 0] // 顶部圆角
|
borderRadius: [4, 4, 0, 0] // 顶部圆角
|
||||||
},
|
},
|
||||||
|
|
@ -1383,8 +1286,8 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
|
||||||
name: "社团组二",
|
name: "社团组二",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#02D7DA',
|
color: "#02D7DA",
|
||||||
borderColor: '#02D7DA',
|
borderColor: "#02D7DA",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: [4, 4, 0, 0] // 顶部圆角
|
borderRadius: [4, 4, 0, 0] // 顶部圆角
|
||||||
},
|
},
|
||||||
|
|
@ -1394,15 +1297,14 @@ export const useAnomalousGroup = defineStore("anomalousGroup", {
|
||||||
name: "社团组三",
|
name: "社团组三",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#FFDA09',
|
color: "#FFDA09",
|
||||||
borderColor: '#FFDA09',
|
borderColor: "#FFDA09",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: [4, 4, 0, 0] // 顶部圆角
|
borderRadius: [4, 4, 0, 0] // 顶部圆角
|
||||||
},
|
},
|
||||||
data: [5, 0, 4, 0, 3, 0, 0]
|
data: [5, 0, 4, 0, 3, 0, 0]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs"
|
||||||
|
import utc from "dayjs/plugin/utc"
|
||||||
|
dayjs.extend(utc)
|
||||||
// 将图片裁剪为圆形并在四周添加透明padding后返回 base64
|
// 将图片裁剪为圆形并在四周添加透明padding后返回 base64
|
||||||
export function cropImageToCircle(url, size = 100, paddingRatio = 0.25) {
|
export function cropImageToCircle(url, size = 100, paddingRatio = 0.25) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const img = new window.Image();
|
const img = new window.Image()
|
||||||
img.crossOrigin = "anonymous";
|
img.crossOrigin = "anonymous"
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
const padding = size * paddingRatio;
|
const padding = size * paddingRatio
|
||||||
const canvasSize = size + padding * 2;
|
const canvasSize = size + padding * 2
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas")
|
||||||
canvas.width = canvasSize;
|
canvas.width = canvasSize
|
||||||
canvas.height = canvasSize;
|
canvas.height = canvasSize
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d")
|
||||||
ctx.clearRect(0, 0, canvasSize, canvasSize);
|
ctx.clearRect(0, 0, canvasSize, canvasSize)
|
||||||
ctx.save();
|
ctx.save()
|
||||||
ctx.beginPath();
|
ctx.beginPath()
|
||||||
ctx.strokeStyle = "#efa7a7"; // 边框颜色
|
ctx.strokeStyle = "#efa7a7" // 边框颜色
|
||||||
context.lineWidth = 10; // 边框宽度
|
context.lineWidth = 10 // 边框宽度
|
||||||
ctx.arc(canvasSize / 2, canvasSize / 2, size / 2, 0, Math.PI * 2, false);
|
ctx.arc(canvasSize / 2, canvasSize / 2, size / 2, 0, Math.PI * 2, false)
|
||||||
ctx.closePath();
|
ctx.closePath()
|
||||||
ctx.clip();
|
ctx.clip()
|
||||||
ctx.drawImage(img, padding, padding, size, size);
|
ctx.drawImage(img, padding, padding, size, size)
|
||||||
ctx.restore();
|
ctx.restore()
|
||||||
resolve(canvas.toDataURL("image/png"));
|
resolve(canvas.toDataURL("image/png"))
|
||||||
};
|
}
|
||||||
img.src = url;
|
img.src = url
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -36,32 +37,42 @@ export function cropImageToCircle(url, size = 100, paddingRatio = 0.25) {
|
||||||
*/
|
*/
|
||||||
export async function cropToCircleAsync(imageSrc, diameter = 50) {
|
export async function cropToCircleAsync(imageSrc, diameter = 50) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new window.Image();
|
const img = new window.Image()
|
||||||
img.crossOrigin = "anonymous";
|
img.crossOrigin = "anonymous"
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas")
|
||||||
canvas.width = diameter;
|
canvas.width = diameter
|
||||||
canvas.height = diameter;
|
canvas.height = diameter
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d")
|
||||||
|
|
||||||
ctx.beginPath();
|
ctx.beginPath()
|
||||||
ctx.arc(diameter / 2, diameter / 2, diameter / 2, 0, Math.PI * 2);
|
ctx.arc(diameter / 2, diameter / 2, diameter / 2, 0, Math.PI * 2)
|
||||||
ctx.closePath();
|
ctx.closePath()
|
||||||
ctx.clip();
|
ctx.clip()
|
||||||
|
|
||||||
ctx.drawImage(img, 0, 0, diameter, diameter);
|
ctx.drawImage(img, 0, 0, diameter, diameter)
|
||||||
resolve(canvas.toDataURL("image/png"));
|
resolve(canvas.toDataURL("image/png"))
|
||||||
};
|
}
|
||||||
img.onerror = reject;
|
img.onerror = reject
|
||||||
img.src = imageSrc;
|
img.src = imageSrc
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//转换时间戳
|
//转换时间戳
|
||||||
export function TansTimestamp(timestamp, format = "YYYY-MM-DD HH:mm:ss") {
|
export function TansTimestamp(timestamp, format = "YYYY-MM-DD HH:mm:ss") {
|
||||||
if (!timestamp) return;
|
if (!timestamp) return
|
||||||
const ts = timestamp.toString().length === 10 ? timestamp * 1000 : timestamp;
|
const ts = timestamp.toString().length === 10 ? timestamp * 1000 : timestamp
|
||||||
return dayjs(ts).format(format);
|
return dayjs(ts).format(format)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将日期字符串转换为ISO 8601 UTC格式 (2024-06-19T07:57:46Z)
|
||||||
|
* @param {string|Date} dateInput - 日期字符串或Date对象
|
||||||
|
* @returns {string} ISO 8601格式的UTC时间字符串
|
||||||
|
*/
|
||||||
|
export function convertToUtcIsoString(dateInput) {
|
||||||
|
// 转换为UTC并格式化为ISO字符串,然后确保以Z结尾
|
||||||
|
return dayjs(dateInput).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")
|
||||||
}
|
}
|
||||||
|
|
||||||
//将后端返回的二进制数据转换成所需的头像格式
|
//将后端返回的二进制数据转换成所需的头像格式
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,61 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="groupGraph-component"></div>
|
<div class="groupGraph-component">
|
||||||
|
<img src="@/assets/images/groupEvolution/graph-title.png" class="titleImage" />
|
||||||
|
<div class="container" id="container"></div>
|
||||||
|
<div class="timeList">
|
||||||
|
<TimeAxis
|
||||||
|
v-if="timeList.length"
|
||||||
|
:time-list="timeList"
|
||||||
|
:is-auto-play="false"
|
||||||
|
:start-time="new Date(timeList[0])"
|
||||||
|
:end-time="new Date(timeList[timeList.length - 1])"
|
||||||
|
@click:pointerDown="handlePointerDown"
|
||||||
|
@slide:pointerUp="handlePointerDown"
|
||||||
|
></TimeAxis>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup></script>
|
<script setup>
|
||||||
|
import { defineProps, defineEmits } from "vue"
|
||||||
|
import { storeToRefs } from "pinia"
|
||||||
|
import TimeAxis from "@/components/timeAxis.vue"
|
||||||
|
import { convertToUtcIsoString } from "@/utils/transform"
|
||||||
|
const props = defineProps({
|
||||||
|
store: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(["click:pointerDownAndSlide"])
|
||||||
|
// 解构 store 中的 state
|
||||||
|
const { timeList } = storeToRefs(props.store)
|
||||||
|
|
||||||
|
// 处理时间轴点击事件和拉动
|
||||||
|
const handlePointerDown = (time) => {
|
||||||
|
const utcTime = convertToUtcIsoString(time)
|
||||||
|
emit("click:pointerDownAndSlide", utcTime)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.groupGraph-component {
|
.groupGraph-component {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
.titleImage {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 503px;
|
||||||
|
}
|
||||||
|
.timeList {
|
||||||
|
width: 95%;
|
||||||
|
height: 42px;
|
||||||
|
position: absolute;
|
||||||
|
left: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-container">
|
<div class="middle-container">
|
||||||
<div class="graph"></div>
|
<div class="graph">
|
||||||
|
<GroupGraph
|
||||||
|
:store="groupDiscoveryStore"
|
||||||
|
@click:pointerDownAndSlide="handleChangeXAxis"
|
||||||
|
></GroupGraph>
|
||||||
|
</div>
|
||||||
<div class="postList">
|
<div class="postList">
|
||||||
<GroupPost
|
<GroupPost
|
||||||
:posts="groupDiscoveryStore.posts"
|
:posts="groupDiscoveryStore.posts"
|
||||||
|
|
@ -38,28 +43,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-dialog v-model="postDialog" width="640" align-center class="custom-dialog">
|
|
||||||
<img src="@/assets/images/head/post-dialog-title.png" alt="" class="postTitleImage" />
|
|
||||||
<div class="dialog-content">
|
|
||||||
<div class="post-content">{{ currentPostPost.content }}</div>
|
|
||||||
<div class="heat">
|
|
||||||
<div class="item-heat-detail">
|
|
||||||
<div class="item-heat-like">
|
|
||||||
<Icon icon="ei:like" width="25" height="25" /> {{ currentPostPost.like }}
|
|
||||||
</div>
|
|
||||||
<div class="item-heat-comment">
|
|
||||||
<Icon icon="la:comment-dots" width="25" height="25" /> {{ currentPostPost.comment }}
|
|
||||||
</div>
|
|
||||||
<div class="item-heat-transmit">
|
|
||||||
<Icon icon="mdi:share-outline" width="25" height="25" /> {{
|
|
||||||
currentPostPost.transmit
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -70,10 +53,10 @@ import GroupChart from "../component/groupChart.vue"
|
||||||
import GroupPost from "../component/groupPost.vue"
|
import GroupPost from "../component/groupPost.vue"
|
||||||
import GroupShow from "../component/groupShow.vue"
|
import GroupShow from "../component/groupShow.vue"
|
||||||
import WordsCloud from "../component/wordsCloud.vue"
|
import WordsCloud from "../component/wordsCloud.vue"
|
||||||
|
import GroupGraph from "../component/groupGraph.vue"
|
||||||
import groupPanelTitleImg from "@/assets/images/groupEvolution/groupPanel-title.png"
|
import groupPanelTitleImg from "@/assets/images/groupEvolution/groupPanel-title.png"
|
||||||
import groupChartTitleImg from "@/assets/images/groupEvolution/chart-title.png"
|
import groupChartTitleImg from "@/assets/images/groupEvolution/chart-title.png"
|
||||||
import groupGroupShowImg from "@/assets/images/groupEvolution/groupDisc-title.png"
|
import groupGroupShowImg from "@/assets/images/groupEvolution/groupDisc-title.png"
|
||||||
import { Icon } from "@iconify/vue"
|
|
||||||
import { useGroupDiscoveryStore } from "@/store/groupEvolution/index"
|
import { useGroupDiscoveryStore } from "@/store/groupEvolution/index"
|
||||||
|
|
||||||
const groupDiscoveryStore = useGroupDiscoveryStore()
|
const groupDiscoveryStore = useGroupDiscoveryStore()
|
||||||
|
|
@ -88,9 +71,14 @@ const handleOpenPostDialog = (post) => {
|
||||||
currentPostPost.value = post
|
currentPostPost.value = post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleChangeXAxis = (utcTime) => {
|
||||||
|
groupDiscoveryStore.initialPostByUtcTime(utcTime) //随着时间轴变动,更新贴文列表
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
groupDiscoveryStore.initializeGroupList()
|
groupDiscoveryStore.initializeGroupList()
|
||||||
groupDiscoveryStore.initializeGroupScaleChart()
|
groupDiscoveryStore.initializeGroupScaleChart()
|
||||||
|
groupDiscoveryStore.initialGraphTimestamp()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user