CzRger 1 month ago
parent
commit
58554ca6d9

+ 6 - 1
src/views/manage/home/index.vue

@@ -1,7 +1,12 @@
-<template>首页</template>
+<template>
+  <div class="size-full p-4">
+    <paramsTextarea />
+  </div>
+</template>
 
 <script setup lang="ts">
 import { getCurrentInstance, reactive, ref } from 'vue'
+import paramsTextarea from '@/views/workflow/instance/component/params-textarea/index.vue'
 
 const emit = defineEmits([])
 const props = defineProps({})

+ 6 - 4
src/views/workflow/instance/answer/panel/index.vue

@@ -1,9 +1,10 @@
 <template>
   <div class="panel-block" v-if="state.nodeData">
-    <div class="_p-title" style="margin-top: 0">
-      <div class="text-sm">可用变量</div>
-    </div>
-    <varsSelect :node="props.node" />
+    <!--    <div class="_p-title" style="margin-top: 0">-->
+    <!--      <div class="text-sm">可用变量</div>-->
+    <!--    </div>-->
+    <!--    <varsSelect :node="props.node" />-->
+    <paramsTextarea />
   </div>
 </template>
 
@@ -11,6 +12,7 @@
 import { getCurrentInstance, reactive, ref, watch } from 'vue'
 import varsSelect from '@/views/workflow/instance/component/vars/vars-select.vue'
 import { useWorkflowStore } from '@/stores'
+import paramsTextarea from '@/views/workflow/instance/component/params-textarea/index.vue'
 
 const WorkflowStore = useWorkflowStore()
 const emit = defineEmits([])

+ 301 - 0
src/views/workflow/instance/component/params-textarea/index.vue

