kode/miniapp

多平台小程序、公众号、企业号统一接入 SDK(微信、支付宝、抖音、百度、QQ、企业微信、钉钉、飞书)

Maintainers

Package info

github.com/kodephp/miniapp

Homepage

pkg:composer/kode/miniapp

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.7.1 2026-04-26 19:14 UTC

This package is auto-updated.

Last update: 2026-04-26 19:17:38 UTC


README

多平台小程序、公众号、企业号统一接入 SDK。

License PHP Version

特性

  • 多平台统一接入:一套代码对接微信、支付宝、抖音、百度、QQ、企业微信、钉钉、飞书
  • PHP 8.2+ 现代化:使用 readonly、enum、match、构造函数属性提升等新特性
  • 企业级能力:除 C端小程序外,完整支持企业微信、钉钉、飞书的通讯录、审批、消息推送
  • 服务端消息处理:统一处理各平台的消息推送和事件回调
  • 支付桥接:内置基础支付能力,同时可桥接到 kode/pays 企业级聚合支付 SDK
  • 工具桥接:内置基础工具类,同时可桥接到 kode/tools 企业级工具包
  • 异常桥接:内置异常体系,同时可桥接到 kode/exception 统一异常处理组件
  • Kode 生态兼容:与 kode/pays、kode/tools、kode/exception、kode/cache、kode/event 等包无缝协作

Kode 生态关联

Kode MiniApp 是 Kode 生态的重要组成部分,与以下包可协同工作:

包名 类型 说明
kode/pays suggest 企业级多平台聚合支付 SDK,安装后可通过 payBridge() 获取更强支付能力
kode/tools suggest PHP 通用工具包(加解密、二维码、消息体等),安装后自动优先使用
kode/exception suggest 统一异常处理组件,安装后扩展异常码体系
kode/cache suggest 高性能缓存组件,支持 Redis/Memcached 等
kode/event suggest 轻量级事件编排库,支持异步事件处理
# 安装核心包
composer require kode/miniapp

# 按需安装生态包(推荐)
composer require kode/pays      # 企业级支付
composer require kode/tools     # 工具包
composer require kode/exception # 异常处理
composer require kode/cache     # 缓存
composer require kode/event     # 事件

支持平台

平台 标识 类型 能力 详细文档
微信 wechat C端 登录、JS-SDK、用户、素材、菜单、客服、消息、订阅消息、小程序码、数据分析、支付、订单物流同步、内容安全、URL Scheme/Link、插件管理、直播、附近小程序、门店、卡券、摇一摇、发票、连Wi-Fi、微信小店、红包、广告、即时配送、搜一搜、动态消息、设备功能、云开发、服务端、回调通知 查看
支付宝 alipay C端 登录、支付、转账、账单、营销、会员、回调通知 查看
抖音 douyin C端 登录、支付、视频、评论 查看
百度 baidu C端 登录、支付、模板消息 查看
QQ qq C端 登录、支付 查看
微信企业号 wechat_work B端 认证、通讯录、部门管理、客户联系、外部联系人、标签、消息、审批、素材管理、应用管理、OA打卡汇报、会议室、公费电话、日程、收集表、微盘、上下游、会话存档、服务端、回调通知 查看
钉钉 dingtalk B端 认证、通讯录、消息、审批、群机器人、考勤、智能人事、日志、项目、智能工作流 查看
飞书 lark B端 认证、通讯录、消息、审批、审批定义、多维表格、文档、日历、任务、知识库、邮件 查看

安装

composer require kode/miniapp

快速开始

use Kode\MiniApp\Kernel;

$kernel = new Kernel([
    'wechat' => [
        'app_id'  => 'wx123...',
        'secret'  => 'abc...',
        'mch_id'  => '123...',
    ],
    'alipay' => [
        'app_id'      => '2024...',
        'private_key' => '...',
        'public_key'  => '...',
    ],
]);

// 微信登录
$session = $kernel->wechat()->app()->auth()->session($code);

// 支付宝下单(内置基础支付)
$order = $kernel->alipay()->app()->pay()->create([
    'out_trade_no' => 'ORDER_001',
    'total_amount' => '99.99',
    'subject'      => '测试商品',
]);

// 如安装了 kode/pays,可使用企业级支付能力
$pay = $kernel->wechat()->app()->payBridge();
if ($pay !== null) {
    // 使用 kode/pays 的企业级支付能力
    $pay->order([...]);
}

架构设计

Kernel(门面)
  └── Provider(平台入口)
        └── App(应用实例)
              ├── Auth(认证)
              ├── Pay(基础支付)
              ├── PayBridge(桥接 kode/pays 企业级支付)
              ├── Message(消息)
              ├── Contact(通讯录)
              ├── Approval(审批)
              ├── Jssdk(JS-SDK)
              ├── Server(服务端处理器)
              └── Notify(回调通知处理器)

核心组件

  • Kernel:统一门面,通过 $kernel->wechat()$kernel->dingtalk() 等快捷方法获取平台实例
  • Provider:平台入口,管理配置和 HTTP 客户端,支持多应用实例
  • App:应用实例,聚合该平台的所有能力模块
  • Server:服务端消息处理器,统一处理各平台的消息推送和事件回调
  • Message:消息构造器,构造被动回复消息
  • Notify:支付回调通知处理器,自动验签并触发业务逻辑
  • PayBridge:支付桥接器,自动检测并桥接到 kode/pays 企业级支付 SDK
  • ToolsBridge:工具桥接器,自动检测并优先使用 kode/tools 工具类
  • ExceptionBridge:异常桥接器,自动检测并扩展 kode/exception 异常码体系

