feat(Account): 添加路由支持并改进通行密钥管理界面

- 在App.vue中引入useRoute并根据当前路由设置默认导航项
- 在PassKey.vue中添加模态窗口组件用于显示确认和警告对话框
- 替换原生alert和confirm为自定义模态窗口
- 实现通行密
This commit is contained in:
2026-03-28 01:09:59 +08:00
parent ddce6e6036
commit 44c7a8c304
2 changed files with 156 additions and 28 deletions

View File

@@ -1,13 +1,15 @@
<script setup> <script setup>
import { ref } from '@vue/reactivity'; import { ref } from '@vue/reactivity';
import { onMounted } from '@vue/runtime-core'; import { onMounted } from '@vue/runtime-core';
import { useRoute } from 'vue-router';
import Account from './components/Account.vue'; import Account from './components/Account.vue';
const route = useRoute();
const isLogin = ref(false); const isLogin = ref(false);
const isLoading = ref(true); const isLoading = ref(true);
const userName = ref(''); const userName = ref('');
const email = ref(''); const email = ref('');
const activeNav = ref('profile'); const activeNav = ref(route.name || 'profile');
//初始化登录信息 //初始化登录信息
var bearer = localStorage.getItem('bearer'); var bearer = localStorage.getItem('bearer');

View File

@@ -6,6 +6,13 @@ const isLoading = ref(true);
const editingId = ref(null); const editingId = ref(null);
const editingName = ref(''); const editingName = ref('');
// 模态窗口状态
const showModal = ref(false);
const modalType = ref(''); // 'confirm' | 'alert'
const modalTitle = ref('');
const modalMessage = ref('');
const modalConfirmCallback = ref(null);
onMounted(() => { onMounted(() => {
GetPasskeyList(); GetPasskeyList();
}) })
@@ -29,11 +36,18 @@ function GetPasskeyList() {
} }
function CreatePasskey() { function CreatePasskey() {
window.open( const authWindow = window.open(
`${localStorage.getItem('loginClientUrl')}?passkey`, `${localStorage.getItem('loginClientUrl')}?passkey`,
'统一身份认证', '统一身份认证',
'height=700,width=1000,top=300,left=200,toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,status=no' 'height=700,width=1000,top=300,left=200,toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,status=no'
) );
const checkClosed = setInterval(() => {
if (authWindow.closed) {
clearInterval(checkClosed);
GetPasskeyList();
}
}, 500);
} }
function StartEditName(id, currentName) { function StartEditName(id, currentName) {
@@ -48,7 +62,7 @@ function CancelEdit() {
function SavePasskeyName(id) { function SavePasskeyName(id) {
if (!editingName.value.trim()) { if (!editingName.value.trim()) {
alert('名称不能为空'); ShowAlert('提示', '名称不能为空');
return; return;
} }
@@ -71,38 +85,64 @@ function SavePasskeyName(id) {
} }
CancelEdit(); CancelEdit();
} else { } else {
alert('修改名称失败,请重试'); ShowAlert('错误', '修改名称失败,请重试');
} }
}).catch(() => { }).catch(() => {
alert('网络错误,请重试'); ShowAlert('错误', '网络错误,请重试');
}) })
} }
function DeletePasskey(id, name) { function ShowConfirm(title, message, callback) {
if (!confirm(`确认删除通行密钥"${name}"吗?`)) { modalType.value = 'confirm';
return; modalTitle.value = title;
modalMessage.value = message;
modalConfirmCallback.value = callback;
showModal.value = true;
}
function ShowAlert(title, message) {
modalType.value = 'alert';
modalTitle.value = title;
modalMessage.value = message;
modalConfirmCallback.value = null;
showModal.value = true;
}
function HandleConfirm() {
if (modalConfirmCallback.value) {
modalConfirmCallback.value();
} }
CloseModal();
}
const loginServerUrl = localStorage.getItem('loginServerUrl'); function CloseModal() {
const formData = new FormData(); showModal.value = false;
formData.append('id', id); modalConfirmCallback.value = null;
}
fetch(loginServerUrl + '/deletepasskey', { function DeletePasskey(id, name) {
method: 'POST', ShowConfirm('确认删除', `确认删除通行密钥"${name}"吗?`, () => {
headers: { const loginServerUrl = localStorage.getItem('loginServerUrl');
Authorization: `Bearer ${window.localStorage.getItem('bearer')}` const formData = new FormData();
}, formData.append('id', id);
body: formData
}).then(res => { fetch(loginServerUrl + '/deletepasskey', {
if (res.ok) { method: 'POST',
passkeyList.value = passkeyList.value.filter(p => p.id !== id); headers: {
alert('请自行前往通行密钥的提供程序删除本地密钥。'); Authorization: `Bearer ${window.localStorage.getItem('bearer')}`
} else { },
alert('删除失败,请重试'); body: formData
} }).then(res => {
}).catch(() => { if (res.ok) {
alert('网络错误,请重试'); passkeyList.value = passkeyList.value.filter(p => p.id !== id);
}) ShowAlert('删除成功', '请自行前往通行密钥的提供程序删除本地密钥。');
} else {
ShowAlert('删除失败', '删除失败,请重试');
}
}).catch(() => {
ShowAlert('网络错误', '网络错误,请重试');
})
});
} }
function formatDate(dateStr) { function formatDate(dateStr) {
@@ -209,6 +249,23 @@ function formatDate(dateStr) {
</div> </div>
</div> </div>
</div> </div>
<!-- 模态窗口 -->
<div class="modal-overlay" v-if="showModal" @click.self="CloseModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">{{ modalTitle }}</h3>
<button class="modal-close" @click="CloseModal">×</button>
</div>
<div class="modal-body">
<p>{{ modalMessage }}</p>
</div>
<div class="modal-footer">
<button v-if="modalType === 'confirm'" class="btn btn-secondary" @click="CloseModal">取消</button>
<button class="btn btn-primary" @click="HandleConfirm">确定</button>
</div>
</div>
</div>
</div> </div>
</template> </template>
@@ -434,4 +491,73 @@ function formatDate(dateStr) {
font-size: 14px; font-size: 14px;
color: var(--text-secondary); color: var(--text-secondary);
} }
/* 模态窗口样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: var(--card-bg);
border-radius: var(--radius-lg);
width: 400px;
max-width: 90%;
box-shadow: var(--shadow-lg);
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid var(--border-color);
}
.modal-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.modal-close {
background: none;
border: none;
font-size: 24px;
color: var(--text-secondary);
cursor: pointer;
padding: 0;
line-height: 1;
}
.modal-close:hover {
color: var(--text-primary);
}
.modal-body {
padding: 24px;
}
.modal-body p {
margin: 0;
color: var(--text-primary);
line-height: 1.6;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
padding: 16px 24px;
border-top: 1px solid var(--border-color);
}
</style> </style>