无人机管理后台前端(已迁走)
chenyao
2025-06-09 4f3474b4a0e25eaba0d2e28f7728bba8fb4297e9
feat: 更新密钥和任务管理数据
5 files modified
4 files added
760 ■■■■ changed files
src/api/system/dict.js 8 ●●●●● patch | view | raw | blame | history
src/assets/images/task/cancel1.png patch | view | raw | blame | history
src/assets/images/uoload-success.png patch | view | raw | blame | history
src/assets/images/upload-error.png patch | view | raw | blame | history
src/axios.js 15 ●●●●● patch | view | raw | blame | history
src/views/job/components/SearchBox.vue 78 ●●●● patch | view | raw | blame | history
src/views/job/components/TaskTop/TaskTotal.vue 5 ●●●●● patch | view | raw | blame | history
src/views/system/userinfo-copy.vue 124 ●●●●● patch | view | raw | blame | history
src/views/system/userinfo.vue 530 ●●●● patch | view | raw | blame | history
src/api/system/dict.js
@@ -86,3 +86,11 @@
    params,
  });
};
export const findLicenseDate = params => {
    return request({
        url: '/blade-system/license/findLicenseDate',
        method: 'get',
        params,
    })
}
src/assets/images/task/cancel1.png
src/assets/images/uoload-success.png
src/assets/images/upload-error.png
src/axios.js
@@ -119,6 +119,21 @@
        const message = res.data.msg || res.data.error_description || res.data.message ||'系统错误';
        const config = res.config;
        const cryptoData = config.cryptoData === true;
        if (status === 511) {
            ElMessage({
                message: '请联系运维人员上传密钥证书!',
                type: 'error',
            });
            // 获取当前路由名称
            const currentRouteName = router.currentRoute.value.name;
            // 如果当前路由不是登录页,则跳转到登录页
            if (currentRouteName !== '登录页') {
                store.dispatch('FedLogOut').then(() => router.push({
                    path: '/login'
                }));
            }
            return Promise.reject(new Error(message));
        }
        //如果在白名单里则自行catch逻辑处理
        if (statusWhiteList.includes(status)) return Promise.reject(res);
        // 如果是401并且没有重试过,尝试刷新token
src/views/job/components/SearchBox.vue
@@ -50,6 +50,7 @@
              class="card-item"
              :class="item === checked ? 'active' : ''"
              v-for="(item, index) in timeList"
              :key="index"
              @click="timeClick(item, index)"
            >
              {{ timeListStr[index] }}
@@ -298,35 +299,35 @@
};
// 监听从巡检任务概况提交的数据
watch(
  () => store.state.task.jumpTask,
  newVal => {
// watch(
//   () => store.state.task.jumpTask,
//   newVal => {
 
    if (newVal && Object.keys(newVal).length) {
      // 兼容当日任务 计划任务 历史任务传参
      if (newVal.clickValue) {
        checked.value = newVal.clickValue;
        searchForm.date_enum = newVal.date_enum;
      }
      if (newVal.date_value) {
        dateRange.value = newVal.date_value;
      }
      if (newVal.status) {
        searchForm.status = newVal.status;
      }
      if (newVal.device_sn) {
        searchForm.device_sn = newVal.device_sn;
        // 不直接赋值的原因: 回选会被清空值
        signDevice_sn.value = newVal.device_sn;
      }
    } else {
      checked.value = 'today';
      searchForm.date_enum = 'TODAY';
    }
    handleSearch();
  },
  { immediate: true, deep: true }
);
//     if (newVal && Object.keys(newVal).length) {
//       // 兼容当日任务 计划任务 历史任务传参
//       if (newVal.clickValue) {
//         checked.value = newVal.clickValue;
//         searchForm.date_enum = newVal.date_enum;
//       }
//       if (newVal.date_value) {
//         dateRange.value = newVal.date_value;
//       }
//       if (newVal.status) {
//         searchForm.status = newVal.status;
//       }
//       if (newVal.device_sn) {
//         searchForm.device_sn = newVal.device_sn;
//         // 不直接赋值的原因: 回选会被清空值
//         signDevice_sn.value = newVal.device_sn;
//       }
//     } else {
//       checked.value = 'today';
//       searchForm.date_enum = 'TODAY';
//     }
//     handleSearch();
//   },
//   { immediate: true, deep: true }
// );
onBeforeUnmount(() => {
  checked.value = 'today';
@@ -336,20 +337,17 @@
onMounted(() => {
  requestDockInfo();
  // 日历传值
const calendarday = ref(route.query.day);
  const calendarday = ref(route.query.day);
if (calendarday.value) {
  const date = dayjs(calendarday.value).format(timeFormat);
  if (calendarday.value) {
    const date = dayjs(calendarday.value).format(timeFormat);
  const dateArray = [date, date];
  dateRange.value = dateArray;
  handleSearch();
}
  // 查询一次
  // handleSearch()
    const dateArray = [date, date];
    dateRange.value = dateArray;
  }
    // 查询一次
    handleSearch()
});
</script>
<style lang="scss"></style>
src/views/job/components/TaskTop/TaskTotal.vue
@@ -61,8 +61,8 @@
        list.value[0].value = res.data.data.planned_executions || 0
        list.value[1].value = res.data.data.executed || 0
        list.value[2].value = res.data.data.running_num || 0
        list.value[3].value = res.data.data.executed || 0
        list.value[4].value = res.data.data.failed_executions || 0
        list.value[3].value = res.data.data.failed_executions || 0
        list.value[4].value = res.data.data.pending_executions || 0
        list.value[5].value = res.data.data.go_home_executions || 0
    })
}
@@ -81,7 +81,6 @@
onMounted(() => {
    getTotalJobNum()
    // getJobStatistics()
})
</script>
src/views/system/userinfo-copy.vue
New file
@@ -0,0 +1,124 @@
<template>
  <div>
    <basic-container>
      <avue-form
        ref="form"
        :option="option"
        v-model="form"
        @tab-click="handleTabClick"
        @submit="handleSubmit"
      >
        <template #email="{ disabled, size }">
            <el-input
            id="adfsdafdsf"
              type="text"
              :disabled="disabled"
              :size="size"
              v-model="form.email"
              placeholder="请输入邮箱"
              :readonly="readonly"
              @focus="readonly = false"
            >
            </el-input>
        </template>
      </avue-form>
    </basic-container>
  </div>
