搜索结果列表页面开发

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,38 @@
TS接口文档可以查看同文件夹下的types.ts, demo可以访问/demo777进行查看
### Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|----------------|-------------------------|-------------------------------|-----------|-------|
| data | 人员列表数据 | Array<MemberItemData> | — | [] |
| size? | 头像尺寸 | number | — | 48 |
| round? | 是否为圆形头像 | boolean | — | true |
| statusOptions? | 用户身份下拉数据项 | {label: string; value: string | number}[] | — | [] |
| isHandling? | 是否处于事务处理中设为true会禁用右边操作 | boolean | — | false |
| isManager? | 当前用户是否为管理员 | boolean | — | false |
| showTags? | 是否显示身份标签 | boolean | — | true |
### Emits
注意:以下事件都是组件内部对应的按钮点击触发,如果用插槽自定义对应区域的内容的话,事件自行监听即可
| 方法 | 说明 | 返回值 |
|-----------|--------|-----------------------|
| cancelInvited | 取消邀请 | { data: MemberItemData; index: number } |
| exitProject | 退出项目 | { data: MemberItemData; index: number } |
| removeMember | 移除成员 | { data: MemberItemData; index: number } |
| applyPass | 通过申请 | { data: MemberItemData; index: number } |
| applyRefuse | 拒绝申请 | { data: MemberItemData; index: number } |
| statusChange | 成员身份变化 | { data: MemberItemData; index: number } |
### Slots
| 名称 | 说明 |
|--------------------|-------------------------------|
| avatar | 组件头像区域插槽 |
| name | 组件名称区域插槽 |
| tags | 组件标签区域插槽 |
| extra-tags | 组件额外标签区域插槽,在只对当前组件标签进行拓展时可以使用 |
| status | 组件成员身份选择区域插槽 |
| action | 组件动作区域插槽 |
| extra-action | 组件额外动作区域插槽,在只对当前组件标签进行拓展时可以使用 |

View File

