Parcourir la source

模型详细界面

liyangwenqi il y a 5 mois
Parent
commit
24cfeee8d2
3 fichiers modifiés avec 481 ajouts et 3 suppressions
  1. 7 1
      src/router/index.ts
  2. 472 0
      src/views/modeldetailed/index.vue
  3. 2 2
      src/views/system/user/index.vue

+ 7 - 1
src/router/index.ts

@@ -90,7 +90,13 @@ export const constantRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/dashboard/index.vue'),
         name:'Dashboard',
         meta: {title: '仪表盘', icon: 'dashboard', affix: true}
-      }
+      },
+        {
+            path: '/modeldetailed',
+            component: () => import('@/views/modeldetailed/index.vue'),
+            name:'ModelDetailed',
+            meta: {title: '模型详细', icon: 'dashboard', affix: true}
+        }
     ]
   },
   {

+ 472 - 0
src/views/modeldetailed/index.vue

@@ -0,0 +1,472 @@
+<template>
+    <div class="model-detail-root">
+        <!-- 面包屑导航 -->
+        <el-breadcrumb separator="/" class="model-breadcrumb">
+            <el-breadcrumb-item>市场模型</el-breadcrumb-item>
+            <el-breadcrumb-item>模型详情</el-breadcrumb-item>
+        </el-breadcrumb>
+        <div class="model-top-right-btns">
+            <el-button type="plain" size="small" class="custom-button">
+                <el-icon><Refresh /></el-icon>
+                刷新
+            </el-button>
+            <el-button type="primary" size="small" class="custom-button">
+                <el-icon><Edit /></el-icon>
+                编辑
+            </el-button>
+            <el-button type="danger" size="small" class="custom-button">
+                <el-icon><SwitchButton /></el-icon>
+                禁用
+            </el-button>
+        </div>
+
+        <!-- 顶部信息区(单卡片,左右分布) -->
+        <el-card class="model-top-card" shadow="never">
+            <div class="model-top-flex">
+                <!-- 左侧基本信息 -->
+                <div class="model-top-left">
+                    <div class="model-top-title">基本信息</div>
+                    <div class="model-top-row">
+                        <span class="model-top-label">模型名称:</span>
+                        <span class="model-top-value">GPT-4</span>
+                    </div>
+                    <div class="model-top-row">
+                        <span class="model-top-label">模型类型:</span>
+                        <span class="model-top-value">大语言模型(LLM)</span>
+                    </div>
+                    <div class="model-top-row">
+                        <span class="model-top-label">模型版本:</span>
+                        <span class="model-top-value">gpt-4-1106-preview</span>
+                    </div>
+                    <div class="model-top-row">
+                        <span class="model-top-label">状态:</span>
+                        <el-tag type="success" size="small">启用</el-tag>
+                    </div>
+                    <div class="model-top-row">
+                        <span class="model-top-label">API地址:</span>
+                        <a class="model-top-link" href="https://api.openai.com/v1/chat/completions" target="_blank">https://api.openai.com/v1/chat/completions</a>
+                    </div>
+                    <div class="model-top-row">
+                        <span class="model-top-label">描述:</span>
+                        <span class="model-top-value">GPT-4是OpenAI最先进的大型语言模型,在各种专业和学术基准上表现最佳。相比GPT-3.5,GPT-4在创造性写作、编码和解决复杂问题方面表现出显著提升,能更好地遵循用户意图,理解和生成更长的内容。</span>
+                    </div>
+                </div>
+                <!-- 右侧服务信息和按钮 -->
+                <div class="model-top-right">
+                    <div class="model-top-right-info">
+                        <div><span class="model-top-label">服务商:</span>&nbsp&nbspOpenAI</div>
+                        <div><span class="model-top-label">优先级:</span>&nbsp&nbsp90</div>
+                        <div><span class="model-top-label">创建时间:</span>&nbsp&nbsp2025-05-15 10:30:15</div>
+                        <div><span class="model-top-label">更新时间:</span>&nbsp&nbsp2025-06-20 14:45:30</div>
+                    </div>
+
+                </div>
+            </div>
+        </el-card>
+
+        <!-- 参数配置 -->
+        <el-card class="model-section-card">
+            <div class="model-section-title">
+                <span>参数配置</span>
+                <el-button type="primary" size="small" class="model-btn-add">+ 添加参数</el-button>
+            </div>
+            <el-table :data="tableData" class="model-param-table" border header-cell-class-name="model-th" cell-class-name="model-td">
+                <el-table-column prop="name" label="参数名称" align="center" min-width="120" />
+                <el-table-column prop="type" label="参数类型" align="center" min-width="120" />
+                <el-table-column prop="defaultValue" label="默认值" align="center" min-width="100" />
+                <el-table-column prop="isRequired" label="是否必需" align="center" min-width="100" />
+                <el-table-column prop="description" label="描述" min-width="200" />
+                <el-table-column label="操作" align="center" min-width="100">
+                    <template #default="scope">
+                        <el-button @click="handleEdit(scope.$index, scope.row)" type="text" size="small">编辑</el-button>
+                        <el-button @click="handleDelete(scope.$index, scope.row)" type="text" size="small">删除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </el-card>
+        <!-- 抽屉 -->
+        <el-drawer
+            title="编辑参数"
+            v-model="drawerVisible"
+            direction="rtl"
+            size="20%"
+    >
+          <el-divider style="margin: 1px 0;" />
+          <div >
+            <h3>模型</h3>
+            <el-card class="model-card" style=" background:#F5F5F5;">
+              GPT-4 (OpenAI)<br/>
+              <span style="color: #777777">版本: gpt-4-1106-preview</span>
+            </el-card>
+
+            <h3 style="color: #777777">快速添加参数模板</h3>
+
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-card class="center-content" style="height: 150px;background: #FAFAFA" >
+                 <div>OpenAI Chat模板</div>
+                  <div style="color: #777777">6个参数</div>
+                </el-card>
+              </el-col>
+
+              <el-col :span="12">
+                <el-card class="center-content"style="background: #FAFAFA">
+                  <div>OpenAI Embedding模板</div>
+                  <div style="color: #777777">三个参数</div>
+                </el-card>
+              </el-col>
+            </el-row>
+
+            <h3>参数列表</h3>
+            <div v-for="(item, index) in tableData" :key="index" class="parameter-card">
+              <el-card shadow="never" style="background-color: #FAFAFA" >
+                <div class="card-content">
+                  <div class="param-name">{{ item.name }} <span style="color: #777777">{{item.type}}</span></div>
+                  <div class="actions" style="display: flex">
+                    <el-button @click="handleEdit(index, item)" type="text" size="small" ></el-button>
+                    <el-button @click="handleDelete(index, item)" type="text" size="small"style="margin-left:auto" ><el-icon color="red"><DeleteFilled /></el-icon></el-button>
+                  </div>
+                </div>
+              </el-card>
+            </div>
+            <el-card style="display: flex;justify-content: center; align-items: center; flex-direction: column;" :body-style="{padding:'1px'}">
+              <el-button @click="addParameter" type="plain" >添加参数</el-button>
+            </el-card>
+
+
+            <div style="text-align: right; margin-top: 20px;">
+              <el-button @click="drawerVisible = false">取消</el-button>
+              <el-button @click="saveEdit" type="primary">保存</el-button>
+            </div>
+          </div>
+
+    </el-drawer>
+
+        <!-- 调用统计 -->
+        <el-row :gutter="20" class="model-stat-row">
+            <el-col :span="6" v-for="(item, idx) in statList" :key="item.label">
+                <el-card class="model-stat-card" shadow="never">
+                    <div class="model-stat-label">{{ item.label }}</div>
+                    <div class="model-stat-value">{{ item.value }}</div>
+                    <div :class="['model-stat-trend', item.trend > 0 ? 'up' : 'down']">
+                        <span v-if="item.trend > 0">↑ {{ item.trend }}% 较上月</span>
+                        <span v-else>↓ {{ Math.abs(item.trend) }}% 较上月</span>
+                    </div>
+                </el-card>
+            </el-col>
+            <div class="model-stat-select">
+                <el-select v-model="statRange" size="small" style="width: 80px">
+                    <el-option label="本月" value="month" />
+                    <el-option label="本年" value="year" />
+                </el-select>
+            </div>
+        </el-row>
+
+        <!-- 调用趋势 -->
+        <el-card class="model-section-card model-chart-section">
+            <div class="model-chart-title">调用趋势</div>
+            <div id="callTrendChart" style="width: 100%; height: 320px;"></div>
+            <div class="model-chart-footer">调用趋势曲线数据</div>
+        </el-card>
+    </div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+import {Refresh} from "@element-plus/icons-vue";
+export default {
+    components: {Refresh},
+    data() {
+        return {
+            tableData: [
+                { name: 'temperature', type: 'NUMBER', defaultValue: '0.7', isRequired: '否', description: '控制生成文本的随机性,值越小结果越随机' },
+                { name: 'max_tokens', type: 'NUMBER', defaultValue: '1024', isRequired: '否', description: '生成文本的最大令牌数' },
+                { name: 'top_p', type: 'NUMBER', defaultValue: '0.95', isRequired: '否', description: '核采样阈值,控制模型选择词的概率分布' },
+                { name: 'frequency_penalty', type: 'NUMBER', defaultValue: '0', isRequired: '否', description: '减少重复词组的出现概率' },
+                { name: 'presence_penalty', type: 'NUMBER', defaultValue: '0', isRequired: '否', description: '增加新话题出现的概率' },
+                { name: 'stream', type: 'BOOLEAN', defaultValue: 'false', isRequired: '否', description: '是否启用流式输出' }
+            ],
+            statList: [
+                { label: '调用次数', value: '156,783', trend: 12.5 },
+                { label: '平均响应时间', value: '1.68s', trend: -0.2 },
+                { label: '成功率', value: '99.87%', trend: 0.05 },
+                { label: 'Token消耗', value: '5.6M', trend: 18.3 }
+            ],
+            statRange: 'month',
+            drawerVisible: false,
+            currentRow: {},       // 当前编辑的行数据
+            currentRowIndex: -1
+        }
+    },
+ // 当前编辑的行索引
+    mounted() {
+        this.initCallTrendChart();
+    },
+    methods: {
+        handleEdit(index, row) {
+            this.currentRowIndex = index
+            this.currentRow = { ...row }  // 拷贝一份数据,避免直接修改原数据
+            this.drawerVisible = true
+        },
+        handleDelete(index, row) {
+            this.tableData.splice(index, 1)
+        },
+        saveEdit() {
+            this.$set(this.tableData, this.currentRowIndex, { ...this.currentRow })  // 替换数组中的对象
+            this.drawerVisible = false
+        },
+        initCallTrendChart() {
+            const callTrendChart = echarts.init(document.getElementById('callTrendChart'));
+            const option = {
+                tooltip: {},
+                xAxis: {
+                    type: 'category',
+                    data: ['1月', '2月', '3月', '4月', '5月', '6月'],
+                    axisLine: { lineStyle: { color: '#e5e6eb' } },
+                    axisLabel: { color: '#888' },
+                },
+                yAxis: {
+                    type: 'value',
+                    axisLine: { lineStyle: { color: '#e5e6eb' } },
+                    splitLine: { lineStyle: { color: '#f0f0f0' } },
+                    axisLabel: { color: '#888' },
+                },
+                series: [
+                    {
+                        data: [120, 200, 150, 80, 70, 110],
+                        type: 'bar',
+                        name: '调用次数',
+                        itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] },
+                        barWidth: 24,
+                    },
+                ],
+                grid: { left: 40, right: 20, top: 30, bottom: 30 },
+            }
+            callTrendChart.setOption(option);
+        }
+    }
+}
+</script>
+
+<style scoped>
+.actions{
+  display: flex;
+}
+
+
+/* 确保图标靠右对齐 */
+
+.parameter-card {
+  margin-bottom: 0;
+}
+
+.card-content {
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+}
+
+.param-name {
+  font-size: 14px;
+  color: #606266;
+}
+.center-content {
+
+  display: flex;
+  justify-content: center; /* 水平居中 */
+  align-items: center; /* 垂直居中 */
+  height: 100%; /* 确保容器有足够的高度 */
+}
+.model-detail-root {
+    background: #f7f8fa;
+    min-height: 100vh;
+    padding: 0 24px 24px 24px;
+}
+.model-breadcrumb {
+    margin: 18px 0 8px 0;
+}
+.model-top-card {
+    border-radius: 10px;
+    border: 1px solid #e5e6eb;
+    background: #fff;
+    box-shadow: none;
+    padding: 0 32px 0 32px;
+    margin-bottom: 24px;
+}
+.model-top-flex {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: flex-start;
+    min-height: 160px;
+    padding: 24px 0 18px 0;
+}
+.model-top-left {
+    flex: 1.5;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+}
+.model-top-title {
+    font-size: 16px;
+    font-weight: 600;
+    margin-bottom: 12px;
+}
+.model-top-row {
+    display: flex;
+    align-items: center;
+    font-size: 13px;
+    margin-bottom: 4px;
+    gap: 8px;
+}
+.model-top-label {
+    color: #888;
+    min-width: 80px;
+    margin-right: 2px;
+}
+.model-top-value {
+    color: #222;
+    margin-right: 24px;
+    word-break: break-all;
+}
+.model-top-link {
+    color: #409eff;
+    text-decoration: underline;
+}
+.model-top-right {
+    flex: 1;
+    display: flex;
+    flex-direction: row;
+    align-items: flex-start;
+    justify-content: space-between;
+    min-width: 360px;
+    margin-left: 32px;
+    margin-right: 32px;
+    gap: 32px;
+}
+.model-top-right-info {
+    color: #222;
+    font-size: 13px;
+    margin-bottom: 0;
+    text-align: left;
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    justify-content: center;
+    flex: 1;
+    min-width: 180px;
+}
+.model-top-right-btns {
+    display: flex;
+    flex-direction: row;
+    gap:0.1px;
+    margin-top: 0;
+    align-items: flex-start;
+    justify-content: flex-end;
+}
+.model-section-card {
+    border-radius: 10px;
+    border: 1px solid #e5e6eb;
+    background: #fff;
+    box-shadow: none;
+    margin-top: 24px;
+    padding: 0 0 18px 0;
+}
+.model-section-title {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0 24px;
+    font-size: 15px;
+    font-weight: 500;
+    height: 48px;
+    background: #fff;
+    border-bottom: 1px solid #f0f0f0;
+}
+.model-btn-add {
+    min-width: 90px;
+    margin-top: 0;
+    align-self: flex-start;
+}
+.model-param-table {
+    margin: 0 24px 0 24px;
+    font-size: 13px;
+    --el-table-border-color: #e5e6eb;
+    --el-table-header-bg-color: #f7f8fa;
+    --el-table-header-text-color: #888;
+    --el-table-row-hover-bg-color: #f5f7fa;
+}
+.model-th {
+    background: #f7f8fa !important;
+    color: #888 !important;
+    font-weight: 500 !important;
+    height: 38px !important;
+}
+.model-td {
+    height: 38px !important;
+    padding: 0 8px !important;
+}
+.model-stat-row {
+    margin-top: 24px;
+    margin-bottom: 0;
+    position: relative;
+}
+.model-stat-card {
+    border-radius: 10px;
+    border: 1px solid #e5e6eb;
+    background: #fff;
+    box-shadow: none;
+    min-height: 100px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: flex-start;
+    padding: 18px 0 12px 24px;
+}
+.model-stat-label {
+    color: #888;
+    font-size: 13px;
+    margin-bottom: 2px;
+}
+.model-stat-value {
+    font-size: 22px;
+    font-weight: 600;
+    color: #222;
+    margin: 2px 0 2px 0;
+}
+.model-stat-trend {
+    font-size: 12px;
+    margin-top: 2px;
+}
+.model-stat-trend.up {
+    color: #67c23a;
+}
+.model-stat-trend.down {
+    color: #f56c6c;
+}
+.model-stat-select {
+    position: absolute;
+    right: 24px;
+    top: 0;
+}
+.model-chart-section {
+    margin-top: 24px;
+    padding: 0 0 18px 0;
+}
+.model-chart-title {
+    font-size: 15px;
+    font-weight: 500;
+    color: #222;
+    margin-bottom: 8px;
+    padding-left: 24px;
+    padding-top: 18px;
+}
+.model-chart-footer {
+    color: #bfbfbf;
+    font-size: 12px;
+    text-align: right;
+    margin-top: 8px;
+    padding-right: 24px;
+}
+
+</style>

+ 2 - 2
src/views/system/user/index.vue

@@ -170,8 +170,8 @@
         </el-row>
         <el-row>
           <el-col :span="12">
-            <el-form-item label="手机号码" prop="phonenumber">
-              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+            label="手机号码" prop="phonenumber">
+              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxleng <el-form-itemth="11" />
             </el-form-item>
           </el-col>
           <el-col :span="12">