Quellcode durchsuchen

Merge remote-tracking branch 'origin/master'

lipenghui vor 1 Monat
Ursprung
Commit
0571872390

+ 56 - 46
src/api/pms/iotprojecttaskschedule/index.ts

@@ -1,46 +1,56 @@
-import request from '@/config/axios'
-
-// 项目任务时间表/施工进度 VO
-export interface IotProjectTaskScheduleVO {
-  id: number // 主键id
-  projectId: number // 项目id
-  taskId: number // 任务id
-  status: number // 施工状态(工作量开始/动迁/准备/施工)
-  description: string // 施工阶段描述
-  startTime: Date // 状态起始时间
-  endTime: Date // 状态结束时间
-  remark: string // 备注
-}
-
-// 项目任务时间表/施工进度 API
-export const IotProjectTaskScheduleApi = {
-  // 查询项目任务时间表/施工进度分页
-  getIotProjectTaskSchedulePage: async (params: any) => {
-    return await request.get({ url: `/rq/iot-project-task-schedule/page`, params })
-  },
-
-  // 查询项目任务时间表/施工进度详情
-  getIotProjectTaskSchedule: async (id: number) => {
-    return await request.get({ url: `/rq/iot-project-task-schedule/get?id=` + id })
-  },
-
-  // 新增项目任务时间表/施工进度
-  createIotProjectTaskSchedule: async (data: IotProjectTaskScheduleVO) => {
-    return await request.post({ url: `/rq/iot-project-task-schedule/create`, data })
-  },
-
-  // 修改项目任务时间表/施工进度
-  updateIotProjectTaskSchedule: async (data: IotProjectTaskScheduleVO) => {
-    return await request.put({ url: `/rq/iot-project-task-schedule/update`, data })
-  },
-
-  // 删除项目任务时间表/施工进度
-  deleteIotProjectTaskSchedule: async (id: number) => {
-    return await request.delete({ url: `/rq/iot-project-task-schedule/delete?id=` + id })
-  },
-
-  // 导出项目任务时间表/施工进度 Excel
-  exportIotProjectTaskSchedule: async (params) => {
-    return await request.download({ url: `/rq/iot-project-task-schedule/export-excel`, params })
-  },
-}
+import request from '@/config/axios'
+
+// 项目任务时间表/施工进度 VO
+export interface IotProjectTaskScheduleVO {
+  id: number // 主键id
+  projectId: number // 项目id
+  taskId: number // 任务id
+  status: number // 施工状态(工作量开始/动迁/准备/施工)
+  description: string // 施工阶段描述
+  startTime: Date // 状态起始时间
+  endTime: Date // 状态结束时间
+  remark: string // 备注
+}
+
+// 项目任务时间表/施工进度 API
+export const IotProjectTaskScheduleApi = {
+  // 查询项目任务时间表/施工进度分页
+  getIotProjectTaskSchedulePage: async (params: any) => {
+    return await request.get({ url: `/rq/iot-project-task-schedule/page`, params })
+  },
+
+  // 查询项目任务时间表/施工进度列表
+  getIotProjectTaskSchedules: async (params: any) => {
+    return await request.get({ url: `/rq/iot-project-task-schedule/list`, params })
+  },
+
+  // 查询项目任务时间表/施工进度详情
+  getIotProjectTaskSchedule: async (id: number) => {
+    return await request.get({ url: `/rq/iot-project-task-schedule/get?id=` + id })
+  },
+
+  // 新增项目任务时间表/施工进度
+  createIotProjectTaskSchedule: async (data: IotProjectTaskScheduleVO) => {
+    return await request.post({ url: `/rq/iot-project-task-schedule/create`, data })
+  },
+
+  // 保存项目日报 任务进度表
+  saveTaskSchedule: async (data: any) => {
+    return await request.post({ url: `/rq/iot-project-task-schedule/saveTaskSchedule`, data })
+  },
+
+  // 修改项目任务时间表/施工进度
+  updateIotProjectTaskSchedule: async (data: IotProjectTaskScheduleVO) => {
+    return await request.put({ url: `/rq/iot-project-task-schedule/update`, data })
+  },
+
+  // 删除项目任务时间表/施工进度
+  deleteIotProjectTaskSchedule: async (id: number) => {
+    return await request.delete({ url: `/rq/iot-project-task-schedule/delete?id=` + id })
+  },
+
+  // 导出项目任务时间表/施工进度 Excel
+  exportIotProjectTaskSchedule: async (params) => {
+    return await request.download({ url: `/rq/iot-project-task-schedule/export-excel`, params })
+  },
+}

