소스 검색

feat:新增首页日志查询,动态表单展示改造

hanyang 1 년 전
부모
커밋
7a0c872ca0

+ 117 - 0
src/components/Editor copy 2.vue

@@ -0,0 +1,117 @@
+<template>
+  <Editor
+    v-model="valueHtml"
+    :defaultConfig="editorConfig"
+    :mode="mode"
+    @onCreated="handleCreated"
+    :style="editor_style"
+  />
+</template>
+
+<script setup>
+import '@wangeditor/editor/dist/css/style.css'; // 引入 css
+
+import { onBeforeUnmount, ref, shallowRef, onMounted, watch } from 'vue';
+import { Editor } from '@wangeditor/editor-for-vue';
+const props = defineProps({
+  content: {
+    type: String,
+    default: '欢迎ccccccccccccccccccc'
+  },
+  editor_style: {
+    type: Object,
+    default: () => {
+      return {
+        width: '100%',
+        height: '100%',
+        padding: '10px 20px'
+      };
+    }
+  }
+});
+
+// 编辑器实例,必须用 shallowRef
+const editorRef = shallowRef();
+
+// 内容 HTML
+const valueHtml = ref(props.content);
+
+watch(
+  () => props.content,
+  (val) => {
+    valueHtml.value = props.content;
+  },
+  {
+    immediate: true
+  }
+);
+
+const editorConfig = {
+  placeholder: '请输入内容...',
+  toolbarConfig: {}, // 可以根据需求配置工具栏
+  toolbarConfig: {
+    // 添加自定义按钮
+    customButtons: [
+      {
+        key: 'printSelectedText', // 自定义按钮的key
+        title: '打印选中文本',
+        iconSvg: '<svg>...</svg>', // 按钮的图标,可以是SVG图标
+        onClick: () => {
+          const editor = editorRef.value;
+          const selectedText = editor.selection.getText(); // 获取选中的文本
+          console.log('选中的文本:', selectedText); // 打印选中的文本
+        }
+      }
+    ]
+  },
+  hoverbarKeys: {
+    text: {
+      menuKeys: [
+        'bold', // 加粗
+        'italic', // 斜体
+        'underline', // 下划线
+        'bulletedList', // 无序列表
+        'numberedList', // 有序列表
+        'customButton' // 新增的自定义按钮
+      ]
+    },
+    image: {
+      menuKeys: [
+        // "editImage",// 编辑图片
+        'deleteImage' // 删除图片
+      ]
+    }
+  }
+};
+
+// 组件销毁时,也及时销毁编辑器
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+
+const handleCreated = (editor) => {
+  editorRef.value = editor; // 记录 editor 实例,重要!
+  console.log(editor);
+  // 绑定自定义按钮的事件
+  // editor.addMenu([
+  //   {
+  //     key: 'customButton', // 自定义按钮的key
+  //     title: '打印选中文本', // 按钮显示的标题
+  //     iconSvg: '<svg>...</svg>', // 自定义按钮图标(你可以用SVG)
+  //     onClick: () => {
+  //       const selectedText = editor.selection.getText(); // 获取选中的文本
+  //       console.log('选中的文本:', selectedText); // 打印选中的文本
+  //     }
+  //   }
+  // ]);
+};
+</script>
+
+<style>
+.editor {
+  border: 1px solid #ccc;
+  padding: 20px;
+}
+</style>

+ 100 - 0
src/components/Editor copy.vue

