# 1. 切换到master分支
git checkout master
# 2. 将test分支合并到master
git merge test
如果有冲突需要解决
如果在合并过程中出现冲突,需要手动解决:
# 1. 查看冲突文件
git status
# 2. 手动编辑冲突文件,解决冲突
# 3. 添加解决后的文件
git add .
# 4. 完成合并
git commit
git branch
git branch -a
git branch -r
git branch -v
在你的项目中运行 git branch,应该能看到类似这样的输出:
* master
test
DELLEVIN@DESKTOP-HISDDCH D:\Proj_Dev\Other\xyjq\xyjq-mp-vue git:6afbbee ❯❯❯ git branch
* (HEAD detached from d7244e3)
master
test
# 1. 切换到master分支
git checkout master
# 2. 将之前分离HEAD状态下的更改合并过来
# 如果你知道那个commit的hash(比如d7244e3),可以这样:
git merge d7244e3
# 1. 基于当前状态创建并切换到新分支
git checkout -b new_feature
# 2. 切换到master
git checkout master
# 3. 合并新分支
git merge new_feature
# 4. 删除临时分支(可选)
git branch -d new_feature
]]>定位到地址文件是lib下面的ipipfree.ipdb,删掉这个就好,用不到了。这个最近的时间是2019年的。真的很无语的。
接下来定位到所在位置是Access_Core.php这个文件的这里代码。(Access_IpDb.php这个也可以删除)
try {
$ipdb = new Access_IpDb(dirname(__file__).'/lib/ipipfree.ipdb');
$city = $ipdb->findInfo($ip, 'CN');
// 写入日志
error_log("IP: {$ip}\nCity Info: " . print_r($city, true), 3, '/tmp/access_debug.log');
$ip_country = $city->country_name;
if($ip_country == '中国') {
$ip_province = $city->region_name;
$ip_city = $city->city_name;
} else {
$ip_province = $ip_city = NULL;
}
} catch(Exception $e) {
$ip_country = $ip_province = $ip_city = '未知';
}
然后根据数据格式,改成他的数据样式的。
try {
// 检查必要的文件是否存在
$dbFile = dirname(__FILE__) . '/lib/ip2region.xdb';
$classFile = dirname(__FILE__) . '/lib/XdbSearcher.php';
if (!file_exists($dbFile)) {
throw new Exception("Ip2region database file not found: {$dbFile}");
}
if (!file_exists($classFile)) {
throw new Exception("XdbSearcher class file not found: {$classFile}");
}
require_once $classFile;
$searcher = XdbSearcher::newWithFileOnly($dbFile);
$region = $searcher->search($ip);
if ($region === null) {
throw new Exception("IP2Region search failed for IP: {$ip}");
}
// 调试日志
error_log("IP: {$ip}\nRegion Info: " . print_r($region, true), 3, '/tmp/access_debug.log');
// 解析数据 (格式: 国家|区域|省份|城市|ISP)
$regionArray = explode('|', $region);
// 清理数据
$cleanData = function($data) {
return (!empty($data) && $data !== '0') ? $data : '';
};
$country = $cleanData($regionArray[0]);
$region_info = $cleanData($regionArray[1]);
$province = $cleanData($regionArray[2]);
$city = $cleanData($regionArray[3]);
// 设置最终保存到数据库的字段
$ip_country = !empty($country) ? $country : '未知';
// 无论国内外都保存区域和城市信息
$ip_province = '';
$ip_city = '';
if (!empty($province)) {
$ip_province = $province;
} elseif (!empty($region_info)) {
// 如果省份为空,但区域不为空,可以用区域代替
$ip_province = $region_info;
}
if (!empty($city)) {
$ip_city = $city;
}
} catch(Exception $e) {
error_log("IP解析异常:" . $e->getMessage(), 3, '/tmp/access_debug.log');
$ip_country = '未知';
$ip_province = '';
$ip_city = '';
}
这样就可以了。
]]>HTTPS页面 (aaa.com)
└── HTTP iframe (bbb.com)
└── HTTP frame (ccc.com)
大概是这种形式的,所以在第一个a网站是我自己写的,所以我就选择了直接使用http替换成https的了
然后配置b网站
server {
listen 80;
server_name www.bbb.com;
# 强制跳转到 HTTPS
return 301 https://$host$request_uri;
}
# 处理www.bbb.com 的 HTTPS 请求
server {
listen 443 ssl;
server_name www.bbb.com;
# SSL 证书配置(你需要配置自己的证书)
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# 添加安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "upgrade-insecure-requests";
# 代理到后端应用
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 特别处理企业查看接口,确保内容中的HTTP链接被替换
location /rotech-xyjq-api/api/enterprise/view {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 替换内容中的HTTP链接为HTTPS
sub_filter 'http://b-plugin.qixin.com/' 'https://b-plugin.qixin.com/';
sub_filter 'http://b-plugin.qixin.com' 'https://b-plugin.qixin.com';
sub_filter_once off;
}
}
这样就可以再a网站加载c网站的了,可以无限套娃了,前提是每个娃娃都有https这个。
]]>效果为这样的:
typecho_contents这个表增加一个字段post_links,类型为text
路径在var/Widget/Contents/Post下面的Edit.php文件
文件地址在admin路径下的write-post.php文件,新增部分。css暂时不写了
<!-- 引用文章开始 -->
<section class="typecho-post-option reference-links-section" id="reference-links-section">
<label class="typecho-label toggle-reference-section" style="cursor: pointer;">
<span class="toggle-icon" style="float: left;"><i class="i-caret-right"></i></span>
<?php _e('参考文章'); ?>
</label>
<div class="reference-links-container" id="post-links-container">
<?php
// 从数据库获取数据
$links = [];
if ($post->have()) {
$db = Typecho\Db::get();
$result = $db->fetchRow($db->select('post_links')->from('table.contents')->where('cid = ?', $post->cid));
if (!empty($result) && !empty($result['post_links'])) {
$postLinks = $result['post_links'];
$links = json_decode($postLinks, true);
if (!is_array($links)) $links = [];
}
}
// 如果没有数据,添加一个空行
if (empty($links)) {
$links = [['name' => '', 'link' => '']];
}
foreach ($links as $index => $link):
?>
<div class="reference-link-item">
<div class="reference-link-inputs">
<input type="text"
name="post_links[<?php echo $index; ?>][name]"
placeholder="<?php _e('链接名称'); ?>"
value="<?php echo htmlspecialchars($link['name'] ?? ''); ?>"
class="text reference-link-name" />
<input type="url"
name="post_links[<?php echo $index; ?>][link]"
placeholder="<?php _e('https://'); ?>"
value="<?php echo htmlspecialchars($link['link'] ?? ''); ?>"
class="text reference-link-url" />
</div>
<div class="reference-link-actions">
<button type="button" class="btn btn-xs remove-reference-link" title="<?php _e('删除'); ?>">
<i class="i-delete"></i>
</button>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="reference-links-footer">
<button type="button" id="add-reference-link" class="btn btn-xs">
<i class="i-plus"></i> <?php _e('添加引用'); ?>
</button>
<span class="reference-links-help"><?php _e('温故而知新,添加相关的参考链接,记忆更牢固。'); ?></span>
</div>
</section>
<!-- 引用文章结束 -->
受限于代码长度过长,使得文章无法正常解析,可以点击链接下载。
因为后台接口少了统计接口,所以这里需要手动后台添加。目录在安装目录下面的/var/Widget/Contents/Attachment
这个目录, 然后编辑Admin.php。复制以下代码即可。
<?php
namespace Widget\Contents\Attachment;
use Typecho\Config;
use Typecho\Db;
use Typecho\Db\Exception;
use Typecho\Db\Query;
use Typecho\Widget\Helper\PageNavigator\Box;
use Widget\Base\Contents;
use Typecho\Common;
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
/**
* 文件管理列表组件
*
* @category typecho
* @package Widget
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
*/
class Admin extends Contents
{
/**
* 用于计算数值的语句对象
*
* @var Query
*/
private $countSql;
/**
* 所有文章个数
*
* @var integer
*/
private $total = false;
/**
* 当前页
*
* @var integer
*/
private $currentPage;
/**
* 执行函数
*
* @return void
* @throws Exception|\Typecho\Widget\Exception
*/
public function execute()
{
$this->parameter->setDefault('pageSize=20');
$this->currentPage = $this->request->get('page', 1);
/** 构建基础查询 */
$select = $this->select()->where('table.contents.type = ?', 'attachment');
/** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
if (!$this->user->pass('editor', true)) {
$select->where('table.contents.authorId = ?', $this->user->uid);
}
/** 过滤标题 */
if (null != ($keywords = $this->request->filter('search')->keywords)) {
$args = [];
$keywordsList = explode(' ', $keywords);
$args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
foreach ($keywordsList as $keyword) {
$args[] = '%' . $keyword . '%';
}
call_user_func_array([$select, 'where'], $args);
}
/** 给计算数目对象赋值,克隆对象 */
$this->countSql = clone $select;
/** 提交查询 */
$select->order('table.contents.created', Db::SORT_DESC)
->page($this->currentPage, $this->parameter->pageSize);
$this->db->fetchAll($select, [$this, 'push']);
}
/**
* 输出分页
*
* @return void
* @throws Exception|\Typecho\Widget\Exception
*/
public function pageNav()
{
$query = $this->request->makeUriByRequest('page={page}');
/** 使用盒状分页 */
$nav = new Box(
false === $this->total ? $this->total = $this->size($this->countSql) : $this->total,
$this->currentPage,
$this->parameter->pageSize,
$query
);
$nav->render('«', '»');
}
/**
* 所属文章
*
* @return Config
* @throws Exception
*/
protected function ___parentPost(): Config
{
return new Config($this->db->fetchRow(
$this->select()->where('table.contents.cid = ?', $this->parentId)->limit(1)
));
}
/**
* 获取附件的 URL 地址
*
* @return string
*/
protected function ___attachmentUrl(): string
{
if (!empty($this->attachment) && !empty($this->attachment->path)) {
// 从 path 字段构建 URL
$path = $this->attachment->path;
// 移除开头的斜杠(如果有的话)
$path = ltrim($path, '/');
return $this->options->siteUrl . $path;
}
// 如果 path 不存在,尝试从 text 字段解析
if (!empty($this->___attachment())) {
$attachment = $this->___attachment();
if (!empty($attachment['path'])) {
$path = ltrim($attachment['path'], '/');
return $this->options->siteUrl . $path;
}
}
return '';
}
/**
* 解析附件信息
*
* @return array
*/
protected function ___attachment(): array
{
if (!empty($this->text)) {
$attachment = @unserialize($this->text);
if (is_array($attachment)) {
return $attachment;
}
}
return [];
}
/**
* 重写 permalink 方法,使用解析后的 URL
*
* @return string
*/
protected function ___permalink(): string
{
return $this->___attachmentUrl();
}
/**
* 获取统计信息
*
* @return array
* @throws Exception
*/
public function getStats(): array
{
$select = $this->select()->where('table.contents.type = ?', 'attachment');
/** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
if (!$this->user->pass('editor', true)) {
$select->where('table.contents.authorId = ?', $this->user->uid);
}
// 总文件数
$total = $this->size(clone $select);
// 图片文件数
$imageSelect = clone $select;
$imageSelect->join('table.fields', 'table.contents.cid = table.fields.cid', Db::LEFT_JOIN)
->where('table.fields.name = ?', 'mime')
->where('table.fields.str_value LIKE ?', 'image/%');
$imageCount = $this->size($imageSelect);
// 未归档文件数
$unattachedSelect = clone $select;
$unattachedSelect->where('table.contents.parent = ?', 0);
$unattachedCount = $this->size($unattachedSelect);
return [
'total' => $total,
'images' => $imageCount,
'unattached' => $unattachedCount
];
}
/**
* 获取总文件数
*
* @return int
* @throws Exception
*/
public function getTotalCount(): int
{
$select = $this->select()->where('table.contents.type = ?', 'attachment');
/** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
if (!$this->user->pass('editor', true)) {
$select->where('table.contents.authorId = ?', $this->user->uid);
}
return $this->size($select);
}
/**
* 获取图片文件数
*
* @return int
* @throws Exception
*/
public function getImageCount(): int
{
$select = $this->select()->where('table.contents.type = ?', 'attachment');
/** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
if (!$this->user->pass('editor', true)) {
$select->where('table.contents.authorId = ?', $this->user->uid);
}
// 通过 MIME 类型过滤图片
$select->where('table.contents.text LIKE ?', '%image/%');
return $this->size($select);
}
/**
* 获取未归档文件数
*
* @return int
* @throws Exception
*/
public function getUnattachedCount(): int
{
$select = $this->select()->where('table.contents.type = ?', 'attachment');
/** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
if (!$this->user->pass('editor', true)) {
$select->where('table.contents.authorId = ?', $this->user->uid);
}
// 未归档文件(parent = 0)
$select->where('table.contents.parent = ?', 0);
return $this->size($select);
}
}
通过查看后台路径可以得知是manage-medias.php这个文件,所以更改一下这个文件就可以了。更改前注意文件备份。
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
$attachments = \Widget\Contents\Attachment\Admin::alloc();
// 获取统计信息
$totalCount = $attachments->getTotalCount();
$imageCount = $attachments->getImageCount();
$unattachedCount = $attachments->getUnattachedCount();
// 获取PHP上传限制
$phpMaxFilesize = function_exists('ini_get') ? trim(ini_get('upload_max_filesize')) : 0;
if (preg_match("/^([0-9]+)([a-z]{1,2})$/i", $phpMaxFilesize, $matches)) {
$phpMaxFilesize = strtolower($matches[1] . $matches[2] . (1 == strlen($matches[2]) ? 'b' : ''));
}
?>
<style>
/* 上传区域样式 */
.upload-section {
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 20px;
margin: 20px 0;
display: none;
}
.upload-section.show {
display: block;
}
.upload-section h3 {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
color: #333;
}
.upload-controls {
display: flex;
gap: 15px;
align-items: center;
flex-wrap: wrap;
margin-bottom: 15px;
}
/* 改为链接样式 */
.upload-link {
color: #007cba;
text-decoration: underline;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 4px;
transition: color 0.2s;
}
.upload-link:hover {
color: #005a87;
text-decoration: none;
}
.upload-link i {
font-size: 16px;
}
.upload-hint {
color: #666;
font-size: 13px;
}
.upload-area {
border: 2px dashed #ddd;
border-radius: 6px;
padding: 30px;
text-align: center;
background: #fafafa;
transition: all 0.3s;
margin-top: 10px;
}
.upload-area.dragover {
border-color: #007cba;
background: #f0f8ff;
}
.upload-area-text {
color: #666;
margin-bottom: 10px;
}
.browse-link {
color: #007cba;
text-decoration: underline;
cursor: pointer;
}
.browse-link:hover {
color: #005a87;
}
/* 上传进度条 */
.upload-progress {
display: none;
margin-top: 15px;
}
.progress-bar {
width: 100%;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: #007cba;
width: 0%;
transition: width 0.3s;
}
.progress-text {
text-align: center;
font-size: 12px;
color: #666;
margin-top: 5px;
}
.media-stats {
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.media-stats h3 {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
color: #666;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
}
.stat-item {
text-align: center;
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
}
.stat-number {
font-size: 24px;
font-weight: bold;
color: #007cba;
margin-bottom: 5px;
}
.stat-label {
font-size: 13px;
color: #666;
}
/* 预览列样式 */
.preview-cell {
text-align: center;
}
.media-preview-img {
width: 50px;
height: 50px;
object-fit: cover;
border-radius: 4px;
border: 1px solid #ddd;
cursor: pointer;
transition: transform 0.2s ease;
}
.media-preview-img:hover {
transform: scale(1.1);
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.media-preview-icon {
font-size: 24px;
color: #999;
}
/* 保持原有样式 */
.typecho-list-operate {
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.typecho-pager {
margin-top: 20px;
text-align: center;
}
/* 图片预览模态框样式 */
.modal {
display: none;
position: fixed;
z-index: 10000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
backdrop-filter: blur(5px);
}
.modal-content {
position: relative;
margin: 5% auto;
padding: 20px;
width: 90%;
max-width: 900px;
max-height: 90vh;
text-align: center;
}
.modal-image {
max-width: 100%;
max-height: 80vh;
object-fit: contain;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
}
.close {
position: absolute;
top: 10px;
right: 25px;
color: #fff;
font-size: 35px;
font-weight: bold;
cursor: pointer;
z-index: 10001;
}
.close:hover {
color: #ccc;
}
.modal-title {
color: white;
margin-top: 10px;
font-size: 16px;
font-weight: normal;
}
/* 上传按钮样式 - 与清理按钮统一 */
.btn-upload {
background: #28a745;
border-color: #28a745;
color: white;
margin-left: 10px;
}
.btn-upload:hover {
background: #218838;
border-color: #1e7e34;
}
/* 取消按钮样式 */
#cancelUploadBtn {
margin-left: 10px;
}
/* 隐藏的文件输入框 */
#fileInput {
display: none;
}
/* 响应式设计 */
@media (max-width: 768px) {
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
.modal-content {
width: 95%;
margin: 10% auto;
}
.modal-image {
max-height: 70vh;
}
.upload-controls {
flex-direction: column;
align-items: stretch;
}
.btn-upload {
margin-left: 0;
margin-top: 5px;
}
}
</style>
<div class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12">
<!-- 统计信息 -->
<div class="media-stats">
<h3>媒体文件统计</h3>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number"><?php echo $totalCount; ?></div>
<div class="stat-label">总文件数</div>
</div>
<div class="stat-item">
<div class="stat-number"><?php echo $imageCount; ?></div>
<div class="stat-label">图片文件</div>
</div>
<div class="stat-item">
<div class="stat-number"><?php echo $stat->publishedPostsNum; ?></div>
<div class="stat-label">文章数</div>
</div>
<div class="stat-item">
<div class="stat-number"><?php echo $unattachedCount; ?></div>
<div class="stat-label">未归档文件</div>
</div>
</div>
</div>
<div class="typecho-list-operate clearfix">
<form method="get">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些文件吗?'); ?>"
href="<?php $security->index('/action/contents-attachment-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
</ul>
<button class="btn btn-s btn-warn btn-operate"
href="<?php $security->index('/action/contents-attachment-edit?do=clear'); ?>"
lang="<?php _e('您确认要清理未归档的文件吗?'); ?>"><?php _e('清理未归档文件'); ?></button>
<!--<button type="button" class="btn btn-s btn-upload" id="toggleUploadBtn">-->
<!-- <?php _e('上传文件'); ?>-->
<!--</button>-->
<!-- 修改这里:添加条件显示 -->
<button type="button" class="btn btn-s btn-upload" id="toggleUploadBtn">
<?php _e('上传文件'); ?>
</button>
<button type="button" class="btn btn-s" id="cancelUploadBtn" style="display: none;">
<?php _e('取消上传'); ?>
</button>
</div>
</div>
<div class="search" role="search">
<?php if ('' != $request->keywords): ?>
<a href="<?php $options->adminUrl('manage-medias.php'); ?>"><?php _e('« 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo $request->filter('html')->keywords; ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
</div><!-- end .typecho-list-operate -->
<!-- 上传区域 - 默认隐藏 -->
<div class="upload-section" id="uploadSection">
<h3><?php _e('上传文件'); ?></h3>
<div class="upload-controls">
<!-- 改为链接形式 -->
<a href="javascript:;" class="upload-link" id="uploadButton">
<!--<i class="i-upload"></i> -->
<?php _e('选择文件'); ?>
</a>
<span class="upload-hint"><?php _e('或拖放文件到下方区域'); ?></span>
</div>
<div class="upload-area" id="uploadArea">
<div class="upload-area-text">
<?php _e('拖放文件到这里'); ?>
</div>
<div>
<?php _e('或者 %s浏览文件%s', '<span class="browse-link" id="browseLink">', '</span>'); ?>
</div>
</div>
<!-- 上传进度条 -->
<div class="upload-progress" id="uploadProgress">
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="progress-text" id="progressText">0%</div>
</div>
<!-- 隐藏的文件输入框 -->
<input type="file" id="fileInput" multiple style="display: none;">
</div>
<form method="post" name="manage_medias" class="operate-form">
<div class="typecho-table-wrap">
<table class="typecho-list-table draggable">
<colgroup>
<col width="20" class="kit-hidden-mb"/>
<col width="6%" class="kit-hidden-mb"/>
<col width="10%" class="kit-hidden-mb"/> <!-- 预览列 -->
<col width="25%"/>
<col width="" class="kit-hidden-mb"/>
<col width="25%" class="kit-hidden-mb"/>
<col width="16%"/>
</colgroup>
<thead>
<tr>
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"><?php _e('预览'); ?></th>
<th><?php _e('文件名'); ?></th>
<th class="kit-hidden-mb"><?php _e('上传者'); ?></th>
<th class="kit-hidden-mb"><?php _e('所属文章'); ?></th>
<th><?php _e('发布日期'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($attachments->have()): ?>
<?php while ($attachments->next()): ?>
<?php
$mime = \Typecho\Common::mimeIconType($attachments->attachment->mime);
$isImage = strpos($attachments->attachment->mime, 'image/') === 0;
$fileUrl = $attachments->attachmentUrl;
?>
<tr id="<?php $attachments->theId(); ?>">
<td class="kit-hidden-mb">
<input type="checkbox" class="typecho-table-checkbox"
value="<?php $attachments->cid(); ?>" name="cid[]"/>
</td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-comments.php?cid=' . $attachments->cid); ?>"
class="balloon-button size-<?php echo \Typecho\Common::splitByCount($attachments->commentsNum, 1, 10, 20, 50, 100); ?>"><?php $attachments->commentsNum(); ?></a>
</td>
<td class="kit-hidden-mb preview-cell">
<?php if ($isImage && !empty($fileUrl)): ?>
<img src="<?php echo $fileUrl; ?>"
class="media-preview-img"
alt="<?php $attachments->title(); ?>"
data-full-src="<?php echo $fileUrl; ?>"
data-title="<?php $attachments->title(); ?>">
<?php else: ?>
<i class="mime-<?php echo $mime; ?> media-preview-icon"></i>
<?php endif; ?>
</td>
<td>
<i class="mime-<?php echo $mime; ?>"></i>
<a href="<?php $options->adminUrl('media.php?cid=' . $attachments->cid); ?>"><?php $attachments->title(); ?></a>
<?php if (!empty($fileUrl)): ?>
<a href="<?php echo $fileUrl; ?>" target="_blank"
title="<?php _e('浏览 %s', $attachments->title); ?>"><i
class="i-exlink"></i></a>
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><?php $attachments->author(); ?></td>
<td class="kit-hidden-mb">
<?php if ($attachments->parentPost->cid): ?>
<a href="<?php $options->adminUrl('write-' . (0 === strpos($attachments->parentPost->type, 'post') ? 'post' : 'page') . '.php?cid=' . $attachments->parentPost->cid); ?>"><?php $attachments->parentPost->title(); ?></a>
<?php else: ?>
<span class="description"><?php _e('未归档'); ?></span>
<?php endif; ?>
</td>
<td><?php $attachments->dateWord(); ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="7"><h6 class="typecho-list-table-title"><?php _e('没有任何文件'); ?></h6>
</td>
</tr>
<?php endif; ?>
</tbody>
</table><!-- end .typecho-list-table -->
</div><!-- end .typecho-table-wrap -->
</form><!-- end .operate-form -->
<div class="typecho-list-operate clearfix">
<form method="get">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些文件吗?'); ?>"
href="<?php $security->index('/action/contents-attachment-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
</ul>
</div>
<button class="btn btn-s btn-warn btn-operate"
href="<?php $security->index('/action/contents-attachment-edit?do=clear'); ?>"
lang="<?php _e('您确认要清理未归档的文件吗?'); ?>"><?php _e('清理未归档文件'); ?></button>
</div>
<?php if ($attachments->have()): ?>
<ul class="typecho-pager">
<?php $attachments->pageNav(); ?>
</ul>
<?php endif; ?>
</form>
</div><!-- end .typecho-list-operate -->
</div>
</div><!-- end .typecho-page-main -->
</div>
</div>
<!-- 图片预览模态框 -->
<div id="imageModal" class="modal">
<span class="close">×</span>
<div class="modal-content">
<img class="modal-image" id="modalImage" src="" alt="">
<div class="modal-title" id="modalTitle"></div>
</div>
</div>
<script src="<?php $options->adminStaticUrl('js', 'moxie.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'plupload.js'); ?>"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取元素
const toggleUploadBtn = document.getElementById('toggleUploadBtn');
const cancelUploadBtn = document.getElementById('cancelUploadBtn');
const uploadSection = document.getElementById('uploadSection');
const uploadButton = document.getElementById('uploadButton');
const browseLink = document.getElementById('browseLink');
const fileInput = document.getElementById('fileInput');
const uploadArea = document.getElementById('uploadArea');
const uploadProgress = document.getElementById('uploadProgress');
const progressFill = document.getElementById('progressFill');
const progressText = document.getElementById('progressText');
// 模态框元素
const modal = document.getElementById('imageModal');
const modalImg = document.getElementById('modalImage');
const modalTitle = document.getElementById('modalTitle');
const closeBtn = document.querySelector('.close');
// 切换上传区域显示/隐藏
// toggleUploadBtn.addEventListener('click', function() {
// uploadSection.classList.toggle('show');
// // 滚动到上传区域
// if (uploadSection.classList.contains('show')) {
// uploadSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
// }
// });
// 切换上传区域显示/隐藏
toggleUploadBtn.addEventListener('click', function() {
uploadSection.classList.add('show');
// 显示取消按钮,隐藏上传按钮
toggleUploadBtn.style.display = 'none';
cancelUploadBtn.style.display = 'inline-block';
// 滚动到上传区域
uploadSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
});
// 取消上传
cancelUploadBtn.addEventListener('click', function() {
uploadSection.classList.remove('show');
// 显示上传按钮,隐藏取消按钮
toggleUploadBtn.style.display = 'inline-block';
cancelUploadBtn.style.display = 'none';
});
// 点击链接触发文件选择
uploadButton.addEventListener('click', function(e) {
e.preventDefault();
// 触发隐藏的文件输入框
fileInput.click();
});
// 点击浏览链接也触发文件选择
browseLink.addEventListener('click', function() {
fileInput.click();
});
// 初始化上传器
var uploader = new plupload.Uploader({
runtimes: 'html5,flash,html4',
browse_button: 'fileInput', // 绑定到隐藏的文件输入框
container: 'uploadArea',
drop_element: 'uploadArea',
url: '<?php $security->index('/action/upload'); ?>',
flash_swf_url: '<?php $options->adminStaticUrl('js', 'Moxie.swf'); ?>',
filters: {
max_file_size: '<?php echo $phpMaxFilesize ?>',
mime_types: [{'title': '<?php _e('允许上传的文件'); ?>', 'extensions': '<?php echo implode(',', $options->allowedAttachmentTypes); ?>'}]
},
init: {
PostInit: function() {
console.log('Uploader initialized');
},
FilesAdded: function(up, files) {
console.log('Files added:', files);
// 显示进度条
uploadProgress.style.display = 'block';
// 开始上传
up.start();
},
UploadProgress: function(up, file) {
// 更新进度条
var percent = file.percent;
progressFill.style.width = percent + '%';
progressText.textContent = percent + '%';
},
FileUploaded: function(up, file, response) {
console.log('File uploaded:', response);
if (response.status === 200) {
try {
var result = JSON.parse(response.response);
if (result && result[1]) {
// 上传成功,刷新页面显示新文件
location.reload();
}
} catch (e) {
console.error('Parse error:', e);
}
}
// 隐藏进度条
setTimeout(function() {
uploadProgress.style.display = 'none';
progressFill.style.width = '0%';
progressText.textContent = '0%';
// 隐藏上传区域
uploadSection.classList.remove('show');
}, 1000);
},
Error: function(up, err) {
console.error('Upload error:', err);
alert('上传出错: ' + err.message);
// 隐藏进度条
uploadProgress.style.display = 'none';
}
}
});
uploader.init();
// 拖拽事件
uploadArea.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', function(e) {
e.preventDefault();
this.classList.remove('dragover');
});
uploadArea.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('dragover');
});
// 图片预览功能
const previewImages = document.querySelectorAll('.media-preview-img');
previewImages.forEach(img => {
img.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const fullSrc = this.getAttribute('data-full-src');
const title = this.getAttribute('data-title');
if (fullSrc) {
modalImg.src = fullSrc;
modalTitle.textContent = title || '';
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
}
});
});
// 关闭模态框
function closeModal() {
modal.style.display = 'none';
document.body.style.overflow = '';
}
closeBtn.addEventListener('click', closeModal);
modal.addEventListener('click', function(e) {
if (e.target === modal) {
closeModal();
}
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && modal.style.display === 'block') {
closeModal();
}
});
});
</script>
<?php
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
include 'footer.php';
?>
]]>sudo apt update && sudo apt upgrade -y
sudo apt install zsh git curl wget -y
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
编辑 ~/.zshrc
:
vim ~/.zshrc
注释掉 ZSH_THEME="robbyrussell"
添加 ZSH_THEME="powerlevel10k/powerlevel10k"
# 下载
wget https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/FiraCode.zip
# 解压
unzip FiraCode.zip -d ~/.local/share/fonts/
# 刷新缓存
fc-cache -fv
# 删除
rm FiraCode.zip
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
编辑配置文件
vim ~/.zshrc
文件-代表删除+代表新增
- plugins=(git)
+ plugins=(
+ git
+ zsh-autosuggestions
+ zsh-syntax-highlighting
+ )
配置完毕后输入
exec zsh
重启终端
which zsh
查看安装位置
chsh -s $(which zsh)
安装后重启电脑即可
如果想要重新配置可以输入即可
p10k configure
]]>设置代理
export http_proxy="http://127.0.0.1:20171"
export https_proxy="http://127.0.0.1:20171"
取消设置代理
unset http_proxy https_proxy
此方式不支持socket5代理
前情提要:因为要按照某个软件,但是有网络监测机制,一直报错,所以就需要通过代理来运行。
安装:sudo apt update
sudo apt install proxychains -y
配置:
sudo vim /etc/proxychains.conf
在末尾添加socks5 127.0.0.1 20170
然后就可以使用了。
重要知识点:ping 不能被代理!
ping 使用的是 ICMP 协议,不是 TCP/HTTP/SOCKS。
proxychains 只能代理 TCP 和 UDP 连接(比如 curl, wget, git, ssh 等)。
所以你用 proxychains ping ... 是无效的,而且会报错或被忽略。
正确测试 proxychains 是否工作的命令是使用 curl 或 wget
(base) dellevin@dellevin-G3-3579:~/Desktop/WhiteSur-gtk-theme$ proxychains curl -v google.com
ProxyChains-3.1 (http://proxychains.sf.net)
|DNS-request| google.com
|S-chain|-<>-127.0.0.1:20170-<><>-4.2.2.2:53-<><>-OK
|DNS-response| google.com is 142.250.189.238
* Host google.com:80 was resolved.
* IPv6: (none)
* IPv4: 142.250.189.238
* Trying 142.250.189.238:80...
|S-chain|-<>-127.0.0.1:20170-<><>-142.250.189.238:80-<><>-OK
* Connected to google.com (142.250.189.238) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: google.com
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-p85NwNurE8Yc0yBkcHZmUQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
< Date: Sat, 23 Aug 2025 05:50:49 GMT
< Expires: Mon, 22 Sep 2025 05:50:49 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 0
< X-Frame-Options: SAMEORIGIN
<
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
* Connection #0 to host google.com left intact
这样说明我已经可以正常访问了
]]>但是我不是vip用户,宝塔面板也是关闭一些权限,剩下的哪些vip功能还是收费,看着碍眼,索性去照代码里面删掉该部分即可。
本教程只适用于宝塔面板v11.0.0。其他版本还需要自行测试。
设置->常用设置->面板栏隐藏,隐藏如下功能
WAF、WP Tools、多用户、邮局、节点管理
一开始我本以为这个是在utils-lib.js里面带着的,后来通过减慢请求查看到是在请求里面带着的。通过搜索关键词get_pay_type
发现,是通过getRecommendContent这个请求函数带过来的。所以我们需要在这里设置返还值为空即将getRecommendContent=()=>useAxios.post("ajax/get_pay_type")
替换成getRecommendContent=()=>{return []}
utils-lib.js去掉如下内容
{path:"ssh",name:"ssh",meta:{title:"SSH登录日志"},component:()=>__vitePreload((()=>import("./index52.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)},
,{path:"auto-deploy",name:"auto-deploy",meta:{title:"自动部署"},component:()=>__vitePreload((()=>import("./index84.js?v=1754557180").then((e=>e.i))),__vite__mapDeps([]),import.meta.url)}
,{path:"daily",name:"daily",meta:{title:"面板日报"},component:()=>__vitePreload((()=>import("./index12.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)}
,{path:"safe-detect",name:"safe-detect",meta:{title:"安全检测"},component:()=>__vitePreload((()=>import("./index41.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)},{path:"keyword",name:"keyword",meta:{title:"违规词检测"},component:()=>__vitePreload((()=>import("./index42.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)},{path:"php-safe",name:"php-safe",meta:{title:"PHP网站安全"},component:()=>__vitePreload((()=>import("./index43.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)},{path:"intrusion",name:"intrusion",meta:{title:"入侵防御"},component:()=>__vitePreload((()=>import("./index44.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)},{path:"fixed",name:"fixed",meta:{title:"系统加固"},component:()=>__vitePreload((()=>import("./index45.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)},{path:"network-scan",name:"network-scan",meta:{title:"扫描感知"},component:()=>__vitePreload((()=>import("./index46.js?v=1754557180")),__vite__mapDeps([]),import.meta.url)}
]]>之前想买个mac尝尝鲜的,但是受限于昂贵的价格所以买了个丐版的mac mini。but。。但是新鲜感过去之后好久没用了。
ps:果然,mac不适合我。
但是总不能一直放着呀,事物存在的本身需要让其发挥出所具有的价值才可以,所以准备改造成一个小服务器(8G的内存都可以跑4b的ai了)。
1.用户与群组->打开自动以此身份登录
2.节能->打开唤醒以供网络访问
3.节能->打开断电后自动启动(有需求打开,无需求可以选择不打开)
4.通用->共享->打开远程桌面(有其他需求可以选择性打开)
5.屏幕->所有都设置为不锁屏
6.如果你有需求可以将dhcp设置为局域网静态ip。
这里我用的是frp-panel。因为m1芯片属于arm架构的,所以客户端需要下载frp-panel-client-darwin-arm64这一个。
开源地址:https://github.com/VaalaCat/frp-panel/
搭建流程和操作步骤详见官方文档。
面板设置好之后添加客户端。mac 端运行给出的命令即可。
如果无法运行需要添加执行权限
chmod +x frp-panel-arm
vim ~/Library/LaunchAgents/com.frp.panel.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.frp.panel</string>
<key>ProgramArguments</key>
<array>
<string>/Users/您的用户名/Downloads/frp-panel-arm</string>
<string>client</string>
<string>-s</string>
<string>6ed79539-8309-4a84-845d-598568add8d8</string>
<string>-i</string>
<string>admin.c.macM1-arm</string>
<string>--api-url</string>
<string>http://152.136.153.72:9000</string>
<string>--rpc-url</string>
<string>grpc://152.136.153.72:9001</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/com.frp.panel.plist
launchctl start com.frp.panel
至此,设置完毕,可以在进程里面查看到frp-panel的进程是否在运行。或者在面板界面查看设备是否上线了。
]]>直接将该代码替换掉原本的代码即可:
<?php
namespace TypechoPlugin\HelloWorld;
use Typecho\Plugin\PluginInterface;
use Typecho\Widget\Helper\Form;
use Typecho\Widget\Helper\Form\Element\Text;
use Widget\Options;
use Widget\Stat;
use Typecho\Db;
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
/**
* Hello World
*
* @package HelloWorld
* @author 白荼
* @version 1.0.0
*/
class Plugin implements PluginInterface
{
/**
* 激活插件方法,如果激活失败,直接抛出异常
*/
public static function activate()
{
\Typecho\Plugin::factory('admin/menu.php')->navBar = __CLASS__ . '::render';
// 添加CSS和JS
\Typecho\Plugin::factory('admin/header.php')->header = __CLASS__ . '::header';
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*/
public static function deactivate()
{
}
/**
* 获取插件配置面板
*
* @param Form $form 配置面板
*/
public static function config(Form $form)
{
/** 分类名称 */
$name = new Text('word', null, 'Hello World', _t('说点什么'));
$form->addInput($name);
}
/**
* 个人用户的配置面板
*
* @param Form $form
*/
public static function personalConfig(Form $form)
{
}
/**
* 在header中添加CSS和JS
*/
public static function header($header)
{
$customCssJs = '
<!-- HelloWorld Plugin CSS -->
<style>
.helloworld-tooltip {
position: absolute;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
z-index: 9999;
min-width: 280px;
display: none;
font-size: 12px;
}
.helloworld-tooltip h4 {
margin: 0 0 10px 0;
padding: 0;
color: #333;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
font-size: 14px;
}
.helloworld-tooltip .comparison {
background: #f8f9fa;
border-left: 3px solid #007cba;
padding: 8px 12px;
margin: 10px 0;
border-radius: 0 4px 4px 0;
font-size: 13px;
}
.helloworld-tooltip ul {
list-style: none;
padding: 0;
margin: 0;
}
.helloworld-tooltip li {
padding: 5px 0;
border-bottom: 1px solid #f5f5f5;
line-height: 1.5;
}
.helloworld-tooltip li:last-child {
border-bottom: none;
}
.helloworld-tooltip strong {
color: #666;
font-weight: normal;
}
.helloworld-trigger {
cursor: pointer;
border-bottom: 1px dotted #BBBBBB;
}
.helloworld-trigger:hover {
color: #666 !important;
border-bottom-color: #666;
}
</style>
<!-- HelloWorld Plugin JS -->
<script>
(function() {
function initHelloWorldTooltip() {
var trigger = document.querySelector(".helloworld-trigger");
var tooltip = document.querySelector(".helloworld-tooltip");
if (trigger && tooltip) {
trigger.addEventListener("click", function(e) {
e.preventDefault();
e.stopPropagation();
// 计算位置
var rect = trigger.getBoundingClientRect();
var tooltipWidth = tooltip.offsetWidth || 280;
var tooltipHeight = tooltip.offsetHeight || 250;
// 默认位置
var left = rect.left + window.scrollX;
var top = rect.bottom + window.scrollY + 5;
// 边界检测
if (left + tooltipWidth > window.innerWidth + window.scrollX) {
left = window.innerWidth + window.scrollX - tooltipWidth - 10;
}
if (top + tooltipHeight > window.innerHeight + window.scrollY) {
top = rect.top + window.scrollY - tooltipHeight - 5;
}
tooltip.style.left = left + "px";
tooltip.style.top = top + "px";
tooltip.style.display = "block";
});
// 点击其他地方关闭
document.addEventListener("click", function(e) {
if (!tooltip.contains(e.target) && e.target !== trigger) {
tooltip.style.display = "none";
}
});
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initHelloWorldTooltip);
} else {
initHelloWorldTooltip();
}
})();
</script>';
return $header . $customCssJs;
}
/**
* 根据字数获取对应的文学著作比较
*/
private static function getLiteraryComparison($wordCount)
{
// 文学著作字数对照表(字数 => 著作名称)
$literaryWorks = [
// 百字级
50 => '几行诗句',
100 => '一段朋友圈文字',
200 => '一条微博内容',
500 => '一篇微博长文',
// 千字级
1000 => '一页A4纸手写内容',
1500 => '一页打印稿',
2000 => '一篇标准作文',
3000 => '一篇博客文章',
5000 => '一篇短篇小说',
8000 => '一篇中篇小说开头',
// 万字级(中国现代文学)
10000 => '《呐喊》',
12000 => '《彷徨》',
15000 => '《朝花夕拾》',
20000 => '《野草》',
25000 => '《故事新编》',
30000 => '《热风》',
35000 => '《坟》',
40000 => '《而已集》',
45000 => '《三闲集》',
// 万字级(其他现代文学)
50000 => '《沉沦》(郁达夫)',
55000 => '《春风沉醉的晚上》',
60000 => '《迟桂花》',
65000 => '《茑萝集》',
70000 => '《过去》',
75000 => '《薄奠》',
80000 => '《微雪的早晨》',
// 万字级(长篇小说选段)
85000 => '《骆驼祥子》前半部分',
90000 => '《二马》',
95000 => '《离婚》',
100000 => '《骆驼祥子》',
110000 => '《四世同堂》第一部分',
120000 => '《边城》',
130000 => '《湘行散记》',
140000 => '《长河》',
150000 => '《家》',
160000 => '《憩园》',
170000 => '《第四病室》',
180000 => '《春》',
190000 => '《秋》',
200000 => '《寒夜》',
// 20万字级
210000 => '《激流三部曲》选段',
220000 => '《爱情三部曲》选段',
230000 => '《抗战三部曲》选段',
240000 => '《人间词话》',
250000 => '《人间喜剧》选段',
260000 => '《巴黎圣母院》',
270000 => '《悲惨世界》选段',
280000 => '《九三年》',
290000 => '《海上劳工》',
300000 => '《笑面人》',
// 30万字级
310000 => '《约翰·克利斯朵夫》选段',
320000 => '《红与黑》',
330000 => '《巴马修道院》',
340000 => '《吕西安·娄凡》',
350000 => '《阿尔芒斯》',
360000 => '《法尼娜·法尼尼》',
370000 => '《瓦尼娜·瓦尼尼》',
380000 => '《红屋骑士》',
390000 => '《卡斯特罗修道院院长》',
400000 => '《意大利遗事》',
// 40万字级
410000 => '《三个火枪手》',
420000 => '《基督山伯爵》',
430000 => '《黑郁金香》',
440000 => '《二十年后》',
450000 => '《布拉热洛纳子爵》',
460000 => '《玛戈王后》',
470000 => '《蒙梭罗夫人》',
480000 => '《四十五卫士》',
490000 => '《侠隐记》',
500000 => '《红楼梦》(精简版)',
// 50万字级
520000 => '《水浒传》选段',
540000 => '《西游记》选段',
560000 => '《三国演义》选段',
580000 => '《儒林外史》',
600000 => '《聊斋志异》选段',
620000 => '《阅微草堂笔记》',
640000 => '《子不语》',
660000 => '《夜雨秋灯录》',
680000 => '《萤窗异草》',
700000 => '《耳食录》',
// 70万字级
720000 => '《浮生六记》',
740000 => '《影梅庵忆语》',
760000 => '《秋灯琐忆》',
780000 => '《香艳丛书》选段',
800000 => '《太平广记》选段',
820000 => '《夷坚志》选段',
840000 => '《剪灯新话》',
860000 => '《剪灯余话》',
880000 => '《觅灯因话》',
900000 => '《喻世明言》',
// 百万字级
920000 => '《警世通言》',
940000 => '《醒世恒言》',
960000 => '《初刻拍案惊奇》',
980000 => '《二刻拍案惊奇》',
1000000 => '《红楼梦》',
1050000 => '《镜花缘》',
1100000 => '《老残游记》',
1150000 => '《孽海花》',
1200000 => '《官场现形记》',
1250000 => '《二十年目睹之怪现状》',
// 百万字级以上
1300000 => '《资本论》第一卷',
1400000 => '《莎士比亚十四行诗集》',
1500000 => '《战争与和平》',
1600000 => '《安娜·卡列尼娜》',
1700000 => '《复活》',
1800000 => '《静静的顿河》',
1900000 => '《被开垦的处女地》',
2000000 => '《一个人的遭遇》',
2100000 => '《静静的顿河》全本',
2200000 => '《钢铁是怎样炼成的》',
2300000 => '《青年近卫军》',
2400000 => '《日瓦戈医生》',
2500000 => '《追忆似水年华》第一卷',
2600000 => '《约翰·克利斯朵夫》',
2700000 => '《马丁·伊登》',
2800000 => '《美国悲剧》',
2900000 => '《嘉莉妹妹》',
3000000 => '《资本论》全三卷',
3100000 => '《莎士比亚全集》悲剧部分',
3200000 => '《莎士比亚全集》喜剧部分',
3300000 => '《莎士比亚全集》历史剧部分',
3400000 => '《莎士比亚十四行诗全集》',
3500000 => '《莎士比亚全集》',
3600000 => '《追忆似水年华》第二卷',
3700000 => '《追忆似水年华》第三卷',
3800000 => '《追忆似水年华》第四卷',
3900000 => '《追忆似水年华》第五卷',
4000000 => '《追忆似水年华》',
4200000 => '《堂吉诃德》',
4400000 => '《神曲》',
4600000 => '《荷马史诗》',
4800000 => '《失乐园》',
5000000 => '《大英百科全书》一卷',
5500000 => '《大英百科全书》两卷',
6000000 => '《牛津英语词典》一卷',
6500000 => '《不列颠百科全书》',
7000000 => '《中国大百科全书》一卷',
7500000 => '《辞海》',
8000000 => '《康熙字典》',
9000000 => '《中华大字典》',
10000000 => '《大英百科全书》全套',
12000000 => '《四库全书》选段',
15000000 => '《永乐大典》残卷',
20000000 => '《古今图书集成》选段'
];
// 找到最接近的著作
$closestWork = '几行文字';
$closestWords = 0;
foreach ($literaryWorks as $words => $work) {
if ($wordCount >= $words) {
$closestWork = $work;
$closestWords = $words;
} else {
break;
}
}
// 计算倍数
if ($closestWords > 0) {
$multiple = round($wordCount / $closestWords, 1);
if ($multiple >= 2) {
return "约等于 {$multiple} 本 {$closestWork} 的字数";
} else {
return "约等于 1 本 {$closestWork} 的字数";
}
} else {
return "约等于几行文字的字数";
}
}
/**
* 获取统计信息
*/
private static function getStats()
{
$db = Db::get();
$user = \Typecho\Widget::widget('Widget_User');
// 最近登录时间
$lastLogin = $user->logged;
$lastLoginText = $lastLogin ? date('Y-m-d H:i:s', $lastLogin) : '未知';
// 文章数量
$postCount = $db->fetchObject($db->select(['COUNT(cid)' => 'num'])
->from('table.contents')
->where('type = ?', 'post')
->where('authorId = ?', $user->uid))->num;
// 字数统计(简单统计标题和内容长度)
$posts = $db->fetchAll($db->select('title', 'text')
->from('table.contents')
->where('type = ?', 'post')
->where('authorId = ?', $user->uid));
$totalWords = 0;
foreach ($posts as $post) {
$totalWords += mb_strlen($post['title'], 'UTF-8');
$totalWords += mb_strlen(strip_tags($post['text']), 'UTF-8');
}
// 最近文章时间
$lastPost = $db->fetchRow($db->select('created')
->from('table.contents')
->where('type = ?', 'post')
->where('authorId = ?', $user->uid)
->order('created', Db::SORT_DESC)
->limit(1));
$lastPostTime = $lastPost ? date('Y-m-d H:i:s', $lastPost['created']) : '暂无文章';
// 获取文学著作比较
$literaryComparison = self::getLiteraryComparison($totalWords);
return [
'lastLogin' => $lastLoginText,
'postCount' => $postCount,
'totalWords' => $totalWords,
'lastPostTime' => $lastPostTime,
'literaryComparison' => $literaryComparison
];
}
/**
* 插件实现方法
*
* @access public
* @return void
*/
public static function render()
{
$stats = self::getStats();
$word = Options::alloc()->plugin('HelloWorld')->word;
// 获取当前登录用户的信息
$user = \Typecho\Widget::widget('Widget_User');
$userName = $user->screenName ?: $user->name; // 优先使用昵称,如果没有则使用登录名
echo '<span class="helloworld-trigger" style="color:#BBBBBB">' .
htmlspecialchars($word) .
'</span>';
echo '<div class="helloworld-tooltip">
<h4>欢迎回来,' . htmlspecialchars($userName) . '</h4>
<div style="margin-bottom:20px;">
您已经写了 ' . $stats['postCount'] . ' 篇文章,一共 ' . $stats['totalWords'] . ' 字,' . $stats['literaryComparison'] . '。
</div>
<ul>
<li><strong>最近登录:</strong>' . $stats['lastLogin'] . '</li>
<li><strong>最近发文:</strong>' . $stats['lastPostTime'] . '</li>
</ul>
</div>';
}
}
]]>