调整代码

This commit is contained in:
guanj
2025-11-20 15:12:01 +08:00
parent 0a52d1afae
commit 028fd44490
17 changed files with 3910 additions and 3761 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

BIN
public/favicon3.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,310 +1,310 @@
<template> <template>
<div class="w100"> <div class="w100">
<!-- el-select 的远程下拉只在有搜索词时才会加载数据显示出 option 列表 --> <!-- el-select 的远程下拉只在有搜索词时才会加载数据显示出 option 列表 -->
<!-- 使用 el-popover 在无数据/无搜索词时显示一个无数据的提醒 --> <!-- 使用 el-popover 在无数据/无搜索词时显示一个无数据的提醒 -->
<el-popover <el-popover
width="100%" width="100%"
placement="bottom" placement="bottom"
popper-class="remote-select-popper" popper-class="remote-select-popper"
:visible="state.focusStatus && !state.loading && !state.keyword && !state.options.length" :visible="state.focusStatus && !state.loading && !state.keyword && !state.options.length"
:teleported="false" :teleported="false"
:content="$t('utils.No data')" :content="$t('utils.No data')"
> >
<template #reference> <template #reference>
<el-select <el-select
ref="selectRef" ref="selectRef"
class="w100" class="w100"
@focus="onFocus" @focus="onFocus"
@blur="onBlur" @blur="onBlur"
:loading="state.loading || state.accidentBlur" :loading="state.loading || state.accidentBlur"
:filterable="true" :filterable="true"
:remote="true" :remote="true"
clearable clearable
remote-show-suffix remote-show-suffix
:remote-method="onLogKeyword" :remote-method="onLogKeyword"
v-model="state.value" v-model="state.value"
@change="onChangeSelect" @change="onChangeSelect"
:multiple="multiple" :multiple="multiple"
:key="state.selectKey" :key="state.selectKey"
@clear="onClear" @clear="onClear"
@visible-change="onVisibleChange" @visible-change="onVisibleChange"
v-bind="$attrs" v-bind="$attrs"
> >
<el-option <el-option
class="remote-select-option" class="remote-select-option"
v-for="item in state.options" v-for="item in state.options"
:label="item[field]" :label="item[field]"
:value="item[state.primaryKey].toString()" :value="item[state.primaryKey].toString()"
:key="item[state.primaryKey]" :key="item[state.primaryKey]"
> >
<el-tooltip placement="right" effect="light" v-if="!isEmpty(tooltipParams)"> <el-tooltip placement="right" effect="light" v-if="!isEmpty(tooltipParams)">
<template #content> <template #content>
<p v-for="(tooltipParam, key) in tooltipParams" :key="key">{{ key }}: {{ item[tooltipParam] }}</p> <p v-for="(tooltipParam, key) in tooltipParams" :key="key">{{ key }}: {{ item[tooltipParam] }}</p>
</template> </template>
<div>{{ item[field] }}</div> <div>{{ item[field] }}</div>
</el-tooltip> </el-tooltip>
</el-option> </el-option>
<el-pagination <el-pagination
v-if="state.total" v-if="state.total"
:currentPage="state.currentPage" :currentPage="state.currentPage"
:page-size="state.pageSize" :page-size="state.pageSize"
class="select-pagination" class="select-pagination"
layout="->, prev, next" layout="->, prev, next"
:total="state.total" :total="state.total"
@current-change="onSelectCurrentPageChange" @current-change="onSelectCurrentPageChange"
/> />
</el-select> </el-select>
</template> </template>
</el-popover> </el-popover>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, watch, onMounted, onUnmounted, ref, nextTick, getCurrentInstance, toRaw } from 'vue' import { reactive, watch, onMounted, onUnmounted, ref, nextTick, getCurrentInstance, toRaw } from 'vue'
import { getSelectData } from '@/api/common' // import { getSelectData } from '@/api/common'
import { uuid } from '@/utils/random' import { uuid } from '@/utils/random'
import type { ElSelect } from 'element-plus' import type { ElSelect } from 'element-plus'
import { isEmpty } from 'lodash-es' import { isEmpty } from 'lodash-es'
import { getArrayKey } from '@/utils/common' // import { getArrayKey } from '@/utils/common'
const selectRef = ref<InstanceType<typeof ElSelect> | undefined>() const selectRef = ref<InstanceType<typeof ElSelect> | undefined>()
type ElSelectProps = Partial<InstanceType<typeof ElSelect>['$props']> type ElSelectProps = Partial<InstanceType<typeof ElSelect>['$props']>
type valType = string | number | string[] | number[] type valType = string | number | string[] | number[]
interface Props extends /* @vue-ignore */ ElSelectProps { interface Props extends /* @vue-ignore */ ElSelectProps {
pk?: string pk?: string
field?: string field?: string
params?: anyObj params?: anyObj
multiple?: boolean multiple?: boolean
remoteUrl: string remoteUrl: string
modelValue: valType modelValue: valType
labelFormatter?: (optionData: anyObj, optionKey: string) => string labelFormatter?: (optionData: anyObj, optionKey: string) => string
tooltipParams?: anyObj tooltipParams?: anyObj
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
pk: 'id', pk: 'id',
field: 'name', field: 'name',
params: () => { params: () => {
return {} return {}
}, },
remoteUrl: '', remoteUrl: '',
modelValue: '', modelValue: '',
multiple: false, multiple: false,
tooltipParams: () => { tooltipParams: () => {
return {} return {}
}, },
}) })
const state: { const state: {
// 主表字段名(不带表别名) // 主表字段名(不带表别名)
primaryKey: string primaryKey: string
options: anyObj[] options: anyObj[]
loading: boolean loading: boolean
total: number total: number
currentPage: number currentPage: number
pageSize: number pageSize: number
params: anyObj params: anyObj
keyword: string keyword: string
value: valType value: valType
selectKey: string selectKey: string
initializeData: boolean initializeData: boolean
accidentBlur: boolean accidentBlur: boolean
focusStatus: boolean focusStatus: boolean
} = reactive({ } = reactive({
primaryKey: props.pk, primaryKey: props.pk,
options: [], options: [],
loading: false, loading: false,
total: 0, total: 0,
currentPage: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
params: props.params, params: props.params,
keyword: '', keyword: '',
value: props.modelValue ? props.modelValue : '', value: props.modelValue ? props.modelValue : '',
selectKey: uuid(), selectKey: uuid(),
initializeData: false, initializeData: false,
accidentBlur: false, accidentBlur: false,
focusStatus: false, focusStatus: false,
}) })
let io: null | IntersectionObserver = null let io: null | IntersectionObserver = null
const instance = getCurrentInstance() const instance = getCurrentInstance()
const emits = defineEmits<{ const emits = defineEmits<{
(e: 'update:modelValue', value: valType): void (e: 'update:modelValue', value: valType): void
(e: 'row', value: any): void (e: 'row', value: any): void
}>() }>()
const onChangeSelect = (val: valType) => { const onChangeSelect = (val: valType) => {
emits('update:modelValue', val) emits('update:modelValue', val)
if (typeof instance?.vnode.props?.onRow == 'function') { if (typeof instance?.vnode.props?.onRow == 'function') {
let pkArr = props.pk.split('.') let pkArr = props.pk.split('.')
let pk = pkArr[pkArr.length - 1] let pk = pkArr[pkArr.length - 1]
if (typeof val == 'number' || typeof val == 'string') { if (typeof val == 'number' || typeof val == 'string') {
const dataKey = getArrayKey(state.options, pk, val.toString()) // const dataKey = getArrayKey(state.options, pk, val.toString())
emits('row', dataKey ? toRaw(state.options[dataKey]) : {}) // emits('row', dataKey ? toRaw(state.options[dataKey]) : {})
} else { } else {
const valueArr = [] // const valueArr = []
for (const key in val) { // for (const key in val) {
let dataKey = getArrayKey(state.options, pk, val[key].toString()) // let dataKey = getArrayKey(state.options, pk, val[key].toString())
if (dataKey) valueArr.push(toRaw(state.options[dataKey])) // if (dataKey) valueArr.push(toRaw(state.options[dataKey]))
} // }
emits('row', valueArr) // emits('row', valueArr)
} }
} }
} }
const onVisibleChange = (val: boolean) => { const onVisibleChange = (val: boolean) => {
// 保持面板状态和焦点状态一致 // 保持面板状态和焦点状态一致
if (!val) { if (!val) {
nextTick(() => { nextTick(() => {
selectRef.value?.blur() selectRef.value?.blur()
}) })
} }
} }
const onFocus = () => { const onFocus = () => {
state.focusStatus = true state.focusStatus = true
if (selectRef.value?.query != state.keyword) { if (selectRef.value?.query != state.keyword) {
state.keyword = '' state.keyword = ''
state.initializeData = false state.initializeData = false
// el-select 自动清理搜索词会产生意外的脱焦 // el-select 自动清理搜索词会产生意外的脱焦
state.accidentBlur = true state.accidentBlur = true
} }
if (!state.initializeData) { if (!state.initializeData) {
getData() getData()
} }
} }
const onBlur = () => { const onBlur = () => {
state.focusStatus = false state.focusStatus = false
} }
const onClear = () => { const onClear = () => {
state.keyword = '' state.keyword = ''
state.initializeData = false state.initializeData = false
} }
const onLogKeyword = (q: string) => { const onLogKeyword = (q: string) => {
if (state.keyword != q) { if (state.keyword != q) {
state.keyword = q state.keyword = q
getData() getData()
} }
} }
const getData = (initValue: valType = '') => { const getData = (initValue: valType = '') => {
state.loading = true state.loading = true
state.params.page = state.currentPage state.params.page = state.currentPage
state.params.initKey = props.pk state.params.initKey = props.pk
state.params.initValue = initValue state.params.initValue = initValue
getSelectData(props.remoteUrl, state.keyword, state.params) // getSelectData(props.remoteUrl, state.keyword, state.params)
.then((res) => { // .then((res) => {
let initializeData = true // let initializeData = true
let opts = res.data.options ? res.data.options : res.data.list // let opts = res.data.options ? res.data.options : res.data.list
if (typeof props.labelFormatter == 'function') { // if (typeof props.labelFormatter == 'function') {
for (const key in opts) { // for (const key in opts) {
opts[key][props.field] = props.labelFormatter(opts[key], key) // opts[key][props.field] = props.labelFormatter(opts[key], key)
} // }
} // }
state.options = opts // state.options = opts
state.total = res.data.total ?? 0 // state.total = res.data.total ?? 0
if (initValue) { // if (initValue) {
// 重新渲染组件,确保在赋值前,opts已加载到-兼容 modelValue 更新 // // 重新渲染组件,确保在赋值前,opts已加载到-兼容 modelValue 更新
state.selectKey = uuid() // state.selectKey = uuid()
initializeData = false // initializeData = false
} // }
state.loading = false // state.loading = false
state.initializeData = initializeData // state.initializeData = initializeData
if (state.accidentBlur) { // if (state.accidentBlur) {
nextTick(() => { // nextTick(() => {
const inputEl = selectRef.value?.$el.querySelector('.el-select__tags .el-select__input') // const inputEl = selectRef.value?.$el.querySelector('.el-select__tags .el-select__input')
inputEl && inputEl.focus() // inputEl && inputEl.focus()
state.accidentBlur = false // state.accidentBlur = false
}) // })
} // }
}) // })
.catch(() => { // .catch(() => {
state.loading = false // state.loading = false
}) // })
} }
const onSelectCurrentPageChange = (val: number) => { const onSelectCurrentPageChange = (val: number) => {
state.currentPage = val state.currentPage = val
getData() getData()
} }
const initDefaultValue = () => { const initDefaultValue = () => {
if (state.value) { if (state.value) {
// number[]转string[]确保默认值能够选中 // number[]转string[]确保默认值能够选中
if (typeof state.value === 'object') { if (typeof state.value === 'object') {
for (const key in state.value as string[]) { for (const key in state.value as string[]) {
state.value[key] = state.value[key].toString() state.value[key] = state.value[key].toString()
} }
} else if (typeof state.value === 'number') { } else if (typeof state.value === 'number') {
state.value = state.value.toString() state.value = state.value.toString()
} }
getData(state.value) getData(state.value)
} }
} }
onMounted(() => { onMounted(() => {
if (props.pk.indexOf('.') > 0) { if (props.pk.indexOf('.') > 0) {
let pk = props.pk.split('.') let pk = props.pk.split('.')
state.primaryKey = pk[1] ? pk[1] : pk[0] state.primaryKey = pk[1] ? pk[1] : pk[0]
} }
initDefaultValue() initDefaultValue()
setTimeout(() => { setTimeout(() => {
if (window?.IntersectionObserver) { if (window?.IntersectionObserver) {
io = new IntersectionObserver((entries) => { io = new IntersectionObserver((entries) => {
for (const key in entries) { for (const key in entries) {
if (!entries[key].isIntersecting) selectRef.value?.blur() if (!entries[key].isIntersecting) selectRef.value?.blur()
} }
}) })
if (selectRef.value?.$el instanceof Element) { if (selectRef.value?.$el instanceof Element) {
io.observe(selectRef.value.$el) io.observe(selectRef.value.$el)
} }
} }
}, 500) }, 500)
}) })
onUnmounted(() => { onUnmounted(() => {
io?.disconnect() io?.disconnect()
}) })
watch( watch(
() => props.modelValue, () => props.modelValue,
(newVal) => { (newVal) => {
if (String(state.value) != String(newVal)) { if (String(state.value) != String(newVal)) {
state.value = newVal ? newVal : '' state.value = newVal ? newVal : ''
initDefaultValue() initDefaultValue()
} }
} }
) )
const getSelectRef = () => { const getSelectRef = () => {
return selectRef.value return selectRef.value
} }
const focus = () => { const focus = () => {
selectRef.value?.focus() selectRef.value?.focus()
} }
const blur = () => { const blur = () => {
selectRef.value?.blur() selectRef.value?.blur()
} }
defineExpose({ defineExpose({
blur, blur,
focus, focus,
getSelectRef, getSelectRef,
}) })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
:deep(.remote-select-popper) { :deep(.remote-select-popper) {
text-align: center; text-align: center;
} }
.remote-select-option { .remote-select-option {
white-space: pre; white-space: pre;
} }
</style> </style>

