mirror of https://github.com/halo-dev/halo
345 lines
11 KiB
Vue
345 lines
11 KiB
Vue
<template>
|
||
<div>
|
||
<a-row
|
||
type="flex"
|
||
justify="center"
|
||
align="middle"
|
||
class="h-screen"
|
||
>
|
||
<a-col
|
||
:xl="8"
|
||
:md="12"
|
||
:sm="20"
|
||
:xs="24"
|
||
>
|
||
<div class="card-container">
|
||
<a-card
|
||
:bordered="false"
|
||
title="Halo 安装向导"
|
||
style="box-shadow: 0px 10px 20px 0px rgba(236, 236, 236, 0.86);"
|
||
>
|
||
|
||
<a-steps :current="stepCurrent">
|
||
<a-step title="博主信息">
|
||
</a-step>
|
||
<a-step title="博客信息">
|
||
</a-step>
|
||
<a-step title="数据导入">
|
||
</a-step>
|
||
</a-steps>
|
||
<a-divider dashed />
|
||
<!-- Blogger info -->
|
||
<a-form-model
|
||
ref="generalForm"
|
||
:model="installation"
|
||
:rules="generalRules"
|
||
layout="horizontal"
|
||
v-show="stepCurrent == 0"
|
||
>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
prop="username"
|
||
>
|
||
<a-input
|
||
v-model="installation.username"
|
||
placeholder="用户名"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="user"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
:style="{'animation-delay': '0.1s'}"
|
||
prop="nickname"
|
||
>
|
||
<a-input
|
||
v-model="installation.nickname"
|
||
placeholder="用户昵称"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="smile"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
:style="{'animation-delay': '0.2s'}"
|
||
prop="email"
|
||
>
|
||
<a-input
|
||
v-model="installation.email"
|
||
placeholder="用户邮箱"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="mail"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
:style="{'animation-delay': '0.3s'}"
|
||
prop="password"
|
||
>
|
||
<a-input
|
||
v-model="installation.password"
|
||
type="password"
|
||
placeholder="用户密码(8-100位)"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="lock"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
:style="{'animation-delay': '0.4s'}"
|
||
prop="confirmPassword"
|
||
>
|
||
<a-input
|
||
v-model="installation.confirmPassword"
|
||
type="password"
|
||
placeholder="确认密码"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="lock"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
</a-form-model>
|
||
|
||
<!-- Blog info -->
|
||
|
||
<a-form-model
|
||
layout="horizontal"
|
||
v-show="stepCurrent == 1"
|
||
ref="blogForm"
|
||
:model="installation"
|
||
:rules="blogRules"
|
||
>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
prop="url"
|
||
>
|
||
<a-input
|
||
v-model="installation.url"
|
||
placeholder="博客地址"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="link"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
<a-form-model-item
|
||
class="animated fadeInUp"
|
||
:style="{'animation-delay': '0.2s'}"
|
||
prop="title"
|
||
>
|
||
<a-input
|
||
v-model="installation.title"
|
||
placeholder="博客标题"
|
||
>
|
||
<a-icon
|
||
slot="prefix"
|
||
type="book"
|
||
style="color: rgba(0,0,0,.25)"
|
||
/>
|
||
</a-input>
|
||
</a-form-model-item>
|
||
</a-form-model>
|
||
|
||
<!-- Data migration -->
|
||
<div v-show="stepCurrent == 2">
|
||
<a-alert
|
||
style="margin-bottom: 1rem"
|
||
message="如果有数据导入需求,请点击并选择之前导出的文件。需要注意的是,并不是所有数据都会导入,该初始化表单的数据会覆盖你导入的数据。"
|
||
type="info"
|
||
/>
|
||
<FilePondUpload
|
||
ref="upload"
|
||
name="file"
|
||
accept="application/json"
|
||
label="拖拽或点击选择数据文件,请确认是否为 Halo 后台导出的文件。"
|
||
:multiple="false"
|
||
:uploadHandler="handleMigrationUpload"
|
||
:loadOptions="false"
|
||
></FilePondUpload>
|
||
</div>
|
||
|
||
<a-row
|
||
class="install-action"
|
||
type="flex"
|
||
justify="space-between"
|
||
style="margin-top: 1rem;"
|
||
>
|
||
<div>
|
||
<a-button
|
||
class="previus-button"
|
||
v-if="stepCurrent != 0"
|
||
@click="stepCurrent--"
|
||
style="margin-right: 1rem;"
|
||
>上一步</a-button>
|
||
<a-button
|
||
type="primary"
|
||
v-if="stepCurrent != 2"
|
||
@click="handleNextStep"
|
||
>下一步</a-button>
|
||
</div>
|
||
<a-button
|
||
v-if="stepCurrent == 2"
|
||
type="primary"
|
||
icon="upload"
|
||
@click="handleInstall"
|
||
:loading="installing"
|
||
>安装</a-button>
|
||
</a-row>
|
||
</a-card>
|
||
</div>
|
||
</a-col>
|
||
</a-row>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import adminApi from '@/api/admin'
|
||
import migrateApi from '@/api/migrate'
|
||
import { mapActions } from 'vuex'
|
||
|
||
export default {
|
||
data() {
|
||
const confirmPasswordValidate = (rule, value, callback) => {
|
||
if (value !== this.installation.password) {
|
||
callback(new Error('确认密码与所输入的密码不一致'))
|
||
} else {
|
||
callback()
|
||
}
|
||
}
|
||
return {
|
||
installation: {},
|
||
stepCurrent: 0,
|
||
migrationData: null,
|
||
installing: false,
|
||
|
||
generalRules: {
|
||
username: [
|
||
{ required: true, message: '* 用户名不能为空', trigger: ['change'] },
|
||
{ max: 50, message: '* 用户名的字符长度不能超过 50', trigger: ['change'] }
|
||
],
|
||
nickname: [
|
||
{ required: true, message: '* 用户昵称不能为空', trigger: ['change'] },
|
||
{ max: 255, message: '* 用户昵称的字符长度不能超过 255', trigger: ['change'] }
|
||
],
|
||
email: [
|
||
{ required: true, message: '* 电子邮件地址不能为空', trigger: ['change'] },
|
||
{ max: 127, message: '* 电子邮件地址的字符长度不能超过 127', trigger: ['change'] },
|
||
{
|
||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/g,
|
||
message: '* 电子邮件地址的格式不正确',
|
||
trigger: ['change']
|
||
}
|
||
],
|
||
password: [
|
||
{ required: true, message: '* 密码不能为空', trigger: ['change'] },
|
||
{ min: 8, max: 100, message: '* 密码的字符长度必须在 8 - 100 之间', trigger: ['change'] }
|
||
],
|
||
confirmPassword: [
|
||
{ required: true, message: '* 确认密码不能为空', trigger: ['change'] },
|
||
{ validator: confirmPasswordValidate, trigger: ['change'] }
|
||
]
|
||
},
|
||
blogRules: {
|
||
url: [{ required: true, message: '* 博客地址不能为空', trigger: ['change'] }],
|
||
title: [{ required: true, message: '* 博客标题不能为空', trigger: ['change'] }]
|
||
}
|
||
}
|
||
},
|
||
beforeMount() {
|
||
this.handleVerifyIsInstall()
|
||
this.$set(this.installation, 'url', window.location.protocol + '//' + window.location.host)
|
||
},
|
||
methods: {
|
||
...mapActions(['installCleanToken']),
|
||
async handleVerifyIsInstall() {
|
||
await adminApi.isInstalled().then((response) => {
|
||
if (response.data.data) {
|
||
this.$router.push({ name: 'Login' })
|
||
}
|
||
})
|
||
},
|
||
handleNextStep() {
|
||
if (this.stepCurrent === 0) {
|
||
this.$refs.generalForm.validate((valid) => {
|
||
if (valid) {
|
||
this.stepCurrent++
|
||
} else {
|
||
return false
|
||
}
|
||
})
|
||
} else if (this.stepCurrent === 1) {
|
||
this.$refs.blogForm.validate((valid) => {
|
||
if (valid) {
|
||
this.stepCurrent++
|
||
} else {
|
||
return false
|
||
}
|
||
})
|
||
}
|
||
},
|
||
handleMigrationUpload(data) {
|
||
this.$log.debug('Selected data', data)
|
||
this.migrationData = data
|
||
return new Promise((resolve, reject) => {
|
||
this.$log.debug('Handle uploading')
|
||
resolve()
|
||
})
|
||
},
|
||
install() {
|
||
this.installCleanToken(this.installation)
|
||
.then((response) => {
|
||
this.$log.debug('Installation response', response)
|
||
this.$message.success('安装成功!')
|
||
setTimeout(() => {
|
||
this.$router.push({ name: 'Login' })
|
||
}, 200)
|
||
})
|
||
.finally(() => {
|
||
setTimeout(() => {
|
||
this.installing = false
|
||
}, 400)
|
||
})
|
||
},
|
||
handleInstall() {
|
||
this.installing = true
|
||
if (this.migrationData) {
|
||
const hide = this.$message.loading('数据导入中...', 0)
|
||
migrateApi
|
||
.migrate(this.migrationData)
|
||
.then((response) => {
|
||
this.$log.debug('Migrated successfullly')
|
||
this.$message.success('数据导入成功!')
|
||
this.install()
|
||
})
|
||
.finally(() => {
|
||
hide()
|
||
})
|
||
} else {
|
||
this.install()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|