فهرست منبع

feat: 轮询规则菜单功能完成

liujt 1 ماه پیش
والد
کامیت
539fadfc73

+ 6 - 6
src/api/config/scheduledTasks.js

@@ -57,16 +57,16 @@ export async function batchDeleteJob(ids) {
 
 // 导出任务
 export async function exportJob(params) {
-  const res = await request.download('/infra/job/export-excel', { params })
-  if (res.data.code == 0) {
-    return res.data.data
+  const res = await request.get('/eam/job/export-excel', { params })
+  if (res) {
+    return res
   }
-  return Promise.reject(new Error(res.data.message))
+  return Promise.reject(new Error(res.message))
 }
 
 // 修改任务状态
 export async function updateJobStatus(id, status) {
-  const res = await request.put('/eam/job/updateStatus', { id, status })
+  const res = await request.put(`/eam/job/updateStatus?id=${id}&status=${status}`)
   if (res.data.code == 0) {
     return res.data.data
   }
@@ -84,7 +84,7 @@ export async function runJob(id) {
 
 // 获取任务后续执行时间
 export async function getJobNextTimes(id) {
-  const res = await request.get('/infra/job/get_next_times?id=' + id)
+  const res = await request.get('/eam/job/get_next_times?id=' + id)
   if (res.data.code == 0) {
     return res.data.data
   }

+ 73 - 0
src/api/config/videoPolling.js

@@ -0,0 +1,73 @@
+import request from '@/utils/request'
+
+// 查询视频轮询规则列表
+export async function getVideoRulePage(data) {
+  const res = await request.post('/eam/video-rule/page', data)
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 查询视频轮询规则详情
+export async function getVideoRule(id) {
+  const res = await request.get(`/eam/video-rule/getById/${id}`)
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 查询视频轮询规则列表
+export async function getVideoRuleList() {
+  const res = await request.get('/eam/video-rule/list')
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 新增视频轮询规则
+export async function createVideoRule(data) {
+  const res = await request.post('/eam/video-rule/add', data)
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 修改视频轮询规则
+export async function updateVideoRule(data) {
+  const res = await request.post('/eam/video-rule/update', data)
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 删除视频轮询规则
+export async function deleteVideoRule(id) {
+  const res = await request.delete('/eam/video-rule/delete?id=' + id)
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 导出视频轮询规则 Excel
+export async function exportVideoRule(params) {
+  const res = await request.download('/isp/video-rule/export-excel', { params })
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}
+
+// 获取摄像头列表
+export async function listByType() {
+  const res = await request.get('/main/camera-info/listByType')
+  if (res.data.code == 0) {
+    return res.data.data
+  }
+  return Promise.reject(new Error(res.data.message))
+}

+ 54 - 0
src/views/config/pollingRules/components/PollingRulesSearch.vue

@@ -0,0 +1,54 @@
+<!-- 搜索表单 -->
+<template>
+  <seekPage :seekList="seekList" :formLength="4" @search="search"></seekPage>
+</template>
+
+<script>
+export default {
+  name: 'PollingRulesSearch',
+  data() {
+    return {}
+  },
+  computed: {
+    seekList() {
+      return [
+        {
+          label: '规则名称:',
+          value: 'ruleName',
+          type: 'input',
+          placeholder: '请输入规则名称'
+        },
+        {
+          label: '规则编码:',
+          value: 'ruleCode',
+          type: 'input',
+          placeholder: '请输入规则编码'
+        },
+        {
+          label: '时间间隔:',
+          value: 'forInterval',
+          type: 'input',
+          placeholder: '请输入时间间隔'
+        },
+        {
+          label: '是否重复:',
+          value: 'repeated',
+          type: 'select',
+          placeholder: '全部',
+          selectList: [
+            { label: '是', value: true },
+            { label: '否', value: false }
+          ]
+        }
+      ]
+    }
+  },
+  methods: {
+    /* 搜索 */
+    search(e) {
+      this.$emit('search', { ...e })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 84 - 0
src/views/config/pollingRules/components/detail.vue

@@ -0,0 +1,84 @@
+<template>
+  <ele-modal
+    :visible.sync="visible"
+    title="规则详情"
+    width="700px"
+    append-to-body
+    :maxable="true"
+  >
+    <el-descriptions :column="2" size="medium" border>
+      <el-descriptions-item>
+        <template slot="label">规则编码</template>
+        {{ detailData.ruleCode }}
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template slot="label">规则名称</template>
+        {{ detailData.ruleName }}
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template slot="label">时间间隔</template>
+        {{ detailData.forInterval }}
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template slot="label">是否重复</template>
+        {{ detailData.repeated ? '是' : '否' }}
+      </el-descriptions-item>
+      <el-descriptions-item>
+        <template slot="label">排序号</template>
+        {{ detailData.indexNo }}
+      </el-descriptions-item>
+      <el-descriptions-item label="关联摄像头" :span="2">
+        <template v-if="detailData.devices && detailData.devices.length">
+          {{ getDeviceNames(detailData.devices) }}
+        </template>
+        <span v-else>-</span>
+      </el-descriptions-item>
+    </el-descriptions>
+
+    <template #footer>
+      <el-button @click="visible = false">关闭</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+import * as VideoPollingApi from '@/api/config/videoPolling'
+
+export default {
+  name: 'VideoPollingDetail',
+  data() {
+    return {
+      visible: false,
+      loading: false,
+      detailData: {}
+    }
+  },
+  methods: {
+    /** 获取摄像头名称 */
+    getDeviceNames(devices) {
+      if (!devices || !devices.length) return '-'
+      return devices.map(d => d.name || d.deviceCode).join('、')
+    },
+
+    /** 打开弹窗 */
+    openForm(id) {
+      this.visible = true
+      this.loading = true
+
+      VideoPollingApi.getVideoRule(id)
+        .then((res) => {
+          res.devices = JSON.parse(res.devices || '[]')
+          this.detailData = res
+        })
+        .catch((e) => {
+          console.error(e)
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 16 - 0
src/views/config/pollingRules/components/draggable.svg

@@ -0,0 +1,16 @@
+<svg
+	t="1708944111828"
+	class="icon"
+	viewBox="0 0 1024 1024"
+	version="1.1"
+	xmlns="http://www.w3.org/2000/svg"
+	p-id="4205"
+	width="25"
+	height="25"
+>
+	<path
+		d="M128 234.666667A64 64 0 0 1 192 170.666667h640a64 64 0 0 1 0 128h-640A64 64 0 0 1 128 234.666667zM128 512a64 64 0 0 1 64-64h640a64 64 0 0 1 0 128h-640A64 64 0 0 1 128 512z m64 213.333333a64 64 0 0 0 0 128h640a64 64 0 0 0 0-128h-640z"
+		fill="#404446"
+		p-id="4206"
+	></path>
+</svg>

+ 158 - 0
src/views/config/pollingRules/components/draggable.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="draggable-container">
+    <draggable
+      :list="localDevices"
+      class="device-list"
+      animation="300"
+      @end="onDragEnd"
+    >
+      <div
+        v-for="(item, index) in localDevices"
+        :key="index"
+        class="device-item"
+        :class="{ 'is-detail': detail }"
+      >
+        <template v-if="!detail">
+          <el-select
+            v-model="item.deviceCode"
+            :disabled="disabled"
+            clearable
+            placeholder="请选择摄像头"
+          >
+            <el-option
+              v-for="camera in cameraList"
+              :key="camera.id"
+              :label="camera.name"
+              :value="camera.deviceCode"
+            />
+          </el-select>
+          <img src="./draggable.svg" class="drag-icon" />
+          <el-button
+            v-if="localDevices.length > 1"
+            type="danger"
+            size="small"
+            @click="delCamera(index)"
+          >
+            删除
+          </el-button>
+        </template>
+        <template v-else>
+          <span class="device-name">{{ getDeviceName(item) }}</span>
+        </template>
+      </div>
+    </draggable>
+    <el-button type="primary" class="mt-10px" @click="addCamera">新增摄像头</el-button>
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+
+export default {
+  name: 'DraggableCamera',
+  components: {
+    draggable
+  },
+  props: {
+    devices: {
+      type: Array,
+      default: () => []
+    },
+    cameraList: {
+      type: Array,
+      default: () => []
+    },
+    detail: {
+      type: Boolean,
+      default: false
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      localDevices: []
+    }
+  },
+  watch: {
+    devices: {
+      immediate: true,
+      deep: true,
+      handler(val) {
+        
+        // 深拷贝避免引用问题
+        this.localDevices = JSON.parse(JSON.stringify(val || []))
+        console.log('devices 变化:', val, this.localDevices, this.cameraList)
+      }
+    }
+  },
+  methods: {
+    /** 获取设备名称 */
+    getDeviceName(element) {
+      const camera = this.cameraList.find(item => item.deviceCode === element.deviceCode)
+      return camera ? camera.name : element.deviceCode || '-'
+    },
+
+    /** 删除摄像头 */
+    delCamera(index) {
+      this.localDevices.splice(index, 1)
+      this.emitUpdate()
+    },
+
+    /** 新增摄像头 */
+    addCamera() {
+      this.localDevices.push({ deviceCode: undefined })
+    },
+
+    /** 拖拽结束 */
+    onDragEnd() {
+      this.emitUpdate()
+    },
+
+    /** 通知父组件更新 */
+    emitUpdate() {
+      this.$emit('updateDevices', this.localDevices)
+    },
+  }
+}
+</script>
+
+<style scoped>
+.draggable-container {
+  width: 100%;
+}
+.device-list {
+  display: flex;
+  flex-direction: column;
+}
+.device-item {
+  display: flex;
+  align-items: center;
+  padding: 10px 0;
+  cursor: move;
+}
+.device-item:not(:last-child) {
+  border-bottom: 1px dashed #eee;
+}
+.device-item.is-detail {
+  cursor: default;
+  padding: 8px 12px;
+  border: 1px solid #eee;
+  border-radius: 4px;
+  margin-bottom: 10px;
+}
+.device-name {
+  color: #606266;
+}
+.drag-icon {
+  margin: 0 10px;
+  cursor: move;
+}
+.ghost {
+  background-color: #f1f1f1;
+  border-radius: 5px;
+  border: 1px dashed rgb(19, 41, 239);
+}
+</style>

+ 249 - 0
src/views/config/pollingRules/components/videoPolingForm.vue

@@ -0,0 +1,249 @@
+<template>
+  <ele-modal
+    :visible.sync="visible"
+    :title="title"
+    width="800px"
+    append-to-body
+    @close="cancel"
+    :maxable="true"
+  >
+    <el-form
+      ref="form"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+      class="create-form"
+    >
+      <el-row :gutter="15">
+        <el-col :span="12">
+          <el-form-item label="规则编码:" prop="ruleCode">
+            <el-input
+              v-model="form.ruleCode"
+              maxlength="50"
+              placeholder="请输入"
+              :disabled="type == 'update'"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="规则名称:" prop="ruleName">
+            <el-input
+              v-model="form.ruleName"
+              maxlength="50"
+              placeholder="请输入"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="时间间隔:" prop="forInterval">
+            <el-input-number
+              v-model="form.forInterval"
+              :min="1"
+              :max="100"
+              controls-position="right"
+              class="w-full"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="是否重复:" prop="repeated">
+            <el-radio-group v-model="form.repeated">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="排序号:" prop="indexNo">
+            <el-input-number
+              v-model="form.indexNo"
+              :min="1"
+              :max="99999"
+              controls-position="right"
+              class="w-full"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="摄像头:" prop="devices" class="!mb-0">
+            <Draggable
+              :devices="form.devices"
+              :camera-list="cameraList"
+              ref="draggable"
+            />
+          </el-form-item>
+          
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="cancel">取消</el-button>
+      <el-button
+        type="primary"
+        @click="save"
+        :loading="loading"
+      >
+        保存
+      </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+import * as VideoPollingApi from '@/api/config/videoPolling'
+import Draggable from './draggable.vue'
+
+const defForm = {
+  id: undefined,
+  ruleCode: '',
+  ruleName: '',
+  forInterval: 10,
+  repeated: true,
+  indexNo: 100,
+  devices: [{ deviceCode: undefined }]
+}
+
+export default {
+  name: 'VideoPolingForm',
+  components: {
+    Draggable
+  },
+    data() {
+    return {
+      visible: false,
+      title: '',
+      type: '',
+      loading: false,
+      form: { ...defForm },
+      cameraList: [],
+      rules: {
+        ruleCode: [{ required: true, message: '规则编码不能为空', trigger: 'blur' }],
+        ruleName: [{ required: true, message: '规则名称不能为空', trigger: 'blur' }],
+        forInterval: [{ required: true, message: '时间间隔不能为空', trigger: 'blur' }],
+        repeated: [{ required: true, message: '请选择是否重复', trigger: 'change' }],
+        indexNo: [{ required: true, message: '排序号不能为空', trigger: 'blur' }]
+      }
+    }
+  },
+  created() {
+    // 初始化时获取摄像头列表
+    this.getCameraList()
+  },
+  methods: {
+    /** 获取摄像头列表 */
+    async getCameraList() {
+      try {
+        const res = await VideoPollingApi.listByType()
+        this.cameraList = res || []
+      } catch (e) {
+        console.error(e)
+      }
+    },
+
+    /** devices 更新回调 */
+    // handleDevicesUpdate(val) {
+    //   this.form.devices = val
+    //   console.log('form.devices:', this.form.devices)
+    // },
+
+    /** 打开弹窗 */
+    openForm(type, id) {
+      this.visible = true
+      this.type = type
+      this.title = type === 'create' ? '新增轮询规则' : '编辑轮询规则'
+
+      // 重置表单
+      this.form = { ...defForm }
+
+      // 修改时,加载数据
+      if (id) {
+        this.loading = true
+        VideoPollingApi.getVideoRule(id)
+          .then((res) => {
+            // 解析 devices 字符串为数组
+            let devices = JSON.parse(res.devices || '[]')
+            res.devices = devices.length ? devices : [{ deviceCode: undefined }]
+            this.form = res
+
+            console.log('res:', res)
+          })
+          .finally(() => {
+            this.loading = false
+          })
+      }
+
+    },
+
+    /** 取消 */
+    cancel() {
+      this.form = { ...defForm }
+      this.visible = false
+    },
+
+    /** 保存 */
+    save() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          console.log('form:', this.form)
+          const devices = this.$refs.draggable.localDevices
+          console.log('devices:', devices)
+          // 验证摄像头选择
+          const hasEmptyCamera = devices.some(item => !item.deviceCode)
+          if (hasEmptyCamera) {
+            this.$message.warning('请选择摄像头')
+            return
+          }
+
+          this.loading = true
+          const formData = { ...this.form }
+          const array = []
+          // 处理摄像头数据:直接使用 deviceCode 数组
+          devices.forEach((item) => {
+              this.cameraList.forEach((camera) => {
+                  if (item.deviceCode == camera.deviceCode) {
+                      array.push(camera)
+                  }
+              })
+          })
+
+          console.log('array:', array)
+          formData.devices = JSON.stringify(array)
+
+          const action = this.type === 'create'
+            ? VideoPollingApi.createVideoRule(formData)
+            : VideoPollingApi.updateVideoRule(formData)
+
+          action
+            .then(() => {
+              this.$message.success('操作成功')
+              this.cancel()
+              this.$emit('success')
+            })
+            .catch((e) => {
+              console.error(e)
+            })
+            .finally(() => {
+              this.loading = false
+            })
+        }
+      })
+    },
+
+    /** 新增摄像头 */
+    addCamera() {
+      this.form.devices.push({ deviceCode: undefined })
+      // 强制刷新 Draggable
+      // this.$nextTick(() => {
+      //   this.$refs.draggable && this.$refs.draggable.refresh()
+      // })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.w-full {
+  width: 100%
+}
+</style>

+ 261 - 0
src/views/config/pollingRules/index.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never" v-loading="loading">
+      <PollingRulesSearch @search="handleQuery" @reset="reload"> </PollingRulesSearch>
+      <!-- 数据表格 -->
+      <ele-pro-table
+        ref="table"
+        :pageSizes="tablePageSizes"
+        :columns="columns"
+        :datasource="datasource"
+        :selection.sync="selection"
+        :cache-key="cacheKeyUrl"
+      >
+        <!-- 表头工具栏 -->
+        <template v-slot:toolbar>
+          <el-button
+            size="small"
+            type="primary"
+            icon="el-icon-plus"
+            class="ele-btn-icon"
+            @click="openForm('create')"
+          >
+            新建
+          </el-button>
+          <el-button
+            size="small"
+            type="danger"
+            icon="el-icon-delete"
+            class="ele-btn-icon"
+            v-if="selection.length"
+            @click="handleBatchDelete"
+          >
+            批量删除
+          </el-button>
+        </template>
+
+        <!-- 是否重复列 -->
+        <template v-slot:repeated="{ row }">
+          <el-switch
+            v-model="row.repeated"
+            @change="handleRepeatedChange(row)"
+          />
+        </template>
+
+        <!-- 操作列 -->
+        <template v-slot:action="{ row }">
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-view"
+            @click="openDetailForm(row.id)"
+          >
+            详情
+          </el-link>
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="openForm('update', row.id)"
+          >
+            编辑
+          </el-link>
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-delete"
+            :style="{ color: delColor }"
+            @click="handleDelete(row.id)"
+          >
+            删除
+          </el-link>
+        </template>
+      </ele-pro-table>
+    </el-card>
+
+    <!-- 表单弹窗:添加/修改 -->
+    <VideoPolingForm ref="formRef" @success="reload" />
+    <!-- 详情弹窗 -->
+    <Detail ref="detailRef" />
+  </div>
+</template>
+
+<script>
+import PollingRulesSearch from './components/PollingRulesSearch.vue'
+import VideoPolingForm from './components/videoPolingForm.vue'
+import Detail from './components/detail.vue'
+
+import * as VideoPollingApi from '@/api/config/videoPolling'
+
+export default {
+  name: 'VideoPolling',
+  components: {
+    PollingRulesSearch,
+    VideoPolingForm,
+    Detail
+  },
+  data() {
+    return {
+      cacheKeyUrl: 'videoPollingTable',
+      delColor: '#F56C6C',
+      selection: [],
+      tablePageSizes: [10, 20, 50, 100],
+      // 表格列配置
+      columns: [
+        {
+          width: 45,
+          type: 'selection',
+          columnKey: 'selection',
+          align: 'center',
+          fixed: 'left'
+        },
+        {
+          columnKey: 'index',
+          label: '序号',
+          type: 'index',
+          width: 55,
+          align: 'center',
+          showOverflowTooltip: true,
+          fixed: 'left'
+        },
+        {
+          prop: 'ruleCode',
+          label: '规则编码',
+          headerAlign: 'center',
+          align: 'center',
+          showOverflowTooltip: true,
+         
+        },
+        {
+          prop: 'ruleName',
+          label: '规则名称',
+          headerAlign: 'center',
+          align: 'center',
+          showOverflowTooltip: true,
+
+        },
+        {
+          prop: 'forInterval',
+          label: '时间间隔',
+          align: 'center',
+          showOverflowTooltip: true,
+          width: 150
+        },
+        {
+          prop: 'repeated',
+          label: '是否重复',
+          align: 'center',
+          showOverflowTooltip: true,
+          width: 100,
+          slot: 'repeated'
+        },
+        {
+          prop: 'indexNo',
+          label: '排序号',
+          align: 'center',
+          showOverflowTooltip: true,
+          width: 150
+        },
+        {
+          columnKey: 'action',
+          fixed: 'right',
+          label: '操作',
+          width: 220,
+          align: 'center',
+          resizable: false,
+          slot: 'action',
+          showOverflowTooltip: true
+        }
+      ],
+      loading: false
+    }
+  },
+  methods: {
+    /* 表格数据源 */
+    datasource({ page, limit, where, order }) {
+      return VideoPollingApi.getVideoRulePage({
+        pageNo: page,
+        pageSize: limit,
+        ...where
+      })
+    },
+    /* 刷新表格 */
+    reload(where) {
+      this.$refs.table.reload({ page: 1, where })
+    },
+
+    /* 搜索 */
+    handleQuery(where) {
+      this.reload(where)
+    },
+
+    /** 添加/修改操作 */
+    openForm(type, id) {
+      this.$refs.formRef.openForm(type, id)
+    },
+
+    /** 详情 */
+    openDetailForm(id) {
+      this.$refs.detailRef.openForm(id)
+    },
+
+    /** 删除按钮操作 */
+    handleDelete(id) {
+      this.$confirm('是否确认删除数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(async () => {
+          await VideoPollingApi.deleteVideoRule(id)
+          this.$message.success('删除成功')
+          this.reload()
+        })
+        .catch(() => {})
+    },
+
+    /** 批量删除按钮操作 */
+    handleBatchDelete() {
+      if (this.selection.length == 0) {
+        this.$message.warning('请选择要删除的数据项')
+        return
+      }
+      this.$confirm('是否确认删除选中的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(async () => {
+          const ids = this.selection.map((item) => item.id)
+          // 循环删除
+          for (const id of ids) {
+            await VideoPollingApi.deleteVideoRule(id)
+          }
+          this.$message.success('删除成功')
+          this.reload()
+        })
+        .catch(() => {})
+    },
+
+    /** 是否重复切换 */
+    handleRepeatedChange(row) {
+      const text = row.repeated ? '启用重复' : '取消重复'
+      this.$confirm('确认要' + text + '?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(async () => {
+          await VideoPollingApi.updateVideoRule({ ...row, repeated: row.repeated })
+          this.$message.success(text + '成功')
+          this.reload()
+        })
+        .catch(() => {
+          row.repeated = !row.repeated
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 38 - 11
src/views/config/scheduledTasks/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="ele-body">
     <el-card shadow="never" v-loading="loading">
-      <scheduledTasksSearch @search="reload"> </scheduledTasksSearch>
+      <scheduledTasksSearch ref="searchRef" @search="reload"> </scheduledTasksSearch>
       <!-- 数据表格 -->
       <ele-pro-table
         ref="table"
@@ -33,7 +33,7 @@
             >
                 批量删除
             </el-button>
-            <!-- <el-button
+            <el-button
                 size="small"
                 type="primary"
                 icon="el-icon-download"
@@ -42,7 +42,7 @@
                 @click="handleExport"
             >
                 导出
-            </el-button> -->
+            </el-button>
         </template>
         <!-- 操作列 -->
         <template v-slot:action="{ row }">
@@ -113,10 +113,14 @@
 import ScheduledTasksSearch from './components/scheduledTasks-search.vue'
 import JobForm from './components/JobForm.vue'
 import JobDetail from './components/JobDetail.vue'
-
+import { getToken, setToken } from '@/utils/token-util';
 import { download } from '@/utils/file';
 import * as JobApi from '@/api/config/scheduledTasks'
 import dictMixins from '@/mixins/dictMixins';
+import axios from 'axios';
+import {
+    API_BASE_URL,
+  } from '@/config/setting';
 
 export default {
   name: 'InfraJob',
@@ -246,7 +250,7 @@ export default {
       )
         .then(async () => {
           const status = row.status === 1 ? 2 : 1
-          await JobApi.updateJobStatus(+row.id, status)
+          await JobApi.updateJobStatus(row.id, status)
           this.$message.success(text + '成功')
           this.reload()
         })
@@ -320,12 +324,35 @@ export default {
 
     /** 导出按钮操作 */
     async handleExport() {
-      try {
-        const data = await JobApi.exportJob(this.$refs.table?.where || {})
-        download(data, '定时任务.xls')
-      } catch (error) {
-        console.error('导出失败:', error)
-      }
+      // try {
+      //   const data = await JobApi.exportJob(this.$refs.table?.where || {})
+      //   console.log('handleExport~~~', data)
+      //   download(data, '定时任务.xls')
+      // } catch (error) {
+      //   console.error('导出失败:', error)
+      // }
+
+      let params = {
+          ...this.$refs.searchRef.where,
+        };
+        this.loading = true;
+        axios({
+          url: `${API_BASE_URL}/eam/job/export-excel`,
+          method: 'get',
+          responseType: 'blob',
+          headers: {
+            Authorization: getToken()
+          },
+          data: params
+        })
+          .then((res) => {
+            this.loading = false;
+            download(res.data, '定时任务.xls');
+            this.$message.success('操作成功');
+          })
+          .catch((err) => {
+            this.loading = false;
+          });
     },
 
     /** 查看操作 */