Commit ea33b4b91bc25be8ad2b15a8b2825e7436c959d7

Authored by xp.Huang
2 parents 690b31fc 292e0ae7

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[];
... ...
... ... @@ -12,5 +12,5 @@ export const PageEnum = {
12 12 //消息配置
13 13 MESSAGE_CONFIG: '/message/config',
14 14 //设备配置
15   - DEVICE_PROFILE: '/device/profiles',
  15 + DEVICE_PROFILE: '/product/profiles',
16 16 };
... ...
... ... @@ -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')}
... ...
... ... @@ -17,7 +17,7 @@ export default {
17 17 device: {
18 18 deviceManagement: '设备管理',
19 19 device: '设备列表',
20   - deviceProfile: '设备配置',
  20 + product: '产品',
21 21 },
22 22
23 23 tenant: {
... ...
... ... @@ -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];
... ...
... ... @@ -59,6 +59,8 @@
59 59 icon: 'clarity:note-edit-line',
60 60 onClick: handleCreateOrEdit.bind(null, record),
61 61 },
  62 + ]"
  63 + :drop-down-actions="[
62 64 {
63 65 label: '删除',
64 66 auth: 'api:yt:video:delete',
... ...
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[]>([]);
... ...
  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,
... ...
... ... @@ -21,7 +21,7 @@ export const descSchema: DescItem[] = [
21 21 },
22 22 {
23 23 field: 'deviceProfile.name',
24   - label: '设备配置',
  24 + label: '产品',
25 25 },
26 26 {
27 27 field: 'gatewayName',
... ...
... ... @@ -32,7 +32,7 @@ export const columns: BasicColumn[] = [
32 32 slots: { customRender: 'deviceType' },
33 33 },
34 34 {
35   - title: '设备配置',
  35 + title: '所属产品',
36 36 dataIndex: 'deviceProfile.name',
37 37 width: 160,
38 38 slots: { customRender: 'deviceProfile' },
... ...
... ... @@ -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',
... ...
... ... @@ -33,7 +33,7 @@ export const formSchema: FormSchema[] = [
33 33 component: 'ApiSelect',
34 34 componentProps: {
35 35 api: getDeviceProfile,
36   - placeholder: '请选择设备配置',
  36 + placeholder: '请选择产品',
37 37 labelField: 'name',
38 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 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);
... ...
... ... @@ -10,7 +10,7 @@ import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi';
10 10
11 11 export const steps = [
12 12 {
13   - title: '设备配置',
  13 + title: '产品',
14 14 content: 'First-content',
15 15 },
16 16 {
... ...
... ... @@ -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 };
... ...
... ... @@ -151,7 +151,7 @@
151 151 showIndexColumn: false,
152 152 clickToRowSelect: false,
153 153 useSearchForm: false,
154   - rowKey: 'id',
  154 + // rowKey: 'id',
155 155 showTableSetting: true,
156 156 bordered: true,
157 157 actionColumn: {
... ...
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 },
... ...
... ... @@ -32,6 +32,8 @@
32 32 onClick: handleEdit.bind(null, record),
33 33 ifShow: record.creator === userId && record.status !== 1,
34 34 },
  35 + ]"
  36 + :drop-down-actions="[
35 37 {
36 38 label: '删除',
37 39 auth: 'api:yt:sceneLinkage:delete',
... ...
... ... @@ -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)) {
... ...
... ... @@ -28,7 +28,7 @@ export const columns: BasicColumn[] = [
28 28 slots: { customRender: 'convertJs' },
29 29 },
30 30 {
31   - title: '描述',
  31 + title: '备注',
32 32 dataIndex: 'description',
33 33 width: 120,
34 34 },
... ...
... ... @@ -61,6 +61,8 @@
61 61 onClick: handleEdit.bind(null, record),
62 62 ifShow: record.level != 0,
63 63 },
  64 + ]"
  65 + :drop-down-actions="[
64 66 {
65 67 label: '删除',
66 68 auth: 'api:yt:user:delete',
... ...
... ... @@ -15,7 +15,7 @@
15 15 </script>
16 16
17 17 <template>
18   - <section class="widget">
  18 + <section class="widget !dark:bg-dark-900">
19 19 <slot name="header"></slot>
20 20
21 21 <div class="widget-content">
... ...
... ... @@ -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>
... ...