初始化

dev_xq_0.0.1
刘政 6 hours ago
parent de5d8c6208
commit bbb43faaa3

@ -13,7 +13,15 @@
</template>
<script setup lang="ts">
import { getCurrentInstance, defineAsyncComponent, ref, onMounted, h, createApp } from 'vue';
import {
getCurrentInstance,
defineAsyncComponent,
ref,
onMounted,
h,
createApp,
reactive
} from 'vue';
import { leftAsideStore } from '@/export';
import viewIndex from '@/layout/view_index.vue';
import zhCn from 'element-plus/es/locale/lang/zh-cn';
@ -74,6 +82,9 @@ import VueGuagePieChart from '@/components/vue-components/echarts-pie-chart.vue'
import VueSignalMonitoring from '@/components/vue-components/vue-signal-monitoring.vue';
import VueImgImmobilization from '@/components/vue-components/vue-img-immobilization.vue';
import VueCharacters from '@/components/vue-components/vue-characters.vue';
import VueGenerateTable from '@/components/vue-components/vue-generate-table.vue';
import { getTableOptionsVOList } from '@/api/TableInfoController';
import type { ILeftAsideConfigItemPublic } from '@/components/mt-edit/store/types';
const instance = getCurrentInstance();
instance?.appContext.app.component('vue-my-button', VueMyButton);
@ -124,8 +135,7 @@ instance?.appContext.app.component('vue-guage-pie-chart', VueGuagePieChart);
instance?.appContext.app.component('vue-img-immobilization', VueImgImmobilization);
instance?.appContext.app.component('vue-signal-monitoring', VueSignalMonitoring);
instance?.appContext.app.component('vue-characters', VueCharacters);
// instance?.appContext.app.component('vue-my-grade-gauge', VueGradeGauge);
instance?.appContext.app.component('vue-generate-table', VueGenerateTable);
const electrical_modules_files = import.meta.glob('./assets/svgs/electrical/**.svg', {
eager: true,
@ -185,9 +195,9 @@ leftAsideStore.registerConfig('vue四遥组件', [
},
{
id: 'vue-characters',
title: '遥信文字',
title: '遥信节点',
type: 'vue',
thumbnail: '/svgs/info.svg',
thumbnail: '/svgs/signal-gaudy.svg',
props: {
moduleType: {
type: 'inputTypeTag',
@ -663,97 +673,6 @@ leftAsideStore.registerConfig('vue公共组件', [
}
}
]);
leftAsideStore.registerConfig('vue图表', [
{
id: 'vue-grade-gauge',
title: '仪表盘',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
moduleType: {
type: 'inputTypeTag',
val: '遥测',
title: '绑定类型'
},
moduleId: {
type: 'inputSelectId',
val: '--',
title: '绑定ID'
},
maxNum: {
type: 'number',
val: 100,
title: '最大值'
},
minNum: {
type: 'number',
val: -10,
title: '最小值'
}
}
},
{
id: 'vue-guage-line-chart',
title: '折线图',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
headline: {
type: 'input',
val: '自定义标题',
title: '标题'
}
}
},
{
id: 'vue-guage-bar-chart',
title: '柱状图',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
headline: {
type: 'input',
val: '自定义标题',
title: '标题'
}
}
},
{
id: 'vue-guage-pie-chart',
title: '饼状图',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
headline: {
type: 'input',
val: '自定义标题',
title: '标题'
}
}
}
]);
leftAsideStore.registerConfig('vue3D组件', [
{
id: 'vue-my-three-machine',
@ -899,7 +818,6 @@ leftAsideStore.registerConfig('vue3D组件', [
}
}
]);
leftAsideStore.registerConfig('vue组件', [
{
id: 'vue-my-base-card-info',
@ -1394,7 +1312,95 @@ leftAsideStore.registerConfig('vue组件', [
}
}
]);
leftAsideStore.registerConfig('vue图表', [
{
id: 'vue-grade-gauge',
title: '仪表盘',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
moduleType: {
type: 'inputTypeTag',
val: '遥测',
title: '绑定类型'
},
moduleId: {
type: 'inputSelectId',
val: '--',
title: '绑定ID'
},
maxNum: {
type: 'number',
val: 100,
title: '最大值'
},
minNum: {
type: 'number',
val: -10,
title: '最小值'
}
}
},
{
id: 'vue-guage-line-chart',
title: '折线图',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
headline: {
type: 'input',
val: '自定义标题',
title: '标题'
}
}
},
{
id: 'vue-guage-bar-chart',
title: '柱状图',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
headline: {
type: 'input',
val: '自定义标题',
title: '标题'
}
}
},
{
id: 'vue-guage-pie-chart',
title: '饼状图',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
headline: {
type: 'input',
val: '自定义标题',
title: '标题'
}
}
}
]);
leftAsideStore.registerConfig('开发测试用', [
{
id: 'my-button',
@ -1520,4 +1526,35 @@ leftAsideStore.registerConfig('开发测试用', [
}
}
]);
const dynamicConfig = ref<any[]>([]);
const loadDynamicComponents = async () => {
const res = await getTableOptionsVOList();
if (res.data.code === 200) {
dynamicConfig.value = [
{
id: 'vue-generate-table',
title: '图表',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
dataSource: {
title: '表格类型',
type: 'select',
val: '--',
options: res.data.data
}
}
}
];
leftAsideStore.registerConfig('动态表格组件', dynamicConfig.value);
}
};
onMounted(() => {
loadDynamicComponents();
});
</script>