@@ -0,0 +1,100 @@
+<template>
+  <Editor
+    v-model="valueHtml"
+    :defaultConfig="editorConfig"
+    :mode="mode"
+    @onCreated="handleCreated"
+    :style="editor_style"
+  />
+  <!-- </div> -->
+</template>
+<script setup>
+import '@wangeditor/editor/dist/css/style.css'; // 引入 css
+
+import { onBeforeUnmount, ref, shallowRef, onMounted, watch } from 'vue';
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+const props = defineProps({
+  content: {
+    type: String,
+    default: '欢迎'
+  },
+  editor_style: {
+    type: Object,
+    default: () => {
+      return {
+        width: '100%',
+        height: '100%',
+        // overflow: 'hidden'
+        padding: '10px 20px'
+      };
+    }
+  }
+});
+
+// 编辑器实例,必须用 shallowRef
+const editorRef = shallowRef();
+
+// 内容 HTML
+const valueHtml = ref(props.content);
+
+watch(
+  () => props.content,
+  (val) => {
+    valueHtml.value = props.content;
+  },
+  {
+    immediate: true
+  }
+);
+
+// 模拟 ajax 异步获取内容
+// onMounted(() => {
+//   setTimeout(() => {
+//     // valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>';
+//   }, 1500);
+// });
+
+const toolbarConfig = {};
+toolbarConfig;
+const editorConfig = { placeholder: '请输入内容...', toolbarConfig };
+
+// 组件销毁时,也及时销毁编辑器
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+
+const handleCreated = (editor) => {
+  editorRef.value = editor; // 记录 editor 实例,重要!
+  console.log('editor', editor.getConfig().hoverbarKeys);
+  addCustomBtn(editor);
+};
+// 当选中的是一个文本时,弹出的工具条中,开头增加一个自定义按钮,单击后可以拿到选中的文本
+const addCustomBtn = (editor) => {
+  // 定义按钮的唯一键
+  const customBtnKey = 'myCustomBtn';
+  console.log(editor);
+  // 注册自定义按钮
+  editor.addMenu({
+    key: customBtnKey, // 自定义按钮的唯一标识
+    iconSvg: '<i class="wangeditor-icon" style="color: #007BFF;">*</i>', // 按钮图标
+    title: '自定义按钮', // 按钮提示文本
+    execute: () => {
+      const selectedText = editor.selection.getText(); // 获取选中的文本
+      console.log('选中的文本:', selectedText); // 输出到控制台
+      alert(`你选中了: ${selectedText}`); // 弹出提示框显示选中的文本
+    }
+  });
+
+  // 将自定义按钮添加到 hoverbar 的文本工具栏菜单中
+  editor.getConfig().hoverbarKeys.text.menuKeys.unshift(customBtnKey);
+};
+</script>
+<style>
+.editor {
+  border: 1px solid #ccc;
+  padding: 20px;
+  /* text-align: left; */
+}
+</style>

+ 55 - 84
src/components/Editor.vue

@@ -1,100 +1,71 @@
 <template>
-  <Editor
-    v-model="valueHtml"
-    :defaultConfig="editorConfig"
-    :mode="mode"
-    @onCreated="handleCreated"
-    :style="editor_style"
-  />
-  <!-- </div> -->
+  <div id="toolbar"></div>
+  <div ref="editorRef" style="border: 1px solid #ccc; height: 500px"></div>
 </template>
+
 <script setup>
+import { onMounted, ref, onUnmounted } from 'vue';
+import { createEditor, createToolbar, Boot } from '@wangeditor/editor';
 import '@wangeditor/editor/dist/css/style.css'; // 引入 css
 
