Merge remote-tracking branch 'origin/master'
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | |
| | | import logo from '@/assets/images/topContainer/logo.png' |
| | | |
| | | import { mapGetters } from 'vuex' |
| | |
| | | }, |
| | | methods: { |
| | | logout () { |
| | | this.$confirm(this.$t('logoutTip'), this.$t('提示'), { |
| | | confirmButtonText: this.$t('submitText'), |
| | | cancelButtonText: this.$t('cancelText'), |
| | | ElMessageBox.confirm(`是否退出系统, 是否继续?`, '提示', { |
| | | type: 'warning', |
| | | customClass: 'command-page-view-message-box', |
| | | confirmButtonClass: 'command-message-box-confirm', |
| | | cancelButtonClass: 'command-message-box-cancel', |
| | | }).then(() => { |
| | | this.$store.dispatch('LogOut').then(() => { |
| | | const env = import.meta.env.VITE_APP_ENV |
| | |
| | | </div> |
| | | <div class="login-weaper"> |
| | | <div class="login-left animate__animated animate__fadeInLeft"> |
| | | <img class="img" src="/img/logo.png" alt="" /> |
| | | <img class="img" src="/img/logo.png" alt="" /> |
| | | <p class="title">{{ $t('login.info') }}</p> |
| | | </div> |
| | | <div class="login-border animate__animated animate__fadeInRight"> |
| | | <div class="login-main"> |
| | | <div class="lock-form animate__animated animate__bounceInDown"> |
| | | <div |
| | | class="animate__animated" |
| | | :class="{ shake: passwdError, animate__bounceOut: pass }" |
| | | > |
| | | <div class="animate__animated" :class="{ shake: passwdError, animate__bounceOut: pass }"> |
| | | <h3 style="color: #333">{{ userInfo.username }}</h3> |
| | | <el-input |
| | | placeholder="请输入登录密码" |
| | | type="password" |
| | | class="input-with-select animated" |
| | | v-model="passwd" |
| | | @keyup.enter="handleLogin" |
| | | > |
| | | <el-input placeholder="请输入登录密码" type="password" class="input-with-select animated" v-model="passwd" |
| | | @keyup.enter="handleLogin"> |
| | | <template #append> |
| | | <i class="icon-bofangqi-suoping" @click="handleLogin"></i> |
| | | |
| | |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import { mapGetters } from 'vuex'; |
| | | import { removeRefreshToken, removeToken } from '@/utils/auth'; |
| | | import { mapGetters } from 'vuex' |
| | | import { removeRefreshToken, removeToken } from '@/utils/auth' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | |
| | | export default { |
| | | name: 'lock', |
| | | data() { |
| | | data () { |
| | | return { |
| | | time: '', |
| | | timeTimer: null, |
| | | passwd: '', |
| | | passwdError: false, |
| | | pass: false, |
| | | }; |
| | | }, |
| | | created() { |
| | | this.getTime(); |
| | | if (this.timeTimer) clearInterval(this.timeTimer); |
| | | this.timeTimer = setInterval(() => { |
| | | this.getTime(); |
| | | }, 1000); |
| | | }, |
| | | beforeDestroy() { |
| | | if (this.timeTimer) { |
| | | clearInterval(this.timeTimer); |
| | | this.timeTimer = null; |
| | | } |
| | | }, |
| | | mounted() {}, |
| | | created () { |
| | | this.getTime() |
| | | if (this.timeTimer) clearInterval(this.timeTimer) |
| | | this.timeTimer = setInterval(() => { |
| | | this.getTime() |
| | | }, 1000) |
| | | }, |
| | | beforeDestroy () { |
| | | if (this.timeTimer) { |
| | | clearInterval(this.timeTimer) |
| | | this.timeTimer = null |
| | | } |
| | | }, |
| | | mounted () { }, |
| | | computed: { |
| | | ...mapGetters(['userInfo', 'tag', 'lockPasswd']), |
| | | }, |
| | | props: [], |
| | | methods: { |
| | | getTime() { |
| | | this.time = this.$dayjs().format('YYYY年MM月DD日 HH:mm:ss'); |
| | | getTime () { |
| | | this.time = this.$dayjs().format('YYYY年MM月DD日 HH:mm:ss') |
| | | }, |
| | | handleLogout() { |
| | | this.$confirm('是否退出系统, 是否继续?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | handleLogout () { |
| | | ElMessageBox.confirm(`是否退出系统, 是否继续?`, '提示', { |
| | | type: 'warning', |
| | | customClass: 'command-page-view-message-box', |
| | | confirmButtonClass: 'command-message-box-confirm', |
| | | cancelButtonClass: 'command-message-box-cancel', |
| | | }).then(() => { |
| | | this.$store.dispatch('LogOut').then(() => { |
| | | // 清除token信息 |
| | | removeToken(); |
| | | removeRefreshToken(); |
| | | this.$router.push({ path: '/login' }); |
| | | }); |
| | | }); |
| | | removeToken() |
| | | removeRefreshToken() |
| | | this.$router.push({ path: '/login' }) |
| | | }) |
| | | }) |
| | | }, |
| | | handleLogin() { |
| | | handleLogin () { |
| | | if (this.passwd !== this.lockPasswd) { |
| | | this.passwd = ''; |
| | | this.passwd = '' |
| | | this.$message({ |
| | | message: '解锁密码错误,请重新输入', |
| | | type: 'error', |
| | | }); |
| | | this.passwdError = true; |
| | | }) |
| | | this.passwdError = true |
| | | setTimeout(() => { |
| | | this.passwdError = false; |
| | | }, 1000); |
| | | return; |
| | | this.passwdError = false |
| | | }, 1000) |
| | | return |
| | | } |
| | | this.pass = true; |
| | | this.pass = true |
| | | setTimeout(() => { |
| | | this.$store.commit('CLEAR_LOCK'); |
| | | this.$store.commit('CLEAR_LOCK') |
| | | this.$router.push({ |
| | | path: this.tag.path, |
| | | }); |
| | | }, 1000); |
| | | }) |
| | | }, 1000) |
| | | }, |
| | | }, |
| | | components: {}, |
| | | }; |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"></style> |
| | |
| | | params: { descs: 'update_time', ...params }, |
| | | }) |
| | | } |
| | | // 查list |
| | | // 查list --- 区域 |
| | | export const fwAreaDivideListApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/area/fwAreaDivide/list`, |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="设备状态" prop="deviceStatus"> |
| | | <el-form-item label="设备状态" prop="status"> |
| | | <el-select |
| | | class="command-select" |
| | | popper-class="command-select-popper" |
| | | v-model="searchParams.deviceStatus" |
| | | v-model="searchParams.status" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="handleSearch" |
| | |
| | | const initSearchParams = () => ({ |
| | | deviceName: '', // 设备名称 |
| | | deviceType: '', // 设备类型 |
| | | deviceStatus: '', // 设备状态 |
| | | status: '', // 设备状态 |
| | | current: 1, // 当前页 |
| | | size: 10, // 每页大小 |
| | | }) |
| | |
| | | <div class="val">{{ formData.deviceSn }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">场景</div> |
| | | <div class="val">{{ formData.defenseSceneName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">区域</div> |
| | | <div class="val">{{ formData.areaDivideName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">场景</div> |
| | | <div class="val">{{ formData.defenseSceneName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="label">调度人员</div> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="场景" prop="defenseSceneId"> |
| | | <el-select class="command-select" popper-class="command-select-popper" |
| | | v-model="formData.defenseSceneId" placeholder="请选择" clearable @change="handleSceneChange"> |
| | | <el-option v-for="item in sceneList" :key="item.id" :label="item.sceneName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="区域" prop="areaDivideId"> |
| | | <el-select class="command-select" popper-class="command-select-popper" |
| | | v-model="formData.areaDivideId" placeholder="请先选择场景" clearable |
| | | :disabled="!formData.defenseSceneId" @change="handleAreaChange"> |
| | | v-model="formData.areaDivideId" placeholder="请选择" clearable |
| | | @change="handleAreaChange"> |
| | | <el-option v-for="item in areaList" :key="item.id" :label="item.areaName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="场景" prop="defenseSceneId"> |
| | | <el-select class="command-select" popper-class="command-select-popper" |
| | | v-model="formData.defenseSceneId" placeholder="请先选择区域" clearable |
| | | :disabled="!formData.areaDivideId" @change="handleSceneChange"> |
| | | <el-option v-for="item in sceneList" :key="item.id" :label="item.sceneName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="调度位置" prop="longitude"> |
| | | <!-- <el-button @click="selectLocation" style="width: 100%">--> |
| | | <el-button style="width: 100%"> |
| | | {{ |
| | | formData.longitude && formData.latitude ? `${formData.longitude}, ${formData.latitude}` : |
| | | '选择区域后自动带出' |
| | | }} |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="调度人员" prop="dispatchUser"> |
| | | <el-input class="command-input" v-model="formData.dispatchUser" maxlength="50" placeholder="请输入" |
| | |
| | | start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="调度位置" prop="longitude"> |
| | | <!-- <el-button @click="selectLocation" style="width: 100%">--> |
| | | <el-button style="width: 100%"> |
| | | {{ |
| | | formData.longitude && formData.latitude ? `${formData.longitude}, ${formData.latitude}` : |
| | | '选择区域后自动带出' |
| | | }} |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="24"> |
| | | <el-form-item label="调度内容" prop="dispatchContent"> |
| | | <el-input class="command-input" v-model="formData.dispatchContent" type="textarea" :rows="3" |
| | |
| | | import { ElMessage } from 'element-plus' |
| | | import { fwTaskScheduleDetailApi, fwTaskScheduleSubmitApi } from './taskScheduleApi' |
| | | import { fwAreaDivideListApi } from '@/views/areaManage/partition/partitionApi' |
| | | import { fwDefenseSceneListApi } from '@/views/areaManage/sceneConfig/sceneConfigApi' |
| | | import { fieldRules } from '@ztzf/utils' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import * as Cesium from 'cesium' |
| | |
| | | }) |
| | | |
| | | const props = defineProps({ |
| | | sceneList: { type: Array, default: () => [] }, |
| | | deviceList: { type: Array, default: () => [] }, |
| | | }) |
| | | |
| | |
| | | const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) |
| | | const tempLocation = ref({ longitude: null, latitude: null }) |
| | | const areaList = ref([]) // 区域列表 |
| | | const sceneList = ref([]) // 场景列表 |
| | | const deviceStatus = ref('') |
| | | |
| | | const rules = { |
| | |
| | | } |
| | | } |
| | | |
| | | // 场景选择变化处理 |
| | | async function handleSceneChange (sceneId) { |
| | | formData.value.areaDivideId = '' |
| | | if (sceneId) { |
| | | await loadAreaList(sceneId) |
| | | async function handleAreaChange (areaId) { |
| | | formData.value.defenseSceneId = '' |
| | | if (areaId) { |
| | | await loadSceneList(areaId) |
| | | } else { |
| | | areaList.value = [] |
| | | sceneList.value = [] |
| | | } |
| | | } |
| | | |
| | | function handleAreaChange (areaId) { |
| | | const find = areaList.value.find(item => item.id === areaId) |
| | | // 场景选择变化处理 |
| | | async function handleSceneChange (sceneId) { |
| | | const find = sceneList.value.find(item => item.id === sceneId) |
| | | formData.value.longitude = find?.longitude |
| | | formData.value.latitude = find?.latitude |
| | | } |
| | | |
| | | // 加载区域列表 |
| | | async function loadAreaList (sceneId) { |
| | | const res = await fwAreaDivideListApi({ sceneId }) |
| | | async function loadAreaList () { |
| | | const res = await fwAreaDivideListApi() |
| | | areaList.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | // 加载场景列表 |
| | | async function loadSceneList(areaId) { |
| | | const res = await fwDefenseSceneListApi({areaId}) |
| | | sceneList.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | // 关闭弹框 |
| | |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | |
| | | onMounted(() => { |
| | | loadAreaList() |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | #mapContainer { |
| | |
| | | @success="getList" |
| | | v-if="dialogVisible" |
| | | v-model="dialogVisible" |
| | | :sceneList="sceneList" |
| | | :deviceList="deviceList" |
| | | /> |
| | | </basic-container> |
| | |
| | | import { nextTick, onMounted, ref, provide } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { fwTaskSchedulePageApi, fwTaskScheduleRemoveApi } from './taskScheduleApi' |
| | | import { fwDefenseSceneListApi } from '@/views/areaManage/sceneConfig/sceneConfigApi' |
| | | import { fwDeviceListApi } from '@/views/basicManage/deviceStock/fwDevice' |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | |
| | | deviceType: [], // 设备类型 |
| | | deviceStatus: [], // 设备状态 |
| | | }) |
| | | const sceneList = ref([]) // 场景列表 |
| | | const deviceList = ref([]) // 设备列表 |
| | | |
| | | // 注入字典到子组件 |
| | |
| | | }) |
| | | } |
| | | |
| | | // 加载场景列表 |
| | | async function loadSceneList() { |
| | | const res = await fwDefenseSceneListApi() |
| | | sceneList.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | // 加载设备列表 |
| | | async function loadDeviceList() { |
| | | const res = await fwDeviceListApi() |
| | |
| | | |
| | | onMounted(() => { |
| | | getDictList() |
| | | loadSceneList() |
| | | loadDeviceList() |
| | | getList() |
| | | }) |
| | |
| | | .detail-container { |
| | | padding: 20px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | gap: 30px; |
| | | align-items: stretch; |
| | | } |
| | | |
| | | /* 左侧步骤条 */ |
| | |
| | | <template> |
| | | <div class="audit-record-container"> |
| | | <div class="label">审批记录</div> |
| | | <el-steps :active="activeStep" direction="vertical" align-center> |
| | | <el-step v-for="(step, index) in displayedSteps" :key="step.status" :title="step.title"> |
| | | <template #description> |
| | | <div class="step-person">{{ step.person }}</div> |
| | | <div class="step-time">{{ step.time }}</div> |
| | | </template> |
| | | </el-step> |
| | | <el-steps direction="vertical" :active="displayedSteps.length"> |
| | | <el-step v-for="step in displayedSteps" :key="step.status" :title="step.title" :description="`${step.person || ''}\n${step.time || ''}`" /> |
| | | </el-steps> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, watch, computed } from 'vue' |
| | | import { ref, watch } from 'vue' |
| | | import { gdSupplyDemandAuditListApi } from '@/views/orderView/orderDataManage/supplyAdd/supplyAddApi' |
| | | |
| | | const props = defineProps({ |
| | |
| | | const detailDemandStatus = inject('detailDemandStatus') |
| | | const reasonForRejection = inject('reasonForRejection') |
| | | |
| | | // 所有可能的步骤配置 |
| | | const allStepConfigs = ref([ |
| | | { title: '需求申请', status: '0', person: '', time: '' }, |
| | | { title: '审核通过', status: '1', person: '', time: '' }, |
| | | { title: '拒绝申请', status: '2', person: '', time: '' } |
| | | ]) |
| | | |
| | | // 步骤条数据 |
| | | const stepResponse = ref([]) |
| | | |
| | | // 当前激活步骤 |
| | | const activeStep = ref(0) |
| | | |
| | | // 计算要显示的步骤 |
| | | const displayedSteps = computed(() => { |
| | | // 创建一个映射,将状态映射到审核记录 |
| | | const statusToRecord = {}; |
| | | stepResponse.value.forEach(record => { |
| | | statusToRecord[record.auditStatus] = record; |
| | | }); |
| | | |
| | | // 根据审核记录筛选并构建要显示的步骤 |
| | | return allStepConfigs.value.filter(stepConfig => { |
| | | // 如果是需求申请步骤,始终显示 |
| | | if (stepConfig.status === '0') { |
| | | return true; |
| | | } |
| | | // 其他步骤只有在有对应状态的审核记录时才显示 |
| | | return statusToRecord.hasOwnProperty(stepConfig.status); |
| | | }).map(stepConfig => { |
| | | // 获取对应状态的审核记录 |
| | | const record = statusToRecord[stepConfig.status]; |
| | | if (record) { |
| | | // 如果有审核记录,使用记录中的信息 |
| | | return { |
| | | ...stepConfig, |
| | | person: record.createUser ? `${record.createUser}` : '', |
| | | time: record.createTime ? record.createTime : '' |
| | | }; |
| | | } |
| | | // 如果没有审核记录,使用默认信息 |
| | | return stepConfig; |
| | | }); |
| | | }) |
| | | |
| | | // 计算当前激活步骤 |
| | | const calculateCurrentStep = () => { |
| | | if (stepResponse.value.length === 0) { |
| | | return 0; |
| | | } |
| | | |
| | | // 获取最新的审核记录 |
| | | const latestRecord = stepResponse.value[stepResponse.value.length - 1]; |
| | | // 查找最新状态在显示步骤中的索引 |
| | | const stepIndex = displayedSteps.value.findIndex(step => step.status === latestRecord.auditStatus); |
| | | return stepIndex !== -1 ? stepIndex : 0; |
| | | } |
| | | const displayedSteps = ref([]) |
| | | |
| | | // 监听 demandId 变化 |
| | | watch(() => props.demandId, (newVal) => { |
| | |
| | | }, { immediate: true }) |
| | | |
| | | // 加载审核记录 |
| | | async function loadAuditRecords(demandId) { |
| | | try { |
| | | const res = await gdSupplyDemandAuditListApi({ demandId }) |
| | | function loadAuditRecords(demandId) { |
| | | gdSupplyDemandAuditListApi({ demandId }).then(res => { |
| | | const auditRecords = res?.data?.data ?? [] |
| | | |
| | | // 按创建时间排序(最新的在最后) |
| | | stepResponse.value = [...auditRecords].sort((a, b) => new Date(a.createTime) - new Date(b.createTime)) |
| | | |
| | | // 查找拒绝原因(auditStatus为2的记录的auditOpinion) |
| | | const rejectedRecord = stepResponse.value.find(record => record.auditStatus === '2') |
| | | reasonForRejection.value = rejectedRecord?.auditOpinion || '' |
| | | |
| | | // 计算当前激活步骤 |
| | | activeStep.value = calculateCurrentStep() |
| | | } catch (error) { |
| | | const sortedRecords = [...auditRecords].sort((a, b) => new Date(a.createTime) - new Date(b.createTime)) |
| | | |
| | | // 构建步骤数据 |
| | | const steps = [] |
| | | |
| | | // 添加需求申请步骤 |
| | | steps.push({ |
| | | status: '0', |
| | | title: '需求申请', |
| | | person: sortedRecords.find(r => r.auditStatus === '0')?.createUser || '', |
| | | time: sortedRecords.find(r => r.auditStatus === '0')?.createTime || '' |
| | | }) |
| | | |
| | | // 添加审核通过步骤(如果有) |
| | | const approvedRecord = sortedRecords.find(r => r.auditStatus === '1') |
| | | if (approvedRecord) { |
| | | steps.push({ |
| | | status: '1', |
| | | title: '审核通过', |
| | | person: approvedRecord.createUser || '', |
| | | time: approvedRecord.createTime || '' |
| | | }) |
| | | } |
| | | |
| | | // 添加拒绝申请步骤(如果有) |
| | | const rejectedRecord = sortedRecords.find(r => r.auditStatus === '2') |
| | | if (rejectedRecord) { |
| | | steps.push({ |
| | | status: '2', |
| | | title: '拒绝申请', |
| | | person: rejectedRecord.createUser || '', |
| | | time: rejectedRecord.createTime || '' |
| | | }) |
| | | // 查找拒绝原因 |
| | | reasonForRejection.value = rejectedRecord.auditOpinion || '' |
| | | } |
| | | |
| | | displayedSteps.value = steps |
| | | }).catch(error => { |
| | | console.error('加载审核记录失败:', error) |
| | | // 重置步骤数据 |
| | | stepResponse.value = [] |
| | | activeStep.value = 0 |
| | | displayedSteps.value = [] |
| | | reasonForRejection.value = '' |
| | | } |
| | | }) |
| | | } |
| | | |
| | | defineExpose({ |
| | |
| | | } |
| | | |
| | | :deep(.el-step) { |
| | | margin-bottom: 20px; |
| | | // margin-bottom: 20px; |
| | | } |
| | | |
| | | :deep(.el-step__title) { |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | /* 步骤描述 */ |
| | | .step-person { |
| | | :deep(.el-step__description) { |
| | | font-size: 13px; |
| | | color: #333; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | color: #666; |
| | | white-space: pre-wrap; |
| | | line-height: 1.4; |
| | | } |
| | | </style> |