首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何开发门店业绩上报管理系统中的商品数据板块?(附架构图+流程图+代码参考)

如何开发门店业绩上报管理系统中的商品数据板块?(附架构图+流程图+代码参考)

原创
作者头像
用户11735492
发布2025-08-22 21:32:21
发布2025-08-22 21:32:21
1350
举报

写这篇文章的目的很简单:很多企业做门店业绩上报系统时,商品数据板块常被当成“表格+导入导出”处理,结果后端混乱、数据不一致、店员上报困难、报表统计不准。本文从落地可用的角度出发,讲清楚为什么要重视商品数据板块、它包含哪些内容(商品类别、商品信息、商品档案),如何设计架构、业务流程、实现细节和开发技巧,并把所有代码集中放在第12部分,方便工程化落地。


本文你将了解

  1. 为什么要讲门店业绩上报管理中的商品数据板块?
  2. 什么是门店业绩上报管理
  3. 商品数据板块的功能清单
  4. 技术架构(含架构图)
  5. 业务流程(含流程图)
  6. 数据库设计
  7. 后端设计
  8. 前端设计
  9. 开发技巧与落地注意事项(干货)
  10. 实现效果(验收要点、示例场景)
  11. 部署、运维与数据迁移建议
  12. 全部代码集中区(SQL / 后端 / 前端 / 工具脚本)

注:本文示例所用方案模板:简道云门店业绩上报管理系统,给大家示例的是一些通用的功能和模块,都是支持自定义修改的,你可以根据自己的需求修改里面的功能。


一、为什么要讲商品数据板块?

一句话:商品数据是门店业绩上报的“基石”。 如果商品基础数据混乱,上报的销量、毛利、促销效果都无法可信。很多问题的根源都是商品维度设计不合理或数据管理缺位。重视商品数据,不是为了系统好看,而是为了让后续的统计、联动促销、库存预警、补货建议都能“说得通”。

常见痛点:

  • 店员上报商品名称不统一(“可乐500ml” vs “可口可乐500ml”)
  • SKU 没有唯一标识,导入错行、重复创建
  • 类目不标准,报表拆解困难
  • 图片、条码、规格等字段缺失或维护困难

本文目标是把这些痛点用工程化方式解决,让商品数据既方便前端操作,又能支撑统计分析和上游 ERP/OMS 对接。


二、什么是门店业绩上报管理?商品数据的角色

门店业绩上报管理系统是门店与总部之间的“数据上链”系统,包含门店的日常销售数据、业绩 KPI、任务完成情况等。商品数据板块负责:

  • 提供标准化、可检索的商品主数据(Master Data)
  • 支撑门店上报时的商品选择、校验和补全
  • 向报表系统输出准确的商品维度数据(品类、品牌、规格)
  • 与采购/库存/价格系统做数据同步(双向或单向)

设计原则:数据质量、稳定标识、可扩展属性优先。


三、商品数据板块的功能清单(必备 + 推荐)

必备功能

  • 商品类别管理(树型类目:一级/二级/三级)
  • 商品信息管理(名称、条码、SKU、品牌、规格、单位、主图)

  • 商品档案(价格历史、成本、上架状态、有效期)
  • 批量导入/导出(CSV/Excel,带验重与校验报错)
  • 商品检索(模糊、条码、SKU、类目筛选)
  • 商品上报校验规则(字段必填、条码格式、上下线时间)
  • 审批/变更记录(谁在什么时候改了什么)
  • API 接口供其他系统调用(门店上报时实时校验)

推荐功能

  • 商品图片管理(支持多图、缩略图、CDN)
  • 全文检索/高亮(ElasticSearch)
  • 相似商品检测(防止重复录入)
  • 价格与促销维度(支持门店定价)
  • 数据质量看板(缺失字段、重复条码)
  • 版本化(当商品属性变化时保留历史记录)

四、技术架构(简单版)

推荐技术栈(兼顾速度与扩展):

  • 前端:React + TypeScript + Ant Design
  • 后端:Node.js + TypeScript + NestJS 或 Express
  • ORM:TypeORM 或 Sequelize(示例采用 TypeORM)
  • DB:PostgreSQL(支持 JSONB)
  • 缓存:Redis
  • 搜索:ElasticSearch(或 PostgreSQL fulltext)
  • 文件存储:S3 / 对象存储(商品图片)
  • MQ:RabbitMQ / Kafka(异步同步、索引更新)

