first
This commit is contained in:
136
src/views/auth/audit/index.vue
Normal file
136
src/views/auth/audit/index.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<div class="custom-table-header">
|
||||
<div class="title">待审核用户</div>
|
||||
<el-button :icon="Check" type="primary" @click="addRole" class="ml10">审核通过</el-button>
|
||||
</div>
|
||||
<Table ref="tableRef" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Check } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { checkUser } from '@/api/user-boot/user'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/audit'
|
||||
})
|
||||
const tableStore = new TableStore({
|
||||
showPage: false,
|
||||
method: 'POST',
|
||||
url: '/user-boot/user/checkUserList',
|
||||
column: [
|
||||
// { width: '60', type: 'checkbox' },
|
||||
{ title: '名称', field: 'name' },
|
||||
{ title: '登录名', field: 'loginName' },
|
||||
{ title: '角色', field: 'roleName' },
|
||||
{ title: '部门', field: 'deptId' },
|
||||
{ title: '电话', field: 'phoneShow' },
|
||||
{ title: '注册时间', field: 'registerTime' },
|
||||
{ title: '类型', field: 'casualUserName' },
|
||||
{ title: '状态', field: 'stateName' },
|
||||
{
|
||||
title: '操作',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
buttons: [
|
||||
{
|
||||
name: 'edit',
|
||||
title: '审核通过',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-Check',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
checkUser([row.id]).then(res => {
|
||||
tableStore.index()
|
||||
ElMessage.success('操作成功')
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'del',
|
||||
title: '审核不通过',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Close',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定不通过该角色吗?'
|
||||
},
|
||||
click: row => {
|
||||
ElMessage.warning('功能尚未实现')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
loadCallback: () => {
|
||||
tableStore.table.data.forEach((item: any) => {
|
||||
item.deptId = item.deptId || '/'
|
||||
item.phoneShow = item.phone || '/'
|
||||
item.roleName = item.role.length ? item.role : '/'
|
||||
switch (item.casualUser) {
|
||||
case 0:
|
||||
item.casualUserName = '临时用户'
|
||||
break
|
||||
case 1:
|
||||
item.casualUserName = '长期用户'
|
||||
break
|
||||
default:
|
||||
item.casualUserName = '/'
|
||||
break
|
||||
}
|
||||
switch (item.state) {
|
||||
case 0:
|
||||
item.stateName = '注销'
|
||||
break
|
||||
case 1:
|
||||
item.stateName = '正常'
|
||||
break
|
||||
case 2:
|
||||
item.stateName = '锁定'
|
||||
break
|
||||
case 3:
|
||||
item.stateName = '待审核'
|
||||
break
|
||||
case 4:
|
||||
item.stateName = '休眠'
|
||||
break
|
||||
case 5:
|
||||
item.stateName = '密码过期'
|
||||
break
|
||||
default:
|
||||
item.stateName = '/'
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
tableStore.table.params.casualUser = 0
|
||||
tableStore.table.params.searchState = 0
|
||||
tableStore.table.params.searchValue = ''
|
||||
tableStore.table.params.searchBeginTime = ''
|
||||
tableStore.table.params.searchEndTime = ''
|
||||
tableStore.table.params.sortBy = ''
|
||||
tableStore.table.params.orderBy = ''
|
||||
provide('tableStore', tableStore)
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
|
||||
const addRole = () => {
|
||||
if (!tableStore.table.selection.length) {
|
||||
ElMessage.warning('请选择用户')
|
||||
return
|
||||
}
|
||||
checkUser(tableStore.table.selection.map((item: any) => item.id)).then(res => {
|
||||
tableStore.index()
|
||||
ElMessage.success('操作成功')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
115
src/views/auth/menu/api.vue
Normal file
115
src/views/auth/menu/api.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="custom-table-header">
|
||||
<div class="title">接口权限列表</div>
|
||||
<el-input
|
||||
v-model="tableStore.table.params.searchValue"
|
||||
style="width: 240px"
|
||||
placeholder="请输入菜单名称"
|
||||
class="ml10"
|
||||
clearable
|
||||
@input="search"
|
||||
/>
|
||||
<el-button :icon="Plus" type="primary" @click="addMenu" class="ml10" :disabled="!props.id">新增</el-button>
|
||||
</div>
|
||||
<Table ref="tableRef" />
|
||||
<popupApi ref="popupRef" @init="tableStore.index()"></popupApi>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, Ref, inject, provide, watch } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import popupApi from './popupApi.vue'
|
||||
import { deleteMenu } from '@/api/user-boot/function'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/menu/api'
|
||||
})
|
||||
const emits = defineEmits<{
|
||||
(e: 'init'): void
|
||||
}>()
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const tableRef = ref()
|
||||
const popupRef = ref()
|
||||
const apiList = ref([])
|
||||
const tableStore = new TableStore({
|
||||
showPage: false,
|
||||
url: '/user-boot/function/getButtonById',
|
||||
column: [
|
||||
{ title: '普通接口/接口名称', field: 'name' },
|
||||
{ title: '接口类型', field: 'type' },
|
||||
{ title: 'URL接口路径', field: 'path' },
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
buttons: [
|
||||
{
|
||||
name: 'edit',
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupRef.value.open('编辑接口权限', row)
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'del',
|
||||
title: '删除',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Delete',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定删除该菜单吗?'
|
||||
},
|
||||
click: row => {
|
||||
deleteMenu(row.id).then(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
loadCallback: () => {
|
||||
apiList.value = tableStore.table.data
|
||||
search()
|
||||
}
|
||||
})
|
||||
tableStore.table.loading = false
|
||||
watch(
|
||||
() => props.id,
|
||||
() => {
|
||||
tableStore.table.params.id = props.id
|
||||
tableStore.index()
|
||||
}
|
||||
)
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
const addMenu = () => {
|
||||
console.log(popupRef)
|
||||
popupRef.value.open('新增接口权限', {
|
||||
pid: props.id
|
||||
})
|
||||
}
|
||||
const search = () => {
|
||||
tableStore.table.data = apiList.value.filter(
|
||||
(item: any) =>
|
||||
!tableStore.table.params.searchValue ||
|
||||
item.name.indexOf(tableStore.table.params.searchValue) !== -1 ||
|
||||
item.path.indexOf(tableStore.table.params.searchValue) !== -1
|
||||
)
|
||||
}
|
||||
</script>
|
||||
38
src/views/auth/menu/index.vue
Normal file
38
src/views/auth/menu/index.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class='default-main' style='display: flex' v-loading='loading'>
|
||||
<Menu style='width: 500px' @init='init' @select='select' :menu-data='menuData' />
|
||||
<Api style='width: calc(100% - 500px)' @init='init' :id='selectedId' />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang='ts'>
|
||||
import { functionTree } from '@/api/user-boot/function'
|
||||
import Menu from './menu.vue'
|
||||
import Api from './api.vue'
|
||||
import { provide, reactive, ref } from 'vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/menu'
|
||||
})
|
||||
const menuData = ref<any[]>([])
|
||||
const selectedId = ref('')
|
||||
const loading = ref(true)
|
||||
const select = (id: string) => {
|
||||
selectedId.value = id
|
||||
}
|
||||
const filterData = (arr: any[]) => {
|
||||
return arr.filter((item: any) => {
|
||||
if (item.children.length) {
|
||||
item.children = filterData(item.children)
|
||||
}
|
||||
return item.type === 0
|
||||
})
|
||||
}
|
||||
const init = () => {
|
||||
loading.value = true
|
||||
functionTree().then(res => {
|
||||
menuData.value = filterData(res.data)
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
init()
|
||||
</script>
|
||||
146
src/views/auth/menu/menu.vue
Normal file
146
src/views/auth/menu/menu.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="custom-table-header">
|
||||
<div class="title">菜单列表</div>
|
||||
<el-input
|
||||
v-model="tableStore.table.params.searchValue"
|
||||
style="width: 240px"
|
||||
placeholder="请输入菜单名称"
|
||||
class="ml10"
|
||||
clearable
|
||||
@input="search"
|
||||
/>
|
||||
<el-button :icon="Plus" type="primary" @click="addMenu" class="ml10">新增</el-button>
|
||||
</div>
|
||||
<Table @currentChange="currentChange" />
|
||||
<popupMenu ref="popupRef" @init="emits('init')"></popupMenu>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, nextTick, inject, provide, watch } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import popupMenu from './popupMenu.vue'
|
||||
import { delMenu } from '@/api/systerm'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/menu/menu'
|
||||
})
|
||||
const emits = defineEmits<{
|
||||
(e: 'init'): void
|
||||
(e: 'select', row: any): void
|
||||
}>()
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
menuData: treeData[]
|
||||
}>(),
|
||||
{
|
||||
menuData: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
)
|
||||
const popupRef = ref()
|
||||
const tableStore = new TableStore({
|
||||
showPage: false,
|
||||
url: '/user-boot/function/functionTree',
|
||||
column: [
|
||||
{ title: '菜单名称', field: 'title', align: 'left', treeNode: true },
|
||||
{
|
||||
title: '图标',
|
||||
field: 'icon',
|
||||
align: 'center',
|
||||
width: '60',
|
||||
render: 'icon'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
buttons: [
|
||||
{
|
||||
name: 'edit',
|
||||
text: '新增',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-Plus',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupRef.value.open('新增菜单', { pid: row.id })
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
text: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupRef.value.open('编辑菜单', row)
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'del',
|
||||
text: '删除',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Delete',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定删除该菜单吗?'
|
||||
},
|
||||
click: row => {
|
||||
delMenu(row.id).then(() => {
|
||||
emits('init')
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
tableStore.table.loading = false
|
||||
watch(
|
||||
() => props.menuData,
|
||||
() => {
|
||||
search()
|
||||
}
|
||||
)
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
const addMenu = () => {
|
||||
console.log(popupRef)
|
||||
popupRef.value.open('新增菜单', {})
|
||||
}
|
||||
const currentChange = (newValue: any) => {
|
||||
emits('select', newValue.row.id)
|
||||
}
|
||||
const search = () => {
|
||||
tableStore.table.data = filterData(JSON.parse(JSON.stringify(props.menuData)))
|
||||
if (tableStore.table.params.searchValue) {
|
||||
nextTick(() => {
|
||||
tableStore.table.ref?.setAllTreeExpand(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤
|
||||
const filterData = (arr: treeData[]): treeData[] => {
|
||||
if (!tableStore.table.params.searchValue) {
|
||||
return arr
|
||||
}
|
||||
return arr.filter((item: treeData) => {
|
||||
if (item.title.includes(tableStore.table.params.searchValue)) {
|
||||
return true
|
||||
} else if (item.children?.length > 0) {
|
||||
item.children = filterData(item.children)
|
||||
return item.children.length > 0
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
103
src/views/auth/menu/popupApi.vue
Normal file
103
src/views/auth/menu/popupApi.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
|
||||
<el-scrollbar>
|
||||
<el-form :mode="form" :inline="false" :model="form" label-width="120px" :rules="rules">
|
||||
<el-form-item prop="name" label="接口/按钮名称">
|
||||
<el-input v-model="form.name" placeholder="请输入接口名称" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" label="接口/按钮标识">
|
||||
<el-input v-model="form.code" placeholder="请输入英文接口标识" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="path" label="接口路径">
|
||||
<el-input v-model="form.path" placeholder="请输入接口路径" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="type" label="接口类型">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio :label="1">普通接口</el-radio>
|
||||
<el-radio :label="2">公用接口</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item prop="sort" label="排序">
|
||||
<el-input-number v-model="form.sort" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="remark" label="接口/按钮描述">
|
||||
<el-input v-model="form.remark" :rows="2" type="textarea" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import { update, add } from '@/api/user-boot/function'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/menu/popupApi'
|
||||
})
|
||||
const emits = defineEmits<{
|
||||
(e: 'init'): void
|
||||
}>()
|
||||
const form: any = reactive({
|
||||
id: '',
|
||||
pid: '0',
|
||||
code: '',
|
||||
name: '',
|
||||
path: '',
|
||||
type: 1,
|
||||
sort: 100,
|
||||
remark: ''
|
||||
})
|
||||
const rules = {
|
||||
code: [
|
||||
{ required: true, message: '标识不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-zA-Z_]{1}[a-zA-Z0-9_]{2,15}$/,
|
||||
message: '请输入至少3-20位英文',
|
||||
min: 3,
|
||||
max: 20,
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
name: [{ required: true, message: '请输入接口名称', trigger: 'blur' }],
|
||||
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
|
||||
path: [{ required: true, message: '请输入接口路径', trigger: 'blur' }]
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增菜单')
|
||||
const open = (text: string, data: anyObj) => {
|
||||
title.value = text
|
||||
// 重置表单
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
form.type = 1
|
||||
form.pid = data.pid
|
||||
if (data.id) {
|
||||
for (let key in form) {
|
||||
form[key] = data[key] || ''
|
||||
}
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submit = async () => {
|
||||
if (form.id) {
|
||||
await update(form)
|
||||
} else {
|
||||
let obj = JSON.parse(JSON.stringify(form))
|
||||
delete obj.id
|
||||
await add(obj)
|
||||
}
|
||||
emits('init')
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
111
src/views/auth/menu/popupMenu.vue
Normal file
111
src/views/auth/menu/popupMenu.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
|
||||
<el-scrollbar>
|
||||
<el-form :inline="false" :model="form" label-width="120px">
|
||||
<el-form-item label="上级菜单">
|
||||
<el-cascader
|
||||
v-model="form.pid"
|
||||
:options="tableStore.table.data"
|
||||
:props="cascaderProps"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单名称">
|
||||
<el-input v-model="form.name" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图标">
|
||||
<IconSelector v-model="form.icon" placeholder="请选择图标" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单路由">
|
||||
<el-input v-model="form.path" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="组件路径">
|
||||
<el-input v-model="form.routeName" placeholder="请输入组件路径,如/src/views/dashboard/index.vue" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序">
|
||||
<el-input-number v-model="form.sort" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单描述">
|
||||
<el-input v-model="form.remark" :rows="2" type="textarea" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import IconSelector from '@/components/baInput/components/iconSelector.vue'
|
||||
import { updateMenu, addMenu } from '@/api/systerm'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/menu/popupMenu'
|
||||
})
|
||||
const emits = defineEmits<{
|
||||
(e: 'init'): void
|
||||
}>()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
const cascaderProps = {
|
||||
label: 'title',
|
||||
value: 'id',
|
||||
checkStrictly: true,
|
||||
emitPath: false
|
||||
}
|
||||
const form: any = reactive({
|
||||
code: '',
|
||||
icon: '',
|
||||
id: '',
|
||||
name: '',
|
||||
path: '',
|
||||
pid: '0',
|
||||
remark: '',
|
||||
routeName: '',
|
||||
sort: 100,
|
||||
type: 0
|
||||
})
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增菜单')
|
||||
const open = (text: string, data: anyObj) => {
|
||||
console.log(data)
|
||||
title.value = text
|
||||
// 重置表单
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
form.pid = data.pid || '0'
|
||||
form.sort = 100
|
||||
form.type = 0
|
||||
|
||||
if (data.id) {
|
||||
for (let key in form) {
|
||||
form[key] = data[key] ? data[key] : data[key] === 0 ? 0 : ''
|
||||
}
|
||||
form.path = data.routePath || ''
|
||||
form.name = data.title || ''
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submit = async () => {
|
||||
if (form.id) {
|
||||
await updateMenu(form)
|
||||
} else {
|
||||
form.code = 'menu'
|
||||
let obj = JSON.parse(JSON.stringify(form))
|
||||
delete obj.id
|
||||
await addMenu(obj)
|
||||
}
|
||||
emits('init')
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
162
src/views/auth/role/index.vue
Normal file
162
src/views/auth/role/index.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div class="default-main" style="display: flex" :style="{ height: height }">
|
||||
<div style="flex: 1; overflow: hidden">
|
||||
<div class="custom-table-header">
|
||||
<div class="title">角色列表</div>
|
||||
<el-button :icon="Plus" type="primary" @click="addRole" class="ml10">新增</el-button>
|
||||
</div>
|
||||
<Table ref="tableRef" @currentChange="currentChange" />
|
||||
</div>
|
||||
<Tree
|
||||
v-if="menuListId"
|
||||
ref="treeRef"
|
||||
show-checkbox
|
||||
width="350px"
|
||||
:data="menuTree"
|
||||
:checkStrictly="checkStrictly"
|
||||
@check-change="checkChange"
|
||||
></Tree>
|
||||
<el-empty style="width: 350px; padding-top: 300px; box-sizing: border-box" description="请选择角色" v-else />
|
||||
<PopupForm ref="popupRef"></PopupForm>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import Tree from '@/components/tree/index.vue'
|
||||
import { functionTree } from '@/api/user-boot/function'
|
||||
import { getFunctionsByRoleIndex, updateRoleMenu } from '@/api/user-boot/roleFuction'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import { del } from '@/api/user-boot/role'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import PopupForm from './popupForm.vue'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
defineOptions({
|
||||
name: 'auth/role'
|
||||
})
|
||||
const height = mainHeight(20).height
|
||||
const treeRef = ref()
|
||||
const menuTree = ref<treeData[]>([])
|
||||
const popupRef = ref()
|
||||
const checkStrictly = ref(true)
|
||||
const menuListId = ref('')
|
||||
const tableStore = new TableStore({
|
||||
showPage: false,
|
||||
url: '/user-boot/role/selectRoleDetail?id=' + adminInfo.$state.userType,
|
||||
method: 'POST',
|
||||
column: [
|
||||
{ title: '角色名称', field: 'name', align: 'center' },
|
||||
{ title: '角色编码', field: 'code', align: 'center' },
|
||||
{ title: '备注', field: 'remark', align: 'center' },
|
||||
{
|
||||
title: '状态',
|
||||
field: 'state',
|
||||
width: '80',
|
||||
render: 'tag',
|
||||
custom: {
|
||||
0: 'danger',
|
||||
1: 'success'
|
||||
},
|
||||
replaceValue: {
|
||||
0: '注销',
|
||||
1: '正常'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
buttons: [
|
||||
{
|
||||
name: 'edit',
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupRef.value.open('编辑角色', row)
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'del',
|
||||
title: '删除',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Delete',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定删除该角色吗?'
|
||||
},
|
||||
click: row => {
|
||||
del([row.id]).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
tableStore.index()
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
tableStore.table.params.searchValue = ''
|
||||
|
||||
provide('tableStore', tableStore)
|
||||
const filterData = (arr: any[]) => {
|
||||
// return arr.filter((item: any) => {
|
||||
// item.name = item.title
|
||||
// if (item.children.length) {
|
||||
// item.children = filterData(item.children)
|
||||
// }
|
||||
// return item.type === 0
|
||||
// })
|
||||
arr.forEach((item: any) => {
|
||||
item.name = item.title
|
||||
if (item.children.length) {
|
||||
filterData(item.children)
|
||||
}
|
||||
})
|
||||
}
|
||||
functionTree().then((res: any) => {
|
||||
filterData(res.data)
|
||||
menuTree.value = res.data
|
||||
})
|
||||
|
||||
const currentChange = (data: any) => {
|
||||
checkStrictly.value = true
|
||||
menuListId.value = data.row.id
|
||||
getFunctionsByRoleIndex({ id: data.row.id }).then((res: any) => {
|
||||
treeRef.value.treeRef.setCheckedKeys(res.data.map((item: any) => item.id))
|
||||
})
|
||||
}
|
||||
|
||||
const timeout = ref<NodeJS.Timeout>()
|
||||
const checkChange = (data: any) => {
|
||||
if (checkStrictly.value) {
|
||||
checkStrictly.value = false
|
||||
return
|
||||
}
|
||||
if (timeout.value) {
|
||||
clearTimeout(timeout.value)
|
||||
}
|
||||
timeout.value = setTimeout(() => {
|
||||
updateRoleMenu({
|
||||
id: menuListId.value,
|
||||
idList: treeRef.value.treeRef.getCheckedNodes(false, true).map((node: any) => node.id)
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const addRole = () => {
|
||||
popupRef.value.open('新增角色')
|
||||
}
|
||||
</script>
|
||||
75
src/views/auth/role/popupForm.vue
Normal file
75
src/views/auth/role/popupForm.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
|
||||
<el-scrollbar>
|
||||
<el-form :inline="false" :model="form" label-width="120px" :rules="rules">
|
||||
<el-form-item label="角色名称">
|
||||
<el-input v-model="form.name" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色编码">
|
||||
<el-input v-model="form.code" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色描述">
|
||||
<el-input v-model="form.remark" :rows="2" type="textarea" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { add, update } from '@/api/user-boot/role'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
// do not use same name with ref
|
||||
const form = reactive({
|
||||
code: '',
|
||||
name: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
type: 0
|
||||
})
|
||||
const rules = {
|
||||
name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '角色编码不能为空', trigger: 'blur' }]
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增菜单')
|
||||
const open = (text: string, data?: anyObj) => {
|
||||
title.value = text
|
||||
dialogVisible.value = true
|
||||
if (data) {
|
||||
for (let key in form) {
|
||||
form[key] = data[key]
|
||||
}
|
||||
} else {
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
const submit = async () => {
|
||||
if (form.id) {
|
||||
await update(form)
|
||||
} else {
|
||||
form.type = adminInfo.$state.userType + 1
|
||||
await add(form)
|
||||
}
|
||||
ElMessage.success('保存成功')
|
||||
tableStore.index()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
226
src/views/auth/userList/index.vue
Normal file
226
src/views/auth/userList/index.vue
Normal file
@@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader>
|
||||
<template v-slot:select>
|
||||
<el-form-item label="用户状态">
|
||||
<el-select v-model="tableStore.table.params.searchState" placeholder="选择用户状态">
|
||||
<el-option
|
||||
v-for="(item, index) in userState"
|
||||
:label="item.label"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户类型:">
|
||||
<el-select v-model="tableStore.table.params.casualUser" placeholder="选择用户类型">
|
||||
<el-option
|
||||
v-for="(item, index) in casualUser"
|
||||
:label="item.label"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键词:">
|
||||
<el-input
|
||||
style="width: 240px"
|
||||
v-model="tableStore.table.params.searchValue"
|
||||
clearable
|
||||
placeholder="仅根据用户名/登录名"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-slot:operation>
|
||||
<el-button :icon="Plus" type="primary" @click="addUser">添加</el-button>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<Table ref="tableRef" />
|
||||
<PopupEdit ref="popupEditRef"></PopupEdit>
|
||||
<PopupPwd ref="popupPwdRef"></PopupPwd>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { activateUser, deluser, passwordConfirm } from '@/api/user-boot/user'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import PopupEdit from './popupEdit.vue'
|
||||
import PopupPwd from './popupPwd.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'auth/userlist'
|
||||
})
|
||||
const popupEditRef = ref()
|
||||
const popupPwdRef = ref()
|
||||
const tableStore = new TableStore({
|
||||
url: '/user-boot/user/list',
|
||||
method: 'POST',
|
||||
column: [
|
||||
{ title: '用户名称', field: 'name', minWidth: '130' },
|
||||
{ title: '登录名', field: 'loginName', minWidth: '130' },
|
||||
{ title: '角色', field: 'roleName', minWidth: '130' },
|
||||
{ title: '部门', field: 'deptName', minWidth: '200' },
|
||||
{ title: '电话', field: 'phoneShow', minWidth: '100' },
|
||||
{ title: '注册时间', field: 'registerTime', minWidth: '130' },
|
||||
{ title: '登录时间', field: 'loginTime', minWidth: '130' },
|
||||
{ title: '类型', field: 'casualUserName', minWidth: '80' },
|
||||
{
|
||||
title: '状态',
|
||||
field: 'state',
|
||||
width: '100',
|
||||
render: 'tag',
|
||||
custom: {
|
||||
0: 'danger',
|
||||
1: 'success',
|
||||
2: 'warning',
|
||||
3: 'warning',
|
||||
4: 'info',
|
||||
5: 'danger'
|
||||
},
|
||||
replaceValue: {
|
||||
0: '注销',
|
||||
1: '正常',
|
||||
2: '锁定',
|
||||
3: '待审核',
|
||||
4: '休眠',
|
||||
5: '密码过期'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
fixed: 'right',
|
||||
buttons: [
|
||||
{
|
||||
name: 'edit',
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
disabled: row => {
|
||||
return row.state !== 1
|
||||
},
|
||||
click: row => {
|
||||
popupEditRef.value.open('编辑用户', row)
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
title: '修改密码',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-Lock',
|
||||
render: 'basicButton',
|
||||
disabled: row => {
|
||||
return row.state !== 1
|
||||
},
|
||||
click: row => {
|
||||
ElMessageBox.prompt('二次校验密码确认', '注销用户', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
inputType: 'password'
|
||||
}).then(({ value }) => {
|
||||
passwordConfirm(value).then(res => {
|
||||
popupPwdRef.value.open(row.id)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
title: '激活',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-Open',
|
||||
render: 'basicButton',
|
||||
disabled: row => {
|
||||
return row.state !== 2 && row.state !== 5 && row.state !== 0 && row.state !== 4
|
||||
},
|
||||
click: row => {
|
||||
activateUser({
|
||||
id: row.id
|
||||
}).then(() => {
|
||||
ElMessage.success('激活成功')
|
||||
tableStore.index()
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
title: '注销',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-SwitchButton',
|
||||
render: 'basicButton',
|
||||
disabled: row => {
|
||||
return row.state !== 1 && row.state !== 3
|
||||
},
|
||||
click: row => {
|
||||
ElMessageBox.prompt('二次校验密码确认', '注销用户', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
inputType: 'password'
|
||||
}).then(({ value }) => {
|
||||
passwordConfirm(value).then(res => {
|
||||
deluser({
|
||||
id: row.id
|
||||
}).then(() => {
|
||||
ElMessage.success('注销成功')
|
||||
tableStore.index()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
loadCallback: () => {
|
||||
tableStore.table.data.forEach((item: any) => {
|
||||
item.deptName = item.deptName || '/'
|
||||
item.phoneShow = item.phone || '/'
|
||||
item.roleName = item.role.length ? item.role : '/'
|
||||
switch (item.casualUser) {
|
||||
case 0:
|
||||
item.casualUserName = '临时用户'
|
||||
break
|
||||
case 1:
|
||||
item.casualUserName = '长期用户'
|
||||
break
|
||||
default:
|
||||
item.casualUserName = '/'
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
provide('tableStore', tableStore)
|
||||
tableStore.table.params.searchState = 1
|
||||
tableStore.table.params.casualUser = -1
|
||||
tableStore.table.params.orderBy = ''
|
||||
const userState = [
|
||||
{ label: '全部', value: -1 },
|
||||
{ label: '注销', value: 0 },
|
||||
{ label: '正常', value: 1 },
|
||||
{ label: '锁定', value: 2 },
|
||||
{ label: '待审核', value: 3 },
|
||||
{ label: '休眠', value: 4 },
|
||||
{ label: '密码过期', value: 5 }
|
||||
]
|
||||
const casualUser = [
|
||||
{ label: '全部', value: -1 },
|
||||
{ label: '临时用户', value: 0 },
|
||||
{ label: '长期用户', value: 1 }
|
||||
]
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
|
||||
const addUser = () => {
|
||||
popupEditRef.value.open('新增用户')
|
||||
}
|
||||
</script>
|
||||
267
src/views/auth/userList/popupEdit.vue
Normal file
267
src/views/auth/userList/popupEdit.vue
Normal file
@@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
|
||||
<el-scrollbar>
|
||||
<el-form :inline="true" :model="form" label-width="120px" :rules="rules">
|
||||
<el-form-item label="用户名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入昵称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="登录名" prop="loginName">
|
||||
<el-input v-model="form.loginName" placeholder="请输入登录名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="默认密码" prop="password" v-if="title === '新增用户'">
|
||||
<el-input v-model="form.password" placeholder="请输入密码" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="权限类型" prop="type">
|
||||
<el-select
|
||||
v-model="form.type"
|
||||
@change="changeValue"
|
||||
disabled
|
||||
placeholder="请选择权限类型"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in UserTypeOption"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:key="index"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户类型" prop="casualUser">
|
||||
<el-select v-model="form.casualUser" placeholder="请选择权限类型">
|
||||
<el-option
|
||||
v-for="(item, index) in TypeOptions"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:key="index"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门" prop="deptId">
|
||||
<Area style="width: 100%" v-model="form.deptId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色" prop="role">
|
||||
<el-select v-model="form.role" placeholder="请选择角色" multiple collapse-tags>
|
||||
<el-option
|
||||
v-for="(item, index) in roleOptions"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:key="index"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="起始IP" prop="limitIpStart">
|
||||
<el-input v-model="form.limitIpStart" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束IP" prop="limitIpEnd">
|
||||
<el-input v-model="form.limitIpEnd" placeholder="请输入描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="时间段" prop="limitTime">
|
||||
<el-slider v-model="form.limitTime" range show-stops :max="24" />
|
||||
</el-form-item>
|
||||
<el-form-item label="短信通知" prop="smsNotice">
|
||||
<el-radio-group v-model="form.smsNotice">
|
||||
<el-radio-button :label="0">是</el-radio-button>
|
||||
<el-radio-button :label="1">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮件通知" prop="emailNotice">
|
||||
<el-radio-group v-model="form.emailNotice">
|
||||
<el-radio-button :label="0">是</el-radio-button>
|
||||
<el-radio-button :label="1">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户ID">
|
||||
<div style="display: flex; width: 100%">
|
||||
<el-radio-group v-model="useId">
|
||||
<el-radio-button :label="1">是</el-radio-button>
|
||||
<el-radio-button :label="0">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-input
|
||||
:disabled="title !== '新增用户'"
|
||||
v-model="form.id"
|
||||
placeholder="请输入用户id"
|
||||
v-if="useId"
|
||||
style="flex: 1"
|
||||
class="ml10"
|
||||
></el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ElMessage, FormItemRule } from 'element-plus'
|
||||
import { roleList } from '@/api/user-boot/role'
|
||||
import { add, edit } from '@/api/user-boot/user'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import Area from '@/components/form/area/index.vue'
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
// do not use same name with ref
|
||||
const form = reactive({
|
||||
id: '',
|
||||
name: '',
|
||||
password: '123456',
|
||||
email: '',
|
||||
limitIpStart: '',
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
casualUser: 1,
|
||||
loginName: '',
|
||||
phone: '',
|
||||
limitIpEnd: '',
|
||||
limitTime: [1, 2],
|
||||
role: [],
|
||||
smsNotice: 0,
|
||||
emailNotice: 0,
|
||||
type: 0
|
||||
})
|
||||
const rules:Partial<Record<string, Array<FormItemRule>>> = {
|
||||
name: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
|
||||
role: [{ required: true, message: '角色不能为空', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }],
|
||||
loginName: [{ required: true, message: '登录名不能为空', trigger: 'blur' }],
|
||||
casualUser: [{ required: true, message: '用户类型不能为空', trigger: 'blur' }],
|
||||
smsNotice: [{ required: true, message: '短信通知不能为空', trigger: 'blur' }],
|
||||
emailNotice: [{ required: true, message: '邮件通知不能为空', trigger: 'blur' }],
|
||||
email: [
|
||||
{ required: false, message: '邮箱不能为空', trigger: 'blur' },
|
||||
{
|
||||
type: 'email',
|
||||
message: "'请输入正确的邮箱地址",
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{ required: false, message: '手机号不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||
message: '请输入正确的手机号码',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
limitTime: [{ required: true, message: '时间段不能为空', trigger: 'blur' }],
|
||||
limitIpStart: [
|
||||
{ required: true, message: '起始IP不能为空', trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
let regexp = /^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}$/
|
||||
let isCorrect = regexp.test(value)
|
||||
if (value == '') {
|
||||
return callback(new Error('请输入IP地址'))
|
||||
} else if (!isCorrect) {
|
||||
callback(new Error('请输入正确的IP地址'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
limitIpEnd: [
|
||||
{ required: true, message: '结束IP不能为空', trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
let regexp = /^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}$/
|
||||
let isCorrect = regexp.test(value)
|
||||
if (value == '') {
|
||||
return callback(new Error('请输入IP地址'))
|
||||
} else if (!isCorrect) {
|
||||
callback(new Error('请输入正确的IP地址'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
const UserTypeOption = [
|
||||
{ label: '管理员', value: 1 },
|
||||
{ label: '普通用户', value: 2 }
|
||||
]
|
||||
const TypeOptions = [
|
||||
{ label: '临时用户', value: 0 },
|
||||
{ label: '长期用户', value: 1 }
|
||||
]
|
||||
const useId = ref(1)
|
||||
const roleOptions = ref<treeData>()
|
||||
const queryRole = () => {
|
||||
roleList(adminInfo.$state.userType).then((res: any) => {
|
||||
roleOptions.value = res.data.map((item: any) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
queryRole()
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增菜单')
|
||||
const open = (text: string, data?: anyObj) => {
|
||||
title.value = text
|
||||
dialogVisible.value = true
|
||||
if (data) {
|
||||
for (let key in form) {
|
||||
form[key] = data[key]
|
||||
}
|
||||
form.limitTime = data.limitTime.split('-')
|
||||
form.role = data.roleList
|
||||
} else {
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
form.casualUser = 1
|
||||
form.limitTime = [0, 23]
|
||||
form.role = []
|
||||
form.smsNotice = 0
|
||||
form.emailNotice = 0
|
||||
useId.value = 1
|
||||
form.id = ''
|
||||
form.limitIpStart = '0.0.0.0'
|
||||
form.limitIpEnd = '255.255.255.255'
|
||||
form.password = '123456'
|
||||
}
|
||||
form.type = adminInfo.$state.userType + 1
|
||||
}
|
||||
const submit = async () => {
|
||||
let obj = JSON.parse(JSON.stringify(form))
|
||||
obj.limitTime = obj.limitTime.join('-')
|
||||
delete obj.password
|
||||
if (form.id) {
|
||||
await edit(obj)
|
||||
ElMessage.success('修改成功')
|
||||
} else {
|
||||
form.type = adminInfo.$state.userType + 1
|
||||
await add(obj)
|
||||
ElMessage.success('新增成功')
|
||||
}
|
||||
tableStore.index()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const changeValue = () => {}
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
97
src/views/auth/userList/popupPwd.vue
Normal file
97
src/views/auth/userList/popupPwd.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" title="修改密码">
|
||||
<el-scrollbar>
|
||||
<el-form :inline="false" :model="form" label-width="120px" :rules="rules" ref="formRef">
|
||||
<el-form-item label="新密码" prop="newPwd">
|
||||
<el-input v-model="form.newPwd" type="password" placeholder="请输入新密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPwd">
|
||||
<el-input v-model="form.confirmPwd" type="password" placeholder="请输入确认密码" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { validatePwd } from '@/utils/common'
|
||||
import { passwordConfirm, updatePassword } from '@/api/user-boot/user'
|
||||
import { debug } from 'console'
|
||||
|
||||
const formRef = ref()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
const form = reactive({
|
||||
id: '',
|
||||
newPwd: '',
|
||||
confirmPwd: '',
|
||||
loginName: ''
|
||||
})
|
||||
const rules = {
|
||||
newPwd: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: '长度在 6 到 16 个字符',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{ validator: validatePwd, trigger: 'blur' }
|
||||
],
|
||||
confirmPwd: [
|
||||
{ required: true, message: '请确认密码', trigger: 'blur' },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: '长度在 6 到 16 个字符',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请再次输入密码'))
|
||||
} else if (value !== form.newPwd) {
|
||||
callback(new Error('两次输入密码不一致!'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增菜单')
|
||||
const open = (id: string, loginName: string) => {
|
||||
form.id = id
|
||||
form.loginName = loginName
|
||||
form.newPwd = ''
|
||||
form.confirmPwd = ''
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submit = async () => {
|
||||
formRef.value.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
updatePassword({
|
||||
id: form.id,
|
||||
newPassword: form.newPwd
|
||||
}).then((res: any) => {
|
||||
ElMessage.success('密码修改成功')
|
||||
dialogVisible.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
3
src/views/common/error/404.vue
Normal file
3
src/views/common/error/404.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
404
|
||||
</template>
|
||||
65
src/views/dashboard/index.vue
Normal file
65
src/views/dashboard/index.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker area></TableHeader>
|
||||
<el-tabs v-model="activeName" type="border-card" v-loading="tableStore.table.loading">
|
||||
<el-tab-pane label="图形" name="1">
|
||||
<Echart :list="list" ref="echarts" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表格" name="2"><Tableabove ref="table" /></el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import Area from '@/components/form/area/index.vue'
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import Echart from '@/views/pms/Event-boot/Region/components/echart.vue'
|
||||
import Tableabove from '@/views/pms/Event-boot/Region/components/Tableabove.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { onMounted, reactive, ref, provide } from 'vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
defineOptions({
|
||||
name: 'Region/overview'
|
||||
})
|
||||
const activeName = ref('1')
|
||||
const list = ref([])
|
||||
const echarts = ref()
|
||||
const Picker = ref()
|
||||
const table = ref()
|
||||
const dictData = useDictData()
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/event-boot/areaStatistics/getAreaCalculation',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
loadCallback: () => {
|
||||
list.value = tableStore.table.data
|
||||
echarts.value.Processing(tableStore.table.data.areaStatistics)
|
||||
echarts.value.Grade(tableStore.table.data.voltageStatistics)
|
||||
echarts.value.Relation(tableStore.table.data.monthlyStatistics)
|
||||
table.value.info(tableStore.table.data)
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Type', ['Load_Type'])[3]
|
||||
tableStore.table.params.monitorFlag = 2
|
||||
tableStore.table.params.powerFlag = 2
|
||||
tableStore.table.params.serverName = 'event-boot'
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const layout = mainHeight(123) as any
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bars_w {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
::v-deep(.el-tabs__content) {
|
||||
height: v-bind('layout.height');
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
481
src/views/pms/Event-boot/Region/components/Compatibility.vue
Normal file
481
src/views/pms/Event-boot/Region/components/Compatibility.vue
Normal file
@@ -0,0 +1,481 @@
|
||||
<template>
|
||||
<div class="flex" style="margin: 15px 0">
|
||||
<span style="width: 100px; margin-top: 3px">电压等级:</span>
|
||||
<el-checkbox
|
||||
:indeterminate="isIndeterminate"
|
||||
v-model="checkAll"
|
||||
@change="handleCheckAllChange"
|
||||
style="margin-right: 28px"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group
|
||||
v-model="checkedVoltage"
|
||||
@change="handleCheckedVoltageChange"
|
||||
style="height: 72px; overflow-y: auto"
|
||||
>
|
||||
<el-checkbox v-for="(item, index) in grade" :label="item" :key="index">{{ item.name }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<div class="flex" style="margin: 15px 0">
|
||||
<span style="width: 100px; margin-top: 3px">干扰源类型:</span>
|
||||
<el-checkbox
|
||||
:indeterminate="isIndeterminate1"
|
||||
v-model="checkAll1"
|
||||
@change="handleCheckAllChange1"
|
||||
style="margin-right: 28px"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group
|
||||
v-model="checkedSource"
|
||||
@change="handleCheckedSourceChange"
|
||||
style="height: 72px; overflow-y: auto"
|
||||
>
|
||||
<el-checkbox v-for="(item, index) in type" :label="item" :key="index">{{ item.name }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<div class="flex" style="margin: 15px 0">
|
||||
<span style="width: 100px; line-height: 32px">兼容曲线:</span>
|
||||
<el-radio-group v-model="radio" @change="radioChange">
|
||||
<el-radio label="ITIC">ITIC</el-radio>
|
||||
<el-radio label="F47">F47</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<my-echart class="bars_w" :options="echartList" />
|
||||
|
||||
<vxe-table class="dw" :data="TableData" height="50px" v-bind="defaultAttribute">
|
||||
<vxe-column field="name" title="名称" width="100px"></vxe-column>
|
||||
<vxe-column field="totalEvents" title="事件总数" width="100px"></vxe-column>
|
||||
<vxe-column field="tolerable" title="可容忍" width="100px"></vxe-column>
|
||||
<vxe-column field="Intolerable" title="不可容忍" width="100px"></vxe-column>
|
||||
</vxe-table>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
import { ref, reactive } from 'vue'
|
||||
const dictData = useDictData()
|
||||
const isIndeterminate = ref(false)
|
||||
const isIndeterminate1 = ref(false)
|
||||
const checkAll = ref(true)
|
||||
const checkAll1 = ref(true)
|
||||
const radio = ref('ITIC')
|
||||
const echartList = ref({})
|
||||
const ITIC = ref({})
|
||||
const F47 = ref({})
|
||||
const pointI: any = ref([])
|
||||
const pointIun: any = ref([])
|
||||
const pointF: any = ref([])
|
||||
const pointFun: any = ref([])
|
||||
const datalist: any = ref([])
|
||||
const TableData = ref([
|
||||
{
|
||||
name: '事件个数',
|
||||
totalEvents: '',
|
||||
tolerable: '',
|
||||
Intolerable: ''
|
||||
}
|
||||
])
|
||||
const checkedVoltage: any = ref(ref(dictData.getBasicData('Dev_Voltage_Stand')))
|
||||
const checkedSource: any = ref(dictData.getBasicData('Interference_Source'))
|
||||
const grade = ref(dictData.getBasicData('Dev_Voltage_Stand'))
|
||||
const type = ref(dictData.getBasicData('Interference_Source'))
|
||||
// 电压等级多选
|
||||
const handleCheckedVoltageChange = (val: any) => {
|
||||
const checkedCount = val.length
|
||||
checkAll.value = checkedCount === grade.value.length
|
||||
isIndeterminate.value = checkedCount > 0 && checkedCount < grade.value.length
|
||||
}
|
||||
const handleCheckAllChange = (val: any) => {
|
||||
checkedVoltage.value = val ? grade.value : []
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
// 干扰源类型多选
|
||||
const handleCheckAllChange1 = (val: any) => {
|
||||
checkedSource.value = val ? type.value : []
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
const handleCheckedSourceChange = (val: any) => {
|
||||
const checkedCount = val.length
|
||||
checkAll1.value = checkedCount === type.value.length
|
||||
isIndeterminate1.value = checkedCount > 0 && checkedCount < type.value.length
|
||||
}
|
||||
|
||||
const info = async (list: any) => {
|
||||
datalist.value = []
|
||||
list.forEach((item: any) => {
|
||||
if (item.eventValue < 2 && item.eventValue > 0) {
|
||||
datalist.value.push(item)
|
||||
}
|
||||
})
|
||||
await gongfunction()
|
||||
ITIC.value = {
|
||||
title: {
|
||||
text: 'ITIC曲线'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (a: any) {
|
||||
if (a[0].value[4] == undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
let relVal = ''
|
||||
relVal = "<font style='color:" + "'>供电公司:" + ' ' + ' ' + a[0].value[3] + '</font><br/>'
|
||||
relVal += "<font style='color:" + "'>变电站:" + ' ' + ' ' + a[0].value[4] + '</font><br/>'
|
||||
relVal += "<font style='color:" + "'>发生时刻:" + ' ' + ' ' + a[0].value[2] + '</font><br/>'
|
||||
relVal +=
|
||||
"<font style='color:" +
|
||||
"'>持续时间:" +
|
||||
' ' +
|
||||
' ' +
|
||||
a[0].value[0].toFixed(3) +
|
||||
's</font><br/>'
|
||||
relVal +=
|
||||
"<font style='color:" + "'>特征幅值:" + ' ' + ' ' + a[0].value[1].toFixed(3) + '%</font>'
|
||||
return relVal
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
|
||||
// selectedMode: false,
|
||||
left: '10px'
|
||||
},
|
||||
color: ['#FF8C00', '#00BFFF', 'green', 'red'],
|
||||
xAxis: {
|
||||
type: 'log',
|
||||
min: '0.001',
|
||||
max: '1000',
|
||||
name: 's',
|
||||
splitLine: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
splitNumber: 10,
|
||||
minInterval: 3,
|
||||
name: '%'
|
||||
},
|
||||
dataZoom: {
|
||||
type: null,
|
||||
show: false
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
name: '上限',
|
||||
type: 'line',
|
||||
data: [
|
||||
[0.001, 200],
|
||||
[0.003, 140],
|
||||
[0.003, 120],
|
||||
[0.5, 120],
|
||||
[0.5, 110],
|
||||
[10, 110],
|
||||
[1000, 110]
|
||||
],
|
||||
showSymbol: false,
|
||||
tooltips: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '下限',
|
||||
type: 'line',
|
||||
data: [
|
||||
[0.02, 0],
|
||||
[0.02, 70],
|
||||
[0.5, 70],
|
||||
[0.5, 80],
|
||||
[10, 80],
|
||||
[10, 90],
|
||||
[1000, 90]
|
||||
],
|
||||
showSymbol: false,
|
||||
tooltips: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '可容忍事件',
|
||||
type: 'scatter',
|
||||
symbol: 'circle',
|
||||
data: pointI.value
|
||||
},
|
||||
{
|
||||
name: '不可容忍事件',
|
||||
type: 'scatter',
|
||||
symbol: 'circle',
|
||||
data: pointIun.value
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
F47.value = {
|
||||
title: {
|
||||
text: 'F47曲线'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (a: any) {
|
||||
if (a[0].value[4] == undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
let relVal = ''
|
||||
relVal = "<font style='color:" + "'>供电公司:" + ' ' + ' ' + a[0].value[3] + '</font><br/>'
|
||||
relVal += "<font style='color:" + "'>变电站:" + ' ' + ' ' + a[0].value[4] + '</font><br/>'
|
||||
relVal += "<font style='color:" + "'>发生时刻:" + ' ' + ' ' + a[0].value[2] + '</font><br/>'
|
||||
relVal +=
|
||||
"<font style='color:" +
|
||||
"'>持续时间:" +
|
||||
' ' +
|
||||
' ' +
|
||||
a[0].value[0].toFixed(3) +
|
||||
's</font><br/>'
|
||||
relVal +=
|
||||
"<font style='color:" + "'>特征幅值:" + ' ' + ' ' + a[0].value[1].toFixed(3) + '%</font>'
|
||||
return relVal
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['分割线', '可容忍事件', '不可容忍事件'],
|
||||
// selectedMode: false,
|
||||
left: '10px'
|
||||
},
|
||||
color: ['yellow', 'green', 'red'],
|
||||
xAxis: {
|
||||
type: 'log',
|
||||
min: '0.001',
|
||||
max: '1000',
|
||||
name: 's',
|
||||
splitLine: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
splitNumber: 10,
|
||||
minInterval: 3,
|
||||
name: '%'
|
||||
},
|
||||
dataZoom: {
|
||||
type: null,
|
||||
show: false
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
name: '分割线',
|
||||
type: 'line',
|
||||
data: [
|
||||
[0.05, 0],
|
||||
[0.05, 50],
|
||||
[0.2, 50],
|
||||
[0.2, 70],
|
||||
[0.5, 70],
|
||||
[0.5, 80],
|
||||
[10, 80],
|
||||
[1000, 80]
|
||||
],
|
||||
showSymbol: false,
|
||||
tooltips: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '可容忍事件',
|
||||
type: 'scatter',
|
||||
symbol: 'circle',
|
||||
data: pointF.value
|
||||
},
|
||||
{
|
||||
name: '不可容忍事件',
|
||||
type: 'scatter',
|
||||
symbol: 'circle',
|
||||
data: pointFun.value
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
radioChange(radio.value)
|
||||
}
|
||||
const radioChange = (e: any) => {
|
||||
if (e == 'ITIC') {
|
||||
echartList.value = ITIC.value
|
||||
TableData.value[0].totalEvents = pointI.value.length + pointIun.value.length
|
||||
TableData.value[0].tolerable = pointI.value.length
|
||||
TableData.value[0].Intolerable = pointIun.value.length
|
||||
} else if (e == 'F47') {
|
||||
echartList.value = F47.value
|
||||
TableData.value[0].totalEvents = pointF.value.length + pointFun.value.length
|
||||
TableData.value[0].tolerable = pointF.value.length
|
||||
TableData.value[0].Intolerable = pointFun.value.length
|
||||
}
|
||||
}
|
||||
|
||||
const gongfunction = () => {
|
||||
var standI = 0
|
||||
var unstandI = 0
|
||||
var standF = 0
|
||||
var unstandF = 0
|
||||
pointI.value = []
|
||||
pointIun.value = []
|
||||
pointF.value = []
|
||||
pointFun.value = []
|
||||
var total = 0
|
||||
total = datalist.value.length
|
||||
if (total == 0) {
|
||||
} else {
|
||||
for (var i = 0; i < datalist.value.length; i++) {
|
||||
var point = []
|
||||
var xx = datalist.value[i].persistTime
|
||||
var yy = datalist.value[i].eventValue * 100
|
||||
var time = datalist.value[i].time.replace('T', ' ')
|
||||
var company = datalist.value[i].gdName
|
||||
var substation = datalist.value[i].subName
|
||||
var index = datalist.value[i].lineId
|
||||
var eventId = datalist.value[i].eventId
|
||||
point = [xx, yy, time, company, substation, index, eventId]
|
||||
|
||||
if (xx <= 0.003) {
|
||||
var line = 0
|
||||
line = 230 - 30000 * xx
|
||||
if (yy > line) {
|
||||
unstandI++
|
||||
pointIun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
} else {
|
||||
standI++
|
||||
pointI.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
}
|
||||
} else if (xx <= 0.02) {
|
||||
if (yy > 120) {
|
||||
unstandI++
|
||||
pointIun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
} else {
|
||||
standI++
|
||||
pointI.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
}
|
||||
} else if (xx <= 0.5) {
|
||||
if (yy > 120 || yy < 70) {
|
||||
unstandI++
|
||||
pointIun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
} else {
|
||||
standI++
|
||||
pointI.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
}
|
||||
} else if (xx <= 10) {
|
||||
if (yy > 110 || yy < 80) {
|
||||
unstandI++
|
||||
pointIun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
} else {
|
||||
standI++
|
||||
pointI.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (yy > 110 || yy < 90) {
|
||||
unstandI++
|
||||
pointIun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
} else {
|
||||
standI++
|
||||
pointI.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (xx < 0.05) {
|
||||
standF++
|
||||
pointF.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
} else if (xx < 0.2) {
|
||||
if (yy > 50) {
|
||||
standF++
|
||||
pointF.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
} else {
|
||||
unstandF++
|
||||
pointFun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
}
|
||||
} else if (xx < 0.5) {
|
||||
if (yy > 70) {
|
||||
standF++
|
||||
pointF.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
} else {
|
||||
unstandF++
|
||||
pointFun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (yy > 80) {
|
||||
standF++
|
||||
pointF.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'green' } }
|
||||
})
|
||||
} else {
|
||||
unstandF++
|
||||
pointFun.value.push({
|
||||
value: point,
|
||||
itemStyle: { normal: { color: 'red' } }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ checkedVoltage, checkedSource, info })
|
||||
const layout = mainHeight(390) as any
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.bars_w {
|
||||
height: calc(v-bind('layout.height'));
|
||||
}
|
||||
.dw {
|
||||
position: absolute;
|
||||
top: 210px;
|
||||
right: 70px;
|
||||
}
|
||||
</style>
|
||||
118
src/views/pms/Event-boot/Region/components/Tableabove.vue
Normal file
118
src/views/pms/Event-boot/Region/components/Tableabove.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<span style="font-size: 14px; font-weight: bold">
|
||||
统计区域: 中国   统计时间: 2023-12-01-2023-12-27   统计次数: {{ frequency + '次' }}
|
||||
</span>
|
||||
<el-tabs tab-position="left" class="demo-tabs" style="margin-top: 10px">
|
||||
<el-tab-pane label="区域">
|
||||
<div class="default-main">
|
||||
<vxe-table :data="areaData" v-bind="defaultAttribute" height="auto" auto-resize>
|
||||
<vxe-column
|
||||
v-for="item in tableHeaderAera"
|
||||
:field="item.prop"
|
||||
:title="item.label"
|
||||
:min-width="item.width"
|
||||
:sortable="item.sortable"
|
||||
:formatter="formatter"
|
||||
></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="电压等级">
|
||||
<div class="default-main">
|
||||
<vxe-table :data="levelData" v-bind="defaultAttribute" height="auto" auto-resize>
|
||||
<vxe-column
|
||||
v-for="item in tableHeaderLevel"
|
||||
:field="item.prop"
|
||||
:title="item.label"
|
||||
:min-width="item.width"
|
||||
:sortable="item.sortable"
|
||||
></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="月份">
|
||||
<div class="default-main">
|
||||
<vxe-table :data="shareData" v-bind="defaultAttribute" height="auto" auto-resize>
|
||||
<vxe-column field="month" title="月份" min-width="120px" sortable></vxe-column>
|
||||
<vxe-column field="notAssociated" title="电压暂降次数" sortable></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, defineExpose, computed } from 'vue'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
|
||||
const areaData:any = ref([])
|
||||
const levelData:any = ref([])
|
||||
const shareData:any = ref([])
|
||||
|
||||
const tableHeaderAera = ref<any[]>([
|
||||
{ prop: 'areaName', label: '区域名称', width: '120px' },
|
||||
{ prop: 'monitoringPoints', label: '监测点数', sortable: true },
|
||||
{ prop: 'frequency', label: '电压暂降次数', sortable: true },
|
||||
{ prop: 'sarfi9', label: 'SARFI-90', sortable: true }
|
||||
])
|
||||
const tableHeaderLevel = ref<any[]>([
|
||||
{ prop: 'voltageLevel', label: '电压等级(kV)', width: '150px' },
|
||||
{ prop: 'monitoringPoints', label: '监测点数' },
|
||||
{ prop: 'frequency', label: '电压暂降次数' }
|
||||
])
|
||||
|
||||
const frequency = ref<number>(875)
|
||||
|
||||
const info = (list: any) => {
|
||||
frequency.value = list.areaStatistics.frequencySum
|
||||
areaData.value = [
|
||||
{
|
||||
areaName: '总计',
|
||||
monitoringPoints: list.areaStatistics.monitoringPointSum,
|
||||
frequency: list.areaStatistics.frequencySum,
|
||||
sarfi9: '/'
|
||||
},
|
||||
...list.areaStatistics.areaCalculation
|
||||
]
|
||||
|
||||
levelData.value = [
|
||||
{
|
||||
voltageLevel: '总计',
|
||||
monitoringPoints: list.voltageStatistics.monitoringPointSum,
|
||||
frequency: list.voltageStatistics.frequencySum
|
||||
},
|
||||
...list.voltageStatistics.voltageLevelCalculation
|
||||
]
|
||||
let all = 0
|
||||
list.monthlyStatistics.monthCalculation.forEach((item: any) => {
|
||||
all += item.linked + item.notAssociated
|
||||
})
|
||||
shareData.value = [
|
||||
{
|
||||
month: '总计',
|
||||
notAssociated: all.toFixed(2)
|
||||
},
|
||||
...list.monthlyStatistics.monthCalculation
|
||||
]
|
||||
}
|
||||
const formatter = (row: any) => {
|
||||
if (row.column.field == 'areaName') {
|
||||
return (row.cellValue = row.cellValue.replace('\n', ''))
|
||||
} else {
|
||||
return row.cellValue
|
||||
}
|
||||
}
|
||||
defineExpose({ info })
|
||||
const layout = mainHeight(185) as any
|
||||
const defaultMain = mainHeight(195) as any
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep(.el-tabs--left, ) {
|
||||
height: v-bind('layout.height');
|
||||
}
|
||||
.default-main {
|
||||
height: v-bind('defaultMain.height');
|
||||
}
|
||||
</style>
|
||||
144
src/views/pms/Event-boot/Region/components/TypeStatistics.vue
Normal file
144
src/views/pms/Event-boot/Region/components/TypeStatistics.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<span style="color: red; font-size: 12px">注:暂降类型仅统计暂降原因为短路故障事件</span>
|
||||
|
||||
<div class="statistics-main">
|
||||
<template v-if="flag">
|
||||
<div>
|
||||
<my-echart :options="descent" />
|
||||
</div>
|
||||
<div>
|
||||
<vxe-table height="auto" auto-resize :data="descentData" v-bind="defaultAttribute">
|
||||
<vxe-column field="name" title="暂降原因"></vxe-column>
|
||||
<vxe-column field="value" title="暂降次数"></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
<div>
|
||||
<my-echart :options="resemble" />
|
||||
</div>
|
||||
<div>
|
||||
<vxe-table height="auto" auto-resize :data="resembleData" v-bind="defaultAttribute">
|
||||
<vxe-column field="name" title="暂降原因"></vxe-column>
|
||||
<vxe-column field="value" title="暂降次数"></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
const descent = ref({})
|
||||
const descentData = ref([])
|
||||
const resemble = ref({})
|
||||
const resembleData = ref([])
|
||||
const flag = ref(true)
|
||||
|
||||
const info = (res: any) => {
|
||||
flag.value = false
|
||||
descentData.value = res.reason
|
||||
resembleData.value = res.type
|
||||
|
||||
descent.value = {
|
||||
title: {
|
||||
text: '暂降原因'
|
||||
},
|
||||
legend: {
|
||||
type: 'scroll',
|
||||
orient: 'vertical',
|
||||
left: 10,
|
||||
top: '5%',
|
||||
tooltip: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
show: false
|
||||
},
|
||||
yAxis: {
|
||||
show: false
|
||||
},
|
||||
dataZoom: { show: false },
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c} (次)'
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
name: '暂降原因',
|
||||
type: 'pie',
|
||||
center: ['50%', '50%'],
|
||||
selectedOffset: 30,
|
||||
clockwise: true,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'outside',
|
||||
textStyle: {
|
||||
//数值样式
|
||||
}
|
||||
},
|
||||
|
||||
data: res.reason?.filter((item: any) => item.name != '总计')
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
resemble.value = {
|
||||
title: {
|
||||
text: '暂降类型'
|
||||
},
|
||||
legend: {
|
||||
type: 'scroll',
|
||||
orient: 'vertical',
|
||||
left: 10,
|
||||
top: '5%'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: '{a} <br/>{b} : {c} (次)',
|
||||
confine: true
|
||||
},
|
||||
xAxis: {
|
||||
show: false
|
||||
},
|
||||
yAxis: {
|
||||
show: false
|
||||
},
|
||||
dataZoom: { show: false },
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
name: '暂降类型',
|
||||
type: 'pie',
|
||||
center: ['50%', '50%'],
|
||||
selectedOffset: 30,
|
||||
clockwise: true,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'outside'
|
||||
},
|
||||
|
||||
data: res.type?.filter((item: any) => item.name != '总计')
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
flag.value = true
|
||||
}
|
||||
|
||||
defineExpose({ info })
|
||||
const layout = mainHeight(175) as any
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.statistics-main {
|
||||
box-sizing: border-box;
|
||||
height: v-bind('layout.height');
|
||||
padding: 0 10px 10px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 600px;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
</style>
|
||||
293
src/views/pms/Event-boot/Region/components/echart.vue
Normal file
293
src/views/pms/Event-boot/Region/components/echart.vue
Normal file
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<div>
|
||||
<my-echart class="bars_w" :options="areaStatistics" />
|
||||
<div class="separate">
|
||||
<my-echart class="bars_w" :options="voltageStatistics" />
|
||||
<my-echart class="bars_w" :options="monthlyStatistics" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import { reactive, ref, defineExpose } from 'vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
let areaStatistics = ref({})
|
||||
let voltageStatistics = ref({})
|
||||
let monthlyStatistics = ref({})
|
||||
|
||||
const Processing = (list: any) => {
|
||||
// 区域
|
||||
let echartsndArr: string[] = []
|
||||
let echartsArr: string[] = []
|
||||
list.areaCalculation.forEach((item: any) => {
|
||||
echartsndArr.push(item.areaName)
|
||||
if (item.frequency == 0) {
|
||||
item.frequency = 1.1
|
||||
} else if (item.frequency == 1) {
|
||||
item.frequency = 1.3
|
||||
}
|
||||
echartsArr.push(item.frequency)
|
||||
})
|
||||
areaStatistics.value = {
|
||||
title: {
|
||||
text: '区域'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
let html = '区域:' + params[0].name
|
||||
params.forEach((item: any) => {
|
||||
if (item.value == 1.1) {
|
||||
html += `<br/>${item.seriesName}: ${0}次`
|
||||
} else if (item.value == 1.3) {
|
||||
html += `<br/>${item.seriesName}: ${1}次`
|
||||
} else {
|
||||
html += `<br/>${item.seriesName}: ${item.value}次`
|
||||
}
|
||||
})
|
||||
return html
|
||||
}
|
||||
},
|
||||
|
||||
legend: {
|
||||
data: ['暂降次数']
|
||||
},
|
||||
xAxis: {
|
||||
name: '区域', // 给X轴加单位
|
||||
data: echartsndArr
|
||||
},
|
||||
yAxis: {
|
||||
name: '次数' // 给X轴加单位
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
barMinHeight: 5,
|
||||
barMaxWidth: 30,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
//这里是颜色
|
||||
color: function (params: any) {
|
||||
if (params.data == 1.1) {
|
||||
return '#B3B3B3'
|
||||
} else {
|
||||
return '#07CCCA '
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
name: '暂降次数',
|
||||
type: 'bar',
|
||||
data: echartsArr
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
// 电压等级
|
||||
const Grade = (list: any) => {
|
||||
let echartsndArr: string[] = []
|
||||
let echartsArr: string[] = []
|
||||
list.voltageLevelCalculation.forEach((item: any) => {
|
||||
echartsndArr.push(item.voltageLevel)
|
||||
if (item.frequency == 0) {
|
||||
item.frequency = 1.1
|
||||
} else if (item.frequency == 1) {
|
||||
item.frequency = 1.3
|
||||
}
|
||||
echartsArr.push(item.frequency)
|
||||
})
|
||||
|
||||
voltageStatistics.value = {
|
||||
title: {
|
||||
text: '电压等级'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
let html = '电压等级:' + params[0].name
|
||||
params.forEach((item: any) => {
|
||||
if (item.value == 1.1) {
|
||||
html += `<br/>${item.seriesName}: ${0}次`
|
||||
} else if (item.value == 1.3) {
|
||||
html += `<br/>${item.seriesName}: ${1}次`
|
||||
} else {
|
||||
html += `<br/>${item.seriesName}: ${item.value}次`
|
||||
}
|
||||
})
|
||||
return html
|
||||
}
|
||||
},
|
||||
|
||||
legend: {
|
||||
data: ['暂降次数']
|
||||
},
|
||||
xAxis: {
|
||||
name: '电压等级',
|
||||
data: echartsndArr
|
||||
},
|
||||
yAxis: {
|
||||
name: '次数' // 给X轴加单位
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
//这里是颜色
|
||||
color: function (params: any) {
|
||||
if (params.data == 1.1) {
|
||||
return '#B3B3B3'
|
||||
} else {
|
||||
return '#07CCCA '
|
||||
}
|
||||
}
|
||||
}
|
||||
// color: echartsColor.FigureColor[0],
|
||||
},
|
||||
name: '暂降次数',
|
||||
type: 'bar',
|
||||
data: echartsArr
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
//时间
|
||||
const Relation = (list: any, interval: number) => {
|
||||
let echartsndArr: string[] = []
|
||||
let echartsArr: string[] = []
|
||||
let echartswArr: string[] = []
|
||||
list.monthCalculation.forEach((item: any, i: number) => {
|
||||
if (i != 0) {
|
||||
item.month = item.month.slice(5)
|
||||
} else if (i == 0) {
|
||||
let date = item.month.slice(5)
|
||||
// let t = item.month.slice(0, 4);
|
||||
// item.month = date + "\n" + "(" + t + ")";
|
||||
item.month = date
|
||||
}
|
||||
|
||||
echartsndArr.push(item.month)
|
||||
// if (item.linked == 0 || item.notAssociated == 0) {
|
||||
// item.linked = 3.14159;
|
||||
// item.notAssociated = 3.14159;
|
||||
// }
|
||||
if (item.linked == 0) {
|
||||
item.linked = 1.1
|
||||
} else if (item.linked == 1) {
|
||||
item.linked = 1.3
|
||||
}
|
||||
echartsArr.push(item.linked)
|
||||
if (item.notAssociated == 0) {
|
||||
item.notAssociated = 1.1
|
||||
} else if (item.notAssociated == 1) {
|
||||
item.notAssociated = 1.3
|
||||
}
|
||||
echartswArr.push(item.notAssociated)
|
||||
})
|
||||
monthlyStatistics.value = {
|
||||
title: {
|
||||
text: '时间'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
let html = '时间:' + params[0].name
|
||||
params.forEach((item: any) => {
|
||||
if (item.value == 1.1) {
|
||||
html += `<br/>${item.seriesName}: ${0}次`
|
||||
} else if (item.value == 1.3) {
|
||||
html += `<br/>${item.seriesName}: ${1}次`
|
||||
} else {
|
||||
html += `<br/>${item.seriesName}: ${item.value}次`
|
||||
}
|
||||
})
|
||||
return html
|
||||
}
|
||||
},
|
||||
|
||||
legend: {
|
||||
data: ['未关联暂降次数', '已关联处理事件']
|
||||
},
|
||||
color: ['#07CCCA', '#Ff6600'],
|
||||
xAxis: {
|
||||
name: '月份', // 给X轴加单位
|
||||
data: echartsndArr
|
||||
},
|
||||
yAxis: {
|
||||
name: '次数' // 给X轴加单位
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
name: '未关联暂降次数',
|
||||
type: 'bar',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
data: echartswArr,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
label: {
|
||||
// show: true, //数字开启显示
|
||||
textStyle: {
|
||||
//数值样式
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
fontWeight: 600
|
||||
}
|
||||
},
|
||||
color: function (params: any) {
|
||||
if (params.data == 1.1) {
|
||||
return '#B3B3B3'
|
||||
} else {
|
||||
return '#07CCCA '
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '已关联处理事件',
|
||||
type: 'bar',
|
||||
barMaxWidth: 30,
|
||||
data: echartsArr,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
label: {
|
||||
// show: true, //数字开启显示
|
||||
textStyle: {
|
||||
//数值样式
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
fontWeight: 600
|
||||
}
|
||||
},
|
||||
color: function (params: any) {
|
||||
if (params.data == 1.1) {
|
||||
return '#B3B3B3'
|
||||
} else {
|
||||
return '#Ff6600'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
// Processing()
|
||||
defineExpose({ Processing, Grade, Relation })
|
||||
const layout = mainHeight(150) as any
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bars_w {
|
||||
width: 100%;
|
||||
height: calc(v-bind('layout.height') / 2);
|
||||
}
|
||||
.separate {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
316
src/views/pms/Event-boot/Region/distribution.vue
Normal file
316
src/views/pms/Event-boot/Region/distribution.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader area ref="header">
|
||||
<template v-slot:select>
|
||||
<!-- <el-form-item label="区域">
|
||||
<Area ref="area" v-model="tableStore.table.params.deptIndex" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="统计类型">
|
||||
<el-select
|
||||
v-model="tableStore.table.params.statisticalType"
|
||||
value-key="id"
|
||||
placeholder="请选择统计类型"
|
||||
size="large"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<div v-loading="tableStore.table.loading" class="pr10">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<MyEchartMap
|
||||
ref="EchartMap"
|
||||
:options="echartMapList"
|
||||
class="map"
|
||||
@eliminate="eliminate"
|
||||
@getRegionByRegion="getRegionByRegion"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<my-echart class="tall" :options="echartList" />
|
||||
<div class="tall">
|
||||
<vxe-table height="auto" auto-resize :data="distributionData" v-bind="defaultAttribute">
|
||||
>
|
||||
<vxe-column
|
||||
field="qy"
|
||||
:title="
|
||||
titleA == '电压等级'
|
||||
? '电压等级'
|
||||
: titleA == '终端厂家'
|
||||
? '终端厂家'
|
||||
: titleA == '干扰源类型'
|
||||
? '干扰源类型'
|
||||
: titleA == '电网拓扑'
|
||||
? '区域'
|
||||
: ''
|
||||
"
|
||||
show-overflow-tooltip
|
||||
></vxe-column>
|
||||
<vxe-column field="jcd" title="监测点数(个数)"></vxe-column>
|
||||
<vxe-column field="zc" title="通讯正常(个数)" sortable></vxe-column>
|
||||
<vxe-column field="zd" title="通讯中断(个数)" sortable></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
import MyEchartMap from '@/components/echarts/MyEchartMap.vue'
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
defineOptions({
|
||||
name: 'Region/distribution'
|
||||
})
|
||||
const EchartMap = ref()
|
||||
const dictData = useDictData()
|
||||
const options = dictData.getBasicData('Statistical_Type', ['Report_Type'])
|
||||
const echartMapList:any = ref({})
|
||||
const echartList = ref({})
|
||||
const titleA = ref('')
|
||||
const header = ref()
|
||||
const distributionData: any = ref([])
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/event-boot/area/getAreaLineDetail',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
loadCallback: () => {
|
||||
titleA.value = tableStore.table.params.statisticalType.name
|
||||
header.value.areaRef.change()
|
||||
// 处理地图数据
|
||||
map(tableStore.table.data)
|
||||
tabulation(tableStore.table.data)
|
||||
histogram(tableStore.table.data)
|
||||
EchartMap.value.GetEchar(header.value.areaRef.areaName)
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
// tableStore.table.params.deptIndex = dictData.state.area[0].id
|
||||
tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Type', ['Report_Type'])[0]
|
||||
tableStore.table.params.monitorFlag = 2
|
||||
tableStore.table.params.powerFlag = 2
|
||||
tableStore.table.params.serverName = 'event-boot'
|
||||
|
||||
// 地图点击事件
|
||||
const getRegionByRegion = (list: any) => {
|
||||
tableStore.table.params.deptIndex = list.id
|
||||
tableStore.onTableAction('search', {})
|
||||
}
|
||||
// 消除点
|
||||
const eliminate = (name: string) => {
|
||||
echartMapList.value.options.series = []
|
||||
EchartMap.value.GetEchar(name)
|
||||
}
|
||||
|
||||
// 地图数处理
|
||||
const map = (res: any) => {
|
||||
echartMapList.value = {
|
||||
name: '',
|
||||
title: {
|
||||
text: '监测网分布' //+ "(" + _this.titles + ")",
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
//console.log(params)
|
||||
var tips = ''
|
||||
if (params.value == 0) {
|
||||
tips = "<font style='color: #000'>暂无数据</font><br/>"
|
||||
} else {
|
||||
tips +=
|
||||
"<font style='color: #000'> " +
|
||||
params.name +
|
||||
'</font><br/>区域暂降评估' +
|
||||
"<font style='color: #000'>:" +
|
||||
params.value +
|
||||
'</font><br/>'
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
color: ['green', 'red'],
|
||||
legend: {
|
||||
data: [
|
||||
{
|
||||
name: '正常'
|
||||
},
|
||||
{
|
||||
name: '中断'
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
series: []
|
||||
}
|
||||
}
|
||||
let mapList:any = [[], [], []]
|
||||
if (res.substationDetailVOList != null) {
|
||||
res.substationDetailVOList.forEach((item: any) => {
|
||||
if (item.color == 'green') {
|
||||
mapList[0].push(item)
|
||||
} else if (item.color == 'red') {
|
||||
mapList[1].push(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
mapList.forEach((item:any, ind:number) => {
|
||||
echartMapList.value.options.series.push({
|
||||
type: 'scatter',
|
||||
mapName: 'china',
|
||||
name: ind == 0 ? '正常' : ind == 1 ? '中断' : '变电站',
|
||||
coordinateSystem: 'geo',
|
||||
geoIndex: 0,
|
||||
animation: false, //坐标点是否显示动画
|
||||
roam: true,
|
||||
symbol: 'pin',
|
||||
symbolSize: function () {
|
||||
//坐标点大小
|
||||
return 30
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
data: item.map(function (itemOpt: any) {
|
||||
// console.log(itemOpt);
|
||||
return {
|
||||
name: itemOpt.srbName,
|
||||
value: [
|
||||
parseFloat(itemOpt.coordY), //经度
|
||||
parseFloat(itemOpt.coordX) //维度
|
||||
],
|
||||
|
||||
itemStyle: {
|
||||
//地图区域的多边形
|
||||
normal: {
|
||||
color: itemOpt.color, //坐标点颜色
|
||||
shadowBlur: 0, // 图形阴影的模糊大小
|
||||
shadowOffsetX: 0 // 阴影水平方向上的偏移距离。
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
//仅在 options中最外层的 tooltip.trigger 为 'item'时有效
|
||||
position: 'bottom', //提示框位置,仅在 options中最外层的 tooltip.trigger 为 'item'时有效
|
||||
formatter: function (params: any, ticket: any, callback: any) {
|
||||
var strHtml = '<div>变电站:' + itemOpt.subName + '<br/>' + '监测点:' + itemOpt.srbName
|
||||
|
||||
strHtml += '</div>'
|
||||
return strHtml
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 表格数据处理
|
||||
const tabulation = (res: any) => {
|
||||
distributionData.value = []
|
||||
for (var i = 0; i < res.areaValue.length; i++) {
|
||||
distributionData.value.push({
|
||||
qy: res.areaValue[i][0],
|
||||
jcd: res.areaValue[i][1],
|
||||
zc: res.areaValue[i][2],
|
||||
zd: res.areaValue[i][3]
|
||||
})
|
||||
}
|
||||
}
|
||||
// 柱状图数据处理
|
||||
const histogram = (res: any) => {
|
||||
echartList.value = {
|
||||
title: {
|
||||
text:
|
||||
titleA.value == '电压等级'
|
||||
? '电压等级'
|
||||
: titleA.value == '终端厂家'
|
||||
? '终端厂家'
|
||||
: titleA.value == '干扰源类型'
|
||||
? '干扰源类型'
|
||||
: titleA.value == '电网拓扑'
|
||||
? header.value.areaRef.areaName
|
||||
: '' // 给X轴加单位
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
// console.log(params);
|
||||
var tips = ''
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
tips += params[i].name + '</br/>'
|
||||
tips += '监测点数' + ':' + ' ' + ' ' + params[i].value + '</br/>'
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
name:
|
||||
titleA.value == '电压等级'
|
||||
? '(电压\n等级)'
|
||||
: titleA.value == '终端厂家'
|
||||
? '(终端\n厂家)'
|
||||
: titleA.value == '干扰源类型'
|
||||
? '(干扰\n源类型)'
|
||||
: titleA.value == '电网拓扑'
|
||||
? '(区域)'
|
||||
: '', // 给X轴加单位
|
||||
data: distributionData.value.map((item: any) => item.qy)
|
||||
},
|
||||
yAxis: {
|
||||
name: '监测点数(个)' // 给X轴加单位
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
// name: '暂降次数',
|
||||
type: 'bar',
|
||||
data: distributionData.value.map((item: any) => item.jcd),
|
||||
barMaxWidth: 30,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#07CCCA'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
textStyle: {
|
||||
//数值样式
|
||||
color: '#000'
|
||||
},
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const layout = mainHeight(83) as any
|
||||
const layout1 = mainHeight(93) as any
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
height: v-bind('layout.height');
|
||||
}
|
||||
.tall {
|
||||
height: calc(v-bind('layout1.height') / 2);
|
||||
}
|
||||
</style>
|
||||
68
src/views/pms/Event-boot/Region/overview.vue
Normal file
68
src/views/pms/Event-boot/Region/overview.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker area>
|
||||
|
||||
</TableHeader>
|
||||
<el-tabs v-model="activeName" type="border-card" v-loading="tableStore.table.loading">
|
||||
<el-tab-pane label="图形" name="1">
|
||||
<Echart :list="list" ref="echarts" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表格" name="2"><Tableabove ref="table" /></el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import Area from '@/components/form/area/index.vue'
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import Echart from './components/echart.vue'
|
||||
import Tableabove from './components/Tableabove.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { onMounted, reactive, ref, provide } from 'vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
defineOptions({
|
||||
name: 'Region/overview'
|
||||
})
|
||||
const activeName = ref('1')
|
||||
const list = ref([])
|
||||
const echarts = ref()
|
||||
const Picker = ref()
|
||||
const table = ref()
|
||||
const dictData = useDictData()
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/event-boot/areaStatistics/getAreaCalculation',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
loadCallback: () => {
|
||||
list.value = tableStore.table.data
|
||||
echarts.value.Processing(tableStore.table.data.areaStatistics)
|
||||
echarts.value.Grade(tableStore.table.data.voltageStatistics)
|
||||
echarts.value.Relation(tableStore.table.data.monthlyStatistics)
|
||||
table.value.info(tableStore.table.data)
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
|
||||
tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Type', ['Load_Type'])[3]
|
||||
tableStore.table.params.monitorFlag = 2
|
||||
tableStore.table.params.powerFlag = 2
|
||||
tableStore.table.params.serverName = 'event-boot'
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const layout = mainHeight(123) as any
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bars_w {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
::v-deep(.el-tabs__content) {
|
||||
height: v-bind('layout.height');
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
79
src/views/pms/Event-boot/Region/statistics.vue
Normal file
79
src/views/pms/Event-boot/Region/statistics.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker area>
|
||||
<template v-slot:select></template>
|
||||
</TableHeader>
|
||||
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick" v-loading="tableStore.table.loading">
|
||||
<el-tab-pane label="暂降原因及类型统计" name="1">
|
||||
<TypeStatistics ref="Statistics" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="电压容忍度曲线兼容性统计" name="2">
|
||||
<Compatibility ref="compatibility" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { onMounted, reactive, ref, provide } from 'vue'
|
||||
import TypeStatistics from './components/TypeStatistics.vue'
|
||||
import Compatibility from './components/Compatibility.vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
defineOptions({
|
||||
name: 'Region/overview'
|
||||
})
|
||||
const activeName = ref('1')
|
||||
const Statistics = ref()
|
||||
const compatibility = ref()
|
||||
const dictData = useDictData()
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/event-boot/areaAnalysis/getEventReason',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
loadCallback: () => {
|
||||
if (activeName.value == '1') {
|
||||
Statistics.value.info(tableStore.table.data)
|
||||
} else {
|
||||
compatibility.value.info(tableStore.table.data.voltageToleranceCurveDataList)
|
||||
}
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Type', ['Load_Type'])[3]
|
||||
tableStore.table.params.monitorFlag = 2
|
||||
tableStore.table.params.powerFlag = 2
|
||||
tableStore.table.params.serverName = 'event-boot'
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const handleClick = async (e: any) => {
|
||||
if (e.paneName == '1') {
|
||||
tableStore.table.params.scale = null
|
||||
tableStore.table.params.loadType = null
|
||||
tableStore.url = '/event-boot/areaAnalysis/getEventReason'
|
||||
} else {
|
||||
tableStore.table.params.scale = compatibility.value.checkedVoltage
|
||||
tableStore.table.params.loadType = compatibility.value.checkedSource
|
||||
tableStore.url = '/event-boot/areaAnalysis/getVoltageToleranceCurve'
|
||||
}
|
||||
await tableStore.onTableAction('search', {})
|
||||
}
|
||||
const layout = mainHeight(123) as any
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bars_w {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
::v-deep(.el-tabs__content) {
|
||||
height: v-bind('layout.height');
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
354
src/views/pms/Event-boot/Region/thermodynamicDiagram.vue
Normal file
354
src/views/pms/Event-boot/Region/thermodynamicDiagram.vue
Normal file
@@ -0,0 +1,354 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader area date-picker ref="header" />
|
||||
<div v-loading="tableStore.table.loading" class="pr10">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<MyEchartMap
|
||||
ref="EchartMap"
|
||||
:options="echartMapList"
|
||||
class="map"
|
||||
@eliminate="eliminate"
|
||||
@getRegionByRegion="getRegionByRegion"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<my-echart class="tall" :options="echartList" />
|
||||
<div class="tall">
|
||||
<vxe-table height="auto" auto-resize :data="distributionData" v-bind="defaultAttribute">
|
||||
>
|
||||
<vxe-column field="areaName" title=" 区域" show-overflow-tooltip></vxe-column>
|
||||
<vxe-column field="ci" title="区域暂降评估">
|
||||
<template #default="{ row }">
|
||||
{{ row.ci == 0.05 ? '暂无数据' : row.ci.toFixed(2) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column sortable field="isCount" title="等级">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.ci == 0.05">暂无等级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 0.2 && row.ci < 0.4">1级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 0.4 && row.ci < 0.8">2级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 0.8 && row.ci < 1.2">3级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 1.2">4级</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import MyEchartMap from '@/components/echarts/MyEchartMap.vue'
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
defineOptions({
|
||||
name: 'Region/distribution'
|
||||
})
|
||||
const EchartMap = ref()
|
||||
const dictData = useDictData()
|
||||
const echartMapList: any = ref({})
|
||||
const echartList = ref({})
|
||||
const header = ref()
|
||||
const distributionData: any = ref([])
|
||||
const list: any = ref([])
|
||||
const geoCoordMap: any = ref([])
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/event-boot/area/getEventHeatMap',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
beforeSearchFun: () => {},
|
||||
loadCallback: () => {
|
||||
header.value.areaRef.change()
|
||||
// 处理地图数据
|
||||
tableStore.table.data.eventHeatMapValue.forEach(val => {
|
||||
val.forEach(item => {
|
||||
list.value.push(item)
|
||||
geoCoordMap.value.push([item.lng, item.lat, item.tail])
|
||||
})
|
||||
})
|
||||
map(tableStore.table.data)
|
||||
// tabulation(tableStore.table.data)
|
||||
// histogram(tableStore.table.data)
|
||||
EchartMap.value.GetEchar(header.value.areaRef.areaName)
|
||||
}
|
||||
})
|
||||
|
||||
tableStore.table.params.monitorFlag = 2
|
||||
tableStore.table.params.powerFlag = 1
|
||||
tableStore.table.params.reportFlag = 3
|
||||
tableStore.table.params.statFlag = true
|
||||
tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Type', ['Load_Type'])[3]
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
// 地图点击事件
|
||||
const getRegionByRegion = (list: any) => {
|
||||
tableStore.table.params.deptIndex = list.id
|
||||
tableStore.onTableAction('search', {})
|
||||
}
|
||||
// 消除点
|
||||
const eliminate = (name: string) => {
|
||||
echartMapList.value.options.series = []
|
||||
EchartMap.value.GetEchar(name)
|
||||
}
|
||||
|
||||
// 地图数处理
|
||||
const map = (res: any) => {
|
||||
let areaData: any = []
|
||||
|
||||
if (geoCoordMap.value.lengt > 0) {
|
||||
geoCoordMap.value.map(item => {
|
||||
console.log("🚀 ~ map ~ item:", item)
|
||||
areaData.push(...new Array(3).fill(item))
|
||||
})
|
||||
}
|
||||
let maxNum = 0
|
||||
let minNum = 0
|
||||
let num: any = []
|
||||
console.log('🚀 ~ map ~ areaData:', areaData)
|
||||
|
||||
if (areaData.length > 0) {
|
||||
areaData.forEach(item => {
|
||||
num.push(item[2])
|
||||
})
|
||||
for (let i = 0; i < num.length; i++) {
|
||||
if (num[i] > maxNum) {
|
||||
maxNum = num[i]
|
||||
} else if (num[i] < minNum) {
|
||||
minNum = num[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echartMapList.value = {
|
||||
name: '',
|
||||
title: {
|
||||
text: '区域暂降热力图分布'
|
||||
},
|
||||
|
||||
visualMap: {
|
||||
left: 26,
|
||||
bottom: 40,
|
||||
show: true,
|
||||
color: ['#ff0000', '#37b70c'],
|
||||
min: minNum,
|
||||
max: maxNum,
|
||||
calculable: true,
|
||||
textStyle: {
|
||||
color: '#000',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
mapType: 'nanshan',
|
||||
top: 'center',
|
||||
left: 'center',
|
||||
width: '65%',
|
||||
height: '95%',
|
||||
|
||||
name: 'AQI',
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'geo',
|
||||
blurSize: 40,
|
||||
data: areaData
|
||||
// 鼠标移入
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格数据处理
|
||||
const tabulation = (res: any) => {
|
||||
distributionData.value = res
|
||||
distributionData.value.forEach((item: any) => {
|
||||
if (item.ci == 0) {
|
||||
item.ci = 0.05
|
||||
}
|
||||
})
|
||||
}
|
||||
// 柱状图数据处理
|
||||
const histogram = (res: any) => {
|
||||
echartList.value = {
|
||||
title: {
|
||||
text: header.value.areaRef.areaName
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
var tips = ''
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].value == 0.05) {
|
||||
tips += params[i].name + '</br>'
|
||||
tips += '评估值:0'
|
||||
} else {
|
||||
tips += params[i].name + '</br>'
|
||||
tips += '评估值:' + params[i].value
|
||||
}
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
name: '(区域)',
|
||||
|
||||
data: res.map((item: any) => item.areaName)
|
||||
},
|
||||
yAxis: {
|
||||
name: ' 等级',
|
||||
min: 0,
|
||||
max: 2,
|
||||
// minInterval: 0.2,
|
||||
axisLabel: {
|
||||
fontSize: 14,
|
||||
// interval: 4,
|
||||
formatter: function (value: any) {
|
||||
var texts = ''
|
||||
if (value === 0.4) {
|
||||
texts = '1级'
|
||||
} else if (value === 0.8) {
|
||||
texts = '2级'
|
||||
} else if (value === 1.2) {
|
||||
texts = '3级'
|
||||
} else if (value === 2) {
|
||||
texts = '4级'
|
||||
}
|
||||
return texts
|
||||
}
|
||||
}
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
//
|
||||
{
|
||||
name: '',
|
||||
data: res.map((item: any) => {
|
||||
if (item.ci == 0) {
|
||||
return (item.ci = 0.05)
|
||||
}
|
||||
return item.ci.toFixed(2)
|
||||
}),
|
||||
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 1,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value > 2 && params.value !== 0.05) {
|
||||
return '#339966'
|
||||
} else if (0.8 < params.value && params.value <= 1.2 && params.value !== 0.05) {
|
||||
return '#3399FF'
|
||||
} else if (0.4 < params.value && params.value <= 0.8 && params.value !== 0.05) {
|
||||
return '#FF9900'
|
||||
} else if (0 < params.value && params.value <= 0.4 && params.value !== 0.05) {
|
||||
return '#CC0000'
|
||||
} else if (params.value == 0.05) {
|
||||
return '#CC0000'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
markLine: {
|
||||
silent: false,
|
||||
symbol: 'circle',
|
||||
lineStyle: {
|
||||
color: 'red',
|
||||
width: 1
|
||||
},
|
||||
emphasis: {
|
||||
lineStyle: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: '',
|
||||
yAxis: 0.4,
|
||||
lineStyle: {
|
||||
color: '#CC0000'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#CC0000'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
yAxis: 0.8,
|
||||
lineStyle: {
|
||||
color: '#FF9900'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#FF9900'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
yAxis: 1.2,
|
||||
lineStyle: {
|
||||
color: '#3399FF'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#3399FF'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
yAxis: 2,
|
||||
lineStyle: {
|
||||
color: '#339966'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#339966'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
tableStore.index()
|
||||
}, 10)
|
||||
})
|
||||
const layout = mainHeight(83) as any
|
||||
const layout1 = mainHeight(93) as any
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
height: v-bind('layout.height');
|
||||
}
|
||||
.tall {
|
||||
height: calc(v-bind('layout1.height') / 2);
|
||||
}
|
||||
</style>
|
||||
397
src/views/pms/Event-boot/Region/transientassessment.vue
Normal file
397
src/views/pms/Event-boot/Region/transientassessment.vue
Normal file
@@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader area date-picker ref="header" />
|
||||
<div v-loading="tableStore.table.loading" class="pr10">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<MyEchartMap
|
||||
ref="EchartMap"
|
||||
:options="echartMapList"
|
||||
class="map"
|
||||
@eliminate="eliminate"
|
||||
@getRegionByRegion="getRegionByRegion"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<my-echart class="tall" :options="echartList" />
|
||||
<div class="tall">
|
||||
<vxe-table height="auto" auto-resize :data="distributionData" v-bind="defaultAttribute">
|
||||
>
|
||||
<vxe-column field="areaName" title=" 区域" show-overflow-tooltip></vxe-column>
|
||||
<vxe-column field="ci" title="区域暂降评估">
|
||||
<template #default="{ row }">
|
||||
{{ row.ci == 0.05 ? '暂无数据' : row.ci.toFixed(2) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column sortable field="isCount" title="等级">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.ci == 0.05">暂无等级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 0.2 && row.ci < 0.4">1级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 0.4 && row.ci < 0.8">2级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 0.8 && row.ci < 1.2">3级</span>
|
||||
<span v-if="row.ci !== 0.05 && row.ci >= 1.2">4级</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="dw">
|
||||
<el-popover placement="left" :width="600" trigger="hover">
|
||||
<template #reference>
|
||||
<span class="level">详细区域暂降评估等级</span>
|
||||
</template>
|
||||
<vxe-table :data="areaData1" v-bind="defaultAttribute">
|
||||
<vxe-column title="等级" field="level" min-width="90"></vxe-column>
|
||||
<vxe-column title="1级" field="one" min-width="80"></vxe-column>
|
||||
<vxe-column title="2级" field="two" min-width="90"></vxe-column>
|
||||
<vxe-column title="3级" field="three" min-width="90"></vxe-column>
|
||||
<vxe-column title="4级" field="four" min-width="90"></vxe-column>
|
||||
</vxe-table>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import MyEchartMap from '@/components/echarts/MyEchartMap.vue'
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
defineOptions({
|
||||
name: 'Region/distribution'
|
||||
})
|
||||
const EchartMap = ref()
|
||||
const dictData = useDictData()
|
||||
const echartMapList: any = ref({})
|
||||
const echartList = ref({})
|
||||
const header = ref()
|
||||
const distributionData: any = ref([])
|
||||
const areaData1: any = ref([
|
||||
{
|
||||
level: '相对得分',
|
||||
one: '[0,0.4]',
|
||||
two: '(0.4,0.8)',
|
||||
three: '(0.8,1.2)',
|
||||
four: '(1.2,+∞)'
|
||||
}
|
||||
])
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/advance-boot/balance/getBalanceInfo',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
beforeSearchFun: () => {
|
||||
tableStore.table.params.deptId = tableStore.table.params.deptIndex
|
||||
},
|
||||
loadCallback: () => {
|
||||
header.value.areaRef.change()
|
||||
// 处理地图数据
|
||||
map(tableStore.table.data)
|
||||
tabulation(tableStore.table.data)
|
||||
histogram(tableStore.table.data)
|
||||
EchartMap.value.GetEchar(header.value.areaRef.areaName)
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
tableStore.table.params.loadType = null
|
||||
tableStore.table.params.deptId = dictData.state.area[0].id
|
||||
|
||||
// 地图点击事件
|
||||
const getRegionByRegion = (list: any) => {
|
||||
tableStore.table.params.deptIndex = list.id
|
||||
tableStore.onTableAction('search', {})
|
||||
}
|
||||
// 消除点
|
||||
const eliminate = (name: string) => {
|
||||
echartMapList.value.options.series = []
|
||||
EchartMap.value.GetEchar(name)
|
||||
}
|
||||
|
||||
// 地图数处理
|
||||
const map = (res: any) => {
|
||||
let list: any = []
|
||||
res.forEach((item: any) => {
|
||||
list.push({
|
||||
name: item.areaName,
|
||||
value: item.ci
|
||||
})
|
||||
})
|
||||
|
||||
echartMapList.value = {
|
||||
name: '',
|
||||
title: {
|
||||
text: '区域暂降评估'
|
||||
},
|
||||
|
||||
visualMap: {
|
||||
min: 0,
|
||||
max: 2,
|
||||
left: 26,
|
||||
bottom: 20,
|
||||
showLabel: !0,
|
||||
|
||||
pieces: [
|
||||
{
|
||||
gt: -2,
|
||||
lte: -1,
|
||||
label: '无数据'
|
||||
},
|
||||
{
|
||||
gte: 0,
|
||||
lte: 0.4,
|
||||
label: '1级--相对得分 [0,0.4]'
|
||||
},
|
||||
{
|
||||
gt: 0.4,
|
||||
lte: 0.9,
|
||||
label: '2级--得分 (0.4,0.8]'
|
||||
},
|
||||
{
|
||||
gt: 0.9,
|
||||
lte: 1.2,
|
||||
label: '3级--相对得分 (0.8,1.2]'
|
||||
},
|
||||
{
|
||||
gt: 1.2,
|
||||
label: '4级--相对得分 (1.2,+∞]'
|
||||
}
|
||||
],
|
||||
inRange: {
|
||||
color: ['#ccc', '#CC0000', '#FF9900', '#3399CC', '#339966']
|
||||
}
|
||||
},
|
||||
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
// type: "scatter",
|
||||
type: 'map',
|
||||
mapName: name,
|
||||
coordinateSystem: 'geo',
|
||||
geoIndex: 0,
|
||||
animation: false, //坐标点是否显示动画
|
||||
roam: true,
|
||||
selectedMode: 'false', //是否允许选中多个区域
|
||||
symbol: 'pin',
|
||||
rippleEffect: {
|
||||
brushType: 'fill' // stroke|fill
|
||||
},
|
||||
|
||||
label: {
|
||||
normal: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true
|
||||
}
|
||||
}
|
||||
},
|
||||
data: list
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格数据处理
|
||||
const tabulation = (res: any) => {
|
||||
distributionData.value = res
|
||||
distributionData.value.forEach((item: any) => {
|
||||
if (item.ci == 0) {
|
||||
item.ci = 0.05
|
||||
}
|
||||
})
|
||||
}
|
||||
// 柱状图数据处理
|
||||
const histogram = (res: any) => {
|
||||
echartList.value = {
|
||||
title: {
|
||||
text: header.value.areaRef.areaName
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
var tips = ''
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].value == 0.05) {
|
||||
tips += params[i].name + '</br>'
|
||||
tips += '评估值:0'
|
||||
} else {
|
||||
tips += params[i].name + '</br>'
|
||||
tips += '评估值:' + params[i].value
|
||||
}
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
name: '(区域)',
|
||||
|
||||
data: res.map((item: any) => item.areaName)
|
||||
},
|
||||
yAxis: {
|
||||
name: ' 等级',
|
||||
min: 0,
|
||||
max: 2,
|
||||
// minInterval: 0.2,
|
||||
axisLabel: {
|
||||
fontSize: 14,
|
||||
// interval: 4,
|
||||
formatter: function (value: any) {
|
||||
var texts = ''
|
||||
if (value === 0.4) {
|
||||
texts = '1级'
|
||||
} else if (value === 0.8) {
|
||||
texts = '2级'
|
||||
} else if (value === 1.2) {
|
||||
texts = '3级'
|
||||
} else if (value === 2) {
|
||||
texts = '4级'
|
||||
}
|
||||
return texts
|
||||
}
|
||||
}
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
//
|
||||
{
|
||||
name: '',
|
||||
data: res.map((item: any) => {
|
||||
if (item.ci == 0) {
|
||||
return (item.ci = 0.05)
|
||||
}
|
||||
return item.ci.toFixed(2)
|
||||
}),
|
||||
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 1,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value > 2 && params.value !== 0.05) {
|
||||
return '#339966'
|
||||
} else if (0.8 < params.value && params.value <= 1.2 && params.value !== 0.05) {
|
||||
return '#3399FF'
|
||||
} else if (0.4 < params.value && params.value <= 0.8 && params.value !== 0.05) {
|
||||
return '#FF9900'
|
||||
} else if (0 < params.value && params.value <= 0.4 && params.value !== 0.05) {
|
||||
return '#CC0000'
|
||||
} else if (params.value == 0.05) {
|
||||
return '#CC0000'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
markLine: {
|
||||
silent: false,
|
||||
symbol: 'circle',
|
||||
lineStyle: {
|
||||
color: 'red',
|
||||
width: 1
|
||||
},
|
||||
emphasis: {
|
||||
lineStyle: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: '',
|
||||
yAxis: 0.4,
|
||||
lineStyle: {
|
||||
color: '#CC0000'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#CC0000'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
yAxis: 0.8,
|
||||
lineStyle: {
|
||||
color: '#FF9900'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#FF9900'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
yAxis: 1.2,
|
||||
lineStyle: {
|
||||
color: '#3399FF'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#3399FF'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
yAxis: 2,
|
||||
lineStyle: {
|
||||
color: '#339966'
|
||||
},
|
||||
label: {
|
||||
// position: "middle",
|
||||
formatter: '{b}',
|
||||
textStyle: {
|
||||
color: '#339966'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
tableStore.index()
|
||||
}, 10)
|
||||
})
|
||||
const layout = mainHeight(83) as any
|
||||
const layout1 = mainHeight(93) as any
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
height: v-bind('layout.height');
|
||||
}
|
||||
.tall {
|
||||
height: calc(v-bind('layout1.height') / 2);
|
||||
}
|
||||
.dw {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 50px;
|
||||
width: 200px;
|
||||
z-index: 2;
|
||||
.level {
|
||||
color: red;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
61
src/views/pms/comptroller/list.vue
Normal file
61
src/views/pms/comptroller/list.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker>
|
||||
<template v-slot:select>
|
||||
<!-- <el-form-item label="用户名">
|
||||
<el-select v-model="value" class="m-2" placeholder="Select" size="large">
|
||||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作类型">
|
||||
<el-input v-model="tableStore.table.params.loginName" placeholder="Please input" />
|
||||
</el-form-item> -->
|
||||
</template>
|
||||
<template v-slot:operation>
|
||||
<el-button :icon="Plus" type="primary" @click="addMenu">添加</el-button>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<Table ref="tableRef" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { saveLogParam } from '@/api/common'
|
||||
|
||||
defineOptions({
|
||||
name: 'comptroller/list'
|
||||
})
|
||||
const tableStore = new TableStore({
|
||||
url: '/system-boot/audit/getAuditLog',
|
||||
method: 'POST',
|
||||
column: [
|
||||
{ title: '操作时间', field: 'time', align: 'center', width: 200 },
|
||||
{ title: '操作人员', field: 'userName', align: 'center', width: 120 },
|
||||
{ title: '操作类型', field: 'operate', align: 'center', width: 220 },
|
||||
{ title: '事件描述', field: 'describe', align: 'center', showOverflow: true,minWidth: 200 },
|
||||
{ title: '事件类型', field: 'type', align: 'center', width: 160 },
|
||||
{ title: '操作结果', field: 'type', align: 'center', width: 100 },
|
||||
{ title: '操作IP', field: 'ip', align: 'center', width: 160 },
|
||||
{ title: '事件等级', field: 'level', align: 'center', width: 100 }
|
||||
]
|
||||
})
|
||||
tableStore.table.params.loginName = ''
|
||||
tableStore.table.params.operateType = ''
|
||||
tableStore.table.params.type = ''
|
||||
tableStore.table.params.pageSize = 100
|
||||
provide('tableStore', tableStore)
|
||||
|
||||
// saveLogParam().then(res => {
|
||||
// console.log(res)
|
||||
// })
|
||||
|
||||
onMounted(() => {
|
||||
// tableStore.index()
|
||||
})
|
||||
|
||||
const addMenu = () => {}
|
||||
</script>
|
||||
146
src/views/pms/voltage/sags/operationsManagement/index.vue
Normal file
146
src/views/pms/voltage/sags/operationsManagement/index.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker area>
|
||||
<template v-slot:select>
|
||||
|
||||
<el-form-item label="终端状态">
|
||||
<el-select
|
||||
multiple
|
||||
clearable
|
||||
collapse-tags
|
||||
v-model="tableStore.table.params.runFlag"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<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
|
||||
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-select
|
||||
multiple
|
||||
clearable
|
||||
collapse-tags
|
||||
v-model="manufacturerForm"
|
||||
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="根据变电站,终端编号,型号或网络参数查询"
|
||||
/>
|
||||
</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: 'voltage/sags/operationsManagement/index'
|
||||
})
|
||||
const dictData = useDictData()
|
||||
const manufacturer = dictData.getBasicData('Dev_Manufacturers')
|
||||
const manufacturerForm = ref<string[]>([])
|
||||
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: () => {
|
||||
manufacturerForm.value = []
|
||||
}
|
||||
})
|
||||
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 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>
|
||||
175
src/views/pms/voltage/sags/operationsManagement/point.vue
Normal file
175
src/views/pms/voltage/sags/operationsManagement/point.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker area>
|
||||
<template v-slot:select>
|
||||
<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="根据变电站,终端编号,型号或网络参数查询"
|
||||
/>
|
||||
</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: 'voltage/sags/operationsManagement/point'
|
||||
})
|
||||
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.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>
|
||||
416
src/views/pms/voltage/sags/operationsManagement/statistics.vue
Normal file
416
src/views/pms/voltage/sags/operationsManagement/statistics.vue
Normal file
@@ -0,0 +1,416 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader date-picker >
|
||||
<template v-slot:select>
|
||||
<el-form-item label="区域">
|
||||
<Area v-model="tableStore.table.params.deptIndex" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<div style="font-weight: bold; background: #fff; text-indent: 1em">
|
||||
<span style="color: #000">
|
||||
(左柱):
|
||||
<span style="color: #0099cc">
|
||||
<span class="smallBlock" style="background: #0099cc"></span>
|
||||
投运
|
||||
</span>
|
||||
<span style="color: #996600">
|
||||
<span class="smallBlock" style="background: #996600"></span>
|
||||
热备用
|
||||
</span>
|
||||
<span style="color: #cc0000">
|
||||
<span class="smallBlock" style="background: #cc0000"></span>
|
||||
停运
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span style="color: #000">
|
||||
(右柱):
|
||||
<span style="color: #2e8b57">
|
||||
<span class="smallBlock" style="background: #2e8b57"></span>
|
||||
{{ '在线率≥90 %' }}
|
||||
</span>
|
||||
<span style="color: #daa520">
|
||||
<span class="smallBlock" style="background: #daa520"></span>
|
||||
{{ '60 %≤在线率 < 90 %' }}
|
||||
</span>
|
||||
<span style="color: #cc0000">
|
||||
<span class="smallBlock" style="background: #cc0000"></span>
|
||||
{{ '在线率 < 60 %' }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="statistics-main" v-loading="tableStore.table.loading">
|
||||
<template v-if="!tableStore.table.loading">
|
||||
<div>
|
||||
<my-echart :options="areaStatistics" />
|
||||
</div>
|
||||
<div>
|
||||
<vxe-table
|
||||
height="auto"
|
||||
auto-resize
|
||||
:data="tableStore.table.data.area.areaInfo"
|
||||
v-bind="defaultAttribute"
|
||||
>
|
||||
<vxe-column field="areaName" title="区域"></vxe-column>
|
||||
<vxe-column field="numberOfTerminals" title="终端个数" width="80"></vxe-column>
|
||||
<vxe-column field="normal" title="投运" width="80"></vxe-column>
|
||||
<vxe-column field="breaks" title="热备用" width="80"></vxe-column>
|
||||
<vxe-column field="shutdown" title="停运" width="80"></vxe-column>
|
||||
<vxe-column field="onlineRate" title="在线率(%)">
|
||||
<template v-slot:default="scoped">
|
||||
{{ scoped.row.onlineRate === 3.14159 ? '/' : scoped.row.onlineRate }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
<div>
|
||||
<my-echart :options="factoryStatistics" />
|
||||
</div>
|
||||
<div>
|
||||
<vxe-table
|
||||
height="auto"
|
||||
auto-resize
|
||||
:data="tableStore.table.data.factory.areaInfo"
|
||||
v-bind="defaultAttribute"
|
||||
>
|
||||
<vxe-column field="areaName" title="厂家"></vxe-column>
|
||||
<vxe-column field="numberOfTerminals" title="终端个数" width="80"></vxe-column>
|
||||
<vxe-column field="normal" title="投运" width="80"></vxe-column>
|
||||
<vxe-column field="breaks" title="热备用" width="80"></vxe-column>
|
||||
<vxe-column field="shutdown" title="停运" width="80"></vxe-column>
|
||||
<vxe-column field="onlineRate" title="在线率(%)">
|
||||
<template v-slot:default="scoped">
|
||||
{{ scoped.row.onlineRate === 3.14159 ? '/' : scoped.row.onlineRate }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import Area from '@/components/form/area/index.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { onMounted, provide, reactive, ref } from 'vue'
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
|
||||
defineOptions({
|
||||
name: 'voltage/sags/operationsManagement/statistics'
|
||||
})
|
||||
const dictData = useDictData()
|
||||
const areaStatistics = ref()
|
||||
const factoryStatistics = ref()
|
||||
const tableStore = new TableStore({
|
||||
url: '/event-boot/area/getTerminalRunningStatistics',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
loadCallback: () => {
|
||||
areaStatistics.value = {
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
title: {
|
||||
text: '区域'
|
||||
},
|
||||
xAxis: {
|
||||
data: tableStore.table.data.area.areaInfo.map(
|
||||
(item: any) => item.areaName + `(${item.numberOfTerminals})`
|
||||
)
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params:any) {
|
||||
var tips = ''
|
||||
tips += params[0].name + '</br/>'
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].value == 3.14159) {
|
||||
tips += params[i].seriesName + ':暂无数据<br/>'
|
||||
} else {
|
||||
tips += params[i].seriesName + ':' + params[i].value + '%<br/>'
|
||||
}
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
yAxis: { name: '%' },
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
stack: 'one',
|
||||
name: '投运',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
data: tableStore.table.data.area.areaInfo.map((item: any) => item.normalRate),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value != 3.14159) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#0099CC'
|
||||
}
|
||||
])
|
||||
} else if ((params.value = 3.14159)) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#ccc'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'bar'
|
||||
},
|
||||
{
|
||||
name: '热备用',
|
||||
stack: 'one',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
data: tableStore.table.data.area.areaInfo.map((item: any) => item.shutdownRate),
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value != 3.14159) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#cc0000'
|
||||
}
|
||||
])
|
||||
} else if ((params.value = 3.14159)) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#ccc'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '在线率',
|
||||
stack: 'two',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
data: tableStore.table.data.area.areaInfo.map((item: any) => item.onlineRate),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value >= 90) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#339966'
|
||||
}
|
||||
])
|
||||
} else if (params.value >= 60 && params.value <= 90) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#FFCC33'
|
||||
}
|
||||
])
|
||||
} else if (params.value <= 60 && params.value != 3.14159) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#CC0000'
|
||||
}
|
||||
])
|
||||
} else if ((params.value = 3.14159)) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#ccc'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'bar'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
factoryStatistics.value = {
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
title: {
|
||||
text: '终端厂家'
|
||||
},
|
||||
xAxis: {
|
||||
data: tableStore.table.data.factory.areaInfo.map(
|
||||
(item: any) => item.areaName + `(${item.numberOfTerminals})`
|
||||
)
|
||||
},
|
||||
yAxis: {
|
||||
name: '%'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
var tips = ''
|
||||
tips += params[0].name + '</br/>'
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].value == 3.14159) {
|
||||
tips += params[i].seriesName + ':暂无数据<br/>'
|
||||
} else {
|
||||
tips += params[i].seriesName + ':' + params[i].value + '%<br/>'
|
||||
}
|
||||
}
|
||||
return tips
|
||||
}
|
||||
},
|
||||
options: {
|
||||
series: [
|
||||
{
|
||||
stack: 'one',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
name: '投运',
|
||||
data: tableStore.table.data.factory.areaInfo.map((item: any) => item.normalRate),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value != 3.14159) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#0099CC'
|
||||
}
|
||||
])
|
||||
} else if ((params.value = 3.14159)) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#ccc'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'bar'
|
||||
},
|
||||
{
|
||||
name: '热备用',
|
||||
stack: 'one',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
data: tableStore.table.data.factory.areaInfo.map((item: any) => item.shutdownRate),
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value != 3.14159) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#cc0000'
|
||||
}
|
||||
])
|
||||
} else if ((params.value = 3.14159)) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#ccc'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '在线率',
|
||||
stack: 'two',
|
||||
barMaxWidth: 30,
|
||||
barMinHeight: 5,
|
||||
data: tableStore.table.data.factory.areaInfo.map((item: any) => item.onlineRate),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params: any) {
|
||||
if (params.value >= 90) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#339966'
|
||||
}
|
||||
])
|
||||
} else if (params.value >= 60 && params.value <= 90) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#FFCC33'
|
||||
}
|
||||
])
|
||||
} else if (params.value <= 60 && params.value != 3.14159) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#CC0000'
|
||||
}
|
||||
])
|
||||
} else if ((params.value = 3.14159)) {
|
||||
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
|
||||
{
|
||||
offset: 1,
|
||||
color: '#ccc'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'bar'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
tableStore.table.params.deptIndex = dictData.state.area[0].id
|
||||
tableStore.table.params.serverName = 'event-boot'
|
||||
tableStore.table.params.monitorFlag = 2
|
||||
tableStore.table.params.powerFlag = 2
|
||||
tableStore.table.params.statisticalType = {
|
||||
name: '电网拓扑',
|
||||
id: 'cc28974d259ad22642f6a1bff708f967',
|
||||
code: 'Power_Network',
|
||||
value: 'cc28974d259ad22642f6a1bff708f967',
|
||||
gvalue: null,
|
||||
label: '电网拓扑',
|
||||
sort: 0
|
||||
}
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const layout = mainHeight(104) as any
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.statistics-main {
|
||||
box-sizing: border-box;
|
||||
height: v-bind('layout.height');
|
||||
padding: 0 10px 10px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 600px;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
grid-gap: 10px;
|
||||
|
||||
}
|
||||
</style>
|
||||
153
src/views/setting/dictionary/list/detail.vue
Normal file
153
src/views/setting/dictionary/list/detail.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<div class="dictiontary-list-detail child-router">
|
||||
<TableHeader>
|
||||
<template #select>
|
||||
<el-form-item label="">
|
||||
<el-page-header @back="$emit('close')">
|
||||
<template #content>
|
||||
<span class="text-large font-600 mr-3">{{ props.detail.name }}详情信息</span>
|
||||
</template>
|
||||
</el-page-header>
|
||||
</el-form-item>
|
||||
<el-form-item label="过滤筛选">
|
||||
<el-input
|
||||
style="width: 240px"
|
||||
v-model="tableStore.table.params.searchValue"
|
||||
clearable
|
||||
placeholder="请输入名称或编码筛选"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template #operation>
|
||||
<el-button :icon="Plus" type="primary" @click="add">新增</el-button>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<Table ref="tableRef" />
|
||||
<PopupDetailEdit ref="popupEditRef"></PopupDetailEdit>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import PopupDetailEdit from './popupDetailEdit.vue'
|
||||
import { dictDataDelete } from '@/api/system-boot/dicData'
|
||||
|
||||
defineOptions({
|
||||
name: 'setting/dictionary/list/detail'
|
||||
})
|
||||
|
||||
interface Props {
|
||||
detail: anyObj
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
detail: () => {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
const popupEditRef = ref()
|
||||
const tableStore = new TableStore({
|
||||
url: '/system-boot/dictData/getTypeIdData',
|
||||
method: 'POST',
|
||||
column: [
|
||||
{ title: '名称', field: 'name' },
|
||||
{ title: '编码', field: 'code' },
|
||||
{ title: '排序', field: 'sort' },
|
||||
{ title: '计算值', field: 'value' },
|
||||
{ title: '事件等级', field: 'levelName' },
|
||||
{ title: '算法描述', field: 'algoDescribe' },
|
||||
{ title: '状态', field: 'stateName' },
|
||||
{
|
||||
title: '操作',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
fixed: 'right',
|
||||
buttons: [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupEditRef.value.open('编辑', {
|
||||
...row,
|
||||
openDescribe: props.detail.openDescribe,
|
||||
openLevel: props.detail.openLevel,
|
||||
typeName: props.detail.name + row.name,
|
||||
typeId: props.detail.id
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Delete',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定删除该字典类型吗?'
|
||||
},
|
||||
click: row => {
|
||||
dictDataDelete([row.id]).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
tableStore.index()
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
loadCallback: () => {
|
||||
tableStore.table.data.forEach((item: any) => {
|
||||
item.stateName = item.state === 1 ? '正常' : '删除'
|
||||
switch (item.level) {
|
||||
case 0:
|
||||
item.levelName = '普通'
|
||||
break
|
||||
case 1:
|
||||
item.levelName = '中等'
|
||||
break
|
||||
case 2:
|
||||
item.levelName = '严重'
|
||||
break
|
||||
default:
|
||||
item.levelName = '未知'
|
||||
break
|
||||
}
|
||||
for (let key in item) {
|
||||
if (typeof item[key] !== 'number') {
|
||||
item[key] = item[key] || '/'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
provide('tableStore', tableStore)
|
||||
tableStore.table.params.searchValue = ''
|
||||
tableStore.table.params.searchState = 0
|
||||
tableStore.table.params.typeId = props.detail.id
|
||||
if (props.detail.openLevel !== 1) {
|
||||
tableStore.table.column = tableStore.table.column.filter((item: any) => item.field !== 'levelName')
|
||||
}
|
||||
if (props.detail.openDescribe !== 1) {
|
||||
tableStore.table.column = tableStore.table.column.filter((item: any) => item.field !== 'algoDescribe')
|
||||
}
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const add = () => {
|
||||
popupEditRef.value.open('新增', {
|
||||
openLevel: props.detail.openLevel,
|
||||
openDescribe: props.detail.openDescribe,
|
||||
typeName: props.detail.name,
|
||||
typeId: props.detail.id
|
||||
})
|
||||
}
|
||||
</script>
|
||||
124
src/views/setting/dictionary/list/index.vue
Normal file
124
src/views/setting/dictionary/list/index.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="default-main" style="position: relative">
|
||||
<TableHeader>
|
||||
<template #select>
|
||||
<el-form-item label="过滤筛选">
|
||||
<el-input
|
||||
style="width: 240px"
|
||||
v-model="tableStore.table.params.searchValue"
|
||||
clearable
|
||||
placeholder="请输入名称或编码筛选"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template #operation>
|
||||
<el-button :icon="Plus" type="primary" @click="add">新增字典类型</el-button>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<Table ref="tableRef" />
|
||||
<PopupEdit ref="popupEditRef"></PopupEdit>
|
||||
<Detail ref="detailRef" :detail="detail" @close="detail = null" v-if="detail"></Detail>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import PopupEdit from './popupEdit.vue'
|
||||
import { dictTypeDelete } from '@/api/system-boot/dictType'
|
||||
import Detail from './detail.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'system-boot/dictType/list'
|
||||
})
|
||||
const popupEditRef = ref()
|
||||
const detail = ref<anyObj | null>(null)
|
||||
const tableStore = new TableStore({
|
||||
url: '/system-boot/dictType/list',
|
||||
method: 'POST',
|
||||
column: [
|
||||
{ title: '序号', type: 'seq', width: '60' },
|
||||
{ title: '名称', field: 'name' },
|
||||
{ title: '编码', field: 'code' },
|
||||
{ title: '开启等级', field: 'openLevelName' },
|
||||
{ title: '开启算法', field: 'openDescribeName' },
|
||||
{ title: '字典描述', field: 'remark' },
|
||||
{ title: '创建时间', field: 'createTime' },
|
||||
{ title: '更新时间', field: 'updateTime' },
|
||||
{
|
||||
title: '状态',
|
||||
field: 'stateName',
|
||||
width: '80',
|
||||
render: 'tag',
|
||||
custom: {
|
||||
'正常': 'success',
|
||||
'删除': 'danger'
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
fixed: 'right',
|
||||
buttons: [
|
||||
{
|
||||
title: '查看',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-ZoomIn',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
detail.value = row
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupEditRef.value.open('编辑字典类型', row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Delete',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定删除该字典类型吗?'
|
||||
},
|
||||
click: row => {
|
||||
dictTypeDelete([row.id]).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
tableStore.index()
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
loadCallback: () => {
|
||||
tableStore.table.data.forEach((item: any) => {
|
||||
item.stateName = item.state === 1 ? '正常' : '删除'
|
||||
item.openLevelName = item.openLevel === 1 ? '开启' : '不开启'
|
||||
item.openDescribeName = item.openDescribe === 1 ? '开启' : '不开启'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
provide('tableStore', tableStore)
|
||||
tableStore.table.params.searchValue = ''
|
||||
tableStore.table.params.searchState = 0
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const add = () => {
|
||||
popupEditRef.value.open('新增字典类型')
|
||||
}
|
||||
</script>
|
||||
135
src/views/setting/dictionary/list/popupDetailEdit.vue
Normal file
135
src/views/setting/dictionary/list/popupDetailEdit.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<el-dialog class='cn-operate-dialog' v-model='dialogVisible' :title='title'>
|
||||
<el-scrollbar>
|
||||
<el-form :inline='false' :model='form' label-width='120px' :rules='rules' ref='formRef'>
|
||||
<el-form-item label='名称:' class='top' prop='name'>
|
||||
<el-input v-model='form.name'></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label='计算值:' class='top'>
|
||||
<el-input v-model='form.value'></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item class='top' label='对应算法:' prop='algoDescribe' v-if='form.openDescribe == 1'>
|
||||
<el-input v-model='form.algoDescribe' placeholder='请输入数字'></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item class='top'
|
||||
label='编码:'
|
||||
prop='code'
|
||||
>
|
||||
<el-input v-model='form.code'></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label='排序:' prop='sort' class='top'>
|
||||
<el-input-number v-model='form.sort' :min='0' />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if='form.openLevel === 1'
|
||||
label='事件等级:'
|
||||
>
|
||||
<el-select v-model='form.level' placeholder='选择开启等级'>
|
||||
<el-option
|
||||
v-for='item in EventOpenLevel'
|
||||
:key='item.value'
|
||||
:label='item.label'
|
||||
:value='item.value'
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class='dialog-footer'>
|
||||
<el-button @click='dialogVisible = false'>取消</el-button>
|
||||
<el-button type='primary' @click='submit'>确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang='ts' setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { add, update } from '@/api/user-boot/role'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { dictDataAdd, dictDataUpdate } from '@/api/system-boot/dicData'
|
||||
|
||||
defineOptions({
|
||||
name: 'diction/list/detail/popupDetailEdit'
|
||||
})
|
||||
const adminInfo = useAdminInfo()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
const formRef = ref()
|
||||
// do not use same name with ref
|
||||
const form = reactive({
|
||||
algoDescribe: '',
|
||||
code: '',
|
||||
level: 0,
|
||||
name: '',
|
||||
value: '',
|
||||
sort: 100,
|
||||
typeId: '',
|
||||
openLevel: 0,
|
||||
openDescribe: 0,
|
||||
typeName: '',
|
||||
id: ''
|
||||
})
|
||||
const EventOpenLevel = [
|
||||
{ value: 0, label: '普通' },
|
||||
{ value: 1, label: '中等' },
|
||||
{ value: 2, label: '严重' }
|
||||
]
|
||||
const rules = {
|
||||
algoDescribe: [
|
||||
{ required: false, message: '对应算法不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^\d+$|^\d+[.]?\d+$/,
|
||||
message: '请您数字对应算法',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '名称不能为空', trigger: 'blur' }
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: '编码不能为空', trigger: 'blur' }
|
||||
],
|
||||
sort: [
|
||||
{ required: true, message: '排序不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增')
|
||||
const open = (text: string, data: anyObj) => {
|
||||
dialogVisible.value = true
|
||||
if (text === '编辑') {
|
||||
for (let key in form) {
|
||||
form[key] = data[key] === '/' ? '' : data[key]
|
||||
}
|
||||
} else if (text === '新增') {
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
form.level = 0
|
||||
form.sort = 100
|
||||
form.typeId = data.typeId
|
||||
form.openLevel = data.openLevel
|
||||
form.typeName = data.typeName
|
||||
form.openDescribe = data.openDescribe
|
||||
}
|
||||
title.value = form.typeName + text
|
||||
}
|
||||
const submit = async () => {
|
||||
await formRef.value.validate()
|
||||
if (form.id) {
|
||||
await dictDataUpdate(form)
|
||||
} else {
|
||||
await dictDataAdd(form)
|
||||
}
|
||||
ElMessage.success('保存成功')
|
||||
tableStore.index()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
128
src/views/setting/dictionary/list/popupEdit.vue
Normal file
128
src/views/setting/dictionary/list/popupEdit.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<el-dialog class='cn-operate-dialog' v-model='dialogVisible' :title='title'>
|
||||
<el-scrollbar>
|
||||
<el-form :inline='false' :model='form' label-width='120px' :rules='rules' ref='formRef'>
|
||||
<el-form-item label='名称' prop='name'>
|
||||
<el-input v-model='form.name'></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label='编码' class='top' prop='code'>
|
||||
<el-input v-model='form.code'></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label='排序' class='top' prop='sort'>
|
||||
<el-input-number v-model="form.sort" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label='开启等级' class='top'>
|
||||
<el-select
|
||||
v-model='form.openLevel'
|
||||
placeholder='选择开启等级'
|
||||
>
|
||||
<el-option
|
||||
v-for='item in OpenLevel'
|
||||
:key='item.value'
|
||||
:label='item.label'
|
||||
:value='item.value'
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label='开启算法' class='top'>
|
||||
<el-select
|
||||
v-model='form.openDescribe'
|
||||
placeholder='选择开启算法'
|
||||
>
|
||||
<el-option
|
||||
v-for='item in OpenDescribe'
|
||||
:key='item.value'
|
||||
:label='item.label'
|
||||
:value='item.value'
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label='字典描述' class='top'>
|
||||
<el-input
|
||||
v-model='form.remark'
|
||||
type='textarea'
|
||||
:rows='2'
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class='dialog-footer'>
|
||||
<el-button @click='dialogVisible = false'>取消</el-button>
|
||||
<el-button type='primary' @click='submit'>确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang='ts' setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { dictTypeAdd, dictTypeUpdate } from '@/api/system-boot/dictType'
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
const OpenLevel = [
|
||||
{ value: 0, label: '不开启' },
|
||||
{ value: 1, label: '开启' }
|
||||
]
|
||||
const OpenDescribe = [
|
||||
{ value: 0, label: '不开启' },
|
||||
{ value: 1, label: '开启' }
|
||||
]
|
||||
const formRef = ref()
|
||||
const form = reactive({
|
||||
openLevel: 0,
|
||||
openDescribe: 0,
|
||||
remark: '',
|
||||
name: '',
|
||||
code: '',
|
||||
sort: 100,
|
||||
id: ''
|
||||
})
|
||||
const rules = {
|
||||
name: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
sort: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '不能为空', trigger: 'blur' }]
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增字典类型')
|
||||
const open = (text: string, data?: anyObj) => {
|
||||
title.value = text
|
||||
dialogVisible.value = true
|
||||
if (data) {
|
||||
for (let key in form) {
|
||||
form[key] = data[key]
|
||||
}
|
||||
} else {
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
form.openLevel = 0
|
||||
form.openDescribe = 0
|
||||
form.sort = 100
|
||||
}
|
||||
}
|
||||
const submit = async () => {
|
||||
formRef.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
if (form.id) {
|
||||
await dictTypeUpdate(form)
|
||||
} else {
|
||||
await dictTypeAdd(form)
|
||||
}
|
||||
ElMessage.success('保存成功')
|
||||
tableStore.index()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
113
src/views/setting/dictionary/tree/index.vue
Normal file
113
src/views/setting/dictionary/tree/index.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class='default-main'>
|
||||
<div class='custom-table-header'>
|
||||
<div class="title">字典树列表</div>
|
||||
<el-button :icon='Plus' type='primary' @click='addMenu'>新增字典类型</el-button>
|
||||
</div>
|
||||
<Table ref='tableRef' />
|
||||
<PopupForm ref='popupFormRef'></PopupForm>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang='ts'>
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import PopupForm from './popupForm.vue'
|
||||
import { dicDelete } from '@/api/system-boot/dic'
|
||||
|
||||
defineOptions({
|
||||
name: 'setting/dictionary/tree'
|
||||
})
|
||||
|
||||
const popupFormRef = ref()
|
||||
const tableStore = new TableStore({
|
||||
showPage:false,
|
||||
url: '/system-boot/dic/dicTree',
|
||||
method: 'GET',
|
||||
column: [
|
||||
{ title: '字典名称', field: 'name', treeNode: true, align: 'left' },
|
||||
// { title: '排序', field: 'sort',width:'80' },
|
||||
{ title: '编码', field: 'code' },
|
||||
{ title: '描述', field: 'remark' },
|
||||
{
|
||||
title: '状态',
|
||||
field: 'status',
|
||||
width: '80',
|
||||
render: 'tag',
|
||||
custom: {
|
||||
0: 'success',
|
||||
1: 'warning',
|
||||
2: 'danger'
|
||||
},
|
||||
replaceValue: {
|
||||
0: '正常',
|
||||
1: '禁用',
|
||||
2: '删除'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: '180',
|
||||
render: 'buttons',
|
||||
fixed: 'right',
|
||||
buttons: [
|
||||
{
|
||||
title: '新增',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-Plus',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupFormRef.value.open('新增字典类型', {
|
||||
name: '',
|
||||
code: '',
|
||||
remark: '',
|
||||
sort: 100,
|
||||
type: 0,
|
||||
pid: row.id,
|
||||
id: ''
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
icon: 'el-icon-EditPen',
|
||||
render: 'basicButton',
|
||||
click: row => {
|
||||
popupFormRef.value.open('编辑字典类型', row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'danger',
|
||||
icon: 'el-icon-Delete',
|
||||
render: 'confirmButton',
|
||||
popconfirm: {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonType: 'danger',
|
||||
title: '确定删除该字典类型吗?'
|
||||
},
|
||||
click: row => {
|
||||
dicDelete(row.id).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
tableStore.index()
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
provide('tableStore', tableStore)
|
||||
tableStore.table.params.searchState = 0
|
||||
onMounted(() => {
|
||||
tableStore.index()
|
||||
})
|
||||
const addMenu = () => {
|
||||
popupFormRef.value.open('新增字典类型')
|
||||
}
|
||||
</script>
|
||||
83
src/views/setting/dictionary/tree/popupForm.vue
Normal file
83
src/views/setting/dictionary/tree/popupForm.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
|
||||
<el-scrollbar>
|
||||
<el-form :inline="false" :model="form" label-width="120px" :rules="rules">
|
||||
<el-form-item label="字典名称:" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入字典名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="序号:" prop="sort" class="top">
|
||||
<el-input v-model="form.sort" placeholder="请输入序号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="编码:" prop="code" class="top">
|
||||
<el-input v-model="form.code" placeholder="请输入字典编码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述:" class="top">
|
||||
<el-input v-model="form.remark" placeholder="请输入字典描述"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { dicAdd, dicUpdate } from '@/api/system-boot/dic'
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
const tableStore = inject('tableStore') as TableStore
|
||||
// do not use same name with ref
|
||||
const form = reactive({
|
||||
name: '',
|
||||
code: '',
|
||||
remark: '',
|
||||
sort: 100,
|
||||
type: 0,
|
||||
pid: 0,
|
||||
id: ''
|
||||
})
|
||||
const rules = {
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
|
||||
sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '编码不能为空', trigger: 'blur' }]
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('新增菜单')
|
||||
const open = (text: string, data?: anyObj) => {
|
||||
title.value = text
|
||||
dialogVisible.value = true
|
||||
if (data) {
|
||||
for (let key in form) {
|
||||
form[key] = data[key]
|
||||
}
|
||||
} else {
|
||||
for (let key in form) {
|
||||
form[key] = ''
|
||||
}
|
||||
form.sort = 100
|
||||
form.pid = 0
|
||||
form.type = 0
|
||||
}
|
||||
}
|
||||
const submit = async () => {
|
||||
if (form.id) {
|
||||
await dicUpdate(form)
|
||||
} else {
|
||||
await dicAdd(form)
|
||||
}
|
||||
ElMessage.success('保存成功')
|
||||
tableStore.index()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
304
src/views/user/login.vue
Normal file
304
src/views/user/login.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<div @keyup.enter="onSubmit(formRef)">
|
||||
<div @contextmenu.stop="" id="bubble" class="bubble">
|
||||
<canvas id="bubble-canvas" class="bubble-canvas"></canvas>
|
||||
</div>
|
||||
<div class="login-image"></div>
|
||||
<div class="login-container-form">
|
||||
<div class="title-container">
|
||||
<div class="title">
|
||||
<span style="font-size: 28px">电能质量数据监测云平台</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-form :rules="rules" ref="formRef" size="large" class="login-form" :model="form">
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
ref="usernameRef"
|
||||
v-model="form.username"
|
||||
type="text"
|
||||
clearable
|
||||
placeholder="用户名"
|
||||
autocomplete="off"
|
||||
>
|
||||
<template #prefix>
|
||||
<span class="iconfont icon-yonghu" style="color: #003078"></span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
ref="passwordRef"
|
||||
v-model="form.password"
|
||||
type="password"
|
||||
placeholder="密码"
|
||||
autocomplete="off"
|
||||
>
|
||||
<template #prefix>
|
||||
<span class="iconfont icon-mima" style="color: #003078"></span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
:loading="state.submitLoading"
|
||||
class="submit-btn"
|
||||
round
|
||||
type="info"
|
||||
@click="onSubmit(formRef)"
|
||||
>
|
||||
登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="copy-right">
|
||||
<span>版权所有 @ 南京灿能电力自动化股份有限公司</span>
|
||||
<br />
|
||||
<img style="width: 20px; height: 20px; position: absolute" src="@/assets/login/jhui.png" />
|
||||
|
||||
<span> 苏公网安备 32011502011902号</span>
|
||||
</div>
|
||||
<PopupUpdatePwd ref="popupUpdatePwdRef"></PopupUpdatePwd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
|
||||
import * as pageBubble from '@/utils/pageBubble'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { gongkey, login } from '@/api/user-boot/user'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import type { FormInstance, InputInstance, FormRules } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ADMIN_INFO } from '@/stores/constant/cacheKey'
|
||||
import { Local } from '@/utils/storage'
|
||||
import PopupUpdatePwd from './popupUpdatePwd.vue'
|
||||
|
||||
const router = useRouter()
|
||||
let timer: number
|
||||
|
||||
const popupUpdatePwdRef = ref()
|
||||
const formRef = ref<FormInstance>()
|
||||
const usernameRef = ref<InputInstance>()
|
||||
const passwordRef = ref<InputInstance>()
|
||||
const userInfo = useAdminInfo()
|
||||
Local.remove(ADMIN_INFO)
|
||||
userInfo.removeToken()
|
||||
|
||||
interface RuleForm {
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
showCaptcha: false,
|
||||
submitLoading: false
|
||||
})
|
||||
const form = reactive({
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules<RuleForm>>({
|
||||
username: [{ required: true, trigger: 'blur', message: '请输入用户名' }],
|
||||
password: [{ required: true, trigger: 'blur', message: '请输入密码' }]
|
||||
})
|
||||
|
||||
const focusInput = () => {
|
||||
if (form.username === '') {
|
||||
usernameRef.value!.focus()
|
||||
} else if (form.password === '') {
|
||||
passwordRef.value!.focus()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
timer = window.setTimeout(() => {
|
||||
pageBubble.init()
|
||||
}, 0)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(timer)
|
||||
pageBubble.removeListeners()
|
||||
})
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
state.submitLoading = true
|
||||
login({
|
||||
username: form.username,
|
||||
password: form.password,
|
||||
grant_type: 'captcha',
|
||||
imageCode: '',
|
||||
verifyCode: 0
|
||||
})
|
||||
.then(res => {
|
||||
userInfo.dataFill(res.data)
|
||||
state.submitLoading = false
|
||||
router.push({
|
||||
path: '/'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.code === 'A0101' && err.message === '登录认证,密码失效,请重置') {
|
||||
popupUpdatePwdRef.value.open(form.username)
|
||||
}
|
||||
})
|
||||
setTimeout(() => {
|
||||
state.submitLoading = false
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bubble {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #003078 !important;
|
||||
background-position: center 110px;
|
||||
background-repeat: repeat;
|
||||
background-size: 100%;
|
||||
background-image: url(https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg);
|
||||
}
|
||||
|
||||
.login-image {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 20%;
|
||||
min-width: 45%;
|
||||
min-height: 80%;
|
||||
|
||||
background: url('../../assets/login/login2.png') no-repeat center center;
|
||||
background-size: contain;
|
||||
transform: translate(-15%, -50%);
|
||||
// box-shadow: 0 0 0 #011b2bab;
|
||||
}
|
||||
|
||||
.form-item-icon {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.login-container-form {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 85%;
|
||||
width: 500px;
|
||||
height: auto;
|
||||
border-radius: 30px;
|
||||
transform: translate(-85%, -50%);
|
||||
box-shadow: 3px 3px 2px 2px #011b2bab;
|
||||
|
||||
.title-container {
|
||||
position: relative;
|
||||
width: 398px;
|
||||
max-width: 100%;
|
||||
padding: 20px 0 0;
|
||||
margin: 0 auto;
|
||||
|
||||
.title {
|
||||
margin-bottom: 20px;
|
||||
font-size: 33px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
& :v-deep .svg-icon {
|
||||
// color: $;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-form {
|
||||
position: relative;
|
||||
width: 368px;
|
||||
max-width: 100%;
|
||||
//padding: 20px 0 0;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
|
||||
&.el-input {
|
||||
input {
|
||||
height: 40px;
|
||||
padding-right: 40px;
|
||||
padding-left: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.el-input__prefix,
|
||||
.el-input__suffix {
|
||||
width: 40px;
|
||||
line-height: 40px;
|
||||
|
||||
.svg-icon {
|
||||
font-size: 16px;
|
||||
vertical-align: -0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__prefix {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.copy-right {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
color: rgb(233, 229, 229);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:v-deep.el-form-item--large {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 20px;
|
||||
background: #4d6ea1;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 720px) {
|
||||
.login {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.login-box {
|
||||
width: 340px;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-height: 800px) {
|
||||
.login .login-box {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
213
src/views/user/logincopy.vue
Normal file
213
src/views/user/logincopy.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<div>
|
||||
<div @contextmenu.stop='' id='bubble' class='bubble'>
|
||||
<canvas id='bubble-canvas' class='bubble-canvas'></canvas>
|
||||
</div>
|
||||
<div class='login'>
|
||||
<div class='login-box'>
|
||||
<div class='head'>
|
||||
<img src='@/assets/login-header.png' alt='' />
|
||||
</div>
|
||||
<div class='form'>
|
||||
<img class='profile-avatar' src='@/assets/avatar.png' alt='' />
|
||||
<div class='content'>
|
||||
<el-form @keyup.enter='onSubmit()' ref='formRef' size='large' :model='form'>
|
||||
<el-form-item prop='username'>
|
||||
<el-input
|
||||
ref='usernameRef'
|
||||
type='text'
|
||||
clearable
|
||||
v-model='form.username'
|
||||
placeholder='请输入账号'
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon name='fa fa-user' class='form-item-icon' size='16'
|
||||
color='var(--el-input-icon-color)' />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop='password'>
|
||||
<el-input
|
||||
ref='passwordRef'
|
||||
v-model='form.password'
|
||||
type='password'
|
||||
placeholder='请输入密码'
|
||||
show-password
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon name='fa fa-unlock-alt' class='form-item-icon' size='16'
|
||||
color='var(--el-input-icon-color)' />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
:loading='state.submitLoading'
|
||||
class='submit-button'
|
||||
round
|
||||
type='primary'
|
||||
size='large'
|
||||
@click='onSubmit()'
|
||||
>
|
||||
登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
|
||||
import * as pageBubble from '@/utils/pageBubble'
|
||||
import type { FormInstance, InputInstance } from 'element-plus'
|
||||
|
||||
let timer: number
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const usernameRef = ref<InputInstance>()
|
||||
const passwordRef = ref<InputInstance>()
|
||||
const state = reactive({
|
||||
showCaptcha: false,
|
||||
submitLoading: false
|
||||
})
|
||||
const form = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
|
||||
const focusInput = () => {
|
||||
if (form.username === '') {
|
||||
usernameRef.value!.focus()
|
||||
} else if (form.password === '') {
|
||||
passwordRef.value!.focus()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
timer = window.setTimeout(() => {
|
||||
pageBubble.init()
|
||||
}, 1000)
|
||||
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(timer)
|
||||
pageBubble.removeListeners()
|
||||
})
|
||||
|
||||
const onSubmit = (captchaInfo = '') => {
|
||||
state.submitLoading = true
|
||||
setTimeout(() => {
|
||||
state.submitLoading = false
|
||||
}, 3000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang='scss'>
|
||||
.switch-language {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
overflow: hidden;
|
||||
background: url(@/assets/bg.jpg) repeat;
|
||||
}
|
||||
|
||||
.form-item-icon {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.login {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.login-box {
|
||||
overflow: hidden;
|
||||
width: 430px;
|
||||
padding: 0;
|
||||
background: var(--ba-bg-color-overlay);
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
.head {
|
||||
background: #ccccff;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 430px;
|
||||
margin: 0 auto;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
position: relative;
|
||||
|
||||
.profile-avatar {
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
border-radius: 50%;
|
||||
border: 4px solid var(--ba-bg-color-overlay);
|
||||
top: -50px;
|
||||
right: calc(50% - 50px);
|
||||
z-index: 2;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 100px 40px 40px 40px;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
letter-spacing: 2px;
|
||||
font-weight: 300;
|
||||
margin-top: 15px;
|
||||
--el-button-bg-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 720px) {
|
||||
.login {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.login-box {
|
||||
width: 340px;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chang-lang :deep(.el-dropdown-menu__item) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content :deep(.el-input__prefix) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media screen and (max-height: 800px) {
|
||||
.login .login-box {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
93
src/views/user/popupUpdatePwd.vue
Normal file
93
src/views/user/popupUpdatePwd.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
|
||||
<el-scrollbar>
|
||||
<el-form :inline="false" :model="form" label-width="120px" :rules="rules" ref="formRef">
|
||||
<el-form-item label="新密码:" prop="newPwd" style="margin-top: 20px">
|
||||
<el-input v-model="form.newPwd" type="password" placeholder="请输入新密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码:" prop="confirmPwd" style="margin-top: 20px">
|
||||
<el-input v-model="form.confirmPwd" type="password" placeholder="请输入确认密码" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submit">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { updateFirstPassword } from '@/api/user-boot/user'
|
||||
import { validatePwd } from '@/utils/common'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const title = ref('修改默认密码')
|
||||
const formRef = ref()
|
||||
// 注意不要和表单ref的命名冲突
|
||||
const form = reactive({
|
||||
newPwd: '',
|
||||
confirmPwd: '',
|
||||
loginName: ''
|
||||
})
|
||||
const rules = {
|
||||
newPwd: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: '长度在 6 到 16 个字符',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{ validator: validatePwd, trigger: 'blur' }
|
||||
],
|
||||
confirmPwd: [
|
||||
{ required: true, message: '请确认密码', trigger: 'blur' },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: '长度在 6 到 16 个字符',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请再次输入密码'))
|
||||
} else if (value !== form.newPwd) {
|
||||
callback(new Error('两次输入密码不一致!'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const open = (loginName: string) => {
|
||||
form.loginName = loginName
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submit = () => {
|
||||
formRef.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
updateFirstPassword({
|
||||
name: form.loginName,
|
||||
password: form.confirmPwd
|
||||
}).then((res: any) => {
|
||||
dialogVisible.value = false
|
||||
ElMessage.success('密码修改成功, 请重新登录')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
Reference in New Issue
Block a user