安付捷支付系统,已完成如下云喇叭、云打印对接工作:
  • 云喇叭:智谷物联、博实结、品生
  • 云打印:智谷物联、博实结、飞鹅

一、表结构

​ 云喇叭、云打印表结构通用

-- 设备厂商配置表

DROP TABLE IF EXISTS `t_device_provide_config`;

CREATE TABLE `t_device_provide_config` (

  `config_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '厂商配置ID',

  `config_desc` VARCHAR(32) NOT NULL COMMENT '厂商配置备注信息, 会在商户侧进行回显',

  `device_type` TINYINT(6) NOT NULL COMMENT '设备类型: 1-云喇叭, 2-云打印, 3-扫码pos',

  `provider` VARCHAR(20) NOT NULL COMMENT '设备厂商: zgwl-智谷物联, bsj-博实结, fe-飞鹅, ps-品生',

  `app_id` VARCHAR(64) COMMENT '厂商配置参数appId(扫码POS定义唯一appId)',

  `provider_params` TEXT COMMENT '厂商配置参数,json字符串',

  `state` TINYINT(6) NOT NULL DEFAULT 1 COMMENT '状态: 0-停用,1-启用',

  `created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',

  `updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',

  PRIMARY KEY (`config_id`),

  UNIQUE KEY (`app_id`)

) ENGINE=INNODB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COMMENT='设备厂商配置表';





-- 商户门店设备配置表

DROP TABLE IF EXISTS `t_mch_store_device`;

CREATE TABLE `t_mch_store_device` (

  `device_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '设备ID',

  `device_name` VARCHAR(128) NOT NULL COMMENT '设备名称',

  `batch_id` VARCHAR(64) COMMENT '批次号',

  `config_id` BIGINT(20) NOT NULL COMMENT '关联厂商配置ID',

  `device_type` TINYINT(6) NOT NULL COMMENT '设备类型: 1-云喇叭, 2-云打印, 3-扫码POS',

  `provider` VARCHAR(20) NOT NULL COMMENT '设备厂商:参考配置表',

  `device_no` VARCHAR(128) NOT NULL COMMENT '设备号',

  `device_params` TEXT NOT NULL COMMENT '设备参数,json字符串',

  `biz_config_params` TEXT COMMENT '业务配置参数,json字符串',

  `store_id` BIGINT(20) DEFAULT NULL COMMENT '门店ID',

  `mch_no` VARCHAR(64) DEFAULT NULL COMMENT '商户号',

  `agent_no` VARCHAR(64) DEFAULT NULL COMMENT '代理商号',

  `state` TINYINT(6) NOT NULL DEFAULT 1 COMMENT '状态: 0-停用,1-启用',

  `bind_state` TINYINT(6) NOT NULL DEFAULT 0 COMMENT '商户绑定状态: 0-未绑定,1-已绑定',

  `created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',

  `updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',

  PRIMARY KEY (`device_id`),

  UNIQUE KEY `IDX_Provider_Type_DeviceNo` (`provider`, `device_type`, `device_no`)

) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COMMENT='商户门店设备配置表';

二、后端接口编码

1.1 > 添加设备参数配置model
1.1.1 命名方式为:厂商首字母 + Speaker/Printer + Params

云喇叭、云打印两种设备同时对接且参数配置一致情况下,可省略Speaker/Printer,如:智谷物联—-ZgwlParams。

1.1.2 在目录:

com.jeequan.jeepay.core.model.device(core项目),添加常量类,包含三个参数:providerParams、deviceParams、bizConfigParams,分别为厂商参数、设备参数、业务参数

1.2 > 设备参数配置

配置接口在manage、agent、merchant项目的MchStoreDeviceController内。包括新增、修改、划拨/收回、绑定/解绑、测试等接口,参考操作手册。

如果设备参数只有一个属性:设备号,则无需进行修改。

特殊情况如飞鹅,需通过接口将设备信息注册,此时在新增、修改设备时需同步处理。

1.3 > 设备对接
1.3.1 ISpeakerService为云喇叭接口定义
public interface ISpeakerService {



    /** 调起播报 **/

    void send(JSONObject deviceParams, PayOrderInfo4Device speakPayOrderInfo) throws BizException;



    /** 自定义语音播报 **/

    void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device speakPayOrderInfo) throws BizException;



}

覆写send()函数: 实现播报推送

覆写sendCustomMsg()函数:厂商喇叭自定义消息推送

1.3.2 IPrinterService为云打印接口定义
public interface IPrinterService {



    /** 调起打印

     * @param deviceParams

     * @param printPayOrderInfo

     * **/

    void send(JSONObject deviceParams, PayOrderInfo4Device printPayOrderInfo) throws BizException;



    /** 添加打印机

     * @param deviceParams

     * **/

    String addPrinter(JSONObject deviceParams);



    /** 修改打印机

     * @param deviceParams

     * **/

    String editPrinter(JSONObject deviceParams);



    /** 清除打印队列

     * @param deviceParams

     * **/

    String clearPrinter(JSONObject deviceParams);



}

覆写send()函数: 实现打印推送

覆写addPrinter()函数:实现在厂商端注册打印机

覆写editPrinter()函数:实现在厂商端修改打印机

覆写clearPrinter()函数:实现在厂商端清除打印队列

1.3.3 以博实结云喇叭设备为例:

