搜索结果列表页面开发

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,68 @@
# MemberAvatarList组件
### 说明
- 通用的用户头像列表组件demo如下
``` js
// template
<member-avatar-list :data="userAvatarList2" hideBottomMore more-icon='icon-op-list' type-icon="icon-homepage" :count="127" :isRound="true" :showHover="false" title="成员" :to-more="`/home`" />
// script
const userAvatarList2: Array<userAvatarListRow> = [
{
avatar: 'https://avatars.githubusercontent.com/u/40119767?v=4',
name: '曾恒瑶'
},
{
avatar: 'https://avatars.githubusercontent.com/u/40119767?v=4',
name: '曾恒瑶'
},
{
avatar: 'https://avatars.githubusercontent.com/u/40119767?v=4',
name: '曾恒瑶'
}
];
```
### Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | -------------------- | ------- | ----------------- | ------ |
| data | 头像列表 | array | 见下表 | [] |
| title | 标题 | string | — | — |
| toMore | 查看全部路由path | string | — | — |
| isRound | 是否圆形 | boolean | false则为圆角矩形 | true |
| showHover | 展示hover | boolean | — | false |
| hideNum | 隐藏标签数字 | boolean | — | false |
| hideBottomMore | 隐藏底部查看全部按钮 | boolean | — | false |
| hideRightMore | 隐藏右上角全部按钮 | boolean | — | false |
| type-icon | 标题前的类型图标 | string | — | — |
| more-icon | 更多按钮图标 | string | — | — |
| count | 成员数 | number | | 0 |
### Props(data)
注意有头像src优先会显示没有src则显示name若设置了customText则优先显示自定义的文案
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|----------------|-------------------------|-------------------------------|-----------|-------|
| avatar | 头像src | string | — | — |
| name | 用户名 | string | — | — |
| customText | 自定义文案 | string | — | — |
### Emits
注意:以下事件都是组件内部对应的按钮点击触发,如果用插槽自定义对应区域的内容的话,事件自行监听即可
| 方法 | 说明 | 返回值 |
|-----------|--------|-----------------------|
| handleMore | 点击更多触发 | |
### Slots
| 名称 | 说明 |
|--------------------|-------------------------------|
| title | |
| content | |
| more | |
| bottomMore | |

View File

@@ -0,0 +1,168 @@
<template>
<div class="g-member-avatar">
<d-row justify="between" v-if="!hideTop">
<d-col class="flex">
<slot name="title">
<Icon class="g-member-avatar-icon" :name="typeIcon"></Icon>
<div class="g-member-avatar-title ml-2 text-G900 text-sm">{{ title }}</div>
<span class="g-member-avatar-num ml-2 text-CG600 " v-if="!hideNum">{{ count }}</span>
</slot>
</d-col>
<d-col v-if="!hideRightMore && data.length" @click="emits('handleMore')">
<slot name="more">
<router-link :to="toMore">
<Icon :name="moreIcon" color="#707A8"></Icon>
</router-link>
</slot>
</d-col>
</d-row>
<div class="g-member-avatar-list">
<slot name="content">
<template v-for="(item, index) in userData.slice(0, 25)" :key="index">
<d-tooltip :content="item.name" :disabled="!showHover">
<GAvatar class="mb-2" :class="{ 'g-member-avatar-list-rounded': !isRound }"
:name="item.name" :is_round="isRound"
:src="item.avatar"></GAvatar>
</d-tooltip>
</template>
<!-- <template v-if="showBlank">
<template v-for="(item, index) in (25 - userData.slice(0, 25).length)" :key="index">
<div class="g-member-avatar-list-empty mb-2" :class="{ 'g-member-avatar-list-rounded': !isRound }"></div>
</template>
</template> -->
</slot>
</div>
<router-link :to="toMore" v-if="!hideBottomMore && data.length">
<div class="g-member-avatar-more" @click="emits('handleMore')">
<slot name="bottomMore">
查看全部{{ title }}
</slot>
</div>
</router-link>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
interface userAvatarListRow {
username:string;
iam_id:string;
name?: string;
avatar?:string;
avatar_url?:string;
}
const props = withDefaults(defineProps<{
data?: Array<userAvatarListRow>;
title?: string;
hideNum?: boolean;
count?: number;
hideTop?: boolean;
hideRightMore?: boolean;
hideBottomMore?: boolean;
toMore?: string
isRound?: boolean
showHover: boolean
moreIcon?: string
typeIcon?: string
showBlank?: boolean
}>(), {
data: () => [],
title: '组织成员',
toMore: '',
hideNum: false,
count: 0,
hideTop: false,
hideRightMore: false,
hideBottomMore: false,
isRound: true,
showHover: false,
moreIcon: 'gt-all',
typeIcon: 'gt-organizations-c',
showBlank: true
});
const emits = defineEmits(['handleMore']);
const userData = ref<userAvatarListRow[]>([]);
watch(() => props.data, (val) => {
init();
}, {
deep: true
});
const init = async() => {
userData.value = JSON.parse(JSON.stringify(props.data || []));
// for (let [i, len] = [0, data.length]; i < len; i++) {
// const item = data[i];
// if (!item.avatar) {
// item.noAvatar = true;
// break;
// // return false;
// }
// try {
// await fetch(item.avatar);
// } catch {
// item.noAvatar = true;
// }
// }
// userData.value = data;
};
init();
</script>
<style scoped lang="scss">
$g-member-avatar-border-color: rgba(0, 0, 0, 0.1);
.g-member-avatar {
width: 100%;
&-icon {
margin-top: 2px;
}
&-list {
display: flex;
align-items: center;
margin-top: 12px;
flex-wrap: wrap;
&-empty {
width: 32px;
height: 32px;
background: #FFFFFF;
border: 1px solid $g-member-avatar-border-color;
border-radius: 50%;
z-index: -1;
margin-right: -4px;
}
&-round {
border-radius: 50%;
}
:deep(.devui-avatar) {
margin-right: -4px;
img {
object-fit: cover;
}
}
&-rounded {
border-radius: 4px !important;
:deep(img) {
border-radius: 4px !important;
}
}
}
:deep(.devui-icon__container) {
vertical-align: middle;
}
&-more {
margin-top: 8px;
}
}
</style>