+ 10 - 0
src/api/system/dept/index.ts

@@ -20,6 +20,16 @@ export const getSimpleDeptList = async (): Promise<DeptVO[]> => {
   return await request.get({ url: '/system/dept/simple-list' })
 }
 
+// 查询当前用户所属的公司级部门列表 项目 日报
+export const companyLevelDepts = async (): Promise<DeptVO[]> => {
+  return await request.get({ url: '/system/dept/companyLevelDepts' })
+}
+
+// 获取公司层级的部门 及所有子部门
+export const companyLevelChildrenDepts = async (): Promise<DeptVO[]> => {
+  return await request.get({ url: '/system/dept/companyLevelChildrenDepts' })
+}
+
 // 查询部门列表
 export const getDeptPage = async (params: PageParam) => {
   return await request.get({ url: '/system/dept/list', params })

+ 40 - 197
src/views/pms/iotprojectinfo/IotProjectInfoForm.vue

@@ -76,196 +76,34 @@
           </el-form-item>
         </el-col>
       </el-row>
-<!--      <el-row>
+
+      <el-row>
         <el-col :span="12">
-          <el-form-item label="施工地点" prop="location">
-            <el-input v-model="formData.location" placeholder="请输入施工地点" />
+          <el-form-item :label="t('iotDevice.company')" prop="deptId">
+            <el-tree-select
+              :disabled="isDeptDisabled"
+              v-model="formData.deptId"
+              :data="deptList"
+              :props="defaultProps"
+              check-strictly
+              node-key="id"
+              filterable
+              placeholder="请选择所在部门"
+            />
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="施工工艺" prop="technique">
-            <el-input v-model="formData.technique" placeholder="请输入施工工艺" />
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
           </el-form-item>
         </el-col>
-      </el-row>-->
-      <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
-      </el-form-item>
+      </el-row>
+
     </el-form>
   </ContentWrap>
-<!--  <ContentWrap>
-    <el-form>
-      <el-button
-        type="primary"
-        plain
-        @click="openForm('create')"
-        v-hasPermi="['rq:iot-project-info:create']"
-      >
-        <Icon icon="ep:plus" class="mr-5px" />任务拆分
-      </el-button>
-    </el-form>
-    <el-table v-loading="loading" :data="taskList" :stripe="true" :show-overflow-tooltip="true">
-      &lt;!&ndash; 添加序号列 &ndash;&gt;
-      <el-table-column
-        type="index"
-        label="序号"
-        width="60"
-        align="center"
-      />
-      <el-table-column label="井号" align="center" prop="wellName" />
-      <el-table-column label="井型/井别" align="center" prop="wellType" />
-      <el-table-column label="施工地点" align="center" prop="location" />
-      <el-table-column label="施工工艺" align="center" prop="technique" />
-      <el-table-column label="设计工作量" align="center" prop="workloadDesign" />
-      <el-table-column label="所属队伍" align="center" prop="deptList" />
-      <el-table-column label="操作" align="center" min-width="120px">
-        <template #default="scope">
-          <div style="display: flex; justify-content: center; align-items: center; width: 100%">
-            &lt;!&ndash; 新增配置按钮 &ndash;&gt;
-            <div style="margin-left: 12px">
-              <el-button
-                link
-                type="primary"
-                @click="openConfigDialog(scope.row)"
-              >
-                推迟保养
-              </el-button>
-            </div>
-            <div style="margin-left: 12px">
-              <el-button
-                link
-                type="primary"
-                @click="openMaterialForm(scope.row)"
-              >
-                选择物料
-              </el-button>
-            </div>
-            <div style="margin-left: 12px">
-              <el-button
-                link
-                type="primary"
-                @click="handleView(scope.row.bomNodeId)"
-              >
-                物料详情
-              </el-button>
-            </div>
-          </div>
-        </template>
-      </el-table-column>
-    </el-table>
-  </ContentWrap>-->
 
   <CustomerList ref="customerZzFormRef" @choose="customerZzChoose" />
-<!--  <IotProjectTaskForm ref="formRef1" @success="getList" />-->
-<!--  <ContentWrap>
-    <div class="content">
-      <div class="toolbar">
-        <div class="actions">
-          <el-button type="primary" @click="addNewRow" icon="plus" >
-            新增行
-          </el-button>
-          <el-button type="success" @click="saveAll" :disabled="editingRowsCount === 0" icon="check">
-            保存所有更改
-          </el-button>
-        </div>
-      </div>
-
-      <div class="table-container">
-        <el-table :data="tableData" :row-class-name="rowClassName" empty-text="暂无数据">
-&lt;!&ndash;          <el-table-column prop="id" label="ID" width="80">
-            <template #default="{ row }">
-              <span v-if="!row.editing">{{ row.id }}</span>
-              <el-input v-else v-model="row.editData.id" disabled class="edit-input" />
-            </template>
-          </el-table-column>&ndash;&gt;
-
-          <el-table-column prop="wellName" label="井号">
-            <template #default="{ row }">
-              <span v-if="!row.editing">{{ row.wellName }}</span>
-              <div v-else>
-                <el-input v-model="row.editData.wellName" class="edit-input" placeholder="请输入井号" />
-                <div v-if="row.errors.wellName" class="error-message">{{ row.errors.wellName }}</div>
-              </div>
-            </template>
-          </el-table-column>
-
-          <el-table-column prop="wellType" label="井型/井别">
-            <template #default="{ row }">
-              <span v-if="!row.editing">{{ row.wellType }}</span>
-              <div v-else>
-                <el-input v-model="row.editData.wellType" class="edit-input" placeholder="请输入井型/井别" />
-                <div v-if="row.errors.wellType" class="error-message">{{ row.errors.wellType }}</div>
-              </div>
-            </template>
-          </el-table-column>
-
-          <el-table-column prop="location" label="施工地点" >
-            <template #default="{ row }">
-              <span v-if="!row.editing">{{ row.location }}</span>
-              <div v-else>
-                <el-input v-model="row.editData.location" class="edit-input" placeholder="请输入施工地点" />
-                <div v-if="row.errors.location" class="error-message">{{ row.errors.location }}</div>
-              </div>
-            </template>
-          </el-table-column>
-
-          <el-table-column prop="technique" label="施工工艺" >
-            <template #default="{ row }">
-              <span v-if="!row.editing">{{ row.technique }}</span>
-              <div v-else>
-                <el-input v-model="row.editData.technique" class="edit-input" placeholder="请输入施工工艺" />
-                <div v-if="row.errors.technique" class="error-message">{{ row.errors.technique }}</div>
-              </div>
-            </template>
-          </el-table-column>
-
-          <el-table-column prop="workloadDesign" label="设计工作量">
-            <template #default="{ row }">
-              <span v-if="!row.editing">{{ row.workloadDesign }}</span>
-              <div v-else>
-                <el-input v-model="row.editData.workloadDesign" class="edit-input" placeholder="请输入设计工作量" />
-                <div v-if="row.errors.workloadDesign" class="error-message">{{ row.errors.workloadDesign }}</div>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column prop="deptIds" label="所属队伍" >
-            <template #default="{ row }">
-              <span v-if="!row.editing">
-                {{ getDeptNames(row.deptIds) }}
-              </span>
-              <div v-else>
-                <el-tree-select
-                  multiple
-                  v-model="row.editData.deptIds"
-                  :data="deptList"
-                  :props="defaultProps"
-                  check-strictly
-                  node-key="id"
-                  filterable
-                  placeholder="请选择所在部门"
-                  clearable
-                />
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="操作" width="200" fixed="right">
-            <template #default="{ row, $index }">
-              <div class="action-cell">
-                <template v-if="!row.editing">
-                  <el-button size="small" type="primary" @click="editRow(row)" icon="edit">编辑</el-button>
-                  <el-button size="small" type="danger" @click="deleteRow($index)" icon="delete">删除</el-button>
-                </template>
-                <template v-else>
-                  <el-button size="small" type="success" @click="saveRow(row)" icon="check">保存</el-button>
-                  <el-button size="small" @click="cancelEdit(row)" icon="close">取消</el-button>
-                </template>
-              </div>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-    </div>
-  </ContentWrap>-->
+
   <ContentWrap>
     <el-form style="float: right">
       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
@@ -302,7 +140,7 @@ const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const loading = ref(true) // 列表的加载中
 const formData = ref({
   id: undefined,
-  deptId: useUserStore().getUser.deptId,
+  deptId: undefined,
   deptName: undefined,
   contractName: undefined,
   contractCode: undefined,
@@ -373,6 +211,11 @@ const getDeptNames = (deptIds) => {
   return names.join(', ');
 };
 
+// 计算属性:判断部门选择框是否应该禁用
+const isDeptDisabled = computed(() => {
+  return formType.value === 'update' || deptList.value.length === 1;
+});
+
 const tableData = ref([
   {
     id: 1,
@@ -392,9 +235,6 @@ const tableData = ref([
 let deptInfo: any[] = "";
 /** 打开弹窗 */
 const open = async () => {
- /* dialogVisible.value = true
-  dialogTitle.value = t('action.' + type)
-  formType.value = type*/
   resetForm()
   // 修改时,设置数据
   if (id) {
@@ -402,20 +242,16 @@ const open = async () => {
     formLoading.value = true
     try {
       formData.value = await IotProjectInfoApi.getIotProjectInfo(id)
-      /*queryParams.projectId = id;
-      const data = await IotProjectTaskApi.getIotProjectTaskPage(queryParams);
-      tableData.value = data.list
-      tableData.value.forEach(item=>{
-        item.deptIds = [167,168];
-        item.editData={};
-        item.originalData={};
-        item.errors={};
-      })*/
+
     } finally {
       formLoading.value = false
     }
-  }else{
+  } else {
     formType.value = 'create';
+    // 如果只有一个部门,则自动选中
+    if (deptList.value.length === 1) {
+      formData.value.deptId = deptList.value[0].id;
+    }
   }
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
@@ -429,7 +265,7 @@ const submitForm = async () => {
   // 提交请求
   formLoading.value = true
   try {
-    formData.value.deptId = useUserStore().getUser.deptId;
+    // formData.value.deptId = useUserStore().getUser.deptId;
     const data = {
       projectData: formData.value as unknown as IotProjectInfoVO,
       //taskList:tableData.value
@@ -471,7 +307,15 @@ const resetForm = () => {
   formRef.value?.resetFields()
 }
 onMounted(async () => {
-  deptList.value = handleTree(await DeptApi.getSimpleDeptList())
+  // deptList.value = handleTree(await DeptApi.getSimpleDeptList())
+  // 查询当前登录人所属的 公司级部门 如果部门列表只有一个值 默认选中
+  deptList.value = await DeptApi.companyLevelDepts()
+
+  // 如果只有一个部门,则自动选中
+  if (deptList.value.length === 1) {
+    formData.value.deptId = deptList.value[0].id;
+  }
+
   open();
 })
 
@@ -644,5 +488,4 @@ const deleteRow = (index) => {
   ElMessage.success('行已删除');
 };
 
-
 </script>

+ 42 - 7
src/views/pms/iotprojecttask/IotProjectTaskForm.vue

@@ -7,7 +7,6 @@
       label-width="100px"
       v-loading="formLoading"
     >
-
       <el-row>
         <el-col :span="12">
           <el-form-item label="合同名称" prop="contractName">
@@ -159,7 +158,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column prop="deptIds" label="所属队伍" >
+          <el-table-column prop="deptIds" label="施工队伍" >
             <template #default="{ row }">
               <span v-if="!row.editing">
                 {{ getDeptNames(row.deptIds) }}
@@ -173,7 +172,27 @@
                   check-strictly
                   node-key="id"
                   filterable
-                  placeholder="请选择所在部门"
+                  placeholder="请选择施工队伍"
+                  clearable
+                />
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="deviceIds" label="施工设备" >
+            <template #default="{ row }">
+              <span v-if="!row.editing">
+                {{ getDeviceNames(row.deviceIds) }}
+              </span>
+              <div v-else>
+                <el-tree-select
+                  multiple
+                  v-model="row.editData.deviceIds"
+                  :data="deviceList"
+                  :props="defaultProps"
+                  check-strictly
+                  node-key="id"
+                  filterable
+                  placeholder="请选择施工设备"
                   clearable
                 />
               </div>
@@ -214,18 +233,20 @@
   </ContentWrap>
 </template>
 <script setup lang="ts">
+
 import { IotProjectInfoApi, IotProjectInfoVO } from '@/api/pms/iotprojectinfo'
 import {defaultProps,handleTree} from "@/utils/tree";
 import * as DeptApi from "@/api/system/dept";
 import CustomerList from '@/views/pms/device/CustomerList.vue'
 import {ref, reactive, computed, onMounted} from "vue";
-/** 项目信息 表单 */
-defineOptions({ name: 'IotProjectTaskInfo' })
-const { params, name } = useRoute() // 查询参数
 import {useUserStore} from "@/store/modules/user";
 import {IotProjectTaskApi, IotProjectTaskVO} from "@/api/pms/iotprojecttask";
 import {ElMessageBox, ElMessage} from "element-plus";
 import {useTagsViewStore} from "@/store/modules/tagsView";
+import {companyLevelChildrenDepts} from "@/api/system/dept";
+import {IotDeviceVO} from "@/api/pms/device";
+
+const { params, name } = useRoute() // 查询参数
 const id = params.id
 const projectId = params.projectId
 const { delView } = useTagsViewStore() // 视图操作
@@ -233,6 +254,7 @@ const { currentRoute, push } = useRouter()
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 const deptList = ref<Tree[]>([]) // 树形结构
+const deviceList = ref<IotDeviceVO[]>([]) // 设备列表
 const dialogVisible = ref(true) // 弹窗的是否展示
 const dialogTitle = ref('') // 弹窗的标题
 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
@@ -240,6 +262,10 @@ const taskList = ref<IotProjectTaskVO[]>([]) // 列表的数据
 const projectList = ref<IotProjectInfoVO[]>([])
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const loading = ref(true) // 列表的加载中
+
+/** 项目信息 表单 */
+defineOptions({ name: 'IotProjectTaskInfo' })
+
 const formData = ref({
   id: undefined,
   contractId: undefined,
@@ -258,6 +284,7 @@ const formData = ref({
   userName: undefined,
   userId: undefined,
 })
+
 const close = () => {
   delView(unref(currentRoute))
   push({ name: 'IotProjectTask', params:{}})
@@ -320,6 +347,11 @@ const getDeptNames = (deptIds) => {
   return names.join(', ');
 };
 
+// 根据设备ID集合获取设备名称
+const getDeviceNames = (deviceIds) => {
+  return '';
+};
+
 const tableData = ref([
   {
     id: 1,
@@ -365,6 +397,7 @@ const open = async () => {
     await autoSelectContract(projectId);
   }
 }
+
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
 /** 自动选择合同 */
@@ -450,7 +483,9 @@ const resetForm = () => {
   formRef.value?.resetFields()
 }
 onMounted(async () => {
-  deptList.value = handleTree(await DeptApi.getSimpleDeptList())
+  // deptList.value = handleTree(await DeptApi.getSimpleDeptList())
+  // 查询当前登录人所属公司下的所有部门
+  deptList.value = handleTree(await DeptApi.companyLevelChildrenDepts())
   let deptId = useUserStore().getUser.deptId
   projectList.value = await IotProjectInfoApi.getIotProjectInfoUser(deptId);
   open();

+ 170 - 2
src/views/pms/iotprojecttask/index.vue

@@ -102,9 +102,18 @@
         :formatter="dateFormatter"
         width="180px"
       />
-      <el-table-column label="备注" align="center" prop="remark" />
+      <!--
+      <el-table-column label="备注" align="center" prop="remark" /> -->
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openPlanDialog(scope.row)"
+            v-hasPermi="['rq:iot-project-task:update']"
+          >
+            计划
+          </el-button>
           <el-button
             link
             type="primary"
@@ -132,13 +141,58 @@
       @pagination="getList"
     />
   </ContentWrap>
+
+  <!-- 计划 Dialog -->
+  <el-dialog
+    v-model="planDialogVisible"
+    :title="`${currentRow?.contractName} - ${currentRow?.wellName} - 任务计划`"
+    width="80%"
+  >
+    <el-table :data="planList" border stripe>
+      <el-table-column label="施工状态" prop="name" min-width="200" />
+      <el-table-column label="开始时间" min-width="200">
+        <template #default="scope">
+          <el-date-picker
+            v-model="scope.row.startTime"
+            type="datetime"
+            placeholder="选择开始时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" min-width="200">
+        <template #default="scope">
+          <el-date-picker
+            v-model="scope.row.endTime"
+            type="datetime"
+            placeholder="选择结束时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+          />
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="planDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="savePlan" :loading="saveLoading">
+          保存
+        </el-button>
+      </span>
+    </template>
+  </el-dialog>
+
 </template>
 
 <script setup lang="ts">
 import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
-import { IotProjectTaskApi, IotProjectTaskVO } from '@/api/pms/iotprojecttask'
+import { IotProjectTaskScheduleApi } from '@/api/pms/iotprojecttaskschedule'
+import { IotProjectTaskApi, IotProjectTaskVO} from '@/api/pms/iotprojecttask'
 import IotProjectTaskForm from './IotProjectTaskForm.vue'
+import * as DictDataApi from '@/api/system/dict/dict.data'
+import { DictDataVO } from '@/api/system/dict/dict.data'
+import dayjs from 'dayjs'
 
 /** 项目信息任务拆分 列表 */
 defineOptions({ name: 'IotProjectTask' })
@@ -163,9 +217,123 @@ const queryParams = reactive({
   userId: undefined,
   remark: undefined,
 })
+
+const dictQueryParams = reactive({
+  pageNo: 1,
+  pageSize: 50,
+  label: '',
+  status: undefined,
+  dictType: 'rq_iot_project_work_progress'
+})
+
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
 const { push } = useRouter() // 路由跳转
+
+// 计划相关状态
+const planDialogVisible = ref(false)
+const planList = ref<Array<{name: string, value: string, startTime: string, endTime: string}>>([])
+const saveLoading = ref(false)
+const currentRow = ref<IotProjectTaskVO | null>(null)
+
+/** 时间戳转换为日期时间字符串(使用dayjs处理) */
+const timestampToDateTime = (timestamp: number | null): string => {
+  if (!timestamp) return ''
+  return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
+}
+
+/** 时间戳转换为日期时间字符串(修正时区问题)
+const timestampToDateTime = (timestamp: number | null): string => {
+  if (!timestamp) return ''
+
+  // 直接使用时间戳创建Date对象
+  const date = new Date(timestamp)
+
+  // 使用UTC方法获取日期时间组件,避免时区影响
+  const year = date.getUTCFullYear()
+  const month = String(date.getUTCMonth() + 1).padStart(2, '0')
+  const day = String(date.getUTCDate()).padStart(2, '0')
+  const hours = String(date.getUTCHours()).padStart(2, '0')
+  const minutes = String(date.getUTCMinutes()).padStart(2, '0')
+  const seconds = String(date.getUTCSeconds()).padStart(2, '0')
+
+  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+} */
+
+/** 打开计划对话框 */
+const openPlanDialog = async (row: IotProjectTaskVO) => {
+  currentRow.value = row
+  try {
+    // 并行获取数据字典和已有计划数据
+    const [dictData, taskSchedules] = await Promise.all([
+      DictDataApi.getDictDataPage(dictQueryParams),
+      IotProjectTaskScheduleApi.getIotProjectTaskSchedules({ taskId: row.id })
+    ])
+
+    // 获取数据字典 - 这里假设有一个获取计划项目字典的接口
+    //  const dictData = await DictDataApi.getDictDataPage(dictQueryParams)
+
+    // 对字典数据按照 sort 升序排序
+    const sortedDictData = dictData.list.sort((a: DictDataVO, b: DictDataVO) => a.sort - b.sort)
+
+    // 将已有计划数据转换为以status为键的映射
+    const existingPlansMap = new Map()
+    if (taskSchedules && taskSchedules.length > 0) {
+      console.log('任务计划已经存在数据了')
+      taskSchedules.forEach((plan: any) => {
+        existingPlansMap.set(plan.status, {
+          startTime: timestampToDateTime(plan.startTime),
+          endTime: timestampToDateTime(plan.endTime)
+        })
+      })
+    }
+
+    // 初始化计划列表,合并字典数据和已有计划数据
+    planList.value = sortedDictData.map((item: DictDataVO) => {
+      const existingPlan = existingPlansMap.get(Number(item.value))
+
+      return {
+        name: item.label,
+        value: item.value,
+        startTime: existingPlan ? existingPlan.startTime : '',
+        endTime: existingPlan ? existingPlan.endTime : ''
+      }
+    })
+
+    planDialogVisible.value = true
+  } catch (error) {
+    message.error('获取计划数据失败')
+    console.error('获取计划数据失败:', error)
+  }
+}
+
+/** 保存计划 */
+const savePlan = async () => {
+  try {
+    saveLoading.value = true
+
+    // 准备提交数据,符合新接口格式
+    const submitData = planList.value.map(item => ({
+      taskId: currentRow.value?.id, // 取自当前行的id
+      status: Number(item.value), // 取自planList中的value值,转换为数字
+      description: item.name, // 取自planList中的name值
+      startTime: item.startTime ? new Date(item.startTime).getTime().toString() : null, // 转换为时间戳字符串
+      endTime: item.endTime ? new Date(item.endTime).getTime().toString() : null // 转换为时间戳字符串
+    }))
+
+    // 调用保存接口
+    await IotProjectTaskScheduleApi.saveTaskSchedule(submitData)
+
+    message.success('保存成功')
+    planDialogVisible.value = false
+  } catch (error) {
+    message.error('保存失败')
+    console.error('保存失败:', error)
+  } finally {
+    saveLoading.value = false
+  }
+}
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true