chore: initialize mini program frontend

This commit is contained in:
souplearn
2026-06-24 15:19:14 +08:00
commit fa73a3c184
96 changed files with 20561 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
# 嘉恒智能报工小程序接口边界
小程序端不能直连 MySQL。生产环境需要一个 HTTPS 后端服务,使用环境变量读取数据库连接信息,并调用微信服务端接口完成手机号解密、订阅通知和小程序码生成。
## Excel 字段
本次读取到的 `/Users/souplearn/Downloads/产品清单.xlsx` 表头为:
`项目号、型材号、产品名称、物料编码、物料名称、使用设备、工序、冲压方式、操作人数、不包含物料转运节拍、标准节拍`
导入产品时:
- `型材号` 保存到 `products.profile_no`。
- `使用设备` 保存到 `products.device_no`。
- `不包含物料转运节拍` 忽略,不进入小程序业务。
- `标准工作量` 如果 Excel 没有提供,由后端按 `28800 / 标准节拍` 生成 8 小时日标准量。
- Excel 中空白 `项目号` 建议沿用上一行项目号,导入前端也应展示导入预览和错误行。
## 推荐接口
### 登录
- `POST /api/auth/wechat-login`
- `GET /api/auth/me`:获取当前账号和同一手机号下的所有角色。
- `POST /api/auth/switch-role`:已登录账号切换当前角色,返回新的 token。
- 入参:`code`、`encryptedData`、`iv` 或新版本手机号授权凭证。
- 逻辑:获取手机号后,在 `personnel` 表匹配;多个手机号时返回人员表中存在的手机号供用户选择。
- 返回:当前人员、角色、token。
### 产品
- `POST /api/products/import`:上传《产品清单》Excel,解析并 upsert。
- `GET /api/products`:分页、关键词、设备号筛选。
- `POST /api/products`:新增或修改产品。
- `DELETE /api/products`:按 `project_no + product_name + device_no + process_name` 删除产品。
产品唯一键为:`项目号 + 产品名称 + 使用设备号 + 工序`。
### 人员
- `POST /api/people/import`:上传《人员清单》Excel,字段为电话号、姓名、角色。
- `GET /api/people`:分页和关键词筛选。
- `POST /api/people`:新增或修改人员。
- `DELETE /api/people/:phone?role=worker`:删除手机号下的某个角色。
人员口径:一个手机号绑定一个姓名,同一手机号可以有多个角色;登录时如果该手机号只有一个角色,直接登录,如果有多个角色,小程序会要求选择本次登录角色。
### 设备二维码
- `POST /api/devices/:deviceNo/qrcode`
- 后端调用微信 `getUnlimitedQRCode`,scene 建议为 `deviceNo=20%23`,page 为 `pages/clock/clock`。
- 返回可打印的小程序码图片地址。
### 扫码报工
- `GET /api/clock/state?deviceNo=20%23`
- `POST /api/clock/start`
- `POST /api/clock/switch-device`
- `POST /api/clock/finish`
状态规则:
- 没有 active session:只返回 `开始上班`。
- 有 active session 且设备没出现过:只返回 `换设备`。
- 有 active session 且设备出现过:只返回 `下班报工`。
- 点击 `下班报工` 后进入 reporting session,30 分钟内返回 `继续报工`,员工可继续填写原报工。
- 超过 30 分钟未提交时返回 `重新报工`,员工点击后更新下班时间为重新报工时间,再重新填写报工。
### 报工提交
- `GET /api/reports/draft?sessionId=...`:按设备号拉取产品候选项。
- `POST /api/reports`:员工确认提交,`report_date` 使用确认提交当天日期。
- 报工草稿和提交都会校验 30 分钟填写有效期;超时必须重新扫码点击 `重新报工`。
- `GET /api/reports/mine`:员工按日期查看自己的报工记录。
### 审核
- `GET /api/reviews/pending`:管理员待审核报工。
- `POST /api/reviews/:reportId/approve`:管理员通过,或修正明细后通过。
- `POST /api/reviews/:reportId/reject`:管理员驳回并写原因。
- `PATCH /api/reports/:reportId/break-minutes`:仅经理可修改休息间隔,必须写 `report_audit_logs`。
- `GET /api/reviews/mine`:管理员自己的审核记录,支持日期筛选。
### 经理看板
- `GET /api/dashboard/reports?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD&page=1`
- 后端只统计 `approved` 报工,并按 `report_date + employee_phone` 合并。
- 返回实际节拍、标准节拍、节拍正负百分比、报工数量、标准工作量、工作量正负百分比。
## 关键计算口径
- 报工日期:员工点击提交后再确认的日期。
- 有效工时:`下班时间 - 上班时间 - 休息间隔`,休息间隔只能经理修改。
- 实际节拍:`有效工时秒数 / (成品数量 + 不良数量)`,报废计入不良数量。
- 标准节拍:按明细产出数量加权平均。
- 标准工作量:使用产品表导入或手动维护的 `标准工作量`,多条明细时累加。
- 工作量对比:`(成品数量 - 标准工作量) / 标准工作量`。
+144
View File
@@ -0,0 +1,144 @@
-- 嘉恒智能报工小程序 MySQL schema
-- 建议 MySQL 8.0+,字符集统一 utf8mb4。
CREATE TABLE IF NOT EXISTS personnel (
phone VARCHAR(20) NOT NULL COMMENT '电话号',
name VARCHAR(64) NOT NULL COMMENT '姓名',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='人员表';
CREATE TABLE IF NOT EXISTS person_roles (
phone VARCHAR(20) NOT NULL COMMENT '电话号',
role ENUM('worker', 'admin', 'manager') NOT NULL COMMENT '角色',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (phone, role),
CONSTRAINT fk_person_roles_person FOREIGN KEY (phone) REFERENCES personnel(phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='人员角色表';
CREATE TABLE IF NOT EXISTS products (
project_no VARCHAR(64) NOT NULL COMMENT '项目号',
product_name VARCHAR(255) NOT NULL COMMENT '产品名称',
profile_no VARCHAR(128) NULL COMMENT '型材号,来自现有产品清单',
material_code VARCHAR(128) NULL COMMENT '物料编码',
material_name VARCHAR(255) NULL COMMENT '物料名称',
supplier VARCHAR(255) NULL COMMENT '供应商',
device_no VARCHAR(64) NOT NULL COMMENT '使用设备号',
process_name VARCHAR(128) NOT NULL COMMENT '工序',
stamping_method VARCHAR(128) NULL COMMENT '冲压方式',
operator_count DECIMAL(10,2) NOT NULL DEFAULT 1 COMMENT '操作人数',
standard_beat DECIMAL(12,3) NOT NULL COMMENT '标准节拍,秒/件',
standard_workload DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '标准工作量,建议按8小时折算',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (project_no, product_name, device_no, process_name),
KEY idx_products_device_no (device_no),
KEY idx_products_material_code (material_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品表';
CREATE TABLE IF NOT EXISTS work_sessions (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
employee_phone VARCHAR(20) NOT NULL,
start_at DATETIME NOT NULL,
end_at DATETIME NULL,
status ENUM('active', 'reporting', 'submitted', 'cancelled') NOT NULL DEFAULT 'active',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_sessions_employee_status (employee_phone, status),
CONSTRAINT fk_sessions_employee FOREIGN KEY (employee_phone) REFERENCES personnel(phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='扫码上班流程';
CREATE TABLE IF NOT EXISTS work_session_devices (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
session_id BIGINT UNSIGNED NOT NULL,
device_no VARCHAR(64) NOT NULL,
scanned_at DATETIME NOT NULL,
sort_order INT NOT NULL DEFAULT 0,
PRIMARY KEY (id),
UNIQUE KEY uk_session_device (session_id, device_no),
KEY idx_session_devices_device (device_no),
CONSTRAINT fk_session_devices_session FOREIGN KEY (session_id) REFERENCES work_sessions(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='一次报工流程中的设备序列';
CREATE TABLE IF NOT EXISTS production_reports (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
session_id BIGINT UNSIGNED NOT NULL,
employee_phone VARCHAR(20) NOT NULL,
report_date DATE NOT NULL COMMENT '以员工确认提交日期为准',
start_at DATETIME NOT NULL,
end_at DATETIME NOT NULL,
duration_minutes DECIMAL(10,2) NOT NULL DEFAULT 0,
break_minutes DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '休息间隔,仅经理可改',
effective_minutes DECIMAL(10,2) NOT NULL DEFAULT 0,
total_good_qty DECIMAL(12,2) NOT NULL DEFAULT 0,
total_output_qty DECIMAL(12,2) NOT NULL DEFAULT 0,
actual_beat DECIMAL(12,3) NOT NULL DEFAULT 0,
standard_beat DECIMAL(12,3) NOT NULL DEFAULT 0,
expected_workload DECIMAL(12,2) NOT NULL DEFAULT 0,
pace_rate DECIMAL(10,2) NOT NULL DEFAULT 0,
workload_rate DECIMAL(10,2) NOT NULL DEFAULT 0,
status ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending',
reviewer_phone VARCHAR(20) NULL,
reviewed_at DATETIME NULL,
reject_reason VARCHAR(500) NULL,
submitted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uk_report_session (session_id),
KEY idx_reports_employee_date (employee_phone, report_date),
KEY idx_reports_status_date (status, report_date),
KEY idx_reports_reviewer (reviewer_phone, reviewed_at),
CONSTRAINT fk_reports_session FOREIGN KEY (session_id) REFERENCES work_sessions(id),
CONSTRAINT fk_reports_employee FOREIGN KEY (employee_phone) REFERENCES personnel(phone),
CONSTRAINT fk_reports_reviewer FOREIGN KEY (reviewer_phone) REFERENCES personnel(phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报工主表';
CREATE TABLE IF NOT EXISTS production_report_items (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
report_id BIGINT UNSIGNED NOT NULL,
device_no VARCHAR(64) NOT NULL,
project_no VARCHAR(64) NOT NULL,
product_name VARCHAR(255) NOT NULL,
material_code VARCHAR(128) NULL,
material_name VARCHAR(255) NULL,
process_name VARCHAR(128) NULL,
standard_beat DECIMAL(12,3) NOT NULL DEFAULT 0,
standard_workload DECIMAL(12,2) NOT NULL DEFAULT 0,
good_qty DECIMAL(12,2) NOT NULL DEFAULT 0,
defect_qty DECIMAL(12,2) NOT NULL DEFAULT 0,
scrap_qty DECIMAL(12,2) NOT NULL DEFAULT 0,
allocated_minutes DECIMAL(10,2) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_report_items_report (report_id),
KEY idx_report_items_product (project_no, product_name),
CONSTRAINT fk_report_items_report FOREIGN KEY (report_id) REFERENCES production_reports(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报工明细';
CREATE TABLE IF NOT EXISTS report_audit_logs (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
report_id BIGINT UNSIGNED NOT NULL,
reviewer_phone VARCHAR(20) NOT NULL,
action ENUM('approve', 'approve_with_correction', 'reject', 'manager_break_update') NOT NULL,
before_json JSON NULL,
after_json JSON NULL,
remark VARCHAR(500) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_audit_report (report_id),
KEY idx_audit_reviewer (reviewer_phone, created_at),
CONSTRAINT fk_audit_report FOREIGN KEY (report_id) REFERENCES production_reports(id),
CONSTRAINT fk_audit_reviewer FOREIGN KEY (reviewer_phone) REFERENCES personnel(phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审核记录';
CREATE TABLE IF NOT EXISTS device_qrcodes (
device_no VARCHAR(64) NOT NULL,
qr_scene VARCHAR(128) NOT NULL,
qr_url VARCHAR(500) NULL,
created_by VARCHAR(20) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (device_no),
CONSTRAINT fk_qrcode_creator FOREIGN KEY (created_by) REFERENCES personnel(phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备二维码';
+9
View File
@@ -0,0 +1,9 @@
MYSQL_HOST=121.40.97.156
MYSQL_PORT=3306
MYSQL_DATABASE=jiaheng_erp
MYSQL_USER=root
MYSQL_PASSWORD=change_me
WECHAT_APP_ID=your_app_id
WECHAT_APP_SECRET=your_app_secret
JWT_SECRET=change_me
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff