4b8f0d1cb618b00303502681159b0ad6bc4404a6..f24ec48c98a485af26321f7f4b74fe1611162f5a
2026-03-25 spring
fix: 吨/公斤换算
f24ec4 对比 | 目录
2026-03-25 spring
fix: 检测提交后,管理员还能进行编辑
a27edc 对比 | 目录
2026-03-25 spring
fix: 优化质量管理
50f0b9 对比 | 目录
已修改15个文件
399 ■■■■ 文件已修改
src/pages/consumablesLogistics/stockManagement/Qualified.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/consumablesLogistics/stockManagement/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/consumablesLogistics/stockManagement/view.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/consumablesLogistics/stockReport/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/dispatchLog/index.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/receiptManagement/index.vue 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/stockManagement/add.vue 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/stockManagement/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/stockManagement/subtract.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/stockManagement/view.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inventoryManagement/stockReport/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/nonconformingManagement/form.vue 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/nonconformingManagement/index.vue 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/rawMaterial/form.vue 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/qualityManagement/rawMaterial/index.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/consumablesLogistics/stockManagement/Qualified.vue
@@ -27,7 +27,7 @@
        <el-table-column label="规格型号" prop="model" min-width="160" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" width="100" show-overflow-tooltip />
        <el-table-column label="库存数量" prop="qualitity" width="110" show-overflow-tooltip />
        <el-table-column label="冻结数量" prop="lockedQuantity" width="110" show-overflow-tooltip />
        <!-- <el-table-column label="冻结数量" prop="lockedQuantity" width="110" show-overflow-tooltip /> -->
        <el-table-column label="最近更新时间" prop="updateTime" width="180" show-overflow-tooltip />
        <el-table-column label="备注" prop="remark" min-width="140" show-overflow-tooltip />
      </el-table>
src/pages/consumablesLogistics/stockManagement/index.vue
@@ -39,7 +39,7 @@
              <view class="row"><text class="l">规格型号</text><text class="r">{{ item.model }}</text></view>
              <view class="row"><text class="l">单位</text><text class="r">{{ item.unit }}</text></view>
              <view class="row"><text class="l">总库存数</text><text class="r highlight">{{ item.qualitity }}</text></view>
              <view class="row"><text class="l">冻结数量</text><text class="r">{{ item.lockedQuantity || 0 }}</text></view>
              <!-- <view class="row"><text class="l">冻结数量</text><text class="r">{{ item.lockedQuantity || 0 }}</text></view> -->
              <view class="row"><text class="l">可用库存</text><text class="r">{{ item.unLockedQuantity ?? (item.qualitity - (item.lockedQuantity || 0)) }}</text></view>
              <view class="row"><text class="l">最近更新时间</text><text class="r">{{ item.updateTime }}</text></view>
            </view>
@@ -50,11 +50,11 @@
              :class="{ disabled: !(item.unLockedQuantity > 0) }"
              @click="openSubtract(item)"
            >出库</view>
            <view
            <!-- <view
              class="btn-link btn-link-warn"
              v-if="item.unLockedQuantity > 0"
              @click="openFrozen(item)"
            >冻结</view>
            >冻结</view> -->
            <view
              class="btn-link btn-link-plain"
              v-if="(item.lockedQuantity || 0) > 0"
src/pages/consumablesLogistics/stockManagement/view.vue
@@ -31,10 +31,10 @@
            <text class="label">总库存</text>
            <text class="value value-num">{{ detail.qualitity ?? '-' }}</text>
          </view>
          <view class="detail-row">
          <!-- <view class="detail-row">
            <text class="label">冻结数量</text>
            <text class="value">{{ detail.lockedQuantity ?? 0 }}</text>
          </view>
          </view> -->
          <view class="detail-row">
            <text class="label">可用库存</text>
            <text class="value">{{ detail.unLockedQuantity ?? '-' }}</text>
src/pages/consumablesLogistics/stockReport/index.vue
@@ -64,7 +64,7 @@
            <view class="row" v-if="searchForm.reportType === 'inout'"><text class="l">出库数量</text><text class="r">{{ item.totalStockOut }}</text></view>
            <view class="row"><text class="l">现在库存</text><text class="r highlight">{{ item.currentStock }}</text></view>
            <view class="row" v-if="item.createBy"><text class="l">入库人</text><text class="r">{{ item.createBy }}</text></view>
            <view class="row" v-if="item.currentWeight"><text class="l">现净重(吨)</text><text class="r">{{ item.currentWeight }}</text></view>
            <!-- <view class="row" v-if="item.currentWeight"><text class="l">现净重(吨)</text><text class="r">{{ item.currentWeight }}</text></view> -->
            <view class="row" v-if="item.recordType"><text class="l">来源</text><text class="r">{{ getRecordType(item.recordType) }}</text></view>
          </view>
        </view>
