| 名词 | 是什么 | 谁来维护 |
|---|---|---|
| 客户端 | 用户装的 PC 软件(Windows)。里面能开店铺页,也能装「应用」(插件),应用跑在客户端里。 | 平台 |
| 应用市场 | 开发者把自己写的插件上架,用户在客户端的应用市场里安装、订阅、付费。 | 平台 + 开发者 |
| 开发包 | 你写插件要用的一整套东西:云捷SDK.js(唯一能力入口)+ 开发文档/skill + 模板 + 组件 + UI 资源。一个 zip、一个版本号。 |
平台下发(你只管用) |
.trae/skills/,用 Trae 打开开发包目录后,AI 会**自动按云捷的规范**帮你写插件、
查接口、避坑,比手写快很多。用 VS Code 也能开发(只是没有这套 skill 加持)。Trae CN-Setup-x64.exeD:\Trae),不要中文/空格trae 打开项目)GET /api/docs/kit.zip),拿到 kit.zip。D:\我的插件。解压后的结构(用 Trae 打开这个目录即可):
D:\开发包\ ← 开发包目录
├── 云捷SDK.js ← 唯一能力入口,别手写、别改名
├── SDK更新日志.md ← 每个版本改了什么
├── 资源\ ← vue.min.js + element-ui(本地文件,不要改用 CDN)
├── 模板\ ← 六个现成骨架(最小插件 / 列表操作插件 / 批量任务插件 / 定时器示例 / 首页面板示例 / 搜索商品示例)
├── 组件\ ← 可复用组件(如 SKU搜索.js)
├── .trae\skills\ ← 给 Trae 的云捷插件开发 skill(用 Trae 打开本目录即生效)
└── 参考\ ← 分模块文档(SDK 速查 / 营销 / 商品 / 售后 / 避坑…)
模板\最小插件\(或 列表操作插件 / 批量任务插件)
整个目录复制出去当你的插件目录,再改成你要的功能 —— 模板里已经带了 云捷SDK.js 和 资源\。发布\ 里,可直接参考这一结构。
D:\我的插件)。.trae/skills/yunjie-plugin-dev(云捷插件开发技能)。参考/02-SDK-营销.md)参考\ 目录:
00-快速开始、01-SDK速查、02-营销、03-商品、04-商机、
05-售后、06-订单评价、07-数据存储、08-宿主能力、09-避坑、
10-接口清单、11-平台能力与组件库。
F12 / Ctrl+Shift+I 也都被拦掉(平台防止用户看到插件内部结构)。
所以要调样式、看报错、查网络请求,都在「本地调试」里做。
index.html(入口,界面) + app.js(业务代码)。
推荐用「发布」目录:只有它里面的内容会被打包上传;不用也没关系(老插件照旧整目录打包)。我的插件\ ← 客户端里选这个当「源码目录」(选**上层这一层**)
├── 发布\ ← 【会上传】要上线运行的文件都放这里
│ ├── 云捷SDK.js ← 包自带,不要动
│ ├── 资源\ ← 包自带(Vue2 + Element UI 本地文件)
│ ├── index.html ← 入口(你写)
│ └── app.js ← 业务代码(你写,ES Module)
├── 笔记.md ← 【不上传】随便放
└── 设计稿.psd ← 【不上传】
发布\ 里的代码 → 调试的 = 上传的。发布\ 也不会报错:客户端按老规矩打包整个源码目录 ——
以前开发的插件照旧能打包上传,不受影响。发布\ 时,「更新开发包」会把 云捷SDK.js 与 资源\ 顺带同步进 发布\。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>我的插件</title>
<!-- UI 资源用本地的,不要改成 CDN -->
<link rel="stylesheet" href="./资源/element-ui/index.css">
</head>
<body>
<div id="app" v-cloak>
<div class="page-header">
<span>我的插件</span>
<el-button size="mini" @click="搜索()">搜索</el-button>
</div>
</div>
<!-- 依赖:先 Vue,再 ElementUI -->
<script src="./资源/vue.min.js"></script>
<script src="./资源/element-ui/index.js"></script>
<!-- ⚠️ 业务代码必须是 ES Module(这样才 import 得动 云捷SDK.js) -->
<script type="module" src="./app.js"></script>
</body>
</html>
// 只从 SDK 拿能力(不要写 const 云捷 = window.云捷,会白屏)
import 云捷 from './云捷SDK.js'
new Vue({
el: '#app',
data() {
return { 店铺列表: [], 当前标签ID: '', 状态: '' }
},
async mounted() {
this.店铺列表 = await 云捷.店铺列表() // 只拿到"本应用可用"的店铺
this.当前标签ID = this.店铺列表[0] ? this.店铺列表[0].标签ID : ''
},
methods: {
/** 搜索商品(每个接口都要 try/catch,失败原因给用户看) */
async 搜索() {
try {
const 结果 = await 云捷.商品.列表(this.当前标签ID, { 标签: 'onSale', 每页: 20 })
if (结果.code !== 0) return this.$message.error('读取失败:' + (结果.msg || '未知原因'))
this.状态 = '共 ' + (结果.data?.products?.length || 0) + ' 条'
} catch (错误) {
this.$message.error('读取失败:' + (错误 && 错误.message ? 错误.message : 错误))
}
}
}
})
import 云捷 from './云捷SDK.js'
/** 每批最多 20 个(抖店接口限制) */
const 每批上限 = 20
new Vue({
el: '#app',
data() {
return {
店铺列表: [], // 有权限的店铺
当前标签ID: '', // 当前店铺的标签ID(调接口都用它)
商品列表: [], // 表格数据
页码: 0, 每页: 20, 总数: 0,
选中商品: [],
执行中: false, // 长任务时给按钮加 loading
结果清单: [] // 成功/失败清单(必须给用户看)
}
},
async mounted() { await this.初始化() },
methods: {
/** 初始化:取店铺列表并选中第一家 */
async 初始化() {
try {
this.店铺列表 = await 云捷.店铺列表()
if (!this.店铺列表.length) return this.$message.warning('这个应用还没有可用店铺,请先在客户端里授权')
this.当前标签ID = this.店铺列表[0].标签ID
await this.搜索()
} catch (错误) {
this.$message.error('初始化失败:' + (错误 && 错误.message ? 错误.message : 错误))
}
},
/** 搜商品(分页从 0 开始) */
async 搜索() {
try {
const 结果 = await 云捷.商品.列表(this.当前标签ID, { 页码: this.页码, 每页: this.每页, 标签: 'onSale' })
if (结果.code !== 0) return this.$message.error('搜索失败:' + (结果.msg || '未知原因'))
this.商品列表 = 结果.data?.products || []
} catch (错误) {
this.$message.error('搜索失败:' + (错误 && 错误.message ? 错误.message : 错误))
}
},
/** 批量下架:先确认 → 分批(≤20)→ 汇总成败 */
async 批量下架() {
if (!this.选中商品.length) return this.$message.warning('先勾选商品')
if (!window.confirm('下架 ' + this.选中商品.length + ' 个商品,确定吗?')) return
this.执行中 = true
this.结果清单 = []
for (let i = 0; i < this.选中商品.length; i += 每批上限) {
const 本批 = this.选中商品.slice(i, i + 每批上限)
try {
const 结果 = await 云捷.商品.批量上下架(this.当前标签ID, {
商品ID列表: 本批.map((项) => 项.product_id), 上架: false
})
// 按接口返回的成败逐条记进"结果清单"
本批.forEach((项) => this.结果清单.push({ 商品ID: 项.product_id, 结果: 结果.code === 0 ? '成功' : '失败', 原因: 结果.msg || '' }))
} catch (错误) {
本批.forEach((项) => this.结果清单.push({ 商品ID: 项.product_id, 结果: '失败', 原因: String(错误 && 错误.message ? 错误.message : 错误) }))
}
}
this.执行中 = false
const 失败数 = this.结果清单.filter((项) => 项.结果 !== '成功').length
this.$message[失败数 ? 'warning' : 'success']('完成:成功 ' + (this.结果清单.length - 失败数) + ',失败 ' + 失败数)
}
}
})
1300 = 13 元);写接口要带店铺令牌 { 令牌: await 云捷.取店铺令牌(店铺ID) }。
具体接口签名见包内 参考/01-SDK速查.md。
参考\ 对应文件。| 要做什么 | 怎么调(都在 云捷 上) | 看哪个文档 |
|---|---|---|
| 拿店铺列表 / 令牌 | 云捷.店铺列表()、云捷.取店铺令牌(店铺ID) | 01-SDK速查 |
| 通用请求 | 云捷.请求(标签ID, 路径, { 方法, 查询, 体, 内容类型, 不补来源参数 }) | 01-SDK速查 |
| 营销(直降/满减/优惠券/新人券) | 云捷.营销.* / 云捷.优惠券.* | 02-SDK-营销 |
| 商品(列表/详情/SKU/主图/上下架/运费模板) | 云捷.商品.* | 03-SDK-商品 |
| 商机(搜索 → 可报商品 → 报名) | 云捷.商机中心.* | 04-SDK-商机 |
| 售后(导出/详情/物流/退货策略) | 云捷.售后.* | 05-SDK-售后 |
| 订单 / 评价 | 云捷.订单.* / 云捷.评价.* | 06-SDK-订单评价 |
| 临时数据 / 正式数据 | 云捷.缓存(会被清)、云捷.数据库(一个应用一个独立库) | 07-数据存储 |
| 文件读写 / 下载图片 / 导出 | 云捷.文件.*、云捷.应用文件.* | 08-宿主能力 |
| 定时任务(无人值守) | 云捷.定时.注册(...) | 08-宿主能力 |
| 往应用页面右键菜单里加自己的项 | 云捷.菜单.设置([{ 名称, 点击 }]) / 清除() | 08-宿主能力 9 |
| 把一个页面做成常驻整页(与「云捷科技」并列,侧边栏「功能」点开;登记即常驻,跟随客户端启动) | 云捷.首页.注册面板({ 名称, 入口, 说明, 权限 }) / 状态() / 设置角标(n) / 取消() | 08-宿主能力 10 |
| 应用内收费:知道"现在是谁在用"(判断这个账号买过没有) | 云捷.身份.票据() → 你的服务端调 POST /api/app/identity/verify 验签换出 归属账号ID / 店铺ID | 08-宿主能力 11 |
| 浏览器自动化(抓页面接口 / 自动操作) | 云捷.浏览器.* | 08-宿主能力 |
| 调站外接口 / 算抖音签名 | 云捷.网络.请求(...)、云捷.签名.aBogus(...) | 08-宿主能力 |
| AI(对话 / 出图) | 云捷.AI.* | 08-宿主能力 |
可复用组件(唯一组件:SKU 编码搜索 <sku-search>) | 包内 组件\ 目录,复制进你的插件用;商品ID 必须用它或商品列表勾选拿到 | 11-平台能力与组件库 4 |
window.云捷 只是底层桥,没有上面的业务封装。写插件一律 import 云捷 from './云捷SDK.js'。
@click="搜索()"、@change="换店铺()";
写成 @click="搜索" 会「只读函数引用不调用」→ 点了毫无反应、Console 还不报错。<el-input ... /> 会把**后面的兄弟节点整片吞掉**
(表现:该有的按钮凭空消失)→ 必须写 <el-input ...></el-input>。
只有 <img />、<br /> 这类 HTML 空元素可以自闭合。ReferenceError,点哪都没反应。云捷.缓存 / 云捷.数据库。<sku-search>(包内 组件\SKU搜索.js,组件库唯一的组件,
用户贴 SKU编码 → 自动搜出商品ID);② 用 云捷.商品.列表() 拉列表让用户勾选。
拿到的是商品ID数组,直接传给批量接口 / 创建活动。详见 11-平台能力与组件库 4.1。<el-[a-z0-9-]+[^<>]*/>)发布\(源码 / 笔记 / 文档放外面不会被上传)type="module" + import 云捷 from './云捷SDK.js'(没有 const 云捷 = window.云捷)window.onerror + unhandledrejection),报错看得见app.js / index.html,保存(Ctrl+S)| 症状 | 原因与改法 |
|---|---|
| 点按钮没有任何反应,也不报错 | 模板里中文方法名没带括号:@click="搜索" → 改成 @click="搜索()"。 |
| 该有的按钮整片不见了(弹窗里没有"确定") | 上面某个自定义标签写成自闭合 <el-input ... /> 把后面的兄弟节点吞了 → 补结束标签。 |
| 整页白屏 / 点哪都没反应 | 模板里引用了不存在的字段(ReferenceError)。检查 data/computed/methods 里有没有这个字段;
先看页面顶部的红色错误条、再看 Console。 |
| 接口返回空 body / 被风控 | 写接口(如商机提交)要加 不补来源参数: true;请求头 / 签名参数必须与真实浏览器一致。
偶发空 body 建议重试 2~3 次(每次间隔 1 秒)。 |
| 弹窗能出来,但里面没有"确定/取消" | 同上(自闭合吞节点)。另外:需要输入的弹窗建议用页面内 el-dialog + el-input,
别用 $prompt / $confirm(本环境可能不弹)。 |
| 图片能下载但画布处理报安全错误 | 外链图片跨域会污染画布 → 必须先用 云捷.文件.下载 落到本地,再 云捷.文件.读取(路径, 'base64') 读回来处理。 |
| 接口返回的字段看不懂 | 表格里用抖店返回的英文原名;界面文案写中文。失败原因在 msg(或 errno、内层 data.msg)。 |
参考\09-避坑.md。遇到新坑建议补进那份文档,下次 AI 不会再犯。
YYYYMMDD-序号),填一句更新说明发布\ 外面,一律不会上传到服务器;
「源码目录」要选包含 发布\ 的那一层,不要选 发布\ 本身。发布\ 的老插件不受影响 —— 仍是整目录打包,行为跟以前一样。
| 版本 | 是什么 | 在哪看 / 怎么升 |
|---|---|---|
| 插件版本 | 你这一版插件(提交审核用的) | 「我的应用 → 版本」里提交时递增;用户看到的是这个 |
| 开发包版本 | SDK + 文档/技能 + 组件 + 资源这一整套的版本(写在 云捷SDK.js 开头的 开发包版本) |
「版本 → 开发包版本」看最新版本与更新说明;点「更新开发包(整包)」整包覆盖进你的目录 |
云捷SDK.js、SDK 更新日志、全部参考文档、模板 / 组件 / 资源一起换成同一版,
不会动你自己写的 index.html / app.js / 图片。
所以平台一更新开发包(新能力、新避坑),你点一下就同步了。
D:\我的插件模板\最小插件\ 的 index.html + app.js 复制到包根云捷.店铺列表(),用 标签ID 调业务接口;失败原因要显示给用户不一定。VS Code 也能写(插件就是 HTML + JS,不需要打包工具)。用 Trae 的好处是开发包自带的
.trae/skills 会让 AI 按云捷规范写代码、自动查接口文档、避开已知坑。
不需要。Vue2 和 Element UI 都是开发包里的本地文件,浏览器直接跑;提交流程也是客户端点按钮自动压缩上传。
不能直连数据库(平台不给)。发请求走 云捷.请求(抖店接口,自带店铺登录态与签名)或
云捷.网络.请求(站外接口,主进程发,绕开跨域)。
本地调试是读磁盘的,但页面会被缓存 → 关掉应用标签重新打开(或再点一次「本地调试」)。仍不行就重启客户端。
九成是模板里中文方法名没带括号(见「铁律」第 1 条);其次是整页渲染崩了(字段不存在,先看页面顶部错误条)。
客户端支持同时开多个应用标签;插件自己按 云捷.店铺列表() 逐个处理即可。
多店铺循环要「一家失败不影响其他家」,最后给出成功/失败清单。
不用。点「更新开发包(整包)」覆盖 SDK 与文档即可(不动你的代码);如果新版本的接口签名变了, 看 SDK 更新日志里对应版本的说明改一下调用点。
把需求提给平台(说明你想调什么接口、要什么参数),平台会把能力封装进 SDK 再随开发包下发 —— 插件永远只调 SDK,不自己造轮子。
本页域名:端口 换成你的服务地址)。| 用途 | 地址 |
|---|---|
| 本页(开发者文档网页版) | GET /api/docs/developer.html |
| 开发文档 Markdown(可下载) | GET /api/docs/developer.md |
| 插件开发包 zip | GET /api/docs/kit.zip |
| 当前开发包版本 + 各版本更新说明 | GET /api/docs/sdk/info |
| 示例插件列表 | GET /api/docs/examples |
| 健康检查 | GET /api/health |
| 官网首页 | GET / |
参考\ 目录就是上面这些内容的离线版,断网也能查。
参考\09-避坑.md。