feat:上下模、备件出入库-输入框优化

master
zhongwenkai 6 days ago
parent c251b49322
commit 6012a3d94a

@ -13,11 +13,11 @@
<view class="action-row">
<view class="scan-input-row">
<input
id="mold-dismount-scan-input"
class="scan-input"
v-model="scanCodeInput"
placeholder="红外扫码或输入设备码"
confirm-type="done"
:focus="true"
@confirm="onScanInputConfirm"
/>
</view>
@ -159,12 +159,14 @@
</scroll-view>
</view>
</uni-popup>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
</template>
<script setup>
import { computed, reactive, ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { computed, reactive, ref, nextTick } from 'vue'
import { onReady, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getDeviceLedgerList, createMoldOperate } from '@/api/mes/moldoperate'
@ -256,6 +258,18 @@ const remarkText = ref('')
const selectedOperator = ref(null)
const scanCodeInput = ref('')
//
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#mold-dismount-scan-input input, input#mold-dismount-scan-input'
function focusKeywordNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 80)
})
}
// ---- ----
function textValue(v) {
if (v === 0) return '0'
@ -547,6 +561,10 @@ function handleCancel() {
})
}
onReady(() => {
focusKeywordNoKeyboard()
})
onShow(async () => {
autoSetOperator()
await Promise.allSettled([loadDevices(), loadLineTree()])

@ -14,11 +14,11 @@
<view class="action-row">
<view class="scan-input-row">
<input
id="mold-scan-input"
class="scan-input"
v-model="scanCodeInput"
placeholder="红外扫码或输入设备码"
confirm-type="done"
:focus="true"
@confirm="onScanInputConfirm"
/>
</view>
@ -140,12 +140,13 @@
<view class="bottom-btn confirm-btn" @click="handleConfirmMount">{{ t('moldOperate.confirmMount') }}</view>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
</template>
<script setup>
import { computed, ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { computed, ref, nextTick } from 'vue'
import { onReady, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getDeviceLedgerList, createMoldOperate } from '@/api/mes/moldoperate'
@ -264,6 +265,18 @@ const remarkText = ref('')
const selectedOperator = ref(null)
const scanCodeInput = ref('') // /
//
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#mold-scan-input input, input#mold-scan-input'
function focusKeywordNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 80)
})
}
// -
const deviceStatusClass = computed(() => {
const status = Number(selectedDevice.value?.deviceStatus)
@ -482,6 +495,10 @@ function goToHistory() {
uni.navigateTo({ url: '/pages_function/pages/moldoperate/history?type=up' })
}
onReady(() => {
focusKeywordNoKeyboard()
})
onShow(async () => {
autoSetOperator()
await Promise.allSettled([loadDevices(), loadLineTree()])

@ -6,11 +6,11 @@
<view class="action-row">
<view class="scan-input-row">
<input
id="sparepart-inbound-scan-input"
class="scan-input"
v-model="scanCodeInput"
placeholder="红外扫码或输入备件码"
confirm-type="done"
:focus="true"
@confirm="onScanInputConfirm"
/>
</view>
@ -146,12 +146,14 @@
<view class="bottom-btn cancel-btn" @click="handleCancel"></view>
<view class="bottom-btn confirm-btn" @click="handleSubmit"></view>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onShow, onHide } from '@dcloudio/uni-app'
import { ref, nextTick } from 'vue'
import { onReady, onShow, onHide } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { createSparepartInbound } from '@/api/mes/sparepartInbound'
@ -163,6 +165,18 @@ const { t } = useI18n()
const itemList = ref([])
const scanCodeInput = ref('') // /
//
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#sparepart-inbound-scan-input input, input#sparepart-inbound-scan-input'
function focusKeywordNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 80)
})
}
//
function onScanInputConfirm() {
const code = scanCodeInput.value.trim()
@ -409,6 +423,10 @@ async function handleSubmit() {
}
}
onReady(() => {
focusKeywordNoKeyboard()
})
onShow(() => {
const items = getApp().globalData?._sparepartInboundItems
if (Array.isArray(items)) {

@ -6,11 +6,11 @@
<view class="action-row">
<view class="scan-input-row">
<input
id="sparepart-outbound-scan-input"
class="scan-input"
v-model="scanCodeInput"
placeholder="红外扫码或输入备件码"
confirm-type="done"
:focus="true"
@confirm="onScanInputConfirm"
/>
</view>
@ -118,12 +118,14 @@
<view class="bottom-btn cancel-btn" @click="handleCancel"></view>
<view class="bottom-btn confirm-btn" @click="handleSubmit"></view>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onShow, onHide } from '@dcloudio/uni-app'
import { ref, nextTick } from 'vue'
import { onReady, onShow, onHide } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { createSparepartOutbound } from '@/api/mes/sparepartOutbound'
@ -153,6 +155,18 @@ function handleSelectSparepart() {
const scanCodeInput = ref('')
//
const focusNoKeyboardRef = ref(null)
const keywordInputSelector = '#sparepart-outbound-scan-input input, input#sparepart-outbound-scan-input'
function focusKeywordNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(keywordInputSelector)
}, 80)
})
}
function onScanInputConfirm() {
const code = scanCodeInput.value.trim()
if (!code) return
@ -263,6 +277,8 @@ async function handleSubmit() {
}
}
onReady(() => { focusKeywordNoKeyboard() })
onShow(() => { const items = getApp().globalData?._sparepartOutboundItems; if (Array.isArray(items)) itemList.value = [...items]; loadOperators() })
onHide(() => { showOperatorDropdown.value = false })
</script>

