Sfoglia il codice sorgente

修复锅炉检测列表页面空白的问题;检验录入的葡萄城编辑器调整插入图片功能;调整筛选条件栏单选组件

yangguanjin 1 settimana fa
parent
commit
dcde83a275

+ 18 - 75
src/components/RadioFilterBar/RadioFilterBar.vue

@@ -1,35 +1,23 @@
 <template>
-  <view class="radio-filter-bar" :class="{ 'has-checkbox': showCheckbox }">
+  <view class="radio-filter-bar">
     <view class="filter-row">
       <view
         v-for="(item, index) in options"
-        :key="item.id"
+        :key="index"
         class="filter-item"
-        :class="{ 'is-radio': type === 'radio', 'is-checkbox': type === 'checkbox' }"
         @click="handleClick(item)"
       >
         <view
-          class="checkbox-wrapper"
-          :style="{ marginLeft: index === 0 ? '0' : marginLeft }"
+          class="radio-wrapper"
+          :style="{ 'margin-left': index === 0 ? '0' : '15px' }"
         >
           <view
-            class="checkbox"
-            :class="{
-              'radio-style': type === 'radio',
-              'square-style': type === 'checkbox',
-              'checked': isChecked(item),
-              'radio-checked': type === 'radio' && isChecked(item),
-            }"
+            class="radio"
+            :class="{ 'radio-checked': isChecked(item) }"
           >
-            <view v-if="type === 'radio' && isChecked(item)" class="radio-inner"></view>
-            <image
-              v-if="type === 'checkbox' && isChecked(item)"
-              class="check-icon"
-              :src="checkIcon"
-              mode="aspectFit"
-            />
+            <view v-if="isChecked(item)" class="radio-inner"></view>
           </view>
-          <text class="checkbox-text">{{ item.value }}</text>
+          <text class="radio-text">{{ item.value }}</text>
         </view>
       </view>
     </view>
@@ -37,9 +25,6 @@
 </template>
 
 <script lang="ts" setup>
