Compare commits
21 Commits
master
...
dev_xq_0.0
| Author | SHA1 | Date |
|---|---|---|
|
|
ed002a77b7 | 7 hours ago |
|
|
e580b6b6e5 | 8 hours ago |
|
|
865045c4fe | 8 hours ago |
|
|
bbb43faaa3 | 8 hours ago |
|
|
05cff73389 | 6 days ago |
|
|
a63f3074c2 | 1 week ago |
|
|
b1d7a2a8f1 | 1 week ago |
|
|
de5d8c6208 | 1 week ago |
|
|
c303d5e79f | 1 week ago |
|
|
0d87c182ae | 1 week ago |
|
|
986bc85def | 1 week ago |
|
|
b632834b07 | 1 week ago |
|
|
726078fdef | 1 week ago |
|
|
1f8dc80c41 | 1 week ago |
|
|
df16d67c14 | 1 week ago |
|
|
b539825bce | 1 week ago |
|
|
e83ee77b89 | 2 weeks ago |
|
|
b4d246ca55 | 2 weeks ago |
|
|
ce92769b3a | 2 weeks ago |
|
|
8a3837f511 | 2 weeks ago |
|
|
c3950561f9 | 2 weeks ago |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 671 B |
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@
|
||||
import axios from '@/utils/axios';
|
||||
import type { ApiResponse } from '@/api/types';
|
||||
export async function getTableOptionsVOList(options?: { [key: string]: any }) {
|
||||
return axios<ApiResponse<any[]>>('/tableInfo/get/list', {
|
||||
method: 'GET',
|
||||
...(options || {})
|
||||
});
|
||||
}
|
||||
export async function getTableInfoVO(options?: { [key: string]: any }) {
|
||||
return axios<ApiResponse<any[]>>('/tableInfo/get/vo', {
|
||||
method: 'GET',
|
||||
...(options || {})
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,144 @@
|
||||
<script setup lang="ts">
|
||||
import type { DataGridSchema } from './type';
|
||||
import type { PropType } from 'vue';
|
||||
const props = defineProps({
|
||||
// 表格的列规范
|
||||
columns: {
|
||||
type: Array as PropType<DataGridSchema>,
|
||||
required: true
|
||||
},
|
||||
// 表格的数据源
|
||||
tableData: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
spanMethod: {
|
||||
type: Function as PropType<
|
||||
(
|
||||
row: any,
|
||||
column: any,
|
||||
rowIndex: number,
|
||||
columnIndex: number
|
||||
) => { rowspan: number; colspan: number } | null
|
||||
>,
|
||||
default: undefined
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['on-action']);
|
||||
const handleActionClick = (actionKey: string, row: any) => {
|
||||
emit('on-action', {
|
||||
actionKey,
|
||||
row
|
||||
});
|
||||
};
|
||||
// 状态字典映射
|
||||
const getStatusConfig = (statusValue: string | number) => {
|
||||
const dict: Record<string, { label: string; elType: string }> = {
|
||||
normal: { label: '正常', elType: 'success' }, // 绿色
|
||||
fault: { label: '故障', elType: 'warning' }, // 黄色
|
||||
alarm: { label: '报警', elType: 'danger' }, // 红色
|
||||
running: { label: '运行', elType: 'primary' }, // 蓝色
|
||||
turnOn: { label: '开启', elType: 'info' }, // 灰色
|
||||
turnOff: { label: '关闭', elType: 'info' }, // 灰色
|
||||
no_action: { label: '未动作', elType: 'info' } // 灰色
|
||||
};
|
||||
return dict[statusValue] || { label: '未知', elType: 'info' };
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="standard-data-grid">
|
||||
<el-table :data="tableData" border :span-method="spanMethod">
|
||||
<template v-for="(item, index) in columns" :key="item.key">
|
||||
<el-table-column
|
||||
v-if="item.children && item.children.length > 0"
|
||||
:label="item.title"
|
||||
:prop="item.key"
|
||||
:align="item.align ?? 'center'"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="subItem in item.children"
|
||||
:key="subItem.key"
|
||||
:prop="subItem.key"
|
||||
:label="subItem.title"
|
||||
:align="subItem.align ?? 'center'"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div v-if="subItem.type === 'action'" class="action-btn-group">
|
||||
<template v-for="btn in subItem.actions" :key="btn.actionKey">
|
||||
<el-button
|
||||
v-if="!btn.showOn || btn.showOn.values.includes(scope.row[btn.showOn.key])"
|
||||
:type="btn.btnType || 'primary'"
|
||||
size="small"
|
||||
@click="handleActionClick(btn.actionKey, scope.row)"
|
||||
>
|
||||
{{ btn.label }}
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-else
|
||||
:label="item.title"
|
||||
:prop="item.key"
|
||||
:align="item.align"
|
||||
:width="item.width"
|
||||
:min-width="item.minWidth"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span v-if="item.type === 'text'">
|
||||
{{ scope.row[item.key] ?? '--' }}
|
||||
</span>
|
||||
<span v-else-if="item.type === 'number'">
|
||||
{{ scope.row[item.key] }}<span class="unit">{{ item.unit }}</span>
|
||||
</span>
|
||||
<span v-else-if="item.type === 'status'">
|
||||
<el-tag :type="getStatusConfig(scope.row[item.key]).elType">
|
||||
{{ getStatusConfig(scope.row[item.key]).label }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<div v-else-if="item.type === 'action'" class="action-btn-group">
|
||||
<template v-for="btn in item.actions" :key="btn.actionKey">
|
||||
<el-button
|
||||
v-if="!btn.showOn || btn.showOn.values.includes(scope.row[btn.showOn.key])"
|
||||
:type="btn.btnType || 'primary'"
|
||||
:disabled="
|
||||
!btn.disabledOn || btn.disabledOn.values.includes(scope.row[btn.disabledOn.key])
|
||||
"
|
||||
@click="handleActionClick(btn.actionKey, scope.row)"
|
||||
>
|
||||
{{ btn.label }}
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
item.horizontalMergeRule &&
|
||||
scope.row[item.horizontalMergeRule.matchCondition.key] ===
|
||||
item.horizontalMergeRule.matchCondition.value
|
||||
"
|
||||
>
|
||||
<div
|
||||
v-if="item?.horizontalMergeRule.renderConfig?.type === 'action'"
|
||||
class="merged-action-cell"
|
||||
>
|
||||
<el-button
|
||||
v-for="btn in item.horizontalMergeRule.renderConfig.actions"
|
||||
:key="btn.actionKey"
|
||||
:type="btn.btnType"
|
||||
@click="handleActionClick(btn.actionKey, scope.row)"
|
||||
>
|
||||
{{ btn.label }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 表格列的基本规范
|
||||
*/
|
||||
interface BaseColumn {
|
||||
// 表头的标题
|
||||
title: string;
|
||||
// 数据源对应的字段名
|
||||
key: string;
|
||||
// 列的宽度
|
||||
width?: number | string;
|
||||
// 单元格的显示位置
|
||||
align?: 'left' | 'center' | 'right';
|
||||
// 固定列
|
||||
fixed?: 'left' | 'right';
|
||||
// 最小宽度,适应不同大小的屏幕
|
||||
minWidth?: number | string;
|
||||
// 标记这个列是否需要纵向合并
|
||||
mergeRow?: boolean;
|
||||
// 标记这个列是否需要横向合并
|
||||
horizontalMergeRule?: {
|
||||
matchCondition: { key: string; value: string | boolean };
|
||||
mergeKeys: string[];
|
||||
renderConfig?: {
|
||||
type: string;
|
||||
actions?: ActionButton[];
|
||||
};
|
||||
};
|
||||
// 多级表头
|
||||
children?: TableColumnSchema[];
|
||||
// 标记合并行时的参考列
|
||||
mergeBy?: string;
|
||||
}
|
||||
// 纯文本列
|
||||
export interface TextColumn extends BaseColumn {
|
||||
type: 'text';
|
||||
}
|
||||
// 状态列
|
||||
export interface StatusColumn extends BaseColumn {
|
||||
type: 'status';
|
||||
dictCode?: string;
|
||||
}
|
||||
// 数值列
|
||||
export interface NumberColumn extends BaseColumn {
|
||||
type: 'number';
|
||||
// 单位后缀
|
||||
unit?: string;
|
||||
}
|
||||
// 操作列
|
||||
export interface ActionColumn extends BaseColumn {
|
||||
type: 'action';
|
||||
// 操作列包含按钮列表
|
||||
actions: ActionButton[];
|
||||
}
|
||||
// 按钮定义的schema
|
||||
export interface ActionButton {
|
||||
// 按钮的文字
|
||||
label: string;
|
||||
//抛出给外层的事件名
|
||||
actionKey: string;
|
||||
// 按钮的视觉类型
|
||||
btnType?: 'primary' | 'default' | 'dashed' | 'danger' | 'link' | 'text';
|
||||
// 根据状态值控制显示
|
||||
showOn?: {
|
||||
key: string; // 依赖哪一列数据
|
||||
values: any[]; // 当值等于数组中的哪些项时,才显示按钮
|
||||
};
|
||||
// 根据状态来控制禁用
|
||||
disabledOn?: {
|
||||
key: string;
|
||||
values: any[];
|
||||
};
|
||||
isRound?: boolean;
|
||||
}
|
||||
export type TableColumnSchema = TextColumn | StatusColumn | NumberColumn | ActionColumn;
|
||||
export type DataGridSchema = TableColumnSchema[];
|
||||
@ -0,0 +1,118 @@
|
||||
// 提取叶子节点列,解决多级表头索引对齐问题
|
||||
const getLeafColumns = (columns: any[]) => {
|
||||
let leaves: any[] = [];
|
||||
columns.forEach((col) => {
|
||||
if (col.children && col.children.length > 0) {
|
||||
leaves.push(...getLeafColumns(col.children));
|
||||
} else {
|
||||
leaves.push(col);
|
||||
}
|
||||
});
|
||||
return leaves;
|
||||
};
|
||||
/**
|
||||
*
|
||||
* @param data 表格的数据源
|
||||
* @param rowMergeConfigs 纵向合并配置 [{ key: 'xxx', mergeBy: 'yyy' }]
|
||||
* @param rawColumns 表格列配置
|
||||
*/
|
||||
export const createRowSpanMethod = (
|
||||
data: any[],
|
||||
rawColumns: any[],
|
||||
rowMergeConfigs: { key: string; mergeBy: string }[]
|
||||
) => {
|
||||
// 1. 拍平获取物理叶子列
|
||||
const columns = getLeafColumns(rawColumns);
|
||||
const rowSpanInfos: Record<string, number[]> = {};
|
||||
rowMergeConfigs.forEach((config) => {
|
||||
const { key, mergeBy } = config;
|
||||
rowSpanInfos[key] = [];
|
||||
let position = 0;
|
||||
data.forEach((item, index) => {
|
||||
if (index === 0) {
|
||||
rowSpanInfos[key].push(1);
|
||||
position = 0;
|
||||
} else {
|
||||
// 如果当前行数据和上一行数据相等,则当前行不显示
|
||||
if (
|
||||
item[mergeBy] === data[index - 1][mergeBy] &&
|
||||
!item.colMergeConfig &&
|
||||
!data[index - 1].colMergeConfig
|
||||
) {
|
||||
rowSpanInfos[key][position] += 1;
|
||||
rowSpanInfos[key].push(0);
|
||||
} else {
|
||||
rowSpanInfos[key].push(1);
|
||||
position = index;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return ({ row, column, rowIndex, columnIndex }: any) => {
|
||||
// 优先处理横向合并
|
||||
const ruleColumn = columns.find(
|
||||
(col) =>
|
||||
col.horizontalMergeRule &&
|
||||
row[col.horizontalMergeRule.matchCondition.key] ===
|
||||
col.horizontalMergeRule.matchCondition.value
|
||||
);
|
||||
if (ruleColumn) {
|
||||
const rule = ruleColumn.horizontalMergeRule;
|
||||
const targetKeys = rule.mergeKeys;
|
||||
const validIndices = targetKeys
|
||||
.map((key) => columns.findIndex((item) => item.key === key))
|
||||
.filter((index) => index != -1);
|
||||
|
||||
if (validIndices.length > 0) {
|
||||
const minIndex = Math.min(...validIndices);
|
||||
const maxIndex = Math.max(...validIndices);
|
||||
const actualColSpan = maxIndex - minIndex + 1;
|
||||
if (columnIndex == minIndex) {
|
||||
return {
|
||||
rowspan: 1,
|
||||
colspan: actualColSpan
|
||||
};
|
||||
}
|
||||
if (columnIndex > minIndex && columnIndex <= maxIndex) {
|
||||
return {
|
||||
rowspan: 0,
|
||||
colspan: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// 再处理纵向合并
|
||||
const mergeTarget = rowMergeConfigs.find((c) => c.key === column.property);
|
||||
if (mergeTarget) {
|
||||
const rowspan = rowSpanInfos[column.property][rowIndex];
|
||||
const colspan = rowspan > 0 ? 1 : 0;
|
||||
return { rowspan, colspan };
|
||||
}
|
||||
return { rowspan: 1, colspan: 1 };
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 通用数组聚合标记函数
|
||||
* @param {Array} list - 原始数组
|
||||
* @param {String} groupKey - 按照哪个字段进行分组统计 (例如 'deviceName')
|
||||
* @param {String} flagName - 生成的布尔值标记名称 (例如 'isMultiNode')
|
||||
*/
|
||||
export const injectMultiNodeFlag = (list: any[], groupKey: string, flagName: string) => {
|
||||
const countMap = {} as Record<string, number>;
|
||||
// 统计
|
||||
list.forEach((item) => {
|
||||
const val = item[groupKey];
|
||||
if (val) countMap[val] = (countMap[val] || 0) + 1;
|
||||
});
|
||||
|
||||
// 映射
|
||||
return list.map((item) => {
|
||||
const val = item[groupKey];
|
||||
if (!val) return item; // 非目标数据,直接返回
|
||||
return {
|
||||
...item,
|
||||
[flagName]: countMap[val] > 1 // 动态注入标记
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -0,0 +1,52 @@
|
||||
import { computed, type Ref, unref } from 'vue';
|
||||
import { createRowSpanMethod } from '@/components/custom-components/table-vue/utils/tableUtils';
|
||||
/**
|
||||
* 只能表格合并 hook
|
||||
* @param tableData 表格数据源
|
||||
* @param tableColumns 表格列配置
|
||||
*/
|
||||
export function useTableSpan(tableData: Ref<any[]>, tableColumns: any[] | Ref<any[]>) {
|
||||
const flatColumns = computed(() => {
|
||||
const columns = unref(tableColumns); // 兼容普通对象和ref对象
|
||||
const flatten = (cols: any[]): any[] => {
|
||||
let result: any[] = [];
|
||||
cols.forEach((col) => {
|
||||
result.push(col);
|
||||
if (col.children && col.children.length > 0) {
|
||||
result.push(...flatten(col.children));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
return flatten(columns);
|
||||
});
|
||||
//自动提取需要纵向合并的列配置
|
||||
const rowMergeConfigs = computed(() => {
|
||||
return flatColumns.value
|
||||
.filter((col) => col.mergeRow)
|
||||
.map((col) => {
|
||||
return {
|
||||
key: col.key,
|
||||
mergeBy: col.mergeBy || col.key
|
||||
};
|
||||
});
|
||||
});
|
||||
// 判断表格需不需要开启合并引擎
|
||||
const needSpan = computed(() => {
|
||||
// 有任何列配置了纵向合并
|
||||
const hasRowMerge = rowMergeConfigs.value.length;
|
||||
// 有任何列配置了横向合并
|
||||
const hasColMerge = flatColumns.value.some((col) => !!col.horizontalMergeRule);
|
||||
return hasRowMerge || hasColMerge;
|
||||
});
|
||||
// 动态返回合并函数
|
||||
const spanMethod = computed(() => {
|
||||
if (!needSpan.value) {
|
||||
return undefined;
|
||||
}
|
||||
return createRowSpanMethod(unref(tableData), unref(tableColumns), rowMergeConfigs.value);
|
||||
});
|
||||
return {
|
||||
spanMethod
|
||||
};
|
||||
}
|
||||
Binary file not shown.
@ -1,20 +1,50 @@
|
||||
<template>
|
||||
<div style="width: 100%; height: 100%">
|
||||
<h2 class="my-button" style="width: 100%; height: 100%">{{ props.modelValue }}</h2>
|
||||
<!-- <h2 class="my-button" style="width: 100%; height: 100%">{{ props.modelValue }}</h2> -->
|
||||
<el-text class="my-button">{{ props.modelValue }}</el-text>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
const props = defineProps({
|
||||
modelValue: String,
|
||||
fontFamily: String,
|
||||
testColor: String
|
||||
testColor: String,
|
||||
fontSize: Number,
|
||||
fontBold: Boolean
|
||||
});
|
||||
|
||||
let computedSize = computed({
|
||||
// 读取
|
||||
get() {
|
||||
return props.fontSize + 'px';
|
||||
}, // 修改
|
||||
set(val) {}
|
||||
});
|
||||
|
||||
let computedBold = computed({
|
||||
// 读取
|
||||
get() {
|
||||
return props.fontBold ? 'bold' : 'normal';
|
||||
}, // 修改
|
||||
set(val) {}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
font-weight: v-bind('computedBold');
|
||||
justify-content: center; /* 水平居中 */
|
||||
align-items: center; /* 垂直居中 */
|
||||
text-align: center;
|
||||
color: v-bind('props.testColor');
|
||||
font-family: v-bind('props.fontFamily');
|
||||
font-size: v-bind('computedSize');
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<el-card class="card">
|
||||
<h2 class="cardHead">基本信息</h2>
|
||||
<div class="cardBody">
|
||||
<el-scrollbar>
|
||||
<el-row
|
||||
v-for="item in dataObj"
|
||||
:key="item.field"
|
||||
:gutter="0"
|
||||
style="display: flex; align-items: center; margin-bottom: 1%"
|
||||
>
|
||||
<el-col :span="8" :offset="4">{{ item.field }}</el-col>
|
||||
<el-col :span="4">
|
||||
<el-tag type="primary" size="small">{{ item.value }}</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- <el-row :gutter="0" style="display: flex; align-items: center;margin-bottom: 1%;">
|
||||
<el-col :span="8" :offset="4"> 名称 </el-col>
|
||||
<el-col :span="4">
|
||||
<el-tag type="primary" size="small">{{ data.name }}</el-tag>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch, onMounted, reactive } from 'vue';
|
||||
import { invariantObjMap, type Paragraph } from '@/utils/invariable';
|
||||
import { da } from 'element-plus/es/locales.mjs';
|
||||
|
||||
const props = defineProps({
|
||||
dataSource: {
|
||||
type: String,
|
||||
default: '--'
|
||||
}
|
||||
});
|
||||
const dataObj = reactive<Paragraph[]>([]);
|
||||
|
||||
function getDataBySource() {
|
||||
dataObj.length = 0;
|
||||
if (props.dataSource != null && props.dataSource !== '' && props.dataSource !== '--') {
|
||||
const dataObjTemp = invariantObjMap[props.dataSource];
|
||||
if (!dataObjTemp) return;
|
||||
dataObj.push(...dataObjTemp);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadDataSource(props.dataSource);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.dataSource,
|
||||
(newVal, oldVal) => {
|
||||
loadDataSource(newVal);
|
||||
}
|
||||
);
|
||||
|
||||
function loadDataSource(val: string) {
|
||||
// 加载对应数据源的数据
|
||||
getDataBySource();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
padding-top: 10px;
|
||||
padding-left: 2%;
|
||||
}
|
||||
|
||||
.el-row .el-col {
|
||||
margin-bottom: 6px; /* 设置上下间距 */
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
padding-bottom: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.cardBody {
|
||||
width: 98%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: calc(100% - 40px);
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<!-- <el-button @click="ccc">Default</el-button> -->
|
||||
<el-card class="card">
|
||||
<el-scrollbar height="100%">
|
||||
<h2 class="cardHead">{{ testContent }}</h2>
|
||||
|
||||
<div class="cardBody" v-if="skeletonBool">
|
||||
<el-skeleton :rows="rows" style="margin-top: 4%" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch, onMounted } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: 'Segoe UI'
|
||||
},
|
||||
fontSize: {
|
||||
type: Number,
|
||||
default: 14
|
||||
},
|
||||
testColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
testContent: {
|
||||
type: String,
|
||||
default: '标题内容'
|
||||
},
|
||||
skeletonBool: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
skeletonRows: {
|
||||
type: Number,
|
||||
default: 5
|
||||
}
|
||||
});
|
||||
let computedSize = computed({
|
||||
// 读取
|
||||
get() {
|
||||
return props.fontSize + 'px';
|
||||
}, // 修改
|
||||
set(val) {
|
||||
console.log('有人修改了fullName', val);
|
||||
}
|
||||
});
|
||||
|
||||
let rows = computed({
|
||||
// 读取
|
||||
get() {
|
||||
if (props.skeletonRows >= 1) return props.skeletonRows - 1;
|
||||
else return 0;
|
||||
},
|
||||
set(val) {}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
padding-top: 10px;
|
||||
/* padding-left: 10px; */
|
||||
}
|
||||
.card {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* max-width: 480px; */
|
||||
color: v-bind('props.testColor');
|
||||
font-family: v-bind('props.fontFamily');
|
||||
/* font-family: 'Segoe UI'; */
|
||||
font-size: v-bind('computedSize');
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
padding-bottom: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.cardBody {
|
||||
width: 90%;
|
||||
height: 100%;
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
/* 让骨架屏的段落更厚且宽度一致 */
|
||||
:deep(.el-skeleton__item) {
|
||||
height: 24px; /* 增加段落高度,默认约 16px */
|
||||
width: 100%; /* 让所有段落宽度一致,填满容器 */
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="vue-characters">
|
||||
<div v-if="type == 0" class="color-dot" :style="{ backgroundColor: color }"></div>
|
||||
<div v-else-if="type == 1">
|
||||
<el-tag size="large">{{ text }}</el-tag>
|
||||
</div>
|
||||
<div v-else-if="type == 2" style="background-color: saddlebrown">
|
||||
<el-tag size="large" :style="{ backgroundColor: color }">{{ text }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { useNodeByModelsStore } from '@/components/mt-edit/store/nodeByModels';
|
||||
import { getIndex, Rec } from '@/utils/config';
|
||||
import emitter from '@/utils/emitter';
|
||||
const nodeByModelsStore = useNodeByModelsStore();
|
||||
const etype = ref(-1);
|
||||
const btype = ref(-1);
|
||||
const valInt = ref(0);
|
||||
const text = ref('');
|
||||
const color = ref('');
|
||||
const type = ref();
|
||||
const props = defineProps({
|
||||
moduleType: {
|
||||
type: String,
|
||||
default: '--'
|
||||
},
|
||||
moduleId: {
|
||||
type: String,
|
||||
default: '--'
|
||||
},
|
||||
definitionItemJson: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
location: {
|
||||
type: String,
|
||||
default: 'bottom'
|
||||
}
|
||||
});
|
||||
function getModuleById(moduleId: string) {
|
||||
const globalData = (window as any).globalData;
|
||||
if (!globalData || moduleId == undefined || moduleId == '' || props.moduleId == '--') {
|
||||
console.warn('globalData 未初始化');
|
||||
return null;
|
||||
}
|
||||
// 根据实际类型访问
|
||||
if (globalData instanceof Map) {
|
||||
// 如果是 Map 类型
|
||||
return globalData.get(moduleId);
|
||||
} else {
|
||||
// 如果是普通对象
|
||||
return globalData[moduleId];
|
||||
}
|
||||
}
|
||||
const getText = () => {
|
||||
switch (type.value) {
|
||||
case 0: {
|
||||
color.value = Rec.EnumTypeValFun);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
text.value = Rec.EnumTypeValFun);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
const temp = Rec.EnumTypeValFun);
|
||||
text.value = temp.split(',')[0];
|
||||
color.value = temp.split(',')[1];
|
||||
console.log(color.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
function loadingModuleById() {
|
||||
let module = getModuleById(props.moduleId);
|
||||
if (props.moduleId !== '' && props.moduleId !== undefined && props.moduleId !== '--' && module) {
|
||||
if (module) {
|
||||
console.log('当前的module', module);
|
||||
etype.value = module.node.etype;
|
||||
btype.value = module.node.btype;
|
||||
valInt.value = module.valInt;
|
||||
type.value = Rec.CONST!.YX.EnumType[etype.value][0];
|
||||
getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
emitter.on(props.definitionItemJson.id, (value) => {
|
||||
loadingModuleById();
|
||||
});
|
||||
watch(
|
||||
() => props.moduleId,
|
||||
(newVal, oldVal) => {
|
||||
loadingModuleById();
|
||||
nodeByModelsStore.change(newVal, oldVal, props.definitionItemJson.id);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vue-characters {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.color-dot {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
|
||||
<h2 class="cardHead">操作流程</h2>
|
||||
<div class="cardBody">
|
||||
<el-steps
|
||||
style="max-width: 100%"
|
||||
:active="4"
|
||||
align-center
|
||||
direction="vertical"
|
||||
finish-status="success"
|
||||
>
|
||||
<el-step description="变压器故障起火" />
|
||||
<el-step>
|
||||
<template #description>
|
||||
保护动作
|
||||
<div class="parallel-box">
|
||||
<el-tag type="primary">重瓦斯动作</el-tag>
|
||||
<el-tag type="success">温控器动作</el-tag>
|
||||
<el-tag type="primary">压力释放动作</el-tag>
|
||||
<el-tag type="primary">火灾探测器动作</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step description="排油阀开启" />
|
||||
<el-step description="注氮阀开启" />
|
||||
<el-step description="注氮阀关闭" />
|
||||
<el-step description="注氮 10 分钟以上达到防爆灭火效果" />
|
||||
</el-steps>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<el-button type="primary" size="small">手动启动</el-button>
|
||||
<el-button type="primary" size="small">手动停止</el-button>
|
||||
<el-button type="primary" size="small">紧急停止</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card :deep(.el-card__body) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 并行步骤框 */
|
||||
.parallel-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/* el-tag 样式调整 */
|
||||
.parallel-box :deep(.el-tag) {
|
||||
text-align: left;
|
||||
padding: 8px 16px;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
/* 并行步骤样式 */
|
||||
.parallel-steps {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* 按钮组样式 */
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 1%;
|
||||
justify-content: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.step-item {
|
||||
padding: 8px 12px;
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
color: #ffffff;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 操作区域 */
|
||||
.operation-area {
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.area-title {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #4facfe;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.notes {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.note {
|
||||
margin: 0;
|
||||
font-size: 11px;
|
||||
color: #f5576c;
|
||||
line-height: 1.6;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.note-label {
|
||||
font-weight: bold;
|
||||
color: #f093fb;
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 768px) {
|
||||
.notes {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
|
||||
<h2 class="cardHead">火灾探测器基本信息</h2>
|
||||
<div class="cardBody">
|
||||
<el-row :gutter="20" style="height: 100%">
|
||||
<el-col :span="12" class="image-col">
|
||||
<img src="/imgs/xianqvan.png" style="width: 100%; height: 100%" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">厂家</el-col>
|
||||
<el-col :span="12"><el-tag size="small">海湾公司</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">型号</el-col>
|
||||
<el-col :span="12"><el-tag size="small">CTI-155X</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">投运日期</el-col>
|
||||
<el-col :span="12"><el-tag size="small">2012-08-08</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">使用环境</el-col>
|
||||
<el-col :span="12"><el-tag size="small">温度 -5℃~45℃</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">火灾响应规模</el-col>
|
||||
<el-col :span="12"><el-tag size="small">10mm</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">测量温度精度</el-col>
|
||||
<el-col :span="12"><el-tag size="small">≤1℃</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">定位精度</el-col>
|
||||
<el-col :span="12"><el-tag size="small">≤1 米</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">类型</el-col>
|
||||
<el-col :span="12"><el-tag size="small">定温式</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">报警温度</el-col>
|
||||
<el-col :span="12"><el-tag size="small">85℃</el-tag></el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="info-row">
|
||||
<el-col :span="10" class="info-label">标准</el-col>
|
||||
<el-col :span="12"><el-tag size="small">GB16280-2014</el-tag></el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card :deep(.el-card__body) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* el-row 高度继承 */
|
||||
.cardBody :deep(.el-row) {
|
||||
/* height: 100%; */
|
||||
}
|
||||
|
||||
/* el-col 高度继承 */
|
||||
.cardBody :deep(.el-col) {
|
||||
/* height: 100%;
|
||||
display: flex;
|
||||
align-items: stretch; */
|
||||
}
|
||||
|
||||
/* 图片列样式 */
|
||||
.image-col {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* 探测器图片样式 */
|
||||
.detector-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* 信息行样式 */
|
||||
.info-row {
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
|
||||
/* 标签样式 */
|
||||
.info-label {
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* el-tag 样式 */
|
||||
.info-row :deep(.el-tag) {
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<div class="table-container">
|
||||
<!-- 2号主变 -->
|
||||
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
|
||||
<h2 class="cardHead">消火栓信息</h2>
|
||||
<div class="table-wrapper" v-loading="arr.length === 0">
|
||||
<el-table
|
||||
:data="arr"
|
||||
style="width: 100%"
|
||||
class="full-height-table"
|
||||
@cell-click="handleCellClick"
|
||||
>
|
||||
<el-table-column prop="equipmentName" label="设备名称" />
|
||||
<el-table-column prop="equipmentModel" label="规格型号" />
|
||||
<el-table-column prop="equipmentPlace" label="设备位置" />
|
||||
<el-table-column prop="manufacturers" label="厂家" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, onUnmounted } from 'vue';
|
||||
import emitter from '@/utils/emitter';
|
||||
|
||||
// 导入全局类型定义
|
||||
/// <reference path="../../../global.d.ts" />
|
||||
|
||||
function handleCellClick(obj: any) {
|
||||
console.log('点击:', obj);
|
||||
emitter.emit('binding-obj-facility-move', obj.id);
|
||||
}
|
||||
|
||||
emitter.on('binding-data-update', () => {
|
||||
console.log('@@binding-data-update');
|
||||
dataInit();
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: '黑体'
|
||||
},
|
||||
fontSize: {
|
||||
type: Number,
|
||||
default: 12
|
||||
},
|
||||
testColor: {
|
||||
type: String,
|
||||
default: '#ffffff'
|
||||
},
|
||||
definitionItemJson: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
});
|
||||
|
||||
console.log('父传子itemjson:', props.definitionItemJson);
|
||||
|
||||
// 计算属性——既读取又修改
|
||||
let computedSize = computed({
|
||||
// 读取
|
||||
get() {
|
||||
return props.fontSize + 'px';
|
||||
}, // 修改
|
||||
set(val) {}
|
||||
});
|
||||
|
||||
//数据初始化
|
||||
async function dataInit() {}
|
||||
|
||||
// 在 onMounted 中
|
||||
onMounted(async () => {
|
||||
await dataInit();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off('binding-data-update');
|
||||
});
|
||||
|
||||
//node
|
||||
interface EquipmentNode {
|
||||
equipmentName: string; //设备名称
|
||||
equipmentModel: string; //规格型号
|
||||
equipmentPlace: string; //设备位置
|
||||
manufacturers: string; //厂家
|
||||
}
|
||||
|
||||
// 数据源头
|
||||
// equipmentState 0正常 1故障
|
||||
// currentState 0未动作 1报警 2动作 3分位 4关闭 5开启 6运行 7正常
|
||||
// operation true屏蔽 false取消屏蔽 null
|
||||
const arr: EquipmentNode[] = [
|
||||
{
|
||||
equipmentName: '生产综合楼一楼消火栓1',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼一楼东走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼一楼消火栓2',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼一楼西走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼二楼消火栓1',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼二楼东走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼二楼消火栓2',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼二楼西走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼一楼消火栓1',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼一楼东走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼一楼消火栓2',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼一楼西走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼二楼消火栓1',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼二楼东走廊',
|
||||
manufacturers: '宏达'
|
||||
},
|
||||
{
|
||||
equipmentName: '生产综合楼二楼消火栓2',
|
||||
equipmentModel: 'SN-65',
|
||||
equipmentPlace: '生产综合楼二楼西走廊',
|
||||
manufacturers: '宏达'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card :deep(.el-card__body) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.full-height-table {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.full-height-table :deep(.el-table__body-wrapper) {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.operation-btn {
|
||||
width: 60px;
|
||||
min-width: 50px;
|
||||
padding: 8px 12px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/* 控制表头文字大小 */
|
||||
.full-height-table :deep(.el-table__header th) {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 控制表格内容文字大小 */
|
||||
.full-height-table :deep(.el-table__body td) {
|
||||
font-size: v-bind('computedSize');
|
||||
color: v-bind('props.testColor');
|
||||
}
|
||||
|
||||
/* 控制标签文字大小 */
|
||||
.full-height-table :deep(.el-tag) {
|
||||
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
|
||||
}
|
||||
|
||||
/* 控制按钮文字大小 */
|
||||
.full-height-table :deep(.el-button) {
|
||||
font-size: v-bind('computedSize');
|
||||
color: v-bind('props.testColor');
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<div class="table-container">
|
||||
<!-- 2号主变 -->
|
||||
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
|
||||
<h2 class="cardHead">运行信息</h2>
|
||||
<div class="table-wrapper" v-loading="arr.length === 0">
|
||||
<el-table
|
||||
:data="arr"
|
||||
style="width: 100%"
|
||||
class="full-height-table"
|
||||
@cell-click="handleCellClick"
|
||||
>
|
||||
<el-table-column prop="equipmentName" label="设备名称" />
|
||||
|
||||
<el-table-column label="设备状态">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.equipmentState === 0 ? 'success' : 'warning'">
|
||||
{{ row.equipmentState === 0 ? '正常' : '故障' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前状态">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="primary">{{ row.currentState }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.operation == null || row.operation === ''" type="info"
|
||||
>无操作</el-tag
|
||||
>
|
||||
<template v-else>
|
||||
<el-button type="primary" size="small">开启</el-button>
|
||||
<el-button type="primary" size="small">关闭</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, onUnmounted } from 'vue';
|
||||
import emitter from '@/utils/emitter';
|
||||
|
||||
// 导入全局类型定义
|
||||
/// <reference path="../../../global.d.ts" />
|
||||
|
||||
function handleCellClick(obj: any) {
|
||||
console.log('点击:', obj);
|
||||
emitter.emit('binding-obj-facility-move', obj.id);
|
||||
}
|
||||
|
||||
emitter.on('binding-data-update', () => {
|
||||
console.log('@@binding-data-update');
|
||||
dataInit();
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: '黑体'
|
||||
},
|
||||
fontSize: {
|
||||
type: Number,
|
||||
default: 12
|
||||
},
|
||||
testColor: {
|
||||
type: String,
|
||||
default: '#ffffff'
|
||||
},
|
||||
definitionItemJson: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
});
|
||||
|
||||
console.log('父传子itemjson:', props.definitionItemJson);
|
||||
|
||||
// 计算属性——既读取又修改
|
||||
let computedSize = computed({
|
||||
// 读取
|
||||
get() {
|
||||
return props.fontSize + 'px';
|
||||
}, // 修改
|
||||
set(val) {}
|
||||
});
|
||||
|
||||
//数据初始化
|
||||
async function dataInit() {}
|
||||
|
||||
// 在 onMounted 中
|
||||
onMounted(async () => {
|
||||
await dataInit();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off('binding-data-update');
|
||||
});
|
||||
|
||||
//node
|
||||
interface EquipmentNode {
|
||||
equipmentName: string; //设备名称
|
||||
equipmentState: number; //设备状态 0正常 1故障
|
||||
currentState: string; //当前状态
|
||||
operation: boolean | null; //操作 true屏蔽 false取消屏蔽 null
|
||||
}
|
||||
|
||||
// 数据源头
|
||||
// equipmentState 0正常 1故障
|
||||
// currentState 0未动作 1报警 2动作 3分位 4关闭 5开启 6运行 7正常
|
||||
// operation true屏蔽 false取消屏蔽 null
|
||||
const arr: EquipmentNode[] = [
|
||||
{
|
||||
equipmentName: '消防泵控制装置',
|
||||
equipmentState: 0,
|
||||
currentState: '运行',
|
||||
operation: null
|
||||
},
|
||||
{
|
||||
equipmentName: '消防泵主供电源供电',
|
||||
equipmentState: 0,
|
||||
currentState: '关',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '消防泵备用电源供电',
|
||||
equipmentState: 0,
|
||||
currentState: '开',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '控制装置主供电源供电',
|
||||
equipmentState: 0,
|
||||
currentState: '开',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '控制装置备用电源供电',
|
||||
equipmentState: 0,
|
||||
currentState: '关',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '深井泵',
|
||||
equipmentState: 0,
|
||||
currentState: '关',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '高压侧断路器',
|
||||
equipmentState: 0,
|
||||
currentState: '关',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '1号消防泵',
|
||||
equipmentState: 0,
|
||||
currentState: '关',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '2号消防泵',
|
||||
equipmentState: 0,
|
||||
currentState: '关',
|
||||
operation: true
|
||||
},
|
||||
{
|
||||
equipmentName: '消防水池水位',
|
||||
equipmentState: 0,
|
||||
currentState: '80%',
|
||||
operation: null
|
||||
},
|
||||
{
|
||||
equipmentName: '管网压力',
|
||||
equipmentState: 0,
|
||||
currentState: '0.4Mpa',
|
||||
operation: null
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card :deep(.el-card__body) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.full-height-table {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.full-height-table :deep(.el-table__body-wrapper) {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0 0 15px 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.operation-btn {
|
||||
width: 60px;
|
||||
min-width: 50px;
|
||||
padding: 8px 12px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/* 控制表头文字大小 */
|
||||
.full-height-table :deep(.el-table__header th) {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 控制表格内容文字大小 */
|
||||
.full-height-table :deep(.el-table__body td) {
|
||||
font-size: v-bind('computedSize');
|
||||
color: v-bind('props.testColor');
|
||||
}
|
||||
|
||||
/* 控制标签文字大小 */
|
||||
.full-height-table :deep(.el-tag) {
|
||||
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
|
||||
}
|
||||
|
||||
/* 控制按钮文字大小 */
|
||||
.full-height-table :deep(.el-button) {
|
||||
font-size: v-bind('computedSize');
|
||||
color: v-bind('props.testColor');
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<el-card class="card">
|
||||
<h3 class="cardHead">2号主变排油注氮灭火</h3>
|
||||
|
||||
<div class="cardBody">
|
||||
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="danger" size="large" class="full-width-tag">火灾探测器1</el-tag>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="danger" size="large" class="full-width-tag">火灾探测器2</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="warning" size="large" class="full-width-tag">火灾探测器3</el-tag>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="primary" size="large" class="full-width-tag">火灾探测器4</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="danger" size="large" class="full-width-tag">注氮阀</el-tag>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="danger" size="large" class="full-width-tag">排油阀</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="danger" size="large" class="full-width-tag">断流阀</el-tag>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="full-width-col">
|
||||
<el-tag type="primary" size="large" class="full-width-tag">氮气瓶</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch, onMounted } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: 'Segoe UI'
|
||||
},
|
||||
fontSize: {
|
||||
type: Number,
|
||||
default: 14
|
||||
},
|
||||
testColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
},
|
||||
testBool: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
let computedSize = computed({
|
||||
// 读取
|
||||
get() {
|
||||
return props.fontSize + 'px';
|
||||
}, // 修改
|
||||
set(val) {
|
||||
console.log('有人修改了fullName', val);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.row-spacing {
|
||||
margin-bottom: 10px; /* 每行之间的间隔 */
|
||||
}
|
||||
|
||||
.full-width-col {
|
||||
display: flex;
|
||||
justify-content: center; /* 水平居中 */
|
||||
align-items: center; /* 垂直居中 */
|
||||
}
|
||||
|
||||
.full-width-tag {
|
||||
width: 85%; /* 填满父容器 */
|
||||
text-align: center; /* 文字水平居中 */
|
||||
display: flex; /* 使用 flexbox */
|
||||
justify-content: center; /* 文字水平居中 */
|
||||
align-items: center; /* 文字垂直居中 */
|
||||
font-size: v-bind('computedSize');
|
||||
}
|
||||
|
||||
/* 闪烁动画 */
|
||||
.blinking-tag {
|
||||
animation: blink 1s infinite; /* 1秒一次无限循环 */
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1; /* 完全不透明 */
|
||||
}
|
||||
50% {
|
||||
opacity: 0.3; /* 半透明 */
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* max-width: 480px; */
|
||||
color: v-bind('props.testColor');
|
||||
font-family: v-bind('props.fontFamily');
|
||||
/* font-family: 'Segoe UI'; */
|
||||
font-size: v-bind('computedSize' - 1);
|
||||
}
|
||||
|
||||
.cardHead {
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
padding-bottom: 20px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
font-size: v-bind('computedSize' + 2);
|
||||
}
|
||||
.cardBody {
|
||||
width: 100%;
|
||||
margin: 0 0%;
|
||||
padding: 0px 0%;
|
||||
/* padding-bottom: 15px; */
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Node 服务示例
|
||||
* 处理设备节点相关的 STOMP 消息
|
||||
*/
|
||||
|
||||
import { stompService } from '@/utils/stompService';
|
||||
|
||||
interface NodeData {
|
||||
id: string;
|
||||
name: string;
|
||||
status: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface NodeRuntime {
|
||||
node: NodeData;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
class NodeService {
|
||||
public runtimes: Record<string, NodeRuntime> = {};
|
||||
|
||||
constructor() {
|
||||
// 注册服务
|
||||
stompService.registerService('node', this);
|
||||
}
|
||||
|
||||
/**
|
||||
* STOMP 连接成功后调用
|
||||
*/
|
||||
mqttReady(): void {
|
||||
console.log('[NodeService] STOMP 已就绪');
|
||||
// 可以在这里请求初始化数据
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接丢失时调用
|
||||
*/
|
||||
onConnectionLost(): void {
|
||||
console.log('[NodeService] STOMP 连接丢失');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 Node 初始化消息
|
||||
* @param value 初始化数据
|
||||
*/
|
||||
msgNodeInit(value: any): void {
|
||||
console.log('[NodeService] 收到 Node 初始化数据:', value);
|
||||
|
||||
// 处理初始化逻辑
|
||||
if (value && Array.isArray(value.nodes)) {
|
||||
value.nodes.forEach((node: NodeData) => {
|
||||
this.runtimes[node.id] = {
|
||||
node,
|
||||
lastUpdate: new Date()
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 Node 更新消息
|
||||
* @param value 更新数据
|
||||
*/
|
||||
msgNode(value: any): void {
|
||||
console.log('[NodeService] 收到 Node 更新:', value);
|
||||
|
||||
if (value && value.id) {
|
||||
const runtime = this.runtimes[value.id];
|
||||
if (runtime) {
|
||||
// 更新现有节点
|
||||
runtime.node = { ...runtime.node, ...value };
|
||||
runtime.lastUpdate = new Date();
|
||||
} else {
|
||||
// 添加新节点
|
||||
this.runtimes[value.id] = {
|
||||
node: value,
|
||||
lastUpdate: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 触发更新事件(可以使用 mitt 或其他事件总线)
|
||||
this.emitNodeUpdate(value.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点数据
|
||||
* @param nodeId 节点 ID
|
||||
*/
|
||||
getNode(nodeId: string): NodeData | null {
|
||||
const runtime = this.runtimes[nodeId];
|
||||
return runtime ? runtime.node : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有节点
|
||||
*/
|
||||
getAllNodes(): NodeData[] {
|
||||
return Object.values(this.runtimes).map((runtime) => runtime.node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节点属性
|
||||
* @param nodeId 节点 ID
|
||||
* @param updates 更新的属性
|
||||
*/
|
||||
updateNode(nodeId: string, updates: Partial<NodeData>): void {
|
||||
const runtime = this.runtimes[nodeId];
|
||||
if (runtime) {
|
||||
runtime.node = { ...runtime.node, ...updates };
|
||||
runtime.lastUpdate = new Date();
|
||||
|
||||
// 发送更新到服务器
|
||||
stompService.send('/app/web/write', 'nodeUpdate', {
|
||||
id: nodeId,
|
||||
updates
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发节点更新事件
|
||||
* @param nodeId 节点 ID
|
||||
*/
|
||||
private emitNodeUpdate(nodeId: string): void {
|
||||
// 这里可以使用 mitt 事件总线
|
||||
// emitter.emit('node-update', nodeId);
|
||||
console.log(`[NodeService] 节点 ${nodeId} 已更新`);
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例
|
||||
export const nodeService = new NodeService();
|
||||
export default nodeService;
|
||||
@ -0,0 +1,7 @@
|
||||
import axios from 'axios';
|
||||
const myAxios = axios.create({
|
||||
baseURL: 'http://localhost:8080',
|
||||
timeout: 60000,
|
||||
withCredentials: true
|
||||
});
|
||||
export default myAxios;
|
||||
@ -0,0 +1,270 @@
|
||||
import { dayjs } from 'element-plus';
|
||||
|
||||
interface RecIn {
|
||||
Node: {
|
||||
InTypeIn: [number, string][];
|
||||
TypeBase: [number, string][];
|
||||
};
|
||||
CONST: {
|
||||
STR: {
|
||||
EnumType: [number, string][];
|
||||
};
|
||||
YX: {
|
||||
EnumType: [number, string][];
|
||||
};
|
||||
UserPage: [string, string][];
|
||||
};
|
||||
EnumTypeVal: [number, string][][];
|
||||
EnumTypeValFun: Function[];
|
||||
regex: any;
|
||||
trans: (val: any, enumArr: [number, string][]) => string;
|
||||
}
|
||||
export const Rec: Partial<RecIn> = {};
|
||||
Rec.Node = {} as RecIn['Node'];
|
||||
Rec.CONST = {} as RecIn['CONST'];
|
||||
Rec.CONST.STR = {} as RecIn['CONST']['STR'];
|
||||
Rec.CONST.YX = {} as RecIn['CONST']['YX'];
|
||||
Rec.trans = (index, type) => {
|
||||
for (let i = 0; i < type.length; i++) {
|
||||
if (type[i][0] == index) {
|
||||
return type[i][1];
|
||||
}
|
||||
}
|
||||
return '*未知*';
|
||||
};
|
||||
// 所有输入类型
|
||||
Rec.Node.InTypeIn = [
|
||||
[1, '遥信'],
|
||||
[2, '遥测']
|
||||
];
|
||||
export const getIndex = (num: number) => {
|
||||
switch (num) {
|
||||
case 1:
|
||||
return 100;
|
||||
case 2:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 节点状态
|
||||
* @param num Node里面的sig值
|
||||
* @returns
|
||||
*/
|
||||
export const getNodeStatus = (sig: number) => {
|
||||
switch (sig) {
|
||||
case -2000:
|
||||
return '未初始化状态';
|
||||
case 0:
|
||||
return '正常';
|
||||
case 1:
|
||||
return '开启';
|
||||
case 5:
|
||||
return '联动关';
|
||||
case 10:
|
||||
return '高联动';
|
||||
case -10:
|
||||
return '低联动';
|
||||
case 20:
|
||||
return '高限告警';
|
||||
case -20:
|
||||
return '低限告警';
|
||||
default:
|
||||
return '未知状态';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 节点颜色
|
||||
* @param num Node里面的sig值
|
||||
* @returns
|
||||
*/
|
||||
export const getNodeColor = (sig: number) => {
|
||||
switch (sig) {
|
||||
case -2000:
|
||||
return 'info';
|
||||
case 0:
|
||||
case 1:
|
||||
return 'primary';
|
||||
case 5:
|
||||
case 10:
|
||||
case -10:
|
||||
return 'warning';
|
||||
case 20:
|
||||
case -20:
|
||||
return 'danger';
|
||||
default:
|
||||
return 'info';
|
||||
}
|
||||
};
|
||||
// 四遥基本类型
|
||||
Rec.Node.TypeBase = [
|
||||
[1, '遥信'],
|
||||
[2, '遥测'],
|
||||
[3, '遥控'],
|
||||
[4, '遥调']
|
||||
];
|
||||
|
||||
// 定值转化的 类型
|
||||
Rec.CONST.STR.EnumType = [
|
||||
[0, '缺省'],
|
||||
[1, '普通开关'],
|
||||
[2, '数值'],
|
||||
[3, '时间秒'],
|
||||
[11, 'RY空调模式'],
|
||||
[12, '空调温度'],
|
||||
[13, '空调风速'],
|
||||
[14, '国网空调模式'],
|
||||
[21, 'KTC空调']
|
||||
];
|
||||
Rec.CONST.YX.EnumType = [
|
||||
[0, '颜色'],
|
||||
[1, '文字'],
|
||||
[2, '颜色+文字']
|
||||
];
|
||||
|
||||
Rec.EnumTypeVal = []; // 定值类型,用于编辑时的选择
|
||||
Rec.EnumTypeValFun = []; // 转换函数,用于显示与控制
|
||||
|
||||
Rec.EnumTypeVal[100] = [
|
||||
[0, 'green'],
|
||||
[1, 'yellow'],
|
||||
[2, 'red']
|
||||
];
|
||||
Rec.EnumTypeVal[101] = [
|
||||
[0, '正常'],
|
||||
[1, '异常'],
|
||||
[2, '故障'],
|
||||
[3, '报警'],
|
||||
[4, '运行'],
|
||||
[5, '关闭']
|
||||
];
|
||||
Rec.EnumTypeVal[102] = [
|
||||
[0, '正常,green'],
|
||||
[1, '异常,saddlebrown'],
|
||||
[2, '故障,yellow'],
|
||||
[3, '报警,red'],
|
||||
[4, '运行,blue'],
|
||||
[5, '关闭,purple']
|
||||
];
|
||||
// 缺省
|
||||
Rec.EnumTypeVal[0] = [
|
||||
[0, '关闭'],
|
||||
[1, '开启']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[0] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![index + 0]);
|
||||
};
|
||||
//Rec.EnumTypeValFun[etype](val,getIndex(btype));
|
||||
|
||||
// 遥控
|
||||
Rec.EnumTypeVal[1] = [
|
||||
[0, '关闭'],
|
||||
[1, '开启']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[1] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![index + 1]);
|
||||
};
|
||||
|
||||
// 数值
|
||||
Rec.EnumTypeVal[2] = [];
|
||||
Rec.EnumTypeValFun[2] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![index + 2]);
|
||||
};
|
||||
|
||||
// timestamp 转换成时间
|
||||
Rec.EnumTypeValFun[3] = function (val: any) {
|
||||
// Ext.Date.format(val * 1000, 'Y-m-d H:i:s')
|
||||
dayjs.unix(val).format('YYYY-MM-DD HH:mm:ss');
|
||||
};
|
||||
|
||||
// 国网空调模式
|
||||
Rec.EnumTypeVal[14] = [
|
||||
[4, '自动'],
|
||||
[0, '制冷'],
|
||||
[1, '制热'],
|
||||
[3, '除湿'],
|
||||
[2, '送风']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[14] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![14]);
|
||||
};
|
||||
|
||||
// RY空调模式
|
||||
Rec.EnumTypeVal[11] = [
|
||||
[0, '自动'],
|
||||
[1, '制冷'],
|
||||
[2, '制热'],
|
||||
[3, '除湿'],
|
||||
[4, '送风']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[11] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![11]);
|
||||
};
|
||||
|
||||
// 空调温度
|
||||
Rec.EnumTypeVal[12] = [
|
||||
[16, '16℃'],
|
||||
[17, '17℃'],
|
||||
[18, '18℃'],
|
||||
[19, '19℃'],
|
||||
[20, '20℃'],
|
||||
[21, '21℃'],
|
||||
[22, '22℃'],
|
||||
[23, '23℃'],
|
||||
[24, '24℃'],
|
||||
[25, '25℃'],
|
||||
[26, '26℃'],
|
||||
[27, '27℃'],
|
||||
[28, '28℃'],
|
||||
[29, '29℃'],
|
||||
[30, '30℃']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[12] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![12]);
|
||||
};
|
||||
|
||||
// 空调风速
|
||||
Rec.EnumTypeVal[13] = [
|
||||
[0, '自动'],
|
||||
[1, '低'],
|
||||
[2, '中'],
|
||||
[3, '高']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[13] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![13]);
|
||||
};
|
||||
|
||||
// KTC 空调
|
||||
Rec.EnumTypeVal[21] = [
|
||||
[0, '关闭'],
|
||||
[1, '制冷'],
|
||||
[2, '制热']
|
||||
];
|
||||
|
||||
Rec.EnumTypeValFun[21] = function (val: any, index: number) {
|
||||
return Rec.trans!(val, Rec.EnumTypeVal![21]);
|
||||
};
|
||||
//
|
||||
Rec.EnumTypeValFun[21]();
|
||||
// 用户的缺省界面
|
||||
Rec.CONST.UserPage = [
|
||||
['Admin', 'Admin'],
|
||||
['User', 'User']
|
||||
];
|
||||
|
||||
// 正则表达式
|
||||
Rec.regex = {
|
||||
// Modbus 配置的正则表达式
|
||||
modbusCfg:
|
||||
/^(?:25[0-4]|2[0-4]\d|1\d{2}|[1-9]\d|[1-9]):(?:[1-6]|10):(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)(?::[2-9])?$/,
|
||||
modbusParm: /^(?:\d+(?::\d+){0,2})?$/
|
||||
};
|
||||
@ -0,0 +1,87 @@
|
||||
const EnumTypeVal: [number, string][][] = [];
|
||||
const EnumTypeValFun: ((val: number) => string)[] = [];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param type
|
||||
* @returns {string|*}
|
||||
*/
|
||||
const trans = function (index: number, type: any[]) {
|
||||
for (let i = 0; i < type.length; i++) {
|
||||
if (type[i][0] == index) {
|
||||
return type[i][1];
|
||||
}
|
||||
}
|
||||
return '*未知*';
|
||||
};
|
||||
|
||||
const EnumType = [
|
||||
[0, '缺省'],
|
||||
[1, '普通开关'],
|
||||
[2, '数值'],
|
||||
[3, '时间秒'],
|
||||
[11, 'RY空调模式'],
|
||||
[12, '空调温度'],
|
||||
[13, '空调风速'],
|
||||
[14, '国网空调模式'],
|
||||
[21, 'KTC空调']
|
||||
];
|
||||
|
||||
// 缺省
|
||||
EnumTypeVal[0] = [
|
||||
[0, '关闭'],
|
||||
[1, '开启']
|
||||
];
|
||||
EnumTypeValFun[0] = function (val: number) {
|
||||
return trans(val, EnumTypeVal[0]);
|
||||
};
|
||||
|
||||
// 遥控
|
||||
EnumTypeVal[1] = [
|
||||
[0, '关闭'],
|
||||
[1, '开启']
|
||||
];
|
||||
EnumTypeValFun[1] = function (val) {
|
||||
return trans(val, EnumTypeVal[1]);
|
||||
};
|
||||
|
||||
// 数值
|
||||
EnumTypeVal[2] = [];
|
||||
EnumTypeValFun[2] = function (val) {
|
||||
return val.toString();
|
||||
};
|
||||
|
||||
// timestamp 转换成时间
|
||||
EnumTypeValFun[3] = function (val) {
|
||||
return format(val * 1000, 'Y-m-d H:i:s');
|
||||
};
|
||||
|
||||
export { EnumTypeVal, EnumTypeValFun };
|
||||
|
||||
const format = function (date: Date, format: string) {
|
||||
var formatFunctions = formatFunctions;
|
||||
|
||||
if (!Ext.isDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (formatFunctions[format] == null) {
|
||||
utilDate.createFormat(format);
|
||||
}
|
||||
|
||||
return formatFunctions[format].call(date) + '';
|
||||
};
|
||||
|
||||
const formatFunctions: { [key: string]: () => string } = {
|
||||
MS: function () {
|
||||
// UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
|
||||
return '\\/Date(' + this.getTime() + ')\\/';
|
||||
},
|
||||
time: function () {
|
||||
return this.getTime().toString();
|
||||
},
|
||||
timestamp: function () {
|
||||
return format(this.getTime(), 'U');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,162 @@
|
||||
export interface Paragraph {
|
||||
field: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const invariantObjMap: Record<string, Paragraph[]> = {
|
||||
// 火灾报警系统主机
|
||||
fireAlarmHost: [
|
||||
{ field: '名称', value: '火灾报警系统主机' },
|
||||
{ field: '产品型号', value: 'JB-QB-GST200' },
|
||||
{ field: '厂商', value: '海湾公司' },
|
||||
{ field: '运行日期', value: '2023-04-01' },
|
||||
{ field: '电源电压', value: '220V AC' },
|
||||
{ field: '频率', value: '50Hz' },
|
||||
{ field: '输出电压', value: '24V DC' },
|
||||
{ field: '输出电流', value: '5A' },
|
||||
{ field: '环境温度', value: '-5℃ ~ 45℃' },
|
||||
{ field: '相对湿度', value: '5% ~ 95%' },
|
||||
{ field: '维护单位', value: '陕西消防科技有限公司' },
|
||||
{ field: '联系电话', value: '188*****00' }
|
||||
],
|
||||
// 主机
|
||||
host: [
|
||||
{ field: '名称', value: 'PAVLN排油注氮智能防护系统控制主机' },
|
||||
{ field: '型号', value: 'JB-QB-GST200' },
|
||||
{ field: '厂家', value: '海湾公司' },
|
||||
{ field: '运行日期', value: '2015-10-10' },
|
||||
{ field: '电源电压', value: 'DC 220V 5A/AC 220V 5A' },
|
||||
{ field: '频率', value: '27~1600MHz' },
|
||||
{ field: '输出电压', value: '24V DC' },
|
||||
{ field: '输出电流', value: '5A' },
|
||||
{ field: '环境温度', value: '-5℃ ~ 45℃' },
|
||||
{ field: '相对湿度', value: '5% ~ 95%' },
|
||||
{ field: '维护单位', value: '陕西消防科技有限公司' },
|
||||
{ field: '联系电话', value: '188*****00' }
|
||||
],
|
||||
// 2号主变油色谱
|
||||
oilChromatography: [
|
||||
{ field: '厂家', value: '宁波理工' },
|
||||
{ field: '型号', value: 'MGA2000-6H' },
|
||||
{ field: '投运日期', value: '2015年10月27日' },
|
||||
{ field: '工作电源', value: 'AC220V,50Hz' },
|
||||
{ field: '工作环境温度', value: '-40°C~+80°C' },
|
||||
{ field: '工作相对湿度', value: '5%~95%' }
|
||||
],
|
||||
//2号主变局放
|
||||
partialDischarge: [
|
||||
{ field: '厂家', value: '上海思瑞在线监测技术有限公司' },
|
||||
{ field: '型号', value: 'MGA2000-6H' },
|
||||
{ field: '投运日期', value: '2015年10月16日' },
|
||||
{ field: '局放测量通道', value: '3个局放测量通道+1个噪音测量通道' },
|
||||
{ field: '局放传感器频宽', value: '300MHZ~2000MHZ' },
|
||||
{ field: '工作环境温度', value: '-25°C~+55°C' },
|
||||
{ field: '工作相对湿度', value: '5%~95%' }
|
||||
],
|
||||
//2215开关间隔
|
||||
switchGap: [
|
||||
{ field: '厂家', value: '许继电气股份有限公司' },
|
||||
{ field: '型号', value: 'DPD-801' },
|
||||
{ field: '投运日期', value: '2015年11月17日' },
|
||||
{ field: '局放测量通道', value: '3个局放测量通道+1个噪音测量通道' },
|
||||
{ field: '工作环境温度', value: '-40°C~+70°C' },
|
||||
{ field: '工作相对湿度', value: '5%~95%' }
|
||||
]
|
||||
};
|
||||
|
||||
const threeDPath = {
|
||||
smokeSiren: '/models/smokeSiren/smokeSiren.glb',
|
||||
default: '/models/default/default.glb'
|
||||
};
|
||||
|
||||
export const invariant3DObjMap: Record<string, Paragraph[]> = {
|
||||
// 烟感报警器
|
||||
smokeSiren: [
|
||||
{ field: '3D模型', value: threeDPath.smokeSiren },
|
||||
{ field: '厂家', value: '海湾公司' },
|
||||
{ field: '型号', value: 'VLP-666-CH标准型' },
|
||||
{ field: '投运日期', value: '2014-06-08' },
|
||||
{ field: '布设位置', value: '35kV高压室' },
|
||||
{ field: '供电电压', value: '18-30VDC' },
|
||||
{ field: 'IP等级', value: 'IP30' },
|
||||
{ field: '接线方式', value: '两线制(L+、L-)' },
|
||||
{ field: '尺寸(长x高x宽)', value: '350mmx225mmx125mm' },
|
||||
{ field: '报警灵敏度范围', value: '0.005%至20%obs/m' },
|
||||
{ field: '运行条件1', value: '探测器环境(-5°C至45°C)' },
|
||||
{ field: '运行条件2', value: '采样空气(-20°C至60°C)' },
|
||||
{ field: '运行条件3', value: '湿度(5%至95%RH)' }
|
||||
],
|
||||
// 温感火灾探测器
|
||||
temperatureFireDetector: [
|
||||
{ field: '3D模型', value: threeDPath.default },
|
||||
{ field: '厂家', value: '海湾公司' },
|
||||
{ field: '型号', value: 'CT1-155X' },
|
||||
{ field: '投运日期', value: '2012-08-08' },
|
||||
{ field: '使用环境', value: '温度-5°C~45°C' },
|
||||
{ field: '火灾响应规模', value: '10mm' },
|
||||
{ field: '测量温度精度', value: '≤1°C' },
|
||||
{ field: '类型', value: '定温式' },
|
||||
{ field: '报警温度', value: '85°C' },
|
||||
{ field: '标准', value: 'GB16280-2014' }
|
||||
],
|
||||
// 消火栓
|
||||
fireHydrant: [
|
||||
{ field: '3D模型', value: threeDPath.default },
|
||||
{ field: '厂家', value: '宏达消防设备制造有限公司' },
|
||||
{ field: '型号', value: 'SN-65' },
|
||||
{ field: '投运日期', value: '2016-10-10' },
|
||||
{ field: '布设位置', value: '生产综合楼1楼走廊' },
|
||||
{ field: '质量保证书类型', value: '型式认证' },
|
||||
{ field: '质保证书', value: 'NO2015-2032' },
|
||||
{ field: '维保单位', value: '陕西消防科技有限公司' },
|
||||
{ field: '联系电话', value: '188*****00' }
|
||||
],
|
||||
// 灭火器
|
||||
fireExtinguisher: [
|
||||
{ field: '3D模型', value: threeDPath.default },
|
||||
{ field: '厂家', value: '天河消防厂' },
|
||||
{ field: '型号', value: 'MFZ35' },
|
||||
{ field: '投运日期', value: '2012-08-08' },
|
||||
{ field: '布设位置', value: '生产综合楼1楼35kV高压室' },
|
||||
{ field: '名称', value: '推车式干粉灭火器' },
|
||||
{ field: '品牌', value: '淮海' },
|
||||
{ field: '灭火剂', value: '碳酸铵盐50%、硫酸铵25%、滑石粉25%' },
|
||||
{ field: '灭火级别', value: 'ABCD' }
|
||||
],
|
||||
// 疏散指示灯
|
||||
evacuationSign: [
|
||||
{ field: '3D模型', value: threeDPath.default },
|
||||
{ field: '厂家', value: 'XXX消防设备有限公司' },
|
||||
{ field: '型号', value: 'BSD128F(自带应急照明)' },
|
||||
{ field: '投运日期', value: '2013-08-06' },
|
||||
{ field: '布设位置', value: '110kV保护室' },
|
||||
{ field: '输入电压', value: 'AC220V(+10%)' },
|
||||
{ field: '频率', value: '50Hz' },
|
||||
{ field: '功率', value: '<3W' },
|
||||
{ field: '应急时间', value: '>=90min' },
|
||||
{ field: '转换时间', value: '<=10s' },
|
||||
{ field: '充电时间', value: '>=24h' },
|
||||
{ field: '电池类型', value: 'Ni-Cd 1.2v 800mAh' }
|
||||
],
|
||||
// 红外对射
|
||||
infraredBeam: [
|
||||
{ field: '3D模型', value: threeDPath.default },
|
||||
{ field: '厂家', value: 'XX霍尼维尔' },
|
||||
{ field: '生产型号', value: 'DT-8041' },
|
||||
{ field: '供电电源', value: '9.0-15VDC' },
|
||||
{ field: '微波频率', value: '10.525GHz' },
|
||||
{ field: '工作温度', value: '-10°C~55°C' },
|
||||
{ field: '相对湿度', value: '5至93%' },
|
||||
{ field: '探测范围', value: '12m' }
|
||||
],
|
||||
// 门禁控制器
|
||||
accessController: [
|
||||
{ field: '3D模型', value: threeDPath.default },
|
||||
{ field: '生产厂家', value: 'Pegasus' },
|
||||
{ field: '生产型号', value: 'PP6750V' },
|
||||
{ field: '投运日期', value: '2017-05-09' },
|
||||
{ field: '电源电压', value: 'DC12V' },
|
||||
{ field: '工作电流', value: '100mA' },
|
||||
{ field: '管理门数', value: '4' }
|
||||
]
|
||||
};
|
||||
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 定义组件名称用于 keep-alive
|
||||
defineOptions({
|
||||
name: 'PreviewIndex'
|
||||
});
|
||||
|
||||
import { MtPreview } from '@/export';
|
||||
import { onMounted, ref, reactive, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { globalStore } from '@/components/mt-edit/store/global';
|
||||
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { modelApi } from '@/utils/request';
|
||||
const route = useRoute();
|
||||
|
||||
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
|
||||
const onEventCallBack = (type: string, item_id: string) => {
|
||||
console.log(type, item_id);
|
||||
|
||||
if (type == 'test-dialog') {
|
||||
ElMessage.success(`获取到了id:${item_id}`);
|
||||
}
|
||||
};
|
||||
onUnmounted(() => {
|
||||
console.log('view卸载完毕');
|
||||
});
|
||||
|
||||
async function newLoadModel() {
|
||||
let endJson = {
|
||||
menuType: route.query.screen
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await modelApi.model_getModelData_post(endJson);
|
||||
|
||||
if (response.code == 200) {
|
||||
const result = await response.data;
|
||||
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
|
||||
|
||||
// 对 importDoneJson 集合中每个元素的 props 属性使用 reactive 包装
|
||||
const processedImportDoneJson = importDoneJson.map((item) => {
|
||||
if (item.props) {
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
});
|
||||
|
||||
console.log('processedImportDoneJson:', processedImportDoneJson);
|
||||
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
|
||||
if (globalStore.group_ids.has(route.query.screen as string)) {
|
||||
globalStore.group_ids.delete(route.query.screen as string);
|
||||
}
|
||||
globalStore.group_ids.set(
|
||||
route.query.screen as string,
|
||||
processedImportDoneJson.map((item) => item.id)
|
||||
);
|
||||
|
||||
ElMessage.success('数据模型加载成功');
|
||||
} else {
|
||||
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
ElMessage.error('网络请求失败');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('view挂载完毕');
|
||||
newLoadModel();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vertical-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 定义组件名称用于 keep-alive
|
||||
defineOptions({
|
||||
name: 'PreviewIndex'
|
||||
});
|
||||
|
||||
import { MtPreview } from '@/export';
|
||||
import { onMounted, ref, reactive, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { globalStore } from '@/components/mt-edit/store/global';
|
||||
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { modelApi } from '@/utils/request';
|
||||
const route = useRoute();
|
||||
|
||||
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
|
||||
const onEventCallBack = (type: string, item_id: string) => {
|
||||
console.log(type, item_id);
|
||||
|
||||
if (type == 'test-dialog') {
|
||||
ElMessage.success(`获取到了id:${item_id}`);
|
||||
}
|
||||
};
|
||||
onUnmounted(() => {
|
||||
console.log('view卸载完毕');
|
||||
});
|
||||
|
||||
async function newLoadModel() {
|
||||
let endJson = {
|
||||
menuType: route.query.screen
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await modelApi.model_getModelData_post(endJson);
|
||||
|
||||
if (response.code == 200) {
|
||||
const result = await response.data;
|
||||
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
|
||||
|
||||
// 对 importDoneJson 集合中每个元素的 props 属性使用 reactive 包装
|
||||
const processedImportDoneJson = importDoneJson.map((item) => {
|
||||
if (item.props) {
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
});
|
||||
|
||||
console.log('processedImportDoneJson:', processedImportDoneJson);
|
||||
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
|
||||
if (globalStore.group_ids.has(route.query.screen as string)) {
|
||||
globalStore.group_ids.delete(route.query.screen as string);
|
||||
}
|
||||
globalStore.group_ids.set(
|
||||
route.query.screen as string,
|
||||
processedImportDoneJson.map((item) => item.id)
|
||||
);
|
||||
|
||||
ElMessage.success('数据模型加载成功');
|
||||
} else {
|
||||
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
ElMessage.error('网络请求失败');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('view挂载完毕');
|
||||
newLoadModel();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vertical-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
|
||||
</template>
|
||||
|
||||
<!-- 2号主变 -->
|
||||
|
||||
<script setup lang="ts">
|
||||
// 定义组件名称用于 keep-alive
|
||||
defineOptions({
|
||||
name: 'PreviewIndex'
|
||||
});
|
||||
|
||||
import { MtPreview } from '@/export';
|
||||
import { onMounted, ref, reactive, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { globalStore } from '@/components/mt-edit/store/global';
|
||||
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { modelApi } from '@/utils/request';
|
||||
const route = useRoute();
|
||||
|
||||
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
|
||||
const onEventCallBack = (type: string, item_id: string) => {
|
||||
console.log(type, item_id);
|
||||
|
||||
if (type == 'test-dialog') {
|
||||
ElMessage.success(`获取到了id:${item_id}`);
|
||||
}
|
||||
};
|
||||
onUnmounted(() => {
|
||||
console.log('view卸载完毕');
|
||||
});
|
||||
|
||||
async function newLoadModel() {
|
||||
let endJson = {
|
||||
menuType: route.query.screen
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await modelApi.model_getModelData_post(endJson);
|
||||
|
||||
if (response.code == 200) {
|
||||
const result = await response.data;
|
||||
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
|
||||
|
||||
// 对 importDoneJson 集合中每个元素的 props 属性使用 reactive 包装
|
||||
const processedImportDoneJson = importDoneJson.map((item) => {
|
||||
if (item.props) {
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
});
|
||||
|
||||
console.log('processedImportDoneJson:', processedImportDoneJson);
|
||||
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
|
||||
if (globalStore.group_ids.has(route.query.screen as string)) {
|
||||
globalStore.group_ids.delete(route.query.screen as string);
|
||||
}
|
||||
globalStore.group_ids.set(
|
||||
route.query.screen as string,
|
||||
processedImportDoneJson.map((item) => item.id)
|
||||
);
|
||||
|
||||
ElMessage.success('数据模型加载成功');
|
||||
} else {
|
||||
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
ElMessage.error('网络请求失败');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('view挂载完毕');
|
||||
newLoadModel();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vertical-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 定义组件名称用于 keep-alive
|
||||
defineOptions({
|
||||
name: 'homeOverrunMessage'
|
||||
});
|
||||
|
||||
import { MtPreview } from '@/export';
|
||||
import { onMounted, ref, reactive, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { globalStore } from '@/components/mt-edit/store/global';
|
||||
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { modelApi } from '@/utils/request';
|
||||
const route = useRoute();
|
||||
|
||||
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
|
||||
const onEventCallBack = (type: string, item_id: string) => {
|
||||
console.log(type, item_id);
|
||||
|
||||
if (type == 'test-dialog') {
|
||||
ElMessage.success(`获取到了id:${item_id}`);
|
||||
}
|
||||
};
|
||||
|
||||
//属性抽取
|
||||
function extractValFromProps(props: any) {
|
||||
const result: Record<string, any> = {};
|
||||
for (const key in props) {
|
||||
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
|
||||
result[key] = props[key].val;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
console.log('view卸载完毕');
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
newLoadModel();
|
||||
});
|
||||
|
||||
async function newLoadModel() {
|
||||
let endJson = {
|
||||
menuType: route.query.screen
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await modelApi.model_getModelData_post(endJson);
|
||||
|
||||
if (response.code == 200) {
|
||||
const result = await response.data;
|
||||
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
|
||||
|
||||
// 对 importDoneJson 集合中每个元素的 props 属性使用 reactive 包装
|
||||
const processedImportDoneJson = importDoneJson.map((item) => {
|
||||
if (item.props) {
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
props: reactive(item.props || {})
|
||||
};
|
||||
});
|
||||
|
||||
console.log('processedImportDoneJson:', processedImportDoneJson);
|
||||
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
|
||||
if (globalStore.group_ids.has(route.query.screen as string)) {
|
||||
globalStore.group_ids.delete(route.query.screen as string);
|
||||
}
|
||||
globalStore.group_ids.set(
|
||||
route.query.screen as string,
|
||||
processedImportDoneJson.map((item) => item.id)
|
||||
);
|
||||
|
||||
ElMessage.success('数据模型加载成功');
|
||||
} else {
|
||||
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('请求错误:', error);
|
||||
ElMessage.error('网络请求失败');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vertical-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
@ -1 +0,0 @@
|
||||
.vertical-radio-group[data-v-67a3c190]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}
|
||||
@ -1 +0,0 @@
|
||||
.vertical-radio-group[data-v-bdccb96b]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}
|
||||
@ -1 +0,0 @@
|
||||
import{d as g,aP as v,r as y,$ as w,Z as x,aw as M,x as l,O as c,I as a,i as h,h as E,o as J,_ as k}from"./index-9847718b.js";import{u as C}from"./index-fd059ba6.js";import{M as D}from"./index-868f5209.js";const I=g({__name:"homeExceptionFacility",setup(q){const n=v(),p=y(),d=(r,o)=>{console.log(r,o),r=="test-dialog"&&a.success(`获取到了id:${o}`)};w(()=>{console.log("view卸载完毕")}),x(()=>{i()});async function i(){var o;let r={menuType:n.query.screen};try{const s=await M.model_getModelData_post(r);if(s.code==200){const u=await s.data,{canvasCfg:_,gridCfg:f,importDoneJson:m}=C(u),t=m.map(e=>e.props?{...e,props:l(e.props||{})}:{...e,props:l(e.props||{})});console.log("processedImportDoneJson:",t),(o=p.value)==null||o.setNewImportJson({canvasCfg:_,gridCfg:f,json:t}),c.group_ids.has(n.query.screen)&&c.group_ids.delete(n.query.screen),c.group_ids.set(n.query.screen,t.map(e=>e.id)),a.success("数据模型加载成功")}else a.error(`数据模型加载失败: ${s.code} - ${s.message}`)}catch(s){console.error("请求错误:",s),a.error("网络请求失败")}}return(r,o)=>(J(),h(E(D),{ref_key:"MtPreviewRef",ref:p,onOnEventCallBack:d},null,512))}});const b=k(I,[["__scopeId","data-v-d872abad"]]);export{b as default};
|
||||
@ -1 +0,0 @@
|
||||
.vertical-radio-group[data-v-d872abad]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}
|
||||
@ -1 +0,0 @@
|
||||
import{d as g,aP as v,r as M,$ as w,Z as y,aw as h,x as u,O as c,I as a,i as J,h as x,o as O,_ as k}from"./index-9847718b.js";import{u as C}from"./index-fd059ba6.js";import{M as D}from"./index-868f5209.js";const I=g({name:"homeOverrunMessage",__name:"homeOverrunMessage",setup(q){const n=v(),p=M(),l=(r,o)=>{console.log(r,o),r=="test-dialog"&&a.success(`获取到了id:${o}`)};w(()=>{console.log("view卸载完毕")}),y(()=>{d()});async function d(){var o;let r={menuType:n.query.screen};try{const s=await h.model_getModelData_post(r);if(s.code==200){const _=await s.data,{canvasCfg:f,gridCfg:i,importDoneJson:m}=C(_),t=m.map(e=>e.props?{...e,props:u(e.props||{})}:{...e,props:u(e.props||{})});console.log("processedImportDoneJson:",t),(o=p.value)==null||o.setNewImportJson({canvasCfg:f,gridCfg:i,json:t}),c.group_ids.has(n.query.screen)&&c.group_ids.delete(n.query.screen),c.group_ids.set(n.query.screen,t.map(e=>e.id)),a.success("数据模型加载成功")}else a.error(`数据模型加载失败: ${s.code} - ${s.message}`)}catch(s){console.error("请求错误:",s),a.error("网络请求失败")}}return(r,o)=>(O(),J(x(D),{ref_key:"MtPreviewRef",ref:p,onOnEventCallBack:l},null,512))}});const $=k(I,[["__scopeId","data-v-436f0bc5"]]);export{$ as default};
|
||||
@ -1 +0,0 @@
|
||||
.vertical-radio-group[data-v-436f0bc5]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}
|
||||
@ -1 +0,0 @@
|
||||
.vertical-radio-group[data-v-d0f0d48f]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}
|
||||
@ -1 +0,0 @@
|
||||
.common-layout[data-v-635be2c1]{height:100vh;display:flex;align-items:center;justify-content:center}.layout-container[data-v-635be2c1]{width:100%;height:100vh;display:flex;flex-direction:column}.header-part[data-v-635be2c1]{height:18.75vh;background-color:#b3c0d1;display:flex;align-items:center;justify-content:center;font-size:36px;font-weight:700;color:#333}.main-part[data-v-635be2c1]{height:74.21875vh;background-color:#e9eef3;display:flex;align-items:center;justify-content:center;font-size:18px;color:#333}.footer-part[data-v-635be2c1]{height:7.03125vh;background-color:#d3dce6;padding:0!important;margin:0!important;color:#333;margin-top:0}.footer-part-col[data-v-635be2c1]{height:100%;background-color:#333;color:#606266;border:3px solid rgb(206,12,12);border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue