本文档为CansCode API管理系统开发手册,适用于系统二次开发人员、模板开发者及插件开发工程师。文档系统梳理了开发过程中核心的技术要点,涵盖内置钩子、数据库操作函数及模板开发规范三大核心模块。其中,内置钩子部分详细说明支付、上传、系统相关钩子的类型、权重及使用场景,并提供注册实例;数据库函数部分包含函数引入方式与查询、新增、修改、删除等常用操作示例;模板规范部分则针对Typecho模板(兼容Joe主题),明确目录结构、核心文件功能、配置页面开发及关键注意事项。通过本文档,开发者可快速掌握系统开发的基础规范与核心能力,提升开发效率并保障开发质量。

内置钩子文档

支付相关

  • Pay_Create_qq类型:执行钩子权重:1-100说明:创建支付订单时,QQ支付,可执行钩子,返回订单所有数据。
  • Pay_Create_wx类型:执行钩子说明:创建支付订单时,微信支付,可执行钩子,返回订单所有数据。
  • Pay_Create_ali类型:执行钩子说明:创建支付订单时,支付宝,可执行钩子,返回订单所有数据。
  • Pay_Create_balance类型:执行钩子(非必要请勿使用!)说明:创建支付订单时,余额支付,可执行钩子,返回订单所有数据。
  • Pay_Create类型:数据钩子说明:创建支付订单时,可返回数据钩子,用于创建后对订单数据进行编辑和返回。
  • Pay_CallBack类型:执行钩子说明:支付成功回调钩子,返回所有回调数据。注意:发起支付若需要跳转链接而不是html,请确保code = 522 并且链接在 data中。

上传相关

  • Update_File_Start类型:执行钩子权重:1-100说明:上传文件开始,返回$_FILES["file"]。
  • Update_Image_Start类型:执行钩子说明:上传图片开始,返回$_FILES["file"]。

系统相关

  • WebNotification类型:数据钩子权重:1-100说明:后台系统通知。
  • AdminNav_Left类型:数据钩子说明:后台导航栏左侧。
  • AdminNav_Chen类型:数据钩子说明:后台导航栏子栏目。
  • 注意:内置钩子请勿重复注册,否则可能出现插件异常,权重越小,越先执行。

注册实例

提供两种类型的钩子注册示例:执行类钩子和数据处理类钩子。

执行类钩子注册实例:

use Logic\Important\Hooks;
// 注册支付创建后,QQ支付处理钩子
Hooks::Register("Pay_Create_qq", 1, function($parameter) {
    echo "Pay_Create_qq";
    var_dump($parameter);
    exit();
}, 10);
数据处理类钩子注册实例:
use Logic\Important\Hooks;
// 支付创建后,处理数据,并将数据返回
Hooks::Register("Pay_Create", 2, function($parameter) {
    $parameter['payname'] = "我爱你";
    return $parameter;
}, 10);

内置函数

返回数据函数:

use Logic\Important\Tos;

// 返回状态
Tos::sendmsg(200);

// 返回单个数据
Tos::sendmsg(200, "", $data);

// 返回列表数据
Tos::sendmsg(200, "", $data, $total);

数据库内置函数

一、引入函数

使用SqlFun库来处理数据库操作。

use Logic\Important\SqlFun;

public function __construct()
{
   // 获取数据库实例
   $this->db = SqlFun::getInstance();
}

二、函数使用示例

1. 普通查询数据

执行一个简单的查询操作以获取数据。

$result = $this->db->query("SELECT * FROM xxx WHERE id = ?", [$id]);
2. 修改数据
更新表中的特定记录。
$this->db->update("xxxxx", [
    "xu_fans" => $merinfo[0]['xu_fans'] - 1,
], 'id = ?', [$merinfo[0]['id']]);
3. 删除数据
从指定表中删除一条记录。
$this->db->delete("xu_merfans", "id = ?", [$res[0]['id']]);
4. 写入数据
向指定表中插入新数据。
$this->db->insert("xu_keyapi", [
    "xu_aid" => $aidlist[$a],
    "xu_kid" => $ids
]);
5. 数据库语句拼接
使用SqlFun提供的方法构建复杂的SQL查询。
$sql = SqlFun::SqlBuilderAdd("xu_name", $pre['search'], 'like')
            ->SqlBuilderAdd("xu_mid", $pre['mid'])
            ->SqlBuilderAdd("xu_status", 1)
            ->SqlBuilderBuild();
            6. 数据库查询语句(分页查询)
            执行分页查询,并返回结果。
