Browse Source

待约检设备

xuzhancheng 7 hours ago
parent
commit
1640469fa2

+ 10 - 0
yudao-ui-admin-vue3/src/api/system/role/index.ts

@@ -59,3 +59,13 @@ export const exportRole = (params:any) => {
     params
   })
 }
+
+// 根据角色ID获取已分配的用户ID列表
+export const getRoleUserIdList = async (roleId: number): Promise<string[]> => {
+  return await request.get({ url: '/system/user/list-by-role?roleId=' + roleId })
+}
+
+// 批量分配用户角色
+export const assignRoleUsers = async (data: { roleId: string; userIds: string[] }) => {
+  return await request.post({ url: '/system/user/assign-role-batch', data })
+}

+ 4 - 0
yudao-ui-admin-vue3/src/views/pressure/equipmentAppointment/index.api.ts

@@ -32,6 +32,10 @@ export default {
     }
     // return request.put({ url: '/pressure/equip-container/equip-container/contact/batch-update', data })
   },
+  // 管道设备批量更新是否有效
+  updatePipeIsValid: (data: { ids: string[], isEffective: boolean }) => {
+    return request.put({ url: '/pressure2/plan-scheduling/pipe/update-is-valid', data })
+  },
 }
 
 export interface AppointmentConfirmOrderVO {

+ 226 - 93
yudao-ui-admin-vue3/src/views/pressure/equipmentAppointment/index.vue

@@ -3,22 +3,56 @@
     <!-- 搜索表单区域 -->
     <div class="search-form">
       <el-form ref="searchFormRef" :model="searchFormDataTable" inline>
+        <!-- ===== 默认显示 ===== -->
         <!-- 设备类型选择 -->
         <el-form-item label="设备类型">
-          <el-select v-model="searchFormDataTable.equipMainType" placeholder="请选择设备类型" @change="handleEquipTypeChange" style="width: 120px">
+          <el-select v-model="searchFormDataTable.equipMainType" placeholder="请选择设备类型" @change="handleEquipTypeChange"
+            style="width: 80px">
             <el-option label="锅炉" value="boiler" />
             <el-option label="管道" value="pipe" />
           </el-select>
         </el-form-item>
 
+        <!-- 下次检验日期 -->
+        <el-form-item label="下次检验日期">
+          <div style="display: flex; gap: 8px; align-items: center">
+            <el-select v-model="datePickerMode" style="width: 90px" @change="handleDateModeChange">
+              <el-option label="月份" value="month" />
+              <el-option label="日期段" value="date" />
+            </el-select>
+            <!-- 月份模式:单月选择 -->
+            <el-date-picker
+              v-if="datePickerMode === 'month'"
+              v-model="searchFormDataTable.checkDate"
+              type="month"
+              placeholder="请选择月份"
+              format="YYYY-MM"
+              value-format="YYYY-MM"
+              style="width: 240px"
+            />
+            <!-- 日期段模式:日期范围选择 -->
+            <el-date-picker
+              v-else
+              v-model="searchFormDataTable.checkDate"
+              type="daterange"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              format="YYYY-MM-DD"
+              value-format="YYYY-MM-DD"
+              style="width: 240px"
+            />
+          </div>
+        </el-form-item>
+
         <!-- 使用单位 -->
         <el-form-item label="使用单位">
           <el-input v-model="searchFormDataTable.unitName" placeholder="请输入使用单位" clearable />
         </el-form-item>
 
-        <!-- 设备代码/工程号 -->
-        <el-form-item :label="selectedEquipMainType === 'boiler' ? '设备注册代码' : '工程号'">
-          <el-input v-model="searchFormDataTable.equipCode" placeholder="请输入" clearable />
+        <!-- 部门 -->
+        <el-form-item label="部门">
+          <el-input v-model="searchFormDataTable.deptName" placeholder="请输入部门" clearable />
         </el-form-item>
 
         <!-- 区域 -->
@@ -26,26 +60,81 @@
           <AreaSelect v-model="searchFormDataTable.equipDistrict" />
         </el-form-item>
 
-        <!-- 联系电话 -->
-        <el-form-item label="联系电话">
-          <el-input v-model="searchFormDataTable.contactPhone" placeholder="请输入联系电话" clearable />
-        </el-form-item>
+        <!-- ===== 展开显示 ===== -->
+        <template v-if="searchExpanded">
+          <!-- 设备代码/工程号 -->
+          <el-form-item :label="selectedEquipMainType === 'boiler' ? '设备注册代码' : '工程号'">
+            <el-input v-model="searchFormDataTable.equipCode" placeholder="请输入" clearable />
+          </el-form-item>
+
+          <!-- 联系电话 -->
+          <el-form-item label="联系电话">
+            <el-input v-model="searchFormDataTable.contactPhone" placeholder="请输入联系电话" clearable />
+          </el-form-item>
+
+          <!-- 使用证编号 -->
+          <el-form-item label="使用证编号">
+            <el-input v-model="searchFormDataTable.useRegisterNo" placeholder="请输入使用证编号" clearable />
+          </el-form-item>
+
+          <!-- 管道:是否有效 -->
+          <el-form-item v-if="selectedEquipMainType === 'pipe'" label="是否有效">
+            <el-select v-model="searchFormData.isEffective" placeholder="请选择" clearable style="width: 100px"
+              @change="getListPageFn">
+              <el-option label="是" value="是" />
+              <el-option label="否" value="否" />
+            </el-select>
+          </el-form-item>
+        </template>
 
         <!-- 操作按钮 -->
-        <el-form-item>
+        <div class="search-actions">
           <el-button type="primary" @click="getListPageFn">
-            <el-icon><Search /></el-icon>
+            <el-icon>
+              <Search />
+            </el-icon>
             搜索
           </el-button>
           <el-button @click="handleReset">
-            <el-icon><Refresh /></el-icon>
+            <el-icon>
+              <Refresh />
+            </el-icon>
             重置
           </el-button>
-        </el-form-item>
+          <el-button type="text" @click="searchExpanded = !searchExpanded">
+            {{ searchExpanded ? '收起' : '展开' }}
+            <el-icon :style="{ transform: searchExpanded ? 'rotate(180deg)' : '', transition: 'transform 0.3s' }">
+              <ArrowDown />
+            </el-icon>
+          </el-button>
+        </div>
       </el-form>
     </div>
 
     <!-- 工具栏区域 -->
+    <div class="toolbar">
+      <div class="toolbar-left">
+        <el-button type="primary" :disabled="!canBatchAppointment()" @click="handleBatchAppointment">
+          批量约检
+        </el-button>
+        <el-button type="primary" :disabled="selectedRows.length === 0" @click="handleBatchEditContact">
+          修改约检联系人
+        </el-button>
+        <el-button type="primary" :disabled="selectedRows.length === 0" @click="handleBatchRemark">
+          批量添加备注
+        </el-button>
+        <el-button v-if="selectedEquipMainType === 'pipe'" type="warning" :disabled="selectedRows.length === 0"
+          @click="handleBatchIsValid">
+          是否有效
+        </el-button>
+        <el-button type="primary" @click="handleExportFn">
+          <el-icon>
+            <Download />
+          </el-icon>
+          导出Excel
+        </el-button>
+      </div>
+    </div>
     <div class="toolbar">
       <div class="toolbar-left">
         <el-radio-group v-model="checkType" @change="handleQuery">
@@ -67,21 +156,6 @@
           <el-radio-button label="都显示" value="flag" />
         </el-radio-group>
       </div>
-      <div class="toolbar-right">
-        <el-button type="primary" :disabled="!canBatchAppointment()" @click="handleBatchAppointment">
-          批量约检
-        </el-button>
-        <el-button type="primary" :disabled="selectedRows.length === 0" @click="handleBatchEditContact">
-          修改约检联系人
-        </el-button>
-        <el-button type="primary" :disabled="selectedRows.length === 0" @click="handleBatchRemark">
-          批量添加备注
-        </el-button>
-        <el-button type="primary" @click="handleExportFn">
-          <el-icon><Download /></el-icon>
-          导出Excel
-        </el-button>
-      </div>
     </div>
 
     <!-- 设备类型筛选区域 -->
@@ -90,9 +164,7 @@
       <el-checkbox-group v-model="searchFormData.equipTypeList" @change="getListPageFn">
         <el-checkbox
           v-for="dict in (selectedEquipMainType === 'boiler' ? getStrDictOptions(DICT_TYPE.SYSTEM_EQUIP_BOILER_TYPE) : getStrDictOptions(DICT_TYPE.PIPE_TYPE))"
-          :key="dict.value"
-          :value="dict.value"
-        >
+          :key="dict.value" :value="dict.value">
           {{ dict.label }}
         </el-checkbox>
       </el-checkbox-group>
@@ -100,14 +172,8 @@
 
     <!-- 表格区域 -->
     <div class="table-container">
-      <el-table
-        ref="tableRef"
-        :data="tableData"
-        v-loading="loading"
-        border
-        style="width: 100%"
-        @selection-change="handleSelectionChange"
-      >
+      <el-table ref="tableRef" :data="tableData" v-loading="loading" border style="width: 100%"
+        @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" />
         <el-table-column label="操作" width="120" fixed="left">
           <template #default="scope">
@@ -120,6 +186,15 @@
           </template>
         </el-table-column>
 
+        <!-- 管道:是否有效列 -->
+        <el-table-column v-if="selectedEquipMainType === 'pipe'" label="是否有效" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEffective === '是' ? 'success' : 'danger'">
+              {{ scope.row.isEffective || '否' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+
         <!-- 使用单位 -->
         <el-table-column label="使用单位" prop="unitName" min-width="150" show-overflow-tooltip />
 
@@ -162,12 +237,8 @@
         <!-- 下次检验日期(带颜色和拒检提示) -->
         <el-table-column label="下次检验日期" min-width="140" show-overflow-tooltip>
           <template #default="scope">
-            <el-popover
-              v-if="scope.row.isRefused && getRefuseTip(scope.row).length > 0"
-              placement="top"
-              :width="250"
-              trigger="hover"
-            >
+            <el-popover v-if="scope.row.isRefused && getRefuseTip(scope.row).length > 0" placement="top" :width="250"
+              trigger="hover">
               <template #reference>
                 <div :style="getCellStyle(scope.row)">
                   <span>{{ scope.row.nextCheckDate || '-' }}</span>
@@ -178,12 +249,7 @@
                 <div v-for="(line, idx) in getRefuseTip(scope.row)" :key="idx">{{ line }}</div>
               </template>
             </el-popover>
-            <el-popover
-              v-else-if="scope.row.hasPendingAppointment"
-              placement="top"
-              :width="200"
-              trigger="hover"
-            >
+            <el-popover v-else-if="scope.row.hasPendingAppointment" placement="top" :width="200" trigger="hover">
               <template #reference>
                 <div :style="getCellStyle(scope.row)">
                   <span>{{ scope.row.nextCheckDate || '-' }}</span>
@@ -195,12 +261,7 @@
                 <div>检验时间:{{ scope.row.appointmentDate || '-' }}</div>
               </template>
             </el-popover>
-            <el-popover
-              v-else-if="isRowScheduled(scope.row)"
-              placement="top"
-              :width="200"
-              trigger="hover"
-            >
+            <el-popover v-else-if="isRowScheduled(scope.row)" placement="top" :width="200" trigger="hover">
               <template #reference>
                 <div :style="getCellStyle(scope.row)">
                   <span>{{ scope.row.nextCheckDate || '-' }}</span>
@@ -226,15 +287,9 @@
 
     <!-- 分页区域 -->
     <div class="pagination-container">
-      <el-pagination
-        v-model:current-page="pageNo"
-        v-model:page-size="pageSize"
-        :page-sizes="[10,20,30, 50, 100]"
-        :total="total"
-        layout="total, sizes, prev, pager, next, jumper"
-        @size-change="handleSizeChange"
-        @current-change="handleCurrentChange"
-      />
+      <el-pagination v-model:current-page="pageNo" v-model:page-size="pageSize" :page-sizes="[10, 20, 30, 50, 100]"
+        :total="total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
+        @current-change="handleCurrentChange" />
     </div>
   </div>
 
@@ -244,23 +299,13 @@
   <EquipPipeForm ref="equipPipeFormRef" />
 
   <!-- 备注弹窗 -->
-  <el-dialog
-    v-model="remarkDialogVisible"
-    :title="Array.isArray(currentRemarkRow) ? '批量添加备注' : '备注'"
-    width="500px"
-    :close-on-click-modal="false"
-    :close-on-press-escape="false"
-  >
+  <el-dialog v-model="remarkDialogVisible" :title="Array.isArray(currentRemarkRow) ? '批量添加备注' : '备注'" width="500px"
+    :close-on-click-modal="false" :close-on-press-escape="false">
     <el-form :model="remarkForm" label-width="80px">
       <el-form-item label="备注内容">
-        <el-input
-          v-model="remarkForm.pendingInspectionRemark"
-          type="textarea"
-          :rows="4"
+        <el-input v-model="remarkForm.pendingInspectionRemark" type="textarea" :rows="4"
           :placeholder="Array.isArray(currentRemarkRow) ? `已选择 ${currentRemarkRow.length} 台设备,请输入备注内容` : '请输入备注内容'"
-          maxlength="300"
-          show-word-limit
-        />
+          maxlength="300" show-word-limit />
       </el-form-item>
     </el-form>
     <template #footer>
@@ -275,12 +320,31 @@
 
   <!-- 批量修改约检联系人弹窗 -->
   <BatchEditForm ref="batchEditFormRef" @success="handleBatchEditFormSuccess" />
+
+  <!-- 管道:是否有效弹窗 -->
+  <el-dialog v-model="isValidDialogVisible" title="是否有效" width="400px" :close-on-click-modal="false"
+    :close-on-press-escape="false">
+    <el-form :model="isValidForm" label-width="100px">
+      <el-form-item label="是否有效">
+        <el-radio-group v-model="isValidForm.isEffective">
+          <el-radio :value="true">是</el-radio>
+          <el-radio :value="false">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button :loading="isValidDialogLoading" @click="handleIsValidClose">取消</el-button>
+      <el-button type="primary" :loading="isValidDialogLoading" @click="handleIsValidConfirm">
+        确定
+      </el-button>
+    </template>
+  </el-dialog>
 </template>
 
 <script lang="ts" setup name="EquipmentAppointment">
 import { ref, onMounted, onUnmounted, computed, nextTick, watch } from 'vue'
 import { ElMessage } from 'element-plus'
-import { Search, Refresh, Download } from '@element-plus/icons-vue'
+import { Search, Refresh, Download, ArrowDown } from '@element-plus/icons-vue'
 import EquipContainerForm from '@/components/EquipContainerForm/index.vue'
 import EquipBoilerForm from '@/components/EquipBoilerForm/index.vue'
 import EquipPipeForm from '@/components/EquipPipeForm/index.vue'
@@ -309,10 +373,9 @@ const router = useRouter()
 // 设备类型
 const selectedEquipMainType = ref('boiler')
 
-// 初始化默认日期值
+// 初始化默认日期值(当前月份)
 const getDefaultDate = () => {
-  const date = dayjs()
-  return ['2000-01-01', date.endOf('month').format('YYYY-MM-DD')]
+  return dayjs().format('YYYY-MM')
 }
 
 // 搜索表单数据
@@ -323,7 +386,9 @@ const searchFormDataTable = ref({
   unitName: '',
   equipCode: '',
   equipDistrict: '',
-  contactPhone: ''
+  contactPhone: '',
+  deptName: '',
+  useRegisterNo: ''
 })
 
 // 保存用户输入的检验日期
@@ -335,7 +400,8 @@ const searchFormData = ref({
   showNoCheckDate: false,
   showNoDistrict: true,
   isRefused: 'flag',
-  equipTypeList: []
+  equipTypeList: [],
+  isEffective: undefined as string | undefined
 })
 
 const tableRef = ref()
@@ -465,8 +531,8 @@ const getCellStyle = (row: Record<string, any>) => {
 
 const isRowScheduled = (row: Record<string, any>) => {
   return (row.checkType == 200 && row.yearSchedulingPlanDate) ||
-         (row.checkType == 100 && row.schedulingPlanDate) ||
-         (row.checkType == 300 && row.expiredSchedulingPlanDate)
+    (row.checkType == 100 && row.schedulingPlanDate) ||
+    (row.checkType == 300 && row.expiredSchedulingPlanDate)
 }
 
 const getScheduledDate = (row: Record<string, any>) => {
@@ -488,6 +554,7 @@ const canAppointment = (row: Record<string, any>) => {
 const handleEquipTypeChange = (value: string) => {
   selectedEquipMainType.value = value
   searchFormData.value.equipTypeList = []
+  searchFormData.value.isEffective = undefined
   checkType.value = 100
   pageNo.value = 1
   getListPageFn()
@@ -511,7 +578,12 @@ const buildCommonRequestParams = (baseParams: any) => {
   }
 
   if (data?.checkDate) {
-    if (Array.isArray(data.checkDate) && data.checkDate.length === 2) {
+    // 月份模式:单月字符串 "YYYY-MM",转为该月第一天和最后一天
+    if (typeof data.checkDate === 'string' && data.checkDate.length === 7) {
+      data.checkDateStart = `${data.checkDate}-01`
+      data.checkDateEnd = dayjs(data.checkDate).endOf('month').format('YYYY-MM-DD')
+    } else if (Array.isArray(data.checkDate) && data.checkDate.length === 2) {
+      // 日期段模式:["YYYY-MM-DD", "YYYY-MM-DD"],直接使用
       data.checkDateStart = data.checkDate[0]
       data.checkDateEnd = data.checkDate[1]
     }
@@ -524,6 +596,11 @@ const buildCommonRequestParams = (baseParams: any) => {
     data.isRefused = data.isRefused === 'true'
   }
 
+  // 是否有效仅管道查询时传递
+  if (selectedEquipMainType.value !== 'pipe') {
+    delete data.isEffective
+  }
+
   return data
 }
 
@@ -578,15 +655,18 @@ const handleReset = () => {
   isResetting.value = true
   searchFormData.value.showNoDistrict = true
   searchFormData.value.equipTypeList = []
+  searchFormData.value.isEffective = undefined
   pageNo.value = 1
   searchFormDataTable.value = {
     // deptId: userStore?.user?.deptId,
-    checkDate: [...savedCheckDate.value],
+    checkDate: savedCheckDate.value,
     equipMainType: selectedEquipMainType.value,
     unitName: '',
     equipCode: '',
     equipDistrict: '',
-    contactPhone: ''
+    contactPhone: '',
+    deptName: '',
+    useRegisterNo: ''
   }
   getListPageFn()
 }
@@ -728,6 +808,41 @@ const handleBatchEditFormSuccess = () => {
   getListPageFn()
 }
 
+// 管道:是否有效弹窗
+const isValidDialogVisible = ref(false)
+const isValidDialogLoading = ref(false)
+const isValidForm = ref({
+  isEffective: true as boolean
+})
+
+const handleBatchIsValid = () => {
+  if (selectedRows.value.length === 0) {
+    ElMessage.warning('请先选择管道设备')
+    return
+  }
+  isValidForm.value.isEffective = true
+  isValidDialogVisible.value = true
+}
+
+const handleIsValidConfirm = async () => {
+  isValidDialogLoading.value = true
+  try {
+    const ids = selectedRows.value.map((row: any) => row.id)
+    await FetchApis.updatePipeIsValid({ ids, isEffective: isValidForm.value.isEffective })
+    ElMessage.success('更新成功')
+    isValidDialogVisible.value = false
+    getListPageFn()
+  } catch {
+    ElMessage.error('更新失败')
+  } finally {
+    isValidDialogLoading.value = false
+  }
+}
+
+const handleIsValidClose = () => {
+  isValidDialogVisible.value = false
+}
+
 // 备注弹窗
 const openRemarkDialog = (row: Record<string, any>) => {
   currentRemarkRow.value = row
@@ -809,13 +924,24 @@ const handleQuery = () => {
 
 const selectedRows = ref([])
 const checkType = ref(100)
+const searchExpanded = ref(false)
+const datePickerMode = ref<'month' | 'date'>('month')
+
+// 日期模式切换:按模式重置默认值
+const handleDateModeChange = () => {
+  if (datePickerMode.value === 'month') {
+    searchFormDataTable.value.checkDate = dayjs().format('YYYY-MM')
+  } else {
+    searchFormDataTable.value.checkDate = ['2000-01-01', dayjs().format('YYYY-MM-DD')]
+  }
+}
 
 // 监听搜索表单 checkDate 变化
 watch(
   () => searchFormDataTable.value.checkDate,
   (newVal) => {
     if (isResetting.value) return
-    if (newVal && Array.isArray(newVal) && newVal.length === 2) {
+    if (newVal) {
       savedCheckDate.value = newVal
     }
   },
@@ -881,6 +1007,7 @@ onMounted(() => {
     searchFormData.value.isRefused = String(query.isRefused)
   }
   if (query.checkDateStart !== undefined && query.checkDateEnd !== undefined) {
+    datePickerMode.value = 'date' // 路由带日期段时切换到日期段模式
     searchFormDataTable.value.checkDate = [String(query.checkDateStart), String(query.checkDateEnd)]
     savedCheckDate.value = [String(query.checkDateStart), String(query.checkDateEnd)]
   }
@@ -913,14 +1040,20 @@ onUnmounted(() => {
   background-color: #f5f7fa;
   border-radius: 4px;
   margin-bottom: 16px;
+
+  .search-actions {
+    margin-left: auto;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
 }
 
 .toolbar {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  padding: 12px 0;
-  margin-bottom: 16px;
+  padding: 6px 0;
 
   .toolbar-left {
     display: flex;