fix: 修复图片上传字段语义颠倒及加载缺失鉴权头导致的 403

- 修正 UploadUtil 返回字段到 FileBean 的映射:
  newName 是原图(较大)、zipFileName 是缩略图(较小)
- 保证 bean.pic 存缩略图、bean.originalPic 存原图
- 全局 loadImage BindingAdapter 对 http(s) URL 自动包装
  GlideUrl + Authorization,避免 /file/getImg/ 接口 403
- ImageSelectViewHolder 缩略图带鉴权加载,点击预览传原图
- 覆盖国内/国际事故签证、国内进港移库/移交编辑页面
- CLAUDE.md 同步修正 UploadBean 字段语义文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-17 14:57:26 +08:00
parent 6ad7f0d3d4
commit 1157a0c4ed
8 changed files with 128 additions and 91 deletions

View File

@@ -12,12 +12,16 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.LazyHeaders
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.base.CommonAdapter
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
import com.lukouguoji.module_base.ktx.loge
import com.lukouguoji.module_base.util.SizeUtils
@@ -111,10 +115,22 @@ fun loadImage(
com.bumptech.glide.request.target.Target.SIZE_ORIGINAL
)
// 对 http(s) 字符串 URL自动包装为带 Authorization header 的 GlideUrl避免 /file/getImg/ 接口 403
val actualSource: Any? = if (source is String && (source.startsWith("http://") || source.startsWith("https://"))) {
GlideUrl(
source,
LazyHeaders.Builder()
.addHeader("Authorization", SharedPreferenceUtil.getString(Constant.Share.token))
.build()
)
} else {
source
}
// 设置图片加载
val load = Glide.with(imageView)
.setDefaultRequestOptions(requestOptions)
.load(source)
.load(actualSource)
.diskCacheStrategy(diskCacheStrategy)
.encodeFormat(encodeFormat)

View File

@@ -1,51 +1,69 @@
package com.lukouguoji.module_base.impl
import android.view.View
import com.luck.picture.lib.adapter.holder.PreviewImageHolder
import com.luck.picture.lib.basic.PictureSelector
import com.lukouguoji.module_base.adapter.loadImage
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.FileBean
import com.lukouguoji.module_base.databinding.ItemImageSelectBinding
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.logd
import com.lukouguoji.module_base.ktx.loge
import com.lukouguoji.module_base.ui.page.preview.PreviewActivity
import com.lukouguoji.module_base.util.MediaUtil
class ImageSelectViewHolder(view: View) : BaseViewHolder<FileBean, ItemImageSelectBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item)!!
binding.bean = bean
binding.rl.setOnClickListener {
if (bean.path.isEmpty()) {
MediaUtil.pickImage(itemView.context, maxNum = 10) {
it.forEach {
logd("添加了图片 : ${it.realPath}")
getRecyclerView()?.commonAdapter()?.addItem(FileBean(path = it.realPath))
}
}
} else {
PreviewActivity.start(itemView.context, listOf(bean))
}
}
// 长按事件
binding.rl.setOnLongClickListener {
clickListener?.onItemClick(bindingAdapterPosition, binding.rl.id)
true
}
notifyItemClick(position, binding.ivDelete)
if (bean.isOnlineResource()) {
loge("开始下载 : ${bean.path}")
bean.download {
loadImage(binding.iv, it)
}
}
}
}
package com.lukouguoji.module_base.impl
import android.view.View
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.LazyHeaders
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.FileBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.databinding.ItemImageSelectBinding
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.logd
import com.lukouguoji.module_base.ui.page.preview.PreviewActivity
import com.lukouguoji.module_base.util.MediaUtil
import java.io.File
class ImageSelectViewHolder(view: View) : BaseViewHolder<FileBean, ItemImageSelectBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item)!!
binding.bean = bean
// 加载缩略图
if (bean.path.isNotEmpty()) {
if (bean.isOnlineResource()) {
val glideUrl = GlideUrl(
bean.path,
LazyHeaders.Builder()
.addHeader("Authorization", SharedPreferenceUtil.getString(Constant.Share.token))
.build()
)
Glide.with(itemView.context).load(glideUrl).into(binding.iv)
} else {
Glide.with(itemView.context).load(File(bean.path)).into(binding.iv)
}
}
binding.rl.setOnClickListener {
if (bean.path.isEmpty()) {
MediaUtil.pickImage(itemView.context, maxNum = 10) {
it.forEach {
logd("添加了图片 : ${it.realPath}")
getRecyclerView()?.commonAdapter()?.addItem(FileBean(path = it.realPath))
}
}
} else {
val items = getRecyclerView()?.commonAdapter()?.items
?.filterIsInstance<FileBean>()
?.filter { it.path.isNotEmpty() }
?: listOf(bean)
val previewList = items.map { fb ->
FileBean(path = if (fb.originalPic.isNotEmpty()) fb.originalPic else fb.path)
}
val previewPosition = items.indexOfFirst { it === bean }.coerceAtLeast(0)
PreviewActivity.start(itemView.context, previewList, previewPosition)
}
}
// 长按事件
binding.rl.setOnLongClickListener {
clickListener?.onItemClick(bindingAdapterPosition, binding.rl.id)
true
}
notifyItemClick(position, binding.ivDelete)
}
}

View File

@@ -24,7 +24,6 @@
<ImageView
android:id="@+id/iv"
loadImage="@{bean.path}"
visible="@{bean.path}"
android:layout_width="match_parent"
android:layout_height="match_parent"