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

Supabase+PostGraphile环境下GraphQL Mutation无法工作求助

问题:GraphQL Mutation无法执行(查询功能正常)

使用Supabase作为数据库、PostGraphile提供GraphQL服务、Nuxt.js构建UI的项目中,GraphQL查询功能正常,但表单对应的GraphQL Mutation无法运行,已确认拥有数据库完整权限。


模板代码

<template>
  <div>
    <form method="POST" @submit.prevent="createAgreement()">
      <nav class="navbar navbar-dark bg-dark">
        <div class="container-fluid">
          <a class="navbar-brand">
            <input type="reset" class="btn btn-warning" value="Reset"></a>
          <a class="navbar-brand">
            <input type="submit" class="btn btn-warning" value="Save Agreement"></a>
        </div>
      </nav>
      <br>
      <div class="row">
        <div class="col-3">
          <!-- Tab navs -->
          <div id="v-tabs-tab" class="nav flex-column nav-tabs text-center" role="tablist" aria-orientation="vertical">
            <a id="v-tabs-home-tab" class="nav-link active" data-mdb-toggle="tab" href="#v-tabs-home" role="tab"
              aria-controls="v-tabs-home" aria-selected="true">Create A New Agreement</a>
          </div>
          <!-- Tab navs -->
        </div>

        <div class="col-9">
          <div id="v-tabs-tabContent" class="tab-scope">
            <div id="v-tabs-home" class="tab-pane fade show active" role="tabpanel" aria-labelledby="v-tabs-home-tab">
              <div class="table table-responsive">
                <table class="table">
                  <tbody>
                    <tr>
                      <td style="text-align: right;">Agreement Name</td>
                      <td>
                        <input v-model="name" type="text" required />
                      </td>
                    </tr>
                    <tr>
                      <td style="text-align: right;">Agreement Type</td>
                      <td>
                        <input v-model="type" type="text" name="Type" />
                      </td>
                    </tr>
                  </tbody>
                </table>
              </div>
              <br><br>
              <div id="accordionExample" class="accordion">
                <div class="accordion-item">
                  <h2 id="headingOne" class="accordion-header">
                    <button class="accordion-button" type="button" data-mdb-toggle="collapse"
                      data-mdb-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                      Content
                    </button>
                  </h2>
                  <div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne"
                    data-mdb-parent="#accordionExample">
                    <div class="accordion-body">
                      <div class="table table-responsive">
                        <table class="table">
                          <tbody>
                            <tr>
                              <td style="text-align: right;">Excerpt</td>
                              <td>
                                <textarea id="excerpt" v-model="excerpt" type="textarea" cols="50" rows="10"
                                  value="Add a short Description"></textarea>
                              </td>
                            </tr>
                            <tr>
                              <td style="text-align: right;">Description</td>
                              <td>
                                <textarea id="excerpt" v-model="content" type="textarea" cols="50" rows="10"
                                  value="Add a Description"></textarea>
                              </td>
                            </tr>
                          </tbody>
                        </table>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="accordion-item">
                  <h2 id="headingThree" class="accordion-header">
                    <button class="accordion-button" type="button" data-mdb-toggle="collapse"
                      data-mdb-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
                      Images and Videos
                    </button>
                  </h2>
                  <div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree"
                    data-mdb-parent="#accordionExample">
                    <div class="accordion-body">
                      <td>
                        <input v-model="image" type="image" name="headshot" value="Select an image to upload"
                          help="Select a png, jpg or gif to upload." validation="mime:image/jpeg,image/png,image/gif" />
                      </td>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </form>
  </div>
</template>

脚本代码

<script>
import gql from "graphql-tag";
import allAgreementsList from "~/apollo/queries/sales/agreements";

const ADD_AGREEMENTS = gql`
    mutation ($name:String!,$excerpt:String,$type:String,$content:String,$image:String){
    createAgreement(objects: {name: $name, excerpt: $excerpt, type: $type, content: $content, image: $image}) {
        affected_rows
        returning {
            name
            excerpt
            type
            content
            image
    }
  }
}`;

export default {
    data() {
    return {
        type: [],
        name: " ",
        excerpt: " ",
        content: " ",
        image: " ",
        
      }
  },
    head: {
        title: 'Add New Agreement'
    },
  methods: {
      async addAgreement() {
            const name = this.name;
            const content = this.content;
            const excerpt = this.excerpt;
            const type = this.type;
            const image = this.image;
            await this.$apollo.mutate({
                mutation: ADD_AGREEMENTS,
                variables: {
                    name,
                    excerpt,
                    type,
                    content,
                    image,
                },
        update: (cache, { data: { insertAgreements }}) => {
                        // Read data from cache for this query
                        try {
                            const insertedAgreement = insertAgreements.returning;
                            console.log(insertedAgreement)
                            cache.writeQuery({
                                query: allAgreementsList
                            })
                        }
                        catch (err) {
                            console.error(err)
                        }
                    }
                }).then(() => {
                    this.$router.push({path: '../sales/agreements'})
                }).catch(err => console.log(err));
                this.name = ' ';
                this.excerpt = ' ';
                this.type = ' ';
                this.content = ' ';
                this.image = ' ';
            },
            
        }
}
</script>

问题排查与修复方案

1. 方法名称不匹配(核心触发问题)

模板中表单提交绑定的是createAgreement(),但脚本里定义的处理方法是addAgreement,导致提交时无法触发Mutation逻辑。
修复:将模板中的@submit.prevent="createAgreement()"改为@submit.prevent="addAgreement()"

2. 变量类型不匹配

data中type初始值为数组[],但Mutation定义的$type是String类型,提交时会传递错误类型的参数。
修复:将data中的type: []改为type: ""

3. Mutation字段名称不匹配

Mutation中定义的是createAgreement,但update函数里引用的是insertAgreements,字段名不一致会导致缓存更新失败,同时可能暴露实际后端Mutation名称是否正确。
修复:将update函数中的data: { insertAgreements }改为data: { createAgreement },同步字段名。

4. 文件上传标签类型错误

图片上传使用了type="image",该类型是表单提交按钮,不是文件上传控件,无法获取文件内容。
修复:将图片上传标签改为type="file",并添加accept属性限制文件类型:

<input v-model="image" type="file" name="headshot" accept="image/jpeg,image/png,image/gif" />

5. 初始值空格问题

data中各字段初始值为空格" ",可能导致后端非空校验失败(空格可能被视为无效内容)。
修复:将所有字段初始值改为空字符串""

6. 缓存更新逻辑缺失

原代码中cache.writeQuery仅传入query,未更新数据,导致列表缓存无法同步新增内容。
修复:补充缓存更新逻辑:

update: (cache, { data: { createAgreement }}) => {
    try {
        const insertedAgreement = createAgreement.returning;
        // 读取现有缓存数据
        const existingAgreements = cache.readQuery({ query: allAgreementsList });
        // 写入新数据
        cache.writeQuery({
            query: allAgreementsList,
            data: {
                agreements: [...existingAgreements.agreements, ...insertedAgreement]
            }
        })
    } catch (err) {
        console.error(err)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 14:45:41