mirror of https://github.com/certd/certd
perf: 支持ftp上传
parent
ee617095ef
commit
b9bddbfabb
|
@ -0,0 +1,14 @@
|
||||||
|
version: '3.3'
|
||||||
|
services:
|
||||||
|
ftp:
|
||||||
|
# 镜像 # ↓↓↓↓↓ --- 1、 镜像版本号,建议改成固定版本号【可选】
|
||||||
|
image: gists/pure-ftpd
|
||||||
|
container_name: ftp # 容器名
|
||||||
|
restart: unless-stopped # 自动重启
|
||||||
|
volumes:
|
||||||
|
- /data/ftp2/:/home/ftpuser
|
||||||
|
ports: # 端口映射
|
||||||
|
- "21:21"
|
||||||
|
- "30000-30009:30000-30009"
|
||||||
|
environment: # 环境变量
|
||||||
|
- TZ=Asia/Shanghai
|
|
@ -1,20 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="layout-vip isPlus">
|
<div class="layout-vip isPlus" @click="openUpgrade">
|
||||||
<contextHolder />
|
<contextHolder />
|
||||||
<fs-icon icon="mingcute:vip-1-line"></fs-icon>
|
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
||||||
<div class="text">
|
|
||||||
<template v-if="userStore.isPlus">
|
<div v-if="mode !== 'icon'" class="text">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template #title> 到期时间:{{ expireTime }} </template>
|
<template #title> {{ text.title }}</template>
|
||||||
<span @click="openUpgrade">{{ texts.plus }}</span>
|
<span>{{ text.name }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title> 升级专业版,享受更多VIP特权 </template>
|
|
||||||
<span @click="openUpgrade"> {{ texts.free }} {{ expiredDays }} </span>
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -26,24 +19,53 @@ import { message, Modal } from "ant-design-vue";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useSettingStore } from "/@/store/modules/settings";
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = withDefaults(
|
||||||
mode?: "button" | "nav";
|
defineProps<{
|
||||||
}>();
|
mode?: "button" | "nav" | "icon";
|
||||||
type Texts = {
|
}>(),
|
||||||
plus: string;
|
{
|
||||||
free: string;
|
mode: "button"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
type Text = {
|
||||||
|
name: string;
|
||||||
|
title?: string;
|
||||||
};
|
};
|
||||||
const texts = computed<Texts>(() => {
|
const text = computed<Text>(() => {
|
||||||
if (props.mode === "button") {
|
const map = {
|
||||||
return {
|
isPlus: {
|
||||||
plus: "专业版已开通",
|
button: {
|
||||||
free: "此为专业版功能"
|
name: "专业版已开通",
|
||||||
|
title: "到期时间:" + expireTime.value
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
name: "",
|
||||||
|
title: "专业版已开通"
|
||||||
|
},
|
||||||
|
nav: {
|
||||||
|
name: "专业版",
|
||||||
|
title: "到期时间:" + expireTime.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
free: {
|
||||||
|
button: {
|
||||||
|
name: "此为专业版功能",
|
||||||
|
title: "升级专业版,享受更多VIP特权"
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
name: "",
|
||||||
|
title: "此为专业版功能"
|
||||||
|
},
|
||||||
|
nav: {
|
||||||
|
name: "免费版",
|
||||||
|
title: "升级专业版,享受更多VIP特权"
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
if (userStore.isPlus) {
|
||||||
|
return map.isPlus[props.mode];
|
||||||
} else {
|
} else {
|
||||||
return {
|
return map.free[props.mode];
|
||||||
plus: "专业版",
|
|
||||||
free: "免费版"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -86,6 +108,7 @@ async function doActive() {
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const computedSiteId = computed(() => settingStore.installInfo?.siteId);
|
const computedSiteId = computed(() => settingStore.installInfo?.siteId);
|
||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
|
|
||||||
function openUpgrade() {
|
function openUpgrade() {
|
||||||
const placeholder = "请输入激活码";
|
const placeholder = "请输入激活码";
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
|
@ -137,6 +160,7 @@ function openUpgrade() {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&.isPlus {
|
&.isPlus {
|
||||||
color: #c5913f;
|
color: #c5913f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<MenuFoldOutlined v-else />
|
<MenuFoldOutlined v-else />
|
||||||
</div>
|
</div>
|
||||||
<fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />
|
<fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />
|
||||||
<vip-button class="flex-center header-btn"></vip-button>
|
<vip-button class="flex-center header-btn" mode="nav" />
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right header-buttons">
|
<div class="header-right header-buttons">
|
||||||
<!-- <button-->
|
<!-- <button-->
|
||||||
|
|
|
@ -16,7 +16,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function buildDefineFields(define: any) {
|
function buildDefineFields(define: any, form: any) {
|
||||||
const formWrapperRef = crudExpose.getFormWrapperRef();
|
const formWrapperRef = crudExpose.getFormWrapperRef();
|
||||||
const columnsRef = toRef(formWrapperRef.formOptions, "columns");
|
const columnsRef = toRef(formWrapperRef.formOptions, "columns");
|
||||||
|
|
||||||
|
@ -32,7 +32,12 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any) {
|
||||||
...value,
|
...value,
|
||||||
key
|
key
|
||||||
};
|
};
|
||||||
columnsRef.value[key] = _.merge({ title: key }, defaultPluginConfig, field);
|
const column = _.merge({ title: key }, defaultPluginConfig, field);
|
||||||
|
if (column.value != null && _.get(form, key) == null) {
|
||||||
|
//设置默认值
|
||||||
|
_.set(form, key, column.value);
|
||||||
|
}
|
||||||
|
columnsRef.value[key] = column;
|
||||||
console.log("form", columnsRef.value);
|
console.log("form", columnsRef.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -55,13 +60,16 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any) {
|
||||||
rules: [{ required: true, message: "请选择类型" }],
|
rules: [{ required: true, message: "请选择类型" }],
|
||||||
valueChange: {
|
valueChange: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
async handle({ value, mode, form }) {
|
async handle({ value, mode, form, immediate }) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const define = await api.GetProviderDefine(value);
|
const define = await api.GetProviderDefine(value);
|
||||||
console.log("define", define);
|
console.log("define", define);
|
||||||
buildDefineFields(define);
|
if (!immediate) {
|
||||||
|
form.access = {};
|
||||||
|
}
|
||||||
|
buildDefineFields(define, form);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
<template #title>
|
<template #title>
|
||||||
<a-avatar :src="item.icon || '/images/plugin.png'" />
|
<a-avatar :src="item.icon || '/images/plugin.png'" />
|
||||||
<span class="title">{{ item.title }}</span>
|
<span class="title">{{ item.title }}</span>
|
||||||
|
<vip-button v-if="item.needPlus" mode="icon" />
|
||||||
</template>
|
</template>
|
||||||
<template #description>
|
<template #description>
|
||||||
<span :title="item.desc">{{ item.desc }}</span>
|
<span :title="item.desc">{{ item.desc }}</span>
|
||||||
|
@ -81,6 +82,7 @@ import _ from "lodash-es";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { CopyOutlined } from "@ant-design/icons-vue";
|
import { CopyOutlined } from "@ant-design/icons-vue";
|
||||||
import { PluginGroups } from "/@/views/certd/pipeline/pipeline/type";
|
import { PluginGroups } from "/@/views/certd/pipeline/pipeline/type";
|
||||||
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PiStepForm",
|
name: "PiStepForm",
|
||||||
|
@ -98,6 +100,7 @@ export default {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function useStepForm() {
|
function useStepForm() {
|
||||||
|
const useStore = useUserStore();
|
||||||
const getPluginGroups: any = inject("getPluginGroups");
|
const getPluginGroups: any = inject("getPluginGroups");
|
||||||
const pluginGroups: PluginGroups = getPluginGroups();
|
const pluginGroups: PluginGroups = getPluginGroups();
|
||||||
const mode: Ref = ref("add");
|
const mode: Ref = ref("add");
|
||||||
|
@ -117,6 +120,10 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
const stepTypeSelected = (item: any) => {
|
const stepTypeSelected = (item: any) => {
|
||||||
|
if (item.needPlus && !useStore.isPlus) {
|
||||||
|
message.warn("此插件需要开通专业版才能使用");
|
||||||
|
throw new Error("此插件需要开通专业版才能使用");
|
||||||
|
}
|
||||||
currentStep.value.type = item.name;
|
currentStep.value.type = item.name;
|
||||||
currentStep.value.title = item.title;
|
currentStep.value.title = item.title;
|
||||||
console.log("currentStepTypeChanged:", currentStep.value);
|
console.log("currentStepTypeChanged:", currentStep.value);
|
||||||
|
@ -128,6 +135,7 @@ export default {
|
||||||
message.warn("请先选择类型");
|
message.warn("请先选择类型");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 给step的input设置默认值
|
// 给step的input设置默认值
|
||||||
changeCurrentPlugin(currentStep.value);
|
changeCurrentPlugin(currentStep.value);
|
||||||
|
|
||||||
|
@ -347,7 +355,7 @@ export default {
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
|
||||||
.ant-card-meta-description {
|
.ant-card-meta-description {
|
||||||
font-size: 10px;
|
font-size: 12px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
color: #7f7f7f;
|
color: #7f7f7f;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"@certd/pipeline": "^1.24.0",
|
"@certd/pipeline": "^1.24.0",
|
||||||
"@certd/plugin-cert": "^1.24.0",
|
"@certd/plugin-cert": "^1.24.0",
|
||||||
"@certd/plugin-plus": "^1.24.0",
|
"@certd/plugin-plus": "^1.24.0",
|
||||||
"@koa/cors": "^3.4.3",
|
"@koa/cors": "^5.0.0",
|
||||||
"@midwayjs/bootstrap": "^3.16.2",
|
"@midwayjs/bootstrap": "^3.16.2",
|
||||||
"@midwayjs/cache": "^3.14.0",
|
"@midwayjs/cache": "^3.14.0",
|
||||||
"@midwayjs/core": "^3.16.2",
|
"@midwayjs/core": "^3.16.2",
|
||||||
|
@ -41,6 +41,7 @@
|
||||||
"@midwayjs/typeorm": "^3.16.4",
|
"@midwayjs/typeorm": "^3.16.4",
|
||||||
"@midwayjs/validate": "^3.16.4",
|
"@midwayjs/validate": "^3.16.4",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
"basic-ftp": "^5.0.5",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"cache-manager": "^3.6.3",
|
"cache-manager": "^3.6.3",
|
||||||
|
@ -50,7 +51,7 @@
|
||||||
"https-proxy-agent": "^7.0.4",
|
"https-proxy-agent": "^7.0.4",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^9.0.0",
|
||||||
"koa-send": "^5.0.1",
|
"koa-send": "^5.0.1",
|
||||||
"kubernetes-client": "^9.0.0",
|
"kubernetes-client": "^9.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
@ -65,7 +66,7 @@
|
||||||
"ssh2": "^1.15.0",
|
"ssh2": "^1.15.0",
|
||||||
"svg-captcha": "^1.4.0",
|
"svg-captcha": "^1.4.0",
|
||||||
"tencentcloud-sdk-nodejs": "^4.0.44",
|
"tencentcloud-sdk-nodejs": "^4.0.44",
|
||||||
"typeorm": "^0.3.11"
|
"typeorm": "0.3.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@midwayjs/mock": "^3.16.4",
|
"@midwayjs/mock": "^3.16.4",
|
||||||
|
|
|
@ -75,7 +75,8 @@ export class AccessService extends BaseService<AccessEntity> implements IAccessS
|
||||||
//星号保护
|
//星号保护
|
||||||
const length = value.length;
|
const length = value.length;
|
||||||
const subIndex = Math.min(2, length);
|
const subIndex = Math.min(2, length);
|
||||||
const starLength = length - subIndex * 2;
|
let starLength = length - subIndex * 2;
|
||||||
|
starLength = Math.max(2, starLength);
|
||||||
const starString = '*'.repeat(starLength);
|
const starString = '*'.repeat(starLength);
|
||||||
json[key] = value.substring(0, subIndex) + starString + value.substring(value.length - subIndex);
|
json[key] = value.substring(0, subIndex) + starString + value.substring(value.length - subIndex);
|
||||||
encryptSetting[key] = {
|
encryptSetting[key] = {
|
||||||
|
|
|
@ -74,14 +74,15 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||||
async getSetting<T>(type: any): Promise<T> {
|
async getSetting<T>(type: any): Promise<T> {
|
||||||
const key = type.__key__;
|
const key = type.__key__;
|
||||||
const cacheKey = type.getCacheKey();
|
const cacheKey = type.getCacheKey();
|
||||||
let settings: T = await this.cache.get(cacheKey);
|
const settings: T = await this.cache.get(cacheKey);
|
||||||
let settingInstance: T = new type();
|
if (settings) {
|
||||||
if (settings == null) {
|
return settings;
|
||||||
settings = await this.getSettingByKey(key);
|
|
||||||
settingInstance = _.merge(settingInstance, settings);
|
|
||||||
await this.cache.set(key, settingInstance);
|
|
||||||
}
|
}
|
||||||
return settingInstance;
|
let newSetting: T = new type();
|
||||||
|
const savedSettings = await this.getSettingByKey(key);
|
||||||
|
newSetting = _.merge(newSetting, savedSettings);
|
||||||
|
await this.cache.set(cacheKey, newSetting);
|
||||||
|
return newSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSetting<T extends BaseSettings>(bean: T) {
|
async saveSetting<T extends BaseSettings>(bean: T) {
|
||||||
|
|
Loading…
Reference in New Issue