简化架构图(文字说明): 前端 ↔ API 网关/后端 ↔ PostgreSQL(Master Data) 后端 ↔ Redis(缓存) 后端 ↔ S3(图片) 后端 → MQ → ES(搜索)/其他系统(ERP/OMS)


五、业务流程(商品新增 / 导入 / 上报)

新增商品(典型流程)

  1. 前端填写商品信息表单(含条码、SKU、类目、图片)
  2. 后端做字段校验(必填、条码格式、类目存在)
  3. 去重检查(条码/SKU/名称相似)
  4. 写入主表并记录变更历史
  5. 图片上传到对象存储并保存 URL
  6. 异步发送消息:更新搜索索引、同步到 ERP、通知门店
  7. 返回创建成功

批量导入(两阶段)

  • 预检:解析文件、逐行校验,返回行级错误与建议(覆盖/跳过/合并)
  • 确认写入:用户确认后正式写入主表,写入历史与记录映射(老系统 ID → 新 SKU)

门店上报

  • 前端扫码或检索商品(按 SKU/条码/名称)并返回 product_id,不允许自由文本作为主键标识
  • 若临时商品,进入临时商品审批流程,审核后生成正式商品数据

六、数据库设计(核心表与设计说明 — 概念)

关键表(概念说明):

  • product_categories(类目树)
  • products(商品主表:sku, barcode, name, category_id, attributes(JSONB), price, cost, status)
  • product_images(多图)
  • product_history(变更审计)
  • import_jobs / import_rows(导入临时表,用于预检)

设计说明:

  • SKU 作为系统主唯一键,barcode 作为辅助唯一键(带冲突处理策略)
  • attributes 使用 JSONB 扩展属性
  • 为 name 建立全文索引或接入 ES 做模糊/相似搜索
  • 每次重要变更写入 product_history(before/after)

注:具体 SQL 与实体代码我已集中放到第 12 部分,便于复制使用。


七、后端设计(接口、服务、异步策略)

建议接口:

  • GET /api/categories:类目树
  • POST /api/products:新增商品(支持事务)
  • PUT /api/products/:id:更新商品(写变更历史)
  • GET /api/products:分页搜索(支持 SKU/barcode/全文)
  • POST /api/products/import:上传导入文件 -> 触发预检任务
  • POST /api/products/import/confirm:确认导入写入主表

要点:

  • 校验层与服务层分离,业务逻辑放服务层
  • 对写操作使用 DB 事务,复杂流程使用 Saga 模式或 MQ 做补偿
  • 写入后通过 MQ 异步触发索引更新与外部同步,保证主流程响应速度

八、前端设计(表单与导入 UX)

前端关键点:

  • 表单要做充分校验(字段必填、数值范围、条码格式)
  • 提供扫码功能(扫码直接填入 barcode 并触发后端查找)
  • 批量导入:上传 -> 预检结果表格展示(成功/失败/警告) -> 用户确认 -> 正式写入
  • 商品列表支持服务端分页、列筛选、导出 CSV/Excel
  • 门店上报界面不要自由文本输入商品字段,必须通过商品选择下拉或扫码映射 product_id,没有匹配则走临时商品流程

(具体 React/TSX 代码我已放到第12部分的前端代码区)


九、开发技巧与落地注意事项(干货)

下面列出实战中非常有用的技巧与注意点,贴合企业落地需求。

9.1 SKU 与 Barcode 策略

  • 把 SKU 当作内部唯一标识并强制索引;条码是门店扫码的主输入,但可能缺失或冲突。导入/新增时按优先级处理:barcode -> sku -> 名称相似度。
  • 导入提供“覆盖/跳过/人工确认”选项,并保留操作日志。

9.2 相似度检测与去重

  • 使用 ElasticSearch fuzzy/phonetic 或 PostgreSQL trigram/Levenshtein 做名称相似检测。相似度高的建议人工确认,不要自动合并。
  • 高并发导入可以先写临时表再合并主表,或使用 Redis 作为并发去重缓存键。

9.3 类目编码与迁移策略

  • 类目维护要有稳定 code,便于与 ERP 做映射。类目变更提供“迁移子类目”功能并记录历史,避免直接修改导致报表混乱。

