mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 07:16:51 +00:00
feat: clarify mutual friends direction labels
This commit is contained in:
@@ -405,9 +405,9 @@
|
|||||||
|
|
||||||
.session-mutual-friends-row {
|
.session-mutual-friends-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 42px minmax(0, 1fr) 96px 72px 110px;
|
grid-template-columns: 42px minmax(0, 1fr) 72px 110px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: start;
|
||||||
padding: 11px 12px;
|
padding: 11px 12px;
|
||||||
border-bottom: 1px solid color-mix(in srgb, var(--border-color) 68%, transparent);
|
border-bottom: 1px solid color-mix(in srgb, var(--border-color) 68%, transparent);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@@ -426,6 +426,14 @@
|
|||||||
|
|
||||||
.session-mutual-friends-rank {
|
.session-mutual-friends-rank {
|
||||||
color: var(--text-tertiary);
|
color: var(--text-tertiary);
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.session-mutual-friends-main {
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-mutual-friends-name {
|
.session-mutual-friends-name {
|
||||||
@@ -437,6 +445,13 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.session-mutual-friends-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.session-mutual-friends-source {
|
.session-mutual-friends-source {
|
||||||
justify-self: start;
|
justify-self: start;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
@@ -447,22 +462,56 @@
|
|||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
|
|
||||||
&.both {
|
&.incoming {
|
||||||
color: var(--primary);
|
color: #065f46;
|
||||||
border-color: color-mix(in srgb, var(--primary) 35%, var(--border-color));
|
border-color: color-mix(in srgb, #10b981 38%, var(--border-color));
|
||||||
background: color-mix(in srgb, var(--primary) 10%, var(--bg-secondary));
|
background: color-mix(in srgb, #10b981 10%, var(--bg-secondary));
|
||||||
}
|
}
|
||||||
|
|
||||||
&.reverse {
|
&.outgoing {
|
||||||
color: #92400e;
|
color: #92400e;
|
||||||
border-color: color-mix(in srgb, #d97706 38%, var(--border-color));
|
border-color: color-mix(in srgb, #d97706 38%, var(--border-color));
|
||||||
background: color-mix(in srgb, #f59e0b 12%, var(--bg-secondary));
|
background: color-mix(in srgb, #f59e0b 12%, var(--bg-secondary));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.bidirectional {
|
||||||
|
color: var(--primary);
|
||||||
|
border-color: color-mix(in srgb, var(--primary) 35%, var(--border-color));
|
||||||
|
background: color-mix(in srgb, var(--primary) 10%, var(--bg-secondary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.session-mutual-friends-behavior {
|
||||||
|
&.likes {
|
||||||
|
color: #1d4ed8;
|
||||||
|
border-color: color-mix(in srgb, #3b82f6 34%, var(--border-color));
|
||||||
|
background: color-mix(in srgb, #3b82f6 9%, var(--bg-secondary));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.comments {
|
||||||
|
color: #7c3aed;
|
||||||
|
border-color: color-mix(in srgb, #8b5cf6 34%, var(--border-color));
|
||||||
|
background: color-mix(in srgb, #8b5cf6 9%, var(--bg-secondary));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.both {
|
||||||
|
color: #be185d;
|
||||||
|
border-color: color-mix(in srgb, #ec4899 34%, var(--border-color));
|
||||||
|
background: color-mix(in srgb, #ec4899 9%, var(--bg-secondary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.session-mutual-friends-desc {
|
||||||
|
min-width: 0;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.45;
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-mutual-friends-count,
|
.session-mutual-friends-count,
|
||||||
.session-mutual-friends-latest {
|
.session-mutual-friends-latest {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
padding-top: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-mutual-friends-empty {
|
.session-mutual-friends-empty {
|
||||||
@@ -3828,7 +3877,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.session-mutual-friends-row {
|
.session-mutual-friends-row {
|
||||||
grid-template-columns: 34px minmax(0, 1fr) 82px 56px 88px;
|
grid-template-columns: 34px minmax(0, 1fr) 56px 88px;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -574,15 +574,19 @@ interface SessionSnsRankItem {
|
|||||||
latestTime: number
|
latestTime: number
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionMutualFriendSource = 'likes' | 'comments' | 'both' | 'reverse'
|
type SessionMutualFriendDirection = 'incoming' | 'outgoing' | 'bidirectional'
|
||||||
|
type SessionMutualFriendBehavior = 'likes' | 'comments' | 'both'
|
||||||
|
|
||||||
interface SessionMutualFriendItem {
|
interface SessionMutualFriendItem {
|
||||||
name: string
|
name: string
|
||||||
likeCount: number
|
incomingLikeCount: number
|
||||||
commentCount: number
|
incomingCommentCount: number
|
||||||
|
outgoingLikeCount: number
|
||||||
|
outgoingCommentCount: number
|
||||||
totalCount: number
|
totalCount: number
|
||||||
latestTime: number
|
latestTime: number
|
||||||
source: SessionMutualFriendSource
|
direction: SessionMutualFriendDirection
|
||||||
|
behavior: SessionMutualFriendBehavior
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SessionMutualFriendsMetric {
|
interface SessionMutualFriendsMetric {
|
||||||
@@ -659,19 +663,22 @@ const buildSessionMutualFriendsMetric = (
|
|||||||
const name = String(likeNameRaw || '').trim() || '未知用户'
|
const name = String(likeNameRaw || '').trim() || '未知用户'
|
||||||
const existing = friendMap.get(name)
|
const existing = friendMap.get(name)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.likeCount += 1
|
existing.incomingLikeCount += 1
|
||||||
existing.totalCount += 1
|
existing.totalCount += 1
|
||||||
existing.source = existing.commentCount > 0 ? 'both' : 'likes'
|
existing.behavior = existing.incomingCommentCount > 0 ? 'both' : 'likes'
|
||||||
if (createTime > existing.latestTime) existing.latestTime = createTime
|
if (createTime > existing.latestTime) existing.latestTime = createTime
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
friendMap.set(name, {
|
friendMap.set(name, {
|
||||||
name,
|
name,
|
||||||
likeCount: 1,
|
incomingLikeCount: 1,
|
||||||
commentCount: 0,
|
incomingCommentCount: 0,
|
||||||
|
outgoingLikeCount: 0,
|
||||||
|
outgoingCommentCount: 0,
|
||||||
totalCount: 1,
|
totalCount: 1,
|
||||||
latestTime: createTime,
|
latestTime: createTime,
|
||||||
source: 'likes'
|
direction: 'incoming',
|
||||||
|
behavior: 'likes'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,19 +686,22 @@ const buildSessionMutualFriendsMetric = (
|
|||||||
const name = String(comment?.nickname || '').trim() || '未知用户'
|
const name = String(comment?.nickname || '').trim() || '未知用户'
|
||||||
const existing = friendMap.get(name)
|
const existing = friendMap.get(name)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.commentCount += 1
|
existing.incomingCommentCount += 1
|
||||||
existing.totalCount += 1
|
existing.totalCount += 1
|
||||||
existing.source = existing.likeCount > 0 ? 'both' : 'comments'
|
existing.behavior = existing.incomingLikeCount > 0 ? 'both' : 'comments'
|
||||||
if (createTime > existing.latestTime) existing.latestTime = createTime
|
if (createTime > existing.latestTime) existing.latestTime = createTime
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
friendMap.set(name, {
|
friendMap.set(name, {
|
||||||
name,
|
name,
|
||||||
likeCount: 0,
|
incomingLikeCount: 0,
|
||||||
commentCount: 1,
|
incomingCommentCount: 1,
|
||||||
|
outgoingLikeCount: 0,
|
||||||
|
outgoingCommentCount: 0,
|
||||||
totalCount: 1,
|
totalCount: 1,
|
||||||
latestTime: createTime,
|
latestTime: createTime,
|
||||||
source: 'comments'
|
direction: 'incoming',
|
||||||
|
behavior: 'comments'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,11 +721,41 @@ const buildSessionMutualFriendsMetric = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSessionMutualFriendSourceLabel = (source: SessionMutualFriendSource): string => {
|
const getSessionMutualFriendDirectionLabel = (direction: SessionMutualFriendDirection): string => {
|
||||||
if (source === 'both') return '点赞/评论'
|
if (direction === 'incoming') return '对方赞/评TA'
|
||||||
if (source === 'reverse') return '反向关联'
|
if (direction === 'outgoing') return 'TA赞/评对方'
|
||||||
if (source === 'likes') return '仅点赞'
|
return '双方有互动'
|
||||||
return '仅评论'
|
}
|
||||||
|
|
||||||
|
const getSessionMutualFriendBehaviorLabel = (behavior: SessionMutualFriendBehavior): string => {
|
||||||
|
if (behavior === 'likes') return '赞'
|
||||||
|
if (behavior === 'comments') return '评'
|
||||||
|
return '赞/评'
|
||||||
|
}
|
||||||
|
|
||||||
|
const summarizeMutualFriendBehavior = (likeCount: number, commentCount: number): SessionMutualFriendBehavior => {
|
||||||
|
if (likeCount > 0 && commentCount > 0) return 'both'
|
||||||
|
if (likeCount > 0) return 'likes'
|
||||||
|
return 'comments'
|
||||||
|
}
|
||||||
|
|
||||||
|
const describeSessionMutualFriendRelation = (
|
||||||
|
item: SessionMutualFriendItem,
|
||||||
|
targetDisplayName: string
|
||||||
|
): string => {
|
||||||
|
if (item.direction === 'incoming') {
|
||||||
|
if (item.behavior === 'likes') return `${item.name} 给 ${targetDisplayName} 点过赞`
|
||||||
|
if (item.behavior === 'comments') return `${item.name} 给 ${targetDisplayName} 评论过`
|
||||||
|
return `${item.name} 给 ${targetDisplayName} 点过赞、评论过`
|
||||||
|
}
|
||||||
|
if (item.direction === 'outgoing') {
|
||||||
|
if (item.behavior === 'likes') return `${targetDisplayName} 给 ${item.name} 点过赞`
|
||||||
|
if (item.behavior === 'comments') return `${targetDisplayName} 给 ${item.name} 评论过`
|
||||||
|
return `${targetDisplayName} 给 ${item.name} 点过赞、评论过`
|
||||||
|
}
|
||||||
|
if (item.behavior === 'likes') return `${targetDisplayName} 和 ${item.name} 双方都有点赞互动`
|
||||||
|
if (item.behavior === 'comments') return `${targetDisplayName} 和 ${item.name} 双方都有评论互动`
|
||||||
|
return `${targetDisplayName} 和 ${item.name} 双方都有点赞或评论互动`
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SessionExportMetric {
|
interface SessionExportMetric {
|
||||||
@@ -2746,15 +2786,35 @@ function ExportPage() {
|
|||||||
if (reverseMatches.length === 0) continue
|
if (reverseMatches.length === 0) continue
|
||||||
|
|
||||||
const reverseCount = reverseMatches.reduce((sum, item) => sum + item.totalCount, 0)
|
const reverseCount = reverseMatches.reduce((sum, item) => sum + item.totalCount, 0)
|
||||||
|
const reverseLikeCount = reverseMatches.reduce((sum, item) => sum + item.incomingLikeCount, 0)
|
||||||
|
const reverseCommentCount = reverseMatches.reduce((sum, item) => sum + item.incomingCommentCount, 0)
|
||||||
const reverseLatestTime = reverseMatches.reduce((latest, item) => Math.max(latest, item.latestTime), 0)
|
const reverseLatestTime = reverseMatches.reduce((latest, item) => Math.max(latest, item.latestTime), 0)
|
||||||
mergedMap.set(sourceProfile.displayName, {
|
const existing = mergedMap.get(sourceProfile.displayName)
|
||||||
name: sourceProfile.displayName,
|
if (existing) {
|
||||||
likeCount: 0,
|
existing.outgoingLikeCount += reverseLikeCount
|
||||||
commentCount: 0,
|
existing.outgoingCommentCount += reverseCommentCount
|
||||||
totalCount: reverseCount,
|
existing.totalCount += reverseCount
|
||||||
latestTime: reverseLatestTime,
|
existing.latestTime = Math.max(existing.latestTime, reverseLatestTime)
|
||||||
source: 'reverse'
|
existing.direction = (existing.incomingLikeCount + existing.incomingCommentCount) > 0
|
||||||
})
|
? 'bidirectional'
|
||||||
|
: 'outgoing'
|
||||||
|
existing.behavior = summarizeMutualFriendBehavior(
|
||||||
|
existing.incomingLikeCount + existing.outgoingLikeCount,
|
||||||
|
existing.incomingCommentCount + existing.outgoingCommentCount
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
mergedMap.set(sourceProfile.displayName, {
|
||||||
|
name: sourceProfile.displayName,
|
||||||
|
incomingLikeCount: 0,
|
||||||
|
incomingCommentCount: 0,
|
||||||
|
outgoingLikeCount: reverseLikeCount,
|
||||||
|
outgoingCommentCount: reverseCommentCount,
|
||||||
|
totalCount: reverseCount,
|
||||||
|
latestTime: reverseLatestTime,
|
||||||
|
direction: 'outgoing',
|
||||||
|
behavior: summarizeMutualFriendBehavior(reverseLikeCount, reverseCommentCount)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = [...mergedMap.values()].sort((a, b) => {
|
const items = [...mergedMap.values()].sort((a, b) => {
|
||||||
@@ -6439,10 +6499,20 @@ function ExportPage() {
|
|||||||
{filteredSessionMutualFriendsDialogItems.map((item, index) => (
|
{filteredSessionMutualFriendsDialogItems.map((item, index) => (
|
||||||
<div className="session-mutual-friends-row" key={`${sessionMutualFriendsDialogTarget.username}-${item.name}`}>
|
<div className="session-mutual-friends-row" key={`${sessionMutualFriendsDialogTarget.username}-${item.name}`}>
|
||||||
<span className="session-mutual-friends-rank">{index + 1}</span>
|
<span className="session-mutual-friends-rank">{index + 1}</span>
|
||||||
<span className="session-mutual-friends-name" title={item.name}>{item.name}</span>
|
<div className="session-mutual-friends-main">
|
||||||
<span className={`session-mutual-friends-source ${item.source}`}>
|
<span className="session-mutual-friends-name" title={item.name}>{item.name}</span>
|
||||||
{getSessionMutualFriendSourceLabel(item.source)}
|
<div className="session-mutual-friends-tags">
|
||||||
</span>
|
<span className={`session-mutual-friends-source ${item.direction}`}>
|
||||||
|
{getSessionMutualFriendDirectionLabel(item.direction)}
|
||||||
|
</span>
|
||||||
|
<span className={`session-mutual-friends-source session-mutual-friends-behavior ${item.behavior}`}>
|
||||||
|
{getSessionMutualFriendBehaviorLabel(item.behavior)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="session-mutual-friends-desc">
|
||||||
|
{describeSessionMutualFriendRelation(item, sessionMutualFriendsDialogTarget.displayName)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<span className="session-mutual-friends-count">{item.totalCount.toLocaleString('zh-CN')}</span>
|
<span className="session-mutual-friends-count">{item.totalCount.toLocaleString('zh-CN')}</span>
|
||||||
<span className="session-mutual-friends-latest">{formatYmdDateFromSeconds(item.latestTime)}</span>
|
<span className="session-mutual-friends-latest">{formatYmdDateFromSeconds(item.latestTime)}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user