实现ISpeakerService接口,覆写send()函数: 实现播报推送。send()函数为调用厂商设备逻辑,异常抛出BizException即可

@Slf4j

@Service

public class BsjSpeakerService implements ISpeakerService {



    private static final String REQ_URL = "https://ioe.car900.com/v1/openApi/dev/controlDevice.json";



    @Override

    public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException {



        JSONObject bsjJSON = new JSONObject();

        bsjJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams")));

        bsjJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams")));



        // 博实结参数

        BsjParams bsjParams = JSON.parseObject(bsjJSON.toJSONString(), BsjParams.class);



        JSONObject resJSON = speak(bsjParams, payOrderInfo);

        if (resJSON == null) {

            throw new BizException("请求失败");

        }

        if (resJSON.getIntValue("code") != 0) {

            throw new BizException(resJSON.getString("msg"));

        }

    }



    @Override

    public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) {

        return;

    }



    /**

     * 发起请求

     */

    private JSONObject speak(BsjParams bsjParams, PayOrderInfo4Device payOrderInfo) throws BizException {



        JSONObject reqParams = new JSONObject();

        reqParams.put("money", AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()));  // 金额

        reqParams.put("broadCastType", getPayTypeCode(payOrderInfo.getIfCode()));  //1-收款成功   2-支付宝收款成功  3-微信收款成功



        return BsjUtil.get(REQ_URL, bsjParams, reqParams);

    }





    /**

     * 支付方式

     */

    private int getPayTypeCode(String ifCode) {

        if (StringUtils.isBlank(ifCode)) {

            return 1;

        }



        if (CS.IF_CODE.WXPAY.equals(ifCode)) { // 微信

            return 2;

        }else if (CS.IF_CODE.ALIPAY.equals(ifCode)) { // 支付宝

            return 3;

        }else {

            return 1;

        }

    }



}

三、前端配置编码

1.1 > 厂商参数配置
1.1.1 只有manage项目有厂商参数配置

在项目的src\views\device下,SpeakerList、PrinterList分别对应云喇叭、云打印列表,一般无需修改。

CommonAddOrEdit.vue文件为新增/修改主入口。

provider目录为厂商参数配置组件

mchstoredevice目录为设备列表及相关组件

1.1.2 CommonAddOrEdit.vue文件为新增/修改组件

参考以下代码添加要对接的厂商,命名:provider为厂商首字母小写,providerName为厂商名称

  /** 定义云喇叭厂商 **/

  const speakerProviderList = [

    { provider: 'zgwl', providerName: '智谷物联' },

    { provider: 'bsj', providerName: '博实结' },

    { provider: 'ps', providerName: '品生' }

  ]

  /** 定义云打印厂商 **/

  const printerProviderList = [

    { provider: 'fe', providerName: '飞鹅' },

    { provider: 'zgwl', providerName: '智谷物联' },

    { provider: 'bsj', providerName: '博实结' }

  ]

参考以下代码添加厂商参数配置组件,命名为:厂商首字母 + Config

  /** 定义厂商参数配置组件 **/

  const allConfigPage = {

    'bsj': BsjConfig,

    'zgwl': ZgwlConfig,

    'fe': FeConfig,

    'ps': PsConfig

  }
1.1.3 以博实结厂商参数配置组件为例:
<template>

  <a-form v-if="vdata.currentConfig" ref="formRef" :model="vdata.currentConfig" layout="vertical" :rules="vdata.formRules">

    <a-divider orientation="left">

      <a-tag color="#FF4B33">博实结设备参数配置</a-tag>

    </a-divider>

    <a-row justify="space-between" type="flex">

      <a-col :span="11">

        <a-form-item label="appId" name="appId">

          <a-input v-model:value="vdata.currentConfig.appId" placeholder="请输入" />

        </a-form-item>

      </a-col>

      <a-col :span="11">

        <a-form-item label="appSecret" name="appSecret">

          <a-input v-model:value="vdata.currentConfig.appSecret" placeholder="请输入" />

        </a-form-item>

      </a-col>

      <a-col :span="11">

        <a-form-item label="userCode" name="userCode">

          <a-input v-model:value="vdata.currentConfig.userCode" placeholder="请输入" />

        </a-form-item>

      </a-col>

    </a-row>

  </a-form>

</template>



<script lang="ts" setup>

import {reactive, ref, defineExpose} from 'vue'



  // 当前的form

  const formRef = ref()



  const  vdata = reactive({

    // 配置对象

    currentConfig: {} as any,

    // 表单规则

    formRules: {

      appId: [{ required: true, message: '请输入appId', trigger: 'blur' }],

      appSecret: [{ required: true, message: '请输入appSecret', trigger: 'blur' }],

      userCode: [{ required: true, message: '请输入userCode', trigger: 'blur' }]

    }

  })



  // 对外提供的页面的渲染函数 ( ifDefineArray = 接口的配置定义项数组,  currentConfig = 当前配置项 )

function pageRender(currentConfig: any){

  // 赋值

  vdata.currentConfig = currentConfig



  // 重置form验证

  if (formRef.value !== undefined && formRef.value !== null) {

    formRef.value.resetFields()

  }

}



// 对外提供的获取配置参数函数 (返回JSON类型)

function getConfigParams(){

  return formRef.value.validate().then( () => {

    return vdata.currentConfig

  })

}



defineExpose({ getConfigParams, pageRender })



</script>

文档更新时间: 2026-02 作者:LK