Commit e535013c053a94c575f4ac130e0709b68c8d8cca

Authored by ww
1 parent 4ba5ef53

feat: widget dataSource add slaveDeviceId && deviceName

... ... @@ -5,6 +5,7 @@ import {
5 5 DataComponentRecord,
6 6 GetDataBoardParams,
7 7 Layout,
  8 + MasterDeviceList,
8 9 UpdateDataBoardLayoutParams,
9 10 UpdateDataBoardParams,
10 11 UpdateDataComponentParams,
... ... @@ -27,7 +28,9 @@ enum DataComponentUrl {
27 28 }
28 29
29 30 enum DeviceUrl {
30   - GET_DEVICE = '/device/list',
  31 + GET_DEVICE = '/device/list/master',
  32 + GET_SLAVE_DEVICE = '/device/list/slave',
  33 + GET_DEVICE_ATTRIBUTE = '/plugins/telemetry',
31 34 }
32 35
33 36 /**
... ... @@ -138,13 +141,42 @@ export const updateDataComponent = (params: UpdateDataComponentParams) => {
138 141 };
139 142
140 143 /**
141   - * @description 获取所有设备
  144 + * @description 获取所有设备
142 145 * @param params
143 146 * @returns
144 147 */
145   -export const getAllAvailableDeviceByOrgId = (params: string) => {
146   - return defHttp.get({
147   - url: `${DeviceUrl.GET_DEVICE}/DIRECT_CONNECTION`,
148   - params: { organizationId: params },
  148 +export const getAllDeviceByOrg = (params: string) => {
  149 + return defHttp.get<MasterDeviceList[]>({
  150 + url: `${DeviceUrl.GET_DEVICE}/${params}`,
149 151 });
150 152 };
  153 +
  154 +/**
  155 + * @description 获取网关子设备
  156 + * @param params
  157 + * @returns
  158 + */
  159 +export const getGatewaySlaveDevice = (params: { organizationId: string; masterId: string }) => {
  160 + const { masterId, organizationId } = params;
  161 + return defHttp.get<MasterDeviceList[]>({
  162 + url: `${DeviceUrl.GET_SLAVE_DEVICE}/${organizationId}`,
  163 + params: { masterId },
  164 + });
  165 +};
  166 +
  167 +/**
  168 + * @description 获取设备属性
  169 + * @param params
  170 + * @returns
  171 + */
  172 +export const getDeviceAttributes = (params: { entityType?: string; deviceId: string }) => {
  173 + const { entityType = 'DEVICE', deviceId } = params;
  174 + return defHttp.get<string[]>(
  175 + {
  176 + url: `${DeviceUrl.GET_DEVICE_ATTRIBUTE}/${entityType}/${deviceId}/keys/timeseries`,
  177 + },
  178 + {
  179 + joinPrefix: false,
  180 + }
  181 + );
  182 +};
... ...
... ... @@ -72,6 +72,8 @@ export interface DataSource {
72 72 organizationId: string;
73 73 attributeRename: string;
74 74 deviceRename: string;
  75 + slaveDeviceId: string;
  76 + isGatewayDevice: boolean;
75 77 componentInfo: ComponentInfo;
76 78 }
77 79
... ... @@ -119,3 +121,9 @@ export interface UpdateDataComponentParams {
119 121 boardId: string;
120 122 record: Partial<DataComponentRecord>;
121 123 }
  124 +
  125 +export interface MasterDeviceList {
  126 + deviceType: 'DIRECT_CONNECTION' | 'GATEWAY';
  127 + id: string;
  128 + name: string;
  129 +}
... ...
... ... @@ -101,6 +101,7 @@ export const instrumentComponent1 = (params?: {
101 101 borderRadius: 8,
102 102 offsetCenter: [0, '-15%'],
103 103 // fontSize: 16,
  104 + fontSize: 14,
104 105 fontWeight: 'bolder',
105 106 formatter: `{value} ${unit ?? '°C'}`,
106 107 color: params?.fontColor || 'inherit',
... ...
1 1 import { DataBoardLayoutInfo } from '../../types/type';
2   -import { DataSource } from '/@/api/dataBoard/model';
3   -
4   -// export interface DataSource {
5   -// id: number | string;
6   -// width: number;
7   -// height: number;
8   -
9   -// [key: string]: any;
10   -// }
11 2
12 3 export type WidgetWrapperRegister = (dataSource: DataBoardLayoutInfo['record'][]) => any;
... ...
... ... @@ -68,6 +68,7 @@
68 68 componentInfo: { ...componentInfo },
69 69 });
70 70 }
  71 + console.log(_dataSource);
71 72 return _dataSource;
72 73 };
73 74
... ... @@ -185,19 +186,19 @@
185 186 </div>
186 187 <div class="flex justify-center gap-3 w-24">
187 188 <Tooltip title="复制">
188   - <CopyOutlined @click="handleCopy(item)" class="cursor-pointer text-lg !leading-30px" />
  189 + <CopyOutlined @click="handleCopy(item)" class="cursor-pointer text-lg !leading-52px" />
189 190 </Tooltip>
190 191 <Tooltip title="设置">
191 192 <SettingOutlined
192 193 v-show="showSettingButton"
193 194 @click="handleSetting(item)"
194   - class="cursor-pointer text-lg !leading-30px"
  195 + class="cursor-pointer text-lg !leading-52px"
195 196 />
196 197 </Tooltip>
197 198 <Tooltip title="删除">
198 199 <DeleteOutlined
199 200 @click="handleDelete(item)"
200   - class="cursor-pointer text-lg !leading-30px"
  201 + class="cursor-pointer text-lg !leading-52px"
201 202 />
202 203 </Tooltip>
203 204 </div>
... ...
... ... @@ -5,9 +5,8 @@
5 5 import VisualConfiguration from './VisualConfiguration.vue';
6 6 import { computed, ref, unref } from 'vue';
7 7 import { RouteParams, useRoute } from 'vue-router';
8   - import { addDataComponent, updateDataBoardLayout, updateDataComponent } from '/@/api/dataBoard';
  8 + import { addDataComponent, updateDataComponent } from '/@/api/dataBoard';
9 9 import { useModalInner } from '/@/components/Modal';
10   - import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH } from '../../config/config';
11 10 import { DataBoardLayoutInfo } from '../../types/type';
12 11 import { useMessage } from '/@/hooks/web/useMessage';
13 12
... ... @@ -44,9 +43,11 @@
44 43 }>();
45 44
46 45 const handleSubmit = () => {
  46 + console.log({ isEdit: unref(isEdit) });
47 47 const { getAllDataSourceFieldValue } = unref(basicConfigurationEl)!;
48 48 const value = getAllDataSourceFieldValue();
49 49 unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value);
  50 + isEdit.value = false;
