mirror of https://github.com/1Panel-dev/1Panel
ssongliu
8 months ago
committed by
GitHub
21 changed files with 600 additions and 9 deletions
@ -0,0 +1,209 @@
|
||||
<template> |
||||
<div> |
||||
<LayoutContent v-loading="loading" :title="$t('setting.license')" :divider="true"> |
||||
<template #main> |
||||
<el-row :gutter="20" class="mt-5; mb-10"> |
||||
<el-col :xs="24" :sm="24" :md="15" :lg="15" :xl="15"> |
||||
<div class="descriptions" v-if="hasLicense()"> |
||||
<el-descriptions :column="1" direction="horizontal" size="large" border> |
||||
<el-descriptions-item :label="$t('license.authorizationId')"> |
||||
{{ license.licenseName || '-' }} |
||||
<el-button type="primary" class="ml-3" plain @click="onSync" size="small"> |
||||
{{ $t('commons.button.sync') }} |
||||
</el-button> |
||||
</el-descriptions-item> |
||||
<el-descriptions-item :label="$t('license.authorizedUser')"> |
||||
{{ license.assigneeName || '-' }} |
||||
</el-descriptions-item> |
||||
<el-descriptions-item :label="$t('license.expiresAt')"> |
||||
{{ license.expiresAt || '-' }} |
||||
</el-descriptions-item> |
||||
<el-descriptions-item :label="$t('license.productName')"> |
||||
{{ license.productName || '-' }} |
||||
</el-descriptions-item> |
||||
<el-descriptions-item :label="$t('license.productStatus')"> |
||||
<div v-if="license.status"> |
||||
<el-tooltip |
||||
v-if="license.status.indexOf('lost') !== -1" |
||||
:content="$t('license.lostHelper')" |
||||
> |
||||
<el-tag type="info"> |
||||
{{ $t('license.' + license.status) }} |
||||
</el-tag> |
||||
</el-tooltip> |
||||
<el-tag v-else>{{ $t('license.' + license.status) }}</el-tag> |
||||
</div> |
||||
<span v-else>-</span> |
||||
</el-descriptions-item> |
||||
</el-descriptions> |
||||
</div> |
||||
|
||||
<CardWithHeader :header="$t('home.overview')" height="160px" v-if="!hasLicense()"> |
||||
<template #body> |
||||
<div class="h-overview"> |
||||
<el-row> |
||||
<el-col :span="6"> |
||||
<span>{{ $t('setting.license') }}</span> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<span>{{ $t('license.community') }}</span> |
||||
</el-col> |
||||
</el-row> |
||||
</div> |
||||
</template> |
||||
</CardWithHeader> |
||||
</el-col> |
||||
|
||||
<el-col :xs="24" :sm="24" :md="9" :lg="9" :xl="9"> |
||||
<CardWithHeader :header="$t('license.quickUpdate')" height="160px"> |
||||
<template #body> |
||||
<div class="h-app-card"> |
||||
<el-row :gutter="10"> |
||||
<el-col :span="15"> |
||||
<div class="h-app-content">{{ $t('license.importLicense') }}:</div> |
||||
</el-col> |
||||
<el-col :span="5"> |
||||
<el-button type="primary" plain round size="small" @click="toUpload"> |
||||
{{ $t('license.import') }} |
||||
</el-button> |
||||
</el-col> |
||||
</el-row> |
||||
</div> |
||||
<div class="h-app-card"> |
||||
<el-row :gutter="10"> |
||||
<el-col :span="15"> |
||||
<div class="h-app-content">{{ $t('license.technicalAdvice') }}:</div> |
||||
</el-col> |
||||
<el-col :span="5"> |
||||
<el-button type="primary" plain round size="small" @click="toHalo()"> |
||||
{{ $t('license.advice') }} |
||||
</el-button> |
||||
</el-col> |
||||
</el-row> |
||||
</div> |
||||
</template> |
||||
</CardWithHeader> |
||||
</el-col> |
||||
</el-row> |
||||
</template> |
||||
</LayoutContent> |
||||
|
||||
<Upload ref="uploadRef" @search="search()" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { ref, reactive, onMounted } from 'vue'; |
||||
import { getLicense, syncLicense } from '@/api/modules/setting'; |
||||
import CardWithHeader from '@/components/card-with-header/index.vue'; |
||||
import Upload from '@/views/setting/license/upload/index.vue'; |
||||
import i18n from '@/lang'; |
||||
import { MsgSuccess } from '@/utils/message'; |
||||
import { GlobalStore } from '@/store'; |
||||
const loading = ref(); |
||||
const uploadRef = ref(); |
||||
const globalStore = GlobalStore(); |
||||
|
||||
const license = reactive({ |
||||
licenseName: '', |
||||
trial: true, |
||||
expiresAt: '', |
||||
assigneeName: '', |
||||
productName: '', |
||||
|
||||
status: '', |
||||
}); |
||||
|
||||
const toHalo = () => { |
||||
window.open('https://halo.test.lxware.cn/', '_blank', 'noopener,noreferrer'); |
||||
}; |
||||
|
||||
const onSync = async () => { |
||||
loading.value = true; |
||||
await syncLicense() |
||||
.then(() => { |
||||
loading.value = false; |
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); |
||||
search(); |
||||
}) |
||||
.catch(() => { |
||||
loading.value = false; |
||||
}); |
||||
}; |
||||
|
||||
const timestampToDate = (timestamp: number) => { |
||||
const date = new Date(timestamp * 1000); |
||||
const y = date.getFullYear(); |
||||
let m: string | number = date.getMonth() + 1; |
||||
m = m < 10 ? `0${String(m)}` : m; |
||||
let d: string | number = date.getDate(); |
||||
d = d < 10 ? `0${String(d)}` : d; |
||||
let h: string | number = date.getHours(); |
||||
h = h < 10 ? `0${String(h)}` : h; |
||||
let minute: string | number = date.getMinutes(); |
||||
minute = minute < 10 ? `0${String(minute)}` : minute; |
||||
let second: string | number = date.getSeconds(); |
||||
second = second < 10 ? `0${String(second)}` : second; |
||||
return `${y}-${m}-${d} ${h}:${minute}:${second}`; |
||||
}; |
||||
|
||||
const search = async () => { |
||||
loading.value = true; |
||||
await getLicense() |
||||
.then((res) => { |
||||
loading.value = false; |
||||
license.status = res.data.status; |
||||
globalStore.isProductPro = res.data.status === 'Enable'; |
||||
if (res.data.status !== 'Enable') { |
||||
return; |
||||
} |
||||
license.licenseName = res.data.licenseName; |
||||
license.assigneeName = res.data.assigneeName; |
||||
license.trial = res.data.trial; |
||||
if (res.data.productPro) { |
||||
license.productName = 'product-1panel-pro'; |
||||
license.expiresAt = |
||||
res.data.productPro === '0' |
||||
? i18n.global.t('license.indefinitePeriod') |
||||
: timestampToDate(Number(res.data.productPro)); |
||||
} |
||||
}) |
||||
.catch(() => { |
||||
loading.value = false; |
||||
}); |
||||
}; |
||||
|
||||
const hasLicense = () => { |
||||
return license.status === 'Enable'; |
||||
}; |
||||
|
||||
const toUpload = () => { |
||||
uploadRef.value.acceptParams(); |
||||
}; |
||||
|
||||
onMounted(() => { |
||||
search(); |
||||
}); |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.h-app-card { |
||||
padding: 10px 15px; |
||||
margin-right: 10px; |
||||
line-height: 18px; |
||||
|
||||
.h-app-content { |
||||
padding-left: 15px; |
||||
.h-app-desc { |
||||
span { |
||||
font-weight: 400; |
||||
font-size: 12px; |
||||
color: var(--el-text-color-regular); |
||||
} |
||||
} |
||||
} |
||||
&:hover { |
||||
background-color: rgba(0, 94, 235, 0.03); |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,107 @@
|
||||
<template> |
||||
<el-drawer |
||||
v-model="open" |
||||
:before-close="handleClose" |
||||
size="30%" |
||||
:destroy-on-close="true" |
||||
:close-on-click-modal="false" |
||||
> |
||||
<template #header> |
||||
<DrawerHeader :header="$t('license.importLicense')" :back="handleClose" /> |
||||
</template> |
||||
<div v-loading="loading"> |
||||
<el-upload |
||||
action="#" |
||||
:auto-upload="false" |
||||
ref="uploadRef" |
||||
class="upload-demo" |
||||
drag |
||||
:limit="1" |
||||
:on-change="fileOnChange" |
||||
:on-exceed="handleExceed" |
||||
v-model:file-list="uploaderFiles" |
||||
> |
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon> |
||||
<div class="el-upload__text"> |
||||
{{ $t('license.importHelper') }} |
||||
</div> |
||||
</el-upload> |
||||
</div> |
||||
|
||||
<template #footer> |
||||
<span class="dialog-footer"> |
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button> |
||||
<el-button type="primary" @click="submit()" :disabled="loading || uploaderFiles.length == 0"> |
||||
{{ $t('commons.button.confirm') }} |
||||
</el-button> |
||||
</span> |
||||
</template> |
||||
</el-drawer> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { ref } from 'vue'; |
||||
import { UploadFile, UploadFiles, UploadInstance, UploadProps, UploadRawFile, genFileId } from 'element-plus'; |
||||
import { UploadFileData } from '@/api/modules/setting'; |
||||
import i18n from '@/lang'; |
||||
import DrawerHeader from '@/components/drawer-header/index.vue'; |
||||
import { MsgSuccess } from '@/utils/message'; |
||||
|
||||
const loading = ref(false); |
||||
const open = ref(false); |
||||
|
||||
const em = defineEmits(['search']); |
||||
|
||||
const uploadRef = ref<UploadInstance>(); |
||||
const uploaderFiles = ref<UploadFiles>([]); |
||||
|
||||
const handleClose = () => { |
||||
open.value = false; |
||||
uploadRef.value!.clearFiles(); |
||||
em('search'); |
||||
}; |
||||
|
||||
const fileOnChange = (_uploadFile: UploadFile, uploadFiles: UploadFiles) => { |
||||
uploaderFiles.value = uploadFiles; |
||||
}; |
||||
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => { |
||||
uploadRef.value!.clearFiles(); |
||||
const file = files[0] as UploadRawFile; |
||||
file.uid = genFileId(); |
||||
uploadRef.value!.handleStart(file); |
||||
}; |
||||
|
||||
const submit = async () => { |
||||
if (uploaderFiles.value.length !== 1) { |
||||
return; |
||||
} |
||||
const file = uploaderFiles.value[0]; |
||||
const formData = new FormData(); |
||||
formData.append('file', file.raw); |
||||
loading.value = true; |
||||
await UploadFileData(formData) |
||||
.then(async () => { |
||||
loading.value = false; |
||||
uploadRef.value!.clearFiles(); |
||||
uploaderFiles.value = []; |
||||
em('search'); |
||||
open.value = false; |
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); |
||||
window.location.reload(); |
||||
}) |
||||
.catch(() => { |
||||
loading.value = false; |
||||
uploadRef.value!.clearFiles(); |
||||
uploaderFiles.value = []; |
||||
}); |
||||
}; |
||||
|
||||
const acceptParams = () => { |
||||
uploaderFiles.value = []; |
||||
uploadRef.value?.clearFiles(); |
||||
open.value = true; |
||||
}; |
||||
|
||||
defineExpose({ acceptParams }); |
||||
</script> |
Loading…
Reference in new issue