Commit 4c79e9e45b2da81875172d7d1b939e95b4922735

Authored by fengwotao
2 parents 1f87bc38 1d60a05b

Merge branch 'main_dev' into ft

@@ -16,6 +16,7 @@ import { @@ -16,6 +16,7 @@ import {
16 UpdateDataComponentParams, 16 UpdateDataComponentParams,
17 } from './model'; 17 } from './model';
18 import { defHttp } from '/@/utils/http/axios'; 18 import { defHttp } from '/@/utils/http/axios';
  19 +import { isShareMode } from '/@/views/sys/share/hook';
19 20
20 enum DataBoardUrl { 21 enum DataBoardUrl {
21 GET_DATA_BOARD = '/data_board', 22 GET_DATA_BOARD = '/data_board',
@@ -224,7 +225,7 @@ export const sendCommandOneway = (params: SendCommandParams) => { @@ -224,7 +225,7 @@ export const sendCommandOneway = (params: SendCommandParams) => {
224 url: `${SendCommand.ONEWAY}/${params.deviceId}`, 225 url: `${SendCommand.ONEWAY}/${params.deviceId}`,
225 params: params.value, 226 params: params.value,
226 }, 227 },
227 - { joinPrefix: false } 228 + { joinPrefix: false, withShareToken: isShareMode() }
228 ); 229 );
229 }; 230 };
230 231
1 import { defHttp } from '/@/utils/http/axios'; 1 import { defHttp } from '/@/utils/http/axios';
2 import { ViewTypeEnum } from '/@/views/sys/share/config/config'; 2 import { ViewTypeEnum } from '/@/views/sys/share/config/config';
  3 +import { isShareMode } from '/@/views/sys/share/hook';
