个人作业Android学习系统开发日志六

Android实现:
CodeLog:
entity:

package com.example.learningmanagement.entity

import com.google.gson.annotations.SerializedName
import java.util.Date

data class CodeLog(
    val id: String = "",
    
    @SerializedName("date")
    val date: Date,
    val estimate: Double = 0.0,
    val analysis: String = "",
    val codingStandard: String = "",
    val designDetails: String = "",
    val code: String = "",
    val workloadMeasurement: String = "",
    val postmortemAnalysis: String = "",
    val improvementPlan: String = "",
    val totalHours: Double = 0.0,
    val userId: Int
)

adapter:

package com.example.learningmanagement.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.learningmanagement.databinding.ItemCodeLogBinding
import com.example.learningmanagement.entity.CodeLog
import java.text.SimpleDateFormat
import java.util.Locale

class CodeLogAdapter : ListAdapter<CodeLog, CodeLogAdapter.ViewHolder>(CodeLogDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemCodeLogBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val codeLog = getItem(position)
        holder.bind(codeLog)
    }

    class ViewHolder(private val binding: ItemCodeLogBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(codeLog: CodeLog) {
            val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
            binding.tvDate.text = "日期: ${dateFormat.format(codeLog.date)}"
            binding.tvEstimate.text = "估计时间: ${codeLog.estimate}小时"
            binding.tvAnalysis.text = "需求分析: ${codeLog.analysis}"
            binding.tvCodingStandard.text = "代码规范: ${codeLog.codingStandard}"
            binding.tvDesignDetails.text = "设计内容: ${codeLog.designDetails}"
            binding.tvCode.text = "代码: ${codeLog.code}"
            binding.tvWorkloadMeasurement.text = "工作量计算: ${codeLog.workloadMeasurement}"
            binding.tvPostmortemAnalysis.text = "事后总结: ${codeLog.postmortemAnalysis}"
            binding.tvImprovementPlan.text = "改进计划: ${codeLog.improvementPlan}"
            binding.tvTotalHours.text = "合计时间: ${codeLog.totalHours}小时"
        }
    }

    class CodeLogDiffCallback : DiffUtil.ItemCallback<CodeLog>() {
        override fun areItemsTheSame(oldItem: CodeLog, newItem: CodeLog): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: CodeLog, newItem: CodeLog): Boolean {
            return oldItem == newItem
        }
    }
}

service:

package com.example.learningmanagement.service

import com.example.learningmanagement.entity.ApiResponse
import com.example.learningmanagement.entity.CodeLog
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path

interface CodeLogService {
    @POST("dailyLog/add")
    suspend fun addCodeLog(@Body codeLog: CodeLog): ApiResponse<Any>

    @GET("dailyLog/selectAll/{userId}")
    suspend fun getCodeLogs(@Path("userId") userId: String): ApiResponse<List<CodeLog>>
}

fragment:

package com.example.learningmanagement.ui.fragment

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.learningmanagement.adapter.CodeLogAdapter
import com.example.learningmanagement.databinding.FragmentCodeLogBinding
import com.example.learningmanagement.entity.CodeLog
import com.example.learningmanagement.network.ServiceCreater
import com.example.learningmanagement.service.CodeLogService
import com.example.learningmanagement.ui.MainActivity
import com.example.learningmanagement.utils.PrefsHelper
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class CodeLogFragment : Fragment() {
    private var _binding: FragmentCodeLogBinding? = null
    private val binding get() = _binding!!
    private val codeLogService = ServiceCreater.create<CodeLogService>()
    private val codeLogAdapter = CodeLogAdapter()
    private lateinit var prefs: PrefsHelper

    override fun onAttach(context: Context) {
        super.onAttach(context)
        prefs = PrefsHelper(context)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentCodeLogBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setupRecyclerView()
        loadCodeLogs()
        
        // 更新标题
        (activity as? MainActivity)?.updateWeekTitle("编程记录")
    }

    private fun setupRecyclerView() {
        binding.rvCodeLogs.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = codeLogAdapter
        }
    }

    fun loadCodeLogs() {
        if (!isAdded) return

        lifecycleScope.launch {
            try {
                val userId = prefs.getUserId()
                if (userId != null) {
                    try {
                        val response = codeLogService.getCodeLogs(userId)
                        
                        if (!isAdded || _binding == null) return@launch
                        
                        if (response.code == "200") {
                            response.data?.let { logs ->
                                if (logs.isNotEmpty()) {
                                    // 只显示最新的一条记录
                                    val latestLog = logs.maxByOrNull { it.date }
                                    latestLog?.let {
                                        codeLogAdapter.submitList(listOf(it))
                                        binding.rvCodeLogs.visibility = View.VISIBLE
                                        binding.tvEmptyData.visibility = View.GONE
                                    } ?: showEmptyView()
                                } else {
                                    showEmptyView()
                                }
                            } ?: showEmptyView()
                        } else {
                            showToast("获取数据失败: ${response.msg}")
                            showEmptyView()
                        }
                    } catch (e: Exception) {
                        if (!isAdded || _binding == null) return@launch
                        
                        showToast("网络请求错误: ${e.message}")
                        showEmptyView()
                    }
                } else {
                    if (!isAdded || _binding == null) return@launch
                    
                    showToast("用户未登录")
                    showEmptyView()
                }
            } catch (e: Exception) {
                if (!isAdded || _binding == null) return@launch
                
                showToast("加载失败: ${e.message}")
                showEmptyView()
            }
        }
    }

    private fun showEmptyView() {
        binding.rvCodeLogs.visibility = View.GONE
        binding.tvEmptyData.visibility = View.VISIBLE
    }

    private fun showToast(message: String) {
        if (isAdded) {
            Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
        }
    }

    // 获取当前日期的方法
    fun getCurrentDate(): String {
        val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
        return dateFormat.format(Date())
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    // 供MainActivity调用的添加方法
    fun showAddCodeLogDialog() {
        (activity as? MainActivity)?.showAddCodeLogDialog()
    }
}

xml:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tvCurrentDate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="当前日期: 2023-01-01"
            android:textSize="16sp"
            android:textStyle="bold"
            android:layout_marginBottom="16dp" />

        <EditText
            android:id="@+id/etEstimate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="估计时间(小时)"
            android:inputType="numberDecimal"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etAnalysis"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="需求分析/学习新技术内容"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etCodingStandard"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="采用的代码规范"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etDesignDetails"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="具体设计内容"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etCode"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="代码"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etWorkloadMeasurement"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="工作量计算"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etPostmortemAnalysis"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="事后总结"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etImprovementPlan"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="改进计划"
            android:inputType="textMultiLine"
            android:minLines="2"
            android:layout_marginBottom="8dp" />

        <EditText
            android:id="@+id/etTotalHours"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="合计时间(小时)"
            android:inputType="numberDecimal"
            android:layout_marginBottom="8dp" />
    </LinearLayout>
</ScrollView>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvCodeLogs"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvEmptyData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="暂无编程记录数据"
        android:textSize="18sp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    app:cardCornerRadius="8dp"
    app:cardElevation="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:id="@+id/tvDate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"
            android:textColor="@color/pink_500" />

        <TextView
            android:id="@+id/tvEstimate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvAnalysis"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvCodingStandard"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvDesignDetails"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvCode"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvWorkloadMeasurement"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvPostmortemAnalysis"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvImprovementPlan"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp" />

        <TextView
            android:id="@+id/tvTotalHours"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:textStyle="bold" />
    </LinearLayout>
</androidx.cardview.widget.CardView>
posted @ 2025-04-01 20:11  vivi_vimi  阅读(8)  评论(0)    收藏  举报