零基础手把手教你如何使用Laf免费玩转Midjourney

这篇具有很好参考价值的文章主要介绍了零基础手把手教你如何使用Laf免费玩转Midjourney。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是Laf?

Laf 是一个 Serverless 框架,提供开箱即用的云函数,云数据库,对象存储等能力,是一个非常干净清爽的开发平台,不仅入门简单,还能像写博客一样写代码!最重要的是,敲重点,三分钟即可上线 ChatGPT 应用

若想深入了解可点击 介绍 | laf 云开发https://doc.laf.run/guide/

二、入门Laf开发应用前的准备

在正式开发应用前需要先进行账号注册和新建应用,具体操作方法可访问Web IDE | laf 云开发https://doc.laf.run/guide/web-ide/

说明:下面讲解的Midjourney需要访问 laf.dev 域名进行注册

三、正式接入Midjourney

在应用列表点击「开发」按钮即可进入 Laf 应用开发 IDE

直接Web IDE在线开发,连安装软件的工作都省了,不得不说,十分亲民

零基础手把手教你如何使用Laf免费玩转Midjourney

零基础手把手教你如何使用Laf免费玩转Midjourney

 1.添加NPM依赖

点击左下角【NPM依赖】处的“+”按钮,在弹框中搜索“midjourney”,选中第一个后再点击“保存并重启”,等待3秒左右依赖会添加完成

零基础手把手教你如何使用Laf免费玩转Midjourney

 2.添加函数

点击左上角【函数列表】处的“+”按钮,在弹框中输入函数名(比如:mj-func),其他默认,完成后点击“确认”按钮,等待3秒左右函数会添加完成

零基础手把手教你如何使用Laf免费玩转Midjourney

说明:关于云函数的入门,可点击下面链接了解详情云函数入门 | laf 云开发https://doc.laf.run/guide/function/

3.初始化Midjourney

上面已经添加了midjourney的依赖,接着需要在刚刚添加的函数中引入midjourney,并进行初始化

import { Midjourney, MidjourneyMessage } from 'midjourney'
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Token

const Limit = 100
const MaxWait = 3

//初始化
const client = new Midjourney({
  ServerId: SERVER_ID,
  ChannelId: CHANNEL_ID,
  SalaiToken: SALAI_TOKEN,
  Debug: true,
  SessionId: SALAI_TOKEN,
  Limit: Limit,
  MaxWait: MaxWait
});

其中服务ID、频道ID和服务Token可在 人人都能接入 Midjourney,赚取自己的第一桶金 中找大佬单独获取

4.生成图片

“export default async function”可以理解成函数的主入口,在其方法内我们可以根据传入的参数去实现不同的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  //参数校验
  if (!type) {
    return resultData(0, '参数type不能为空!')
  }

  switch (type) {
    case 'imagine':
      //生成图片
      return await imagine(param)
  }
}

下面为【生成图片】的具体实现,需要question和msg_Id两个参数

question:其实就是prompt(提示),需要输入英文

msg_Id:可以理解成会话ID

