Commit dc4c118afca81acdee8c67c46edc779a8e2dbaad

Authored by xp.Huang
2 parents 263e9ac3 88fb959f

Merge branch 'dev-ww' into 'main_dev'

perf(share page): 优化分享页面的携带token影响当前用户在IOT平台操作

See merge request yunteng/thingskit-view!43
  1 +import type { ErrorMessageMode } from '/#/external/axios';
  2 +
  3 +export function checkStatus(
  4 + status: number,
  5 + msg: string,
  6 + errorMessageMode: ErrorMessageMode = 'message'
  7 +) {
  8 + let errMessage = msg;
  9 + switch (status) {
  10 + case 400:
  11 + errMessage = `${msg}`;
  12 + break;
  13 + // 401: Not logged in
  14 + // Jump to the login page if not logged in, and carry the path of the current page
  15 + // Return to the current page after successful login. This step needs to be operated on the login page.
  16 + case 401:
  17 + errMessage = '没有权限';
  18 + break;
  19 + case 403:
  20 + errMessage = '未授权';
  21 + break;
  22 + // 404请求不存在
  23 + case 404:
  24 + errMessage = '未找到该资源!';
  25 + break;
  26 + case 405:
  27 + errMessage = '网络请求错误,请求方法未允许!';
  28 + break;
  29 + case 408:
  30 + errMessage = '网络请求超时!';
  31 + break;
  32 + case 500:
  33 + errMessage = '服务器错误,请联系管理员!';
  34 + break;
  35 + case 501:
  36 + errMessage = '网络未实现!';
  37 + break;
  38 + case 502:
  39 + errMessage = '网络错误!';
  40 + break;
  41 + case 503:
  42 + errMessage = '服务不可用,服务器暂时过载或维护!';
  43 + break;
  44 + case 504:
  45 + errMessage = '网络超时!';
  46 + break;
  47 + case 505:
  48 + errMessage = 'http版本不支持该请求!';
  49 + break;
  50 + default:
  51 + }
  52 +
  53 + if (errMessage) {
  54 + if (errorMessageMode === 'message') {
  55 + const { error } = window['$message']
  56 + error(errMessage);
  57 + }
  58 + }
  59 + return !!errMessage
  60 +}