@@ -252,6 +252,10 @@
      openDatePicker("endMonth");
    }, 300);
  } else if (datePickerTarget.value === "endMonth") {
    if (searchForm.value.startMonth && !dayjs(`${str}-01`).isAfter(dayjs(`${searchForm.value.startMonth}-01`))) {
      uni.showToast({ title: "结束月份必须大于开始月份", icon: "none" });
      return;
    }
    searchForm.value.endMonth = str;
    showDatePicker.value = false;
    handleQuery();
@@ -262,6 +266,10 @@
      openDatePicker("endDate");
    }, 300);
  } else if (datePickerTarget.value === "endDate") {
    if (searchForm.value.startDate && !dayjs(str).isAfter(dayjs(searchForm.value.startDate))) {
      uni.showToast({ title: "结束日期必须大于开始日期", icon: "none" });
      return;
    }
    searchForm.value.endDate = str;
    showDatePicker.value = false;
    handleQuery();
src/pages/inventoryManagement/dispatchLog/index.vue
@@ -83,7 +83,19 @@
          </view>
          <view class="form-row">
            <text class="form-label required">毛重(吨)</text>
            <text class="form-label">单位</text>
            <up-radio-group v-model="editForm.unit" class="unit-radio-group">
              <up-radio
                v-for="opt in unitOptions"
                :key="opt.value"
                :label="opt.label"
                :name="opt.value"
              ></up-radio>
            </up-radio-group>
          </view>
          <view class="form-row">
            <text class="form-label required">毛重</text>
            <up-input
              v-model="editForm.grossWeight"
              type="digit"
@@ -93,7 +105,7 @@
          </view>
          <view class="form-row">
            <text class="form-label required">皮重(吨)</text>
            <text class="form-label required">皮重</text>
            <up-input
              v-model="editForm.tareWeight"
              type="digit"
@@ -103,7 +115,7 @@
          </view>
          <view class="form-row">
            <text class="form-label required">净重(吨)</text>
            <text class="form-label required">净重</text>
            <up-input v-model="editForm.netWeight" type="digit" placeholder="自动计算" disabled />
          </view>
@@ -285,6 +297,7 @@
const editForm = reactive({
  id: null,
  licensePlateNo: '',
  unit: '吨',
  grossWeight: '',
  tareWeight: '',
  netWeight: '',
@@ -292,6 +305,26 @@
  weighingOperator: '',
  remark: ''
})
const unitOptions = [
  { label: '吨', value: '吨' },
  { label: '公斤', value: '公斤' }
]
const normalizeUnit = (u) => {
  if (!u) return '吨'
  const s = String(u).trim()
  if (s === '吨' || s === 't' || s === 'ton' || s === 'tonne') return '吨'
  if (
    s === '公斤' ||
    s === 'kg' ||
    s === 'kilogram' ||
    s === '千克' ||
    s === 'kilograms'
  )
    return '公斤'
  return '吨'
}
const computeNetWeightEdit = () => {
  const gross = Number(editForm.grossWeight)
@@ -324,6 +357,7 @@
const handleEdit = (row) => {
  Object.assign(editForm, row || {})
  editForm.unit = normalizeUnit(editForm.unit)
  // 以当前毛重/皮重为准计算净重
  computeNetWeightEdit()
  showEditModal.value = true
@@ -525,6 +559,12 @@
  color: #f56c6c;
  margin-right: 6rpx;
}
.unit-radio-group {
  display: flex;
  gap: 24rpx;
  align-items: center;
  flex-wrap: wrap;
}
.selector-trigger {
  display: flex;
  align-items: center;
src/pages/inventoryManagement/receiptManagement/index.vue
@@ -81,16 +81,29 @@
            <text class="form-label required">车牌号</text>
            <up-input v-model="editForm.licensePlateNo" placeholder="请输入车牌号" />
          </view>
          <view class="form-row">
            <text class="form-label required">毛重(吨)</text>
            <text class="form-label">单位</text>
            <up-radio-group v-model="editForm.unit" class="unit-radio-group">
              <up-radio
                v-for="opt in unitOptions"
                :key="opt.value"
                :label="opt.label"
                :name="opt.value"
              ></up-radio>
            </up-radio-group>
          </view>
          <view class="form-row">
            <text class="form-label required">毛重</text>
            <up-input v-model="editForm.grossWeight" type="digit" placeholder="请输入毛重" @blur="computeNetWeightEdit" />
          </view>
          <view class="form-row">
            <text class="form-label required">皮重(吨)</text>
            <text class="form-label required">皮重</text>
            <up-input v-model="editForm.tareWeight" type="digit" placeholder="请输入皮重" @blur="computeNetWeightEdit" />
          </view>
          <view class="form-row">
            <text class="form-label required">净重(吨)</text>
            <text class="form-label required">净重</text>
            <up-input v-model="editForm.netWeight" type="digit" placeholder="自动计算" disabled />
          </view>
          <view class="form-row">
@@ -275,6 +288,7 @@
const editForm = reactive({
  id: null,
  licensePlateNo: '',
  unit: '吨',
  grossWeight: '',
  tareWeight: '',
  netWeight: '',
@@ -282,6 +296,26 @@
  weighingOperator: '',
  remark: ''
})
const unitOptions = [
  { label: '吨', value: '吨' },
  { label: '公斤', value: '公斤' }
]
const normalizeUnit = (u) => {
  if (!u) return '吨'
  const s = String(u).trim()
  if (s === '吨' || s === 't' || s === 'ton' || s === 'tonne') return '吨'
  if (
    s === '公斤' ||
    s === 'kg' ||
    s === 'kilogram' ||
    s === '千克' ||
    s === 'kilograms'
  )
    return '公斤'
  return '吨'
}
const computeNetWeightEdit = () => {
  const gross = Number(editForm.grossWeight)
@@ -312,6 +346,7 @@
const handleEdit = (row) => {
  Object.assign(editForm, row || {})
  editForm.unit = normalizeUnit(editForm.unit)
  computeNetWeightEdit()
  showEditModal.value = true
}
@@ -534,6 +569,12 @@
  color: #f56c6c;
  margin-right: 6rpx;
}
.unit-radio-group {
  display: flex;
  gap: 24rpx;
  align-items: center;
  flex-wrap: wrap;
}
.selector-trigger {
  display: flex;
  align-items: center;
src/pages/inventoryManagement/stockManagement/add.vue
@@ -19,7 +19,14 @@
        </view>
        <view class="form-row">
          <text class="form-label">单位</text>
          <up-input v-model="form.unit" disabled placeholder="请选择产品后自动带出" />
          <up-radio-group v-model="form.unit" class="unit-radio-group">
            <up-radio
              v-for="opt in unitOptions"
              :key="opt.value"
              :label="opt.label"
              :name="opt.value"
            ></up-radio>
          </up-radio-group>
        </view>
      </view>
@@ -39,7 +46,7 @@
          <up-input v-model="form.licensePlateNo" placeholder="请输入车牌号" />
        </view>
        <view class="form-row">
          <text class="form-label required">毛重(吨)</text>
          <text class="form-label required">毛重</text>
          <up-input
            v-model="form.grossWeight"
            type="digit"
@@ -47,7 +54,7 @@
          />
        </view>
        <view class="form-row">
          <text class="form-label required">皮重(吨)</text>
          <text class="form-label required">皮重</text>
          <up-input
            v-model="form.tareWeight"
            type="digit"
@@ -55,7 +62,7 @@
          />
        </view>
        <view class="form-row">
          <text class="form-label">净重(吨)</text>
          <text class="form-label">净重</text>
          <up-input
            v-model="form.netWeight"
            type="digit"
@@ -156,7 +163,7 @@
  productModelId: undefined,
  productName: '',
  productModelName: '',
  unit: '',
  unit: '吨',
  productType: undefined,
  parentName: '',
  licensePlateNo: '',
@@ -168,6 +175,26 @@
  qualitity: '',
  remark: ''
})
const unitOptions = [
  { label: '吨', value: '吨' },
  { label: '公斤', value: '公斤' }
]
const normalizeUnit = (u) => {
  if (!u) return ''
  const s = String(u).trim()
  if (s === '吨' || s === 't' || s === 'ton' || s === 'tonne') return '吨'
  if (
    s === '公斤' ||
    s === 'kg' ||
    s === 'kilogram' ||
    s === '千克' ||
    s === 'kilograms'
  )
    return '公斤'
  return s
}
const type = ref('0') // 固定合格库存
const isQualified = computed(() => true)
@@ -227,7 +254,8 @@
  form.productModelId = item.id
  form.productName = item.productName
  form.productModelName = item.model
  form.unit = item.unit
  const normalizedUnit = normalizeUnit(item.unit)
  form.unit = normalizedUnit === '吨' || normalizedUnit === '公斤' ? normalizedUnit : '吨'
  form.productType = item.productType
  form.parentName = parentName
@@ -470,6 +498,12 @@
  font-size: 24rpx;
  color: #666;
}
.unit-radio-group {
  display: flex;
  gap: 24rpx;
  align-items: center;
  flex-wrap: wrap;
}
.no-data {
  text-align: center;
  padding: 40rpx 0;
src/pages/inventoryManagement/stockManagement/index.vue
@@ -41,7 +41,7 @@
              <view class="row"><text class="l">规格型号</text><text class="r">{{ item.model }}</text></view>
              <view class="row"><text class="l">单位</text><text class="r">{{ item.unit }}</text></view>
              <view class="row"><text class="l">总库存数</text><text class="r highlight">{{ item.qualitity }}</text></view>
              <view class="row"><text class="l">冻结数量</text><text class="r">{{ item.lockedQuantity || 0 }}</text></view>
              <!-- <view class="row"><text class="l">冻结数量</text><text class="r">{{ item.lockedQuantity || 0 }}</text></view> -->
              <view class="row"><text class="l">可用库存</text><text class="r">{{ item.unLockedQuantity ?? (item.qualitity - (item.lockedQuantity || 0)) }}</text></view>
              <view class="row"><text class="l">最近更新时间</text><text class="r">{{ item.updateTime }}</text></view>
            </view>
@@ -52,11 +52,11 @@
              :class="{ disabled: !(item.unLockedQuantity > 0) }"
              @click="openSubtract(item)"
            >出库</view>
            <view
            <!-- <view
              class="btn-link btn-link-warn"
              v-if="item.unLockedQuantity > 0"
              @click="openFrozen(item)"
            >冻结</view>
            >冻结</view> -->
            <view
              class="btn-link btn-link-plain"
              v-if="(item.lockedQuantity || 0) > 0"
src/pages/inventoryManagement/stockManagement/subtract.vue
@@ -14,7 +14,14 @@
        </view>
        <view class="form-row">
          <text class="form-label">单位</text>
          <up-input v-model="form.unit" disabled />
          <up-radio-group v-model="form.unit" class="unit-radio-group">
            <up-radio
              v-for="opt in unitOptions"
              :key="opt.value"
              :label="opt.label"
              :name="opt.value"
            ></up-radio>
          </up-radio-group>
        </view>
      </view>
@@ -22,7 +29,11 @@
        <view class="section-title">出库信息</view>
        <view class="form-row">
          <text class="form-label">出库数量</text>
          <up-input v-model="form.stockOutNum" type="number" :placeholder="'最大' + (form.unLockedQuantity ?? 0)" />
          <up-input
            v-model="form.stockOutNum"
            type="number"
            :placeholder="'最大' + maxOutQuantity"
          />
        </view>
        <view class="form-row">
          <text class="form-label">备注</text>
@@ -52,7 +63,7 @@
  parentName: '',
  productName: '',
  model: '',
  unit: '',
  unit: '吨',
  qualitity: undefined,
  lockedQuantity: undefined,
  unLockedQuantity: undefined,
@@ -69,6 +80,45 @@
})
const type = ref('0') // 固定合格库存
const unitOptions = [
  { label: '吨', value: '吨' },
  { label: '公斤', value: '公斤' }
]
// 记录的原始单位,用于吨/公斤换算校验“最大可出库数量”
const recordUnit = ref('')
const normalizeUnit = (u) => {
  if (!u) return ''
  const s = String(u).trim()
  if (s === '吨' || s === 't' || s === 'ton' || s === 'tonne') return '吨'
  if (
    s === '公斤' ||
    s === 'kg' ||
    s === 'kilogram' ||
    s === '千克' ||
    s === 'kilograms'
  )
    return '公斤'
  return s
}
const convertByUnit = (value, fromUnit, toUnit) => {
  if (value === '' || value === undefined || value === null) return 0
  const num = Number(value)
  if (Number.isNaN(num)) return 0
  if (fromUnit === toUnit) return num
  // 默认只处理吨<->公斤;其他单位直接原样返回
  if (fromUnit === '吨' && toUnit === '公斤') return num * 1000
  if (fromUnit === '公斤' && toUnit === '吨') return num / 1000
  return num
}
const maxOutQuantity = computed(() => {
  const baseMax = Number(form.unLockedQuantity ?? 0)
  if (!recordUnit.value || !form.unit) return baseMax
  return convertByUnit(baseMax, recordUnit.value, form.unit)
})
onLoad((options) => {
  type.value = '0'
@@ -79,6 +129,9 @@
      const item = payload && payload.item ? payload.item : payload
      // 将列表记录的完整字段拷贝到表单中,保持与 PC 端 Subtract.vue 一致
      Object.assign(form, item)
      const normalizedUnit = normalizeUnit(form.unit)
      form.unit = normalizedUnit === '吨' || normalizedUnit === '公斤' ? normalizedUnit : '吨'
      recordUnit.value = form.unit
      uni.removeStorageSync('stockSubtractRecord')
    } catch (e) {
      uni.removeStorageSync('stockSubtractRecord')
@@ -91,8 +144,11 @@
    uni.showToast({ title: '记录信息缺失,无法出库', icon: 'none' })
    return
  }
  const normalizedUnit = normalizeUnit(form.unit)
  form.unit = normalizedUnit === '吨' || normalizedUnit === '公斤' ? normalizedUnit : '吨'
  const outNum = Number(form.stockOutNum)
  const max = Number(form.unLockedQuantity ?? 0)
  const max = Number(maxOutQuantity.value ?? 0)
  if (!outNum || outNum <= 0 || outNum > max) {
    uni.showToast({ title: `请输入 1~${max} 之间的数量`, icon: 'none' })
    return
@@ -100,7 +156,8 @@
  const payload = {
    id: form.id,
    stockOutNum: outNum,
    remark: form.remark
    remark: form.remark,
    unit: form.unit
  }
  subtractStockInventory(payload)
    .then(() => {
@@ -181,5 +238,11 @@
  align-items: center;
  justify-content: center;
}
.unit-radio-group {
  display: flex;
  gap: 24rpx;
  align-items: center;
  flex-wrap: wrap;
}
</style>
src/pages/inventoryManagement/stockManagement/view.vue
@@ -41,10 +41,10 @@
            <text class="label">总库存数</text>
            <text class="value value-num">{{ detail.qualitity ?? '-' }}</text>
          </view>
          <view class="detail-row">
          <!-- <view class="detail-row">
            <text class="label">冻结数量</text>
            <text class="value">{{ detail.lockedQuantity ?? 0 }}</text>
          </view>
          </view> -->
          <view class="detail-row">
            <text class="label">可用库存</text>
            <text class="value">{{ detail.unLockedQuantity ?? (detail.qualitity - (detail.lockedQuantity || 0)) }}</text>
src/pages/inventoryManagement/stockReport/index.vue
@@ -69,7 +69,7 @@
            <view class="row" v-if="searchForm.reportType === 'inout'"><text class="l">出库数量</text><text class="r">{{ item.totalStockOut }}</text></view>
            <view class="row"><text class="l">现在库存</text><text class="r highlight">{{ item.currentStock }}</text></view>
            <view class="row" v-if="item.createBy"><text class="l">入库人</text><text class="r">{{ item.createBy }}</text></view>
            <view class="row" v-if="item.currentWeight"><text class="l">现净重(吨)</text><text class="r">{{ item.currentWeight }}</text></view>
            <!-- <view class="row" v-if="item.currentWeight"><text class="l">现净重(吨)</text><text class="r">{{ item.currentWeight }}</text></view> -->
            <view class="row" v-if="item.recordType"><text class="l">来源</text><text class="r">{{ getRecordType(item.recordType) }}</text></view>
          </view>
        </view>
@@ -274,6 +274,10 @@
      openDatePicker('endMonth')
    }, 300)
  } else if (datePickerTarget.value === 'endMonth') {
    if (searchForm.value.startMonth && !dayjs(`${str}-01`).isAfter(dayjs(`${searchForm.value.startMonth}-01`))) {
      uni.showToast({ title: '结束月份必须大于开始月份', icon: 'none' })
      return
    }
    searchForm.value.endMonth = str
    showDatePicker.value = false
    handleQuery()
@@ -285,6 +289,10 @@
      openDatePicker('endDate')
    }, 300)
  } else if (datePickerTarget.value === 'endDate') {
    if (searchForm.value.startDate && !dayjs(str).isAfter(dayjs(searchForm.value.startDate))) {
      uni.showToast({ title: '结束日期必须大于开始日期', icon: 'none' })
      return
    }
    searchForm.value.endDate = str
    showDatePicker.value = false
    handleQuery()
src/pages/qualityManagement/nonconformingManagement/form.vue
@@ -189,6 +189,7 @@
const pageType = ref('add') // add | edit
const id = ref('')
const submitting = ref(false)
const editFallback = ref({})
const isEdit = computed(() => pageType.value === 'edit')
const pageTitle = computed(() => (isEdit.value ? '编辑不合格管理' : '新增不合格管理'))
@@ -366,6 +367,46 @@
  if (!id.value) return
  const res = await getQualityUnqualifiedInfo(id.value)
  const d = res?.data || {}
  const rawCheckType =
    d.checkType ??
    d.inspectType ??
    d.check_type ??
    d.inspect_type ??
    d.checkTypeLabel ??
    d.inspectTypeLabel
  let normalizedCheckType = undefined
  if (!(rawCheckType === undefined || rawCheckType === null || rawCheckType === '')) {
    const rawText = String(rawCheckType).trim()
    if (rawText === '入厂检') normalizedCheckType = 0
    else if (rawText === '车间检') normalizedCheckType = 1
    else if (rawText === '出厂检') normalizedCheckType = 2
    else {
      const n = Number(rawText)
      normalizedCheckType = Number.isNaN(n) ? undefined : n
    }
  }
  const normalizedBatchNo =
    d.batchNo ??
    d.batchNO ??
    d.batchNum ??
    d.batchNumber ??
    d.batch ??
    d.inboundBatches ??
    d.lotNo ??
    d.lotNumber ??
    editFallback.value?.batchNo ??
    ''
  const fallbackCheckTypeRaw = editFallback.value?.checkType
  if (normalizedCheckType === undefined && !(fallbackCheckTypeRaw === undefined || fallbackCheckTypeRaw === null || fallbackCheckTypeRaw === '')) {
    const fallbackText = String(fallbackCheckTypeRaw).trim()
    if (fallbackText === '入厂检') normalizedCheckType = 0
    else if (fallbackText === '车间检') normalizedCheckType = 1
    else if (fallbackText === '出厂检') normalizedCheckType = 2
    else {
      const n = Number(fallbackText)
      normalizedCheckType = Number.isNaN(n) ? undefined : n
    }
  }
  Object.assign(form, {
    id: d.id,
    productId: d.productId,
@@ -373,9 +414,10 @@
    productModelId: d.productModelId ?? d.modelId ?? d.productModeId ?? '',
    model: d.model,
    unit: d.unit,
    batchNo: d.batchNo,
    // 兼容后端返回字段:优先 checkType,其次 inspectType
    checkType: d.checkType ?? d.inspectType,
    // 兼容后端返回字段:batchNo/batchNum/lotNo 等
    batchNo: normalizedBatchNo,
    // 兼容后端返回字段:checkType/inspectType 等,统一为 number
    checkType: normalizedCheckType,
    checkName: d.checkName,
    checkTime: d.checkTime,
    defectivePhenomena: d.defectivePhenomena,
@@ -423,6 +465,13 @@
onLoad(async (options) => {
  pageType.value = options?.type || 'add'
  id.value = options?.id || ''
  if (options?.fallback) {
    try {
      editFallback.value = JSON.parse(decodeURIComponent(options.fallback))
    } catch (e) {
      editFallback.value = {}
    }
  }
  form.dealResult = getScrapDealResultValue()
  await loadUsers()
  if (isEdit.value) {
src/pages/qualityManagement/nonconformingManagement/index.vue
@@ -377,14 +377,22 @@
};
const openForm = (type, row) => {
  if (type === 'edit' && !hasNonconformingEdit.value) return
  if (type !== 'add' && row?.inspectState == 1) {
    toast('已处理的数据不能再编辑')
    return
  }
  // if (type === 'edit' && !hasNonconformingEdit.value) return
  // if (type !== 'add' && row?.inspectState == 1) {
  //   toast('已处理的数据不能再编辑')
  //   return
  // }
  const id = row?.id
  let fallback = ''
  if (row) {
    const fallbackData = {
      batchNo: row.batchNo ?? '',
      checkType: row.checkType ?? row.inspectType ?? ''
    }
    fallback = `&fallback=${encodeURIComponent(JSON.stringify(fallbackData))}`
  }
  uni.navigateTo({
    url: `/pages/qualityManagement/nonconformingManagement/form?type=${type}${id ? `&id=${id}` : ''}`
    url: `/pages/qualityManagement/nonconformingManagement/form?type=${type}${id ? `&id=${id}` : ''}${fallback}`
  })
}
src/pages/qualityManagement/rawMaterial/form.vue
@@ -1,6 +1,6 @@
<template>
  <view class="rm-form-page">
    <PageHeader :title="operationType === 'add' ? '新增原料检' : '编辑原料检'" @back="goBack" />
    <PageHeader :title="operationType === 'add' ? '新增原料检' : (operationType === 'detail' ? '原料检验详情' : '编辑原料检')" @back="goBack" />
    <scroll-view scroll-y class="content-scroll">
      <view class="section-card">
@@ -8,7 +8,11 @@
        <view class="form-row">
          <text class="form-label required">产品名称</text>
          <view class="selector-trigger" @click="openProductSelector" :class="{ disabled: operationType === 'edit' }">
          <view
            class="selector-trigger"
            @click="!isReadOnly && openProductSelector()"
            :class="{ disabled: operationType === 'edit' || isReadOnly }"
          >
            <text class="selector-text" :class="{ placeholder: !form.productName }">
              {{ form.productName || '请选择产品' }}
            </text>
@@ -28,12 +32,12 @@
        <view class="form-row">
          <text class="form-label required">批号</text>
          <up-input v-model="form.batchNo" placeholder="请输入批号" />
          <up-input v-model="form.batchNo" :disabled="isReadOnly" placeholder="请输入批号" />
        </view>
        <view class="form-row">
          <text class="form-label required">检验类型</text>
          <view class="selector-trigger" @click="showCheckTypeSheet = true">
          <view class="selector-trigger" @click="!isReadOnly && (showCheckTypeSheet = true)">
            <text class="selector-text" :class="{ placeholder: form.checkType === '' || form.checkType == null }">
              {{ checkTypeLabel }}
            </text>
@@ -43,7 +47,7 @@
        <view class="form-row">
          <text class="form-label required">检测结果</text>
          <view class="selector-trigger" @click="showCheckResultSheet = true">
          <view class="selector-trigger" @click="!isReadOnly && (showCheckResultSheet = true)">
            <text class="selector-text" :class="{ placeholder: form.checkResult === '' || form.checkResult == null }">
              {{ checkResultLabel }}
            </text>
@@ -53,12 +57,12 @@
        <view class="form-row">
          <text class="form-label required">检验员</text>
          <up-input v-model="form.checkUserName" placeholder="请输入检验员" />
          <up-input v-model="form.checkUserName" :disabled="isReadOnly" placeholder="请输入检验员" />
        </view>
        <view class="form-row">
          <text class="form-label required">检测日期</text>
          <view class="selector-trigger" @click="openCheckDatePicker">
          <view class="selector-trigger" @click="!isReadOnly && openCheckDatePicker()">
            <text class="selector-text" :class="{ placeholder: !form.checkTime }">
              {{ form.checkTime || '请选择检测日期' }}
            </text>
@@ -70,36 +74,36 @@
      <view class="section-card">
        <view class="section-title row-between">
          <text>检测项目</text>
          <view class="btn-inline" @click="openItemSelector">添加检测项目</view>
          <view class="btn-inline" v-if="!isReadOnly" @click="openItemSelector">添加检测项目</view>
        </view>
        <view v-if="inspectItems.length > 0">
          <view v-for="(it, idx) in inspectItems" :key="it.id || idx" class="item-card">
            <view class="item-head">
              <text class="item-name">{{ it.name }}</text>
              <view class="item-del" @click="removeItem(it.id)">删除</view>
              <view class="item-del" v-if="!isReadOnly" @click="removeItem(it.id)">删除</view>
            </view>
            <view class="item-row"><text class="l">单位</text><text class="r">{{ it.unit || '-' }}</text></view>
            <view class="item-row"><text class="l">标准值</text><text class="r">{{ it.standardValue || '-' }}</text></view>
            <view class="item-row"><text class="l">内控值</text><text class="r">{{ it.internalControl || '-' }}</text></view>
            <view class="item-row input-row">
              <text class="l">化验值</text>
              <up-input v-model="it.testValue" placeholder="请输入" class="test-value-input" />
              <up-input v-model="it.testValue" :disabled="isReadOnly" placeholder="请输入" class="test-value-input" />
            </view>
          </view>
        </view>
        <view v-else class="no-data">请添加检测项目</view>
        <view v-else class="no-data">{{ isReadOnly ? '暂无检测项目' : '请添加检测项目' }}</view>
      </view>
    </scroll-view>
    <view class="bottom-bar">
    <view class="bottom-bar" v-if="!isReadOnly">
      <view class="btn-submit" :class="{ disabled: submitLoading }" @click="handleSubmit">
        {{ submitLoading ? '提交中...' : '保存' }}
      </view>
    </view>
    <!-- 产品选择弹窗(复用 pageModel 接口) -->
    <up-popup :show="showProductPopup" mode="bottom" @close="showProductPopup = false">
    <up-popup :show="showProductPopup && !isReadOnly" mode="bottom" @close="showProductPopup = false">
      <view class="popup-wrap">
        <view class="popup-header">
          <text class="popup-title">选择产品</text>
@@ -123,7 +127,7 @@
    </up-popup>
    <!-- 检测项目选择弹窗(简化:从检测项维护表里选) -->
    <up-popup :show="showItemPopup" mode="bottom" @close="showItemPopup = false">
    <up-popup :show="showItemPopup && !isReadOnly" mode="bottom" @close="showItemPopup = false">
      <view class="popup-wrap">
        <view class="popup-header">
          <text class="popup-title">选择检测项目</text>
@@ -164,11 +168,23 @@
    </up-popup>
    <!-- 选择器:检验类型/结果 -->
    <up-action-sheet :actions="checkTypeActions" :show="showCheckTypeSheet" @close="showCheckTypeSheet = false" @select="onSelectCheckType" title="检验类型" />
    <up-action-sheet :actions="checkResultActions" :show="showCheckResultSheet" @close="showCheckResultSheet = false" @select="onSelectCheckResult" title="检测结果" />
    <up-action-sheet
      :actions="checkTypeActions"
      :show="showCheckTypeSheet && !isReadOnly"
      @close="showCheckTypeSheet = false"
      @select="onSelectCheckType"
      title="检验类型"
    />
    <up-action-sheet
      :actions="checkResultActions"
      :show="showCheckResultSheet && !isReadOnly"
      @close="showCheckResultSheet = false"
      @select="onSelectCheckResult"
      title="检测结果"
    />
    <!-- 日期选择 -->
    <up-popup :show="showCheckDatePicker" mode="bottom" @close="showCheckDatePicker = false">
    <up-popup :show="showCheckDatePicker && !isReadOnly" mode="bottom" @close="showCheckDatePicker = false">
      <up-datetime-picker :show="true" v-model="checkDateValue" mode="date" @confirm="onCheckDateConfirm" @cancel="showCheckDatePicker = false" />
    </up-popup>
  </view>
@@ -187,6 +203,7 @@
const userStore = useUserStore()
const operationType = ref('add')
const isReadOnly = computed(() => operationType.value === 'detail')
const submitLoading = ref(false)
const form = reactive({
@@ -240,7 +257,7 @@
const productList = ref([])
const productLoading = ref(false)
const openProductSelector = () => {
  if (operationType.value === 'edit') return
  if (operationType.value === 'edit' || isReadOnly.value) return
  showProductPopup.value = true
  if (productList.value.length === 0) loadProductList()
}
@@ -270,6 +287,7 @@
const selectedItemIds = ref(new Set())
const isItemSelected = (id) => selectedItemIds.value.has(id)
const openItemSelector = () => {
  if (isReadOnly.value) return
  showItemPopup.value = true
  selectedItemIds.value = new Set(inspectItems.value.map(i => i.id))
  if (itemList.value.length === 0) loadItemList()
@@ -320,6 +338,7 @@
}
const handleSubmit = () => {
  if (isReadOnly.value) return
  if (submitLoading.value) return
  const msg = validate()
  if (msg) {
@@ -343,7 +362,7 @@
onLoad((options) => {
  operationType.value = options?.type || 'add'
  const id = options?.id
  if (operationType.value === 'edit' && id) {
  if ((operationType.value === 'edit' || operationType.value === 'detail') && id) {
    findRawMaterialDetail(id).then(res => {
      const d = res?.data || {}
      form.id = d.id
src/pages/qualityManagement/rawMaterial/index.vue
@@ -60,7 +60,8 @@
          </view>
        </view>
        <view class="item-actions">
          <up-button v-if="item.inspectState != 1" type="primary" size="mini" @click.stop="openForm('edit', item)">编辑</up-button>
          <up-button v-if="item.inspectState != 1||hasRawCancel" type="primary" size="mini" @click.stop="openForm('edit', item)">编辑</up-button>
          <up-button type="warning" size="mini" @click.stop="openDetail(item)">详情</up-button>
          <up-button type="info" size="mini" @click.stop="openFiles(item)">附件</up-button>
          <up-button v-if="item.inspectState != 1" type="success" size="mini" @click.stop="handleConfirmSubmit(item)">提交</up-button>
          <up-button v-if="hasRawCancel" type="error" size="mini" @click.stop="handleDelete(item)">删除</up-button>
@@ -203,13 +204,21 @@
};
const openForm = (type, item) => {
  if (type === 'edit' && !hasRawEdit.value) return
  // if (type === 'edit' && !hasRawEdit.value) return
  const id = item?.id
  uni.navigateTo({
    url: `/pages/qualityManagement/rawMaterial/form?type=${type}${id ? `&id=${id}` : ''}`
  })
};
const openDetail = (item) => {
  const id = item?.id
  if (!id) return
  uni.navigateTo({
    url: `/pages/qualityManagement/rawMaterial/form?type=detail&id=${id}`
  })
}
const handleConfirmSubmit = (row) => {
  showConfirm('确认提交该检验记录吗?').then(res => {
    if (res.confirm) {