在线商城
官方 shop 插件把产品目录变成可以下单的商城。插件随框架一起发布(plugins/shop),无需额外下载。
node node_modules/nuxtcms/scripts/plugin.mjs add shop
pnpm build:cf && pnpm deploy
shop 为付费插件:已授权的域名(以及插件中心所有者自己的站点)在 后台 → 插件 中自动激活;nuxt dev 下无需授权即可使用。
功能一览
| 模块 | 功能 |
|---|---|
| 商品 | 售价、划线价、SKU、库存(可不跟踪)、规格(每个规格可单独定价和库存)、图集、角标、单品税率、"价格面议"与仅展示模式 |
| 前台 | 产品卡片显示价格、购买区(规格、数量)、图集、页头购物车按钮、侧滑购物车、悬浮购物车按钮、/cart、/checkout、/order/<订单号>、/order(查询订单) |
| 结账 | 免注册下单;快递配送(固定运费、满额包邮、可配送国家)或到店自提;优惠券(百分比、固定金额、免运费,可设时间、次数、门槛);价格含税或另计税;最低下单金额;购买条款勾选;Turnstile 与频率限制 |
| 支付 | Stripe Checkout、PayPal、Paytrail(芬兰,欧元)、微信支付与支付宝(中国大陆,人民币)、银行转账、货到付款 / 到店付款 |
| 订单 | 待付款 → 已付款 → 处理中 → 已发货 → 已完成,已取消、已退款;下单即预留库存,取消/退款自动释放;销量统计;订单记录;物流公司和单号;内部备注;CSV 导出 |
| 邮件 | 下单成功(附银行转账信息或自提地址)、付款成功、已发货(含物流单号)、已完成、已取消、已退款;新订单通知店主 |
| 自动化 | 定时任务自动取消超时未付款的在线支付订单;事件 order.created、order.paid、order.status_changed 可推送到钉钉、飞书、企业微信等机器人 |
| SEO | 产品 JSON-LD 中输出 schema.org Offer(价格、币种、库存状态)与 sku |
运费模板
后台 商城 → 运费模板 可以按地区设置不同的运费;一个模板都没有时,沿用商城设置里的固定运费和满额包邮。
| 字段 | 说明 |
|---|---|
| 适用国家 / 指定省份 | 国家填 ISO 代码,* 表示全部;省份(州)留空表示整个国家,可写「上海, 江苏, 浙江」,「广东省」「广东」都能匹配 |
| 计费方式 | 固定运费;按件数(首件 N 件多少钱,每续 M 件加多少);按重量(首重、续重按公斤填写,续重不足一档按一档算) |
| 包邮条件 | 满额包邮(按优惠后的金额)、满件包邮,可以同时设置 |
匹配顺序:先匹配指定了省份且省份对上的模板,其次是指定了国家的模板,最后是 *;同一级别按排序数字从小到大。收货地址匹配不到任何模板时,不能选快递配送下单。顾客还没填地址时,结算页按第一个全国模板预估运费。重量取商品编辑页「商城」卡片里的重量(克),未填写的商品按 0 计算;「免运费」优惠码对所有模板有效。
会员账户
在商城设置里打开 开启会员账户 后:
- 页头出现账户图标,顾客可以注册、登录(
/member/login)、找回密码(邮件链接 1 小时内有效,改密码后失效)。 - 我的账户(
/member):订单列表(点开即订单页)、个人资料、修改密码;收货地址(/member/addresses):增删改、设默认,最多 20 个。 - 结账时自动带出姓名、邮箱、电话和默认地址,可以选择已保存的地址;填写新地址时可勾选「保存到地址簿」。
- 关闭 允许免注册下单 后,必须登录才能结账;默认仍允许访客下单。
- 后台 商城 → 会员:会员列表(订单数、已付款金额、最近下单)、停用 / 启用账户(停用后立即退出登录)。
会员与后台管理员是两套账户:会员使用单独的数据表(shop_customers、shop_addresses)和单独的 Cookie,无法进入后台。注册、登录和找回密码沿用「安全验证」里的登录验证设置,并有频率限制。会员下的订单关联到会员(shop_orders.customer_id,老站点升级时自动加列);免注册订单不会按邮箱自动归入会员。
积分
开启会员账户后,在商城设置里打开 开启积分:
| 设置 | 说明 |
|---|---|
| 每消费 1 元获得积分 | 订单 完成 后按商品实付金额发放(不含运费和另计的税),0 = 不发放 |
| 多少积分抵 1 元 | 例如 100,即 100 积分抵 1 元 |
| 积分最多抵扣商品金额的 % | 例如 50,即最多抵扣一半 |
| 注册赠送积分 | 新会员注册时发放 |
结账时会员可以勾选「使用积分抵扣」,按余额和上限自动计算;积分在下单时扣除。订单取消或退款时退回已用积分,并收回该订单发放的积分(余额不足时收回剩余部分)。会员在 我的账户 查看余额和明细;后台 商城 → 会员 点积分数字可以手动加减(不能扣成负数)。所有变动都记在 shop_points_ledger。
门店
在后台 商城 → 门店 添加门店(名称、地址、营业时间、电话、通知邮箱、服务区域、是否可自提)。没有门店时一切照旧:自提使用设置里的自提地址,订单不分配门店。
- 到店自提:商城设置里开启「到店自提」后,结账时顾客从「可自提」的门店中选一家,必须选择;订单页和下单邮件显示该门店的地址、营业时间和电话。
- 快递订单分配:按收货地址匹配门店的服务区域,规则和运费模板一样(地区匹配 > 国家匹配,同级按排序靠前)。服务国家留空的门店是兜底门店,接收其他门店都不覆盖的订单。
- 通知:门店填了通知邮箱,分配给它的新订单会发一封邮件过去(和店主通知同样的内容)。
- 后台:订单列表可以按门店筛选(也可以筛「未分配门店」),订单详情里可以改派门店,改派记在订单记录里。删除门店后,它的订单变为未分配。
门店库存
在 商城 → 门店库存 里,每个商品(有规格的按规格)一行、每家门店一列,填写各门店的库存:
- 某个商品或规格只要填写了任意一家门店的库存,就改为 按门店计算:可售数量 = 启用门店的库存之和(自动写回商品,前台显示和下单数量限制照常生效)。在商品编辑里修改库存对它无效。
- 下单从订单所属门店扣减,取消或退款时退回该门店;后台改派门店时,库存跟着订单从原门店转到新门店。
- 到店自提只能选择备齐了这些商品的门店(结账页会标出缺货门店);快递订单优先分给服务区域内有货的门店,区域内都缺货时分给其他有货的门店。没有一家门店能备齐所有商品时无法下单,需要分开下单。
- 停用的门店不计入可售数量。删除门店会一并删除它的库存。
- 所有门店都留空,商品恢复按商品统一计算库存;没填写门店库存的商品一直按原方式计算。
商家入驻
开启会员账户后,在商城设置里打开 开启商家入驻,并设置平台默认佣金比例、订单完成后几天结算、商家最低提现金额。
- 申请:会员在 商家中心(
/merchant,「我的账户」里有入口)填写店铺名称、联系人、电话等提交申请。 - 审核:后台 商城 → 商家入驻 通过或驳回(驳回原因商家可见,可修改后重新提交)。可以为每个商家单独设置佣金比例,留空用默认值。
- 分配商品:点商家的商品数,勾选它销售的商品。商品的标题、描述、图片仍由平台在后台维护,商家不接触网页内容和文件上传。
- 商家日常:在商家中心修改自己商品(含规格)的售价、划线价和库存(按门店计库存的商品由平台维护);查看包含自己商品的订单,只显示自己的商品行和收货信息(不显示买家邮箱),填写快递公司和单号标记发货(记入订单记录)。有新的已付款订单时给商家发邮件(店铺邮箱,留空用会员邮箱)。
- 结算:订单 付款 后为每个商家生成一条结算记录:应结算 = 该商家商品的销售额 − 平台佣金(四舍五入到分)。订单 完成 后过了结算天数计入商家余额。取消或退款时,未结算的取消、已结算的从余额扣回(可能为负,之后的结算先抵扣)。
- 提现:商家申请提现后金额立即从余额扣除;平台线下转账后在后台 提现记录 点「已打款」,或驳回并填写原因(金额退回)。同一时间只能有一笔处理中的提现。
说明:优惠券、积分抵扣和运费都由平台承担或收取,不影响商家结算;平台自己的商品(没有分配给商家)照常销售。暂停的商家不能登录商家中心,但它商品的订单照常产生结算。数据表为 shop_merchants、shop_merchant_earnings、shop_merchant_payouts,商品和订单明细上有 merchant_id。
两级分销
开启会员账户后,在商城设置里打开 开启两级分销:
| 设置 | 说明 |
|---|---|
| 一级佣金比例 % | 推广员自己带来的订单,按商品实付金额计算(不含运费和另计的税) |
| 二级佣金比例 % | 推广员的上级(邀请他的人)获得的比例,0 = 只有一级 |
| 推广员需后台审核 | 打开后申请要在后台通过才生效 |
| 推广链接有效天数 | 访客点击链接后这段时间内下单计入推广员,默认 30 天 |
| 订单完成后几天佣金到账 | 默认 7 天,期间退款会取消佣金 |
| 最低提现金额 | 低于这个金额不能申请提现 |
流程:
- 会员在 我的账户 → 推广中心 申请成为推广员,拿到推广码和链接。任何页面地址后加
?ref=推广码都有效。 - 访客通过链接进站,浏览器记住推广码。访客注册会员后与推广员 永久绑定;未注册或已有会员也按链接计入(链接过期后不再计入)。
- 订单 付款 后生成佣金(待到账):一级给推广员,二级给推广员的上级。订单 完成 后过了等待天数才到账,可以提现。到账由定时任务「商城:取消超时未付款订单」处理,打开推广中心或后台分销页时也会顺便结算。
- 订单取消或退款:未到账的佣金取消;已到账的佣金扣回,余额可能变成负数,之后的佣金会先抵扣。
- 推广员在推广中心填写收款方式(支付宝、微信、银行卡等)和账号申请提现,金额立即从余额扣除。商家在后台 商城 → 分销推广 → 提现记录 线下打款后点「已打款」(可填流水号);也可以驳回并填写原因,金额会退回余额。同一时间只能有一笔处理中的提现。
限制:最多两级;自己通过自己的链接购买不计佣金;停用的推广员不再获得新佣金(已有余额保留);推广员只能看到打码后的订单号,看不到买家信息。数据表为 shop_commissions 和 shop_withdrawals。
国内的分销活动请遵守相关法规,不要设置超过两级的返佣,也不要以拉人头本身作为收益来源。
发票与收据
商城设置 发票 / 收据 有四个选项:不提供、开票申请、自动收据、两者都提供。
- 开票申请(适合中国大陆):顾客在结算页勾选「需要发票」,或付款后在订单页申请,填写个人 / 企业抬头和纳税人识别号(企业必填)。后台 商城 → 发票 处理:在税务系统开好后上传 PDF(最大 5 MB),顾客收到邮件并在订单页下载;也可以驳回并说明原因,顾客修改后重新提交。PDF 存在附件存储的
private/目录下,/api/media不会提供这些文件,只能凭订单链接下载。 - 自动收据(适合海外):订单付款后,订单页出现「查看收据」,打开即为可打印的收据 / 发票(卖方名称、地址、税号、购买方、明细、税额、积分和优惠),用浏览器「打印 → 另存为 PDF」即可保存。卖方信息在商城设置里填写,留空时使用站点名称和公司地址。
配置步骤
- 后台 → 插件 → 在线商城 → 配置(或 商城 → 商城设置):币种、税率、配送、自提、订单号前缀、通知邮箱以及要启用的支付方式。
- 打开任意产品,编辑器右侧的 商城 卡片里设置价格、库存、规格和图集,随产品一起保存。商城数据按产品 slug 关联,同一产品的各语言版本共用价格与库存。
- 在 后台 → 邮件配置 设置 SMTP,客户才能收到订单邮件。
- 确认定时任务 Worker(
deploy/cron-worker)在运行,"取消超时未付款订单"任务才会执行。
支付方式
| 支付方式 | 需要填写 | 说明 |
|---|---|---|
| Stripe | Secret Key sk_…;可选 Webhook 密钥 whsec_… | 客户返回网站时通过 API 核实付款。更稳妥的做法是在 Stripe 后台添加 Webhook /api/shop/webhooks/stripe,事件选 checkout.session.completed 和 checkout.session.async_payment_succeeded。 |
| PayPal | Client ID + Secret,可切换沙箱 | 使用 Orders v2,客户返回时扣款。 |
| Paytrail | 商户号 + 密钥 | 仅支持欧元。跳转参数与服务器回调 /api/shop/webhooks/paytrail 均做 HMAC 校验并核对金额。测试账号:商户号 375917,密钥 SAIPPUAKAUPPIAS。 |
| 微信支付 | 商户号、AppID、APIv3 密钥、商户 API 证书序列号、商户 API 私钥(apiclient_key.pem);可选微信支付公钥及其 ID | 仅人民币,APIv3。电脑端在订单页显示二维码(Native 支付),付款后页面自动更新;手机浏览器在开启"H5 支付"后跳转微信付款(需在商户平台开通 H5 支付并配置域名),否则也显示二维码;微信内打开时显示二维码,长按识别即可。回调地址 /api/shop/webhooks/wechat(需 https):用 APIv3 密钥解密,填写公钥后同时校验签名。 |
| 支付宝 | AppID、应用私钥(RSA2,PKCS8 / PKCS1 均可)、支付宝公钥;沙箱开关 | 仅人民币,公钥模式。电脑端跳转电脑网站支付(扫码或登录付款),手机端跳转手机网站支付并拉起支付宝 App。微信内不提供支付宝(微信会拦截)。异步通知 /api/shop/webhooks/alipay 做 RSA2 验签,客户返回时再调用 alipay.trade.query 核实。 |
| 银行转账 | 转账说明 | 订单保持"待付款",收到款项后在后台手动标记为已付款。 |
| 货到付款 | — | 同上,收款后手动标记为已付款。 |
所有在线支付在标记为已付款前,都会在服务器端核对订单金额与币种。微信支付和支付宝的付款有效期与"未付款订单自动取消"一致(time_expire);如果已取消的订单仍收到付款,会在订单记录里提示退款。浏览器从不提交价格,购物车由 /api/shop/quote 和 /api/shop/checkout 重新计价。
站点预设与环境变量
可以在站点的 nuxtcms.plugins.json 中预设插件设置(后台保存的值优先),支付密钥也可以放在环境变量里,不必存进数据库:
{ "plugins": [{ "id": "shop", "package": "nuxtcms/plugins/shop", "license": "NCMS-…",
"settings": { "currency": "EUR", "taxRate": 14, "pickupEnabled": true, "orderPrefix": "LC" } }] }
| 变量 | 对应设置 |
|---|---|
NUXT_SHOP_STRIPE_SECRET_KEY / NUXT_SHOP_STRIPE_WEBHOOK_SECRET | Stripe |
NUXT_SHOP_PAYPAL_CLIENT_ID / NUXT_SHOP_PAYPAL_SECRET | PayPal |
NUXT_SHOP_PAYTRAIL_MERCHANT_ID / NUXT_SHOP_PAYTRAIL_SECRET | Paytrail |
NUXT_SHOP_WECHAT_MCH_ID / _APP_ID / _API_V3_KEY / _SERIAL_NO / _PRIVATE_KEY / _PUBLIC_KEY_ID / _PUBLIC_KEY | 微信支付 |
NUXT_SHOP_ALIPAY_APP_ID / NUXT_SHOP_ALIPAY_PRIVATE_KEY / NUXT_SHOP_ALIPAY_PUBLIC_KEY | 支付宝 |
自定义
所有界面都通过扩展点渲染,站点的布局不受影响。在站点的 app/app.config.ts 中调整:
export default defineAppConfig({
nuxtcms: {
slots: {
'header:actions': { ShopCartButton: false }, // 站点页头已有自己的购物车图标
},
},
})
全局组件 ShopCartButton、ShopBuyBox、ShopCardPrice、ShopGallery 可以直接放进自定义布局(<ShopCartButton />)。站点也可以在同一路径覆盖插件页面,例如自己写一个 app/pages/checkout.vue。
数据表({前缀}shop_products、shop_orders、shop_order_items、shop_order_notes、shop_coupons)在首次使用时自动创建,支持 SQLite / D1、PostgreSQL 和 MySQL。