修改测试bug 优化页面
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="dialogVisible" title="自定义功能管理" width="600">
|
||||
<el-dialog v-model="dialogVisible" title="自定义功能管理" width="650">
|
||||
<div style="display: flex; justify-content: end" class="mb10">
|
||||
<el-button icon="el-icon-Plus" type="primary" @click="add">新增</el-button>
|
||||
</div>
|
||||
<div style="height: calc(100vh / 2); max-height: 400px">
|
||||
<div style="height: 300px; max-height: 400px">
|
||||
<vxe-table
|
||||
border
|
||||
ref="tableRef"
|
||||
@@ -25,6 +25,7 @@
|
||||
<el-switch
|
||||
v-model="row.state"
|
||||
inline-prompt
|
||||
:disabled="!hasAdmin && row.scope"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="已激活"
|
||||
@@ -33,11 +34,29 @@
|
||||
/>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="startTime" title="是否全局" v-if="hasAdmin">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.scope"
|
||||
inline-prompt
|
||||
:active-value="1"
|
||||
width="50px"
|
||||
:inactive-value="0"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
:before-change="() => beforeChange1(row)"
|
||||
/>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="startTime" title="操作">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="edit(row)">编辑</el-button>
|
||||
<el-button type="primary" link @click="edit(row)" v-if="!(!hasAdmin && row.scope)">
|
||||
编辑
|
||||
</el-button>
|
||||
|
||||
<el-button type="danger" link @click="deletes(row)">删除</el-button>
|
||||
<el-button type="danger" link @click="deletes(row)" v-if="!(!hasAdmin && row.scope)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
@@ -49,18 +68,20 @@
|
||||
import { ref, reactive } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
import { getDashboardPageByUserId, deleteDashboard, activatePage } from '@/api/system-boot/csstatisticalset'
|
||||
import { getDashboardPageByUserId, deleteDashboard, activatePage, scopePage } from '@/api/system-boot/csstatisticalset'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
import { getMenu } from '@/utils/router'
|
||||
|
||||
const { push } = useRouter()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const route = useRouter()
|
||||
const navTabs = useNavTabs()
|
||||
const adminInfo = useAdminInfo()
|
||||
const pageList: any = ref([])
|
||||
const hasAdmin = adminInfo.roleCode.some(item => item.includes('operation_manager') || item.includes('root'))
|
||||
|
||||
const open = () => {
|
||||
dialogVisible.value = true
|
||||
@@ -68,7 +89,10 @@ const open = () => {
|
||||
}
|
||||
const init = () => {
|
||||
getDashboardPageByUserId({ id: adminInfo.id, state: false }).then(res => {
|
||||
pageList.value = res.data
|
||||
pageList.value = res.data.filter(item => {
|
||||
item.scope = item.userId == '0' ? 1 : 0
|
||||
return item
|
||||
})
|
||||
})
|
||||
}
|
||||
// 新增
|
||||
@@ -93,7 +117,7 @@ const beforeChange = (row: any): Promise<boolean> => {
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
activatePage({ id: row.id, state: row.state == 0 ? 1 : 0 }).then( async(res: any) => {
|
||||
activatePage({ id: row.id, state: row.state == 0 ? 1 : 0 }).then(async (res: any) => {
|
||||
if (res.code == 'A0000') {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
@@ -102,19 +126,45 @@ const beforeChange = (row: any): Promise<boolean> => {
|
||||
}
|
||||
init()
|
||||
resolve(true)
|
||||
await getMenu()
|
||||
await setTimeout(() => {
|
||||
navTabs.refresh()
|
||||
await getMenu()
|
||||
await setTimeout(() => {
|
||||
navTabs.refresh()
|
||||
}, 1000)
|
||||
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '已取消删除'
|
||||
.catch(() => {})
|
||||
})
|
||||
}
|
||||
// 全局
|
||||
const beforeChange1 = (row: any): Promise<boolean> => {
|
||||
return new Promise(resolve => {
|
||||
// setTimeout(() => {
|
||||
// loading1.value = false
|
||||
// ElMessage.success('Switch success')
|
||||
// return resolve(true)
|
||||
// }, 1000)
|
||||
ElMessageBox.confirm('此操作将页面配置成全局, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
scopePage({ id: row.id, userId: row.scope == 0 ? '0' : adminInfo.id }).then(async (res: any) => {
|
||||
if (res.code == 'A0000') {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '操作成功!'
|
||||
})
|
||||
}
|
||||
init()
|
||||
resolve(true)
|
||||
await getMenu()
|
||||
await setTimeout(() => {
|
||||
navTabs.refresh()
|
||||
}, 1000)
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
})
|
||||
}
|
||||
// 删除
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-slot:operation>
|
||||
<el-button type="primary" icon="el-icon-Edit" @click="editd">编辑</el-button>
|
||||
<el-button type="primary" icon="el-icon-Edit" v-if="hasAdmin || adminInfo.id == userId" @click="editd">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-Tools"
|
||||
@@ -46,7 +48,13 @@
|
||||
{{ (item as LayoutItem).name }}
|
||||
</div>
|
||||
<!-- <FullScreen class="HelpFilled" style="cursor: pointer" @click="setZoom(item)" /> -->
|
||||
<img :src="flag ? img : img1" style="cursor: pointer; height: 16px" @click="setZoom(item)" />
|
||||
<span style="display: flex; align-items: center">
|
||||
<img
|
||||
:src="flag ? img : img1"
|
||||
style="cursor: pointer; height: 16px"
|
||||
@click="setZoom(item)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<component
|
||||
@@ -82,12 +90,15 @@ import { queryActivatePage, queryByPagePath } from '@/api/system-boot/csstatisti
|
||||
import RoutingConfig from '@/views/pqs/cockpit/homePage/components/routingConfig.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useTimeCacheStore } from '@/stores/timeCache'
|
||||
import { Sort } from '@element-plus/icons-vue'
|
||||
const { push } = useRouter()
|
||||
const datePickerRef = ref()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const timeCacheStore = useTimeCacheStore()
|
||||
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
const adminInfo = useAdminInfo()
|
||||
const hasAdmin = adminInfo.roleCode.some(item => item.includes('operation_manager') || item.includes('root'))
|
||||
defineOptions({
|
||||
// name: 'dashboard/index'
|
||||
})
|
||||
@@ -109,6 +120,7 @@ interface LayoutItem {
|
||||
}
|
||||
const zoom = ref(1)
|
||||
const RoutingConfigRef = ref()
|
||||
const userId = ref('')
|
||||
const key = ref(0)
|
||||
const img = new URL(`@/assets/img/amplify.png`, import.meta.url).href
|
||||
const img1 = new URL(`@/assets/img/reduce.png`, import.meta.url).href
|
||||
@@ -219,6 +231,7 @@ const seRowHeight = (value: any) => {
|
||||
const fetchLayoutData = async () => {
|
||||
try {
|
||||
const { data } = await queryByPagePath({ pagePath: router.currentRoute.value.name })
|
||||
userId.value = data.userId
|
||||
dataList.value = data
|
||||
const parsedLayout = JSON.parse(data.containerConfig || '[]') as LayoutItem[]
|
||||
// 处理布局数据
|
||||
|
||||
146
src/views/pqs/cockpit/realTimeData/bind.vue
Normal file
146
src/views/pqs/cockpit/realTimeData/bind.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="cn-operate-dialog"
|
||||
width="1200px"
|
||||
append-to-body
|
||||
v-model.trim="dialogVisible"
|
||||
title="绑定"
|
||||
>
|
||||
<el-form ref="formRef" label-width="80px" class="form">
|
||||
<el-form-item label="项目名称">
|
||||
<el-input
|
||||
maxlength="32"
|
||||
show-word-limit
|
||||
clearable
|
||||
style="width: 240px"
|
||||
v-model.trim="searchValue"
|
||||
placeholder="请输入项目名称"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="info" icon="el-icon-Search">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="height: calc(60vh - 120px); overflow-y: auto" v-loading="loading">
|
||||
<el-row :gutter="10" style="width: 100%; margin: auto">
|
||||
<el-col :span="6" v-for="item in list" :key="item.id" class="mt10">
|
||||
<el-card class="box-card" shadow="hover">
|
||||
<div slot="header" class="clearfix mb10">
|
||||
<span style="display: flex; align-items: center;justify-content: space-between;">
|
||||
{{ item.name }}
|
||||
|
||||
<!-- <el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="绑定实时数据"
|
||||
placement="top"
|
||||
v-if="bindId != item.id"
|
||||
>
|
||||
<Sort
|
||||
style="margin-left: 5px; width: 16px"
|
||||
class="xiaoshou color"
|
||||
@click="activate(item)"
|
||||
/>
|
||||
</el-tooltip> -->
|
||||
<el-button type="primary" v-if="bindId != item.id" @click="activate(item)" icon="el-icon-Sort" link>绑定</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<img v-if="item.fileContent" :src="item.fileContent" class="image" />
|
||||
<el-empty v-else description="暂无设计" style="height: 220px" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, inject } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import { coFqueryPage, getByUserId, savePageIdWithUser } from '@/api/cs-harmonic-boot/mxgraph'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { Sort } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
const adminInfo = useAdminInfo()
|
||||
const emit = defineEmits(['bindClick'])
|
||||
const dialogVisible = ref(false)
|
||||
const searchValue = ref('')
|
||||
const bindId = ref('')
|
||||
const list = ref([])
|
||||
const loading = ref(false)
|
||||
const open = (text: string, data: anyObj) => {
|
||||
searchValue.value = ''
|
||||
list.value = []
|
||||
info()
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const info = () => {
|
||||
loading.value = true
|
||||
getBindId()
|
||||
coFqueryPage({
|
||||
currentUserId: adminInfo.id,
|
||||
roleCode: adminInfo.roleCode.join(','),
|
||||
searchValue: searchValue.value,
|
||||
pageNum: 1,
|
||||
pageSize: 1000
|
||||
})
|
||||
.then(res => {
|
||||
list.value = res.data.records
|
||||
loading.value = false
|
||||
})
|
||||
.catch(err => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
const getBindId = () => {
|
||||
getByUserId({ userId: adminInfo.id }).then(res => {
|
||||
bindId.value = res.data.pageId
|
||||
})
|
||||
}
|
||||
const activate = (e: any) => {
|
||||
ElMessageBox.confirm('是否绑定页面?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
savePageIdWithUser({ pageId: e.id, userId: adminInfo.id }).then(res => {
|
||||
if (res.code == 'A0000') {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '操作成功'
|
||||
})
|
||||
bindId.value = e.id
|
||||
emit('bindClick', bindId.value)
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 35px;
|
||||
}
|
||||
.image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
.xiaoshou {
|
||||
cursor: pointer;
|
||||
}
|
||||
.color {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.box-card {
|
||||
width: 100%;
|
||||
// border: 1px solid #000;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
}
|
||||
:deep(.el-card__body) {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -12,6 +12,8 @@
|
||||
style="position: relative"
|
||||
>
|
||||
<iframe
|
||||
v-if="bindId"
|
||||
:key="bindId"
|
||||
:src="iframeSrc"
|
||||
width="100%"
|
||||
height="100%"
|
||||
@@ -20,6 +22,7 @@
|
||||
id="iframeLeft"
|
||||
@load="onIframeLoad"
|
||||
></iframe>
|
||||
<el-empty v-else description="暂无绑定页面" style="height: 100%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-container">
|
||||
@@ -28,13 +31,15 @@
|
||||
:icon="show ? 'el-icon-ArrowDownBold' : 'el-icon-ArrowUpBold'"
|
||||
@click="show = !show"
|
||||
style="width: 100%"
|
||||
v-if="bindId"
|
||||
>
|
||||
事件列表
|
||||
</el-button>
|
||||
<el-button class="bindBut" type="primary" icon="el-icon-Sort" @click="bindClick">绑定</el-button>
|
||||
<!-- <div class="buttonBox">
|
||||
<el-button type="primary" icon="el-icon-Aim" @click="reset">复位</el-button>
|
||||
</div> -->
|
||||
|
||||
|
||||
<transition name="table-fade">
|
||||
<div class="tableBox" v-if="show">
|
||||
<vxe-table border auto-resize height="230px" :data="tableData" ref="tableRef">
|
||||
@@ -46,6 +51,8 @@
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<!--绑定实时数据 -->
|
||||
<Bind ref="bindRef" @bindClick="info" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -53,11 +60,16 @@ import { ref, watch, onMounted, onUnmounted, provide } from 'vue'
|
||||
import Table from '@/components/table/index.vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { audit, add, coFqueryPage, getByUserId } from '@/api/cs-harmonic-boot/mxgraph'
|
||||
import Bind from './bind.vue'
|
||||
// import { getActive } from "@/api/manage_wx/index";
|
||||
|
||||
// const props = defineProps<{
|
||||
// project: { id: string; name: string } | null
|
||||
// }>()
|
||||
const adminInfo = useAdminInfo()
|
||||
const show = ref(false)
|
||||
const prop = defineProps({
|
||||
width: { type: [String, Number] },
|
||||
@@ -65,10 +77,9 @@ const prop = defineProps({
|
||||
timeKey: { type: Array as () => string[] },
|
||||
timeValue: { type: Object }
|
||||
})
|
||||
|
||||
const tableData = ref([
|
||||
|
||||
])
|
||||
const bindRef = ref()
|
||||
const tableData = ref([])
|
||||
const bindId = ref('')
|
||||
|
||||
// 在父页面中添加事件监听器
|
||||
window.addEventListener('message', function (event) {
|
||||
@@ -83,6 +94,9 @@ window.addEventListener('message', function (event) {
|
||||
const tableRef = ref()
|
||||
|
||||
const pageHeight = mainHeight(40)
|
||||
const bindClick = () => {
|
||||
bindRef.value.open()
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
// 向 iframe 发送复位事件
|
||||
@@ -128,15 +142,10 @@ const iframeSrc = ref('')
|
||||
// { immediate: true, deep: true }
|
||||
// )
|
||||
|
||||
onMounted(() => {
|
||||
iframeSrc.value =
|
||||
window.location.origin + `/zutai/?id=4b4f7f4260198776594f5f9d93a532e8&&name=stt&&preview=true#/preview_YPT`
|
||||
|
||||
onMounted(async () => {
|
||||
info()
|
||||
// tableStore.index()
|
||||
|
||||
// 监听来自 eventStatistics 组件的消息
|
||||
window.addEventListener('message', handleMessage)
|
||||
|
||||
// getActive({}).then((res: any) => {
|
||||
// if (res.code == "A0000") {
|
||||
// // window.location.origin
|
||||
@@ -148,7 +157,31 @@ onMounted(() => {
|
||||
// }
|
||||
// });
|
||||
})
|
||||
|
||||
const info = async () => {
|
||||
iframeSrc.value = ''
|
||||
await getByUserId({ userId: adminInfo.id })
|
||||
.then(res => {
|
||||
bindId.value = res.data.pageId
|
||||
})
|
||||
.catch(async err => {
|
||||
// bindId.value = '4b4f7f4260198776594f5f9d93a532e8'
|
||||
await coFqueryPage({
|
||||
currentUserId: adminInfo.id,
|
||||
roleCode: adminInfo.roleCode.join(','),
|
||||
searchValue: '',
|
||||
pageNum: 1,
|
||||
pageSize: 1000
|
||||
}).then(res => {
|
||||
bindId.value = res.data.records.filter(item => item.scope == 1)[0]?.id || null
|
||||
|
||||
})
|
||||
})
|
||||
await setTimeout(() => {
|
||||
iframeSrc.value = window.location.origin + `/zutai/?id=${bindId.value}&&name=stt&&preview=true#/preview_YPT`
|
||||
// iframeSrc.value = `http://192.168.2.128:4001/zutai/?id=${bindId.value}&&name=stt&&preview=true#/preview_YPT`
|
||||
window.addEventListener('message', handleMessage)
|
||||
}, 0)
|
||||
}
|
||||
onUnmounted(() => {
|
||||
// 清理事件监听器
|
||||
window.removeEventListener('message', handleMessage)
|
||||
@@ -258,4 +291,9 @@ const sendKeysToIframe = (keyList: string[]) => {
|
||||
.table-fade-enter-active {
|
||||
transition-delay: 0.05s;
|
||||
}
|
||||
.bindBut {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: -35px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,136 +1,195 @@
|
||||
<template>
|
||||
<div class="pd10">
|
||||
<el-card>
|
||||
<el-form ref="formRef" inline :rules="rules" :model="form" label-width="auto" class="form-four">
|
||||
<el-form-item label="页面名称" prop="pageName">
|
||||
<el-input
|
||||
style="width: 100%"
|
||||
maxlength="32"
|
||||
show-word-limit
|
||||
v-model.trim="form.pageName"
|
||||
placeholder="请输入页面名称"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标">
|
||||
<IconSelector v-model.trim="form.icon" style="width: 80%" placeholder="请选择图标" />
|
||||
</el-form-item>
|
||||
<el-form-item label="页面排序" prop="sort">
|
||||
<el-input-number style="width: 100%" v-model.trim="form.sort" :min="0" :max="10000" :step="1" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="是否激活">
|
||||
|
||||
<el-switch
|
||||
v-model="form.state"
|
||||
inline-prompt
|
||||
:disabled="form.pagePath == 'dashboard/index'"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" class="top">
|
||||
<el-input
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
type="textarea"
|
||||
:rows="1"
|
||||
placeholder="请输入内容"
|
||||
v-model.trim="form.remark"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="width: 100%; display: flex; justify-content: end">
|
||||
<el-button type="primary" icon="el-icon-Check" @click="onSubmit">保存</el-button>
|
||||
<back-component />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-card class="mt10" :style="height">
|
||||
<div style="display: flex">
|
||||
<div style="width: 605px; overflow: auto" :style="indicatorHeight" class="mr10">
|
||||
<el-collapse v-model="activeNames" :expand-icon-position="position">
|
||||
<el-collapse-item
|
||||
v-for="item in treeComponents"
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:name="item.id"
|
||||
>
|
||||
<el-collapse v-model="activeNames1" class="ml20">
|
||||
<el-collapse-item v-for="k in item.children" :key="k.id" :title="k.name" :name="k.id">
|
||||
<div class="Box">
|
||||
<div
|
||||
v-for="(s, index) in k.children"
|
||||
:key="index"
|
||||
class="mr10 mb10 imgBox"
|
||||
draggable="true"
|
||||
unselectable="on"
|
||||
@drag="drag(s)"
|
||||
@dragend="dragEnd(s)"
|
||||
>
|
||||
<div class="textName">{{ s.name }}</div>
|
||||
<img :src="s.image" style="width: 180px" />
|
||||
<div class="default-main pd10">
|
||||
<div style="width: 100%; display: flex; justify-content: end">
|
||||
<el-button type="primary" icon="el-icon-Check" @click="onSubmit">保存</el-button>
|
||||
<back-component />
|
||||
</div>
|
||||
<div style="display: flex" class="mt10">
|
||||
<!-- <el-tabs type="border-card">
|
||||
<el-tab-pane label="组件">
|
||||
<div style="width: 520px; overflow: auto" :style="indicatorHeight" class="mr10">
|
||||
<el-collapse v-model="activeNames" :expand-icon-position="position">
|
||||
<el-collapse-item
|
||||
v-for="item in treeComponents"
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:name="item.id"
|
||||
>
|
||||
<el-collapse v-model="activeNames1" class="ml20">
|
||||
<el-collapse-item
|
||||
v-for="k in item.children"
|
||||
:key="k.id"
|
||||
:title="k.name"
|
||||
:name="k.id"
|
||||
>
|
||||
<div class="Box">
|
||||
<div
|
||||
v-for="(s, index) in k.children"
|
||||
:key="index"
|
||||
class="mr10 mb10 imgBox"
|
||||
draggable="true"
|
||||
unselectable="on"
|
||||
@drag="drag(s)"
|
||||
@dragend="dragEnd(s)"
|
||||
>
|
||||
<div class="textName">{{ s.name }}</div>
|
||||
<img :src="s.image" style="width: 150px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
<div style="flex: 1" ref="wrapper">
|
||||
<GridLayout
|
||||
class="GridLayout"
|
||||
ref="gridLayout"
|
||||
v-model:layout="layout"
|
||||
style="width: 100%"
|
||||
:style="{ height: GridHeight + 'px' }"
|
||||
:row-height="rowHeight"
|
||||
:col-num="12"
|
||||
prevent-collision
|
||||
:vertical-compact="false"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div class="imgBox">
|
||||
<div class="textName">{{ item.name }}</div>
|
||||
|
||||
<img
|
||||
:src="getImg(item.path)"
|
||||
:style="{
|
||||
height:
|
||||
item.h * rowHeight -
|
||||
(item.h == 1
|
||||
? 30
|
||||
: item.h == 2
|
||||
? 20
|
||||
: item.h == 3
|
||||
? 10
|
||||
: item.h == 4
|
||||
? -0
|
||||
: item.h == 5
|
||||
? -10
|
||||
: -20) +
|
||||
'px'
|
||||
}"
|
||||
/>
|
||||
|
||||
<CloseBold class="remove" @click="removeItem(item.i)" />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs> -->
|
||||
<el-tabs v-model="tableName" type="border-card" @tab-change="changeTab">
|
||||
<el-tab-pane v-for="item in treeComponents" :key="item.name" :label="item.name" :name="item.name">
|
||||
<el-tabs v-model="tableName1" tab-position="top">
|
||||
<el-tab-pane v-for="k in item?.children" :key="k.name" :label="k.name" :name="k.name">
|
||||
<div :style="indicatorHeight" style="overflow-y: auto; overflow-x: hidden">
|
||||
<el-row :gutter="10" class="pl5 pr5 pt5" style="width: 520px">
|
||||
<el-col :span="8" v-for="component in k.children" :key="component.id" class="mb10">
|
||||
<el-card
|
||||
class="box-card"
|
||||
shadow="hover"
|
||||
@drag="drag(component)"
|
||||
@dragend="dragEnd(component)"
|
||||
>
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="display: flex; align-items: center">
|
||||
{{ component.name }}
|
||||
</span>
|
||||
</div>
|
||||
<img v-if="component.image" :src="component.image" class="image xiaoshou" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- <span class="text">{{ `${item?.name}` }}</span>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div style="flex: 1" ref="wrapper" class="ml10">
|
||||
<el-tabs type="border-card" class="mb10">
|
||||
<el-tab-pane label="基础信息">
|
||||
<el-form ref="formRef" inline :rules="rules" :model="form" label-width="auto" class="form-four">
|
||||
<el-form-item label="页面名称" prop="pageName">
|
||||
<el-input
|
||||
style="width: 100%"
|
||||
maxlength="32"
|
||||
show-word-limit
|
||||
v-model.trim="form.pageName"
|
||||
placeholder="请输入页面名称"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标">
|
||||
<IconSelector v-model.trim="form.icon" placeholder="请选择图标" />
|
||||
</el-form-item>
|
||||
<el-form-item label="页面排序" prop="sort">
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
v-model.trim="form.sort"
|
||||
:min="0"
|
||||
:max="10000"
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="是否激活">
|
||||
<el-switch
|
||||
v-model="form.state"
|
||||
inline-prompt
|
||||
width="60px"
|
||||
:disabled="form.pagePath == 'dashboard/index'"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="是 "
|
||||
inactive-text="否 "
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否全局" v-if="hasAdmin">
|
||||
<el-switch
|
||||
v-model="form.scope"
|
||||
inline-prompt
|
||||
width="60px"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
:disabled="form.pagePath == 'dashboard/index'"
|
||||
active-text="是 "
|
||||
inactive-text="否 "
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="top">
|
||||
<el-input
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
style="width: 100%"
|
||||
type="textarea"
|
||||
:rows="1"
|
||||
placeholder="请输入内容"
|
||||
v-model.trim="form.remark"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item></el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div ref="PaneRef">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="画布" :style="height">
|
||||
<GridLayout
|
||||
class="GridLayout"
|
||||
ref="gridLayout"
|
||||
v-model:layout="layout"
|
||||
style="width: 100%"
|
||||
:style="{ height: GridHeight + 'px' }"
|
||||
:row-height="rowHeight"
|
||||
:col-num="12"
|
||||
prevent-collision
|
||||
:is-bounded="true"
|
||||
:vertical-compact="false"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div class="imgBox">
|
||||
<div class="textName">{{ item.name }}</div>
|
||||
|
||||
<img
|
||||
:src="getImg(item.path)"
|
||||
:style="{
|
||||
height:
|
||||
item.h * rowHeight -
|
||||
(item.h == 1
|
||||
? 30
|
||||
: item.h == 2
|
||||
? 20
|
||||
: item.h == 3
|
||||
? 10
|
||||
: item.h == 4
|
||||
? -0
|
||||
: item.h == 5
|
||||
? -10
|
||||
: -20) +
|
||||
'px'
|
||||
}"
|
||||
/>
|
||||
|
||||
<CloseBold class="remove" @click="removeItem(item.i)" />
|
||||
</div>
|
||||
<!-- <span class="text">{{ `${item?.name}` }}</span>
|
||||
-->
|
||||
</template>
|
||||
</GridLayout>
|
||||
</template>
|
||||
</GridLayout>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import BackComponent from '@/components/icon/back/index.vue'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
@@ -145,17 +204,22 @@ import { addDashboard, updateDashboard, queryById } from '@/api/system-boot/csst
|
||||
import html2canvas from 'html2canvas'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getMenu } from '@/utils/router'
|
||||
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
const tableName = ref('')
|
||||
const tableName1 = ref('')
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
// defineOptions({
|
||||
// name: 'cockpit/popup'
|
||||
// })
|
||||
const adminInfo = useAdminInfo()
|
||||
const hasAdmin = adminInfo.roleCode.some(item => item.includes('operation_manager') || item.includes('root'))
|
||||
|
||||
const { go } = useRouter()
|
||||
const navTabs = useNavTabs()
|
||||
const { query } = useRoute()
|
||||
const router = useRouter()
|
||||
const height = mainHeight(148)
|
||||
const indicatorHeight = mainHeight(168)
|
||||
const height = mainHeight(295)
|
||||
const indicatorHeight = mainHeight(180)
|
||||
const rowHeight = ref(0)
|
||||
const pageList: any = ref([])
|
||||
const GridHeight = ref(0)
|
||||
@@ -167,6 +231,7 @@ const form: any = reactive({
|
||||
sort: '100',
|
||||
id: '',
|
||||
state: 1,
|
||||
scope: 0,
|
||||
icon: '',
|
||||
pagePath: '',
|
||||
remark: '',
|
||||
@@ -205,6 +270,8 @@ const info = () => {
|
||||
activeNames1.value = []
|
||||
componentTree().then(res => {
|
||||
treeComponents.value = res.data
|
||||
tableName.value = tableName.value == '' ? treeComponents.value[0].name : tableName.value
|
||||
tableName1.value = tableName1.value == '' ? treeComponents.value[0].children[0].name : tableName1.value
|
||||
activeNames.value = treeComponents.value.map(item => item.id)
|
||||
res.data.forEach(item => {
|
||||
item.children.forEach(k => {
|
||||
@@ -223,6 +290,7 @@ const info = () => {
|
||||
form.remark = res.data.remark
|
||||
form.id = res.data.id
|
||||
form.state = res.data.state
|
||||
form.scope = res.data.userId == 0 ? 1 : 0
|
||||
form.icon = res.data.icon
|
||||
})
|
||||
} else {
|
||||
@@ -251,6 +319,10 @@ const tree2List = (list: any, id: any) => {
|
||||
// 返回结果数组
|
||||
return arr
|
||||
}
|
||||
const changeTab = (e: any) => {
|
||||
console.log('🚀 ~ changeTab ~ e:', e)
|
||||
tableName1.value = treeComponents.filter(item => item.name == e)[0].children[0].name
|
||||
}
|
||||
// 删除拖拽
|
||||
const removeItem = (id: string) => {
|
||||
const index = layout.value.findIndex(item => item.i === id)
|
||||
@@ -260,6 +332,7 @@ const removeItem = (id: string) => {
|
||||
}
|
||||
}
|
||||
const wrapper = ref<HTMLElement>()
|
||||
const PaneRef = ref<HTMLElement>()
|
||||
const gridLayout = ref<InstanceType<typeof GridLayout>>()
|
||||
|
||||
const mouseAt = { x: -1, y: -1 }
|
||||
@@ -365,6 +438,12 @@ const onSubmit = () => {
|
||||
if (layout.value.length == 0) {
|
||||
return ElMessage.warning('页面设计不能为空!')
|
||||
}
|
||||
console.log(123, findDuplicateNames(layout.value))
|
||||
let repeat = findDuplicateNames(layout.value) || []
|
||||
if (repeat.length > 0) {
|
||||
return ElMessage.warning(repeat.join('、')+' 组件重复,请删除重复组件!')
|
||||
}
|
||||
|
||||
// const maxValue = Math.max(...layout.value.map(item => item.y + item.h))
|
||||
// if (maxValue > 6) {
|
||||
// return ElMessage.warning('组件不能超出当前容器!')
|
||||
@@ -381,21 +460,27 @@ const onSubmit = () => {
|
||||
|
||||
if (valid) {
|
||||
if (form.id == '') {
|
||||
await addDashboard({ ...form, containerConfig: JSON.stringify(layout.value), thumbnail: url }).then(
|
||||
async (res: any) => {
|
||||
ElMessage.success('新增页面成功!')
|
||||
// go(-1)
|
||||
await getMenu()
|
||||
}
|
||||
)
|
||||
await addDashboard({
|
||||
...form,
|
||||
containerConfig: JSON.stringify(layout.value),
|
||||
thumbnail: url,
|
||||
userId: form.scope == 1 ? '0' : adminInfo.id
|
||||
}).then(async (res: any) => {
|
||||
ElMessage.success('新增页面成功!')
|
||||
// go(-1)
|
||||
await getMenu()
|
||||
})
|
||||
} else {
|
||||
await updateDashboard({ ...form, containerConfig: JSON.stringify(layout.value), thumbnail: url }).then(
|
||||
async (res: any) => {
|
||||
ElMessage.success('修改页面成功!')
|
||||
// go(-1)
|
||||
await getMenu()
|
||||
}
|
||||
)
|
||||
await updateDashboard({
|
||||
...form,
|
||||
containerConfig: JSON.stringify(layout.value),
|
||||
thumbnail: url,
|
||||
userId: form.scope == 1 ? '0' : adminInfo.id
|
||||
}).then(async (res: any) => {
|
||||
ElMessage.success('修改页面成功!')
|
||||
// go(-1)
|
||||
await getMenu()
|
||||
})
|
||||
}
|
||||
await setTimeout(() => {
|
||||
router.push({
|
||||
@@ -406,17 +491,47 @@ const onSubmit = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
// 查找重复的name
|
||||
const findDuplicateNames = (arr: any) => {
|
||||
// 用于记录每个name出现的次数
|
||||
const nameCount = {}
|
||||
// 用于存储重复的name
|
||||
const duplicates = []
|
||||
|
||||
// 遍历数组统计每个name的出现次数
|
||||
arr.forEach(item => {
|
||||
const name = item.name
|
||||
if (nameCount[name]) {
|
||||
nameCount[name]++
|
||||
} else {
|
||||
nameCount[name] = 1
|
||||
}
|
||||
})
|
||||
|
||||
// 筛选出出现次数大于1的name
|
||||
for (const name in nameCount) {
|
||||
if (nameCount[name] > 1) {
|
||||
duplicates.push(name)
|
||||
}
|
||||
}
|
||||
|
||||
return duplicates
|
||||
}
|
||||
const getImg = throttle((path: string) => {
|
||||
if (path != undefined) return treeComponentsCopy.value.filter(item => item.path == path)[0]?.image
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
info()
|
||||
|
||||
GridHeight.value = wrapper.value?.offsetWidth / 1.77777
|
||||
rowHeight.value = GridHeight.value / 6 - 11.5
|
||||
document.documentElement.style.setProperty('--GridLayout-height', rowHeight.value + 10 + 'px')
|
||||
document.addEventListener('dragover', syncMousePosition)
|
||||
nextTick(() => {
|
||||
GridHeight.value = PaneRef.value?.offsetHeight - 60 //wrapper.value?.offsetWidth / 1.77777
|
||||
setTimeout(() => {
|
||||
console.log('🚀 ~ wrapper.value?.offsetWidth:', PaneRef.value?.offsetWidth)
|
||||
}, 500)
|
||||
rowHeight.value = GridHeight.value / 6 - 11.5
|
||||
document.documentElement.style.setProperty('--GridLayout-height', rowHeight.value + 10 + 'px')
|
||||
document.addEventListener('dragover', syncMousePosition)
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -436,7 +551,7 @@ onBeforeUnmount(() => {
|
||||
display: flex;
|
||||
// flex: 1;
|
||||
// align-items: center;
|
||||
width: 24%;
|
||||
width: 32%;
|
||||
.el-form-item__content {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
@@ -516,4 +631,24 @@ onBeforeUnmount(() => {
|
||||
:deep(.el-form--inline .el-form-item) {
|
||||
margin-right: 0px;
|
||||
}
|
||||
:deep(.el-card__header) {
|
||||
padding: 13px 20px;
|
||||
height: 44px;
|
||||
}
|
||||
:deep(.el-card__body) {
|
||||
padding: 10px;
|
||||
}
|
||||
.xiaoshou {
|
||||
cursor: pointer;
|
||||
}
|
||||
.image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
.box-card {
|
||||
width: 100%;
|
||||
// border: 1px solid #000;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user