| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- <template>
- <el-dialog
- v-model="dialogVisible"
- :title="isEdit ? '编辑模型配置' : '新增模型配置'"
- width="800px"
- :close-on-click-modal="false"
- :destroy-on-close="true"
- >
- <!-- 步骤导航 -->
- <div class="step-header">
- <div
- v-for="(step, index) in steps"
- :key="index"
- class="step-item"
- :class="{ active: currentStep === index + 1, completed: stepsCompleted[index] }"
- >
- <span class="step-number">{{ index + 1 }}</span>
- <span class="step-title">{{ step }}</span>
- </div>
- </div>
- <!-- 步骤内容 -->
- <el-form
- ref="formRef"
- :model="form"
- label-width="120px"
- style="margin-top: 20px"
- >
- <!-- 第一步:选择模型 -->
- <div v-if="currentStep === 1">
- <el-form-item label="选择模型服务商">
- <el-radio-group v-model="form.step1.selectedVendor">
- <el-radio v-for="vendor in vendors" :key="vendor.id" :label="vendor.id">
- {{ vendor.name }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="选择模型" prop="selectedModel">
- <el-select
- v-model="form.step1.selectedModel"
- placeholder="请选择模型"
- @change="onModelSelected"
- >
- <el-option
- v-for="model in modelsList"
- :key="model.id"
- :label="model.name"
- :value="model.id"
- />
- </el-select>
- </el-form-item>
- </div>
- <!-- 第二步:基本配置 -->
- <div v-if="currentStep === 2">
- <el-form-item label="模型名称" prop="modelName">
- <el-input v-model="form.step2.modelName" placeholder="请输入模型名称,如:OPENAI" />
- <p class="form-tip">给模型起一个易于识别的名字,便于在企业内部使用</p>
- </el-form-item>
- <el-form-item label="模型版本" prop="modelVersion">
- <el-input v-model="form.step2.modelVersion" placeholder="请输入模型版本" />
- <p class="form-tip">API调用时使用的模型版本标识符</p>
- </el-form-item>
- <el-form-item label="环境" prop="env">
- <el-select v-model="form.step2.env" placeholder="请选择环境">
- <el-option label="生产" value="PROD" />
- <el-option label="测试" value="TEST" />
- <el-option label="开发" value="DEV" />
- </el-select>
- </el-form-item>
- <el-form-item label="API基础地址" prop="apiBaseURL">
- <el-input v-model="form.step2.apiBaseURL" placeholder="默认使用服务商的API基础地址,可自定义" />
- </el-form-item>
- <el-form-item label="API密钥" prop="apiKey">
- <el-input v-model="form.step2.apiKey" placeholder="API安全密钥将使用安全算法进行加密存储" />
- </el-form-item>
- <el-form-item label="优先级" prop="priority">
- <el-input-number
- v-model="form.step2.priority"
- :min="0"
- :max="100"
- controls-position="right"
- />
- <p class="form-tip">数值越大优先级越高,范围0-100</p>
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-switch v-model="form.step2.status" />
- <p class="form-tip" :class="{ 'text-gray': !form.step2.status }">
- {{ form.step2.status ? '启用' : '禁用' }}
- </p>
- </el-form-item>
- <el-form-item label="描述" prop="description">
- <el-input
- v-model="form.step2.description"
- type="textarea"
- :rows="3"
- placeholder="请输入模型描述"
- />
- </el-form-item>
- </div>
- <!-- 第三步:参数设置 -->
- <div v-if="currentStep === 3">
- <el-form-item label="快速添加参数模板">
- <el-select v-model="form.step3.selectedTemplate" placeholder="请选择模板" @change="addTemplateParams">
- <el-option
- v-for="template in parameterTemplates"
- :key="template.id"
- :label="template.name"
- :value="template.id"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="参数列表">
- <el-table :data="form.step3.parameters" border style="width: 100%">
- <el-table-column prop="name" label="参数名" />
- <el-table-column prop="value" label="参数值">
- <template #default="scope">
- <el-input v-model="scope.row.value" />
- </template>
- </el-table-column>
- <el-table-column label="操作">
- <template #default="scope">
- <el-button
- size="small"
- type="danger"
- @click="deleteParameter(scope.$index)"
- >
- 删除
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-form-item>
- </div>
- </el-form>
- <!-- 操作按钮 -->
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="prevStep" v-if="currentStep > 1">上一步</el-button>
- <el-button @click="cancelDialog">取消</el-button>
- <el-button
- type="primary"
- @click="nextStep"
- v-if="currentStep < 3"
- >
- 下一步
- </el-button>
- <el-button
- type="success"
- @click="submitForm"
- v-if="currentStep === 3"
- >
- 保存
- </el-button>
- </div>
- </template>
- </el-dialog>
- </template>
- <script setup>
- import { ref, reactive, watch, defineEmits, defineProps } from 'vue'
- import { ElMessage } from 'element-plus'
- const props = defineProps(['model'])
- const emit = defineEmits(['success'])
- // 弹窗控制
- const dialogVisible = ref(false)
- const currentStep = ref(1)
- const stepsCompleted = ref([false, false, false])
- const isEdit = ref(false)
- // 表单数据
- const formRef = ref()
- const form = reactive({
- step1: {
- selectedVendor: '',
- selectedModel: ''
- },
- step2: {
- modelName: '',
- modelVersion: '',
- env: '',
- apiBaseURL: '',
- apiKey: '',
- priority: 0,
- status: true,
- description: ''
- },
- step3: {
- selectedTemplate: '',
- parameters: []
- }
- })
- // 表单规则
- const rules = {
- selectedModel: [{ required: true, message: '请选择模型', trigger: 'change' }],
- modelName: [{ required: true, message: '请输入模型名称', trigger: 'blur' }],
- modelVersion: [{ required: true, message: '请输入模型版本', trigger: 'blur' }],
- env: [{ required: true, message: '请选择环境', trigger: 'change' }],
- apiBaseURL: [{ required: true, message: '请输入API基础地址', trigger: 'blur' }],
- apiKey: [{ required: true, message: '请输入API密钥', trigger: 'blur' }],
- priority: [
- { required: true, message: '请输入优先级', trigger: 'blur' },
- { type: 'number', min: 0, max: 100, message: '优先级范围0-100', trigger: 'blur' }
- ]
- }
- // 模拟数据
- const vendors = ref([
- { id: 'v1', name: '阿里云' },
- { id: 'v2', name: '腾讯云' }
- ])
- const modelsList = ref([
- { id: 'm1', name: 'Qwen-Plus' },
- { id: 'm2', name: 'Qwen-Max' }
- ])
- const parameterTemplates = ref([
- { id: 't1', name: '基础模板', parameters: [{ name: 'timeout', value: '60' }] },
- { id: 't2', name: '高级模板', parameters: [{ name: 'retries', value: '3' }] }
- ])
- // 方法
- const open = (row = null) => {
- dialogVisible.value = true
- isEdit.value = !!row
- if (row) {
- // 编辑模式初始化数据
- form.step1.selectedVendor = row.vendorId
- form.step1.selectedModel = row.modelId
- form.step2.modelName = row.modelName
- form.step2.modelVersion = row.modelVersion
- form.step2.env = row.env
- form.step2.apiBaseURL = row.apiBaseURL
- form.step2.apiKey = row.apiKey
- form.step2.priority = row.priority
- form.step2.status = row.status
- form.step2.description = row.description
- form.step3.parameters = row.parameters || []
- } else {
- resetForm()
- }
- }
- const onModelSelected = () => {
- stepsCompleted.value[0] = true
- }
- const nextStep = async () => {
- // const currentRules = getRulesForCurrentStep()
- // const isValid = await formRef.value.validate(currentRules)
- // if (!isValid) return
- currentStep.value++
- stepsCompleted.value[currentStep.value - 1] = true
- }
- const prevStep = () => {
- currentStep.value--
- }
- const cancelDialog = () => {
- dialogVisible.value = false
- resetForm()
- }
- const submitForm = async () => {
- const isValid = await formRef.value.validate()
- if (!isValid) return
- // 提交逻辑
- ElMessage.success('保存成功')
- dialogVisible.value = false
- emit('success')
- resetForm()
- }
- const addTemplateParams = () => {
- const template = parameterTemplates.value.find(t => t.id === form.step3.selectedTemplate)
- if (template) {
- form.step3.parameters.push(...template.parameters)
- }
- }
- const deleteParameter = (index) => {
- form.step3.parameters.splice(index, 1)
- }
- const resetForm = () => {
- currentStep.value = 1
- stepsCompleted.value = [false, false, false]
- formRef.value.resetFields()
- form.step1.selectedVendor = ''
- form.step1.selectedModel = ''
- form.step2.modelName = ''
- form.step2.modelVersion = ''
- form.step2.env = ''
- form.step2.apiBaseURL = ''
- form.step2.apiKey = ''
- form.step2.priority = 0
- form.step2.status = true
- form.step2.description = ''
- form.step3.selectedTemplate = ''
- form.step3.parameters = []
- }
- // 辅助函数
- const getRulesForCurrentStep = () => {
- const stepRules = {
- 1: { selectedModel: rules.selectedModel },
- 2: {
- modelName: rules.modelName,
- modelVersion: rules.modelVersion,
- env: rules.env,
- apiBaseURL: rules.apiBaseURL,
- apiKey: rules.apiKey,
- priority: rules.priority
- }
- }
- return stepRules[currentStep.value]
- }
- defineExpose({ open })
- </script>
- <style scoped>
- .step-header {
- display: flex;
- justify-content: space-between;
- margin-bottom: 20px;
- }
- .step-item {
- flex: 1;
- text-align: center;
- position: relative;
- padding-bottom: 10px;
- cursor: not-allowed;
- }
- .step-item.active, .step-item.completed {
- cursor: default;
- }
- .step-item.active .step-number {
- background-color: #409EFF;
- color: white;
- }
- .step-item.completed .step-number {
- background-color: #67C23A;
- color: white;
- }
- .step-number {
- display: inline-block;
- width: 24px;
- height: 24px;
- line-height: 24px;
- border-radius: 50%;
- background-color: #E4E7ED;
- margin-right: 8px;
- font-weight: bold;
- }
- .form-tip {
- margin-top: 4px;
- font-size: 12px;
- color: #999;
- }
- .text-gray {
- color: #999;
- }
- .dialog-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- </style>
|