9.4 图片管理

  • 图片上传走对象存储(S3),保存 URL,配合 CDN。保存原图与缩略图,前端按需展示,后端提供图片尺寸校验与审核流程。

9.5 缓存策略

  • 热门商品、类目树缓存 Redis,列表分页按需缓存,搜索走 ES。避免把商品列表全部拉到前端分页。

9.6 审计与回滚

  • change history 必不可少:记录 before/after 与 change_by。支持按时间点回滚(慎重,需要审批),并保留回滚记录。

9.7 同步与幂等

  • 同步 ERP/OMS 时使用幂等设计:携带外部系统 ID 或使用幂等 token,记录同步状态、错误信息与重试策略。

9.8 数据质量监控

  • 设数据质量看板:缺失条码、重复 SKU、无价格、无类目等,定期触发邮件/工作流让负责人补齐。

十、实现效果(验收要点与示例场景)

实现后的验收点(可用于验收清单):

  1. 新增商品耗时(表单提交到成功) < 30 秒(含图片上传)
  2. 批量导入 1000 行:预检在 1-2 分钟返回校验结果(异步),确认写入可在后台任务完成并记录日志
  3. 门店上报实时校验:扫码/搜索能在 300ms 内返回商品标准信息(缓存 & 索引)
  4. 报表能按类目/品牌/规格准确统计销量与毛利(cost 字段可用于毛利计算)
  5. 数据质量看板显示缺失/重复问题并可触发角色分配的处理流程

示例场景:促销活动统计某类目门店销量

  • 通过类目 code 精准定位商品集合(支持多级类目)
  • 关联销售表的 product_id 做聚合,保证聚合准确性的前提是 product_id 的稳定与一致性

十一、部署、运维与数据迁移建议

  • 初期可单体部署(API + DB),后期拆微服务(Product Service、Search Service、Sync Service)
  • 数据迁移:先导入临时表做预检,生成老系统 ID -> 新 SKU 的映射表,人工或半自动确认后批量写入主表并生成映射关系
  • 灾备:定期导出 products 表 CSV,DB 做物理备份与 WAL 备份
  • 监控:接口延迟、MQ 堆积、同步失败率、数据质量异常,设置告警阈值与自动重试机制

十二、代码展示

下面把文章中所有的代码集中放在这里,按文件/用途分类——包含 SQL(建表)、后端(TypeORM 实体、Service、Controller、MQ 示例)、前端(React + Antd 表单、导入思路)、工具与示例脚本。把这些文件放入示例仓库即可快速上手。

说明:代码为 示例/模板,实际使用时请按项目规范(日志、异常处理、安全、配置管理)完善。


12.1 SQL:建表(PostgreSQL 精简版)

代码语言:txt
复制
-- 商品类别(树形)
CREATE TABLE product_categories (
  id SERIAL PRIMARY KEY,
  name VARCHAR(200) NOT NULL,
  parent_id INTEGER REFERENCES product_categories(id) ON DELETE SET NULL,
  code VARCHAR(100),
  created_at TIMESTAMP DEFAULT now(),
  updated_at TIMESTAMP DEFAULT now()
);
-- 商品主表
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  sku VARCHAR(100) UNIQUE NOT NULL,
  barcode VARCHAR(64) UNIQUE,
  name VARCHAR(500) NOT NULL,
  category_id INTEGER REFERENCES product_categories(id),
  brand VARCHAR(200),
  spec VARCHAR(200),
  unit VARCHAR(50) DEFAULT '件',
  price NUMERIC(12,2),
  cost NUMERIC(12,2),
  status VARCHAR(20) DEFAULT 'active',
  attributes JSONB,
  main_image_url TEXT,
  created_by INTEGER,
  updated_by INTEGER,
  created_at TIMESTAMP DEFAULT now(),
  updated_at TIMESTAMP DEFAULT now()
);
-- 商品图片
CREATE TABLE product_images (
  id SERIAL PRIMARY KEY,
  product_id INTEGER REFERENCES products(id) ON DELETE CASCADE,
  url TEXT NOT NULL,
  is_main BOOLEAN DEFAULT FALSE,
  sort_order INTEGER DEFAULT 0
);
-- 历史记录(变更审计)
CREATE TABLE product_history (
  id SERIAL PRIMARY KEY,
  product_id INTEGER,
  change_type VARCHAR(50),
  change_by INTEGER,
  change_at TIMESTAMP DEFAULT now(),
  before JSONB,
  after JSONB
);
-- 临时导入表(预检)
CREATE TABLE product_import_jobs (
  id SERIAL PRIMARY KEY,
  filename VARCHAR(255),
  total_rows INTEGER,
  success_rows INTEGER,
  failed_rows INTEGER,
  status VARCHAR(50) DEFAULT 'pending',
  created_by INTEGER,
  created_at TIMESTAMP DEFAULT now(),
  updated_at TIMESTAMP DEFAULT now()
);
CREATE TABLE product_import_rows (
  id SERIAL PRIMARY KEY,
  job_id INTEGER REFERENCES product_import_jobs(id) ON DELETE CASCADE,
  row_index INTEGER,
  raw_data JSONB,
  status VARCHAR(50), -- pending/ok/error
  error_msg TEXT
);
-- 索引建议
CREATE INDEX idx_products_category ON products(category_id);
CREATE INDEX idx_products_name_gin ON products USING gin (to_tsvector('simple', name));


