master
denghaohaoya 2026-03-27 00:18:36 +08:00
parent 51aebf505e
commit ead30c3479
8 changed files with 818 additions and 26 deletions

11
api/translation.js Normal file
View File

@ -0,0 +1,11 @@
import request from '@/utils/request'
// 根据用户ID查询门店列表
export function PostData(data) {
return request({
baseUrl: 'http://193.112.94.36:8081',
url: `/mall/product/getByBarcodes`,
method: 'post',
data:data
})
}

View File

@ -1,6 +1,6 @@
{
"name" : "海驰24",
"appid" : "__UNI__B012241",
"appid" : "__UNI__7302921",
"description" : "111",
"versionName" : "1.2.0",
"versionCode" : "100",

View File

@ -28,6 +28,12 @@
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/translation/translation",
"style": {
"navigationBarTitleText": "录入清单"
}
}
],
"subPackages": [

View File

@ -177,7 +177,7 @@
<view class="form-item" v-if="productInfo.expirationManagement">
<text class="item-label">临期提醒天数</text>
<view class="warning-days-display">
<text class="warning-days-value">{{ warningDaysDisplay }}</text>
<text class="warning-days-value">{{ productInfo.shelfLife }}</text>
<text class="warning-days-unit"></text>
</view>
</view>
@ -222,11 +222,37 @@
<button class="save-button" @tap="handleSave"></button>
</view>
</view>
<!-- 微信小程序全屏扫码覆盖层 -->
<!-- #ifdef MP-WEIXIN -->
<view v-if="showScanner" class="scanner-overlay">
<camera
class="scanner-camera"
mode="scanCode"
device-position="back"
flash="off"
@scancode="onOverlayScanResult"
>
<cover-view class="scanner-mask">
<cover-view class="scanner-box">
<cover-view class="box-corner tl"></cover-view>
<cover-view class="box-corner tr"></cover-view>
<cover-view class="box-corner bl"></cover-view>
<cover-view class="box-corner br"></cover-view>
</cover-view>
<cover-view class="scanner-actions">
<cover-view class="scanner-btn" @tap="closeScanner"></cover-view>
</cover-view>
</cover-view>
</camera>
</view>
<!-- #endif -->
</template>
<script>
import { addProductWithFile } from '@/api/product'
import { getStoreId } from '@/utils/auth'
import apiUrl from '@/utils/api'
export default {
data() {
@ -240,11 +266,14 @@ export default {
cost: '',
expirationManagement: false,
shelfCode: '',
shelfLife:'',
productCode: '',
expirationDays: '',
warningDays: '',
productionDate: ''
}
productionDate: '',
url:''
},
showScanner: false
}
},
computed: {
@ -265,31 +294,85 @@ export default {
}
},
onLoad(options) {
console.log('页面参数:', options);
console.log('页面参数:', options,apiUrl);
this.url = apiUrl
//
if (options && options.fromData) {
try {
this.productInfo.barcode = options.barcode
const fromData = JSON.parse(options.fromData)[0];
this.productInfo.name = fromData.productName || '';
this.productInfo.cost = fromData.costPrice || '';
this.productInfo.barcode = fromData.productBarCode || '';
this.productInfo.price = fromData.storePrice || '';
this.productInfo.quantity = fromData.stockQuantity || '';
this.productInfo.productCode = fromData.productCode || '';
this.productInfo.image = this.url + fromData.mainImage || '';
this.productInfo.shelfCode = fromData.shelfCode || '';
this.productInfo.expirationManagement = fromData.shelfLife?true:false;
if(fromData.shelfLife){
console.log(fromData.productionDate);
this.productInfo.productionDate = fromData.productionDate || '2026-12-19'
this.productInfo.shelfLife = fromData.shelfLife;
}
console.log(this.productInfo);
} catch (e) {
this.productInfo.barcode = options.barcode
}
}
if (options.fromData) {
try {
const fromData = JSON.parse(decodeURIComponent(options.fromData));
console.log('接收到的商品数据:', fromData);
this.productInfo.name = fromData.productName || '';
this.productInfo.barcode = fromData.productBarCode || '';
this.productInfo.price = fromData.storePrice || '';
this.productInfo.quantity = fromData.stockQuantity || '';
this.productInfo.productCode = fromData.productCode || '';
this.productInfo.image = fromData.mainImage || '';
} catch (error) {
console.error('解析商品数据失败:', error);
}
}
},
methods: {
//
handleScan() {
uni.showToast({ title: '扫码功能(模拟)', icon: 'none' })
setTimeout(() => {
this.productInfo.barcode = '6921168558032'
// #ifdef MP-WEIXIN
this.showScanner = true
// #endif
// #ifndef MP-WEIXIN
uni.scanCode({
onlyFromCamera: true,
scanType: ['barCode'],
success: (res) => {
const code = (res.result || '').trim()
const type = (res.scanType || res.codeType || '').toString().toUpperCase()
const isBarcode = type.indexOf('QR') === -1
const numericOk = /^\d{8,20}$/.test(code)
if (isBarcode || numericOk) {
this.productInfo.barcode = code
uni.showToast({ title: '扫码成功', icon: 'success' })
} else {
uni.showToast({ title: '请扫条形码', icon: 'none' })
}
},
fail: () => {
uni.showToast({ title: '扫码失败', icon: 'none' })
}
})
// #endif
},
closeScanner() {
this.showScanner = false
},
onOverlayScanResult(e) {
if (!this.showScanner) return
const { result, scanType } = e.detail || {}
const code = (result || '').trim()
const type = (scanType || '').toString().toUpperCase()
const isBarcode = type.indexOf('QR') === -1
const numericOk = /^\d{8,20}$/.test(code)
if (isBarcode || numericOk) {
this.productInfo.barcode = code
this.showScanner = false
uni.showToast({ title: '扫码成功', icon: 'success' })
}, 500)
} else {
uni.showToast({ title: '请扫条形码', icon: 'none' })
}
},
//
@ -329,7 +412,7 @@ export default {
if (!this.productInfo.price) { uni.showToast({ title: '请输入售价', icon: 'none' });return false }
//
if (this.productInfo.expirationManagement) {
if (!this.productInfo.expirationDays) { uni.showToast({ title: '请选择保质期天数', icon: 'none' });return false }
if (!this.productInfo.shelfLife) { uni.showToast({ title: '请选择保质期天数', icon: 'none' });return false }
//
if (!this.productInfo.productionDate) { uni.showToast({ title: '请选择生产日期', icon: 'none' });return false }
}
@ -349,7 +432,7 @@ export default {
productBarCode: this.productInfo.barcode,
storePrice: this.productInfo.price,
stockQuantity: this.productInfo.quantity,
costPrice: this.productInfo.cost,
costPrice: this.productInfo.costPrice,
productCode: this.productInfo.productCode,
shelfCode: this.productInfo.shelfCode,
expirationManagement: this.productInfo.expirationManagement ? 1 : 0,
@ -463,4 +546,50 @@ export default {
.recommend-list { flex-direction:column; }
.recommend-item { margin:10rpx 0; }
}
/* 微信小程序全屏扫码覆盖层样式 */
.scanner-overlay {
position: fixed;
left: 0; right: 0; top: 0; bottom: 0;
background: #000;
z-index: 9999;
}
.scanner-camera {
width: 100%;
height: 100%;
}
.scanner-mask {
position: absolute;
left: 0; top: 0; right: 0; bottom: 0;
}
.scanner-box {
position: fixed;
left: 50%;
top: 50%;
width: 520rpx;
height: 520rpx;
transform: translate(-50%, -50%);
}
.box-corner {
position: absolute;
width: 40rpx;
height: 40rpx;
border: 4rpx solid #fff;
}
.box-corner.tl { left: 0; top: 0; border-right: none; border-bottom: none; }
.box-corner.tr { right: 0; top: 0; border-left: none; border-bottom: none; }
.box-corner.bl { left: 0; bottom: 0; border-right: none; border-top: none; }
.box-corner.br { right: 0; bottom: 0; border-left: none; border-top: none; }
.scanner-actions {
position: absolute;
left: 0; right: 0; bottom: 80rpx;
display: flex; justify-content: center;
}
.scanner-btn {
padding: 20rpx 40rpx;
color: #fff;
border: 2rpx solid rgba(255,255,255,0.6);
border-radius: 40rpx;
background: rgba(0,0,0,0.35);
}
</style>

View File

@ -3,7 +3,7 @@
<view class="one">
<view class="barsOne" @click="showDrawer('showLeft')" ><uni-icons type="bars" size="30" class="barsIcons"></uni-icons></view>
<view class="scanOne"><uni-icons type="scan" size="30" class="scanIcons"></uni-icons></view>
<view class="scanOne" @click="codeData"><uni-icons type="scan" size="30" class="scanIcons"></uni-icons></view>
<view class="gearOne" @click="goSetting"><uni-icons type="gear" size="30" class="gearIcons"></uni-icons></view>
</view>
@ -308,6 +308,13 @@ export default {
}
},
methods: {
//
codeData(){
uni.showToast({
title: `扫码`,
icon: 'none'
})
},
//
selectShop(type) {
this.selectedShop = type;

View File

@ -124,7 +124,7 @@
<view class="goods-info">
<text class="goods-name">{{ item.productName }}</text>
<text class="goods-barcode">{{ item.productBarCode }}</text>
<text class="goods-price">{{ item.storePrice ? item.storePrice.toFixed(2) : '0.00' }}</text>
<text class="goods-price">{{ item.storePrice ? (item.storePrice * 1).toFixed(2) : '0.00' }}</text>
</view>
</view>
<view class="goods-divider"></view>
@ -402,10 +402,10 @@
},
addNewGoods() {
uni.navigateTo({
url: '/pages/addProduct/addProduct'
// url: '/pages/enter/enter'
});
uni.navigateTo({
url: '/pages/translation/translation'
})
},
batchOperation() {

View File

@ -0,0 +1,636 @@
<template>
<!-- 扫码页面整体容器 -->
<view class="scan-page">
<!-- 顶部扫描卡片摄像头预览 + 叠加提示 + 操作按钮 -->
<view class="scan-card" :class="{ zoomed: zoomed }">
<!-- App(真机打包)使用 HTML5+ 原生条码识别视图嵌入在当前 card 区域 -->
<!-- #ifdef APP-PLUS -->
<view class="camera-host"><!-- 仅用于测量与承载原生扫码视图 --></view>
<!-- #endif -->
<!-- 微信小程序使用 camera 组件的扫码模式进行连续识别 -->
<!-- #ifdef MP-WEIXIN -->
<camera
class="camera-view"
mode="scanCode"
device-position="back"
flash="off"
@scancode="onScanResult"
>
<!-- 双击捕获层用于切换放大/缩小视角 -->
<cover-view class="wx-tap-capture" @tap="onTapArea"></cover-view>
<cover-view class="wx-overlay">
<cover-view class="wx-overlay-tips">对准商品条码自动识别</cover-view>
<cover-view class="wx-corners">
<cover-view class="wx-corner tl"></cover-view>
<cover-view class="wx-corner tr"></cover-view>
<cover-view class="wx-corner bl"></cover-view>
<cover-view class="wx-corner br"></cover-view>
</cover-view>
<cover-view class="wx-controls">
<cover-view class="wx-btn" @tap="toggleTorch">
<cover-view>{{ flashOn ? '关闭手电' : '开启手电' }}</cover-view>
</cover-view>
<cover-view class="wx-btn" @tap="togglePause">
<cover-view>{{ paused ? '继续扫码' : '暂停扫码' }}</cover-view>
</cover-view>
</cover-view>
</cover-view>
</camera>
<!-- #endif -->
<!-- 其它平台回退提示下方按钮触发系统扫码 -->
<!-- #ifndef APP-PLUS || MP-WEIXIN -->
<view class="camera-fallback">
<text class="fallback-text">当前平台不支持内嵌连续扫码请使用下方按钮进行扫码</text>
</view>
<!-- #endif -->
<!-- 叠加层提示文案四角描边控制按钮- App/微信小程序平台 -->
<!-- #ifndef APP-PLUS || MP-WEIXIN -->
<view class="tap-capture" @tap="onTapArea"></view>
<view class="overlay">
<text class="overlay-tips">对准商品条码自动识别</text>
<view class="corners">
<view class="corner tl"></view>
<view class="corner tr"></view>
<view class="corner bl"></view>
<view class="corner br"></view>
</view>
<view class="controls">
<view class="control-btn" @tap="toggleTorch">
<text>{{ flashOn ? '关闭手电' : '开启手电' }}</text>
</view>
<view class="control-btn" @tap="togglePause">
<text>{{ paused ? '继续扫码' : '暂停扫码' }}</text>
</view>
</view>
</view>
<!-- #endif -->
</view>
<!-- App 平台将控制按钮放在扫描卡片下方避免被原生视图覆盖 -->
<!-- #ifdef APP-PLUS -->
<view class="controls controls-bar">
<view class="control-btn" @tap="toggleTorch">
<text>{{ flashOn ? '关闭手电' : '开启手电' }}</text>
</view>
<view class="control-btn" @tap="togglePause">
<text>{{ paused ? '继续扫码' : '暂停扫码' }}</text>
</view>
</view>
<!-- #endif -->
<!-- 下方内容卡片占位样式与截图一致 -->
<view class="empty-card">
<view class="empty-icon"></view>
<text class="empty-title">暂未录入商品</text>
<view class="empty-tip">
<text>请在上方选择商品录入方式</text>
</view>
</view>
<!-- 回退平台的操作按钮调用系统扫码 -->
<!-- #ifndef APP-PLUS || MP-WEIXIN -->
<view class="h5-actions">
<button type="primary" class="scan-btn" @tap="triggerSystemScan"></button>
</view>
<!-- #endif -->
</view>
</template>
<script>
import { PostData } from '@/api/translation.js'
import { getStoreId } from '@/utils/auth'
/*
页面功能说明
1支持条形码与二维码识别
2支持打开/关闭手电筒闪光灯
3支持暂停/继续扫码
4根据平台差异选择实现
- AppAPP-PLUS使用 HTML5+ plus.barcode 原生视图连续识别并可控闪光灯
- 微信小程序MP-WEIXIN使用 camera 组件的 scanCode 模式事件回调处理结果并通过 CameraContext 控制闪光灯
- 其它平台 H5使用 uni.scanCode 作为回退方案不嵌入连续预览
*/
export default {
data() {
return {
storeId:null,
//
paused: false,
//
flashOn: false,
// /
zoomed: false,
//
lastTapTime: 0,
//
lastResult: '',
//
lastScanValue: '',
lastScanAt: 0,
// App
barcodeView: null,
//
cameraCtx: null,
//
rescanTimer: null
}
},
onReady() {
//
// #ifdef APP-PLUS
this.initAppScanner()
// #endif
// #ifdef MP-WEIXIN
this.initMpScanner()
// #endif
},
onUnload() {
//
// #ifdef APP-PLUS
this.destroyAppScanner()
// #endif
},
onLoad() {
this.storeId = getStoreId()
},
methods: {
/* ========== 通用:处理识别结果 ========== */
async handleScanResult(type, result) {
//
if (this.paused) return
this.lastResult = typeof result === 'string' ? result.trim() : String(result || '')
// 1200ms
const now = Date.now()
if (this.lastScanValue === this.lastResult && (now - this.lastScanAt) < 1200) {
return
}
this.lastScanValue = this.lastResult
this.lastScanAt = now
//
if (this.isQRType(type)) {
uni.showToast({ title: '请扫条形码', icon: 'none' })
this.rescanAfter(1200)
return
}
//
if (!this.isValidBarcode(this.lastResult)) {
uni.showToast({ title: '请扫条形码', icon: 'none' })
this.rescanAfter(1200)
return
}
//
this.setTorch(false)
let query = {
"barcodes": [this.lastResult],
"storeId":this.storeId
}
let data = '';
PostData(query).then(res=>{
if(res.code == 200){
data = res.data;
uni.navigateTo({
url: `/pages/addProduct/addProduct?barcode=${this.lastResult}&fromData=${JSON.stringify(data)}`
})
}
else{
uni.showToast({ title: res.msg, icon: 'none' })
}
})
},
//
isQRType(t) {
// App 使 plus.barcode
// #ifdef APP-PLUS
if (typeof t === 'number') {
return t === plus.barcode.QR
}
// #endif
// /H5 QR
if (typeof t === 'string') {
return t.toUpperCase().indexOf('QR') !== -1
}
return false
},
// 8-20
isValidBarcode(code) {
return /^\d{8,20}$/.test(code || '')
},
// /
onTapArea() {
// App 使
// #ifdef APP-PLUS
return
// #endif
const now = Date.now()
if (now - this.lastTapTime <= 300) {
this.zoomed = !this.zoomed
this.lastTapTime = 0
} else {
this.lastTapTime = now
}
},
//
rescanAfter(delay = 800) {
if (this.rescanTimer) {
clearTimeout(this.rescanTimer)
this.rescanTimer = null
}
this.rescanTimer = setTimeout(() => {
// #ifdef APP-PLUS
if (this.barcodeView) {
try {
this.barcodeView.cancel && this.barcodeView.cancel()
this.barcodeView.start && this.barcodeView.start()
} catch (e) {}
}
// #endif
// #ifdef MP-WEIXIN
// camera scanCode
// #endif
// #ifndef APP-PLUS || MP-WEIXIN
this.triggerSystemScan()
// #endif
this.rescanTimer = null
}, delay)
},
/* ========== 控制:手电筒开关 ========== */
toggleTorch() {
this.setTorch(!this.flashOn)
},
//
setTorch(isOn) {
this.flashOn = !!isOn
// App
// #ifdef APP-PLUS
if (this.barcodeView && typeof this.barcodeView.setFlash === 'function') {
this.barcodeView.setFlash(this.flashOn)
}
// #endif
//
// #ifdef MP-WEIXIN
if (this.cameraCtx && typeof this.cameraCtx.setTorch === 'function') {
this.cameraCtx.setTorch({ isTorchOn: this.flashOn })
}
// #endif
//
// #ifndef APP-PLUS || MP-WEIXIN
if (isOn) {
uni.showToast({ title: '当前平台不支持手电筒', icon: 'none' })
}
// #endif
},
/* ========== 控制:暂停/继续扫码 ========== */
togglePause() {
this.paused = !this.paused
// App cancel()/start()
// #ifdef APP-PLUS
if (this.barcodeView) {
if (this.paused) {
this.barcodeView.cancel && this.barcodeView.cancel()
} else {
this.barcodeView.start && this.barcodeView.start()
}
}
// #endif
// paused
//
},
/* ========== H5/其它:系统扫码回退 ========== */
async triggerSystemScan() {
let query = {
"barcodes": ['6901028064835'],
"storeId":'2'
}
PostData(query).then(res=>{
if(res.code == 200){
let data = res.data;
uni.navigateTo({
url: `/pages/addProduct/addProduct?barcode=6901028064835&fromData=${JSON.stringify(data)}`
})
}
else{
uni.showToast({ title: res.msg, icon: 'none' })
}
})
// 使
uni.scanCode({
onlyFromCamera: true,
success: (res) => {
// res.result
this.handleScanResult(res.scanType || 'UNKNOWN', res.result)
},
fail: () => {
uni.showToast({ title: '扫码失败', icon: 'none' })
}
})
},
/* ========== 微信小程序:初始化摄像头上下文 ========== */
// camera
onScanResult(e) {
// e.detail { result, scanType, charSet, rawData }
const { result, scanType } = e.detail || {}
this.handleScanResult(scanType || 'WEAPP', result || '')
},
initMpScanner() {
//
try {
this.cameraCtx = uni.createCameraContext()
} catch (err) {
this.cameraCtx = null
}
},
/* ========== App创建原生条码识别视图 ========== */
initAppScanner() {
// Barcode
this.$nextTick(() => {
uni.createSelectorQuery()
.in(this)
.select('.scan-card')
.boundingClientRect((rect) => {
if (!rect) return
// Webview
const webview = this.$scope && this.$scope.$getAppWebview
? this.$scope.$getAppWebview()
: (this.$mp && this.$mp.page && this.$mp.page.$getAppWebview
? this.$mp.page.$getAppWebview()
: null)
if (!webview) return
//
const types = [
plus.barcode.QR,
plus.barcode.EAN13,
plus.barcode.EAN8,
plus.barcode.UPCA,
plus.barcode.UPCE,
plus.barcode.CODE128,
plus.barcode.CODE39,
plus.barcode.ITF,
plus.barcode.PDF417,
plus.barcode.DATAMATRIX
]
const styles = {
top: rect.top + 'px',
left: rect.left + 'px',
width: rect.width + 'px',
height: rect.height + 'px'
}
const barcode = plus.barcode.create('scan-barcode', types, {
frameColor: '#FFFFFF',
scanbarColor: '#FFFFFF'
})
barcode.setStyle(styles)
//
webview.append(barcode)
//
barcode.onmarked = (type, result) => {
this.handleScanResult(type, result)
}
//
barcode.start()
this.barcodeView = barcode
})
.exec()
})
},
destroyAppScanner() {
//
if (this.barcodeView && typeof this.barcodeView.close === 'function') {
try {
this.barcodeView.close()
} catch (e) {}
this.barcodeView = null
}
}
}
}
</script>
<style scoped lang="scss">
/* 页面背景与基本布局 */
.scan-page {
background-color: #f5f5f5;
min-height: 100vh;
padding: 12px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 12px;
}
/* 顶部扫描卡片 */
.scan-card {
position: relative;
background: #000;
border-radius: 12px;
overflow: hidden;
height: 240px;
transition: transform 0.2s ease;
}
.scan-card.zoomed {
transform: scale(1.2);
}
.camera-host {
width: 100%;
height: 100%;
}
.camera-view {
width: 100%;
height: 100%;
}
/* 微信小程序覆盖层(使用 cover-view */
/* 双击捕获层(非小程序使用 view微信小程序使用 cover-view */
.tap-capture {
position: absolute;
left: 0; top: 0; right: 0; bottom: 0;
z-index: 2;
background: transparent;
}
.wx-tap-capture {
position: absolute;
left: 0; top: 0; right: 0; bottom: 0;
}
.wx-overlay {
position: absolute;
left: 0;
top: 0;
right: 0;
right: 0;
bottom: 0;
}
.wx-overlay-tips {
position: absolute;
left: 50%;
top: 10px;
transform: translateX(-50%);
color: #fff;
background: rgba(0,0,0,0.35);
padding: 6px 12px;
border-radius: 18px;
font-size: 12px;
}
.wx-corners .wx-corner {
position: absolute;
width: 22px;
height: 22px;
border: 2px solid #fff;
}
.wx-corners .tl { left: 10px; top: 10px; border-right: none; border-bottom: none; }
.wx-corners .tr { right: 10px; top: 10px; border-left: none; border-bottom: none; }
.wx-corners .bl { left: 10px; bottom: 10px; border-right: none; border-top: none; }
.wx-corners .br { right: 10px; bottom: 10px; border-left: none; border-top: none; }
.wx-controls {
position: absolute;
left: 0;
right: 0;
bottom: 10px;
display: flex;
justify-content: center;
gap: 28px;
}
.wx-btn {
min-width: 96px;
height: 36px;
padding: 0 14px;
border-radius: 18px;
background: rgba(0,0,0,0.45);
border: 1px solid rgba(255,255,255,0.35);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 14px;
}
.camera-fallback {
width: 100%;
height: 100%;
background: #222;
display: flex;
align-items: center;
justify-content: center;
}
.fallback-text {
color: #bbb;
font-size: 14px;
}
/* 叠加层(提示 + 四角 + 控制按钮) */
.overlay {
pointer-events: none; /* 使叠加层不阻挡相机事件,按钮区域再单独打开事件 */
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.overlay-tips {
position: absolute;
left: 50%;
top: 10px;
transform: translateX(-50%);
color: #fff;
background: rgba(0,0,0,0.35);
padding: 6px 12px;
border-radius: 18px;
font-size: 12px;
}
.corners .corner {
position: absolute;
width: 22px;
height: 22px;
border: 2px solid #fff;
}
.corners .tl { left: 10px; top: 10px; border-right: none; border-bottom: none; }
.corners .tr { right: 10px; top: 10px; border-left: none; border-bottom: none; }
.corners .bl { left: 10px; bottom: 10px; border-right: none; border-top: none; }
.corners .br { right: 10px; bottom: 10px; border-left: none; border-top: none; }
.controls {
pointer-events: auto; /* 允许点击按钮 */
position: absolute;
left: 0;
right: 0;
bottom: 10px;
display: flex;
justify-content: center;
gap: 28px;
}
.control-btn {
min-width: 96px;
height: 36px;
padding: 0 14px;
border-radius: 18px;
background: rgba(0,0,0,0.45);
border: 1px solid rgba(255,255,255,0.35);
display: flex;
align-items: center;
justify-content: center;
}
.control-btn text {
color: #fff;
font-size: 14px;
}
/* App 平台下方控制条 */
.controls-bar {
margin-top: 8px;
position: relative;
display: flex;
justify-content: center;
gap: 28px;
}
/* 下方内容卡片 */
.empty-card {
background: #fff;
border-radius: 12px;
padding: 24px 16px 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.empty-icon {
width: 60px;
height: 60px;
border-radius: 30px;
background: #ffecec;
}
.empty-title {
color: #333;
font-size: 16px;
}
.empty-tip {
margin-top: 4px;
background: #f7f7f7;
padding: 8px 12px;
border-radius: 18px;
}
.empty-tip text {
color: #888;
font-size: 12px;
}
/* H5 回退按钮 */
.h5-actions {
display: flex;
justify-content: center;
}
.scan-btn {
width: 200px;
border-radius: 24px;
}
</style>

3
utils/api.js Normal file
View File

@ -0,0 +1,3 @@
const apiUrl = 'http://193.112.94.36:8081'
export default apiUrl