各平台详细文档

每个平台都有独立的详细使用文档,包含配置说明和各功能模块的完整使用示例:

平台 文档路径 说明
微信 docs/wechat.md 公众号/小程序,30+ 功能模块
支付宝 docs/alipay.md 小程序/生活号,支付/转账/营销
抖音 docs/douyin.md 小程序,视频管理/支付
百度 docs/baidu.md 小程序,登录/支付/模板消息
QQ docs/qq.md 小程序,登录/支付
微信企业号 docs/wechat-work.md 企业微信,通讯录/审批/客户联系/会话存档
钉钉 docs/dingtalk.md 企业办公,通讯录/审批/考勤/智能人事
飞书 docs/lark.md 企业办公,通讯录/审批/多维表格/文档/日历

各平台详细配置

微信

'wechat' => [
    'app_id'     => 'wx1234567890',
    'secret'     => 'your-secret',
    'mch_id'     => '1234567890',
    'api_v3_key' => 'your-api-v3-key',
    'cert_path'  => '/path/to/apiclient_cert.pem',
    'key_path'   => '/path/to/apiclient_key.pem',
    'token'      => 'your-token',
    'aes_key'    => 'your-aes-key',
]

支付宝

'alipay' => [
    'app_id'      => '2024...',
    'private_key' => 'your-private-key',
    'public_key'  => 'alipay-public-key',
    'sandbox'     => false,
]

抖音

'douyin' => [
    'app_id'    => 'tt...',
    'secret'    => 'your-secret',
    'salt'      => 'your-salt',
    'mch_id'    => 'your-mch-id',
    'pay_token' => 'your-pay-token',
]

百度

'baidu' => [
    'app_id'  => 'your-app-id',
    'secret'  => 'your-secret',
    'deal_id' => 'your-deal-id',
    'pay_key' => 'your-pay-key',
]

QQ

'qq' => [
    'app_id'  => 'your-app-id',
    'secret'  => 'your-secret',
]

QQ

$app = $kernel->qq()->app();

// 登录
$user = $app->auth()->user($code);

// 支付
$app->pay()->unifiedOrder(['body' => '商品描述', 'out_trade_no' => 'ORDER001', 'total_fee' => 100, 'spbill_create_ip' => '127.0.0.1', 'notify_url' => 'https://example.com/notify', 'trade_type' => 'MINIAPP']);
$app->pay()->orderQuery('ORDER001');
$app->pay()->closeOrder('ORDER001');
$app->pay()->refund(['out_trade_no' => 'ORDER001', 'out_refund_no' => 'REFUND001', 'total_fee' => 100, 'refund_fee' => 50]);

微信企业号

'wechat_work' => [
    'corp_id'        => 'ww...',
    'secret'         => 'your-secret',
    'agent_id'       => '1000002',
    'contact_secret' => 'contact-secret',
    'token'          => 'your-token',
    'aes_key'        => 'your-aes-key',
]

钉钉

'dingtalk' => [
    'app_id'     => 'ding...',
    'app_key'    => 'your-app-key',
    'app_secret' => 'your-app-secret',
    'agent_id'   => '123456',
]

飞书

'lark' => [
    'app_id'             => 'cli_...',
    'secret'             => 'your-secret',
    'is_feishu'          => true,  // true=国内版, false=国际版
    'encrypt_key'        => 'your-encrypt-key',
    'verification_token' => 'your-token',
]

平台能力使用

微信

$app = $kernel->wechat()->app();

// 小程序登录
$session = $app->auth()->session($code);

// 获取 AccessToken
$token = $app->auth()->token();

// JS-SDK 配置
$jssdk = $app->jssdk()->config($url, ['updateAppMessageShareData']);

// 用户管理
$users = $app->user()->list();
$userInfo = $app->user()->info($openid);
$app->user()->remark($openid, 'VIP用户');

// 素材管理
$media = $app->media()->upload('image', '/path/to/image.jpg');
$app->media()->uploadNews([['title' => '标题', 'content' => '内容']]);
$app->media()->delete($mediaId);

// 菜单管理
$app->menu()->create([
    ['type' => 'click', 'name' => '今日歌曲', 'key' => 'V1001_TODAY_MUSIC'],
    ['type' => 'view', 'name' => '搜索', 'url' => 'http://www.soso.com/'],
]);
$app->menu()->delete();

// 客服消息
$app->customerService()->text($openid, '您好!');
$app->customerService()->image($openid, $mediaId);
$app->customerService()->news($openid, [['title' => '标题', 'description' => '描述', 'url' => 'https://example.com', 'picurl' => 'https://example.com/pic.jpg']]);
$app->customerService()->miniProgramPage($openid, '标题', $appid, 'pages/index/index', $thumbMediaId);
$app->customerService()->menu($openid, '请选择', [['id' => '1', 'content' => '选项1']], '感谢使用');

// 客服管理
$kfList = $app->customerService()->list();
$records = $app->customerService()->msgRecord(strtotime('-1 day'), time());
$app->customerService()->invite($openid, 'kf_account@gh_xxx');

