Files
sh-app/scanpages/hj/material_sampling.vue
T
2026-07-06 17:05:24 +08:00

586 lines
13 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>
<block v-for="(item, index) in info.preWeldMaterialItems" :key="item.MaterialCode || index">
<!-- 材料信息 -->
<view class="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">{{ item.MaterialName || item.MaterialCode || '--' }}</text>
</view>
<view class="card">
<view class="card__row">
<text class="card__label">炉号</text>
<text class="card__value">
{{ item.HeatNo || '--' }}
</text>
</view>
<view class="card__row">
<text class="card__label">批号</text>
<text class="card__value">{{ item.BatchNo || '--' }}</text>
</view>
<view class="card__row">
<text class="card__label">规格</text>
<text class="card__value">{{ item.MaterialSpec || '--' }}</text>
</view>
<view class="card__row">
<text class="card__label">单位</text>
<text class="card__value">{{ item.MaterialUnit || '--' }}</text>
</view>
<view class="card__row card__row--stack">
<text class="card__label">材料描述</text>
<text class="card__value">{{ item.MaterialDef || '--' }}</text>
</view>
</view>
<view class="nav-row" @click="handleMutualCheck(item.MaterialCode)">
<view class="nav-row__left">
<view class="nav-row__dot"></view>
<text class="nav-row__label">互检上一工序</text>
</view>
<text class="nav-row__arrow"></text>
</view>
<!-- 防腐记录 -->
<nbd-anti-record :custom-style="{ margin: '0rpx'}" :params="{ materialCode: item.MaterialCode, projectId: currentProject.ProjectId }" />
</view>
</block>
<!-- 备注 -->
<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="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">照片</text>
</view>
<view class="img-box">
<nbd-photo-upload ref="photoRef" v-model:attachUrl="formAttachUrl" typeName="MaterialSampling" />
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-bar">
<view class="btn-primary-gradient" @click="handleSubmit">
<text class="btn-primary-gradient__text">提交校验结果</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onShow } 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('')
const formAttachUrl = ref('')
const id = ref('')
const check = ref({
CodeBatch: true,
Quantity: true
})
// 照片组件引用
const photoRef = ref(null)
const handleSubmit = () => {
uni.showModal({
title: '确认提交',
content: '确定提交校验结果吗?',
success: async (res) => {
if (res.confirm) {
if (photoRef.value?.hasPending()) {
uni.showLoading({ title: '上传照片中...', mask: true })
await photoRef.value.uploadAll()
uni.hideLoading()
}
const CuttingAttachUrl1 = formAttachUrl.value || info.value.CuttingAttachUrl1 || ''
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,
CuttingAttachUrl1
}
console.log('提交参数:', params)
await reqSaveCuttingCheck(params)
uni.showToast({ title: '提交成功', icon: 'none' })
setTimeout(() => { uni.navigateBack() }, 1500)
}
}
})
}
onLoad((opt) => {
if (opt.id) {
id.value = opt.id
}
})
onShow(() => {
if (id.value) {
getInfo(id.value)
}
})
const getInfo = async (id) => {
try {
uni.showLoading({ title: '加载中...', mask: true })
const res = await reqPreWeldJointByWeldJointId(id)
if (res.code === 1) {
info.value = res.data
formAttachUrl.value = res.data?.CuttingAttachUrl1 || ''
}
} catch (error) {
console.error('获取焊口详情失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}
const handleMutualCheck = (id) => {
if (!id) {
uni.showToast({ title: '缺少材料信息', icon: 'none' })
return
}
uni.navigateTo({ url: `/scanpages/hj/do_anti_rust?id=${id}` })
}
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>
// 继承全局变量(定义在 uni.scss)
$primary: $app-primary;
$primary-light: $app-primary-light;
$primary-mid: $app-primary-mid;
$primary-dark: $app-primary-dark;
$text: $app-text;
$text-secondary: $app-text-secondary;
$border: $app-border;
$radius: $app-radius;
// 页面专属
$bg: #f0f2f5;
$card-bg: #ffffff;
$shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
$shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
.detail-page {
background: $bg;
}
// ===== 焊口主标识 =====
.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;
}
}
}
// ===== 坡口参数仪表 =====
.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);
}
}
}
}
// ===== 校验卡片 =====
.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;
}
}
// ===== 提交栏(悬浮底部) =====
.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%);
}
// ===== 备注输入框 =====
.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;
}
}
// ================================================================
// 材料质检区块 —— 三合一 section
// ================================================================
// section 容器:微背景 + 内边距聚合三个子元素
.section {
background: #fafbfc;
border-radius: 20rpx;
padding: 24rpx 0 0;
margin-bottom: 28rpx;
box-shadow: $shadow-md;
}
// ---- 材料详情卡片 ----
// 底部圆角清零,与下方 nav-row 无缝衔接
.card {
border-radius: $radius $radius 0 0;
box-shadow: none;
}
// 编码类字段(炉号 / 批号 / 规格 / 单位)→ monospace
.card__value {
font-family: 'SF Mono', 'Menlo', 'Consolas', monospace;
font-size: 28rpx;
font-weight: 500;
color: $text;
letter-spacing: 0.3rpx;
}
// 材料描述 → 回退系统字体
.card__row--stack .card__value {
font-family: inherit;
font-size: 26rpx;
font-weight: 400;
letter-spacing: normal;
color: $text-secondary;
}
// ---- 互检导航按钮 ----
.nav-row {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0;
padding: 24rpx 28rpx;
background: $card-bg;
border-radius: 0;
border-top: 1rpx solid $border;
box-shadow: none;
transition: background 0.2s ease;
&:active {
background: #f5f7fa;
}
&__left {
display: flex;
align-items: center;
gap: 14rpx;
}
&__dot {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background: $primary;
flex-shrink: 0;
}
&__label {
font-size: 28rpx;
font-weight: 600;
color: $text;
letter-spacing: 1rpx;
}
&__arrow {
font-size: 36rpx;
color: $text-secondary;
font-weight: 300;
line-height: 1;
margin-right: -4rpx;
}
}
// ---- 防腐记录 ----
// 覆盖组件内部边距(已由父 .section 聚合)
:deep(.anti-record__section) {
margin: 0;
}
// 防腐记录卡片底部圆角收口,与 section 容器对齐
:deep(.anti-record__card) {
border-radius: 0 0 $radius $radius;
border-top: 1rpx solid $border;
}
// 防腐记录 header 缩进对齐,隐藏蓝色竖条(父 section header 已承载标题层级)
:deep(.anti-record__header) {
padding: 20rpx 28rpx 12rpx;
margin-bottom: 0;
}
:deep(.anti-record__bar) {
display: none;
}
</style>