搜索结果列表页面开发

This commit is contained in:
付民康
2025-03-12 18:41:20 +08:00
commit 7cebe8fc00
739 changed files with 88149 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
### Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|-------------|-------------------|----------------|-------------------------------- |-------|
| data | 用户信息数据 | FollowUserData | — | {} |
| loading? | 该数据是否在处理中 | boolean | — | false |
| showButton? | 是否显示操作按钮 | boolean | — | true |
| isFirst? | 是否为第一条数据(用于控制样式) | boolean | — | false |
| isLast? | 是否为最后一条数据(用于控制样式) | boolean | — | false |
### Emits
| 方法 | 说明 | 返回值 |
|-----------|---------|---------------|
| starred | 关注/取消关注 | data: boolean |
### Slots
| 名称 | 说明 |
|-------------|--------------|
| avatar | 组件头像区域插槽 |
| title | 组件标题区域插槽 |
| description | 组件描述区域插槽 |
| others | 组件底部其他信息区域插槽 |
| action | 组件操作区域插槽 |

View File

@@ -0,0 +1,181 @@
<template>
<div class="g-user-item" :class="{ 'is-last': isLast, 'is-first': isFirst }">
<div class="g-user-item-avatar flex items-center">
<slot name="avatar">
<a :href="`/${data.username}`" target="_blank">
<GAvatar
:src="data.avatar"
:name="data.nickname"
:is_round="data.round"
/>
</a>
</slot>
</div>
<div class="g-user-item-info">
<div class="g-user-item-title">
<slot name="title" :data="data">
<a :href="`/${data.username}`" target="_blank">
<span class="g-user-item-name" v-html="highlightWords(keywords,data.nickname)"></span>
</a>
<span class="g-user-item-username" v-html="highlightWords(keywords,`@${data.username}`)"></span>
</slot>
</div>
<div class="g-user-item-description">
<slot name="description" :data="data">
<g-text :config="{ ellipse: true, line: 2, tooltip: true }">
{{ data.description || '-' }}
</g-text>
</slot>
</div>
<div class="g-user-item-others">
<slot name="others" :data="data">
<div v-if="data.org" class="g-user-item-icon-text">
<Icon name="gt-organizations" size="16px" />
<a :href="data.website" target="_blank">
<span class="g-user-item-text">@<g-text style="max-width: 200px">{{ data.org }}</g-text></span>
</a>
</div>
<div class="g-user-item-icon-text" v-if="data.location">
<Icon name="gt-location" size="16px" color="#9FA7B3" />
<span class="g-user-item-text"><g-text style="max-width: 200px">{{ data.location || '未知' }}</g-text></span>
</div>
</slot>
</div>
</div>
<div v-if="showButton" class="g-user-item-actions">
<slot name="action">
<d-button
v-if="data.hasStarred"
color="secondary"
:loading="loading"
class="g-user-item-action"
@click="emits('starred', false)"
>
取消关注
</d-button>
<d-button v-else :loading="loading" color="secondary" class="g-user-item-action" @click="emits('starred', true)">关注</d-button>
</slot>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'user-item'
};
</script>
<script setup lang="ts">
import { highlightWords } from '@/utils';
type FollowUserData = {
id: string;
avatar?: string;
nickname?: string;
username: string;
description?: string;
location?: string;
org?: string;
round?: boolean;
loading?: boolean;
hasStarred?: boolean;
website?: string;
}
withDefaults(defineProps<{
data: FollowUserData;
loading?: boolean;
showButton?: boolean;
isFirst?: boolean;
isLast?: boolean;
keywords?: string
}>(), {
data: () => ({
id: '',
location: '-',
round: false,
nickname: '',
username: '',
hasStarred: false
}),
loading: false,
showButton: true,
isFirst: false,
isLast: false,
keywords: ''
});
const emits = defineEmits<{(e: 'starred', data: boolean): void
}>();
</script>
<style scoped lang="scss">
$g-user-item-color: var(--color-G900);
$g-user-item-color-second: var(--color-G700);
$g-user-item-color-third: #606060;
$g-user-item-border-color: var(--color-G200);
$g-user-item-border-radius: 4px;
.g-user-item {
display: flex;
border-bottom: 1px solid $g-user-item-border-color;
padding: 16px 20px;
// border-bottom: none;
&.is-first {
border-top-left-radius: $g-user-item-border-radius;
border-top-right-radius: $g-user-item-border-radius;
}
&.is-last {
border-bottom-left-radius: $g-user-item-border-radius;
border-bottom-right-radius: $g-user-item-border-radius;
border-bottom: none;
}
&-info {
padding: 0 24px;
flex: 1;
}
&-title {
margin-bottom: 8px;
display: flex;
align-items: center;
line-height: 1;
}
&-name {
color: $g-user-item-color;
font-size: 14px;
font-weight: 500;
line-height: 20px;
margin-right: 8px;
}
&-username {
color: $g-user-item-color-second;
font-size: 14px;
line-height: 20px;
}
&-description {
color: $g-user-item-color-second;
font-size: 14px;
margin-bottom: 8px;
line-height: 20px;
}
&-others {
display: flex;
align-items: center;
}
&-icon-text {
display: flex;
align-items: center;
margin-right: 24px;
line-height: 1;
}
&-text {
margin-left: 8px;
color: $g-user-item-color-second;
font-size: 14px;
line-height: 20px;
display: flex;
align-items: center;
}
&-action {
padding: 6px 12px;
}
}
</style>