feat: AI建议 & 许可证页面

This commit is contained in:
@user8949
2025-03-14 20:03:14 +08:00
parent 154a03dcf0
commit 03db951292
14 changed files with 786 additions and 89 deletions

View File

@@ -0,0 +1,104 @@
<template>
<div>
<slot name="header"></slot>
</div>
<Transition
name="collapse-transition"
@beforeEnter="beforeEnter"
@enter="enter"
@afterEnter="afterEnter"
@beforeLeave="beforeLeave"
@leave="leave"
@afterLeave="afterLeave"
>
<div v-if="props.expand">
<slot name="body"></slot>
</div>
</Transition>
</template>
<script setup lang="ts">
import { ref, defineProps, type RendererElement } from 'vue';
const props = defineProps({
expand: {
type: Boolean,
required: true
},
});
const beforeEnter = (el: RendererElement) => {
if (!el.dataset) {
el.dataset = {};
}
if (el.style.height) {
el.dataset.height = el.style.height;
}
el.style.maxHeight = 0;
};
const enter = (el: RendererElement) => {
requestAnimationFrame(() => {
el.dataset.oldOverflow = el.style.overflow;
if (el.dataset.height) {
el.style.maxHeight = el.dataset.height;
} else if (el.scrollHeight !== 0) {
el.style.maxHeight = `${el.scrollHeight}px`;
} else {
el.style.maxHeight = 0;
}
el.style.overflow = 'hidden';
});
};
const afterEnter = (el: RendererElement) => {
el.style.maxHeight = '';
el.style.overflow = el.dataset.oldOverflow;
};
const beforeLeave = (el: RendererElement) => {
if (!el.dataset) {
el.dataset = {};
}
el.dataset.oldOverflow = el.style.overflow;
el.style.maxHeight = `${el.scrollHeight}px`;
el.style.overflow = 'hidden';
};
const leave = (el: RendererElement) => {
if (el.scrollHeight !== 0) {
el.style.maxHeight = 0;
}
};
const afterLeave = (el: RendererElement) => {
el.style.maxHeight = '';
el.style.overflow = el.dataset.oldOverflow;
};
</script>
<style scoped lang="scss">
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.collapse-transition {
&-enter-from,
&-leave-to {
opacity: 0;
}
&-enter-to,
&-leave-from {
opacity: 1;
}
&-enter-active,
&-leave-active {
transition:
max-height 0.3s cubic-bezier(0.5, 0.05, 0.5, 0.95),
opacity 0.3s cubic-bezier(0.5, 0.05, 0.5, 0.95);
}
}
</style>

View File

@@ -0,0 +1,46 @@
<template>
<d-table :data="dataSource" @sort-change="handleSortChange" :header-bg="true">
<d-column v-for="(column, index) in props.tableConfig" :field="column.field"
:header="column.header" :sortable="column.sortable" :sort-method="column.sortMethod"></d-column>
</d-table>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue';
export default defineComponent({
props: {
tableConfig: {
type: Array,
default: () => [],
},
dataSource: {
type: Array,
default: () => [],
},
},
setup(props) {
onMounted(() => {
console.log('props', props);
});
const handleSortChange = ({ field, direction }) => {
console.log('field', field);
console.log('direction', direction);
};
const sortDateMethod = (a, b) => {
return a.date > b.date;
};
const sortNameMethod = (a, b) => {
return a.lastName > b.lastName;
};
return { props, handleSortChange, sortDateMethod, sortNameMethod };
},
});
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,9 +1,9 @@
<template>
<div class="full-w" :style="{ height: `${height}px` }">
<div class="g-header fixed z-20" ref="headerRef">
<div class="g-header fixed z-20" ref="headerRef" :class="{'home-background': isHome, 'normal-background': !isHome}">
<div class="g-toolbar w-full overflow-hidden" :class="[searchClass, route?.meta?.headerClassName]">
<div class="g-toolbar-left flex-shrink items-center">
<div class="flex-center gap-[16px]">
<div class="flex-center gap-[16px]" v-if="!isHome">
<!-- <g-icon v-if="!asideSetShow" @click="$emit('clickMenu')" name="gt-hamburger" size="20px" class="cursor-pointer hover:!text-black" color="#1D1F3A"></g-icon>-->
<GLink class="g-toolbar-left-logo" :href="baseUrl" />
<GLink class="g-toolbar-left-title" :href="baseUrl">可信代码库</GLink>
@@ -11,7 +11,7 @@
<!-- <Entrance v-if="isLogin" :is-mobile="isMobile" /> -->
</div>
</div>
<div class="flex-1 flex items-center justify-end">
<div class="flex-1 flex items-center justify-end" v-if="!isHome">
<Search class="g-toolbar-left-search" v-if="!isMobile" :key="$route.fullPath"/>
</div>
<div class="g-toolbar-right gap-[12px] flex-grow-0 flex-shrink-0">
@@ -101,6 +101,7 @@ const { height = 56 } = useElementSize(headerRef);
const userInfo = useAccountStore();
const { isLogin } = storeToRefs(userInfo);
const showSearch = computed(() => route.name !== 'home' && route.name !== 'search');
const isHome = computed(() => route.name === 'home');
const handleLogin = (type) => {
emitEvent('login', { type, triggerType: '主动注册' });
};
@@ -139,7 +140,12 @@ $header-bg: #fff;
flex-direction: column;
align-items: stretch;
justify-content: space-between;
background-color: $header-bg;
.home-background {
background-color: #fff0;
}
.normal-background {
background-color: $header-bg;
}
:deep(.g-link) {
color: $devui-text-weak;
}