View File

@@ -1,190 +1,190 @@
<template> <template>
<div v-if="view2"> <div v-if="view2">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<span style="font-size: 14px; line-height: 30px">值类型选择:</span> <span style="font-size: 14px; line-height: 30px">值类型选择:</span>
<el-select <el-select
style="min-width: 200px; width: 200px" style="min-width: 200px; width: 200px"
@change="changeView" @change="changeView"
v-model="value" v-model="value"
placeholder="请选择值类型" placeholder="请选择值类型"
> >
<el-option <el-option
v-for="item in options" v-for="item in options"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
></el-option> ></el-option>
</el-select> </el-select>
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary" <!-- <el-button v-if="view2 && senior" class="ml10" type="primary"
@click="AdvancedAnalytics">高级分析</el-button> --> @click="AdvancedAnalytics">高级分析</el-button> -->
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-button <el-button
@click="backbxlb" @click="backbxlb"
class="el-icon-refresh-right" class="el-icon-refresh-right"
icon="el-icon-CloseBold" icon="el-icon-Back"
style="float: right" style="float: right"
> >
返回 返回
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
<div v-loading="loading" style="height: calc(100vh - 190px)"> <div v-loading="loading" style="height: calc(100vh - 190px)">
<el-tabs v-if="view4" class="default-main" v-model="bxactiveName" @tab-click="bxhandleClick"> <el-tabs v-if="view4" class="default-main" v-model="bxactiveName" @tab-click="bxhandleClick">
<el-tab-pane <el-tab-pane
label="瞬时波形" label="瞬时波形"
name="ssbx" name="ssbx"
class="boxbx pt10 pb10" class="boxbx pt10 pb10"
:style="'height:' + bxecharts + ';overflow-y: scroll;'" :style="'height:' + bxecharts + ';overflow-y: scroll;'"
> >
<shushiboxi <shushiboxi
ref="shushiboxiRef" ref="shushiboxiRef"
v-if="bxactiveName == 'ssbx' && showBoxi" v-if="bxactiveName == 'ssbx' && showBoxi"
:value="value" :value="value"
:parentHeight="parentHeight" :parentHeight="parentHeight"
:boxoList="boxoList" :boxoList="boxoList"
:wp="wp" :wp="wp"
></shushiboxi> ></shushiboxi>
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane
label="RMS波形" label="RMS波形"
class="boxbx pt10 pb10" class="boxbx pt10 pb10"
name="rmsbx" name="rmsbx"
:style="'height:' + bxecharts + ';overflow-y: scroll;'" :style="'height:' + bxecharts + ';overflow-y: scroll;'"
> >
<rmsboxi <rmsboxi
ref="rmsboxiRef" ref="rmsboxiRef"
v-if="bxactiveName == 'rmsbx' && showBoxi" v-if="bxactiveName == 'rmsbx' && showBoxi"
:value="value" :value="value"
:parentHeight="parentHeight" :parentHeight="parentHeight"
:boxoList="boxoList" :boxoList="boxoList"
:wp="wp" :wp="wp"
></rmsboxi> ></rmsboxi>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" /> <el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" />
</div> </div>
</div> </div>
<div v-if="view3" class="pd10"> <div v-if="view3" class="pd10">
<span style="font-weight: 500; font-size: 22px">高级分析</span> <span style="font-weight: 500; font-size: 22px">高级分析</span>
<el-button icon="el-icon-Back" @click="gaoBack" style="float: right">返回</el-button> <el-button icon="el-icon-Back" @click="gaoBack" style="float: right">返回</el-button>
<analytics :flag="true" :GJList="GJList" :boxoList="boxoList"></analytics> <analytics :flag="true" :GJList="GJList" :boxoList="boxoList"></analytics>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import shushiboxi from '@/components/echarts/shushiboxi.vue' import shushiboxi from '@/components/echarts/shushiboxi.vue'
import rmsboxi from '@/components/echarts/rmsboxi.vue' import rmsboxi from '@/components/echarts/rmsboxi.vue'
import analytics from '@/components/echarts/analytics.vue' import analytics from '@/components/echarts/analytics.vue'
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import { analysis } from '@/api/advance-boot/analyse' import { analysis } from '@/api/advance-boot/analyse'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { getMonitorEventAnalyseWave, downloadWaveFile } from '@/api/event-boot/transient' import { getMonitorEventAnalyseWave, downloadWaveFile } from '@/api/event-boot/transient'
const emit = defineEmits(['backbxlb']) const emit = defineEmits(['backbxlb'])
interface Props { interface Props {
// boxoList: any // boxoList: any
// wp: any, // wp: any,
senior?: boolean senior?: boolean
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
senior: false senior: false
}) })
const parentHeight = ref(0) const parentHeight = ref(0)
const loading = ref(true) const loading = ref(true)
const bxactiveName = ref('ssbx') const bxactiveName = ref('ssbx')
const rmsboxiRef = ref() const rmsboxiRef = ref()
const value = ref(1) const value = ref(1)
const options = ref([ const options = ref([
{ {
value: 1, value: 1,
label: '一次值' label: '一次值'
}, },
{ {
value: 2, value: 2,
label: '二次值' label: '二次值'
} }
]) ])
const shushiboxiRef = ref() const shushiboxiRef = ref()
const bxecharts = ref(mainHeight(95).height as any) const bxecharts = ref(mainHeight(95).height as any)
const view2 = ref(true) const view2 = ref(true)
const boxoList = ref(null) const boxoList = ref(null)
const wp = ref(null) const wp = ref(null)
const showBoxi = ref(true) const showBoxi = ref(true)
const view3 = ref(false) const view3 = ref(false)
const view4 = ref(false) const view4 = ref(false)
const GJList = ref([]) const GJList = ref([])
const open = async (row: any) => { const open = async (row: any) => {
loading.value = true loading.value = true
await getMonitorEventAnalyseWave({ id: row.eventId, systemType: 0 }) await getMonitorEventAnalyseWave({ id: row.eventId, systemType: 0 })
.then(res => { .then(res => {
row.loading = false row.loading = false
if (res != undefined) { if (res != undefined) {
boxoList.value = row boxoList.value = row
wp.value = res.data wp.value = res.data
loading.value = false loading.value = false
view4.value = true view4.value = true
} }
}) })
.catch(() => { .catch(() => {
loading.value = false loading.value = false
}) })
} }
const bxhandleClick = (tab: any) => { const bxhandleClick = (tab: any) => {
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb() if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb() if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
loading.value = true loading.value = true
if (tab.name == 'ssbx') { if (tab.name == 'ssbx') {
bxactiveName.value = 'ssbx' bxactiveName.value = 'ssbx'
} else if (tab.name == 'rmsbx') { } else if (tab.name == 'rmsbx') {
bxactiveName.value = 'rmsbx' bxactiveName.value = 'rmsbx'
} }
setTimeout(() => { setTimeout(() => {
loading.value = false loading.value = false
}, 0) }, 0)
// console.log(tab, event); // console.log(tab, event);
} }
const backbxlb = () => { const backbxlb = () => {
boxoList.value = null boxoList.value = null
wp.value = null wp.value = null
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb() if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb() if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
emit('backbxlb') emit('backbxlb')
} }
const setHeight = (h: any, vh: any) => { const setHeight = (h: any, vh: any) => {
if (h != false) { if (h != false) {
parentHeight.value = h parentHeight.value = h
} }
setTimeout(() => { setTimeout(() => {
bxecharts.value = mainHeight(vh).height bxecharts.value = mainHeight(vh).height
}, 100) }, 100)
} }
// 高级分析 // 高级分析
const AdvancedAnalytics = () => { const AdvancedAnalytics = () => {
analysis({ analysis({
eventIndex: boxoList.value.eventId eventIndex: boxoList.value.eventId
}).then(res => { }).then(res => {
GJList.value = res.data GJList.value = res.data
view3.value = true view3.value = true
view2.value = false view2.value = false
}) })
} }
const changeView = () => { const changeView = () => {
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb() if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb() if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
showBoxi.value = false showBoxi.value = false
setTimeout(() => { setTimeout(() => {
showBoxi.value = true showBoxi.value = true
}, 0) }, 0)
} }
const gaoBack = () => { const gaoBack = () => {
view2.value = true view2.value = true
view3.value = false view3.value = false
} }
defineExpose({ open, setHeight }) defineExpose({ open, setHeight })
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@@ -1,43 +1,24 @@
<template> <template>
<div :style="{ height:props.height?props.height: tableStore.table.height }"> <div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
<vxe-table <vxe-table ref="tableRef" height="auto" :key="key" :data="tableStore.table.data"
ref="tableRef" v-loading="tableStore.table.loading" v-bind="Object.assign({}, defaultAttribute, $attrs)"
height="auto" @checkbox-all="selectChangeEvent" @checkbox-change="selectChangeEvent" :showOverflow="showOverflow"
:key="key" @sort-change="handleSortChange">
:data="tableStore.table.data"
v-loading="tableStore.table.loading"
v-bind="Object.assign({}, defaultAttribute, $attrs)"
@checkbox-all="selectChangeEvent"
@checkbox-change="selectChangeEvent"
:showOverflow="showOverflow"
@sort-change="handleSortChange"
>
<!-- Column 组件内部是 el-table-column --> <!-- Column 组件内部是 el-table-column -->
<template v-if="isGroup"> <template v-if="isGroup">
<GroupColumn :column="tableStore.table.column" /> <GroupColumn :column="tableStore.table.column" />
</template> </template>
<template v-else> <template v-else>
<Column <Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column"
:attr="item" :tree-node="item.treeNode">
:key="key + '-column'"
v-for="(item, key) in tableStore.table.column"
:tree-node="item.treeNode"
>
<!-- tableStore 预设的列 render 方案 --> <!-- tableStore 预设的列 render 方案 -->
<template v-if="item.render" #default="scope"> <template v-if="item.render" #default="scope">
<FieldRender <FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key +
:field="item" '-' +
:row="scope.row" item.render +
:column="scope.column" '-' +
:index="scope.rowIndex" (item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
:key=" " />
key +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
"
/>
</template> </template>
</Column> </Column>
</template> </template>
@@ -46,16 +27,11 @@
</div> </div>
<div v-if="tableStore.showPage" class="table-pagination"> <div v-if="tableStore.showPage" class="table-pagination">
<el-pagination <el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize"
:currentPage="tableStore.table.params!.pageNum" :page-sizes="pageSizes" background
:page-size="tableStore.table.params!.pageSize"
:page-sizes="pageSizes"
background
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'" :layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
:total="tableStore.table.total" :total="tableStore.table.total" @size-change="onTableSizeChange"
@size-change="onTableSizeChange" @current-change="onTableCurrentChange"></el-pagination>
@current-change="onTableCurrentChange"
></el-pagination>
</div> </div>
<slot name="footer"></slot> <slot name="footer"></slot>
</template> </template>
@@ -80,13 +56,13 @@ const key = ref(0)
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> { interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
isGroup?: boolean isGroup?: boolean
showOverflow?: boolean showOverflow?: boolean
height?: string | boolean height?: string | number
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
isGroup: false, isGroup: false,
showOverflow: true, showOverflow: true,
height: false height: undefined
}) })
onMounted(() => { onMounted(() => {
tableStore.table.ref = tableRef.value as VxeTableInstance tableStore.table.ref = tableRef.value as VxeTableInstance

View File

@@ -1,197 +1,197 @@
<template> <template>
<Tree ref="treRef" :data="tree" style="height: 100%" :width="'100%'" :expanded="expanded" /> <Tree ref="treRef" :data="tree" style="height: 100%" :width="'100%'" :expanded="expanded" />
</template> </template>
<!-- <div class="mb10"> <!-- <div class="mb10">
<el-button type="primary" icon="el-icon-Download" size="small" @click="exportExcelTemplate" :loading="loading">模版下载</el-button> <el-button type="primary" icon="el-icon-Download" size="small" @click="exportExcelTemplate" :loading="loading">模版下载</el-button>
<el-button type="primary" icon="el-icon-Upload" size="small">导入</el-button> <el-button type="primary" icon="el-icon-Upload" size="small">导入</el-button>
<el-button type="primary" icon="el-icon-Download" size="small" @click="ledgerEverywhere" :loading="loading1">导出</el-button> <el-button type="primary" icon="el-icon-Download" size="small" @click="ledgerEverywhere" :loading="loading1">导出</el-button>
</div> --> </div> -->
<script lang="ts" setup> <script lang="ts" setup>
import { ref, nextTick } from 'vue' import { ref, nextTick } from 'vue'
import Tree from './index.vue' import Tree from './index.vue'
import { getTerminalTree,downTerminalTemplate,exportTerminalBase } from '@/api/device-boot/Business' import { getTerminalTree,downTerminalTemplate,exportTerminalBase } from '@/api/device-boot/Business'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei' const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
defineOptions({ defineOptions({
name: 'govern/deviceTree' name: 'govern/deviceTree'
}) })
const loading = ref(false) const loading = ref(false)
const loading1 = ref(false) const loading1 = ref(false)
const emit = defineEmits(['init']) const emit = defineEmits(['init'])
const config = useConfig() const config = useConfig()
const expanded: any = ref([]) const expanded: any = ref([])
const tree = ref() const tree = ref()
const treRef = ref() const treRef = ref()
const info = (id: any) => { const info = (id: any) => {
expanded.value = [id] expanded.value = [id]
getTerminalTree().then(res => { getTerminalTree().then(res => {
// let arr: any[] = [] // let arr: any[] = []
if (VITE_FLAG) { if (VITE_FLAG) {
res.data.forEach((item: any) => { res.data.forEach((item: any) => {
item.icon = 'el-icon-Menu' item.icon = 'el-icon-Menu'
item.plevel = item.level item.plevel = item.level
item.level = 0 item.level = 0
item.children.forEach((item2: any) => { item.children.forEach((item2: any) => {
item2.icon = 'el-icon-HomeFilled' item2.icon = 'el-icon-HomeFilled'
item2.plevel = item2.level item2.plevel = item2.level
item2.level = 100 item2.level = 100
expanded.value.push(item2.id) expanded.value.push(item2.id)
item2.children.forEach((item3: any) => { item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-CollectionTag' item3.icon = 'el-icon-CollectionTag'
item3.plevel = item3.level item3.plevel = item3.level
item3.level = 200 item3.level = 200
item3.children.forEach((item4: any) => { item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Flag' item4.icon = 'el-icon-Flag'
item4.plevel = item4.level item4.plevel = item4.level
item4.level = 300 item4.level = 300
// arr.push(item4) // arr.push(item4)
item4.children.forEach((item5: any) => { item4.children.forEach((item5: any) => {
item5.icon = 'el-icon-OfficeBuilding' item5.icon = 'el-icon-OfficeBuilding'
item5.plevel = item5.level item5.plevel = item5.level
item5.level = 300 item5.level = 300
// item5.id = item4.id // item5.id = item4.id
item5.children.forEach((item6: any) => { item5.children.forEach((item6: any) => {
item6.icon = 'el-icon-HelpFilled' item6.icon = 'el-icon-HelpFilled'
item6.plevel = 4 item6.plevel = 4
if (item6.name == '电网侧' && item6.children.length == 0) { if (item6.name == '电网侧' && item6.children.length == 0) {
item6.level = 400 item6.level = 400
} else { } else {
item6.level = 400 item6.level = 400
} }
item6.children.forEach((item7: any) => { item6.children.forEach((item7: any) => {
item7.icon = 'el-icon-Film' item7.icon = 'el-icon-Film'
item7.plevel = item7.level item7.plevel = item7.level
item7.level = 400 item7.level = 400
item7.children.forEach((item8: any) => { item7.children.forEach((item8: any) => {
item8.icon = 'el-icon-Collection' item8.icon = 'el-icon-Collection'
item8.plevel = item8.level item8.plevel = item8.level
item8.level = 500 item8.level = 500
item8.children.forEach((item9: any) => { item8.children.forEach((item9: any) => {
item9.icon = 'el-icon-Share' item9.icon = 'el-icon-Share'
item9.plevel = item9.level item9.plevel = item9.level
item9.level = 600 item9.level = 600
item9.children.forEach((item10: any) => { item9.children.forEach((item10: any) => {
item10.icon = 'el-icon-Location' item10.icon = 'el-icon-Location'
item10.plevel = item10.level item10.plevel = item10.level
item10.level = 700 item10.level = 700
}) })
}) })
}) })
}) })
}) })
}) })
}) })
}) })
}) })
}) })
} else { } else {
res.data.forEach((item: any) => { res.data.forEach((item: any) => {
item.icon = 'el-icon-Menu' item.icon = 'el-icon-Menu'
item.plevel = item.level item.plevel = item.level
item.level = (item.level + 1) * 100 item.level = (item.level + 1) * 100
item.children.forEach((item2: any) => { item.children.forEach((item2: any) => {
item2.icon = 'el-icon-HomeFilled' item2.icon = 'el-icon-HomeFilled'
item2.plevel = item2.level item2.plevel = item2.level
item2.level = (item2.level + 1) * 100 item2.level = (item2.level + 1) * 100
expanded.value.push(item2.id) expanded.value.push(item2.id)
item2.children.forEach((item3: any) => { item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-CollectionTag' item3.icon = 'el-icon-CollectionTag'
item3.plevel = item3.level item3.plevel = item3.level
item3.level = (item3.level + 1) * 100 item3.level = (item3.level + 1) * 100
item3.children.forEach((item4: any) => { item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Flag' item4.icon = 'el-icon-Flag'
item4.plevel = item4.level item4.plevel = item4.level
item4.level = (item4.level + 1) * 100 item4.level = (item4.level + 1) * 100
item4.children.forEach((item5: any) => { item4.children.forEach((item5: any) => {
item5.icon = 'el-icon-OfficeBuilding' item5.icon = 'el-icon-OfficeBuilding'
item5.plevel = item5.level item5.plevel = item5.level
item5.level = (item5.level == 7 ? 4 : item5.level + 1) * 100 item5.level = (item5.level == 7 ? 4 : item5.level + 1) * 100
item5.children.forEach((item6: any) => { item5.children.forEach((item6: any) => {
item6.icon = 'el-icon-Film' item6.icon = 'el-icon-Film'
item6.plevel = item6.level item6.plevel = item6.level
item6.level = (item6.level + 1) * 100 item6.level = (item6.level + 1) * 100
item6.children.forEach((item7: any) => { item6.children.forEach((item7: any) => {
item7.icon = 'el-icon-Share' item7.icon = 'el-icon-Share'
item7.plevel = item7.level item7.plevel = item7.level
item7.level = (item7.level + 1) * 100 item7.level = (item7.level + 1) * 100
item7.children.forEach((item8: any) => { item7.children.forEach((item8: any) => {
item8.icon = 'el-icon-Location' item8.icon = 'el-icon-Location'
item8.plevel = item8.level item8.plevel = item8.level
item8.level = (item8.level + 1) * 100 item8.level = (item8.level + 1) * 100
}) })
}) })
}) })
}) })
}) })
}) })
}) })
}) })
} }
tree.value = res.data tree.value = res.data
nextTick(() => { nextTick(() => {
treRef.value.setCurrentKey(id) treRef.value.setCurrentKey(id)
// if (arr.length) { // if (arr.length) {
// treRef.value.treeRef.setCurrentKey(arr[0].id) // treRef.value.treeRef.setCurrentKey(arr[0].id)
// // 注册父组件事件 // // 注册父组件事件
// emit('init', { // emit('init', {
// level: 2, // level: 2,
// ...arr[0] // ...arr[0]
// }) // })
// } else { // } else {
// emit('init') // emit('init')
// } // }
}) })
}) })
} }
// 下载模版 // 下载模版
const exportExcelTemplate = async() => { const exportExcelTemplate = async() => {
loading.value = true loading.value = true
downTerminalTemplate().then((res: any) => { downTerminalTemplate().then((res: any) => {
let blob = new Blob([res], { let blob = new Blob([res], {
type: 'application/vnd.ms-excel' type: 'application/vnd.ms-excel'
}) })
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') const link = document.createElement('a')
link.href = url link.href = url
link.download = '终端台账模版' link.download = '终端台账模版'
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
link.remove() link.remove()
}) })
await setTimeout(() => { await setTimeout(() => {
loading.value = false loading.value = false
}, 0) }, 0)
} }
// 导出台账 // 导出台账
const ledgerEverywhere = async() => { const ledgerEverywhere = async() => {
loading1.value = true loading1.value = true
exportTerminalBase().then((res: any) => { exportTerminalBase().then((res: any) => {
let blob = new Blob([res], { let blob = new Blob([res], {
type: 'application/vnd.ms-excel' type: 'application/vnd.ms-excel'
}) })
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') const link = document.createElement('a')
link.href = url link.href = url
link.download = '终端台账' link.download = '终端台账'
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
link.remove() link.remove()
}) })
await setTimeout(() => { await setTimeout(() => {
loading1.value = false loading1.value = false
}, 0) }, 0)
} }
info('') info('')
defineExpose({ info }) defineExpose({ info })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.el-tree { .el-tree {
background: #efeff0; background: #efeff0;
} }
</style> </style>