@@ -0,0 +1,301 @@
+<template>
+  <div class="czr-markdown-main">
+    <div class="czr-markdown-main-content" :class="`layout-${layout}`">
+      <div class="editor">
+        <textarea
+          ref="ref_textarea"
+          v-model="markdownValue"
+          @input="updateMarkdown"
+        ></textarea>
+      </div>
+      <div class="preview" v-html="markdownHtmlCpt"></div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+defineOptions({
+  name: 'CzrMarkdown',
+})
+import { ref, computed, onMounted, reactive } from 'vue'
+import { marked } from 'marked'
+import DOMPurify from 'dompurify'
+
+const renderer: any = new marked.Renderer()
+renderer.link = ({ href, text }) => {
+  return `<a href="${href}">${text}</a>`
+}
+renderer.text = ({ text }) => {
+  return text.replace(/\$\{([^}]+)\}/g, (match, p1) => {
+    return `<span class='border-1 bg-red-400'>${state.optionsMap.get(p1)?.label}</span>`
+  })
+}
+DOMPurify.addHook('afterSanitizeAttributes', (node) => {
+  if (node.tagName === 'A') {
+    node.setAttribute('target', '_blank')
+    node.setAttribute('rel', 'noopener noreferrer')
+  }
+})
+const emit = defineEmits(['update:modelValue'])
+const props = defineProps({
+  modelValue: {
+    type: String,
+    default: '',
+  },
+  layout: {
+    type: String,
+    default: 'x',
+  },
+  rendererFunc: <any>{},
+})
+const state = reactive({
+  optionsMap: new Map([
+    ['123', { label: '变量1', id: '123', type: 'String' }],
+    ['223', { label: '变量变量变量变量变量2', id: '223', type: 'String' }],
+    [
+      '333',
+      {
+        label: '变量变量变量变量变量变量变量变量变量变量变量3',
+        id: '333',
+        type: 'Number',
+      },
+    ],
+  ]),
+})
+const Menus: any = [
+  {
+    icon: 'czr_md-title',
+    title: '标题',
+    options: [
+      { title: '一级标题', start: '# ', end: '' },
+      { title: '二级标题', start: '## ', end: '' },
+      { title: '三级标题', start: '### ', end: '' },
+      { title: '四级标题', start: '#### ', end: '' },
+      { title: '五级标题', start: '##### ', end: '' },
+      {
+        label: 'H6',
+        title: '六级标题',
+        start: '###### ',
+        end: '',
+      },
+    ],
+  },
+  { icon: 'czr_md-bold', title: '加粗', start: '**', end: '**' },
+  { icon: 'czr_md-em', title: '斜体', start: '*', end: '*' },
+  { icon: 'czr_md-bold-em', title: '加粗斜体', start: '***', end: '***' },
+  {
+    icon: 'czr_md-s',
+    title: '删除线',
+    start: '~~',
+    end: '~~',
+  },
+  {
+    icon: 'czr_md-u',
+    title: '下划线',
+    start: '<u>',
+    end: '</u>',
+    split: true,
+  },
+  { icon: 'czr_md-code', title: '代码块', start: '\n```\n', end: '\n```' },
+  {
+    icon: 'czr_md-link',
+    title: '链接',
+    start: '[链接](',
+    end: ')',
+  },
+  { icon: 'czr_md-img', title: '图片', start: '![图片](', end: ')' },
+]
+const ref_textarea = ref(null)
+const markdownValue = ref(props.modelValue)
+
+const markdownHtmlCpt = computed(() => {
+  return DOMPurify.sanitize(marked(markdownValue.value) as any)
+})
+
+const updateMarkdown = () => {
+  emit('update:modelValue', markdownValue.value)
+}
+
+const insertText = (before, after) => {
+  const dom: any = ref_textarea.value
+  if (dom) {
+    const start = dom.selectionStart
+    const end = dom.selectionEnd
+    const selectedText = markdownValue.value.substring(start, end)
+    markdownValue.value =
+      markdownValue.value.substring(0, start) +
+      before +
+      selectedText +
+      after +
+      markdownValue.value.substring(end)
+    // 移动光标位置
+    setTimeout(() => {
+      dom.selectionStart = start + before.length
+      dom.selectionEnd = end + before.length
+      dom.focus()
+    }, 0)
+    emit('update:modelValue', markdownValue.value)
+  }
+}
+onMounted(() => {
+  marked.setOptions({
+    renderer: renderer,
+    breaks: true,
+    gfm: true,
+  })
+  console.log(props)
+})
+</script>
+
+<style scoped lang="scss">
+.czr-markdown-main {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
+  .czr-markdown-main-menus {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
+    padding: 10px;
+    .split {
+      width: 1px;
+      height: 16px;
+      background-color: rgba(0, 0, 0, 0.3);
+    }
+  }
+  .czr-markdown-main-content {
+    flex: 1;
+    display: flex;
+    overflow: hidden;
+    &.layout-y {
+      flex-direction: column;
+      .editor {
+        border-bottom: 1px solid rgba(0, 0, 0, 0.15);
+      }
+    }
+    &.layout-x {
+      .editor {
+        border-right: 1px solid rgba(0, 0, 0, 0.15);
+      }
+    }
+    .editor,
+    .preview {
+      flex: 1;
+      padding: 14px;
+    }
+    .editor {
+      textarea {
+        width: 100%;
+        height: 100%;
+        resize: none;
+      }
+    }
+    :deep(.preview) {
+      overflow: auto;
+      /* 通用标题样式 */
+      h1,
+      h2,
+      h3,
+      h4,
+      h5,
+      h6 {
+        font-family:
+          -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
+          Arial, sans-serif;
+        font-weight: 600;
+        line-height: 1.25;
+        margin-top: 1.5em;
+        margin-bottom: 0.5em;
+        color: #222;
+      }
+
+      /* H1 样式 */
+      h1 {
+        font-size: 2em;
+        border-bottom: 1px solid #eaecef;
+        padding-bottom: 0.3em;
+        margin-top: 0;
+      }
+
+      /* H2 样式 */
+      h2 {
+        font-size: 1.5em;
+        border-bottom: 1px solid #eaecef;
+        padding-bottom: 0.3em;
+      }
+
+      /* H3 样式 */
+      h3 {
+        font-size: 1.25em;
+      }
+
+      /* H4 样式 */
+      h4 {
+        font-size: 1em;
+      }
+
+      /* H5 样式 */
+      h5 {
+        font-size: 0.875em;
+      }
+
+      /* H6 样式 */
+      h6 {
+        font-size: 0.85em;
+        color: #6a737d;
+      }
+      /* 默认链接样式 */
+      a {
+        color: #0366d6; /* 链接颜色 */
+        text-decoration: none; /* 去掉下划线 */
+        transition: color 0.2s; /* 颜色过渡效果 */
+        /* 鼠标悬停样式 */
+        &:hover {
+          color: #0550a8; /* 悬停颜色 */
+          text-decoration: underline; /* 显示下划线 */
+        }
+        /* 已访问链接 */
+        &:visited {
+          color: #5a32a3; /* 紫色表示已访问 */
+        }
+
+        /* 活动链接 (点击时) */
+        &:active {
+          color: #d63384;
+        }
+      }
+
+      /*
+ * 暗色系代码块样式
+ * 适用于夜间/暗色模式的代码展示
+ */
+
+      // 基础代码块样式
+      pre {
+        background-color: #1e1e1e; // 深灰背景
+        border-radius: 6px; // 圆角
+        padding: 1.25rem; // 内边距
+        margin: 1.5rem 0; // 外边距
+        overflow: auto; // 溢出滚动
+        border: 1px solid #333; // 边框
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); // 阴影效果
+
+        // 代码内容样式
+        code {
+          display: block;
+          color: #d4d4d4; // 主文本颜色
+          font-family:
+            'Fira Code', 'Consolas', 'Monaco', monospace; // 等宽字体栈
+          font-size: 0.95em;
+          line-height: 1.5;
+          text-shadow: none;
+          white-space: pre;
+        }
+      }
+    }
+  }
+}
+</style>