chore: initialize frontend and backend workspace
This commit is contained in:
parent
86c906727b
commit
ca9ce54d13
9
.gitignore
vendored
9
.gitignore
vendored
@ -1 +1,8 @@
|
|||||||
.DS_store
|
node_modules/
|
||||||
|
.DS_Store
|
||||||
|
dist/
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
client/src/api/generated/
|
||||||
|
server/data/*.tmp
|
||||||
|
|||||||
2
client/index.html
Normal file
2
client/index.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>备考通</title></head><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body></html>
|
||||||
21
client/package.json
Normal file
21
client/package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "@gwy/client",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"typecheck": "vue-tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@vitejs/plugin-vue": "latest",
|
||||||
|
"vite": "latest",
|
||||||
|
"vue": "latest",
|
||||||
|
"vue-router": "latest",
|
||||||
|
"pinia": "latest"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.7.3",
|
||||||
|
"vue-tsc": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
20
client/src/App.vue
Normal file
20
client/src/App.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const nav = ['数据中枢', '刷题中心', '模考分析', '备考计划', '要闻', '我的']
|
||||||
|
const active = ref(0)
|
||||||
|
const title = computed(() => nav[active.value])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="app-shell">
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="brand"><span>✦</span><strong>备考中枢</strong></div>
|
||||||
|
<button v-for="(item, index) in nav" :key="item" :class="['nav-item', { active: active === index }]" @click="active = index">{{ item }}</button>
|
||||||
|
<div class="sidebar-spacer" />
|
||||||
|
<button class="nav-item">题库管理</button><button class="nav-item">设置</button>
|
||||||
|
</aside>
|
||||||
|
<main class="content"><header><div><h1>{{ title }}</h1><p>个人备考工作台 · 页面骨架</p></div><button class="primary">开始使用</button></header><section class="welcome"><h2>备考通已就绪</h2><p>前端工程骨架已启动,后续任务将逐页还原原型并接入真实数据。</p></section></main>
|
||||||
|
<nav class="mobile-tabs"> <button v-for="(item, index) in nav" :key="item" :class="{ active: active === index }" @click="active = index"><span>{{ ['⌂','▣','▥','▤','▤','●'][index] }}</span>{{ item }}</button></nav>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
6
client/src/main.ts
Normal file
6
client/src/main.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
|
import App from './App.vue'
|
||||||
|
import './styles/main.css'
|
||||||
|
|
||||||
|
createApp(App).use(createPinia()).mount('#app')
|
||||||
1
client/src/styles/main.css
Normal file
1
client/src/styles/main.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
:root{font-family:Arial,"PingFang SC",sans-serif;color:#1a1f2e;background:#f7f6f2;font-synthesis:none}*{box-sizing:border-box}body{margin:0}.app-shell{min-height:100vh}.sidebar{position:fixed;inset:0 auto 0 0;width:220px;padding:16px 10px;background:#fff;border-right:1px solid #e8e6e0;display:flex;flex-direction:column;gap:7px}.brand{height:36px;display:flex;align-items:center;gap:9px}.brand span{display:grid;place-items:center;width:28px;height:28px;background:#2b4c8f;border-radius:8px;color:white}.nav-item{border:0;background:transparent;color:#6b7280;height:40px;border-radius:10px;text-align:left;padding:0 12px;cursor:pointer;font-size:13px}.nav-item.active{background:#2b4c8f;color:#fff}.sidebar-spacer{flex:1}.content{margin-left:220px;padding:32px;max-width:1250px}header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}h1{font-size:24px;margin:0 0 5px}h2{margin:0 0 8px}p{font-size:13px;color:#6b7280;margin:0;line-height:1.5}.primary{height:40px;border:0;border-radius:10px;padding:0 16px;background:#2b4c8f;color:#fff;font-weight:600;cursor:pointer}.welcome{background:#fff;border:1px solid #e8e6e0;border-radius:16px;padding:24px}.mobile-tabs{display:none}@media(max-width:767px){.sidebar{display:none}.content{margin:0;padding:28px 24px 110px}.content header{margin-bottom:24px}.content h1{font-size:22px}.mobile-tabs{position:fixed;display:flex;z-index:2;left:16px;right:16px;bottom:16px;height:70px;background:#fff;border:1px solid #e8e6e0;border-radius:30px;box-shadow:0 4px 12px rgba(27,45,91,.08);justify-content:space-around;padding:8px}.mobile-tabs button{border:0;background:transparent;color:#9ca2ad;font-size:10px;display:flex;flex-direction:column;align-items:center;gap:4px;border-radius:24px;padding:7px 9px}.mobile-tabs button.active{background:#2b4c8f;color:#fff}.mobile-tabs span{font-size:17px}.primary{height:36px;padding:0 11px;font-size:12px}}
|
||||||
4
client/tsconfig.json
Normal file
4
client/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "jsx": "preserve", "skipLibCheck": true, "allowImportingTsExtensions": true, "isolatedModules": true, "noEmit": true, "types": ["vite/client"] },
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.vue"]
|
||||||
|
}
|
||||||
7
client/vite.config.ts
Normal file
7
client/vite.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
server: { port: 5173 }
|
||||||
|
})
|
||||||
22
docs/checks/task-01.md
Normal file
22
docs/checks/task-01.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 任务 01 检查记录:项目初始化与目录确定
|
||||||
|
|
||||||
|
日期:2026-08-28
|
||||||
|
|
||||||
|
## 命令检查
|
||||||
|
|
||||||
|
- `pnpm install`:通过
|
||||||
|
- `pnpm typecheck`:通过(server、client)
|
||||||
|
- `pnpm build`:通过(server、client)
|
||||||
|
- `GET /health`:通过,返回 `{"status":"ok","service":"gwy-server"}`
|
||||||
|
- 前端开发服务:可启动,Vite 返回 HTTP 200
|
||||||
|
|
||||||
|
## 浏览器检查
|
||||||
|
|
||||||
|
- 已启动 Vite 与 Fastify 服务。
|
||||||
|
- 按计划尝试使用内置浏览器打开前端并获取 DOM/截图。
|
||||||
|
- 当前运行环境的内置浏览器无法访问本地开发端口,返回 `ERR_CONNECTION_REFUSED`;终端网络环境可以访问同一端口。
|
||||||
|
- 因此本项的浏览器实际操作和原型截图对比暂记为“环境阻塞”,不宣称通过;待浏览器可访问本地服务后补检。
|
||||||
|
|
||||||
|
## 当前结论
|
||||||
|
|
||||||
|
工程骨架、依赖安装、类型检查、生产构建和服务健康检查均通过;浏览器检查未通过,后续任务继续前需补齐该项。
|
||||||
11
package.json
Normal file
11
package.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "gwy-exam",
|
||||||
|
"private": true,
|
||||||
|
"packageManager": "pnpm@9.1.2",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "pnpm --filter @gwy/client dev",
|
||||||
|
"dev:server": "pnpm --filter @gwy/server dev",
|
||||||
|
"build": "pnpm -r build",
|
||||||
|
"typecheck": "pnpm -r typecheck"
|
||||||
|
}
|
||||||
|
}
|
||||||
1930
pnpm-lock.yaml
generated
Normal file
1930
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
packages:
|
||||||
|
- client
|
||||||
|
- server
|
||||||
8
server/package.json
Normal file
8
server/package.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "@gwy/server",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": { "dev": "tsx watch src/server.ts", "build": "tsc", "typecheck": "tsc --noEmit" },
|
||||||
|
"dependencies": { "@fastify/cors": "latest", "fastify": "latest", "zod": "latest" },
|
||||||
|
"devDependencies": { "tsx": "latest", "typescript": "latest", "@types/node": "latest" }
|
||||||
|
}
|
||||||
7
server/src/server.ts
Normal file
7
server/src/server.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Fastify from 'fastify'
|
||||||
|
import cors from '@fastify/cors'
|
||||||
|
|
||||||
|
const app = Fastify({ logger: true })
|
||||||
|
await app.register(cors, { origin: true })
|
||||||
|
app.get('/health', async () => ({ status: 'ok', service: 'gwy-server' }))
|
||||||
|
app.listen({ port: Number(process.env.PORT ?? 3000), host: '127.0.0.1' })
|
||||||
1
server/tsconfig.json
Normal file
1
server/tsconfig.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"compilerOptions":{"target":"ES2022","module":"NodeNext","moduleResolution":"NodeNext","strict":true,"esModuleInterop":true,"skipLibCheck":true,"rootDir":"src","outDir":"dist"},"include":["src/**/*.ts"]}
|
||||||
Loading…
x
Reference in New Issue
Block a user