Files
UUVPN/iOS-SwiftUI-Code/XiaoXiong/DefaultUI/View/SupportTicketView.swift
T
2025-01-22 14:09:10 +08:00

531 lines
19 KiB
Swift

//
// SupportticketView.swift
// SFI
//
// Created by Mac on 2024/10/20.
//
import Foundation
import SwiftUI
import ApplicationLibrary
struct SupportTicketView : View {
var edges = getSafeAreaInsets()
@State var selectedTab = "Chats"
@Namespace var animation
@Environment(\.presentationMode) var presentationMode // 环境变量用于控制视图的呈现
@State private var TicketsList: [TicketsReponseDatum] = []
@State private var isLoading = false
@State private var errorMessage: String?
@State private var alert: Alert?
@State private var showInputSheet = false
@State private var tickettitle = ""
@State private var userInput = ""
@State private var isInputLoading = false
@State private var submitmessage = ""
var body: some View{
NavigationView(content: {
VStack(spacing: 0){
VStack{
ZStack{
HStack{
Button(action: {
presentationMode.wrappedValue.dismiss() // 手动触发返回
}, label: {
Image(systemName: "chevron.left")
.foregroundColor(.white)
Text("返回")
.foregroundColor(.white)
}).padding(10) // 增加可点击区域
Spacer(minLength: 0)
Button(action: {
showInputSheet.toggle()
}, label: {
// Image(systemName: "note.text.badge.plus")
Text("提交新工单").foregroundColor(.red)
})
}
Text("我的工单").fontWeight(.bold).lineLimit(1)
}
.padding()
// .padding(.top,edges.top)
.foregroundColor(.white)
// HStack(spacing: 20){
//
// ForEach(tabs,id: \.self){title in
//
// TabButton(selectedTab: $selectedTab, title: title, animation: animation)
// }
// }
// .padding()
// .background(Color.white.opacity(0.08))
// .cornerRadius(15)
// .padding(.vertical)
}
.padding(.bottom)
// .background(Color("top"))
// .clipShape(CustomCorner(corner: .bottomLeft, size: 65))
ZStack{
// Color("top")
// Color("bg")
// .clipShape(CustomCorner(corner: .topRight, size: 65))
ScrollView(.vertical, showsIndicators: false, content: {
VStack(spacing: 20){
/*HStack{
Text("All Chats")
.font(.title2)
.fontWeight(.bold)
Spacer(minLength: 0)
Button(action: {}, label: {
Image(systemName: "slider.horizontal.3")
.font(.system(size: 22))
.foregroundColor(.primary)
})
}
.padding([.horizontal,.top])*/
if isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
.padding()
}
if let errorMessage = errorMessage {
Text(errorMessage)
.bold()
.foregroundColor(.red)
.multilineTextAlignment(.center) // 确保多行文本居中
.padding()
}
if TicketsList.count > 0 {
ForEach(TicketsList){chatData in
// Chat View...
NavigationLink(destination: SupportTicketChatView(ticketID: chatData.idOLD)) {
ChatView(chatData: chatData)
}
}
}else{
if !isLoading
{
Text("暂无记录").font(.caption)
.foregroundColor(.gray)
.multilineTextAlignment(.center) // 确保多行文本居中
.padding()
}
}
}
.padding(.vertical)
})
//.clipShape(CustomCorner(corner: .topRight, size: 65))
// its cutting off inside view may be its a bug....
}
}.onAppear(){
Task{
await getPlanList()
}
}
.navigationBarHidden(true)
//.background(Color("bg").ignoresSafeArea(.all, edges: .all))
.background(
LinearGradient(colors: [
Color("BG1"),
Color("BG1"),
Color("BG2"),
Color("BG2"),
], startPoint: .top, endPoint: .bottom).ignoresSafeArea(.all, edges: .all))
// .ignoresSafeArea(.all, edges: .top)
.sheet(isPresented: $showInputSheet) {
InputSheet(tickettitle: $tickettitle, userInput: $userInput, isInputLoading: $isInputLoading, submitmessage: $submitmessage, onSubmit: {
Task {
// 提交网络请求
await submitTicketData(title: tickettitle, userInput: userInput)
}
})
}
})
.navigationBarHidden(true)
.alertBinding($alert)
.navigationBarBackButtonHidden(true) // 隐藏返回按钮
}
public func submitTicketData(title: String, userInput: String) async{
isInputLoading = true
let userInfoUrl = URL(string: "\(UserManager.shared.baseURL())user/ticket/save?subject=\(title)&level=0&message=\(userInput)")!
var request = URLRequest(url: userInfoUrl)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(UserManager.shared.getAutoData(), forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
isInputLoading = false
if let error = error {
submitmessage = ( "数据请求失败: \(error.localizedDescription)")
return
}
guard let data = data else {
submitmessage = ( "数据请求失败")
return
}
// MARK: - TicketSendMsgReponse
struct TicketSendMsgReponse: Codable {
let status, message: String?
}
// Parse the user info response
if let SendMsgReponse = try? JSONDecoder().decode(TicketSendMsgReponse.self, from: data), let message = SendMsgReponse.message {
if let stutas = SendMsgReponse.status , stutas == "success" {
submitmessage = message
//1s 后 关闭窗口
withAnimation {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
showInputSheet = false
//刷新界面
Task{
await getPlanList()
}
}
}
}else{
submitmessage = (message)
}
}else{
submitmessage = ( "数据请求失败: JSON 解析错误")
}
}
}
task.resume()
}
public func getPlanList() async {
isLoading = true
errorMessage = nil
let userInfoUrl = URL(string: "\(UserManager.shared.baseURL())user/ticket/fetch")!
var request = URLRequest(url: userInfoUrl)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(UserManager.shared.getAutoData(), forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
self.isLoading = false
if let error = error {
self.errorMessage = "数据请求失败: \(error.localizedDescription)"
return
}
guard let data = data else {
self.errorMessage = "数据请求失败"
return
}
// Parse the user info response
if let Subscribe = try? JSONDecoder().decode(TicketsReponse.self, from: data) {
if let data = Subscribe.data {
TicketsList = data
}else{
self.errorMessage = Subscribe.message ?? ""
}
}else{
self.errorMessage = "数据请求失败: JSON 解析错误"
}
}
}
task.resume()
}
}
var tabs = ["Chats","Status","Calls"]
struct TabButton : View {
@Binding var selectedTab : String
var title : String
var animation : Namespace.ID
var body: some View{
Button(action: {
withAnimation{
selectedTab = title
}
}, label: {
Text(title)
.foregroundColor(.white)
.padding(.vertical,10)
.padding(.horizontal)
// Sliding Effect...
.background(
ZStack{
if selectedTab == title{
RoundedRectangle(cornerRadius: 10)
.fill(Color("top"))
.matchedGeometryEffect(id: "Tab", in: animation)
}
}
)
})
}
}
struct CustomCorner : Shape {
var corner : UIRectCorner
var size : CGFloat
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corner, cornerRadii: CGSize(width: size, height: size))
return Path(path.cgPath)
}
}
struct ChatView : View {
var chatData : TicketsReponseDatum
var body: some View{
HStack(spacing: 10){
VStack(spacing: 12) {
HStack {
VStack(alignment: .leading, spacing: 8, content: {
Text(chatData.subject)
.fontWeight(.bold)
.lineLimit(1).foregroundColor(.white)
// Text("官方回复:\(chatData.message ?? "未回复")")
// .font(.caption)
// .lineLimit(1)
HStack(content: {
if(chatData.status == 1){
Text("工单状态 : 已关闭").fontWeight(.light).foregroundColor(.gray).font(.subheadline)
}else if(chatData.status == 0){
Text("工单状态 : 待回复").fontWeight(.light).foregroundColor(.red).font(.subheadline)
}else if(chatData.status == 2){
Text("工单状态 : 已回复").fontWeight(.light).foregroundColor(.green).font(.subheadline)
}
Spacer(minLength: 0)
Text("\(TimestampConverter.convertTimestampToDateString(chatData.updatedAt))")
.font(.subheadline).foregroundColor(.white)
})
})
}
Divider()
}
}
.padding(.horizontal)
}
}
// Model And Sample Data....
//
//struct Chat : Identifiable {
//
// var id = UUID().uuidString
// var name : String
// var image : String
// var msg : String
// var time : String
//}
//
//// were going to do custom grouping of views....
//
//struct HomeData {
//
// var groupName : String
// var groupData : [Chat]
//}
//var FriendsChat : [Chat] = [
//
// Chat(name: "iJustine",image: "p0", msg: "Hey EveryOne !!!", time: "02:45"),
// Chat(name: "Kavsoft",image: "p1", msg: "Learn - Develop - Deploy", time: "03:45"),
// Chat(name: "SwiftUI",image: "p2", msg: "New Framework For iOS", time: "04:55"),
// Chat(name: "Bill Gates",image: "p3", msg: "Founder Of Microsoft", time: "06:25"),
// Chat(name: "Tim Cook",image: "p4", msg: "Apple lnc CEO", time: "07:19"),
// Chat(name: "Jeff",image: "p5", msg: "I dont Know How To Spend Money :)))", time: "08:22"),
//]
//
//var GroupChat : [Chat] = [
//
// Chat(name: "iTeam",image: "p0", msg: "Hey EveryOne !!!", time: "02:45"),
// Chat(name: "Kavsoft - Developers",image: "p1", msg: "Next Video :))))", time: "03:45"),
// Chat(name: "SwiftUI - Community",image: "p2", msg: "New File Importer/Exporter", time: "04:55"),
//]
//
//var data = [
//
// // Group 1
// HomeData(groupName: "", groupData: FriendsChat),
//]
struct InputSheet: View {
@Binding var tickettitle: String
@Binding var userInput: String
@Binding var isInputLoading: Bool
@Binding var submitmessage:String
var onSubmit: () -> Void
var body: some View {
VStack(spacing: 20) {
Spacer()
Text("新的工单").fontWeight(.bold).lineLimit(1)
Text("请输入工单标题").font(.subheadline) .foregroundColor(.gray)
.frame(maxWidth: .infinity)
.multilineTextAlignment(.leading)
.padding(.leading, 5) // 添加左侧内边距
.padding(.top, 8) // 添加顶部内边距
TextEditor( text: $tickettitle)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
.frame(width: UIScreen.main.bounds.width * 0.9,height: 50)
.background(Color.clear) // 设置背景为透明
.cornerRadius(10) // 圆角
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray.opacity(0.5), lineWidth: 1)
) // 添加边框
.background(Color.clear) // 设置背景为透明// 添加边框
.font(.system(size: 18))
.transparentScrolling()
Text("请输入工单内容").font(.subheadline) .foregroundColor(.gray)
.frame(maxWidth: .infinity)
.padding(.leading, 5) // 添加左侧内边距
.padding(.top, 8) // 添加顶部内边距
.multilineTextAlignment(.leading)
TextEditor(text: $userInput)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
.frame(width: UIScreen.main.bounds.width * 0.9,height: UIScreen.main.bounds.height * 0.4)
.background(Color.clear) // 设置背景为透明
.cornerRadius(10) // 圆角
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray.opacity(0.5), lineWidth: 1)
) // 添加边框
.font(.system(size: 18))
.transparentScrolling()
Spacer()
if !submitmessage.isEmpty{
Text(submitmessage).font(.subheadline).foregroundColor(Color.red.opacity(0.9))
}
Button(action: {
if( tickettitle.count > 0 && userInput.count > 0){
onSubmit() // 提交时触发回调
}
}) {
if isInputLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle()).tint(Color("Main"))
} else {
Text("提交工单")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
.padding()
.frame(maxWidth: .infinity)
.padding(.bottom, 20)
}
.background(Color("bg").ignoresSafeArea(.all, edges: .all))
.ignoresSafeArea(edges: .bottom) // 忽略安全区域,保证按钮位置靠底部
}
}