... ...
  1 +import type { AxiosResponse } from 'axios';
  2 +import type { RequestOptions, Result } from '/#/external/axios';
  3 +import type { AxiosTransform, CreateAxiosOptions } from '@/utils/external/http/axios/axiosTransform';
  4 +import { useGlobSetting } from '@/hooks/external/setting';
  5 +import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum';
  6 +import { isString } from '@/utils/external/is';
  7 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth';
  8 +import { setObjToUrlParams, deepMerge } from '@/utils/external';
  9 +import { formatRequestDate, joinTimestamp } from '@/utils/external/http/axios/helper';
  10 +import { VAxios } from '@/utils/external/http/axios/Axios';
  11 +import { checkStatus } from './checkStatus';
  12 +
  13 +const globSetting = useGlobSetting();
  14 +const urlPrefix = globSetting.urlPrefix;
  15 +
  16 +/**
  17 + * @description: 数据处理,方便区分多种处理方式
  18 + */
  19 +const transform: AxiosTransform = {
  20 + /**
  21 + * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误
  22 + */
  23 + transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
  24 + const { isReturnNativeResponse } = options;
  25 + // 是否返回原生响应头 比如:需要获取响应头时使用该属性
  26 + if (isReturnNativeResponse) {
  27 + return res;
  28 + }
  29 + return res.data;
  30 + },
  31 +
  32 + // 请求之前处理config
  33 + beforeRequestHook: (config, options) => {
  34 + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;
  35 +
  36 + if (joinPrefix) {
  37 + config.url = `${urlPrefix}${config.url}`;
  38 + }
  39 +
  40 + if (apiUrl && isString(apiUrl)) {
  41 + config.url = `${apiUrl}${config.url}`;
  42 + }
  43 +
  44 + const params = config.params || {};
  45 + const data = config.data || false;
  46 + formatDate && data && !isString(data) && formatRequestDate(data);
  47 + if (config.method?.toUpperCase() === RequestEnum.GET) {
  48 + if (!isString(params)) {
  49 + // 给 get 请求加上时间戳参数,避免从缓存中拿数据。
  50 + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
  51 + } else {
  52 + // 兼容restful风格
  53 + config.url = config.url + params + `${joinTimestamp(joinTime, true)}`;
  54 + config.params = undefined;
  55 + }
  56 + } else {
  57 + if (!isString(params)) {
  58 + formatDate && formatRequestDate(params);
  59 + if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) {
  60 + config.data = data;
  61 + config.params = params;
  62 + } else {
  63 + // 非GET请求如果没有提供data,则将params视为data
  64 + config.data = params;
  65 + config.params = undefined;
  66 + }
  67 + if (joinParamsToUrl) {
  68 + config.url = setObjToUrlParams(
  69 + config.url as string,
  70 + Object.assign({}, config.params, config.data)
  71 + );
  72 + }
  73 + } else {
  74 + // 兼容restful风格
  75 + config.url = config.url + params;
  76 + config.params = undefined;
  77 + }
  78 + }
  79 + return config;
  80 + },
  81 +
  82 + /**
  83 + * @description: 请求拦截器处理
  84 + */
  85 + requestInterceptors: (config, options) => {
  86 + // 请求之前处理config
  87 + const { requestOptions } = config;
  88 + const { withShareToken } = requestOptions || {};
  89 + const { requestOptions: { withToken } = {} } = options;
  90 + if (withToken !== false) {
  91 + const shareToken = getShareJwtToken();
  92 + if (withShareToken && shareToken) {
  93 + config.headers!['X-Authorization'] = options.authenticationScheme
  94 + ? `${options.authenticationScheme} ${shareToken}`
  95 + : shareToken;
  96 + } else {
  97 + const token = getJwtToken();
  98 + if (token) {
  99 + config.headers!['X-Authorization'] = options.authenticationScheme
  100 + ? `${options.authenticationScheme} ${token}`
  101 + : token;
  102 + }
  103 + }
  104 + }
  105 + return config
  106 + },
  107 +
  108 + /**
  109 + * @description: 响应拦截器处理
  110 + */
  111 + responseInterceptors: (res: AxiosResponse<any>) => {
  112 + return res;
  113 + },
  114 +
  115 + /**
  116 + * @description: 响应错误处理
  117 + */
  118 + responseInterceptorsCatch: (error: any) => {
  119 +
  120 + const { response, config } = error || {};
  121 + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none';
  122 + const errorMsgIsObj = typeof response?.data === 'object';
  123 + const msg: string = errorMsgIsObj
  124 + ? response?.data?.message || response?.data?.msg
  125 + : response?.data;
  126 +
  127 + const flag = checkStatus(error?.response?.status, msg, errorMessageMode);
  128 + return Promise.reject(response?.data);
  129 + },
  130 +};
  131 +
  132 +function createAxios(opt?: Partial<CreateAxiosOptions>) {
  133 + return new VAxios(
  134 + deepMerge(
  135 + {
  136 + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
  137 + // authentication schemes,e.g: Bearer
  138 + // authenticationScheme: 'Bearer',
  139 + authenticationScheme: 'Bearer',
  140 + timeout: 10 * 1000,
  141 + // 基础接口地址
  142 + // baseURL: globSetting.apiUrl,
  143 + // 接口可能会有通用的地址部分,可以统一抽取出来
  144 + urlPrefix: urlPrefix,
  145 + headers: { 'Content-Type': ContentTypeEnum.JSON },
  146 + // 如果是form-data格式
  147 + // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
  148 + // 数据处理方式
  149 + transform,
  150 + // 配置项,下面的选项都可以在独立的接口请求中覆盖
  151 + requestOptions: {
  152 + // 默认将prefix 添加到url
  153 + joinPrefix: true,
  154 + // 是否返回原生响应头 比如:需要获取响应头时使用该属性
  155 + isReturnNativeResponse: false,
  156 + // 需要对返回数据进行处理
  157 + isTransformResponse: true,
  158 + // post请求的时候添加参数到url
  159 + joinParamsToUrl: false,
  160 + // 格式化提交参数时间
  161 + formatDate: true,
  162 + // 消息提示类型
  163 + errorMessageMode: 'message',
  164 + // 接口地址
  165 + apiUrl: globSetting.apiUrl,
  166 + // 是否加入时间戳
  167 + joinTime: true,
  168 + // 忽略重复请求
  169 + ignoreCancelToken: true,
  170 + // 是否携带token
  171 + withToken: true
  172 + },
  173 + },
  174 + opt || {}
  175 + )
  176 + );
  177 +}
  178 +export const customHttp = createAxios();
  179 +
