app #1 simpleasm: 从 oci 迁过来,asm.famzheng.me 已上线
deploy cube / build-and-deploy (push) Successful in 1m18s
deploy simpleasm / build-and-deploy (push) Successful in 1m45s

- 后端 FastAPI 重写为 axum + rusqlite (musl static, 2.8MB)
- 前端原样搬运 (Vue3 + Vite + Pinia + vue-router + vite-plugin-yaml)
- k8s: cube-simpleasm ns + 1Gi PVC (k3s local-path) + Recreate strategy
- CI: 复刻 deploy-cube.yml,按 apps/simpleasm/** 触发
- cube 门户里 simpleasm 状态从 pending 改成 live
- 数据冷启 (Fam 拍板不带历史进度)
This commit is contained in:
Fam Zheng
2026-05-04 15:12:22 +01:00
parent 5b2e53c040
commit 388b505e0b
40 changed files with 3985 additions and 3 deletions
@@ -0,0 +1,84 @@
import { defineStore } from 'pinia'
export const useGameStore = defineStore('game', {
state: () => ({
playerName: localStorage.getItem('asm_playerName') || '',
playerId: parseInt(localStorage.getItem('asm_playerId')) || null,
progress: JSON.parse(localStorage.getItem('asm_progress') || '{}'),
}),
getters: {
isLoggedIn: (state) => !!state.playerName && !!state.playerId,
totalStars: (state) => Object.values(state.progress).reduce((s, p) => s + (p.stars || 0), 0),
levelsCompleted: (state) => Object.values(state.progress).filter(p => p.completed).length,
isLevelUnlocked() {
return (levelId) => {
if (levelId === 1) return true
return !!this.progress[levelId - 1]?.completed
}
},
},
actions: {
async login(name) {
try {
const res = await fetch('/api/players', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name }),
})
const data = await res.json()
this.playerName = data.name
this.playerId = data.id
if (data.progress) {
this.progress = { ...this.progress, ...data.progress }
}
this._persist()
return true
} catch {
// offline mode - just save locally
this.playerName = name
this.playerId = Date.now()
this._persist()
return true
}
},
async saveProgress(levelId, stars, code) {
const existing = this.progress[levelId]
const bestStars = Math.max(stars, existing?.stars || 0)
this.progress[levelId] = { completed: true, stars: bestStars, code }
this._persist()
try {
await fetch('/api/progress', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
player_id: this.playerId,
level_id: levelId,
stars: bestStars,
code,
}),
})
} catch {
// ok, saved locally
}
},
logout() {
this.playerName = ''
this.playerId = null
this.progress = {}
localStorage.removeItem('asm_playerName')
localStorage.removeItem('asm_playerId')
localStorage.removeItem('asm_progress')
},
_persist() {
localStorage.setItem('asm_playerName', this.playerName)
localStorage.setItem('asm_playerId', String(this.playerId))
localStorage.setItem('asm_progress', JSON.stringify(this.progress))
},
},
})