3 4
4 enum Api { 5 enum Api {
5 CHECK = '/share/check', 6 CHECK = '/share/check',
@@ -8,9 +9,14 @@ enum Api { @@ -8,9 +9,14 @@ enum Api {
8 } 9 }
9 10
10 export const checkShareAccessToken = (type: ViewTypeEnum, id: string) => { 11 export const checkShareAccessToken = (type: ViewTypeEnum, id: string) => {
11 - return defHttp.get<Record<'data', boolean>>({  
12 - url: `${Api.CHECK}/${type}/${id}`,  
13 - }); 12 + return defHttp.get<Record<'data', boolean>>(
  13 + {
  14 + url: `${Api.CHECK}/${type}/${id}`,
  15 + },
  16 + {
  17 + withShareToken: isShareMode(),
  18 + }
  19 + );
14 }; 20 };
15 21
16 export const sharePageLogin = (publicId: string) => { 22 export const sharePageLogin = (publicId: string) => {
@@ -21,14 +27,20 @@ export const sharePageLogin = (publicId: string) => { @@ -21,14 +27,20 @@ export const sharePageLogin = (publicId: string) => {
21 }, 27 },
22 { 28 {
23 joinPrefix: false, 29 joinPrefix: false,
  30 + withShareToken: isShareMode(),
24 } 31 }
25 ); 32 );
26 }; 33 };
27 34
28 export const getShareContent = (record: Record<'accessCredentials' | 'id', string>) => { 35 export const getShareContent = (record: Record<'accessCredentials' | 'id', string>) => {
29 const { id, accessCredentials } = record; 36 const { id, accessCredentials } = record;
30 - return defHttp.get({  
31 - url: `${Api.SHARE_CONTENT}/${ViewTypeEnum.DATA_BOARD}/share_data/${id}`,  
32 - params: { accessCredentials },  
33 - }); 37 + return defHttp.get(
  38 + {
  39 + url: `${Api.SHARE_CONTENT}/${ViewTypeEnum.DATA_BOARD}/share_data/${id}`,
  40 + params: { accessCredentials },
  41 + },
  42 + {
  43 + withShareToken: isShareMode(),
  44 + }
  45 + );
34 }; 46 };
@@ -47,6 +47,7 @@ export interface TaskRecordType extends CreateTaskRecordType { @@ -47,6 +47,7 @@ export interface TaskRecordType extends CreateTaskRecordType {
47 enabled: boolean; 47 enabled: boolean;
48 state: number; 48 state: number;
49 lastExecuteTime?: number; 49 lastExecuteTime?: number;
  50 + lastExecuteStr?: string;
50 tkDeviceTaskCenter?: { 51 tkDeviceTaskCenter?: {
51 allowState: number; 52 allowState: number;
52 taskCenterId: string; 53 taskCenterId: string;
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 import { ReloadOutlined } from '@ant-design/icons-vue'; 2 import { ReloadOutlined } from '@ant-design/icons-vue';
3 - import { Button, List, Tooltip } from 'ant-design-vue'; 3 + import { Button, List, Space, Tooltip } from 'ant-design-vue';
4 import { reactive } from 'vue'; 4 import { reactive } from 'vue';
5 import { ref } from 'vue'; 5 import { ref } from 'vue';
  6 + import { BasicForm, useForm } from '../../Form';
  7 + import { basicListProps } from './props';
  8 + import { ExtractPropTypes } from 'vue';
  9 + defineProps<ExtractPropTypes<typeof basicListProps>>();
  10 +
  11 + const [registerForm] = useForm({
  12 + schemas: [
  13 + {
  14 + field: '123',
  15 + label: 'test',
  16 + component: 'Input',
  17 + },
  18 + ],
  19 + labelWidth: 100,
  20 + layout: 'inline',
  21 + baseColProps: { span: 8 },
  22 + showAdvancedButton: true,
  23 + compact: true,
  24 + });
6 25
7 const listElRef = ref<Nullable<ComponentElRef>>(null); 26 const listElRef = ref<Nullable<ComponentElRef>>(null);
8 27
9 - const pagination = reactive({}); 28 + const pagination = reactive({ size: 'small' });
10 29
11 const loading = ref(false); 30 const loading = ref(false);
12 31
@@ -16,31 +35,48 @@ @@ -16,31 +35,48 @@
16 </script> 35 </script>
17 36
18 <template> 37 <template>
19 - <section class="bg-light-50 my-4 p-4 x dark:text-gray-300 dark:bg-dark-900">  
20 - <List  
21 - ref="listElRef"  
22 - :dataSource="dataSource"  
23 - :pagination="pagination"  
24 - :grid="{ gutter: 16, xs: 1, sm: 1, md: 1, lg: 2, xl: 2, xxl: 3, column: 3 }"  
25 - :loading="loading"  
26 - >  
27 - <template #header>  
28 - <section class="flex justify-between gap-4 min-h-12 items-center">  
29 - <div class="text-lg font-semibold">  
30 - <span>任务列表</span>  
31 - </div>  
32 - <Tooltip title="刷新">  
33 - <Button type="primary" @click="getDataSource">  
34 - <ReloadOutlined :spin="loading" />  
35 - </Button>  
36 - </Tooltip>  
37 - </section>  
38 - </template>  
39 - <template #renderItem="{ item }">  
40 - <List.Item :key="item.id">  
41 - <slot name="item" :item="item"></slot>  
42 - </List.Item>  
43 - </template>  
44 - </List> 38 + <section class="basic-list-container">
  39 + <section class="mb-4 bg-light-50 p-2 x dark:text-gray-300 dark:bg-dark-900">
  40 + <BasicForm @register="registerForm" />
  41 + </section>
  42 + <section class="bg-light-50 p-2 x dark:text-gray-300 dark:bg-dark-900">
  43 + <List
  44 + ref="listElRef"
  45 + :dataSource="dataSource"
  46 + :pagination="pagination"
  47 + :grid="{ gutter: 16, xs: 1, sm: 1, md: 1, lg: 2, xl: 2, xxl: 3, column: 3 }"
  48 + :loading="loading"
  49 + >
  50 + <template #header>
  51 + <section class="flex px-5 justify-between gap-4 min-h-12 items-center">
  52 + <div class="text-lg font-semibold">
  53 + <span>任务列表</span>
  54 + </div>
  55 + <Space>
  56 + <slot name="toolbar"></slot>
  57 + <Tooltip title="刷新">
  58 + <Button type="primary" @click="getDataSource">
  59 + <ReloadOutlined :spin="loading" />
  60 + </Button>
  61 + </Tooltip>
  62 + </Space>
  63 + </section>
  64 + </template>
  65 + <template #renderItem="{ item }">
  66 + <List.Item :key="item.id">
  67 + <slot name="item" :item="item"></slot>
  68 + </List.Item>
  69 + </template>
  70 + </List>
  71 + </section>
45 </section> 72 </section>
46 </template> 73 </template>
  74 +
  75 +<style lang="less" scoped>
  76 + .basic-list-container {
  77 + :deep(.ant-list-header) {
  78 + padding-top: 0;
  79 + padding-bottom: 8px;
  80 + }
  81 + }
  82 +</style>
  1 +import type { ComputedRef, Slots } from 'vue';
  2 +import type { BasicTableProps, FetchParams } from '../types/table';
  3 +import { unref, computed } from 'vue';
  4 +import type { FormProps } from '/@/components/Form';
  5 +import { isFunction } from '/@/utils/is';
  6 +
  7 +export function useTableForm(
  8 + propsRef: ComputedRef<BasicTableProps>,
  9 + slots: Slots,
  10 + fetch: (opt?: FetchParams | undefined) => Promise<void>,
  11 + getLoading: ComputedRef<boolean | undefined>
  12 +) {
  13 + const getFormProps = computed((): Partial<FormProps> => {
  14 + const { formConfig } = unref(propsRef);
  15 + const { submitButtonOptions } = formConfig || {};
  16 + return {
  17 + showAdvancedButton: true,
  18 + ...formConfig,
  19 + submitButtonOptions: { loading: unref(getLoading), ...submitButtonOptions },
  20 + compact: true,
  21 + };
  22 + });
  23 +
  24 + const getFormSlotKeys: ComputedRef<string[]> = computed(() => {
  25 + const keys = Object.keys(slots);
  26 + return keys
  27 + .map((item) => (item.startsWith('form-') ? item : null))
  28 + .filter((item) => !!item) as string[];
  29 + });
  30 +
  31 + function replaceFormSlotKey(key: string) {
  32 + if (!key) return '';
  33 + return key?.replace?.(/form\-/, '') ?? '';
  34 + }
  35 +
  36 + function handleSearchInfoChange(info: Recordable) {
  37 + const { handleSearchInfoFn } = unref(propsRef);
  38 + if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) {
  39 + info = handleSearchInfoFn(info) || info;
  40 + }
  41 + fetch({ searchInfo: info, page: 1 });
  42 + }
  43 +
  44 + return {
  45 + getFormProps,
  46 + replaceFormSlotKey,
  47 + getFormSlotKeys,
  48 + handleSearchInfoChange,
  49 + };
  50 +}
1 -import { ComponentPropsOptions } from 'vue'; 1 +import { FormProps } from '../../Form';
2 2
3 -export const props = { 3 +export const basicListProps = {
  4 + immediate: {
  5 + type: Boolean,
  6 + default: true,
  7 + },
  8 + searchInfo: {
  9 + type: Object as PropType<Recordable>,
  10 + },
  11 + formConfig: {
  12 + type: Object as PropType<Partial<FormProps>>,
  13 + default: null,
  14 + },
4 title: { 15 title: {
5 type: String, 16 type: String,
6 }, 17 },
7 -} as ComponentPropsOptions; 18 + titleHelpMessage: {
  19 + type: [String, Array] as PropType<string | string[]>,
  20 + },
  21 + autoCreateKey: {
  22 + type: Boolean,
  23 + default: true,
  24 + },
  25 + api: {
  26 + type: Function as PropType<Fn<any, Promise<any>>>,
  27 + },
  28 + beforeFetch: {
  29 + type: Function as PropType<Fn>,
  30 + },
  31 + afterFetch: {
  32 + type: Function as PropType<Fn>,
  33 + },
  34 + handleSearchInfoFn: {
  35 + type: Function as PropType<Fn>,
  36 + },
  37 +};
  1 +import { FormProps } from 'ant-design-vue/es/form/Form';
  2 +
  3 +export interface BasicListProps {
  4 + /**
  5 + * @description 立即执行
  6 + */
  7 + immediate?: boolean;
  8 +
  9 + /**
  10 + * @description 额外的请求参数
  11 + */
  12 + searchInfo?: Recordable;
  13 +
  14 + /**
  15 + * @description 搜索表单
  16 + */
  17 + formConfig?: Partial<FormProps>;
  18 +
  19 + /**
  20 + * @description 列表名
  21 + */
  22 + title?: string;
  23 +
  24 + /**
  25 + * @description 列表标题帮助信息
  26 + */
  27 + titleHelpMessage?: string | string[];
  28 +
  29 + /**
  30 + * @description 自动创建key
  31 + */
  32 + autoCreateKey?: boolean;
  33 +
  34 + /**
  35 + * @description 请求接口
  36 + * @param args
  37 + * @returns
  38 + */
  39 + api?: (...args: any) => Promise<any>;
  40 +
  41 + /**
  42 + * @description 请求前对参数处理
  43 + */
  44 + beforeFetch?: Fn;
  45 +
  46 + /**
  47 + * @description 请求后对结果处理
  48 + */
  49 + afterFetch?: Fn;
  50 +
  51 + /**
  52 + * @description 请求前处理搜索参数
  53 + */
  54 + handleSearchInfoFn?: Fn;
  55 +}
@@ -5,6 +5,10 @@ export const JWT_TOKEN_KEY = 'JWT_TOKEN'; @@ -5,6 +5,10 @@ export const JWT_TOKEN_KEY = 'JWT_TOKEN';
5 5
6 export const REFRESH_TOKEN_KEY = 'REFRESH_TOKEN'; 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 export const LOCALE_KEY = 'LOCALE__'; 12 export const LOCALE_KEY = 'LOCALE__';
9 13
10 // user info key 14 // user info key
@@ -224,7 +224,7 @@ export const usePermissionStore = defineStore({ @@ -224,7 +224,7 @@ export const usePermissionStore = defineStore({
224 // !Simulate to obtain permission codes from the background, 224 // !Simulate to obtain permission codes from the background,
225 // this function may only need to be executed once, and the actual project can be put at the right time by itself 225 // this function may only need to be executed once, and the actual project can be put at the right time by itself
226 let routeList: AppRouteRecordRaw[] = []; 226 let routeList: AppRouteRecordRaw[] = [];
227 - const userInfo: any = getAuthCache(USER_INFO_KEY); 227 + const userInfo: any = getAuthCache(USER_INFO_KEY) || { roles: [] };
228 const filterMenu = (allMenuList, menuIdsList) => { 228 const filterMenu = (allMenuList, menuIdsList) => {
229 return allMenuList 229 return allMenuList
230 .filter((item) => { 230 .filter((item) => {
@@ -4,7 +4,14 @@ import { defineStore } from 'pinia'; @@ -4,7 +4,14 @@ import { defineStore } from 'pinia';
4 import { store } from '/@/store'; 4 import { store } from '/@/store';
5 import { RoleEnum } from '/@/enums/roleEnum'; 5 import { RoleEnum } from '/@/enums/roleEnum';
6 import { PageEnum } from '/@/enums/pageEnum'; 6 import { PageEnum } from '/@/enums/pageEnum';
7 -import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY, ROLES_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; 7 +import {
  8 + JWT_TOKEN_KEY,
  9 + REFRESH_TOKEN_KEY,
  10 + ROLES_KEY,
  11 + SHARE_JWT_TOKEN_KEY,
  12 + SHARE_REFRESH_TOKEN_KEY,
  13 + USER_INFO_KEY,
  14 +} from '/@/enums/cacheEnum';
8 import { getAuthCache, setAuthCache } from '/@/utils/auth'; 15 import { getAuthCache, setAuthCache } from '/@/utils/auth';
9 import { 16 import {
10 LoginParams, 17 LoginParams,
@@ -33,6 +40,8 @@ interface UserState { @@ -33,6 +40,8 @@ interface UserState {
33 lastUpdateTime: number; 40 lastUpdateTime: number;
34 jwtToken?: string; 41 jwtToken?: string;
35 refreshToken?: string; 42 refreshToken?: string;
  43 + shareJwtToken?: string;
  44 + shareRefreshToken?: string;
36 outTarget?: string; 45 outTarget?: string;
37 } 46 }
38 47
@@ -100,6 +109,13 @@ export const useUserStore = defineStore({ @@ -100,6 +109,13 @@ export const useUserStore = defineStore({
100 setAuthCache(JWT_TOKEN_KEY, jwtToken); 109 setAuthCache(JWT_TOKEN_KEY, jwtToken);
101 setAuthCache(REFRESH_TOKEN_KEY, refreshToken); 110 setAuthCache(REFRESH_TOKEN_KEY, refreshToken);
102 }, 111 },
  112 +
  113 + storeShareToken(jwtToken: string, refreshToken: string) {
  114 + this.shareJwtToken = jwtToken;
  115 + this.shareRefreshToken = refreshToken;
  116 + setAuthCache(SHARE_JWT_TOKEN_KEY, jwtToken);
  117 + setAuthCache(SHARE_REFRESH_TOKEN_KEY, refreshToken);
  118 + },
103 setToken(info: string | undefined) { 119 setToken(info: string | undefined) {
104 this.jwtToken = info; 120 this.jwtToken = info;
105 setAuthCache(JWT_TOKEN_KEY, info); 121 setAuthCache(JWT_TOKEN_KEY, info);
@@ -232,6 +248,18 @@ export const useUserStore = defineStore({ @@ -232,6 +248,18 @@ export const useUserStore = defineStore({
232 } 248 }
233 }, 249 },
234 250
  251 + async doShareRefresh() {
  252 + try {
  253 + const req = { refreshToken: this.shareRefreshToken } as RefreshTokenParams;
  254 + const data = await doRefreshToken(req);
  255 + const { token, refreshToken } = data;
  256 + this.storeToken(token, refreshToken);
  257 + } catch (error) {
  258 + window.location.reload();
  259 + throw error;
  260 + }
  261 + },
  262 +
235 /** 263 /**
236 * @description: Confirm before logging out 264 * @description: Confirm before logging out
237 */ 265 */
1 import { Persistent, BasicKeys } from '/@/utils/cache/persistent'; 1 import { Persistent, BasicKeys } from '/@/utils/cache/persistent';
2 -import { CacheTypeEnum } from '/@/enums/cacheEnum'; 2 +import { CacheTypeEnum, SHARE_JWT_TOKEN_KEY, SHARE_REFRESH_TOKEN_KEY } from '/@/enums/cacheEnum';
3 import projectSetting from '/@/settings/projectSetting'; 3 import projectSetting from '/@/settings/projectSetting';
4 import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY } from '/@/enums/cacheEnum'; 4 import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY } from '/@/enums/cacheEnum';
5 5
@@ -26,3 +26,11 @@ export function getJwtToken() { @@ -26,3 +26,11 @@ export function getJwtToken() {
26 export function getRefreshToken() { 26 export function getRefreshToken() {
27 return getAuthCache(REFRESH_TOKEN_KEY); 27 return getAuthCache(REFRESH_TOKEN_KEY);
28 } 28 }
  29 +
  30 +export function getShareJwtToken() {
  31 + return getAuthCache(SHARE_JWT_TOKEN_KEY);
  32 +}
  33 +
  34 +export function getShareRefreshToken() {
  35 + return getAuthCache(SHARE_REFRESH_TOKEN_KEY);
  36 +}
@@ -17,6 +17,8 @@ import { @@ -17,6 +17,8 @@ import {
17 APP_SESSION_CACHE_KEY, 17 APP_SESSION_CACHE_KEY,
18 MULTIPLE_TABS_KEY, 18 MULTIPLE_TABS_KEY,
19 MENU_LIST, 19 MENU_LIST,
  20 + SHARE_JWT_TOKEN_KEY,
  21 + SHARE_REFRESH_TOKEN_KEY,
20 } from '/@/enums/cacheEnum'; 22 } from '/@/enums/cacheEnum';
21 import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; 23 import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
22 import { toRaw } from 'vue'; 24 import { toRaw } from 'vue';
@@ -33,6 +35,8 @@ interface BasicStore { @@ -33,6 +35,8 @@ interface BasicStore {
33 [PROJ_CFG_KEY]: ProjectConfig; 35 [PROJ_CFG_KEY]: ProjectConfig;
34 [MULTIPLE_TABS_KEY]: RouteLocationNormalized[]; 36 [MULTIPLE_TABS_KEY]: RouteLocationNormalized[];
35 [MENU_LIST]: any[]; 37 [MENU_LIST]: any[];
  38 + [SHARE_JWT_TOKEN_KEY]: string;
  39 + [SHARE_REFRESH_TOKEN_KEY]: string;
36 } 40 }
37 41
38 type LocalStore = BasicStore; 42 type LocalStore = BasicStore;
@@ -80,7 +80,6 @@ export class VAxios { @@ -80,7 +80,6 @@ export class VAxios {
80 private refreshTokenBeforeReq(doRefreshTokenApi: () => Promise<unknown>): Promise<unknown> { 80 private refreshTokenBeforeReq(doRefreshTokenApi: () => Promise<unknown>): Promise<unknown> {
81 // 创建一个未完成的promise,把改变状态的resolve方法交给请求token结束后执行 81 // 创建一个未完成的promise,把改变状态的resolve方法交给请求token结束后执行
82 const promise = new Promise((resolve) => { 82 const promise = new Promise((resolve) => {
83 - console.log('等待新token');  
84 // 等待队列放的是一个回调函数,来延迟resolve的执行,以此控制promise状态的改变 83 // 等待队列放的是一个回调函数,来延迟resolve的执行,以此控制promise状态的改变
85 this.waitingQueue.push(() => resolve(null)); 84 this.waitingQueue.push(() => resolve(null));
86 }); 85 });
@@ -88,7 +87,6 @@ export class VAxios { @@ -88,7 +87,6 @@ export class VAxios {
88 this.refreshing = true; 87 this.refreshing = true;
89 // 模拟请求刷新Token接口,当接口返回数据时执行then方法 TODO 添加catch捕获异常 88 // 模拟请求刷新Token接口,当接口返回数据时执行then方法 TODO 添加catch捕获异常
90 doRefreshTokenApi().then(() => { 89 doRefreshTokenApi().then(() => {
91 - console.log('刷新token成功,放行队列中的请求', this.waitingQueue.length);  
92 this.refreshing = false; 90 this.refreshing = false;
93 this.waitingQueue.forEach((cb) => cb()); 91 this.waitingQueue.forEach((cb) => cb());
94 this.waitingQueue.length = 0; 92 this.waitingQueue.length = 0;
@@ -117,12 +115,19 @@ export class VAxios { @@ -117,12 +115,19 @@ export class VAxios {
117 this.axiosInstance.interceptors.request.use(async (config: AxiosRequestConfig) => { 115 this.axiosInstance.interceptors.request.use(async (config: AxiosRequestConfig) => {
118 // If cancel repeat request is turned on, then cancel repeat request is prohibited 116 // If cancel repeat request is turned on, then cancel repeat request is prohibited
119 const userStore = useUserStore(); 117 const userStore = useUserStore();
120 - if (userStore && userStore.jwtToken) { 118 + if (userStore) {
121 try { 119 try {
122 - const res = jwt_decode(userStore.jwtToken) as JwtModel;  
123 - const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000;  
124 - if (currentTime >= res.exp && this.isNeedTokenURL(config.url)) {  
125 - await this.refreshTokenBeforeReq(userStore.doRefresh); 120 + const { requestOptions = {} } = config;
  121 + const { withShareToken, withToken } = requestOptions;
  122 + const token = withShareToken && withToken ? userStore.shareJwtToken : userStore.jwtToken;
  123 + const doRefresh =
  124 + 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 + }
126 } 131 }
127 } catch (error) { 132 } catch (error) {
128 userStore.logout(); 133 userStore.logout();
@@ -244,7 +249,6 @@ export class VAxios { @@ -244,7 +249,6 @@ export class VAxios {
244 const { requestOptions } = this.options; 249 const { requestOptions } = this.options;
245 250
246 const opt: RequestOptions = Object.assign({}, requestOptions, options); 251 const opt: RequestOptions = Object.assign({}, requestOptions, options);
247 -  
248 const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {}; 252 const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
249 if (beforeRequestHook && isFunction(beforeRequestHook)) { 253 if (beforeRequestHook && isFunction(beforeRequestHook)) {
250 conf = beforeRequestHook(conf, opt); 254 conf = beforeRequestHook(conf, opt);
1 /** 1 /**
2 * Data processing class, can be configured according to the project 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 OriginalAxiosRequestConfig, AxiosResponse } from 'axios';
5 import type { RequestOptions, Result } from '/#/axios'; 5 import type { RequestOptions, Result } from '/#/axios';
6 6
7 export interface CreateAxiosOptions extends AxiosRequestConfig { 7 export interface CreateAxiosOptions extends AxiosRequestConfig {
@@ -10,6 +10,7 @@ export interface CreateAxiosOptions extends AxiosRequestConfig { @@ -10,6 +10,7 @@ export interface CreateAxiosOptions extends AxiosRequestConfig {
10 transform?: AxiosTransform; 10 transform?: AxiosTransform;
11 requestOptions?: RequestOptions; 11 requestOptions?: RequestOptions;
12 } 12 }
  13 +export type AxiosRequestConfig = OriginalAxiosRequestConfig & { requestOptions?: RequestOptions };
13 14
14 export abstract class AxiosTransform { 15 export abstract class AxiosTransform {
15 /** 16 /**
@@ -10,7 +10,7 @@ import { useGlobSetting } from '/@/hooks/setting'; @@ -10,7 +10,7 @@ import { useGlobSetting } from '/@/hooks/setting';
10 import { useMessage } from '/@/hooks/web/useMessage'; 10 import { useMessage } from '/@/hooks/web/useMessage';
11 import { RequestEnum, ContentTypeEnum } from '/@/enums/httpEnum'; 11 import { RequestEnum, ContentTypeEnum } from '/@/enums/httpEnum';
12 import { isString } from '/@/utils/is'; 12 import { isString } from '/@/utils/is';
13 -import { getJwtToken } from '/@/utils/auth'; 13 +import { getJwtToken, getShareJwtToken } from '/@/utils/auth';
14 import { setObjToUrlParams, deepMerge } from '/@/utils'; 14 import { setObjToUrlParams, deepMerge } from '/@/utils';
15 import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'; 15 import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
16 import { useI18n } from '/@/hooks/web/useI18n'; 16 import { useI18n } from '/@/hooks/web/useI18n';
@@ -92,12 +92,23 @@ const transform: AxiosTransform = { @@ -92,12 +92,23 @@ const transform: AxiosTransform = {
92 */ 92 */
93 requestInterceptors: (config, options) => { 93 requestInterceptors: (config, options) => {
94 // 请求之前处理config 94 // 请求之前处理config
95 - const token = getJwtToken();  
96 - if (token && (config as Recordable)?.requestOptions?.withToken !== false) {  
97 - // jwt token  
98 - config.headers['X-Authorization'] = options.authenticationScheme  
99 - ? `${options.authenticationScheme} ${token}`  
100 - : token; 95 + const { requestOptions } = config;
  96 + const { withShareToken } = requestOptions || {};
  97 + const { requestOptions: { withToken } = {} } = options;
  98 + if (withToken !== false) {
  99 + const shareToken = getShareJwtToken();
  100 + if (withShareToken && shareToken) {
  101 + config.headers['X-Authorization'] = options.authenticationScheme
  102 + ? `${options.authenticationScheme} ${shareToken}`
  103 + : shareToken;
  104 + } else {
  105 + const token = getJwtToken();
  106 + if (token) {
  107 + config.headers['X-Authorization'] = options.authenticationScheme
  108 + ? `${options.authenticationScheme} ${token}`
  109 + : token;
  110 + }
  111 + }
101 } 112 }
102 return config; 113 return config;
103 }, 114 },
@@ -194,7 +205,7 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { @@ -194,7 +205,7 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
194 ignoreCancelToken: true, 205 ignoreCancelToken: true,
195 // 是否携带token 206 // 是否携带token
196 withToken: true, 207 withToken: true,
197 - }, 208 + } as RequestOptions,
198 }, 209 },
199 opt || {} 210 opt || {}
200 ) 211 )
@@ -25,7 +25,7 @@ export const schemas: FormSchema[] = [ @@ -25,7 +25,7 @@ export const schemas: FormSchema[] = [
25 { 25 {
26 field: FieldsEnum.ACCESS_CREDENTIALS, 26 field: FieldsEnum.ACCESS_CREDENTIALS,
27 label: '访问凭证', 27 label: '访问凭证',
28 - component: 'Input', 28 + component: 'InputPassword',
29 ifShow: ({ model }) => model[FieldsEnum.IS_SHARE], 29 ifShow: ({ model }) => model[FieldsEnum.IS_SHARE],
30 componentProps: { 30 componentProps: {
31 maxLength: 64, 31 maxLength: 64,
  1 +export const isShareMode = () => {
  2 + const sharePageReg = /^\/share\/[^/]+\/[^/]+\/[^/]+$/;
  3 + const { pathname } = location;
  4 + return sharePageReg.test(pathname);
  5 +};
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 import { onMounted } from 'vue'; 2 import { onMounted } from 'vue';
3 - import { BasicModal, useModal } from '/@/components/Modal';  
4 - import { Spin } from 'ant-design-vue'; 3 + import { Spin, Modal, Button, Input, Row, Col } from 'ant-design-vue';
5 import { ref } from 'vue'; 4 import { ref } from 'vue';
6 import { useRoute } from 'vue-router'; 5 import { useRoute } from 'vue-router';
7 import { checkShareAccessToken, sharePageLogin, getShareContent } from '/@/api/sys/share'; 6 import { checkShareAccessToken, sharePageLogin, getShareContent } from '/@/api/sys/share';
@@ -16,7 +15,9 @@ @@ -16,7 +15,9 @@
16 const contentData = ref<any>(); 15 const contentData = ref<any>();
17 const canLoadComponent = ref(false); 16 const canLoadComponent = ref(false);
18 17
19 - const [register, { openModal }] = useModal(); 18 + const modelVisable = ref(false);
  19 +
  20 + // const [register, { openModal }] = useModal();
20 21
21 const [registerForm, { getFieldsValue }] = useForm({ 22 const [registerForm, { getFieldsValue }] = useForm({
22 schemas: [ 23 schemas: [
@@ -24,11 +25,15 @@ @@ -24,11 +25,15 @@
24 field: FieldsEnum.ACCESS_CREDENTIALS, 25 field: FieldsEnum.ACCESS_CREDENTIALS,
25 component: 'Input', 26 component: 'Input',
26 label: '访问令牌', 27 label: '访问令牌',
  28 + slot: 'tokenInput',
  29 + componentProps: {
  30 + placeholder: '请输入访问令牌',
  31 + },
27 }, 32 },
28 ], 33 ],
29 showActionButtonGroup: false, 34 showActionButtonGroup: false,
30 - layout: 'inline',  
31 - labelWidth: 100, 35 + layout: 'vertical',
  36 + baseColProps: { span: 24 },
32 }); 37 });
33 38
34 const userStore = useUserStore(); 39 const userStore = useUserStore();
@@ -37,7 +42,7 @@ @@ -37,7 +42,7 @@
37 const { params } = ROUTE; 42 const { params } = ROUTE;
38 const { publicId } = params as Partial<ShareRouteParams>; 43 const { publicId } = params as Partial<ShareRouteParams>;
39 const { token, refreshToken } = await sharePageLogin(publicId!); 44 const { token, refreshToken } = await sharePageLogin(publicId!);
40 - userStore.storeToken(token, refreshToken); 45 + userStore.storeShareToken(token, refreshToken);
41 }; 46 };
42 47
43 const getCheckNeedAccessToken = async () => { 48 const getCheckNeedAccessToken = async () => {
@@ -45,7 +50,7 @@ @@ -45,7 +50,7 @@
45 loading.value = true; 50 loading.value = true;
46 const { viewType, id } = params as Partial<ShareRouteParams>; 51 const { viewType, id } = params as Partial<ShareRouteParams>;
47 const { data } = await checkShareAccessToken(viewType!, id!); 52 const { data } = await checkShareAccessToken(viewType!, id!);
48 - data ? openModal(data) : await getContentData(); 53 + data ? (modelVisable.value = true) : await getContentData();
49 }; 54 };
50 55
51 const getContentLoading = ref(false); 56 const getContentLoading = ref(false);
@@ -59,7 +64,8 @@ @@ -59,7 +64,8 @@
59 contentData.value = result; 64 contentData.value = result;
60 loading.value = false; 65 loading.value = false;
61 canLoadComponent.value = true; 66 canLoadComponent.value = true;
62 - openModal(false); 67 + // openModal(false);
  68 + modelVisable.value = false;
63 } catch (error) { 69 } catch (error) {
64 } finally { 70 } finally {
65 getContentLoading.value = false; 71 getContentLoading.value = false;
@@ -77,15 +83,64 @@ @@ -77,15 +83,64 @@
77 </script> 83 </script>
78 84
79 <template> 85 <template>
80 - <BasicModal  
81 - @register="register"  
82 - title="公开"  
83 - @ok="handleSubmit"  
84 - :showCancelBtn="false"  
85 - :okButtonProps="{ loading: getContentLoading }" 86 + <Modal
  87 + v-model:visible="modelVisable"
  88 + centered
  89 + :title="null"
  90 + :close-icon="null"
  91 + width="350px"
  92 + :footer="null"
  93 + wrapClassName="share-page-token-modal"
86 > 94 >
87 - <BasicForm @register="registerForm" />  
88 - </BasicModal> 95 + <section class="w-full h-full flex flex-col p-8 justify-center items-center">
  96 + <BasicForm @register="registerForm" class="w-full" @keyup.enter="handleSubmit">
  97 + <template #tokenInput="{ field, model }">
  98 + <Input.Group>
  99 + <Row>
  100 + <Col :span="18">
  101 + <Input.Password v-model:value="model[field]" placeholder="请输入访问令牌" />
  102 + </Col>
  103 + <Col :span="6">
  104 + <Button
  105 + class="w-full !flex justify-center items-center"
  106 + :loading="getContentLoading"
  107 + type="primary"
  108 + @click="handleSubmit"
  109 + >
  110 + <svg
  111 + t="1682068997810"
  112 + class="icon"
  113 + viewBox="0 0 1024 1024"
  114 + version="1.1"
  115 + xmlns="http://www.w3.org/2000/svg"
  116 + p-id="79416"
  117 + width="24"
  118 + height="24"
  119 + >
  120 + <path
  121 + 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"
  122 + fill="#fff"
  123 + p-id="79417"
  124 + />
  125 + <path
  126 + 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"
  127 + fill="#fff"
  128 + p-id="79418"
  129 + />
  130 + <path
  131 + 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"
  132 + fill="#fff"
  133 + p-id="79419"
  134 + />
  135 + </svg>
  136 + </Button>
  137 + </Col>
  138 + </Row>
  139 + </Input.Group>
  140 + </template>
  141 + </BasicForm>
  142 + </section>
  143 + </Modal>
89 <Spin 144 <Spin
90 :spinning="loading" 145 :spinning="loading"
91 tip="正在加载中..." 146 tip="正在加载中..."
@@ -96,4 +151,10 @@ @@ -96,4 +151,10 @@
96 </Spin> 151 </Spin>
97 </template> 152 </template>
98 153
99 -<style lang="less" scoped></style> 154 +<style lang="less">
  155 + .share-page-token-modal {
  156 + .ant-modal-close {
  157 + display: none;
  158 + }
  159 + }
  160 +</style>
@@ -213,11 +213,7 @@ @@ -213,11 +213,7 @@
213 > 213 >
214 <div class="text-gray-400 text-xs truncate"> 214 <div class="text-gray-400 text-xs truncate">
215 <span class="mr-2">最近执行</span> 215 <span class="mr-2">最近执行</span>
216 - <span>{{  
217 - getLastExecuteTime.value > 0  
218 - ? `${getLastExecuteTime.value}${getLastExecuteTime.unitName}前`  
219 - : '刚刚'  
220 - }}</span> 216 + <span>{{ getRecord.lastExecuteStr }}</span>
221 </div> 217 </div>
222 </Tooltip> 218 </Tooltip>
223 </div> 219 </div>
1 import { useWebSocket } from '@vueuse/core'; 1 import { useWebSocket } from '@vueuse/core';
2 import { Ref, unref } from 'vue'; 2 import { Ref, unref } from 'vue';
3 import { DataBoardLayoutInfo } from '../types/type'; 3 import { DataBoardLayoutInfo } from '../types/type';
4 -import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';  
5 import { useGlobSetting } from '/@/hooks/setting'; 4 import { useGlobSetting } from '/@/hooks/setting';
6 -import { getAuthCache } from '/@/utils/auth';  
7 import { isNullAndUnDef } from '/@/utils/is'; 5 import { isNullAndUnDef } from '/@/utils/is';
  6 +import { getJwtToken, getShareJwtToken } from '/@/utils/auth';
  7 +import { isShareMode } from '/@/views/sys/share/hook';
8 8
9 interface SocketMessage { 9 interface SocketMessage {
10 tsSubCmds: SocketMessageItem[]; 10 tsSubCmds: SocketMessageItem[];
@@ -50,7 +50,7 @@ const generateMessage = (deviceId: string, cmdId: number, attr: string): SocketM @@ -50,7 +50,7 @@ const generateMessage = (deviceId: string, cmdId: number, attr: string): SocketM
50 }; 50 };
51 51
52 export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) { 52 export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) {
53 - const token = getAuthCache(JWT_TOKEN_KEY); 53 + const token = isShareMode() ? getShareJwtToken() : getJwtToken();
54 54
55 const cmdIdMapping = new Map<number, GroupMappingRecord[]>(); 55 const cmdIdMapping = new Map<number, GroupMappingRecord[]>();
56 56
@@ -21,6 +21,8 @@ export interface RequestOptions { @@ -21,6 +21,8 @@ export interface RequestOptions {
21 ignoreCancelToken?: boolean; 21 ignoreCancelToken?: boolean;
22 // Whether to send token in header 22 // Whether to send token in header
23 withToken?: boolean; 23 withToken?: boolean;
  24 + // Carry and share token 携带分享的访问令牌
  25 + withShareToken?: boolean;
24 } 26 }
25 27
26 export interface Result<T = any> { 28 export interface Result<T = any> {