RFID 标签打印机与 EAM 系统的工程集成实践

举报
yd_263375679 发表于 2026/09/20 09:17:57 2026/09/20
【摘要】 首发于华为云开发者社区技术栈:Vue 3 + TypeScript + uni-app + Spring Boot + 工业级 UHF RFID 标签打印机场景:企业资产 / 备件管理 SaaS 中的 RFID 标签写入与打印一体化关键词:RFID 标签打印机、UHF、EPC、User 区、ZPL/EPL、打印机 SDK、资产标签、批量打印 一、为什么我们必须自己接 RFID 标签打印机?上...

首发于华为云开发者社区
技术栈:Vue 3 + TypeScript + uni-app + Spring Boot + 工业级 UHF RFID 标签打印机
场景:企业资产 / 备件管理 SaaS 中的 RFID 标签写入与打印一体化
关键词:RFID 标签打印机、UHF、EPC、User 区、ZPL/EPL、打印机 SDK、资产标签、批量打印


一、为什么我们必须自己接 RFID 标签打印机?

上一篇文章《从扫码枪到射频读卡器》里,我讲了首码 EAM 怎么用 PDA + RFID 读写器做盘点。但盘点只是「读取侧」,写入侧——把 EPC 编码写入 RFID 标签,再把标签贴到资产上——这套链路在企业内部几乎没人讲过。

而我们恰恰踩进了这个坑:客户上线首码 EAM 后,资产卡片需要一张张贴上 RFID 标签。如果用手持 PDA 单个写入、单个打印条码标签、再人工对粘,5000 件资产意味着:

5000 件 ×(写卡 5s + 打印条码 3s + 贴标 4s) ≈ 1.5 人天

而一台工业级 RFID 标签打印机(带 UHF 写卡模块)能一次完成「写 EPC + 打印条码 + 打印资产信息」,单机速度 2~3 秒/张。同样 5000 件,一个人半天就能完成。

更重要的是——标签一旦由打印机统一生成,EPC 与资产编号的映射关系就锁死在系统里,彻底杜绝了「贴错标签」的人为事故。

于是我们花了 3 周时间,把首码 EAM 和市面上 3 款主流 RFID 标签打印机打通。本文把全过程拆开讲,重点放在实战里踩过的坑——这些坑在所有 RFID 标签打印机厂商的文档里都不会写。


二、硬件选型:选打印机不是选贵的

工业级 RFID 标签打印机比普通条码打印机贵 5~10 倍。选错型号,整个项目成本就要失控。我们的选型逻辑如下:

维度 桌面级 工业级(推荐)
日打印量 < 500 张/天 1000~10000 张/天
标签宽度 固定 50~80mm 可调 25~104mm
UHF 写卡模块 选配或无 标配(关键)
碳带支持 部分支持 完整支持(树脂碳带)
寿命 1~3 年 5~8 年

我们最终选了桌面级+工业级双方案:办公环境用桌面级(轻量、低噪音),机房/工厂车间用工业级(防尘、抗震、长寿命)。

频段方面,国内合规的 UHF RFID 频段是 840~845MHz 和 920~925MHz,标签打印机和 PDA 读写器必须落在同一频段,否则写入的 EPC 标签,PDA 读不到——这种「写进去读不出来」的坑我们踩过,后面会讲。


三、SDK 集成的两条路:私有协议 vs 标准 API

RFID 标签打印机厂商通常提供两套接入方式:

  1. 私有 SDK(厂商提供 .dll/.so/.jar):功能最强,但强耦合厂商
  2. 标准 EPLZPL 命令集(斑马体系):跨厂商,但功能受限

首码 EAM 走的路线是:底层用 EPL/ZPL 命令 + 上层抽象接口。原因有三:

  1. 跨厂商兼容:今天用 A 厂商打印机,明天客户换 B 厂商,业务代码不动
  2. 后端 Java 可直接拼命令串:不需要为每个厂商维护 native 库
  3. 方便单测:EPL/ZPL 命令串本身就是字符串,可以断言校验

我们的抽象接口(TypeScript):

// modules/rfid-printer/interface.ts

/**
 * RFID 标签打印机抽象接口
 * 不同厂商通过适配器实现该接口
 */
