diff --git a/.env.docker-compose.example b/.env.docker-compose.example
new file mode 100644
index 0000000..4ce825d
--- /dev/null
+++ b/.env.docker-compose.example
@@ -0,0 +1,17 @@
+# Web 映射到宿主机的端口
+PORT=666
+
+# MySQL 映射到宿主机的端口
+MYSQL_PORT=3306
+
+# MySQL 数据库名
+MYSQL_DATABASE=code6
+
+# MySQL 用户名(请使用非 root 用户)
+MYSQL_USER=
+
+# MySQL 密码
+MYSQL_PASSWORD=
+
+# MySQL 挂载到宿主机的目录
+MYSQL_VOLUME_PATH=
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..d3c98c5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,15 @@
+## 安装方式
+Docker-Compose 安装、Docker 安装 或 源码安装
+
+## 问题描述
+请描述遇到的问题..
+
+## 运行环境
+```
+请复制 php doctor.php 运行结果
+```
+
+## 报错日志
+```
+日志目录:storage/logs
+```
diff --git a/.gitignore b/.gitignore
index f5b7047..8f5f877 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,5 @@ Homestead.yaml
npm-debug.log
yarn-error.log
.idea
+.DS_Store
+.env.docker-compose
diff --git a/Dockerfile b/Dockerfile
index 2ec0286..1e9bdec 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,50 +2,46 @@ FROM php:7.4-apache
EXPOSE 80
-ENV MYSQL_HOST="172.17.0.1"
+ENV MYSQL_HOST="mysql"
ENV MYSQL_PORT="3306"
ENV MYSQL_DATABASE="code6"
ENV MYSQL_USERNAME=""
ENV MYSQL_PASSWORD=""
+ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
# 复制代码
COPY . /var/www/html
+COPY docker-entrypoint.sh docker-entrypoint.sh
WORKDIR /var/www/html
# 使用阿里镜像并安装包
-RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak
-RUN echo 'deb http://mirrors.aliyun.com/debian buster main'>> /etc/apt/sources.list
-RUN echo 'deb http://mirrors.aliyun.com/debian buster-updates main'>> /etc/apt/sources.list
-RUN apt-get update && apt-get install -y --allow-downgrades zip cron vim zlib1g=1:1.2.11.dfsg-1 zlib1g-dev libpng-dev
-RUN rm -rf /var/lib/apt/lists/* && apt-get clean
-
+RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak;\
+echo 'deb http://mirrors.aliyun.com/debian buster main'>> /etc/apt/sources.list;\
+echo 'deb http://mirrors.aliyun.com/debian buster-updates main'>> /etc/apt/sources.list;\
+apt-get update;\
+apt-get install -y --allow-downgrades zip cron vim zlib1g=1:1.2.11.dfsg-1+deb10u1 zlib1g-dev libpng-dev;\
+rm -rf /var/lib/apt/lists/*;\
# 安装 PHP 扩展
-RUN docker-php-ext-install pdo_mysql
-RUN docker-php-ext-install gd
-
+docker-php-ext-install pdo_mysql;\
+docker-php-ext-install gd;\
# 配置 Web 路径
-ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
-RUN sed -ri -e "s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g" /etc/apache2/sites-available/*.conf
-RUN sed -ri -e "s!/var/www/!${APACHE_DOCUMENT_ROOT}!g" /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
-
+sed -ri -e "s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g" /etc/apache2/sites-available/*.conf;\
+sed -ri -e "s!/var/www/!${APACHE_DOCUMENT_ROOT}!g" /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf;\
# 修改时区
-RUN rm -rf /etc/localtime
-RUN ln -s /usr/share/zoneinfo/PRC /etc/localtime
-
+rm -rf /etc/localtime;\
+ln -s /usr/share/zoneinfo/PRC /etc/localtime;\
# 设置别名
-RUN echo "alias ll='ls -l'">> /etc/bash.bashrc
-
+echo "alias ll='ls -l'">> /etc/bash.bashrc;\
# Vim 编码配置
-RUN echo 'set fileencodings=utf-8'>> /etc/vim/vimrc
-RUN echo 'set termencoding=utf-8'>> /etc/vim/vimrc
-RUN echo 'set encoding=utf-8'>> /etc/vim/vimrc
-
+echo 'set fileencodings=utf-8'>> /etc/vim/vimrc;\
+echo 'set termencoding=utf-8'>> /etc/vim/vimrc;\
+echo 'set encoding=utf-8'>> /etc/vim/vimrc;\
# 安装 Composer 及项目依赖包
-RUN curl -sO https://mirrors.aliyun.com/composer/composer.phar
-RUN chmod +x composer.phar
-RUN mv composer.phar /usr/local/bin/composer
-RUN composer config repo.packagist composer https://mirrors.aliyun.com/composer/
-RUN composer install --no-dev --no-progress --optimize-autoloader
+curl -sO https://mirrors.aliyun.com/composer/composer.phar;\
+chmod +x composer.phar;\
+mv composer.phar /usr/local/bin/composer;\
+composer config repo.packagist composer https://mirrors.aliyun.com/composer/;\
+composer install --no-dev --no-progress --optimize-autoloader;\
+chmod +x docker-entrypoint.sh;
-RUN chmod +x docker-entrypoint.sh
ENTRYPOINT /bin/bash docker-entrypoint.sh
diff --git a/README.md b/README.md
index d54b073..d99ab48 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,10 @@
---
+> 因 GitHub 官方搜索架构调整,码小六即日起暂停维护,详见 https://github.com/4x99/code6/issues/264 ,感谢大家支持,后会有期! 2023年04月27日
+
+---
+
## 系统特点
- 全可视化界面,操作简单
- 支持移动端,随时随地解决问题
@@ -36,7 +40,7 @@
---
## 安装部署
-码小六支持 [Docker 部署](doc/deploy-docker.md) 与 [源码部署](doc/deploy-source.md),请根据情况选择!
+码小六支持 [Docker-Compose 部署](doc/deploy-docker-compose.md)(推荐)、[Docker 部署](doc/deploy-docker.md) 与 [源码部署](doc/deploy-source.md),请根据情况选择!
---
diff --git a/app/Console/Commands/JobRunCommand.php b/app/Console/Commands/JobRunCommand.php
index 25b2c7f..a5997ea 100644
--- a/app/Console/Commands/JobRunCommand.php
+++ b/app/Console/Commands/JobRunCommand.php
@@ -85,19 +85,24 @@ public function handle()
$this->log->info('Get whitelist success');
while ($job = $this->takeJob()) {
- $keyword = $job->keyword;
- $this->log->info('Get a job from the queue', ['keyword' => $keyword]);
- $configJob = ConfigJob::where('keyword', $keyword)->first();
- $configJob->last_scan_at = date('Y-m-d H:i:s');
- $page = 1;
- do {
- $client = $this->service->getClient();
- $data = $this->searchCode($client, $keyword, $page);
- $count = $this->store($data, $configJob);
- $this->log->info('Store record', ['count' => $count]);
- $lastResponse = ResponseMediator::getPagination($client->getLastResponse());
- } while ($lastResponse['next'] && (++$page <= $configJob->scan_page));
- $configJob->save();
+ try {
+ $keyword = $job->keyword;
+ $this->log->info('Get a job from the queue', ['keyword' => $keyword]);
+ $configJob = ConfigJob::where('keyword', $keyword)->first();
+ $configJob->last_scan_at = date('Y-m-d H:i:s');
+ $page = 1;
+ do {
+ $client = $this->service->getClient();
+ $data = $this->searchCode($client, $keyword, $page);
+ $count = $this->store($data, $configJob);
+ $this->log->info('Store record', ['count' => $count]);
+ $lastResponse = ResponseMediator::getPagination($client->getLastResponse());
+ } while ($lastResponse['next'] && (++$page <= $configJob->scan_page));
+ $configJob->save();
+ } catch (Exception $exception) {
+ $this->log->error($exception->getMessage());
+ }
+ $job->delete();
}
$this->log->info('Work done');
@@ -124,10 +129,9 @@ private function createGitHubService()
*/
private function takeJob()
{
- if (!$job = QueueJob::orderBy('created_at')->first()) {
+ if (!$job = QueueJob::orderBy('id')->first()) {
return false;
}
- $job->delete();
return $job;
}
diff --git a/app/Http/Controllers/CodeLeakController.php b/app/Http/Controllers/CodeLeakController.php
index 892cd78..5882458 100644
--- a/app/Http/Controllers/CodeLeakController.php
+++ b/app/Http/Controllers/CodeLeakController.php
@@ -37,15 +37,22 @@ public function index(Request $request)
return $query->where('status', $request->input('status'));
});
- foreach (['repo_owner', 'repo_name', 'repo_description', 'keyword', 'path'] as $field) {
- $query->when($request->input($field), function ($query, $value) use ($field) {
- return $query->where($field, 'like', "%$value%");
+ $query->when($request->input('keyword'), function ($query) use ($request) {
+ return $query->where('keyword', $request->input('keyword'));
+ });
+
+ $query->when($search = $request->input('search'), function ($query) use ($search) {
+ $query->where(function ($query) use ($search) {
+ $query->where('path', 'like', "%$search%");
+ foreach (['repo_name', 'repo_owner', 'repo_description', 'handle_user', 'description'] as $column) {
+ $query->orwhere($column, 'like', "%$search%");
+ }
});
- }
+ });
$perPage = $request->input('limit', 100);
$data = $query->orderByDesc('id')->paginate($perPage);
- foreach ($data->items() as &$item){
+ foreach ($data->items() as &$item) {
$item->repo_description = htmlspecialchars($item->repo_description);
}
return $data;
diff --git a/app/Http/Controllers/ConfigJobController.php b/app/Http/Controllers/ConfigJobController.php
index 2193ad5..6df932d 100644
--- a/app/Http/Controllers/ConfigJobController.php
+++ b/app/Http/Controllers/ConfigJobController.php
@@ -3,7 +3,7 @@
namespace App\Http\Controllers;
use App\Models\ConfigJob;
-use Cron\CronExpression;
+use App\Models\QueueJob;
use Illuminate\Http\Request;
class ConfigJobController extends Controller
@@ -94,6 +94,37 @@ public function destroy($id)
}
}
+ /**
+ * 批量删除任务
+ *
+ * @param Request $request
+ * @return array
+ */
+ public function batchDestroy(Request $request)
+ {
+ try {
+ $id = json_decode($request->input('id'), true);
+ $success = ConfigJob::whereIn('id', $id)->delete();
+ return ['success' => $success];
+ } catch (\Exception $e) {
+ return ['success' => false, 'message' => $e->getMessage()];
+ }
+ }
+
+ /**
+ * 任务队列
+ *
+ * @return array
+ */
+ public function queue()
+ {
+ $data = QueueJob::orderBy('id')->get()->toArray();
+ foreach ($data as $k => $v) {
+ $data[$k]['status'] = $k == 0 ? 1 : 0;
+ }
+ return $data;
+ }
+
/**
* 下次扫描时间
*
@@ -102,8 +133,7 @@ public function destroy($id)
*/
private function getNextScanAt($interval)
{
- $expression = "*/$interval * * * *";
- $cron = CronExpression::factory($expression);
- return $cron->getNextRunDate()->format('Y-m-d H:i:s');
+ $nextScanAt = floor(LARAVEL_START - LARAVEL_START % ($interval * 60) + ($interval * 60));
+ return date('Y-m-d H:i:s', $nextScanAt);
}
}
diff --git a/app/Http/Controllers/ConfigNotifyController.php b/app/Http/Controllers/ConfigNotifyController.php
index 6bf869b..553b567 100644
--- a/app/Http/Controllers/ConfigNotifyController.php
+++ b/app/Http/Controllers/ConfigNotifyController.php
@@ -5,7 +5,6 @@
use App\Models\ConfigNotify;
use App\Services\NotifyService;
use Illuminate\Http\Request;
-use Illuminate\Support\Arr;
use Illuminate\Validation\Rule;
class ConfigNotifyController extends Controller
diff --git a/app/Http/Controllers/MobileController.php b/app/Http/Controllers/MobileController.php
index 7bf98c3..d966cf7 100644
--- a/app/Http/Controllers/MobileController.php
+++ b/app/Http/Controllers/MobileController.php
@@ -2,11 +2,17 @@
namespace App\Http\Controllers;
+use App\Models\CodeLeak;
+use Illuminate\Support\Facades\Request;
+
class MobileController extends Controller
{
public function home()
{
- $data = ['title' => '码小六'];
+ $page = Request::query('page', 1);
+ $tab = Request::query('tab', 'all');
+ $count = CodeLeak::query()->count();
+ $data = ['title' => '码小六', 'page' => $page, 'tab' => $tab, 'count' => $count];
return view('mobile.home', $data);
}
diff --git a/app/Services/GitHubService.php b/app/Services/GitHubService.php
index 2f6d0ac..02bb3dd 100644
--- a/app/Services/GitHubService.php
+++ b/app/Services/GitHubService.php
@@ -44,7 +44,7 @@ public function __construct()
*/
public function init()
{
- $this->proxy = $this->testProxy($this->proxy) ? $this->proxy : null;
+ $this->proxy = $this->proxy ? ($this->testProxy($this->proxy) ? $this->proxy : null) : null;
$tokens = ConfigToken::inRandomOrder()->get()->pluck('token');
foreach ($tokens as $token) {
$client = ['token' => $token];
diff --git a/app/Services/NotifyService.php b/app/Services/NotifyService.php
index d5843c4..8d0a2e7 100644
--- a/app/Services/NotifyService.php
+++ b/app/Services/NotifyService.php
@@ -28,11 +28,11 @@ public function email($title, $content, $config)
{
Config::set('mail', [
'driver' => 'smtp',
- 'encryption' => 'ssl',
'host' => $config['host'],
'port' => $config['port'] ?? 465,
'username' => $config['username'],
'password' => $config['password'],
+ 'encryption' => $config['encryption'] ?? 'SSL',
]);
try {
diff --git a/composer.lock b/composer.lock
index b0403fd..353364e 100644
--- a/composer.lock
+++ b/composer.lock
@@ -883,16 +883,16 @@
},
{
"name": "knplabs/github-api",
- "version": "v2.14.0",
+ "version": "v2.20.0",
"source": {
"type": "git",
"url": "https://github.com/KnpLabs/php-github-api.git",
- "reference": "953c9b453d3258a97755ec3557d112f271176f74"
+ "reference": "939869394c6414768547685945fdba4fe3f061b5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/KnpLabs/php-github-api/zipball/953c9b453d3258a97755ec3557d112f271176f74",
- "reference": "953c9b453d3258a97755ec3557d112f271176f74",
+ "url": "https://api.github.com/repos/KnpLabs/php-github-api/zipball/939869394c6414768547685945fdba4fe3f061b5",
+ "reference": "939869394c6414768547685945fdba4fe3f061b5",
"shasum": "",
"mirrors": [
{
@@ -916,12 +916,14 @@
"guzzlehttp/psr7": "^1.2",
"php-http/guzzle6-adapter": "^1.0 || ^2.0",
"php-http/mock-client": "^1.2",
+ "phpstan/phpstan": "^0.12.23",
"phpunit/phpunit": "^7.0 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.14.x-dev"
+ "dev-2.x": "2.20.x-dev",
+ "dev-master": "3.2.x-dev"
}
},
"autoload": {
@@ -952,7 +954,17 @@
"gist",
"github"
],
- "time": "2020-04-25T20:36:03+00:00"
+ "support": {
+ "issues": "https://github.com/KnpLabs/php-github-api/issues",
+ "source": "https://github.com/KnpLabs/php-github-api/tree/v2.20.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/acrobat",
+ "type": "github"
+ }
+ ],
+ "time": "2021-04-16T09:36:20+00:00"
},
{
"name": "laravel/framework",
@@ -7262,5 +7274,5 @@
"php": "^7.2.5"
},
"platform-dev": [],
- "plugin-api-version": "1.1.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/doc/deploy-docker-compose.md b/doc/deploy-docker-compose.md
new file mode 100644
index 0000000..19975b9
--- /dev/null
+++ b/doc/deploy-docker-compose.md
@@ -0,0 +1,69 @@
+# Docker-Compose 部署
+## 克隆代码
+```
+git clone https://github.com/4x99/code6.git
+```
+
+---
+
+## 修改配置
+```
+cd code6
+cp .env.docker-compose.example .env.docker-compose
+vim .env.docker-compose
+```
+
+请根据实际情况修改配置,这里 Web 端口以 `666` 为例:
+```
+# Web 映射到宿主机的端口
+PORT=666
+
+# MySQL 映射到宿主机的端口
+MYSQL_PORT=3306
+
+# MySQL 数据库名
+MYSQL_DATABASE=code6
+
+# MySQL 用户名(请使用非 root 用户)
+MYSQL_USER=
+
+# MySQL 密码
+MYSQL_PASSWORD=
+
+# MySQL 挂载到宿主机的目录
+MYSQL_VOLUME_PATH=
+```
+
+---
+
+## 启动容器
+启动容器,码小六将自动连接 MySQL 并导入数据表:
+```
+docker-compose --env-file .env.docker-compose up -d --build
+```
+
+---
+
+## 创建用户
+```
+docker exec -it code6-server /bin/bash
+php artisan code6:user-add <邮箱> <密码>
+```
+
+如需查看用户列表或删除用户请执行:
+```
+php artisan code6:user-list
+php artisan code6:user-delete <邮箱>
+```
+
+---
+
+## 访问系统
+```
+http://<宿主机 IP>:666
+```
+
+---
+
+## 配置令牌与任务
+进入系统后请前往 `[ 令牌配置 ]` 和 `[ 任务配置 ]` 模块进行配置,配置完毕即可使用!
diff --git a/doc/deploy-source.md b/doc/deploy-source.md
index e17a50c..e50707c 100644
--- a/doc/deploy-source.md
+++ b/doc/deploy-source.md
@@ -87,7 +87,6 @@ crontab -e -u <用户>
## 创建用户
```
-docker exec -it code6-server /bin/bash
php artisan code6:user-add <邮箱> <密码>
```
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..cc94741
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,45 @@
+version: "3.9"
+services:
+ mysql:
+ image: mysql/mysql-server:5.7
+ container_name: code6-mysql
+ restart: always
+ env_file:
+ - .env.docker-compose
+ networks:
+ - code6-network
+ ports:
+ - ${MYSQL_PORT}:3306
+ volumes:
+ - /etc/localtime:/etc/localtime:ro
+ - ${MYSQL_VOLUME_PATH}:/var/lib/mysql
+ healthcheck:
+ test: mysql ${MYSQL_DATABASE} -u${MYSQL_USER} -p${MYSQL_PASSWORD} -e 'SELECT 1'
+ interval: 5s
+ retries: 10
+ start_period: 60s
+ code6:
+ image: code6
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: code6-server
+ depends_on:
+ mysql:
+ condition: service_healthy
+ restart: always
+ env_file:
+ - .env.docker-compose
+ environment:
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_USERNAME: ${MYSQL_USER}
+ ports:
+ - ${PORT}:80
+ networks:
+ - code6-network
+ links:
+ - mysql
+networks:
+ code6-network:
+ name: code6-network
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index deb9fec..c125229 100644
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -1,20 +1,22 @@
#!/bin/bash
# 项目配置
-cp .env.example .env
-chmod -R 755 storage
-chown -R www-data:www-data storage
-php artisan key:generate
-sed -i "s!DB_HOST=127.0.0.1!DB_HOST=$MYSQL_HOST!" .env
-sed -i "s!DB_PORT=3306!DB_PORT=$MYSQL_PORT!" .env
-sed -i "s!DB_DATABASE=code6!DB_DATABASE=$MYSQL_DATABASE!" .env
-sed -i "s!DB_USERNAME=!DB_USERNAME=$MYSQL_USERNAME!" .env
-sed -i "s!DB_PASSWORD=!DB_PASSWORD=$MYSQL_PASSWORD!" .env
-php artisan migrate --force
+if [ ! -e '.env' ];then
+ cp -i .env.example .env
+ chmod -R 755 storage
+ chown -R www-data:www-data storage
+ php artisan key:generate
+ sed -i "s!DB_HOST=127.0.0.1!DB_HOST=$MYSQL_HOST!" .env
+ sed -i "s!DB_PORT=3306!DB_PORT=$MYSQL_PORT!" .env
+ sed -i "s!DB_DATABASE=code6!DB_DATABASE=$MYSQL_DATABASE!" .env
+ sed -i "s!DB_USERNAME=!DB_USERNAME=$MYSQL_USERNAME!" .env
+ sed -i "s!DB_PASSWORD=!DB_PASSWORD=$MYSQL_PASSWORD!" .env
+ php artisan migrate --force
+fi
# 配置任务调度
service cron start
-echo "* * * * * cd /var/www/html && /usr/local/bin/php artisan schedule:run>> /dev/null 2>&1">> /etc/cron.d/code6
+echo "* * * * * cd /var/www/html && /usr/local/bin/php artisan schedule:run>> /dev/null 2>&1"> /etc/cron.d/code6
crontab /etc/cron.d/code6
# 配置 Apache
diff --git a/doctor.php b/doctor.php
new file mode 100644
index 0000000..5c61a46
--- /dev/null
+++ b/doctor.php
@@ -0,0 +1,106 @@
+=') ? '' : 'PHP 版本需>= 7.3.0';
+console('PHP 版本', PHP_VERSION, $err);
+
+// PDO 扩展
+$pdo = class_exists('pdo');
+$err = $pdo ? '' : '请先安装 PHP PDO 扩展';
+console('PDO 扩展', $pdo ? '已安装' : '未安装', $err);
+
+// Laravel 密钥
+$err = $env['APP_KEY'] ? '' : '请执行命令 php artisan key:generate 生成密钥';
+console('Laravel 密钥', $env['APP_KEY'] ? '已生成' : '未生成', $err);
+
+// Storage 目录
+$writable = is_writable(ROOT.'/storage');
+$err = $writable ? '' : '请设置 storage 目录为可读写';
+console('Storage 目录', $writable ? '可读写' : '不可读写', $err);
+
+// Composer Package
+$import = file_exists(ROOT.'/vendor/autoload.php');
+$err = $import ? '' : '请安装 Composer 并执行 composer install 安装包';
+console('Composer Package', $import ? '已导入' : '未导入', $err);
+
+// MySQL 连接
+try {
+ $dberr = '';
+ $dsn = "mysql:host={$env['DB_HOST']}:{$env['DB_PORT']};dbname={$env['DB_DATABASE']}";
+ $db = new PDO($dsn, $env['DB_USERNAME'], $env['DB_PASSWORD'], [PDO::ATTR_TIMEOUT => 3]);
+} catch (Exception $e) {
+ $dberr = $e->getMessage();
+}
+console('MySQL 连接', $dberr ? '失败' : '成功', $dberr);
+
+// MySQL 数据表
+try {
+ if ($dberr) {
+ throw new Exception($dberr);
+ }
+ $err = false;
+ $tables = $db->query("show tables like 'code_leak'")->fetchAll(PDO::FETCH_ASSOC)[0];
+ if (!count($tables)) {
+ throw new Exception('请执行 php artisan migrate 导入数据表');
+ }
+} catch (Exception $e) {
+ $err = $e->getMessage();
+}
+console('MySQL 数据表', $err ? '未导入' : '已导入', $err);
+
+// GitHub API
+try {
+ $apierr = false;
+ $url = 'https://api.github.com';
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ curl_setopt($ch, CURLOPT_USERAGENT, 'code6');
+ $result = json_decode(curl_exec($ch), true);
+ if (empty($result)) {
+ throw new Exception("请求 $url 错误");
+ }
+ curl_close($ch);
+} catch (Exception $e) {
+ $apierr = $e->getMessage();
+}
+console('GitHub API', $apierr ? '请求错误' : '请求成功', $apierr);
+
+// PHP 禁用函数
+$disFuns = get_cfg_var('disable_functions') ?: '无';
+echo "PHP 禁用函数:$disFuns\n";
+
+// PHP 已编译模块
+$exts = implode(',', get_loaded_extensions());
+echo "PHP 已编译模块:$exts\n";
+
+echo DIVIDER."[ 系统信息 ]\n";
+
+// 码小六版本
+$version = trim(file_get_contents(ROOT.'/version'));
+echo "码小六版本:$version\n";
+
+// 框架运行环境
+$appEnv = $env['APP_ENV'] ?? '无';
+echo "框架运行环境:$appEnv\n";
+
+// 框架调试开关
+$appDebug = $env['APP_DEBUG'] ?? '无';
+echo "框架调试开关:$appDebug\n";
+
+echo DIVIDER."\n有任何问题和建议请联系-> https://github.com/4x99/code6/issues\n\n";
diff --git a/public/css/style.css b/public/css/style.css
index ebaf106..1da105b 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -189,6 +189,10 @@ textarea::-webkit-input-placeholder, input::-webkit-input-placeholder {
background: url(../image/icon/email.png) no-repeat;
}
+.icon-excel {
+ background: url(../image/icon/excel.png) no-repeat;
+}
+
.icon-feishu {
background: url(../image/icon/feishu.png) no-repeat;
}
diff --git a/public/image/icon/excel.png b/public/image/icon/excel.png
new file mode 100644
index 0000000..3f47759
Binary files /dev/null and b/public/image/icon/excel.png differ
diff --git a/public/js/extjs/plugin/export.js b/public/js/extjs/plugin/export.js
new file mode 100644
index 0000000..49fd892
--- /dev/null
+++ b/public/js/extjs/plugin/export.js
@@ -0,0 +1,52 @@
+/**
+ * 导出数据
+ */
+Ext.define('plugin.export', {
+ extend: 'Ext.Button',
+ text: '导出数据',
+ iconCls: 'icon-excel',
+ onClick: function () {
+ var data = this.getData();
+ this.saveCsv(data);
+ },
+ // 读取数据
+ getData: function () {
+ var header = [], value = [];
+ var grid = this.up('gridpanel');
+ var store = grid.store;
+ var columns = grid.columns ? grid.columns : grid.columnManager.columns;
+ Ext.each(store.getData().items, function (record, index) {
+ var row = [];
+ if (store.filters && !store.filters.filterFn(record)) {
+ return true;
+ }
+ Ext.each(columns, function (column) {
+ if (column.hidden || column.xtype === 'widgetcolumn') {
+ return true;
+ }
+ if (index === 0) {
+ header.push(column.text);
+ }
+ var value = record.get(column.dataIndex);
+ if (column.renderer) {
+ value = column.renderer(value, {}, record);
+ }
+ value = String(value).replace(/\n+|(
)+/ig, ' '); // 去除换行
+ value = Ext.util.Format.stripTags(value);
+ row.push(`"${value}"`);
+ });
+ value.push(row.join(','));
+ });
+ return header.join(',') + '\n' + value.join('\n');
+ },
+ // 保存 CSV 文件
+ saveCsv: function (data) {
+ const blob = new Blob([data], {type: 'text/csv'});
+ const url = window.URL.createObjectURL(blob)
+ const a = document.createElement('a')
+ a.href = url;
+ a.download = Ext.Date.format(new Date(), 'YmdHis') + '.csv'
+ a.click()
+ a.remove();
+ }
+});
diff --git a/public/js/extjs/plugin/grid.js b/public/js/extjs/plugin/grid.js
index 93c86c7..6bddff7 100644
--- a/public/js/extjs/plugin/grid.js
+++ b/public/js/extjs/plugin/grid.js
@@ -17,6 +17,14 @@ Ext.define('plugin.grid', {
xtype: 'pagingtoolbar',
dock: 'bottom',
displayInfo: true,
+ listeners: {
+ change: function (obj) {
+ var view = obj.up('grid').getView();
+ if (typeof(view.scrollTo) == 'function') {
+ view.scrollTo(0, 0);
+ }
+ }
+ }
}
]
});
diff --git a/resources/views/codeLeak/index.blade.php b/resources/views/codeLeak/index.blade.php
index 2b02311..7c2fdf5 100644
--- a/resources/views/codeLeak/index.blade.php
+++ b/resources/views/codeLeak/index.blade.php
@@ -50,7 +50,7 @@
format: 'Y-m-d',
maxValue: new Date(),
emptyText: '开始日期',
- width: 110,
+ width: 120,
},
{
xtype: 'datefield',
@@ -58,41 +58,19 @@
format: 'Y-m-d',
maxValue: new Date(),
emptyText: '结束日期',
- width: 110,
+ width: 120,
},
{
xtype: 'combo',
valueField: 'value',
- width: 65,
+ width: 120,
name: 'status',
emptyText: '状态',
store: {data: status}
},
- {
- xtype: 'textfield',
- name: 'repo_owner',
- emptyText: '用户名',
- },
- {
- xtype: 'textfield',
- name: 'repo_name',
- emptyText: '仓库名',
- },
- {
- xtype: 'textfield',
- name: 'path',
- emptyText: '文件路径',
- width: 130,
- },
- {
- xtype: 'textfield',
- name: 'repo_description',
- emptyText: '仓库描述',
- width: 130,
- },
{
xtype: 'combo',
- width: 150,
+ width: 120,
name: 'keyword',
displayField: 'keyword',
valueField: 'keyword',
@@ -110,9 +88,15 @@
},
},
},
+ {
+ xtype: 'textfield',
+ width: 380,
+ name: 'search',
+ emptyText: '用户名 / 仓库名 / 文件路径 / 仓库描述 / 处理人 / 说明',
+ },
{
xtype: 'buttongroup',
- baseCls: 'border:0',
+ baseCls: '',
width: 150,
items: [
{
@@ -202,6 +186,25 @@
}
]
},
+ dockedItems: [
+ {
+ xtype: 'pagingtoolbar',
+ dock: 'bottom',
+ displayInfo: true,
+ items: [
+ '-',
+ Ext.create('plugin.export'),
+ ],
+ listeners: {
+ change: function (obj) {
+ let view = obj.up('grid').getView();
+ if (typeof (view.scrollTo) == 'function') {
+ view.scrollTo(0, 0);
+ }
+ }
+ }
+ }
+ ],
columns: [
{
text: 'ID',
@@ -289,7 +292,7 @@
flex: 1,
align: 'center',
renderer: function (value) {
- return value ? value : '-';
+ return value ? Ext.String.htmlEncode(value) : '-';
}
},
{
@@ -300,7 +303,7 @@
xtype: 'widgetcolumn',
widget: {
xtype: 'buttongroup',
- baseCls: 'border:0',
+ baseCls: '',
layout: {
type: 'hbox',
pack: 'center',
@@ -461,7 +464,7 @@ function winForm(value, handler, modal) {
return Ext.create('Ext.window.Window', {
title: '编辑信息',
iconCls: 'icon-add',
- width: 350,
+ width: 600,
modal: modal,
layout: 'fit',
items: [
@@ -473,8 +476,9 @@ function winForm(value, handler, modal) {
{
fieldLabel: '说明',
name: 'description',
- xtype: 'textfield',
+ xtype: 'textareafield',
value: value,
+ fieldStyle: 'min-height:150px',
}
],
buttons: [
diff --git a/resources/views/configJob/index.blade.php b/resources/views/configJob/index.blade.php
index a706117..161c92c 100644
--- a/resources/views/configJob/index.blade.php
+++ b/resources/views/configJob/index.blade.php
@@ -6,8 +6,6 @@
Ext.onReady(function () {
Ext.QuickTips.init(true, {dismissDelay: 0});
- var GitHub = 'https://github.com/';
-
Ext.create('Ext.data.Store', {
storeId: 'store',
pageSize: 99999, // 不分页
@@ -24,9 +22,18 @@
{value: 2, text: '一个仓库只记录一次', qtip: '一个仓库只记录一次'},
];
+ var queue = {
+ config: [
+ {text: '待执行', color: 'gray'},
+ {text: '执行中', color: 'green'},
+ ],
+ tpl: new Ext.XTemplate('