修改前端包结构.

This commit is contained in:
lijiahang
2024-06-24 09:57:33 +08:00
parent 6c4e9cd5c6
commit ef10c8b8b6
11 changed files with 112 additions and 74 deletions

View File

@@ -0,0 +1,305 @@
<template>
<a-card class="general-card"
:body-style="{ padding: config.status === EnabledStatus.ENABLED ? '' : '0' }">
<!-- 标题 -->
<template #title>
<div class="config-title-wrapper">
<span>SSH 配置</span>
<a-switch v-model="config.status"
:disabled="loading"
type="round"
:checked-value="EnabledStatus.ENABLED"
:unchecked-value="EnabledStatus.DISABLED"
:before-change="s => updateStatus(s as number)" />
</div>
</template>
<!-- 表单 -->
<a-spin v-show="config.status" :loading="loading" class="config-form-wrapper">
<!-- 表单 -->
<a-form :model="formModel"
ref="formRef"
label-align="right"
:auto-label-width="true"
:rules="rules">
<!-- 系统类型 -->
<a-form-item field="osType"
label="系统类型"
:hide-asterisk="true">
<a-select v-model="formModel.osType"
:options="toOptions(sshOsTypeKey)"
placeholder="请选择系统类型" />
</a-form-item>
<!-- 用户名 -->
<a-form-item field="username"
label="用户名"
:rules="usernameRules"
:help="SshAuthType.IDENTITY === formModel.authType ? '将使用主机身份的用户名' : undefined">
<a-input v-model="formModel.username"
:disabled="SshAuthType.IDENTITY === formModel.authType"
placeholder="请输入用户名" />
</a-form-item>
<!-- SSH 端口 -->
<a-form-item field="port"
label="SSH端口"
:hide-asterisk="true">
<a-input-number v-model="formModel.port"
placeholder="请输入SSH端口"
hide-button />
</a-form-item>
<!-- 验证方式 -->
<a-form-item field="authType"
label="验证方式"
:hide-asterisk="true">
<a-radio-group type="button"
class="auth-type-group usn"
v-model="formModel.authType"
:options="toRadioOptions(sshAuthTypeKey)" />
</a-form-item>
<!-- 主机密码 -->
<a-form-item v-if="SshAuthType.PASSWORD === formModel.authType"
field="password"
label="主机密码"
:rules="passwordRules">
<a-input-password v-model="formModel.password"
:disabled="!formModel.useNewPassword && formModel.hasPassword"
placeholder="主机密码" />
<a-switch v-if="formModel.hasPassword"
v-model="formModel.useNewPassword"
class="password-switch"
type="round"
checked-text="使用新密码"
unchecked-text="使用原密码" />
</a-form-item>
<!-- 主机密钥 -->
<a-form-item v-if="SshAuthType.KEY === formModel.authType"
field="keyId"
label="主机密钥"
:hide-asterisk="true">
<host-key-selector v-model="formModel.keyId" />
</a-form-item>
<!-- 主机身份 -->
<a-form-item v-if="SshAuthType.IDENTITY === formModel.authType"
field="identityId"
label="主机身份"
:hide-asterisk="true">
<host-identity-selector v-model="formModel.identityId" />
</a-form-item>
<!-- 用户名 -->
<a-form-item field="connectTimeout"
label="连接超时时间"
:hide-asterisk="true">
<a-input-number v-model="formModel.connectTimeout"
placeholder="请输入连接超时时间"
hide-button>
<template #suffix>
ms
</template>
</a-input-number>
</a-form-item>
<!-- SSH输出编码 -->
<a-form-item field="charset"
label="SSH输出编码"
:hide-asterisk="true">
<a-input v-model="formModel.charset" placeholder="请输入 SSH 输出编码" />
</a-form-item>
<!-- 文件名称编码 -->
<a-form-item field="fileNameCharset"
label="文件名称编码"
:hide-asterisk="true">
<a-input v-model="formModel.fileNameCharset" placeholder="请输入 SFTP 文件名称编码" />
</a-form-item>
<!-- 文件内容编码 -->
<a-form-item field="fileContentCharset"
label="文件内容编码"
:hide-asterisk="true">
<a-input v-model="formModel.fileContentCharset" placeholder="请输入 SFTP 文件内容编码" />
</a-form-item>
</a-form>
<!-- 操作按钮 -->
<div class="config-button-group">
<a-space>
<a-button size="small"
@click="resetConfig">
重置
</a-button>
<a-button type="primary"
size="small"
@click="saveConfig">
保存
</a-button>
</a-space>
</div>
</a-spin>
</a-card>
</template>
<script lang="ts">
export default {
name: 'sshConfigForm'
};
</script>
<script lang="ts" setup>
import type { FieldRule } from '@arco-design/web-vue';
import type { HostSshConfig } from '../types/const';
import { reactive, ref, watch } from 'vue';
import { updateHostConfigStatus, updateHostConfig } from '@/api/asset/host-config';
import { sshAuthTypeKey, sshOsTypeKey, SshAuthType, SshOsType } from '../types/const';
import rules from '../types/ssh-form.rules';
import { Message } from '@arco-design/web-vue';
import useLoading from '@/hooks/loading';
import { useDictStore } from '@/store';
import { EnabledStatus } from '@/types/const';
import { HostConfigType } from '../types/const';
import HostKeySelector from '@/components/asset/host-key/selector/index.vue';
import HostIdentitySelector from '@/components/asset/host-identity/selector/index.vue';
const { loading, setLoading } = useLoading();
const { toOptions, toRadioOptions } = useDictStore();
const props = defineProps<{
content: any;
hostId: number;
}>();
const emits = defineEmits(['submitted']);
const config = reactive({
status: undefined,
version: undefined,
});
const formRef = ref();
const formModel = ref<HostSshConfig>({
osType: SshOsType.LINUX,
username: undefined,
port: undefined,
password: undefined,
authType: SshAuthType.PASSWORD,
keyId: undefined,
identityId: undefined,
connectTimeout: undefined,
charset: undefined,
fileNameCharset: undefined,
fileContentCharset: undefined,
useNewPassword: false,
hasPassword: false,
});
// 监听数据变化
watch(() => props.content, (v: any) => {
config.status = v?.status;
config.version = v?.version;
resetConfig();
});
// 用户名验证
const usernameRules = [{
validator: (value, cb) => {
if (value && value.length > 128) {
cb('用户名长度不能大于128位');
return;
}
if (formModel.value.authType !== SshAuthType.IDENTITY && !value) {
cb('请输入用户名');
return;
}
}
}] as FieldRule[];
// 密码验证
const passwordRules = [{
validator: (value, cb) => {
if (value && value.length > 256) {
cb('密码长度不能大于256位');
return;
}
if (formModel.value.useNewPassword && !value) {
cb('请输入密码');
return;
}
}
}] as FieldRule[];
// 修改状态
const updateStatus = async (e: number) => {
setLoading(true);
return updateHostConfigStatus({
hostId: props?.hostId,
type: HostConfigType.SSH,
status: e,
version: config.version
}).then(({ data }) => {
config.version = data;
setLoading(false);
return true;
}).catch(() => {
setLoading(false);
return false;
});
};
// 重置配置
const resetConfig = () => {
formModel.value = Object.assign({}, props.content?.config);
// 使用新密码默认为不包含密码
formModel.value.useNewPassword = !formModel.value.hasPassword;
};
// 保存配置
const saveConfig = async () => {
try {
// 验证参数
const error = await formRef.value.validate();
if (error) {
return false;
}
setLoading(true);
// 更新
const { data } = await updateHostConfig({
hostId: props?.hostId,
type: HostConfigType.SSH,
version: config.version,
config: JSON.stringify(formModel.value)
});
config.version = data;
setLoading(false);
Message.success('修改成功');
// 回调 props
emits('submitted', { ...props.content, ...config, config: { ...formModel.value } });
} catch (e) {
} finally {
setLoading(false);
}
};
</script>
<style lang="less" scoped>
.config-title-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
}
.config-form-wrapper {
width: 100%;
}
.config-button-group {
display: flex;
align-items: center;
justify-content: flex-end;
}
.auth-type-group {
width: 100%;
display: flex;
justify-content: space-between;
}
.password-switch {
width: 148px;
margin-left: 8px;
}
</style>

