This commit is contained in:
仲么了
2023-12-29 14:46:20 +08:00
parent d6f3a74ac7
commit 526d541cc2
15 changed files with 372 additions and 111 deletions

View File

@@ -10,6 +10,7 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@fortawesome/fontawesome-free": "^6.5.1",
"@vueuse/core": "^10.7.0",
"axios": "^1.6.2",
"crypto-js": "^4.2.0",

9
pnpm-lock.yaml generated
View File

@@ -4,6 +4,9 @@ dependencies:
'@element-plus/icons-vue':
specifier: ^2.3.1
version: 2.3.1(vue@3.3.13)
'@fortawesome/fontawesome-free':
specifier: ^6.5.1
version: 6.5.1
'@vueuse/core':
specifier: ^10.7.0
version: 10.7.0(vue@3.3.13)
@@ -586,6 +589,12 @@ packages:
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==, tarball: https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.1.6.tgz}
dev: false
/@fortawesome/fontawesome-free@6.5.1:
resolution: {integrity: sha512-CNy5vSwN3fsUStPRLX7fUYojyuzoEMSXPl7zSLJ8TgtRfjv24LOnOWKT2zYwaHZCJGkdyRnTmstR0P+Ah503Gw==}
engines: {node: '>=6'}
requiresBuild: true
dev: false
/@jridgewell/gen-mapping@0.3.3:
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
engines: {node: '>=6.0.0'}

View File

@@ -1,22 +1,19 @@
<template>
<el-config-provider :locale="zhCn">
<el-config-provider :locale='zhCn'>
<router-view></router-view>
</el-config-provider>
</template>
<script lang="ts" setup>
<script lang='ts' setup>
import { computed, ref } from 'vue'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import { useConfig } from '@/stores/config'
import { useElementPlusTheme } from "use-element-plus-theme"
import { useElementPlusTheme } from 'use-element-plus-theme'
const configStore = useConfig()
useElementPlusTheme(configStore.getColorVal('elementUiPrimary'))
// document.documentElement.style.setProperty('--el-color-primary', configStore.getColorVal('elementUiPrimary'));
</script>
<style lang="scss">
// $primaryColor: v-bind('configStore.getColorVal("elementUiPrimary")');
// :root {
// --el-color-primary: $primaryColor !important;
// }
<style lang='scss'>
</style>

View File

