商城使用说明(运营 / 管理员)
商城使用说明(运营 / 管理员)
面向对象:商城运营、客服、店铺管理员。 本文讲怎么用、规则是什么;代码实现与接口细节见文末「相关文档」。 适用版本:当前仓库代码(会员体系 + 实物/虚拟商品 + 售后单 + 运费模板 + 销售统计)。
一、商城能做什么
| 端 | 位置 | 能力 |
|---|---|---|
| 后台管理端 | ZRAdmin-Vue3 → 菜单「商城管理」 | 品牌、分类、商品、规格模板、库存/SKU、运费模板、订单、售后、支付流水、会员、销售统计 |
| C 端商城 | ZRAdmin-mall-vue3(H5 / 小程序) | 登录注册、首页、分类、搜索、商品详情、购物车、下单、支付、我的订单、售后、地址簿、个人资料 |
| 内置任务 | 后台「定时任务」 | 待付款超时自动取消、发货后自动确认收货 |
账号体系是两套,互不相通:后台账号(sys_user,Authorization 令牌)管店铺;C 端会员(ums_member,mall-token 令牌)只买东西。会员不能登录后台,后台账号也不能冒充会员下单。
二、开通商城(一次性配置)
商城模块默认关闭,需要按顺序开启:
- 打开模块开关:
appsettings.json中ModuleInit:Mall设为true。 - 执行初始化:
dotnet run -- --initdb(或dotnet ZR.Admin.WebApi.dll --initdb)。会建商城业务表、写入「商城管理」菜单与按钮权限、写入两个内置定时任务;幂等,重复执行不会重复插。- 非 SaaS:建到
MallDb配置的库;SaaS:建到对应租户库。
- 非 SaaS:建到
- 配置会员令牌密钥:
MemberJwt:SecretKey必配。未配置时会员登录、下单全部失败(安全上取"失败关闭"策略)。 - 配置支付(可选):
- 联调:
WechatPay:Enabled=false+MallSettings:AllowMockPay=true(模拟支付,直接把订单标记已付); - 生产:
WechatPay:Enabled=true并补全商户号、证书等;AllowMockPay必须为false。
- 联调:
- 分配权限:给运营角色勾选「商城管理」下对应菜单与按钮(见第八节)。
- 重启宿主:配置改动需重启才生效。
微信支付回调地址在微信商户平台固定配置为
/shopping/front/order/wechat/notify,不要修改,否则回调打不到、订单会永远停在「待付款」。
相关配置项
| 配置 | 默认 | 作用 |
|---|---|---|
ModuleInit:Mall | false | 商城模块开关(影响建表与菜单) |
MallDb | — | 非 SaaS 下商城库的 ConfigId |
MemberJwt:SecretKey | — | 必配,会员令牌密钥 |
MemberJwt:Expire | 20160 分钟 | 会员登录有效期(14 天) |
MallSettings:AllowMockPay | false | 是否允许模拟支付 |
MallSettings:ClosePendingMinutes | 30 | 待付款超时自动取消(分钟) |
MallSettings:AutoConfirmReceiptDays | 7 | 发货后自动确认收货(天) |
MallSettings:AfterSaleDays | 15 | 确认收货后可申请售后(天),0 表示不限 |
WechatPay:Enabled | false | 微信支付总开关 |
MockSms:Enabled | false | 开发环境返回验证码(devCode),生产必须关闭 |
三、开店顺序(推荐)
商品分类 → 品牌 → 运费模板 → 规格模板 → 新建商品(价格/库存/下单表单)→ 上架
→ 用 C 端真机自测下单 → 配首页轮播(后台广告位)
顺序有依赖:商品要选分类与运费模板,SKU 来自规格模板,没上架的商品 C 端看不到。
四、后台各页面操作
菜单路径统一为「商城管理 → xxx」。页面上能看到的按钮由角色权限决定,看不到按钮通常是没有对应权限。
4.1 商品分类
- 树形结构,可多级(父分类 → 子分类),可设图标、排序、说明。
- "是否显示"必须为显示,否则 C 端分类页不展示该分类。
- 分类下有商品时不要直接删;删了分类,商品会成为"无分类"商品,只能靠搜索找到。
- C 端分类列表按"显示 + 未删除"过滤,改完刷新页面即可看到。
4.2 品牌管理
维护品牌名称、图标、排序。品牌是商品的选填属性,用于列表筛选与展示,可先不建。
4.3 运费模板(重要,建议先配)
运费模板决定"收多少运费",规则如下(Freight = 模板里的运费单价):
| 计费方式 | 规则 |
|---|---|
| 按件 | 总件数 ≤ 首件 → 收 1 份运费;超出部分每满「续件」加收 1 份 |
| 按重 | 总重量 ≤ 首重(kg)→ 收 1 份;超出部分每满「续重」加收 1 份(重量取 SKU 上填的重量) |
| 包邮 | 包邮门槛 > 0 且该模板命中的商品总额 ≥ 门槛 → 该模板运费 0 |
| 多模板 | 一单里商品绑了不同模板时,各模板分别算再相加(相当于分段配送) |
补充规则:
- 默认模板:一单只有 1 个模板可设为默认。商品没绑模板时按默认模板收费——留空不等于包邮。
- 不配送地区:可只选省、只选市或选到区。命中后 C 端运费试算与下单都会直接报错(不会出现"能试算、下不了单")。
- 虚拟商品不计运费:虚拟商品(纯服务类)自动跳过运费,与绑定哪个模板无关。
- 运费只在"下单/试算"时按收货地区 + 件数/重量重算,前端试算结果仅供参考,最终以服务端计算为准。
- 商品详情页只能显示"是否包邮 + 门槛"(此时还没有收货地址与整单金额),不要拿详情页文案当作最终运费。
4.4 规格模板
维护可复用的规格组合(如"颜色: 红/蓝;尺寸: S/M/L")。新建商品时选模板可批量生成 SKU;模板只是生成器,商品保存后与模板不再联动,改模板不影响已建好的商品。
4.5 商品管理
列表支持按商品名、编码、关键词、分类、售卖状态、添加时间筛选,可批量上架/下架、删除(软删除)、导出。列表上的「排序」可直接改(数值越大越靠前)。
商品编辑页有 5 个页签:
① 基本信息
| 字段 | 说明 |
|---|---|
| 商品类型 | 实物 / 虚拟(纯服务类),保存后影响下单与售后流程(见 5.1) |
| 商品名称、编码、单位、介绍 | 展示与检索用 |
| 分类、品牌 | 分类决定 C 端归类 |
| 运费模板 | 虚拟商品禁用此项;实物商品留空 = 按默认模板收费 |
| 主图、轮播图、视频 | 列表与详情展示 |
| 售卖状态 | 在售 / 下架,只有"在售"才出现在 C 端 |
| 排序 | 综合排序的置顶值,越大越靠前 |
| 置顶开始/结束时间 | 为空表示长期有效;超出时间窗后置顶自动失效,无需人工下架 |
| 首页 / 分类 / 搜索权重 | C 端三个场景的推荐权重,越大越靠前(详见 4.5.1) |
② 价格 / 库存:按规格生成 SKU,逐个填价格、库存、重量(按重计费必填)、SKU 图片。商品列表展示的价格与总库存由 SKU 自动汇总。
③ 下单表单:让买家在结算时额外填写信息(虚拟商品收"接收账号/接收手机号",实物也能用,如预约配送时间)。
- 勾选式配置:内置 8 个预设(接收手机号、接收账号、接收人姓名、微信号、接收邮箱、QQ 号、预约日期、买家备注),勾上后可改标题、必填、占位提示,也可自由增删字段。
- 字段键(
Field)保存后不要再改——它是订单快照与回传值的匹配依据,改了等于换了个字段。 - 支持自定义正则、长度上限、候选项;勾"敏感"的字段在订单详情里默认打码。
- 不改动就不会覆盖:打开商品但没碰这个页签,保存时保留原配置。
④ 商品详情:富文本详情。
⑤ 预览:提交前总检查,确认无误再保存。
AI 文案(shop:product:ai):商品页可让 AI 生成标题/卖点/详情草稿,只返回草稿不落库,需人工确认后再粘贴保存。
4.5.1 C 端商品排序规则(运营调排序看这里)
| 排序档 | 规则 |
|---|---|
| 综合(默认) | 置顶值(在置顶时间窗内)→ 销量 → 上新时间 |
| 销量 | 销量倒序 |
| 价格升序 / 降序 | 价格 |
| 上新 | 上架时间倒序 |
- 只有「综合」档会用到置顶值(排序 + 置顶时间窗),其他档位不会插队。
- 三个权重按场景生效:首页/推荐位用首页权重、分类筛选用分类权重、关键词搜索用搜索权重(搜索仍先按相关性再按权重)。
- 缺货商品在 C 端会沉底,可配合"仅看有货"筛选。
4.6 库存 / SKU
独立页面,可按商品查/改 SKU 的价格、库存、重量、规格图。日常补货改库存即可,不用进商品编辑页。
库存口径(后台看到的三个数):
| 字段 | 含义 |
|---|---|
库存(Stock) | 总库存;可售 = 库存 − 锁定库存 |
锁定库存(LockStock) | 已下单但未出库占用(下单即锁,取消/超时回补,发货时释放) |
销量(SalesVolume) | 累计已售,取消与退款会相应冲减 |
4.7 订单管理
页面顶部有状态计数概览(含"待发货未发货"数)。列表列显示订单号、金额、状态、物流、会员、订单备注等。
筛选:订单号、物流单号、会员 ID、下单时间,配合状态页签。
注意:不选任何条件时默认只查最近 7 天。查更早的订单必须手动选下单时间,否则会以为"订单丢了"。
列表操作
| 操作 | 权限 | 说明 |
|---|---|---|
| 备注 | oms:order:edit | 写"商家备注",只有后台可见,不影响买家 |
| 发货 | oms:order:ship | 填物流公司 + 物流单号,待发货 → 已发货,同时释放锁定库存 |
| 退款 | oms:order:refund | 见下方"两种退款语义" |
| 批量剔除 | oms:order:cancel | 批量取消,仅待付款/待发货生效,其余状态自动跳过并回补库存 |
| 导出 | oms:order:export | 导出当前筛选条件的数据 |
| 详情 | oms:order:query | 进订单详情页 |
两种退款语义(容易搞混)
| 场景 | 按钮含义 | 结果 |
|---|---|---|
| 已付款且未取消(待发货/已发货/已完成) | 发起退款 | 订单关闭;未发货回补库存,已发货只关闭不回补(货已出库) |
| 已取消且退款状态为"退款中" | 确认退款完成 | 只把退款状态推进为"已退款",不再动库存 |
渠道退款(微信商户平台实际打款)需人工在渠道完成,系统只负责流程与记账。
发货与批量发货
- 单个发货:物流公司 + 单号会做格式校验(长度、字符),不合格直接拒绝。
- 批量发货:先下载导入模板(订单号 / 物流公司 / 物流单号),上传后逐单返回结果(成功 / 失败原因)。已发货、订单号不存在、收货信息不完整的行会单独标注,不影响其他行。
- 批量发货不发短信:买家靠"我的订单"看物流进度,避免重复操作。
- 收货信息缺失(收件人/手机号/地区/详细地址有缺)无法发货,需先在详情里补地址。
订单详情页
- 展示订单信息、金额构成、收货信息、买家填写的下单表单值、物流信息。
- 表单里的敏感字段(手机号/邮箱默认敏感,身份证/银行卡按值兜底)默认打码;需要明文(如给虚拟商品充值)时点「显示完整内容」,该操作要求
oms:order:sensitive权限并记录操作日志。 - 金额构成:
实付 = 商品总额 + 运费 − 优惠 − 积分抵扣。当前版本优惠券与积分未上线,后两项恒为 0。
删除:仅软删除,删除后不参与任何统计。运营异常单建议"取消/退款"而不是删除。
4.8 售后管理
售后单是独立单据(一单可对应多笔售后,但同一时刻只允许一笔进行中)。不要用"订单退款"替代售后:订单退款会把已完成订单置为已关闭,丢掉"曾经完成"的事实。
两条流程
仅退款: 待审核 → 待退款 → 已完成
退货退款:待审核 → 待买家退货 → 待商家收货 → 待退款 → 已完成
任意阶段买家可撤销(→ 已撤销),审核环节可驳回(→ 已驳回)
列表操作
| 操作 | 权限 | 说明 |
|---|---|---|
| 审核 | shop:aftersale:audit | 通过 / 驳回,驳回必须填原因(会展示给买家) |
| 确认收货 | shop:aftersale:audit | 退货退款专用:收到买家退回的货后点,进入"待退款" |
| 登记退款 | shop:aftersale:refund | 在渠道实际退款后登记:退款金额 + 渠道退款单号,售后完成 |
| 撤销 | shop:aftersale:audit | 代客撤销(后台不限阶段) |
| 详情 | shop:aftersale:query | 含订单实付/已退金额与商品摘要 |
金额口径
- 申请金额(
ApplyAmount)是买家要的,实际退款(RefundAmount)是运营登记退的,两者可不同(部分退款、扣运费等),对账以实际退款为准。 - 订单累计已退金额有护栏:不得超过订单实付,重复退款会被拒绝。
- 登记退款前先看详情里的"可退余额",超出会被拒。
库存回补口径
| 情况 | 是否回补可售库存 |
|---|---|
| 未发货(货还在仓) | 回补 |
| 退货退款且商家已确认收到退货 | 回补 |
| 已发货的仅退款(货不退回) | 不回补,只冲减销量 |
当前版本不支持售后凭证图片(公网宿主未开放 C 端上传),沟通走客服渠道。
4.9 支付流水
按订单号、支付类型、状态、创建时间查每笔预支付与支付记录,用于对账和排查"付了钱但订单没变"。微信支付会先记预支付流水,回调成功后更新为已支付。
4.10 会员管理
- 列表:会员 Id(自增,起始 100000)、手机号、昵称、头像、性别、状态、注册时间、最近登录。
- 可启用/禁用(
shop:member:edit)。禁用后该会员无法登录,已有订单不受影响。 - 后台账号与会员是两套体系,这里只显示 C 端会员,查不到
sys_user。
4.11 销售统计
| 指标 | 口径 |
|---|---|
| 有效订单 | 已支付(有支付时间)、未软删、状态不是"已取消/已关闭" |
| 销售总额 / 趋势 / Top10 | 按商品总额统计,不含运费 |
| 客单价 | 实付合计 ÷ 有效订单数 |
| 退款金额率 | 累计退款金额 ÷ 实付合计 |
| 退款订单率 | 发生过退款的订单数 ÷ 有效订单数 |
| 售后率 | 区间内申请的售后单数 ÷ 有效订单数 |
| 实物/虚拟占比 | 按订单形态(下单时快照)统计 |
| 复购率 | 有两单及以上的会员数 ÷ 有订单的会员数 |
| 退款 Top10 商品 | 按商品维度的退款订单数、退款销售额、退款占比 |
趋势与 Top10 支持导出 Excel。统计口径全部收口在"有效订单"一处,指标之间可以互相对得上。
4.12 内置定时任务
初始化时自动写入,可在「定时任务」页查看、改 Cron、停用,建议不要删除。
| 任务 | 默认频率 | 作用 |
|---|---|---|
| 商城待付款订单超时自动取消 | 每 5 分钟 | 超过 ClosePendingMinutes(默认 30 分钟)未付款自动取消并回补库存 |
| 商城发货后自动确认收货 | 每小时 | 发货超过 AutoConfirmReceiptDays(默认 7 天)自动确认收货 |
SaaS 模式下任务按启用租户展开;这两条任务都是幂等的,重复跑不会重复处理。
五、买家侧(C 端)流程
5.1 商品形态决定流程
| 实物商品 | 虚拟(纯服务类) | |
|---|---|---|
| 运费 | 按运费模板计 | 不计运费 |
| 收货地址 | 必填 | 不需要 |
| 付款后状态 | 待发货 | 直接已完成(无发货/收货环节) |
| 买家能否申请售后 | 能(在时效内) | 不能 |
- 一单只能一种形态,混着买会被拒绝(提示分开结算)。
- 订单形态是下单时的快照:之后把商品改成另一种形态,不影响已产生的订单。
- 虚拟商品也可以有库存与限购(沿用 SKU 逻辑),只是没有物流。
5.2 完整链路
- 登录:手机号 + 验证码,未注册自动注册(登录即注册),默认昵称"会员+脱敏手机号"。
- 逛:首页(轮播图 + 商品)、分类、搜索、排序;购物车在设备本地保存(退出登录会清空,换设备不同步)。
- 首页轮播读的是后台「广告位」里 广告类型 = 99、状态显示、且在有效期内的记录,按排序值升序;未配起止时间视为长期有效。
- 商品详情:选规格看价格/库存,显示包邮标签与限购提示。
- 确认订单:选收货地址(地址簿或新填)、查看运费试算、填写商品要求的下单表单、提交。
- 下单必须登录;收货手机号只是联系方式,不需要再收一次短信验证码。
- 支付:微信 H5 / 小程序 / App(微信小程序需先换 OpenId);开发环境可用模拟支付。已支付订单重复点支付直接返回成功,不会重复扣。
- 我的订单:按状态筛选、查看详情与物流、取消(待付款/待发货)、确认收货。
- 售后:订单详情里申请(仅退款 / 退货退款)→ 等待审核 → 通过后退货退款需填回寄物流 → 商家确认收货 → 退款到账。
5.3 买家能申请售后的前提
- 订单状态为待发货、已发货、已完成(待付款只能取消,不能售后);
- 不是虚拟商品;
- 未超过售后时效(确认收货后
AfterSaleDays天,默认 15 天;未签收/无确认收货时间不受限); - 该订单当前没有进行中的售后;
- 申请金额不超过可退余额。
超期后买家仍有路可走:联系客服,由运营在订单页发起退款。
六、状态与规则速查
6.1 订单状态
| 值 | 状态 | 说明 |
|---|---|---|
| 0 | 待付款 | 下单未支付,超时自动取消 |
| 1 | 待发货 | 已支付,等待发货(虚拟单不会停留在这里) |
| 2 | 已发货 | 物流中,可确认收货 |
| 3 | 已完成 | 买家确认或系统自动确认 |
| 4 | 已取消 | 买家/后台取消、超时未付 |
| 5 | 已关闭 | 退款/售后完成后关闭 |
发货状态:0 未发货 / 1 已发货 / 2 已收货。 退款状态:0 无 / 1 退款中 / 2 已退款(3/4 预留给退货进度,当前由售后单自己记录)。
6.2 售后状态
| 值 | 状态 |
|---|---|
| 0 | 待审核 |
| 1 | 已驳回 |
| 2 | 待买家退货 |
| 3 | 待商家收货 |
| 4 | 待退款 |
| 5 | 已完成 |
| 6 | 已撤销 |
6.3 限购
- 位置:商品基本信息里的限购配置(是否开启 / 每单限购 / 总限购)。
- 按商品维度、会员维度累计:同一商品拆成多个 SKU 也会合并计算。
- 不累计的订单:已取消、已关闭、已退款、已退货;退款中、退货中仍计入(防止退款流程中重复下单占额度)。
- 前端只按"每单限购"和库存提示,总限购超标要提交后由服务端拒绝。
- 历史游客订单(会员体系上线前的单)不计入限购。
6.4 防刷与幂等
- 下单限流:IP 维度 10 分钟 10 次、手机号维度 10 分钟 30 次。
- 重复提交防护:前端传
RequestId时按它去重,否则按"会员 + 商品 + 金额(+ 下单表单内容)"签名去重;15 分钟内不会生成两笔相同订单。 - 库存扣减用乐观锁,防超卖。
七、后台权限清单
初始化时自动写入,按角色勾选即可。
| 页面 | 权限编码 |
|---|---|
| 品牌管理 | shop:brand:list/query/add/edit/delete/export |
| 商品分类 | shop:category:list/query/add/edit/delete/export |
| 商品管理 | shop:product:list/query/add/edit/delete/export、shop:product:ai |
| 规格模板 | spectpl:list/query/add/edit/delete |
| 库存 / SKU | shop:skus:list/query/add/edit/delete |
| 订单管理 | oms:order:list/query/edit/ship/cancel/refund/delete/export、oms:order:sensitive |
| 支付流水 | oms:payment:list |
| 运费模板 | shop:freight:list/query/add/edit/delete |
| 会员管理 | shop:member:list/query/edit |
| 售后管理 | shop:aftersale:list/query/audit/refund |
| 销售统计 | oms:sale:query、oms:sale:export |
oms:order:sensitive(查看买家敏感信息明文)默认不发给普通运营,只发给确实需要发货/充值的人,使用会记操作日志。
八、常见问题
Q:订单列表看不到前几个月的订单? 不选任何条件时默认只查最近 7 天,选下单时间再查。
Q:C 端看不到某个商品? 检查:售卖状态是否"在售"、商品是否被删除、所属分类是否"显示"、SKU 是否无库存(缺货会沉底)、C 端分类缓存(5 分钟)。
Q:详情页写包邮,下单却收了运费? 商品没绑运费模板时按默认模板计费,留空不代表免运费。真正的免运费是:模板金额为 0,或整单该模板商品额达到包邮门槛。
Q:下单提示"超出限购"? 总限购按会员累计,前端不提示,服务端拒绝。退款中/退货中的订单仍占额度。
Q:发货按钮点不了/发货失败? 常见原因:订单不是待发货(已取消/已关闭/已发货)、收货信息不完整、物流信息格式不合法。
Q:虚拟商品怎么发货? 虚拟单付款后直接"已完成",没有发货动作。要拿接收账号就去订单详情点「显示完整内容」(需要敏感信息权限)。
Q:买家申请不了售后? 检查是否虚拟商品、是否超过售后时效、订单是否待付款、是否已有进行中的售后、申请金额是否超过可退余额。
Q:退款后库存没回来? 已发货的"仅退款"不回补(货在买家手里);未发货或退货且商家确认收到的才回补。
Q:支付提示"未开通支付通道"或"支付未配置完整"?WechatPay:Enabled=false 时必须显式开 MallSettings:AllowMockPay=true 才能模拟支付;Enabled=true 时若商户配置缺失会拒绝支付(不会降级为模拟支付,避免白拿货)。
Q:会员登录一直失败? 检查 MemberJwt:SecretKey 是否配置、会员是否被禁用、短信通道是否可用(生产环境 MockSms 必须关闭且接入真实短信)。
Q:改商品形态/价格会影响老订单吗? 不会。订单里的商品名、规格、单价、数量、下单表单值、收货地址、订单形态都是下单时的快照。
Q:优惠券、积分、会员等级什么时候有? 当前未上线:订单表已预留字段(恒为 0),会员等级预留字段(恒为 0)。上线前 C 端实付 = 商品总额 + 运费。
九、相关文档
| 文档 | 内容 |
|---|---|
商城系统文档.md | 当前技术实现:认证令牌、接口清单、订单归属、数据模型、部署配置 |
商城会员接口对接文档.md | C 端会员/地址/订单接口的字段与错误码(客户端对接用) |
商城商品形态与售后时效.md | 实物/虚拟分流、售后时效、下单表单校验规则 |
商城运费与售后单.md | 运费计算引擎、售后单状态机、库存回补与金额护栏 |
公网C端与后台拆分部署说明.md | C 端与后台分离部署 |