View File

@@ -1,33 +1,33 @@
<template> <template>
<el-container class="layout-container"> <el-container class="layout-container">
<Aside /> <Aside />
<el-container class="content-wrapper"> <el-container class="content-wrapper">
<Header /> <Header />
<Nav /> <Nav />
<Main /> <Main />
</el-container> </el-container>
</el-container> </el-container>
<CloseFullScreen v-if="navTabs.state.tabFullScreen" /> <CloseFullScreen v-if="navTabs.state.tabFullScreen" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Aside from '@/layouts/admin/components/aside.vue' import Aside from '@/layouts/admin/components/aside.vue'
import Header from '@/layouts/admin/components/header.vue' import Header from '@/layouts/admin/components/header.vue'
import Main from '@/layouts/admin/router-view/main.vue' import Main from '@/layouts/admin/router-view/main.vue'
import CloseFullScreen from '@/layouts/admin/components/closeFullScreen.vue' import CloseFullScreen from '@/layouts/admin/components/closeFullScreen.vue'
import { useNavTabs } from '@/stores/navTabs' import { useNavTabs } from '@/stores/navTabs'
import Nav from '@/layouts/admin/components/nav.vue' import Nav from '@/layouts/admin/components/nav.vue'
const navTabs = useNavTabs() const navTabs = useNavTabs()
</script> </script>
<style scoped> <style scoped>
.layout-container { .layout-container {
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
.content-wrapper { .content-wrapper {
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
</style> </style>

View File

@@ -1,71 +1,70 @@
import { useCache, CACHE_KEY } from '@/hooks/web/useCache' import { useCache, CACHE_KEY } from '@/hooks/web/useCache'
import { TokenType } from '@/api/login/types' import { decrypt, encrypt } from '@/utils/jsencrypt'
import { decrypt, encrypt } from '@/utils/jsencrypt'
const { wsCache } = useCache()
const { wsCache } = useCache()
const AccessTokenKey = 'ACCESS_TOKEN'
const AccessTokenKey = 'ACCESS_TOKEN' const RefreshTokenKey = 'REFRESH_TOKEN'
const RefreshTokenKey = 'REFRESH_TOKEN'
// 获取token
// 获取token export const getAccessToken = () => {
export const getAccessToken = () => { // 此处与TokenKey相同此写法解决初始化时Cookies中不存在TokenKey报错
// 此处与TokenKey相同此写法解决初始化时Cookies中不存在TokenKey报错 return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN')
return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN') }
}
// 刷新token
// 刷新token export const getRefreshToken = () => {
export const getRefreshToken = () => { return wsCache.get(RefreshTokenKey)
return wsCache.get(RefreshTokenKey) }
}
// 设置token
// 设置token export const setToken = (token: any) => {
export const setToken = (token: TokenType) => { wsCache.set(RefreshTokenKey, token.refreshToken)
wsCache.set(RefreshTokenKey, token.refreshToken) wsCache.set(AccessTokenKey, token.accessToken)
wsCache.set(AccessTokenKey, token.accessToken) }
}
// 删除token
// 删除token export const removeToken = () => {
export const removeToken = () => { wsCache.delete(AccessTokenKey)
wsCache.delete(AccessTokenKey) wsCache.delete(RefreshTokenKey)
wsCache.delete(RefreshTokenKey) }
}
/** 格式化tokenjwt格式 */
/** 格式化tokenjwt格式 */ export const formatToken = (token: string): string => {
export const formatToken = (token: string): string => { return 'Bearer ' + token
return 'Bearer ' + token }
} // ========== 账号相关 ==========
// ========== 账号相关 ==========
export type LoginFormType = {
export type LoginFormType = { tenantName: string
tenantName: string username: string
username: string password: string
password: string rememberMe: boolean
rememberMe: boolean }
}
export const getLoginForm = () => {
export const getLoginForm = () => { const loginForm: LoginFormType = wsCache.get(CACHE_KEY.LoginForm)
const loginForm: LoginFormType = wsCache.get(CACHE_KEY.LoginForm) if (loginForm) {
if (loginForm) { loginForm.password = decrypt(loginForm.password) as string
loginForm.password = decrypt(loginForm.password) as string }
} return loginForm
return loginForm }
}
export const setLoginForm = (loginForm: LoginFormType) => {
export const setLoginForm = (loginForm: LoginFormType) => { loginForm.password = encrypt(loginForm.password) as string
loginForm.password = encrypt(loginForm.password) as string wsCache.set(CACHE_KEY.LoginForm, loginForm, { exp: 30 * 24 * 60 * 60 })
wsCache.set(CACHE_KEY.LoginForm, loginForm, { exp: 30 * 24 * 60 * 60 }) }
}
export const removeLoginForm = () => {
export const removeLoginForm = () => { wsCache.delete(CACHE_KEY.LoginForm)
wsCache.delete(CACHE_KEY.LoginForm) }
}
// ========== 租户相关 ==========
// ========== 租户相关 ==========
export const getTenantId = () => {
export const getTenantId = () => { return wsCache.get(CACHE_KEY.TenantId)
return wsCache.get(CACHE_KEY.TenantId) }
}
export const setTenantId = (username: string) => {
export const setTenantId = (username: string) => { wsCache.set(CACHE_KEY.TenantId, username)
wsCache.set(CACHE_KEY.TenantId, username) }
}

View File

@@ -1,159 +1,302 @@
const dataProcessing = (arr: any[]) => { const dataProcessing = (arr: any[]) => {
return arr return arr
.filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item)))) .filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item))))
.map(item => (typeof item === 'number' ? item : parseFloat(item))) .map(item => (typeof item === 'number' ? item : parseFloat(item)))
} }
const calculateValue = (o: number, value: number, num: number, isMin: boolean) => { const calculateValue = (o: number, value: number, num: number, isMin: boolean) => {
if (value === 0) { if (value === 0) {
return 0 return 0
} else if (value > 0 && Math.abs(value) < 1 && isMin == true) { } else if (value > 0 && Math.abs(value) < 1 && isMin == true) {
return 0 return 0
} else if (value > -1 && value < 0 && isMin == false) { } else if (value > -1 && value < 0 && isMin == false) {
return 0 return 0
} }
let base let base
if (Math.abs(o) >= 100) { if (Math.abs(o) >= 100) {
base = 100 base = 100
} else if (Math.abs(o) >= 10) { } else if (Math.abs(o) >= 10) {
base = 10 base = 10
} else if (Math.abs(o) >= 1) { } else if (Math.abs(o) >= 1) {
base = 1 base = 1
} else { } else {
base = 0.1 base = 0.1
} }
let calculatedValue let calculatedValue
if (isMin) { if (isMin) {
if (value < 0) { if (value < 0) {
calculatedValue = value + num * value calculatedValue = value + num * value
} else { } else {
calculatedValue = value - num * value calculatedValue = value - num * value
} }
} else { } else {
if (value < 0) { if (value < 0) {
calculatedValue = value - num * value calculatedValue = value - num * value
} else { } else {
calculatedValue = value + num * value calculatedValue = value + num * value
} }
} }
if (base === 0.1) { if (base === 0.1) {
return parseFloat(calculatedValue.toFixed(1)) return parseFloat(calculatedValue.toFixed(1))
} else if (isMin) { } else if (isMin) {
return Math.floor(calculatedValue / base) * base return Math.floor(calculatedValue / base) * base
} else { } else {
return Math.ceil(calculatedValue / base) * base return Math.ceil(calculatedValue / base) * base
} }
} }
// 处理y轴最大最小值 // 处理y轴最大最小值
export const yMethod = (arr: any) => { export const yMethod = (arr: any) => {
let num = 0.1 let num = 0.1
let numList = dataProcessing(arr) let numList = dataProcessing(arr)
let maxValue = 0 let maxValue = 0
let minValue = 0 let minValue = 0
let max = 0 let max = 0
let min = 0 let min = 0
maxValue = Math.max(...numList) maxValue = Math.max(...numList)
minValue = Math.min(...numList) minValue = Math.min(...numList)
const o = maxValue - minValue const o = maxValue - minValue
if (Math.abs(o) >= 300) { if (Math.abs(o) >= 300) {
num = 0.02 num = 0.02
} }
min = calculateValue(o, minValue, num, true) min = calculateValue(o, minValue, num, true)
max = calculateValue(o, maxValue, num, false) max = calculateValue(o, maxValue, num, false)
// if (-100 >= minValue) { // if (-100 >= minValue) {
// min = Math.floor((minValue + num * minValue) / 100) * 100 // min = Math.floor((minValue + num * minValue) / 100) * 100
// } else if (-10 >= minValue && minValue > -100) { // } else if (-10 >= minValue && minValue > -100) {
// min = Math.floor((minValue + num * minValue) / 10) * 10 // min = Math.floor((minValue + num * minValue) / 10) * 10
// } else if (-1 >= minValue && minValue > -10) { // } else if (-1 >= minValue && minValue > -10) {
// min = Math.floor(minValue + num * minValue) // min = Math.floor(minValue + num * minValue)
// } else if (0 > minValue && minValue > -1) { // } else if (0 > minValue && minValue > -1) {
// min = parseFloat((minValue + num * minValue).toFixed(1)) // min = parseFloat((minValue + num * minValue).toFixed(1))
// } else if (minValue == 0) { // } else if (minValue == 0) {
// min = 0 // min = 0
// } else if (0 < minValue && minValue < 1) { // } else if (0 < minValue && minValue < 1) {
// min = parseFloat((minValue - num * minValue).toFixed(1)) // min = parseFloat((minValue - num * minValue).toFixed(1))
// } else if (1 <= minValue && minValue < 10) { // } else if (1 <= minValue && minValue < 10) {
// min = Math.floor(minValue - num * minValue) // min = Math.floor(minValue - num * minValue)
// } else if (10 <= minValue && minValue < 100) { // } else if (10 <= minValue && minValue < 100) {
// min = Math.floor((minValue - num * minValue) / 10) * 10 // min = Math.floor((minValue - num * minValue) / 10) * 10
// } else if (100 <= minValue) { // } else if (100 <= minValue) {
// min = Math.floor((minValue - num * minValue) / 100) * 100 // min = Math.floor((minValue - num * minValue) / 100) * 100
// } // }
// if (-100 >= maxValue) { // if (-100 >= maxValue) {
// max = Math.ceil((maxValue - num * maxValue) / 100) * 100 // max = Math.ceil((maxValue - num * maxValue) / 100) * 100
// } else if (-10 >= maxValue && maxValue > -100) { // } else if (-10 >= maxValue && maxValue > -100) {
// max = Math.ceil((maxValue - num * maxValue) / 10) * 10 // max = Math.ceil((maxValue - num * maxValue) / 10) * 10
// } else if (-1 >= maxValue && maxValue > -10) { // } else if (-1 >= maxValue && maxValue > -10) {
// max = Math.ceil(maxValue - num * maxValue) // max = Math.ceil(maxValue - num * maxValue)
// } else if (0 > maxValue && maxValue > -1) { // } else if (0 > maxValue && maxValue > -1) {
// max = parseFloat((maxValue - num * maxValue).toFixed(1)) // max = parseFloat((maxValue - num * maxValue).toFixed(1))
// } else if (maxValue == 0) { // } else if (maxValue == 0) {
// max = 0 // max = 0
// } else if (0 < maxValue && maxValue < 1) { // } else if (0 < maxValue && maxValue < 1) {
// max = parseFloat((maxValue + num * maxValue).toFixed(1)) // max = parseFloat((maxValue + num * maxValue).toFixed(1))
// } else if (1 <= maxValue && maxValue < 10) { // } else if (1 <= maxValue && maxValue < 10) {
// max = Math.ceil(maxValue + num * maxValue) // max = Math.ceil(maxValue + num * maxValue)
// } else if (10 <= maxValue && maxValue < 100) { // } else if (10 <= maxValue && maxValue < 100) {
// max = Math.ceil((maxValue + num * maxValue) / 10) * 10 // max = Math.ceil((maxValue + num * maxValue) / 10) * 10
// } else if (100 <= maxValue) { // } else if (100 <= maxValue) {
// max = Math.ceil((maxValue + num * maxValue) / 100) * 100 // max = Math.ceil((maxValue + num * maxValue) / 100) * 100
// } // }
// if (maxValue > 1000 || minValue < -1000) { // if (maxValue > 1000 || minValue < -1000) {
// max = Math.ceil(maxValue / 100) * 100 // max = Math.ceil(maxValue / 100) * 100
// if (minValue == 0) { // if (minValue == 0) {
// min = 0 // min = 0
// } else { // } else {
// min = Math.floor(minValue / 100) * 100 // min = Math.floor(minValue / 100) * 100
// } // }
// } else if (maxValue < 60 && minValue > 40) { // } else if (maxValue < 60 && minValue > 40) {
// max = 60 // max = 60
// min = 40 // min = 40
// } else if (maxValue == minValue && maxValue < 10 && minValue > 0) { // } else if (maxValue == minValue && maxValue < 10 && minValue > 0) {
// max = Math.ceil(maxValue / 10) * 10 // max = Math.ceil(maxValue / 10) * 10
// min = Math.floor(minValue / 10) * 10 // min = Math.floor(minValue / 10) * 10
// } else if (maxValue == minValue && maxValue != 0 && minValue != 0) { // } else if (maxValue == minValue && maxValue != 0 && minValue != 0) {
// max = Math.ceil(maxValue / 10 + 1) * 10 // max = Math.ceil(maxValue / 10 + 1) * 10
// min = Math.floor(minValue / 10 - 1) * 10 // min = Math.floor(minValue / 10 - 1) * 10
// } else { // } else {
// max = Math.ceil(maxValue / 10) * 10 // max = Math.ceil(maxValue / 10) * 10
// min = Math.floor(minValue / 10) * 10 // min = Math.floor(minValue / 10) * 10
// } // }
// if (maxValue > 0 && maxValue < 1) { // if (maxValue > 0 && maxValue < 1) {
// max = 1 // max = 1
// } else if (max == 0 && minValue > -1 && minValue < 0) { // } else if (max == 0 && minValue > -1 && minValue < 0) {
// min = -1 // min = -1
// } // }
return [min, max] return [min, max]
} }
/** /**
* title['A相','B相',] * title['A相','B相',]
* data[[1,2],[3,4]] * data[[1,2],[3,4]]
*/ */
// 导出csv文件 // 导出csv文件
const convertToCSV = (title: object, data: any) => { const convertToCSV = (title: object, data: any) => {
console.log('🚀 ~ convertToCSV ~ data:', data) console.log('🚀 ~ convertToCSV ~ data:', data)
let csv = '' let csv = ''
// 添加列头 // 添加列头
csv += ',' + title.join(',') + '\n' csv += ',' + title.join(',') + '\n'
// 遍历数据并添加到CSV字符串中 // 遍历数据并添加到CSV字符串中
data?.map(item => { data?.map(item => {
csv += item.join(',') + '\n' csv += item.join(',') + '\n'
}) })
return csv return csv
} }
export const exportCSV = (title: object, data: any, filename: string) => { export const exportCSV = (title: object, data: any, filename: string) => {
const csv = convertToCSV(title, data) const csv = convertToCSV(title, data)
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a') const link = document.createElement('a')
link.href = URL.createObjectURL(blob) link.href = URL.createObjectURL(blob)
link.download = filename link.download = filename
link.click() link.click()
// 释放URL对象 // 释放URL对象
URL.revokeObjectURL(link.href) URL.revokeObjectURL(link.href)
} }
/**
* 补全时间序列数据中缺失的条目
* @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...]
* @returns 补全后的数据,缺失条目数值为 null
*/
export const completeTimeSeries = (rawData: string[][]): (string | null)[][] => {
// 步骤1校验原始数据并解析时间
if (rawData.length < 2) {
console.warn('数据量不足2条无法计算时间间隔直接返回原始数据')
return rawData.map(item => [...item])
}
// 解析所有时间为Date对象过滤无效时间并按时间排序
const validData = rawData
.map(item => {
// 确保至少有时间和数值字段
if (!item[0]) {
return { time: new Date(0), item, isValid: false }
}
const time = new Date(item[0])
return { time, item, isValid: !isNaN(time.getTime()) }
})
.filter(data => data.isValid)
.sort((a, b) => a.time.getTime() - b.time.getTime()) // 确保数据按时间排序
.map(data => data.item)
if (validData.length < 2) {
throw new Error('有效时间数据不足2条无法继续处理')
}
// 步骤2计算时间间隔分析前几条数据确定最可能的间隔
const intervals: number[] = []
// 分析前10条数据来确定间隔避免单一间隔出错
const analyzeCount = Math.min(10, validData.length - 1)
for (let i = 0; i < analyzeCount; i++) {
const currentTime = new Date(validData[i][0]!).getTime()
const nextTime = new Date(validData[i + 1][0]!).getTime()
const interval = nextTime - currentTime
if (interval > 0) {
intervals.push(interval)
}
}
// 取最常见的间隔作为标准间隔
const timeInterval = getMostFrequentValue(intervals)
if (timeInterval <= 0) {
throw new Error('无法确定有效的时间间隔')
}
// 步骤3生成完整的时间序列范围从第一条到最后一条
const startTime = new Date(validData[0][0]!).getTime()
const endTime = new Date(validData[validData.length - 1][0]!).getTime()
const completeTimes: Date[] = []
// 生成从 startTime 到 endTime 的所有间隔时间点
for (let time = startTime; time <= endTime; time += timeInterval) {
completeTimes.push(new Date(time))
}
// 步骤4将原始数据转为时间映射表使用精确的时间字符串匹配
const timeDataMap = new Map<string, (string | undefined)[]>()
validData.forEach(item => {
// 使用原始时间字符串作为键,避免格式转换导致的匹配问题
if (item[0]) {
timeDataMap.set(item[0], item)
}
})
// 提取模板数据(从第一条有效数据中提取单位和类型,处理可能的缺失)
const template = validData[0]
// 步骤5对比补全数据缺失条目数值为 null
const completedData = completeTimes.map(time => {
// 保持与原始数据相同的时间格式
const timeStr = formatTime(time)
const existingItem = timeDataMap.get(timeStr)
if (existingItem) {
// 存在该时间,返回原始数据
return [...existingItem]
} else {
// 缺失该时间,数值设为 null其他字段沿用第一个有效数据的格式
// 处理可能缺失的单位和类型字段
const result: (string | null | undefined)[] = [timeStr, '/']
// 仅在原始数据有单位字段时才添加
if (template.length > 2) {
result.push(template[2])
}
// 仅在原始数据有类型字段时才添加
if (template.length > 3) {
result.push(template[3])
}
return result
}
})
return completedData
}
/**
* 格式化时间为 "YYYY-MM-DD HH:mm:ss" 格式
* @param date 日期对象
* @returns 格式化后的时间字符串
*/
function formatTime(date: Date): string {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
/**
* 获取数组中出现频率最高的值
* @param arr 数字数组
* @returns 出现频率最高的值
*/
function getMostFrequentValue(arr: number[]): number {
if (arr.length === 0) return 0
const frequencyMap = new Map<number, number>()
arr.forEach(num => {
frequencyMap.set(num, (frequencyMap.get(num) || 0) + 1)
})
let maxFrequency = 0
let mostFrequent = arr[0]
frequencyMap.forEach((frequency, num) => {
if (frequency > maxFrequency) {
maxFrequency = frequency
mostFrequent = num
}
})
return mostFrequent
}

View File

@@ -1,295 +1,295 @@
import router from '@/router/index' import router from '@/router/index'
import { isNavigationFailure, NavigationFailureType } from 'vue-router' import { isNavigationFailure, NavigationFailureType } from 'vue-router'
import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router' import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router'
import { ElNotification } from 'element-plus' import { ElNotification } from 'element-plus'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import { useNavTabs } from '@/stores/navTabs' import { useNavTabs } from '@/stores/navTabs'
import { closeShade } from '@/utils/pageShade' import { closeShade } from '@/utils/pageShade'
import { adminBaseRoute } from '@/router/static' import { adminBaseRoute } from '@/router/static'
import { compact, isEmpty, reverse } from 'lodash-es' import { compact, isEmpty, reverse } from 'lodash-es'
import { isAdminApp } from '@/utils/common' import { isAdminApp } from '@/utils/common'
/** /**
* 导航失败有错误消息的路由push * 导航失败有错误消息的路由push
* @param to — 导航位置,同 router.push * @param to — 导航位置,同 router.push
*/ */
export const routePush = async (to: RouteLocationRaw) => { export const routePush = async (to: RouteLocationRaw) => {
try { try {
const failure = await router.push(to) const failure = await router.push(to)
if (isNavigationFailure(failure, NavigationFailureType.aborted)) { if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
ElNotification({ ElNotification({
message: 'utils.Navigation failed, navigation guard intercepted!', message: 'utils.Navigation failed, navigation guard intercepted!',
type: 'error' type: 'error'
}) })
} else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) { } else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {
// ElNotification({ // ElNotification({
// message: '已在目标页', // message: '已在目标页',
// type: 'warning' // type: 'warning'
// }) // })
} }
} catch (error) { } catch (error) {
ElNotification({ ElNotification({
message: '导航失败,路由无效', message: '导航失败,路由无效',
type: 'error' type: 'error'
}) })
console.error(error) console.error(error)
} }
} }
/** /**
* 获取第一个菜单 * 获取第一个菜单
*/ */
export const getFirstRoute = (routes: RouteRecordRaw[], menuType = 'tab'): false | RouteRecordRaw => { export const getFirstRoute = (routes: RouteRecordRaw[], menuType = 'tab'): false | RouteRecordRaw => {
const routerPaths: string[] = [] const routerPaths: string[] = []
const routers = router.getRoutes() const routers = router.getRoutes()
routers.forEach(item => { routers.forEach(item => {
if (item.path) routerPaths.push(item.path) if (item.path) routerPaths.push(item.path)
}) })
let find: boolean | RouteRecordRaw = false let find: boolean | RouteRecordRaw = false
for (const key in routes) { for (const key in routes) {
if ( if (
routes[key].meta?.type == 'menu' && routes[key].meta?.type == 'menu' &&
routes[key].meta?.menu_type == menuType && routes[key].meta?.menu_type == menuType &&
routerPaths.indexOf(routes[key].path) !== -1 routerPaths.indexOf(routes[key].path) !== -1
) { ) {
return routes[key] return routes[key]
} else if (routes[key].children && routes[key].children?.length) { } else if (routes[key].children && routes[key].children?.length) {
find = getFirstRoute(routes[key].children!) find = getFirstRoute(routes[key].children!)
if (find) return find if (find) return find
} }
} }
return find return find
} }
/** /**
* 打开侧边菜单 * 打开侧边菜单
* @param menu 菜单数据 * @param menu 菜单数据
*/ */
export const onClickMenu = (menu: RouteRecordRaw) => { export const onClickMenu = (menu: RouteRecordRaw) => {
switch (menu.meta?.menu_type) { switch (menu.meta?.menu_type) {
case 'iframe': case 'iframe':
case 'tab': case 'tab':
routePush({ path: menu.path }) routePush({ path: menu.path })
break break
case 'link': case 'link':
window.open(menu.path, '_blank') window.open(menu.path, '_blank')
break break
default: default:
ElNotification({ ElNotification({
message: 'utils.Navigation failed, the menu type is unrecognized!', message: 'utils.Navigation failed, the menu type is unrecognized!',
type: 'error' type: 'error'
}) })
break break
} }
const config = useConfig() const config = useConfig()
if (config.layout.shrink) { if (config.layout.shrink) {
closeShade(() => { closeShade(() => {
config.setLayout('menuCollapse', true) config.setLayout('menuCollapse', true)
}) })
} }
} }
/** /**
* 处理后台的路由 * 处理后台的路由
*/ */
export const handleAdminRoute = (routes: any) => { export const handleAdminRoute = (routes: any) => {
const viewsComponent = import.meta.glob('/src/views/**/*.vue') const viewsComponent = import.meta.glob('/src/views/**/*.vue')
addRouteAll(viewsComponent, routes, adminBaseRoute.name as string) addRouteAll(viewsComponent, routes, adminBaseRoute.name as string)
const menuAdminBaseRoute = (adminBaseRoute.path as string) + '/' const menuAdminBaseRoute = (adminBaseRoute.path as string) + '/'
// 更新stores中的路由菜单数据 // 更新stores中的路由菜单数据
const navTabs = useNavTabs() const navTabs = useNavTabs()
navTabs.setTabsViewRoutes(handleMenuRule(routes, menuAdminBaseRoute)) navTabs.setTabsViewRoutes(handleMenuRule(routes, menuAdminBaseRoute))
navTabs.fillAuthNode(handleAuthNode(routes, menuAdminBaseRoute)) navTabs.fillAuthNode(handleAuthNode(routes, menuAdminBaseRoute))
} }
/** /**
* 获取菜单的paths * 获取菜单的paths
*/ */
export const getMenuPaths = (menus: RouteRecordRaw[]): string[] => { export const getMenuPaths = (menus: RouteRecordRaw[]): string[] => {
let menuPaths: string[] = [] let menuPaths: string[] = []
menus.forEach(item => { menus.forEach(item => {
menuPaths.push(item.path) menuPaths.push(item.path)
if (item.children && item.children.length > 0) { if (item.children && item.children.length > 0) {
menuPaths = menuPaths.concat(getMenuPaths(item.children)) menuPaths = menuPaths.concat(getMenuPaths(item.children))
} }
}) })
return menuPaths return menuPaths
} }
/** /**
* 后台的菜单处理 * 后台的菜单处理
*/ */
const handleMenuRule = (routes: any, pathPrefix = '/', type = ['menu', 'menu_dir']) => { const handleMenuRule = (routes: any, pathPrefix = '/', type = ['menu', 'menu_dir']) => {
const menuRule: RouteRecordRaw[] = [] const menuRule: RouteRecordRaw[] = []
for (const key in routes) { for (const key in routes) {
if (routes[key].extend == 'add_rules_only') { if (routes[key].extend == 'add_rules_only') {
continue continue
} }
if (!type.includes(routes[key].type)) { if (!type.includes(routes[key].type)) {
continue continue
} }
if (routes[key].type == 'menu_dir' && routes[key].children && !routes[key].children.length) { if (routes[key].type == 'menu_dir' && routes[key].children && !routes[key].children.length) {
continue continue
} }
if ( if (
['route', 'menu', 'nav_user_menu', 'nav'].includes(routes[key].type) && ['route', 'menu', 'nav_user_menu', 'nav'].includes(routes[key].type) &&
((routes[key].menu_type == 'tab' && !routes[key].component) || ((routes[key].menu_type == 'tab' && !routes[key].component) ||
(['link', 'iframe'].includes(routes[key].menu_type) && !routes[key].url)) (['link', 'iframe'].includes(routes[key].menu_type) && !routes[key].url))
) { ) {
continue continue
} }
const currentPath = ['link', 'iframe'].includes(routes[key].menu_type) const currentPath = ['link', 'iframe'].includes(routes[key].menu_type)
? routes[key].url ? routes[key].url
: pathPrefix + routes[key].path : pathPrefix + routes[key].path
let children: RouteRecordRaw[] = [] let children: RouteRecordRaw[] = []
if (routes[key].children && routes[key].children.length > 0) { if (routes[key].children && routes[key].children.length > 0) {
children = handleMenuRule(routes[key].children, pathPrefix, type) children = handleMenuRule(routes[key].children, pathPrefix, type)
} }
menuRule.push({ menuRule.push({
path: currentPath, path: currentPath,
name: routes[key].name, name: routes[key].name,
component: routes[key].component, component: routes[key].component,
meta: { meta: {
id: routes[key].id, id: routes[key].id,
title: routes[key].title, title: routes[key].title,
icon: routes[key].icon, icon: routes[key].icon,
keepalive: routes[key].keepalive, keepalive: routes[key].keepalive,
menu_type: routes[key].menu_type, menu_type: routes[key].menu_type,
type: routes[key].type type: routes[key].type
}, },
children: children children: children
}) })
} }
return menuRule return menuRule
} }
/** /**
* 处理权限节点 * 处理权限节点
* @param routes 路由数据 * @param routes 路由数据
* @param prefix 节点前缀 * @param prefix 节点前缀
* @returns 组装好的权限节点 * @returns 组装好的权限节点
*/ */
const handleAuthNode = (routes: any, prefix = '/') => { const handleAuthNode = (routes: any, prefix = '/') => {
const authNode: Map<string, string[]> = new Map([]) const authNode: Map<string, string[]> = new Map([])
assembleAuthNode(routes, authNode, prefix, prefix) assembleAuthNode(routes, authNode, prefix, prefix)
return authNode return authNode
} }
const assembleAuthNode = (routes: any, authNode: Map<string, string[]>, prefix = '/', parent = '/') => { const assembleAuthNode = (routes: any, authNode: Map<string, string[]>, prefix = '/', parent = '/') => {
const authNodeTemp = [] const authNodeTemp = []
for (const key in routes) { for (const key in routes) {
if (routes[key].type == 'button') authNodeTemp.push(prefix + routes[key].name) if (routes[key].type == 'button') authNodeTemp.push(prefix + routes[key].name)
if (routes[key].children && routes[key].children.length > 0) { if (routes[key].children && routes[key].children.length > 0) {
assembleAuthNode(routes[key].children, authNode, prefix, prefix + routes[key].name) assembleAuthNode(routes[key].children, authNode, prefix, prefix + routes[key].name)
} }
} }
if (authNodeTemp && authNodeTemp.length > 0) { if (authNodeTemp && authNodeTemp.length > 0) {
authNode.set(parent, authNodeTemp) authNode.set(parent, authNodeTemp)
} }
} }
/** /**
* 动态添加路由-带子路由 * 动态添加路由-带子路由
* @param viewsComponent * @param viewsComponent
* @param routes * @param routes
* @param parentName * @param parentName
* @param analyticRelation 根据 name 从已注册路由分析父级路由 * @param analyticRelation 根据 name 从已注册路由分析父级路由
*/ */
export const addRouteAll = ( export const addRouteAll = (
viewsComponent: Record<string, any>, viewsComponent: Record<string, any>,
routes: any, routes: any,
parentName: string, parentName: string,
analyticRelation = false analyticRelation = false
) => { ) => {
for (const idx in routes) { for (const idx in routes) {
if (routes[idx].extend == 'add_menu_only') { if (routes[idx].extend == 'add_menu_only') {
continue continue
} }
if ( if (
(routes[idx].menu_type == 'tab' && viewsComponent[routes[idx].component]) || (routes[idx].menu_type == 'tab' && viewsComponent[routes[idx].component]) ||
routes[idx].menu_type == 'iframe' routes[idx].menu_type == 'iframe'
) { ) {
addRouteItem(viewsComponent, routes[idx], parentName, analyticRelation) addRouteItem(viewsComponent, routes[idx], parentName, analyticRelation)
} }
if (routes[idx].children && routes[idx].children.length > 0) { if (routes[idx].children && routes[idx].children.length > 0) {
addRouteAll(viewsComponent, routes[idx].children, parentName, analyticRelation) addRouteAll(viewsComponent, routes[idx].children, parentName, analyticRelation)
} }
} }
} }
/** /**
* 动态添加路由 * 动态添加路由
* @param viewsComponent * @param viewsComponent
* @param route * @param route
* @param parentName * @param parentName
* @param analyticRelation 根据 name 从已注册路由分析父级路由 * @param analyticRelation 根据 name 从已注册路由分析父级路由
*/ */
export const addRouteItem = ( export const addRouteItem = (
viewsComponent: Record<string, any>, viewsComponent: Record<string, any>,
route: any, route: any,
parentName: string, parentName: string,
analyticRelation: boolean analyticRelation: boolean
) => { ) => {
let path = '', let path = '',
component component
if (route.menu_type == 'iframe') { if (route.menu_type == 'iframe') {
path = (isAdminApp() ? adminBaseRoute.path : '') + '/iframe/' + encodeURIComponent(route.url) path = (isAdminApp() ? adminBaseRoute.path : '') + '/iframe/' + encodeURIComponent(route.url)
component = () => import('@/layouts/common/router-view/iframe.vue') component = () => import('@/layouts/common/router-view/iframe.vue')
} else { } else {
path = parentName ? route.path : '/' + route.path path = parentName ? route.path : '/' + route.path
component = viewsComponent[route.component] component = viewsComponent[route.component]
} }
if (route.menu_type == 'tab' && analyticRelation) { if (route.menu_type == 'tab' && analyticRelation) {
const parentNames = getParentNames(route.name) const parentNames = getParentNames(route.name)
if (parentNames.length) { if (parentNames.length) {
for (const key in parentNames) { for (const key in parentNames) {
if (router.hasRoute(parentNames[key])) { if (router.hasRoute(parentNames[key])) {
parentName = parentNames[key] parentName = parentNames[key]
break break
} }
} }
} }
} }
const routeBaseInfo: RouteRecordRaw = { const routeBaseInfo: RouteRecordRaw = {
path: path, path: path,
name: route.name, name: route.name,
component: component, component: component,
meta: { meta: {
...route, ...route,
title: route.title, title: route.title,
extend: route.extend, extend: route.extend,
icon: route.icon, icon: route.icon,
keepalive: route.keepalive, keepalive: route.keepalive,
menu_type: route.menu_type, menu_type: route.menu_type,
type: route.type, type: route.type,
url: route.url, url: route.url,
addtab: true addtab: true
} }
} }
if (parentName) { if (parentName) {
router.addRoute(parentName, routeBaseInfo) router.addRoute(parentName, routeBaseInfo)
} else { } else {
router.addRoute(routeBaseInfo) router.addRoute(routeBaseInfo)
} }
} }
/** /**
* 根据name字符串获取父级name组合的数组 * 根据name字符串获取父级name组合的数组
* @param name * @param name
*/ */
const getParentNames = (name: string) => { const getParentNames = (name: string) => {
const names = compact(name.split('/')) const names = compact(name.split('/'))
const tempNames = [] const tempNames = []
const parentNames = [] const parentNames = []
for (const key in names) { for (const key in names) {
tempNames.push(names[key]) tempNames.push(names[key])
if (parseInt(key) != names.length - 1) { if (parseInt(key) != names.length - 1) {
parentNames.push(tempNames.join('/')) parentNames.push(tempNames.join('/'))
} }
} }
return reverse(parentNames) return reverse(parentNames)
} }

