Commit b1fea99bc5155d6014b6d3550f9f4b42a45f51ba
Committed by
xp.Huang
1 parent
b65d9399
feat:看板添加手机端逻辑
Showing
27 changed files
with
462 additions
and
66 deletions
@@ -53,6 +53,7 @@ export interface DataBoardRecord { | @@ -53,6 +53,7 @@ export interface DataBoardRecord { | ||
53 | publicId: string; | 53 | publicId: string; |
54 | organizationId?: string; | 54 | organizationId?: string; |
55 | accessCredentials?: string; | 55 | accessCredentials?: string; |
56 | + platform?: string; | ||
56 | } | 57 | } |
57 | 58 | ||
58 | export interface DataBoardList { | 59 | export interface DataBoardList { |
@@ -137,7 +138,12 @@ export interface MasterDeviceList { | @@ -137,7 +138,12 @@ export interface MasterDeviceList { | ||
137 | } | 138 | } |
138 | 139 | ||
139 | export interface ComponentInfoDetail { | 140 | export interface ComponentInfoDetail { |
140 | - data: { componentData: DataComponentRecord[]; componentLayout: Layout[] }; | 141 | + data: { |
142 | + componentData: DataComponentRecord[]; | ||
143 | + componentLayout: Layout[]; | ||
144 | + phoneModel?: string | object; | ||
145 | + platform: string; | ||
146 | + }; | ||
141 | } | 147 | } |
142 | 148 | ||
143 | export interface DeviceAttributeParams { | 149 | export interface DeviceAttributeParams { |
@@ -21,6 +21,7 @@ enum Api { | @@ -21,6 +21,7 @@ enum Api { | ||
21 | SendLoginSmsCode = '/noauth/send_login_code/', | 21 | SendLoginSmsCode = '/noauth/send_login_code/', |
22 | ResetCode = '/noauth/reset_code/', | 22 | ResetCode = '/noauth/reset_code/', |
23 | ResetPassword = '/noauth/reset/', | 23 | ResetPassword = '/noauth/reset/', |
24 | + APP_GET_TOKEN = '/third/login/id/', | ||
24 | } | 25 | } |
25 | 26 | ||
26 | /** | 27 | /** |
@@ -100,3 +101,9 @@ export const getUserToken = (id: string) => { | @@ -100,3 +101,9 @@ export const getUserToken = (id: string) => { | ||
100 | url: `/third/login/id/${id}`, | 101 | url: `/third/login/id/${id}`, |
101 | }); | 102 | }); |
102 | }; | 103 | }; |
104 | + | ||
105 | +export const doAppLogin = (userId: string) => { | ||
106 | + return defHttp.get<Record<'refreshToken' | 'token', string>>({ | ||
107 | + url: `${Api.APP_GET_TOKEN}${userId}`, | ||
108 | + }); | ||
109 | +}; |
src/assets/svg/battery.svg
0 → 100644
1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1702374950759" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1997" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M144.700101 684.994006l535.580045 0L680.280146 359.237781 144.700101 359.237781 144.700101 684.994006 144.700101 684.994006zM918.373823 440.680675l0-81.442894c0-44.791136-36.649711-81.437777-81.437777-81.437777l-692.235944 0c-44.791136 0-81.437777 36.646642-81.437777 81.437777L63.262324 684.994006c0 44.791136 36.646642 81.442894 81.437777 81.442894l692.235944 0c44.788066 0 81.437777-36.650735 81.437777-81.442894l0-81.437777c22.396079 0 40.7194-18.322297 40.7194-40.7194l0-81.436754C959.093223 459.003995 940.769902 440.680675 918.373823 440.680675L918.373823 440.680675zM877.655446 481.400075l0 81.436754L877.655446 684.994006c0 22.395056-18.323321 40.718377-40.7194 40.718377l-692.235944 0c-22.396079 0-40.7194-18.323321-40.7194-40.718377L103.980701 359.237781c0-22.396079 18.323321-40.7194 40.7194-40.7194l692.235944 0c22.396079 0 40.7194 18.323321 40.7194 40.7194L877.655446 481.400075 877.655446 481.400075zM877.655446 481.400075" fill="#272636" p-id="1998"></path></svg> |
src/assets/svg/signal.svg
0 → 100644
1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1702374946029" class="icon" viewBox="0 0 1294 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1850" xmlns:xlink="http://www.w3.org/1999/xlink" width="252.734375" height="200"><path d="M0 727.578947l188.631579 0 0 296.421053-188.631579 0 0-296.421053Z" p-id="1851"></path><path d="M269.473684 565.894737l188.631579 0 0 458.105263-188.631579 0 0-458.105263Z" p-id="1852"></path><path d="M565.894737 377.263158l161.684211 0 0 646.736842-161.684211 0 0-646.736842Z" p-id="1853"></path><path d="M835.368421 188.631579l188.631579 0 0 835.368421-188.631579 0 0-835.368421Z" p-id="1854"></path><path d="M1104.842105 0l188.631579 0 0 1024-188.631579 0 0-1024Z" p-id="1855"></path></svg> |
src/assets/svg/wifi.svg
0 → 100644
1 | +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1702374954963" class="icon" viewBox="0 0 1280 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2277" xmlns:xlink="http://www.w3.org/1999/xlink" width="250" height="200"><path d="M1269.82 309.76C915.48-17.98 364.38-17.86 10.18 309.76c-13.32 12.32-13.58 33.18-0.7 45.96l68.48 67.94c12.28 12.2 32.04 12.46 44.8 0.76 291.84-267.36 742.6-267.42 1034.5 0 12.76 11.7 32.52 11.42 44.8-0.76l68.48-67.94c12.86-12.78 12.6-33.64-0.72-45.96zM640 704c-70.7 0-128 57.3-128 128s57.3 128 128 128 128-57.3 128-128-57.3-128-128-128z m405.34-167.18c-230.52-203.86-580.42-203.64-810.68 0-13.8 12.2-14.24 33.38-1.14 46.3l68.88 67.98c12 11.84 31.32 12.64 44.1 1.6 167.9-145.14 419.48-144.82 586.98 0 12.78 11.04 32.1 10.26 44.1-1.6l68.88-67.98c13.12-12.92 12.66-34.12-1.12-46.3z" p-id="2278"></path></svg> |
@@ -16,6 +16,7 @@ export const PageEnum = { | @@ -16,6 +16,7 @@ export const PageEnum = { | ||
16 | DEVICE_LIST: '/device/list', | 16 | DEVICE_LIST: '/device/list', |
17 | 17 | ||
18 | SHARE_PAGE: '/share/:viewType/:id/:publicId', | 18 | SHARE_PAGE: '/share/:viewType/:id/:publicId', |
19 | + APP_PAGE: '/appPage/:boardId/:userId', | ||
19 | 20 | ||
20 | RULE_CHAIN_DETAIL: '/rule/chain/:id', | 21 | RULE_CHAIN_DETAIL: '/rule/chain/:id', |
21 | 22 |
@@ -2,7 +2,7 @@ import { RouteLocationNormalizedLoaded } from 'vue-router'; | @@ -2,7 +2,7 @@ import { RouteLocationNormalizedLoaded } from 'vue-router'; | ||
2 | 2 | ||
3 | const menuMap = new Map(); | 3 | const menuMap = new Map(); |
4 | 4 | ||
5 | -menuMap.set('/visual/board/detail/:boardId/:boardName/:organizationId?', '/visual/board'); | 5 | +menuMap.set('/visual/board/detail/:boardId/:boardName/:platform/:organizationId?', '/visual/board'); |
6 | menuMap.set('/rule/chain/:id', '/rule/chain'); | 6 | menuMap.set('/rule/chain/:id', '/rule/chain'); |
7 | 7 | ||
8 | export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => { | 8 | export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => { |
@@ -11,7 +11,8 @@ import { getAuthCache } from '/@/utils/auth'; | @@ -11,7 +11,8 @@ import { getAuthCache } from '/@/utils/auth'; | ||
11 | const LOGIN_PATH = PageEnum.BASE_LOGIN; | 11 | const LOGIN_PATH = PageEnum.BASE_LOGIN; |
12 | const ROOT_PATH = RootRoute.path; | 12 | const ROOT_PATH = RootRoute.path; |
13 | const SHARE_PATH = PageEnum.SHARE_PAGE; | 13 | const SHARE_PATH = PageEnum.SHARE_PAGE; |
14 | -const whitePathList: string[] = [LOGIN_PATH, SHARE_PATH]; | 14 | +const APP_PATH = PageEnum.APP_PAGE; |
15 | +const whitePathList: string[] = [LOGIN_PATH, SHARE_PATH, APP_PATH]; | ||
15 | // const userInfo1 = getAuthCache(USER_INFO_KEY); | 16 | // const userInfo1 = getAuthCache(USER_INFO_KEY); |
16 | // const userInfo = ref(userInfo1); | 17 | // const userInfo = ref(userInfo1); |
17 | 18 |
src/router/routes/appPage.ts
0 → 100644
1 | +import { AppRouteRecordRaw } from '../types'; | ||
2 | +import { PageEnum } from '/@/enums/pageEnum'; | ||
3 | + | ||
4 | +export const APP_PAGE_ROUTER: AppRouteRecordRaw = { | ||
5 | + path: PageEnum.APP_PAGE, | ||
6 | + name: 'appPage', | ||
7 | + component: () => import('/@/views/sys/appPage/index.vue'), | ||
8 | + meta: { | ||
9 | + title: '公开', | ||
10 | + hideBreadcrumb: true, | ||
11 | + hideChildrenInMenu: true, | ||
12 | + }, | ||
13 | +}; |
@@ -5,6 +5,7 @@ import { PageEnum } from '/@/enums/pageEnum'; | @@ -5,6 +5,7 @@ import { PageEnum } from '/@/enums/pageEnum'; | ||
5 | import { t } from '/@/hooks/web/useI18n'; | 5 | import { t } from '/@/hooks/web/useI18n'; |
6 | import { LAYOUT } from '../constant'; | 6 | import { LAYOUT } from '../constant'; |
7 | import { PUBLIC_PAGE_ROUTER } from './public'; | 7 | import { PUBLIC_PAGE_ROUTER } from './public'; |
8 | +import { APP_PAGE_ROUTER } from './appPage'; | ||
8 | 9 | ||
9 | const modules = import.meta.globEager('./modules/**/*.ts'); | 10 | const modules = import.meta.globEager('./modules/**/*.ts'); |
10 | const routeModuleList: AppRouteModule[] = []; | 11 | const routeModuleList: AppRouteModule[] = []; |
@@ -87,4 +88,5 @@ export const basicRoutes = [ | @@ -87,4 +88,5 @@ export const basicRoutes = [ | ||
87 | REDIRECT_ROUTE, | 88 | REDIRECT_ROUTE, |
88 | PAGE_NOT_FOUND_ROUTE, | 89 | PAGE_NOT_FOUND_ROUTE, |
89 | PUBLIC_PAGE_ROUTER, | 90 | PUBLIC_PAGE_ROUTER, |
91 | + APP_PAGE_ROUTER, | ||
90 | ]; | 92 | ]; |
@@ -105,7 +105,7 @@ export const getFormSchemas = (hasAlarmNotify: Ref<boolean>): FormSchema[] => { | @@ -105,7 +105,7 @@ export const getFormSchemas = (hasAlarmNotify: Ref<boolean>): FormSchema[] => { | ||
105 | field: FormFieldsEnum.ALARM_PROFILED, | 105 | field: FormFieldsEnum.ALARM_PROFILED, |
106 | label: '', | 106 | label: '', |
107 | component: 'AlarmProfileSelect', | 107 | component: 'AlarmProfileSelect', |
108 | - rules: [{ required: true, message: `请选择${FormFieldsEnum.ALARM_PROFILED}` }], | 108 | + // rules: [{ required: true, message: `请选择${FormFieldsEnum.ALARM_PROFILED}` }], |
109 | ifShow: ({ model }) => model[FormFieldsEnum.OUT_TARGET] === ExecutionActionEnum.MSG_NOTIFY, | 109 | ifShow: ({ model }) => model[FormFieldsEnum.OUT_TARGET] === ExecutionActionEnum.MSG_NOTIFY, |
110 | componentProps: () => { | 110 | componentProps: () => { |
111 | return { | 111 | return { |
src/views/sys/appPage/config/config.ts
0 → 100644
1 | +import { useRouter } from 'vue-router'; | ||
2 | + | ||
3 | +export enum ViewTypeEnum { | ||
4 | + DATA_BOARD = 'DATA_BOARD', | ||
5 | + LARGE_SCREEN = 'LARGE_SCREEN', | ||
6 | + SCADA = 'SCADA', | ||
7 | +} | ||
8 | + | ||
9 | +export const goShareUrl = (options: { type: ViewTypeEnum; id: string }, openNew?: false) => { | ||
10 | + const { type, id } = options; | ||
11 | + const ROUTER = useRouter(); | ||
12 | + const { origin } = location; | ||
13 | + const path = `/share/${type}/${id}`; | ||
14 | + openNew ? ROUTER.push(path) : open(`${origin}${path}`); | ||
15 | +}; |
src/views/sys/appPage/hook/index.ts
0 → 100644
src/views/sys/appPage/index.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { onMounted } from 'vue'; | ||
3 | + import { Spin } from 'ant-design-vue'; | ||
4 | + import { ref } from 'vue'; | ||
5 | + import { useRoute } from 'vue-router'; | ||
6 | + import { useUserStore } from '/@/store/modules/user'; | ||
7 | + import BoardDetail from '/@/views/visual/board/detail/index.vue'; | ||
8 | + import { doAppLogin } from '/@/api/sys/user'; | ||
9 | + | ||
10 | + const loading = ref(true); | ||
11 | + const ROUTE = useRoute(); | ||
12 | + const contentData = ref<any>(); | ||
13 | + const canLoadComponent = ref(false); | ||
14 | + | ||
15 | + const modelVisable = ref(false); | ||
16 | + | ||
17 | + const userStore = useUserStore(); | ||
18 | + | ||
19 | + const getShareToken = async () => { | ||
20 | + const { params } = ROUTE; | ||
21 | + const { userId }: any = params; | ||
22 | + const { token, refreshToken } = await doAppLogin(userId); | ||
23 | + userStore.storeToken(token, refreshToken); | ||
24 | + }; | ||
25 | + | ||
26 | + const getContentLoading = ref(false); | ||
27 | + const getContentData = async () => { | ||
28 | + try { | ||
29 | + getContentLoading.value = true; | ||
30 | + loading.value = false; | ||
31 | + canLoadComponent.value = true; | ||
32 | + modelVisable.value = false; | ||
33 | + } catch (error) { | ||
34 | + } finally { | ||
35 | + getContentLoading.value = false; | ||
36 | + } | ||
37 | + }; | ||
38 | + | ||
39 | + onMounted(async () => { | ||
40 | + await getShareToken(); | ||
41 | + await getContentData(); | ||
42 | + }); | ||
43 | +</script> | ||
44 | + | ||
45 | +<template> | ||
46 | + <Spin | ||
47 | + :spinning="loading" | ||
48 | + tip="正在加载中..." | ||
49 | + size="large" | ||
50 | + class="!flex justify-center items-center w-full h-full share-full-loading" | ||
51 | + > | ||
52 | + <BoardDetail v-if="canLoadComponent" :value="contentData" /> | ||
53 | + </Spin> | ||
54 | +</template> | ||
55 | + | ||
56 | +<style lang="less"> | ||
57 | + .share-page-token-modal { | ||
58 | + .ant-modal-close { | ||
59 | + display: none; | ||
60 | + } | ||
61 | + } | ||
62 | +</style> |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { BasicModal, useModalInner } from '/@/components/Modal'; | 2 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
3 | import { BasicForm, useForm } from '/@/components/Form'; | 3 | import { BasicForm, useForm } from '/@/components/Form'; |
4 | - import { formSchema } from '../config/panelDetail'; | 4 | + import { formSchema, PlatformType } from '../config/panelDetail'; |
5 | import { addDataBoard, updateDataBoard } from '/@/api/dataBoard'; | 5 | import { addDataBoard, updateDataBoard } from '/@/api/dataBoard'; |
6 | import { AddDataBoardParams } from '/@/api/dataBoard/model'; | 6 | import { AddDataBoardParams } from '/@/api/dataBoard/model'; |
7 | import { useMessage } from '/@/hooks/web/useMessage'; | 7 | import { useMessage } from '/@/hooks/web/useMessage'; |
@@ -34,6 +34,9 @@ | @@ -34,6 +34,9 @@ | ||
34 | if (!Reflect.get(value, 'accessCredentials')) { | 34 | if (!Reflect.get(value, 'accessCredentials')) { |
35 | Reflect.deleteProperty(value, 'accessCredentials'); | 35 | Reflect.deleteProperty(value, 'accessCredentials'); |
36 | } | 36 | } |
37 | + if (value.platform === PlatformType.PC) { | ||
38 | + Reflect.deleteProperty(value, 'phoneModel'); | ||
39 | + } | ||
37 | return value as any; | 40 | return value as any; |
38 | }; | 41 | }; |
39 | 42 |
@@ -4,7 +4,13 @@ export enum ViewType { | @@ -4,7 +4,13 @@ export enum ViewType { | ||
4 | PRIVATE_VIEW = 'PRIVATE_VIEW', | 4 | PRIVATE_VIEW = 'PRIVATE_VIEW', |
5 | PUBLIC_VIEW = 'PUBLIC_VIEW', | 5 | PUBLIC_VIEW = 'PUBLIC_VIEW', |
6 | } | 6 | } |
7 | +import { Platform } from '../../palette/components/PagerHeader/config'; | ||
8 | + | ||
7 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); | 9 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); |
10 | +export enum PlatformType { | ||
11 | + PHONE = 'phone', | ||
12 | + PC = 'pc', | ||
13 | +} | ||
8 | 14 | ||
9 | export const formSchema: FormSchema[] = [ | 15 | export const formSchema: FormSchema[] = [ |
10 | { | 16 | { |
@@ -24,6 +30,32 @@ export const formSchema: FormSchema[] = [ | @@ -24,6 +30,32 @@ export const formSchema: FormSchema[] = [ | ||
24 | rules: [{ required: true, message: '组织为必填项' }], | 30 | rules: [{ required: true, message: '组织为必填项' }], |
25 | }, | 31 | }, |
26 | { | 32 | { |
33 | + field: 'platform', | ||
34 | + label: '平台', | ||
35 | + required: true, | ||
36 | + component: 'RadioGroup', | ||
37 | + defaultValue: PlatformType.PC, | ||
38 | + componentProps({ formModel }) { | ||
39 | + return { | ||
40 | + defaultValue: PlatformType.PC, | ||
41 | + options: [ | ||
42 | + { label: 'PC端', value: PlatformType.PC }, | ||
43 | + { label: '移动端', value: PlatformType.PHONE }, | ||
44 | + ], | ||
45 | + onChange(e) { | ||
46 | + formModel.phoneModel = | ||
47 | + e?.target?.value === PlatformType.PHONE ? JSON.stringify(Platform[1]) : []; | ||
48 | + }, | ||
49 | + }; | ||
50 | + }, | ||
51 | + }, | ||
52 | + { | ||
53 | + field: 'phoneModel', | ||
54 | + label: '手机端尺寸', | ||
55 | + component: 'Input', | ||
56 | + ifShow: false, | ||
57 | + }, | ||
58 | + { | ||
27 | field: 'remark', | 59 | field: 'remark', |
28 | label: '备注', | 60 | label: '备注', |
29 | component: 'InputTextArea', | 61 | component: 'InputTextArea', |
@@ -135,12 +135,13 @@ | @@ -135,12 +135,13 @@ | ||
135 | 135 | ||
136 | const handleViewBoard = (record: DataBoardRecord) => { | 136 | const handleViewBoard = (record: DataBoardRecord) => { |
137 | const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL); | 137 | const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL); |
138 | + const { platform = 'pc' } = record || {}; | ||
138 | if (hasDetailPermission) { | 139 | if (hasDetailPermission) { |
139 | const boardId = encode(record.id); | 140 | const boardId = encode(record.id); |
140 | const boardName = encode(record.name); | 141 | const boardName = encode(record.name); |
141 | const organizationId = encode(record!.organizationId!); | 142 | const organizationId = encode(record!.organizationId!); |
142 | 143 | ||
143 | - router.push(`/visual/board/detail/${boardId}/${boardName}/${organizationId}`); | 144 | + router.push(`/visual/board/detail/${boardId}/${boardName}/${platform}/${organizationId}`); |
144 | } else createMessage.warning('没有权限'); | 145 | } else createMessage.warning('没有权限'); |
145 | }; | 146 | }; |
146 | </script> | 147 | </script> |
@@ -170,7 +171,7 @@ | @@ -170,7 +171,7 @@ | ||
170 | </Dropdown> | 171 | </Dropdown> |
171 | </template> | 172 | </template> |
172 | <section @click="handleViewBoard(item)"> | 173 | <section @click="handleViewBoard(item)"> |
173 | - <div class="flex data-card__info"> | 174 | + <div class="flex data-card__info relative"> |
174 | <div> | 175 | <div> |
175 | <div>组件数量</div> | 176 | <div>组件数量</div> |
176 | <Statistic class="text-2xl" :value="item.componentNum"> | 177 | <Statistic class="text-2xl" :value="item.componentNum"> |
@@ -179,6 +180,12 @@ | @@ -179,6 +180,12 @@ | ||
179 | </template> | 180 | </template> |
180 | </Statistic> | 181 | </Statistic> |
181 | </div> | 182 | </div> |
183 | + <div class="absolute" style="right: 1%"> | ||
184 | + <Icon | ||
185 | + :icon="item.platform === 'pc' ? 'ri:computer-line' : 'clarity:mobile-phone-solid'" | ||
186 | + style="font-size: 32px" | ||
187 | + /> | ||
188 | + </div> | ||
182 | </div> | 189 | </div> |
183 | <div class="flex justify-between mt-4 text-sm" style="color: #999"> | 190 | <div class="flex justify-between mt-4 text-sm" style="color: #999"> |
184 | <div class="flex min-w-20 mr-3"> | 191 | <div class="flex min-w-20 mr-3"> |
@@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
23 | import { WidgetDataType } from '../../hooks/useDataSource'; | 23 | import { WidgetDataType } from '../../hooks/useDataSource'; |
24 | import { ExtraDataSource } from '../../types'; | 24 | import { ExtraDataSource } from '../../types'; |
25 | import { OrderByEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config'; | 25 | import { OrderByEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config'; |
26 | + import { useApp } from '../../hooks/useApp'; | ||
26 | 27 | ||
27 | type DeviceOption = Record<'label' | 'value' | 'organizationId', string>; | 28 | type DeviceOption = Record<'label' | 'value' | 'organizationId', string>; |
28 | 29 | ||
@@ -38,6 +39,8 @@ | @@ -38,6 +39,8 @@ | ||
38 | 39 | ||
39 | const historyData = ref<{ ts: number; value: string; name: string }[]>([]); | 40 | const historyData = ref<{ ts: number; value: string; name: string }[]>([]); |
40 | 41 | ||
42 | + const { getIsAppPage } = useApp(); | ||
43 | + | ||
41 | const { deviceAttrs, getDeviceKeys, getSearchParams, setChartOptions, getDeviceAttribute } = | 44 | const { deviceAttrs, getDeviceKeys, getSearchParams, setChartOptions, getDeviceAttribute } = |
42 | useHistoryData(); | 45 | useHistoryData(); |
43 | 46 | ||
@@ -294,7 +297,7 @@ | @@ -294,7 +297,7 @@ | ||
294 | :destroy-on-close="true" | 297 | :destroy-on-close="true" |
295 | :show-ok-btn="false" | 298 | :show-ok-btn="false" |
296 | cancel-text="关闭" | 299 | cancel-text="关闭" |
297 | - width="70%" | 300 | + :width="getIsAppPage ? '100%' : '75%'" |
298 | title="历史趋势" | 301 | title="历史趋势" |
299 | > | 302 | > |
300 | <section | 303 | <section |
1 | +export const Platform = [ | ||
2 | + { key: 'iPhone 8', title: 'iPhone 8', width: 375, height: 667 }, | ||
3 | + { key: 'iPhone 8 Plus', title: 'iPhone 8 Plus', width: 415, height: 737 }, | ||
4 | + { key: 'iPhone X/XS', title: 'iPhone X/XS', width: 376, height: 813 }, | ||
5 | + { key: 'iPad 4', title: 'iPad 4', width: 709, height: 1025 }, | ||
6 | + { key: 'Galaxy S9', title: 'Galaxy S9', width: 361, height: 741 }, | ||
7 | + { key: 'Galaxy S10/S10+', title: 'Galaxy S10/S10+', width: 413, height: 870 }, | ||
8 | + { key: 'Pixel 2', title: 'Pixel 2', width: 413, height: 732 }, | ||
9 | + { key: 'custom', title: '自定义', width: '', height: '' }, | ||
10 | +]; |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | - import { PageHeader } from 'ant-design-vue'; | ||
3 | - import { computed, unref } from 'vue'; | 2 | + import { PageHeader, RadioButton, RadioGroup, InputNumber, Button } from 'ant-design-vue'; |
3 | + import { computed, ref, unref, onMounted } from 'vue'; | ||
4 | import { useRoute, useRouter } from 'vue-router'; | 4 | import { useRoute, useRouter } from 'vue-router'; |
5 | import { decode } from '../..'; | 5 | import { decode } from '../..'; |
6 | import { RollbackOutlined } from '@ant-design/icons-vue'; | 6 | import { RollbackOutlined } from '@ant-design/icons-vue'; |
7 | + import { Platform } from './config'; | ||
8 | + import { useApp } from '../../hooks/useApp'; | ||
9 | + import { getDataComponent } from '/@/api/dataBoard'; | ||
10 | + import { updateDataBoard } from '/@/api/dataBoard'; | ||
11 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
7 | 12 | ||
8 | defineProps<{ widgetNumber: number }>(); | 13 | defineProps<{ widgetNumber: number }>(); |
14 | + const emits = defineEmits(['getPhoneSize']); | ||
9 | 15 | ||
10 | const ROUTE = useRoute(); | 16 | const ROUTE = useRoute(); |
11 | const ROUTER = useRouter(); | 17 | const ROUTER = useRouter(); |
18 | + | ||
19 | + const { isPhone } = useApp(); | ||
12 | const getIsSharePage = computed(() => { | 20 | const getIsSharePage = computed(() => { |
13 | return ROUTE.matched.find((item) => item.path === '/share/:viewType/:id/:publicId'); | 21 | return ROUTE.matched.find((item) => item.path === '/share/:viewType/:id/:publicId'); |
14 | }); | 22 | }); |
@@ -22,7 +30,85 @@ | @@ -22,7 +30,85 @@ | ||
22 | ROUTER.go(-1); | 30 | ROUTER.go(-1); |
23 | }; | 31 | }; |
24 | 32 | ||
25 | - // const handleOpenCreatePanel = () => {}; | 33 | + const getSize = () => { |
34 | + return { | ||
35 | + width: '', | ||
36 | + height: '', | ||
37 | + }; | ||
38 | + }; | ||
39 | + | ||
40 | + const phoneRadio = ref<string>('iPhone 8'); | ||
41 | + const phoneSize = ref<{ width?: number | string; height?: number | string }>(getSize()); | ||
42 | + const ifShowWidth = ref<boolean>(false); | ||
43 | + | ||
44 | + const phoneModel = ref<{ | ||
45 | + key: string; | ||
46 | + width: string | number; | ||
47 | + height: number | string; | ||
48 | + title: string; | ||
49 | + }>(); | ||
50 | + const getDataList = async () => { | ||
51 | + const values = await getDataComponent(decode((ROUTE.params as { boardId: string }).boardId)); | ||
52 | + phoneModel.value = values?.data.phoneModel && JSON.parse(values?.data.phoneModel as string); | ||
53 | + phoneRadio.value = unref(phoneModel)?.key as any; | ||
54 | + ifShowWidth.value = unref(phoneRadio) === 'custom' ? true : false; | ||
55 | + phoneSize.value = { | ||
56 | + width: unref(phoneModel)?.width, | ||
57 | + height: unref(phoneModel)?.height, | ||
58 | + }; | ||
59 | + | ||
60 | + emits('getPhoneSize', unref(phoneSize)); | ||
61 | + }; | ||
62 | + | ||
63 | + const updateComponent = () => { | ||
64 | + const { boardId, boardName, organizationId, platform } = ROUTE.params; | ||
65 | + | ||
66 | + const values = { | ||
67 | + id: boardId, | ||
68 | + boardName, | ||
69 | + organizationId, | ||
70 | + platform, | ||
71 | + phoneModel: JSON.stringify({ | ||
72 | + key: unref(phoneRadio), | ||
73 | + ...phoneSize.value, | ||
74 | + }), | ||
75 | + }; | ||
76 | + updateDataBoard(values as any); | ||
77 | + }; | ||
78 | + | ||
79 | + const handleChange = (e) => { | ||
80 | + const { target } = e || {}; | ||
81 | + phoneSize.value = getSize(); | ||
82 | + if (target.value === 'custom') { | ||
83 | + ifShowWidth.value = true; | ||
84 | + return; | ||
85 | + } else { | ||
86 | + ifShowWidth.value = false; | ||
87 | + const values = Platform.find((item) => item.key == target.value); | ||
88 | + phoneSize.value = { | ||
89 | + width: values?.width || '', | ||
90 | + height: values?.height || '', | ||
91 | + }; | ||
92 | + } | ||
93 | + updateComponent(); | ||
94 | + emits('getPhoneSize', unref(phoneSize)); | ||
95 | + }; | ||
96 | + | ||
97 | + const { createMessage } = useMessage(); | ||
98 | + | ||
99 | + const handleCustom = () => { | ||
100 | + const { width, height } = unref(phoneSize); | ||
101 | + if (!width || !height) { | ||
102 | + createMessage.warning('请填写尺寸大小'); | ||
103 | + return; | ||
104 | + } | ||
105 | + emits('getPhoneSize', unref(phoneSize)); | ||
106 | + updateComponent(); | ||
107 | + }; | ||
108 | + | ||
109 | + onMounted(() => { | ||
110 | + getDataList(); | ||
111 | + }); | ||
26 | </script> | 112 | </script> |
27 | 113 | ||
28 | <template> | 114 | <template> |
@@ -46,6 +132,18 @@ | @@ -46,6 +132,18 @@ | ||
46 | <span class="mr-3 text-sm text-gray-500">已创建组件:</span> | 132 | <span class="mr-3 text-sm text-gray-500">已创建组件:</span> |
47 | <span class="text-blue-500"> {{ widgetNumber }}个</span> | 133 | <span class="text-blue-500"> {{ widgetNumber }}个</span> |
48 | </div> | 134 | </div> |
135 | + <div v-if="isPhone()" class="flex items-center my-1"> | ||
136 | + <RadioGroup v-model:value="phoneRadio" button-style="solid" @change="handleChange"> | ||
137 | + <RadioButton v-for="item in Platform" :value="item.key" :key="item.key">{{ | ||
138 | + item.title | ||
139 | + }}</RadioButton> | ||
140 | + </RadioGroup> | ||
141 | + <div class="ml-1" v-if="ifShowWidth"> | ||
142 | + <InputNumber v-model:value="phoneSize.width" :min="300" placeholder="请输入宽度" /> | ||
143 | + <InputNumber v-model:value="phoneSize.height" :min="300" placeholder="请输入高度" /> | ||
144 | + <Button type="primary" @click="handleCustom" class="ml-1">确定</Button> | ||
145 | + </div> | ||
146 | + </div> | ||
49 | </PageHeader> | 147 | </PageHeader> |
50 | </template> | 148 | </template> |
51 | 149 |
@@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
7 | import { BasicForm } from '/@/components/Form'; | 7 | import { BasicForm } from '/@/components/Form'; |
8 | import { BasicModal } from '/@/components/Modal'; | 8 | import { BasicModal } from '/@/components/Modal'; |
9 | import { nextTick } from 'vue'; | 9 | import { nextTick } from 'vue'; |
10 | + import { useApp } from '../../hooks/useApp'; | ||
10 | const emit = defineEmits(['register', 'getAlarmForm', 'getHistoryForm']); | 11 | const emit = defineEmits(['register', 'getAlarmForm', 'getHistoryForm']); |
11 | // const emit = defineEmits<{ | 12 | // const emit = defineEmits<{ |
12 | // (event: 'getAlarmForm', data: WidgetDataType): void; | 13 | // (event: 'getAlarmForm', data: WidgetDataType): void; |
@@ -15,6 +16,8 @@ | @@ -15,6 +16,8 @@ | ||
15 | // const fontId = ref(''); | 16 | // const fontId = ref(''); |
16 | const [registerModal, { closeModal }] = useModalInner(async () => {}); | 17 | const [registerModal, { closeModal }] = useModalInner(async () => {}); |
17 | 18 | ||
19 | + const { getIsAppPage } = useApp(); | ||
20 | + | ||
18 | const [register, method] = useForm({ | 21 | const [register, method] = useForm({ |
19 | schemas: formSchema(), | 22 | schemas: formSchema(), |
20 | baseColProps: useGridLayout(1) as unknown as ColEx, | 23 | baseColProps: useGridLayout(1) as unknown as ColEx, |
@@ -53,7 +56,7 @@ | @@ -53,7 +56,7 @@ | ||
53 | :destroy-on-close="true" | 56 | :destroy-on-close="true" |
54 | :show-ok-btn="true" | 57 | :show-ok-btn="true" |
55 | cancel-text="关闭" | 58 | cancel-text="关闭" |
56 | - width="40%" | 59 | + :width="getIsAppPage ? '80%' : '40%'" |
57 | title="历史趋势" | 60 | title="历史趋势" |
58 | > | 61 | > |
59 | <section | 62 | <section |
src/views/visual/palette/hooks/useApp.ts
0 → 100644
1 | +import { computed } from 'vue'; | ||
2 | +import { useRoute } from 'vue-router'; | ||
3 | + | ||
4 | +export const useApp = () => { | ||
5 | + const ROUTE = useRoute(); | ||
6 | + const getIsAppPage = computed(() => { | ||
7 | + return ROUTE.matched.find((item) => item.path === '/appPage/:boardId/:userId'); | ||
8 | + }); | ||
9 | + | ||
10 | + const isPhone = () => { | ||
11 | + const values = location?.pathname.split('/') || []; | ||
12 | + return values[values?.length - 2] === 'phone' ? true : false; | ||
13 | + }; | ||
14 | + | ||
15 | + return { getIsAppPage, isPhone }; | ||
16 | +}; |
1 | import { unref } from 'vue'; | 1 | import { unref } from 'vue'; |
2 | import { Layout } from 'vue3-grid-layout'; | 2 | import { Layout } from 'vue3-grid-layout'; |
3 | -import { DEFAULT_MAX_COL, DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH } from '..'; | 3 | +import { DEFAULT_MAX_COL, DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, PHONE_SIZE } from '..'; |
4 | +import { useApp } from './useApp'; | ||
4 | 5 | ||
5 | interface GapRecord { | 6 | interface GapRecord { |
6 | maxGap: number; | 7 | maxGap: number; |
@@ -8,9 +9,14 @@ interface GapRecord { | @@ -8,9 +9,14 @@ interface GapRecord { | ||
8 | endIndex: Nullable<number>; | 9 | endIndex: Nullable<number>; |
9 | } | 10 | } |
10 | 11 | ||
12 | +const { isPhone } = useApp(); | ||
13 | + | ||
11 | export const useCalcNewWidgetPosition = ( | 14 | export const useCalcNewWidgetPosition = ( |
12 | layoutInfo: Layout[], | 15 | layoutInfo: Layout[], |
13 | - randomLayout = { width: DEFAULT_WIDGET_WIDTH, height: DEFAULT_WIDGET_HEIGHT } | 16 | + randomLayout = { |
17 | + width: isPhone() ? PHONE_SIZE.DEFAULT_WIDGET_WIDTH : DEFAULT_WIDGET_WIDTH, | ||
18 | + height: isPhone() ? PHONE_SIZE.DEFAULT_WIDGET_HEIGHT : DEFAULT_WIDGET_HEIGHT, | ||
19 | + } | ||
14 | ) => { | 20 | ) => { |
15 | let maxWidth = 0; | 21 | let maxWidth = 0; |
16 | let maxHeight = 0; | 22 | let maxHeight = 0; |
@@ -30,6 +30,10 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { | @@ -30,6 +30,10 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { | ||
30 | const getIsSharePage = computed(() => { | 30 | const getIsSharePage = computed(() => { |
31 | return ROUTE.matched.find((item) => item.path === '/share/:viewType/:id/:publicId'); | 31 | return ROUTE.matched.find((item) => item.path === '/share/:viewType/:id/:publicId'); |
32 | }); | 32 | }); |
33 | + //小程序打开的页面 | ||
34 | + const getIsAppPage = computed(() => { | ||
35 | + return ROUTE.matched.find((item) => item.path === '/appPage/:boardId/:userId'); | ||
36 | + }); | ||
33 | 37 | ||
34 | const getBoardId = computed(() => { | 38 | const getBoardId = computed(() => { |
35 | return decode((ROUTE.params as { boardId: string }).boardId); | 39 | return decode((ROUTE.params as { boardId: string }).boardId); |
@@ -131,8 +135,8 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { | @@ -131,8 +135,8 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { | ||
131 | 135 | ||
132 | return { | 136 | return { |
133 | loading, | 137 | loading, |
134 | - draggable: !unref(getIsSharePage), | ||
135 | - resizable: !unref(getIsSharePage), | 138 | + draggable: !unref(getIsSharePage) && !unref(getIsAppPage), |
139 | + resizable: !unref(getIsSharePage) && !unref(getIsAppPage), | ||
136 | dataSource, | 140 | dataSource, |
137 | rawDataSource, | 141 | rawDataSource, |
138 | getDataSource, | 142 | getDataSource, |
@@ -11,6 +11,12 @@ export const DEFAULT_WIDGET_HEIGHT = 6; | @@ -11,6 +11,12 @@ export const DEFAULT_WIDGET_HEIGHT = 6; | ||
11 | export const DEFAULT_MIN_HEIGHT = 5; | 11 | export const DEFAULT_MIN_HEIGHT = 5; |
12 | export const DEFAULT_MIN_WIDTH = 3; | 12 | export const DEFAULT_MIN_WIDTH = 3; |
13 | export const DEFAULT_ITEM_MARIGN = 20; | 13 | export const DEFAULT_ITEM_MARIGN = 20; |
14 | +export const PHONE_SIZE = { | ||
15 | + DEFAULT_WIDGET_WIDTH: 12, | ||
16 | + DEFAULT_WIDGET_HEIGHT: 4, | ||
17 | + DEFAULT_MIN_HEIGHT: 4, | ||
18 | + DEFAULT_MIN_WIDTH: 11, | ||
19 | +}; | ||
14 | 20 | ||
15 | import { ViewTypeEnum } from '/@/views/sys/share/config/config'; | 21 | import { ViewTypeEnum } from '/@/views/sys/share/config/config'; |
16 | 22 |
@@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
10 | DEFAULT_MIN_WIDTH, | 10 | DEFAULT_MIN_WIDTH, |
11 | DEFAULT_ITEM_MARIGN, | 11 | DEFAULT_ITEM_MARIGN, |
12 | VisualComponentPermission, | 12 | VisualComponentPermission, |
13 | + PHONE_SIZE, | ||
13 | } from './index'; | 14 | } from './index'; |
14 | import { useDragGridLayout } from './hooks/useDragGridLayout'; | 15 | import { useDragGridLayout } from './hooks/useDragGridLayout'; |
15 | import { WidgetHeader, WidgetWrapper } from './components/WidgetWrapper'; | 16 | import { WidgetHeader, WidgetWrapper } from './components/WidgetWrapper'; |
@@ -19,6 +20,7 @@ | @@ -19,6 +20,7 @@ | ||
19 | import { DataSourceBindPanel } from '../dataSourceBindPanel'; | 20 | import { DataSourceBindPanel } from '../dataSourceBindPanel'; |
20 | import { PageHeader } from './components/PagerHeader'; | 21 | import { PageHeader } from './components/PagerHeader'; |
21 | import { useShare } from './hooks/useShare'; | 22 | import { useShare } from './hooks/useShare'; |
23 | + import { useApp } from './hooks/useApp'; | ||
22 | import { useRole } from '/@/hooks/business/useRole'; | 24 | import { useRole } from '/@/hooks/business/useRole'; |
23 | import { Authority } from '/@/components/Authority'; | 25 | import { Authority } from '/@/components/Authority'; |
24 | import { useModal } from '/@/components/Modal'; | 26 | import { useModal } from '/@/components/Modal'; |
@@ -33,6 +35,11 @@ | @@ -33,6 +35,11 @@ | ||
33 | import { useSocket } from '/@/views/visual/packages/hook/socket/useSocket'; | 35 | import { useSocket } from '/@/views/visual/packages/hook/socket/useSocket'; |
34 | import { createAlarmContext } from './hooks/useAlarmTime'; | 36 | import { createAlarmContext } from './hooks/useAlarmTime'; |
35 | import { createHistoryContext } from './hooks/useHistoryForm'; | 37 | import { createHistoryContext } from './hooks/useHistoryForm'; |
38 | + import { MoreOutlined, LeftOutlined } from '@ant-design/icons-vue'; | ||
39 | + import WIFISVG from '/@/assets/svg/wifi.svg'; | ||
40 | + import SIGNALSVG from '/@/assets/svg/signal.svg'; | ||
41 | + import BATTERYSVG from '/@/assets/svg/battery.svg'; | ||
42 | + import { useRoute } from 'vue-router'; | ||
36 | 43 | ||
37 | const props = defineProps<{ | 44 | const props = defineProps<{ |
38 | value?: Recordable; | 45 | value?: Recordable; |
@@ -44,6 +51,8 @@ | @@ -44,6 +51,8 @@ | ||
44 | 51 | ||
45 | const containerRectRef = ref<DOMRect>({} as unknown as DOMRect); | 52 | const containerRectRef = ref<DOMRect>({} as unknown as DOMRect); |
46 | 53 | ||
54 | + const ROUTE = useRoute(); | ||
55 | + | ||
47 | const { loading, draggable, resizable, dataSource, rawDataSource, setLayoutInfo, getDataSource } = | 56 | const { loading, draggable, resizable, dataSource, rawDataSource, setLayoutInfo, getDataSource } = |
48 | useDataSource(getProps); | 57 | useDataSource(getProps); |
49 | 58 | ||
@@ -63,6 +72,9 @@ | @@ -63,6 +72,9 @@ | ||
63 | } | 72 | } |
64 | }); | 73 | }); |
65 | const { getIsSharePage } = useShare(); | 74 | const { getIsSharePage } = useShare(); |
75 | + | ||
76 | + // getIsAppPage 是否是小程序进入的页面 isPhone 是否是创建的手机端 | ||
77 | + const { getIsAppPage, isPhone } = useApp(); | ||
66 | const { isCustomerUser } = useRole(); | 78 | const { isCustomerUser } = useRole(); |
67 | const handleOpenCreatePanel = () => { | 79 | const handleOpenCreatePanel = () => { |
68 | openModal(true, { mode: DataActionModeEnum.CREATE } as ModalParamsType); | 80 | openModal(true, { mode: DataActionModeEnum.CREATE } as ModalParamsType); |
@@ -157,6 +169,28 @@ | @@ -157,6 +169,28 @@ | ||
157 | }, | 169 | }, |
158 | { immediate: true } | 170 | { immediate: true } |
159 | ); | 171 | ); |
172 | + watch( | ||
173 | + getIsAppPage, | ||
174 | + (value) => { | ||
175 | + if (value) { | ||
176 | + const root = document.querySelector('#app'); | ||
177 | + (root as HTMLDivElement).style.backgroundColor = | ||
178 | + unref(getDarkMode) === ThemeEnum.LIGHT ? '#F5F5F5' : '#1b1b1b'; | ||
179 | + } | ||
180 | + }, | ||
181 | + { immediate: true } | ||
182 | + ); | ||
183 | + const getDataBoardName = computed(() => { | ||
184 | + return decodeURIComponent((ROUTE.params as { boardName: string }).boardName || ''); | ||
185 | + }); | ||
186 | + | ||
187 | + const phoneSize = ref({ | ||
188 | + width: '' || 375, | ||
189 | + height: '' || 667, | ||
190 | + }); | ||
191 | + const getPhoneSize = (values) => { | ||
192 | + phoneSize.value = { ...values }; | ||
193 | + }; | ||
160 | </script> | 194 | </script> |
161 | 195 | ||
162 | <template> | 196 | <template> |
@@ -164,7 +198,11 @@ | @@ -164,7 +198,11 @@ | ||
164 | ref="containerRefEl" | 198 | ref="containerRefEl" |
165 | class="palette w-full h-full flex-col bg-neutral-100 flex dark:bg-dark-700 dark:text-light-50" | 199 | class="palette w-full h-full flex-col bg-neutral-100 flex dark:bg-dark-700 dark:text-light-50" |
166 | > | 200 | > |
167 | - <PageHeader :widget-number="dataSource.length"> | 201 | + <PageHeader |
202 | + v-if="!getIsAppPage" | ||
203 | + :widget-number="dataSource.length" | ||
204 | + @getPhoneSize="getPhoneSize" | ||
205 | + > | ||
168 | <Authority :value="VisualComponentPermission.CREATE"> | 206 | <Authority :value="VisualComponentPermission.CREATE"> |
169 | <Button | 207 | <Button |
170 | v-if="!getIsSharePage && !isCustomerUser" | 208 | v-if="!getIsSharePage && !isCustomerUser" |
@@ -177,55 +215,104 @@ | @@ -177,55 +215,104 @@ | ||
177 | </PageHeader> | 215 | </PageHeader> |
178 | 216 | ||
179 | <Spin :spinning="loading"> | 217 | <Spin :spinning="loading"> |
180 | - <GridLayout | ||
181 | - v-model:layout="dataSource" | ||
182 | - :col-num="DEFAULT_MAX_COL" | ||
183 | - :row-height="30" | ||
184 | - :margin="[DEFAULT_ITEM_MARIGN, DEFAULT_ITEM_MARIGN]" | ||
185 | - :is-draggable="draggable" | ||
186 | - :is-resizable="resizable" | ||
187 | - :vertical-compact="true" | ||
188 | - :use-css-transforms="true" | ||
189 | - style="width: 100%" | ||
190 | - > | ||
191 | - <GridItem | ||
192 | - v-for="item in dataSource" | ||
193 | - :key="item.i" | ||
194 | - :static="item.static" | ||
195 | - :x="item.x" | ||
196 | - :y="item.y" | ||
197 | - :w="item.w" | ||
198 | - :h="item.h" | ||
199 | - :i="item.i" | ||
200 | - :min-h="DEFAULT_MIN_HEIGHT" | ||
201 | - :min-w="DEFAULT_MIN_WIDTH" | ||
202 | - :style="{ display: 'flex', flexWrap: 'wrap' }" | ||
203 | - class="grid-item-layout" | ||
204 | - @resized="resized" | ||
205 | - @resize="resize" | ||
206 | - @moved="moved" | ||
207 | - @container-resized="containerResized" | ||
208 | - drag-ignore-from=".no-drag" | 218 | + <div class="w-full h-full flex justify-center items-center mb-3"> |
219 | + <div | ||
220 | + :style=" | ||
221 | + !getIsAppPage && isPhone() | ||
222 | + ? { | ||
223 | + width: phoneSize.width + 'px', | ||
224 | + height: phoneSize.height + 'px', | ||
225 | + border: '2px solid #e5e7eb', | ||
226 | + } | ||
227 | + : { width: '100%', height: '100%' } | ||
228 | + " | ||
229 | + style="border-radius: 1%" | ||
209 | > | 230 | > |
210 | - <WidgetWrapper> | ||
211 | - <template #header> | ||
212 | - <WidgetHeader | ||
213 | - :raw-data-source="rawDataSource" | ||
214 | - :source-info="item" | ||
215 | - @update="handleUpdateWidget" | ||
216 | - @open-trend="handleOpenTrend" | ||
217 | - @open-alarm="handleOpenAlarm" | ||
218 | - @ok="getDataSource" | ||
219 | - /> | ||
220 | - </template> | ||
221 | - <WidgetDistribute :source-info="item" /> | ||
222 | - </WidgetWrapper> | ||
223 | - </GridItem> | ||
224 | - </GridLayout> | ||
225 | - <Empty | ||
226 | - v-if="!dataSource.length" | ||
227 | - class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" | ||
228 | - /> | 231 | + <!-- 手机端写的模拟样式 --> |
232 | + <div | ||
233 | + v-if="!getIsAppPage && isPhone()" | ||
234 | + style="height: 60px; background: white" | ||
235 | + class="px-1 py-1 relative" | ||
236 | + > | ||
237 | + <div class="flex justify-between"> | ||
238 | + <div>thingskit</div> | ||
239 | + <div class="flex items-center"> | ||
240 | + <img :src="WIFISVG" alt="" class="w-3 h-3" /> | ||
241 | + <img :src="SIGNALSVG" alt="" class="w-3 h-3 mx-1" /> | ||
242 | + <img :src="BATTERYSVG" alt="" class="w-4 h-4 rotate-45" /> | ||
243 | + <h1 class="mb-0">18:13</h1> | ||
244 | + </div> | ||
245 | + </div> | ||
246 | + <div class="flex items-center justify-between"> | ||
247 | + <LeftOutlined class="transform cursor-pointer text-lg" /> | ||
248 | + <h1 class="font-bold">{{ getDataBoardName }}</h1> | ||
249 | + <MoreOutlined class="transform rotate-90 cursor-pointer text-lg" /> | ||
250 | + </div> | ||
251 | + </div> | ||
252 | + | ||
253 | + <div | ||
254 | + id="appLayoutId" | ||
255 | + :style=" | ||
256 | + !getIsAppPage && isPhone() ? { height: `calc(${phoneSize.height}px - 67px)` } : {} | ||
257 | + " | ||
258 | + class="overflow-y-scroll" | ||
259 | + > | ||
260 | + <GridLayout | ||
261 | + v-model:layout="dataSource" | ||
262 | + :col-num="DEFAULT_MAX_COL" | ||
263 | + :row-height="30" | ||
264 | + :margin="[DEFAULT_ITEM_MARIGN, DEFAULT_ITEM_MARIGN]" | ||
265 | + :is-draggable="draggable" | ||
266 | + :is-resizable="resizable" | ||
267 | + :vertical-compact="true" | ||
268 | + :use-css-transforms="true" | ||
269 | + style="width: 100%" | ||
270 | + :style="{ | ||
271 | + '--is-app': isPhone() ? 'auto' : 'none', | ||
272 | + }" | ||
273 | + > | ||
274 | + <GridItem | ||
275 | + v-for="item in dataSource" | ||
276 | + :key="item.i" | ||
277 | + :static="item.static" | ||
278 | + :x="item.x" | ||
279 | + :y="item.y" | ||
280 | + :w="item.w" | ||
281 | + :h="item.h" | ||
282 | + :i="item.i" | ||
283 | + :min-h="isPhone() ? PHONE_SIZE.DEFAULT_MIN_HEIGHT : DEFAULT_MIN_HEIGHT" | ||
284 | + :min-w="isPhone() ? PHONE_SIZE.DEFAULT_MIN_WIDTH : DEFAULT_MIN_WIDTH" | ||
285 | + :style="{ display: 'flex', flexWrap: 'wrap' }" | ||
286 | + class="grid-item-layout" | ||
287 | + @resized="resized" | ||
288 | + @resize="resize" | ||
289 | + @moved="moved" | ||
290 | + @container-resized="containerResized" | ||
291 | + drag-ignore-from=".no-drag" | ||
292 | + > | ||
293 | + <WidgetWrapper> | ||
294 | + <template #header> | ||
295 | + <WidgetHeader | ||
296 | + :raw-data-source="rawDataSource" | ||
297 | + :source-info="item" | ||
298 | + @update="handleUpdateWidget" | ||
299 | + @open-trend="handleOpenTrend" | ||
300 | + @open-alarm="handleOpenAlarm" | ||
301 | + @ok="getDataSource" | ||
302 | + /> | ||
303 | + </template> | ||
304 | + <WidgetDistribute :source-info="item" /> | ||
305 | + </WidgetWrapper> | ||
306 | + </GridItem> | ||
307 | + </GridLayout> | ||
308 | + </div> | ||
309 | + <Empty | ||
310 | + v-if="!dataSource.length" | ||
311 | + :class="isPhone() ? 'absolute' : 'fixed'" | ||
312 | + class="top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" | ||
313 | + /> | ||
314 | + </div> | ||
315 | + </div> | ||
229 | </Spin> | 316 | </Spin> |
230 | 317 | ||
231 | <DataSourceBindPanel @register="register" :layout="dataSource" @ok="getDataSource" /> | 318 | <DataSourceBindPanel @register="register" :layout="dataSource" @ok="getDataSource" /> |
@@ -238,4 +325,9 @@ | @@ -238,4 +325,9 @@ | ||
238 | </section> | 325 | </section> |
239 | </template> | 326 | </template> |
240 | 327 | ||
241 | -<style lang="less" scoped></style> | 328 | +<style lang="less"> |
329 | + .vue-grid-item { | ||
330 | + pointer-events: painted; | ||
331 | + touch-action: var(--is-app) !important; | ||
332 | + } | ||
333 | +</style> |
@@ -91,6 +91,7 @@ export interface ComponentLayoutType { | @@ -91,6 +91,7 @@ export interface ComponentLayoutType { | ||
91 | export interface ApiDataBoardDataType { | 91 | export interface ApiDataBoardDataType { |
92 | componentData: ComponentDataType[]; | 92 | componentData: ComponentDataType[]; |
93 | componentLayout: ComponentLayoutType[]; | 93 | componentLayout: ComponentLayoutType[]; |
94 | + phoneModel?: string; | ||
94 | } | 95 | } |
95 | 96 | ||
96 | export interface ApiDataBoardInfoType { | 97 | export interface ApiDataBoardInfoType { |