feat:备件模块添加扫一扫、对接接口

master
黄伟杰 1 month ago
parent 878304b2c9
commit 41fd0348bf

@ -7,10 +7,6 @@
</view>
<view class="header-content">
<text class="header-title">备件详情</text>
<text class="header-code">{{ spareData.code }}</text>
</view>
<view class="status-badge" :class="'status-' + spareData.statusType">
<text>{{ spareData.status }}</text>
</view>
</view>
@ -19,58 +15,32 @@
<view class="card-title">基本信息</view>
<view class="info-list">
<view class="info-row">
<text class="info-label">备件名称</text>
<text class="info-value">{{ spareData.name }}</text>
<text class="info-label">备件编码</text>
<text class="info-value">{{ getField('barCode') }}</text>
</view>
<view class="info-row">
<text class="info-label">备件类型</text>
<text class="info-value">{{ spareData.type }}</text>
<text class="info-label">备件名称</text>
<text class="info-value">{{ getField('name') }}</text>
</view>
<view class="info-row">
<text class="info-label">规格型号</text>
<text class="info-value">{{ spareData.spec }}</text>
<text class="info-label">单位</text>
<text class="info-value">{{ unitLabel }}</text>
</view>
<view class="info-row">
<text class="info-label">存放位置</text>
<text class="info-value">{{ spareData.location }}</text>
<text class="info-label">规格</text>
<text class="info-value">{{ getField('standard') }}</text>
</view>
</view>
</view>
<view class="info-card">
<view class="card-title">库存信息</view>
<view class="info-list">
<view class="info-row">
<text class="info-label">库存数量</text>
<text class="info-value highlight">{{ spareData.stock }}</text>
<text class="info-label">预警库存</text>
<text class="info-value">{{ getField('safetyNumber') }}</text>
</view>
<view class="info-row">
<text class="info-label">最低库存</text>
<text class="info-value">{{ spareData.minStock }}</text>
<text class="info-label">备注</text>
<text class="info-value">{{ getField('remark') }}</text>
</view>
<view class="info-row">
<text class="info-label">供应商</text>
<text class="info-value">{{ spareData.supplier }}</text>
</view>
<view class="info-row">
<text class="info-label">最后入库时间</text>
<text class="info-value">{{ spareData.lastInTime }}</text>
</view>
</view>
</view>
<view class="info-card">
<view class="card-title">出入库记录</view>
<view class="record-list">
<view v-for="(record, index) in stockRecords" :key="index" class="record-item">
<view class="record-dot"></view>
<view class="record-content">
<text class="record-title">{{ record.title }}</text>
<text class="record-time">{{ record.time }}</text>
</view>
<view class="record-type" :class="'type-' + record.type">
<text>{{ record.typeText }}</text>
</view>
<text class="info-label">创建时间</text>
<text class="info-value">{{ createTimeLabel }}</text>
</view>
</view>
</view>
@ -79,41 +49,100 @@
</template>
<script setup>
import { reactive, onMounted } from 'vue';
const spareData = reactive({
code: '',
name: '轴承组件',
type: '机械备件',
spec: 'SKF-6205-2RS',
location: 'A仓库-01货架',
status: '充足',
statusType: 'normal',
stock: '150',
minStock: '50',
supplier: 'SKF中国',
lastInTime: '2024-03-10'
});
const stockRecords = reactive([
{ title: '入库 - 采购入库', time: '2024-03-10 10:30', type: 'in', typeText: '入库' },
{ title: '出库 - 维修领用', time: '2024-03-08 14:20', type: 'out', typeText: '出库' },
{ title: '入库 - 采购入库', time: '2024-03-05 09:15', type: 'in', typeText: '入库' },
{ title: '出库 - 维修领用', time: '2024-03-01 16:45', type: 'out', typeText: '出库' }
]);
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import request from '@/utils/request'
const spareId = ref(undefined)
const loading = ref(false)
const detailData = ref(null)
const unitList = ref([])
function goBack() {
uni.navigateBack();
}
onMounted(() => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const options = currentPage.options || {};
if (options.code) {
spareData.code = decodeURIComponent(options.code);
function detailValue(v) {
if (v === 0) return '0'
if (v === false) return '否'
if (v === true) return '是'
if (v === null || v === undefined) return '-'
const s = String(v).trim()
return s ? s : '-'
}
function getField(field) {
const d = detailData.value
return detailValue(d ? d[field] : undefined)
}
function pad2(v) {
return String(v).padStart(2, '0')
}
function formatDateTime(v) {
if (v === null || v === undefined || v === '') return '-'
const d = new Date(typeof v === 'number' ? v : String(v))
if (Number.isNaN(d.getTime())) return '-'
const yyyy = d.getFullYear()
const mm = pad2(d.getMonth() + 1)
const dd = pad2(d.getDate())
const hh = pad2(d.getHours())
const mi = pad2(d.getMinutes())
const ss = pad2(d.getSeconds())
return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`
}
const createTimeLabel = computed(() => {
const d = detailData.value
return formatDateTime(d ? d.createTime : undefined)
})
const unitLabel = computed(() => {
const d = detailData.value
const explicit = d ? d.unitName : undefined
if (explicit) return detailValue(explicit)
const unitId = d ? d.unitId : undefined
const list = unitList.value
const matched = Array.isArray(list) ? list.find(u => u && u.id === unitId) : undefined
return detailValue(matched ? matched.name : undefined)
})
async function fetchAll() {
if (!spareId.value) {
uni.showToast({ title: '缺少备件ID', icon: 'none' })
return
}
});
loading.value = true
try {
const [detailRes, unitRes] = await Promise.all([
request({
url: '/admin-api/erp/product/get',
method: 'get',
params: { id: spareId.value },
showLoading: false
}),
request({
url: '/admin-api/erp/product-unit/simple-list',
method: 'get',
showLoading: false
})
])
detailData.value = detailRes ? detailRes.data : null
unitList.value = unitRes ? unitRes.data : []
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
loading.value = false
}
}
onLoad((query) => {
const rawId = query && (query.id !== undefined ? query.id : query.code)
const decoded = rawId ? decodeURIComponent(String(rawId)) : ''
spareId.value = decoded ? decoded : undefined
fetchAll()
})
</script>
<style lang="scss" scoped>
@ -191,7 +220,7 @@ onMounted(() => {
.content-section {
padding: 0 30rpx 30rpx;
margin-top: -40rpx;
margin-top: 40rpx;
}
.info-card {

@ -31,10 +31,7 @@
<view class="corner corner-br"></view>
</view>
</view>
<text class="scanning-text">正在扫描中...</text>
<view class="progress-bar">
<view class="progress-fill" :style="{ width: scanProgress + '%' }"></view>
</view>
<text class="scanning-text">正在打开扫码...</text>
</view>
</view>
@ -68,7 +65,6 @@ import { ref } from 'vue';
const spareCode = ref('');
const isScanning = ref(false);
const scanProgress = ref(0);
function goBack() {
uni.navigateBack();
@ -76,27 +72,44 @@ function goBack() {
function startScan() {
if (isScanning.value) return;
isScanning.value = true;
scanProgress.value = 0;
const duration = 2000;
const interval = 50;
const steps = duration / interval;
let currentStep = 0;
const timer = setInterval(() => {
currentStep++;
scanProgress.value = Math.min((currentStep / steps) * 100, 100);
if (currentStep >= steps) {
clearInterval(timer);
setTimeout(() => {
isScanning.value = false;
navigateToDetail('SP-SCAN-001');
}, 200);
}
}, interval);
const finish = () => {
isScanning.value = false;
}
uni.scanCode({
onlyFromCamera: true,
scanType: ['qrCode', 'barCode'],
success: (res) => {
let info;
try {
info = res && res.result ? JSON.parse(res.result) : undefined;
} catch (e) {
info = undefined;
}
const id = info && info.id !== undefined ? info.id : (res ? res.result : undefined);
if (!id) {
uni.showToast({ title: '未获取到扫码结果', icon: 'none' })
return
}
navigateToDetail(id);
},
fail: (err) => {
const msg = String(err?.errMsg || '')
if (msg.includes('cancel')) {
uni.showToast({ title: '已取消扫码', icon: 'none' })
return
}
if (msg.toLowerCase().includes('not support') || msg.toLowerCase().includes('not supported')) {
uni.showToast({ title: '当前平台不支持扫码', icon: 'none' })
return
}
uni.showToast({ title: '扫码失败', icon: 'none' })
},
complete: finish
})
}
function confirmInput() {
@ -111,9 +124,9 @@ function confirmInput() {
navigateToDetail(spareCode.value.trim());
}
function navigateToDetail(code) {
function navigateToDetail(id) {
uni.navigateTo({
url: `/pages_function/pages/spare/detail?code=${encodeURIComponent(code)}`
url: `/pages_function/pages/spare/detail?id=${encodeURIComponent(id)}`
});
}
</script>
@ -169,7 +182,6 @@ function navigateToDetail(code) {
.content-section {
padding: 40rpx 30rpx;
margin-top: -40rpx;
}
.scan-section {

Loading…
Cancel
Save