export interface IRfidPrinter {
  // 连接(USB/串口/网口/蓝牙)
  connect(opts: ConnectOptions): Promise<boolean>

  // 断开
  disconnect(): Promise<void>

  // 打印并写入 EPC(核心 API)
  // EPC 数据写入标签的 EPC 区,User 数据写入 User 区
  printAndWriteTag(params: PrintWriteParams): Promise<PrintResult>

  // 仅打印(普通条码标签,不写卡)
  printLabelOnly(params: PrintParams): Promise<PrintResult>

  // 仅写卡(已有标签,只补 EPC)
  writeTagOnly(params: WriteParams): Promise<WriteResult>

  // 读取当前光标位置的标签 EPC(用于校验)
  readTagEpc(): Promise<string>

  // 获取打印机状态
  getStatus(): Promise<PrinterStatus>
}

export interface PrintWriteParams {
  // 打印内容(条码、二维码、文字、图片)
  label: LabelTemplate

  // 要写入的 EPC 编码(96 bit / 128 bit 两种常见长度)
  epc?: string

  // 要写入的 User 区数据(最多 512 bit)
  userData?: string

  // 访问密码(部分高安全场景使用)
  accessPassword?: string

  // 写入失败重试次数
  retryCount?: number
}

export interface PrintResult {
  success: boolean
  epc?: string
  errorCode?: string
  errorMsg?: string
}

这个接口有个细节:readTagEpc() 用于校验——打印完一张标签,立刻回头读一次,确认 EPC 真的写进去了。这是「打印成功 ≠ 写入成功」这个坑的关键防御手段(详见第六节坑 3)。


四、EPC 区与 User 区:标签的「身份证」和「笔记本」

很多团队搞不清 EPC 和 User 区的区别,把所有数据都往 EPC 区塞。结果就是:

  • EPC 区超长(超过 128 bit),某些老读写器不识别
  • 修改资产信息时,要重写整个 EPC 区,旧标签作废
  • 同一标签被多个系统读取时数据冲突

正确的做法是把 RFID 标签当成一个微文件系统:

┌──────────────────────────────────────────────┐
│ TID 区(出厂固化,不可写,96 bit)             │
│ → 标签的「全球唯一 ID」,全球不重复            │
├──────────────────────────────────────────────┤
│ EPC 区(可写,默认 96 bit,可扩到 496 bit)    │
│ → 资产的「业务身份证」,存资产编号             │
├──────────────────────────────────────────────┤
│ User 区(可写,0~512 bit,型号决定上限)       │
│ → 资产的「动态笔记本」,存可变信息           │
├──────────────────────────────────────────────┤
│ Reserved 区(锁定后不可改)                   │
│ → 访问密码、销毁密码                          │
└──────────────────────────────────────────────┘

我们在首码 EAM 里的写入策略是:

区 存什么 写入时机 修改频率
TID 标签出厂 ID 只读 从不
EPC 资产编号(如 ASSET-2024-001234) 入库贴标时 报废前不变
User 当前位置、责任人、状态 每次转移/盘点 高频

User 区由 PDA 读写器在盘点时原地更新,不需要重新打印标签。这意味着:

  • 标签可以重复使用(盘亏资产回收后,重新贴到新资产上即可)
  • 历史轨迹不会丢(每次盘点都写一次 User 区)
  • EPC 始终指向「正在」资产上,User 区指向「此刻」状态

具体写卡代码(基于厂商 SDK 二次封装):

// RfidLabelPrintService.java

@Service
public class RfidLabelPrintService {

    @Autowired
    private IRfidPrinter printer;

