feat: feishu alert

This commit is contained in:
zzc
2026-06-24 23:15:47 +08:00
parent 0ef2b697a3
commit bb819d07a1
9 changed files with 153 additions and 306 deletions

View File

@@ -0,0 +1,108 @@
<template>
<div class="user-info-component">
<div v-if="user" class="user-info-cell" :class="{ 'is-clickable': !user.isRobot }" @click="handleUserClick">
<el-image v-if="user.avatar" class="user-avatar" :preview-src-list="[user.avatar]" :src="getThumbUrl(user.avatar)" @click.stop />
<div v-else class="user-avatar-placeholder"><i class="el-icon-user" /></div>
<div class="user-details">
<div class="user-nickname" :class="{ 'hover-link': !user.isRobot }">
{{ user.nickname || '未知用户' }}
<el-tag v-if="user.isRobot" size="mini" style="margin-left: 4px" type="info">机器人</el-tag>
<el-tag v-else size="mini" style="margin-left: 4px" type="success">真人</el-tag>
</div>
<div class="user-id">{{ user.id }}</div>
</div>
</div>
<div v-else class="user-details">
<div class="user-id">{{ userId }}</div>
</div>
</div>
</template>
<script>
import { getThumbUrl } from '@/utils/blessing'
export default {
name: 'UserInfo',
props: {
user: {
type: Object,
default: () => null,
},
userId: {
type: String,
default: '',
},
},
methods: {
getThumbUrl,
handleUserClick() {
if (this.user && !this.user.isRobot) {
// 跳转到用户页面
this.$router.push({
path: '/spring/user/user',
query: { userId: this.user.id },
})
}
},
},
}
</script>
<style scoped>
.user-info-component {
display: block;
}
.user-info-cell {
display: flex;
align-items: center;
}
.is-clickable {
cursor: pointer;
}
.is-clickable:hover .hover-link {
color: #409eff;
text-decoration: underline;
}
.user-avatar,
.user-avatar-placeholder {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
flex-shrink: 0;
}
.user-avatar-placeholder {
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 20px;
}
.user-details {
display: flex;
flex-direction: column;
overflow: hidden;
}
.user-nickname {
font-weight: bold;
color: #303133;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: color 0.2s;
}
.user-id {
font-size: 12px;
color: #909399;
}
</style>

View File