// 创建生图任务
async function imagine(param) {
  console.log("imagine", param)
  const { question, msg_Id } = param
  //参数校验
  if (!question || !msg_Id) {
    return resultData(0, '参数question或msg_Id不能为空!')
  }

  try {
    const obj = await client.Imagine(
      `[${msg_Id}] ${question}`,
      (uri: string, progress: string) => {
        console.log("loading", uri, "progress", progress);
      }
    );
    console.log("imagine success ", obj)
    return resultData(200, 'imagine success', obj)
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

 为了让前端在调用接口时接收到的数据风格统一化,故这里在返回数据时进行了统一的封装处理

//返回结果数据
async function resultData(code = 0, msg = '', data = null) {
  return { code, msg, data }
}

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{
    "type": "imagine",
    "param": {
        "question": "a beautiful girl",
        "msg_Id": "20230523_G001"
    }
}

零基础手把手教你如何使用Laf免费玩转Midjourney

说明:在返回的结果数据中code为200时表示请求成功,data为null不用理会,请求成功后大约等待30秒到一分钟左右的时间, Midjourney会自动在后台生成我们想要的图片,届时我们再调用【查询最近消息】的接口获取生成的图片。

另外,除了通过apipost或postman调用接口,我们还可以使用Web IDE自带的接口调试进行调用,不仅可以清晰的看到运行的结果,还能在控制台打印出我们想要的日志信息,十分的便利,如下图:

零基础手把手教你如何使用Laf免费玩转Midjourney

5.查询最近消息

在主入口方法中增加【查询最近消息】的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  //参数校验
  if (!type) {
    return resultData(0, '参数type不能为空!')
  }

  switch (type) {
    case 'retrieveMessages':
      //查询最近消息
      return await retrieveMessages(param)
    case 'imagine':
      //生成图片
      return await imagine(param)
  }
}

下面为【查询最近消息】的具体实现,由于默认查询的是所有用户最近50条的消息,所以这里根据msg_Id进行了数据筛选(若想查询所有的可以去掉这个限制)

msg_Id:会话ID(需与生成图片时传的msg_Id一致)

// 查询消息(最近50条)
async function retrieveMessages(param) {
  console.log("retrieveMessages", param)
  const { msg_Id } = param
  //参数校验
  if (!msg_Id) {
    return resultData(0, '参数msg_Id不能为空!')
  }

  try {
    const client = new MidjourneyMessage({
      ChannelId: CHANNEL_ID,
      SalaiToken: SALAI_TOKEN,
    });
    const obj = await client.RetrieveMessages();
    console.log("retrieveMessages success ", obj)
    //解析返回的list数据,获取图片信息
    if (obj) {
      //查找满足当前会话的消息
      let info = obj.find(x => x.content.indexOf(msg_Id) > -1);
      //校验是否完成了图片的生成,条件:attachments节点下的第一个子对象,且width大于512
      if (info && info.attachments && info.attachments.length > 0 && info.attachments[0].width > 512) {
        let d = info.attachments[0];

        //调用云函数获取网络图片并存储
        const res = await cloud.invoke('store-func', {
          body: {
            type: 'fetchImg',
            param: {
              fileName: d.filename,
              fileUrl: d.url,
              contentType: d.content_type
            }
          }
        });
        if (res.code == 200) {
          d.pic = res.data
          res.data = d
        }
        return res;
      }
    }
    return resultData(0, '未获取到数据!')
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

其中,这里“调用云函数获取网络图片并存储”是写在另一个云函数中,所以需要另外再创建一个云函数“store-func”,具体实现如下:

import cloud from "@lafjs/cloud";
import { GetObjectCommand, S3 } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

//初始化
const s3Client = new S3({
  endpoint: process.env.OSS_EXTERNAL_ENDPOINT,
  region: process.env.OSS_REGION,
  credentials: {
    accessKeyId: process.env.OSS_ACCESS_KEY,
    secretAccessKey: process.env.OSS_ACCESS_SECRET
  },
  forcePathStyle: true,
})
//存储空间名称,不带 Laf 应用 appid
const bucketName = 'store-file'

//主入口
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  //参数校验
  if (!type) {
    return resultData(0, '参数type不能为空!')
  }

  switch (type) {
    case 'fetchImg':
      //存储网络图片
      return await fetchImgToStore(param)
  }
}

//获取网络图片并存储
async function fetchImgToStore(param) {
  console.log("fetchImgToStore", param);
  const { fileName, fileUrl, contentType } = param
  //参数校验
  if (!fileName || !fileUrl || !contentType) {
    return resultData(0, '参数fileName、fileUrl或contentType不能为空!')
  }

  try {
    //下载url图片二进制数据
    const ret = await cloud.fetch({
      url: fileUrl,
      method: "get",
      responseType: "arraybuffer"
    });
    // console.log(ret.data);
    if (ret.data) {
      //图片存储
      const res = await uploadAppFile(fileName, ret.data, contentType);
      console.log('文件存储结果:', res)
      if (res && res.$metadata && res.$metadata.httpStatusCode == 200) {
        //获取图片存储的绝对路径
        const fileUrl = await getAppFileUrl(fileName);
        return resultData(200, '成功', fileUrl)
      }
      return resultData(0, '文件存储失败!')
    }
    return resultData(0, '获取网络图片失败!')
  }
  catch (e) {
    return resultData(0, '出现异常!', e)
  }
}

//拼接文件桶名字
function getInternalBucketName() {
  const appid = process.env.APP_ID;
  return `${appid}-${bucketName}`;
}

//上传文件
async function uploadAppFile(key, body, contentType) {
  const bucket = getInternalBucketName();
  const res = await s3Client
    .putObject({
      Bucket: bucket,
      Key: key,
      ContentType: contentType,
      Body: body,
    })
  return res;
}

//获取文件 url
async function getAppFileUrl(key) {
  const bucket = getInternalBucketName();
  const res = await getSignedUrl(s3Client, new GetObjectCommand({
    Bucket: bucket,
    Key: key,
  }));
  return res;
}

//返回结果数据
async function resultData(code = 0, msg = '', data = null) {
  return { code, msg, data }
}

这里涉及到了云函数的调用,以及云存储,详细资料可在下面链接中进行查阅云存储简介 | laf 云开发https://doc.laf.run/guide/oss/

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{
    "type": "retrieveMessages",
    "param": {
        "msg_Id": "20230523_G001"
    }
}

零基础手把手教你如何使用Laf免费玩转Midjourney

 返回的data中pic的链接即为生成的图片

零基础手把手教你如何使用Laf免费玩转Midjourney

零基础手把手教你如何使用Laf免费玩转Midjourney 零基础手把手教你如何使用Laf免费玩转Midjourney

 6.放大图片

在主入口方法中增加【放大图片】的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  //参数校验
  if (!type) {
    return resultData(0, '参数type不能为空!')
  }

  switch (type) {
    case 'retrieveMessages':
      //查询最近消息
      return await retrieveMessages(param)
    case 'imagine':
      //生成图片
      return await imagine(param)
    case 'upscale':
      //放大图片
      return await upscale(param)
  }
}

下面为【放大图片】的具体实现,需要question、index、id和url四个参数

question:与生成图片时的参数,需要输入英文

index:你想要的第几张图(默认生成的4张图,按1234的顺序)

id:查询最近消息接口返回的数据体中的id

url:查询最近消息接口返回的数据体中attachments节点下的url

// upscale 放大图片
async function upscale(param) {
  console.log("upscale", param)
  const { question, index, id, url } = param
  //参数校验
  if (!question || !index || !id || !url) {
    return resultData(0, '参数question、index、id或url不能为空!')
  }

  try {
    const hash = url.split("_").pop()?.split(".")[0] ?? ""
    const obj = await client.Upscale(
      question,
      index,
      id,
      hash,
      (uri: string, progress: string) => {
        console.log("loading", uri, "progress", progress);
      }
    );
    console.log("upscale success ", obj)
    return resultData(200, 'upscale success', obj)
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{
    "type": "upscale",
    "param": {
        "question": "a beautiful girl",
        "index": 2,
        "id": "1110429562023723048",
        "url": "https://cdn.discordapp.com/attachments/1110206663958466611/1110429561428135976/johnsonmaureen_20230523_G001_a_beautiful_girl_1925266c-7937-4b8d-8150-c16f013d0dca.png"
    }
}

零基础手把手教你如何使用Laf免费玩转Midjourney

成功后,大约等待30秒到一分钟,重新再调用一下【查询最近消息】的接口,获取可访问的放大后的图片

零基础手把手教你如何使用Laf免费玩转Midjourney

零基础手把手教你如何使用Laf免费玩转Midjourney

或者,也可以在【放大图片】的接口中将新生成的图片进行云存储后再返回给前端,两种方式都可以

7.变换图片

在主入口方法中增加【变换图片】的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  //参数校验
  if (!type) {
    return resultData(0, '参数type不能为空!')
  }

  switch (type) {
    case 'retrieveMessages':
      //查询最近消息
      return await retrieveMessages(param)
    case 'imagine':
      //生成图片
      return await imagine(param)
    case 'upscale':
      //放大图片
      return await upscale(param)
    case 'variation':
      //变换图片
      return await variation(param)
  }
}

下面为【变换图片】的具体实现,需要question、index、id和url四个参数

question:与生成图片时的参数,需要输入英文

index:你想要的第几张图(默认生成的4张图,按1234的顺序)

id:查询最近消息接口返回的数据体中的id

url:查询最近消息接口返回的数据体中attachments节点下的url

// variation 变换图片
async function variation(param) {
  console.log("variation", param)
  const { question, index, id, url } = param
  //参数校验
  if (!question || !index || !id || !url) {
    return resultData(0, '参数question、index、id或url不能为空!')
  }

  try {
    const hash = url.split("_").pop()?.split(".")[0] ?? ""
    const obj = await client.Variation(
      question,
      index,
      id,
      hash,
      (uri: string, progress: string) => {
        console.log("loading", uri, "progress", progress);
      }
    );
    console.log("variation success ", obj)
    return resultData(200, 'variation success', obj)
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{
    "type": "variation",
    "param": {
        "question": "a beautiful girl",
        "index": 3,
        "id": "1110429562023723048",
        "url": "https://cdn.discordapp.com/attachments/1110206663958466611/1110429561428135976/johnsonmaureen_20230523_G001_a_beautiful_girl_1925266c-7937-4b8d-8150-c16f013d0dca.png"
    }
}

零基础手把手教你如何使用Laf免费玩转Midjourney

 说明:在返回的结果数据中code为200时表示请求成功,data为null不用理会,请求成功后大约等待30秒到一分钟左右的时间, Midjourney会自动在后台重新生成我们想要的图片,届时我们再调用【查询最近消息】的接口获取变换后的图片。

零基础手把手教你如何使用Laf免费玩转Midjourney

零基础手把手教你如何使用Laf免费玩转Midjourney

8.关于云存储

如使用云存储,需在云存储中新建Bucket,如下图:

零基础手把手教你如何使用Laf免费玩转Midjourney

下面为云函数mj-func的完整代码:

import cloud from '@lafjs/cloud'
import { Midjourney, MidjourneyMessage } from 'midjourney'
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Token

const Limit = 100
const MaxWait = 3

//初始化
const client = new Midjourney({
  ServerId: SERVER_ID,
  ChannelId: CHANNEL_ID,
  SalaiToken: SALAI_TOKEN,
  Debug: true,
  SessionId: SALAI_TOKEN,
  Limit: Limit,
  MaxWait: MaxWait
});

//主入口
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  //参数校验
  if (!type) {
    return resultData(0, '参数type不能为空!')
  }

  switch (type) {
    case 'retrieveMessages':
      //查询最近消息
      return await retrieveMessages(param)
    case 'imagine':
      //生成图片
      return await imagine(param)
    case 'upscale':
      //放大图片
      return await upscale(param)
    case 'variation':
      //变换图片
      return await variation(param)
  }
}

// 查询消息(最近50条)
async function retrieveMessages(param) {
  console.log("retrieveMessages", param)
  const { msg_Id } = param
  //参数校验
  if (!msg_Id) {
    return resultData(0, '参数msg_Id不能为空!')
  }

  try {
    const client = new MidjourneyMessage({
      ChannelId: CHANNEL_ID,
      SalaiToken: SALAI_TOKEN,
    });
    const obj = await client.RetrieveMessages();
    console.log("retrieveMessages success ", obj)
    //解析返回的list数据,获取图片信息
    if (obj) {
      //查找满足当前会话的消息
      let info = obj.find(x => x.content.indexOf(msg_Id) > -1);
      //校验是否完成了图片的生成,条件:attachments节点下的第一个子对象,且width大于512
      if (info && info.attachments && info.attachments.length > 0 && info.attachments[0].width > 512) {
        let d = info.attachments[0];

        //调用云函数获取网络图片并存储
        const res = await cloud.invoke('store-func', {
          body: {
            type: 'fetchImg',
            param: {
              fileName: d.filename,
              fileUrl: d.url,
              contentType: d.content_type
            }
          }
        });
        if (res.code == 200) {
          info.pic = res.data
          res.data = info
        }
        return res;
      }
    }
    return resultData(0, '未获取到数据!')
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

// 创建生图任务
async function imagine(param) {
  console.log("imagine", param)
  const { question, msg_Id } = param
  //参数校验
  if (!question || !msg_Id) {
    return resultData(0, '参数question或msg_Id不能为空!')
  }

  try {
    const obj = await client.Imagine(
      `[${msg_Id}] ${question}`,
      (uri: string, progress: string) => {
        console.log("loading", uri, "progress", progress);
      }
    );
    console.log("imagine success ", obj)
    return resultData(200, 'imagine success', obj)
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

// upscale 放大图片
async function upscale(param) {
  console.log("upscale", param)
  const { question, index, id, url } = param
  //参数校验
  if (!question || !index || !id || !url) {
    return resultData(0, '参数question、index、id或url不能为空!')
  }

  try {
    const hash = url.split("_").pop()?.split(".")[0] ?? ""
    const obj = await client.Upscale(
      question,
      index,
      id,
      hash,
      (uri: string, progress: string) => {
        console.log("loading", uri, "progress", progress);
      }
    );
    console.log("upscale success ", obj)
    return resultData(200, 'upscale success', obj)
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

// variation 变换图片
async function variation(param) {
  console.log("variation", param)
  const { question, index, id, url } = param
  //参数校验
  if (!question || !index || !id || !url) {
    return resultData(0, '参数question、index、id或url不能为空!')
  }

  try {
    const hash = url.split("_").pop()?.split(".")[0] ?? ""
    const obj = await client.Variation(
      question,
      index,
      id,
      hash,
      (uri: string, progress: string) => {
        console.log("loading", uri, "progress", progress);
      }
    );
    console.log("variation success ", obj)
    return resultData(200, 'variation success', obj)
  }
  catch (e) {
    return resultData(0, '参数错误!', e)
  }
}

//返回结果数据
async function resultData(code = 0, msg = '', data = null) {
  return { code, msg, data }
}

 以上即为使用Laf接入Midjourney的完整演示,如有疑问,欢迎提出!文章来源地址https://www.toymoban.com/news/detail-484375.html

到了这里,关于零基础手把手教你如何使用Laf免费玩转Midjourney的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 手把手教你如何免费Midjourney Adobe FireFly AI绘图—Window本地快速部署stable diffusion AI绘图及使用指南(小白也能学会)

    最近看到朋友圈最近各种文字生图、图生图,眼花缭乱的图片AI生成,我也心动了,于是赶紧研究了下目前业内认为最强大的 Midjourney、Adobe FireFly ,本来想试用下,奈何全球人民太热情了, Midjourney 被薅羊毛薅的不行了,原本 Midjourney 刚注册可以免费玩25次,现在也被Midjour

    2024年02月04日
    浏览(51)
  • 手把手教你如何使用Docker

    我们在公司开发中,会有开发环境,测试环境,上线环境, 比如我们开发人员开发好了一个项目,在开发环境中运行正常,但测试人员拉到测试环境就跑不起来【jdk版本等】,或者上线的时候运行不起来,这时候就要为每个机器配置一个环境,那运维人员不得累死?【哈哈,

    2024年02月10日
    浏览(52)
  • 手把手教你如何使用SimiliarWeb

    在之前的“手把手教你如何使用Google Trends”文章中我们讲到从事跨境电商的卖家第一步遇到的问题是“客户在哪里?”该如何推广我的产品?因此若想自己的店铺做大做好,则需要工具来帮助分析市场行情,根据市场行情调整自己的业务状况。小编在上篇中已经讲解了三个特

    2024年02月09日
    浏览(46)
  • 【Java技术专题】「Guava开发指南」手把手教你如何进行使用Guava工具箱进行开发系统实战指南(基础编程篇)

    Preconditions(前置条件):让方法调用的前置条件判断更简单 。 Guava在Preconditions 类中提供了若干前置条件判断的实用方法,我们强烈建议在 Eclipse 中静态导入这些方法。每个方法都有三个变种: 当方法没有额外参数时,抛出的异常中不包含错误消息,这会使得调用方很难确

    2024年02月07日
    浏览(53)
  • 手把手教你如何使用Fiddler抓包工具

    什么是 Fiddler? Fiddler 是一个 HTTP 协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的 HTTP 通讯。Fiddler 提供了电脑端、移动端的抓包、包括 http 协议和 https 协议都可以捕获到报文并进行分析;可以设置断点调试、截取报文进行请求替换和数据篡改,也可以进行

    2024年02月07日
    浏览(43)
  • 【零基础】手把手教你使用Docker部署Springboot项目(详细版)

    ​  本篇文章适合刚学完Docker,想要部署Springboot项目的小白;当然,如果你还没有学习Docker,只要严格按照本篇文章的步骤执行,理论上也是可以完成部署的。   我接下来部署的项目都是以一台全新Liunx服务器视角来操作,该服务器上jdk,mysql和Docker都还没有安装。 ​

    2024年01月20日
    浏览(47)
  • 手把手教你如何正确永久使用Microsoft Office365?

    office2019和office 365有什么区别的呢?为什么越来越多的人更加钟爱office365。简单来说office 2019的零售版本属于一次售出永久使用,价格上比较贵,而且功能上也不会再有更新。而office 365是一种基于云的订阅服务,我们花钱买的是一定时期的服务,在使用期间我们可以获得offi

    2024年02月07日
    浏览(42)
  • 手把手教你如何使用Unity搭建简易图片服务器

    目录 引言 服务器 WAMP简介 WAMP的配置与使用 主要的WAMP集成环境有: 正文 1、外部工具素材准备 首先下载并安装 WAMP  图片路径设置 2、创建 Unity 工程 将图片加载到 Unity 项目中: 代码块 运行效果如下: 网络游戏中,服务器的搭建尤为重要,无论是授权服务器,还是非授权服务

    2024年02月02日
    浏览(43)
  • 新人必看!手把手教你如何使用浏览器表格插件(下)

    本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 作为一名优秀的打工人,Excel是大家上班中必不可少的办公软件。随着互联网时代的到来,越来越多的公司开始使用各种B/S系统

    2024年02月06日
    浏览(49)
  • 新人必看!手把手教你如何使用浏览器表格插件(上)

    本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 作为一名优秀的打工人,Excel是大家上班中必不可少的办公软件。随着互联网时代的到来,越来越多的公司开始使用各种B/S系统

    2024年02月06日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包