    /**
     * 打印并写入资产标签
     */
    public PrintResult printAndWriteAssetLabel(AssetLabelDTO dto) {
        // 1. 拼装 EPL/ZPL 打印命令
        String printCmd = buildLabelCommand(dto);

        // 2. 拼装 EPC 写入指令(厂商私有协议)
        String epcHex = StringUtils.leftPad(
            dto.getAssetCode(), 24, '0' // 96 bit EPC,24 字节十六进制
        );

        // 3. 拼装 User 区数据(存放初始位置和责任人)
        String userData = buildUserData(dto);

        // 4. 一次打印 + 写卡
        PrintResult result = printer.printAndWriteTag(
            PrintWriteParams.builder()
                .label(LabelTemplate.fromEpl(printCmd))
                .epc(epcHex)
                .userData(userData)
                .retryCount(2)        // 失败重试 2 次
                .build()
        );

        // 5. 写入失败要回滚已生成的资产编号(避免号段浪费)
        if (!result.isSuccess()) {
            assetCodeService.release(dto.getAssetCode());
            throw new RfidPrintException(result.getErrorMsg());
        }
        return result;
    }

    /**
     * 拼装 User 区数据(JSON 紧凑格式)
     * 96 bit 起标 512 bit 都能放下
     */
    private String buildUserData(AssetLabelDTO dto) {
        Map<String, Object> userMap = new LinkedHashMap<>();
        userMap.put("loc", dto.getLocationCode());   // 位置码
        userMap.put("own", dto.getOwnerId());        // 责任人
        userMap.put("sts", dto.getStatusCode());     // 状态码
        userMap.put("ts",  dto.getUpdateTime());     // 更新时间戳
        // 用最短字段名压缩到 64 字节以内
        return JSON.toJSONString(userMap);
    }
}

注意 retryCount(2)——工业现场电磁环境复杂,写卡失败是常态。只重试一次不够。但也不要超过 3 次,否则连续失败会让现场实施人员失去耐心。


五、打印模板:CSV → 模板引擎的演进

5.1 阶段一:硬编码 EPL/ZPL 命令

项目初期,我们直接在代码里拼 EPL 命令:

String cmd = "^XA\n" +
             "^FO50,50^A0N,40,40^FD" + assetCode + "^FS\n" +
             "^FO50,100^BY3^BCN,80,Y,N,N^FD" + assetCode + "^FS\n" +
             "^FO50,200^A0N,30,30^FD" + assetName + "^FS\n" +
             "^XZ";

能用,但完全不能改——客户要求「把资产名称字体调大、加个二维码、LOGO 放左下角」时,只能改代码、发版。

5.2 阶段二:基于模板引擎(推荐)

我们最终选择前后端分离的模板方案:

  • 后端:维护一套「标签模板定义」(JSON),存数据库
  • 前端:用 Vue3 + Canvas 渲染预览,所见即所得
  • 运行时:用户调整模板 → 保存 → 后端生成 EPL/ZPL 命令

模板定义示例:

// modules/rfid-printer/template.ts

export interface LabelTemplate {
  // 标签尺寸(毫米)
  width: number
  height: number

  // 元素列表(按 z-order 渲染)
  elements: LabelElement[]
}

export type LabelElement =
  | TextElement      // 文字
  | BarcodeElement   // 一维条码
  | QrcodeElement    // 二维码
  | ImageElement     // 图片
  | LineElement      // 直线
  | BoxElement       // 矩形框

export interface TextElement {
  type: 'text'
  x: number
  y: number
  fontSize: number   // 毫米为单位
  content: string    // 支持 {{assetCode}} 这样的占位符
  bold?: boolean
  align?: 'left' | 'center' | 'right'
}

// 二维码元素(存放 EPC 编码,方便 PDA 扫码替代 RFID 读取)
export interface QrcodeElement {
  type: 'qrcode'
  x: number
  y: number
  size: number       // 边长,毫米
  content: string    // 默认是 EPC 编码
  errorLevel?: 'L' | 'M' | 'Q' | 'H'
}

后端把模板编译成 EPL/ZPL 的代码(核心片段):

// LabelTemplateCompiler.java

public String compileToEpl(LabelTemplate template, Map<String, String> data) {
    StringBuilder sb = new StringBuilder();
    sb.append("^XA\n");              // 开始
    sb.append("^PW").append(toDots(template.getWidth())).append("\n");  // 标签宽度
    sb.append("^LL").append(toDots(template.getHeight())).append("\n"); // 标签长度

    for (LabelElement el : template.getElements()) {
        sb.append(renderElement(el, data));
    }

    sb.append("^XZ");                // 结束
    return sb.toString();
}