-import { onBeforeUnmount, ref, shallowRef, onMounted, watch } from 'vue';
-import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
-const props = defineProps({
-  content: {
-    type: String,
-    default: '欢迎'
-  },
-  editor_style: {
-    type: Object,
-    default: () => {
-      return {
-        width: '100%',
-        height: '100%',
-        // overflow: 'hidden'
-        padding: '10px 20px'
-      };
-    }
+const editorRef = ref(null);
+let editor = null;
+let toolbarEditor = null;
+
+onMounted(() => {
+  if (editorRef.value) {
+    editor = createEditor({ selector: editorRef.value });
+    toolbarEditor = createToolbar({
+      editor,
+      selector: '#toolbar' // 确保有一个id为toolbar的DOM元素
+    });
   }
+  console.log('editor', editor);
+  console.log(Boot);
 });
 
-// 编辑器实例,必须用 shallowRef
-const editorRef = shallowRef();
+onUnmounted(() => {
+  if (editor) {
+    editor.destroy(); // 销毁编辑器实例
+  }
+  if (toolbarEditor) {
+    toolbarEditor.destroy(); // 销毁工具栏实例(如果有的话)
+  }
+});
 
-// 内容 HTML
-const valueHtml = ref(props.content);
+//自定义菜单
+class MyButtonMenu {
+  // JS 语法
 
-watch(
-  () => props.content,
-  (val) => {
-    valueHtml.value = props.content;
-  },
-  {
-    immediate: true
+  constructor(title, iconSvg, tag, exec) {
+    this.title = title; // 自定义菜单标题
+    this.iconSvg = iconSvg; // 自定义菜单的svg
+    this.tag = tag; //自定义菜单的类型
+    this.exec = exec; //自定义菜单点击的方法
   }
-);
-
-// 模拟 ajax 异步获取内容
-// onMounted(() => {
-//   setTimeout(() => {
-//     // valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>';
-//   }, 1500);
-// });
 
-const toolbarConfig = {};
-toolbarConfig;
-const editorConfig = { placeholder: '请输入内容...', toolbarConfig };
+  // 获取菜单执行时的 value ,用不到则返回空 字符串或 false
+  getValue(editor) {
+    // JS 语法
+    return ' hello ';
+  }
 
-// 组件销毁时,也及时销毁编辑器
-onBeforeUnmount(() => {
-  const editor = editorRef.value;
-  if (editor == null) return;
-  editor.destroy();
-});
+  // 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 false
+  isActive(editor) {
+    // JS 语法
+    return false;
+  }
 
-const handleCreated = (editor) => {
-  editorRef.value = editor; // 记录 editor 实例,重要!
-  console.log('editor', editor.getConfig().hoverbarKeys);
-  addCustomBtn(editor);
-};
-// 当选中的是一个文本时,弹出的工具条中,开头增加一个自定义按钮,单击后可以拿到选中的文本
-const addCustomBtn = (editor) => {
-  // 定义按钮的唯一键
-  const customBtnKey = 'myCustomBtn';
-  console.log(editor);
-  // 注册自定义按钮
-  editor.addMenu({
-    key: customBtnKey, // 自定义按钮的唯一标识
-    iconSvg: '<i class="wangeditor-icon" style="color: #007BFF;">*</i>', // 按钮图标
-    title: '自定义按钮', // 按钮提示文本
-    execute: () => {
-      const selectedText = editor.selection.getText(); // 获取选中的文本
-      console.log('选中的文本:', selectedText); // 输出到控制台
-      alert(`你选中了: ${selectedText}`); // 弹出提示框显示选中的文本
-    }
-  });
+  // 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 false
+  isDisabled(editor) {
+    // JS 语法
+    return false;
+  }
 
-  // 将自定义按钮添加到 hoverbar 的文本工具栏菜单中
-  editor.getConfig().hoverbarKeys.text.menuKeys.unshift(customBtnKey);
-};
-</script>
-<style>
-.editor {
-  border: 1px solid #ccc;
-  padding: 20px;
-  /* text-align: left; */
+  // 点击菜单时触发的函数
+  // exec(editor, value) {                              // JS 语法
+  //     if (this.isDisabled(editor)) return
+  //     editor.insertText(value) // value 即 this.value(editor) 的返回值
+  // }
 }
-</style>
+</script>

+ 47 - 33
src/components/MindMap.vue

@@ -428,46 +428,60 @@ const downloadSVG = () => {
 };
 // 下载为 PNG
 const downloadPNG = () => {
-  const svg = svgRef.value;
-  const svgClone = svg.cloneNode(true); // 克隆原始 SVG
+  const image_type = 'png';
+  const scale = 1;
+  const file_name = 'export.' + image_type;
 
-  // 将 SVG 转换为 Canvas
-  const canvas = document.createElement('canvas');
-  const ctx = canvas.getContext('2d');
+  const n = svgRef.value;
 
-  const svgData = new XMLSerializer().serializeToString(svgClone);
-  const img = new Image();
+  const r = new XMLSerializer();
+  var o = r.serializeToString(n);
+
+  const l = o.match(/\<g transform="translate\(.+?,(.+?)\) scale\((.+?)\)"/),
+    c = parseFloat(l[2]),
+    h = Math.round(parseFloat(l[1]) / c) * scale;
+  const g = n.getBBox();
 
-  // 如果是跨域加载,设置 crossOrigin
-  img.crossOrigin = 'Anonymous'; // 设置跨域请求,允许加载外部资源
+  Math.round(g.x);
 
-  // 使用 Blob 转换为图片
-  const svgBlob = new Blob([svgData], { type: 'image/svg+xml' });
-  const url = URL.createObjectURL(svgBlob);
-  console.log(url);
+  const y = Math.round(g.y),
+    v = Math.round(g.width),
+    M = Math.round(g.height),
+    D = Math.round(y / c) * scale,
+    O = Math.round(v / c) * scale,
+    I = Math.round(M / c) * scale;
+
+  o = o.replace(
+    /\<g transform="translate\((.+?)\) scale\((.+?)\)"/,
+    `<g transform="translate(0,${h}) scale(${scale})"`
+  );
+  o = o.replace(/<svg ([^>]+?)( height=".+?")(.*?)>/, '<svg $1$2>');
+  o = o.replace(/<svg /, `<svg width="${O}" height="${I}" viewBox="0 ${D} ${O + 8} ${I + 8}" `);
+
+  const img = new Image();
+  img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(o)}`;
 
   img.onload = () => {
-    // 确保加载完成后进行绘制
-    canvas.width = img.width;
-    canvas.height = img.height;
-
-    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空 Canvas
-    ctx.drawImage(img, 0, 0);
-    console.log('canvas', canvas);
-    // 转换为 PNG 数据
-    canvas.toBlob((blob) => {
-      // 创建下载链接
-      const link = document.createElement('a');
-      const url = URL.createObjectURL(blob);
-      link.href = url;
-      link.download = 'mindmap.png'; // 设置下载文件名
-      link.click();
-      URL.revokeObjectURL(url); // 清理 URL 对象
-    }, 'image/png');
-  };
+    const canvas = document.createElement('canvas');
+    const ctx = canvas.getContext('2d');
+
+    canvas.width = O + 16;
+    canvas.height = I + 16;
+
+    ctx.fillStyle = 'white';
+    ctx.fillRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(img, 0, 0, O, I, 8, 8, O, I);
 
-  // 设置图片的 source 为生成的 Blob URL
-  img.src = url;
+    const down_href = canvas.toDataURL('image/' + image_type);
+
+    const ele_a = document.createElement('a');
+    ele_a.style.display = 'none';
+    ele_a.href = down_href;
+    ele_a.download = file_name;
+    document.body.appendChild(ele_a);
+    ele_a.click();
+    setTimeout(() => ele_a.remove(), 1);
+  };
 };
 watch(
   () => props.content,

+ 1 - 0
src/modules/conversation-aside/web-page/Web-page-list.vue

@@ -18,6 +18,7 @@
       </div>
     </div>
   </div>
+  <a-empty v-if="!page_list.length" />
 </template>
 
 <script setup>

+ 1 - 0
src/modules/conversation-chat/use-conversation-chat-parameters.js

@@ -37,6 +37,7 @@ export default function useConversationChatParameters() {
           const res_config = res.data; // 历史记录列表
 
           conversation_params.value = res_config;
+          console.log(conversation_params.value);
           // api请求成功
           api_status.value = 3;
           api_message.value = 'success';

+ 49 - 13
src/modules/form-dynamic/BtnConfigDynamic.vue

@@ -5,25 +5,34 @@
 
   <a-modal
     v-model:visible="visible"
-    @ok="handleOk"
-    @cancel="handleCancel"
+    :mask-closable="false"
+    :closable="false"
+    :hide-cancel="is_init_model"
+    :hide-ok="is_init_model"
     modal-class="dynamicform-config-container-modal"
     body-class="dynamicform-config-container-body"
   >
     <template #title> <img class="chujuan-logo-img" :src="logo" /> {{ $t('wendangchujuan.dynamic_title') }} </template>
 
     <!-- <DynamicFormWraper ref="confForm" /> -->
-    <DynamicFormBasic ref="confForm" :form_params="user_input_form" />
+    <DynamicFormBasic
+      ref="confForm"
+      :is_init_model="is_init_model"
+      :form_params="user_input_form"
+      @submitForm="submitForm"
+      @toCancel="toCancel"
+    />
   </a-modal>
 </template>
 
 <script setup>
-import { ref } from 'vue';
+import { ref, onMounted, computed } from 'vue';
 
 import logo from '../../assets/1.png';
 
 // import DynamicFormWraper from '../form-dynamic/DynamicFormWraper.vue';
 import DynamicFormBasic from './dynamicformbasic.vue';
+import { Message } from '@arco-design/web-vue';
 
 const props = defineProps({
   user_input_form: Array
@@ -33,22 +42,40 @@ const emits = defineEmits(['confirm']);
 
 const confForm = ref(null);
 const visible = ref(false);
-
+// const ok_text = computed(() => {
+//   return is_init_model.value ? '开始对话' : '确认';
+// });
+const is_init_model = ref(false); //是否是初始的配置
 const handleClick = () => {
   visible.value = true;
+  is_init_model.value = false;
 };
-const handleOk = () => {
-  const target = confForm.value;
-  if (target && typeof target.getValues === 'function') {
-    const data = target.getValues();
-    emits('confirm', data);
-  }
+// const handleOk = () => {
+//   const target = confForm.value;
+//   if (target && typeof target.getValues === 'function') {
+//     const data = target.getValues();
+//     console.log('data', data);
+//     emits('confirm', data);
+//   }
 
+//   visible.value = false;
+// };
+const toCancel = () => {
   visible.value = false;
 };
-const handleCancel = () => {
+const submitForm = (data) => {
+  console.log(data, 111);
+  emits('confirm', data);
   visible.value = false;
+  is_init_model.value = false;
 };
+
+onMounted(() => {
+  if (props.user_input_form.length) {
+    visible.value = true;
+    is_init_model.value = true;
+  }
+});
 </script>
 
 <style scoped>
@@ -65,7 +92,7 @@ const handleCancel = () => {
 
 <style>
 .dynamicform-config-container-modal.arco-modal {
-  width: 50%;
+  width: 40%;
 }
 .dynamicform-config-container-body.arco-modal-body {
   padding: 30px;
@@ -76,4 +103,13 @@ const handleCancel = () => {
   width: 100%;
   height: 80vh;
 }
+.dynamicform-config-container-modal.arco-modal .arco-modal-header {
+  background-color: #f3f3f3;
+}
+.dynamicform-config-container-modal.arco-modal .arco-modal-header .arco-modal-title {
+  justify-content: flex-start;
+}
+.dynamicform-config-container-modal.arco-modal .arco-modal-footer .arco-btn {
+  display: none;
+}
 </style>

+ 23 - 4
src/modules/form-dynamic/DynamicFormBasic.vue

@@ -5,6 +5,7 @@
       :style="{ width: '100%' }"
       :rules="form_rules"
       class="dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk"
+      @submit="handleSubmit"
     >
       <template v-for="(item, index) of form_fields">
         <!-- 单行文本:数字 -->
@@ -88,6 +89,15 @@
             </template>
           </a-upload>
         </a-form-item>
+        <!-- 提交按钮 -->
+        <a-form-item>
+          <a-button class="btn_1" style="margin-right: 10px" type="primary" html-type="submit" v-if="is_init_model"
+            >开始对话</a-button
+          >
+          <a-button class="btn_1" style="margin-right: 10px" type="primary" html-type="submit" v-else>保存</a-button>
+
+          <a-button class="btn_1" html-type="submit" v-if="!is_init_model" @click="handleCancel">取消</a-button>
+        </a-form-item>
       </template>
     </a-form>
   </div>
@@ -108,9 +118,13 @@ const props = defineProps({
    * 配置项
    * 数据结构,可查看同目录下的 dynamic-form-params.md 文件
    */
-  form_params: Array
+  form_params: Array,
+  /**
+   * 是否是点击智能体打开的弹框,还是点击参数配置按钮打开的弹框
+   * */
+  is_init_model: Boolean
 });
-
+const emit = defineEmits(['submitForm', 'toCancel']);
 /**
  * 表单的所有值
  */
@@ -283,8 +297,13 @@ const handleFileChange = (item, event) => {
   // form_values[field_key] = event;
 };
 
-const handleSubmit = (data) => {
-  console.log(data);
+const handleSubmit = ({ values, errors }) => {
+  if (!errors) {
+    emit('submitForm', getFormFiledValues());
+  }
+};
+const handleCancel = () => {
+  emit('toCancel');
 };
 
 /**

+ 12 - 2
src/views/Home.vue

@@ -3,7 +3,14 @@
 
   <div class="box">
     <Editor></Editor>
-    <!-- <MindMap :content="mindMap_content" :box_style="box_style" :svg_style="svg_style" @extend="extend"></MindMap> -->
+    <!-- <MindMap
+      ref="mind_map"
+      :content="mindMap_content"
+      :box_style="box_style"
+      :svg_style="svg_style"
+      @extend="extend"
+    ></MindMap> -->
+    <button type="submit" @click="toUpload">22222222</button>
   </div>
 </template>
 
@@ -17,7 +24,7 @@ const isFullScreen = ref(false);
 const toFullScreen = () => {
   isFullScreen.value = !isFullScreen.value;
 };
-
+const mind_map = ref(null);
 const mindMap_content = ref('');
 const test_mk_str = `
 # 一体机 (AIO)\n## 定义\n- 集成系统\n  - 显示器\n    - 基本特点\n      - 显示技术\n        - 液晶显示器(LCD)\n          - TN\n          - IPS\n          - VA\n        - 有机发光二极管显示器(OLED)\n        - 微型LED显示器(MicroLED)\n      - 分辨率\n        - 1080p (1920x1080)\n        - 2K (2560x1440)\n        - 4K (3840x2160)\n      - 刷新率\n        - 60Hz\n        - 75Hz\n        - 120Hz\n        - 144Hz\n      - 响应时间\n        - 减少图像拖影\n        - 提高动态画面清晰度\n      - 接口类型\n        - VGA\n        - DVI\n        - HDMI\n        - DisplayPort\n    - 分类\n      - 按用途\n        - 普通显示器\n        - 专业显示器\n        - 游戏显示器\n      - 按尺寸\n        - 21.5英寸\n        - 24英寸\n        - 27英寸\n        - 32英寸\n      - 按曲率\n        - 平面显示器\n        - 曲面显示器\n    - 适用范围\n      - 个人电脑\n      - 笔记本电脑\n      - 电视\n      - 手机\n      - 平板电脑\n  - 主板\n  - 处理器\n  - 内存\n  - 存储设备\n  - 电源\n## 特点\n- 紧凑设计\n  - 节省空间\n  - 整洁环境\n- 易于安装和维护\n  - 快速连接\n  - 集成组件\n- 外观美观\n  - 现代化设计\n  - 适合装饰\n- 性能多样\n  - 办公应用\n  - 图形处理\n  - 游戏\n- 扩展性有限\n  - 内部空间小\n  - 升级能力低\n## 适用范围\n- 办公\n- 家庭娱乐\n- 教育\n
@@ -66,6 +73,9 @@ const extend = (item) => {
     mindMap_content.value = test_mk_str_extend;
   }, 1000);
 };
+const toUpload = () => {
+  mind_map.value.downloadPNG();
+};
 onMounted(() => {
   mindMap_content.value = test_mk_str;
 });