Files
sh-app/scanpages/hj/material_sampling.vue
T
2026-06-18 15:10:50 +08:00

687 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="detail-page">
<!-- 焊口主标识 -->
<view class="joint-hero">
<text class="joint-hero__code">{{ info.WeldJointCode || '--' }}</text>
<view class="joint-hero__meta">
<view class="joint-hero__pill">
<text class="pill-label">管线编码</text>
<text class="pill-value">{{ info.PipelineCode || '--' }}</text>
</view>
<view class="joint-hero__pill">
<text class="pill-label">项目名称</text>
<text class="pill-value">{{ info.ProjectName || info.ProjectId || '--' }}</text>
</view>
</view>
</view>
<!-- 坡口参数 - 测量仪表 -->
<view class="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">坡口参数</text>
</view>
<view class="spec-grid">
<view class="spec-item">
<view class="spec-item__header">
<text class="spec-item__label">坡口角度</text>
<text class="spec-item__value">{{ info.GrooveAngle || '--' }}<text class="spec-item__unit">°</text></text>
</view>
<view class="spec-item__bar-track">
<view class="spec-item__bar-fill" :style="{ width: gaugeWidth(info.GrooveAngle, 0, 90) }"></view>
</view>
</view>
<view class="spec-item">
<view class="spec-item__header">
<text class="spec-item__label">组对间隙</text>
<text class="spec-item__value">{{ info.FitupGap || '--' }}<text class="spec-item__unit">mm</text></text>
</view>
<view class="spec-item__bar-track">
<view class="spec-item__bar-fill fill--amber" :style="{ width: gaugeWidth(info.FitupGap, 0, 10) }"></view>
</view>
</view>
<view class="spec-item">
<view class="spec-item__header">
<text class="spec-item__label">错边量</text>
<text class="spec-item__value">{{ info.Misalignment || '--' }}<text class="spec-item__unit">mm</text></text>
</view>
<view class="spec-item__bar-track">
<view class="spec-item__bar-fill fill--teal" :style="{ width: gaugeWidth(info.Misalignment, 0, 5) }"></view>
</view>
</view>
</view>
</view>
<!-- 坡口类型 -->
<view class="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">坡口信息</text>
</view>
<view class="card">
<view class="card__row">
<text class="card__label">坡口类型名称</text>
<view class="card__value-wrap">
<text class="card__value">{{ info.GrooveTypeName || '--' }}</text>
</view>
</view>
<view class="card__row">
<text class="card__label">坡口类型编号</text>
<view class="card__value-wrap">
<text class="card__value">{{ info.GrooveTypeCode || '--' }}</text>
</view>
</view>
<view class="card__row">
<text class="card__label">坡口加工类型</text>
<text class="card__value">{{ info.GrooveProcessType || '--' }}</text>
</view>
</view>
</view>
<!-- 材料校验 -->
<view class="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">材料校验</text>
</view>
<view class="check-card">
<view class="check-item">
<view class="check-item__left">
<text class="check-item__label">材料编码及炉批号校验</text>
<text class="check-item__desc">核对实物编码与批次信息</text>
</view>
<view class="check-item__action" @click="toggleCheck('CodeBatch')">
<view class="check-btn" :class="{
'check-btn--pass': check.CodeBatch === true,
'check-btn--fail': check.CodeBatch === false
}">
<template v-if="check.CodeBatch === true">
<text class="check-btn__icon"></text>
<text class="check-btn__text">通过</text>
</template>
<template v-else>
<text class="check-btn__icon"></text>
<text class="check-btn__text">不通过</text>
</template>
</view>
</view>
</view>
<view class="check-item">
<view class="check-item__left">
<text class="check-item__label">材料数量校验</text>
<text class="check-item__desc">核对实物数量与单据一致</text>
</view>
<view class="check-item__action" @click="toggleCheck('Quantity')">
<view class="check-btn" :class="{
'check-btn--pass': check.Quantity === true,
'check-btn--fail': check.Quantity === false
}">
<template v-if="check.Quantity === true">
<text class="check-btn__icon"></text>
<text class="check-btn__text">通过</text>
</template>
<template v-else>
<text class="check-btn__icon"></text>
<text class="check-btn__text">不通过</text>
</template>
</view>
</view>
</view>
</view>
</view>
<!-- 备注 -->
<view class="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">备注</text>
</view>
<view class="remark-card">
<textarea
class="remark-input"
v-model="remark"
placeholder="请输入备注信息(选填)"
:maxlength="200"
auto-height
/>
<text class="remark-count">{{ remark.length }}/200</text>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-bar">
<view class="submit-btn" @click="handleSubmit">
<text class="submit-btn__text">提交校验结果</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/store'
import { reqPreWeldJointByWeldJointId, reqSaveCuttingCheck } from '@/api/hj'
const userStore = useUserStore()
const { userInfo, currentProject } = storeToRefs(userStore)
const info = ref({})
const remark = ref('')
// 校验状态:true=通过,false=不通过
const check = ref({
CodeBatch: true,
Quantity: true
})
const toggleCheck = (key) => {
const val = check.value[key]
check.value[key] = val === true ? false : true
}
const handleSubmit = () => {
uni.showModal({
title: '确认提交',
content: '确定提交校验结果吗?',
success: async (res) => {
if (res.confirm) {
const now = new Date()
const pad = (n) => String(n).padStart(2, '0')
const checkTime = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`
const params = {
ProjectId: currentProject.value?.ProjectId,
WeldJointId: info.value?.WeldJointId,
IsMaterialCodeBatchNoAccurate: check.value.CodeBatch,
IsMaterialQuantityAccurate: check.value.Quantity,
CheckPerson: userInfo.value?.PersonId,
CheckTime: checkTime,
Remark: remark.value
}
console.log('提交参数:', params)
await reqSaveCuttingCheck(params)
uni.showToast({ title: '提交成功', icon: 'none' })
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
})
}
onLoad((opt) => {
if (opt.id) {
getInfo(opt.id)
}
})
const getInfo = async (id) => {
try {
uni.showLoading({ title: '加载中...', mask: true })
const res = await reqPreWeldJointByWeldJointId(id)
if (res.code === 1) { info.value = res.data }
} catch (error) {
console.error('获取焊口详情失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}
// 模拟进度条宽度(0~100%
const gaugeWidth = (val, min, max) => {
if (!val && val !== 0) return '0%'
const num = parseFloat(val)
if (isNaN(num)) return '0%'
const pct = Math.min(Math.max((num - min) / (max - min) * 100, 0), 100)
return pct + '%'
}
</script>
<style lang="scss" scoped>
$primary: #2979ff;
$primary-light: #e8f0fe;
$primary-mid: #d0ddff;
$primary-dark: #1a56cc;
$bg: #f0f2f5;
$text: #0f1724;
$text-secondary: #6b7c93;
$border: #e8ecf1;
$card-bg: #ffffff;
$radius: 16rpx;
$shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
$shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
.detail-page {
min-height: 100vh;
background: $bg;
padding-bottom: 180rpx;
}
// ===== 焊口主标识 =====
.joint-hero {
position: relative;
margin: 24rpx;
padding: 36rpx 32rpx 28rpx;
background: $card-bg;
border-radius: $radius;
box-shadow: $shadow-md;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4rpx;
background: linear-gradient(90deg, $primary, #6ba3ff, $primary);
background-size: 200% 100%;
animation: shimmer 3s ease-in-out infinite;
}
@keyframes shimmer {
0%, 100% { background-position: 0% 0; }
50% { background-position: 100% 0; }
}
&__code {
display: block;
font-size: 52rpx;
font-weight: 800;
color: $text;
line-height: 1.2;
word-break: break-all;
font-family: monospace;
letter-spacing: 2rpx;
margin-bottom: 28rpx;
position: relative;
padding-left: 24rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 6rpx;
bottom: 6rpx;
width: 4rpx;
background: $primary;
border-radius: 2rpx;
}
}
&__meta {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
}
&__pill {
display: inline-flex;
width: 100%;
align-items: center;
gap: 8rpx;
background: $primary-light;
padding: 10rpx 18rpx;
border-radius: 10rpx;
border: 1rpx solid $primary-mid;
.pill-label {
font-size: 22rpx;
color: $text-secondary;
width: 60rpx;
}
.pill-value {
font-size: 24rpx;
font-weight: 600;
color: $primary-dark;
font-family: monospace;
}
}
}
// ===== 区块标题 =====
.section {
margin: 0 24rpx 20rpx;
&__header {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 14rpx;
padding: 0 6rpx;
}
&__bar {
width: 6rpx;
height: 26rpx;
background: linear-gradient(180deg, $primary, #6ba3ff);
border-radius: 3rpx;
flex-shrink: 0;
}
&__title {
font-size: 28rpx;
font-weight: 600;
color: $text;
letter-spacing: 0.5rpx;
}
}
// ===== 坡口参数仪表 =====
.spec-grid {
background: $card-bg;
border-radius: $radius;
padding: 8rpx 0;
box-shadow: $shadow-md;
.spec-item {
padding: 24rpx 28rpx;
border-bottom: 1rpx solid $border;
&:last-child {
border-bottom: none;
}
&__header {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 14rpx;
}
&__label {
font-size: 24rpx;
color: $text-secondary;
font-weight: 500;
}
&__value {
font-size: 40rpx;
font-weight: 700;
color: $text;
line-height: 1;
font-variant-numeric: tabular-nums;
}
&__unit {
font-size: 24rpx;
font-weight: 400;
color: $text-secondary;
margin-left: 6rpx;
}
&__bar-track {
height: 8rpx;
background: #f0f2f5;
border-radius: 4rpx;
overflow: hidden;
position: relative;
}
&__bar-fill {
height: 100%;
border-radius: 4rpx;
background: linear-gradient(90deg, $primary, #6ba3ff);
transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
position: relative;
&::after {
content: '';
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 12rpx;
border-radius: 4rpx;
background: rgba(255, 255, 255, 0.35);
}
&.fill--amber {
background: linear-gradient(90deg, #f59e0b, #fbbf24);
}
&.fill--teal {
background: linear-gradient(90deg, #14b8a6, #2dd4bf);
}
}
}
}
// ===== 信息卡片 =====
.card {
background: $card-bg;
border-radius: $radius;
overflow: hidden;
box-shadow: $shadow-md;
&__row {
display: flex;
align-items: center;
padding: 22rpx 28rpx;
border-bottom: 1rpx solid $border;
&:last-child {
border-bottom: none;
}
&:active {
background: #fafbfc;
}
}
&__label {
width: 180rpx;
font-size: 26rpx;
color: $text-secondary;
flex-shrink: 0;
position: relative;
padding-left: 16rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4rpx;
height: 16rpx;
background: $primary-mid;
border-radius: 2rpx;
}
}
&__value {
flex: 1;
font-size: 28rpx;
color: $text;
font-weight: 500;
}
&__value-wrap {
flex: 1;
display: flex;
align-items: center;
gap: 12rpx;
}
}
// ===== 校验卡片 =====
.check-card {
background: $card-bg;
border-radius: $radius;
overflow: hidden;
box-shadow: $shadow-md;
}
.check-item {
display: flex;
align-items: center;
padding: 22rpx 28rpx;
border-bottom: 1rpx solid $border;
&:last-child {
border-bottom: none;
}
&__left {
flex: 1;
min-width: 0;
}
&__label {
font-size: 26rpx;
font-weight: 500;
color: $text;
display: block;
margin-bottom: 4rpx;
}
&__desc {
font-size: 22rpx;
color: $text-secondary;
display: block;
}
&__action {
flex-shrink: 0;
margin-left: 20rpx;
}
}
// ===== 校验按钮(二态切换) =====
.check-btn {
display: inline-flex;
align-items: center;
gap: 8rpx;
padding: 12rpx 24rpx;
border-radius: 12rpx;
transition: all 0.25s ease;
min-width: 120rpx;
justify-content: center;
&--pass {
background: #ebf9f0;
border: 1rpx solid #b7ebc6;
.check-btn__icon {
font-size: 26rpx;
color: #22c55e;
font-weight: 700;
}
.check-btn__text {
font-size: 24rpx;
color: #16a34a;
font-weight: 600;
}
}
&--fail {
background: #fef2f2;
border: 1rpx solid #fecaca;
.check-btn__icon {
font-size: 26rpx;
color: #ef4444;
font-weight: 700;
}
.check-btn__text {
font-size: 24rpx;
color: #dc2626;
font-weight: 600;
}
}
&:active {
transform: scale(0.96);
}
}
// ===== 提交栏(悬浮底部) =====
.submit-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 24rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: linear-gradient(180deg, rgba(240, 242, 245, 0) 0%, $bg 20%);
}
.submit-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 24rpx;
background: linear-gradient(135deg, $primary, #5a9aff);
border-radius: 14rpx;
box-shadow: 0 6rpx 24rpx rgba($primary, 0.3);
transition: all 0.25s ease;
&:active {
opacity: 0.9;
transform: scale(0.98);
}
&--disabled {
background: #c5cbd5;
box-shadow: none;
&:active {
opacity: 1;
transform: none;
}
.submit-btn__text {
color: #94a3b8;
}
}
&__text {
font-size: 30rpx;
font-weight: 600;
color: #ffffff;
letter-spacing: 2rpx;
}
}
// ===== 备注输入框 =====
.remark-card {
background: $card-bg;
border-radius: $radius;
padding: 24rpx 28rpx;
box-shadow: $shadow-md;
position: relative;
.remark-input {
width: 100%;
min-height: 120rpx;
font-size: 26rpx;
color: $text;
line-height: 1.6;
padding: 0;
margin: 0;
background: transparent;
&::placeholder {
color: #b0bec5;
}
}
.remark-count {
position: absolute;
bottom: 16rpx;
right: 24rpx;
font-size: 22rpx;
color: $text-secondary;
}
}
</style>