@@ -1,55 +1,53 @@
<template>
<el-popover
:placement="placement"
trigger="focus"
:hide-after="0"
:width="state.selectorWidth"
:visible="state.popoverVisible"
:placement='placement'
trigger='focus'
:hide-after='0'
:width='state.selectorWidth'
:visible='state.popoverVisible'
>
<div
@mouseover.stop="state.iconSelectorMouseover = true"
@mouseout.stop="state.iconSelectorMouseover = false"
class="icon-selector"
@mouseover.stop='state.iconSelectorMouseover = true'
@mouseout.stop='state.iconSelectorMouseover = false'
class='icon-selector'
>
<transition name="el-zoom-in-center">
<div class="icon-selector-box">
<div class="selector-header">
<div class="selector-title">{{ title ? title : '请选择图标' }}</div>
<!-- <div class="selector-tab">
<transition name='el-zoom-in-center'>
<div class='icon-selector-box'>
<div class='selector-header'>
<div class='selector-title'>{{ title ? title : '请选择图标' }}</div>
<div class='selector-tab'>
<span
:title="'Element Puls ' + 'utils.Icon'"
@click="onChangeTab('ele')"
:class="state.iconType == 'ele' ? 'active' : ''"
>ele</span
>
>ele</span>
<span
:title="'Font Awesome ' + 'utils.Icon'"
@click="onChangeTab('awe')"
:class="state.iconType == 'awe' ? 'active' : ''"
>awe</span
>
<span :title="'utils.Ali iconcont Icon'" @click="onChangeTab('ali')" :class="state.iconType == 'ali' ? 'active' : ''"
>ali</span
>
<span
:title="'utils.Local icon title'"
@click="onChangeTab('local')"
:class="state.iconType == 'local' ? 'active' : ''"
>local</span
>
</div> -->
>awe</span>
<!-- <span :title="'utils.Ali iconcont Icon'" @click="onChangeTab('ali')"-->
<!-- :class="state.iconType == 'ali' ? 'active' : ''"-->
<!-- >ali</span>-->
<!-- <span-->
<!-- :title="'utils.Local icon title'"-->
<!-- @click="onChangeTab('local')"-->
<!-- :class="state.iconType == 'local' ? 'active' : ''"-->
<!-- >local</span-->
<!-- >-->
</div>
<div class="selector-body">
<el-scrollbar ref="selectorScrollbarRef">
<div v-if="renderFontIconNames.length > 0">
</div>
<div class='selector-body'>
<el-scrollbar ref='selectorScrollbarRef'>
<div v-if='renderFontIconNames.length > 0'>
<div
class="icon-selector-item"
:title="item"
@click="onIcon(item)"
v-for="(item, key) in renderFontIconNames"
:key="key"
class='icon-selector-item'
:title='item'
@click='onIcon(item)'
v-for='(item, key) in renderFontIconNames'
:key='key'
>
<Icon :name="item" />
<Icon :name='item' />
</div>
</div>
</el-scrollbar>
@@ -59,37 +57,37 @@
</div>
<template #reference>
<el-input
v-model="state.inputValue"
:size="size"
:disabled="disabled"
placeholder="搜索图标"
ref="selectorInput"
@focus="onInputFocus"
@blur="onInputBlur"
v-model='state.inputValue'
:size='size'
:disabled='disabled'
placeholder='搜索图标'
ref='selectorInput'
@focus='onInputFocus'
@blur='onInputBlur'
:class="'size-' + size"
>
<template #prepend>
<div class="icon-prepend">
<div class='icon-prepend'>
<Icon
:key="'icon' + state.iconKey"
:name="state.prependIcon ? state.prependIcon : state.defaultModelValue"
:name='state.prependIcon ? state.prependIcon : state.defaultModelValue'
/>
<div v-if="showIconName" class="name">
<div v-if='showIconName' class='name'>
{{ state.prependIcon ? state.prependIcon : state.defaultModelValue }}
</div>
</div>
</template>
<template #append>
<Icon @click="onInputRefresh" name="el-icon-RefreshRight" />
<Icon @click='onInputRefresh' name='el-icon-RefreshRight' />
</template>
</el-input>
</template>
</el-popover>
</template>
<script setup lang="ts">
<script setup lang='ts'>
import { reactive, ref, onMounted, nextTick, watch, computed } from 'vue'
import { getElementPlusIconfontNames } from '@/utils/iconfont'
import { getElementPlusIconfontNames,getAwesomeIconfontNames } from '@/utils/iconfont'
import { useEventListener } from '@vueuse/core'
import type { Placement } from 'element-plus'
@@ -104,6 +102,7 @@ interface Props {
modelValue?: string
showIconName?: boolean
}
const props = withDefaults(defineProps<Props>(), {
size: 'default',
disabled: false,
@@ -111,7 +110,7 @@ const props = withDefaults(defineProps<Props>(), {
type: 'ele',
placement: 'bottom',
modelValue: '',
showIconName: false,
showIconName: false
})
const emits = defineEmits<{
@@ -142,7 +141,7 @@ const state: {
inputValue: '',
prependIcon: props.modelValue,
defaultModelValue: props.modelValue || 'fa fa-circle-o',
iconKey: 0, // 给icon标签准备个key以随时使用 h 函数重新生成元素
iconKey: 0 // 给icon标签准备个key以随时使用 h 函数重新生成元素
})
const onInputFocus = () => {
@@ -158,27 +157,27 @@ const onInputRefresh = () => {
state.inputValue = ''
emits('update:modelValue', state.defaultModelValue)
emits('change', state.defaultModelValue)
// }
// const onChangeTab = (name: IconType) => {
// state.iconType = name
// state.fontIconNames = []
// if (name == 'ele') {
// getElementPlusIconfontNames().then((res) => {
// state.fontIconNames = res
// })
// } else if (name == 'awe') {
// getAwesomeIconfontNames().then((res) => {
// state.fontIconNames = res.map((name) => `fa ${name}`)
// })
// } else if (name == 'ali') {
// getIconfontNames().then((res) => {
// state.fontIconNames = res.map((name) => `iconfont ${name}`)
// })
// } else if (name == 'local') {
// getLocalIconfontNames().then((res) => {
// state.fontIconNames = res
// })
// }
}
const onChangeTab = (name: IconType) => {
state.iconType = name
state.fontIconNames = []
if (name == 'ele') {
getElementPlusIconfontNames().then((res) => {
state.fontIconNames = res
})
} else if (name == 'awe') {
getAwesomeIconfontNames().then((res) => {
state.fontIconNames = res.map((name) => `fa ${name}`)
})
} else if (name == 'ali') {
getIconfontNames().then((res) => {
state.fontIconNames = res.map((name) => `iconfont ${name}`)
})
} else if (name == 'local') {
getLocalIconfontNames().then((res) => {
state.fontIconNames = res
})
}
}
const onIcon = (icon: string) => {
state.iconSelectorMouseover = state.popoverVisible = false
@@ -232,35 +231,43 @@ onMounted(() => {
})
</script>
<style scoped lang="scss">
<style scoped lang='scss'>
.size-small {
height: 24px;
}
.size-large {
height: 40px;
}
.size-default {
height: 32px;
}
.icon-prepend {
display: flex;
align-items: center;
justify-content: center;
.name {
padding-left: 5px;
}
}
.selector-header {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.selector-tab {
margin-left: auto;
span {
padding: 0 5px;
cursor: pointer;
user-select: none;
&.active,
&:hover {
color: var(--el-color-primary);
@@ -268,9 +275,11 @@ onMounted(() => {
}
}
}
.selector-body {
height: 250px;
}
.icon-selector-item {
display: inline-block;
padding: 10px 10px 6px 10px;
@@ -279,17 +288,21 @@ onMounted(() => {
border-radius: var(--el-border-radius-base);
cursor: pointer;
font-size: 18px;
.icon {
height: 18px;
width: 18px;
}
&:hover {
border: 1px solid var(--el-color-primary);
}
}
:deep(.el-input-group__prepend) {
padding: 0 10px;
}
:deep(.el-input-group__append) {
padding: 0 10px;
}

View File

@@ -15,7 +15,7 @@
</div>
</transition>
<div class='table-header ba-scroll-style'>
<div class='table-header ba-scroll-style' v-if='showOperation'>
<slot name='operation'></slot>
<!-- 右侧搜索框和工具按钮 -->
<div class='table-search' v-if='$slots.select'>
@@ -39,11 +39,14 @@ const date = ref([window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd'), window.
interface Props {
// 默认展开
showSelect?: boolean
showOperation?: boolean // 是否显示operation
datePicker?: boolean
}
const props = withDefaults(defineProps<Props>(), {
showSelect: true,
showOperation: true,
datePicker: false
})
if (props.datePicker) {

View File

@@ -12,6 +12,7 @@
v-bind="$attrs"
:column-config="{resizable: true}"
:tree-config="{}"
:row-config="{isCurrent: true, isHover: true}"
>
<!-- Column 组件内部是 el-table-column -->
<Column

View File

@@ -54,7 +54,7 @@
<Icon
:color="configStore.getColorVal('headerBarTabColor')"
class="nav-menu-icon"
name="el-icon-Setting"
name="fa fa-cogs"
size="18"
/>
</div>

View File

@@ -69,7 +69,7 @@ const init = async () => {
title: '控制台',
name: 'dashboard',
path: 'dashboard',
icon: 'el-icon-Platform',
icon: 'fa fa-dashboard',
menu_type: 'tab',
url: '',
component: '/src/views/dashboard/index.vue',
@@ -111,32 +111,59 @@ const init = async () => {
{
id: 3,
pid: 0,
type: 'menu',
type: 'menu_dir',
title: '电压暂降',
name: 'voltage/sags',
path: 'voltage/sags',
icon: 'el-icon-BellFilled',
menu_type: 'tab',
url: '',
component: '/src/views/dashboard/test.vue',
keepalive: 'voltage/sags',
extend: 'none',
children: [
{
id: 1,
pid: 3,
type: 'menu_dir',
title: '运行管理',
name: 'voltage/sags/operationsManagement',
path: 'voltage/sags/operationsManagement',
icon: 'fa-solid fa-bars-progress',
menu_type: 'tab',
url: '',
extend: 'none',
children: [
{
id: 1,
pid: 3,
type: 'menu',
title: '运行管理',
name: 'voltage/sags/operationsManagement',
path: 'voltage/sags/operationsManagement',
icon: 'el-icon-Management',
title: '终端运行管理',
name: 'voltage/sags/operationsManagement/index',
path: 'voltage/sags/operationsManagement/index',
icon: 'fa-solid fa-recycle',
menu_type: 'tab',
url: '',
component: '/src/views/voltage/sags/operationsManagement/index.vue',
keepalive: 'voltage/sags/operationsManagement',
keepalive: 'voltage/sags/operationsManagement/index',
extend: 'none',
children: []
},
{
id: 1,
pid: 3,
type: 'menu',
title: '监测点台账信息',
name: 'voltage/sags/operationsManagement/point',
path: 'voltage/sags/operationsManagement/point',
icon: 'fa-brands fa-square-pinterest',
menu_type: 'tab',
url: '',
component: '/src/views/voltage/sags/operationsManagement/point.vue',
keepalive: 'voltage/sags/operationsManagement/point',
extend: 'none',
children: []
}
]
},
{
id: 2,
pid: 3,
@@ -161,7 +188,7 @@ const init = async () => {
title: '权限管理',
name: 'auth',
path: 'auth',
icon: 'el-icon-Tools',
icon: 'fa fa-group',
menu_type: null,
url: '',
component: '',

View File

@@ -10,7 +10,7 @@ import 'vxe-table/lib/style.css'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/display.css'
// modules import mark, Please do not remove.
import '@fortawesome/fontawesome-free/css/all.css'
import '@/styles/index.scss'
import '@/assets/font/iconfont.css'

View File

@@ -29,4 +29,8 @@ $border-color: map.merge(
@include set-css-var-value('color-primary-light', $primary-light);
@include set-component-css-var('bg-color', $bg-color);
@include set-component-css-var('border-color', $border-color);
--vxe-table-row-current-background-color: var(--el-color-primary-light-7);
--vxe-table-row-hover-background-color: var(--el-color-primary-light-9);
--vxe-table-row-hover-current-background-color: var(--el-color-primary-light-7);
--vxe-table-row-hover-striped-background-color: var(--el-color-primary-light-9);
}

View File

@@ -1,5 +1,7 @@
import { nextTick } from 'vue'
import * as elIcons from '@element-plus/icons-vue'
import { getUrl } from '@/utils/request'
/*
* 获取element plus 自带的图标
*/
@@ -19,3 +21,65 @@ export function getElementPlusIconfontNames() {
})
})
}
/**
* 获取Vite开发服务/编译后的样式表内容
* @param devID style 标签的 viteDevId只开发服务有
*/
function getStylesFromVite(devId: string) {
const sheets = []
const styles: StyleSheetList = document.styleSheets
if (import.meta.env.MODE == 'production') {
const url = getUrl()
for (const key in styles) {
if (styles[key].href && styles[key].href?.indexOf(url) === 0) {
sheets.push(styles[key])
}
}
return sheets
}
for (const key in styles) {
const ownerNode = styles[key].ownerNode as HTMLMapElement
if (ownerNode && ownerNode.dataset?.viteDevId && ownerNode.dataset.viteDevId!.indexOf(devId) > -1) {
sheets.push(styles[key])
}
}
return sheets
}
/*
* 获取 Awesome-Iconfont 的 name 列表
*/
export function getAwesomeIconfontNames() {
return new Promise<string[]>((resolve, reject) => {
nextTick(() => {
const iconfonts = []
const sheets = getStylesFromVite('all.css')
console.log(sheets)
for (const key in sheets) {
const rules: any = sheets[key].cssRules
for (const k in rules) {
if (!rules[k].selectorText || rules[k].selectorText.indexOf('.fa-') !== 0) {
continue
}
if (/^\.fa-(.*)::before$/g.test(rules[k].selectorText)) {
if (rules[k].selectorText.indexOf(', ') > -1) {
const iconNames = rules[k].selectorText.split(', ')
iconfonts.push(`${iconNames[0].substring(1, iconNames[0].length).replace(/\:\:before/gi, '')}`)
} else {
iconfonts.push(`${rules[k].selectorText.substring(1, rules[k].selectorText.length).replace(/\:\:before/gi, '')}`)
}
}
}
}
if (iconfonts.length > 0) {
resolve(iconfonts)
} else {
reject('没有样式表')
}
})
})
}

View File

@@ -43,6 +43,7 @@ export default class TableStore {
this.method = options.method || 'GET'
this.table.column = options.column
this.table.resetCallback = options.resetCallback || null
this.table.loadCallback = options.loadCallback || null
Object.assign(this.table.params, options.params)
}

View File

@@ -1,6 +1,6 @@
<template>
<div class='default-main'>
<TableHeader date-picker>
<TableHeader date-picker :showOperation='false'>
<template v-slot:select>
<el-form-item label='区域'>
<Area v-model='tableStore.table.params.deptIndex' />

View File

@@ -0,0 +1,141 @@
<template>
<div class='default-main'>
<TableHeader date-picker :showOperation='false'>
<template v-slot:select>
<el-form-item label='区域'>
<Area v-model='tableStore.table.params.deptIndex' />
</el-form-item>
<el-form-item label='终端状态'>
<el-select v-model='form.runFlag' placeholder='请选择' @change='onRunFlagChange'>
<el-option label='投运' value='0' />
<el-option label='热备用' value='1' />
<el-option label='停运' value='2' />
</el-select>
</el-form-item>
<el-form-item label='通讯状态'>
<el-select v-model='form.comFlag' placeholder='请选择' @change='onComFlagChange'>
<el-option label='正常' value='1' />
<el-option label='中断' value='0' />
</el-select>
</el-form-item>
<el-form-item label='厂家'>
<el-select v-model='form.manufacturer' placeholder='请选择' @change='onManufacturerChange'>
<el-option
v-for='item in manufacturer'
:key='item.id'
:label='item.name'
:value='item.id'
/>
</el-select>
</el-form-item>
<el-form-item label='筛选数据'>
<el-input v-model='tableStore.table.params.searchValue'
placeholder='根据变电站,终端编号,型号或网络参数查询' style='width:300px' />
</el-form-item>
</template>
</TableHeader>
<Table ref='tableRef' />
</div>
</template>
<script setup lang='tsx'>
import { ref, onMounted, provide, reactive } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import Area from '@/components/form/area/index.vue'
defineOptions({
name: 'comptroller/list'
})
const dictData = useDictData()
const manufacturer = dictData.getBasicData('Dev_Manufacturers')
const tableStore = new TableStore({
isWebPaging: true,
url: '/device-boot/runManage/getRuntimeData',
method: 'POST',
column: [
{ title: '序号', type: 'seq', align: 'center', width: 60 },
{ title: '区域', field: 'areaName', align: 'center', width: 120 },
{ title: '供电公司', field: 'gdName', align: 'center', width: 120 },
{ title: '变电站', field: 'bdName', align: 'center', showOverflow: true, minWidth: 100 },
{ title: '终端编号', field: 'devName', align: 'center', width: 160 },
{ title: '投运时间', field: 'loginTime', align: 'center', width: 200 },
{ title: '厂家', field: 'manufacturer', align: 'center', width: 160 },
{ title: '型号', field: 'devType', align: 'center', width: 200 },
{ title: '网络参数', field: 'ip', align: 'center', width: 200 },
{ title: '端口', field: 'port', align: 'center', width: 100 },
{ title: '终端状态', field: 'runFlag', align: 'center', width: 100 },
{ title: '通讯状态', field: 'comFlag', align: 'center', width: 100 },
{ title: '最新数据', field: 'updateTime', align: 'center', width: 200 },
{
title: '评价',
field: 'onlineEvaluate',
align: 'center',
width: 100,
render: 'customRender',
customRender: props => {
if (props.renderValue == null) {
return <span></span>
} else if (props.renderValue * 100 > 90) {
return (
<el-tag effect='dark' type='success'>
</el-tag>
)
} else if (props.renderValue * 100 > 60) {
return (
<el-tag effect='dark' type='warning'>
</el-tag>
)
} else {
return (
<el-tag effect='dark' type='danger'>
</el-tag>
)
}
}
}
],
resetCallback: () => {
form.runFlag = ''
form.comFlag = ''
form.manufacturer = ''
}
})
const form = reactive({
runFlag: '',
comFlag: '',
manufacturer: ''
})
tableStore.table.params.deptIndex = dictData.state.area[0].id
tableStore.table.params.runFlag = []
tableStore.table.params.comFlag = []
tableStore.table.params.manufacturer = []
tableStore.table.params.statisticalType = {}
tableStore.table.params.serverName = 'event-boot'
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore)
onMounted(() => {
tableStore.index()
})
const onRunFlagChange = (val: any) => {
tableStore.table.params.runFlag = [val]
}
const onComFlagChange = (val: any) => {
tableStore.table.params.comFlag = [val]
}
const onManufacturerChange = (val: any) => {
let obj = manufacturer.find(item => item.id === val) as any
obj.label = obj.name
obj.value = obj.id
tableStore.table.params.manufacturer = [obj]
}
const addMenu = () => {
}
</script>

4
types/table.d.ts vendored
View File

@@ -23,8 +23,8 @@ declare global {
pageSize: number
[key: string]: any
}
loadCallback: () => void | null
resetCallback: () => void | null
loadCallback: (() => void )| null
resetCallback: (() => void)| null
}
/* 表格行 */