Browse Source

分页刷新问题

master
zhanglei 1 day ago
parent
commit
0521c19267
  1. 216
      templates/vue/index.vue.j2
  2. 203
      vue-vben-admin/apps/web-antd/src/views/device/index.vue
  3. 214
      vue-vben-admin/apps/web-antd/src/views/fun/index.vue

216
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 currentRow = ref(null);
const isEdit = ref(false); const isEdit = ref(false);
const modalTitle = ref('新增'); const modalTitle = ref('新增');
const uploadVisible = ref(false);
const uploadFieldName = ref(''); const uploadFieldName = ref('');
const uploadImageUrl = ref(''); const uploadImageUrl = ref('');
const uploadedUrl = ref(''); // 上传成功后返回的 const uploadedUrl = ref(''); // 上传成功后返回的
@ -33,14 +32,12 @@ const enumData = reactive({
}); });
//todo 枚举数据在查询里面不展示的配置 //todo 枚举数据在查询里面不展示的配置
const hiddenColumns = ref(['fun_code', 'graduallyIntervalTime', 'funMsgTitle', 'funImg', 'createdAt', 'updatedBy', 'updatedAt', 'userPassword', 'userId', 'userSys', 'deletedFlag', "userFace"]) 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 { function isImageField(field: string) {
const lowerName = fieldName.toLowerCase(); return /img|face|picture/i.test(field);
return lowerName.includes('img') || lowerName.includes('face') || lowerName.includes('picture');
} }
// ========== 初始化枚举数据和查询表单 ========== // ========== 初始化枚举数据和查询表单 ==========
async function initEnumData() { async function initEnumData() {
try { try {
@ -111,7 +108,6 @@ onMounted(() => {
initEnumData(); initEnumData();
}); });
// ========== 查询表单配置 (初始为空 schema) ========== // ========== 查询表单配置 (初始为空 schema) ==========
const [QueryForm, queryFormApi] = useVbenForm({ const [QueryForm, queryFormApi] = useVbenForm({
schema: [], // 初始化为空数组 schema: [], // 初始化为空数组
@ -134,9 +130,13 @@ watch(
{immediate: false} {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 = { const gridOptions = {
columns: [ columns: [
...columns.map(col => { ...columns.map(col => {
@ -149,126 +149,27 @@ const gridOptions = {
slots: { slots: {
default: ({row}: any) => { default: ({row}: any) => {
const imgUrl = row[col.field]; const imgUrl = row[col.field];
const handleClick = (e: Event) => {
// 如果没有图片,显示提示文字
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(); e.stopPropagation();
// 设置当前行数据
currentRow.value = row; currentRow.value = row;
isEdit.value = true; // 设置为编辑模式 isEdit.value = true;
openUploadDialog(col.field, imgUrl); openUploadDialog(col.field, imgUrl);
}, };
style: { if (!imgUrl) {
padding: '4px 8px', return h('div', { class: 'flex items-center justify-center gap-2 h-[50px]' }, [
fontSize: '12px', h('span', { class: 'text-gray-400 text-xs' }, '无图片'),
color: '#1890ff', h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '上传'),
backgroundColor: '#e6f7ff',
border: '1px solid #1890ff',
borderRadius: '4px',
cursor: 'pointer',
}
}, '上传')
]); ]);
} }
return h('div', { class: 'flex items-center gap-2 justify-center' }, [
// 判断是否是完整的 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, { h(Image, {
src: fullUrl, src: getFullUrl(imgUrl),
height: 60,
width: 80, width: 80,
height: 60,
preview: true, 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', { h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '更换'),
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'
}
}, '渲染失败');
}
} }
} }
}; };
@ -289,14 +190,6 @@ const gridOptions = {
try { try {
// 获取查询表单的值 // 获取查询表单的值
const queryValues = await queryFormApi.getValues(); 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({ const res = await {{entity}}Api.page({
pageNum: page.currentPage || 1, pageNum: page.currentPage || 1,
pageSize: page?.pageSize || 10, pageSize: page?.pageSize || 10,
@ -343,6 +236,7 @@ const [Modal, modalApi] = useVbenModal({
modalApi.close(); modalApi.close();
}, },
onConfirm: async () => { onConfirm: async () => {
let loadingMessage: any = null;
try { try {
const values = await formApi.validateAndSubmitForm(); const values = await formApi.validateAndSubmitForm();
if (!values) return; if (!values) return;
@ -357,22 +251,31 @@ const [Modal, modalApi] = useVbenModal({
...submitValues, ...submitValues,
userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null, userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null,
}; };
// 显示 loading 提示
loadingMessage = message.loading(isEdit.value ? '保存中...' : '新增中...', 0);
if (isEdit.value && currentRow.value?.id) { if (isEdit.value && currentRow.value?.id) {
await {{entity}}Api.save({...finalSubmitValues, id: currentRow.value.id}); await {{entity}}Api.save({...finalSubmitValues, id: currentRow.value.id});
Object.assign(currentRow.value, finalSubmitValues); Object.assign(currentRow.value, finalSubmitValues);
modalApi.close(); modalApi.close();
gridApi.reloadRow(currentRow.value); gridApi.reloadRow(currentRow.value);
loadingMessage();
isEdit.value = false; isEdit.value = false;
message.success('保存成功!');
} else { } else {
await {{entity}}Api.add(finalSubmitValues); await {{entity}}Api.add(finalSubmitValues);
// 新增才 reload(必须) // 新增才 reload(必须)
modalApi.close(); modalApi.close();
gridApi.reload(); gridApi.reload();
formUploadUrls.value = {}; formUploadUrls.value = {};
loadingMessage();
message.success('新增成功!');
} }
} catch (error) { } catch (error) {
console.error('保存失败:', error); console.error('保存失败:', error);
if (loadingMessage) {
loadingMessage();
}
} }
}, },
onOpenChange(isOpen: boolean) { onOpenChange(isOpen: boolean) {
@ -399,6 +302,7 @@ const [UploadModal, uploadModalApi] = useVbenModal({
uploadedUrl.value = ''; uploadedUrl.value = '';
}, },
onConfirm: async () => { onConfirm: async () => {
let loadingMessage: any = null;
console.log('=== 点击确认保存 ===', { console.log('=== 点击确认保存 ===', {
uploadedUrl: uploadedUrl.value, uploadedUrl: uploadedUrl.value,
isEdit: isEdit.value, isEdit: isEdit.value,
@ -427,14 +331,15 @@ const [UploadModal, uploadModalApi] = useVbenModal({
id: currentRow.value.id id: currentRow.value.id
}; };
console.log('📤 提交保存数据:', submitData); console.log('📤 提交保存数据:', submitData);
// 显示 loading 提示
loadingMessage = message.loading('保存图片中...', 0);
await {{entity}}Api.save(submitData); await {{entity}}Api.save(submitData);
message.success('保存成功!'); message.success('保存成功!');
// 关闭弹窗并刷新表格 // 关闭弹窗并刷新表格
uploadModalApi.close(); uploadModalApi.close();
// gridApi.reload(); // gridApi.reload();
loadingMessage()
// 重置状态 // 重置状态
uploadFileList.value = []; uploadFileList.value = [];
uploadedUrl.value = ''; uploadedUrl.value = '';
@ -452,6 +357,9 @@ const [UploadModal, uploadModalApi] = useVbenModal({
} catch (error: any) { } catch (error: any) {
console.error('❌ 保存失败:', error); console.error('❌ 保存失败:', error);
if (loadingMessage) {
loadingMessage();
}
message.error(error?.message || '保存失败'); message.error(error?.message || '保存失败');
} }
} else { } else {
@ -497,13 +405,7 @@ const getEditFormSchema = () => {
console.log('📦 新增表单内上传文件:', file); console.log('📦 新增表单内上传文件:', file);
try { try {
const formData = new FormData(); const resultUrl = await uploadFile(file);
formData.append('file', file);
// 调用上传 API
const res = await {{entity}}Api.upload(formData);
const resultUrl = res.result || res.message || res.url || res;
console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl); console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl);
message.success('上传成功!'); 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) { function openUploadDialog(fieldName: string, currentUrl: string) {
console.log('=== 打开上传对话框 ===', { console.log('=== 打开上传对话框 ===', {
@ -559,7 +474,6 @@ function openUploadDialog(fieldName: string, currentUrl: string) {
uploadImageUrl.value = currentUrl || ''; uploadImageUrl.value = currentUrl || '';
uploadedUrl.value = ''; // 重置上传后的 URL uploadedUrl.value = ''; // 重置上传后的 URL
uploadFileList.value = []; // 清空文件列表 uploadFileList.value = []; // 清空文件列表
uploadVisible.value = true;
uploadModalApi.open(); uploadModalApi.open();
} }
@ -575,17 +489,9 @@ async function handleCustomRequest(options: any) {
size: file.size, size: file.size,
lastModified: file.lastModified, lastModified: file.lastModified,
}); });
const resultUrl = await uploadFile(file);
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;
console.log('✅ 上传成功,URL:', resultUrl); console.log('✅ 上传成功,URL:', resultUrl);
message.success('上传成功!'); message.success('上传成功!');
// 保存上传返回的 URL // 保存上传返回的 URL
uploadedUrl.value = resultUrl; uploadedUrl.value = resultUrl;
console.log('=== uploadedUrl 赋值后 ===', uploadedUrl.value); 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() { function handleAdd() {
isEdit.value = false; isEdit.value = false;
@ -679,7 +571,6 @@ function handleReset() {
queryFormApi.resetForm(); queryFormApi.resetForm();
gridApi.reload(); gridApi.reload();
} }
</script> </script>
@ -728,7 +619,6 @@ function handleReset() {
<Form/> <Form/>
</Modal> </Modal>
<!-- 上传对话框 --> <!-- 上传对话框 -->
<!-- 上传对话框 -->
<UploadModal> <UploadModal>
<div style="padding: 20px;margin-top: 16px; text-align: center;"> <div style="padding: 20px;margin-top: 16px; text-align: center;">
<Upload <Upload
@ -769,7 +659,7 @@ function handleReset() {
<div v-if="uploadImageUrl && !uploadedUrl" style="margin-top: 16px; text-align: center;"> <div v-if="uploadImageUrl && !uploadedUrl" style="margin-top: 16px; text-align: center;">
<p style="color: #999; font-size: 12px; margin-bottom: 8px;">当前图片:</p> <p style="color: #999; font-size: 12px; margin-bottom: 8px;">当前图片:</p>
<Image <Image
:src="uploadImageUrl.startsWith('http') || uploadImageUrl.startsWith('/') ? uploadImageUrl : `${API_BASE_URL}${uploadImageUrl}`" :src="getFullUrl(uploadImageUrl)"
style="max-width: 200px; border-radius: 4px;" style="max-width: 200px; border-radius: 4px;"
:preview="true" :preview="true"
/> />

203
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 currentRow = ref(null);
const isEdit = ref(false); const isEdit = ref(false);
const modalTitle = ref('新增'); const modalTitle = ref('新增');
const uploadVisible = ref(false);
const uploadFieldName = ref(''); const uploadFieldName = ref('');
const uploadImageUrl = ref(''); const uploadImageUrl = ref('');
const uploadedUrl = ref(''); // const uploadedUrl = ref(''); //
@ -36,11 +35,9 @@ const hiddenColumns = ref(['fun_code', 'graduallyIntervalTime', 'funMsgTitle', '
const editFields = ['userId', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy', 'deletedFlag']; const editFields = ['userId', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy', 'deletedFlag'];
// ========== ========== // ========== ==========
function isImageField(fieldName: string): boolean { function isImageField(field: string) {
const lowerName = fieldName.toLowerCase(); return /img|face|picture/i.test(field);
return lowerName.includes('img') || lowerName.includes('face') || lowerName.includes('picture');
} }
// ========== ========== // ========== ==========
async function initEnumData() { async function initEnumData() {
try { try {
@ -111,7 +108,6 @@ onMounted(() => {
initEnumData(); initEnumData();
}); });
// ========== ( schema) ========== // ========== ( schema) ==========
const [QueryForm, queryFormApi] = useVbenForm({ const [QueryForm, queryFormApi] = useVbenForm({
schema: [], // schema: [], //
@ -137,6 +133,11 @@ watch(
// //
const currentPageRef = ref(1); const currentPageRef = ref(1);
// ========== ========== // ========== ==========
function getFullUrl(url: string) {
if (!url) return '';
if (url.startsWith('http')) return url;
return `${API_BASE_URL}${url}`;
}
const gridOptions = { const gridOptions = {
columns: [ columns: [
...columns.map(col => { ...columns.map(col => {
@ -149,126 +150,27 @@ const gridOptions = {
slots: { slots: {
default: ({row}: any) => { default: ({row}: any) => {
const imgUrl = row[col.field]; const imgUrl = row[col.field];
const handleClick = (e: Event) => {
//
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(); e.stopPropagation();
//
currentRow.value = row; currentRow.value = row;
isEdit.value = true; // isEdit.value = true;
openUploadDialog(col.field, imgUrl); openUploadDialog(col.field, imgUrl);
}, };
style: { if (!imgUrl) {
padding: '4px 8px', return h('div', { class: 'flex items-center justify-center gap-2 h-[50px]' }, [
fontSize: '12px', h('span', { class: 'text-gray-400 text-xs' }, '无图片'),
color: '#1890ff', h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '上传'),
backgroundColor: '#e6f7ff',
border: '1px solid #1890ff',
borderRadius: '4px',
cursor: 'pointer',
}
}, '上传')
]); ]);
} }
return h('div', { class: 'flex items-center gap-2 justify-center' }, [
// 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, { h(Image, {
src: fullUrl, src: getFullUrl(imgUrl),
height: 60,
width: 80, width: 80,
height: 60,
preview: true, 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', { h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '更换'),
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'
}
}, '渲染失败');
}
} }
} }
}; };
@ -343,6 +245,7 @@ const [Modal, modalApi] = useVbenModal({
modalApi.close(); modalApi.close();
}, },
onConfirm: async () => { onConfirm: async () => {
let loadingMessage: any = null;
try { try {
const values = await formApi.validateAndSubmitForm(); const values = await formApi.validateAndSubmitForm();
if (!values) return; if (!values) return;
@ -357,22 +260,31 @@ const [Modal, modalApi] = useVbenModal({
...submitValues, ...submitValues,
userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null, userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null,
}; };
// loading
loadingMessage = message.loading(isEdit.value ? '保存中...' : '新增中...', 0);
if (isEdit.value && currentRow.value?.id) { if (isEdit.value && currentRow.value?.id) {
await deviceApi.save({...finalSubmitValues, id: currentRow.value.id}); await deviceApi.save({...finalSubmitValues, id: currentRow.value.id});
Object.assign(currentRow.value, finalSubmitValues); Object.assign(currentRow.value, finalSubmitValues);
modalApi.close(); modalApi.close();
gridApi.reloadRow(currentRow.value); gridApi.reloadRow(currentRow.value);
loadingMessage();
isEdit.value = false; isEdit.value = false;
message.success('保存成功!');
} else { } else {
await deviceApi.add(finalSubmitValues); await deviceApi.add(finalSubmitValues);
// reload // reload
modalApi.close(); modalApi.close();
gridApi.reload(); gridApi.reload();
formUploadUrls.value = {}; formUploadUrls.value = {};
loadingMessage();
message.success('新增成功!');
} }
} catch (error) { } catch (error) {
console.error('保存失败:', error); console.error('保存失败:', error);
if (loadingMessage) {
loadingMessage();
}
} }
}, },
onOpenChange(isOpen: boolean) { onOpenChange(isOpen: boolean) {
@ -399,6 +311,7 @@ const [UploadModal, uploadModalApi] = useVbenModal({
uploadedUrl.value = ''; uploadedUrl.value = '';
}, },
onConfirm: async () => { onConfirm: async () => {
let loadingMessage: any = null;
console.log('=== 点击确认保存 ===', { console.log('=== 点击确认保存 ===', {
uploadedUrl: uploadedUrl.value, uploadedUrl: uploadedUrl.value,
isEdit: isEdit.value, isEdit: isEdit.value,
@ -427,14 +340,15 @@ const [UploadModal, uploadModalApi] = useVbenModal({
id: currentRow.value.id id: currentRow.value.id
}; };
console.log('📤 提交保存数据:', submitData); console.log('📤 提交保存数据:', submitData);
// loading
loadingMessage = message.loading('保存图片中...', 0);
await deviceApi.save(submitData); await deviceApi.save(submitData);
message.success('保存成功!'); message.success('保存成功!');
// //
uploadModalApi.close(); uploadModalApi.close();
// gridApi.reload(); // gridApi.reload();
loadingMessage()
// //
uploadFileList.value = []; uploadFileList.value = [];
uploadedUrl.value = ''; uploadedUrl.value = '';
@ -452,6 +366,9 @@ const [UploadModal, uploadModalApi] = useVbenModal({
} catch (error: any) { } catch (error: any) {
console.error('❌ 保存失败:', error); console.error('❌ 保存失败:', error);
if (loadingMessage) {
loadingMessage();
}
message.error(error?.message || '保存失败'); message.error(error?.message || '保存失败');
} }
} else { } else {
@ -497,13 +414,7 @@ const getEditFormSchema = () => {
console.log('📦 新增表单内上传文件:', file); console.log('📦 新增表单内上传文件:', file);
try { try {
const formData = new FormData(); const resultUrl = await uploadFile(file);
formData.append('file', file);
// API
const res = await deviceApi.upload(formData);
const resultUrl = res.result || res.message || res.url || res;
console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl); console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl);
message.success('上传成功!'); 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) { function openUploadDialog(fieldName: string, currentUrl: string) {
console.log('=== 打开上传对话框 ===', { console.log('=== 打开上传对话框 ===', {
@ -559,7 +483,6 @@ function openUploadDialog(fieldName: string, currentUrl: string) {
uploadImageUrl.value = currentUrl || ''; uploadImageUrl.value = currentUrl || '';
uploadedUrl.value = ''; // URL uploadedUrl.value = ''; // URL
uploadFileList.value = []; // uploadFileList.value = []; //
uploadVisible.value = true;
uploadModalApi.open(); uploadModalApi.open();
} }
@ -575,17 +498,9 @@ async function handleCustomRequest(options: any) {
size: file.size, size: file.size,
lastModified: file.lastModified, lastModified: file.lastModified,
}); });
const resultUrl = await uploadFile(file);
const formData = new FormData();
formData.append('file', file);
// API
const res = await deviceApi.upload(formData);
const resultUrl = res.result || res.message || res.url || res;
console.log('✅ 上传成功,URL:', resultUrl); console.log('✅ 上传成功,URL:', resultUrl);
message.success('上传成功!'); message.success('上传成功!');
// URL // URL
uploadedUrl.value = resultUrl; uploadedUrl.value = resultUrl;
console.log('=== uploadedUrl 赋值后 ===', uploadedUrl.value); 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() { function handleAdd() {
isEdit.value = false; isEdit.value = false;
@ -679,7 +580,6 @@ function handleReset() {
queryFormApi.resetForm(); queryFormApi.resetForm();
gridApi.reload(); gridApi.reload();
} }
</script> </script>
@ -728,7 +628,6 @@ function handleReset() {
<Form/> <Form/>
</Modal> </Modal>
<!-- 上传对话框 --> <!-- 上传对话框 -->
<!-- 上传对话框 -->
<UploadModal> <UploadModal>
<div style="padding: 20px;margin-top: 16px; text-align: center;"> <div style="padding: 20px;margin-top: 16px; text-align: center;">
<Upload <Upload
@ -769,7 +668,7 @@ function handleReset() {
<div v-if="uploadImageUrl && !uploadedUrl" style="margin-top: 16px; text-align: center;"> <div v-if="uploadImageUrl && !uploadedUrl" style="margin-top: 16px; text-align: center;">
<p style="color: #999; font-size: 12px; margin-bottom: 8px;">当前图片:</p> <p style="color: #999; font-size: 12px; margin-bottom: 8px;">当前图片:</p>
<Image <Image
:src="uploadImageUrl.startsWith('http') || uploadImageUrl.startsWith('/') ? uploadImageUrl : `${API_BASE_URL}${uploadImageUrl}`" :src="getFullUrl(uploadImageUrl)"
style="max-width: 200px; border-radius: 4px;" style="max-width: 200px; border-radius: 4px;"
:preview="true" :preview="true"
/> />

214
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 currentRow = ref(null);
const isEdit = ref(false); const isEdit = ref(false);
const modalTitle = ref('新增'); const modalTitle = ref('新增');
const uploadVisible = ref(false);
const uploadFieldName = ref(''); const uploadFieldName = ref('');
const uploadImageUrl = ref(''); const uploadImageUrl = ref('');
const uploadedUrl = ref(''); // const uploadedUrl = ref(''); //
@ -36,11 +35,9 @@ const hiddenColumns = ref(['fun_code', 'graduallyIntervalTime', 'funMsgTitle', '
const editFields = ['userId','createdAt','createdBy','updatedAt','updatedBy','deletedFlag']; const editFields = ['userId','createdAt','createdBy','updatedAt','updatedBy','deletedFlag'];
// ========== ========== // ========== ==========
function isImageField(fieldName: string): boolean { function isImageField(field: string) {
const lowerName = fieldName.toLowerCase(); return /img|face|picture/i.test(field);
return lowerName.includes('img') || lowerName.includes('face') || lowerName.includes('picture');
} }
// ========== ========== // ========== ==========
async function initEnumData() { async function initEnumData() {
try { try {
@ -111,7 +108,6 @@ onMounted(() => {
initEnumData(); initEnumData();
}); });
// ========== ( schema) ========== // ========== ( schema) ==========
const [QueryForm, queryFormApi] = useVbenForm({ const [QueryForm, queryFormApi] = useVbenForm({
schema: [], // schema: [], //
@ -134,9 +130,13 @@ watch(
{immediate: false} {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 = { const gridOptions = {
columns: [ columns: [
...columns.map(col => { ...columns.map(col => {
@ -149,126 +149,27 @@ const gridOptions = {
slots: { slots: {
default: ({row}: any) => { default: ({row}: any) => {
const imgUrl = row[col.field]; const imgUrl = row[col.field];
const handleClick = (e: Event) => {
//
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(); e.stopPropagation();
//
currentRow.value = row; currentRow.value = row;
isEdit.value = true; // isEdit.value = true;
openUploadDialog(col.field, imgUrl); openUploadDialog(col.field, imgUrl);
}, };
style: { if (!imgUrl) {
padding: '4px 8px', return h('div', { class: 'flex items-center justify-center gap-2 h-[50px]' }, [
fontSize: '12px', h('span', { class: 'text-gray-400 text-xs' }, '无图片'),
color: '#1890ff', h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '上传'),
backgroundColor: '#e6f7ff',
border: '1px solid #1890ff',
borderRadius: '4px',
cursor: 'pointer',
}
}, '上传')
]); ]);
} }
return h('div', { class: 'flex items-center gap-2 justify-center' }, [
// 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, { h(Image, {
src: fullUrl, src: getFullUrl(imgUrl),
height: 60,
width: 80, width: 80,
height: 60,
preview: true, 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', { h('button', { onClick: handleClick, class: 'text-blue-500 text-xs' }, '更换'),
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'
}
}, '渲染失败');
}
} }
} }
}; };
@ -289,14 +190,6 @@ const gridOptions = {
try { try {
// //
const queryValues = await queryFormApi.getValues(); const queryValues = await queryFormApi.getValues();
console.log('=== 查询参数 ===', {
pageNum: page?.currentPage || 1,
pageSize: page?.pageSize || 10,
currentPageRef: currentPageRef.value,
...queryValues,
})
const res = await funApi.page({ const res = await funApi.page({
pageNum: page.currentPage || 1, pageNum: page.currentPage || 1,
pageSize: page?.pageSize || 10, pageSize: page?.pageSize || 10,
@ -343,6 +236,7 @@ const [Modal, modalApi] = useVbenModal({
modalApi.close(); modalApi.close();
}, },
onConfirm: async () => { onConfirm: async () => {
let loadingMessage: any = null;
try { try {
const values = await formApi.validateAndSubmitForm(); const values = await formApi.validateAndSubmitForm();
if (!values) return; if (!values) return;
@ -357,22 +251,31 @@ const [Modal, modalApi] = useVbenModal({
...submitValues, ...submitValues,
userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null, userBirthday: submitValues.userBirthday ? dayjs(submitValues.userBirthday).format('YYYY-MM-DD') : null,
}; };
// loading
loadingMessage = message.loading(isEdit.value ? '保存中...' : '新增中...', 0);
if (isEdit.value && currentRow.value?.id) { if (isEdit.value && currentRow.value?.id) {
await funApi.save({...finalSubmitValues, id: currentRow.value.id}); await funApi.save({...finalSubmitValues, id: currentRow.value.id});
Object.assign(currentRow.value, finalSubmitValues); Object.assign(currentRow.value, finalSubmitValues);
modalApi.close(); modalApi.close();
gridApi.reloadRow(currentRow.value); gridApi.reloadRow(currentRow.value);
loadingMessage();
isEdit.value = false; isEdit.value = false;
message.success('保存成功!');
} else { } else {
await funApi.add(finalSubmitValues); await funApi.add(finalSubmitValues);
// reload // reload
modalApi.close(); modalApi.close();
gridApi.reload(); gridApi.reload();
formUploadUrls.value = {}; formUploadUrls.value = {};
loadingMessage();
message.success('新增成功!');
} }
} catch (error) { } catch (error) {
console.error('保存失败:', error); console.error('保存失败:', error);
if (loadingMessage) {
loadingMessage();
}
} }
}, },
onOpenChange(isOpen: boolean) { onOpenChange(isOpen: boolean) {
@ -399,6 +302,7 @@ const [UploadModal, uploadModalApi] = useVbenModal({
uploadedUrl.value = ''; uploadedUrl.value = '';
}, },
onConfirm: async () => { onConfirm: async () => {
let loadingMessage: any = null;
console.log('=== 点击确认保存 ===', { console.log('=== 点击确认保存 ===', {
uploadedUrl: uploadedUrl.value, uploadedUrl: uploadedUrl.value,
isEdit: isEdit.value, isEdit: isEdit.value,
@ -427,14 +331,15 @@ const [UploadModal, uploadModalApi] = useVbenModal({
id: currentRow.value.id id: currentRow.value.id
}; };
console.log('📤 提交保存数据:', submitData); console.log('📤 提交保存数据:', submitData);
// loading
loadingMessage = message.loading('保存图片中...', 0);
await funApi.save(submitData); await funApi.save(submitData);
message.success('保存成功!'); message.success('保存成功!');
// //
uploadModalApi.close(); uploadModalApi.close();
// gridApi.reload(); // gridApi.reload();
loadingMessage()
// //
uploadFileList.value = []; uploadFileList.value = [];
uploadedUrl.value = ''; uploadedUrl.value = '';
@ -452,6 +357,9 @@ const [UploadModal, uploadModalApi] = useVbenModal({
} catch (error: any) { } catch (error: any) {
console.error('❌ 保存失败:', error); console.error('❌ 保存失败:', error);
if (loadingMessage) {
loadingMessage();
}
message.error(error?.message || '保存失败'); message.error(error?.message || '保存失败');
} }
} else { } else {
@ -497,13 +405,7 @@ const getEditFormSchema = () => {
console.log('📦 新增表单内上传文件:', file); console.log('📦 新增表单内上传文件:', file);
try { try {
const formData = new FormData(); const resultUrl = await uploadFile(file);
formData.append('file', file);
// API
const res = await funApi.upload(formData);
const resultUrl = res.result || res.message || res.url || res;
console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl); console.log(item.fieldName + ' 新增表单内上传成功,URL:', resultUrl);
message.success('上传成功!'); 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) { function openUploadDialog(fieldName: string, currentUrl: string) {
console.log('=== 打开上传对话框 ===', { console.log('=== 打开上传对话框 ===', {
@ -559,7 +474,6 @@ function openUploadDialog(fieldName: string, currentUrl: string) {
uploadImageUrl.value = currentUrl || ''; uploadImageUrl.value = currentUrl || '';
uploadedUrl.value = ''; // URL uploadedUrl.value = ''; // URL
uploadFileList.value = []; // uploadFileList.value = []; //
uploadVisible.value = true;
uploadModalApi.open(); uploadModalApi.open();
} }
@ -575,17 +489,9 @@ async function handleCustomRequest(options: any) {
size: file.size, size: file.size,
lastModified: file.lastModified, lastModified: file.lastModified,
}); });
const resultUrl = await uploadFile(file);
const formData = new FormData();
formData.append('file', file);
// API
const res = await funApi.upload(formData);
const resultUrl = res.result || res.message || res.url || res;
console.log('✅ 上传成功,URL:', resultUrl); console.log('✅ 上传成功,URL:', resultUrl);
message.success('上传成功!'); message.success('上传成功!');
// URL // URL
uploadedUrl.value = resultUrl; uploadedUrl.value = resultUrl;
console.log('=== uploadedUrl 赋值后 ===', uploadedUrl.value); 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() { function handleAdd() {
isEdit.value = false; isEdit.value = false;
@ -679,7 +571,6 @@ function handleReset() {
queryFormApi.resetForm(); queryFormApi.resetForm();
gridApi.reload(); gridApi.reload();
} }
</script> </script>
@ -728,7 +619,6 @@ function handleReset() {
<Form/> <Form/>
</Modal> </Modal>
<!-- 上传对话框 --> <!-- 上传对话框 -->
<!-- 上传对话框 -->
<UploadModal> <UploadModal>
<div style="padding: 20px;margin-top: 16px; text-align: center;"> <div style="padding: 20px;margin-top: 16px; text-align: center;">
<Upload <Upload
@ -769,7 +659,7 @@ function handleReset() {
<div v-if="uploadImageUrl && !uploadedUrl" style="margin-top: 16px; text-align: center;"> <div v-if="uploadImageUrl && !uploadedUrl" style="margin-top: 16px; text-align: center;">
<p style="color: #999; font-size: 12px; margin-bottom: 8px;">当前图片:</p> <p style="color: #999; font-size: 12px; margin-bottom: 8px;">当前图片:</p>
<Image <Image
:src="uploadImageUrl.startsWith('http') || uploadImageUrl.startsWith('/') ? uploadImageUrl : `${API_BASE_URL}${uploadImageUrl}`" :src="getFullUrl(uploadImageUrl)"
style="max-width: 200px; border-radius: 4px;" style="max-width: 200px; border-radius: 4px;"
:preview="true" :preview="true"
/> />

Loading…
Cancel
Save