初始化柏悦物流海外版 PDA
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<view v-if="user" class="page-shell portal-page"><PortalHeader title="作业记录" :user="user" /><view class="portal-content"><view class="summary-card"><view><text class="summary-number">0</text><text class="summary-label">今日完成</text></view><view><text class="summary-number pending-color">0</text><text class="summary-label">进行中</text></view></view><text class="group-title">最近作业</text><view class="history-empty"><text class="history-empty-icon">▤</text><text class="history-empty-title">暂无海外仓作业记录</text><text class="history-empty-desc">接入海外仓真实任务后,完成记录会显示在这里</text></view></view></view>
|
||||
</template>
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'; import { session, requireSession } from '@/stores/session.js'
|
||||
export default { components: { PortalHeader }, data() { return { user: session.currentUser } }, onShow() { if (!requireSession()) return; this.user = session.currentUser } }
|
||||
</script>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<view v-if="user" class="page-shell portal-page home-page">
|
||||
<PortalHeader ref="portalHeader" title="首页" :user="user" menu @menu-change="menuOpen = $event" />
|
||||
<view class="home-menu">
|
||||
<view v-for="group in groups" :key="group.key" class="home-group">
|
||||
<view class="home-group-title"><view class="home-group-mark" :class="`home-group-mark-${group.key}`"></view><text>{{ group.name }}</text></view>
|
||||
<view class="home-operation-grid">
|
||||
<button v-for="operation in group.operations" :key="operation.name" class="home-operation" :class="{ 'home-operation-primary': operation.available, 'home-operation-disabled': !operation.available }" :disabled="!operation.available" @tap="openOperation(operation)">
|
||||
<view class="home-operation-icon" aria-hidden="true"><uni-icons :type="operation.iconType" :color="operation.available ? '#135ee8' : '#9aa6b2'" size="28" /></view>
|
||||
<text class="home-operation-name">{{ operation.name }}</text>
|
||||
<text v-if="operation.available" class="home-operation-pending">{{ operation.badge }}</text>
|
||||
<text v-else class="home-operation-unavailable">未开放</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'
|
||||
import { MODULES } from '@/data/overseas-workbench.js'
|
||||
import { session, requireSession } from '@/stores/session.js'
|
||||
|
||||
const HOME_GROUPS = MODULES.map((module) => ({
|
||||
...module,
|
||||
available: module.operations.some((operation) => operation.available),
|
||||
operations: module.operations.map((operation) => ({ ...operation, iconType: operation.iconType || 'circle' }))
|
||||
}))
|
||||
|
||||
export default {
|
||||
components: { PortalHeader },
|
||||
data() { return { user: session.currentUser, groups: HOME_GROUPS, menuOpen: false } },
|
||||
onShow() { if (!requireSession()) return; this.user = session.currentUser },
|
||||
onBackPress() {
|
||||
if (!this.menuOpen) return false
|
||||
this.$refs.portalHeader.closeMenu()
|
||||
return true
|
||||
},
|
||||
methods: {
|
||||
openOperation(operation) {
|
||||
if (!operation.available) return
|
||||
const module = this.groups.find((group) => group.operations.some((item) => item.name === operation.name))
|
||||
uni.navigateTo({ url: `/pages/operation/operation?module=${module?.key || 'query'}&name=${encodeURIComponent(operation.name)}` })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<view class="page-shell login-page">
|
||||
<view class="login-brand">
|
||||
<image class="login-logo-icon" src="/static/brand-mark-white.png" mode="aspectFit" aria-hidden="true" />
|
||||
<text class="login-logo-title">柏悦物流海外版</text><text class="login-logo-sub">海外仓现场作业系统</text>
|
||||
</view>
|
||||
<view class="login-card">
|
||||
<view class="login-field"><text class="login-field-label">工号 / 用户名</text><input v-model="form.userId" class="login-field-input" aria-label="工号 / 用户名" placeholder="请输入工号" confirm-type="next" @focus="error = ''" /></view>
|
||||
<view class="login-field"><text class="login-field-label">密码</text><input v-model="form.password" class="login-field-input" aria-label="密码" type="password" placeholder="请输入密码" confirm-type="done" @focus="error = ''" @confirm="login" /></view>
|
||||
<text v-if="error" class="login-error" role="alert">{{ error }}</text>
|
||||
<button class="login-btn" :disabled="submitting" @tap="login">{{ submitting ? '登录中...' : '登录' }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { login as loginRequest } from '@/api/auth.js'
|
||||
import { session, restoreSession, signInWithTokens } from '@/stores/session.js'
|
||||
import { requireOnline } from '@/utils/network.js'
|
||||
export default {
|
||||
data() { return { form: { userId: '', password: '' }, error: '', submitting: false } },
|
||||
onLoad() { if (session.currentUser || restoreSession()) uni.reLaunch({ url: '/pages/home/home' }) },
|
||||
methods: {
|
||||
async login() {
|
||||
const userId = this.form.userId.trim()
|
||||
if (!userId) return void (this.error = '请输入工号')
|
||||
if (!this.form.password) return void (this.error = '请输入密码')
|
||||
this.submitting = true
|
||||
this.error = ''
|
||||
try {
|
||||
requireOnline('当前网络不可用,无法登录')
|
||||
const tokens = await loginRequest(userId, this.form.password)
|
||||
signInWithTokens(tokens)
|
||||
uni.reLaunch({ url: '/pages/home/home' })
|
||||
} catch (error) {
|
||||
this.error = error.network ? '当前网络不可用,请联网后重试' : (error.message || '登录失败')
|
||||
} finally {
|
||||
this.submitting = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<view v-if="user && currentModule" class="page-shell portal-page">
|
||||
<PortalHeader title="业务模块" :user="user" />
|
||||
<view class="portal-content">
|
||||
<view class="module-hero" :class="`module-hero-${currentModule.key}`"><view class="module-hero-icon">{{ currentModule.icon }}</view><view><text class="module-hero-title">{{ currentModule.name }}</text><text class="module-hero-desc">{{ currentModule.description }}</text></view></view>
|
||||
<text class="group-title">业务功能</text>
|
||||
<view class="operation-list"><button v-for="operation in currentModule.operations" :key="operation.name" class="operation-item" :class="{ 'operation-item-disabled': !operation.available }" :disabled="!operation.available" @tap="openOperation(operation)"><view class="operation-icon">{{ operation.icon }}</view><view class="operation-info"><text class="operation-name">{{ operation.name }}</text><text class="operation-desc">{{ operation.description }}</text></view><text v-if="operation.available" class="operation-prototype">{{ operation.badge }}</text><text v-else class="operation-prototype">未开放</text><text v-if="operation.available" class="operation-arrow">›</text></button></view>
|
||||
<view class="module-empty-note">当前为海外仓独立工程首版原型;真实作业接口统一经海外网关接入。</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'
|
||||
import { MODULES } from '@/data/overseas-workbench.js'
|
||||
import { session, requireSession } from '@/stores/session.js'
|
||||
export default {
|
||||
components: { PortalHeader },
|
||||
data() { return { user: session.currentUser, moduleKey: 'inbound' } },
|
||||
computed: { currentModule() { return MODULES.find((module) => module.key === this.moduleKey) || MODULES[0] } },
|
||||
onLoad(options) { this.moduleKey = options.key || 'inbound' },
|
||||
onShow() { if (!requireSession()) return; this.user = session.currentUser },
|
||||
methods: {
|
||||
openOperation(operation) { if (operation.available) uni.navigateTo({ url: `/pages/operation/operation?module=${this.moduleKey}&name=${encodeURIComponent(operation.name)}` }) }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<view v-if="user" class="page-shell portal-page">
|
||||
<PortalHeader :title="operationName" :user="user" :fallback-url="`/pages/module/module?key=${moduleKey}`" />
|
||||
<view class="portal-content operation-page">
|
||||
<view class="operation-page-title-row"><view><text class="operation-page-title">{{ operationName }}</text><text class="operation-page-subtitle">{{ prototype.subtitle }}</text></view><text class="prototype-badge">静态原型</text></view>
|
||||
<view class="operation-scan-card"><text class="operation-scan-label">{{ prototype.scanLabel }}</text><view class="operation-scan-row"><input v-model="scanValue" class="operation-scan-input" :aria-label="prototype.scanLabel" :placeholder="prototype.scanPlaceholder" confirm-type="search" @confirm="prototypeScan" /><button class="operation-scan-button" @tap="prototypeScan">确认</button></view><text class="operation-scan-tip">支持 Android PDA 广播扫码,也可手工输入单号</text></view>
|
||||
<view class="operation-metrics"><view v-for="metric in prototype.metrics" :key="metric.label" class="operation-metric"><text class="operation-metric-value" :class="metric.tone">{{ metric.value }}</text><text class="operation-metric-label">{{ metric.label }}</text></view></view>
|
||||
<view class="task-toolbar"><text class="group-title operation-group-title">任务列表</text><button class="filter-button" @tap="showToast('筛选面板为静态原型', 'warning')">筛选</button></view>
|
||||
<view class="prototype-tabs"><button v-for="item in tabs" :key="item" class="prototype-tab" :class="{ active: tab === item }" @tap="tab = item">{{ item }}</button></view>
|
||||
<view v-if="filteredTasks.length" class="prototype-task-list"><view v-for="task in filteredTasks" :key="task.code" class="prototype-task-card"><view class="prototype-task-head"><text class="prototype-task-code">{{ task.code }}</text><text class="prototype-task-status" :class="task.tone">{{ task.status }}</text></view><text class="prototype-task-title">{{ task.title }}</text><view class="prototype-task-meta"><text>{{ task.meta }}</text><text>{{ task.location }}</text></view><view class="prototype-task-foot"><text class="prototype-task-qty">{{ task.quantity }}</text><button class="prototype-task-action" @tap="showToast(`${task.action}:${task.code}`, 'success')">{{ task.action }}</button></view></view></view>
|
||||
<view v-else class="operation-empty"><text class="operation-empty-icon">✓</text><text class="history-empty-title">暂无{{ tab }}任务</text><text class="history-empty-desc">切换其他状态查看演示数据</text></view>
|
||||
</view>
|
||||
<view v-if="toast.visible" class="app-toast" :class="toast.type" role="status">{{ toast.message }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'
|
||||
import { MODULES, getOperationPrototype } from '@/data/overseas-workbench.js'
|
||||
import { session, requireSession } from '@/stores/session.js'
|
||||
import { startScanBroadcast } from '@/utils/scan-broadcast.js'
|
||||
import { playSuccessSound } from '@/utils/audio-feedback.js'
|
||||
export default {
|
||||
components: { PortalHeader },
|
||||
data() { return { user: session.currentUser, moduleKey: 'query', operationName: '库存查询', scanValue: '', tabs: ['待处理', '进行中', '已完成'], tab: '待处理', toast: { visible: false, message: '', type: '' } } },
|
||||
computed: { currentModule() { return MODULES.find((module) => module.key === this.moduleKey) || MODULES[0] }, prototype() { return getOperationPrototype(this.operationName) }, filteredTasks() { return this.prototype.tasks.filter((task) => task.status === this.tab) } },
|
||||
onLoad(options) { this.moduleKey = options.module || 'query'; this.operationName = decodeURIComponent(options.name || '库存查询') },
|
||||
onShow() { if (!requireSession()) return; this.user = session.currentUser; this.startScanner() },
|
||||
onHide() { this.stopScanner() },
|
||||
onUnload() { this.stopScanner() },
|
||||
beforeUnmount() { clearTimeout(this._toastTimer); this.stopScanner() },
|
||||
methods: {
|
||||
startScanner() { this.stopScanner(); this._stopScanner = startScanBroadcast({ onScan: (value) => { this.scanValue = value; this.prototypeScan() } }) },
|
||||
stopScanner() { if (typeof this._stopScanner === 'function') this._stopScanner(); this._stopScanner = null },
|
||||
prototypeScan() { const value = String(this.scanValue || '').trim(); if (!value) return this.showToast('请先扫描或输入编码', 'warning'); playSuccessSound(); this.showToast(`已读取 ${value};业务接口待接入`, 'success') },
|
||||
showToast(message, type) { clearTimeout(this._toastTimer); this.toast = { visible: true, message, type }; this._toastTimer = setTimeout(() => { this.toast.visible = false }, 2200) }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<view v-if="user" class="page-shell portal-page"><PortalHeader title="个人中心" :user="user" :show-profile="false" /><view class="portal-content profile-content"><view class="profile-card"><view class="profile-avatar">{{ user.name.slice(0, 1) }}</view><view><text class="profile-name">{{ user.name }}</text><text class="profile-role">{{ user.role }} · {{ user.id }}</text></view></view><view class="profile-list"><view class="profile-row"><text>作业仓库</text><text class="profile-value">{{ user.warehouse || '登录后由海外仓服务分配' }}</text></view><view class="profile-row"><text>当前班次</text><text class="profile-value">以海外仓排班为准</text></view><view class="profile-row"><text>应用版本</text><text class="profile-value">0.1.0</text></view></view><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><view v-if="toast" class="app-toast warning" role="status">设置功能将在后续版本开放</view></view>
|
||||
</template>
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'; import PopupHeader from '@/components/PopupHeader.vue'; import { session, requireSession, signOut } from '@/stores/session.js'
|
||||
export default { components: { PopupHeader, PortalHeader }, data() { return { user: session.currentUser, logoutOpen: false, toast: false } }, onShow() { if (!requireSession()) return; this.user = session.currentUser }, beforeUnmount() { clearTimeout(this._toastTimer) }, onBackPress() { if (!this.logoutOpen) return false; this.closeLogout(); return true }, methods: { 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) }, logout() { signOut(); uni.reLaunch({ url: '/pages/login/login' }) } } }
|
||||
</script>
|
||||
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<view v-if="user" class="page-shell portal-page scanner-test-page">
|
||||
<PortalHeader title="广播扫码测试" :user="user" />
|
||||
<view class="scanner-test-content">
|
||||
<view class="scanner-status" :class="`scanner-status-${status}`" role="status">
|
||||
<view class="scanner-status-dot"></view>
|
||||
<view>
|
||||
<text class="scanner-status-title">{{ statusTitle }}</text>
|
||||
<text class="scanner-status-detail">{{ statusDetail }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scanner-result" :class="{ 'scanner-result-received': lastValue }">
|
||||
<text class="scanner-result-label">最近收到</text>
|
||||
<text class="scanner-result-value">{{ lastValue || '等待扫描' }}</text>
|
||||
<text class="scanner-result-meta">{{ lastValue ? `${lastTime} · 本页第 ${scanCount} 次` : '按下 PDA 硬件扫描键' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="scanner-config">
|
||||
<view class="scanner-config-row"><text class="scanner-config-label">Action</text><text class="scanner-config-value">{{ action }}</text></view>
|
||||
<view class="scanner-config-row"><text class="scanner-config-label">Extra 标签</text><text class="scanner-config-value">{{ extra }}</text></view>
|
||||
</view>
|
||||
|
||||
<view class="scanner-history-head">
|
||||
<text class="scanner-history-title">接收记录</text>
|
||||
<button class="scanner-clear" :disabled="!history.length" @tap="clearHistory">清空</button>
|
||||
</view>
|
||||
<view v-if="history.length" class="scanner-history">
|
||||
<view v-for="item in history" :key="item.id" class="scanner-history-item">
|
||||
<text class="scanner-history-index">{{ item.index }}</text>
|
||||
<view class="scanner-history-main"><text class="scanner-history-value">{{ item.value }}</text><text class="scanner-history-time">{{ item.time }}</text></view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="scanner-empty"><text>暂无广播数据</text></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'
|
||||
import { session, requireSession } from '@/stores/session.js'
|
||||
import { SCAN_BROADCAST_ACTION, SCAN_BROADCAST_EXTRA, startScanBroadcast } from '@/utils/scan-broadcast.js'
|
||||
|
||||
export default {
|
||||
components: { PortalHeader },
|
||||
data() {
|
||||
return {
|
||||
user: session.currentUser,
|
||||
action: SCAN_BROADCAST_ACTION,
|
||||
extra: SCAN_BROADCAST_EXTRA,
|
||||
status: 'waiting',
|
||||
lastValue: '',
|
||||
lastTime: '',
|
||||
scanCount: 0,
|
||||
history: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
statusTitle() {
|
||||
if (this.status === 'error') return '接收器启动失败'
|
||||
if (this.status === 'unsupported') return '当前环境不支持广播'
|
||||
return this.lastValue ? '已收到扫描广播' : '接收器已启动'
|
||||
},
|
||||
statusDetail() {
|
||||
if (this.status === 'error') return '请检查 PDA 扫描服务设置后重新进入页面'
|
||||
if (this.status === 'unsupported') return '请在 Android App 真机中测试'
|
||||
return this.lastValue ? '继续扫描可验证连续接收' : '正在等待硬件扫描结果'
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
if (!requireSession()) return
|
||||
this.user = session.currentUser
|
||||
this.startScanner()
|
||||
},
|
||||
onHide() { this.stopScanner() },
|
||||
onUnload() { this.stopScanner() },
|
||||
beforeUnmount() { this.stopScanner() },
|
||||
methods: {
|
||||
startScanner() {
|
||||
this.stopScanner()
|
||||
this.status = 'waiting'
|
||||
// #ifndef APP-PLUS
|
||||
this.status = 'unsupported'
|
||||
// #endif
|
||||
this._stopScanner = startScanBroadcast({
|
||||
onScan: (value) => this.recordScan(value),
|
||||
onError: () => { this.status = 'error' }
|
||||
})
|
||||
},
|
||||
stopScanner() {
|
||||
if (typeof this._stopScanner !== 'function') return
|
||||
this._stopScanner()
|
||||
this._stopScanner = null
|
||||
},
|
||||
recordScan(value) {
|
||||
const now = new Date()
|
||||
const time = [now.getHours(), now.getMinutes(), now.getSeconds()].map((part) => String(part).padStart(2, '0')).join(':')
|
||||
this.scanCount += 1
|
||||
this.lastValue = value
|
||||
this.lastTime = time
|
||||
this.status = 'received'
|
||||
this.history = [{ id: `${Date.now()}-${this.scanCount}`, index: this.scanCount, value, time }, ...this.history].slice(0, 20)
|
||||
},
|
||||
clearHistory() {
|
||||
this.lastValue = ''
|
||||
this.lastTime = ''
|
||||
this.scanCount = 0
|
||||
this.history = []
|
||||
this.status = 'waiting'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.scanner-test-content { padding: 16px 14px calc(24px + env(safe-area-inset-bottom)); }
|
||||
.scanner-status { display: flex; align-items: center; min-height: 64px; padding: 12px 14px; border-radius: 8px; color: #20405f; background: #e7f1ff; }
|
||||
.scanner-status-dot { width: 12px; height: 12px; margin-right: 12px; border-radius: 50%; background: #1769e8; }
|
||||
.scanner-status-title, .scanner-status-detail, .scanner-result-label, .scanner-result-value, .scanner-result-meta, .scanner-config-label, .scanner-config-value, .scanner-history-title, .scanner-history-value, .scanner-history-time { display: block; }
|
||||
.scanner-status-title { font-size: 15px; font-weight: 700; }
|
||||
.scanner-status-detail { margin-top: 3px; font-size: 12px; line-height: 18px; }
|
||||
.scanner-status-received { color: #145c38; background: #ddf5e8; }
|
||||
.scanner-status-received .scanner-status-dot { background: #168552; }
|
||||
.scanner-status-error { color: #912018; background: #fee7e5; }
|
||||
.scanner-status-error .scanner-status-dot { background: #d92d20; }
|
||||
.scanner-status-unsupported { color: #664d10; background: #fff1c7; }
|
||||
.scanner-status-unsupported .scanner-status-dot { background: #b7791f; }
|
||||
.scanner-result { min-height: 168px; margin-top: 14px; padding: 18px 16px; border: 2px dashed #aebdce; border-radius: 8px; background: #ffffff; }
|
||||
.scanner-result-received { border-style: solid; border-color: #168552; }
|
||||
.scanner-result-label { color: #63758a; font-size: 12px; font-weight: 700; }
|
||||
.scanner-result-value { margin-top: 26px; color: #27384d; font-size: 24px; font-weight: 800; line-height: 32px; overflow-wrap: anywhere; text-align: center; }
|
||||
.scanner-result-received .scanner-result-value { color: #11643c; }
|
||||
.scanner-result-meta { margin-top: 15px; color: #63758a; font-size: 12px; text-align: center; }
|
||||
.scanner-config { margin-top: 14px; border-radius: 8px; background: #ffffff; }
|
||||
.scanner-config-row { padding: 13px 14px; border-bottom: 1px solid #e4e9ef; }
|
||||
.scanner-config-row:last-child { border-bottom: 0; }
|
||||
.scanner-config-label { margin-bottom: 5px; color: #63758a; font-size: 11px; font-weight: 700; }
|
||||
.scanner-config-value { color: #27384d; font-size: 13px; line-height: 19px; overflow-wrap: anywhere; }
|
||||
.scanner-history-head { display: flex; align-items: center; justify-content: space-between; margin-top: 22px; }
|
||||
.scanner-history-title { font-size: 16px; font-weight: 800; }
|
||||
.scanner-clear { width: 64px; height: 48px; margin: 0; padding: 0; color: #1769e8; font-size: 13px; line-height: 48px; background: transparent; }
|
||||
.scanner-clear[disabled] { color: #9ba8b7; }
|
||||
.scanner-history { margin-top: 8px; border-radius: 8px; background: #ffffff; }
|
||||
.scanner-history-item { display: flex; align-items: center; min-height: 62px; padding: 9px 13px; border-bottom: 1px solid #e4e9ef; }
|
||||
.scanner-history-item:last-child { border-bottom: 0; }
|
||||
.scanner-history-index { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin-right: 11px; border-radius: 50%; color: #ffffff; font-size: 12px; font-weight: 700; background: #1769e8; }
|
||||
.scanner-history-main { min-width: 0; flex: 1; }
|
||||
.scanner-history-value { color: #27384d; font-size: 15px; font-weight: 700; overflow-wrap: anywhere; }
|
||||
.scanner-history-time { margin-top: 3px; color: #718095; font-size: 11px; }
|
||||
.scanner-empty { display: flex; align-items: center; justify-content: center; height: 96px; margin-top: 8px; border-radius: 8px; color: #718095; font-size: 13px; background: #ffffff; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user