write-prompt-index.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. const fs = require('fs')
  2. const paths = [
  3. 'd:/ylrz_saas_new/saas-companyui/src/views/lobster/prompt/index.vue',
  4. 'd:/ylrz_saas_new/saas-mgnui/src/views/lobster/prompt/index.vue',
  5. 'd:/ylrz_saas_new/adminui/src/views/lobster/prompt/index.vue'
  6. ]
  7. const content = `<template>
  8. <div class="app-container lobster-prompt-page">
  9. <el-alert
  10. :title="pageNotes.title"
  11. type="info"
  12. show-icon
  13. :closable="false"
  14. class="page-note"
  15. >
  16. <ul class="note-list">
  17. <li v-for="(line, idx) in pageNotes.lines" :key="'intro-' + idx">{{ line }}</li>
  18. </ul>
  19. </el-alert>
  20. <el-alert
  21. :title="pageNotes.variableTitle"
  22. type="warning"
  23. show-icon
  24. :closable="false"
  25. class="page-note"
  26. >
  27. <ul class="note-list">
  28. <li v-for="(line, idx) in pageNotes.variableLines" :key="'var-' + idx">{{ line }}</li>
  29. </ul>
  30. </el-alert>
  31. <el-row :gutter="12" class="toolbar-row">
  32. <el-col :span="5">
  33. <el-input v-model="search" placeholder="\u641c\u7d22\u540d\u79f0\u6216\u7528\u9014" clearable size="small" @keyup.enter.native="loadList" />
  34. </el-col>
  35. <el-col :span="3">
  36. <el-select v-model="filterCategory" placeholder="\u5206\u7c7b\u7b5b\u9009" clearable size="small" @change="loadList">
  37. <el-option v-for="c in sceneOptions" :key="c.value" :label="c.label" :value="c.value" />
  38. </el-select>
  39. </el-col>
  40. <el-col :span="16" class="toolbar-actions">
  41. <el-button size="small" icon="el-icon-refresh" @click="loadList">\u5237\u65b0</el-button>
  42. <el-button size="small" type="warning" plain :loading="bootstrapping" @click="handleBootstrap(false)">\u540c\u6b65\u9ed8\u8ba4\u63d0\u793a\u8bcd</el-button>
  43. <el-button size="small" type="danger" plain :loading="bootstrapping" @click="handleBootstrap(true)">\u91cd\u7f6e\u4e3a\u76ee\u5f55\u9ed8\u8ba4</el-button>
  44. </el-col>
  45. </el-row>
  46. <el-table v-loading="loading" :data="promptList" border size="small">
  47. <el-table-column prop="category_label" label="\u5206\u7c7b" width="100" />
  48. <el-table-column prop="prompt_name" label="\u573a\u666f\u540d\u79f0" width="160" show-overflow-tooltip />
  49. <el-table-column prop="prompt_key" label="\u573a\u666f\u7f16\u7801" width="200" show-overflow-tooltip />
  50. <el-table-column label="\u7528\u9014\u8bf4\u660e" min-width="200" show-overflow-tooltip>
  51. <template slot-scope="scope">
  52. {{ scope.row.scene_hint || sceneHintOf(scope.row.prompt_key) || '\u2014' }}
  53. </template>
  54. </el-table-column>
  55. <el-table-column label="\u662f\u5426\u5df2\u4fee\u6539" width="90" align="center">
  56. <template slot-scope="scope">
  57. <el-tag :type="scope.row.customized ? 'warning' : 'info'" size="mini">
  58. {{ scope.row.customized ? '\u5df2\u81ea\u5b9a\u4e49' : '\u9ed8\u8ba4' }}
  59. </el-tag>
  60. </template>
  61. </el-table-column>
  62. <el-table-column label="\u64cd\u4f5c" width="90" fixed="right">
  63. <template slot-scope="scope">
  64. <el-button type="text" size="mini" @click="openEdit(scope.row)">\u7f16\u8f91</el-button>
  65. </template>
  66. </el-table-column>
  67. </el-table>
  68. <pagination
  69. v-show="total > 0"
  70. :total="total"
  71. :page.sync="page"
  72. :limit.sync="pageSize"
  73. @pagination="loadList"
  74. />
  75. <el-dialog
  76. :title="editForm.prompt_name || '\u7f16\u8f91\u63d0\u793a\u8bcd'"
  77. :visible.sync="editVisible"
  78. width="820px"
  79. append-to-body
  80. custom-class="lobster-prompt-edit-dialog"
  81. >
  82. <el-alert
  83. :title="sceneHintOf(editForm.prompt_key) || '\u6682\u65e0\u573a\u666f\u8bf4\u660e'"
  84. type="info"
  85. :closable="false"
  86. show-icon
  87. class="dialog-scene-hint"
  88. />
  89. <el-form ref="editRef" :model="editForm" label-width="100px">
  90. <el-form-item label="\u573a\u666f\u7f16\u7801">
  91. <el-input v-model="editForm.prompt_key" disabled />
  92. </el-form-item>
  93. <el-form-item label="\u573a\u666f\u540d\u79f0">
  94. <el-input v-model="editForm.prompt_name" />
  95. </el-form-item>
  96. <el-form-item label="\u7cfb\u7edf\u89d2\u8272" v-if="editForm.system_role !== undefined && editForm.system_role !== null">
  97. <el-input
  98. v-model="editForm.system_role"
  99. type="textarea"
  100. :rows="2"
  101. placeholder="\u5b9a\u4e49 AI \u626e\u6f14\u4ec0\u4e48\u89d2\u8272\uff0c\u4f8b\u5982\uff1a\u4f60\u662f\u4f01\u4e1a\u77e5\u8bc6\u5e93\u52a9\u624b\uff0c\u53ea\u57fa\u4e8e\u63d0\u4f9b\u7684\u77e5\u8bc6\u56de\u7b54\u95ee\u9898"
  102. />
  103. <div class="field-tip">\u5907\u6ce8\uff1a\u7cfb\u7edf\u89d2\u8272\u662f\u5bf9 AI \u7684\u8eab\u4efd\u7ea6\u675f\uff0c\u4e00\u822c\u4fdd\u6301\u9ed8\u8ba4\u5373\u53ef\uff1b\u5982\u9700\u8c03\u6574\u8bed\u6c14\u6216\u4e13\u4e1a\u9886\u57df\u53ef\u5728\u6b64\u4fee\u6539\u3002</div>
  104. </el-form-item>
  105. <el-form-item label="\u63d0\u793a\u8bcd\u5185\u5bb9" prop="prompt_content">
  106. <prompt-structured-editor
  107. v-model="editForm.prompt_content"
  108. :prompt-key="editForm.prompt_key"
  109. />
  110. <div class="field-tip">\u5907\u6ce8\uff1a\u53ea\u9700\u6539\u767d\u8272\u6587\u672c\u6846\u91cc\u7684\u4e2d\u6587\u8bf4\u660e\uff1b\u7070\u8272\u300c\u81ea\u52a8\u586b\u5165\u300d\u5757\u8bf7\u52ff\u5220\u9664\u3002\u4fdd\u5b58\u540e\u7acb\u5373\u751f\u6548\u3002</div>
  111. </el-form-item>
  112. </el-form>
  113. <div slot="footer">
  114. <el-button @click="editVisible = false">\u53d6\u6d88</el-button>
  115. <el-button type="primary" :loading="saving" @click="handleSave">\u4fdd\u5b58</el-button>
  116. </div>
  117. </el-dialog>
  118. </div>
  119. </template>
  120. <script>
  121. import { listPrompts, updatePrompt, bootstrapPromptDefaults, refreshPromptCache } from '@/api/workflow/lobster'
  122. import PromptStructuredEditor from '@/views/lobster/components/PromptStructuredEditor.vue'
  123. import {
  124. PROMPT_PAGE_NOTES,
  125. PROMPT_SCENE_OPTIONS,
  126. sceneHintOf
  127. } from '@/utils/lobster/promptCatalog'
  128. export default {
  129. name: 'LobsterPrompt',
  130. components: { PromptStructuredEditor },
  131. data() {
  132. return {
  133. search: '',
  134. filterCategory: '',
  135. loading: false,
  136. bootstrapping: false,
  137. saving: false,
  138. promptList: [],
  139. page: 1,
  140. pageSize: 50,
  141. total: 0,
  142. editVisible: false,
  143. editForm: {},
  144. sceneOptions: PROMPT_SCENE_OPTIONS,
  145. pageNotes: PROMPT_PAGE_NOTES
  146. }
  147. },
  148. created() {
  149. this.initPage()
  150. },
  151. methods: {
  152. initPage() {
  153. this.loading = true
  154. bootstrapPromptDefaults(false).catch(() => {}).finally(() => {
  155. this.loadList()
  156. })
  157. },
  158. loadList() {
  159. this.loading = true
  160. listPrompts({
  161. page: this.page,
  162. size: this.pageSize,
  163. scene: this.filterCategory || undefined,
  164. search: this.search || undefined
  165. }).then(res => {
  166. const data = res.data || {}
  167. this.promptList = data.list || []
  168. this.total = data.total || 0
  169. }).finally(() => { this.loading = false })
  170. },
  171. openEdit(row) {
  172. this.editForm = {
  173. id: row.id,
  174. prompt_key: row.prompt_key,
  175. prompt_name: row.prompt_name,
  176. prompt_category: row.prompt_category,
  177. category_label: row.category_label || row.prompt_category,
  178. prompt_content: row.prompt_content || '',
  179. system_role: row.system_role || ''
  180. }
  181. this.editVisible = true
  182. },
  183. handleSave() {
  184. if (!this.editForm.prompt_content || !this.editForm.prompt_content.trim()) {
  185. this.$message.warning('\u63d0\u793a\u8bcd\u5185\u5bb9\u4e0d\u80fd\u4e3a\u7a7a')
  186. return
  187. }
  188. this.saving = true
  189. updatePrompt(this.editForm.id, {
  190. promptName: this.editForm.prompt_name,
  191. promptCategory: this.editForm.prompt_category,
  192. promptContent: this.editForm.prompt_content,
  193. systemRole: this.editForm.system_role
  194. }).then(() => {
  195. this.$message.success('\u4fdd\u5b58\u6210\u529f')
  196. this.editVisible = false
  197. refreshPromptCache().catch(() => {})
  198. this.loadList()
  199. }).finally(() => { this.saving = false })
  200. },
  201. handleBootstrap(reset) {
  202. const tip = reset
  203. ? '\u5c06\u628a\u6240\u6709\u5f15\u64ce\u63d0\u793a\u8bcd\u8986\u76d6\u4e3a\u76ee\u5f55\u9ed8\u8ba4\u503c\uff0c\u81ea\u5b9a\u4e49\u4fee\u6539\u4f1a\u4e22\u5931\uff0c\u662f\u5426\u7ee7\u7eed\uff1f'
  204. : '\u5c06\u4e3a\u7f3a\u5931\u7684 Key \u5199\u5165\u76ee\u5f55\u9ed8\u8ba4\u5185\u5bb9\uff0c\u8865\u5168\u7f3a\u5931\u7684\u5206\u7c7b/\u540d\u79f0\uff0c\u5e76\u81ea\u52a8\u5c06\u4ecd\u4e3a\u65e7\u7248\u82f1\u6587\u9ed8\u8ba4\u7684\u5185\u5bb9\u5347\u7ea7\u4e3a\u4e2d\u6587\u7248\uff0c\u662f\u5426\u7ee7\u7eed\uff1f'
  205. this.$confirm(tip, '\u63d0\u793a', { type: reset ? 'warning' : 'info' }).then(() => {
  206. this.bootstrapping = true
  207. bootstrapPromptDefaults(reset).then(res => {
  208. this.$message.success(res.msg || '\u540c\u6b65\u5b8c\u6210')
  209. this.loadList()
  210. }).finally(() => { this.bootstrapping = false })
  211. }).catch(() => {})
  212. },
  213. sceneHintOf
  214. }
  215. }
  216. </script>
  217. <style scoped lang="scss">
  218. .lobster-prompt-page {
  219. .page-note {
  220. margin-bottom: 16px;
  221. }
  222. .note-list {
  223. margin: 8px 0 0;
  224. padding-left: 18px;
  225. line-height: 1.7;
  226. color: #606266;
  227. font-size: 13px;
  228. }
  229. .toolbar-row {
  230. margin-bottom: 12px;
  231. }
  232. .toolbar-actions {
  233. text-align: right;
  234. }
  235. .dialog-scene-hint {
  236. margin-bottom: 16px;
  237. }
  238. .field-tip {
  239. margin-top: 6px;
  240. font-size: 12px;
  241. line-height: 1.5;
  242. color: #909399;
  243. }
  244. }
  245. </style>
  246. `
  247. paths.forEach(p => {
  248. fs.writeFileSync(p, content, 'utf8')
  249. console.log('wrote', p)
  250. })