@ -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;
}

@ -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
};
}

@ -42,10 +42,6 @@
<!-- 按钮 -->
<el-col :span="3" v-if="isUpload">
<!-- <el-form-item>
<el-button type="success">上传</el-button>
</el-form-item> -->
<el-upload
accept="image/*"
:action="BASE_URL + '/fileStorage/saveFile'"
@ -175,8 +171,6 @@ const props = defineProps({
}
});
console.log('dialogImageVisible:', props.dialogImageVisible);
const emit = defineEmits(['updateDialogImageVisible', 'bindingImg']);
const bindingImg = (obj: any) => {
@ -287,7 +281,6 @@ async function loadFileList() {
startTime: form.fileDate ? new Date(form.fileDate[0]).getTime() : null,
endTime: form.fileDate ? new Date(form.fileDate[1]).getTime() : null
};
console.log('endJson:', endJson);
const response = await modelApi.fileStorage_file_list_post(endJson);
tableData.value = [];
if (!response.data) {

@ -15,6 +15,7 @@
:value="item.value"
/>
</el-select>
<!-- number -->
<el-input-number
v-else-if="attr_item.type === 'number' && !attr_item.disabled"
@ -67,15 +68,6 @@
</template>
</el-input-tag>
<!-- <el-upload
v-else-if="attr_item.type === 'upload' && !attr_item.disabled"
accept="image/*"
:action="BASE_URL + '/fileStorage/saveFile'"
:on-success="saveImageSuccess"
>
<el-button type="primary">绑定图片</el-button>
</el-upload> -->
<!-- inputTypeTag 类型标签 -->
<el-tag v-else-if="attr_item.type === 'inputTypeTag' && !attr_item.disabled">
{{ attr_item.val }}
@ -275,9 +267,7 @@ function bindingImg(obj: any) {
let modelIds = ref<string[]>([]);
function handleEdit(obj: any) {
console.log('绑定', modelIds.value);
dialogTableVisible.value = false;
modelIds.value = [obj.modeId];
attrItem.val = obj.modeId;
emits('selectById', obj.modeId);
}

@ -11,6 +11,7 @@ export type ILeftAsideConfigItemPublicPropsType =
| 'inputSelectId'
| 'inputTypeTag' //inputTypeTag 必须和 inputSelectId 一起使用
| 'inputSelectImgId'
| 'tableSelect'
| 'map'; //使用这个类型 disabled必须为true(必须隐藏)
// 开放注册配置
export type ILeftAsideConfigItemPublicProps = Record<

@ -1,14 +1,26 @@
<template>
<div class="vue-characters"></div>
<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 double = ref(-1);
const boolean = ref(false);
const alarms = ref(false);
const text = ref('正常');
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,
@ -27,16 +39,12 @@ const props = defineProps({
default: 'bottom'
}
});
const getSting = (data: any) => {
};
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
@ -46,22 +54,41 @@ function getModuleById(moduleId: string) {
return globalData[moduleId];
}
}
const getText = () => {
switch (type.value) {
case 0: {
color.value = Rec.EnumTypeValFun![etype.value](valInt.value, getIndex(btype.value));
break;
}
case 1: {
text.value = Rec.EnumTypeValFun![etype.value](valInt.value, getIndex(btype.value));
break;
}
case 2: {
const temp = Rec.EnumTypeValFun![etype.value](valInt.value, getIndex(btype.value));
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);
double.value = module.double;
boolean.value = module.double;
getSting({
double: double.value,
boolean: boolean.value,
alarms: alarms.value,
...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) => {
@ -75,5 +102,17 @@ watch(
.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,160 @@
<template>
<div class="generate-table">
<StandardDataGrid
:columns="tableColumns"
:tableData="deviceList"
:span-method="spanMethod"
@on-action="handleTableAction"
/>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue';
import type { DataGridSchema } from '@/components/custom-components/table-vue/type';
import StandardDataGrid from '@/components/custom-components/table-vue/StandardDataGrid.vue';
import {
createRowSpanMethod,
injectMultiNodeFlag
} from '@/components/custom-components/table-vue/utils/tableUtils';
import { useTableSpan } from '@/components/custom-components/table-vue/utils/useTableSpan';
import { Rec } from '@/utils/config';
import emitter from '@/utils/emitter';
import { useNodeByModelsStore } from '@/components/mt-edit/store/nodeByModels';
const nodeByModelsStore = useNodeByModelsStore();
const tableColumns = reactive<DataGridSchema>([]);
const deviceList = ref<any[]>([]);
const fetchDeviceData = async () => {
deviceList.value = [
{
id: 1,
location: '生产综合楼一楼',
deviceName: '一楼走廊控制器',
deviceStatus: '正常',
commStatus: '正常',
address: '一楼门厅',
switchStatus: 'turnOn'
},
{
id: 2,
location: '生产综合楼一楼',
deviceName: '一楼走廊控制器', // 🌟
deviceStatus: '正常',
commStatus: '正常',
address: '一楼走廊',
switchStatus: 'turnOff'
},
{
id: 3,
location: '生产综合楼一楼',
deviceName: '安全工器具室控制器', //
deviceStatus: '正常',
commStatus: '正常',
address: '安全工器具室',
switchStatus: 'turnOff'
},
{
id: 4,
location: '生产综合楼一楼',
deviceName: '220kV 保护室控制器',
deviceStatus: '正常',
commStatus: '正常',
address: '220kV 保护室东侧',
switchStatus: 'turnOff'
},
{
id: 5,
location: '生产综合楼一楼',
deviceName: '220kV 保护室控制器',
deviceStatus: '正常',
commStatus: '正常',
address: '220kV 保护室西侧',
switchStatus: 'turnOff'
},
{
type: 'controller',
location: '生产综合楼一楼照明:'
},
// --- ---
{
id: 6,
location: '生产综合楼二楼',
deviceName: '二楼走廊控制器',
deviceStatus: '正常',
commStatus: '正常',
address: '二楼走廊',
switchStatus: 'turnOff'
},
{
id: 7,
location: '生产综合楼二楼',
deviceName: '110kV GIS室控制器',
deviceStatus: '正常',
commStatus: '正常',
address: '110kV GIS室东侧',
switchStatus: 'turnOff'
},
{
id: 8,
location: '生产综合楼二楼',
deviceName: '110kV GIS室控制器',
deviceStatus: '正常',
commStatus: '正常',
address: '110kV GIS室西侧',
switchStatus: 'turnOn'
},
// 🌟
{
type: 'controller',
location: '生产综合楼二楼照明:'
}
];
//
deviceList.value = injectMultiNodeFlag(deviceList.value, 'deviceName', 'isMultiNode');
};
const { spanMethod } = useTableSpan(deviceList, tableColumns);
const handleTableAction = (action: any, data: any) => {
console.log('action', action);
console.log('data', data);
};
const props = defineProps({
moduleType: {
type: String,
default: '--'
},
moduleId: {
type: String,
default: '--'
},
definitionItemJson: {
type: Object,
default: () => ({})
},
location: {
type: String,
default: 'bottom'
},
dataSource: {
type: String,
default: '--'
}
});
watch(
() => props.dataSource,
(newVal, oldVal) => {
if(newVal==='--') return;
}
);
// onMounted(() => {
// fetchDeviceData();
// });
</script>
<style scoped>
div {
display: flex;
flex-direction: column;
}
</style>

@ -0,0 +1,7 @@
import axios from 'axios';
const myAxios = axios.create({
baseURL: 'http://localhost:8080',
timeout: 60000,
withCredentials: true
});
export default myAxios;

@ -2,57 +2,57 @@ import { dayjs } from 'element-plus';
interface RecIn {
Node: {
InTypeIn: [number, string][],
TypeBase: [number, string][],
},
InTypeIn: [number, string][];
TypeBase: [number, string][];
};
CONST: {
STR: {
EnumType: [number, string][]
},
EnumType: [number, string][];
};
YX: {
EnumType: [number, string][]
},
UserPage:[string, string][]
},
EnumTypeVal: [number, string][][],
EnumTypeValFun: Function[],
regex: any,
trans: (val: any, enumArr: [number, string][])=> string
EnumType: [number, string][];
};
UserPage: [string, string][];
};
EnumTypeVal: [number, string][][];
EnumTypeValFun: Function[];
regex: any;
trans: (val: any, enumArr: [number, string][]) => string;
}
const Rec: Partial<RecIn>={};
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 "*未知*";
return '*未知*';
};
// 所有输入类型
Rec.Node.InTypeIn = [
[1, '遥信'],
[2, '遥测']
];
const getIndex=(num:number)=>{
switch (num)
{
export const getIndex = (num: number) => {
switch (num) {
case 1:
return 100
return 100;
case 2:
return 0
return 0;
default:
return -1
}
return -1;
}
};
// 四遥基本类型
Rec.Node.TypeBase = [
[1, '遥信'],
[2, '遥测'],
[3, '遥控'],
[4, '遥调'],
[4, '遥调']
];
// 定值转化的 类型
@ -70,23 +70,32 @@ Rec.CONST.STR.EnumType = [
Rec.CONST.YX.EnumType = [
[0, '颜色'],
[1, '文字'],
[2, '颜色+文字'],
]
[2, '颜色+文字']
];
Rec.EnumTypeVal = []; // 定值类型,用于编辑时的选择
Rec.EnumTypeValFun = []; // 转换函数,用于显示与控制
Rec.EnumTypeVal[100] = [
[0, '绿色'],
[1, '黄色'],
[2, '红色'],
[0, 'green'],
[1, 'yellow'],
[2, 'red']
];
Rec.EnumTypeVal[101] = [
[0, '开启'],
[1, '关闭'],
[2, ''],
[0, '正常'],
[1, '异常'],
[2, '故障'],
[3, '报警'],
[4, '运行'],
[5, '关闭']
];
Rec.EnumTypeVal[102] = [
[0, '正常,green'],
[1, '异常,saddlebrown'],
[2, '故障,yellow'],
[3, '报警,red'],
[4, '运行,blue'],
[5, '关闭,purple']
];
// 缺省
Rec.EnumTypeVal[0] = [
@ -95,9 +104,9 @@ Rec.EnumTypeVal[0] = [
];
Rec.EnumTypeValFun[0] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index+0])
}
//Rec.EnumTypeValFun[0](val,getIndex(btype));
return Rec.trans!(val, Rec.EnumTypeVal![index + 0]);
};
//Rec.EnumTypeValFun[etype](val,getIndex(btype));
// 遥控
Rec.EnumTypeVal[1] = [
@ -106,20 +115,20 @@ Rec.EnumTypeVal[1] = [
];
Rec.EnumTypeValFun[1] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index+1])
}
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')
}
dayjs.unix(val).format('YYYY-MM-DD HH:mm:ss');
};
// 国网空调模式
Rec.EnumTypeVal[14] = [
@ -131,8 +140,8 @@ Rec.EnumTypeVal[14] = [
];
Rec.EnumTypeValFun[14] = function (val: any) {
return Rec.trans!(val, Rec.EnumTypeVal![14])
}
return Rec.trans!(val, Rec.EnumTypeVal![14]);
};
// RY空调模式
Rec.EnumTypeVal[11] = [
@ -144,8 +153,8 @@ Rec.EnumTypeVal[11] = [
];
Rec.EnumTypeValFun[11] = function (val: any) {
return Rec.trans!(val, Rec.EnumTypeVal![11])
}
return Rec.trans!(val, Rec.EnumTypeVal![11]);
};
// 空调温度
Rec.EnumTypeVal[12] = [
@ -167,8 +176,8 @@ Rec.EnumTypeVal[12] = [
];
Rec.EnumTypeValFun[12] = function (val: any) {
return Rec.trans!(val, Rec.EnumTypeVal![12])
}
return Rec.trans!(val, Rec.EnumTypeVal![12]);
};
// 空调风速
Rec.EnumTypeVal[13] = [
@ -179,8 +188,8 @@ Rec.EnumTypeVal[13] = [
];
Rec.EnumTypeValFun[13] = function (val: any) {
return Rec.trans!(val, Rec.EnumTypeVal![13])
}
return Rec.trans!(val, Rec.EnumTypeVal![13]);
};
// KTC 空调
Rec.EnumTypeVal[21] = [
@ -190,19 +199,20 @@ Rec.EnumTypeVal[21] = [
];
Rec.EnumTypeValFun[21] = function (val: any) {
return Rec.trans!(val, Rec.EnumTypeVal![21])
}
return Rec.trans!(val, Rec.EnumTypeVal![21]);
};
//
Rec.EnumTypeValFun[21]()
Rec.EnumTypeValFun[21]();
// 用户的缺省界面
Rec.CONST.UserPage = [
['Admin', 'Admin'],
['User', 'User'],
]
['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])?$/,
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})?$/
}
};