12.2 后端(Node.js + TypeScript + TypeORM 示例)

12.2.1 Entity:Product(product.entity.ts)

代码语言:txt
复制
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity('products')
export class Product {
  @PrimaryGeneratedColumn()
  id: number;
  @Column({ unique: true })
  sku: string;
  @Column({ unique: true, nullable: true })
  barcode: string;
  @Column()
  name: string;
  @Column({ nullable: true })
  brand: string;
  @Column({ nullable: true })
  spec: string;
  @Column('numeric', { nullable: true })
  price: number;
  @Column('numeric', { nullable: true })
  cost: number;
  @Column({ type: 'jsonb', nullable: true })
  attributes: any;
  @Column({ nullable: true })
  main_image_url: string;
  @CreateDateColumn()
  created_at: Date;
  @UpdateDateColumn()
  updated_at: Date;
}

12.2.2 Service:ProductService(product.service.ts)

代码语言:txt
复制
import { getRepository } from 'typeorm';
import { Product } from './product.entity';
import { publishToMQ } from './mq';
import { saveHistory } from './history.service';
export class ProductService {
  private repo = getRepository(Product);
  async createProduct(payload: any, userId: number) {
    if (!payload.sku && !payload.barcode) {
      throw new Error('SKU 或 条码 必填其一');
    }
    if (payload.barcode) {
      const exists = await this.repo.findOne({ where: { barcode: payload.barcode } });
      if (exists) {
        throw new Error(`条码 ${payload.barcode} 已存在(ID=${exists.id})`);
      }
    }
    if (payload.sku) {
      const existsSku = await this.repo.findOne({ where: { sku: payload.sku } });
      if (existsSku) {
        throw new Error(`SKU ${payload.sku} 已存在(ID=${existsSku.id})`);
      }
    }
    const product = this.repo.create(payload);
    const saved = await this.repo.save(product);
    await saveHistory({
      product_id: saved.id,
      change_type: 'create',
      change_by: userId,
      before: null,
      after: saved
    });
    publishToMQ('product.created', { productId: saved.id });
    return saved;
  }
  async updateProduct(id: number, payload: any, userId: number) {
    const existing = await this.repo.findOneOrFail(id);
    const before = { ...existing };
    if (payload.barcode && payload.barcode !== existing.barcode) {
      const e = await this.repo.findOne({ where: { barcode: payload.barcode } });
      if (e) throw new Error('条码冲突');
    }
    Object.assign(existing, payload);
    const saved = await this.repo.save(existing);
    await saveHistory({
      product_id: saved.id,
      change_type: 'update',
      change_by: userId,
      before,
      after: saved
    });
    publishToMQ('product.updated', { productId: saved.id });
    return saved;
  }
  async findByBarcodeOrSku(code: string) {
    const p = await this.repo.findOne({ where: [{ barcode: code }, { sku: code }] });
    return p;
  }
}

12.2.3 Controller(product.route.ts)

