fix: 修复 Docker 部署 API 地址与数据库连接问题
This commit is contained in:
@@ -315,44 +315,123 @@ th {
|
||||
|
||||
.list-foot {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto 1fr auto;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.list-foot button {
|
||||
min-height: 32px;
|
||||
border: 1px solid #d7e0ea;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: #334155;
|
||||
font-weight: 750;
|
||||
gap: 16px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.pager {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 4px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.pager button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 9px;
|
||||
background: transparent;
|
||||
color: #334155;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
transition: background 160ms ease, color 160ms ease, box-shadow 160ms ease;
|
||||
}
|
||||
|
||||
.pager button:hover:not(.active) {
|
||||
background: #fff;
|
||||
color: #059669;
|
||||
box-shadow: 0 1px 4px rgba(15, 23, 42, .08);
|
||||
}
|
||||
|
||||
.pager button.active {
|
||||
border-color: #059669;
|
||||
background: #059669;
|
||||
color: #fff;
|
||||
box-shadow: 0 8px 16px rgba(5, 150, 105, .20);
|
||||
}
|
||||
|
||||
.list-foot input {
|
||||
width: 42px;
|
||||
height: 30px;
|
||||
.list-foot .page-summary {
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.page-nav {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.page-size-wrap {
|
||||
position: relative;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.page-size {
|
||||
justify-self: end;
|
||||
min-width: 112px;
|
||||
min-height: 38px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 9px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid #d7e0ea;
|
||||
border-radius: 7px;
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
|
||||
color: #334155;
|
||||
font-size: 14px;
|
||||
font-weight: 750;
|
||||
white-space: nowrap;
|
||||
transition: border-color 160ms ease, color 160ms ease;
|
||||
}
|
||||
|
||||
.page-size:hover {
|
||||
border-color: rgba(16, 185, 129, .32);
|
||||
color: #0f9f78;
|
||||
}
|
||||
|
||||
.page-size-dropdown {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 6px);
|
||||
right: 0;
|
||||
z-index: 40;
|
||||
display: grid;
|
||||
border: 1px solid #d7e0ea;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
box-shadow: 0 12px 32px rgba(15, 23, 42, .14);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-size-dropdown button {
|
||||
height: 36px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: #334155;
|
||||
font-size: 13px;
|
||||
font-weight: 750;
|
||||
white-space: nowrap;
|
||||
padding: 0 20px;
|
||||
transition: background 120ms ease, color 120ms ease;
|
||||
}
|
||||
|
||||
.page-size-dropdown button:hover {
|
||||
background: #f0fdf4;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.page-size-dropdown button.active {
|
||||
background: #059669;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.preview-column {
|
||||
@@ -640,4 +719,15 @@ th {
|
||||
.list-foot {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.list-foot {
|
||||
gap: 12px;
|
||||
justify-items: stretch;
|
||||
}
|
||||
|
||||
.pager,
|
||||
.page-size-wrap,
|
||||
.page-size {
|
||||
justify-self: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,26 +27,8 @@ const authIdleTimeoutMs =
|
||||
? authIdleTimeoutMinutes * 60 * 1000
|
||||
: 30 * 60 * 1000
|
||||
|
||||
function resolveBrowserApiBaseUrl(state) {
|
||||
const server = state?.server || {}
|
||||
const configuredHost = String(server.host || '127.0.0.1').trim()
|
||||
const port = Number(server.port || 8000)
|
||||
const apiPrefix = String(import.meta.env.VITE_API_BASE_PREFIX || '/api/v1').replace(/\/$/, '') || '/api/v1'
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
return `http://${configuredHost}:${port}${apiPrefix}`
|
||||
}
|
||||
|
||||
const browserHost = window.location.hostname
|
||||
const normalizedHost = configuredHost.toLowerCase()
|
||||
const host =
|
||||
normalizedHost === '0.0.0.0' ||
|
||||
normalizedHost === '::' ||
|
||||
(normalizedHost === '127.0.0.1' && browserHost && browserHost !== '127.0.0.1' && browserHost !== 'localhost')
|
||||
? browserHost
|
||||
: configuredHost
|
||||
|
||||
return `http://${host}:${port}${apiPrefix}`
|
||||
function resolveBrowserApiBaseUrl() {
|
||||
return '/api/v1'
|
||||
}
|
||||
|
||||
let sessionRouter = null
|
||||
|
||||
@@ -39,9 +39,11 @@ function readStoredApiBaseUrl() {
|
||||
return resolveBrowserReachableApiBaseUrl(window.localStorage.getItem(API_BASE_STORAGE_KEY) || '')
|
||||
}
|
||||
|
||||
let runtimeApiBaseUrl = resolveBrowserReachableApiBaseUrl(
|
||||
readStoredApiBaseUrl() || import.meta.env.VITE_API_BASE_URL || '/api/v1'
|
||||
)
|
||||
let runtimeApiBaseUrl = normalizeApiBaseUrl('/api/v1')
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.localStorage.removeItem(API_BASE_STORAGE_KEY)
|
||||
}
|
||||
|
||||
export function setRuntimeApiBaseUrl(value) {
|
||||
runtimeApiBaseUrl = resolveBrowserReachableApiBaseUrl(value)
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="doc in filteredDocuments"
|
||||
v-for="doc in visibleDocuments"
|
||||
:key="doc.name"
|
||||
class="doc-row"
|
||||
:class="{ selected: selectedDocument?.name === doc.name }"
|
||||
@@ -93,6 +93,7 @@
|
||||
</div>
|
||||
|
||||
<footer class="list-foot">
|
||||
<template v-if="false">
|
||||
<span>共 {{ filteredDocuments.length }} 条</span>
|
||||
<button type="button">10条/页 <i class="mdi mdi-chevron-down"></i></button>
|
||||
<div class="pager" aria-label="分页">
|
||||
@@ -102,6 +103,45 @@
|
||||
<button type="button" aria-label="下一页"><i class="mdi mdi-chevron-right"></i></button>
|
||||
</div>
|
||||
<label>前往 <input value="1" aria-label="页码" /> 页</label>
|
||||
</template>
|
||||
<span class="page-summary">共 {{ totalCount }} 条,目前第 {{ currentPage }} 页</span>
|
||||
<div class="pager" aria-label="分页">
|
||||
<button class="page-nav" type="button" :disabled="currentPage === 1" aria-label="上一页" @click="currentPage--">
|
||||
<i class="mdi mdi-chevron-left"></i>
|
||||
</button>
|
||||
<button
|
||||
v-for="page in totalPages"
|
||||
:key="page"
|
||||
class="page-number"
|
||||
:class="{ active: currentPage === page }"
|
||||
type="button"
|
||||
:aria-current="currentPage === page ? 'page' : undefined"
|
||||
@click="currentPage = page"
|
||||
>
|
||||
{{ page }}
|
||||
</button>
|
||||
<button class="page-nav" type="button" :disabled="currentPage === totalPages" aria-label="下一页" @click="currentPage++">
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="page-size-wrap">
|
||||
<button class="page-size" type="button" @click="pageSizeOpen = !pageSizeOpen">
|
||||
{{ pageSize }} 条/页<i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
|
||||
<button
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
type="button"
|
||||
role="option"
|
||||
:aria-selected="pageSize === size"
|
||||
:class="{ active: pageSize === size }"
|
||||
@click="changePageSize(size)"
|
||||
>
|
||||
{{ size }} 条/页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { watch } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'PoliciesView' ,
|
||||
setup(props, { emit }) {
|
||||
@@ -230,6 +232,30 @@ export default {
|
||||
})
|
||||
)
|
||||
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOpen = ref(false)
|
||||
|
||||
const totalCount = computed(() => filteredDocuments.value.length)
|
||||
const totalPages = computed(() => Math.max(1, Math.ceil(totalCount.value / pageSize.value)))
|
||||
|
||||
const visibleDocuments = computed(() => {
|
||||
const start = (currentPage.value - 1) * pageSize.value
|
||||
return filteredDocuments.value.slice(start, start + pageSize.value)
|
||||
})
|
||||
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
watch(filteredDocuments, () => {
|
||||
currentPage.value = 1
|
||||
pageSizeOpen.value = false
|
||||
})
|
||||
|
||||
return {
|
||||
folderSearch,
|
||||
activeFolder,
|
||||
@@ -237,7 +263,15 @@ export default {
|
||||
folders,
|
||||
documents,
|
||||
filteredFolders,
|
||||
filteredDocuments
|
||||
filteredDocuments,
|
||||
currentPage,
|
||||
pageSize,
|
||||
pageSizes,
|
||||
pageSizeOpen,
|
||||
totalCount,
|
||||
totalPages,
|
||||
visibleDocuments,
|
||||
changePageSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user