# Preloaded Image Fallback Pattern for HTML Dashboards

When dashboards have per-record images (screenshots, instrument data, etc.) that
come from Excel but can't fit in localStorage (~5MB limit), use this pattern:

## Architecture

```
images.json (URL paths)          image files (on HTTP server)
───────────────────────          ┌─────────────────────────┐
{                                │ /数据/test_feedback_images/ │
  "0": ["/path/img_0_0.jpg"],    │   img_0_0.jpeg (101 KB)    │
  "1": ["/path/img_1_0.jpg"],    │   img_1_0.jpeg (104 KB)    │
  ...                            │   ...                      │
}                                └─────────────────────────┘
         │
         ▼
HTML page loads both data.json + images.json
  → localStorage empty? → use preloadedImages (file URLs)
  → localStorage has user uploads? → use uploadedImages (base64, editable)
```

## HTML Integration Pattern

```javascript
// Double-load: data + preloaded images
var preloadedImages = {};
Promise.all([
  fetch('/数据/test_feedback.json').then(r => r.json()),
  fetch('/数据/test_feedback_images/image_paths.json').then(r => r.json()).catch(() => ({}))
]).then(function(results) {
  DATA = results[0];
  preloadedImages = results[1];
  render();
});

// In render: merge localStorage + preloaded
var savedImgs = uploadedImages[key] || [];
var usePreloaded = (savedImgs.length === 0 && preloadedImages[key]);
var allImgs = usePreloaded ? preloadedImages[key] : savedImgs;

// Preloaded images are file URLs (read-only, no delete button)
// User-uploaded images are base64 (editable, stored in localStorage)
```

## When to Use

- Excel has embedded images (chat screenshots, experiment results) → extract to files
- Total base64 size > 5MB (exceeds localStorage) → use file URLs
- Images are read-only reference data (not user-editable) → preloaded
- User may want to add more images later → localStorage as override layer

## Pitfalls

1. **localStorage size limit**: Safari 5MB, Chrome 10MB. 43 images at 8.3MB raw = way over.
   Base64 encoding adds ~33% overhead. Always prefer file URLs for >10 images.

2. **File path vs base64**: preloadedImages URLs must be accessible from the page's HTTP
   context (same origin or CORS). Local `file://` paths won't work for fetch-loaded pages.

3. **Index stability**: Both localStorage keys and preloadedImages keys use filtered-list
   index (not record ID). Filters change the index → images show for wrong record.
   Solution: use immutable record IDs as keys, or preload only for unfiltered view.
