暂降治理评估

This commit is contained in:
2024-03-08 10:33:06 +08:00
parent 2191d2dc6b
commit 50bbba807f
13 changed files with 968 additions and 6 deletions

View File

@@ -22,6 +22,8 @@ npm run dev
* 命名风格所有的包文件夹、文件名以小驼峰的风格命名比如xxxAaa禁止XxxAaa或者xxx-aaa。
* 命名语义:禁止中文命名或拼音,英文命名借用下工具,稍微准确一点,不要与实际业务相差太远。
* 功能组件创建风格:以**功能名称**命名文件夹,每个功能下以**index.vue**作为该功能的组件入口。正确示例参考:/src/views/auth/menu/index.vue。
![组件层级图](./src/assets/readme/moduleLevel.png)
* todo...:待后续补充。

View File

@@ -0,0 +1,40 @@
import createAxios from '@/utils/request'
const ADVANCE_BOOT = '/advance-boot'
/**
* 新增业务用户
*/
export const addSgIncomingLine = (data: any) => {
return createAxios({
url: ADVANCE_BOOT + '/sgIncomingLine/add',
method: 'POST',
data: data
})
}
/**
* 更新业务用户
*/
export const updateSgIncomingLine = (data: any) => {
return createAxios({
url: ADVANCE_BOOT + '/sgIncomingLine/update',
method: 'POST',
data: data
})
}
/**
* 删除业务用户
*/
export const deleteSgIncomingLine = (data: any) => {
let ids = [data]
return createAxios({
url: ADVANCE_BOOT + '/sgIncomingLine/delete',
method: 'POST',
data: ids
})
}

View File

@@ -0,0 +1,40 @@
import createAxios from '@/utils/request'
const ADVANCE_BOOT = '/advance-boot'
/**
* 新增业务用户
*/
export const addSgUser = (data: any) => {
return createAxios({
url: ADVANCE_BOOT + '/sgUser/add',
method: 'POST',
data: data
})
}
/**
* 更新业务用户
*/
export const updateSgUser = (data: any) => {
return createAxios({
url: ADVANCE_BOOT + '/sgUser/update',
method: 'POST',
data: data
})
}
/**
* 删除业务用户
*/
export const deleteSgUser = (data: any) => {
let ids = [data]
return createAxios({
url: ADVANCE_BOOT + '/sgUser/delete',
method: 'POST',
data: ids
})
}

View File

