Sfoglia il codice sorgente

培训记录 修复返回bug

Hwf 1 anno fa
parent
commit
f74af38bc0

+ 78 - 1
src/api/riskPrevention/planManage.ts

@@ -15,7 +15,7 @@ export function getTrainingList(params) {
   });
 }
 
-export function getPlanDetail(params) {
+export function getPlanList(params) {
   return request({
     url: '/api/emergency_plan/plan/list',
     method: 'get',
@@ -23,9 +23,86 @@ export function getPlanDetail(params) {
   });
 }
 
+export function getPlanDetail(planId: string) {
+  return request({
+    url: '/api/emergency_plan/plan/' + planId,
+    method: 'get'
+  });
+}
+
 export function getResponseDetail(responseId) {
   return request({
     url: '/api/emergency_plan/plan/' + responseId,
     method: 'get'
   });
 }
+
+// 修改预案
+export const updateReport = (data) => {
+  return request({
+    url: `/api/reports/update`,
+    method: 'put',
+    data: data
+  });
+};
+
+// 删除预案
+export const deletePlan = (data) => {
+  return request({
+    url: `/api/emergency_plan/plan/delete`,
+    method: 'delete',
+    data: data
+  });
+};
+
+// 新增预案
+export const addReport = (data) => {
+  return request({
+    url: '/api/emergency_plan/plan/create',
+    method: 'post',
+    data: data
+  });
+};
+
+export const listDrill = (params) => {
+  return request({
+    url: '/api/emergency_plan/drill/list',
+    method: 'get',
+    params: params
+  });
+};
+
+// 新增培训记录
+export const addTraining = (data) => {
+  return request({
+    url: '/api/emergency_plan/training/create',
+    method: 'post',
+    data: data
+  });
+};
+
+// 修改培训记录
+export const updateTraining = (data) => {
+  return request({
+    url: '/api/emergency_plan/training/update',
+    method: 'put',
+    data: data
+  });
+};
+
+// 培训记录详情
+export const getTrainingDetail = (trainingId) => {
+  return request({
+    url: '/api/emergency_plan/training/' + trainingId,
+    method: 'get'
+  });
+};
+
+// 删除培训记录
+export const deleteTraining = (data) => {
+  return request({
+    url: '/api/emergency_plan/training/delete',
+    method: 'delete',
+    data: data
+  });
+};

+ 1 - 11
src/api/system/user/index.ts

@@ -42,17 +42,7 @@ export const listPlan = (query: PlanQuery): AxiosPromise<PlanVO[]> => {
     params: query
   });
 };