@@ -27,25 +27,7 @@
<el-table-column align="left" label="用户信息" min-width="180">
<template #default="{ row }">
<div v-if="row.user" class="user-info-cell">
<el-image
v-if="row.user.avatar"
class="user-avatar"
:preview-src-list="[row.user.avatar]"
:src="getThumbUrl(row.user.avatar)"
/>
<div v-else class="user-avatar-placeholder"><i class="el-icon-user" /></div>
<div class="user-details">
<div class="user-nickname">
{{ row.user.nickname || '未知用户' }}
<el-tag v-if="row.user.isRobot" size="mini" style="margin-left: 4px" type="info">机器人</el-tag>
<el-tag v-else size="mini" style="margin-left: 4px" type="success">真人</el-tag>
</div>
</div>
</div>
<div v-else class="user-details">
<div class="user-id">{{ row.userId }}</div>
</div>
<user-info :user="row.user" :user-id="row.userId" />
</template>
</el-table-column>
@@ -78,9 +60,11 @@
import { getCommentList, toggleEnable } from '@/api/rating/pk'
import { formatTime } from '@/utils'
import { getThumbUrl } from '@/utils/blessing'
import UserInfo from '@/components/UserInfo'
export default {
name: 'CommentReplyList',
components: { UserInfo },
data() {
return {
title: '回复列表',
@@ -188,46 +172,4 @@
.meta-item i {
margin-right: 4px;
}
.user-info-cell {
display: flex;
align-items: center;
}
.user-avatar,
.user-avatar-placeholder {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 8px;
flex-shrink: 0;
}
.user-avatar-placeholder {
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 16px;
}
.user-details {
display: flex;
flex-direction: column;
overflow: hidden;
}
.user-nickname {
font-weight: bold;
color: #303133;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-id {
font-size: 12px;
color: #909399;
}
</style>

View File

@@ -79,26 +79,7 @@
<el-table-column align="left" label="用户信息" min-width="200">
<template #default="{ row }">
<div v-if="row.user" class="user-info-cell">
<el-image
v-if="row.user.avatar"
class="user-avatar"
:preview-src-list="[row.user.avatar]"
:src="getThumbUrl(row.user.avatar)"
/>
<div v-else class="user-avatar-placeholder"><i class="el-icon-user" /></div>
<div class="user-details">
<div class="user-nickname">
{{ row.user.nickname || '未知用户' }}
<el-tag v-if="row.user.isRobot" size="mini" style="margin-left: 4px" type="info">机器人</el-tag>
<el-tag v-else size="mini" style="margin-left: 4px" type="success">真人</el-tag>
</div>
<div class="user-id">{{ row.user.id }}</div>
</div>
</div>
<div v-else class="user-details">
<div class="user-id">{{ row.userId }}</div>
</div>
<user-info :user="row.user" :user-id="row.userId" />
</template>
</el-table-column>
@@ -135,13 +116,14 @@
import { getCommentList, toggleEnable, getList as getPkList } from '@/api/rating/pk'
import { formatTime } from '@/utils'
import { getThumbUrl } from '@/utils/blessing'
import UserInfo from '@/components/UserInfo'
import PkCommentEdit from './components/PkCommentEdit'
import PkCommentLikeEdit from './components/PkCommentLikeEdit'
import CommentReplyList from './components/CommentReplyList'
export default {
name: 'PkComment',
components: { PkCommentEdit, PkCommentLikeEdit, CommentReplyList },
components: { PkCommentEdit, PkCommentLikeEdit, CommentReplyList, UserInfo },
directives: {
loadmore: {
bind(el, binding) {
@@ -330,47 +312,4 @@
font-weight: bold;
color: #303133;
}
.user-info-cell {
display: flex;
align-items: center;
}
.user-avatar,
.user-avatar-placeholder {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
flex-shrink: 0;
}
.user-avatar-placeholder {
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 20px;
}
.user-details {
display: flex;
flex-direction: column;
overflow: hidden;
}
.user-nickname {
font-weight: bold;
color: #303133;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-id {
font-size: 12px;
color: #909399;
}
</style>

View File

@@ -3,14 +3,7 @@
<el-table v-loading="listLoading" :data="list" :element-loading-text="elementLoadingText">
<el-table-column align="left" label="投票用户" min-width="150">
<template #default="{ row }">
<div class="user-info-cell">
<el-image v-if="row.avatar" class="user-avatar" :preview-src-list="[row.avatar]" :src="getThumbUrl(row.avatar)" />
<div v-else class="user-avatar-placeholder"><i class="el-icon-user" /></div>
<div class="user-details">
<div class="user-nickname">{{ row.nickname || '未知用户' }}</div>
<div class="user-id">{{ row.id }}</div>
</div>
</div>
<user-info :user="row" :user-id="row.id" />
</template>
</el-table-column>
</el-table>
@@ -30,9 +23,11 @@
<script>
import { getParticipantList } from '@/api/rating/pk'
import { getThumbUrl } from '@/utils/blessing'
import UserInfo from '@/components/UserInfo'
export default {
name: 'PkParticipantList',
components: { UserInfo },
data() {
return {
title: '投票用户列表',
@@ -87,47 +82,3 @@
},
}
</script>
<style scoped>
.user-info-cell {
display: flex;
align-items: center;
}
.user-avatar,
.user-avatar-placeholder {
width: 36px;
height: 36px;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.user-avatar-placeholder {
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 18px;
}
.user-details {
display: flex;
flex-direction: column;
overflow: hidden;
}
.user-nickname {
font-weight: bold;
color: #303133;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-id {
font-size: 12px;
color: #909399;
}
</style>

View File

@@ -1,10 +1,10 @@
<template>
<div class="rating-topic-container">
<vab-query-form>
<vab-query-form-left-panel :span="12">
<vab-query-form-left-panel>
<el-button icon="el-icon-plus" type="primary" @click="handleAdd">创建话题</el-button>
</vab-query-form-left-panel>
<vab-query-form-right-panel :span="12">
<vab-query-form-left-panel>
<el-form :inline="true" :model="queryForm" @submit.native.prevent>
<el-form-item>
<el-select v-model="queryForm.status" clearable placeholder="请选择状态" @change="queryData">
@@ -21,7 +21,7 @@
<el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
</el-form-item>
</el-form>
</vab-query-form-right-panel>
</vab-query-form-left-panel>
</vab-query-form>
<el-table v-loading="listLoading" :data="list" :element-loading-text="elementLoadingText">
@@ -46,10 +46,10 @@
</template>
</el-table-column>
<el-table-column align="center" label="允许评论" width="100">
<el-table-column align="left" label="用户信息" min-width="200" width="300">
<template #default="{ row }">
<el-tag v-if="row.allowComment === 1 || row.allowComment === true" type="success"></el-tag>
<el-tag v-else type="danger"></el-tag>
<user-info v-if="row.user" :user="row.user" :user-id="row.userId" />
<span v-else>系统创建</span>
</template>
</el-table-column>
@@ -125,10 +125,11 @@
import { formatTime } from '@/utils'
import { getThumbUrl } from '@/utils/blessing'
import TopicEdit from './components/TopicEdit'
import UserInfo from '@/components/UserInfo'
export default {
name: 'RatingTopicIndex',
components: { TopicEdit },
components: { TopicEdit, UserInfo },
data() {
return {
list: [],
@@ -145,6 +146,9 @@
}
},
created() {
if (this.$route.query.topicId) {
this.queryForm.keyword = this.$route.query.topicId
}
this.fetchData()
},
methods: {

View File

@@ -130,26 +130,7 @@
<el-table-column align="left" label="用户信息" min-width="200">
<template #default="{ row }">
<div v-if="row.user" class="user-info-cell">
<el-image
v-if="row.user.avatar"
class="user-avatar"
:preview-src-list="[row.user.avatar]"
:src="getThumbUrl(row.user.avatar)"
/>
<div v-else class="user-avatar-placeholder"><i class="el-icon-user" /></div>
<div class="user-details">
<div class="user-nickname">
{{ row.user.nickname || '未知用户' }}
<el-tag v-if="row.user.isRobot" size="mini" style="margin-left: 4px" type="info">机器人</el-tag>
<el-tag v-else size="mini" style="margin-left: 4px" type="success">真人</el-tag>
</div>
<div class="user-id">{{ row.user.id }}</div>
</div>
</div>
<div v-else class="user-details">
<div class="user-id">{{ row.userId }}</div>
</div>
<user-info :user="row.user" :user-id="row.userId" />
</template>
</el-table-column>
@@ -182,12 +163,13 @@
import { getList as getItemList } from '@/api/rating/topicItem'
import { formatTime } from '@/utils'
import { getThumbUrl } from '@/utils/blessing'
import UserInfo from '@/components/UserInfo'
import RecordCommentEdit from './components/RecordCommentEdit'
import RecordCommentLikeEdit from './components/RecordCommentLikeEdit'
export default {
name: 'RatingTopicCommentIndex',
components: { RecordCommentEdit, RecordCommentLikeEdit },
components: { RecordCommentEdit, RecordCommentLikeEdit, UserInfo },
directives: {
loadmore: {
bind(el, binding) {
@@ -420,45 +402,6 @@
margin-right: 4px;
}
/* 用户信息列样式 */
.user-info-cell {
display: flex;
align-items: center;
}
.user-avatar,
.user-avatar-placeholder {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
flex-shrink: 0;
}
.user-avatar-placeholder {
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 20px;
}
.user-details {
display: flex;
flex-direction: column;
overflow: hidden;
}
.user-nickname {
font-weight: bold;
color: #303133;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-id {
font-size: 12px;
color: #909399;
}
/* 评价目标列样式 */
.target-info-cell {
display: flex;

View File

@@ -61,6 +61,13 @@
</template>
</el-table-column>
<el-table-column align="left" label="用户信息" min-width="200" width="300">
<template #default="{ row }">
<user-info v-if="row.user" :user="row.user" :user-id="row.userId" />
<span v-else>系统创建</span>
</template>
</el-table-column>
<el-table-column align="left" label="分数统计">
<template #default="{ row }">
<div class="stat-cell">
@@ -150,10 +157,11 @@
import { getThumbUrl } from '@/utils/blessing'
import TopicItemRatingEdit from './components/TopicItemRatingEdit'
import TopicItemCommentEdit from './components/TopicItemCommentEdit'
import UserInfo from '@/components/UserInfo'
export default {
name: 'RatingTopicItemIndex',
components: { TopicItemRatingEdit, TopicItemCommentEdit },
components: { TopicItemRatingEdit, TopicItemCommentEdit, UserInfo },
data() {
return {
list: [],

View File

@@ -9,7 +9,7 @@
<el-table v-loading="listLoading" :data="list" :element-loading-text="elementLoadingText">
<el-table-column align="left" label="推荐话题" min-width="220" width="220">
<template #default="{ row }">
<div class="topic-cell">
<div class="topic-cell" @click="handleClick(row.topic)">
<div class="topic-title">{{ row.topic ? row.topic.title : '-' }}</div>
<div class="topic-meta">
<span class="meta-label">Topic ID:</span>
@@ -91,6 +91,14 @@
this.queryForm.pageNo = val
this.fetchData()
},
handleClick(topic) {
this.$router.push({
path: '/rating/topic',
query: {
topicId: topic.id,
},
})
},
async fetchData() {
this.listLoading = true
try {
@@ -142,6 +150,7 @@
.topic-cell {
display: flex;
flex-direction: column;
cursor: pointer;
}
.topic-title {

View File

@@ -108,26 +108,7 @@
</el-table-column>
<el-table-column align="left" label="用户信息" min-width="200">
<template #default="{ row }">
<div v-if="row.user" class="user-info-cell">
<el-image
v-if="row.user.avatar"
class="user-avatar"
:preview-src-list="[row.user.avatar]"
:src="getThumbUrl(row.user.avatar)"
/>
<div v-else class="user-avatar-placeholder"><i class="el-icon-user" /></div>
<div class="user-details">
<div class="user-nickname">
{{ row.user.nickname || '未知用户' }}
<el-tag v-if="row.user.isRobot" size="mini" style="margin-left: 4px" type="info">机器人</el-tag>
<el-tag v-else size="mini" style="margin-left: 4px" type="success">真人</el-tag>
</div>
<div class="user-id">{{ row.user.id }}</div>
</div>
</div>
<div v-else class="user-details">
<div class="user-id">{{ row.userId }}</div>
</div>
<user-info :user="row.user" :user-id="row.userId" />
</template>
</el-table-column>
@@ -161,11 +142,12 @@
import { getList as getItemList } from '@/api/rating/topicItem'
import { formatTime } from '@/utils'
import { getThumbUrl } from '@/utils/blessing'
import UserInfo from '@/components/UserInfo'
import RecordRatingEdit from './components/RecordRatingEdit'
export default {
name: 'RatingTopicRecordIndex',
components: { RecordRatingEdit },
components: { RecordRatingEdit, UserInfo },
directives: {
loadmore: {
bind(el, binding) {
@@ -392,45 +374,6 @@
padding: 20px;
}
/* 用户信息列样式 */
.user-info-cell {
display: flex;
align-items: center;
}
.user-avatar,
.user-avatar-placeholder {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 12px;
flex-shrink: 0;
}
.user-avatar-placeholder {
background-color: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
font-size: 20px;
}
.user-details {
display: flex;
flex-direction: column;
overflow: hidden;
}
.user-nickname {
font-weight: bold;
color: #303133;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-id {
font-size: 12px;
color: #909399;
}
/* 评价目标列样式 */
.target-info-cell {
display: flex;