@@ -0,0 +1,62 @@
import createAxios from '@/utils/request'
const SYSTEM_PREFIX = '/system-boot'
/**
* 上传文件
* @param file
*/
export const uploadFile = (file: any, path: string) => {
let form = new FormData()
form.append('file', file)
form.append('path', path)
return createAxios({
url: SYSTEM_PREFIX + '/file/upload',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
data: form
})
}
/**
* 删除文件
*/
export const deleteFile = (filePath: string) => {
let form = new FormData()
form.append('filePath', filePath)
return createAxios({
url: SYSTEM_PREFIX + '/file/delete',
method: 'POST',
data: form
})
}
/**
* 下载文件
*/
export const downloadFile = (filePath: string) => {
let form = new FormData()
form.append('filePath', filePath)
return createAxios({
url: SYSTEM_PREFIX + '/file/download',
method: 'GET'
})
}
/**
* 获取文件的短期url展示
*/
export const getFileUrl = (filePath: string) => {
let form = new FormData()
form.append('filePath', filePath)
return createAxios({
url: SYSTEM_PREFIX + '/file/getFileUrl',
method: 'POST'
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View File

@@ -0,0 +1,121 @@
<template>
<el-cascader
class='tags_cascader_input'
ref='areaCascader'
:options='options'
:props='isMultiple?baseMultipleCascader:baseCascader'
@change='change'
clearable
collapse-tags
collapse-tags-tooltip
/>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
const areaCascader = ref()
let areaValue = ref()
const change = (e: any) => {
areaValue = areaCascader.value.getCheckedNodes()
}
const options = [
{
value: '海口市',
label: '海口市',
children: [
{
value: '秀英区',
label: '秀英区',
children: [
{
value: '秀英区',
label: '秀英区',
children: []
},
{
value: '龙华区',
label: '龙华区',
children: []
},
{
value: '琼山区',
label: '琼山区',
children: []
}
]
},
{
value: '龙华区',
label: '龙华区',
children: []
},
{
value: '琼山区',
label: '琼山区',
children: []
}
]
},
{
value: '三亚市',
label: '三亚市',
children: [
{
value: '海棠区',
label: '海棠区',
children: []
},
{
value: '吉阳区',
label: '吉阳区',
children: []
},
{
value: '天涯区',
label: '天涯区',
children: []
}
]
}
]
// 区域联级下拉框配置,多选
const baseMultipleCascader = {
expandTrigger: 'hover' as const,
multiple: true
}
// 区域联级下拉框配置,单选
const baseCascader = {
expandTrigger: 'hover' as const
}
/*暴露areaValue、areaCascader*/
defineExpose({
areaCascader,
areaValue
})
/*定义参数给父组件*/
const props = defineProps({
//根据父组件传递是否多选,默认单选
isMultiple: Boolean
})
</script>
<style>
.tags_cascader_input {
height: 32px !important;
width: 350px;
}
.tags_cascader_input .el-input--suffix {
height: 32px !important;
width: 280px;
}
</style>

View File

@@ -24,6 +24,43 @@ export const adminBaseRoute = {
meta: {
title: `pagesTitle.loading`
}
},
// {
// path: 'businessUser/eventView',
// name: 'eventView',
// component: () => import('@/views/pqs/voltageSags/sagGovern/businessUser/eventView.vue'),
// meta: {
// title: `router.eventView`
// }
// },
// {
// path: 'businessUser/eventView',
// name: 'eventView',
// component: () => import('@/views/pqs/voltageSags/sagGovern/businessUser/index.vue'),
// meta: {
// title: `router.eventView`
// }
// },
{
path: 'businessUserRouter',
name: '业务管理员页面',
meta: {
title: pageTitle('businessUser'),
icon: 'ep:management',
alwaysShow: true
},
children: [
{
path: 'eventView',
component: () => import('@/views/pqs/voltageSags/sagGovern/businessUser/eventView.vue'),
name: '暂降事件查看页面',
meta: {
title: pageTitle('router.eventView')
}
}
]
}
]
}
@@ -56,7 +93,6 @@ const staticRoutes: Array<RouteRecordRaw> = [
redirect: '/404'
},
{
// 404
path: '/404',
name: 'notFound',
component: () => import('@/views/common/error/404.vue'),

View File

@@ -0,0 +1,97 @@
<!--进线管理界面-->
<template>
<div class='default-main'>
<TableHeader>
<template v-slot:operation>
<el-button type='primary' @click='add' class='ml10' :icon='Plus'>新增</el-button>
</template>
</TableHeader>
<!--表格-->
<Table ref='tableRef'></Table>
<!--弹框-->
<incoming-line-popup ref='incomingLinePopup' />
</div>
</template>
<script setup lang='ts'>
import { provide, ref } from 'vue'
import { Plus } from '@element-plus/icons-vue'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import IncomingLinePopup from './incomingLinePopup.vue'
import TableStore from '@/utils/tableStore'
import { ElMessage } from 'element-plus'
import { deleteSgIncomingLine } from '@/api/advance-boot/sgGroven/incomingLine'
//进线信息弹出框
const incomingLinePopup = ref()
const userId = ref()
const tableStore = new TableStore({
url: '',
method: 'GET',
publicHeight: 350,
showPage: false,
column: [
{ title: '序号', type: 'seq' },
{ title: '进线名称', field: 'name' },
{ title: '监测点名称', field: 'lineName' },
{
title: '操作',
align: 'center',
width: '150',
render: 'buttons',
buttons: [
{
name: 'update',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
click: row => {
incomingLinePopup.value.open('修改进线', row)
}
},
{
name: 'update',
title: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定删除吗?'
},
click: row => {
deleteSgIncomingLine(row.id).then(res => {
ElMessage.success('删除成功')
tableStore.index()
})
}
}
]
}
]
})
const getTableData = (tempId: string) => {
userId.value = tempId
tableStore.url = '/advance-boot/sgIncomingLine/list?userId=' + userId.value
tableStore.index()
}
/**********新增、编辑进线************/
//新增进线信息
const add = () => {
incomingLinePopup.value.open('新增进线', { userId: userId.value })
}
provide('tableStore', tableStore)
defineExpose({ getTableData })
</script>

View File

@@ -0,0 +1,20 @@
<template>
<h1>暂降事件查询</h1>
<h1>{{ id }}</h1>
<el-button type='primary' @click='go(-1)' class='ml10'>返回</el-button>
</template>
<script setup lang='ts'>
import { useRouter, useRoute } from 'vue-router'
import { ref } from 'vue'
import { Plus } from '@element-plus/icons-vue'
const { push, go } = useRouter()
const { query } = useRoute()
const id = ref()
const getTableDet = async () => {
id.value = query.id
}
getTableDet()
</script>

View File

@@ -0,0 +1,115 @@
<template>
<el-dialog class='cn-operate-dialog' v-model='incomingDialogVisible' :title='title'
style='max-width: 750px;width: 400px;height: 300px' top='30vh'>
<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' placeholder='请输入进线名称'/>
</el-form-item>
<el-form-item label='关联监测点' prop='lineId'>
<el-select v-model='form.lineId' placeholder='请选择关联监测点' :filterable='true'>
<el-option
v-for='line in lineList'
:key='line.id'
:label='line.name'
:value='line.id'
/>
</el-select>
</el-form-item>
</el-form>
</el-scrollbar>
<template #footer>
<span class='dialog-footer'>
<el-button @click='incomingDialogVisible = false'>取消</el-button>
<el-button type='primary' @click='submit'>确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang='ts' setup>
import { ref, inject, reactive} from 'vue'
import { ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import { addSgIncomingLine,updateSgIncomingLine } from '@/api/advance-boot/sgGroven/incomingLine' // 若不是列表页面弹框可删除
const incomingDialogVisible = ref(false)
const title = ref('')
const tableStore = inject('tableStore') as TableStore
const formRef = ref()
const lineList = reactive([
{
'id': '123456',
'name': '测试1号线'
},
{
'id': '01e796a4ffbd8de00c4ee9f34b49d7cb',
'name': '测试2号线'
},
{
'id': '1223456',
'name': '测试3号线'
}
])
// 注意不要和表单ref的命名冲突
const form = reactive({
id: '',
userId: '',
name: '',
lineId: ''
})
//form表单校验规则
const rules = {
name: [{ required: true, message: '进线名不能为空', trigger: 'blur' }],
lineId: [{ required: true, message: '监测点不能为空', trigger: 'change' }]
}
const resetForm = () => {
if (formRef.value) {
formRef.value.resetFields()
}
}
const open = (text: string, data: any) => {
title.value = text
//默认选中第一个tab
incomingDialogVisible.value = true
if (data.id) {
// 表单赋值
for (let key in form) {
form[key] = data[key]
}
} else {
resetForm()
// 在此处恢复默认表单
for (let key in form) {
form[key] = ''
}
}
form.userId = data.userId
}
const submit = () => {
formRef.value.validate(async (valid:any) => {
if (valid) {
if (form.id) {
await updateSgIncomingLine(form)
} else {
await addSgIncomingLine(form)
}
ElMessage.success('保存进线成功')
tableStore.index()
incomingDialogVisible.value = false
}
})
}
defineExpose({ open })
</script>
<style scoped>
.el-select {
min-width: 180px;
}
</style>

View File

@@ -0,0 +1,173 @@
<!--业务用户管理界面-->
<template>
<div class='default-main'>
<TableHeader>
<template v-slot:select>
<el-form-item label='关键词'>
<el-input
v-model='tableStore.table.params.searchValue'
clearable
placeholder='关键词模糊查询'
/>
</el-form-item>
<el-form-item label='区域'>
<area-cascard
ref='areaRef'
:isMultiple=true
v-model='tableStore.table.params.addr'
/>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type='primary' @click='add' class='ml10' :icon='Plus'>新增</el-button>
</template>
</TableHeader>
<!--表格-->
<Table ref='tableRef'></Table>
<!--弹框-->
<user-popup ref='userPopup' />
</div>
</template>
<script setup lang='ts'>
import { Plus } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import AreaCascard from '@/components/form/areaCascard/index.vue'
import { onMounted, provide, ref } from 'vue'
import { useRouter } from 'vue-router'
import { deleteSgUser } from '@/api/advance-boot/sgGroven/sgUser'
import UserPopup from './userPopup.vue'
const { push } = useRouter()
//区域联级选择
const areaRef = ref()
//用户信息弹出框
const userPopup = ref()
const tableStore = new TableStore({
url: '/advance-boot/sgUser/list',
method: 'POST',
column: [
{ title: '序号', type: 'seq' },
{ title: '用户名', field: 'userName' },
{ title: '所属行业', field: 'industry' },
{ title: '所属地区', field: 'addr' },
{ title: '产线数', width: '130', field: 'productCount' },
{ title: '进线数', width: '130', field: 'lineCount' },
{
title: '暂降数据',
align: 'center',
width: '180',
render: 'buttons',
buttons: [
{
name: 'view',
title: '查看',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
click: async row => {
push(`/admin/businessUserRouter/eventView?id=${row.id}`)
}
},
{
name: 'import',
title: '导入',
type: 'primary',
icon: 'el-icon-Delete',
render: 'basicButton'
// click: row => {
// delNode(row.id).then(res => {
// ElMessage.success('删除成功')
// tableStore.index()
// })
// }
}
]
},
{
title: '操作',
align: 'center',
width: '230',
render: 'buttons',
buttons: [
{
name: 'productSetting',
title: '生产线设置',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton'
// click: async row => {
// dialogFormVisible.value = true
// dialogTitle.value = '前置机修改'
// formData.value = JSON.parse(JSON.stringify(row))
// }
},
{
name: 'update',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
click: row => {
userPopup.value.open('修改用户', row)
}
},
{
name: 'update',
title: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定删除吗?'
},
click: row => {
deleteSgUser(row.id).then(res => {
ElMessage.success('删除成功')
tableStore.index()
})
}
}
]
}
],
beforeSearchFun: () => {
if (tableStore.table.params.addr) {
tableStore.table.params.addrStrOption = tableStore.table.params.addr.map(tempArray => tempArray.join('/'))
}
for (let key in tableStore.table.params) {
if (tableStore.table.params[key] === '') {
delete tableStore.table.params[key]
}
}
}
})
onMounted(() => {
// 加载数据
tableStore.index()
})
tableStore.table.params.orderBy = 'desc'
tableStore.table.params.searchValue = ''
tableStore.table.params.addr = []
provide('tableStore', tableStore)
//新增用户信息
const add = () => {
userPopup.value.open('新增用户')
}
</script>

View File

@@ -0,0 +1,258 @@
<template>
<el-dialog class='cn-operate-dialog' v-model='dialogVisible' :title='title' style='max-width: 750px'>
<el-scrollbar>
<el-form :inline='false' :model='form' label-width='120px' :rules='rules' ref='formRef'>
<el-tabs tab-position='left' style='height: 100%' :before-leave='checkUserId' v-model='tab'>
<el-tab-pane label='基本信息' name='user'>
<el-form-item label='用户名' prop='userName'>
<el-input v-model='form.userName' />
</el-form-item>
<el-row>
<el-col :span='12'>
<el-form-item label='重点用户'>
<el-select v-model='form.keyUser'>
<el-option label='重要' value='1' />
<el-option label='不重要' value='0' />
</el-select>
</el-form-item>
</el-col>
<el-col :span='12'>
<el-form-item label='所属行业' prop='industry'>
<el-input v-model='form.industry' />
</el-form-item>
</el-col>
</el-row>
<el-form-item label='所在地区' prop='addr'>
<area-cascard
v-model='form.addr'
@change='reValueAddr'
ref='areaRef'
/>
</el-form-item>
<el-form-item label='详细地址'>
<el-input v-model='form.addrDetail' />
</el-form-item>
<el-form-item label='联系方式'>
<el-input v-model='form.concact' />
</el-form-item>
<el-form-item label='用户描述'>
<el-input v-model='form.remark' :rows='2' type='textarea' placeholder='请输入描述' />
</el-form-item>
<el-form-item label='企业照片'>
<el-upload
action=''
v-model:file-list='fileList'
list-type='picture-card'
:auto-upload='false'
:limit='1'
accept='.png,.jpg'
:on-change='chooseImage'
:on-remove='handleRemove'
:before-upload='beforeAvatarUpload'
:on-preview='handlePictureCardPreview'
>
<el-icon>
<Plus />
</el-icon>
</el-upload>
<el-dialog v-model='dialogVisibleLogo'>
<img w-full :src='fileList[0].url' alt='预览图片' />
</el-dialog>
</el-form-item>
</el-tab-pane>
<el-tab-pane label='进线' name='incomingLine'>
<IncomingTable ref='incomingTable'></IncomingTable>
</el-tab-pane>
<el-tab-pane label='生产线' name='productLine'>
生产线
</el-tab-pane>
</el-tabs>
</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, onMounted, reactive, provide, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import type { UploadProps, UploadUserFile } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import TableStore from '@/utils/tableStore' // 若不是列表页面弹框可删除
import AreaCascard from '@/components/form/areaCascard/index.vue'
import { uploadFile, deleteFile } from '@/api/system-boot/file'
import { addSgUser, updateSgUser } from '@/api/advance-boot/sgGroven/sgUser'
import IncomingTable from './IncomingTable.vue'
const dialogVisible = ref(false)
const title = ref('')
const tableStore = inject('tableStore') as TableStore
const areaRef = ref()
const formRef = ref()
const tab = ref('user')
//进线表格子组件
const incomingTable = ref()
const fileList = ref<UploadUserFile[]>([])
const dialogVisibleLogo = ref(false)
// 注意不要和表单ref的命名冲突
const form = reactive({
id: '',
userName: '',
keyUser: '',
industry: '',
addr: [],
addrStrOption: '',
addrDetail: '',
concact: '',
remark: '',
userLogo: ''
})
//form表单校验规则
const rules = {
userName: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
industry: [{ required: true, message: '所属行业不能为空', trigger: 'blur' }],
addr: [{ required: true, message: '所在地区不能为空', trigger: 'change' }]
}
const resetForm = () => {
if (formRef.value) {
formRef.value.resetFields()
}
}
const open = (text: string, data?: anyObj) => {
tab.value = 'user'
title.value = text
//默认选中第一个tab
dialogVisible.value = true
if (data) {
// 表单赋值
for (let key in form) {
form[key] = data[key]
}
form.addr = data.addr.split('/')
form.keyUser = String(data.keyUser)
//待子组件渲染完毕
nextTick(() => {
incomingTable.value.getTableData(form.id)
})
} else {
resetForm()
// 在此处恢复默认表单
for (let key in form) {
form[key] = ''
}
form.keyUser = '1'
}
}
/**
* 将联级选择的区域数组转为字符串
*/
const reValueAddr = () => {
form.addrStrOption = form.addr.join('/')
console.log(form.addrStrOption)
}
/**
* 选择图片上传
* @param e
*/
const chooseImage = (e: any) => {
fileList.value = []
uploadFile(e.raw, 'sgGovern/').then(res => {
fileList.value[0].name = res.data.name
fileList.value[0].url = res.data.url
form.userLogo = res.data.name
ElMessage.success('新增成功')
})
}
/**
* 上传文件之前
*/
const beforeAvatarUpload = () => {
fileList.value = []
}
/**
* 删除文件操作
*/
const handleRemove = (e: any, fileList: any) => {
form.userLogo = ''
fileList.value = []
deleteFile(e.name).then(res => {
ElMessage.success('删除成功')
})
}
/**
* 预览图片
*/
const handlePictureCardPreview = () => {
dialogVisibleLogo.value = true
}
/**
* 提交用户表单数据
*/
const submit = () => {
formRef.value.validate(async (valid: any) => {
if (valid) {
if (form.id) {
await updateSgUser(form)
} else {
await addSgUser(form).then(res => {
form.id = res.data
//查询进线数据避免一直处于loading状态
incomingTable.value.getTableData(form.id)
})
}
ElMessage.success('保存成功')
console.log(form)
tableStore.index()
dialogVisible.value = true
}
})
}
/************针对tab切换*************/
const checkUserId = (tab: any, event: any) => {
if (tab == 'user') {
return true
}
if (form.id) {
return true
} else {
ElMessage.error('请先创建用户基础信息!')
return false
}
}
defineExpose({ open })
</script>
<style scoped>
.el-upload-list__item {
transition: none !important;
}
.el-select {
min-width: 180px;
}
</style>

View File

@@ -11,16 +11,14 @@ export default defineConfig({
host: '0.0.0.0',
proxy: {
'/api': {
// target: 'http://192.168.1.81:10215', //数据中心
target: 'http://192.168.1.31:10215', //数据中心
target: 'http://192.168.1.125:10215', //数据中心
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '') //路径重写,把'/api'替换为''
},
'/map': {
target: 'http://192.168.1.81:8088', //数据中心
target: 'http://192.168.1.125:8088', //数据中心
changeOrigin: true,
},
}
}
},
resolve: {