功能调整
This commit is contained in:
+19
@@ -36,11 +36,30 @@ export const reqGetGrooveTypeList = ()=>get(`BaseInfo/GetGrooveType`)
|
|||||||
*/
|
*/
|
||||||
export const reqGetWeldTypeList = () => get(`BaseInfo/GetWeldType`)
|
export const reqGetWeldTypeList = () => get(`BaseInfo/GetWeldType`)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按关键字分页查询入库明细条码
|
||||||
|
* @param {object} data
|
||||||
|
* @param {string} data.barCodeKeyword - 条码关键字
|
||||||
|
* @param {number} data.pageIndex - 页码(从 1 开始)
|
||||||
|
* @param {number} data.pageSize - 每页条数
|
||||||
|
*/
|
||||||
|
export const reqGetInputDetailBarCodes = (data = {}) => get('BaseInfo/GetInputDetailBarCodes', {
|
||||||
|
barCodeKeyword: data.barCodeKeyword ?? '',
|
||||||
|
pageIndex: data.pageIndex ?? 1,
|
||||||
|
pageSize: data.pageSize ?? 20,
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取焊接方法列表
|
* 获取焊接方法列表
|
||||||
*/
|
*/
|
||||||
export const reqGetWeldingMethodList = () => get(`BaseInfo/GetWeldingMethod`)
|
export const reqGetWeldingMethodList = () => get(`BaseInfo/GetWeldingMethod`)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按类型获取焊接耗材
|
||||||
|
* @param {number} consumablesType - 焊材类型:1焊丝,2焊条
|
||||||
|
*/
|
||||||
|
export const reqGetWeldingConsumables = (consumablesType) => get('BaseInfo/GetWeldingConsumables', { consumablesType })
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 附件上传
|
* 附件上传
|
||||||
* @param {string} filePath - 本地文件路径
|
* @param {string} filePath - 本地文件路径
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
get,
|
get,
|
||||||
post
|
post,
|
||||||
|
request
|
||||||
} from '@/utils/request.js'
|
} from '@/utils/request.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,8 +16,18 @@ export const reqHJIndexData = (projectId) => get(`HJGLIndex/GetJGLIndexItem?proj
|
|||||||
export const reqGetWeldJointByWeldJointId = (id) => get(`PipeJoint/getWeldJointByWeldJointId?WeldJointId=${id}`)
|
export const reqGetWeldJointByWeldJointId = (id) => get(`PipeJoint/getWeldJointByWeldJointId?WeldJointId=${id}`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 焊接日报填报(提交时传 WeldTypeId / WeldingMethodId,后端同步更新焊口对应字段)
|
* 搜索筛选焊口(下料/组对等中间页)
|
||||||
* @param {Object} data - { WeldJointId, Personid, time, weldingLocation, welderType, WeldTypeId, WeldingMethodId, PreWeldAttachUrl, PostWeldAttachUrl }
|
* @param {Object} params - { projectId, keyword?, pageIndex?, pageSize? }
|
||||||
|
*/
|
||||||
|
export const reqPipeJointWeldedJoints = (params = {}) => request('PipeJoint/GetWeldedJoints', {
|
||||||
|
method: 'GET',
|
||||||
|
data: params,
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 焊接日报填报(提交时传 WeldTypeId/WeldTypeCode、WeldingMethodId/WeldingMethodCode,后端同步更新焊口对应字段)
|
||||||
|
* @param {Object} data - { WeldJointId, Personid, time, weldingLocation, welderType, WeldTypeId, WeldTypeCode, WeldingMethodId, WeldingMethodCode, WeldingWire, WeldingRod, PreWeldAttachUrl, PostWeldAttachUrl }
|
||||||
*/
|
*/
|
||||||
export const reqSaveWeldingDailyByWeldJointId = (data={}) => post(
|
export const reqSaveWeldingDailyByWeldJointId = (data={}) => post(
|
||||||
`PreWeldingDaily/SaveWeldingDailyByWeldJointId`,data
|
`PreWeldingDaily/SaveWeldingDailyByWeldJointId`,data
|
||||||
@@ -205,8 +216,9 @@ export const reqGetAntiCorrosionCheck = (params = {}) => {
|
|||||||
// ========================= 日报审核 ====================================
|
// ========================= 日报审核 ====================================
|
||||||
/**
|
/**
|
||||||
* 获取焊接日报待审核列表
|
* 获取焊接日报待审核列表
|
||||||
* @param {Object} params - { projectId, unitWorkId?, weldingDate?, pipelineCode?, welderCode?, pageIndex? }
|
* @param {Object} params - { projectId, unitWorkId?, weldingDate?, pipelineCode?, welderCode?, pageIndex?, pageSize? }
|
||||||
* pageIndex 从 1 开始,小于等于 0 时返回全部记录
|
* pageIndex 从 1 开始;小于等于 0 时返回全部记录
|
||||||
|
* 响应 data.pageCount 为总记录数(不是总页数)
|
||||||
*/
|
*/
|
||||||
export const reqPendingWeldingDailyList = (params = {}) => get('/PreWeldingDaily/GetPendingWeldingDailyTempDetailList', params)
|
export const reqPendingWeldingDailyList = (params = {}) => get('/PreWeldingDaily/GetPendingWeldingDailyTempDetailList', params)
|
||||||
|
|
||||||
@@ -217,13 +229,19 @@ export const reqPendingWeldingDailyList = (params = {}) => get('/PreWeldingDaily
|
|||||||
export const reqPendingWeldingDailyDetail = (tempDetailId) => get(`/PreWeldingDaily/GetPendingWeldingDailyTempDetail?tempDetailId=${tempDetailId}`)
|
export const reqPendingWeldingDailyDetail = (tempDetailId) => get(`/PreWeldingDaily/GetPendingWeldingDailyTempDetail?tempDetailId=${tempDetailId}`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量审核通过焊接日报待审核明细
|
* 班组批量审核焊接日报待审核明细(状态 0 → 1)
|
||||||
|
* @param {Object} data - { TempDetailIds: string[], AuditMan: string }
|
||||||
|
*/
|
||||||
|
export const reqTeamAuditWeldingDaily = (data = {}) => post(`/PreWeldingDaily/TeamAuditPendingWeldingDailyTempDetails`, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专工批量审核焊接日报待审核明细(状态 1 → 2)
|
||||||
* @param {Object} data - { TempDetailIds: string[], AuditMan: string }
|
* @param {Object} data - { TempDetailIds: string[], AuditMan: string }
|
||||||
*/
|
*/
|
||||||
export const reqAuditWeldingDaily = (data = {}) => post(`/PreWeldingDaily/AuditPendingWeldingDailyTempDetails`, data)
|
export const reqAuditWeldingDaily = (data = {}) => post(`/PreWeldingDaily/AuditPendingWeldingDailyTempDetails`, data)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除(驳回)焊接日报待审核明细
|
* 批量删除未审核明细(仅状态 0)
|
||||||
* @param {Object} data - { TempDetailIds: string[] }
|
* @param {Object} data - { TempDetailIds: string[] }
|
||||||
*/
|
*/
|
||||||
export const reqDeleteWeldingDaily = (data = {}) => post(`/PreWeldingDaily/DeletePendingWeldingDailyTempDetails`, data)
|
export const reqDeleteWeldingDaily = (data = {}) => post(`/PreWeldingDaily/DeletePendingWeldingDailyTempDetails`, data)
|
||||||
@@ -243,7 +261,26 @@ export const reqWeldAppearanceJointDetail = (weldJointId) => get('/WeldAppearanc
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存焊缝外观检测记录
|
* 保存焊缝外观检测记录
|
||||||
* @param {Object} data - { AppearanceCheckId?, ProjectId, WeldJointId, IsQualified, CheckPerson, CheckTime, Remark, AttachUrl, CreateUser }
|
* @param {Object} data - { AppearanceCheckId?, ProjectId, WeldJointId, IsQualified, CheckPerson, CheckTime, Remark, AttachUrl, CreateUser, WeldReinforcement, WeldHeight, WeldWidth, SurfaceDefect, PreheatTemperature, InterpassTemperature }
|
||||||
*/
|
*/
|
||||||
export const reqSaveWeldAppearanceCheck = (data = {}) => post('/WeldAppearanceCheck/SaveRecord', data)
|
export const reqSaveWeldAppearanceCheck = (data = {}) => post('/WeldAppearanceCheck/SaveRecord', data)
|
||||||
|
|
||||||
|
// ========================= 焊接任务单 ====================================
|
||||||
|
/**
|
||||||
|
* 按班组查询任务单列表
|
||||||
|
* @param {Object} params - { projectId, teamGroupId?, unitWorkId? }
|
||||||
|
*/
|
||||||
|
export const reqWeldTaskListByTeamGroup = (params = {}) => get('WeldTask/GetTaskListByTeamGroup', params)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询任务单详情(含 Joints)
|
||||||
|
* @param {Object} params - { projectId, taskCode, unitWorkId? }
|
||||||
|
*/
|
||||||
|
export const reqWeldTaskDetail = (params = {}) => get('WeldTask/GetTaskDetail', params)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据任务单生成出库申请
|
||||||
|
* @param {Object} data - { ProjectId, TaskCode, PersonId }
|
||||||
|
*/
|
||||||
|
export const reqWeldTaskGenerateOutPlan = (data = {}) => post('WeldTask/GenerateOutPlan', data)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view v-for="field in extraFields" :key="field.key" class="history-card__row">
|
||||||
|
<text class="history-card__label">{{ field.label }}</text>
|
||||||
|
<text class="history-card__value">{{ latest[field.key] || '--' }}</text>
|
||||||
|
</view>
|
||||||
<view class="history-card__row">
|
<view class="history-card__row">
|
||||||
<text class="history-card__label">检测人</text>
|
<text class="history-card__label">检测人</text>
|
||||||
<text class="history-card__value">{{ latest.CheckPersonName || '--' }}</text>
|
<text class="history-card__value">{{ latest.CheckPersonName || '--' }}</text>
|
||||||
@@ -71,6 +75,10 @@
|
|||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view v-for="field in extraFields" :key="field.key" class="history-card__row">
|
||||||
|
<text class="history-card__label">{{ field.label }}</text>
|
||||||
|
<text class="history-card__value">{{ item[field.key] || '--' }}</text>
|
||||||
|
</view>
|
||||||
<view class="history-card__row">
|
<view class="history-card__row">
|
||||||
<text class="history-card__label">检测人</text>
|
<text class="history-card__label">检测人</text>
|
||||||
<text class="history-card__value">{{ item.CheckPersonName || '--' }}</text>
|
<text class="history-card__value">{{ item.CheckPersonName || '--' }}</text>
|
||||||
@@ -117,6 +125,15 @@
|
|||||||
const showPopup = ref(false)
|
const showPopup = ref(false)
|
||||||
const latest = computed(() => props.list[0] || null)
|
const latest = computed(() => props.list[0] || null)
|
||||||
|
|
||||||
|
const extraFields = [
|
||||||
|
{ label: '焊缝余高', key: 'WeldReinforcement' },
|
||||||
|
{ label: '焊缝高度', key: 'WeldHeight' },
|
||||||
|
{ label: '焊缝宽度', key: 'WeldWidth' },
|
||||||
|
{ label: '表面缺陷', key: 'SurfaceDefect' },
|
||||||
|
{ label: '预热温度', key: 'PreheatTemperature' },
|
||||||
|
{ label: '层间温度', key: 'InterpassTemperature' },
|
||||||
|
]
|
||||||
|
|
||||||
const isPass = (item) => item?.IsQualified === true
|
const isPass = (item) => item?.IsQualified === true
|
||||||
|
|
||||||
const qualifiedText = (item) => {
|
const qualifiedText = (item) => {
|
||||||
|
|||||||
+25
@@ -3,6 +3,7 @@
|
|||||||
"autoscan": true,
|
"autoscan": true,
|
||||||
"custom": {
|
"custom": {
|
||||||
"^nbd-print-prop$": "@/scanpages/components/nbd-print-prop.vue",
|
"^nbd-print-prop$": "@/scanpages/components/nbd-print-prop.vue",
|
||||||
|
"^nbd-print-prop-qr$": "@/scanpages/components/nbd-print-prop-qr.vue",
|
||||||
"^u-(.*)": "uview-pro/components/u-$1/u-$1.vue",
|
"^u-(.*)": "uview-pro/components/u-$1/u-$1.vue",
|
||||||
"^nbd-(.*)": "@/components/nbd-$1.vue"
|
"^nbd-(.*)": "@/components/nbd-$1.vue"
|
||||||
}
|
}
|
||||||
@@ -169,6 +170,30 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "焊缝检测"
|
"navigationBarTitleText": "焊缝检测"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hj/barcode_search",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "条码查询"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hj/weld_joint_search",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "选择焊口"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hj/weld_task_list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "焊接任务单"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hj/weld_task_detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "任务单详情"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,4 +337,10 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSkipByPath = (path) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: path
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -0,0 +1,748 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<u-popup v-model="localVisible" mode="bottom" :height="height" :closeable="true" @close="handleClose">
|
||||||
|
<view class="print-popup">
|
||||||
|
<!-- 标题栏 -->
|
||||||
|
<view class="print-popup__header">
|
||||||
|
<text class="print-popup__title">标签打印</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 隐藏画布:标签绘制 -->
|
||||||
|
<canvas
|
||||||
|
:id="canvasId"
|
||||||
|
:canvas-id="canvasId"
|
||||||
|
type="2d"
|
||||||
|
:style="canvasStyles"
|
||||||
|
/>
|
||||||
|
<!-- 隐藏画布:二维码生成(独立,避免占用标签画布导致只导出左上角) -->
|
||||||
|
<canvas
|
||||||
|
:id="barcodeCanvasId"
|
||||||
|
:canvas-id="barcodeCanvasId"
|
||||||
|
type="2d"
|
||||||
|
:style="barcodeCanvasStyles"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<scroll-view scroll-y="true" class="print-popup__body">
|
||||||
|
<!-- 预览区域 -->
|
||||||
|
<view class="preview-section" v-if="previewList.length > 0">
|
||||||
|
<text class="preview-section__title">打印预览</text>
|
||||||
|
<view class="preview-section__list">
|
||||||
|
<image
|
||||||
|
v-for="item in previewList"
|
||||||
|
:src="item.value"
|
||||||
|
:key="item.key"
|
||||||
|
class="preview-img"
|
||||||
|
mode="widthFix"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 打印机选择 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">打印机</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="deviceIndex" :range="deviceList" @change="onDeviceChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text
|
||||||
|
class="setting-row__value"
|
||||||
|
:class="{ 'setting-row__value--empty': !deviceList[deviceIndex]?.deviceId }"
|
||||||
|
>
|
||||||
|
{{ deviceList[deviceIndex]?.name || '未检测到打印机' }}
|
||||||
|
</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 出纸方向 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">出纸方向</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="rotationIndex" :range="rotationList" @change="onRotationChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ rotationList[rotationIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 纸张类型 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">纸张类型</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="gapIndex" :range="gapList" @change="onGapTypeChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ gapList[gapIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 打印浓度 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">打印浓度</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="darknessIndex" :range="darknessList" @change="onDarknessChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ darknessList[darknessIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 打印速度 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">打印速度</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="speedIndex" :range="speedList" @change="onPrintSpeedChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ speedList[speedIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 灰度阈值 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">灰度阈值</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<input class="setting-row__input" type="number" v-model="threshold" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- JSON配置模式 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">JSON配置</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<switch :checked="jsonMode" @change="onPrintModeChanged" style="transform: scale(0.75)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<view class="print-popup__footer">
|
||||||
|
<view class="footer-grid">
|
||||||
|
<view class="footer-btn" @click="handleStartDiscovery">
|
||||||
|
<u-icon name="search" :size="30" color="#2979ff" />
|
||||||
|
<text>搜索打印机</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn" @click="handleStopDiscovery">
|
||||||
|
<u-icon name="close-circle" :size="30" color="#f56c6c" />
|
||||||
|
<text>停止搜索</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn" @click="handleOpenPrinter">
|
||||||
|
<u-icon name="link" :size="30" color="#2979ff" />
|
||||||
|
<text>连接打印机</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn" @click="handleClosePrinter">
|
||||||
|
<u-icon name="minus-circle" :size="30" color="#f56c6c" />
|
||||||
|
<text>断开连接</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn footer-btn--print" @click="handlePrintLabel">
|
||||||
|
<u-icon v-if="!printing" name="printer" :size="30" color="#fff" />
|
||||||
|
<u-icon v-else name="reload" :size="30" color="#fff" class="spinning" />
|
||||||
|
<text>{{ printing ? '打印中...' : '打印' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'
|
||||||
|
import {
|
||||||
|
DrawType,
|
||||||
|
LPAPIFactory
|
||||||
|
} from '@/assets/js/js_sdk'
|
||||||
|
import '@/utils/bwipjs-polyfill.js'
|
||||||
|
import bwipjs from '@/scanpages/assets/bwip-js/bwip-js.mjs'
|
||||||
|
|
||||||
|
// ===== Props =====
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Boolean, default: false },
|
||||||
|
height: { type: String, default: '85%' },
|
||||||
|
labelWidth: { type: Number, default: 50 },
|
||||||
|
labelHeight: { type: Number, default: 30 },
|
||||||
|
margin: { type: Number, default: 2 },
|
||||||
|
barcodeText: { type: String, default: '12345678' },
|
||||||
|
barcodeTopText: { type: String, default: '' },
|
||||||
|
barcodeBottomText: { type: String, default: '' }
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'close', 'printed', 'error'])
|
||||||
|
|
||||||
|
const instance = getCurrentInstance()
|
||||||
|
|
||||||
|
// ===== 响应式数据 =====
|
||||||
|
const canvasId = 'lpapi-ble-popup-qr'
|
||||||
|
const barcodeCanvasId = 'lpapi-ble-barcode-qr'
|
||||||
|
const labelW = ref(960)
|
||||||
|
const labelH = ref(960)
|
||||||
|
const barcodeCanvasPx = ref(320)
|
||||||
|
const canvasStyles = ref({})
|
||||||
|
const barcodeCanvasStyles = ref({})
|
||||||
|
const localVisible = ref(false)
|
||||||
|
const deviceList = ref([{ name: '未检测到打印机' }])
|
||||||
|
const deviceIndex = ref(0)
|
||||||
|
const rotationIndex = ref(1)
|
||||||
|
const rotationList = [
|
||||||
|
{ name: '横向打印', value: 0 },
|
||||||
|
{ name: '右转90度', value: 90 },
|
||||||
|
{ name: '转转180度', value: 180 },
|
||||||
|
{ name: '左转90度', value: 270 }
|
||||||
|
]
|
||||||
|
const gapList = [
|
||||||
|
{ name: '随打印机设置', value: 255 },
|
||||||
|
{ name: '小票纸', value: 0 },
|
||||||
|
{ name: '不干胶', value: 2 },
|
||||||
|
{ name: '卡纸', value: 3 }
|
||||||
|
]
|
||||||
|
const gapIndex = ref(0)
|
||||||
|
const darknessList = [
|
||||||
|
{ name: '随打印机设置', value: 255 },
|
||||||
|
{ name: '6 (正常)', value: 6 },
|
||||||
|
{ name: '7', value: 7 },
|
||||||
|
{ name: '8', value: 8 },
|
||||||
|
{ name: '9', value: 9 },
|
||||||
|
{ name: '10 (较浓)', value: 10 },
|
||||||
|
{ name: '11', value: 11 },
|
||||||
|
{ name: '12', value: 12 },
|
||||||
|
{ name: '13', value: 13 },
|
||||||
|
{ name: '14', value: 14 },
|
||||||
|
{ name: '15 (最浓)', value: 15 }
|
||||||
|
]
|
||||||
|
const darknessIndex = ref(0)
|
||||||
|
const speedList = [
|
||||||
|
{ name: '随打印机设置', value: 255 },
|
||||||
|
{ name: '最慢', value: 1 },
|
||||||
|
{ name: '较慢', value: 2 },
|
||||||
|
{ name: '正常', value: 3 },
|
||||||
|
{ name: '较快', value: 4 },
|
||||||
|
{ name: '最快', value: 5 }
|
||||||
|
]
|
||||||
|
const speedIndex = ref(0)
|
||||||
|
const threshold = ref(128)
|
||||||
|
const jsonMode = ref(false)
|
||||||
|
const printing = ref(false)
|
||||||
|
const isWeiXin = ref(false)
|
||||||
|
const isAlipay = ref(false)
|
||||||
|
const lpapi = ref(undefined)
|
||||||
|
const context = ref(undefined)
|
||||||
|
const previewList = ref([])
|
||||||
|
|
||||||
|
// ===== 取值辅助 =====
|
||||||
|
const getDevice = () => {
|
||||||
|
return deviceList.value[deviceIndex.value]
|
||||||
|
}
|
||||||
|
const getOrientation = () => {
|
||||||
|
return rotationList[rotationIndex.value]?.value || 0
|
||||||
|
}
|
||||||
|
const getGapType = () => {
|
||||||
|
return gapList[gapIndex.value]?.value || 255
|
||||||
|
}
|
||||||
|
const getPrintDarkness = () => {
|
||||||
|
return darknessList[darknessIndex.value]?.value || 255
|
||||||
|
}
|
||||||
|
const getPrintSpeed = () => {
|
||||||
|
return speedList[speedIndex.value]?.value || 255
|
||||||
|
}
|
||||||
|
const getThreshold = () => {
|
||||||
|
return Number(threshold.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Canvas 样式 =====
|
||||||
|
const updateCanvasStyle = () => {
|
||||||
|
var pos = { position: 'absolute' }
|
||||||
|
if (isWeiXin.value) {
|
||||||
|
pos.left = '-999999rpx'
|
||||||
|
pos.top = '-999999rpx'
|
||||||
|
pos.opacity = '0'
|
||||||
|
pos.pointerEvents = 'none'
|
||||||
|
pos.zIndex = '-1'
|
||||||
|
} else {
|
||||||
|
pos.left = '-999999rpx'
|
||||||
|
pos.top = '-999999rpx'
|
||||||
|
}
|
||||||
|
canvasStyles.value = Object.assign(
|
||||||
|
{ width: labelW.value + 'px', height: labelH.value + 'px' },
|
||||||
|
pos
|
||||||
|
)
|
||||||
|
barcodeCanvasStyles.value = Object.assign(
|
||||||
|
{
|
||||||
|
width: barcodeCanvasPx.value + 'px',
|
||||||
|
height: barcodeCanvasPx.value + 'px',
|
||||||
|
},
|
||||||
|
pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Canvas 更新 =====
|
||||||
|
const updateCanvas = (jobInfo) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (jobInfo && jobInfo.canvas) {
|
||||||
|
labelW.value = jobInfo.canvas.width
|
||||||
|
labelH.value = jobInfo.canvas.height
|
||||||
|
updateCanvasStyle()
|
||||||
|
}
|
||||||
|
setTimeout(() => resolve(true), 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 二维码生成(bwip-js qrcode,保持正方形不拉伸)=====
|
||||||
|
const _renderBwipjs = (canvas, opts) => {
|
||||||
|
try {
|
||||||
|
bwipjs.toCanvas(canvas, opts)
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof canvas.getContext === 'function') {
|
||||||
|
var proto = Object.getPrototypeOf(canvas)
|
||||||
|
var ctorName = proto && proto.constructor && proto.constructor.name
|
||||||
|
if (ctorName && !(/HTMLCanvasElement|OffscreenCanvas/).test(ctorName)) {
|
||||||
|
try {
|
||||||
|
Object.defineProperty(proto.constructor, 'name', { configurable: true, value: 'HTMLCanvasElement' })
|
||||||
|
bwipjs.toCanvas(canvas, opts)
|
||||||
|
Object.defineProperty(proto.constructor, 'name', { configurable: true, value: ctorName })
|
||||||
|
return
|
||||||
|
} catch (e2) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成正方形二维码图片(使用独立画布,避免与标签画布尺寸冲突)
|
||||||
|
* @param {string} text
|
||||||
|
* @param {number} sizeMM 边长(毫米)
|
||||||
|
*/
|
||||||
|
const generateBarcodeImage = (text, sizeMM) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var dpi = 203
|
||||||
|
var pxPerMM = dpi / 25.4
|
||||||
|
var tw = Math.max(160, Math.round(sizeMM * pxPerMM))
|
||||||
|
barcodeCanvasPx.value = tw
|
||||||
|
updateCanvasStyle()
|
||||||
|
|
||||||
|
var baseScale = Math.max(4, Math.floor(tw / 33))
|
||||||
|
var bwipOpts = {
|
||||||
|
bcid: 'qrcode',
|
||||||
|
text: text || '',
|
||||||
|
scale: baseScale,
|
||||||
|
includetext: false,
|
||||||
|
padding: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
var query = uni.createSelectorQuery().in(instance)
|
||||||
|
query.select('#' + barcodeCanvasId).node().exec((res) => {
|
||||||
|
try {
|
||||||
|
if (!res || !res[0] || !res[0].node) {
|
||||||
|
return reject(new Error('二维码 canvas 未找到'))
|
||||||
|
}
|
||||||
|
var canvas = res[0].node
|
||||||
|
// 先固定位图尺寸,再交给 bwip 绘制(微信 2d canvas 不独立设置会沿用错误尺寸)
|
||||||
|
canvas.width = tw
|
||||||
|
canvas.height = tw
|
||||||
|
_renderBwipjs(canvas, bwipOpts)
|
||||||
|
|
||||||
|
var outW = canvas.width || tw
|
||||||
|
var outH = canvas.height || tw
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvas: canvas,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: outW,
|
||||||
|
height: outH,
|
||||||
|
destWidth: outW,
|
||||||
|
destHeight: outH,
|
||||||
|
success: (t) => {
|
||||||
|
if (isWeiXin.value) {
|
||||||
|
var img = canvas.createImage()
|
||||||
|
img.src = t.tempFilePath
|
||||||
|
img.onload = () => { resolve(img) }
|
||||||
|
img.onerror = (e) => { reject(e) }
|
||||||
|
} else {
|
||||||
|
resolve(t.tempFilePath)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (e) => { reject(e) }
|
||||||
|
})
|
||||||
|
} catch (e) { reject(e) }
|
||||||
|
})
|
||||||
|
}, 50)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在可用区域内居中放置正方形二维码
|
||||||
|
* @param {number} areaX
|
||||||
|
* @param {number} areaY
|
||||||
|
* @param {number} areaW
|
||||||
|
* @param {number} areaH
|
||||||
|
*/
|
||||||
|
const getQrDrawRect = (areaX, areaY, areaW, areaH) => {
|
||||||
|
var size = Math.min(areaW, areaH)
|
||||||
|
return {
|
||||||
|
x: areaX + (areaW - size) / 2,
|
||||||
|
y: areaY + (areaH - size) / 2,
|
||||||
|
size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 标签绘制(总入口) =====
|
||||||
|
const printLabel = (isPreview) => {
|
||||||
|
if (jsonMode.value) {
|
||||||
|
return printLabelWithJsonMode(isPreview)
|
||||||
|
} else {
|
||||||
|
return printLabelWithDrawMode(isPreview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const printLabelWithDrawMode = async (isPreview) => {
|
||||||
|
var api = lpapi.value
|
||||||
|
var lW = props.labelWidth
|
||||||
|
var lH = props.labelHeight
|
||||||
|
var m = props.margin
|
||||||
|
var uW = lW - m * 2
|
||||||
|
|
||||||
|
var jobInfo = api.startJob({
|
||||||
|
context: context.value,
|
||||||
|
width: lW,
|
||||||
|
height: lH,
|
||||||
|
orientation: getOrientation(),
|
||||||
|
isPreview: isPreview
|
||||||
|
})
|
||||||
|
await updateCanvas(jobInfo)
|
||||||
|
|
||||||
|
if (props.barcodeTopText) {
|
||||||
|
api.drawText({
|
||||||
|
text: props.barcodeTopText,
|
||||||
|
x: m,
|
||||||
|
y: m,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 4,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var barcodeY = m + (props.barcodeTopText ? 7 : 0)
|
||||||
|
var barcodeH = lH - m * 2 - (props.barcodeTopText ? 7 : 0) - (props.barcodeBottomText ? 7 : 0)
|
||||||
|
try {
|
||||||
|
var rect = getQrDrawRect(m, barcodeY, uW, barcodeH)
|
||||||
|
var img = await generateBarcodeImage(props.barcodeText, rect.size)
|
||||||
|
api.drawImage({ img: img, x: rect.x, y: rect.y, width: rect.size, height: rect.size })
|
||||||
|
} catch (e) {
|
||||||
|
console.error('二维码绘制失败:', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.barcodeBottomText) {
|
||||||
|
var by = lH - m - 5
|
||||||
|
api.drawText({
|
||||||
|
text: props.barcodeBottomText,
|
||||||
|
x: m,
|
||||||
|
y: by,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 3.5,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.commitJob({
|
||||||
|
gapType: getGapType(),
|
||||||
|
printDarkness: getPrintDarkness(),
|
||||||
|
printSpeed: getPrintSpeed()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const printLabelWithJsonMode = (isPreview) => {
|
||||||
|
var device = getDevice()
|
||||||
|
var lW = props.labelWidth
|
||||||
|
var lH = props.labelHeight
|
||||||
|
var m = props.margin
|
||||||
|
var uW = lW - m * 2
|
||||||
|
|
||||||
|
var jobPage = []
|
||||||
|
|
||||||
|
if (props.barcodeTopText) {
|
||||||
|
jobPage.push({
|
||||||
|
type: DrawType.text,
|
||||||
|
text: props.barcodeTopText,
|
||||||
|
x: m,
|
||||||
|
y: m,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 4,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var barcodeY = m + (props.barcodeTopText ? 7 : 0)
|
||||||
|
var barcodeH = lH - m * 2 - (props.barcodeTopText ? 7 : 0) - (props.barcodeBottomText ? 7 : 0)
|
||||||
|
var rect = getQrDrawRect(m, barcodeY, uW, barcodeH)
|
||||||
|
return generateBarcodeImage(props.barcodeText, rect.size).then((img) => {
|
||||||
|
jobPage.push({
|
||||||
|
type: DrawType.image,
|
||||||
|
img: img,
|
||||||
|
x: rect.x,
|
||||||
|
y: rect.y,
|
||||||
|
width: rect.size,
|
||||||
|
height: rect.size
|
||||||
|
})
|
||||||
|
|
||||||
|
if (props.barcodeBottomText) {
|
||||||
|
jobPage.push({
|
||||||
|
type: DrawType.text,
|
||||||
|
text: props.barcodeBottomText,
|
||||||
|
x: m,
|
||||||
|
y: lH - m - 5,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 3.5,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpapi.value.print({
|
||||||
|
jobInfo: {
|
||||||
|
jobWidth: lW,
|
||||||
|
jobHeight: lH,
|
||||||
|
orientation: getOrientation(),
|
||||||
|
isPreview: isPreview
|
||||||
|
},
|
||||||
|
printerInfo: {
|
||||||
|
name: device ? device.name : undefined,
|
||||||
|
deviceId: device ? device.deviceId : undefined
|
||||||
|
},
|
||||||
|
jobPage: jobPage,
|
||||||
|
onJobCreated: (jobInfo) => {
|
||||||
|
return updateCanvas(jobInfo)
|
||||||
|
},
|
||||||
|
onPageComplete: (res) => {
|
||||||
|
// 标签页面渲染完毕时的回调
|
||||||
|
},
|
||||||
|
onPagePrintComplete: (res) => {
|
||||||
|
// 标签页面打印完毕时的回调
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 初始化 =====
|
||||||
|
const initPrinter = () => {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
isWeiXin.value = true
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
isAlipay.value = true
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
updateCanvasStyle()
|
||||||
|
|
||||||
|
lpapi.value = LPAPIFactory.getInstance({ showLog: 4 })
|
||||||
|
|
||||||
|
lpapi.value.startDiscovery({
|
||||||
|
timeout: 0,
|
||||||
|
deviceFound: (devices) => {
|
||||||
|
if (devices && devices.length > 0) {
|
||||||
|
deviceList.value.splice(0)
|
||||||
|
deviceList.value.push(...devices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isWeiXin.value) {
|
||||||
|
context.value = lpapi.value.createDrawContext()
|
||||||
|
} else {
|
||||||
|
context.value = lpapi.value.createDrawContext({ canvasId: canvasId })
|
||||||
|
}
|
||||||
|
if (context.value) {
|
||||||
|
lpapi.value.setDrawContext(context.value)
|
||||||
|
handlePreviewLabel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 选择器变更 =====
|
||||||
|
const onDeviceChanged = (e) => {
|
||||||
|
deviceIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onRotationChanged = (e) => {
|
||||||
|
rotationIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onGapTypeChanged = (e) => {
|
||||||
|
gapIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onDarknessChanged = (e) => {
|
||||||
|
darknessIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onPrintSpeedChanged = (e) => {
|
||||||
|
speedIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onPrintModeChanged = (e) => {
|
||||||
|
jsonMode.value = e.detail.value
|
||||||
|
handlePreviewLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 打印机操作 =====
|
||||||
|
const handleStartDiscovery = () => {
|
||||||
|
uni.showLoading({ title: '正在搜索打印机...' })
|
||||||
|
lpapi.value.startDiscovery({
|
||||||
|
timeout: 5000,
|
||||||
|
deviceFound: (devices) => {
|
||||||
|
if (devices && devices.length > 0) {
|
||||||
|
deviceList.value.splice(0)
|
||||||
|
deviceList.value.push(...devices)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
adapterStateChange: (result) => {
|
||||||
|
if (!result.discovering) {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleStopDiscovery = () => {
|
||||||
|
lpapi.value.stopDiscovery()
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
const handleOpenPrinter = () => {
|
||||||
|
const currDevice = getDevice()
|
||||||
|
if (!currDevice || !currDevice.deviceId) {
|
||||||
|
uni.showToast({ title: '未检测到打印机', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.showLoading({ title: '正在连接打印机...' })
|
||||||
|
lpapi.value.openPrinter({
|
||||||
|
name: currDevice.name,
|
||||||
|
deviceId: currDevice.deviceId,
|
||||||
|
tryTimes: isAlipay.value ? 1 : 5,
|
||||||
|
success: (resp) => {
|
||||||
|
console.log('---- 【打印机连接成功】')
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '打印机连接成功!', icon: 'success' })
|
||||||
|
},
|
||||||
|
fail: (resp) => {
|
||||||
|
console.warn('---- 【打印机连接失败】:', JSON.stringify(resp))
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '打印机连接失败!', icon: 'error' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleClosePrinter = () => {
|
||||||
|
console.log('---- 关闭打印机!')
|
||||||
|
lpapi.value.closePrinter()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 预览 =====
|
||||||
|
const handlePreviewLabel = () => {
|
||||||
|
previewList.value.splice(0)
|
||||||
|
printLabel(true).then((res) => {
|
||||||
|
if (res.statusCode === 0) {
|
||||||
|
res.previewData.forEach((v) => {
|
||||||
|
previewList.value.push({
|
||||||
|
value: v,
|
||||||
|
key: Date.now() + '-' + Math.random() * 1000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.warn('预览失败:', res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 打印 =====
|
||||||
|
const handlePrintLabel = async () => {
|
||||||
|
printing.value = true
|
||||||
|
try {
|
||||||
|
var d = getDevice()
|
||||||
|
if (!d || !d.deviceId) {
|
||||||
|
printing.value = false
|
||||||
|
return uni.showToast({ title: '未检测到打印机', icon: 'none' })
|
||||||
|
}
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
lpapi.value.openPrinter({
|
||||||
|
name: d.name,
|
||||||
|
deviceId: d.deviceId,
|
||||||
|
tryTimes: 5,
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
})
|
||||||
|
})
|
||||||
|
var res = await printLabel(false)
|
||||||
|
if (res.statusCode === 0) {
|
||||||
|
uni.showToast({ title: '打印成功!', icon: 'success' })
|
||||||
|
emit('printed', { statusCode: 0 })
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: res.errMsg || '打印失败!', icon: 'error' })
|
||||||
|
emit('error', res)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('打印异常:', e)
|
||||||
|
uni.showToast({ title: '打印机连接失败!', icon: 'error' })
|
||||||
|
emit('error', e)
|
||||||
|
} finally {
|
||||||
|
printing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 关闭弹窗 =====
|
||||||
|
const handleClose = () => {
|
||||||
|
handleClosePrinter()
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 监听器 =====
|
||||||
|
watch(() => props.modelValue, (val) => {
|
||||||
|
localVisible.value = val
|
||||||
|
if (val) nextTick(() => initPrinter())
|
||||||
|
})
|
||||||
|
watch(localVisible, (val) => {
|
||||||
|
emit('update:modelValue', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (lpapi.value) {
|
||||||
|
lpapi.value.closePrinter()
|
||||||
|
lpapi.value.stopDiscovery()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.print-popup { display: flex; flex-direction: column; height: 100%; background: #f5f6f8;
|
||||||
|
&__header { flex-shrink: 0; padding: 28rpx 32rpx 20rpx; text-align: center; border-bottom: 1rpx solid #e8ecf1; }
|
||||||
|
&__title { font-size: 32rpx; font-weight: 700; color: #1a1a2e; }
|
||||||
|
&__body { flex: 1; overflow-y: auto; overflow-x: hidden; box-sizing: border-box; padding: 20rpx 24rpx; }
|
||||||
|
&__footer { flex-shrink: 0; padding: 12rpx 24rpx; padding-bottom: calc(12rpx + env(safe-area-inset-bottom)); background: #fff; border-top: 1rpx solid #e8ecf1; }
|
||||||
|
}
|
||||||
|
.footer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12rpx; }
|
||||||
|
.footer-btn { display: flex; align-items: center; justify-content: center; gap: 8rpx; height: 76rpx; font-size: 26rpx; font-weight: 500; border-radius: 12rpx; background: #f5f6f8; color: #1a1a2e; transition: transform .15s, box-shadow .15s;
|
||||||
|
&:active { transform: scale(.95); opacity: .85; }
|
||||||
|
&--print { background: linear-gradient(135deg, #2979ff, #5a9aff); color: #fff; box-shadow: 0 4rpx 16rpx rgba(41,121,255,.35); grid-column: 1 / -1;}
|
||||||
|
}
|
||||||
|
.spinning { animation: spin .8s linear infinite; }
|
||||||
|
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||||||
|
.setting-row { display: flex; align-items: center; justify-content: space-between; box-sizing: border-box; padding: 22rpx 24rpx; margin-bottom: 12rpx; background: #fff; border-radius: 12rpx;
|
||||||
|
&__label { font-size: 26rpx; color: #6b7c93; flex-shrink: 0; width: 160rpx; }
|
||||||
|
&__right { flex: 1; display: flex; justify-content: flex-end; }
|
||||||
|
&__picker { display: flex; align-items: center; gap: 8rpx; }
|
||||||
|
&__value { font-size: 26rpx; color: #1a1a2e; font-weight: 500;
|
||||||
|
&--empty { color: #b0bec5; }
|
||||||
|
}
|
||||||
|
&__input { flex: 1; font-size: 26rpx; color: #1a1a2e; text-align: right; padding: 4rpx 0; }
|
||||||
|
}
|
||||||
|
.preview-section { margin-bottom: 24rpx; padding: 20rpx; background: #fff; border-radius: 12rpx; overflow: hidden;
|
||||||
|
&__title { display: block; font-size: 26rpx; font-weight: 600; color: #1a1a2e; margin-bottom: 16rpx; }
|
||||||
|
&__list { display: flex; flex-wrap: wrap; justify-content: center; gap: 16rpx; }
|
||||||
|
}
|
||||||
|
.preview-img { width: 100%; border: 1rpx dashed #ccc; border-radius: 4rpx; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
<template>
|
||||||
|
<view class="page-list">
|
||||||
|
<!-- 关键字搜索 -->
|
||||||
|
<view class="filter-header">
|
||||||
|
<view class="search-row">
|
||||||
|
<u-search
|
||||||
|
v-model="keyword"
|
||||||
|
placeholder="请输入条码关键字(至少2位)"
|
||||||
|
:show-action="false"
|
||||||
|
shape="square"
|
||||||
|
bg-color="#f5f6f8"
|
||||||
|
@change="handleSearch"
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view
|
||||||
|
class="list-scroll"
|
||||||
|
scroll-y
|
||||||
|
@scrolltolower="loadMore"
|
||||||
|
refresher-enabled
|
||||||
|
:refresher-triggered="refreshing"
|
||||||
|
@refresherrefresh="handleRefresh"
|
||||||
|
>
|
||||||
|
<view class="list-wrap">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in listData"
|
||||||
|
:key="item.Id || item.BarCode || index"
|
||||||
|
class="card-item"
|
||||||
|
>
|
||||||
|
<view class="card-header">
|
||||||
|
<text class="card-code">{{ item.BarCode || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-body">
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">材料编码</text>
|
||||||
|
<text class="row-value">{{ item.MaterialCode || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">数量</text>
|
||||||
|
<text class="row-value">{{ formatQuantity(item.Quantity) }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card-footer">
|
||||||
|
<view
|
||||||
|
class="print-btn"
|
||||||
|
@click.stop="handlePrint(item)"
|
||||||
|
>
|
||||||
|
<text class="print-btn__text">打印</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<u-empty
|
||||||
|
v-if="!loading && listData.length === 0"
|
||||||
|
mode="list"
|
||||||
|
:text="emptyText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-if="loading && listData.length > 0"
|
||||||
|
class="loading-more"
|
||||||
|
>
|
||||||
|
<u-loading
|
||||||
|
mode="circle"
|
||||||
|
size="32"
|
||||||
|
/>
|
||||||
|
<text>加载中...</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-if="!loading && !hasMore && listData.length > 0"
|
||||||
|
class="no-more"
|
||||||
|
>
|
||||||
|
<text>— 没有更多了 —</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 标签预览与打印 -->
|
||||||
|
<nbd-print-prop-qr
|
||||||
|
v-model="showPrint"
|
||||||
|
:labelWidth="50"
|
||||||
|
:labelHeight="30"
|
||||||
|
:margin="2"
|
||||||
|
:barcodeText="printBarcode"
|
||||||
|
:barcodeTopText="printTop"
|
||||||
|
:barcodeBottomText="printBottom"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
/**
|
||||||
|
* 条码查询:按条码关键字分页查询入库明细,支持标签预览与蓝牙打印
|
||||||
|
*/
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { reqGetInputDetailBarCodes } from '@/api/base.js'
|
||||||
|
|
||||||
|
/** 最少关键字长度(文档建议 2~3) */
|
||||||
|
const MIN_KEYWORD_LEN = 2
|
||||||
|
|
||||||
|
/** 搜索关键字 */
|
||||||
|
const keyword = ref('')
|
||||||
|
/** 列表数据 */
|
||||||
|
const listData = ref([])
|
||||||
|
/** 加载中 */
|
||||||
|
const loading = ref(false)
|
||||||
|
/** 下拉刷新中 */
|
||||||
|
const refreshing = ref(false)
|
||||||
|
/** 是否还有更多 */
|
||||||
|
const hasMore = ref(true)
|
||||||
|
/** 当前页码(从 1 开始) */
|
||||||
|
const currentPage = ref(1)
|
||||||
|
/** 每页条数 */
|
||||||
|
const pageSize = 20
|
||||||
|
/** 总页数(接口 pageCount) */
|
||||||
|
const pageCount = ref(0)
|
||||||
|
/** 搜索防抖定时器 */
|
||||||
|
let searchTimer = null
|
||||||
|
|
||||||
|
/** 是否展示打印弹窗 */
|
||||||
|
const showPrint = ref(false)
|
||||||
|
/** 打印:条码内容 */
|
||||||
|
const printBarcode = ref('')
|
||||||
|
/** 打印:条码上方文案 */
|
||||||
|
const printTop = ref('')
|
||||||
|
/** 打印:条码下方文案 */
|
||||||
|
const printBottom = ref('')
|
||||||
|
|
||||||
|
/** 空状态文案 */
|
||||||
|
const emptyText = computed(() => {
|
||||||
|
const kw = keyword.value.trim()
|
||||||
|
if (!kw) return '请输入条码关键字查询'
|
||||||
|
if (kw.length < MIN_KEYWORD_LEN) return `请至少输入${MIN_KEYWORD_LEN}个字符`
|
||||||
|
return '暂无数据'
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数量展示
|
||||||
|
* @param {unknown} q
|
||||||
|
*/
|
||||||
|
const formatQuantity = (q) => {
|
||||||
|
if (q === undefined || q === null || q === '') return '--'
|
||||||
|
return String(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从响应中取出当前页列表
|
||||||
|
* @param {any} data
|
||||||
|
* @returns {array}
|
||||||
|
*/
|
||||||
|
const pickList = (data) => {
|
||||||
|
if (!data || typeof data !== 'object') return []
|
||||||
|
if (Array.isArray(data.getDataList)) return data.getDataList
|
||||||
|
if (Array.isArray(data.list)) return data.list
|
||||||
|
if (Array.isArray(data)) return data
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 清空本地列表状态 */
|
||||||
|
const clearList = () => {
|
||||||
|
listData.value = []
|
||||||
|
hasMore.value = false
|
||||||
|
pageCount.value = 0
|
||||||
|
refreshing.value = false
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拉取一页数据;关键字为空或过短时不请求
|
||||||
|
* @param {boolean} isRefresh
|
||||||
|
*/
|
||||||
|
const fetchData = async (isRefresh = false) => {
|
||||||
|
const kw = keyword.value.trim()
|
||||||
|
if (!kw || kw.length < MIN_KEYWORD_LEN) {
|
||||||
|
clearList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (loading.value || (!isRefresh && !hasMore.value)) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
if (isRefresh) refreshing.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await reqGetInputDetailBarCodes({
|
||||||
|
barCodeKeyword: kw,
|
||||||
|
pageIndex: currentPage.value,
|
||||||
|
pageSize,
|
||||||
|
})
|
||||||
|
const data = res?.data ?? {}
|
||||||
|
const pageData = pickList(data)
|
||||||
|
const totalPages = Number(data.pageCount) || 0
|
||||||
|
pageCount.value = totalPages
|
||||||
|
if (totalPages > 0) {
|
||||||
|
hasMore.value = currentPage.value < totalPages
|
||||||
|
} else {
|
||||||
|
hasMore.value = pageData.length >= pageSize
|
||||||
|
}
|
||||||
|
listData.value = isRefresh ? pageData : listData.value.concat(pageData)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('条码列表加载失败:', e)
|
||||||
|
uni.showToast({ title: '加载失败,请重试', icon: 'none' })
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
refreshing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置到第一页并重新加载 */
|
||||||
|
const resetAndLoad = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
hasMore.value = true
|
||||||
|
listData.value = []
|
||||||
|
fetchData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 下拉刷新 */
|
||||||
|
const handleRefresh = () => {
|
||||||
|
const kw = keyword.value.trim()
|
||||||
|
if (!kw || kw.length < MIN_KEYWORD_LEN) {
|
||||||
|
clearList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resetAndLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 关键字变更(防抖);清空或过短时直接清空列表 */
|
||||||
|
const handleSearch = () => {
|
||||||
|
if (searchTimer) clearTimeout(searchTimer)
|
||||||
|
searchTimer = setTimeout(() => {
|
||||||
|
const kw = keyword.value.trim()
|
||||||
|
if (!kw || kw.length < MIN_KEYWORD_LEN) {
|
||||||
|
clearList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resetAndLoad()
|
||||||
|
}, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 上拉加载更多 */
|
||||||
|
const loadMore = () => {
|
||||||
|
if (!loading.value && hasMore.value && keyword.value.trim().length >= MIN_KEYWORD_LEN) {
|
||||||
|
currentPage.value += 1
|
||||||
|
fetchData(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开标签预览与打印(与材料详情一致:图内编码为 MaterialCode)
|
||||||
|
* @param {object} item
|
||||||
|
*/
|
||||||
|
const handlePrint = (item) => {
|
||||||
|
const code = item.MaterialCode || ''
|
||||||
|
if (!code) {
|
||||||
|
uni.showToast({ title: '缺少材料编码', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printBarcode.value = code
|
||||||
|
printTop.value = item.BarCode || ''
|
||||||
|
printBottom.value = item.Quantity != null && item.Quantity !== ''
|
||||||
|
? `数量 ${item.Quantity}`
|
||||||
|
: ''
|
||||||
|
showPrint.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
// 空关键字不自动请求
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 16rpx;
|
||||||
|
border-top: 1rpx solid #f0f0f0;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
.print-btn {
|
||||||
|
padding: 10rpx 28rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
background: #2979ff;
|
||||||
|
}
|
||||||
|
.print-btn__text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+212
-110
@@ -2,38 +2,43 @@
|
|||||||
<view class="page-list">
|
<view class="page-list">
|
||||||
<!-- 头部过滤区域 -->
|
<!-- 头部过滤区域 -->
|
||||||
<view class="filter-header">
|
<view class="filter-header">
|
||||||
<!-- 第一行:管线编号搜索 -->
|
<!-- 焊工编号 + 焊接日期 + 单位工程 -->
|
||||||
<view class="search-row">
|
<view class="filter-grid">
|
||||||
<u-search v-model="pipelineCode" placeholder="请输入管线编号" :show-action="false" shape="square"
|
<view class="filter-item">
|
||||||
bg-color="#f5f6f8" @change="handleSearch" />
|
<view class="filter-btn" @click="handleShowUnitWorkSelect">
|
||||||
</view>
|
<text class="filter-btn__text" :class="{ 'filter-btn__text--placeholder': !selectedUnitWork }">
|
||||||
<!-- 第二行:焊工编号 + 焊接日期 + 单位工程 -->
|
{{ selectedUnitWork?.BaseInfoName || '单位工程' }}
|
||||||
<view class="filter-row">
|
|
||||||
<view class="welder-input-wrap">
|
|
||||||
<input class="welder-input" v-model="welderCode" placeholder="焊工编号" confirm-type="search"
|
|
||||||
@confirm="handleSearch" @blur="handleSearch" />
|
|
||||||
</view>
|
|
||||||
<picker mode="date" :value="weldingDate" @change="onDateChange">
|
|
||||||
<view class="filter-btn">
|
|
||||||
<text class="filter-btn__text" :class="{ 'filter-btn__text--placeholder': !weldingDate }">
|
|
||||||
{{ weldingDate || '焊接日期' }}
|
|
||||||
</text>
|
</text>
|
||||||
<u-icon v-if="weldingDate" name="close" :size="20" color="#999" @click.stop="onDateClear" />
|
<u-icon name="arrow-down" :size="18" color="#999" />
|
||||||
<u-icon v-else name="calendar" :size="24" color="#999" />
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="filter-item">
|
||||||
|
<picker class="filter-picker" mode="date" :value="weldingDate" @change="onDateChange">
|
||||||
|
<view class="filter-btn">
|
||||||
|
<text class="filter-btn__text" :class="{ 'filter-btn__text--placeholder': !weldingDate }">
|
||||||
|
{{ weldingDate || '焊接日期' }}
|
||||||
|
</text>
|
||||||
|
<u-icon v-if="weldingDate" name="close" :size="20" color="#999" @click.stop="onDateClear" />
|
||||||
|
<u-icon v-else name="calendar" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
<view class="filter-item">
|
||||||
|
<u-search v-model="pipelineCode" placeholder="请输入管线编号" :show-action="false" shape="square"
|
||||||
|
height="70" bg-color="#f5f6f8" @change="handleSearch" />
|
||||||
|
</view>
|
||||||
|
<view class="filter-item">
|
||||||
|
<view class="filter-btn">
|
||||||
|
<input class="welder-input" v-model="welderCode" placeholder="焊工编号" confirm-type="search"
|
||||||
|
@confirm="handleSearch" @blur="handleSearch" />
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
|
||||||
<view class="filter-btn" @click="handleShowUnitWorkSelect">
|
|
||||||
<text class="filter-btn__text" :class="{ 'filter-btn__text--placeholder': !selectedUnitWork }">
|
|
||||||
{{ selectedUnitWork?.BaseInfoName || '单位工程' }}
|
|
||||||
</text>
|
|
||||||
<u-icon name="arrow-down" :size="18" color="#999" />
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 列表内容 -->
|
<!-- 列表内容 -->
|
||||||
<scroll-view class="list-scroll" scroll-y refresher-enabled="true" :refresher-triggered="refreshing"
|
<scroll-view class="list-scroll" scroll-y refresher-enabled="true" :refresher-triggered="refreshing"
|
||||||
@refresherrefresh="handleRefresh">
|
@refresherrefresh="handleRefresh" @scrolltolower="loadMore">
|
||||||
<view class="list-wrap">
|
<view class="list-wrap">
|
||||||
<view v-for="(item, index) in listData" :key="item.TempDetailId || index" class="card-item audit-card"
|
<view v-for="(item, index) in listData" :key="item.TempDetailId || index" class="card-item audit-card"
|
||||||
@click="handleItemClick(item)">
|
@click="handleItemClick(item)">
|
||||||
@@ -45,7 +50,9 @@
|
|||||||
<view class="audit-card__content">
|
<view class="audit-card__content">
|
||||||
<view class="card-header">
|
<view class="card-header">
|
||||||
<text class="card-code">{{ item.WeldJointCode || '--' }}</text>
|
<text class="card-code">{{ item.WeldJointCode || '--' }}</text>
|
||||||
<text class="card-tag status-1">待审核</text>
|
<text class="card-tag" :class="item.AuditState == 1 ? 'status-2' : 'status-1'">
|
||||||
|
{{ item.AuditStateText || '待审核' }}
|
||||||
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-body">
|
<view class="card-body">
|
||||||
<view class="card-row">
|
<view class="card-row">
|
||||||
@@ -78,10 +85,16 @@
|
|||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<u-empty v-if="!loading && listData.length === 0" mode="list" text="暂无待审核日报"></u-empty>
|
<u-empty v-if="!loading && listData.length === 0" mode="list" text="暂无待审核日报"></u-empty>
|
||||||
|
<view v-if="loading && listData.length > 0" class="loading-more">
|
||||||
|
<u-loading mode="circle" size="32"></u-loading>
|
||||||
|
<text>加载中...</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="!loading && !hasMore && listData.length > 0" class="no-more">
|
||||||
|
<text>— 没有更多了 —</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 底部批量操作栏 -->
|
|
||||||
<view v-if="canEdit" class="audit-bar">
|
<view v-if="canEdit" class="audit-bar">
|
||||||
<view class="audit-bar__all" @click="handleToggleAll">
|
<view class="audit-bar__all" @click="handleToggleAll">
|
||||||
<view class="check-circle" :class="{ 'check-circle--checked': isAllSelected }">
|
<view class="check-circle" :class="{ 'check-circle--checked': isAllSelected }">
|
||||||
@@ -91,10 +104,12 @@
|
|||||||
</view>
|
</view>
|
||||||
<text class="audit-bar__count">已选 {{ selectedIds.length }} 项</text>
|
<text class="audit-bar__count">已选 {{ selectedIds.length }} 项</text>
|
||||||
<view class="audit-bar__btns">
|
<view class="audit-bar__btns">
|
||||||
<u-button size="medium" type="error" :disabled="selectedIds.length === 0"
|
<u-button size="mini" type="error" :disabled="submitting || selectedIds.length === 0"
|
||||||
@click="handleBatchDelete">删除</u-button>
|
:loading="submitting" @click="handleBatchDelete">删除</u-button>
|
||||||
<u-button size="medium" type="primary" :disabled="selectedIds.length === 0"
|
<u-button size="mini" type="primary" :disabled="submitting || selectedIds.length === 0"
|
||||||
@click="handleBatchAudit">审核通过</u-button>
|
:loading="submitting" @click="handleTeamAudit">班组审核</u-button>
|
||||||
|
<u-button size="mini" type="primary" :disabled="submitting || selectedIds.length === 0"
|
||||||
|
:loading="submitting" @click="handleProfessionalAudit">专工审核</u-button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -125,6 +140,7 @@
|
|||||||
} from '@/api/base.js'
|
} from '@/api/base.js'
|
||||||
import {
|
import {
|
||||||
reqPendingWeldingDailyList,
|
reqPendingWeldingDailyList,
|
||||||
|
reqTeamAuditWeldingDaily,
|
||||||
reqAuditWeldingDaily,
|
reqAuditWeldingDaily,
|
||||||
reqDeleteWeldingDaily
|
reqDeleteWeldingDaily
|
||||||
} from '@/api/hj.js'
|
} from '@/api/hj.js'
|
||||||
@@ -136,6 +152,9 @@
|
|||||||
currentProject
|
currentProject
|
||||||
} = storeToRefs(userStore)
|
} = storeToRefs(userStore)
|
||||||
const canEdit = computed(() => menuStore.canEditFunc('dailyAudit'))
|
const canEdit = computed(() => menuStore.canEditFunc('dailyAudit'))
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
|
const uniqIds = (ids) => [...new Set((ids || []).filter(Boolean))]
|
||||||
|
|
||||||
// ===== 筛选条件 =====
|
// ===== 筛选条件 =====
|
||||||
const pipelineCode = ref('')
|
const pipelineCode = ref('')
|
||||||
@@ -144,12 +163,12 @@
|
|||||||
|
|
||||||
const onDateChange = (e) => {
|
const onDateChange = (e) => {
|
||||||
weldingDate.value = e.detail.value
|
weldingDate.value = e.detail.value
|
||||||
fetchData()
|
resetAndLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDateClear = () => {
|
const onDateClear = () => {
|
||||||
weldingDate.value = ''
|
weldingDate.value = ''
|
||||||
fetchData()
|
resetAndLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 单位工程选择 =====
|
// ===== 单位工程选择 =====
|
||||||
@@ -170,44 +189,73 @@
|
|||||||
const handleUnitWorkConfirm = (item) => {
|
const handleUnitWorkConfirm = (item) => {
|
||||||
selectedUnitWork.value = item?.BaseInfoId ? item : null
|
selectedUnitWork.value = item?.BaseInfoId ? item : null
|
||||||
showUnitWorkSelect.value = false
|
showUnitWorkSelect.value = false
|
||||||
fetchData()
|
resetAndLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 列表数据 =====
|
// ===== 列表数据 =====
|
||||||
const listData = ref([])
|
const listData = ref([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const refreshing = ref(false)
|
const refreshing = ref(false)
|
||||||
|
const hasMore = ref(true)
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = 20
|
||||||
|
|
||||||
// 加载待审核列表(不分页,一次拉全部待审核记录)
|
const fetchData = async (isRefresh = false) => {
|
||||||
const fetchData = async () => {
|
if (loading.value || (!isRefresh && !hasMore.value)) return
|
||||||
if (loading.value) return
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
refreshing.value = true
|
if (isRefresh) refreshing.value = true
|
||||||
try {
|
try {
|
||||||
const res = await reqPendingWeldingDailyList({
|
const res = await reqPendingWeldingDailyList({
|
||||||
projectId: currentProject.value?.ProjectId,
|
projectId: currentProject.value?.ProjectId,
|
||||||
unitWorkId: selectedUnitWork.value?.BaseInfoId || '',
|
unitWorkId: selectedUnitWork.value?.BaseInfoId || '',
|
||||||
weldingDate: weldingDate.value || '',
|
weldingDate: weldingDate.value || '',
|
||||||
pipelineCode: pipelineCode.value || '',
|
pipelineCode: pipelineCode.value || '',
|
||||||
welderCode: welderCode.value || ''
|
welderCode: welderCode.value || '',
|
||||||
|
pageIndex: currentPage.value,
|
||||||
|
pageSize
|
||||||
})
|
})
|
||||||
listData.value = res.data?.list || res.data?.getDataList || (Array.isArray(res.data) ? res.data : [])
|
const pageData = res.data?.list || res.data?.getDataList || (Array.isArray(res.data) ? res.data : [])
|
||||||
// 刷新后清空已选(原记录可能已不存在)
|
if (isRefresh) {
|
||||||
selectedIds.value = []
|
listData.value = pageData
|
||||||
|
selectedIds.value = []
|
||||||
|
} else {
|
||||||
|
listData.value = [...listData.value, ...pageData]
|
||||||
|
}
|
||||||
|
const totalCount = Number(res.data?.totalCount ?? res.data?.pageCount ?? 0)
|
||||||
|
if (totalCount > 0) {
|
||||||
|
hasMore.value = listData.value.length < totalCount
|
||||||
|
} else {
|
||||||
|
hasMore.value = pageData.length >= pageSize
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载待审核日报失败:', error)
|
console.error('加载待审核日报失败:', error)
|
||||||
|
if (!isRefresh && currentPage.value > 1) currentPage.value--
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
refreshing.value = false
|
refreshing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resetAndLoad = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
hasMore.value = true
|
||||||
|
listData.value = []
|
||||||
|
fetchData(true)
|
||||||
|
}
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
fetchData()
|
resetAndLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
fetchData()
|
resetAndLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadMore = () => {
|
||||||
|
if (!loading.value && hasMore.value) {
|
||||||
|
currentPage.value++
|
||||||
|
fetchData(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 勾选 =====
|
// ===== 勾选 =====
|
||||||
@@ -233,57 +281,79 @@
|
|||||||
if (isAllSelected.value) {
|
if (isAllSelected.value) {
|
||||||
selectedIds.value = []
|
selectedIds.value = []
|
||||||
} else {
|
} else {
|
||||||
selectedIds.value = listData.value.map(item => item.TempDetailId)
|
selectedIds.value = uniqIds(listData.value.map(item => item.TempDetailId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 批量操作 =====
|
const getSelectedIds = () => {
|
||||||
const handleBatchAudit = () => {
|
const ids = uniqIds(selectedIds.value)
|
||||||
|
if (!ids.length) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先选择要操作的日报',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
const runBatch = ({
|
||||||
|
title,
|
||||||
|
request
|
||||||
|
}) => {
|
||||||
|
if (submitting.value) return
|
||||||
|
const ids = getSelectedIds()
|
||||||
|
if (!ids.length) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '信息提示',
|
title: '信息提示',
|
||||||
content: `确定审核通过选中的 ${selectedIds.value.length} 条日报吗?`,
|
content: `确定${title}选中的 ${ids.length} 条日报吗?`,
|
||||||
success: async ({
|
success: async ({
|
||||||
confirm
|
confirm
|
||||||
}) => {
|
}) => {
|
||||||
if (!confirm) return
|
if (!confirm) return
|
||||||
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await reqAuditWeldingDaily({
|
await request(ids)
|
||||||
TempDetailIds: selectedIds.value,
|
|
||||||
AuditMan: userInfo.value?.PersonId
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return // 报错已由 request.js 统一 toast
|
submitting.value = false
|
||||||
|
return
|
||||||
}
|
}
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '审核成功',
|
title: '操作成功',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
fetchData()
|
submitting.value = false
|
||||||
|
resetAndLoad()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleTeamAudit = () => {
|
||||||
|
runBatch({
|
||||||
|
title: '班组审核',
|
||||||
|
request: (ids) => reqTeamAuditWeldingDaily({
|
||||||
|
TempDetailIds: ids,
|
||||||
|
AuditMan: userInfo.value?.PersonId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleProfessionalAudit = () => {
|
||||||
|
runBatch({
|
||||||
|
title: '专工审核',
|
||||||
|
request: (ids) => reqAuditWeldingDaily({
|
||||||
|
TempDetailIds: ids,
|
||||||
|
AuditMan: userInfo.value?.PersonId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const handleBatchDelete = () => {
|
const handleBatchDelete = () => {
|
||||||
uni.showModal({
|
runBatch({
|
||||||
title: '信息提示',
|
title: '删除',
|
||||||
content: `确定删除选中的 ${selectedIds.value.length} 条日报吗?`,
|
request: (ids) => reqDeleteWeldingDaily({
|
||||||
success: async ({
|
TempDetailIds: ids
|
||||||
confirm
|
})
|
||||||
}) => {
|
|
||||||
if (!confirm) return
|
|
||||||
try {
|
|
||||||
await reqDeleteWeldingDaily({
|
|
||||||
TempDetailIds: selectedIds.value
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
return // 报错已由 request.js 统一 toast
|
|
||||||
}
|
|
||||||
uni.showToast({
|
|
||||||
title: '删除成功',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
fetchData()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,48 +385,57 @@
|
|||||||
|
|
||||||
// ===== 生命周期 =====
|
// ===== 生命周期 =====
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
fetchData()
|
resetAndLoad()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$primary: $app-primary;
|
$primary: $app-primary;
|
||||||
|
|
||||||
.filter-row {
|
.page-list {
|
||||||
display: flex;
|
height: calc(100vh - var(--window-top, 0px));
|
||||||
align-items: center;
|
overflow: hidden;
|
||||||
gap: 12rpx;
|
}
|
||||||
|
|
||||||
.welder-input-wrap {
|
.filter-header {
|
||||||
flex: 1;
|
.filter-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background: #f5f6f8;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
height: 70rpx;
|
height: 70rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 16rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.welder-input {
|
.filter-picker {
|
||||||
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 28rpx;
|
height: 70rpx;
|
||||||
color: #333;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 70rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn {
|
.filter-btn {
|
||||||
flex: 1;
|
width: 100%;
|
||||||
min-width: 0;
|
height: 70rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background: #f5f6f8;
|
background: #f5f6f8;
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
padding: 0 16rpx;
|
padding: 0 16rpx;
|
||||||
height: 70rpx;
|
box-sizing: border-box;
|
||||||
|
|
||||||
&__text {
|
&__text {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
color: #333;
|
color: #333;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -367,9 +446,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.welder-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.u-search) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.u-content) {
|
||||||
|
height: 70rpx !important;
|
||||||
|
border-radius: 12rpx !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 勾选圆圈
|
|
||||||
.check-circle {
|
.check-circle {
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
@@ -387,7 +483,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 带勾选框的卡片
|
|
||||||
.audit-card {
|
.audit-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -403,18 +498,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 底部批量操作栏
|
.list-scroll {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-wrap {
|
||||||
|
padding-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.audit-bar {
|
.audit-bar {
|
||||||
position: fixed;
|
flex-shrink: 0;
|
||||||
left: 0;
|
position: relative;
|
||||||
right: 0;
|
z-index: 20;
|
||||||
bottom: 0;
|
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
padding: 20rpx 32rpx;
|
padding: 16rpx 24rpx;
|
||||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20rpx;
|
gap: 12rpx;
|
||||||
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
|
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
&__all {
|
&__all {
|
||||||
@@ -436,20 +540,18 @@
|
|||||||
|
|
||||||
&__btns {
|
&__btns {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16rpx;
|
flex: 1 0 100%;
|
||||||
|
gap: 12rpx;
|
||||||
|
|
||||||
.u-size-medium {
|
:deep(.u-btn) {
|
||||||
height: 72rpx;
|
flex: 1;
|
||||||
font-size: 28rpx;
|
min-width: 0;
|
||||||
|
height: 64rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 32rpx;
|
padding: 0 8rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 给底部操作栏留出空间(含安全区)
|
|
||||||
.list-scroll {
|
|
||||||
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -100,6 +100,26 @@
|
|||||||
<text class="card__label">提交时间</text>
|
<text class="card__label">提交时间</text>
|
||||||
<text class="card__value">{{ fmtDateTime(form.SubmitDate) }}</text>
|
<text class="card__value">{{ fmtDateTime(form.SubmitDate) }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">审核状态</text>
|
||||||
|
<text class="card__value">{{ form.AuditStateText || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">班组审核人</text>
|
||||||
|
<text class="card__value">{{ form.TeamAuditManName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">班组审核时间</text>
|
||||||
|
<text class="card__value">{{ fmtDateTime(form.TeamAuditDate) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">专工审核人</text>
|
||||||
|
<text class="card__value">{{ form.ProfessionalAuditManName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">专工审核时间</text>
|
||||||
|
<text class="card__value">{{ fmtDateTime(form.ProfessionalAuditDate) }}</text>
|
||||||
|
</view>
|
||||||
<!-- 焊前拍照 -->
|
<!-- 焊前拍照 -->
|
||||||
<view class="card__row card__row--stack">
|
<view class="card__row card__row--stack">
|
||||||
<text class="card__label">焊前拍照</text>
|
<text class="card__label">焊前拍照</text>
|
||||||
@@ -126,8 +146,12 @@
|
|||||||
|
|
||||||
<!-- 底部按钮 -->
|
<!-- 底部按钮 -->
|
||||||
<view v-if="canEdit" class="bottom-btns">
|
<view v-if="canEdit" class="bottom-btns">
|
||||||
<u-button class="btn-delete" size="medium" type="error" @click="handleDelete">删除</u-button>
|
<u-button class="btn-delete" size="mini" type="error" :disabled="submitting" :loading="submitting"
|
||||||
<u-button class="btn-audit" size="medium" type="primary" @click="handleAudit">审核通过</u-button>
|
@click="handleDelete">删除</u-button>
|
||||||
|
<u-button class="btn-audit" size="mini" type="primary" :disabled="submitting" :loading="submitting"
|
||||||
|
@click="handleTeamAudit">班组审核</u-button>
|
||||||
|
<u-button class="btn-audit" size="mini" type="primary" :disabled="submitting" :loading="submitting"
|
||||||
|
@click="handleProfessionalAudit">专工审核</u-button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -146,6 +170,7 @@
|
|||||||
} from '@/store'
|
} from '@/store'
|
||||||
import {
|
import {
|
||||||
reqPendingWeldingDailyDetail,
|
reqPendingWeldingDailyDetail,
|
||||||
|
reqTeamAuditWeldingDaily,
|
||||||
reqAuditWeldingDaily,
|
reqAuditWeldingDaily,
|
||||||
reqDeleteWeldingDaily
|
reqDeleteWeldingDaily
|
||||||
} from '@/api/hj.js'
|
} from '@/api/hj.js'
|
||||||
@@ -159,28 +184,35 @@
|
|||||||
|
|
||||||
const tempDetailId = ref('')
|
const tempDetailId = ref('')
|
||||||
const form = ref({})
|
const form = ref({})
|
||||||
|
const submitting = ref(false)
|
||||||
|
const auditState = computed(() => Number(form.value.AuditState))
|
||||||
|
const isTeamPending = computed(() => auditState.value === 0)
|
||||||
|
const isProfessionalPending = computed(() => auditState.value === 1 && !!form.value.TeamAuditDate)
|
||||||
|
|
||||||
// ===== 操作 =====
|
const runAction = ({
|
||||||
const handleAudit = () => {
|
title,
|
||||||
|
request
|
||||||
|
}) => {
|
||||||
|
if (submitting.value) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '信息提示',
|
title: '信息提示',
|
||||||
content: '确定审核通过该日报吗?',
|
content: `确定${title}该日报吗?`,
|
||||||
success: async ({
|
success: async ({
|
||||||
confirm
|
confirm
|
||||||
}) => {
|
}) => {
|
||||||
if (!confirm) return
|
if (!confirm) return
|
||||||
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await reqAuditWeldingDaily({
|
await request()
|
||||||
TempDetailIds: [tempDetailId.value],
|
|
||||||
AuditMan: userInfo.PersonId
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return // 报错已由 request.js 统一 toast
|
submitting.value = false
|
||||||
|
return
|
||||||
}
|
}
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '审核成功',
|
title: '操作成功',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
|
submitting.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
@@ -188,7 +220,28 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleTeamAudit = () => {
|
||||||
|
runAction({
|
||||||
|
title: '班组审核',
|
||||||
|
request: () => reqTeamAuditWeldingDaily({
|
||||||
|
TempDetailIds: [tempDetailId.value],
|
||||||
|
AuditMan: userInfo.PersonId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleProfessionalAudit = () => {
|
||||||
|
runAction({
|
||||||
|
title: '专工审核',
|
||||||
|
request: () => reqAuditWeldingDaily({
|
||||||
|
TempDetailIds: [tempDetailId.value],
|
||||||
|
AuditMan: userInfo.PersonId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
|
if (submitting.value) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '信息提示',
|
title: '信息提示',
|
||||||
content: '确定删除该日报吗?',
|
content: '确定删除该日报吗?',
|
||||||
@@ -196,17 +249,20 @@
|
|||||||
confirm
|
confirm
|
||||||
}) => {
|
}) => {
|
||||||
if (!confirm) return
|
if (!confirm) return
|
||||||
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await reqDeleteWeldingDaily({
|
await reqDeleteWeldingDaily({
|
||||||
TempDetailIds: [tempDetailId.value]
|
TempDetailIds: [tempDetailId.value]
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return // 报错已由 request.js 统一 toast
|
submitting.value = false
|
||||||
|
return
|
||||||
}
|
}
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '删除成功',
|
title: '删除成功',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
|
submitting.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
@@ -247,6 +303,7 @@
|
|||||||
|
|
||||||
.detail-page {
|
.detail-page {
|
||||||
background: #f0f2f5;
|
background: #f0f2f5;
|
||||||
|
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 焊口主标识(同 daily_paper) =====
|
// ===== 焊口主标识(同 daily_paper) =====
|
||||||
@@ -338,4 +395,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom-btns {
|
||||||
|
padding: 16rpx 20rpx;
|
||||||
|
padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
|
||||||
|
gap: 12rpx;
|
||||||
|
z-index: 20;
|
||||||
|
|
||||||
|
:deep(.u-btn) {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 64rpx;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 8rpx !important;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+117
-17
@@ -133,6 +133,26 @@
|
|||||||
<u-icon name="arrow-right" :size="24" color="#bbb" />
|
<u-icon name="arrow-right" :size="24" color="#bbb" />
|
||||||
</view>
|
</view>
|
||||||
</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">
|
<view class="card__row card__row--stack">
|
||||||
<text class="card__label">备注</text>
|
<text class="card__label">备注</text>
|
||||||
@@ -185,6 +205,14 @@
|
|||||||
<!-- 焊接方法选择弹窗 -->
|
<!-- 焊接方法选择弹窗 -->
|
||||||
<nbd-select v-model="showWeldingMethodPicker" :show-search="true" title="选择焊接方法" :list="weldingMethodList"
|
<nbd-select v-model="showWeldingMethodPicker" :show-search="true" title="选择焊接方法" :list="weldingMethodList"
|
||||||
label-key="BaseInfoCode" value-key="BaseInfoId" @confirm="handleConfirmWeldingMethod" />
|
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>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -192,7 +220,7 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { reqGetWeldJointByWeldJointId, reqSaveWeldingDailyByWeldJointId, reqGetManualPointSave, reqFitupCheckByWeldJointId } from '@/api/hj.js'
|
import { reqGetWeldJointByWeldJointId, reqSaveWeldingDailyByWeldJointId, reqGetManualPointSave, reqFitupCheckByWeldJointId } from '@/api/hj.js'
|
||||||
import { reqWeldingLocation, reqGetWeldTypeList, reqGetWeldingMethodList } from '@/api/base.js'
|
import { reqWeldingLocation, reqGetWeldTypeList, reqGetWeldingMethodList, reqGetWeldingConsumables } from '@/api/base.js'
|
||||||
import { useUserStore, useMenuStore } from '@/store'
|
import { useUserStore, useMenuStore } from '@/store'
|
||||||
|
|
||||||
|
|
||||||
@@ -211,9 +239,13 @@ const showLocationPicker = ref(false)
|
|||||||
const showTypePicker = ref(false)
|
const showTypePicker = ref(false)
|
||||||
const showWeldTypePicker = ref(false)
|
const showWeldTypePicker = ref(false)
|
||||||
const showWeldingMethodPicker = ref(false)
|
const showWeldingMethodPicker = ref(false)
|
||||||
|
const showWirePicker = ref(false)
|
||||||
|
const showRodPicker = ref(false)
|
||||||
const locationList = ref([])
|
const locationList = ref([])
|
||||||
const weldTypeList = ref([])
|
const weldTypeList = ref([])
|
||||||
const weldingMethodList = ref([])
|
const weldingMethodList = ref([])
|
||||||
|
const wireList = ref([])
|
||||||
|
const rodList = ref([])
|
||||||
const welderTypeList = ref([
|
const welderTypeList = ref([
|
||||||
{ BaseInfoName: '打底/盖面', BaseInfoCode: 0 },
|
{ BaseInfoName: '打底/盖面', BaseInfoCode: 0 },
|
||||||
{ BaseInfoName: '打底', BaseInfoCode: 1 },
|
{ BaseInfoName: '打底', BaseInfoCode: 1 },
|
||||||
@@ -227,16 +259,8 @@ const afterPhotoRef = ref(null)
|
|||||||
const weldJointId = ref('')
|
const weldJointId = ref('')
|
||||||
const fitupList = ref([])
|
const fitupList = ref([])
|
||||||
const fitupFields = [
|
const fitupFields = [
|
||||||
{ label: '坡口类型名称', key: 'GrooveTypeName' },
|
|
||||||
{ label: '坡口类型编码', key: 'GrooveTypeCode' },
|
|
||||||
{ label: '坡口加工类型', key: 'GrooveProcessType' },
|
|
||||||
{ label: '坡口角度', key: 'GrooveAngle' },
|
|
||||||
{ label: '组对间隙', key: 'FitupGap' },
|
{ label: '组对间隙', key: 'FitupGap' },
|
||||||
{ label: '错边量', key: 'Misalignment' },
|
{ label: '错边量', key: 'Misalignment' },
|
||||||
{ label: '焊缝余高', key: 'WeldReinforcement' },
|
|
||||||
{ label: '焊缝高度', key: 'WeldHeight' },
|
|
||||||
{ label: '焊缝宽度', key: 'WeldWidth' },
|
|
||||||
{ label: '表面缺陷', key: 'SurfaceDefect' },
|
|
||||||
{ label: '检查人', key: 'CheckPersonName' },
|
{ label: '检查人', key: 'CheckPersonName' },
|
||||||
{ label: '检查时间', key: 'CheckTime' },
|
{ label: '检查时间', key: 'CheckTime' },
|
||||||
{ label: '检查结果', key: 'CheckResult', type: 'tag', tagMatch: '合格' },
|
{ label: '检查结果', key: 'CheckResult', type: 'tag', tagMatch: '合格' },
|
||||||
@@ -294,6 +318,56 @@ const handleConfirmWeldingMethod = (item) => {
|
|||||||
showWeldingMethodPicker.value = false
|
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 () => {
|
const handlePoint = async () => {
|
||||||
await reqGetManualPointSave(form.value.WeldJointId)
|
await reqGetManualPointSave(form.value.WeldJointId)
|
||||||
@@ -329,7 +403,11 @@ const handleReport = () => {
|
|||||||
welderType: form.value.welderType,
|
welderType: form.value.welderType,
|
||||||
// 同步更新焊口焊缝类型 / 焊接方法
|
// 同步更新焊口焊缝类型 / 焊接方法
|
||||||
WeldTypeId: form.value.WeldTypeId || '',
|
WeldTypeId: form.value.WeldTypeId || '',
|
||||||
|
WeldTypeCode: form.value.WeldTypeCode || '',
|
||||||
WeldingMethodId: form.value.WeldingMethodId || '',
|
WeldingMethodId: form.value.WeldingMethodId || '',
|
||||||
|
WeldingMethodCode: form.value.WeldingMethodCode || '',
|
||||||
|
WeldingWire: form.value.WeldingWire || '',
|
||||||
|
WeldingRod: form.value.WeldingRod || '',
|
||||||
PreWeldAttachUrl: preWeldAttachUrl.value || form.value.PreWeldAttachUrl || '',
|
PreWeldAttachUrl: preWeldAttachUrl.value || form.value.PreWeldAttachUrl || '',
|
||||||
PostWeldAttachUrl: postWeldAttachUrl.value || form.value.PostWeldAttachUrl || ''
|
PostWeldAttachUrl: postWeldAttachUrl.value || form.value.PostWeldAttachUrl || ''
|
||||||
})
|
})
|
||||||
@@ -350,14 +428,16 @@ const handleMutualCheck = () => {
|
|||||||
const fillTypeMethodIds = async () => {
|
const fillTypeMethodIds = async () => {
|
||||||
const needWeldType = form.value.WeldTypeCode && !form.value.WeldTypeId
|
const needWeldType = form.value.WeldTypeCode && !form.value.WeldTypeId
|
||||||
const needMethod = form.value.WeldingMethodCode && !form.value.WeldingMethodId
|
const needMethod = form.value.WeldingMethodCode && !form.value.WeldingMethodId
|
||||||
if (!needWeldType && !needMethod) return
|
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 {
|
try {
|
||||||
const tasks = []
|
const [typeRes, methodRes, wireRes, rodRes] = await Promise.all([
|
||||||
if (needWeldType) tasks.push(reqGetWeldTypeList())
|
needWeldType ? reqGetWeldTypeList() : Promise.resolve(null),
|
||||||
else tasks.push(Promise.resolve(null))
|
needMethod ? reqGetWeldingMethodList() : Promise.resolve(null),
|
||||||
if (needMethod) tasks.push(reqGetWeldingMethodList())
|
needWire ? fetchConsumables(CONSUMABLE_WIRE) : Promise.resolve(null),
|
||||||
else tasks.push(Promise.resolve(null))
|
needRod ? fetchConsumables(CONSUMABLE_ROD) : Promise.resolve(null),
|
||||||
const [typeRes, methodRes] = await Promise.all(tasks)
|
])
|
||||||
if (typeRes?.data) {
|
if (typeRes?.data) {
|
||||||
const hit = typeRes.data.find(i => i.BaseInfoCode === form.value.WeldTypeCode)
|
const hit = typeRes.data.find(i => i.BaseInfoCode === form.value.WeldTypeCode)
|
||||||
if (hit) {
|
if (hit) {
|
||||||
@@ -372,8 +452,28 @@ const fillTypeMethodIds = async () => {
|
|||||||
form.value.WeldingMethodName = hit.BaseInfoName
|
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) {
|
} catch (e) {
|
||||||
console.error('回填焊缝类型/焊接方法ID失败:', e)
|
console.error('回填焊缝类型/焊接方法/焊材ID失败:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-58
@@ -33,15 +33,6 @@
|
|||||||
<text class="section__title">组对填报</text>
|
<text class="section__title">组对填报</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="card">
|
<view class="card">
|
||||||
<!-- 坡口加工类型 -->
|
|
||||||
<view class="card__row">
|
|
||||||
<text class="card__label">坡口加工类型</text>
|
|
||||||
<view class="card__value-wrap">
|
|
||||||
<input class="card__input" v-model="makeRightForm.GrooveProcessType" type="text"
|
|
||||||
placeholder="请输入坡口加工类型" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 组对间隙 -->
|
<!-- 组对间隙 -->
|
||||||
<view class="card__row">
|
<view class="card__row">
|
||||||
<text class="card__label">组对间隙</text>
|
<text class="card__label">组对间隙</text>
|
||||||
@@ -161,14 +152,13 @@
|
|||||||
|
|
||||||
<!-- 提交按钮 -->
|
<!-- 提交按钮 -->
|
||||||
<view v-if="canEdit" class="submit-bar">
|
<view v-if="canEdit" class="submit-bar">
|
||||||
<view class="btn-primary-gradient" @click="handleSubmit">
|
<view class="btn-primary-gradient" :class="{ 'btn-primary-gradient--disabled': submitting }"
|
||||||
<text class="btn-primary-gradient__text">提交结果</text>
|
@click="handleSubmit">
|
||||||
|
<text class="btn-primary-gradient__text">{{ submitting ? '提交中...' : '提交结果' }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<nbd-select v-model="showGrooveTypePicker" title="选择坡口类型" :list="grooveTypeList" label-key="BaseInfoName"
|
|
||||||
value-key="BaseInfoCode" @confirm="selectGrooveType" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -178,11 +168,11 @@ import { storeToRefs } from 'pinia'
|
|||||||
import { useUserStore, useMenuStore } from '@/store'
|
import { useUserStore, useMenuStore } from '@/store'
|
||||||
|
|
||||||
import { reqPreWeldJointByWeldJointId, reqSaveFitupCheck, reqCuttingCheckByWeldJointId, reqFitupCheckByWeldJointId } from '@/api/hj'
|
import { reqPreWeldJointByWeldJointId, reqSaveFitupCheck, reqCuttingCheckByWeldJointId, reqFitupCheckByWeldJointId } from '@/api/hj'
|
||||||
import { reqGetGrooveTypeList } from '@/api/base'
|
|
||||||
|
|
||||||
const cuttingFields = [
|
const cuttingFields = [
|
||||||
{ label: '下料长度', key: 'CuttingLength' },
|
{ label: '下料长度', key: 'CuttingLength' },
|
||||||
{ label: '坡口形式', key: 'GrooveForm' },
|
{ label: '坡口形式', key: 'GrooveForm' },
|
||||||
|
{ label: '坡口加工类型', key: 'GrooveProcessType' },
|
||||||
{ label: '材料编码批次', key: 'IsMaterialCodeBatchNoAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
{ label: '材料编码批次', key: 'IsMaterialCodeBatchNoAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
||||||
{ label: '材料数量', key: 'IsMaterialQuantityAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
{ label: '材料数量', key: 'IsMaterialQuantityAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
||||||
{ label: '检查人', key: 'CheckPersonName' },
|
{ label: '检查人', key: 'CheckPersonName' },
|
||||||
@@ -194,7 +184,6 @@ const cuttingFields = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const fitupFields = [
|
const fitupFields = [
|
||||||
{ label: '坡口加工类型', key: 'GrooveProcessType' },
|
|
||||||
{ label: '组对间隙', key: 'FitupGap' },
|
{ label: '组对间隙', key: 'FitupGap' },
|
||||||
{ label: '错边量', key: 'Misalignment' },
|
{ label: '错边量', key: 'Misalignment' },
|
||||||
{ label: '检查人', key: 'CheckPersonName' },
|
{ label: '检查人', key: 'CheckPersonName' },
|
||||||
@@ -218,8 +207,6 @@ const remark = ref('')
|
|||||||
const formAttachUrl = ref('')
|
const formAttachUrl = ref('')
|
||||||
const id = ref('')
|
const id = ref('')
|
||||||
const makeRightForm = ref({
|
const makeRightForm = ref({
|
||||||
GrooveTypeId: '', // 坡口类型ID
|
|
||||||
GrooveProcessType: '', // 坡口加工类型
|
|
||||||
FitupGap: '', // 组对间隙
|
FitupGap: '', // 组对间隙
|
||||||
Misalignment: '', // 错边量
|
Misalignment: '', // 错边量
|
||||||
CheckResult: '合格', // 检查结果
|
CheckResult: '合格', // 检查结果
|
||||||
@@ -228,12 +215,9 @@ const makeRightForm = ref({
|
|||||||
Remark: '', // 备注
|
Remark: '', // 备注
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const showGrooveTypePicker = ref(false)
|
|
||||||
const grooveTypeList = ref([])
|
|
||||||
|
|
||||||
// 照片组件引用
|
// 照片组件引用
|
||||||
const photoRef = ref(null)
|
const photoRef = ref(null)
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
const failVisible = ref(makeRightForm.value.CheckResult === '不合格')
|
const failVisible = ref(makeRightForm.value.CheckResult === '不合格')
|
||||||
const failAnimating = ref(false)
|
const failAnimating = ref(false)
|
||||||
@@ -262,63 +246,48 @@ const handleSubmit = () => {
|
|||||||
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
|
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (submitting.value) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '确认提交',
|
title: '确认提交',
|
||||||
content: '确定提交吗?',
|
content: '确定提交吗?',
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (!res.confirm) return
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
if (photoRef.value?.hasPending()) {
|
if (photoRef.value?.hasPending()) {
|
||||||
uni.showLoading({ title: '上传照片中...', mask: true })
|
uni.showLoading({ title: '上传照片中...', mask: true })
|
||||||
await photoRef.value.uploadAll()
|
await photoRef.value.uploadAll()
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
}
|
}
|
||||||
const CuttingAttachUrl1 = formAttachUrl.value||''
|
const CuttingAttachUrl1 = formAttachUrl.value||''
|
||||||
|
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
ProjectId: currentProject.value?.ProjectId, // 项目ID
|
FitupCheckId: null,
|
||||||
WeldJointId: info.value?.WeldJointId, // 焊口ID
|
ProjectId: currentProject.value?.ProjectId,
|
||||||
GrooveTypeId: makeRightForm.value.GrooveTypeId, // 坡口类型ID
|
WeldJointId: info.value?.WeldJointId,
|
||||||
GrooveProcessType: makeRightForm.value.GrooveProcessType, // 坡口加工类型
|
FitupGap: makeRightForm.value.FitupGap,
|
||||||
FitupGap: makeRightForm.value.FitupGap, // 组对间隙
|
Misalignment: makeRightForm.value.Misalignment,
|
||||||
Misalignment: makeRightForm.value.Misalignment, // 错边量
|
CheckTime: uni.formatTime(new Date().getTime(), 'YYYY-MM-DD HH:mm'),
|
||||||
CheckTime: uni.formatTime(new Date().getTime(), 'YYYY-MM-DD HH:mm'), // 检查时间
|
CreateUser: userInfo.value?.PersonId,
|
||||||
CreateUser: userInfo.value?.PersonId, // 创建人员
|
CheckPerson: userInfo.value?.PersonId,
|
||||||
CheckPerson: userInfo.value?.PersonId, // 检查人员
|
CheckResult: makeRightForm.value.CheckResult,
|
||||||
CheckResult: makeRightForm.value.CheckResult, // 检查结果
|
Remark: makeRightForm.value.Remark || '',
|
||||||
Remark: remark.value, // 备注
|
UnqualifiedReason: makeRightForm.value.UnqualifiedReason,
|
||||||
UnqualifiedReason: makeRightForm.value.UnqualifiedReason, // 不合格原因
|
RectifyRequirement: makeRightForm.value.RectifyRequirement,
|
||||||
RectifyRequirement: makeRightForm.value.RectifyRequirement, // 整改要求
|
|
||||||
AttachUrl1: CuttingAttachUrl1,
|
AttachUrl1: CuttingAttachUrl1,
|
||||||
}
|
}
|
||||||
console.log('提交参数:', params)
|
|
||||||
await reqSaveFitupCheck(params)
|
await reqSaveFitupCheck(params)
|
||||||
uni.showToast({ title: '提交成功', icon: 'none' })
|
uni.showToast({ title: '提交成功', icon: 'none' })
|
||||||
setTimeout(() => { uni.navigateBack() }, 1500)
|
setTimeout(() => { uni.navigateBack() }, 1500)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存组对抽查失败:', error)
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectGrooveType = (item) => {
|
|
||||||
makeRightForm.value.GrooveTypeId = item.BaseInfoId
|
|
||||||
makeRightForm.value.GrooveProcessType = item.BaseInfoName
|
|
||||||
showGrooveTypePicker.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchGrooveTypes = async () => {
|
|
||||||
try {
|
|
||||||
const res = await reqGetGrooveTypeList()
|
|
||||||
if (res.code === 1 && res.data) {
|
|
||||||
grooveTypeList.value = res.data
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取坡口类型列表失败:', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onLoad((opt) => {
|
onLoad((opt) => {
|
||||||
fetchGrooveTypes()
|
|
||||||
if (opt.id) {
|
if (opt.id) {
|
||||||
id.value = opt.id
|
id.value = opt.id
|
||||||
getInfo(opt.id)
|
getInfo(opt.id)
|
||||||
@@ -341,8 +310,6 @@ const getInfo = async (id) => {
|
|||||||
if (fitupRes.code === 1 && fitupRes.data) {
|
if (fitupRes.code === 1 && fitupRes.data) {
|
||||||
fitupList.value = fitupRes.data
|
fitupList.value = fitupRes.data
|
||||||
if (fitupRes.data.length > 0) {
|
if (fitupRes.data.length > 0) {
|
||||||
makeRightForm.value.GrooveTypeId = fitupRes.data[0].GrooveTypeId
|
|
||||||
makeRightForm.value.GrooveProcessType = fitupRes.data[0].GrooveProcessType
|
|
||||||
makeRightForm.value.FitupGap = fitupRes.data[0].FitupGap
|
makeRightForm.value.FitupGap = fitupRes.data[0].FitupGap
|
||||||
makeRightForm.value.Misalignment = fitupRes.data[0].Misalignment
|
makeRightForm.value.Misalignment = fitupRes.data[0].Misalignment
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<view class="card">
|
<view class="card">
|
||||||
<!-- 下料长度 -->
|
<!-- 下料长度 -->
|
||||||
<view class="card__row" @click="showPaintCodePicker = true">
|
<view class="card__row" @click="showPaintCodePicker = true">
|
||||||
<text class="card__label">下料长度</text>
|
<text class="card__label">下料长度(mm)</text>
|
||||||
<view class="card__value-wrap">
|
<view class="card__value-wrap">
|
||||||
<input class="card__input" v-model="layingOffForm.CuttingLength" type="digit"
|
<input class="card__input" v-model="layingOffForm.CuttingLength" type="digit"
|
||||||
placeholder="请输入下料长度" />
|
placeholder="请输入下料长度" />
|
||||||
@@ -38,6 +38,14 @@
|
|||||||
placeholder="请输入坡口形式" />
|
placeholder="请输入坡口形式" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 坡口加工类型 -->
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">坡口加工类型</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="layingOffForm.GrooveProcessType" type="text"
|
||||||
|
placeholder="请输入坡口加工类型" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<!-- 坡口角度 -->
|
<!-- 坡口角度 -->
|
||||||
<view class="card__row">
|
<view class="card__row">
|
||||||
<text class="card__label">坡口角度</text>
|
<text class="card__label">坡口角度</text>
|
||||||
@@ -63,8 +71,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 专项审核办理人:材料编码批次或材料数量不准确时必填 -->
|
<!-- 专项审核办理人:材料编码批次或材料数量不准确时必填 -->
|
||||||
<view class="card__row" @click="handleShowReviewerSelect">
|
<view v-if="needSpecialReviewer" class="card__row" @click="handleShowReviewerSelect">
|
||||||
<text class="card__label" :class="{ required: needSpecialReviewer }">专项审核办理人</text>
|
<text class="card__label required">专项审核办理人</text>
|
||||||
<view class="card__value-wrap card__value-wrap--clickable">
|
<view class="card__value-wrap card__value-wrap--clickable">
|
||||||
<text class="card__value" :class="{ 'card__value--placeholder': !specialReviewerName }">
|
<text class="card__value" :class="{ 'card__value--placeholder': !specialReviewerName }">
|
||||||
{{ specialReviewerName || '请选择' }}
|
{{ specialReviewerName || '请选择' }}
|
||||||
@@ -73,12 +81,18 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 两侧主编码反馈 -->
|
<!-- 两侧主编码 -->
|
||||||
<view class="card__row card__row--stack">
|
<view class="card__row card__row--stack">
|
||||||
<text class="card__label">两侧主编码反馈</text>
|
<text class="card__label">两侧主编码</text>
|
||||||
<view class="card__value-wrap">
|
<view v-if="sideMaterials.length" class="side-codes">
|
||||||
<textarea readonly class="remark-input" placeholder="请输入" :maxlength="200" auto-height />
|
<view v-for="(m, idx) in sideMaterials" :key="m.side || idx" class="side-codes__item">
|
||||||
|
<text class="side-codes__title">侧{{ m.side || (idx + 1) }}</text>
|
||||||
|
<text class="side-codes__line">上报主编码:{{ m.reported || '--' }}</text>
|
||||||
|
<text class="side-codes__line">原主编码:{{ m.original || '--' }}</text>
|
||||||
|
<text v-if="m.batchChanged" class="side-codes__changed">批次已变更</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<text v-else class="card__value">暂无主编码信息</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -188,8 +202,9 @@
|
|||||||
|
|
||||||
<!-- 提交按钮 -->
|
<!-- 提交按钮 -->
|
||||||
<view v-if="canEdit" class="submit-bar">
|
<view v-if="canEdit" class="submit-bar">
|
||||||
<view class="btn-primary-gradient" @click="handleSubmit">
|
<view class="btn-primary-gradient" :class="{ 'btn-primary-gradient--disabled': submitting }"
|
||||||
<text class="btn-primary-gradient__text">提交结果</text>
|
@click="handleSubmit">
|
||||||
|
<text class="btn-primary-gradient__text">{{ submitting ? '提交中...' : '提交结果' }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -210,7 +225,12 @@ import { reqPreWeldJointByWeldJointId, reqSaveCuttingCheck, reqCuttingCheckByWel
|
|||||||
const cuttingFields = [
|
const cuttingFields = [
|
||||||
{ label: '下料长度', key: 'CuttingLength' },
|
{ label: '下料长度', key: 'CuttingLength' },
|
||||||
{ label: '坡口形式', key: 'GrooveForm' },
|
{ label: '坡口形式', key: 'GrooveForm' },
|
||||||
|
{ label: '坡口加工类型', key: 'GrooveProcessType' },
|
||||||
{ label: '坡口角度', key: 'GrooveAngle' },
|
{ label: '坡口角度', key: 'GrooveAngle' },
|
||||||
|
{ label: '侧1上报主编码', key: 'Side1ReportedMainCode' },
|
||||||
|
{ label: '侧1原主编码', key: 'Side1OriginalMainCode' },
|
||||||
|
{ label: '侧2上报主编码', key: 'Side2ReportedMainCode' },
|
||||||
|
{ label: '侧2原主编码', key: 'Side2OriginalMainCode' },
|
||||||
{ label: '材料编码批次', key: 'IsMaterialCodeBatchNoAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
{ label: '材料编码批次', key: 'IsMaterialCodeBatchNoAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
||||||
{ label: '材料数量', key: 'IsMaterialQuantityAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
{ label: '材料数量', key: 'IsMaterialQuantityAccurate', type: 'tag', tagMatch: true, tagPassText: '准确', tagFailText: '不准确' },
|
||||||
{ label: '专项审核办理人', key: 'SpecialReviewerName' },
|
{ label: '专项审核办理人', key: 'SpecialReviewerName' },
|
||||||
@@ -250,6 +270,7 @@ const formAttachUrl = ref('')
|
|||||||
const layingOffForm = ref({
|
const layingOffForm = ref({
|
||||||
CuttingLength: '',
|
CuttingLength: '',
|
||||||
GrooveForm: '',
|
GrooveForm: '',
|
||||||
|
GrooveProcessType: '',
|
||||||
GrooveAngle: '',
|
GrooveAngle: '',
|
||||||
CheckResult: '合格',
|
CheckResult: '合格',
|
||||||
IsMaterialCodeBatchNoAccurate: '准确',
|
IsMaterialCodeBatchNoAccurate: '准确',
|
||||||
@@ -270,8 +291,48 @@ const needSpecialReviewer = computed(() =>
|
|||||||
layingOffForm.value.IsMaterialQuantityAccurate === '不准确'
|
layingOffForm.value.IsMaterialQuantityAccurate === '不准确'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const pickMaterials = (list) => Array.isArray(list) ? list : []
|
||||||
|
|
||||||
|
const flattenCuttingRecord = (item) => {
|
||||||
|
const extra = {}
|
||||||
|
pickMaterials(item.Materials).forEach((m) => {
|
||||||
|
const side = m.MaterialSide
|
||||||
|
if (side === undefined || side === null || side === '') return
|
||||||
|
extra[`Side${side}ReportedMainCode`] = m.ReportedMainCode || ''
|
||||||
|
extra[`Side${side}OriginalMainCode`] = m.OriginalMainCode || ''
|
||||||
|
})
|
||||||
|
return { ...item, ...extra }
|
||||||
|
}
|
||||||
|
|
||||||
|
const sideMaterials = computed(() => {
|
||||||
|
const fromCheck = pickMaterials(cuttingList.value[0]?.Materials)
|
||||||
|
if (fromCheck.length) {
|
||||||
|
return fromCheck.map((m) => ({
|
||||||
|
side: m.MaterialSide ?? '',
|
||||||
|
reported: m.ReportedMainCode || '',
|
||||||
|
original: m.OriginalMainCode || '',
|
||||||
|
batchChanged: !!m.IsBatchChanged,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
const items = info.value.preWeldMaterialItems || []
|
||||||
|
return items.map((item, i) => ({
|
||||||
|
side: i + 1,
|
||||||
|
reported: item.ReportedMainCode || item.MainCode || item.MaterialCode || '',
|
||||||
|
original: item.OriginalMainCode || '',
|
||||||
|
batchChanged: !!item.IsBatchChanged,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(needSpecialReviewer, (need) => {
|
||||||
|
if (!need) {
|
||||||
|
layingOffForm.value.SpecialReviewerId = ''
|
||||||
|
specialReviewerName.value = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 照片组件引用
|
// 照片组件引用
|
||||||
const photoRef = ref(null)
|
const photoRef = ref(null)
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
const failVisible = ref(layingOffForm.value.CheckResult === '不合格')
|
const failVisible = ref(layingOffForm.value.CheckResult === '不合格')
|
||||||
const failAnimating = ref(false)
|
const failAnimating = ref(false)
|
||||||
@@ -326,41 +387,48 @@ const handleSubmit = () => {
|
|||||||
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
|
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (submitting.value) return
|
||||||
if (!validateSpecialReviewer()) return
|
if (!validateSpecialReviewer()) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '确认提交',
|
title: '确认提交',
|
||||||
content: '确定提交吗?',
|
content: '确定提交吗?',
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (!res.confirm) return
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
if (photoRef.value?.hasPending()) {
|
if (photoRef.value?.hasPending()) {
|
||||||
uni.showLoading({ title: '上传照片中...', mask: true })
|
uni.showLoading({ title: '上传照片中...', mask: true })
|
||||||
await photoRef.value.uploadAll()
|
await photoRef.value.uploadAll()
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
}
|
}
|
||||||
const CuttingAttachUrl1 = formAttachUrl.value || info.value.CuttingAttachUrl1 || ''
|
const CuttingAttachUrl1 = formAttachUrl.value || info.value.CuttingAttachUrl1 || ''
|
||||||
|
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
ProjectId: currentProject.value?.ProjectId, // 项目ID
|
CuttingCheckId: null,
|
||||||
WeldJointId: info.value?.WeldJointId, // 焊口ID
|
ProjectId: currentProject.value?.ProjectId,
|
||||||
CuttingLength: layingOffForm.value.CuttingLength, // 下料长度
|
WeldJointId: info.value?.WeldJointId,
|
||||||
GrooveForm: layingOffForm.value.GrooveForm, // 坡口形式
|
CuttingLength: layingOffForm.value.CuttingLength,
|
||||||
GrooveAngle: layingOffForm.value.GrooveAngle, // 坡口角度
|
GrooveForm: layingOffForm.value.GrooveForm,
|
||||||
IsMaterialCodeBatchNoAccurate: layingOffForm.value.IsMaterialCodeBatchNoAccurate === '准确', // 材料编码批次
|
GrooveProcessType: layingOffForm.value.GrooveProcessType,
|
||||||
IsMaterialQuantityAccurate: layingOffForm.value.IsMaterialQuantityAccurate === '准确', // 材料数量
|
GrooveAngle: layingOffForm.value.GrooveAngle,
|
||||||
SpecialReviewerId: layingOffForm.value.SpecialReviewerId || '', // 专项审核办理人
|
IsMaterialCodeBatchNoAccurate: layingOffForm.value.IsMaterialCodeBatchNoAccurate === '准确',
|
||||||
CheckPerson: userInfo.value?.PersonId, // 检查人员
|
IsMaterialQuantityAccurate: layingOffForm.value.IsMaterialQuantityAccurate === '准确',
|
||||||
CheckTime: uni.formatTime(new Date().getTime(), 'YYYY-MM-DD HH:mm'), // 检查时间
|
SpecialReviewerId: needSpecialReviewer.value ? (layingOffForm.value.SpecialReviewerId || null) : null,
|
||||||
CreateUser: userInfo.value?.PersonId, // 创建人员
|
CheckPerson: userInfo.value?.PersonId,
|
||||||
CheckResult: layingOffForm.value.CheckResult, // 检查结果
|
CheckTime: uni.formatTime(new Date().getTime(), 'YYYY-MM-DD HH:mm'),
|
||||||
Remark: remark.value, // 备注
|
CreateUser: userInfo.value?.PersonId,
|
||||||
UnqualifiedReason: layingOffForm.value.UnqualifiedReason, // 不合格原因
|
CheckResult: layingOffForm.value.CheckResult,
|
||||||
RectifyRequirement: layingOffForm.value.RectifyRequirement, // 整改要求
|
Remark: layingOffForm.value.Remark || '',
|
||||||
|
UnqualifiedReason: layingOffForm.value.UnqualifiedReason,
|
||||||
|
RectifyRequirement: layingOffForm.value.RectifyRequirement,
|
||||||
AttachUrl1: CuttingAttachUrl1,
|
AttachUrl1: CuttingAttachUrl1,
|
||||||
}
|
}
|
||||||
await reqSaveCuttingCheck(params)
|
await reqSaveCuttingCheck(params)
|
||||||
uni.showToast({ title: '提交成功', icon: 'none' })
|
uni.showToast({ title: '提交成功', icon: 'none' })
|
||||||
setTimeout(() => { uni.navigateBack() }, 1500)
|
setTimeout(() => { uni.navigateBack() }, 1500)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存下料抽检失败:', error)
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -384,13 +452,19 @@ const getInfo = async (id) => {
|
|||||||
if (info.value.WeldJointId) {
|
if (info.value.WeldJointId) {
|
||||||
const cuttingRes = await reqCuttingCheckByWeldJointId(info.value.WeldJointId)
|
const cuttingRes = await reqCuttingCheckByWeldJointId(info.value.WeldJointId)
|
||||||
if (cuttingRes.code === 1 && cuttingRes.data) {
|
if (cuttingRes.code === 1 && cuttingRes.data) {
|
||||||
cuttingList.value = cuttingRes.data
|
cuttingList.value = (Array.isArray(cuttingRes.data) ? cuttingRes.data : []).map(flattenCuttingRecord)
|
||||||
if (cuttingList.value.length > 0) {
|
if (cuttingList.value.length > 0) {
|
||||||
layingOffForm.value.CuttingLength = cuttingList.value[0].CuttingLength
|
const latest = cuttingList.value[0]
|
||||||
layingOffForm.value.GrooveForm = cuttingList.value[0].GrooveForm
|
layingOffForm.value.CuttingLength = latest.CuttingLength
|
||||||
layingOffForm.value.GrooveAngle = cuttingList.value[0].GrooveAngle
|
layingOffForm.value.GrooveForm = latest.GrooveForm
|
||||||
layingOffForm.value.IsMaterialCodeBatchNoAccurate = cuttingList.value[0].IsMaterialCodeBatchNoAccurate?'准确' : '不准确'
|
layingOffForm.value.GrooveProcessType = latest.GrooveProcessType || ''
|
||||||
layingOffForm.value.IsMaterialQuantityAccurate = cuttingList.value[0].IsMaterialQuantityAccurate?'准确' : '不准确'
|
layingOffForm.value.GrooveAngle = latest.GrooveAngle
|
||||||
|
layingOffForm.value.IsMaterialCodeBatchNoAccurate = latest.IsMaterialCodeBatchNoAccurate?'准确' : '不准确'
|
||||||
|
layingOffForm.value.IsMaterialQuantityAccurate = latest.IsMaterialQuantityAccurate?'准确' : '不准确'
|
||||||
|
if (latest.SpecialReviewerId) {
|
||||||
|
layingOffForm.value.SpecialReviewerId = latest.SpecialReviewerId
|
||||||
|
specialReviewerName.value = latest.SpecialReviewerName || ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,4 +708,38 @@ $shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.side-codes {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 8rpx 0 12rpx;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6rpx;
|
||||||
|
padding: 16rpx 20rpx;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__line {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: $text-secondary;
|
||||||
|
font-family: 'SF Mono', 'Menlo', 'Consolas', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__changed {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -29,6 +29,48 @@
|
|||||||
failText="不合格" />
|
failText="不合格" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊缝余高</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="form.WeldReinforcement" type="digit"
|
||||||
|
placeholder="请输入焊缝余高" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊缝高度</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="form.WeldHeight" type="digit"
|
||||||
|
placeholder="请输入焊缝高度" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊缝宽度</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="form.WeldWidth" type="digit"
|
||||||
|
placeholder="请输入焊缝宽度" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">表面缺陷</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="form.SurfaceDefect" type="text"
|
||||||
|
placeholder="请输入表面缺陷" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">预热温度</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="form.PreheatTemperature" type="digit"
|
||||||
|
placeholder="请输入预热温度" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">层间温度</text>
|
||||||
|
<view class="card__value-wrap">
|
||||||
|
<input class="card__input" v-model="form.InterpassTemperature" type="digit"
|
||||||
|
placeholder="请输入层间温度" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="card__row">
|
<view class="card__row">
|
||||||
<text class="card__label">检测人</text>
|
<text class="card__label">检测人</text>
|
||||||
<view class="card__value-wrap">
|
<view class="card__value-wrap">
|
||||||
@@ -59,8 +101,9 @@
|
|||||||
|
|
||||||
<!-- 提交按钮 -->
|
<!-- 提交按钮 -->
|
||||||
<view class="submit-bar">
|
<view class="submit-bar">
|
||||||
<view class="btn-primary-gradient" @click="handleSubmit">
|
<view class="btn-primary-gradient" :class="{ 'btn-primary-gradient--disabled': submitting }"
|
||||||
<text class="btn-primary-gradient__text">提交结果</text>
|
@click="handleSubmit">
|
||||||
|
<text class="btn-primary-gradient__text">{{ submitting ? '提交中...' : '提交结果' }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -95,11 +138,18 @@
|
|||||||
const info = ref({})
|
const info = ref({})
|
||||||
const recordList = ref([])
|
const recordList = ref([])
|
||||||
const photoRef = ref(null)
|
const photoRef = ref(null)
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
qualifiedText: '合格',
|
qualifiedText: '合格',
|
||||||
Remark: '',
|
Remark: '',
|
||||||
AttachUrl: ''
|
AttachUrl: '',
|
||||||
|
WeldReinforcement: '',
|
||||||
|
WeldHeight: '',
|
||||||
|
WeldWidth: '',
|
||||||
|
SurfaceDefect: '',
|
||||||
|
PreheatTemperature: '',
|
||||||
|
InterpassTemperature: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const checkPersonName = computed(() => userInfo.value?.PersonName || '')
|
const checkPersonName = computed(() => userInfo.value?.PersonName || '')
|
||||||
@@ -172,7 +222,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toNum = (val) => {
|
||||||
|
if (val === '' || val === null || val === undefined) return null
|
||||||
|
const n = Number(val)
|
||||||
|
return Number.isNaN(n) ? null : n
|
||||||
|
}
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
|
if (submitting.value) return
|
||||||
const jointId = info.value.WeldJointId || id.value
|
const jointId = info.value.WeldJointId || id.value
|
||||||
if (!jointId) {
|
if (!jointId) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -195,6 +252,7 @@
|
|||||||
confirm
|
confirm
|
||||||
}) => {
|
}) => {
|
||||||
if (!confirm) return
|
if (!confirm) return
|
||||||
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
if (photoRef.value?.hasPending()) {
|
if (photoRef.value?.hasPending()) {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
@@ -205,6 +263,7 @@
|
|||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
}
|
}
|
||||||
await reqSaveWeldAppearanceCheck({
|
await reqSaveWeldAppearanceCheck({
|
||||||
|
AppearanceCheckId: null,
|
||||||
ProjectId: currentProject.value?.ProjectId || info.value.ProjectId,
|
ProjectId: currentProject.value?.ProjectId || info.value.ProjectId,
|
||||||
WeldJointId: jointId,
|
WeldJointId: jointId,
|
||||||
IsQualified: form.value.qualifiedText === '合格',
|
IsQualified: form.value.qualifiedText === '合格',
|
||||||
@@ -213,7 +272,12 @@
|
|||||||
CreateUser: userInfo.value?.PersonId,
|
CreateUser: userInfo.value?.PersonId,
|
||||||
Remark: form.value.Remark || '',
|
Remark: form.value.Remark || '',
|
||||||
AttachUrl: form.value.AttachUrl,
|
AttachUrl: form.value.AttachUrl,
|
||||||
AppearanceCheckId: ''
|
WeldReinforcement: toNum(form.value.WeldReinforcement),
|
||||||
|
WeldHeight: toNum(form.value.WeldHeight),
|
||||||
|
WeldWidth: toNum(form.value.WeldWidth),
|
||||||
|
SurfaceDefect: form.value.SurfaceDefect || '',
|
||||||
|
PreheatTemperature: toNum(form.value.PreheatTemperature),
|
||||||
|
InterpassTemperature: toNum(form.value.InterpassTemperature)
|
||||||
})
|
})
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '提交成功',
|
title: '提交成功',
|
||||||
@@ -224,6 +288,8 @@
|
|||||||
}, 1500)
|
}, 1500)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存焊缝外观检测失败:', error)
|
console.error('保存焊缝外观检测失败:', error)
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,385 @@
|
|||||||
|
<template>
|
||||||
|
<view class="search-page">
|
||||||
|
<!-- 顶部:输入框内扫码(类似淘宝搜索) -->
|
||||||
|
<view class="search-bar">
|
||||||
|
<view class="search-bar__input-wrap">
|
||||||
|
<u-icon
|
||||||
|
name="scan"
|
||||||
|
:size="28"
|
||||||
|
color="#2979ff"
|
||||||
|
@click="handleScan"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="search-bar__input"
|
||||||
|
v-model="keyword"
|
||||||
|
type="text"
|
||||||
|
confirm-type="search"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:focus="autoFocus"
|
||||||
|
@input="handleSearchInput"
|
||||||
|
@confirm="handleSearchConfirm"
|
||||||
|
/>
|
||||||
|
<u-icon
|
||||||
|
v-if="keyword"
|
||||||
|
name="close-circle-fill"
|
||||||
|
:size="28"
|
||||||
|
color="#ccc"
|
||||||
|
@click="handleClear"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 结果列表 -->
|
||||||
|
<scroll-view
|
||||||
|
class="result-scroll"
|
||||||
|
scroll-y
|
||||||
|
@scrolltolower="loadMore"
|
||||||
|
>
|
||||||
|
<view class="result-list">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in listData"
|
||||||
|
:key="item.WeldJointId || item.Id || index"
|
||||||
|
class="result-item"
|
||||||
|
@click="handleSelect(item)"
|
||||||
|
>
|
||||||
|
<view class="result-item__main">
|
||||||
|
<text class="result-item__code">{{ item.WeldJointCode || '--' }}</text>
|
||||||
|
<text
|
||||||
|
v-if="item.PipelineCode"
|
||||||
|
class="result-item__sub"
|
||||||
|
>管线 {{ item.PipelineCode }}</text>
|
||||||
|
</view>
|
||||||
|
<u-icon
|
||||||
|
name="arrow-right"
|
||||||
|
:size="24"
|
||||||
|
color="#ccc"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<u-empty
|
||||||
|
v-if="!loading && searched && listData.length === 0"
|
||||||
|
mode="search"
|
||||||
|
text="未找到焊口"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-if="!searched && !loading"
|
||||||
|
class="result-hint"
|
||||||
|
>
|
||||||
|
<text>扫码或输入焊口/管线编号搜索</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-if="loading && listData.length > 0"
|
||||||
|
class="loading-more"
|
||||||
|
>
|
||||||
|
<u-loading
|
||||||
|
mode="circle"
|
||||||
|
size="28"
|
||||||
|
/>
|
||||||
|
<text>加载中...</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-if="!loading && !hasMore && listData.length > 0"
|
||||||
|
class="no-more"
|
||||||
|
>
|
||||||
|
<text>— 没有更多了 —</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
/**
|
||||||
|
* 焊口搜索中间页:扫码进入业务页,或关键字搜索后点选进入
|
||||||
|
* 入参:target(业务页路径)、title(导航标题)
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useUserStore, useMenuStore } from '@/store'
|
||||||
|
import { getUrlParam } from '@/utils/request.js'
|
||||||
|
import { reqPipeJointWeldedJoints } from '@/api/hj.js'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
const { currentProject } = storeToRefs(userStore)
|
||||||
|
|
||||||
|
/** 业务目标页,如 /scanpages/hj/material_sampling */
|
||||||
|
const targetPath = ref('')
|
||||||
|
const placeholder = ref('搜索焊口')
|
||||||
|
const autoFocus = ref(true)
|
||||||
|
|
||||||
|
const keyword = ref('')
|
||||||
|
const listData = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const searched = ref(false)
|
||||||
|
const hasMore = ref(true)
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = 20
|
||||||
|
let searchTimer = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从接口响应取出列表
|
||||||
|
* @param {any} data
|
||||||
|
*/
|
||||||
|
const pickList = (data) => {
|
||||||
|
if (!data) return []
|
||||||
|
if (Array.isArray(data)) return data
|
||||||
|
if (Array.isArray(data.getDataList)) return data.getDataList
|
||||||
|
if (Array.isArray(data.list)) return data.list
|
||||||
|
if (Array.isArray(data.records)) return data.records
|
||||||
|
if (Array.isArray(data.Items)) return data.Items
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearList = () => {
|
||||||
|
listData.value = []
|
||||||
|
hasMore.value = false
|
||||||
|
searched.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拉取焊口列表
|
||||||
|
* @param {boolean} isRefresh
|
||||||
|
*/
|
||||||
|
const loadList = async (isRefresh = true) => {
|
||||||
|
const kw = keyword.value.trim()
|
||||||
|
const projectId = currentProject.value?.ProjectId
|
||||||
|
if (!projectId) {
|
||||||
|
uni.showToast({ title: '请先选择项目', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!kw) {
|
||||||
|
clearList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (loading.value) return
|
||||||
|
if (!isRefresh && !hasMore.value) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
if (isRefresh) {
|
||||||
|
currentPage.value = 1
|
||||||
|
hasMore.value = true
|
||||||
|
listData.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await reqPipeJointWeldedJoints({
|
||||||
|
projectId,
|
||||||
|
keyword: kw,
|
||||||
|
pageIndex: currentPage.value,
|
||||||
|
pageSize,
|
||||||
|
})
|
||||||
|
const data = res?.data ?? {}
|
||||||
|
const pageData = pickList(data)
|
||||||
|
const totalPages = Number(data.pageCount) || 0
|
||||||
|
const totalCount = Number(data.totalCount) || 0
|
||||||
|
if (totalPages > 0) {
|
||||||
|
hasMore.value = currentPage.value < totalPages
|
||||||
|
} else if (totalCount > 0) {
|
||||||
|
hasMore.value = listData.value.length + pageData.length < totalCount
|
||||||
|
} else {
|
||||||
|
hasMore.value = pageData.length >= pageSize
|
||||||
|
}
|
||||||
|
listData.value = isRefresh ? pageData : listData.value.concat(pageData)
|
||||||
|
searched.value = true
|
||||||
|
} catch (e) {
|
||||||
|
console.error('焊口搜索失败:', e)
|
||||||
|
if (isRefresh) listData.value = []
|
||||||
|
searched.value = true
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearchInput = () => {
|
||||||
|
if (searchTimer) clearTimeout(searchTimer)
|
||||||
|
searchTimer = setTimeout(() => {
|
||||||
|
const kw = keyword.value.trim()
|
||||||
|
if (!kw) {
|
||||||
|
clearList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadList(true)
|
||||||
|
}, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearchConfirm = () => {
|
||||||
|
if (searchTimer) clearTimeout(searchTimer)
|
||||||
|
loadList(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClear = () => {
|
||||||
|
keyword.value = ''
|
||||||
|
clearList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadMore = () => {
|
||||||
|
if (!loading.value && hasMore.value && keyword.value.trim()) {
|
||||||
|
currentPage.value += 1
|
||||||
|
loadList(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进入业务页
|
||||||
|
* @param {string} id WeldJointId
|
||||||
|
*/
|
||||||
|
const goTarget = (id) => {
|
||||||
|
if (!id) {
|
||||||
|
uni.showToast({ title: '缺少焊口信息', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!targetPath.value) {
|
||||||
|
uni.showToast({ title: '缺少目标页面', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!menuStore.canAccessPath(targetPath.value)) {
|
||||||
|
uni.showToast({ title: '当前岗位无此功能权限', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `${targetPath.value}?id=${encodeURIComponent(id)}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点选搜索结果
|
||||||
|
* @param {object} item
|
||||||
|
*/
|
||||||
|
const handleSelect = (item) => {
|
||||||
|
const id = item.WeldJointId || item.Id || item.id
|
||||||
|
goTarget(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫码:与首页菜单扫码一致,解析 id 后进入业务页
|
||||||
|
*/
|
||||||
|
const handleScan = () => {
|
||||||
|
uni.scanCode({
|
||||||
|
scanType: ['datamatrix', 'barCode', 'qrCode', 'wxCode', 'pdf417'],
|
||||||
|
success: (res) => {
|
||||||
|
const result = res.result || ''
|
||||||
|
let id = getUrlParam(result, 'id')
|
||||||
|
if (!id) {
|
||||||
|
id = String(result).trim()
|
||||||
|
}
|
||||||
|
if (!id) {
|
||||||
|
uni.showToast({ title: '未识别到焊口', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
goTarget(id)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
if (err?.errMsg && String(err.errMsg).includes('cancel')) return
|
||||||
|
uni.showToast({ title: '扫码失败,请重试', icon: 'none' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((opt) => {
|
||||||
|
targetPath.value = decodeURIComponent(opt.target || '')
|
||||||
|
const title = opt.title ? decodeURIComponent(opt.title) : '选择焊口'
|
||||||
|
uni.setNavigationBarTitle({ title })
|
||||||
|
if (!targetPath.value) {
|
||||||
|
uni.showToast({ title: '入口参数错误', icon: 'none' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.search-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f5f6f8;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx 24rpx;
|
||||||
|
background: #fff;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
&__input-wrap {
|
||||||
|
flex: 1;
|
||||||
|
height: 72rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
background: #f5f6f8;
|
||||||
|
border-radius: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
height: 72rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-scroll {
|
||||||
|
flex: 1;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-list {
|
||||||
|
padding: 16rpx 24rpx 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 28rpx 24rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
|
||||||
|
&__main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__code {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a2332;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__sub {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-hint {
|
||||||
|
padding: 80rpx 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-more,
|
||||||
|
.no-more {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
padding: 24rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
<template>
|
||||||
|
<view class="detail-page">
|
||||||
|
<!-- 任务单摘要 -->
|
||||||
|
<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>
|
||||||
|
<text class="card__value card__value--mono">{{ detail.TaskCode || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">任务日期</text>
|
||||||
|
<text class="card__value">{{ fmtDate(detail.TaskDate) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">单位工程</text>
|
||||||
|
<text class="card__value">{{ detail.UnitWorkName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">施工单位</text>
|
||||||
|
<text class="card__value">{{ detail.UnitName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">班组</text>
|
||||||
|
<text class="card__value">{{ detail.TeamGroupName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">流水号</text>
|
||||||
|
<text class="card__value">{{ detail.SerialNumber || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊口数量</text>
|
||||||
|
<text class="card__value">{{ detail.WeldJointCount ?? joints.length }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 焊口明细 -->
|
||||||
|
<view class="section">
|
||||||
|
<view class="section__header">
|
||||||
|
<view class="section__bar"></view>
|
||||||
|
<text class="section__title">焊口明细({{ joints.length }})</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in joints"
|
||||||
|
:key="item.WeldTaskId || item.WeldJointId || index"
|
||||||
|
class="card joint-card"
|
||||||
|
>
|
||||||
|
<view class="joint-card__title">{{ item.WeldJointCode || '--' }}</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">管线编号</text>
|
||||||
|
<text class="card__value">{{ item.PipelineCode || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊口属性</text>
|
||||||
|
<text class="card__value">{{ item.JointAttribute || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊接模式</text>
|
||||||
|
<text class="card__value">{{ item.WeldingMode || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">焊接类型</text>
|
||||||
|
<text class="card__value">{{ item.WeldTypeCode || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">达因</text>
|
||||||
|
<text class="card__value">{{ formatSize(item.Size) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">盖面焊工</text>
|
||||||
|
<text class="card__value">{{ item.CoverWelderId || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card__row">
|
||||||
|
<text class="card__label">打底焊工</text>
|
||||||
|
<text class="card__value">{{ item.BackingWelderId || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<u-empty
|
||||||
|
v-if="!loading && joints.length === 0"
|
||||||
|
mode="list"
|
||||||
|
text="暂无焊口明细"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 生成出库申请 -->
|
||||||
|
<view class="submit-bar">
|
||||||
|
<view
|
||||||
|
class="btn-primary-gradient"
|
||||||
|
:class="{ 'btn-primary-gradient--disabled': submitting || !canGenerate }"
|
||||||
|
@click="handleGenerate"
|
||||||
|
>
|
||||||
|
<text class="btn-primary-gradient__text">
|
||||||
|
{{ submitting ? '处理中...' : '生成出库申请单' }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
/**
|
||||||
|
* 焊接任务单详情:展示 Joints,支持生成出库申请单
|
||||||
|
*/
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import { reqWeldTaskDetail, reqWeldTaskGenerateOutPlan } from '@/api/hj.js'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { userInfo, token } = storeToRefs(userStore)
|
||||||
|
|
||||||
|
const projectId = ref('')
|
||||||
|
const taskCode = ref('')
|
||||||
|
const unitWorkId = ref('')
|
||||||
|
const detail = ref({})
|
||||||
|
const loading = ref(false)
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
|
const joints = computed(() => {
|
||||||
|
const list = detail.value?.Joints
|
||||||
|
return Array.isArray(list) ? list : []
|
||||||
|
})
|
||||||
|
|
||||||
|
const canGenerate = computed(() => !!(projectId.value && taskCode.value))
|
||||||
|
|
||||||
|
const fmtDate = (val) => {
|
||||||
|
if (!val) return '--'
|
||||||
|
const d = new Date(val)
|
||||||
|
if (isNaN(d.getTime())) return String(val).slice(0, 10)
|
||||||
|
const y = d.getFullYear()
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(d.getDate()).padStart(2, '0')
|
||||||
|
return `${y}-${m}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatSize = (val) => {
|
||||||
|
if (val === undefined || val === null || val === '') return '--'
|
||||||
|
return String(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadDetail = async () => {
|
||||||
|
if (!projectId.value || !taskCode.value) {
|
||||||
|
uni.showToast({ title: '入口参数错误', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await reqWeldTaskDetail({
|
||||||
|
projectId: projectId.value,
|
||||||
|
taskCode: taskCode.value,
|
||||||
|
unitWorkId: unitWorkId.value || undefined,
|
||||||
|
})
|
||||||
|
detail.value = res?.data || {}
|
||||||
|
if (!res?.data) {
|
||||||
|
uni.showToast({ title: '未找到任务单', icon: 'none' })
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('任务单详情加载失败:', e)
|
||||||
|
detail.value = {}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGenerate = () => {
|
||||||
|
if (submitting.value || !canGenerate.value) return
|
||||||
|
uni.showModal({
|
||||||
|
title: '确认生成',
|
||||||
|
content: '确定根据当前任务单生成出库申请单吗?已生成过的不会重复建单。',
|
||||||
|
success: async (modalRes) => {
|
||||||
|
if (!modalRes.confirm) return
|
||||||
|
const personId = userInfo.value?.PersonId || token.value
|
||||||
|
if (!personId) {
|
||||||
|
uni.showToast({ title: '缺少登录人信息', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
|
await reqWeldTaskGenerateOutPlan({
|
||||||
|
ProjectId: projectId.value,
|
||||||
|
TaskCode: taskCode.value,
|
||||||
|
PersonId: personId,
|
||||||
|
})
|
||||||
|
// 接口成功也可能 data 为 null(首次/已存在/无材料均可能 code:1)
|
||||||
|
uni.showToast({
|
||||||
|
title: '生成请求已处理',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.error('生成出库申请失败:', e)
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((opt) => {
|
||||||
|
projectId.value = decodeURIComponent(opt.projectId || '')
|
||||||
|
taskCode.value = decodeURIComponent(opt.taskCode || '')
|
||||||
|
unitWorkId.value = decodeURIComponent(opt.unitWorkId || '')
|
||||||
|
loadDetail()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 24rpx 24rpx 160rpx;
|
||||||
|
background: #f5f6f8;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bar {
|
||||||
|
width: 8rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
background: #2979ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a2332;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 8rpx 24rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24rpx;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value {
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
&--mono {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a2332;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.joint-card {
|
||||||
|
&__title {
|
||||||
|
padding: 20rpx 0 4rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a2332;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-bar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 20rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary-gradient {
|
||||||
|
height: 88rpx;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(135deg, #2979ff, #5a9aff);
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<view class="page-list">
|
||||||
|
<scroll-view
|
||||||
|
class="list-scroll"
|
||||||
|
scroll-y
|
||||||
|
refresher-enabled
|
||||||
|
:refresher-triggered="refreshing"
|
||||||
|
@refresherrefresh="handleRefresh"
|
||||||
|
>
|
||||||
|
<view class="list-wrap">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in listData"
|
||||||
|
:key="item.TaskCode || index"
|
||||||
|
class="card-item"
|
||||||
|
@click="handleItemClick(item)"
|
||||||
|
>
|
||||||
|
<view class="card-header">
|
||||||
|
<text class="card-code">{{ item.TaskCode || '--' }}</text>
|
||||||
|
<text class="card-tag status-1">焊口 {{ item.WeldJointCount ?? 0 }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-body">
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">任务日期</text>
|
||||||
|
<text class="row-value">{{ fmtDate(item.TaskDate) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">单位工程</text>
|
||||||
|
<text class="row-value">{{ item.UnitWorkName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">施工单位</text>
|
||||||
|
<text class="row-value">{{ item.UnitName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">班组</text>
|
||||||
|
<text class="row-value">{{ item.TeamGroupName || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-row">
|
||||||
|
<text class="row-label">流水号</text>
|
||||||
|
<text class="row-value">{{ item.SerialNumber || '--' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<u-empty
|
||||||
|
v-if="!loading && listData.length === 0"
|
||||||
|
mode="list"
|
||||||
|
text="暂无焊接任务单"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
/**
|
||||||
|
* 焊接任务单列表:自动带入登录人 teamGroupId / unitWorkId + 当前项目查询
|
||||||
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { onShow } from '@dcloudio/uni-app'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import { reqWeldTaskListByTeamGroup } from '@/api/hj.js'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { currentProject, userInfo } = storeToRefs(userStore)
|
||||||
|
|
||||||
|
const listData = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const refreshing = ref(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录人班组 ID
|
||||||
|
* @param {object|null} user
|
||||||
|
*/
|
||||||
|
const resolveTeamGroupId = (user) => {
|
||||||
|
if (!user) return ''
|
||||||
|
return user.teamGroupId || user.TeamGroupId || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录人单位工程 ID
|
||||||
|
* @param {object|null} user
|
||||||
|
*/
|
||||||
|
const resolveUnitWorkId = (user) => {
|
||||||
|
if (!user) return ''
|
||||||
|
return user.unitWorkId || user.UnitWorkId || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const fmtDate = (val) => {
|
||||||
|
if (!val) return '--'
|
||||||
|
const d = new Date(val)
|
||||||
|
if (isNaN(d.getTime())) return String(val).slice(0, 10)
|
||||||
|
const y = d.getFullYear()
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(d.getDate()).padStart(2, '0')
|
||||||
|
return `${y}-${m}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchList = async () => {
|
||||||
|
const projectId = currentProject.value?.ProjectId
|
||||||
|
if (!projectId) {
|
||||||
|
uni.showToast({ title: '请先选择项目', icon: 'none' })
|
||||||
|
listData.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (loading.value) return
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await reqWeldTaskListByTeamGroup({
|
||||||
|
projectId,
|
||||||
|
teamGroupId: resolveTeamGroupId(userInfo.value) || undefined,
|
||||||
|
unitWorkId: resolveUnitWorkId(userInfo.value) || undefined,
|
||||||
|
})
|
||||||
|
const data = res?.data
|
||||||
|
listData.value = Array.isArray(data) ? data : []
|
||||||
|
} catch (e) {
|
||||||
|
console.error('任务单列表加载失败:', e)
|
||||||
|
listData.value = []
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
refreshing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
refreshing.value = true
|
||||||
|
fetchList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleItemClick = (item) => {
|
||||||
|
const projectId = item.ProjectId || currentProject.value?.ProjectId || ''
|
||||||
|
const taskCode = item.TaskCode || ''
|
||||||
|
const unitWorkId = item.UnitWorkId || item.unitWorkId || resolveUnitWorkId(userInfo.value) || ''
|
||||||
|
if (!projectId || !taskCode) {
|
||||||
|
uni.showToast({ title: '任务单信息不完整', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let url = `/scanpages/hj/weld_task_detail?projectId=${encodeURIComponent(projectId)}&taskCode=${encodeURIComponent(taskCode)}`
|
||||||
|
if (unitWorkId) {
|
||||||
|
url += `&unitWorkId=${encodeURIComponent(unitWorkId)}`
|
||||||
|
}
|
||||||
|
uni.navigateTo({ url })
|
||||||
|
}
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
fetchList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
+18
-4
@@ -54,8 +54,7 @@ export const defaultApps = [{
|
|||||||
name: '下料抽检',
|
name: '下料抽检',
|
||||||
icon: 'xialiaochoujianjilu',
|
icon: 'xialiaochoujianjilu',
|
||||||
menuId: "",
|
menuId: "",
|
||||||
path: "/scanpages/hj/material_sampling",
|
path: "/scanpages/hj/weld_joint_search?target=%2Fscanpages%2Fhj%2Fmaterial_sampling&title=%E4%B8%8B%E6%96%99%E6%8A%BD%E6%A3%80",
|
||||||
isScan: true,
|
|
||||||
funcKey: 'sampling',
|
funcKey: 'sampling',
|
||||||
prefix: 'nbd-icon',
|
prefix: 'nbd-icon',
|
||||||
selected: false
|
selected: false
|
||||||
@@ -64,8 +63,7 @@ export const defaultApps = [{
|
|||||||
name: '组对抽查',
|
name: '组对抽查',
|
||||||
icon: 'zudui',
|
icon: 'zudui',
|
||||||
menuId: "",
|
menuId: "",
|
||||||
path: "/scanpages/hj/make_right",
|
path: "/scanpages/hj/weld_joint_search?target=%2Fscanpages%2Fhj%2Fmake_right&title=%E7%BB%84%E5%AF%B9%E6%8A%BD%E6%9F%A5",
|
||||||
isScan: true,
|
|
||||||
funcKey: 'makeRight',
|
funcKey: 'makeRight',
|
||||||
prefix: 'nbd-icon',
|
prefix: 'nbd-icon',
|
||||||
selected: false
|
selected: false
|
||||||
@@ -97,6 +95,22 @@ export const defaultApps = [{
|
|||||||
isScan: true,
|
isScan: true,
|
||||||
prefix: 'nbd-icon',
|
prefix: 'nbd-icon',
|
||||||
selected: false
|
selected: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '条码查询',
|
||||||
|
icon: 'saoyisao',
|
||||||
|
menuId: '',
|
||||||
|
path: '/scanpages/hj/barcode_search',
|
||||||
|
prefix: 'nbd-icon',
|
||||||
|
selected: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '焊接任务单',
|
||||||
|
icon: 'daiban',
|
||||||
|
menuId: '',
|
||||||
|
path: '/scanpages/hj/weld_task_list',
|
||||||
|
prefix: 'nbd-icon',
|
||||||
|
selected: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user