Showing
18 changed files
with
318 additions
and
51 deletions
... | ... | @@ -22,6 +22,7 @@ enum DataBoardUrl { |
22 | 22 | DELETE_DATA_BOARD = '/data_board', |
23 | 23 | UPDATE_DATA_BOARD = '/data_board/update', |
24 | 24 | UPDATE_DATA_BOARD_LAYOUT = '/data_board', |
25 | + SHARE_DATA_BOARD = '/data_board/share', | |
25 | 26 | } |
26 | 27 | |
27 | 28 | enum DataComponentUrl { |
... | ... | @@ -232,3 +233,16 @@ export const getDeviceRelation = (params: { deviceId: string; isSlave: boolean } |
232 | 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 | +}; | ... | ... |
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 | +}; | ... | ... |
... | ... | @@ -10,7 +10,8 @@ import { getAuthCache } from '/@/utils/auth'; |
10 | 10 | |
11 | 11 | const LOGIN_PATH = PageEnum.BASE_LOGIN; |
12 | 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 | 15 | // const userInfo1 = getAuthCache(USER_INFO_KEY); |
15 | 16 | // const userInfo = ref(userInfo1); |
16 | 17 | |
... | ... | @@ -32,7 +33,7 @@ export function createPermissionGuard(router: Router) { |
32 | 33 | const token = userStore.getJwtToken; |
33 | 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 | 37 | if (to.path === LOGIN_PATH && token) { |
37 | 38 | const isSessionTimeout = userStore.getSessionTimeout; |
38 | 39 | try { | ... | ... |
... | ... | @@ -4,6 +4,7 @@ import { mainOutRoutes } from './mainOut'; |
4 | 4 | import { PageEnum } from '/@/enums/pageEnum'; |
5 | 5 | import { t } from '/@/hooks/web/useI18n'; |
6 | 6 | import { LAYOUT } from '../constant'; |
7 | +import { PUBLIC_PAGE_ROUTER } from './public'; | |
7 | 8 | |
8 | 9 | const modules = import.meta.globEager('./modules/**/*.ts'); |
9 | 10 | const routeModuleList: AppRouteModule[] = []; |
... | ... | @@ -86,4 +87,5 @@ export const basicRoutes = [ |
86 | 87 | REDIRECT_ROUTE, |
87 | 88 | PAGE_NOT_FOUND_ROUTE, |
88 | 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 | 30 | |
31 | 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 | 40 | const handleCreatePanel = async () => { |
34 | 41 | await method.validate(); |
35 | 42 | try { |
36 | - const value = method.getFieldsValue() as AddDataBoardParams; | |
43 | + let value = method.getFieldsValue() as AddDataBoardParams; | |
44 | + value = handleSubmitValue(value); | |
37 | 45 | loading.value = true; |
38 | 46 | changeLoading(true); |
39 | 47 | await addDataBoard(value); |
... | ... | @@ -52,7 +60,8 @@ |
52 | 60 | await method.validate(); |
53 | 61 | try { |
54 | 62 | loading.value = true; |
55 | - const value = method.getFieldsValue() as UpdateDataBoardParams; | |
63 | + let value = method.getFieldsValue() as UpdateDataBoardParams; | |
64 | + value = handleSubmitValue(value); | |
56 | 65 | value.id = unref(recordId) as string; |
57 | 66 | changeLoading(true); |
58 | 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 | 3 | export enum MoreActionEvent { |
2 | 4 | EDIT = 'edit', |
3 | 5 | COPY = 'copy', |
4 | 6 | DELETE = 'delete', |
7 | + SHARE = 'share', | |
5 | 8 | } |
6 | 9 | |
7 | 10 | export enum VisualBoardPermission { |
... | ... | @@ -24,11 +27,8 @@ export const DEFAULT_WIDGET_HEIGHT = 6; |
24 | 27 | export const DEFAULT_MIN_HEIGHT = 5; |
25 | 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 | 33 | export const isBataBoardSharePage = (url: string) => { |
34 | 34 | const reg = /^\/data\/board\/share/g; | ... | ... |
... | ... | @@ -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 | 38 | field: 'remark', |
55 | 39 | label: '备注', |
56 | 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 | 14 | DEFAULT_MIN_WIDTH, |
15 | 15 | DEFAULT_WIDGET_HEIGHT, |
16 | 16 | DEFAULT_WIDGET_WIDTH, |
17 | - isBataBoardSharePage, | |
18 | 17 | MoreActionEvent, |
19 | 18 | VisualComponentPermission, |
20 | 19 | } from '../config/config'; |
... | ... | @@ -22,7 +21,6 @@ |
22 | 21 | addDataComponent, |
23 | 22 | deleteDataComponent, |
24 | 23 | getDataComponent, |
25 | - getShareBoardComponentInfo, | |
26 | 24 | updateDataBoardLayout, |
27 | 25 | } from '/@/api/dataBoard'; |
28 | 26 | import { useRoute, useRouter } from 'vue-router'; |
... | ... | @@ -48,6 +46,10 @@ |
48 | 46 | import { useScript } from '/@/hooks/web/useScript'; |
49 | 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 | 53 | const ROUTE = useRoute(); |
52 | 54 | |
53 | 55 | const ROUTER = useRouter(); |
... | ... | @@ -67,13 +69,12 @@ |
67 | 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 | 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 | 80 | const widgetEl = new Map<string, Fn>(); |
... | ... | @@ -220,19 +221,9 @@ |
220 | 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 | 224 | const getDataBoradDetail = async () => { |
232 | 225 | try { |
233 | - return unref(getIsSharePage) | |
234 | - ? await getSharePageComponentData() | |
235 | - : await getBasePageComponentData(); | |
226 | + return unref(getIsSharePage) ? unref(getSharePageData) : await getBasePageComponentData(); | |
236 | 227 | } catch (error) {} |
237 | 228 | return {} as ComponentInfoDetail; |
238 | 229 | }; |
... | ... | @@ -388,7 +379,7 @@ |
388 | 379 | |
389 | 380 | <template> |
390 | 381 | <section class="flex flex-col overflow-hidden h-full w-full board-detail"> |
391 | - <PageHeader> | |
382 | + <PageHeader v-if="!getIsSharePage"> | |
392 | 383 | <template #title> |
393 | 384 | <div class="flex items-center"> |
394 | 385 | <img | ... | ... |
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | import { encode } from './config/config'; |
22 | 22 | import { useForm, BasicForm } from '/@/components/Form'; |
23 | 23 | import { formSchema } from './config/searchForm'; |
24 | + import ShareModal from './components/ShareModal.vue'; | |
24 | 25 | |
25 | 26 | const ListItem = List.Item; |
26 | 27 | const router = useRouter(); |
... | ... | @@ -77,14 +78,15 @@ |
77 | 78 | getDatasource(); |
78 | 79 | } |
79 | 80 | |
80 | - const createShareUrl = (boardId: string, tenantId: string, name: string) => { | |
81 | + const createShareUrl = (record: DataBoardRecord) => { | |
81 | 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 | 87 | const { clipboardRef } = useCopyToClipboard(); |
86 | 88 | const handleCopyShareUrl = (record: DataBoardRecord) => { |
87 | - clipboardRef.value = createShareUrl(record.id, record.tenantId, record.name); | |
89 | + clipboardRef.value = createShareUrl(record); | |
88 | 90 | unref(clipboardRef) ? createMessage.success('复制成功') : createMessage.error('未找到分享链接'); |
89 | 91 | }; |
90 | 92 | |
... | ... | @@ -92,7 +94,13 @@ |
92 | 94 | const dropMenuList = computed<DropMenu[]>(() => { |
93 | 95 | const hasUpdatePermission = hasPermission(VisualBoardPermission.UPDATE); |
94 | 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 | 104 | if (hasUpdatePermission) |
97 | 105 | basicMenu.push({ |
98 | 106 | text: '编辑', |
... | ... | @@ -124,6 +132,10 @@ |
124 | 132 | } |
125 | 133 | }; |
126 | 134 | |
135 | + const handleOpenShareModal = (record: DataBoardRecord) => { | |
136 | + openShareModal(true, record); | |
137 | + }; | |
138 | + | |
127 | 139 | const handleMenuEvent = (event: DropMenu, record: DataBoardRecord) => { |
128 | 140 | if (event.event === MoreActionEvent.EDIT) handleEdit(record); |
129 | 141 | if (event.event === MoreActionEvent.DELETE) { |
... | ... | @@ -133,6 +145,7 @@ |
133 | 145 | onOk: () => handleRemove(record), |
134 | 146 | }); |
135 | 147 | } |
148 | + if (event.event === MoreActionEvent.SHARE) handleOpenShareModal(record); | |
136 | 149 | }; |
137 | 150 | |
138 | 151 | const handleEdit = (record: DataBoardRecord) => { |
... | ... | @@ -156,6 +169,8 @@ |
156 | 169 | |
157 | 170 | const [registerModal, { openModal }] = useModal(); |
158 | 171 | |
172 | + const [registerShareModal, { openModal: openShareModal }] = useModal(); | |
173 | + | |
159 | 174 | const handleViewBoard = (record: DataBoardRecord) => { |
160 | 175 | const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL); |
161 | 176 | if (hasDetailPermission) { |
... | ... | @@ -238,10 +253,7 @@ |
238 | 253 | <span> |
239 | 254 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} |
240 | 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 | 257 | <Tooltip title="点击复制分享链接"> |
246 | 258 | <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" /> |
247 | 259 | </Tooltip> |
... | ... | @@ -255,6 +267,7 @@ |
255 | 267 | </template> |
256 | 268 | </List> |
257 | 269 | </Spin> |
270 | + <ShareModal @register="registerShareModal" @success="getDatasource" /> | |
258 | 271 | <PanelDetailModal @register="registerModal" @change="getDatasource" /> |
259 | 272 | </PageWrapper> |
260 | 273 | </template> | ... | ... |