Commit 63b3580b7a943dee98aa46331fd772857a7469c4
Merge branch 'ww' into 'main'
feat: product profile add card mode && fix bug in teambition See merge request huang/yun-teng-iot-front!445
Showing
23 changed files
with
1042 additions
and
544 deletions
@@ -2,7 +2,9 @@ import { defHttp } from '/@/utils/http/axios'; | @@ -2,7 +2,9 @@ import { defHttp } from '/@/utils/http/axios'; | ||
2 | import { | 2 | import { |
3 | TDeviceConfigParams, | 3 | TDeviceConfigParams, |
4 | IDeviceConfigAddOrEditModel, | 4 | IDeviceConfigAddOrEditModel, |
5 | + ProfileRecord, | ||
5 | } from '/@/api/device/model/deviceConfigModel'; | 6 | } from '/@/api/device/model/deviceConfigModel'; |
7 | +import { PaginationResult } from '/#/axios'; | ||
6 | 8 | ||
7 | enum EDeviceConfigApi { | 9 | enum EDeviceConfigApi { |
8 | /** | 10 | /** |
@@ -52,7 +54,7 @@ export const alarmContactGetPage = () => { | @@ -52,7 +54,7 @@ export const alarmContactGetPage = () => { | ||
52 | * 分页查询设备配置页面 | 54 | * 分页查询设备配置页面 |
53 | */ | 55 | */ |
54 | export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { | 56 | export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { |
55 | - return defHttp.get({ | 57 | + return defHttp.get<PaginationResult<ProfileRecord>>({ |
56 | url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, | 58 | url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, |
57 | params, | 59 | params, |
58 | }); | 60 | }); |
@@ -199,3 +199,45 @@ export interface AlarmLogItem { | @@ -199,3 +199,45 @@ export interface AlarmLogItem { | ||
199 | organizationId: string; | 199 | organizationId: string; |
200 | organizationName: string; | 200 | organizationName: string; |
201 | } | 201 | } |
202 | + | ||
203 | +export interface Configuration { | ||
204 | + type: string; | ||
205 | +} | ||
206 | + | ||
207 | +export interface TransportConfiguration { | ||
208 | + type: string; | ||
209 | +} | ||
210 | + | ||
211 | +export interface ProvisionConfiguration { | ||
212 | + type: string; | ||
213 | + provisionDeviceSecret?: any; | ||
214 | +} | ||
215 | + | ||
216 | +export interface ProfileData { | ||
217 | + configuration: Configuration; | ||
218 | + transportConfiguration: TransportConfiguration; | ||
219 | + provisionConfiguration: ProvisionConfiguration; | ||
220 | + alarms?: any; | ||
221 | +} | ||
222 | + | ||
223 | +export interface ProfileRecord { | ||
224 | + id: string; | ||
225 | + creator: string; | ||
226 | + createTime: string; | ||
227 | + updater: string; | ||
228 | + updateTime: string; | ||
229 | + name: string; | ||
230 | + tenantId: string; | ||
231 | + transportType: string; | ||
232 | + provisionType: string; | ||
233 | + deviceType: string; | ||
234 | + tbProfileId: string; | ||
235 | + profileData: ProfileData; | ||
236 | + defaultRuleChainId: string; | ||
237 | + defaultQueueName: string; | ||
238 | + image: string; | ||
239 | + type: string; | ||
240 | + default: boolean; | ||
241 | + | ||
242 | + checked?: boolean; | ||
243 | +} |
src/assets/icons/product-default.svg
0 → 100644
1 | +<svg t="1671442803003" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4002" width="200" height="200"><path d="M0 0m178.086957 0l667.826086 0q178.086957 0 178.086957 178.086957l0 667.826086q0 178.086957-178.086957 178.086957l-667.826086 0q-178.086957 0-178.086957-178.086957l0-667.826086q0-178.086957 178.086957-178.086957Z" fill="#2E7BFC" p-id="4003"></path><path d="M758.717217 394.373565v268.866783l-238.191304 134.455652v-268.911304l124.14887-70.054957v94.497391l51.956869-29.985391V429.412174l62.107826-35.038609z m-493.434434 0l238.191304 134.433392v268.866782l-238.191304-134.433391V394.373565zM512 226.304l246.717217 139.241739L512 504.787478l-246.717217-139.241739L512 226.326261z" fill="#FFFFFF" p-id="4004"></path></svg> |
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | const iconList = IconData.icons; | 13 | const iconList = IconData.icons; |
14 | const [register, { openDrawer, closeDrawer }] = useDrawer(); | 14 | const [register, { openDrawer, closeDrawer }] = useDrawer(); |
15 | const getIcon = computed(() => { | 15 | const getIcon = computed(() => { |
16 | - return props.value || 'temperature'; | 16 | + return props.value || 'shuiwen'; |
17 | }); | 17 | }); |
18 | 18 | ||
19 | const getColor = computed(() => { | 19 | const getColor = computed(() => { |
src/components/Widget/CardLayoutButton.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { Popover, Slider, Button } from 'ant-design-vue'; | ||
3 | + import { LayoutOutlined } from '@ant-design/icons-vue'; | ||
4 | + import { computed } from 'vue'; | ||
5 | + | ||
6 | + const props = withDefaults( | ||
7 | + defineProps<{ | ||
8 | + min?: number; | ||
9 | + max?: number; | ||
10 | + value?: number; | ||
11 | + }>(), | ||
12 | + { | ||
13 | + min: 4, | ||
14 | + max: 12, | ||
15 | + value: 4, | ||
16 | + } | ||
17 | + ); | ||
18 | + | ||
19 | + const emit = defineEmits(['change', 'update:value']); | ||
20 | + | ||
21 | + const generateLayoutMarks = (min: number, max: number) => { | ||
22 | + const marks = {}; | ||
23 | + Array.from({ length: max - min + 1 }).forEach((_, index) => { | ||
24 | + const key = index + min; | ||
25 | + marks[key] = key; | ||
26 | + }); | ||
27 | + return marks; | ||
28 | + }; | ||
29 | + | ||
30 | + const getMarks = computed(() => { | ||
31 | + const { min, max } = props; | ||
32 | + return generateLayoutMarks(min, max); | ||
33 | + }); | ||
34 | + | ||
35 | + const handleChange = (value: number) => { | ||
36 | + emit('update:value', value); | ||
37 | + emit('change', value); | ||
38 | + }; | ||
39 | +</script> | ||
40 | + | ||
41 | +<template> | ||
42 | + <Popover :trigger="['hover']"> | ||
43 | + <template #content> | ||
44 | + <div class="w-60"> | ||
45 | + <div>每行显示数量</div> | ||
46 | + <Slider | ||
47 | + :value="props.value" | ||
48 | + :max="props.max" | ||
49 | + :min="props.min" | ||
50 | + :marks="getMarks" | ||
51 | + @change="handleChange" | ||
52 | + /> | ||
53 | + </div> | ||
54 | + </template> | ||
55 | + <Button type="primary"> | ||
56 | + <LayoutOutlined /> | ||
57 | + </Button> | ||
58 | + </Popover> | ||
59 | +</template> |
src/components/Widget/ModeSwitchButton.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { RadioButton, RadioGroup, Tooltip } from 'ant-design-vue'; | ||
3 | + import { TABLE_CARD_MODE_LIST } from './const'; | ||
4 | + import { ModeList } from './types'; | ||
5 | + import Icon from '../Icon'; | ||
6 | + const props = withDefaults( | ||
7 | + defineProps<{ | ||
8 | + value: string; | ||
9 | + mode?: ModeList[]; | ||
10 | + }>(), | ||
11 | + { | ||
12 | + mode: () => TABLE_CARD_MODE_LIST, | ||
13 | + } | ||
14 | + ); | ||
15 | + | ||
16 | + const emit = defineEmits(['change']); | ||
17 | + | ||
18 | + const handleChange = (event: Event) => { | ||
19 | + const value = (event.target as HTMLInputElement).value; | ||
20 | + emit('change', value); | ||
21 | + }; | ||
22 | +</script> | ||
23 | + | ||
24 | +<template> | ||
25 | + <RadioGroup :value="props.value" button-style="solid" @change="handleChange"> | ||
26 | + <template v-for="item in $props.mode" :key="item.value"> | ||
27 | + <Tooltip :title="item.label"> | ||
28 | + <RadioButton class="cursor-pointer" :value="item.value"> | ||
29 | + <Icon :icon="item.icon" /> | ||
30 | + </RadioButton> | ||
31 | + </Tooltip> | ||
32 | + </template> | ||
33 | + </RadioGroup> | ||
34 | +</template> |
src/components/Widget/const.ts
0 → 100644
1 | +import { ModeList } from './types'; | ||
2 | + | ||
3 | +export enum EnumTableCardMode { | ||
4 | + CARD = 'CARD', | ||
5 | + TABLE = 'TABLE', | ||
6 | +} | ||
7 | + | ||
8 | +export enum EnumTableChartMode { | ||
9 | + TABLE = 'TABLE', | ||
10 | + CHART = 'CHART', | ||
11 | +} | ||
12 | + | ||
13 | +export const TABLE_CARD_MODE_LIST: ModeList[] = [ | ||
14 | + { | ||
15 | + label: '卡片模式', | ||
16 | + value: EnumTableCardMode.CARD, | ||
17 | + icon: 'ant-design:appstore-outlined', | ||
18 | + }, | ||
19 | + { | ||
20 | + label: '列表模式', | ||
21 | + value: EnumTableCardMode.TABLE, | ||
22 | + icon: 'ant-design:unordered-list-outlined', | ||
23 | + }, | ||
24 | +]; | ||
25 | + | ||
26 | +export const TABLE_CHART_MODE_LIST: ModeList[] = [ | ||
27 | + { | ||
28 | + label: '图表模式', | ||
29 | + value: EnumTableChartMode.CHART, | ||
30 | + icon: 'ant-design:line-chart-outlined', | ||
31 | + }, | ||
32 | + { | ||
33 | + label: '列表模式', | ||
34 | + value: EnumTableChartMode.TABLE, | ||
35 | + icon: 'ant-design:unordered-list-outlined', | ||
36 | + }, | ||
37 | +]; |
src/components/Widget/index.ts
0 → 100644
1 | +export { default as ModeSwitchButton } from './ModeSwitchButton.vue'; | ||
2 | +export { default as CardLayoutButton } from './CardLayoutButton.vue'; | ||
3 | +export { | ||
4 | + EnumTableCardMode, | ||
5 | + EnumTableChartMode, | ||
6 | + TABLE_CARD_MODE_LIST, | ||
7 | + TABLE_CHART_MODE_LIST, | ||
8 | +} from './const'; | ||
9 | +export type { ModeList } from './types'; |
src/components/Widget/types.ts
0 → 100644
@@ -11,10 +11,10 @@ | @@ -11,10 +11,10 @@ | ||
11 | > | 11 | > |
12 | <template #toolbar> | 12 | <template #toolbar> |
13 | <a-button type="primary" @click="handleSwitchMode">分屏模式</a-button> | 13 | <a-button type="primary" @click="handleSwitchMode">分屏模式</a-button> |
14 | - <Authority value="api:yt:video:post"> | 14 | + <Authority :value="CameraPermission.CREATE"> |
15 | <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增视频 </a-button> | 15 | <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增视频 </a-button> |
16 | </Authority> | 16 | </Authority> |
17 | - <Authority value="api:yt:video:delete"> | 17 | + <Authority :value="CameraPermission.DELETE"> |
18 | <Popconfirm | 18 | <Popconfirm |
19 | title="您确定要批量删除数据" | 19 | title="您确定要批量删除数据" |
20 | ok-text="确定" | 20 | ok-text="确定" |
@@ -50,12 +50,12 @@ | @@ -50,12 +50,12 @@ | ||
50 | { | 50 | { |
51 | label: '预览', | 51 | label: '预览', |
52 | icon: 'clarity:note-edit-line', | 52 | icon: 'clarity:note-edit-line', |
53 | - auth: 'api:yt:video:get', | 53 | + auth: CameraPermission.PREVIEW, |
54 | onClick: handleViewVideo.bind(null, record), | 54 | onClick: handleViewVideo.bind(null, record), |
55 | }, | 55 | }, |
56 | { | 56 | { |
57 | label: '编辑', | 57 | label: '编辑', |
58 | - auth: 'api:yt:video:update', | 58 | + auth: CameraPermission.UPDATE, |
59 | icon: 'clarity:note-edit-line', | 59 | icon: 'clarity:note-edit-line', |
60 | onClick: handleCreateOrEdit.bind(null, record), | 60 | onClick: handleCreateOrEdit.bind(null, record), |
61 | }, | 61 | }, |
@@ -63,7 +63,7 @@ | @@ -63,7 +63,7 @@ | ||
63 | :drop-down-actions="[ | 63 | :drop-down-actions="[ |
64 | { | 64 | { |
65 | label: '删除', | 65 | label: '删除', |
66 | - auth: 'api:yt:video:delete', | 66 | + auth: CameraPermission.DELETE, |
67 | icon: 'ant-design:delete-outlined', | 67 | icon: 'ant-design:delete-outlined', |
68 | color: 'error', | 68 | color: 'error', |
69 | popConfirm: { | 69 | popConfirm: { |
@@ -89,7 +89,7 @@ | @@ -89,7 +89,7 @@ | ||
89 | import CameraDrawer from './CameraDrawer.vue'; | 89 | import CameraDrawer from './CameraDrawer.vue'; |
90 | import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree'; | 90 | import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree'; |
91 | import { cameraPage, deleteCameraManage } from '/@/api/camera/cameraManager'; | 91 | import { cameraPage, deleteCameraManage } from '/@/api/camera/cameraManager'; |
92 | - import { searchFormSchema, columns, AccessMode, PageMode } from './config.data'; | 92 | + import { searchFormSchema, columns, AccessMode, PageMode, CameraPermission } from './config.data'; |
93 | import VideoPreviewModal from './DialogPreviewVideo.vue'; | 93 | import VideoPreviewModal from './DialogPreviewVideo.vue'; |
94 | import { useModal } from '/@/components/Modal'; | 94 | import { useModal } from '/@/components/Modal'; |
95 | import { Authority } from '/@/components/Authority'; | 95 | import { Authority } from '/@/components/Authority'; |
@@ -199,6 +199,7 @@ | @@ -199,6 +199,7 @@ | ||
199 | registerModal, | 199 | registerModal, |
200 | AccessMode, | 200 | AccessMode, |
201 | handleSwitchMode, | 201 | handleSwitchMode, |
202 | + CameraPermission, | ||
202 | }; | 203 | }; |
203 | }, | 204 | }, |
204 | }); | 205 | }); |
@@ -8,13 +8,14 @@ | @@ -8,13 +8,14 @@ | ||
8 | import { useFullscreen } from '@vueuse/core'; | 8 | import { useFullscreen } from '@vueuse/core'; |
9 | import CameraDrawer from './CameraDrawer.vue'; | 9 | import CameraDrawer from './CameraDrawer.vue'; |
10 | import { useDrawer } from '/@/components/Drawer'; | 10 | import { useDrawer } from '/@/components/Drawer'; |
11 | - import { AccessMode, PageMode } from './config.data'; | 11 | + import { AccessMode, CameraPermission, PageMode } from './config.data'; |
12 | import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; | 12 | import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; |
13 | import { getStreamingPlayUrl } from '/@/api/camera/cameraManager'; | 13 | import { getStreamingPlayUrl } from '/@/api/camera/cameraManager'; |
14 | import { buildUUID } from '/@/utils/uuid'; | 14 | import { buildUUID } from '/@/utils/uuid'; |
15 | import { BasicVideoPlay, getVideoTypeByUrl } from '/@/components/Video'; | 15 | import { BasicVideoPlay, getVideoTypeByUrl } from '/@/components/Video'; |
16 | import { VideoJsPlayerOptions } from 'video.js'; | 16 | import { VideoJsPlayerOptions } from 'video.js'; |
17 | import { getBoundingClientRect } from '/@/utils/domUtils'; | 17 | import { getBoundingClientRect } from '/@/utils/domUtils'; |
18 | + import { Authority } from '/@/components/Authority'; | ||
18 | 19 | ||
19 | type CameraRecordItem = CameraRecord & { | 20 | type CameraRecordItem = CameraRecord & { |
20 | canPlay?: boolean; | 21 | canPlay?: boolean; |
@@ -220,7 +221,9 @@ | @@ -220,7 +221,9 @@ | ||
220 | </div> | 221 | </div> |
221 | <div class="flex items-center gap-4"> | 222 | <div class="flex items-center gap-4"> |
222 | <div class="flex"> | 223 | <div class="flex"> |
223 | - <Button type="primary" @click="handleAddCamera">新增视频</Button> | 224 | + <Authority :value="CameraPermission.CREATE"> |
225 | + <Button type="primary" @click="handleAddCamera">新增视频</Button> | ||
226 | + </Authority> | ||
224 | </div> | 227 | </div> |
225 | <Space> | 228 | <Space> |
226 | <Button type="primary" @click="handleChangeMode(PageMode.SPLIT_SCREEN_MODE)"> | 229 | <Button type="primary" @click="handleChangeMode(PageMode.SPLIT_SCREEN_MODE)"> |
@@ -6,6 +6,14 @@ import type { FormSchema as QFormSchema } from '/@/components/Form/index'; | @@ -6,6 +6,14 @@ import type { FormSchema as QFormSchema } from '/@/components/Form/index'; | ||
6 | import { CameraVideoUrl, CameraMaxLength, MediaTypeValidate } from '/@/utils/rules'; | 6 | import { CameraVideoUrl, CameraMaxLength, MediaTypeValidate } from '/@/utils/rules'; |
7 | import { h } from 'vue'; | 7 | import { h } from 'vue'; |
8 | import SnHelpMessage from './SnHelpMessage.vue'; | 8 | import SnHelpMessage from './SnHelpMessage.vue'; |
9 | + | ||
10 | +export enum CameraPermission { | ||
11 | + PREVIEW = 'api:yt:video:get', | ||
12 | + CREATE = 'api:yt:video:post', | ||
13 | + UPDATE = 'api:yt:video:update', | ||
14 | + DELETE = 'api:yt:video:delete', | ||
15 | +} | ||
16 | + | ||
9 | export enum AccessMode { | 17 | export enum AccessMode { |
10 | ManuallyEnter = 0, | 18 | ManuallyEnter = 0, |
11 | Streaming = 1, | 19 | Streaming = 1, |
@@ -9,6 +9,14 @@ export enum Platform { | @@ -9,6 +9,14 @@ export enum Platform { | ||
9 | PC = 'pc', | 9 | PC = 'pc', |
10 | } | 10 | } |
11 | 11 | ||
12 | +export enum ConfigurationPermission { | ||
13 | + CREATE = 'api:yt:configuration:center:post', | ||
14 | + UPDATE = 'api:yt:configuration:center:update', | ||
15 | + DELETE = 'api:yt:configuration:center:delete', | ||
16 | + DESIGN = 'api:yt:configuration:center:get_configuration_info:design', | ||
17 | + PREVIEW = 'api:yt:configuration:center:get_configuration_info:preview', | ||
18 | +} | ||
19 | + | ||
12 | export const PC_DEFAULT_CONTENT = | 20 | export const PC_DEFAULT_CONTENT = |
13 | '<mxfile><diagram>dZHBDsIgDIafhvuEzOh5Tr142sEzGXWQsHVhmKFP7xbAidMT5fv/UtoSVrTuZHgvLyhAE5oJR9iBUMrybT4dM3l4stnTzJPGKBHYAir1hACj7a4EDInRImqr+hTW2HVQ24RxY3BMbTfUadWeN7ACVc31ml6VsPK7jVk4g2pkLJ3tgtLy6A5gkFzg+IFYSVhhEK2PWleAnscXB+Pzjn/U988MdPZHwhQsb0+XZEesfAE=</diagram></mxfile>'; | 21 | '<mxfile><diagram>dZHBDsIgDIafhvuEzOh5Tr142sEzGXWQsHVhmKFP7xbAidMT5fv/UtoSVrTuZHgvLyhAE5oJR9iBUMrybT4dM3l4stnTzJPGKBHYAir1hACj7a4EDInRImqr+hTW2HVQ24RxY3BMbTfUadWeN7ACVc31ml6VsPK7jVk4g2pkLJ3tgtLy6A5gkFzg+IFYSVhhEK2PWleAnscXB+Pzjn/U988MdPZHwhQsb0+XZEesfAE=</diagram></mxfile>'; |
14 | 22 |
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | EditOutlined, | 7 | EditOutlined, |
8 | EllipsisOutlined, | 8 | EllipsisOutlined, |
9 | } from '@ant-design/icons-vue'; | 9 | } from '@ant-design/icons-vue'; |
10 | - import { onMounted, reactive, ref, unref } from 'vue'; | 10 | + import { computed, onMounted, reactive, ref, unref } from 'vue'; |
11 | import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree'; | 11 | import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree'; |
12 | import { | 12 | import { |
13 | deleteConfigurationCenter, | 13 | deleteConfigurationCenter, |
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | import { PageWrapper } from '/@/components/Page'; | 17 | import { PageWrapper } from '/@/components/Page'; |
18 | import { Dropdown } from '/@/components/Dropdown'; | 18 | import { Dropdown } from '/@/components/Dropdown'; |
19 | import { BasicForm, useForm } from '/@/components/Form'; | 19 | import { BasicForm, useForm } from '/@/components/Form'; |
20 | - import { searchFormSchema } from './center.data'; | 20 | + import { ConfigurationPermission, searchFormSchema } from './center.data'; |
21 | import { useMessage } from '/@/hooks/web/useMessage'; | 21 | import { useMessage } from '/@/hooks/web/useMessage'; |
22 | import { Authority } from '/@/components/Authority'; | 22 | import { Authority } from '/@/components/Authority'; |
23 | import { isDevMode } from '/@/utils/env'; | 23 | import { isDevMode } from '/@/utils/env'; |
@@ -98,6 +98,16 @@ | @@ -98,6 +98,16 @@ | ||
98 | 98 | ||
99 | const [registerDrawer, { openDrawer }] = useDrawer(); | 99 | const [registerDrawer, { openDrawer }] = useDrawer(); |
100 | 100 | ||
101 | + const { hasPermission } = usePermission(); | ||
102 | + | ||
103 | + const getPreviewFlag = computed(() => { | ||
104 | + return hasPermission(ConfigurationPermission.PREVIEW); | ||
105 | + }); | ||
106 | + | ||
107 | + const getDesignFlag = computed(() => { | ||
108 | + return hasPermission(ConfigurationPermission.DESIGN); | ||
109 | + }); | ||
110 | + | ||
101 | const handleCreateOrUpdate = (record?: ConfigurationCenterItemsModal) => { | 111 | const handleCreateOrUpdate = (record?: ConfigurationCenterItemsModal) => { |
102 | if (record) { | 112 | if (record) { |
103 | openDrawer(true, { | 113 | openDrawer(true, { |
@@ -114,15 +124,15 @@ | @@ -114,15 +124,15 @@ | ||
114 | const { configurationPrefix } = useGlobSetting(); | 124 | const { configurationPrefix } = useGlobSetting(); |
115 | const isDev = isDevMode(); | 125 | const isDev = isDevMode(); |
116 | 126 | ||
117 | - const { hasPermission } = usePermission(); | ||
118 | const handlePreview = (record: ConfigurationCenterItemsModal) => { | 127 | const handlePreview = (record: ConfigurationCenterItemsModal) => { |
119 | - if (!hasPermission('api:yt:configuration:center:get_configuration_info:get')) return; | 128 | + if (!unref(getPreviewFlag)) return; |
120 | window.open( | 129 | window.open( |
121 | `${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}&lightbox=1` | 130 | `${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}&lightbox=1` |
122 | ); | 131 | ); |
123 | }; | 132 | }; |
124 | 133 | ||
125 | const handleDesign = (record: ConfigurationCenterItemsModal) => { | 134 | const handleDesign = (record: ConfigurationCenterItemsModal) => { |
135 | + if (!unref(getDesignFlag)) return; | ||
126 | window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`); | 136 | window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`); |
127 | }; | 137 | }; |
128 | 138 | ||
@@ -175,7 +185,9 @@ | @@ -175,7 +185,9 @@ | ||
175 | > | 185 | > |
176 | <template #header> | 186 | <template #header> |
177 | <div class="flex gap-3 justify-end"> | 187 | <div class="flex gap-3 justify-end"> |
178 | - <Button type="primary" @click="handleCreateOrUpdate()">新增组态</Button> | 188 | + <Authority :value="ConfigurationPermission.CREATE"> |
189 | + <Button type="primary" @click="handleCreateOrUpdate()">新增组态</Button> | ||
190 | + </Authority> | ||
179 | <Popover :trigger="['hover']"> | 191 | <Popover :trigger="['hover']"> |
180 | <template #content> | 192 | <template #content> |
181 | <div class="w-50"> | 193 | <div class="w-50"> |
@@ -204,7 +216,7 @@ | @@ -204,7 +216,7 @@ | ||
204 | <List.Item> | 216 | <List.Item> |
205 | <Card hoverable> | 217 | <Card hoverable> |
206 | <template #cover> | 218 | <template #cover> |
207 | - <div class="h-full w-full !flex justify-center items-center text-center"> | 219 | + <div class="h-full w-full !flex justify-center items-center text-center p-1"> |
208 | <img | 220 | <img |
209 | class="w-full h-36" | 221 | class="w-full h-36" |
210 | alt="example" | 222 | alt="example" |
@@ -214,29 +226,35 @@ | @@ -214,29 +226,35 @@ | ||
214 | </div> | 226 | </div> |
215 | </template> | 227 | </template> |
216 | <template class="ant-card-actions" #actions> | 228 | <template class="ant-card-actions" #actions> |
217 | - <Authority value="api:yt:configuration:center:get_configuration_info:get"> | ||
218 | - <Tooltip title="预览"> | ||
219 | - <EyeOutlined key="setting" @click="handlePreview(item)" /> | ||
220 | - </Tooltip> | ||
221 | - </Authority> | ||
222 | - <Authority value="api:yt:configuration:center:get_configuration_info:get"> | ||
223 | - <Tooltip title="设计"> | ||
224 | - <EditOutlined key="edit" @click="handleDesign(item)" /> | ||
225 | - </Tooltip> | ||
226 | - </Authority> | 229 | + <Tooltip title="预览"> |
230 | + <EyeOutlined | ||
231 | + :class="getPreviewFlag ? '' : '!cursor-not-allowed !text-gray-200'" | ||
232 | + key="setting" | ||
233 | + @click="handlePreview(item)" | ||
234 | + /> | ||
235 | + </Tooltip> | ||
236 | + <Tooltip title="设计"> | ||
237 | + <EditOutlined | ||
238 | + :class="getDesignFlag ? '' : '!cursor-not-allowed !text-gray-200'" | ||
239 | + key="edit" | ||
240 | + @click="handleDesign(item)" | ||
241 | + /> | ||
242 | + </Tooltip> | ||
227 | <Dropdown | 243 | <Dropdown |
228 | :dropMenuList="[ | 244 | :dropMenuList="[ |
229 | { | 245 | { |
230 | text: '编辑', | 246 | text: '编辑', |
231 | - auth: 'api:yt:configuration:center:update', | 247 | + auth: ConfigurationPermission.UPDATE, |
232 | icon: 'clarity:note-edit-line', | 248 | icon: 'clarity:note-edit-line', |
249 | + event: '', | ||
233 | onClick: handleCreateOrUpdate.bind(null, item), | 250 | onClick: handleCreateOrUpdate.bind(null, item), |
234 | }, | 251 | }, |
235 | { | 252 | { |
236 | text: '删除', | 253 | text: '删除', |
237 | - auth: 'api:yt:configuration:center:delete', | 254 | + auth: ConfigurationPermission.DELETE, |
238 | icon: 'ant-design:delete-outlined', | 255 | icon: 'ant-design:delete-outlined', |
239 | color: 'error', | 256 | color: 'error', |
257 | + event: '', | ||
240 | onClick: handleDelete.bind(null, item), | 258 | onClick: handleDelete.bind(null, item), |
241 | }, | 259 | }, |
242 | ]" | 260 | ]" |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { computed, nextTick, onMounted, onUnmounted, Ref, ref, unref } from 'vue'; | 2 | import { computed, nextTick, onMounted, onUnmounted, Ref, ref, unref } from 'vue'; |
3 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; | 3 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; |
4 | - import { Empty, Spin, Tooltip, Button } from 'ant-design-vue'; | 4 | + import { Empty, Spin } from 'ant-design-vue'; |
5 | import { useECharts } from '/@/hooks/web/useECharts'; | 5 | import { useECharts } from '/@/hooks/web/useECharts'; |
6 | import { AggregateDataEnum, selectDeviceAttrSchema } from '/@/views/device/localtion/config.data'; | 6 | import { AggregateDataEnum, selectDeviceAttrSchema } from '/@/views/device/localtion/config.data'; |
7 | import { useTimePeriodForm } from '/@/views/device/localtion/cpns/TimePeriodForm'; | 7 | import { useTimePeriodForm } from '/@/views/device/localtion/cpns/TimePeriodForm'; |
@@ -13,8 +13,12 @@ | @@ -13,8 +13,12 @@ | ||
13 | import { useHistoryData } from '../../hook/useHistoryData'; | 13 | import { useHistoryData } from '../../hook/useHistoryData'; |
14 | import { formatToDateTime } from '/@/utils/dateUtil'; | 14 | import { formatToDateTime } from '/@/utils/dateUtil'; |
15 | import { useTable, BasicTable } from '/@/components/Table'; | 15 | import { useTable, BasicTable } from '/@/components/Table'; |
16 | - import { LineChartOutlined, BarsOutlined } from '@ant-design/icons-vue'; | ||
17 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | 16 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; |
17 | + import { | ||
18 | + ModeSwitchButton, | ||
19 | + TABLE_CHART_MODE_LIST, | ||
20 | + EnumTableChartMode, | ||
21 | + } from '/@/components/Widget'; | ||
18 | 22 | ||
19 | interface DeviceDetail { | 23 | interface DeviceDetail { |
20 | tbDeviceId: string; | 24 | tbDeviceId: string; |
@@ -26,12 +30,7 @@ | @@ -26,12 +30,7 @@ | ||
26 | attr?: string; | 30 | attr?: string; |
27 | }>(); | 31 | }>(); |
28 | 32 | ||
29 | - enum Mode { | ||
30 | - TABLE = 'table', | ||
31 | - CHART = 'chart', | ||
32 | - } | ||
33 | - | ||
34 | - const mode = ref<Mode>(Mode.CHART); | 33 | + const mode = ref<EnumTableChartMode>(EnumTableChartMode.CHART); |
35 | 34 | ||
36 | const chartRef = ref(); | 35 | const chartRef = ref(); |
37 | 36 | ||
@@ -151,9 +150,9 @@ | @@ -151,9 +150,9 @@ | ||
151 | attrInfo?.detail.dataType.type as unknown as DataTypeEnum | 150 | attrInfo?.detail.dataType.type as unknown as DataTypeEnum |
152 | ) | 151 | ) |
153 | ) { | 152 | ) { |
154 | - mode.value = Mode.TABLE; | 153 | + mode.value = EnumTableChartMode.TABLE; |
155 | } else { | 154 | } else { |
156 | - mode.value = Mode.CHART; | 155 | + mode.value = EnumTableChartMode.CHART; |
157 | } | 156 | } |
158 | } | 157 | } |
159 | } catch (error) {} | 158 | } catch (error) {} |
@@ -200,7 +199,7 @@ | @@ -200,7 +199,7 @@ | ||
200 | setOptions(setChartOptions(res, selectedKeys)); | 199 | setOptions(setChartOptions(res, selectedKeys)); |
201 | }; | 200 | }; |
202 | 201 | ||
203 | - const switchMode = (flag: Mode) => { | 202 | + const switchMode = (flag: EnumTableChartMode) => { |
204 | mode.value = flag; | 203 | mode.value = flag; |
205 | }; | 204 | }; |
206 | 205 | ||
@@ -221,55 +220,32 @@ | @@ -221,55 +220,32 @@ | ||
221 | </section> | 220 | </section> |
222 | <section class="bg-white p-3"> | 221 | <section class="bg-white p-3"> |
223 | <Spin :spinning="loading" :absolute="true"> | 222 | <Spin :spinning="loading" :absolute="true"> |
224 | - <div v-show="mode === Mode.CHART" class="flex h-70px items-center justify-end p-2"> | ||
225 | - <Tooltip title="图表模式"> | ||
226 | - <Button | ||
227 | - :class="[mode === Mode.CHART && '!bg-blue-500 svg:text-light-50']" | ||
228 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
229 | - @click="switchMode(Mode.CHART)" | ||
230 | - > | ||
231 | - <LineChartOutlined /> | ||
232 | - </Button> | ||
233 | - </Tooltip> | ||
234 | - | ||
235 | - <Tooltip title="列表模式"> | ||
236 | - <Button | ||
237 | - class="!p-2 !children:flex flex justify-center items-center" | ||
238 | - @click="switchMode(Mode.TABLE)" | ||
239 | - > | ||
240 | - <BarsOutlined /> | ||
241 | - </Button> | ||
242 | - </Tooltip> | 223 | + <div |
224 | + v-show="mode === EnumTableChartMode.CHART" | ||
225 | + class="flex h-70px items-center justify-end p-2" | ||
226 | + > | ||
227 | + <ModeSwitchButton | ||
228 | + v-model:value="mode" | ||
229 | + :mode="TABLE_CHART_MODE_LIST" | ||
230 | + @change="switchMode" | ||
231 | + /> | ||
243 | </div> | 232 | </div> |
244 | <div | 233 | <div |
245 | - v-show="isNull && mode === Mode.CHART" | 234 | + v-show="isNull && mode === EnumTableChartMode.CHART" |
246 | ref="chartRef" | 235 | ref="chartRef" |
247 | :style="{ height: '400px', width: '100%' }" | 236 | :style="{ height: '400px', width: '100%' }" |
248 | > | 237 | > |
249 | </div> | 238 | </div> |
250 | - <Empty v-show="!isNull && mode === Mode.CHART" /> | 239 | + <Empty v-show="!isNull && mode === EnumTableChartMode.CHART" /> |
251 | 240 | ||
252 | - <BasicTable v-show="mode === Mode.TABLE" @register="registerTable"> | 241 | + <BasicTable v-show="mode === EnumTableChartMode.TABLE" @register="registerTable"> |
253 | <template #toolbar> | 242 | <template #toolbar> |
254 | - <div v-show="mode === Mode.TABLE" class="flex h-70px items-center justify-end p-2"> | ||
255 | - <Tooltip title="图表模式"> | ||
256 | - <Button | ||
257 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
258 | - @click="switchMode(Mode.CHART)" | ||
259 | - > | ||
260 | - <LineChartOutlined /> | ||
261 | - </Button> | ||
262 | - </Tooltip> | ||
263 | - | ||
264 | - <Tooltip title="列表模式"> | ||
265 | - <Button | ||
266 | - :class="[mode === Mode.TABLE && '!bg-blue-500 svg:text-light-50']" | ||
267 | - class="!p-2 !children:flex flex justify-center items-center" | ||
268 | - @click="switchMode(Mode.TABLE)" | ||
269 | - > | ||
270 | - <BarsOutlined /> | ||
271 | - </Button> | ||
272 | - </Tooltip> | 243 | + <div class="flex h-70px items-center justify-end p-2"> |
244 | + <ModeSwitchButton | ||
245 | + v-model:value="mode" | ||
246 | + :mode="TABLE_CHART_MODE_LIST" | ||
247 | + @change="switchMode" | ||
248 | + /> | ||
273 | </div> | 249 | </div> |
274 | </template> | 250 | </template> |
275 | </BasicTable> | 251 | </BasicTable> |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { nextTick, onUnmounted, reactive, ref, unref } from 'vue'; | 2 | import { nextTick, onUnmounted, reactive, ref, unref } from 'vue'; |
3 | - import { List, Button, Tooltip, Card } from 'ant-design-vue'; | 3 | + import { List, Button, Card } from 'ant-design-vue'; |
4 | import { PageWrapper } from '/@/components/Page'; | 4 | import { PageWrapper } from '/@/components/Page'; |
5 | - import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons-vue'; | ||
6 | import { BasicTable, useTable } from '/@/components/Table'; | 5 | import { BasicTable, useTable } from '/@/components/Table'; |
7 | import { realTimeDataColumns } from '../../config/detail.config'; | 6 | import { realTimeDataColumns } from '../../config/detail.config'; |
8 | import { useWebSocket } from '@vueuse/core'; | 7 | import { useWebSocket } from '@vueuse/core'; |
@@ -20,6 +19,7 @@ | @@ -20,6 +19,7 @@ | ||
20 | import { isArray, isObject } from '/@/utils/is'; | 19 | import { isArray, isObject } from '/@/utils/is'; |
21 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | 20 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; |
22 | import { useGlobSetting } from '/@/hooks/setting'; | 21 | import { useGlobSetting } from '/@/hooks/setting'; |
22 | + import { ModeSwitchButton, EnumTableCardMode } from '/@/components/Widget'; | ||
23 | 23 | ||
24 | interface ReceiveMessage { | 24 | interface ReceiveMessage { |
25 | data: { | 25 | data: { |
@@ -112,14 +112,9 @@ | @@ -112,14 +112,9 @@ | ||
112 | 112 | ||
113 | const [registerModal, { openModal }] = useModal(); | 113 | const [registerModal, { openModal }] = useModal(); |
114 | 114 | ||
115 | - enum Mode { | ||
116 | - TABLE = 'table', | ||
117 | - CARD = 'card', | ||
118 | - } | ||
119 | - | ||
120 | - const mode = ref<Mode>(Mode.CARD); | 115 | + const mode = ref<EnumTableCardMode>(EnumTableCardMode.CARD); |
121 | 116 | ||
122 | - const switchMode = async (value: Mode) => { | 117 | + const switchMode = async (value: EnumTableCardMode) => { |
123 | mode.value = value; | 118 | mode.value = value; |
124 | await nextTick(); | 119 | await nextTick(); |
125 | setTableData(socketInfo.dataSource); | 120 | setTableData(socketInfo.dataSource); |
@@ -210,28 +205,14 @@ | @@ -210,28 +205,14 @@ | ||
210 | </div> | 205 | </div> |
211 | </section> | 206 | </section> |
212 | <section class="bg-light-50"> | 207 | <section class="bg-light-50"> |
213 | - <div v-show="mode === Mode.CARD" class="flex h-70px items-center justify-end p-2"> | ||
214 | - <Tooltip title="卡片模式"> | ||
215 | - <Button | ||
216 | - :class="[mode === Mode.CARD && '!bg-blue-500 svg:text-light-50']" | ||
217 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
218 | - @click="switchMode(Mode.CARD)" | ||
219 | - > | ||
220 | - <AppstoreOutlined /> | ||
221 | - </Button> | ||
222 | - </Tooltip> | ||
223 | - | ||
224 | - <Tooltip title="列表模式"> | ||
225 | - <Button | ||
226 | - class="!p-2 !children:flex flex justify-center items-center" | ||
227 | - @click="switchMode(Mode.TABLE)" | ||
228 | - > | ||
229 | - <BarsOutlined /> | ||
230 | - </Button> | ||
231 | - </Tooltip> | 208 | + <div |
209 | + v-show="mode === EnumTableCardMode.CARD" | ||
210 | + class="flex h-70px items-center justify-end p-2" | ||
211 | + > | ||
212 | + <ModeSwitchButton v-model:value="mode" @change="switchMode" /> | ||
232 | </div> | 213 | </div> |
233 | <List | 214 | <List |
234 | - v-if="mode === Mode.CARD" | 215 | + v-if="mode === EnumTableCardMode.CARD" |
235 | class="list-mode !px-2" | 216 | class="list-mode !px-2" |
236 | :data-source="socketInfo.dataSource" | 217 | :data-source="socketInfo.dataSource" |
237 | :grid="grid" | 218 | :grid="grid" |
@@ -260,27 +241,13 @@ | @@ -260,27 +241,13 @@ | ||
260 | </List> | 241 | </List> |
261 | </section> | 242 | </section> |
262 | 243 | ||
263 | - <BasicTable v-if="mode === Mode.TABLE" @register="registerTable"> | 244 | + <BasicTable v-if="mode === EnumTableCardMode.TABLE" @register="registerTable"> |
264 | <template #toolbar> | 245 | <template #toolbar> |
265 | - <div v-show="mode === Mode.TABLE" class="flex h-70px items-center justify-end p-2"> | ||
266 | - <Tooltip title="卡片模式"> | ||
267 | - <Button | ||
268 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
269 | - @click="switchMode(Mode.CARD)" | ||
270 | - > | ||
271 | - <AppstoreOutlined /> | ||
272 | - </Button> | ||
273 | - </Tooltip> | ||
274 | - | ||
275 | - <Tooltip title="列表模式"> | ||
276 | - <Button | ||
277 | - :class="[mode === Mode.TABLE && '!bg-blue-500 svg:text-light-50']" | ||
278 | - class="!p-2 !children:flex flex justify-center items-center" | ||
279 | - @click="switchMode(Mode.TABLE)" | ||
280 | - > | ||
281 | - <BarsOutlined /> | ||
282 | - </Button> | ||
283 | - </Tooltip> | 246 | + <div |
247 | + v-show="mode === EnumTableCardMode.TABLE" | ||
248 | + class="flex h-70px items-center justify-end p-2" | ||
249 | + > | ||
250 | + <ModeSwitchButton v-model:value="mode" @change="switchMode" /> | ||
284 | </div> | 251 | </div> |
285 | </template> | 252 | </template> |
286 | </BasicTable> | 253 | </BasicTable> |
@@ -50,28 +50,18 @@ | @@ -50,28 +50,18 @@ | ||
50 | <TimePeriodForm @register="timePeriodRegister" /> | 50 | <TimePeriodForm @register="timePeriodRegister" /> |
51 | <section> | 51 | <section> |
52 | <Spin :spinning="loading"> | 52 | <Spin :spinning="loading"> |
53 | - <div v-show="mode === Mode.CHART" class="flex h-70px items-center justify-end p-2"> | ||
54 | - <Tooltip title="图表模式"> | ||
55 | - <Button | ||
56 | - :class="[mode === Mode.CHART && '!bg-blue-500 svg:text-light-50']" | ||
57 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
58 | - @click="switchMode(Mode.CHART)" | ||
59 | - > | ||
60 | - <LineChartOutlined /> | ||
61 | - </Button> | ||
62 | - </Tooltip> | ||
63 | - | ||
64 | - <Tooltip title="列表模式"> | ||
65 | - <Button | ||
66 | - class="!p-2 !children:flex flex justify-center items-center" | ||
67 | - @click="switchMode(Mode.TABLE)" | ||
68 | - > | ||
69 | - <BarsOutlined /> | ||
70 | - </Button> | ||
71 | - </Tooltip> | 53 | + <div |
54 | + v-show="mode === EnumTableChartMode.CHART" | ||
55 | + class="flex h-70px items-center justify-end p-2" | ||
56 | + > | ||
57 | + <ModeSwitchButton | ||
58 | + v-model:value="mode" | ||
59 | + :mode="TABLE_CHART_MODE_LIST" | ||
60 | + @change="switchMode" | ||
61 | + /> | ||
72 | </div> | 62 | </div> |
73 | <div | 63 | <div |
74 | - v-show="isNull && mode === Mode.CHART" | 64 | + v-show="isNull && mode === EnumTableChartMode.CHART" |
75 | ref="chartRef" | 65 | ref="chartRef" |
76 | :style="{ height: '400px', width }" | 66 | :style="{ height: '400px', width }" |
77 | > | 67 | > |
@@ -79,30 +69,17 @@ | @@ -79,30 +69,17 @@ | ||
79 | <Empty | 69 | <Empty |
80 | :style="{ height: '550px', width }" | 70 | :style="{ height: '550px', width }" |
81 | class="flex flex-col justify-center items-center" | 71 | class="flex flex-col justify-center items-center" |
82 | - v-show="!isNull && mode === Mode.CHART" | 72 | + v-show="!isNull && mode === EnumTableChartMode.CHART" |
83 | /> | 73 | /> |
84 | 74 | ||
85 | - <BasicTable v-show="mode === Mode.TABLE" @register="registerAttrTable"> | 75 | + <BasicTable v-show="mode === EnumTableChartMode.TABLE" @register="registerAttrTable"> |
86 | <template #toolbar> | 76 | <template #toolbar> |
87 | - <div v-show="mode === Mode.TABLE" class="flex h-70px items-center justify-end p-2"> | ||
88 | - <Tooltip title="图表模式"> | ||
89 | - <Button | ||
90 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
91 | - @click="switchMode(Mode.CHART)" | ||
92 | - > | ||
93 | - <LineChartOutlined /> | ||
94 | - </Button> | ||
95 | - </Tooltip> | ||
96 | - | ||
97 | - <Tooltip title="列表模式"> | ||
98 | - <Button | ||
99 | - :class="[mode === Mode.TABLE && '!bg-blue-500 svg:text-light-50']" | ||
100 | - class="!p-2 !children:flex flex justify-center items-center" | ||
101 | - @click="switchMode(Mode.TABLE)" | ||
102 | - > | ||
103 | - <BarsOutlined /> | ||
104 | - </Button> | ||
105 | - </Tooltip> | 77 | + <div class="flex h-70px items-center justify-end p-2"> |
78 | + <ModeSwitchButton | ||
79 | + v-model:value="mode" | ||
80 | + :mode="TABLE_CHART_MODE_LIST" | ||
81 | + @change="switchMode" | ||
82 | + /> | ||
106 | </div> | 83 | </div> |
107 | </template> | 84 | </template> |
108 | </BasicTable> | 85 | </BasicTable> |
@@ -134,7 +111,7 @@ | @@ -134,7 +111,7 @@ | ||
134 | import { formSchema, columns } from './config.data'; | 111 | import { formSchema, columns } from './config.data'; |
135 | import { BasicTable, useTable } from '/@/components/Table'; | 112 | import { BasicTable, useTable } from '/@/components/Table'; |
136 | import { devicePage } from '/@/api/alarm/contact/alarmContact'; | 113 | import { devicePage } from '/@/api/alarm/contact/alarmContact'; |
137 | - import { Tag, Empty, Spin, Tooltip, Button } from 'ant-design-vue'; | 114 | + import { Tag, Empty, Spin } from 'ant-design-vue'; |
138 | import { DeviceState } from '/@/api/device/model/deviceModel'; | 115 | import { DeviceState } from '/@/api/device/model/deviceModel'; |
139 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; | 116 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; |
140 | import { useModal, BasicModal } from '/@/components/Modal'; | 117 | import { useModal, BasicModal } from '/@/components/Modal'; |
@@ -157,8 +134,12 @@ | @@ -157,8 +134,12 @@ | ||
157 | import { QueryWay, SchemaFiled, AggregateDataEnum } from './cpns/TimePeriodForm/config'; | 134 | import { QueryWay, SchemaFiled, AggregateDataEnum } from './cpns/TimePeriodForm/config'; |
158 | import { useAsyncQueue } from './useAsyncQueue'; | 135 | import { useAsyncQueue } from './useAsyncQueue'; |
159 | import { useHistoryData } from '../list/hook/useHistoryData'; | 136 | import { useHistoryData } from '../list/hook/useHistoryData'; |
160 | - import { LineChartOutlined, BarsOutlined } from '@ant-design/icons-vue'; | ||
161 | import { formatToDateTime } from '/@/utils/dateUtil'; | 137 | import { formatToDateTime } from '/@/utils/dateUtil'; |
138 | + import { | ||
139 | + TABLE_CHART_MODE_LIST, | ||
140 | + EnumTableChartMode, | ||
141 | + ModeSwitchButton, | ||
142 | + } from '/@/components/Widget'; | ||
162 | 143 | ||
163 | interface DeviceInfo { | 144 | interface DeviceInfo { |
164 | alarmStatus: 0 | 1; | 145 | alarmStatus: 0 | 1; |
@@ -183,10 +164,7 @@ | @@ -183,10 +164,7 @@ | ||
183 | DeviceDetailDrawer, | 164 | DeviceDetailDrawer, |
184 | TimePeriodForm, | 165 | TimePeriodForm, |
185 | Spin, | 166 | Spin, |
186 | - Tooltip, | ||
187 | - Button, | ||
188 | - LineChartOutlined, | ||
189 | - BarsOutlined, | 167 | + ModeSwitchButton, |
190 | }, | 168 | }, |
191 | props: { | 169 | props: { |
192 | width: { | 170 | width: { |
@@ -199,12 +177,7 @@ | @@ -199,12 +177,7 @@ | ||
199 | }, | 177 | }, |
200 | }, | 178 | }, |
201 | setup() { | 179 | setup() { |
202 | - enum Mode { | ||
203 | - TABLE = 'table', | ||
204 | - CHART = 'chart', | ||
205 | - } | ||
206 | - | ||
207 | - const mode = ref<Mode>(Mode.CHART); | 180 | + const mode = ref<EnumTableChartMode>(EnumTableChartMode.CHART); |
208 | let entityId = ''; | 181 | let entityId = ''; |
209 | let globalRecord: any = {}; | 182 | let globalRecord: any = {}; |
210 | const wrapRef = ref<HTMLDivElement | null>(null); | 183 | const wrapRef = ref<HTMLDivElement | null>(null); |
@@ -571,13 +544,14 @@ | @@ -571,13 +544,14 @@ | ||
571 | openGatewayDetailDrawer(true, data); | 544 | openGatewayDetailDrawer(true, data); |
572 | }; | 545 | }; |
573 | 546 | ||
574 | - const switchMode = (flag: Mode) => { | 547 | + const switchMode = (flag: EnumTableChartMode) => { |
575 | mode.value = flag; | 548 | mode.value = flag; |
576 | }; | 549 | }; |
577 | 550 | ||
578 | return { | 551 | return { |
579 | mode, | 552 | mode, |
580 | - Mode, | 553 | + EnumTableChartMode, |
554 | + TABLE_CHART_MODE_LIST, | ||
581 | wrapRef, | 555 | wrapRef, |
582 | registerTable, | 556 | registerTable, |
583 | deviceRowClick, | 557 | deviceRowClick, |
src/views/device/profiles/CardMode.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { PageWrapper } from '/@/components/Page'; | ||
3 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
4 | + import { List, Button, Tooltip, Card, PaginationProps, Image } from 'ant-design-vue'; | ||
5 | + import { ReloadOutlined, EyeOutlined, FormOutlined, MoreOutlined } from '@ant-design/icons-vue'; | ||
6 | + import { computed, onMounted, reactive, ref, unref } from 'vue'; | ||
7 | + import { CardLayoutButton, EnumTableCardMode, ModeSwitchButton } from '/@/components/Widget'; | ||
8 | + import { Authority } from '/@/components/Authority'; | ||
9 | + import { | ||
10 | + deviceConfigDelete, | ||
11 | + deviceConfigGetQuery, | ||
12 | + setDeviceProfileIsDefaultApi, | ||
13 | + } from '/@/api/device/deviceConfigApi'; | ||
14 | + import { ProfileRecord } from '/@/api/device/model/deviceConfigModel'; | ||
15 | + import { Dropdown } from '/@/components/Dropdown'; | ||
16 | + import { | ||
17 | + defaultObj, | ||
18 | + searchFormSchema, | ||
19 | + DeviceTypeName, | ||
20 | + ProductPermission, | ||
21 | + } from './device.profile.data'; | ||
22 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
23 | + import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; | ||
24 | + import DeviceProfileModal from './DeviceProfileModal.vue'; | ||
25 | + import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
26 | + import { useModal } from '/@/components/Modal'; | ||
27 | + import { useDrawer } from '/@/components/Drawer'; | ||
28 | + import productDefault from '/@/assets/icons/product-default.svg'; | ||
29 | + import { usePermission } from '/@/hooks/web/usePermission'; | ||
30 | + | ||
31 | + defineProps<{ | ||
32 | + mode: EnumTableCardMode; | ||
33 | + }>(); | ||
34 | + | ||
35 | + const emit = defineEmits(['changeMode']); | ||
36 | + | ||
37 | + enum DropMenuEvent { | ||
38 | + SET_DEFAULT = 'setDefault', | ||
39 | + DELETE = 'delete', | ||
40 | + } | ||
41 | + const IMAGE_FALLBACK = productDefault; | ||
42 | + | ||
43 | + const { createMessage } = useMessage(); | ||
44 | + const { createSyncConfirm } = useSyncConfirm(); | ||
45 | + | ||
46 | + const [register, { getFieldsValue }] = useForm({ | ||
47 | + showAdvancedButton: true, | ||
48 | + labelWidth: 100, | ||
49 | + compact: true, | ||
50 | + baseColProps: { span: 8 }, | ||
51 | + schemas: searchFormSchema, | ||
52 | + submitFunc: async () => { | ||
53 | + getDataSource(); | ||
54 | + }, | ||
55 | + }); | ||
56 | + | ||
57 | + const [registerModal, { openModal }] = useModal(); | ||
58 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
59 | + | ||
60 | + const loading = ref(false); | ||
61 | + | ||
62 | + const pagination = reactive<PaginationProps>({ | ||
63 | + size: 'small', | ||
64 | + showTotal: (total: number) => `共 ${total} 条数据`, | ||
65 | + current: 1, | ||
66 | + onChange: (page: number) => { | ||
67 | + pagination.current = page; | ||
68 | + getDataSource(); | ||
69 | + }, | ||
70 | + }); | ||
71 | + | ||
72 | + const dataSource = ref<ProfileRecord[]>([]); | ||
73 | + | ||
74 | + const colNumber = ref(4); | ||
75 | + | ||
76 | + const getSelectAllFlag = computed(() => { | ||
77 | + return unref(dataSource).every((item) => item.checked); | ||
78 | + }); | ||
79 | + | ||
80 | + const getCheckedRecord = computed(() => { | ||
81 | + return unref(dataSource) | ||
82 | + .filter((item) => item.checked) | ||
83 | + .map((item) => item.id); | ||
84 | + }); | ||
85 | + | ||
86 | + const getDataSource = async () => { | ||
87 | + try { | ||
88 | + loading.value = true; | ||
89 | + const params = getFieldsValue(); | ||
90 | + const { items, total } = await deviceConfigGetQuery({ | ||
91 | + page: pagination.current, | ||
92 | + pageSize: unref(colNumber) * 2, | ||
93 | + ...params, | ||
94 | + }); | ||
95 | + pagination.total = total; | ||
96 | + dataSource.value = items.map((item) => ({ ...item, checked: false })); | ||
97 | + } catch (error) { | ||
98 | + } finally { | ||
99 | + loading.value = false; | ||
100 | + } | ||
101 | + }; | ||
102 | + | ||
103 | + const { hasPermission } = usePermission(); | ||
104 | + | ||
105 | + const getHasDeleteFlag = computed(() => { | ||
106 | + return hasPermission(ProductPermission.DELETE); | ||
107 | + }); | ||
108 | + | ||
109 | + const getHasDetailFlag = computed(() => { | ||
110 | + return hasPermission(ProductPermission.DETAIL); | ||
111 | + }); | ||
112 | + | ||
113 | + const getHasUpdateFlag = computed(() => { | ||
114 | + return hasPermission(ProductPermission.UPDATE); | ||
115 | + }); | ||
116 | + | ||
117 | + const getDropDownList = (record: ProfileRecord) => { | ||
118 | + const list = [ | ||
119 | + { | ||
120 | + text: '默认', | ||
121 | + event: DropMenuEvent.SET_DEFAULT, | ||
122 | + icon: 'ant-design:unordered-list-outlined', | ||
123 | + onClick: handleSetDefault.bind(null, record), | ||
124 | + }, | ||
125 | + ]; | ||
126 | + if (unref(getHasDeleteFlag)) { | ||
127 | + list.push({ | ||
128 | + text: '删除', | ||
129 | + event: DropMenuEvent.DELETE, | ||
130 | + icon: 'ant-design:delete-outlined', | ||
131 | + onClick: handleDelete.bind(null, [record.id]), | ||
132 | + }); | ||
133 | + } | ||
134 | + return list; | ||
135 | + }; | ||
136 | + | ||
137 | + const handleModeChange = (mode: EnumTableCardMode) => { | ||
138 | + emit('changeMode', mode); | ||
139 | + }; | ||
140 | + | ||
141 | + const handleCheckCard = (item: ProfileRecord) => { | ||
142 | + item.checked = !item.checked; | ||
143 | + }; | ||
144 | + | ||
145 | + const handleSelectAll = () => { | ||
146 | + dataSource.value = unref(dataSource).map((item) => { | ||
147 | + return { | ||
148 | + ...item, | ||
149 | + checked: !unref(getSelectAllFlag), | ||
150 | + }; | ||
151 | + }); | ||
152 | + }; | ||
153 | + | ||
154 | + const handleCreate = () => { | ||
155 | + openModal(true, { | ||
156 | + isUpdate: false, | ||
157 | + }); | ||
158 | + }; | ||
159 | + | ||
160 | + const handleShowDetail = (record: ProfileRecord) => { | ||
161 | + if (!unref(getHasDetailFlag)) return; | ||
162 | + openDrawer(true, { record }); | ||
163 | + }; | ||
164 | + | ||
165 | + const handleUpdate = (record: ProfileRecord) => { | ||
166 | + if (!unref(getHasUpdateFlag)) return; | ||
167 | + openModal(true, { | ||
168 | + record, | ||
169 | + isUpdate: true, | ||
170 | + }); | ||
171 | + }; | ||
172 | + | ||
173 | + const handleDelete = async (id: string[]) => { | ||
174 | + try { | ||
175 | + await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' }); | ||
176 | + await deviceConfigDelete(id); | ||
177 | + createMessage.success('删除成功'); | ||
178 | + await getDataSource(); | ||
179 | + } catch (error) { | ||
180 | + throw error; | ||
181 | + } | ||
182 | + }; | ||
183 | + | ||
184 | + const handleSetDefault = async (record: ProfileRecord) => { | ||
185 | + try { | ||
186 | + const { tbProfileId } = record; | ||
187 | + const data = await setDeviceProfileIsDefaultApi(tbProfileId, 'default', defaultObj); | ||
188 | + if (!data) return createMessage.error('设置该产品为默认失败'); | ||
189 | + createMessage.success('设置该产品为默认成功'); | ||
190 | + await getDataSource(); | ||
191 | + } catch (error) { | ||
192 | + throw error; | ||
193 | + } | ||
194 | + }; | ||
195 | + | ||
196 | + onMounted(() => { | ||
197 | + getDataSource(); | ||
198 | + }); | ||
199 | +</script> | ||
200 | + | ||
201 | +<template> | ||
202 | + <PageWrapper dense contentFullHeight contentClass="flex"> | ||
203 | + <section class="flex-auto p-4 w-full profile-list"> | ||
204 | + <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4"> | ||
205 | + <BasicForm @register="register" /> | ||
206 | + </div> | ||
207 | + <List | ||
208 | + ref="listEl" | ||
209 | + :loading="loading" | ||
210 | + class="flex-auto bg-light-50 dark:bg-dark-900 !p-2 !mt-4" | ||
211 | + position="bottom" | ||
212 | + :pagination="pagination" | ||
213 | + :data-source="dataSource" | ||
214 | + :grid="{ gutter: 4, column: colNumber }" | ||
215 | + > | ||
216 | + <template #header> | ||
217 | + <div class="flex gap-3 justify-end"> | ||
218 | + <Authority :value="ProductPermission.CREATE"> | ||
219 | + <Button type="primary" @click="handleCreate">新增产品</Button> | ||
220 | + </Authority> | ||
221 | + | ||
222 | + <Button type="primary" @click="handleSelectAll"> | ||
223 | + {{ getSelectAllFlag ? '反选' : '全选' }} | ||
224 | + </Button> | ||
225 | + <Authority :value="ProductPermission.DELETE"> | ||
226 | + <Button | ||
227 | + type="primary" | ||
228 | + danger | ||
229 | + :disabled="!getCheckedRecord.length" | ||
230 | + @click="handleDelete(getCheckedRecord)" | ||
231 | + > | ||
232 | + 批量删除 | ||
233 | + </Button> | ||
234 | + </Authority> | ||
235 | + | ||
236 | + <ModeSwitchButton :value="$props.mode" @change="handleModeChange" /> | ||
237 | + <CardLayoutButton v-model:value="colNumber" @change="getDataSource" /> | ||
238 | + | ||
239 | + <Tooltip title="刷新"> | ||
240 | + <Button type="primary" @click="getDataSource"> | ||
241 | + <ReloadOutlined :spin="loading" /> | ||
242 | + </Button> | ||
243 | + </Tooltip> | ||
244 | + </div> | ||
245 | + </template> | ||
246 | + <template #renderItem="{ item }"> | ||
247 | + <List.Item> | ||
248 | + <Card | ||
249 | + hoverable | ||
250 | + @click="handleCheckCard(item)" | ||
251 | + :class="item.checked ? '!border-blue-500 !border-2' : ''" | ||
252 | + > | ||
253 | + <template #cover> | ||
254 | + <div class="h-full w-full !flex justify-center items-center text-center p-1"> | ||
255 | + <Image | ||
256 | + @click.stop | ||
257 | + :height="144" | ||
258 | + :src="item.image" | ||
259 | + placeholder | ||
260 | + :fallback="IMAGE_FALLBACK" | ||
261 | + /> | ||
262 | + </div> | ||
263 | + </template> | ||
264 | + <template class="ant-card-actions" #actions> | ||
265 | + <Tooltip title="详情"> | ||
266 | + <EyeOutlined | ||
267 | + :class="getHasDetailFlag ? '' : '!cursor-not-allowed !text-gray-200'" | ||
268 | + key="setting" | ||
269 | + @click.stop="handleShowDetail(item)" | ||
270 | + /> | ||
271 | + </Tooltip> | ||
272 | + <Tooltip title="编辑"> | ||
273 | + <FormOutlined | ||
274 | + :class="getHasUpdateFlag ? '' : '!cursor-not-allowed !text-gray-200'" | ||
275 | + key="edit" | ||
276 | + @click.stop="handleUpdate(item)" | ||
277 | + /> | ||
278 | + </Tooltip> | ||
279 | + <Dropdown :trigger="['hover']" :drop-menu-list="getDropDownList(item)"> | ||
280 | + <MoreOutlined @click.stop class="transform rotate-90" /> | ||
281 | + </Dropdown> | ||
282 | + </template> | ||
283 | + <Card.Meta> | ||
284 | + <template #title> | ||
285 | + <span class="truncate"> {{ item.name }} </span> | ||
286 | + </template> | ||
287 | + <template #description> | ||
288 | + <div class="truncate h-11"> | ||
289 | + <div class="truncate">{{ DeviceTypeName[item.deviceType] }} </div> | ||
290 | + <div class="truncate">{{ item.transportType }} </div> | ||
291 | + </div> | ||
292 | + </template> | ||
293 | + </Card.Meta> | ||
294 | + </Card> | ||
295 | + </List.Item> | ||
296 | + </template> | ||
297 | + </List> | ||
298 | + </section> | ||
299 | + <DeviceProfileModal @register="registerModal" @success="getDataSource" /> | ||
300 | + <DeviceProfileDrawer @register="registerDrawer" /> | ||
301 | + </PageWrapper> | ||
302 | +</template> | ||
303 | + | ||
304 | +<style lang="less" scoped> | ||
305 | + .profile-list:deep(.ant-image-img) { | ||
306 | + width: 100% !important; | ||
307 | + height: 100% !important; | ||
308 | + } | ||
309 | +</style> |
src/views/device/profiles/TableMode.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <BasicTable | ||
4 | + class="devide-profiles" | ||
5 | + @register="registerTable" | ||
6 | + :rowSelection="{ type: 'checkbox' }" | ||
7 | + :clickToRowSelect="false" | ||
8 | + > | ||
9 | + <template #toolbar> | ||
10 | + <Authority :value="ProductPermission.CREATE"> | ||
11 | + <a-button type="primary" @click="handleCreate"> 新增产品 </a-button> | ||
12 | + </Authority> | ||
13 | + <Authority :value="ProductPermission.IMPORT"> | ||
14 | + <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> | ||
15 | + <a-button @click="handleImport"> 导入产品 </a-button> | ||
16 | + </ImpExcel> | ||
17 | + </Authority> | ||
18 | + <Authority :value="ProductPermission.DELETE"> | ||
19 | + <Popconfirm | ||
20 | + title="您确定要批量删除数据" | ||
21 | + ok-text="确定" | ||
22 | + cancel-text="取消" | ||
23 | + @confirm="handleDeleteOrBatchDelete(null)" | ||
24 | + > | ||
25 | + <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
26 | + </Popconfirm> | ||
27 | + </Authority> | ||
28 | + <ModeSwitchButton :value="$props.mode" @change="handleModeChange" /> | ||
29 | + </template> | ||
30 | + <template #img="{ record }"> | ||
31 | + <TableImg | ||
32 | + :size="30" | ||
33 | + :showBadge="false" | ||
34 | + :simpleShow="true" | ||
35 | + :imgList=" | ||
36 | + typeof record.image !== 'undefined' && record.image !== '' && record.image != null | ||
37 | + ? [record.image] | ||
38 | + : null | ||
39 | + " | ||
40 | + /> | ||
41 | + </template> | ||
42 | + <template #action="{ record }"> | ||
43 | + <TableAction | ||
44 | + :actions="[ | ||
45 | + { | ||
46 | + label: '详情', | ||
47 | + auth: ProductPermission.DETAIL, | ||
48 | + icon: 'ant-design:eye-outlined', | ||
49 | + onClick: handleDetailView.bind(null, record), | ||
50 | + }, | ||
51 | + { | ||
52 | + label: '编辑', | ||
53 | + auth: ProductPermission.UPDATE, | ||
54 | + icon: 'clarity:note-edit-line', | ||
55 | + onClick: handleEdit.bind(null, record), | ||
56 | + ifShow: () => { | ||
57 | + return record.name !== 'default' ? true : false; | ||
58 | + }, | ||
59 | + }, | ||
60 | + ]" | ||
61 | + :drop-down-actions="[ | ||
62 | + { | ||
63 | + label: '默认', | ||
64 | + icon: 'ant-design:profile-outlined', | ||
65 | + onClick: handleSetDefault.bind(null, record), | ||
66 | + ifShow: () => { | ||
67 | + return record.default === false; | ||
68 | + }, | ||
69 | + }, | ||
70 | + { | ||
71 | + label: '导出', | ||
72 | + auth: ProductPermission.EXPORT, | ||
73 | + icon: 'ant-design:login-outlined', | ||
74 | + onClick: handleExport.bind(null, record), | ||
75 | + }, | ||
76 | + { | ||
77 | + label: '删除', | ||
78 | + auth: ProductPermission.DELETE, | ||
79 | + icon: 'ant-design:delete-outlined', | ||
80 | + color: 'error', | ||
81 | + popConfirm: { | ||
82 | + title: '是否确认删除', | ||
83 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
84 | + }, | ||
85 | + ifShow: () => { | ||
86 | + return record.default === false && record.name !== 'default'; | ||
87 | + }, | ||
88 | + }, | ||
89 | + ]" | ||
90 | + /> | ||
91 | + </template> | ||
92 | + </BasicTable> | ||
93 | + <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> | ||
94 | + <DeviceProfileDrawer @register="registerDrawer" /> | ||
95 | + <ExpExcelModal | ||
96 | + ref="expExcelModalRef" | ||
97 | + @register="registerExportModal" | ||
98 | + @success="defaultHeader" | ||
99 | + /> | ||
100 | + </div> | ||
101 | +</template> | ||
102 | +<script lang="ts" setup> | ||
103 | + import { ref, nextTick, onUnmounted } from 'vue'; | ||
104 | + import { BasicTable, TableImg, useTable, TableAction, BasicColumn } from '/@/components/Table'; | ||
105 | + import { columns, searchFormSchema, defaultObj, ProductPermission } from './device.profile.data'; | ||
106 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
107 | + import { | ||
108 | + deviceConfigGetQuery, | ||
109 | + deviceConfigDelete, | ||
110 | + setDeviceProfileIsDefaultApi, | ||
111 | + } from '/@/api/device/deviceConfigApi'; | ||
112 | + import { useModal } from '/@/components/Modal'; | ||
113 | + import { useDrawer } from '/@/components/Drawer'; | ||
114 | + import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; | ||
115 | + import { ImpExcel, ExcelData } from '/@/components/Excel'; | ||
116 | + import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; | ||
117 | + import { Authority } from '/@/components/Authority'; | ||
118 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
119 | + import { Popconfirm } from 'ant-design-vue'; | ||
120 | + import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
121 | + import { EnumTableCardMode, ModeSwitchButton } from '/@/components/Widget'; | ||
122 | + | ||
123 | + defineProps<{ | ||
124 | + mode: EnumTableCardMode; | ||
125 | + }>(); | ||
126 | + | ||
127 | + const emit = defineEmits(['changeMode']); | ||
128 | + | ||
129 | + const exportData: any = ref([]); | ||
130 | + const expExcelModalRef: any = ref(null); | ||
131 | + const getPathUrl = ref(''); | ||
132 | + const getPathUrlName = ref(''); | ||
133 | + const disabled = ref(true); | ||
134 | + const onCloseVal = ref(0); | ||
135 | + const immediateStatus = ref(false); | ||
136 | + const { createMessage } = useMessage(); | ||
137 | + const [registerModal, { openModal }] = useModal(); | ||
138 | + const [registerExportModal, { openModal: openModalExcel }] = useModal(); | ||
139 | + const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ | ||
140 | + title: '产品列表', | ||
141 | + clickToRowSelect: false, | ||
142 | + api: deviceConfigGetQuery, | ||
143 | + immediate: immediateStatus.value, | ||
144 | + columns, | ||
145 | + formConfig: { | ||
146 | + labelWidth: 120, | ||
147 | + schemas: searchFormSchema, | ||
148 | + }, | ||
149 | + rowKey: 'id', | ||
150 | + useSearchForm: true, | ||
151 | + showTableSetting: true, | ||
152 | + bordered: true, | ||
153 | + showIndexColumn: false, | ||
154 | + actionColumn: { | ||
155 | + width: 200, | ||
156 | + title: '操作', | ||
157 | + dataIndex: 'action', | ||
158 | + slots: { customRender: 'action' }, | ||
159 | + fixed: 'right', | ||
160 | + }, | ||
161 | + }); | ||
162 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
163 | + deviceConfigDelete, | ||
164 | + handleSuccess, | ||
165 | + setProps | ||
166 | + ); | ||
167 | + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
168 | + // Demo:status为1的选择框禁用 | ||
169 | + if (record.default === true) { | ||
170 | + return { disabled: true }; | ||
171 | + } else if (record.name == 'default') { | ||
172 | + return { disabled: true }; | ||
173 | + } else { | ||
174 | + return { disabled: false }; | ||
175 | + } | ||
176 | + }; | ||
177 | + nextTick(() => { | ||
178 | + setProps(selectionOptions); | ||
179 | + }); | ||
180 | + /** | ||
181 | + *@param url,name | ||
182 | + **/ | ||
183 | + function getParam(url, name) { | ||
184 | + try { | ||
185 | + let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); | ||
186 | + let r = url.split('?')[1].match(reg); | ||
187 | + if (r != null) { | ||
188 | + return r[2]; | ||
189 | + } | ||
190 | + return ''; //如果此处只写return;则返回的是undefined | ||
191 | + } catch (e) { | ||
192 | + return ''; //如果此处只写return;则返回的是undefined | ||
193 | + } | ||
194 | + } | ||
195 | + getPathUrl.value = window.location.href; | ||
196 | + const name = 'name'; | ||
197 | + const getName = getParam(getPathUrl.value, name); | ||
198 | + getPathUrlName.value = decodeURIComponent(getName); | ||
199 | + | ||
200 | + const setRowClassName = async () => { | ||
201 | + if (getPathUrlName.value !== '') { | ||
202 | + const { items } = await deviceConfigGetQuery({ | ||
203 | + page: 1, | ||
204 | + pageSize: 10, | ||
205 | + name: getPathUrlName.value, | ||
206 | + }); | ||
207 | + nextTick(() => { | ||
208 | + setTableData(items); | ||
209 | + const { setFieldsValue, resetFields } = getForm(); | ||
210 | + setFieldsValue({ | ||
211 | + name: getPathUrlName.value, | ||
212 | + }); | ||
213 | + if (onCloseVal.value == 1) { | ||
214 | + resetFields(); | ||
215 | + } | ||
216 | + }); | ||
217 | + } else { | ||
218 | + setTimeout(() => { | ||
219 | + reload(); | ||
220 | + }, 80); | ||
221 | + } | ||
222 | + }; | ||
223 | + setRowClassName(); | ||
224 | + onUnmounted(() => { | ||
225 | + getPathUrlName.value = ''; | ||
226 | + onCloseVal.value = 1; | ||
227 | + }); | ||
228 | + const tableListRef = ref< | ||
229 | + { | ||
230 | + title: string; | ||
231 | + columns?: any[]; | ||
232 | + dataSource?: any[]; | ||
233 | + }[] | ||
234 | + >([]); | ||
235 | + | ||
236 | + function loadDataSuccess(excelDataList: ExcelData[]) { | ||
237 | + tableListRef.value = []; | ||
238 | + console.log(excelDataList); | ||
239 | + for (const excelData of excelDataList) { | ||
240 | + const { | ||
241 | + header, | ||
242 | + results, | ||
243 | + meta: { sheetName }, | ||
244 | + } = excelData; | ||
245 | + const columns: BasicColumn[] = []; | ||
246 | + for (const title of header) { | ||
247 | + columns.push({ title, dataIndex: title }); | ||
248 | + } | ||
249 | + tableListRef.value.push({ title: sheetName, dataSource: results, columns }); | ||
250 | + } | ||
251 | + } | ||
252 | + //新增 | ||
253 | + function handleCreate() { | ||
254 | + openModal(true, { | ||
255 | + isUpdate: false, | ||
256 | + }); | ||
257 | + } | ||
258 | + //编辑 | ||
259 | + function handleEdit(record: Recordable) { | ||
260 | + openModal(true, { | ||
261 | + record, | ||
262 | + isUpdate: true, | ||
263 | + }); | ||
264 | + } | ||
265 | + | ||
266 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
267 | + //详情 | ||
268 | + function handleDetailView(record: Recordable) { | ||
269 | + openDrawer(true, { record }); | ||
270 | + } | ||
271 | + | ||
272 | + function defaultHeader({ filename, bookType }: ExportModalResult) { | ||
273 | + // 默认Object.keys(data[0])作为header | ||
274 | + const data = exportData.value; | ||
275 | + jsonToSheetXlsx({ | ||
276 | + data, | ||
277 | + filename, | ||
278 | + write2excelOpts: { | ||
279 | + bookType, | ||
280 | + }, | ||
281 | + }); | ||
282 | + } | ||
283 | + //导出 | ||
284 | + const handleExport = (record: Recordable) => { | ||
285 | + exportData.value = []; | ||
286 | + exportData.value.push({ | ||
287 | + createTime: record.createTime, | ||
288 | + description: record.description, | ||
289 | + name: record.name, | ||
290 | + }); | ||
291 | + nextTick(() => { | ||
292 | + openModalExcel(); | ||
293 | + expExcelModalRef.value?.clearFieldFunc(); | ||
294 | + }); | ||
295 | + }; | ||
296 | + //导入 | ||
297 | + function handleImport() { | ||
298 | + console.log('record'); | ||
299 | + } | ||
300 | + function handleSuccess() { | ||
301 | + reload(); | ||
302 | + } | ||
303 | + | ||
304 | + const handleSetDefault = async (record: Recordable) => { | ||
305 | + let id = record.tbProfileId; | ||
306 | + const data = await setDeviceProfileIsDefaultApi(id, 'default', defaultObj); | ||
307 | + if (!data) return createMessage.error('设置该产品为默认失败'); | ||
308 | + createMessage.success('设置该产品为默认成功'); | ||
309 | + reload(); | ||
310 | + disabled.value = true; | ||
311 | + }; | ||
312 | + | ||
313 | + const handleModeChange = (value: EnumTableCardMode) => { | ||
314 | + emit('changeMode', value); | ||
315 | + }; | ||
316 | +</script> | ||
317 | + | ||
318 | +<style lang="css"> | ||
319 | + .devide-profiles .rowcolor { | ||
320 | + color: red; | ||
321 | + } | ||
322 | + | ||
323 | + .devide-profiles .rowcolor2 { | ||
324 | + background: #a2c3e6; | ||
325 | + } | ||
326 | +</style> |
@@ -9,6 +9,26 @@ import { FormField, FunctionType } from './step/cpns/physical/cpns/config'; | @@ -9,6 +9,26 @@ import { FormField, FunctionType } from './step/cpns/physical/cpns/config'; | ||
9 | import { h } from 'vue'; | 9 | import { h } from 'vue'; |
10 | import { Tag } from 'ant-design-vue'; | 10 | import { Tag } from 'ant-design-vue'; |
11 | 11 | ||
12 | +export enum Mode { | ||
13 | + CARD = 'card', | ||
14 | + TABLE = 'table', | ||
15 | +} | ||
16 | + | ||
17 | +export enum DeviceTypeName { | ||
18 | + DIRECT_CONNECTION = '直连设备', | ||
19 | + GATEWAY = '网关设备', | ||
20 | + SENSOR = '网关子设备', | ||
21 | +} | ||
22 | +export enum ProductPermission { | ||
23 | + DETAIL = 'api:yt:deviceProfile:get', | ||
24 | + CREATE = 'api:yt:deviceProfile:post', | ||
25 | + UPDATE = 'api:yt:deviceProfile:update', | ||
26 | + DELETE = 'api:yt:deviceProfile:delete', | ||
27 | + SET_DEFAULT = '', | ||
28 | + IMPORT = 'api:yt:deviceProfile:import', | ||
29 | + EXPORT = 'api:yt:deviceProfile:export', | ||
30 | +} | ||
31 | + | ||
12 | export enum ModelOfMatterPermission { | 32 | export enum ModelOfMatterPermission { |
13 | CREATE = 'api:yt:things_model:post', | 33 | CREATE = 'api:yt:things_model:post', |
14 | UPDATE = 'api:yt:things_model:put', | 34 | UPDATE = 'api:yt:things_model:put', |
1 | -<template> | ||
2 | - <div> | ||
3 | - <BasicTable | ||
4 | - class="devide-profiles" | ||
5 | - @register="registerTable" | ||
6 | - :rowSelection="{ type: 'checkbox' }" | ||
7 | - :clickToRowSelect="false" | ||
8 | - > | ||
9 | - <template #toolbar> | ||
10 | - <Authority value="api:yt:deviceProfile:post"> | ||
11 | - <a-button type="primary" @click="handleCreate"> 新增产品 </a-button> | ||
12 | - </Authority> | ||
13 | - <Authority value="api:yt:deviceProfile:import"> | ||
14 | - <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> | ||
15 | - <a-button @click="handleImport"> 导入产品 </a-button> | ||
16 | - </ImpExcel> | ||
17 | - </Authority> | ||
18 | - <Authority value="api:yt:deviceProfile:delete"> | ||
19 | - <Popconfirm | ||
20 | - title="您确定要批量删除数据" | ||
21 | - ok-text="确定" | ||
22 | - cancel-text="取消" | ||
23 | - @confirm="handleDeleteOrBatchDelete(null)" | ||
24 | - > | ||
25 | - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
26 | - </Popconfirm> | ||
27 | - </Authority> | ||
28 | - </template> | ||
29 | - <template #img="{ record }"> | ||
30 | - <TableImg | ||
31 | - :size="30" | ||
32 | - :showBadge="false" | ||
33 | - :simpleShow="true" | ||
34 | - :imgList=" | ||
35 | - typeof record.image !== 'undefined' && record.image !== '' && record.image != null | ||
36 | - ? [record.image] | ||
37 | - : null | ||
38 | - " | ||
39 | - /> | ||
40 | - </template> | ||
41 | - <template #action="{ record }"> | ||
42 | - <TableAction | ||
43 | - :actions="[ | ||
44 | - { | ||
45 | - label: '详情', | ||
46 | - auth: 'api:yt:deviceProfile:get', | ||
47 | - icon: 'ant-design:eye-outlined', | ||
48 | - onClick: handleDetailView.bind(null, record), | ||
49 | - }, | ||
50 | - { | ||
51 | - label: '编辑', | ||
52 | - auth: 'api:yt:deviceProfile:update', | ||
53 | - icon: 'clarity:note-edit-line', | ||
54 | - onClick: handleEdit.bind(null, record), | ||
55 | - ifShow: () => { | ||
56 | - return record.name !== 'default' ? true : false; | ||
57 | - }, | ||
58 | - }, | ||
59 | - ]" | ||
60 | - :drop-down-actions="[ | ||
61 | - { | ||
62 | - label: '默认', | ||
63 | - icon: 'ant-design:profile-outlined', | ||
64 | - onClick: handleSetDefault.bind(null, record), | ||
65 | - ifShow: () => { | ||
66 | - return record.default === false; | ||
67 | - }, | ||
68 | - }, | ||
69 | - { | ||
70 | - label: '导出', | ||
71 | - auth: 'api:yt:deviceProfile:export', | ||
72 | - icon: 'ant-design:login-outlined', | ||
73 | - onClick: handleExport.bind(null, record), | ||
74 | - }, | ||
75 | - { | ||
76 | - label: '删除', | ||
77 | - auth: 'api:yt:deviceProfile:delete', | ||
78 | - icon: 'ant-design:delete-outlined', | ||
79 | - color: 'error', | ||
80 | - popConfirm: { | ||
81 | - title: '是否确认删除', | ||
82 | - confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
83 | - }, | ||
84 | - ifShow: () => { | ||
85 | - return record.default === false && record.name !== 'default'; | ||
86 | - }, | ||
87 | - }, | ||
88 | - ]" | ||
89 | - /> | ||
90 | - </template> | ||
91 | - </BasicTable> | ||
92 | - <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> | ||
93 | - <DeviceProfileDrawer @register="registerDrawer" /> | ||
94 | - <ExpExcelModal | ||
95 | - ref="expExcelModalRef" | ||
96 | - @register="registerExportModal" | ||
97 | - @success="defaultHeader" | ||
98 | - /> | ||
99 | - </div> | ||
100 | -</template> | ||
101 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
102 | - import { ref, nextTick, onUnmounted } from 'vue'; | ||
103 | - import { BasicTable, TableImg, useTable, TableAction, BasicColumn } from '/@/components/Table'; | ||
104 | - import { columns, searchFormSchema, defaultObj } from './device.profile.data'; | ||
105 | - import { useMessage } from '/@/hooks/web/useMessage'; | ||
106 | - import { | ||
107 | - deviceConfigGetQuery, | ||
108 | - deviceConfigDelete, | ||
109 | - setDeviceProfileIsDefaultApi, | ||
110 | - } from '/@/api/device/deviceConfigApi'; | ||
111 | - import { useModal } from '/@/components/Modal'; | ||
112 | - import { useDrawer } from '/@/components/Drawer'; | ||
113 | - import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; | ||
114 | - import { ImpExcel, ExcelData } from '/@/components/Excel'; | ||
115 | - import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; | ||
116 | - import { Authority } from '/@/components/Authority'; | ||
117 | - import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
118 | - import { Popconfirm } from 'ant-design-vue'; | ||
119 | - import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
120 | - | ||
121 | - const exportData: any = ref([]); | ||
122 | - const expExcelModalRef: any = ref(null); | ||
123 | - const getPathUrl = ref(''); | ||
124 | - const getPathUrlName = ref(''); | ||
125 | - const disabled = ref(true); | ||
126 | - const onCloseVal = ref(0); | ||
127 | - const immediateStatus = ref(false); | ||
128 | - const { createMessage } = useMessage(); | ||
129 | - const [registerModal, { openModal }] = useModal(); | ||
130 | - const [registerExportModal, { openModal: openModalExcel }] = useModal(); | ||
131 | - const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ | ||
132 | - title: '产品列表', | ||
133 | - clickToRowSelect: false, | ||
134 | - api: deviceConfigGetQuery, | ||
135 | - immediate: immediateStatus.value, | ||
136 | - columns, | ||
137 | - formConfig: { | ||
138 | - labelWidth: 120, | ||
139 | - schemas: searchFormSchema, | ||
140 | - }, | ||
141 | - rowKey: 'id', | ||
142 | - useSearchForm: true, | ||
143 | - showTableSetting: true, | ||
144 | - bordered: true, | ||
145 | - showIndexColumn: false, | ||
146 | - actionColumn: { | ||
147 | - width: 200, | ||
148 | - title: '操作', | ||
149 | - dataIndex: 'action', | ||
150 | - slots: { customRender: 'action' }, | ||
151 | - fixed: 'right', | ||
152 | - }, | ||
153 | - }); | ||
154 | - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
155 | - deviceConfigDelete, | ||
156 | - handleSuccess, | ||
157 | - setProps | ||
158 | - ); | ||
159 | - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
160 | - // Demo:status为1的选择框禁用 | ||
161 | - if (record.default === true) { | ||
162 | - return { disabled: true }; | ||
163 | - } else if (record.name == 'default') { | ||
164 | - return { disabled: true }; | ||
165 | - } else { | ||
166 | - return { disabled: false }; | ||
167 | - } | ||
168 | - }; | ||
169 | - nextTick(() => { | ||
170 | - setProps(selectionOptions); | ||
171 | - }); | ||
172 | - /** | ||
173 | - *@param url,name | ||
174 | - **/ | ||
175 | - function getParam(url, name) { | ||
176 | - try { | ||
177 | - let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); | ||
178 | - let r = url.split('?')[1].match(reg); | ||
179 | - if (r != null) { | ||
180 | - return r[2]; | ||
181 | - } | ||
182 | - return ''; //如果此处只写return;则返回的是undefined | ||
183 | - } catch (e) { | ||
184 | - return ''; //如果此处只写return;则返回的是undefined | ||
185 | - } | ||
186 | - } | ||
187 | - getPathUrl.value = window.location.href; | ||
188 | - const name = 'name'; | ||
189 | - const getName = getParam(getPathUrl.value, name); | ||
190 | - getPathUrlName.value = decodeURIComponent(getName); | ||
191 | - | ||
192 | - const setRowClassName = async () => { | ||
193 | - if (getPathUrlName.value !== '') { | ||
194 | - const { items } = await deviceConfigGetQuery({ | ||
195 | - page: 1, | ||
196 | - pageSize: 10, | ||
197 | - name: getPathUrlName.value, | ||
198 | - }); | ||
199 | - nextTick(() => { | ||
200 | - setTableData(items); | ||
201 | - const { setFieldsValue, resetFields } = getForm(); | ||
202 | - setFieldsValue({ | ||
203 | - name: getPathUrlName.value, | ||
204 | - }); | ||
205 | - if (onCloseVal.value == 1) { | ||
206 | - resetFields(); | ||
207 | - } | ||
208 | - }); | ||
209 | - } else { | ||
210 | - setTimeout(() => { | ||
211 | - reload(); | ||
212 | - }, 80); | ||
213 | - } | ||
214 | - }; | ||
215 | - setRowClassName(); | ||
216 | - onUnmounted(() => { | ||
217 | - getPathUrlName.value = ''; | ||
218 | - onCloseVal.value = 1; | ||
219 | - }); | ||
220 | - const tableListRef = ref< | ||
221 | - { | ||
222 | - title: string; | ||
223 | - columns?: any[]; | ||
224 | - dataSource?: any[]; | ||
225 | - }[] | ||
226 | - >([]); | ||
227 | - | ||
228 | - function loadDataSuccess(excelDataList: ExcelData[]) { | ||
229 | - tableListRef.value = []; | ||
230 | - console.log(excelDataList); | ||
231 | - for (const excelData of excelDataList) { | ||
232 | - const { | ||
233 | - header, | ||
234 | - results, | ||
235 | - meta: { sheetName }, | ||
236 | - } = excelData; | ||
237 | - const columns: BasicColumn[] = []; | ||
238 | - for (const title of header) { | ||
239 | - columns.push({ title, dataIndex: title }); | ||
240 | - } | ||
241 | - tableListRef.value.push({ title: sheetName, dataSource: results, columns }); | ||
242 | - } | ||
243 | - } | ||
244 | - //新增 | ||
245 | - function handleCreate() { | ||
246 | - openModal(true, { | ||
247 | - isUpdate: false, | ||
248 | - }); | ||
249 | - } | ||
250 | - //编辑 | ||
251 | - function handleEdit(record: Recordable) { | ||
252 | - openModal(true, { | ||
253 | - record, | ||
254 | - isUpdate: true, | ||
255 | - }); | ||
256 | - } | ||
257 | - | ||
258 | - const [registerDrawer, { openDrawer }] = useDrawer(); | ||
259 | - //详情 | ||
260 | - function handleDetailView(record: Recordable) { | ||
261 | - openDrawer(true, { record }); | ||
262 | - } | ||
263 | - | ||
264 | - function defaultHeader({ filename, bookType }: ExportModalResult) { | ||
265 | - // 默认Object.keys(data[0])作为header | ||
266 | - const data = exportData.value; | ||
267 | - jsonToSheetXlsx({ | ||
268 | - data, | ||
269 | - filename, | ||
270 | - write2excelOpts: { | ||
271 | - bookType, | ||
272 | - }, | ||
273 | - }); | ||
274 | - } | ||
275 | - //导出 | ||
276 | - const handleExport = (record: Recordable) => { | ||
277 | - exportData.value = []; | ||
278 | - exportData.value.push({ | ||
279 | - createTime: record.createTime, | ||
280 | - description: record.description, | ||
281 | - name: record.name, | ||
282 | - }); | ||
283 | - nextTick(() => { | ||
284 | - openModalExcel(); | ||
285 | - expExcelModalRef.value?.clearFieldFunc(); | ||
286 | - }); | ||
287 | - }; | ||
288 | - //导入 | ||
289 | - function handleImport() { | ||
290 | - console.log('record'); | ||
291 | - } | ||
292 | - function handleSuccess() { | ||
293 | - reload(); | ||
294 | - } | ||
295 | - | ||
296 | - const handleSetDefault = async (record: Recordable) => { | ||
297 | - let id = record.tbProfileId; | ||
298 | - const data = await setDeviceProfileIsDefaultApi(id, 'default', defaultObj); | ||
299 | - if (!data) return createMessage.error('设置该产品为默认失败'); | ||
300 | - createMessage.success('设置该产品为默认成功'); | ||
301 | - reload(); | ||
302 | - disabled.value = true; | 2 | + import { ref } from 'vue'; |
3 | + import TableMode from './TableMode.vue'; | ||
4 | + import CardMode from './CardMode.vue'; | ||
5 | + import { EnumTableCardMode } from '/@/components/Widget'; | ||
6 | + const mode = ref(EnumTableCardMode.CARD); | ||
7 | + | ||
8 | + const handleChangeMode = (flag: EnumTableCardMode) => { | ||
9 | + mode.value = flag; | ||
303 | }; | 10 | }; |
304 | </script> | 11 | </script> |
305 | 12 | ||
306 | -<style lang="css"> | ||
307 | - .devide-profiles .rowcolor { | ||
308 | - color: red; | ||
309 | - } | ||
310 | - | ||
311 | - .devide-profiles .rowcolor2 { | ||
312 | - background: #a2c3e6; | ||
313 | - } | ||
314 | -</style> | 13 | +<template> |
14 | + <section> | ||
15 | + <CardMode v-if="mode === EnumTableCardMode.CARD" :mode="mode" @change-mode="handleChangeMode" /> | ||
16 | + <TableMode | ||
17 | + v-if="mode === EnumTableCardMode.TABLE" | ||
18 | + :mode="mode" | ||
19 | + @change-mode="handleChangeMode" | ||
20 | + /> | ||
21 | + </section> | ||
22 | +</template> |
@@ -152,6 +152,17 @@ | @@ -152,6 +152,17 @@ | ||
152 | field: 'transportType', | 152 | field: 'transportType', |
153 | componentProps: { | 153 | componentProps: { |
154 | disabled: status, | 154 | disabled: status, |
155 | + options: [ | ||
156 | + { label: '默认', value: 'DEFAULT' }, | ||
157 | + { label: 'MQTT', value: 'MQTT' }, | ||
158 | + { label: 'CoAP', value: 'COAP' }, | ||
159 | + { label: 'LWM2M', value: 'LWM2M' }, | ||
160 | + { label: 'SNMP', value: 'SNMP' }, | ||
161 | + { label: 'TCP', value: 'TCP' }, | ||
162 | + ], | ||
163 | + onChange(e) { | ||
164 | + isMqttType.value = e; | ||
165 | + }, | ||
155 | }, | 166 | }, |
156 | }); | 167 | }); |
157 | }; | 168 | }; |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { computed, nextTick, Ref, ref, unref } from 'vue'; | 2 | import { computed, nextTick, Ref, ref, unref } from 'vue'; |
3 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; | 3 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; |
4 | - import { Empty, Tooltip, Button, Spin } from 'ant-design-vue'; | 4 | + import { Empty, Spin } from 'ant-design-vue'; |
5 | import { useECharts } from '/@/hooks/web/useECharts'; | 5 | import { useECharts } from '/@/hooks/web/useECharts'; |
6 | import { AggregateDataEnum } from '/@/views/device/localtion/config.data'; | 6 | import { AggregateDataEnum } from '/@/views/device/localtion/config.data'; |
7 | import { useGridLayout } from '/@/hooks/component/useGridLayout'; | 7 | import { useGridLayout } from '/@/hooks/component/useGridLayout'; |
@@ -14,19 +14,18 @@ | @@ -14,19 +14,18 @@ | ||
14 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; | 14 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; |
15 | import { useHistoryData } from '/@/views/device/list/hook/useHistoryData'; | 15 | import { useHistoryData } from '/@/views/device/list/hook/useHistoryData'; |
16 | import { BasicTable, useTable } from '/@/components/Table'; | 16 | import { BasicTable, useTable } from '/@/components/Table'; |
17 | - import { LineChartOutlined, BarsOutlined } from '@ant-design/icons-vue'; | ||
18 | import { formatToDateTime } from '/@/utils/dateUtil'; | 17 | import { formatToDateTime } from '/@/utils/dateUtil'; |
18 | + import { | ||
19 | + ModeSwitchButton, | ||
20 | + TABLE_CHART_MODE_LIST, | ||
21 | + EnumTableChartMode, | ||
22 | + } from '/@/components/Widget'; | ||
19 | 23 | ||
20 | type DeviceOption = Record<'label' | 'value' | 'organizationId', string>; | 24 | type DeviceOption = Record<'label' | 'value' | 'organizationId', string>; |
21 | 25 | ||
22 | defineEmits(['register']); | 26 | defineEmits(['register']); |
23 | 27 | ||
24 | - enum Mode { | ||
25 | - TABLE = 'table', | ||
26 | - CHART = 'chart', | ||
27 | - } | ||
28 | - | ||
29 | - const mode = ref<Mode>(Mode.CHART); | 28 | + const mode = ref<EnumTableChartMode>(EnumTableChartMode.CHART); |
30 | 29 | ||
31 | const chartRef = ref(); | 30 | const chartRef = ref(); |
32 | 31 | ||
@@ -245,7 +244,7 @@ | @@ -245,7 +244,7 @@ | ||
245 | destory(); | 244 | destory(); |
246 | }; | 245 | }; |
247 | 246 | ||
248 | - const switchMode = (flag: Mode) => { | 247 | + const switchMode = (flag: EnumTableChartMode) => { |
249 | mode.value = flag; | 248 | mode.value = flag; |
250 | }; | 249 | }; |
251 | </script> | 250 | </script> |
@@ -269,61 +268,38 @@ | @@ -269,61 +268,38 @@ | ||
269 | </section> | 268 | </section> |
270 | <section class="bg-white p-3" style="min-height: 350px"> | 269 | <section class="bg-white p-3" style="min-height: 350px"> |
271 | <Spin :spinning="loading" :absolute="true"> | 270 | <Spin :spinning="loading" :absolute="true"> |
272 | - <div v-show="mode === Mode.CHART" class="flex h-70px items-center justify-end p-2"> | ||
273 | - <Tooltip title="图表模式"> | ||
274 | - <Button | ||
275 | - :class="[mode === Mode.CHART && '!bg-blue-500 svg:text-light-50']" | ||
276 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
277 | - @click="switchMode(Mode.CHART)" | ||
278 | - > | ||
279 | - <LineChartOutlined /> | ||
280 | - </Button> | ||
281 | - </Tooltip> | ||
282 | - | ||
283 | - <Tooltip title="列表模式"> | ||
284 | - <Button | ||
285 | - class="!p-2 !children:flex flex justify-center items-center" | ||
286 | - @click="switchMode(Mode.TABLE)" | ||
287 | - > | ||
288 | - <BarsOutlined /> | ||
289 | - </Button> | ||
290 | - </Tooltip> | 271 | + <div |
272 | + v-show="mode === EnumTableChartMode.CHART" | ||
273 | + class="flex h-70px items-center justify-end p-2" | ||
274 | + > | ||
275 | + <ModeSwitchButton | ||
276 | + v-model:value="mode" | ||
277 | + :mode="TABLE_CHART_MODE_LIST" | ||
278 | + @change="switchMode" | ||
279 | + /> | ||
291 | </div> | 280 | </div> |
292 | 281 | ||
293 | <div | 282 | <div |
294 | - v-show="isNull && mode === Mode.CHART" | 283 | + v-show="isNull && mode === EnumTableChartMode.CHART" |
295 | ref="chartRef" | 284 | ref="chartRef" |
296 | :style="{ height: '350px', width: '100%' }" | 285 | :style="{ height: '350px', width: '100%' }" |
297 | > | 286 | > |
298 | </div> | 287 | </div> |
299 | <Empty | 288 | <Empty |
300 | - v-if="mode === Mode.CHART" | 289 | + v-if="mode === EnumTableChartMode.CHART" |
301 | class="h-350px flex flex-col justify-center items-center" | 290 | class="h-350px flex flex-col justify-center items-center" |
302 | description="暂无数据,请选择设备查询" | 291 | description="暂无数据,请选择设备查询" |
303 | v-show="!isNull" | 292 | v-show="!isNull" |
304 | /> | 293 | /> |
305 | 294 | ||
306 | - <BasicTable v-show="mode === Mode.TABLE" @register="registerTable"> | 295 | + <BasicTable v-show="mode === EnumTableChartMode.TABLE" @register="registerTable"> |
307 | <template #toolbar> | 296 | <template #toolbar> |
308 | - <div v-show="mode === Mode.TABLE" class="flex h-70px items-center justify-end p-2"> | ||
309 | - <Tooltip title="图表模式"> | ||
310 | - <Button | ||
311 | - class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
312 | - @click="switchMode(Mode.CHART)" | ||
313 | - > | ||
314 | - <LineChartOutlined /> | ||
315 | - </Button> | ||
316 | - </Tooltip> | ||
317 | - | ||
318 | - <Tooltip title="列表模式"> | ||
319 | - <Button | ||
320 | - :class="[mode === Mode.TABLE && '!bg-blue-500 svg:text-light-50']" | ||
321 | - class="!p-2 !children:flex flex justify-center items-center" | ||
322 | - @click="switchMode(Mode.TABLE)" | ||
323 | - > | ||
324 | - <BarsOutlined /> | ||
325 | - </Button> | ||
326 | - </Tooltip> | 297 | + <div class="flex h-70px items-center justify-end p-2"> |
298 | + <ModeSwitchButton | ||
299 | + v-model:value="mode" | ||
300 | + :mode="TABLE_CHART_MODE_LIST" | ||
301 | + @change="switchMode" | ||
302 | + /> | ||
327 | </div> | 303 | </div> |
328 | </template> | 304 | </template> |
329 | </BasicTable> | 305 | </BasicTable> |