</template>
<script>
import option from '@/option/user/info';
import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user';
import md5 from 'js-md5';
import func from '@/utils/func';
import { validatenull } from '@/utils/validate';
import defaultAva from '@/assets/images/defaultava.png';
export default {
  data() {
    return {
      index: 0,
      option: option,
      form: {  },
      readonly: true
    };
  },
  created() {
    this.handleWitch();
  },
  methods: {
    handleSubmit(form, done) {
      if (this.index === 0) {
        form.name = form.realName;
        updateInfo(form).then(
          res => {
            if (res.data.success) {
              this.$message({
                type: 'success',
                message: '修改信息成功!',
              });
            } else {
              this.$message({
                type: 'error',
                message: res.data.msg,
              });
            }
            done();
          },
          error => {
            window.console.log(error);
            done();
          }
        );
      } else {
        updatePassword(md5(form.oldPassword), md5(form.newPassword), md5(form.newPassword1)).then(
          res => {
            if (res.data.success) {
              this.$message({
                type: 'success',
                message: '修改密码成功!',
              });
            } else {
              this.$message({
                type: 'error',
                message: res.data.msg,
              });
            }
            done();
          },
          error => {
            window.console.log(error);
            done();
          }
        );
      }
    },
    handleWitch() {
      if (this.index === 0) {
        getUserInfo().then(res => {
          const user = res.data.data;
          this.form = {
            id: user.id,
            avatar: user.avatar ? user.avatar :defaultAva,
            name: user.name,
            realName: user.realName,
            phone: user.phone,
            email: user.email,
          };
        });
      }
    },
    handleTabClick(tabs) {
      if (validatenull(tabs.index)) {
        return;
      }
      this.index = func.toInt(tabs.index, 0);
      this.handleWitch();
    },
  },
};
</script>
<style></style>
src/views/system/userinfo.vue
@@ -1,124 +1,416 @@
<template>
  <div>
    <basic-container>
      <avue-form
        ref="form"
        :option="option"
        v-model="form"
        @tab-click="handleTabClick"
        @submit="handleSubmit"
      >
        <template #email="{ disabled, size }">
            <el-input
            id="adfsdafdsf"
              type="text"
              :disabled="disabled"
              :size="size"
              v-model="form.email"
              placeholder="请输入邮箱"
              :readonly="readonly"
              @focus="readonly = false"
            >
            </el-input>
        </template>
      </avue-form>
    </basic-container>
  </div>
        <div class="user-info-new">
      <div class="titleBoxs">
            <div
                class="titleItem"
                :class="index === checked ? 'activeItem' : ''"
                v-for="(item, index) in titleList"
                :key="index"
                @click="titleClick(item, index)"
            >
                {{ item }}
            </div>
        </div>
        <!-- 个人信息 -->
        <div class="message" v-if="checked === 0">
            <div class="info">
                <div class="section">
                    <el-form label-width="120px">
                        <el-form-item label="头像:">
                            <el-upload
                                class="avatar-uploader"
                                :http-request="customUpload"
                                :show-file-list="false"
                                :before-upload="beforeAvatarUpload"
                                :disabled="uploadLoading"
                                action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
                            >
                                <img v-if="userInfo.avatar" :src="userInfo.avatar" class="avatar" />
                                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
                                <template #tip>
                                    <div class="upload-tip">只能上传jpg/png用户头像,且不超过500kb</div>
                                </template>
                            </el-upload>
                            <!-- <el-dialog v-model="dialogVisible">
                                <img w-full :src="dialogImageUrl" alt="Preview Image" />
                            </el-dialog> -->
                        </el-form-item>
                    </el-form>
                </div>
                <div class="section">
                    <el-form :model="userInfo" label-width="120px">
                        <el-form-item label="姓名:">
                            <el-input class="ztzf-input" :style="{ width: pxToRem(230) }" v-model="userInfo.realName" disabled />
                        </el-form-item>
                        <!--                        <el-form-item label="昵称:">
                                                    <el-input class="ztzf-input" v-model="userInfo.name" />
                                                </el-form-item>-->
                        <el-form-item label="所属单位:">
                            <el-input class="ztzf-input" v-model="userInfo.deptName" disabled />
                        </el-form-item>
                        <el-form-item label="手机号:">
                            <el-input class="ztzf-input" v-model="userInfo.phone" />
                        </el-form-item>
                        <el-form-item label="邮箱:">
                            <el-input class="ztzf-input" v-model="userInfo.email" />
                        </el-form-item>
                    </el-form>
                </div>
            </div>
            <div class="butn">
                <!-- <img @click="reset" :style="{ marginRight: pxToRem(23) }" :src="cancel1" alt="" />
                <img @click="submit" :style="{ marginRight: pxToRem(23) }" :src="publish1" alt="" /> -->
        <el-button type="primary" @click="submit" style="margin-right: 10px;">提交</el-button>
        <el-button @click="reset">重置</el-button>
            </div>
        </div>
        <!-- 修改密码 -->
        <div class="passwordBox" v-else-if="checked === 1">
            <div class="password">
                <el-form :model="passwordForm" label-width="120px">
                    <el-form-item label="原始密码:" prop="oldPassword">
                        <el-input class="ztzf-input" v-model="passwordForm.oldPassword" type="password" show-password />
                    </el-form-item>
                    <el-form-item label="新密码:" prop="newPassword">
                        <el-input class="ztzf-input" v-model="passwordForm.newPassword" type="password" show-password />
                    </el-form-item>
                    <el-form-item label="确认密码:" prop="newPassword1">
                        <el-input class="ztzf-input" v-model="passwordForm.newPassword1" type="password" show-password />
                    </el-form-item>
                </el-form>
            </div>
            <div class="butn">
                <!-- <img @click="reset" :style="{ marginRight: pxToRem(23) }" :src="cancel1" alt="" />
                <img @click="submit" :style="{ marginRight: pxToRem(23) }" :src="publish1" alt="" /> -->
      <el-button type="primary" @click="submit" style="margin-right: 10px;">提交</el-button>
        <el-button @click="reset">重置</el-button>
            </div>
        </div>
        <!-- 密钥上传 -->
        <div class="upload-file" v-else-if="checked === 2">
            <img v-if="isSuccess === 'success'" :src="uploadSuccess" alt="" />
            <img v-if="isSuccess === 'error'" :src="uploadError" alt="" />
            <el-upload action="/upload" accept=".lic" :show-file-list="false" :before-upload="handleUpload">
                <div class="upload-btn">密钥上传</div>
            </el-upload>
            <div class="password-time">密钥有效期:{{ passwordTime || '永久有效' }}</div>
        </div>
    </div>
