fastbee/yack-web/src/views/platform/instance/index.vue
2026-07-31 05:53:20 +08:00

429 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="platform-instance">
<!-- 搜索 -->
<el-card v-show="showSearch" style="margin-bottom:10px">
<el-form :model="queryParams" ref="queryForm" size="mini" :inline="true" style="margin-bottom:-18px">
<el-form-item label="平台名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入平台名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="启用状态" prop="enable">
<el-select v-model="queryParams.enable" placeholder="全部" clearable>
<el-option label="启用" value="1" />
<el-option label="禁用" value="0" />
</el-select>
</el-form-item>
<el-form-item style="float:right">
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card>
<el-row :gutter="10" style="margin-bottom:15px">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['platform:instance:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['platform:instance:remove']">删除</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="平台名称" prop="name" min-width="140" />
<el-table-column label="标识" prop="code" width="100" />
<el-table-column label="baseURL" prop="baseUrl" min-width="200" show-overflow-tooltip />
<el-table-column label="认证类型" prop="authType" width="100" align="center">
<template slot-scope="scope">
<el-tag size="small" type="info" v-if="scope.row.authType===1">密码Token</el-tag>
<el-tag size="small" type="warning" v-if="scope.row.authType===2">ApiKey</el-tag>
<el-tag size="small" v-if="scope.row.authType===3">OAuth2</el-tag>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="初始化" width="90" align="center">
<template slot-scope="scope">
<el-tag size="small" type="success" v-if="scope.row.initStatus===1">已初始化</el-tag>
<el-tag size="small" type="info" v-else>未初始化</el-tag>
</template>
</el-table-column>
<el-table-column label="启用" width="70" align="center">
<template slot-scope="scope">
<el-switch v-model="scope.row.enable" active-value="1" inactive-value="0" @change="handleEnableChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
<el-table-column label="操作" fixed="right" width="260" align="center">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-user" @click="handleUserAuth(scope.row)" v-hasPermi="['platform:userAuth:list']">用户</el-button>
<el-button size="mini" type="text" icon="el-icon-s-operation" @click="handleInterface(scope.row)" v-hasPermi="['platform:interface:list']">接口</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['platform:instance:edit']">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['platform:instance:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 新增/编辑弹窗 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="平台名称" prop="name">
<el-input v-model="form.name" placeholder="如:DCP结构监测" />
</el-form-item>
<el-form-item label="平台标识" prop="code">
<el-input v-model="form.code" placeholder="如:dcp(唯一,不可重复)" :disabled="form.id!=null" />
</el-form-item>
<el-form-item label="baseURL" prop="baseUrl">
<el-input v-model="form.baseUrl" placeholder="如:http://47.108.182.132:8200" />
</el-form-item>
<el-form-item label="认证类型" prop="authType">
<el-select v-model="form.authType" style="width:100%">
<el-option :value="1" label="密码Token(POST /connect/token)" />
<el-option :value="2" label="ApiKey(Header)" />
<el-option :value="3" label="OAuth2" />
</el-select>
</el-form-item>
<!-- 密码Token认证配置 -->
<template v-if="form.authType===1">
<el-form-item label="用户名">
<el-input v-model="authConfigParsed.userName" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="authConfigParsed.password" type="password" show-password />
</el-form-item>
<el-form-item label="clientId">
<el-input v-model="authConfigParsed.clientId" placeholder="如:DACP_App" />
</el-form-item>
<el-form-item label="scope">
<el-input v-model="authConfigParsed.scope" placeholder="如:DACP" />
</el-form-item>
</template>
<!-- ApiKey认证配置 -->
<template v-if="form.authType===2">
<el-form-item label="Header名称">
<el-input v-model="authConfigParsed.headerName" placeholder="如:X-Api-Key" />
</el-form-item>
<el-form-item label="ApiKey值">
<el-input v-model="authConfigParsed.apiKey" type="password" show-password />
</el-form-item>
</template>
<el-divider content-position="left">平台参数</el-divider>
<div class="schema-tip" style="margin-bottom:8px">
这里维护平台运行所需的业务参数,例如站点编码等;初始化流程写回的值也会保存在这里,可直接前端补录或修改。
</div>
<key-value-editor
v-model="platformConfigRows"
add-text="添加平台参数"
:show-enabled="false"
:show-description="true"
key-placeholder="参数名"
value-placeholder="参数值"
/>
<el-form-item label="启用">
<el-switch v-model="form.enable" active-value="1" inactive-value="0" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="submitForm" :loading="submitLoading">确定</el-button>
</div>
</el-dialog>
<!-- 接口管理抽屉 -->
<interface-drawer ref="interfaceDrawer" :platform-id="currentPlatformId" :platform-name="currentPlatformName" />
<!-- 用户管理弹窗 -->
<el-dialog title="用户认证管理" :visible.sync="userAuthOpen" width="1000px" append-to-body :close-on-click-modal="false">
<div style="margin-bottom:12px">
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAddUserAuth" v-hasPermi="['platform:userAuth:add']">新增用户</el-button>
</div>
<el-table v-loading="userAuthLoading" :data="userAuthList" border>
<el-table-column label="用户ID" prop="platformUserId" min-width="220">
<template slot-scope="scope">
<span v-if="scope.row.platformUserId">{{ scope.row.platformUserId }}</span>
<span v-else style="color:#909399">待初始化</span>
</template>
</el-table-column>
<el-table-column label="用户名" prop="platformUserName" min-width="120">
<template slot-scope="scope">
<span v-if="scope.row.platformUserName">{{ scope.row.platformUserName }}</span>
<span v-else style="color:#909399">-</span>
</template>
</el-table-column>
<el-table-column label="Token状态" width="100" align="center">
<template slot-scope="scope">
<el-tag size="small" type="success" v-if="userAuthTokenValid(scope.row)">有效</el-tag>
<el-tag size="small" type="danger" v-else-if="scope.row.tokenExpiresAt">已过期</el-tag>
<el-tag size="small" type="info" v-else>未认证</el-tag>
</template>
</el-table-column>
<el-table-column label="初始化" width="90" align="center">
<template slot-scope="scope">
<el-tag size="small" type="success" v-if="scope.row.initStatus===1">已初始化</el-tag>
<el-tag size="small" type="info" v-else>未初始化</el-tag>
</template>
</el-table-column>
<el-table-column label="启用" width="70" align="center">
<template slot-scope="scope">
<el-switch v-model="scope.row.enable" active-value="1" inactive-value="0" @change="handleUserAuthEnableChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="handleInitializeUserAuth(scope.row)" v-hasPermi="['platform:userAuth:initialize']"
:disabled="scope.row.initStatus===1">初始化</el-button>
<el-button size="mini" type="text" @click="handleEditUserAuth(scope.row)" v-hasPermi="['platform:userAuth:edit']">编辑</el-button>
<el-button size="mini" type="text" @click="handleDeleteUserAuth(scope.row)" v-hasPermi="['platform:userAuth:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 新增/编辑用户弹窗 -->
<el-dialog :title="userFormTitle" :visible.sync="userFormOpen" width="550px" append-to-body :close-on-click-modal="false">
<el-form ref="userForm" :model="userForm" label-width="100px">
<!-- 编辑时显示用户ID和用户名(只读,由初始化流程填充) -->
<template v-if="userForm.id">
<el-form-item label="用户ID">
<el-input v-model="userForm.platformUserId" disabled />
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="userForm.platformUserName" disabled />
</el-form-item>
</template>
<el-divider content-position="left">认证配置</el-divider>
<el-form-item label="用户名(认证)">
<el-input v-model="userAuthConfigParsed.userName" />
</el-form-item>
<el-form-item label="密码(认证)">
<el-input v-model="userAuthConfigParsed.password" type="password" show-password />
</el-form-item>
<el-form-item label="clientId">
<el-input v-model="userAuthConfigParsed.clientId" placeholder="如:DACP_App" />
</el-form-item>
<el-form-item label="scope">
<el-input v-model="userAuthConfigParsed.scope" placeholder="如:DACP" />
</el-form-item>
<el-form-item label="启用">
<el-switch v-model="userForm.enable" active-value="1" inactive-value="0" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="userForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="userFormOpen = false">取消</el-button>
<el-button type="primary" @click="submitUserForm" :loading="userFormLoading">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listPlatformInstance, getPlatformInstance, addPlatformInstance, updatePlatformInstance, delPlatformInstance } from '@/api/platform/instance'
import { listPlatformUserAuth, getPlatformUserAuth, addPlatformUserAuth, updatePlatformUserAuth, delPlatformUserAuth, initializeUserAuth } from '@/api/platform/userAuth'
import InterfaceDrawer from '../components/InterfaceDrawer'
import KeyValueEditor from '../components/KeyValueEditor'
export default {
name: 'PlatformInstance',
components: { InterfaceDrawer, KeyValueEditor },
data() {
return {
loading: false,
submitLoading: false,
showSearch: true,
multiple: true,
total: 0,
list: [],
open: false,
title: '',
currentPlatformId: null,
currentPlatformName: '',
queryParams: { pageNum: 1, pageSize: 10, name: '', enable: '' },
form: { authType: 1, enable: '1' },
authConfigParsed: { userName: '', password: '', clientId: '', scope: '' },
platformConfigRows: [],
rules: {
name: [{ required: true, message: '请输入平台名称', trigger: 'blur' }],
code: [{ required: true, message: '请输入平台标识', trigger: 'blur' }],
baseUrl: [{ required: true, message: '请输入baseURL', trigger: 'blur' }],
authType:[{ required: true, message: '请选择认证类型', trigger: 'change' }]
},
// 用户管理
userAuthOpen: false,
userAuthLoading: false,
userAuthList: [],
userFormOpen: false,
userFormTitle: '',
userFormLoading: false,
userForm: { platformId: null, enable: '1' },
userAuthConfigParsed: { userName: '', password: '', clientId: '', scope: '' }
}
},
created() { this.getList() },
methods: {
getList() {
this.loading = true
listPlatformInstance(this.queryParams).then(res => {
this.list = res.rows
this.total = res.total
this.loading = false
})
},
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
resetQuery() { this.resetForm('queryForm'); this.handleQuery() },
handleSelectionChange(sel) { this.multiple = sel.length !== 1 },
handleAdd() {
this.form = { authType: 1, enable: '1' }
this.authConfigParsed = { userName: '', password: '', clientId: '', scope: '' }
this.platformConfigRows = []
this.title = '新增平台'
this.open = true
},
handleUpdate(row) {
getPlatformInstance(row.id).then(res => {
this.form = res.data
this.authConfigParsed = this.form.authConfig ? JSON.parse(this.form.authConfig) : {}
this.platformConfigRows = this.parseObjectRows(this.form.extraConfig)
this.title = '编辑平台'
this.open = true
})
},
handleDelete(row) {
const ids = row.id ? [row.id] : this.ids
this.$confirm('确认删除?').then(() => {
delPlatformInstance(ids.join(',')).then(() => { this.getList(); this.$modal.msgSuccess('删除成功') })
})
},
handleEnableChange(row) {
updatePlatformInstance({ id: row.id, enable: row.enable }).then(() => {
this.$modal.msgSuccess(row.enable === '1' ? '已启用' : '已禁用')
})
},
handleInterface(row) {
this.currentPlatformId = row.id
this.currentPlatformName = row.name
this.$nextTick(() => { this.$refs.interfaceDrawer.open() })
},
// 用户管理
handleUserAuth(row) {
this.currentPlatformId = row.id
this.currentPlatformName = row.name
this.userAuthOpen = true
this.loadUserAuthList()
},
loadUserAuthList() {
this.userAuthLoading = true
listPlatformUserAuth({ platformId: this.currentPlatformId }).then(res => {
this.userAuthList = res.rows || []
this.userAuthLoading = false
}).catch(() => { this.userAuthLoading = false })
},
userAuthTokenValid(row) {
if (!row.tokenExpiresAt) return false
return new Date(row.tokenExpiresAt).getTime() > Date.now() + 5 * 60 * 1000
},
handleAddUserAuth() {
this.userForm = { platformId: this.currentPlatformId, enable: '1' }
this.userAuthConfigParsed = { userName: '', password: '', clientId: '', scope: '' }
this.userFormTitle = '新增用户认证'
this.userFormOpen = true
},
handleEditUserAuth(row) {
getPlatformUserAuth(row.id).then(res => {
this.userForm = res.data
this.userAuthConfigParsed = this.userForm.authConfig ? JSON.parse(this.userForm.authConfig) : {}
this.userFormTitle = '编辑用户认证'
this.userFormOpen = true
})
},
handleDeleteUserAuth(row) {
this.$confirm('确认删除该用户认证?').then(() => {
delPlatformUserAuth(row.id).then(() => {
this.$modal.msgSuccess('删除成功')
this.loadUserAuthList()
})
})
},
handleUserAuthEnableChange(row) {
updatePlatformUserAuth({ id: row.id, enable: row.enable }).then(() => {
this.$modal.msgSuccess(row.enable === '1' ? '已启用' : '已禁用')
})
},
handleInitializeUserAuth(row) {
this.$confirm(`确认初始化用户【${row.platformUserName || row.platformUserId}】?将执行初始化流程获取 userId。`).then(() => {
initializeUserAuth(row.id).then(() => {
this.$modal.msgSuccess('初始化成功')
this.loadUserAuthList()
})
})
},
submitUserForm() {
this.$refs.userForm.validate(valid => {
if (!valid) return
this.userForm.authConfig = JSON.stringify(this.userAuthConfigParsed)
this.userFormLoading = true
const api = this.userForm.id ? updatePlatformUserAuth : addPlatformUserAuth
api(this.userForm).then(() => {
this.$modal.msgSuccess(this.userForm.id ? '修改成功' : '新增成功')
this.userFormOpen = false
this.loadUserAuthList()
}).finally(() => { this.userFormLoading = false })
})
},
parseObjectRows(value) {
if (!value) return []
try {
const parsed = JSON.parse(value)
return Object.keys(parsed).filter(key => !['projectId', 'projectName'].includes(key)).map(key => ({
key,
value: parsed[key] == null ? '' : String(parsed[key]),
description: ''
}))
} catch (e) {
return []
}
},
buildObjectJson(rows) {
const result = {}
;(rows || []).forEach(item => {
if (!item || !item.key || ['projectId', 'projectName'].includes(item.key)) return
result[item.key] = item.value
})
return Object.keys(result).length > 0 ? JSON.stringify(result) : null
},
cancel() { this.open = false },
submitForm() {
this.$refs.form.validate(valid => {
if (!valid) return
this.form.authTemplate = JSON.stringify(this.authConfigParsed)
this.form.extraConfig = this.buildObjectJson(this.platformConfigRows)
this.submitLoading = true
const api = this.form.id ? updatePlatformInstance : addPlatformInstance
api(this.form).then(() => {
this.$modal.msgSuccess(this.form.id ? '修改成功' : '新增成功')
this.open = false
this.getList()
}).finally(() => { this.submitLoading = false })
})
}
}
}
</script>
<style scoped>
.schema-tip {
font-size: 12px;
color: #909399;
line-height: 1.6;
}
</style>