$result = $this->db->getPaginatedData("xu_api", $sql, [$pre['sortname'], $pre['sorttype']], $pagination, [
    "xu_queryper", "xu_bodyper", "xu_headerper", "xu_cookies", "xu_errlist", "xu_bodyjson", "xu_words", "xu_apisource"
]);

模板规范

Typecho 模板开发指南(Joe 主题兼容)

一、目录结构

一个标准的 Typecho 模板目录结构如下:

mytemplate/
├── user/                  # 用户中心页面(自动判断登录)
├── Main.php               # 主逻辑文件
├── package.json           # 模板描述信息文件
├── ConfigurationPage.php  # 模板配置页面

二、Main.php —— 主逻辑文件

该文件定义模板的核心行为和生命周期钩子。

示例代码:

<?php

namespace Resource\Template\default;

use Logic\Important\Rote;
use Logic\Important\Tos;
use Resource\Template\default\cp;

class Main
{
    public function CallBack($parameter)
    {
        if ($parameter['status'] == 1) {
            cp::setteP($data);
            Tos::sendmsg(200);
        }

        if ($parameter['status'] == 2) {
            cp::checkUpdate(3);
        }
    }

    public function init(): void
    {
        $this->getAuthCert();
    }

    public function Userinit(): void
    {
        $this->getAuthCert();
    }

    public function Admininit(): void
    {
        // 检查模板是否存在新版本
        cp::checkUpdate();
    }

    public function getAuthCert()
    {
        // 授权验证示例(可选)
        // $auth = new Rote();
        // $res = $auth->appCertificate('5a6e619c-29d1-2890-1776-14078b36b4c3');
        // if ($res['code'] !== '5200') {
        //     error_log('未授权');
        // } else {
        //     error_log('已授权');
        // }
    }
}

三、package.json —— 模板描述文件

用于存储模板的基本信息,便于管理与更新。

示例内容:

{
  "tep_name": "默认模板",
  "tep_version": "0.0.1",
  "tep_image": "https://imgsbad.semoun.com/uploads/2025/03/19/67da24298292e.jpg",
  "tep_brief": "自带的默认模板",
  "tep_cansid": "default",
  "tep_page": true,
  "tep_PagePath": "ConfigurationPage.php",
  "tep_code": "5a6e619c-29d1-2890-1776-14078b36b4c3",
  "author_name": "CansCode"
}

四、ConfigurationPage.php —— 模板配置页面

用于提供后台可视化配置界面,支持用户自定义设置。

示例代码片段(HTML + Vue.js):

<?php

use Logic\Function\MainControl\WebInfo;
use Resource\Template\default\cp;

$config = cp::gettep();
$pack = cp::getpack();
$info = new WebInfo();
$webinfo = $info->getWebInfo(2);

// 获取版本
$type = $_GET['type'] ?? 1;

$upinfo = cp::checkUpdate(2);
?>
<link rel="stylesheet" href="/Resource/Template/default/assets/css/page.min.css">
<link rel="stylesheet" href="/Resource/Template/default/assets/css/XuZhiGlobal.min.css">
<style>
    .WebPagesPg{
        background-color: #fff;
        min-height: 100vh;
    }
    .tab-header {
        display: flex;
        border-bottom: 1px solid #eee;
        margin-bottom: 20px;
    }

    .tab-header div {
        padding: 10px 20px;
        cursor: pointer;
        font-size: 16px;
        border-bottom: 2px solid transparent;
    }

    .tab-header .active {
        border-color: #1890ff;
        font-weight: bold;
        color: #1890ff;
    }

    .tabpanel {
        display: none;
    }

    .tabpanel.active {
        display: block;
    }

    .update-box {
        border: 1px solid #ddd;
        padding: 16px;
        background: #f9f9f9;
        border-radius: 8px;
    }

    .update-log {
        margin-top: 16px;
    }

    .download-box {
        margin-top: 20px;
    }

    .download-btn {
        display: inline-block;
        padding: 10px 16px;
        background-color: #1466ff;
        color: #fff;
        border-radius: 6px;
        text-decoration: none;
    }

    .download-btn:hover {
        background-color: #0056d2;
    }
</style>

