Merge remote-tracking branch 'origin/main'

# Conflicts:
#	internal/httpapi/dist/assets/index-CL42Ur3_.css
#	internal/httpapi/dist/assets/index-CbqC9m-j.js
#	internal/httpapi/dist/assets/index-RFHYrCiX.css
#	internal/httpapi/dist/assets/index-jvouiCgh.css
#	internal/httpapi/dist/index.html
#	internal/store/store.go
#	web/src/api.ts
#	web/src/views/ClusterView.vue
This commit is contained in:
JianFeeeee
2026-08-24 23:30:19 +08:00
28 changed files with 1143 additions and 1084 deletions

View File

@ -8,7 +8,7 @@
</div>
<div class="tb-right">
<button class="w4f-btn ghost small" @click="loadStatus"> 刷新</button>
<button class="w4f-btn small" @click="openAdd"> 添加远程节点</button>
<button v-if="canWrite" class="w4f-btn small" @click="openAdd"> 添加远程节点</button>
</div>
</div>
@ -43,9 +43,9 @@
<span class="k-ic"></span>{{ g.label }}
<span class="grp-count">{{ g.items.length }} </span>
<span class="grp-actions">
<button class="w4f-btn small" @click="groupStart(g.key)">一键启动整组</button>
<button class="w4f-btn ghost small" @click="groupStop(g.key)">一键停止整组</button>
<button v-if="g.key" class="w4f-btn ghost small danger" @click="deleteGroup(g.key)">删除分组</button>
<button v-if="canWrite" class="w4f-btn small" @click="groupStart(g.key)">一键启动整组</button>
<button v-if="canWrite" class="w4f-btn ghost small" @click="groupStop(g.key)">一键停止整组</button>
<button v-if="canWrite && g.key" class="w4f-btn ghost small danger" @click="deleteGroup(g.key)">删除分组</button>
</span>
</h3>
<div class="card-grid">
@ -70,13 +70,14 @@
<span v-if="f.localProto" class="w4f-tag w4f-tag-primary">{{ f.localProto }}</span>
<span
class="w4f-tag w4f-tag-info group-chip"
@click="editGroup(f)"
:title="'点击修改分组(当前:' + (f.group || '未分组') + ''"
:class="{ readonly: !canWrite }"
@click="canWrite && editGroup(f)"
:title="canWrite ? '点击修改分组(当前:' + (f.group || '未分组') + '' : '当前分组:' + (f.group || '未分组')"
>{{ f.group || '未分组' }}</span>
<span v-if="f.kind === 'remote'" class="fwd-owner" :title="f.ownerId || ''">{{ ownerLabel(f) }}</span>
<span class="fwd-actions">
<button v-if="!f.active" class="w4f-btn small" @click="startForward(f)">启动转发</button>
<button v-else class="w4f-btn ghost small" @click="stopForward(f)">停止转发</button>
<button v-if="canWrite && !f.active" class="w4f-btn small" @click="startForward(f)">启动转发</button>
<button v-else-if="canWrite" class="w4f-btn ghost small" @click="stopForward(f)">停止转发</button>
</span>
</div>
</div>
@ -101,8 +102,8 @@
<span class="w4f-dot" :class="connDotClass(p.connState)" />{{ connStateLabel(p.connState) }}
</span>
<span class="nc-actions">
<button class="w4f-btn ghost small" @click="openEdit(p)">编辑</button>
<button class="w4f-btn danger small" @click="removeRemote(p.name)">删除</button>
<button v-if="canWrite" class="w4f-btn ghost small" @click="openEdit(p)">编辑</button>
<button v-if="canWrite" class="w4f-btn danger small" @click="removeRemote(p.name)">删除</button>
</span>
</div>
<div class="nc-meta">
@ -172,31 +173,31 @@
<el-dialog v-model="dialog.visible" :title="dialog.isNew ? '添加远程节点' : '编辑远程节点'" width="440px">
<div class="form-row">
<label>名称</label>
<el-input v-model="dialog.remote.name" :disabled="!dialog.isNew" placeholder="如 aliyun-hz" />
<el-input v-model="dialog.remote.name" :disabled="!canWrite || !dialog.isNew" placeholder="如 aliyun-hz" />
</div>
<div class="form-row">
<label>服务器 IP</label>
<el-input v-model="dialog.remote.ip" placeholder="frps 地址" />
<el-input v-model="dialog.remote.ip" :disabled="!canWrite" placeholder="frps 地址" />
</div>
<div class="form-row">
<label>端口</label>
<el-input-number v-model="dialog.remote.port" :min="1" :max="65535" />
<el-input-number v-model="dialog.remote.port" :disabled="!canWrite" :min="1" :max="65535" />
</div>
<div class="form-row">
<label>Token</label>
<el-input v-model="dialog.remote.token" placeholder="可选" />
<el-input v-model="dialog.remote.token" :disabled="!canWrite" placeholder="可选" />
</div>
<div class="form-row">
<label>URL</label>
<el-input v-model="dialog.remote.url" placeholder="可选" />
<el-input v-model="dialog.remote.url" :disabled="!canWrite" placeholder="可选" />
</div>
<div class="form-row">
<label>启用</label>
<el-switch v-model="dialog.remote.enabled" />
<el-switch v-model="dialog.remote.enabled" :disabled="!canWrite" />
</div>
<template #footer>
<button class="w4f-btn ghost small" @click="dialog.visible = false">取消</button>
<button class="w4f-btn small" @click="saveRemote">保存</button>
<button class="w4f-btn small" :disabled="!canWrite" @click="saveRemote">保存</button>
</template>
</el-dialog>
</div>
@ -206,6 +207,7 @@
import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { api } from '../api'
import { canWrite } from '../auth'
import type { ForwardStatus, Remote, StatusResp } from '../types'
const status = ref<StatusResp | null>(null)
@ -616,7 +618,7 @@ onBeforeUnmount(() => {
.fwd-actions { display: flex; gap: 6px; }
.grp-count { font-size: 12px; color: $color-text-muted; font-weight: 600; }
.grp-actions { margin-left: auto; display: flex; gap: 6px; }
.group-chip { cursor: pointer; transition: background $transition-fast; &:hover { background: color-mix(in srgb, var(--w4f-info) 30%, transparent); } }
.group-chip { cursor: pointer; transition: background $transition-fast; &:hover { background: color-mix(in srgb, var(--w4f-info) 30%, transparent); } &.readonly { cursor: default; &:hover { background: none; } } }
/* local service card */
.local-card { padding: 14px 16px; }