View File

@@ -0,0 +1,121 @@
<template>
<a-drawer v-model:visible="visible"
:width="460"
:esc-to-close="false"
:mask-closable="false"
:unmount-on-close="true"
:ok-button-props="{ disabled: loading }"
:cancel-button-props="{ disabled: loading }"
:footer="false"
@cancel="handleCancel">
<!-- 标题 -->
<template #title>
<span class="host-title-text">
主机配置 <span class="host-name-title-text">{{ record.name }}</span>
</span>
</template>
<a-spin :loading="loading" class="host-config-container">
<!-- SSH 配置 -->
<ssh-config-form :host-id="record.id"
:content="config.ssh"
@submitted="(e) => config.ssh = e" />
</a-spin>
</a-drawer>
</template>
<script lang="ts">
export default {
name: 'hostConfigDrawer'
};
</script>
<script lang="ts" setup>
import type { HostConfigWrapper, HostSshConfig } from '../types/const';
import { ref } from 'vue';
import useVisible from '@/hooks/visible';
import useLoading from '@/hooks/loading';
import { Message } from '@arco-design/web-vue';
import { getHostConfigList } from '@/api/asset/host-config';
import { useCacheStore, useDictStore } from '@/store';
import { dictKeys } from '../types/const';
import SshConfigForm from '../components/ssh-config-form.vue';
const { visible, setVisible } = useVisible();
const { loading, setLoading } = useLoading();
const cacheStore = useCacheStore();
const record = ref({} as any);
const config = ref<HostConfigWrapper>({
ssh: {} as HostSshConfig
});
// 打开
const open = async (e: any) => {
record.value = { ...e };
try {
setLoading(true);
setVisible(true);
// 加载字典值
const dictStore = useDictStore();
await dictStore.loadKeys(dictKeys);
// 加载配置
const { data } = await getHostConfigList(record.value.id);
data.forEach(s => {
config.value[s.type] = s;
});
} catch ({ message }) {
Message.error(`配置加载失败 ${message}`);
setVisible(false);
} finally {
setLoading(false);
}
};
// 关闭
const handleCancel = () => {
setLoading(false);
setVisible(false);
};
defineExpose({ open });
</script>
<style lang="less" scoped>
.host-title-text {
width: 368px;
display: flex;
font-size: 16px;
line-height: 16px;
font-weight: 600;
.host-name-title-text {
max-width: 288px;
margin-left: 8px;
font-size: 14px;
display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: rgb(var(--arcoblue-6));
}
.host-name-title-text::before {
content: '(';
}
.host-name-title-text::after {
content: ')';
}
}
.host-config-container {
width: 100%;
height: 100%;
background-color: var(--color-fill-2);
}
.arco-card {
margin: 18px 18px 0 18px;
}
</style>

