<template>
|
<view class="order-detail-container">
|
<!-- 顶部订单信息 -->
|
<view class="order-header">
|
<view class="order-info">
|
<text class="info-label">订单编号:</text>
|
<text class="info-value">{{orderInfo.orderNo}}</text>
|
</view>
|
<view class="order-info">
|
<text class="info-label">创建时间:</text>
|
<text class="info-value">{{formatDisplayDate(orderInfo.createTime)}}</text>
|
</view>
|
</view>
|
|
<!-- 物料Tabs -->
|
<view class="material-tabs">
|
<scroll-view scroll-x class="tabs-scroll">
|
<view class="tabs-container">
|
<!-- 只显示前3个Tab -->
|
<view v-for="(tab, index) in tabs.slice(0, 3)" :key="index" class="tab-item"
|
:class="{'active': activeTab === index}" @click="switchTab(index)">
|
<text>{{tab.name}}</text>
|
</view>
|
|
<!-- 下拉按钮 -->
|
<view class="dropdown-btn" :class="{'active': activeTab >= 3}" v-if="tabs.length > 3"
|
@click="toggleCollapse">
|
<text>{{activeTab >= 3 ? tabs[activeTab].name : '更多'}}</text>
|
<uni-icons :type="isCollapsed ? 'arrowdown' : 'arrowup'" size="16"></uni-icons>
|
</view>
|
</view>
|
</scroll-view>
|
|
<!-- 下拉菜单 -->
|
<view class="dropdown-menu" v-if="!isCollapsed && tabs.length > 3">
|
<view v-for="(tab, index) in tabs.slice(3)" :key="index + 3" class="dropdown-item"
|
:class="{'active': activeTab === index + 3}" @click="switchTab(index + 3)">
|
<text>{{tab.name}}</text>
|
</view>
|
</view>
|
</view>
|
|
<!-- Tab内容区 -->
|
<view class="tab-content">
|
<!-- 扫码输入框 -->
|
<view class="scan-section">
|
<uni-easyinput v-model="scanInput" placeholder="请扫描二维码" @confirm="handleScanInput" :focus="focus"
|
clearable></uni-easyinput>
|
</view>
|
|
<!-- 扫描记录 -->
|
<view class="scan-records">
|
<view class="section-title">
|
<text>扫描记录</text>
|
<text class="record-count">({{currentRecords.length}})</text>
|
</view>
|
|
<scroll-view scroll-y class="record-list">
|
<view v-for="(record, index) in currentRecords" :key="index" class="record-item">
|
<view class="record-header">
|
<text class="record-time">扫描时间: {{ formatDisplayDate(record.scan_time)}}</text>
|
<text class="record-index">序号: {{currentRecords.length - index}}</text>
|
</view>
|
<view class="record-calibration">标定信息: {{record.reference_content}}</view>
|
<view class="record-status" :class="{'error': !record.is_matched}">
|
{{record.is_matched ? '✓' : '✗'}}
|
</view>
|
</view>
|
</scroll-view>
|
</view>
|
</view>
|
|
<!-- 首次扫描弹窗 -->
|
<uni-popup ref="firstScanPopup" type="dialog">
|
<view class="scan-popup">
|
<view class="popup-header">
|
<text>{{confirmHiden?'请选择核对标准':'请查看核对标准'}}</text>
|
</view>
|
<view class="popup-content">
|
<view class="scan-textarea">
|
<view class="text-line">
|
<view v-for="(char, index) in formattedText" :key="index" class="text-char"
|
:class="{'selected': selectedSegments.includes(index)}"
|
@click="confirmHiden?toggleSegment(index):()=>{}">
|
{{char}}
|
</view>
|
</view>
|
</view>
|
<view class="selection-info">
|
<text>已选择:</text>
|
<block v-if="getSelectedSegments().length > 0">
|
<text v-for="(segment, idx) in getSelectedSegments()" :key="idx">
|
{{segment.text}}
|
<text v-if="idx < getSelectedSegments().length - 1">|</text>
|
</text>
|
</block>
|
<text v-else>无</text>
|
</view>
|
</view>
|
<view class="popup-footer">
|
<button class="confirm-btn" v-show="confirmHiden" @click="confirmSelection">确认</button>
|
</view>
|
</view>
|
</uni-popup>
|
|
<!-- 错误提示弹窗 -->
|
<uni-popup ref="errorPopup" type="dialog">
|
<view class="error-popup">
|
<view class="popup-header">
|
<text>扫描错误</text>
|
</view>
|
<view class="popup-content">
|
<text>当前扫描结果不符合核对标准</text>
|
</view>
|
<view class="popup-footer">
|
<button class="confirm-btn" @click="closeErrorPopup">确定</button>
|
</view>
|
</view>
|
</uni-popup>
|
|
<!-- 在template中添加侧边弹窗 -->
|
<uni-popup ref="sideActionPopup" type="right">
|
<view class="side-action-popup">
|
<view class="popup-header">
|
<text>订单操作</text>
|
<uni-icons type="close" size="24" @click="hideSideActionPopup"></uni-icons>
|
</view>
|
|
<view class="side-action-content">
|
<view class="action-item" @click="viewCalibration">
|
<uni-icons type="eye" size="24" color="#2979ff"></uni-icons>
|
<text>查看当前标定内容</text>
|
</view>
|
|
<!-- <view class="action-item" @click="">
|
<uni-icons type="settings-filled" size="24" color="#2979ff"></uni-icons>
|
<text>屏蔽软件盘</text>
|
</view> -->
|
|
<view class="action-item logout" @click="endOrder">
|
<uni-icons type="poweroff" size="24" color="#f56c6c"></uni-icons>
|
<text>结束单据</text>
|
</view>
|
</view>
|
</view>
|
</uni-popup>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
orderInfo: {
|
orderNo: "",
|
createTime: ""
|
},
|
tabs: [], // 物料Tabs
|
activeTab: 0,
|
scanRecords: {}, // 各物料的扫描记录 {物料ID: [记录数组]}
|
verificationData: {}, // 各物料的验证数据 {物料ID: [验证文本数组]}
|
scanResult: "", // 当前扫描结果
|
scanInput: "", // 扫码输入
|
textSegments: [], // 文本分段
|
selectedSegments: [], // 选中的文本段
|
isFirstScan: {}, // 记录各物料是否是首次扫描
|
isCollapsed: true, // 是否折叠多余Tabs
|
selectedText: "", // 选中的文本内容
|
tempScanInput: '',
|
currentRecords: [],
|
focus: true,
|
confirmHiden: true
|
};
|
},
|
// 添加导航栏按钮点击处理
|
onNavigationBarButtonTap() {
|
this.$refs.sideActionPopup.open();
|
},
|
computed: {
|
// 格式化文本为行和单词的二维数组
|
formattedText() {
|
// 直接返回字符数组
|
return this.textSegments || [];
|
}
|
},
|
onLoad(options) {
|
try {
|
// 接收订单信息
|
if (options.orderNo && options.createTime) {
|
this.orderInfo = {
|
orderNo: options.orderNo,
|
createTime: options.createTime
|
};
|
}
|
|
// 接收物料列表
|
if (options.materials) {
|
const materials = JSON.parse(decodeURIComponent(options.materials));
|
this.tabs = materials.map(m => ({
|
id: m.id,
|
name: m.name
|
}));
|
//#ifdef APP-PLUS
|
// 初始化扫描状态
|
this.tabs.forEach(tab => {
|
const scanrecordService = require('@/services/scanrecordService').default
|
scanrecordService.getScanRecords(this.orderInfo.orderNo, tab.name).then(res => {
|
|
this.scanRecords[tab.name] = res.length > 0 ? res : [];
|
this.isFirstScan[tab.name] = res.length > 0 ? false : true;
|
|
const materialId = this.tabs[this.activeTab]?.name;
|
this.currentRecords = materialId ? this.scanRecords[materialId] || [] : [];
|
});
|
|
const materialContentService = require('@/services/materialContentService').default
|
materialContentService.getMaterialContent(this.orderInfo.orderNo, tab.name).then(res => {
|
this.verificationData[tab.name] = [];
|
for (var index = 0; index < res.length; index++) {
|
var element = res[index];
|
const text = element.reference_content.split('@#@');
|
this.verificationData[tab.name].push(text);
|
}
|
});
|
});
|
//#endif
|
}
|
} catch (e) {
|
console.error('detail.onload', e)
|
}
|
|
},
|
methods: {
|
formatDisplayDate(dateString) {
|
if (!dateString) return ''
|
const date = new Date(dateString)
|
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
},
|
|
// 显示侧边弹窗
|
showSideActionPopup() {
|
this.$refs.sideActionPopup.open();
|
},
|
|
// 隐藏侧边弹窗
|
hideSideActionPopup() {
|
this.$refs.sideActionPopup.close();
|
},
|
|
// 查看标定内容
|
async viewCalibration() {
|
this.confirmHiden = false;
|
const materialId = this.tabs[this.activeTab]?.name;
|
this.selectedSegments = [];
|
this.textSegments = [];
|
const materialContentService = require('@/services/materialContentService').default
|
const matContent = await materialContentService.getAMaterialContent(this.orderInfo.orderNo,
|
materialId);
|
if (matContent.length > 0) {
|
const contentIndexes = matContent[0].reference_content_index.split("@#@");
|
let contentIndex = [];
|
if (contentIndexes.length > 1) {
|
for (var index = 0; index < contentIndexes.length - 1; index++) {
|
if (index === 0) {
|
let arr1 = JSON.parse(contentIndexes[index])
|
let arr2 = JSON.parse(contentIndexes[index + 1])
|
contentIndex = arr1.concat(arr2);
|
} else {
|
let arr2 = Array.from(contentIndexes[index + 1])
|
contentIndex = contentIndex.concat(arr2);
|
}
|
}
|
} else {
|
contentIndex = JSON.parse(contentIndexes[0])
|
}
|
|
this.textSegments = Array.from(matContent[0].original_content);
|
this.selectedSegments = contentIndex;
|
|
this.$refs.firstScanPopup.open();
|
|
this.hideSideActionPopup();
|
} else {
|
uni.showToast({
|
title: '暂未标定内容',
|
icon: 'error'
|
})
|
}
|
},
|
|
// 结束单据
|
async endOrder() {
|
this.hideSideActionPopup();
|
uni.showModal({
|
title: "提示",
|
content: "确定要结束当前单据吗?",
|
success: async res => {
|
if (res.confirm) {
|
|
const orderService = require('@/services/orderService').default
|
await orderService.updateOrderStatus(this.orderInfo.orderNo, 'completed')
|
|
uni.showToast({
|
title: "单据已结束",
|
icon: "success"
|
});
|
|
uni.redirectTo({
|
url: '/pages/index/index'
|
})
|
// 这里可以添加结束单据的逻辑
|
}
|
}
|
});
|
},
|
|
// 切换Tab
|
switchTab(index) {
|
this.activeTab = index;
|
// 选择后自动折叠下拉菜单
|
if (!this.isCollapsed) {
|
this.isCollapsed = true;
|
}
|
|
const materialId = this.tabs[this.activeTab]?.name;
|
this.currentRecords = materialId ? this.scanRecords[materialId] || [] : [];
|
},
|
|
// 处理扫码输入
|
async handleScanInput() {
|
this.confirmHiden = true;
|
this.focus = false;
|
this.tempScanInput = this.scanInput;
|
const currentMaterial = this.tabs[this.activeTab];
|
if (!currentMaterial || !this.scanInput) return;
|
|
|
await this.handleScanResult(this.tempScanInput, currentMaterial.name);
|
this.focus = true;
|
|
this.$nextTick(() => {
|
this.scanInput = ""; // 清空输入框
|
})
|
},
|
|
// 处理扫码结果
|
async handleScanResult(result, materialId) {
|
try {
|
this.scanResult = result;
|
|
if (this.isFirstScan[materialId]) {
|
// 首次扫描处理
|
this.processFirstScan(result, materialId);
|
} else {
|
// 后续扫描处理
|
await this.processSubsequentScan(result, materialId);
|
}
|
} catch (e) {
|
console.error('handleScanResult', e)
|
}
|
|
},
|
|
// 处理首次扫描
|
processFirstScan(result, materialId) {
|
try {
|
// 将文本拆分为字符数组
|
this.textSegments = Array.from(result);
|
this.selectedSegments = [];
|
this.selectedText = "";
|
|
// 显示选择弹窗
|
this.$refs.firstScanPopup.open();
|
} catch (e) {
|
console.error('processFirstScan', e);
|
}
|
},
|
|
// 处理后续扫描
|
async processSubsequentScan(result, materialId) {
|
try {
|
let isValid = false;
|
let text = [];
|
const verificationTexts = this.verificationData[materialId];
|
for (var index = 0; index < verificationTexts.length; index++) {
|
var element = verificationTexts[index];
|
isValid = element.every(text => result.includes(text));
|
if (isValid) {
|
text = element;
|
break;
|
}
|
}
|
|
if (isValid) {
|
// 记录扫描结果
|
await this.recordScanResult(result, materialId, isValid, text);
|
} else {
|
// 无效时显示错误
|
this.$refs.errorPopup.open();
|
this.playErrorSound();
|
}
|
} catch (e) {
|
console.error('processSubsequentScan', e)
|
}
|
},
|
|
// 记录扫描结果
|
async recordScanResult(result, materialId, isValid, text = []) {
|
let scantime = this.formatDisplayDate(new Date().toISOString())
|
const record = {
|
scan_time: scantime,
|
reference_content: this.verificationData[materialId] ?
|
this.verificationData[materialId].join(" | ") : "无标定信息",
|
is_matched: isValid
|
};
|
let contents = this.getSelectedSegments();
|
if (text.length > 0) {
|
contents = text;
|
}
|
//#ifdef APP-PLUS
|
const scanrecordService = require('@/services/scanrecordService').default
|
await scanrecordService.saveScanRecord(this.orderInfo.orderNo, this.tabs[this.activeTab]
|
.name, this
|
.tempScanInput, contents);
|
//#endif
|
|
this.scanRecords[materialId].unshift(record); // 使用unshift确保倒序
|
},
|
|
// 确认选择
|
async confirmSelection() {
|
const materialId = this.tabs[this.activeTab].name;
|
|
// 标记为非首次扫描
|
this.isFirstScan[materialId] = false;
|
|
const contents = this.getSelectedSegments();
|
|
if(contents.length === 0){
|
uni.showToast({
|
title: "未选择需要标定的文字信息",
|
icon: "exception"
|
});
|
return;
|
}
|
|
// 关闭弹窗
|
this.$refs.firstScanPopup.close();
|
|
let texts = []
|
for (var index = 0; index < contents.length; index++) {
|
var element = contents[index];
|
texts.push(element.text);
|
}
|
|
// 保存验证数据
|
this.verificationData[materialId].push(texts);
|
|
// 记录扫描结果
|
await this.recordScanResult(this.scanResult, materialId, true);
|
|
//#ifdef APP-PLUS
|
const materialContentService = require('@/services/materialContentService').default
|
await materialContentService.saveMaterialContent(this.orderInfo.orderNo, this.tabs[this.activeTab]
|
.name, this
|
.tempScanInput, contents);
|
|
const orderService = require('@/services/orderService').default
|
await orderService.updateOrderStatus(this.orderInfo.orderNo, 'processing')
|
//#endif
|
},
|
|
// 关闭错误弹窗
|
closeErrorPopup() {
|
this.$refs.errorPopup.close();
|
},
|
|
// 播放错误声音
|
playErrorSound() {
|
const innerAudioContext = uni.createInnerAudioContext();
|
innerAudioContext.src = "/static/error.mp3";
|
innerAudioContext.play();
|
},
|
|
// 格式化时间
|
formatTime(date) {
|
const h = date
|
.getHours()
|
.toString()
|
.padStart(2, "0");
|
const m = date
|
.getMinutes()
|
.toString()
|
.padStart(2, "0");
|
const s = date
|
.getSeconds()
|
.toString()
|
.padStart(2, "0");
|
return `${h}:${m}:${s}`;
|
},
|
|
// 切换折叠状态
|
toggleCollapse() {
|
this.isCollapsed = !this.isCollapsed;
|
},
|
|
// 获取分段后的选中文本
|
getSelectedSegments() {
|
if (!this.selectedSegments || this.selectedSegments.length === 0)
|
return [];
|
|
// 对选中的索引进行排序
|
const sorted = [...this.selectedSegments].sort((a, b) => a - b);
|
|
const segments = [];
|
let currentSegment = [sorted[0]];
|
|
for (let i = 1; i < sorted.length; i++) {
|
if (sorted[i] === sorted[i - 1] + 1) {
|
// 连续字符,加入当前段
|
currentSegment.push(sorted[i]);
|
} else {
|
// 不连续,保存当前段并开始新段
|
segments.push(currentSegment);
|
currentSegment = [sorted[i]];
|
}
|
}
|
segments.push(currentSegment);
|
|
let content = segments.map(segment => ({
|
text: segment.map(index => this.textSegments[index]).join(""),
|
indexes: segment
|
}));
|
|
return content;
|
},
|
|
// 更新选中文本显示
|
updateSelectedText() {
|
const segments = this.getSelectedSegments();
|
this.selectedText = segments.map(s => s.text).join(" | ");
|
},
|
|
// 选择文本段
|
toggleSegment(index) {
|
const idx = this.selectedSegments.indexOf(index);
|
if (idx === -1) {
|
this.selectedSegments.push(index);
|
} else {
|
this.selectedSegments.splice(idx, 1);
|
}
|
this.updateSelectedText();
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss">
|
/* 添加侧边弹窗样式 */
|
.side-action-popup {
|
width: 70vw;
|
height: 100%;
|
background-color: #fff;
|
|
.popup-header {
|
padding: 30rpx;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
border-bottom: 1rpx solid #eee;
|
|
text {
|
font-size: 32rpx;
|
font-weight: bold;
|
}
|
}
|
|
.side-action-content {
|
padding: 30rpx;
|
|
.action-item {
|
display: flex;
|
align-items: center;
|
padding: 30rpx 0;
|
border-bottom: 1rpx solid #f5f5f5;
|
|
text {
|
margin-left: 20rpx;
|
font-size: 30rpx;
|
}
|
|
&.logout {
|
color: #f56c6c;
|
}
|
}
|
}
|
}
|
|
/* 主题变量 */
|
$primary-color: #2979ff;
|
$primary-gradient: linear-gradient(135deg, #2979ff, #00b0ff);
|
$success-color: #52c41a;
|
$error-color: #f5222d;
|
$text-color: #333;
|
$text-light: #666;
|
$text-lighter: #999;
|
$border-color: rgba(41, 121, 255, 0.1);
|
$bg-color: #f5f9ff;
|
$card-bg: #fff;
|
$shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
$shadow-md: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
$shadow-lg: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
|
|
.order-detail-container {
|
height: 100vh;
|
display: flex;
|
flex-direction: column;
|
background-color: #f5f7fa;
|
|
.order-header {
|
padding: 20rpx;
|
background-color: #fff;
|
margin-bottom: 20rpx;
|
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
|
|
.order-info {
|
display: flex;
|
margin-bottom: 10rpx;
|
font-size: 28rpx;
|
|
.info-label {
|
color: #666;
|
width: 150rpx;
|
}
|
|
.info-value {
|
color: #333;
|
font-weight: bold;
|
}
|
}
|
}
|
|
.material-tabs {
|
background-color: #fff;
|
padding: 0 20rpx;
|
border-bottom: 1rpx solid #eee;
|
position: relative;
|
|
.tabs-scroll {
|
width: 100%;
|
white-space: nowrap;
|
|
.tabs-container {
|
display: inline-flex;
|
align-items: center;
|
height: 80rpx;
|
|
.tab-item {
|
flex-shrink: 0;
|
display: flex;
|
align-items: center;
|
padding: 0 30rpx;
|
height: 100%;
|
font-size: 28rpx;
|
color: #666;
|
position: relative;
|
|
&.active {
|
color: #2979ff;
|
font-weight: bold;
|
|
&::after {
|
content: "";
|
position: absolute;
|
bottom: 0;
|
left: 30rpx;
|
right: 30rpx;
|
height: 4rpx;
|
background-color: #2979ff;
|
}
|
}
|
}
|
|
.dropdown-btn {
|
flex-shrink: 0;
|
display: flex;
|
align-items: center;
|
padding: 0 20rpx;
|
height: 60rpx;
|
font-size: 28rpx;
|
color: #666;
|
background-color: #f5f7fa;
|
border-radius: 8rpx;
|
margin-left: 10rpx;
|
max-width: 180rpx;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
|
&.active {
|
color: #2979ff;
|
font-weight: bold;
|
}
|
|
&:active {
|
background-color: #e8e8e8;
|
}
|
|
uni-icons {
|
margin-left: 10rpx;
|
flex-shrink: 0;
|
}
|
}
|
}
|
}
|
|
.dropdown-menu {
|
position: absolute;
|
top: 80rpx;
|
left: 20rpx;
|
right: 20rpx;
|
background-color: #fff;
|
border-radius: 8rpx;
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
z-index: 100;
|
max-height: 400rpx;
|
overflow-y: auto;
|
animation: fadeInDown 0.3s;
|
|
.dropdown-item {
|
padding: 20rpx 30rpx;
|
font-size: 28rpx;
|
color: #666;
|
border-bottom: 1rpx solid #f5f5f5;
|
|
&.active {
|
color: #2979ff;
|
background-color: #f0f7ff;
|
}
|
|
&:last-child {
|
border-bottom: none;
|
}
|
}
|
}
|
}
|
|
@keyframes fadeInDown {
|
from {
|
opacity: 0;
|
transform: translateY(-10rpx);
|
}
|
|
to {
|
opacity: 1;
|
transform: translateY(0);
|
}
|
}
|
|
.tab-content {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
padding: 20rpx;
|
background-color: #fff;
|
margin: 20rpx;
|
border-radius: 16rpx;
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
|
.scan-section {
|
margin-bottom: 30rpx;
|
padding: 20rpx;
|
background-color: #fff;
|
border-radius: 8rpx;
|
border: 1rpx solid #eee;
|
|
::v-deep .uni-easyinput__content {
|
min-height: 100rpx;
|
|
.uni-easyinput__input {
|
font-size: 36rpx;
|
text-align: center;
|
}
|
}
|
}
|
|
.scan-records {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
|
.section-title {
|
font-size: 28rpx;
|
color: #333;
|
margin-bottom: 20rpx;
|
display: flex;
|
align-items: center;
|
|
.record-count {
|
color: #999;
|
margin-left: 10rpx;
|
font-size: 24rpx;
|
}
|
}
|
|
.record-list {
|
flex: 1;
|
border: 1rpx solid #eee;
|
border-radius: 8rpx;
|
// padding: 0 20rpx;
|
width: calc(100% - 24px);
|
padding: 12px;
|
}
|
|
.record-item {
|
padding: 20rpx;
|
border-bottom: 1rpx solid #f5f5f5;
|
position: relative;
|
|
.record-header {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 10rpx;
|
|
.record-time {
|
font-size: 26rpx;
|
color: #666;
|
}
|
|
.record-index {
|
font-size: 26rpx;
|
color: #2979ff;
|
font-weight: bold;
|
}
|
}
|
|
.record-calibration {
|
font-size: 26rpx;
|
color: #333;
|
margin-bottom: 10rpx;
|
word-break: break-all;
|
}
|
|
.record-data {
|
font-size: 26rpx;
|
color: #666;
|
word-break: break-all;
|
margin-bottom: 10rpx;
|
}
|
|
.record-status {
|
position: absolute;
|
right: 20rpx;
|
bottom: 20rpx;
|
font-size: 32rpx;
|
|
&.error {
|
color: #f5222d;
|
}
|
}
|
}
|
}
|
}
|
|
.scan-popup,
|
.error-popup {
|
background-color: #fff;
|
border-radius: 16rpx;
|
width: 80vw;
|
max-width: 600rpx;
|
overflow: hidden;
|
|
.popup-header {
|
padding: 24rpx;
|
text-align: center;
|
font-size: 32rpx;
|
font-weight: bold;
|
border-bottom: 1rpx solid #eee;
|
}
|
|
.popup-content {
|
padding: 24rpx;
|
|
.scan-textarea {
|
width: 100%;
|
min-height: 200rpx;
|
border: 1rpx solid #eee;
|
border-radius: 8rpx;
|
padding: 16rpx;
|
margin-bottom: 20rpx;
|
font-size: 40rpx;
|
|
.text-line {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 8rpx;
|
margin-bottom: 10rpx;
|
|
.text-char {
|
display: inline-flex;
|
justify-content: center;
|
align-items: center;
|
width: 50rpx;
|
height: 50rpx;
|
cursor: pointer;
|
transition: all 0.2s ease;
|
border-radius: 8rpx;
|
background-color: #f5f5f5;
|
font-size: 36rpx;
|
|
&.selected {
|
background: linear-gradient(135deg, #2979ff, #00b0ff);
|
color: white;
|
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.3);
|
transform: scale(1.1);
|
}
|
|
&:active {
|
transform: scale(0.95);
|
}
|
}
|
}
|
}
|
|
.text-selection {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10rpx;
|
|
.text-segment {
|
padding: 8rpx 16rpx;
|
background-color: #f5f5f5;
|
border-radius: 8rpx;
|
font-size: 26rpx;
|
color: #333;
|
|
&.selected {
|
background-color: #d0e9ff;
|
color: #2979ff;
|
}
|
}
|
}
|
}
|
|
.popup-footer {
|
padding: 25rpx;
|
border-top: 1rpx solid rgba(41, 121, 255, 0.1);
|
background-color: #f8fafc;
|
|
.confirm-btn {
|
background: linear-gradient(to right, #2979ff, #00b0ff);
|
color: #fff;
|
height: 90rpx;
|
line-height: 90rpx;
|
border-radius: 45rpx;
|
font-size: 30rpx;
|
box-shadow: 0 4rpx 12rpx rgba(41, 121, 255, 0.3);
|
transition: all 0.3s ease;
|
|
&:active {
|
transform: translateY(2rpx);
|
box-shadow: 0 2rpx 6rpx rgba(41, 121, 255, 0.3);
|
}
|
}
|
}
|
}
|
}
|
</style>
|