Compare commits

...

80 Commits

Author SHA1 Message Date
xiaojunnuo
a096a43c56 v1.1.5 2023-07-03 17:59:34 +08:00
xiaojunnuo
8114a33d20 build: prepare to build 2023-07-03 17:57:54 +08:00
xiaojunnuo
9f3adddd41 refactor: cacheControl 2023-07-03 17:57:26 +08:00
xiaojunnuo
05f74ab654 refactor: cacheControl 2023-07-03 17:43:21 +08:00
xiaojunnuo
0317118cd9 refactor: 1.1.4 2023-07-03 13:42:48 +08:00
xiaojunnuo
461de8d269 refactor: 1.1.4 2023-07-03 12:39:03 +08:00
xiaojunnuo
b258e92620 v1.1.4 2023-07-03 12:30:41 +08:00
xiaojunnuo
f6148ef1fb build: prepare to build 2023-07-03 12:25:26 +08:00
xiaojunnuo
457da594be build: prepare to build 2023-07-03 11:53:44 +08:00
xiaojunnuo
891a43ae67 perf: flush log 2023-07-03 11:53:11 +08:00
xiaojunnuo
bc65c0a786 perf: cancel task 2023-07-03 11:45:32 +08:00
xiaojunnuo
3eeb1f77aa perf: timeout 2023-07-03 11:16:46 +08:00
xiaojunnuo
91be6826b9 perf: flush logger 2023-07-03 10:54:03 +08:00
xiaojunnuo
f87eee3b9f fix: 成功图标转动的问题 2023-07-03 10:31:25 +08:00
xiaojunnuo
b4e17691c4 chore: index update fast 2023-07-03 10:29:06 +08:00
xiaojunnuo
cce372aeba chore: env config 2023-07-03 10:14:22 +08:00
xiaojunnuo
b5a8a9e08a chore: deploy 2023-07-03 10:05:50 +08:00
xiaojunnuo
35632da284 chore: deploy 2023-07-03 09:33:18 +08:00
xiaojunnuo
02a9b0d16c chore: 1.1.3 2023-07-03 09:25:52 +08:00
xiaojunnuo
d1809e0f7d v1.1.3 2023-07-03 09:22:33 +08:00
xiaojunnuo
abb4a7c0f9 build: prepare to build 2023-07-03 09:21:35 +08:00
xiaojunnuo
cd6fa8b15c chore: 1.1.2 2023-07-03 09:20:10 +08:00
xiaojunnuo
ecfcada802 v1.1.2 2023-07-03 09:18:03 +08:00
xiaojunnuo
f8ec5ae253 build: prepare to build 2023-07-03 09:16:50 +08:00
xiaojunnuo
832ba5c8fb chore: static cache 2023-07-03 09:15:52 +08:00
xiaojunnuo
fa8e91cdcd chore: lodash-es 2023-06-29 17:29:36 +08:00
xiaojunnuo
e5d902663b chore: lodash-es 2023-06-29 17:20:47 +08:00
xiaojunnuo
042535536e chore: pref 2023-06-29 17:19:05 +08:00
xiaojunnuo
6d3063437c chore: pref 2023-06-29 16:45:16 +08:00
xiaojunnuo
3db4d04e4c chore: pref 2023-06-29 16:42:08 +08:00
xiaojunnuo
96f9eab5cd chore: env 2023-06-29 10:34:52 +08:00
xiaojunnuo
1e641b83c1 chore: env 2023-06-29 09:31:26 +08:00
xiaojunnuo
3791d92d67 chore: token expire 2023-06-29 08:56:09 +08:00
xiaojunnuo
2bcab76f5a chore: change password 2023-06-28 23:15:37 +08:00
xiaojunnuo
f5493c542b chore: get random value 2023-06-28 22:10:52 +08:00
xiaojunnuo
68eb4198f1 v1.1.1 2023-06-28 15:48:03 +08:00
xiaojunnuo
ef94607728 build: prepare to build 2023-06-28 15:46:58 +08:00
xiaojunnuo
4ccadbd2be build: prepare to build 2023-06-28 15:42:36 +08:00
xiaojunnuo
0643063b80 chore: auth 2023-06-28 15:42:10 +08:00
xiaojunnuo
d6c6ab932a chore: auth 2023-06-28 15:35:31 +08:00
xiaojunnuo
46004d2db8 chore: login 2023-06-28 15:18:36 +08:00
xiaojunnuo
620d1d4092 chore: clear file 2023-06-28 15:16:19 +08:00
xiaojunnuo
f30afac47e chore: 同步npm镜像 2023-06-28 14:34:22 +08:00
xiaojunnuo
1779e34773 chore: 1 2023-06-28 13:55:48 +08:00
xiaojunnuo
28f535f41c chore: 1 2023-06-28 13:54:17 +08:00
xiaojunnuo
e921f58d2f chore: 1 2023-06-28 13:45:19 +08:00
xiaojunnuo
301f6cc273 chore: off cron when remove 2023-06-28 12:46:29 +08:00
xiaojunnuo
f04e497999 chore: 1.1.0 2023-06-28 11:34:37 +08:00
xiaojunnuo
8db438d76b chore: 1.0.7 2023-06-28 10:29:16 +08:00
xiaojunnuo
af75e607ec chore: 1.0.7 2023-06-28 10:27:37 +08:00
xiaojunnuo
cd4b9527c3 v1.1.0 2023-06-28 10:23:14 +08:00
xiaojunnuo
ea8dc446ae build: prepare to build 2023-06-28 10:22:03 +08:00
xiaojunnuo
ba6270990b chore: 1.0.7 2023-06-28 10:21:32 +08:00
xiaojunnuo
df55f1066c chore: build set -e 2023-06-28 09:58:58 +08:00
xiaojunnuo
b562d661db chore: build +x 2023-06-28 09:57:20 +08:00
xiaojunnuo
aede78a0ec chore: build 2023-06-28 09:44:35 +08:00
xiaojunnuo
7e8c3fbab7 chore: 1 2023-06-27 23:17:32 +08:00
xiaojunnuo
6621601155 chore: 1 2023-06-27 23:06:08 +08:00
xiaojunnuo
1fbd585a46 chore: 1 2023-06-27 22:55:36 +08:00
xiaojunnuo
5a51c14de5 feat: cert download 2023-06-27 22:45:27 +08:00
xiaojunnuo
27a4c81c6d feat: 权限控制 2023-06-27 09:29:43 +08:00
xiaojunnuo
fdc25dc0d7 feat: config merge 2023-06-26 12:26:59 +08:00
xiaojunnuo
99522fb49a feat: save files 2023-06-25 23:45:13 +08:00
xiaojunnuo
671d273e2f feat: save files 2023-06-25 23:25:56 +08:00
xiaojunnuo
2851a33eb2 fix: 修复access选择类型trigger 2023-06-25 16:25:23 +08:00
xiaojunnuo
937e3fac19 feat: 邮件通知 2023-06-25 15:30:18 +08:00
xiaojunnuo
64afebecd4 chore: email 2023-06-07 23:36:42 +08:00
xiaojunnuo
4c324960e6 chore: 1 2023-06-07 23:10:33 +08:00
xiaojunnuo
f516b0931f chore: jwt key 2023-05-26 16:18:24 +08:00
xiaojunnuo
2297121eff chore: node 16 2023-05-26 14:43:38 +08:00
xiaojunnuo
0c2684d1cf chore: node 16 2023-05-26 14:39:51 +08:00
xiaojunnuo
4b4c5dba73 chore: node 16 2023-05-26 14:39:33 +08:00
xiaojunnuo
7b9d70e093 chore: node 16 2023-05-26 14:31:37 +08:00
xiaojunnuo
71a289b009 chore: node 16 2023-05-26 14:08:37 +08:00
xiaojunnuo
ddf98ff593 chore: node 16 2023-05-26 12:48:06 +08:00
xiaojunnuo
db8043ecb6 chore: node 16 2023-05-26 12:33:03 +08:00
xiaojunnuo
ea756cf0a4 chore: node 16 2023-05-26 10:54:30 +08:00
xiaojunnuo
8446a6d813 chore: node 16 2023-05-26 09:09:57 +08:00
xiaojunnuo
a18aaeacf7 chore: node 16 2023-05-26 01:40:03 +08:00
xiaojunnuo
58a43b3785 chore: node 16 2023-05-26 00:35:44 +08:00
185 changed files with 2924 additions and 1041 deletions

View File

