Commit ea33b4b91bc25be8ad2b15a8b2825e7436c959d7
Merge branch 'ww' into 'main'
fix: BUG in teambition See merge request huang/yun-teng-iot-front!377
Showing
37 changed files
with
729 additions
and
289 deletions
1 | 1 | import { defHttp } from '/@/utils/http/axios'; |
2 | 2 | import type { |
3 | 3 | queryPageParams, |
4 | - ConfigurationModal, | |
5 | 4 | ConfigurationCenterParams, |
6 | 5 | ConfigurationCenterInfo, |
6 | + ConfigurationCenterItemsModal, | |
7 | 7 | } from './model/configurationCenterModal'; |
8 | 8 | import { getPageData } from '../../base'; |
9 | 9 | enum API { |
... | ... | @@ -11,7 +11,7 @@ enum API { |
11 | 11 | } |
12 | 12 | |
13 | 13 | export const getPage = (params: queryPageParams) => { |
14 | - return getPageData<ConfigurationModal>(params, API.basicUrl); | |
14 | + return getPageData<ConfigurationCenterItemsModal>(params, API.basicUrl); | |
15 | 15 | }; |
16 | 16 | |
17 | 17 | export const saveConfigurationCenter = (params: ConfigurationCenterParams) => { | ... | ... |
1 | 1 | import { BasicPageParams } from '/@/api/model/baseModel'; |
2 | -import { ContactParams } from '/@/api/alarm/contact/model/alarmContactModal'; | |
3 | 2 | |
4 | -interface ConfigurationCenterItemsModal { | |
3 | +export interface ConfigurationCenterItemsModal { | |
5 | 4 | id: string; |
6 | 5 | name: string; |
7 | 6 | createTime: string; |
8 | 7 | creator: string; |
9 | 8 | remark: string; |
10 | 9 | } |
11 | -export type queryPageParams = BasicPageParams & { name: string; organizationId: string }; | |
10 | +export type queryPageParams = BasicPageParams & { | |
11 | + name?: Nullable<string>; | |
12 | + organizationId?: Nullable<number>; | |
13 | +}; | |
12 | 14 | |
13 | 15 | export interface ConfigurationModal { |
14 | 16 | items: ConfigurationCenterItemsModal[]; | ... | ... |
... | ... | @@ -47,8 +47,8 @@ export default defineComponent({ |
47 | 47 | const { |
48 | 48 | getContentMode, |
49 | 49 | getShowFooter, |
50 | - getShowBreadCrumb, | |
51 | - getShowBreadCrumbIcon, | |
50 | + // getShowBreadCrumb, | |
51 | + // getShowBreadCrumbIcon, | |
52 | 52 | getShowLogo, |
53 | 53 | getFullContent, |
54 | 54 | getColorWeak, |
... | ... | @@ -281,7 +281,7 @@ export default defineComponent({ |
281 | 281 | function renderContent() { |
282 | 282 | return ( |
283 | 283 | <> |
284 | - <SwitchItem | |
284 | + {/* <SwitchItem | |
285 | 285 | title={t('layout.setting.breadcrumb')} |
286 | 286 | event={HandlerEnum.SHOW_BREADCRUMB} |
287 | 287 | def={unref(getShowBreadCrumb)} |
... | ... | @@ -299,7 +299,7 @@ export default defineComponent({ |
299 | 299 | title={t('layout.setting.tabs')} |
300 | 300 | event={HandlerEnum.TABS_SHOW} |
301 | 301 | def={unref(getShowMultipleTab)} |
302 | - /> | |
302 | + /> */} | |
303 | 303 | |
304 | 304 | <SwitchItem |
305 | 305 | title={t('layout.setting.tabsRedoBtn')} | ... | ... |
... | ... | @@ -250,7 +250,7 @@ export const DeviceProfileIdMaxLength: Rule[] = [ |
250 | 250 | required: true, |
251 | 251 | validator: (_, value: string) => { |
252 | 252 | if (String(value).length > 36) { |
253 | - return Promise.reject('设备配置长度不超过36字'); | |
253 | + return Promise.reject('所属产品长度不超过36字'); | |
254 | 254 | } |
255 | 255 | return Promise.resolve(); |
256 | 256 | }, | ... | ... |
... | ... | @@ -22,8 +22,8 @@ export enum AlarmPermissionKey { |
22 | 22 | export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { |
23 | 23 | const { |
24 | 24 | alarmNotifyStatus = AlarmStatus.ACTIVE_UN_ACK, |
25 | - interval = import.meta.env.VITE_ALARM_NOTIFY_POLLING_INTERVAL_TIME, | |
26 | - duration = import.meta.env.VITE_ALARM_NOTIFY_DURATION, | |
25 | + interval = import.meta.env.VITE_ALARM_NOTIFY_POLLING_INTERVAL_TIME || 60000, | |
26 | + duration = import.meta.env.VITE_ALARM_NOTIFY_DURATION || 5, | |
27 | 27 | color = 'orange', |
28 | 28 | } = params; |
29 | 29 | const alarmNotifyStatusMean = AlarmStatusMean[alarmNotifyStatus]; | ... | ... |
1 | 1 | <script setup lang="ts"> |
2 | 2 | import { PageWrapper } from '/@/components/Page'; |
3 | 3 | import OrganizationIdTree from '../../common/organizationIdTree/src/OrganizationIdTree.vue'; |
4 | - import { computed, onMounted, reactive, ref, unref, watch } from 'vue'; | |
5 | - import { Tabs, Row, Col, Spin, Button, Pagination, Empty } from 'ant-design-vue'; | |
4 | + import { onMounted, reactive, ref, unref, watch } from 'vue'; | |
5 | + import { Spin, Button, Pagination, Space, List } from 'ant-design-vue'; | |
6 | 6 | import { cameraPage } from '/@/api/camera/cameraManager'; |
7 | 7 | import { CameraRecord } from '/@/api/camera/model/cameraModel'; |
8 | 8 | import { videoPlay as VideoPlay } from 'vue3-video-play'; |
... | ... | @@ -14,6 +14,7 @@ |
14 | 14 | import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; |
15 | 15 | import { isDef } from '/@/utils/is'; |
16 | 16 | import { getStreamingPlayUrl } from '/@/api/camera/cameraManager'; |
17 | + import { buildUUID } from '/@/utils/uuid'; | |
17 | 18 | |
18 | 19 | type CameraRecordItem = CameraRecord & { |
19 | 20 | canPlay?: boolean; |
... | ... | @@ -67,15 +68,11 @@ |
67 | 68 | getCameraList(); |
68 | 69 | }; |
69 | 70 | |
70 | - const getColLayout = computed(() => { | |
71 | - const totalSpan = 24; | |
72 | - return totalSpan / pagination.colNumber; | |
73 | - }); | |
74 | - | |
75 | 71 | const getCameraList = async () => { |
76 | 72 | try { |
73 | + cameraList.value = []; | |
77 | 74 | loading.value = true; |
78 | - const { items, total } = await cameraPage({ | |
75 | + let { items, total } = await cameraPage({ | |
79 | 76 | page: pagination.page, |
80 | 77 | pageSize: pagination.pageSize, |
81 | 78 | organizationId: unref(organizationId)!, |
... | ... | @@ -87,6 +84,14 @@ |
87 | 84 | (item as CameraRecordItem).isTransform = false; |
88 | 85 | beforeVideoPlay(item); |
89 | 86 | } |
87 | + if (items.length < pagination.pageSize) { | |
88 | + const fillArr: any = Array.from({ length: pagination.pageSize - items.length }).map(() => ({ | |
89 | + id: buildUUID(), | |
90 | + placeholder: true, | |
91 | + })); | |
92 | + items = [...items, ...fillArr]; | |
93 | + console.log(fillArr); | |
94 | + } | |
90 | 95 | cameraList.value = items; |
91 | 96 | } catch (error) { |
92 | 97 | } finally { |
... | ... | @@ -128,7 +133,10 @@ |
128 | 133 | } |
129 | 134 | }; |
130 | 135 | |
136 | + const gridLayout = ref({ gutter: 1, column: 2 }); | |
137 | + | |
131 | 138 | const handleSwitchLayoutWay = (pageSize: number, layout: number) => { |
139 | + gridLayout.value = { gutter: 1, column: Math.sqrt(pageSize) }; | |
132 | 140 | pagination.colNumber = layout; |
133 | 141 | pagination.pageSize = pageSize; |
134 | 142 | pagination.page = 1; |
... | ... | @@ -185,7 +193,7 @@ |
185 | 193 | <PageWrapper dense contentFullHeight contentClass="flex"> |
186 | 194 | <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> |
187 | 195 | <section class="p-4 pl-9 split-screen-mode flex flex-col flex-auto w-3/4 xl:w-4/5"> |
188 | - <div class="p-3 bg-light-50 flex justify-between mb-4"> | |
196 | + <div class="p-3 bg-light-50 flex justify-between mb-4 dark:bg-dark-900"> | |
189 | 197 | <div class="flex gap-4 cursor-pointer items-center"> |
190 | 198 | <div |
191 | 199 | class="w-8 h-8 flex justify-center items-center" |
... | ... | @@ -225,14 +233,67 @@ |
225 | 233 | <div class="flex"> |
226 | 234 | <Button type="primary" @click="handleAddCamera">新增视频</Button> |
227 | 235 | </div> |
228 | - <Tabs type="card" v-model:activeKey="activeKey" @change="handleChangeMode"> | |
229 | - <Tabs.TabPane :key="PageMode.SPLIT_SCREEN_MODE" tab="分屏模式" /> | |
230 | - <Tabs.TabPane :key="PageMode.LIST_MODE" tab="列表模式" /> | |
231 | - <Tabs.TabPane :key="PageMode.FULL_SCREEN_MODE" tab="全屏" /> | |
232 | - </Tabs> | |
236 | + <Space> | |
237 | + <Button type="primary" @click="handleChangeMode(PageMode.SPLIT_SCREEN_MODE)"> | |
238 | + 分屏模式 | |
239 | + </Button> | |
240 | + <Button type="primary" @click="handleChangeMode(PageMode.LIST_MODE)"> | |
241 | + 列表模式 | |
242 | + </Button> | |
243 | + <Button type="primary" @click="handleChangeMode(PageMode.FULL_SCREEN_MODE)"> | |
244 | + 全屏 | |
245 | + </Button> | |
246 | + </Space> | |
233 | 247 | </div> |
234 | 248 | </div> |
235 | - <section ref="videoContainer" class="bg-light-50 flex-auto"> | |
249 | + <List | |
250 | + :loading="loading" | |
251 | + :data-source="cameraList" | |
252 | + class="bg-light-50 flex-auto dark:bg-dark-900 split-mode-list" | |
253 | + :grid="gridLayout" | |
254 | + :style="{ '--height': `${100 / pagination.colNumber}%` }" | |
255 | + > | |
256 | + <template #renderItem="{ item }"> | |
257 | + <List.Item> | |
258 | + <div class="box-border w-full h-full p-1px"> | |
259 | + <div | |
260 | + v-if="item.placeholder" | |
261 | + class="bg-black w-full h-full overflow-hidden relative" | |
262 | + ></div> | |
263 | + <div | |
264 | + v-if="!item.placeholder" | |
265 | + class="bg-black w-full h-full overflow-hidden relative video-container" | |
266 | + > | |
267 | + <Spin v-show="!item.isTransform" :spinning="!item.isTransform"> | |
268 | + <div class="bg-black text-light-50"> </div> | |
269 | + </Spin> | |
270 | + <VideoPlay | |
271 | + v-show="item.isTransform" | |
272 | + @loadstart="handleLoadStart(item)" | |
273 | + @loadeddata="handleLoadData(item)" | |
274 | + v-bind="options" | |
275 | + :src="item.videoUrl" | |
276 | + :title="item.name" | |
277 | + :type="item.type" | |
278 | + /> | |
279 | + <div | |
280 | + v-if="item.isTransform && isDef(item.canPlay) && !item.canPlay" | |
281 | + class="video-container-error-msk absolute top-0 left-0 text-lg w-full h-full text-light-50 flex justify-center items-center z-50 bg-black" | |
282 | + > | |
283 | + 视频加载出错了! | |
284 | + </div> | |
285 | + <div | |
286 | + class="video-container-mask absolute top-0 left-0 z-50 text-lg w-full text-light-50 flex justify-center items-center" | |
287 | + style="height: 100%; background-color: rgba(0, 0, 0, 0.5)" | |
288 | + > | |
289 | + <span>{{ item.name }}</span> | |
290 | + </div> | |
291 | + </div> | |
292 | + </div> | |
293 | + </List.Item> | |
294 | + </template> | |
295 | + </List> | |
296 | + <!-- <section ref="videoContainer" class="bg-light-50 flex-auto dark:bg-dark-900"> | |
236 | 297 | <Spin :spinning="loading" class="h-full"> |
237 | 298 | <Empty |
238 | 299 | class="h-full flex flex-col justify-center items-center" |
... | ... | @@ -277,7 +338,7 @@ |
277 | 338 | </Col> |
278 | 339 | </Row> |
279 | 340 | </Spin> |
280 | - </section> | |
341 | + </section> --> | |
281 | 342 | </section> |
282 | 343 | </PageWrapper> |
283 | 344 | <CameraDrawer @register="registerDrawer" @success="getCameraList" /> |
... | ... | @@ -334,4 +395,20 @@ |
334 | 395 | } |
335 | 396 | } |
336 | 397 | } |
398 | + | |
399 | + .split-mode-list:deep(.ant-row) { | |
400 | + width: 100%; | |
401 | + height: 100%; | |
402 | + } | |
403 | + | |
404 | + .split-mode-list:deep(.ant-list-item) { | |
405 | + width: 100%; | |
406 | + height: 100%; | |
407 | + } | |
408 | + | |
409 | + .split-mode-list:deep(.ant-col) { | |
410 | + width: 100%; | |
411 | + // height: var(--height); | |
412 | + height: 100%; | |
413 | + } | |
337 | 414 | </style> | ... | ... |
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | <div class="organization-tree flex relative"> |
3 | 3 | <div class="cursor-pointer flex py-4 fold-icon" :class="foldFlag ? 'absolute' : ''"> |
4 | 4 | <div @click="handleFold"> |
5 | - <DoubleRightOutlined :class="[foldFlag ? '' : 'rotate-180']" class="text-xl transform" /> | |
5 | + <CaretRightOutlined :class="[foldFlag ? '' : 'rotate-180']" class="text-xl transform" /> | |
6 | 6 | </div> |
7 | 7 | </div> |
8 | 8 | <div |
... | ... | @@ -29,7 +29,7 @@ |
29 | 29 | import { onMounted, ref, unref } from 'vue'; |
30 | 30 | import { BasicTree, TreeItem } from '/@/components/Tree'; |
31 | 31 | import { getOrganizationList } from '/@/api/system/system'; |
32 | - import { DoubleRightOutlined } from '@ant-design/icons-vue'; | |
32 | + import { CaretRightOutlined } from '@ant-design/icons-vue'; | |
33 | 33 | |
34 | 34 | const emit = defineEmits(['select']); |
35 | 35 | const treeData = ref<TreeItem[]>([]); | ... | ... |
src/views/configuration/center/TableMode.vue
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <PageWrapper dense contentFullHeight contentClass="flex"> | |
4 | + <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> | |
5 | + <BasicTable | |
6 | + style="flex: auto" | |
7 | + :clickToRowSelect="false" | |
8 | + @register="registerTable" | |
9 | + :searchInfo="searchInfo" | |
10 | + class="w-3/4 xl:w-4/5" | |
11 | + > | |
12 | + <template #platform="{ record }"> | |
13 | + <Tag :color="record.platform === Platform.PHONE ? 'cyan' : 'blue'"> | |
14 | + {{ record.platform === Platform.PHONE ? '移动端' : 'PC端' }} | |
15 | + </Tag> | |
16 | + </template> | |
17 | + <template #toolbar> | |
18 | + <Authority value="api:yt:configuration:center:post"> | |
19 | + <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增组态 </a-button> | |
20 | + </Authority> | |
21 | + <Authority value="api:yt:configuration:center:delete"> | |
22 | + <Popconfirm | |
23 | + title="您确定要批量删除数据" | |
24 | + ok-text="确定" | |
25 | + cancel-text="取消" | |
26 | + @confirm="handleDeleteOrBatchDelete(null)" | |
27 | + > | |
28 | + <a-button type="primary" color="error" :disabled="hasBatchDelete"> | |
29 | + 批量删除 | |
30 | + </a-button> | |
31 | + </Popconfirm> | |
32 | + </Authority> | |
33 | + </template> | |
34 | + <template #action="{ record }"> | |
35 | + <TableAction | |
36 | + :actions="[ | |
37 | + { | |
38 | + label: '设计', | |
39 | + auth: 'api:yt:configuration:center:get_configuration_info:get', | |
40 | + icon: 'clarity:note-edit-line', | |
41 | + onClick: handleDesign.bind(null, record), | |
42 | + }, | |
43 | + { | |
44 | + label: '预览', | |
45 | + auth: 'api:yt:configuration:center:get_configuration_info:get', | |
46 | + icon: 'ant-design:eye-outlined', | |
47 | + onClick: handlePreview.bind(null, record), | |
48 | + }, | |
49 | + { | |
50 | + label: '编辑', | |
51 | + auth: 'api:yt:configuration:center:update', | |
52 | + icon: 'clarity:note-edit-line', | |
53 | + onClick: handleCreateOrEdit.bind(null, record), | |
54 | + }, | |
55 | + { | |
56 | + label: '删除', | |
57 | + auth: 'api:yt:configuration:center:delete', | |
58 | + icon: 'ant-design:delete-outlined', | |
59 | + color: 'error', | |
60 | + popConfirm: { | |
61 | + title: '是否确认删除', | |
62 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | |
63 | + }, | |
64 | + }, | |
65 | + ]" | |
66 | + /> | |
67 | + </template> | |
68 | + </BasicTable> | |
69 | + </PageWrapper> | |
70 | + <ContactDrawer @register="registerDrawer" @success="handleSuccess" /> | |
71 | + </div> | |
72 | +</template> | |
73 | + | |
74 | +<script lang="ts"> | |
75 | + import { defineComponent, reactive, nextTick } from 'vue'; | |
76 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
77 | + import { PageWrapper } from '/@/components/Page'; | |
78 | + import { useDrawer } from '/@/components/Drawer'; | |
79 | + import ContactDrawer from './ConfigurationCenterDrawer.vue'; | |
80 | + import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree'; | |
81 | + import { searchFormSchema, columns, Platform } from './center.data'; | |
82 | + import { | |
83 | + getPage, | |
84 | + deleteConfigurationCenter, | |
85 | + } from '/@/api/configuration/center/configurationCenter'; | |
86 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | |
87 | + import { getAppEnvConfig, isDevMode } from '/@/utils/env'; | |
88 | + import { Authority } from '/@/components/Authority'; | |
89 | + import { Popconfirm } from 'ant-design-vue'; | |
90 | + import { Tag } from 'ant-design-vue'; | |
91 | + export default defineComponent({ | |
92 | + components: { | |
93 | + PageWrapper, | |
94 | + OrganizationIdTree, | |
95 | + BasicTable, | |
96 | + TableAction, | |
97 | + ContactDrawer, | |
98 | + Authority, | |
99 | + Popconfirm, | |
100 | + Tag, | |
101 | + }, | |
102 | + setup() { | |
103 | + const { VITE_GLOB_CONFIGURATION } = getAppEnvConfig(); | |
104 | + const isDev = isDevMode(); | |
105 | + const searchInfo = reactive<Recordable>({}); | |
106 | + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | |
107 | + // 表格hooks | |
108 | + const [registerTable, { reload, setProps }] = useTable({ | |
109 | + title: '组态中心列表', | |
110 | + api: getPage, | |
111 | + columns, | |
112 | + clickToRowSelect: false, | |
113 | + formConfig: { | |
114 | + labelWidth: 120, | |
115 | + schemas: searchFormSchema, | |
116 | + resetFunc: resetFn, | |
117 | + }, | |
118 | + showIndexColumn: false, | |
119 | + useSearchForm: true, | |
120 | + showTableSetting: true, | |
121 | + bordered: true, | |
122 | + rowKey: 'id', | |
123 | + actionColumn: { | |
124 | + width: 200, | |
125 | + title: '操作', | |
126 | + dataIndex: 'action', | |
127 | + slots: { customRender: 'action' }, | |
128 | + fixed: 'right', | |
129 | + }, | |
130 | + }); | |
131 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | |
132 | + deleteConfigurationCenter, | |
133 | + handleSuccess, | |
134 | + setProps | |
135 | + ); | |
136 | + nextTick(() => { | |
137 | + setProps(selectionOptions); | |
138 | + }); | |
139 | + | |
140 | + // 弹框 | |
141 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
142 | + | |
143 | + // 刷新 | |
144 | + function handleSuccess() { | |
145 | + reload(); | |
146 | + } | |
147 | + // 新增或编辑 | |
148 | + const handleCreateOrEdit = (record: Recordable | null) => { | |
149 | + if (record) { | |
150 | + openDrawer(true, { | |
151 | + isUpdate: true, | |
152 | + record, | |
153 | + }); | |
154 | + } else { | |
155 | + openDrawer(true, { | |
156 | + isUpdate: false, | |
157 | + }); | |
158 | + } | |
159 | + }; | |
160 | + // 树形选择器 | |
161 | + const handleSelect = (organizationId: string) => { | |
162 | + searchInfo.organizationId = organizationId; | |
163 | + handleSuccess(); | |
164 | + }; | |
165 | + | |
166 | + const handlePreview = (record: Recordable | null) => { | |
167 | + window.open( | |
168 | + `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${ | |
169 | + record!.id | |
170 | + }&lightbox=1` | |
171 | + ); | |
172 | + }; | |
173 | + const handleDesign = (record: Recordable | null) => { | |
174 | + window.open( | |
175 | + `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}` | |
176 | + ); | |
177 | + }; | |
178 | + | |
179 | + return { | |
180 | + Platform, | |
181 | + searchInfo, | |
182 | + hasBatchDelete, | |
183 | + handleCreateOrEdit, | |
184 | + handleDeleteOrBatchDelete, | |
185 | + handleSelect, | |
186 | + handleSuccess, | |
187 | + handlePreview, | |
188 | + handleDesign, | |
189 | + registerTable, | |
190 | + registerDrawer, | |
191 | + organizationIdTreeRef, | |
192 | + }; | |
193 | + }, | |
194 | + }); | |
195 | +</script> | ... | ... |
1 | -<template> | |
2 | - <div> | |
3 | - <PageWrapper dense contentFullHeight contentClass="flex"> | |
4 | - <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> | |
5 | - <BasicTable | |
6 | - style="flex: auto" | |
7 | - :clickToRowSelect="false" | |
8 | - @register="registerTable" | |
9 | - :searchInfo="searchInfo" | |
10 | - class="w-3/4 xl:w-4/5" | |
11 | - > | |
12 | - <template #platform="{ record }"> | |
13 | - <Tag :color="record.platform === Platform.PHONE ? 'cyan' : 'blue'"> | |
14 | - {{ record.platform === Platform.PHONE ? '移动端' : 'PC端' }} | |
15 | - </Tag> | |
16 | - </template> | |
17 | - <template #toolbar> | |
18 | - <Authority value="api:yt:configuration:center:post"> | |
19 | - <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增组态 </a-button> | |
20 | - </Authority> | |
21 | - <Authority value="api:yt:configuration:center:delete"> | |
22 | - <Popconfirm | |
23 | - title="您确定要批量删除数据" | |
24 | - ok-text="确定" | |
25 | - cancel-text="取消" | |
26 | - @confirm="handleDeleteOrBatchDelete(null)" | |
27 | - > | |
28 | - <a-button type="primary" color="error" :disabled="hasBatchDelete"> | |
29 | - 批量删除 | |
30 | - </a-button> | |
31 | - </Popconfirm> | |
32 | - </Authority> | |
33 | - </template> | |
34 | - <template #action="{ record }"> | |
35 | - <TableAction | |
36 | - :actions="[ | |
37 | - { | |
38 | - label: '设计', | |
39 | - auth: 'api:yt:configuration:center:get_configuration_info:get', | |
40 | - icon: 'clarity:note-edit-line', | |
41 | - onClick: handleDesign.bind(null, record), | |
42 | - }, | |
43 | - { | |
44 | - label: '预览', | |
45 | - auth: 'api:yt:configuration:center:get_configuration_info:get', | |
46 | - icon: 'ant-design:eye-outlined', | |
47 | - onClick: handlePreview.bind(null, record), | |
48 | - }, | |
49 | - { | |
50 | - label: '编辑', | |
51 | - auth: 'api:yt:configuration:center:update', | |
52 | - icon: 'clarity:note-edit-line', | |
53 | - onClick: handleCreateOrEdit.bind(null, record), | |
54 | - }, | |
55 | - { | |
56 | - label: '删除', | |
57 | - auth: 'api:yt:configuration:center:delete', | |
58 | - icon: 'ant-design:delete-outlined', | |
59 | - color: 'error', | |
60 | - popConfirm: { | |
61 | - title: '是否确认删除', | |
62 | - confirm: handleDeleteOrBatchDelete.bind(null, record), | |
63 | - }, | |
64 | - }, | |
65 | - ]" | |
66 | - /> | |
67 | - </template> | |
68 | - </BasicTable> | |
69 | - </PageWrapper> | |
70 | - <ContactDrawer @register="registerDrawer" @success="handleSuccess" /> | |
71 | - </div> | |
72 | -</template> | |
73 | - | |
74 | -<script lang="ts"> | |
75 | - import { defineComponent, reactive, nextTick } from 'vue'; | |
76 | - import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
77 | - import { PageWrapper } from '/@/components/Page'; | |
78 | - import { useDrawer } from '/@/components/Drawer'; | |
79 | - import ContactDrawer from './ConfigurationCenterDrawer.vue'; | |
80 | - import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree'; | |
81 | - import { searchFormSchema, columns, Platform } from './center.data'; | |
1 | +<script setup lang="ts"> | |
2 | + import { List, Card, Button, PaginationProps, Popover, Slider, Tooltip } from 'ant-design-vue'; | |
3 | + import { | |
4 | + ReloadOutlined, | |
5 | + AppstoreOutlined, | |
6 | + EyeOutlined, | |
7 | + EditOutlined, | |
8 | + EllipsisOutlined, | |
9 | + } from '@ant-design/icons-vue'; | |
10 | + import { onMounted, reactive, ref, unref } from 'vue'; | |
11 | + import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree'; | |
82 | 12 | import { |
83 | - getPage, | |
84 | 13 | deleteConfigurationCenter, |
14 | + getPage, | |
85 | 15 | } from '/@/api/configuration/center/configurationCenter'; |
86 | - import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | |
87 | - import { getAppEnvConfig, isDevMode } from '/@/utils/env'; | |
16 | + import { ConfigurationCenterItemsModal } from '/@/api/configuration/center/model/configurationCenterModal'; | |
17 | + import { PageWrapper } from '/@/components/Page'; | |
18 | + import { Dropdown } from '/@/components/Dropdown'; | |
19 | + import { BasicForm, useForm } from '/@/components/Form'; | |
20 | + import { searchFormSchema } from './center.data'; | |
21 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
88 | 22 | import { Authority } from '/@/components/Authority'; |
89 | - import { Popconfirm } from 'ant-design-vue'; | |
90 | - import { Tag } from 'ant-design-vue'; | |
91 | - export default defineComponent({ | |
92 | - components: { | |
93 | - PageWrapper, | |
94 | - OrganizationIdTree, | |
95 | - BasicTable, | |
96 | - TableAction, | |
97 | - ContactDrawer, | |
98 | - Authority, | |
99 | - Popconfirm, | |
100 | - Tag, | |
23 | + import { isDevMode } from '/@/utils/env'; | |
24 | + import ConfigurationCenterDrawer from './ConfigurationCenterDrawer.vue'; | |
25 | + import { useDrawer } from '/@/components/Drawer'; | |
26 | + import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; | |
27 | + import { getBoundingClientRect } from '/@/utils/domUtils'; | |
28 | + | |
29 | + const listColumn = ref(4); | |
30 | + | |
31 | + const { createMessage } = useMessage(); | |
32 | + | |
33 | + const organizationId = ref<Nullable<number>>(null); | |
34 | + | |
35 | + const pagination = reactive<PaginationProps>({ | |
36 | + size: 'small', | |
37 | + showTotal: (total: number) => `共 ${total} 条数据`, | |
38 | + current: 1, | |
39 | + onChange: (page: number) => { | |
40 | + pagination.current = page; | |
41 | + getListData(); | |
42 | + }, | |
43 | + }); | |
44 | + | |
45 | + const loading = ref(false); | |
46 | + | |
47 | + const dataSource = ref<ConfigurationCenterItemsModal[]>([]); | |
48 | + | |
49 | + const [registerForm, { getFieldsValue }] = useForm({ | |
50 | + schemas: searchFormSchema, | |
51 | + showAdvancedButton: true, | |
52 | + labelWidth: 100, | |
53 | + compact: true, | |
54 | + resetFunc: () => { | |
55 | + resetFn(); | |
56 | + organizationId.value = null; | |
57 | + return getListData(); | |
101 | 58 | }, |
102 | - setup() { | |
103 | - const { VITE_GLOB_CONFIGURATION } = getAppEnvConfig(); | |
104 | - const isDev = isDevMode(); | |
105 | - const searchInfo = reactive<Recordable>({}); | |
106 | - const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | |
107 | - // 表格hooks | |
108 | - const [registerTable, { reload, setProps }] = useTable({ | |
109 | - title: '组态中心列表', | |
110 | - api: getPage, | |
111 | - columns, | |
112 | - clickToRowSelect: false, | |
113 | - formConfig: { | |
114 | - labelWidth: 120, | |
115 | - schemas: searchFormSchema, | |
116 | - resetFunc: resetFn, | |
117 | - }, | |
118 | - showIndexColumn: false, | |
119 | - useSearchForm: true, | |
120 | - showTableSetting: true, | |
121 | - bordered: true, | |
122 | - rowKey: 'id', | |
123 | - actionColumn: { | |
124 | - width: 200, | |
125 | - title: '操作', | |
126 | - dataIndex: 'action', | |
127 | - slots: { customRender: 'action' }, | |
128 | - fixed: 'right', | |
129 | - }, | |
59 | + submitFunc: async () => { | |
60 | + const value = getFieldsValue(); | |
61 | + getListData(value); | |
62 | + }, | |
63 | + }); | |
64 | + | |
65 | + async function getListData(value: Recordable = {}) { | |
66 | + try { | |
67 | + loading.value = true; | |
68 | + const pageSize = 4 * unref(listColumn); | |
69 | + const { items, total } = await getPage({ | |
70 | + organizationId: unref(organizationId), | |
71 | + ...value, | |
72 | + page: pagination.current!, | |
73 | + pageSize, | |
74 | + }); | |
75 | + dataSource.value = items; | |
76 | + pagination.total = total; | |
77 | + pagination.pageSize = pageSize; | |
78 | + } catch (error) { | |
79 | + } finally { | |
80 | + loading.value = false; | |
81 | + } | |
82 | + } | |
83 | + | |
84 | + onMounted(() => { | |
85 | + getListData(); | |
86 | + }); | |
87 | + | |
88 | + const searchInfo = reactive<Recordable>({}); | |
89 | + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | |
90 | + const handleSelect = (orgId: number) => { | |
91 | + organizationId.value = orgId; | |
92 | + getListData(); | |
93 | + }; | |
94 | + | |
95 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
96 | + | |
97 | + const handleCreateOrUpdate = (record?: ConfigurationCenterItemsModal) => { | |
98 | + if (record) { | |
99 | + openDrawer(true, { | |
100 | + isUpdate: true, | |
101 | + record, | |
130 | 102 | }); |
131 | - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | |
132 | - deleteConfigurationCenter, | |
133 | - handleSuccess, | |
134 | - setProps | |
135 | - ); | |
136 | - nextTick(() => { | |
137 | - setProps(selectionOptions); | |
103 | + } else { | |
104 | + openDrawer(true, { | |
105 | + isUpdate: false, | |
138 | 106 | }); |
107 | + } | |
108 | + }; | |
139 | 109 | |
140 | - // 弹框 | |
141 | - const [registerDrawer, { openDrawer }] = useDrawer(); | |
142 | - | |
143 | - // 刷新 | |
144 | - function handleSuccess() { | |
145 | - reload(); | |
146 | - } | |
147 | - // 新增或编辑 | |
148 | - const handleCreateOrEdit = (record: Recordable | null) => { | |
149 | - if (record) { | |
150 | - openDrawer(true, { | |
151 | - isUpdate: true, | |
152 | - record, | |
153 | - }); | |
154 | - } else { | |
155 | - openDrawer(true, { | |
156 | - isUpdate: false, | |
157 | - }); | |
158 | - } | |
159 | - }; | |
160 | - // 树形选择器 | |
161 | - const handleSelect = (organizationId: string) => { | |
162 | - searchInfo.organizationId = organizationId; | |
163 | - handleSuccess(); | |
164 | - }; | |
165 | - | |
166 | - const handlePreview = (record: Recordable | null) => { | |
167 | - window.open( | |
168 | - `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${ | |
169 | - record!.id | |
170 | - }&lightbox=1` | |
171 | - ); | |
172 | - }; | |
173 | - const handleDesign = (record: Recordable | null) => { | |
174 | - window.open( | |
175 | - `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}` | |
176 | - ); | |
177 | - }; | |
178 | - | |
179 | - return { | |
180 | - Platform, | |
181 | - searchInfo, | |
182 | - hasBatchDelete, | |
183 | - handleCreateOrEdit, | |
184 | - handleDeleteOrBatchDelete, | |
185 | - handleSelect, | |
186 | - handleSuccess, | |
187 | - handlePreview, | |
188 | - handleDesign, | |
189 | - registerTable, | |
190 | - registerDrawer, | |
191 | - organizationIdTreeRef, | |
192 | - }; | |
193 | - }, | |
110 | + const { VITE_GLOB_CONFIGURATION } = import.meta.env; | |
111 | + const isDev = isDevMode(); | |
112 | + | |
113 | + const handlePreview = (record: ConfigurationCenterItemsModal) => { | |
114 | + console.log(record); | |
115 | + window.open( | |
116 | + `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${ | |
117 | + record!.id | |
118 | + }&lightbox=1` | |
119 | + ); | |
120 | + }; | |
121 | + | |
122 | + const handleDesign = (record: ConfigurationCenterItemsModal) => { | |
123 | + window.open( | |
124 | + `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}` | |
125 | + ); | |
126 | + }; | |
127 | + | |
128 | + const { createSyncConfirm } = useSyncConfirm(); | |
129 | + const handleDelete = async (record: ConfigurationCenterItemsModal) => { | |
130 | + try { | |
131 | + await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' }); | |
132 | + await deleteConfigurationCenter([record.id]); | |
133 | + createMessage.success('删除成功'); | |
134 | + await getListData(); | |
135 | + } catch (error) {} | |
136 | + }; | |
137 | + | |
138 | + const listEl = ref<Nullable<ComponentElRef>>(null); | |
139 | + | |
140 | + onMounted(() => { | |
141 | + const clientHeight = document.documentElement.clientHeight; | |
142 | + const rect = getBoundingClientRect(unref(listEl)!.$el!) as DOMRect; | |
143 | + // margin-top 24 height 24 | |
144 | + const paginationHeight = 24 + 24 + 8; | |
145 | + // list pading top 8 maring-top 8 extra slot 56 | |
146 | + const listContainerMarginBottom = 8 + 8 + 56; | |
147 | + const listContainerHeight = | |
148 | + clientHeight - rect.top - paginationHeight - listContainerMarginBottom; | |
149 | + const listContainerEl = (unref(listEl)!.$el as HTMLElement).querySelector( | |
150 | + '.ant-spin-container' | |
151 | + ) as HTMLElement; | |
152 | + listContainerEl && | |
153 | + (listContainerEl.style.height = listContainerHeight + 'px') && | |
154 | + (listContainerEl.style.overflowY = 'auto') && | |
155 | + (listContainerEl.style.overflowX = 'hidden'); | |
194 | 156 | }); |
195 | 157 | </script> |
158 | + | |
159 | +<template> | |
160 | + <PageWrapper dense contentFullHeight contentClass="flex"> | |
161 | + <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> | |
162 | + <section class="flex-auto pl-9 p-4 configuration-list"> | |
163 | + <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4"> | |
164 | + <BasicForm @register="registerForm" /> | |
165 | + </div> | |
166 | + <List | |
167 | + ref="listEl" | |
168 | + :loading="loading" | |
169 | + class="flex-auto bg-light-50 dark:bg-dark-900 !p-2 !mt-4" | |
170 | + position="bottom" | |
171 | + :pagination="pagination" | |
172 | + :data-source="dataSource" | |
173 | + :grid="{ gutter: 4, column: listColumn }" | |
174 | + > | |
175 | + <template #header> | |
176 | + <div class="flex gap-3 justify-end"> | |
177 | + <Button type="primary" @click="handleCreateOrUpdate()">新增组态</Button> | |
178 | + <Popover :trigger="['hover']"> | |
179 | + <template #content> | |
180 | + <div class="w-50"> | |
181 | + <div>每行显示数量</div> | |
182 | + <Slider | |
183 | + v-model:value="listColumn" | |
184 | + :max="12" | |
185 | + :min="4" | |
186 | + :marks="{ 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 }" | |
187 | + @change="getListData" | |
188 | + /> | |
189 | + </div> | |
190 | + </template> | |
191 | + <Button type="primary"> | |
192 | + <AppstoreOutlined /> | |
193 | + </Button> | |
194 | + </Popover> | |
195 | + <Tooltip title="刷新"> | |
196 | + <Button type="primary" @click="getListData"> | |
197 | + <ReloadOutlined @click="getListData" /> | |
198 | + </Button> | |
199 | + </Tooltip> | |
200 | + </div> | |
201 | + </template> | |
202 | + <template #renderItem="{ item }"> | |
203 | + <List.Item> | |
204 | + <Card hoverable> | |
205 | + <template #cover> | |
206 | + <img | |
207 | + alt="example" | |
208 | + src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png" | |
209 | + /> | |
210 | + </template> | |
211 | + <template class="ant-card-actions" #actions> | |
212 | + <Authority value="api:yt:configuration:center:get_configuration_info:get"> | |
213 | + <Tooltip title="预览"> | |
214 | + <EyeOutlined key="setting" @click="handlePreview(item)" /> | |
215 | + </Tooltip> | |
216 | + </Authority> | |
217 | + <Authority value="api:yt:configuration:center:update"> | |
218 | + <Tooltip title="编辑"> | |
219 | + <EditOutlined key="edit" @click="handleCreateOrUpdate(item)" /> | |
220 | + </Tooltip> | |
221 | + </Authority> | |
222 | + <Dropdown | |
223 | + :dropMenuList="[ | |
224 | + { | |
225 | + text: '设计', | |
226 | + auth: 'api:yt:configuration:center:get_configuration_info:get', | |
227 | + icon: 'clarity:note-edit-line', | |
228 | + onClick: handleDesign.bind(null, item), | |
229 | + }, | |
230 | + { | |
231 | + text: '删除', | |
232 | + auth: 'api:yt:configuration:center:delete', | |
233 | + icon: 'ant-design:delete-outlined', | |
234 | + color: 'error', | |
235 | + onClick: handleDelete.bind(null, item), | |
236 | + }, | |
237 | + ]" | |
238 | + :trigger="['hover']" | |
239 | + > | |
240 | + <EllipsisOutlined key="ellipsis" /> | |
241 | + </Dropdown> | |
242 | + </template> | |
243 | + <Card.Meta :title="item.name"> | |
244 | + <template #description> | |
245 | + <div class="truncate">{{ item.organizationDTO.name }}</div> | |
246 | + <div class="truncate">{{ item.remark }} </div> | |
247 | + </template> | |
248 | + </Card.Meta> | |
249 | + </Card> | |
250 | + </List.Item> | |
251 | + </template> | |
252 | + </List> | |
253 | + </section> | |
254 | + <ConfigurationCenterDrawer @register="registerDrawer" @success="getListData" /> | |
255 | + </PageWrapper> | |
256 | +</template> | |
257 | + | |
258 | +<style lang="less" scoped> | |
259 | + .configuration-list:deep(.ant-list-header) { | |
260 | + border-bottom: none !important; | |
261 | + } | |
262 | + | |
263 | + .configuration-list:deep(.ant-list-pagination) { | |
264 | + height: 24px; | |
265 | + } | |
266 | +</style> | ... | ... |
... | ... | @@ -206,7 +206,7 @@ |
206 | 206 | target: '_blank ', |
207 | 207 | }, |
208 | 208 | { |
209 | - title: '什么是设备配置?', | |
209 | + title: '什么是产品?', | |
210 | 210 | href: 'https://docs.thingskit.com/thingskit-link/operation-guide/device-manage.html#%E8%AE%BE%E5%A4%87%E9%85%8D%E7%BD%AE', |
211 | 211 | target: '_blank ', |
212 | 212 | }, | ... | ... |
... | ... | @@ -51,8 +51,8 @@ |
51 | 51 | series: [ |
52 | 52 | { |
53 | 53 | name: '告警数', |
54 | - barWidth: '10%', | |
55 | - type: 'bar', | |
54 | + // barWidth: '10%', | |
55 | + type: 'line', | |
56 | 56 | stack: 'Total', |
57 | 57 | data: props.alarmList, |
58 | 58 | color: '#3C78FF', |
... | ... | @@ -63,6 +63,7 @@ |
63 | 63 | watch( |
64 | 64 | () => props.alarmList, |
65 | 65 | (newValue) => { |
66 | + console.log({ newValue, props }); | |
66 | 67 | let alarmTotal = 0; |
67 | 68 | for (const item of props.alarmList) { |
68 | 69 | alarmTotal += Number(item[1]); |
... | ... | @@ -91,10 +92,10 @@ |
91 | 92 | series: [ |
92 | 93 | { |
93 | 94 | name: '告警数', |
94 | - type: 'bar', | |
95 | + type: 'line', | |
95 | 96 | stack: 'Total', |
96 | 97 | color: '#3C78FF', |
97 | - barWidth: '10%', | |
98 | + // barWidth: '10%', | |
98 | 99 | data: newValue, |
99 | 100 | }, |
100 | 101 | ], | ... | ... |
... | ... | @@ -63,17 +63,17 @@ |
63 | 63 | series: [ |
64 | 64 | { |
65 | 65 | name: '传输数据点', |
66 | - type: 'bar', | |
66 | + type: 'line', | |
67 | 67 | stack: 'total', |
68 | 68 | data: newValue, |
69 | - barWidth: '10%', | |
69 | + // barWidth: '10%', | |
70 | 70 | color: '#5AEEED', |
71 | 71 | }, |
72 | 72 | { |
73 | 73 | name: '传输消息量', |
74 | - type: 'bar', | |
74 | + type: 'line', | |
75 | 75 | stack: 'total', |
76 | - barWidth: '10%', | |
76 | + // barWidth: '10%', | |
77 | 77 | data: newValue1, |
78 | 78 | color: '#3C78FF', |
79 | 79 | }, | ... | ... |
... | ... | @@ -35,7 +35,7 @@ export const step1Schemas: FormSchema[] = [ |
35 | 35 | }, |
36 | 36 | { |
37 | 37 | field: 'profileId', |
38 | - label: '设备配置', | |
38 | + label: '所属产品', | |
39 | 39 | required: true, |
40 | 40 | component: 'ApiSelect', |
41 | 41 | componentProps: ({ formActionType }) => { |
... | ... | @@ -57,7 +57,7 @@ export const step1Schemas: FormSchema[] = [ |
57 | 57 | required: true, |
58 | 58 | component: 'ApiSelect', |
59 | 59 | dynamicDisabled: true, |
60 | - helpMessage: ['选择设备配置,自动关联设备类型'], | |
60 | + helpMessage: ['选择所属产品,自动关联设备类型'], | |
61 | 61 | componentProps: { |
62 | 62 | placeholder: '设备类型', |
63 | 63 | api: findDictItemByCode, | ... | ... |
... | ... | @@ -103,6 +103,21 @@ |
103 | 103 | <template #action="{ record }"> |
104 | 104 | <TableAction |
105 | 105 | :actions="[ |
106 | + { | |
107 | + label: '详情', | |
108 | + icon: 'ant-design:eye-outlined', | |
109 | + auth: 'api:yt:device:get', | |
110 | + onClick: handleDetail.bind(null, record), | |
111 | + }, | |
112 | + { | |
113 | + label: '编辑', | |
114 | + auth: 'api:yt:device:update', | |
115 | + icon: 'clarity:note-edit-line', | |
116 | + ifShow: authBtn(role) && record.customerId === undefined, | |
117 | + onClick: handleEdit.bind(null, record), | |
118 | + }, | |
119 | + ]" | |
120 | + :dropDownActions="[ | |
106 | 121 | record.customerId |
107 | 122 | ? { |
108 | 123 | label: '取消分配', |
... | ... | @@ -119,20 +134,6 @@ |
119 | 134 | ifShow: authBtn(role), |
120 | 135 | onClick: handleDispatchCustomer.bind(null, record), |
121 | 136 | }, |
122 | - | |
123 | - { | |
124 | - label: '详情', | |
125 | - icon: 'ant-design:eye-outlined', | |
126 | - auth: 'api:yt:device:get', | |
127 | - onClick: handleDetail.bind(null, record), | |
128 | - }, | |
129 | - { | |
130 | - label: '编辑', | |
131 | - auth: 'api:yt:device:update', | |
132 | - icon: 'clarity:note-edit-line', | |
133 | - ifShow: authBtn(role) && record.customerId === undefined, | |
134 | - onClick: handleEdit.bind(null, record), | |
135 | - }, | |
136 | 137 | { |
137 | 138 | label: '删除', |
138 | 139 | auth: 'api:yt:device:delete', |
... | ... | @@ -235,7 +236,7 @@ |
235 | 236 | searchInfo: searchInfo, |
236 | 237 | clickToRowSelect: false, |
237 | 238 | actionColumn: { |
238 | - width: 300, | |
239 | + width: 200, | |
239 | 240 | title: '操作', |
240 | 241 | slots: { customRender: 'action' }, |
241 | 242 | fixed: 'right', | ... | ... |
1 | +<template> | |
2 | + <BasicDrawer v-bind="$attrs" title="产品详情" @register="register" width="50%"> | |
3 | + <Tabs :animated="true" v-model:activeKey="activeKey"> | |
4 | + <TabPane forceRender key="1" tab="产品"> | |
5 | + <div class="relative"> | |
6 | + <DeviceConfigurationStep :ifShowBtn="false" ref="DevConStRef" /> | |
7 | + <div class="absolute w-full h-full top-0 cursor-not-allowed"></div> | |
8 | + </div> | |
9 | + </TabPane> | |
10 | + <TabPane forceRender key="2" tab="传输配置"> | |
11 | + <div class="relative"> | |
12 | + <TransportConfigurationStep :ifShowBtn="false" ref="TransConStRef" /> | |
13 | + <div class="absolute w-full h-full top-0 cursor-not-allowed"></div> | |
14 | + </div> | |
15 | + </TabPane> | |
16 | + <TabPane forceRender key="3" tab="物模型管理"> | |
17 | + <PhysicalModelManagementStep /> | |
18 | + </TabPane> | |
19 | + </Tabs> | |
20 | + </BasicDrawer> | |
21 | +</template> | |
22 | +<script lang="ts" setup> | |
23 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
24 | + import { Tabs, TabPane } from 'ant-design-vue'; | |
25 | + import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; | |
26 | + import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; | |
27 | + import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue'; | |
28 | + import { ref, unref } from 'vue'; | |
29 | + import { deviceConfigGetDetail } from '/@/api/device/deviceConfigApi'; | |
30 | + | |
31 | + defineEmits(['register']); | |
32 | + | |
33 | + const activeKey = ref('1'); | |
34 | + | |
35 | + const DevConStRef = ref<InstanceType<typeof DeviceConfigurationStep>>(); | |
36 | + const TransConStRef = ref<InstanceType<typeof TransportConfigurationStep>>(); | |
37 | + // const PhysicalModManRef = ref<InstanceType<typeof PhysicalModelManagementStep>>(); | |
38 | + | |
39 | + const setDeviceConfFormData = async (res: Recordable) => { | |
40 | + unref(DevConStRef)?.setFormData(res); | |
41 | + }; | |
42 | + const setTransConfFormData = async (res: Recordable) => { | |
43 | + unref(TransConStRef)?.setFormData(res); | |
44 | + }; | |
45 | + | |
46 | + const [register, {}] = useDrawerInner(async (data: Recordable) => { | |
47 | + activeKey.value = '1'; | |
48 | + const res = await deviceConfigGetDetail(data.record.id); | |
49 | + setDeviceConfFormData(res); | |
50 | + setTransConfFormData(res); | |
51 | + }); | |
52 | +</script> | |
53 | + | |
54 | +<style lang="less" scope></style> | ... | ... |
... | ... | @@ -33,7 +33,7 @@ |
33 | 33 | :size="size" |
34 | 34 | @change="handleChange" |
35 | 35 | > |
36 | - <TabPane forceRender key="1" tab="设备配置"> | |
36 | + <TabPane forceRender key="1" tab="产品"> | |
37 | 37 | <div class="relative"> |
38 | 38 | <DeviceConfigurationStep |
39 | 39 | :ifShowBtn="isViewDetail ? false : true" |
... | ... | @@ -109,7 +109,7 @@ |
109 | 109 | isEditCreatTime.value = data.record !== undefined ? data.record.createTime : null; |
110 | 110 | if (!unref(isViewDetail)) { |
111 | 111 | dynamicWidth.value = 55 + 'rem'; |
112 | - const title = !unref(isUpdate) ? '编辑设备配置' : '新增设备配置'; | |
112 | + const title = !unref(isUpdate) ? '编辑产品' : '新增产品'; | |
113 | 113 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); |
114 | 114 | if (!unref(isUpdate)) { |
115 | 115 | await setDeviceConfEditFormData(res); |
... | ... | @@ -118,7 +118,7 @@ |
118 | 118 | } |
119 | 119 | } else { |
120 | 120 | dynamicWidth.value = 60 + 'rem'; |
121 | - setModalProps({ showOkBtn: false, showCancelBtn: false, title: '设备配置详情' }); | |
121 | + setModalProps({ showOkBtn: false, showCancelBtn: false, title: '产品详情' }); | |
122 | 122 | await setDeviceConfEditFormData(res); |
123 | 123 | await setTransConfEditFormData(res); |
124 | 124 | handleStepNext(false, res); | ... | ... |
... | ... | @@ -8,11 +8,11 @@ |
8 | 8 | > |
9 | 9 | <template #toolbar> |
10 | 10 | <Authority value="api:yt:deviceProfile:post"> |
11 | - <a-button type="primary" @click="handleCreate"> 新增设备配置 </a-button> | |
11 | + <a-button type="primary" @click="handleCreate"> 新增产品 </a-button> | |
12 | 12 | </Authority> |
13 | 13 | <Authority value="api:yt:deviceProfile:import"> |
14 | 14 | <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> |
15 | - <a-button @click="handleImport"> 导入设备配置 </a-button> | |
15 | + <a-button @click="handleImport"> 导入产品 </a-button> | |
16 | 16 | </ImpExcel> |
17 | 17 | </Authority> |
18 | 18 | <Authority value="api:yt:deviceProfile:delete"> |
... | ... | @@ -42,14 +42,6 @@ |
42 | 42 | <TableAction |
43 | 43 | :actions="[ |
44 | 44 | { |
45 | - label: '默认', | |
46 | - icon: 'ant-design:profile-outlined', | |
47 | - onClick: handleSetDefault.bind(null, record), | |
48 | - ifShow: () => { | |
49 | - return record.default === false; | |
50 | - }, | |
51 | - }, | |
52 | - { | |
53 | 45 | label: '详情', |
54 | 46 | auth: 'api:yt:deviceProfile:get', |
55 | 47 | icon: 'ant-design:eye-outlined', |
... | ... | @@ -64,6 +56,16 @@ |
64 | 56 | return record.name !== 'default' ? true : false; |
65 | 57 | }, |
66 | 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 | + }, | |
67 | 69 | { |
68 | 70 | label: '导出', |
69 | 71 | auth: 'api:yt:deviceProfile:export', |
... | ... | @@ -88,6 +90,7 @@ |
88 | 90 | </template> |
89 | 91 | </BasicTable> |
90 | 92 | <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> |
93 | + <DeviceProfileDrawer @register="registerDrawer" /> | |
91 | 94 | <ExpExcelModal |
92 | 95 | ref="expExcelModalRef" |
93 | 96 | @register="registerExportModal" |
... | ... | @@ -106,12 +109,14 @@ |
106 | 109 | setDeviceProfileIsDefaultApi, |
107 | 110 | } from '/@/api/device/deviceConfigApi'; |
108 | 111 | import { useModal } from '/@/components/Modal'; |
112 | + import { useDrawer } from '/@/components/Drawer'; | |
109 | 113 | import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; |
110 | 114 | import { ImpExcel, ExcelData } from '/@/components/Excel'; |
111 | 115 | import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; |
112 | 116 | import { Authority } from '/@/components/Authority'; |
113 | 117 | import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; |
114 | 118 | import { Popconfirm } from 'ant-design-vue'; |
119 | + import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | |
115 | 120 | |
116 | 121 | const exportData: any = ref([]); |
117 | 122 | const expExcelModalRef: any = ref(null); |
... | ... | @@ -124,7 +129,7 @@ |
124 | 129 | const [registerModal, { openModal }] = useModal(); |
125 | 130 | const [registerExportModal, { openModal: openModalExcel }] = useModal(); |
126 | 131 | const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ |
127 | - title: '设备配置列表', | |
132 | + title: '产品列表', | |
128 | 133 | clickToRowSelect: false, |
129 | 134 | api: deviceConfigGetQuery, |
130 | 135 | immediate: immediateStatus.value, |
... | ... | @@ -139,7 +144,7 @@ |
139 | 144 | bordered: true, |
140 | 145 | showIndexColumn: false, |
141 | 146 | actionColumn: { |
142 | - width: 240, | |
147 | + width: 200, | |
143 | 148 | title: '操作', |
144 | 149 | dataIndex: 'action', |
145 | 150 | slots: { customRender: 'action' }, |
... | ... | @@ -251,13 +256,16 @@ |
251 | 256 | isView: false, |
252 | 257 | }); |
253 | 258 | } |
259 | + | |
260 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
254 | 261 | //详情 |
255 | 262 | function handleDetailView(record: Recordable) { |
256 | - openModal(true, { | |
257 | - record, | |
258 | - isUpdate: false, | |
259 | - isView: true, | |
260 | - }); | |
263 | + openDrawer(true, { record }); | |
264 | + // openModal(true, { | |
265 | + // record, | |
266 | + // isUpdate: false, | |
267 | + // isView: true, | |
268 | + // }); | |
261 | 269 | } |
262 | 270 | |
263 | 271 | function defaultHeader({ filename, bookType }: ExportModalResult) { |
... | ... | @@ -295,8 +303,8 @@ |
295 | 303 | const handleSetDefault = async (record: Recordable) => { |
296 | 304 | let id = record.tbProfileId; |
297 | 305 | const data = await setDeviceProfileIsDefaultApi(id, 'default', defaultObj); |
298 | - if (!data) return createMessage.error('设置该设备配置为默认失败'); | |
299 | - createMessage.success('设置该设备配置为默认成功'); | |
306 | + if (!data) return createMessage.error('设置该产品为默认失败'); | |
307 | + createMessage.success('设置该产品为默认成功'); | |
300 | 308 | reload(); |
301 | 309 | disabled.value = true; |
302 | 310 | }; | ... | ... |
1 | 1 | <template> |
2 | - <div style="background-color: #f0f2f5"> | |
3 | - <BasicTable @register="registerTable"> | |
2 | + <div style="background-color: #f0f2f5" class="dark:bg-dark-900"> | |
3 | + <BasicTable @register="registerTable" class="dark:bg-dark-900"> | |
4 | 4 | <template #toolbar> |
5 | 5 | <Authority value="api:yt:smsLog:export"> |
6 | 6 | <a-button type="primary" @click="handleCreate"> 导出 </a-button> | ... | ... |
1 | 1 | <template> |
2 | - <div style="background-color: #f0f2f5"> | |
3 | - <BasicTable @register="registerTable"> | |
2 | + <div style="background-color: #f0f2f5" class="dark:bg-dark-900"> | |
3 | + <BasicTable @register="registerTable" class="dark:bg-dark-900"> | |
4 | 4 | <template #toolbar> |
5 | 5 | <Authority value="api:yt:smsLog:export"> |
6 | 6 | <a-button type="primary" @click="handleExport"> 导出 </a-button> | ... | ... |
... | ... | @@ -103,15 +103,15 @@ export const formSchema: FormSchema[] = [ |
103 | 103 | }, |
104 | 104 | { |
105 | 105 | field: PackageField.DEVICE_PROFILE_INFO, |
106 | - label: '设备配置', | |
106 | + label: '所属产品', | |
107 | 107 | component: 'ApiSearchSelect', |
108 | 108 | helpMessage: ['上传的包仅适用于具有所选配置文件的设备'], |
109 | 109 | defaultValue: 'default', |
110 | - rules: [{ required: true, message: '设备配置为必填项' }], | |
110 | + rules: [{ required: true, message: '所属产品为必填项' }], | |
111 | 111 | componentProps: ({ formActionType }) => { |
112 | 112 | const { setFieldsValue } = formActionType; |
113 | 113 | return { |
114 | - placeholder: '请选择设备配置', | |
114 | + placeholder: '请选择所属产品', | |
115 | 115 | showSearch: true, |
116 | 116 | resultField: 'data', |
117 | 117 | labelField: 'name', |
... | ... | @@ -137,7 +137,7 @@ export const formSchema: FormSchema[] = [ |
137 | 137 | field: PackageField.PACKAGE_TYPE, |
138 | 138 | label: '包类型', |
139 | 139 | component: 'Select', |
140 | - helpMessage: ['上传包后,您将无法修改标题、版本、设备配置文件和包类型'], | |
140 | + helpMessage: ['上传包后,您将无法修改标题、版本、产品文件和包类型'], | |
141 | 141 | defaultValue: PackageType.FIRMWARE, |
142 | 142 | rules: [{ required: true, message: '包类型为必填项' }], |
143 | 143 | componentProps: () => { |
... | ... | @@ -146,7 +146,7 @@ export const formSchema: FormSchema[] = [ |
146 | 146 | { label: '固件', value: PackageType.FIRMWARE }, |
147 | 147 | { label: '软件', value: PackageType.SOFTWARE }, |
148 | 148 | ], |
149 | - placeholder: '请选择设备配置', | |
149 | + placeholder: '请选择所属产品', | |
150 | 150 | }; |
151 | 151 | }, |
152 | 152 | }, | ... | ... |
... | ... | @@ -21,7 +21,7 @@ export const formSchema: FormSchema[] = [ |
21 | 21 | }, |
22 | 22 | { |
23 | 23 | field: PackageField.DEVICE_PROFILE_INFO, |
24 | - label: '设备配置', | |
24 | + label: '所属产品', | |
25 | 25 | component: 'Input', |
26 | 26 | }, |
27 | 27 | { |
... | ... | @@ -35,7 +35,7 @@ export const formSchema: FormSchema[] = [ |
35 | 35 | { label: '固件', value: PackageType.FIRMWARE }, |
36 | 36 | { label: '软件', value: PackageType.SOFTWARE }, |
37 | 37 | ], |
38 | - placeholder: '请选择设备配置', | |
38 | + placeholder: '请选择所属产品', | |
39 | 39 | }; |
40 | 40 | }, |
41 | 41 | }, | ... | ... |
... | ... | @@ -60,7 +60,8 @@ |
60 | 60 | converScriptRef.value?.setFormData(data.record); |
61 | 61 | } |
62 | 62 | if (unref(isTitle) == 'test') { |
63 | - converScriptRef.value?.setScriptContentData(''); | |
63 | + // converScriptRef.value?.setScriptContentData(''); | |
64 | + converScriptRef.value?.setFormData(data.record); | |
64 | 65 | } |
65 | 66 | setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText }); |
66 | 67 | if (!unref(isUpdate)) { | ... | ... |
... | ... | @@ -45,7 +45,14 @@ |
45 | 45 | |
46 | 46 | .widget-select:deep(.ant-card-body) { |
47 | 47 | /* height: 240px; */ |
48 | - width: 240px; | |
48 | + | |
49 | + /* width: 236px; | |
50 | + height: 196px; */ | |
51 | + | |
52 | + /* width: 100%; | |
53 | + height: 100%; */ | |
54 | + width: 236px; | |
55 | + height: 236px; | |
49 | 56 | padding: 0; |
50 | 57 | box-sizing: border-box; |
51 | 58 | display: flex; |
... | ... | @@ -64,10 +71,18 @@ |
64 | 71 | } |
65 | 72 | |
66 | 73 | .widget-select .widget-container { |
67 | - width: 240px; | |
68 | - height: 200px; | |
74 | + width: 236px; | |
75 | + height: 196px; | |
69 | 76 | display: flex; |
70 | 77 | justify-content: center; |
71 | 78 | align-items: center; |
72 | 79 | } |
80 | + | |
81 | + [data-theme='dark'] .widget-select:deep(.ant-card-body) { | |
82 | + @apply bg-dark-900; | |
83 | + } | |
84 | + | |
85 | + [data-theme='dark'] .widget-select:deep(.ant-card) { | |
86 | + @apply border-dark-300; | |
87 | + } | |
73 | 88 | </style> | ... | ... |
... | ... | @@ -565,6 +565,10 @@ |
565 | 565 | background-color: #fff; |
566 | 566 | } |
567 | 567 | |
568 | + [data-theme='dark'] .board-detail:deep(.ant-page-header-heading) { | |
569 | + @apply bg-dark-900; | |
570 | + } | |
571 | + | |
568 | 572 | .board-detail:deep(.ant-page-header-heading-extra) { |
569 | 573 | margin: 0; |
570 | 574 | line-height: 78px; | ... | ... |
... | ... | @@ -189,13 +189,13 @@ |
189 | 189 | |
190 | 190 | <template> |
191 | 191 | <PageWrapper> |
192 | - <div class="flex items-center mb-3 bg-light-100 h-78px"> | |
192 | + <div class="flex items-center mb-3 bg-light-100 h-78px dark:text-gray-300 dark:bg-dark-900"> | |
193 | 193 | <div class="text-lg ml-30px mr-9px font-bold">自定义看板</div> |
194 | 194 | <Authority value="api:yt:data_board:add:post"> |
195 | 195 | <Button type="primary" @click="handleOpenDetailModal">创建看板</Button> |
196 | 196 | </Authority> |
197 | 197 | </div> |
198 | - <div class="bg-light-100 mb-6 w-full p-3 search-form"> | |
198 | + <div class="bg-light-100 mb-6 w-full p-3 search-form dark:text-gray-300 dark:bg-dark-900"> | |
199 | 199 | <BasicForm class="flex-auto w-full" @register="searchFormRegister" /> |
200 | 200 | </div> |
201 | 201 | <Spin :spinning="loading"> |
... | ... | @@ -309,4 +309,9 @@ |
309 | 309 | padding: 10px; |
310 | 310 | background-color: #fff; |
311 | 311 | } |
312 | + | |
313 | + [data-theme='dark'] .data-board-list:deep(.ant-list-pagination) { | |
314 | + padding: 10px; | |
315 | + background-color: #000; | |
316 | + } | |
312 | 317 | </style> | ... | ... |