diff --git a/templates/vue/api.ts.j2 b/templates/vue/api.ts.j2 index 54fb1a6..9df1d2a 100644 --- a/templates/vue/api.ts.j2 +++ b/templates/vue/api.ts.j2 @@ -9,46 +9,46 @@ import { useAccessStore } from '@vben/stores'; export namespace {{entity}}Api { - const applicationConfig = useAppConfig(import.meta.env, import.meta.env.PROD); - console.log('=== 接口域名 ===', applicationConfig.javaURL) + const applicationConfig = useAppConfig(import.meta.env, import.meta.env.PROD); + console.log('=== 接口域名 ===', applicationConfig.javaURL) - /** - * 分页查询 - */ - export function page(params: any) { - return requestClient.post(applicationConfig.javaURL+'/{{old_table}}/page', params, - { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); - } + /** + * 分页查询 + */ + export function page(params: any) { + return requestClient.post(applicationConfig.javaURL+'/{{old_table}}/page', params, + { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); + } - /** - * 获取详情 - */ - export function get(id: number) { - return requestClient.get(applicationConfig.javaURL+'/{{old_table}}/' + id); - } + /** + * 获取详情 + */ + export function get(id: number) { + return requestClient.get(applicationConfig.javaURL+'/{{old_table}}/' + id); + } - /** - * 新增 - */ - export function add(data: any) { - return requestClient.post(applicationConfig.javaURL+'/{{old_table}}/add', data, - { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); - } + /** + * 新增 + */ + export function add(data: any) { + return requestClient.post(applicationConfig.javaURL+'/{{old_table}}/add', data, + { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); + } - /** - * 修改 - */ - export function save(data: any) { - return requestClient.post(applicationConfig.javaURL+'/{{old_table}}/modify', data, - { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); - } + /** + * 修改 + */ + export function save(data: any) { + return requestClient.post(applicationConfig.javaURL+'/{{old_table}}/modify', data, + { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); + } - /** - * 删除 - */ - export function remove(id: number) { - return requestClient.delete(applicationConfig.javaURL+'/{{old_table}}/' + id); - } + /** + * 删除 + */ + export function remove(id: number) { + return requestClient.delete(applicationConfig.javaURL+'/{{old_table}}/' + id); + } /** * 枚举列表 @@ -58,12 +58,12 @@ export namespace {{entity}}Api { { headers: {'Content-Type': 'application/json', Token: useAccessStore().accessToken, version: '1.0.1'}}); } - /** - * 上传图片 - */ - export function upload(params: any) { - return requestClient.post(applicationConfig.javaURL+'/file/up', params, - { headers: {'Content-Type': 'multipart/form-data', Token: useAccessStore().accessToken, version: '1.0.1'}}); - } + /** + * 上传图片 + */ + export function upload(params: any) { + return requestClient.post(applicationConfig.javaURL+'/file/up', params, + { headers: {'Content-Type': 'multipart/form-data', Token: useAccessStore().accessToken, version: '1.0.1'}}); + } } \ No newline at end of file diff --git a/templates/vue/index.vue.j2 b/templates/vue/index.vue.j2 index 3b20dad..1949336 100644 --- a/templates/vue/index.vue.j2 +++ b/templates/vue/index.vue.j2 @@ -18,7 +18,6 @@ const API_BASE_URL = import.meta.env.VITE_GLOB_API_URL || ''; const currentRow = ref(null); const isEdit = ref(false); const modalTitle = ref('新增'); -const uploadVisible = ref(false); const uploadFieldName = ref(''); const uploadImageUrl = ref(''); const uploadedUrl = ref(''); // 上传成功后返回的 @@ -33,14 +32,12 @@ const enumData = reactive({ }); //todo 枚举数据在查询里面不展示的配置 const hiddenColumns = ref(['fun_code', 'graduallyIntervalTime', 'funMsgTitle', 'funImg', 'createdAt', 'updatedBy', 'updatedAt', 'userPassword', 'userId', 'userSys', 'deletedFlag', "userFace"]) -const editFields = ['userId', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy', 'deletedFlag']; +const editFields = [{{editFields}}]; // ========== 判断是否是图片字段 ========== -function isImageField(fieldName: string): boolean { - const lowerName = fieldName.toLowerCase(); - return lowerName.includes('img') || lowerName.includes('face') || lowerName.includes('picture'); +function isImageField(field: string) { + return /img|face|picture/i.test(field); } - // ========== 初始化枚举数据和查询表单 ========== async function initEnumData() { try { @@ -111,7 +108,6 @@ onMounted(() => { initEnumData(); }); - // ========== 查询表单配置 (初始为空 schema) ========== const [QueryForm, queryFormApi] = useVbenForm({ schema: [], // 初始化为空数组 @@ -134,9 +130,13 @@ watch( {immediate: false} ); -// 存储当前页码 -const currentPageRef = ref(1); + // ========== 表格配置 ========== +function getFullUrl(url: string) { + if (!url) return ''; + if (url.startsWith('http')) return url; + return `${API_BASE_URL}${url}`; +} const gridOptions = { columns: [ ...columns.map(col => { @@ -149,126 +149,27 @@ const gridOptions = { slots: { default: ({row}: any) => { const imgUrl = row[col.field]; - - // 如果没有图片,显示提示文字 + const handleClick = (e: Event) => { + e.stopPropagation(); + currentRow.value = row; + isEdit.value = true; + openUploadDialog(col.field, imgUrl); + }; if (!imgUrl) { - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - gap: '8px', - height: '50px', - } - }, [ - h('span', { - style: { - color: '#999', - fontSize: '12px' - } - }, '无图片'), - h('button', { - onClick: (e: Event) => { - e.stopPropagation(); - // 设置当前行数据 - currentRow.value = row; - isEdit.value = true; // 设置为编辑模式 - openUploadDialog(col.field, imgUrl); - }, - style: { - padding: '4px 8px', - fontSize: '12px', - color: '#1890ff', - backgroundColor: '#e6f7ff', - border: '1px solid #1890ff', - borderRadius: '4px', - cursor: 'pointer', - } - }, '上传') + return h('div', { class: 'flex items-center justify-center gap-2 h-[50px]' }, [ + h('span', { class: 'text-gray-400 text-xs' }, '无图片'), + h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '上传'), ]); } - - // 判断是否是完整的 URL - let fullUrl = imgUrl; - if (!imgUrl.startsWith('http://') && !imgUrl.startsWith('https://')) { - // 如果不是完整 URL,拼接基础 API 地址 - const apiURL = import.meta.env.VITE_GLOB_API_URL || ''; - fullUrl = `${apiURL}${imgUrl}`; - } - - console.log('🖼️ 图片 URL:', fullUrl); - - // 返回图片组件和上传按钮 - try { - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - gap: '8px', - } - }, [ - h(Image, { - src: fullUrl, - height: 60, - width: 80, - preview: true, - style: { - borderRadius: '4px', - objectFit: 'cover', - cursor: 'pointer', - boxShadow: '0 2px 4px rgba(0,0,0,0.1)', - }, - onError: () => { - console.error('❌ 图片加载失败:', fullUrl); - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '50px', - backgroundColor: '#f5f5f5', - borderRadius: '4px', - color: '#999', - fontSize: '12px' - } - }, '加载失败'); - } - }), - h('button', { - onClick: (e: Event) => { - e.stopPropagation(); - // 设置当前行数据 - currentRow.value = row; - isEdit.value = true; // 设置为编辑模式 - openUploadDialog(col.field, imgUrl); - }, - style: { - padding: '4px 8px', - fontSize: '12px', - color: '#1890ff', - backgroundColor: '#e6f7ff', - border: '1px solid #1890ff', - borderRadius: '4px', - cursor: 'pointer', - } - }, '更换') - ]); - } catch (error) { - console.error('❌ 图片渲染错误:', error); - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '50px', - backgroundColor: '#fffbe6', - borderRadius: '4px', - color: '#faad14', - fontSize: '12px' - } - }, '渲染失败'); - } + return h('div', { class: 'flex items-center gap-2 justify-center' }, [ + h(Image, { + src: getFullUrl(imgUrl), + width: 80, + height: 60, + preview: true, + }), + h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '更换'), + ]); } } }; @@ -289,14 +190,6 @@ const gridOptions = { try { // 获取查询表单的值 const queryValues = await queryFormApi.getValues(); - - console.log('=== 查询参数 ===', { - pageNum: page?.currentPage || 1, - pageSize: page?.pageSize || 10, - currentPageRef: currentPageRef.value, - ...queryValues, - }) - const res = await {{entity}}Api.page({ pageNum: page.currentPage || 1, pageSize: page?.pageSize || 10, @@ -343,6 +236,7 @@ const [Modal, modalApi] = useVbenModal({ modalApi.close(); }, onConfirm: async () => { + let loadingMessage: any = null; try { const values = await formApi.validateAndSubmitForm(); if (!values) return; @@ -357,22 +251,31 @@ const [Modal, modalApi] = useVbenModal({ ...submitValues, userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null, }; + // 显示 loading 提示 + loadingMessage = message.loading(isEdit.value ? '保存中...' : '新增中...', 0); if (isEdit.value && currentRow.value?.id) { await {{entity}}Api.save({...finalSubmitValues, id: currentRow.value.id}); Object.assign(currentRow.value, finalSubmitValues); modalApi.close(); gridApi.reloadRow(currentRow.value); + loadingMessage(); isEdit.value = false; + message.success('保存成功!'); } else { await {{entity}}Api.add(finalSubmitValues); // 新增才 reload(必须) modalApi.close(); gridApi.reload(); formUploadUrls.value = {}; + loadingMessage(); + message.success('新增成功!'); } } catch (error) { console.error('保存失败:', error); + if (loadingMessage) { + loadingMessage(); + } } }, onOpenChange(isOpen: boolean) { @@ -399,6 +302,7 @@ const [UploadModal, uploadModalApi] = useVbenModal({ uploadedUrl.value = ''; }, onConfirm: async () => { + let loadingMessage: any = null; console.log('=== 点击确认保存 ===', { uploadedUrl: uploadedUrl.value, isEdit: isEdit.value, @@ -427,14 +331,15 @@ const [UploadModal, uploadModalApi] = useVbenModal({ id: currentRow.value.id }; console.log('📤 提交保存数据:', submitData); - + // 显示 loading 提示 + loadingMessage = message.loading('保存图片中...', 0); await {{entity}}Api.save(submitData); message.success('保存成功!'); // 关闭弹窗并刷新表格 uploadModalApi.close(); // gridApi.reload(); - + loadingMessage() // 重置状态 uploadFileList.value = []; uploadedUrl.value = ''; @@ -452,6 +357,9 @@ const [UploadModal, uploadModalApi] = useVbenModal({ } catch (error: any) { console.error('❌ 保存失败:', error); + if (loadingMessage) { + loadingMessage(); + } message.error(error?.message || '保存失败'); } } else { @@ -497,13 +405,7 @@ const getEditFormSchema = () => { console.log('📦 新增表单内上传文件:', file); try { - const formData = new FormData(); - formData.append('file', file); - - // 调用上传 API - const res = await {{entity}}Api.upload(formData); - const resultUrl = res.result || res.message || res.url || res; - + const resultUrl = await uploadFile(file); console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl); message.success('上传成功!'); @@ -545,6 +447,19 @@ const [Form, formApi] = useVbenForm({ }, }) +// ========== 上传文件 ========== + +async function uploadFile(file: File) { + let loadingMessage: any = null; + // 显示 loading 提示 + loadingMessage = message.loading('图片上传中...', 0); + const formData = new FormData(); + formData.append('file', file); + const res = await {{entity}}Api.upload(formData); + loadingMessage(); + return res.result || res.message || res.url || res; +} + // ========== 打开上传对话框 ========== function openUploadDialog(fieldName: string, currentUrl: string) { console.log('=== 打开上传对话框 ===', { @@ -559,7 +474,6 @@ function openUploadDialog(fieldName: string, currentUrl: string) { uploadImageUrl.value = currentUrl || ''; uploadedUrl.value = ''; // 重置上传后的 URL uploadFileList.value = []; // 清空文件列表 - uploadVisible.value = true; uploadModalApi.open(); } @@ -575,17 +489,9 @@ async function handleCustomRequest(options: any) { size: file.size, lastModified: file.lastModified, }); - - const formData = new FormData(); - formData.append('file', file); - - // 调用上传 API - const res = await {{entity}}Api.upload(formData); - const resultUrl = res.result || res.message || res.url || res; - + const resultUrl = await uploadFile(file); console.log('✅ 上传成功,URL:', resultUrl); message.success('上传成功!'); - // 保存上传返回的 URL uploadedUrl.value = resultUrl; console.log('=== uploadedUrl 赋值后 ===', uploadedUrl.value); @@ -608,20 +514,6 @@ async function handleCustomRequest(options: any) { } } -// ========== 上传成功或失败后的处理 -function handleChange(info: any) { - const {status} = info.file; - console.log('📋 文件状态变化:', status, info.file); - - if (status === 'done') { - console.log('✅ 上传完成响应:', info); - } else if (status === 'error') { - console.error('❌ 上传失败:', info); - message.error(`${info.file.name} 上传失败`); - } -} - - // ========== 打开新增弹窗 ========== function handleAdd() { isEdit.value = false; @@ -679,7 +571,6 @@ function handleReset() { queryFormApi.resetForm(); gridApi.reload(); } - @@ -728,7 +619,6 @@ function handleReset() {
-

当前图片:

diff --git a/vue-vben-admin/apps/web-antd/src/views/device/index.vue b/vue-vben-admin/apps/web-antd/src/views/device/index.vue index b760d3e..b42154d 100644 --- a/vue-vben-admin/apps/web-antd/src/views/device/index.vue +++ b/vue-vben-admin/apps/web-antd/src/views/device/index.vue @@ -18,7 +18,6 @@ const API_BASE_URL = import.meta.env.VITE_GLOB_API_URL || ''; const currentRow = ref(null); const isEdit = ref(false); const modalTitle = ref('新增'); -const uploadVisible = ref(false); const uploadFieldName = ref(''); const uploadImageUrl = ref(''); const uploadedUrl = ref(''); // 上传成功后返回的 @@ -36,11 +35,9 @@ const hiddenColumns = ref(['fun_code', 'graduallyIntervalTime', 'funMsgTitle', ' const editFields = ['userId', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy', 'deletedFlag']; // ========== 判断是否是图片字段 ========== -function isImageField(fieldName: string): boolean { - const lowerName = fieldName.toLowerCase(); - return lowerName.includes('img') || lowerName.includes('face') || lowerName.includes('picture'); +function isImageField(field: string) { + return /img|face|picture/i.test(field); } - // ========== 初始化枚举数据和查询表单 ========== async function initEnumData() { try { @@ -111,7 +108,6 @@ onMounted(() => { initEnumData(); }); - // ========== 查询表单配置 (初始为空 schema) ========== const [QueryForm, queryFormApi] = useVbenForm({ schema: [], // 初始化为空数组 @@ -137,6 +133,11 @@ watch( // 存储当前页码 const currentPageRef = ref(1); // ========== 表格配置 ========== +function getFullUrl(url: string) { + if (!url) return ''; + if (url.startsWith('http')) return url; + return `${API_BASE_URL}${url}`; +} const gridOptions = { columns: [ ...columns.map(col => { @@ -149,126 +150,27 @@ const gridOptions = { slots: { default: ({row}: any) => { const imgUrl = row[col.field]; - - // 如果没有图片,显示提示文字 + const handleClick = (e: Event) => { + e.stopPropagation(); + currentRow.value = row; + isEdit.value = true; + openUploadDialog(col.field, imgUrl); + }; if (!imgUrl) { - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - gap: '8px', - height: '50px', - } - }, [ - h('span', { - style: { - color: '#999', - fontSize: '12px' - } - }, '无图片'), - h('button', { - onClick: (e: Event) => { - e.stopPropagation(); - // 设置当前行数据 - currentRow.value = row; - isEdit.value = true; // 设置为编辑模式 - openUploadDialog(col.field, imgUrl); - }, - style: { - padding: '4px 8px', - fontSize: '12px', - color: '#1890ff', - backgroundColor: '#e6f7ff', - border: '1px solid #1890ff', - borderRadius: '4px', - cursor: 'pointer', - } - }, '上传') - ]); - } - - // 判断是否是完整的 URL - let fullUrl = imgUrl; - if (!imgUrl.startsWith('http://') && !imgUrl.startsWith('https://')) { - // 如果不是完整 URL,拼接基础 API 地址 - const apiURL = import.meta.env.VITE_GLOB_API_URL || ''; - fullUrl = `${apiURL}${imgUrl}`; - } - - console.log('🖼️ 图片 URL:', fullUrl); - - // 返回图片组件和上传按钮 - try { - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - gap: '8px', - } - }, [ - h(Image, { - src: fullUrl, - height: 60, - width: 80, - preview: true, - style: { - borderRadius: '4px', - objectFit: 'cover', - cursor: 'pointer', - boxShadow: '0 2px 4px rgba(0,0,0,0.1)', - }, - onError: () => { - console.error('❌ 图片加载失败:', fullUrl); - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '50px', - backgroundColor: '#f5f5f5', - borderRadius: '4px', - color: '#999', - fontSize: '12px' - } - }, '加载失败'); - } - }), - h('button', { - onClick: (e: Event) => { - e.stopPropagation(); - // 设置当前行数据 - currentRow.value = row; - isEdit.value = true; // 设置为编辑模式 - openUploadDialog(col.field, imgUrl); - }, - style: { - padding: '4px 8px', - fontSize: '12px', - color: '#1890ff', - backgroundColor: '#e6f7ff', - border: '1px solid #1890ff', - borderRadius: '4px', - cursor: 'pointer', - } - }, '更换') + return h('div', { class: 'flex items-center justify-center gap-2 h-[50px]' }, [ + h('span', { class: 'text-gray-400 text-xs' }, '无图片'), + h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '上传'), ]); - } catch (error) { - console.error('❌ 图片渲染错误:', error); - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '50px', - backgroundColor: '#fffbe6', - borderRadius: '4px', - color: '#faad14', - fontSize: '12px' - } - }, '渲染失败'); } + return h('div', { class: 'flex items-center gap-2 justify-center' }, [ + h(Image, { + src: getFullUrl(imgUrl), + width: 80, + height: 60, + preview: true, + }), + h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '更换'), + ]); } } }; @@ -343,6 +245,7 @@ const [Modal, modalApi] = useVbenModal({ modalApi.close(); }, onConfirm: async () => { + let loadingMessage: any = null; try { const values = await formApi.validateAndSubmitForm(); if (!values) return; @@ -357,22 +260,31 @@ const [Modal, modalApi] = useVbenModal({ ...submitValues, userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null, }; + // 显示 loading 提示 + loadingMessage = message.loading(isEdit.value ? '保存中...' : '新增中...', 0); if (isEdit.value && currentRow.value?.id) { await deviceApi.save({...finalSubmitValues, id: currentRow.value.id}); Object.assign(currentRow.value, finalSubmitValues); modalApi.close(); gridApi.reloadRow(currentRow.value); + loadingMessage(); isEdit.value = false; + message.success('保存成功!'); } else { await deviceApi.add(finalSubmitValues); // 新增才 reload(必须) modalApi.close(); gridApi.reload(); formUploadUrls.value = {}; + loadingMessage(); + message.success('新增成功!'); } } catch (error) { console.error('保存失败:', error); + if (loadingMessage) { + loadingMessage(); + } } }, onOpenChange(isOpen: boolean) { @@ -399,6 +311,7 @@ const [UploadModal, uploadModalApi] = useVbenModal({ uploadedUrl.value = ''; }, onConfirm: async () => { + let loadingMessage: any = null; console.log('=== 点击确认保存 ===', { uploadedUrl: uploadedUrl.value, isEdit: isEdit.value, @@ -427,14 +340,15 @@ const [UploadModal, uploadModalApi] = useVbenModal({ id: currentRow.value.id }; console.log('📤 提交保存数据:', submitData); - + // 显示 loading 提示 + loadingMessage = message.loading('保存图片中...', 0); await deviceApi.save(submitData); message.success('保存成功!'); // 关闭弹窗并刷新表格 uploadModalApi.close(); // gridApi.reload(); - + loadingMessage() // 重置状态 uploadFileList.value = []; uploadedUrl.value = ''; @@ -452,6 +366,9 @@ const [UploadModal, uploadModalApi] = useVbenModal({ } catch (error: any) { console.error('❌ 保存失败:', error); + if (loadingMessage) { + loadingMessage(); + } message.error(error?.message || '保存失败'); } } else { @@ -497,13 +414,7 @@ const getEditFormSchema = () => { console.log('📦 新增表单内上传文件:', file); try { - const formData = new FormData(); - formData.append('file', file); - - // 调用上传 API - const res = await deviceApi.upload(formData); - const resultUrl = res.result || res.message || res.url || res; - + const resultUrl = await uploadFile(file); console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl); message.success('上传成功!'); @@ -545,6 +456,19 @@ const [Form, formApi] = useVbenForm({ }, }) +// ========== 上传文件 ========== + +async function uploadFile(file: File) { + let loadingMessage: any = null; + // 显示 loading 提示 + loadingMessage = message.loading('图片上传中...', 0); + const formData = new FormData(); + formData.append('file', file); + const res = await deviceApi.upload(formData); + loadingMessage(); + return res.result || res.message || res.url || res; +} + // ========== 打开上传对话框 ========== function openUploadDialog(fieldName: string, currentUrl: string) { console.log('=== 打开上传对话框 ===', { @@ -559,7 +483,6 @@ function openUploadDialog(fieldName: string, currentUrl: string) { uploadImageUrl.value = currentUrl || ''; uploadedUrl.value = ''; // 重置上传后的 URL uploadFileList.value = []; // 清空文件列表 - uploadVisible.value = true; uploadModalApi.open(); } @@ -575,17 +498,9 @@ async function handleCustomRequest(options: any) { size: file.size, lastModified: file.lastModified, }); - - const formData = new FormData(); - formData.append('file', file); - - // 调用上传 API - const res = await deviceApi.upload(formData); - const resultUrl = res.result || res.message || res.url || res; - + const resultUrl = await uploadFile(file); console.log('✅ 上传成功,URL:', resultUrl); message.success('上传成功!'); - // 保存上传返回的 URL uploadedUrl.value = resultUrl; console.log('=== uploadedUrl 赋值后 ===', uploadedUrl.value); @@ -608,20 +523,6 @@ async function handleCustomRequest(options: any) { } } -// ========== 上传成功或失败后的处理 -function handleChange(info: any) { - const {status} = info.file; - console.log('📋 文件状态变化:', status, info.file); - - if (status === 'done') { - console.log('✅ 上传完成响应:', info); - } else if (status === 'error') { - console.error('❌ 上传失败:', info); - message.error(`${info.file.name} 上传失败`); - } -} - - // ========== 打开新增弹窗 ========== function handleAdd() { isEdit.value = false; @@ -679,7 +580,6 @@ function handleReset() { queryFormApi.resetForm(); gridApi.reload(); } - @@ -728,7 +628,6 @@ function handleReset() { -

当前图片:

diff --git a/vue-vben-admin/apps/web-antd/src/views/fun/index.vue b/vue-vben-admin/apps/web-antd/src/views/fun/index.vue index 9cda98c..779a556 100644 --- a/vue-vben-admin/apps/web-antd/src/views/fun/index.vue +++ b/vue-vben-admin/apps/web-antd/src/views/fun/index.vue @@ -18,7 +18,6 @@ const API_BASE_URL = import.meta.env.VITE_GLOB_API_URL || ''; const currentRow = ref(null); const isEdit = ref(false); const modalTitle = ref('新增'); -const uploadVisible = ref(false); const uploadFieldName = ref(''); const uploadImageUrl = ref(''); const uploadedUrl = ref(''); // 上传成功后返回的 @@ -33,14 +32,12 @@ const enumData = reactive({ }); //todo 枚举数据在查询里面不展示的配置 const hiddenColumns = ref(['fun_code', 'graduallyIntervalTime', 'funMsgTitle', 'funImg', 'createdAt', 'updatedBy', 'updatedAt', 'userPassword', 'userId', 'userSys', 'deletedFlag', "userFace"]) -const editFields = ['userId', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy', 'deletedFlag']; +const editFields = ['userId','createdAt','createdBy','updatedAt','updatedBy','deletedFlag']; // ========== 判断是否是图片字段 ========== -function isImageField(fieldName: string): boolean { - const lowerName = fieldName.toLowerCase(); - return lowerName.includes('img') || lowerName.includes('face') || lowerName.includes('picture'); +function isImageField(field: string) { + return /img|face|picture/i.test(field); } - // ========== 初始化枚举数据和查询表单 ========== async function initEnumData() { try { @@ -111,7 +108,6 @@ onMounted(() => { initEnumData(); }); - // ========== 查询表单配置 (初始为空 schema) ========== const [QueryForm, queryFormApi] = useVbenForm({ schema: [], // 初始化为空数组 @@ -134,9 +130,13 @@ watch( {immediate: false} ); -// 存储当前页码 -const currentPageRef = ref(1); + // ========== 表格配置 ========== +function getFullUrl(url: string) { + if (!url) return ''; + if (url.startsWith('http')) return url; + return `${API_BASE_URL}${url}`; +} const gridOptions = { columns: [ ...columns.map(col => { @@ -149,126 +149,27 @@ const gridOptions = { slots: { default: ({row}: any) => { const imgUrl = row[col.field]; - - // 如果没有图片,显示提示文字 + const handleClick = (e: Event) => { + e.stopPropagation(); + currentRow.value = row; + isEdit.value = true; + openUploadDialog(col.field, imgUrl); + }; if (!imgUrl) { - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - gap: '8px', - height: '50px', - } - }, [ - h('span', { - style: { - color: '#999', - fontSize: '12px' - } - }, '无图片'), - h('button', { - onClick: (e: Event) => { - e.stopPropagation(); - // 设置当前行数据 - currentRow.value = row; - isEdit.value = true; // 设置为编辑模式 - openUploadDialog(col.field, imgUrl); - }, - style: { - padding: '4px 8px', - fontSize: '12px', - color: '#1890ff', - backgroundColor: '#e6f7ff', - border: '1px solid #1890ff', - borderRadius: '4px', - cursor: 'pointer', - } - }, '上传') + return h('div', { class: 'flex items-center justify-center gap-2 h-[50px]' }, [ + h('span', { class: 'text-gray-400 text-xs' }, '无图片'), + h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '上传'), ]); } - - // 判断是否是完整的 URL - let fullUrl = imgUrl; - if (!imgUrl.startsWith('http://') && !imgUrl.startsWith('https://')) { - // 如果不是完整 URL,拼接基础 API 地址 - const apiURL = import.meta.env.VITE_GLOB_API_URL || ''; - fullUrl = `${apiURL}${imgUrl}`; - } - - console.log('🖼️ 图片 URL:', fullUrl); - - // 返回图片组件和上传按钮 - try { - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - gap: '8px', - } - }, [ - h(Image, { - src: fullUrl, - height: 60, - width: 80, - preview: true, - style: { - borderRadius: '4px', - objectFit: 'cover', - cursor: 'pointer', - boxShadow: '0 2px 4px rgba(0,0,0,0.1)', - }, - onError: () => { - console.error('❌ 图片加载失败:', fullUrl); - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '50px', - backgroundColor: '#f5f5f5', - borderRadius: '4px', - color: '#999', - fontSize: '12px' - } - }, '加载失败'); - } - }), - h('button', { - onClick: (e: Event) => { - e.stopPropagation(); - // 设置当前行数据 - currentRow.value = row; - isEdit.value = true; // 设置为编辑模式 - openUploadDialog(col.field, imgUrl); - }, - style: { - padding: '4px 8px', - fontSize: '12px', - color: '#1890ff', - backgroundColor: '#e6f7ff', - border: '1px solid #1890ff', - borderRadius: '4px', - cursor: 'pointer', - } - }, '更换') - ]); - } catch (error) { - console.error('❌ 图片渲染错误:', error); - return h('div', { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '50px', - backgroundColor: '#fffbe6', - borderRadius: '4px', - color: '#faad14', - fontSize: '12px' - } - }, '渲染失败'); - } + return h('div', { class: 'flex items-center gap-2 justify-center' }, [ + h(Image, { + src: getFullUrl(imgUrl), + width: 80, + height: 60, + preview: true, + }), + h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '更换'), + ]); } } }; @@ -289,14 +190,6 @@ const gridOptions = { try { // 获取查询表单的值 const queryValues = await queryFormApi.getValues(); - - console.log('=== 查询参数 ===', { - pageNum: page?.currentPage || 1, - pageSize: page?.pageSize || 10, - currentPageRef: currentPageRef.value, - ...queryValues, - }) - const res = await funApi.page({ pageNum: page.currentPage || 1, pageSize: page?.pageSize || 10, @@ -343,6 +236,7 @@ const [Modal, modalApi] = useVbenModal({ modalApi.close(); }, onConfirm: async () => { + let loadingMessage: any = null; try { const values = await formApi.validateAndSubmitForm(); if (!values) return; @@ -357,22 +251,31 @@ const [Modal, modalApi] = useVbenModal({ ...submitValues, userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null, }; + // 显示 loading 提示 + loadingMessage = message.loading(isEdit.value ? '保存中...' : '新增中...', 0); if (isEdit.value && currentRow.value?.id) { await funApi.save({...finalSubmitValues, id: currentRow.value.id}); Object.assign(currentRow.value, finalSubmitValues); modalApi.close(); gridApi.reloadRow(currentRow.value); + loadingMessage(); isEdit.value = false; + message.success('保存成功!'); } else { await funApi.add(finalSubmitValues); // 新增才 reload(必须) modalApi.close(); gridApi.reload(); formUploadUrls.value = {}; + loadingMessage(); + message.success('新增成功!'); } } catch (error) { console.error('保存失败:', error); + if (loadingMessage) { + loadingMessage(); + } } }, onOpenChange(isOpen: boolean) { @@ -399,6 +302,7 @@ const [UploadModal, uploadModalApi] = useVbenModal({ uploadedUrl.value = ''; }, onConfirm: async () => { + let loadingMessage: any = null; console.log('=== 点击确认保存 ===', { uploadedUrl: uploadedUrl.value, isEdit: isEdit.value, @@ -427,14 +331,15 @@ const [UploadModal, uploadModalApi] = useVbenModal({ id: currentRow.value.id }; console.log('📤 提交保存数据:', submitData); - + // 显示 loading 提示 + loadingMessage = message.loading('保存图片中...', 0); await funApi.save(submitData); message.success('保存成功!'); // 关闭弹窗并刷新表格 uploadModalApi.close(); // gridApi.reload(); - + loadingMessage() // 重置状态 uploadFileList.value = []; uploadedUrl.value = ''; @@ -452,6 +357,9 @@ const [UploadModal, uploadModalApi] = useVbenModal({ } catch (error: any) { console.error('❌ 保存失败:', error); + if (loadingMessage) { + loadingMessage(); + } message.error(error?.message || '保存失败'); } } else { @@ -497,13 +405,7 @@ const getEditFormSchema = () => { console.log('📦 新增表单内上传文件:', file); try { - const formData = new FormData(); - formData.append('file', file); - - // 调用上传 API - const res = await funApi.upload(formData); - const resultUrl = res.result || res.message || res.url || res; - + const resultUrl = await uploadFile(file); console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl); message.success('上传成功!'); @@ -545,6 +447,19 @@ const [Form, formApi] = useVbenForm({ }, }) +// ========== 上传文件 ========== + +async function uploadFile(file: File) { + let loadingMessage: any = null; + // 显示 loading 提示 + loadingMessage = message.loading('图片上传中...', 0); + const formData = new FormData(); + formData.append('file', file); + const res = await funApi.upload(formData); + loadingMessage(); + return res.result || res.message || res.url || res; +} + // ========== 打开上传对话框 ========== function openUploadDialog(fieldName: string, currentUrl: string) { console.log('=== 打开上传对话框 ===', { @@ -559,7 +474,6 @@ function openUploadDialog(fieldName: string, currentUrl: string) { uploadImageUrl.value = currentUrl || ''; uploadedUrl.value = ''; // 重置上传后的 URL uploadFileList.value = []; // 清空文件列表 - uploadVisible.value = true; uploadModalApi.open(); } @@ -575,17 +489,9 @@ async function handleCustomRequest(options: any) { size: file.size, lastModified: file.lastModified, }); - - const formData = new FormData(); - formData.append('file', file); - - // 调用上传 API - const res = await funApi.upload(formData); - const resultUrl = res.result || res.message || res.url || res; - + const resultUrl = await uploadFile(file); console.log('✅ 上传成功,URL:', resultUrl); message.success('上传成功!'); - // 保存上传返回的 URL uploadedUrl.value = resultUrl; console.log('=== uploadedUrl 赋值后 ===', uploadedUrl.value); @@ -608,20 +514,6 @@ async function handleCustomRequest(options: any) { } } -// ========== 上传成功或失败后的处理 -function handleChange(info: any) { - const {status} = info.file; - console.log('📋 文件状态变化:', status, info.file); - - if (status === 'done') { - console.log('✅ 上传完成响应:', info); - } else if (status === 'error') { - console.error('❌ 上传失败:', info); - message.error(`${info.file.name} 上传失败`); - } -} - - // ========== 打开新增弹窗 ========== function handleAdd() { isEdit.value = false; @@ -679,7 +571,6 @@ function handleReset() { queryFormApi.resetForm(); gridApi.reload(); } - @@ -728,7 +619,6 @@ function handleReset() { -

当前图片: