Showing
37 changed files
with
729 additions
and
289 deletions
| 1 | import { defHttp } from '/@/utils/http/axios'; | 1 | import { defHttp } from '/@/utils/http/axios'; |
| 2 | import type { | 2 | import type { |
| 3 | queryPageParams, | 3 | queryPageParams, |
| 4 | - ConfigurationModal, | ||
| 5 | ConfigurationCenterParams, | 4 | ConfigurationCenterParams, |
| 6 | ConfigurationCenterInfo, | 5 | ConfigurationCenterInfo, |
| 6 | + ConfigurationCenterItemsModal, | ||
| 7 | } from './model/configurationCenterModal'; | 7 | } from './model/configurationCenterModal'; |
| 8 | import { getPageData } from '../../base'; | 8 | import { getPageData } from '../../base'; |
| 9 | enum API { | 9 | enum API { |
| @@ -11,7 +11,7 @@ enum API { | @@ -11,7 +11,7 @@ enum API { | ||
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | export const getPage = (params: queryPageParams) => { | 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 | export const saveConfigurationCenter = (params: ConfigurationCenterParams) => { | 17 | export const saveConfigurationCenter = (params: ConfigurationCenterParams) => { |
| 1 | import { BasicPageParams } from '/@/api/model/baseModel'; | 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 | id: string; | 4 | id: string; |
| 6 | name: string; | 5 | name: string; |
| 7 | createTime: string; | 6 | createTime: string; |
| 8 | creator: string; | 7 | creator: string; |
| 9 | remark: string; | 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 | export interface ConfigurationModal { | 15 | export interface ConfigurationModal { |
| 14 | items: ConfigurationCenterItemsModal[]; | 16 | items: ConfigurationCenterItemsModal[]; |
| @@ -47,8 +47,8 @@ export default defineComponent({ | @@ -47,8 +47,8 @@ export default defineComponent({ | ||
| 47 | const { | 47 | const { |
| 48 | getContentMode, | 48 | getContentMode, |
| 49 | getShowFooter, | 49 | getShowFooter, |
| 50 | - getShowBreadCrumb, | ||
| 51 | - getShowBreadCrumbIcon, | 50 | + // getShowBreadCrumb, |
| 51 | + // getShowBreadCrumbIcon, | ||
| 52 | getShowLogo, | 52 | getShowLogo, |
| 53 | getFullContent, | 53 | getFullContent, |
| 54 | getColorWeak, | 54 | getColorWeak, |
| @@ -281,7 +281,7 @@ export default defineComponent({ | @@ -281,7 +281,7 @@ export default defineComponent({ | ||
| 281 | function renderContent() { | 281 | function renderContent() { |
| 282 | return ( | 282 | return ( |
| 283 | <> | 283 | <> |
| 284 | - <SwitchItem | 284 | + {/* <SwitchItem |
| 285 | title={t('layout.setting.breadcrumb')} | 285 | title={t('layout.setting.breadcrumb')} |
| 286 | event={HandlerEnum.SHOW_BREADCRUMB} | 286 | event={HandlerEnum.SHOW_BREADCRUMB} |
| 287 | def={unref(getShowBreadCrumb)} | 287 | def={unref(getShowBreadCrumb)} |
| @@ -299,7 +299,7 @@ export default defineComponent({ | @@ -299,7 +299,7 @@ export default defineComponent({ | ||
| 299 | title={t('layout.setting.tabs')} | 299 | title={t('layout.setting.tabs')} |
| 300 | event={HandlerEnum.TABS_SHOW} | 300 | event={HandlerEnum.TABS_SHOW} |
| 301 | def={unref(getShowMultipleTab)} | 301 | def={unref(getShowMultipleTab)} |
| 302 | - /> | 302 | + /> */} |
| 303 | 303 | ||
| 304 | <SwitchItem | 304 | <SwitchItem |
| 305 | title={t('layout.setting.tabsRedoBtn')} | 305 | title={t('layout.setting.tabsRedoBtn')} |
| @@ -250,7 +250,7 @@ export const DeviceProfileIdMaxLength: Rule[] = [ | @@ -250,7 +250,7 @@ export const DeviceProfileIdMaxLength: Rule[] = [ | ||
| 250 | required: true, | 250 | required: true, |
| 251 | validator: (_, value: string) => { | 251 | validator: (_, value: string) => { |
| 252 | if (String(value).length > 36) { | 252 | if (String(value).length > 36) { |
| 253 | - return Promise.reject('设备配置长度不超过36字'); | 253 | + return Promise.reject('所属产品长度不超过36字'); |
| 254 | } | 254 | } |
| 255 | return Promise.resolve(); | 255 | return Promise.resolve(); |
| 256 | }, | 256 | }, |
| @@ -22,8 +22,8 @@ export enum AlarmPermissionKey { | @@ -22,8 +22,8 @@ export enum AlarmPermissionKey { | ||
| 22 | export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { | 22 | export function useAlarmNotify(params: UseAlarmNotifyParams = {}) { |
| 23 | const { | 23 | const { |
| 24 | alarmNotifyStatus = AlarmStatus.ACTIVE_UN_ACK, | 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 | color = 'orange', | 27 | color = 'orange', |
| 28 | } = params; | 28 | } = params; |
| 29 | const alarmNotifyStatusMean = AlarmStatusMean[alarmNotifyStatus]; | 29 | const alarmNotifyStatusMean = AlarmStatusMean[alarmNotifyStatus]; |
| @@ -59,6 +59,8 @@ | @@ -59,6 +59,8 @@ | ||
| 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 | }, |
| 62 | + ]" | ||
| 63 | + :drop-down-actions="[ | ||
| 62 | { | 64 | { |
| 63 | label: '删除', | 65 | label: '删除', |
| 64 | auth: 'api:yt:video:delete', | 66 | auth: 'api:yt:video:delete', |
| 1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
| 2 | import { PageWrapper } from '/@/components/Page'; | 2 | import { PageWrapper } from '/@/components/Page'; |
| 3 | import OrganizationIdTree from '../../common/organizationIdTree/src/OrganizationIdTree.vue'; | 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 | import { cameraPage } from '/@/api/camera/cameraManager'; | 6 | import { cameraPage } from '/@/api/camera/cameraManager'; |
| 7 | import { CameraRecord } from '/@/api/camera/model/cameraModel'; | 7 | import { CameraRecord } from '/@/api/camera/model/cameraModel'; |
| 8 | import { videoPlay as VideoPlay } from 'vue3-video-play'; | 8 | import { videoPlay as VideoPlay } from 'vue3-video-play'; |
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; | 14 | import SvgIcon from '/@/components/Icon/src/SvgIcon.vue'; |
| 15 | import { isDef } from '/@/utils/is'; | 15 | import { isDef } from '/@/utils/is'; |
| 16 | import { getStreamingPlayUrl } from '/@/api/camera/cameraManager'; | 16 | import { getStreamingPlayUrl } from '/@/api/camera/cameraManager'; |
| 17 | + import { buildUUID } from '/@/utils/uuid'; | ||
| 17 | 18 | ||
| 18 | type CameraRecordItem = CameraRecord & { | 19 | type CameraRecordItem = CameraRecord & { |
| 19 | canPlay?: boolean; | 20 | canPlay?: boolean; |
| @@ -67,15 +68,11 @@ | @@ -67,15 +68,11 @@ | ||
| 67 | getCameraList(); | 68 | getCameraList(); |
| 68 | }; | 69 | }; |
| 69 | 70 | ||
| 70 | - const getColLayout = computed(() => { | ||
| 71 | - const totalSpan = 24; | ||
| 72 | - return totalSpan / pagination.colNumber; | ||
| 73 | - }); | ||
| 74 | - | ||
| 75 | const getCameraList = async () => { | 71 | const getCameraList = async () => { |
| 76 | try { | 72 | try { |
| 73 | + cameraList.value = []; | ||
| 77 | loading.value = true; | 74 | loading.value = true; |
| 78 | - const { items, total } = await cameraPage({ | 75 | + let { items, total } = await cameraPage({ |
| 79 | page: pagination.page, | 76 | page: pagination.page, |
| 80 | pageSize: pagination.pageSize, | 77 | pageSize: pagination.pageSize, |
| 81 | organizationId: unref(organizationId)!, | 78 | organizationId: unref(organizationId)!, |
| @@ -87,6 +84,14 @@ | @@ -87,6 +84,14 @@ | ||
| 87 | (item as CameraRecordItem).isTransform = false; | 84 | (item as CameraRecordItem).isTransform = false; |
| 88 | beforeVideoPlay(item); | 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 | cameraList.value = items; | 95 | cameraList.value = items; |
| 91 | } catch (error) { | 96 | } catch (error) { |
| 92 | } finally { | 97 | } finally { |
| @@ -128,7 +133,10 @@ | @@ -128,7 +133,10 @@ | ||
| 128 | } | 133 | } |
| 129 | }; | 134 | }; |
| 130 | 135 | ||
| 136 | + const gridLayout = ref({ gutter: 1, column: 2 }); | ||
| 137 | + | ||
| 131 | const handleSwitchLayoutWay = (pageSize: number, layout: number) => { | 138 | const handleSwitchLayoutWay = (pageSize: number, layout: number) => { |
| 139 | + gridLayout.value = { gutter: 1, column: Math.sqrt(pageSize) }; | ||
| 132 | pagination.colNumber = layout; | 140 | pagination.colNumber = layout; |
| 133 | pagination.pageSize = pageSize; | 141 | pagination.pageSize = pageSize; |
| 134 | pagination.page = 1; | 142 | pagination.page = 1; |
| @@ -185,7 +193,7 @@ | @@ -185,7 +193,7 @@ | ||
| 185 | <PageWrapper dense contentFullHeight contentClass="flex"> | 193 | <PageWrapper dense contentFullHeight contentClass="flex"> |
| 186 | <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> | 194 | <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> |
| 187 | <section class="p-4 pl-9 split-screen-mode flex flex-col flex-auto w-3/4 xl:w-4/5"> | 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 | <div class="flex gap-4 cursor-pointer items-center"> | 197 | <div class="flex gap-4 cursor-pointer items-center"> |
| 190 | <div | 198 | <div |
| 191 | class="w-8 h-8 flex justify-center items-center" | 199 | class="w-8 h-8 flex justify-center items-center" |
| @@ -225,14 +233,67 @@ | @@ -225,14 +233,67 @@ | ||
| 225 | <div class="flex"> | 233 | <div class="flex"> |
| 226 | <Button type="primary" @click="handleAddCamera">新增视频</Button> | 234 | <Button type="primary" @click="handleAddCamera">新增视频</Button> |
| 227 | </div> | 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 | </div> | 247 | </div> |
| 234 | </div> | 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 | <Spin :spinning="loading" class="h-full"> | 297 | <Spin :spinning="loading" class="h-full"> |
| 237 | <Empty | 298 | <Empty |
| 238 | class="h-full flex flex-col justify-center items-center" | 299 | class="h-full flex flex-col justify-center items-center" |
| @@ -277,7 +338,7 @@ | @@ -277,7 +338,7 @@ | ||
| 277 | </Col> | 338 | </Col> |
| 278 | </Row> | 339 | </Row> |
| 279 | </Spin> | 340 | </Spin> |
| 280 | - </section> | 341 | + </section> --> |
| 281 | </section> | 342 | </section> |
| 282 | </PageWrapper> | 343 | </PageWrapper> |
| 283 | <CameraDrawer @register="registerDrawer" @success="getCameraList" /> | 344 | <CameraDrawer @register="registerDrawer" @success="getCameraList" /> |
| @@ -334,4 +395,20 @@ | @@ -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 | </style> | 414 | </style> |
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | <div class="organization-tree flex relative"> | 2 | <div class="organization-tree flex relative"> |
| 3 | <div class="cursor-pointer flex py-4 fold-icon" :class="foldFlag ? 'absolute' : ''"> | 3 | <div class="cursor-pointer flex py-4 fold-icon" :class="foldFlag ? 'absolute' : ''"> |
| 4 | <div @click="handleFold"> | 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 | </div> | 6 | </div> |
| 7 | </div> | 7 | </div> |
| 8 | <div | 8 | <div |
| @@ -29,7 +29,7 @@ | @@ -29,7 +29,7 @@ | ||
| 29 | import { onMounted, ref, unref } from 'vue'; | 29 | import { onMounted, ref, unref } from 'vue'; |
| 30 | import { BasicTree, TreeItem } from '/@/components/Tree'; | 30 | import { BasicTree, TreeItem } from '/@/components/Tree'; |
| 31 | import { getOrganizationList } from '/@/api/system/system'; | 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 | const emit = defineEmits(['select']); | 34 | const emit = defineEmits(['select']); |
| 35 | const treeData = ref<TreeItem[]>([]); | 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 | import { | 12 | import { |
| 83 | - getPage, | ||
| 84 | deleteConfigurationCenter, | 13 | deleteConfigurationCenter, |
| 14 | + getPage, | ||
| 85 | } from '/@/api/configuration/center/configurationCenter'; | 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 | import { Authority } from '/@/components/Authority'; | 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 | </script> | 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,7 +206,7 @@ | ||
| 206 | target: '_blank ', | 206 | target: '_blank ', |
| 207 | }, | 207 | }, |
| 208 | { | 208 | { |
| 209 | - title: '什么是设备配置?', | 209 | + title: '什么是产品?', |
| 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', | 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 | target: '_blank ', | 211 | target: '_blank ', |
| 212 | }, | 212 | }, |
| @@ -51,8 +51,8 @@ | @@ -51,8 +51,8 @@ | ||
| 51 | series: [ | 51 | series: [ |
| 52 | { | 52 | { |
| 53 | name: '告警数', | 53 | name: '告警数', |
| 54 | - barWidth: '10%', | ||
| 55 | - type: 'bar', | 54 | + // barWidth: '10%', |
| 55 | + type: 'line', | ||
| 56 | stack: 'Total', | 56 | stack: 'Total', |
| 57 | data: props.alarmList, | 57 | data: props.alarmList, |
| 58 | color: '#3C78FF', | 58 | color: '#3C78FF', |
| @@ -63,6 +63,7 @@ | @@ -63,6 +63,7 @@ | ||
| 63 | watch( | 63 | watch( |
| 64 | () => props.alarmList, | 64 | () => props.alarmList, |
| 65 | (newValue) => { | 65 | (newValue) => { |
| 66 | + console.log({ newValue, props }); | ||
| 66 | let alarmTotal = 0; | 67 | let alarmTotal = 0; |
| 67 | for (const item of props.alarmList) { | 68 | for (const item of props.alarmList) { |
| 68 | alarmTotal += Number(item[1]); | 69 | alarmTotal += Number(item[1]); |
| @@ -91,10 +92,10 @@ | @@ -91,10 +92,10 @@ | ||
| 91 | series: [ | 92 | series: [ |
| 92 | { | 93 | { |
| 93 | name: '告警数', | 94 | name: '告警数', |
| 94 | - type: 'bar', | 95 | + type: 'line', |
| 95 | stack: 'Total', | 96 | stack: 'Total', |
| 96 | color: '#3C78FF', | 97 | color: '#3C78FF', |
| 97 | - barWidth: '10%', | 98 | + // barWidth: '10%', |
| 98 | data: newValue, | 99 | data: newValue, |
| 99 | }, | 100 | }, |
| 100 | ], | 101 | ], |
| @@ -63,17 +63,17 @@ | @@ -63,17 +63,17 @@ | ||
| 63 | series: [ | 63 | series: [ |
| 64 | { | 64 | { |
| 65 | name: '传输数据点', | 65 | name: '传输数据点', |
| 66 | - type: 'bar', | 66 | + type: 'line', |
| 67 | stack: 'total', | 67 | stack: 'total', |
| 68 | data: newValue, | 68 | data: newValue, |
| 69 | - barWidth: '10%', | 69 | + // barWidth: '10%', |
| 70 | color: '#5AEEED', | 70 | color: '#5AEEED', |
| 71 | }, | 71 | }, |
| 72 | { | 72 | { |
| 73 | name: '传输消息量', | 73 | name: '传输消息量', |
| 74 | - type: 'bar', | 74 | + type: 'line', |
| 75 | stack: 'total', | 75 | stack: 'total', |
| 76 | - barWidth: '10%', | 76 | + // barWidth: '10%', |
| 77 | data: newValue1, | 77 | data: newValue1, |
| 78 | color: '#3C78FF', | 78 | color: '#3C78FF', |
| 79 | }, | 79 | }, |
| @@ -35,7 +35,7 @@ export const step1Schemas: FormSchema[] = [ | @@ -35,7 +35,7 @@ export const step1Schemas: FormSchema[] = [ | ||
| 35 | }, | 35 | }, |
| 36 | { | 36 | { |
| 37 | field: 'profileId', | 37 | field: 'profileId', |
| 38 | - label: '设备配置', | 38 | + label: '所属产品', |
| 39 | required: true, | 39 | required: true, |
| 40 | component: 'ApiSelect', | 40 | component: 'ApiSelect', |
| 41 | componentProps: ({ formActionType }) => { | 41 | componentProps: ({ formActionType }) => { |
| @@ -57,7 +57,7 @@ export const step1Schemas: FormSchema[] = [ | @@ -57,7 +57,7 @@ export const step1Schemas: FormSchema[] = [ | ||
| 57 | required: true, | 57 | required: true, |
| 58 | component: 'ApiSelect', | 58 | component: 'ApiSelect', |
| 59 | dynamicDisabled: true, | 59 | dynamicDisabled: true, |
| 60 | - helpMessage: ['选择设备配置,自动关联设备类型'], | 60 | + helpMessage: ['选择所属产品,自动关联设备类型'], |
| 61 | componentProps: { | 61 | componentProps: { |
| 62 | placeholder: '设备类型', | 62 | placeholder: '设备类型', |
| 63 | api: findDictItemByCode, | 63 | api: findDictItemByCode, |
| @@ -21,7 +21,7 @@ export const descSchema: DescItem[] = [ | @@ -21,7 +21,7 @@ export const descSchema: DescItem[] = [ | ||
| 21 | }, | 21 | }, |
| 22 | { | 22 | { |
| 23 | field: 'deviceProfile.name', | 23 | field: 'deviceProfile.name', |
| 24 | - label: '设备配置', | 24 | + label: '产品', |
| 25 | }, | 25 | }, |
| 26 | { | 26 | { |
| 27 | field: 'gatewayName', | 27 | field: 'gatewayName', |
| @@ -32,7 +32,7 @@ export const columns: BasicColumn[] = [ | @@ -32,7 +32,7 @@ export const columns: BasicColumn[] = [ | ||
| 32 | slots: { customRender: 'deviceType' }, | 32 | slots: { customRender: 'deviceType' }, |
| 33 | }, | 33 | }, |
| 34 | { | 34 | { |
| 35 | - title: '设备配置', | 35 | + title: '所属产品', |
| 36 | dataIndex: 'deviceProfile.name', | 36 | dataIndex: 'deviceProfile.name', |
| 37 | width: 160, | 37 | width: 160, |
| 38 | slots: { customRender: 'deviceProfile' }, | 38 | slots: { customRender: 'deviceProfile' }, |
| @@ -103,6 +103,21 @@ | @@ -103,6 +103,21 @@ | ||
| 103 | <template #action="{ record }"> | 103 | <template #action="{ record }"> |
| 104 | <TableAction | 104 | <TableAction |
| 105 | :actions="[ | 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 | record.customerId | 121 | record.customerId |
| 107 | ? { | 122 | ? { |
| 108 | label: '取消分配', | 123 | label: '取消分配', |
| @@ -119,20 +134,6 @@ | @@ -119,20 +134,6 @@ | ||
| 119 | ifShow: authBtn(role), | 134 | ifShow: authBtn(role), |
| 120 | onClick: handleDispatchCustomer.bind(null, record), | 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), | ||
| 134 | - onClick: handleEdit.bind(null, record), | ||
| 135 | - }, | ||
| 136 | { | 137 | { |
| 137 | label: '删除', | 138 | label: '删除', |
| 138 | auth: 'api:yt:device:delete', | 139 | auth: 'api:yt:device:delete', |
| @@ -235,7 +236,7 @@ | @@ -235,7 +236,7 @@ | ||
| 235 | searchInfo: searchInfo, | 236 | searchInfo: searchInfo, |
| 236 | clickToRowSelect: false, | 237 | clickToRowSelect: false, |
| 237 | actionColumn: { | 238 | actionColumn: { |
| 238 | - width: 300, | 239 | + width: 200, |
| 239 | title: '操作', | 240 | title: '操作', |
| 240 | slots: { customRender: 'action' }, | 241 | slots: { customRender: 'action' }, |
| 241 | fixed: 'right', | 242 | fixed: 'right', |
| @@ -33,7 +33,7 @@ export const formSchema: FormSchema[] = [ | @@ -33,7 +33,7 @@ export const formSchema: FormSchema[] = [ | ||
| 33 | component: 'ApiSelect', | 33 | component: 'ApiSelect', |
| 34 | componentProps: { | 34 | componentProps: { |
| 35 | api: getDeviceProfile, | 35 | api: getDeviceProfile, |
| 36 | - placeholder: '请选择设备配置', | 36 | + placeholder: '请选择产品', |
| 37 | labelField: 'name', | 37 | labelField: 'name', |
| 38 | valueField: 'id', | 38 | valueField: 'id', |
| 39 | }, | 39 | }, |
| 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,7 +33,7 @@ | ||
| 33 | :size="size" | 33 | :size="size" |
| 34 | @change="handleChange" | 34 | @change="handleChange" |
| 35 | > | 35 | > |
| 36 | - <TabPane forceRender key="1" tab="设备配置"> | 36 | + <TabPane forceRender key="1" tab="产品"> |
| 37 | <div class="relative"> | 37 | <div class="relative"> |
| 38 | <DeviceConfigurationStep | 38 | <DeviceConfigurationStep |
| 39 | :ifShowBtn="isViewDetail ? false : true" | 39 | :ifShowBtn="isViewDetail ? false : true" |
| @@ -109,7 +109,7 @@ | @@ -109,7 +109,7 @@ | ||
| 109 | isEditCreatTime.value = data.record !== undefined ? data.record.createTime : null; | 109 | isEditCreatTime.value = data.record !== undefined ? data.record.createTime : null; |
| 110 | if (!unref(isViewDetail)) { | 110 | if (!unref(isViewDetail)) { |
| 111 | dynamicWidth.value = 55 + 'rem'; | 111 | dynamicWidth.value = 55 + 'rem'; |
| 112 | - const title = !unref(isUpdate) ? '编辑设备配置' : '新增设备配置'; | 112 | + const title = !unref(isUpdate) ? '编辑产品' : '新增产品'; |
| 113 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); | 113 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); |
| 114 | if (!unref(isUpdate)) { | 114 | if (!unref(isUpdate)) { |
| 115 | await setDeviceConfEditFormData(res); | 115 | await setDeviceConfEditFormData(res); |
| @@ -118,7 +118,7 @@ | @@ -118,7 +118,7 @@ | ||
| 118 | } | 118 | } |
| 119 | } else { | 119 | } else { |
| 120 | dynamicWidth.value = 60 + 'rem'; | 120 | dynamicWidth.value = 60 + 'rem'; |
| 121 | - setModalProps({ showOkBtn: false, showCancelBtn: false, title: '设备配置详情' }); | 121 | + setModalProps({ showOkBtn: false, showCancelBtn: false, title: '产品详情' }); |
| 122 | await setDeviceConfEditFormData(res); | 122 | await setDeviceConfEditFormData(res); |
| 123 | await setTransConfEditFormData(res); | 123 | await setTransConfEditFormData(res); |
| 124 | handleStepNext(false, res); | 124 | handleStepNext(false, res); |
| @@ -10,7 +10,7 @@ import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; | @@ -10,7 +10,7 @@ import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; | ||
| 10 | 10 | ||
| 11 | export const steps = [ | 11 | export const steps = [ |
| 12 | { | 12 | { |
| 13 | - title: '设备配置', | 13 | + title: '产品', |
| 14 | content: 'First-content', | 14 | content: 'First-content', |
| 15 | }, | 15 | }, |
| 16 | { | 16 | { |
| @@ -8,11 +8,11 @@ | @@ -8,11 +8,11 @@ | ||
| 8 | > | 8 | > |
| 9 | <template #toolbar> | 9 | <template #toolbar> |
| 10 | <Authority value="api:yt:deviceProfile:post"> | 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 | </Authority> | 12 | </Authority> |
| 13 | <Authority value="api:yt:deviceProfile:import"> | 13 | <Authority value="api:yt:deviceProfile:import"> |
| 14 | <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> | 14 | <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> |
| 15 | - <a-button @click="handleImport"> 导入设备配置 </a-button> | 15 | + <a-button @click="handleImport"> 导入产品 </a-button> |
| 16 | </ImpExcel> | 16 | </ImpExcel> |
| 17 | </Authority> | 17 | </Authority> |
| 18 | <Authority value="api:yt:deviceProfile:delete"> | 18 | <Authority value="api:yt:deviceProfile:delete"> |
| @@ -42,14 +42,6 @@ | @@ -42,14 +42,6 @@ | ||
| 42 | <TableAction | 42 | <TableAction |
| 43 | :actions="[ | 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 | label: '详情', | 45 | label: '详情', |
| 54 | auth: 'api:yt:deviceProfile:get', | 46 | auth: 'api:yt:deviceProfile:get', |
| 55 | icon: 'ant-design:eye-outlined', | 47 | icon: 'ant-design:eye-outlined', |
| @@ -64,6 +56,16 @@ | @@ -64,6 +56,16 @@ | ||
| 64 | return record.name !== 'default' ? true : false; | 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 | label: '导出', | 70 | label: '导出', |
| 69 | auth: 'api:yt:deviceProfile:export', | 71 | auth: 'api:yt:deviceProfile:export', |
| @@ -88,6 +90,7 @@ | @@ -88,6 +90,7 @@ | ||
| 88 | </template> | 90 | </template> |
| 89 | </BasicTable> | 91 | </BasicTable> |
| 90 | <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> | 92 | <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> |
| 93 | + <DeviceProfileDrawer @register="registerDrawer" /> | ||
| 91 | <ExpExcelModal | 94 | <ExpExcelModal |
| 92 | ref="expExcelModalRef" | 95 | ref="expExcelModalRef" |
| 93 | @register="registerExportModal" | 96 | @register="registerExportModal" |
| @@ -106,12 +109,14 @@ | @@ -106,12 +109,14 @@ | ||
| 106 | setDeviceProfileIsDefaultApi, | 109 | setDeviceProfileIsDefaultApi, |
| 107 | } from '/@/api/device/deviceConfigApi'; | 110 | } from '/@/api/device/deviceConfigApi'; |
| 108 | import { useModal } from '/@/components/Modal'; | 111 | import { useModal } from '/@/components/Modal'; |
| 112 | + import { useDrawer } from '/@/components/Drawer'; | ||
| 109 | import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; | 113 | import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; |
| 110 | import { ImpExcel, ExcelData } from '/@/components/Excel'; | 114 | import { ImpExcel, ExcelData } from '/@/components/Excel'; |
| 111 | import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; | 115 | import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; |
| 112 | import { Authority } from '/@/components/Authority'; | 116 | import { Authority } from '/@/components/Authority'; |
| 113 | import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | 117 | import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; |
| 114 | import { Popconfirm } from 'ant-design-vue'; | 118 | import { Popconfirm } from 'ant-design-vue'; |
| 119 | + import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
| 115 | 120 | ||
| 116 | const exportData: any = ref([]); | 121 | const exportData: any = ref([]); |
| 117 | const expExcelModalRef: any = ref(null); | 122 | const expExcelModalRef: any = ref(null); |
| @@ -124,7 +129,7 @@ | @@ -124,7 +129,7 @@ | ||
| 124 | const [registerModal, { openModal }] = useModal(); | 129 | const [registerModal, { openModal }] = useModal(); |
| 125 | const [registerExportModal, { openModal: openModalExcel }] = useModal(); | 130 | const [registerExportModal, { openModal: openModalExcel }] = useModal(); |
| 126 | const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ | 131 | const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ |
| 127 | - title: '设备配置列表', | 132 | + title: '产品列表', |
| 128 | clickToRowSelect: false, | 133 | clickToRowSelect: false, |
| 129 | api: deviceConfigGetQuery, | 134 | api: deviceConfigGetQuery, |
| 130 | immediate: immediateStatus.value, | 135 | immediate: immediateStatus.value, |
| @@ -139,7 +144,7 @@ | @@ -139,7 +144,7 @@ | ||
| 139 | bordered: true, | 144 | bordered: true, |
| 140 | showIndexColumn: false, | 145 | showIndexColumn: false, |
| 141 | actionColumn: { | 146 | actionColumn: { |
| 142 | - width: 240, | 147 | + width: 200, |
| 143 | title: '操作', | 148 | title: '操作', |
| 144 | dataIndex: 'action', | 149 | dataIndex: 'action', |
| 145 | slots: { customRender: 'action' }, | 150 | slots: { customRender: 'action' }, |
| @@ -251,13 +256,16 @@ | @@ -251,13 +256,16 @@ | ||
| 251 | isView: false, | 256 | isView: false, |
| 252 | }); | 257 | }); |
| 253 | } | 258 | } |
| 259 | + | ||
| 260 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
| 254 | //详情 | 261 | //详情 |
| 255 | function handleDetailView(record: Recordable) { | 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 | function defaultHeader({ filename, bookType }: ExportModalResult) { | 271 | function defaultHeader({ filename, bookType }: ExportModalResult) { |
| @@ -295,8 +303,8 @@ | @@ -295,8 +303,8 @@ | ||
| 295 | const handleSetDefault = async (record: Recordable) => { | 303 | const handleSetDefault = async (record: Recordable) => { |
| 296 | let id = record.tbProfileId; | 304 | let id = record.tbProfileId; |
| 297 | const data = await setDeviceProfileIsDefaultApi(id, 'default', defaultObj); | 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 | reload(); | 308 | reload(); |
| 301 | disabled.value = true; | 309 | disabled.value = true; |
| 302 | }; | 310 | }; |
| @@ -151,7 +151,7 @@ | @@ -151,7 +151,7 @@ | ||
| 151 | showIndexColumn: false, | 151 | showIndexColumn: false, |
| 152 | clickToRowSelect: false, | 152 | clickToRowSelect: false, |
| 153 | useSearchForm: false, | 153 | useSearchForm: false, |
| 154 | - rowKey: 'id', | 154 | + // rowKey: 'id', |
| 155 | showTableSetting: true, | 155 | showTableSetting: true, |
| 156 | bordered: true, | 156 | bordered: true, |
| 157 | actionColumn: { | 157 | actionColumn: { |
| 1 | <template> | 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 | <template #toolbar> | 4 | <template #toolbar> |
| 5 | <Authority value="api:yt:smsLog:export"> | 5 | <Authority value="api:yt:smsLog:export"> |
| 6 | <a-button type="primary" @click="handleCreate"> 导出 </a-button> | 6 | <a-button type="primary" @click="handleCreate"> 导出 </a-button> |
| 1 | <template> | 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 | <template #toolbar> | 4 | <template #toolbar> |
| 5 | <Authority value="api:yt:smsLog:export"> | 5 | <Authority value="api:yt:smsLog:export"> |
| 6 | <a-button type="primary" @click="handleExport"> 导出 </a-button> | 6 | <a-button type="primary" @click="handleExport"> 导出 </a-button> |
| @@ -103,15 +103,15 @@ export const formSchema: FormSchema[] = [ | @@ -103,15 +103,15 @@ export const formSchema: FormSchema[] = [ | ||
| 103 | }, | 103 | }, |
| 104 | { | 104 | { |
| 105 | field: PackageField.DEVICE_PROFILE_INFO, | 105 | field: PackageField.DEVICE_PROFILE_INFO, |
| 106 | - label: '设备配置', | 106 | + label: '所属产品', |
| 107 | component: 'ApiSearchSelect', | 107 | component: 'ApiSearchSelect', |
| 108 | helpMessage: ['上传的包仅适用于具有所选配置文件的设备'], | 108 | helpMessage: ['上传的包仅适用于具有所选配置文件的设备'], |
| 109 | defaultValue: 'default', | 109 | defaultValue: 'default', |
| 110 | - rules: [{ required: true, message: '设备配置为必填项' }], | 110 | + rules: [{ required: true, message: '所属产品为必填项' }], |
| 111 | componentProps: ({ formActionType }) => { | 111 | componentProps: ({ formActionType }) => { |
| 112 | const { setFieldsValue } = formActionType; | 112 | const { setFieldsValue } = formActionType; |
| 113 | return { | 113 | return { |
| 114 | - placeholder: '请选择设备配置', | 114 | + placeholder: '请选择所属产品', |
| 115 | showSearch: true, | 115 | showSearch: true, |
| 116 | resultField: 'data', | 116 | resultField: 'data', |
| 117 | labelField: 'name', | 117 | labelField: 'name', |
| @@ -137,7 +137,7 @@ export const formSchema: FormSchema[] = [ | @@ -137,7 +137,7 @@ export const formSchema: FormSchema[] = [ | ||
| 137 | field: PackageField.PACKAGE_TYPE, | 137 | field: PackageField.PACKAGE_TYPE, |
| 138 | label: '包类型', | 138 | label: '包类型', |
| 139 | component: 'Select', | 139 | component: 'Select', |
| 140 | - helpMessage: ['上传包后,您将无法修改标题、版本、设备配置文件和包类型'], | 140 | + helpMessage: ['上传包后,您将无法修改标题、版本、产品文件和包类型'], |
| 141 | defaultValue: PackageType.FIRMWARE, | 141 | defaultValue: PackageType.FIRMWARE, |
| 142 | rules: [{ required: true, message: '包类型为必填项' }], | 142 | rules: [{ required: true, message: '包类型为必填项' }], |
| 143 | componentProps: () => { | 143 | componentProps: () => { |
| @@ -146,7 +146,7 @@ export const formSchema: FormSchema[] = [ | @@ -146,7 +146,7 @@ export const formSchema: FormSchema[] = [ | ||
| 146 | { label: '固件', value: PackageType.FIRMWARE }, | 146 | { label: '固件', value: PackageType.FIRMWARE }, |
| 147 | { label: '软件', value: PackageType.SOFTWARE }, | 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,7 +21,7 @@ export const formSchema: FormSchema[] = [ | ||
| 21 | }, | 21 | }, |
| 22 | { | 22 | { |
| 23 | field: PackageField.DEVICE_PROFILE_INFO, | 23 | field: PackageField.DEVICE_PROFILE_INFO, |
| 24 | - label: '设备配置', | 24 | + label: '所属产品', |
| 25 | component: 'Input', | 25 | component: 'Input', |
| 26 | }, | 26 | }, |
| 27 | { | 27 | { |
| @@ -35,7 +35,7 @@ export const formSchema: FormSchema[] = [ | @@ -35,7 +35,7 @@ export const formSchema: FormSchema[] = [ | ||
| 35 | { label: '固件', value: PackageType.FIRMWARE }, | 35 | { label: '固件', value: PackageType.FIRMWARE }, |
| 36 | { label: '软件', value: PackageType.SOFTWARE }, | 36 | { label: '软件', value: PackageType.SOFTWARE }, |
| 37 | ], | 37 | ], |
| 38 | - placeholder: '请选择设备配置', | 38 | + placeholder: '请选择所属产品', |
| 39 | }; | 39 | }; |
| 40 | }, | 40 | }, |
| 41 | }, | 41 | }, |
| @@ -32,6 +32,8 @@ | @@ -32,6 +32,8 @@ | ||
| 32 | onClick: handleEdit.bind(null, record), | 32 | onClick: handleEdit.bind(null, record), |
| 33 | ifShow: record.creator === userId && record.status !== 1, | 33 | ifShow: record.creator === userId && record.status !== 1, |
| 34 | }, | 34 | }, |
| 35 | + ]" | ||
| 36 | + :drop-down-actions="[ | ||
| 35 | { | 37 | { |
| 36 | label: '删除', | 38 | label: '删除', |
| 37 | auth: 'api:yt:sceneLinkage:delete', | 39 | auth: 'api:yt:sceneLinkage:delete', |
| @@ -60,7 +60,8 @@ | @@ -60,7 +60,8 @@ | ||
| 60 | converScriptRef.value?.setFormData(data.record); | 60 | converScriptRef.value?.setFormData(data.record); |
| 61 | } | 61 | } |
| 62 | if (unref(isTitle) == 'test') { | 62 | if (unref(isTitle) == 'test') { |
| 63 | - converScriptRef.value?.setScriptContentData(''); | 63 | + // converScriptRef.value?.setScriptContentData(''); |
| 64 | + converScriptRef.value?.setFormData(data.record); | ||
| 64 | } | 65 | } |
| 65 | setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText }); | 66 | setModalProps({ title, showOkBtn: true, showCancelBtn: true, okText }); |
| 66 | if (!unref(isUpdate)) { | 67 | if (!unref(isUpdate)) { |
| @@ -28,7 +28,7 @@ export const columns: BasicColumn[] = [ | @@ -28,7 +28,7 @@ export const columns: BasicColumn[] = [ | ||
| 28 | slots: { customRender: 'convertJs' }, | 28 | slots: { customRender: 'convertJs' }, |
| 29 | }, | 29 | }, |
| 30 | { | 30 | { |
| 31 | - title: '描述', | 31 | + title: '备注', |
| 32 | dataIndex: 'description', | 32 | dataIndex: 'description', |
| 33 | width: 120, | 33 | width: 120, |
| 34 | }, | 34 | }, |
| @@ -61,6 +61,8 @@ | @@ -61,6 +61,8 @@ | ||
| 61 | onClick: handleEdit.bind(null, record), | 61 | onClick: handleEdit.bind(null, record), |
| 62 | ifShow: record.level != 0, | 62 | ifShow: record.level != 0, |
| 63 | }, | 63 | }, |
| 64 | + ]" | ||
| 65 | + :drop-down-actions="[ | ||
| 64 | { | 66 | { |
| 65 | label: '删除', | 67 | label: '删除', |
| 66 | auth: 'api:yt:user:delete', | 68 | auth: 'api:yt:user:delete', |
| @@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
| 15 | </script> | 15 | </script> |
| 16 | 16 | ||
| 17 | <template> | 17 | <template> |
| 18 | - <section class="widget"> | 18 | + <section class="widget !dark:bg-dark-900"> |
| 19 | <slot name="header"></slot> | 19 | <slot name="header"></slot> |
| 20 | 20 | ||
| 21 | <div class="widget-content"> | 21 | <div class="widget-content"> |
| @@ -45,7 +45,14 @@ | @@ -45,7 +45,14 @@ | ||
| 45 | 45 | ||
| 46 | .widget-select:deep(.ant-card-body) { | 46 | .widget-select:deep(.ant-card-body) { |
| 47 | /* height: 240px; */ | 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 | padding: 0; | 56 | padding: 0; |
| 50 | box-sizing: border-box; | 57 | box-sizing: border-box; |
| 51 | display: flex; | 58 | display: flex; |
| @@ -64,10 +71,18 @@ | @@ -64,10 +71,18 @@ | ||
| 64 | } | 71 | } |
| 65 | 72 | ||
| 66 | .widget-select .widget-container { | 73 | .widget-select .widget-container { |
| 67 | - width: 240px; | ||
| 68 | - height: 200px; | 74 | + width: 236px; |
| 75 | + height: 196px; | ||
| 69 | display: flex; | 76 | display: flex; |
| 70 | justify-content: center; | 77 | justify-content: center; |
| 71 | align-items: center; | 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 | </style> | 88 | </style> |
| @@ -565,6 +565,10 @@ | @@ -565,6 +565,10 @@ | ||
| 565 | background-color: #fff; | 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 | .board-detail:deep(.ant-page-header-heading-extra) { | 572 | .board-detail:deep(.ant-page-header-heading-extra) { |
| 569 | margin: 0; | 573 | margin: 0; |
| 570 | line-height: 78px; | 574 | line-height: 78px; |
| @@ -189,13 +189,13 @@ | @@ -189,13 +189,13 @@ | ||
| 189 | 189 | ||
| 190 | <template> | 190 | <template> |
| 191 | <PageWrapper> | 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 | <div class="text-lg ml-30px mr-9px font-bold">自定义看板</div> | 193 | <div class="text-lg ml-30px mr-9px font-bold">自定义看板</div> |
| 194 | <Authority value="api:yt:data_board:add:post"> | 194 | <Authority value="api:yt:data_board:add:post"> |
| 195 | <Button type="primary" @click="handleOpenDetailModal">创建看板</Button> | 195 | <Button type="primary" @click="handleOpenDetailModal">创建看板</Button> |
| 196 | </Authority> | 196 | </Authority> |
| 197 | </div> | 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 | <BasicForm class="flex-auto w-full" @register="searchFormRegister" /> | 199 | <BasicForm class="flex-auto w-full" @register="searchFormRegister" /> |
| 200 | </div> | 200 | </div> |
| 201 | <Spin :spinning="loading"> | 201 | <Spin :spinning="loading"> |
| @@ -309,4 +309,9 @@ | @@ -309,4 +309,9 @@ | ||
| 309 | padding: 10px; | 309 | padding: 10px; |
| 310 | background-color: #fff; | 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 | </style> | 317 | </style> |