View File

@@ -0,0 +1,53 @@
// 主机所有配置
export interface HostConfigWrapper {
ssh: HostSshConfig;
[key: string]: unknown;
}
// 主机 SSH 配置
export interface HostSshConfig {
osType?: string;
port?: number;
username?: string;
password?: string;
authType?: string;
identityId?: number;
keyId?: number;
connectTimeout?: number;
charset?: string;
fileNameCharset?: string;
fileContentCharset?: string;
useNewPassword?: boolean;
hasPassword?: boolean;
}
// 主机验证方式
export const SshAuthType = {
// 密码验证
PASSWORD: 'PASSWORD',
// 密钥验证
KEY: 'KEY',
// 身份验证
IDENTITY: 'IDENTITY'
};
// 主机系统版本
export const SshOsType = {
LINUX: 'LINUX',
WINDOWS: 'WINDOWS',
};
// 主机配置类型
export const HostConfigType = {
SSH: 'ssh'
};
// 主机验证方式 字典项
export const sshAuthTypeKey = 'hostSshAuthType';
// 主机系统类型 字典项
export const sshOsTypeKey = 'hostSshOsType';
// 加载的字典值
export const dictKeys = [sshAuthTypeKey, sshOsTypeKey];

View File

@@ -0,0 +1,77 @@
import type { FieldRule } from '@arco-design/web-vue';
export const osType = [{
required: true,
message: '请选择系统类型'
}] as FieldRule[];
export const port = [{
required: true,
message: '请输入SSH端口'
}, {
type: 'number',
min: 1,
max: 65535,
message: '输入的端口不合法'
}] as FieldRule[];
export const authType = [{
required: true,
message: '请选择认证方式'
}] as FieldRule[];
export const keyId = [{
required: true,
message: '请选择主机密钥'
}] as FieldRule[];
export const identityId = [{
required: true,
message: '请选择主机身份'
}] as FieldRule[];
export const connectTimeout = [{
required: true,
message: '请输入连接超时时间'
}, {
type: 'number',
min: 0,
max: 100000,
message: '连接超时时间需要在 0 - 100000 之间'
}] as FieldRule[];
export const charset = [{
required: true,
message: '请输入SSH输出编码'
}, {
maxLength: 12,
message: 'SSH输出编码长度不能超过12位'
}] as FieldRule[];
export const fileNameCharset = [{
required: true,
message: '请输入文件名称编码'
}, {
maxLength: 12,
message: '文件名称编码长度不能超过12位'
}] as FieldRule[];
export const fileContentCharset = [{
required: true,
message: '请输入SSH输出编码'
}, {
maxLength: 12,
message: '文件内容编码长度不能超过12位'
}] as FieldRule[];
export default {
osType,
port,
authType,
keyId,
identityId,
connectTimeout,
charset,
fileNameCharset,
fileContentCharset,
} as Record<string, FieldRule | FieldRule[]>;