mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	refactor: 完成管理后台的系统设置页面重构
This commit is contained in:
		@@ -137,8 +137,7 @@ func authorizeMiddleware(s *AppServer) gin.HandlerFunc {
 | 
			
		||||
		if c.Request.URL.Path == "/api/user/login" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/admin/login" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/user/register" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/apikey/add" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/apikey/list" {
 | 
			
		||||
			c.Request.URL.Path == "/api/config/get" {
 | 
			
		||||
			c.Next()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,4 @@ type SystemConfig struct {
 | 
			
		||||
	UserInitCalls int      `json:"user_init_calls"` // 新用户注册默认总送多少次调用
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var GptModels = []string{"gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-4", "gpt-4-0613", "gpt-4-32k", "gpt-4-32k-0613"}
 | 
			
		||||
 | 
			
		||||
const UserInitCalls = 1000
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
package handler
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"chatplus/core"
 | 
			
		||||
	"chatplus/core/types"
 | 
			
		||||
	"chatplus/handler"
 | 
			
		||||
	"chatplus/store/model"
 | 
			
		||||
	"chatplus/utils"
 | 
			
		||||
	"chatplus/utils/resp"
 | 
			
		||||
@@ -12,14 +13,14 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ConfigHandler struct {
 | 
			
		||||
	BaseHandler
 | 
			
		||||
	handler.BaseHandler
 | 
			
		||||
	db *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewConfigHandler(app *core.AppServer, db *gorm.DB) *ConfigHandler {
 | 
			
		||||
	handler := ConfigHandler{db: db}
 | 
			
		||||
	handler.App = app
 | 
			
		||||
	return &handler
 | 
			
		||||
	h := ConfigHandler{db: db}
 | 
			
		||||
	h.App = app
 | 
			
		||||
	return &h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *ConfigHandler) Update(c *gin.Context) {
 | 
			
		||||
@@ -71,8 +72,3 @@ func (h *ConfigHandler) Get(c *gin.Context) {
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllGptModels 获取所有的 GPT 模型
 | 
			
		||||
func (h *ConfigHandler) AllGptModels(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c, types.GptModels)
 | 
			
		||||
}
 | 
			
		||||
@@ -85,7 +85,7 @@ func main() {
 | 
			
		||||
		fx.Provide(handler.NewChatRoleHandler),
 | 
			
		||||
		fx.Provide(handler.NewUserHandler),
 | 
			
		||||
		fx.Provide(handler.NewChatHandler),
 | 
			
		||||
		fx.Provide(handler.NewConfigHandler),
 | 
			
		||||
		fx.Provide(admin.NewConfigHandler),
 | 
			
		||||
 | 
			
		||||
		fx.Provide(admin.NewAdminHandler),
 | 
			
		||||
		fx.Provide(admin.NewApiKeyHandler),
 | 
			
		||||
@@ -117,13 +117,13 @@ func main() {
 | 
			
		||||
			group.GET("tokens", h.Tokens)
 | 
			
		||||
			group.GET("stop", h.StopGenerate)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *handler.ConfigHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/config/")
 | 
			
		||||
 | 
			
		||||
		//
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.ConfigHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/config/")
 | 
			
		||||
			group.POST("update", h.Update)
 | 
			
		||||
			group.GET("get", h.Get)
 | 
			
		||||
			group.GET("models", h.AllGptModels)
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.ManagerHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/")
 | 
			
		||||
			group.POST("login", h.Login)
 | 
			
		||||
 
 | 
			
		||||
@@ -200,7 +200,8 @@ import {
 | 
			
		||||
  Close,
 | 
			
		||||
  Delete,
 | 
			
		||||
  Edit,
 | 
			
		||||
  Plus, Promotion,
 | 
			
		||||
  Plus,
 | 
			
		||||
  Promotion,
 | 
			
		||||
  RefreshRight,
 | 
			
		||||
  Search,
 | 
			
		||||
  Tools,
 | 
			
		||||
@@ -270,7 +271,7 @@ if (!user.value) {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 加载系统配置
 | 
			
		||||
  httpGet('/api/config/get?key=system').then(res => {
 | 
			
		||||
  httpGet('/api/admin/config/get?key=system').then(res => {
 | 
			
		||||
    title.value = res.data.title;
 | 
			
		||||
    models.value = res.data.models;
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
@@ -731,8 +732,10 @@ $borderColor = #4676d0;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
 | 
			
		||||
    // left side
 | 
			
		||||
 | 
			
		||||
    .el-aside {
 | 
			
		||||
      background-color: $sideBgColor;
 | 
			
		||||
 | 
			
		||||
      .title-box {
 | 
			
		||||
        padding: 6px 10px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
 
 | 
			
		||||
@@ -94,16 +94,15 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {computed, defineComponent, onMounted, ref} from 'vue'
 | 
			
		||||
import {computed, onMounted, ref} from 'vue'
 | 
			
		||||
import {Fold, Menu} from "@element-plus/icons-vue"
 | 
			
		||||
import XWelcome from "@/views/admin/Welcome.vue";
 | 
			
		||||
import SysConfig from "@/views/admin/SysConfig.vue";
 | 
			
		||||
import {arrayContains, removeArrayItem} from "@/utils/libs";
 | 
			
		||||
import UserList from "@/views/admin/UserList.vue";
 | 
			
		||||
import RoleList from "@/views/admin/RoleList.vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {setLoginUser} from "@/utils/storage";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
 | 
			
		||||
const title = ref('Chat-Plus 控制台')
 | 
			
		||||
@@ -118,7 +117,7 @@ const navs = ref([
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    id: 2,
 | 
			
		||||
    title: '口令管理',
 | 
			
		||||
    title: '用户管理',
 | 
			
		||||
    tab: 'user',
 | 
			
		||||
    active: false,
 | 
			
		||||
  },
 | 
			
		||||
@@ -129,20 +128,20 @@ const navs = ref([
 | 
			
		||||
    active: false,
 | 
			
		||||
  }
 | 
			
		||||
])
 | 
			
		||||
const tabs= ref([])
 | 
			
		||||
const tabs = ref([])
 | 
			
		||||
const curNav = ref(null)
 | 
			
		||||
const curTab = ref('welcome')
 | 
			
		||||
const winHeight = ref(window.innerHeight)
 | 
			
		||||
const showSidebar = ref(true)
 | 
			
		||||
 | 
			
		||||
const sideWidth = computed(() =>{
 | 
			
		||||
const sideWidth = computed(() => {
 | 
			
		||||
  return showSidebar.value ? 250 : 30
 | 
			
		||||
})
 | 
			
		||||
const foldIconRight = computed(() =>{
 | 
			
		||||
const foldIconRight = computed(() => {
 | 
			
		||||
  return showSidebar.value ? 3 : 0
 | 
			
		||||
})
 | 
			
		||||
const nodeListPaddingLeft = computed(() =>{
 | 
			
		||||
  return showSidebar.value ?  20 : 5
 | 
			
		||||
const nodeListPaddingLeft = computed(() => {
 | 
			
		||||
  return showSidebar.value ? 20 : 5
 | 
			
		||||
})
 | 
			
		||||
const router = useRouter()
 | 
			
		||||
 | 
			
		||||
@@ -151,8 +150,16 @@ onMounted(() => {
 | 
			
		||||
    winHeight.value = window.innerHeight
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // 获取会话信息
 | 
			
		||||
  httpGet("/api/admin/session").catch(() => {
 | 
			
		||||
   router.push('/admin/login')
 | 
			
		||||
    router.push('/admin/login')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // 加载系统配置
 | 
			
		||||
  httpGet('/api/admin/config/get?key=system').then(res => {
 | 
			
		||||
    title.value = res.data['admin_title'];
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("加载系统配置失败: " + e.message)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@@ -160,12 +167,12 @@ const logout = function () {
 | 
			
		||||
  httpGet("/api/admin/logout").then(() => {
 | 
			
		||||
    router.push('/admin/login')
 | 
			
		||||
  }).catch((e) => {
 | 
			
		||||
    ElMessage.error("注销失败: "+ e.message);
 | 
			
		||||
    ElMessage.error("注销失败: " + e.message);
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 添加 tab 窗口
 | 
			
		||||
const addTab= function (nav) {
 | 
			
		||||
const addTab = function (nav) {
 | 
			
		||||
  if (curNav.value) {
 | 
			
		||||
    curNav.value.active = false
 | 
			
		||||
  }
 | 
			
		||||
@@ -178,7 +185,7 @@ const addTab= function (nav) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 切换 tab 窗口
 | 
			
		||||
const changeTab= function (name) {
 | 
			
		||||
const changeTab = function (name) {
 | 
			
		||||
  for (let i = 0; i < navs.value.length; i++) {
 | 
			
		||||
    let _nav = navs.value[i]
 | 
			
		||||
    if (_nav.tab === name) {
 | 
			
		||||
@@ -191,7 +198,7 @@ const changeTab= function (name) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除 tab 窗口
 | 
			
		||||
const removeTab= function (name) {
 | 
			
		||||
const removeTab = function (name) {
 | 
			
		||||
  tabs.value = removeArrayItem(tabs.value, name);
 | 
			
		||||
  if (tabs.value.length === 0) {
 | 
			
		||||
    curTab.value = 'welcome';
 | 
			
		||||
@@ -286,6 +293,7 @@ $borderColor = #4676d0;
 | 
			
		||||
 | 
			
		||||
    .nav-footer {
 | 
			
		||||
      flex-direction column
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        padding 10px 20px;
 | 
			
		||||
        font-size 14px;
 | 
			
		||||
@@ -311,7 +319,6 @@ $borderColor = #4676d0;
 | 
			
		||||
  .el-main {
 | 
			
		||||
    --el-main-padding: 0;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    background-image url("~@/assets/img/bg_01.jpeg")
 | 
			
		||||
 | 
			
		||||
    .main-container {
 | 
			
		||||
      display: flex;
 | 
			
		||||
@@ -325,6 +332,10 @@ $borderColor = #4676d0;
 | 
			
		||||
          height 35px
 | 
			
		||||
          line-height 35px
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .el-tabs__content {
 | 
			
		||||
          padding 10px 20px 20px 20px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
@@ -332,5 +343,4 @@ $borderColor = #4676d0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,213 +1,183 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="system-config" v-loading="loading">
 | 
			
		||||
    <el-form :model="form" label-width="120px">
 | 
			
		||||
      <el-form-item label="应用标题">
 | 
			
		||||
        <el-input v-model="form['title']"/>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="控制台标题">
 | 
			
		||||
        <el-input v-model="form['console_title']"/>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="代理地址">
 | 
			
		||||
        <el-input v-model="form['proxy_url']" placeholder="多个地址之间用逗号隔开"/>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
 | 
			
		||||
      <el-form-item label="微信群聊二维码">
 | 
			
		||||
        <el-input v-model="form['img_url']['wechat_group']" placeholder="群聊二维码地址"/>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
 | 
			
		||||
      <el-form-item label="个人微信名片">
 | 
			
		||||
        <el-input v-model="form['img_url']['wechat_card']" placeholder="名片二维码地址"/>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
      <el-divider content-position="center">基本设置</el-divider>
 | 
			
		||||
      <el-form :model="system" label-width="120px" label-position="left" ref="systemFormRef" :rules="rules">
 | 
			
		||||
        <el-form-item label="网站标题" prop="title">
 | 
			
		||||
          <el-input v-model="system['title']"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="控制台标题" prop="admin_title">
 | 
			
		||||
          <el-input v-model="system['admin_title']"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="注册赠送次数" prop="init_calls">
 | 
			
		||||
          <el-input v-model.number="system['init_calls']" placeholder="新用户注册赠送对话次数"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-alert type="info" show-icon :closable="false">
 | 
			
		||||
          <p>在这里维护前端聊天页面可用的 GPT 模型列表</p>
 | 
			
		||||
        </el-alert>
 | 
			
		||||
        <el-form-item label="GPT 模型" prop="models">
 | 
			
		||||
          <div class="models">
 | 
			
		||||
            <el-tag
 | 
			
		||||
                v-for="item in system.models"
 | 
			
		||||
                :key="item"
 | 
			
		||||
                @close="removeModel(item)"
 | 
			
		||||
                round
 | 
			
		||||
                closable
 | 
			
		||||
            >
 | 
			
		||||
              {{ item }}
 | 
			
		||||
            </el-tag>
 | 
			
		||||
            <el-button type="success" :icon="Plus" @click="addModel" size="small" circle/>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item>
 | 
			
		||||
          <el-button type="primary" @click="save('system')">保存</el-button>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
      </el-form>
 | 
			
		||||
 | 
			
		||||
      <el-divider content-position="center">聊天设置</el-divider>
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <div class="grid-content">
 | 
			
		||||
            <el-form-item label="GPT模型">
 | 
			
		||||
              <el-input v-model="form['model']" placeholder="gpt-3/gpt-3.5-turbo/gpt-4"/>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-col>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <div class="grid-content">
 | 
			
		||||
            <el-form-item label="模型温度">
 | 
			
		||||
              <el-input v-model="form['temperature']" placeholder="0-1之间的小数"/>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <div class="grid-content">
 | 
			
		||||
            <el-form-item label="Max Tokens">
 | 
			
		||||
              <el-input v-model="form['max_tokens']" placeholder="回复的最大字数,最大4096"/>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-col>
 | 
			
		||||
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <div class="grid-content">
 | 
			
		||||
            <el-form-item label="上下文超时">
 | 
			
		||||
              <el-input v-model="form['chat_context_expire_time']" placeholder="单位:秒"/>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
 | 
			
		||||
      <el-form-item label="对话上下文">
 | 
			
		||||
        <el-switch v-model="form['enable_context']"/>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
 | 
			
		||||
      <el-form-item>
 | 
			
		||||
        <el-button type="primary" @click="saveConfig">保存</el-button>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
    </el-form>
 | 
			
		||||
 | 
			
		||||
    <el-divider content-position="center">API KEY 管理</el-divider>
 | 
			
		||||
    <el-row class="api-key-box">
 | 
			
		||||
      <el-input
 | 
			
		||||
          v-model="apiKey"
 | 
			
		||||
          placeholder="输入 API KEY"
 | 
			
		||||
          class="input-with-select"
 | 
			
		||||
      >
 | 
			
		||||
        <template #prepend>
 | 
			
		||||
          <el-button type="primary">
 | 
			
		||||
            <el-icon>
 | 
			
		||||
              <Plus/>
 | 
			
		||||
            </el-icon>
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template #append>
 | 
			
		||||
          <el-button class="new-proxy" @click="addApiKey">新增</el-button>
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-input>
 | 
			
		||||
    </el-row>
 | 
			
		||||
 | 
			
		||||
    <el-row>
 | 
			
		||||
      <el-table :data="apiKeys" style="width: 100%">
 | 
			
		||||
        <el-table-column prop="value" label="API-KEY"/>
 | 
			
		||||
        <el-table-column prop="last_used" label="最后使用" width="180">
 | 
			
		||||
          <template #default="scope">
 | 
			
		||||
            <span v-if="scope.row['last_used'] > 0">{{ dateFormat(scope.row['last_used']) }}</span>
 | 
			
		||||
            <el-tag v-else>未使用</el-tag>
 | 
			
		||||
          </template>
 | 
			
		||||
        </el-table-column>
 | 
			
		||||
        <el-table-column label="操作" width="180">
 | 
			
		||||
          <template #default="scope">
 | 
			
		||||
            <el-popconfirm
 | 
			
		||||
                width="220"
 | 
			
		||||
                confirm-button-text="确定"
 | 
			
		||||
                cancel-button-text="取消"
 | 
			
		||||
                title="确定删除该记录吗?"
 | 
			
		||||
                :hide-after="0"
 | 
			
		||||
                @confirm="removeApiKey(scope.row.value)"
 | 
			
		||||
            >
 | 
			
		||||
              <template #reference>
 | 
			
		||||
                <el-button
 | 
			
		||||
                    size="small"
 | 
			
		||||
                    type="danger">删除
 | 
			
		||||
                </el-button>
 | 
			
		||||
              </template>
 | 
			
		||||
            </el-popconfirm>
 | 
			
		||||
 | 
			
		||||
          </template>
 | 
			
		||||
        </el-table-column>
 | 
			
		||||
      </el-table>
 | 
			
		||||
    </el-row>
 | 
			
		||||
      <el-alert type="info" show-icon :closable="false">
 | 
			
		||||
        <p>以下配置为新用户注册默认初始化的聊天参数,用户登录后还可以自己修改参数。</p>
 | 
			
		||||
      </el-alert>
 | 
			
		||||
      <el-form :model="chat" label-position="left" label-width="120px">
 | 
			
		||||
        <el-form-item label="OpenAI API 地址">
 | 
			
		||||
          <el-input v-model="chat['api_url']" placeholder="gpt-3/gpt-3.5-turbo/gpt-4"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="默认模型">
 | 
			
		||||
          <el-input v-model="chat['model']" placeholder="用户默认使用的 GPT 模型"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="模型温度">
 | 
			
		||||
          <el-input v-model="chat['temperature']" placeholder="0-1之间的小数"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="Max Tokens">
 | 
			
		||||
          <el-input v-model="chat['max_tokens']" placeholder="回复的最大字数,最大4096"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="开启聊天上下文">
 | 
			
		||||
          <el-switch v-model="chat['enable_context']"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="保存聊天记录">
 | 
			
		||||
          <el-switch v-model="chat['enable_history']"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
 | 
			
		||||
        <el-form-item style="text-align: right">
 | 
			
		||||
          <el-button type="primary" @click="save('chat')">保存</el-button>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
      </el-form>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {defineComponent, nextTick} from "vue";
 | 
			
		||||
import {Plus} from "@element-plus/icons-vue";
 | 
			
		||||
<script setup>
 | 
			
		||||
import {nextTick, onMounted, reactive, ref} from "vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {dateFormat, removeArrayItem} from "@/utils/libs";
 | 
			
		||||
import {ElMessage, ElMessageBox} from "element-plus";
 | 
			
		||||
import {Plus} from "@element-plus/icons-vue";
 | 
			
		||||
import {removeArrayItem} from "@/utils/libs";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'SysConfig',
 | 
			
		||||
  components: {Plus},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      apiKey: '',
 | 
			
		||||
      form: {img_url: {}},
 | 
			
		||||
      apiKeys: [],
 | 
			
		||||
      loading: true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    // 获取系统配置
 | 
			
		||||
    httpGet('/api/admin/config/get').then((res) => {
 | 
			
		||||
      this.form = res.data;
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      ElMessage.error('获取系统配置失败')
 | 
			
		||||
const system = ref({models: []})
 | 
			
		||||
const chat = ref({})
 | 
			
		||||
const loading = ref(true)
 | 
			
		||||
const systemFormRef = ref(null)
 | 
			
		||||
const tempModel = ref('')
 | 
			
		||||
const models = ref([])
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  // 加载系统配置
 | 
			
		||||
  httpGet('/api/admin/config/get?key=system').then(res => {
 | 
			
		||||
    system.value = res.data
 | 
			
		||||
    system.value['models'].forEach(model => {
 | 
			
		||||
      models.value.push({
 | 
			
		||||
        name: model,
 | 
			
		||||
        edit: false
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    // 获取 API KEYS
 | 
			
		||||
    httpPost('api/admin/apikey/list').then((res) => {
 | 
			
		||||
      this.apiKeys = res.data
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      ElMessage.error('获取 API KEY 失败')
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("加载系统配置失败: " + e.message)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
      this.loading = false
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    dateFormat() {
 | 
			
		||||
      return dateFormat
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    saveConfig: function () {
 | 
			
		||||
      this.form['temperature'] = parseFloat(this.form.temperature)
 | 
			
		||||
      this.form['chat_context_expire_time'] = parseInt(this.form.chat_context_expire_time)
 | 
			
		||||
      this.form['max_tokens'] = parseInt(this.form.max_tokens)
 | 
			
		||||
      httpPost("/api/admin/config/set", this.form).then(() => {
 | 
			
		||||
        ElMessage.success("保存成功");
 | 
			
		||||
      }).catch((e) => {
 | 
			
		||||
        console.log(e.message);
 | 
			
		||||
        ElMessage.error("保存失败");
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  // 加载聊天配置
 | 
			
		||||
  httpGet('/api/admin/config/get?key=chat').then(res => {
 | 
			
		||||
    chat.value = res.data
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("加载聊天配置失败: " + e.message)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
    addApiKey: function () {
 | 
			
		||||
      if (this.apiKey.trim() === '') {
 | 
			
		||||
        ElMessage.error('请输入 API KEY')
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      httpPost('api/admin/apikey/add', {api_key: this.apiKey.trim()}).then(() => {
 | 
			
		||||
        ElMessage.success('添加成功')
 | 
			
		||||
        this.apiKeys.unshift({value: this.apiKey, last_used: 0})
 | 
			
		||||
        this.apiKey = ''
 | 
			
		||||
      }).catch((e) => {
 | 
			
		||||
        ElMessage.error('添加失败,' + e.message)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeApiKey: function (key) {
 | 
			
		||||
      httpPost('api/admin/apikey/remove', {api_key: key}).then(() => {
 | 
			
		||||
        ElMessage.success('删除成功')
 | 
			
		||||
        this.apiKeys = removeArrayItem(this.apiKeys, key, function (v1, v2) {
 | 
			
		||||
          return v1.value === v2
 | 
			
		||||
        })
 | 
			
		||||
      }).catch((e) => {
 | 
			
		||||
        ElMessage.error('删除失败,' + e.message)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const rules = reactive({
 | 
			
		||||
  title: [{required: true, message: '请输入网站标题', trigger: 'blur',}],
 | 
			
		||||
  admin_title: [{required: true, message: '请输入控制台标题', trigger: 'blur',}],
 | 
			
		||||
  init_calls: [{required: true, message: '必须填入大于0的数组', trigger: 'blur',}],
 | 
			
		||||
  models: [{required: true, message: '至少保留一个 GPT 模型', trigger: 'blur',}],
 | 
			
		||||
})
 | 
			
		||||
const save = function (key) {
 | 
			
		||||
  systemFormRef.value.validate((valid) => {
 | 
			
		||||
    if (valid) {
 | 
			
		||||
      const data = key === 'system' ? system.value : chat.value
 | 
			
		||||
      httpPost('/api/admin/config/update', {key: key, config: data}).then(() => {
 | 
			
		||||
        ElMessage.success("操作成功!")
 | 
			
		||||
      }).catch(e => {
 | 
			
		||||
        ElMessage.error("操作失败:" + e.message)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const removeModel = function (model) {
 | 
			
		||||
  system.value.models = removeArrayItem(system.value.models, model, (v1, v2) => {
 | 
			
		||||
    return v1 === v2
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 增加 GPT 模型
 | 
			
		||||
const addModel = function () {
 | 
			
		||||
  ElMessageBox.prompt('请输入 GPT 模型名称', '新增模型', {
 | 
			
		||||
    confirmButtonText: '保存',
 | 
			
		||||
    cancelButtonText: '取消',
 | 
			
		||||
    inputPattern:
 | 
			
		||||
        /[\w+]/,
 | 
			
		||||
    inputErrorMessage: '请输入模型名称',
 | 
			
		||||
 | 
			
		||||
  }).then(({value}) => {
 | 
			
		||||
    system.value.models.push(value)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.system-config {
 | 
			
		||||
  display flex
 | 
			
		||||
  justify-content center
 | 
			
		||||
 | 
			
		||||
  .api-key-box {
 | 
			
		||||
    padding-bottom: 10px;
 | 
			
		||||
  .container {
 | 
			
		||||
    width 100%
 | 
			
		||||
    max-width 800px;
 | 
			
		||||
 | 
			
		||||
    .el-form {
 | 
			
		||||
      .el-form-item__content {
 | 
			
		||||
        .models {
 | 
			
		||||
          .el-tag {
 | 
			
		||||
            margin-right 10px;
 | 
			
		||||
 | 
			
		||||
            .el-input {
 | 
			
		||||
              max-width 100px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .el-button--small {
 | 
			
		||||
            font-size 16px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-alert {
 | 
			
		||||
      margin-bottom 15px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="user-list" v-loading="loading">
 | 
			
		||||
    <el-row class="opt-box">
 | 
			
		||||
      <el-button type="primary" @click="showUserDialog = true">
 | 
			
		||||
        <el-icon>
 | 
			
		||||
          <Plus/>
 | 
			
		||||
        </el-icon>
 | 
			
		||||
        新增口令
 | 
			
		||||
      </el-button>
 | 
			
		||||
 | 
			
		||||
      <el-button type="success" @click="showBatchAddUserDialog = true">
 | 
			
		||||
        <el-icon>
 | 
			
		||||
          <Plus/>
 | 
			
		||||
        </el-icon>
 | 
			
		||||
        批量生成口令
 | 
			
		||||
      </el-button>
 | 
			
		||||
    </el-row>
 | 
			
		||||
 | 
			
		||||
    <el-row>
 | 
			
		||||
      <el-table :data="users">
 | 
			
		||||
        <el-table-column prop="name" label="口令名称"/>
 | 
			
		||||
@@ -258,7 +242,6 @@
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {nextTick, onMounted, reactive, ref} from "vue";
 | 
			
		||||
import {Plus} from "@element-plus/icons-vue";
 | 
			
		||||
import {httpPost} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {arrayContains, removeArrayItem} from "@/utils/libs";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="welcome" :style="{ height: winHeight + 'px' }">
 | 
			
		||||
    <h1>Chat-Plus 控制台</h1>
 | 
			
		||||
    <h1>ChatGPT-PLUS 控制台</h1>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user