This commit is contained in:
GGJ
2023-12-29 16:25:34 +08:00
18 changed files with 579 additions and 170 deletions

View File

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

9
pnpm-lock.yaml generated
View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ const cascaderProps = {
label: 'name', label: 'name',
value: 'id', value: 'id',
checkStrictly: true, checkStrictly: true,
showAllLevels: false emitPath: false
} }
const dictData = useDictData() const dictData = useDictData()
const options = dictData.state.area const options = dictData.state.area

View File

@@ -13,6 +13,7 @@ export default defineComponent({
}, },
setup(props, { slots }) { setup(props, { slots }) {
const attr = reactive(props.attr) const attr = reactive(props.attr)
attr['align'] = attr['align'] ? attr['align'] : 'center'
attr['column-key'] = attr['column-key'] ? attr['column-key'] : attr.prop || uuid() attr['column-key'] = attr['column-key'] ? attr['column-key'] : attr.prop || uuid()
return () => { return () => {
return createVNode(Column, attr, slots.default) return createVNode(Column, attr, slots.default)

View File

@@ -31,7 +31,7 @@
<!-- datetime --> <!-- datetime -->
<div v-if="field.render == 'datetime'"> <div v-if="field.render == 'datetime'">
{{ !fieldValue ? '-' : timeFormat(fieldValue, field.timeFormat ?? undefined) }} {{ !fieldValue ? '/' : timeFormat(fieldValue, field.timeFormat ?? undefined) }}
</div> </div>
<!-- color --> <!-- color -->

View File

@@ -15,7 +15,7 @@
</div> </div>
</transition> </transition>
<div class='table-header ba-scroll-style'> <div class='table-header ba-scroll-style' v-if='showOperation'>
<slot name='operation'></slot> <slot name='operation'></slot>
<!-- 右侧搜索框和工具按钮 --> <!-- 右侧搜索框和工具按钮 -->
<div class='table-search' v-if='$slots.select'> <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 { interface Props {
// 默认展开 // 默认展开
showSelect?: boolean showSelect?: boolean
showOperation?: boolean // 是否显示operation
datePicker?: boolean datePicker?: boolean
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
showSelect: true, showSelect: true,
showOperation: true,
datePicker: false datePicker: false
}) })
if (props.datePicker) { if (props.datePicker) {

View File

@@ -1,61 +1,88 @@
<template> <template>
<vxe-table <vxe-table
ref="tableRef" ref='tableRef'
class="ba-data-table w100" class='ba-data-table w100'
header-cell-class-name="table-header-cell" header-cell-class-name='table-header-cell'
:data="tableStore.table.data" :data='tableStore.table.data'
:border="true" :border='true'
v-loading="tableStore.table.loading" v-loading='tableStore.table.loading'
stripe stripe
size="small" size='small'
@checkbox-change="onSelectionChange" @checkbox-change='onSelectionChange'
v-bind="$attrs" v-bind='$attrs'
:column-config="{resizable: true}" :column-config='{resizable: true}'
:tree-config="{}" :tree-config='{}'
:row-config='{isCurrent: true, isHover: true}'
> >
<!-- Column 组件内部是 el-table-column --> <!-- Column 组件内部是 el-table-column -->
<template v-if='isGroup'>
<vxe-table-colgroup
v-if='isGroup'
v-for='(item, index) in tableStore.table.column'
:field='item.field'
:title='item.title'
:key='index'
:min-width='item.width'
show-overflow
align='center'
>
<Column <Column
:attr="item" :attr='child'
:key="key + '-column'" :key="key + '-column'"
v-for="(item, key) in tableStore.table.column" v-for='(child, key) in item.children'
:tree-node='item.treeNode' :tree-node='child.treeNode'
> >
<!-- tableStore 预设的列 render 方案 --> <!-- tableStore 预设的列 render 方案 -->
<template v-if="item.render" #default="scope"> <template v-if='child.render' #default='scope'>
<FieldRender <FieldRender
:field="item" :field='child'
:row="scope.row" :row='scope.row'
:column="scope.column" :column='scope.column'
:index="scope.rowIndex" :index='scope.rowIndex'
:key=" :key='child.field+scope.rowIndex'
key +
'-' +
scope.rowIndex +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
"
/> />
</template> </template>
</Column> </Column>
</vxe-table-colgroup>
</template>
<template v-else>
<Column
:attr='item'
:key="key + '-column'"
v-for='(item, key) in tableStore.table.column'
:tree-node='item.treeNode'
>
<!-- tableStore 预设的列 render 方案 -->
<template v-if='item.render' #default='scope'>
<FieldRender
:field='item'
:row='scope.row'
:column='scope.column'
:index='scope.rowIndex'
:key='item.field+scope.rowIndex'
/>
</template>
</Column>
</template>
</vxe-table> </vxe-table>
<div v-if="props.pagination" class="table-pagination"> <div v-if='props.pagination' class='table-pagination'>
<el-pagination <el-pagination
:currentPage="tableStore.table.params!.pageNum" :currentPage='tableStore.table.params!.pageNum'
:page-size="tableStore.table.params!.pageSize" :page-size='tableStore.table.params!.pageSize'
:page-sizes="pageSizes" :page-sizes='pageSizes'
background 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" @current-change='onTableCurrentChange'
></el-pagination> ></el-pagination>
</div> </div>
<slot name="footer"></slot> <slot name='footer'></slot>
</template> </template>
<script setup lang="ts"> <script setup lang='ts'>
import { ref, nextTick, inject, computed } from 'vue' import { ref, nextTick, inject, computed } from 'vue'
import type { ElTable, TableInstance } from 'element-plus' import type { ElTable, TableInstance } from 'element-plus'
import FieldRender from '@/components/table/fieldRender/index.vue' import FieldRender from '@/components/table/fieldRender/index.vue'
@@ -69,9 +96,12 @@ const tableStore = inject('tableStore') as TableStoreClass
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> { interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
pagination?: boolean pagination?: boolean
isGroup?: boolean
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
pagination: true pagination: true,
isGroup: false
}) })
const onTableSizeChange = (val: number) => { const onTableSizeChange = (val: number) => {
@@ -109,16 +139,18 @@ defineExpose({
}) })
</script> </script>
<style scoped lang="scss"> <style scoped lang='scss'>
.ba-data-table :deep(.el-button + .el-button) { .ba-data-table :deep(.el-button + .el-button) {
margin-left: 6px; margin-left: 6px;
} }
.ba-data-table :deep(.table-header-cell) .cell { .ba-data-table :deep(.table-header-cell) .cell {
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.table-pagination { .table-pagination {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ import 'vxe-table/lib/style.css'
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/display.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 '@/styles/index.scss'
import '@/assets/font/iconfont.css' 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-css-var-value('color-primary-light', $primary-light);
@include set-component-css-var('bg-color', $bg-color); @include set-component-css-var('bg-color', $bg-color);
@include set-component-css-var('border-color', $border-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 { nextTick } from 'vue'
import * as elIcons from '@element-plus/icons-vue' import * as elIcons from '@element-plus/icons-vue'
import { getUrl } from '@/utils/request'
/* /*
* 获取element plus 自带的图标 * 获取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

@@ -10,6 +10,8 @@ interface TableStoreParams {
params?: anyObj params?: anyObj
method?: Method method?: Method
isWebPaging?: boolean // 是否前端分页 isWebPaging?: boolean // 是否前端分页
resetCallback?: () => void
loadCallback?: () => void
} }
export default class TableStore { export default class TableStore {
@@ -29,7 +31,9 @@ export default class TableStore {
pageSize: 20 pageSize: 20
}, },
loading: true, loading: true,
column: [] column: [],
loadCallback: null,
resetCallback: null
}) })
constructor(public options: TableStoreParams) { constructor(public options: TableStoreParams) {
@@ -38,6 +42,8 @@ export default class TableStore {
this.isWebPaging = options.isWebPaging || false this.isWebPaging = options.isWebPaging || false
this.method = options.method || 'GET' this.method = options.method || 'GET'
this.table.column = options.column this.table.column = options.column
this.table.resetCallback = options.resetCallback || null
this.table.loadCallback = options.loadCallback || null
Object.assign(this.table.params, options.params) Object.assign(this.table.params, options.params)
} }
@@ -61,6 +67,7 @@ export default class TableStore {
this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize) this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize)
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1] this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
} }
this.table.loadCallback && this.table.loadCallback()
this.table.loading = false this.table.loading = false
}) })
} }
@@ -85,6 +92,7 @@ export default class TableStore {
delete this.initData.pageSize delete this.initData.pageSize
Object.assign(this.table.params, this.initData) Object.assign(this.table.params, this.initData)
this.index() this.index()
this.table.resetCallback && this.table.resetCallback()
} }
], ],
[ [

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class='default-main'> <div class='default-main'>
<TableHeader date-picker> <TableHeader date-picker :showOperation='false'>
<template v-slot:select> <template v-slot:select>
<el-form-item label='区域'> <el-form-item label='区域'>
<Area v-model='tableStore.table.params.deptIndex' /> <Area v-model='tableStore.table.params.deptIndex' />
</el-form-item> </el-form-item>
<el-form-item label='终端状态'> <el-form-item label='终端状态'>
<el-select v-model='tableStore.table.params.runFlag' <el-select multiple clearable collapse-tags v-model='tableStore.table.params.runFlag'
placeholder='请选择'> placeholder='请选择'>
<el-option label='投运' value='0' /> <el-option label='投运' value='0' />
<el-option label='热备用' value='1' /> <el-option label='热备用' value='1' />
@@ -14,16 +14,15 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label='通讯状态'> <el-form-item label='通讯状态'>
<el-select v-model='tableStore.table.params.comFlag' <el-select multiple clearable collapse-tags v-model='tableStore.table.params.comFlag'
placeholder='请选择'> placeholder='请选择'>
<el-option label='正常' value='1' /> <el-option label='正常' value='1' />
<el-option label='中断' value='0' /> <el-option label='中断' value='0' />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label='厂家'> <el-form-item label='厂家'>
<el-select v-model='tableStore.table.params.manufacturer' <el-select multiple clearable collapse-tags v-model='manufacturerForm' placeholder='请选择'
placeholder='请选择' @change='onManufacturerChange'>
>
<el-option <el-option
v-for='item in manufacturer' v-for='item in manufacturer'
:key='item.id' :key='item.id'
@@ -33,7 +32,8 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label='筛选数据'> <el-form-item label='筛选数据'>
<el-input v-model='tableStore.table.params.searchValue' placeholder='请输入' /> <el-input v-model='tableStore.table.params.searchValue'
placeholder='根据变电站,终端编号,型号或网络参数查询' style='width:300px' />
</el-form-item> </el-form-item>
</template> </template>
</TableHeader> </TableHeader>
@@ -41,7 +41,7 @@
</div> </div>
</template> </template>
<script setup lang='tsx'> <script setup lang='tsx'>
import { ref, onMounted, provide } from 'vue' import { ref, onMounted, provide, reactive } from 'vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
@@ -53,6 +53,7 @@ defineOptions({
}) })
const dictData = useDictData() const dictData = useDictData()
const manufacturer = dictData.getBasicData('Dev_Manufacturers') const manufacturer = dictData.getBasicData('Dev_Manufacturers')
const manufacturerForm = ref<string[]>([])
const tableStore = new TableStore({ const tableStore = new TableStore({
isWebPaging: true, isWebPaging: true,
url: '/device-boot/runManage/getRuntimeData', url: '/device-boot/runManage/getRuntimeData',
@@ -101,12 +102,17 @@ const tableStore = new TableStore({
} }
} }
} }
] ],
resetCallback: () => {
manufacturerForm.value = []
}
}) })
tableStore.table.params.deptIndex = '5699e5916a18a6381e1ac92da5bd2628' tableStore.table.params.deptIndex = dictData.state.area[0].id
tableStore.table.params.runFlag = [] tableStore.table.params.runFlag = []
tableStore.table.params.comFlag = [] tableStore.table.params.comFlag = []
tableStore.table.params.manufacturer = [] tableStore.table.params.manufacturer = []
tableStore.table.params.statisticalType = {}
tableStore.table.params.serverName = 'event-boot'
tableStore.table.params.searchValue = '' tableStore.table.params.searchValue = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
@@ -114,6 +120,15 @@ onMounted(() => {
tableStore.index() tableStore.index()
}) })
const addMenu = () => { const onManufacturerChange = () => {
tableStore.table.params.manufacturer = manufacturer.filter(item => {
return manufacturerForm.value.includes(item.id)
}).map(item => {
return {
...item,
label: item.name,
value: item.id
}
})
} }
</script> </script>

View File

@@ -0,0 +1,232 @@
<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 multiple clearable collapse-tags v-model='interferenceSourceForm' placeholder='请选择'
@change='onLoadTypeChange'>
<el-option
v-for='item in interferenceSource'
:key='item.id'
:label='item.name'
:value='item.id'
/>
</el-select>
</el-form-item>
<el-form-item label='电压等级'>
<el-select multiple clearable collapse-tags v-model='scaleForm' placeholder='请选择'
@change='onScaleChange'
>
<el-option
v-for='item in level'
:key='item.id'
:label='item.name'
:value='item.id'
/>
</el-select>
</el-form-item>
<el-form-item label='通讯状态'>
<el-select multiple clearable collapse-tags v-model='tableStore.table.params.comFlag'
placeholder='请选择'>
<el-option label='正常' value='1' />
<el-option label='中断' value='0' />
</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 isGroup 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 interferenceSource = dictData.getBasicData('Interference_Source')
const level = dictData.getBasicData('Dev_Voltage_Stand')
const interferenceSourceForm = ref<string[]>([])
const scaleForm = ref<string[]>([])
const tableStore = new TableStore({
isWebPaging: true,
url: '/device-boot/runManage/getLineLedger',
method: 'POST',
column: [
{ field: 'areaName', title: '省公司', width: 120 },
{ field: 'gdName', title: '市公司', width: 120 },
{ field: 'scale', title: '监测点电压等级', width: 150 },
{ field: 'lineName', title: '监测点名称', width: 120 },
{ field: 'bdName', title: '所属变电站', width: 120 },
{ field: 'loadType', title: '干扰源类型', width: 120 },
{ field: 'objName', title: '监测对象名称', width: 180 },
{
field: 'shortCapacity', title: '最小短路容量(MVA)', width: 190
},
{
field: 'devCapacity', title: '供电设备容量(MVA )', width: 190
},
{
field: 'dealCapacity', title: '用户协议容量(MVA)', width: 190
},
{ field: 'comFlag', title: '通讯状态 ', width: 120 },
{ field: 'id', title: '监测点序号', width: 120 },
{ field: 'devName', title: '监测终端编号 ', width: 140 },
{ field: 'ptType', title: '监测终端接线方式', width: 160 },
{
field: 'voltageDev', title: '电压偏差上限(%)', width: 160
},
{
field: 'uvoltageDev', title: '电压偏差下限(%)', width: 160
},
{
field: 'limitValue',
title: '限值',
children: [{ field: 'freqDev', title: '频率(Hz)', width: 120 }, {
field: 'ubalance',
title: '三相电压不平衡度(%)',
width: 190
}, { field: 'ineg', title: '负序电流(A)', width: 120 }, {
field: 'flicker',
title: '长时间闪变',
width: 120
}, {
field: 'uaberrance', title: '电压总谐波畸变率(%)', width: 190
},
{
field: 'oddHarm',
title: '奇数次谐波电压(%)',
width: 180
},
{
field: 'evenHarm',
title: '偶数次谐波电压(%)',
width: 180
}
]
},
{
field: 'evaluate',
title: '电流限值',
children: [
{ field: 'iharm2', title: '2次谐波(A)', width: 120 },
{ field: 'iharm3', title: '3次谐波(A)', width: 120 },
{ field: 'iharm4', title: '4次谐波(A)', width: 120 },
{ field: 'iharm5', title: '5次谐波(A)', width: 120 },
{ field: 'iharm6', title: '6次谐波(A)', width: 120 },
{ field: 'iharm7', title: '7次谐波(A)', width: 120 },
{ field: 'iharm8', title: '8次谐波(A)', width: 120 },
{ field: 'iharm9', title: '9次谐波(A)', width: 120 },
{ field: 'iharm10', title: '10次谐波(A)', width: 140 },
{
field: 'iharm11', title: '11次谐波(A)', width: 140
},
{
field: 'iharm12', title: '12次谐波(A)', width: 140
},
{
field: 'iharm13', title: '13次谐波(A)', width: 140
},
{
field: 'iharm14', title: '14次谐波(A)', width: 140
},
{
field: 'iharm15', title: '15次谐波(A)', width: 140
},
{
field: 'iharm16', title: '16次谐波(A)', width: 140
},
{
field: 'iharm17', title: '17次谐波(A)', width: 140
},
{
field: 'iharm18', title: '18次谐波(A)', width: 140
},
{
field: 'iharm19', title: '19次谐波(A)', width: 140
},
{
field: 'iharm10', title: '20次谐波(A)', width: 140
},
{
field: 'iharm21', title: '21次谐波(A)', width: 140
},
{
field: 'iharm22', title: '22次谐波(A)', width: 140
},
{
field: 'iharm23', title: '23次谐波(A)', width: 140
},
{
field: 'iharm24', title: '24次谐波(A)', width: 140
},
{
field: 'iharm25', title: '25次谐波(A)', width: 140
},
{
field: 'inUharm', title: '0.5-1.5次间谐波(A)', width: 180
},
{
field: 'inUharm16', title: '2.5-15.5次间谐波(A)', width: 190
}
]
}
],
resetCallback: () => {
interferenceSourceForm.value = []
scaleForm.value = []
}
})
tableStore.table.params.deptIndex = dictData.state.area[0].id
tableStore.table.params.scale = []
tableStore.table.params.comFlag = []
tableStore.table.params.loadType = []
tableStore.table.params.statisticalType = {}
tableStore.table.params.serverName = 'event-boot'
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore)
onMounted(() => {
tableStore.index()
})
const onLoadTypeChange = () => {
tableStore.table.params.loadType = interferenceSource.filter(item => {
return interferenceSourceForm.value.includes(item.id)
}).map(item => {
return {
...item,
label: item.name,
value: item.id
}
})
}
const onScaleChange = () => {
tableStore.table.params.scale = level.filter(item => {
return scaleForm.value.includes(item.id)
}).map(item => {
return {
...item,
label: item.name,
value: item.id
}
})
}
</script>

3
types/table.d.ts vendored
View File

@@ -23,6 +23,8 @@ declare global {
pageSize: number pageSize: number
[key: string]: any [key: string]: any
} }
loadCallback: (() => void )| null
resetCallback: (() => void)| null
} }
/* 表格行 */ /* 表格行 */
@@ -65,6 +67,7 @@ declare global {
column: VxeColumnProps, column: VxeColumnProps,
index: number index: number
) => string ) => string
children?: TableColumn[]
} }
/* 表格右侧操作按钮 */ /* 表格右侧操作按钮 */