diff --git a/GAHFrontend/src/components/ComponentTest.vue b/GAHFrontend/src/components/ComponentTest.vue new file mode 100644 index 0000000..6beff51 --- /dev/null +++ b/GAHFrontend/src/components/ComponentTest.vue @@ -0,0 +1,2 @@ + diff --git a/GAHFrontend/src/components/component_test.vue b/GAHFrontend/src/components/component_test.vue deleted file mode 100644 index cc340bc..0000000 --- a/GAHFrontend/src/components/component_test.vue +++ /dev/null @@ -1 +0,0 @@ - diff --git a/GAHFrontend/src/components/customize/AddAdminDialogFrom.vue b/GAHFrontend/src/components/customize/AddAdminDialogFrom.vue index 4694858..bb1290b 100644 --- a/GAHFrontend/src/components/customize/AddAdminDialogFrom.vue +++ b/GAHFrontend/src/components/customize/AddAdminDialogFrom.vue @@ -1,25 +1,26 @@ @@ -36,7 +37,7 @@ defineProps({ const emit = defineEmits(['update:modelValue', 'submit']) -// 表单字段对应 adminAdd.go 的请求体 +// Form fields map to the request body of adminAdd.go const form = reactive({ username: '', password: '', @@ -47,6 +48,7 @@ const form = reactive({ can_get_admin: false, can_operate_user: false, can_operate_character: false, + can_operate_app_key: false, }, }) diff --git a/GAHFrontend/src/components/customize/AddCharacterDialogFrom.vue b/GAHFrontend/src/components/customize/AddCharacterDialogFrom.vue index 33255c6..d67f239 100644 --- a/GAHFrontend/src/components/customize/AddCharacterDialogFrom.vue +++ b/GAHFrontend/src/components/customize/AddCharacterDialogFrom.vue @@ -1,23 +1,23 @@ @@ -35,7 +35,7 @@ defineProps({ const emit = defineEmits(['update:modelValue', 'submit']) -// 表单字段对应 characterAdd.go 的请求体 +// Form fields map to the request body of characterAdd.go const form = reactive({ character_name: '', password: '', diff --git a/GAHFrontend/src/components/customize/AddKeyDialogFrom.vue b/GAHFrontend/src/components/customize/AddKeyDialogFrom.vue new file mode 100644 index 0000000..116dbc7 --- /dev/null +++ b/GAHFrontend/src/components/customize/AddKeyDialogFrom.vue @@ -0,0 +1,56 @@ + + + diff --git a/GAHFrontend/src/components/customize/AddUserDialogFrom.vue b/GAHFrontend/src/components/customize/AddUserDialogFrom.vue index f73c73a..9324b3f 100644 --- a/GAHFrontend/src/components/customize/AddUserDialogFrom.vue +++ b/GAHFrontend/src/components/customize/AddUserDialogFrom.vue @@ -1,20 +1,20 @@ @@ -32,7 +32,7 @@ defineProps({ const emit = defineEmits(['update:modelValue', 'submit']) -// 表单字段对应 userAdd.go 的请求体 +// Form fields map to the request body of userAdd.go const form = reactive({ username: '', password: '', diff --git a/GAHFrontend/src/components/customize/EditAdminDialogFrom.vue b/GAHFrontend/src/components/customize/EditAdminDialogFrom.vue index ed15606..66404c7 100644 --- a/GAHFrontend/src/components/customize/EditAdminDialogFrom.vue +++ b/GAHFrontend/src/components/customize/EditAdminDialogFrom.vue @@ -1,22 +1,23 @@ @@ -29,7 +30,7 @@ const props = defineProps({ type: Boolean, default: false, }, - // 被编辑的管理员行数据,用于回填表单 + // Admin row being edited, used to populate the form admin: { type: Object, default: null, @@ -38,7 +39,7 @@ const props = defineProps({ const emit = defineEmits(['update:modelValue', 'submit']) -// 表单字段对应 adminEdit.go 的请求体 +// Form fields map to the request body of adminEdit.go const form = reactive({ uu_hash: '', admin_info: { @@ -50,11 +51,12 @@ const form = reactive({ can_get_admin: false, can_operate_user: false, can_operate_character: false, + can_operate_app_key: false, }, }, }) -// 打开弹窗或切换目标行时回填表单 +// Populate the form when the dialog opens or the target row changes watch( () => [props.modelValue, props.admin], () => { diff --git a/GAHFrontend/src/components/customize/EditCharacterDialog.vue b/GAHFrontend/src/components/customize/EditCharacterDialog.vue index 9e9aaab..44bef2b 100644 --- a/GAHFrontend/src/components/customize/EditCharacterDialog.vue +++ b/GAHFrontend/src/components/customize/EditCharacterDialog.vue @@ -1,20 +1,20 @@ @@ -28,7 +28,7 @@ const props = defineProps({ type: Boolean, default: false, }, - // 被编辑的角色行数据,用于回填表单 + // Character row being edited, used to populate the form character: { type: Object, default: null, @@ -37,7 +37,7 @@ const props = defineProps({ const emit = defineEmits(['update:modelValue', 'submit']) -// 表单字段对应 characterEdit.go 的请求体 +// Form fields map to the request body of characterEdit.go const form = reactive({ user_uu_hash: '', character_uu_hash: '', @@ -46,7 +46,7 @@ const form = reactive({ meta_data: '', }) -// 打开弹窗或切换目标行时回填表单 +// Populate the form when the dialog opens or the target row changes watch( () => [props.modelValue, props.character], () => { diff --git a/GAHFrontend/src/components/customize/EditUserDialog.vue b/GAHFrontend/src/components/customize/EditUserDialog.vue index 6860646..45889e9 100644 --- a/GAHFrontend/src/components/customize/EditUserDialog.vue +++ b/GAHFrontend/src/components/customize/EditUserDialog.vue @@ -1,20 +1,20 @@ @@ -28,7 +28,7 @@ const props = defineProps({ type: Boolean, default: false, }, - // 被编辑的用户行数据,用于回填表单 + // User row being edited, used to populate the form user: { type: Object, default: null, @@ -37,7 +37,7 @@ const props = defineProps({ const emit = defineEmits(['update:modelValue', 'submit']) -// 表单字段对应 userEdit.go 的请求体 +// Form fields map to the request body of userEdit.go const form = reactive({ uu_hash: '', username: '', @@ -45,7 +45,7 @@ const form = reactive({ meta_data: '', }) -// 打开弹窗或切换目标行时回填表单 +// Populate the form when the dialog opens or the target row changes watch( () => [props.modelValue, props.user], () => { diff --git a/GAHFrontend/src/components/customize/MetaDataEditor.vue b/GAHFrontend/src/components/customize/MetaDataEditor.vue index 911dbc4..78e3abc 100644 --- a/GAHFrontend/src/components/customize/MetaDataEditor.vue +++ b/GAHFrontend/src/components/customize/MetaDataEditor.vue @@ -10,22 +10,22 @@ + \ No newline at end of file diff --git a/GAHFrontend/src/components/main/page/admin.vue b/GAHFrontend/src/components/main/page/admin.vue index 79760ed..7198425 100644 --- a/GAHFrontend/src/components/main/page/admin.vue +++ b/GAHFrontend/src/components/main/page/admin.vue @@ -1,22 +1,23 @@ @@ -71,10 +72,10 @@ const adminList = ref([]) const PAGE_SIZE = 100 const loading = ref(false) -// 后端是否已无更多数据 +// Whether the backend has no more data const noMore = ref(false) -// 筛选条件表单(提交后由后端筛选) +// Filter form (filtered by the backend after submit) const searchForm = reactive({ username: '', uu_hash: '', @@ -85,16 +86,17 @@ const searchForm = reactive({ can_get_admin: false, can_operate_user: false, can_operate_character: false, + can_operate_app_key: false, }, }) -// 当前生效的筛选条件,随每次 range 请求发给后端 +// Currently active filter, sent to the backend with each range request const searchCondition = ref({}) -// 添加管理员弹窗 +// Add admin dialog const dialogVisible = ref(false) -// 编辑管理员弹窗 +// Edit admin dialog const editVisible = ref(false) const editRow = ref(null) @@ -103,13 +105,13 @@ const canGetAdmin = computed(() => { return Boolean(adminInfo.value.permission?.can_get_admin) }) -// 权限列统一渲染:命中为“是”,否则“否” -const permCell = (key) => ({ rowData }) => h('span', rowData.Permission?.[key] ? '是' : '否') +// Unified permission cell rendering: "Yes" when granted, otherwise "No" +const permCell = (key) => ({ rowData }) => h('span', rowData.Permission?.[key] ? 'Yes' : 'No') -// 勾选状态:以行 ID 记录 +// Selection state: recorded by row ID const selectedIds = ref([]) const isSelected = (id) => selectedIds.value.includes(id) -// 全选判定基于当前数据 +// Select-all is based on the current data const allSelected = computed( () => adminList.value.length > 0 && adminList.value.every((row) => isSelected(row.ID)) ) @@ -127,12 +129,12 @@ const toggleAll = () => { : [...new Set([...selectedIds.value, ...shownIds])] } -// 取消全部选中 +// Clear all selections const handleCheckboxCancel = () => { selectedIds.value = [] } -// 查询:把筛选条件交给后端,重新从第一页取 +// Search: send the filter to the backend and refetch from the first page const handleSearch = () => { searchCondition.value = { username: searchForm.username.trim(), @@ -143,11 +145,12 @@ const handleSearch = () => { can_get_admin: searchForm.permission.can_get_admin, can_operate_user: searchForm.permission.can_operate_user, can_operate_character: searchForm.permission.can_operate_character, + can_operate_app_key: searchForm.permission.can_operate_app_key, } range(1) } -// 重置:清空筛选条件并重新从第一页取全部 +// Reset: clear the filter and refetch everything from the first page const handleReset = () => { searchForm.username = '' searchForm.uu_hash = '' @@ -158,12 +161,12 @@ const handleReset = () => { range(1) } -// 打开添加管理员弹窗 +// Open the add admin dialog const handleAdd = () => { dialogVisible.value = true } -// 提交添加:调用 /admin/add,成功后刷新列表 +// Submit add: call /admin/add and refresh the list on success const handleAddSubmit = async (form) => { try { await post('/admin/add', { @@ -171,72 +174,72 @@ const handleAddSubmit = async (form) => { password: form.password, permission: { ...form.permission }, }, { autoRedirect401: false }) - ElMessage.success('添加管理员成功') + ElMessage.success('Admin added successfully') dialogVisible.value = false range(1) } catch { - // 失败提示已由 request 封装统一弹出 + // Failure messages are already shown by the request wrapper } } -// 执行删除并同步列表(后端每次只接收一个 uu_hash,故逐条调用) +// Perform deletion and sync the list (the backend accepts one uu_hash per request, so call one by one) const deleteAdmins = async (rows) => { const results = await Promise.allSettled( rows.map((item) => del('/admin/delete', { uu_hash: item.UUHash }, { autoRedirect401: false, showError: false })) ) const successIds = rows.filter((_, index) => results[index].status === 'fulfilled').map((item) => item.ID) const failed = results.filter((result) => result.status === 'rejected') - // 成功的行取消勾选 + // Deselect successfully deleted rows selectedIds.value = selectedIds.value.filter((id) => !successIds.includes(id)) if (failed.length === 0) { - ElMessage.success(`删除成功,共 ${successIds.length} 条`) + ElMessage.success(`Deleted successfully, ${successIds.length} in total`) } else if (successIds.length === 0) { - ElMessage.error(failed[0].reason?.message || '删除失败') + ElMessage.error(failed[0].reason?.message || 'Delete failed') } else { - ElMessage.warning(`成功 ${successIds.length} 条,失败 ${failed.length} 条:${failed[0].reason?.message ?? '未知原因'}`) + ElMessage.warning(`Succeeded: ${successIds.length}, failed: ${failed.length}: ${failed[0].reason?.message ?? 'Unknown reason'}`) } if (successIds.length > 0) range(1) } -// 单个删除:确认后删除该行 +// Single delete: confirm, then delete the row const handleDelete = async (row) => { try { - await ElMessageBox.confirm(`确定删除管理员"${row.Username}"吗?`, '删除确认', { + await ElMessageBox.confirm(`Are you sure you want to delete admin "${row.Username}"?`, 'Delete Confirmation', { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消', + confirmButtonText: 'Confirm', + cancelButtonText: 'Cancel', }) } catch { - // 取消删除 + // Deletion canceled return } deleteAdmins([row]) } -// 批量删除:确认后删除所有选中行 +// Batch delete: confirm, then delete all selected rows const handleBatchDelete = async () => { const rows = adminList.value.filter((item) => selectedIds.value.includes(item.ID)) if (rows.length === 0) return try { - await ElMessageBox.confirm(`确定删除选中的 ${rows.length} 条管理员吗?`, '删除确认', { + await ElMessageBox.confirm(`Are you sure you want to delete the ${rows.length} selected admins?`, 'Delete Confirmation', { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消', + confirmButtonText: 'Confirm', + cancelButtonText: 'Cancel', }) } catch { - // 取消删除 + // Deletion canceled return } deleteAdmins(rows) } -// 打开编辑管理员弹窗 +// Open the edit admin dialog const handleEdit = (row) => { editRow.value = row editVisible.value = true } -// 提交编辑:调用 /admin/edit,成功后刷新列表 +// Submit edit: call /admin/edit and refresh the list on success const handleEditSubmit = async (form) => { try { await put('/admin/edit', { @@ -246,21 +249,21 @@ const handleEditSubmit = async (form) => { permission: { ...form.admin_info.permission }, }, }, { autoRedirect401: false }) - ElMessage.success('修改管理员成功') + ElMessage.success('Admin updated successfully') editVisible.value = false range(1) } catch { - // 失败提示已由 request 封装统一弹出 + // Failure messages are already shown by the request wrapper } } -// 复制文本到剪贴板 +// Copy text to the clipboard const handleCopy = async (text) => { try { await navigator.clipboard.writeText(text) - ElMessage.success('已复制') + ElMessage.success('Copied') } catch { - ElMessage.error('复制失败') + ElMessage.error('Copy failed') } } @@ -280,33 +283,34 @@ const columns = [ }), }, { key: 'ID', dataKey: 'ID', title: 'ID', width: 70 }, - { key: 'Username', dataKey: 'Username', title: '用户名', width: 140 }, + { key: 'Username', dataKey: 'Username', title: 'Username', width: 140 }, { key: 'UUHash', title: 'UUHash', - width: 600, - cellRenderer: ({ rowData }) => h('div', { style: 'display: flex; align-items: center; gap: 8px;' }, [ - h('span', rowData.UUHash), + width: 300, + cellRenderer: ({ rowData }) => h('div', { style: 'display: flex; align-items: center; gap: 8px; min-width: 0;' }, [ + h('span', { style: 'flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;' }, rowData.UUHash), h(ElButton, { size: 'small', - title: '复制 UUHash', + title: 'Copy UUHash', onClick: () => handleCopy(rowData.UUHash), }, () => h(ElIcon, null, () => h(DocumentCopy))), ]), }, - { key: 'can_add_admin', title: '添加管理员', width: 110, cellRenderer: permCell('can_add_admin') }, - { key: 'can_delete_admin', title: '删除管理员', width: 110, cellRenderer: permCell('can_delete_admin') }, - { key: 'can_edit_admin', title: '修改管理员', width: 110, cellRenderer: permCell('can_edit_admin') }, - { key: 'can_get_admin', title: '查看管理员', width: 110, cellRenderer: permCell('can_get_admin') }, - { key: 'can_operate_user', title: '操作用户', width: 100, cellRenderer: permCell('can_operate_user') }, - { key: 'can_operate_character', title: '操作角色', width: 100, cellRenderer: permCell('can_operate_character') }, + { key: 'can_add_admin', title: 'Add Admin', width: 110, cellRenderer: permCell('can_add_admin') }, + { key: 'can_delete_admin', title: 'Delete Admin', width: 110, cellRenderer: permCell('can_delete_admin') }, + { key: 'can_edit_admin', title: 'Edit Admin', width: 110, cellRenderer: permCell('can_edit_admin') }, + { key: 'can_get_admin', title: 'View Admin', width: 110, cellRenderer: permCell('can_get_admin') }, + { key: 'can_operate_user', title: 'Operate Users', width: 100, cellRenderer: permCell('can_operate_user') }, + { key: 'can_operate_character', title: 'Operate Characters', width: 100, cellRenderer: permCell('can_operate_character') }, + { key: 'can_operate_app_key', title: 'Operate App Key', width: 110, cellRenderer: permCell('can_operate_app_key') }, { key: 'actions', - title: '操作', + title: 'Actions', width: 200, cellRenderer: ({ rowData }) => h('div', { style: 'display: flex; gap: 8px;' }, [ - h(ElButton, { type: 'danger', size: 'small', onClick: () => handleDelete(rowData) }, () => '删除管理员'), - h(ElButton, { type: 'primary', size: 'small', onClick: () => handleEdit(rowData) }, () => '编辑管理员'), + h(ElButton, { type: 'danger', size: 'small', onClick: () => handleDelete(rowData) }, () => 'Delete Admin'), + h(ElButton, { type: 'primary', size: 'small', onClick: () => handleEdit(rowData) }, () => 'Edit Admin'), ]), }, ] @@ -320,13 +324,13 @@ const range = async (start = 1) => { adminList.value = merged.sort((a, b) => a.ID - b.ID) noMore.value = list.length < PAGE_SIZE } catch { - // 401 已由 request 封装自动跳转登录页 + // 401 already redirects to the login page via the request wrapper } finally { loading.value = false } } -// 滚动到底部:后端还有数据时继续请求下一页 100 行 +// Scroll to bottom: keep requesting the next 100 rows while the backend has more data const handleEndReached = () => { if (loading.value || noMore.value) return range(Math.floor(adminList.value.length / PAGE_SIZE) + 1) @@ -337,7 +341,7 @@ onMounted(async () => { const res = await post('/admin/info') adminInfo.value = res.data } catch { - // 401 已由 request 封装自动跳转登录页,网络错误时不再继续鉴权 + // 401 already redirects to the login page via the request wrapper; stop auth check on network errors return } if (!canGetAdmin.value) { @@ -346,4 +350,4 @@ onMounted(async () => { } range() }) - + \ No newline at end of file diff --git a/GAHFrontend/src/components/main/page/character.vue b/GAHFrontend/src/components/main/page/character.vue index 074ade9..e63a603 100644 --- a/GAHFrontend/src/components/main/page/character.vue +++ b/GAHFrontend/src/components/main/page/character.vue @@ -1,16 +1,16 @@