ConfigurationView.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <el-row>
  3. <h2>配置</h2>
  4. </el-row>
  5. <el-row style="margin:15px; ">
  6. <el-tabs v-model="activeName" style="width: 100%;">
  7. <el-tab-pane label="基本配置" name="basic"
  8. style="width: 100%;height: 800px; overflow-y:auto; display: flex; flex-direction: row;">
  9. <el-form :model="basicConfig" label-width="120px" style="margin: 5px;">
  10. <el-form-item label="名称" prop="name" style="height: 25px;">
  11. <el-input v-model="basicConfig.name"></el-input>
  12. </el-form-item>
  13. <el-form-item label="联系人" prop="contactor" style="height: 25px;">
  14. <el-input v-model="basicConfig.contactor"></el-input>
  15. </el-form-item>
  16. <el-form-item label="联系电话" prop="contact_phone" style="height: 25px;">
  17. <el-input v-model="basicConfig.contact_phone"></el-input>
  18. </el-form-item>
  19. <el-form-item label="启用日期" prop="system_uptime" style="height: 25px;">
  20. <el-date-picker v-model="basicConfig.system_uptime" type="date" placeholder="选择日期">
  21. </el-date-picker>
  22. </el-form-item>
  23. <el-form-item label="结束日期" prop="system_downtime" style="height: 25px;">
  24. <el-date-picker v-model="basicConfig.system_downtime" type="date" placeholder="选择日期">
  25. </el-date-picker>
  26. </el-form-item>
  27. </el-form>
  28. </el-tab-pane>
  29. <el-tab-pane label="队列配置" name="first"
  30. style="width: 100%;height: 800px; overflow-y:auto; display: flex; flex-direction: row;">
  31. <div v-for="(queue) in queueData" :key="queue.id" style="margin-right:8px;width:350px; ">
  32. <span style="font-weight: bold;"> {{ queue.queue_label }}</span> <span style="font-size: 8pt;">({{
  33. queue.queue_category }}_{{ queue.queue_name }})</span><br />
  34. <br />
  35. <div style="border: solid 1px #CDCDCD;padding:8px;">
  36. 当成功时,转到 {{ queue.queue_config?.success.queue_category }}_{{
  37. queue.queue_config?.success.queue_name }}<br />
  38. 当失败时,转到 {{ queue.queue_config?.failed.queue_category }}_{{ queue.queue_config?.failed.queue_name
  39. }}<br />
  40. 当错误时,转到 {{ queue.queue_config?.error.queue_category }}_{{ queue.queue_config?.error.queue_name
  41. }}<br />
  42. 最大实例数:<el-select v-model="queue.queue_config.max_instance" style="width:55px;margin-right:5px;">
  43. <el-option v-for="item in [1, 2, 3, 4, 5]" :key="item" :label="item"
  44. :value="item"></el-option>
  45. </el-select>
  46. <div style="border-top: solid 1px #CDCDCD; margin-top:5px; display:grid;justify-items: right;">
  47. <el-button @click="handleSaveConfig(queue)"
  48. style=" width:80px; margin-top:3px;">保存</el-button>
  49. </div>
  50. </div>
  51. </div>
  52. </el-tab-pane>
  53. <el-tab-pane label="大模型配置" name="second">
  54. <el-button link type="primary" @click="handleSaveLLMConfig" style="">保存</el-button>
  55. <div style="width: 100%;display: flex; flex-direction: row; flex-wrap:wrap;">
  56. <div
  57. style="width: 300px;height:210px;border: 1px solid #CDCDCD; display: flex; flex-direction: column;justify-content:center;margin-right: 8px; margin-bottom: 8px;">
  58. <el-button link type="primary" @click="handleAddLLMConfig">添加</el-button>
  59. </div>
  60. <template v-for="(item) in llmConfig.items" :key="item.id">
  61. <div
  62. style="width: 300px;height:210px;border: 1px solid #CDCDCD; display: flex; flex-direction: column;justify-content:center;margin-right: 8px; margin-bottom: 8px;">
  63. <div v-if="item.is_default"
  64. style="position: relative; width: 15px; height:15px;left: 0px; top:15px; background-color: darkgreen;">
  65. <span style="height:15px;">&nbsp;</span>
  66. </div>
  67. <el-form :model="item" label-width="80px" style="margin: 5px;">
  68. <el-form-item label="类型" prop="api_name" style="height: 25px;">
  69. <span v-if="getLLMConfigEditFlag(item) == false">{{ item.api_name }}</span>
  70. <el-select v-else v-model="item.api_name" style="width: 150px;">
  71. <el-option v-for="option in ['openai', 'deepseek v3', 'deepseek r1']"
  72. :key="option" :label="option" :value="option"></el-option>
  73. </el-select>
  74. </el-form-item>
  75. <el-form-item lable="模型" prop="model_name" style="height: 25px;">
  76. <span v-if="getLLMConfigEditFlag(item) == false">{{ item.model_name }}</span>
  77. <el-input v-else v-model="item.model_name"></el-input>
  78. </el-form-item>
  79. <el-form-item label="API 地址" prop="api_host" style="height: 25px;">
  80. <span v-if="getLLMConfigEditFlag(item) == false" style="overflow: hidden;">{{
  81. formatOverflowText(item.api_host, 32) }}</span>
  82. <el-input v-else v-model="item.api_host"></el-input>
  83. </el-form-item>
  84. <el-form-item label="API Key" prop="api_key" style="height: 25px;">
  85. <span v-if="getLLMConfigEditFlag(item) == false">********</span>
  86. <el-input v-else v-model="item.api_key"></el-input>
  87. </el-form-item>
  88. <el-form-item style="display:grid;justify-items: right; height:25px;">
  89. <el-button v-if="!item.is_default" link type="primary"
  90. @click="handleSetLLMConfigDefault(item)" style=" ">设为默认</el-button>
  91. <el-button link type="danger" @click="handleDeleteLLMConfig(item)"
  92. v-if="getLLMConfigEditFlag(item) == false" style=" ">删除</el-button>
  93. <el-button link type="primary" @click="handleEditLLMConfig(item)"
  94. v-if="getLLMConfigEditFlag(item) == false" style=" ">编辑</el-button>
  95. <el-button link type="primary" @click="handleCancelEditLLMConfig(item)"
  96. v-if="getLLMConfigEditFlag(item) == true" style=" ">取消</el-button>
  97. </el-form-item>
  98. </el-form>
  99. </div>
  100. </template>
  101. </div>
  102. </el-tab-pane>
  103. <!-- <el-tab-pane label="许可证" name="third">
  104. 第一步:通过hash数值查询许可证信息<br/>
  105. 第二步:导入许可证文件
  106. <el-image style="width: 300px; height: 300px" :src="'/api/agent/qrcode/somm'" wid></el-image>
  107. </el-tab-pane> -->
  108. </el-tabs>
  109. </el-row>
  110. </template>
  111. <script setup lang="ts">
  112. import { ref, onMounted, watch, nextTick } from 'vue'
  113. import { getConfig, setConfig, getQueues } from '@/api/AgentApi'
  114. import { ElMessage } from 'element-plus'
  115. import { formatOverflowText } from '@/utils/misc'
  116. import { ITEM_RENDER_EVT } from 'element-plus/es/components/virtual-list/src/defaults.mjs'
  117. interface ViewBasicInfo {
  118. name: string,
  119. contactor: string,
  120. contact_phone: string,
  121. system_uptime: Date,
  122. system_downtime: Date
  123. }
  124. interface ActionQueue {
  125. queue_category: string
  126. queue_name: string
  127. }
  128. interface QueueConfig {
  129. command: string
  130. script: string
  131. args: string[]
  132. success: ActionQueue
  133. failed: ActionQueue
  134. error: ActionQueue
  135. max_instance: number
  136. }
  137. interface QueueData {
  138. id: number
  139. queue_category: string
  140. queue_name: string
  141. queue_label: string
  142. queue_config: QueueConfig
  143. }
  144. interface ConfigData {
  145. id: number
  146. code: string
  147. name: string
  148. content: string
  149. status: number
  150. }
  151. interface LLMConfigData {
  152. current_api_name: string
  153. items: LLMConfigItemData[]
  154. }
  155. interface LLMConfigItemData {
  156. api_key: string
  157. api_host: string
  158. api_name: string
  159. model_name: string
  160. is_default: boolean
  161. }
  162. const basicConfig = ref<ViewBasicInfo>({} as ViewBasicInfo)
  163. const activeName = ref('first')
  164. const queueData = ref<QueueData[]>([])
  165. const llmConfig = ref<LLMConfigData>({ current_api_name: "", items: [] })
  166. const llmConfigEditFlag = ref<Map<LLMConfigItemData, boolean>>(new Map())
  167. function loadQueueConfigData() {
  168. queueData.value.forEach((queue) => {
  169. var queue_code = queue.queue_category + "_" + queue.queue_name
  170. getConfig({ code: queue_code }).then((res) => {
  171. var config: ConfigData = res.records[0] as ConfigData
  172. var config_data: QueueConfig = JSON.parse(config.content) as QueueConfig
  173. queue.queue_config = config_data
  174. if (queue.queue_config != null) {
  175. if (queue.queue_config.max_instance === undefined) {
  176. queue.queue_config.max_instance = 1
  177. }
  178. }
  179. })
  180. })
  181. }
  182. function loadLLMConfigData() {
  183. getConfig({ code: "LLM_CONFIG" }).then((res) => {
  184. var config: ConfigData = res.records[0] as ConfigData
  185. var config_data: LLMConfigData = JSON.parse(config.content) as LLMConfigData
  186. llmConfig.value = config_data
  187. })
  188. }
  189. function handleSaveLLMConfig() {
  190. llmConfig.value.items.forEach((item) => {
  191. if (item.is_default) {
  192. llmConfig.value.current_api_name = item.api_name
  193. }
  194. })
  195. var config: ConfigData = { id: 0, code: "LLM_CONFIG", name: "大模型配置", content: JSON.stringify(llmConfig.value), status: 1 }
  196. setConfig(config).then((res) => {
  197. if (res.code == 200) {
  198. ElMessage.success("保存成功")
  199. }
  200. })
  201. }
  202. function handleSaveConfig(queue: QueueData) {
  203. }
  204. function handleSetLLMConfigDefault(item: LLMConfigItemData) {
  205. llmConfig.value.items.forEach((item) => {
  206. item.is_default = false
  207. })
  208. item.is_default = true
  209. }
  210. function handleDeleteLLMConfig(item: LLMConfigItemData) {
  211. var index = llmConfig.value.items.indexOf(item)
  212. llmConfig.value.items.splice(index, 1)
  213. }
  214. function getLLMConfigEditFlag(item: LLMConfigItemData) {
  215. return llmConfigEditFlag.value.get(item) == true ? true : false
  216. }
  217. function handleEditLLMConfig(item: LLMConfigItemData) {
  218. llmConfigEditFlag.value.set(item, true)
  219. }
  220. function handleCancelEditLLMConfig(item: LLMConfigItemData) {
  221. llmConfigEditFlag.value.set(item, false)
  222. }
  223. function handleAddLLMConfig() {
  224. var item: LLMConfigItemData = { api_key: "", api_host: "", api_name: "", is_default: false, model_name: "" }
  225. item.api_name = "openai"
  226. llmConfig.value.items.push(item)
  227. llmConfigEditFlag.value.set(item, true)
  228. }
  229. function loadQueues() {
  230. getQueues().then(async (res) => {
  231. queueData.value = []
  232. let data = res.records as QueueData[]
  233. // loadQueueConfigData()
  234. await Promise.allSettled(data.map(async (queue, index) => {
  235. var queue_code = data[index].queue_category + "_" + data[index].queue_name
  236. await getConfig({ code: queue_code }).then((res) => {
  237. var config: ConfigData = res.records[0] as ConfigData
  238. var config_data: QueueConfig = JSON.parse(config.content) as QueueConfig
  239. data[index].queue_config = config_data
  240. if (data[index].queue_config != null) {
  241. if (data[index].queue_config.max_instance === undefined) {
  242. data[index].queue_config.max_instance = 1
  243. }
  244. }
  245. })
  246. queueData.value.push(data[index])
  247. }))
  248. // queueData.value = data
  249. })
  250. }
  251. onMounted(() => {
  252. loadQueues()
  253. loadLLMConfigData()
  254. })
  255. </script>
  256. <style lang="css" scoped></style>