-import { computed } from 'vue'
-import iconMap from '@/utils/imagesMap'
-
 interface FilterOption {
   id: string | number
   value: string
@@ -47,43 +32,24 @@ interface FilterOption {
 
 interface Props {
   options: FilterOption[]
-  modelValue: string | number | boolean
-  type?: 'radio' | 'checkbox'
-  showCheckbox?: boolean
-  marginLeft?: string
+  modelValue: string | number
 }
 
 const props = withDefaults(defineProps<Props>(), {
-  type: 'radio',
-  showCheckbox: false,
-  marginLeft: '15px',
 })
 
 const emit = defineEmits<{
-  'update:modelValue': [value: string | number | boolean]
-  change: [value: string | number | boolean]
+  'update:modelValue': [value: string | number]
+  change: [value: string | number]
 }>()
 
-const checkIcon = computed(() => iconMap.WhiteCheck)
-
 const isChecked = (item: FilterOption) => {
-  if (props.type === 'checkbox') {
-    return props.modelValue === true
-  }
   return props.modelValue === item.id
 }
 
 const handleClick = (item: FilterOption) => {
-  let newValue: string | number | boolean
-
-  if (props.type === 'checkbox') {
-    newValue = !props.modelValue
-  } else {
-    newValue = item.id
-  }
-
-  emit('update:modelValue', newValue)
-  emit('change', newValue)
+  emit('update:modelValue', item.id)
+  emit('change', item.id)
 }
 </script>
 
@@ -96,10 +62,6 @@ const handleClick = (item: FilterOption) => {
   padding: 10px 15px;
   background-color: #fff;
   border-bottom: 1px solid #eee;
-
-  &.has-checkbox {
-    flex-wrap: wrap;
-  }
 }
 
 .filter-row {
@@ -114,30 +76,21 @@ const handleClick = (item: FilterOption) => {
   align-items: center;
 }
 
-.checkbox-wrapper {
+.radio-wrapper {
   display: flex;
   flex-direction: row;
   align-items: center;
 }
 
-.checkbox {
+.radio {
   display: flex;
   align-items: center;
   justify-content: center;
-  border: 1px solid #bbb;
-  background-color: #fff;
-}
-
-.radio-style {
   width: 15px;
   height: 15px;
   border-radius: 7.5px;
-}
-
-.square-style {
-  width: 18px;
-  height: 18px;
-  border-radius: 3px;
+  border: 1px solid #bbb;
+  background-color: #fff;
 }
 
 .radio-checked {
@@ -151,17 +104,7 @@ const handleClick = (item: FilterOption) => {
   border-radius: 4.75px;
 }
 
-.checkbox.checked {
-  background-color: #2f8eff;
-  border-width: 0;
-}
-
-.check-icon {
-  width: 12px;
-  height: 12px;
-}
-
-.checkbox-text {
+.radio-text {
   margin-left: 6px;
   font-size: 14px;
   color: #333;

+ 108 - 12
src/components/SpreadDesigner/spreadDesigner.vue

@@ -40,7 +40,7 @@
         <view class="floating-field-name-display">{{ currentFieldName }}</view>
         <view class="button-group">
           <button class="upload-image-btn" :disabled="!currentCell" @click="openCamera">
-            拍摄图片
+            插入图片
           </button>
           <button
             class="special-symbol-btn"
@@ -108,6 +108,29 @@
       </view>
     </view>
 
+    <view
+      v-if="imageSourceDialogVisible"
+      class="dialog-overlay"
+      @click="imageSourceDialogVisible = false"
+    >
+      <view class="image-source-dialog-content" @click.stop>
+        <view class="image-source-dialog-header">
+          <text class="image-source-dialog-title">插入图片</text>
+          <button class="image-source-dialog-close" @click="imageSourceDialogVisible = false">
+            ×
+          </button>
+        </view>
+        <view class="image-source-options">
+          <button class="image-source-option-btn" @click="handleTakePhoto">
+            <text class="option-label">拍摄图片</text>
+          </button>
+          <button class="image-source-option-btn" @click="handlePickFile">
+            <text class="option-label">选择文件</text>
+          </button>
+        </view>
+      </view>
+    </view>
+
     <view v-if="dialogVisible" class="dialog-overlay" @click="dialogVisible = false">
       <view class="dialog-content" @click.stop>
         <view class="modal-message">{{ dialogMessage }}</view>
@@ -164,6 +187,7 @@ const emit = defineEmits([
   'cancel',
   'close',
   'openCamera',
+  'openFilePicker',
   'calcCompleted',
   'selectedReport',
   'updateCheckItemData',
@@ -186,6 +210,7 @@ const currentFieldName = ref('-')
 const fieldNameMapping = ref([])
 const dialogVisible = ref(false)
 const dialogMessage = ref('')
+const imageSourceDialogVisible = ref(false)
 const floatingInputRef = ref(null)
 const floatingInputCursor = ref(0)
 const specialSymbolVisible = ref(false)
@@ -582,7 +607,7 @@ function setDataSource(designerInstance, schemaData, dataSourceValues) {
     totalDataCount,
   } = processContinueDataSource(spreadInstance, resultDataSource)
 
-  console.log("@@@@xxxxxxxxx111111....", continuePageProceedDataSource)
+  console.log("@@@@preContinuePageProceedDatasource....", continuePageProceedDataSource)
   prefixFields = prefixFieldSet
   dataCount = totalDataCount
   processContinuePage(
@@ -591,7 +616,7 @@ function setDataSource(designerInstance, schemaData, dataSourceValues) {
     sheetToRecordRowCount,
     totalDataCount,
   )
-  console.log("@@@@@xxxxxxxx2222222....", continuePageProceedDataSource)
+  console.log("@@@@@afterContinuePageProceedDatasource....", continuePageProceedDataSource)
   registerCellValuesChangeEventHandlerForEverySheet(spreadInstance.sheets)
   for (const sheet of spreadInstance.sheets) {
     const tables = sheet.tables?.all() || []
@@ -1340,9 +1365,6 @@ function handleDataJson(dataJson) {
 
   const prefixFieldData = {}
   for (const prefixField of prefixFields) {
-    if(prefixField.startsWith('yearInspectionConclusion')) {
-      continue
-    }
     const cellDataList = []
     for (let i = 0; i < dataCount; i++) {
       const cellData = dataJson[`${prefixField}_${i+1}`]
@@ -1355,12 +1377,6 @@ function handleDataJson(dataJson) {
       if(key.startsWith(prefixField)) {
         delete dataJson[key]
       }
-      if(key.startsWith("yearInspectionConclusion")) {
-        const yc = dataJson[key]
-        if(yc == null || yc == "") {
-          delete dataJson[key]
-        }
-      }
     }
   }
 
@@ -1407,9 +1423,19 @@ function goBack() {
 }
 
 function openCamera() {
+  imageSourceDialogVisible.value = true
+}
+
+function handleTakePhoto() {
+  imageSourceDialogVisible.value = false
   emit('openCamera')
 }
 
+function handlePickFile() {
+  imageSourceDialogVisible.value = false
+  emit('openFilePicker')
+}
+
 function getPictureSource(photoData) {
   if (!photoData?.base64) return ''
   if (photoData.base64.startsWith('data:')) return photoData.base64
@@ -2148,4 +2174,74 @@ defineExpose({
   color: #333;
   text-align: center;
 }
+
+.image-source-dialog-content {
+  width: min(80vw, 320px);
+  padding: 20px;
+  background-color: white;
+  border-radius: 8px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.image-source-dialog-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 16px;
+}
+
+.image-source-dialog-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+}
+
+.image-source-dialog-close {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 28px;
+  height: 28px;
+  font-size: 18px;
+  color: #666;
+  cursor: pointer;
+  background: #f5f5f5;
+  border: none;
+  border-radius: 14px;
+}
+
+.image-source-options {
+  display: flex;
+  gap: 12px;
+  justify-content: center;
+}
+
+.image-source-option-btn {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 120px;
+  height: 80px;
+  font-size: 14px;
+  font-weight: 500;
+  color: #333;
+  cursor: pointer;
+  background: #f8f9fa;
+  border: 1px solid #dee2e6;
+  border-radius: 8px;
+  transition: all 0.2s ease;
+}
+
+.image-source-option-btn:hover {
+  color: #007aff;
+  background: #eef6ff;
+  border-color: #007aff;
+}
+
+.option-label {
+  font-size: 14px;
+  font-weight: 500;
+  color: inherit;
+}
 </style>

+ 1 - 1
src/components/SpreadDesigner/spreadDesignerGeneric.vue

@@ -42,7 +42,7 @@
             :disabled="!currentCell"
             @click="openCamera"
           >
-            拍摄图片
+            插入图片
           </button>
           <button
             class="special-symbol-btn"

+ 19 - 0
src/pages/editor/equipCheckRecordEditor.vue

@@ -24,6 +24,7 @@
       @cancel="handleCancel"
       @close="handleCancel"
       @openCamera="handleOpenCamera"
+      @openFilePicker="handleOpenFilePicker"
       @selectedReport="handleSelectedReport"
     />
   </view>
@@ -105,6 +106,7 @@ const handleGetCheckItemDetail = async (
 
     const dynamicTbResp = await getDynamicTbVal({
       refId: reportId,
+      templateId: newTemplateId,
     })
     const dynamicTb = dynamicTbResp.data
     const initJSONResult = {}
@@ -447,6 +449,15 @@ const takePhotoRN = () => {
   )
 }
 
+// 调起RN文件选择器
+const pickFileRN = () => {
+  ;(window as any).ReactNativeWebView.postMessage(
+    JSON.stringify({
+      type: 'pickFile',
+    }),
+  )
+}
+
 // 非RN环境选择本地图片
 const pickPhotoH5 = () => {
   const input = document.createElement('input')
@@ -490,6 +501,14 @@ const handleOpenCamera = () => {
   pickPhotoH5()
 }
 
+const handleOpenFilePicker = () => {
+  if (isRNEnv()) {
+    pickFileRN()
+    return
+  }
+  pickPhotoH5()
+}
+
 const handleSelectedReport = async (data: any) => {
   if (data.reportId === checkItemData.value?.checkItemId) {
     return

+ 21 - 14
src/pages/equipment/detail/components/PipeInspectProject.vue

@@ -36,9 +36,7 @@
                 <text
                   class="conclusion-text"
                   :class="{
-                    'conclusion-error-text': isConclusionError(
-                      item.reportConclusion,
-                    ),
+                    'conclusion-error-text': isConclusionError(item.reportConclusion),
                   }"
                 >
                   {{ item.reportConclusion || '无' }}
@@ -321,12 +319,12 @@ import {
   PressureCheckerMyTaskStatusMap,
 } from '@/utils/dictMap'
 import { isCheckItemEditable, isAssignedToOthers } from '@/utils/equipmentPermissions'
+import { getApprovalDetail, getUserGroupUserList, pressure2NotVerifyPageApi } from '@/api/task'
 import {
-  getApprovalDetail,
-  getUserGroupUserList,
-  pressure2NotVerifyPageApi,
-} from '@/api/task'
-import { cancelPipeInSpectProject, addPipeMajorIssues, submitPipeReport } from '@/api/pipe/pipeTaskOrder'
+  cancelPipeInSpectProject,
+  addPipeMajorIssues,
+  submitPipeReport,
+} from '@/api/pipe/pipeTaskOrder'
 import { updatePipeTaskOrderItemReportConclusion } from '@/api/pipe/pipeTaskOrderReport'
 
 import TipsPopup from './inspectProjectComponent/TipsPopup.vue'
@@ -507,7 +505,6 @@ const handleSelectProject = (item: CheckItem) => {
   selectAll.value = selectedProjects.value.length === props.reportList.length
 }
 
-
 const isConclusionError = (conclusion: string): boolean => {
   return /不合格|不符合/.test(conclusion || '')
 }
@@ -638,6 +635,11 @@ const handleCalcFee = (item: CheckItem) => {
     return
   }
 
+  if (item.taskStatus === PressureCheckerMyTaskStatus.REPORT_END) {
+    uni.showToast({ title: '报告已办结,不能录入费用', icon: 'error' })
+    return
+  }
+
   selectedCheckItem.value = { ...item, orderItemId: props.orderItemId }
   showCalcPopup.value = true
 }
@@ -649,7 +651,7 @@ const hideCalcPopup = () => {
 
 const handleUpdateRenderItem = async (calcData: any) => {
   await updatePipeTaskOrderItemReportConclusion(calcData)
-  const report = props.reportList.find(item => item.id === calcData.id)
+  const report = props.reportList.find((item) => item.id === calcData.id)
   const feeKey = 'fee'
   report[feeKey] = calcData[feeKey]
   props.refreshDetail()
@@ -733,10 +735,10 @@ const hideConclusionPopup = () => {
 
 const handleUpdateConclusionConfirm = async (conclusionData: any) => {
   await updatePipeTaskOrderItemReportConclusion(conclusionData)
-    // 先前端缓存结果,让响应更快,从而可以不引入Loading动画表达中间过渡
+  // 先前端缓存结果,让响应更快,从而可以不引入Loading动画表达中间过渡
   for (const key in conclusionData) {
-    if (!Object.hasOwn(conclusionData, key)) continue;
-    const element = conclusionData[key];
+    if (!Object.hasOwn(conclusionData, key)) continue
+    const element = conclusionData[key]
     currentCheckItem.value[key] = element
   }
   props.refreshDetail()
@@ -882,7 +884,12 @@ const handleAssociationOperation = (item: CheckItem) => {
 
 const showAddWorkInstructionPopup = async () => {
   try {
-    const result = await pressure2NotVerifyPageApi({ reportType: PressureReportType.WORKINSTRUCTION, status: 200, pageNo: 1, pageSize: 9999 })
+    const result = await pressure2NotVerifyPageApi({
+      reportType: PressureReportType.WORKINSTRUCTION,
+      status: 200,
+      pageNo: 1,
+      pageSize: 9999,
+    })
     const list = (result?.data || []).map((item: any) => ({
       ...item,
       label: item.tbName || '',

+ 1 - 1
src/pages/taskOnlinePage/taskOnline.vue

@@ -27,7 +27,7 @@
 
     <!-- 筛选条件栏 -->
     <RadioFilterBar
-      v-if="equipType === EquipmentType.BOILER""
+      v-if="equipType === EquipmentType.BOILER"
       v-model="rightType"
       :options="rightTypeList"
       type="radio"

+ 51 - 12
src/pages/unClaim/unClaimList.vue

@@ -32,16 +32,19 @@
       <RadioFilterBar
         v-model="rightType"
         :options="rightTypeList"
-        type="radio"
         @change="handleRightRefresh"
       />
-      <RadioFilterBar
-        v-model="showTodayOnly"
-        :options="todayOnlyOptions"
-        type="checkbox"
-        :margin-left="'15px'"
-        @change="handleShowTodayOnly"
-      />
+      <view class="today-toggle" @click="handleShowTodayOnly">
+        <view class="today-checkbox" :class="{ checked: showTodayOnly }">
+          <image
+            v-if="showTodayOnly"
+            class="today-check-icon"
+            :src="checkIcon"
+            mode="aspectFit"
+          />
+        </view>
+        <text class="today-text">仅看今天</text>
+      </view>
     </view>
 
     <!-- 列表 -->
@@ -76,13 +79,14 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted } from 'vue'
+import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
 import { onShow } from '@dcloudio/uni-app'
 import dayjs from 'dayjs'
 import QueryView from './components/query/QueryView.vue'
 import TaskItem from './components/TaskItem.vue'
 import UpdateContactPopup from './components/UpdateContactPopup.vue'
 import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
+import iconMap from '@/utils/imagesMap'
 import { useConfigStore } from '@/store/config'
 import { useUserStore } from '@/store/user'
 import { TaskOrderFuncName, requestFunc } from '@/api/ApiRouter/taskOrder'
@@ -114,7 +118,7 @@ const rightTypeList = [
   { value: '待认领', id: '100' },
   { value: '已认领', id: '400' },
 ]
-const todayOnlyOptions = [{ value: '仅看今天', id: 'today' }]
+const checkIcon = computed(() => iconMap.WhiteCheck)
 const defaultTypeValue = {}
 const itemRefs = reactive<Record<string, any>>({})
 const showUpdateContactPopup = ref(false)
@@ -204,8 +208,8 @@ const handleRightRefresh = (value: string | number | boolean) => {
 }
 
 // 切换仅看今天
-const handleShowTodayOnly = (value: string | number | boolean) => {
-  showTodayOnly.value = value as boolean
+const handleShowTodayOnly = () => {
+  showTodayOnly.value = !showTodayOnly.value
   params.showTodayOnly = showTodayOnly.value
   refreshList()
 }
@@ -364,7 +368,42 @@ defineExpose({
 .filter-bar {
   display: flex;
   justify-content: space-between;
+  align-items: center;
   flex-shrink: 0;
   background-color: white;
 }
+
+.today-toggle {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  padding-right: 15px;
+}
+
+.today-checkbox {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 18px;
+  height: 18px;
+  border-radius: 3px;
+  border: 1px solid #bbb;
+  background-color: #fff;
+
+  &.checked {
+    background-color: #2f8eff;
+    border-width: 0;
+  }
+}
+
+.today-check-icon {
+  width: 12px;
+  height: 12px;
+}
+
+.today-text {
+  margin-left: 6px;
+  font-size: 14px;
+  color: #333;
+}
 </style>