50 51 };
51 52
52 53 const handleAddComponent = async (value: Recordable) => {
... ...
  1 +<script setup lang="ts"></script>
  2 +
  3 +<template>
  4 + <div>历史趋势</div>
  5 +</template>
... ...
1   -import { getAllAvailableDeviceByOrgId } from '/@/api/dataBoard';
2   -import { getAttribute } from '/@/api/ruleengine/ruleengineApi';
  1 +import { getAllDeviceByOrg, getDeviceAttributes, getGatewaySlaveDevice } from '/@/api/dataBoard';
  2 +import { MasterDeviceList } from '/@/api/dataBoard/model';
3 3 import { getOrganizationList } from '/@/api/system/system';
4 4 import { FormSchema } from '/@/components/Form';
5 5 import { copyTransFun } from '/@/utils/fnUtils';
6   -import { to } from '/@/utils/to';
  6 +
  7 +export enum BasicConfigField {
  8 + NAME = 'name',
  9 + REMARK = 'remark',
  10 +}
  11 +
  12 +const getDeviceAttribute = async (deviceId: string) => {
  13 + try {
  14 + const data = await getDeviceAttributes({ deviceId });
  15 + if (data) return data.map((item) => ({ label: item, value: item }));
  16 + } catch (error) {}
  17 + return [];
  18 +};
7 19
8 20 export enum DataSourceField {
  21 + IS_GATEWAY_DEVICE = 'isGatewayDevice',
  22 + ORIGINATION_ID = 'organizationId',
9 23 DEVICE_ID = 'deviceId',
  24 + SLAVE_DEVICE_ID = 'slaveDeviceId',
  25 + ATTRIBUTE = 'attribute',
  26 + ATTRIBUTE_RENAME = 'attributeRename',
  27 + DEVICE_NAME = 'deviceName',
  28 + DEVICE_RENAME = 'deviceRename',
10 29 }
11 30
12 31 export const basicSchema: FormSchema[] = [
13 32 {
14   - field: 'name',
  33 + field: BasicConfigField.NAME,
15 34 label: '组件名称',
16 35 component: 'Input',
17 36 componentProps: {
... ... @@ -19,7 +38,7 @@ export const basicSchema: FormSchema[] = [
19 38 },
20 39 },
21 40 {
22   - field: 'remark',
  41 + field: BasicConfigField.REMARK,
23 42 label: '组件备注',
24 43 component: 'InputTextArea',
25 44 componentProps: {
... ... @@ -30,10 +49,22 @@ export const basicSchema: FormSchema[] = [
30 49
31 50 export const dataSourceSchema: FormSchema[] = [
32 51 {
33   - field: 'organizationId',
  52 + field: DataSourceField.IS_GATEWAY_DEVICE,
  53 + component: 'Switch',
  54 + label: '是否是网关设备',
  55 + show: false,
  56 + },
  57 + {
  58 + field: DataSourceField.DEVICE_NAME,
  59 + component: 'Input',
  60 + label: '设备名',
  61 + show: false,
  62 + },
  63 + {
  64 + field: DataSourceField.ORIGINATION_ID,
34 65 component: 'ApiTreeSelect',
35 66 label: '组织',
36   - colProps: { span: 6 },
  67 + colProps: { span: 8 },
37 68 componentProps({ formActionType }) {
38 69 const { setFieldsValue } = formActionType;
39 70 return {
... ... @@ -44,32 +75,47 @@ export const dataSourceSchema: FormSchema[] = [
44 75 return data;
45 76 },
46 77 onChange() {
47   - setFieldsValue({ deviceId: null, attribute: null });
  78 + setFieldsValue({
  79 + [DataSourceField.DEVICE_ID]: null,
  80 + [DataSourceField.ATTRIBUTE]: null,
  81 + [DataSourceField.SLAVE_DEVICE_ID]: null,
  82 + [DataSourceField.IS_GATEWAY_DEVICE]: false,
  83 + });
48 84 },
49 85 getPopupContainer: () => document.body,
50 86 };
51 87 },
52 88 },
53 89 {
54   - field: 'deviceId',
  90 + field: DataSourceField.DEVICE_ID,
55 91 component: 'ApiSelect',
56 92 label: '设备',
57   - colProps: { span: 5 },
  93 + colProps: { span: 8 },
58 94 componentProps({ formModel, formActionType }) {
59 95 const { setFieldsValue } = formActionType;
60   - const orgId = formModel['organizationId'];
  96 + const organizationId = formModel[DataSourceField.ORIGINATION_ID];
61 97 return {
62 98 api: async () => {
63   - if (orgId) {
64   - const [, data] = await to<Record<'id' | 'name', string>[]>(
65   - getAllAvailableDeviceByOrgId(orgId)
66   - );
67   - if (data) return data.map((item) => ({ label: item.name, value: item.id }));
  99 + if (organizationId) {
  100 + try {
  101 + const data = await getAllDeviceByOrg(organizationId);
  102 + if (data)
  103 + return data.map((item) => ({
  104 + label: item.name,
  105 + value: item.id,
  106 + deviceType: item.deviceType,
  107 + }));
  108 + } catch (error) {}
68 109 }
69 110 return [];
70 111 },
71   - onChange() {
72   - setFieldsValue({ attribute: null });
  112 + onChange(_value, record: Record<'value' | 'label' | 'deviceType', string>) {
  113 + setFieldsValue({
  114 + [DataSourceField.ATTRIBUTE]: null,
  115 + [DataSourceField.IS_GATEWAY_DEVICE]: record?.deviceType === 'GATEWAY',
  116 + [DataSourceField.SLAVE_DEVICE_ID]: null,
  117 + [DataSourceField.DEVICE_NAME]: record?.label,
  118 + });
73 119 },
74 120 placeholder: '请选择设备',
75 121 getPopupContainer: () => document.body,
... ... @@ -77,19 +123,68 @@ export const dataSourceSchema: FormSchema[] = [
77 123 },
78 124 },
79 125 {
80   - field: 'attribute',
  126 + field: DataSourceField.SLAVE_DEVICE_ID,
  127 + label: '网关子设备',
  128 + component: 'ApiSelect',
  129 + colProps: { span: 8 },
  130 + ifShow({ model }) {
  131 + return model['isGatewayDevice'];
  132 + },
  133 + dynamicRules({ model }) {
  134 + return [{ required: model[DataSourceField.IS_GATEWAY_DEVICE], message: '请选择网关子设备' }];
  135 + },
  136 + componentProps({ formModel, formActionType }) {
  137 + const { setFieldsValue } = formActionType;
  138 + const organizationId = formModel[DataSourceField.ORIGINATION_ID];
  139 + const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE];
  140 + const deviceId = formModel[DataSourceField.DEVICE_ID];
  141 + return {
  142 + api: async () => {
  143 + if (organizationId && isGatewayDevice) {
  144 + try {
  145 + const data = await getGatewaySlaveDevice({ organizationId, masterId: deviceId });
  146 + if (data)
  147 + return data.map((item) => ({
  148 + label: item.name,
  149 + value: item.id,
  150 + deviceType: item.deviceType,
  151 + }));
  152 + } catch (error) {}
  153 + }
  154 + return [];
  155 + },
  156 + onChange(_value, record: Record<'value' | 'label' | 'deviceType', string>) {
  157 + setFieldsValue({
  158 + [DataSourceField.ATTRIBUTE]: null,
  159 + [DataSourceField.DEVICE_NAME]: record?.label,
  160 + });
  161 + },
  162 + placeholder: '请选择网关子设备',
  163 + getPopupContainer: () => document.body,
  164 + };
  165 + },
  166 + },
  167 + {
  168 + field: DataSourceField.ATTRIBUTE,
81 169 component: 'ApiSelect',
82 170 label: '属性',
83   - colProps: { span: 5 },
  171 + colProps: { span: 8 },
84 172 componentProps({ formModel }) {
85   - const orgId = formModel['organizationId'];
86   - const deviceId = formModel['deviceId'];
  173 + const organizationId = formModel[DataSourceField.ORIGINATION_ID];
  174 + const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE];
  175 + const deviceId = formModel[DataSourceField.DEVICE_ID];
  176 + const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID];
87 177 return {
88 178 api: async () => {
89   - if (orgId && deviceId) {
90   - const [, data] = await to<string[]>(getAttribute(orgId, deviceId));
91   - // TODO attribute exist null
92   - if (data) return data.filter(Boolean).map((item) => ({ label: item, value: item }));
  179 + if (organizationId && deviceId) {
  180 + try {
  181 + if (isGatewayDevice && slaveDeviceId) {
  182 + return await getDeviceAttribute(slaveDeviceId);
  183 + }
  184 + if (!isGatewayDevice) {
  185 + return await getDeviceAttribute(deviceId);
  186 + }
  187 + } catch (error) {}
93 188 }
94 189 return [];
95 190 },
... ... @@ -99,19 +194,19 @@ export const dataSourceSchema: FormSchema[] = [
99 194 },
100 195 },
101 196 {
102   - field: 'deviceRename',
  197 + field: DataSourceField.DEVICE_RENAME,
103 198 component: 'Input',
104 199 label: '设备',
105   - colProps: { span: 4 },
  200 + colProps: { span: 8 },
106 201 componentProps: {
107 202 placeholder: '设备重命名',
108 203 },
109 204 },
110 205 {
111   - field: 'attributeRename',
  206 + field: DataSourceField.ATTRIBUTE_RENAME,
112 207 component: 'Input',
113 208 label: '属性',
114   - colProps: { span: 4 },
  209 + colProps: { span: 8 },
115 210 componentProps: {
116 211 placeholder: '属性重命名',
117 212 },
... ...
1 1 <script lang="ts" setup>
2   - import { Button, PageHeader } from 'ant-design-vue';
  2 + import { Button, PageHeader, Empty } from 'ant-design-vue';
3 3 import { GridItem, GridLayout } from 'vue3-grid-layout';
4 4 import { nextTick, onMounted, ref } from 'vue';
5 5 import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue';
... ... @@ -254,7 +254,7 @@
254 254 </template>
255 255 <div>
256 256 <span class="mr-3 text-gray-400">已创建组件:</span>
257   - <span class="text-cyan-400"> {{ dataBoardList.length }}个</span>
  257 + <span style="color: #409eff"> {{ dataBoardList.length }}个</span>
258 258 </div>
259 259 </PageHeader>
260 260 <section class="flex-1">
... ... @@ -307,6 +307,7 @@
307 307 </WidgetWrapper>
308 308 </GridItem>
309 309 </GridLayout>
  310 + <Empty v-if="!dataBoardList.length" />
310 311 </section>
311 312 <DataBindModal @register="register" @submit="getDataBoardComponent" />
312 313 </section>
... ...
... ... @@ -183,7 +183,7 @@
183 183 <div class="flex justify-between items-center">
184 184 <div>{{ item.name }}</div>
185 185 <div class="flex content-center">
186   - <Statistic value="12">
  186 + <Statistic :value="item.componentNum">
187 187 <template #suffix>
188 188 <span class="text-sm">个组件</span>
189 189 </template>
... ...