| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- const fs = require('fs')
- const paths = [
- 'd:/ylrz_saas_new/saas-companyui/src/views/lobster/components/PromptStructuredEditor.vue',
- 'd:/ylrz_saas_new/saas-mgnui/src/views/lobster/components/PromptStructuredEditor.vue',
- 'd:/ylrz_saas_new/adminui/src/views/lobster/components/PromptStructuredEditor.vue'
- ]
- const content = `<template>
- <div class="prompt-structured-editor">
- <div class="editor-toolbar">
- <span class="toolbar-label">\u7f16\u8f91\u65b9\u5f0f</span>
- <el-radio-group v-model="editMode" size="mini" @change="handleModeChange">
- <el-radio-button label="structured">\u5206\u6bb5\u7f16\u8f91\uff08\u63a8\u8350\uff09</el-radio-button>
- <el-radio-button label="raw">\u539f\u6587\u7f16\u8f91</el-radio-button>
- </el-radio-group>
- </div>
- <div v-if="editMode === 'structured'" class="structured-body">
- <div v-if="!hasVariables" class="single-text">
- <el-input
- type="textarea"
- :rows="12"
- v-model="plainText"
- placeholder="\u8bf7\u8f93\u5165\u63d0\u793a\u8bcd\u8bf4\u660e\u6587\u5b57"
- @input="emitPlain"
- />
- </div>
- <div v-else class="segment-list">
- <div
- v-for="(seg, idx) in segments"
- :key="idx"
- :class="['segment-item', seg.type === 'var' ? 'is-var' : 'is-text']"
- >
- <template v-if="seg.type === 'var'">
- <div class="var-chip">
- <i class="el-icon-connection" />
- <span class="var-chip-label">{{ variableLabel(seg.name) }}</span>
- </div>
- <div class="var-chip-note">\u7cfb\u7edf\u81ea\u52a8\u586b\u5165 \u00b7 \u4e0d\u53ef\u5220\u9664\u6216\u6539\u540d</div>
- </template>
- <el-input
- v-else
- type="textarea"
- :autosize="{ minRows: 2, maxRows: 8 }"
- v-model="seg.value"
- placeholder="\u53ef\u4fee\u6539\u7684\u8bf4\u660e\u6587\u5b57"
- @input="emitFromSegments"
- />
- </div>
- </div>
- </div>
- <div v-else class="raw-body">
- <el-input
- type="textarea"
- :rows="14"
- v-model="rawText"
- placeholder="\u652f\u6301 {\u53d8\u91cf\u540d} \u6216 \${\u53d8\u91cf\u540d}\uff0c\u8fd0\u884c\u65f6\u7531\u5f15\u64ce\u81ea\u52a8\u66ff\u6362"
- @input="emitRaw"
- />
- <div class="raw-tip">\u9ad8\u7ea7\u6a21\u5f0f\uff1a\u8bf7\u4fdd\u7559\u6240\u6709 {\u53d8\u91cf}\uff0c\u5426\u5219\u8fd0\u884c\u65f6\u4f1a\u7f3a\u5c11\u6570\u636e\u3002</div>
- </div>
- <div v-if="showPreview" class="preview-panel">
- <div class="preview-title">
- <i class="el-icon-view" /> \u6548\u679c\u9884\u89c8\uff08\u793a\u4f8b\u6570\u636e\uff0c\u975e\u771f\u5b9e\u5ba2\u6237\u4fe1\u606f\uff09
- </div>
- <pre class="preview-content">{{ previewText }}</pre>
- </div>
- <div v-if="variableHints.length" class="variable-legend">
- <span class="legend-label">\u672c\u573a\u666f\u53ef\u7528\u53d8\u91cf\uff1a</span>
- <el-tag
- v-for="v in variableHints"
- :key="v.name"
- size="mini"
- effect="plain"
- type="info"
- class="legend-tag"
- >
- {{ v.desc }}\uff08{{ v.name }}\uff09
- </el-tag>
- </div>
- </div>
- </template>
- <script>
- import {
- parsePromptTemplate,
- buildPromptTemplate,
- previewPromptContent,
- getVariableHints,
- variableLabel as variableLabelFn
- } from '@/utils/lobster/promptCatalog'
- export default {
- name: 'PromptStructuredEditor',
- props: {
- value: {
- type: String,
- default: ''
- },
- promptKey: {
- type: String,
- default: ''
- },
- showPreview: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- editMode: 'structured',
- segments: [],
- plainText: '',
- rawText: '',
- syncing: false
- }
- },
- computed: {
- variableHints() {
- return getVariableHints(this.promptKey)
- },
- hasVariables() {
- return this.segments.some(seg => seg.type === 'var')
- },
- previewText() {
- return previewPromptContent(this.currentContent, this.promptKey)
- },
- currentContent() {
- if (this.editMode === 'raw') {
- return this.rawText
- }
- if (!this.hasVariables) {
- return this.plainText
- }
- return buildPromptTemplate(this.segments)
- }
- },
- watch: {
- value: {
- immediate: true,
- handler(val) {
- if (this.syncing) return
- this.syncFromValue(val || '')
- }
- },
- promptKey() {
- this.syncFromValue(this.value || '')
- }
- },
- methods: {
- variableLabel(name) {
- return variableLabelFn(name, this.promptKey)
- },
- syncFromValue(val) {
- this.rawText = val
- this.segments = parsePromptTemplate(val)
- this.plainText = val
- },
- emitContent(content) {
- this.syncing = true
- this.$emit('input', content)
- this.$nextTick(() => {
- this.syncing = false
- })
- },
- emitFromSegments() {
- this.emitContent(buildPromptTemplate(this.segments))
- },
- emitPlain() {
- this.emitContent(this.plainText)
- },
- emitRaw() {
- this.emitContent(this.rawText)
- },
- handleModeChange(mode) {
- if (mode === 'raw') {
- this.rawText = this.currentContent
- this.emitRaw()
- return
- }
- this.syncFromValue(this.rawText || this.value || '')
- this.emitFromSegments()
- }
- }
- }
- </script>
- <style scoped lang="scss">
- .prompt-structured-editor {
- .editor-toolbar {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 12px;
- .toolbar-label {
- font-size: 13px;
- color: #606266;
- }
- }
- .segment-list {
- border: 1px solid #ebeef5;
- border-radius: 4px;
- padding: 8px;
- max-height: 360px;
- overflow-y: auto;
- background: #fafafa;
- }
- .segment-item {
- margin-bottom: 8px;
- &:last-child {
- margin-bottom: 0;
- }
- &.is-var {
- padding: 8px 10px;
- background: #f0f2f5;
- border: 1px dashed #c0c4cc;
- border-radius: 4px;
- }
- }
- .var-chip {
- display: flex;
- align-items: center;
- gap: 6px;
- color: #606266;
- font-size: 13px;
- font-weight: 500;
- .el-icon-connection {
- color: #909399;
- }
- }
- .var-chip-note {
- margin-top: 4px;
- font-size: 12px;
- color: #909399;
- }
- .raw-tip {
- margin-top: 8px;
- font-size: 12px;
- color: #e6a23c;
- }
- .preview-panel {
- margin-top: 14px;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- background: #fff;
- }
- .preview-title {
- padding: 8px 12px;
- font-size: 13px;
- color: #606266;
- background: #f5f7fa;
- border-bottom: 1px solid #ebeef5;
- }
- .preview-content {
- margin: 0;
- padding: 12px;
- white-space: pre-wrap;
- word-break: break-word;
- font-size: 13px;
- line-height: 1.6;
- color: #303133;
- max-height: 200px;
- overflow-y: auto;
- font-family: inherit;
- }
- .variable-legend {
- margin-top: 12px;
- line-height: 1.8;
- .legend-label {
- font-size: 12px;
- color: #909399;
- margin-right: 6px;
- }
- .legend-tag {
- margin: 2px 4px 2px 0;
- }
- }
- }
- </style>
- `
- paths.forEach(p => {
- fs.writeFileSync(p, content, 'utf8')
- console.log('wrote', p)
- })
|