端上:#47~#55 打包 —— 行程双轨、动态类型、表单全局规范 (#53)
#48 计划/实际双轨:nodeAction(start/done/cancel),完成即转实际行程, 实际行程不再显示状态;新增 actualStartedAt/actualEndedAt #49 类型/出行方式/车辆 chip 改内部读状态(@Builder 值传参不刷新) #50 类型点击立即变色、出行方式平铺、参与人显示已选头像 #51 节点类型动态加载(原硬编码5种)、地址 onPick 拿详细地址与坐标 #52 标签改主题色 Bold、必填红无星号、编辑行程标题同步 #53 表单两排版式(标签独占一行解决左右对不齐);电影弹层 layoutWeight 修滚动 #54 地址联想框加时间窗抑制(600ms 内不搜)、候选限高 180 含附件回填诊断日志(DIAG-ATTACH/FILL),待真机确认后移除
This commit is contained in:
@@ -46,6 +46,73 @@ export async function fbUploadOne(path: string, field: string, uri: string,
|
||||
return r.ok ? '' : r.error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂存上传:把文件传到暂存区,返回**令牌**。
|
||||
*
|
||||
* 🔴 2026-11-05。用户:「先上传,拿到地址,然后提交的时候,连带着跟其他参数一起提交,
|
||||
* 后台接口拿到数据,先插入行程,拿到 id,再把图片插入进去。」
|
||||
*
|
||||
* 这是「新增时也能挂照片」的关键:新增行程时节点还不存在,
|
||||
* 只能先把文件暂存起来拿 stoken,等保存表单时把 stoken 一起提交,
|
||||
* 服务端建完节点再 `claim` 上去。
|
||||
*
|
||||
* @param uri picker 给的文件 URI
|
||||
* @param token 访问令牌
|
||||
* @returns stoken 为空串 = 失败(看 error)
|
||||
*/
|
||||
export interface FbStageUpload {
|
||||
/** 暂存令牌(空 = 失败) */
|
||||
stoken: string;
|
||||
/** 原始文件名 */
|
||||
name: string;
|
||||
/** 是否图片(服务端按 MIME 嗅探) */
|
||||
isImage: boolean;
|
||||
/** 预览地址(相对路径) */
|
||||
url: string;
|
||||
/** 错误说明(成功时为空) */
|
||||
error: string;
|
||||
}
|
||||
|
||||
export async function fbUploadStage(uri: string, token: string): Promise<FbStageUpload> {
|
||||
const out: FbStageUpload = {
|
||||
stoken: '', name: '', isImage: false, url: '', error: ''
|
||||
};
|
||||
const r: FbUploadRaw = await fbUploadRaw('/api/v1/uploads/stage', 'file', uri, token);
|
||||
if (!r.ok) {
|
||||
out.error = r.error !== '' ? r.error : '上传失败';
|
||||
return out;
|
||||
}
|
||||
/* 服务端信封:{ok:true, data:{stoken,...}}(`fbApi` 层已拆过一层,
|
||||
但 multipart 这条路是自己解析的,要按原始信封读) */
|
||||
try {
|
||||
const env: Record<string, Object> = JSON.parse(r.body) as Record<string, Object>;
|
||||
let dataObj: Record<string, Object> = env;
|
||||
const nested: Object | undefined = env['data'];
|
||||
if (nested !== undefined) {
|
||||
dataObj = nested as Record<string, Object>;
|
||||
}
|
||||
const st: Object | undefined = dataObj['stoken'];
|
||||
if (typeof st === 'string' && st !== '') {
|
||||
out.stoken = st as string;
|
||||
}
|
||||
const nm: Object | undefined = dataObj['name'];
|
||||
if (typeof nm === 'string') {
|
||||
out.name = nm as string;
|
||||
}
|
||||
out.isImage = dataObj['is_image'] === true;
|
||||
const u: Object | undefined = dataObj['url'];
|
||||
if (typeof u === 'string') {
|
||||
out.url = u as string;
|
||||
}
|
||||
if (out.stoken === '') {
|
||||
out.error = '服务端没返回令牌';
|
||||
}
|
||||
} catch (err) {
|
||||
out.error = '响应解析失败';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片并**拿回响应载荷**(工单 #23 用)。
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user