Files
shj-app/scanpages/hj/daily_paper.vue
T
2026-08-18 18:05:16 +08:00

671 lines
21 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">{{ form.WeldJointCode || '--' }}</text>
<view class="joint-hero__meta">
<view class="joint-hero__pill">
<text class="pill-label">管线编码</text>
<text class="pill-value">{{ form.PipelineCode || '--' }}</text>
</view>
</view>
</view>
<!-- 组对记录 -->
<view class="section">
<nbd-record-card title="组对" :list="fitupList" :fields="fitupFields" status-key="CheckResult"
status-match="合格" />
</view>
<!-- 互检上一工序 -->
<view class="nav-row" @click="handleMutualCheck">
<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>
<!-- 焊口信息 -->
<view class="section">
<view class="section__header">
<view class="section__bar"></view>
<text class="section__title">焊口信息</text>
</view>
<view class="card">
<!-- 材质1 -->
<view class="card__row">
<text class="card__label">材质1</text>
<text class="card__value">{{ form.Material1Code || '--' }}</text>
</view>
<!-- 材质2 -->
<view class="card__row">
<text class="card__label">材质2</text>
<text class="card__value">{{ form.Material2Code || '--' }}</text>
</view>
<!-- 达因 -->
<view class="card__row">
<text class="card__label">达因</text>
<text class="card__value">{{ form.Size || '--' }}</text>
</view>
<!-- 外径 -->
<view class="card__row">
<text class="card__label">外径</text>
<text class="card__value">{{ form.Dia || '--' }}</text>
</view>
<!-- DN公称直径 -->
<view class="card__row">
<text class="card__label">DN公称直径</text>
<text class="card__value">{{ form.DNDia || '--' }}</text>
</view>
<!-- 壁厚 -->
<view class="card__row">
<text class="card__label">壁厚</text>
<text class="card__value">{{ form.Thickness || '--' }}</text>
</view>
<!-- 规格 -->
<view class="card__row">
<text class="card__label">规格</text>
<text class="card__value">{{ form.Specification || '--' }}</text>
</view>
<!-- 焊缝类型 -->
<view class="card__row" @click="handleShowWeldTypeSelect">
<text class="card__label">焊缝类型</text>
<view class="card__value-wrap card__value-wrap--clickable">
<text class="card__value" :class="{ 'card__value--placeholder': !form.WeldTypeCode }">
{{ form.WeldTypeCode || '请选择' }}
</text>
<u-icon name="arrow-right" :size="24" color="#bbb" />
</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" @click="handleShowLocationSelect">
<text class="card__label">焊口位置</text>
<view class="card__value-wrap card__value-wrap--clickable">
<text class="card__value" :class="{ 'card__value--placeholder': !form.WeldingLocationCode }">
{{ form.WeldingLocationCode ? `${form.WeldingLocationCode}(${form.WeldingLocationName ||
'--'})` : '请选择' }}
</text>
<u-icon name="arrow-right" :size="24" color="#bbb" />
</view>
</view>
<!-- 焊接日期 -->
<view class="card__row">
<text class="card__label">焊接日期</text>
<view class="card__value-wrap">
<input class="card__input" v-model="form.WeldingDateTemp" type="text" placeholder="请输入焊接日期" />
</view>
</view>
<!-- 焊工类型 -->
<view class="card__row" @click="showTypePicker = true">
<text class="card__label">焊工类型</text>
<view class="card__value-wrap card__value-wrap--clickable">
<text class="card__value" :class="{ 'card__value--placeholder': !form.welderTypeName }">
{{ form.welderTypeName || '请选择' }}
</text>
<u-icon name="arrow-right" :size="24" color="#bbb" />
</view>
</view>
<!-- 焊工 -->
<view class="card__row">
<text class="card__label">焊工</text>
<view class="card__value-wrap">
<input class="card__input" v-model="form.welderName" type="text" placeholder="请输入焊工" />
</view>
</view>
<!-- 焊接方法 -->
<view class="card__row" @click="handleShowWeldingMethodSelect">
<text class="card__label">焊接方法</text>
<view class="card__value-wrap card__value-wrap--clickable">
<text class="card__value" :class="{ 'card__value--placeholder': !form.WeldingMethodCode }">
{{ form.WeldingMethodCode || '请选择' }}
</text>
<u-icon name="arrow-right" :size="24" color="#bbb" />
</view>
</view>
<!-- 焊丝 -->
<view class="card__row" @click="handleShowWireSelect">
<text class="card__label">焊丝</text>
<view class="card__value-wrap card__value-wrap--clickable">
<text class="card__value" :class="{ 'card__value--placeholder': !wireDisplay }">
{{ wireDisplay || '请选择' }}
</text>
<u-icon name="arrow-right" :size="24" color="#bbb" />
</view>
</view>
<!-- 焊条 -->
<view class="card__row" @click="handleShowRodSelect">
<text class="card__label">焊条</text>
<view class="card__value-wrap card__value-wrap--clickable">
<text class="card__value" :class="{ 'card__value--placeholder': !rodDisplay }">
{{ rodDisplay || '请选择' }}
</text>
<u-icon name="arrow-right" :size="24" color="#bbb" />
</view>
</view>
<!-- 备注 -->
<view class="card__row card__row--stack">
<text class="card__label">备注</text>
<view class="card__value-wrap">
<textarea class="remark-input" v-model="form.Remark" placeholder="请输入备注" :maxlength="200"
auto-height />
</view>
</view>
<!-- 焊前拍照 -->
<view class="card__row card__row--stack">
<text class="card__label">焊前拍照</text>
<view class="card__value-wrap">
<nbd-photo-upload ref="beforePhotoRef" v-model:attachUrl="preWeldAttachUrl"
typeName="WeldingDaily_Before" />
</view>
</view>
<!-- 焊后拍照 -->
<view class="card__row card__row--stack">
<text class="card__label">焊后拍照</text>
<view class="card__value-wrap">
<nbd-photo-upload ref="afterPhotoRef" v-model:attachUrl="postWeldAttachUrl"
typeName="WeldingDaily_After" />
</view>
</view>
</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-btns">
<u-button v-if="canEdit && !form.WeldingDate" class="btn-submit" size="medium" type="primary"
@click="handleReport">填报</u-button>
<u-button v-if="canEdit && form.WeldingDailyId" class="btn-point" size="medium" type="primary"
@click="handlePoint">点口</u-button>
<u-button class="btn-cancel" size="medium" @click="handleClose">取消</u-button>
</view>
<!-- 焊口位置选择弹窗 -->
<nbd-select v-model="showLocationPicker" :show-search="true" title="选择焊口位置" :list="locationList"
label-key="BaseInfoCode" value-key="BaseInfoId" @confirm="handleConfirmLocation" />
<!-- 焊工类型选择弹窗 -->
<nbd-select v-model="showTypePicker" title="选择焊工类型" :list="welderTypeList" label-key="BaseInfoName"
value-key="BaseInfoCode" @confirm="handleConfirmType" />
<!-- 焊缝类型选择弹窗 -->
<nbd-select v-model="showWeldTypePicker" :show-search="true" title="选择焊缝类型" :list="weldTypeList"
label-key="BaseInfoCode" value-key="BaseInfoId" @confirm="handleConfirmWeldType" />
<!-- 焊接方法选择弹窗 -->
<nbd-select v-model="showWeldingMethodPicker" :show-search="true" title="选择焊接方法" :list="weldingMethodList"
label-key="BaseInfoCode" value-key="BaseInfoId" @confirm="handleConfirmWeldingMethod" />
<!-- 焊丝选择弹窗 -->
<nbd-select v-model="showWirePicker" :show-search="true" title="选择焊丝" :list="wireList"
label-key="BaseInfoCode" value-key="BaseInfoId" @confirm="handleConfirmWire" />
<!-- 焊条选择弹窗 -->
<nbd-select v-model="showRodPicker" :show-search="true" title="选择焊条" :list="rodList"
label-key="BaseInfoCode" value-key="BaseInfoId" @confirm="handleConfirmRod" />
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { reqGetWeldJointByWeldJointId, reqSaveWeldingDailyByWeldJointId, reqGetManualPointSave, reqFitupCheckByWeldJointId } from '@/api/hj.js'
import { reqWeldingLocation, reqGetWeldTypeList, reqGetWeldingMethodList, reqGetWeldingConsumables } from '@/api/base.js'
import { useUserStore, useMenuStore } from '@/store'
const userStore = useUserStore()
const menuStore = useMenuStore()
const { userInfo } = userStore
const canEdit = computed(() => menuStore.canEditFunc('dailyPaper'))
// ===== 表单数据 =====
const form = ref({})
const preWeldAttachUrl = ref('')
const postWeldAttachUrl = ref('')
// ===== 弹窗 =====
const showLocationPicker = ref(false)
const showTypePicker = ref(false)
const showWeldTypePicker = ref(false)
const showWeldingMethodPicker = ref(false)
const showWirePicker = ref(false)
const showRodPicker = ref(false)
const locationList = ref([])
const weldTypeList = ref([])
const weldingMethodList = ref([])
const wireList = ref([])
const rodList = ref([])
const welderTypeList = ref([
{ BaseInfoName: '打底/盖面', BaseInfoCode: 0 },
{ BaseInfoName: '打底', BaseInfoCode: 1 },
{ BaseInfoName: '盖面', BaseInfoCode: 2 },
])
const beforePhotoRef = ref(null)
const afterPhotoRef = ref(null)
// ===== 组对记录 =====
const weldJointId = ref('')
const fitupList = ref([])
const fitupFields = [
{ label: '组对间隙', key: 'FitupGap' },
{ label: '错边量', key: 'Misalignment' },
{ label: '检查人', key: 'CheckPersonName' },
{ label: '检查时间', key: 'CheckTime' },
{ label: '检查结果', key: 'CheckResult', type: 'tag', tagMatch: '合格' },
{ label: '不合格原因', key: 'UnqualifiedReason', showWhen: { key: 'CheckResult', notEqual: '合格' } },
{ label: '整改要求', key: 'RectifyRequirement', showWhen: { key: 'CheckResult', notEqual: '合格' } },
{ label: '照片', key: 'AttachUrl1', type: 'photo', cols: 4 },
]
// ===== 弹窗 ========
const handleShowLocationSelect = () => {
reqWeldingLocation().then(res => {
locationList.value = res.data
showLocationPicker.value = true
})
}
const handleConfirmLocation = (item) => {
form.value.WeldingLocationCode = item.BaseInfoCode
form.value.WeldingLocationName = item.BaseInfoName
form.value.WeldingLocationId = item.BaseInfoId
showLocationPicker.value = false
}
const handleConfirmType = (item) => {
form.value.welderType = item.BaseInfoCode
form.value.welderTypeName = item.BaseInfoName
showTypePicker.value = false
}
const handleShowWeldTypeSelect = () => {
reqGetWeldTypeList().then(res => {
weldTypeList.value = res.data || []
showWeldTypePicker.value = true
})
}
const handleConfirmWeldType = (item) => {
form.value.WeldTypeId = item.BaseInfoId
form.value.WeldTypeCode = item.BaseInfoCode
form.value.WeldTypeName = item.BaseInfoName
showWeldTypePicker.value = false
}
const handleShowWeldingMethodSelect = () => {
reqGetWeldingMethodList().then(res => {
weldingMethodList.value = res.data || []
showWeldingMethodPicker.value = true
})
}
const handleConfirmWeldingMethod = (item) => {
form.value.WeldingMethodId = item.BaseInfoId
form.value.WeldingMethodCode = item.BaseInfoCode
form.value.WeldingMethodName = item.BaseInfoName
showWeldingMethodPicker.value = false
}
const CONSUMABLE_WIRE = 1
const CONSUMABLE_ROD = 2
const pickConsumableId = (item) => item?.BaseInfoId || item?.Id || ''
const pickConsumableCode = (item) => item?.BaseInfoCode || item?.Code || ''
const pickConsumableName = (item) => item?.BaseInfoName || item?.Name || pickConsumableCode(item)
const normalizeConsumables = (list) => (Array.isArray(list) ? list : []).map((item) => ({
...item,
BaseInfoId: pickConsumableId(item),
BaseInfoCode: pickConsumableCode(item),
BaseInfoName: pickConsumableName(item),
}))
const fetchConsumables = async (type) => {
const res = await reqGetWeldingConsumables(type)
return normalizeConsumables(res.data)
}
const handleShowWireSelect = () => {
fetchConsumables(CONSUMABLE_WIRE).then((list) => {
wireList.value = list
showWirePicker.value = true
})
}
const handleConfirmWire = (item) => {
form.value.WeldingWire = item.BaseInfoId
form.value.WeldingWireCode = item.BaseInfoCode
form.value.WeldingWireName = item.BaseInfoName
showWirePicker.value = false
}
const handleShowRodSelect = () => {
fetchConsumables(CONSUMABLE_ROD).then((list) => {
rodList.value = list
showRodPicker.value = true
})
}
const handleConfirmRod = (item) => {
form.value.WeldingRod = item.BaseInfoId
form.value.WeldingRodCode = item.BaseInfoCode
form.value.WeldingRodName = item.BaseInfoName
showRodPicker.value = false
}
const wireDisplay = computed(() => form.value.WeldingWireCode || form.value.WeldingWireName || '')
const rodDisplay = computed(() => form.value.WeldingRodCode || form.value.WeldingRodName || '')
// ===== 操作 =====
const handlePoint = async () => {
await reqGetManualPointSave(form.value.WeldJointId)
uni.showToast({ title: '点口成功', icon: 'none' })
setTimeout(() => { uni.navigateBack() }, 1500)
}
const handleReport = () => {
if (!canEdit.value) {
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
return
}
uni.showModal({
title: '信息提示',
content: '确定要填报吗?',
success: async ({ confirm }) => {
if (confirm) {
console.log(beforePhotoRef.value?.hasPending())
const needBefore = beforePhotoRef.value?.hasPending()
const needAfter = afterPhotoRef.value?.hasPending()
if (needBefore || needAfter) {
uni.showLoading({ title: '上传照片中...', mask: true })
if (needBefore) await beforePhotoRef.value.uploadAll()
if (needAfter) await afterPhotoRef.value.uploadAll()
uni.hideLoading()
}
await reqSaveWeldingDailyByWeldJointId({
WeldJointId: form.value.WeldJointId,
Personid: userInfo.PersonId,
time: form.value.WeldingDateTemp,
weldingLocation: form.value.WeldingLocationId || '',
welderType: form.value.welderType,
// 同步更新焊口焊缝类型 / 焊接方法
WeldTypeId: form.value.WeldTypeId || '',
WeldTypeCode: form.value.WeldTypeCode || '',
WeldingMethodId: form.value.WeldingMethodId || '',
WeldingMethodCode: form.value.WeldingMethodCode || '',
WeldingWire: form.value.WeldingWire || '',
WeldingRod: form.value.WeldingRod || '',
PreWeldAttachUrl: preWeldAttachUrl.value || form.value.PreWeldAttachUrl || '',
PostWeldAttachUrl: postWeldAttachUrl.value || form.value.PostWeldAttachUrl || ''
})
uni.showToast({ title: '保存成功', icon: 'none' })
setTimeout(() => { uni.navigateBack() }, 1500)
}
}
})
}
const handleClose = () => { uni.navigateBack() }
const handleMutualCheck = () => {
uni.navigateTo({ url: '/scanpages/hj/make_right?id=' + weldJointId.value })
}
// 按 Code 回填 Id,保证未重选时提交仍能同步更新焊口
const fillTypeMethodIds = async () => {
const needWeldType = form.value.WeldTypeCode && !form.value.WeldTypeId
const needMethod = form.value.WeldingMethodCode && !form.value.WeldingMethodId
const needWire = (form.value.WeldingWireCode && !form.value.WeldingWire) || (form.value.WeldingWire && !form.value.WeldingWireCode)
const needRod = (form.value.WeldingRodCode && !form.value.WeldingRod) || (form.value.WeldingRod && !form.value.WeldingRodCode)
if (!needWeldType && !needMethod && !needWire && !needRod) return
try {
const [typeRes, methodRes, wireRes, rodRes] = await Promise.all([
needWeldType ? reqGetWeldTypeList() : Promise.resolve(null),
needMethod ? reqGetWeldingMethodList() : Promise.resolve(null),
needWire ? fetchConsumables(CONSUMABLE_WIRE) : Promise.resolve(null),
needRod ? fetchConsumables(CONSUMABLE_ROD) : Promise.resolve(null),
])
if (typeRes?.data) {
const hit = typeRes.data.find(i => i.BaseInfoCode === form.value.WeldTypeCode)
if (hit) {
form.value.WeldTypeId = hit.BaseInfoId
form.value.WeldTypeName = hit.BaseInfoName
}
}
if (methodRes?.data) {
const hit = methodRes.data.find(i => i.BaseInfoCode === form.value.WeldingMethodCode)
if (hit) {
form.value.WeldingMethodId = hit.BaseInfoId
form.value.WeldingMethodName = hit.BaseInfoName
}
}
if (wireRes) {
const hit = wireRes.find(i =>
i.BaseInfoId === form.value.WeldingWire || i.BaseInfoCode === form.value.WeldingWireCode
)
if (hit) {
form.value.WeldingWire = hit.BaseInfoId
form.value.WeldingWireCode = hit.BaseInfoCode
form.value.WeldingWireName = hit.BaseInfoName
}
}
if (rodRes) {
const hit = rodRes.find(i =>
i.BaseInfoId === form.value.WeldingRod || i.BaseInfoCode === form.value.WeldingRodCode
)
if (hit) {
form.value.WeldingRod = hit.BaseInfoId
form.value.WeldingRodCode = hit.BaseInfoCode
form.value.WeldingRodName = hit.BaseInfoName
}
}
} catch (e) {
console.error('回填焊缝类型/焊接方法/焊材ID失败:', e)
}
}
// ===== 生命周期 =====
onLoad((opt) => {
weldJointId.value = opt.id || ''
reqGetWeldJointByWeldJointId(opt.id).then(async (res) => {
form.value = res.data || {}
if (form.value.CoverWelderName) {
form.value.welderName = form.value.CoverWelderName
}
if (form.value.BackingWelderName) {
form.value.welderName += '/' + form.value.BackingWelderName
}
const now = new Date()
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
form.value.WeldingDateTemp = form.value.WeldingDate || today
form.value.welderType = 0
form.value.welderTypeName = "打底/盖面"
// 回显已有照片
preWeldAttachUrl.value = form.value.PreWeldAttachUrl || ''
postWeldAttachUrl.value = form.value.PostWeldAttachUrl || ''
await fillTypeMethodIds()
})
reqFitupCheckByWeldJointId(opt.id).then(res => {
if (res.code === 1 && res.data) {
fitupList.value = res.data
}
})
})
</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;
// 页面专属
$bg: #f0f2f5;
$card-bg: #ffffff;
$border: #e8ecf1;
$shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
.detail-page {
background: $bg;
min-height: 100vh;
padding-bottom: 180rpx;
}
// ===== 焊口主标识 =====
.joint-hero {
position: relative;
margin: 24rpx;
padding: 36rpx 32rpx 28rpx;
background: $card-bg;
border-radius: $app-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;
}
}
}
// ---- 互检导航按钮 ----
.nav-row {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 24rpx;
padding: 24rpx 28rpx;
background: $card-bg;
border-radius: $app-radius;
border-top: 1rpx solid $border;
box-shadow: none;
transition: background 0.2s ease;
margin-bottom: 28rpx;
&: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;
}
}
</style>