// 发送订阅消息(小程序)
$app->message()->sendSubscribe($openid, $templateId, ['thing1' => ['value' => '测试']]);

// 发送模板消息(公众号)
$app->message()->sendTemplate($openid, $templateId, '', ['thing1' => ['value' => '测试']]);

// 小程序码生成
$qrCode = $app->miniProgramCode()->getUnlimited(['scene' => 'id=123', 'page' => 'pages/index/index']);
file_put_contents('/tmp/qrcode.png', $qrCode);

// 数据分析
$retain = $app->dataAnalysis()->getDailyRetain('2024-01-01', '2024-01-07');
$trend  = $app->dataAnalysis()->getDailyVisitTrend('2024-01-01', '2024-01-07');
$portrait = $app->dataAnalysis()->getUserPortrait('2024-01-01', '2024-01-07');

// 订阅消息管理(小程序)
$app->subscribeMessage()->send($openid, $templateId, ['thing1' => ['value' => '测试']]);
$templates = $app->subscribeMessage()->getTemplateList();
$app->subscribeMessage()->deleteTemplate($priTmplId);

// 基础支付
$app->pay()->order([
    'description'  => '商品描述',
    'out_trade_no' => 'ORDER_001',
    'amount'       => ['total' => 100],
    'payer'        => ['openid' => $openid],
]);

// 查询订单
$app->pay()->query('ORDER_001');

// 关闭订单
$app->pay()->close('ORDER_001');

// 申请退款
$app->pay()->refund([
    'out_trade_no'  => 'ORDER_001',
    'out_refund_no' => 'REFUND_001',
    'reason'        => '用户申请退款',
    'amount'        => [
        'refund'   => 100,
        'total'    => 100,
        'currency' => 'CNY',
    ],
]);

// 查询退款
$app->pay()->queryRefund('REFUND_001');

// 申请账单
$app->pay()->tradeBill('2024-01-01');
$app->pay()->fundBill('2024-01-01');

// 小程序订单物流同步(发货)
// 标准快递发货
$app->shipping()->express(
    'ORDER_001',
    '1',
    [
        [
            'tracking_no'   => 'SF1234567890',
            'express_company' => '顺丰速运',
            'item_desc'     => '商品描述',
        ],
    ],
    $payerOpenid
);

// 无需物流发货(虚拟商品/服务)
$app->shipping()->noShipping('ORDER_001', '1', $payerOpenid);

// 同城配送发货
$app->shipping()->sameCity('ORDER_001', '1', [
    ['tracking_no' => 'RIDER_001', 'express_company' => '同城配送', 'item_desc' => '商品描述'],
], $payerOpenid);

// 用户自提发货
$app->shipping()->selfPickup('ORDER_001', '1', [
    ['tracking_no' => 'PICKUP_001', 'express_company' => '用户自提', 'item_desc' => '商品描述'],
], $payerOpenid);

// 查询发货信息
$app->shipping()->getOrder('', 'ORDER_001');

// 确认收货提醒
$app->shipping()->notifyConfirmReceive('', 'ORDER_001');

// 设置消息跳转路径
$app->shipping()->setMsgJumpPath('pages/order/detail');

// 内容安全检测
$result = $app->security()->msgSecCheck('待检测文本内容');
$result = $app->security()->imgSecCheck('https://example.com/image.jpg');
$result = $app->security()->mediaCheckAsync('https://example.com/audio.mp3', 1);

// URL Scheme / URL Link(短信、邮件、微信外打开小程序)
$scheme = $app->urlLink()->generateScheme([
    'jump_wxa' => ['path' => '/pages/index/index', 'query' => 'id=123'],
]);
$link = $app->urlLink()->generateUrlLink([
    'path'  => '/pages/index/index',
    'query' => 'id=123',
]);
$shortLink = $app->urlLink()->generateShortLink('pages/index/index?id=123', '页面标题');

// 插件管理
$app->plugin()->applyPlugin('wx1234567890');
$plugins = $app->plugin()->list();
$app->plugin()->unbindPlugin('wx1234567890');

// 小程序直播
$app->live()->createRoom([
    'name'         => '直播间名称',
    'coverImg'     => 'https://example.com/cover.jpg',
    'startTime'    => time(),
    'endTime'      => time() + 7200,
    'anchorName'   => '主播名称',
    'anchorWechat' => 'anchor_wechat',
    'type'         => 1,
]);
$liveRooms = $app->live()->getLiveInfo();
$replay = $app->live()->getReplay($roomId);
$app->live()->addGoods($goodsInfo);
$app->live()->audit($goodsId);

// 附近小程序
$app->nearby()->addPoi(['related_name' => '门店名称', 'related_credential' => '营业执照号', 'related_address' => '地址', 'related_phone' => '电话']);
$app->nearby()->listPoi();
$app->nearby()->deletePoi($poiId);
$app->nearby()->setStatus($poiId, 1);

// 门店小程序
$app->store()->create(['name' => '门店名称', 'longitude' => '113.2644', 'latitude' => '23.1291', 'address' => '广州市天河区', 'phone' => '020-12345678']);
$app->store()->list();
$app->store()->get($poiId);
$app->store()->update(['poi_id' => $poiId, 'name' => '新门店名称']);
$app->store()->delete($poiId);