@ -5,7 +5,7 @@
<view class="sparepart-section">
<view class="section-title-bar">
<view class="section-bar-line"></view>
<text class="section-title">å·²éå¤ä»?/text>
<text class="section-title">已选备件</text>
</view>
<view class="sparepart-card">
<view class="card-top">
@ -14,24 +14,24 @@
<view v-else class="card-image-empty"><text class="empty-img-icon">📦</text></view>
</view>
<view class="card-info-right">
<view class="info-item"><text class="info-label">å¤ä»å<EFBFBD><EFBFBD>ç§°ï¼?/text><text class="info-name">{{ textValue(sparepart.name) }}</text></view>
<view class="info-item"><text class="info-label">è§æ ¼ï¼?/text><text class="info-value">{{ textValue(sparepart.standard || sparepart.deviceSpec) }}</text></view>
<view class="info-item"><text class="info-label">å½å<EFBFBD>åºå­˜ï¼?/text><text class="info-value stock-highlight">{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.minStockUnitName || 'ä¸?) }}</text></view>
<view class="info-item"><text class="info-label">备件名称</text><text class="info-name">{{ textValue(sparepart.name) }}</text></view>
<view class="info-item"><text class="info-label">规格</text><text class="info-value">{{ textValue(sparepart.standard || sparepart.deviceSpec) }}</text></view>
<view class="info-item"><text class="info-label">当前库存</text><text class="info-value stock-highlight">{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.minStockUnitName || '个') }}</text></view>
</view>
</view>
<view class="card-bottom">
<view class="detail-row two-col">
<view class="detail-col"><text class="detail-label">éè´­å<EFBFBD>ä½<EFBFBD>ï¼?/text><text class="detail-value">{{ textValue(sparepart.purchaseUnitName) }}</text></view>
<view class="detail-col"><text class="detail-label">åºå­˜å<EFBFBD>ä½<EFBFBD>ï¼?/text><text class="detail-value">{{ textValue(sparepart.unitName || sparepart.minStockUnitName || 'ä¸?) }}</text></view>
<view class="detail-col"><text class="detail-label">采购单位</text><text class="detail-value">{{ textValue(sparepart.purchaseUnitName) }}</text></view>
<view class="detail-col"><text class="detail-label">库存单位</text><text class="detail-value">{{ textValue(sparepart.unitName || sparepart.minStockUnitName || '个') }}</text></view>
</view>
<view class="detail-row"><text class="detail-label">æ<EFBFBD>¢ç®å³ç³»ï¼?/text><text class="detail-value">1{{ textValue(sparepart.purchaseUnitName) }}={{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }}</text></view>
<view class="detail-row"><text class="detail-label">换算关系</text><text class="detail-value">1{{ textValue(sparepart.purchaseUnitName) }}={{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }}</text></view>
</view>
</view>
<!-- åºåºç¨é?-->
<!-- 出库用途 -->
<view class="section-title-bar" style="padding-top: 24rpx;">
<view class="section-bar-line"></view>
<text class="section-title">åºåºç¨é?/text>
<text class="section-title">出库用途</text>
</view>
<view class="purpose-card">
<view class="purpose-item" :class="{ active: selectedPurpose === 'repair' }" @click="setPurpose('repair')">
@ -59,15 +59,15 @@
<view class="warehouse-area-dropdown" @click="toggleDeviceDropdown">
<view class="dropdown-input">
<text :class="['dropdown-value', { placeholder: !selectedDevice }]">{{ selectedDevice ? selectedDevice.label : '请选择' }}</text>
<text class="dropdown-arrow">â?/text>
<text class="dropdown-arrow"></text>
</view>
<view v-if="showDeviceDropdown" class="dropdown-panel">
<view class="dropdown-scroll">
<view v-for="item in filteredDeviceOptions" :key="item.value" class="dropdown-item" :class="{ active: selectedDevice?.value === item.value }" @click.stop="handleSelectDevice(item)">
<text class="dropdown-item-text">{{ item.label }}</text>
<text v-if="selectedDevice?.value === item.value" class="dropdown-check">�/text>
<text v-if="selectedDevice?.value === item.value" class="dropdown-check"></text>
</view>
<view v-if="deviceLoading" class="dropdown-empty">加载�..</view>
<view v-if="deviceLoading" class="dropdown-empty">...</view>
<view v-else-if="!filteredDeviceOptions.length" class="dropdown-empty">{{ selectedPurpose === 'maintain' ? '暂无保养设备' : '暂无设备数据' }}</view>
</view>
</view>
@ -78,15 +78,15 @@
<view class="warehouse-area-dropdown" @click="toggleOrderDropdown">
<view class="dropdown-input">
<text :class="['dropdown-value', { placeholder: !currentOrder }]">{{ currentOrder ? currentOrder.label : '请选择' }}</text>
<text class="dropdown-arrow">â?/text>
<text class="dropdown-arrow"></text>
</view>
<view v-if="showOrderDropdown" class="dropdown-panel">
<view class="dropdown-scroll">
<view v-for="item in currentOrderOptions" :key="item.value" class="dropdown-item" :class="{ active: currentOrder?.value === item.value }" @click.stop="handleSelectOrder(item)">
<text class="dropdown-item-text">{{ item.label }}</text>
<text v-if="currentOrder?.value === item.value" class="dropdown-check">�/text>
<text v-if="currentOrder?.value === item.value" class="dropdown-check"></text>
</view>
<view v-if="!currentOrderOptions.length" class="dropdown-empty">{{ selectedPurpose === 'repair' ? 'æšæ ç»´ä¿®å<EFBFBD>? : 'æšæ ä¿<EFBFBD>å»å<EFBFBD>? }}</view>
<view v-if="!currentOrderOptions.length" class="dropdown-empty">{{ selectedPurpose === 'repair' ? '' : '' }}</view>
</view>
</view>
</view>
@ -101,7 +101,7 @@
<view class="qty-input-card">
<view class="form-field">
<text class="form-label">出库数量</text>
<input v-model="outboundQty" class="form-input" placeholder="请输� confirm-type="done" />
<input v-model="outboundQty" class="form-input" placeholder="请输入" confirm-type="done" />
<text class="form-suffix-text">单位{{ textValue(sparepart.purchaseUnitName) }}</text>
</view>
<view class="convert-row">
@ -111,20 +111,19 @@
</view>
<view class="convert-helper">{{ currentStockText }}</view>
<view class="convert-formula-inline">{{ outboundQty || 0 }}{{ textValue(sparepart.purchaseUnitName) }} × {{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(sparepart) }}</view>
<!-- åºå­˜ä¸<EFBFBD>è³æ<EFBFBD><EFBFBD>示 -->
<view v-if="stockExceeded" class="stock-warning">
<text class="warning-icon">âš?/text>
<text class="warning-icon"></text>
<view class="warning-text">
<text class="warning-line">å½å<EFBFBD>åºå­˜ä¸<EFBFBD>è³ï¼Œä¸<EFBFBD>能åºåº?/text>
<text class="warning-line">å½å<EFBFBD>åºå­˜ï¼š{{ stockCount }}{{ stockUnitLabel(sparepart) }}({{ stockPackText }}ï¼?/text>
<text class="warning-line">本次åºåºï¼š{{ calculatedStock }}{{ stockUnitLabel(sparepart) }}({{ outboundPackText }}ï¼?/text>
<text class="warning-line">当前库存不足不能出库</text>
<text class="warning-line">当前库存{{ stockCount }}{{ stockUnitLabel(sparepart) }}{{ stockPackText }}</text>
<text class="warning-line">本次出库{{ calculatedStock }}{{ stockUnitLabel(sparepart) }}{{ outboundPackText }}</text>
</view>
</view>
</view>
<!-- ä¾åºå?-->
<!-- 供应商 -->
<view class="section-title-bar" style="padding-top: 24rpx;">
<view class="section-bar-line"></view><text class="section-title">ä¾åºå?/text>
<view class="section-bar-line"></view><text class="section-title">供应商</text>
</view>
<view class="select-row-card">
<view class="full-dropdown">
@ -143,13 +142,13 @@
<view class="warehouse-area-dropdown" @click="toggleWarehouseDropdown">
<view class="dropdown-input">
<text :class="['dropdown-value', { placeholder: !selectedWarehouse }]">{{ selectedWarehouse ? selectedWarehouse.label : '请选择' }}</text>
<text class="dropdown-arrow">â?/text>
<text class="dropdown-arrow"></text>
</view>
<view v-if="showWarehouseDropdown" class="dropdown-panel">
<view class="dropdown-scroll">
<view v-for="item in warehouseOptions" :key="item.value" class="dropdown-item" :class="{ active: selectedWarehouse?.value === item.value }" @click.stop="handleSelectWarehouse(item)">
<text class="dropdown-item-text">{{ item.label }}</text>
<text v-if="selectedWarehouse?.value === item.value" class="dropdown-check">�/text>
<text v-if="selectedWarehouse?.value === item.value" class="dropdown-check"></text>
</view>
</view>
</view>
@ -159,14 +158,14 @@
<text class="warehouse-area-label">库区</text>
<view class="warehouse-area-dropdown" @click="toggleAreaDropdown">
<view class="dropdown-input">
<text :class="['dropdown-value', { placeholder: !selectedArea }]">{{ selectedArea ? selectedArea.label : (loadingAreas ? '加载�..' : '请选择') }}</text>
<text class="dropdown-arrow">â?/text>
<text :class="['dropdown-value', { placeholder: !selectedArea }]">{{ selectedArea ? selectedArea.label : (loadingAreas ? '加载中...' : '请选择') }}</text>
<text class="dropdown-arrow"></text>
</view>
<view v-if="showAreaDropdown" class="dropdown-panel">
<view class="dropdown-scroll">
<view v-for="item in areaOptions" :key="item.value" class="dropdown-item" :class="{ active: selectedArea?.value === item.value }" @click.stop="handleSelectArea(item)">
<text class="dropdown-item-text">{{ item.label }}</text>
<text v-if="selectedArea?.value === item.value" class="dropdown-check">�/text>
<text v-if="selectedArea?.value === item.value" class="dropdown-check"></text>
</view>
</view>
</view>
@ -224,7 +223,6 @@ const showOrderDropdown = ref(false)
const currentOrder = computed(() => selectedPurpose.value === 'repair' ? selectedRepairOrder.value : selectedMaintainOrder.value)
const currentOrderOptions = computed(() => selectedPurpose.value === 'repair' ? repairOrderOptions.value : maintainOrderOptions.value)
// ä»åº/åºåŒº
const warehouseOptions = ref([])
const selectedWarehouse = ref(null)
const showWarehouseDropdown = ref(false)
@ -252,7 +250,6 @@ const stockExceeded = computed(() => {
return outboundQty.value > 0 && calculatedStock.value > stockCount.value
})
// åºå­˜æ ¼å¼<EFBFBD>åŒï¼šXåŒY根(带å<EFBFBD>ä½<EFBFBD>ï¼
function formatStockPack(count) {
const ratio = Number(sparepart.value.purchaseUnitConvertQuantity) || 1
if (ratio === 1) return ''
@ -266,13 +263,11 @@ function formatStockPack(count) {
const currentStockText = computed(() => {
const text = formatStockPack(stockCount.value)
return text ? `当å‰<EFBFBD>库存ï¼?{text}` : ''
return text ? `当前库存:${text}` : ''
})
const stockPackText = computed(() => {
return formatStockPack(stockCount.value) || `${stockCount.value}${stockUnitLabel(sparepart)}`
})
const outboundPackText = computed(() => {
return formatStockPack(calculatedStock.value) || `${calculatedStock.value}${stockUnitLabel(sparepart)}`
})
@ -290,30 +285,26 @@ const defaultSupplierName = computed(() => {
function textValue(v) { if (v === 0) return '0'; if (v == null) return '-'; const s = String(v).trim(); return s || '-' }
function textUnit(v) { if (v === 0) return '0'; if (v == null) return ''; return String(v).trim() }
function stockUnitLabel(item) { return item.unitName || item.minStockUnitName || '� }
function stockUnitLabel(item) { return item.unitName || item.minStockUnitName || '个' }
function handleCancel() { uni.navigateBack() }
// ç¨é映å°ï¼šrepairâ?, maintainâ?, otherâ?
const PURPOSE_MAP = { repair: 1, maintain: 2, other: 3 }
function handleConfirm() {
if (!outboundQty.value || Number(outboundQty.value) <= 0) {
uni.showToast({ title: '请输入出库数�, icon: 'none' }); return
uni.showToast({ title: '请输入出库数量', icon: 'none' }); return
}
if (stockExceeded.value) {
uni.showModal({
title: '库存不足',
content: `当å‰<EFBFBD>库存ï¼?{stockCount.value}${stockUnitLabel(sparepart)}ï¼?{stockPackText.value})\n本次出库ï¼?{calculatedStock.value}${stockUnitLabel(sparepart)}ï¼?{outboundPackText.value})`,
content: `当前库存:${stockCount.value}${stockUnitLabel(sparepart)}${stockPackText.value}\n本次出库${calculatedStock.value}${stockUnitLabel(sparepart)}${outboundPackText.value}`,
showCancel: false,
confirmText: '知é<EFBFBD>äº?
confirmText: '知道了'
})
return
}
if (selectedPurpose.value === 'repair' && !selectedDevice.value) {
uni.showToast({ title: '请选æ©å…³è<C2B3>”设备', icon: 'none' }); return
}
if (selectedPurpose.value === 'maintain' && !selectedDevice.value) {
if ((selectedPurpose.value === 'repair' || selectedPurpose.value === 'maintain') && !selectedDevice.value) {
uni.showToast({ title: '请选择关联设备', icon: 'none' }); return
}
if (!selectedWarehouse.value) {
@ -355,7 +346,7 @@ function handleConfirm() {
}
getApp().globalData._sparepartOutboundItems.push(item)
uni.showToast({ title: '已添� ' + (sparepart.value.name || ''), icon: 'success', duration: 1200 })
uni.showToast({ title: '已添加: ' + (sparepart.value.name || ''), icon: 'success', duration: 1200 })
setTimeout(() => {
const fromScan = getApp().globalData._sparepartFromScan
getApp().globalData._sparepartFromScan = false
@ -363,7 +354,6 @@ function handleConfirm() {
}, 800)
}
// Device dropdown
function toggleDeviceDropdown() {
showDeviceDropdown.value = !showDeviceDropdown.value
if (showDeviceDropdown.value && selectedPurpose.value === 'maintain' && maintainDeviceIds.value.size === 0) {
@ -458,7 +448,6 @@ async function loadRepairOrdersById(deviceId) {
} catch (e) { console.error('loadRepairOrdersById error', e) }
}
// ä»åº
function toggleWarehouseDropdown() { showWarehouseDropdown.value = !showWarehouseDropdown.value }
function handleSelectWarehouse(item) { selectedWarehouse.value = item; showWarehouseDropdown.value = false; selectedArea.value = null; areaOptions.value = []; loadAreas(item.value) }
async function loadWarehouses() {
@ -466,13 +455,11 @@ async function loadWarehouses() {
const res = await getWarehouseSimpleList()
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
warehouseOptions.value = data.map(w => ({ value: w.id, label: w.name || String(w.id || '') }))
// 默认é中"å¤ä»ä»?
const defaultWh = warehouseOptions.value.find(w => (w.label || '').includes('å¤ä»ä»?))
const defaultWh = warehouseOptions.value.find(w => (w.label || '').includes('备件仓'))
if (defaultWh) { selectedWarehouse.value = defaultWh; loadAreas(defaultWh.value) }
} catch (e) {}
}
// åºåŒº
function toggleAreaDropdown() { if (!selectedWarehouse.value) { uni.showToast({ title: '请先选择仓库', icon: 'none' }); return }; showAreaDropdown.value = !showAreaDropdown.value }
function handleSelectArea(item) { selectedArea.value = item; showAreaDropdown.value = false }
async function loadAreas(warehouseId) {
@ -483,8 +470,7 @@ async function loadAreas(warehouseId) {
const res = await getWarehouseAreaSimpleList(warehouseId)
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
areaOptions.value = data.map(a => ({ value: a.id, label: a.name || a.areaName || String(a.id || '') }))
// 默认é中"å¤ä»åº?
const defaultArea = areaOptions.value.find(a => (a.label || '').includes('å¤ä»åº?))
const defaultArea = areaOptions.value.find(a => (a.label || '').includes('备件库'))
if (defaultArea) selectedArea.value = defaultArea
} catch (e) {} finally { loadingAreas.value = false }
}
@ -587,4 +573,4 @@ onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false
.bottom-btn { flex: 1; height: 84rpx; line-height: 84rpx; text-align: center; border-radius: 16rpx; font-size: 30rpx; font-weight: 600; &:active { opacity: 0.85; } }
.cancel-btn { background: #eef2f7; color: #475569; }
.confirm-btn { background: #1f4b79; color: #ffffff; }
</style>
</style>
Loading…
Cancel
Save