@@ -0,0 +1,343 @@
<template>
<section class="g-member-items">
<div
v-for="(item, index) in data"
:key="index"
class="g-member-items-item g-border-bottom"
:class="{ 'is-last-item': index === data.length - 1 }"
>
<div class="g-member-items-item-info">
<div class="g-member-items-item-avatar">
<slot name="avatar" :data="item" :index="index">
<router-link :to="item.path">
<GAvatar
:src="item.imageSrc"
:name="item.nickname"
:width="size"
:height="size"
:is_round="round"
></GAvatar>
</router-link>
</slot>
</div>
<div class="g-member-items-item-names w-[280px]">
<slot name="name" :data="item" :index="index">
<router-link :to="item.path">
<div class="g-member-items-item-nickname flex items-center">
<GText class="devui-link-hover">{{ xssPurify(item.nickname) }}</GText>
<custom-tag
v-if="item.isSelf"
class="g-member-items-item-tag shrink-0 ml-2"
color="#9FA7B3"
border-color="#E4E9F0"
bg-color="#ffffff"
>
自己
</custom-tag>
</div>
<div class="g-member-items-item-userName devui-link-hover ellipsis">@{{ item.userName }}</div>
</router-link>
</slot>
</div>
<div v-if="showTags" class="g-member-items-item-tags shrink-0 ml-2">
<slot name="tags" :data="item" :index="index">
<custom-tag v-if="item.isToBeInvited" class="g-member-items-item-tag">
待接受邀请
</custom-tag>
<custom-tag
v-if="item.isManager"
class="g-member-items-item-tag"
color="#2865E0"
border-color="#E4E9F0">
管理者
</custom-tag>
<custom-tag
v-if="item.isVisitor && (item.join_way === 'inherit' || !(isManager && isAdmin) )"
class="g-member-items-item-tag"
color="#0EB07B"
border-color="#E4E9F0">
浏览者
</custom-tag>
<custom-tag
v-if="item.isDeveloper && (item.join_way === 'inherit' || !(isManager && isAdmin) )"
class="g-member-items-item-tag"
color="#707A87"
border-color="#E4E9F0">
开发者
</custom-tag>
</slot>
<!--用户额外补充标志-->
<slot name="extra-tags" :data="item" :index="index"></slot>
</div>
</div>
<div class="g-member-items-item-actions" v-if="item.join_way !== 'inherit'">
<slot v-if="isManager && !item.isSelf && isAdmin" name="status" :data="item" :index="index">
<div class="g-member-items-item-status">
<d-select
class="g-member-items-item-status-select g-member-items-item-remove-member"
v-model="item.status"
:options="item.type === 'GroupMember' ? item?.statusOptions || statusOptions : item?.statusOptions || statusOptions.slice(1)"
:disabled="(item.disabledOption || isHandling) || !isAdmin"
size="sm"
placeholder="身份"
@value-change="emits('statusChange', { data: item, index })"
>
</d-select>
</div>
</slot>
<slot v-if="(isManager) || item.isSelf" name="action" :data="item" :index="index">
<div class="g-member-items-item-action">
<d-button
v-if="item.isToBeInvited && isManager"
icon="close"
variant="text"
:loading="isHandling"
class="g-member-items-item-cancel"
@click="emits('cancelInvited', { data: item, index })"
>
撤销邀请
</d-button>
<d-button
v-if="item.isSelf && item.allowedExit"
icon="exit"
variant="text"
:loading="isHandling"
class="g-member-items-item-cancel"
@click="emits('exitProject', { data: item, index })"
>
退出{{ item.type === 'GroupMember' ? '组织': '项目' }}
</d-button>
<d-button
v-if="isManager && !item.isToBeInvited && !item.isSelf && !item.isApplying && isAdmin"
icon="remove-member-icon"
variant="solid"
color="secondary"
:loading="isHandling"
class="g-member-items-item-remove-member"
@click="emits('removeMember', { data: item, index })"
>
移除成员
</d-button>
<template v-if="item.isApplying">
<d-button
icon="add"
variant="text"
:loading="isHandling"
class="g-member-items-item-pass"
@click="emits('applyPass', { data: item, index })"
>
通过申请
</d-button>
<d-button
icon="close"
variant="solid"
:loading="isHandling"
class="g-member-items-item-refuse"
@click="emits('applyRefuse', { data: item, index })"
>
拒绝申请
</d-button>
</template>
</div>
</slot>
<slot name="extra-action" :data="item" :index="index"></slot>
</div>
<d-tooltip position="top" v-else :content="'该成员权限继承自组织,请前往组织管理中调整该组织成员权限'">
<div><span class="mr-1">组织成员</span><Icon name="gt-tooltip"/></div>
</d-tooltip>
</div>
</section>
</template>
<script lang="ts">
export default {
name: 'member-items'
};
</script>
<script lang="ts" setup>
import type { MemberItemData } from '@/components/MemberItems/types';
import CustomTag from '@/components/CustomTag/index.vue';
import { xssPurify } from '@/utils';
withDefaults(defineProps<{
data: MemberItemData[];
// 头像尺寸
size?: number;
// 是否显示圆形头像
round?: boolean;
// 用户身份下拉数据
statusOptions?: { name: string; value: string | number }[];
// 是否处于事务处理中设为true会禁用右边操作
isHandling?: boolean;
// 当前用户是否为管理员
isManager?: boolean;
// 是否显示标签
showTags?: boolean;
// 是否是管理者权限
isAdmin?: boolean
}>(), {
data: () => [],
size: 48,
round: true,
statusOptions: () => [
{ /** 个人不允许设置为管理员 */
name: '管理员',
value: '50'
},
{
name: '开发者',
value: '30'
},
{
name: '浏览者',
value: '10'
}
],
isHandling: false,
isManager: false,
showTags: true,
isAdmin: true
});
const emits = defineEmits<{(e: 'cancelInvited', data: { data: MemberItemData; index: number }): void;
(e: 'exitProject', data: { data: MemberItemData; index: number }): void;
(e: 'removeMember', data: { data: MemberItemData; index: number }): void;
(e: 'applyPass', data: { data: MemberItemData; index: number }): void;
(e: 'applyRefuse', data: { data: MemberItemData; index: number }): void;
(e: 'statusChange', data: { data: MemberItemData; index: number }): void;
}>();
</script>
<style scoped lang="scss">
$g-member-items-border-radius: 4px;
$g-member-items-text-color: #2D2D2E;
$g-member-items-text-color-second: #707A87;
$g-member-items-text-color-third: #606060;
$g-member-items-tag-border-color: #D3D3D3;
$g-member-items-tag-bg-color: #F5F7F9;
.g-member-items {
&-item {
padding: 14px 20px;
display: flex;
justify-content: space-between;
align-items: center;
&.is-last-item {
border-bottom: none;
}
&-info {
display: flex;
align-items: center;
justify-items: space-between;
// width: 50%;
}
&-avatar {
:deep(.devui-avatar) {
display: block;
img {
display: block;
}
}
:deep(.devui-avatar--style) {
vertical-align: middle;
}
}
&-names {
margin-left: 20px;
margin-top: -3px;
}
&-nickname {
color: $g-member-items-text-color;
font-size: 16px;
font-weight: 500;
line-height: normal;
}
&-userName {
color: $g-member-items-text-color-second;
font-size: 14px;
font-weight: 400;
line-height: normal;
margin-top: 8px;
}
&-tags {
margin-left: 120px;
display: flex;
align-items: center;
}
&-tag {
// padding: 6px 12px;
}
&-actions {
display: flex;
align-items: center;
:deep(.devui-button--text) {
padding: 4px 10px;
}
}
&-cancel {
:deep(.devui-button__icon-fix) {
color: #FF3241 !important;
}
}
&-pass {
:deep(.devui-button__icon-fix) {
color: #0EB07B !important;
}
}
&-status {
&-select {
:deep(.devui-select__selection) {
border: none;
background: transparent;
font-size: 14px;
}
:deep(.devui-select__input) {
color: $g-member-items-text-color-third;
}
:deep(.devui-select__input) {
padding: 0;
}
}
}
&-action {
margin-left: 16px;
}
&-refuse {
margin-left: 16px;
color: #FF3241;
background-color: $g-member-items-tag-bg-color;
border: 1px solid $g-member-items-tag-border-color;
border-radius: $g-member-items-border-radius;
padding: 4px 10px;
&:hover {
opacity: 0.8;
}
&:active {
opacity: 0.6;
}
:deep(i) {
color: #FF3241;
}
}
&-remove-member {
color: $g-member-items-text-color-third;
background-color: $g-member-items-tag-bg-color;
border: 1px solid $g-member-items-tag-border-color;
border-radius: $g-member-items-border-radius;
padding: 4px 10px;
width: 100px;
// &:hover {
// opacity: 0.8;
// }
&:active {
opacity: 0.6;
}
:deep(i) {
color: $g-member-items-text-color-third;
}
}
}
}
</style>

View File

@@ -0,0 +1,28 @@
// 传入的成员列表数据
export type MemberItemData = {
// 头像图片
imageSrc?: null | string;
// 用户昵称
nickname: string;
// 个人中心访问路径
path: string;
// 用户名
userName: string;
// 是否为本人
isSelf?: boolean;
// 是否为管理员
isManager?: boolean;
// 是否为被邀请人员
isToBeInvited?: boolean;
// 用户身份
status: string | number;
// 是否为申请中
isApplying?: boolean;
// 是否允许退出项目 个人项目本人不允许退出 组织项目最后一个管理员不允许退出
allowedExit?: boolean;
// 禁用option修改权限
disabledOption?: boolean;
// 权限下拉列表 用于组织成员设置管理员权限
statusOptions?: { name: string, value: string }[]
[propName: string]: any;
}