You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Apps Script动态上传Drive报错:TypeError非法值修复示例请求

错误修复方案

错误根源

  1. 前端代码中saveForm函数里的selectedFile变量未定义,导致รูป(图片)属性值为undefined,触发TypeError
  2. 浏览器的File对象无法直接通过google.script.run序列化传递给Google Apps Script,必须先上传文件并获取可存储的标识(如Drive文件链接)

修复后的代码示例

前端JavaScript代码

var inputCount = 0;
function addInputField() {
    const dynamicInputs = document.getElementById('dynamicInputs');
    const rowContainer = document.createElement('div');
    rowContainer.className = 'row g-3';
    const col1 = document.createElement('div');
    col1.className = 'col-sm';
    col1.innerHTML = `<input type="text" class="form-control inp" value="${inputCount + 1}" readonly>`;
    const col2 = document.createElement('div');
    col2.className = 'col-sm-7';
    const inputField1 = document.createElement('input');
    inputField1.type = 'text';
    inputField1.className = 'form-control inp';
    inputField1.placeholder = '任务内容';
    inputField1.setAttribute('aria-label', '任务内容');
    col2.appendChild(inputField1);
    const col3 = document.createElement('div');
    col3.className = 'col-sm';
    const inputField2 = document.createElement('input');
    inputField2.type = 'file';
    inputField2.className = 'form-control inp';
    inputField2.placeholder = '图片';
    inputField2.setAttribute('aria-label', '图片');
    // 给每个文件输入框添加唯一ID,方便后续定位
    inputField2.id = `file-${inputCount}`;
    col3.appendChild(inputField2);
    const col4 = document.createElement('div');
    col4.className = 'col-sm';
    const inputField3 = document.createElement('input');
    inputField3.type = 'text';
    inputField3.className = 'form-control inp';
    inputField3.placeholder = '备注';
    inputField3.setAttribute('aria-label', '备注');
    col4.appendChild(inputField3);
    rowContainer.id = `input${inputCount}`;
    rowContainer.appendChild(col1);
    rowContainer.appendChild(col2);
    rowContainer.appendChild(col3);
    rowContainer.appendChild(col4);
    dynamicInputs.appendChild(rowContainer);
    inputCount++;
    document.getElementById('inputCount').innerText = inputCount;
}

function deleteLastInputField() {
    if (inputCount > 0) {
        inputCount--;
        const dynamicInputs = document.getElementById('dynamicInputs');
        const lastRowContainer = document.getElementById(`input${inputCount}`);
        if (lastRowContainer) {
            lastRowContainer.remove();
        }
        document.getElementById('inputCount').innerText = inputCount;
    }
}

function deleteAllInputFields() {
    const dynamicInputs = document.getElementById('dynamicInputs');
    dynamicInputs.innerHTML = '';
    inputCount = 0;
    document.getElementById('inputCount').innerText = inputCount;
}

// 异步上传单个文件,返回Drive文件链接
function uploadFile(file) {
    return new Promise((resolve, reject) => {
        const formData = new FormData();
        formData.append('fileUpload', file);
        fetch('/exec', {
            method: 'POST',
            body: formData
        })
        .then(response => response.text())
        .then(data => {
            resolve(data.startsWith('https://') ? data : '无上传文件');
        })
        .catch(error => {
            console.error('上传失败:', error);
            resolve('上传失败');
        });
    });
}

async function saveForm() {
    const dynamicInputs = document.getElementById('dynamicInputs');
    const rows = dynamicInputs.getElementsByClassName('row g-3');
    const tasks = [];

    // 遍历每一行,先完成文件上传再收集数据
    for (let i = 0; i < rows.length; i++) {
        const row = rows[i];
        const columns = row.getElementsByTagName('input');
        const fileInput = document.getElementById(`file-${i}`);
        let fileUrl = '无上传文件';
        
        if (fileInput.files.length > 0) {
            fileUrl = await uploadFile(fileInput.files[0]);
        }

        const task = {
            ลำดับ: columns[0].value,
            รายการ: columns[1].value,
            รูป: fileUrl,
            หมายเหตุ: columns[3].value,
        };
        tasks.push(task);
    }

    // 所有文件上传完成后,提交数据到表格
    google.script.run.withSuccessHandler(() => {
        alert('数据保存成功');
        deleteAllInputFields();
    }).saveFormData(tasks);
}

Google Apps Script后端代码

function saveFormData(formData) {
    var sheet = SpreadsheetApp.openById('xxx').getActiveSheet();
    var newData = [];

    for (var i = 0; i < formData.length; i++) {
        var data = formData[i];
        // 处理空值,避免写入表格时出错
        newData.push([
            data['ลำดับ'] || '',
            data['รายการ'] || '',
            data['รูป'] || '',
            data['หมายเหตุ'] || ''
        ]);
    }

    if (newData.length > 0) {
        sheet.getRange(sheet.getLastRow() + 1, 1, newData.length, newData[0].length).setValues(newData);
    }
}

function doPost(e) {
    var destinationId = 'xxx';
    try {
        if (e.parameter.fileUpload) {
            var fileBlob = e.parameters.fileUpload[0];
            var folder = DriveApp.getFolderById(destinationId);
            var file = folder.createFile(fileBlob);
            // 设置文件为公开可查看(可选,根据需求调整权限)
            file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
            // 返回文件的可访问链接
            return ContentService.createTextOutput(file.getUrl()).setMimeType(ContentService.MimeType.TEXT);
        } else {
            return ContentService.createTextOutput('未上传任何文件').setMimeType(ContentService.MimeType.TEXT);
        }
    } catch (error) {
        return ContentService.createTextOutput('上传失败: ' + error.message).setMimeType(ContentService.MimeType.TEXT);
    }
}

关键修复说明

  1. 给每个文件输入框添加唯一ID,确保能准确获取对应行的上传文件
  2. 新增异步文件上传逻辑,通过fetch调用doPost接口,获取文件在Google Drive的可访问链接
  3. 修改saveForm为异步函数,确保所有文件上传完成后再提交数据到表格
  4. 后端doPost调整为返回文件链接,而非单纯的成功提示
  5. 后端saveFormData添加空值处理,避免因字段为空导致的写入错误

内容的提问来源于stack exchange,提问作者What

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:15:11