爱简收旧衣按件回收前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

993 lines
30 KiB

<template>
<view class="inspect-result-container" :class="{ 'popup-open': isPopupOpen }">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="back" @tap="goBack">
<uni-icons type="left" size="20" color="#222" />
</view>
<text class="nav-title">步骤二合格质检</text>
<view class="nav-icons">
<uni-icons type="more" size="24" color="#222" />
</view>
</view>
<view class="main-content">
<!-- 合格产品卡片 -->
<view v-if="hasQualifiedItems" class="result-card">
<view class="card-title">合格产品</view>
<view v-for="item in qualifiedList" :key="item.id" class="result-row">
<view class="row-main">
<view class="goods-name-section">
<text class="goods-name">{{getItemName(item.id)}}</text>
<text class="goods-brand">{{getItemBrand(item.id)}}</text>
</view>
<text class="row-price">¥ {{item.price}} <text class="row-unit">/件</text></text>
<text class="row-count">x{{item.count}}</text>
<text class="row-total">¥{{item.total}}</text>
</view>
<view class="row-reason">
<text class="reason-label">{{getItemName(item.id)}}</text>
<view class="reason-select" @tap="selectReasonForQualified(item)">
<text class="reason-placeholder" :class="{ 'selected': hasSelectedReason(item) }">
{{ hasSelectedReason(item) ? '已选择' : '请选择理由(选填)' }}
</text>
<uni-icons type="right" size="18" color="#bbb" />
</view>
</view>
</view>
</view>
<!-- 不合格产品卡片 -->
<view v-if="hasUnqualifiedItems" class="result-card">
<view class="card-title">不合格产品</view>
<view v-for="group in unqualifiedGroups" :key="group.name" class="result-group">
<view class="row-main">
<view class="goods-name-section">
<text class="goods-name">{{getItemName(group.id)}}</text>
<text class="goods-brand">{{getItemBrand(group.id)}}</text>
</view>
<text class="row-price">¥ {{group.price}} <text class="row-unit">/件</text></text>
<text class="row-total">¥{{group.total}}</text>
</view>
<view v-for="item in group.items" :key="item.id" class="row-reason">
<text class="reason-label">{{item.name}}</text>
<view class="reason-select" @tap="selectReason(item)">
<text class="reason-placeholder" :class="{ 'selected': hasSelectedReason(item) }">
{{ hasSelectedReason(item) ? '已选择' : '请选择理由' }}
</text>
<uni-icons type="right" size="18" color="#bbb" />
</view>
</view>
</view>
</view>
<!-- 不可回收产品卡片 -->
<view v-if="hasUnrecyclableItems" class="result-card">
<view class="card-title">不可回收产品</view>
<view v-for="item in unrecyclableList" :key="item.id" class="result-row">
<view class="row-main">
<view class="goods-name-section">
<text class="goods-name">{{getItemName(item.id)}}</text>
<text class="goods-brand">{{getItemBrand(item.id)}}</text>
</view>
<text class="row-price">¥ {{item.price || '—'}} <text class="row-unit">/件</text></text>
<text class="row-count">x{{item.count}}</text>
<text class="row-total">¥{{item.total}}</text>
</view>
<view class="row-reason">
<text class="reason-label">{{getItemName(item.id)}}</text>
<view class="reason-select" @tap="selectReasonForUnrecyclable(item)">
<text class="reason-placeholder" :class="{ 'selected': hasSelectedReason(item) }">
{{ hasSelectedReason(item) ? '已选择' : '请选择理由(选填)' }}
</text>
<uni-icons type="right" size="18" color="#bbb" />
</view>
</view>
</view>
</view>
<!-- 回收信息卡片 -->
<view class="result-card info-card">
<view class="card-title-row">
<text class="card-title">回收信息</text>
<view class="status-tag">待质检</view>
</view>
<view class="info-row">
<text class="info-label">订单编号</text>
<text class="info-value copy-btn">{{ order?.ordeNo || 'RE82738127861525' }} 复制</text>
</view>
<view class="info-row">
<text class="info-label">取件时间</text>
<text class="info-value">{{ order?.goTime || '2025-03-20 11:00' }}</text>
</view>
</view>
</view>
<!-- 底部操作按钮 -->
<view class="footer-btns">
<button class="btn-outline" @tap="goPrev">上一步</button>
<button class="btn-main" @tap="finishInspect">完成质检</button>
</view>
<!-- 理由弹窗 -->
<uni-popup ref="reasonPopup" type="bottom" :mask-click="false" :safe-area="false" class="reason-popup-wrapper">
<view class="reason-popup">
<view class="popup-header">
<text class="popup-close" @tap="closeReasonPopup">关闭</text>
<text class="popup-title">{{ currentReasonTitle }}</text>
</view>
<scroll-view class="popup-content" scroll-y="true">
<view class="popup-section">
<text class="section-label">上传图片</text>
<view class="img-list">
<view class="img-item add" @tap="addReasonImg">
<uni-icons type="plusempty" size="32" color="#bbb" />
</view>
<view v-for="(img, idx) in reasonImages" :key="idx" class="img-item">
<image :src="img" class="img" />
<view class="img-del" @tap="removeReasonImg(idx)">×</view>
</view>
</view>
</view>
<view class="popup-section">
<text class="section-label">选择理由</text>
<view v-for="(item, index) in reasonOptions" :key="item.id" class="reason-row" @tap="toggleReason(index)">
<view :class="['checkbox', {checked: reasonChecked[index]}]" />
<text class="reason-text">{{ item.reason }}</text>
</view>
</view>
</scroll-view>
<button class="popup-save-btn" @tap="saveReason">保存</button>
</view>
</uni-popup>
</view>
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
import OSS from '@/utils/oss-upload/oss/index.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
inspectData: null, // 从步骤一传过来的质检数据
order: null, // 订单数据
qualifiedList: [],
unqualifiedGroups: [],
unrecyclableList: [],
reasonPopupVisible: false,
currentReasonTitle: '',
reasonImages: [],
reasonOptions: [],
reasonChecked: [],
currentReasonItem: null,
isPopupOpen: false // 控制弹窗状态
}
},
computed: {
hasQualifiedItems() {
return this.qualifiedList && this.qualifiedList.length > 0
},
hasUnqualifiedItems() {
return this.unqualifiedGroups && this.unqualifiedGroups.length > 0
},
hasUnrecyclableItems() {
return this.unrecyclableList && this.unrecyclableList.length > 0
}
},
onLoad(options) {
// 接收质检数据和订单数据
if (options && options.resultData) {
try {
const resultData = JSON.parse(decodeURIComponent(options.resultData))
this.inspectData = resultData.inspectResult
this.order = resultData.order
console.log('接收到的质检数据:', this.inspectData)
console.log('接收到的订单数据:', this.order)
this.processInspectData()
} catch (error) {
console.error('解析数据失败:', error)
}
}
// 兼容旧的参数格式
if (options && options.inspectData && !options.resultData) {
try {
this.inspectData = JSON.parse(decodeURIComponent(options.inspectData))
console.log('接收到的质检数据:', this.inspectData)
this.processInspectData()
} catch (error) {
console.error('解析质检数据失败:', error)
}
}
},
methods: {
processInspectData() {
if (!this.inspectData || !this.inspectData.list) return
this.qualifiedList = []
this.unqualifiedGroups = []
this.unrecyclableList = []
this.inspectData.list.forEach(item => {
// 跳过不可回收分类
if (item.id === 'unrecyclable') return
// 从order中获取对应的商品信息
const orderItem = this.order?.commonOrderList?.find(orderGoods => orderGoods.id == item.id)
if (!orderItem) return
const itemName = orderItem.title || '未知商品'
const itemBrand = orderItem.pinName || ''
const displayName = itemBrand ? `${itemName} ${itemBrand}` : itemName
const itemNames = itemBrand ? `${itemName}` : itemName
const itemPrice = orderItem.onePrice || 0
// 统计各种状态的数量
let qualifiedCount = 0
let unqualifiedCount = 0
let unrecyclableCount = 0
console.log('item', item)
item.commonOrderList.forEach(commonItem => {
if (commonItem.testingStatus === 0) {
qualifiedCount++
} else if (commonItem.testingStatus === 1) {
unqualifiedCount++
} else if (commonItem.testingStatus === 2) {
unrecyclableCount++
}
})
// 处理合格产品
if (qualifiedCount > 0) {
// 获取合格商品的理由和图片信息
const qualifiedCommonItem = item.commonOrderList.find(commonItem => commonItem.testingStatus === 0)
const savedImages = qualifiedCommonItem?.testingImages ? qualifiedCommonItem.testingImages.split(',').filter(img => img) : []
const savedReasons = this.parseTestingInstructions(qualifiedCommonItem?.testingInstructions || '')
this.qualifiedList.push({
id: item.id,
name: displayName,
shopClass: this.getShopClass(item.id),
shopId: item.shopId,
price: itemPrice,
count: qualifiedCount,
total: item.price || 0, // 使用质检时填写的总金额
reason: '',
images: savedImages,
reasons: savedReasons
})
}
// 处理不合格产品
if (unqualifiedCount > 0) {
const unqualifiedItems = []
let index = 1
item.commonOrderList.forEach(commonItem => {
if (commonItem.testingStatus === 1) {
const savedImages = commonItem.testingImages ? commonItem.testingImages.split(',').filter(img => img) : []
const savedReasons = this.parseTestingInstructions(commonItem.testingInstructions || '')
unqualifiedItems.push({
id: commonItem.id,
name: `${itemNames}${index}`,
shopClass: this.getShopClass(item.id),
shopId: item.shopId,
reason: '',
images: savedImages,
reasons: savedReasons
})
index++
}
})
if (unqualifiedItems.length > 0) {
this.unqualifiedGroups.push({
id: item.id,
name: displayName,
shopClass: this.getShopClass(item.id),
shopId: item.shopId,
price: itemPrice,
total: 0, // 不合格产品总价为0
items: unqualifiedItems
})
}
}
// 处理不可回收产品
if (unrecyclableCount > 0) {
// 获取不可回收商品的理由和图片信息
const unrecyclableCommonItem = item.commonOrderList.find(commonItem => commonItem.testingStatus === 2)
const savedImages = unrecyclableCommonItem?.testingImages ? unrecyclableCommonItem.testingImages.split(',').filter(img => img) : []
const savedReasons = this.parseTestingInstructions(unrecyclableCommonItem?.testingInstructions || '')
this.unrecyclableList.push({
id: item.id,
name: displayName,
shopClass: item.shopClass,
shopId: item.shopId,
price: '', // 不可回收产品不显示价格
count: unrecyclableCount,
total: 0,
reason: '',
images: savedImages,
reasons: savedReasons
})
}
})
console.log('处理后的数据:', {
qualifiedList: this.qualifiedList,
unqualifiedGroups: this.unqualifiedGroups,
unrecyclableList: this.unrecyclableList
})
},
goBack() {
uni.navigateBack()
},
goPrev() {
uni.navigateBack()
},
finishInspect() {
// 这里可以将最终的inspectData提交到服务器
this.inspectData["list"]=JSON.stringify(this.inspectData["list"], null, 2)
console.log('最终的质检数据:', this.inspectData);
// 可以调用API提交数据
this.$api('submitQualityInfo', this.inspectData , res => {
if (res && res.code === 200) {
uni.showToast({ title: '质检完成', icon: 'success' })
uni.navigateBack()
}
})
uni.showToast({ title: '完成质检', icon: 'success' })
},
selectReasonForUnqualified(item,type) {
this.$api('getcheckoutReasons', {
classId: item.shopClass,
type: type
}, res => {
console.log('res', res)
if(res.code == 200){
this.reasonOptions = res.result;
}
})
},
selectReason(item) {
console.log('item', item)
this.currentReasonItem = item
this.currentReasonTitle = item.name
this.reasonImages = item.images || []
this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
this.selectReasonForUnqualified(item,0)
this.lockScroll()
this.$refs.reasonPopup.open()
},
selectReasonForQualified(item) {
this.currentReasonItem = item
this.currentReasonTitle = this.getItemName(item.id)
this.reasonImages = item.images || []
this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
this.selectReasonForUnqualified(item,1)
this.lockScroll()
this.$refs.reasonPopup.open()
},
selectReasonForUnrecyclable(item) {
console.log('item', item)
this.currentReasonItem = item
this.currentReasonTitle = this.getItemName(item.id)
this.reasonImages = item.images || []
this.reasonChecked = item.reasons || Array(this.reasonOptions.length).fill(false)
this.selectReasonForUnqualified(item,2)
this.lockScroll()
this.$refs.reasonPopup.open()
},
closeReasonPopup() {
this.unlockScroll()
this.$refs.reasonPopup.close()
},
addReasonImg() {
// 检查是否已达到最大数量限制
if (this.reasonImages.length >= 3) {
uni.showToast({
title: '最多只能上传3张图片',
icon: 'none'
})
return
}
uni.chooseMedia({
count: 3 - this.reasonImages.length, // 剩余可选择数量
mediaType: ['image'], // 只选择图片
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机
maxDuration: 30,
camera: 'back',
success: (res) => {
console.log('选择的图片:', res.tempFiles)
// 显示上传进度
uni.showLoading({
title: '上传中...'
})
// 处理选择的图片
const uploadPromises = res.tempFiles.map(file => {
return this.uploadImageToOSS(file.tempFilePath)
})
// 批量上传
Promise.all(uploadPromises).then(urls => {
this.reasonImages = this.reasonImages.concat(urls)
uni.hideLoading()
uni.showToast({
title: '上传成功',
icon: 'success'
})
}).catch(error => {
console.error('上传失败:', error)
uni.hideLoading()
uni.showToast({
title: '上传失败,请重试',
icon: 'none'
})
})
},
fail: (error) => {
console.error('选择图片失败:', error)
uni.showToast({
title: '选择图片失败',
icon: 'none'
})
}
})
},
async uploadImageToOSS(filePath) {
try {
// 使用项目中的OSS上传工具
const url = await OSS.ossUpload(filePath)
return url
} catch (error) {
console.error('OSS上传失败:', error)
throw error
}
},
removeReasonImg(idx) {
this.reasonImages.splice(idx, 1)
},
toggleReason(idx) {
console.log
this.$set(this.reasonChecked, idx, !this.reasonChecked[idx])
},
saveReason() {
// 保存到当前item
if (this.currentReasonItem) {
this.currentReasonItem.images = [...this.reasonImages]
this.currentReasonItem.reasons = [...this.reasonChecked]
// console.log('this.currentReasonItem', this.currentReasonItem)
// 更新inspectData中的数据
this.updateInspectData()
}
this.closeReasonPopup()
},
updateInspectData() {
if (!this.inspectData || !this.currentReasonItem) return
// 获取选中的理由ID(假设理由选项的索引就是ID)
const selectedReasonIds = []
this.reasonChecked.forEach((checked, index) => {
if (checked) {
selectedReasonIds.push(this.reasonOptions[index].id.toString())
}
})
// 将理由ID用逗号分割保存
const testingInstructions = selectedReasonIds.join(',')
// 将图片URL用逗号分割保存
const testingImages = this.reasonImages.join(',')
// 根据当前选择的商品类型,找到对应的inspectData项进行更新
if (this.isQualifiedItem(this.currentReasonItem)) {
this.updateQualifiedItemInspectData(testingInstructions, testingImages)
} else if (this.isUnqualifiedItem(this.currentReasonItem)) {
this.updateUnqualifiedItemInspectData(testingInstructions, testingImages)
} else if (this.isUnrecyclableItem(this.currentReasonItem)) {
this.updateUnrecyclableItemInspectData(testingInstructions, testingImages)
}
console.log('更新后的inspectData:', JSON.stringify(this.inspectData, null, 2))
},
isQualifiedItem(item) {
return this.qualifiedList.some(qualified => qualified.id === item.id)
},
isUnqualifiedItem(item) {
return this.unqualifiedGroups.some(group =>
group.items.some(unqualified => unqualified.id === item.id)
)
},
isUnrecyclableItem(item) {
return this.unrecyclableList.some(unrecyclable => unrecyclable.id === item.id)
},
updateQualifiedItemInspectData(testingInstructions, testingImages) {
const inspectItem = this.inspectData.list.find(item => item.id == this.currentReasonItem.id)
if (inspectItem && inspectItem.commonOrderList) {
// 为合格的商品更新所有状态为0的项
inspectItem.commonOrderList.forEach(commonItem => {
if (commonItem.testingStatus === 0) {
commonItem.testingInstructions = testingInstructions
commonItem.testingImages = testingImages
}
})
}
},
updateUnqualifiedItemInspectData(testingInstructions, testingImages) {
// 对于不合格商品,需要根据具体的commonOrderList项ID来更新
this.unqualifiedGroups.forEach(group => {
const targetItem = group.items.find(item => item.id === this.currentReasonItem.id)
if (targetItem) {
// 找到对应的inspectData项
const inspectItem = this.inspectData.list.find(item => item.id == group.id)
if (inspectItem && inspectItem.commonOrderList) {
// 根据不合格项的ID找到对应的commonOrderList项
const commonItem = inspectItem.commonOrderList.find(common => common.id === targetItem.id)
if (commonItem) {
commonItem.testingInstructions = testingInstructions
commonItem.testingImages = testingImages
}
}
}
})
},
updateUnrecyclableItemInspectData(testingInstructions, testingImages) {
const inspectItem = this.inspectData.list.find(item => item.id == this.currentReasonItem.id)
if (inspectItem && inspectItem.commonOrderList) {
// 为不可回收的商品更新所有状态为2的项
inspectItem.commonOrderList.forEach(commonItem => {
if (commonItem.testingStatus === 2) {
commonItem.testingInstructions = testingInstructions
commonItem.testingImages = testingImages
}
})
}
},
lockScroll() {
// 禁用页面滚动
this.isPopupOpen = true
},
unlockScroll() {
// 恢复页面滚动
this.isPopupOpen = false
},
async onRefresh() {
await this.refreshData && this.refreshData()
},
refreshData() {
// 可根据实际需求刷新质检结果数据
// 例如重新请求接口或重置数据
},
getItemName(id) {
if (this.order && this.order.commonOrderList) {
const orderItem = this.order.commonOrderList.find(item => item.id == id)
return orderItem ? (orderItem.title || '未知商品') : '未知商品'
}
return '未知商品'
},
getShopClass(id) {
if (this.order && this.order.commonOrderList) {
// console.log('this.order', ShopClass)
const ShopClass = this.order.commonOrderList.find(item => item.id == id)
// console.log('ShopClass', ShopClass)
return ShopClass ? ShopClass.shopClass: ''
}
return ''
},
getItemBrand(id) {
if (this.order && this.order.commonOrderList) {
const orderItem = this.order.commonOrderList.find(item => item.id == id)
return orderItem ? (orderItem.pinName || '') : ''
}
return ''
},
parseTestingInstructions(instructions) {
// 解析理由ID字符串,返回布尔数组
const reasonArray = Array(this.reasonOptions.length).fill(false)
if (instructions) {
const selectedIds = instructions.split(',').map(id => id.trim()).filter(id => id)
selectedIds.forEach(id => {
const index = parseInt(id)
if (index >= 0 && index < reasonArray.length) {
reasonArray[index] = true
}
})
}
return reasonArray
},
hasSelectedReason(item) {
// 检查该商品是否已选择理由或上传图片
return (item.reasons && item.reasons.some(checked => checked)) ||
(item.images && item.images.length > 0)
}
}
}
</script>
<style lang="scss" scoped>
.inspect-result-container {
min-height: 100vh;
background: #f8f8f8;
display: flex;
flex-direction: column;
&.popup-open {
overflow: hidden;
position: fixed;
width: 100%;
height: 100vh;
}
}
.nav-bar {
display: flex;
align-items: center;
height: calc(150rpx + var(--status-bar-height));
padding: 0 32rpx;
padding-top: var(--status-bar-height);
background: #fff;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
box-sizing: border-box;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
.back {
padding: 20rpx;
margin-left: -20rpx;
}
.nav-title {
flex: 1;
text-align: center;
font-size: 32rpx;
font-weight: 500;
color: #222;
}
.nav-icons {
display: flex;
align-items: center;
gap: 12px;
}
}
.main-content {
margin-top: calc(200rpx + var(--status-bar-height));
display: flex;
flex-direction: column;
background: none;
padding-bottom: 120px;
}
.result-card {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(0,0,0,0.06);
margin: 0 24px 24px 24px;
padding: 24px 24px 0 24px;
}
.card-title {
font-size: 16px;
font-weight: bold;
color: #222;
margin-bottom: 18px;
}
.card-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 18px;
}
.status-tag {
background: #fff7e6;
color: #ffb400;
font-size: 12px;
border-radius: 12px;
padding: 2px 14px;
font-weight: 400;
height: 22px;
display: flex;
align-items: center;
}
.result-row, .result-group {
margin-bottom: 18px;
}
.row-main {
display: flex;
align-items: center;
.goods-name-section {
display: flex;
flex-direction: column;
margin-right: 8px;
.goods-name {
font-size: 14px;
font-weight: bold;
color: #222;
line-height: 1.2;
}
.goods-brand {
font-size: 11px;
color: #999;
font-weight: normal;
line-height: 1.2;
margin-top: 2px;
}
}
.row-name {
font-size: 14px;
font-weight: bold;
color: #222;
margin-right: 8px;
}
.row-price {
font-size: 13px;
color: #ffb400;
font-weight: bold;
margin-right: 8px;
.row-unit {
font-size: 11px;
color: #bbb;
}
}
.row-count {
font-size: 13px;
color: #888;
margin-right: 8px;
}
.row-total {
font-size: 14px;
color: #222;
font-weight: bold;
margin-left: auto;
}
}
.row-reason {
display: flex;
align-items: center;
margin-top: 8px;
.reason-label {
font-size: 13px;
color: #bbb;
min-width: 80px;
}
.reason-input {
flex: 1;
height: 36px;
border-radius: 12px;
background: #f6f6f6;
border: none;
font-size: 14px;
color: #222;
padding-left: 12px;
margin-left: 8px;
}
.reason-select {
flex: 1;
display: flex;
align-items: center;
height: 36px;
border-radius: 12px;
background: #f6f6f6;
font-size: 14px;
color: #bbb;
padding-left: 12px;
margin-left: 8px;
justify-content: flex-end;
}
.reason-placeholder {
color: #bbb;
font-size: 14px;
&.selected {
color: #52c41a;
font-weight: 500;
}
}
}
.info-card {
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(0,0,0,0.06);
margin: 0 24px 24px 24px;
padding: 24px 24px 0 24px;
}
.info-row {
display: flex;
align-items: center;
margin-bottom: 16px;
.info-label {
font-size: 13px;
color: #bbb;
min-width: 80px;
}
.info-value {
font-size: 13px;
color: #222;
margin-left: 8px;
}
.copy-btn {
color: #ffb400;
margin-left: 8px;
}
}
.footer-btns {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
display: flex;
gap: 16px;
padding: 12px 16px 24px 16px;
z-index: 101;
.btn-outline {
flex: 1;
height: 40px;
border-radius: 16px;
border: 1px solid #ffe09a;
color: #ffb400;
background: #fff0d2;
font-size: 15px;
font-weight: 500;
box-shadow: none;
padding: 0 18px;
}
.btn-main {
flex: 1;
height: 40px;
border-radius: 16px;
background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
color: #fff;
border: none;
font-size: 15px;
font-weight: 500;
box-shadow: none;
padding: 0 18px;
}
}
.reason-popup-wrapper {
z-index: 10000 !important;
}
.reason-popup-wrapper .uni-popup__wrapper {
z-index: 10000 !important;
}
.reason-popup {
background: #fff;
border-radius: 24px 24px 0 0;
padding: 0;
height: 75vh;
position: relative;
z-index: 9999;
.popup-header {
display: flex;
align-items: center;
justify-content: center;
height: 60px;
border-bottom: 1px solid #f0f0f0;
position: relative;
.popup-close {
position: absolute;
left: 20px;
color: #666;
font-size: 16px;
}
.popup-title {
font-size: 18px;
font-weight: 600;
color: #222;
}
}
.popup-content {
height: calc(75vh - 60px - 82px);
overflow-y: auto;
}
.popup-section {
padding: 0 20px 24px 20px;
&:first-child {
padding-top: 24px;
}
.section-label {
font-size: 16px;
color: #222;
margin-bottom: 16px;
display: block;
font-weight: 500;
}
.img-list {
display: flex;
gap: 12px;
margin-bottom: 32px;
.img-item {
width: 80px;
height: 80px;
border-radius: 12px;
background: #f8f8f8;
position: relative;
.img {
width: 100%;
height: 100%;
border-radius: 12px;
object-fit: cover;
}
.img-del {
position: absolute;
top: -6px;
right: -6px;
width: 24px;
height: 24px;
background: rgba(0,0,0,0.6);
color: #fff;
border-radius: 50%;
text-align: center;
line-height: 24px;
font-size: 16px;
font-weight: bold;
}
&.add {
display: flex;
align-items: center;
justify-content: center;
background: #f8f8f8;
border: 2px dashed #ddd;
color: #bbb;
}
}
}
.reason-row {
display: flex;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.checkbox {
width: 20px;
height: 20px;
border-radius: 4px;
border: 2px solid #ddd;
margin-right: 12px;
background: #fff;
position: relative;
&.checked {
border-color: #ffb400;
background: #ffb400;
&::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
font-size: 12px;
font-weight: bold;
}
}
}
.reason-text {
font-size: 16px;
color: #222;
line-height: 1.4;
}
}
}
.popup-save-btn {
position: fixed;
bottom: 34px;
left: 20px;
right: 20px;
height: 48px;
border-radius: 24px;
background: linear-gradient(90deg, #ffd01e 0%, #ffac04 100%);
color: #fff;
font-size: 18px;
font-weight: 600;
border: none;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(255, 172, 4, 0.3);
}
}
</style>