Merge remote-tracking branch 'origin/master'
build / task (16.x, npm, macOS-latest) (push) Canceled after 0s
build / task (16.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, npm, windows-latest) (push) Canceled after 0s
build / task (16.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (16.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (16.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (16.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (16.x, yarn, windows-latest) (push) Canceled after 0s
build / task (18.x, npm, macOS-latest) (push) Canceled after 0s
build / task (18.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, npm, windows-latest) (push) Canceled after 0s
build / task (18.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (18.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (18.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (18.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (18.x, yarn, windows-latest) (push) Canceled after 0s
build / task (20.x, npm, macOS-latest) (push) Canceled after 0s
build / task (20.x, npm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, npm, windows-latest) (push) Canceled after 0s
build / task (20.x, pnpm, macOS-latest) (push) Canceled after 0s
build / task (20.x, pnpm, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, pnpm, windows-latest) (push) Canceled after 0s
build / task (20.x, yarn, macOS-latest) (push) Canceled after 0s
build / task (20.x, yarn, ubuntu-latest) (push) Canceled after 0s
build / task (20.x, yarn, windows-latest) (push) Canceled after 0s

This commit is contained in:
zjf committed 2026-10-29 22:00:24 +08:00
commit 23dd3532bc
5 files changed
+109 -53

No files matched your search

+6
View File
@@ -21,3 +21,9 @@ VITE_IMAGE_BASE_PATH = https://www.pjzhhq.cn/api
# 代码生成服务地址
VITE_GEN_PROXY_PATH = http://123.156.230.15:5003
VITE_FILE_ACCESS_APP_ID="admin"
VITE_FILE_ACCESS_KEY_ID="v1"
VITE_FILE_ACCESS_KEY="5UhL2DT+y//+0qCF4Abm9h6MPbEOvJfGuLf2eZ28QSw="
VITE_FILE_ACCESS_ALLOWED_ORIGINS="https://www.pjzhhq.cn,https://stgl.pj.gov.cn"
+15 -19
View File
@@ -66,7 +66,7 @@ interface UploadFileProps {
drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
fileType?: File.ImageMimeType[] // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
fileType?: string[] // 图片类型限制 ==> 非必传(默认 JPEG、PNG、GIF、WebP)
height?: string // 组件高度 ==> 非必传(默认为 150px)
width?: string // 组件宽度 ==> 非必传(默认为 150px)
borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
@@ -82,7 +82,7 @@ const props = withDefaults(defineProps<UploadFileProps>(), {
drag: true,
disabled: false,
fileSize: 5,
fileType: () => ["image/jpeg", "image/png", "image/gif"],
fileType: () => ["image/jpeg", "image/png", "image/gif", "image/webp"],
height: "150px",
width: "150px",
borderRadius: "8px",
@@ -116,21 +116,17 @@ const handleHttpUpload = async (options: UploadRequestOptions) => {
let formData = new FormData()
formData.append("file", options.file)
formData.append("dir", props.dir)
try {
const { data } = await request({
url: props.uploadFileUrl,
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
emit("update:imageUrl", data.url)
// 调用 el-form 内部的校验方法(可自动校验)
formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
} catch (error) {
options.onError(error as any)
}
const { data } = await request({
url: props.uploadFileUrl,
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
emit("update:imageUrl", data.url)
// 调用 el-form 内部的校验方法(可自动校验)
formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
}
/**
@@ -186,10 +182,10 @@ const uploadSuccess = () => {
/**
* @description 图片上传错误
* */
const uploadError = () => {
const uploadError = (error: any) => {
ElNotification({
title: "温馨提示",
message: "图片上传失败,请您重新上传!",
message: error?.msg || error?.message || "图片上传失败,请您重新上传!",
type: "error",
})
}
+13 -17
View File
@@ -42,7 +42,7 @@ interface UploadFileProps {
}
const props = withDefaults(defineProps<UploadFileProps>(), {
disabled: false,
fileType: () => ["image/jpeg", "image/png", "image/gif"],
fileType: () => ["image/jpeg", "image/png", "image/gif", "image/webp"],
fileSize: 5,
height: "150px",
width: "150px",
@@ -66,20 +66,16 @@ const formContext = inject(formContextKey, void 0)
const handleHttpUpload = async (options: UploadRequestOptions) => {
let formData = new FormData()
formData.append("file", options.file)
try {
const res = await request({
url: "/admin/sys-file/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
if (res.code == 0) {
return res
}
} catch (error) {
options.onError(error as any)
const res = await request({
url: "/admin/sys-file/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
if (res.code == 0) {
return res
}
}
@@ -151,10 +147,10 @@ const handleRemove = (uploadFile: any, uploadFiles: any[]) => {
/**
* @description 图片上传错误
* */
const uploadError = () => {
const uploadError = (error: any) => {
ElNotification({
title: "温馨提示",
message: "图片上传失败,请您重新上传!",
message: error?.msg || error?.message || "图片上传失败,请您重新上传!",
type: "error",
})
}
+13 -17
View File
@@ -31,7 +31,7 @@ interface UploadFileProps {
}
const props = withDefaults(defineProps<UploadFileProps>(), {
disabled: false,
fileType: () => ["image/jpeg", "image/png", "image/gif"],
fileType: () => ["image/jpeg", "image/png", "image/gif", "image/webp"],
fileSize: 5,
height: "150px",
width: "150px",
@@ -51,20 +51,16 @@ const formContext = inject(formContextKey, void 0)
const handleHttpUpload = async (options: UploadRequestOptions) => {
let formData = new FormData()
formData.append("file", options.file)
try {
const res = await request({
url: "/admin/sys-file/qn/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
if (res.code == 0) {
return res
}
} catch (error) {
options.onError(error as any)
const res = await request({
url: "/admin/sys-file/qn/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
if (res.code == 0) {
return res
}
}
@@ -137,10 +133,10 @@ const handleRemove = (uploadFile: any, uploadFiles: any[]) => {
/**
* @description 图片上传错误
* */
const uploadError = () => {
const uploadError = (error: any) => {
ElNotification({
title: "温馨提示",
message: "图片上传失败,请您重新上传!",
message: error?.msg || error?.message || "图片上传失败,请您重新上传!",
type: "error",
})
}
+62
View File
@@ -0,0 +1,62 @@
const { test } = require('node:test')
const assert = require('node:assert/strict')
const fs = require('node:fs')
const path = require('node:path')
const vue = require('vue')
const { parse, compileScript } = require('@vue/compiler-sfc')
const { compile, root } = require('./helpers/file-access-runtime.cjs')
function setup(name, request) {
const notifications = [], events = [], model = vue.ref('')
const descriptor = parse(fs.readFileSync(path.join(root, 'src/components/Upload', name), 'utf8')).descriptor
const loaded = { exports: {} }
const mockVue = { ...vue, inject() {}, onMounted() {}, onBeforeUnmount() {}, useModel: () => model }
const mocks = {
vue: mockVue,
'element-plus': { ElNotification: value => notifications.push(value), formContextKey: Symbol(), formItemContextKey: Symbol() },
'@element-plus/icons-vue': {},
'/@/utils/request': { default: request },
'/@/utils/other': { generateUUID: () => 'upload-test' },
'/@/utils/file-access': { fileUrl: value => value, originalFileUrl: value => value, resolveFileUrl: value => value },
'/@/utils/file-access-dom': { bindFileAccessDom() {} },
}
const globals = { inject: mockVue.inject, computed: vue.computed, onMounted() {}, onBeforeUnmount() {} }
const source = compileScript(descriptor, { id: name }).content.replace(/import\.meta\.env/g, '({})')
new Function('module', 'exports', 'require', ...Object.keys(globals), compile(source))(
loaded, loaded.exports, key => key in mocks ? mocks[key] : require(key), ...Object.values(globals))
const props = {}
for (const [name, settings] of Object.entries(loaded.exports.default.props)) {
if ('default' in settings) props[name] = typeof settings.default === 'function' ? settings.default() : settings.default
}
const state = loaded.exports.default.setup(props, { expose() {}, emit: (...args) => events.push(args) })
return { state, props, notifications, events, model }
}
for (const name of ['Image.vue', 'Images.vue', 'qnImages.vue']) {
test(name + ': WebP is allowed by default and backend errors never trigger a success notification', async () => {
const failure = { msg: '图片实际格式未在白名单中' }
const { state, props, notifications, events } = setup(name, async () => { throw failure })
const file = new File(['public test fixture'], 'logo.webp', { type: 'image/webp' })
assert.ok(props.fileType.includes('image/webp'))
assert.equal(state.beforeUpload(file), true)
assert.equal(notifications.length, 0)
let callbackCount = 0
await state.handleHttpUpload({ file, onError() { callbackCount++ } })
.then(state.uploadSuccess, state.uploadError)
assert.equal(callbackCount, 0, 'Element Plus handles the rejected Promise once')
assert.deepEqual(notifications.map(value => [value.type, value.message]), [['error', failure.msg]])
assert.equal(events.length, 0)
props.fileType = ['image/png']
assert.equal(state.beforeUpload(file), false, 'explicit business type restrictions are respected')
})
}
test('single-image uploads preserve the canonical raw WebP URL returned by the server', async () => {
const raw = '/admin/sys-file/oss/file?fileName=logo.webp'
const { state, events } = setup('Image.vue', async options => {
assert.equal(options.data.get('file').name, 'logo.png')
return { code: 0, data: { url: raw } }
})
await state.handleHttpUpload({ file: new File(['test'], 'logo.png', { type: 'image/png' }) })
assert.deepEqual(events, [['update:imageUrl', raw]])
})