// 卡券
$app->card()->create(['card_type' => 'GROUPON', 'groupon' => ['base_info' => ['brand_name' => '商家名称'], 'deal_detail' => '优惠详情']]);
$app->card()->get($cardId);
$app->card()->consume('CODE123', $cardId);
$app->card()->list();

// 摇一摇
$app->shake()->applyDeviceId(10);
$app->shake()->addPage(['title' => '页面标题', 'description' => '描述', 'page_url' => 'https://example.com', 'comment' => '备注']);
$app->shake()->getShakeInfo($ticket);

// 发票
$app->invoice()->getAuthUrl(['s_pappid' => 'wx123', 'order_id' => 'ORDER001', 'money' => 100, 'timestamp' => time(), 'source' => 'web']);
$app->invoice()->makeOutInvoice(['wxopenid' => $openid, 'order_id' => 'ORDER001', 'card_id' => $cardId, 'card_ext' => '{}']);
$app->invoice()->queryInvoiceInfo($cardId, $encryptCode);

// 连Wi-Fi
$app->wifi()->addDevice(['shop_id' => 123, 'ssid' => 'MyWiFi', 'password' => 'password123']);
$app->wifi()->deviceList();
$app->wifi()->getQrcode(123);

// 微信小店(视频号电商)
$app->goods()->add(['title' => '商品标题', 'head_imgs' => ['https://example.com/img.jpg'], 'category_id' => 100]);
$app->goods()->list();
$app->goods()->get($productId);
$app->goods()->listing($productId);
$app->goods()->orderList();

// 红包
$app->redpack()->send(['send_name' => '商家名称', 're_openid' => $openid, 'total_amount' => 100, 'total_num' => 1, 'wishing' => '恭喜发财', 'act_name' => '活动名称', 'remark' => '备注']);
$app->redpack()->query('MCHBILLNO001');

// 广告
$app->ad()->createAdUnit(['ad_unit_name' => '广告单元1', 'ad_unit_type' => 1]);
$app->ad()->adUnitList();
$app->ad()->getData($adUnitId, '2024-01-01', '2024-01-31');

// 即时配送
$app->express()->deliveryList();
$app->express()->addOrder(['shopid' => 'SHOP001', 'shop_order_id' => 'ORDER001', 'shop_no' => '001', 'delivery_id' => 1, 'openid' => $openid, 'sender' => [], 'receiver' => [], 'cargo' => [], 'order_info' => []]);
$app->express()->cancelOrder(['shopid' => 'SHOP001', 'shop_order_id' => 'ORDER001', 'delivery_id' => 1, 'waybill_id' => 'WB001']);

// 搜一搜
$app->search()->submitPages(['pages/index/index', 'pages/detail/detail']);
$app->search()->getData('2024-01-01', '2024-01-31');

// 动态消息
$app->dynamicMessage()->createActivityId();
$app->dynamicMessage()->setUpdatableMsg(['activity_id' => $activityId, 'target_state' => 0, 'template_info' => ['parameter_list' => []]]);

// 设备功能
$app->device()->getQrcode([['id' => 'DEVICE001', 'mac' => '00:11:22:33:44:55', 'connect_protocol' => '3', 'auth_key' => '', 'close_strategy' => '1', 'conn_strategy' => '1', 'crypt_method' => '0', 'auth_ver' => '0', 'manu_mac_pos' => '-1', 'ser_mac_pos' => '-2', 'ble_simple_protocol' => '0']]);
$app->device()->authorize([['id' => 'DEVICE001', 'mac' => '00:11:22:33:44:55', 'connect_protocol' => '3', 'auth_key' => '', 'close_strategy' => '1', 'conn_strategy' => '1', 'crypt_method' => '0', 'auth_ver' => '0', 'manu_mac_pos' => '-1', 'ser_mac_pos' => '-2', 'ble_simple_protocol' => '0']]);
$app->device()->bind($ticket, $deviceId, $openid);
$app->device()->getStat($deviceId);

// 云开发
$app->cloudbase()->invokeFunction('myFunction', ['key' => 'value']);
$app->cloudbase()->databaseQuery(['env' => 'prod-env', 'query' => 'db.collection("users").get()']);
$app->cloudbase()->databaseAdd(['env' => 'prod-env', 'query' => 'db.collection("users").add({data:{name:"张三"}})']);
$app->cloudbase()->uploadFile('/path/to/file.jpg');

// 企业级支付(需安装 kode/pays)
$pay = $app->payBridge();
if ($pay !== null) {
    $pay->order([...]);
}

微信服务端消息处理

use Kode\MiniApp\Server\Message;

$server = $kernel->wechat()->app()->server();

$server->on('text', function (array $payload, $app) {
    return Message::toXml(Message::text('收到:' . $payload['Content'], $payload));
});

$server->on('subscribe', function (array $payload, $app) {
    return Message::toXml(Message::text('感谢关注!', $payload));
});

$response = $server->serve();
$response->send();

微信/支付宝支付回调通知

$notify = $kernel->wechat()->app()->notify();

$result = $notify
    ->onPaid(function (array $payload, $app) {
        // 处理支付成功逻辑
        $outTradeNo = $payload['out_trade_no'];
        // 更新订单状态...
    })
    ->onRefund(function (array $payload, $app) {
        // 处理退款通知
    })
    ->handle();

