Files
my-page/src/pages/corp/TechOpensourcePage.vue
2026-08-13 21:14:30 +08:00

831 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { ref } from 'vue'
import { corpProfiles } from '../../data/corpProfiles'
const c = corpProfiles.tech
const stars = ref(48217)
const starred = ref(false)
function toggleStar() {
starred.value = !starred.value
stars.value += starred.value ? 1 : -1
}
const repos = [
{ name: 'qleap-runtime', desc: '端侧推理运行时,3 行代码部署模型', lang: 'C++', star: '21.4k', upd: 'yesterday' },
{ name: 'qleap-compiler', desc: '模型编译器,自动算子融合与量化', lang: 'Rust', star: '12.8k', upd: '3 days ago' },
{ name: 'awesome-edge-ai', desc: '端侧 AI 资源大全,社区共同维护', lang: 'Markdown', star: '9.6k', upd: 'last week' },
{ name: 'qleap-examples', desc: '40+ 场景示例:质检 / 座舱 / 无人机', lang: 'Python', star: '4.4k', upd: '2 weeks ago' },
]
const langColors = { 'C++': '#f34b7d', Rust: '#dea584', Markdown: '#3b6fb5', Python: '#3572a5' }
/* 产品 README 面板:仓库与 cases 一一对应 */
const rmIdx = ref(-1)
const rm = ref(null)
function openReadme(i) {
rmIdx.value = i
rm.value = c.cases[i]
}
function closeReadme() {
rmIdx.value = -1
rm.value = null
}
const starPath =
'M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z'
const repoPath =
'M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z'
/* 贡献热力图:确定性伪随机,26 周 × 7 天 */
const cells = Array.from({ length: 26 * 7 }, (_, i) => {
const v = (i * 2654435761 + 97) % 97
return v < 34 ? 0 : v < 58 ? 1 : v < 78 ? 2 : v < 90 ? 3 : 4
})
</script>
<template>
<div class="to">
<nav class="to-nav">
<b class="to-logo">&lt;/&gt; qleap-oss</b>
<div class="to-menu">
<a href="#readme">README</a>
<a href="#repos">仓库</a>
</div>
<router-link to="/corp" class="to-back">cd ../合集</router-link>
</nav>
<header class="to-hero">
<div class="to-term">
<div class="to-term-bar"><i></i><i></i><i></i><span>bash — qleap</span></div>
<div class="to-term-body">
<p><span class="to-p">$</span> npm install @qleap/runtime</p>
<p class="to-dim">+ @qleap/runtime@3.2.0 · added 1 package in 2.4s</p>
<p><span class="to-p">$</span> qleap deploy ./model.onnx --target edge</p>
<p class="to-ok">✓ compiled for X1 · latency 8ms · power 3.2W</p>
<p><span class="to-p">$</span> <span class="to-cursor">▊</span></p>
</div>
</div>
<div class="to-hero-txt">
<h1>开源,是我们的<br />第二条产品线</h1>
<p>{{ c.name }}开源社区 · 让每台设备都跑得起 AI</p>
<button class="to-star" :class="{ on: starred }" @click="toggleStar">
<svg class="to-star-ic" viewBox="0 0 16 16" aria-hidden="true"><path :d="starPath" /></svg>
{{ starred ? 'Starred' : 'Star' }}
<b>{{ stars.toLocaleString() }}</b>
</button>
</div>
</header>
<!-- README -->
<section id="readme" class="to-sec">
<h2 class="to-h2"># README.md</h2>
<div class="to-readme">
<div class="to-badges" aria-hidden="true">
<span class="to-badge"><i>build</i><em class="b-ok">passing</em></span>
<span class="to-badge"><i>coverage</i><em class="b-cov">94%</em></span>
<span class="to-badge"><i>license</i><em class="b-lic">MIT</em></span>
<span class="to-badge"><i>PRs</i><em class="b-prs">welcome</em></span>
</div>
<p class="to-md-h">## 为什么做开源</p>
<p class="to-dim">{{ c.desc }}</p>
<p class="to-md-h">## 我们提供什么</p>
<ul>
<li v-for="s in c.services" :key="s.name"><b>{{ s.name }}</b> — {{ s.desc }}</li>
</ul>
</div>
</section>
<!-- 社区脉搏 -->
<section class="to-sec">
<h2 class="to-h2"># 社区脉搏</h2>
<div class="to-graph-wrap">
<div class="to-graph-days" aria-hidden="true"><span>Mon</span><span>Wed</span><span>Fri</span></div>
<div class="to-graph" aria-label="贡献热力图">
<i v-for="(l, i) in cells" :key="i" :data-l="l"></i>
</div>
</div>
<div class="to-graph-note">
<span>last 26 weeks · 3,842 contributions · 214 contributors · 平均合并耗时 26h</span>
<span class="to-legend" aria-hidden="true">Less <i data-l="0"></i><i data-l="1"></i><i data-l="2"></i><i data-l="3"></i><i data-l="4"></i> More</span>
</div>
</section>
<!-- 仓库 -->
<section id="repos" class="to-sec">
<h2 class="to-h2"># 热门仓库</h2>
<div class="to-repos">
<div v-for="(r, i) in repos" :key="r.name" class="to-repo" :style="{ '--i': i }" @click="openReadme(i)">
<b class="to-repo-name">
<svg class="to-repo-ic" viewBox="0 0 16 16" aria-hidden="true"><path :d="repoPath" /></svg>
{{ r.name }}
<em>Public</em>
</b>
<p>{{ r.desc }}</p>
<div class="to-repo-meta">
<span class="to-lang"><i :style="{ background: langColors[r.lang] }"></i>{{ r.lang }}</span>
<span class="to-repo-star"><svg viewBox="0 0 16 16" aria-hidden="true"><path :d="starPath" /></svg>{{ r.star }}</span>
<span>Updated {{ r.upd }}</span>
<span class="to-repo-more">$ cat README →</span>
</div>
</div>
</div>
</section>
<!-- 产品 README 面板 -->
<Transition name="to-cat">
<div v-if="rm" class="to-mask" @click.self="closeReadme">
<article class="to-panel">
<div class="to-panel-bar">
<span class="to-panel-path">{{ repos[rmIdx].name }} / <b>README.md</b></span>
<button class="to-panel-x" aria-label="关闭" @click="closeReadme">✕</button>
</div>
<div class="to-panel-body">
<p class="to-panel-h1"># {{ rm.name }}</p>
<div class="to-badges" aria-hidden="true">
<span class="to-badge"><i>type</i><em class="b-lic">{{ rm.tag }}</em></span>
<span class="to-badge"><i>build</i><em class="b-ok">passing</em></span>
<span class="to-badge"><i>PRs</i><em class="b-prs">welcome</em></span>
</div>
<img class="to-panel-img" :src="rm.image" :alt="rm.name" />
<p class="to-md-h">## 这是什么</p>
<p class="to-panel-story">{{ rm.story }}</p>
<p class="to-md-h">## Features</p>
<ul class="to-panel-feats">
<li v-for="h in rm.highlights" :key="h"><span class="to-p">-</span> {{ h }}</li>
</ul>
<p class="to-md-h">## Changelog</p>
<div class="to-panel-log">
<p v-for="t in rm.timeline" :key="t.at"><span class="to-panel-commit" aria-hidden="true">●</span><i>{{ t.at }}</i>{{ t.event }}</p>
</div>
<p class="to-md-h">## Benchmarks</p>
<div class="to-panel-mx">
<div v-for="m in rm.metrics" :key="m.label"><b>{{ m.value }}</b><span>{{ m.label }}</span></div>
</div>
<p class="to-panel-eof">// EOF · MIT License · star 一下再走呗 ⭐</p>
</div>
</article>
</div>
</Transition>
<section class="to-sec">
<div class="to-stats-term">
<p class="to-stats-cmd"><span class="to-p">$</span> qleap stats --org --human</p>
<div class="to-stats">
<div v-for="(s, i) in c.stats" :key="s.label" :style="{ '--i': i }"><b>{{ s.value }}</b><span>{{ s.label }}</span></div>
</div>
</div>
</section>
<footer class="to-footer">
<p class="to-dim">// {{ c.name }} {{ c.nameEn }} · {{ c.contacts.email }} · {{ c.contacts.addr }}</p>
<p class="to-links">
<router-link to="/corp">cd /corp 返回企业合集</router-link>
<router-link to="/">cd / 个人页面合集</router-link>
</p>
<p class="to-copy">© {{ c.founded }}–2026 · MIT License · 风格演示页,公司与仓库均为虚构</p>
</footer>
</div>
</template>
<style scoped>
.to {
min-height: 100vh;
background: #0d1117;
color: #e6edf3;
font-family: Consolas, 'Courier New', monospace;
}
@keyframes to-fade {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
.to-nav {
position: sticky;
top: 0;
z-index: 40;
display: flex;
align-items: center;
gap: 22px;
padding: 13px clamp(16px, 5vw, 48px);
background: rgba(13, 17, 23, 0.95);
backdrop-filter: blur(6px);
border-bottom: 1px solid #30363d;
}
.to-logo {
font-size: 15px;
color: #3fb950;
}
.to-menu {
display: flex;
gap: 18px;
}
.to-menu a {
color: #8b949e;
text-decoration: none;
font-size: 13px;
}
.to-menu a:hover {
color: #58a6ff;
}
@media (max-width: 600px) {
.to-menu {
display: none;
}
}
.to-back {
margin-left: auto;
color: #0d1117;
background: #3fb950;
text-decoration: none;
font-size: 12.5px;
font-weight: 700;
padding: 6px 14px;
border-radius: 6px;
}
.to-back:hover {
background: #56d364;
}
.to-hero {
max-width: 1060px;
margin: 0 auto;
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 34px;
align-items: center;
padding: clamp(44px, 7vw, 80px) clamp(16px, 4vw, 26px) 56px;
}
.to-term {
background: #010409;
border: 1px solid #30363d;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
animation: to-fade 0.6s 0.05s both;
}
.to-term-bar {
display: flex;
align-items: center;
gap: 7px;
padding: 10px 14px;
background: #161b22;
border-bottom: 1px solid #30363d;
}
.to-term-bar i {
width: 11px;
height: 11px;
border-radius: 50%;
}
.to-term-bar i:nth-child(1) { background: #ff5f57; }
.to-term-bar i:nth-child(2) { background: #febc2e; }
.to-term-bar i:nth-child(3) { background: #28c840; }
.to-term-bar span {
margin-left: 8px;
font-size: 11px;
color: #8b949e;
}
.to-term-body {
padding: 18px 18px 22px;
font-size: 13px;
line-height: 2;
}
.to-term-body p {
margin: 0;
}
.to-p {
color: #3fb950;
margin-right: 8px;
}
.to-dim {
color: #8b949e;
}
.to-ok {
color: #3fb950;
}
.to-cursor {
animation: to-blink 1s step-end infinite;
}
@keyframes to-blink {
50% { opacity: 0; }
}
.to-hero-txt {
animation: to-fade 0.6s 0.15s both;
}
.to-hero-txt h1 {
margin: 0 0 14px;
font-size: clamp(28px, 4.6vw, 44px);
line-height: 1.25;
color: #e6edf3;
}
.to-hero-txt p {
margin: 0 0 24px;
font-size: 14px;
color: #8b949e;
}
.to-star {
display: inline-flex;
align-items: center;
gap: 8px;
background: #21262d;
border: 1px solid #30363d;
color: #e6edf3;
font-family: inherit;
font-size: 14px;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
transition: all 0.18s ease;
}
.to-star:hover {
border-color: #8b949e;
}
.to-star.on {
color: #e3b341;
border-color: #e3b341;
}
.to-star-ic {
width: 16px;
height: 16px;
fill: none;
stroke: currentColor;
stroke-width: 1;
}
.to-star.on .to-star-ic {
fill: #e3b341;
stroke: #e3b341;
animation: to-pop 0.35s ease;
}
@keyframes to-pop {
40% {
transform: scale(1.4) rotate(-10deg);
}
}
.to-star b {
background: #30363d;
padding: 2px 10px;
border-radius: 99px;
font-size: 13px;
font-variant-numeric: tabular-nums;
}
.to-sec {
max-width: 1060px;
margin: 0 auto 52px;
padding: 0 clamp(16px, 4vw, 26px);
}
.to-h2 {
font-size: 19px;
color: #58a6ff;
margin: 0 0 18px;
}
.to-readme {
background: #161b22;
border: 1px solid #30363d;
border-radius: 10px;
padding: 24px 26px;
font-size: 13.5px;
line-height: 2;
}
.to-badges {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 18px;
}
.to-badge {
display: inline-flex;
font-size: 11px;
line-height: 1;
border-radius: 3px;
overflow: hidden;
}
.to-badge i {
font-style: normal;
background: #21262d;
color: #c9d1d9;
padding: 4.5px 7px;
}
.to-badge em {
font-style: normal;
font-weight: 700;
color: #0d1117;
padding: 4.5px 7px;
}
.to-badge .b-ok { background: #3fb950; }
.to-badge .b-cov { background: #58a6ff; }
.to-badge .b-lic { background: #d2a8ff; }
.to-badge .b-prs { background: #e3b341; }
.to-readme p {
margin: 0 0 8px;
}
.to-md-h {
color: #d2a8ff;
font-weight: 700;
border-bottom: 1px solid #21262d;
padding-bottom: 6px;
margin: 0 0 10px;
}
.to-readme .to-md-h + p {
margin-bottom: 18px;
}
.to-readme ul {
margin: 0;
padding-left: 22px;
color: #8b949e;
}
.to-readme li {
margin-bottom: 8px;
}
.to-readme li b {
font-weight: 400;
color: #79c0ff;
background: #21262d;
padding: 1px 7px;
border-radius: 4px;
}
.to-graph-wrap {
display: flex;
gap: 8px;
padding: 14px;
border: 1px solid #30363d;
border-radius: 8px;
background: #0a0e14;
overflow-x: auto;
}
.to-graph-days {
display: grid;
grid-template-rows: repeat(7, 12px);
gap: 3px;
font-size: 9.5px;
color: #8b949e;
}
.to-graph-days span:nth-child(1) { grid-row: 2; }
.to-graph-days span:nth-child(2) { grid-row: 4; }
.to-graph-days span:nth-child(3) { grid-row: 6; }
.to-graph {
display: grid;
grid-template-rows: repeat(7, 12px);
grid-auto-flow: column;
grid-auto-columns: 12px;
gap: 3px;
}
.to-graph i {
border-radius: 2.5px;
background: #161b22;
transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.to-graph i:hover {
transform: scale(1.3);
box-shadow: 0 0 0 1px rgba(230, 237, 243, 0.4);
}
.to-graph i[data-l='1'], .to-legend i[data-l='1'] { background: #0e4429; }
.to-graph i[data-l='2'], .to-legend i[data-l='2'] { background: #006d32; }
.to-graph i[data-l='3'], .to-legend i[data-l='3'] { background: #26a641; }
.to-graph i[data-l='4'], .to-legend i[data-l='4'] { background: #39d353; }
.to-graph-note {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 8px;
margin: 10px 2px 0;
font-size: 11.5px;
color: #8b949e;
}
.to-legend {
display: inline-flex;
align-items: center;
gap: 3px;
}
.to-legend i {
width: 10px;
height: 10px;
border-radius: 2px;
background: #161b22;
}
/* 仓库:GitHub 列表行 */
.to-repos {
border: 1px solid #30363d;
border-radius: 8px;
overflow: hidden;
}
.to-repo {
padding: 16px 20px;
border-bottom: 1px solid #21262d;
transition: background 0.15s ease;
animation: to-fade 0.5s calc(var(--i) * 0.07s) both;
}
.to-repo:last-child {
border-bottom: none;
}
.to-repo:hover {
background: #161b22;
}
.to-repo-name {
display: inline-flex;
align-items: center;
gap: 8px;
color: #58a6ff;
font-size: 14.5px;
}
.to-repo:hover .to-repo-name {
text-decoration: underline;
}
.to-repo-ic {
width: 16px;
height: 16px;
fill: #8b949e;
flex: none;
}
.to-repo-name em {
font-style: normal;
font-size: 10.5px;
font-weight: 400;
color: #8b949e;
border: 1px solid #30363d;
border-radius: 999px;
padding: 1px 8px;
text-decoration: none;
}
.to-repo p {
margin: 8px 0 12px;
font-size: 12.5px;
line-height: 1.8;
color: #8b949e;
}
.to-repo-meta {
display: flex;
flex-wrap: wrap;
gap: 16px;
font-size: 12px;
color: #8b949e;
}
.to-lang {
display: inline-flex;
align-items: center;
gap: 6px;
}
.to-lang i {
width: 10px;
height: 10px;
border-radius: 50%;
}
.to-repo-star {
display: inline-flex;
align-items: center;
gap: 5px;
font-variant-numeric: tabular-nums;
}
.to-repo-star svg {
width: 13px;
height: 13px;
fill: currentColor;
}
/* 组织统计:终端输出 */
.to-stats-term {
background: #010409;
border: 1px solid #30363d;
border-radius: 10px;
padding: 16px 18px 18px;
}
.to-stats-cmd {
margin: 0 0 14px;
font-size: 13px;
}
.to-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 10px 0;
}
.to-stats > div {
border-left: 2px solid #21262d;
padding: 2px 16px;
animation: to-fade 0.5s calc(0.15s + var(--i) * 0.08s) both;
}
.to-stats b {
display: block;
font-size: clamp(20px, 3.4vw, 26px);
color: #3fb950;
font-variant-numeric: tabular-nums;
}
.to-stats span {
font-size: 11.5px;
color: #8b949e;
}
.to-stats span::before {
content: '# ';
color: #484f58;
}
.to-footer {
border-top: 1px solid #30363d;
text-align: center;
padding: 28px 20px 40px;
font-size: 12.5px;
}
.to-footer p {
margin: 0 0 10px;
}
.to-links a {
color: #58a6ff;
text-decoration: none;
margin: 0 12px;
}
.to-links a:hover {
text-decoration: underline;
}
.to-copy {
font-size: 11px;
color: #484f58;
}
@media (max-width: 820px) {
.to-hero {
grid-template-columns: 1fr;
}
}
/* ---- 产品 README 面板 ---- */
.to-repo {
cursor: pointer;
}
.to-repo-more {
margin-left: auto;
color: #3fb950;
opacity: 0;
transition: opacity 0.2s ease;
}
.to-repo:hover .to-repo-more {
opacity: 1;
}
.to-mask {
position: fixed;
inset: 0;
z-index: 520;
display: grid;
place-items: center;
padding: 20px;
background: rgba(1, 4, 9, 0.8);
backdrop-filter: blur(4px);
}
.to-panel {
position: relative;
width: min(640px, 94vw);
max-height: 88vh;
display: flex;
flex-direction: column;
background: #0d1117;
border: 1px solid #30363d;
border-radius: 10px;
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.7);
overflow: hidden;
}
.to-panel-bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 10px 16px;
background: #161b22;
border-bottom: 1px solid #30363d;
}
.to-panel-path {
font-size: 12px;
color: #8b949e;
}
.to-panel-path b {
color: #58a6ff;
}
.to-panel-x {
width: 28px;
height: 28px;
border: 1px solid #30363d;
border-radius: 6px;
background: #0d1117;
color: #8b949e;
font-size: 12px;
cursor: pointer;
}
.to-panel-x:hover {
color: #e6edf3;
border-color: #8b949e;
}
.to-panel-body {
padding: 20px 24px 24px;
overflow-y: auto;
}
.to-panel-h1 {
margin: 0 0 10px;
font-size: 22px;
font-weight: 700;
color: #e6edf3;
border-bottom: 1px solid #30363d;
padding-bottom: 10px;
}
.to-panel-img {
display: block;
width: 100%;
aspect-ratio: 16 / 7;
object-fit: cover;
border-radius: 8px;
border: 1px solid #30363d;
margin: 12px 0 4px;
}
.to-panel-story {
margin: 0;
font-size: 13px;
line-height: 1.9;
color: #b6c2cf;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.to-panel-feats {
margin: 0;
padding: 0;
list-style: none;
}
.to-panel-feats li {
padding: 3px 0;
font-size: 12.5px;
color: #b6c2cf;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.to-panel-feats .to-p {
font-family: Consolas, monospace;
margin-right: 8px;
}
.to-panel-log p {
display: flex;
align-items: baseline;
gap: 10px;
margin: 0 0 6px;
font-size: 12.5px;
color: #b6c2cf;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.to-panel-commit {
color: #3fb950;
font-size: 10px;
}
.to-panel-log i {
flex: 0 0 62px;
font-style: normal;
font-family: Consolas, monospace;
font-size: 11px;
color: #8b949e;
font-variant-numeric: tabular-nums;
}
.to-panel-mx {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-top: 4px;
}
.to-panel-mx > div {
background: #161b22;
border: 1px solid #30363d;
border-radius: 8px;
padding: 10px 8px;
text-align: center;
}
.to-panel-mx b {
display: block;
font-size: 17px;
color: #3fb950;
}
.to-panel-mx span {
font-size: 10.5px;
color: #8b949e;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.to-panel-eof {
margin: 16px 0 0;
font-size: 11px;
color: #484f58;
}
.to-cat-enter-active,
.to-cat-leave-active {
transition: opacity 0.22s ease;
}
.to-cat-enter-active .to-panel,
.to-cat-leave-active .to-panel {
transition: transform 0.26s cubic-bezier(0.25, 1.1, 0.4, 1);
}
.to-cat-enter-from,
.to-cat-leave-to {
opacity: 0;
}
.to-cat-enter-from .to-panel,
.to-cat-leave-to .to-panel {
transform: translateY(18px) scale(0.97);
}
</style>