private String renderElement(LabelElement el, Map<String, String> data) {
    String content = replacePlaceholder(el.getContent(), data);
    switch (el.getType()) {
        case "text":
            return String.format("^FO%d,%d^A0N,%d,%d^FD%s^FS\n",
                toDots(el.getX()), toDots(el.getY()),
                toFontHeight(el.getFontSize()), toFontWidth(el.getFontSize()),
                content);
        case "barcode":
            return String.format("^FO%d,%d^BY%d^BCN,%d,Y,N,N^FD%s^FS\n",
                toDots(el.getX()), toDots(el.getY()),
                2, toDots(el.getHeight()),
                content);
        case "qrcode":
            // ZPL 的二维码指令:^BQN + ^FD + 数据 + ^FS
            return String.format("^FO%d,%d^BQN,2,%d^FD%s^FS\n",
                toDots(el.getX()), toDots(el.getY()),
                el.getErrorLevel() == 'H' ? 4 : 2,
                content);
        // ... 其他元素
        default:
            return "";
    }
}

private String replacePlaceholder(String template, Map<String, String> data) {
    // {{assetCode}} → 实际资产编号
    Pattern p = Pattern.compile("\\{\\{(\\w+)\\}\\}");
    Matcher m = p.matcher(template);
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
        String key = m.group(1);
        m.appendReplacement(sb, data.getOrDefault(key, ""));
    }
    m.appendTail(sb);
    return sb.toString();
}

这套模板引擎的核心优势:

  1. 零代码改模板:实施人员登录后台就能改
  2. 预览所见即所得:前端 Canvas 渲染,打印前能确认
  3. 多模板并存:不同类型的资产(设备、备件、办公电脑)用不同模板

六、踩坑实战:这 8 个坑你早晚都会遇到

这一节才是全文最值钱的。所有坑都是我们一行一行踩出来的。

坑 1:打印成功 ≠ 写入成功

最隐蔽、最严重的坑。打印机返回成功,可能只是「打印头走纸完成」,RFID 写卡模块根本没工作。

表现:标签打印出来了,条码能扫,但 PDA 读写器读不到 EPC。

根因:写卡模块需要 RFID 标签的 UHF 芯片处于读写器射频场内。打印过程中,标签快速移动,可能有一瞬间离开了射频场,写卡失败但打印机不会报错。

修法:写入后立刻回读校验。

public PrintResult printAndWriteTag(PrintWriteParams params) {
    PrintResult result = doPrintAndWrite(params);

    if (result.isSuccess()) {
        // 关键步骤:写完后立刻读一次
        String actualEpc = printer.readTagEpc();

        if (!Objects.equals(actualEpc, params.getEpc())) {
            // 读到的 EPC 和写入的不一致 → 写卡失败
            return PrintResult.fail("EPC_VERIFY_FAILED",
                "写入后回读不一致,写入=" + params.getEpc() +
                " 回读=" + actualEpc);
        }
    }
    return result;
}

我们的现场数据显示:大约 6% 的「打印成功」其实写卡失败,全靠这个回读机制兜底。

坑 2:EPC 长度 96 bit 还是 128 bit?

厂商 A 默认填 96 bit(24 字节十六进制),厂商 B 默认填 128 bit。同一台打印机可以通过命令切换,但很多客户不知道。

坑的表现:用厂商 A 的打印机写入 EPC = 3034 3038 3030 3030 3031 3233,共 96 bit。但用厂商 B 的 PDA 读写器默认只读 96 bit,读到的是截断后的数据 3034 3038 3030 3030。

修法:项目启动时统一所有硬件的 EPC 长度。首码 EAM 配置项里有:

// config/rfid.ts
export const RFID_EPC_LENGTH = 96  // 单位 bit,全项目硬编码

// 计算 EPC 字符串时强制转换
export function buildEpc(assetCode: string): string {
  const hex = Buffer.from(assetCode, 'utf8').toString('hex')  // 字符串 → 十六进制
  if (hex.length * 4 > RFID_EPC_LENGTH) {
    throw new Error(`资产编号 ${assetCode} 超出 EPC 长度限制`)
  }
  return hex.padEnd(RFID_EPC_LENGTH / 4, '0')  // 不够补 0
}