-export const listDrill = (params: DrillForm): AxiosPromise<FetchDrillResponse> => {
-  return request({
-    url: '/api/emergency_plan/drill/list',
-    method: 'get',
-    params: {
-      page: params.pageNum, // 分页参数中的页码
-      page_size: params.pageSize, // 分页参数中的每页大小
-      planNum: params.planId // 预案编号
-    }
-  });
-};
+
 export const listResponse = (query: DrillQuery): AxiosPromise<ResponseVO[]> => {
   return request({
     url: '/system/user/list',

+ 0 - 9
src/api/system/user/planList.ts

@@ -26,15 +26,6 @@ export const addReport = (data: PlanVO): AxiosPromise<void> => {
   });
 };
 
-// 修改预案
-export const updateReport = (data: PlanVO): AxiosPromise<void> => {
-  return request({
-    url: `/api/reports/update/${data.reportNumber}`,
-    method: 'put',
-    data: data
-  });
-};
-
 // 删除预案
 export const deleteReport = (reportNumber: string): AxiosPromise<void> => {
   return request({

+ 1 - 0
src/api/system/user/types.ts

@@ -73,6 +73,7 @@ export interface PlanForm {
   publish_date?: [string, string];
   planName: string;
   planType?: string;
+  keywords?: string;
 }
 export interface PlanInfoVO {
   plan: PlanVO;

+ 16 - 4
src/types/components.d.ts

@@ -16,16 +16,21 @@ declare module 'vue' {
     CompanyMap: typeof import('./../components/Map/company-map.vue')['default']
     DictTag: typeof import('./../components/DictTag/index.vue')['default']
     Editor: typeof import('./../components/Editor/index.vue')['default']
+    ElAnchor: typeof import('element-plus/es')['ElAnchor']
+    ElAnchorLink: typeof import('element-plus/es')['ElAnchorLink']
     ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
     ElBadge: typeof import('element-plus/es')['ElBadge']
     ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
     ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
     ElButton: typeof import('element-plus/es')['ElButton']
+    ElCard: typeof import('element-plus/es')['ElCard']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
     ElCol: typeof import('element-plus/es')['ElCol']
     ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
+    ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
@@ -38,31 +43,38 @@ declare module 'vue' {
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
+    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElLink: typeof import('element-plus/es')['ElLink']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPopover: typeof import('element-plus/es')['ElPopover']
+    ElProgress: typeof import('element-plus/es')['ElProgress']
+    ElRadio: typeof import('element-plus/es')['ElRadio']
+    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
-    ElStep: typeof import('element-plus/es')['ElStep']
-    ElSteps: typeof import('element-plus/es')['ElSteps']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
     ElTable: typeof import('element-plus/es')['ElTable']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElTabPane: typeof import('element-plus/es')['ElTabPane']
+    ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTag: typeof import('element-plus/es')['ElTag']
-    ElTimeline: typeof import('element-plus/es')['ElTimeline']
-    ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
+    ElText: typeof import('element-plus/es')['ElText']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ElTree: typeof import('element-plus/es')['ElTree']
+    ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
     Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
     HeaderSearch: typeof import('./../components/HeaderSearch/index.vue')['default']
     IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
+    IEpCaretBottom: typeof import('~icons/ep/caret-bottom')['default']
+    IEpCaretTop: typeof import('~icons/ep/caret-top')['default']
+    IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default']
     IFrame: typeof import('./../components/iFrame/index.vue')['default']
     ImagePreview: typeof import('./../components/ImagePreview/index.vue')['default']
     ImageUpload: typeof import('./../components/ImageUpload/index.vue')['default']

+ 27 - 20
src/utils/request.ts

@@ -201,26 +201,33 @@ export function download(url: string, params: any, fileName: string) {
 // 通用下载方法
 export function download2(url: string, fileName: string) {
   downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
-  return service.get(url, {}, {
-    headers: { 'Content-Type': 'application/octet-stream' },
-    responseType: 'blob'
-  }).then(async (resp: any) => {
-    const isLogin = blobValidate(resp);
-    if (isLogin) {
-      const blob = new Blob([resp]);
-      FileSaver.saveAs(blob, fileName);
-    } else {
-      const resText = await resp.data.text();
-      const rspObj = JSON.parse(resText);
-      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];
-      ElMessage.error(errMsg);
-    }
-    downloadLoadingInstance.close();
-  }).catch((r: any) => {
-    console.error(r);
-    ElMessage.error('下载文件出现错误,请联系管理员!');
-    downloadLoadingInstance.close();
-  });
+  return service
+    .get(
+      url,
+      {},
+      {
+        headers: { 'Content-Type': 'application/octet-stream' },
+        responseType: 'blob'
+      }
+    )
+    .then(async (resp: any) => {
+      const isLogin = blobValidate(resp);
+      if (isLogin) {
+        const blob = new Blob([resp]);
+        FileSaver.saveAs(blob, fileName);
+      } else {
+        const resText = await resp.data.text();
+        const rspObj = JSON.parse(resText);
+        const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];
+        ElMessage.error(errMsg);
+      }
+      downloadLoadingInstance.close();
+    })
+    .catch((r: any) => {
+      console.error(r);
+      ElMessage.error('下载文件出现错误,请联系管理员!');
+      downloadLoadingInstance.close();
+    });
 }
 // 导出 axios 实例
 export default service;

+ 13 - 0
src/utils/ruoyi.ts

@@ -63,6 +63,19 @@ export const addDateRange = (params: any, dateRange: any[], propName?: string) =
   return search;
 };
 
+export const addDateRange2 = (params: any, dateRange: any[], beginTimeName?: string, endTimeName?: string) => {
+  const search = params;
+  dateRange = Array.isArray(dateRange) ? dateRange : [];
+  if (!beginTimeName || !endTimeName) {
+    search['beginTime'] = dateRange[0];
+    search['endTime'] = dateRange[1];
+  } else {
+    search[beginTimeName] = dateRange[0];
+    search[beginTimeName] = dateRange[1];
+  }
+  return search;
+};
+
 // 回显数据字典
 export const selectDictLabel = (datas: any, value: number | string) => {
   if (value === undefined) {

+ 1 - 1
src/views/duty/eventing/eventDetails.vue

@@ -190,7 +190,7 @@ const eventTrackState = reactive({
 });
 // 返回上一级
 const handleBack = () => {
-  router.go(-1);
+  proxy?.$tab.closePage();
 };
 let eventId = ref('');
 let detailData = ref({

+ 1 - 1
src/views/knowledge/knowledge-management/detail.vue

@@ -83,7 +83,7 @@ const mm_event_type = ref([]);
 
 // 返回上一级
 const goBack = () => {
-  router.go(-1);
+  proxy?.$tab.closePage();
 };
 
 // 编辑报告

+ 280 - 0
src/views/riskPrevention/planManage/DrillRecord.vue

@@ -0,0 +1,280 @@
+<template>
+  <el-card shadow="hover">
+    <template #header>
+      <el-row :gutter="10">
+        <el-col :span="1.5">
+          <el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()"> 删除 </el-button>
+        </el-col>
+      </el-row>
+    </template>
+
+    <el-table
+      v-loading="loading"
+      :default-sort="{ prop: 'startTime,endTime', order: 'descending' }"
+      :data="dataList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="50" align="center" />
+      <el-table-column label="培训主题" align="center" prop="theme" :show-overflow-tooltip="true" />
+      <el-table-column label="培训单位" align="center" prop="unitName" :show-overflow-tooltip="true" />
+      <el-table-column label="培训内容" align="center" prop="Content" :show-overflow-tooltip="true" />
+      <el-table-column label="参与人数" align="center" prop="peopleNum" width="120" />
+      <el-table-column label="培训方式" align="center" prop="trainingWay" width="120" />
+      <el-table-column label="开始时间" sortable align="center" prop="startTime" width="160">
+        <template #default="scope">
+          <span>{{ scope.row.startTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" sortable align="center" prop="endTime" width="160">
+        <template #default="scope">
+          <span>{{ scope.row.endTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column key="address" label="培训地点" align="center" prop="address" :show-overflow-tooltip="true" />
+      <el-table-column fixed="right" label="操作" width="100">
+        <template #default="scope">
+          <el-tooltip v-if="scope.row.textId !== 1" content="编辑" placement="top">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
+          </el-tooltip>
+          <el-tooltip v-if="scope.row.textId !== 1" content="删除" placement="top">
+            <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"></el-button>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total > queryParams.pageSize"
+      v-model:page="queryParams.page"
+      v-model:limit="queryParams.pageSize"
+      :total="total"
+      @pagination="getList"
+    />
+  </el-card>
+  <!-- 添加或修改培训记录配置对话框 -->
+  <el-dialog ref="formDialogRef" v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
+      <el-form-item label="培训主题" prop="theme">
+        <el-input v-model="form.theme" placeholder="请输入培训主题" />
+      </el-form-item>
+      <el-form-item label="培训单位" prop="unitName">
+        <el-input v-model="form.unitName" placeholder="请输入培训单位" />
+      </el-form-item>
+      <el-form-item label="培训方式" prop="trainingWay">
+        <el-select v-model="form.trainingWay" placeholder="请选择培训方式">
+          <el-option label="线上培训" value="1" />
+          <el-option label="线下培训" value="2" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="参与人数" prop="peopleNum">
+        <el-input v-model="form.peopleNum" placeholder="请输入参与人数" />
+      </el-form-item>
+      <el-form-item label="开始时间" prop="startTime">
+        <el-date-picker v-model="form.startTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" />
+      </el-form-item>
+      <el-form-item label="结束时间" prop="endTime">
+        <el-date-picker v-model="form.endTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="结束时间" />
+      </el-form-item>
+      <el-form-item label="培训地点" prop="address">
+        <el-input v-model="form.address" placeholder="请选择培训地点" readonly>
+          <template #append>
+            <div style="cursor: pointer" @click="openMapDialog">地图定位</div>
+          </template>
+        </el-input>
+      </el-form-item>
+      <el-form-item label="培训内容" prop="Content">
+        <el-input v-model="form.Content" type="textarea" placeholder="请输入培训内容"></el-input>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+  <!-- 地图弹窗 -->
+  <company-map v-model:visible="mapDialogVisible" :address="form.address" @confirm="handleMapChange"></company-map>
+</template>
+<script setup lang="ts">
+import {
+  getTrainingList,
+  addTraining,
+  updateTraining,
+  getTrainingDetail,
+  deleteTraining
+} from '@/api/riskPrevention/planManage';
+import { to } from 'await-to-js';
+import { ref } from 'vue';
+import { PlanVO } from '@/api/system/user/types';
+
+const props = defineProps({
+  id: String
+});
+
+const formRef = ref<ElFormInstance>();
+const ids = ref<string[]>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const selectedRow = ref<PlanVO | null>(null);
+const dataList = ref([]);
+const loading = ref(true);
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const emits = defineEmits(['update:modelValue', 'getList']);
+let visible = ref(false);
+let buttonLoading = ref(false);
+let title = ref('');
+const queryParams = reactive({
+  page: 1,
+  pageSize: 10
+});
+const form = ref({
+  trainingId: '',
+  theme: '',
+  unitName: '',
+  address: '',
+  lon: '',
+  lat: '',
+  startTime: '',
+  endTime: '',
+  peopleNum: '',
+  Content: '',
+  trainingWay: ''
+});
+const rules = reactive({
+  theme: [{ required: true, message: '培训主题不能为空', trigger: 'blur' }],
+  unitName: [{ required: true, message: '培训单位不能为空', trigger: 'blur' }],
+  peopleNum: [{ required: true, message: '参与人数不能为空', trigger: 'blur' }],
+  trainingWay: [{ required: true, message: '培训方式不能为空', trigger: 'blur' }],
+  address: [{ required: true, message: '培训地点不能为空', trigger: 'blur' }],
+  Content: [{ required: true, message: '培训内容不能为空', trigger: 'blur' }],
+  startTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
+  endTime: [{ required: true, message: '结束时间不能为空', trigger: 'change' }]
+});
+
+// 获取列表数据
+const getList = () => {
+  loading.value = true;
+  getTrainingList({ ...queryParams, planNum: props.id })
+    .then((res) => {
+      dataList.value = res.data;
+      total.value = res.total;
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+};
+
+watch(
+  () => props.id,
+  () => {
+    if (props.id) {
+      getList();
+    }
+  },
+  {
+    immediate: true
+  }
+);
+
+/** 重置操作表单 */
+const reset = () => {
+  form.value = {
+    trainingId: '',
+    theme: '',
+    unitName: '',
+    address: '',
+    lon: '',
+    lat: '',
+    startTime: '',
+    endTime: '',
+    peopleNum: '',
+    Content: '',
+    trainingWay: ''
+  };
+  formRef.value?.resetFields();
+};
+/** 取消按钮 */
+const cancel = () => {
+  resetForm();
+  visible.value = false;
+};
+
+/**
+ * 关闭用户弹窗
+ */
+const closeDialog = () => {
+  emits('update:modelValue', false);
+  resetForm();
+};
+
+const resetForm = () => {
+  formRef.value?.resetFields();
+  formRef.value?.clearValidate();
+};
+
+const handleUpdate = async (row) => {
+  if (row) {
+    resetForm();
+    const res = await getTrainingDetail(row.trainingId);
+    form.value = res.data;
+    visible.value = true;
+    title.value = '修改培训记录';
+  }
+};
+
+const handleAdd = () => {
+  resetForm();
+  visible.value = true;
+  title.value = '添加培训记录';
+};
+
+/**提交按钮 */
+const submitForm = () => {
+  formRef.value?.validate(async (valid) => {
+    if (valid) {
+      try {
+        buttonLoading.value = true;
+        form.value.trainingId ? await updateTraining({ ...form.value, planId: props.id }) : await addTraining({ ...form.value, planId: props.id });
+        proxy?.$modal.msgSuccess(form.value.trainingId ? '修改成功' : '新增成功');
+        visible.value = false;
+        getList();
+      } finally {
+        buttonLoading.value = false;
+      }
+    }
+  });
+};
+
+const handleSelectionChange = (selection) => {
+  ids.value = selection.map((item) => item.trainingId);
+  selectedRow.value = selection.length === 1 ? selection[0] : null;
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+const handleDelete = async (row) => {
+  const deleteIds = row && row.trainingId ? [row?.trainingId] : ids.value;
+  const [err] = await to(proxy?.$modal.confirm('是否确认删除选择的培训记录?') as any);
+  if (!err) {
+    await deleteTraining(deleteIds);
+    getList();
+    proxy?.$modal.msgSuccess('删除成功');
+  }
+};
+
+// 地图定位
+const mapDialogVisible = ref(false);
+const openMapDialog = () => {
+  mapDialogVisible.value = true;
+};
+const handleMapChange = (data) => {
+  form.value.address = data.address;
+  form.value.lon = data.lnglat[0];
+  form.value.lat = data.lnglat[1];
+  mapDialogVisible.value = false;
+};
+</script>

+ 280 - 0
src/views/riskPrevention/planManage/TrainingRecord.vue

@@ -0,0 +1,280 @@
+<template>
+  <el-card shadow="hover">
+    <template #header>
+      <el-row :gutter="10">
+        <el-col :span="1.5">
+          <el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()"> 删除 </el-button>
+        </el-col>
+      </el-row>
+    </template>
+
+    <el-table
+      v-loading="loading"
+      :default-sort="{ prop: 'startTime,endTime', order: 'descending' }"
+      :data="dataList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="50" align="center" />
+      <el-table-column label="培训主题" align="center" prop="theme" :show-overflow-tooltip="true" />
+      <el-table-column label="培训单位" align="center" prop="unitName" :show-overflow-tooltip="true" />
+      <el-table-column label="培训内容" align="center" prop="Content" :show-overflow-tooltip="true" />
+      <el-table-column label="参与人数" align="center" prop="peopleNum" width="120" />
+      <el-table-column label="培训方式" align="center" prop="trainingWay" width="120" />
+      <el-table-column label="开始时间" sortable align="center" prop="startTime" width="160">
+        <template #default="scope">
+          <span>{{ scope.row.startTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" sortable align="center" prop="endTime" width="160">
+        <template #default="scope">
+          <span>{{ scope.row.endTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column key="address" label="培训地点" align="center" prop="address" :show-overflow-tooltip="true" />
+      <el-table-column fixed="right" label="操作" width="100">
+        <template #default="scope">
+          <el-tooltip v-if="scope.row.textId !== 1" content="编辑" placement="top">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
+          </el-tooltip>
+          <el-tooltip v-if="scope.row.textId !== 1" content="删除" placement="top">
+            <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"></el-button>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total > queryParams.pageSize"
+      v-model:page="queryParams.page"
+      v-model:limit="queryParams.pageSize"
+      :total="total"
+      @pagination="getList"
+    />
+  </el-card>
+  <!-- 添加或修改培训记录配置对话框 -->
+  <el-dialog ref="formDialogRef" v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
+      <el-form-item label="培训主题" prop="theme">
+        <el-input v-model="form.theme" placeholder="请输入培训主题" />
+      </el-form-item>
+      <el-form-item label="培训单位" prop="unitName">
+        <el-input v-model="form.unitName" placeholder="请输入培训单位" />
+      </el-form-item>
+      <el-form-item label="培训方式" prop="trainingWay">
+        <el-select v-model="form.trainingWay" placeholder="请选择培训方式">
+          <el-option label="线上培训" value="1" />
+          <el-option label="线下培训" value="2" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="参与人数" prop="peopleNum">
+        <el-input v-model="form.peopleNum" placeholder="请输入参与人数" />
+      </el-form-item>
+      <el-form-item label="开始时间" prop="startTime">
+        <el-date-picker v-model="form.startTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" />
+      </el-form-item>
+      <el-form-item label="结束时间" prop="endTime">
+        <el-date-picker v-model="form.endTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="结束时间" />
+      </el-form-item>
+      <el-form-item label="培训地点" prop="address">
+        <el-input v-model="form.address" placeholder="请选择培训地点" readonly>
+          <template #append>
+            <div style="cursor: pointer" @click="openMapDialog">地图定位</div>
+          </template>
+        </el-input>
+      </el-form-item>
+      <el-form-item label="培训内容" prop="Content">
+        <el-input v-model="form.Content" type="textarea" placeholder="请输入培训内容"></el-input>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+  <!-- 地图弹窗 -->
+  <company-map v-model:visible="mapDialogVisible" :address="form.address" @confirm="handleMapChange"></company-map>
+</template>
+<script setup lang="ts">
+import {
+  getTrainingList,
+  addTraining,
+  updateTraining,
+  getTrainingDetail,
+  deleteTraining
+} from '@/api/riskPrevention/planManage';
+import { to } from 'await-to-js';
+import { ref } from 'vue';
+import { PlanVO } from '@/api/system/user/types';
+
+const props = defineProps({
+  id: String
+});
+
+const formRef = ref<ElFormInstance>();
+const ids = ref<string[]>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const selectedRow = ref<PlanVO | null>(null);
+const dataList = ref([]);
+const loading = ref(true);
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const emits = defineEmits(['update:modelValue', 'getList']);
+let visible = ref(false);
+let buttonLoading = ref(false);
+let title = ref('');
+const queryParams = reactive({
+  page: 1,
+  pageSize: 10
+});
+const form = ref({
+  trainingId: '',
+  theme: '',
+  unitName: '',
+  address: '',
+  lon: '',
+  lat: '',
+  startTime: '',
+  endTime: '',
+  peopleNum: '',
+  Content: '',
+  trainingWay: ''
+});
+const rules = reactive({
+  theme: [{ required: true, message: '培训主题不能为空', trigger: 'blur' }],
+  unitName: [{ required: true, message: '培训单位不能为空', trigger: 'blur' }],
+  peopleNum: [{ required: true, message: '参与人数不能为空', trigger: 'blur' }],
+  trainingWay: [{ required: true, message: '培训方式不能为空', trigger: 'blur' }],
+  address: [{ required: true, message: '培训地点不能为空', trigger: 'blur' }],
+  Content: [{ required: true, message: '培训内容不能为空', trigger: 'blur' }],
+  startTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
+  endTime: [{ required: true, message: '结束时间不能为空', trigger: 'change' }]
+});
+
+// 获取列表数据
+const getList = () => {
+  loading.value = true;
+  getTrainingList({ ...queryParams, planNum: props.id })
+    .then((res) => {
+      dataList.value = res.data;
+      total.value = res.total;
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+};
+
+watch(
+  () => props.id,
+  () => {
+    if (props.id) {
+      getList();
+    }
+  },
+  {
+    immediate: true
+  }
+);
+
+/** 重置操作表单 */
+const reset = () => {
+  form.value = {
+    trainingId: '',
+    theme: '',
+    unitName: '',
+    address: '',
+    lon: '',
+    lat: '',
+    startTime: '',
+    endTime: '',
+    peopleNum: '',
+    Content: '',
+    trainingWay: ''
+  };
+  formRef.value?.resetFields();
+};
+/** 取消按钮 */
+const cancel = () => {
+  resetForm();
+  visible.value = false;
+};
+
+/**
+ * 关闭用户弹窗
+ */
+const closeDialog = () => {
+  emits('update:modelValue', false);
+  resetForm();
+};
+
+const resetForm = () => {
+  formRef.value?.resetFields();
+  formRef.value?.clearValidate();
+};
+
+const handleUpdate = async (row) => {
+  if (row) {
+    resetForm();
+    const res = await getTrainingDetail(row.trainingId);
+    form.value = res.data;
+    visible.value = true;
+    title.value = '修改培训记录';
+  }
+};
+
+const handleAdd = () => {
+  resetForm();
+  visible.value = true;
+  title.value = '添加培训记录';
+};
+
+/**提交按钮 */
+const submitForm = () => {
+  formRef.value?.validate(async (valid) => {
+    if (valid) {
+      try {
+        buttonLoading.value = true;
+        form.value.trainingId ? await updateTraining({ ...form.value, planId: props.id }) : await addTraining({ ...form.value, planId: props.id });
+        proxy?.$modal.msgSuccess(form.value.trainingId ? '修改成功' : '新增成功');
+        visible.value = false;
+        getList();
+      } finally {
+        buttonLoading.value = false;
+      }
+    }
+  });
+};
+
+const handleSelectionChange = (selection) => {
+  ids.value = selection.map((item) => item.trainingId);
+  selectedRow.value = selection.length === 1 ? selection[0] : null;
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+const handleDelete = async (row) => {
+  const deleteIds = row && row.trainingId ? [row?.trainingId] : ids.value;
+  const [err] = await to(proxy?.$modal.confirm('是否确认删除选择的培训记录?') as any);
+  if (!err) {
+    await deleteTraining(deleteIds);
+    getList();
+    proxy?.$modal.msgSuccess('删除成功');
+  }
+};
+
+// 地图定位
+const mapDialogVisible = ref(false);
+const openMapDialog = () => {
+  mapDialogVisible.value = true;
+};
+const handleMapChange = (data) => {
+  form.value.address = data.address;
+  form.value.lon = data.lnglat[0];
+  form.value.lat = data.lnglat[1];
+  mapDialogVisible.value = false;
+};
+</script>

+ 0 - 217
src/views/riskPrevention/planManage/drill.vue

@@ -1,217 +0,0 @@
-<template>
-  <!-- 添加或修改培训记录配置对话框 -->
-  <el-dialog ref="formDialogRef" v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
-    <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="演练名称" prop="drillName">
-            <el-input v-model="form.drillName" placeholder="请输入演练名称" maxlength="30" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="演练单位" prop="drillUnit">
-            <el-input v-model="form.drillUnit" placeholder="请输入演练单位" maxlength="30" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="年度" prop="year">
-            <el-input v-model="form.year" placeholder="请输入演练年度" maxlength="11" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20" class="block">
-          <el-form-item label="演练时间" prop="drillTime">
-            <el-date-picker v-model="form.drillTime" :shortcuts="shortcuts" placeholder="请选择开始时间" maxlength="11" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="演练地点" prop="drillAddress">
-            <el-button>地图定位</el-button>
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="演练方案" prop="drillProject">
-            <el-button>上传</el-button>
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="演练视频" prop="drillVideo">
-            <el-button>上传</el-button>
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row>
-        <el-col :span="20">
-          <el-form-item label="演练图片" prop="drillPicture">
-            <el-button>上传</el-button>
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-    <template #footer>
-      <div class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel()">取 消</el-button>
-      </div>
-    </template>
-  </el-dialog>
-</template>
-<script setup lang="ts">
-import { ref } from 'vue';
-import api from '@/api/system/user';
-import { DrillForm, DrillVO, DrillQuery } from '@/api/system/user/types';
-const userFormRef = ref<ElFormInstance>();
-const ids = ref<Array<number | string>>([]);
-const drillList = ref<DrillVO[]>();
-const loading = ref(true);
-const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const emits = defineEmits(['update:modelValue', 'getList']);
-const total = ref(0);
-import { to } from 'await-to-js';
-
-const props = defineProps({
-  modelValue: Boolean,
-  id: String
-});
-
-watch(
-  () => props.modelValue,
-  (val) => {
-    visible.value = val;
-  }
-);
-
-let visible = ref(false);
-const title = computed(() => {
-  return props.id ? '编辑演练' : '新建演练';
-});
-
-/***培训记录编辑界面时间选择 */
-
-const shortcuts = [
-  {
-    text: '今天',
-    value: new Date()
-  },
-  {
-    text: '昨天',
-    value: () => {
-      const date = new Date();
-      date.setDate(date.getDate() - 1);
-      return date;
-    }
-  },
-  {
-    text: '一周前',
-    value: () => {
-      const date = new Date();
-      date.setDate(date.getDate() - 7);
-      return date;
-    }
-  }
-];
-const initFormData: DrillForm = {
-  drillId: undefined,
-  drillName: undefined,
-  drillUnit: undefined,
-  year: undefined,
-  drillTime: undefined,
-  drillAddress: undefined,
-  drillProject: undefined,
-  drillVideo: undefined,
-  drillPicture: undefined
-};
-
-const initData: PageData<DrillForm, DrillQuery> = {
-  form: { ...initFormData },
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    planId: 'YJYA0000000001'
-  },
-  rules: {
-    drillName: [
-      { required: true, message: '演练名称不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        message: '演练名称长度必须介于 1 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    drillUnit: [
-      { required: true, message: '演练单位不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        max: 20,
-        message: '演练单位长度必须介于 1 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    year: [{ required: true, message: '演练年度不能为空', trigger: 'blur' }],
-    drillTime: [{ required: true, message: '演练时间不能为空', trigger: 'change' }]
-  }
-};
-
-const data = reactive<PageData<DrillForm, DrillQuery>>(initData);
-
-const { queryParams, form, rules } = toRefs<PageData<DrillForm, DrillQuery>>(data);
-
-const getList = async () => {
-  loading.value = true;
-  const res = await api.listDrill(proxy?.addDateRange(queryParams.value, dateRange.value));
-  loading.value = false;
-  drillList.value = res.rows;
-  total.value = res.total;
-};
-
-/** 重置操作表单 */
-const reset = () => {
-  form.value = { ...initFormData };
-  userFormRef.value?.resetFields();
-  form.value.drillId = undefined;
-};
-/** 取消按钮 */
-const cancel = () => {
-  emits('update:modelValue', false);
-  reset();
-};
-
-/**
- * 关闭用户弹窗
- */
-const closeDialog = () => {
-  emits('update:modelValue', false);
-  resetForm();
-};
-
-const resetForm = () => {
-  userFormRef.value?.resetFields();
-  userFormRef.value?.clearValidate();
-
-  form.value.drillId = undefined;
-};
-
-/**提交按钮 */
-const submitForm = () => {
-  userFormRef.value?.validate(async (valid: boolean) => {
-    if (valid) {
-      form.value.drillId ? await api.updateDrill(form.value) : await api.addDrill(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
-      emits('update:modelValue', true);
-      emits('getList');
-    }
-  });
-};
-</script>

+ 51 - 82
src/views/riskPrevention/planManage/index.vue

@@ -5,23 +5,21 @@
         <el-form ref="queryFormRef" :model="planForm" :inline="true">
           <el-form-item style="width: 200px" label="预案类型" prop="planType">
             <el-select v-model="planForm.planType" placeholder="全部" clearable>
-              <el-option label="总体应急预案" value="1" />
-              <el-option label="专项应急预案" value="2" />
-              <el-option label="部门应急预案" value="3" />
+              <el-option v-for="item in plan_type" :key="item.value" :label="item.label" :value="item.value"></el-option>
             </el-select>
           </el-form-item>
           <el-form-item label="发布日期" prop="publish_date">
             <el-date-picker
-              v-model="planForm.publish_date"
+              v-model="dateRange"
               type="daterange"
               range-separator="-"
               start-placeholder="开始日期"
               end-placeholder="结束日期"
-              value-format="yyyy-MM-dd"
+              value-format="YYYY-MM-DD"
             ></el-date-picker>
           </el-form-item>
           <el-form-item>
-            <el-input v-model="planForm.planName" placeholder="请输入预案名称/编制单位" clearable @keyup.enter="handleQuery" />
+            <el-input v-model="planForm.keywords" placeholder="请输入预案名称/编制单位" clearable @keyup.enter="handleQuery" />
           </el-form-item>
           <el-form-item>
             <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -36,15 +34,9 @@
       <el-col :span="1.5">
         <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
       </el-col>
-      <el-col :span="1.5">
-        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate(selectedRow)">修改</el-button>
-      </el-col>
       <el-col :span="1.5">
         <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete(selectedRow)">删除</el-button>
       </el-col>
-      <el-col :span="1.5">
-        <el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
-      </el-col>
       <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
     </el-row>
 
@@ -53,9 +45,13 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="预案编号" align="center" prop="planId" />
       <el-table-column label="预案名称" align="center" prop="planName" />
-      <el-table-column label="预案类型" align="center" prop="planType" />
+      <el-table-column label="预案类型" align="center" prop="planType">
+        <template #default="scope">
+          <dict-tag :options="plan_type" :value="scope.row.planType" />
+        </template>
+      </el-table-column>
       <el-table-column label="发文字号" align="center" prop="document" />
-      <el-table-column label="编制单位" align="center" prop="organUnit" />
+      <el-table-column label="编制单位" align="center" prop="organizingUnit" />
       <el-table-column label="发布日期" align="center" prop="publishDate" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
@@ -72,7 +68,7 @@
       </el-table-column>
     </el-table>
 
-    <pagination v-show="total > 0" v-model:page="planForm.pageNum" v-model:limit="planForm.pageSize" :total="total" @pagination="getList" />
+    <pagination v-show="total > 0" v-model:page="planForm.page" v-model:limit="planForm.pageSize" :total="total" @pagination="getList" />
 
     <!-- 新增/修改弹窗 -->
     <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
@@ -82,24 +78,21 @@
         </el-form-item>
         <el-form-item label="预案类型" prop="planType">
           <el-select v-model="form.planType" placeholder="请选择预案类型" clearable>
-            <el-option label="总体应急预案" value="1" />
-            <el-option label="专项应急预案" value="2" />
-            <el-option label="部门应急预案" value="3" />
+            <el-option v-for="item in plan_type" :key="item.value" :label="item.label" :value="item.value"></el-option>
           </el-select>
         </el-form-item>
         <el-form-item label="发布日期" prop="publishDate">
           <el-date-picker v-model="form.publishDate" type="date" placeholder="选择发布日期" value-format="YYYY-MM-DD"></el-date-picker>
         </el-form-item>
+        <el-form-item label="编制单位" prop="organizingUnit">
+          <el-input v-model="form.organizingUnit" placeholder="请输入编制单位" />
+        </el-form-item>
         <el-form-item label="发文字号" prop="document">
           <el-input v-model="form.document" placeholder="请输入发文字号" />
         </el-form-item>
-        <el-form-item label="编制单位" prop="organizingUnit">
-          <el-input v-model="form.organizingUnit" placeholder="请输入编制单位" />
+        <el-form-item label="预案附件" prop="fileList">
+          <file-upload v-model="form.fileList" />
         </el-form-item>
-        <el-col :span="1.5">
-          <!-- 使用分片上传组件,每个分片 -->
-          <chunk-upload :max-file-size="50 * 1024 * 1024" :max-files="5" />
-        </el-col>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
@@ -112,15 +105,13 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onMounted } from 'vue';
-import { ElMessage } from 'element-plus';
-import { fetchReports, addReport, updateReport, deleteReport } from '@/api/system/user/planList.ts';
+import { ref, reactive, onMounted, toRefs } from 'vue';
 import { PlanForm, PlanVO } from '@/api/system/user/types';
-import ChunkUpload from '@/components/ChunkUpload/index.vue';
 import { getDicts } from '@/api/system/dict/data';
-
 import { useRouter } from 'vue-router';
-import { getPlanDetail, getTrainingList } from "@/api/riskPrevention/planManage";
+import { getPlanDetail, getPlanList, updateReport, deletePlan, addReport } from '@/api/riskPrevention/planManage';
+import { addDateRange2 } from '@/utils/ruoyi';
+import { to } from 'await-to-js';
 
 const router = useRouter();
 const demoFormRef = ref(null);
@@ -133,24 +124,25 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 const selectedRow = ref<PlanVO | null>(null);
-let proxy = getCurrentInstance()?.proxy;
-const { mm_event_type } = toRefs<any>(proxy?.useDict('mm_event_type'));
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { plan_type } = toRefs<any>(proxy?.useDict('plan_type'));
 
+const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 const planForm = reactive<PlanForm>({
-  pageNum: 1,
+  page: 1,
   pageSize: 10,
   planType: '',
-  publish_date: ['', ''],
-  planName: ''
+  keywords: ''
 });
 
-const form = reactive({
+let form = ref({
   planId: '',
   planName: '',
   planType: '',
   document: '',
   organizingUnit: '',
-  publishDate: ''
+  publishDate: '',
+  fileList: []
 });
 
 const rules = reactive({
@@ -168,41 +160,28 @@ const dialog = reactive({
   title: ''
 });
 
-// const getList = async () => {
-//   loading.value = true;
-//   try {
-//     const response = await fetchReports(planForm);
-//     demoList.value = response.data;
-//     total.value = response.total;
-//   } catch (error) {
-//     console.error('获取数据时出错:', error);
-//   } finally {
-//     loading.value = false;
-//   }
-// };
 const getList = async () => {
   loading.value = true;
-  const res = await getPlanDetail(planForm);
+  const res = await getPlanList(addDateRange2(planForm, dateRange.value));
   loading.value = false;
   demoList.value = res.data;
   total.value = res.total;
 };
 const handleQuery = () => {
-  planForm.pageNum = 1;
+  planForm.page = 1;
   getList();
 };
 
 const resetQuery = () => {
-  planForm.pageNum = 1;
-  planForm.pageSize = 10;
-  queryParams.planType = '';
-  queryParams.publish_date = ['', ''];
-  queryParams.planName = '';
-  getList();
+  planForm.page = 1;
+  planForm.planType = '';
+  planForm.keywords = '';
+  dateRange.value = ['', ''];
+  handleQuery();
 };
 
 const handleSelectionChange = (selection: PlanVO[]) => {
-  ids.value = selection.map((item) => item.planId);
+  ids.value = selection.map((item) => item.planUid);
   selectedRow.value = selection.length === 1 ? selection[0] : null;
   single.value = selection.length != 1;
   multiple.value = !selection.length;
@@ -214,22 +193,23 @@ const handleAdd = () => {
   dialog.title = '添加预案';
 };
 
-const handleUpdate = (row: PlanVO) => {
+const handleUpdate = async(row: PlanVO) => {
   if (row) {
     resetForm();
-    Object.assign(form, row);
+    const res = await getPlanDetail(row.planId);
+    form.value = res.data;
     dialog.visible = true;
     dialog.title = '修改预案';
   }
 };
 
-const handleDelete = async (row: PlanVO) => {
-  try {
-    await deleteReport(row.planId);
-    ElMessage.success('删除成功');
+const handleDelete = async (row) => {
+  const planUid = row && row.planUid ? [row?.planUid] : ids.value;
+  const [err] = await to(proxy?.$modal.confirm('是否确认删除选择的数据项?') as any);
+  if (!err) {
+    await deletePlan(planUid);
     getList();
-  } catch (error) {
-    ElMessage.error('删除失败');
+    proxy?.$modal.msgSuccess('删除成功');
   }
 };
 
@@ -243,19 +223,12 @@ const handleView = (row: PlanVO) => {
 const submitForm = () => {
   demoFormRef.value?.validate(async (valid) => {
     if (valid) {
-      buttonLoading.value = true;
       try {
-        if (form.planId) {
-          await updateReport(form);
-          ElMessage.success('更新成功');
-        } else {
-          await addReport(form);
-          ElMessage.success('添加成功');
-        }
+        buttonLoading.value = true;
+        form.value.planId ? await updateReport(form.value) : await addReport(form.value);
+        proxy?.$modal.msgSuccess(form.value.planId ? '修改成功' : '新增成功');
         dialog.visible = false;
         getList();
-      } catch (error) {
-        ElMessage.error('操作失败');
       } finally {
         buttonLoading.value = false;
       }
@@ -264,14 +237,14 @@ const submitForm = () => {
 };
 
 const resetForm = () => {
-  Object.assign(form, {
+  form.value = {
     planId: '',
     planName: '',
     planType: '',
     document: '',
     organizingUnit: '',
     publishDate: ''
-  });
+  };
   demoFormRef.value?.resetFields();
 };
 
@@ -280,10 +253,6 @@ const cancel = () => {
   dialog.visible = false;
 };
 
-const handleExport = () => {
-  ElMessage.success('导出成功');
-};
-
 onMounted(() => {
   getList();
   getDicts('mm_event_type').then((res) => {

+ 0 - 171
src/views/riskPrevention/planManage/plan.vue

@@ -1,171 +0,0 @@
-<template>
-  <!--添加或修改预案配置-->
-  <el-dialog ref="formDialogRef" v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
-    <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
-      <el-form-item label="预案编号" prop="planId">
-        <el-input v-model="form.planId" placeholder="请输入预案编号" />
-      </el-form-item>
-      <el-form-item label="预案名称" prop="planName">
-        <el-input v-model="form.planName" placeholder="请输入预案名称" />
-      </el-form-item>
-      <el-form-item label="预案类型" prop="planType">
-        <el-select v-model="form.planType" placeholder="请选择预案类型" maxlength="11">
-          <el-option label="总体应急预案" value="1" />
-          <el-option label="专项应急预案" value="2" />
-          <el-option label="部门应急预案" value="3" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="发文字号" prop="document">
-        <el-input v-model="form.document" placeholder="请输入发文字号" />
-      </el-form-item>
-      <el-form-item label="编制单位" prop="organUnit">
-        <el-input v-model="form.organUnit" placeholder="请输入编制单位" />
-      </el-form-item>
-      <el-form-item label="发布日期" prop="publish_date">
-        <el-date-picker v-model="form.publish_date" type="date" placeholder="选择发布日期" value-format="yyyy-MM-dd"></el-date-picker>
-      </el-form-item>
-    </el-form>
-    <template #footer>
-      <div class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel()">取 消</el-button>
-      </div>
-    </template>
-  </el-dialog>
-</template>
-<script setup lang="ts">
-import { ref } from 'vue';
-import api from '@/api/system/user';
-import { PlanForm, PlanVO, PlanQuery } from '@/api/system/user/types';
-const userFormRef = ref<ElFormInstance>();
-const ids = ref<Array<number | string>>([]);
-const planList = ref<PlanVO[]>();
-const loading = ref(true);
-const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const emits = defineEmits(['update:modelValue', 'getList']);
-const total = ref(0);
-import { to } from 'await-to-js';
-
-const props = defineProps({
-  modelValue: Boolean,
-  id: String
-});
-
-watch(
-  () => props.modelValue,
-  (val) => {
-    visible.value = val;
-  }
-);
-
-let visible = ref(false);
-const title = computed(() => {
-  return props.id ? '编辑演练' : '新建演练';
-});
-
-const initFormData: PlanForm = {
-  planId: undefined,
-  planName: undefined,
-  planType: undefined,
-  publish_date: undefined,
-  organUnit: undefined,
-  document: undefined
-};
-
-const initData: PageData<PlanForm, PlanQuery> = {
-  form: { ...initFormData },
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    planName: ''
-  },
-  rules: {
-    planId: [
-      { required: true, message: '预案编号不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        message: '预案编号长度必须大于1',
-        trigger: 'blur'
-      }
-    ],
-    planName: [
-      { required: true, message: '预案名称不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        max: 20,
-        message: '预案名称长度必须介于 1 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    organUnit: [
-      { required: true, message: '编制单位不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        max: 20,
-        message: '编制单位长度必须介于 1 和 20 之间1',
-        trigger: 'blur'
-      }
-    ],
-    planType: [{ required: true, message: '预案类型不能为空', trigger: 'blur' }],
-    document: [
-      { required: true, message: '发文字号不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        message: '发文字号长度必须大于1',
-        trigger: 'blur'
-      }
-    ],
-    publish_date: [{ required: true, message: '发布时间不能为空', trigger: 'change' }]
-  }
-};
-const data = reactive<PageData<PlanForm, PlanQuery>>(initData);
-
-const { queryParams, form, rules } = toRefs<PageData<PlanForm, PlanQuery>>(data);
-
-const getList = async () => {
-  loading.value = true;
-  const res = await api.listPlan(proxy?.addDateRange(queryParams.value, dateRange.value));
-  loading.value = false;
-  planList.value = res.rows;
-  total.value = res.total;
-};
-
-/** 重置操作表单 */
-const reset = () => {
-  form.value = { ...initFormData };
-  userFormRef.value?.resetFields();
-};
-/** 取消按钮 */
-const cancel = () => {
-  emits('update:modelValue', false);
-  reset();
-};
-
-/**
- * 关闭用户弹窗
- */
-const closeDialog = () => {
-  emits('update:modelValue', false);
-  resetForm();
-};
-
-const resetForm = () => {
-  userFormRef.value?.resetFields();
-  userFormRef.value?.clearValidate();
-
-  form.value.planId = undefined;
-};
-
-/**提交按钮 */
-const submitForm = () => {
-  userFormRef.value?.validate(async (valid: boolean) => {
-    if (valid) {
-      form.value.planId ? await api.updatePlan(form.value) : await api.addPlan(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
-      emits('update:modelValue', true);
-      emits('getList');
-    }
-  });
-};
-</script>

+ 178 - 844
src/views/riskPrevention/planManage/planList.vue

@@ -14,26 +14,27 @@
             <el-button v-has-permi="['system:plan:add']" type="success" plain icon="Edit" @click="planUpdate()"> 编辑 </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button v-has-permi="['system:plan:delete']" type="danger" plain icon="Delete" @click="planDelete()"> 删除预案 </el-button>
+            <el-button v-has-permi="['system:plan:delete']" type="danger" plain icon="Delete" @click="handleDelete"> 删除预案 </el-button>
           </el-col>
         </el-row>
-        <plan :id="dialog0.id" v-model="dialog0.visible" />
         <div class="line" style="background: #e7e7e7; width: auto; height: 0.6px; position: relative"></div>
         <h3>基础信息</h3>
         <div style="white-space: nowrap">
-          <el-text :lg="15" class="mx-1">附件</el-text>
-          <el-text :lg="15" class="mx-2" type="primary">
-            <a v-if="detailData.file_list && detailData.file_list[0]" :href="detailData.file_list[0].file_url">{{
-              detailData.file_list[0].file_name_desc
-            }}</a>
+          <el-text :lg="15" class="mx-1">附件</el-text>
+          <el-text v-if="detailData.fileList && detailData.fileList[0]" :lg="15" class="mx-2" type="primary" style="cursor: pointer">
+            <span @click="handleDownload(detailData.fileList[0])">
+              {{ detailData.fileList[0]?.name }}
+            </span>
           </el-text>
         </div>
         <el-card style="margin-top: 10px" shadow="hover">
           <el-descriptions title="">
             <el-descriptions-item key="planId" label="预案编号:">{{ detailData.planId }}</el-descriptions-item>
-            <el-descriptions-item key="planType" label="预案类型:">{{ detailData.planType }}</el-descriptions-item>
-            <el-descriptions-item key="publish_date" label="发布日期:">{{ detailData.publish_date }}</el-descriptions-item>
-            <el-descriptions-item key="organUnit" label="编制单位:">{{ detailData.organUnit }}</el-descriptions-item>
+            <el-descriptions-item key="planType" label="预案类型:">
+              <dict-tag :options="plan_type" :value="detailData.planType" style="display: inline-block" />
+            </el-descriptions-item>
+            <el-descriptions-item key="publishDate" label="发布日期:">{{ detailData.publishDate }}</el-descriptions-item>
+            <el-descriptions-item key="organizingUnit" label="编制单位:">{{ detailData.organizingUnit }}</el-descriptions-item>
             <el-descriptions-item key="document" label="发文字号:">{{ detailData.document }}</el-descriptions-item>
           </el-descriptions>
         </el-card>
@@ -97,431 +98,127 @@
       <el-col :lg="30" :xs="24">
         <!-- 培训记录 -->
         <h3>培训记录</h3>
-        <el-card shadow="hover">
-          <template #header>
-            <el-row :gutter="10">
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:add']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
-                  修改
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:delete']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
-                  删除
-                </el-button>
-              </el-col>
-              <right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
-            </el-row>
-          </template>
-
-          <el-table
-            v-loading="loading3"
-            :default-sort="{ prop: 'startTime,endTime', order: 'descending' }"
-            :data="userList"
-            @selection-change="handleSelectionChange"
-          >
-            <el-table-column type="selection" width="50" align="center" />
-            <el-table-column v-if="columns[0].visible" key="textId" label="记录编号" align="center" prop="textId" />
-            <el-table-column v-if="columns[1].visible" key="theme" label="培训主题" align="center" prop="theme" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[2].visible" key="unitName" label="培训单位" align="center" prop="unitName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[3].visible" key="Content" label="培训内容" align="center" prop="Content" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[4].visible" key="peopleNum" label="参与人数" align="center" prop="peopleNum" width="120" />
-            <el-table-column v-if="columns[4].visible" key="trainingWay" label="培训方式" align="center" prop="trainingWay" width="120" />
-            <el-table-column v-if="columns[5].visible" label="开始时间" sortable align="center" prop="startTime" width="160">
-              <template #default="scope">
-                <span>{{ scope.row.startTime }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column v-if="columns[6].visible" label="结束时间" sortable align="center" prop="endTime" width="160">
-              <template #default="scope">
-                <span>{{ scope.row.endTime }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column v-if="columns[7].visible" key="address" label="培训地点" align="center" prop="address" :show-overflow-tooltip="true" />
-            <el-table-column fixed="right" label="操作" width="100">
-              <template #default="scope">
-                <el-tooltip v-if="scope.row.textId !== 1" content="修改" placement="top">
-                  <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
-                </el-tooltip>
-                <el-tooltip v-if="scope.row.textId !== 1" content="删除" placement="top">
-                  <el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
-                </el-tooltip>
-              </template>
-            </el-table-column>
-          </el-table>
-          <pagination
-            v-show="total3 > 0"
-            v-model:page="queryParams3.page"
-            v-model:limit="queryParams3.pageSize"
-            :total="total3"
-            @pagination="getList3"
-          />
-        </el-card>
+        <TrainingRecord :id="planId" />
       </el-col>
       <el-col :lg="30" :xs="24">
         <!-- 演练记录 -->
         <h3>演练记录</h3>
-        <el-card shadow="hover">
-          <template #header>
-            <el-row :gutter="10">
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:drill:add']" type="primary" plain icon="Plus" @click="drillAdd()">新增</el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:drill:add']" type="success" plain :disabled="single" icon="Edit" @click="drillUpdate()">
-                  修改
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:drill:delete']" type="danger" plain :disabled="multiple" icon="Delete" @click="drillDelete()">
-                  删除
-                </el-button>
-              </el-col>
-              <right-toolbar v-model:showSearch="showSearch" :columns="columns0" :search="true" @query-table="getList2"></right-toolbar>
-            </el-row>
-            <drill :id="dialog3.id" v-model="dialog3.visible" @getlist="getList2" />
-          </template>
-          <el-table v-loading="loading2" :data="drillList" @selection-change="handleSelectionChangeDrill">
-            <el-table-column type="selection" width="50" align="center" />
-            <el-table-column v-if="columns0[0].visible" key="drillId" label="演练编号" align="center" prop="drillId" />
-            <el-table-column
-              v-if="columns0[1].visible"
-              key="drillName"
-              label="演练名称"
-              align="center"
-              prop="drillName"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns0[2].visible"
-              key="drillUnit"
-              label="演练单位"
-              align="center"
-              prop="drillUnit"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column v-if="columns0[3].visible" key="year" label="年度" align="center" prop="year" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns0[4].visible" label="演练时间" align="center" prop="drillTime" width="160">
-              <template #default="scope">
-                <span>{{ scope.row.year }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column
-              v-if="columns0[5].visible"
-              key="drillAddress"
-              label="演练地点"
-              align="center"
-              prop="drillAddress"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns0[6].visible"
-              key="drillProject"
-              label="演练方案"
-              align="center"
-              prop="drillProject"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns0[7].visible"
-              key="drillVideo"
-              label="演练视频"
-              align="center"
-              prop="drillVideo"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns0[8].visible"
-              key="drillPicture"
-              label="演练图片"
-              align="center"
-              prop="drillPicture"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column fixed="right" label="操作" width="100">
-              <template #default="scope">
-                <el-tooltip v-if="scope.row.drillId !== 1" content="修改" placement="top">
-                  <el-button v-hasPermi="['system:drill:edit']" link type="primary" icon="Edit" @click="drillUpdate(scope.row)"></el-button>
-                </el-tooltip>
-                <el-tooltip v-if="scope.row.drillId !== 1" content="删除" placement="top">
-                  <el-button v-hasPermi="['system:drill:remove']" link type="primary" icon="Delete" @click="drillDelete(scope.row)"></el-button>
-                </el-tooltip>
-              </template>
-            </el-table-column>
-          </el-table>
-
-          <pagination v-show="total2 > 0" v-model:page="drillForm.page" v-model:limit="drillForm.pageSize" :total="total2" @pagination="getList2" />
-        </el-card>
+        <DrillRecord :id="planId" />
       </el-col>
       <el-col :lg="30" :xs="24">
         <!-- 响应记录 -->
         <h3>响应记录</h3>
-        <el-card shadow="hover">
-          <el-table v-loading="loading4" @selection-change="handleSelectionChangeResponse">
-            <el-table-column type="selection" width="50" align="center" />
-            <el-table-column v-if="columns1[0].visible" key="eventId" label="事件编号" align="center" prop="eventId" />
-            <el-table-column
-              v-if="columns1[1].visible"
-              key="eventName"
-              label="事件名称"
-              align="center"
-              prop="eventName"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns1[2].visible"
-              key="eventType"
-              label="事件类型"
-              align="center"
-              prop="eventType"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns1[3].visible"
-              key="responseUnit"
-              label="响应单位"
-              align="center"
-              prop="responseUnit"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns1[4].visible"
-              key="eventAddress"
-              label="事件地点"
-              align="center"
-              prop="eventAddress"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column
-              v-if="columns1[5].visible"
-              key="responseLevel"
-              label="响应级别"
-              align="center"
-              prop="responseLevel"
-              :show-overflow-tooltip="true"
-            />
-            <el-table-column v-if="columns1[6].visible" label="响应开始时间" align="center" prop="responseStartTime" width="160">
-              <template #default="scope">
-                <span>{{ scope.row.responseStartTime }}</span>
-              </template>
-            </el-table-column>
-            <el-table-column v-if="columns1[7].visible" label="响应开始时间" align="center" prop="responseEndTime" width="160">
-              <template #default="scope">
-                <span>{{ scope.row.responseEndTime }}</span>
-              </template>
-            </el-table-column>
-          </el-table>
-          <pagination
-            v-show="total4 > 0"
-            v-model:page="queryParams.pageNum"
-            v-model:limit="queryParams.pageSize"
-            :total="total4"
-            @pagination="getListResponse"
-          />
-        </el-card>
+<!--        <el-card shadow="hover">-->
+<!--          <el-table v-loading="loading4" @selection-change="handleSelectionChangeResponse">-->
+<!--            <el-table-column type="selection" width="50" align="center" />-->
+<!--            <el-table-column v-if="columns1[0].visible" key="eventId" label="事件编号" align="center" prop="eventId" />-->
+<!--            <el-table-column-->
+<!--              v-if="columns1[1].visible"-->
+<!--              key="eventName"-->
+<!--              label="事件名称"-->
+<!--              align="center"-->
+<!--              prop="eventName"-->
+<!--              :show-overflow-tooltip="true"-->
+<!--            />-->
+<!--            <el-table-column-->
+<!--              v-if="columns1[2].visible"-->
+<!--              key="eventType"-->
+<!--              label="事件类型"-->
+<!--              align="center"-->
+<!--              prop="eventType"-->
+<!--              :show-overflow-tooltip="true"-->
+<!--            />-->
+<!--            <el-table-column-->
+<!--              v-if="columns1[3].visible"-->
+<!--              key="responseUnit"-->
+<!--              label="响应单位"-->
+<!--              align="center"-->
+<!--              prop="responseUnit"-->
+<!--              :show-overflow-tooltip="true"-->
+<!--            />-->
+<!--            <el-table-column-->
+<!--              v-if="columns1[4].visible"-->
+<!--              key="eventAddress"-->
+<!--              label="事件地点"-->
+<!--              align="center"-->
+<!--              prop="eventAddress"-->
+<!--              :show-overflow-tooltip="true"-->
+<!--            />-->
+<!--            <el-table-column-->
+<!--              v-if="columns1[5].visible"-->
+<!--              key="responseLevel"-->
+<!--              label="响应级别"-->
+<!--              align="center"-->
+<!--              prop="responseLevel"-->
+<!--              :show-overflow-tooltip="true"-->
+<!--            />-->
+<!--            <el-table-column v-if="columns1[6].visible" label="响应开始时间" align="center" prop="responseStartTime" width="160">-->
+<!--              <template #default="scope">-->
+<!--                <span>{{ scope.row.responseStartTime }}</span>-->
+<!--              </template>-->
+<!--            </el-table-column>-->
+<!--            <el-table-column v-if="columns1[7].visible" label="响应开始时间" align="center" prop="responseEndTime" width="160">-->
+<!--              <template #default="scope">-->
+<!--                <span>{{ scope.row.responseEndTime }}</span>-->
+<!--              </template>-->
+<!--            </el-table-column>-->
+<!--          </el-table>-->
+<!--          <pagination-->
+<!--            v-show="total4 > 0"-->
+<!--            v-model:page="queryParams.pageNum"-->
+<!--            v-model:limit="queryParams.pageSize"-->
+<!--            :total="total4"-->
+<!--            @pagination="getListResponse"-->
+<!--          />-->
+<!--        </el-card>-->
       </el-col>
     </el-row>
-    <!-- 添加或修改培训记录配置对话框 -->
-    <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
-      <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训主题" prop="theme">
-              <el-input v-model="form.theme" placeholder="请输入培训主题" maxlength="30" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训单位" prop="unitName">
-              <el-input v-model="form.unitName" placeholder="请输入培训单位" maxlength="30" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训方式" prop="trainingWay">
-              <el-select v-model="form.trainingWay" placeholder="请选择培训方式" maxlength="11">
-                <el-option label="线上培训" value="1" />
-                <el-option label="线下培训" value="2" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="参与人数" prop="peopleNum">
-              <el-input v-model="form.peopleNum" placeholder="请输入参与人数" maxlength="11" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20" class="block">
-            <el-form-item label="开始时间" prop="startTime">
-              <el-date-picker v-model="form.startTime" :shortcuts="shortcuts" placeholder="请选择开始时间" maxlength="11" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20" class="block">
-            <el-form-item label="结束时间" prop="endTime">
-              <el-date-picker v-model="form.endTime" :shortcuts="shortcuts" placeholder="请选择开始时间" maxlength="11" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训地点" prop="address">
-              <el-input v-model="form.address" placeholder="请输入培训地点" maxlength="30" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训内容" prop="Content">
-              <el-input v-model="form.Content" type="textarea" placeholder="请输入内容"></el-input>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel()">取 消</el-button>
-        </div>
-      </template>
-    </el-dialog>
-
-    <!-- 用户导入对话框 -->
-    <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
-      <el-upload
-        ref="uploadRef"
-        :limit="1"
-        accept=".xlsx, .xls"
-        :headers="upload.headers"
-        :action="upload.url + '?updateSupport=' + upload.updateSupport"
-        :disabled="upload.isUploading"
-        :on-progress="handleFileUploadProgress"
-        :on-success="handleFileSuccess"
-        :auto-upload="false"
-        drag
-      >
-        <el-icon class="el-icon--upload">
-          <i-ep-upload-filled />
-        </el-icon>
-        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
-        <template #tip>
-          <div class="text-center el-upload__tip">
-            <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
-            <span>仅允许导入xls、xlsx格式文件。</span>
-            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
-          </div>
-        </template>
-      </el-upload>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel()">取 消</el-button>
-        </div>
-      </template>
-    </el-dialog>
-    <!-- 添加或修改培训记录配置对话框 -->
-    <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
-      <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训主题" prop="theme">
-              <el-input v-model="form.theme" placeholder="请输入培训主题" maxlength="30" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训单位" prop="unitName">
-              <el-input v-model="form.unitName" placeholder="请输入培训单位" maxlength="30" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训方式" prop="trainingWay">
-              <el-select v-model="form.trainingWay" placeholder="请选择培训方式" maxlength="11">
-                <el-option label="线上培训" value="1" />
-                <el-option label="线下培训" value="2" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="参与人数" prop="peopleNum">
-              <el-input v-model="form.peopleNum" placeholder="请输入参与人数" maxlength="11" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20" class="block">
-            <el-form-item label="开始时间" prop="startTime">
-              <el-date-picker v-model="form.startTime" :shortcuts="shortcuts" placeholder="请选择开始时间" maxlength="11" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20" class="block">
-            <el-form-item label="结束时间" prop="endTime">
-              <el-date-picker v-model="form.endTime" :shortcuts="shortcuts" placeholder="请选择开始时间" maxlength="11" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训地点" prop="address">
-              <el-input v-model="form.address" placeholder="请输入培训地点" maxlength="30" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="20">
-            <el-form-item label="培训内容" prop="Content">
-              <el-input v-model="form.Content" type="textarea" placeholder="请输入内容"></el-input>
-            </el-form-item>
-          </el-col>
-        </el-row>
+    <!-- 修改弹窗 -->
+    <el-dialog v-model="visible" title="修改预案" width="500px" append-to-body>
+      <el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="预案名称" prop="planName">
+          <el-input v-model="form.planName" placeholder="请输入预案名称" />
+        </el-form-item>
+        <el-form-item label="预案类型" prop="planType">
+          <el-select v-model="form.planType" placeholder="请选择预案类型" clearable>
+            <el-option v-for="item in plan_type" :key="item.value" :label="item.label" :value="item.value"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发布日期" prop="publishDate">
+          <el-date-picker v-model="form.publishDate" type="date" placeholder="选择发布日期" value-format="YYYY-MM-DD"></el-date-picker>
+        </el-form-item>
+        <el-form-item label="编制单位" prop="organizingUnit">
+          <el-input v-model="form.organizingUnit" placeholder="请输入编制单位" />
+        </el-form-item>
+        <el-form-item label="发文字号" prop="document">
+          <el-input v-model="form.document" placeholder="请输入发文字号" />
+        </el-form-item>
+        <el-form-item label="预案附件" prop="fileList">
+          <file-upload v-model="form.fileList" :limit="1" :file-type="['pdf', 'doc', 'docx', 'xls', 'xlsx']" />
+        </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel()">取 消</el-button>
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确定</el-button>
+          <el-button @click="cancel">取消</el-button>
         </div>
       </template>
     </el-dialog>
   </div>
 </template>
 
-<script setup name="User" lang="ts">
-import api from '@/api/system/user';
-import { UserForm, UserQuery, UserVO, PlanVO, DrillVO, ResponseVO, PlanForm } from '@/api/system/user/types';
-import { DeptVO } from '@/api/system/dept/types';
-import { RoleVO } from '@/api/system/role/types';
-import { PostQuery, PostVO } from '@/api/system/post/types';
-import { treeselect } from '@/api/system/dept';
-import { globalHeaders } from '@/utils/request';
+<script setup name="planList" lang="ts">
 import { to } from 'await-to-js';
-import { optionselect } from '@/api/system/post';
 import type { TabsPaneContext } from 'element-plus';
-import { ArrowLeft } from '@element-plus/icons-vue';
-import { useRouter } from 'vue-router';
-import { reactive } from 'vue';
-import { getDrillList, getPlanDetail, getResponseDetail, getTrainingList } from '@/api/riskPrevention/planManage';
-import drill from './drill.vue';
-import { fetchReportDetail } from "@/api/kenowledge";
+import { download2 } from '@/utils/request';
+import { deletePlan, getPlanDetail, updateReport } from '@/api/riskPrevention/planManage';
+import TrainingRecord from './TrainingRecord.vue';
+import DrillRecord from './DrillRecord.vue';
+
 const router = useRouter();
 
 const goBack = () => {
-  router.go(-1);
+  proxy?.$tab.closePage();
 };
 
 const containerRef = ref<HTMLElement | null>(null);
@@ -535,467 +232,104 @@ const handleClick2 = (tab: TabsPaneContext, event: Event) => {
   console.log(tab, event);
 };
 
-const handleClick = (tab: TabsPaneContext, event: Event) => {
-  console.log(tab, event);
-};
-
 /***培训记录编辑界面时间选择 */
-
-const shortcuts = [
-  {
-    text: '今天',
-    value: new Date()
-  },
-  {
-    text: '昨天',
-    value: () => {
-      const date = new Date();
-      date.setDate(date.getDate() - 1);
-      return date;
-    }
-  },
-  {
-    text: '一周前',
-    value: () => {
-      const date = new Date();
-      date.setDate(date.getDate() - 7);
-      return date;
-    }
-  }
-];
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
-const userList = ref<UserVO[]>();
-const loading4 = ref(false);
-const loading3 = ref(false);
-const total4 = ref(0);
-const total3 = ref(0);
-const drillList = ref<DrillVO[]>();
-const loading2 = ref(false);
-const total2 = ref(0);
-const responseList = ref<ResponseVO[]>();
-const loading = ref(true);
-const showSearch = ref(true);
-const ids = ref<Array<number | string>>([]);
-const single = ref(true);
-const multiple = ref(true);
-const total = ref(0);
-const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
-const Content = ref('');
-const initPassword = ref<string>('');
-const postOptions = ref<PostVO[]>([]);
-/*** 用户导入参数 */
-const upload = reactive<ImportOption>({
-  // 是否显示弹出层(用户导入)
-  open: false,
-  // 弹出层标题(用户导入)
-  title: '',
-  // 是否禁用上传
-  isUploading: false,
-  // 是否更新已经存在的用户数据
-  updateSupport: 0,
-  // 设置上传的请求头部
-  headers: globalHeaders(),
-  // 上传的地址
-  url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
-});
-// 培训列显隐信息
-const columns = ref<FieldOption[]>([
-  { key: 0, label: `培训编号`, visible: false, children: [] },
-  { key: 1, label: `培训主题`, visible: true, children: [] },
-  { key: 2, label: `培训单位`, visible: true, children: [] },
-  { key: 3, label: `培训内容`, visible: true, children: [] },
-  { key: 4, label: `参与人数`, visible: true, children: [] },
-  { key: 5, label: `开始时间`, visible: true, children: [] },
-  { key: 6, label: `结束时间`, visible: true, children: [] },
-  { key: 7, label: `培训地点`, visible: true, children: [] }
-]);
+const { plan_type } = toRefs<any>(proxy?.useDict('plan_type'));
 
-// 演练列显隐信息
-const columns0 = ref<FieldOption[]>([
-  { key: 0, label: `演练编号`, visible: false, children: [] },
-  { key: 1, label: `演练名称`, visible: true, children: [] },
-  { key: 2, label: `演练单位`, visible: true, children: [] },
-  { key: 3, label: `年度`, visible: true, children: [] },
-  { key: 4, label: `演练时间`, visible: true, children: [] },
-  { key: 5, label: `演练地点`, visible: true, children: [] },
-  { key: 6, label: `演练方案`, visible: true, children: [] },
-  { key: 7, label: `演练视频`, visible: true, children: [] },
-  { key: 8, label: `演练图片`, visible: true, children: [] }
-]);
-// 响应列显隐信息
-const columns1 = ref<FieldOption[]>([
-  { key: 0, label: `事件编号`, visible: false, children: [] },
-  { key: 1, label: `事件名称`, visible: true, children: [] },
-  { key: 2, label: `事件类型`, visible: true, children: [] },
-  { key: 3, label: `响应单位`, visible: true, children: [] },
-  { key: 4, label: `事件地点`, visible: true, children: [] },
-  { key: 5, label: `响应级别`, visible: true, children: [] },
-  { key: 6, label: `响应开始时间`, visible: true, children: [] },
-  { key: 7, label: `响应结束时间`, visible: true, children: [] }
-]);
-const deptTreeRef = ref<ElTreeInstance>();
-const queryFormRef = ref<ElFormInstance>();
-const userFormRef = ref<ElFormInstance>();
-const uploadRef = ref<ElUploadInstance>();
-const formDialogRef = ref<ElDialogInstance>();
-
-const dialog = reactive<DialogOption>({
-  visible: false,
-  title: ''
-});
-const dialog0 = reactive<DialogOption>({
-  visible: false,
-  id: ''
-});
-const dialog3 = reactive<DialogOption>({
-  visible: false,
-  id: ''
-});
-
-const initFormData: UserForm = {
-  textId: undefined,
-  theme: '',
-  unitName: undefined,
-  peopleNum: undefined
-};
-
-const initData: PageData<UserForm, UserQuery> = {
-  form2: { ...initFormData },
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    theme: '',
-    unitName: ''
-  },
-  rules: {
-    theme: [
-      { required: true, message: '培训主题不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        max: 20,
-        message: '培训主题长度必须介于 1 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    unitName: [
-      { required: true, message: '培训单位不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        max: 20,
-        message: '培训主题长度必须介于 1 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    peopleNum: [
-      { required: true, message: '参与人数不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        message: '参与人数长度必须大于1',
-        trigger: 'blur'
-      }
-    ],
-    trainingWay: [{ required: true, message: '培训方式不能为空', trigger: 'blur' }],
-    address: [
-      { required: true, message: '培训地点不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        max: 20,
-        message: '培训主题长度必须介于 1 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    Content: [
-      { required: true, message: '培训内容不能为空', trigger: 'blur' },
-      {
-        min: 1,
-        message: '参与人数长度必须大于1',
-        trigger: 'blur'
-      }
-    ],
-    startTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
-    endTime: [{ required: true, message: '结束时间不能为空', trigger: 'change' }]
-  }
-};
-const data = reactive<PageData<UserForm, UserQuery>>(initData);
-
-
-const { queryParams, form2, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
-//演练
-const drillForm = reactive<DrillForm>({
-  pageNum: 1,
-  pageSize: 10,
-  planNum: 'YJYA0000000001'
-});
-//培训
-const queryParams3 = reactive({
-  page: 1,
-  pageSize: 10,
-  planNum: 'YJYA0000000001'
+// 预案编辑
+let detailData = ref({
+  planId: '',
+  planName: '',
+  planType: '',
+  publishDate: '',
+  organizingUnit: '',
+  document: '',
+  fileList: []
 });
-//响应
-const responseParams = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  planId: 'YJYA0000000001'
+let planId = ref();
+let visible = ref(false);
+const demoFormRef = ref(null);
+const buttonLoading = ref(false);
+let form = ref({
+  planId: '',
+  planName: '',
+  planType: '',
+  document: '',
+  organizingUnit: '',
+  publishDate: '',
+  fileList: []
 });
-
-/** 通过条件过滤节点  */
-const filterNode = (value: string, data: any) => {
-  if (!value) return true;
-  return data.label.indexOf(value) !== -1;
-};
-/** 根据名称筛选培训内容树 */
-watchEffect(
-  () => {
-    deptTreeRef.value?.filter(Content.value);
-  },
-  {
-    flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
-  }
-);
-
-/** 查询培训列表 */
-const getList3 = async () => {
-  loading3.value = true;
-  const res = await getTrainingList(queryParams3);
-  loading3.value = false;
-  userList.value = res.data;
-  total3.value = res.total;
-};
-/** 查询演练列表 */
-/*const getList2 = async () => {
-  loading2.value = true;
-  const res = await api.listDrill(proxy?.addDateRange(drillForm.value, dateRange.value));
-  loading2.value = false;
-  drillList.value = res.rows;
-  total2.value = res.total;
-};*/
-const getList2 = async () => {
-  loading2.value = true;
-  const res = await getDrillList(drillForm);
-  loading2.value = false;
-  res.data.forEach((item) => {
-    item.drillPicture = item.drillPicture[0]?.file_name_desc;
-    item.drillVideo = item.drillVideo[0]?.file_name_desc;
-  });
-  drillList.value = res.data;
-  total2.value = res.total;
+const rules = reactive({
+  planName: [{ required: true, message: '预案名称不能为空', trigger: 'blur' }],
+  planType: [{ required: true, message: '预案类型不能为空', trigger: 'blur' }],
+  document: [{ required: true, message: '发文字号不能为空', trigger: 'blur' }],
+  organizingUnit: [{ required: true, message: '编制单位不能为空', trigger: 'blur' }],
+  publishDate: [{ required: true, message: '发布日期不能为空', trigger: 'blur' }]
+})
+/** 修改预案按钮操作 */
+const planUpdate = async () => {
+  resetForm();
+  const res = await getPlanDetail(planId.value);
+  form.value = res.data;
+  visible.value = true;
 };
-
-/** 查询响应列表 */
-/**const getListResponse = async () => {
-  loading4.value = true;
-  const res = await api.listResponse(proxy?.addDateRange(queryParams.value, dateRange.value));
-  loading4.value = false;
-  responseList.value = res.rows;
-  total.value = res.total;
-};*/
-const getListResponse = async () => {
-  loading4.value = true;
-  const res = await getResponseDetail(responseParams);
-  loading4.value = false;
-  // res.data.forEach(item => {
-  //   item.drillPicture = item.drillPicture[0].file_name_desc
-  //   item.drillVideo = item.drillVideo[0].file_name_desc
-  // })
-  responseList.value = res.data;
-  total4.value = res.total;
+const resetForm = () => {
+  form.value = {
+    planId: '',
+    planName: '',
+    planType: '',
+    document: '',
+    organizingUnit: '',
+    publishDate: ''
+  };
+  demoFormRef.value?.resetFields();
 };
 /** 删除按钮操作 */
-const handleDelete = async (row?: UserVO) => {
-  const textIds = row?.textId || ids.value;
-  const [err] = await to(proxy?.$modal.confirm('是否确认删除记录编号为"' + textIds + '"的数据项?') as any);
+const handleDelete = async () => {
+  const [err] = await to(proxy?.$modal.confirm('是否确认删除该条预案?') as any);
   if (!err) {
-    await api.delUser(textIds);
-    await getList3();
+    await deletePlan([detailData.value.planUid]);
     proxy?.$modal.msgSuccess('删除成功');
+    router.go(-1);
   }
 };
-
-/** 选择条数  */
-const handleSelectionChange = (selection: UserVO[]) => {
-  ids.value = selection.map((item) => item.textId);
-  single.value = selection.length != 1;
-  multiple.value = !selection.length;
-};
-const handleSelectionChangeDrill = (selection: DrillVO[]) => {
-  ids.value = selection.map((item) => item.drillId);
-  single.value = selection.length != 1;
-  multiple.value = !selection.length;
-};
-const handleSelectionChangeResponse = (selection: ResponseVO[]) => {
-  ids.value = selection.map((item) => item.eventId);
-  single.value = selection.length != 1;
-  multiple.value = !selection.length;
-};
-/** 导入按钮操作 */
-const handleImport = () => {
-  upload.title = '用户导入';
-  upload.open = true;
-};
-/** 导出按钮操作 */
-const handleExport = () => {
-  proxy?.download(
-    'system/user/export',
-    {
-      ...queryParams.value
-    },
-    `user_${new Date().getTime()}.xlsx`
-  );
-};
-/** 下载模板操作 */
-const importTemplate = () => {
-  proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
-};
-
-/**文件上传中处理 */
-const handleFileUploadProgress = () => {
-  upload.isUploading = true;
-};
-/** 文件上传成功处理 */
-const handleFileSuccess = (response: any, file: UploadFile) => {
-  upload.open = false;
-  upload.isUploading = false;
-  uploadRef.value?.handleRemove(file);
-  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
-    dangerouslyUseHTMLString: true
-  });
-  getList3();
-};
-
-/** 提交上传文件 */
-function submitFileForm() {
-  uploadRef.value?.submit();
-}
-
-/** 重置操作表单 */
-const reset = () => {
-  form.value = { ...initFormData };
-  userFormRef.value?.resetFields();
-};
-/** 取消按钮 */
 const cancel = () => {
-  dialog.visible = false;
-  reset();
-};
-
-/** 修改按钮操作 */
-const handleUpdate = async (row?: UserForm) => {
-  reset();
-  //const textId = row?.textId || ids.value[0];
-  //const { data } = await api.getUser(textId);
-  dialog.visible = true;
-  dialog.title = '修改培训记录';
-  Object.assign(form.value, data.user);
+  resetForm();
+  visible.value = false;
 };
 
-/** 提交培训按钮 */
+/** 提交修改 */
 const submitForm = () => {
-  userFormRef.value?.validate(async (valid: boolean) => {
+  demoFormRef.value?.validate(async (valid) => {
     if (valid) {
-      form.value.textId ? await api.updateUser(form.value) : await api.addUser(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
-      dialog.visible = false;
-      await getList3();
+      try {
+        buttonLoading.value = true;
+        await updateReport(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+        visible.value = false;
+        getPlanDetail(planId.value).then((res) => {
+          detailData.value = res.data;
+        });
+      } finally {
+        buttonLoading.value = false;
+      }
     }
   });
 };
 
-/**
- * 关闭培训弹窗
- */
-const closeDialog = () => {
-  dialog.visible = false;
-  resetForm();
+const baseUrl = import.meta.env.VITE_APP_BASE_API;
+// 下载方法
+const handleDownload = (file: any) => {
+  download2(baseUrl + '/api/file/download/' + file.url, file.name);
 };
 
-/**
- * 重置表单
- */
-const resetForm = () => {
-  userFormRef.value?.resetFields();
-  userFormRef.value?.clearValidate();
-  form.value.textId = undefined;
-};
-/** 新增按钮操作 */
-const handleAdd = async () => {
-  reset();
-  //const { data } = await api.getUser();
-  dialog.visible = true;
-  dialog.title = '新增培训记录';
-};
-
-let detailData = ref({
-  planId: '',
-  planName: '',
-  planType: '',
-  publish_date: '',
-  organUnit: '',
-  document: '',
-});
-
 onMounted(() => {
-  const planId = route.query.planId;
-  drillForm.planNum = planId;
-  queryParams3.planNum = planId;
-  getPlanDetail(planId).then((res) => {
+  planId.value = route.query.planId;
+  getPlanDetail(planId.value).then((res) => {
     detailData.value = res.data;
   });
-  getList2(); // 初始化列表数据
-  getList3(); // 初始化列表数据
-  proxy?.getConfigKey('sys.user.initPassword').then((response) => {
-    initPassword.value = response.data;
-  });
 });
-
-async function handleDeptChange(value: number | string) {
-  const response = await optionselect(value);
-  postOptions.value = response.data;
-}
-
-/** 新增预案按钮操作
-const planAdd = () => {
-  dialog0.visible = true;
-  dialog0.id = '';
-};*/
-/** 修改预案按钮操作 */
-const planUpdate = (row) => {
-  dialog1.visible = true;
-  dialog0.id = row.planId;
-};
-/** 删除预案按钮操作 */
-const planDelete = async (row?: PlanVO) => {
-  const planIds = row?.planId || ids.value;
-  const [err] = await to(proxy?.$modal.confirm('是否确认删除记录编号为"' + planIds + '"的数据项?') as any);
-  if (!err) {
-    await api.delPlan(planIds);
-    await getListResponse();
-    proxy?.$modal.msgSuccess('删除成功');
-  }
-};
-
-/** 新增演练按钮操作 */
-const drillAdd = () => {
-  dialog3.visible = true;
-  dialog3.id = '';
-};
-/** 修改演练按钮操作 */
-const drillUpdate = (row) => {
-  dialog3.visible = true;
-  dialog3.id = row.drillId;
-};
-/** 删除演练按钮操作 */
-const drillDelete = async (row?: DrillVO) => {
-  const drillIds = row?.drillId || ids.value;
-  const [err] = await to(proxy?.$modal.confirm('是否确认删除记录编号为"' + drillIds + '"的数据项?') as any);
-  if (!err) {
-    await api.delPlan(drillIds);
-    await getList3();
-    proxy?.$modal.msgSuccess('删除成功');
-  }
-};
 </script>
 
 <style lang="scss" scoped>