Compare commits

..

25 Commits

Author SHA1 Message Date
dependabot[bot] c71df0c645 build(deps): bump guzzlehttp/guzzle from 7.10.4 to 7.14.1
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.10.4 to 7.14.1.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.15/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.10.4...7.14.1)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-version: 7.14.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-13 08:16:05 +00:00
net909 6c37f6d628 修复主域名判断 2026-07-02 18:02:47 +08:00
net909 7f2dfef3ba 新增HE DNS 2026-06-30 16:54:44 +08:00
wmwlwmwl ff8cb42e2d fix: 移除废弃的 curl_close() 调用,兼容 PHP 8.5 (#498)
- 删除 18 个文件中共 32 处 curl_close() 调用(PHP 8.0+ 已为无操作)

- 修复 ACMEv2.php 中 $code 可能为 null 的潜在问题

- 调整 public/.htaccess 伪静态规则,兼容 Windows + CGI 模式
2026-06-28 18:13:20 +08:00
dependabot[bot] 1d26b6c830 build(deps): bump cccyun/think-captcha from 3.0.11 to 3.0.12 (#496)
Bumps [cccyun/think-captcha](https://github.com/netcccyun/think-captcha) from 3.0.11 to 3.0.12.
- [Release notes](https://github.com/netcccyun/think-captcha/releases)
- [Commits](https://github.com/netcccyun/think-captcha/compare/3.0.11...3.0.12)

---
updated-dependencies:
- dependency-name: cccyun/think-captcha
  dependency-version: 3.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-24 21:10:24 +08:00
dependabot[bot] d75a7cb512 build(deps): bump phpmailer/phpmailer from 7.0.2 to 7.1.1 (#473)
Bumps [phpmailer/phpmailer](https://github.com/PHPMailer/PHPMailer) from 7.0.2 to 7.1.1.
- [Release notes](https://github.com/PHPMailer/PHPMailer/releases)
- [Changelog](https://github.com/PHPMailer/PHPMailer/blob/master/changelog.md)
- [Commits](https://github.com/PHPMailer/PHPMailer/compare/v7.0.2...v7.1.1)

---
updated-dependencies:
- dependency-name: phpmailer/phpmailer
  dependency-version: 7.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 17:42:45 +08:00
dependabot[bot] 81a80c6955 build(deps): bump guzzlehttp/guzzle from 7.10.0 to 7.10.4 (#479)
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.10.0 to 7.10.4.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.10/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.10.0...7.10.4)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-version: 7.10.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 17:42:32 +08:00
dependabot[bot] eb3b7dc256 build(deps): bump symfony/polyfill-mbstring from 1.37.0 to 1.38.1 (#480)
Bumps [symfony/polyfill-mbstring](https://github.com/symfony/polyfill-mbstring) from 1.37.0 to 1.38.1.
- [Release notes](https://github.com/symfony/polyfill-mbstring/releases)
- [Commits](https://github.com/symfony/polyfill-mbstring/compare/v1.37.0...v1.38.1)

---
updated-dependencies:
- dependency-name: symfony/polyfill-mbstring
  dependency-version: 1.38.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 17:42:18 +08:00
dependabot[bot] cade32cdfa build(deps): bump symfony/polyfill-php81 from 1.37.0 to 1.38.1 (#481)
Bumps [symfony/polyfill-php81](https://github.com/symfony/polyfill-php81) from 1.37.0 to 1.38.1.
- [Release notes](https://github.com/symfony/polyfill-php81/releases)
- [Commits](https://github.com/symfony/polyfill-php81/compare/v1.37.0...v1.38.1)

---
updated-dependencies:
- dependency-name: symfony/polyfill-php81
  dependency-version: 1.38.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 17:41:43 +08:00
dependabot[bot] 5b41a62934 build(deps): bump symfony/polyfill-intl-idn from 1.37.0 to 1.38.1 (#482)
Bumps [symfony/polyfill-intl-idn](https://github.com/symfony/polyfill-intl-idn) from 1.37.0 to 1.38.1.
- [Release notes](https://github.com/symfony/polyfill-intl-idn/releases)
- [Commits](https://github.com/symfony/polyfill-intl-idn/compare/v1.37.0...v1.38.1)

---
updated-dependencies:
- dependency-name: symfony/polyfill-intl-idn
  dependency-version: 1.38.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 17:41:24 +08:00
dependabot[bot] 547b81ffc3 build(deps): bump actions/checkout from 6 to 7 (#492)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 11:23:13 +08:00
Hanada 7f2d57331e feat: 网宿CDNPro支持直接部署指定证书 (#488) 2026-06-06 16:07:00 +08:00
nameless a98d7427d8 fix 火山云部署证书增加上传项目名称,增加延迟一秒修改证书实例 (#484)
* fix 火山云部署证书增加上传项目名称,增加延迟一秒修改证书实例

* fix 火山云视频直播上传证书支持上传到指定项目名称

* fix 格式化代码
2026-06-02 09:49:09 +08:00
net909 80f1f543e3 优化服务端列头排序 2026-05-18 11:06:09 +08:00
TomyJan 53cb2ac875 feat: 全部列表页支持服务端列头排序 (#470) 2026-05-18 10:49:18 +08:00
net909 12a40cfa7a 修复权限校验问题 2026-05-17 13:19:36 +08:00
net909 9bddf14be9 优化持久化分页大小功能 2026-05-17 13:08:44 +08:00
TomyJan 04acd73033 refactor: 重构分页系统,统一使用localStorage持久化分页大小 (#467)
* refactor: 重构分页系统,统一使用localStorage持久化分页大小

所有列表统一分页大小选项 [10, 15, 20, 30, 50, 100, 200, 300, 500],默认值 15
前端所有表格页面使用 localStorage 替代 cookie 持久化用户选择的分页大小
前端 getStoredPageSize/setStoredPageSize 对分页大小做白名单校验
后端新增 validateLimit() 方法对所有 limit 参数做白名单校验
移除原有的 cookie 分页大小存储逻辑

* fix: 避免缓存 custom.js
2026-05-17 12:53:35 +08:00
net909 ab7a40afbd Merge branch 'main' of ssh://ssh.github.com:443/netcccyun/dnsmgr 2026-05-09 12:42:23 +08:00
net909 a4fe9393b8 阿里云腾讯云DNS支持解析记录分组 2026-05-09 12:42:02 +08:00
dependabot[bot] f2c769375b build(deps): bump docker/login-action from 3 to 4 (#461)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3 to 4.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 18:57:55 +08:00
dependabot[bot] fb057050fe build(deps): bump actions/checkout from 4 to 6 (#462)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 18:57:44 +08:00
dependabot[bot] a35f6c90df build(deps): bump docker/setup-buildx-action from 3 to 4 (#463)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 18:57:34 +08:00
dependabot[bot] 8b13dee807 build(deps): bump docker/setup-qemu-action from 3 to 4 (#464)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 18:57:26 +08:00
dependabot[bot] c736ddf2fc build(deps): bump docker/build-push-action from 6 to 7 (#460)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6 to 7.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 18:57:17 +08:00
59 changed files with 1513 additions and 269 deletions
+6 -6
View File
@@ -18,29 +18,29 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to Huawei SWR
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: swr.cn-east-3.myhuaweicloud.com
username: ${{ secrets.HUAWEI_SWR_USERNAME }}
password: ${{ secrets.HUAWEI_SWR_PASSWORD }}
- name: Build and push (Docker Hub + Huawei SWR, latest only)
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .github/docker
file: .github/docker/Dockerfile
+1 -1
View File
@@ -312,7 +312,7 @@ function getMainDomain($host)
}
}
$domain_root = file_get_contents(app()->getBasePath() . 'data' . DIRECTORY_SEPARATOR . 'domain_root.txt');
$domain_root = explode("\r\n", $domain_root);
$domain_root = explode("\n", $domain_root);
$data = explode('.', $host);
$co_ta = count($data);
if ($co_ta <= 2) return $host;
+36 -4
View File
@@ -33,13 +33,21 @@ class Cert extends BaseController
$kw = $this->request->post('kw', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('cert_account')->where('deploy', $deploy);
if (!empty($kw)) {
$select->whereLike('name|remark', '%' . $kw . '%')->whereOr('id', $kw);
}
$total = $select->count();
$rows = $select->order('id', 'desc')->limit($offset, $limit)->select();
$allowedSort = ['id' => 'id', 'typename' => 'type', 'name' => 'name', 'remark' => 'remark', 'addtime' => 'addtime'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('id', 'desc');
}
$rows = $select->limit($offset, $limit)->select();
$list = [];
foreach ($rows as $row) {
@@ -216,6 +224,8 @@ class Cert extends BaseController
$status = input('post.status', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('cert_order')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id');
if (!empty($id)) {
@@ -242,7 +252,13 @@ class Cert extends BaseController
}
}
$total = $select->count();
$rows = $select->fieldRaw('A.*,B.type,B.remark aremark')->order('id', 'desc')->limit($offset, $limit)->select();
$allowedSort = ['id' => 'A.id', 'typename' => 'B.type', 'keytype' => 'A.keytype', 'isauto' => 'A.isauto', 'issuetime' => 'A.issuetime', 'end_day' => 'A.expiretime', 'status' => 'A.status'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$rows = $select->fieldRaw('A.*,B.type,B.remark aremark')->limit($offset, $limit)->select();
$list = [];
foreach ($rows as $row) {
@@ -650,6 +666,8 @@ class Cert extends BaseController
$remark = input('post.remark', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('cert_deploy')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id')->leftJoin('cert_order C', 'A.oid = C.id')->leftJoin('cert_account D', 'C.aid = D.id');
if (!empty($oid)) {
@@ -671,7 +689,13 @@ class Cert extends BaseController
$select->where('A.remark', $remark);
}
$total = $select->count();
$rows = $select->fieldRaw('A.*,B.type,B.remark aremark,B.name aname,D.type certtype,D.id certaid')->order('id', 'desc')->limit($offset, $limit)->select();
$allowedSort = ['id' => 'A.id', 'typename' => 'B.type', 'remark' => 'A.remark', 'active' => 'A.active', 'lasttime' => 'A.lasttime', 'status' => 'A.status'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$rows = $select->fieldRaw('A.*,B.type,B.remark aremark,B.name aname,D.type certtype,D.id certaid')->limit($offset, $limit)->select();
$list = [];
foreach ($rows as $row) {
@@ -862,13 +886,21 @@ class Cert extends BaseController
$kw = $this->request->post('kw', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('cert_cname')->alias('A')->leftJoin('domain B', 'A.did = B.id');
if (!empty($kw)) {
$select->whereLike('A.domain', '%' . $kw . '%');
}
$total = $select->count();
$rows = $select->order('A.id', 'desc')->limit($offset, $limit)->field('A.*,B.name cnamedomain')->select();
$allowedSort = ['id' => 'A.id', 'domain' => 'A.domain', 'status' => 'A.status', 'addtime' => 'A.addtime'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$rows = $select->limit($offset, $limit)->field('A.*,B.name cnamedomain')->select();
$list = [];
foreach ($rows as $row) {
+9 -1
View File
@@ -43,6 +43,8 @@ class Dmonitor extends BaseController
$kw = input('post.kw', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('dmtask')->alias('A')->join('domain B', 'A.did = B.id');
if (!empty($kw)) {
@@ -62,7 +64,13 @@ class Dmonitor extends BaseController
$select->where('status', intval($status));
}
$total = $select->count();
$list = $select->order('A.id', 'desc')->limit($offset, $limit)->field('A.*,B.name domain')->select()->toArray();
$allowedSort = ['id' => 'A.id', 'rr' => 'A.rr', 'main_value' => 'A.main_value', 'type' => 'A.type', 'checktype' => 'A.checktype', 'frequency' => 'A.frequency', 'status' => 'A.status', 'active' => 'A.active', 'checktimestr' => 'A.checktime', 'addtimestr' => 'A.addtime', 'remark' => 'A.remark'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$list = $select->limit($offset, $limit)->field('A.*,B.name domain')->select()->toArray();
foreach ($list as &$row) {
$row['addtimestr'] = date('Y-m-d H:i:s', $row['addtime']);
+70 -19
View File
@@ -26,13 +26,21 @@ class Domain extends BaseController
$kw = $this->request->post('kw', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('account');
if (!empty($kw)) {
$select->whereLike('name|remark', '%' . $kw . '%');
}
$total = $select->count();
$rows = $select->order('id', 'desc')->limit($offset, $limit)->select();
$allowedSort = ['id' => 'id', 'typename' => 'type', 'name' => 'name', 'remark' => 'remark', 'addtime' => 'addtime'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('id', 'desc');
}
$rows = $select->limit($offset, $limit)->select();
$list = [];
foreach ($rows as $row) {
@@ -192,7 +200,8 @@ class Domain extends BaseController
$type = input('post.type', null, 'trim');
$status = input('post.status', null, 'trim');
$cid = input('post.cid', null, 'trim');
$order = input('post.order', null, 'trim');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$offset = input('post.offset/d', 0);
$limit = input('post.limit/d', 10);
$id = input('post.id');
@@ -224,21 +233,11 @@ class Domain extends BaseController
}
}
$total = $select->count();
switch ($order) {
case '1':
$select->order('A.regtime', 'asc');
break;
case '2':
$select->order('A.regtime', 'desc');
break;
case '3':
$select->order('A.expiretime', 'asc');
break;
case '4':
$select->order('A.expiretime', 'desc');
break;
default:
$select->order('A.id', 'desc');
$allowedSort = ['id' => 'A.id', 'name' => 'A.name', 'recordcount' => 'A.recordcount', 'addtime' => 'A.addtime', 'regtime' => 'A.regtime', 'expiretime' => 'A.expiretime', 'is_notice' => 'A.is_notice', 'is_hide' => 'A.is_hide', 'is_sso' => 'A.is_sso', 'typename' => 'B.type', 'category_name' => 'A.cid', 'remark' => 'A.remark'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$rows = $select->fieldRaw('A.*,B.type,B.remark aremark')->limit($offset, $limit)->select();
@@ -256,12 +255,12 @@ class Domain extends BaseController
public function domain_op()
{
if (!checkPermission(1)) return $this->alert('error', '无权限');
$act = input('param.act');
if ($act == 'get') {
$id = input('post.id/d');
$row = Db::name('domain')->where('id', $id)->find();
if (!$row) return json(['code' => -1, 'msg' => '域名不存在']);
if (!checkPermission(0, $row['name'])) return json(['code' => -1, 'msg' => '无权限']);
return json(['code' => 0, 'data' => $row]);
} elseif ($act == 'add') {
if (!checkPermission(2)) return $this->alert('error', '无权限');
@@ -771,6 +770,18 @@ class Domain extends BaseController
}
}
$msg = '批量修改备注,成功' . $success . '条,失败' . $fail . '条';
} else if ($action == 'group') {
$dnstype = Db::name('account')->where('id', $drow['aid'])->value('type');
if (!in_array($dnstype, ['aliyun', 'dnspod'])) {
return json(['code' => -1, 'msg' => '该DNS类型不支持分组']);
}
$groupid = input('post.groupid', '', 'trim');
$recordIdList = array_column($recordinfo, 'RecordId');
if ($dns->changeRecordGroup($recordIdList, $groupid)) {
$msg = '成功修改' . count($recordIdList) . '条记录的分组';
} else {
return json(['code' => -1, 'msg' => '修改分组失败,' . $dns->getError()]);
}
}
return json(['code' => 0, 'msg' => $msg]);
}
@@ -1078,6 +1089,38 @@ class Domain extends BaseController
}
}
public function record_groups()
{
$id = input('param.id/d');
$drow = Db::name('domain')->where('id', $id)->find();
if (!$drow) {
return json(['code' => -1, 'msg' => '域名不存在']);
}
if (!checkPermission(0, $drow['name'])) return json(['code' => -1, 'msg' => '无权限']);
$dnstype = Db::name('account')->where('id', $drow['aid'])->value('type');
if (!in_array($dnstype, ['aliyun', 'dnspod'])) {
return json(['code' => -1, 'msg' => '该DNS类型不支持分组']);
}
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$groups = $dns->getRecordGroups();
if ($groups === false) {
return json(['code' => -1, 'msg' => '获取分组列表失败,' . $dns->getError()]);
}
$groupList = [];
if ($dnstype == 'dnspod') {
$groupList[] = ['id' => '', 'name' => '全部记录'];
}
foreach ($groups as $group) {
$groupList[] = [
'id' => $group['GroupId'],
'name' => $group['GroupName'] . (isset($group['RecordCount']) ? '(' . $group['RecordCount'] . ')' : ''),
];
}
return json(['code' => 0, 'data' => $groupList]);
}
private function add_log($domain, $action, $data)
{
if (strlen($data) > 500) $data = substr($data, 0, 500);
@@ -1348,10 +1391,18 @@ class Domain extends BaseController
if (!checkPermission(2)) return json(['total' => 0, 'rows' => []]);
$offset = input('post.offset/d', 0);
$limit = input('post.limit/d', 10);
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('domain_category');
$total = $select->count();
$rows = $select->order('sort', 'asc')->order('id', 'desc')->limit($offset, $limit)->select()->toArray();
$allowedSort = ['id' => 'id', 'name' => 'name', 'remark' => 'remark', 'sort' => 'sort', 'addtime' => 'addtime'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('id', 'desc');
}
$rows = $select->limit($offset, $limit)->select()->toArray();
foreach ($rows as &$row) {
$row['domain_count'] = Db::name('domain')->where('cid', $row['id'])->count();
+9 -1
View File
@@ -45,6 +45,8 @@ class Optimizeip extends BaseController
$status = input('post.status', null);
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('optimizeip')->alias('A')->join('domain B', 'A.did = B.id');
if (!empty($kw)) {
@@ -58,7 +60,13 @@ class Optimizeip extends BaseController
$select->where('status', intval($status));
}
$total = $select->count();
$list = $select->order('A.id', 'desc')->limit($offset, $limit)->field('A.*,B.name domain')->select();
$allowedSort = ['id' => 'A.id', 'rr' => 'A.rr', 'cdn_type' => 'A.cdn_type', 'recordnum' => 'A.recordnum', 'ip_type' => 'A.ip_type', 'active' => 'A.active', 'updatetime' => 'A.updatetime', 'status' => 'A.status'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$list = $select->limit($offset, $limit)->field('A.*,B.name domain')->select();
return json(['total' => $total, 'rows' => $list]);
}
+9 -1
View File
@@ -24,6 +24,8 @@ class Schedule extends BaseController
$stype = input('post.stype', null);
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('sctask')->alias('A')->join('domain B', 'A.did = B.id');
if (!empty($kw)) {
@@ -41,7 +43,13 @@ class Schedule extends BaseController
$select->where('type', $stype);
}
$total = $select->count();
$list = $select->order('A.id', 'desc')->limit($offset, $limit)->field('A.*,B.name domain')->select()->toArray();
$allowedSort = ['id' => 'A.id', 'rr' => 'A.rr', 'type' => 'A.type', 'switchtype' => 'A.switchtype', 'active' => 'A.active', 'updatetimestr' => 'A.updatetime', 'nexttimestr' => 'A.nexttime', 'addtimestr' => 'A.addtime', 'remark' => 'A.remark'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('A.id', 'desc');
}
$list = $select->limit($offset, $limit)->field('A.*,B.name domain')->select()->toArray();
foreach ($list as &$row) {
$row['addtimestr'] = date('Y-m-d H:i:s', $row['addtime']);
+9 -1
View File
@@ -28,13 +28,21 @@ class User extends BaseController
$kw = input('post.kw', null, 'trim');
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$sort = input('post.sortName', null, 'trim');
$orderDir = strtolower(input('post.sortOrder', 'desc')) === 'asc' ? 'asc' : 'desc';
$select = Db::name('user');
if (!empty($kw)) {
$select->whereLike('id|username', $kw);
}
$total = $select->count();
$rows = $select->order('id', 'desc')->limit($offset, $limit)->select();
$allowedSort = ['id' => 'id', 'username' => 'username', 'level' => 'level', 'is_api' => 'is_api', 'regtime' => 'regtime', 'lasttime' => 'lasttime', 'status' => 'status'];
if ($sort && isset($allowedSort[$sort])) {
$select->order($allowedSort[$sort], $orderDir);
} else {
$select->order('id', 'desc');
}
$rows = $select->limit($offset, $limit)->select();
return json(['total' => $total, 'rows' => $rows]);
}
+8 -1
View File
@@ -2035,6 +2035,12 @@ ctrl+x 保存退出<br/>',
'show' => 'product==\'clb\'||product==\'alb\'',
'required' => true,
],
'project_name' => [
'name' => '证书上传项目名称',
'type' => 'input',
'placeholder' => '证书实例所属的火山引擎项目名称。如果不设置该参数,证书实例会属于default项目。',
'required' => false,
],
],
],
'west' => [
@@ -2116,6 +2122,7 @@ ctrl+x 保存退出<br/>',
'options' => [
['value'=>'cdn', 'label'=>'CDN'],
['value'=>'cdnpro', 'label'=>'CDN Pro'],
['value'=>'cdnpro_certificate', 'label'=>'CDN Pro证书管理'],
['value'=>'certificate', 'label'=>'证书管理']
],
'value' => 'cdn',
@@ -2138,7 +2145,7 @@ ctrl+x 保存退出<br/>',
'cert_id' => [
'name' => '证书ID',
'type' => 'input',
'show' => 'product==\'certificate\'',
'show' => 'product==\'certificate\'||product==\'cdnpro_certificate\'',
'placeholder' => '',
'required' => true,
],
+36
View File
@@ -442,6 +442,41 @@ class DnsHelper
'page' => true,
'add' => false,
],
'henet' => [
'name' => 'HE DNS',
'icon' => 'he.ico',
'note' => '',
'config' => [
'username' => [
'name' => '用户名/邮箱',
'type' => 'input',
'placeholder' => '',
'required' => true,
],
'password' => [
'name' => '密码',
'type' => 'input',
'placeholder' => '',
'required' => true,
],
'proxy' => [
'name' => '使用代理服务器',
'type' => 'radio',
'options' => [
'0' => '否',
'1' => '是',
],
'value' => '0'
],
],
'remark' => 0,
'status' => false,
'redirect' => false,
'log' => false,
'weight' => false,
'page' => true,
'add' => false,
],
'spaceship' => [
'name' => 'Spaceship',
'icon' => 'spaceship.ico',
@@ -699,6 +734,7 @@ class DnsHelper
'qingcloud' => ['DEF' => '0', 'CT' => '2', 'CU' => '3', 'CM' => '4', 'AB' => '8'],
'cloudflare' => ['DEF' => '0'],
'namesilo' => ['DEF' => 'default'],
'henet' => ['DEF' => 'default'],
'powerdns' => ['DEF' => 'default'],
'spaceship' => ['DEF' => 'default'],
'aliyunesa' => ['DEF' => '0'],
+2 -3
View File
@@ -29,7 +29,6 @@ class ACMEv2
public function __destruct()
{
if (PHP_MAJOR_VERSION < 8 && $this->account_key) openssl_pkey_free($this->account_key);
if ($this->ch) curl_close($this->ch);
}
public function loadAccountKey($account_key_pem)
@@ -377,7 +376,7 @@ class ACMEv2
if (!empty($headers['content-type'])) {
switch ($headers['content-type']) {
case 'application/json':
if ($code[0] == '2') { // on non 2xx response: fall through to problem+json case
if (!is_null($code) && $code[0] == '2') { // on non 2xx response: fall through to problem+json case
$body = $this->json_decode($body);
if (isset($body['error']) && !(isset($body['status']) && $body['status'] === 'valid')) {
$this->handleError($body['error']);
@@ -391,7 +390,7 @@ class ACMEv2
}
}
if ($code[0] != '2') {
if (!is_null($code) && $code[0] != '2') {
throw new Exception('Invalid HTTP-Status-Code received: ' . $code . ': ' . print_r($body, true));
}
-2
View File
@@ -286,7 +286,6 @@ class AWS
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
@@ -297,7 +296,6 @@ class AWS
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$response = substr($response, $headerSize);
}
curl_close($ch);
if ($httpCode >= 200 && $httpCode < 300) {
if (empty($response)) return true;
-2
View File
@@ -63,10 +63,8 @@ class Aliyun
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
$arr = json_decode($response, true);
if ($httpCode == 200) {
-2
View File
@@ -169,11 +169,9 @@ class AliyunNew
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($response, true);
if ($httpCode == 200) {
-2
View File
@@ -120,10 +120,8 @@ class AliyunOSS
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
if ($httpCode >= 200 && $httpCode < 300) {
if (empty($response)) return true;
-2
View File
@@ -159,10 +159,8 @@ class BaiduCloud
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
if (empty($response) && $httpCode == 200) {
return true;
-2
View File
@@ -150,10 +150,8 @@ class Ctyun
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
$arr = json_decode($response, true);
if (isset($arr['statusCode']) && ($arr['statusCode'] == 100000 || $arr['statusCode'] == 0 && $this->endpoint == 'cf-global.ctapi.ctyun.cn')) {
-2
View File
@@ -164,11 +164,9 @@ class HuaweiCloud
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($response, true);
if ($arr) {
-2
View File
@@ -107,10 +107,8 @@ class HuaweiOBS
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
if ($httpCode >= 200 && $httpCode < 300) {
if (empty($response)) return true;
-2
View File
@@ -168,11 +168,9 @@ class Jdcloud
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($response, true);
if ($httpCode == 200) {
-2
View File
@@ -189,11 +189,9 @@ class Ksyun
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($response, true);
if ($httpCode == 200) {
-2
View File
@@ -122,10 +122,8 @@ class Qiniu
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
if ($httpCode == 200) {
$arr = json_decode($response, true);
-2
View File
@@ -114,10 +114,8 @@ class TencentCloud
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
curl_close($ch);
$arr = json_decode($response, true);
if ($arr) {
-2
View File
@@ -219,11 +219,9 @@ class Volcengine
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$arr = json_decode($response, true);
if ($httpCode == 200) {
+9 -3
View File
@@ -33,7 +33,7 @@ class huoshan implements DeployInterface
if ($config['product'] == 'live') {
$this->deploy_live($fullchain, $privatekey, $config);
} else {
$cert_id = $this->get_cert_id($fullchain, $privatekey);
$cert_id = $this->get_cert_id($fullchain, $privatekey, $config);
if (!$cert_id) throw new Exception('获取证书ID失败');
$info['cert_id'] = $cert_id;
if (!isset($config['product']) || $config['product'] == 'cdn') {
@@ -121,6 +121,9 @@ class huoshan implements DeployInterface
],
'UseWay' => 'https',
];
if (!empty($config['project_name'])) {
$param['ProjectName'] = $config['project_name'];
}
$result = $client->request('POST', 'CreateCert', $param);
$this->log('上传证书成功 ChainID=' . $result['ChainID']);
@@ -214,7 +217,7 @@ class huoshan implements DeployInterface
$this->log('ALB监听器 ' . $config['listener_id'] . ' 部署证书成功!');
}
private function get_cert_id($fullchain, $privatekey)
private function get_cert_id($fullchain, $privatekey, $config)
{
$certInfo = openssl_x509_parse($fullchain, true);
if (!$certInfo) throw new Exception('证书解析失败');
@@ -229,6 +232,9 @@ class huoshan implements DeployInterface
'PrivateKey' => $privatekey,
],
];
if (!empty($config['project_name'])) {
$param['ProjectName'] = $config['project_name'];
}
try {
$data = $client->request('POST', 'ImportCertificate', $param);
} catch (Exception $e) {
@@ -237,7 +243,7 @@ class huoshan implements DeployInterface
if (!empty($data['InstanceId'])) {
$cert_id = $data['InstanceId'];
$this->log('上传证书成功 CertId=' . $cert_id);
sleep(1);
$param = [
'InstanceId' => $cert_id,
'Options' => [
-1
View File
@@ -175,7 +175,6 @@ class k8s implements DeployInterface
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$err = curl_error($ch);
curl_close($ch);
return [$code, $resp, $err];
}
-2
View File
@@ -105,11 +105,9 @@ class s3storage implements DeployInterface
$errno = curl_errno($ch);
if ($errno) {
$errmsg = curl_error($ch);
curl_close($ch);
throw new Exception('Curl error: ' . $errmsg);
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 200 && $httpCode < 300) {
return $response;
+97
View File
@@ -44,6 +44,10 @@ class wangsu implements DeployInterface
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
$serial_no = strtolower($certInfo['serialNumberHex']);
$this->get_cert_id($fullchain, $privatekey, $cert_name, $config['cert_id'], $serial_no, true);
} elseif ($config['product'] == 'cdnpro_certificate') {
$this->deploy_cdnpro_certificate($fullchain, $privatekey, $config, $info);
} else {
throw new Exception('未知的产品类型');
}
@@ -213,6 +217,56 @@ class wangsu implements DeployInterface
$info['cert_id'] = $cert_id;
}
public function deploy_cdnpro_certificate($fullchain, $privatekey, $config, &$info)
{
$certInfo = openssl_x509_parse($fullchain, true);
if (!$certInfo) {
throw new Exception('证书解析失败');
}
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
$cert_id = isset($config['cert_id']) ? $config['cert_id'] : null;
if (empty($cert_id)) {
throw new Exception('证书ID不能为空');
}
$result = $this->update_cert_id_cdnpro($fullchain, $privatekey, $cert_name, $cert_id);
$cert_id = $result['cert_id'];
if (empty($result['updated'])) {
$info['cert_id'] = $cert_id;
return;
}
$certVersion = $result['version'];
// 下发证书部署任务
$deploymentTasks = [
'target' => 'production',
'actions' => [
[
'action' => 'deploy_cert',
'certificateId' => $cert_id,
'version' => intval($certVersion),
]
],
'name' => 'Deploy certificate ' . $cert_name,
];
try {
$data = $this->request('/cdn/deploymentTasks', $deploymentTasks, true, null, 'POST', false, ['Check-Certificate' => 'no', 'Check-Usage' => 'no']);
} catch (Exception $e) {
throw new Exception('下发证书部署任务失败:' . $e->getMessage());
}
$url_parts = parse_url($data);
$path_parts = explode('/', $url_parts['path']);
$deploymentTaskId = end($path_parts);
$this->log('证书部署任务下发成功,部署任务ID:' . $deploymentTaskId);
$info['cert_id'] = $cert_id;
}
private function get_cert_id($fullchain, $privatekey, $cert_name, $cert_id = null, $serial_no = null, $overwrite = false)
{
if ($cert_id) {
@@ -349,6 +403,49 @@ class wangsu implements DeployInterface
return $cert_id;
}
private function update_cert_id_cdnpro($fullchain, $privatekey, $cert_name, $cert_id)
{
try {
$data = $this->request('/cdn/certificates/' . $cert_id);
} catch (Exception $e) {
throw new Exception('证书ID ' . $cert_id . ' 不存在或获取失败:' . $e->getMessage());
}
if (isset($data['name']) && $data['name'] == $cert_name) {
$this->log('证书已是最新,无需更新,证书ID:' . $cert_id);
return ['cert_id' => $cert_id, 'updated' => false];
}
$this->log('证书已过期,准备更新...');
$date = gmdate("D, d M Y H:i:s T");
$encryptedKey = $this->encryptPrivateKey($privatekey, $date);
$param = [
'name' => $cert_name,
'newVersion' => [
'privateKey' => $encryptedKey,
'certificate' => $fullchain,
'comments' => $cert_name,
]
];
try {
$location = $this->request('/cdn/certificates/' . $cert_id, $param, true, $date, 'PATCH', true);
} catch (Exception $e) {
throw new Exception('更新证书失败:' . $e->getMessage());
}
// 从 Location 头解析版本号,格式:.../certificates/{id}/versions/{version}
$version = 1;
if (is_string($location)) {
$path_parts = explode('/', parse_url($location, PHP_URL_PATH));
$version = intval(end($path_parts));
}
$this->log('更新证书成功,证书ID' . $cert_id . ',版本号:' . $version);
return ['cert_id' => $cert_id, 'version' => $version, 'updated' => true];
}
private function encryptPrivateKey($privateKey, $date = null)
{
// 获取当前 GMT 时间(DATE
+23 -1
View File
@@ -72,6 +72,10 @@ class aliyun implements DnsInterface
$Status = $Status == '1' ? 'Enable' : 'Disable';
$param += ['Status' => $Status];
}
$groupid = request()->post('groupid');
if (!empty($groupid)) {
$param += ['GroupId' => $groupid];
}
$data = $this->request($param, true);
if ($data) {
$list = [];
@@ -234,7 +238,7 @@ class aliyun implements DnsInterface
public function getDomainInfo()
{
if (!empty($this->domainInfo)) return $this->domainInfo;
$param = ['Action' => 'DescribeDomainInfo', 'DomainName' => $this->domain, 'NeedDetailAttributes' => 'true'];
$param = ['Action' => 'DescribeDomainInfo', 'DomainName' => $this->domain, 'NeedDetailAttributes' => 'true', 'Lang' => 'zh'];
$data = $this->request($param, true);
if ($data) {
$this->domainInfo = $data;
@@ -253,6 +257,24 @@ class aliyun implements DnsInterface
return false;
}
//获取解析记录分组列表
public function getRecordGroups()
{
$param = ['Action' => 'DescribeRecordGroups', 'DomainName' => $this->domain, 'PageSize' => 100, 'Lang' => 'zh'];
$data = $this->request($param, true);
if ($data) {
return $data['RecordGroups']['RecordGroup'];
}
return false;
}
//修改解析记录分组
public function changeRecordGroup($RecordIdList, $GroupId)
{
$param = ['Action' => 'ChangeRecordGroup', 'DomainName' => $this->domain, 'RecordIdList' => json_encode($RecordIdList), 'GroupId' => $GroupId];
return $this->request($param);
}
//获取权重配置子域名列表
public function getWeightSubDomains($PageNumber = 1, $PageSize = 20, $SubDomain = null)
{
+25 -1
View File
@@ -66,7 +66,8 @@ class dnspod implements DnsInterface
public function getDomainRecords($PageNumber = 1, $PageSize = 20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null)
{
$offset = ($PageNumber - 1) * $PageSize;
if (!isNullOrEmpty($Status) || !isNullOrEmpty($Value)) {
$groupid = request()->post('groupid');
if (!isNullOrEmpty($Status) || !isNullOrEmpty($Value) || !empty($groupid)) {
$action = 'DescribeRecordFilterList';
$param = ['Domain' => $this->domain, 'Offset' => $offset, 'Limit' => $PageSize, 'RecordValue' => $Value];
if (!isNullOrEmpty($SubDomain)) $param['SubDomain'] = $SubDomain;
@@ -78,6 +79,7 @@ class dnspod implements DnsInterface
}
if (!isNullOrEmpty($Type)) $param['RecordType'] = [$this->convertType($Type)];
if (!isNullOrEmpty($Line)) $param['RecordLine'] = [$Line];
if (!empty($groupid)) $param['GroupId'] = [intval($groupid)];
} else {
$action = 'DescribeRecordList';
$param = ['Domain' => $this->domain, 'Subdomain' => $SubDomain, 'RecordType' => $this->convertType($Type), 'RecordLineId' => $Line, 'Keyword' => $KeyWord, 'Offset' => $offset, 'Limit' => $PageSize];
@@ -365,6 +367,28 @@ class dnspod implements DnsInterface
return is_array($data);
}
//获取解析记录分组列表
public function getRecordGroups()
{
$action = 'DescribeRecordGroupList';
$param = ['Domain' => $this->domain];
$data = $this->send_request($action, $param);
if ($data) {
return $data['GroupList'];
}
return false;
}
//将记录移动到分组
public function changeRecordGroup($RecordIdList, $GroupId)
{
$action = 'ModifyRecordToGroup';
$RecordIdList = implode('|', $RecordIdList);
$param = ['Domain' => $this->domain, 'GroupId' => intval($GroupId), 'RecordId' => strval($RecordIdList)];
$data = $this->send_request($action, $param);
return is_array($data);
}
private function convertLineCode($line)
{
$convert_dict = ['default' => '0', 'unicom' => '10=1', 'telecom' => '10=0', 'mobile' => '10=3', 'edu' => '10=2', 'oversea' => '3=0', 'btvn' => '10=22', 'search' => '80=0', 'internal' => '7=0'];
+562
View File
@@ -0,0 +1,562 @@
<?php
namespace app\lib\dns;
use app\lib\DnsInterface;
use Exception;
use think\facade\Cache;
class henet implements DnsInterface
{
private $username;
private $password;
private $baseUrl = 'https://dns.he.net/';
private $error;
private $domain;
private $domainid;
private $proxy;
private $cookie = '';
private $loggedIn = false;
private $cacheKey;
public function __construct($config)
{
$this->username = $config['username'];
$this->password = $config['password'];
$this->domain = $config['domain'];
$this->domainid = $config['domainid'];
$this->proxy = isset($config['proxy']) ? $config['proxy'] == 1 : false;
$this->cacheKey = 'henet_cookie_' . md5($this->username . '|' . $this->password);
$this->loadCachedSession();
}
public function getError()
{
return $this->error;
}
public function check()
{
return $this->getDomainList() !== false;
}
public function getDomainList($KeyWord = null, $PageNumber = 1, $PageSize = 20)
{
$html = $this->login();
if ($html === false) {
return false;
}
$list = $this->parseDomains($html);
if (!isNullOrEmpty($KeyWord)) {
$list = array_values(array_filter($list, function ($row) use ($KeyWord) {
return stripos($row['Domain'], $KeyWord) !== false;
}));
}
$total = count($list);
$offset = max(0, ($PageNumber - 1) * $PageSize);
$list = array_slice($list, $offset, $PageSize);
return ['total' => $total, 'list' => $list];
}
public function getDomainRecords($PageNumber = 1, $PageSize = 20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null)
{
$zoneid = $this->getZoneId();
if ($zoneid === false) {
return false;
}
$html = $this->request('GET', 'index.cgi?' . http_build_query([
'hosted_dns_zoneid' => $zoneid,
'menu' => 'edit_zone',
'hosted_dns_editzone' => '',
]));
if ($html === false) {
return false;
}
$list = $this->parseRecords($html);
if (!isNullOrEmpty($SubDomain)) {
$list = array_values(array_filter($list, function ($row) use ($SubDomain) {
return strcasecmp($row['Name'], $SubDomain) === 0;
}));
} else {
if (!isNullOrEmpty($KeyWord)) {
$list = array_values(array_filter($list, function ($row) use ($KeyWord) {
return stripos($row['Name'], $KeyWord) !== false || stripos($row['Value'], $KeyWord) !== false;
}));
}
if (!isNullOrEmpty($Value)) {
$list = array_values(array_filter($list, function ($row) use ($Value) {
return $row['Value'] == $Value;
}));
}
if (!isNullOrEmpty($Type)) {
$list = array_values(array_filter($list, function ($row) use ($Type) {
return strcasecmp($row['Type'], $Type) === 0;
}));
}
if (!isNullOrEmpty($Status)) {
$list = array_values(array_filter($list, function ($row) use ($Status) {
return $row['Status'] == $Status;
}));
}
}
$total = count($list);
$offset = max(0, ($PageNumber - 1) * $PageSize);
$list = array_slice($list, $offset, $PageSize);
return ['total' => $total, 'list' => $list];
}
public function getSubDomainRecords($SubDomain, $PageNumber = 1, $PageSize = 20, $Type = null, $Line = null)
{
if ($SubDomain == '') $SubDomain = '@';
return $this->getDomainRecords($PageNumber, $PageSize, null, $SubDomain, null, $Type, $Line);
}
public function getDomainRecordInfo($RecordId)
{
$records = $this->getDomainRecords(1, 1000);
if ($records === false) {
return false;
}
foreach ($records['list'] as $row) {
if ($row['RecordId'] == $RecordId) {
return $row;
}
}
$this->setError('解析记录不存在');
return false;
}
public function addDomainRecord($Name, $Type, $Value, $Line = 'default', $TTL = 600, $MX = 1, $Weight = null, $Remark = null)
{
$zoneid = $this->getZoneId();
if ($zoneid === false) {
return false;
}
$params = $this->buildRecordParams($zoneid, '', $Name, $Type, $Value, $TTL, $MX);
$params['hosted_dns_editrecord'] = 'Submit';
$html = $this->request('POST', 'index.cgi', $params);
if ($html !== false && $this->isSuccess($html, 'Successfully added new record')) {
$recordid = $this->findRecordInHtml($html, $Name, $Type, $Value);
return $recordid ? $recordid : true;
}
$this->setError($this->extractMessage($html) ?: '添加解析记录失败');
return false;
}
public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = 'default', $TTL = 600, $MX = 1, $Weight = null, $Remark = null)
{
$zoneid = $this->getZoneId();
if ($zoneid === false) {
return false;
}
$params = $this->buildRecordParams($zoneid, $RecordId, $Name, $Type, $Value, $TTL, $MX);
$params['hosted_dns_editrecord'] = 'Update';
$html = $this->request('POST', 'index.cgi', $params);
if ($html !== false && $this->isSuccess($html, 'Successfully updated record')) {
return true;
}
$this->setError($this->extractMessage($html) ?: '修改解析记录失败');
return false;
}
public function updateDomainRecordRemark($RecordId, $Remark)
{
return false;
}
public function deleteDomainRecord($RecordId)
{
$zoneid = $this->getZoneId();
if ($zoneid === false) {
return false;
}
$html = $this->request('POST', 'index.cgi', [
'menu' => 'edit_zone',
'hosted_dns_zoneid' => $zoneid,
'hosted_dns_recordid' => $RecordId,
'hosted_dns_editzone' => '1',
'hosted_dns_delrecord' => '1',
'hosted_dns_delconfirm' => 'delete',
]);
if ($html !== false && $this->isSuccess($html, 'Successfully removed record')) {
return true;
}
$this->setError($this->extractMessage($html) ?: '删除解析记录失败');
return false;
}
public function setDomainRecordStatus($RecordId, $Status)
{
return false;
}
public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null)
{
return false;
}
public function getRecordLine()
{
return ['default' => ['name' => '默认', 'parent' => null]];
}
public function getMinTTL()
{
return 300;
}
public function addDomain($Domain)
{
return false;
}
private function login()
{
if ($this->loggedIn) {
return $this->request('GET', '');
}
$this->request('GET', '', null, false);
$html = $this->request('POST', '', [
'email' => $this->username,
'pass' => $this->password,
], false);
if ($html === false) {
return false;
}
if (stripos($html, 'incorrect') !== false || stripos($html, 'Invalid') !== false) {
$this->setError($this->extractMessage($html) ?: '登录失败,请检查用户名和密码');
return false;
}
$domains = $this->parseDomains($html);
if (empty($domains) && stripos($html, 'hosted_dns_zoneid') === false) {
$this->setError($this->extractMessage($html) ?: '登录失败,未找到域名列表');
return false;
}
$this->loggedIn = true;
$this->saveCachedSession();
return $html;
}
private function getZoneId()
{
if (!isNullOrEmpty($this->domainid)) {
return $this->domainid;
}
if (isNullOrEmpty($this->domain)) {
$this->setError('未指定域名');
return false;
}
$domains = $this->getDomainList($this->domain, 1, 1000);
if ($domains === false) {
return false;
}
foreach ($domains['list'] as $row) {
if (strcasecmp($row['Domain'], $this->domain) === 0) {
$this->domainid = $row['DomainId'];
return $this->domainid;
}
}
$this->setError('域名不存在或无权限访问');
return false;
}
private function buildRecordParams($zoneid, $recordid, $Name, $Type, $Value, $TTL, $MX)
{
return [
'account' => '',
'menu' => 'edit_zone',
'Type' => strtoupper($Type),
'hosted_dns_zoneid' => $zoneid,
'hosted_dns_recordid' => $recordid,
'hosted_dns_editzone' => '1',
'Priority' => strtoupper($Type) == 'MX' ? intval($MX) : '',
'Name' => $this->toFullName($Name),
'Content' => $this->convertValue($Value, $Type),
'TTL' => intval($TTL),
];
}
private function parseDomains($html)
{
$list = [];
$patterns = [
'/onclick="delete_dom\(this\);"[^>]*name="([^"]+)"[^>]*value="(\d+)"/i',
'/name="([^"]+)"[^>]*value="(\d+)"[^>]*onclick="delete_dom\(this\);"/i',
];
foreach ($patterns as $pattern) {
if (!preg_match_all($pattern, $html, $matches, PREG_SET_ORDER)) {
continue;
}
foreach ($matches as $match) {
$domain = html_entity_decode($match[1], ENT_QUOTES);
$zoneid = $match[2];
$list[$zoneid] = [
'DomainId' => $zoneid,
'Domain' => $domain,
'RecordCount' => 0,
];
}
}
if (preg_match_all('/hosted_dns_zoneid=(\d+)[^"\']*["\'][^>]*>\s*([^<]+)\s*</i', $html, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$domain = trim(html_entity_decode($match[2], ENT_QUOTES));
if ($domain !== '' && !isset($list[$match[1]])) {
$list[$match[1]] = [
'DomainId' => $match[1],
'Domain' => $domain,
'RecordCount' => 0,
];
}
}
}
return array_values($list);
}
private function parseRecords($html)
{
$list = [];
if (!preg_match_all('/<tr class="dns_tr" [^>]*>.*?<\/tr>/is', $html, $rows, PREG_SET_ORDER)) {
return $list;
}
foreach ($rows as $row) {
$cells = $this->extractCells($row[0]);
if (count($cells) < 4) continue;
$ttl = is_numeric($cells[4]) ? intval($cells[4]) : 0;
$name = $cells[2];
$type = strtoupper($cells[3]);
$value = $cells[6];
$priority = is_numeric($cells[5]) ? intval($cells[5]) : null;
$list[] = [
'RecordId' => $cells[1],
'Domain' => $this->domain,
'Name' => $this->fromFullName($name),
'Type' => $type,
'Value' => $this->normalizeValue($value, $type),
'Line' => 'default',
'TTL' => $ttl,
'MX' => $priority,
'Status' => stripos($row[0], 'disabled') !== false ? '0' : '1',
'Weight' => null,
'Remark' => null,
'UpdateTime' => null,
];
}
return $list;
}
private function extractCells($html)
{
$cells = [];
if (preg_match_all('/<td[^>]*>(.*?)<\/td>/is', $html, $matches)) {
foreach ($matches[1] as $cell) {
$cell = preg_replace('/<script\b[^>]*>.*?<\/script>/is', '', $cell);
$cell = preg_replace('/<style\b[^>]*>.*?<\/style>/is', '', $cell);
$cell = trim(html_entity_decode(strip_tags($cell), ENT_QUOTES));
$cell = preg_replace('/\s+/', ' ', $cell);
if ($cell !== '') {
$cells[] = $cell;
}
}
}
return $cells;
}
private function findRecordInHtml($html, $Name, $Type, $Value)
{
$records = $this->parseRecords($html);
$name = $this->fromFullName($this->toFullName($Name));
$value = $this->normalizeValue($this->convertValue($Value, $Type), $Type);
foreach ($records as $record) {
if (
strcasecmp($record['Name'], $name) === 0 &&
strcasecmp($record['Type'], $Type) === 0 &&
$record['Value'] == $value
) {
return $record;
}
}
return false;
}
private function toFullName($name)
{
if ($name == '@' || $name == '') {
return $this->domain;
}
if (str_ends_with($name, '.' . $this->domain) || strcasecmp($name, $this->domain) === 0) {
return $name;
}
return $name . '.' . $this->domain;
}
private function fromFullName($name)
{
$name = rtrim($name, '.');
if (strcasecmp($name, $this->domain) === 0) {
return '@';
}
if (str_ends_with(strtolower($name), '.' . strtolower($this->domain))) {
return substr($name, 0, -(strlen($this->domain) + 1));
}
return $name;
}
private function convertValue($value, $type)
{
if (strtoupper($type) == 'TXT') {
return trim($value, '"');
}
return $value;
}
private function normalizeValue($value, $type)
{
$value = trim($value);
if (strtoupper($type) == 'TXT') {
return trim($value, '"');
}
return $value;
}
private function isSuccess($html, $message)
{
return stripos($html, $message) !== false;
}
private function extractMessage($html)
{
if (!$html) {
return null;
}
if (preg_match('/<(?:div|span)[^>]*class="[^"]*(?:error|warn|success|message)[^"]*"[^>]*>(.*?)<\/(?:div|span)>/is', $html, $match)) {
return trim(html_entity_decode(strip_tags($match[1]), ENT_QUOTES));
}
if (preg_match('/(Successfully [^<]+|Error:[^<]+|Invalid [^<]+)/i', $html, $match)) {
return trim(html_entity_decode($match[1], ENT_QUOTES));
}
return null;
}
private function request($method, $path, $params = null, $requireLogin = true, $allowRelogin = true)
{
if ($requireLogin && !$this->loggedIn && $this->login() === false) {
return false;
}
$url = str_starts_with($path, 'http') ? $path : $this->baseUrl . $path;
try {
$response = http_request($url, $params ? http_build_query($params) : null, $this->baseUrl, $this->cookie, null, $this->proxy, $method, 20);
} catch (Exception $e) {
$this->setError($e->getMessage());
return false;
}
$this->storeCookie($response['headers']);
if ($response['code'] >= 400) {
$this->setError('HTTP请求失败:' . $response['code']);
return false;
}
if ($requireLogin && $allowRelogin && $this->isLoginExpired($response['body'])) {
$this->clearCachedSession();
if ($this->login() === false) {
return false;
}
return $this->request($method, $path, $params, true, false);
}
return $response['body'];
}
private function storeCookie($headers)
{
$cookies = [];
if ($this->cookie !== '') {
foreach (explode('; ', $this->cookie) as $cookie) {
$parts = explode('=', $cookie, 2);
if (count($parts) == 2) {
$cookies[$parts[0]] = $parts[1];
}
}
}
foreach ($headers as $name => $values) {
if (strtolower($name) !== 'set-cookie') {
continue;
}
foreach ((array)$values as $value) {
$cookie = explode(';', $value, 2)[0];
$parts = explode('=', $cookie, 2);
if (count($parts) == 2) {
$cookies[$parts[0]] = $parts[1];
}
}
}
$pairs = [];
foreach ($cookies as $name => $value) {
$pairs[] = $name . '=' . $value;
}
$this->cookie = implode('; ', $pairs);
if ($this->loggedIn && $this->cookie !== '') {
$this->saveCachedSession();
}
}
private function loadCachedSession()
{
$cookie = Cache::get($this->cacheKey);
if (is_string($cookie) && $cookie !== '') {
$this->cookie = $cookie;
$this->loggedIn = true;
}
}
private function saveCachedSession()
{
if ($this->cookie !== '') {
Cache::set($this->cacheKey, $this->cookie, 3600 * 12);
}
}
private function clearCachedSession()
{
$this->cookie = '';
$this->loggedIn = false;
Cache::delete($this->cacheKey);
}
private function isLoginExpired($html)
{
if (!$html) {
return false;
}
return stripos($html, 'name="email"') !== false
&& stripos($html, 'name="pass"') !== false
&& stripos($html, 'hosted_dns_zoneid') === false;
}
private function setError($message)
{
$this->error = $message;
}
}
-1
View File
@@ -31,7 +31,6 @@ class Sendcloud
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$json = curl_exec($ch);
curl_close($ch);
$arr = json_decode($json, true);
if ($arr['statusCode'] == 200) {
return true;
-1
View File
@@ -468,7 +468,6 @@ class MsgNotice
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$ret = curl_exec($ch);
curl_close($ch);
return $ret;
}
}
+21 -8
View File
@@ -27,42 +27,52 @@
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'certaccount_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/cert/account/data?deploy=0',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'typename',
title: '所属平台',
sortable: true,
formatter: function(value, row, index) {
return '<img src="/static/images/'+row.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
title: '账户名称',
sortable: true
},
{
field: 'remark',
title: '备注'
title: '备注',
sortable: true
},
{
field: 'addtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'action',
@@ -72,7 +82,10 @@ $(document).ready(function(){
return html;
}
},
]
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function delItem(id){
+20 -5
View File
@@ -55,13 +55,15 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/FileSaver-2.0.5.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 10;
const pageSizeKey = 'certorder_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey, 10);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/cert/order/data',
@@ -69,6 +71,9 @@ $(document).ready(function(){
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: '',
@@ -76,11 +81,13 @@ $(document).ready(function(){
},
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'typename',
title: '证书账户',
sortable: true,
formatter: function(value, row, index) {
if(value){
return '<span title="'+row.aremark+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+value+'('+row.aid+')</span>';
@@ -98,6 +105,7 @@ $(document).ready(function(){
{
field: 'keytype',
title: '证书信息',
sortable: true,
formatter: function(value, row, index) {
return '<span class="text-muted">签名算法:</span>'+row.keytype+'('+row.keysize+')'+(row.issuer?'<br/><span class="text-muted">颁发机构:</span>'+row.issuer:'');
}
@@ -105,6 +113,7 @@ $(document).ready(function(){
{
field: 'isauto',
title: '自动续签',
sortable: true,
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="isauto'+row.id+'" type="checkbox" checked onchange="setAuto('+row.id+',0)"/><label for="isauto'+row.id+'" class="label-primary"></label></div>';
@@ -116,6 +125,7 @@ $(document).ready(function(){
{
field: 'issuetime',
title: '签发时间',
sortable: true,
formatter: function(value, row, index) {
return value ? value.substring(0,10) : '暂未签发';
}
@@ -123,6 +133,7 @@ $(document).ready(function(){
{
field: 'end_day',
title: '到期时间',
sortable: true,
formatter: function(value, row, index) {
if(value != null){
if(value > 7){
@@ -140,6 +151,7 @@ $(document).ready(function(){
{
field: 'status',
title: '状态',
sortable: true,
formatter: function(value, row, index) {
if(value == 4) {
return '<span class="label" style="background-color: #a5a5a5;">已吊销</span>';
@@ -252,7 +264,10 @@ $(document).ready(function(){
}
$(e.target).children('.dropdown-menu').css({position:'fixed', top:top, left:left});
});
}
},
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function showmsg(msg){
+18 -6
View File
@@ -74,13 +74,15 @@ tbody tr>td:nth-child(4){word-break:break-all;max-width:260px;}
<script src="/static/js/clipboard-1.7.1.min.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'cname_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/cert/cname/data',
@@ -88,14 +90,19 @@ $(document).ready(function(){
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'domain',
title: '被代理域名'
title: '被代理域名',
sortable: true
},
{
field: 'host',
@@ -114,6 +121,7 @@ $(document).ready(function(){
{
field: 'status',
title: '状态',
sortable: true,
formatter: function(value, row, index) {
var html = '';
if(value == 1) {
@@ -127,7 +135,8 @@ $(document).ready(function(){
},
{
field: 'addtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'action',
@@ -147,6 +156,9 @@ $(document).ready(function(){
layer.msg('复制失败', {icon: 2});
});
},
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function addframe(){
+21 -8
View File
@@ -27,42 +27,52 @@
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'deployaccount_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/cert/account/data?deploy=1',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'typename',
title: '账户类型',
sortable: true,
formatter: function(value, row, index) {
return '<img src="/static/images/'+row.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
title: '账户名称',
sortable: true
},
{
field: 'remark',
title: '备注'
title: '备注',
sortable: true
},
{
field: 'addtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'action',
@@ -72,7 +82,10 @@ $(document).ready(function(){
return html;
}
},
]
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function delItem(id){
+20 -6
View File
@@ -54,13 +54,15 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/FileSaver-2.0.5.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 10;
const pageSizeKey = 'deploytask_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey, 10);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/cert/deploy/data',
@@ -68,6 +70,9 @@ $(document).ready(function(){
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: '',
@@ -75,11 +80,13 @@ $(document).ready(function(){
},
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'typename',
title: '自动部署账户',
sortable: true,
formatter: function(value, row, index) {
if(!value) return '已被删除'
return '<span title="'+row.aname+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+(row.aremark?row.aremark:value+'('+row.aid+')')+'</span>';
@@ -97,11 +104,13 @@ $(document).ready(function(){
},
{
field: 'remark',
title: '备注'
title: '备注',
sortable: true
},
{
field: 'active',
title: '任务开关',
sortable: true,
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
@@ -113,6 +122,7 @@ $(document).ready(function(){
{
field: 'lasttime',
title: '上次执行时间',
sortable: true,
formatter: function(value, row, index) {
return value ? value : '暂未执行'
}
@@ -120,6 +130,7 @@ $(document).ready(function(){
{
field: 'status',
title: '状态',
sortable: true,
formatter: function(value, row, index) {
if(value == 1) {
return '<span class="label label-success">已完成</span>';
@@ -173,7 +184,10 @@ $(document).ready(function(){
}
$(e.target).children('.dropdown-menu').css({position:'fixed', top:top, left:left});
});
}
},
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function showmsg(msg){
+7 -4
View File
@@ -458,7 +458,7 @@
<script src="/static/js/bootstrapValidator.min.js"></script>
<script src="/static/js/select2-4.0.13.min.js"></script>
<script src="/static/js/select2-i18n-zh-CN-4.0.13.min.js"></script>
<script src="/static/js/custom.js?v=1005"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var currentVerificationHostnameId = '';
var allHostnameData = []; // 保存完整的原始数据用于客户端搜索
@@ -468,6 +468,7 @@ $(document).ready(function(){
$("#form-store").bootstrapValidator();
loadFallbackOrigin();
loadDcvDelegationUuid();
const pageSizeKey = 'hostnames_pagesize';
$("#listTable").bootstrapTable({
url: '/cloudflare/hostnames/data/{$domainId}',
method: 'post',
@@ -476,8 +477,7 @@ $(document).ready(function(){
uniqueId: 'id',
sidePagination: 'client',
pagination: true,
pageSize: 20,
pageList: [10, 20, 50, 100],
pageSize: getStoredPageSize(pageSizeKey),
queryParams: function(params){ return {}; },
responseHandler: hostnameResponseHandler,
columns: [
@@ -502,7 +502,10 @@ $(document).ready(function(){
+ '<a href="javascript:deleteHostname(\''+row.id+'\', \''+htmlEscape(row.hostname)+'\')" class="btn btn-danger btn-xs">删除</a>';
}
}
]
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
});
// 添加复选框事件监听
+7 -2
View File
@@ -164,7 +164,7 @@
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var selectedTunnelId = '';
var selectedTunnelName = '';
@@ -172,12 +172,14 @@ var selectedTunnelName = '';
$(document).ready(function(){
$("#form-tunnel").bootstrapValidator();
const pageSizeKey = 'tunnels_pagesize';
$("#listTable").bootstrapTable({
url: '/cloudflare/tunnels/data/{$accountId}',
method: 'post',
toolbar: '',
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
pageSize: getStoredPageSize(pageSizeKey),
responseHandler: tableResponseHandler,
columns: [
{field: 'name', title: '名称'},
@@ -197,7 +199,10 @@ $(document).ready(function(){
+ '<a href="javascript:deleteTunnel(\''+row.id+'\', \''+htmlEscape(row.name)+'\')" class="btn btn-danger btn-xs">删除</a>';
}
}
]
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
});
$("#publicTable").bootstrapTable({
+22 -6
View File
@@ -45,19 +45,24 @@ tbody tr>td:nth-child(4){overflow: hidden;text-overflow: ellipsis;white-space: n
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'dmtask_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/dmonitor/task/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: '',
@@ -65,11 +70,13 @@ $(document).ready(function(){
},
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'rr',
title: '域名',
sortable: true,
formatter: function(value, row, index) {
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
@@ -77,6 +84,7 @@ $(document).ready(function(){
{
field: 'main_value',
title: '解析记录',
sortable: true,
formatter: function(value, row, index) {
return value;
}
@@ -123,6 +131,7 @@ $(document).ready(function(){
{
field: 'status',
title: '健康状况',
sortable: true,
formatter: function(value, row, index) {
if(value == 0) {
return '<span class="label label-success">正常</span>';
@@ -134,6 +143,7 @@ $(document).ready(function(){
{
field: 'active',
title: '运行开关',
sortable: true,
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
@@ -144,16 +154,19 @@ $(document).ready(function(){
},
{
field: 'checktimestr',
title: '上次检测时间'
title: '上次检测时间',
sortable: true
},
{
field: 'addtimestr',
title: '添加时间',
sortable: true,
visible: false
},
{
field: 'remark',
title: '备注',
sortable: true,
visible: false
},
{
@@ -170,7 +183,10 @@ $(document).ready(function(){
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
}
},
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function setActive(id, active){
+6 -3
View File
@@ -32,14 +32,14 @@ tbody tr>td:nth-child(4){overflow: hidden;text-overflow: ellipsis;white-space: n
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var action_name = {$info.action_name|json_encode|raw};
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'dmtaskinfo_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
$("#listTable").bootstrapTable({
url: '/dmonitor/task/log/data/{$info.id}',
@@ -67,6 +67,9 @@ $(document).ready(function(){
title: '异常原因'
}
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
</script>
+20 -7
View File
@@ -27,43 +27,53 @@
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var userLevel = "{$user['level']|default=''}";
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'account_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/account/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'typename',
title: '所属平台',
sortable: true,
formatter: function(value, row, index) {
return '<img src="/static/images/'+row.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
title: '账户名称',
sortable: true
},
{
field: 'remark',
title: '备注'
title: '备注',
sortable: true
},
{
field: 'addtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'action',
@@ -78,6 +88,9 @@ $(document).ready(function(){
}
},
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function delItem(id) {
+1 -1
View File
@@ -65,7 +65,7 @@
{/block}
{block name="script"}
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var domainId = {$domainId};
+18 -10
View File
@@ -61,13 +61,15 @@
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script src="/static/js/custom.js?v=1003"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
let defaultPageSize = getCookie('category_pagesize') ? getCookie('category_pagesize') : 10;
const pageSizeKey = 'category_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/domain/category/data',
@@ -75,25 +77,32 @@ $(document).ready(function(){
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'name',
title: '分类名称'
title: '分类名称',
sortable: true
},
{
field: 'remark',
title: '备注',
sortable: true,
formatter: function(value, row, index) {
return value ? value : '-';
}
},
{
field: 'sort',
title: '排序'
title: '排序',
sortable: true
},
{
field: 'domain_count',
@@ -104,7 +113,8 @@ $(document).ready(function(){
},
{
field: 'addtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'action',
@@ -118,9 +128,7 @@ $(document).ready(function(){
},
],
onPageChange: function(number, size){
if(size != defaultPageSize){
setCookie('category_pagesize', size, 24 * 3600 * 30);
}
setStoredPageSize(pageSizeKey, size);
},
});
+25 -13
View File
@@ -155,9 +155,6 @@
<div class="form-group">
<select name="status" class="form-control"><option value="">所有状态</option><option value="1">即将到期</option><option value="2">已到期</option></select>
</div>
<div class="form-group">
<select name="order" class="form-control"><option value="">默认排序</option><option value="1">注册时间↑</option><option value="2">注册时间↓</option><option value="3">到期时间↑</option><option value="4">到期时间↓</option></select>
</div>
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
<a href="javascript:searchClear()" class="btn btn-default" title="刷新域名列表"><i class="fa fa-refresh"></i> 刷新</a>
{if $user['level'] eq 2}<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
@@ -184,14 +181,16 @@
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/select2-4.0.13.min.js"></script>
<script src="/static/js/select2-i18n-zh-CN-4.0.13.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var userLevel = "{$user['level']|default=''}";
$(document).ready(function(){
updateToolbar();
const defaultPageSize = getCookie('domain_pagesize') ? getCookie('domain_pagesize') : 15;
const pageSizeKey = 'domain_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/domain/data',
@@ -199,6 +198,9 @@ $(document).ready(function(){
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: '',
@@ -206,11 +208,13 @@ $(document).ready(function(){
},
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'typename',
title: '平台账户',
sortable: true,
formatter: function(value, row, index) {
return '<img src="/static/images/'+row.icon+'" class="type-logo"></img>'+(row.aremark?row.aremark:value+'('+row.aid+')');
}
@@ -218,21 +222,25 @@ $(document).ready(function(){
{
field: 'name',
title: '域名',
sortable: true,
formatter: function(value, row, index) {
return '<a href="/record/'+row.id+'" title="进入解析记录管理" onclick="loading()">'+value+'</a>';
}
},
{
field: 'recordcount',
title: '记录数'
title: '记录数',
sortable: true
},
{
field: 'addtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'regtime',
title: '注册时间',
sortable: true,
visible: false,
formatter: function(value, row, index) {
var html = '';
@@ -251,6 +259,7 @@ $(document).ready(function(){
{
field: 'expiretime',
title: '到期时间',
sortable: true,
formatter: function(value, row, index) {
var html = '';
if(value == null) {
@@ -278,6 +287,7 @@ $(document).ready(function(){
{
field: 'is_notice',
title: '到期提醒',
sortable: true,
formatter: function(value, row, index) {
return value==1?'<font color="green"></font>':'<font color="blue"></font>';
}
@@ -285,6 +295,7 @@ $(document).ready(function(){
{
field: 'is_hide',
title: '是否隐藏',
sortable: true,
visible: false,
formatter: function(value, row, index) {
return value==1?'<font color="grey"></font>':'<font color="blue"></font>';
@@ -293,6 +304,7 @@ $(document).ready(function(){
{
field: 'is_sso',
title: '对接开关',
sortable: true,
visible: false,
formatter: function(value, row, index) {
return value==1?'<font color="green"></font>':'<font color="red"></font>';
@@ -301,13 +313,15 @@ $(document).ready(function(){
{
field: 'category_name',
title: '分类',
sortable: true,
formatter: function(value, row, index) {
return value ? '<span class="label label-default">' + value + '</span>' : '-';
}
},
{
field: 'remark',
title: '备注'
title: '备注',
sortable: true
},
{
field: 'action',
@@ -326,9 +340,7 @@ $(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip()
},
onPageChange: function(number, size){
if(size != defaultPageSize){
setCookie('domain_pagesize', size, 24 * 3600 * 30);
}
setStoredPageSize(pageSizeKey, size);
},
})
+2 -1
View File
@@ -51,6 +51,7 @@
{block name="script"}
<script src="/static/js/vue-2.7.16.min.js"></script>
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
new Vue({
el: '#app',
@@ -58,7 +59,7 @@ new Vue({
aid: '',
domainList: [],
page: 1,
pagesize: 10,
pagesize: getStoredPageSize('domainadd_pagesize'),
checkall: false,
},
watch: {
+6 -3
View File
@@ -18,13 +18,13 @@
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'domainlog_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
$("#listTable").bootstrapTable({
url: '/record/log/{$domainId}',
@@ -41,6 +41,9 @@ $(document).ready(function(){
title: '操作行为'
}
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
</script>
+85 -9
View File
@@ -188,7 +188,7 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
{if $dnsconfig.type=='dnspod'}<a href="/record/alias/{$domainId}" class="btn btn-default">域名别名</a>{/if}
<div class="btn-group" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">批量操作 <span class="caret"></span></button>
<ul class="dropdown-menu"><li><a href="/record/batchadd/{$domainId}">添加</a></li><li><a href="javascript:operation('open')">启用</a></li><li><a href="javascript:operation('pause')">暂停</a></li><li><a href="javascript:operation('edit')">修改记录</a></li><li><a href="javascript:operation('editline')">修改线路</a></li>{if $dnsconfig.remark == 1}<li><a href="javascript:operation('editremark')">修改备注</a></li>{/if}<li><a href="javascript:operation('delete')">删除</a></li></ul>
<ul class="dropdown-menu"><li><a href="/record/batchadd/{$domainId}">添加</a></li><li><a href="javascript:operation('open')">启用</a></li><li><a href="javascript:operation('pause')">暂停</a></li><li><a href="javascript:operation('edit')">修改记录</a></li><li><a href="javascript:operation('editline')">修改线路</a></li>{if $dnsconfig.remark == 1}<li><a href="javascript:operation('editremark')">修改备注</a></li>{/if}{if $dnsconfig.type=='aliyun' || $dnsconfig.type=='dnspod'}<li><a href="javascript:operation('editgroup')">修改分组</a></li>{/if}<li><a href="javascript:operation('delete')">删除</a></li></ul>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">日志 <span class="caret"></span></button>
@@ -223,6 +223,11 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
<div class="form-group">
<input type="text" class="form-control" name="value" placeholder="输入记录值">
</div>
{if $dnsconfig.type=='aliyun' || $dnsconfig.type=='dnspod'}
<div class="form-group">
<select name="groupid" id="groupid" class="form-control"></select>
</div>
{/if}
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
<a href="javascript:searchClear()" class="btn btn-default" title="刷新解析记录列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="javascript:advanceSearch()" class="btn"><i class="fa fa-angle-up"></i> 收起</a>
@@ -241,7 +246,7 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script src="/static/js/custom.js?v=1003"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var recordLine = {$recordLine|json_encode|raw};
var dnsconfig = {$dnsconfig|json_encode|raw};
@@ -250,9 +255,9 @@ var sidePagination = dnsconfig.page ? 'client' : 'server';
var showWeight = dnsconfig.weight;
$(document).ready(function(){
updateToolbar();
let defaultPageSize = getCookie('record_pagesize') ? getCookie('record_pagesize') : 15;
const pageSizeKey = 'record_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
$("#listTable").bootstrapTable({
url: '/record/data/{$domainId}',
@@ -294,11 +299,11 @@ $(document).ready(function(){
formatter: function(value, row, index) {
var copyId = 'copy-value-' + row.RecordId;
if(row.Type == 'MX' && dnsconfig.type!='huawei') {
return '<span id="'+copyId+'" data-value="'+htmlEscape(value)+'">'+value+'</span>'
return '<span id="'+copyId+'" data-value="'+htmlEscape(value)+'">'+htmlEscape(value)+'</span>'
+ '<a href="javascript:void(0);" title="复制记录值" onclick="copyToClipboard(null, \'#'+copyId+'\')" style="padding-left:6px;"><i class=\"fa fa-copy\"></i></a>'
+ '<span class="mx-priority"> | '+row.MX+'</span>';
} else {
return '<span id="'+copyId+'" data-value="'+htmlEscape(value)+'">'+value+'</span>'
return '<span id="'+copyId+'" data-value="'+htmlEscape(value)+'">'+htmlEscape(value)+'</span>'
+ '<a href="javascript:void(0);" title="复制记录值" onclick="copyToClipboard(null, \'#'+copyId+'\')" style="padding-left:6px;"><i class=\"fa fa-copy\"></i></a>';
}
}
@@ -365,9 +370,7 @@ $(document).ready(function(){
},
],
onPageChange: function(number, size){
if(size != defaultPageSize){
setCookie('record_pagesize', size, 24 * 3600 * 30);
}
setStoredPageSize(pageSizeKey, size);
},
});
@@ -397,6 +400,7 @@ $(document).ready(function(){
$("#searchToolbar select[name='line']").append('<option value="'+item.id+'">'+item.name+'</option>');
}
})
})
function initLine(option, elem){
option = option || '';
@@ -588,6 +592,9 @@ function operation(action){
}else if(action == 'editremark'){
batch_edit_remark(rows)
return;
}else if(action == 'editgroup'){
batch_edit_group(rows)
return;
}
layer.confirm('确定要'+(action=='open'?'启用':(action=='pause'?'暂停':'删除'))+'所选记录吗?', {title: '提示', icon: 0}, function(){
@@ -714,6 +721,74 @@ function batch_edit_remark(rows) {
}
});
}
function batch_edit_group(rows) {
var showDialog = function(options){
layer.open({
type: 1,
area: ['350px'],
closeBtn: 2,
title: '批量修改分组',
content: '<div style="padding:15px"><div class="form-group"><select class="form-control" id="batch_groupid">'+options+'</select></div></div>',
btn: ['确认', '取消'],
yes: function(){
var groupid = $('#batch_groupid').val();
var recordIds = rows.map(function(r){ return r.RecordId; });
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: 'POST',
url: '/record/batch/{$domainId}',
data: {action:'group', recordinfo: JSON.stringify(rows), groupid: groupid},
dataType: 'json',
success: function(data){
layer.close(ii);
layer.alert(data.msg, {icon: data.code==0?1:2, closeBtn: false}, function(){
layer.closeAll();
if(data.code == 0) searchRefresh();
groupLoaded = false;
});
},
error: function(){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
});
};
if(groupLoaded && $('#groupid').length > 0){
var options = '';
$('#groupid option').each(function(){ options += '<option value="'+$(this).val()+'">'+$(this).text()+'</option>'; });
showDialog(options);
}else{
var ii = layer.load(2);
$.post('/record/groups/{$domainId}', function(res){
layer.close(ii);
if(res.code == 0){
var options = '';
$.each(res.data, function(i, item){
options += '<option value="'+item.id+'">'+item.name+'</option>';
});
showDialog(options);
}else{
layer.alert(res.msg, {icon: 2});
}
}, 'json');
}
}
var groupLoaded = false;
function loadRecordGroups(){
if(groupLoaded || (dnsconfig.type != 'aliyun' && dnsconfig.type != 'dnspod')) return;
groupLoaded = true;
$.post('/record/groups/{$domainId}', function(res){
if(res.code == 0){
$('#groupid').empty();
$.each(res.data, function(i, item){
$('#groupid').append('<option value="'+item.id+'">'+item.name+'</option>');
});
updateToolbar();
}
}, 'json');
}
function advanceSearch(){
$('#searchToolbar').find('input[name]').each(function() {
$(this).val('');
@@ -724,6 +799,7 @@ function advanceSearch(){
if($("#searchbox1").is(":visible")){
$("#searchbox1").slideUp();
$("#searchbox2").slideDown();
loadRecordGroups();
}else{
$("#searchbox2").slideUp();
$("#searchbox1").slideDown();
+6 -3
View File
@@ -76,7 +76,7 @@
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
var dnsconfig = {$dnsconfig|json_encode|raw};
var recordLine = {$recordLine|json_encode|raw};
@@ -85,9 +85,9 @@ var weightList = [];
var lineList = [];
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'weight_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
$("#listTable").bootstrapTable({
url: '/record/weight/data/{$domainId}',
@@ -138,6 +138,9 @@ $(document).ready(function(){
}
},
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function editframe(id){
+21 -5
View File
@@ -40,27 +40,34 @@ tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: n
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'opiplist_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/optimizeip/opiplist/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'rr',
title: '域名',
sortable: true,
formatter: function(value, row, index) {
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
@@ -68,6 +75,7 @@ $(document).ready(function(){
{
field: 'cdn_type',
title: 'CDN运营商',
sortable: true,
formatter: function(value, row, index) {
if(value == 1){
return 'CloudFlare';
@@ -85,6 +93,7 @@ $(document).ready(function(){
{
field: 'recordnum',
title: '解析数量',
sortable: true,
formatter: function(value, row, index) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="TTL'+row.ttl+'" class="tips">'+value+'</span>';
}
@@ -92,6 +101,7 @@ $(document).ready(function(){
{
field: 'ip_type',
title: '解析IP类型',
sortable: true,
formatter: function(value, row, index) {
var value = value.split(',')
value.forEach((element, index) => {
@@ -104,6 +114,7 @@ $(document).ready(function(){
{
field: 'active',
title: '任务开关',
sortable: true,
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
@@ -115,6 +126,7 @@ $(document).ready(function(){
{
field: 'updatetime',
title: '上次更新时间',
sortable: true,
formatter: function(value, row, index) {
return value ? value : '无';
}
@@ -122,6 +134,7 @@ $(document).ready(function(){
{
field: 'status',
title: '上次更新结果',
sortable: true,
formatter: function(value, row, index) {
if(value == 1) {
return '<span class="label label-success">成功</span>';
@@ -146,7 +159,10 @@ $(document).ready(function(){
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
}
},
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function setActive(id, active){
+22 -7
View File
@@ -45,19 +45,24 @@ tbody tr>td:nth-child(5){overflow: hidden;text-overflow: ellipsis;white-space: n
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'stask_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/schedule/stask/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: '',
@@ -65,11 +70,13 @@ $(document).ready(function(){
},
{
field: 'id',
title: 'ID'
title: 'ID',
sortable: true
},
{
field: 'rr',
title: '域名',
sortable: true,
formatter: function(value, row, index) {
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
@@ -112,6 +119,7 @@ $(document).ready(function(){
{
field: 'active',
title: '运行开关',
sortable: true,
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
@@ -122,21 +130,25 @@ $(document).ready(function(){
},
{
field: 'updatetimestr',
title: '上次切换时间'
title: '上次切换时间',
sortable: true
},
{
field: 'nexttimestr',
title: '下次切换时间',
sortable: true,
visible: false
},
{
field: 'addtimestr',
title: '添加时间',
sortable: true,
visible: false
},
{
field: 'remark',
title: '备注'
title: '备注',
sortable: true
},
{
field: 'action',
@@ -153,7 +165,10 @@ $(document).ready(function(){
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
}
},
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function setActive(id, active){
+6 -3
View File
@@ -29,13 +29,13 @@
<script src="/static/js/layer/layer.js"></script>
<script src="/static/js/bootstrap-table-1.21.4.min.js"></script>
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'userlog_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
$("#listTable").bootstrapTable({
url: '/log/data',
@@ -71,6 +71,9 @@ $(document).ready(function(){
title: '时间'
}
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
</script>
+22 -7
View File
@@ -113,31 +113,39 @@
<script src="/static/js/bootstrap-table-page-jump-to-1.21.4.min.js"></script>
<script src="/static/js/select2-4.0.13.min.js"></script>
<script src="/static/js/select2-i18n-zh-CN-4.0.13.min.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/js/custom.js?v=1006"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageSizeKey = 'user_pagesize';
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
const pageSize = getStoredPageSize(pageSizeKey);
var urlSort = typeof window.$_GET['sortName'] != 'undefined' ? window.$_GET['sortName'] : undefined;
var urlOrder = typeof window.$_GET['sortOrder'] != 'undefined' ? window.$_GET['sortOrder'] : undefined;
$("#listTable").bootstrapTable({
url: '/user/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
sortReset: false,
sortName: urlSort,
sortOrder: urlOrder,
columns: [
{
field: 'id',
title: 'UID'
title: 'UID',
sortable: true
},
{
field: 'username',
title: '用户名'
title: '用户名',
sortable: true
},
{
field: 'level',
title: '用户等级',
sortable: true,
formatter: function(value, row, index) {
switch(value){
case 1: return '<font color="blue">普通用户</font>';break;
@@ -148,6 +156,7 @@ $(document).ready(function(){
{
field: 'is_api',
title: 'API接口',
sortable: true,
formatter: function(value, row, index) {
switch(value){
case 0: return '<font color="grey">关闭</font>';break;
@@ -157,15 +166,18 @@ $(document).ready(function(){
},
{
field: 'regtime',
title: '添加时间'
title: '添加时间',
sortable: true
},
{
field: 'lasttime',
title: '上次登录时间'
title: '上次登录时间',
sortable: true
},
{
field: 'status',
title: '状态',
sortable: true,
formatter: function(value, row, index) {
switch(value){
case 0: return '<a href="javascript:setStatus('+row.id+',1)"><font color=red><i class="fa fa-times-circle"></i>封禁</font></a>';break;
@@ -182,6 +194,9 @@ $(document).ready(function(){
}
},
],
onPageChange: function(number, size){
setStoredPageSize(pageSizeKey, size);
},
})
})
function addframe(){
Generated
+165 -72
View File
@@ -68,16 +68,16 @@
},
{
"name": "cccyun/think-captcha",
"version": "3.0.11",
"version": "3.0.12",
"source": {
"type": "git",
"url": "https://github.com/netcccyun/think-captcha.git",
"reference": "40012811bf27b41011b1b60bcfadf16ad339931c"
"reference": "e20974d9f86a7e3039ead56a66995c396109a757"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/netcccyun/think-captcha/zipball/40012811bf27b41011b1b60bcfadf16ad339931c",
"reference": "40012811bf27b41011b1b60bcfadf16ad339931c",
"url": "https://api.github.com/repos/netcccyun/think-captcha/zipball/e20974d9f86a7e3039ead56a66995c396109a757",
"reference": "e20974d9f86a7e3039ead56a66995c396109a757",
"shasum": ""
},
"require": {
@@ -114,31 +114,32 @@
],
"description": "captcha package for thinkphp",
"support": {
"source": "https://github.com/netcccyun/think-captcha/tree/3.0.11"
"source": "https://github.com/netcccyun/think-captcha/tree/3.0.12"
},
"time": "2025-04-26T08:37:18+00:00"
"time": "2026-06-23T15:30:22+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.10.0",
"version": "7.14.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
"reference": "6b1d2429a2c312474c523aa9017fba0c07b5f4a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/6b1d2429a2c312474c523aa9017fba0c07b5f4a0",
"reference": "6b1d2429a2c312474c523aa9017fba0c07b5f4a0",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"guzzlehttp/promises": "^2.5.1",
"guzzlehttp/psr7": "^2.12.5",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
"symfony/deprecation-contracts": "^2.5 || ^3.0",
"symfony/polyfill-php80": "^1.25"
},
"provide": {
"psr/http-client-implementation": "1.0"
@@ -146,9 +147,10 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2",
"guzzle/client-integration-tests": "3.0.3",
"guzzlehttp/test-server": "^0.6",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"phpunit/phpunit": "^8.5.52 || ^9.6.34",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
@@ -226,7 +228,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
"source": "https://github.com/guzzle/guzzle/tree/7.14.1"
},
"funding": [
{
@@ -242,28 +244,29 @@
"type": "tidelift"
}
],
"time": "2025-08-23T22:36:01+00:00"
"time": "2026-07-13T01:32:54+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.3.0",
"version": "2.5.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
"reference": "9ad1e4fc607446a055b95870c7f668e93b5cff29"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
"url": "https://api.github.com/repos/guzzle/promises/zipball/9ad1e4fc607446a055b95870c7f668e93b5cff29",
"reference": "9ad1e4fc607446a055b95870c7f668e93b5cff29",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
"php": "^7.2.5 || ^8.0",
"symfony/deprecation-contracts": "^2.5 || ^3.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
"phpunit/phpunit": "^8.5.52 || ^9.6.34"
},
"type": "library",
"extra": {
@@ -309,7 +312,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.3.0"
"source": "https://github.com/guzzle/promises/tree/2.5.1"
},
"funding": [
{
@@ -325,27 +328,29 @@
"type": "tidelift"
}
],
"time": "2025-08-22T14:34:08+00:00"
"time": "2026-07-08T15:48:39+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.9.0",
"version": "2.12.5",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884"
"reference": "9365d578a9fd1552ad6ca9c3cb530708526feb09"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884",
"reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/9365d578a9fd1552ad6ca9c3cb530708526feb09",
"reference": "9365d578a9fd1552ad6ca9c3cb530708526feb09",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
"ralouphie/getallheaders": "^3.0",
"symfony/deprecation-contracts": "^2.5 || ^3.0",
"symfony/polyfill-php80": "^1.25"
},
"provide": {
"psr/http-factory-implementation": "1.0",
@@ -353,9 +358,9 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"http-interop/http-factory-tests": "1.1.0",
"jshttp/mime-db": "1.54.0.1",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
"phpunit/phpunit": "^8.5.52 || ^9.6.34"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -426,7 +431,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.9.0"
"source": "https://github.com/guzzle/psr7/tree/2.12.5"
},
"funding": [
{
@@ -442,20 +447,20 @@
"type": "tidelift"
}
],
"time": "2026-03-10T16:41:02+00:00"
"time": "2026-07-13T01:27:20+00:00"
},
{
"name": "phpmailer/phpmailer",
"version": "v7.0.2",
"version": "v7.1.1",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088"
"reference": "1bc1716a507a65e039d4ac9d9adebbbd0d346e15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088",
"reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/1bc1716a507a65e039d4ac9d9adebbbd0d346e15",
"reference": "1bc1716a507a65e039d4ac9d9adebbbd0d346e15",
"shasum": ""
},
"require": {
@@ -516,7 +521,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v7.0.2"
"source": "https://github.com/PHPMailer/PHPMailer/tree/v7.1.1"
},
"funding": [
{
@@ -524,7 +529,7 @@
"type": "github"
}
],
"time": "2026-01-09T18:02:33+00:00"
"time": "2026-05-18T08:06:14+00:00"
},
{
"name": "psr/container",
@@ -886,16 +891,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"version": "v3.7.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d",
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d",
"shasum": ""
},
"require": {
@@ -908,7 +913,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
"dev-main": "3.7-dev"
}
},
"autoload": {
@@ -933,7 +938,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1"
},
"funding": [
{
@@ -944,12 +949,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
"time": "2026-06-05T06:23:12+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -1036,16 +1045,16 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.37.0",
"version": "v1.38.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
"reference": "dc21118016c039a66235cf93d96b435ffb282412"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/dc21118016c039a66235cf93d96b435ffb282412",
"reference": "dc21118016c039a66235cf93d96b435ffb282412",
"shasum": ""
},
"require": {
@@ -1099,7 +1108,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.37.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.38.1"
},
"funding": [
{
@@ -1119,20 +1128,20 @@
"type": "tidelift"
}
],
"time": "2024-09-10T14:38:51+00:00"
"time": "2026-05-25T15:22:23+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.37.0",
"version": "v1.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
"reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b",
"reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b",
"shasum": ""
},
"require": {
@@ -1184,7 +1193,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.37.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0"
},
"funding": [
{
@@ -1204,20 +1213,20 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2026-05-25T13:48:31+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.37.0",
"version": "v1.38.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315"
"reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315",
"reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92",
"reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92",
"shasum": ""
},
"require": {
@@ -1269,7 +1278,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.37.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1"
},
"funding": [
{
@@ -1289,20 +1298,104 @@
"type": "tidelift"
}
],
"time": "2026-04-10T17:25:58+00:00"
"time": "2026-05-26T12:51:13+00:00"
},
{
"name": "symfony/polyfill-php81",
"name": "symfony/polyfill-php80",
"version": "v1.37.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.38.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/6bfb9c766cacffbc8e118cb87217d08ed84e5cd7",
"reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7",
"shasum": ""
},
"require": {
@@ -1349,7 +1442,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.38.1"
},
"funding": [
{
@@ -1369,7 +1462,7 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2026-05-26T12:45:58+00:00"
},
{
"name": "symfony/polyfill-php82",
+4 -1
View File
@@ -1,8 +1,11 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:/$1]
RewriteRule ^(.*)$ index.php [L,QSA,E=PATH_INFO:/$1]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</IfModule>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+56 -5
View File
@@ -49,13 +49,16 @@ function updateToolbar(){
function updateQueryStr(obj){
var arr = [];
for (var p in obj){
if (obj.hasOwnProperty(p) && typeof obj[p] != 'undefined' && obj[p] != '') {
if (obj.hasOwnProperty(p) && typeof obj[p] != 'undefined' && obj[p] != null && obj[p] != '') {
arr.push(p + "=" + encodeURIComponent(obj[p]));
}
}
history.replaceState({}, null, '?'+arr.join("&"));
}
var VALID_PAGE_SIZES = [10, 15, 20, 30, 50, 100, 200, 300, 500];
var DEFAULT_PAGE_SIZE = 15;
if (typeof $.fn.bootstrapTable !== "undefined") {
$.fn.bootstrapTable.custom = {
method: 'post',
@@ -64,8 +67,8 @@ if (typeof $.fn.bootstrapTable !== "undefined") {
pagination: true,
sidePagination: 'server',
pageNumber: 1,
pageSize: 20,
pageList: [10, 15, 20, 30, 50, 100],
pageSize: 15,
pageList: [10, 15, 20, 30, 50, 100, 200, 300, 500],
loadingFontSize: '18px',
toolbar: '#searchToolbar',
showColumns: true,
@@ -98,7 +101,32 @@ if (typeof $.fn.bootstrapTable !== "undefined") {
},
formatNoMatches: function(){
return '没有找到匹配的记录';
}
},
onSort: function(name, order) {
var $table = $('#listTable');
if (!name) {
$table.data('_sortClicks', null);
return;
}
var clicks = $table.data('_sortClicks') || {};
if (clicks._last !== name) {
clicks = {_last: name};
clicks[name] = 1;
this.sortOrder = 'desc';
} else {
clicks[name] = (clicks[name] || 0) + 1;
if (clicks[name] === 1) {
this.sortOrder = 'desc';
} else if (clicks[name] === 2) {
this.sortOrder = 'asc';
} else {
this.sortName = undefined;
this.sortOrder = undefined;
clicks = {};
}
}
$table.data('_sortClicks', clicks);
},
};
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.custom);
}
@@ -171,4 +199,27 @@ function delCookie(name)
if(cval!=null){
document.cookie= name + "="+cval+";expires="+exp.toGMTString();
}
}
}
function getStoredPageSize(key, defaultSize) {
defaultSize = defaultSize || DEFAULT_PAGE_SIZE;
var urlSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : null;
if (urlSize && VALID_PAGE_SIZES.indexOf(urlSize) !== -1) {
return urlSize;
}
var stored = localStorage.getItem(key);
if (stored) {
var storedSize = parseInt(stored);
if (VALID_PAGE_SIZES.indexOf(storedSize) !== -1) {
return storedSize;
}
}
return defaultSize;
}
function setStoredPageSize(key, size) {
var intSize = parseInt(size);
if (VALID_PAGE_SIZES.indexOf(intSize) !== -1) {
localStorage.setItem(key, intSize);
}
}
+1
View File
@@ -108,6 +108,7 @@ Route::group(function () {
Route::get('/record/batchadd', 'domain/record_batch_add2');
Route::any('/record/batchedit', 'domain/record_batch_edit2');
Route::any('/record/log/:id', 'domain/record_log');
Route::post('/record/groups/:id', 'domain/record_groups');
Route::post('/record/list', 'domain/record_list');
Route::post('/record/weight/data/:id', 'domain/weight_data');
Route::any('/record/weight/:id', 'domain/weight');