Browse Source

1.2.2

pull/233/head
xiaoz 5 days ago
parent
commit
2c8bdd08df
  1. 85
      class/Api.php
  2. 108
      controller/api.php
  3. 7
      data/update.log
  4. 16
      templates/admin/add_category.php
  5. 14
      templates/admin/add_category_new.php
  6. 14
      templates/admin/edit_category.php
  7. 15
      templates/admin/edit_category_new.php
  8. 4
      templates/admin/setting/theme.php
  9. 227
      templates/admin/setting/theme_detail.php
  10. 2
      templates/admin/static/embed.js
  11. 2
      version.txt

85
class/Api.php

@ -738,38 +738,66 @@ class Api { @@ -738,38 +738,66 @@ class Api {
}
/**
* 导出HTML链接进行备份
* 导出HTML链接进行备份(支持二级分类)
* 返回结构:
* [
* [
* 'id'=>1,'name'=>'父分类','links'=>[...],
* 'children'=>[
* ['id'=>2,'name'=>'子分类','links'=>[...]],
* ...
* ]
* ],
* ...
* ]
*/
public function export_link(){
//鉴权
$this->auth($token);
//查询所有分类
$categorys = $this->db->select("on_categorys","*");
//定义一个空数组用来存储查询后的数据
$data = [];
//遍历分类
foreach ($categorys as $key => $category) {
//查询该分类下的所有链接
$links = $this->db->select("on_links","*",[
"fid" => $category['id']
]);
// echo $category['name'];
// var_dump($links);
// exit;
//组合为一个一维数组
$arr[$category['name']] = $links;
// var_dump();
// exit;
$data[$category['name']] = $arr[$category['name']];
//清除临时数据
unset($arr);
// 一次性获取所有分类与链接,减少查询次数
$categories = $this->db->select("on_categorys", [
"id","name","fid","weight","add_time"
]);
$links = $this->db->select("on_links", [
"id","fid","title","url","add_time","weight"
],[
"ORDER" => ["weight"=>"DESC","id"=>"DESC"]
]);
// 预分配链接到分类
$linksByCat = [];
foreach ($links as $l) {
$linksByCat[$l['fid']][] = $l;
}
// 构建分类映射
$catMap = [];
foreach ($categories as $c) {
$catMap[$c['id']] = [
'id' => $c['id'],
'name' => $c['name'],
'fid' => $c['fid'],
'links' => isset($linksByCat[$c['id']]) ? $linksByCat[$c['id']] : [],
'children' => []
];
}
// 组装层级(仅两级:fid=0 为顶级,其它挂到父类 children)
$tree = [];
foreach ($catMap as $id => &$node) {
if ($node['fid'] == 0) {
$tree[] = &$node;
} else {
if (isset($catMap[$node['fid']])) {
$catMap[$node['fid']]['children'][] = &$node;
} else {
// 父分类缺失时降级为顶级
$tree[] = &$node;
}
}
}
//返回数据
return $data;
unset($node);
return $tree;
}
/**
* name:修改链接
@ -2852,6 +2880,7 @@ class Api { @@ -2852,6 +2880,7 @@ class Api {
set_time_limit(1200); // 设置执行最大时间为20分钟
// 验证授权
$this->auth($token);
// 验证订阅
$this->check_is_subscribe();
@ -3116,7 +3145,7 @@ class Api { @@ -3116,7 +3145,7 @@ class Api {
$messages = [
[
"role" => "system",
"content" => "请自动检测用户输入的语言。当输入内容是中文时,翻译成英文;当输入内容不中文时,翻译成中文。只需返回翻译后的内容,不需要额外解释或描述。"
"content" => "请自动检测用户输入的语言。当输入内容是中文时,翻译成英文;当输入内容不属于中文时,翻译成中文。只需返回翻译后的内容,不需要额外解释或描述。"
],
[
"role" => "user",

108
controller/api.php

@ -519,7 +519,86 @@ function get_theme_config($api) { @@ -519,7 +519,86 @@ function get_theme_config($api) {
$api->get_theme_config();
}
//批量设置链接私有属性
//导出链接数据
function export_link($api) {
header('Content-Type: text/html; charset=UTF-8');
// 若已有树结构(之前的 export_link 方法),复用;否则自行构建。
$tree = [];
if (method_exists($api,'export_link')) {
$tree = $api->export_link();
}
// 兜底:没有返回结构则直接结束
if (!is_array($tree)) { $tree = []; }
$now = time();
// 递归输出函数(模仿 Chrome 导出格式,目录在前,链接在后)
$printCategory = function ($cat, $depth = 2) use (&$printCategory, $now) {
$indent = str_repeat(' ', $depth);
$indentInner = str_repeat(' ', $depth + 1);
$name = $cat['name'];
// 特殊处理默认分类名称
if ($name === '默认分类') {
$name = 'OneNav默认分类';
}
$name = htmlspecialchars($name, ENT_QUOTES);
$add_date = isset($cat['add_time']) && intval($cat['add_time'])>0 ? intval($cat['add_time']) : $now;
$last_mod = $add_date;
echo "{$indent}<DT><H3 ADD_DATE=\"{$add_date}\" LAST_MODIFIED=\"{$last_mod}\">{$name}</H3>\n";
echo "{$indent}<DL><p>\n";
// 子目录
if (!empty($cat['children'])) {
foreach ($cat['children'] as $sub) {
$printCategory($sub, $depth + 1);
}
}
// 链接
if (!empty($cat['links'])) {
foreach ($cat['links'] as $link) {
$title = htmlspecialchars($link['title'], ENT_QUOTES);
$url = htmlspecialchars($link['url'], ENT_QUOTES);
$l_add = isset($link['add_time']) && intval($link['add_time'])>0 ? intval($link['add_time']) : $now;
echo "{$indentInner}<DT><A HREF=\"{$url}\" ADD_DATE=\"{$l_add}\">{$title}</A>\n";
}
}
echo "{$indent}</DL><p>\n";
};
// 输出头部(保持与 Chrome/Edge 格式一致)
echo <<<HTML
<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
It will be read and overwritten.
DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
HTML;
// 构造根目录“书签栏”包裹所有顶级分类
$rootAdd = $now;
$rootMod = $now;
echo " <DT><H3 ADD_DATE=\"{$rootAdd}\" LAST_MODIFIED=\"{$rootMod}\" PERSONAL_TOOLBAR_FOLDER=\"true\">OneNav</H3>\n";
echo " <DL><p>\n";
foreach ($tree as $topCat) {
$printCategory($topCat, 2);
}
echo " </DL><p>\n";
echo "</DL><p>\n";
}
// 批量设置链接私有属性
function set_link_attribute($api) {
$ids = $_POST['ids'];
$property = intval( $_POST['property'] );
@ -530,33 +609,6 @@ function set_link_attribute($api) { @@ -530,33 +609,6 @@ function set_link_attribute($api) {
$api->set_link_attribute($data);
}
//导出链接数据
function export_link($api) {
header('Content-Type: text/html;charset=utf8');
$data = $api->export_link();
//当前时间
$current = time();
echo <<< EOF
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>从OneNav导出的书签</TITLE>
<H1>Bookmarks</H1>
EOF;
//遍历结果
foreach ($data as $key => $value) {
echo "<DT><H3 ADD_DATE=\"$current\" LAST_MODIFIED=\"$current\">$key</H3>\n";
echo "<DL><P></P>\n";
foreach ($value as $link) {
$title = $link['title'];
$add_time = $link['add_time'];
$url = $link['url'];
echo "<DT><A HREF=\"$url\" ADD_DATE=\"$add_time\" ICON=\"\">$title</a></DT>\n";
}
echo "<P></P></DL>\n";
echo "</DT>\n";
}
}
//获取用户登录状态
function check_login($api) {
$token = trim($_REQUEST['token']);

7
data/update.log

@ -1,3 +1,10 @@ @@ -1,3 +1,10 @@
2025.09.01
1. 导出所有链接支持二级分类
2. 删除空白的default3主题
3. 支持删除分类图标
4. default2主题支持后台设置每个分类要展示的数量
5. 新增主题:BookNest
2025.08.13
1. 后台分类列表,支持按权重排序
2. 移出default2主题侧边栏底部工具按钮

16
templates/admin/add_category.php

@ -21,13 +21,18 @@ @@ -21,13 +21,18 @@
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">字体图标</label>
<label for="" class="layui-form-label">字体图标</label>
<div class="layui-input-inline" style = "width:240px;">
<input name="font_icon" type="text" id="iconHhys2" value="" lay-filter="iconHhys2" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
<div class="layui-input-inline">
<button onclick="del_font_icon()" type="button" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-delete"></i>
</button>
</div>
<!-- <div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
</div> -->
</div>
<div class="layui-form-item">
@ -79,6 +84,11 @@ @@ -79,6 +84,11 @@
<?php include_once('footer.php'); ?>
<script>
// 清空id=iconHhys2的value
function del_font_icon(){
$("#iconHhys2").val("");
layer.msg("图标已取消,添加或更新后将不再显示图标!",{icon:1});
}
//参考:https://gitee.com/luckygyl/iconFonts
layui.use(['iconHhysFa'], function(){
var iconHhysFa = layui.iconHhysFa;

14
templates/admin/add_category_new.php

@ -24,9 +24,14 @@ @@ -24,9 +24,14 @@
<div class="layui-input-inline" style = "width:240px;">
<input name="font_icon" type="text" id="iconHhys2" value="" lay-filter="iconHhys2" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
<div class="layui-input-inline">
<button onclick="del_font_icon()" type="button" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-delete"></i>
</button>
</div>
<!-- <div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
</div> -->
</div>
<div class="layui-form-item">
@ -77,6 +82,11 @@ @@ -77,6 +82,11 @@
</div>
<script>
// 清空id=iconHhys2的value
function del_font_icon(){
$("#iconHhys2").val("");
layer.msg("图标已取消,添加或更新后将不再显示图标!",{icon:1});
}
//参考:https://gitee.com/luckygyl/iconFonts
layui.use(['iconHhysFa'], function(){
var iconHhysFa = layui.iconHhysFa;

14
templates/admin/edit_category.php

@ -72,9 +72,14 @@ @@ -72,9 +72,14 @@
<div class="layui-input-inline" style = "width:240px;">
<input name="font_icon" type="text" id="iconHhys2" value="<?php echo $category_one['font_icon']; ?>" lay-filter="iconHhys2" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
<div class="layui-input-inline">
<button onclick="del_font_icon()" type="button" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-delete"></i>
</button>
</div>
<!-- <div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
</div> -->
</div>
<div class="layui-form-item">
@ -113,6 +118,11 @@ @@ -113,6 +118,11 @@
<?php include_once('footer.php'); ?>
<script>
// 清空id=iconHhys2的value
function del_font_icon(){
$("#iconHhys2").val("");
layer.msg("图标已取消,添加或更新后将不再显示图标!",{icon:1});
}
//参考:https://gitee.com/luckygyl/iconFonts
layui.use(['iconHhysFa'], function(){
var iconHhysFa = layui.iconHhysFa;

15
templates/admin/edit_category_new.php

@ -70,9 +70,15 @@ @@ -70,9 +70,15 @@
<div class="layui-input-inline" style = "width:240px;">
<input name="font_icon" type="text" id="iconHhys2" value="<?php echo $category_one['font_icon']; ?>" lay-filter="iconHhys2" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
<div class="layui-input-inline">
<button onclick="del_font_icon()" type="button" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-delete"></i>
</button>
</div>
<!-- <div class="layui-form-mid layui-word-aux">
图标对照表可参考:<a rel = "nofollow" target = "_blank" href="https://fontawesome.dashgame.com/">FontAwesome4</a>
</div> -->
</div>
<div class="layui-form-item">
@ -110,6 +116,11 @@ @@ -110,6 +116,11 @@
</div>
<script>
// 清空id=iconHhys2的value
function del_font_icon(){
$("#iconHhys2").val("");
layer.msg("图标已取消,添加或更新后将不再显示图标!",{icon:1});
}
//参考:https://gitee.com/luckygyl/iconFonts
layui.use(['iconHhysFa'], function(){
var iconHhysFa = layui.iconHhysFa;

4
templates/admin/setting/theme.php

@ -183,7 +183,7 @@ function theme_detail(name){ @@ -183,7 +183,7 @@ function theme_detail(name){
layer.open({
title: name,
type:2,
area: ['60%', '59%'],
area: ['1200px', '680px'],
content:'/index.php?c=admin&page=setting/theme_detail&name=' + name
});
}
@ -192,7 +192,7 @@ function theme_detail_online(name){ @@ -192,7 +192,7 @@ function theme_detail_online(name){
layer.open({
title: name,
type:2,
area: ['60%', '59%'],
area: ['1200px', '680px'],
content:'/index.php?c=admin&page=setting/theme_detail&name=' + name
});
}

227
templates/admin/setting/theme_detail.php

@ -6,25 +6,226 @@ @@ -6,25 +6,226 @@
<title>OneNav后台管理</title>
<link rel='stylesheet' href='static/layui/css/layui.css'>
<link rel='stylesheet' href='templates/admin/static/style.css?v=v0.9.17-20220314'>
<style>
:root{
--c-bg:#f5f7fb;
--c-bg-alt:#ffffff;
--c-text:#2f363c;
--c-text-light:#5d6b76;
--c-primary:#2b7bcb;
--c-primary-grad-start:#2b7bcb;
--c-primary-grad-end:#6fb7ff;
--c-accent:#318ce3;
--c-border:#e3e8ef;
--c-radius:14px;
--c-shadow:0 4px 12px -2px rgba(28,39,49,.08),0 8px 24px -4px rgba(28,39,49,.06);
--c-shadow-hover:0 6px 18px -2px rgba(28,39,49,.15),0 14px 32px -6px rgba(28,39,49,.12);
--duration:.35s;
--ease:cubic-bezier(.4,.14,.3,1);
}
@media (prefers-color-scheme: dark){
:root{
--c-bg:#151a20;
--c-bg-alt:#1e252c;
--c-text:#e6ecf2;
--c-text-light:#9aa5b1;
--c-border:#2a323c;
--c-shadow:0 4px 14px -2px rgba(0,0,0,.55),0 8px 28px -6px rgba(0,0,0,.4);
--c-shadow-hover:0 6px 20px -2px rgba(0,0,0,.6),0 16px 40px -8px rgba(0,0,0,.5);
}
.description{background:rgba(49,140,227,.15);}
}
body{
background:linear-gradient(135deg,var(--c-bg) 0%,var(--c-bg-alt) 100%);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
color:var(--c-text);
line-height:1.55;
-webkit-font-smoothing:antialiased;
padding:2.2rem 1.4rem 3rem;
}
.page-wrap{
max-width:1180px;
margin:0 auto;
display:flex;
gap:1.8rem;
align-items:flex-start;
flex-wrap:wrap;
opacity:0;
animation:fadeIn .6s var(--ease) forwards;
margin-top:1em;
margin-bottom:1em;
}
@keyframes fadeIn{to{opacity:1;transform:none}}
.card{
background:var(--c-bg-alt);
border:1px solid var(--c-border);
border-radius:var(--c-radius);
box-shadow:var(--c-shadow);
transition:box-shadow var(--duration) var(--ease),transform var(--duration) var(--ease),border-color var(--duration) var(--ease);
position:relative;
overflow:hidden;
}
.card:hover{
box-shadow:var(--c-shadow-hover);
transform:translateY(-4px);
border-color:rgba(49,140,227,.35);
}
.left-pane{
flex:1 1 62%;
min-width:320px;
padding:1.2rem 1.2rem 1.6rem;
}
.right-pane{
flex:1 1 300px;
max-width:360px;
padding:1.6rem 1.4rem 2rem;
display:flex;
flex-direction:column;
gap:.75rem;
}
.theme-screenshot{
border-radius:10px;
overflow:hidden;
position:relative;
background:linear-gradient(135deg,#d9e6f2,#f2f8fc);
aspect-ratio:16/9;
display:flex;
align-items:center;
justify-content:center;
box-shadow:inset 0 0 0 1px rgba(255,255,255,.4);
}
.theme-screenshot img{
width:100%;
height:100%;
object-fit:cover;
display:block;
filter:saturate(1.04);
transform:scale(1.01);
transition:transform 1.2s var(--ease),filter .8s var(--ease);
}
.theme-screenshot:hover img{
transform:scale(1.045);
filter:saturate(1.12);
}
.detail h1{
background:linear-gradient(90deg,var(--c-primary-grad-start) 0%,var(--c-primary-grad-end) 85%);
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
font-size:2rem;
font-weight:700;
letter-spacing:.5px;
margin:0 0 .6rem;
line-height:1.25;
}
.description{
background:linear-gradient(125deg,rgba(49,140,227,.15),rgba(49,140,227,.08));
color:var(--c-text);
padding:.85rem 1rem;
border-radius:10px;
font-size:.92rem;
line-height:1.5;
position:relative;
border:1px solid rgba(49,140,227,.25);
}
.meta-item{
margin:0;
font-size:.9rem;
color:var(--c-text-light);
display:flex;
gap:.4rem;
align-items:center;
}
.meta-item strong{
font-weight:600;
color:var(--c-text);
background:linear-gradient(90deg,rgba(49,140,227,.18),rgba(49,140,227,0));
padding:.2rem .55rem;
border-radius:6px;
font-size:.78rem;
letter-spacing:.5px;
text-transform:uppercase;
}
.links a{
color:var(--c-accent);
position:relative;
font-weight:500;
text-decoration:none;
display:inline-flex;
align-items:center;
gap:.35rem;
}
.links a::after{
content:"";
position:absolute;
left:0;
bottom:-2px;
height:2px;
width:0;
background:linear-gradient(90deg,var(--c-accent),var(--c-primary-grad-end));
transition:width .45s var(--ease);
border-radius:2px;
}
.links a:hover::after{width:100%;}
.badge{
display:inline-block;
padding:.25rem .55rem;
background:linear-gradient(90deg,var(--c-primary-grad-start),var(--c-primary-grad-end));
color:#fff;
border-radius:20px;
font-size:.7rem;
letter-spacing:.5px;
font-weight:500;
box-shadow:0 2px 4px rgba(43,123,203,.35);
margin-left:.4rem;
vertical-align:middle;
}
.split-line{
height:1px;
background:linear-gradient(90deg,rgba(49,140,227,.35),rgba(49,140,227,0));
margin:1rem 0 .5rem;
border:none;
}
@media (max-width:880px){
.page-wrap{flex-direction:column;}
.left-pane,.right-pane{max-width:100%;}
.detail h1{font-size:1.65rem;}
body{padding:1.6rem 1rem 2.4rem;}
}
</style>
</head>
<body class="layui-fluid">
<div class="layui-row" style = "margin-top:1em;">
<div class="layui-col-sm9" style = "border-right:1px solid #e2e2e2;">
<div style = "margin-left:1em;margin-right:1em;">
<img src="<?php echo $theme->screenshot; ?>" alt="" style = "max-width:100%;">
<!-- 新布局容器 -->
<div class="page-wrap">
<div class="card left-pane">
<div class="theme-screenshot">
<img src="<?php echo $theme->screenshot; ?>" alt="<?php echo $theme->name; ?> Screenshot">
</div>
</div>
<div class="layui-col-sm3">
<div style = "margin-left:1em;margin-right:1em;">
<h1><?php echo $theme->name; ?></h1>
<p>描述:<?php echo $theme->description; ?></p>
<p>版本:<?php echo $theme->version; ?></p>
<p>更新时间:<?php echo $theme->update; ?></p>
<p>作者:<?php echo $theme->author; ?></p>
<p>使用说明:<a style = "color:#01AAED;" href="<?php echo $theme->help_url; ?>" target="_blank" rel = "nofollow"><?php echo $theme->help_url; ?></a></p>
<p>主页:<a style = "color:#01AAED;" href="<?php echo $theme->homepage; ?>" target="_blank" rel = "nofollow"><?php echo $theme->homepage; ?></a></p>
<div class="card right-pane detail">
<!-- 标题 + 版本徽标 -->
<h1>
<?php echo $theme->name; ?>
</h1>
<div class="description">
<?php echo $theme->description; ?>
</div>
<hr class="split-line">
<p class="meta-item"><strong>更新时间</strong><?php echo $theme->update; ?></p>
<p class="meta-item"><strong>作者</strong><?php echo $theme->author; ?></p>
<p class="meta-item links">
<strong>使用说明</strong>
<a href="<?php echo $theme->help_url; ?>" target="_blank" rel="nofollow noopener noreferrer">
<?php echo $theme->help_url; ?>
</a>
</p>
<p class="meta-item links">
<strong>主页</strong>
<a href="<?php echo $theme->homepage; ?>" target="_blank" rel="nofollow noopener noreferrer">
<?php echo $theme->homepage; ?>
</a>
</p>
</div>
</div>
<!-- ...existing code (原布局结构已替换为上方 page-wrap,更现代化) ... -->
</body>
</html>

2
templates/admin/static/embed.js

@ -698,6 +698,8 @@ layui.use(['element','table','layer','form','upload','iconHhysFa'], function(){ @@ -698,6 +698,8 @@ layui.use(['element','table','layer','form','upload','iconHhysFa'], function(){
//添加分类目录
form.on('submit(add_category)', function(data){
// console.log(data);
// return;
$.post('/index.php?c=api&method=add_category',data.field,function(data,status){
//如果添加成功
if(data.code == 0) {

2
version.txt

@ -1 +1 @@ @@ -1 +1 @@
v1.2.1-20250819
v1.2.2-20250901
Loading…
Cancel
Save