日报2025513
团队作业开发
设备故障报修、维修任务接取与提交
package com.example.sanpaias.activity
import android.app.ProgressDialog
import android.os.Build
import android.os.Bundle
import android.view.MenuItem
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.sanpaias.R
import com.example.sanpaias.entity.Device
import com.example.sanpaias.entity.DeviceFault
import com.example.sanpaias.network.RetrofitClient
import com.google.gson.Gson
import com.google.gson.JsonObject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class DeviceFaultReportActivity : AppCompatActivity() {
private lateinit var etDeviceId: EditText
private lateinit var etFaultDesc: EditText
private lateinit var spinnerReportType: Spinner
private lateinit var etReporter: EditText
private lateinit var etContactPhone: EditText
private lateinit var btnCancel: Button
private lateinit var btnSubmit: Button
private var device: Device? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_device_fault_report)
// 设置返回按钮
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "设备故障报修"
// 初始化视图
initViews()
// 获取传递的设备信息
// 修改这里,使用新的 Parcelable 获取方式
device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra("device", Device::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableExtra("device")
}
// 设置设备编号 - 确保这里正确设置
device?.let {
etDeviceId.setText(it.deviceId)
// 可以添加更多设备信息显示
// 例如:在界面上显示设备类型和位置
}
// 设置报修类型下拉选项
val reportTypes = arrayOf("自主报修", "电话报修")
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, reportTypes)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerReportType.adapter = adapter
// 自动填充用户信息
fillUserInfo()
// 设置按钮点击事件
btnCancel.setOnClickListener {
finish()
}
btnSubmit.setOnClickListener {
submitFaultReport()
}
}
private fun initViews() {
etDeviceId = findViewById(R.id.etDeviceId)
etFaultDesc = findViewById(R.id.etFaultDesc)
spinnerReportType = findViewById(R.id.spinnerReportType)
etReporter = findViewById(R.id.etReporter)
etContactPhone = findViewById(R.id.etContactPhone)
btnCancel = findViewById(R.id.btnCancel)
btnSubmit = findViewById(R.id.btnSubmit)
}
private fun fillUserInfo() {
// 从SharedPreferences获取用户信息
val userJson = getSharedPreferences("user_prefs", 0).getString("user_info", null)
if (!userJson.isNullOrEmpty()) {
try {
val userObject = Gson().fromJson(userJson, JsonObject::class.java)
val username = userObject.get("username")?.asString ?: ""
val userId = userObject.get("id")?.asString ?: ""
val phone = userObject.get("phone")?.asString ?: ""
etReporter.setText(username)
etContactPhone.setText(phone)
// 保存用户ID用于提交
etReporter.tag = userId
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this, "获取用户信息失败", Toast.LENGTH_SHORT).show()
}
}
}
private fun submitFaultReport() {
val deviceId = etDeviceId.text.toString()
val faultDesc = etFaultDesc.text.toString()
val reportType = spinnerReportType.selectedItem.toString()
val reporterName = etReporter.text.toString()
val contactPhone = etContactPhone.text.toString()
// 验证输入
if (deviceId.isEmpty() || faultDesc.isEmpty() || reporterName.isEmpty() || contactPhone.isEmpty()) {
Toast.makeText(this, "请填写完整信息", Toast.LENGTH_SHORT).show()
return
}
// 获取用户ID,如果tag为空则使用默认值
val userId = etReporter.tag?.toString() ?: "C001"
// 创建故障报告对象
val deviceFault = DeviceFault(
faultId = 0, // 新建故障ID为0,由服务器生成
deviceId = deviceId,
faultDesc = faultDesc,
reportType = reportType,
reportedId = userId, // 使用从用户信息中获取的ID
reportedName = reporterName,
reportedPhone = contactPhone,
status = "待处理"
)
// 显示加载对话框
val progressDialog = ProgressDialog(this)
progressDialog.setMessage("提交中...")
progressDialog.setCancelable(false)
progressDialog.show()
// 发送网络请求
lifecycleScope.launch {
try {
val response = RetrofitClient.instance.addDeviceFault(deviceFault)
progressDialog.dismiss()
if (response.isSuccessful) {
// 使用原始JSON字符串解析,避免类型不匹配问题
val jsonString = response.body()?.string()
val jsonObject = Gson().fromJson(jsonString, JsonObject::class.java)
val code = jsonObject?.get("code")?.asInt
if (code == 200) {
Toast.makeText(this@DeviceFaultReportActivity, "报修成功", Toast.LENGTH_SHORT).show()
finish()
} else {
val msg = jsonObject?.get("msg")?.asString ?: "未知错误"
Toast.makeText(this@DeviceFaultReportActivity, "报修失败: $msg", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this@DeviceFaultReportActivity, "网络请求失败: ${response.message()}", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
progressDialog.dismiss()
e.printStackTrace()
Toast.makeText(this@DeviceFaultReportActivity, "发生错误: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
}
return super.onOptionsItemSelected(item)
}
}
package com.example.sanpaias.activity
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.sanpaias.R
import com.example.sanpaias.entity.DeviceFault
import com.example.sanpaias.entity.RepairOrder
import com.example.sanpaias.network.RetrofitClient
import kotlinx.coroutines.launch
class RepairOrderDetailActivity : AppCompatActivity() {
// 移除 tvSafetyNotice 声明
private lateinit var tvOrderId: TextView
private lateinit var tvDeviceId: TextView
private lateinit var tvFaultDesc: TextView
private lateinit var tvReportedBy: TextView
private lateinit var tvEngineerName: TextView
private lateinit var tvRepairDesc: TextView
private lateinit var tvStatus: TextView
private lateinit var btnApprove: Button
private lateinit var btnReject: Button
private var orderId: Int = 0
private var repairOrder: RepairOrder? = null
private var deviceFault: DeviceFault? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_repair_order_detail)
// 设置返回按钮
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "维修工单详情"
// 初始化视图
initViews()
// 获取工单ID
orderId = intent.getIntExtra("orderId", 0)
if (orderId == 0) {
Toast.makeText(this, "工单ID无效", Toast.LENGTH_SHORT).show()
finish()
return
}
// 加载工单详情
loadOrderDetail()
}
private fun initViews() {
// 移除 tvSafetyNotice 初始化
tvOrderId = findViewById(R.id.tvOrderId)
tvDeviceId = findViewById(R.id.tvDeviceId)
tvFaultDesc = findViewById(R.id.tvFaultDesc)
tvReportedBy = findViewById(R.id.tvReportedBy)
tvEngineerName = findViewById(R.id.tvEngineerName)
tvRepairDesc = findViewById(R.id.tvRepairDesc)
tvStatus = findViewById(R.id.tvStatus)
btnApprove = findViewById(R.id.btnApprove)
btnReject = findViewById(R.id.btnReject)
// 设置按钮点击事件
btnApprove.setOnClickListener {
approveOrder(true)
}
btnReject.setOnClickListener {
approveOrder(false)
}
}
private fun loadOrderDetail() {
lifecycleScope.launch {
try {
// 添加日志记录API调用
Log.d("RepairOrderDetail", "正在获取工单ID: $orderId 的详情")
// 获取维修工单详情
val orderResponse = RetrofitClient.instance.getRepairOrderById(orderId)
// 记录API响应
Log.d("RepairOrderDetail", "工单API响应: ${orderResponse.code()} - ${orderResponse.message()}")
if (orderResponse.code() == 404) {
Toast.makeText(this@RepairOrderDetailActivity, "工单不存在", Toast.LENGTH_SHORT).show()
finish()
return@launch
}
if (orderResponse.isSuccessful && orderResponse.body()?.code == 200) {
repairOrder = orderResponse.body()?.data
Log.d("RepairOrderDetail", "获取到工单数据: $repairOrder")
// 获取故障详情
repairOrder?.let { order ->
Log.d("RepairOrderDetail", "正在获取故障ID: ${order.faultId} 的详情")
val faultResponse = RetrofitClient.instance.getFaultById(order.faultId)
Log.d("RepairOrderDetail", "故障API响应: ${faultResponse.code()} - ${faultResponse.message()}")
if (faultResponse.isSuccessful && faultResponse.body()?.code == 200) {
deviceFault = faultResponse.body()?.data
Log.d("RepairOrderDetail", "获取到故障数据: $deviceFault")
// 更新UI
updateUI()
} else {
val errorBody = faultResponse.errorBody()?.string()
Log.e("RepairOrderDetail", "获取故障详情失败: $errorBody")
Toast.makeText(this@RepairOrderDetailActivity, "获取故障详情失败", Toast.LENGTH_SHORT).show()
}
}
} else {
val errorBody = orderResponse.errorBody()?.string()
Log.e("RepairOrderDetail", "获取工单详情失败: $errorBody")
Toast.makeText(this@RepairOrderDetailActivity, "获取工单详情失败: ${orderResponse.message()}", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
e.printStackTrace()
Log.e("RepairOrderDetail", "发生异常: ${e.message}", e)
Toast.makeText(this@RepairOrderDetailActivity, "发生错误: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
private fun updateUI() {
repairOrder?.let { order ->
tvOrderId.text = "工单编号: ${order.orderId}"
tvRepairDesc.text = order.repairDesc ?: "暂无维修描述"
tvStatus.text = "状态: ${order.status}"
// 移除 tvSafetyNotice 相关设置
// 根据状态显示或隐藏按钮
if (order.status == "待审批") {
btnApprove.visibility = View.VISIBLE
btnReject.visibility = View.VISIBLE
} else {
btnApprove.visibility = View.GONE
btnReject.visibility = View.GONE
}
}
deviceFault?.let { fault ->
tvDeviceId.text = "设备编号: ${fault.deviceId}"
tvFaultDesc.text = "故障描述: ${fault.faultDesc}"
tvReportedBy.text = "报修人: ${fault.reportedName}"
// 添加报修时间显示
}
// 获取工程师姓名
repairOrder?.let { order ->
lifecycleScope.launch {
try {
val response = RetrofitClient.instance.getUserById(order.engineerId)
if (response.isSuccessful && response.body()?.code == 200) {
val engineer = response.body()?.data
tvEngineerName.text = "维修工程师: ${engineer?.username ?: "未知"}"
}
} catch (e: Exception) {
e.printStackTrace()
tvEngineerName.text = "维修工程师: ${order.engineerId}"
}
}
}
}
private fun approveOrder(isApproved: Boolean) {
repairOrder?.let { order ->
// 更新工单状态
val updatedOrder = order.copy(
status = if (isApproved) "已完成" else "处理中"
)
lifecycleScope.launch {
try {
// 确保这个接口路径正确
val response = RetrofitClient.instance.updateRepairOrder(updatedOrder)
if (response.isSuccessful && response.body()?.code == 200) {
Toast.makeText(
this@RepairOrderDetailActivity,
if (isApproved) "工单已通过" else "工单已驳回",
Toast.LENGTH_SHORT
).show()
// 刷新UI
repairOrder = updatedOrder
updateUI()
} else {
// 添加更详细的错误信息
val errorMsg = response.errorBody()?.string() ?: response.message()
Toast.makeText(
this@RepairOrderDetailActivity,
"操作失败: $errorMsg",
Toast.LENGTH_SHORT
).show()
Log.e("RepairOrderDetail", "API错误: $errorMsg")
}
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(
this@RepairOrderDetailActivity,
"发生错误: ${e.message}",
Toast.LENGTH_SHORT
).show()
Log.e("RepairOrderDetail", "异常: ${e.message}", e)
}
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
}
return super.onOptionsItemSelected(item)
}
}
package com.example.sanpaias.adapter
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.sanpaias.R
import com.example.sanpaias.entity.InspectionOrder
import com.example.sanpaias.entity.MaintenanceOrder
import com.example.sanpaias.entity.RepairOrder
import com.example.sanpaias.entity.TestingOrder // 添加这一行导入
// 修改构造函数,添加查看详情的回调
class OrderApprovalAdapter(
private val context: Context,
private var orders: List<Any>,
private val onApproveClick: (Any, Boolean) -> Unit,
private val onViewDetailClick: (Any) -> Unit // 添加查看详情的回调
) : RecyclerView.Adapter<OrderApprovalAdapter.OrderViewHolder>() {
// Add these property declarations
private var deviceMap: Map<Int, String> = emptyMap()
private var faultDescMap: Map<Int, String> = emptyMap()
private var engineerMap: Map<String, String> = emptyMap()
class OrderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvOrderId: TextView = view.findViewById(R.id.tvOrderId)
val tvDeviceId: TextView = view.findViewById(R.id.tvDeviceId) // 确保ID与布局文件匹配
val tvFaultDesc: TextView = view.findViewById(R.id.tvFaultDesc) // 确保ID与布局文件匹配
val tvEngineerName: TextView = view.findViewById(R.id.tvEngineerName) // 确保ID与布局文件匹配
val btnApprove: Button = view.findViewById(R.id.btnApprove)
val btnReject: Button = view.findViewById(R.id.btnReject)
val btnViewDetail: Button = view.findViewById(R.id.btnViewDetail) // 添加查看详情按钮
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.item_order_approval, parent, false)
return OrderViewHolder(view)
}
override fun onBindViewHolder(holder: OrderViewHolder, position: Int) {
val order = orders[position]
when (order) {
is RepairOrder -> bindRepairOrder(holder, order)
is InspectionOrder -> bindInspectionOrder(holder, order)
is MaintenanceOrder -> bindMaintenanceOrder(holder, order)
is TestingOrder -> bindTestingOrder(holder, order) // 添加这一行
else -> {
Log.e("OrderApprovalAdapter", "未知工单类型: ${order.javaClass.simpleName}")
holder.tvOrderId.text = "未知工单类型"
}
}
holder.btnApprove.setOnClickListener {
onApproveClick(order, true)
}
holder.btnReject.setOnClickListener {
onApproveClick(order, false)
}
// 设置查看详情按钮点击事件
holder.btnViewDetail.setOnClickListener {
onViewDetailClick(order)
}
}
private fun bindRepairOrder(holder: OrderViewHolder, order: RepairOrder) {
holder.tvOrderId.text = "维修工单 #${order.orderId}"
// Use deviceMap to get device ID
val deviceId = deviceMap[order.faultId] ?: "未知设备"
holder.tvDeviceId.text = "设备ID: $deviceId"
// Use faultDescMap to get fault description
val faultDesc = faultDescMap[order.faultId] ?: "无描述"
holder.tvFaultDesc.text = "故障描述: $faultDesc"
// Use engineerMap to get engineer name
val engineerName = engineerMap[order.engineerId] ?: order.engineerId
holder.tvEngineerName.text = "工程师: $engineerName"
}
private fun bindInspectionOrder(holder: OrderViewHolder, order: InspectionOrder) {
holder.tvOrderId.text = "巡检工单 #${order.orderId}"
holder.tvDeviceId.text = "计划ID: ${order.planId}"
holder.tvFaultDesc.text = "巡检描述: ${order.inspectionDesc ?: "无"}"
holder.tvEngineerName.text = "工程师: ${order.engineerId}"
}
// 添加保养工单绑定方法
private fun bindMaintenanceOrder(holder: OrderViewHolder, order: MaintenanceOrder) {
holder.tvOrderId.text = "保养工单 #${order.orderId}"
holder.tvDeviceId.text = "计划ID: ${order.planId}"
holder.tvFaultDesc.text = "保养描述: ${order.maintenanceDesc ?: "无"}"
holder.tvEngineerName.text = "工程师: ${order.engineerId}"
// 添加日志输出,帮助调试
Log.d("OrderApprovalAdapter", "绑定保养工单: ${order.orderId}, 状态: ${order.status}")
}
// 添加检测工单绑定方法
private fun bindTestingOrder(holder: OrderViewHolder, order: TestingOrder) {
holder.tvOrderId.text = "检测工单 #${order.orderId}"
holder.tvDeviceId.text = "计划ID: ${order.planId}"
holder.tvFaultDesc.text = "检测描述: ${order.testingDesc ?: "无"}"
holder.tvEngineerName.text = "工程师: ${order.engineerId}"
// 添加日志输出,帮助调试
Log.d("OrderApprovalAdapter", "绑定检测工单: ${order.orderId}, 状态: ${order.status}")
}
override fun getItemCount(): Int = orders.size
// Modified updateData method with additional parameters
fun updateData(
newOrders: List<Any>,
deviceMap: Map<Int, String> = emptyMap(),
faultDescMap: Map<Int, String> = emptyMap(),
engineerMap: Map<String, String> = emptyMap()
) {
orders = newOrders
this.deviceMap = deviceMap
this.faultDescMap = faultDescMap
this.engineerMap = engineerMap
notifyDataSetChanged()
}
}
package com.example.sanpaias.entity
import java.io.Serializable
data class DeviceFault(
val faultId: Int,
val deviceId: String,
val faultDesc: String,
val reportType: String,
val reportedId: String,
val reportedName: String,
val reportedPhone: String,
val status: String
) : Serializable
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvDetailTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="工单详情"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="16dp"/>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="1">
<!-- 保持现有行不变 -->
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="工单编号:"
android:textStyle="bold"
android:padding="4dp"/>
<TextView
android:id="@+id/tvDetailOrderId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"/>
</TableRow>
<!-- 其他现有行保持不变 -->
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设备/计划:"
android:textStyle="bold"
android:padding="4dp"/>
<TextView
android:id="@+id/tvDetailDeviceId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"/>
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="工程师:"
android:textStyle="bold"
android:padding="4dp"/>
<TextView
android:id="@+id/tvDetailEngineer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"/>
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="状态:"
android:textStyle="bold"
android:padding="4dp"/>
<TextView
android:id="@+id/tvDetailStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"/>
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="描述:"
android:textStyle="bold"
android:padding="4dp"/>
<TextView
android:id="@+id/tvDetailDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"/>
</TableRow>
<!-- 添加照片显示行 -->
<TableRow android:id="@+id/rowPhotos">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="照片:"
android:textStyle="bold"
android:padding="4dp"/>
<LinearLayout
android:id="@+id/layoutPhotos"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="4dp">
<!-- 照片将在代码中动态添加 -->
</LinearLayout>
</TableRow>
</TableLayout>
<Button
android:id="@+id/btnCloseDetail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="关闭"
android:layout_marginTop="16dp"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

浙公网安备 33010602011771号