321 lines
9.4 KiB
Vue
321 lines
9.4 KiB
Vue
<template>
|
|
<section class="g-release-card">
|
|
<div v-if="!simple" class="g-release-card-header">
|
|
<slot name="header">
|
|
<div class="g-release-card-base-info flex-wrap">
|
|
<div class="g-release-card-title inline-block truncate ellipsis-pre">
|
|
<slot name="title">{{ data.title || data.version }}</slot>
|
|
</div>
|
|
<div class="g-release-card-info">
|
|
<slot name="info">
|
|
<div class="g-release-card-avatar">
|
|
<slot name="avatar">
|
|
<user-avatar size="16" :user-info="data.userInfo" />
|
|
</slot>
|
|
</div>
|
|
<div class="g-release-card-created-time">
|
|
<slot name="created-time">
|
|
于 {{ formatTimeFromNow(data.createdTime) }}创建
|
|
</slot>
|
|
</div>
|
|
<div class="g-release-card-tag">
|
|
<slot name="tag">
|
|
<d-icon name="tag" size="20px"></d-icon>
|
|
<span>{{ data.tag }}</span>
|
|
</slot>
|
|
</div>
|
|
<div class="g-release-card-commit">
|
|
<slot name="commit">
|
|
<d-icon name="commit" size="20px"></d-icon>
|
|
<span>{{ data.commit }}</span>
|
|
</slot>
|
|
</div>
|
|
<slot name="validated">
|
|
<custom-tag border-color="#333" color="#333">
|
|
{{ data.validated ? '已验证' : '未验证' }}
|
|
</custom-tag>
|
|
</slot>
|
|
</slot>
|
|
<slot name="info-extra"></slot>
|
|
</div>
|
|
</div>
|
|
<div class="g-release-card-actions">
|
|
<slot name="actions">
|
|
<div class="g-release-card-action">
|
|
<d-button variant="text" @click="emits('compare', data)">
|
|
<div class="g-release-card-custom-btn">
|
|
<d-icon name="tag" size="16px"></d-icon>
|
|
<span>对比 Tag</span>
|
|
</div>
|
|
</d-button>
|
|
</div>
|
|
<div class="g-release-card-action">
|
|
<d-button variant="text" @click="emits('edit', data)">
|
|
<d-icon name="edit" size="16px"></d-icon>
|
|
</d-button>
|
|
</div>
|
|
<div class="g-release-card-action">
|
|
<d-button variant="text" @click="emits('delete', data)">
|
|
<d-icon name="delete" size="16px"></d-icon>
|
|
</d-button>
|
|
</div>
|
|
</slot>
|
|
</div>
|
|
</slot>
|
|
<div class="g-release-card-header-divide" />
|
|
</div>
|
|
<div class="g-release-card-detail-info ellipsis-pre">
|
|
<div v-if="simple" class="g-release-card-detail-header">
|
|
<slot name="header">
|
|
<div class="g-release-card-title">
|
|
<slot name="title">{{ data.title || data.version }}</slot>
|
|
</div>
|
|
<div class="g-release-card-actions">
|
|
<slot name="actions">
|
|
<div class="g-release-card-action">
|
|
<d-button variant="text" @click="emits('edit', data)">
|
|
<d-icon name="edit" size="16px"></d-icon>
|
|
</d-button>
|
|
</div>
|
|
<div class="g-release-card-action">
|
|
<d-button variant="text" @click="emits('delete', data)">
|
|
<d-icon name="delete" size="16px"></d-icon>
|
|
</d-button>
|
|
</div>
|
|
</slot>
|
|
</div>
|
|
</slot>
|
|
</div>
|
|
<slot name="detail">{{ data.message }}</slot>
|
|
</div>
|
|
<div class="g-release-card-attachments">
|
|
<div class="g-release-card-attachments-header pl-[6px] pt-[6px] pb-[6px]">
|
|
<!-- <d-icon
|
|
:name="open ? 'chevron-down' : 'chevron-up'"
|
|
size="20px"
|
|
/> -->
|
|
<slot name="attachments-header">
|
|
<span class="g-release-card-attachments-title">下载</span>
|
|
<!-- <custom-tag border-color="transparent" bg-color="#EAEAEA" color="#606060">
|
|
{{ data.attachments?.length || 0 }}
|
|
</custom-tag> -->
|
|
</slot>
|
|
</div>
|
|
<div v-show="open" class="g-release-card-attachments-content">
|
|
<slot name="attachments-content">
|
|
<template v-if="data.attachments && data.attachments.length">
|
|
<div
|
|
v-for="(item, index) in data.attachments"
|
|
:key="`${item.id}_${index}`"
|
|
class="g-release-card-attachment pt-[6px] pb-[6px]"
|
|
>
|
|
<slot name="attachment" :data="item" :index="index">
|
|
<div class="g-release-card-attachment-name pl-[6px]">
|
|
<a :href="item.link ?? 'javascript:void(0);'" class="g-release-card-attachment-name">
|
|
<slot name="attachment-name" :data="item" :index="index">
|
|
<Icon name="gt-file-zip-c" size="14px" />
|
|
<span class="text-[#2562C4] font-semibold">{{ item.filename }}</span>
|
|
</slot>
|
|
</a>
|
|
</div>
|
|
<div class="g-release-card-attachment-size">
|
|
<slot name="attachment-size" :data="item" :index="index">
|
|
{{ item.size }}
|
|
</slot>
|
|
</div>
|
|
<div class="g-release-card-attachment-time">
|
|
<slot name="attachment-time" :data="item" :index="index">
|
|
{{ formatTimeFromNow(item.updatedTime) }}
|
|
</slot>
|
|
</div>
|
|
</slot>
|
|
</div>
|
|
</template>
|
|
<div v-else class="g-release-card-empty">暂无附件数据</div>
|
|
</slot>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
export default {
|
|
name: 'release-card'
|
|
};
|
|
</script>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import type { ReleaseCardData } from '@/components/ReleaseCard/types';
|
|
import UserAvatar from '@/components/UserAvatar/index.vue';
|
|
import { useTimeFormat } from '@/utils/hooks/useTimeFormat';
|
|
import CustomTag from '@/components/CustomTag/index.vue';
|
|
|
|
withDefaults(defineProps<{
|
|
data: ReleaseCardData;
|
|
simple?: boolean;
|
|
}>(), {
|
|
data: () => ({
|
|
version: '',
|
|
title: '',
|
|
userInfo: {
|
|
imgSrc: ''
|
|
},
|
|
createdTime: '',
|
|
commit: '',
|
|
tag: ''
|
|
}),
|
|
simple: false
|
|
});
|
|
const emits = defineEmits<{(e: 'compare', data: ReleaseCardData): void;
|
|
(e: 'edit', data: ReleaseCardData): void;
|
|
(e: 'delete', data: ReleaseCardData): void;
|
|
}>();
|
|
|
|
const { formatTimeFromNow } = useTimeFormat();
|
|
|
|
const open = ref<boolean>(true);
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
$g-release-card-border-color: #e5e4e4;
|
|
$g-release-card-bg-color: #F5F7F9;
|
|
$g-release-card-border-radius: 4px;
|
|
$g-release-card-color: #000000;
|
|
$g-release-card-color-second: #606060;
|
|
.g-release-card {
|
|
border-radius: $g-release-card-border-radius;
|
|
&-header {
|
|
position: relative;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
&-divide {
|
|
position: absolute;
|
|
// left: 20px;
|
|
width: 100%;
|
|
height: 1px;
|
|
bottom: 0;
|
|
background-color: $g-release-card-border-color;
|
|
}
|
|
}
|
|
&-title {
|
|
font-size: 36px;
|
|
font-weight: 500;
|
|
color: $g-release-card-color;
|
|
}
|
|
&-info {
|
|
margin-top: 16px;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
&-created-time {
|
|
margin-left: 8px;
|
|
color: $g-release-card-color-second;
|
|
}
|
|
&-tag, &-commit {
|
|
margin-left: 20px;
|
|
color: $g-release-card-color-second;
|
|
display: flex;
|
|
align-items: center;
|
|
> span {
|
|
margin-left: 8px;
|
|
}
|
|
}
|
|
&-commit {
|
|
margin-right: 8px;
|
|
}
|
|
&-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
&-action {
|
|
padding: 8px;
|
|
border: 1px solid $g-release-card-border-color;
|
|
border-radius: $g-release-card-border-radius;
|
|
line-height: 1;
|
|
margin-left: 16px;
|
|
:deep(.button-content) {
|
|
line-height: 10px;
|
|
}
|
|
&:hover {
|
|
cursor: pointer;
|
|
background-color: $g-release-card-bg-color;
|
|
}
|
|
&:active {
|
|
background-color: #f2f4f6;
|
|
}
|
|
}
|
|
&-custom-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
> span {
|
|
margin-left: 8px;
|
|
}
|
|
}
|
|
&-detail-info {
|
|
padding: 24px 16px 32px 0;
|
|
// border-bottom: 1px solid $g-release-card-border-color;
|
|
}
|
|
&-detail-header {
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 20px;
|
|
}
|
|
&-attachments {
|
|
// padding: 16px;
|
|
border: 1px solid #F0F1F2;
|
|
&-header {
|
|
display: flex;
|
|
align-items: center;
|
|
// margin-bottom: 16px;
|
|
background: #FBFBFB;
|
|
&:hover {
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
&-title {
|
|
// padding: 0 8px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: $g-release-card-color;
|
|
}
|
|
&-content {
|
|
// border: 1px solid $g-release-card-border-color;
|
|
border-radius: $g-release-card-border-radius;
|
|
}
|
|
}
|
|
&-attachment {
|
|
display: flex;
|
|
align-items: center;
|
|
border-top: 1px solid $g-release-card-border-color;
|
|
font-size: 14px;
|
|
color: $g-release-card-color-second;
|
|
&-name {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
> span {
|
|
padding-left: 8px;
|
|
display: inline-block;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
&-size, &-time {
|
|
min-width: 84px;
|
|
padding: 0 8px;
|
|
}
|
|
&-time {
|
|
text-align: right;
|
|
}
|
|
}
|
|
&-empty {
|
|
padding: 32px;
|
|
font-size: 24px;
|
|
text-align: center;
|
|
}
|
|
}
|
|
</style>
|