坑 3:写入失败但 PDA 读到了旧 EPC

更隐蔽的坑——你以为写卡成功了,但 PDA 读到的还是上一张标签的 EPC。

根因:工业级 RFID 标签打印机通常是「批处理模式」:把 10 张标签同时放进出纸口,打印机按顺序处理。如果第 5 张写卡失败,但打印动作完成了,EPC 留在了第 4 张标签上——下次盘点读到第 4 张就是错的。

修法:

  1. 开启打印机「写卡失败则抛卡」功能(大部分工业机支持)
  2. 抛出的标签回收重新打
  3. 后端记录「被抛出的标签 EPC」黑名单,盘点时过滤
// 检测到抛卡 → 加入废标签表
if (result.getErrorCode().equals("TAG_REJECTED")) {
    rejectedTagService.save(result.getEpc());
    // 业务上:
    // 1. 该资产标签状态置为「待重打」
    // 2. 操作员界面提示「第 X 张抛卡,请取出重打」
}

坑 4:碳带类型和标签材质不匹配

打印机的碳带有三种:

  • 蜡基碳带:便宜,打印纸张类标签
  • 树脂基碳带:贵,打印 PET / 合成纸
  • 混合基碳带:介于两者之间

如果用蜡基碳带打印 PET 合成纸,条码扫不出来——墨水附着不牢。

坑的表现:打印测试样张没问题,但贴到资产上一个月后,条码褪色扫不到。

修法:

// 模板里强制标注碳带类型
export interface LabelTemplate {
  ribbonType: 'WAX' | 'RESIN' | 'MIXED'  // 必填
}

// 打印前校验
function validateTemplate(template: LabelTemplate) {
  if (template.material === 'PET' && template.ribbonType === 'WAX') {
    throw new Error('PET 标签必须使用 RESIN 碳带,否则条码易褪色')
  }
}

坑 5:标签偏移(Print Offset)

坑的表现:模板在预览里看着完美,但实际打印出来整体偏移 3~5mm。条码下方被切掉一部分。

根因:打印机对「标签起始位置」有自动校准(Auto Calibration),但校准一次后,后续如果换了一批厚度不同的标签,会重新校准。两次校准之间的偏差就是偏移。

修法:

  1. 每批新标签入库,先做一次手动校准
  2. 不要混批使用:同一卷标签用完再开新卷
  3. 工业级打印机建议开启「强制校准模式」
public void calibrateBeforePrint() {
    // 发送校准命令
    printer.sendRawCommand("~JC");  // ZPL 校准指令
    Thread.sleep(2000);            // 等校准完成
}

坑 6:跨平台字体兼容

后端把中文标签内容编译成 EPL/ZPL 命令时,中文字符不是直接发送 UTF-8。ZPL 默认用 GB18030 或 UTF-16BE 编码中文。

坑的表现:PC 上生成的 EPL 命令拷到打印机,打印出来中文变乱码。

修法:

// 中文编码转换
public byte[] encodeChinese(String content, String printerEncoding) {
    switch (printerEncoding) {
        case "GB18030":
            return content.getBytes(Charset.forName("GB18030"));
        case "UTF-16BE":
            // UTF-16BE + ZPL 特定指令
            byte[] unicode = content.getBytes(StandardCharsets.UTF_16BE);
            return prependUtf16Indicator(unicode);
        case "UTF-8":
            return content.getBytes(StandardCharsets.UTF_8);
        default:
            return content.getBytes(Charset.forName("GB18030"));  // 兜底
    }
}

关键:打印机的「中文编码模式」需要在打印前用 ^CI 指令设置,并且和后端编码必须一致。

坑 7:批量打印的内存溢出

5000 张标签一次性发给打印机,部分老型号打印机只支持 256KB 命令缓冲区。

坑的表现:打印前 100 张正常,到第 101 张时打印机无响应,必须重启。

修法:

public void batchPrint(List<AssetLabelDTO> labels) {
    int batchSize = 50;  // 每批最多 50 张

    for (int i = 0; i < labels.size(); i += batchSize) {
        List<AssetLabelDTO> batch = labels.subList(i, Math.min(i + batchSize, labels.size()));
        String combinedCmd = batch.stream()
            .map(this::compileLabelCommand)
            .collect(Collectors.joining("\n"));

        printer.printRaw(combinedCmd);

        // 关键:每批之间等待打印机反馈
        waitForPrinterReady();
    }
}

waitForPrinterReady() 必须等打印机返回「READY」状态,再发下一批——否则还是溢出。

坑 8:RFID 模块温度过高保护

工业级 RFID 标签打印机连续工作 30 分钟后,写卡模块温度会升高。部分厂商的写卡模块在温度 > 65℃ 时会自动停写,但打印动作继续——这就是「打印成功但写入失败」的另一大来源。

修法:

  1. 操作员界面实时显示打印机温度(通过 ~HS 指令查询)
  2. 温度超过 55℃ 时提示「请暂停 5 分钟散热」
  3. 现场部署时给打印机留出散热空间(背面至少 10cm 空隙)
public void checkTemperatureBeforePrint() {
    PrinterStatus status = printer.getStatus();
    if (status.getRfidTemp() > 55) {
        throw new BusinessException(
            "RFID 模块温度过高(" + status.getRfidTemp() + "℃),请暂停后再打印"
        );
    }
}

七、闭环联动:标签的生命周期

打通写入侧后,标签就成了资产的全生命周期载体:

[ 资产创建 ]
    │  生成资产编号 ASSET-2024-001234
    ▼
[ 打印标签 ] (RFID 标签打印机)
    │  写入 EPC = ASSET-2024-001234
    │  写入 User = {loc: 仓库A, own: 张三, sts: 在库}
    ▼
[ 贴标入库 ]
    │  PDA 扫描 EPC 入库
    ▼
[ 资产领用 ] (User 区原地更新)
    │  User = {loc: 车间B, own: 李四, sts: 在用}
    ▼
[ 季度盘点 ] (PDA 读取 EPC + User)
    │  比对账实,差异自动生成盘盈/盘亏单
    ▼
[ 资产转移 ] (User 区再次更新)
    ▼
[ 资产报废 ] (EPC 区标记销毁状态)
    │  EPC 高 8 位写 0xFF,标签「逻辑死亡」
    ▼
[ 标签回收 ] (从报废资产上撕下)
    │  重新写 EPC 给新资产

这套闭环的关键是:EPC 跟随资产编号,User 区跟随状态。盘点时 PDA 读到 EPC → 查系统资产表 → 比对 User 区的位置/责任人是否一致 → 不一致就触发盘亏单。


八、给后来人的 6 条建议

  1. 选工业级打印机之前,先确认 UHF 写卡模块是标配,桌面级多半是选配
  2. EPC 长度全项目统一(96 bit 或 128 bit),不要混用
  3. 写入后立刻回读校验,这是发现「假成功」的唯一手段
  4. 碳带和标签材质必须匹配,这是条码褪色的根因
  5. 中文编码(GB18030 / UTF-16BE)和打印机 ^CI 指令必须配对
  6. 批量打印每 50 张等一次 READY 状态,避免老打印机缓冲区溢出

九、关于首码 EAM

首码 EAM 是一套面向中大型企业的资产/备件一体化管理 SaaS,覆盖:

  • 资产全生命周期(采购 → 入库 → 领用 → 转移 → 盘点 → 报废)
  • RFID 标签打印 + RFID 盘点一体化(本文主题)
  • 备件批次件 + 序列号件混合管理
  • BPM 流程审批
  • PC 端 + 移动端 App(H5 / 微信小程序 / 原生 App)
  • 三语言国际化(简中 / 繁中 / 英文)
  • 国密 SM2 加密 + 多租户数据隔离

技术栈:Vue 3 + TypeScript + Vite + uni-app + Spring Boot + Spring Cloud + Nacos。

后续会写系列文章拆解 PDA 扫描服务统一接入、国密 SM2 接入实战、Vue2 → Vue3 迁移避坑清单 等模块,欢迎评论区告诉我你最想看哪一篇。


如果这篇文章帮你少踩了几个坑,欢迎点赞 / 收藏 / 关注,你的支持是我写下去的最大动力。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。