feat: 上传素材

This commit is contained in:
jinyaqiu 2025-08-20 13:15:55 +08:00
parent 6a05bd0dc2
commit 4b11885d21
4 changed files with 98 additions and 59 deletions

View File

@ -507,16 +507,49 @@ struct PhotoPicker: UIViewControllerRepresentable {
case .success(let results):
uploadResults[index] = results
// Upload file info to backend
MaterialService.shared.uploadMaterialInfo(
fileId: results.original.fileId,
previewFileId: results.compressed.fileId
) { success, errorMessage in
if success {
print("✅ 文件信息上传成功")
} else if let errorMessage = errorMessage {
print("❌ 文件信息上传失败: \(errorMessage)")
// 使 NetworkService
let parameters: [String: Any] = [
"file_id": results.original.fileId,
"preview_file_id": results.compressed.fileId
]
//
let requestBody: [[String: Any]] = [parameters]
//
struct MaterialResponse: Decodable {
let success: Bool
let message: String?
}
// 使 URLSession
do {
let jsonData = try JSONSerialization.data(withJSONObject: requestBody)
var request = URLRequest(url: URL(string: "\(APIConfig.baseURL)/material")!)
request.httpMethod = "POST"
request.allHTTPHeaderFields = APIConfig.authHeaders
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("❌ 文件信息上传失败: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
if (200...299).contains(httpResponse.statusCode) {
print("✅ 文件信息上传成功")
} else {
let statusCode = httpResponse.statusCode
let errorMessage = String(data: data ?? Data(), encoding: .utf8) ?? ""
print("❌ 服务器返回错误状态码: \(statusCode), 响应: \(errorMessage)")
}
}
}
task.resume()
} catch {
print("❌ 请求数据序列化失败: \(error.localizedDescription)")
}
case .failure(let error):

View File

@ -17,10 +17,12 @@ class MaterialService {
previewFileId: String,
completion: @escaping (Bool, String?) -> Void) {
let materialData: [[String: String]] = [[
"file_id": fileId,
"preview_file_id": previewFileId
]]
let materialData: [String: Any] = [
"material": [
"file_id": fileId,
"preview_file_id": previewFileId
]
]
guard let url = URL(string: "\(APIConfig.baseURL)/material") else {
completion(false, "无效的URL")
@ -46,7 +48,8 @@ class MaterialService {
completion(true, nil)
} else {
let statusCode = httpResponse.statusCode
completion(false, "服务器返回错误状态码: \(statusCode)")
let errorMessage = String(data: data ?? Data(), encoding: .utf8) ?? ""
completion(false, "服务器返回错误状态码: \(statusCode), 响应: \(errorMessage)")
}
} else {
completion(false, "无效的服务器响应")

View File

@ -10,7 +10,6 @@ struct UserInfo: View {
@State private var darkModeEnabled = false
@State private var showLogoutAlert = false
@State private var avatarImage: UIImage? // Add this line
@State private var name: String = ""
var body: some View {
VStack(spacing: 0) {
@ -40,49 +39,53 @@ struct UserInfo: View {
.font(Typography.font(for: .title))
.frame(maxWidth: .infinity, alignment: .center)
// Avatar section
VStack {
Text("your name")
.font(.headline)
.padding(.bottom, 10)
// Avatar
ZStack {
// Show either the SVG or the uploaded image
if let avatarImage = avatarImage {
Image(uiImage: avatarImage)
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.clipShape(Circle())
} else {
SVGImage(svgName: "Avatar")
.frame(width: 200, height: 200)
}
// Avatar image or placeholder
Circle()
.fill(Color.gray.opacity(0.3))
.frame(width: 100, height: 100)
.overlay(
Image(systemName: "person.fill")
.resizable()
.scaledToFit()
.foregroundColor(.white)
.padding(30)
)
// Make sure the AvatarUploader is on top and covers the entire area
AvatarUploader(selectedImage: $avatarImage, size: 200)
.contentShape(Rectangle()) // This makes the entire area tappable
}
.padding(.top, 30)
.frame(width: 200, height: 200)
.padding(.vertical, 20)
// Name input field
TextField("Enter your name", text: $name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal, 40)
.padding(.top, 20)
Spacer()
// Next/Open button
// Buttons
Button(action: {
// Action for open button
// Action for first button
}) {
Text("Open")
Text("Upload from Gallery")
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 25)
.fill(Color(red: 1.0, green: 0.973, blue: 0.871))
)
}
Button(action: {
// Action for second button
}) {
Text("Take a Photo")
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 25)
.fill(Color(red: 1.0, green: 0.714, blue: 0.271))
.fill(Color(red: 1.0, green: 0.973, blue: 0.871))
)
}
.padding(.bottom, 30)
.padding(.horizontal, 20)
}
.padding()
.background(Color(.white))

View File

@ -43,8 +43,8 @@ struct WakeApp: App {
} else {
//
if authState.isAuthenticated {
//
ContentView()
// userInfo
UserInfo()
.environmentObject(authState)
} else {
//
@ -54,12 +54,12 @@ struct WakeApp: App {
}
}
.onAppear {
// 3
// DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
// withAnimation {
// showSplash = false
// }
// }
//3
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
withAnimation {
showSplash = false
}
}
}
}
.modelContainer(container)
@ -91,10 +91,10 @@ struct WakeApp: App {
}
// 3
// DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
// withAnimation {
// showSplash = false
// }
// }
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
withAnimation {
showSplash = false
}
}
}
}