日报2025529
团队任务开发
修复任务提交bug,修改水印添加功能
package com.example.sanpaias.activity
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.provider.MediaStore
import android.util.Base64
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.sanpaias.R
import com.example.sanpaias.adapter.PhotoAdapter
import com.example.sanpaias.entity.RepairOrder
import com.example.sanpaias.network.RetrofitClient
import kotlinx.coroutines.launch
import java.io.ByteArrayOutputStream
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.location.Geocoder
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.FileProvider
import com.example.sanpaias.entity.DeviceFault
import com.example.sanpaias.entity.FaultStatusUpdate
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import java.io.File
class TaskEditActivity : AppCompatActivity() {
private lateinit var toolbar: Toolbar
private lateinit var tvOrderId: TextView
private lateinit var tvFaultId: TextView
private lateinit var tvStatus: TextView
private lateinit var etRepairDesc: EditText
private lateinit var btnTakePhoto: Button
private lateinit var btnSave: Button
private lateinit var btnSubmit: Button // 添加提交按钮引用
private lateinit var recyclerViewPhotos: RecyclerView
private lateinit var photoAdapter: PhotoAdapter
private var repairOrder: RepairOrder? = null
private val photoList = mutableListOf<String>()
// 添加位置相关变量
private lateinit var fusedLocationClient: FusedLocationProviderClient
private var currentLocation: Location? = null
companion object {
private const val REQUEST_CAMERA_PERMISSION = 100
private const val REQUEST_IMAGE_CAPTURE = 101
private const val REQUEST_LOCATION_PERMISSION = 102
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_task_edit)
// 初始化位置服务
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
// 初始化视图
initViews()
// 获取传递的维修工单
repairOrder = intent.getParcelableExtra("repair_order")
// 显示工单信息
displayOrderInfo()
// 设置按钮点击事件
setupButtonListeners()
// 获取当前位置
getCurrentLocation()
}
private fun initViews() {
toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "维修工单"
tvOrderId = findViewById(R.id.tvOrderId)
tvFaultId = findViewById(R.id.tvFaultId)
tvStatus = findViewById(R.id.tvStatus)
etRepairDesc = findViewById(R.id.etRepairDesc)
btnTakePhoto = findViewById(R.id.btnTakePhoto)
btnSave = findViewById(R.id.btnSave)
btnSubmit = findViewById(R.id.btnSubmit) // 初始化提交按钮
// 初始化照片RecyclerView
recyclerViewPhotos = findViewById(R.id.recyclerViewPhotos)
recyclerViewPhotos.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
photoAdapter = PhotoAdapter(
photoList = photoList,
onDeleteClick = { position ->
photoList.removeAt(position)
photoAdapter.notifyItemRemoved(position)
}
)
recyclerViewPhotos.adapter = photoAdapter
}
private fun displayOrderInfo() {
repairOrder?.let { order ->
tvOrderId.text = "工单编号: ${order.orderId}"
tvFaultId.text = "故障编号: ${order.faultId}"
tvStatus.text = "状态: ${order.status}"
etRepairDesc.setText(order.repairDesc)
// 加载已有照片
order.photos?.let { photosStr ->
if (photosStr.isNotEmpty()) {
val photos = photosStr.split(",").filter { it.isNotEmpty() }
photoList.addAll(photos)
photoAdapter.notifyDataSetChanged()
}
}
}
}
private fun setupButtonListeners() {
btnTakePhoto.setOnClickListener {
requestPermissions()
}
btnSave.setOnClickListener {
saveRepairOrder()
}
btnSubmit.setOnClickListener {
submitRepairOrder()
}
}
// 修改权限请求方法,同时请求相机和位置权限
private fun requestPermissions() {
val permissionsNeeded = mutableListOf<String>()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.CAMERA)
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
if (permissionsNeeded.isNotEmpty()) {
ActivityCompat.requestPermissions(this, permissionsNeeded.toTypedArray(), REQUEST_CAMERA_PERMISSION)
} else {
dispatchTakePictureIntent()
}
}
// 获取当前位置
private fun getCurrentLocation() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
currentLocation = location
if (location == null) {
Log.w("TaskEditActivity", "无法获取位置信息")
}
}
.addOnFailureListener { e ->
Log.e("TaskEditActivity", "获取位置失败", e)
}
}
}
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
takePictureIntent.resolveActivity(packageManager)?.also {
currentPhotoFile = createImageFile()
currentPhotoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.example.sanpaias.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
cameraLauncher.launch(takePictureIntent)
}
}
}
}
private fun createImageFile(): File {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val storageDir: File = getExternalFilesDir("Pictures")!!
return File.createTempFile(
"JPEG_${timeStamp}_",
".jpg",
storageDir
)
}
// 添加文件相关变量
private var currentPhotoFile: File? = null
// 替换原有的拍照方式
private val cameraLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == RESULT_OK) {
currentPhotoFile?.let { file ->
if (file.exists()) {
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, Uri.fromFile(file))
val watermarkedBitmap = addWatermark(bitmap)
val base64Image = bitmapToBase64(watermarkedBitmap)
photoList.add(base64Image)
photoAdapter.notifyItemInserted(photoList.size - 1)
}
}
}
}
// 修改水印方法,添加位置信息
private fun addWatermark(src: Bitmap): Bitmap {
val width = src.width
val height = src.height
// 创建一个新的Bitmap,与原图大小相同
val config = src.config ?: Bitmap.Config.ARGB_8888
val result = Bitmap.createBitmap(width, height, config)
// 创建Canvas对象
val canvas = Canvas(result)
// 绘制原始图片
canvas.drawBitmap(src, 0f, 0f, null)
// 设置水印文本
val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
val locationText = getLocationText()
// 创建画笔
val paint = Paint().apply {
color = Color.WHITE
textSize = width / 35f // 稍微调小字体
isAntiAlias = true
style = Paint.Style.FILL
setShadowLayer(3f, 1f, 1f, Color.BLACK) // 添加阴影使文字更清晰
}
// 计算时间文本位置(右下角)
val timeBounds = Rect()
paint.getTextBounds(timestamp, 0, timestamp.length, timeBounds)
val timeTextWidth = paint.measureText(timestamp)
val timeTextHeight = timeBounds.height()
val timeX = width - timeTextWidth - width / 50f
val timeY = height - timeTextHeight - height / 50f
// 绘制时间文本
canvas.drawText(timestamp, timeX, timeY, paint)
// 如果有位置信息,绘制位置文本(时间上方)
if (locationText.isNotEmpty()) {
val locationBounds = Rect()
paint.getTextBounds(locationText, 0, locationText.length, locationBounds)
val locationTextWidth = paint.measureText(locationText)
val locationTextHeight = locationBounds.height()
val locationX = width - locationTextWidth - width / 50f
val locationY = timeY - locationTextHeight - height / 100f // 在时间上方,留出间距
// 绘制位置文本
canvas.drawText(locationText, locationX, locationY, paint)
}
return result
}
// 获取位置文本 - 修改为返回具体地址
private fun getLocationText(): String {
return currentLocation?.let { location ->
try {
val geocoder = Geocoder(this, Locale.getDefault())
val addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
if (addresses?.isNotEmpty() == true) {
val address = addresses[0]
// 构建地址字符串,优先显示详细地址
val addressParts = mutableListOf<String>()
// 添加街道地址
address.getAddressLine(0)?.let { line: String -> addressParts.add(line) }
// 如果没有详细地址,则使用行政区划信息
if (addressParts.isEmpty()) {
address.locality?.let { city: String -> addressParts.add(city) } // 城市
address.subLocality?.let { district: String -> addressParts.add(district) } // 区县
address.thoroughfare?.let { street: String -> addressParts.add(street) } // 街道
}
val locationText = if (addressParts.isNotEmpty()) {
addressParts.joinToString(" ")
} else {
"${address.locality ?: ""} ${address.subAdminArea ?: ""}".trim()
}
if (locationText.isNotEmpty()) "位置: $locationText" else ""
} else {
// 如果地理编码失败,显示经纬度作为备选
val latitude = String.format("%.4f", location.latitude)
val longitude = String.format("%.4f", location.longitude)
"位置: $latitude, $longitude"
}
} catch (e: Exception) {
// 地理编码异常时,显示经纬度作为备选
val latitude = String.format("%.4f", location.latitude)
val longitude = String.format("%.4f", location.longitude)
"位置: $latitude, $longitude"
}
} ?: ""
}
private fun bitmapToBase64(bitmap: Bitmap): String {
val byteArrayOutputStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, byteArrayOutputStream)
val byteArray = byteArrayOutputStream.toByteArray()
return Base64.encodeToString(byteArray, Base64.DEFAULT)
}
private fun saveRepairOrder() {
repairOrder?.let { order ->
// 更新维修描述
order.repairDesc = etRepairDesc.text.toString()
// 更新照片
order.photos = photoList.joinToString(",")
// 显示加载进度
val progressBar = findViewById<View>(R.id.progressBar)
progressBar.visibility = View.VISIBLE
lifecycleScope.launch {
try {
val response = RetrofitClient.instance.updateRepairOrder(order)
progressBar.visibility = View.GONE
if (response.isSuccessful) {
val apiResponse = response.body()
if (apiResponse?.code == 200) {
Toast.makeText(this@TaskEditActivity, "保存成功", Toast.LENGTH_SHORT).show()
setResult(Activity.RESULT_OK)
finish()
} else {
Toast.makeText(this@TaskEditActivity,
apiResponse?.msg ?: "保存失败",
Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this@TaskEditActivity,
"网络请求失败: ${response.code()}",
Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
progressBar.visibility = View.GONE
Toast.makeText(this@TaskEditActivity,
"保存异常: ${e.message}",
Toast.LENGTH_SHORT).show()
Log.e("TaskEditActivity", "保存异常", e)
}
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
// 添加提交工单的方法
private fun submitRepairOrder() {
repairOrder?.let { order ->
// 更新维修描述
order.repairDesc = etRepairDesc.text.toString()
// 更新照片
order.photos = photoList.joinToString(",")
// 更新状态为待审批
order.status = "待审批"
// 显示加载进度
val progressBar = findViewById<View>(R.id.progressBar)
progressBar.visibility = View.VISIBLE
lifecycleScope.launch {
try {
// 更新维修工单
val response = RetrofitClient.instance.updateRepairOrder(order)
if (response.isSuccessful) {
val apiResponse = response.body()
if (apiResponse?.code == 200) {
// 更新故障状态为待审批
try {
val faultStatusUpdate = FaultStatusUpdate(
faultId = order.faultId.toString(),
status = "待审批"
)
val faultResponse = RetrofitClient.instance.updateFaultStatus(faultStatusUpdate)
progressBar.visibility = View.GONE
if (faultResponse.isSuccessful && faultResponse.body()?.code == 200) {
Toast.makeText(this@TaskEditActivity,
"工单已提交审批", Toast.LENGTH_SHORT).show()
setResult(Activity.RESULT_OK)
finish()
} else {
Toast.makeText(this@TaskEditActivity,
"工单已提交,但故障状态更新失败", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
progressBar.visibility = View.GONE
Toast.makeText(this@TaskEditActivity,
"工单已提交,但故障状态更新失败: ${e.message}", Toast.LENGTH_SHORT).show()
Log.e("TaskEditActivity", "故障状态更新异常", e)
}
} else {
progressBar.visibility = View.GONE
Toast.makeText(this@TaskEditActivity,
apiResponse?.msg ?: "提交失败",
Toast.LENGTH_SHORT).show()
}
} else {
progressBar.visibility = View.GONE
Toast.makeText(this@TaskEditActivity,
"网络请求失败: ${response.code()}",
Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
progressBar.visibility = View.GONE
Toast.makeText(this@TaskEditActivity,
"提交异常: ${e.message}",
Toast.LENGTH_SHORT).show()
Log.e("TaskEditActivity", "提交异常", e)
}
} // 这里可能缺少了lifecycleScope.launch的右花括号
} // 这里可能缺少了repairOrder?.let的右花括号
} // 这里是submitRepairOrder方法的右花括号
}

浙公网安备 33010602011771号