2098 lines
43 KiB
Vue
2098 lines
43 KiB
Vue
<template>
|
||
<view class="index-container">
|
||
<!-- 返回按钮 -->
|
||
<!-- <view v-if="showBackButton" class="back-button" @click="handleBack">
|
||
<IconFont name="arrow-left" color="#333" :size="20" />
|
||
<text class="back-text">返回</text>
|
||
</view> -->
|
||
|
||
<view v-if="!isBound" class="state-hint">
|
||
<view class="state-img-wrapper" @click="handleEmptyStateClick">
|
||
<image class="state-img" :src="emptyImg" mode="aspectFit" />
|
||
</view>
|
||
<view class="state-title">暂无数据</view>
|
||
</view>
|
||
|
||
<view v-else class="list-container">
|
||
<!-- 搜索框和状态筛选 -->
|
||
<view class="search-container">
|
||
<view class="search-box">
|
||
<IconFont name="search" color="#999" :size="16" />
|
||
<input :value="searchKeyword" @input="(e) => searchKeyword = e.detail.value" placeholder="请输入订单号搜索"
|
||
class="search-input" @confirm="handleSearch" confirm-type="search" />
|
||
<view v-if="searchKeyword" class="search-clear" @click="clearSearch">
|
||
<IconFont name="close" color="#999" :size="14" />
|
||
</view>
|
||
</view>
|
||
<!-- 状态筛选:Tab 可换行显示 -->
|
||
<view class="status-tabs">
|
||
<view class="status-tab" v-for="(item, idx) in statusOptions" :key="idx"
|
||
:class="{ active: selectedStatusIndex === idx }" @click="onStatusTabClick(idx)">
|
||
{{ item.label }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<OrderList
|
||
:check-status="selectedStatus"
|
||
:search-keyword="searchKeyword"
|
||
:show-action="true"
|
||
:can-view="canView"
|
||
:can-add="canAdd"
|
||
:can-edit="canEdit"
|
||
:can-delete="canDelete"
|
||
@item-click="handleItemClick"
|
||
@refresh="handleListRefresh"
|
||
@viewCheck="handleViewCheck"
|
||
@view-check="handleViewCheck"
|
||
ref="orderListRef" />
|
||
</view>
|
||
|
||
<!-- 图片预览弹窗 -->
|
||
<nut-popup v-model:visible="showImagePopup" position="center" :style="{ padding: '20rpx' }" round
|
||
:close-on-click-overlay="true">
|
||
<view class="image-popup">
|
||
<view class="image-popup-header">
|
||
<text class="image-popup-title">
|
||
图片预览 ({{ currentImageIndex + 1 }}/{{ currentImages.length }})
|
||
</text>
|
||
<view class="image-popup-close" @click="showImagePopup = false">
|
||
<IconFont name="close" color="#666" :size="20" />
|
||
</view>
|
||
</view>
|
||
<swiper class="image-swiper" :current="currentImageIndex" @change="onSwiperChange"
|
||
:indicator-dots="currentImages.length > 1" :indicator-color="'rgba(0, 0, 0, 0.3)'"
|
||
:indicator-active-color="'#1890ff'" :circular="true">
|
||
<swiper-item v-for="(image, index) in currentImages" :key="index">
|
||
<image :src="image" mode="aspectFit" class="preview-image" />
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
</nut-popup>
|
||
|
||
<!-- 质检表单弹窗 -->
|
||
<CheckFormPopup v-model="showFormPopup" :order-item="currentFormItem" :mode="formMode"
|
||
@submit-success="handleFormSubmitSuccess" />
|
||
|
||
<!-- 查看质检信息弹窗 -->
|
||
<CheckFormPopup v-model="showViewCheckPopup" :order-item="currentViewItem" mode="view" />
|
||
|
||
<!-- 绑定弹窗 -->
|
||
<BindPopup v-model="showBindPopup" @bind-success="handleBindSuccess" />
|
||
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, computed, watch } from 'vue'
|
||
import Taro from '@tarojs/taro'
|
||
import { IconFont } from '@nutui/icons-vue'
|
||
import { request } from '../../utils/request'
|
||
import api from '../../api'
|
||
import emptyImg from '../../assets/empty-state.svg'
|
||
import OrderList from '../../components/order-list/index.vue'
|
||
import BindPopup from '../../components/bind-popup/index.vue'
|
||
import CheckFormPopup from '../../components/check-form-popup/index.vue'
|
||
import { useAuth } from '../../composables/useAuth'
|
||
|
||
// 导入图片工具函数
|
||
import { buildImgUrl, buildFileUrl } from '../../utils/image'
|
||
|
||
// 判断是否显示返回按钮(页面栈长度大于1时显示)
|
||
const showBackButton = computed(() => {
|
||
try {
|
||
const pages = Taro.getCurrentPages()
|
||
return pages.length > 1
|
||
} catch (e) {
|
||
return false
|
||
}
|
||
})
|
||
|
||
// 返回上一页
|
||
const handleBack = () => {
|
||
try {
|
||
const pages = Taro.getCurrentPages()
|
||
if (pages.length > 1) {
|
||
Taro.navigateBack()
|
||
} else {
|
||
// 如果没有上一页,跳转到首页
|
||
Taro.switchTab({
|
||
url: '/pages/home/index'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('返回失败:', error)
|
||
// 如果 navigateBack 失败,尝试跳转到首页
|
||
Taro.switchTab({
|
||
url: '/pages/home/index'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 图标列表(NutUI内置图标,使用 IconFont 的 name 属性)
|
||
const iconList = [
|
||
'home',
|
||
'my',
|
||
'setting',
|
||
'notice',
|
||
'cart',
|
||
'category',
|
||
'star',
|
||
'heart',
|
||
'share',
|
||
'download',
|
||
'uploader',
|
||
'edit',
|
||
'del',
|
||
'search',
|
||
'find',
|
||
'add',
|
||
'minus',
|
||
'check',
|
||
'close',
|
||
'arrow-right',
|
||
'star-fill',
|
||
'heart-fill',
|
||
'cart2',
|
||
'shop',
|
||
'people'
|
||
]
|
||
|
||
// 图标颜色列表(蓝色系)
|
||
const iconColors = [
|
||
'#1890ff',
|
||
'#40a9ff',
|
||
'#69c0ff',
|
||
'#91d5ff',
|
||
'#bae7ff',
|
||
'#096dd9',
|
||
'#0050b3'
|
||
]
|
||
|
||
// 标题模板
|
||
const titleTemplates = [
|
||
'项目管理系统',
|
||
'数据分析平台',
|
||
'客户关系管理',
|
||
'在线协作工具',
|
||
'内容管理系统',
|
||
'电商运营平台',
|
||
'移动应用开发',
|
||
'云存储服务',
|
||
'智能推荐系统',
|
||
'企业办公套件',
|
||
'在线教育平台',
|
||
'社交网络应用',
|
||
'视频会议系统',
|
||
'任务管理工具',
|
||
'财务管理系统'
|
||
]
|
||
|
||
// 描述模板
|
||
const descTemplates = [
|
||
'高效的项目管理解决方案,提升团队协作效率',
|
||
'强大的数据分析能力,助力业务决策',
|
||
'完善的客户管理功能,提升客户满意度',
|
||
'实时协作编辑,让团队工作更高效',
|
||
'灵活的内容管理,满足各种业务需求',
|
||
'全面的电商功能,助力业务增长',
|
||
'专业的移动应用开发服务',
|
||
'安全可靠的云存储解决方案',
|
||
'基于AI的智能推荐算法',
|
||
'一站式企业办公解决方案',
|
||
'优质的在线教育体验',
|
||
'连接你我,分享生活',
|
||
'高清流畅的视频会议体验',
|
||
'简单易用的任务管理工具',
|
||
'专业的财务管理解决方案'
|
||
]
|
||
|
||
// 位置列表
|
||
const locations = [
|
||
'北京',
|
||
'上海',
|
||
'广州',
|
||
'深圳',
|
||
'杭州',
|
||
'成都',
|
||
'武汉',
|
||
'西安',
|
||
'南京',
|
||
'重庆'
|
||
]
|
||
|
||
// 生成随机数据
|
||
const generateRandomItem = (id) => {
|
||
const randomIcon = iconList[Math.floor(Math.random() * iconList.length)]
|
||
const randomIconColor = iconColors[Math.floor(Math.random() * iconColors.length)]
|
||
const randomTitle = titleTemplates[Math.floor(Math.random() * titleTemplates.length)]
|
||
const randomDesc = descTemplates[Math.floor(Math.random() * descTemplates.length)]
|
||
const randomLocation = locations[Math.floor(Math.random() * locations.length)]
|
||
const randomTime = `${Math.floor(Math.random() * 12) + 1}小时前`
|
||
const images = getRandomImages(id)
|
||
|
||
return {
|
||
id,
|
||
icon: randomIcon,
|
||
iconColor: randomIconColor,
|
||
title: randomTitle,
|
||
description: randomDesc,
|
||
location: randomLocation,
|
||
time: randomTime,
|
||
images: images
|
||
}
|
||
}
|
||
|
||
// 状态文案
|
||
const getStatusText = (status) => {
|
||
const map = {
|
||
0: '待质检',
|
||
2: '质检通过',
|
||
3: '质检失败'
|
||
}
|
||
return map[status] || '未知状态'
|
||
}
|
||
|
||
// 列表数据
|
||
const listData = ref([])
|
||
const safeList = computed(() => {
|
||
const arr = Array.isArray(listData.value) ? listData.value : []
|
||
return arr.filter(Boolean)
|
||
})
|
||
const loading = ref(false)
|
||
const hasMore = ref(true)
|
||
const page = ref(1)
|
||
const pageSize = 10
|
||
const searchKeyword = ref('') // 搜索关键词
|
||
|
||
// 状态筛选(Tab)
|
||
// 状态:全部 / 待质检 / 已质检 / 拆包中 / 已驳回 / 质检完成 / 质检作废
|
||
const statusOptions = [
|
||
{ label: '全部', value: '' },
|
||
{ label: '待质检', value: 0 },
|
||
{ label: '已质检', value: 1 },
|
||
{ label: '拆包中', value: 2 },
|
||
{ label: '已驳回', value: 3 },
|
||
{ label: '质检完成', value: 4 },
|
||
{ label: '质检作废', value: 5 }
|
||
]
|
||
const selectedStatusIndex = ref(0) // 当前选中的状态索引
|
||
const selectedStatus = computed(() => statusOptions[selectedStatusIndex.value].value)
|
||
|
||
// 弹窗控制
|
||
const showImagePopup = ref(false)
|
||
const showFormPopup = ref(false)
|
||
const currentImages = ref([])
|
||
const currentImageIndex = ref(0)
|
||
const formRef = ref(null)
|
||
|
||
// 使用公共登录逻辑
|
||
const { token, isBound, showBindPopup, checkAuth, showBindPopupFromError } = useAuth()
|
||
|
||
// 权限检查
|
||
const permissions = ref([])
|
||
|
||
// 权限常量
|
||
const PERMISSIONS = {
|
||
VIEW: 'twopoint_zhxyOrderCheck_view', // 查看
|
||
ADD: 'twopoint_zhxyOrderCheck_add', // 新增
|
||
EDIT: 'twopoint_zhxyOrderCheck_edit', // 编辑
|
||
DEL: 'twopoint_zhxyOrderCheck_del' // 删除
|
||
}
|
||
|
||
// 权限检查函数
|
||
const hasPermission = (permission) => {
|
||
if (!permissions.value || permissions.value.length === 0) {
|
||
console.log('权限数组为空,返回 false')
|
||
return false
|
||
}
|
||
const has = permissions.value.includes(permission)
|
||
console.log(`检查权限 ${permission}:`, has, '权限数组:', permissions.value)
|
||
return has
|
||
}
|
||
|
||
// 计算属性:是否有查看权限
|
||
const canView = computed(() => hasPermission(PERMISSIONS.VIEW))
|
||
// 计算属性:是否有新增权限
|
||
const canAdd = computed(() => hasPermission(PERMISSIONS.ADD))
|
||
// 计算属性:是否有编辑权限
|
||
const canEdit = computed(() => hasPermission(PERMISSIONS.EDIT))
|
||
// 计算属性:是否有删除权限
|
||
const canDelete = computed(() => hasPermission(PERMISSIONS.DEL))
|
||
|
||
// 加载权限数据
|
||
const loadPermissions = () => {
|
||
try {
|
||
const storedPermissions = Taro.getStorageSync('permissions')
|
||
console.log('存储的权限数据:', storedPermissions)
|
||
console.log('权限数据类型:', typeof storedPermissions)
|
||
console.log('是否为数组:', Array.isArray(storedPermissions))
|
||
|
||
if (storedPermissions) {
|
||
// 如果是数组,直接使用
|
||
if (Array.isArray(storedPermissions)) {
|
||
permissions.value = storedPermissions
|
||
}
|
||
// 如果是对象,尝试提取权限数组
|
||
else if (typeof storedPermissions === 'object') {
|
||
// 可能是 { permissions: [...] } 格式
|
||
if (storedPermissions.permissions && Array.isArray(storedPermissions.permissions)) {
|
||
permissions.value = storedPermissions.permissions
|
||
}
|
||
// 可能是对象数组,需要提取权限标识
|
||
else if (Array.isArray(Object.values(storedPermissions))) {
|
||
// 尝试从对象中提取权限标识
|
||
permissions.value = Object.values(storedPermissions).filter(p => typeof p === 'string')
|
||
}
|
||
// 如果是对象,尝试获取所有键值
|
||
else {
|
||
permissions.value = Object.keys(storedPermissions).filter(k => typeof k === 'string')
|
||
}
|
||
}
|
||
// 如果是字符串,尝试解析
|
||
else if (typeof storedPermissions === 'string') {
|
||
try {
|
||
const parsed = JSON.parse(storedPermissions)
|
||
if (Array.isArray(parsed)) {
|
||
permissions.value = parsed
|
||
}
|
||
} catch (e) {
|
||
permissions.value = []
|
||
}
|
||
}
|
||
else {
|
||
permissions.value = []
|
||
}
|
||
} else {
|
||
permissions.value = []
|
||
}
|
||
|
||
console.log('最终权限数组:', permissions.value)
|
||
console.log('权限检查结果:', {
|
||
canView: canView.value,
|
||
canAdd: canAdd.value,
|
||
canEdit: canEdit.value,
|
||
canDelete: canDelete.value
|
||
})
|
||
} catch (error) {
|
||
console.error('加载权限失败:', error)
|
||
permissions.value = []
|
||
}
|
||
}
|
||
|
||
// 检查是否需要重新绑定(来自 424 错误)
|
||
const checkNeedRebind = () => {
|
||
const needRebind = Taro.getStorageSync('needRebind')
|
||
if (needRebind) {
|
||
showBindPopupFromError()
|
||
}
|
||
}
|
||
const canViewList = computed(() => isBound.value)
|
||
const isFirstLoad = ref(true) // 是否是首次加载
|
||
|
||
// 点击暂无数据图标,触发登录检查
|
||
const handleEmptyStateClick = async () => {
|
||
await checkAuth()
|
||
}
|
||
|
||
// 绑定成功回调
|
||
const handleBindSuccess = () => {
|
||
// 绑定成功后刷新列表
|
||
if (orderListRef.value) {
|
||
orderListRef.value.refresh()
|
||
}
|
||
|
||
// 绑定成功后,如果有待打开的列表项,根据checkStatus打开表单
|
||
if (currentItem.value) {
|
||
setTimeout(() => {
|
||
const checkStatus = currentItem.value.checkStatus
|
||
if (checkStatus === 0) {
|
||
openForm(currentItem.value, 'create')
|
||
} else if (checkStatus === 3) {
|
||
openForm(currentItem.value, 'edit')
|
||
}
|
||
currentItem.value = null
|
||
}, 500)
|
||
}
|
||
}
|
||
|
||
const formMode = ref('create') // 'create' 或 'edit'
|
||
const currentFormItem = ref(null) // 当前表单对应的订单项
|
||
const showViewCheckPopup = ref(false) // 查看质检信息弹窗
|
||
const currentViewItem = ref(null) // 当前查看的订单项
|
||
|
||
// 生成随机图片URL数组(使用占位图服务)
|
||
const getRandomImages = (id) => {
|
||
// 每个列表项生成1-5张随机图片
|
||
const imageCount = Math.floor(Math.random() * 5) + 1
|
||
const images = []
|
||
const width = 600
|
||
const height = 400
|
||
|
||
for (let i = 0; i < imageCount; i++) {
|
||
const seed = (id * 10 + i) % 100
|
||
images.push(`https://picsum.photos/seed/${seed}/${width}/${height}`)
|
||
}
|
||
|
||
return images
|
||
}
|
||
|
||
// 从 localImg 字符串拆解图片URL数组
|
||
const buildImagesFromLocalImg = (localImg) => {
|
||
if (!localImg) return []
|
||
const source = Array.isArray(localImg) ? localImg : String(localImg).split(/[,;\s]+/)
|
||
return source
|
||
.map((item) => String(item).trim())
|
||
.filter(Boolean)
|
||
.map((fileName) => buildFileUrl(fileName))
|
||
}
|
||
|
||
// 加载数据
|
||
const loadData = async (isRefresh = false) => {
|
||
if (loading.value) return
|
||
if (!canViewList.value) {
|
||
loading.value = false
|
||
return
|
||
}
|
||
|
||
loading.value = true
|
||
|
||
try {
|
||
// 调用真实的 API 接口
|
||
const params = {
|
||
quecurrent: isRefresh ? 1 : page.value,
|
||
size: pageSize
|
||
}
|
||
|
||
// 如果有搜索关键词,添加orderNum参数
|
||
if (searchKeyword.value && searchKeyword.value.trim()) {
|
||
params.orderNum = searchKeyword.value.trim()
|
||
}
|
||
|
||
// 如果有选中的状态,添加checkStatus参数
|
||
if (selectedStatus.value !== '') {
|
||
params.checkStatus = selectedStatus.value
|
||
}
|
||
|
||
const res = await api.getCheckOrder(params)
|
||
|
||
if (res.statusCode === 200) {
|
||
const raw =
|
||
res.data?.records ??
|
||
res.data?.data?.records ??
|
||
res.data?.data ??
|
||
res.data ??
|
||
[]
|
||
const newData = Array.isArray(raw) ? raw : []
|
||
|
||
// 规范化数据:处理 localImg 为图片数组,并确保 id 存在
|
||
const startIndex = isRefresh ? 0 : listData.value.length
|
||
const processed = newData.map((item, idx) => {
|
||
const images =
|
||
Array.isArray(item?.images) && item.images.length > 0
|
||
? item.images
|
||
: buildImagesFromLocalImg(item?.localImg)
|
||
|
||
const fallbackId =
|
||
item?.id ??
|
||
item?.contractId ??
|
||
`${item?.companyName || 'item'}-${startIndex + idx}`
|
||
|
||
return {
|
||
...item,
|
||
id: fallbackId,
|
||
images
|
||
}
|
||
})
|
||
|
||
if (isRefresh) {
|
||
listData.value = processed
|
||
page.value = 1
|
||
} else {
|
||
listData.value = [...listData.value, ...processed]
|
||
page.value++
|
||
}
|
||
|
||
// 判断是否还有更多数据
|
||
if (newData.length < pageSize) {
|
||
hasMore.value = false
|
||
}
|
||
} else {
|
||
throw new Error(res.data?.message || '请求失败')
|
||
}
|
||
} catch (error) {
|
||
Taro.showToast({
|
||
title: error.message || '加载失败,请重试',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
} finally {
|
||
loading.value = false
|
||
|
||
// 停止下拉刷新动画
|
||
if (isRefresh) {
|
||
Taro.stopPullDownRefresh()
|
||
}
|
||
}
|
||
}
|
||
|
||
// 下拉刷新函数
|
||
const onRefresh = () => {
|
||
if (!canViewList.value) {
|
||
Taro.showToast({
|
||
title: '请先登录并绑定手机号',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
Taro.stopPullDownRefresh()
|
||
return
|
||
}
|
||
if (orderListRef.value) {
|
||
orderListRef.value.refresh()
|
||
}
|
||
Taro.stopPullDownRefresh()
|
||
}
|
||
|
||
// 触底加载 - 使用页面滚动到底部事件
|
||
const onReachBottom = () => {
|
||
if (canViewList.value && orderListRef.value) {
|
||
orderListRef.value.loadMore()
|
||
}
|
||
}
|
||
|
||
// 点击图标 - 单图预览(carImg)
|
||
const handleIconClick = (item) => {
|
||
if (!item) return
|
||
const imgUrl = buildImgUrl(item.carImg || '')
|
||
if (!imgUrl) {
|
||
Taro.showToast({
|
||
title: '暂无车辆图片',
|
||
icon: 'none',
|
||
duration: 1500
|
||
})
|
||
return
|
||
}
|
||
Taro.previewImage({
|
||
current: imgUrl,
|
||
urls: [imgUrl]
|
||
})
|
||
}
|
||
|
||
// 拨打电话
|
||
const makePhoneCall = (phone) => {
|
||
if (!phone) {
|
||
Taro.showToast({
|
||
title: '当前司机无手机号',
|
||
icon: 'none',
|
||
duration: 1500
|
||
})
|
||
return
|
||
}
|
||
Taro.makePhoneCall({
|
||
phoneNumber: String(phone)
|
||
})
|
||
}
|
||
|
||
// Swiper 切换事件
|
||
const onSwiperChange = (e) => {
|
||
currentImageIndex.value = e.detail.current
|
||
}
|
||
|
||
// 存储当前点击的列表项,用于登录后打开表单
|
||
const currentItem = ref(null)
|
||
|
||
// 打开表单 - 使用组件
|
||
const openForm = (item, mode = 'create') => {
|
||
if (!item) return
|
||
currentFormItem.value = item
|
||
formMode.value = mode
|
||
showFormPopup.value = true
|
||
}
|
||
|
||
// 格式化时间:只显示年月日、时分
|
||
const formatDateTime = (dateTime) => {
|
||
if (!dateTime) return ''
|
||
|
||
try {
|
||
const date = new Date(dateTime)
|
||
if (isNaN(date.getTime())) {
|
||
// 如果不是标准日期格式,尝试其他格式
|
||
return dateTime
|
||
}
|
||
|
||
const year = date.getFullYear()
|
||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||
const day = String(date.getDate()).padStart(2, '0')
|
||
const hours = String(date.getHours()).padStart(2, '0')
|
||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||
|
||
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||
} catch (e) {
|
||
// 如果解析失败,返回原值
|
||
return dateTime
|
||
}
|
||
}
|
||
|
||
// 搜索处理
|
||
const orderListRef = ref(null)
|
||
const handleSearch = () => {
|
||
// 通过组件ref刷新列表
|
||
if (orderListRef.value) {
|
||
orderListRef.value.refresh()
|
||
}
|
||
}
|
||
|
||
// 清空搜索
|
||
const clearSearch = () => {
|
||
searchKeyword.value = ''
|
||
// 通过组件ref刷新列表
|
||
if (orderListRef.value) {
|
||
orderListRef.value.refresh()
|
||
}
|
||
}
|
||
|
||
// 状态筛选改变
|
||
const onStatusChange = (e) => {
|
||
const index = parseInt(e.detail.value)
|
||
selectedStatusIndex.value = index
|
||
// 状态改变时重置分页并刷新数据
|
||
page.value = 1
|
||
hasMore.value = true
|
||
listData.value = []
|
||
loadData(true)
|
||
}
|
||
|
||
// 复制订单号
|
||
const copyOrderNum = (orderNum) => {
|
||
if (!orderNum) return
|
||
|
||
Taro.setClipboardData({
|
||
data: String(orderNum),
|
||
success: () => {
|
||
Taro.showToast({
|
||
title: '订单号已复制',
|
||
icon: 'success',
|
||
duration: 2000
|
||
})
|
||
},
|
||
fail: () => {
|
||
Taro.showToast({
|
||
title: '复制失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
// 显示确认框后再打开表单
|
||
const showConfirmBeforeOpenForm = (item, mode) => {
|
||
// 获取车牌号和品类名称
|
||
const carNum = item.carNum || '--'
|
||
const categoryName = item.orderTypeName || '--'
|
||
|
||
Taro.showModal({
|
||
title: '确认质检',
|
||
content: `车牌号:${carNum}\n品类:${categoryName}\n\n确认开始质检吗?`,
|
||
confirmText: '确认',
|
||
cancelText: '取消',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
// 用户确认后打开表单
|
||
openForm(item, mode)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 点击列表项其他部分 - 根据checkStatus判断
|
||
const handleItemClick = (item) => {
|
||
if (!item) return
|
||
// 检查绑定状态
|
||
if (!isBound.value) {
|
||
currentItem.value = item
|
||
showBindPopup.value = true
|
||
return
|
||
}
|
||
|
||
const checkStatus = item.checkStatus
|
||
if (checkStatus === 0) {
|
||
// 待质检:先显示确认框,再打开新增表单
|
||
// 权限检查在 showConfirmBeforeOpenForm 中进行,无权限会静默返回
|
||
if (canAdd.value) {
|
||
showConfirmBeforeOpenForm(item, 'create')
|
||
}
|
||
} else if (checkStatus === 3) {
|
||
// 供应商驳回:先显示确认框,再打开编辑表单
|
||
// 权限检查在 showConfirmBeforeOpenForm 中进行,无权限会静默返回
|
||
if (canEdit.value) {
|
||
showConfirmBeforeOpenForm(item, 'edit')
|
||
}
|
||
} else if (checkStatus === 2) {
|
||
// 供应商确认,拆包中:允许编辑
|
||
// 权限检查在 showConfirmBeforeOpenForm 中进行,无权限会静默返回
|
||
if (canEdit.value) {
|
||
showConfirmBeforeOpenForm(item, 'edit')
|
||
}
|
||
}
|
||
// 其他状态静默处理,不显示任何提示
|
||
}
|
||
|
||
// 列表刷新回调
|
||
const handleListRefresh = () => {
|
||
if (orderListRef.value) {
|
||
orderListRef.value.refresh()
|
||
}
|
||
}
|
||
|
||
// 查看质检信息
|
||
const handleViewCheck = (item) => {
|
||
if (!item) {
|
||
return
|
||
}
|
||
|
||
// 权限检查 - 静默处理,无权限直接返回
|
||
if (!canView.value) {
|
||
return
|
||
}
|
||
|
||
// 先设置订单项,再打开弹窗,确保数据传递正确
|
||
currentViewItem.value = { ...item }
|
||
showViewCheckPopup.value = true
|
||
}
|
||
|
||
// 状态Tab点击
|
||
const onStatusTabClick = (idx) => {
|
||
selectedStatusIndex.value = idx
|
||
// OrderList 组件的 watch 会自动监听 checkStatus 变化并刷新
|
||
}
|
||
|
||
// 表单提交成功回调
|
||
const handleFormSubmitSuccess = () => {
|
||
// 刷新列表
|
||
if (orderListRef.value) {
|
||
orderListRef.value.refresh()
|
||
}
|
||
}
|
||
|
||
// 初始化
|
||
onMounted(() => {
|
||
// 加载权限数据
|
||
loadPermissions()
|
||
|
||
// 页面进入时检查登录状态
|
||
checkAuth().then((isAuth) => {
|
||
// 检查是否需要重新绑定(来自 424 错误)
|
||
checkNeedRebind()
|
||
// 登录检查完成后,将刷新函数存储到全局,供 script 块使用
|
||
if (typeof globalThis !== 'undefined') {
|
||
globalThis.__pageRefreshHandler = onRefresh
|
||
globalThis.__pageReachBottomHandler = onReachBottom
|
||
}
|
||
|
||
// 检查 URL 参数,如果是从首页跳转过来的,自动打开表单
|
||
const pages = Taro.getCurrentPages()
|
||
const currentPage = pages[pages.length - 1]
|
||
if (currentPage && currentPage.options) {
|
||
const { orderId, autoOpen } = currentPage.options
|
||
if (orderId && autoOpen === 'true' && isAuth) {
|
||
// 从订单列表中找到对应的订单
|
||
setTimeout(async () => {
|
||
if (orderListRef.value) {
|
||
// 先刷新列表,确保数据是最新的
|
||
await orderListRef.value.refresh()
|
||
// 等待列表加载完成后再查找订单
|
||
setTimeout(() => {
|
||
// 这里需要从 OrderList 组件获取数据,或者直接调用接口获取订单详情
|
||
// 暂时先通过接口获取订单详情
|
||
api.getCheckOrder({ quecurrent: 1, size: 100 }).then(res => {
|
||
if (res.statusCode === 200) {
|
||
const orders = res.data?.records || res.data?.data?.records || res.data?.data || []
|
||
const targetOrder = orders.find(order =>
|
||
String(order.id) === String(orderId) ||
|
||
String(order.orderId) === String(orderId)
|
||
)
|
||
if (targetOrder) {
|
||
handleItemClick(targetOrder)
|
||
}
|
||
}
|
||
})
|
||
}, 500)
|
||
}
|
||
}, 300)
|
||
}
|
||
}
|
||
})
|
||
})
|
||
|
||
// 监听登录与绑定状态,只在首次加载时自动加载
|
||
watch(canViewList, (val) => {
|
||
if (val && isFirstLoad.value && listData.value.length === 0) {
|
||
hasMore.value = true
|
||
page.value = 1
|
||
loadData(true)
|
||
isFirstLoad.value = false
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<script>
|
||
import Taro from '@tarojs/taro'
|
||
|
||
// Taro 页面生命周期
|
||
export default {
|
||
onPullDownRefresh() {
|
||
// 从全局获取刷新函数
|
||
if (typeof globalThis !== 'undefined' && globalThis.__pageRefreshHandler) {
|
||
globalThis.__pageRefreshHandler()
|
||
} else {
|
||
// 如果无法访问,至少停止刷新动画
|
||
setTimeout(() => {
|
||
Taro.stopPullDownRefresh()
|
||
}, 1000)
|
||
}
|
||
},
|
||
onReachBottom() {
|
||
// 触底加载
|
||
if (typeof globalThis !== 'undefined' && globalThis.__pageReachBottomHandler) {
|
||
globalThis.__pageReachBottomHandler()
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="less">
|
||
.back-button {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx 24rpx;
|
||
margin: 24rpx 24rpx 16rpx 24rpx;
|
||
background: #fff;
|
||
border-radius: 12rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.back-button:active {
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.back-text {
|
||
margin-left: 8rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.index-container {
|
||
min-height: 100vh;
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.list-container {
|
||
padding: 24rpx;
|
||
padding-bottom: 148rpx;
|
||
background: linear-gradient(180deg, #f7f9fc 0%, #f5f7fa 100%);
|
||
}
|
||
|
||
/* 搜索框样式 */
|
||
.search-container {
|
||
padding: 0 0rpx 20rpx 0rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.search-box {
|
||
display: flex;
|
||
align-items: center;
|
||
background-color: #fff;
|
||
border-radius: 12rpx;
|
||
padding: 0 24rpx;
|
||
height: 80rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.search-box .nut-icon {
|
||
margin-right: 16rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.search-input {
|
||
flex: 1;
|
||
height: 100%;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.search-clear {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-left: 16rpx;
|
||
flex-shrink: 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.status-filter {
|
||
padding: 0 0rpx;
|
||
}
|
||
|
||
.status-tabs {
|
||
margin-top: 12rpx;
|
||
width: 100%;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.status-tab {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 64rpx;
|
||
padding: 0 28rpx;
|
||
border-radius: 32rpx;
|
||
background: #f3f5f8;
|
||
color: #5f6b7a;
|
||
font-size: 26rpx;
|
||
border: 1rpx solid transparent;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.status-tab.active {
|
||
background: #e6f0ff;
|
||
color: #1755ff;
|
||
border-color: #d6e4ff;
|
||
box-shadow: 0 4rpx 12rpx rgba(23, 85, 255, 0.12);
|
||
}
|
||
|
||
.state-hint {
|
||
min-height: 40vh;
|
||
padding: 60rpx 40rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 24rpx;
|
||
color: #555;
|
||
}
|
||
|
||
.state-title {
|
||
font-size: 30rpx;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.state-btn {
|
||
width: 280rpx;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||
color: #fff;
|
||
border-radius: 8rpx;
|
||
font-size: 30rpx;
|
||
border: none;
|
||
}
|
||
|
||
.state-btn::after {
|
||
border: none;
|
||
}
|
||
|
||
.state-img-wrapper {
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
display: inline-block;
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
|
||
.state-img {
|
||
width: 260rpx;
|
||
height: 200rpx;
|
||
object-fit: contain;
|
||
display: block;
|
||
}
|
||
|
||
.list-item {
|
||
margin-bottom: 24rpx;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
|
||
transition: all 0.2s ease;
|
||
|
||
&:active {
|
||
transform: translateY(1rpx);
|
||
box-shadow: 0 1rpx 4rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
}
|
||
|
||
// 订单头部
|
||
.order-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
padding: 24rpx 24rpx 16rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
}
|
||
|
||
.order-number-section {
|
||
display: flex;
|
||
align-items: center;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.order-number-label {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.order-number-text {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 600;
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.copy-btn {
|
||
margin-left: 16rpx;
|
||
padding: 4rpx 12rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 4rpx;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.copy-text {
|
||
font-size: 22rpx;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.order-status-badge {
|
||
padding: 6rpx 16rpx;
|
||
border-radius: 4rpx;
|
||
font-size: 24rpx;
|
||
font-weight: 500;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
// 订单内容
|
||
.order-content {
|
||
display: flex;
|
||
padding: 20rpx 24rpx;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.order-image-wrapper {
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
border-radius: 12rpx;
|
||
overflow: hidden;
|
||
background: #f5f5f5;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.order-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.order-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
// 车辆信息
|
||
.vehicle-details {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.detail-row {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.detail-label {
|
||
color: #999;
|
||
margin-right: 8rpx;
|
||
width: 120rpx;
|
||
flex-shrink: 0;
|
||
text-align: left;
|
||
}
|
||
|
||
.detail-value {
|
||
color: #333;
|
||
font-weight: 500;
|
||
flex: 1;
|
||
}
|
||
|
||
.phone-row-clickable {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.phone-row-disabled {
|
||
cursor: default;
|
||
}
|
||
|
||
.phone-value {
|
||
color: #1890ff;
|
||
}
|
||
|
||
.phone-value-unknown,
|
||
.phone-row-disabled .phone-value {
|
||
color: #999;
|
||
}
|
||
|
||
.phone-icon {
|
||
margin-left: 8rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
// 时间信息
|
||
.time-details {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
padding-top: 12rpx;
|
||
border-top: 1rpx solid #f5f5f5;
|
||
}
|
||
|
||
.time-detail-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.time-detail-label {
|
||
color: #999;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.time-detail-value {
|
||
color: #666;
|
||
}
|
||
|
||
.item-title {
|
||
font-size: 36rpx;
|
||
font-weight: 800;
|
||
color: #0f172a;
|
||
line-height: 1.45;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.item-desc {
|
||
font-size: 28rpx;
|
||
color: #4a5568;
|
||
line-height: 1.6;
|
||
margin-bottom: 18rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
}
|
||
|
||
.item-order-num {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
padding: 8rpx 0;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.order-num-label {
|
||
font-size: 24rpx;
|
||
color: #5f6b7a;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.order-num-text {
|
||
font-size: 30rpx;
|
||
color: #1f2937;
|
||
font-weight: 600;
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.order-num-copy {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
cursor: pointer;
|
||
border-radius: 4rpx;
|
||
transition: background-color 0.2s;
|
||
padding: 4rpx 8rpx;
|
||
margin-left: 8rpx;
|
||
}
|
||
|
||
.copy-icon {
|
||
font-size: 24rpx;
|
||
color: #1765ad;
|
||
padding: 4rpx 10rpx;
|
||
border: 1rpx solid #d0e2ff;
|
||
border-radius: 6rpx;
|
||
background-color: #eff6ff;
|
||
}
|
||
|
||
.order-num-copy:active {
|
||
background-color: rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.order-num-copy:active .copy-icon {
|
||
background-color: rgba(24, 144, 255, 0.2);
|
||
}
|
||
|
||
.item-order-line {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12rpx;
|
||
margin-bottom: 10rpx;
|
||
padding: 0 12rpx;
|
||
}
|
||
|
||
.item-order-line .item-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.order-actions {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
}
|
||
|
||
.status-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
padding: 0 12rpx;
|
||
}
|
||
|
||
// 状态标签样式
|
||
.status-0 {
|
||
background: #fff7e6;
|
||
color: #d48806;
|
||
}
|
||
|
||
.status-1 {
|
||
background: #e6f7ff;
|
||
color: #096dd9;
|
||
}
|
||
|
||
.status-2 {
|
||
background: #f6ffed;
|
||
color: #389e0d;
|
||
}
|
||
|
||
.status-3 {
|
||
background: #fff7e6;
|
||
color: #d46b08;
|
||
}
|
||
|
||
.status-unknown {
|
||
background: #f5f5f5;
|
||
color: #999;
|
||
}
|
||
|
||
.time-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 16rpx;
|
||
margin-top: 4rpx;
|
||
padding: 0 12rpx;
|
||
}
|
||
|
||
.time-item {
|
||
flex: 1;
|
||
padding: 12rpx 14rpx;
|
||
background: #f7f9fc;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.time-label {
|
||
display: block;
|
||
font-size: 22rpx;
|
||
color: #6b7280;
|
||
margin-bottom: 6rpx;
|
||
}
|
||
|
||
.time-text {
|
||
font-size: 26rpx;
|
||
color: #1f2937;
|
||
font-weight: 600;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.vehicle-info {
|
||
margin: 10rpx 0 8rpx;
|
||
padding: 12rpx 18rpx;
|
||
background: #fcfdff;
|
||
border-radius: 14rpx;
|
||
color: #1f2a44;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12rpx 20rpx;
|
||
}
|
||
|
||
.vehicle-left {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 12rpx 20rpx;
|
||
}
|
||
|
||
.vehicle-right {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.vehicle-field {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
}
|
||
|
||
.vehicle-label {
|
||
padding: 4rpx 10rpx;
|
||
border-radius: 10rpx;
|
||
background: rgba(31, 42, 68, 0.08);
|
||
font-size: 22rpx;
|
||
color: #1f2a44;
|
||
}
|
||
|
||
.vehicle-value {
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
color: #0f172a;
|
||
}
|
||
|
||
.vehicle-phone {
|
||
background: rgba(23, 85, 255, 0.12);
|
||
padding: 8rpx 14rpx;
|
||
border-radius: 14rpx;
|
||
cursor: pointer;
|
||
border: 1rpx solid rgba(23, 85, 255, 0.18);
|
||
}
|
||
|
||
.phone-emoji {
|
||
font-size: 30rpx;
|
||
line-height: 1;
|
||
color: #1755ff;
|
||
}
|
||
|
||
.item-actions {
|
||
margin-left: 16rpx;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
// 操作按钮区域(恢复旧版“去质检”样式)
|
||
.item-footer {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12rpx;
|
||
padding: 20rpx 24rpx;
|
||
background: #fafbfc;
|
||
border-top: 1rpx solid #eef0f3;
|
||
}
|
||
|
||
.footer-divider {
|
||
height: 1rpx;
|
||
background: linear-gradient(90deg, transparent 0%, #e6e9ef 20%, #e6e9ef 80%, transparent 100%);
|
||
}
|
||
|
||
/* footer-actions 由布局继承,无需额外样式,这里移除空规则避免告警 */
|
||
|
||
.check-btn {
|
||
min-width: 140rpx;
|
||
height: 64rpx;
|
||
line-height: 64rpx;
|
||
padding: 0 24rpx;
|
||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||
color: #fff;
|
||
border-radius: 12rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
border: none;
|
||
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.3);
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.check-btn::after {
|
||
border: none;
|
||
}
|
||
|
||
.check-btn:active {
|
||
transform: translateY(1rpx);
|
||
box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.25);
|
||
}
|
||
|
||
.item-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.meta-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.meta-text {
|
||
font-size: 24rpx;
|
||
color: #6b7280;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.item-arrow {
|
||
margin-left: 16rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
// 旧的 footer 样式已移除,使用新的 order-actions
|
||
|
||
.loading-more,
|
||
.no-more {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 40rpx 0;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.loading-text,
|
||
.no-more-text {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.no-more-text {
|
||
color: #ccc;
|
||
}
|
||
|
||
/* 图片预览弹窗样式 */
|
||
.image-popup {
|
||
width: 600rpx;
|
||
max-width: 90vw;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.image-popup-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 24rpx 30rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
}
|
||
|
||
.image-popup-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.image-popup-close {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.image-swiper {
|
||
width: 100%;
|
||
height: 500rpx;
|
||
}
|
||
|
||
.preview-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
/* 表单弹窗样式 */
|
||
.form-popup {
|
||
background-color: #fff;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
max-height: 80vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.form-scroll {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.form-popup-header {
|
||
padding: 30rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
text-align: center;
|
||
}
|
||
|
||
.form-popup-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.custom-form {
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.form-item {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.form-label {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 12rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.form-label-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 12rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.required {
|
||
color: #ff4d4f;
|
||
margin-left: 4rpx;
|
||
}
|
||
|
||
.required-star {
|
||
color: #ff4d4f;
|
||
margin-right: 4rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
padding: 0 24rpx;
|
||
background-color: #f5f5f5;
|
||
border-radius: 8rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.form-picker-wrapper {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
padding: 0 24rpx;
|
||
background-color: #f5f5f5;
|
||
border-radius: 8rpx;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
position: relative;
|
||
}
|
||
|
||
.form-picker-input {
|
||
flex: 1;
|
||
height: 100%;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
background-color: transparent;
|
||
border: none;
|
||
padding: 0;
|
||
}
|
||
|
||
.form-picker-icon {
|
||
flex-shrink: 0;
|
||
margin-left: 12rpx;
|
||
}
|
||
|
||
.form-picker-wrapper.disabled {
|
||
color: #999;
|
||
background-color: #f0f0f0;
|
||
}
|
||
|
||
.form-picker-wrapper.disabled .form-picker-input {
|
||
color: #999;
|
||
}
|
||
|
||
.form-select-wrapper {
|
||
width: 100%;
|
||
position: relative;
|
||
}
|
||
|
||
.form-select-display {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
padding: 0 24rpx;
|
||
background-color: #f5f5f5;
|
||
border-radius: 8rpx;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.form-select-text {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.form-select-wrapper.disabled .form-select-display {
|
||
color: #999;
|
||
background-color: #f0f0f0;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.form-select-wrapper.disabled .form-select-text {
|
||
color: #999;
|
||
}
|
||
|
||
.form-select-options {
|
||
position: absolute;
|
||
top: 88rpx;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #fff;
|
||
border-radius: 8rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||
max-height: 400rpx;
|
||
overflow-y: auto;
|
||
z-index: 1000;
|
||
border: 1rpx solid #e8e8e8;
|
||
}
|
||
|
||
.form-select-option {
|
||
padding: 24rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.form-select-option:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.form-select-option:active {
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.form-select-option.active {
|
||
color: #1890ff;
|
||
background-color: #e6f7ff;
|
||
}
|
||
|
||
.form-textarea {
|
||
width: 100%;
|
||
min-height: 160rpx;
|
||
padding: 20rpx 24rpx;
|
||
background-color: #f5f5f5;
|
||
border-radius: 8rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
box-sizing: border-box;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.uploader-container {
|
||
width: 100%;
|
||
}
|
||
|
||
.form-actions-placeholder {
|
||
height: 120rpx;
|
||
}
|
||
|
||
.form-actions-fixed {
|
||
padding: 20rpx 30rpx;
|
||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||
background-color: #fff;
|
||
border-top: 1rpx solid #f0f0f0;
|
||
display: flex;
|
||
gap: 20rpx;
|
||
box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.form-btn {
|
||
flex: 1;
|
||
height: 88rpx;
|
||
line-height: 88rpx;
|
||
border-radius: 8rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
border: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.form-btn-cancel {
|
||
background-color: #f5f5f5;
|
||
color: #333;
|
||
}
|
||
|
||
.form-btn-cancel::after {
|
||
border: none;
|
||
}
|
||
|
||
.form-btn-submit {
|
||
background-color: #1890ff;
|
||
color: #fff;
|
||
}
|
||
|
||
.form-btn-submit::after {
|
||
border: none;
|
||
}
|
||
|
||
.form-btn:active {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
/* 登录弹窗样式 */
|
||
.login-popup {
|
||
width: 560rpx;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.login-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 30rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
}
|
||
|
||
.login-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.login-close {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.login-content {
|
||
padding: 40rpx 30rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.login-desc {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-bottom: 40rpx;
|
||
display: block;
|
||
}
|
||
|
||
.login-btn {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
line-height: 88rpx;
|
||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||
color: #fff;
|
||
border-radius: 8rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
border: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.login-btn::after {
|
||
border: none;
|
||
}
|
||
|
||
.login-btn:active {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
/* 绑定弹窗样式 */
|
||
.bind-popup {
|
||
width: 640rpx;
|
||
background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%);
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.bind-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 40rpx 40rpx 30rpx;
|
||
background: linear-gradient(135deg, #e6f7ff 0%, #f0f9ff 100%);
|
||
border-bottom: 1rpx solid rgba(24, 144, 255, 0.1);
|
||
}
|
||
|
||
.bind-title-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.bind-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #1890ff;
|
||
letter-spacing: 0.5rpx;
|
||
}
|
||
|
||
.bind-close {
|
||
width: 56rpx;
|
||
height: 56rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
border-radius: 50%;
|
||
background-color: rgba(0, 0, 0, 0.04);
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.bind-close:active {
|
||
background-color: rgba(0, 0, 0, 0.08);
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.bind-content {
|
||
padding: 50rpx 40rpx 40rpx;
|
||
}
|
||
|
||
.bind-desc {
|
||
font-size: 26rpx;
|
||
color: #8c8c8c;
|
||
margin-bottom: 50rpx;
|
||
display: block;
|
||
text-align: center;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.bind-form {
|
||
margin-bottom: 50rpx;
|
||
}
|
||
|
||
.bind-form-item {
|
||
margin-bottom: 36rpx;
|
||
}
|
||
|
||
.form-item-label {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
margin-bottom: 16rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.input-wrapper {
|
||
position: relative;
|
||
background-color: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
border: 2rpx solid #e8e8e8;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.input-wrapper:focus-within {
|
||
border-color: #1890ff;
|
||
background-color: #fff;
|
||
box-shadow: 0 0 0 4rpx rgba(24, 144, 255, 0.1);
|
||
}
|
||
|
||
.bind-code-item {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.code-input-wrapper {
|
||
flex: 1;
|
||
}
|
||
|
||
.bind-input {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
padding: 0 28rpx;
|
||
background-color: transparent;
|
||
border: none;
|
||
border-radius: 12rpx;
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.bind-input::placeholder {
|
||
color: #bfbfbf;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.bind-code-input {
|
||
flex: 1;
|
||
}
|
||
|
||
.bind-code-btn {
|
||
width: 200rpx;
|
||
height: 96rpx;
|
||
line-height: 96rpx;
|
||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||
color: #fff;
|
||
border-radius: 12rpx;
|
||
font-size: 26rpx;
|
||
font-weight: 500;
|
||
border: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
flex-shrink: 0;
|
||
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.3);
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.bind-code-btn::after {
|
||
border: none;
|
||
}
|
||
|
||
.bind-code-btn:disabled {
|
||
background: #d9d9d9;
|
||
color: #fff;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.bind-code-btn:active:not(:disabled) {
|
||
transform: translateY(2rpx);
|
||
box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.3);
|
||
}
|
||
|
||
.bind-actions {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.bind-btn {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
line-height: 96rpx;
|
||
border-radius: 48rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
border: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
transition: all 0.3s;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
|
||
.bind-btn-submit {
|
||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||
color: #fff;
|
||
box-shadow: 0 8rpx 20rpx rgba(24, 144, 255, 0.4);
|
||
order: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.bind-btn-submit::after {
|
||
border: none;
|
||
}
|
||
|
||
.bind-btn-submit:disabled {
|
||
opacity: 0.6;
|
||
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.2);
|
||
}
|
||
|
||
.bind-btn-submit:active:not(:disabled) {
|
||
transform: translateY(2rpx);
|
||
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.4);
|
||
}
|
||
|
||
.bind-btn-cancel {
|
||
background-color: #f5f5f5;
|
||
color: #8c8c8c;
|
||
order: 2;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.bind-btn-cancel::after {
|
||
border: none;
|
||
}
|
||
|
||
.bind-btn-cancel:disabled {
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.bind-btn-cancel:active:not(:disabled) {
|
||
background-color: #e8e8e8;
|
||
transform: scale(0.98);
|
||
}
|
||
</style>
|