<div class="WebPagesPg" id="WebPages">
    <!-- 标签页 -->
    <div class="tab-header">
        <div :class="{tabbtn:true, active:showtag == 1}" data-tab="update" @click="showtag = 1">模板配置</div>
        <div :class="{tabbtn:true, active:showtag == 2}" data-tab="config" @click="showtag = 2">模板更新</div>
    </div>

    <div class="x_from">
        <!-- 模板配置 -->
        <div :class="{tabpanel:true, active:showtag == 1}" id="tab-update">
            <div class="x_from_item">
                <p class="x_from_title">站点简介</p>
                <input type="text" v-model="conform.desc" class="x_input" id="site_desc" placeholder="请输入站点简介">
                <trg class="x_from_trg">Ps: 将显示在首页底部文字区域</trg>
            </div>
            <div class="x_from_item">
                <p class="x_from_title">底部二维码</p>
                <input type="text" class="x_input" v-model="conform.qr_urla" id="qr_urla" placeholder="请输入二维码图片地址">
            </div>
            <div class="x_from_item">
                <p class="x_from_title">底部二维码</p>
                <input type="text" class="x_input" v-model="conform.qr_urlb" id="qr_urlb" placeholder="请输入二维码图片地址">
            </div>
            <div class="x_from_item">
                <button class="x_button" @click="upconfig()">确认修改配置</button>
            </div>
        </div>
        <div :class="{tabpanel:true, active:showtag == 2}" id="tab-config">
            <div class="x_from_item" style="display: flex; gap: 20px; align-items: flex-start;">
                <div style="flex: 1;">
                    <p class="">模板名称:<span id="tep_name" style="color: #333;">{{ tepInfo.tep_name}}</span></p>
                    <p class="">模板标识:<span id="tep_cansid" style="color: #888;">{{ tepInfo.tep_cansid}}</span></p>
                    <p class="">模板版本:<span id="tep_version" style="color: #007bff;">v{{ tepInfo.tep_version}}</span> -- <span id="tep_version" style="color: #007bff;">v{{upinfo.NewVersion}}</span></p>
                    <p class="">作者:<span id="author_name" style="color: #555;">{{tepInfo.author_name}}</span></p>
                </div>
            </div>
            <button class="x_button" @click="update()" style="margin-bottom: 20px;">更新至最新版</button>
            <div v-if="upinfo && upinfo.data?.length">
                <div class="update-box">
                    <h2 style="font-size: 16px">版本更新说明</h2>
                    <p style="margin-top: 10px"><strong>最新版本:</strong> {{ upinfo.NewVersion }}</p>
                    <div v-html="upinfo.data[0].x_word" class="update-log"></div>
                </div>
            </div>
        </div>
    </div>
</div>
<img style="display: none;" src="/Public/Assets/images/loadw.png" alt="">
<script src="/Public/Assets/js/axios.js"></script>
<script src="/Public/Assets/js/vue.js"></script>
<script>
    const {
        ref,
        createApp
    } = Vue;
    const App = {
        data() {
            const showtag = ref(1);
            const config = ref(JSON.parse('<?= json_encode($config, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>'));
            const tepInfo = ref(JSON.parse('<?= json_encode($pack, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>'));
            const upinfo = ref(<?= json_encode($upinfo, JSON_UNESCAPED_UNICODE) ?>);

            const conform = ref({
                type: 'TempCallBack',
                status: 1,
                desc: config.value.footer_text,
                qr_urla: config.value.footer_qrlist?.[0]?.url || "",
                qr_urlb: config.value.footer_qrlist?.[1]?.url || "",
            })

            const upconfig = () => {
                window.parent.postMessage(JSON.parse(JSON.stringify(conform.value)))
            }
            const update = () => {
                window.parent.postMessage({
                    type: 'TempCallBack',
                    status: 2
                })
            }

            return {
                config,
                tepInfo,
                conform,
                showtag,
                upinfo,
                upconfig,
                update
            }
        }
    }
    const app = Vue.createApp(App);
    window.vm = app.mount("#WebPages");
</script>

五、功能说明


功能模块描述
CallBack()处理来自系统的回调事件(如配置更新、版本升级)
init()初始化函数,在前台加载时执行
Userinit()用户中心初始化函数
Admininit()后台初始化函数,可用于检查模板更新
getAuthCert()可选的授权验证逻辑

六、注意事项

  • 所有模板页面需放置在 /usr/themes/ 目录下。
  • 若模板包含用户中心页面,请放入 user/ 文件夹,并确保系统会自动进行登录验证。
  • 使用 Vue.js 前端框架时,确保引入了对应的 JS 库(如 vue.js, axios.js)。
  • 所有数据交互应使用 window.parent.postMessage() 发送至主窗口处理。