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

一、表结构

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

-- 设备厂商配置表
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>
文档更新时间: 2023-08-18 17:04   作者:大森林