</template>
<script>
import option from '@/option/user/info';
import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user';
import md5 from 'js-md5';
import func from '@/utils/func';
import { validatenull } from '@/utils/validate';
import defaultAva from '@/assets/images/defaultava.png';
export default {
  data() {
    return {
      index: 0,
      option: option,
      form: {  },
      readonly: true
    };
  },
  created() {
    this.handleWitch();
  },
  methods: {
    handleSubmit(form, done) {
      if (this.index === 0) {
        form.name = form.realName;
        updateInfo(form).then(
          res => {
            if (res.data.success) {
              this.$message({
                type: 'success',
                message: '修改信息成功!',
              });
            } else {
              this.$message({
                type: 'error',
                message: res.data.msg,
              });
            }
            done();
          },
          error => {
            window.console.log(error);
            done();
          }
        );
      } else {
        updatePassword(md5(form.oldPassword), md5(form.newPassword), md5(form.newPassword1)).then(
          res => {
            if (res.data.success) {
              this.$message({
                type: 'success',
                message: '修改密码成功!',
              });
            } else {
              this.$message({
                type: 'error',
                message: res.data.msg,
              });
            }
            done();
          },
          error => {
            window.console.log(error);
            done();
          }
        );
      }
    },
    handleWitch() {
      if (this.index === 0) {
        getUserInfo().then(res => {
          const user = res.data.data;
          this.form = {
            id: user.id,
            avatar: user.avatar ? user.avatar :defaultAva,
            name: user.name,
            realName: user.realName,
            phone: user.phone,
            email: user.email,
          };
        });
      }
    },
<script setup>
import { pxToRem } from '@/utils/rem'
import { useStore } from 'vuex'
import { ElMessage } from 'element-plus'
import { getToken } from '@/utils/auth'
import md5 from 'js-md5'
import request from '@/axios'
import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user'
import { findLicenseDate } from '@/api/system/dict'
import { uploadLicense } from '@/api/license/uploadLicense';
    handleTabClick(tabs) {
      if (validatenull(tabs.index)) {
        return;
      }
      this.index = func.toInt(tabs.index, 0);
      this.handleWitch();
    },
  },
};
import uploadSuccess from '@/assets/images/uoload-success.png';
import uploadError from '@/assets/images/upload-error.png';
import cancel1 from '@/assets/images/task/cancel1.png';
import publish1 from '@/assets/images/task/publish1.png';
const store = useStore()
const token = getToken()
const userinforShow = defineModel('show')
const userInfoAs = computed(() => store.state.user.userInfo)
const titleList = ref(['个人信息', '修改密码', '密钥上传'])
const checked = ref(0)
const uploadUrl = computed(() => `${import.meta.env.VITE_APP_API_URL}/blade-resource/oss/endpoint/put-file`)
// 表单数据
const userInfo = ref({
    id: '',
    avatar: '',
    realName: '',
    name: '',
    phone: '',
    email: '',
    deptName: '',
})
// 校验手机号
const validatePhone = () => {
    const phoneRegex = /^1[3-9]\d{9}$/
    if (!phoneRegex.test(userInfo.value.phone)) {
        ElMessage.error('请输入正确的手机号码')
        return false
    }
    return true
}
const passwordForm = ref({
    oldPassword: '',
    newPassword: '',
    newPassword1: '',
})
// 头像
const beforeAvatarUpload = file => {
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
    const isLt500KB = file.size / 1024 < 500
    if (!isJpgOrPng) {
        ElMessage.error('头像图片只能是 JPG/PNG 格式!')
        return false
    }
    if (!isLt500KB) {
        ElMessage.error('头像图片大小不能超过 500KB!')
        return false
    }
    return true
}
const uploadLoading = ref(false)
const customUpload = async options => {
    const { file } = options
    uploadLoading.value = true
    const formData = new FormData()
    formData.append('file', file) // 根据后端API调整字段名
    try {
        const res = await request.post('/blade-resource/oss/endpoint/put-file', formData, {
            headers: {
                'Content-Type': 'multipart/form-data',
            },
        })
        if (res.data.code === 200) {
            ElMessage.success('头像上传成功')
            userInfo.value.avatar = res.data.data.link
            return res.data
        } else {
            throw new Error(res.data.msg || '上传失败')
        }
    } catch (error) {
        ElMessage.error(error.response?.data?.msg || error.message || '上传失败')
        return Promise.reject(error)
    } finally {
        uploadLoading.value = false
    }
}
const titleClick = (item, index) => {
    checked.value = index
    if (index === 2) {
        getFindLicenseDate()
    }
}
const getUserInfoData = () => {
    getUserInfo().then(res => {
        const user = res.data.data
        userInfo.value = {
            id: user.id,
            avatar: user.avatar,
            name: user.name,
            realName: user.realName,
            phone: user.phone,
            email: user.email,
            deptName: user.deptName,
        }
    })
}
const emit = defineEmits(['logout'])
const submit = () => {
    if (checked.value === 0) {
        // if (!validatePhone()) return
        userInfo.value.name = userInfo.value.realName
        updateInfo(userInfo.value).then(res => {
            if (res.data.code === 200) {
                ElMessage.success('修改信息成功!')
                userinforShow.value = false
            } else {
                ElMessage.error(res.msg)
            }
        })
    } else if (checked.value === 1) {
        updatePassword(
            md5(passwordForm.value.oldPassword),
            md5(passwordForm.value.newPassword),
            md5(passwordForm.value.newPassword1)
        ).then(res => {
            if (res.data.code === 200) {
                ElMessage.success('修改密码成功!')
                // 调用父组件方法
                userinforShow.value = false
                emit('logout')
            } else {
                ElMessage.error(res.msg)
            }
        })
    }
}
const reset = () => {
    if (checked.value === 0) {
        getUserInfoData()
        userinforShow.value = false
    } else if (checked.value === 1) {
        passwordForm.value = {
            id: userInfoAs.value.userId,
            oldPassword: '',
            newPassword: '',
            newPassword1: '',
        }
        userinforShow.value = false
    }
}
const isSuccess = ref('')
const passwordTime = ref('')
const handleUpload = file => {
    const formData = new FormData()
    formData.append('file', file)
    uploadLicense(formData)
        .then(res => {
            if (res.data.code !== 200) return ElMessage.error('上传失败')
            ElMessage.success('上传成功')
            isSuccess.value = 'success'
            getFindLicenseDate()
        })
        .catch(err => {
            isSuccess.value = 'error'
            ElMessage.error('上传失败')
        })
}
const getFindLicenseDate = () => {
    findLicenseDate()
        .then(res => {
            if (res.data.code !== 0) return ElMessage.error('获取失败')
            passwordTime.value = res.data.data
        })
        .catch(err => {
            ElMessage.error('获取失败')
        })
}
// const dialogImageUrl = ref('')
// const dialogVisible = ref(false)
// const handlePictureCardPreview = () => {}
// const handleRemove = () => {}
onMounted(() => {
    getUserInfoData()
})
</script>
<style></style>
<style scoped lang="scss">
.user-info-new {
  margin: 16px;
  padding: 10px;
  background-color: #ffffff;
}
.titleBoxs {
    margin: 0 24px;
    margin-bottom: 10px;
    // background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
    // background-size: 100% 100%;
    p {
        display: inline-block;
        margin-left: 30px;
        font-size: 16px;
        color: #000;
        line-height: 20px;
        text-align: left;
        margin-bottom: 8px;
    }
}
:deep(.el-form-item__label) {
    color: #000 !important;
}
:deep(.el-button) {
    width: 150px !important;
}
.info {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 80px 0 50px;
}
.password {
    padding: 0 120px 0 50px;
}
.butn {
    // position: absolute;
    // bottom: 20px;
    // left: 50%;
    // transform: translate(-50%);
  display: flex;
  justify-content: center;
    cursor: pointer;
    img {
        width: 96px;
        height: 32px;
    }
}
.titleBoxs {
    display: flex;
    padding: 0 20px;
}
.titleItem {
    color: #61809c;
    font-size: 16px;
    margin-right: 50px;
    cursor: pointer;
}
.activeItem {
    border-radius: 0px 0px 0px 0px;
    color: #51abff;
    border-bottom: 2px solid #198cff;
}
.avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}
.avatar-uploader .el-upload:hover {
    border-color: #409eff;
}
.avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    line-height: 178px;
    text-align: center;
}
.avatar {
    width: 178px;
    height: 178px;
    display: block;
}
.upload-tip {
    margin-top: 10px;
    color: #999;
    font-size: 12px;
    text-align: center;
}
.message,
.passwordBox {
    margin-top: 40px;
}
.upload-file {
    text-align: center;
    margin-top: 60px;
    .upload-btn {
        width: 93px;
        height: 38px;
        line-height: 38px;
        background: #1b3e6c;
        border-radius: 8px 8px 8px 8px;
        border: 1px solid #ffffff;
        color: #fff;
        text-align: center;
    }
    .password-time {
        margin-top: 50px;
        width: 100%;
        height: 16px;
        font-family: Source Han Sans CN, Source Han Sans CN;
        font-weight: 400;
        font-size: 14px;
        color: #2d9dff;
        line-height: 16px;
        // text-align: left;
    }
}
</style>