Files
mes-ui-d2/src/layout/header-aside/components/header-user/index.vue
sheng 659f000bf6
Some checks failed
Release pipeline / publish (push) Has been cancelled
Release pipeline / Always run job (push) Has been cancelled
补齐头部用户下拉功能
2026-06-25 10:25:42 +08:00

306 lines
11 KiB
Vue

<template>
<el-dropdown size="small" class="d2-mr">
<span class="btn-text">
{{ info.name ? $t('page.layout.user.greeting', { name: info.name }) : $t('page.layout.user.not_logged_in') }}
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-if="isAdmin" icon="el-icon-setting" @click.native="openApiDebug">
{{ $t('page.layout.user.api_debug') }}
</el-dropdown-item>
<el-dropdown-item icon="el-icon-key" @click.native="openPasswordDialog">
{{ $t('page.layout.user.change_password') }}
</el-dropdown-item>
<el-dropdown-item icon="el-icon-refresh" @click.native="reloadMenu">
{{ $t('page.layout.user.reload_menu') }}
</el-dropdown-item>
<el-dropdown-item icon="el-icon-document-checked" @click.native="openAuthDialog">
{{ $t('page.layout.user.product_authorization') }}
</el-dropdown-item>
<el-dropdown-item divided @click.native="logOff">
<d2-icon name="power-off" class="d2-mr-5" />
{{ $t('page.layout.user.logout') }}
</el-dropdown-item>
</el-dropdown-menu>
<el-dialog
:title="$t('page.layout.user.change_password')"
width="600px"
:visible.sync="passwordDialogVisible"
:append-to-body="true"
:close-on-click-modal="false"
@close="resetPasswordForm"
>
<el-form ref="passwordForm" :model="passwordForm" :rules="passwordRules" label-width="110px" size="small">
<el-form-item :label="$t('page.layout.user.original_password')" prop="password_old">
<el-input v-model.trim="passwordForm.password_old" type="password" :placeholder="$t('page.layout.user.placeholder_original_password')" clearable show-password />
</el-form-item>
<el-form-item :label="$t('page.layout.user.new_password')" prop="password">
<el-input v-model.trim="passwordForm.password" type="password" :placeholder="$t('page.layout.user.placeholder_new_password')" clearable show-password />
</el-form-item>
<el-form-item :label="$t('page.layout.user.confirm_password')" prop="password_confirm">
<el-input v-model.trim="passwordForm.password_confirm" type="password" :placeholder="$t('page.layout.user.placeholder_confirm_password')" clearable show-password />
</el-form-item>
</el-form>
<div slot="footer">
<el-button size="small" @click="passwordDialogVisible = false">{{ $t('page.layout.user.cancel') }}</el-button>
<el-button size="small" type="primary" :loading="passwordSubmitting" @click="submitPassword">
{{ $t('page.layout.user.confirm') }}
</el-button>
</div>
</el-dialog>
<el-dialog
:title="$t('page.layout.user.product_authorization')"
width="600px"
:visible.sync="authDialogVisible"
:append-to-body="true"
:close-on-click-modal="false"
@opened="clearAuthFiles"
>
<el-descriptions :column="1" border>
<el-descriptions-item :label="$t('page.layout.user.authorization_validity_period')">
{{ authTime || '-' }}
</el-descriptions-item>
</el-descriptions>
<el-upload
ref="authUpload"
class="auth-upload"
drag
action=""
:limit="1"
:show-file-list="true"
:before-upload="beforeAuthUpload"
:http-request="uploadAuthFile"
>
<i class="el-icon-upload" />
<div class="el-upload__text">
{{ $t('page.layout.user.drag_upload_hint') }}<em>{{ $t('page.layout.user.click_upload') }}</em>
</div>
<div slot="tip" class="el-upload__tip">{{ $t('page.layout.user.upload_file_tip') }}</div>
</el-upload>
</el-dialog>
</el-dropdown>
</template>
<script>
import util from '@/libs/util'
import { mapActions, mapState } from 'vuex'
import { updateUserPwd } from '@/api/system-administration/user'
import { getAuthNearTime, getAuthTime, getAuthTimeByUpload } from '@/api/auth'
export default {
data () {
return {
passwordDialogVisible: false,
passwordSubmitting: false,
authDialogVisible: false,
authTime: '',
authNoticeTimer: null,
passwordForm: this.emptyPasswordForm(),
passwordRules: {
password_old: [
{ required: true, message: this.$t('page.layout.user.old_password_required'), trigger: 'blur' },
{ min: 6, max: 64, message: this.$t('page.layout.user.length_6_to_64'), trigger: 'blur' }
],
password: [
{ required: true, message: this.$t('page.layout.user.new_password_required'), trigger: 'blur' },
{ min: 6, max: 64, message: this.$t('page.layout.user.length_6_to_64'), trigger: 'blur' }
],
password_confirm: [
{ required: true, message: this.$t('page.layout.user.confirm_password_required'), trigger: 'blur' },
{ min: 6, max: 64, message: this.$t('page.layout.user.length_6_to_64'), trigger: 'blur' }
]
}
}
},
computed: {
...mapState('d2admin/user', [
'info'
]),
isAdmin () {
return String(this.info && this.info.admin && this.info.admin.role_id) === '1'
}
},
mounted () {
this.loadAuthTime()
},
beforeDestroy () {
this.clearAuthNoticeTimer()
},
methods: {
...mapActions('d2admin/account', [
'logout'
]),
emptyPasswordForm () {
return {
password_old: '',
password: '',
password_confirm: ''
}
},
normalizeAuthResponse (res) {
const source = res && res.data ? res.data : res
return {
status: Number(source && source.status),
msg: source && source.msg ? source.msg : ''
}
},
openApiDebug () {
const routeData = this.$router.resolve({
path: '/api',
query: { token: this.info && this.info.token }
})
window.open(routeData.href, '_blank')
},
openPasswordDialog () {
this.passwordForm = this.emptyPasswordForm()
this.passwordDialogVisible = true
this.$nextTick(() => {
this.$refs.passwordForm && this.$refs.passwordForm.clearValidate()
})
},
resetPasswordForm () {
this.passwordForm = this.emptyPasswordForm()
this.$nextTick(() => {
this.$refs.passwordForm && this.$refs.passwordForm.clearValidate()
})
},
submitPassword () {
this.$refs.passwordForm.validate(async valid => {
if (!valid) return
if (this.passwordForm.password_old === this.passwordForm.password) {
this.$message.error(this.$t('page.layout.user.password_same_error'))
return
}
if (this.passwordForm.password !== this.passwordForm.password_confirm) {
this.$message.error(this.$t('page.layout.user.password_not_match'))
return
}
this.passwordSubmitting = true
try {
await updateUserPwd({
user_id: this.info && this.info.admin && this.info.admin.user_id,
...this.passwordForm
})
this.passwordDialogVisible = false
this.$message.success(this.$t('page.layout.user.password_change_success'))
util.cookies.remove('token')
util.cookies.remove('uuid')
util.cookies.remove('block')
localStorage.removeItem('user_id')
this.logout({ confirm: false })
} finally {
this.passwordSubmitting = false
}
})
},
async reloadMenu () {
await this.$store.dispatch('d2admin/menu/menuReload')
this.$store.commit('d2admin/page/keepAliveClean')
await this.$router.replace('/refresh')
this.$message.success(this.$t('page.layout.user.menu_permission_reloaded'))
},
openAuthDialog () {
this.authDialogVisible = true
this.loadAuthTime()
},
clearAuthFiles () {
this.$nextTick(() => {
this.$refs.authUpload && this.$refs.authUpload.clearFiles()
})
},
beforeAuthUpload (file) {
const ext = String(file.name || '').replace(/.+\./, '').toLowerCase()
if (ext !== 'license') {
this.$message.error(this.$t('page.layout.user.please_upload_license'))
return false
}
return true
},
async uploadAuthFile ({ file }) {
const formData = new FormData()
formData.append('method', 'get.auth.timeByUpload')
formData.append('platform', 'admin')
formData.append('file', file)
try {
const res = this.normalizeAuthResponse(await getAuthTimeByUpload(formData))
if (res.status !== 0) {
this.$message.error(res.msg)
return
}
this.authTime = res.msg
this.$message.success(this.$t('page.layout.user.authorization_update_success', { time: res.msg }))
} finally {
this.clearAuthFiles()
}
},
notifyAuthExpired (message) {
if (process.env.NODE_ENV === 'development') return
this.$notify.error({
title: this.$t('page.layout.user.prompt'),
message,
duration: 4500,
position: 'bottom-right',
showClose: false
})
},
notifyAuthNearTime (message) {
if (process.env.NODE_ENV === 'development') return
this.$notify.warning({
title: this.$t('page.layout.user.prompt'),
message,
duration: 4500,
position: 'top-right',
showClose: false
})
},
clearAuthNoticeTimer () {
if (this.authNoticeTimer) {
clearInterval(this.authNoticeTimer)
this.authNoticeTimer = null
}
},
startAuthNoticeTimer (type, message) {
if (process.env.NODE_ENV === 'development') return
this.clearAuthNoticeTimer()
const notify = type === 'expired' ? this.notifyAuthExpired : this.notifyAuthNearTime
const interval = type === 'expired' ? 5000 : 30000
this.authNoticeTimer = setInterval(() => notify(message), interval)
},
async loadAuthTime () {
try {
const auth = this.normalizeAuthResponse(await getAuthTime())
if (auth.msg) this.authTime = auth.msg
if (auth.status === 1) {
const message = this.$t('page.layout.user.authorization_expired_message', { time: auth.msg })
this.notifyAuthExpired(message)
this.startAuthNoticeTimer('expired', message)
}
const near = this.normalizeAuthResponse(await getAuthNearTime())
if (near.status === 1) {
const message = this.$t('page.layout.user.authorization_near_message', { message: near.msg })
this.notifyAuthNearTime(message)
this.startAuthNoticeTimer('near', message)
}
} catch (error) {
this.clearAuthNoticeTimer()
}
},
logOff () {
localStorage.removeItem('user_id')
this.logout({
confirm: true
})
}
}
}
</script>
<style scoped>
.auth-upload {
margin-top: 16px;
}
</style>