Browse Source

调整签名提交和推送对接、对接结果告知签名接口、调整前端组件的使用

yangguanjin 3 weeks ago
parent
commit
5c64bdef1c
29 changed files with 614 additions and 729 deletions
  1. 2 1
      env/.env.development
  2. 1 1
      env/.env.production
  3. 1 1
      src/api/ApiRouter/sign.ts
  4. 40 0
      src/api/ApiRouter/taskOrder.ts
  5. 8 0
      src/api/boiler/boilerTaskOrder.ts
  6. 9 0
      src/api/pipe/pipeTaskOrder.ts
  7. 1 1
      src/api/sign.ts
  8. 169 0
      src/components/RadioFilterBar/RadioFilterBar.vue
  9. 10 15
      src/components/SpreadDesigner/SpreadPDFConverter.vue
  10. 1 0
      src/components/components.d.ts
  11. 13 9
      src/pages/deviceExam/deviceExam.vue
  12. 12 7
      src/pages/equipment/detail/equipmentDetail.vue
  13. 7 7
      src/pages/home/index.vue
  14. 12 11
      src/pages/inspectionApproval/preViewReport/index.vue
  15. 10 73
      src/pages/inspectionPlanAudit/list/InspectionPlanAuditList.vue
  16. 10 14
      src/pages/pendingApproval/preViewReport/index.vue
  17. 11 14
      src/pages/pendingPreparation/preViewReport/index.vue
  18. 10 14
      src/pages/pendingRatify/preViewReport/index.vue
  19. 12 7
      src/pages/pendingVerification/preViewReport/index.vue
  20. 21 72
      src/pages/sign/index.vue
  21. 13 9
      src/pages/systemFile/systemFile.vue
  22. 13 7
      src/pages/taskOnline/TaskOnlineEquipmentList.vue
  23. 9 81
      src/pages/taskOnlinePage/taskOnline.vue
  24. 5 3
      src/pages/unClaim/components/TaskItemInfo.vue
  25. 80 67
      src/pages/unClaim/components/UpdateContactPopup.vue
  26. 51 44
      src/pages/unClaim/components/query/CheckDateCom.vue
  27. 40 40
      src/pages/unClaim/components/query/CheckNatureCom.vue
  28. 33 158
      src/pages/unClaim/unClaimList.vue
  29. 10 73
      src/pages/workInstructionAudit/list/WorkInstructionAuditList.vue

+ 2 - 1
env/.env.development

@@ -8,7 +8,8 @@ VITE_SHOW_SOURCEMAP = true
 VITE_SERVER_BASEURL = 'http://192.168.0.53:48080/appapi'
 # VITE_SERVER_BASEURL = 'http://127.0.0.1:48080/appapi'
 
-VITE_FILE_URL = 'https://youdao.hofo.co/dexdev'
+# VITE_FILE_URL = 'https://youdao.hofo.co/dexdev'
+VITE_FILE_URL = 'http://192.168.0.53:9110/dexdev'
 
 VITE_APP_PUBLIC_BASE = '/app-h5/'
 

+ 1 - 1
env/.env.production

@@ -9,7 +9,7 @@ VITE_SHOW_SOURCEMAP = false
 
 VITE_SERVER_BASEURL = 'http://192.168.0.53:48080/appapi'
 
-VITE_FILE_URL = 'https://youdao.hofo.co/dexdev'
+VITE_FILE_URL = 'http://192.168.0.53:9110/dexdev'
 
 VITE_APP_PUBLIC_BASE = '/app-h5/'
 

+ 1 - 1
src/api/ApiRouter/sign.ts