// 返回给微信/支付宝
if ($result['code'] === 'SUCCESS') {
    echo '<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>';
} else {
    echo '<xml><return_code><![CDATA[FAIL]]></return_code></xml>';
}

微信企业号

$app = $kernel->wechatWork()->app();

// 获取用户信息
$user = $app->auth()->user($code);
$userDetail = $app->auth()->userDetail($userId);

// 通讯录管理
$app->contact()->createUser(['userid' => 'zhangsan', 'name' => '张三']);
$departments = $app->contact()->departments();
$users = $app->contact()->departmentUsers(1);

// 标签管理
$app->tag()->create('新员工');
$app->tag()->addUsers(1, ['zhangsan']);
$tags = $app->tag()->list();

// 部门管理
$app->department()->create(['name' => '技术部', 'parentid' => 1]);
$departments = $app->department()->list();
$app->department()->update(['id' => 2, 'name' => '产品部']);
$app->department()->delete(2);

// 客户联系(外部联系人)
$followUsers = $app->externalContact()->getFollowUserList();
$customers = $app->externalContact()->list('zhangsan');
$detail = $app->externalContact()->get($externalUserid);
$app->externalContact()->addContactWay([
    'type' => 1,
    'scene' => 1,
    'style' => 1,
    'remark' => '渠道客户',
]);
$app->externalContact()->remark([
    'userid' => 'zhangsan',
    'external_userid' => $externalUserid,
    'remark' => 'VIP客户',
]);

// 客户群管理
$groups = $app->externalContact()->groupChatList();
$groupDetail = $app->externalContact()->groupChatGet('chat_id');

// 离职继承
$unassigned = $app->externalContact()->getUnassignedList();
$app->externalContact()->transfer([
    'external_userid' => $externalUserid,
    'handover_userid' => 'zhangsan',
    'takeover_userid' => 'lisi',
]);

// 客户标签
$tags = $app->externalContact()->getCorpTagList();
$app->externalContact()->addCorpTag([
    'group_name' => '客户等级',
    'tag' => [['name' => 'VIP']],
]);

// 素材管理
$media = $app->media()->upload('image', '/path/to/image.jpg');
$app->media()->uploadImg('/path/to/image.jpg');
$app->media()->uploadAttachment('image', '/path/to/image.jpg', 'image');

// 应用管理
$app->agent()->get(1000002);
$app->agent()->list();
$app->agent()->set(['agentid' => 1000002, 'report_location_flag' => 0]);

// 消息推送
$app->message()->text('Hello World', ['zhangsan']);
$app->message()->markdown('# 标题\n内容', ['zhangsan']);
$app->message()->news([['title' => '标题', 'description' => '描述', 'url' => 'https://example.com', 'picurl' => 'https://example.com/pic.jpg']], ['zhangsan']);
$app->message()->file($mediaId, ['zhangsan']);
$app->message()->image($mediaId, ['zhangsan']);
$app->message()->voice($mediaId, ['zhangsan']);
$app->message()->video($mediaId, '标题', '描述', ['zhangsan']);
$app->message()->textCard('标题', '描述内容', 'https://example.com', ['zhangsan'], '查看详情');
$app->message()->miniProgramNotice([
    'appid'             => 'wx123',
    'page'              => 'pages/index',
    'title'             => '通知标题',
    'description'       => '通知内容',
    'emphasis_first_item' => true,
    'content_item'      => [['key' => '订单号', 'value' => '123456']],
], ['zhangsan']);

// 审批
$app->approval()->template($templateId);
$app->approval()->apply($approvalData);
$app->approval()->detail($spNo);

// OA 打卡汇报
$app->oa()->getCheckinOption(time(), ['zhangsan']);
$app->oa()->getCheckinData(strtotime('-7 days'), time(), ['zhangsan']);
$app->oa()->getCheckinDayData(strtotime('-7 days'), time(), ['zhangsan']);
$app->oa()->getCheckinMonthData(strtotime('-30 days'), time(), ['zhangsan']);
$app->oa()->getJournalRecordList(strtotime('-7 days'), time());
$app->oa()->getJournalStat(strtotime('-7 days'), time());

// 会议室管理
$app->meeting()->create(['name' => '会议室A', 'capacity' => 10, 'city' => '深圳']);
$app->meeting()->list();
$app->meeting()->getBookingInfo($meetingRoomId, '2024-01-01T09:00:00', '2024-01-01T18:00:00');
$app->meeting()->book(['meetingroom_id' => $meetingRoomId, 'subject' => '周会', 'start_time' => time(), 'end_time' => time() + 3600, 'booker' => 'zhangsan']);
$app->meeting()->cancelBook($meetingId);

// 公费电话
$app->dial()->call(['zhangsan'], 'lisi', '拨打原因');
$app->dial()->records(strtotime('-7 days'), time());

// 日程管理
$app->schedule()->add(['organizer' => 'zhangsan', 'start_time' => time(), 'end_time' => time() + 3600, 'attendees' => [['userid' => 'lisi']], 'summary' => '周会', 'description' => '讨论下周计划']);
$app->schedule()->get($scheduleId);
$app->schedule()->update(['schedule_id' => $scheduleId, 'summary' => '更新后的标题']);
$app->schedule()->delete($scheduleId);

