Showing
14 changed files
with
263 additions
and
15 deletions
... | ... | @@ -15,6 +15,7 @@ VITE_PUBLIC_PATH = / |
15 | 15 | # 线上测试环境 |
16 | 16 | # VITE_PROXY = [["/api","http://localhost:8080/api"],["/thingskit-drawio","http://localhost:3000/"]] |
17 | 17 | VITE_PROXY = [["/api","https://dev.thingskit.com/api"],["/thingskit-drawio","http://localhost:3000/"]] |
18 | +# VITE_PROXY = [["/api","http://192.168.10.106:8080/api"],["/thingskit-drawio","http://192.168.10.106:8080/api"]] | |
18 | 19 | |
19 | 20 | # 实时数据的ws地址 |
20 | 21 | # VITE_WEB_SOCKET = ws://localhost:8080/api/ws/plugins/telemetry?token= | ... | ... |
src/assets/icons/command.svg
0 → 100644
1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><path fill="currentColor" d="M3.5 2A1.5 1.5 0 0 1 5 3.5V5H3.5a1.5 1.5 0 1 1 0-3zM6 5V3.5A2.5 2.5 0 1 0 3.5 6H5v4H3.5A2.5 2.5 0 1 0 6 12.5V11h4v1.5a2.5 2.5 0 1 0 2.5-2.5H11V6h1.5A2.5 2.5 0 1 0 10 3.5V5H6zm4 1v4H6V6h4zm1-1V3.5A1.5 1.5 0 1 1 12.5 5H11zm0 6h1.5a1.5 1.5 0 1 1-1.5 1.5V11zm-6 0v1.5A1.5 1.5 0 1 1 3.5 11H5z"/></svg> | ... | ... |
src/assets/icons/light-bulb-off.svg
0 → 100644
1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64"><path fill="currentColor" d="M32 2C20.973 2 12 9.889 12 19.586c0 5.13 3.368 10.412 6.621 15.516c2.803 4.393 5.48 8.586 6.316 12.898h14.125c.838-4.313 3.512-8.506 6.314-12.898C48.631 29.998 52 24.716 52 19.586C52 9.889 43.027 2 32 2m0 27.674c1.932 2.085 3.752 2.705 4.584 2.889c-.125.555-.238 1.097-.369 1.631c-.246 1.092-.486 2.156-.719 3.178a723.122 723.122 0 0 0-1.895 8.629h-3.203a787.762 787.762 0 0 0-1.895-8.629l-.721-3.178c-.131-.534-.244-1.076-.367-1.631c.833-.184 2.653-.804 4.585-2.889m-.539-2.183c-.191-.413-.26-.835-.064-1.146c.164-.247.381-.388.604-.388s.438.141.604.388c.195.311.127.732-.064 1.146c-.141.292-.334.57-.541.839a4.66 4.66 0 0 1-.539-.839m12.23 6.534c-2.583 4.049-5.039 7.898-6.203 11.975h-3.246a801.908 801.908 0 0 0 2.113-8.465c.246-1.021.506-2.078.771-3.168c.148-.58.279-1.178.424-1.773c.756-.051 1.479-.287 2.043-.804c.578-.569.879-1.313.744-2.107c-.061-.38-.346-.872-.896-1.04a1.397 1.397 0 0 0-.832-.019a1.572 1.572 0 0 0-.598.396c-.533.592-.727 1.183-.945 1.769c-.102.295-.186.59-.266.881c0 0-.85.065-2.668-1.158c-1.01-.679-1.301-1.17-1.594-1.495c.316-.351.619-.736.854-1.203c.125-.261.23-.544.266-.862s-.023-.678-.205-.988a1.749 1.749 0 0 0-.865-.76c-.182-.065-.385-.096-.588-.096s-.408.03-.588.096a1.758 1.758 0 0 0-.867.76c-.182.311-.24.67-.205.988a2.7 2.7 0 0 0 .268.862c.234.467.537.853.854 1.203c-.293.325-.586.816-1.596 1.495c-1.818 1.224-2.668 1.158-2.668 1.158a14.153 14.153 0 0 0-.264-.881c-.221-.586-.412-1.177-.945-1.769a1.565 1.565 0 0 0-.598-.396a1.397 1.397 0 0 0-.832.019c-.553.168-.836.66-.896 1.04c-.137.794.166 1.538.744 2.107c.566.517 1.287.753 2.043.804c.143.596.273 1.193.424 1.773l.771 3.168A834.101 834.101 0 0 0 29.758 46h-3.246c-1.162-4.073-3.619-7.922-6.209-11.979C17.204 29.158 14 24.13 14 19.586C14 10.992 22.074 4 32 4c9.925 0 18 6.992 18 15.586c0 4.546-3.207 9.575-6.309 14.439m-5.892-2.361c.059-.205.119-.413.189-.613c.189-.527.43-1.1.758-1.443c.078-.088.158-.123.199-.146c0 .004.098-.012.16.019c.111.028.217.143.258.364c.08.428-.123.979-.49 1.324c-.258.245-.656.417-1.074.495m-11.6 0c-.418-.078-.816-.25-1.072-.496c-.369-.345-.57-.896-.49-1.324c.041-.222.146-.336.258-.364c.063-.03.16-.015.16-.019c.039.023.121.059.195.146c.33.344.57.916.76 1.443c.07.201.131.409.189.614m.321 17.893h-1v3.6h.768v3.201h.768v3.201h1.286C28.947 60.988 30.347 62 32 62c1.652 0 3.051-1.012 3.658-2.443h1.327v-3.221l.112-.041l.655-.24v-2.923l.065-.021l.701-.22v-3.335H26.52z"/></svg> | ... | ... |
src/assets/icons/light-bulb-on.svg
0 → 100644
1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64"><path fill="#616466" d="M28 58c0 2.2 1.8 4 4 4s4-1.8 4-4h-8"/><path fill="#ffce31" d="M24.9 48H39c.8-4.3 3.5-8.5 6.3-12.9C48.6 30 52 24.7 52 19.6C52 9.9 43 2 32 2S12 9.9 12 19.6c0 5.1 3.4 10.4 6.6 15.5c2.8 4.4 5.5 8.6 6.3 12.9"/><path fill="#c79127" d="M26.4 33.6c.1.6.3 1.2.4 1.8c.3 1.1.5 2.1.8 3.2c.9 3.8 1.7 7 2.4 9.5h.6c-.5-2.5-1.2-5.8-2.1-9.6c-.2-1-.5-2.1-.7-3.2c-.1-.5-.2-1.1-.4-1.6c.8-.2 2.7-.8 4.6-2.9c1.9 2.1 3.8 2.7 4.6 2.9c-.1.6-.2 1.1-.4 1.6c-.2 1.1-.5 2.2-.7 3.2c-.9 3.8-1.6 7.1-2.1 9.6h.6c.6-2.5 1.5-5.7 2.4-9.5c.2-1 .5-2.1.8-3.2c.1-.6.3-1.2.4-1.8c.8-.1 1.5-.3 2-.8c.6-.6.9-1.3.7-2.1c-.1-.4-.3-.9-.9-1c-.3-.1-.5-.1-.8 0c-.3.1-.5.3-.6.4c-.5.6-.7 1.2-.9 1.8l-.3.9s-.8.1-2.7-1.2c-1-.7-1.3-1.2-1.6-1.5c.3-.4.6-.7.9-1.2c.1-.3.2-.5.3-.9c0-.3 0-.7-.2-1c-.2-.3-.4-.6-.9-.8c-.2-.1-.4-.1-.6-.1s-.4 0-.6.1c-.4.2-.7.5-.9.8c-.2.3-.2.7-.2 1c0 .3.1.6.3.9c.2.5.5.9.9 1.2c-.3.3-.6.8-1.6 1.5c-1.8 1.2-2.7 1.2-2.7 1.2l-.3-.9c-.2-.6-.4-1.2-.9-1.8c-.1-.1-.3-.3-.6-.4c-.3-.1-.6-.1-.8 0c-.6.2-.8.7-.9 1c-.1.8.2 1.5.7 2.1c.6.5 1.3.7 2 .8M38 32.1c.2-.5.4-1.1.8-1.4c.1-.1.2-.1.2-.1h.2c.1 0 .2.1.3.4c.1.4-.1 1-.5 1.3c-.3.2-.7.4-1.1.5c0-.3 0-.5.1-.7m-6.6-4.8c.2-.2.4-.4.6-.4c.2 0 .4.1.6.4c.2.3.1.7-.1 1.1c-.1.3-.3.6-.5.8c-.2-.3-.4-.5-.5-.8c-.2-.3-.3-.7-.1-1.1m-6.8 3.5c0-.2.1-.3.3-.4h.2s.1.1.2.1c.3.3.6.9.8 1.4c.1.2.1.4.2.6c-.4-.1-.8-.2-1.1-.5c-.4-.2-.6-.7-.6-1.2"/><path fill="#94989b" d="M24.9 50h14.3v1.8H24.9zm1 3.6h12.3v1.8H25.9z"/><path fill="#616466" d="M25.9 51.8h12.3v1.8H25.9z"/><path fill="#94989b" d="m39.2 50l-13.3 3.6v1.9l13.3-3.7zm-12.3 7.3h10.3v1.8H26.9z"/><path fill="#616466" d="M26.9 55.5h10.3v1.8H26.9z"/><path fill="#94989b" d="m38.2 53.6l-11.3 3.7v1.9l11.3-3.7z"/></svg> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | - import on from '../assets/light-bulb-on.svg'; | |
3 | - import off from '../assets/light-bulb-off.svg'; | |
2 | + import on from '/@/assets/icons/light-bulb-on.svg'; | |
3 | + import off from '/@/assets/icons/light-bulb-off.svg'; | |
4 | 4 | |
5 | 5 | const props = defineProps<{ |
6 | 6 | value?: boolean; | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { computed } from '@vue/reactivity'; | |
3 | + import { Statistic } from 'ant-design-vue'; | |
4 | + import type { TextComponentLayout, TextComponentValue } from './config'; | |
5 | + import { SvgIcon } from '/@/components/Icon'; | |
6 | + const props = defineProps({ | |
7 | + layout: { | |
8 | + type: Object as PropType<TextComponentLayout>, | |
9 | + default: () => ({ base: true } as TextComponentLayout), | |
10 | + }, | |
11 | + value: { | |
12 | + type: Object as PropType<TextComponentValue>, | |
13 | + default: () => ({ name: '温度', value: 123 } as TextComponentValue), | |
14 | + }, | |
15 | + }); | |
16 | + | |
17 | + const getIsColumnLayout = computed(() => { | |
18 | + const { base } = props.layout; | |
19 | + return base; | |
20 | + }); | |
21 | + | |
22 | + const getShowIcon = computed(() => { | |
23 | + const { showIcon, base } = props.layout; | |
24 | + return base ? false : showIcon; | |
25 | + }); | |
26 | + | |
27 | + const getShowUpdate = computed(() => { | |
28 | + const { showUpdate, base } = props.layout; | |
29 | + return base ? false : showUpdate; | |
30 | + }); | |
31 | + | |
32 | + const getShowUnit = computed(() => { | |
33 | + const { showUnit, base } = props.layout; | |
34 | + return base ? false : showUnit; | |
35 | + }); | |
36 | +</script> | |
37 | + | |
38 | +<template> | |
39 | + <div class="w-full h-full flex flex-col"> | |
40 | + <div | |
41 | + class="flex justify-center items-center w-full text-center flex-auto" | |
42 | + :style="{ flexDirection: getIsColumnLayout ? 'column' : 'row' }" | |
43 | + > | |
44 | + <div class="w-1/2"> | |
45 | + <div> | |
46 | + <div v-if="getShowIcon"> | |
47 | + <SvgIcon name="CO2" prefix="iconfont" class="!w-1/2 !h-[2em]" /> | |
48 | + </div> | |
49 | + <div>{{ props.value.name }}</div> | |
50 | + </div> | |
51 | + </div> | |
52 | + <div class="w-1/2 flex justify-center"> | |
53 | + <Statistic | |
54 | + value="123" | |
55 | + :suffix="getShowUnit ? props.value.unit : ''" | |
56 | + :value-style="{ fontSize: '1.3em' }" | |
57 | + /> | |
58 | + </div> | |
59 | + </div> | |
60 | + <div v-if="getShowUpdate" class="h-6 text-center text-xs text-gray-400"> | |
61 | + <span> 更新时间: {{ props.value.updateTime }}</span> | |
62 | + </div> | |
63 | + </div> | |
64 | +</template> | ... | ... |
1 | +import { formatToDateTime } from '/@/utils/dateUtil'; | |
2 | + | |
3 | +export interface TextComponentLayout { | |
4 | + id: string; | |
5 | + base?: boolean; | |
6 | + showUpdate?: boolean; | |
7 | + showIcon?: boolean; | |
8 | + showUnit?: boolean; | |
9 | +} | |
10 | + | |
11 | +export interface TextComponentValue { | |
12 | + name: string; | |
13 | + value: number; | |
14 | + icon?: string; | |
15 | + unit?: string; | |
16 | + updateTime?: string; | |
17 | + fontColor?: string; | |
18 | + iconColor?: string; | |
19 | +} | |
20 | + | |
21 | +type TextComponentDefault = TextComponentLayout & { value: TextComponentValue }; | |
22 | + | |
23 | +export const textComponentConfig: TextComponentDefault[] = [ | |
24 | + { id: 'text-component-1', base: true, value: { value: 123, name: '温度' } }, | |
25 | + { id: 'text-component-2', base: false, value: { value: 123, name: '温度' } }, | |
26 | + { | |
27 | + id: 'text-component-3', | |
28 | + base: false, | |
29 | + showUpdate: true, | |
30 | + value: { | |
31 | + value: 123, | |
32 | + name: '温度', | |
33 | + updateTime: formatToDateTime(new Date(), 'YYYY-MM-DD HH:mm:ss'), | |
34 | + }, | |
35 | + }, | |
36 | + { | |
37 | + id: 'text-component-4', | |
38 | + base: false, | |
39 | + showIcon: true, | |
40 | + showUpdate: true, | |
41 | + showUnit: true, | |
42 | + value: { | |
43 | + value: 123, | |
44 | + name: '温度', | |
45 | + updateTime: formatToDateTime(new Date(), 'YYYY-MM-DD HH:mm:ss'), | |
46 | + unit: '℃', | |
47 | + }, | |
48 | + }, | |
49 | + { | |
50 | + id: 'text-component-5', | |
51 | + base: false, | |
52 | + showIcon: true, | |
53 | + showUnit: true, | |
54 | + value: { value: 123, name: '温度', unit: '℃' }, | |
55 | + }, | |
56 | +]; | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | - import { CopyOutlined, DeleteOutlined } from '@ant-design/icons-vue'; | |
2 | + import { CopyOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue'; | |
3 | 3 | import { Tooltip, Button } from 'ant-design-vue'; |
4 | 4 | import { useForm } from '/@/components/Form'; |
5 | 5 | import { basicSchema, dataSourceSchema } from '../config/basicConfiguration'; |
6 | 6 | import BasicForm from '/@/components/Form/src/BasicForm.vue'; |
7 | 7 | import { ref, unref } from 'vue'; |
8 | + import VisualOptionsModal from './VisualOptionsModal.vue'; | |
9 | + import { useModal } from '/@/components/Modal'; | |
8 | 10 | |
9 | 11 | const dataSource = ref([{ id: 1 }]); |
10 | 12 | |
... | ... | @@ -32,6 +34,12 @@ |
32 | 34 | }); |
33 | 35 | }; |
34 | 36 | |
37 | + const [registerVisualOptionModal, { openModal }] = useModal(); | |
38 | + | |
39 | + const handleSetting = () => { | |
40 | + openModal(true); | |
41 | + }; | |
42 | + | |
35 | 43 | const handleDelete = (data: Recordable) => { |
36 | 44 | const index = unref(dataSource).findIndex((item) => item.id === data.id); |
37 | 45 | |
... | ... | @@ -51,16 +59,19 @@ |
51 | 59 | <div class="w-3/4"> |
52 | 60 | <BasicForm @register="basicRegister" /> |
53 | 61 | </div> |
54 | - <h3 class="w-24 text-right pr-2 my-4">选择数据源</h3> | |
62 | + <h3 class="w-24 flex-shrink-0 text-right pr-2 my-4">选择数据源</h3> | |
55 | 63 | <div v-for="item in dataSource" :key="item.id" class="flex"> |
56 | - <div class="w-24 text-right">选择设备</div> | |
64 | + <div class="w-24 text-right" style="flex: 0 0 96px; padding-right: 8px">选择设备</div> | |
57 | 65 | <div class="pl-2 flex-auto"> |
58 | 66 | <BasicForm @register="dataSourceRegister" /> |
59 | 67 | </div> |
60 | - <div class="flex justify-center gap-3 w-12"> | |
68 | + <div class="flex justify-center gap-3 w-18"> | |
61 | 69 | <Tooltip title="复制"> |
62 | 70 | <CopyOutlined @click="handleCopy(item)" class="cursor-pointer text-lg" /> |
63 | 71 | </Tooltip> |
72 | + <Tooltip title="设置"> | |
73 | + <SettingOutlined @click="handleSetting(item)" class="cursor-pointer text-lg" /> | |
74 | + </Tooltip> | |
64 | 75 | <Tooltip title="删除"> |
65 | 76 | <DeleteOutlined @click="handleDelete(item)" class="cursor-pointer text-lg" /> |
66 | 77 | </Tooltip> |
... | ... | @@ -69,5 +80,6 @@ |
69 | 80 | <div class="text-center"> |
70 | 81 | <Button type="primary" @click="handleAdd">添加数据源</Button> |
71 | 82 | </div> |
83 | + <VisualOptionsModal @register="registerVisualOptionModal" /> | |
72 | 84 | </section> |
73 | 85 | </template> | ... | ... |
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | import BasicModal from '/@/components/Modal/src/BasicModal.vue'; |
5 | 5 | import BasicConfiguration from './BasicConfiguration.vue'; |
6 | 6 | import VisualConfiguration from './VisualConfiguration.vue'; |
7 | - import VisualOptions from './VisualOptions.vue'; | |
7 | + import VisualOptionsModal from './VisualOptionsModal.vue'; | |
8 | 8 | const activeKey = ref('1'); |
9 | 9 | </script> |
10 | 10 | |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | <VisualConfiguration /> |
20 | 20 | </Tabs.TabPane> |
21 | 21 | <Tabs.TabPane key="3" tab="可视化选项"> |
22 | - <VisualOptions /> | |
22 | + <VisualOptionsModal /> | |
23 | 23 | </Tabs.TabPane> |
24 | 24 | </Tabs> |
25 | 25 | </section> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | - import {} from 'ant-design-vue'; | |
2 | + import { Tabs, List } from 'ant-design-vue'; | |
3 | + import { ref } from 'vue'; | |
4 | + import VisualWidgetSelect from './VisualWidgetSelect.vue'; | |
5 | + import TextComponent from '../../components/TextComponent/TextComponent.vue'; | |
6 | + import { textComponentConfig } from '../../components/TextComponent/config'; | |
7 | + const checkedId = ref('1'); | |
8 | + | |
9 | + const handleCheck = (checked: string) => { | |
10 | + checkedId.value = checked; | |
11 | + }; | |
3 | 12 | </script> |
4 | 13 | |
5 | 14 | <template> |
6 | - <section> 可视化配置 </section> | |
15 | + <section> | |
16 | + <Tabs> | |
17 | + <Tabs.TabPane key="1" tab="文本组件"> | |
18 | + <List :grid="{ gutter: 10, column: 3 }" :data-source="textComponentConfig"> | |
19 | + <template #renderItem="{ item }"> | |
20 | + <List.Item> | |
21 | + <VisualWidgetSelect | |
22 | + :checked-id="checkedId" | |
23 | + :control-id="item.id" | |
24 | + @change="handleCheck" | |
25 | + > | |
26 | + <TextComponent :layout="item" :value="item.value" /> | |
27 | + </VisualWidgetSelect> | |
28 | + </List.Item> | |
29 | + </template> | |
30 | + </List> | |
31 | + </Tabs.TabPane> | |
32 | + <Tabs.TabPane key="2" tab="仪表组件"> | |
33 | + <div>仪表组件</div> | |
34 | + </Tabs.TabPane> | |
35 | + </Tabs> | |
36 | + </section> | |
7 | 37 | </template> | ... | ... |
src/views/data/board/detail/components/VisualOptions.vue
deleted
100644 → 0
1 | +<script lang="ts" setup> | |
2 | + import { Card } from 'ant-design-vue'; | |
3 | + | |
4 | + const props = defineProps({ | |
5 | + controlId: { | |
6 | + type: String, | |
7 | + required: true, | |
8 | + }, | |
9 | + checkedId: { | |
10 | + type: String, | |
11 | + required: true, | |
12 | + }, | |
13 | + }); | |
14 | + const emit = defineEmits(['change']); | |
15 | + | |
16 | + const handleClick = () => { | |
17 | + emit('change', props.controlId); | |
18 | + }; | |
19 | +</script> | |
20 | + | |
21 | +<template> | |
22 | + <Card | |
23 | + :style="{ borderColor: props.controlId === props.checkedId ? '#1a74e8' : '#f0f0f0' }" | |
24 | + hoverable | |
25 | + bordered | |
26 | + class="w-60 h-60 widget-select" | |
27 | + @click="handleClick" | |
28 | + > | |
29 | + <div class="widget-container"> | |
30 | + <slot></slot> | |
31 | + </div> | |
32 | + <Card.Meta> | |
33 | + <template #description> 选择 </template> | |
34 | + </Card.Meta> | |
35 | + </Card> | |
36 | +</template> | |
37 | + | |
38 | +<style scoped> | |
39 | + .widget-select:deep(.ant-card-body) { | |
40 | + /* height: 240px; */ | |
41 | + width: 240px; | |
42 | + padding: 0; | |
43 | + box-sizing: border-box; | |
44 | + display: flex; | |
45 | + flex-direction: column; | |
46 | + align-items: center; | |
47 | + justify-content: center; | |
48 | + } | |
49 | + | |
50 | + .widget-select:deep(.ant-card-meta) { | |
51 | + border-top: 1px solid #efefef; | |
52 | + width: 100%; | |
53 | + height: 40px; | |
54 | + text-align: center; | |
55 | + line-height: 40px; | |
56 | + margin: 0; | |
57 | + } | |
58 | + | |
59 | + .widget-select .widget-container { | |
60 | + width: 240px; | |
61 | + height: 200px; | |
62 | + display: flex; | |
63 | + justify-content: center; | |
64 | + align-items: center; | |
65 | + } | |
66 | +</style> | ... | ... |