This commit is contained in:
Yvan
2026-09-04 10:51:45 +08:00
parent d94e2ed225
commit af1e194396
17 changed files with 1015 additions and 61 deletions
+6 -7
View File
@@ -1,10 +1,9 @@
server {
listen 8080;
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# K8s 部署:proxy_pass 的服务名由 Jenkins envsubst '$KRA_APP' 渲染为 <APP_NAME>-backend,
# 产物写至 web/nginx.k8s.conf(不入库)。本地手动构建 web 镜像前需先执行渲染。
location / {
root /usr/share/nginx/html;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
@@ -17,10 +16,10 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/(.*)$ /$1 break; #重写
proxy_pass http://177.7.0.12:8888; # 设置代理服务器的协议和地址
proxy_pass http://${KRA_APP}-backend:8000; # Kubernetes Service
}
location /api/swagger/index.html {
proxy_pass http://127.0.0.1:8888/swagger/index.html;
proxy_pass http://${KRA_APP}-backend:8000/swagger/index.html;
}
}
}
+3
View File
@@ -3,3 +3,6 @@ ENV = 'production'
#下方为上线需要用到的程序代理前缀,一般用于nginx代理转发
VITE_BASE_API = /api
VITE_FILE_API = /api
# 后端与前端端口不一致时配置,例如 VITE_SERVER_PORT = 30081。
# 也可以使用 VITE_WEBSOCKET_URL = http://192.168.200.128:30081 指定后端地址。
+2
View File
@@ -4,3 +4,5 @@ package-lock.json
yarn.lock
bun.lockb
config.yaml
# 渲染产物:Jenkins 从 .docker-compose/nginx/conf.d/my.conf 生成
/nginx.k8s.conf
+5 -24
View File
@@ -1,24 +1,5 @@
# 如果需要用 cicd ,请设置环境变量:
# variables:
# DOCKER_BUILDKIT: 1
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod
FROM base AS build
COPY --from=prod-deps /app/node_modules /app/node_modules
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install && pnpm run build
FROM nginx:alpine
COPY --from=base /app/.docker-compose/nginx/conf.d/my.conf /etc/nginx/conf.d/my.conf
COPY --from=build /app/dist /usr/share/nginx/html
RUN ls -al /usr/share/nginx/html
FROM docker.m.daocloud.io/nginx:alpine
# nginx.k8s.conf is rendered by Jenkins from
# .docker-compose/nginx/conf.d/my.conf (envsubst '$KRA_APP').
COPY nginx.k8s.conf /etc/nginx/conf.d/default.conf
COPY dist /usr/share/nginx/html
+6 -6
View File
@@ -1,7 +1,7 @@
allowBuilds:
'@parcel/watcher': set this to true or false
'@vue-office/docx': set this to true or false
'@vue-office/excel': set this to true or false
'@vue-office/pdf': set this to true or false
es5-ext: set this to true or false
vue-demi: set this to true or false
'@parcel/watcher': true
'@vue-office/docx': true
'@vue-office/excel': true
'@vue-office/pdf': true
es5-ext: true
vue-demi: true
@@ -170,7 +170,7 @@
<el-button
v-if="isWebSocket(selected)"
:icon="DocumentCopy"
:disabled="isBusy(selected)"
:disabled="isBusy(selected) || !canTestConnectionInfo(selected)"
@click="openConnectionInfo"
>
连接信息
@@ -326,9 +326,18 @@ const selected = computed(
const integrationKey = (item) => `${item.kind}/${item.provider}`
const providerMeta = (item) => TARGETS[integrationKey(item)] || TARGETS[TARGET_ORDER[0]]
const isWebSocket = (item) => integrationKey(item) === 'websocket/melody'
const websocketBackendIsExplicit = () =>
Boolean(
String(import.meta.env.VITE_WEBSOCKET_URL || '').trim() ||
String(import.meta.env.VITE_SERVER_PORT || '').trim()
)
const websocketOrigin = () => {
if (import.meta.env.DEV && import.meta.env.VITE_SERVER_PORT) {
const configuredBase = String(import.meta.env.VITE_BASE_PATH || window.location.origin)
if (websocketBackendIsExplicit()) {
const configuredBase = String(
import.meta.env.VITE_WEBSOCKET_URL ||
import.meta.env.VITE_BASE_PATH ||
window.location.origin
)
const backend = new URL(configuredBase, window.location.origin)
if (
['127.0.0.1', 'localhost'].includes(backend.hostname) &&
@@ -336,18 +345,27 @@ const websocketOrigin = () => {
) {
backend.hostname = window.location.hostname
}
backend.port = String(import.meta.env.VITE_SERVER_PORT)
if (import.meta.env.VITE_SERVER_PORT) {
backend.port = String(import.meta.env.VITE_SERVER_PORT)
}
backend.protocol = backend.protocol === 'https:' ? 'wss:' : 'ws:'
return `${backend.protocol}//${backend.host}`
}
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
return `${protocol}//${window.location.host}`
}
const websocketPathPrefix = () => {
if (websocketBackendIsExplicit()) return ''
const base = String(import.meta.env.VITE_BASE_API || '').trim()
if (!base || /^https?:\/\//i.test(base)) return ''
return `/${base.replace(/^\/+|\/+$/g, '')}`
}
const connectionInfo = computed(() => {
const path = String(selected.value?.config?.path || '/ws').trim() || '/ws'
const normalizedPath = path.startsWith('/') ? path : `/${path}`
const routePath = `${websocketPathPrefix()}${normalizedPath}`
const token = String(userStore.token || '').trim()
const url = `${websocketOrigin()}${normalizedPath}${token ? `?token=${encodeURIComponent(token)}` : ''}`
const url = `${websocketOrigin()}${routePath}${token ? `?token=${encodeURIComponent(token)}` : ''}`
return {
url,
example: `const socket = new WebSocket(${JSON.stringify(url)})\n\nsocket.onopen = () => console.log('connected')\nsocket.onmessage = (event) => console.log(event.data)`
@@ -357,7 +375,7 @@ const connectionTestMessage = computed(() => {
if (connectionTestStatus.value === 'testing') return '等待服务器握手包...'
if (connectionTestStatus.value === 'success') return '握手成功,WebSocket 已连接。'
if (connectionTestStatus.value === 'error') return '握手失败,请查看 websocket/websocket.log。'
return '点击“测试此地址”验证浏览器到服务器的真实握手。'
return '“测试连接”仅校验当前参数;保存并启用后可测试正式地址。'
})
const connectionTestAlertType = computed(() => {
if (connectionTestStatus.value === 'success') return 'success'
@@ -469,6 +487,8 @@ const isBusy = (item) => Boolean(pending[operationKey(item)])
const isSaving = (item) => pending[operationKey(item)] === 'save'
const isToggling = (item) => pending[operationKey(item)] === 'toggle'
const isTesting = (item) => pending[operationKey(item)] === 'test'
const canTestConnectionInfo = (item) =>
Boolean(item?.configured && item.enabled && !isDirty(item))
const numberConstraint = (fieldKey) =>
NUMBER_CONSTRAINTS[fieldKey] || { min: undefined, max: undefined }
@@ -601,7 +621,7 @@ const testSelected = async () => {
if (res.code !== 0) {
return
}
ElMessage.success(`${item.name || providerMeta(item).name} 连接测试成功`)
ElMessage.success(`${item.name || providerMeta(item).name} 配置测试成功`)
} catch {
// The request layer owns transport and server error presentation.
} finally {