tam chat
This commit is contained in:
181
client/app.go
181
client/app.go
@@ -104,6 +104,8 @@ type App struct {
|
||||
wifiRejected bool
|
||||
quitDialogShown bool
|
||||
monitoringTornDown bool
|
||||
chatUnread int
|
||||
replyStaffID uint
|
||||
}
|
||||
|
||||
type LocalStats struct {
|
||||
@@ -274,10 +276,7 @@ func (a *App) startLocalServer() {
|
||||
blocker.Instance.Start()
|
||||
|
||||
// Kiểm tra điều kiện app được phép và giờ học trước khi tải giao diện
|
||||
go a.fetchAllowedApps(st.SystemID)
|
||||
go a.fetchStudentStatus(st.StudentID)
|
||||
go a.fetchWifiPolicy()
|
||||
go a.refreshNetworkStatus()
|
||||
go a.refreshStudentData()
|
||||
|
||||
// Chuyển hướng WebView về trang dashboard của app bằng cách reload app assets
|
||||
runtime.WindowReloadApp(a.ctx)
|
||||
@@ -315,10 +314,8 @@ func (a *App) loadSession() {
|
||||
log.Printf("[APP] Loaded local session: %s (%s)", s.FullName, s.StudentCode)
|
||||
blocker.Instance.Start()
|
||||
|
||||
go a.fetchAllowedApps(s.SystemID)
|
||||
go a.fetchStudentStatus(s.StudentID)
|
||||
go a.refreshStudentData()
|
||||
go a.fetchWifiPolicy()
|
||||
go a.refreshNetworkStatus()
|
||||
go a.syncProfileToServer(&s)
|
||||
}
|
||||
}
|
||||
@@ -589,6 +586,33 @@ func (a *App) runMonitorTick() {
|
||||
}
|
||||
}
|
||||
|
||||
// refreshNetworkStatus — đọc WiFi + ping server ngay (không cộng thời gian online/offline).
|
||||
func (a *App) resolveClassRkID() int64 {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.dashboard.ClassRkID > 0 {
|
||||
return a.dashboard.ClassRkID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a *App) refreshStudentData() {
|
||||
a.mu.Lock()
|
||||
student := a.student
|
||||
a.mu.Unlock()
|
||||
if student == nil {
|
||||
return
|
||||
}
|
||||
a.fetchStudentStatus(student.StudentID)
|
||||
classID := a.resolveClassRkID()
|
||||
if classID > 0 {
|
||||
a.fetchAllowedApps(classID)
|
||||
} else {
|
||||
a.fetchAllowedApps(0)
|
||||
}
|
||||
a.refreshNetworkStatus()
|
||||
}
|
||||
|
||||
// refreshNetworkStatus — đọc WiFi + ping server ngay (không cộng thời gian online/offline).
|
||||
func (a *App) refreshNetworkStatus() {
|
||||
if !a.isMonitoringActive() || !a.CheckLoginStatus() {
|
||||
@@ -601,11 +625,14 @@ func (a *App) refreshNetworkStatus() {
|
||||
a.wifiBSSID = wifi.BSSID
|
||||
a.backendOnline = backendOnline
|
||||
a.mu.Unlock()
|
||||
if backendOnline {
|
||||
a.connectWS()
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) pingBackend() bool {
|
||||
client := http.Client{Timeout: 3 * time.Second}
|
||||
resp, err := client.Get("http://127.0.0.1:8080/api/stats")
|
||||
resp, err := client.Get("http://127.0.0.1:8080/api/health")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -628,12 +655,18 @@ func (a *App) syncLogsToServer() {
|
||||
return
|
||||
}
|
||||
|
||||
go a.fetchStudentStatus(student.StudentID)
|
||||
go a.fetchAllowedApps(student.SystemID)
|
||||
go func() {
|
||||
a.fetchStudentStatus(student.StudentID)
|
||||
classID := a.resolveClassRkID()
|
||||
if classID <= 0 {
|
||||
classID = student.SystemID
|
||||
}
|
||||
a.fetchAllowedApps(classID)
|
||||
}()
|
||||
|
||||
payload := map[string]any{
|
||||
"studentRkId": student.StudentID,
|
||||
"classRkId": student.SystemID,
|
||||
"classRkId": a.resolveClassRkID(),
|
||||
"sessionDate": time.Now().Format("2006-01-02"),
|
||||
"addOnlineSeconds": unsyncedOn,
|
||||
"addOfflineSeconds": unsyncedOff,
|
||||
@@ -809,8 +842,9 @@ func (a *App) fetchAllowedApps(classId int64) {
|
||||
}
|
||||
a.mu.Unlock()
|
||||
|
||||
url := fmt.Sprintf("http://127.0.0.1:8080/api/classes/%d/allowed-apps?studentId=%d", classId, studentID)
|
||||
client := http.Client{Timeout: 4 * time.Second}
|
||||
resp, err := client.Get(fmt.Sprintf("http://127.0.0.1:8080/api/classes/%d/allowed-apps?studentId=%d", classId, studentID))
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -888,7 +922,7 @@ func (a *App) fetchStudentStatus(studentID int64) {
|
||||
}
|
||||
|
||||
func (a *App) connectWS() {
|
||||
if !a.isMonitoringActive() {
|
||||
if !a.CheckLoginStatus() {
|
||||
return
|
||||
}
|
||||
a.mu.Lock()
|
||||
@@ -897,9 +931,13 @@ func (a *App) connectWS() {
|
||||
return
|
||||
}
|
||||
student := a.student
|
||||
classID := a.dashboard.ClassRkID
|
||||
if classID <= 0 {
|
||||
classID = student.SystemID
|
||||
}
|
||||
a.mu.Unlock()
|
||||
|
||||
wsUrl := fmt.Sprintf("ws://127.0.0.1:8080/ws?role=student&studentId=%d&classId=%d", student.StudentID, student.SystemID)
|
||||
wsUrl := fmt.Sprintf("ws://127.0.0.1:8080/ws?role=student&studentId=%d&classId=%d", student.StudentID, classID)
|
||||
dialer := websocket.Dialer{HandshakeTimeout: 4 * time.Second}
|
||||
conn, _, err := dialer.Dial(wsUrl, nil)
|
||||
if err != nil {
|
||||
@@ -934,6 +972,20 @@ func (a *App) connectWS() {
|
||||
runtime.EventsEmit(a.ctx, "start_webcam_stream")
|
||||
case "stop_webcam_stream":
|
||||
runtime.EventsEmit(a.ctx, "stop_webcam_stream")
|
||||
case "chat:message":
|
||||
if staffVal, ok := msg.Data["staffId"].(float64); ok {
|
||||
a.mu.Lock()
|
||||
a.replyStaffID = uint(staffVal)
|
||||
a.chatUnread++
|
||||
unread := a.chatUnread
|
||||
a.mu.Unlock()
|
||||
runtime.EventsEmit(a.ctx, "chat:notify", map[string]any{
|
||||
"unread": unread,
|
||||
"preview": msg.Data["body"],
|
||||
"from": msg.Data["staffName"],
|
||||
})
|
||||
}
|
||||
runtime.EventsEmit(a.ctx, "chat:message", msg.Data)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -1003,3 +1055,104 @@ func (a *App) stopScreenshotStream() {
|
||||
close(a.streamScStop)
|
||||
log.Println("[WS] Screenshot screen-streaming stopped.")
|
||||
}
|
||||
|
||||
func (a *App) GetChatUnread() int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.chatUnread
|
||||
}
|
||||
|
||||
func (a *App) ClearChatUnread() {
|
||||
a.mu.Lock()
|
||||
a.chatUnread = 0
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
func (a *App) GetChatConversations() ([]map[string]any, error) {
|
||||
a.mu.Lock()
|
||||
student := a.student
|
||||
a.mu.Unlock()
|
||||
if student == nil {
|
||||
return nil, errors.New("chưa đăng nhập")
|
||||
}
|
||||
url := fmt.Sprintf("http://127.0.0.1:8080/api/student/chat/conversations?studentRkId=%d", student.StudentID)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var payload struct {
|
||||
Data []map[string]any `json:"data"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload.Data, nil
|
||||
}
|
||||
|
||||
func (a *App) GetChatMessages(staffID uint) ([]map[string]any, error) {
|
||||
a.mu.Lock()
|
||||
student := a.student
|
||||
a.mu.Unlock()
|
||||
if student == nil {
|
||||
return nil, errors.New("chưa đăng nhập")
|
||||
}
|
||||
url := fmt.Sprintf("http://127.0.0.1:8080/api/student/chat/messages?studentRkId=%d&staffId=%d", student.StudentID, staffID)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var payload struct {
|
||||
Data []map[string]any `json:"data"`
|
||||
ReplyStaffID uint `json:"replyStaffId"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if staffID > 0 {
|
||||
a.mu.Lock()
|
||||
a.replyStaffID = staffID
|
||||
a.mu.Unlock()
|
||||
} else if payload.ReplyStaffID > 0 {
|
||||
a.mu.Lock()
|
||||
a.replyStaffID = payload.ReplyStaffID
|
||||
a.mu.Unlock()
|
||||
}
|
||||
a.ClearChatUnread()
|
||||
return payload.Data, nil
|
||||
}
|
||||
|
||||
func (a *App) SendChatMessage(body string) error {
|
||||
body = strings.TrimSpace(body)
|
||||
if body == "" {
|
||||
return errors.New("tin nhắn trống")
|
||||
}
|
||||
a.mu.Lock()
|
||||
student := a.student
|
||||
staffID := a.replyStaffID
|
||||
a.mu.Unlock()
|
||||
if student == nil {
|
||||
return errors.New("chưa đăng nhập")
|
||||
}
|
||||
payload := map[string]any{
|
||||
"studentRkId": student.StudentID,
|
||||
"staffId": staffID,
|
||||
"body": body,
|
||||
}
|
||||
b, _ := json.Marshal(payload)
|
||||
resp, err := http.Post("http://127.0.0.1:8080/api/student/chat/messages", "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 300 {
|
||||
var errBody map[string]any
|
||||
_ = json.NewDecoder(resp.Body).Decode(&errBody)
|
||||
if msg, ok := errBody["error"].(string); ok {
|
||||
return errors.New(msg)
|
||||
}
|
||||
return fmt.Errorf("gửi tin thất bại (%d)", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user