... ...
1 1 import { RequestBodyEnum, RequestParams } from "@/enums/httpEnum"
2   -import { ExternalRequestType, ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d"
3   -import { RequestConfigType, RequestGlobalConfigType } from "@/store/modules/chartEditStore/chartEditStore.d"
4   -import { defHttp } from "@/utils/external/http/axios"
  2 +import { ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d"
  3 +import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d"
  4 +import { isShareMode } from "@/views/share/hook"
  5 +import { customHttp } from "./http"
5 6
6 7 export enum ParamsType {
7 8 REQUIRED,
... ... @@ -86,7 +87,7 @@ const transformBodyValue = (body: RequestParams['Body'], requestParamsBodyType:
86 87
87 88 const extraValue = (object: Recordable) => {
88 89 return Object.keys(object).reduce((prev, next) => {
89   - return {...prev, ...(object[next] ? {[next]: object[next]} : {} )}
  90 + return { ...prev, ...(object[next] ? { [next]: object[next] } : {}) }
90 91 }, {})
91 92 }
92 93
... ... @@ -103,8 +104,8 @@ export const customRequest = async (request: RequestConfigType) => {
103 104 }
104 105
105 106 const body = transformBodyValue(Body, requestParamsBodyType)
106   -
107   - return defHttp.request<any>({
  107 +
  108 + return customHttp.request<any>({
108 109 url: requestUrl,
109 110 baseURL: getOriginUrl(requestOriginUrl!),
110 111 method: requestHttpType,
... ... @@ -113,6 +114,7 @@ export const customRequest = async (request: RequestConfigType) => {
113 114 headers: extraValue(Header)
114 115 }, {
115 116 joinPrefix: false,
116   - apiUrl: ''
  117 + apiUrl: '',
  118 + withShareToken: isShareMode()
117 119 })
118 120 }
... ...
1 1 import { ViewTypeEnum } from "@/enums/external/viewEnum"
2 2 import { defHttp } from "@/utils/external/http/axios"
  3 +import { isShareMode } from "@/views/share/hook"
3 4
4 5 enum Api {
5 6 TOKEN = '/auth/login/public',
... ... @@ -17,7 +18,7 @@ export const getPublicToken = (publicId: string) => {
17 18 return defHttp.post<Record<'token' | 'refreshToken', string>>({
18 19 url: Api.TOKEN,
19 20 data: { publicId }
20   - }, { joinPrefix: false })
  21 + }, { joinPrefix: false, withShareToken: isShareMode() })
21 22 }
22 23
23 24 /**
... ... @@ -27,7 +28,7 @@ export const getPublicToken = (publicId: string) => {
27 28 export const checkSharePageNeedAccessToken = (id: string) => {
28 29 return defHttp.get<{ data: boolean }>({
29 30 url: `${Api.CHECK}/${ViewTypeEnum.LARGE_SCREEN}/${id}`
30   - })
  31 + }, { withShareToken: isShareMode() })
31 32 }
32 33
33 34 /**
... ... @@ -39,5 +40,5 @@ export const getShareContentData = (options: Record<'id' | 'accessCredentials',
39 40 return defHttp.get<{ data: any }>({
40 41 url: `${Api.SHARE_CONTENT}/${ViewTypeEnum.LARGE_SCREEN}/share_data/${options.id}`,
41 42 params: accessCredentials ? { accessCredentials } : {}
42   - })
  43 + }, { withShareToken: isShareMode() })
43 44 }
... ...
... ... @@ -5,6 +5,10 @@ export const JWT_TOKEN_KEY = 'JWT_TOKEN';
5 5
6 6 export const REFRESH_TOKEN_KEY = 'REFRESH_TOKEN';
7 7
  8 +export const SHARE_JWT_TOKEN_KEY = 'SHARE_JWT_TOKEN';
  9 +
  10 +export const SHARE_REFRESH_TOKEN_KEY = 'SHARE_REFRESH_TOKEN';
  11 +
8 12 export const LOCALE_KEY = 'LOCALE__';
9 13
10 14 // user info key
... ...
... ... @@ -3,10 +3,11 @@ import { CreateComponentType } from "@/packages/index.d";
3 3 import { useSocketStore } from "@/store/external/modules/socketStore";
4 4 import { SocketReceiveMessageType } from "@/store/external/modules/socketStore.d";
5 5 import { useChartEditStore } from "@/store/modules/chartEditStore/chartEditStore";
6   -import { getJwtToken } from "@/utils/external/auth";
  6 +import { getJwtToken, getShareJwtToken } from "@/utils/external/auth";
7 7 import { useWebSocket, WebSocketResult } from "@vueuse/core";
8 8 import { onMounted, unref } from "vue";
9 9 import { ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d";
  10 +import { isShareMode } from "@/views/share/hook";
10 11
11 12
12 13 interface SocketConnectionPoolType {
... ... @@ -39,7 +40,7 @@ const getSocketInstance = (request: ExtraRequestConfigType) => {
39 40 if (~index) {
40 41 return socketConnectionPool[index].ws
41 42 }
42   - const token = getJwtToken()
  43 + const token = isShareMode() ? getShareJwtToken() : getJwtToken()
43 44 const socketUrl = `${getOriginUrl(requestOriginUrl || '')}${requestUrl}?token=${token}`
44 45
45 46 const instance = useWebSocket(socketUrl, {
... ...
... ... @@ -3,7 +3,7 @@ import type { ErrorMessageMode } from '/#/external/axios';
3 3 import { defineStore } from 'pinia';
4 4 import { pinia as store } from '@/store';
5 5 import { RoleEnum } from '@/enums/external/roleEnum';
6   -import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY, ROLES_KEY, USER_INFO_KEY } from '@/enums/external/cacheEnum';
  6 +import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY, ROLES_KEY, SHARE_JWT_TOKEN_KEY, SHARE_REFRESH_TOKEN_KEY, USER_INFO_KEY } from '@/enums/external/cacheEnum';
7 7 import { getAuthCache, getJwtToken, getRefreshToken, setAuthCache } from '@/utils/external/auth';
8 8 import {
9 9 LoginParams,
... ... @@ -29,6 +29,8 @@ interface UserState {
29 29 lastUpdateTime: number;
30 30 jwtToken?: string;
31 31 refreshToken?: string;
  32 + shareJwtToken?: string;
  33 + shareRefreshToken?: string;
32 34 outTarget?: string;
33 35 }
34 36
... ... @@ -47,6 +49,8 @@ export const useUserStore = defineStore({
47 49 jwtToken: getJwtToken() as string || undefined,
48 50 //refresh Token
49 51 refreshToken: getRefreshToken() as string || undefined,
  52 + shareJwtToken: undefined,
  53 + shareRefreshToken: undefined,
50 54 // roleList
51 55 roleList: [],
52 56 // Whether the login expired
... ... @@ -96,6 +100,12 @@ export const useUserStore = defineStore({
96 100 setAuthCache(JWT_TOKEN_KEY, jwtToken);
97 101 setAuthCache(REFRESH_TOKEN_KEY, refreshToken);
98 102 },
  103 + storeShareToken(jwtToken: string, refreshToken: string) {
  104 + this.shareJwtToken = jwtToken;
  105 + this.shareRefreshToken = refreshToken;
  106 + setAuthCache(SHARE_JWT_TOKEN_KEY, jwtToken);
  107 + setAuthCache(SHARE_REFRESH_TOKEN_KEY, refreshToken);
  108 + },
99 109 setToken(info: string | undefined) {
100 110 this.jwtToken = info;
101 111 setAuthCache(JWT_TOKEN_KEY, info);
... ... @@ -152,14 +162,6 @@ export const useUserStore = defineStore({
152 162 }
153 163 return userInfo;
154 164 },
155   - async smsCodelogin(
156   - params: SmsLoginParams & {
157   - goHome?: boolean;
158   - mode?: ErrorMessageMode;
159   - }
160   - ) {
161   -
162   - },
163 165 async getMyUserInfoAction() {
164 166 const userInfo = await getMyInfo();
165 167 this.setUserInfo(userInfo);
... ... @@ -193,6 +195,20 @@ export const useUserStore = defineStore({
193 195 },
194 196
195 197 /**
  198 + * @description 刷新分享页面的token
  199 + */
  200 + async doShareRefresh() {
  201 + try {
  202 + const req = { refreshToken: this.shareRefreshToken } as RefreshTokenParams
  203 + const { token, refreshToken } = await doRefreshToken(req)
  204 + this.storeShareToken(token, refreshToken)
  205 + } catch (error) {
  206 + window.location.reload()
  207 + throw error
  208 + }
  209 + },
  210 +
  211 + /**
196 212 * @description: Confirm before logging out
197 213 */
198 214 confirmLoginOut() {
... ...
1 1 import { Persistent, BasicKeys } from '@/utils/external/cache/persistent';
2   -import { CacheTypeEnum } from '@/enums/external/cacheEnum';
  2 +import { CacheTypeEnum, SHARE_JWT_TOKEN_KEY, SHARE_REFRESH_TOKEN_KEY } from '@/enums/external/cacheEnum';
3 3 import projectSetting from '@/settings/external/projectSetting';
4 4 import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY } from '@/enums/external/cacheEnum';
5 5
... ... @@ -20,9 +20,17 @@ export function clearAuthCache(immediate = true) {
20 20 const fn = isLocal ? Persistent.clearLocal : Persistent.clearSession;
21 21 return fn(immediate);
22 22 }
23   -export function getJwtToken() {
  23 +export function getJwtToken(): string {
24 24 return getAuthCache(JWT_TOKEN_KEY);
25 25 }
26   -export function getRefreshToken() {
  26 +export function getRefreshToken(): string {
27 27 return getAuthCache(REFRESH_TOKEN_KEY);
28 28 }
  29 +
  30 +export function getShareJwtToken(): string {
  31 + return getAuthCache(SHARE_JWT_TOKEN_KEY);
  32 +}
  33 +export function getShareRefreshToken(): string {
  34 + return getAuthCache(SHARE_REFRESH_TOKEN_KEY);
  35 +}
  36 +
... ...
... ... @@ -17,9 +17,11 @@ import {
17 17 APP_SESSION_CACHE_KEY,
18 18 MULTIPLE_TABS_KEY,
19 19 MENU_LIST,
  20 + SHARE_JWT_TOKEN_KEY,
  21 + SHARE_REFRESH_TOKEN_KEY,
20 22 } from '@/enums/external/cacheEnum';
21 23 import { DEFAULT_CACHE_TIME } from '@/settings/external/encryptionSetting';
22   -import { toRaw } from 'vue';
  24 +import { toRaw } from 'vue';
23 25 import omit from 'lodash/omit';
24 26 import pick from 'lodash/pick';
25 27
... ... @@ -34,6 +36,8 @@ interface BasicStore {
34 36 [PROJ_CFG_KEY]: ProjectConfig;
35 37 [MULTIPLE_TABS_KEY]: RouteLocationNormalized[];
36 38 [MENU_LIST]: any[];
  39 + [SHARE_JWT_TOKEN_KEY]: string
  40 + [SHARE_REFRESH_TOKEN_KEY]: string
37 41 }
38 42
39 43 type LocalStore = BasicStore;
... ...
1   -import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError } from 'axios';
2   -import type { CreateAxiosOptions } from './axiosTransform';
  1 +import type { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
  2 +import type { AxiosRequestConfig, CreateAxiosOptions } from './axiosTransform';
3 3 import axios from 'axios';
4 4 import qs from 'qs';
5 5 import { AxiosCanceler } from './axiosCancel';
... ... @@ -115,13 +115,21 @@ export class VAxios {
115 115 this.axiosInstance.interceptors.request.use(async (config: AxiosRequestConfig) => {
116 116 // If cancel repeat request is turned on, then cancel repeat request is prohibited
117 117 const userStore = useUserStore();
118   - if (userStore && userStore.jwtToken) {
  118 + // if (userStore && (userStore.jwtToken || userStore.shareJwtToken)) {
  119 + if (userStore) {
119 120 try {
120   - const res = jwt_decode(userStore.jwtToken) as JwtModel;
121   - const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000;
122   - if (currentTime >= res.exp && this.isNeedTokenURL(config.url!)) {
123   - await this.refreshTokenBeforeReq(userStore.doRefresh);
  121 + const { requestOptions = {} } = config
  122 + const { withShareToken, withToken } = requestOptions
  123 + const token = withShareToken && withToken ? userStore.shareJwtToken : userStore.jwtToken
  124 + const doRefresh = withShareToken && withToken ? userStore.doShareRefresh : userStore.doRefresh
  125 + if (token) {
  126 + const res = jwt_decode(token) as JwtModel;
  127 + const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000;
  128 + if (currentTime >= res.exp && this.isNeedTokenURL(config.url!)) {
  129 + await this.refreshTokenBeforeReq(doRefresh);
  130 + }
124 131 }
  132 +
125 133 } catch (error) {
126 134 userStore.logout();
127 135 }
... ...
1 1 /**
2 2 * Data processing class, can be configured according to the project
3 3 */
4   -import type { AxiosRequestConfig, AxiosResponse } from 'axios';
  4 +import type { AxiosRequestConfig as OriginAxiosRequestConfig, AxiosResponse } from 'axios';
5 5 import type { RequestOptions, Result } from '/#/external/axios';
6 6
7 7 export interface CreateAxiosOptions extends AxiosRequestConfig {
... ... @@ -11,6 +11,8 @@ export interface CreateAxiosOptions extends AxiosRequestConfig {
11 11 requestOptions?: RequestOptions;
12 12 }
13 13
  14 +export type AxiosRequestConfig = OriginAxiosRequestConfig & {requestOptions?: RequestOptions}
  15 +
14 16 export abstract class AxiosTransform {
15 17 /**
16 18 * @description: Process configuration before request
... ...
... ... @@ -9,7 +9,7 @@ import { checkStatus } from './checkStatus';
9 9 import { useGlobSetting } from '@/hooks/external/setting';
10 10 import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum';
11 11 import { isString } from '@/utils/external/is';
12   -import { getJwtToken } from '@/utils/external/auth';
  12 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth';
13 13 import { setObjToUrlParams, deepMerge } from '@/utils/external';
14 14 import { joinTimestamp, formatRequestDate } from './helper';
15 15 import { PageEnum } from '@/enums/external/pageEnum';
... ... @@ -89,14 +89,25 @@ const transform: AxiosTransform = {
89 89 */
90 90 requestInterceptors: (config, options) => {
91 91 // 请求之前处理config
92   - const token = getJwtToken();
93   - if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
94   - // jwt token
95   - config.headers!['X-Authorization'] = options.authenticationScheme
96   - ? `${options.authenticationScheme} ${token}`
97   - : token as string;
  92 + const { requestOptions } = config;
  93 + const { withShareToken } = requestOptions || {};
  94 + const { requestOptions: { withToken } = {} } = options;
  95 + if (withToken !== false) {
  96 + const shareToken = getShareJwtToken();
  97 + if (withShareToken && shareToken) {
  98 + config.headers!['X-Authorization'] = options.authenticationScheme
  99 + ? `${options.authenticationScheme} ${shareToken}`
  100 + : shareToken;
  101 + } else {
  102 + const token = getJwtToken();
  103 + if (token) {
  104 + config.headers!['X-Authorization'] = options.authenticationScheme
  105 + ? `${options.authenticationScheme} ${token}`
  106 + : token;
  107 + }
  108 + }
98 109 }
99   - return config;
  110 + return config
100 111 },
101 112
102 113 /**
... ...
  1 +export const isShareMode = () => {
  2 + const sharePageReg = /^\/share\/[^/]+\/[^/]+\/[^/]+$/;
  3 + const { hash } = location;
  4 + return sharePageReg.test(hash.substring(1));
  5 +};
... ...
... ... @@ -5,10 +5,23 @@
5 5 <NCard>
6 6 <NForm @keyup.enter="handleSubmit">
7 7 <NFormItem label="访问令牌">
8   - <NInput v-model:value="accessCredentials" type="password" />
9   - </NFormItem>
10   - <NFormItem :showLabel="false">
11   - <NButton :loading="loading" type="primary" style="width: 100%;" @click="handleSubmit">访问</NButton>
  8 + <NInputGroup>
  9 + <NInput v-model:value="accessCredentials" show-password-on="mousedown" type="password"
  10 + style="width: 70%;" />
  11 + <NButton :loading="loading" type="primary" style="width: 30%;" @click="handleSubmit">
  12 + <svg t="1682068997810" class="icon" viewBox="0 0 1024 1024" version="1.1"
  13 + xmlns="http://www.w3.org/2000/svg" p-id="79416" width="24" height="24">
  14 + <path
  15 + d="M512 928H128c-19.2 0-32-12.8-32-32V128c0-19.2 12.8-32 32-32h384c19.2 0 32 12.8 32 32s-12.8 32-32 32H160v704h352c19.2 0 32 12.8 32 32s-12.8 32-32 32z"
  16 + fill="#fff" p-id="79417" />
  17 + <path
  18 + d="M534.4 736c-9.6 0-16-3.2-22.4-9.6l-192-192c-12.8-12.8-12.8-32 0-44.8l192-192c12.8-12.8 32-12.8 44.8 0 12.8 12.8 12.8 32 0 44.8L387.2 512l169.6 169.6c12.8 12.8 12.8 32 0 44.8-6.4 6.4-16 9.6-22.4 9.6z"
  19 + fill="#fff" p-id="79418" />
  20 + <path d="M896 544H342.4c-19.2 0-32-12.8-32-32s12.8-32 32-32H896c19.2 0 32 12.8 32 32s-12.8 32-32 32z"
  21 + fill="#fff" p-id="79419" />
  22 + </svg>
  23 + </NButton>
  24 + </NInputGroup>
12 25 </NFormItem>
13 26 </NForm>
14 27 </NCard>
... ... @@ -17,11 +30,11 @@
17 30 </template>
18 31
19 32 <script setup lang="ts">
20   -import { NModal, NCard, NForm, NFormItem, NInput, NButton, } from 'naive-ui'
  33 +import { NModal, NCard, NForm, NFormItem, NInput, NButton, NInputGroup } from 'naive-ui'
21 34 import { getSessionStorageInfo } from '../preview/utils'
22 35 import type { ChartEditStorageType } from '../preview/index.d'
23 36 import { SavePageEnum } from '@/enums/editPageEnum'
24   -import { JSONParse, setSessionStorage } from '@/utils'
  37 +import { JSONParse, setSessionStorage, setTitle } from '@/utils'
25 38 import { StorageEnum } from '@/enums/storageEnum'
26 39 import { onMounted, ref, unref } from 'vue'
27 40 import Preview from '../preview/index.vue'
... ... @@ -42,7 +55,7 @@ const getToken = async () => {
42 55 const { params } = ROUTE
43 56 const { publicId } = params as Record<'id' | 'publicId', string>
44 57 const { token, refreshToken } = await getPublicToken(publicId)
45   - userStore.storeToken(token, refreshToken)
  58 + userStore.storeShareToken(token, refreshToken)
46 59 }
47 60
48 61 const checkNeedAccessToken = async () => {
... ... @@ -77,6 +90,7 @@ const getSharePageContentData = async () => {
77 90 chartEditStore.requestGlobalConfig = requestGlobalConfig
78 91 chartEditStore.componentList = componentList
79 92 }
  93 + setTitle(dataViewName || '')
80 94 showModal.value = false
81 95 allowLoadPreviewPage.value = false
82 96 } catch (error) {
... ...
... ... @@ -20,7 +20,8 @@
20 20 ],
21 21 "typeRoots": [
22 22 "./node_modules/@types/",
23   - "./types"
  23 + "./types",
  24 + "./types/external"
24 25 ],
25 26 "paths": {
26 27 "@/*": [
... ...
... ... @@ -21,6 +21,8 @@ export interface RequestOptions {
21 21 ignoreCancelToken?: boolean;
22 22 // Whether to send token in header
23 23 withToken?: boolean;
  24 + // Carry and share token 携带分享的访问令牌
  25 + withShareToken?: boolean
24 26 }
25 27
26 28 export interface Result<T = any> {
... ...