更新666
This commit is contained in:
@@ -4,6 +4,16 @@
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v2.1
|
||||
|
||||
- 增加网页全网搜功能
|
||||
- 对接微信对话功能
|
||||
- 更新优化Seo
|
||||
- 后台增加批量删除功能
|
||||
- 优化表格导入功能
|
||||
|
||||
注:如何更新见文件夹updateLog/24.11.4
|
||||
|
||||
### v2
|
||||
|
||||
- UI改版:不再使用uniapp
|
||||
|
||||
@@ -153,14 +153,18 @@ class Source extends QfShop
|
||||
if (!$this->pk_value) {
|
||||
return jerr($this->pk . "必须填写", 400);
|
||||
}
|
||||
|
||||
//根据主键获取一行数据
|
||||
$item = $this->getRowByPk();
|
||||
if (empty($item)) {
|
||||
return jerr("数据查询失败", 404);
|
||||
}
|
||||
$this->model->where($this->pk, $this->pk_value)->delete();
|
||||
|
||||
if (isInteger($this->pk_value)){
|
||||
//根据主键获取一行数据
|
||||
$item = $this->getRowByPk();
|
||||
if (empty($item)) {
|
||||
return jerr("数据查询失败", 404);
|
||||
}
|
||||
$this->model->where($this->pk, $this->pk_value)->delete();
|
||||
}else{
|
||||
$list = explode(',', $this->pk_value);
|
||||
$this->model->where($this->pk, 'in', $list)->delete();
|
||||
}
|
||||
return jok('删除成功');
|
||||
}
|
||||
|
||||
@@ -192,7 +196,7 @@ class Source extends QfShop
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
// try {
|
||||
try {
|
||||
$file = request()->file('file');
|
||||
try {
|
||||
validate(['file' => 'filesize:' . config("qfshop.upload_max_file") . '|fileExt:' . config("qfshop.upload_file_type")])
|
||||
@@ -205,11 +209,12 @@ class Source extends QfShop
|
||||
|
||||
$extension = pathinfo($file_name, PATHINFO_EXTENSION);
|
||||
if ($extension == 'csv') {
|
||||
return jerr('转成xlsx格式吧');
|
||||
$PHPReader = new \PHPExcel_Reader_CSV();
|
||||
$encoding = $this->detectFileEncoding($file_name);
|
||||
if (!$encoding || strtoupper($encoding) == 'UTF-8') {
|
||||
$encoding = 'GBK'; // 尝试将其强制转为GBK
|
||||
}
|
||||
// if (!$encoding || strtoupper($encoding) == 'UTF-8') {
|
||||
// $encoding = 'GBK'; // 尝试将其强制转为GBK
|
||||
// }
|
||||
$PHPReader->setInputEncoding($encoding);
|
||||
$PHPReader->setDelimiter(',');
|
||||
} elseif ($extension == 'xlsx') {
|
||||
@@ -284,9 +289,9 @@ class Source extends QfShop
|
||||
} catch (ValidateException $e) {
|
||||
return jerr($e->getMessage());
|
||||
}
|
||||
// } catch (\Exception $error) {
|
||||
// return jerr('上传文件失败,请检查你的文件!');
|
||||
// }
|
||||
} catch (\Exception $error) {
|
||||
return jerr('上传文件失败,请检查你的文件!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@ class SourceCategory extends QfShop
|
||||
];
|
||||
$this->insertFields = [
|
||||
//允许添加的字段列表
|
||||
"name","sort","status","image"
|
||||
"name","sort","status","image","is_update"
|
||||
];
|
||||
$this->updateFields = [
|
||||
//允许更新的字段列表
|
||||
"name","sort","status","image"
|
||||
"name","sort","status","image","is_update"
|
||||
];
|
||||
$this->insertRequire = [
|
||||
//添加时必须填写的字段
|
||||
@@ -196,6 +196,19 @@ class SourceCategory extends QfShop
|
||||
if (!$source_category_id) {
|
||||
return jerr("ID参数必须填写", 400);
|
||||
}
|
||||
|
||||
|
||||
$d = [
|
||||
"status" => 1,
|
||||
"update_time" => time(),
|
||||
];
|
||||
if(input("type") == 1){
|
||||
$d = [
|
||||
"is_update" => 0,
|
||||
"update_time" => time(),
|
||||
];
|
||||
}
|
||||
|
||||
if (isInteger($source_category_id)) {
|
||||
//根据主键获取一行数据
|
||||
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
|
||||
@@ -204,17 +217,11 @@ class SourceCategory extends QfShop
|
||||
}
|
||||
//单个操作
|
||||
$map = ["source_category_id" => $source_category_id];
|
||||
$this->model->where($map)->update([
|
||||
"status" => 1,
|
||||
"update_time" => time(),
|
||||
]);
|
||||
$this->model->where($map)->update($d);
|
||||
} else {
|
||||
//批量操作
|
||||
$list = explode(',', $source_category_id);
|
||||
$this->model->where("source_category_id", 'in', $list)->update([
|
||||
"status" => 1,
|
||||
"update_time" => time(),
|
||||
]);
|
||||
$this->model->where("source_category_id", 'in', $list)->update($d);
|
||||
}
|
||||
return jok("禁用成功");
|
||||
}
|
||||
@@ -236,6 +243,18 @@ class SourceCategory extends QfShop
|
||||
if (!$source_category_id) {
|
||||
return jerr("ID参数必须填写", 400);
|
||||
}
|
||||
|
||||
$d = [
|
||||
"status" => 0,
|
||||
"update_time" => time(),
|
||||
];
|
||||
if(input("type") == 1){
|
||||
$d = [
|
||||
"is_update" => 1,
|
||||
"update_time" => time(),
|
||||
];
|
||||
}
|
||||
|
||||
if (isInteger($source_category_id)) {
|
||||
//根据主键获取一行数据
|
||||
$item = $this->model->where("source_category_id", $source_category_id)->field($this->selectDetail)->find();
|
||||
@@ -244,17 +263,11 @@ class SourceCategory extends QfShop
|
||||
}
|
||||
//单个操作
|
||||
$map = ["source_category_id" => $source_category_id];
|
||||
$this->model->where($map)->update([
|
||||
"status" => 0,
|
||||
"update_time" => time(),
|
||||
]);
|
||||
$this->model->where($map)->update($d);
|
||||
} else {
|
||||
//批量操作
|
||||
$list = explode(',', $source_category_id);
|
||||
$this->model->where("source_category_id", 'in', $list)->update([
|
||||
"status" => 0,
|
||||
"update_time" => time(),
|
||||
]);
|
||||
$this->model->where("source_category_id", 'in', $list)->update($d);
|
||||
}
|
||||
return jok("启用成功");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\api\QfShop;
|
||||
use think\facade\Request;
|
||||
use think\facade\Cache;
|
||||
use app\model\Source as SourceModel;
|
||||
|
||||
class Chatbot extends QfShop
|
||||
{
|
||||
// 应用管理 开放API 生成三个参数填在下方 回调地址:https://XXXX/api/chatbot 填在微信官方 即可
|
||||
private $appId = '';
|
||||
private $token = '';
|
||||
private $encodingAESKey = '';
|
||||
|
||||
|
||||
// 回复内容在下方,如有需要自行修改
|
||||
private $wName = '心悦搜索';
|
||||
|
||||
private $key;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->key = base64_decode($this->encodingAESKey . "=");
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$encrypted = input('encrypted');
|
||||
|
||||
//解决全局搜时会多次接收相同消息导致多次请求的bug,原因未知
|
||||
if(!empty($encrypted)){
|
||||
if(Cache::get($encrypted) == 1){
|
||||
return;
|
||||
}
|
||||
Cache::set($encrypted, 1, 600);
|
||||
}
|
||||
|
||||
$msg = $this->decryptMessage($encrypted);
|
||||
|
||||
|
||||
$msgtype = $msg['content']['msgtype']??'';
|
||||
$message = $msg['content']['msg']??'';
|
||||
if ($msgtype !== 'text' || empty($message)) {
|
||||
if(Cache::get($msg['userid']) != 1){
|
||||
$messages = "欢迎来到 ".$this->wName."!🍿🎬 这里是影迷的梦幻天堂,准备好享受每一部影视的精彩时刻吧!\n\n";
|
||||
$messages .= "🔍 使用指南 🔍\n\n";
|
||||
$messages .= "1. 搜剧命令\n";
|
||||
$messages .= "回复 “搜剧+剧名”,免费获取最全的影视资源。\n";
|
||||
$messages .= "示例:<a href='weixin://bizmsgmenu?msgmenucontent=搜剧我被美女包围了&msgmenuid=搜剧我被美女包围了'>搜剧我被美女包围了</a>\n\n";
|
||||
$messages .= "2. 全网搜\n";
|
||||
$messages .= "回复 “全网搜+关键词”,快速找到全网资源!\n";
|
||||
$messages .= "示例:<a href='weixin://bizmsgmenu?msgmenucontent=全网搜学剪辑&msgmenuid=全网搜学剪辑'>全网搜学剪辑</a>\n\n";
|
||||
$messages .= "赶快准备好你的爆米花,和我们一起开启下一场视觉盛宴吧!🎥";
|
||||
|
||||
$this->sendMessage($msg, $messages);
|
||||
}
|
||||
Cache::set($msg['userid'], 1, 604800);
|
||||
}
|
||||
// 检查用户消息内容中开头第一个字是否包含“搜”关键字
|
||||
if (strncmp($message, '搜', 1) === 0 || strncmp($message, '全网搜', 1) === 0) {
|
||||
|
||||
if(strncmp($message, '全网搜', 1) === 0){
|
||||
$list = [];
|
||||
// 去除“全网搜”关键字,提取用户输入的剧名
|
||||
$newString = preg_replace('/^全网搜/u', '', $message);
|
||||
}else{
|
||||
// 去除“搜剧”关键字,提取用户输入的剧名
|
||||
$newString = preg_replace('/^搜剧|^搜/u', '', $message);
|
||||
|
||||
// 实例化资源模型,并搜索匹配的剧名
|
||||
$map['page_size'] = 5;
|
||||
$map['title'] = $newString;
|
||||
$SourceModel = new SourceModel();
|
||||
$result = $SourceModel->getList($map);
|
||||
$list = $result['items']??[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(empty($list)){
|
||||
//系统没有资源去全网搜
|
||||
$this->sendMessage($msg, "正在深入搜索,请稍等...");
|
||||
|
||||
$list = $this->Qsearch($newString);
|
||||
}
|
||||
|
||||
$content = "🔍 ".$newString."丨搜索结果";
|
||||
$is_times = 0;
|
||||
if (!empty($list)) {
|
||||
foreach ($list as $item) {
|
||||
$content = $content . "\n";
|
||||
if(!empty($item['is_time']) && $item['is_time'] == 1){
|
||||
$content = $content . "\n🌐️ " . $item['title'] . "\n<a href='" . $item['url'] . "'>" . $item['url'] . "</a>";
|
||||
$is_times++;
|
||||
}else{
|
||||
$content = $content . "\n" . $item['title'] . "\n<a href='" . $item['url'] . "'>" . $item['url'] . "</a>";
|
||||
}
|
||||
}
|
||||
$content = $content . "\n";
|
||||
if($is_times>0){
|
||||
$content = $content . "\n🌐️ 资源来源网络,30分钟后删除";
|
||||
}else if(!empty($newString)){
|
||||
$content = $content . "\n 不是短剧?请尝试:<a href='weixin://bizmsgmenu?msgmenucontent=全网搜".$newString."&msgmenuid=全网搜".$newString."'>全网搜".$newString."</a>";
|
||||
}
|
||||
$content = $content . "\n ------------------------------------------------";
|
||||
$content = $content . "\n 欢迎观看!如果喜欢可以喊你的朋友一起来哦";
|
||||
} else {
|
||||
// 如果没有找到匹配的剧名,提示用户减少关键词尝试搜索
|
||||
$content = $content . "\n";
|
||||
$content = $content . "\n 未找到,可换个关键词尝试哦~";
|
||||
$content = $content . "\n ⚠️宁少写,不多写、错写~";
|
||||
}
|
||||
|
||||
$this->sendMessage($msg, $content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function Qsearch($newString)
|
||||
{
|
||||
$list = [];
|
||||
$urlData = array(
|
||||
'title' => $newString,
|
||||
);
|
||||
$res = curlHelper(Request::domain()."/api/other/all_search", "POST", $urlData)['body'];
|
||||
$res = json_decode($res, true);
|
||||
|
||||
if($res['code'] === 200){
|
||||
$list = $res['data']??[];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
// 解密消息
|
||||
private function decryptMessage($encrypted)
|
||||
{
|
||||
$result = $this->decrypt($encrypted,$this->appId);
|
||||
if ($result[0] !== 0) {
|
||||
return [];
|
||||
}
|
||||
return json_decode(json_encode(simplexml_load_string($result[1])), true);
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
private function sendMessage($msg, $message)
|
||||
{
|
||||
$data = $this->createXmlMessage($msg, $message);
|
||||
$result = $this->encrypt($data,$this->appId);
|
||||
|
||||
if ($result[0] !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendPostRequest("https://chatbot.weixin.qq.com/openapi/sendmsg/".$this->token, [
|
||||
'encrypt' => $result[1],
|
||||
]);
|
||||
}
|
||||
|
||||
// 创建 XML 消息
|
||||
private function createXmlMessage($msg, $message)
|
||||
{
|
||||
return '<xml>
|
||||
<appid><![CDATA['.$msg['appid'].']]></appid>
|
||||
<openid><![CDATA['.$msg['userid'].']]></openid>
|
||||
<msg><![CDATA['.$message.']]></msg>
|
||||
<channel>'.$msg['channel'].'</channel>
|
||||
</xml>';
|
||||
}
|
||||
|
||||
private function sendPostRequest($url, $data)
|
||||
{
|
||||
$options = [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
],
|
||||
CURLOPT_POSTFIELDS => json_encode($data),
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, $options);
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
// 处理错误(可添加日志)
|
||||
return ['error' => curl_error($ch)];
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
return json_decode($response, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 对密文进行解密
|
||||
* @param string $encrypted 需要解密的密文
|
||||
* @return string 解密得到的明文
|
||||
*/
|
||||
private function decrypt($encrypted,$appid)
|
||||
{
|
||||
try {
|
||||
if(version_compare(PHP_VERSION, '7','>=')) {
|
||||
$iv = substr($this->key, 0, 16);
|
||||
$decrypted = openssl_decrypt($encrypted,'AES-256-CBC',substr($this->key, 0, 32),OPENSSL_ZERO_PADDING,$iv);
|
||||
} else {
|
||||
//使用BASE64对需要解密的字符串进行解码
|
||||
$ciphertext_dec = base64_decode($encrypted);
|
||||
$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
|
||||
$iv = substr($this->key, 0, 16);
|
||||
mcrypt_generic_init($module, $this->key, $iv);
|
||||
|
||||
//解密
|
||||
$decrypted = mdecrypt_generic($module, $ciphertext_dec);
|
||||
mcrypt_generic_deinit($module);
|
||||
mcrypt_module_close($module);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [-40007, null];
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
//去除补位字符
|
||||
$result = $this->decode($decrypted);
|
||||
//去除16位随机字符串,网络字节序和AppId
|
||||
if (strlen($result) < 16)
|
||||
return "";
|
||||
$content = substr($result, 16, strlen($result));
|
||||
$len_list = unpack("N", substr($content, 0, 4));
|
||||
$xml_len = $len_list[1];
|
||||
$xml_content = substr($content, 4, $xml_len);
|
||||
$from_appid = substr($content, $xml_len + 4);
|
||||
if(version_compare(PHP_VERSION, '7','>=')) {
|
||||
if (!$appid) {
|
||||
//如果传入的appid是空的,则认为是订阅号,使用数据中提取出来的appid
|
||||
$appid = $from_appid;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
//print $e;
|
||||
return [-40008, null];
|
||||
}
|
||||
if ($from_appid != $appid)
|
||||
return [-40005, null];
|
||||
//不注释上边两行,避免传入appid是错误的情况
|
||||
if(version_compare(PHP_VERSION, '7','>=')) {
|
||||
//增加appid,为了解决后面加密回复消息的时候没有appid的订阅号会无法回复
|
||||
return array(0, $xml_content, $from_appid);
|
||||
} else {
|
||||
return array(0, $xml_content);
|
||||
}
|
||||
return $encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对解密后的明文进行补位删除
|
||||
* @param decrypted 解密后的明文
|
||||
* @return 删除填充补位后的明文
|
||||
*/
|
||||
private function decode($text)
|
||||
{
|
||||
|
||||
$pad = ord(substr($text, -1));
|
||||
if ($pad < 1 || $pad > 32) {
|
||||
$pad = 0;
|
||||
}
|
||||
return substr($text, 0, (strlen($text) - $pad));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对明文进行加密
|
||||
* @param string $text 需要加密的明文
|
||||
* @return string 加密后的密文
|
||||
*/
|
||||
private function encrypt($text, $appid)
|
||||
{
|
||||
try {
|
||||
if(version_compare(PHP_VERSION, '7','>=')) {
|
||||
//获得16位随机字符串,填充到明文之前
|
||||
$random = $this->getRandomStr();
|
||||
$text = $random . pack("N", strlen($text)) . $text . $appid;
|
||||
$iv = substr($this->key, 0, 16);
|
||||
$text = $this->encode($text);
|
||||
$encrypted = openssl_encrypt($text,'AES-256-CBC',substr($this->key, 0, 32),OPENSSL_ZERO_PADDING,$iv);
|
||||
} else {
|
||||
//获得16位随机字符串,填充到明文之前
|
||||
$random = $this->getRandomStr();
|
||||
$text = $random . pack("N", strlen($text)) . $text . $appid;
|
||||
// 网络字节序
|
||||
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
|
||||
$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
|
||||
$iv = substr($this->key, 0, 16);
|
||||
//使用自定义的填充方式对明文进行补位填充
|
||||
$text = $this->encode($text);
|
||||
mcrypt_generic_init($module, $this->key, $iv);
|
||||
//加密
|
||||
$encrypted = mcrypt_generic($module, $text);
|
||||
mcrypt_generic_deinit($module);
|
||||
mcrypt_module_close($module);
|
||||
$encrypted = base64_encode($encrypted);
|
||||
}
|
||||
|
||||
//print($encrypted);
|
||||
//使用BASE64对加密后的字符串进行编码
|
||||
return [0, $encrypted];
|
||||
} catch (Exception $e) {
|
||||
//print $e;
|
||||
return [-40006, null];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 对需要加密的明文进行填充补位
|
||||
* @param $text 需要进行填充补位操作的明文
|
||||
* @return 补齐明文字符串
|
||||
*/
|
||||
private function encode($text)
|
||||
{
|
||||
$block_size = 32;
|
||||
$text_length = strlen($text);
|
||||
//计算需要填充的位数
|
||||
$amount_to_pad = 32 - ($text_length % 32);
|
||||
if ($amount_to_pad == 0) {
|
||||
$amount_to_pad = 32;
|
||||
}
|
||||
//获得补位所用的字符
|
||||
$pad_chr = chr($amount_to_pad);
|
||||
$tmp = "";
|
||||
for ($index = 0; $index < $amount_to_pad; $index++) {
|
||||
$tmp .= $pad_chr;
|
||||
}
|
||||
return $text . $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成16位字符串
|
||||
* @return string 生成的字符串
|
||||
*/
|
||||
private function getRandomStr()
|
||||
{
|
||||
|
||||
$str = "";
|
||||
$str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
$max = strlen($str_pol) - 1;
|
||||
for ($i = 0; $i < 16; $i++) {
|
||||
$str .= $str_pol[mt_rand(0, $max)];
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
private function writeLog($value)
|
||||
{
|
||||
// 获取当前目录
|
||||
$currentDir = __DIR__; // 当前控制器目录
|
||||
$logFile = $currentDir . '/log.txt'; // 日志文件名称,可以自定义
|
||||
|
||||
// 生成时间戳
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
|
||||
// 判断 $value 是否为数组,如果是,则转换为 JSON 字符串
|
||||
if (is_array($value)) {
|
||||
$value = json_encode($value); // 转换为 JSON 字符串
|
||||
}
|
||||
|
||||
$logEntry = "[$timestamp] 参数值: $value\n"; // 日志内容
|
||||
|
||||
// 写入日志文件
|
||||
file_put_contents($logFile, $logEntry, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace app\api\controller;
|
||||
|
||||
use think\App;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Request;
|
||||
use app\api\QfShop;
|
||||
use app\model\Source as SourceModel;
|
||||
@@ -36,7 +37,7 @@ class Other extends QfShop
|
||||
$map[] = ['is_time', '=', 1];
|
||||
$map[] = ['title|description', 'like', '%' . trim($title) . '%'];
|
||||
|
||||
$urls = $this->model->where($map)->field('source_id as id, title, url')->order('update_time', 'desc')->limit(5)->select()->toArray();
|
||||
$urls = $this->model->where($map)->field('source_id as id, title, url,is_time')->order('update_time', 'desc')->limit(5)->select()->toArray();
|
||||
if (!empty($urls)) {
|
||||
|
||||
// 获取所有需要更新的ID
|
||||
@@ -52,6 +53,33 @@ class Other extends QfShop
|
||||
|
||||
return jok('临时资源获取成功',$urls);
|
||||
}
|
||||
|
||||
|
||||
//同一个搜索内容锁机
|
||||
if (Cache::has($title)) {
|
||||
// 检查缓存中是否已有结果
|
||||
return jok('临时资源获取成功1', Cache::get($title));
|
||||
}
|
||||
|
||||
|
||||
// 检查是否有正在处理的请求
|
||||
if (Cache::has($title . '_processing')) {
|
||||
// 如果当前正在处理相同关键词的请求,等待结果
|
||||
$startTime = time(); // 记录开始时间
|
||||
while (Cache::has($title . '_processing')) {
|
||||
usleep(1000000); // 暂停1秒
|
||||
|
||||
// 检查是否超过60秒
|
||||
if (time() - $startTime > 60) {
|
||||
return jok('临时资源获取成功3', []); // 返回空数组
|
||||
}
|
||||
}
|
||||
return jok('临时资源获取成功2', Cache::get($title));
|
||||
}
|
||||
|
||||
|
||||
// 设置处理状态为正在处理
|
||||
Cache::set($title . '_processing', true, 60); // 锁定60秒
|
||||
|
||||
$searchList = []; //查询的结果集
|
||||
$datas = []; //最终数据
|
||||
@@ -115,6 +143,9 @@ class Other extends QfShop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache::set($title, $datas, 60); // 缓存结果60秒
|
||||
Cache::delete($title . '_processing'); // 解锁
|
||||
|
||||
return jok('临时资源获取成功',$datas);
|
||||
}
|
||||
@@ -176,7 +207,7 @@ class Other extends QfShop
|
||||
$data["is_time"] = 1;
|
||||
$data["update_time"] = time();
|
||||
$data["create_time"] = time();
|
||||
$this->model->insertGetId($data);
|
||||
$data["id"] = $this->model->insertGetId($data);
|
||||
$datas[] =$data;
|
||||
$num_success++;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace app\api\controller;
|
||||
|
||||
use think\App;
|
||||
use think\facade\Request;
|
||||
use think\facade\Cache;
|
||||
use app\api\QfShop;
|
||||
use app\model\User as Usermodel;
|
||||
use app\model\Ads as Adsmodel;
|
||||
@@ -147,4 +149,37 @@ class Tool extends QfShop
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 网页端全网搜接口
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function Qsearch()
|
||||
{
|
||||
$title = input('title');
|
||||
$list = [];
|
||||
|
||||
if (empty($title)) {
|
||||
return jok('临时资源获取成功', $list);
|
||||
}
|
||||
|
||||
$keys = Request::ip()."_".$title;
|
||||
if(Cache::get($keys) == 1){
|
||||
return jerr('调用太过频繁啦');
|
||||
}
|
||||
Cache::set($keys, 1, 10);
|
||||
|
||||
$urlData = array(
|
||||
'title' => $title,
|
||||
);
|
||||
$res = curlHelper(Request::domain()."/api/other/all_search", "POST", $urlData)['body'];
|
||||
$res = json_decode($res, true);
|
||||
|
||||
if($res['code'] === 200){
|
||||
$list = $res['data']??[];
|
||||
}
|
||||
Cache::delete($keys);
|
||||
return jok('临时资源获取成功', $list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ use app\index\QfShop;
|
||||
use app\model\Source as SourceModel;
|
||||
use app\model\SourceCategory as SourceCategoryModel;
|
||||
|
||||
use Lizhichao\Word\VicWord;
|
||||
|
||||
|
||||
class Index extends QfShop
|
||||
{
|
||||
@@ -48,9 +50,26 @@ class Index extends QfShop
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//热门排行榜数据
|
||||
$hotList = [];
|
||||
$cacheDir = root_path('runtime/api/cache'); // runtime/cache 目录
|
||||
foreach ($rankList as $value) {
|
||||
$cacheFile = $cacheDir . "ranking_data_{$value['name']}.cache";
|
||||
if (file_exists($cacheFile)) {
|
||||
$hotList[] = array(
|
||||
'name'=> $value['name'],
|
||||
'image'=> $value['image'],
|
||||
'list'=> json_decode(file_get_contents($cacheFile), true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$config = config("qfshop");
|
||||
|
||||
View::assign('newList', $newList);
|
||||
View::assign('hotList', $hotList);
|
||||
View::assign('config', $config);
|
||||
View::assign('rankList', $rankList);
|
||||
View::assign('fixed', 1);
|
||||
@@ -80,9 +99,25 @@ class Index extends QfShop
|
||||
|
||||
$category = $this->SourceCategoryModel->field('name,source_category_id as id')->where([['status','=',0]])->order('sort desc')->select();
|
||||
|
||||
|
||||
//热门排行榜数据
|
||||
$hotList = [];
|
||||
$cacheDir = root_path('runtime/api/cache'); // runtime/cache 目录
|
||||
foreach ($rankList as $value) {
|
||||
$cacheFile = $cacheDir . "ranking_data_{$value['name']}.cache";
|
||||
if (file_exists($cacheFile)) {
|
||||
$hotList[] = array(
|
||||
'name'=> $value['name'],
|
||||
'image'=> $value['image'],
|
||||
'list'=> json_decode(file_get_contents($cacheFile), true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$config = config("qfshop");
|
||||
|
||||
View::assign('hotList', $hotList);
|
||||
View::assign('rankList', $rankList);
|
||||
View::assign('category', $category);
|
||||
View::assign('list', $list);
|
||||
@@ -118,9 +153,53 @@ class Index extends QfShop
|
||||
}
|
||||
|
||||
$rankList = $this->SourceCategoryModel->field('name,image')->where([['status','=',0],['is_sys','=',1]])->order('sort desc')->select();
|
||||
|
||||
//热门排行榜数据
|
||||
$hotList = [];
|
||||
$cacheDir = root_path('runtime/api/cache'); // runtime/cache 目录
|
||||
foreach ($rankList as $value) {
|
||||
$cacheFile = $cacheDir . "ranking_data_{$value['name']}.cache";
|
||||
if (file_exists($cacheFile)) {
|
||||
$hotList[] = array(
|
||||
'name'=> $value['name'],
|
||||
'image'=> $value['image'],
|
||||
'list'=> json_decode(file_get_contents($cacheFile), true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//相关资源
|
||||
$map[] = ['status', '=', 1];
|
||||
$map[] = ['is_delete', '=', 0];
|
||||
$fc = new VicWord();
|
||||
$keywords = $fc->getAutoWord(preg_replace('/[\(\(][^\)]*[\)\)]/u', '', $detail['title']));
|
||||
$keywords = filterAndExtractWords($keywords);
|
||||
$keywords[] = '';//这个是为了在没有相关资源时不至于获取不到资源
|
||||
$weightExpr = [];
|
||||
foreach ($keywords as $keyword) {
|
||||
$weightExpr[] = "IF(title LIKE '%{$keyword}%' OR description LIKE '%{$keyword}%', 1, 0)";
|
||||
$searchTitle[] = $keyword;
|
||||
}
|
||||
$weightExpr = implode(' + ', $weightExpr);
|
||||
// 在查询中添加权重计算和排序
|
||||
$query = $this->SourceModel->alias('a')
|
||||
->field('a.*, (' . $weightExpr . ') as weight')->where($map)
|
||||
->where(function($query) use ($keywords) {
|
||||
foreach ($keywords as $keyword) {
|
||||
$query->whereOr('title', 'like', '%' . trim($keyword) . '%')
|
||||
->whereOr('description', 'like', '%' . trim($keyword) . '%');
|
||||
}
|
||||
});
|
||||
$order = ['weight' => 'desc', 'source_id' => 'desc'];
|
||||
$sameList = $query->where('source_id','<>',$detail['id'])->order($order)->limit(10)->select();
|
||||
|
||||
|
||||
|
||||
$config = config("qfshop");
|
||||
|
||||
View::assign('sameList', $sameList);
|
||||
View::assign('hotList', $hotList);
|
||||
View::assign('rankList', $rankList);
|
||||
View::assign('detail', $detail);
|
||||
View::assign('config', $config);
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
const rankDj = ref([]);
|
||||
const is_m = ref(0);
|
||||
const newList = ref([]);
|
||||
const QStatus = ref(0);
|
||||
const QList = ref([]);
|
||||
const QLoading = ref(false);
|
||||
const total_result = ref(0);
|
||||
|
||||
|
||||
// 公共消息方法
|
||||
@@ -167,7 +171,7 @@
|
||||
});
|
||||
|
||||
// 返回数据和方法
|
||||
return { elementOpacity, scrollThreshold, keyword, searchBtn, rankList,newList, setnum, qcodeVisible, layerVisible, content, saveBtn, rankDj,goLink,changeBtn,copyText,drawer,selectBtn,is_m };
|
||||
return { elementOpacity, scrollThreshold, keyword, searchBtn, rankList,newList, setnum, qcodeVisible, layerVisible, content, saveBtn, rankDj,goLink,changeBtn,copyText,drawer,selectBtn,is_m,QList,QLoading,QStatus,total_result };
|
||||
}
|
||||
})
|
||||
.use(ElementPlus) // 使用 Element Plus
|
||||
|
||||
@@ -76,47 +76,58 @@
|
||||
</div>
|
||||
{/notempty}
|
||||
<div class="btns">
|
||||
<div class="btn btnCol" @click.stop="copyText($event,'{$detail.title}','{$detail.url}','{$detail.code}')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
|
||||
<div class="btn btnCol" @click.stop="copyText($event,'{$detail.title|trim}','{$detail.url}','{$detail.code}')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
|
||||
<a href="{$detail.url}" target="_blank" class="btn"><i class="iconfont icon-yun_o"></i>立即访问</a>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="samelistNav">相关资源</h3>
|
||||
<div class="box details samelistBox">
|
||||
<div class="samelist">
|
||||
{volist name="sameList" id="vo"}
|
||||
<a href="/d/{$vo.source_id}.html" class="item">
|
||||
<p>
|
||||
<span>{$key+1}</span>
|
||||
{$vo.title}
|
||||
</p>
|
||||
</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<block v-for="(item,index) in rankList" :key="index">
|
||||
{volist name="hotList" id="vo"}
|
||||
<div class="nav">
|
||||
<img :src="item.image" v-if="item.image">
|
||||
{{item.name}}
|
||||
{notempty name="vo.image"}
|
||||
<img src="{$vo.image}" :alt="{$vo.name}">
|
||||
{/notempty}
|
||||
{$vo.name}
|
||||
</div>
|
||||
<div class="box" v-if="item.list && item.list.length>0">
|
||||
<div class="list">
|
||||
<a :href="'/s/'+vo.title+'.html'" v-for="(vo,i) in item.list" :key="i" class="item" v-show="i<5">
|
||||
<div class="box">
|
||||
<div class="list">
|
||||
{volist name="vo.list" id="vos" length="5"}
|
||||
<a href="/s/{$vos.title}.html" class="item">
|
||||
<p>
|
||||
<span>{{i+1}}</span>
|
||||
{{vo.title}}
|
||||
<span>{$key+1}</span>
|
||||
{$vos.title}
|
||||
</p>
|
||||
</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</block>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
{include file="common/foot"}
|
||||
</div>
|
||||
{include file="common/footer"}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
if(!app.is_m){
|
||||
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
|
||||
for (const item of app.rankList) {
|
||||
axios.get('/api/tool/ranking',{
|
||||
params: {
|
||||
channel: item.name,
|
||||
is_m: app.is_m
|
||||
}
|
||||
})
|
||||
.then(function (res) {
|
||||
item.list = res.data.data
|
||||
})
|
||||
}
|
||||
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
|
||||
for (const item of app.rankList) {
|
||||
axios.get('/api/tool/ranking',{
|
||||
params: {
|
||||
channel: item.name
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -36,78 +36,92 @@
|
||||
<div class="content">
|
||||
{if $config.ranking_type == 1 }
|
||||
<div class="list">
|
||||
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in newList" :key="i">
|
||||
{volist name="newList" id="vos"}
|
||||
{if condition="strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') === false || $key < $config.ranking_m_num"}
|
||||
<a href="/s/{$vos.title}.html" target="_blank" class="item">
|
||||
<div class="img">
|
||||
<img :src="vo.src" :alt="vo.title"/>
|
||||
<img src="{$vos.src}" alt="{$vos.title}" />
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
<p>{{vo.title}}</p>
|
||||
<p>{$vos.title}</p>
|
||||
</a>
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
{else /}
|
||||
<div class="list">
|
||||
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in newList" :key="i">
|
||||
{volist name="newList" id="vos"}
|
||||
{if condition="strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') === false || $key < $config.ranking_m_num"}
|
||||
<a href="/s/{$vos.title}.html" target="_blank" class="item">
|
||||
<p>
|
||||
<span>{{i+1}}</span>
|
||||
{{vo.title}}
|
||||
<span>{$key+1}</span>
|
||||
{$vos.title}
|
||||
</p>
|
||||
</a>
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="block" v-for="(item,index) in rankList" :key="index">
|
||||
|
||||
{volist name="hotList" id="vo"}
|
||||
<div class="block">
|
||||
<div class="nav">
|
||||
<img :src="item.image" :alt="item.name" v-if="item.image">
|
||||
{{item.name}}
|
||||
{notempty name="vo.image"}
|
||||
<img src="{$vo.image}" :alt="{$vo.name}">
|
||||
{/notempty}
|
||||
{$vo.name}
|
||||
</div>
|
||||
<div class="content">
|
||||
{if $config.ranking_type == 1 }
|
||||
<div class="list">
|
||||
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in item.list" :key="i">
|
||||
{volist name="vo.list" id="vos"}
|
||||
{if condition="strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') === false || $key < $config.ranking_m_num"}
|
||||
<a href="/s/{$vos.title}.html" target="_blank" class="item">
|
||||
<div class="img">
|
||||
<img :src="vo.src" :alt="vo.title" />
|
||||
<img src="{$vos.src}" alt="{$vos.title}" />
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
<p>{{vo.title}}</p>
|
||||
<p>{$vos.title}</p>
|
||||
</a>
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
{else /}
|
||||
<div class="list">
|
||||
<a :href="'/s/'+vo.title+'.html'" target="_blank" class="item" v-for="(vo,i) in item.list" :key="i">
|
||||
{volist name="vo.list" id="vos"}
|
||||
{if condition="strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') === false || $key < $config.ranking_m_num"}
|
||||
<a href="/s/{$vos.title}.html" target="_blank" class="item">
|
||||
<p>
|
||||
<span>{{i+1}}</span>
|
||||
{{vo.title}}
|
||||
<span>{$key+1}</span>
|
||||
{$vos.title}
|
||||
</p>
|
||||
</a>
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{include file="common/foot"}
|
||||
</div>
|
||||
{include file="common/footer"}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
app.newList = JSON.parse('<?php echo json_encode($newList, JSON_UNESCAPED_UNICODE); ?>');
|
||||
let num = '{$config.ranking_m_num}';
|
||||
if(app.is_m){
|
||||
app.newList = app.newList.slice(0, num);
|
||||
}
|
||||
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
|
||||
for (const item of app.rankList) {
|
||||
axios.get('/api/tool/ranking',{
|
||||
params: {
|
||||
channel: item.name,
|
||||
is_m: app.is_m
|
||||
channel: item.name
|
||||
}
|
||||
})
|
||||
.then(function (res) {
|
||||
item.list = res.data.data
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+102
-25
@@ -32,9 +32,50 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="left">
|
||||
<h3>为您找到【<span>{$keyword}</span>】相关资源<span> {$list.total_result} </span>条</h3>
|
||||
<div class="box">
|
||||
<h3 v-if="total_result>0">为您找到【<span>{$keyword}</span>】相关资源<span> {{total_result}} </span>条</h3>
|
||||
<h3 v-else>为您找到【<span>{$keyword}</span>】相关资源<span> {$list.total_result} </span>条</h3>
|
||||
|
||||
{if condition="$config.is_quan == 1"}
|
||||
<div class="Ebox" v-if="QStatus">
|
||||
<div class="Qloading" v-if="QLoading">
|
||||
<div class="loader"></div>
|
||||
</div>
|
||||
<div class="list">
|
||||
<div class="item" v-for="(item,index) in QList" :key="index">
|
||||
<a target="_blank" :href="item.url" class="title">
|
||||
{{item.title}}
|
||||
</a>
|
||||
<div class="type time">30分钟后自动删除,请及时保存</div>
|
||||
<div class="type">
|
||||
<span>来源:网络资源</span>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<div class="btn" @click.stop="copyText($event,item.title,item.url,'')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
|
||||
<a :href="'/d/'+item.id+'.html'" class="btn"><i class="iconfont icon-fangwen"></i>查看详情</a>
|
||||
<a target="_blank" :href="item.url" class="btn">
|
||||
<img src="/static/index/images/0.png" class="icon" />
|
||||
立即访问
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<block v-if="!QLoading && QList.length==0">
|
||||
<div class="Qtips" v-if="QStatus==1">
|
||||
<p>未找到更多的资源~</p>
|
||||
</div>
|
||||
<el-empty v-else style="margin-top: 10%;padding-bottom: 10%;" :image-size="200" image="{$config.search_bg??''}" description="{$config.search_tips|default='未找到,可换个关键词尝试哦~'}"></el-empty>
|
||||
</block>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="box" v-if="QStatus!=2">
|
||||
{if condition="$list.total_result>0"}
|
||||
{if condition="$config.is_quan == 1"}
|
||||
<div class="Qbtn">
|
||||
<div class="btn" onclick="getMore()">以下资源不是你想要的?点击尝试获取新资源</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="list">
|
||||
{foreach $list.items as $key=>$vo }
|
||||
<div class="item">
|
||||
@@ -59,7 +100,7 @@
|
||||
{/notempty}
|
||||
</div>
|
||||
<div class="btns">
|
||||
<div class="btn" @click.stop="copyText($event,'{$vo.title}','{$vo.url}','{$vo.code}')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
|
||||
<div class="btn" @click.stop="copyText($event,'{$vo.title|trim}','{$vo.url}','{$vo.code}')"><i class="iconfont icon-fenxiang1"></i>复制分享</div>
|
||||
<a href="/d/{$vo.id}.html" class="btn"><i class="iconfont icon-fangwen"></i>查看详情</a>
|
||||
<a target="_blank" href="{$vo.url}" class="btn">
|
||||
<img src="/static/index/images/{$vo.is_type}.png" class="icon" />
|
||||
@@ -80,42 +121,78 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<block v-for="(item,index) in rankList" :key="index">
|
||||
{volist name="hotList" id="vo"}
|
||||
<div class="nav">
|
||||
<img :src="item.image" v-if="item.image">
|
||||
{{item.name}}
|
||||
{notempty name="vo.image"}
|
||||
<img src="{$vo.image}" :alt="{$vo.name}">
|
||||
{/notempty}
|
||||
{$vo.name}
|
||||
</div>
|
||||
<div class="box" v-if="item.list && item.list.length>0">
|
||||
<div class="list">
|
||||
<a :href="'/s/'+vo.title+'.html'" v-for="(vo,i) in item.list" :key="i" class="item" v-show="i<5">
|
||||
<div class="box">
|
||||
<div class="list">
|
||||
{volist name="vo.list" id="vos" length="5"}
|
||||
<a href="/s/{$vos.title}.html" class="item">
|
||||
<p>
|
||||
<span>{{i+1}}</span>
|
||||
{{vo.title}}
|
||||
<span>{$key+1}</span>
|
||||
{$vos.title}
|
||||
</p>
|
||||
</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</block>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
{include file="common/foot"}
|
||||
</div>
|
||||
{include file="common/footer"}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
// if(!app.is_m){
|
||||
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
|
||||
for (const item of app.rankList) {
|
||||
axios.get('/api/tool/ranking',{
|
||||
params: {
|
||||
channel: item.name,
|
||||
is_m: app.is_m
|
||||
}
|
||||
})
|
||||
.then(function (res) {
|
||||
item.list = res.data.data
|
||||
})
|
||||
app.rankList = JSON.parse('<?php echo json_encode($rankList, JSON_UNESCAPED_UNICODE); ?>');
|
||||
for (const item of app.rankList) {
|
||||
axios.get('/api/tool/ranking',{
|
||||
params: {
|
||||
channel: item.name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
var status
|
||||
if({$list.total_result} == 0){
|
||||
if('{$config.is_quan}' == 1) {
|
||||
//默认资源没有直接执行
|
||||
status = 2
|
||||
app.QStatus = status
|
||||
getAll()
|
||||
}
|
||||
// }
|
||||
}
|
||||
function getMore(){
|
||||
if('{$config.is_quan}' == 1){
|
||||
status = 1
|
||||
app.QStatus = status
|
||||
getAll()
|
||||
}
|
||||
}
|
||||
function getAll() {
|
||||
if(app.QStatus==0 || app.QLoading || '{$config.is_quan}' != 1) return
|
||||
app.QLoading = true
|
||||
axios.post('/api/tool/Qsearch',{
|
||||
title: app.keyword
|
||||
})
|
||||
.then(function (res) {
|
||||
app.QLoading = false
|
||||
app.QStatus = status
|
||||
app.QList = res.data.data
|
||||
app.total_result = {$list.total_result} + app.QList.length
|
||||
})
|
||||
.catch(function (error) {
|
||||
app.QLoading = false;
|
||||
app.QStatus = status
|
||||
app.QList = []
|
||||
app.total_result = {$list.total_result} + app.QList.length
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,14 +29,14 @@
|
||||
<el-table-column label="是否每日更新" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-switch v-model="scope.row.is_update==1?true:false"
|
||||
@change="clickStatus(scope.row)">
|
||||
@change="clickStatus(scope.row,1)">
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否前台展示" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-switch v-model="scope.row.status==1?false:true"
|
||||
@change="clickStatus(scope.row)">
|
||||
@change="clickStatus(scope.row,0)">
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -228,10 +228,15 @@ console.log(error);
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
clickStatus(row) {
|
||||
clickStatus(row,type) {
|
||||
var that = this;
|
||||
axios.post(row.status ? '/admin/source_category/enable' : '/admin/source_category/disable', Object.assign({}, PostBase, {
|
||||
source_category_id: row.source_category_id
|
||||
let url = row.status ? '/admin/source_category/enable' : '/admin/source_category/disable'
|
||||
if(type==1){
|
||||
url = !row.is_update ? '/admin/source_category/enable' : '/admin/source_category/disable'
|
||||
}
|
||||
axios.post(url, Object.assign({}, PostBase, {
|
||||
source_category_id: row.source_category_id,
|
||||
type: type
|
||||
}))
|
||||
.then(function (response) {
|
||||
that.getList();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<el-form :inline="true" @submit.native.prevent>
|
||||
<el-form-item>
|
||||
<el-button icon="el-icon-plus" size="small" @click="clickAdd" plain>添加资源</el-button>
|
||||
<el-button icon="el-icon-delete" size="small" @click="postMultDelete" plain>批量删除</el-button>
|
||||
<el-button icon="el-icon-document-copy" size="small" @click="getExport" plain>导出资源</el-button>
|
||||
<el-button icon="el-icon-plus" size="small" @click="ImportShow" plain>夸克导入专用</el-button>
|
||||
<el-button icon="el-icon-plus" size="small" @click="ImportBatch" plain>批量导入</el-button>
|
||||
@@ -29,7 +30,9 @@
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-table :data="dataList.data" v-loading="loading">
|
||||
<el-table :data="dataList.data" @selection-change="changeSelection" v-loading="loading">
|
||||
<el-table-column type="selection" width="50">
|
||||
</el-table-column>
|
||||
<el-table-column prop="source_id" label="ID" width="80">
|
||||
</el-table-column>
|
||||
<el-table-column prop="title" label="资源名称">
|
||||
@@ -146,7 +149,7 @@
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
<span style="color: #999;">请导入夸克官方导出的csv文件</span>
|
||||
<span style="color: #999;">请使用xlsx格式,第一列资源名称 第二列资源地址</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
@@ -214,6 +217,7 @@ https://drive.uc.cn/s/xxxxxxxxxxx"
|
||||
dialogFormAdd: false,
|
||||
dialogFormEdit: false,
|
||||
loading: true,
|
||||
selectList: [],
|
||||
dataList: [],
|
||||
form: {
|
||||
page: 1,
|
||||
@@ -468,6 +472,47 @@ https://drive.uc.cn/s/xxxxxxxxxxx"
|
||||
window.open(url);
|
||||
that.$message.success('数据导出成功');
|
||||
},
|
||||
|
||||
|
||||
postMultDelete() {
|
||||
var that = this;
|
||||
if (that.selectList.length == 0) {
|
||||
that.$message.error('未选择任何资源!');
|
||||
return;
|
||||
}
|
||||
this.$confirm('即将删除选中的资源, 是否确认?', '批量删除', {
|
||||
confirmButtonText: '删除',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
axios.post('/admin/source/delete', Object.assign({}, PostBase, {
|
||||
source_id: that.selectList.join(",")
|
||||
}))
|
||||
.then(function (response) {
|
||||
that.getList();
|
||||
if (response.data.code == CODE_SUCCESS) {
|
||||
that.$message({
|
||||
message: response.data.message,
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
that.$message.error(response.data.message);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
that.$message.error('服务器内部错误');
|
||||
console.log(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
changeSelection(list) {
|
||||
var that = this;
|
||||
that.selectList = [];
|
||||
for (var index in list) {
|
||||
that.selectList.push(list[index].source_id);
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -164,6 +164,8 @@ INSERT INTO `qf_conf` VALUES (48, 'search_tips', '', '未搜索提示词', '为
|
||||
INSERT INTO `qf_conf` VALUES (49, 'search_bg', '', '未搜索提示图', '', 0, 4, NULL, 1, 1, 0, 1, 1726108851, 1726108851);
|
||||
INSERT INTO `qf_conf` VALUES (50, 'home_new', '1', '最新列表', '仅无图模式有效', 0, 2, '开启=>0\n关闭=>1', 3, 1, 79, 1, 1726299605, 1726299605);
|
||||
INSERT INTO `qf_conf` VALUES (51, 'home_new_img', '', '最新图标', '', 0, 4, NULL, 3, 1, 79, 1, 1726302688, 1726302688);
|
||||
INSERT INTO `qf_conf` VALUES (52, 'is_quan', '0', '全网搜', '', 0, 2, '关闭=>0\n开启=>1', 1, 1, 1, 1, 1729928547, 1729928547);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for qf_days
|
||||
|
||||
@@ -434,7 +434,7 @@ a:hover {
|
||||
.listBox h3:after{
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 18px;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
width: 4px;
|
||||
background-color: var(--theme-theme);
|
||||
@@ -462,6 +462,7 @@ a:hover {
|
||||
.listBox .left{
|
||||
width: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.listBox .left .list{
|
||||
padding: 0 15px;
|
||||
@@ -614,6 +615,7 @@ a:hover {
|
||||
|
||||
.listBox .details{
|
||||
padding: 40px 50px;
|
||||
min-height: inherit;
|
||||
}
|
||||
|
||||
.details .pic{
|
||||
@@ -739,6 +741,96 @@ a:hover {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin: auto;
|
||||
width: fit-content;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
font-size: 24px;
|
||||
background: radial-gradient(circle closest-side,var(--theme-theme) 94%,#0000) right/calc(200% - 1em) 100%;
|
||||
animation: l24 1s infinite alternate linear;
|
||||
}
|
||||
.loader::before {
|
||||
content: "全网检索中,请稍等...";
|
||||
line-height: 1em;
|
||||
color: #0000;
|
||||
background: inherit;
|
||||
background-image: radial-gradient(circle closest-side,#fff 94%,var(--theme-theme));
|
||||
-webkit-background-clip:text;
|
||||
background-clip:text;
|
||||
}
|
||||
|
||||
@keyframes l24{
|
||||
100%{background-position: left}
|
||||
}
|
||||
|
||||
|
||||
.listBox .Ebox{
|
||||
border-radius: 12px;
|
||||
background-color: var(--theme-other_background);
|
||||
box-shadow: 0 4px 10px rgba(225, 225, 225, 0.3);
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.listBox .left .Ebox .list .item:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
.Qtips{
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
.Qbtn{
|
||||
text-align: center;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.Qbtn .btn{
|
||||
display: inline-block;
|
||||
color: #999999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*//相关资源*/
|
||||
.listBox .details.samelistBox{
|
||||
padding: 25px 30px;
|
||||
}
|
||||
.samelist {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.samelist .item {
|
||||
width: 50%;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
text-align: left;
|
||||
padding: 3px 0;
|
||||
}
|
||||
.samelist .item p {
|
||||
margin-top: 0;
|
||||
padding: 4px 6px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.samelist .item:hover{
|
||||
transform: translateY(0);
|
||||
}
|
||||
.samelist .item p span {
|
||||
color: #c4c7ce;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.samelist .item:nth-child(1) p span {
|
||||
color: #FE2D46;
|
||||
}
|
||||
.samelist .item:nth-child(2) p span {
|
||||
color: #FF6600;
|
||||
}
|
||||
.samelist .item:nth-child(3) p span {
|
||||
color: #FAA90E;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -176,6 +176,28 @@
|
||||
text-align: justify;
|
||||
min-height: calc(100% - 50vw);
|
||||
}
|
||||
.listBox .Ebox{
|
||||
padding: 0 4vw 5vw;
|
||||
margin-top: 4vw;
|
||||
margin-bottom: 4vw;
|
||||
text-align: justify;
|
||||
}
|
||||
.listBox .left .Ebox .list .item:last-child{
|
||||
padding: 5vw 0 0;
|
||||
}
|
||||
.Qloading {
|
||||
padding-top: 6vw;
|
||||
}
|
||||
.Qtips{
|
||||
padding-top: 5.6vw;
|
||||
}
|
||||
.loader{
|
||||
font-size: 18px;
|
||||
}
|
||||
.Qbtn{
|
||||
padding-top: 5vw;
|
||||
}
|
||||
|
||||
.listBox .left .list {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -274,14 +296,38 @@
|
||||
.searchDetail .search input {
|
||||
padding-left: 5vw;
|
||||
}
|
||||
.detailBox{
|
||||
min-height: inherit;
|
||||
}
|
||||
.detailBox h3{
|
||||
display: none;
|
||||
}
|
||||
.detailBox .details {
|
||||
padding-top: 5vw;
|
||||
margin-top: 20vw;
|
||||
min-height: inherit;
|
||||
}
|
||||
|
||||
.listBox .details.samelistBox{
|
||||
padding: 3vw;
|
||||
margin-top: 0;
|
||||
}
|
||||
.detailBox h3.samelistNav{
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 30px 0 17px 15px;
|
||||
font-size: 4.2vw;
|
||||
text-align: left;
|
||||
}
|
||||
.detailBox h3.samelistNav:after {
|
||||
display: block;
|
||||
}
|
||||
.samelist .item {
|
||||
width: 100%;
|
||||
}
|
||||
.samelist .item p {
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
更新方式
|
||||
1、app文件夹整包上传覆盖
|
||||
2、替换 public\static\index\css\app.css和public\static\index\css\m.css
|
||||
3、执行sql语句
|
||||
INSERT INTO `qf_conf` VALUES (52, 'is_quan', '0', '全网搜', '', 0, 2, '关闭=>0\n开启=>1', 1, 1, 1, 1, 1729928547, 1729928547);
|
||||
|
||||
如何对接微信对话功能
|
||||
详情见 app\api\controller\Chatbot.php
|
||||
Reference in New Issue
Block a user