From 21d11697a02884b829a6a40728771eba3819a82e Mon Sep 17 00:00:00 2001
From: Zones <765289303@qq.com>
Date: Mon, 6 Jul 2026 16:46:07 +0800
Subject: [PATCH] =?UTF-8?q?=E4=B8=8B=E6=96=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
api/hj.js | 6 +-
assets/css/page.scss | 97 +++
components/barcodePrint.vue | 673 ------------------
components/nbd-anti-record.vue | 81 ++-
components/nbd-photo-view.vue | 85 +++
scanpages/hj/do_anti_rust.vue | 71 +-
scanpages/hj/material_sampling.vue | 1023 ++++++++++++++--------------
utils/request.js | 241 +++----
8 files changed, 899 insertions(+), 1378 deletions(-)
delete mode 100644 components/barcodePrint.vue
create mode 100644 components/nbd-photo-view.vue
diff --git a/api/hj.js b/api/hj.js
index cc7e706..69855fc 100644
--- a/api/hj.js
+++ b/api/hj.js
@@ -181,8 +181,10 @@ export const reqSaveAntiCorrosionCheck = (data={})=>post(`/AntiCorrosionCheck/Sa
/**
* 获取防腐填报记录
- * @param {String} materialCode
+ * @param {Object} params - { materialCode, projectId }
*/
-export const reqGetAntiCorrosionCheck = (params) => get(`/AntiCorrosionCheck/GetRecordsByMaterialCode?materialCode=${params.materialCode}&projectId=${params.projectId}`)
+export const reqGetAntiCorrosionCheck = (params = {}) => {
+ return get('/AntiCorrosionCheck/GetRecordsByMaterialCode', params)
+}
diff --git a/assets/css/page.scss b/assets/css/page.scss
index aef8ab6..3fbcb1f 100644
--- a/assets/css/page.scss
+++ b/assets/css/page.scss
@@ -1667,3 +1667,100 @@
}
}
}
+
+// ===== 详情页区块与卡片通用样式(do_anti_rust / 焊口详情页等)=====
+.section {
+ margin: 0 24rpx 20rpx;
+
+ &__header {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ margin-bottom: 14rpx;
+ padding: 0 6rpx;
+ }
+
+ &__bar {
+ width: 6rpx;
+ height: 26rpx;
+ background: #2979ff;
+ border-radius: 3rpx;
+ flex-shrink: 0;
+ }
+
+ &__title {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #0f1724;
+ letter-spacing: 0.5rpx;
+ }
+}
+
+.card {
+ background: #fff;
+ border-radius: 16rpx;
+ overflow: hidden;
+ box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.06);
+
+ &__row {
+ display: flex;
+ align-items: center;
+ padding: 22rpx 28rpx;
+ border-bottom: 1rpx solid #e8ecf1;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ &--stack {
+ flex-direction: column;
+ align-items: flex-start;
+ .card__label {
+ margin-bottom: 8rpx;
+ }
+ .card__value-wrap {
+ width: 100%;
+ justify-content: flex-start;
+ }
+ }
+ }
+
+ &__label {
+ width: 180rpx;
+ font-size: 26rpx;
+ color: #6b7c93;
+ flex-shrink: 0;
+ }
+
+ &__value {
+ flex: 1;
+ font-size: 28rpx;
+ color: #0f1724;
+ text-align: left;
+ }
+
+ &__value-wrap {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+ }
+
+ &__unit {
+ font-size: 24rpx;
+ color: #6b7c93;
+ flex-shrink: 0;
+ }
+
+ &__input {
+ flex: 1;
+ font-size: 28rpx;
+ color: #0f1724;
+ text-align: left;
+ height: 48rpx;
+
+ &::placeholder {
+ color: #b0bec5;
+ }
+ }
+}
diff --git a/components/barcodePrint.vue b/components/barcodePrint.vue
deleted file mode 100644
index ada883a..0000000
--- a/components/barcodePrint.vue
+++ /dev/null
@@ -1,673 +0,0 @@
-
-
-
-
-
-
-
- 打印机:
-
-
- {{ deviceList[deviceIndex].name }}
-
-
-
-
-
- 出纸方向:
-
-
- {{ rotationList[rotationIndex].name }}
-
-
-
-
-
- 纸张类型:
-
-
- {{ gapList[gapIndex].name }}
-
-
-
-
-
- 打印浓度:
-
-
- {{ darknessList[darknessIndex].name }}
-
-
-
-
-
- 打印速度:
-
-
- {{ speedList[speedIndex].name }}
-
-
-
-
-
- 灰度阈值:
-
-
-
-
-
-
- JSON配置模式
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/components/nbd-anti-record.vue b/components/nbd-anti-record.vue
index f2fa81f..a13a2cd 100644
--- a/components/nbd-anti-record.vue
+++ b/components/nbd-anti-record.vue
@@ -12,7 +12,7 @@
-
+
+
+ 喷砂情况
+
+ {{ latest.SandBlasting || '--' }}
+
+
+
+ 除锈喷砂情况
+
+ {{ latest.RustSandBlasting || '--' }}
+
+
检查人
{{ latest.CheckPersonName || '--' }}
@@ -56,15 +68,21 @@
{{ latest.CheckResult || '--' }}
-
- 不合格原因
- {{ latest.UnqualifiedReason }}
+
+ 不合格原因
+ {{ latest.UnqualifiedReason }}
-
- 整改要求
- {{ latest.RectifyRequirement
+
+ 整改要求
+ {{ latest.RectifyRequirement
}}
+
+ 照片
+
+
+
+
@@ -95,6 +113,18 @@
漆膜厚度
{{ item.FilmThickness || '--' }}
+
+ 喷砂情况
+
+ {{ item.SandBlasting || '--' }}
+
+
+
+ 除锈喷砂情况
+
+ {{ item.RustSandBlasting || '--' }}
+
+
检查人
{{ item.CheckPersonName || '--' }}
@@ -109,19 +139,25 @@
:class="item.CheckResult === '合格' ? 'anti-record__tag--pass' : 'anti-record__tag--fail'">
{{ item.CheckResult === '合格' ? '\u2713' :
'\u2717'
- }}
+ }}
{{ item.CheckResult || '--' }}
-
- 不合格原因
- {{ item.UnqualifiedReason
- }}
+
+ 不合格原因
+ {{ item.UnqualifiedReason
+ }}
-
- 整改要求
- {{ item.RectifyRequirement
- }}
+
+ 整改要求
+ {{ item.RectifyRequirement
+ }}
+
+
+ 照片
+
+
+
@@ -136,7 +172,8 @@ import { ref, computed, watch } from 'vue'
import { reqGetAntiCorrosionCheck } from '@/api/hj.js'
const props = defineProps({
- params: { type: Object, default: () => ({}) }
+ params: { type: Object, default: () => ({}) },
+ customStyle: { type: Object, default: () => ({}) },
})
const list = ref([])
@@ -146,9 +183,11 @@ const showPopup = ref(false)
const latest = computed(() => list.value[0] || null)
const fetchRecords = async () => {
+
const { materialCode, projectId } = props.params
if (!materialCode || !projectId) return
loading.value = true
+
try {
const res = await reqGetAntiCorrosionCheck(props.params)
if (res.code === 1 && res.data) {
@@ -261,6 +300,7 @@ $text-secondary: #8e99a4;
}
&--stack {
+ flex-direction: column;
align-items: flex-start;
.anti-record__value {
@@ -275,7 +315,7 @@ $text-secondary: #8e99a4;
color: $text-secondary;
flex-shrink: 0;
margin-right: 24rpx;
- width: 140rpx;
+ width: 160rpx;
&--stack {
font-size: 26rpx;
@@ -295,6 +335,9 @@ $text-secondary: #8e99a4;
&--stack {
font-size: 24rpx;
+ padding-left: 20rpx;
+ padding-bottom: 8rpx;
+ padding-top: 8rpx;
}
}
@@ -355,7 +398,7 @@ $text-secondary: #8e99a4;
&__popup {
width: 100%;
- height: 70vh;
+ height: 80vh;
background: #fff;
border-radius: 24rpx 24rpx 0 0;
display: flex;
diff --git a/components/nbd-photo-view.vue b/components/nbd-photo-view.vue
new file mode 100644
index 0000000..447e5ca
--- /dev/null
+++ b/components/nbd-photo-view.vue
@@ -0,0 +1,85 @@
+
+
+
+
+ 暂无图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scanpages/hj/do_anti_rust.vue b/scanpages/hj/do_anti_rust.vue
index 873d33d..e02d24c 100644
--- a/scanpages/hj/do_anti_rust.vue
+++ b/scanpages/hj/do_anti_rust.vue
@@ -55,7 +55,7 @@
- 防腐等级
+ 防腐等级
{{ antiForm.AnticorrosionLevel || '请选择防腐等级' }}
@@ -79,7 +79,7 @@
- 漆膜厚度
+ 漆膜厚度
@@ -107,7 +107,7 @@
-
+
-->
-
-
-
-
-
-
-
-
-
-
- 材料编码及炉批号校验
- 核对实物编码与批次信息
-
-
-
-
-
-
-
- 材料数量校验
- 核对实物数量与单据一致
-
-
-
-
-
-
-
+
@@ -113,13 +65,8 @@
备注
@@ -145,491 +92,531 @@
diff --git a/utils/request.js b/utils/request.js
index 326bfb4..96eb129 100644
--- a/utils/request.js
+++ b/utils/request.js
@@ -1,153 +1,115 @@
import { useUserStore } from '@/store'
-// TODO: 替换为实际的 API 地址
export const baseUrl = 'https://lygcgs.com.cn:8078/shjapi/api/'
export const baseFileUrl = 'https://lygcgs.com.cn:8078/shj/'
-// ===== 防止重复请求 =====
-const pendingRequests = new Map()
/**
- * 生成请求唯一标识
+ * 将参数对象序列化为 URL query string
+ * 手动构建确保跨平台(小程序 / H5 / App)行为一致
+ * - 过滤 undefined 和 null
+ * - encodeURIComponent 编码中文和特殊字符
*/
-function getRequestKey(config) {
- const { url = '', method = 'GET', data = {} } = config
- const paramStr = JSON.stringify(data)
- return `${method}:${url}:${paramStr}`
+function toQueryString(params) {
+ if (!params) return ''
+ const parts = Object.keys(params)
+ .filter((k) => params[k] !== undefined && params[k] !== null)
+ .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
+ return parts.length ? '?' + parts.join('&') : ''
}
/**
- * 检查是否为重复请求
+ * 核心请求方法(兼容 小程序 / H5 / App)
+ *
+ * @param {string} url - API 路径(不含 baseUrl)
+ * @param {object} options - 可选配置
+ * {string} method - GET | POST,默认 GET
+ * {object} data - GET 时自动拼入 query string,POST 时作为请求体
+ * {object} header - 自定义请求头
+ * {boolean} loading - 是否显示 loading,默认 true
+ * {boolean} toast - 是否在失败时弹 toast,默认 true
*/
-function checkDuplicate(config) {
- const key = getRequestKey(config)
- if (pendingRequests.has(key)) {
- const meta = config.meta || {}
- if (meta.toast !== false) {
- uni.showToast({ title: '请求过于频繁,请稍后再试', icon: 'none' })
- }
- return new Error('duplicate request')
+export function request(url, options = {}) {
+ const {
+ method = 'GET',
+ data,
+ header = {},
+ loading = true,
+ toast = true
+ } = options
+
+ const userStore = useUserStore()
+ const headers = {
+ 'content-type': 'application/json',
+ ...header
+ }
+ if (userStore.token) {
+ headers.token = userStore.token
}
- pendingRequests.set(key, true)
- return null
-}
-/**
- * 移除请求标识
- */
-function removePending(config) {
- const key = getRequestKey(config)
- pendingRequests.delete(key)
-}
-// ========================
+ // GET: 手动拼 query string(不依赖 uni.request 各平台差异)
+ let fullUrl = `${baseUrl}${url}`
+ if (method === 'GET' && data) {
+ fullUrl += toQueryString(data)
+ }
-// uview-pro 全局请求配置
-export const httpRequestConfig = {
- baseUrl,
- header: {
- 'content-type': 'application/json'
- },
- meta: {
- originalData: true,
- toast: true,
- loading: true
- }
-}
+ if (loading) {
+ uni.showLoading({ title: '加载中...', mask: true })
+ }
-// 全局请求/响应拦截器
-export const httpInterceptor = {
- request: (config) => {
- // 检查重复请求
- const dupError = checkDuplicate(config)
- if (dupError) throw dupError
-
- const meta = config.meta || {}
- if (meta.loading) {
- uni.showLoading({ title: '加载中...', mask: true })
- }
- const userStore = useUserStore()
- if (userStore.token) {
- config.header.token = userStore.token
- }
- return config
- },
- response: (response) => {
- const meta = response.config?.meta || {}
- if (meta.loading) {
- uni.hideLoading()
- }
-
- // 请求完成,移除标识
- removePending(response.config)
-
- // 根据业务处理错误、例如登录失效等处理接口返回错误码
- if (response.data.code !== 1) {
- if (meta.toast) {
- uni.showToast({
- title: response.data.message || '请求失败',
- icon: 'none'
- })
- }
- // 401 登录失效,跳转登录页
- if (response.data.code === 401) {
- const userStore = useUserStore()
- userStore.logout()
- uni.reLaunch({ url: '/pages/login/index' })
- }
- throw new Error(response.data.message || '请求失败')
- }
- uni.showToast({
- title: response.data.message || '请求成功',
- icon: 'none'
+ return new Promise((resolve, reject) => {
+ uni.request({
+ url: fullUrl,
+ method,
+ data: method === 'POST' ? data : undefined,
+ header: headers,
+ success: (res) => {
+ if (loading) uni.hideLoading()
+ const body = res.data
+ if (body.code !== 1) {
+ if (toast) {
+ uni.showToast({
+ title: body.message || '请求失败',
+ icon: 'none'
+ })
+ }
+ if (body.code === 401) {
+ userStore.logout()
+ uni.reLaunch({ url: '/pages/login/index' })
+ }
+ reject(new Error(body.message || '请求失败'))
+ return
+ }
+ resolve(body)
+ },
+ fail: (err) => {
+ if (loading) uni.hideLoading()
+ uni.showToast({ title: '网络连接失败', icon: 'none' })
+ reject(err)
+ }
})
- return response.data
- }
+ })
}
/**
- * 便捷请求方法(基于 uni.request 封装)
- * 也可用 uni.$http.get / uni.$http.post(uview-pro)
+ * GET 快捷方法
+ * 兼容两种调用方式:
+ * get('/path?key=val') 旧风格(URL 自带参数)
+ * get('/path', { key: 'val' }) 新风格(参数对象,自动编码)
*/
-export function request(options) {
- return new Promise((resolve, reject) => {
- // 运行请求拦截器
- const config = { ...httpRequestConfig, ...options }
- const finalConfig = httpInterceptor.request({
- ...config,
- header: { ...httpRequestConfig.header, ...options.header }
- })
-
- uni.request({
- ...finalConfig,
- url: `${finalConfig.baseUrl}${finalConfig.url}`,
- success: (res) => {
- try {
- const data = httpInterceptor.response({ data: res.data, config: finalConfig })
- resolve(data)
- } catch (err) {
- reject(err)
- }
- },
- fail: (err) => {
- removePending(finalConfig) // 网络失败也要清理标识
- uni.hideLoading()
- uni.showToast({ title: '网络连接失败', icon: 'none' })
- reject(err)
- }
- })
- })
+export const get = (url, params) => {
+ if (params) {
+ url += toQueryString(params)
+ }
+ return request(url, { method: 'GET' })
}
-// GET 快捷方法
-export const get = (url, params = {}) => {
- return request({ url, method: 'GET', data: params })
+/**
+ * POST 快捷方法
+ */
+export const post = (url, data) => {
+ return request(url, { method: 'POST', data })
}
-// POST 快捷方法
-export const post = (url, data = {}) => {
- return request({ url, method: 'POST', data })
-}
-
-
/**
* 解析附件 URL 字符串为可展示的照片列表
* @param {string} urlStr - 逗号分隔的附件路径,如 "FileUpLoad/xxx.png,FileUpLoad/yyy.png"
@@ -157,7 +119,7 @@ export const post = (url, data = {}) => {
export const parseAttachUrls = (urlStr, startId = 0) => {
if (!urlStr) return []
let id = startId
- return urlStr.split(',').filter(Boolean).map(url => ({
+ return urlStr.split(',').filter(Boolean).map((url) => ({
_id: ++id,
src: `${baseFileUrl}${url}`,
_attachUrl: url,
@@ -166,20 +128,11 @@ export const parseAttachUrls = (urlStr, startId = 0) => {
}
export const getUrlParam = (url, name) => {
- if (!url || !name) return null;
-
- // 构造正则:匹配 ?name= 或 &name= 后面的值
- // [?&] : 匹配起始分隔符
- // ${name}: 匹配具体的参数名
- // = : 匹配等号
- // ([^&]*) : 捕获组,匹配直到下一个 & 或字符串结束的内容
- const regex = new RegExp(`[?&]${name}=([^&]*)`, 'i'); // 'i' 表示忽略大小写
-
- const match = url.match(regex);
-
- if (match && match[1]) {
- return decodeURIComponent(match[1]);
- }
-
- return null;
-};
\ No newline at end of file
+ if (!url || !name) return null
+ const regex = new RegExp(`[?&]${name}=([^&]*)`, 'i')
+ const match = url.match(regex)
+ if (match && match[1]) {
+ return decodeURIComponent(match[1])
+ }
+ return null
+}