@@ -22,7 +22,7 @@ const map = {
     },
     [EquipmentType.PIPE]: {
       inputAdapter: null,
-      reqFunction: submitPipeSign,
+      reqFunction: submitBoilerSign,
       outputAdapter: null,
     },
     [EquipmentType.CONTAINER]: {

+ 40 - 0
src/api/ApiRouter/taskOrder.ts

@@ -30,6 +30,8 @@ import {
   getPipePendingPreparationListApi,
   getPipeMajorIssuesAuditList,
   updatePipeTaskOrder,
+  getPipeOrderForm,
+  addPipeMajorIssues,
 } from '@/api/pipe/pipeTaskOrder'
 import {
   getBoilerTaskConfirmPage,
@@ -45,6 +47,8 @@ import {
   getBoilerPendingPreparationListApi,
   getBoilerMajorIssuesAuditList,
   updateBoilerTaskOrder,
+  getBoilerOrderForm,
+  addBoilerMajorIssues,
 } from '@/api/boiler/boilerTaskOrder'
 
 type Adapter = {
@@ -69,6 +73,8 @@ export enum TaskOrderFuncName {
   ApprovalList,
   RatifyList,
   MajorIssuesAuditList,
+  GetOrderForm,
+  AddMajorIssues,
 }
 
 // 接口注册表(按接口、设备类型调用对应接口)
@@ -340,6 +346,40 @@ const map = {
       outputAdapter: null,
     },
   },
+  [TaskOrderFuncName.GetOrderForm]: {
+    [EquipmentType.BOILER]: {
+      inputAdapter: null,
+      reqFunction: getBoilerOrderForm,
+      outputAdapter: null,
+    },
+    [EquipmentType.PIPE]: {
+      inputAdapter: null,
+      reqFunction: getPipeOrderForm,
+      outputAdapter: null,
+    },
+    [EquipmentType.CONTAINER]: {
+      inputAdapter: null,
+      reqFunction: getBoilerOrderForm,
+      outputAdapter: null,
+    },
+  },
+  [TaskOrderFuncName.AddMajorIssues]: {
+    [EquipmentType.BOILER]: {
+      inputAdapter: null,
+      reqFunction: addBoilerMajorIssues,
+      outputAdapter: null,
+    },
+    [EquipmentType.PIPE]: {
+      inputAdapter: null,
+      reqFunction: addPipeMajorIssues,
+      outputAdapter: null,
+    },
+    [EquipmentType.CONTAINER]: {
+      inputAdapter: null,
+      reqFunction: addBoilerMajorIssues,
+      outputAdapter: null,
+    },
+  },
 }
 
 export const requestFunc = (funcName: TaskOrderFuncName, equipType: EquipmentType, params: any) => {

+ 8 - 0
src/api/boiler/boilerTaskOrder.ts

@@ -79,3 +79,11 @@ export const getBoilerPendingPreparationListApi = (params: any) => {
 export const getBoilerMajorIssuesAuditList = (params: any) => {
   return httpGet('/pressure2/boiler-task-order/order-item/major-issues/page', params)
 }
+
+export const getBoilerOrderForm = (params: any) => {
+  return httpGet('/pressure2/boiler-task-order/service-from/orderForm', params)
+}
+
+export const addBoilerMajorIssues = (data: any) => {
+  return httpPost('/pressure2/boiler-task-order/order-item/addMajorIssues', data)
+}

+ 9 - 0
src/api/pipe/pipeTaskOrder.ts

@@ -79,3 +79,12 @@ export const getPipePendingPreparationListApi = (params: any) => {
 export const getPipeMajorIssuesAuditList = (params: any) => {
   return httpGet('/pressure2/pipe-task-order/order-item/major-issues/page', params)
 }
+
+
+export const getPipeOrderForm = (params: any) => {
+  return httpGet('/pressure2/pipe-task-order/service-from/orderForm', params)
+}
+
+export const addPipeMajorIssues = (data: any) => {
+  return httpPost('/pressure2/pipe-task-order/order-item/addMajorIssues', data)
+}

+ 1 - 1
src/api/sign.ts

@@ -69,7 +69,7 @@ export const pushTaskOrder = (data: any) => {
  * 推送任务单
  */
 export const pushPressure2TaskOrder = (data: any) => {
-  return httpPost('/pressure2/boiler-task-order-sign-file/create', data)
+  return httpPost('/pressure2/boiler-task-order/service-from/push', data)
 }
 
 /**

+ 169 - 0
src/components/RadioFilterBar/RadioFilterBar.vue

@@ -0,0 +1,169 @@
+<template>
+  <view class="radio-filter-bar" :class="{ 'has-checkbox': showCheckbox }">
+    <view class="filter-row">
+      <view
+        v-for="(item, index) in options"
+        :key="item.id"
+        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 }"
+        >
+          <view
+            class="checkbox"
+            :class="{
+              'radio-style': type === 'radio',
+              'square-style': type === 'checkbox',
+              'checked': isChecked(item),
+              'radio-checked': type === 'radio' && 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>
+          <text class="checkbox-text">{{ item.value }}</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { computed } from 'vue'
+import iconMap from '@/utils/imagesMap'
+
+interface FilterOption {
+  id: string | number
+  value: string
+}
+
+interface Props {
+  options: FilterOption[]
+  modelValue: string | number | boolean
+  type?: 'radio' | 'checkbox'
+  showCheckbox?: boolean
+  marginLeft?: string
+}
+
+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]
+}>()
+
+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)
+}
+</script>
+
+<style lang="scss" scoped>
+.radio-filter-bar {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  padding: 10px 15px;
+  background-color: #fff;
+  border-bottom: 1px solid #eee;
+
+  &.has-checkbox {
+    flex-wrap: wrap;
+  }
+}
+
+.filter-row {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+}
+
+.filter-item {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+
+.checkbox-wrapper {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+
+.checkbox {
+  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;
+}
+
+.radio-checked {
+  border-color: rgb(47, 142, 255);
+}
+
+.radio-inner {
+  width: 9.5px;
+  height: 9.5px;
+  background-color: rgb(47, 142, 255);
+  border-radius: 4.75px;
+}
+
+.checkbox.checked {
+  background-color: #2f8eff;
+  border-width: 0;
+}
+
+.check-icon {
+  width: 12px;
+  height: 12px;
+}
+
+.checkbox-text {
+  margin-left: 6px;
+  font-size: 14px;
+  color: #333;
+}
+</style>

+ 10 - 15
src/components/SpreadDesigner/SpreadPDFConverter.vue

@@ -337,7 +337,13 @@ function deepMergeSchemaValue(target, source) {
             ? targetValue
             : deepMergeSchemaValue(targetValue, sourceValue)
       } else if (sourceValue !== undefined && sourceValue !== '') {
-        result[key] = sourceValue
+        const trimmedSourceValue = sourceValue.trim()
+        // JSON字符串需要解析为对象或数组
+        if (typeof trimmedSourceValue === 'string' && (trimmedSourceValue.startsWith("{") || trimmedSourceValue.startsWith("["))) {
+          result[key] = JSON.parse(trimmedSourceValue)
+        } else {
+          result[key] = trimmedSourceValue
+        }
       }
     }
   }
@@ -844,11 +850,11 @@ function handleWorkbookInitialized(spreadInstance) {
   }
 
   if (templateData && templateData.pathNameMapping) {
+    // console.log('字段名映射已初始化:', fieldNameMapping.value)
     fieldNameMapping.value = templateData.pathNameMapping
-    console.log('字段名映射已初始化:', fieldNameMapping.value)
   } else {
+    // console.log('未找到字段名映射,使用空数组')
     fieldNameMapping.value = []
-    console.log('未找到字段名映射,使用空数组')
   }
 }
 
@@ -900,14 +906,12 @@ function handleNavButtonClick(button) {
  * @param templateData 模板数据,填充模板文件中对应的数据格
  */
 function loadTemplateData(templateBlob, templateData) {
-  console.log('触发模板渲染加载。。。')
   if (!designer.value || !templateData) return
 
   const spreadInstance = designer.value.getWorkbook()
   spreadInstance.touchToolStrip.clear()
 
   if (templateBlob) {
-    console.log('开始加载模板文件')
 
     try {
       const blob = base64ToBlob(templateBlob, 'application/ssjson')
@@ -915,7 +919,6 @@ function loadTemplateData(templateBlob, templateData) {
       spreadInstance.open(
         blob,
         () => {
-          console.log('模板文件加载成功!')
           initDesignerSheetConfig(spreadInstance.getActiveSheet())
 
           if (templateData.schema) {
@@ -935,17 +938,11 @@ function loadTemplateData(templateBlob, templateData) {
       console.error('处理模板文件时发生错误:', error)
     }
   } else if (templateData.schema) {
-    console.log(
-      '开始加载schema模板:',
-      JSON.stringify(templateData.schema).substring(0, 200) + '...',
-    )
-    console.log('开始加载数据:', JSON.stringify(templateData.data).substring(0, 200) + '...')
 
     if (spreadInstance.getSheetCount() === 0) {
       const sheet = spreadInstance.addSheet(0)
       sheet.name('Sheet1')
       initDesignerSheetConfig(sheet)
-      console.log('创建了新工作表')
     }
 
     initDataSource(designer.value, templateData)
@@ -954,8 +951,6 @@ function loadTemplateData(templateBlob, templateData) {
     handleSheetTableCopyTo(designer.value, true)
     initSpreadInputEvents(spreadInstance)
   }
-
-  console.log('模板数据加载完成。。。')
 }
 
 function saveExcel() {
@@ -1192,7 +1187,7 @@ watch(
   () => props.templateBlob,
   (newBlob, oldBlob) => {
     if (newBlob && newBlob !== oldBlob && designer.value && props.templateData) {
-      console.log('templateBlob 发生变化,重新加载模板,数据:', props.templateData)
+      // console.log('templateBlob 发生变化,重新加载模板,数据:', props.templateData)
       loadTemplateData(props.templateBlob, props.templateData)
     }
   },

+ 1 - 0
src/components/components.d.ts

@@ -14,6 +14,7 @@ PageLayout: typeof import('./PageLayout/PageLayout.vue')['default']
 Popup: typeof import('./Popup/Popup.vue')['default']
 PopupDict: typeof import('./PopupDict/PopupDict.vue')['default']
 ProgressMap: typeof import('./ProgressMap/ProgressMap.vue')['default']
+RadioFilterBar: typeof import('./RadioFilterBar/RadioFilterBar.vue')['default']
 RightConditionFilter: typeof import('./RightConditionFilter/RightConditionFilter.vue')['default']
 SelectDept: typeof import('./SelectDept/SelectDept.vue')['default']
 SelectUser: typeof import('./SelectUser/SelectUser.vue')['default']

+ 13 - 9
src/pages/deviceExam/deviceExam.vue

@@ -26,12 +26,11 @@
       <view v-if="controlQueryVisible" class="query-form">
         <view class="form-item">
           <text class="form-label">设备类别</text>
-          <picker class="form-picker" :range="equipmentTypes" range-key="label" @change="onTypeChange">
-            <view class="picker-value">
-              <text>{{ selectedType?.label || '请选择' }}</text>
-              <text class="picker-arrow">▼</text>
-            </view>
-          </picker>
+          <wd-picker
+            v-model="selectedTypeValue"
+            :columns="equipmentTypesColumn"
+            @change="onTypeChange"
+          />
         </view>
         <view class="form-item">
           <text class="form-label">设备名称</text>
@@ -96,7 +95,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted } from 'vue'
+import { ref, reactive, onMounted, computed } from 'vue'
 import { useConfigStore } from '@/store/config'
 import { EquipFuncName, requestFunc } from '@/api/ApiRouter/equipment'
 import NavBar from '@/components/NavBar/NavBar.vue'
@@ -127,12 +126,16 @@ const formData = reactive({
 })
 
 const selectedType = ref<any>(null)
+const selectedTypeValue = ref('')
 const equipmentTypes = ref([
   { label: '全部', value: '' },
   { label: '压力容器', value: '1' },
   { label: '锅炉', value: '2' },
   { label: '管道', value: '3' },
 ])
+const equipmentTypesColumn = computed(() => [
+  equipmentTypes.value.map((item) => ({ label: item.label, value: item.value })),
+])
 
 // 获取列表数据
 const fetchList = async (refresh = false) => {
@@ -177,10 +180,11 @@ const refreshList = () => {
 }
 
 // 选择设备类别
-const onTypeChange = (e: any) => {
-  const index = e.detail.value
+const onTypeChange = ({ selected }) => {
+  const index = selected[0]
   selectedType.value = equipmentTypes.value[index]
   formData.type = selectedType.value?.value || ''
+  selectedTypeValue.value = selectedType.value?.value || ''
 }
 
 // 重置

+ 12 - 7
src/pages/equipment/detail/equipmentDetail.vue

@@ -106,11 +106,11 @@
     <view v-if="showSelectUserPopup" class="popup-overlay" @click="closeSelectUserPopup">
       <view class="popup-content" @click.stop>
         <text class="popup-title">选择校核人</text>
-        <picker :range="recheckUserGroupList" range-key="label" @change="onUserChange">
-          <view class="picker-value">
-            <text>{{ currentReckUser?.label || '请选择' }}</text>
-          </view>
-        </picker>
+        <wd-picker
+          v-model="selectedUserValue"
+          :columns="recheckUserColumn"
+          @change="onUserChange"
+        />
         <view class="popup-actions">
           <button class="action-btn cancel-btn" @click="closeSelectUserPopup">取消</button>
           <button class="action-btn confirm-btn" @click="confirmSelectUser">确定</button>
@@ -188,6 +188,10 @@ const isInspectMode = ref(false)
 const showSelectUserPopup = ref(false)
 const showCheckProject = ref(false)
 const recheckUserGroupList = ref<any[]>([])
+const selectedUserValue = ref('')
+const recheckUserColumn = computed(() => [
+  recheckUserGroupList.value.map((item) => ({ label: item.label, value: item.value })),
+])
 const currentReckUser = ref<any>(null)
 const currentCheckItem = ref<any>(null)
 
@@ -468,9 +472,10 @@ const closeSelectUserPopup = () => {
 }
 
 // 用户选择变化
-const onUserChange = (e: any) => {
-  const index = e.detail.value
+const onUserChange = ({ selected }) => {
+  const index = selected[0]
   currentReckUser.value = recheckUserGroupList.value[index]
+  selectedUserValue.value = currentReckUser.value?.value || ''
 }
 
 // 确认选择用户

+ 7 - 7
src/pages/home/index.vue

@@ -450,13 +450,13 @@ const capabilityList = [
     path: '/pages/unitQuery/unitQuery',
     backgroundColor: '#FEF7F6',
   },
-  {
-    title: '体系文件',
-    desc: '查看体系文件',
-    iconUrl: iconMap.systemFile,
-    path: '/pages/systemFile/systemFile',
-    backgroundColor: '#F6FBF6',
-  },
+  // {
+  //   title: '体系文件',
+  //   desc: '查看体系文件',
+  //   iconUrl: iconMap.systemFile,
+  //   path: '/pages/systemFile/systemFile',
+  //   backgroundColor: '#F6FBF6',
+  // },
 ]
 
 // 跳转

+ 12 - 11
src/pages/inspectionApproval/preViewReport/index.vue

@@ -54,15 +54,11 @@
     <view v-if="showSelectUser" class="popup-overlay" @click="closeSelectUserPopup">
       <view class="popup-content" @click.stop>
         <text class="popup-title">选择批准人</text>
-        <picker
-          :range="auditUserGroupList"
-          range-key="label"
+        <wd-picker
+          v-model="selectedUserValue"
+          :columns="auditUserColumn"
           @change="onUserChange"
-        >
-          <view class="picker-value">
-            <text>{{ selectedUser?.label || '请选择' }}</text>
-          </view>
-        </picker>
+        />
         <view class="popup-actions">
           <button class="action-btn cancel-btn" @click="closeSelectUserPopup">取消</button>
           <button class="action-btn confirm-btn" @click="confirmSelectUser">确定</button>
@@ -73,7 +69,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, computed } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
 import { getApprovalDetail, getUserGroupUserList, passOpinionNoticeApproval, rejectOpinionNoticeApproval } from '@/api/task'
 import NavBar from '@/components/NavBar/NavBar.vue'
@@ -91,7 +87,11 @@ const showGoBack = ref(false)
 const showSelectUser = ref(false)
 const goBackReason = ref('')
 const selectedUser = ref<UserItem | null>(null)
+const selectedUserValue = ref('')
 const auditUserGroupList = ref<UserItem[]>([])
+const auditUserColumn = computed(() => [
+  auditUserGroupList.value.map((item) => ({ label: item.label, value: item.value })),
+])
 const defaultSelect = ref<UserItem | null>(null)
 
 let id = ''
@@ -180,9 +180,10 @@ const closeSelectUserPopup = () => {
 }
 
 // 用户选择变化
-const onUserChange = (e: any) => {
-  const index = e.detail.value
+const onUserChange = ({ selected }) => {
+  const index = selected[0]
   selectedUser.value = auditUserGroupList.value[index]
+  selectedUserValue.value = selectedUser.value?.value || ''
 }
 
 // 确认选择用户

+ 10 - 73
src/pages/inspectionPlanAudit/list/InspectionPlanAuditList.vue

@@ -18,19 +18,12 @@
     <NavBar title="检验方案审核" />
 
     <!-- 筛选栏 -->
-    <view class="filter-bar">
-      <view
-        v-for="item in rightTypeList"
-        :key="item.id"
-        class="filter-item"
-        @click="handleRightRefresh(item.id)"
-      >
-        <view class="checkbox-wrapper">
-          <view class="checkbox" :class="{ checked: rightType === item.id }"></view>
-          <text class="checkbox-text">{{ item.value }}</text>
-        </view>
-      </view>
-    </view>
+    <RadioFilterBar
+      v-model="rightType"
+      :options="rightTypeList"
+      type="radio"
+      @change="handleRightRefresh"
+    />
 
     <!-- 列表 -->
     <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
@@ -53,6 +46,7 @@ import { useUserStore } from '@/store/user'
 import { useConfigStore } from '@/store/config'
 import Item from '@/pages/inspectionPlanAudit/components/Item.vue'
 import NavBar from '@/components/NavBar/NavBar.vue'
+import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
 import { requestFunc, TaskOrderFuncName } from '@/api/ApiRouter/taskOrder'
 
 defineOptions({
@@ -132,9 +126,9 @@ const refreshList = () => {
 }
 
 // 筛选刷新
-const handleRightRefresh = (id: string) => {
-  rightType.value = id
-  params.status = id
+const handleRightRefresh = (value: string | number | boolean) => {
+  rightType.value = value as string
+  params.status = rightType.value
   refreshList()
 }
 
@@ -168,63 +162,6 @@ onUnmounted(() => {
   background-color: #f5f5f5;
 }
 
-.navigate-view {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  height: 44px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.navigate-title {
-  font-size: 17px;
-  font-weight: 500;
-  color: #333;
-}
-
-.filter-bar {
-  display: flex;
-  flex-direction: row;
-  padding: 10px 15px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.filter-item {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  margin-right: 15px;
-}
-
-.checkbox-wrapper {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-}
-
-.checkbox {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 18px;
-  height: 18px;
-  margin-right: 6px;
-  border: 1px solid #bbb;
-  border-radius: 100%;
-}
-
-.checkbox.checked {
-  background-color: #2f8eff;
-  border-width: 0;
-}
-
-.checkbox-text {
-  font-size: 14px;
-  color: #333;
-}
-
 .list-scroll {
   flex: 1;
   overflow: hidden;

+ 10 - 14
src/pages/pendingApproval/preViewReport/index.vue

@@ -13,18 +13,11 @@
     <!-- 导航栏 -->
     <ReportNavBar>
       <template #right>
-        <picker
-          class="report-picker"
+        <wd-picker
+          v-model="selectedReportIndex"
+          :columns="reportDOColumn"
           @change="handleReportChange"
-          :value="selectedReportIndex"
-          :range="reportDOList"
-          range-key="name"
-        >
-          <view class="picker-content">
-            <text class="picker-text">{{ reportDOList[selectedReportIndex]?.name || '选择报告' }}</text>
-            <text class="picker-arrow">▼</text>
-          </view>
-        </picker>
+        />
         <button class="nav-btn btn-grey">查看附件</button>
         <button class="nav-btn btn-grey">查看档案</button>
         <button class="nav-btn btn-orange">查看记录</button>
@@ -44,7 +37,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, watch } from 'vue'
+import { ref, watch, computed } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
 import { submitApi, rollbackApi } from '@/api/pendingApproval'
 import ReportNavBar from '@/components/NavBar/ReportNavBar.vue'
@@ -106,10 +99,13 @@ const businessConfig = ref<any>({
 })
 const templateData = ref<any>({})
 const selectedReportIndex = ref(0)
+const reportDOColumn = computed(() => [
+  reportDOList.value.map((item) => ({ label: item.name, value: item.id })),
+])
 
 // 处理报告选择
-const handleReportChange = (e) => {
-  const index = e.detail.value
+const handleReportChange = ({ selected }) => {
+  const index = selected[0]
   selectedReportIndex.value = index
   selectedReport.value = reportList.value?.[index] || null
 }

+ 11 - 14
src/pages/pendingPreparation/preViewReport/index.vue

@@ -13,18 +13,11 @@
     <!-- 导航栏 -->
     <ReportNavBar>
       <template #right>
-        <picker
-          class="report-picker"
+        <wd-picker
+          v-model="selectedReportIndex"
+          :columns="reportDOColumn"
           @change="handleReportChange"
-          :value="selectedReportIndex"
-          :range="reportDOList"
-          range-key="name"
-        >
-          <view class="picker-content">
-            <text class="picker-text">{{ reportDOList[selectedReportIndex].name }}</text>
-            <text class="picker-arrow">▼</text>
-          </view>
-        </picker>
+        />
         <button class="nav-btn btn-grey">查看附件</button>
         <button class="nav-btn btn-grey">查看档案</button>
         <button class="nav-btn btn-orange">编制主报告</button>
@@ -43,7 +36,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, watch } from 'vue'
+import { ref, watch, computed } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
 import { submitApi } from '@/api/pendingPreparation'
 import ReportNavBar from '@/components/NavBar/ReportNavBar.vue'
@@ -105,9 +98,13 @@ const businessConfig = ref<any>({
 })
 const templateData = ref<any>({})
 const selectedReportIndex = ref(0)
+const reportDOColumn = computed(() => [
+  reportDOList.value.map((item) => ({ label: item.name, value: item.id })),
+])
+
 // 处理报告选择
-const handleReportChange = (e) => {
-  const index = e.detail.value
+const handleReportChange = ({ selected }) => {
+  const index = selected[0]
   selectedReportIndex.value = index
   selectedReport.value = reportList.value?.[index] || null
 }

+ 10 - 14
src/pages/pendingRatify/preViewReport/index.vue

@@ -13,18 +13,11 @@
     <!-- 导航栏 -->
     <ReportNavBar>
       <template #right>
-        <picker
-          class="report-picker"
+        <wd-picker
+          v-model="selectedReportIndex"
+          :columns="reportDOColumn"
           @change="handleReportChange"
-          :value="selectedReportIndex"
-          :range="reportDOList"
-          range-key="name"
-        >
-          <view class="picker-content">
-            <text class="picker-text">{{ reportDOList[selectedReportIndex]?.name || '选择报告' }}</text>
-            <text class="picker-arrow">▼</text>
-          </view>
-        </picker>
+        />
         <button class="nav-btn btn-grey">查看附件</button>
         <button class="nav-btn btn-grey">查看档案</button>
         <button class="nav-btn btn-orange">查看记录</button>
@@ -44,7 +37,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, watch } from 'vue'
+import { ref, watch, computed } from 'vue'
 import { onLoad } from '@dcloudio/uni-app'
 import { finishApi, rollbackApi } from '@/api/pendingRatify'
 import ReportNavBar from '@/components/NavBar/ReportNavBar.vue'
@@ -106,10 +99,13 @@ const businessConfig = ref<any>({
 })
 const templateData = ref<any>({})
 const selectedReportIndex = ref(0)
+const reportDOColumn = computed(() => [
+  reportDOList.value.map((item) => ({ label: item.name, value: item.id })),
+])
 
 // 处理报告选择
-const handleReportChange = (e) => {
-  const index = e.detail.value
+const handleReportChange = ({ selected }) => {
+  const index = selected[0]
   selectedReportIndex.value = index
   selectedReport.value = reportList.value?.[index] || null
 }

+ 12 - 7
src/pages/pendingVerification/preViewReport/index.vue

@@ -31,11 +31,11 @@
       <view class="popup-body">
         <view class="row">
           <text class="center-text">退回阶段:</text>
-          <picker :range="rejectStageDict" range-key="label" @change="onStageChange">
-            <view class="picker-value">
-              <text>{{ selectedStage?.label || '请选择' }}</text>
-            </view>
-          </picker>
+          <wd-picker
+            v-model="selectedStageValue"
+            :columns="rejectStageColumn"
+            @change="onStageChange"
+          />
         </view>
 
         <view class="row" style="margin-bottom: 20px">
@@ -184,11 +184,14 @@ const showGoBack = ref(false)
 const rejectStageDict = [{ label: '记录录入', value: '500' }]
 const rejectReqData = ref<any>({ id: null, reason: null })
 const selectedStage = ref<StringAnyObj | null>(null)
+const selectedStageValue = ref('')
+const rejectStageColumn = ref([rejectStageDict.map((item) => ({ label: item.label, value: item.value }))])
 
 const showGoBackPopupFn = () => {
   rejectReqData.value.id = null
   rejectReqData.value.reason = null
   selectedStage.value = null
+  selectedStageValue.value = ''
   showGoBack.value = true
 }
 
@@ -196,12 +199,14 @@ const closeGoBackPopup = () => {
   rejectReqData.value.id = null
   rejectReqData.value.reason = null
   selectedStage.value = null
+  selectedStageValue.value = ''
   showGoBack.value = false
 }
 
-const onStageChange = (e: any) => {
-  const index = e.detail.value
+const onStageChange = ({ selected }) => {
+  const index = selected[0]
   selectedStage.value = rejectStageDict[index] || null
+  selectedStageValue.value = selectedStage.value?.value || ''
 }
 
 const toast = useToast()

+ 21 - 72
src/pages/sign/index.vue

@@ -176,8 +176,6 @@ import { SignFuncName, requestFunc } from '@/api/ApiRouter/sign'
 import { TaskOrderFuncName, requestFunc as taskOrderRequestFunc } from '@/api/ApiRouter/taskOrder'
 import { EquipmentType } from '@/utils/dictMap'
 
-
-
 const equipType = useConfigStore().getEquipType()
 const title = ref('')
 const routeType = ref<'FWD' | 'JYRS' | 'AQJC' | 'ZXXX'>()
@@ -288,73 +286,6 @@ onLoad((options) => {
   canvasWidth.value = sysInfo.windowWidth - 32
 })
 
-// 获取任务单配置
-// const getTaskOrderGcConfig = async () => {
-//   try {
-//     const result: any = await getGcConfig(
-//       {
-//         orderId: orderId.value,
-//         businessType: routeType.value ? businessTypeMap[routeType.value] : '',
-//         orderItemId: orderItemId.value || undefined,
-//         templateId: templateId.value || undefined,
-//       },
-//       userInfo.value,
-//     )
-
-//     const res = result?.data
-//     gcConfig.value = res
-
-//     if (res) {
-//       fetchTaskOrderImg(res)
-//     } else {
-//       uni.showToast({ title: '获取配置信息失败', icon: 'error' })
-//     }
-//   } catch (error) {
-//     console.error('获取配置失败:', error)
-//     uni.showToast({ title: '获取配置失败', icon: 'error' })
-//   }
-// }
-
-// 获取任务单图片
-// const fetchTaskOrderImg = async (res: any) => {
-//   const { dataStr, templateUrl, templateId, fileVersionId } = res
-
-//   if (!orderId.value) return
-
-//   if (orderId.value && dataStr && templateUrl) {
-//     const params: any = {
-//       dataStr,
-//       templateUrl,
-//       orderId: orderId.value,
-//       businessType: routeType.value ? businessTypeMap[routeType.value] : '',
-//       fileType: 100,
-//       orderItemId: orderItemId.value || undefined,
-//       templateId,
-//     }
-
-//     if (routeType.value === 'ZXXX' && fileVersionId) {
-//       params.fileVersionId = fileVersionId
-//     }
-
-//     try {
-//       const result: any = await getTaskOrderImg(params)
-//       if (result) {
-//         pdfImg.value = result
-//         uni.getImageInfo({
-//           src: result,
-//           success: (imageInfo) => {
-//             const screenWidth = uni.getSystemInfoSync().windowWidth - 32
-//             pdfWidth.value = screenWidth
-//             pdfHeight.value = (screenWidth * imageInfo.height) / imageInfo.width
-//           },
-//         })
-//       }
-//     } catch (error) {
-//       console.error('获取图片失败:', error)
-//     }
-//   }
-// }
-
 const orderReportId = ref('')
 const getPreviewData = async () => {
   // orderId --> templateId + refId --> templateBlob 和 templateData
@@ -384,6 +315,25 @@ const getPreviewData = async () => {
         id: orderId.value,
       })
       const notificationformReport = orderDetail.data?.notificationformReport
+      if (!notificationformReport) {
+        const orderFormRes = await taskOrderRequestFunc(TaskOrderFuncName.GetOrderForm, equipType, {
+          orderId: orderId.value,
+          businessType: 1000,
+        })
+        const JYRSTemplateId = orderFormRes.data?.templateId || ''
+        const addMajorIssuesRes = await taskOrderRequestFunc(TaskOrderFuncName.AddMajorIssues, equipType, {
+          orderId: orderId.value,
+          businessType: 1000,
+          templateId: JYRSTemplateId,
+        })
+        const JYRSReportId = addMajorIssuesRes.data
+        templateId.value = JYRSTemplateId
+        refId.value = (JYRSReportId as string) || ''
+      } else {
+        templateId.value = notificationformReport?.templateId || ''
+        refId.value = notificationformReport?.id || ''
+        orderReportId.value = notificationformReport?.id || ''
+      }
       if (!notificationformReport) {
         uni.showToast({ title: '暂无检验结果告知报表', icon: 'error' })
         return
@@ -538,7 +488,7 @@ const confirmSign = async () => {
     const path = await signatureRef.value.getImage()
     signImg.value = path
     showSignImg.value = path
-    console.log('imagePath....', path)
+    // console.log('imagePath....', path)
 
     uni.getImageInfo({
       src: path,
@@ -707,6 +657,7 @@ const handlePushOrderSubmit = () => {
     receiverPhone: inputPhone.value,
     receiverEmail: routeType.value !== 'ZXXX' ? inputEmail.value || '' : '',
     businessType: routeType.value ? businessTypeMap[routeType.value] : '',
+    signUrl: uploadedSignUrl.value || signImg.value,
     orderItemId: orderItemId.value || undefined,
     securityCheckId: securityCheckId.value,
     equipMainType: equipTypeCode(equipType),
@@ -717,7 +668,6 @@ const handlePushOrderSubmit = () => {
       if (res?.code === 0) {
         uni.showToast({ title: '推送成功', icon: 'success' })
         showInputPopup.value = false
-        // getTaskOrderGcConfig()
       } else {
         uni.showToast({ title: res?.msg || '推送失败', icon: 'none' })
       }
@@ -743,7 +693,6 @@ const equipTypeCode = (type: EquipmentType) => {
 
 onMounted(() => {
   if (orderId.value) {
-    // getTaskOrderGcConfig()
     getPreviewData()
   }
 })

+ 13 - 9
src/pages/systemFile/systemFile.vue

@@ -26,12 +26,11 @@
       <view v-if="controlQueryVisible" class="query-form">
         <view class="form-item">
           <text class="form-label">文件类型</text>
-          <picker class="form-picker" :range="fileTypes" range-key="label" @change="onTypeChange">
-            <view class="picker-value">
-              <text>{{ selectedType?.label || '请选择' }}</text>
-              <text class="picker-arrow">▼</text>
-            </view>
-          </picker>
+          <wd-picker
+            v-model="selectedTypeValue"
+            :columns="fileTypesColumn"
+            @change="onTypeChange"
+          />
         </view>
         <view class="form-item">
           <text class="form-label">文件名称</text>
@@ -86,7 +85,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted } from 'vue'
+import { ref, reactive, onMounted, computed } from 'vue'
 import { getStandardDocList, getStandardDocFileByUploadId } from '@/api/index'
 import dayjs from 'dayjs'
 import NavBar from '@/components/NavBar/NavBar.vue'
@@ -112,6 +111,7 @@ const formData = reactive({
 })
 
 const selectedType = ref<any>({ label: '标准文件', value: 1 })
+const selectedTypeValue = ref(1)
 const fileTypes = [
   { label: '标准文件', value: 1 },
   { label: '作业指导书', value: 2 },
@@ -121,6 +121,9 @@ const fileTypes = [
   { label: '质量记录', value: 6 },
   { label: '外来文件', value: 7 },
 ]
+const fileTypesColumn = computed(() => [
+  fileTypes.map((item) => ({ label: item.label, value: item.value })),
+])
 
 const statusEnum: Record<string, string> = {
   '0': '待审核',
@@ -176,10 +179,11 @@ const refreshList = () => {
 }
 
 // 选择文件类型
-const onTypeChange = (e: any) => {
-  const index = e.detail.value
+const onTypeChange = ({ selected }) => {
+  const index = selected[0]
   selectedType.value = fileTypes[index]
   formData.type = selectedType.value?.value || 1
+  selectedTypeValue.value = selectedType.value?.value || 1
 }
 
 // 重置

+ 13 - 7
src/pages/taskOnline/TaskOnlineEquipmentList.vue

@@ -218,11 +218,11 @@
         <text class="popup-title">添加检验方案</text>
         <view class="form-item">
           <text class="form-label">模板封面</text>
-          <picker :range="templateList" range-key="name" @change="onTemplateChange">
-            <view class="picker-value">
-              <text>{{ selectedTemplate?.name || '请选择' }}</text>
-            </view>
-          </picker>
+          <wd-picker
+            v-model="selectedTemplateId"
+            :columns="templateListColumn"
+            @change="onTemplateChange"
+          />
         </view>
         <view class="form-item">
           <text class="form-label">检验方案名称</text>
@@ -336,7 +336,11 @@ const suspendReason = ref('')
 const showInspectionplanPopup = ref(false)
 const inspectionplanName = ref('')
 const selectedTemplate = ref<any>(null)
+const selectedTemplateId = ref('')
 const templateList = ref<any[]>([])
+const templateListColumn = computed(() => [
+  templateList.value.map((item) => ({ label: item.name, value: item.id })),
+])
 
 const showUpdateContactPopup = ref(false)
 const currentItem = ref<any>({})
@@ -724,8 +728,10 @@ const closeInspectionplanPopup = () => {
   showInspectionplanPopup.value = false
 }
 
-const onTemplateChange = (e: any) => {
-  selectedTemplate.value = templateList.value[e.detail.value]
+const onTemplateChange = ({ selected }) => {
+  const index = selected[0]
+  selectedTemplate.value = templateList.value[index]
+  selectedTemplateId.value = selectedTemplate.value?.id || ''
 }
 
 const addInspectionplanConfirm = async () => {

+ 9 - 81
src/pages/taskOnlinePage/taskOnline.vue

@@ -21,21 +21,12 @@
     <QueryView ref="queryViewRef" :query-type="defaultTypeValue" @query-action="queryAction" />
 
     <!-- 筛选条件栏 -->
-    <view class="filter-bar">
-      <view
-        v-for="(item, index) in rightTypeList"
-        :key="item.id"
-        class="filter-item"
-        @click="handleRightType(item.id)"
-      >
-        <view class="checkbox-wrapper" :style="{ marginLeft: index === 0 ? '0' : '15px' }">
-          <view class="checkbox" :class="{ 'radio-checked': rightType === item.id }">
-            <view v-if="rightType === item.id" class="radio-inner"></view>
-          </view>
-          <text class="checkbox-text">{{ item.value }}</text>
-        </view>
-      </view>
-    </view>
+    <RadioFilterBar
+      v-model="rightType"
+      :options="rightTypeList"
+      type="radio"
+      @change="handleRightType"
+    />
 
     <!-- 列表 -->
     <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
@@ -62,6 +53,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
 import { useUserStore } from '@/store/user'
 import QueryView from './components/query/QueryView.vue'
 import TaskItem from './components/TaskItem.vue'
+import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
 import { useConfigStore } from '@/store/config'
 import { TaskOrderFuncName, requestFunc } from '@/api/ApiRouter/taskOrder'
 import NavBar from '@/components/NavBar/NavBar.vue'
@@ -193,8 +185,8 @@ const queryAction = () => {
 }
 
 // 切换筛选类型
-const handleRightType = (id: string) => {
-  rightType.value = id as 'claim' | 'allot' | 'unclaim'
+const handleRightType = (value: string | number | boolean) => {
+  rightType.value = value as 'claim' | 'allot' | 'unclaim' | ''
   refreshList()
 }
 
@@ -236,70 +228,6 @@ onMounted(() => {
   background-color: #f5f5f5;
 }
 
-.navigate-view {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  height: 44px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.navigate-title {
-  font-size: 17px;
-  font-weight: 500;
-  color: #333;
-}
-
-.filter-bar {
-  display: flex;
-  flex-direction: row;
-  flex-wrap: wrap;
-  padding: 10px 15px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.filter-item {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-}
-
-.checkbox-wrapper {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-}
-
-.checkbox {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 16px;
-  height: 16px;
-  margin-right: 6px;
-  border: 1px solid #bbb;
-  border-radius: 50%;
-}
-
-.checkbox.radio-checked {
-  background-color: #fff;
-  border-color: #2f8eff;
-}
-
-.checkbox .radio-inner {
-  width: 8px;
-  height: 8px;
-  background-color: #2f8eff;
-  border-radius: 50%;
-}
-
-.checkbox-text {
-  font-size: 14px;
-  color: #333;
-}
-
 .list-scroll {
   flex: 1;
   overflow: hidden;

+ 5 - 3
src/pages/unClaim/components/TaskItemInfo.vue

@@ -11,7 +11,9 @@
 
     <view class="row-center">
       <text class="title flex-1">项目负责人:<text class="text">{{ item.manager?.nickname }}</text></text>
-      <text class="title flex-1">检验人:<text class="text">{{ item.checkUsers }}</text></text>
+    </view>
+    <view class="row-center">
+      <text class="title flex-1">检验人:<text class="text">{{ item?.appoinmentUser?.map((v: any) => v.nickname)?.join('、') || '' }}</text></text>
     </view>
 
     <text v-if="item.remark" class="title block">备注:<text class="text">{{ item.remark }}</text></text>
@@ -52,7 +54,7 @@ const emit = defineEmits<{
 
 // 服务单/受理单状态
 const serviceOrderStatus = computed(() => {
-  const list = props.item.signFileRespVOList || []
+  const list = props.item.signFileList || []
   return list.find((v: any) => v.businessType === 100)
 })
 
@@ -65,7 +67,7 @@ const serviceOrderStatusText = computed(() => {
 
 // 检验结果状态
 const resultStatus = computed(() => {
-  const list = props.item.signFileRespVOList || []
+  const list = props.item.signFileList || []
   return list.find((v: any) => v.businessType === 200)
 })
 

+ 80 - 67
src/pages/unClaim/components/UpdateContactPopup.vue

@@ -1,81 +1,89 @@
 <template>
-  <view class="popup-container">
-    <view class="head-title">
-      <text class="head-title-text">联系人修改</text>
-    </view>
-
-    <view class="tabs-container">
-      <view class="tab-bar">
-        <view v-for="(tab, index) in tabs" :key="tab.id" class="tab-item" @click="switchTab(index)">
-          <text class="tab-text" :class="{ active: currentTab === index }">{{ tab.value }}</text>
-          <view v-if="currentTab === index" class="tab-line"></view>
-        </view>
+  <wd-popup
+    v-model="showPopup"
+    position="center"
+    :close-on-click-modal="true"
+    custom-style="border-radius: 10px; width: 90%; max-width: 400px; max-height: 80vh;"
+    @close="handleClose"
+  >
+    <view class="popup-container">
+      <view class="head-title">
+        <text class="head-title-text">联系人修改</text>
       </view>
 
-      <view class="tab-content">
-        <view v-show="currentTab === 0" class="form-panel">
-          <view class="form-item">
-            <text class="form-label">联系人:</text>
-            <input class="form-input" v-model="formData.unitContact" placeholder="请输入联系人" />
-          </view>
-          <view class="form-item">
-            <text class="form-label">联系电话:</text>
-            <input
-              class="form-input"
-              v-model="formData.unitPhone"
-              placeholder="请输入联系电话"
-              type="number"
-            />
+      <view class="tabs-container">
+        <view class="tab-bar">
+          <view v-for="(tab, index) in tabs" :key="tab.id" class="tab-item" @click="switchTab(index)">
+            <text class="tab-text" :class="{ active: currentTab === index }">{{ tab.value }}</text>
+            <view v-if="currentTab === index" class="tab-line"></view>
           </view>
         </view>
 
-        <view v-show="currentTab === 1" class="form-panel">
-          <view class="form-item">
-            <text class="form-label">接收人:</text>
-            <input
-              class="form-input"
-              v-model="formData.recipient"
-              placeholder="请输入电子报告接收人"
-            />
+        <view class="tab-content">
+          <view v-show="currentTab === 0" class="form-panel">
+            <view class="form-item">
+              <text class="form-label">联系人:</text>
+              <input class="form-input" v-model="formData.unitContact" placeholder="请输入联系人" />
+            </view>
+            <view class="form-item">
+              <text class="form-label">联系电话:</text>
+              <input
+                class="form-input"
+                v-model="formData.unitPhone"
+                placeholder="请输入联系电话"
+                type="number"
+              />
+            </view>
           </view>
-          <view class="form-item">
-            <text class="form-label">接收人电话:</text>
-            <input
-              class="form-input"
-              v-model="formData.recipientPhone"
-              placeholder="请输入接收人联系电话"
-              type="number"
-            />
-          </view>
-        </view>
 
-        <view v-show="currentTab === 2" class="form-panel">
-          <view class="form-item">
-            <text class="form-label">缴费联系人:</text>
-            <input
-              class="form-input"
-              v-model="formData.payerContactName"
-              placeholder="请输入缴费联系人"
-            />
+          <view v-show="currentTab === 1" class="form-panel">
+            <view class="form-item">
+              <text class="form-label">接收人:</text>
+              <input
+                class="form-input"
+                v-model="formData.recipient"
+                placeholder="请输入电子报告接收人"
+              />
+            </view>
+            <view class="form-item">
+              <text class="form-label">接收人电话:</text>
+              <input
+                class="form-input"
+                v-model="formData.recipientPhone"
+                placeholder="请输入接收人联系电话"
+                type="number"
+              />
+            </view>
           </view>
-          <view class="form-item">
-            <text class="form-label">联系人电话:</text>
-            <input
-              class="form-input"
-              v-model="formData.payerContact"
-              placeholder="请输入联系电话"
-              type="number"
-            />
+
+          <view v-show="currentTab === 2" class="form-panel">
+            <view class="form-item">
+              <text class="form-label">缴费联系人:</text>
+              <input
+                class="form-input"
+                v-model="formData.payerContactName"
+                placeholder="请输入缴费联系人"
+              />
+            </view>
+            <view class="form-item">
+              <text class="form-label">联系人电话:</text>
+              <input
+                class="form-input"
+                v-model="formData.payerContact"
+                placeholder="请输入联系电话"
+                type="number"
+              />
+            </view>
           </view>
         </view>
       </view>
-    </view>
 
-    <view class="bottom-btn">
-      <button class="cancel-btn" @click="handleCancel">取消</button>
-      <button class="confirm-btn" @click="handleConfirm">确定</button>
+      <view class="bottom-btn">
+        <button class="cancel-btn" @click="handleCancel">取消</button>
+        <button class="confirm-btn" @click="handleConfirm">确定</button>
+      </view>
     </view>
-  </view>
+  </wd-popup>
 </template>
 
 <script lang="ts" setup>
@@ -107,6 +115,8 @@ const configStore = useConfigStore()
 
 const equipType = configStore.getEquipType()
 
+const showPopup = ref(true)
+
 const tabs = [
   { value: '联系人', id: 'aaa' },
   { value: '电子报告接收人', id: 'bbb' },
@@ -147,7 +157,12 @@ const switchTab = (index: number) => {
 
 const phoneRegex = /^1[3456789]\d{9}$/
 
+const handleClose = () => {
+  emit('hide')
+}
+
 const handleCancel = () => {
+  showPopup.value = false
   emit('hide')
 }
 
@@ -185,6 +200,7 @@ const handleConfirm = async () => {
     })
     if (res?.code === 0) {
       uni.showToast({ title: '修改成功', icon: 'success' })
+      showPopup.value = false
       emit('hide')
       emit('refresh')
     } else {
@@ -201,10 +217,7 @@ const handleConfirm = async () => {
 .popup-container {
   display: flex;
   flex-direction: column;
-  max-height: 70vh;
-  overflow: hidden;
   background-color: #fff;
-  border-radius: 10px;
 }
 
 .head-title {

+ 51 - 44
src/pages/unClaim/components/query/CheckDateCom.vue

@@ -1,11 +1,21 @@
 <template>
   <view class="check-date-box" :style="style">
     <view class="title" :style="textStyle">{{ title }}</view>
-    <view class="date-input" @click="handleClick">
-      <text class="date-text">
-        {{ displayText || '请选择日期范围' }}
-      </text>
-    </view>
+    <wd-datetime-picker
+      class="date-picker"
+      v-model="dateRange"
+      type="date"
+      :min-date="minDate"
+      :max-date="maxDate"
+      :default-value="defaultValue"
+      @confirm="onConfirm"
+    >
+      <view class="date-input">
+        <text :class="['date-text', { 'date-text--placeholder': !displayText }]">
+          {{ displayText || '请选择日期范围' }}
+        </text>
+      </view>
+    </wd-datetime-picker>
   </view>
 </template>
 
@@ -26,49 +36,37 @@ const emit = defineEmits<{
   change: [date: string[], type: string]
 }>()
 
-const rangeStartDate = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))
-const rangeEndDate = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))
-const displayText = ref('')
+const minDate = new Date(new Date().getFullYear() - 10, 0, 1).getTime()
+const maxDate = new Date(new Date().getFullYear() + 10, 11, 31).getTime()
+const defaultValue = [Date.now(), Date.now()]
 
-// 暴露方法
-defineExpose({
-  reset: () => {
-    rangeStartDate.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
-    rangeEndDate.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
-    displayText.value = ''
-  },
-  inputContent: displayText.value ? [rangeStartDate.value, rangeEndDate.value] : '',
-})
-
-// 获取显示的文本
-const getDisplayText = () => {
-  if (displayText.value) return displayText.value
-  return '请选择日期范围'
-}
-
-// 点击选择日期
-const handleClick = () => {
-  const startDatePart = rangeStartDate.value.split(' ')[0]
-  const endDatePart = rangeEndDate.value.split(' ')[0]
+const dateRange = ref<(number | string)[]>([])
 
-  uni.navigateTo({
-    url: `/pages/dateRangePicker/index?startDate=${startDatePart}&endDate=${endDatePart}&type=${props.type}`,
-  })
-}
-
-// 监听日期选择事件
-uni.$on('DateRangeSelected', (data: any) => {
-  if (data.type === props.type) {
-    const startDateTime = `${data.startDate} 00:00:00`
-    const endDateTime = `${data.endDate} 23:59:59`
-
-    rangeStartDate.value = startDateTime
-    rangeEndDate.value = endDateTime
-
-    displayText.value = `${dayjs(data.startDate).format('YYYY-MM-DD')} 至 ${dayjs(data.endDate).format('YYYY-MM-DD')}`
+const displayText = computed(() => {
+  if (!dateRange.value || dateRange.value.length < 2 || !dateRange.value[0] || !dateRange.value[1]) {
+    return ''
+  }
+  const start = dayjs(Number(dateRange.value[0])).format('YYYY-MM-DD')
+  const end = dayjs(Number(dateRange.value[1])).format('YYYY-MM-DD')
+  return `${start} 至 ${end}`
+})
 
+const onConfirm = ({ value }: { value: (number | string)[] }) => {
+  if (value && value.length === 2) {
+    const startDateTime = `${dayjs(Number(value[0])).format('YYYY-MM-DD')} 00:00:00`
+    const endDateTime = `${dayjs(Number(value[1])).format('YYYY-MM-DD')} 23:59:59`
     emit('change', [startDateTime, endDateTime], props.type)
   }
+}
+
+defineExpose({
+  reset: () => {
+    dateRange.value = []
+  },
+  inputContent: computed(() => {
+    if (!dateRange.value || dateRange.value.length < 2) return ''
+    return [dateRange.value[0], dateRange.value[1]]
+  }),
 })
 </script>
 
@@ -88,6 +86,11 @@ uni.$on('DateRangeSelected', (data: any) => {
   text-align: right;
 }
 
+.date-picker {
+  flex: 1;
+  min-width: 0;
+}
+
 .date-input {
   box-sizing: border-box;
   display: flex;
@@ -103,6 +106,10 @@ uni.$on('DateRangeSelected', (data: any) => {
 
 .date-text {
   font-size: 12px;
-  color: rgba(136, 136, 136, 1);
+  color: rgb(51, 51, 51);
+
+  &--placeholder {
+    color: rgba(136, 136, 136, 1);
+  }
 }
 </style>

+ 40 - 40
src/pages/unClaim/components/query/CheckNatureCom.vue

@@ -1,17 +1,23 @@
 <template>
   <view class="check-nature-box">
     <view class="title" :style="textStyle">检验性质:</view>
-    <view class="nature-input" @click="showPicker">
-      <text class="nature-text">{{ selectorChecked || '请选择' }}</text>
-      <image class="arrow-icon" :src="iconMap.ArrowDown" :class="{ 'arrow-rotate': isOpen }" />
-    </view>
+    <wd-picker
+      class="nature-picker"
+      v-model="selectCode"
+      :columns="columns"
+      @confirm="onConfirm"
+    >
+      <view class="nature-input">
+        <text :class="['nature-text', { 'nature-text--placeholder': !displayLabel }]">
+          {{ displayLabel || '请选择' }}
+        </text>
+      </view>
+    </wd-picker>
   </view>
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue'
-import iconMap from '@/utils/imagesMap'
-import { getCheckTypeFromText } from '@/utils/dictMap'
+import { ref, computed } from 'vue'
 
 interface Props {
   type: string
@@ -24,36 +30,32 @@ const emit = defineEmits<{
   change: [text: number, type: string]
 }>()
 
-const isOpen = ref(false)
-const selectorChecked = ref('')
 const selectCode = ref<number | undefined>(undefined)
 
-const itemList = ['定期检验', '年度检查', '超年限检验']
+const columns = [
+  { label: '定期检验', value: 100 },
+  { label: '年度检查', value: 200 },
+  // { label: '超年限检验', value: 300 },
+]
+
+const displayLabel = computed(() => {
+  if (selectCode.value == null) return ''
+  const item = columns.find((c) => c.value === selectCode.value)
+  return item ? item.label : ''
+})
+
+const onConfirm = ({ value }: { value: number }) => {
+  if (value) {
+    emit('change', value, props.type)
+  }
+}
 
-// 暴露方法
 defineExpose({
   reset: () => {
-    selectorChecked.value = ''
     selectCode.value = undefined
   },
-  inputContent: selectCode.value || undefined,
+  inputContent: computed(() => selectCode.value || undefined),
 })
-
-// 显示选择器
-const showPicker = () => {
-  uni.showActionSheet({
-    itemList,
-    success: (res) => {
-      const selected = itemList[res.tapIndex]
-      selectorChecked.value = selected
-      const code = getCheckTypeFromText(selected)
-      if (code) {
-        selectCode.value = code
-        emit('change', code, props.type)
-      }
-    },
-  })
-}
 </script>
 
 <style lang="scss" scoped>
@@ -72,13 +74,17 @@ const showPicker = () => {
   text-align: right;
 }
 
+.nature-picker {
+  flex: 1;
+  min-width: 0;
+}
+
 .nature-input {
   box-sizing: border-box;
   display: flex;
   flex: 1;
   flex-direction: row;
   align-items: center;
-  justify-content: space-between;
   min-width: 0;
   height: 30px;
   min-height: 30px;
@@ -89,16 +95,10 @@ const showPicker = () => {
 
 .nature-text {
   font-size: 12px;
-  color: rgba(136, 136, 136, 1);
-}
-
-.arrow-icon {
-  width: 15px;
-  height: 15px;
-  transition: transform 0.3s;
-}
+  color: rgb(51, 51, 51);
 
-.arrow-rotate {
-  transform: rotate(180deg);
+  &--placeholder {
+    color: rgba(136, 136, 136, 1);
+  }
 }
 </style>

+ 33 - 158
src/pages/unClaim/unClaimList.vue

@@ -24,35 +24,19 @@
 
     <!-- 筛选条件栏 -->
     <view class="filter-bar">
-      <view class="filter-row">
-        <view
-          v-for="(item, index) in rightTypeList"
-          :key="item.id"
-          class="filter-item"
-          @click="handleRightRefresh(item.id)"
-        >
-          <view class="checkbox-wrapper" :style="{ marginLeft: index === 0 ? '0' : '15px' }">
-            <view class="checkbox radio-style">
-              <view class="radio-inner" :class="{ 'radio-checked': rightType === item.id }"></view>
-            </view>
-            <text class="checkbox-text">{{ item.value }}</text>
-          </view>
-        </view>
-      </view>
-
-      <view class="filter-item" @click="handleShowTodayOnly">
-        <view class="checkbox-wrapper">
-          <view class="checkbox square-style" :class="{ checked: showTodayOnly }">
-            <image
-              v-if="showTodayOnly"
-              class="check-icon"
-              :src="iconMap.WhiteCheck"
-              mode="aspectFit"
-            />
-          </view>
-          <text class="checkbox-text">仅看今天</text>
-        </view>
-      </view>
+      <RadioFilterBar
+        v-model="rightType"
+        :options="rightTypeList"
+        type="radio"
+        @change="handleRightRefresh"
+      />
+      <RadioFilterBar
+        v-model="showTodayOnly"
+        :options="todayOnlyOptions"
+        type="checkbox"
+        :margin-left="'15px'"
+        @change="handleShowTodayOnly"
+      />
     </view>
 
     <!-- 列表 -->
@@ -77,37 +61,22 @@
     </scroll-view>
 
     <!-- 修改联系人弹窗 -->
-    <view v-if="showUpdateContactPopup" class="popup-mask" @click="closeUpdateContactPopup">
-      <view class="popup-content" @click.stop>
-        <UpdateContactPopup
-          :popup-data="currentOrderInfo"
-          @hide="closeUpdateContactPopup"
-          @refresh="refreshList"
-        />
-      </view>
-    </view>
-
-    <!-- Tips 弹窗 -->
-    <view v-if="showTipsPopup" class="popup-mask" @click="closeTipsPopup">
-      <view class="popup-content" @click.stop>
-        <TipsPopup
-          :text="tipsPopupData.text"
-          :confirm="tipsPopupData.confirm"
-          @hide="closeTipsPopup"
-        />
-      </view>
-    </view>
+    <UpdateContactPopup
+      v-if="showUpdateContactPopup"
+      :popup-data="currentOrderInfo"
+      @hide="closeUpdateContactPopup"
+      @refresh="refreshList"
+    />
   </view>
 </template>
 
 <script lang="ts" setup>
 import { ref, reactive, onMounted, onUnmounted } from 'vue'
-import iconMap from '@/utils/imagesMap'
 import dayjs from 'dayjs'
 import QueryView from './components/query/QueryView.vue'
 import TaskItem from './components/TaskItem.vue'
 import UpdateContactPopup from './components/UpdateContactPopup.vue'
-import TipsPopup from '@/components/popup/components/TipsPopup.vue'
+import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
 import { useConfigStore } from '@/store/config'
 import { TaskOrderFuncName, requestFunc } from '@/api/ApiRouter/taskOrder'
 import {
@@ -138,15 +107,12 @@ const rightTypeList = [
   { value: '待认领', id: '100' },
   { value: '已认领', id: '400' },
 ]
+const todayOnlyOptions = [{ value: '仅看今天', id: 'today' }]
 const defaultTypeValue = {}
 const itemRefs = reactive<Record<string, any>>({})
 const showUpdateContactPopup = ref(false)
 const currentOrderInfo = ref<any>({})
 
-// 弹窗相关
-const showTipsPopup = ref(false)
-const tipsPopupData = ref<any>({})
-
 const configStore = useConfigStore()
 const equipType = configStore.getEquipType()
 
@@ -219,17 +185,17 @@ const queryAction = () => {
   refreshList()
 }
 
-// 切换仅看今天
-const handleShowTodayOnly = () => {
-  showTodayOnly.value = !showTodayOnly.value
-  params.showTodayOnly = showTodayOnly.value
+// 筛选刷新
+const handleRightRefresh = (value: string | number | boolean) => {
+  rightType.value = value as string
+  params.taskStatus = rightType.value
   refreshList()
 }
 
-// 筛选刷新
-const handleRightRefresh = (id: string) => {
-  rightType.value = id
-  params.taskStatus = id
+// 切换仅看今天
+const handleShowTodayOnly = (value: string | number | boolean) => {
+  showTodayOnly.value = value as boolean
+  params.showTodayOnly = showTodayOnly.value
   refreshList()
 }
 
@@ -324,12 +290,6 @@ const closeUpdateContactPopup = () => {
   currentOrderInfo.value = {}
 }
 
-// 关闭 Tips 弹窗
-const closeTipsPopup = () => {
-  showTipsPopup.value = false
-  tipsPopupData.value = {}
-}
-
 // PDF 详情(告知单/服务单/受理单)
 const handlePdfDetail = (businessType: number, signFilePdf: string, orderId: string) => {
   const businessTypeTitle = businessType === 200 ? '告知单' : '服务单/受理单'
@@ -372,80 +332,6 @@ defineExpose({
   flex-shrink: 0;
 }
 
-.filter-bar {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  justify-content: space-between;
-  padding: 10px 15px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.filter-row {
-  display: flex;
-  flex-direction: row;
-}
-
-.filter-item {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-}
-
-.checkbox-wrapper {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-}
-
-.checkbox {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 15px;
-  height: 15px;
-  margin-right: 6px;
-  background-color: rgb(255, 255, 255);
-  border: 1px solid rgb(187, 187, 187);
-}
-
-.radio-style {
-  border-radius: 7.5px;
-}
-
-.square-style {
-  width: 18px;
-  height: 18px;
-  border-radius: 3px;
-}
-
-.radio-inner {
-  width: 9.5px;
-  height: 9.5px;
-  background-color: transparent;
-  border-radius: 4.75px;
-}
-
-.radio-checked {
-  background-color: rgb(47, 142, 255);
-}
-
-.square-style.checked {
-  background-color: #2f8eff;
-  border-width: 0;
-}
-
-.check-icon {
-  width: 12px;
-  height: 12px;
-}
-
-.checkbox-text {
-  font-size: 14px;
-  color: #333;
-}
-
 .list-scroll {
   flex: 1;
   overflow: hidden;
@@ -469,21 +355,10 @@ defineExpose({
   color: #999;
 }
 
-.popup-mask {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 999;
+.filter-bar {
   display: flex;
-  align-items: flex-end;
-  justify-content: center;
-  background-color: rgba(0, 0, 0, 0.5);
-}
-
-.popup-content {
-  width: 100%;
-  max-width: 500px;
+  justify-content: space-between;
+  flex-shrink: 0;
+  background-color: white;
 }
 </style>

+ 10 - 73
src/pages/workInstructionAudit/list/WorkInstructionAuditList.vue

@@ -16,19 +16,12 @@
   <view class="audit-container">
     <NavBar title="操作指导书批准" />
 
-    <view class="filter-bar">
-      <view
-        v-for="item in rightTypeList"
-        :key="item.id"
-        class="filter-item"
-        @click="handleRightRefresh(item.id)"
-      >
-        <view class="checkbox-wrapper">
-          <view class="checkbox" :class="{ checked: rightType === item.id }"></view>
-          <text class="checkbox-text">{{ item.value }}</text>
-        </view>
-      </view>
-    </view>
+    <RadioFilterBar
+      v-model="rightType"
+      :options="rightTypeList"
+      type="radio"
+      @change="handleRightRefresh"
+    />
 
     <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
       <view v-for="item in listData" :key="item.id" class="item-box">
@@ -50,6 +43,7 @@ import { useUserStore } from '@/store/user'
 import { useConfigStore } from '@/store/config'
 import Item from '@/pages/inspectionPlanAudit/components/Item.vue'
 import NavBar from '@/components/NavBar/NavBar.vue'
+import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
 import { requestFunc, TaskOrderFuncName } from '@/api/ApiRouter/taskOrder'
 
 defineOptions({ name: 'WorkInstructionAuditList' })
@@ -113,9 +107,9 @@ const refreshList = () => {
   fetchList(true)
 }
 
-const handleRightRefresh = (id: string) => {
-  rightType.value = id
-  params.status = id
+const handleRightRefresh = (value: string | number | boolean) => {
+  rightType.value = value as string
+  params.status = rightType.value
   refreshList()
 }
 
@@ -145,63 +139,6 @@ onUnmounted(() => {
   background-color: #f5f5f5;
 }
 
-.navigate-view {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  height: 44px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.navigate-title {
-  font-size: 17px;
-  font-weight: 500;
-  color: #333;
-}
-
-.filter-bar {
-  display: flex;
-  flex-direction: row;
-  padding: 10px 15px;
-  background-color: #fff;
-  border-bottom: 1px solid #eee;
-}
-
-.filter-item {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  margin-right: 15px;
-}
-
-.checkbox-wrapper {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-}
-
-.checkbox {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 18px;
-  height: 18px;
-  margin-right: 6px;
-  border: 1px solid #bbb;
-  border-radius: 100%;
-}
-
-.checkbox.checked {
-  background-color: #2f8eff;
-  border-width: 0;
-}
-
-.checkbox-text {
-  font-size: 14px;
-  color: #333;
-}
-
 .list-scroll {
   flex: 1;
   overflow: hidden;