adtec-core-package 3.2.4 → 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/upload/CustomElUpload.vue +14 -16
- package/src/components/upload/ElUploads.vue +14 -16
- package/src/config/VxeTableConfig.ts +11 -3
- package/src/utils/AxiosConfig.ts +4 -7
- package/src/utils/buildUploadHeaders.ts +58 -0
- package/src/utils/uploadAccept.ts +3 -1
package/package.json
CHANGED
|
@@ -44,15 +44,7 @@
|
|
|
44
44
|
:before-upload="beforeUpload"
|
|
45
45
|
drag
|
|
46
46
|
:accept="getAccept"
|
|
47
|
-
:action="
|
|
48
|
-
'/api/doc/uploadFile/' +
|
|
49
|
-
business +
|
|
50
|
-
'/' +
|
|
51
|
-
businessId +
|
|
52
|
-
'/' +
|
|
53
|
-
association +
|
|
54
|
-
(watermarkCode ? '?watermarkCode=' + watermarkCode : '')
|
|
55
|
-
"
|
|
47
|
+
:action="uploadAction"
|
|
56
48
|
multiple
|
|
57
49
|
:limit="limit"
|
|
58
50
|
:headers="uploadHeaders"
|
|
@@ -101,7 +93,7 @@
|
|
|
101
93
|
|
|
102
94
|
<script setup lang="ts">
|
|
103
95
|
import { UploadFilled } from '@element-plus/icons-vue'
|
|
104
|
-
import { computed,
|
|
96
|
+
import { computed, ref } from 'vue'
|
|
105
97
|
import {
|
|
106
98
|
ElMessage,
|
|
107
99
|
ElMessageBox,
|
|
@@ -116,11 +108,9 @@ import documentApi from '../../api/DocumentApi.ts'
|
|
|
116
108
|
import frameworkUtils from '../../utils/FrameworkUtils.ts'
|
|
117
109
|
import { userInfoStore } from '../../stores/userInfoStore'
|
|
118
110
|
import { getAcceptString } from '../../utils/uploadAccept.ts'
|
|
111
|
+
import { buildUploadHeaders } from '../../utils/buildUploadHeaders.ts'
|
|
119
112
|
|
|
120
113
|
const { fileView: fileView } = useFileView()
|
|
121
|
-
const uploadHeaders = ref({
|
|
122
|
-
Authorization: '',
|
|
123
|
-
})
|
|
124
114
|
const emit = defineEmits(['success'])
|
|
125
115
|
const userInfo = userInfoStore()
|
|
126
116
|
const ref_upload = ref()
|
|
@@ -217,6 +207,17 @@ const props = defineProps({
|
|
|
217
207
|
default: () => undefined,
|
|
218
208
|
},
|
|
219
209
|
})
|
|
210
|
+
const uploadAction = computed(
|
|
211
|
+
() =>
|
|
212
|
+
'/api/doc/uploadFile/' +
|
|
213
|
+
props.business +
|
|
214
|
+
'/' +
|
|
215
|
+
props.businessId +
|
|
216
|
+
'/' +
|
|
217
|
+
props.association +
|
|
218
|
+
(props.watermarkCode ? '?watermarkCode=' + props.watermarkCode : ''),
|
|
219
|
+
)
|
|
220
|
+
const uploadHeaders = computed(() => buildUploadHeaders(uploadAction.value))
|
|
220
221
|
/**
|
|
221
222
|
* 文件列表
|
|
222
223
|
*/
|
|
@@ -435,9 +436,6 @@ const confirm = async (autoDelete: boolean = true) => {
|
|
|
435
436
|
}
|
|
436
437
|
}
|
|
437
438
|
}
|
|
438
|
-
onMounted(() => {
|
|
439
|
-
uploadHeaders.value.Authorization = sessionStorage.getItem('Authorization') + ''
|
|
440
|
-
})
|
|
441
439
|
defineExpose({
|
|
442
440
|
remove,
|
|
443
441
|
confirm,
|
|
@@ -40,15 +40,7 @@
|
|
|
40
40
|
:before-upload="beforeUpload"
|
|
41
41
|
drag
|
|
42
42
|
:accept="getAccept"
|
|
43
|
-
:action="
|
|
44
|
-
'/api/doc/uploadFile/' +
|
|
45
|
-
business +
|
|
46
|
-
'/' +
|
|
47
|
-
businessId +
|
|
48
|
-
'/' +
|
|
49
|
-
association +
|
|
50
|
-
(watermarkCode ? '?watermarkCode=' + watermarkCode : '')
|
|
51
|
-
"
|
|
43
|
+
:action="uploadAction"
|
|
52
44
|
multiple
|
|
53
45
|
:limit="limit"
|
|
54
46
|
:headers="uploadHeaders"
|
|
@@ -97,7 +89,7 @@
|
|
|
97
89
|
|
|
98
90
|
<script setup lang="ts">
|
|
99
91
|
import { UploadFilled } from '@element-plus/icons-vue'
|
|
100
|
-
import { computed,
|
|
92
|
+
import { computed, ref, watch } from 'vue'
|
|
101
93
|
import {
|
|
102
94
|
ElMessage,
|
|
103
95
|
ElMessageBox,
|
|
@@ -112,11 +104,9 @@ import documentApi from '../../api/DocumentApi.ts'
|
|
|
112
104
|
import frameworkUtils from '../../utils/FrameworkUtils.ts'
|
|
113
105
|
import { userInfoStore } from '../../stores/userInfoStore'
|
|
114
106
|
import { getAcceptString } from '../../utils/uploadAccept.ts'
|
|
107
|
+
import { buildUploadHeaders } from '../../utils/buildUploadHeaders.ts'
|
|
115
108
|
|
|
116
109
|
const { fileView: fileView } = useFileView()
|
|
117
|
-
const uploadHeaders = ref({
|
|
118
|
-
Authorization: '',
|
|
119
|
-
})
|
|
120
110
|
const userInfo = userInfoStore()
|
|
121
111
|
const ref_upload = ref()
|
|
122
112
|
const hoverfileName = ref('')
|
|
@@ -201,6 +191,17 @@ const props = defineProps({
|
|
|
201
191
|
default: () => undefined,
|
|
202
192
|
},
|
|
203
193
|
})
|
|
194
|
+
const uploadAction = computed(
|
|
195
|
+
() =>
|
|
196
|
+
'/api/doc/uploadFile/' +
|
|
197
|
+
props.business +
|
|
198
|
+
'/' +
|
|
199
|
+
props.businessId +
|
|
200
|
+
'/' +
|
|
201
|
+
props.association +
|
|
202
|
+
(props.watermarkCode ? '?watermarkCode=' + props.watermarkCode : ''),
|
|
203
|
+
)
|
|
204
|
+
const uploadHeaders = computed(() => buildUploadHeaders(uploadAction.value))
|
|
204
205
|
const mousemove = (fileName: string) => {
|
|
205
206
|
hoverfileName.value = fileName
|
|
206
207
|
}
|
|
@@ -325,9 +326,6 @@ const remove = async (file: UploadFile) => {
|
|
|
325
326
|
}
|
|
326
327
|
// }
|
|
327
328
|
}
|
|
328
|
-
onMounted(() => {
|
|
329
|
-
uploadHeaders.value.Authorization = sessionStorage.getItem('Authorization') + ''
|
|
330
|
-
})
|
|
331
329
|
defineExpose({
|
|
332
330
|
remove,
|
|
333
331
|
})
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
VxeUI,
|
|
5
5
|
VxeTooltip } from 'vxe-pc-ui'
|
|
6
6
|
|
|
7
|
-
import VxeUIPluginRenderElement from '@vxe-ui/plugin-render-element'
|
|
8
7
|
import '@vxe-ui/plugin-render-element/dist/style.css'
|
|
9
8
|
import 'vxe-pc-ui/lib/style.css'
|
|
10
9
|
import '../css/vxeTableUI/all.scss'
|
|
@@ -23,8 +22,17 @@ export function initVxeTableInPage(
|
|
|
23
22
|
VxeUI.setI18n('zh-CN', zhCN)
|
|
24
23
|
VxeUI.setLanguage('zh-CN')
|
|
25
24
|
VxeUI.component(VxeTooltip)
|
|
26
|
-
//
|
|
27
|
-
|
|
25
|
+
// 局部注册插件(CJS 包动态加载,避免 Vite 静态 import 无 default 导出)
|
|
26
|
+
if (enableElementPlus) {
|
|
27
|
+
void import('@vxe-ui/plugin-render-element').then((renderModule) => {
|
|
28
|
+
const VxeUIPluginRenderElement =
|
|
29
|
+
renderModule.default ??
|
|
30
|
+
(renderModule as { VxeUIPluginRenderElement?: typeof renderModule.default })
|
|
31
|
+
.VxeUIPluginRenderElement ??
|
|
32
|
+
renderModule
|
|
33
|
+
VxeUI.use(VxeUIPluginRenderElement)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
28
36
|
if (enableExcel) {
|
|
29
37
|
void Promise.all([
|
|
30
38
|
import('exceljs'),
|
package/src/utils/AxiosConfig.ts
CHANGED
|
@@ -14,6 +14,7 @@ import encrypt from './encrypt'
|
|
|
14
14
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
15
15
|
|
|
16
16
|
import { Md5 } from 'ts-md5'
|
|
17
|
+
import { computeSigna, normalizeSignaPayload } from './buildUploadHeaders'
|
|
17
18
|
import { ElMessage } from 'element-plus'
|
|
18
19
|
import { useEventBus } from '@vueuse/core'
|
|
19
20
|
/** 是否正在刷新的标志 */
|
|
@@ -31,7 +32,6 @@ const request = axios.create({
|
|
|
31
32
|
function setHeaders(config: any) {
|
|
32
33
|
//数据防止篡改
|
|
33
34
|
const Authorization = config.skipAuthorization ? '' : sessionStorage.getItem('Authorization')
|
|
34
|
-
const signa = 'F2E49299-D0D2-4AA1-87A3-270272EA3D6A'
|
|
35
35
|
let dataJson: string = ''
|
|
36
36
|
if (config.method === 'get') {
|
|
37
37
|
if (config.params) {
|
|
@@ -52,14 +52,11 @@ function setHeaders(config: any) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
// @ts-ignore
|
|
57
|
-
dataJson=dataJson.replace(/[^\u4E00-\u9FA5A-Za-z0-9]/g, '')
|
|
58
|
-
dataJson = dataJson.split('').sort().join('').trim()
|
|
55
|
+
const normalizedPayload = normalizeSignaPayload(dataJson)
|
|
59
56
|
config.headers.sessionId = config.skipAuthorization ? '' : sessionStorage.getItem('sessionId')
|
|
60
57
|
config.headers.Authorization = Authorization
|
|
61
|
-
config.headers.signa =
|
|
62
|
-
config.headers.antiShakeKey = Md5.hashStr(
|
|
58
|
+
config.headers.signa = computeSigna(Authorization || '', dataJson)
|
|
59
|
+
config.headers.antiShakeKey = Md5.hashStr(normalizedPayload)
|
|
63
60
|
//防止重放 GUID+当前时间+TOKEN 加密
|
|
64
61
|
const timeDifference = sessionStorage.getItem('timeDifference')
|
|
65
62
|
const id = uuidv4()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Md5 } from 'ts-md5'
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
3
|
+
import encrypt from './encrypt'
|
|
4
|
+
|
|
5
|
+
/** 与后端 token.dataSigna / DataTamperingFilter 一致 */
|
|
6
|
+
export const SIGNA_KEY = 'F2E49299-D0D2-4AA1-87A3-270272EA3D6A'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 规范化 signa 参与签名的字符串(strip 非字母数字 → 字符排序)。
|
|
10
|
+
* multipart 上传使用完整 URL(含 query);JSON 接口使用序列化后的 body。
|
|
11
|
+
*/
|
|
12
|
+
export function normalizeSignaPayload(raw: string): string {
|
|
13
|
+
return raw
|
|
14
|
+
.replace(/[^\u4E00-\u9FA5A-Za-z0-9]/g, '')
|
|
15
|
+
.split('')
|
|
16
|
+
.sort()
|
|
17
|
+
.join('')
|
|
18
|
+
.trim()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function computeSigna(authorization: string, payload: string): string {
|
|
22
|
+
return Md5.hashStr(authorization + SIGNA_KEY + normalizeSignaPayload(payload))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface BuildUploadHeadersOptions {
|
|
26
|
+
/** 上传 action 路径,如 /api/doc/uploadFile/biz/id/true?watermarkCode=xxx */
|
|
27
|
+
url: string
|
|
28
|
+
skipAuthorization?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* el-upload / uni.uploadFile 等不走 axios 拦截器的上传请求头。
|
|
33
|
+
* signa 按 URL 计算,与 DataTamperingFilter multipart 分支对齐。
|
|
34
|
+
*/
|
|
35
|
+
export function buildUploadHeaders(
|
|
36
|
+
options: BuildUploadHeadersOptions | string,
|
|
37
|
+
): Record<string, string> {
|
|
38
|
+
const url = typeof options === 'string' ? options : options.url
|
|
39
|
+
const skipAuthorization =
|
|
40
|
+
typeof options === 'string' ? false : (options.skipAuthorization ?? false)
|
|
41
|
+
|
|
42
|
+
const Authorization = skipAuthorization ? '' : sessionStorage.getItem('Authorization') || ''
|
|
43
|
+
const normalizedPayload = normalizeSignaPayload(url)
|
|
44
|
+
|
|
45
|
+
const timeDifference = sessionStorage.getItem('timeDifference')
|
|
46
|
+
const id = uuidv4()
|
|
47
|
+
const localTime = new Date().getTime()
|
|
48
|
+
const replayObj = { timeDifference, guid: id, localTime }
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
Authorization,
|
|
52
|
+
sessionId: skipAuthorization ? '' : sessionStorage.getItem('sessionId') || '',
|
|
53
|
+
signa: computeSigna(Authorization, url),
|
|
54
|
+
antiShakeKey: Md5.hashStr(normalizedPayload),
|
|
55
|
+
'Cache-Control': 'no-cache',
|
|
56
|
+
replayToken: encrypt.encrypt(JSON.stringify(replayObj)),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -16,6 +16,8 @@ export function getAcceptString(accept: string): string | undefined {
|
|
|
16
16
|
return '.xls,.xlsx'
|
|
17
17
|
} else if (accept === 'ppt') {
|
|
18
18
|
return '.ppt,.pptx'
|
|
19
|
+
} else if (accept === 'zip') {
|
|
20
|
+
return '.zip'
|
|
19
21
|
}
|
|
20
22
|
return undefined
|
|
21
23
|
}
|
|
@@ -28,7 +30,7 @@ export function getAcceptSuffixes(accept: string): string[] | null {
|
|
|
28
30
|
return acceptStr.split(',').map((suffix) => suffix.slice(1).toLowerCase())
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
const ACCEPT_TYPES = ['images', 'document', 'txt', 'pdf', 'word', 'excel', 'ppt'] as const
|
|
33
|
+
const ACCEPT_TYPES = ['images', 'document', 'txt', 'pdf', 'word', 'excel', 'ppt', 'zip'] as const
|
|
32
34
|
|
|
33
35
|
const ALL_PREVIEW_SUFFIXES = new Set(
|
|
34
36
|
ACCEPT_TYPES.flatMap((accept) => getAcceptSuffixes(accept) ?? []),
|