Showing
18 changed files
with
318 additions
and
51 deletions
@@ -22,6 +22,7 @@ enum DataBoardUrl { | @@ -22,6 +22,7 @@ enum DataBoardUrl { | ||
22 | DELETE_DATA_BOARD = '/data_board', | 22 | DELETE_DATA_BOARD = '/data_board', |
23 | UPDATE_DATA_BOARD = '/data_board/update', | 23 | UPDATE_DATA_BOARD = '/data_board/update', |
24 | UPDATE_DATA_BOARD_LAYOUT = '/data_board', | 24 | UPDATE_DATA_BOARD_LAYOUT = '/data_board', |
25 | + SHARE_DATA_BOARD = '/data_board/share', | ||
25 | } | 26 | } |
26 | 27 | ||
27 | enum DataComponentUrl { | 28 | enum DataComponentUrl { |
@@ -232,3 +233,16 @@ export const getDeviceRelation = (params: { deviceId: string; isSlave: boolean } | @@ -232,3 +233,16 @@ export const getDeviceRelation = (params: { deviceId: string; isSlave: boolean } | ||
232 | params, | 233 | params, |
233 | }); | 234 | }); |
234 | }; | 235 | }; |
236 | + | ||
237 | +export const shareBoard = (record: { | ||
238 | + id: string; | ||
239 | + accessCredentials?: string; | ||
240 | + isShare?: boolean; | ||
241 | +}) => { | ||
242 | + const { id, isShare, accessCredentials } = record; | ||
243 | + return defHttp.post({ | ||
244 | + url: `${DataBoardUrl.SHARE_DATA_BOARD}/${id}?isShare=${isShare}${ | ||
245 | + accessCredentials ? `&accessCredentials=${accessCredentials}` : '' | ||
246 | + }`, | ||
247 | + }); | ||
248 | +}; |
@@ -48,6 +48,8 @@ export interface DataBoardRecord { | @@ -48,6 +48,8 @@ export interface DataBoardRecord { | ||
48 | layout: Layout[]; | 48 | layout: Layout[]; |
49 | defaultConfig: string; | 49 | defaultConfig: string; |
50 | tenantStatus: string; | 50 | tenantStatus: string; |
51 | + publicId: string; | ||
52 | + accessCredentials?: string; | ||
51 | } | 53 | } |
52 | 54 | ||
53 | export interface DataBoardList { | 55 | export interface DataBoardList { |
src/api/sys/model/shareModel.ts
0 → 100644
src/api/sys/share.ts
0 → 100644
1 | +import { defHttp } from '/@/utils/http/axios'; | ||
2 | +import { ViewTypeEnum } from '/@/views/sys/share/config/config'; | ||
3 | + | ||
4 | +enum Api { | ||
5 | + CHECK = '/share/check', | ||
6 | + PUBLIC_LOGIN = '/auth/login/public', | ||
7 | + SHARE_CONTENT = '/share', | ||
8 | +} | ||
9 | + | ||
10 | +export const checkShareAccessToken = (type: ViewTypeEnum, id: string) => { | ||
11 | + return defHttp.get<Record<'data', boolean>>({ | ||
12 | + url: `${Api.CHECK}/${type}/${id}`, | ||
13 | + }); | ||
14 | +}; | ||
15 | + | ||
16 | +export const sharePageLogin = (publicId: string) => { | ||
17 | + return defHttp.post<Record<'token' | 'refreshToken', string>>( | ||
18 | + { | ||
19 | + url: Api.PUBLIC_LOGIN, | ||
20 | + data: { publicId }, | ||
21 | + }, | ||
22 | + { | ||
23 | + joinPrefix: false, | ||
24 | + } | ||
25 | + ); | ||
26 | +}; | ||
27 | + | ||
28 | +export const getShareContent = (record: Record<'accessCredentials' | 'id', string>) => { | ||
29 | + const { id, accessCredentials } = record; | ||
30 | + return defHttp.get({ | ||
31 | + url: `${Api.SHARE_CONTENT}/${ViewTypeEnum.DATA_BOARD}/share_data/${id}`, | ||
32 | + params: { accessCredentials }, | ||
33 | + }); | ||
34 | +}; |
@@ -14,4 +14,6 @@ export const PageEnum = { | @@ -14,4 +14,6 @@ export const PageEnum = { | ||
14 | //设备配置 | 14 | //设备配置 |
15 | DEVICE_PROFILE: '/product/profiles', | 15 | DEVICE_PROFILE: '/product/profiles', |
16 | DEVICE_LIST: '/device/list', | 16 | DEVICE_LIST: '/device/list', |
17 | + | ||
18 | + SHARE_PAGE: '/share/:viewType/:id/:publicId', | ||
17 | }; | 19 | }; |
@@ -10,7 +10,8 @@ import { getAuthCache } from '/@/utils/auth'; | @@ -10,7 +10,8 @@ import { getAuthCache } from '/@/utils/auth'; | ||
10 | 10 | ||
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 whitePathList: string[] = [LOGIN_PATH]; | 13 | +const SHARE_PATH = PageEnum.SHARE_PAGE; |
14 | +const whitePathList: string[] = [LOGIN_PATH, SHARE_PATH]; | ||
14 | // const userInfo1 = getAuthCache(USER_INFO_KEY); | 15 | // const userInfo1 = getAuthCache(USER_INFO_KEY); |
15 | // const userInfo = ref(userInfo1); | 16 | // const userInfo = ref(userInfo1); |
16 | 17 | ||
@@ -32,7 +33,7 @@ export function createPermissionGuard(router: Router) { | @@ -32,7 +33,7 @@ export function createPermissionGuard(router: Router) { | ||
32 | const token = userStore.getJwtToken; | 33 | const token = userStore.getJwtToken; |
33 | // Whitelist can be directly entered | 34 | // Whitelist can be directly entered |
34 | // 路由守卫拦截, 如果是已经登陆情况, 就不要回到登陆页面了; | 35 | // 路由守卫拦截, 如果是已经登陆情况, 就不要回到登陆页面了; |
35 | - if (whitePathList.includes(to.path as PageEnum)) { | 36 | + if (to.matched.find((item) => whitePathList.includes(item.path))) { |
36 | if (to.path === LOGIN_PATH && token) { | 37 | if (to.path === LOGIN_PATH && token) { |
37 | const isSessionTimeout = userStore.getSessionTimeout; | 38 | const isSessionTimeout = userStore.getSessionTimeout; |
38 | try { | 39 | try { |
@@ -4,6 +4,7 @@ import { mainOutRoutes } from './mainOut'; | @@ -4,6 +4,7 @@ import { mainOutRoutes } from './mainOut'; | ||
4 | import { PageEnum } from '/@/enums/pageEnum'; | 4 | 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 | 8 | ||
8 | const modules = import.meta.globEager('./modules/**/*.ts'); | 9 | const modules = import.meta.globEager('./modules/**/*.ts'); |
9 | const routeModuleList: AppRouteModule[] = []; | 10 | const routeModuleList: AppRouteModule[] = []; |
@@ -86,4 +87,5 @@ export const basicRoutes = [ | @@ -86,4 +87,5 @@ export const basicRoutes = [ | ||
86 | REDIRECT_ROUTE, | 87 | REDIRECT_ROUTE, |
87 | PAGE_NOT_FOUND_ROUTE, | 88 | PAGE_NOT_FOUND_ROUTE, |
88 | DATA_BOARD_SHARE, | 89 | DATA_BOARD_SHARE, |
90 | + PUBLIC_PAGE_ROUTER, | ||
89 | ]; | 91 | ]; |
src/router/routes/public.ts
0 → 100644
1 | +import { AppRouteRecordRaw } from '../types'; | ||
2 | +import { PageEnum } from '/@/enums/pageEnum'; | ||
3 | + | ||
4 | +export const PUBLIC_PAGE_ROUTER: AppRouteRecordRaw = { | ||
5 | + path: PageEnum.SHARE_PAGE, | ||
6 | + name: 'publicPage', | ||
7 | + component: () => import('/@/views/sys/share/index.vue'), | ||
8 | + meta: { | ||
9 | + title: '公开', | ||
10 | + hideBreadcrumb: true, | ||
11 | + hideChildrenInMenu: true, | ||
12 | + }, | ||
13 | +}; |
src/views/sys/share/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/share/index.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { onMounted } from 'vue'; | ||
3 | + import { BasicModal, useModal } from '/@/components/Modal'; | ||
4 | + import { Spin } from 'ant-design-vue'; | ||
5 | + import { ref } from 'vue'; | ||
6 | + import { useRoute } from 'vue-router'; | ||
7 | + import { checkShareAccessToken, sharePageLogin, getShareContent } from '/@/api/sys/share'; | ||
8 | + import { ShareRouteParams } from '/@/api/sys/model/shareModel'; | ||
9 | + import { useUserStore } from '/@/store/modules/user'; | ||
10 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
11 | + import { FieldsEnum } from '../../visual/board/config/share'; | ||
12 | + import BoardDetail from '/@/views/visual/board/detail/index.vue'; | ||
13 | + | ||
14 | + const loading = ref(true); | ||
15 | + const ROUTE = useRoute(); | ||
16 | + const contentData = ref<any>(); | ||
17 | + const canLoadComponent = ref(false); | ||
18 | + | ||
19 | + const [register, { openModal }] = useModal(); | ||
20 | + | ||
21 | + const [registerForm, { getFieldsValue }] = useForm({ | ||
22 | + schemas: [ | ||
23 | + { | ||
24 | + field: FieldsEnum.ACCESS_CREDENTIALS, | ||
25 | + component: 'Input', | ||
26 | + label: '访问令牌', | ||
27 | + }, | ||
28 | + ], | ||
29 | + showActionButtonGroup: false, | ||
30 | + layout: 'inline', | ||
31 | + labelWidth: 100, | ||
32 | + }); | ||
33 | + | ||
34 | + const userStore = useUserStore(); | ||
35 | + | ||
36 | + const getShareToken = async () => { | ||
37 | + const { params } = ROUTE; | ||
38 | + const { publicId } = params as Partial<ShareRouteParams>; | ||
39 | + const { token, refreshToken } = await sharePageLogin(publicId!); | ||
40 | + userStore.storeToken(token, refreshToken); | ||
41 | + }; | ||
42 | + | ||
43 | + const getCheckNeedAccessToken = async () => { | ||
44 | + const { params } = ROUTE; | ||
45 | + loading.value = true; | ||
46 | + const { viewType, id } = params as Partial<ShareRouteParams>; | ||
47 | + const { data } = await checkShareAccessToken(viewType!, id!); | ||
48 | + data ? openModal(data) : await getContentData(); | ||
49 | + }; | ||
50 | + | ||
51 | + const getContentLoading = ref(false); | ||
52 | + const getContentData = async () => { | ||
53 | + try { | ||
54 | + getContentLoading.value = true; | ||
55 | + const { params } = ROUTE; | ||
56 | + const { id } = params as unknown as ShareRouteParams; | ||
57 | + const value = getFieldsValue() as Record<'accessCredentials', string>; | ||
58 | + const result = await getShareContent({ id, ...value }); | ||
59 | + contentData.value = result; | ||
60 | + loading.value = false; | ||
61 | + canLoadComponent.value = true; | ||
62 | + openModal(false); | ||
63 | + } catch (error) { | ||
64 | + } finally { | ||
65 | + getContentLoading.value = false; | ||
66 | + } | ||
67 | + }; | ||
68 | + | ||
69 | + const handleSubmit = async () => { | ||
70 | + await getContentData(); | ||
71 | + }; | ||
72 | + | ||
73 | + onMounted(async () => { | ||
74 | + await getShareToken(); | ||
75 | + await getCheckNeedAccessToken(); | ||
76 | + }); | ||
77 | +</script> | ||
78 | + | ||
79 | +<template> | ||
80 | + <BasicModal | ||
81 | + @register="register" | ||
82 | + title="公开" | ||
83 | + @ok="handleSubmit" | ||
84 | + :showCancelBtn="false" | ||
85 | + :okButtonProps="{ loading: getContentLoading }" | ||
86 | + > | ||
87 | + <BasicForm @register="registerForm" /> | ||
88 | + </BasicModal> | ||
89 | + <Spin | ||
90 | + :spinning="loading" | ||
91 | + tip="正在加载中..." | ||
92 | + size="large" | ||
93 | + class="!flex justify-center items-center w-full h-full share-full-loading" | ||
94 | + > | ||
95 | + <BoardDetail v-if="canLoadComponent" :value="contentData" /> | ||
96 | + </Spin> | ||
97 | +</template> | ||
98 | + | ||
99 | +<style lang="less" scoped></style> |
@@ -30,10 +30,18 @@ | @@ -30,10 +30,18 @@ | ||
30 | 30 | ||
31 | const { createMessage } = useMessage(); | 31 | const { createMessage } = useMessage(); |
32 | 32 | ||
33 | + const handleSubmitValue = (value: Recordable) => { | ||
34 | + if (!Reflect.get(value, 'accessCredentials')) { | ||
35 | + Reflect.deleteProperty(value, 'accessCredentials'); | ||
36 | + } | ||
37 | + return value as any; | ||
38 | + }; | ||
39 | + | ||
33 | const handleCreatePanel = async () => { | 40 | const handleCreatePanel = async () => { |
34 | await method.validate(); | 41 | await method.validate(); |
35 | try { | 42 | try { |
36 | - const value = method.getFieldsValue() as AddDataBoardParams; | 43 | + let value = method.getFieldsValue() as AddDataBoardParams; |
44 | + value = handleSubmitValue(value); | ||
37 | loading.value = true; | 45 | loading.value = true; |
38 | changeLoading(true); | 46 | changeLoading(true); |
39 | await addDataBoard(value); | 47 | await addDataBoard(value); |
@@ -52,7 +60,8 @@ | @@ -52,7 +60,8 @@ | ||
52 | await method.validate(); | 60 | await method.validate(); |
53 | try { | 61 | try { |
54 | loading.value = true; | 62 | loading.value = true; |
55 | - const value = method.getFieldsValue() as UpdateDataBoardParams; | 63 | + let value = method.getFieldsValue() as UpdateDataBoardParams; |
64 | + value = handleSubmitValue(value); | ||
56 | value.id = unref(recordId) as string; | 65 | value.id = unref(recordId) as string; |
57 | changeLoading(true); | 66 | changeLoading(true); |
58 | await updateDataBoard(value); | 67 | await updateDataBoard(value); |
1 | +<script lang="ts" setup> | ||
2 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
3 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
4 | + import { FieldsEnum, schemas } from '../config/share'; | ||
5 | + import { DataBoardRecord } from '/@/api/dataBoard/model'; | ||
6 | + import { Alert } from 'ant-design-vue'; | ||
7 | + import { ref, unref } from 'vue'; | ||
8 | + import { shareBoard } from '/@/api/dataBoard'; | ||
9 | + import { ViewType } from '../config/panelDetail'; | ||
10 | + import { nextTick } from 'vue'; | ||
11 | + | ||
12 | + const loading = ref(false); | ||
13 | + const record = ref<DataBoardRecord>({} as unknown as DataBoardRecord); | ||
14 | + | ||
15 | + const [register, { closeModal }] = useModalInner(async (data: DataBoardRecord) => { | ||
16 | + record.value = data; | ||
17 | + await nextTick(); | ||
18 | + setFieldsValue({ | ||
19 | + [FieldsEnum.IS_SHARE]: data.viewType === ViewType.PUBLIC_VIEW, | ||
20 | + [FieldsEnum.ACCESS_CREDENTIALS]: data.accessCredentials, | ||
21 | + }); | ||
22 | + }); | ||
23 | + | ||
24 | + const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({ | ||
25 | + schemas, | ||
26 | + showActionButtonGroup: false, | ||
27 | + layout: 'inline', | ||
28 | + labelWidth: 120, | ||
29 | + }); | ||
30 | + | ||
31 | + const emit = defineEmits(['register', 'success']); | ||
32 | + | ||
33 | + const handleSubmit = async () => { | ||
34 | + try { | ||
35 | + loading.value = true; | ||
36 | + const value = getFieldsValue(); | ||
37 | + const { id } = unref(record); | ||
38 | + await shareBoard({ id, ...value }); | ||
39 | + closeModal(); | ||
40 | + emit('success'); | ||
41 | + } finally { | ||
42 | + loading.value = false; | ||
43 | + } | ||
44 | + }; | ||
45 | +</script> | ||
46 | + | ||
47 | +<template> | ||
48 | + <BasicModal title="分享" @register="register" @ok="handleSubmit" :loading="loading"> | ||
49 | + <Alert | ||
50 | + class="!mb-4" | ||
51 | + type="info" | ||
52 | + message="私有视图只有项目成员可以浏览,公开视图拥有一个公开的 URL,任何人无需登录即可浏览." | ||
53 | + /> | ||
54 | + <BasicForm @register="registerForm" /> | ||
55 | + </BasicModal> | ||
56 | +</template> |
1 | +import { ViewTypeEnum } from '/@/views/sys/share/config/config'; | ||
2 | + | ||
1 | export enum MoreActionEvent { | 3 | export enum MoreActionEvent { |
2 | EDIT = 'edit', | 4 | EDIT = 'edit', |
3 | COPY = 'copy', | 5 | COPY = 'copy', |
4 | DELETE = 'delete', | 6 | DELETE = 'delete', |
7 | + SHARE = 'share', | ||
5 | } | 8 | } |
6 | 9 | ||
7 | export enum VisualBoardPermission { | 10 | export enum VisualBoardPermission { |
@@ -24,11 +27,8 @@ export const DEFAULT_WIDGET_HEIGHT = 6; | @@ -24,11 +27,8 @@ export const DEFAULT_WIDGET_HEIGHT = 6; | ||
24 | export const DEFAULT_MIN_HEIGHT = 5; | 27 | export const DEFAULT_MIN_HEIGHT = 5; |
25 | export const DEFAULT_MIN_WIDTH = 3; | 28 | export const DEFAULT_MIN_WIDTH = 3; |
26 | 29 | ||
27 | -export const DATA_BOARD_SHARE_URL = ( | ||
28 | - boardId = ':boardId', | ||
29 | - tenantId = ':tenantId', | ||
30 | - name = ':boardName?' | ||
31 | -) => `/data/board/share/${boardId}/${tenantId}/${name}`; | 30 | +export const DATA_BOARD_SHARE_URL = (id: string, publicId: string) => |
31 | + `/share/${ViewTypeEnum.DATA_BOARD}/${id}/${publicId}`; | ||
32 | 32 | ||
33 | export const isBataBoardSharePage = (url: string) => { | 33 | export const isBataBoardSharePage = (url: string) => { |
34 | const reg = /^\/data\/board\/share/g; | 34 | const reg = /^\/data\/board\/share/g; |
@@ -35,22 +35,6 @@ export const formSchema: FormSchema[] = [ | @@ -35,22 +35,6 @@ export const formSchema: FormSchema[] = [ | ||
35 | }, | 35 | }, |
36 | }, | 36 | }, |
37 | { | 37 | { |
38 | - field: 'viewType', | ||
39 | - label: '公开性', | ||
40 | - component: 'RadioGroup', | ||
41 | - defaultValue: ViewType.PRIVATE_VIEW, | ||
42 | - helpMessage: [ | ||
43 | - '私有视图只有项目成员可以浏览。公开视图拥有一个公开的 URL,任何人无需登录即可浏览。 ', | ||
44 | - ], | ||
45 | - componentProps: { | ||
46 | - placeholder: '请选择公开性', | ||
47 | - options: [ | ||
48 | - { label: '私有看板', value: ViewType.PRIVATE_VIEW }, | ||
49 | - { label: '公开看板', value: ViewType.PUBLIC_VIEW, disabled: true }, | ||
50 | - ], | ||
51 | - }, | ||
52 | - }, | ||
53 | - { | ||
54 | field: 'remark', | 38 | field: 'remark', |
55 | label: '备注', | 39 | label: '备注', |
56 | component: 'InputTextArea', | 40 | component: 'InputTextArea', |
src/views/visual/board/config/share.ts
0 → 100644
1 | +import { FormSchema } from '/@/components/Form'; | ||
2 | + | ||
3 | +export enum FieldsEnum { | ||
4 | + IS_SHARE = 'isShare', | ||
5 | + ACCESS_CREDENTIALS = 'accessCredentials', | ||
6 | +} | ||
7 | + | ||
8 | +export const schemas: FormSchema[] = [ | ||
9 | + { | ||
10 | + field: FieldsEnum.IS_SHARE, | ||
11 | + label: '公开性', | ||
12 | + component: 'Switch', | ||
13 | + defaultValue: false, | ||
14 | + }, | ||
15 | + { | ||
16 | + field: FieldsEnum.ACCESS_CREDENTIALS, | ||
17 | + label: '访问凭证', | ||
18 | + component: 'Input', | ||
19 | + ifShow: ({ model }) => model[FieldsEnum.IS_SHARE], | ||
20 | + componentProps: { | ||
21 | + maxLength: 64, | ||
22 | + }, | ||
23 | + }, | ||
24 | +]; |
@@ -14,7 +14,6 @@ | @@ -14,7 +14,6 @@ | ||
14 | DEFAULT_MIN_WIDTH, | 14 | DEFAULT_MIN_WIDTH, |
15 | DEFAULT_WIDGET_HEIGHT, | 15 | DEFAULT_WIDGET_HEIGHT, |
16 | DEFAULT_WIDGET_WIDTH, | 16 | DEFAULT_WIDGET_WIDTH, |
17 | - isBataBoardSharePage, | ||
18 | MoreActionEvent, | 17 | MoreActionEvent, |
19 | VisualComponentPermission, | 18 | VisualComponentPermission, |
20 | } from '../config/config'; | 19 | } from '../config/config'; |
@@ -22,7 +21,6 @@ | @@ -22,7 +21,6 @@ | ||
22 | addDataComponent, | 21 | addDataComponent, |
23 | deleteDataComponent, | 22 | deleteDataComponent, |
24 | getDataComponent, | 23 | getDataComponent, |
25 | - getShareBoardComponentInfo, | ||
26 | updateDataBoardLayout, | 24 | updateDataBoardLayout, |
27 | } from '/@/api/dataBoard'; | 25 | } from '/@/api/dataBoard'; |
28 | import { useRoute, useRouter } from 'vue-router'; | 26 | import { useRoute, useRouter } from 'vue-router'; |
@@ -48,6 +46,10 @@ | @@ -48,6 +46,10 @@ | ||
48 | import { useScript } from '/@/hooks/web/useScript'; | 46 | import { useScript } from '/@/hooks/web/useScript'; |
49 | import { BAI_DU_MAP_GL_LIB, BAI_DU_MAP_TRACK_ANIMATION } from '/@/utils/fnUtils'; | 47 | import { BAI_DU_MAP_GL_LIB, BAI_DU_MAP_TRACK_ANIMATION } from '/@/utils/fnUtils'; |
50 | 48 | ||
49 | + const props = defineProps<{ | ||
50 | + value: Recordable; | ||
51 | + }>(); | ||
52 | + | ||
51 | const ROUTE = useRoute(); | 53 | const ROUTE = useRoute(); |
52 | 54 | ||
53 | const ROUTER = useRouter(); | 55 | const ROUTER = useRouter(); |
@@ -67,13 +69,12 @@ | @@ -67,13 +69,12 @@ | ||
67 | return decode((ROUTE.params as { boardName: string }).boardName || ''); | 69 | return decode((ROUTE.params as { boardName: string }).boardName || ''); |
68 | }); | 70 | }); |
69 | 71 | ||
70 | - const getSharePageParams = computed(() => { | ||
71 | - const { boardId, tenantId } = ROUTE.params as { boardId: string; tenantId: string }; | ||
72 | - return { boardId: decode(boardId), tenantId: decode(tenantId) }; | 72 | + const getSharePageData = computed(() => { |
73 | + return props.value; | ||
73 | }); | 74 | }); |
74 | 75 | ||
75 | const getIsSharePage = computed(() => { | 76 | const getIsSharePage = computed(() => { |
76 | - return isBataBoardSharePage(ROUTE.path); | 77 | + return ROUTE.matched.find((item) => item.path === '/share/:viewType/:id/:publicId'); |
77 | }); | 78 | }); |
78 | 79 | ||
79 | const widgetEl = new Map<string, Fn>(); | 80 | const widgetEl = new Map<string, Fn>(); |
@@ -220,19 +221,9 @@ | @@ -220,19 +221,9 @@ | ||
220 | return {} as ComponentInfoDetail; | 221 | return {} as ComponentInfoDetail; |
221 | }; | 222 | }; |
222 | 223 | ||
223 | - const getSharePageComponentData = async () => { | ||
224 | - try { | ||
225 | - const params = unref(getSharePageParams); | ||
226 | - return await getShareBoardComponentInfo(params); | ||
227 | - } catch (error) {} | ||
228 | - return {} as ComponentInfoDetail; | ||
229 | - }; | ||
230 | - | ||
231 | const getDataBoradDetail = async () => { | 224 | const getDataBoradDetail = async () => { |
232 | try { | 225 | try { |
233 | - return unref(getIsSharePage) | ||
234 | - ? await getSharePageComponentData() | ||
235 | - : await getBasePageComponentData(); | 226 | + return unref(getIsSharePage) ? unref(getSharePageData) : await getBasePageComponentData(); |
236 | } catch (error) {} | 227 | } catch (error) {} |
237 | return {} as ComponentInfoDetail; | 228 | return {} as ComponentInfoDetail; |
238 | }; | 229 | }; |
@@ -388,7 +379,7 @@ | @@ -388,7 +379,7 @@ | ||
388 | 379 | ||
389 | <template> | 380 | <template> |
390 | <section class="flex flex-col overflow-hidden h-full w-full board-detail"> | 381 | <section class="flex flex-col overflow-hidden h-full w-full board-detail"> |
391 | - <PageHeader> | 382 | + <PageHeader v-if="!getIsSharePage"> |
392 | <template #title> | 383 | <template #title> |
393 | <div class="flex items-center"> | 384 | <div class="flex items-center"> |
394 | <img | 385 | <img |
@@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
21 | import { encode } from './config/config'; | 21 | import { encode } from './config/config'; |
22 | import { useForm, BasicForm } from '/@/components/Form'; | 22 | import { useForm, BasicForm } from '/@/components/Form'; |
23 | import { formSchema } from './config/searchForm'; | 23 | import { formSchema } from './config/searchForm'; |
24 | + import ShareModal from './components/ShareModal.vue'; | ||
24 | 25 | ||
25 | const ListItem = List.Item; | 26 | const ListItem = List.Item; |
26 | const router = useRouter(); | 27 | const router = useRouter(); |
@@ -77,14 +78,15 @@ | @@ -77,14 +78,15 @@ | ||
77 | getDatasource(); | 78 | getDatasource(); |
78 | } | 79 | } |
79 | 80 | ||
80 | - const createShareUrl = (boardId: string, tenantId: string, name: string) => { | 81 | + const createShareUrl = (record: DataBoardRecord) => { |
81 | const { origin } = location; | 82 | const { origin } = location; |
82 | - return `${origin}${DATA_BOARD_SHARE_URL(encode(boardId), encode(tenantId), encode(name))}`; | 83 | + const { id, publicId } = record; |
84 | + return `${origin}${DATA_BOARD_SHARE_URL(id, publicId)}`; | ||
83 | }; | 85 | }; |
84 | 86 | ||
85 | const { clipboardRef } = useCopyToClipboard(); | 87 | const { clipboardRef } = useCopyToClipboard(); |
86 | const handleCopyShareUrl = (record: DataBoardRecord) => { | 88 | const handleCopyShareUrl = (record: DataBoardRecord) => { |
87 | - clipboardRef.value = createShareUrl(record.id, record.tenantId, record.name); | 89 | + clipboardRef.value = createShareUrl(record); |
88 | unref(clipboardRef) ? createMessage.success('复制成功') : createMessage.error('未找到分享链接'); | 90 | unref(clipboardRef) ? createMessage.success('复制成功') : createMessage.error('未找到分享链接'); |
89 | }; | 91 | }; |
90 | 92 | ||
@@ -92,7 +94,13 @@ | @@ -92,7 +94,13 @@ | ||
92 | const dropMenuList = computed<DropMenu[]>(() => { | 94 | const dropMenuList = computed<DropMenu[]>(() => { |
93 | const hasUpdatePermission = hasPermission(VisualBoardPermission.UPDATE); | 95 | const hasUpdatePermission = hasPermission(VisualBoardPermission.UPDATE); |
94 | const hasDeletePermission = hasPermission(VisualBoardPermission.DELETE); | 96 | const hasDeletePermission = hasPermission(VisualBoardPermission.DELETE); |
95 | - const basicMenu: DropMenu[] = []; | 97 | + const basicMenu: DropMenu[] = [ |
98 | + { | ||
99 | + text: '分享', | ||
100 | + event: MoreActionEvent.SHARE, | ||
101 | + icon: 'ant-design:share-alt-outlined', | ||
102 | + }, | ||
103 | + ]; | ||
96 | if (hasUpdatePermission) | 104 | if (hasUpdatePermission) |
97 | basicMenu.push({ | 105 | basicMenu.push({ |
98 | text: '编辑', | 106 | text: '编辑', |
@@ -124,6 +132,10 @@ | @@ -124,6 +132,10 @@ | ||
124 | } | 132 | } |
125 | }; | 133 | }; |
126 | 134 | ||
135 | + const handleOpenShareModal = (record: DataBoardRecord) => { | ||
136 | + openShareModal(true, record); | ||
137 | + }; | ||
138 | + | ||
127 | const handleMenuEvent = (event: DropMenu, record: DataBoardRecord) => { | 139 | const handleMenuEvent = (event: DropMenu, record: DataBoardRecord) => { |
128 | if (event.event === MoreActionEvent.EDIT) handleEdit(record); | 140 | if (event.event === MoreActionEvent.EDIT) handleEdit(record); |
129 | if (event.event === MoreActionEvent.DELETE) { | 141 | if (event.event === MoreActionEvent.DELETE) { |
@@ -133,6 +145,7 @@ | @@ -133,6 +145,7 @@ | ||
133 | onOk: () => handleRemove(record), | 145 | onOk: () => handleRemove(record), |
134 | }); | 146 | }); |
135 | } | 147 | } |
148 | + if (event.event === MoreActionEvent.SHARE) handleOpenShareModal(record); | ||
136 | }; | 149 | }; |
137 | 150 | ||
138 | const handleEdit = (record: DataBoardRecord) => { | 151 | const handleEdit = (record: DataBoardRecord) => { |
@@ -156,6 +169,8 @@ | @@ -156,6 +169,8 @@ | ||
156 | 169 | ||
157 | const [registerModal, { openModal }] = useModal(); | 170 | const [registerModal, { openModal }] = useModal(); |
158 | 171 | ||
172 | + const [registerShareModal, { openModal: openShareModal }] = useModal(); | ||
173 | + | ||
159 | const handleViewBoard = (record: DataBoardRecord) => { | 174 | const handleViewBoard = (record: DataBoardRecord) => { |
160 | const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL); | 175 | const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL); |
161 | if (hasDetailPermission) { | 176 | if (hasDetailPermission) { |
@@ -238,10 +253,7 @@ | @@ -238,10 +253,7 @@ | ||
238 | <span> | 253 | <span> |
239 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} | 254 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} |
240 | </span> | 255 | </span> |
241 | - <span | ||
242 | - style="display: none" | ||
243 | - v-if="item.viewType === ViewType.PUBLIC_VIEW && false" | ||
244 | - > | 256 | + <span v-if="item.viewType === ViewType.PUBLIC_VIEW"> |
245 | <Tooltip title="点击复制分享链接"> | 257 | <Tooltip title="点击复制分享链接"> |
246 | <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" /> | 258 | <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" /> |
247 | </Tooltip> | 259 | </Tooltip> |
@@ -255,6 +267,7 @@ | @@ -255,6 +267,7 @@ | ||
255 | </template> | 267 | </template> |
256 | </List> | 268 | </List> |
257 | </Spin> | 269 | </Spin> |
270 | + <ShareModal @register="registerShareModal" @success="getDatasource" /> | ||
258 | <PanelDetailModal @register="registerModal" @change="getDatasource" /> | 271 | <PanelDetailModal @register="registerModal" @change="getDatasource" /> |
259 | </PageWrapper> | 272 | </PageWrapper> |
260 | </template> | 273 | </template> |