@@ -3,6 +3,50 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package root
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Bug Fixes
* 成功图标转动的问题 ([f87eee3](https://github.com/certd/certd/commit/f87eee3b9ff1ef9874e79a81fe0ed7104cb9ee8c))
### Performance Improvements
* cancel task ([bc65c0a](https://github.com/certd/certd/commit/bc65c0a786360c087fe95cad93ec6a87804cc5ee))
* flush log ([891a43a](https://github.com/certd/certd/commit/891a43ae6716ff98ed06643f7da2e35199ee195c))
* flush logger ([91be682](https://github.com/certd/certd/commit/91be6826b902e0f302b1a6cbdb1d24e15914c18d))
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package root
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package root
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package root
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Bug Fixes
* 修复access选择类型trigger ([2851a33](https://github.com/certd/certd/commit/2851a33eb2510f038fadb55da29512597a4ba512))
### Features
* 权限控制 ([27a4c81](https://github.com/certd/certd/commit/27a4c81c6d70e70abb3892c3ea58d4719988808a))
* 邮件通知 ([937e3fa](https://github.com/certd/certd/commit/937e3fac19cd03b8aa91db8ba03fda7fcfbacea2))
* cert download ([5a51c14](https://github.com/certd/certd/commit/5a51c14de521cb8075a80d2ae41a16e6d5281259))
* config merge ([fdc25dc](https://github.com/certd/certd/commit/fdc25dc0d795555cffacc4572648ec158988fbbb))
* save files ([99522fb](https://github.com/certd/certd/commit/99522fb49adb42c1dfdf7bec3dd52d641158285b))
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package root

View File

@@ -6,9 +6,10 @@ CertD 是一个帮助你全自动申请和部署SSL证书的工具。
## 特性
本项目不仅支持证书申请过程自动化,还可以自动化部署证书,让你的证书永不过期。
* 全自动申请证书
* 全自动申请证书(支持阿里云、腾讯云、华为云注册的域名)
* 全自动部署证书(目前支持服务器上传部署、阿里云、腾讯云等)
* 可与CI/DI工具结合使用
* 支持通配符域名
* 支持多个域名打到一个证书上
## 免费证书申请说明
* 本项目ssl证书提供商为letencrypt

102
deploy.js
View File

@@ -1,58 +1,80 @@
const http = require("axios")
const exec = require('child_process').exec;
import http from 'axios'
import fs from 'fs'
//builder
function execute(cmd){
return new Promise((resolve,reject)=>{
console.log("cmd executing: " + cmd)
exec(cmd, function(error, stdout, stderr) {
if(error){
console.error(error);
console.info(stderr)
reject(error)
}
else{
console.info(stdout)
console.log("success");
resolve(true)
//读取 packages/core/pipline/package.json的版本号
import {default as packageJson} from './packages/core/pipeline/package.json' assert {type: "json"};
const certdVersion = packageJson.version
console.log("certdVersion", certdVersion)
// 同步npmmirror的包
async function getPackages(directoryPath) {
return new Promise((resolve, reject) => {
// 读取目录下的文件和目录列表
fs.readdir(directoryPath, {withFileTypes: true}, (err, files) => {
if (err) {
console.log('无法读取目录:', err);
reject(err)
return;
}
// 过滤仅保留目录
const directories = files
.filter(file => file.isDirectory())
.map(directory => directory.name);
console.log('目录列表:', directories);
resolve(directories)
});
})
}
async function build(){
await execute("cd ./packages/fast-admin/fs-admin-antdv/ && npm run build")
await execute("cd ./packages/fast-admin/fs-admin-element/ && npm run build")
await execute("cd ./packages/fast-admin/fs-admin-naive-ui/ && npm run build")
await execute("npm run docs:build")
async function getAllPackages() {
const base = await getPackages("./packages/core")
const plugins = await getPackages("./packages/plugins")
return base.concat(plugins)
}
async function sync() {
const packages = await getAllPackages()
for (const pkg of packages) {
await http({
url: `http://registry-direct.npmmirror.com/@certd/${pkg}/sync?sync_upstream=true`,
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
data: {}
})
console.log(`sync success:${pkg}`)
await sleep(1000)
}
}
// curl -X PUT https://registry-direct.npmmirror.com/@certd/plugin-cert/sync?sync_upstream=true
// trigger
const certdImageBuild = "http://flow-openapi.aliyun.com/pipeline/webhook/4zgFk3i4RZEMGuQzlOcI"
const webhooks = [certdImageBuild]
const naive = "http://flow-openapi.aliyun.com/pipeline/webhook/Zm3TJyDtyFZgV4dtJiD1"
const doc = "http://flow-openapi.aliyun.com/pipeline/webhook/soOYdQ5sF3kLjTPJGmIO"
const antdv = "http://flow-openapi.aliyun.com/pipeline/webhook/HiL0uVYxfUnBzIMJZVXB"
const element = "http://flow-openapi.aliyun.com/pipeline/webhook/uFTI0XJ9RgqnofX7jpRD"
const webhooks = [doc,naive,antdv,element]
async function sleep(time){
async function sleep(time) {
return new Promise(resolve => {
setTimeout(resolve,time)
setTimeout(resolve, time)
})
}
async function trigger(){
async function triggerBuild() {
for (const webhook of webhooks) {
await http({
url:webhook,
method:'POST',
headers:{
url: webhook,
method: 'POST',
headers: {
"Content-Type": "application/json"
},
data:{}
data: {
'CERTD_VERSION': certdVersion
}
})
console.log(`webhook success:${webhook}`)
await sleep(1000)
@@ -60,11 +82,13 @@ async function trigger(){
}
async function start(){
async function start() {
// await build()
console.log("等待60秒")
await sleep(60*1000)
await trigger()
await sleep(60 * 1000)
await sync()
await sleep(60 * 1000)
await triggerBuild()
}
start()

View File

@@ -1,9 +1,18 @@
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/node:16-alpine
RUN npm install -g pnpm && npm install -g cross-env
ADD ./workspace/certd-server/ /app/
EXPOSE 7001
ENV NODE_ENV production
ENV MIDWAY_SERVER_ENV production
WORKDIR /app/
RUN pnpm install -P
CMD ["npm","run","start"]
#RUN npm install cross-env -g --registry=https://registry.npmmirror.com
#RUN npm install pm2 -g --registry=https://registry.npmmirror.com
#RUN pm2 install pm2-logrotate
ADD ./workspace/certd-server/ /app/
RUN yarn install --production --registry=https://registry.npmmirror.com
#RUN yarn install --production
RUN npm run build
#CMD ["pm2-runtime", "start", "./bootstrap.js","--name", "certd","-i","1"]
CMD ["npm", "run","start"]

9
docker/image/build.sh Normal file → Executable file
View File

@@ -1,16 +1,17 @@
#!/bin/bash
set -e
echo "请先输入一个版本号:"
read version
echo "您输入的版本号是: $version"
echo "登录aliyun镜像仓库"
docker login --username=252959493@qq.com registry.cn-shenzhen.aliyuncs.com
sudo docker login --username=252959493@qq.com registry.cn-shenzhen.aliyuncs.com
build=$(pwd)
cd ../../
root=$(pwd)
echo "安装依赖"
#pnpm install --registry=https://registry.npmmirror.com
pnpm install
echo "client build"
@@ -31,4 +32,6 @@ mkdir -p $build/workspace/certd-server
\cp ./* $build/workspace/certd-server -rf
\cp ../certd-client/dist/* $build/workspace/certd-server/public/ -rf
#export TAG=$version
#sudo -E docker compose build
#sudo -E docker compose push

9
docker/run/Dockerfile Normal file
View File

@@ -0,0 +1,9 @@
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
EXPOSE 7001
RUN npm run build
#RUN npm install pm2 -g --registry=https://registry.npmmirror.com
#CMD ["pm2-runtime", "start", "./bootstrap.js","--name", "certd","-i","1","--", "-p", "7001"]
CMD ["npm","run", "start"]

15
docker/run/build.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
set -e
# 判断$CERTD_VERSION 是否存在
if [ -n "$CERTD_VERSION" ]; then
echo "CERTD_VERSION is set = $CERTD_VERSION"
version=$CERTD_VERSION
else
echo "CERTD_VERSION is not set"
echo "请先输入一个版本号(如 1.0.6)"
read version
fi
echo "您输入的版本号是: $version"
export TAG="$version"
sudo -E docker compose up -d

View File

@@ -1,15 +1,23 @@
version: '3.3' # 指定docker-compose 版本
services: # 要拉起的服务们
version: '3.3'
services:
certd:
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
# 镜像 # ↓↓↓↓↓ --- 1、 修改镜像版本号
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${TAG}
container_name: certd # 容器名
restart: unless-stopped # 重启
volumes: # 挂载目录
volumes:
# ↓↓↓↓↓ ------------------------------------------------------- 2、 修改数据库以及证书存储路径
- /data/certd:/app/data
ports: # 端口映射
- "7001:7001"
environment:
environment: # 环境变量
- TZ=Asia/Shanghai
- CERTD_AUTH_JWT_KEY=changeme
#注意修改成你的自定义密钥 ↑↑↑↑↑
- certd_auth_jwt_secret=changeme
# ↑↑↑↑↑ ---------------------------------- 3、 修改成你的自定义密钥
# 设置环境变量即可自定义certd配置
# 服务端配置项见: packages/ui/certd-server/src/config/config.default.ts
# 服务端配置规则: certd_ + 配置项, 点号用_代替
# 如jwt密钥配置为 auth.jwt.secret则设置环境变量 certd_auth_jwt_secret=changeme
# 客户端配置项见: packages/ui/certd-client/.env
# 按实际名称配置环境变量即可,如: VITE_APP_API=http://localhost:7001

View File

@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.0.6"
"version": "1.1.5"
}

View File

@@ -5,20 +5,22 @@
"type": "module",
"devDependencies": {
"@lerna-lite/cli": "^2.4.0",
"@lerna-lite/run": "^2.4.0",
"@lerna-lite/publish": "^2.4.0"
"@lerna-lite/publish": "^2.4.0",
"@lerna-lite/run": "^2.4.0"
},
"scripts": {
"start": "lerna bootstrap --hoist",
"i-all": "lerna link && lerna exec npm install ",
"publish": "npm run proxy && npm run prepublishOnly1 && lerna publish --conventional-commits && npm run afterpublishOnly",
"publish": "npm run proxy && npm run prepublishOnly1 && lerna publish --conventional-commits && npm run afterpublishOnly && npm run deploy1",
"afterpublishOnly": "",
"proxy": "npm config set proxy=http://127.0.0.1:10809",
"prepublishOnly1": "npm run before-build && lerna run build ",
"before-build": "cd ./packages/core/acme-client && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\""
"before-build": "cd ./packages/core/acme-client && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
"deploy1": "node deploy.js"
},
"license": "MIT",
"dependencies": {
"axios": "^1.4.0",
"lodash": "^4.17.21"
},
"workspaces": [

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/publishlab/node-acme-client/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/acme-client
## [1.1.4](https://github.com/publishlab/node-acme-client/compare/v1.1.3...v1.1.4) (2023-07-03)
**Note:** Version bump only for package @certd/acme-client
## [1.1.3](https://github.com/publishlab/node-acme-client/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/acme-client
## [1.1.2](https://github.com/publishlab/node-acme-client/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/acme-client
## [1.1.1](https://github.com/publishlab/node-acme-client/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/acme-client
# [1.1.0](https://github.com/publishlab/node-acme-client/compare/v1.0.6...v1.1.0) (2023-06-28)
**Note:** Version bump only for package @certd/acme-client
## [1.0.6](https://github.com/publishlab/node-acme-client/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/acme-client

View File

@@ -1 +1 @@
00:19
17:57

View File

@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.0.6",
"version": "1.1.5",
"main": "src/index.js",
"types": "types",
"license": "MIT",
@@ -58,5 +58,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -3,6 +3,44 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/pipeline
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* cancel task ([bc65c0a](https://github.com/certd/certd/commit/bc65c0a786360c087fe95cad93ec6a87804cc5ee))
* flush log ([891a43a](https://github.com/certd/certd/commit/891a43ae6716ff98ed06643f7da2e35199ee195c))
* flush logger ([91be682](https://github.com/certd/certd/commit/91be6826b902e0f302b1a6cbdb1d24e15914c18d))
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/pipeline
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/pipeline
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/pipeline
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Bug Fixes
* 修复access选择类型trigger ([2851a33](https://github.com/certd/certd/commit/2851a33eb2510f038fadb55da29512597a4ba512))
### Features
* 邮件通知 ([937e3fa](https://github.com/certd/certd/commit/937e3fac19cd03b8aa91db8ba03fda7fcfbacea2))
* cert download ([5a51c14](https://github.com/certd/certd/commit/5a51c14de521cb8075a80d2ae41a16e6d5281259))
* save files ([99522fb](https://github.com/certd/certd/commit/99522fb49adb42c1dfdf7bec3dd52d641158285b))
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/pipeline

View File

@@ -1,10 +1,10 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.0.6",
"main": "./dist/bundle.js",
"module": "./dist/pipeline.mjs",
"types": "./dist/d/index.d.ts",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
"publishConfig": {
"main": "./dist/bundle.js",
"module": "./dist/bundle.mjs",
@@ -19,10 +19,11 @@
"dependencies": {
"axios": "^1.4.0",
"node-forge": "^1.3.1",
"nodemailer": "^6.9.3",
"qs": "^6.11.2"
},
"devDependencies": {
"@certd/acme-client": "^1.0.6",
"@certd/acme-client": "^1.1.5",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
@@ -32,6 +33,7 @@
"@types/lodash": "^4.14.194",
"@types/mocha": "^10.0.1",
"@types/node-forge": "^1.3.2",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"chai": "^4.3.7",
@@ -54,5 +56,5 @@
"vite": "^4.3.8",
"vue-tsc": "^1.6.5"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -1,7 +1,7 @@
import { ConcurrencyStrategy, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task } from "../d.ts";
import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task } from "../d.ts";
import _ from "lodash";
import { RunHistory, RunnableCollection } from "./run-history";
import { AbstractTaskPlugin, PluginDefine, pluginRegistry } from "../plugin";
import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext } from "../plugin";
import { ContextFactory, IContext } from "./context";
import { IStorage } from "./storage";
import { logger } from "../utils/util.log";
@@ -10,31 +10,37 @@ import { request } from "../utils/util.request";
import { IAccessService } from "../access";
import { RegistryItem } from "../registry";
import { Decorator } from "../decorator";
import { IEmailService } from "../service";
import { FileStore } from "./file-store";
import { TimeoutPromise } from "../utils/util.promise";
export class Executor {
export type ExecutorOptions = {
userId: any;
pipeline: Pipeline;
runtime!: RunHistory;
storage: IStorage;
onChanged: (history: RunHistory) => Promise<void>;
accessService: IAccessService;
emailService: IEmailService;
fileRootDir?: string;
};
export class Executor {
pipeline: Pipeline;
runtime!: RunHistory;
contextFactory: ContextFactory;
logger: Logger;
pipelineContext!: IContext;
lastStatusMap!: RunnableCollection;
lastRuntime!: RunHistory;
options: ExecutorOptions;
canceled = false;
onChanged: (history: RunHistory) => void;
constructor(options: {
userId: any;
pipeline: Pipeline;
storage: IStorage;
onChanged: (history: RunHistory) => Promise<void>;
accessService: IAccessService;
}) {
constructor(options: ExecutorOptions) {
this.options = options;
this.pipeline = _.cloneDeep(options.pipeline);
this.onChanged = async (history: RunHistory) => {
await options.onChanged(history);
};
this.accessService = options.accessService;
this.userId = options.userId;
this.pipeline.userId = this.userId;
this.pipeline.userId = options.userId;
this.contextFactory = new ContextFactory(options.storage);
this.logger = logger;
this.pipelineContext = this.contextFactory.getContext("pipeline", this.pipeline.id);
@@ -42,9 +48,16 @@ export class Executor {
async init() {
const lastRuntime = await this.pipelineContext.getObj(`lastRuntime`);
this.lastRuntime = lastRuntime;
this.lastStatusMap = new RunnableCollection(lastRuntime?.pipeline);
}
async cancel() {
this.canceled = true;
this.runtime?.cancel(this.pipeline);
await this.onChanged(this.runtime);
}
async run(runtimeId: any = 0, triggerType: string) {
try {
await this.init();
@@ -52,10 +65,16 @@ export class Executor {
// 读取last
this.runtime = new RunHistory(runtimeId, trigger, this.pipeline);
this.logger.info(`pipeline.${this.pipeline.id} start`);
await this.notification("start");
await this.runWithHistory(this.pipeline, "pipeline", async () => {
await this.runStages(this.pipeline);
});
if (this.lastRuntime && this.lastRuntime.pipeline.status?.status === ResultType.error) {
await this.notification("turnToSuccess");
}
await this.notification("success");
} catch (e) {
await this.notification("error", e);
this.logger.error("pipeline 执行失败", e);
} finally {
await this.pipelineContext.setObj("lastRuntime", this.runtime);
@@ -88,17 +107,24 @@ export class Executor {
return ResultType.skip;
}
}
try {
await run();
this.runtime.success(runnable);
const intervalFlushLogId = setInterval(async () => {
await this.onChanged(this.runtime);
}, 5000);
const timeout = runnable.timeout ?? 20 * 60 * 1000;
try {
if (this.canceled) {
throw new Error("task canceled");
}
await TimeoutPromise(run, timeout);
this.runtime.success(runnable);
return ResultType.success;
} catch (e: any) {
this.runtime.error(runnable, e);
await this.onChanged(this.runtime);
throw e;
} finally {
this.runtime.finally(runnable);
clearInterval(intervalFlushLogId);
await this.onChanged(this.runtime);
}
}
@@ -181,27 +207,74 @@ export class Executor {
}
});
const context: any = {
logger: this.runtime._loggers[step.id],
accessService: this.accessService,
pipelineContext: this.pipelineContext,
const taskCtx: TaskInstanceContext = {
pipeline: this.pipeline,
step,
lastStatus,
userContext: this.contextFactory.getContext("user", this.userId),
http: request,
logger: this.runtime._loggers[step.id],
accessService: this.options.accessService,
emailService: this.options.emailService,
pipelineContext: this.pipelineContext,
userContext: this.contextFactory.getContext("user", this.options.userId),
fileStore: new FileStore({
scope: this.pipeline.id,
parent: this.runtime.id,
rootDir: this.options.fileRootDir,
}),
};
Decorator.inject(define.autowire, instance, context);
instance.setCtx(taskCtx);
await instance.onInstance();
await instance.execute();
if (instance.result.clearLastStatus) {
if (instance._result.clearLastStatus) {
this.lastStatusMap.clear();
}
//输出到output context
_.forEach(define.output, (item, key) => {
step!.status!.output[key] = instance[key];
step.status!.output[key] = instance[key];
const stepOutputKey = `step.${step.id}.${key}`;
this.runtime.context[stepOutputKey] = instance[key];
});
step.status!.files = instance.getFiles();
}
async notification(when: NotificationWhen, error?: any) {
if (!this.pipeline.notifications) {
return;
}
let subject = "";
let content = "";
if (when === "start") {
subject = `【CertD】开始执行${this.pipeline.title}, buildId:${this.runtime.id}`;
content = subject;
} else if (when === "success") {
subject = `【CertD】执行成功${this.pipeline.title}, buildId:${this.runtime.id}`;
content = subject;
} else if (when === "turnToSuccess") {
subject = `【CertD】执行成功错误转成功${this.pipeline.title}, buildId:${this.runtime.id}`;
content = subject;
} else if (when === "error") {
subject = `【CertD】执行失败${this.pipeline.title}, buildId:${this.runtime.id}`;
content = `<pre>${error.message}</pre>`;
} else {
return;
}
for (const notification of this.pipeline.notifications) {
if (!notification.when.includes(when)) {
continue;
}
if (notification.type === "email") {
this.options.emailService?.send({
userId: this.pipeline.userId,
subject,
content,
receivers: notification.options.receivers,
});
}
}
}
}

View File

@@ -0,0 +1,50 @@
import { fileUtils } from "../utils/util.file";
import dayjs from "dayjs";
import path from "path";
import fs from "fs";
export type FileStoreOptions = {
rootDir?: string;
scope: string;
parent: string;
};
export class FileStore {
rootDir: string;
scope: string;
parent: string;
constructor(options?: FileStoreOptions) {
this.rootDir = fileUtils.getFileRootDir(options?.rootDir);
this.scope = options?.scope || "0";
this.parent = options?.parent || "0";
}
readFile(filePath: string) {
if (!fs.existsSync(filePath)) {
return null;
}
return fs.readFileSync(filePath);
}
writeFile(filename: string, file: Buffer) {
const localPath = this.buildFilePath(filename);
fs.writeFileSync(localPath, file);
return localPath;
}
private buildFilePath(filename: string) {
const parentDir = path.join(this.rootDir, this.scope + "", this.parent + "", dayjs().format("YYYY-MM-DD"));
if (!fs.existsSync(parentDir)) {
fs.mkdirSync(parentDir, { recursive: true });
}
return path.join(parentDir, filename);
}
deleteByParent(scope: string, parent: string) {
const dir = path.join(this.rootDir, scope, parent);
if (fs.existsSync(dir)) {
fs.unlinkSync(dir);
}
}
}

View File

@@ -2,3 +2,4 @@ export * from "./executor";
export * from "./run-history";
export * from "./context";
export * from "./storage";
export * from "./file-store";

View File

@@ -92,6 +92,19 @@ export class RunHistory {
this.logError(runnable, e);
}
cancel(runnable: Runnable) {
const now = new Date().getTime();
const status = runnable.status;
_.merge(status, {
status: ResultType.canceled,
endTime: now,
result: ResultType.canceled,
message: "用户取消",
});
this.log(runnable, "任务取消");
}
log(runnable: Runnable, text: string) {
// @ts-ignore
this._loggers[runnable.id].info(`[${runnable.title}]<id:${runnable.id}> [${runnable.runnableType}]`, text);
@@ -119,25 +132,25 @@ export class RunnableCollection {
this.collection = map;
}
private each<T extends Runnable>(list: T[], exec: (item: Runnable) => void) {
static each<T extends Runnable>(list: T[], exec: (item: Runnable) => void) {
list.forEach((item) => {
exec(item);
if (item.runnableType === "pipeline") {
// @ts-ignore
this.each<Stage>(item.stages, exec);
RunnableCollection.each<Stage>(item.stages, exec);
} else if (item.runnableType === "stage") {
// @ts-ignore
this.each<Task>(item.tasks, exec);
RunnableCollection.each<Task>(item.tasks, exec);
} else if (item.runnableType === "task") {
// @ts-ignore
this.each<Step>(item.steps, exec);
RunnableCollection.each<Step>(item.steps, exec);
}
});
}
private toMap(pipeline: Pipeline) {
public toMap(pipeline: Pipeline) {
const map: RunnableMap = {};
this.each(pipeline.stages, (item) => {
RunnableCollection.each(pipeline.stages, (item) => {
map[item.id] = item;
});
return map;
@@ -151,7 +164,7 @@ export class RunnableCollection {
if (!this.pipeline) {
return;
}
this.each(this.pipeline.stages, (item) => {
RunnableCollection.each(this.pipeline.stages, (item) => {
item.status = undefined;
});
}

View File

@@ -1,7 +1,6 @@
import fs from "fs";
import path from "path";
import { fileUtils } from "../utils/util.file";
export interface IStorage {
get(scope: string, namespace: string, version: string, key: string): Promise<string | null>;
@@ -12,15 +11,7 @@ export interface IStorage {
export class FileStorage implements IStorage {
root: string;
constructor(rootDir?: string) {
if (rootDir == null) {
const userHome = process.env.HOME || process.env.USERPROFILE;
rootDir = userHome + "/.certd/storage/";
}
this.root = rootDir;
if (!fs.existsSync(this.root)) {
fs.mkdirSync(this.root, { recursive: true });
}
this.root = fileUtils.getFileRootDir(rootDir);
}
async remove(scope: string, namespace: string, version: string, key: string): Promise<void> {

View File

@@ -55,22 +55,40 @@ export type Trigger = {
type: string;
};
export type FileItem = {
id: string;
filename: string;
path: string;
};
export type Runnable = {
id: string;
title: string;
strategy?: RunnableStrategy;
runnableType?: string; // pipeline, stage, task , step
status?: HistoryResult;
timeout?: number;
default?: {
[key: string]: any;
};
};
export type EmailOptions = {
receivers: string[];
};
export type NotificationWhen = "error" | "success" | "turnToSuccess" | "start";
export type NotificationType = "email" | "url";
export type Notification = {
type: NotificationType;
when: NotificationWhen[];
options: EmailOptions;
};
export type Pipeline = Runnable & {
version?: number;
userId: any;
stages: Stage[];
triggers: Trigger[];
notifications: Notification[];
};
export type Context = {
@@ -88,6 +106,7 @@ export enum ResultType {
start = "start",
success = "success",
error = "error",
canceled = "canceled",
skip = "skip",
none = "none",
}
@@ -101,6 +120,7 @@ export type HistoryResultGroup = {
export type HistoryResult = {
input: any;
output: any;
files?: FileItem[];
/**
* 任务状态
*/

View File

@@ -7,3 +7,4 @@ export * from "./plugin";
export * from "./utils";
export * from "./context";
export * from "./decorator";
export * from "./service";

View File

@@ -1,5 +1,11 @@
import { Registrable } from "../registry";
import { FormItemProps } from "../d.ts";
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../d.ts";
import { FileStore } from "../core/file-store";
import { Logger } from "log4js";
import { IAccessService } from "../access";
import { IEmailService } from "../service";
import { IContext } from "../core";
import { AxiosInstance } from "axios";
export enum ContextScope {
global,
@@ -7,16 +13,11 @@ export enum ContextScope {
runtime,
}
export type Storage = {
scope: ContextScope;
path: string;
};
export type TaskOutputDefine = {
title: string;
value?: any;
storage?: Storage;
};
export type TaskInputDefine = FormItemProps;
export type PluginDefine = Registrable & {
@@ -31,6 +32,12 @@ export type PluginDefine = Registrable & {
autowire?: {
[key: string]: any;
};
reference?: {
src: string;
dest: string;
type: "computed";
}[];
};
export type ITaskPlugin = {
@@ -41,15 +48,66 @@ export type ITaskPlugin = {
export type TaskResult = {
clearLastStatus?: boolean;
files?: FileItem[];
};
export type TaskInstanceContext = {
pipeline: Pipeline;
step: Step;
logger: Logger;
accessService: IAccessService;
emailService: IEmailService;
pipelineContext: IContext;
userContext: IContext;
http: AxiosInstance;
fileStore: FileStore;
lastStatus?: Runnable;
};
export abstract class AbstractTaskPlugin implements ITaskPlugin {
result: TaskResult = {};
_result: TaskResult = { clearLastStatus: false, files: [] };
ctx!: TaskInstanceContext;
clearLastStatus() {
this.result.clearLastStatus = true;
this._result.clearLastStatus = true;
}
getFiles() {
return this._result.files;
}
setCtx(ctx: TaskInstanceContext) {
this.ctx = ctx;
}
randomFileId() {
return Math.random().toString(36).substring(2, 9);
}
linkFile(file: FileItem) {
this._result.files!.push({
...file,
id: this.randomFileId(),
});
}
saveFile(filename: string, file: Buffer) {
const filePath = this.ctx.fileStore.writeFile(filename, file);
this._result.files!.push({
id: this.randomFileId(),
filename,
path: filePath,
});
}
get pipeline() {
return this.ctx.pipeline;
}
get step() {
return this.ctx.step;
}
async onInstance(): Promise<void> {
return;
}
abstract execute(): Promise<void>;
}

View File

@@ -8,7 +8,6 @@ import "reflect-metadata";
export const PLUGIN_CLASS_KEY = "pipeline:plugin";
export function IsTaskPlugin(define: PluginDefine): ClassDecorator {
console.log("IsTaskPlugin");
return (target: any) => {
target = Decorator.target(target);
@@ -61,3 +60,11 @@ export function TaskOutput(output?: TaskOutputDefine): PropertyDecorator {
Reflect.defineMetadata(PLUGIN_OUTPUT_KEY, output, target, propertyKey);
};
}
export const PLUGIN_DOWNLOAD_KEY = "pipeline:plugin:download";
export function TaskDownload(output?: TaskOutputDefine): PropertyDecorator {
return (target, propertyKey) => {
target = Decorator.target(target, propertyKey);
Reflect.defineMetadata(PLUGIN_DOWNLOAD_KEY, output, target, propertyKey);
};
}

View File

@@ -0,0 +1,10 @@
export type EmailSend = {
userId: number;
subject: string;
content: string;
receivers: string[];
};
export interface IEmailService {
send(email: EmailSend): Promise<void>;
}

View File

@@ -0,0 +1 @@
export * from "./email";

View File

@@ -0,0 +1,16 @@
import fs from "fs";
function getFileRootDir(rootDir?: string) {
if (rootDir == null) {
const userHome = process.env.HOME || process.env.USERPROFILE;
rootDir = userHome + "/.certd/storage/";
}
if (!fs.existsSync(rootDir)) {
fs.mkdirSync(rootDir, { recursive: true });
}
return rootDir;
}
export const fileUtils = {
getFileRootDir,
};

View File

@@ -0,0 +1,13 @@
export function TimeoutPromise(callback: () => Promise<void>, ms = 30 * 1000) {
let timeout: any;
return Promise.race([
callback(),
new Promise((resolve, reject) => {
timeout = setTimeout(() => {
reject(new Error(`Task timeout in ${ms} ms`));
}, ms);
}),
]).finally(() => {
clearTimeout(timeout);
});
}

View File

@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-aliyun
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-aliyun
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-aliyun
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-aliyun
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Features
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-aliyun

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-aliyun",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -23,10 +23,10 @@
"node-forge": "^0.10.0"
},
"devDependencies": {
"@certd/acme-client": "^1.0.6",
"@certd/pipeline": "^1.0.6",
"@certd/plugin-cert": "^1.0.6",
"@certd/plugin-util": "^1.0.6",
"@certd/acme-client": "^1.1.5",
"@certd/pipeline": "^1.1.5",
"@certd/plugin-cert": "^1.1.5",
"@certd/plugin-util": "^1.1.5",
"@midwayjs/core": "^3.0.0",
"@midwayjs/decorator": "^3.0.0",
"@rollup/plugin-commonjs": "^23.0.4",
@@ -59,5 +59,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
// @ts-ignore
import { ROAClient } from "@alicloud/pop-core";
import { AliyunAccess } from "../../access";
@@ -103,11 +103,13 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
})
accessId!: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
async onInstance(): Promise<void> {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
console.log("开始部署证书到阿里云cdn");
const { regionId, ingressClass, clusterId, isPrivateIpAddress, cert } = this;

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
import dayjs from "dayjs";
import Core from "@alicloud/pop-core";
import RPCClient from "@alicloud/pop-core";
@@ -17,7 +17,7 @@ import { AliyunAccess } from "../../access";
export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
@TaskInput({
title: "CDN加速域名",
helper: "你在阿里云上配置的CDN加速域名比如certd.docmirror.cn",
helper: "你在阿里云上配置的CDN加速域名比如:certd.docmirror.cn",
required: true,
})
domainName!: string;
@@ -49,13 +49,13 @@ export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
})
accessId!: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
console.log("开始部署证书到阿里云cdn");
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import Core from "@alicloud/pop-core";
import { AliyunAccess } from "../../access";
import { appendTimeSuffix, checkRet, ZoneOptions } from "../../utils";
@@ -59,14 +59,13 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
})
aliyunCertId!: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: Logger;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
console.log("开始部署证书到阿里云cdn");

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-all
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-all
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-all
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-all
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-all
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-all

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-all",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -17,12 +17,12 @@
"preview": "vite preview"
},
"devDependencies": {
"@certd/pipeline": "^1.0.6",
"@certd/plugin-aliyun": "^1.0.6",
"@certd/plugin-cert": "^1.0.6",
"@certd/plugin-host": "^1.0.6",
"@certd/plugin-huawei": "^1.0.6",
"@certd/plugin-tencent": "^1.0.6",
"@certd/pipeline": "^1.1.5",
"@certd/plugin-aliyun": "^1.1.5",
"@certd/plugin-cert": "^1.1.5",
"@certd/plugin-host": "^1.1.5",
"@certd/plugin-huawei": "^1.1.5",
"@certd/plugin-tencent": "^1.1.5",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
@@ -48,5 +48,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -3,6 +3,39 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-cert
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-cert
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-cert
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-cert
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Bug Fixes
* 修复access选择类型trigger ([2851a33](https://github.com/certd/certd/commit/2851a33eb2510f038fadb55da29512597a4ba512))
### Features
* save files ([99522fb](https://github.com/certd/certd/commit/99522fb49adb42c1dfdf7bec3dd52d641158285b))
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-cert

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -17,8 +17,9 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/acme-client": "^1.0.6",
"@certd/pipeline": "^1.0.6",
"@certd/acme-client": "^1.1.5",
"@certd/pipeline": "^1.1.5",
"jszip": "^3.10.1",
"node-forge": "^0.10.0"
},
"devDependencies": {
@@ -56,5 +57,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -1,12 +1,11 @@
import { AbstractTaskPlugin, Autowire, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
import { AbstractTaskPlugin, Decorator, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
import dayjs from "dayjs";
import { AcmeService, CertInfo } from "./acme";
import _ from "lodash";
import { Logger } from "log4js";
import { Decorator } from "@certd/pipeline";
import { DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider";
import { CertReader } from "./cert-reader";
import JSZip from "jszip";
export { CertReader };
export type { CertInfo };
@@ -73,6 +72,13 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
},
required: true,
helper: "请选择dns解析提供商授权",
reference: [
{
src: "form.dnsProviderType",
dest: "component.type",
type: "computed",
},
],
})
dnsProviderAccess!: string;
@@ -102,22 +108,11 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
})
csrInfo: any;
// @ts-ignore
acme: AcmeService;
@Autowire()
acme!: AcmeService;
logger!: Logger;
@Autowire()
userContext!: IContext;
@Autowire()
accessService!: IAccessService;
@Autowire()
http!: HttpClient;
@Autowire()
lastStatus!: Step;
@TaskOutput({
@@ -126,17 +121,23 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
cert?: CertInfo;
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
this.userContext = this.ctx.userContext;
this.http = this.ctx.http;
this.lastStatus = this.ctx.lastStatus as Step;
this.acme = new AcmeService({ userContext: this.userContext, logger: this.logger });
}
async execute(): Promise<void> {
const oldCert = await this.condition();
if (oldCert != null) {
return this.output(oldCert);
return await this.output(oldCert.toCertInfo());
}
const cert = await this.doCertApply();
if (cert != null) {
this.output(cert.toCertInfo());
await this.output(cert.toCertInfo());
//清空后续任务的状态,让后续任务能够重新执行
this.clearLastStatus();
} else {
@@ -144,8 +145,17 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
}
}
output(cert: CertInfo) {
async output(cert: CertInfo) {
this.cert = cert;
await this.zipCert(cert);
}
async zipCert(cert: CertInfo) {
const zip = new JSZip();
zip.file("cert.crt", cert.crt);
zip.file("cert.key", cert.key);
const content = await zip.generateAsync({ type: "nodebuffer" });
this.saveFile("cert.zip", content);
}
/**

View File

@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-host
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-host
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-host
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-host
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Features
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-host

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-host",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -17,8 +17,8 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/pipeline": "^1.0.6",
"@certd/plugin-cert": "^1.0.6",
"@certd/pipeline": "^1.1.5",
"@certd/plugin-cert": "^1.1.5",
"ssh2": "^0.8.9"
},
"devDependencies": {
@@ -57,5 +57,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -61,6 +61,9 @@ export class SshClient {
return new Promise((resolve, reject) => {
this.connect({
connectConf,
onError(err: any) {
reject(err);
},
onReady: (conn: any) => {
conn.exec(script, (err: Error, stream: any) => {
if (err) {
@@ -98,6 +101,10 @@ export class SshClient {
return new Promise((resolve, reject) => {
this.connect({
connectConf,
onError: (err: any) => {
this.logger.error(err);
reject(err);
},
onReady: (conn: any) => {
conn.shell((err: Error, stream: any) => {
if (err) {
@@ -122,10 +129,13 @@ export class SshClient {
});
}
connect(options: { connectConf: any; onReady: any }) {
const { connectConf, onReady } = options;
connect(options: { connectConf: any; onReady: any; onError: any }) {
const { connectConf, onReady, onError } = options;
const conn = new ssh2.Client();
conn
.on("error", (err: any) => {
onError(err);
})
.on("ready", () => {
this.logger.info("Client :: ready");
onReady(conn);

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
import { SshClient } from "../../lib/ssh";
@IsTaskPlugin({
@@ -32,13 +32,12 @@ export class HostShellExecutePlugin extends AbstractTaskPlugin {
})
script!: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const { script, accessId } = this;
const connectConf = await this.accessService.getById(accessId);

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import { SshClient } from "../../lib/ssh";
import { CertInfo, CertReader } from "@certd/plugin-cert";
import * as fs from "fs";
@@ -49,11 +49,6 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
})
sudo!: boolean;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
@TaskOutput({
title: "证书保存路径",
})
@@ -64,7 +59,13 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
})
hostKeyPath!: string;
async onInstance() {}
accessService!: IAccessService;
logger!: ILogger;
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const { crtPath, keyPath, cert, accessId, sudo } = this;
const certReader = new CertReader(cert);

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-huawei
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-huawei
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-huawei
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-huawei
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-huawei
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-huawei

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-huawei",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -17,10 +17,10 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/acme-client": "^1.0.6",
"@certd/pipeline": "^1.0.6",
"@certd/plugin-cert": "^1.0.6",
"@certd/plugin-util": "^1.0.6",
"@certd/acme-client": "^1.1.5",
"@certd/pipeline": "^1.1.5",
"@certd/plugin-cert": "^1.1.5",
"@certd/plugin-util": "^1.1.5",
"axios": "^0.27.2",
"dayjs": "^1.11.6",
"lodash": "^4.17.21",
@@ -59,5 +59,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-tencent
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-tencent
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-tencent
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-tencent
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Features
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-tencent

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-tencent",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -17,9 +17,9 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/pipeline": "^1.0.6",
"@certd/plugin-cert": "^1.0.6",
"@certd/plugin-util": "^1.0.6",
"@certd/pipeline": "^1.1.5",
"@certd/plugin-cert": "^1.1.5",
"@certd/plugin-util": "^1.1.5",
"tencentcloud-sdk-nodejs": "^4.0.44"
},
"devDependencies": {
@@ -58,5 +58,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
import tencentcloud from "tencentcloud-sdk-nodejs/index";
import { TencentAccess } from "../../access";
import { CertInfo } from "@certd/plugin-cert";
@@ -47,14 +47,14 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
})
domainName!: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const accessProvider: TencentAccess = (await this.accessService.getById(this.accessId)) as TencentAccess;

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
import tencentcloud from "tencentcloud-sdk-nodejs/index";
import { TencentAccess } from "../../access";
import dayjs from "dayjs";
@@ -71,14 +71,13 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
})
accessId!: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const accessProvider = (await this.accessService.getById(this.accessId)) as TencentAccess;
const client = this.getClient(accessProvider, this.region);

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
import tencentcloud from "tencentcloud-sdk-nodejs/index";
import { K8sClient } from "@certd/plugin-util";
import dayjs from "dayjs";
@@ -80,15 +80,12 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
})
cert!: any;
@Autowire()
logger!: Logger;
@Autowire()
accessService!: IAccessService;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const accessProvider = this.accessService.getById(this.accessId);
const tkeClient = this.getTkeClient(accessProvider, this.region);

View File

@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import tencentcloud from "tencentcloud-sdk-nodejs/index";
import dayjs from "dayjs";
@@ -42,14 +42,13 @@ export class UploadToTencentPlugin extends AbstractTaskPlugin {
})
tencentCertId?: string;
@Autowire()
accessService!: IAccessService;
@Autowire()
logger!: ILogger;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const { accessId, name, cert } = this;

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-util
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Performance Improvements
* timeout ([3eeb1f7](https://github.com/certd/certd/commit/3eeb1f77aa2922f3545f3d2067f561d95621d54f))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-util
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/plugin-util
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-util
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
**Note:** Version bump only for package @certd/plugin-util
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/plugin-util

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-util",
"private": false,
"version": "1.0.6",
"version": "1.1.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
@@ -21,7 +21,7 @@
"shelljs": "^0.8.5"
},
"devDependencies": {
"@certd/pipeline": "^1.0.6",
"@certd/pipeline": "^1.1.5",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
@@ -44,5 +44,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "5950e1cae7cf30ebfc5128c15c7d1b0d101cbbb8"
"gitHead": "b258e926209fef4cc4d633b0383eb54e26c516f9"
}

View File

@@ -1,3 +1,4 @@
VITE_APP_API=/api
#登录与权限关闭
VITE_APP_PM_ENABLED=true
VITE_APP_TITLE=Certd

View File

@@ -1,3 +1,3 @@
VITE_APP_API=http://www.docmirror.cn:7001/api
VITE_APP_API=/api
#登录与权限开启
VITE_APP_PM_ENABLED=true

View File

@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.5](https://github.com/certd/certd/compare/v1.1.4...v1.1.5) (2023-07-03)
**Note:** Version bump only for package @certd/ui-client
## [1.1.4](https://github.com/certd/certd/compare/v1.1.3...v1.1.4) (2023-07-03)
### Bug Fixes
* 成功图标转动的问题 ([f87eee3](https://github.com/certd/certd/commit/f87eee3b9ff1ef9874e79a81fe0ed7104cb9ee8c))
### Performance Improvements
* cancel task ([bc65c0a](https://github.com/certd/certd/commit/bc65c0a786360c087fe95cad93ec6a87804cc5ee))
* flush log ([891a43a](https://github.com/certd/certd/commit/891a43ae6716ff98ed06643f7da2e35199ee195c))
## [1.1.3](https://github.com/certd/certd/compare/v1.1.2...v1.1.3) (2023-07-03)
**Note:** Version bump only for package @certd/ui-client
## [1.1.2](https://github.com/certd/certd/compare/v1.1.1...v1.1.2) (2023-07-03)
**Note:** Version bump only for package @certd/ui-client
## [1.1.1](https://github.com/certd/certd/compare/v1.1.0...v1.1.1) (2023-06-28)
**Note:** Version bump only for package @certd/ui-client
# [1.1.0](https://github.com/certd/certd/compare/v1.0.6...v1.1.0) (2023-06-28)
### Bug Fixes
* 修复access选择类型trigger ([2851a33](https://github.com/certd/certd/commit/2851a33eb2510f038fadb55da29512597a4ba512))
### Features
* 权限控制 ([27a4c81](https://github.com/certd/certd/commit/27a4c81c6d70e70abb3892c3ea58d4719988808a))
* 邮件通知 ([937e3fa](https://github.com/certd/certd/commit/937e3fac19cd03b8aa91db8ba03fda7fcfbacea2))
* cert download ([5a51c14](https://github.com/certd/certd/commit/5a51c14de521cb8075a80d2ae41a16e6d5281259))
* save files ([671d273](https://github.com/certd/certd/commit/671d273e2f9136d16896536b0ca127cf372f1619))
## [1.0.6](https://github.com/certd/certd/compare/v1.0.5...v1.0.6) (2023-05-25)
**Note:** Version bump only for package @certd/ui-client

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" href="/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>antdv-fast-crud</title>
<title>Certd-让你的证书永不过期</title>
<link rel="stylesheet" type="text/css" href="/index.css" />
</head>
<body>
@@ -14,8 +14,8 @@
<div class="fs-bootstrap__loading"></div>
</div>
<div class="fs-bootstrap__footer">
<a href="https://github.com/fast-crud/fast-crud" target="_blank">
https://github.com/fast-crud/fast-crud
<a href="https://github.com/certd/certd" target="_blank">
https://github.com/certd/certd
</a>
</div>
</div>

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.0.6",
"version": "1.1.5",
"private": true,
"scripts": {
"dev": "vite",
@@ -22,12 +22,11 @@
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.0.1",
"@certd/acme-client": "^1.0.6",
"@certd/pipeline": "^1.0.6",
"@fast-crud/fast-crud": "^1.13.8",
"@fast-crud/fast-extends": "^1.13.8",
"@fast-crud/ui-antdv": "^1.13.8",
"@fast-crud/ui-interface": "^1.13.8",
"@certd/acme-client": "^1.1.5",
"@fast-crud/fast-crud": "^1.14.4",
"@fast-crud/fast-extends": "^1.14.4",
"@fast-crud/ui-antdv": "^1.14.4",
"@fast-crud/ui-interface": "^1.14.4",
"@iconify/iconify": "^3.0.1",
"@iconify/json": "^2.1.151",
"@purge-icons/generated": "^0.9.0",
@@ -60,9 +59,11 @@
"vuedraggable": "^4.0.1"
},
"devDependencies": {
"@certd/pipeline": "^1.1.5",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-node-resolve": "^15.0.1",
"@types/chai": "^4.3.4",
"@types/lodash-es": "^4.17.7",
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.15",
"@typescript-eslint/eslint-plugin": "^5.46.1",
@@ -73,7 +74,7 @@
"@vue/compiler-sfc": "^3.2.45",
"@vue/eslint-config-typescript": "^11.0.2",
"@vue/test-utils": "^2.2.6",
"autoprefixer": "^10.4.12",
"autoprefixer": "^10.4.14",
"caller-path": "^4.0.0",
"chai": "^4.3.7",
"eslint": "8.29.0",
@@ -88,7 +89,7 @@
"less": "^4.1.3",
"less-loader": "^11.0.0",
"lint-staged": "^13.1.0",
"postcss": "^8.4.20",
"postcss": "^8.4.23",
"prettier": "2.8.1",
"pretty-quick": "^3.1.3",
"rimraf": "^3.0.2",
@@ -97,7 +98,7 @@
"stylelint": "^14.16.0",
"stylelint-config-prettier": "^9.0.4",
"stylelint-order": "^5.0.0",
"tailwindcss": "^3.2.4",
"tailwindcss": "^3.3.2",
"ts-node": "^10.9.1",
"typescript": "4.9.4",
"vite": "^4.0.1",
@@ -106,10 +107,8 @@
"vite-plugin-package-config": "^0.1.1",
"vite-plugin-purge-icons": "^0.9.2",
"vite-plugin-theme": "^0.8.1",
"vite-plugin-windicss": "^1.8.10",
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^0.40.13",
"windicss": "^3.5.6"
"vue-tsc": "^0.40.13"
},
"husky": {
"hooks": {

View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -1,106 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="210mm"
height="210mm"
viewBox="0 0 210 210"
version="1.1"
id="svg8"
>
<g id="layer1" style="display:inline">
<path
style="fill:#002255;stroke:none;stroke-width:0.625348"
d="M 35.587501,69.766667 V 59.766664 h 70.000109 69.99991 v 10.000003 9.999997 H 105.58761 35.587501 Z"
id="path12" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-2"
width="32.244232"
height="20"
x="71.506088"
y="106.64581" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-8-8"
width="32.244232"
height="20"
x="107.42467"
y="106.64581" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-8-5-8"
width="32.244232"
height="20"
x="143.34325"
y="106.64581" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-2-4"
width="32.244232"
height="20"
x="71.506088"
y="129.82079" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-8-8-3"
width="32.244232"
height="20"
x="107.42467"
y="129.82079" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-8-5-8-2"
width="32.244232"
height="20"
x="143.34325"
y="129.82079" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-2-7"
width="32.244232"
height="20"
x="35.587502"
y="106.64581" />
<rect
style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-2-4-0"
width="32.244232"
height="20"
x="35.587502"
y="129.82079" />
<rect
style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-2-9"
width="32.244232"
height="20"
x="71.506088"
y="82.941666" />
<rect
style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-8-8-37"
width="32.244232"
height="20"
x="107.42467"
y="82.941666" />
<rect
style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-8-5-8-4"
width="32.244232"
height="20"
x="143.34325"
y="82.941666" />
<rect
style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
id="rect22-2-7-1"
width="32.244232"
height="20"
x="35.587502"
y="82.941666" />
</g>
<polygon
points="75.3,174.4 103.1,103.6 79.8,103.6 112.6,41.3 156.4,41.3 129.9,90.5 148.1,90.5 "
fill="#f6cc00"
id="polygon276"
transform="matrix(1.0930933,0,0,0.99853202,-17.517362,-0.52287941)" />
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="500" height="500" viewBox="0 0 500.000000 500.000000"
>
<path d="M28.34 56.68h28.34V36.12H28.34a7.79 7.79 0 1 1 0-15.58h19.84v9.05h8.5V12H28.34a16.29 16.29 0 0 0 0 32.58h19.84v3.56H28.34a19.84 19.84 0 0 1 0-39.68h28.34V0H28.34a28.34 28.34 0 0 0 0 56.68z"
transform="translate(70, 76) scale(6,6)"
></path>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 402 B

View File

@@ -11,9 +11,9 @@ import { provide, ref, nextTick } from "vue";
import { usePageStore } from "/src/store/modules/page";
import { useResourceStore } from "/src/store/modules/resource";
import { useSettingStore } from "/@/store/modules/settings";
import 'dayjs/locale/zh-cn';
import 'dayjs/locale/en';
import dayjs from 'dayjs'
import "dayjs/locale/zh-cn";
import "dayjs/locale/en";
import dayjs from "dayjs";
export default {
name: "App",
setup() {
@@ -29,13 +29,13 @@ export default {
console.log("locale changed:", value);
if (value === "zh-cn") {
locale.value = zhCN;
dayjs.locale('zh-cn');
dayjs.locale("zh-cn");
} else if (value === "en") {
locale.value = enUS;
dayjs.locale('en');
dayjs.locale("en");
}
}
localeChanged('zh-cn')
localeChanged("zh-cn");
provide("fn:router.reload", reload);
provide("fn:locale.changed", localeChanged);

View File

@@ -1,5 +1,11 @@
import { request, requestForMock } from "../service";
import { env } from "/@/utils/util.env";
export interface RegisterReq {
username: string;
password: string;
confirmPassword: string;
}
/**
* @description: Login interface parameters
*/
@@ -19,6 +25,14 @@ export interface LoginRes {
expire: number;
}
export async function register(user: RegisterReq): Promise<UserInfoRes> {
return await request({
url: "/register",
method: "post",
data: user
});
}
export async function login(data: LoginReq): Promise<LoginRes> {
if (env.PM_ENABLED === "false") {
//没有开启权限模块,模拟登录

View File

@@ -1,5 +1,5 @@
import axios from "axios";
import { get } from "lodash";
import { get } from "lodash-es";
import Adapter from "axios-mock-adapter";
import { errorLog, errorCreate } from "./tools";
import { env } from "/src/utils/util.env";
@@ -31,7 +31,7 @@ function createService() {
const { code } = dataAxios;
// 根据 code 进行判断
if (code === undefined) {
// 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
// 如果没有 code 代表这不是项目后端开发的接口
errorCreate(`非标准返回:${dataAxios} ${response.config.url}`);
return dataAxios;
} else {
@@ -106,8 +106,8 @@ function createService() {
* @description 创建请求方法
* @param {Object} service axios 实例
*/
function createRequestFunction(service) {
return function (config) {
function createRequestFunction(service: any) {
return function (config: any) {
const configDefault = {
headers: {
"Content-Type": get(config, "headers.Content-Type", "application/json")

View File

@@ -48,9 +48,12 @@ export function responseError(data = {}, msg = "请求失败", code = 500) {
* @description 记录和显示错误
* @param {Error} error 错误对象
*/
export function errorLog(error) {
export function errorLog(error: any) {
if (error?.response?.data?.message) {
error.message = error?.response?.data?.message;
}
// 打印到控制台
console.error(error);
console.error("errorLog", error);
// 显示提示
uiContext.get().notification.error({ message: error.message });
}
@@ -59,8 +62,9 @@ export function errorLog(error) {
* @description 创建一个错误
* @param {String} msg 错误信息
*/
export function errorCreate(msg) {
const error = new Error(msg);
errorLog(error);
throw error;
export function errorCreate(msg: string) {
const err = new Error(msg);
console.error("errorCreate", err);
uiContext.get().notification.error({ message: err.message });
throw err;
}

View File

@@ -1,20 +1,13 @@
import { createI18n } from "vue-i18n";
//
import enFsLocale from "@fast-crud/fast-crud/dist/locale/lang/en.js";
import zhFsLocale from "@fast-crud/fast-crud/dist/locale/lang/zh-cn.js";
import en from "./locale/en";
import zh from "./locale/zh_CN";
const messages = {
en: {
label: "English",
// 定义您自己的字典,但是请不要和 `fs` 重复,这样会导致 fast-crud 内部组件的翻译失效.
fs: enFsLocale.fs,
...en
},
"zh-cn": {
label: "简体中文",
// 定义您自己的字典,但是请不要和 `fs` 重复,这样会导致 fast-crud 内部组件的翻译失效.
fs: zhFsLocale.fs,
...zh
}
};

View File

@@ -1,6 +1,9 @@
<template>
<a-dropdown class="fs-locale-picker">
<fs-iconify icon="ion-globe-outline" @click.prevent></fs-iconify>
<div>
<fs-iconify icon="ion-globe-outline" @click.prevent></fs-iconify>
</div>
<template #overlay>
<a-menu @click="changeLocale">
<a-menu-item v-for="item in languages" :key="item.key" :command="item.key">
@@ -22,7 +25,7 @@
<script>
import i18n from "../../../i18n";
import { computed, inject } from "vue";
import _ from "lodash";
import _ from "lodash-es";
export default {
name: "FsLocale",
setup() {
@@ -46,7 +49,7 @@ export default {
const changeLocale = (change) => {
i18n.global.locale.value = change.key;
routerReload();
localeChanged(change.key)
localeChanged(change.key);
};
return {
languages,
@@ -58,7 +61,7 @@ export default {
</script>
<style lang="less">
.locale-picker {
.fs-locale-picker {
display: flex;
align-items: center;
}

View File

@@ -1,7 +1,7 @@
import { useRoute, useRouter } from "vue-router";
import { ref, watch, onMounted, onUnmounted, resolveComponent, nextTick, defineComponent } from "vue";
import getEachDeep from "deepdash-es/getEachDeep";
import _ from "lodash";
import _ from "lodash-es";
import BScroll from "better-scroll";
import "./index.less";
const eachDeep = getEachDeep(_);

View File

@@ -1,4 +1,4 @@
<template xmlns:w="http://www.w3.org/1999/xhtml">
<template>
<a-layout class="fs-framework">
<a-layout-sider v-model:collapsed="asideCollapsed" :trigger="null" collapsible>
<div class="header-logo">
@@ -49,10 +49,10 @@
</router-view>
</a-layout-content>
<a-layout-footer class="fs-framework-footer">
<div>Powered by Greper</div>
<div>Powered by handsfree.work</div>
<div>v{{ version }}</div>
<fs-source-link />
<!-- <fs-source-link />-->
</a-layout-footer>
</a-layout>
</a-layout>
@@ -95,7 +95,7 @@ export default {
}
onErrorCaptured((e) => {
console.error("ErrorCaptured:", e);
notification.error({ message: e.message });
// notification.error({ message: e.message });
//阻止错误向上传递
return false;
});

View File

@@ -2,10 +2,7 @@ import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.less";
// import "virtual:windi.css";
import "./style/common.less";
import "./mock";
import i18n from "./i18n";
import store from "./store";
import components from "./components";

View File

@@ -1,4 +1,4 @@
import _ from "lodash";
import _ from "lodash-es";
function copyList(originList, newList, options, parentId) {
for (const item of originList) {
const newItem = { ...item, parentId };

View File

@@ -1,4 +1,4 @@
import _ from "lodash";
import _ from "lodash-es";
export async function getPcasData() {
const pcasData = () => import("china-division/dist/pcas-code.json");
const ret = await pcasData();

View File

@@ -1,6 +1,6 @@
import { mock } from "../api/service";
import * as tools from "../api/tools";
import _ from "lodash";
import _ from "lodash-es";
const commonMocks = import.meta.globEager("./common/mock.*.js");
const apiMocks = import.meta.globEager("../api/modules/*.mock.ts");
const viewMocks = import.meta.globEager("../views/**/mock.js");

View File

@@ -1,225 +0,0 @@
import { request, requestForMock } from "/src/api/service";
import "/src/mock";
import UiAntdv from "@fast-crud/ui-antdv";
import { FastCrud, UseCrudProps, useTypes, setLogger } from "@fast-crud/fast-crud";
import "@fast-crud/fast-crud/dist/style.css";
import { FsExtendsUploader, FsExtendsEditor, FsExtendsJson, FsExtendsCopyable, FsExtendsTime } from "@fast-crud/fast-extends";
import "@fast-crud/fast-extends/dist/style.css";
import { useCrudPermission } from "../permission";
function install(app, options: any = {}) {
app.use(UiAntdv);
//设置日志级别
setLogger({ level: "debug" });
app.use(FastCrud, {
i18n: options.i18n,
async dictRequest({ url }) {
if (url && url.startsWith("/mock")) {
//如果是crud开头的dict请求视为mock
return await requestForMock({ url, method: "post" });
}
return await request({ url, method: "post" });
},
/**
* useCrud时会被执行
* @param contextuseCrud的参数
*/
commonOptions(context: UseCrudProps) {
const crudBinding = context.expose?.crudBinding;
const opts = {
table: {
size: "small",
pagination: false,
onResizeColumn: (w, col) => {
crudBinding.value.table.columnsMap[col.key].width = w;
}
},
rowHandle: {
buttons: {
view: { type: "link", text: null, icon: "ion:eye-outline" },
edit: { type: "link", text: null, icon: "ion:create-outline" },
remove: { type: "link", style: { color: "red" }, text: null, icon: "ion:trash-outline" }
},
dropdown: {
more: {
type: "link"
}
}
},
request: {
transformQuery: ({ page, form, sort }) => {
const limit = page.pageSize;
const currentPage = page.currentPage ?? 1;
const offset = limit * (currentPage - 1);
sort = sort == null ? {} : sort;
return {
page: {
limit,
offset
},
query: form,
sort
};
},
transformRes: ({ res }) => {
const pageSize = res.limit;
let currentPage = res.offset / pageSize;
if (res.offset % pageSize === 0) {
currentPage++;
}
return { currentPage, pageSize, ...res };
}
},
form: {
display: "flex",
labelCol: {
//固定label宽度
span: null,
style: {
width: "120px"
}
},
wrapperCol: {
span: null
}
}
};
// 从 useCrud({permission}) 里获取permission参数去设置各个按钮的权限
const crudPermission = useCrudPermission({ permission: context.permission });
return crudPermission.merge(opts);
}
});
// fast-extends里面的扩展组件均为异步组件只有在使用时才会被加载并不会影响首页加载速度
//安装uploader 公共参数
app.use(FsExtendsUploader, {
defaultType: "cos",
cos: {
domain: "https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com",
bucket: "d2p-demo-1251260344",
region: "ap-guangzhou",
secretId: "", //
secretKey: "", // 传了secretKey 和secretId 代表使用本地签名模式(不安全,生产环境不推荐)
getAuthorization(custom) {
// 不传secretKey代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
return request({
url: "http://www.docmirror.cn:7070/api/upload/cos/getAuthorization",
method: "get"
}).then((ret) => {
// 返回结构如下
// ret.data:{
// TmpSecretId,
// TmpSecretKey,
// XCosSecurityToken,
// ExpiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization
// }
return ret;
});
},
successHandle(ret) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
}
},
alioss: {
domain: "https://d2p-demo.oss-cn-shenzhen.aliyuncs.com",
bucket: "d2p-demo",
region: "oss-cn-shenzhen",
accessKeyId: "",
accessKeySecret: "",
async getAuthorization(custom, context) {
// 不传accessKeySecret代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/alioss/getAuthorization",
method: "get"
});
console.log("ret", ret);
return ret;
},
sdkOpts: {
// sdk配置
secure: true // 默认为非https上传,为了安全设置为true
},
successHandle(ret) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
}
},
qiniu: {
bucket: "d2p-demo",
async getToken(options) {
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/qiniu/getToken",
method: "get"
});
return ret; // {token:xxx,expires:xxx}
},
successHandle(ret) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
},
domain: "http://d2p.file.handsfree.work/"
},
form: {
action: "http://www.docmirror.cn:7070/api/upload/form/upload",
name: "file",
withCredentials: false,
uploadRequest: async ({ action, file, onProgress }) => {
// @ts-ignore
const data = new FormData();
data.append("file", file);
return await request({
url: action,
method: "post",
headers: {
"Content-Type": "multipart/form-data"
},
timeout: 60000,
data,
onUploadProgress: (p) => {
onProgress({ percent: Math.round((p.loaded / p.total) * 100) });
}
});
},
successHandle(ret) {
// 上传完成后的结果处理, 此处应返回格式为{url:xxx}
return {
url: "http://www.docmirror.cn:7070" + ret,
key: ret.replace("/api/upload/form/download?key=", "")
};
}
}
});
//安装editor
app.use(FsExtendsEditor, {
//编辑器的公共配置
wangEditor: {}
});
app.use(FsExtendsJson);
app.use(FsExtendsTime);
app.use(FsExtendsCopyable);
const { addTypes } = useTypes();
addTypes({
time2: {
//如果与官方字段类型同名,将会覆盖官方的字段类型
form: { component: { name: "a-date-picker" } },
column: { component: { name: "fs-date-format", format: "YYYY-MM-DD" } },
valueBuilder(context) {
console.log("time2,valueBuilder", context);
}
}
});
}
export default {
install
};

View File

@@ -1,17 +1,17 @@
import { request, requestForMock } from "/src/api/service";
import "/src/mock";
import { FastCrud, UseCrudProps, useTypes, setLogger, useColumns, ColumnCompositionProps, MergeColumnPlugin, CrudOptions } from "@fast-crud/fast-crud";
import { ColumnCompositionProps, CrudOptions, FastCrud, setLogger, useColumns, UseCrudProps, useTypes } from "@fast-crud/fast-crud";
import "@fast-crud/fast-crud/dist/style.css";
import { FsExtendsUploader, FsExtendsEditor, FsExtendsJson, FsExtendsCopyable, FsExtendsTime } from "@fast-crud/fast-extends";
import { FsExtendsCopyable, FsExtendsEditor, FsExtendsJson, FsExtendsTime, FsExtendsUploader } from "@fast-crud/fast-extends";
import "@fast-crud/fast-extends/dist/style.css";
import UiAntdv from "@fast-crud/ui-antdv";
import _ from "lodash";
import _ from "lodash-es";
import { useCrudPermission } from "../permission";
import { App } from "vue";
function install(app, options: any = {}) {
function install(app: App, options: any = {}) {
app.use(UiAntdv);
//设置日志级别
setLogger({ level: "debug" });
setLogger({ level: "info" });
app.use(FastCrud, {
i18n: options.i18n,
async dictRequest({ url }) {
@@ -31,7 +31,7 @@ function install(app, options: any = {}) {
table: {
size: "small",
pagination: false,
onResizeColumn: (w, col) => {
onResizeColumn: (w: any, col: any) => {
crudBinding.value.table.columnsMap[col.key].width = w;
}
},
@@ -70,7 +70,7 @@ function install(app, options: any = {}) {
if (res.offset % pageSize === 0) {
currentPage++;
}
return { currentPage, pageSize, ...res };
return { currentPage, pageSize, total: res.total, records: res.records };
}
},
form: {
@@ -96,7 +96,9 @@ function install(app, options: any = {}) {
// fast-extends里面的扩展组件均为异步组件只有在使用时才会被加载并不会影响首页加载速度
//安装uploader 公共参数
app.use(FsExtendsUploader, {
// @ts-ignore
defaultType: "cos",
cos: {
domain: "https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com",
@@ -109,7 +111,7 @@ function install(app, options: any = {}) {
return request({
url: "http://www.docmirror.cn:7070/api/upload/cos/getAuthorization",
method: "get"
}).then((ret) => {
}).then((ret: any) => {
// 返回结构如下
// ret.data:{
// TmpSecretId,
@@ -132,7 +134,7 @@ function install(app, options: any = {}) {
region: "oss-cn-shenzhen",
accessKeyId: "",
accessKeySecret: "",
async getAuthorization(custom, context) {
async getAuthorization(custom: any, context: any) {
// 不传accessKeySecret代表使用临时签名模式,此时此参数必传(安全,生产环境推荐)
const ret = await request({
url: "http://www.docmirror.cn:7070/api/upload/alioss/getAuthorization",
@@ -183,7 +185,7 @@ function install(app, options: any = {}) {
},
timeout: 60000,
data,
onUploadProgress: (p) => {
onUploadProgress: (p: any) => {
onProgress({ percent: Math.round((p.loaded / p.total) * 100) });
}
});
@@ -214,7 +216,7 @@ function install(app, options: any = {}) {
//如果与官方字段类型同名,将会覆盖官方的字段类型
form: { component: { name: "a-date-picker" } },
column: { component: { name: "fs-date-format", format: "YYYY-MM-DD" } },
valueBuilder(context) {
valueBuilder(context: any) {
console.log("time2,valueBuilder", context);
}
}

View File

@@ -1 +1 @@
import "./iconfont.js"
import "./iconfont.js";

View File

@@ -1,8 +1,9 @@
import "./iconify";
import "./iconfont";
import FastCrud from "./fast-crud";
import FastCrud from "./fast-crud/index";
import permission from "./permission";
function install(app, options: any = {}) {
import { App } from "vue";
function install(app: App, options: any = {}) {
app.use(FastCrud, options);
app.use(permission);
}

View File

@@ -1,5 +1,5 @@
import { usePermission } from "/@/plugin/permission";
import _ from "lodash";
import _ from "lodash-es";
/**
* 设置按钮动作权限

View File

@@ -1,5 +1,5 @@
import LayoutPass from "/src/layout/layout-pass.vue";
import _ from "lodash";
import _ from "lodash-es";
import { outsideResource } from "./source/outside";
import { headerResource } from "./source/header";
import { frameworkResource } from "./source/framework";

View File

@@ -13,14 +13,14 @@ export const headerResource = [
children: [
{
title: "github",
path: "http://github.com/certd/certd",
path: "https://github.com/certd/certd",
meta: {
icon: "ion:logo-github"
}
},
{
title: "gitee",
path: "http://gitee.com/certd/certd",
path: "https://gitee.com/certd/certd",
meta: {
icon: "ion:logo-octocat"
}

View File

@@ -35,6 +35,38 @@ export const certdResources = [
meta: {
icon: "ion:disc-outline"
}
},
{
title: "设置",
name: "certdSettings",
path: "/certd/settings",
redirect: "/certd/settings/email",
meta: {
icon: "ion:settings-outline",
auth: true
},
children: [
{
title: "邮箱设置",
name: "email",
path: "/certd/settings/email",
component: "/certd/settings/email-setting.vue",
meta: {
icon: "ion:mail-outline",
auth: true
}
},
{
title: "账号信息",
name: "userProfile",
path: "/certd/mine/user-profile",
component: "/certd/mine/user-profile.vue",
meta: {
icon: "ion:person-outline",
auth: true
}
}
]
}
]
}

View File

@@ -15,6 +15,14 @@ export const outsideResource = [
name: "login",
path: "/login",
component: "/framework/login/index.vue"
},
{
meta: {
title: "注册"
},
name: "register",
path: "/register",
component: "/framework/register/index.vue"
}
]
},

View File

@@ -1,5 +1,5 @@
import { defineStore } from "pinia";
import { cloneDeep, get, uniq } from "lodash";
import { cloneDeep, get, uniq } from "lodash-es";
import router from "/src/router";
import { frameworkRoutes } from "/src/router/resolve";
// @ts-ignore
@@ -21,7 +21,7 @@ interface PageState {
inited: boolean;
}
// 判定是否需要缓存
const isKeepAlive = (data) => get(data, "meta.cache", false);
const isKeepAlive = (data: any) => get(data, "meta.cache", false);
export const usePageStore = defineStore({
id: "app.page",
@@ -48,6 +48,7 @@ export const usePageStore = defineStore({
inited: false
}),
getters: {
// @ts-ignore
getOpened() {
// @ts-ignore
return this.opened;
@@ -91,7 +92,7 @@ export const usePageStore = defineStore({
const valid: Array<number> = [];
// 处理数据
this.opened = value
.map((opened) => {
.map((opened: any) => {
// 忽略首页
if (opened.fullPath === "/index") {
valid.push(1);
@@ -105,7 +106,7 @@ export const usePageStore = defineStore({
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
return Object.assign({}, opened, find);
})
.filter((opened, index) => valid[index] === 1);
.filter((opened: any, index: any) => valid[index] === 1);
// 标记已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201
this.openedLoaded = true;
// 根据 opened 数据生成缓存设置
@@ -132,7 +133,7 @@ export const usePageStore = defineStore({
* @param {Object} context
* @param {Object} payload { index, params, query, fullPath } 路由信息
*/
async openedUpdate({ index, params, query, fullPath }) {
async openedUpdate({ index, params, query, fullPath }: any) {
// 更新页面列表某一项
const page = this.opened[index];
page.params = params || page.params;
@@ -148,7 +149,7 @@ export const usePageStore = defineStore({
* @param {Object} context
* @param {Object} payload { oldIndex, newIndex } 位置信息
*/
async openedSort({ oldIndex, newIndex }) {
async openedSort({ oldIndex, newIndex }: any) {
// 重排页面列表某一项
const page = this.opened[oldIndex];
this.opened.splice(oldIndex, 1);
@@ -162,7 +163,7 @@ export const usePageStore = defineStore({
* @param {Object} context
* @param {Object} payload new tag info
*/
async add({ tag, params, query, fullPath }) {
async add({ tag, params, query, fullPath }: any) {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
const newTag = tag;
newTag.params = params || newTag.params;
@@ -183,7 +184,7 @@ export const usePageStore = defineStore({
* @param {Object} context
* @param {Object} payload 从路由钩子的 to 对象上获取 { name, params, query, fullPath, meta } 路由信息
*/
async open({ name, params, query, fullPath, meta }) {
async open({ name, params, query, fullPath, meta }: any) {
// 已经打开的页面
const opened = this.opened;
// 判断此页面是否已经打开 并且记录位置
@@ -227,7 +228,7 @@ export const usePageStore = defineStore({
* @param {Object} context
* @param {Object} payload { tagName: 要关闭的标签名字 }
*/
async close({ tagName }) {
async close({ tagName }: any) {
// 预定下个新页面
let newPage = {};
const isCurrent = this.current === tagName;
@@ -267,7 +268,7 @@ export const usePageStore = defineStore({
*/
async closeLeft(opts = {}) {
await this.closeByCondition({
condition({ i, currentIndex }) {
condition({ i, currentIndex }: any) {
return i >= currentIndex;
},
...opts
@@ -280,7 +281,7 @@ export const usePageStore = defineStore({
*/
async closeRight(opts = {}) {
await this.closeByCondition({
condition({ i, currentIndex }) {
condition({ i, currentIndex }: any) {
return currentIndex >= i;
},
...opts
@@ -321,7 +322,7 @@ export const usePageStore = defineStore({
*/
async closeOther(opts = {}) {
await this.closeByCondition({
condition({ i, currentIndex }) {
condition({ i, currentIndex }: any) {
return currentIndex === i;
},
...opts
@@ -364,7 +365,7 @@ export const usePageStore = defineStore({
* @param {Object} state state
* @param {String} name name
*/
keepAliveRemove(name) {
keepAliveRemove(name: any) {
const list = cloneDeep(this.keepAlive);
const index = list.findIndex((item) => item === name);
if (index !== -1) {
@@ -377,7 +378,7 @@ export const usePageStore = defineStore({
* @param {Object} state state
* @param {String} name name
*/
keepAlivePush(name) {
keepAlivePush(name: any) {
const keep = cloneDeep(this.keepAlive);
keep.push(name);
this.keepAlive = uniq(keep);
@@ -395,7 +396,7 @@ export const usePageStore = defineStore({
* @param {Object} state state
* @param {String} fullPath new fullPath
*/
currentSet(fullPath) {
currentSet(fullPath: any) {
this.current = fullPath;
},
/**
@@ -404,7 +405,7 @@ export const usePageStore = defineStore({
* @param {Object} state state
* @param {Array} routes routes
*/
async init(routes) {
async init(routes: any) {
if (this.inited) {
return;
}
@@ -414,9 +415,9 @@ export const usePageStore = defineStore({
routes = frameworkRoutes;
}
const pool = [];
const push = function (routes) {
routes.forEach((route) => {
const pool: any = [];
const push = function (routes: any) {
routes.forEach((route: any) => {
if (route.children && route.children.length > 0) {
push(route.children);
} else {

View File

@@ -1,7 +1,7 @@
import { defineStore } from "pinia";
// @ts-ignore
import { frameworkMenus, headerMenus, filterMenus, findMenus } from "/src/router/resolve";
import _ from "lodash";
import _ from "lodash-es";
import { mitter } from "/src/utils/util.mitt";
//监听注销事件
mitter.on("app.logout", () => {
@@ -30,13 +30,19 @@ export const useResourceStore = defineStore({
currentAsidePath: ""
}),
getters: {
// @ts-ignore
getAsideMenus() {
// @ts-ignore
return this.asideMenus;
},
// @ts-ignore
getHeaderMenus() {
// @ts-ignore
return this.headerMenus;
},
// @ts-ignore
getFrameworkMenus() {
// @ts-ignore
return this.frameworkMenus;
}
},
@@ -54,17 +60,17 @@ export const useResourceStore = defineStore({
this.inited = true;
const showMenus = _.cloneDeep(frameworkMenus[0].children);
this.frameworkMenus = filterMenus(showMenus, (item) => {
this.frameworkMenus = filterMenus(showMenus, (item: any) => {
return item?.meta?.showOnHeader !== false;
});
this.fixedAsideMenus = findMenus(showMenus, (item) => {
this.fixedAsideMenus = findMenus(showMenus, (item: any) => {
return item?.meta?.fixedAside === true;
});
this.headerMenus = headerMenus;
this.setAsideMenu();
},
setAsideMenu(topMenu?) {
setAsideMenu(topMenu?: any) {
if (this.frameworkMenus.length === 0) {
return;
}
@@ -74,13 +80,13 @@ export const useResourceStore = defineStore({
const asideMenus = topMenu?.children || [];
this.asideMenus = [...this.fixedAsideMenus, ...asideMenus];
},
setAsideMenuByCurrentRoute(matched) {
setAsideMenuByCurrentRoute(matched: any) {
const menuHeader = this.frameworkMenus;
if (matched?.length <= 1) {
return;
}
function findFromTree(tree, find) {
function findFromTree(tree: any, find: any) {
const results: Array<any> = [];
for (const item of tree) {
if (find(item)) {
@@ -88,7 +94,7 @@ export const useResourceStore = defineStore({
return results;
}
if (item.children && item.children.length > 0) {
const found = findFromTree(item.children, find);
const found: any = findFromTree(item.children, find);
if (found) {
results.push(item);
return results.concat(found);
@@ -97,7 +103,7 @@ export const useResourceStore = defineStore({
}
}
const matchedPath = matched[1].path;
const _side = findFromTree(menuHeader, (menu) => menu.path === matchedPath);
const _side = findFromTree(menuHeader, (menu: any) => menu.path === matchedPath);
if (_side?.length > 0) {
if (this.currentAsidePath === _side[0]) {
return;
@@ -106,11 +112,11 @@ export const useResourceStore = defineStore({
this.setAsideMenu(_side[0]);
}
},
filterByPermission(permissions) {
filterByPermission(permissions: any) {
this.frameworkMenus = this.filterChildrenByPermission(this.frameworkMenus, permissions);
},
filterChildrenByPermission(list, permissions) {
const menus = list.filter((item) => {
filterChildrenByPermission(list: any, permissions: any) {
const menus = list.filter((item: any) => {
if (item?.meta?.permission) {
return permissions.includes(item.meta.permission);
}

View File

@@ -51,7 +51,7 @@ export const useSettingStore = defineStore({
this.persistTheme();
// await changeTheme(this.theme.primaryColor);
},
async setPrimaryColor(color) {
async setPrimaryColor(color: any) {
const theme = this.theme;
theme.primaryColor = color;
await this.setTheme();

View File

@@ -7,10 +7,11 @@ import { LocalStorage } from "/src/utils/util.storage";
import * as UserApi from "/src/api/modules/api.user";
// @ts-ignore
import { LoginReq, UserInfoRes } from "/@/api/modules/api.user";
import { Modal } from "ant-design-vue";
import { Modal, notification } from "ant-design-vue";
import { useI18n } from "vue-i18n";
import { mitter } from "/src/utils/util.mitt";
import { RegisterReq } from "/src/api/modules/api.user";
interface UserState {
userInfo: Nullable<UserInfoRes>;
@@ -50,6 +51,14 @@ export const useUserStore = defineStore({
LocalStorage.remove(TOKEN_KEY);
LocalStorage.remove(USER_INFO_KEY);
},
async register(user: RegisterReq) {
await UserApi.register(user);
notification.success({
message: "注册成功,请登录"
});
await router.replace("/login");
},
/**
* @description: login
*/

View File

@@ -1,8 +1,12 @@
@import './tailwind.less';
@import "ant-design-vue/dist/antd.less";
@import './theme/index.less';
@import './theme/default.less';
@import './scroll.less';
@import './transition.less';
@import './fix-windicss.less';
svg { vertical-align: baseline; }
html, body {
@@ -49,9 +53,7 @@ h1, h2, h3, h4, h5, h6 {
text-align: center;
}
.red{
color:red
}
.font12{
font-size: 12px;
@@ -88,27 +90,6 @@ h1, h2, h3, h4, h5, h6 {
}
}
.mt-10{
margin-top:10px;
}
.ml-5{
margin-left:5px;
}
.ml-10{
margin-left: 10px;
}
.mtb-5{
margin: 5px 0 5px 0;
}
.mb-10{
margin-bottom: 10px;
}
.mlr-5{
margin: 0 5px 0 5px;
}
.gray{
color:gray;
}
@@ -125,10 +106,6 @@ h1, h2, h3, h4, h5, h6 {
color:yellow;
}
.ml-2{
margin-left: 2px;
}
.font-20{
font-size:20px
}

View File

@@ -1,3 +1,4 @@
img.ant-image-preview-img{
display: initial;
}

View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,13 +1,13 @@
import _ from "lodash";
import _ from "lodash-es";
export default {
arrayToMap(array) {
arrayToMap(array: any) {
if (!array) {
return {};
}
if (!_.isArray(array)) {
return array;
}
const map = {};
const map: any = {};
for (const item of array) {
if (item.key) {
map[item.key] = item;
@@ -15,7 +15,7 @@ export default {
}
return map;
},
mapToArray(map) {
mapToArray(map: any) {
if (!map) {
return [];
}

View File

@@ -1,15 +1,16 @@
import _ from "lodash";
export function getEnvValue(key) {
// @ts-ignore
import _ from "lodash-es";
export function getEnvValue(key: string) {
// @ts-ignore
return import.meta.env["VITE_APP_" + key];
}
export class EnvConfig {
API;
MODE;
STORAGE;
TITLE;
PM_ENABLED;
API: string;
MODE: string;
STORAGE: string;
TITLE: string;
PM_ENABLED: string;
constructor() {
this.init();
}
@@ -19,6 +20,7 @@ export class EnvConfig {
_.forEach(import.meta.env, (value, key) => {
if (key.startsWith("VITE_APP")) {
key = key.replace("VITE_APP_", "");
//@ts-ignore
this[key] = value;
}
});
@@ -26,7 +28,8 @@ export class EnvConfig {
this.MODE = import.meta.env.MODE;
}
get(key, defaultValue) {
get(key: string, defaultValue: string) {
//@ts-ignore
return this[key] ?? defaultValue;
}
isDev() {

View File

@@ -2,9 +2,9 @@ import { env } from "./util.env";
export const site = {
/**
* @description 更新标题
* @param {String} title 标题
* @param titleText
*/
title: function (titleText) {
title: function (titleText: string) {
const processTitle = env.TITLE || "FsAdmin";
window.document.title = `${processTitle}${titleText ? ` | ${titleText}` : ""}`;
}

View File

@@ -1,5 +1,5 @@
import { env } from "./util.env";
function isNullOrUnDef(value) {
function isNullOrUnDef(value: any) {
return value == null;
}
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;

View File

@@ -2,7 +2,7 @@ import { ColumnCompositionProps, dict } from "@fast-crud/fast-crud";
// @ts-ignore
import * as api from "./api";
// @ts-ignore
import _ from "lodash";
import _ from "lodash-es";
import { toRef } from "vue";
export function getCommonColumnDefine(crudExpose: any, typeRef: any) {

View File

@@ -57,6 +57,9 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
name: {
title: "名称",
type: "text",
search: {
show: true
},
form: {
rules: [{ required: true, message: "必填项" }]
}

View File

@@ -1,7 +1,10 @@
<template>
<fs-page>
<template #header>
<div class="title">授权管理</div>
<div class="title">
授权管理
<span class="sub">管理第三方系统授权信息</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>

View File

@@ -0,0 +1,16 @@
import { request } from "/src/api/service";
export async function getMineInfo() {
return request({
url: "/mine/info",
method: "POST"
});
}
export async function changePassword(form: any) {
return request({
url: "/mine/changePassword",
method: "POST",
data: form
});
}

View File

@@ -0,0 +1,98 @@
<template>
<fs-page>
<div class="p-4">
<a-descriptions title="我的信息" bordered>
<a-descriptions-item label="用户名">{{ userInfo.userInfoname }}</a-descriptions-item>
<a-descriptions-item label="昵称">{{ userInfo.nickName }}</a-descriptions-item>
<a-descriptions-item label="邮箱">{{ userInfo.email }}</a-descriptions-item>
<a-descriptions-item label="手机号">{{ userInfo.phoneCode }}{{ userInfo.mobile }}</a-descriptions-item>
<a-descriptions-item label="修改密码">
<a-button type="primary" @click="changePassword">修改密码</a-button>
</a-descriptions-item>
</a-descriptions>
</div>
</fs-page>
</template>
<script lang="ts" setup>
import * as api from "./api";
import { Ref, ref } from "vue";
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
const userInfo: Ref = ref({});
const getUserInfo = async () => {
userInfo.value = await api.getMineInfo();
};
getUserInfo();
let passwordFormRef = ref();
const validatePass1 = async (rule: any, value: any) => {
if (value === "") {
throw new Error("请输入密码");
}
if (passwordFormRef.value.getFormData().confirmNewPassword !== "") {
passwordFormRef.value.formRef.formRef.validateFields(["confirmNewPassword"]);
}
};
const validatePass2 = async (rule: any, value: any) => {
if (value === "") {
throw new Error("请再次输入密码");
} else if (value !== passwordFormRef.value.getFormData().newPassword) {
throw new Error("两次输入密码不一致!");
}
};
const { openDialog } = useFormWrapper();
const { buildFormOptions } = useColumns();
const passwordFormOptions: CrudOptions = {
form: {
col: {
span: 24
},
wrapper: {
width: "500px"
},
async doSubmit({ form }) {
await api.changePassword(form);
}
},
columns: {
password: {
title: "旧密码",
type: "password",
form: {
rules: [{ required: true, message: "请输入旧密码" }]
}
},
newPassword: {
title: "新密码",
type: "password",
form: {
rules: [
{ required: true, message: "请输入确认密码" },
//@ts-ignore
{ validator: validatePass1, trigger: "blur" }
]
}
},
confirmNewPassword: {
title: "确认新密码",
type: "password",
form: {
rules: [
{ required: true, message: "请输入确认密码" },
//@ts-ignore
{ validator: validatePass2, trigger: "blur" }
]
}
}
}
};
async function changePassword() {
const formOptions = buildFormOptions(passwordFormOptions);
formOptions.newInstance = true; //新实例打开
passwordFormRef.value = await openDialog(formOptions);
}
</script>

View File

@@ -1,9 +1,9 @@
import { RunHistory } from "./pipeline/type";
import { request } from "/src/api/service";
import { RunHistory } from "/@/views/certd/pipeline/pipeline/type";
const apiPrefix = "/pi/history";
export async function GetList(query) {
export async function GetList(query: any) {
const list = await request({
url: apiPrefix + "/list",
method: "post",
@@ -18,7 +18,7 @@ export async function GetList(query) {
return list;
}
export async function GetDetail(query): Promise<RunHistory> {
export async function GetDetail(query: any): Promise<RunHistory> {
const detail = await request({
url: apiPrefix + "/detail",
method: "post",

View File

@@ -1,5 +1,5 @@
import { request } from "/src/api/service";
import _ from "lodash";
import _ from "lodash-es";
const apiPrefix = "/pi/plugin";
const defaultInputDefine = {
@@ -9,7 +9,7 @@ const defaultInputDefine = {
}
};
export async function GetList(query) {
export async function GetList(query: any) {
const plugins = await request({
url: apiPrefix + "/list",
method: "post",

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