feat: M0-M2 骨架落地(服务端/前端/宿主/数据库/积分引擎)
- server: Go 单二进制骨架,embed 内嵌前端,配置/迁移/HTTP 路由 - store: system.db + event.db 两套迁移,业务表 + 种子数据 - domain: 积分引擎(并列三口径/计分通道/流水/排名/破纪录)+ 68 个测试 - web: Vite + Vue 三入口骨架 + shared 层(类型/API/WebSocket 客户端) - console: Electron 宿主骨架(选屏/防熄屏/进程守护/托盘)
This commit is contained in:
1 parent
a61d793d79
commit
7d5d94f815
76 files changed
+10131
No files matched your search
@@ -0,0 +1,180 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
// 占位数据:M1/M3 接入 /api 后替换为实时数据
|
||||
const teams = ref([
|
||||
{ rank: 1, name: '第一分公司', points: 186 },
|
||||
{ rank: 2, name: '机关本部', points: 172 },
|
||||
{ rank: 3, name: '第二分公司', points: 158 },
|
||||
{ rank: 4, name: '第三分公司', points: 141 },
|
||||
{ rank: 5, name: '第四分公司', points: 127 },
|
||||
{ rank: 6, name: '第五分公司', points: 103 },
|
||||
{ rank: 7, name: '第六分公司', points: 95 },
|
||||
])
|
||||
|
||||
const scale = ref(1)
|
||||
const stage = ref<HTMLElement | null>(null)
|
||||
|
||||
function fit() {
|
||||
const s = Math.min(window.innerWidth / 1920, window.innerHeight / 1080)
|
||||
scale.value = s
|
||||
if (stage.value) {
|
||||
stage.value.style.left = `${(window.innerWidth - 1920 * s) / 2}px`
|
||||
stage.value.style.top = `${(window.innerHeight - 1080 * s) / 2}px`
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fit()
|
||||
window.addEventListener('resize', fit)
|
||||
})
|
||||
onUnmounted(() => window.removeEventListener('resize', fit))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="stage" class="stage" :style="{ transform: `scale(${scale})` }">
|
||||
<header class="head">
|
||||
<div class="logo">会标</div>
|
||||
<h1>赛事积分榜</h1>
|
||||
<div class="spacer" />
|
||||
</header>
|
||||
|
||||
<section class="board">
|
||||
<h2>总积分榜</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="rk">名次</th>
|
||||
<th>单位</th>
|
||||
<th class="pt">总分</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="t in teams" :key="t.name">
|
||||
<td class="rk">{{ t.rank }}</td>
|
||||
<td class="nm">{{ t.name }}</td>
|
||||
<td class="pt">{{ t.points }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<footer class="ticker">底栏信息条(轮播占位)</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.stage {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
transform-origin: top left;
|
||||
padding: 40px 48px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
background:
|
||||
radial-gradient(ellipse at 20% 0%, rgba(79, 216, 255, 0.12), transparent 55%),
|
||||
radial-gradient(ellipse at 85% 100%, rgba(255, 215, 94, 0.08), transparent 50%), var(--bg);
|
||||
cursor: none;
|
||||
}
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 28px;
|
||||
}
|
||||
.logo {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid var(--gold);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 22px;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
h1 {
|
||||
font-size: 64px;
|
||||
letter-spacing: 8px;
|
||||
background: linear-gradient(180deg, #fff 30%, var(--gold) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
.board {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
background: var(--panel);
|
||||
border: 2px solid var(--panel-border);
|
||||
border-radius: 16px;
|
||||
padding: 20px 28px 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
h2 {
|
||||
font-size: 34px;
|
||||
letter-spacing: 4px;
|
||||
color: var(--cyan);
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid rgba(79, 216, 255, 0.35);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
font-size: 30px;
|
||||
padding: 12px 8px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
th {
|
||||
font-size: 20px;
|
||||
color: var(--text-dim);
|
||||
font-weight: 400;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
td.rk {
|
||||
width: 140px;
|
||||
font-weight: 800;
|
||||
font-size: 34px;
|
||||
}
|
||||
tbody tr:nth-child(1) td.rk {
|
||||
color: var(--gold);
|
||||
}
|
||||
tbody tr:nth-child(2) td.rk {
|
||||
color: #d8e2ee;
|
||||
}
|
||||
tbody tr:nth-child(3) td.rk {
|
||||
color: #e0995e;
|
||||
}
|
||||
td.nm {
|
||||
text-align: left;
|
||||
padding-left: 32px;
|
||||
}
|
||||
td.pt {
|
||||
width: 220px;
|
||||
color: var(--gold);
|
||||
font-weight: 800;
|
||||
font-size: 36px;
|
||||
}
|
||||
.ticker {
|
||||
height: 88px;
|
||||
border-radius: 16px;
|
||||
background: var(--panel);
|
||||
border: 2px solid var(--panel-border);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 26px;
|
||||
color: var(--text-dim);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import '@/shared/styles/base.css'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
Reference in new issue
Block a user