// 收集表
$app->collect()->create(['form_title' => '入职信息收集', 'form_desc' => '请填写个人信息', 'form_question' => [['question_id' => 1, 'title' => '姓名', 'question_type' => 'text']]]);
$app->collect()->get($formid);
$app->collect()->getAnswer($formid);

// 微盘
$app->drive()->spaceCreate(['space_name' => '项目资料', 'auth_list' => ['userid' => 'zhangsan', 'auth' => 1]]);
$app->drive()->spaceInfo($spaceId);
$app->drive()->fileList($spaceId);
$app->drive()->fileDownload($spaceId, $fileId);

// 上下游/互联企业
$app->corpGroup()->getAppShareInfo();
$app->corpGroup()->unionidToExternalUserid($unionid, $openid);

// 会话内容存档
$app->msghub()->getPermitUserList();
$app->msghub()->getSingleAgreeStatus(['zhangsan', 'lisi']);
$app->msghub()->getRoomAgreeStatus(['ROOM001']);
$app->msghub()->getRoomInfo('ROOM001');

// 服务端消息处理
$server = $app->server();
$server->on('text', fn($payload) => 'success');
$server->serve()->send();

钉钉

$app = $kernel->dingtalk()->app();

// 获取用户信息
$user = $app->auth()->user($code);
$detail = $app->auth()->userDetail($userId);

// 通讯录
$app->contact()->createUser(['userid' => 'zhangsan', 'name' => '张三']);
$departments = $app->contact()->departments();

// 消息
$app->message()->text('Hello', ['zhangsan']);
$app->message()->markdown('标题', '内容', ['zhangsan']);
$app->message()->image($mediaId, ['zhangsan']);
$app->message()->file($mediaId, ['zhangsan']);
$app->message()->link('标题', '内容', 'https://example.com', 'https://example.com/pic.jpg', ['zhangsan']);
$app->message()->oa($oaContent, ['zhangsan']);
$app->message()->actionCard([
    'title'          => '标题',
    'markdown'       => '内容',
    'single_title'   => '查看详情',
    'single_url'     => 'https://example.com',
], ['zhangsan']);

// 审批
$app->approval()->instance($processInstanceId);
$app->approval()->create($data);

// 群机器人消息
$app->robot()->text($webhook, $secret, 'Hello 钉钉');
$app->robot()->markdown($webhook, $secret, '标题', '**加粗内容**');
$app->robot()->link($webhook, $secret, '标题', '内容', 'https://example.com');
$app->robot()->actionCard($webhook, $secret, [
    'title' => '标题',
    'markdown' => '内容',
    'singleTitle' => '查看详情',
    'singleURL' => 'https://example.com',
]);

// 考勤管理
$app->attendance()->list('2024-01-01 00:00:00', '2024-01-31 23:59:59', ['zhangsan']);
$app->attendance()->listSchedule(['zhangsan'], '2024-01-01');
$app->attendance()->getGroup(1);
$app->attendance()->getRecord('2024-01-01 00:00:00', '2024-01-31 23:59:59', ['zhangsan']);

// 智能人事
$app->hrm()->getEmpRosterDetail(['zhangsan']);
$app->hrm()->queryOnJob();
$app->hrm()->queryPreEntry();
$app->hrm()->queryDimission();

// 日志管理
$app->report()->list('2024-01-01 00:00:00', '2024-01-31 23:59:59');
$app->report()->get($reportId);
$app->report()->templateList();

// 项目管理
$app->project()->create(['name' => '新项目', 'manager_uid' => 'zhangsan', 'description' => '项目描述']);
$app->project()->get($projectId);
$app->project()->list();
$app->project()->addTask($projectId, ['content' => '完成需求分析', 'executor_uid' => 'lisi']);
$app->project()->taskList($projectId);

// 智能工作流
$app->workflow()->createInstance(['process_code' => 'PROC-XXX', 'originator_user_id' => 'zhangsan', 'dept_id' => 1, 'form_component_values' => [['name' => '标题', 'value' => '请假申请']]]);
$app->workflow()->getInstance($processInstanceId);
$app->workflow()->templateList();
$app->workflow()->instanceList(['process_code' => 'PROC-XXX', 'start_time' => strtotime('-7 days') * 1000]);
$app->workflow()->terminateInstance($processInstanceId);

飞书

$app = $kernel->lark()->app();

// 获取用户信息
$user = $app->auth()->user($code);
$detail = $app->auth()->userDetail($userId);

// 通讯录
$departments = $app->contact()->departments();
$users = $app->contact()->departmentUsers('0');

// 消息
$app->message()->text('ou_xxx', 'Hello World');
$app->message()->post('ou_xxx', ['zh_cn' => ['title' => '标题', 'content' => [['tag' => 'text', 'text' => '内容']]]]);
$app->message()->image('ou_xxx', $imageKey);
$app->message()->file('ou_xxx', $fileKey);
$app->message()->interactive('ou_xxx', ['config' => ['wide_screen_mode' => true], 'elements' => []]);

// 审批
$app->approval()->create($data);
$app->approval()->instance($instanceCode);

// 多维表格
$app->bitable()->meta($appToken);
$app->bitable()->tables($appToken);
$app->bitable()->createRecord($appToken, $tableId, ['字段名' => '']);
$app->bitable()->records($appToken, $tableId);
$app->bitable()->updateRecord($appToken, $tableId, $recordId, ['字段名' => '新值']);
$app->bitable()->deleteRecord($appToken, $tableId, $recordId);

