.env.jiangwu
New file @@ -0,0 +1,42 @@ NODE_ENV = 'jiangwu' #生产环境配置 VITE_APP_ENV = 'jiangwu' #接口地址 #填写前缀 [/api] 需要用nginx进行反向代理 #填写地址 [https://api.bladex.cn] 只需要保证接口支持跨域即可, 无需再做代理 VITE_APP_API=/api #页面基础路径 VITE_APP_BASE=/manage # 服务地址 VITE_APP_URL = http://192.168.253.121:8080/api # 域名 VITE_APP_AREA_NAME = http://192.168.253.121:8080/ #新大屏地址 VITE_APP_DASHBOARD_URL = 'http://192.168.253.121:8080/command-center-dashboard/' # ws地址 VITE_APP_WS_API_URL = ws://192.168.253.121:8080 # 航线文件地址 VITE_APP_AIRLINE_URL = http://192.168.253.121:9000/cloud-bucket # 算法仓库图片地址 VITE_APP_PICTURE_URL = http://192.168.253.121:9000/aiskyminio/cloud-bucket # 是否在打包时开启压缩,支持 gzip 和 brotli VITE_BUILD_COMPRESS = gzip VITE_APP_OFFLINE_MAP_URL = http://192.168.253.121:9000/cloud-bucket/offline_map # 地形存放地址 VITE_APP_TERRAIN_URL = http://192.168.253.121:9000/cloud-bucket/ztzf_terrain # 图片资源存放地址 VITE_APP_IMAGESOURCE_URL = http://192.168.253.121:9000/cloud-bucket .env.test
New file @@ -0,0 +1,42 @@ NODE_ENV = 'test' #开发环境配置 VITE_APP_ENV = 'test' #接口地址 VITE_APP_API=/api #页面基础路径 VITE_APP_BASE=/manage # 服务地址 VITE_APP_URL = https://wrj.shuixiongit.com/api #VITE_APP_URL= http://192.168.1.168 rjg #VITE_APP_URL= http://192.168.1.33 #新大屏地址 VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/' # 域名 VITE_APP_AREA_NAME = https://wrj.shuixiongit.com # ws地址 VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com # 航线文件地址 VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket # 图片存放地址 VITE_APP_TERRAIN_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_terrain/all_terrain # 算法仓库图片地址 VITE_APP_PICTURE_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket # 是否在打包时开启压缩,支持 gzip 和 brotli VITE_BUILD_COMPRESS = gzip #页面基础路径 # VITE_APP_BASE_COMMAND = /drone-web-manage/ #天地图token 浏览器端口 VITE_APP_TDT_TOKEN = e110584a27d506da2740edca951683f4 VITE_APP_CESIUM_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkYTZlNGNlYS01NTU1LTQ1MGEtYmNlZS0yNTE2NDk5YWM2MjEiLCJpZCI6MTc5Njk2LCJpYXQiOjE3MDA1NDcwMjV9.qcl4AH2731cfFd0-I1ZLUINPXqvglLkDFD-UGR2zU5M package.json
@@ -5,8 +5,9 @@ "dev": "vite --host", "base": "vite --host --mode localhost", "prod": "vite --mode production", "build:test": "vite build --mode development", "build:test": "vite build --mode test", "build:prod": "vite build --mode production", "build:jiangwu": "vite build --mode jiangwu", "serve": "vite preview --host" }, "dependencies": { @@ -51,4 +52,4 @@ "vite-plugin-compression": "^0.5.1", "vite-plugin-vue-setup-extend": "^0.4.0" } } } src/axios.js
@@ -9,32 +9,17 @@ import axios from 'axios'; import store from '@/store/'; import router from '@/router/'; import { serialize } from '@/utils/util'; import { getToken, removeToken, removeRefreshToken } from '@/utils/auth'; import { isURL, validatenull } from '@/utils/validate'; import { ElMessage } from 'element-plus'; import { serialize } from '@/utils/util'; import { getToken, removeToken, removeRefreshToken } from '@/utils/auth'; import { isURL, validatenull } from '@/utils/validate'; import { ElMessage } from 'element-plus'; import website from '@/config/website'; import NProgress from 'nprogress'; // progress bar import 'nprogress/nprogress.css'; // progress bar style import { Base64 } from 'js-base64'; import { baseUrl } from '@/config/env'; import { Base64 } from 'js-base64'; import { baseUrl } from '@/config/env'; import crypto from '@/utils/crypto'; const adminUrl = import.meta.env.VITE_APP_DASHBOARD_URL const adminUrl = import.meta.env.VITE_APP_DASHBOARD_URL; // 全局未授权错误提示状态,只提示一次 let isErrorShown = false; @@ -42,193 +27,209 @@ // 超时时间设置为10分钟,部分接口上传比较慢,如固件上传 axios.defaults.timeout = 600000; //返回其他状态码 axios.defaults.validateStatus = function(status) { return status >= 200 && status <= 500; // 默认的 axios.defaults.validateStatus = function (status) { return status >= 200 && status <= 500; // 默认的 }; //跨域请求,允许保存cookie axios.defaults.withCredentials = true; // NProgress Configuration NProgress.configure({ showSpinner: false, showSpinner: false, }); //http request拦截 axios.interceptors.request.use( config => { // start progress bar NProgress.start(); // 初始化错误提示状态 isErrorShown = false; //地址为已经配置状态则不添加前缀 if (!isURL(config.url) && !config.url.startsWith(baseUrl)) { config.url = baseUrl + config.url; } //安全请求header config.headers['areaCode'] = store?.state?.user?.userInfo?.detail?.areaCode config.headers['Blade-Requested-With'] = 'BladeHttpRequest'; //headers判断是否需要 const authorization = config.authorization === false; if (!authorization) { config.headers['Authorization'] = `Basic ${Base64.encode( config => { // start progress bar NProgress.start(); // 初始化错误提示状态 isErrorShown = false; //地址为已经配置状态则不添加前缀 if (!isURL(config.url) && !config.url.startsWith(baseUrl)) { config.url = baseUrl + config.url; } //安全请求header config.headers['areaCode'] = store?.state?.user?.userInfo?.detail?.areaCode; config.headers['Blade-Requested-With'] = 'BladeHttpRequest'; //headers判断是否需要 const authorization = config.authorization === false; if (!authorization) { config.headers['Authorization'] = `Basic ${Base64.encode( `${website.clientId}:${website.clientSecret}` )}`; } //headers判断请求是否携带token const meta = config.meta || {}; const isToken = meta.isToken === false; //headers传递token是否加密 const cryptoToken = config.cryptoToken === true; //判断传递数据是否加密 const cryptoData = config.cryptoData === true; const token = getToken(); if (token && !isToken) { config.headers[website.tokenHeader] = cryptoToken ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey) : 'bearer ' + token; } // 开启报文加密 // if (cryptoData) { // if (config.params) { // const data = crypto.encryptAES(JSON.stringify(config.params), crypto.aesKey); // config.params = { data }; // } // if (config.data) { // config.text = true; // config.data = crypto.encryptAES(JSON.stringify(config.data), crypto.aesKey); // } // } //headers中配置text请求 if (config.text === true) { config.headers['Content-Type'] = 'text/plain'; } //headers中配置serialize为true开启序列化 if (config.method === 'post' && meta.isSerialize === true) { config.data = serialize(config.data); } return config; }, error => { return Promise.reject(error); } } //headers判断请求是否携带token const meta = config.meta || {}; const isToken = meta.isToken === false; //headers传递token是否加密 const cryptoToken = config.cryptoToken === true; //判断传递数据是否加密 const cryptoData = config.cryptoData === true; const token = getToken(); if (token && !isToken) { config.headers[website.tokenHeader] = cryptoToken ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey) : 'bearer ' + token; } // 开启报文加密 // if (cryptoData) { // if (config.params) { // const data = crypto.encryptAES(JSON.stringify(config.params), crypto.aesKey); // config.params = { data }; // } // if (config.data) { // config.text = true; // config.data = crypto.encryptAES(JSON.stringify(config.data), crypto.aesKey); // } // } //headers中配置text请求 if (config.text === true) { config.headers['Content-Type'] = 'text/plain'; } //headers中配置serialize为true开启序列化 if (config.method === 'post' && meta.isSerialize === true) { config.data = serialize(config.data); } return config; }, error => { return Promise.reject(error); } ); //http response拦截 axios.interceptors.response.use( res => { NProgress.done(); const status = res.data.error_code || res.data.code || res.status; const statusWhiteList = website.statusWhiteList || []; 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 if (status === 401 && !_retry) { // 标记此请求已尝试刷新token _retry = true; // 调用RefreshToken action来刷新token return store .dispatch('RefreshToken') .then(() => { const meta = config.meta || {}; const isToken = meta.isToken === false; const cryptoToken = config.cryptoToken === true; // 获取刷新后的token const token = getToken(); if (token && !isToken) { config.headers[website.tokenHeader] = cryptoToken ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey) : 'bearer ' + token; } // 重新发送原来的请求 return axios(config); }) .catch(() => { // 首次报错时提示 if (!isErrorShown) { isErrorShown = true; ElMessage({ message: message, type: 'error', }); } // 清除token信息 removeToken(); removeRefreshToken(); // 重定向到登录页 // store.dispatch('FedLogOut').then(() => router.push({ // path: '/login' // })); store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`)); return Promise.reject(new Error(message)); }); } // 如果是401并且已经重试过,直接跳转到登录页面 if (status === 401 && _retry) { // 首次报错时提示 if (!isErrorShown) { isErrorShown = true; ElMessage({ message: '用户令牌过期,请重新登录', type: 'error', }); } // 清除token信息 removeToken(); removeRefreshToken(); // 重定向到登录页 // store.dispatch('FedLogOut').then(() => router.push({ // path: '/login' // })); store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`)); return Promise.reject(new Error(message)); } // 如果请求为oauth2错误码则首次报错时提示 if (status > 2000 && !validatenull(res.data.error_description)) { // 首次报错时提示 if (!isErrorShown) { isErrorShown = true; ElMessage({ message: message, type: 'error', }); } return Promise.reject(new Error(message)); } // 如果请求为非200默认统一处理 if (status !== 200 && status !== 0) { if (!isErrorShown) { ElMessage({ message: message, type: 'error', }); } return Promise.reject(new Error(message)); } // 解析加密报文 if (cryptoData) { res.data = JSON.parse(crypto.decryptAES(res.data, crypto.aesKey)); } return res; }, error => { NProgress.done(); return Promise.reject(new Error(error)); } res => { NProgress.done(); const status = res.data.error_code || res.data.code || res.status; const statusWhiteList = website.statusWhiteList || []; 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 if (status === 401 && !_retry) { // 标记此请求已尝试刷新token _retry = true; // 调用RefreshToken action来刷新token return store .dispatch('RefreshToken') .then(() => { const meta = config.meta || {}; const isToken = meta.isToken === false; const cryptoToken = config.cryptoToken === true; // 获取刷新后的token const token = getToken(); if (token && !isToken) { config.headers[website.tokenHeader] = cryptoToken ? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey) : 'bearer ' + token; } // 重新发送原来的请求 return axios(config); }) .catch(() => { // 首次报错时提示 if (!isErrorShown) { isErrorShown = true; ElMessage({ message: message, type: 'error', }); } // 清除token信息 removeToken(); removeRefreshToken(); const env = import.meta.env.VITE_APP_ENV; // 重定向到登录页 // store.dispatch('FedLogOut').then(() => router.push({ // path: '/login' // })); env === 'development' ? store.dispatch('FedLogOut').then(() => router.push({ path: '/login', }) ) : store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`)); return Promise.reject(new Error(message)); }); } // 如果是401并且已经重试过,直接跳转到登录页面 if (status === 401 && _retry) { // 首次报错时提示 if (!isErrorShown) { isErrorShown = true; ElMessage({ message: '用户令牌过期,请重新登录', type: 'error', }); } // 清除token信息 removeToken(); removeRefreshToken(); // 重定向到登录页 // store.dispatch('FedLogOut').then(() => router.push({ // path: '/login' // })); const env = import.meta.env.VITE_APP_ENV; env === 'development' ? store.dispatch('FedLogOut').then(() => router.push({ path: '/login', }) ) : store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`)); return Promise.reject(new Error(message)); } // 如果请求为oauth2错误码则首次报错时提示 if (status > 2000 && !validatenull(res.data.error_description)) { // 首次报错时提示 if (!isErrorShown) { isErrorShown = true; ElMessage({ message: message, type: 'error', }); } return Promise.reject(new Error(message)); } // 如果请求为非200默认统一处理 if (status !== 200 && status !== 0) { if (!isErrorShown) { ElMessage({ message: message, type: 'error', }); } return Promise.reject(new Error(message)); } // 解析加密报文 if (cryptoData) { res.data = JSON.parse(crypto.decryptAES(res.data, crypto.aesKey)); } return res; }, error => { NProgress.done(); return Promise.reject(new Error(error)); } ); export default axios; src/buildConfig/buildConfig/config.default.js
New file @@ -0,0 +1,5 @@ export default function getBaseConfig () { return { loginTitle: '中图智飞低空智能感知网平台', //登陆页面标题 } } src/buildConfig/buildConfig/config.jiangwu.js
New file @@ -0,0 +1,10 @@ export default function getBaseConfig () { return { userLoginTitle (key) { return '大吉山钨业无人机安防监测平台' }, loginTitle: '大吉山钨业无人机安防监测平台', hideMenuTopLogo: true, // 是否隐藏菜单顶部logo } } src/buildConfig/config.js
New file @@ -0,0 +1,14 @@ // 直接导入所有配置文件 import jiangwuConfig from '@/buildConfig/buildConfig/config.jiangwu.js' import defaultConfig from '@/buildConfig/buildConfig/config.default.js' // 根据环境变量选择配置 const env = import.meta.env.VITE_APP_ENV || 'default' const configMap = { jiangwu: jiangwuConfig, default: defaultConfig } // 导出配置函数 export default configMap[env] || configMap.default src/page/index/logo.vue
@@ -3,13 +3,13 @@ <transition name="fade"> <span v-if="getScreen(isCollapse)" class="avue-logo_subtitle" key="0"> <!-- {{ website.logo }}--> <img class="logoImg" src="/img/bg/mainLogo.png" alt=""/> <img v-if="!hideMenuTopLogo" class="logoImg" src="/img/bg/mainLogo.png" alt=""/> </span> </transition> <transition-group name="fade"> <template v-if="getScreen(!isCollapse)"> <div class="fadeStyle"> <img class="logoImg" src="/img/bg/mainLogo.png" alt=""/> <img v-if="!hideMenuTopLogo" class="logoImg" src="/img/bg/mainLogo.png" alt=""/> <div class="titleName">综合管理平台</div> <!-- <span style="font-size: 20px;" key="1"> {{ this.parentDeptInfo.sysName }} @@ -22,11 +22,14 @@ <script> import { mapGetters } from 'vuex'; import getBaseConfig from '@/buildConfig/config'; const { hideMenuTopLogo } = getBaseConfig() export default { name: 'logo', data() { return {}; return { hideMenuTopLogo }; }, created() {}, computed: { src/page/index/top/index.vue
@@ -102,9 +102,11 @@ type: 'warning', }).then(() => { this.$store.dispatch('LogOut').then(() => { // this.$router.push({ path: '/login' }) const env = import.meta.env.VITE_APP_ENV console.log(env); const adminUrl = import.meta.env.VITE_APP_DASHBOARD_URL window.location.replace(`${adminUrl}#/login`) env === 'development' ? this.$router.push({ path: '/login' }):window.location.replace(`${adminUrl}#/login`) }) }) }, src/page/login/index.vue
@@ -39,7 +39,8 @@ import { getQueryString, getTopUrl } from '@/utils/util'; import { getDetail } from '@/api/system/sysConfig' import website from '@/config/website'; import getBaseConfig from '@/buildConfig/config' const { loginTitle} = getBaseConfig() export default { name: 'login', components: { @@ -51,7 +52,7 @@ data() { return { login:{ info: '中图智绘低空无人机监测网平台' info: loginTitle }, website: website, time: '', @@ -72,7 +73,10 @@ created() { this.handleLogin(); this.getTime(); if(!loginTitle) { this.getSysConfigInfo(); } }, mounted() {}, computed: { @@ -85,6 +89,7 @@ let sysConfigId = this.$route.query?.id || 1; getDetail(sysConfigId).then(res=>{ this.login.info = res.data.data.name }) }, getTime() { src/permission.js
@@ -19,6 +19,8 @@ const lockPage = '/lock' //锁屏页 const urlParams = getUrlParams(window.location.href) const adminUrl = import.meta.env.VITE_APP_DASHBOARD_URL const env = import.meta.env.VITE_APP_ENV function findRouteByPath (routes, targetPath) { // 遍历数组中的每个路由对象 for (const route of routes) { @@ -39,7 +41,6 @@ // 遍历完所有路由都没找到,返回null return null } router.beforeEach((to, from, next) => { const meta = to.meta || {} const isMenu = meta.menu === undefined ? to.query.menu : meta.menu @@ -93,10 +94,10 @@ } else { const systemToken = store.getters.token || urlParams?.token if (systemToken === 0) { // store.dispatch('FedLogOut').then(() => { // next({ path: '/login' }) // }) store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`)); store.dispatch('FedLogOut').then(() => { next({ path: '/login' }) }) // store.dispatch('FedLogOut').then(() => window.location.replace(`${adminUrl}#/login`)); } else { const meta = to.meta || {} const query = to.query || {} @@ -121,8 +122,7 @@ if (meta.isAuth === false) { next() } else { // next('/login') window.location.replace(`${adminUrl}#/login`) env === 'development' ? next('/login') : window.location.replace(`${adminUrl}#/login`) } } }) src/views/algorithmRepository/algorithmRepository.vue
@@ -73,7 +73,7 @@ ref="imageRef" :src="getSmallImg(item.url)" show-progress :preview-src-list="[getSmallImg(item.url)]" :preview-src-list="[getShowImg(item.url)]" fit="cover" /> @@ -110,7 +110,7 @@ import { getDictionaryByCode } from '@/api/system/dictbiz'; import { getalgorithmList, selectDeviceList } from '@/api/algorithm'; import { getSmallImg } from '@/utils/util'; import { getSmallImg,getShowImg } from '@/utils/util'; import { useRouter } from 'vue-router'; const router = useRouter(); const baseUrl = import.meta.env.VITE_APP_PICTURE_URL; @@ -259,6 +259,7 @@ &:hover { background: url('/src/assets/images/ht-sfbg-hover.png') no-repeat center; background-size: 100% 100%; cursor: pointer; } &.active-bg { background: url('/src/assets/images/ht-sfbg-click.png') no-repeat center; src/views/job/components/JobRelatedEvents.vue
@@ -28,7 +28,7 @@ </div> <div class="item"> <div class="itemchild">关联算法:</div> <TaskAlgorithmBusiness :setWidth="186 +'px'" :showAlgorithm="true" @algorithmChange="algorithmChange" /> <TaskAlgorithmBusiness :setWidth="186" :showAlgorithm="true" @algorithmChange="algorithmChange" /> </div> </div> <div class="search-btn"> src/views/job/components/SearchBox.vue
@@ -234,12 +234,15 @@ let checked = ref('today'); let timeClick = (item, index) => { checked.value = item; // dateRange.value = dateRanges[item]; dateRange.value = []; // emit('change', dateRanges[item],timeListEnum[index]); searchForm.date_enum = timeListEnum[index]; handleSearch(); if (checked.value === item){ checked.value = null searchForm.date_enum = undefined }else{ checked.value = item searchForm.date_enum = timeListEnum[index] } dateRange.value = [] handleSearch() }; // 搜索 const handleSearch = () => { @@ -265,18 +268,8 @@ emit('search', params); }; const handleDateChange = val => { if (val && val.length === 2) { const start = dayjs(val[0]); const end = dayjs(val[1]); const diff = end.diff(start, 'day'); if (diff > 31) { ElMessage.warning('日期范围不能超过31天'); dateRange.value = []; return; } } handleSearch(); checked.value = null searchForm.date_enum = undefined }; // 重置 @@ -302,7 +295,7 @@ // watch( // () => store.state.task.jumpTask, // newVal => { // if (newVal && Object.keys(newVal).length) { // // 兼容当日任务 计划任务 历史任务传参 // if (newVal.clickValue) { @@ -343,7 +336,7 @@ const date = dayjs(calendarday.value).format(timeFormat); const dateArray = [date, date]; dateRange.value = dateArray; } // 查询一次 src/views/job/components/TaskAlgorithmBusiness.vue
@@ -2,6 +2,7 @@ <template> <div class="task-algorithm" v-if="showAlgorithm"> <el-select class="ztzf-select" :teleported="false" :style="{ width: pxToRem(setWidth) }" v-model="ai_types" @@ -16,7 +17,7 @@ </el-select> </div> <div class="task-business" v-if="showBusiness"> <el-select <el-select class="ztzf-select" :teleported="false" :style="{ width: pxToRem(setWidth) }" v-model="industry_type" @@ -31,7 +32,7 @@ <script setup> import { getMultipleDictionary } from '@/api/job/task' import { pxToRem } from '@/utils/rem' import { pxToRem } from '@/utils/rem'; // 接收父组件传参 const props = defineProps({ @@ -88,4 +89,33 @@ // --el-tag-hover-color: none !important; // color: #fff !important; // } ::v-deep(.ztzf-select) { .el-select__wrapper { z-index: 1111; /* 修改 Tooltip 面板样式 */ .el-popper.is-light { background: #fff !important; // box-shadow: none !important; // border: none !important; border-radius: 4px !important; .el-select__selection { max-width: 240px !important; .el-select__selected-item { .el-tag { // background: #fff !important; // color: #000; } } } .el-popper__arrow::before { // background: #fff !important; // border: 1px solid #8d8b8b !important; } } } } </style> src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue
@@ -50,12 +50,22 @@ <el-table-column prop="creator_name" label="创建人" align="center" show-overflow-tooltip /> <el-table-column label="操作" width="200" align="center"> <template #default="scope"> <div v-if="scope.row.status === 2" class="btnItem turnBack" link type="primary" @click="turnBack(scope.row)"> <div v-if="scope.row.status === 2" class="btnItem" link type="primary" @click="turnBack(scope.row)" > 返航 </div> <div v-if="scope.row.status === 1" class="btnItem cancelTask" link type="primary" @click="cancelTask(scope.row)"> <div v-if="scope.row.status === 1" class="btnItem" link type="primary" @click="cancelTask(scope.row)" > 取消任务 </div> <div class="btnItem" link type="primary" @click="handleDetail(scope.row)">查看</div> @@ -64,10 +74,19 @@ </el-table> </div> <div class="pagination"> <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" v-model:current-page="jobListParams.current" v-model:page-size="jobListParams.size" :page-sizes="[10, 20, 30, 40]" layout="prev, pager, next, sizes, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background :page-sizes="[10, 20, 30, 40,50,100]" :size="size" v-model:current-page="jobListParams.current" v-model:page-size="jobListParams.size" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </div> <!-- 添加任务 --> @@ -271,7 +290,7 @@ :deep(.el-pagination) { display: flex; justify-content: flex-end; justify-content: right; } :deep(.el-pagination button) { src/views/job/components/TaskTop/TaskTotal.vue
@@ -51,13 +51,14 @@ totalJobNum().then(res => { if (res.data.code !== 0) returen total.value = res.data.data.job_total_num numTotal.value = res.data.data.deal_job_num }) } // 获取其他任务统计 const getJobStatistics = value => { jobStatistics(value).then(res => { if (res.data.code !== 0) returen const {executed = 0,failed_executions = 0,go_home_executions = 0} = res.data?.data || {} numTotal.value = executed + failed_executions + go_home_executions 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 @@ -79,9 +80,6 @@ { immediate: true,deep: true } ) onMounted(() => { getTotalJobNum() }) </script> <style scoped lang="scss"> @@ -136,7 +134,7 @@ height: 160px; display: flex; gap: 10px; flex-wrap: wrap; align-content: space-evenly; .total { src/views/license/upload.vue
@@ -1,6 +1,6 @@ <!-- filepath: /d:/work/drone-web-manage/src/views/license/upload.vue --> <template> <basic-container> <!-- <basic-container> <el-upload class="upload-demo" drag @@ -12,46 +12,101 @@ <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> <div class="el-upload__tip">仅支持扩展名:lic</div> </el-upload> </basic-container> </basic-container> --> <!-- 密钥上传 --> <div class="upload-file"> <img v-if="isSuccess === 'success'" :src="uploadSuccess" alt="" /> <div v-if="isSuccess === 'success'">上传成功</div> <img v-if="isSuccess === 'error'" :src="uploadError" alt="" /> <div v-if="isSuccess === 'error'">上传失败</div> <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> </template> <script> import { uploadLicense } from '@/api/license/uploadLicense'; import { findLicenseDate } from '@/api/system/dict'; import uploadSuccess from '@/assets/images/uoload-success.png'; import uploadError from '@/assets/images/upload-error.png'; export default { data() { return { isSuccess: '', // 上传状态 passwordTime: '', // 密钥有效期 uploadSuccess, // 上传成功图片 uploadError, // 上传失败图片 }; }, mounted() { this.getFindLicenseDate(); }, methods: { async customUpload({ file }) { try { const response = await uploadLicense(file); if (response.data.success) { this.$message.success('文件上传成功'); } else { this.$message.error(response.data.message || '文件上传失败'); } } catch (error) { console.error('上传失败:', error); this.$message.error('文件上传失败'); } handleUpload(file) { uploadLicense(file) .then(res => { console.log(res.data.code,'444') if (res.data.code !== 200) return this.$message.error('上传失败'); this.$message.success('上传成功'); this.isSuccess = 'success'; this.getFindLicenseDate(); }) .catch(err => { this.isSuccess = 'error'; this.$message.error('上传失败'); }); }, getFindLicenseDate() { findLicenseDate() .then(res => { if (res.data.code !== 0) return this.$message.error('上传失败'); this.passwordTime = res.data.data; }) .catch(err => { this.$message.error('获取失败失败'); }); }, }, }; </script> <style scoped> .upload-demo { width: 100%; border: 2px dashed #d9d9d9; border-radius: 6px; background-color: #fafafa; <style scoped lang="scss"> .upload-file { text-align: center; margin-top: 60px; .upload-btn { width: 93px; height: 38px; background: #DDEBFF; border-radius: 8px 8px 8px 8px; border: 1px solid #409EFF; text-align: center; padding: 40px 20px; } .el-upload__text { font-size: 16px; color: #606266; } .el-upload__tip { font-size: 12px; color: #909399; font-family: Source Han Sans CN, Source Han Sans CN; font-weight: bold; font-size: 14px; color: #228CFA; line-height: 38px; text-align: center; margin-top: 10px; } .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> src/views/system/userinfo.vue
@@ -108,22 +108,6 @@ <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="" /> <div v-if="isSuccess === 'success'">上传成功</div> <img v-if="isSuccess === 'error'" :src="uploadError" alt="" /> <div v-if="isSuccess === 'error'">上传失败</div> <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> @@ -136,7 +120,6 @@ import request from '@/axios'; import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user'; import { findLicenseDate } from '@/api/system/dict'; import { uploadLicense } from '@/api/license/uploadLicense'; import uploadSuccess from '@/assets/images/uoload-success.png'; import uploadError from '@/assets/images/upload-error.png'; import cancel1 from '@/assets/images/task/cancel1.png'; @@ -146,7 +129,7 @@ const token = getToken(); const userinforShow = defineModel('show'); const userInfoAs = computed(() => store.state.user.userInfo); const titleList = ref(['个人信息', '修改密码', '密钥上传']); const titleList = ref(['个人信息', '修改密码']); const checked = ref(0); const uploadUrl = computed( () => `${import.meta.env.VITE_APP_API_URL}/blade-resource/oss/endpoint/put-file` @@ -221,9 +204,6 @@ const titleClick = (item, index) => { checked.value = index; if (index === 2) { getFindLicenseDate(); } }; const getUserInfoData = () => { getUserInfo().then(res => { @@ -285,21 +265,6 @@ }; 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 => { @@ -415,34 +380,5 @@ .passwordBox { margin-top: 40px; } .upload-file { text-align: center; margin-top: 60px; .upload-btn { width: 93px; height: 38px; background: #DDEBFF; border-radius: 8px 8px 8px 8px; border: 1px solid #409EFF; text-align: center; font-family: Source Han Sans CN, Source Han Sans CN; font-weight: bold; font-size: 14px; color: #228CFA; line-height: 38px; text-align: center; margin-top: 10px; } .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> src/views/tickets/ticket.vue
@@ -32,7 +32,7 @@ <!-- 表格部分 --> <avue-crud ref="avueCrud" v-model="tableData" :option="option" :data="tableData" v-model:page="page" @size-change="sizeChange" @current-change="handleCurrentChange" :table-loading="loading" @size-change="sizeChange" @current-change="handleCurrentChange" @refresh-change="refreshChange" :table-loading="loading" @selection-change="handleSelectionChange" :permission="permissionList" v-if="activeTab === tab.name"> <template #menu-left> <el-button v-if="(activeTab === 'all' || activeTab === 'myTickets') && permissionList.addBtn" @@ -53,8 +53,11 @@ <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button> </template> <el-button v-if="row.status === 4 && row.isReview !== 1" type="text" icon="el-icon-check" @click="reCheck(row)">复核</el-button> <template v-if="permission.tickets_repeat_review"> <el-button v-if="row.status === 4 && row.isReview !== 1" type="text" icon="el-icon-check" @click="reCheck(row)">复核</el-button> </template> </template> <template #status="{ row }"> <span :style="getStatusTagType(row.status) ? 'color:' + getStatusTagType(row.status) : ''"> @@ -145,11 +148,21 @@ </el-col> <el-col :span="12"> <el-form-item label="附件图片" prop="photos" required class="upload-wrapper"> <el-upload ref="upload" :action="'#'" :auto-upload="false" list-type="picture-card" <el-upload v-if="createoredit === 1" ref="upload" :action="'#'" :auto-upload="false" list-type="picture-card" :on-change="handleFileChange" :on-remove="handleUploadRemove" :before-upload="beforeUpload" :file-list="form.photos" :limit="1" accept="image/*" class="create-upload"> <template v-if="form.photos.length < 1"> <!-- <i class="el-icon-plus">+</i> --> <div class="el-icon-plus"> <span>+</span> </div> </template> </el-upload> <el-upload v-else ref="upload" :action="'#'" :auto-upload="false" list-type="picture-card" :on-change="handleFileChange" :on-remove="handleUploadRemove" :before-upload="beforeUpload" :file-list="popupShowImage(form.photos)" :limit="1" accept="image/*" class="create-upload"> <template v-if="form.photos.length < 1"> <div class="el-icon-plus"> <span>+</span> </div> @@ -504,9 +517,11 @@ </template> <script> import { getSmallImg,getShowImg } from '@/utils/util'; import { ElMessageBox, ElLoading } from 'element-plus' import { calculateDefaultRange } from '@/utils/util' import { gcj02ToWgs84, wgs84ToGcj02 } from '@/utils/coordinateTransformation' import _ from 'lodash' import { getList, createTicket, @@ -519,7 +534,6 @@ } from '@/api/tickets/ticket' import { export_json_to_excel } from '@/utils/exportExcel' import geoJson from '@/assets/geoJson.json' import { mapGetters } from 'vuex' import { getAdcodeObj } from '@/utils/disposeData' function regExp (label, name) { @@ -539,6 +553,7 @@ dispatchLoading: false, completeLoading: false, finalizeLoading: false, createoredit:'', activeTab: 'all', // tabs 只保留静态结构,不做权限判断 tabs: [ @@ -730,6 +745,11 @@ mounted () { const href = this.$route.href if (this.$route?.query?.status !== undefined && this.$route?.query?.status !== null){ this.filters.status = this.$route?.query?.status + '' this.$router.replace({}) } let curQueryParams = {} if (href.indexOf('?') != -1 && href.split('?').length > 0) { @@ -891,7 +911,7 @@ { label: '关联任务', value: this.currentDetail.job_name || '/' }, { label: '任务发起人', value: this.currentDetail.creator }, { label: '当前状态', value: this.mapStatus(this.currentDetail.status) }, { label: '事件地址', value: this.currentDetail.address }, // 包含经纬度信息 { label: '事件地址', value: this.currentDetail.address || this.currentDetail.latAndLon }, // 包含经纬度信息 { label: '关联算法', value: this.currentDetail.aiType }, { label: '发起单位', value: this.currentDetail.department }, { label: '发起任务时间', value: this.currentDetail.startTime }, @@ -968,6 +988,16 @@ return '/' } }, popupShowImage () { return (list) => { return list.map(item => ({ ...item, url: getShowImg(item.url) })) } } }, methods: { @@ -1474,6 +1504,8 @@ }, async handleCurrentChange (val) { // 先更新页码 this.page.currentPage = val // 等待 DOM 更新后再请求数据 @@ -1482,6 +1514,7 @@ }, async sizeChange (val) { this.page.pageSize = val this.page.currentPage = 1 // 重置到第一页 await this.$nextTick() @@ -1489,6 +1522,8 @@ }, handleAdd () { this.createoredit =1 this.dialogVisible = true this.mapParams.center = null this.form.location = [] @@ -1520,6 +1555,7 @@ }, async handleViewDetail (row) { // 找到当前行在tableData中的索引 this.currentIndex = this.tableData.findIndex(item => item.id === row.id) // 先设置workType,直接从row读取 @@ -1569,8 +1605,8 @@ }) } this.currentDetail.status = row.status } catch (error) { if (this.activeTab === 'myTickets') { const statusArr = this.workType === 1 ? ['3', '4'] : this.fixedStatuses @@ -1583,8 +1619,13 @@ this.stepInfos = [] } } console.log(detailData,'detailDatadetailDatadetailData'); this.currentDetail = { ...detailData, address:null, latAndLon: _.round(detailData.location[0],6) + ',' + _.round(detailData.location[1],6) } this.currentDetail = detailData console.log('this.currentDetail',this.currentDetail); this.detailVisible = true this.$nextTick(() => { @@ -1999,6 +2040,7 @@ // 添加编辑方法 handleEdit (row) { this.createoredit = 2 console.log('编辑原始数据:', row) // 尝试从row.dept_id或通过部门名称查找对应的部门ID @@ -2074,6 +2116,7 @@ address: row.address || '', content: row.content, photos: [], } let curLocation = [] @@ -2147,6 +2190,7 @@ // 添加选择变化处理方法 handleSelectionChange (selection) { this.selections = selection console.log('已选择的行:', selection) },