diff --git a/README.md b/README.md index 5dd752d..53ac5ff 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ > [!WARNING] > 强烈建议使用 **iptables** 或 **fail2ban** 等安全服务限制IP访问,谨慎暴露面板服务到公网。 -> [!NOTE] -> 客户端信息监控与webssh功能都将以`该服务器作为中转`。中国大陆连接建议使用香港、新加坡、日本、韩国等地区的低延迟服务器来安装服务端 + + - + - +
- + ({ +const formField = { group: 'default', name: '', host: '', @@ -260,18 +297,23 @@ const resetForm = () => ({ consoleUrl: '', remark: '', command: '' -}) +} -const hostForm = reactive(resetForm()) -const privateKeyRef = ref(null) -const oldHost = ref('') +let hostForm = ref({ ...formField }) +let privateKeyRef = ref(null) +let oldHost = ref('') +let formRef = ref(null) + +let isBatchModify = computed(() => props.isBatchModify) +let batchHosts = computed(() => props.batchHosts) +let defaultData = computed(() => props.defaultData) const rules = computed(() => { return { - group: { required: true, message: '选择一个分组' }, - name: { required: true, message: '输入实例别名', trigger: 'change' }, - host: { required: true, message: '输入IP/域名', trigger: 'change' }, + group: { required: !isBatchModify.value, message: '选择一个分组' }, + name: { required: !isBatchModify.value, message: '输入实例别名', trigger: 'change' }, + host: { required: !isBatchModify.value, message: '输入IP/域名', trigger: 'change' }, port: { required: true, type: 'number', message: '输入ssh端口', trigger: 'change' }, - index: { required: true, type: 'number', message: '输入数字', trigger: 'change' }, + index: { required: !isBatchModify.value, type: 'number', message: '输入数字', trigger: 'change' }, // password: [{ required: hostForm.authType === 'password', trigger: 'change' },], // privateKey: [{ required: hostForm.authType === 'privateKey', trigger: 'change' },], expired: { required: false }, @@ -281,30 +323,41 @@ const rules = computed(() => { } }) -const formRef = ref(null) - const visible = computed({ get: () => props.show, set: (newVal) => emit('update:show', newVal) }) -const title = computed(() => props.defaultData ? '修改实例' : '添加实例') +const title = computed(() => { + return isBatchModify.value ? '批量修改实例' : (defaultData.value ? '修改实例' : '添加实例') +}) let groupList = computed(() => $store.groupList) let sshList = computed(() => $store.sshList) -const handleClosed = () => { - // console.log('handleClosed') - Object.assign(hostForm, resetForm()) - emit('closed') - nextTick(() => formRef.value.resetFields()) +const setDefaultData = () => { + if (!defaultData.value) return + let { host } = defaultData.value + oldHost.value = host + Object.assign(hostForm.value, { ...defaultData.value }) } -const setDefaultData = () => { - if (!props.defaultData) return - let { host } = props.defaultData - oldHost.value = host - Object.assign(hostForm, { ...props.defaultData }) +const setBatchDefaultData = () => { + if (!isBatchModify.value) return + Object.assign(hostForm.value, { ...formField }, { group: '' }) +} +const handleOpen = async () => { + setDefaultData() + setBatchDefaultData() + await nextTick() + formRef.value.clearValidate() +} + +const handleClosed = async () => { + emit('closed') + Object.assign(hostForm.value, { ...formField }) + await nextTick() + formRef.value.resetFields() } const handleClickUploadBtn = () => { @@ -315,7 +368,7 @@ const handleSelectPrivateKeyFile = (event) => { let file = event.target.files[0] let reader = new FileReader() reader.onload = (e) => { - hostForm.privateKey = e.target.result + hostForm.value.privateKey = e.target.result privateKeyRef.value = '' } reader.readAsText(file) @@ -346,30 +399,53 @@ const toCredentials = () => { const handleSave = () => { formRef.value.validate() .then(async () => { - let tempKey = randomStr(16) - let formData = { ...hostForm } - console.log('formData:', formData) - // 加密传输 - if (formData.password) formData.password = AESEncrypt(formData.password, tempKey) - if (formData.privateKey) formData.privateKey = AESEncrypt(formData.privateKey, tempKey) - if (formData.credential) formData.credential = AESEncrypt(formData.credential, tempKey) - formData.tempKey = RSAEncrypt(tempKey) - if (props.defaultData) { - let { msg } = await $api.updateHost(Object.assign({}, formData, { oldHost: oldHost.value })) + let formData = { ...hostForm.value } + if (isBatchModify.value) { + // eslint-disable-next-line + let updateFileData = Object.fromEntries(Object.entries(formData).filter(([key, value]) => Boolean(value))) // 剔除掉未更改的值 + // console.log(updateFileData) + let newHosts = batchHosts.value + .map(item => ({ ...item, ...updateFileData })) + .map(item => { + const { authType } = item + let tempKey = randomStr(16) + if (item[authType]) item[authType] = AESEncrypt(item[authType], tempKey) + item.tempKey = RSAEncrypt(tempKey) + return item + }) + let { msg } = await $api.updateHost({ hosts: newHosts }) $message({ type: 'success', center: true, message: msg }) } else { - let { msg } = await $api.addHost(formData) - $message({ type: 'success', center: true, message: msg }) + let tempKey = randomStr(16) + let { authType } = formData + if (formData[authType]) formData[authType] = AESEncrypt(formData[authType], tempKey) + formData.tempKey = RSAEncrypt(tempKey) + if (defaultData.value) { + let { msg } = await $api.updateHost(Object.assign({}, formData, { oldHost: oldHost.value })) + $message({ type: 'success', center: true, message: msg }) + } else { + let { msg } = await $api.addHost(formData) + $message({ type: 'success', center: true, message: msg }) + } } visible.value = false - const { host, username, port, authType } = formData - emit('update-list', { isConfig: Boolean(username && port && (formData[authType])), host }) - Object.assign(hostForm, resetForm()) + emit('update-list') }) } + + diff --git a/web/src/views/server/index.vue b/web/src/views/server/index.vue index 7acc992..823986d 100644 --- a/web/src/views/server/index.vue +++ b/web/src/views/server/index.vue @@ -1,10 +1,22 @@