// 文档管理
$doc = $app->doc()->create('新文档标题', $folderToken);
$app->doc()->meta($documentId);
$app->doc()->rawContent($documentId);
$app->doc()->blocks($documentId, $blockId);
$app->doc()->createBlock($documentId, $blockId, [
    ['block_type' => 2, 'text' => ['elements' => [['text_run' => ['content' => 'Hello World']]]]],
]);

// 日历管理
$app->calendar()->create(['summary' => '团队日历', 'description' => '用于团队协作']);
$app->calendar()->list();
$app->calendar()->get($calendarId);
$app->calendar()->delete($calendarId);
$app->calendar()->createEvent($calendarId, [
    'summary'     => '周会',
    'start'       => ['date_time' => '2024-01-01T10:00:00+08:00'],
    'end'         => ['date_time' => '2024-01-01T11:00:00+08:00'],
    'attendees'   => [['user_id' => 'ou_xxx']],
]);
$app->calendar()->listEvents($calendarId);
$app->calendar()->getEvent($calendarId, $eventId);
$app->calendar()->deleteEvent($calendarId, $eventId);

// 任务管理
$task = $app->task()->create(['summary' => '完成需求文档', 'due' => ['date' => '2024-01-15']]);
$app->task()->get($taskGuid);
$app->task()->update($taskGuid, ['summary' => '更新后的任务标题']);
$app->task()->complete($taskGuid);
$app->task()->uncomplete($taskGuid);
$app->task()->delete($taskGuid);

// 知识库
$app->wiki()->list();
$app->wiki()->get($spaceId);
$app->wiki()->nodes($spaceId);
$app->wiki()->createNode($spaceId, ['obj_type' => 22, 'node_type' => 'origin', 'origin_node_token' => $docToken, 'parent_node_token' => $parentToken, 'title' => '新节点']);

// 审批定义(流程配置)
$app->approvalDef()->list();
$app->approvalDef()->get($approvalCode);
$app->approvalDef()->createInstance(['approval_code' => $approvalCode, 'user_id' => 'ou_xxx', 'form' => ['控件ID' => ['value' => '']]]);
$app->approvalDef()->instanceList($approvalCode);
$app->approvalDef()->approve(['instance_code' => $instanceCode, 'user_id' => 'ou_xxx', 'comment' => '同意']);
$app->approvalDef()->reject(['instance_code' => $instanceCode, 'user_id' => 'ou_xxx', 'comment' => '驳回']);

// 邮件
$app->mail()->send(['subject' => '会议通知', 'body' => ['content' => '明天上午10点开会', 'content_type' => 'text/plain'], 'to' => [['mail_address' => 'user@example.com']]]);
$app->mail()->mailGroupList();
$app->mail()->createMailGroup(['mail_group_name' => '技术部', 'email' => 'tech@company.com']);
$app->mail()->getMailGroup($mailGroupId);
$app->mail()->deleteMailGroup($mailGroupId);

支付宝

$app = $kernel->alipay()->app();

// 登录
$user = $app->auth()->token($code);
$userInfo = $app->auth()->user($accessToken);

// 基础支付
$app->pay()->create([
    'out_trade_no' => 'ORDER_001',
    'total_amount' => '99.99',
    'subject'      => '测试商品',
]);

// 企业级支付(需安装 kode/pays)
$pay = $app->payBridge();
if ($pay !== null) {
    $pay->create([...]);
}

// 转账
$app->transfer()->create([
    'out_biz_no'    => 'TRANSFER_001',
    'trans_amount'  => '100.00',
    'order_title'   => '提现',
    'payee_account' => 'user@example.com',
    'payee_name'    => '张三',
]);

// 账单
$app->bill()->download('trade', '2024-01-01');

// 营销
$app->marketing()->createCashActivity(['coupon_name' => '现金红包活动', 'prize_type' => 'FIX', 'total_money' => 10000, 'total_num' => 100]);
$app->marketing()->triggerCash(['user_id' => $userId, 'out_biz_no' => 'BIZ001', 'amount' => 100]);
$app->marketing()->createVoucherTemplate(['voucher_name' => '优惠券模板', 'brand_name' => '商家名称']);
$app->marketing()->sendVoucher(['voucher_template_id' => $templateId, 'user_id' => $userId]);
$app->marketing()->precreate(['out_trade_no' => 'ORDER001', 'total_amount' => '100.00', 'subject' => '商品标题']);
$app->marketing()->refund(['out_trade_no' => 'ORDER001', 'refund_amount' => '50.00']);

// 会员
$app->member()->info($accessToken);
$app->member()->authInfo($authToken);
$app->member()->pointBalance($userId);

// 回调通知
$result = $app->notify()
    ->onPaid(function ($payload) {
        $outTradeNo = $payload['out_trade_no'];
        // 更新订单...
    })
    ->handle();

echo 'success'; // 返回给支付宝

抖音

$app = $kernel->douyin()->app();

// 登录
$user = $app->auth()->user($code);

