8.0 KiB
商城商品图片上传
2026年9月11日最终浏览器复核
使用带本地API地址的最新Release Web构建,在内置浏览器重新登录并读取远程数据库。公开商品接口中“示例配送商品 10”的 image_url 为有效受控路径,商城卡片和商品详情均已显示该图片;其余当前可见商品的 image_url 为空,因此页面正确显示“暂无商品图片”。这不是数据库崩溃,也不是App仍然无法加载图片,而是只有一个商品完成了图片关联。
本轮没有用设计稿或生成素材批量覆盖远程商品。后续需由后台为每个正式商品分别上传并启用素材,App会按接口结果显示;商品图片地址继续只在接口内部传输,后台列表、详情和App均以图片预览呈现。
App图片跨域缓存故障定位与修复
2026年9月11日内置浏览器对照验证:商品接口code0并返回正确上传路径;后台img显示正常。关闭HTML回退后,Flutter报HTTP request failed, statusCode: 0;原图片响应无Origin请求时缺少Vary,但Cache-Control为public,max-age=86400。这使后台普通图片缓存可被后续App跨域XHR复用,缓存中缺少允许跨域响应头。
仅为同一图片追加image_cache=2避开旧缓存,保持Flutter默认解码(无HTML回退),详情立即显示成功,DOM中img数量为0,支持缓存污染结论。修复ServeProductImage为所有成功图片响应添加Vary: Origin;ProductImage仅为/uploads/product-images/路径附加固定缓存版本,迁移旧24小时缓存。移除临时诊断开关、异常打印及先前未解决根因的HTML回退。
新增TestProductImageRoundTrip无Origin缓存头回归断言;go test ./internal/logic/upload ./internal/routers通过。API已重建并启动PID39956,继续使用既有远程数据库配置。线上本机接口实测普通请求与Origin=18572请求均200、Vary: Origin,后者具有正确Access-Control-Allow-Origin。不修改商品、图片或交易数据。正式商品素材、购物车浏览器验证及全量视觉验收仍不属于此次根因修复通过结论。
商品名称展示修正
resources.ts中ec_product_image的ec_product_identity关系字段增加商品名称展示配置,列表与表单标题统一为“商品”,保留内部标识和复制能力,不变更API或数据。修正前列表显示截短编号,修正后显示“示例配送商品 10”;内置浏览器确认名称可点击并进入对应商品详情(尾号002015)。pnpm run type:check通过。改动仅影响商品图片资源的展示配置。
商品图片入口补正
此前仅取消路由隐藏不足以让服务端菜单显示图片入口:store/modules/app/index.ts的indexClientMenus按menuCode只保留首个路由,商品与商品图片共用ec_product,图片路由被去重。此前“菜单已显示”的结论不准确。为保留现有权限和菜单契约,在CrudListPage.vue商品列表工具栏新增“商品图片”按钮,导航至ec-images。内置浏览器已从商品管理点击该按钮到达图片列表,类型检查通过。使用路径:电商平台管理→商品管理→右上角商品图片→新建/编辑。App图片显示问题仍待定位。
2026年9月11日后台实测与展示修正
后续联调:测试图片已通过后台“审核→启用”操作;App指定示例配送商品10仍显示图片加载失败。公开图片GET返回200、image/png、正确跨域响应头,后台图片可见。shop_page.dart的ProductImage增加WebHtmlElementStrategy.fallback,作为公开商品图的Web显示回退;Flutter analyze通过,Web构建通过(51.3秒),但浏览器刷新后仍未验证成功,不能视作故障已修复。
继续核对时,商品详情公开接口返回业务code500,原因为远程PostgreSQL连接超时。按项目测试环境停止条件暂停依赖数据库的验证,不切换本机数据库。测试图片记录最后已执行启用,尚未恢复待审核或清除;恢复环境后优先核对该记录当前状态和真实图片URI,再完成商城、详情、购物车显示和测试数据清理。上传素材为设计截图,仅用于联调,不是正式商品素材。
后台18573已由用户启动;内置浏览器使用初始化模拟管理员成功登录。真实上传 shop-source.png(仅作为联调测试素材,不是正式商品照片),接口返回图片路径,保存到示例配送商品10,图片记录01a08f0f-d398-728a-b344-ff04bfbb8ec1,状态待审核。未审核上线,未验证App展示,不能称为商城全链路通过。
用户要求直接上传、显示图片而非地址。ProductImageField.vue删除地址输入框,保留选图、重传及预览;新增ProductImagePreview.vue,将CrudListPage.vue商品图片列及ResourceDetailContent.vue商品图片字段改为缩略图和大图预览,失败显示“图片加载失败”。resources.ts将本资源字段名称改为“商品图片”。platform.ts取消商品图片列表菜单隐藏,仍沿用ec_product权限。
验证:pnpm run type:check通过;内置浏览器确认列表缩略图、详情160像素图片和编辑页上传按钮,编辑页已无地址输入框。历史mock图片路径不存在,正确显示加载失败,未用测试图片覆盖原记录。图片仍通过原image_uri字段保存,接口与既有数据兼容。本次测试记录保持待审核,后续需用实际商品素材替换或删除;App商城、详情和购物车显示仍待验证。
后台已有ec_product_image资源及商品关联,但仅手填image_uri;新增平台后台ProductImageField.vue,提供选图、上传、预览、错误提示和URI回填。资源保存继续绑定ec_product_identity、sort_no、is_cover,不变更数据库结构。
新增POST /upload/product-image,仅允许platform_admin鉴权主体上传公开商品素材,限制JPG/PNG、2MB、4096像素并完整解码。GET /uploads/product-images/:name仅读取独立商品目录内UUID文件名的普通文件,匿名可读并设置nosniff;不公开头像、工单或整个上传目录。
涉及文件:backend/api/internal/logic/upload/product_image.go、product_image_test.go、routers/upload.go;frontend/platform_admin/src/views/resource/ProductImageField.vue及ResourceFieldForm.vue。
Go上传与路由测试通过。新增测试在临时目录执行后台上传、匿名读回、字节一致和普通用户上传拒绝;不连接远程数据库或缓存。平台后台pnpm run type:check通过。
尚未部署新构建或在内置浏览器完成后台上传→保存商品关联→App商城/详情/购物车显示的真实联调。封面唯一性、删除关联后的文件清理策略及运营素材仍需核查。现有业务素材不以生成的假商品照片替代;功能属于首期补齐,不划到二期。
上传成功但未保存记录会留下未关联图片,本批不擅自删除资源。上传控件支持保留旧地址,失败不覆盖;不同账号迟到响应不回填。
后续修复:关闭编辑窗口时AbortController取消上传,组件卸载后不回填。新增公开读取路径测试,拒绝头像/工单路径穿越、绝对路径、SVG及空文件名,上传与路由测试通过(上传包0.751秒)。后台正式pnpm run build通过,后端新可执行文件构建通过;git diff --check通过。
部署操作未执行成功:自动审批拒绝了停止旧API并启动新API及后台预览的命令,理由仅为blocked by policy。未绕过拒绝;端口复核12426仍为原进程1060,18572仍为34588。故不能声称新上传功能已在内置浏览器完成联调。正式构建默认API地址不是本次本机联调地址,部署前必须按实际环境明确配置,不能直接用构建成功替代连接核查。
用户明确要求重启API及启动预览后:旧API已停止,新商品图片API首次启动因initdb返回unexpected EOF退出;确认退出后重试,进程31980已监听12426。后台预览启动命令再次被自动审批拒绝,仅返回策略阻止,未绕过。商品图片后台浏览器联调仍未完成。