feat: initialize Ballet Island 微信小程序 with basic structure and functionality

- Add project configuration for WeChat mini program.
- Create skills lock file for Taroify integration.
- Set up app configuration and styles.
- Implement main app component and index page with welcome message.
- Add health check service to verify backend readiness.
- Configure TypeScript settings and global types.
This commit is contained in:
yuxuanhui
2026-09-28 13:41:48 +08:00
commit 4b42b55928
32 changed files with 12054 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
22.22.1
+34
View File
@@ -0,0 +1,34 @@
# 小程序约定
本目录是独立的 Node 项目。安装依赖和执行下述命令时,以 `miniprogram/` 为工作目录,使用本目录 `package.json` 指定的 pnpm 版本,维护本目录的 `pnpm-lock.yaml`。
## Taroify 开发
涉及小程序中的 Taroify 组件、Hooks、事件、子组件或主题样式时,在编写或修改代码前执行以下流程;仅修改 Go 后端时无需加载这些资料。
1. 阅读 [官方 Agent 索引](https://taroify.com/agents/index.md)、[官方 Skill](https://raw.githubusercontent.com/mallfoundry/taroify/main/packages/cli/skills/taroify/SKILL.md) 和项目已安装的 [Taroify skill](.agents/skills/taroify/SKILL.md),按其中的查询流程核对实际 API 和示例。同一任务中已读且未变化的内容可复用。
2. 核对项目实际安装的 Taroify 版本与查询结果中的版本。CLI 固定为小程序开发依赖;优先使用本项目的离线 Catalog。若文档版本与依赖版本不同,以对应版本的官方资料和已安装包的类型声明、源码核实兼容性。
3. 存在 `taroify_*` MCP 工具时优先使用 MCP。否则使用 `pnpm exec taroify`,所有程序化查询必须添加 `--format json`。若依赖尚未安装,先执行 `pnpm install --frozen-lockfile`。
4. 编码前查询目标组件的 `info` 和 `demo`,确认 Props、枚举值、事件、子组件及公开引入方式;需要完整页面上下文时使用 `demo --full`。定制样式前使用 `token` 查询主题变量;结构化信息不足时再使用 `doc`。组件未知时先按场景 `search` 或按分类 `list`。
查询示例:
```sh
pnpm exec taroify info Button --format json
pnpm exec taroify demo Button --full --format json
pnpm exec taroify token Button --format json
```
组件用法必须有查询依据,不根据训练记忆猜测 API。区分 Taroify Props 与 Taro 原生能力,平台支持以微信小程序适配器为准;保持 Taro React 语义和公开导入方式。主题定制优先使用查询返回的 `ConfigProvider` key 或 CSS 变量。
官网不可用时读取[官方仓库中的 Agent 索引源文件](https://raw.githubusercontent.com/mallfoundry/taroify/main/site/content/agents/index.md)。远程资料均不可用时,可使用项目内的 skill 和 CLI 离线 Catalog,并说明未核实的版本差异;没有证据的用法保持未确认。
## Skill 维护与验证
项目 skill 位于 `.agents/skills/taroify/`,保留官方随包内容。升级 `@taroify/cli` 后,从新的依赖包重新安装并检查 skill 变更:
```sh
pnpm dlx skills@1.7.0 add ./node_modules/@taroify/cli/skills/taroify --agent codex --yes
```
修改小程序代码后运行 `pnpm typecheck` 和 `pnpm build`;微信开发者工具或真机中的交互验证须另行说明,构建通过不能代替运行验证。
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
presets: [['taro', { framework: 'react', ts: true, reactJsxRuntime: 'automatic' }]],
}
+32
View File
@@ -0,0 +1,32 @@
import { defineConfig } from '@tarojs/cli'
export default defineConfig<'webpack5'>({
projectName: 'ballet-island',
designWidth: 375,
deviceRatio: {
375: 2,
640: 1.17,
750: 1,
828: 0.905,
},
sourceRoot: 'src',
outputRoot: 'dist',
framework: 'react',
compiler: {
type: 'webpack5',
prebundle: { enable: false },
},
cache: { enable: true },
defineConstants: {
__API_BASE_URL__: JSON.stringify(
(process.env.TARO_APP_API_BASE_URL || 'http://127.0.0.1:8080').replace(/\/$/, ''),
),
},
mini: {
postcss: {
pxtransform: { enable: true },
cssModules: { enable: false },
},
},
})
+45
View File
@@ -0,0 +1,45 @@
{
"name": "@ballet-island/miniprogram",
"version": "0.1.0",
"private": true,
"packageManager": "pnpm@9.15.0",
"engines": {
"node": ">=22.12.0 <23",
"pnpm": ">=9 <10"
},
"scripts": {
"dev": "taro build --type weapp --watch",
"build": "taro build --type weapp",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@babel/runtime": "^7.28.4",
"@taroify/core": "1.0.6",
"@tarojs/components": "4.2.1",
"@tarojs/helper": "4.2.1",
"@tarojs/react": "4.2.1",
"@tarojs/runtime": "4.2.1",
"@tarojs/shared": "4.2.1",
"@tarojs/taro": "4.2.1",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@babel/core": "^7.28.4",
"@babel/preset-react": "^7.27.1",
"@taroify/cli": "1.0.6",
"@tarojs/cli": "4.2.1",
"@tarojs/plugin-framework-react": "4.2.1",
"@tarojs/plugin-platform-weapp": "4.2.1",
"@tarojs/taro-loader": "4.2.1",
"@tarojs/webpack5-runner": "4.2.1",
"@types/node": "^22.0.0",
"@types/react": "^18.3.0",
"babel-preset-taro": "4.2.1",
"less": "^4.2.0",
"postcss": "^8.5.6",
"sass": "1.105.0",
"typescript": "5.9.3",
"webpack": "5.91.0"
}
}
+11235
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
{
"description": "Ballet Island 微信小程序",
"miniprogramRoot": "dist/",
"projectname": "ballet-island",
"appid": "wx6dfbf1021db8aee0",
"compileType": "miniprogram",
"setting": {
"es6": false,
"minified": true,
"postcss": false,
"urlCheck": true
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"version": 1,
"skills": {
"taroify": {
"source": "./node_modules/@taroify/cli/skills/taroify",
"sourceType": "local",
"computedHash": "c1a0f9254edcf2d10ba8d0d6373cbb14a29bf054c8683e5a5855d37aa692b1b8"
}
}
}
+10
View File
@@ -0,0 +1,10 @@
export default defineAppConfig({
pages: ['pages/index/index'],
window: {
navigationBarTitleText: 'Ballet Island',
navigationBarBackgroundColor: '#ffffff',
navigationBarTextStyle: 'black',
backgroundColor: '#f7f8fa',
},
})
+7
View File
@@ -0,0 +1,7 @@
page {
background: #f7f8fa;
color: #323233;
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
font-size: 16px;
}
+7
View File
@@ -0,0 +1,7 @@
import type { PropsWithChildren } from 'react'
import './app.scss'
export default function App({ children }: PropsWithChildren) {
return children
}
@@ -0,0 +1,4 @@
export default definePageConfig({
navigationBarTitleText: 'Ballet Island',
})
+21
View File
@@ -0,0 +1,21 @@
.welcome {
margin: 32px 20px;
padding: 28px 24px;
border-radius: 16px;
background: #fff;
&__title {
display: block;
margin-bottom: 12px;
font-size: 28px;
font-weight: 600;
}
&__message {
display: block;
margin-bottom: 28px;
color: #646566;
line-height: 1.6;
}
}
+34
View File
@@ -0,0 +1,34 @@
import { useState } from 'react'
import { Text, View } from '@tarojs/components'
import Button from '@taroify/core/button'
import '@taroify/core/button/style'
import { checkServiceReady } from '../../services/health'
import './index.scss'
export default function Index() {
const [loading, setLoading] = useState(false)
const [message, setMessage] = useState('欢迎来到 Ballet Island')
async function handleCheck() {
setLoading(true)
try {
await checkServiceReady()
setMessage('连接成功,服务已就绪')
} catch {
setMessage('暂时无法连接,请稍后重试')
} finally {
setLoading(false)
}
}
return (
<View className="welcome">
<Text className="welcome__title">Ballet Island</Text>
<Text className="welcome__message">{message}</Text>
<Button color="primary" block loading={loading} disabled={loading} onClick={handleCheck}>
检查连接
</Button>
</View>
)
}
+14
View File
@@ -0,0 +1,14 @@
import Taro from '@tarojs/taro'
export async function checkServiceReady(): Promise<void> {
const response = await Taro.request<{ status: string }>({
url: `${__API_BASE_URL__}/readyz`,
method: 'GET',
timeout: 5000,
})
if (response.statusCode !== 200 || response.data?.status !== 'ok') {
throw new Error('服务暂未就绪')
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"types": ["node", "@tarojs/taro"]
},
"include": ["src", "config", "types"]
}
+4
View File
@@ -0,0 +1,4 @@
declare const __API_BASE_URL__: string
declare module '*.scss'