feat: add change user password

This commit is contained in:
马登山
2025-11-05 14:54:03 +08:00
parent e79dd87fc3
commit a0ac284805
5 changed files with 180 additions and 1 deletions
+158
View File
@@ -0,0 +1,158 @@
<template>
<Modal
v-model="modalVisible"
:title="t('Change Secret Key') + (accessKey ? `: ${accessKey}` : '')"
size="md"
:close-on-backdrop="false"
>
<div class="space-y-4">
<Field>
<FieldLabel for="secret-key-new">{{ t('New Secret Key') }}</FieldLabel>
<FieldContent>
<Input id="secret-key-new" v-model="formModel.new_secret_key" type="password" autocomplete="off" />
</FieldContent>
<FieldDescription v-if="errors.new_secret_key" class="text-destructive">
{{ errors.new_secret_key }}
</FieldDescription>
</Field>
<Field>
<FieldLabel for="secret-key-confirm">{{ t('Confirm New Secret Key') }}</FieldLabel>
<FieldContent>
<Input
id="secret-key-confirm"
v-model="formModel.re_new_secret_key"
type="password"
autocomplete="off"
:disabled="!formModel.new_secret_key"
/>
</FieldContent>
<FieldDescription v-if="errors.re_new_secret_key" class="text-destructive">
{{ errors.re_new_secret_key }}
</FieldDescription>
</Field>
</div>
<template #footer>
<div class="flex justify-end gap-2">
<Button variant="outline" @click="closeModal()">
{{ t('Cancel') }}
</Button>
<Button variant="default" :disabled="submitting" @click="submitForm">
<Spinner v-if="submitting" class="size-4" />
<span>{{ t('Submit') }}</span>
</Button>
</div>
</template>
</Modal>
</template>
<script setup lang="ts">
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Spinner } from '@/components/ui/spinner'
import { Field, FieldContent, FieldDescription, FieldLabel } from '@/components/ui/field'
import { computed, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import Modal from '~/components/modal.vue'
const { t } = useI18n()
const { createUser } = useUsers()
const message = useMessage()
interface Props {
visible: boolean
accessKey: string
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
interface Emits {
(e: 'update:visible', visible: boolean): void
}
const formModel = reactive({
new_secret_key: '',
re_new_secret_key: '',
})
const errors = reactive({
new_secret_key: '',
re_new_secret_key: '',
})
const submitting = ref(false)
const modalVisible = computed({
get() {
return props.visible
},
set(value) {
closeModal(value)
},
})
function clearForm() {
formModel.new_secret_key = ''
formModel.re_new_secret_key = ''
Object.keys(errors).forEach(key => {
errors[key as keyof typeof errors] = ''
})
}
function closeModal(visible = false) {
emit('update:visible', visible)
if (!visible) {
clearForm()
submitting.value = false
}
}
function validate() {
errors.new_secret_key = formModel.new_secret_key ? '' : t('Please enter new password')
if (!formModel.re_new_secret_key) {
errors.re_new_secret_key = t('Please enter new password again')
} else if (formModel.re_new_secret_key !== formModel.new_secret_key) {
errors.re_new_secret_key = t('The two passwords are inconsistent')
} else {
errors.re_new_secret_key = ''
}
return !errors.new_secret_key && !errors.re_new_secret_key
}
async function submitForm() {
if (!validate()) {
message.error(t('Please fill in the correct format'))
return
}
submitting.value = true
try {
await createUser({
accessKey: props.accessKey,
secretKey: formModel.new_secret_key,
status: 'enabled',
})
message.success(t('Updated successfully'))
closeModal()
} catch (error) {
console.error(error)
message.error(t('Update failed'))
} finally {
submitting.value = false
}
}
watch(
() => props.visible,
value => {
if (value) {
clearForm()
}
}
)
</script>
+13 -1
View File
@@ -1,9 +1,13 @@
<template>
<Modal v-model="visible" :title="user.accessKey || t('Account')" size="lg" :close-on-backdrop="false">
<div class="space-y-4">
<div class="flex items-center justify-between rounded-md border px-3 py-2">
<div class="flex items-center justify-start gap-2 rounded-md border px-3 py-2">
<span class="text-sm text-muted-foreground">{{ t('Status') }}</span>
<Switch v-model="statusBoolean" />
<Button variant="outline" @click="handleChangeSecretKey" class="ml-auto">
<Icon name="ri:key-2-line" class="size-4" />
<span>{{ t('Change Secret Key') }}</span>
</Button>
</div>
<Tabs v-model="activeTab" class="flex flex-col gap-4">
@@ -27,6 +31,8 @@
<user-notice ref="noticeRef" @search="refreshUser" />
</div>
</Modal>
<user-change-secret-key v-model:visible="changeSecretKeyVisible" :access-key="user.accessKey" />
</template>
<script setup lang="ts">
@@ -39,6 +45,7 @@ import Modal from '~/components/modal.vue'
const { t } = useI18n()
const visible = ref(false)
const activeTab = ref('groups')
const changeSecretKeyVisible = ref(false)
const { getUser, changeUserStatus } = useUsers()
interface UserInfo {
@@ -85,6 +92,11 @@ const noticeDialog = (data: any) => {
noticeRef.value?.openDialog(data)
}
const handleChangeSecretKey = () => {
visible.value = false
changeSecretKeyVisible.value = true
}
async function openDialog(row: any) {
user.value = {
accessKey: row.accessKey,
+3
View File
@@ -113,7 +113,9 @@
"Canceled": "Canceled",
"Cannot Preview": "Cannot preview this object content (MIME type: {contentType}), please download to view",
"Change Password": "Change Password",
"Change Secret Key": "Change Secret Key",
"Change current account password": "Change current account password",
"Confirm New Secret Key": "Confirm New Secret Key",
"Choose the encryption method for this bucket": "Choose the encryption method for this bucket",
"Clear All": "Clear All",
"Clear Cache": "Clear Cache",
@@ -429,6 +431,7 @@
"New Folder": "New Folder",
"New Form": "New {type}",
"New Password": "New Password",
"New Secret Key": "New Secret Key",
"New Policy": "New Policy",
"New user has been created": "New user has been created",
"Next": "Next",
+3
View File
@@ -113,7 +113,9 @@
"Canceled": "İptal Edildi",
"Cannot Preview": "Bu nesne içeriği önizlenemiyor (MIME türü: {contentType}), lütfen görüntülemek için indirin",
"Change Password": "Change Password",
"Change Secret Key": "Change Secret Key",
"Change current account password": "Change current account password",
"Confirm New Secret Key": "Confirm New Secret Key",
"Choose the encryption method for this bucket": "Choose the encryption method for this bucket",
"Clear All": "Clear All",
"Clear Cache": "Clear Cache",
@@ -429,6 +431,7 @@
"New Folder": "Yeni Klasör",
"New Form": "Yeni {type}",
"New Password": "New Password",
"New Secret Key": "New Secret Key",
"New Policy": "Yeni Politika",
"New user has been created": "Yeni kullanıcı oluşturuldu",
"Next": "Sonraki",
+3
View File
@@ -113,7 +113,9 @@
"Canceled": "已取消",
"Cannot Preview": "无法预览该对象的内容(MIME类型:{contentType}),请下载查看",
"Change Password": "更改密码",
"Change Secret Key": "更改密钥",
"Change current account password": "更改当前账户密码",
"Confirm New Secret Key": "确认新密钥",
"Choose the encryption method for this bucket": "选择此存储桶的加密方法",
"Clear All": "清除全部",
"Clear Cache": "清除缓存",
@@ -429,6 +431,7 @@
"New Folder": "新建目录",
"New Form": "新建{type}",
"New Password": "新密码",
"New Secret Key": "新密钥",
"New Policy": "新建策略",
"New user has been created": "新用户已创建",
"Next": "下一页",