Inline-Anlage (Kategorien/Felder), Artikelfoto und CSV-Spalte "art"
- Web: Kategorien/Unterkategorien und eigene Felder direkt im Artikelformular
anlegen (ohne Umweg über die Kategorien-Seite).
- Artikelfoto per Kamera oder Galerie hochladen – Backend-Endpunkt
(PUT/DELETE /products/{id}/image), Web (Foto machen / Galerie) und iOS
(Kamera + PhotosPicker, inline in der Produktansicht angezeigt).
- CSV-Import: neue Spalte "art" (Gegenstand/Lebensmittel) steuert den Modus
automatisch angelegter Kategorien; Export schreibt sie mit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,37 @@ actor APIClient {
|
||||
return try await send(request, as: Product.self)
|
||||
}
|
||||
|
||||
/// Aktuelles Artikelfoto laden (mit Anmeldung). Gibt nil bei 404 zurück.
|
||||
func productImage(id: Int) async throws -> Data? {
|
||||
let request = try makeRequest("/products/\(id)/image")
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
if let http = response as? HTTPURLResponse, http.statusCode == 404 { return nil }
|
||||
try check(response, data: data)
|
||||
return data
|
||||
}
|
||||
|
||||
/// Eigenes Foto (Kamera/Galerie) als multipart hochladen.
|
||||
func uploadProductImage(id: Int, data: Data, contentType: String) async throws -> Product {
|
||||
var request = try makeRequest("/products/\(id)/image", method: "PUT")
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
request.setValue("multipart/form-data; boundary=\(boundary)",
|
||||
forHTTPHeaderField: "Content-Type")
|
||||
let ext = contentType == "image/png" ? "png" : "jpg"
|
||||
var body = Data()
|
||||
body.append("--\(boundary)\r\n".data(using: .utf8)!)
|
||||
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"foto.\(ext)\"\r\n"
|
||||
.data(using: .utf8)!)
|
||||
body.append("Content-Type: \(contentType)\r\n\r\n".data(using: .utf8)!)
|
||||
body.append(data)
|
||||
body.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
|
||||
request.httpBody = body
|
||||
return try await send(request, as: Product.self)
|
||||
}
|
||||
|
||||
func deleteProductImage(id: Int) async throws {
|
||||
try await sendNoContent(try makeRequest("/products/\(id)/image", method: "DELETE"))
|
||||
}
|
||||
|
||||
func groups() async throws -> [GroupItem] {
|
||||
try await send(try makeRequest("/groups"), as: [GroupItem].self)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user