View File

@@ -0,0 +1,137 @@
<template>
<d-layout class="dlayout">
<d-header class="dheader">
<div class="title">
<h1>Apache License 2.0</h1>
<d-icon style="cursor: pointer;" name="icon-close" @click="emit('close')"></d-icon>
</div>
<div class="sub-title">
<span>分数</span>
<span>3</span>
<span>类型</span>
<d-tag color="#3ac295" size="sm">获准的</d-tag>
</div>
</d-header>
<d-content class="dcontent">
<div class="content-title"></div>
<div class="content-body">
<d-row>
<d-col :span="8">
<div class="content-body-col">
<span class="color-allow">允许的</span>
<span>Commercial Use</span>
<span>Modify</span>
<span>Distribute</span>
<span>Sublicense</span>
<span>Private Use</span>
</div>
</d-col>
<d-col :span="8">
<div class="content-body-col">
<span class="color-info">必要的</span>
<span>Include Copyright</span>
<span>Include License</span>
<span>State changes</span>
<span>Include Notice</span>
</div>
</d-col>
<d-col :span="8">
<div class="content-body-col">
<span class="color-danger">受限的</span>
<span>Place Warranty</span>
<span>Hold Liable</span>
<span>Use Trademark</span>
</div>
</d-col>
</d-row>
</div>
</d-content>
<d-footer class="dfooter">
<div>
<span>影响组件</span>
<span>request</span>
</div>
<div>
<span>当前版本</span>
<span>2.0</span>
</div>
</d-footer>
</d-layout>
</template>
<script setup>
import { ref, defineEmits } from 'vue';
const emit = defineEmits(['close']);
</script>
<style scoped lang="scss">
@import 'devui-theme/styles-var/devui-var.scss';
.dlayout {
width: 100%;
display: flex;
flex-direction: column;
align-items: start;
gap: 8px;
padding: 12px;
.dheader, .dcontent{
width: 100%;
border-bottom: 1px solid gray;
padding: 12px;
}
.dfooter {
width: 100%;
padding: 12px;
}
.title {
font-size: 20px;
font-weight: bold;
display: flex;
justify-content: space-between;
d-icon {
cursor: pointer;
}
}
.sub-title {
display: flex;
gap: 8px;
align-items: center;
}
}
.content-body-col {
display: flex;
flex-direction: column;
gap: 4px;
}
.dfooter {
display: flex;
flex-direction: column;
align-items: start;
gap: 4px;
}
.side-panel {
padding: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}
.color-danger {
color: $devui-danger;
}
.color-info {
color: $devui-warning;
}
.color-allow {
color: $devui-success;
}
</style>