Compare commits

..

3 Commits

Author SHA1 Message Date
xiaojunnuo 85c633fddf Merge branch 'v2-dev' into v2-invite 2026-05-19 22:59:18 +08:00
xiaojunnuo f9a310b6c3 feat: 商业版支持邀请返佣功能 2026-05-18 13:25:35 +08:00
xiaojunnuo 1bdcfe646f chore: tsconfig.build 支持sourcemap控制 2026-05-18 13:25:01 +08:00
114 changed files with 29108 additions and 1027 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
# cache: 'npm'
# working-directory: ./packages/ui/certd-client
- run: |
npm install -g pnpm@10.33.4
npm install -g pnpm
pnpm install
npm run build
working-directory: ./packages/ui/certd-client
+1 -1
View File
@@ -46,7 +46,7 @@ jobs:
console.log("certd_version:",pkg.version);
return pkg.version
- run: |
npm install -g pnpm@10.33.4
npm install -g pnpm
pnpm install
npm run build
working-directory: ./packages/ui/certd-client
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
run: |
export GITEE_TOKEN=${{ secrets.GITEE_TOKEN }}
rm -rf ./pnpm*.yaml
npm install -g pnpm@10.33.4
npm install -g pnpm
pnpm install
npm run publish_to_gitee
working-directory: ./
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
run: |
export GITHUB_TOKEN=${{ secrets.GH_TOKEN }}
rm -rf ./pnpm*.yaml
npm install -g pnpm@10.33.4
npm install -g pnpm
pnpm install
npm run publish_to_github
working-directory: ./
+1 -1
View File
@@ -50,7 +50,7 @@ jobs:
# cache: 'npm'
# working-directory: ./packages/ui/certd-client
- run: |
npm install -g pnpm@10.33.4
npm install -g pnpm
pnpm install
npm run build
working-directory: ./packages/ui/certd-client
+1 -4
View File
@@ -31,7 +31,4 @@ test/**/*.js
/packages/pro/
test.js
.history
/logs
.pnpm-lock.yaml
pnpm-lock.yaml
.studio/
/logs
-38
View File
@@ -33,44 +33,6 @@ version: 1.0.0
7. 删除、审核通过、拒绝等危险操作必须保留确认弹窗和错误提示,成功后刷新当前 CRUD 列表。
8. 对话框里只做纯确认时可以使用 `Modal.confirm`;只要需要字段输入、表单校验或提交字段,统一使用 `useFormDialog` / `openFormDialog`,不要在 `Modal.confirm``content` 里手写输入框。
## crud 配置
const crudOptions ={
id: string, //表格唯一标识,同一个页面的多个表格的列设置和字段设置会根据id进行区分保存
request:{}, //http请求
columns:{ //字段配置
key:{ //字段key
column:{}, //对应table-column配置
form:{}, //表单中该字段的公共配置,viewForm、addForm、editForm、search会集成此配置,支持对应ui的form-item配置
viewForm:{}, //查看表单中该字段的配置,支持对应ui的form-item配置
addForm:{}, // 添加表单中该字段的配置,支持对应ui的form-item配置
editForm:{}, //编辑表单中该字段的配置,支持对应ui的form-item配置
search:{} //对应查询表单的form-item配置
}
},
search:{ //查询框配置 ,对应fs-search组件
options:{} //查询表单配置 ,对应el-from, a-form配置
},
actionbar:{}, //动作条,添加按钮,对应fs-actionbar组件
toolbar:{}, //工具条 ,对应fs-toolbar组件
table:{ //表格配置,对应fs-table
// 对应 el-table / a-table的配置
slots:{} // 对应el-table ,a-table的插槽
},
data:{}, //列表数据,无需配置,自动从pageRequest中获取
// 如果你要手动改变表格数据,可以通过crudBinding.value.data直接赋值修改表格数据
rowHandle:{}, //操作列配置,对应fs-row-handle
form:{ //表单的公共配置,对应el-forma-form配置
wrapper:{} //表单外部容器(对话框)的配置,对应el-dialog,el-drawer,a-model,a-drawer的配置
},
viewForm:{}, //查看表单的独立配置
editForm:{}, //编辑表单的独立配置
addForm:{}, //添加表单的独立配置
pagination:{}, //分页配置 ,对应el-pagination / a-pagination
container:{}, //容器配置 ,对应fs-container
}
## 布局高度
- Fast Crud 表格依赖外部容器高度计算。虽然表格本身有默认约 200px 高度,但页面内嵌 `fs-crud` 时,为了获得稳定可用的列表区域,必须让外层容器提供明确高度或剩余高度。
+1 -2
View File
@@ -20,6 +20,5 @@
"scm.repositories.visible": 9,
"scm.repositories.explorer": false,
"scm.repositories.selectionMode": "multiple",
"scm.repositories.sortOrder": "discovery time",
"git.ignoreLimitWarning": true
"scm.repositories.sortOrder": "discovery time"
}
+13 -4
View File
@@ -1,4 +1,4 @@
# Certd 开发 Agent 上下文
# Certd 开发 Agent 上下文
这个文件是给在本仓库工作的开发 agent 看的常驻项目说明。后续会话进入仓库后,应先读取它,再按任务需要查看具体代码,避免每次都重新全量扫描项目。
@@ -35,6 +35,8 @@ Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。
- `packages/ui/certd-server/`:后端服务
- `packages/ui/certd-client/`:前端 Web 管理台
`packages/pro/` 是独立 Git 工作区,使用 `packages/pro/.git` 管理。根仓库的 `git status` / `git diff` 默认看不到这里的实际改动;修改商业版代码后,要在 `packages/pro` 目录内单独执行 `git status` / `git diff` 检查。
## 后端
主要后端包:`packages/ui/certd-server`
@@ -108,6 +110,14 @@ Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。
- 不要运行前端 `pnpm tsc` / `vue-tsc`:当前依赖组合中 `vue-tsc@1.8.27` 会直接抛内部错误 `Search string not found: "/supportedTSExtensions = .*(?=;)/"`,不是有效的项目类型检查结果。
- 前端暂不跑单元测试;当前 `test:unit` 只是占位脚本
前端列表管理页面约定:
- 列表管理、后台管理、记录查询、CRUD 表格类页面,默认优先使用 Fast Crud(`@fast-crud/fast-crud``fs-crud``useFs``createCrudOptions`)实现。
- 只有轻量只读展示、强交互自定义界面或已有页面模式明确不适合 Fast Crud 时,才手写 `a-table` / 自定义列表,并在回复中说明原因。
- 开发或重构这类页面前,先读取 `.trae/skills/fast-crud-page-dev/SKILL.md`,按仓库内 Fast Crud 页面拆分与验证方式实现。
- 前端对话框里只做纯确认时可以使用 `Modal.confirm`;只要对话框里有字段输入、表单校验或提交字段,统一使用 `useFormDialog` / `openFormDialog`,不要在 `Modal.confirm``content` 里手写输入框。
- 页面内嵌 Fast Crud 表格时,要显式给外层容器稳定高度或 `flex: 1; min-height: 0` 的撑满链路;Fast Crud 依赖外部元素高度,不能只依赖表格默认高度。
## 流水线与插件模型
项目最关键的架构概念是证书流水线。
@@ -168,6 +178,7 @@ Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。
- `packages/ui/certd-server/data/``logs/`、生成的 metadata/dist 等通常视为运行时或构建产物,除非任务明确要求处理它们。
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
- 本仓库代码注释优先使用中文,尤其是解释业务规则、兼容逻辑、协议细节和隐藏风险时;除非文件已有明确英文注释风格或引用外部英文术语,否则不要新增英文说明性注释。
- 代码可读性优先于短写法。遇到包含业务分支的复杂三元表达式、内联对象、链式调用或条件组合时,优先拆成命名清晰的中间变量、独立分支或小函数,让读代码的人能一眼看出业务意图;不要为了少写几行把逻辑压成难读的一坨。
## 插件开发技能
@@ -182,6 +193,7 @@ Certd 是一个支持私有化部署的 SSL/TLS 证书自动化管理平台。
- `access-plugin-dev`:开发 Access 授权插件
- `dns-provider-dev`:开发 DNS Provider 插件
- `fast-crud-page-dev`:开发或重构前端 Fast Crud 列表管理页面
- `task-plugin-dev`:开发 Task 部署任务插件
- `plugin-converter`:将插件转换为 YAML 配置
@@ -218,6 +230,3 @@ Get-ChildItem packages\ui\certd-client\src\views\certd
- 单个 monorepo 包运行单元测试时,优先使用 `corepack pnpm --dir <包目录> test:unit`,例如 `corepack pnpm --dir packages\ui\certd-server test:unit``corepack pnpm --dir packages\core\basic test:unit``corepack pnpm --dir packages\plugins\plugin-lib test:unit`;也可以用包名过滤,例如 `corepack pnpm --filter @certd/ui-server test:unit`。前端 `packages\ui\certd-client` 暂时不跑单元测试。
- 前端 TS/Vue/locale 等文件改动后,优先只对本次改动文件运行项目现有自动格式化/修复;Windows/PowerShell 下 Prettier 已验证可用命令为 `packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`ESLint 可用命令为 `packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`;不要运行 `vue-tsc` / `pnpm tsc`;不要为了格式化无关文件而扩大 diff。项目保留了 `tslint` 依赖,但当前主要使用 ESLint + Prettier。
- 优先对改动包运行聚焦的测试;后端可按包运行单元测试,前端优先使用 Prettier/ESLint 做改动文件验证。只有跨包影响明显时再考虑全 monorepo 构建。
- 不要主动运行 `pnpm install` 安装依赖:用户会事先准备好 `node_modules`。如果 `pnpm install``test:unit` 因缺少依赖、TTY 或网络问题失败,立即停止尝试,告知用户解决环境问题。
-31
View File
@@ -3,37 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Bug Fixes
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
* 修复暗黑模式下注册页面验证码看不清的问题 ([5ba33be](https://github.com/certd/certd/commit/5ba33be30f765f06cafbfcc04f5e25320db01449))
### Performance Improvements
* 修复商业版套餐添加和修改时的字段显示 ([fb5b00d](https://github.com/certd/certd/commit/fb5b00d73f925036a65ce5003c57c1199578c34d))
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
### Bug Fixes
* **certd-server:** 调整首页缓存控制头的判断逻辑 ([0499347](https://github.com/certd/certd/commit/0499347588ee544862420ab9a5afd2546d61bc6c))
### Performance Improvements
* **controller:** 更换版本获取源并添加版本标准化处理 ([cb08e06](https://github.com/certd/certd/commit/cb08e061d257ba23a0fefdbfb046a8c759def828))
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
### Bug Fixes
-1
View File
@@ -119,7 +119,6 @@ export default defineConfig({
{text: "Certd本身的证书更新", link: "/guide/use/https/index.md"},
{text: "js脚本插件使用", link: "/guide/use/custom-script/index.md"},
{text: "邮箱配置", link: "/guide/use/email/index.md"},
{text: "证书复用", link: "/guide/use/pretask/"},
{text: "IPv6支持", link: "/guide/use/setting/ipv6.md"},
{text: "ESXi", link: "/guide/use/ESXi/index.md"},
{text: "宝塔动态IP白名单", link: "/guide/use/baota/white_list.md"},
-20
View File
@@ -3,26 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
* 修复暗黑模式下注册页面验证码看不清的问题 ([5ba33be](https://github.com/certd/certd/commit/5ba33be30f765f06cafbfcc04f5e25320db01449))
### Performance Improvements
* 修复商业版套餐添加和修改时的字段显示 ([fb5b00d](https://github.com/certd/certd/commit/fb5b00d73f925036a65ce5003c57c1199578c34d))
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
### Bug Fixes
* **certd-server:** 调整首页缓存控制头的判断逻辑 ([0499347](https://github.com/certd/certd/commit/0499347588ee544862420ab9a5afd2546d61bc6c))
### Performance Improvements
* **controller:** 更换版本获取源并添加版本标准化处理 ([cb08e06](https://github.com/certd/certd/commit/cb08e061d257ba23a0fefdbfb046a8c759def828))
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
### Bug Fixes
+8 -9
View File
@@ -1,5 +1,5 @@
# 任务插件
`132` 款任务插件
`131` 款任务插件
## 1. 证书申请
| 序号 | 名称 | 说明 |
@@ -93,14 +93,13 @@
| 9.| **阿里云-部署至ESA** | 部署证书到阿里云ESA(边缘安全加速),自动删除过期证书 |
| 10.| **阿里云-部署至阿里云FC(3.0)** | 部署证书到阿里云函数计算(FC3.0) |
| 11.| **阿里云-部署至GA** | 部署证书到阿里云GA(全球加速),支持更新默认证书和扩展证书 |
| 12.| **阿里云-部署至直播(Live** | 部署证书到阿里云视频直播(Live)域名 |
| 13.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
| 14.| **阿里云-部署证书至OSS** | 部署域名证书阿里云OSS自定义域名,不是上传到阿里云oss |
| 15.| **阿里云-部署至CLB(传统负载均衡)** | 部署证书到阿里云CLB(传统负载均衡) |
| 16.| **阿里云-部署至VOD** | 部署证书到阿里云视频点播(vod |
| 17.| **阿里云-部署至阿里云WAF(云产品接入)** | 部署证书到阿里云WAF(云产品接入)CNAME方式接入的请选择另外一个waf插件 |
| 18.| **阿里云-部署至阿里云WAF(cname接入)** | 部署证书到阿里云WAF(cname接入),云资源的请选择另外一个waf插件 |
| 19.| **阿里云-上传证书到CAS** | 上传证书到阿里云证书管理服务(CAS),如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
| 12.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
| 13.| **阿里云-部署证书至OSS** | 部署域名证书至阿里云OSS自定义域名,不是上传到阿里云oss |
| 14.| **阿里云-部署至CLB(传统负载均衡)** | 部署证书阿里云CLB(传统负载均衡) |
| 15.| **阿里云-部署至VOD** | 部署证书到阿里云视频点播(vod |
| 16.| **阿里云-部署至阿里云WAF(云产品接入)** | 部署证书到阿里云WAF(云产品接入),CNAME方式接入的请选择另外一个waf插件 |
| 17.| **阿里云-部署至阿里云WAF(cname接入)** | 部署证书到阿里云WAF(cname接入),云资源的请选择另外一个waf插件 |
| 18.| **阿里云-上传证书到CAS** | 上传证书到阿里云证书管理服务(CAS),如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
## 6. 华为云
| 序号 | 名称 | 说明 |
+1 -4
View File
@@ -59,7 +59,4 @@ DNS problem: NXDOMAIN looking up TXT for _acme-challenge.xxxxx - check that a D
证书颁发机构向域名ns查询TXT验证记录失败,有以下几种可能
1、域名的ns服务器修改成别的了,但申请证书时的DNS提供商选择错误(检查确认,配置正确的DNS提供商)
2、证书颁发机构与ns域名服务器之间访问不通,无法查询到TXT记录(尝试更换证书颁发机构)
3、ns服务商解析值生效慢(尝试修改证书申请任务里面的等待生效时长600-1000s)
## 8. 同一份证书上传多次的问题
同一份证书在阿里云、腾讯云中上传多次,[请使用证书复用功能](../use/pretask/index.md),避免重复上传。
3、ns服务商解析值生效慢(尝试修改证书申请任务里面的等待生效时长600-1000s)
+3 -3
View File
@@ -1,13 +1,13 @@
# 证书复用
# 带输出的前置任务
前置任务输出可以在后续任务中使用
比如上传证书到阿里云,会返回阿里云的CertId,之后其他阿里云的部署任务可以选择复用这个证书
## 使用方法
## 复用证书
![img.png](images/pretask1.png)
在后续任务中可以选择前置任务的输出
![img.png](images/pretask2.png)
![img.png](images/pretask2.png)
+1 -1
View File
@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.40.4"
"version": "1.40.1"
}
+1 -2
View File
@@ -20,7 +20,6 @@
"devb": "lerna run dev-build",
"i-all": "lerna link && lerna exec npm install ",
"publish": "pnpm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits && pnpm run afterpublishOnly ",
"publish2":" npm run pub_all && pnpm run afterpublishOnly",
"afterpublishOnly": "pnpm run copylogs && time /t >trigger/build.trigger && git add ./trigger/build.trigger && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && pnpm run commitAll",
"transform-sql": "cd ./packages/ui/certd-server/db/ && node --experimental-json-modules transform.js",
"plugin-doc-gen": "cd ./packages/ui/certd-server/ && pnpm run export-metadata",
@@ -40,7 +39,7 @@
"test:unit": "cross-env NODE_ENV=unittest pnpm -r --workspace-concurrency=1 run test:unit",
"pub": "echo 1",
"dev": "pnpm run -r --parallel compile ",
"pub_all": "node ./scripts/pub-all.js",
"pub_all":"pnpm run -r --parallel pub ",
"release": "time /t >trigger/release.trigger && git add trigger/release.trigger && git commit -m \"build: release\" && git push",
"publish_to_atomgit": "node --experimental-json-modules ./scripts/publish-atomgit.js",
"publish_to_gitee": "node --experimental-json-modules ./scripts/publish-gitee.js",
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/publishlab/node-acme-client/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/acme-client
## [1.40.3](https://github.com/publishlab/node-acme-client/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/acme-client
## [1.40.2](https://github.com/publishlab/node-acme-client/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/acme-client
## [1.40.1](https://github.com/publishlab/node-acme-client/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/acme-client
+3 -3
View File
@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"module": "./dist/index.js",
"main": "./dist/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.40.4",
"@certd/basic": "^1.40.1",
"@peculiar/x509": "^1.11.0",
"asn1js": "^3.0.5",
"axios": "^1.9.0",
@@ -76,5 +76,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/basic
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/basic
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/basic
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/basic
+1 -1
View File
@@ -1 +1 @@
00:18
00:34
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -52,5 +52,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/pipeline
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/pipeline
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/pipeline
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/pipeline
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -19,8 +19,8 @@
"compile": "tsc --skipLibCheck --watch"
},
"dependencies": {
"@certd/basic": "^1.40.4",
"@certd/plus-core": "^1.40.4",
"@certd/basic": "^1.40.1",
"@certd/plus-core": "^1.40.1",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"reflect-metadata": "^0.1.13"
@@ -49,5 +49,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/lib-huawei
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-huawei
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/lib-huawei
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/lib-huawei
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts",
@@ -27,5 +27,5 @@
"prettier": "^2.8.8",
"tslib": "^2.8.1"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/lib-iframe
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-iframe
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/lib-iframe
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/lib-iframe
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -34,5 +34,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/jdcloud
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/jdcloud
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/jdcloud
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/jdcloud
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.40.4",
"version": "1.40.1",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
@@ -59,5 +59,5 @@
"fetch"
]
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/lib-k8s
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-k8s
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/lib-k8s
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/lib-k8s
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -19,7 +19,7 @@
"compile": "tsc --skipLibCheck --watch"
},
"dependencies": {
"@certd/basic": "^1.40.4",
"@certd/basic": "^1.40.1",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
@@ -36,5 +36,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-14
View File
@@ -3,20 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/lib-server
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/lib-server
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/lib-server
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.40.4",
"version": "1.40.1",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -29,11 +29,11 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.40.4",
"@certd/basic": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@certd/plugin-lib": "^1.40.4",
"@certd/plus-core": "^1.40.4",
"@certd/acme-client": "^1.40.1",
"@certd/basic": "^1.40.1",
"@certd/pipeline": "^1.40.1",
"@certd/plugin-lib": "^1.40.1",
"@certd/plus-core": "^1.40.1",
"@midwayjs/cache": "3.14.0",
"@midwayjs/core": "3.20.11",
"@midwayjs/i18n": "3.20.13",
@@ -69,5 +69,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
@@ -245,8 +245,6 @@ export class SysSuiteSetting extends BaseSettings {
enabled: boolean = false;
allowSuiteStack: boolean = false;
registerGift?: {
productId: number;
duration: number;
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/midway-flyway-js
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.40.4",
"version": "1.40.1",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -49,5 +49,5 @@
"typeorm": "^0.3.11",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-12
View File
@@ -3,18 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
**Note:** Version bump only for package @certd/plugin-cert
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/plugin-cert
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/plugin-cert
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/plugin-cert
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -18,10 +18,10 @@
"compile": "tsc --skipLibCheck --watch"
},
"dependencies": {
"@certd/acme-client": "^1.40.4",
"@certd/basic": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@certd/plugin-lib": "^1.40.4",
"@certd/acme-client": "^1.40.1",
"@certd/basic": "^1.40.1",
"@certd/pipeline": "^1.40.1",
"@certd/plugin-lib": "^1.40.1",
"psl": "^1.9.0",
"punycode.js": "^2.3.1"
},
@@ -41,5 +41,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
-14
View File
@@ -3,20 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
**Note:** Version bump only for package @certd/plugin-lib
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/plugin-lib
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
**Note:** Version bump only for package @certd/plugin-lib
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.40.4",
"version": "1.40.1",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -23,10 +23,10 @@
"@alicloud/pop-core": "^1.7.10",
"@alicloud/tea-util": "^1.4.11",
"@aws-sdk/client-s3": "^3.964.0",
"@certd/acme-client": "^1.40.4",
"@certd/basic": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@certd/plus-core": "^1.40.4",
"@certd/acme-client": "^1.40.1",
"@certd/basic": "^1.40.1",
"@certd/pipeline": "^1.40.1",
"@certd/plus-core": "^1.40.1",
"@kubernetes/client-node": "0.21.0",
"ali-oss": "^6.22.0",
"basic-ftp": "^5.0.5",
@@ -61,5 +61,5 @@
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "01c91ba294f88bd07fddf9358c4301bbb4027916"
"gitHead": "73996f055bbff996ee776e7788e5a5cb500fc197"
}
@@ -13,7 +13,7 @@ export interface ICertInfoGetter {
export type CertInfo = {
crt: string; //fullchain证书
key: string; //私钥
csr?: string; //csr
csr: string; //csr
oc?: string; //仅证书,非fullchain证书
ic?: string; //中间证书
pfx?: string;
-20
View File
@@ -3,26 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
* 修复暗黑模式下注册页面验证码看不清的问题 ([5ba33be](https://github.com/certd/certd/commit/5ba33be30f765f06cafbfcc04f5e25320db01449))
### Performance Improvements
* 修复商业版套餐添加和修改时的字段显示 ([fb5b00d](https://github.com/certd/certd/commit/fb5b00d73f925036a65ce5003c57c1199578c34d))
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
**Note:** Version bump only for package @certd/ui-client
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
### Performance Improvements
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.40.4",
"version": "1.40.1",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -106,8 +106,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@certd/lib-iframe": "^1.40.1",
"@certd/pipeline": "^1.40.1",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",
@@ -54,30 +54,6 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe735;</span>
<div class="name">wechat</div>
<div class="code-name">&amp;#xe735;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe667;</span>
<div class="name">QQ</div>
<div class="code-name">&amp;#xe667;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60c;</span>
<div class="name">wechat</div>
<div class="code-name">&amp;#xe60c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe609;</span>
<div class="name">acepanel</div>
<div class="code-name">&amp;#xe609;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60a;</span>
<div class="name">飞牛</div>
@@ -276,7 +252,7 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.svg?t=1779270521617#iconfont') format('svg');
src: url('iconfont.svg?t=1766772710945#iconfont') format('svg');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -302,42 +278,6 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-wxpay"></span>
<div class="name">
wechat
</div>
<div class="code-name">.icon-wxpay
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-qq"></span>
<div class="name">
QQ
</div>
<div class="code-name">.icon-qq
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-wechat"></span>
<div class="name">
wechat
</div>
<div class="code-name">.icon-wechat
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-acepanel"></span>
<div class="name">
acepanel
</div>
<div class="code-name">.icon-acepanel
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fnos"></span>
<div class="name">
@@ -635,38 +575,6 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-wxpay"></use>
</svg>
<div class="name">wechat</div>
<div class="code-name">#icon-wxpay</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-qq"></use>
</svg>
<div class="name">QQ</div>
<div class="code-name">#icon-qq</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-wechat"></use>
</svg>
<div class="name">wechat</div>
<div class="code-name">#icon-wechat</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-acepanel"></use>
</svg>
<div class="name">acepanel</div>
<div class="code-name">#icon-acepanel</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fnos"></use>
@@ -1,6 +1,6 @@
@font-face {
font-family: "iconfont"; /* Project id 4688792 */
src: url('iconfont.svg?t=1779270521617#iconfont') format('svg');
src: url('iconfont.svg?t=1766772710945#iconfont') format('svg');
}
.iconfont {
@@ -11,22 +11,6 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-wxpay:before {
content: "\e735";
}
.icon-qq:before {
content: "\e667";
}
.icon-wechat:before {
content: "\e60c";
}
.icon-acepanel:before {
content: "\e609";
}
.icon-fnos:before {
content: "\e60a";
}
File diff suppressed because one or more lines are too long
@@ -5,34 +5,6 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "5466096",
"name": "wechat",
"font_class": "wxpay",
"unicode": "e735",
"unicode_decimal": 59189
},
{
"icon_id": "9186714",
"name": "QQ",
"font_class": "qq",
"unicode": "e667",
"unicode_decimal": 58983
},
{
"icon_id": "26267577",
"name": "wechat",
"font_class": "wechat",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "37557578",
"name": "acepanel",
"font_class": "acepanel",
"unicode": "e609",
"unicode_decimal": 58889
},
{
"icon_id": "45984300",
"name": "飞牛",
@@ -14,14 +14,6 @@
/>
<missing-glyph />
<glyph glyph-name="wxpay" unicode="&#59189;" d="M410.493712 251.773712c-64.448471-36.97706-74.006881 20.759958-74.006881 20.759958l-80.772173 193.983933c-31.078562 92.178305 26.897497 41.56191 26.897498 41.561909s49.746372-38.732181 87.50193-62.333712c37.732946-23.602608 80.745253-6.927882 80.745254-6.927882l528.043743 250.842313C881.479874 814.421333 720.547129 896 538.352656 896 241.013636 896 0 678.901232 0 411.080547c0-154.046856 79.806318-291.154103 204.11518-380.019214L181.698086-101.56551s-10.92805-38.720336 26.945952-20.759958c25.808892 12.243853 91.603314 56.122953 130.768353 82.82771 61.570288-22.083298 128.651441-34.345455 198.970414-34.345455 297.315331 0 538.378498 217.098768 538.378499 484.924837 0 77.573115-20.313102 150.8338-56.295235 215.861568-168.236416-104.176656-559.545472-346.282128-609.973434-375.167327z" horiz-adv-x="1076" />
<glyph glyph-name="qq" unicode="&#58983;" d="M511.09761-61.257c-80.159 0-153.737 25.019-201.11 62.386-24.057-6.702-54.831-17.489-74.252-30.864-16.617-11.439-14.546-23.106-11.55-27.816 13.15-20.689 225.583-13.211 286.912-6.767v3.061zM496.65061-61.257c80.157 0 153.737 25.019 201.11 62.386 24.057-6.702 54.83-17.489 74.253-30.864 16.616-11.439 14.543-23.106 11.55-27.816-13.15-20.689-225.584-13.211-286.914-6.767v3.061zM497.12861 421.476c131.934 0.876 237.669 25.783 273.497 35.34 8.541 2.28 13.11 6.364 13.11 6.364 0.03 1.172 0.542 20.952 0.542 31.155C784.27761 666.167 701.12561 838.827 496.64061 838.838 292.15661 838.827 209.00061 666.168 209.00061 494.335c0-10.203 0.516-29.983 0.547-31.155 0 0 3.717-3.821 10.529-5.67 33.078-8.98 140.803-35.139 276.08-36.034h0.972zM860.28261 276.218c-8.12 26.086-19.204 56.506-30.427 85.72 0 0-6.456 0.795-9.718-0.148-100.71-29.205-222.773-47.818-315.792-46.695h-0.962C410.88561 313.983 289.65061 332.383 189.27961 361.302 185.44461 362.405 177.87261 361.937 177.87261 361.937 166.64961 332.724 155.56661 302.304 147.44761 276.218 108.72961 151.832 121.27261 100.356 130.82461 99.202c20.496-2.474 79.78 93.637 79.78 93.637 0-97.66 88.324-247.617 290.576-248.996a718.01 718.01 0 0 0 5.367 0C708.80161-54.778 797.12261 95.178 797.12261 192.838c0 0 59.284-96.111 79.783-93.637 9.55 1.154 22.093 52.63-16.623 177.017M434.38261 579.083c-27.9-1.24-51.745 30.106-53.24 69.956-1.518 39.877 19.858 73.207 47.764 74.454 27.875 1.224 51.703-30.109 53.218-69.974 1.527-39.877-19.853-73.2-47.742-74.436m206.67 69.956c-1.494-39.85-25.34-71.194-53.24-69.956-27.888 1.238-49.269 34.559-47.742 74.435 1.513 39.868 25.341 71.201 53.216 69.974 27.909-1.247 49.285-34.576 47.767-74.453M683.94261 527.373c-7.323 17.609-81.062 37.227-172.353 37.227h-0.98c-91.29 0-165.031-19.618-172.352-37.227a6.244 6.244 0 0 1-0.535-2.505c0-1.269 0.393-2.414 1.006-3.386 6.168-9.765 88.054-58.018 171.882-58.018h0.98c83.827 0 165.71 48.25 171.881 58.016a6.352 6.352 0 0 1 1.002 3.395c0 0.897-0.2 1.736-0.531 2.498M467.63161 639.623c1.26-15.886-7.377-30-19.266-31.542-11.907-1.544-22.569 10.083-23.836 25.978-1.243 15.895 7.381 30.008 19.25 31.538 11.927 1.549 22.607-10.088 23.852-25.974m73.097-7.935c2.533 4.118 19.827 25.77 55.62 17.886 9.401-2.07 13.75-5.116 14.668-6.316 1.355-1.77 1.726-4.29 0.352-7.684-2.722-6.725-8.338-6.542-11.454-5.226-2.01 0.85-26.94 15.889-49.905-6.553-1.579-1.545-4.405-2.074-7.085-0.242-2.678 1.834-3.786 5.553-2.196 8.135M504.33261 311.505h-0.967c-63.568-0.752-140.646 7.504-215.286 21.92-6.391-36.262-10.25-81.838-6.936-136.196 8.37-137.384 91.62-223.736 220.118-224.996H506.48461c128.498 1.26 211.748 87.612 220.12 224.996 3.314 54.362-0.547 99.938-6.94 136.203-74.654-14.423-151.745-22.684-215.332-21.927M323.27461 318.984v-137.468s64.957-12.705 130.031-3.91V304.41c-41.225 2.262-85.688 7.304-130.031 14.574M788.09761 463.464s-121.98-40.387-283.743-41.539h-0.962c-161.497 1.147-283.328 41.401-283.744 41.539l-40.854-106.952c102.186-32.31 228.837-53.135 324.598-51.926l0.96 0.002c95.768-1.216 222.4 19.61 324.6 51.924l-40.855 106.952z" horiz-adv-x="1024" />
<glyph glyph-name="wechat" unicode="&#58892;" d="M1024.16 201.184c0 149.92-143.104 271.392-319.584 271.392-176.576 0-319.68-121.504-319.68-271.392S528-70.208 704.576-70.208c55.456 0 107.648 12.096 153.184 33.248l125.984-54.528-14.592 140.544c34.784 43.392 55.04 95.808 55.04 152.128zM596.832 274.72c-25.152 0-45.472 20.352-45.472 45.472s20.32 45.472 45.472 45.472c25.12 0 45.44-20.384 45.44-45.472s-20.384-45.472-45.44-45.472z m215.392 0c-25.056 0-45.44 20.352-45.44 45.472s20.384 45.472 45.44 45.472c25.184 0 45.536-20.384 45.536-45.472s-20.352-45.472-45.536-45.472zM704.576 508.512c49.376 0 96.416-8.8 139.264-24.64 0.32 5.728 0.992 11.232 0.992 16.992 0 198.08-189.152 358.624-422.432 358.624C189.184 859.488 0.032 698.976 0.032 500.864c0-74.496 26.816-143.776 72.704-201.12L53.472 114.08l166.432 72.096c41.216-19.2 86.784-32.16 134.88-38.784-3.616 17.504-5.824 35.424-5.824 53.792 0.032 169.44 159.552 307.296 355.616 307.296z m-139.808 209.6c33.184 0 60-26.88 60-60 0-33.184-26.816-60.064-60-60.064s-60.032 26.88-60.032 60.064c0 33.152 26.88 60 60.032 60zM280.032 598.048c-33.184 0-60 26.88-60 60.064 0 33.152 26.848 60 60 60 33.184 0 60.032-26.88 60.032-60s-26.88-60.064-60.032-60.064z" horiz-adv-x="1025" />
<glyph glyph-name="acepanel" unicode="&#58889;" d="M0 896m100.8867 0l822.2266 0q100.8867 0 100.8867-100.8867l0-822.2266q0-100.8867-100.8867-100.8867l-822.2266 0q-100.8867 0-100.8867 100.8867l0 822.2266q0 100.8867 100.8867 100.8867ZM469.123153 705.576355h171.507389l2.522167-29.004926 3.783252-30.26601 6.305418-55.487685 7.566503-69.359606 3.783251-29.004926 2.522167-23.960591 5.044335-42.876847 2.522168-26.482759 5.044335-40.35468 2.522167-23.960591 5.044335-44.137931 3.783252-32.788177 2.522167-21.438424v-6.305419h229.517241l-7.566502-27.743842-15.133005-50.44335-11.349754-39.093596-11.349753-39.093596-3.783252-10.08867h-23.960591l6.305419 6.305419 7.566503 8.827586v3.783251l-21.438424 16.394089h-3.783251l-8.827587-10.08867-11.349753-6.305419-8.827586-2.522167h-11.349754l-10.08867 3.783251-6.305419 7.566502-2.522167 7.566503v8.827586l1.261083 1.261084 36.571429 3.783251 25.221675 7.566503 13.871921 7.566502 8.827586 8.827586 5.044335 10.08867 2.522168 16.394089-2.522168 12.610837-6.305418 10.08867-8.827587 7.566503-15.133005 6.305418-5.044335 1.261084h-29.004926l-16.394088-5.044335-13.871922-7.566502-12.610837-11.349754-12.610837-18.916256-7.566503-20.17734-2.522167-17.655172v-17.655173l2.522167-15.133005 6.305419-15.133005 5.044335-6.305418v-2.522168h-49.182266l7.566502 10.08867 7.566503 11.349754v5.044335l-25.221675 11.349753-3.783251 1.261084-8.827587-12.610837-6.305418-6.305419-8.827587-3.783251h-8.827586l-10.08867 3.783251-5.044335 6.305419-2.522167 10.08867 2.522167 20.17734 5.044335 23.960591 5.044335 12.610837 6.305419 7.566503 7.566502 3.783251 6.305419 1.261084h8.827586l8.827587-3.783252 6.305418-10.08867 1.261084-3.783251 6.305419 1.261084 26.482758 10.08867-1.261083 10.08867-7.566503 12.610837-10.08867 7.566503-13.871921 6.305418-8.827586 1.261084h-25.221675l-15.133005-5.044335-13.871921-7.566502-12.610838-11.349754-8.827586-13.871921-6.305418-12.610838-3.783252-12.610837-2.522167-22.699507 1.261084-25.221675 6.305418-15.133005 6.305419-11.349754h-37.832512l-2.522168 16.394089-3.783251 45.399015-3.783251 35.310344-5.044335 59.270936H435.073892l6.305418 15.133005 18.916257 39.093596 10.088669 22.699508 10.08867 20.17734 6.305419 13.871921h66.837439l-1.261084 5.044335-5.044335 71.881773-2.522168 29.004926-3.783251 55.487685-6.305419 81.970443v11.349754h-8.827586l-2.522167-7.566502-20.17734-44.137931-20.17734-44.137932-22.699507-49.182266-23.960592-51.704433-20.17734-42.876847-10.088669-23.960591-12.610838-27.743843-10.08867-20.17734-10.08867-21.438423-10.08867-20.17734-15.133005-31.527094-22.699507-46.660098-13.871921-29.004926-15.133005-31.527094-13.871921-29.004926-1.261084-1.261084H139.980296l2.522167 7.566503 17.655172 35.310344 12.610838 23.960591 29.004926 56.748769 12.610837 23.960591 16.394089 32.788177 12.610838 23.960592 25.221674 49.182266 17.655173 34.049261 10.08867 18.916256 10.08867 20.17734 30.26601 59.270936 17.655172 34.049261 11.349754 21.438423 10.08867 20.17734 29.004926 56.748769 21.438423 41.615763 18.916257 36.571429 22.699507 44.137931zM809.615764 170.876847h13.871921l7.566502-3.783251 2.522168-3.783251v-11.349754l-6.305419-7.566502-12.610837-5.044335-22.699508-3.783252h-7.566502l2.522167 13.871922 6.305419 10.08867 10.08867 8.827586z" horiz-adv-x="1024" />
<glyph glyph-name="fnos" unicode="&#58890;" d="M144.482434 896h730.821577c67.983402-28.323585 116.141145-76.481328 144.46473-144.46473v-730.821577c-28.323585-67.983402-76.481328-116.141145-144.46473-144.46473h-730.821577c-67.983402 28.323585-116.141145 76.481328-144.46473 144.46473v730.821577c28.323585 67.983402 76.481328 116.141145 144.46473 144.46473zM229.461687 632.564315c-1.665593-32.445079 1.164216-66.43678 8.497926-101.975103 17.990108-19.800166 40.654075-29.717245 67.983402-29.742739-18.63595-17.208299-27.133876-38.453112-25.493776-63.73444-84.486373 1.053743-117.058921 43.543369-97.726141 127.46888a431.320697 431.320697 0 0 0 46.738589 67.983402zM781.826833 632.564315c66.938158-53.536929 75.436083-114.44156 25.493776-182.705394a3226.917178 3226.917178 0 0 0-399.40249-12.746888v-237.941909h50.987552c-9.883087 77.900481 24.108614 109.062373 101.975104 93.477179a275.647203 275.647203 0 0 0 4.248962 67.983402 80.458357 80.458357 0 0 0 21.244813 12.746888 571.281527 571.281527 0 0 0 169.958507-4.248962c-32.436581-40.280166-74.926207-60.105826-127.46888-59.485477 11.149278-79.387618-22.842423-107.719701-101.975104-84.979254a347.871071 347.871071 0 0 0-4.248962-76.481327 59.273029 59.273029 0 0 0-29.742739-21.244814 361.14483 361.14483 0 0 0-110.473029 0 59.273029 59.273029 0 0 0-29.742739 21.244814 814.381676 814.381676 0 0 0-12.746888 161.460581 814.381676 814.381676 0 0 0 12.746888 161.46058 305.415436 305.415436 0 0 0 38.240664 29.742739l365.410789 8.497925c15.576697 4.248963 25.493776 14.166041 29.742738 29.742739 5.761593 31.62078 4.34244 62.782672-4.248962 93.477178z" horiz-adv-x="1024" />
<glyph glyph-name="ksyun" unicode="&#59565;" d="M718.5408 442.1632c-4.1984 0-8.3968 0.7168-12.5952 0.7168a103.8336 103.8336 0 0 1-67.8912-25.088 139.6736 139.6736 0 0 1 13.6192 60.3136 133.12 133.12 0 0 1-2.4576 25.7024 139.5712 139.5712 0 0 1-274.432 0 133.12 133.12 0 0 1-2.4576-25.7024 139.6736 139.6736 0 0 1 13.6192-60.3136 103.8336 103.8336 0 0 1-67.8912 25.088c-4.1984 0-8.3968 0-12.5952-0.7168a104.5504 104.5504 0 1 1 101.0688-159.4368 116.736 116.736 0 0 1 6.144 11.0592 105.1648 105.1648 0 0 1 4.9152 76.6976 62.6688 62.6688 0 0 0 27.3408-20.48l2.6624-3.8912a83.2512 83.2512 0 0 0 133.9392 3.3792l4.7104-6.8608 51.2-73.9328a84.0704 84.0704 0 0 1 62.464-34.6112h5.5296a104.5504 104.5504 0 0 1 12.5952 208.384zM512 896a512 512 0 1 1 512-512A512 512 0 0 1 512 896z m200.8064-732.3648h-6.8608a152.4736 152.4736 0 0 0-120.5248 58.9824S509.2352 331.3664 508.0064 332.8a42.1888 42.1888 0 0 1-32.4608 15.2576 40.96 40.96 0 0 1-24.064-7.5776l122.88-175.4112a62.5664 62.5664 0 0 1 77.0048-20.48A97.5872 97.5872 0 0 0 593.92 112.4352a97.0752 97.0752 0 0 0-95.5392 39.1168l-49.4592 70.656a174.8992 174.8992 0 1 0-143.36 290.5088 209.7152 209.7152 0 0 0 413.9008 0 174.7968 174.7968 0 0 0-6.144-349.0816z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 86 KiB

@@ -1,5 +1,5 @@
<template>
<div class="flex captcha-image-input">
<div class="flex">
<a-input :value="valueRef" :placeholder="t('certd.captcha.inputImageCode')" autocomplete="off" @update:value="onChange">
<template #prefix>
<fs-icon icon="ion:image-outline"></fs-icon>
@@ -71,10 +71,3 @@ function emitChange(value: any) {
emit("change", value);
}
</script>
<style lang="less">
.captcha-image-input {
.input-right {
background-color: #cfcfcf;
}
}
</style>
@@ -22,6 +22,8 @@ export default {
mySuite: "我的套餐",
suiteBuy: "套餐购买",
myTrade: "我的订单",
myWallet: "我的钱包",
inviteCommission: "邀请返佣",
paymentReturn: "支付返回",
source: "源码",
github: "github",
@@ -46,6 +48,8 @@ export default {
suiteSetting: "套餐设置",
orderManager: "订单管理",
userSuites: "用户套餐",
inviteCommissionSetting: "邀请返佣设置",
inviteWithdraw: "提现申请记录",
netTest: "网络测试",
enterpriseManager: "企业管理设置",
projectManager: "项目管理",
+2
View File
@@ -12,9 +12,11 @@ import plugin from "./plugin/";
import { setupVben } from "./vben";
import { util } from "/@/utils";
import { initPreferences } from "/@/vben/preferences";
import { inviteUtils } from "/@/utils/util.invite";
// import "./components/code-editor/import-works";
// @ts-ignore
async function bootstrap() {
inviteUtils.captureFromLocation();
const app = createApp(App);
// app.use(Antd);
app.use(Antd);
@@ -324,7 +324,7 @@ export const certdResources = [
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
return settingStore.isInviteCommissionEnabled;
},
icon: "ion:gift-outline",
auth: true,
@@ -359,6 +359,36 @@ export const certdResources = [
keepAlive: true,
},
},
{
title: "certd.myWallet",
name: "MyWallet",
path: "/certd/wallet",
component: "/certd/wallet/index.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:wallet-outline",
auth: true,
keepAlive: true,
},
},
{
title: "certd.inviteCommission",
name: "InviteCommission",
path: "/certd/invite",
component: "/certd/invite/index.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:gift-outline",
auth: true,
keepAlive: true,
},
},
{
title: "certd.paymentReturn",
name: "PaymentReturn",
@@ -286,6 +286,38 @@ export const sysResources = [
keepAlive: true,
},
},
{
title: "certd.sysResources.inviteCommissionSetting",
name: "SysInviteCommissionSetting",
path: "/sys/suite/invite/setting",
component: "/sys/suite/invite/setting.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:gift-outline",
permission: "sys:settings:edit",
auth: true,
keepAlive: true,
},
},
{
title: "certd.sysResources.inviteWithdraw",
name: "SysInviteWithdraw",
path: "/sys/suite/invite/withdraw",
component: "/sys/suite/invite/withdraw.vue",
meta: {
show: () => {
const settingStore = useSettingStore();
return settingStore.isComm;
},
icon: "ion:cash-outline",
permission: "sys:settings:edit",
auth: true,
keepAlive: true,
},
},
],
},
{
@@ -97,6 +97,9 @@ export type SysPublicSetting = {
export type SuiteSetting = {
enabled?: boolean;
};
export type InviteSetting = {
enabled?: boolean;
};
export type SysPrivateSetting = {
httpProxy?: string;
httpsProxy?: string;
@@ -142,6 +145,7 @@ export type AllSettings = {
siteEnv: SiteEnv;
headerMenus: HeaderMenus;
suiteSetting: SuiteSetting;
inviteSetting: InviteSetting;
app: AppInfo;
};
@@ -30,6 +30,9 @@ export interface SettingState {
headerMenus?: HeaderMenus;
inited?: boolean;
suiteSetting?: SuiteSetting;
inviteSetting?: {
enabled?: boolean;
};
app: {
version?: string;
time?: number;
@@ -102,6 +105,7 @@ export const useSettingStore = defineStore({
menus: [],
},
suiteSetting: { enabled: false },
inviteSetting: { enabled: false },
inited: false,
app: {
version: "",
@@ -196,6 +200,9 @@ export const useSettingStore = defineStore({
// @ts-ignore
return this.suiteSetting?.enabled === true;
},
isInviteCommissionEnabled(): boolean {
return this.isComm && this.inviteSetting?.enabled === true;
},
},
actions: {
checkPlus() {
@@ -215,6 +222,7 @@ export const useSettingStore = defineStore({
merge(this.plusInfo, allSettings.plusInfo || {});
merge(this.headerMenus, allSettings.headerMenus || {});
merge(this.suiteSetting, allSettings.suiteSetting || {});
merge(this.inviteSetting, allSettings.inviteSetting || {});
//@ts-ignore
this.initSiteInfo(allSettings.siteInfo || {});
this.initAppInfo(allSettings.app || {});
@@ -4,6 +4,7 @@ export interface RegisterReq {
username: string;
password: string;
confirmPassword: string;
inviteCode?: string;
}
/**
* @description: Login interface parameters
@@ -18,6 +19,7 @@ export interface SmsLoginReq {
phoneCode: string;
smsCode: string;
randomStr: string;
inviteCode?: string;
}
export interface ForgotPasswordReq {
@@ -0,0 +1,54 @@
const INVITE_STORAGE_KEY = "certd_invite_code";
const INVITE_TTL = 3 * 24 * 60 * 60 * 1000;
export type InviteCache = {
code: string;
expiresAt: number;
};
function normalizeInviteCode(code?: string | null) {
return code?.trim().toUpperCase();
}
export const inviteUtils = {
save(code?: string | null) {
const normalized = normalizeInviteCode(code);
if (!normalized) {
return;
}
const cache: InviteCache = {
code: normalized,
expiresAt: Date.now() + INVITE_TTL,
};
localStorage.setItem(INVITE_STORAGE_KEY, JSON.stringify(cache));
},
get() {
const text = localStorage.getItem(INVITE_STORAGE_KEY);
if (!text) {
return "";
}
try {
const cache = JSON.parse(text) as InviteCache;
if (!cache.code || !cache.expiresAt || cache.expiresAt < Date.now()) {
localStorage.removeItem(INVITE_STORAGE_KEY);
return "";
}
return cache.code;
} catch (e) {
localStorage.removeItem(INVITE_STORAGE_KEY);
return "";
}
},
captureFromLocation() {
const hashQuery = window.location.hash?.split("?")[1] || "";
const search = window.location.search?.replace(/^\?/, "") || "";
const hashParams = new URLSearchParams(hashQuery);
const searchParams = new URLSearchParams(search);
const code = hashParams.get("inviteCode") || searchParams.get("inviteCode");
if (code) {
this.save(code);
}
},
};
@@ -0,0 +1,13 @@
import { request } from "/@/api/service";
export async function GetMyInvite() {
return await request({ url: "/invite/my", method: "post" });
}
export async function GetInvitees(query: any) {
return await request({ url: "/invite/invitees/page", method: "post", data: query });
}
export async function GetCommissionLogs(query: any) {
return await request({ url: "/invite/commission/page", method: "post", data: query });
}
@@ -0,0 +1,34 @@
import { CreateCrudOptionsProps, CreateCrudOptionsRet, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import * as api from "./api";
export default function (): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetInvitees(query);
};
return {
crudOptions: {
request: { pageRequest },
actionbar: { show: false },
toolbar: { show: false },
rowHandle: { show: false },
columns: {
inviteeUserId: {
title: "被邀请人ID",
type: "number",
column: { width: 140 },
},
inviteCode: {
title: "邀请码",
type: "text",
column: { width: 160 },
},
createTime: {
title: "邀请时间",
type: "datetime",
column: { width: 180 },
},
},
},
};
}
@@ -0,0 +1,59 @@
import { CreateCrudOptionsRet, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import * as api from "./api";
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
export default function (): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetCommissionLogs(query);
};
return {
crudOptions: {
request: { pageRequest },
actionbar: { show: false },
toolbar: { show: false },
rowHandle: { show: false },
columns: {
type: {
title: "类型",
type: "dict-select",
dict: dict({
data: [{ label: "佣金入账", value: "commission", color: "success" }],
}),
column: { width: 130 },
},
amount: {
title: "金额",
type: "number",
column: {
width: 120,
component: { name: PriceInput, vModel: "modelValue", edit: false },
},
},
inviteeUserDisplay: {
title: "被邀请用户",
type: "text",
column: { width: 150 },
},
consumeAmount: {
title: "消费金额",
type: "number",
column: {
width: 120,
component: { name: PriceInput, vModel: "modelValue", edit: false },
},
},
remark: {
title: "备注",
type: "text",
column: { minWidth: 220 },
},
createTime: {
title: "时间",
type: "datetime",
column: { width: 180 },
},
},
},
};
}
@@ -0,0 +1,137 @@
<template>
<fs-page class="page-invite">
<template #header>
<div class="title">邀请返佣</div>
</template>
<div v-if="loaded && enabled" class="invite-body">
<div class="invite-link-row flex-o">
<span class="label">邀请码</span>
<fs-copyable v-model="inviteInfo.inviteCode" />
</div>
<div class="invite-link-row flex-o mt-10">
<span class="label">邀请链接</span>
<fs-copyable v-model="inviteInfo.inviteLink" />
</div>
<a-tabs v-model:active-key="activeTab" class="invite-tabs mt-6">
<a-tab-pane key="invitees" tab="邀请成功">
<fs-crud v-if="activeTab === 'invitees'" ref="inviteesCrudRef" class="invite-crud" v-bind="inviteesCrudBinding" />
</a-tab-pane>
<a-tab-pane key="logs" tab="佣金记录">
<fs-crud v-if="activeTab === 'logs'" ref="logsCrudRef" class="invite-crud" v-bind="logsCrudBinding" />
</a-tab-pane>
</a-tabs>
</div>
<a-empty v-else-if="loaded" description="邀请返佣未开启" />
</fs-page>
</template>
<script lang="ts" setup>
import { computed, nextTick, onActivated, onMounted, reactive, ref } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import * as api from "./api";
import createInviteesCrudOptions from "./crud-invitees";
import createLogsCrudOptions from "./crud-logs";
import { useSettingStore } from "/@/store/settings";
defineOptions({ name: "InviteCommission" });
const settingStore = useSettingStore();
const enabled = computed(() => settingStore.isInviteCommissionEnabled);
const activeTab = ref("invitees");
const inviteInfo = reactive<any>({ inviteCode: "", inviteLink: "" });
const loaded = ref(false);
const { crudBinding: inviteesCrudBinding, crudExpose: inviteesCrudExpose, crudRef: inviteesCrudRef } = useFs({ createCrudOptions: createInviteesCrudOptions });
const { crudBinding: logsCrudBinding, crudExpose: logsCrudExpose, crudRef: logsCrudRef } = useFs({ createCrudOptions: createLogsCrudOptions });
async function loadMyInvite() {
const res: any = await api.GetMyInvite();
inviteInfo.inviteCode = res.inviteCode;
inviteInfo.inviteLink = res.inviteLink;
}
async function refreshActiveList() {
if (activeTab.value === "invitees") {
await inviteesCrudExpose.doRefresh();
} else if (activeTab.value === "logs") {
await logsCrudExpose.doRefresh();
}
}
async function refreshInvitePage(refreshAll = false) {
await settingStore.initOnce();
loaded.value = true;
if (!enabled.value) {
return;
}
await loadMyInvite();
await nextTick();
if (refreshAll) {
await Promise.all([inviteesCrudExpose.doRefresh(), logsCrudExpose.doRefresh()]);
return;
}
await refreshActiveList();
}
onMounted(async () => {
await refreshInvitePage(true);
});
onActivated(async () => {
if (!loaded.value) {
return;
}
await refreshInvitePage();
});
</script>
<style lang="less">
.page-invite {
display: flex;
min-height: 0;
.fs-page-content {
display: flex;
min-height: 0;
}
.invite-body {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
padding: 20px;
}
.invite-tabs {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
}
.ant-tabs-content-holder,
.ant-tabs-content,
.ant-tabs-tabpane {
display: flex;
flex: 1;
min-height: 0;
}
.ant-tabs-tabpane {
flex-direction: column;
}
.invite-crud {
flex: 1;
min-height: 0;
}
.label {
width: 80px;
flex: none;
text-align: right;
margin-right: 8px;
}
}
</style>
@@ -46,6 +46,7 @@ export type TradeCreateReq = {
duration: number;
num: number;
payType: string;
useRebateBalance?: boolean;
};
export async function TradeCreate(form: TradeCreateReq) {
@@ -8,7 +8,7 @@
<a-col :span="24">
<a-card>
<div class="suite-intro-box">
<div>{{ buyHelperText }}</div>
<div>说明 同一时间只有最新购买的一个套餐生效 可以购买多个加量包加量包立即生效 套餐和加量包内的数量可以叠加</div>
<div v-if="suiteIntro" v-html="suiteIntro"></div>
</div>
</a-card>
@@ -31,7 +31,7 @@
</template>
<script lang="ts" setup>
import { computed, ref } from "vue";
import { ref } from "vue";
import * as api from "./api";
import ProductInfo from "/@/views/certd/suite/product-info.vue";
import OrderModal from "/@/views/certd/suite/order-modal.vue";
@@ -55,17 +55,9 @@ async function doOrder(req: any) {
}
const suiteIntro = ref("");
const allowSuiteStack = ref(false);
const buyHelperText = computed(() => {
if (allowSuiteStack.value) {
return "说明:可以购买多个套餐和加量包,套餐和加量包内的数量可以叠加";
}
return "说明:① 同一时间只有最新购买的一个套餐生效;② 可以购买多个加量包,加量包立即生效;③ 套餐和加量包内的数量可以叠加";
});
async function loadSuiteIntro() {
const res = await api.GetSuiteSetting();
suiteIntro.value = res.intro;
allowSuiteStack.value = !!res.allowSuiteStack;
}
loadSuiteIntro();
</script>
@@ -28,10 +28,19 @@
<span class="label">{{ $t("certd.order.price") }}</span>
<price-input :edit="false" :model-value="durationSelected.price"></price-input>
</div>
<div v-if="durationSelected.price > 0 && wallet.availableAmount > 0" class="flex-o mt-5">
<span class="label">返利抵扣</span>
<a-switch v-model:checked="formRef.useRebateBalance" />
<span class="ml-10">可用 {{ amountToYuan(wallet.availableAmount) }} 预计抵扣 {{ amountToYuan(expectedRebateAmount) }} </span>
</div>
<div v-if="durationSelected.price > 0 && formRef.useRebateBalance" class="flex-o mt-5">
<span class="label">还需支付</span>
<span class="color-red">{{ amountToYuan(expectedThirdPartyAmount) }} </span>
</div>
<div class="flex-o mt-5">
<span class="label">{{ $t("certd.order.paymentMethod") }}</span>
<div v-if="durationSelected.price === 0">{{ $t("certd.order.free") }}</div>
<div v-if="durationSelected.price === 0 || expectedThirdPartyAmount === 0">{{ $t("certd.order.free") }}</div>
<fs-dict-select v-else v-model:value="formRef.payType" :dict="paymentsDictRef" style="width: 200px"> </fs-dict-select>
</div>
</div>
@@ -39,7 +48,7 @@
</template>
<script setup lang="tsx">
import { ref } from "vue";
import { computed, ref } from "vue";
import { GetPaymentTypes, OrderModalOpenReq, TradeCreate } from "/@/views/certd/suite/api";
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
@@ -49,11 +58,14 @@ import DurationValue from "/@/views/sys/suite/product/duration-value.vue";
import { useRouter } from "vue-router";
import qrcode from "qrcode";
import * as api from "/@/views/certd/suite/api";
import { GetMyInvite } from "/@/views/certd/invite/api";
import { util } from "/@/utils";
const openRef = ref(false);
const product = ref<any>(null);
const formRef = ref<any>({});
const durationSelected = ref<any>(null);
const wallet = ref<any>({ availableAmount: 0 });
async function open(opts: OrderModalOpenReq) {
openRef.value = true;
@@ -63,6 +75,13 @@ async function open(opts: OrderModalOpenReq) {
formRef.value.productId = opts.product.id;
formRef.value.duration = opts.duration;
formRef.value.num = opts.num ?? 1;
formRef.value.useRebateBalance = false;
try {
const inviteInfo: any = await GetMyInvite();
wallet.value = inviteInfo.wallet || { availableAmount: 0 };
} catch (e) {
wallet.value = { availableAmount: 0 };
}
}
const paymentsDictRef = dict({
async getData() {
@@ -77,6 +96,21 @@ const paymentsDictRef = dict({
const router = useRouter();
const expectedRebateAmount = computed(() => {
if (!formRef.value.useRebateBalance) {
return 0;
}
return Math.min(wallet.value.availableAmount || 0, durationSelected.value?.price || 0);
});
const expectedThirdPartyAmount = computed(() => {
return Math.max(0, (durationSelected.value?.price || 0) - expectedRebateAmount.value);
});
function amountToYuan(amount: number) {
return util.amount.toYuan(amount || 0);
}
async function orderCreate() {
if (durationSelected.value.price === 0) {
//0
@@ -93,7 +127,7 @@ async function orderCreate() {
return;
}
if (!formRef.value.payType) {
if (expectedThirdPartyAmount.value > 0 && !formRef.value.payType) {
notification.error({
message: "请选择支付方式",
});
@@ -104,8 +138,17 @@ async function orderCreate() {
duration: formRef.value.duration,
num: formRef.value.num ?? 1,
payType: formRef.value.payType,
useRebateBalance: formRef.value.useRebateBalance,
});
if (paymentReq.paid) {
notification.success({
message: "套餐购买成功",
});
openRef.value = false;
return;
}
async function onPaid() {
openRef.value = false;
router.push({
@@ -151,6 +151,30 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
},
},
rebateAmount: {
title: "返利抵扣",
type: "number",
column: {
width: 110,
component: {
name: PriceInput,
vModel: "modelValue",
edit: false,
},
},
},
thirdPartyPayAmount: {
title: "实付金额",
type: "number",
column: {
width: 110,
component: {
name: PriceInput,
vModel: "modelValue",
edit: false,
},
},
},
status: {
title: "状态",
search: { show: true },
@@ -177,6 +201,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
{ label: "支付宝", value: "alipay" },
{ label: "微信", value: "wxpay" },
{ label: "免费", value: "free" },
{ label: "返利余额", value: "rebate" },
],
}),
column: {
@@ -0,0 +1,21 @@
import { request } from "/@/api/service";
export async function GetWalletSummary() {
return await request({ url: "/wallet/summary", method: "post" });
}
export async function GetWithdrawSetting() {
return await request({ url: "/wallet/withdraw/setting/get", method: "post" });
}
export async function SaveWithdrawSetting(data: any) {
return await request({ url: "/wallet/withdraw/setting/save", method: "post", data });
}
export async function ApplyWithdraw(amount: number) {
return await request({ url: "/wallet/withdraw/apply", method: "post", data: { amount } });
}
export async function GetWithdraws(query: any) {
return await request({ url: "/wallet/withdraw/page", method: "post", data: query });
}
@@ -0,0 +1,56 @@
import { CreateCrudOptionsRet, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import * as api from "./api";
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
export default function (): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetWithdraws(query);
};
return {
crudOptions: {
request: { pageRequest },
actionbar: { show: false },
toolbar: { show: false },
rowHandle: { show: false },
columns: {
amount: {
title: "金额",
type: "number",
column: {
width: 120,
component: { name: PriceInput, vModel: "modelValue", edit: false },
},
},
status: {
title: "状态",
type: "dict-select",
dict: dict({
data: [
{ label: "待审核", value: "pending", color: "warning" },
{ label: "已通过", value: "approved", color: "success" },
{ label: "已拒绝", value: "rejected", color: "error" },
],
}),
column: { width: 110 },
},
channel: {
title: "提现渠道",
type: "dict-select",
dict: dict({
data: [
{ label: "支付宝", value: "alipay" },
{ label: "银行卡", value: "bank" },
],
}),
column: { width: 110 },
},
realName: { title: "真实姓名", type: "text", column: { width: 120 } },
account: { title: "收款账号", type: "text", column: { width: 180 } },
bankName: { title: "开户银行", type: "text", column: { width: 160 } },
auditRemark: { title: "审核备注", type: "text", column: { minWidth: 180 } },
createTime: { title: "申请时间", type: "datetime", column: { width: 180 } },
},
},
};
}
@@ -0,0 +1,174 @@
<template>
<fs-page class="page-wallet">
<template #header>
<div class="title">我的钱包</div>
</template>
<div class="wallet-body">
<a-row :gutter="16" class="wallet-summary">
<a-col :span="6">
<a-statistic title="可用余额" :value="amountToYuan(summary.availableAmount)" suffix="元" />
</a-col>
<a-col :span="6">
<a-statistic title="冻结余额" :value="amountToYuan(summary.frozenAmount)" suffix="元" />
</a-col>
<a-col :span="6">
<a-statistic title="累计收入" :value="amountToYuan(summary.totalIncomeAmount)" suffix="元" />
</a-col>
<a-col :span="6">
<a-statistic title="累计提现" :value="amountToYuan(summary.totalWithdrawAmount)" suffix="元" />
</a-col>
</a-row>
<div class="wallet-actions">
<a-space>
<a-button type="primary" @click="openWithdrawSetting">提现设置</a-button>
<a-input-number v-model:value="withdrawAmountYuan" :min="0" addon-before="提现金额" addon-after="" />
<a-button @click="applyWithdraw">申请提现</a-button>
</a-space>
</div>
<fs-crud ref="withdrawCrudRef" class="wallet-crud" v-bind="withdrawCrudBinding" />
</div>
</fs-page>
</template>
<script lang="ts" setup>
import { onActivated, onMounted, reactive, ref } from "vue";
import { compute, dict, useFs } from "@fast-crud/fast-crud";
import { notification } from "ant-design-vue";
import * as api from "./api";
import createWithdrawCrudOptions from "./crud-withdraw";
import { util } from "/@/utils";
import { useFormDialog } from "/@/use/use-dialog";
defineOptions({ name: "MyWallet" });
const summary = reactive<any>({ availableAmount: 0, frozenAmount: 0, totalIncomeAmount: 0, totalWithdrawAmount: 0 });
const withdrawAmountYuan = ref(0);
const loaded = ref(false);
const { openFormDialog } = useFormDialog();
const { crudBinding: withdrawCrudBinding, crudExpose: withdrawCrudExpose, crudRef: withdrawCrudRef } = useFs({ createCrudOptions: createWithdrawCrudOptions });
function amountToYuan(amount: number) {
return util.amount.toYuan(amount || 0);
}
async function loadWalletSummary() {
const res: any = await api.GetWalletSummary();
Object.assign(summary, res || {});
}
async function openWithdrawSetting() {
const setting: any = await api.GetWithdrawSetting();
const initialForm = Object.assign({ channel: "alipay", realName: "", account: "", bankName: "" }, setting || {});
await openFormDialog({
title: "提现设置",
wrapper: {
width: 560,
},
initialForm,
columns: {
channel: {
title: "提现渠道",
type: "dict-radio",
dict: dict({
data: [
{ label: "支付宝", value: "alipay" },
{ label: "银行卡", value: "bank" },
],
}),
form: {
col: { span: 24 },
rules: [{ required: true, message: "请选择提现渠道" }],
},
},
realName: {
title: "真实姓名",
type: "text",
form: {
col: { span: 24 },
rules: [{ required: true, message: "请输入真实姓名" }],
},
},
account: {
title: "收款账号",
type: "text",
form: {
col: { span: 24 },
rules: [{ required: true, message: "请输入收款账号" }],
},
},
bankName: {
title: "开户银行",
type: "text",
form: {
col: { span: 24 },
show: compute(({ form }) => form.channel === "bank"),
rules: [{ required: compute(({ form }) => form.channel === "bank"), message: "请输入开户银行" }],
},
},
},
async onSubmit(form: any) {
await api.SaveWithdrawSetting(form);
notification.success({ message: "保存成功" });
},
});
}
async function applyWithdraw() {
await api.ApplyWithdraw(util.amount.toCent(withdrawAmountYuan.value || 0));
withdrawAmountYuan.value = 0;
await loadWalletSummary();
await withdrawCrudExpose.doRefresh();
notification.success({ message: "提现申请已提交" });
}
async function refreshWalletPage() {
await loadWalletSummary();
await withdrawCrudExpose.doRefresh();
loaded.value = true;
}
onMounted(refreshWalletPage);
onActivated(async () => {
if (!loaded.value) {
return;
}
await refreshWalletPage();
});
</script>
<style lang="less">
.page-wallet {
display: flex;
min-height: 0;
.fs-page-content {
display: flex;
min-height: 0;
}
.wallet-body {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
padding: 20px;
}
.wallet-summary,
.wallet-actions {
flex: none;
}
.wallet-actions {
margin: 16px 0 10px;
}
.wallet-crud {
flex: 1;
min-height: 0;
}
}
</style>
@@ -204,7 +204,6 @@ const hasNewVersion = computed(() => {
return isNewVersion(version.value, latestVersion.value);
});
async function loadLatestVersion() {
// version.value = settingsStore.app.version; //
latestVersion.value = await api.GetLatestVersion();
console.log("latestVersion", latestVersion.value);
@@ -4,14 +4,8 @@
<a-popover>
<template #content>
<div style="width: 300px">
<div v-if="hiddenSuiteList.length > 0 || detail.addonList.length > 0" class="flex flex-wrap">
<a-tag v-for="(item, index) of hiddenSuiteList" :key="`suite-${index}`" color="green" class="pointer flex-o m-1">
<span class="mr-5">
{{ item.title }}
</span>
<span>(<expires-time-text :value="item.expiresTime" />)</span>
</a-tag>
<a-tag v-for="(item, index) of detail.addonList" :key="`addon-${index}`" color="green" class="pointer flex-o m-1">
<div v-if="detail.addonList.length > 0" class="flex flex-wrap">
<a-tag v-for="(item, index) of detail.addonList" :key="index" color="green" class="pointer flex-o m-1">
<span class="mr-5">
{{ item.title }}
</span>
@@ -43,19 +37,19 @@
</div>
<div class="flex-between mt-5">
<div class="flex-o"><fs-icon icon="ant-design:check-outlined" class="color-green mr-5" /> 监控站点数</div>
<suite-value :model-value="detail.monitorCount.max" :used="detail.monitorCount.used" unit="" />
<suite-value :model-value="detail.monitorCount.max" :used="detail.monitorCount.used" unit="" />
</div>
</div>
</template>
<div class="flex-o">
<fs-icon icon="ant-design:gift-outlined" class="color-green mr-5" />
<a-tag v-if="currentSuite" color="green" class="pointer flex-o">
<a-tag v-for="(item, index) of detail.suiteList" :key="index" color="green" class="pointer flex-o">
<span class="mr-5">
{{ currentSuite.title }}
{{ item.title }}
</span>
<span>(<expires-time-text :value="currentSuite.expiresTime" />)</span>
<span v-if="hiddenCount > 0" class="ml-5">+{{ hiddenCount }}</span>
<span>(<expires-time-text :value="item.expiresTime" />)</span>
</a-tag>
<a-tag v-if="detail.addonList.length > 0" color="green" class="pointer flex-o">加量包+{{ detail.addonList.length }}</a-tag>
<div v-if="detail.suites?.length === 0" class="flex-o ml-5">暂无套餐 <a-button class="ml-5" type="primary" size="small" @click="goBuy">去购买</a-button></div>
</div>
</a-popover>
@@ -65,7 +59,7 @@
<script lang="ts" setup>
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
import { computed, ref } from "vue";
import { ref } from "vue";
import ExpiresTimeText from "/@/components/expires-time-text.vue";
import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api";
import { FsIcon } from "@fast-crud/fast-crud";
@@ -77,10 +71,6 @@ defineOptions({
const detail = ref<SuiteDetail>({});
const currentSuite = computed(() => detail.value.suiteList?.[0]);
const hiddenSuiteList = computed(() => detail.value.suiteList?.slice(1) || []);
const hiddenCount = computed(() => hiddenSuiteList.value.length + (detail.value.addonList?.length || 0));
async function loadSuiteDetail() {
detail.value = await mySuiteApi.SuiteDetailGet();
const suites = detail.value.suites.filter(item => item.productType === "suite");
@@ -1,3 +1,4 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div class="main login-page">
<a-form v-if="!twoFactor.loginId" ref="formRef" class="user-layout-login" name="custom-validation" :model="formState" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed">
@@ -108,6 +109,7 @@ import * as oauthApi from "../oauth/api";
import { notification } from "ant-design-vue";
import { request } from "/src/api/service";
import * as UserApi from "/src/store/user/api.user";
import { inviteUtils } from "/@/utils/util.invite";
const { t } = useI18n();
const route = useRoute();
@@ -136,6 +138,7 @@ const formState = reactive({
smsCode: "",
captcha: null,
smsCaptcha: null,
inviteCode: inviteUtils.get(),
});
const rules = {
@@ -262,6 +265,7 @@ onMounted(() => {});
.input-right {
width: 160px;
margin-left: 10px;
background: #cfcfcf !important;
}
.forge-password {
@@ -7,7 +7,7 @@
<passkey-login></passkey-login>
<template v-for="item in oauthProviderList" :key="buildProviderKey(item)">
<div v-if="item.addonId" class="oauth-icon-button pointer" @click="goOauthLogin(item)">
<div><fs-icon :icon="item.icon" class="text-40" /></div>
<div><fs-icon :icon="item.icon" class="text-blue-600 text-40" /></div>
<div class="ellipsis title" :title="item.addonTitle || item.title">{{ item.addonTitle || item.title }}</div>
</div>
</template>
@@ -125,6 +125,7 @@ async function goOauthLogin(item: OauthProviderItem) {
}
.fs-icon {
font-size: 36px;
color: #006be6;
margin: 0px !important;
}
}
@@ -78,6 +78,14 @@
</a-tab-pane>
</a-tabs>
<a-form-item v-if="registerType !== 'mobile'" has-feedback name="inviteCode" label="邀请码">
<a-input v-model:value="formState.inviteCode" placeholder="邀请码(选填)" size="large" autocomplete="off">
<template #prefix>
<fs-icon icon="ion:gift-outline"></fs-icon>
</template>
</a-input>
</a-form-item>
<a-form-item v-if="registerType !== 'mobile'">
<a-button type="primary" size="large" html-type="submit" class="login-button">注册</a-button>
</a-form-item>
@@ -97,6 +105,7 @@ import { useSettingStore } from "/@/store/settings";
import { notification } from "ant-design-vue";
import CaptchaInput from "/@/components/captcha/captcha-input.vue";
import { useRouter } from "vue-router";
import { inviteUtils } from "/@/utils/util.invite";
export default defineComponent({
name: "RegisterPage",
components: { CaptchaInput, EmailCode },
@@ -125,6 +134,7 @@ export default defineComponent({
confirmPassword: "",
captcha: null,
captchaForEmail: null,
inviteCode: inviteUtils.get(),
});
const rules = {
@@ -213,6 +223,7 @@ export default defineComponent({
email: formState.email,
captcha: registerType.value === "email" ? formState.captchaForEmail : formState.captcha,
validateCode: formState.validateCode,
inviteCode: formState.inviteCode,
}) as any
);
} finally {
@@ -0,0 +1,21 @@
import { request } from "/@/api/service";
export async function GetSettings() {
return await request({ url: "/sys/invite/settings/get", method: "post" });
}
export async function SaveSettings(data: any) {
return await request({ url: "/sys/invite/settings/save", method: "post", data });
}
export async function GetWithdraws(query: any) {
return await request({ url: "/sys/wallet/withdraw/page", method: "post", data: query });
}
export async function ApproveWithdraw(id: number, remark?: string) {
return await request({ url: "/sys/wallet/withdraw/approve", method: "post", data: { id, remark } });
}
export async function RejectWithdraw(id: number, remark: string) {
return await request({ url: "/sys/wallet/withdraw/reject", method: "post", data: { id, remark } });
}
@@ -0,0 +1,135 @@
import { compute, CreateCrudOptionsProps, CreateCrudOptionsRet, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { Modal, notification } from "ant-design-vue";
import * as api from "./api";
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
import { useFormDialog } from "/@/use/use-dialog";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { openFormDialog } = useFormDialog();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetWithdraws(query);
};
async function approve(row: any) {
Modal.confirm({
title: "确认提现已线下打款?",
async onOk() {
await api.ApproveWithdraw(row.id);
await crudExpose.doRefresh();
notification.success({ message: "已审核通过" });
},
});
}
async function reject(row: any) {
await openFormDialog({
title: "拒绝提现申请",
wrapper: {
width: 520,
},
initialForm: {
remark: "",
},
columns: {
remark: {
title: "拒绝理由",
type: "textarea",
form: {
col: {
span: 24,
},
component: {
name: "a-textarea",
vModel: "value",
rows: 4,
placeholder: "请填写拒绝理由",
},
rules: [{ required: true, message: "请填写拒绝理由" }],
},
},
},
async onSubmit(form: any) {
const remark = form.remark.trim();
if (!remark) {
notification.error({ message: "请填写拒绝理由" });
throw new Error("请填写拒绝理由");
}
await api.RejectWithdraw(row.id, remark);
await crudExpose.doRefresh();
notification.success({ message: "已拒绝并退回余额" });
},
});
}
return {
crudOptions: {
request: { pageRequest },
actionbar: { show: false },
toolbar: { show: false },
rowHandle: {
width: 150,
fixed: "right",
buttons: {
view: { show: false },
edit: { show: false },
copy: { show: false },
remove: { show: false },
approve: {
text: "通过",
type: "link",
show: compute(({ row }) => row.status === "pending"),
click: ({ row }) => approve(row),
},
reject: {
text: "拒绝",
type: "link",
show: compute(({ row }) => row.status === "pending"),
click: ({ row }) => reject(row),
},
},
},
columns: {
userId: { title: "用户ID", type: "number", search: { show: true }, column: { width: 100 } },
amount: {
title: "金额",
type: "number",
column: {
width: 120,
component: { name: PriceInput, vModel: "modelValue", edit: false },
},
},
status: {
title: "状态",
type: "dict-select",
search: { show: true },
dict: dict({
data: [
{ label: "待审核", value: "pending", color: "warning" },
{ label: "已通过", value: "approved", color: "success" },
{ label: "已拒绝", value: "rejected", color: "error" },
],
}),
column: { width: 110 },
},
channel: {
title: "提现渠道",
type: "dict-select",
search: { show: true },
dict: dict({
data: [
{ label: "支付宝", value: "alipay" },
{ label: "银行卡", value: "bank" },
],
}),
column: { width: 110 },
},
realName: { title: "真实姓名", type: "text", search: { show: true }, column: { width: 120 } },
account: { title: "收款账号", type: "text", column: { width: 180 } },
bankName: { title: "开户银行", type: "text", column: { width: 160 } },
auditRemark: { title: "审核备注", type: "text", column: { minWidth: 180 } },
createTime: { title: "申请时间", type: "datetime", column: { width: 180 } },
},
},
};
}
@@ -0,0 +1,74 @@
<template>
<fs-page class="page-sys-invite-setting">
<template #header>
<div class="title">邀请返佣设置</div>
</template>
<div class="page-body">
<a-form ref="formRef" :model="settings" :label-col="{ style: { width: '140px' } }" class="settings-form">
<a-form-item label="开启返佣" name="enabled">
<a-switch v-model:checked="settings.enabled" />
</a-form-item>
<a-form-item label="返佣比例" name="commissionRate">
<a-input-number v-model:value="settings.commissionRate" :min="0" :max="100" addon-after="%" />
</a-form-item>
<a-form-item label="最低提现金额" name="minWithdrawAmountYuan">
<a-input-number v-model:value="settings.minWithdrawAmountYuan" :min="0" addon-after="" />
</a-form-item>
<a-form-item label="提现渠道" name="withdrawChannels">
<a-checkbox-group v-model:value="settings.withdrawChannels" :options="withdrawChannelOptions" />
</a-form-item>
<a-form-item label=" ">
<a-button type="primary" @click="saveSettings">保存设置</a-button>
</a-form-item>
</a-form>
</div>
</fs-page>
</template>
<script lang="ts" setup>
import { onMounted, reactive } from "vue";
import { notification } from "ant-design-vue";
import * as api from "./api";
import { util } from "/@/utils";
import { useSettingStore } from "/@/store/settings";
defineOptions({ name: "SysInviteCommissionSetting" });
const settings = reactive<any>({ enabled: false, commissionRate: 0, minWithdrawAmountYuan: 0, withdrawChannels: ["alipay", "bank"] });
const withdrawChannelOptions = [
{ label: "支付宝", value: "alipay" },
{ label: "银行卡", value: "bank" },
];
async function loadSettings() {
const data: any = await api.GetSettings();
settings.enabled = !!data?.enabled;
settings.commissionRate = data?.commissionRate || 0;
settings.minWithdrawAmountYuan = util.amount.toYuan(data?.minWithdrawAmount || 0);
settings.withdrawChannels = data?.withdrawChannels?.length ? data.withdrawChannels : ["alipay", "bank"];
}
async function saveSettings() {
await api.SaveSettings({
enabled: settings.enabled,
commissionRate: settings.commissionRate || 0,
minWithdrawAmount: util.amount.toCent(settings.minWithdrawAmountYuan || 0),
withdrawChannels: settings.withdrawChannels || [],
});
await useSettingStore().loadSysSettings();
notification.success({ message: "保存成功" });
}
onMounted(loadSettings);
</script>
<style lang="less">
.page-sys-invite-setting {
.page-body {
padding: 20px;
}
.settings-form {
max-width: 720px;
}
}
</style>
@@ -0,0 +1,25 @@
<template>
<fs-page class="page-sys-invite-withdraw">
<template #header>
<div class="title">提现申请记录</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding" />
</fs-page>
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud-withdraw";
defineOptions({ name: "SysInviteWithdraw" });
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(() => {
crudExpose.doRefresh();
});
</script>
@@ -1,5 +1,5 @@
<template>
<a-tag color="green"> {{ durationDict.dataMap[modelValue]?.label || modelValue + "天" }}</a-tag>
<a-tag color="green"> {{ durationDict.dataMap[modelValue]?.label }}</a-tag>
</template>
<script lang="ts" setup>
@@ -21,11 +21,6 @@
<div class="helper">不建议设置免费套餐可以在下方配置注册赠送套餐或者在用户套餐管理中手动赠送套餐</div>
</a-form-item>
<a-form-item label="套餐支持叠加" name="allowSuiteStack">
<a-switch v-model:checked="formState.allowSuiteStack" />
<div class="helper">默认只有一个套餐生效开启此开关可以让多个套餐可以叠加加量包无论是否开启此开关都可以叠加</div>
</a-form-item>
<a-form-item label="注册赠送套餐" name="registerGift">
<suite-duration-selector ref="suiteDurationSelectedRef" v-model="formState.registerGift"></suite-duration-selector>
<div class="helper">添加套餐后再选择</div>
@@ -78,7 +73,6 @@ const formRef = ref<any>(null);
const formState = reactive<
Partial<{
enabled: boolean;
allowSuiteStack: boolean;
registerGift?: {
productId?: number;
duration?: number;
@@ -174,6 +174,30 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
},
},
rebateAmount: {
title: "返利抵扣",
type: "number",
column: {
width: 110,
component: {
name: PriceInput,
vModel: "modelValue",
edit: false,
},
},
},
thirdPartyPayAmount: {
title: "实付金额",
type: "number",
column: {
width: 110,
component: {
name: PriceInput,
vModel: "modelValue",
edit: false,
},
},
},
status: {
title: "状态",
search: { show: true },
@@ -200,6 +224,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
{ label: "支付宝", value: "alipay" },
{ label: "微信", value: "wxpay" },
{ label: "免费", value: "free" },
{ label: "返利余额", value: "rebate" },
],
}),
column: {
@@ -123,15 +123,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
value: "id",
label: "nickName",
}),
editForm: {
component: {
disabled: true,
},
},
form: {
show: true,
component: {
disabled: false,
disabled: true,
crossPage: true,
multiple: false,
select: {
@@ -175,6 +170,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
productType: {
title: t("certd.type"),
type: "dict-select",
editForm: {
component: {
disabled: true,
},
},
dict: dict({
data: [
{ label: t("certd.package"), value: "suite", color: "green" },
@@ -182,7 +182,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
],
}),
form: {
show: false,
show: true,
component: {
disabled: true,
},
@@ -205,9 +205,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
"content.maxDomainCount": {
title: t("certd.domain_count"),
type: "text",
addForm: {
show: false,
},
form: {
key: ["content", "maxDomainCount"],
component: {
@@ -230,9 +227,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
"content.maxWildcardDomainCount": {
title: t("certd.wildcardDomainCountPart"),
type: "text",
addForm: {
show: false,
},
form: {
key: ["content", "maxWildcardDomainCount"],
component: {
@@ -255,9 +249,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
"content.maxPipelineCount": {
title: t("certd.pipeline_count"),
type: "text",
addForm: {
show: false,
},
form: {
key: ["content", "maxPipelineCount"],
component: {
@@ -280,9 +271,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
"content.maxDeployCount": {
title: t("certd.deploy_count"),
type: "text",
addForm: {
show: false,
},
form: {
key: ["content", "maxDeployCount"],
component: {
@@ -308,9 +296,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
"content.maxMonitorCount": {
title: t("certd.monitor_count"),
type: "text",
addForm: {
show: false,
},
form: {
key: ["content", "maxMonitorCount"],
component: {
@@ -332,10 +317,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
duration: {
title: t("certd.duration"),
type: "number",
addForm: {
show: false,
},
type: "text",
form: {
rules: [{ required: true, message: t("certd.field_required") }],
},
@@ -381,9 +363,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
expiresTime: {
title: t("certd.expires_time"),
type: "date",
addForm: {
show: false,
},
form: {
valueBuilder: ({ value }) => {
return dayjs(value);
@@ -414,9 +393,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
{ label: t("certd.is_present_no"), value: false, color: "blue" },
],
}),
addForm: {
show: false,
},
form: {
value: true,
},
@@ -428,9 +404,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
deployCountUsed: {
title: t("certd.deploy_count_used"),
type: "number",
addForm: {
show: false,
},
form: {
value: 0,
rules: [{ required: true, message: t("certd.field_required") }],
-26
View File
@@ -3,32 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Bug Fixes
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
### Performance Improvements
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
* 修复暗黑模式下注册页面验证码看不清的问题 ([5ba33be](https://github.com/certd/certd/commit/5ba33be30f765f06cafbfcc04f5e25320db01449))
## [1.40.2](https://github.com/certd/certd/compare/v1.40.1...v1.40.2) (2026-05-19)
### Bug Fixes
* **certd-server:** 调整首页缓存控制头的判断逻辑 ([0499347](https://github.com/certd/certd/commit/0499347588ee544862420ab9a5afd2546d61bc6c))
### Performance Improvements
* **controller:** 更换版本获取源并添加版本标准化处理 ([cb08e06](https://github.com/certd/certd/commit/cb08e061d257ba23a0fefdbfb046a8c759def828))
## [1.40.1](https://github.com/certd/certd/compare/v1.40.0...v1.40.1) (2026-05-18)
### Bug Fixes
@@ -0,0 +1,88 @@
ALTER TABLE cd_trade ADD COLUMN rebate_amount bigint NOT NULL DEFAULT 0;
ALTER TABLE cd_trade ADD COLUMN third_party_pay_amount bigint NOT NULL DEFAULT 0;
CREATE TABLE `cd_invite_code`
(
`id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL,
`user_id` bigint,
`code` varchar(50),
`disabled` boolean NOT NULL DEFAULT false,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX `index_invite_code_user_id` ON `cd_invite_code` (`user_id`);
CREATE UNIQUE INDEX `index_invite_code_code` ON `cd_invite_code` (`code`);
CREATE TABLE `cd_invite_relation`
(
`id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL,
`inviter_user_id` bigint,
`invitee_user_id` bigint,
`invite_code` varchar(50),
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX `index_invite_relation_inviter` ON `cd_invite_relation` (`inviter_user_id`);
CREATE UNIQUE INDEX `index_invite_relation_invitee` ON `cd_invite_relation` (`invitee_user_id`);
CREATE TABLE `cd_user_wallet`
(
`id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL,
`user_id` bigint,
`available_amount` bigint NOT NULL DEFAULT 0,
`frozen_amount` bigint NOT NULL DEFAULT 0,
`total_income_amount` bigint NOT NULL DEFAULT 0,
`total_consumed_amount` bigint NOT NULL DEFAULT 0,
`total_withdraw_amount` bigint NOT NULL DEFAULT 0,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX `index_user_wallet_user_id` ON `cd_user_wallet` (`user_id`);
CREATE TABLE `cd_invite_commission_log`
(
`id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL,
`user_id` bigint,
`amount` bigint,
`trade_id` bigint,
`invitee_user_id` bigint,
`consume_amount` bigint NOT NULL DEFAULT 0,
`remark` varchar(2048),
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX `index_invite_log_user_id` ON `cd_invite_commission_log` (`user_id`);
CREATE TABLE `cd_user_wallet_log`
(
`id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL,
`user_id` bigint,
`type` varchar(50),
`amount` bigint,
`balance_after` bigint,
`trade_id` bigint,
`withdraw_id` bigint,
`remark` varchar(2048),
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX `index_user_wallet_log_user_id` ON `cd_user_wallet_log` (`user_id`);
CREATE TABLE `cd_user_wallet_withdraw`
(
`id` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL,
`user_id` bigint,
`amount` bigint,
`status` varchar(50),
`channel` varchar(50),
`real_name` varchar(100),
`account` varchar(200),
`bank_name` varchar(200),
`audit_user_id` bigint,
`audit_remark` varchar(2048),
`audit_time` bigint,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX `index_user_wallet_withdraw_user_id` ON `cd_user_wallet_withdraw` (`user_id`);
CREATE INDEX `index_user_wallet_withdraw_status` ON `cd_user_wallet_withdraw` (`status`);
@@ -0,0 +1,88 @@
ALTER TABLE cd_trade ADD COLUMN rebate_amount bigint NOT NULL DEFAULT 0;
ALTER TABLE cd_trade ADD COLUMN third_party_pay_amount bigint NOT NULL DEFAULT 0;
CREATE TABLE "cd_invite_code"
(
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY NOT NULL,
"user_id" bigint,
"code" varchar(50),
"disabled" boolean NOT NULL DEFAULT (false),
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE UNIQUE INDEX "index_invite_code_user_id" ON "cd_invite_code" ("user_id");
CREATE UNIQUE INDEX "index_invite_code_code" ON "cd_invite_code" ("code");
CREATE TABLE "cd_invite_relation"
(
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY NOT NULL,
"inviter_user_id" bigint,
"invitee_user_id" bigint,
"invite_code" varchar(50),
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_invite_relation_inviter" ON "cd_invite_relation" ("inviter_user_id");
CREATE UNIQUE INDEX "index_invite_relation_invitee" ON "cd_invite_relation" ("invitee_user_id");
CREATE TABLE "cd_user_wallet"
(
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY NOT NULL,
"user_id" bigint,
"available_amount" bigint NOT NULL DEFAULT 0,
"frozen_amount" bigint NOT NULL DEFAULT 0,
"total_income_amount" bigint NOT NULL DEFAULT 0,
"total_consumed_amount" bigint NOT NULL DEFAULT 0,
"total_withdraw_amount" bigint NOT NULL DEFAULT 0,
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE UNIQUE INDEX "index_user_wallet_user_id" ON "cd_user_wallet" ("user_id");
CREATE TABLE "cd_invite_commission_log"
(
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY NOT NULL,
"user_id" bigint,
"amount" bigint,
"trade_id" bigint,
"invitee_user_id" bigint,
"consume_amount" bigint NOT NULL DEFAULT 0,
"remark" varchar(2048),
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_invite_log_user_id" ON "cd_invite_commission_log" ("user_id");
CREATE TABLE "cd_user_wallet_log"
(
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY NOT NULL,
"user_id" bigint,
"type" varchar(50),
"amount" bigint,
"balance_after" bigint,
"trade_id" bigint,
"withdraw_id" bigint,
"remark" varchar(2048),
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_user_wallet_log_user_id" ON "cd_user_wallet_log" ("user_id");
CREATE TABLE "cd_user_wallet_withdraw"
(
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY NOT NULL,
"user_id" bigint,
"amount" bigint,
"status" varchar(50),
"channel" varchar(50),
"real_name" varchar(100),
"account" varchar(200),
"bank_name" varchar(200),
"audit_user_id" bigint,
"audit_remark" varchar(2048),
"audit_time" bigint,
"create_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_user_wallet_withdraw_user_id" ON "cd_user_wallet_withdraw" ("user_id");
CREATE INDEX "index_user_wallet_withdraw_status" ON "cd_user_wallet_withdraw" ("status");
@@ -0,0 +1,88 @@
ALTER TABLE cd_trade ADD COLUMN rebate_amount integer NOT NULL DEFAULT 0;
ALTER TABLE cd_trade ADD COLUMN third_party_pay_amount integer NOT NULL DEFAULT 0;
CREATE TABLE "cd_invite_code"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer,
"code" varchar(50),
"disabled" boolean NOT NULL DEFAULT (false),
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE UNIQUE INDEX "index_invite_code_user_id" ON "cd_invite_code" ("user_id");
CREATE UNIQUE INDEX "index_invite_code_code" ON "cd_invite_code" ("code");
CREATE TABLE "cd_invite_relation"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"inviter_user_id" integer,
"invitee_user_id" integer,
"invite_code" varchar(50),
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_invite_relation_inviter" ON "cd_invite_relation" ("inviter_user_id");
CREATE UNIQUE INDEX "index_invite_relation_invitee" ON "cd_invite_relation" ("invitee_user_id");
CREATE TABLE "cd_user_wallet"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer,
"available_amount" integer NOT NULL DEFAULT 0,
"frozen_amount" integer NOT NULL DEFAULT 0,
"total_income_amount" integer NOT NULL DEFAULT 0,
"total_consumed_amount" integer NOT NULL DEFAULT 0,
"total_withdraw_amount" integer NOT NULL DEFAULT 0,
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE UNIQUE INDEX "index_user_wallet_user_id" ON "cd_user_wallet" ("user_id");
CREATE TABLE "cd_invite_commission_log"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer,
"amount" integer,
"trade_id" integer,
"invitee_user_id" integer,
"consume_amount" integer NOT NULL DEFAULT 0,
"remark" varchar(2048),
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_invite_log_user_id" ON "cd_invite_commission_log" ("user_id");
CREATE TABLE "cd_user_wallet_log"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer,
"type" varchar(50),
"amount" integer,
"balance_after" integer,
"trade_id" integer,
"withdraw_id" integer,
"remark" varchar(2048),
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_user_wallet_log_user_id" ON "cd_user_wallet_log" ("user_id");
CREATE TABLE "cd_user_wallet_withdraw"
(
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer,
"amount" integer,
"status" varchar(50),
"channel" varchar(50),
"real_name" varchar(100),
"account" varchar(200),
"bank_name" varchar(200),
"audit_user_id" integer,
"audit_remark" varchar(2048),
"audit_time" integer,
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
);
CREATE INDEX "index_user_wallet_withdraw_user_id" ON "cd_user_wallet_withdraw" ("user_id");
CREATE INDEX "index_user_wallet_withdraw_status" ON "cd_user_wallet_withdraw" ("status");
@@ -21,10 +21,10 @@ input:
options:
- label: QQ
value: qq
icon: svg:icon-qq
icon: cib:tencent-qq:#007AFF
- label: 微信
value: wx
icon: svg:icon-wechat
icon: simple-icons:wechat:#34C759
- label: 支付宝
value: alipay
icon: simple-icons:alipay:#0099ff
@@ -1,96 +0,0 @@
showRunStrategy: false
default:
strategy:
runStrategy: 1
name: DeployCertToAliyunLive
title: 阿里云-部署至直播(Live
icon: svg:icon-aliyun
group: aliyun
desc: 部署证书到阿里云视频直播(Live)域名
needPlus: false
input:
cert:
title: 域名证书
helper: 请选择前置任务输出的域名证书
component:
name: output-selector
from:
- ':cert:'
- uploadCertToAliyun
template: false
required: true
order: 0
certDomains:
title: 当前证书域名
component:
name: cert-domains-getter
mergeScript: |2-
return {
component:{
inputKey: ctx.compute(({form})=>{
return form.cert
}),
}
}
template: false
required: false
order: 0
accessId:
title: Access授权
helper: 阿里云授权AccessKeyId、AccessKeySecret
component:
name: access-selector
type: aliyun
required: true
order: 0
endpoint:
title: 证书服务接入点
helper: 不会选就按默认
value: cas.aliyuncs.com
component:
name: a-select
options:
- value: cas.aliyuncs.com
label: 中国大陆
- value: cas.ap-southeast-1.aliyuncs.com
label: 新加坡
- value: cas.eu-central-1.aliyuncs.com
label: 德国(法兰克福)
required: true
order: 0
domainList:
title: 直播域名
component:
name: remote-select
vModel: value
mode: tags
type: plugin
typeName: DeployCertToAliyunLive
action: onGetDomainList
search: true
pager: true
multi: true
watches:
- certDomains
- accessId
- certDomains
- accessId
required: true
mergeScript: |2-
return {
component:{
form: ctx.compute(({form})=>{
return form
})
},
}
helper: 请选择要部署证书的直播域名
order: 0
output: {}
pluginType: deploy
type: builtIn
scriptFilePath: /plugins/plugin-aliyun/plugin/deploy-to-live/index.js
+14 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-server",
"version": "1.40.4",
"version": "1.40.1",
"description": "fast-server base midway",
"private": true,
"type": "module",
@@ -53,20 +53,20 @@
"@aws-sdk/client-sts": "^3.990.0",
"@azure/arm-dns": "^5.1.0",
"@azure/identity": "^4.13.1",
"@certd/acme-client": "^1.40.4",
"@certd/basic": "^1.40.4",
"@certd/commercial-core": "^1.40.4",
"@certd/acme-client": "^1.40.1",
"@certd/basic": "^1.40.1",
"@certd/commercial-core": "^1.40.1",
"@certd/cv4pve-api-javascript": "^8.4.2",
"@certd/jdcloud": "^1.40.4",
"@certd/lib-huawei": "^1.40.4",
"@certd/lib-k8s": "^1.40.4",
"@certd/lib-server": "^1.40.4",
"@certd/midway-flyway-js": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@certd/plugin-cert": "^1.40.4",
"@certd/plugin-lib": "^1.40.4",
"@certd/plugin-plus": "^1.40.4",
"@certd/plus-core": "^1.40.4",
"@certd/jdcloud": "^1.40.1",
"@certd/lib-huawei": "^1.40.1",
"@certd/lib-k8s": "^1.40.1",
"@certd/lib-server": "^1.40.1",
"@certd/midway-flyway-js": "^1.40.1",
"@certd/pipeline": "^1.40.1",
"@certd/plugin-cert": "^1.40.1",
"@certd/plugin-lib": "^1.40.1",
"@certd/plugin-plus": "^1.40.1",
"@certd/plus-core": "^1.40.1",
"@google-cloud/dns": "^5.3.1",
"@google-cloud/publicca": "^1.3.0",
"@huaweicloud/huaweicloud-sdk-cdn": "3.1.185",
@@ -1,11 +1,6 @@
export function shouldSetDefaultNoCache(path: string, cacheControl?: string) {
if(path === '/' || path === '/index.html' ){
//首页不管怎样都不要缓存
return true;
}
if (cacheControl) {
return false;
}
// api也不要缓存,如果他本身有设置缓存除外
return path.startsWith('/api');
return path === '/' || path === '/index.html' || path.startsWith('/api');
}
@@ -13,9 +13,7 @@ describe("shouldSetDefaultNoCache", () => {
});
it("keeps explicit cache headers from file responses", () => {
assert.equal(shouldSetDefaultNoCache("/", "public,max-age=259200"), true);
assert.equal(shouldSetDefaultNoCache("/index.html", "public,max-age=259200"), true);
assert.equal(shouldSetDefaultNoCache("/api/basic/file/download", "public,max-age=259200"), false);
assert.equal(shouldSetDefaultNoCache("/api/basic/file/download", "public,max-age=259200"), false);
});
it("ignores non-html and non-api paths", () => {
@@ -124,9 +124,7 @@ export class MainConfiguration {
this.app.getMiddleware().insertFirst(async (ctx: IMidwayKoaContext, next: NextFunction) => {
await next();
const path = ctx.path;
// 如果是首页则强制设置为不缓存
if (shouldSetDefaultNoCache(path, ctx.response.get('Cache-Control')) ) {
if (shouldSetDefaultNoCache(ctx.path, ctx.response.get('Cache-Control'))) {
ctx.response.set('Cache-Control', 'public,max-age=0');
}
});
@@ -138,6 +136,5 @@ export class MainConfiguration {
logger.info('当前环境:', this.app.getEnv()); // prod
// throw new Error("address family not supported")
}
}
@@ -64,6 +64,7 @@ export class LoginController extends BaseController {
mobile: body.mobile,
smsCode: body.smsCode,
randomStr: body.randomStr,
inviteCode: body.inviteCode,
});
this.writeTokenCookie(token);
@@ -3,6 +3,7 @@ import { BaseController, Constants, SysSettingsService } from '@certd/lib-server
import { RegisterType, UserService } from '../../../modules/sys/authority/service/user-service.js';
import { CodeService } from '../../../modules/basic/service/code-service.js';
import { checkComm, checkPlus } from '@certd/plus-core';
import { InviteService } from '@certd/commercial-core';
export type RegisterReq = {
type: RegisterType;
@@ -14,6 +15,7 @@ export type RegisterReq = {
validateCode: string;
captcha:any;
inviteCode?: string;
};
/**
@@ -29,6 +31,9 @@ export class RegisterController extends BaseController {
@Inject()
sysSettingsService: SysSettingsService;
@Inject()
inviteService: InviteService;
@Post('/register', { description: Constants.per.guest })
public async register(
@Body(ALL)
@@ -53,10 +58,13 @@ export class RegisterController extends BaseController {
}
await this.codeService.checkCaptcha(body.captcha,{remoteIp});
const newUser = await this.userService.register(body.type, {
const registerUser = {
username: body.username,
password: body.password,
} as any);
} as any;
const newUser = await this.userService.register(body.type, registerUser, async txManager => {
await this.inviteService.bindInvitee(registerUser.id, body.inviteCode, txManager);
});
return this.ok(newUser);
} else if (body.type === 'mobile') {
if (sysPublicSettings.mobileRegisterEnabled === false) {
@@ -70,12 +78,15 @@ export class RegisterController extends BaseController {
smsCode: body.validateCode,
throwError: true,
});
const newUser = await this.userService.register(body.type, {
const registerUser = {
username: body.username,
phoneCode: body.phoneCode,
mobile: body.mobile,
password: body.password,
} as any);
} as any;
const newUser = await this.userService.register(body.type, registerUser, async txManager => {
await this.inviteService.bindInvitee(registerUser.id, body.inviteCode, txManager);
});
return this.ok(newUser);
} else if (body.type === 'email') {
if (sysPublicSettings.emailRegisterEnabled === false) {
@@ -87,11 +98,14 @@ export class RegisterController extends BaseController {
validateCode: body.validateCode,
throwError: true,
});
const newUser = await this.userService.register(body.type, {
const registerUser = {
username: body.username,
email: body.email,
password: body.password,
} as any);
} as any;
const newUser = await this.userService.register(body.type, registerUser, async txManager => {
await this.inviteService.bindInvitee(registerUser.id, body.inviteCode, txManager);
});
return this.ok(newUser);
}
}
@@ -11,6 +11,7 @@ import {
SysSuiteSetting
} from "@certd/lib-server";
import { AppKey, getPlusInfo, isComm } from "@certd/plus-core";
import { SysInviteCommissionSetting } from "@certd/commercial-core";
import { cloneDeep } from "lodash-es";
import { getVersion } from "../../utils/version.js";
import { http } from "@certd/basic";
@@ -57,6 +58,16 @@ export class BasicSettingsController extends BaseController {
};
}
public async getInviteSetting() {
if (!isComm()) {
return { enabled: false };
}
const setting = await this.sysSettingsService.getSetting<SysInviteCommissionSetting>(SysInviteCommissionSetting);
return {
enabled: setting.enabled,
};
}
public async getSiteEnv() {
const env: SysSiteEnv = {
agent: this.agentConfig
@@ -92,6 +103,7 @@ export class BasicSettingsController extends BaseController {
const plusInfo = await this.plusInfo();
const headerMenus = await this.getHeaderMenus();
const suiteSetting = await this.getSuiteSetting();
const inviteSetting = await this.getInviteSetting();
const version = await getVersion();
return this.ok({
sysPublic,
@@ -101,6 +113,7 @@ export class BasicSettingsController extends BaseController {
plusInfo,
headerMenus,
suiteSetting,
inviteSetting,
app: {
time: new Date().getTime(),
version
@@ -23,25 +23,21 @@ describe("AutoFix", () => {
autoFix.googleCommonEabAccountKeyFix = {
async init() {
calls.push("google");
return true;
},
} as any;
autoFix.oauthSubtypeBoundTypeFix = {
async init() {
calls.push("oauth");
return true;
},
} as any;
autoFix.certInfoWildcardDomainCountFix = {
async init() {
calls.push("cert");
return true;
},
} as any;
autoFix.suiteContentWildcardDomainCountFix = {
async init() {
calls.push("suite");
return true;
},
} as any;
@@ -8,7 +8,7 @@ import { SuiteContentWildcardDomainCountFix } from "./suite-content-wildcard-dom
type AutoFixTask = {
key: string;
fix: {
init(): Promise<boolean>;
init(): Promise<void>;
};
};
@@ -56,8 +56,8 @@ export class AutoFix {
if (setting.fixed?.[task.key]) {
continue;
}
const ret = await task.fix.init();
setting.fixed[task.key] = ret;
await task.fix.init();
setting.fixed[task.key] = true;
await this.sysSettingsService.saveSetting(setting);
}
}
@@ -38,10 +38,8 @@ export class CertInfoWildcardDomainCountFix {
if (fixedCount > 0) {
logger.info(`已修复证书泛域名数量历史数据,数量=${fixedCount}`);
}
return true
} catch (e: any) {
logger.error("修复证书泛域名数量历史数据失败", e);
}
return false
}
}
@@ -47,7 +47,7 @@ export class GoogleCommonEabAccountKeyFix {
async init() {
if (!isComm()) {
return true;
return;
}
try {
const certApplyConfig = await this.pluginConfigService.getPluginConfig({
@@ -56,33 +56,31 @@ export class GoogleCommonEabAccountKeyFix {
});
const googleCommonEabAccessId = certApplyConfig?.sysSetting?.input?.googleCommonEabAccessId;
if (!googleCommonEabAccessId) {
return true;
return;
}
const eabAccess = await this.accessService.getAccessById(googleCommonEabAccessId, false);
if (eabAccess.accountKey) {
return true;
return;
}
if (!eabAccess.kid) {
logger.info("公共Google EAB授权缺少KID,跳过历史ACME账号私钥修复");
return true;
return;
}
const accountConfig = await this.getLegacyGoogleAccountConfig(eabAccess.email);
const privateKey = accountConfig?.privateKey || accountConfig?.key || accountConfig?.accountKey;
if (!privateKey) {
logger.info("未找到可迁移到公共Google EAB授权的历史ACME账号私钥");
return true;
return;
}
const accountKey = buildEabAccountKeyValue(eabAccess.kid, privateKey);
await this.accessService.updateAccess({ id: googleCommonEabAccessId, eabType: "google", accountKey });
logger.info(`已修复公共Google EAB授权的ACME账号私钥,accessId=${googleCommonEabAccessId}`);
return true;
} catch (e: any) {
logger.error("修复公共Google EAB授权ACME账号私钥失败", e);
}
return false
}
async getLegacyGoogleAccountConfig(email?: string) {
@@ -41,7 +41,6 @@ export class OauthSubtypeBoundTypeFix {
await this.convertLegacyAddonLoginTypeToArray(addonEntity, legacyLoginType, manager);
}
});
return true
} catch (e: any) {
logger.error("修复OAuth subtype绑定历史数据失败", e);
}

Some files were not shown because too many files have changed in this diff Show More