Blog Helper · 小程序动态
小程序(免开发)一键设置心情状态、同步微信运动、快速发布说说|时光机|碎语|日记|心情
image效果截图
点击放大code配置代码
这张卡片没有 HTML 内容
(function () {
var KEY = 'bloghelper-stats'; // 缓存键(无 card- 前缀)
var TTL = 60 * 1000; // 缓存 1 分钟
var OPTS = { scope: 'site' }; // 全站共享(后台各管理员看到同一份数据)
var body = card.querySelector('.ab-custom-body');
// —— 当天 0 点(用于"今日"统计)——
var d = new Date();
var p2 = function (n) { return (n < 10 ? '0' : '') + n; };
var todayDate = d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate());
var todayStart = todayDate + ' 00:00:00'; // DATETIME 列(log 表)用
var todayUnix = Math.floor(new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime() / 1000); // int 列(contents)用
// —— 时间显示:int 时间戳 / DATETIME 字符串 → "MM-DD HH:mm"(自行实现,不依赖 format API 的入参格式)——
function fmt(t) {
try {
var dt = (/^\d+$/.test(String(t))) ? new Date(Number(t) * 1000) : new Date(String(t).replace(' ', 'T'));
if (isNaN(dt.getTime())) { return String(t || ''); }
return p2(dt.getMonth() + 1) + '-' + p2(dt.getDate()) + ' ' + p2(dt.getHours()) + ':' + p2(dt.getMinutes());
} catch (e) { return String(t || ''); }
}
// —— 骨架:4 个指标磁贴 + 动态清单容器 + 缓存提示 ——
var tiles = ab.ui.metrics([
{ icon: 'forum', label: '说说总数', value: '—', skeleton: true },
{ icon: 'today', label: '今日说说', value: '—', skeleton: true },
{ icon: 'directions_run', label: '最新步数', value: '—', skeleton: true },
{ icon: 'bolt', label: '今日运动打卡', value: '—', skeleton: true }
], { cols: 2 });
var listBox = ab.ui.el('div');
ab.ui.mount(body, [
tiles,
listBox,
ab.ui.notice({ icon: 'info', text: '数据缓存 1 分钟,点「重新读取」立即刷新', tone: 'info' })
]);
// 卡片底部入口:跳插件设置页(本地已验证的地址)
ab.ui.footer(card, { text: '插件设置', icon: 'settings', href: 'options-plugin.php?config=BlogHelper' });
// —— 渲染:官方用法 tiles.children + setValue 逐项刷新 ——
function render(s) {
var t = tiles.children;
ab.ui.setValue(t[0], ab.ui.num(s.talkTotal));
ab.ui.setValue(t[1], ab.ui.num(s.talkToday));
ab.ui.setValue(t[2], s.steps === null ? '—' : ab.ui.num(s.steps));
ab.ui.setValue(t[3], ab.ui.num(s.pushToday));
var rows = [];
if (s.talkLast) {
rows.push({ icon: 'edit', label: s.talkLast.title || '未命名', value: fmt(s.talkLast.created), hint: '最新说说' });
}
if (s.moodName) {
rows.push({ icon: 'mood', label: s.moodName, value: fmt(s.moodTime), hint: '最新心情' });
}
if (s.steps !== null) {
rows.push({ icon: 'directions_run', label: ab.ui.num(s.steps) + ' 步', value: s.stepsDate || '', hint: '最新步数' });
}
ab.ui.mount(listBox, rows.length
? ab.ui.rows(rows)
: ab.ui.empty({ icon: 'inbox', text: '还没有小程序推送记录', hint: '在小程序里发射一次就会出现在这里' }));
}
// —— 取数(全部只读:ab.db.read 官方示例同款 contents 表 + 插件自有三表)——
function fetchCounts() {
return Promise.all([
// 说说文章:正文含 storys 排版标记 chrison_grid_(插件发布说说时写入的特有标记)
ab.db.read('contents', {
columns: ['cid', 'title', 'created'],
where: [{ field: 'text', op: 'LIKE', value: '%chrison_grid_%' }],
orderBy: { field: 'created', dir: 'desc' },
limit: 200
}),
// 今日说说
ab.db.read('contents', {
columns: ['cid'],
where: [
{ field: 'text', op: 'LIKE', value: '%chrison_grid_%' },
{ field: 'created', op: '>=', value: todayUnix }
],
limit: 200
}),
// 最新步数
ab.db.read('blog_helper_wechat', {
columns: ['steps', 'step_date'],
orderBy: { field: 'created', dir: 'desc' },
limit: 1
}),
// 最新心情
ab.db.read('blog_helper_status', {
columns: ['emoji_name', 'created'],
orderBy: { field: 'created', dir: 'desc' },
limit: 1
}),
// 今日运动打卡次数(推送成功记录)
ab.db.read('blog_helper_log', {
columns: ['id'],
where: [
{ field: 'action', op: '=', value: 'steps' },
{ field: 'result', op: '=', value: 1 },
{ field: 'created', op: '>=', value: todayStart }
],
limit: 200
})
]).then(function (rs) {
var talks = rs[0].rows || [];
var wechat = (rs[2].rows || [])[0] || null;
var mood = (rs[3].rows || [])[0] || null;
return {
talkTotal: talks.length,
talkToday: (rs[1].rows || []).length,
talkLast: talks[0] || null,
steps: wechat ? Number(wechat.steps) : null,
stepsDate: wechat ? wechat.step_date : '',
moodName: mood ? mood.emoji_name : '',
moodTime: mood ? mood.created : '',
pushToday: (rs[4].rows || []).length
};
});
}
// —— 加载(getCached:1 分钟内切页回来不重复查询)——
function load() {
ab.data.getCached(KEY, TTL, fetchCounts, OPTS).then(function (s) {
render(s);
}).catch(function (e) {
ab.ui.setValue(tiles.children[0], '—');
ab.ui.setValue(tiles.children[1], '—');
ab.ui.setValue(tiles.children[2], '—');
ab.ui.setValue(tiles.children[3], '—');
ab.ui.mount(listBox, ab.ui.empty({ icon: 'error', text: '数据加载失败', hint: (e && e.message) || '' }));
ab.ui.notice({ text: 'Blog Helper 数据加载失败:' + ((e && e.message) || '未知错误'), tone: 'danger' });
});
}
load();
// 手动刷新(清缓存重拉)
ab.ui.mount(body, ab.ui.actions([
ab.ui.button({ text: '重新读取', icon: 'refresh', tone: 'info', onClick: function () {
ab.data.clearCached(KEY, OPTS);
load();
}})
]));
})();
download_for_offline如何导入
Typecho 后台 → 控制台 → 插件 → AB Admin(AdminBeautify)→「概要页卡片设置」
找到 自定义卡片 区域,打开总开关(默认关闭)
点 添加卡片,按下表填写:
| 图标 | insights |
| 卡片标题 | Blog Helper · 小程序动态 |
| HTML 内容 | (留空) |
| JavaScript | 见上方「JavaScript」标签页 |
点右下角 保存设置,回到概要页即可看到卡片(顺序可在排序列表里拖动调整)
shield安全信息
verified_user
扫描通过
warning
卡片 JavaScript 会在你的后台页面里执行。本站已做敏感信息、站外请求与越权操作的自动扫描 + 人工审核,但仍请在使用前自行阅读上方代码;发现可疑卡片请到
GitHub 反馈。