@ -13,7 +13,7 @@ const trans = function (index: number, type: any[]) {
return type[i][1];
}
}
return "*未知*";
return '*未知*';
};
const EnumType = [
@ -34,8 +34,8 @@ EnumTypeVal[0] = [
[1, '开启']
];
EnumTypeValFun[0] = function (val: number) {
return trans(val, EnumTypeVal[0])
}
return trans(val, EnumTypeVal[0]);
};
// 遥控
EnumTypeVal[1] = [
@ -43,24 +43,21 @@ EnumTypeVal[1] = [
[1, '开启']
];
EnumTypeValFun[1] = function (val) {
return trans(val, EnumTypeVal[1])
}
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')
}
return format(val * 1000, 'Y-m-d H:i:s');
};
export {EnumTypeVal,EnumTypeValFun}
export { EnumTypeVal, EnumTypeValFun };
const format = function (date: Date, format: string) {
var formatFunctions = formatFunctions;
@ -74,17 +71,17 @@ const format = function(date: Date, format: string) {
}
return formatFunctions[format].call(date) + '';
}
};
const formatFunctions: { [key: string]: () => string } = {
"MS": function() {
MS: function () {
// UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
return '\\/Date(' + this.getTime() + ')\\/';
},
"time": function() {
time: function () {
return this.getTime().toString();
},
"timestamp": function() {
timestamp: function () {
return format(this.getTime(), 'U');
}
}
};

@ -7,7 +7,8 @@
@on-return-click="onReturnClick"
@on-save-click="onSaveClick"
@on-thumbnail-click="onThumbnailClick"
></mt-edit>
>
</mt-edit>
</div>
</template>

Loading…
Cancel
Save