优化
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { overseasRequest } from './overseas.js'
|
||||
|
||||
const BASE = '/api/pda/v1/last-leg/pallet-operations'
|
||||
|
||||
export function resolvePallet(code) {
|
||||
return overseasRequest('POST', `${BASE}/pallets/resolve`, { code: String(code || '').trim() })
|
||||
}
|
||||
|
||||
export function assemblePallet(payload) {
|
||||
return overseasRequest('POST', `${BASE}/assemble`, payload)
|
||||
}
|
||||
|
||||
export function disassemblePallet(payload) {
|
||||
return overseasRequest('POST', `${BASE}/disassemble`, payload)
|
||||
}
|
||||
|
||||
export function swapPallet(payload) {
|
||||
return overseasRequest('POST', `${BASE}/swap`, payload)
|
||||
}
|
||||
|
||||
export function unbindPallet(payload) {
|
||||
return overseasRequest('POST', `${BASE}/unbind`, payload)
|
||||
}
|
||||
+3
-3
@@ -6,9 +6,9 @@ import es from './locales/es.js'
|
||||
const LOCALE_KEY = 'overseas-pda-locale'
|
||||
export const SUPPORTED_LOCALES = ['zh-CN', 'en', 'es']
|
||||
export const LOCALE_OPTIONS = [
|
||||
{ value: 'zh-CN', labelKey: 'language.zh' },
|
||||
{ value: 'en', labelKey: 'language.en' },
|
||||
{ value: 'es', labelKey: 'language.es' }
|
||||
{ value: 'zh-CN', label: '简体中文', labelKey: 'language.zh' },
|
||||
{ value: 'en', label: 'English', labelKey: 'language.en' },
|
||||
{ value: 'es', label: 'Español', labelKey: 'language.es' }
|
||||
]
|
||||
|
||||
function normalizeLocale(value) {
|
||||
|
||||
@@ -3,25 +3,19 @@
|
||||
<PortalHeader :title="inboundMode ? '拆柜收货' : operationName" :user="user" :fallback-url="`/pages/module/module?key=${moduleKey}`" />
|
||||
<view class="portal-content receiving-content" :class="{ 'receiving-content-with-action': phase === 'detail' || phase === 'sign' || (phase === 'receive' && allInboundsReconciled) }">
|
||||
<template v-if="inboundMode">
|
||||
<view v-if="phase !== 'receive'" class="receiving-heading"><view><text class="receiving-title">{{ pageTitle }}</text><text class="receiving-subtitle">{{ pageSubtitle }}</text></view></view>
|
||||
<view v-if="phase !== 'candidates' && phase !== 'receive'" class="receiving-heading"><view><text class="receiving-title">{{ pageTitle }}</text><text class="receiving-subtitle">{{ pageSubtitle }}</text></view></view>
|
||||
|
||||
<view v-if="loading" class="state-card"><uni-load-more status="loading" /><text>正在恢复当前柜作业…</text></view>
|
||||
|
||||
<template v-else-if="phase === 'candidates'">
|
||||
<view class="scan-card">
|
||||
<text class="section-label">扫描柜号</text>
|
||||
<ScanTargetInput name="container" v-model="containerInput" label="柜号" placeholder="扫描或人工输入柜号" :active="activeTarget === 'container'" @activate="activeTarget = 'container'" @submit="openContainer" />
|
||||
<button class="primary-button" :disabled="busy || !containerInput.trim()" @tap="openContainer(containerInput)">查询柜号</button>
|
||||
</view>
|
||||
<view class="list-toolbar"><text>{{ candidates.length }} 个待卸货集装箱</text><button :disabled="busy || candidateLoading" @tap="loadCandidates">{{ candidateLoading ? '刷新中…' : '刷新' }}</button></view>
|
||||
<view class="list-toolbar"><text>共 {{ candidates.length }} 柜</text><button :disabled="busy || candidateLoading" @tap="loadCandidates">{{ candidateLoading ? '刷新中…' : '刷新' }}</button></view>
|
||||
<view v-if="candidateError" class="error-card candidate-error-card"><text class="error-message">{{ candidateError.message || '待卸货集装箱加载失败' }}</text><text v-if="candidateError.code">code={{ candidateError.code }}</text><text v-if="candidateError.requestId">requestId={{ candidateError.requestId }}</text><text v-if="candidateError.traceId">traceId={{ candidateError.traceId }}</text><button class="secondary-button" :disabled="candidateLoading" @tap="loadCandidates">重新加载</button></view>
|
||||
<view v-if="candidateLoading && !candidates.length" class="state-card"><uni-load-more status="loading" /><text>正在刷新待卸货集装箱…</text></view>
|
||||
<view v-else-if="!candidateError && !candidates.length" class="empty-card"><uni-icons type="info" color="#8090a3" size="34" /><text>暂无待卸货集装箱</text><button class="secondary-button" :disabled="candidateLoading" @tap="loadCandidates">重新加载</button></view>
|
||||
<view v-for="item in candidates" :key="item.containerNo" class="container-card">
|
||||
<view class="card-head"><view><text class="container-no">{{ item.containerNo }}</text><text class="container-meta">{{ item.inboundCodeCount }} 个入仓码 · {{ item.planCount }} 个计划<template v-if="item.plannedPalletCount != null"> · {{ item.plannedPalletCount }} 托</template></text><text v-if="item.destinationCodes?.length" class="container-meta">目的仓:{{ item.destinationCodes.join(' / ') }}</text></view><text class="status-tag" :class="statusTone(item.status)">{{ statusLabel(item.status) }}</text></view>
|
||||
<view class="progress-row"><text>收货进度</text><text><strong>{{ item.receivedPackages }}</strong> / {{ item.totalPackages }} 箱</text></view>
|
||||
<view class="progress-track"><view class="progress-fill" :style="{ width: percent(item.receivedPackages, item.totalPackages) + '%' }"></view></view>
|
||||
<button class="primary-button" :disabled="busy" @tap="openContainer(item.containerNo)">{{ item.currentAccount ? '继续当前柜' : '查看详情' }}</button>
|
||||
<view v-for="item in candidates" :key="item.containerNo" class="container-card container-card-compact" role="button" :aria-label="`${item.containerNo},${item.currentAccount ? '继续当前柜' : '查看详情'}`" hover-class="container-card-pressed" @tap="openContainer(item.containerNo)">
|
||||
<view class="card-head"><text class="container-no">{{ item.containerNo }}</text><view class="container-card-actions"><text class="status-tag" :class="statusTone(item.status)">{{ statusLabel(item.status) }}</text><text class="container-detail-link">{{ item.currentAccount ? '继续' : '详情' }} ›</text></view></view>
|
||||
<view class="candidate-facts"><view><strong>{{ item.inboundCodeCount }}</strong><text>入仓码</text></view><view><strong>{{ item.totalPackages }}</strong><text>箱</text></view><view><strong>{{ item.plannedPalletCount }}</strong><text>计划托盘</text></view><view><strong>{{ item.destinationCodes?.length || 0 }}</strong><text>目的仓</text></view></view>
|
||||
<text v-if="item.destinationCodes?.length" class="candidate-destinations">仓码:{{ item.destinationCodes.join(' / ') }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -113,7 +107,7 @@
|
||||
|
||||
export default {
|
||||
components: { PortalHeader, ReceivingSessionSummary, ScanTargetInput },
|
||||
data() { return { user: session.currentUser, moduleKey: 'query', operationName: '库存查询', loading: false, candidateLoading: false, busy: false, bootstrapped: false, detailOpen: false, containerInput: '', cartonInput: '', palletInput: '', packageCount: 1, candidateError: null, error: null, toast: { visible: false, message: '', type: '' } } },
|
||||
data() { return { user: session.currentUser, moduleKey: 'query', operationName: '库存查询', loading: false, candidateLoading: false, busy: false, bootstrapped: false, detailOpen: false, cartonInput: '', palletInput: '', packageCount: 1, candidateError: null, error: null, toast: { visible: false, message: '', type: '' } } },
|
||||
computed: {
|
||||
inboundMode() { return this.moduleKey === 'inbound' },
|
||||
photoSteps() { return RECEIVING_PHOTO_ROLES.map((role) => ({ role, label: ({ LICENSE_PLATE: '车牌照片', CONTAINER_SEAL: '集装箱封签', DOOR_OPEN: '开柜现场' })[role] })) },
|
||||
@@ -132,19 +126,19 @@
|
||||
onHide() { this.stopScanner() }, onUnload() { this.stopScanner() }, beforeUnmount() { clearTimeout(this._toastTimer); this.stopScanner() },
|
||||
methods: {
|
||||
statusLabel(status) { return ({ WAIT_SIGN: '待签收', SIGNED: '已签收', RECEIVING: '收货中', COMPLETED: '已完成' })[status] || status },
|
||||
statusTone(status) { return status === 'RECEIVING' ? 'status-current' : status === 'COMPLETED' ? 'status-good' : 'status-wait' }, percent(received, total) { return total ? Math.min(100, Math.round(Number(received || 0) / Number(total) * 100)) : 0 },
|
||||
statusTone(status) { return status === 'RECEIVING' ? 'status-current' : status === 'COMPLETED' ? 'status-good' : 'status-wait' },
|
||||
destinationLabel(item) { return item?.destinationType === 'FBA' ? (item.fbaWarehouseCode || 'FBA') : (item?.destinationWarehouseName || item?.destinationWarehouseCode || '海外仓') },
|
||||
photoStateLabel(photo) { if (photo?.status === 'uploading') return '正在上传…'; if (photo?.status === 'error') return photo.fileId ? '重拍失败,已保留原图' : '上传失败,请重试'; return photo?.fileId ? '点击左侧照片可查看大图' : '请拍摄现场照片' },
|
||||
startScanner() { this.stopScanner(); this._stopScanner = startScanBroadcast({ onScan: (value) => this.handleHardwareScan(value), onError: (error) => { this.error = error; this.showToast('硬件扫码接收器异常,请检查扫描服务', 'warning') } }) }, stopScanner() { if (typeof this._stopScanner === 'function') this._stopScanner(); this._stopScanner = null },
|
||||
handleHardwareScan(value) { console.info('[Overseas PDA scan] dispatch', { value, phase: this.phase, target: this.activeTarget, matchedInbound: this.activeInbound?.inboundCode }); if (!this.inboundMode) return this.showToast('该功能缺少海外 PDA 专用接口,扫码未提交', 'warning'); if (this.phase === 'candidates') { this.containerInput = value; return this.openContainer(value) } if (this.phase !== 'receive') return; if (this.activeTarget === 'pallet' && this.activeInbound) { this.palletInput = value; return this.resolvePallet(value) } this.cartonInput = value; return this.resolveCarton(value) },
|
||||
handleHardwareScan(value) { console.info('[Overseas PDA scan] dispatch', { value, phase: this.phase, target: this.activeTarget, matchedInbound: this.activeInbound?.inboundCode }); if (!this.inboundMode) return this.showToast('该功能缺少海外 PDA 专用接口,扫码未提交', 'warning'); if (this.phase === 'candidates') return this.showToast('请直接点击待卸货集装箱进入详情', 'warning'); if (this.phase !== 'receive') return; if (this.activeTarget === 'pallet' && this.activeInbound) { this.palletInput = value; return this.resolvePallet(value) } this.cartonInput = value; return this.resolveCarton(value) },
|
||||
async run(action, work) { this.busy = true; this.error = null; try { const result = await work(); this.showToast(`${action}成功`, 'success'); return result } catch (error) { this.error = error; playErrorSound(); this.showToast(error.message || `${action}失败`, 'error'); throw error } finally { this.busy = false } },
|
||||
setScanTargetForCurrent(value) { receiving.activeScanTarget = value?.status === 'WAIT_SIGN' ? 'container' : 'carton' },
|
||||
async restorePhotoPreviews() { await Promise.all(receiving.photoSlots.filter((photo) => photo?.downloadPath && !photo.localPath).map(async (photo) => { photo.status = 'restoring'; try { photo.localPath = await downloadCurrentUnloadPhoto(photo.downloadPath); photo.status = 'success' } catch (error) { photo.status = 'error'; photo.errorMessage = error.message || '照片加载失败'; this.error = error } })) },
|
||||
async applyCurrentReceiving(value) { setCurrentReceiving(value); await this.restorePhotoPreviews(); this.setScanTargetForCurrent(value) },
|
||||
async bootstrap() { if (this.loading) return; this.loading = true; this.error = null; this.detailOpen = false; try { const current = await getCurrentReceiving(); await this.applyCurrentReceiving(current); this.candidateError = null; this.bootstrapped = true } catch (error) { if (isNoCurrentReceiving(error)) { resetReceivingDraft(); await this.loadCandidates(false); this.bootstrapped = true } else this.candidateError = error } finally { this.loading = false } },
|
||||
async recoverCurrentAfterConflict(error) { if (!isReceivingConflict(error)) return false; try { const current = await getCurrentReceiving(); await this.applyCurrentReceiving(current); this.detailOpen = false; this.error = null; this.showToast(`账号已有未完成柜 ${current.containerNo},已返回当前柜`, 'warning'); return true } catch (recoveryError) { this.error = recoveryError; return false } },
|
||||
async recoverCurrentAfterConflict(error) { if (!isReceivingConflict(error)) return false; try { const current = await getCurrentReceiving(); await this.applyCurrentReceiving(current); this.detailOpen = false; this.error = null; this.showToast(`账号已有未完成柜 ${current.containerNo},已返回当前柜`, 'warning'); return true } catch (recoveryError) { if (isNoCurrentReceiving(recoveryError)) { this.detailOpen = false; receiving.selected = null; await this.loadCandidates(false); this.error = null; this.showToast('该柜已被其他账号选择,列表已刷新', 'warning'); return true } this.error = error; return false } },
|
||||
async loadCandidates(feedback = true) { if (this.candidateLoading) return; this.candidateLoading = true; this.candidateError = null; this.error = null; try { receiving.candidates = await listReceivingCandidates(); if (feedback) this.showToast('刷新待卸柜成功', 'success') } catch (error) { this.candidateError = error; if (feedback) { playErrorSound(); this.showToast(error.message || '刷新待卸柜失败', 'error') } } finally { this.candidateLoading = false } },
|
||||
async openContainer(raw) { const containerNo = String(raw?.detail?.value ?? raw ?? this.containerInput).trim(); if (!containerNo || this.busy) return; try { receiving.selected = await this.run('查询柜号', () => getReceivingContainer(containerNo)); this.containerInput = containerNo; this.detailOpen = true; playSuccessSound() } catch (error) { await this.recoverCurrentAfterConflict(error) } },
|
||||
async openContainer(raw) { const containerNo = String(raw?.detail?.value ?? raw ?? '').trim(); if (!containerNo || this.busy) return; try { receiving.selected = await this.run('查询柜号', () => getReceivingContainer(containerNo)); this.detailOpen = true; playSuccessSound() } catch (error) { await this.recoverCurrentAfterConflict(error) } },
|
||||
cancelDetail() { this.detailOpen = false; receiving.selected = null },
|
||||
async prepareContainer() { if (!this.selected?.containerNo || this.busy) return; const key = idempotencyKey('prepare', { containerNo: this.selected.containerNo }); try { const value = await this.run('选择当前柜', () => prepareReceivingContainer(this.selected.containerNo, { idempotencyKey: key.value })); releaseIdempotencyKey(key.signature); setCurrentReceiving(value); this.setScanTargetForCurrent(value); this.detailOpen = false } catch (error) { await this.recoverCurrentAfterConflict(error) } },
|
||||
choosePhoto(index) { if (this.busy) return; uni.chooseImage({ count: 1, sourceType: ['camera'], success: ({ tempFilePaths }) => { const path = tempFilePaths?.[0]; if (path) this.replacePhoto(index, path) } }) },
|
||||
@@ -191,4 +185,5 @@
|
||||
.receiving-content-with-action{padding-bottom:calc(152px + env(safe-area-inset-bottom,0px))}
|
||||
.primary-button,.secondary-button,.ghost-button{display:flex;box-sizing:border-box;align-items:center;justify-content:center;padding-top:0;padding-bottom:0;line-height:normal;text-align:center}
|
||||
.sticky-action button{display:flex;align-items:center;justify-content:center;line-height:normal;text-align:center}
|
||||
.list-toolbar{height:28px;margin:0 2px 7px;align-items:center}.list-toolbar button{box-sizing:border-box;width:auto;min-width:48px;height:28px;min-height:28px;margin:0;padding:0 8px;border:1px solid #bdd1eb;border-radius:7px;color:#1668dc;font-size:11px;line-height:26px;background:#f7faff}.container-card-compact{padding:11px 13px;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}.container-card-pressed{border-color:#93baf0;background:#f4f8ff}.container-card-actions{display:flex;flex-shrink:0;align-items:flex-end;flex-direction:column;gap:5px}.container-detail-link{box-sizing:border-box;min-height:24px;padding:0 4px;color:#1668dc;font-size:11px;font-weight:700;line-height:24px}.candidate-facts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:9px;padding:8px 0;border-top:1px solid #edf1f5;border-bottom:1px solid #edf1f5}.candidate-facts view{display:flex;align-items:center;flex-direction:column;border-right:1px solid #edf1f5}.candidate-facts view:last-child{border-right:0}.candidate-facts strong{color:#17324d;font-size:17px;line-height:21px}.candidate-facts text{margin-top:2px;color:#6f8194;font-size:10px}.candidate-destinations{display:block;margin-top:7px;overflow:hidden;color:#6f8194;font-size:11px;line-height:17px;text-overflow:ellipsis;white-space:nowrap}
|
||||
</style>
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
<view class="profile-row"><text>作业仓库</text><text class="profile-value">{{ warehouseDisplay }}</text></view>
|
||||
<view class="profile-row"><text>当前班次</text><text class="profile-value">以海外仓排班为准</text></view>
|
||||
<view class="profile-row"><text>应用版本</text><text class="profile-value">{{ appVersion }}</text></view>
|
||||
<button class="profile-row profile-row-action" @tap="checkUpdate"><text>检查更新</text><text class="profile-row-arrow">›</text></button>
|
||||
<button class="profile-row profile-row-action" @tap="showSettings"><text>系统设置</text><text class="profile-row-arrow">›</text></button>
|
||||
<button class="profile-row profile-row-action" @tap="selectLanguage"><text>切换语言</text><view class="profile-row-end"><text class="profile-value">{{ languageLabel }}</text><text class="profile-row-arrow">›</text></view></button>
|
||||
</view>
|
||||
<button class="profile-action" @tap="checkUpdate">检查更新 <text>›</text></button>
|
||||
<button class="profile-action" @tap="showSettings">系统设置 <text>›</text></button>
|
||||
<button class="logout-action" @tap="openLogout">退出登录</button>
|
||||
</view>
|
||||
<uni-popup ref="logoutPopup" type="center" :is-mask-click="true" @change="handleLogoutChange"><view class="logout-dialog-card" role="dialog" aria-modal="true" aria-label="确认退出登录"><PopupHeader title="确认退出登录?" tone="danger" @close="closeLogout" /><text class="logout-dialog-content">退出后会清空海外 PDA 的本地登录会话;未提交作业数据不得跨账号保留。</text><view class="logout-dialog-actions"><button class="logout-dialog-cancel" @tap="closeLogout">取消</button><button class="logout-dialog-confirm" @tap="logout">确认退出</button></view></view></uni-popup>
|
||||
@@ -20,15 +21,17 @@
|
||||
import PortalHeader from '@/components/PortalHeader.vue'
|
||||
import PopupHeader from '@/components/PopupHeader.vue'
|
||||
import { getCurrentWarehouseProfile } from '@/api/inbound.js'
|
||||
import { currentLocale, LOCALE_OPTIONS, setLocale } from '@/i18n/index.js'
|
||||
import { applyWarehouseProfile, session, requireSession, signOut } from '@/stores/session.js'
|
||||
import { checkForAppUpdate } from '@/utils/app-update.js'
|
||||
export default {
|
||||
components: { PopupHeader, PortalHeader },
|
||||
data() { return { user: session.currentUser, appVersion: '0.0.1', logoutOpen: false, toast: false } },
|
||||
data() { return { user: session.currentUser, appVersion: '0.0.1', locale: currentLocale(), logoutOpen: false, toast: false } },
|
||||
computed: {
|
||||
displayName() { const name = String(this.user?.name || ''); return name && !/^[a-z0-9._-]+$/i.test(name) ? name : '仓库作业员' },
|
||||
avatar() { return this.displayName.slice(0, 1).toUpperCase() },
|
||||
warehouseDisplay() { return this.user?.warehouseName ? (this.user.warehouseCode ? `${this.user.warehouseName} · ${this.user.warehouseCode}` : this.user.warehouseName) : (this.user?.warehouse || '正在读取仓库主档') }
|
||||
warehouseDisplay() { return this.user?.warehouseName ? (this.user.warehouseCode ? `${this.user.warehouseName} · ${this.user.warehouseCode}` : this.user.warehouseName) : (this.user?.warehouse || '正在读取仓库主档') },
|
||||
languageLabel() { return LOCALE_OPTIONS.find((item) => item.value === this.locale)?.label || 'English' }
|
||||
},
|
||||
onShow() { if (!requireSession()) return; this.user = session.currentUser; this.loadAppVersion(); this.loadWarehouseProfile() },
|
||||
beforeUnmount() { clearTimeout(this._toastTimer) },
|
||||
@@ -48,6 +51,17 @@
|
||||
uni.showToast({ title: '请在 PDA App 中检查更新', icon: 'none' })
|
||||
// #endif
|
||||
},
|
||||
selectLanguage() {
|
||||
uni.showActionSheet({
|
||||
itemList: LOCALE_OPTIONS.map((item) => item.label),
|
||||
success: ({ tapIndex }) => {
|
||||
const selected = LOCALE_OPTIONS[tapIndex]
|
||||
if (!selected) return
|
||||
this.locale = setLocale(selected.value)
|
||||
uni.showToast({ title: `语言设置已保存:${selected.label}`, icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
async loadWarehouseProfile() { try { this.user = applyWarehouseProfile(await getCurrentWarehouseProfile()) } catch (_) { this.user = session.currentUser } },
|
||||
openLogout() { this.logoutOpen = true; this.$refs.logoutPopup.open() }, closeLogout() { this.logoutOpen = false; this.$refs.logoutPopup.close() }, handleLogoutChange(event) { this.logoutOpen = Boolean(event.show) },
|
||||
showSettings() { clearTimeout(this._toastTimer); this.toast = true; this._toastTimer = setTimeout(() => { this.toast = false }, 2200) },
|
||||
|
||||
+9
-5
@@ -24,8 +24,9 @@
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
button::after {
|
||||
border: 0;
|
||||
button::after,
|
||||
uni-button::after {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
button:focus-visible,
|
||||
@@ -892,9 +893,12 @@
|
||||
.profile-row { display: flex; align-items: center; justify-content: space-between; min-height: 52px; border-bottom: 1px solid $border; font-size: 13px; }
|
||||
.profile-row:last-child { border-bottom: 0; }
|
||||
.profile-value { max-width: 66%; color: $text-secondary; font-size: 12px; line-height: 18px; text-align: right; overflow-wrap: anywhere; }
|
||||
.profile-action, .logout-action { box-sizing: border-box; width: 100%; height: 50px; margin-top: 14px; padding: 0 15px; border-radius: 11px; font-size: 13px; line-height: 50px; text-align: left; background: #ffffff; }
|
||||
.profile-action { display: flex; justify-content: space-between; color: $text; }
|
||||
.logout-action { color: $danger; text-align: center; }
|
||||
.profile-row-action { box-sizing: border-box; width: 100%; height: 52px; margin: 0; padding: 0; border-radius: 0; color: $text; line-height: normal; text-align: left; background: transparent; }
|
||||
.profile-row-action::after { border: 0; }
|
||||
.profile-row-action:active { background: #f7f9fc; }
|
||||
.profile-row-end { display: flex; min-width: 0; align-items: center; justify-content: flex-end; gap: 8px; }
|
||||
.profile-row-arrow { flex-shrink: 0; color: $text-secondary; font-size: 18px; }
|
||||
.logout-action { box-sizing: border-box; width: 100%; height: 50px; margin-top: 14px; padding: 0 15px; border-radius: 11px; color: $danger; font-size: 13px; line-height: 50px; text-align: center; background: #ffffff; }
|
||||
.logout-dialog-card { box-sizing: border-box; width: calc(100vw - 48px); max-width: 320px; overflow: hidden; border-radius: 12px; background: #ffffff; box-shadow: 0 18px 50px rgba(0, 0, 0, 0.24); }
|
||||
.logout-dialog-title { display: block; padding: 24px 22px 0; color: $danger; font-size: 17px; font-weight: 700; text-align: center; }
|
||||
.logout-dialog-content { display: block; padding: 18px 22px 22px; color: $text-secondary; font-size: 14px; line-height: 22px; }
|
||||
|
||||
Reference in New Issue
Block a user