refactor: remove certd v1 code

This commit is contained in:
xiaojunnuo
2022-10-31 21:27:32 +08:00
parent 6094a4af79
commit e68862b633
113 changed files with 181 additions and 4868 deletions
-16
View File
@@ -1,16 +0,0 @@
module.exports = {
root: true,
parserOptions: {
sourceType: 'module',
ecmaVersion: '2020'
},
parser: 'babel-eslint',
extends: ['standard'],
env: {
node: true
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}
-7
View File
@@ -1,7 +0,0 @@
.vscode/
node_modules/
npm-debug.log
yarn-error.log
yarn.lock
package-lock.json
/.idea/
-6
View File
@@ -1,6 +0,0 @@
FROM registry.cn-shenzhen.aliyuncs.com/greper/node:15.8.0-alpine
ENV TZ=Asia/Shanghai
EXPOSE 3000
ADD ./ /app/
RUN cd /app/ && ls
ENTRYPOINT node /app/bin/www.js
-59
View File
@@ -1,59 +0,0 @@
import Koa from 'koa'
import json from 'koa-json'
import onerror from 'koa-onerror'
import bodyparser from 'koa-bodyparser'
import logger from 'koa-logger'
import Static from 'koa-static'
import fs from 'fs'
import _ from 'lodash-es'
import './install.js'
import pathUtil from './utils/util.path.js'
import compress from 'koa-compress'
const app = new Koa()
// error handler
onerror(app)
// middlewares
app.use(bodyparser({
enableTypes: ['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
// gzip
// app.use(compress({ threshold: 5120 }))
const staticPlugin = Static(pathUtil.join('public'), {
maxage: 30 * 24 * 60 * 3600,
gzip: true
})
app.use(staticPlugin)
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
// routes
const files = fs.readdirSync(new URL('controllers/', import.meta.url))
// 过滤出.js文件:
const jsFiles = files.filter((f) => {
return f.endsWith('.js')
})
_.forEach(jsFiles, async item => {
let mapping = await import(new URL('controllers/' + item, import.meta.url))
mapping = mapping.default
app.use(mapping.routes(), mapping.allowedMethods())
})
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
})
console.log('http://localhost:3000/')
export default app
-93
View File
@@ -1,93 +0,0 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
import app from '../app.js';
import debuger from 'debug'
const debug = debuger('demo:serer')
// require('debug')('demo:server');
import http from 'http';
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
// app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app.callback());
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
@@ -1,16 +0,0 @@
import Router from 'koa-router'
import { accessProviderRegistry } from '@certd/api'
import _ from 'lodash-es'
import { Ret } from '../models/Ret.js'
const router = Router()
router.prefix('/api/access-providers')
router.get('/list', function (ctx, next) {
const list = []
_.forEach(accessProviderRegistry.collection, item => {
list.push(item.define())
})
ctx.body = Ret.success(list)
})
export default router
@@ -1,16 +0,0 @@
import Router from 'koa-router'
import { dnsProviderRegistry } from '@certd/api'
import _ from 'lodash-es'
import { Ret } from '../models/Ret.js'
const router = Router()
router.prefix('/api/dns-providers')
router.get('/list', function (ctx, next) {
const list = []
_.forEach(dnsProviderRegistry.collection, item => {
list.push(item.define())
})
ctx.body = Ret.success(list)
})
export default router
@@ -1,23 +0,0 @@
import Router from 'koa-router'
import fs from 'fs'
import exportsService from '../service/exports-service.js'
const router = Router()
router.prefix('/api/exports')
router.post('/toZip', async function (ctx, next) {
// const request = ctx.request
// const query = request.query
const body = ctx.request.body
// const req_queryString = request.queryString
const { zipPath, fileName } = await exportsService.exportsToZip(body.options, 'certd-run')
console.log('zipFile', zipPath)
ctx.set('Content-disposition', 'attachment;filename=' + fileName)
ctx.set('Content-Type', 'application/zip')
ctx.body = fs.createReadStream(zipPath)
//
// // ctx.body = Ret.success(zipPath)
})
export default router
@@ -1,10 +0,0 @@
import Router from 'koa-router'
const router = Router()
router.get('/api/', async (ctx, next) => {
await ctx.render('index', {
title: 'Hello CertD!'
})
})
export default router
@@ -1,16 +0,0 @@
import Router from 'koa-router'
import { pluginRegistry } from '@certd/api'
import _ from 'lodash-es'
import { Ret } from '../models/Ret.js'
const router = Router()
router.prefix('/api/plugins')
router.get('/list', function (ctx, next) {
const list = []
_.forEach(pluginRegistry.collection, item => {
list.push(item.define())
})
ctx.body = Ret.success(list)
})
export default router
-8
View File
@@ -1,8 +0,0 @@
import PluginAliyun from '@certd/plugin-aliyun'
import PluginTencent from '@certd/plugin-tencent'
import PluginHost from '@certd/plugin-host'
// 安装默认插件和授权提供者
PluginAliyun.install()
PluginTencent.install()
PluginHost.install()
-15
View File
@@ -1,15 +0,0 @@
export class Ret {
constructor (code = 0, msg, data) {
this.code = code
this.msg = msg
this.data = data
}
static success (data) {
return new Ret(0, '', data)
}
static error (msg) {
return new Ret(1, msg)
}
}
-43
View File
@@ -1,43 +0,0 @@
{
"name": "@certd/server",
"version": "0.2.2",
"private": false,
"type": "module",
"scripts": {
"start": "node bin/www.js",
"dev": "./node_modules/.bin/nodemon bin/www.js",
"prd": "pm2 start bin/www.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@certd/api": "^0.3.0",
"@certd/executor": "^0.3.0",
"@certd/plugin-aliyun": "^0.3.0",
"@certd/plugin-host": "^0.3.0",
"@certd/plugin-tencent": "^0.3.0",
"compressing": "^1.5.1",
"debug": "^4.1.1",
"fs-extra": "^9.1.0",
"koa": "^2.7.0",
"koa-bodyparser": "^4.2.1",
"koa-compress": "^5.0.1",
"koa-convert": "^1.2.0",
"koa-json": "^2.0.2",
"koa-logger": "^3.2.0",
"koa-onerror": "^4.1.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"koa-views": "^6.2.0",
"lodash-es": "^4.17.20"
},
"devDependencies": {
"babel-eslint": "^10.1.0",
"eslint": "^7.19.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"nodemon": "^1.19.1"
},
"gitHead": "5fbd7742665c0a949333d805153e9b6af91c0a71"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

@@ -1,17 +0,0 @@
<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"
fill="#2c3e50"
transform="translate(124, 60) scale(4,4)"
></path>
<path d="M13.00-21.91L21.24-21.91L21.24-17.23L14.04-17.23Q10.39-17.23 9-15.62L9-15.62Q7.65-14.08 7.65-10.93L7.65-10.93Q7.65-7.42 9.86-5.80L9.86-5.80Q10.75-5.17 11.81-4.93Q12.87-4.68 14.76-4.68L14.76-4.68L21.24-4.68L21.24 0L13.00 0Q9.67 0 7.74-0.67Q5.80-1.35 4.32-3.01L4.32-3.01Q1.48-6.17 1.48-11.03L1.48-11.03Q1.48-16.88 4.86-19.75L4.86-19.75Q6.21-20.93 8.10-21.42Q9.99-21.91 13.00-21.91L13.00-21.91ZM31.05-13.32L43.74-13.32L43.74-8.64L31.05-8.64Q31.23-6.48 32.44-5.58Q33.66-4.68 36.41-4.68L36.41-4.68L43.74-4.68L43.74 0L35.73 0Q33.12 0 31.48-0.47Q29.83-0.94 28.39-2.02L28.39-2.02Q24.39-5.13 24.39-11.25L24.39-11.25Q24.39-15.21 26.50-18.18L26.50-18.18Q27.94-20.20 29.97-21.06Q31.99-21.91 35.28-21.91L35.28-21.91L43.74-21.91L43.74-17.23L35.73-17.23Q33.25-17.23 32.27-16.40Q31.27-15.57 31.05-13.32L31.05-13.32ZM48.64 0L48.64-21.91L57.55-21.91Q60.30-21.91 61.81-21.53Q63.31-21.15 64.31-20.25L64.31-20.25Q65.30-19.35 65.70-18Q66.10-16.65 66.10-14.13L66.10-14.13L66.10-12.01L60.30-12.01L60.30-13.18Q60.30-15.52 59.49-16.38Q58.68-17.23 56.38-17.23L56.38-17.23L54.67-17.23L54.67 0L48.64 0ZM67.50-21.91L71.33-21.91L71.33-30.02L77.36-30.02L77.36-21.91L82.94-21.91L82.94-17.23L77.36-17.23L77.36-9.27Q77.36-6.48 77.85-5.76L77.85-5.76Q78.61-4.68 80.55-4.68L80.55-4.68L82.94-4.68L82.94 0L78.57 0Q74.66 0 72.99-1.89Q71.33-3.78 71.33-8.23L71.33-8.23L71.33-17.23L67.50-17.23L67.50-21.91ZM96.08-21.91L101.75-21.91L101.75-30.02L107.73-30.02L107.73 0L97.38 0Q94.23 0 92.61-0.49L92.61-0.49Q88.78-1.71 86.90-5.26L86.90-5.26Q85.59-7.65 85.59-11.12L85.59-11.12Q85.59-16.74 89.37-19.84L89.37-19.84Q91.84-21.91 96.08-21.91L96.08-21.91ZM97.38-4.68L101.75-4.68L101.75-17.23L97.38-17.23Q94.50-17.23 93.02-15.30L93.02-15.30Q91.71-13.68 91.71-11.12L91.71-11.12Q91.71-7.38 93.87-5.76L93.87-5.76Q95.36-4.68 97.38-4.68L97.38-4.68Z"
fill="#2c3e50"
transform="translate(28, 430) scale(4,4)"
></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,55 +0,0 @@
import os from 'os'
import fs from 'fs-extra'
import pathUtil from '../utils/util.path.js'
import cryptoRandomString from 'crypto-random-string'
import zipUtil from '../utils/util.zip.js'
import path from 'path'
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
export default {
async exportsToZip (options, dirName) {
const tempDir = os.tmpdir()
const targetDir = path.join(tempDir, 'certd-server', cryptoRandomString(10))
const projectName = dirName
const targetProjectDir = path.join(targetDir, projectName)
const templateDir = pathUtil.join('templates/' + projectName)
console.log('targetDir', targetDir)
console.log('projectName', projectName)
console.log('tempalteDir', templateDir)
console.log('targetProjectDir', targetProjectDir)
fs.copySync(templateDir, targetProjectDir)
// options
const optionsFilePath = path.join(targetProjectDir, 'options.json')
fs.writeJsonSync(optionsFilePath, options)
// 依赖版本
const exePkgJson = fs.readFileSync(pathUtil.join('node_modules/@certd/executor/package.json'))
const executorPkg = JSON.parse(exePkgJson)
const currentVersion = executorPkg.version
const templatePkgJson = fs.readFileSync(pathUtil.join('templates/certd-run/package.json'))
const templatePkg = JSON.parse(templatePkgJson)
templatePkg.dependencies['@certd/executor'] = '^' + currentVersion
templatePkg.dependencies['@certd/plugin-aliyun'] = '^' + currentVersion
templatePkg.dependencies['@certd/plugin-host'] = '^' + currentVersion
templatePkg.dependencies['@certd/plugin-tencent'] = '^' + currentVersion
const pkgFilePath = path.join(targetProjectDir, 'package.json')
fs.writeJsonSync(pkgFilePath, templatePkg)
const zipName = dirName + '.zip'
const outputFilePath = path.join(targetDir, zipName)
console.log('outputFilePath', outputFilePath)
await zipUtil.compress({ dir: targetProjectDir, output: outputFilePath })
return {
dir: targetDir,
fileName: zipName,
zipPath: outputFilePath
}
}
}
@@ -1,18 +0,0 @@
import { Executor } from '@certd/executor'
import PluginAliyun from '@certd/plugin-aliyun'
import PluginTencent from '@certd/plugin-tencent'
import PluginHost from '@certd/plugin-host'
// import options
import { createRequire } from 'module'
// 安装默认插件和授权提供者
PluginAliyun.install()
PluginTencent.install()
PluginHost.install()
const require = createRequire(import.meta.url)
const options = require('./options.json')
// 开始执行
const executor = new Executor()
await executor.run(options)
@@ -1 +0,0 @@
{}
@@ -1,22 +0,0 @@
{
"name": "certd-run",
"version": "1.0.0",
"description": "certd run",
"main": "index.js",
"scripts": {
"certd": "node index.js"
},
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/certd/certd"
},
"author": "greper",
"license": "MIT",
"dependencies": {
"@certd/executor": "^0.3.0",
"@certd/plugin-aliyun": "^0.3.0",
"@certd/plugin-host": "^0.3.0",
"@certd/plugin-tencent": "^0.3.0"
}
}
@@ -1,11 +0,0 @@
import os from 'os'
export default {
join (...dirs) {
const url = new URL('../' + dirs.join('/'), import.meta.url)
let path = url.pathname
if (os.type() === 'Windows_NT') {
path = path.substring(1)
}
return path
}
}
@@ -1,8 +0,0 @@
import compressing from 'compressing'
export default {
compress ({
dir, output
}) {
return compressing.zip.compressDir(dir, output)
}
}
-3
View File
@@ -1,3 +0,0 @@
> 1%
last 2 versions
not dead
-5
View File
@@ -1,5 +0,0 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
-1
View File
@@ -1 +0,0 @@
VITE_APP_API=/api
-2
View File
@@ -1,2 +0,0 @@
node_modules
.idea
-76
View File
@@ -1,76 +0,0 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true
},
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React",
ecmaFeatures: {
jsx: true,
tsx: true
}
},
extends: [
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
rules: {
//"max-len": [0, 200, 2, { ignoreUrls: true }],
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
// "@typescript-eslint/no-unused-vars": [
// "error",
// {
// argsIgnorePattern: "^h$",
// varsIgnorePattern: "^h$",
// },
// ],
// "no-unused-vars": [
// "error",
// {
// argsIgnorePattern: "^h$",
// varsIgnorePattern: "^h$",
// },
// ],
// "vue/custom-event-name-casing": "off",
// "no-use-before-define": "off",
// "space-before-function-paren": "off",
// "vue/attributes-order": "off",
// "vue/one-component-per-file": "off",
// "vue/html-closing-bracket-newline": "off",
// "vue/max-attributes-per-line": "off",
// "vue/multiline-html-element-content-newline": "off",
// "vue/singleline-html-element-content-newline": "off",
// "vue/attribute-hyphenation": "off",
// "vue/require-default-prop": "off",
// "vue/html-self-closing": [
// "error",
// {
// html: {
// void: "always",
// normal: "never",
// component: "always",
// },
// svg: "always",
// math: "always",
// },
// ],
}
};
-11
View File
@@ -1,11 +0,0 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
/stats.html
yarn.lock
.idea
/.idea/
yarn-error.log
vite-profile.cpuprofile
-2
View File
@@ -1,2 +0,0 @@
node_modules
/stats.html
-5
View File
@@ -1,5 +0,0 @@
{
"trailingComma": "none",
"printWidth": 120
}
-29
View File
@@ -1,29 +0,0 @@
# certd-ui
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your unit tests
```
npm run test:unit
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
-9
View File
@@ -1,9 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
// plugins: [['import', {
// libraryName: 'ant-design-vue',
// style: true // or 'css'
// }]]
}
-21
View File
@@ -1,21 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>certd</title>
<link rel="stylesheet" type="text/css" href="/index.css" />
</head>
<body>
<div id="app">
<div class="fs-bootstrap">
<div class="fs-bootstrap__main">
<div class="fs-bootstrap__loading"></div>
</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
-88
View File
@@ -1,88 +0,0 @@
{
"name": "@certd/certd-ui",
"version": "0.2.1",
"private": true,
"scripts": {
"dev": "vite",
"dev:pm": "vite --mode pm",
"dev:force": "vite --force",
"debug": "vite --mode debug",
"debug:pm": "vite --mode debugpm",
"debug:force": "vite --force --mode debug",
"build": "vite build ",
"serve": "vite preview",
"preview": "vite preview",
"pretty-quick": "pretty-quick",
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/",
"upgrade": "yarn upgrade-interactive --latest"
},
"author": "Greper",
"license": "MIT",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.0.1",
"ant-design-vue": "^3.2.12",
"axios": "^0.27.2",
"core-js": "^3.25.4",
"dayjs": "^1.11.5",
"lodash-es": "^4.17.15",
"mitt": "^3.0.0",
"vue": "^3.2.40",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.5"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^22.0.2",
"@rollup/plugin-node-resolve": "^14.1.0",
"@types/chai": "^4.3.3",
"@types/mocha": "^10.0.0",
"@types/node": "^18.8.0",
"@typescript-eslint/eslint-plugin": "^5.38.1",
"@typescript-eslint/parser": "^5.38.1",
"@vitejs/plugin-legacy": "^2.2.0",
"@vitejs/plugin-vue": "^3.1.2",
"@vitejs/plugin-vue-jsx": "^2.0.1",
"@vue/compiler-sfc": "^3.2.40",
"@vue/eslint-config-typescript": "^11.0.2",
"@vue/test-utils": "^2.1.0",
"autoprefixer": "^10.4.12",
"caller-path": "^4.0.0",
"chai": "^4.1.2",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.0.1",
"eslint-plugin-vue": "^9.5.1",
"less": "^4.1.3",
"less-loader": "^11.0.0",
"lint-staged": "^13.0.3",
"postcss": "^8.4.17",
"prettier": "2.7.1",
"rimraf": "^3.0.2",
"rollup": "^2.79.1",
"rollup-plugin-visualizer": "^5.8.2",
"stylelint": "^14.13.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-order": "^5.0.0",
"vite": "^3.1.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1",
"vue-eslint-parser": "^9.1.0"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
},
"gitHead": "9c2162697f3affea22c9a8cbc0ca74f4034ab27e",
"vite": {
"optimizeDeps": {
"include": [
"@iconify/iconify"
]
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

-17
View File
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

@@ -1,7 +0,0 @@
<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: 402 B

@@ -1,44 +0,0 @@
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="800" height="300" viewBox="0 0 800.000000 300.000000"
>
<g fill="#333">
<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(40, 40) scale(4,4)"
></path>
<g transform="translate(280, 260) scale(2,2)">
<path d="M28.95-58.70L49.98-58.70L49.98-48.22L33.70-48.22Q27.37-48.22 24.46-47.34Q21.56-46.46 19.62-43.91L19.62-43.91Q18.30-42.15 17.82-40.39Q17.34-38.63 16.98-34.41L16.98-34.41L49.98-34.41L49.98-23.94L16.98-23.94Q17.69-16.37 21.47-13.42Q25.26-10.47 34.32-10.47L34.32-10.47L49.98-10.47L49.98 0L33.70 0Q27.10 0 22.09-0.79L22.09-0.79Q14.17-2.11 9.50-7.74L9.50-7.74Q2.82-15.84 2.82-29.66L2.82-29.66Q2.82-44.97 12.23-53.50L12.23-53.50Q15.49-56.41 19.14-57.55Q22.79-58.70 28.95-58.70L28.95-58.70Z"
transform="translate(0 0) "
></path>
<path d="M28.51-22.26L18.48-22.26L18.48 0L5.98 0L5.98-58.70L34.67-58.70Q46.99-58.70 51.83-55.53L51.83-55.53Q55.18-53.42 56.98-49.94Q58.78-46.46 58.78-42.33L58.78-42.33Q58.78-33.97 54.56-29.39L54.56-29.39Q51.92-26.66 47.61-25.26L47.61-25.26Q51.04-24.02 52.80-22.66Q54.56-21.30 55.97-18.66L55.97-18.66Q57.02-16.54 57.51-14.61Q57.99-12.67 58.26-8.89L58.26-8.89Q58.78-2.55 59.66 0L59.66 0L45.67 0Q45.06-2.02 44.35-8.36L44.35-8.36Q43.91-13.46 42.55-16.19Q41.18-18.92 38.46-20.50L38.46-20.50Q35.02-22.35 28.51-22.26L28.51-22.26ZM18.48-48.22L18.48-32.74L35.99-32.74Q40.39-32.74 42.24-34.06L42.24-34.06Q45.06-35.99 45.06-40.83L45.06-40.83Q45.06-46.20 40.83-47.70L40.83-47.70Q39.34-48.22 35.99-48.22L35.99-48.22L18.48-48.22Z"
transform="translate(58.855999999999995 0) "
></path>
<path d="M19.01 0L19.01-48.22L0.35-48.22L0.35-58.70L50.95-58.70L50.95-48.22L31.50-48.22L31.50 0L19.01 0Z"
transform="translate(126.68799999999999 0) "
></path>
<path d="M5.98 0L5.98-58.70L30.89-58.70Q40.22-58.70 45.32-56.85L45.32-56.85Q54.74-53.42 57.90-44.26L57.90-44.26Q60.28-37.22 60.28-29.22L60.28-29.22Q60.28-21.30 57.99-14.26L57.99-14.26Q55.70-7.04 50.42-3.61L50.42-3.61Q47.08-1.50 43.08-0.75Q39.07 0 30.89 0L30.89 0L5.98 0ZM30.89-48.22L18.48-48.22L18.48-10.47L30.89-10.47Q39.07-10.47 42.24-14.08L42.24-14.08Q44.18-16.37 45.36-20.50Q46.55-24.64 46.55-29.30L46.55-29.30Q46.55-34.50 45.14-38.81Q43.74-43.12 41.45-45.23L41.45-45.23Q38.10-48.22 30.89-48.22L30.89-48.22Z"
transform="translate(183.07999999999998 0) "
></path>
</g>
<!-- <path d="M13.00-21.91L21.24-21.91L21.24-17.23L14.04-17.23Q10.39-17.23-->
<!-- 9-15.62L9-15.62Q7.65-14.08-->
<!-- 7.65-10.93L7.65-10.93Q7.65-7.42 9.86-5.80L9.86-5.80Q10.75-5.17-->
<!-- 11.81-4.93Q12.87-4.68-->
<!-- 14.76-4.68L14.76-4.68L21.24-4.68L21.24-->
<!-- 0L13.00 0Q9.67 0 7.74-0.67Q5.80-1.35-->
<!-- 4.32-3.01L4.32-3.01Q1.48-6.17-->
<!-- 1.48-11.03L1.48-11.03Q1.48-16.88-->
<!-- 4.86-19.75L4.86-19.75Q6.21-20.93-->
<!-- 8.10-21.42Q9.99-21.91-->
<!-- 13.00-21.91L13.00-21.91ZM31.05-13.32L43.74-13.32L43.74-8.64L31.05-8.64Q31.23-6.48-->
<!-- 32.44-5.58Q33.66-4.68 36.41-4.68L36.41-4.68L43.74-4.68L43.74 0L35.73 0Q33.12 0 31.48-0.47Q29.83-0.94 28.39-2.02L28.39-2.02Q24.39-5.13 24.39-11.25L24.39-11.25Q24.39-15.21 26.50-18.18L26.50-18.18Q27.94-20.20 29.97-21.06Q31.99-21.91 35.28-21.91L35.28-21.91L43.74-21.91L43.74-17.23L35.73-17.23Q33.25-17.23 32.27-16.40Q31.27-15.57 31.05-13.32L31.05-13.32ZM48.64 0L48.64-21.91L57.55-21.91Q60.30-21.91 61.81-21.53Q63.31-21.15 64.31-20.25L64.31-20.25Q65.30-19.35 65.70-18Q66.10-16.65 66.10-14.13L66.10-14.13L66.10-12.01L60.30-12.01L60.30-13.18Q60.30-15.52 59.49-16.38Q58.68-17.23 56.38-17.23L56.38-17.23L54.67-17.23L54.67 0L48.64 0ZM67.50-21.91L71.33-21.91L71.33-30.02L77.36-30.02L77.36-21.91L82.94-21.91L82.94-17.23L77.36-17.23L77.36-9.27Q77.36-6.48 77.85-5.76L77.85-5.76Q78.61-4.68 80.55-4.68L80.55-4.68L82.94-4.68L82.94 0L78.57 0Q74.66 0 72.99-1.89Q71.33-3.78 71.33-8.23L71.33-8.23L71.33-17.23L67.50-17.23L67.50-21.91ZM96.08-21.91L101.75-21.91L101.75-30.02L107.73-30.02L107.73 0L97.38 0Q94.23 0 92.61-0.49L92.61-0.49Q88.78-1.71 86.90-5.26L86.90-5.26Q85.59-7.65 85.59-11.12L85.59-11.12Q85.59-16.74 89.37-19.84L89.37-19.84Q91.84-21.91 96.08-21.91L96.08-21.91ZM97.38-4.68L101.75-4.68L101.75-17.23L97.38-17.23Q94.50-17.23 93.02-15.30L93.02-15.30Q91.71-13.68 91.71-11.12L91.71-11.12Q91.71-7.38 93.87-5.76L93.87-5.76Q95.36-4.68 97.38-4.68L97.38-4.68Z"-->
<!-- fill="#2c3e50"-->
<!-- transform="translate(300, 270) scale(4,4)"-->
<!-- ></path>-->
<text x="300" y="100" font-size="50" font-weight="bold">让你的证书永不过期</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

@@ -1,44 +0,0 @@
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="800" height="300" viewBox="0 0 800.000000 300.000000"
>
<g fill="#fff">
<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(40, 40) scale(4,4)"
></path>
<g transform="translate(280, 260) scale(2,2)">
<path d="M28.95-58.70L49.98-58.70L49.98-48.22L33.70-48.22Q27.37-48.22 24.46-47.34Q21.56-46.46 19.62-43.91L19.62-43.91Q18.30-42.15 17.82-40.39Q17.34-38.63 16.98-34.41L16.98-34.41L49.98-34.41L49.98-23.94L16.98-23.94Q17.69-16.37 21.47-13.42Q25.26-10.47 34.32-10.47L34.32-10.47L49.98-10.47L49.98 0L33.70 0Q27.10 0 22.09-0.79L22.09-0.79Q14.17-2.11 9.50-7.74L9.50-7.74Q2.82-15.84 2.82-29.66L2.82-29.66Q2.82-44.97 12.23-53.50L12.23-53.50Q15.49-56.41 19.14-57.55Q22.79-58.70 28.95-58.70L28.95-58.70Z"
transform="translate(0 0) "
></path>
<path d="M28.51-22.26L18.48-22.26L18.48 0L5.98 0L5.98-58.70L34.67-58.70Q46.99-58.70 51.83-55.53L51.83-55.53Q55.18-53.42 56.98-49.94Q58.78-46.46 58.78-42.33L58.78-42.33Q58.78-33.97 54.56-29.39L54.56-29.39Q51.92-26.66 47.61-25.26L47.61-25.26Q51.04-24.02 52.80-22.66Q54.56-21.30 55.97-18.66L55.97-18.66Q57.02-16.54 57.51-14.61Q57.99-12.67 58.26-8.89L58.26-8.89Q58.78-2.55 59.66 0L59.66 0L45.67 0Q45.06-2.02 44.35-8.36L44.35-8.36Q43.91-13.46 42.55-16.19Q41.18-18.92 38.46-20.50L38.46-20.50Q35.02-22.35 28.51-22.26L28.51-22.26ZM18.48-48.22L18.48-32.74L35.99-32.74Q40.39-32.74 42.24-34.06L42.24-34.06Q45.06-35.99 45.06-40.83L45.06-40.83Q45.06-46.20 40.83-47.70L40.83-47.70Q39.34-48.22 35.99-48.22L35.99-48.22L18.48-48.22Z"
transform="translate(58.855999999999995 0) "
></path>
<path d="M19.01 0L19.01-48.22L0.35-48.22L0.35-58.70L50.95-58.70L50.95-48.22L31.50-48.22L31.50 0L19.01 0Z"
transform="translate(126.68799999999999 0) "
></path>
<path d="M5.98 0L5.98-58.70L30.89-58.70Q40.22-58.70 45.32-56.85L45.32-56.85Q54.74-53.42 57.90-44.26L57.90-44.26Q60.28-37.22 60.28-29.22L60.28-29.22Q60.28-21.30 57.99-14.26L57.99-14.26Q55.70-7.04 50.42-3.61L50.42-3.61Q47.08-1.50 43.08-0.75Q39.07 0 30.89 0L30.89 0L5.98 0ZM30.89-48.22L18.48-48.22L18.48-10.47L30.89-10.47Q39.07-10.47 42.24-14.08L42.24-14.08Q44.18-16.37 45.36-20.50Q46.55-24.64 46.55-29.30L46.55-29.30Q46.55-34.50 45.14-38.81Q43.74-43.12 41.45-45.23L41.45-45.23Q38.10-48.22 30.89-48.22L30.89-48.22Z"
transform="translate(183.07999999999998 0) "
></path>
</g>
<!-- <path d="M13.00-21.91L21.24-21.91L21.24-17.23L14.04-17.23Q10.39-17.23-->
<!-- 9-15.62L9-15.62Q7.65-14.08-->
<!-- 7.65-10.93L7.65-10.93Q7.65-7.42 9.86-5.80L9.86-5.80Q10.75-5.17-->
<!-- 11.81-4.93Q12.87-4.68-->
<!-- 14.76-4.68L14.76-4.68L21.24-4.68L21.24-->
<!-- 0L13.00 0Q9.67 0 7.74-0.67Q5.80-1.35-->
<!-- 4.32-3.01L4.32-3.01Q1.48-6.17-->
<!-- 1.48-11.03L1.48-11.03Q1.48-16.88-->
<!-- 4.86-19.75L4.86-19.75Q6.21-20.93-->
<!-- 8.10-21.42Q9.99-21.91-->
<!-- 13.00-21.91L13.00-21.91ZM31.05-13.32L43.74-13.32L43.74-8.64L31.05-8.64Q31.23-6.48-->
<!-- 32.44-5.58Q33.66-4.68 36.41-4.68L36.41-4.68L43.74-4.68L43.74 0L35.73 0Q33.12 0 31.48-0.47Q29.83-0.94 28.39-2.02L28.39-2.02Q24.39-5.13 24.39-11.25L24.39-11.25Q24.39-15.21 26.50-18.18L26.50-18.18Q27.94-20.20 29.97-21.06Q31.99-21.91 35.28-21.91L35.28-21.91L43.74-21.91L43.74-17.23L35.73-17.23Q33.25-17.23 32.27-16.40Q31.27-15.57 31.05-13.32L31.05-13.32ZM48.64 0L48.64-21.91L57.55-21.91Q60.30-21.91 61.81-21.53Q63.31-21.15 64.31-20.25L64.31-20.25Q65.30-19.35 65.70-18Q66.10-16.65 66.10-14.13L66.10-14.13L66.10-12.01L60.30-12.01L60.30-13.18Q60.30-15.52 59.49-16.38Q58.68-17.23 56.38-17.23L56.38-17.23L54.67-17.23L54.67 0L48.64 0ZM67.50-21.91L71.33-21.91L71.33-30.02L77.36-30.02L77.36-21.91L82.94-21.91L82.94-17.23L77.36-17.23L77.36-9.27Q77.36-6.48 77.85-5.76L77.85-5.76Q78.61-4.68 80.55-4.68L80.55-4.68L82.94-4.68L82.94 0L78.57 0Q74.66 0 72.99-1.89Q71.33-3.78 71.33-8.23L71.33-8.23L71.33-17.23L67.50-17.23L67.50-21.91ZM96.08-21.91L101.75-21.91L101.75-30.02L107.73-30.02L107.73 0L97.38 0Q94.23 0 92.61-0.49L92.61-0.49Q88.78-1.71 86.90-5.26L86.90-5.26Q85.59-7.65 85.59-11.12L85.59-11.12Q85.59-16.74 89.37-19.84L89.37-19.84Q91.84-21.91 96.08-21.91L96.08-21.91ZM97.38-4.68L101.75-4.68L101.75-17.23L97.38-17.23Q94.50-17.23 93.02-15.30L93.02-15.30Q91.71-13.68 91.71-11.12L91.71-11.12Q91.71-7.38 93.87-5.76L93.87-5.76Q95.36-4.68 97.38-4.68L97.38-4.68Z"-->
<!-- fill="#2c3e50"-->
<!-- transform="translate(300, 270) scale(4,4)"-->
<!-- ></path>-->
<text x="300" y="100" font-size="50" font-weight="bold">让你的证书永不过期</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

@@ -1,17 +0,0 @@
<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"
fill="#2c3e50"
transform="translate(124, 60) scale(4,4)"
></path>
<path d="M13.00-21.91L21.24-21.91L21.24-17.23L14.04-17.23Q10.39-17.23 9-15.62L9-15.62Q7.65-14.08 7.65-10.93L7.65-10.93Q7.65-7.42 9.86-5.80L9.86-5.80Q10.75-5.17 11.81-4.93Q12.87-4.68 14.76-4.68L14.76-4.68L21.24-4.68L21.24 0L13.00 0Q9.67 0 7.74-0.67Q5.80-1.35 4.32-3.01L4.32-3.01Q1.48-6.17 1.48-11.03L1.48-11.03Q1.48-16.88 4.86-19.75L4.86-19.75Q6.21-20.93 8.10-21.42Q9.99-21.91 13.00-21.91L13.00-21.91ZM31.05-13.32L43.74-13.32L43.74-8.64L31.05-8.64Q31.23-6.48 32.44-5.58Q33.66-4.68 36.41-4.68L36.41-4.68L43.74-4.68L43.74 0L35.73 0Q33.12 0 31.48-0.47Q29.83-0.94 28.39-2.02L28.39-2.02Q24.39-5.13 24.39-11.25L24.39-11.25Q24.39-15.21 26.50-18.18L26.50-18.18Q27.94-20.20 29.97-21.06Q31.99-21.91 35.28-21.91L35.28-21.91L43.74-21.91L43.74-17.23L35.73-17.23Q33.25-17.23 32.27-16.40Q31.27-15.57 31.05-13.32L31.05-13.32ZM48.64 0L48.64-21.91L57.55-21.91Q60.30-21.91 61.81-21.53Q63.31-21.15 64.31-20.25L64.31-20.25Q65.30-19.35 65.70-18Q66.10-16.65 66.10-14.13L66.10-14.13L66.10-12.01L60.30-12.01L60.30-13.18Q60.30-15.52 59.49-16.38Q58.68-17.23 56.38-17.23L56.38-17.23L54.67-17.23L54.67 0L48.64 0ZM67.50-21.91L71.33-21.91L71.33-30.02L77.36-30.02L77.36-21.91L82.94-21.91L82.94-17.23L77.36-17.23L77.36-9.27Q77.36-6.48 77.85-5.76L77.85-5.76Q78.61-4.68 80.55-4.68L80.55-4.68L82.94-4.68L82.94 0L78.57 0Q74.66 0 72.99-1.89Q71.33-3.78 71.33-8.23L71.33-8.23L71.33-17.23L67.50-17.23L67.50-21.91ZM96.08-21.91L101.75-21.91L101.75-30.02L107.73-30.02L107.73 0L97.38 0Q94.23 0 92.61-0.49L92.61-0.49Q88.78-1.71 86.90-5.26L86.90-5.26Q85.59-7.65 85.59-11.12L85.59-11.12Q85.59-16.74 89.37-19.84L89.37-19.84Q91.84-21.91 96.08-21.91L96.08-21.91ZM97.38-4.68L101.75-4.68L101.75-17.23L97.38-17.23Q94.50-17.23 93.02-15.30L93.02-15.30Q91.71-13.68 91.71-11.12L91.71-11.12Q91.71-7.38 93.87-5.76L93.87-5.76Q95.36-4.68 97.38-4.68L97.38-4.68Z"
fill="#2c3e50"
transform="translate(28, 430) scale(4,4)"
></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,7 +0,0 @@
<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: 402 B

@@ -1,108 +0,0 @@
<?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">
<defs
id="defs2" />
<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>

Before

Width:  |  Height:  |  Size: 3.8 KiB

@@ -1,44 +0,0 @@
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="800" height="300" viewBox="0 0 800.000000 300.000000"
>
<g fill="#fff">
<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(40, 40) scale(4,4)"
></path>
<g transform="translate(280, 260) scale(2,2)">
<path d="M28.95-58.70L49.98-58.70L49.98-48.22L33.70-48.22Q27.37-48.22 24.46-47.34Q21.56-46.46 19.62-43.91L19.62-43.91Q18.30-42.15 17.82-40.39Q17.34-38.63 16.98-34.41L16.98-34.41L49.98-34.41L49.98-23.94L16.98-23.94Q17.69-16.37 21.47-13.42Q25.26-10.47 34.32-10.47L34.32-10.47L49.98-10.47L49.98 0L33.70 0Q27.10 0 22.09-0.79L22.09-0.79Q14.17-2.11 9.50-7.74L9.50-7.74Q2.82-15.84 2.82-29.66L2.82-29.66Q2.82-44.97 12.23-53.50L12.23-53.50Q15.49-56.41 19.14-57.55Q22.79-58.70 28.95-58.70L28.95-58.70Z"
transform="translate(0 0) "
></path>
<path d="M28.51-22.26L18.48-22.26L18.48 0L5.98 0L5.98-58.70L34.67-58.70Q46.99-58.70 51.83-55.53L51.83-55.53Q55.18-53.42 56.98-49.94Q58.78-46.46 58.78-42.33L58.78-42.33Q58.78-33.97 54.56-29.39L54.56-29.39Q51.92-26.66 47.61-25.26L47.61-25.26Q51.04-24.02 52.80-22.66Q54.56-21.30 55.97-18.66L55.97-18.66Q57.02-16.54 57.51-14.61Q57.99-12.67 58.26-8.89L58.26-8.89Q58.78-2.55 59.66 0L59.66 0L45.67 0Q45.06-2.02 44.35-8.36L44.35-8.36Q43.91-13.46 42.55-16.19Q41.18-18.92 38.46-20.50L38.46-20.50Q35.02-22.35 28.51-22.26L28.51-22.26ZM18.48-48.22L18.48-32.74L35.99-32.74Q40.39-32.74 42.24-34.06L42.24-34.06Q45.06-35.99 45.06-40.83L45.06-40.83Q45.06-46.20 40.83-47.70L40.83-47.70Q39.34-48.22 35.99-48.22L35.99-48.22L18.48-48.22Z"
transform="translate(58.855999999999995 0) "
></path>
<path d="M19.01 0L19.01-48.22L0.35-48.22L0.35-58.70L50.95-58.70L50.95-48.22L31.50-48.22L31.50 0L19.01 0Z"
transform="translate(126.68799999999999 0) "
></path>
<path d="M5.98 0L5.98-58.70L30.89-58.70Q40.22-58.70 45.32-56.85L45.32-56.85Q54.74-53.42 57.90-44.26L57.90-44.26Q60.28-37.22 60.28-29.22L60.28-29.22Q60.28-21.30 57.99-14.26L57.99-14.26Q55.70-7.04 50.42-3.61L50.42-3.61Q47.08-1.50 43.08-0.75Q39.07 0 30.89 0L30.89 0L5.98 0ZM30.89-48.22L18.48-48.22L18.48-10.47L30.89-10.47Q39.07-10.47 42.24-14.08L42.24-14.08Q44.18-16.37 45.36-20.50Q46.55-24.64 46.55-29.30L46.55-29.30Q46.55-34.50 45.14-38.81Q43.74-43.12 41.45-45.23L41.45-45.23Q38.10-48.22 30.89-48.22L30.89-48.22Z"
transform="translate(183.07999999999998 0) "
></path>
</g>
<!-- <path d="M13.00-21.91L21.24-21.91L21.24-17.23L14.04-17.23Q10.39-17.23-->
<!-- 9-15.62L9-15.62Q7.65-14.08-->
<!-- 7.65-10.93L7.65-10.93Q7.65-7.42 9.86-5.80L9.86-5.80Q10.75-5.17-->
<!-- 11.81-4.93Q12.87-4.68-->
<!-- 14.76-4.68L14.76-4.68L21.24-4.68L21.24-->
<!-- 0L13.00 0Q9.67 0 7.74-0.67Q5.80-1.35-->
<!-- 4.32-3.01L4.32-3.01Q1.48-6.17-->
<!-- 1.48-11.03L1.48-11.03Q1.48-16.88-->
<!-- 4.86-19.75L4.86-19.75Q6.21-20.93-->
<!-- 8.10-21.42Q9.99-21.91-->
<!-- 13.00-21.91L13.00-21.91ZM31.05-13.32L43.74-13.32L43.74-8.64L31.05-8.64Q31.23-6.48-->
<!-- 32.44-5.58Q33.66-4.68 36.41-4.68L36.41-4.68L43.74-4.68L43.74 0L35.73 0Q33.12 0 31.48-0.47Q29.83-0.94 28.39-2.02L28.39-2.02Q24.39-5.13 24.39-11.25L24.39-11.25Q24.39-15.21 26.50-18.18L26.50-18.18Q27.94-20.20 29.97-21.06Q31.99-21.91 35.28-21.91L35.28-21.91L43.74-21.91L43.74-17.23L35.73-17.23Q33.25-17.23 32.27-16.40Q31.27-15.57 31.05-13.32L31.05-13.32ZM48.64 0L48.64-21.91L57.55-21.91Q60.30-21.91 61.81-21.53Q63.31-21.15 64.31-20.25L64.31-20.25Q65.30-19.35 65.70-18Q66.10-16.65 66.10-14.13L66.10-14.13L66.10-12.01L60.30-12.01L60.30-13.18Q60.30-15.52 59.49-16.38Q58.68-17.23 56.38-17.23L56.38-17.23L54.67-17.23L54.67 0L48.64 0ZM67.50-21.91L71.33-21.91L71.33-30.02L77.36-30.02L77.36-21.91L82.94-21.91L82.94-17.23L77.36-17.23L77.36-9.27Q77.36-6.48 77.85-5.76L77.85-5.76Q78.61-4.68 80.55-4.68L80.55-4.68L82.94-4.68L82.94 0L78.57 0Q74.66 0 72.99-1.89Q71.33-3.78 71.33-8.23L71.33-8.23L71.33-17.23L67.50-17.23L67.50-21.91ZM96.08-21.91L101.75-21.91L101.75-30.02L107.73-30.02L107.73 0L97.38 0Q94.23 0 92.61-0.49L92.61-0.49Q88.78-1.71 86.90-5.26L86.90-5.26Q85.59-7.65 85.59-11.12L85.59-11.12Q85.59-16.74 89.37-19.84L89.37-19.84Q91.84-21.91 96.08-21.91L96.08-21.91ZM97.38-4.68L101.75-4.68L101.75-17.23L97.38-17.23Q94.50-17.23 93.02-15.30L93.02-15.30Q91.71-13.68 91.71-11.12L91.71-11.12Q91.71-7.38 93.87-5.76L93.87-5.76Q95.36-4.68 97.38-4.68L97.38-4.68Z"-->
<!-- fill="#2c3e50"-->
<!-- transform="translate(300, 270) scale(4,4)"-->
<!-- ></path>-->
<text x="300" y="100" font-size="50" font-weight="bold">让你的证书永不过期</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

@@ -1,106 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 3.7 KiB

@@ -1,12 +0,0 @@
html, body, #app { height: 100%; margin: 0; padding: 0; width: 100%;}
.fs-bootstrap { background-color: #474949; height: 100%; display: flex; flex-direction: column;position: fixed;width: 100% }
.fs-bootstrap__main {flex:1; user-select: none; width: 100%; flex-grow: 1; display: flex; justify-content: center; align-items: center; flex-direction: column; }
.fs-bootstrap__footer { width: 100%; flex-grow: 0; text-align: center; padding: 10px 0; }
.fs-bootstrap__footer > a { font-size: 12px; color: #ABABAB; text-decoration: none; }
.fs-bootstrap__loading {box-sizing: border-box; height: 50px; width: 50px; margin-bottom: 5px;border:5px solid #333333;border-bottom:#aaa 5px solid;
border-radius:1000px; animation:load 1.1s infinite linear;-webkit-animation:load 1.1s infinite linear;-moz-animation:load 1.1s infinite linear; -o-animation:load 1.1s infinite linear;
}
@keyframes load {from {transform:rotate(0deg);-ms-transform:rotate(0deg);}to { transform:rotate(360deg);-ms-transform:rotate(360deg); }
}@-webkit-keyframes load {from {-webkit-transform:rotate(0deg); }to { -webkit-transform:rotate(360deg);}
}@-moz-keyframes load { from { -moz-transform:rotate(0deg); } to { -moz-transform:rotate(360deg);}
}@-o-keyframes load { from { -o-transform:rotate(0deg);} to { -o-transform:rotate(360deg);}}
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
-106
View File
@@ -1,106 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 3.7 KiB

-38
View File
@@ -1,38 +0,0 @@
<template>
<a-config-provider :locale="locale">
<a-layout class="page-layout">
<a-layout-header>Cert-D</a-layout-header>
<a-layout style="flex:1">
<router-view/>
</a-layout>
<a-layout-footer>
by greper
</a-layout-footer>
</a-layout>
</a-config-provider>
</template>
<script>
import zhCN from 'ant-design-vue/es/locale/zh_CN'
export default {
data () {
return {
locale: zhCN
}
},
setup () {
}
}
</script>
<style lang="less">
.page-layout{
height: 100%;
overflow-x: hidden;
.ant-layout-header{
color:#fff;
}
}
</style>
-86
View File
@@ -1,86 +0,0 @@
import _ from 'lodash'
import {
AutoComplete,
Alert,
Avatar,
Badge,
Button,
Calendar,
Card,
Cascader,
Checkbox,
Col,
DatePicker,
Divider,
Dropdown,
Form,
Input,
InputNumber,
Layout,
List,
LocaleProvider,
Modal,
Radio,
Row,
Select,
Switch,
Tabs,
Tag,
TimePicker,
Tooltip,
Drawer,
// ColorPicker,
ConfigProvider,
Descriptions,
Space
} from 'ant-design-vue'
const list = {
AutoComplete,
Alert,
Avatar,
Badge,
Button,
Calendar,
Card,
Cascader,
Checkbox,
Col,
DatePicker,
Divider,
Dropdown,
Form,
Input,
InputNumber,
Layout,
List,
LocaleProvider,
TimePicker,
Modal,
Radio,
Row,
Select,
Switch,
Tabs,
Tag,
Tooltip,
Drawer,
// ColorPicker,
ConfigProvider,
Descriptions,
Space
}
export default function (app) {
_.forEach(list, item => {
app.use(item)
//
// app.config.globalProperties.$message = message
// app.config.globalProperties.$notification = notification
app.config.globalProperties.$info = Modal.info
app.config.globalProperties.$success = Modal.success
app.config.globalProperties.$error = Modal.error
app.config.globalProperties.$warning = Modal.warning
app.config.globalProperties.$confirm = Modal.confirm
app.config.globalProperties.$destroyAll = Modal.destroyAll
})
}
@@ -1,14 +0,0 @@
import { request } from "./service";
import inputHandler from "./util.input.handler";
export default {
async list() {
const ret = await request({
url: "/access-providers/list"
});
inputHandler.handle(ret);
return ret;
}
};
@@ -1,14 +0,0 @@
import { request } from "./service";
import inputHandler from "./util.input.handler";
export default {
async list() {
const ret = await request({
url: "/dns-providers/list"
});
inputHandler.handle(ret);
return ret;
}
};
@@ -1,40 +0,0 @@
import { request } from "./service";
import _ from "lodash-es";
function arrayToMap(arr) {
if (arr && arr instanceof Array) {
const map = {};
_.forEach(arr, (item) => {
map[item.key] = item;
});
return map;
}
return arr;
}
function transfer(options) {
options.accessProviders = arrayToMap(options.accessProviders);
}
export default {
exportsToZip(options) {
transfer(options);
return request({
url: "/exports/toZip",
data: { options },
method: "post",
responseType: "blob" // 重点在于配置responseType: 'blob'
}).then((res) => {
console.log("res", res);
const filename = decodeURI(res.headers["content-disposition"].replace("attachment;filename=", "")); // 由后端设置下载文件名
const blob = new Blob([res.data], { type: "application/zip" });
const a = document.createElement("a");
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
const body = document.getElementsByTagName("body")[0];
body.appendChild(a);
a.click();
body.removeChild(a);
window.URL.revokeObjectURL(url);
});
}
};
@@ -1,14 +0,0 @@
import { request } from "./service";
import inputHandler from "./util.input.handler";
export default {
async list() {
const ret = await request({
url: "/plugins/list"
});
inputHandler.handle(ret);
console.log("plugins", ret);
return ret;
}
};
-15
View File
@@ -1,15 +0,0 @@
import { assign, map } from "lodash";
import { service, request } from "./service";
const files = require.context("./modules", false, /\.js$/);
const generators = files.keys().map((key) => files(key).default);
export default assign(
{},
...map(generators, (generator) =>
generator({
service,
request
})
)
);
-117
View File
@@ -1,117 +0,0 @@
import axios from "axios";
import { get } from "lodash-es";
import { errorLog, errorCreate } from "./tools";
import { env } from "/src/utils/util.env";
/**
* @description 创建请求实例
*/
function createService() {
// 创建一个 axios 实例
const service = axios.create();
// 请求拦截
service.interceptors.request.use(
(config) => config,
(error) => {
// 发送失败
console.log(error);
return Promise.reject(error);
}
);
// 响应拦截
service.interceptors.response.use(
(response) => {
console.log("response.config", response.config);
if (response.config.responseType === "blob") {
return response;
}
// dataAxios 是 axios 返回数据中的 data
const dataAxios = response.data;
// 这个状态码是和后端约定的
const { code } = dataAxios;
// 根据 code 进行判断
if (code === undefined) {
// 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
if (response.config.unpack) {
return dataAxios;
}
return dataAxios.data;
} else {
// 有 code 代表这是一个后端接口 可以进行进一步的判断
switch (code) {
case 0:
// [ 示例 ] code === 0 代表没有错误
return dataAxios.data;
default:
// 不是正确的 code
errorCreate(`${dataAxios.msg}: ${response.config.url}`);
return dataAxios;
}
}
},
(error) => {
const status = get(error, "response.status");
switch (status) {
case 400:
error.message = "请求错误";
break;
case 401:
error.message = "未授权,请登录";
break;
case 403:
error.message = "拒绝访问";
break;
case 404:
error.message = `请求地址出错: ${error.response.config.url}`;
break;
case 408:
error.message = "请求超时";
break;
case 500:
error.message = "服务器内部错误";
break;
case 501:
error.message = "服务未实现";
break;
case 502:
error.message = "网关错误";
break;
case 503:
error.message = "服务不可用";
break;
case 504:
error.message = "网关超时";
break;
case 505:
error.message = "HTTP版本不受支持";
break;
default:
break;
}
errorLog(error);
return Promise.reject(error);
}
);
return service;
}
/**
* @description 创建请求方法
* @param {Object} service axios 实例
*/
function createRequestFunction(service) {
return function (config) {
const configDefault = {
headers: {
"Content-Type": get(config, "headers.Content-Type", "application/json")
},
timeout: 5000,
baseURL: env.API,
data: {}
};
return service(Object.assign(configDefault, config));
};
}
// 用于真实网络请求的实例和请求方法
export const service = createService();
export const request = createRequestFunction(service);
-68
View File
@@ -1,68 +0,0 @@
import { notification } from "ant-design-vue";
/**
* @description 安全地解析 json 字符串
* @param {String} jsonString 需要解析的 json 字符串
* @param {String} defaultValue 默认值
*/
export function parse(jsonString = "{}", defaultValue = {}) {
let result = defaultValue;
try {
result = JSON.parse(jsonString);
} catch (error) {
console.log(error);
}
return result;
}
/**
* @description 接口请求返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
* @param {Number} code 状态码
*/
export function response(data = {}, msg = "", code = 0) {
return [200, { code, msg, data }];
}
/**
* @description 接口请求返回 正确返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
*/
export function responseSuccess(data = {}, msg = "成功") {
return response(data, msg);
}
/**
* @description 接口请求返回 错误返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
* @param {Number} code 状态码
*/
export function responseError(data = {}, msg = "请求失败", code = 500) {
return response(data, msg, code);
}
/**
* @description 记录和显示错误
* @param {Error} error 错误对象
*/
export function errorLog(error) {
// 打印到控制台
console.log(error);
// 显示提示
notification.error({
message: error.message
});
}
/**
* @description 创建一个错误
* @param {String} msg 错误信息
*/
export function errorCreate(msg) {
const error = new Error(msg);
errorLog(error);
throw error;
}
@@ -1,35 +0,0 @@
import _ from "lodash-es";
function handleInputs(inputs) {
if (inputs == null) {
return;
}
_.forEach(inputs, (item, key) => {
if (item.required === true) {
if (item.component == null) {
item.component = {};
}
let rules = item.component.rules;
if (rules == null) {
item.component.rules = rules = [];
}
if (rules.length > 0) {
const hasRequired = rules.filter((rule) => {
return rule.required === true;
});
if (hasRequired.length > 0) {
return;
}
}
rules.push({ required: true, message: "该项必填" });
delete item.required;
}
});
}
export default {
handle(list) {
_.forEach(list, (item) => {
handleInputs(item.input);
});
}
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

-17
View File
@@ -1,17 +0,0 @@
<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"
fill="#2c3e50"
transform="translate(124, 60) scale(4,4)"
></path>
<path d="M13.00-21.91L21.24-21.91L21.24-17.23L14.04-17.23Q10.39-17.23 9-15.62L9-15.62Q7.65-14.08 7.65-10.93L7.65-10.93Q7.65-7.42 9.86-5.80L9.86-5.80Q10.75-5.17 11.81-4.93Q12.87-4.68 14.76-4.68L14.76-4.68L21.24-4.68L21.24 0L13.00 0Q9.67 0 7.74-0.67Q5.80-1.35 4.32-3.01L4.32-3.01Q1.48-6.17 1.48-11.03L1.48-11.03Q1.48-16.88 4.86-19.75L4.86-19.75Q6.21-20.93 8.10-21.42Q9.99-21.91 13.00-21.91L13.00-21.91ZM31.05-13.32L43.74-13.32L43.74-8.64L31.05-8.64Q31.23-6.48 32.44-5.58Q33.66-4.68 36.41-4.68L36.41-4.68L43.74-4.68L43.74 0L35.73 0Q33.12 0 31.48-0.47Q29.83-0.94 28.39-2.02L28.39-2.02Q24.39-5.13 24.39-11.25L24.39-11.25Q24.39-15.21 26.50-18.18L26.50-18.18Q27.94-20.20 29.97-21.06Q31.99-21.91 35.28-21.91L35.28-21.91L43.74-21.91L43.74-17.23L35.73-17.23Q33.25-17.23 32.27-16.40Q31.27-15.57 31.05-13.32L31.05-13.32ZM48.64 0L48.64-21.91L57.55-21.91Q60.30-21.91 61.81-21.53Q63.31-21.15 64.31-20.25L64.31-20.25Q65.30-19.35 65.70-18Q66.10-16.65 66.10-14.13L66.10-14.13L66.10-12.01L60.30-12.01L60.30-13.18Q60.30-15.52 59.49-16.38Q58.68-17.23 56.38-17.23L56.38-17.23L54.67-17.23L54.67 0L48.64 0ZM67.50-21.91L71.33-21.91L71.33-30.02L77.36-30.02L77.36-21.91L82.94-21.91L82.94-17.23L77.36-17.23L77.36-9.27Q77.36-6.48 77.85-5.76L77.85-5.76Q78.61-4.68 80.55-4.68L80.55-4.68L82.94-4.68L82.94 0L78.57 0Q74.66 0 72.99-1.89Q71.33-3.78 71.33-8.23L71.33-8.23L71.33-17.23L67.50-17.23L67.50-21.91ZM96.08-21.91L101.75-21.91L101.75-30.02L107.73-30.02L107.73 0L97.38 0Q94.23 0 92.61-0.49L92.61-0.49Q88.78-1.71 86.90-5.26L86.90-5.26Q85.59-7.65 85.59-11.12L85.59-11.12Q85.59-16.74 89.37-19.84L89.37-19.84Q91.84-21.91 96.08-21.91L96.08-21.91ZM97.38-4.68L101.75-4.68L101.75-17.23L97.38-17.23Q94.50-17.23 93.02-15.30L93.02-15.30Q91.71-13.68 91.71-11.12L91.71-11.12Q91.71-7.38 93.87-5.76L93.87-5.76Q95.36-4.68 97.38-4.68L97.38-4.68Z"
fill="#2c3e50"
transform="translate(28, 430) scale(4,4)"
></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,295 +0,0 @@
<template>
<a-drawer
title="授权管理"
placement="right"
:closable="true"
width="500px"
v-model:visible="visible"
:destroyOnClose="true"
@after-visible-change="onAfterVisibleChange"
>
<div class="d-container access-provider-manager">
<a-button @click="add">
添加授权
</a-button>
<a-list
class="list"
item-layout="horizontal"
:data-source="getProviders()"
>
<template #renderItem="{ item ,index }">
<a-list-item>
<template #actions>
<a-button type="primary" @click="openEdit(item,index)"><template #icon><EditOutlined /></template></a-button>
<a-button type="danger" @click="remove(item,index)"><template #icon ><DeleteOutlined /></template></a-button>
</template>
<a-radio :disabled="isDisabled(item)" :checked="item.key===selectedKey" @update:checked="selectedKey = item.key" >
{{ item.name }} ({{item.type}})
</a-radio>
</a-list-item>
</template>
</a-list>
<div>
<a-button @click="onProviderSelectSubmit">确定</a-button>
</div>
</div>
</a-drawer>
<a-modal v-model:visible="editVisible" dialogClass="d-dialog" width="700px" title="编辑授权" @ok="onSubmit">
<a-alert v-if="currentProvider?.desc" :message="currentProvider.desc" type="success" />
<a-form ref="formRef" class="domain-form" :model="formData" labelWidth="150px" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="类型" name="type" :rules="rules.type">
<a-radio-group :disabled="editIndex!=null" v-model:value="formData.type" @change="onTypeChanged" >
<a-radio-button v-for="(option) of providerDefineList" :disabled="isDisabled(option,'name')" :key="option.name" :value="option.name">
{{option.label}}
</a-radio-button>
</a-radio-group>
</a-form-item>
<template v-if="formData.type && currentProvider">
<a-form-item label="名称" name="name" :rules="rules.name">
<a-input v-model:value="formData.name"/>
</a-form-item>
<a-form-item v-for="(item,key,index) in currentProvider.input"
:key="index"
v-bind="item.component||{}"
:label="item.label || key"
:name="key">
<component-render v-model:value="formData[key]" v-bind="item.component || {}"></component-render>
<template #extra >
<div v-if="item.desc" class="helper">{{item.desc}}</div>
</template>
</a-form-item>
</template>
</a-form>
</a-modal>
</template>
<script>
import { ref, reactive, nextTick, watch, inject } from 'vue'
import _ from 'lodash-es'
import providerApi from '../../api/api.access-providers'
function useEdit (props, context, onEditSave) {
const formData = reactive({
key: '',
name: '',
type: undefined
})
const rules = ref({
type: [{
type: 'string',
required: true,
message: '请选择类型'
}],
name: [{
type: 'string',
required: true,
message: '请输入名称'
}]
})
const formRef = ref()
// eslint-disable-next-line no-unused-vars
// const { resetFields, validate, validateInfos } = useForm(formData, rules)
const onSubmit = async e => {
e.preventDefault()
const res = await formRef.value.validate()
console.log('validation:', res)
const newProvider = _.cloneDeep(formData)
onEditSave(newProvider, editIndex.value)
closeEdit()
}
const editVisible = ref(false)
const editIndex = ref(null)
const openEdit = (item, index) => {
if (item) {
editIndex.value = index
_.forEach(formData, (value, key) => {
formData[key] = null
})
_.merge(formData, item)
changeType(item.type)
} else {
editIndex.value = null
formData.type = null
}
editVisible.value = true
}
const add = () => {
openEdit()
}
const closeEdit = () => {
editVisible.value = false
}
const providerDefineList = ref([])
const onCreated = async () => {
providerDefineList.value = await providerApi.list()
}
onCreated()
const currentProvider = ref(null)
const onTypeChanged = (e) => {
const value = e.target.value
changeType(value)
// 遍历input 设置到form rules
}
const changeType = (type) => {
if (providerDefineList.value == null) {
return
}
for (const item of providerDefineList.value) {
if (item.name === type) {
currentProvider.value = item
break
}
}
if (editIndex.value == null) {
// 添加时
formData.key = currentProvider.value.name
formData.name = currentProvider.value.label || currentProvider.value.name
// 设置默认值
for (const key in currentProvider.value.input) {
const input = currentProvider.value.input[key]
if (input.default != null) {
formData[key] = input.default
}
}
}
}
const isDisabled = (item, keyName = 'type') => {
if (!props.filter) {
return false
}
return item[keyName
] !== props.filter
}
return {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
formData,
onSubmit,
rules,
editVisible,
formRef,
currentProvider,
providerDefineList,
editIndex,
openEdit,
onTypeChanged,
add,
isDisabled
}
}
let index = 0
const keyPrefix = 'provider_'
function generateNewKey (list) {
index++
let exists = false
for (const item of list) {
if (item.key === keyPrefix + index) {
exists = true
break
}
}
if (exists) {
return generateNewKey(list)
}
return keyPrefix + index
}
export default {
name: 'access-provider-manager',
props: {
value: {},
filter: {}
},
emits: ['update:value'],
setup (props, context) {
const visible = ref(false)
const close = () => {
visible.value = false
}
const onAfterVisibleChange = () => {
}
const getProviders = inject('get:accessProviders')
// const providerList = ref([])
const selectedKey = ref(null)
watch(() => props.value, () => {
selectedKey.value = props.value
}, { immediate: true })
const onEditSave = (newProvider, editIndex) => {
const providerList = getProviders()
if (editIndex == null) {
// add 生成一个key
newProvider.key = generateNewKey(providerList)
providerList.push(newProvider)
} else {
_.merge(providerList[editIndex], newProvider)
}
}
const editModule = useEdit(props, context, onEditSave)
const open = () => {
visible.value = true
const providerList = getProviders()
if (providerList.length === 0) {
nextTick(() => {
editModule.add()
})
}
}
const remove = (item, index) => {
const providerList = getProviders()
providerList.splice(index, 1)
}
const updateProviders = inject('update:accessProviders')
// watch(() => providers, () => {
// providerList.value = _.cloneDeep(props.providers || [])
// }, { immediate: true })
const onProviderSelectSubmit = () => {
const providerList = getProviders()
updateProviders(providerList)
context.emit('update:value', selectedKey.value)
close()
}
return {
visible,
open,
close,
onAfterVisibleChange,
remove,
selectedKey,
onProviderSelectSubmit,
getProviders,
...editModule
}
}
}
</script>
<style lang="less">
.access-provider-manager{
padding:10px;
}
</style>
@@ -1,87 +0,0 @@
<template>
<div>
<div class="access-provider-selector">
<a-select
:value="value"
@update:value="valueUpdate"
placeholder="没有可选时请点右边按钮添加"
>
<a-select-option v-for="item of getProviders()" :key="item.key" :value="item.key" :disabled="isDisabled(item)">
{{ item.name }}
</a-select-option>
</a-select>
<a-button class="suffix" @click="providerManagerOpen">
添加授权
</a-button>
</div>
<access-provider-manager ref="providerManagerRef"
:value="value"
:filter="filter"
@update:value="valueUpdate"
></access-provider-manager>
</div>
</template>
<script>
import { ref, inject } from 'vue'
import AccessProviderManager from './access-provider-manager.vue'
export default {
name: 'access-provider-selector',
components: { AccessProviderManager },
emits: ['update:providers', 'update:value'],
// 属性定义
props: {
value: {
type: String
},
filter: {}
},
setup (props, context) {
const providerManagerRef = ref(null)
const providerManagerOpen = () => {
console.log('providerManagerRef', providerManagerRef)
if (providerManagerRef.value) {
providerManagerRef.value.open()
}
}
const providersUpdate = (val) => {
console.log('accessUpdate', val)
context.emit('update:providers', val)
}
const valueUpdate = (val) => {
context.emit('update:value', val)
}
const isDisabled = (item) => {
if (!props.filter) {
return false
}
return item.type !== props.filter
}
const getProviders = inject('get:accessProviders')
return {
providersUpdate,
valueUpdate,
providerManagerOpen,
providerManagerRef,
isDisabled,
getProviders
}
}
}
</script>
<style lang="less">
.access-provider-selector{
display: flex;
flex-direction: row;
.ant-select{
flex:1;
}
.suffix{
flex-shrink: 0;
margin-left:5px;
}
}
</style>
@@ -1,33 +0,0 @@
<script>
import { h, resolveComponent } from 'vue'
import _ from 'lodash-es'
export default {
name: 'component-render',
props: {
name: {
type: String,
default: 'a-input'
},
children: {
type: Array
},
on: {
type: Object
}
},
setup (props, context) {
const attrs = {
...context.$attrs
}
_.forEach(props.on, (value, key) => {
attrs[key] = value
if (typeof value === 'string') {
// eslint-disable-next-line no-eval
attrs[key] = eval(value)
}
})
const comp = resolveComponent(props.name)
return () => h(comp, context.$attrs, props.children)
}
}
</script>
@@ -1,56 +0,0 @@
<template>
<div class="d-container">
<div class="box">
<div class="inner">
<div class="header">
<slot name="header"></slot>
</div>
<div class="body">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'd-container'
}
</script>
<style lang="less">
.d-container{
height: 100%;
width: 100%;
position: relative;
.box {
height: 100%;
position: absolute;
width: 100%;
top: 0;
left: 0;
.inner{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
.header{
flex-shrink: 0;
}
.body{
overflow-y: auto;
flex:1
}
.footer{
flex-shrink: 0;
}
}
}
}
</style>
@@ -1,16 +0,0 @@
import DContainer from './d-container.vue'
import ComponentRender from './component-render.vue'
import AccessProviderSelector from './access-provider-selector/access-provider-selector.vue'
const list = [
DContainer,
ComponentRender,
AccessProviderSelector
]
export default {
install (app) {
for (const item of list) {
app.component(item.name, item)
}
}
}
-11
View File
@@ -1,11 +0,0 @@
import { createI18n } from 'vue-i18n'
import zh from './locales/zh.json'
import en from './locales/en.json'
export const i18n = createI18n({
// something vue-i18n options here ...
locale: 'zh', // set current locale
messages: {
en,
zh
}
})
-26
View File
@@ -1,26 +0,0 @@
import _ from 'lodash'
import {
PlusCircleOutlined,
PlusOutlined,
CheckOutlined, EditOutlined,
ArrowRightOutlined,
NodeIndexOutlined,
ThunderboltOutlined,
DeleteOutlined
} from '@ant-design/icons-vue'
const icons = {
PlusCircleOutlined,
PlusOutlined,
CheckOutlined,
EditOutlined,
ArrowRightOutlined,
NodeIndexOutlined,
ThunderboltOutlined,
DeleteOutlined
}
export default function (app) {
_.forEach(icons, (item, key) => {
app.component(key, item)
})
}
-3
View File
@@ -1,3 +0,0 @@
{
}
-9
View File
@@ -1,9 +0,0 @@
{
"hello": "你好",
"domain": "域名",
"next": "下一步",
"submit": "提交",
"reset": "重置",
"please.input.domain": "请输入域名",
"email": "邮箱"
}
-13
View File
@@ -1,13 +0,0 @@
import { createApp } from 'vue'
import router from './router'
import App from './App.vue'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import './style/common.less'
import icons from './icons'
import components from './components'
const app = createApp(App)
icons(app)
app.use(Antd)
app.use(components)
app.use(router).mount('#app')
-24
View File
@@ -1,24 +0,0 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Detail from '../views/detail/index.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/detail',
name: 'detail',
component: Detail
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
@@ -1,97 +0,0 @@
div#app {
height: 100%
}
h1, h2, h3, h4, h5, h6 {
margin-bottom: 0;
}
.flex-center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.flex-row {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.ml-10{
margin-left:10px;
}
.mt-10{
margin-top:10px;
}
.mr-10{
margin-right:10px;
}
.mb-10{
margin-bottom:10px;
}
.ant-layout {
height: 100%
}
.ant-form{
.ant-form-item-children {
&>{
min-height: 40px;
display: flex;
flex-direction: column;
justify-content: center;
}
}
.ant-form-explain, .ant-form-extra{
font-size:12px;
line-height: 1.4;
min-height: 20px;
margin:0px;
padding:0px;
}
}
.ant-drawer-body{
padding:0px;
}
.ant-drawer-content {
.ant-drawer-wrapper-body{
display: flex;
flex-direction: column;
}
.ant-drawer-body {
position: relative;
flex:1;
}
}
.d-dialog{
.ant-modal-body{
max-height: 60vh;
overflow-y: auto;
}
@media(min-height:600px) and (max-height:700px){
.ant-modal-body {
max-height: 50vh
}
}
@media (max-height:600px) {
.ant-modal-body {
max-height: 40vh
}
}
}
@@ -1,33 +0,0 @@
import _ from 'lodash-es'
export default {
arrayToMap (array) {
if (!array) {
return {}
}
if (!_.isArray(array)) {
return array
}
const map = {}
for (const item of array) {
if (item.key) {
map[item.key] = item
}
}
return map
},
mapToArray (map) {
if (!map) {
return []
}
if (_.isArray(map)) {
return map
}
const array = []
for (const key in map) {
const item = map[key]
item.key = key
array.push(item)
}
return array
}
}
@@ -1,40 +0,0 @@
import _ from "lodash-es";
export function getEnvValue(key) {
// @ts-ignore
return import.meta.env["VITE_APP_" + key];
}
export class EnvConfig {
API;
MODE;
STORAGE;
TITLE;
PM_ENABLED;
constructor() {
this.init();
}
init() {
// @ts-ignore
_.forEach(import.meta.env, (value, key) => {
if (key.startsWith("VITE_APP")) {
key = key.replace("VITE_APP_", "");
this[key] = value;
}
});
// @ts-ignore
this.MODE = import.meta.env.MODE;
}
get(key, defaultValue) {
return this[key] ?? defaultValue;
}
isDev() {
return this.MODE === "development" || this.MODE === "debug";
}
isProd() {
return this.MODE === "production";
}
}
export const env = new EnvConfig();
-122
View File
@@ -1,122 +0,0 @@
<template>
<div class="page-index flex-center">
<h2 class="title">CERT-D</h2>
<div class="page-body">
<a-tabs >
<a-tab-pane key="1" tab="创建新证书">
<div class="create-from-domains">
<div class="input-row flex-row">
<a-select
size="large"
mode="tags"
placeholder="请输入域名"
v-model:value="formData.cert.domains"
:open="false"
></a-select>
<div class="row-append">
<a-button size="large" type="primary" @click="createFromDomain">创建新证书</a-button>
</div>
</div>
<div class="helper">
支持泛域名例如*.test.yourdomain.com<br/>
支持多个域名打包到一张证书输入一个域名后回车再输下一个
</div>
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="从配置导入" force-render>
<a-textarea v-model:value="optionsText" class="textarea" type="textarea" :auto-size="autoSize" allow-clear></a-textarea>
<a-button class="mt-10" type="primary" @click="createFromText">导入</a-button>
</a-tab-pane>
</a-tabs>
</div>
</div>
</template>
<script>
// eslint-disable-next-line no-unused-vars
import { reactive, toRaw, ref } from 'vue'
import { useRouter } from 'vue-router'
export default {
setup () {
const formData = reactive({
cert: {
domains: [],
email: '',
dnsProvider: { type: undefined }
}
})
const router = useRouter()
const createFromDomain = () => {
console.log("formData:",formData)
goToDetail(JSON.stringify(formData))
}
const goToDetail = (options) => {
console.log("options:",options)
router.push({ name: 'detail', state: { options } })
}
const autoSize = reactive({ minRows: 8, maxRows: 10 })
const optionsText = ref()
const createFromText = () => {
try {
JSON.parse(optionsText.value)
} catch (e) {
throw new Error('json格式有误', e)
}
goToDetail(optionsText.value)
}
return {
createFromDomain,
formData,
autoSize,
optionsText,
createFromText
}
}
}
</script>
<style lang="less">
.page-index{
background-color: #fff;
height: 100%;
&.flex-center{
justify-content: flex-start;
}
.title{
margin:50px;
}
.page-body{
min-width: 700px;width: 60%
}
.create-from-domains{
width:100%;
.input-row{
width:100%;
.ant-select{
flex:1;
}
.row-append{
padding-left:10px
}
}
}
.helper{
margin-top:5px;
}
.ant-tabs-bar {
margin: 0 0 16px;
border-bottom: 1px solid #f0f0f0;
outline: none;
}
}
</style>
@@ -1,261 +0,0 @@
<template>
<a-drawer
title="证书申请配置"
placement="right"
:closable="true"
width="600px"
v-model:visible="visible"
@after-visible-change="afterVisibleChange"
>
<d-container>
<a-form class="domain-form" :model="formData" :scrollToFirstError="true" :label-col="labelCol" :wrapper-col="wrapperCol">
<h3>域名信息</h3>
<a-form-item label="域名" v-bind="validateInfos.domains">
<a-select
mode="tags"
placeholder="请输入域名"
v-model:value="formData.domains"
:open="false"
></a-select>
<template #extra >
例如*.yourdomain.com输入完成后回车支持多个
</template>
</a-form-item>
<a-form-item label="邮箱" v-bind="validateInfos.email">
<a-input v-model:value="formData.email"/>
</a-form-item>
<a-form-item label="dns验证" v-bind="validateInfos['dnsProvider.type']">
<a-select v-model:value="formData.dnsProvider.type" @change="onCurrentDnsProviderChanged">
<a-select-option v-for="item of dnsProviderDefineList" :key="item.name" :value="item.name">{{item.label}}</a-select-option>
</a-select>
</a-form-item>
<template v-if="currentDnsProviderDefine">
<a-form-item v-for="(item,key) in currentDnsProviderDefine.input" v-bind="item.component || {}" :key="key" :label="item.label" :name="'dnsProvider.'+key">
<component-render v-model:value="formData.dnsProvider[key]" v-bind="item.component || {}"></component-render>
<template #extra v-if="item.desc" >
{{item.desc}}
</template>
</a-form-item>
</template>
<a-form-item label="CA" v-bind="validateInfos.ca">
<a-radio-group v-model:value="formData.ca" >
<a-radio value="LetEncrypt">
LetEncrypt
</a-radio>
</a-radio-group>
</a-form-item>
<h3>CSR <span>必须全英文</span></h3>
<a-form-item label="国家" v-bind="validateInfos['csr.country']">
<a-input v-model:value="formData.csr.country"/>
</a-form-item>
<a-form-item label="省份" v-bind="validateInfos['csr.state']">
<a-input v-model:value="formData.csr.state"/>
</a-form-item>
<a-form-item label="市区" v-bind="validateInfos['csr.locality']">
<a-input v-model:value="formData.csr.locality"/>
</a-form-item>
<a-form-item label="组织" v-bind="validateInfos['csr.organization']">
<a-input v-model:value="formData.csr.organization"/>
</a-form-item>
<a-form-item label="部门" v-bind="validateInfos['csr.organizationUnit']">
<a-input v-model:value="formData.csr.organizationUnit"/>
</a-form-item>
<a-form-item label="联系人邮箱">
<a-input v-model:value="formData.csr.emailAddress"/>
</a-form-item>
</a-form>
<template #footer>
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="onSubmit">
确定
</a-button>
</a-form-item>
</template>
</d-container>
</a-drawer>
</template>
<script>
import { reactive, ref, watch } from 'vue'
import { Form } from 'ant-design-vue';
const useForm = Form.useForm;
import dnsProviderApi from '../../../api/api.dns-providers'
import _ from 'lodash-es'
function useDrawer () {
const visible = ref(false)
const afterVisibleChange = (val) => {
console.log('visible', val)
}
const open = () => {
visible.value = true
}
const close = () => {
visible.value = false
}
return {
afterVisibleChange,
open,
close,
visible
}
}
export default {
name: 'cert-form',
emits: ['update:accessProviders', 'update:cert'],
// 属性定义
props: {
cert: {
type: Object
},
accessProviders: {
type: Object
}
},
setup (props, context) {
const drawer = useDrawer()
const certFormData = {
domains: [],
email: undefined,
dnsProvider: { type: undefined, accessProvider: undefined },
ca: 'LetEncrypt',
csr: {
country: '',
state: 'GuangDong',
locality: 'ShengZhen',
organization: 'CertD Org.',
organizationUnit: 'IT Department',
emailAddress: undefined
}
}
const formData = reactive(certFormData)
watch(props.cert, () => {
console.log('cert props')
_.merge(formData, props.cert)
}, { immediate: true })
const rules = reactive({
domains: [{
type: 'array',
required: true,
message: '请输入域名'
}],
email: [{
type: 'email',
required: true,
message: '请输入正确的邮箱'
}],
'dnsProvider.type': [{
required: true,
message: '请选择dns类型'
}],
'dnsProvider.accessProvider': [{
required: true,
message: '请选择dns授权提供者'
}],
'csr.country': [{ required: true, message: '请输入国家代码' }],
'csr.state': [{ required: true, message: '请输入省份' }],
'csr.locality': [{ required: true, message: '请输入市区' }],
'csr.organization': [{ required: false, message: '请输入组织名称' }],
'csr.organizationUnit': [{ required: false, message: '请输入部门名称' }],
'csr.emailAddress': [{ required: false, message: '请输入邮箱' }]
})
// eslint-disable-next-line no-unused-vars
const { resetFields, validate, validateInfos, mergeValidateInfo } = useForm(formData, rules)
console.log('validateInfos', validateInfos)
const onSubmit = async e => {
e.preventDefault()
try {
await validate()
context.emit('update:cert', formData)
drawer.close()
} catch (err) {
console.error('表单校验错误', err)
}
}
const reset = () => {
resetFields()
}
const providerManagerRef = ref(null)
const providerManagerOpen = () => {
console.log('providerManagerRef', providerManagerRef)
if (providerManagerRef.value) {
providerManagerRef.value.open()
}
}
const accessProvidersUpdate = (val) => {
console.log('accessUpdate', val)
context.emit('update:accessProviders', val)
}
const dnsProviderDefineList = ref()
const currentDnsProviderDefine = ref()
const onCreate = async () => {
const list = await dnsProviderApi.list()
dnsProviderDefineList.value = list
onCurrentDnsProviderChanged(formData?.dnsProvider?.type)
}
const onCurrentDnsProviderChanged = (type) => {
if (type == null) {
return
}
formData.dnsProvider.type = type
formData.dnsProvider.accessProvider = null
for (const item of dnsProviderDefineList.value) {
if (item.name === type) {
currentDnsProviderDefine.value = item
return
}
}
}
onCreate()
return {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
formData,
onSubmit,
reset,
validateInfos,
providerManagerRef,
providerManagerOpen,
accessProvidersUpdate,
dnsProviderDefineList,
onCurrentDnsProviderChanged,
currentDnsProviderDefine,
...drawer
}
}
}
</script>
<style lang="less">
.ant-form.domain-form {
height: 100%;
overflow-y: auto;
padding: 10px 24px;
h3 {
span {
font-weight: 200;
margin-left: 5px;
font-size: 12px;
color: #888;
}
}
}
</style>
@@ -1,314 +0,0 @@
<template>
<a-drawer
placement="right"
:closable="true"
width="600px"
v-model:visible="taskDrawerVisible"
@after-visible-change="taskDrawerOnAfterVisibleChange"
>
<template #title>
编辑任务
<a-button @click="taskDelete()">
<template #icon><DeleteOutlined /></template>
</a-button>
</template>
<template v-if="currentTask">
<d-container v-if="currentTask._isAdd" class="task-edit-form">
<a-row :gutter="10">
<a-col v-for="(item,index) of taskPluginDefineList" :key="index" class="task-plugin" :span="12">
<a-card hoverable :class="{'current':item.name === currentTask.type}"
@click="taskTypeSelected(item)" @dblclick="taskTypeSelected(item);taskTypeSave()">
<a-card-meta>
<template #title>
<a-avatar :src="item.icon||'/images/plugin.png'"/>
<span class="title">{{ item.label }}</span>
</template>
<template #description>
<span :title="item.desc">{{ item.desc }}</span>
</template>
</a-card-meta>
</a-card>
</a-col>
</a-row>
<a-button type="primary" @click="taskTypeSave">
确定
</a-button>
</d-container>
<d-container v-else class="d-container" >
<a-form ref="taskFormRef" class="task-form" :model="currentTask" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="任务名称" name="taskName" :rules="rules.name">
<a-input
placeholder="请输入任务名称"
v-model:value="currentTask.taskName"
></a-input>
</a-form-item>
<a-form-item v-for="(item,key) in currentPlugin.input" v-bind="item.component || {}" :key="key" :label="item.label" :name="'props.'+key">
<component-render v-model:value="currentTask['props.'+key]" v-bind="item.component || {}"></component-render>
<template #extra v-if="item.desc" >
{{item.desc}}
</template>
</a-form-item>
</a-form>
<template #footer>
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="taskSave">
确定
</a-button>
</a-form-item>
</template>
</d-container>
</template>
</a-drawer>
</template>
<script>
import { message } from 'ant-design-vue'
import pluginsApi from '../../../api/api.plugins'
import { ref } from 'vue'
// eslint-disable-next-line no-unused-vars
import _ from 'lodash-es'
/**
* task drawer
* @returns
*/
function useTaskForm (context) {
const taskPluginDefineList = ref([])
const onCreated = async () => {
const plugins = await pluginsApi.list()
console.log('plugins', plugins)
taskPluginDefineList.value = plugins
}
onCreated()
const currentTask = ref({ taskName: undefined })
const currentTaskIndex = ref()
const currentDeploy = ref()
const currentPlugin = ref(null)
const taskFormRef = ref(null)
const taskDrawerVisible = ref(false)
const rules = ref({
name: [{
type: 'string',
required: true,
message: '请输入名称'
}]
})
const taskAdd = (deploy) => {
const task = { taskName: '新任务', type: undefined, _isAdd: true }
currentDeploy.value = deploy
currentDeploy.value.tasks.push(task)
const index = deploy.tasks.length - 1
currentTask.value = deploy.tasks[index]
currentTaskIndex.value = index
taskDrawerShow()
console.log('currentTaskTypeChanged:', currentTask.value)
}
const taskTypeSelected = (item) => {
currentTask.value.type = item.name
currentTask.value.taskName = item.label
console.log('currentTaskTypeChanged:', currentTask.value)
}
const taskTypeSave = () => {
currentTask.value._isAdd = false
if (currentTask.value.type == null) {
message.warn('请先选择类型')
return
}
// 给task的input设置默认值
changeCurrentPlugin(currentTask.value)
if (currentTask.value.props) {
currentTask.value.props = {}
}
for (const key in currentPlugin.value.input) {
const input = currentPlugin.value.input[key]
if (input.default != null) {
currentTask.value.props[key] = input.default
}
}
}
const taskDrawerShow = () => {
taskDrawerVisible.value = true
}
const taskDrawerClose = () => {
taskDrawerVisible.value = false
}
const taskDrawerOnAfterVisibleChange = (val) => {
console.log('taskDrawerOnAfterVisibleChange', val)
}
const taskEdit = (deploy, task, index) => {
currentTask.value = flatData(_.cloneDeep(task))
console.log('currentTaskEdit', currentTask.value)
currentTaskIndex.value = index
currentDeploy.value = deploy
changeCurrentPlugin(currentTask.value)
taskDrawerShow()
}
const changeCurrentPlugin = (task) => {
const taskType = task.type
const currentPlugins = taskPluginDefineList.value.filter(p => {
return p.name === taskType
})
if (currentPlugins.length <= 0) {
task.type = undefined
task._isAdd = true
// throw new Error('未知插件:' + taskType)
}
currentPlugin.value = currentPlugins[0]
console.log('currentTaskTypeChanged:', currentTask.value)
}
const flatData = (obj, parentKey = '', member = obj) => {
_.forEach(member, (value, key) => {
const pathKey = parentKey + key
if (!_.isArray(value) && _.isObjectLike(value)) {
parentKey = pathKey + '.'
flatData(obj, parentKey, value)
if (parentKey === '') {
delete (obj[key])
}
} else {
obj[pathKey] = value
}
})
return obj
}
const unFlatData = (obj) => {
const newObj = {}
_.merge(newObj, obj)
for (const key in obj) {
const value = obj[key]
if (key.indexOf('.') >= 0) {
delete newObj[key]
_.set(newObj, key, value)
}
}
return newObj
}
const taskSave = async (e) => {
console.log('currentTaskSave', currentTask.value, currentTaskIndex.value)
e.preventDefault()
await taskFormRef.value.validate()
const newTask = unFlatData(currentTask.value)
currentDeploy.value.tasks[currentTaskIndex.value] = newTask
// context.emit('update', newTask)
taskDrawerClose()
}
const taskDelete = () => {
if (currentTaskIndex.value != null) {
currentDeploy.value.tasks.splice(currentTaskIndex.value, 1)
}
taskDrawerClose()
}
return {
taskTypeSelected,
taskTypeSave,
taskPluginDefineList,
taskFormRef,
taskAdd,
taskEdit,
taskDrawerShow,
taskDrawerVisible,
taskDrawerOnAfterVisibleChange,
currentTask,
currentTaskIndex,
currentPlugin,
taskSave,
taskDelete,
rules
}
}
function useProviderManager () {
const providerManager = ref(null)
const providerManagerOpen = () => {
providerManager.value.open()
}
return { providerManager, providerManagerOpen }
}
export default {
name: 'task-form',
emits: ['update'],
props: {
options: {}
},
setup (props, context) {
return {
...useTaskForm(context),
...useProviderManager(),
labelCol: { span: 6 },
wrapperCol: { span: 16 }
}
}
}
</script>
<style lang="less">
.task-edit-form{
.body{
padding:10px;
.ant-card {
margin-bottom: 10px;
&.current {
border-color: #00B7FF;
}
.ant-card-meta-title {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
.ant-avatar {
width: 24px;
height: 24px;
flex-shrink: 0;
}
.title {
margin-left: 5px;
white-space: nowrap;
flex: 1;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
.ant-card-body {
padding: 14px;
height: 100px;
overflow-y: hidden;
.ant-card-meta-description {
font-size: 10px;
line-height: 20px;
height: 40px;
color: #7f7f7f
}
}
}
}
</style>
@@ -1,502 +0,0 @@
<template>
<div class="page-detail">
<div class="flow">
<div class="flow-group flow-cert">
<h3 class="group-head">
证书申请
</h3>
<a-divider></a-divider>
<div class="cert-display group-body">
<a-button class="cert-edit-btn" type="link" @click="certFormOpen">
编辑
</a-button>
<div class="label-list">
<div class="title">证书</div>
<div class="label-item">
<label>域名:</label>
<div class="value">
<a-tag type="primary" v-for="item of options.cert.domains " :key="item">
{{ item }}
</a-tag>
</div>
</div>
<div class="label-item">
<label>邮箱:</label>
<div>
{{ options.cert.email }}
</div>
</div>
<div class="label-item">
<label>dns校验:</label>
<div>
<span v-if="options.cert?.dnsProvider">
{{ options.cert.dnsProvider?.type }}-
{{options.accessProviders[options.cert.dnsProvider.accessProvider]?.label}}
</span>
</div>
</div>
<div class="label-item">
<label>CA:</label>
<div>
{{ options.cert.ca }}
</div>
</div>
<br/>
<div class="title">
CSR
<span>必须全英文</span>
</div>
<div class="label-item">
<label>国家:</label>
<div>
{{ options.cert.csr.country }}
</div>
</div>
<div class="label-item">
<label>省份:</label>
<div>
{{ options.cert.csr.state }}
</div>
</div>
<div class="label-item">
<label>市区:</label>
<div>
{{ options.cert.csr.locality }}
</div>
</div>
<div class="label-item">
<label>组织:</label>
<div>
{{ options.cert.csr.organization }}
</div>
</div>
<div class="label-item">
<label>部门:</label>
<div>
{{ options.cert.csr.organizationUnit }}
</div>
</div>
<div class="label-item">
<label>邮箱:</label>
<div>
{{ options.cert.csr.emailAddress }}
</div>
</div>
</div>
</div>
</div>
<div class="flow-group flow-deploy">
<h3 class="group-head">
部署流程
<PlusCircleOutlined title="添加部署流程" class="add-icon" @click="deployAdd"/>
</h3>
<a-divider></a-divider>
<div class="group-body deploy-list">
<a-card class="deploy-item" v-for="(deploy,index) of options.deploy" :key="index">
<template #title>
<div class="deploy-name">
<template v-if="deploy._isEdit">
<a-input v-model:value="deploy.deployName"
:validateStatus="deploy.deployName?'':'error'"
placeholder="请输入流程名称"
@keyup.enter="deployCloseEditMode(deploy)"
@blur="deployCloseEditMode(deploy)"
>
<template #suffix>
<CheckOutlined @click="deployCloseEditMode(deploy)" style="color: rgba(0,0,0,.45)"/>
</template>
</a-input>
</template>
<template v-else>
<span @click="deployNameEdit"> <NodeIndexOutlined/> {{ deploy.deployName }}</span>
<EditOutlined class="ml-10 edit-icon" @click="deployOpenEditMode(deploy)"/>
</template>
</div>
</template>
<template #extra>
<a-button type="danger" @click="deployDelete(deploy,index)">
<template #icon><DeleteOutlined /></template>
</a-button>
</template>
<div class="task-list">
<div class="task-item-wrapper" v-for="(task,iindex) of deploy.tasks" :key="iindex">
<a-button class="task-item" shape="round" @click="taskEdit(deploy,task,index)">
<ThunderboltOutlined/>
{{ task.taskName }}
</a-button>
<ArrowRightOutlined class="task-next-icon"/>
</div>
<div class="task-item-wrapper">
<a-button type="primary" class="task-item" shape="round" @click="taskAdd(deploy)">
<PlusOutlined/>
添加新任务
</a-button>
</div>
</div>
</a-card>
</div>
</div>
<div class="flow-group flow-export">
<h3 class="group-head">
导出
</h3>
<a-divider></a-divider>
<div class="export group-body" >
<d-container>
<template #header>
<div><a-button @click="exportsToZip">导出为可执行项目</a-button></div>
<br/>
<!-- <div> <a-button @click="exportsToJson">复制options.json</a-button></div>-->
<!-- <br/>-->
</template>
<pre class="json">{{options}}</pre>
</d-container>
</div>
</div>
</div>
<cert-form ref="certFormRef" v-model:cert="options.cert" v-model:access-providers="options.accessProviders"></cert-form>
<task-form ref="taskFormRef" @update="taskUpdated" ></task-form>
</div>
</template>
<script>
import { message } from 'ant-design-vue'
// eslint-disable-next-line no-unused-vars
import { reactive, ref, toRef, toRefs, provide, readonly } from 'vue'
// eslint-disable-next-line no-unused-vars
import { useRoute,useRouter } from 'vue-router'
import CertForm from './components/cert-form.vue'
import TaskForm from './components/task-form.vue'
import exportsApi from '../../api/api.exports'
import _ from 'lodash-es'
import DContainer from '../../components/d-container.vue'
import commonUtil from '/src/utils/util.common'
function useDeploy (options) {
const deployAdd = () => {
options.deploy.push({
deployName: `D${options.deploy.length + 1}-新部署流程`,
_isEdit: false,
tasks: []
})
}
const deployCloseEditMode = (deploy) => {
if (!deploy.deployName) {
message.error('请输入流程名称')
return
}
deploy._isEdit = false
console.log('options', options)
}
const deployOpenEditMode = (deploy) => {
deploy._isEdit = true
}
const deployDelete = (deploy, index) => {
options.deploy.splice(index, 1)
}
return {
deployAdd, deployCloseEditMode, deployOpenEditMode, deployDelete
}
}
function useProvideAccessProviders (options) {
provide('get:accessProviders', () => {
return options.accessProviders
})
provide('update:accessProviders', (providers) => {
options.accessProviders = providers
})
}
function useExports (options) {
return {
async exportsToZip () {
await exportsApi.exportsToZip(options)
},
async exportsToJson () {
}
}
}
export default {
components: { DContainer, CertForm, TaskForm },
setup () {
const state = history.state
const optionParams = state.options ? JSON.parse(state.options ) : {}
if (optionParams.accessProviders) {
optionParams.accessProviders = commonUtil.mapToArray(optionParams.accessProviders)
}
const optionsDefault = {
cert: {
csr: {
country: 'CN',
state: 'GuangDong',
locality: 'ShengZhen',
organization: 'CertD Org.',
organizationUnit: 'IT Department'
}
},
accessProviders: [],
deploy: []
}
_.merge(optionsDefault, optionParams)
// optionsDefault.accessProviders = reactive(optionsDefault.accessProviders)
const options = reactive(optionsDefault)
const certFormChanged = (value) => {
console.log('certFormChanged', value)
options.cert = value
}
const certFormRef = ref(null)
const certFormOpen = () => {
certFormRef.value.open()
}
const taskFormRef = ref(null)
const taskAdd = (deploy) => {
taskFormRef.value.taskAdd(deploy)
}
const taskEdit = (deploy, task, index) => {
taskFormRef.value.taskEdit(deploy, task, index)
}
function taskUpdated(task){
console.log('task updated',task)
}
useProvideAccessProviders(options)
return {
options,
certFormChanged,
certFormRef,
certFormOpen,
...useDeploy(options),
taskFormRef,
taskAdd,
taskEdit,
taskUpdated,
...useExports(options)
}
}
}
</script>
<style lang="less">
.page-detail {
height: 100%;
overflow-y: auto;
position: relative;
width: 100%;
background-color: #fff;
.label-list {
.title{
font-weight: 500;
font-size: 16px;
color:#555;
span{
font-weight: 200;
margin-left:5px;
font-size: 12px;
color:#888;
}
}
.label-item {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: baseline;
padding: 8px 0px;
label {
width: 70px;
flex-shrink: 0;
color: rgba(0, 0, 0, 0.85);
font-weight: normal;
font-size: 14px;
line-height: 1.5715;
text-align: end;
padding-right: 10px;
}
.value {
flex: 1;
}
}
}
.flow {
height: 100%;
h3 {
text-align: center;
}
display: flex;
flex-direction: row;
.flow-group {
min-width: 300px;
height: 100%;
border-right: 1px #eee solid;
padding: 20px;
flex: 1;
display: flex;
flex-direction: column;
.group-head {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
.add-icon {
margin-left: 20px;
font-size: 24px;
color: #737070;
}
}
.group-body{
flex:1
}
}
.flow-cert {
max-width: 400px;
.cert-display {
position: relative;
.cert-edit-btn {
position: absolute;
right: 0px;
top: 0px;
}
}
}
.add-icon {
font-size: 26px;
}
.flow-deploy {
flex-shrink: 0;
flex: 1;
display: flex;
flex-direction: column;
.deploy-list {
flex: 1;
overflow-y: auto;
.deploy-item {
margin-bottom: 10px;
}
}
// min-width:70%;
.deploy-name {
max-width: 300px;
.edit-icon {
color: #737070;
}
}
}
.flow-export{
max-width: 500px;
}
}
}
.ant-form.task-form {
padding: 10px 24px;
}
.task-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
> * {
margin-bottom: 10px;
}
.task-item-wrapper {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
}
.task-item {
//border: 1px solid #eee;
//padding: 10px 20px;
//border-radius: 20px;
}
.task-add-icon {
font-size: 24px;
margin-right: 10px;
}
.task-next-icon {
margin-left: 10px;
margin-right: 10px;
}
}
.task-type-selector {
}
.task-form {
.task-plugin-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
> * {
margin-right: 8px;
}
.task-plugin {
margin-bottom: 10px;
}
}
}
</style>
@@ -1,13 +0,0 @@
import { expect } from 'chai'
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = shallowMount(HelloWorld, {
props: { msg }
})
expect(wrapper.text()).to.include(msg)
})
})
-45
View File
@@ -1,45 +0,0 @@
{
"compilerOptions": {
// 这样就可以对 `this` 上的数据属性进行更严格的推断`
"noImplicitAny": false,
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"outDir": "./dist/ts",
"types": [
"mocha",
"chai",
"node"
],
"paths": {
"/@/*": ["src/*"],
"/src/*": ["src/*"],
"/#/*": ["types/*"]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
-66
View File
@@ -1,66 +0,0 @@
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import visualizer from "rollup-plugin-visualizer";
import viteCompression from "vite-plugin-compression";
import * as path from "path";
// import { generateModifyVars } from "./build/modify-vars";
// import { configThemePlugin } from "./build/theme-plugin";
// import OptimizationPersist from "vite-plugin-optimize-persist";
// import PkgConfig from "vite-plugin-package-config";
// https://vitejs.dev/config/
// 增加环境变量 _
process.env.VITE_APP_VERSION = require("./package.json").version;
process.env.VITE_APP_BUILD_TIME = require("dayjs")().format("YYYY-M-D HH:mm:ss");
export default ({ command, mode }) => {
console.log("args", command, mode);
const devServerFs: any = {};
const devAlias: any[] = [];
return {
base: "/",
plugins: [
vueJsx(),
vue(),
// 压缩build后的代码
viteCompression()
],
esbuild: {
// pure: ["console.log", "debugger"],
jsxFactory: "h",
jsxFragment: "Fragment"
},
resolve: {
alias: [
...devAlias,
{ find: "/@", replacement: path.resolve("./src") },
{ find: "/#", replacement: path.resolve("./types") }
],
dedupe: ["vue"]
},
build: {
rollupOptions: {
plugins: [visualizer()]
}
},
css: {
preprocessorOptions: {
less: {
// 修改默认主题颜色,配置less变量
// modifyVars: generateModifyVars(),
javascriptEnabled: true
}
}
},
server: {
fs: devServerFs,
proxy: {
// with options
"/api": {
//配套后端 https://github.com/fast-crud/fs-server-js
target: "http://127.0.0.1:3000"
}
}
}
};
};