|
|
<template>
|
|
|
<view class="page-container">
|
|
|
<!-- 顶部导航栏 -->
|
|
|
<view class="custom-nav">
|
|
|
<view class="nav-back" @click="goBack">
|
|
|
<text class="back-icon"><</text>
|
|
|
</view>
|
|
|
<text class="nav-title">{{ t('moldOperate.tabUp') }}</text>
|
|
|
<view class="nav-placeholder"></view>
|
|
|
</view>
|
|
|
|
|
|
<!-- ========== 上模 ========== -->
|
|
|
<!-- 操作按钮区 -->
|
|
|
<view class="action-row">
|
|
|
<view class="action-btn scan-btn" @click="handleScan">
|
|
|
<view class="btn-icon-wrap">
|
|
|
<text class="iconfont icon-scan btn-icon"></text>
|
|
|
</view>
|
|
|
<text class="btn-text">{{ t('moldOperate.scanDevice') }}</text>
|
|
|
</view>
|
|
|
<view class="action-btn select-btn" @click="openDevicePicker">
|
|
|
<view class="btn-icon-wrap">
|
|
|
<text class="iconfont icon-device btn-icon"></text>
|
|
|
</view>
|
|
|
<text class="btn-text">{{ t('moldOperate.selectDevice') }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 已选设备卡片 -->
|
|
|
<view class="section-card">
|
|
|
<view class="section-title-bar">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">{{ t('moldOperate.selectedDevice') }}</text>
|
|
|
</view>
|
|
|
<view class="card-body-grid">
|
|
|
<view class="grid-row">
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.deviceName') }}</text>
|
|
|
<text class="grid-value">{{ textValue(selectedDevice.deviceName) }}</text>
|
|
|
</view>
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.deviceCode') }}</text>
|
|
|
<text class="grid-value">{{ textValue(selectedDevice.deviceCode) }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="grid-row">
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.productionLine') }}</text>
|
|
|
<text class="grid-value">{{ textValue(selectedDevice.workshopName) }}</text>
|
|
|
</view>
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.currentMold') }}</text>
|
|
|
<text class="grid-value highlight">{{ currentMoldDisplay }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="grid-row">
|
|
|
<view class="grid-cell full-width">
|
|
|
<text class="grid-label">{{ t('moldOperate.deviceStatus') }}</text>
|
|
|
<view class="status-tag" :class="deviceStatusClass">{{ deviceStatusLabel }}</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 选择待上模模具 -->
|
|
|
<view class="section-card">
|
|
|
<view class="section-title-bar">
|
|
|
<view class="section-bar-line"></view>
|
|
|
<text class="section-title">{{ t('moldOperate.selectMountMold') }}</text>
|
|
|
</view>
|
|
|
|
|
|
<template v-if="selectedMountMolds.length > 0">
|
|
|
<view v-for="(mold, index) in selectedMountMolds" :key="mold.id || index" class="card-body-grid">
|
|
|
<view class="grid-row">
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.moldName') }}</text>
|
|
|
<text class="grid-value highlight">{{ textValue(mold.name || mold.moldName) }}</text>
|
|
|
</view>
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.moldCode') }}</text>
|
|
|
<text class="grid-value">{{ textValue(mold.code || mold.moldCode) }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="grid-row">
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.product') }}</text>
|
|
|
<text class="grid-value">{{ textValue(mold.productName) }}</text>
|
|
|
</view>
|
|
|
<view class="grid-cell">
|
|
|
<text class="grid-label">{{ t('moldOperate.status') }}</text>
|
|
|
<view :class="['status-tag', getMoldStatusClass(mold.status)]">{{ getMoldStatusText(mold.status) }}</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 更换上模对象按钮 -->
|
|
|
<view class="change-target-btn" @click="openMountMoldPicker">
|
|
|
<text class="change-icon">⇄</text>
|
|
|
<text class="change-text">{{ t('moldOperate.changeMountTarget') }}</text>
|
|
|
</view>
|
|
|
</template>
|
|
|
<view v-else class="empty-mold-hint" @click="openMountMoldPicker">
|
|
|
<text class="empty-mold-text">+ {{ t('moldOperate.clickSelectMold') }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 底部操作栏 - 上模 -->
|
|
|
<view class="bottom-actions">
|
|
|
<view class="bottom-btn confirm-btn" @click="handleConfirmMount">{{ t('moldOperate.confirmMount') }}</view>
|
|
|
<view class="bottom-btn cancel-btn" @click="handleCancel">{{ t('functionCommon.cancel') }}</view>
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { computed, ref } from 'vue'
|
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
import { getDeviceLedgerList, createMoldOperate } from '@/api/mes/moldoperate'
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
|
// ---- 工具函数 ----
|
|
|
function textValue(v) {
|
|
|
if (v === 0) return '0'
|
|
|
if (v == null) return '-'
|
|
|
const s = String(v).trim()
|
|
|
return s || '-'
|
|
|
}
|
|
|
|
|
|
// ==================== 共享: 设备列表 ====================
|
|
|
const deviceOptions = ref([])
|
|
|
|
|
|
async function loadDevices() {
|
|
|
try {
|
|
|
const res = await getDeviceLedgerList({ pageNo: 1, pageSize: 100 })
|
|
|
const root = res && res.data !== undefined ? res.data : res
|
|
|
const data = Array.isArray(root)
|
|
|
? root
|
|
|
: Array.isArray(root?.list) ? root.list
|
|
|
: Array.isArray(root?.rows) ? root.rows
|
|
|
: Array.isArray(root?.records) ? root.records
|
|
|
: []
|
|
|
deviceOptions.value = data.map((d) => ({
|
|
|
value: d.id,
|
|
|
label: `${d.deviceCode || ''} ${d.deviceName || ''}`.trim(),
|
|
|
raw: d
|
|
|
}))
|
|
|
} catch (e) {
|
|
|
console.error('loadDevices error', e)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ==================== 上模模块 ====================
|
|
|
const selectedDevice = ref({})
|
|
|
|
|
|
const selectedMountMolds = ref([])
|
|
|
const tempSelectedDeviceId = ref(null)
|
|
|
|
|
|
// 设备状态 - 上模
|
|
|
const deviceStatusClass = computed(() => {
|
|
|
const status = Number(selectedDevice.value?.deviceStatus)
|
|
|
if (status === 0) return 'running-tag'
|
|
|
if (status === 1) return 'stop-tag'
|
|
|
if (status >= 2) return 'fault-tag'
|
|
|
return ''
|
|
|
})
|
|
|
|
|
|
const deviceStatusLabel = computed(() => {
|
|
|
const status = Number(selectedDevice.value?.deviceStatus)
|
|
|
const map = {
|
|
|
0: t('moldOperate.statusRunning'),
|
|
|
1: t('moldOperate.statusStop'),
|
|
|
2: t('moldOperate.statusFault'),
|
|
|
3: t('moldOperate.statusFault')
|
|
|
}
|
|
|
return map[status] || textValue(selectedDevice.value?.deviceStatus) || '-'
|
|
|
})
|
|
|
|
|
|
const MOLD_STATUS_MAP = { 0: '在机', 1: '待用', 2: '维修', 3: '报废' }
|
|
|
function getMoldStatusText(s) { return MOLD_STATUS_MAP[s] || textValue(s) }
|
|
|
function getMoldStatusClass(s) {
|
|
|
if (s === 0) return 'inuse-tag'
|
|
|
if (s === 2) return 'repair-tag'
|
|
|
if (s === 3) return 'scrap-tag'
|
|
|
return 'standby-tag'
|
|
|
}
|
|
|
|
|
|
// ---- 持久化在机模具信息(按设备ID索引,避免多设备覆盖)----
|
|
|
const MOUNTED_MOLD_KEY = '_mountedMoldInfoMap'
|
|
|
function getMountedMoldMap() {
|
|
|
try {
|
|
|
const data = uni.getStorageSync(MOUNTED_MOLD_KEY) || {}
|
|
|
return data
|
|
|
} catch (e) {
|
|
|
console.warn('[上模] getMountedMoldMap 异常', e)
|
|
|
return {}
|
|
|
}
|
|
|
}
|
|
|
function getMountedMoldByDevice(deviceId) {
|
|
|
if (!deviceId) return null
|
|
|
const map = getMountedMoldMap()
|
|
|
const key = String(deviceId)
|
|
|
return map[key] || null
|
|
|
}
|
|
|
function saveMountedMoldInfo(info) {
|
|
|
if (!info || !info.deviceId) return
|
|
|
try {
|
|
|
const map = getMountedMoldMap()
|
|
|
map[String(info.deviceId)] = info
|
|
|
uni.setStorageSync(MOUNTED_MOLD_KEY, map)
|
|
|
console.log('[上模] saveMountedMoldInfo 写入成功, deviceId=', info.deviceId, 'map keys=', Object.keys(map))
|
|
|
} catch (e) {
|
|
|
console.warn('[上模] saveMountedMoldInfo 异常', e)
|
|
|
}
|
|
|
}
|
|
|
function clearMountedMoldInfo(deviceId) {
|
|
|
if (!deviceId) {
|
|
|
try { uni.removeStorageSync(MOUNTED_MOLD_KEY) } catch {}
|
|
|
return
|
|
|
}
|
|
|
try {
|
|
|
const map = getMountedMoldMap()
|
|
|
delete map[String(deviceId)]
|
|
|
uni.setStorageSync(MOUNTED_MOLD_KEY, map)
|
|
|
} catch {}
|
|
|
}
|
|
|
|
|
|
// 当前在机模具 - 优先从持久化存储获取(实时),否则用设备台账静态字段
|
|
|
const currentMoldDisplay = computed(() => {
|
|
|
if (!selectedDevice.value?.id) return '-'
|
|
|
const saved = getMountedMoldByDevice(selectedDevice.value.id)
|
|
|
if (saved) {
|
|
|
console.log('[上模] currentMoldDisplay 命中持久化, deviceId=', selectedDevice.value.id, 'mold=', saved.mold?.name || saved.mold?.moldName)
|
|
|
return saved.mold?.name || saved.mold?.moldName || '-'
|
|
|
}
|
|
|
return textValue(selectedDevice.value.currentMold)
|
|
|
})
|
|
|
|
|
|
function selectDevice(device) {
|
|
|
selectedDevice.value = device || {}
|
|
|
tempSelectedDeviceId.value = device ? device.id : null
|
|
|
selectedMountMolds.value = []
|
|
|
}
|
|
|
|
|
|
function openDevicePicker() {
|
|
|
uni.navigateTo({ url: '/pages_function/pages/moldoperate/deviceSelect' })
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openMountMoldPicker() {
|
|
|
if (!selectedDevice.value?.id) {
|
|
|
uni.showToast({ title: t('moldOperate.validatorDeviceRequired'), icon: 'none' })
|
|
|
return
|
|
|
}
|
|
|
// 把已选模具 ID 传过去做回显
|
|
|
getApp().globalData._moldSelectPreSelected = selectedMountMolds.value.map((m) => String(m.id))
|
|
|
uni.navigateTo({ url: '/pages_function/pages/moldoperate/moldSelect' })
|
|
|
}
|
|
|
|
|
|
function validFormMount() {
|
|
|
if (!selectedDevice.value?.id) {
|
|
|
uni.showToast({ title: t('moldOperate.validatorDeviceRequired'), icon: 'none' })
|
|
|
return false
|
|
|
}
|
|
|
if (!selectedMountMolds.value.length) {
|
|
|
uni.showToast({ title: t('moldOperate.validatorMoldRequired'), icon: 'none' })
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
async function handleConfirmMount() {
|
|
|
if (!validFormMount()) return
|
|
|
try {
|
|
|
const moldIds = selectedMountMolds.value.map((m) => m.id)
|
|
|
const payload = {
|
|
|
operateType: '1',
|
|
|
deviceId: String(selectedDevice.value.id),
|
|
|
moldId: moldIds.length === 1 ? String(moldIds[0]) : moldIds.map(String).join(',')
|
|
|
}
|
|
|
console.log('=== 上模提交参数 ===', JSON.stringify(payload))
|
|
|
console.log('=== deviceId type:', typeof payload.deviceId, 'value:', payload.deviceId)
|
|
|
console.log('=== moldId type:', typeof payload.moldId, 'value:', payload.moldId)
|
|
|
const res = await createMoldOperate(payload)
|
|
|
console.log('=== 上模返回 ===', JSON.stringify(res))
|
|
|
uni.showToast({ title: t('functionCommon.createSuccess'), icon: 'success' })
|
|
|
|
|
|
// 上模成功后持久化保存,供下模/设备选择页读取
|
|
|
if (selectedMountMolds.value.length > 0) {
|
|
|
const info = {
|
|
|
deviceId: selectedDevice.value.id,
|
|
|
deviceCode: selectedDevice.value.deviceCode,
|
|
|
deviceName: selectedDevice.value.deviceName,
|
|
|
mold: selectedMountMolds.value[0],
|
|
|
mountTime: new Date().toLocaleString()
|
|
|
}
|
|
|
saveMountedMoldInfo(info)
|
|
|
// 同步到 globalData(兼容旧逻辑)
|
|
|
getApp().globalData._mountedMoldInfo = info
|
|
|
getApp().globalData._mountedMoldInfoMap = getMountedMoldMap()
|
|
|
console.log('=== 已保存在机模具信息 ===', JSON.stringify(info))
|
|
|
}
|
|
|
|
|
|
selectedDevice.value = {}
|
|
|
selectedMountMolds.value = []
|
|
|
} catch (e) {
|
|
|
console.error('=== 上模失败 ===', e)
|
|
|
const errMsg = e?.msg || (typeof e === 'string' ? e : e?.message) || '系统异常'
|
|
|
console.error('=== 错误详情 ===', errMsg)
|
|
|
uni.showToast({ title: t('functionCommon.saveFailed') + ': ' + errMsg, icon: 'none', duration: 3000 })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ==================== 共享: 扫码 / 取消 / 返回 ====================
|
|
|
function handleScan() {
|
|
|
uni.scanCode({
|
|
|
onlyFromCamera: false,
|
|
|
scanType: ['qrCode', 'barCode'],
|
|
|
success(res) {
|
|
|
const code = res.result?.trim()
|
|
|
if (!code) return
|
|
|
const matched = deviceOptions.value.find((d) =>
|
|
|
d.raw.deviceCode === code || String(d.raw.code) === code || d.label.includes(code)
|
|
|
)
|
|
|
if (matched) {
|
|
|
selectDevice(matched.raw)
|
|
|
} else {
|
|
|
uni.showToast({ title: t('moldOperate.deviceNotFound'), icon: 'none' })
|
|
|
}
|
|
|
},
|
|
|
fail(err) {
|
|
|
if (err.errMsg && !err.errMsg.includes('cancel')) {
|
|
|
console.warn('scan failed:', err)
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
|
|
|
function handleCancel() {
|
|
|
selectedDevice.value = {}
|
|
|
selectedMountMolds.value = []
|
|
|
}
|
|
|
|
|
|
function goBack() {
|
|
|
uni.navigateBack({ fail: () => uni.switchTab({ url: '/pages/index/index' }) })
|
|
|
}
|
|
|
|
|
|
onShow(async () => {
|
|
|
await Promise.allSettled([loadDevices()])
|
|
|
// 从 globalData 读取设备选择页回传的设备
|
|
|
const device = getApp().globalData._deviceSelectResult
|
|
|
if (device) {
|
|
|
getApp().globalData._deviceSelectResult = null
|
|
|
selectDevice(device)
|
|
|
}
|
|
|
// 从 globalData 读取模具选择页回传的模具列表
|
|
|
const molds = getApp().globalData._moldSelectResult
|
|
|
if (molds) {
|
|
|
getApp().globalData._moldSelectResult = null
|
|
|
selectedMountMolds.value = molds
|
|
|
}
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.page-container {
|
|
|
min-height: 100vh;
|
|
|
background: #f5f6f8;
|
|
|
padding-bottom: 140rpx;
|
|
|
}
|
|
|
|
|
|
/* ====== 自定义导航栏 ====== */
|
|
|
.custom-nav {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
height: 88rpx;
|
|
|
padding: 0 24rpx;
|
|
|
background: #1a365d;
|
|
|
color: #fff;
|
|
|
|
|
|
.nav-back {
|
|
|
width: 60rpx;
|
|
|
height: 60rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
.back-icon {
|
|
|
font-size: 36rpx;
|
|
|
font-weight: bold;
|
|
|
}
|
|
|
|
|
|
.nav-title {
|
|
|
font-size: 34rpx;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
.nav-placeholder {
|
|
|
width: 60rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* ====== 操作按钮区 ====== */
|
|
|
.action-row {
|
|
|
display: flex;
|
|
|
gap: 20rpx;
|
|
|
padding: 20rpx 24rpx;
|
|
|
}
|
|
|
|
|
|
.action-btn {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
gap: 12rpx;
|
|
|
height: 96rpx;
|
|
|
border-radius: 12rpx;
|
|
|
background: #2563eb;
|
|
|
color: #fff;
|
|
|
font-size: 28rpx;
|
|
|
font-weight: 600;
|
|
|
|
|
|
.btn-icon-wrap {
|
|
|
width: 44rpx;
|
|
|
height: 44rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
.btn-icon {
|
|
|
font-size: 36rpx;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.btn-text {
|
|
|
font-size: 28rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* ====== 卡片通用样式 ====== */
|
|
|
.section-card {
|
|
|
margin: 16rpx 24rpx;
|
|
|
background: #ffffff;
|
|
|
border-radius: 14rpx;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.section-title-bar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 10rpx;
|
|
|
padding: 22rpx 24rpx 0;
|
|
|
}
|
|
|
|
|
|
.section-bar-line {
|
|
|
width: 6rpx;
|
|
|
height: 32rpx;
|
|
|
border-radius: 3rpx;
|
|
|
background: #2563eb;
|
|
|
}
|
|
|
|
|
|
.section-title {
|
|
|
font-size: 30rpx;
|
|
|
font-weight: 700;
|
|
|
color: #1a1a1a;
|
|
|
}
|
|
|
|
|
|
.card-body-grid {
|
|
|
padding: 20rpx 24rpx 28rpx;
|
|
|
}
|
|
|
|
|
|
/* ====== 网格布局 ====== */
|
|
|
.grid-row {
|
|
|
display: flex;
|
|
|
gap: 20rpx;
|
|
|
margin-top: 18rpx;
|
|
|
|
|
|
&:first-child {
|
|
|
margin-top: 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.grid-cell {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
|
|
|
&.full-width {
|
|
|
flex-basis: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 12rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.grid-label {
|
|
|
display: block;
|
|
|
font-size: 24rpx;
|
|
|
color: #999;
|
|
|
margin-bottom: 6rpx;
|
|
|
}
|
|
|
|
|
|
.grid-value {
|
|
|
display: block;
|
|
|
font-size: 27rpx;
|
|
|
color: #333;
|
|
|
word-break: break-all;
|
|
|
|
|
|
&.highlight {
|
|
|
color: #2563eb;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* ====== 状态标签 ====== */
|
|
|
.status-tag {
|
|
|
display: inline-flex;
|
|
|
align-items: center;
|
|
|
padding: 6rpx 18rpx;
|
|
|
border-radius: 6rpx;
|
|
|
font-size: 24rpx;
|
|
|
font-weight: 500;
|
|
|
|
|
|
&.running-tag {
|
|
|
color: #059669; background: #ecfdf5; border: 1rpx solid #a7f3d0;
|
|
|
}
|
|
|
&.stop-tag {
|
|
|
color: #d97706; background: #fffbeb; border: 1rpx solid #fde68a;
|
|
|
}
|
|
|
&.fault-tag {
|
|
|
color: #dc2626; background: #fef2f2; border: 1rpx solid #fecaca;
|
|
|
}
|
|
|
// 模具状态
|
|
|
&.inuse-tag {
|
|
|
color: #059669; background: #ecfdf5; border: 1rpx solid #a7f3d0;
|
|
|
}
|
|
|
&.standby-tag {
|
|
|
color: #2563eb; background: #eff6ff; border: 1rpx solid #bfdbfe;
|
|
|
}
|
|
|
&.repair-tag {
|
|
|
color: #d97706; background: #fffbeb; border: 1rpx solid #fde68a;
|
|
|
}
|
|
|
&.scrap-tag {
|
|
|
color: #dc2626; background: #fef2f2; border: 1rpx solid #fecaca;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* ====== 更换下模对象按钮 ====== */
|
|
|
.change-target-btn {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
gap: 8rpx;
|
|
|
margin: 0 24rpx 24rpx;
|
|
|
padding: 20rpx 0;
|
|
|
border: 1rpx dashed #ccc;
|
|
|
border-radius: 10rpx;
|
|
|
|
|
|
&:active { background: #fafafa; }
|
|
|
|
|
|
.change-icon { font-size: 28rpx; color: #666; }
|
|
|
.change-text { font-size: 26rpx; color: #666; }
|
|
|
}
|
|
|
|
|
|
/* ====== 空提示 ====== */
|
|
|
.empty-mold-hint {
|
|
|
padding: 40rpx 24rpx;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.empty-mold-text {
|
|
|
font-size: 28rpx;
|
|
|
color: #2563eb;
|
|
|
|
|
|
&.loading-text {
|
|
|
color: #999;
|
|
|
}
|
|
|
|
|
|
&.empty-gray {
|
|
|
color: #bbb;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* ====== 底部操作栏 ====== */
|
|
|
.bottom-actions {
|
|
|
position: fixed;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
display: flex;
|
|
|
gap: 20rpx;
|
|
|
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
|
|
background: #fff;
|
|
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
|
|
|
z-index: 99;
|
|
|
|
|
|
&.single-btn {
|
|
|
gap: 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.bottom-btn {
|
|
|
height: 88rpx;
|
|
|
line-height: 88rpx;
|
|
|
text-align: center;
|
|
|
border-radius: 12rpx;
|
|
|
font-size: 30rpx;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
.confirm-btn {
|
|
|
flex: 1;
|
|
|
background: #2563eb;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.cancel-btn {
|
|
|
flex: 1;
|
|
|
background: #fff;
|
|
|
color: #666;
|
|
|
border: 1rpx solid #ddd;
|
|
|
}
|
|
|
|
|
|
|
|
|
</style>
|