Prepare production smart scale Android app
This commit is contained in:
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user