Prepare production smart scale Android app

This commit is contained in:
FinleyHsu
2026-07-28 16:44:40 +08:00
parent af50188332
commit eab3ca651a
70 changed files with 4286 additions and 459 deletions
+67 -78
View File
@@ -1,98 +1,87 @@
# vinext-starter
# 沃尔核材智能电子秤
A clean full-stack starter running on
[vinext](https://github.com/cloudflare/vinext), with optional Cloudflare D1 and
Drizzle support.
面向生产现场 Android 终端的横屏智能称重应用。应用完成废料选择、人员与机台确认、连续稳定采样、称重记录上传、本地备份和异常补传。
## Prerequisites
## 主要功能
- Node.js `>=22.13.0`
- 首页选择废铜、废电线、废铝或废锡,Type ID 默认为 3、4、5、6。
- 从本地服务器读取门禁人员和生产机台数据。
- 通过 WebSocket 连续读取电子秤重量,支持 kg、g、lb 单位切换。
- 支持清零、去皮、累计和取消上一次累计。
- 重量稳定后提交记录;网络异常时写入本地备份和补传队列。
- 管理员可维护废料字典、设备信息、接口地址、语言和密码。
- 预留 USB 摄像头拍照与打印机触发点。
- 支持开机自启动、系统设置、文件管理、实时日志和日志导出。
## Quick Start
## 正式数据接口
```bash
npm install
npm run dev
npm run build
```
应用不包含人员、机台或重量模拟数据。接口未配置或不可用时,界面会显示错误并保留在安全等待状态。
This starter does not use `wrangler.jsonc`.
### 人员接口
## Included Shape
返回 JSON:
- edit site code under `app/`
- `.openai/hosting.json` declares optional Sites D1 and R2 bindings
- `vite.config.ts` simulates declared bindings for local development
- `db/schema.ts` starts intentionally empty
- `examples/d1/` contains an optional D1 example surface
- `drizzle.config.ts` supports local migration generation when needed
## Workspace Auth Headers
OpenAI workspace sites can read the current user's email from
`oai-authenticated-user-email`.
SIWC-authenticated workspace sites may also receive
`oai-authenticated-user-full-name` when the user's SIWC profile has a non-empty
`name` claim. The full-name value is percent-encoded UTF-8 and is accompanied by
`oai-authenticated-user-full-name-encoding: percent-encoded-utf-8`.
Treat the full name as optional and fall back to email when it is absent:
```tsx
import { headers } from "next/headers";
export default async function Home() {
const requestHeaders = await headers();
const email = requestHeaders.get("oai-authenticated-user-email");
const encodedFullName = requestHeaders.get("oai-authenticated-user-full-name");
const fullName =
encodedFullName &&
requestHeaders.get("oai-authenticated-user-full-name-encoding") ===
"percent-encoded-utf-8"
? decodeURIComponent(encodedFullName)
: null;
const displayName = fullName ?? email;
// ...
```json
{
"name": "员工姓名",
"employeeId": "员工工号"
}
```
## Optional Dispatch-Owned ChatGPT Sign-In
### 机台接口
Import the ready-to-use helpers from `app/chatgpt-auth.ts` when the site needs
optional or required ChatGPT sign-in:
可返回字符串数组,或包含 `machines` 的对象:
- Use `getChatGPTUser()` for optional signed-in UI.
- Use `requireChatGPTUser(returnTo)` for server-rendered pages that should send
anonymous visitors through Sign in with ChatGPT.
- Use `chatGPTSignInPath(returnTo)` and `chatGPTSignOutPath(returnTo)` for
browser links or actions.
- Pass a same-origin relative `returnTo` path for the destination after sign-in
or sign-out. The helper validates and safely encodes it.
- Mark protected pages with `export const dynamic = "force-dynamic"` because
they depend on per-request identity headers.
```json
{
"machines": [
{ "id": "机台号", "name": "机台名称" }
]
}
```
Dispatch owns `/signin-with-chatgpt`, `/signout-with-chatgpt`, `/callback`, the
OAuth cookies, and identity header injection. Do not implement app routes for
those reserved paths. Routes that do not import and call the helper remain
anonymous-compatible.
### 电子秤接口
SIWC establishes identity only; it does not prove workspace membership. Use the
Sites hosting platform's access policy controls for workspace-wide restrictions,
or enforce explicit server-side membership or allowlist checks.
使用 WebSocket。支持纯数字或 JSON 消息:
Use SIWC for account pages, user-specific dashboards, saved records, and write
actions tied to the current ChatGPT user. Leave public content anonymous.
```json
{ "weight": 2490, "unit": "g" }
```
## Useful Commands
内部统一换算为 kg。支持 `weightKg`、`weight`、`value` 字段和 `kg`、`g`、`lb` 单位。
- `npm run dev`: start local development
- `npm run build`: verify the vinext build output
- `npm test`: build the starter and verify its rendered loading skeleton
- `npm run db:generate`: generate Drizzle migrations after schema changes
### 上传接口
## Learn More
使用 HTTP POST,内容类型为 `application/json`,字段包括员工、机台、废料、重量和称重时间。
- [vinext Documentation](https://github.com/cloudflare/vinext)
- [Drizzle D1 Guide](https://orm.drizzle.team/docs/get-started/d1-new)
## 本地目录
- 图片:`/sdcard/smart/image/`
- 称重备份:`/sdcard/smart/cache/`
- 运行及导出日志:`/sdcard/smart/logs/`
## 开发与测试
要求 Node.js 22 或更高版本、pnpm、Android SDK 和 JDK 21。
```bash
pnpm install
pnpm test
pnpm run lint
```
Android Web 资源检查与打包:
```bash
cd android-app
pnpm install
pnpm exec tsc --noEmit
pnpm run build:web
pnpm exec cap copy android
cd android
./gradlew test assembleDebug
```
调试 APK 输出位置:
`android-app/android/app/build/outputs/apk/debug/app-debug.apk`