// 视频管理
$app->video()->upload($accessToken, ['open_id' => $openId, 'video' => $videoData]);
$app->video()->create($accessToken, ['open_id' => $openId, 'item_id' => $itemId, 'title' => '视频标题', 'cover' => $coverUrl]);
$app->video()->list($accessToken, $openId);
$app->video()->data($accessToken, $openId, [$itemId]);
$app->video()->commentList($accessToken, $openId, $itemId);
$app->video()->commentReply($accessToken, ['open_id' => $openId, 'item_id' => $itemId, 'comment_id' => $commentId, 'content' => '回复内容']);

百度

$app = $kernel->baidu()->app();

// 登录
$app->auth()->session($code);
$app->auth()->userInfo($accessToken);

// 支付
$app->pay()->order(['dealId' => 'DEAL001', 'appKey' => 'APP001', 'totalAmount' => '100', 'tpOrderId' => 'ORDER001']);

// 模板消息
$app->message()->send(['touser' => $openId, 'template_id' => $templateId, 'data' => ['keyword1' => '值1', 'keyword2' => '值2']]);
$app->message()->templateList();
$app->message()->templateDetail($templateId);
$app->message()->deleteTemplate($templateId);

Kode 生态桥接使用

支付桥接(kode/pays)

use Kode\MiniApp\Bridge\PayBridge;

// 检查是否安装了 kode/pays
if (PayBridge::hasPayPackage()) {
    // 获取企业级支付实例
    $pay = $kernel->wechat()->app()->payBridge();
    $pay->order([...]);
    
    // 获取企业级通知处理器
    $notify = PayBridge::getNotify($kernel->wechat()->app());
}

工具桥接(kode/tools)

use Kode\MiniApp\Bridge\ToolsBridge;

// 自动检测并优先使用 kode/tools
$strClass = ToolsBridge::str();   // Kode\Tools\Str 或 Kode\MiniApp\Utils\Str
$signClass = ToolsBridge::sign(); // Kode\Tools\Sign 或 Kode\MiniApp\Utils\Sign

// 获取加密工具(仅 kode/tools 提供)
if (ToolsBridge::crypto()) {
    $crypto = ToolsBridge::crypto();
    // 使用加密工具...
}

// 获取二维码工具(仅 kode/tools 提供)
if (ToolsBridge::qrcode()) {
    $qrcode = ToolsBridge::qrcode();
    // 生成二维码...
}

异常桥接(kode/exception)

use Kode\MiniApp\Bridge\ExceptionBridge;
use Kode\MiniApp\Contracts\Platform;

// 自动使用 kode/exception 的异常码体系(如已安装)
$exception = ExceptionBridge::wrap(
    '请求失败',
    Platform::Wechat,
    1001,
    $previous
);

// 异常码映射规则
// 微信: 100000+, 支付宝: 200000+, 抖音: 300000+
// 百度: 400000+, QQ: 500000+, 企业微信: 600000+
// 钉钉: 700000+, 飞书: 800000+

HTTP 客户端

SDK 内置基于 Guzzle 的 HTTP 客户端,支持中间件、重试、日志:

use Kode\MiniApp\Core\HttpClient;
use Monolog\Logger;

$logger = new Logger('miniapp');
$http = new HttpClient(['timeout' => 30], $logger);

$kernel = new Kernel($config, $http);

缓存

AccessToken 自动缓存基于 Symfony Cache:

use Kode\MiniApp\Core\Cache;
use Kode\MiniApp\Core\AccessToken;

// 使用内置缓存
$cache = Cache::getInstance('/custom/cache/path');
$tokenManager = new AccessToken($cache);

// 如安装了 kode/cache,可替换为高性能缓存
// composer require kode/cache

工具类

use Kode\MiniApp\Utils\Str;
use Kode\MiniApp\Utils\Sign;
use Kode\MiniApp\Utils\Xml;

// 字符串
Str::random(16);
Str::uuid();
Str::camel('foo_bar'); // fooBar
Str::snake('fooBar');  // foo_bar

// 签名
Sign::md5($params, $key);
Sign::hmac($params, $key);
Sign::rsa($params, $privateKey);
Sign::verifyRsa($params, $publicKey, $sign);

// XML
Xml::build(['name' => 'test']);
Xml::parse($xmlString);

异常处理

use Kode\MiniApp\Exceptions\MiniAppException;
use Kode\MiniApp\Exceptions\PlatformException;
use Kode\MiniApp\Exceptions\ConfigException;

try {
    $kernel->wechat()->app()->auth()->session($code);
} catch (ConfigException $e) {
    // 配置错误
} catch (PlatformException $e) {
    // 平台级错误,包含平台信息
    echo $e->platform()->label();
} catch (MiniAppException $e) {
    // 通用错误
}

版本管理

版本号由 composer.json 统一管理:

# 升级 patch 版本(1.1.0 -> 1.1.1)
composer run version:bump

# 升级 minor 版本
composer run version:bump minor

# 升级 major 版本
composer run version:bump major

# 打 tag 并推送
composer run version:tag

代码质量

# 运行全部检查
composer run check

# 单独运行
composer run phpstan
composer run cs
composer run test

扩展新平台

  1. src/Contracts/Platform.php 添加枚举值
  2. src/Providers/{Platform}/ 实现 Provider、App、Config、Modules
  3. src/Kernel.php 注册 Provider
  4. tests/Providers/{Platform}/ 编写测试

许可证

Apache-2.0 License