View File

@@ -23,7 +23,7 @@ const prop = defineProps({
const dictData = useDictData() const dictData = useDictData()
const fontdveoption = dictData.getBasicData('Dev_Ops') const fontdveoption = dictData.getBasicData('Dev_Ops')
const tableStore = new TableStore({ const tableStore:any = new TableStore({
url: '/device-boot/pqsTerminalLogs/getList', url: '/device-boot/pqsTerminalLogs/getList',
method: 'POST', method: 'POST',
column: [ column: [

View File

@@ -399,7 +399,7 @@ const handleCurrentChange = (val: number) => {
const exportEvent = () => { const exportEvent = () => {
const allFilteredData = filteredData.value const allFilteredData = filteredData.value
tableRef.value.exportData({ tableRef.value.exportData({
filename: '场级评估-污染值报告', filename: '场级评估-污染值报告',
sheetName: 'Sheet1', sheetName: 'Sheet1',
type: 'xlsx', type: 'xlsx',
useStyle: true, useStyle: true,

View File

@@ -652,7 +652,7 @@ const initRadioCharts = () => {
echartsData1.value.options.series[i].center = ['50%', '50%'] echartsData1.value.options.series[i].center = ['50%', '50%']
} }
} }
const initEcharts = (color: string, key: number) => { const initEcharts = (color: string, key: number, name: string) => {
return { return {
options: { options: {
tooltip: {}, tooltip: {},
@@ -731,7 +731,7 @@ const initEcharts = (color: string, key: number) => {
data: [ data: [
{ {
value: 0, value: 0,
name: 'A相', name: name,
itemStyle: { itemStyle: {
color: color color: color
} }
@@ -744,14 +744,14 @@ const initEcharts = (color: string, key: number) => {
} }
//渲染echarts //渲染echarts
const init = () => { const init = () => {
const url = (localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/api/pushMessage/') const url = localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/api/pushMessage/'
echartsDataV1.value = initEcharts('#DAA520', 0) echartsDataV1.value = initEcharts('#DAA520', 0, 'A相')
echartsDataV2.value = initEcharts('#2E8B57', 0) echartsDataV2.value = initEcharts('#2E8B57', 0, 'B相')
echartsDataV3.value = initEcharts('#A52a2a', 0) echartsDataV3.value = initEcharts('#A52a2a', 0, 'C相')
echartsDataA1.value = initEcharts('#DAA520', 1) echartsDataA1.value = initEcharts('#DAA520', 1, 'A相')
echartsDataA2.value = initEcharts('#2E8B57', 1) echartsDataA2.value = initEcharts('#2E8B57', 1, 'B相')
echartsDataA3.value = initEcharts('#A52a2a', 1) echartsDataA3.value = initEcharts('#A52a2a', 1, 'C相')
if (!dataSocket.socketServe) { if (!dataSocket.socketServe) {
console.error('WebSocket 客户端实例不存在') console.error('WebSocket 客户端实例不存在')
@@ -764,9 +764,7 @@ const url = (localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/ap
}) })
} }
let pids = monitoringPoint.state.pid.split(',') let pids = monitoringPoint.state.pid.split(',')
dataSocket.socketServe.connect( dataSocket.socketServe.connect(`${url}${adminInfo.id},${monitoringPoint.state.lineId},${pids[pids.length - 2]}`)
`${url}${adminInfo.id},${monitoringPoint.state.lineId},${pids[pids.length - 2]}`
)
dataSocket.socketServe.registerCallBack('message', (res: any) => { dataSocket.socketServe.registerCallBack('message', (res: any) => {
txtContent.value = res.value txtContent.value = res.value
let data = JSON.parse(res.value) let data = JSON.parse(res.value)

View File

@@ -1,170 +1,172 @@
<template> <template>
<div class="default-main" :style="height"> <div class="default-main" :style="height">
<splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes"> <splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes">
<pane :size="size"> <pane :size="size">
<PointTree <PointTree
v-if="showTree" v-if="showTree"
:default-expand-all="false" :default-expand-all="false"
@node-click="handleNodeClick" @node-click="handleNodeClick"
@init="handleNodeClick" @init="handleNodeClick"
></PointTree> ></PointTree>
</pane> </pane>
<pane style="background: #fff" :style="height"> <pane style="background: #fff" :style="height">
<TableHeader ref="TableHeaderRef" datePicker @selectChange="selectChange"> <TableHeader ref="TableHeaderRef" datePicker @selectChange="selectChange">
<template v-slot:select> <template v-slot:select>
<el-form-item label="模板策略"> <el-form-item label="模板策略">
<el-select v-model="Template" @change="changetype" placeholder="请选择模版" value-key="id"> <el-select v-model="Template" @change="changetype" placeholder="请选择模版" value-key="id">
<el-option <el-option
v-for="item in templatePolicy" v-for="item in templatePolicy"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item" :value="item"
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="报表类型"> <el-form-item label="报表类型">
<el-input readonly type="text" value="分析报表"></el-input> <el-input readonly type="text" value="分析报表"></el-input>
<!-- <el-select--> <!-- <el-select-->
<!-- :disabled="true"--> <!-- :disabled="true"-->
<!-- v-model="reportForm"--> <!-- v-model="reportForm"-->
<!-- :popper-append-to-body="false"--> <!-- :popper-append-to-body="false"-->
<!-- placeholder="请选择报表类型"--> <!-- placeholder="请选择报表类型"-->
<!-- >--> <!-- >-->
<!-- <el-option--> <!-- <el-option-->
<!-- v-for="item in reportFormList"--> <!-- v-for="item in reportFormList"-->
<!-- :key="item.value"--> <!-- :key="item.value"-->
<!-- :label="item.label"--> <!-- :label="item.label"-->
<!-- :value="item.value"--> <!-- :value="item.value"-->
<!-- ></el-option>--> <!-- ></el-option>-->
<!-- </el-select>--> <!-- </el-select>-->
</el-form-item> </el-form-item>
</template> </template>
<template #operation> <template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出excel</el-button> <el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出excel</el-button>
</template> </template>
</TableHeader> </TableHeader>
<div class="box"> <div class="box">
<div id="luckysheet" :style="`height: calc(${tableStore.table.height} + 45px)`"></div> <div id="luckysheet" :style="`height: calc(${tableStore.table.height} + 45px)`"></div>
</div> </div>
</pane> </pane>
</splitpanes> </splitpanes>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, provide } from 'vue' import { onMounted, ref, provide } from 'vue'
import 'splitpanes/dist/splitpanes.css' import 'splitpanes/dist/splitpanes.css'
import { Splitpanes, Pane } from 'splitpanes' import { Splitpanes, Pane } from 'splitpanes'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import PointTree from '@/components/tree/pqs/pointTree.vue' import PointTree from '@/components/tree/pqs/pointTree.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { getTemplateByDept } from '@/api/harmonic-boot/luckyexcel' import { getTemplateByDept } from '@/api/harmonic-boot/luckyexcel'
import { exportExcel } from '@/views/system/reportForms/export.js' import { exportExcel } from '@/views/system/reportForms/export.js'
defineOptions({ defineOptions({
name: 'harmonic-boot/xieboReport' name: 'harmonic-boot/xieboReport'
}) })
const showTree = ref(false) const showTree = ref(false)
const height = mainHeight(20) const height = mainHeight(20)
const size = ref(0) const size = ref(0)
const dictData = useDictData() const dictData = useDictData()
const TableHeaderRef = ref() const TableHeaderRef = ref()
const dotList: any = ref({}) const dotList: any = ref({})
const Template: any = ref({}) const Template: any = ref({})
const reportForm: any = ref('') const reportForm: any = ref('')
const templatePolicy: any = ref([]) const templatePolicy: any = ref([])
const reportFormList: any = ref([ const reportFormList: any = ref([
{ {
value: '1', value: '1',
label: '分析报表' label: '分析报表'
}, },
{ {
value: '2', value: '2',
label: '统计报表' label: '统计报表'
}, },
{ {
value: '3', value: '3',
label: '自定义报表' label: '自定义报表'
} }
]) ])
const tableStore = new TableStore({ const tableStore = new TableStore({
url: '/harmonic-boot/customReport/getCustomReport', url: '/harmonic-boot/customReport/getCustomReport',
method: 'POST', method: 'POST',
column: [], column: [],
beforeSearchFun: () => { beforeSearchFun: () => {
tableStore.table.params.tempId = Template.value.id tableStore.table.params.tempId = Template.value.id
tableStore.table.params.lineId = dotList.value.id tableStore.table.params.lineId = dotList.value.id
}, },
loadCallback: () => { loadCallback: () => {
tableStore.table.data.forEach((item: any) => { tableStore.table.data.forEach((item: any) => {
item.data1 ? (item.data = JSON.parse(item.data1)) : '' item.data1 ? (item.data = JSON.parse(item.data1)) : ''
item.celldata.forEach((k: any) => { item.celldata.forEach((k: any) => {
item.data[k.r][k.c].v ? (item.data[k.r][k.c] = k.v) : '' item.data[k.r][k.c].v ? (item.data[k.r][k.c] = k.v) : ''
}) })
}) })
console.log(tableStore.table.data) console.log(tableStore.table.data)
setTimeout(() => { setTimeout(() => {
luckysheet.create({ luckysheet.create({
container: 'luckysheet', container: 'luckysheet',
title: '', // 表 头名 title: '', // 表 头名
lang: 'zh', // 中文 lang: 'zh', // 中文
showtoolbar: false, // 是否显示工具栏 showtoolbar: false, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏 showinfobar: false, // 是否显示顶部信息栏
showsheetbar: true, // 是否显示底部sheet按钮 showsheetbar: true, // 是否显示底部sheet按钮
data: tableStore.table.data allowEdit: false, // 禁止所有编辑操作(必填)
}) data: tableStore.table.data
}, 10) })
} }, 10)
}) }
provide('tableStore', tableStore) })
provide('tableStore', tableStore)
onMounted(() => {
const dom = document.getElementById('navigation-splitpanes') onMounted(() => {
if (dom) { const dom = document.getElementById('navigation-splitpanes')
size.value = Math.round((180 / dom.offsetHeight) * 100) if (dom) {
} size.value = Math.round((180 / dom.offsetHeight) * 100)
}) }
getTemplateByDept({ id: dictData.state.area[0].id }) })
.then((res: any) => { getTemplateByDept({ id: dictData.state.area[0].id })
templatePolicy.value = res.data .then((res: any) => {
Template.value = res.data[0] templatePolicy.value = res.data
reportForm.value = res.data[0]?.reportForm Template.value = res.data[0]
showTree.value = true reportForm.value = res.data[0]?.reportForm
}) showTree.value = true
.catch((err: any) => { })
showTree.value = true .catch((err: any) => {
}) showTree.value = true
const changetype = (val: any) => { })
reportForm.value = val.reportForm const changetype = (val: any) => {
} reportForm.value = val.reportForm
const selectChange = () => { }
console.log('🚀 ~ selectChange ~ tableStore.table.data.lnegth :', tableStore.table.data.length) const selectChange = () => {
if (tableStore.table.data.length != 0) { console.log('🚀 ~ selectChange ~ tableStore.table.data.lnegth :', tableStore.table.data.length)
setTimeout(() => { if (tableStore.table.data.length != 0) {
luckysheet && luckysheet?.resize() setTimeout(() => {
}, 10) luckysheet && luckysheet?.resize()
} }, 10)
} }
}
const handleNodeClick = (data: any, node: any) => {
if (data.level == 6) { const handleNodeClick = (data: any, node: any) => {
dotList.value = data if (data.level == 6) {
tableStore.index() dotList.value = data
} tableStore.index()
} }
}
const exportEvent = () => {
exportExcel(luckysheet.getAllSheets(), '统计报表下载') const exportEvent = () => {
} exportExcel(luckysheet.getAllSheets(), '统计报表下载')
</script> }
<style lang="scss"> </script>
.splitpanes.default-theme .splitpanes__pane { <style lang="scss">
background: #eaeef1; .splitpanes.default-theme .splitpanes__pane {
} background: #eaeef1;
}
.box {
padding: 10px; .box {
} padding: 10px;
</style>
}
</style>

View File

@@ -1,338 +1,338 @@
<template> <template>
<div @keyup.enter="onSubmit(formRef)"> <div @keyup.enter="onSubmit(formRef)">
<div @contextmenu.stop="" id="bubble" class="bubble"> <div @contextmenu.stop="" id="bubble" class="bubble">
<canvas id="bubble-canvas" class="bubble-canvas"></canvas> <canvas id="bubble-canvas" class="bubble-canvas"></canvas>
</div> </div>
<div class="login-image"></div> <div class="login-image"></div>
<div class="login-container-form"> <div class="login-container-form">
<div class="title-container"> <div class="title-container">
<div class="title"> <div class="title">
<span style="font-size: 28px">{{ getThemeList.name || '电能质量监测系统' }}</span> <span style="font-size: 28px">{{ getThemeList.name || '电能质量监测系统' }}</span>
</div> </div>
</div> </div>
<el-form :rules="rules" ref="formRef" size="large" class="login-form" :model="form"> <el-form :rules="rules" ref="formRef" size="large" class="login-form" :model="form">
<el-form-item prop="username"> <el-form-item prop="username">
<el-input <el-input
ref="usernameRef" ref="usernameRef"
v-model="form.username" v-model="form.username"
type="text" type="text"
clearable clearable
placeholder="用户名" placeholder="用户名"
autocomplete="off" autocomplete="off"
> >
<template #prefix> <template #prefix>
<!-- <span class="iconfont icon-yonghu" style="color: var(--el-color-primary)"></span> --> <!-- <span class="iconfont icon-yonghu" style="color: var(--el-color-primary)"></span> -->
<Icon name="fa fa-user" style="color: var(--el-color-primary); font-size: 16px" /> <Icon name="fa fa-user" style="color: var(--el-color-primary); font-size: 16px" />
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input <el-input
ref="passwordRef" ref="passwordRef"
v-model="form.password" v-model="form.password"
type="password" type="password"
placeholder="密码" placeholder="密码"
autocomplete="off" autocomplete="off"
> >
<template #prefix> <template #prefix>
<Icon name="local-password" style="color: var(--el-color-primary); font-size: 16px" /> <Icon name="local-password" style="color: var(--el-color-primary); font-size: 16px" />
<!-- <span class="iconfont icon-mima" style="color: var(--el-color-primary)"></span> --> <!-- <span class="iconfont icon-mima" style="color: var(--el-color-primary)"></span> -->
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button <el-button
:loading="state.submitLoading" :loading="state.submitLoading"
class="submit-btn" class="submit-btn"
round round
type="info" type="info"
@click="onSubmit(formRef)" @click="onSubmit(formRef)"
> >
登录 登录
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<!-- <div class="copy-right"> <!-- <div class="copy-right">
<span>版权所有 @ 南京灿能电力自动化股份有限公司</span> <span>版权所有 @ 南京灿能电力自动化股份有限公司</span>
<br /> <br />
<img style="width: 20px; height: 20px; position: absolute" src="@/assets/login/jhui.png" /> <img style="width: 20px; height: 20px; position: absolute" src="@/assets/login/jhui.png" />
<span>  苏公网安备 32011502011902</span> <span>  苏公网安备 32011502011902</span>
</div> --> </div> -->
<PopupUpdatePwd ref="popupUpdatePwdRef"></PopupUpdatePwd> <PopupUpdatePwd ref="popupUpdatePwdRef"></PopupUpdatePwd>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue' import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
import * as pageBubble from '@/utils/pageBubble' import * as pageBubble from '@/utils/pageBubble'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { gongkey, login,getSysConfig } from '@/api/user-boot/user' import { gongkey, login,getSysConfig } from '@/api/user-boot/user'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import type { FormInstance, InputInstance, FormRules } from 'element-plus' import type { FormInstance, InputInstance, FormRules } from 'element-plus'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { ADMIN_INFO } from '@/stores/constant/cacheKey' import { ADMIN_INFO } from '@/stores/constant/cacheKey'
import { Local } from '@/utils/storage' import { Local } from '@/utils/storage'
import { getTheme } from '@/api/systerm' import { getTheme } from '@/api/systerm'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import PopupUpdatePwd from './popupUpdatePwd.vue' import PopupUpdatePwd from './popupUpdatePwd.vue'
const router = useRouter() const router = useRouter()
let timer: number let timer: number
const configStore = useConfig() const configStore = useConfig()
const popupUpdatePwdRef = ref() const popupUpdatePwdRef = ref()
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const usernameRef = ref<InputInstance>() const usernameRef = ref<InputInstance>()
const passwordRef = ref<InputInstance>() const passwordRef = ref<InputInstance>()
const userInfo = useAdminInfo() const userInfo = useAdminInfo()
Local.remove(ADMIN_INFO) Local.remove(ADMIN_INFO)
userInfo.removeToken() userInfo.removeToken()
const getThemeList: any = ref([]) const getThemeList: any = ref([])
interface RuleForm { interface RuleForm {
username: string username: string
password: string password: string
} }
const state = reactive({ const state = reactive({
showCaptcha: false, showCaptcha: false,
submitLoading: false submitLoading: false
}) })
const form = reactive({ const form = reactive({
username: '', username: '',
password: '' password: ''
}) })
const rules = reactive<FormRules<RuleForm>>({ const rules = reactive<FormRules<RuleForm>>({
username: [{ required: true, trigger: 'blur', message: '请输入用户名' }], username: [{ required: true, trigger: 'blur', message: '请输入用户名' }],
password: [{ required: true, trigger: 'blur', message: '请输入密码' }] password: [{ required: true, trigger: 'blur', message: '请输入密码' }]
}) })
const focusInput = () => { const focusInput = () => {
if (form.username === '') { if (form.username === '') {
usernameRef.value!.focus() usernameRef.value!.focus()
} else if (form.password === '') { } else if (form.password === '') {
passwordRef.value!.focus() passwordRef.value!.focus()
} }
} }
onMounted(() => { onMounted(() => {
timer = window.setTimeout(() => { timer = window.setTimeout(() => {
pageBubble.init() pageBubble.init()
}, 0) }, 0)
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearTimeout(timer) clearTimeout(timer)
pageBubble.removeListeners() pageBubble.removeListeners()
}) })
getTheme().then(res => { getTheme().then(res => {
document.title = res.data.name || '电能质量在线监测系统' document.title = res.data.name || '电能质量在线监测系统'
let list: any = [ let list: any = [
'elementUiPrimary', 'elementUiPrimary',
'tableHeaderBackground', 'tableHeaderBackground',
'tableHeaderColor', 'tableHeaderColor',
'tableCurrent', 'tableCurrent',
'menuBackground', 'menuBackground',
'menuColor', 'menuColor',
'menuTopBarBackground', 'menuTopBarBackground',
'menuActiveBackground', 'menuActiveBackground',
'menuActiveColor', 'menuActiveColor',
'headerBarTabColor', 'headerBarTabColor',
'headerBarBackground' 'headerBarBackground'
] ]
getThemeList.value = res.data getThemeList.value = res.data
window.localStorage.setItem('getTheme', JSON.stringify(res.data)) window.localStorage.setItem('getTheme', JSON.stringify(res.data))
for (let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
configStore.setLayout(list[i], JSON.parse(res.data[list[i]])) configStore.setLayout(list[i], JSON.parse(res.data[list[i]]))
} }
configStore.setLayout('elementUiPrimary', JSON.parse(res.data['elementUiPrimary'])) configStore.setLayout('elementUiPrimary', JSON.parse(res.data['elementUiPrimary']))
}) })
const onSubmit = async (formEl: FormInstance | undefined) => { const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {
if (valid) { if (valid) {
state.submitLoading = true state.submitLoading = true
login({ login({
username: form.username, username: form.username,
password: form.password, password: form.password,
grant_type: 'captcha', grant_type: 'captcha',
imageCode: '', imageCode: '',
verifyCode: 0 verifyCode: 0
}) })
.then(res => { .then(res => {
userInfo.dataFill(res.data) userInfo.dataFill(res.data)
state.submitLoading = false state.submitLoading = false
getSysConfig().then(res => { getSysConfig().then(res => {
window.localStorage.setItem('sysdata', JSON.stringify(res.data)) window.localStorage.setItem('sysdata', JSON.stringify(res.data))
}) })
router.push({ router.push({
path: '/' path: '/'
}) })
}) })
.catch(err => { .catch(err => {
if (err.code === 'A0101' && err.message === '登录认证,密码失效,请重置') { if (err.code === 'A0101' && err.message === '登录认证,密码失效,请重置') {
popupUpdatePwdRef.value.open(form.username) popupUpdatePwdRef.value.open(form.username)
} }
}) })
setTimeout(() => { setTimeout(() => {
state.submitLoading = false state.submitLoading = false
}, 500) }, 500)
} }
}) })
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.bubble { .bubble {
position: relative; position: relative;
width: 100%; width: 100%;
min-height: 100%; min-height: 100%;
overflow: hidden; overflow: hidden;
background-color: var(--el-color-primary) !important; background-color: var(--el-color-primary) !important;
background-position: center 110px; background-position: center 110px;
background-repeat: repeat; background-repeat: repeat;
background-size: 100%; background-size: 100%;
background-image: url(https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg); background-image: url(https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg);
} }
.login-image { .login-image {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 20%; left: 20%;
min-width: 45%; min-width: 45%;
min-height: 80%; min-height: 80%;
background: url('../../assets/login/login2.png') no-repeat center center; background: url('../../assets/login/login2.png') no-repeat center center;
background-size: contain; background-size: contain;
transform: translate(-15%, -50%); transform: translate(-15%, -50%);
// box-shadow: 0 0 0 #011b2bab; // box-shadow: 0 0 0 #011b2bab;
} }
.form-item-icon { .form-item-icon {
height: auto; height: auto;
} }
.login-container-form { .login-container-form {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 85%; left: 85%;
width: 500px; width: 500px;
height: auto; height: auto;
border-radius: 30px; border-radius: 30px;
transform: translate(-85%, -50%); transform: translate(-85%, -50%);
box-shadow: 3px 3px 2px 2px #011b2bab; box-shadow: 3px 3px 2px 2px #011b2bab;
.title-container { .title-container {
position: relative; position: relative;
width: 398px; width: 398px;
max-width: 100%; max-width: 100%;
padding: 20px 0 0; padding: 20px 0 0;
margin: 0 auto; margin: 0 auto;
.title { .title {
margin-bottom: 20px; margin-bottom: 20px;
font-size: 33px; font-size: 33px;
font-weight: 600; font-weight: 600;
color: rgba(255, 255, 255, 0.85); color: rgba(255, 255, 255, 0.85);
text-align: center; text-align: center;
& :v-deep .svg-icon { & :v-deep .svg-icon {
// color: $; // color: $;
} }
.logo { .logo {
width: 46px; width: 46px;
height: 46px; height: 46px;
margin-right: 10px; margin-right: 10px;
vertical-align: middle; vertical-align: middle;
} }
} }
} }
} }
.login-form { .login-form {
position: relative; position: relative;
width: 368px; width: 368px;
max-width: 100%; max-width: 100%;
//padding: 20px 0 0; //padding: 20px 0 0;
margin: 0 auto; margin: 0 auto;
margin-bottom: 20px; margin-bottom: 20px;
overflow: hidden; overflow: hidden;
&.el-input { &.el-input {
input { input {
height: 40px; height: 40px;
padding-right: 40px; padding-right: 40px;
padding-left: 40px; padding-left: 40px;
line-height: 40px; line-height: 40px;
border-radius: 5px; border-radius: 5px;
} }
.el-input__prefix, .el-input__prefix,
.el-input__suffix { .el-input__suffix {
width: 40px; width: 40px;
line-height: 40px; line-height: 40px;
.svg-icon { .svg-icon {
font-size: 16px; font-size: 16px;
vertical-align: -0.25em; vertical-align: -0.25em;
} }
} }
.el-input__prefix { .el-input__prefix {
left: 0; left: 0;
} }
.el-input__suffix { .el-input__suffix {
right: 0; right: 0;
} }
} }
} }
.copy-right { .copy-right {
position: absolute; position: absolute;
bottom: 10px; bottom: 10px;
width: 100%; width: 100%;
font-size: 14px; font-size: 14px;
color: rgb(233, 229, 229); color: rgb(233, 229, 229);
text-align: center; text-align: center;
} }
:v-deep.el-form-item--large { :v-deep.el-form-item--large {
margin-bottom: 15px; margin-bottom: 15px;
} }
.submit-btn { .submit-btn {
width: 100%; width: 100%;
margin-top: 0px; margin-top: 0px;
margin-bottom: 20px; margin-bottom: 20px;
background: var(--el-color-primary-light-3); background: var(--el-color-primary-light-3);
// background: #009688; // background: #009688;
//background: #4d6ea1; //background: #4d6ea1;
border-radius: 0; border-radius: 0;
&:hover { &:hover {
background: var(--el-color-primary-light-5); background: var(--el-color-primary-light-5);
} }
} }
@media screen and (max-width: 720px) { @media screen and (max-width: 720px) {
.login { .login {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.login-box { .login-box {
width: 340px; width: 340px;
margin-top: 0; margin-top: 0;
} }
} }
} }
@media screen and (max-height: 800px) { @media screen and (max-height: 800px) {
.login .login-box { .login .login-box {
margin-bottom: 0; margin-bottom: 0;
} }
} }
</style> </style>