代码语言:txt
复制
import express from 'express';
import { ProductService } from './product.service';
const router = express.Router();
const svc = new ProductService();
router.post('/', async (req, res) => {
  try {
    const userId = req.user?.id || 0;
    const product = await svc.createProduct(req.body, userId);
    res.status(201).json(product);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});
router.put('/:id', async (req, res) => {
  try {
    const userId = req.user?.id || 0;
    const product = await svc.updateProduct(Number(req.params.id), req.body, userId);
    res.json(product);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});
router.get('/search', async (req, res) => {
  try {
    const q = req.query.q as string;
    // 简单模糊搜索示例(实际用 ES)
    const result = await svc.findByBarcodeOrSku(q);
    res.json(result);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});
export default router;

12.2.4 MQ(publishToMQ)示例(mq.ts)

代码语言:txt
复制
export async function publishToMQ(topic: string, payload: any) {
  // 示例:实际接入 RabbitMQ/Kafka
  // const channel = await mq.getChannel();
  // channel.publish(exchange, routingKey, Buffer.from(JSON.stringify(payload)));
  console.log('MQ Publish ->', topic, payload);
}

12.2.5 History Service(history.service.ts)

代码语言:txt
复制
import { getManager } from 'typeorm';
export async function saveHistory(entry: {
  product_id: number;
  change_type: string;
  change_by: number;
  before: any;
  after: any;
}) {
  const em = getManager();
  await em.query(
    `INSERT INTO product_history (product_id, change_type, change_by, before, after) VALUES ($1, $2, $3, $4, $5)`,
    [entry.product_id, entry.change_type, entry.change_by, JSON.stringify(entry.before), JSON.stringify(entry.after)]
  );
}


12.3 前端(React + TypeScript + Ant Design 示例)

代码语言:txt
复制
import React from 'react';
import { Form, Input, Button, Upload, TreeSelect, InputNumber } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import axios from 'axios';
const ProductForm = ({ initialValues = {}, onSaved }) => {
  const [form] = Form.useForm();
  const onFinish = async (values: any) => {
    try {
      // 处理图片 URL 等(这里假设上传返回 url)
      const res = await axios.post('/api/products', values);
      onSaved && onSaved(res.data);
    } catch (e) {
      console.error(e);
    }
  };
  return (
    <Form form={form} initialValues={initialValues} onFinish={onFinish} layout="vertical">
      <Form.Item name="sku" label="SKU" rules={[{ required: true, message: '请输入 SKU' }]}>
        <Input />
      </Form.Item>
      <Form.Item name="barcode" label="条码">
        <Input />
      </Form.Item>
      <Form.Item name="name" label="商品名称" rules={[{ required: true }]}>
        <Input />
      </Form.Item>
      <Form.Item name="category_id" label="类目" rules={[{ required: true }]}>
        <TreeSelect treeData={/* 从接口获取类目树 */[]} />
      </Form.Item>
      <Form.Item name="price" label="价格">
        <InputNumber min={0} />
      </Form.Item>
      <Form.Item name="main_image" label="主图">
        <Upload name="file" action="/api/upload" listType="picture">
          <Button icon={<UploadOutlined />}>上传主图</Button>
        </Upload>
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit">保存</Button>
      </Form.Item>
    </Form>
  );
};
export default ProductForm;


12.4 导入解析后端示例(简化)

代码语言:txt
复制
// 使用 exceljs 或 xlsx 解析文件,生成 product_import_rows
// 伪代码:
async function handleFileUpload(file, userId) {
  const rows = parseExcel(file);
  const job = await createImportJob({ filename: file.name, total_rows: rows.length, created_by: userId });
  for (let i = 0; i < rows.length; i++) {
    const row = rows[i];
    const errors = validateRow(row); // 检查必填、条码格式、类目是否存在等
    await insertImportRow(job.id, i+1, row, errors.length ? 'error' : 'ok', errors.join(';'));
  }
  // 触发异步任务进行预检(或实时同步处理)
  return job;
}


12.5 前后端交互(扫码/上报示例)

代码语言:txt
复制
// 门店扫码或输入条码,前端调用:
axios.get('/api/products/search?q=BARCODE_OR_SKU')
  .then(res => {
    if (res.data) {
      // 使用 res.data.product_id 进行上报
    } else {
      // 提示临时商品流程
    }
  });


12.6 示例:导出商品为 CSV(Node.js)

代码语言:txt
复制
import { getRepository } from 'typeorm';
import { Product } from './product.entity';
import { Parser } from 'json2csv';
import fs from 'fs';
export async function exportProductsCSV(filePath: string) {
  const repo = getRepository(Product);
  const products = await repo.find();
  const fields = ['id','sku','barcode','name','brand','spec','price','cost','category_id'];
  const parser = new Parser({ fields });
  const csv = parser.parse(products);
  fs.writeFileSync(filePath, csv);
}


十三、常见问题

FAQ1:条码和 SKU 哪个更重要?如果条码重复怎么办?

条码(barcode)和 SKU 在实践中各有用途:条码通常由供应商或生产厂家分配,适合门店扫码使用;SKU 多由企业内部定义,承担业务唯一标识的责任。因此建议把 SKU 作为系统的主唯一标识(必须唯一索引),同时把条码作为辅助唯一标识并加索引。对于条码重复(比如不同供应商使用相同条码或条码录错),系统应在导入/创建时做冲突校验:如果发现已有条码,提示“条码已存在,是否关联到该商品或创建独立 SKU?”。导入流程要提供“覆盖/跳过/人工合并”选项,并记录所有操作的历史,以便回溯。总体原则是:不盲目覆盖,保留人工判断路径,并通过相似度检测(名称+规格)降低误合并风险。

FAQ2:如何做批量导入时的数据质量控制,避免导入脏数据?

批量导入要分两步走:预检正式写入。预检阶段把上传的 CSV/Excel 解析到临时表或内存中,对每一行做字段校验(必填项、数值范围、条码格式、类目是否存在)、唯一性检测(sku/barcode)和相似度检测(名称与现有商品比对),将结果返回给前端让用户确认。预检结果要给出详细错误信息与行号,并提供行级操作(修改、忽略、合并)。只有用户确认后才写入主表。对于一次性大规模导入,建议先在测试环境跑一遍并做人工核查。同时记录导入日志,支持回滚或补偿操作。增量导入应确保幂等(以 SKU 为键进行 upsert)。

FAQ3:门店上报如何保证商品选择的标准化,避免门店用自由文本?

要保证上报标准化,前端上报界面必须把商品选择从“自由文本输入”改为“选择稳定主数据”的模式:门店上报时提供按 SKU/条码/名称搜索的下拉选择,扫码直接填入条码并在后台映射到 product_id,不允许店员仅输入文本作为商品标识。对于确实找不到的商品(如临时售卖品),提供“临时商品”流程:临时商品先在客户端以临时记录的方式提交,后台触发管理员审批,审批通过后生成正式 SKU 并通知门店,否则被回退修改。系统应支持离线补报(门店断网)但在同步时做严格校验并把“待同步”项标注清楚。总体目标是从入口端把自由文本空间压缩,依靠主数据保证上报一致性。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么要讲商品数据板块?
  • 二、什么是门店业绩上报管理?商品数据的角色
  • 三、商品数据板块的功能清单(必备 + 推荐)
  • 四、技术架构(简单版)
  • 五、业务流程(商品新增 / 导入 / 上报)
  • 六、数据库设计(核心表与设计说明 — 概念)
  • 七、后端设计(接口、服务、异步策略)
  • 八、前端设计(表单与导入 UX)
  • 九、开发技巧与落地注意事项(干货)
    • 9.1 SKU 与 Barcode 策略
    • 9.2 相似度检测与去重
    • 9.3 类目编码与迁移策略
    • 9.4 图片管理
    • 9.5 缓存策略
    • 9.6 审计与回滚
    • 9.7 同步与幂等
    • 9.8 数据质量监控
  • 十、实现效果(验收要点与示例场景)
  • 十一、部署、运维与数据迁移建议
  • 十二、代码展示
    • 12.1 SQL:建表(PostgreSQL 精简版)
    • 12.2 后端(Node.js + TypeScript + TypeORM 示例)
    • 12.2.1 Entity:Product(product.entity.ts)
      • 12.2.2 Service:ProductService(product.service.ts)
      • 12.2.3 Controller(product.route.ts)
      • 12.2.4 MQ(publishToMQ)示例(mq.ts)
      • 12.2.5 History Service(history.service.ts)
    • 12.3 前端(React + TypeScript + Ant Design 示例)
    • 12.4 导入解析后端示例(简化)
    • 12.5 前后端交互(扫码/上报示例)
    • 12.6 示例:导出商品为 CSV(Node.js)
  • 十三、常见问题
    • FAQ1:条码和 SKU 哪个更重要?如果条码重复怎么办?
    • FAQ2:如何做批量导入时的数据质量控制,避免导入脏数据?
    • FAQ3:门店上报如何保证商品选择的标准化,避免门店用自由文本?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档