allen vor 2 Jahren
Ursprung
Commit
e092fb06f2

+ 44 - 0
src/api/extract/subTaskDetail.js.bak

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询知识抽取子任务明细列表
+export function listSubTaskDetail(query) {
+  return request({
+    url: '/extract/subTaskDetail/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询知识抽取子任务明细详细
+export function getSubTaskDetail(id) {
+  return request({
+    url: '/extract/subTaskDetail/' + id,
+    method: 'get'
+  })
+}
+
+// 新增知识抽取子任务明细
+export function addSubTaskDetail(data) {
+  return request({
+    url: '/extract/subTaskDetail',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改知识抽取子任务明细
+export function updateSubTaskDetail(data) {
+  return request({
+    url: '/extract/subTaskDetail',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除知识抽取子任务明细
+export function delSubTaskDetail(id) {
+  return request({
+    url: '/extract/subTaskDetail/' + id,
+    method: 'delete'
+  })
+}

+ 10 - 0
src/api/knowledge/search.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询实体管理列表
+export function getGraphByEntiry(query) {
+  return request({
+    url: '/kg/getRelationByName',
+    method: 'get',
+    params: query
+  })
+}

+ 119 - 0
src/components/Echarts/chartByD3.vue

@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8" />
+    <title>Knowledge Graph Example</title>
+    <script src="https://unpkg.com/vue@3.2.13/dist/vue.global.js"></script>
+    <script src="https://d3js.org/d3.v6.min.js"></script>
+    <style>
+      .node {
+        fill: #ccc;
+        stroke: #fff;
+        stroke-width: 2px;
+      }
+
+      .link {
+        stroke: #999;
+        stroke-opacity: 0.6;
+      }
+
+      .label {
+        font-family: sans-serif;
+        font-size: 12px;
+        fill: #000;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="app">
+      <svg ref="svg" width="600" height="400"></svg>
+    </div>
+
+    <script>
+      const app = Vue.createApp({
+        data() {
+          return {
+            nodes: [
+              { id: "A", group: 1, name: "Node A" },
+              { id: "B", group: 2, name: "Node B" },
+              { id: "C", group: 3, name: "Node C" },
+              { id: "D", group: 2, name: "Node D" },
+              { id: "E", group: 1, name: "Node E" },
+            ],
+            links: [
+              { source: "A", target: "B", name: "Link AB" },
+              { source: "B", target: "C", name: "Link BC" },
+              { source: "C", target: "D", name: "Link CD" },
+              { source: "D", target: "E", name: "Link DE" },
+              { source: "E", target: "A", name: "Link EA" },
+            ],
+            width: 600,
+            height: 400,
+          };
+        },
+        mounted() {
+          const svg = d3.select(this.$refs.svg);
+
+          const node = svg
+            .selectAll(".node")
+            .data(this.nodes)
+            .enter()
+            .append("circle")
+            .attr("class", "node")
+            .attr("r", 20);
+
+          const link = svg
+            .selectAll(".link")
+            .data(this.links)
+            .enter()
+            .append("line")
+            .attr("class", "link")
+            .attr("stroke-width", 2);
+
+          const nodeLabel = svg
+            .selectAll(".node-label")
+            .data(this.nodes)
+            .enter()
+            .append("text")
+            .attr("class", "label")
+            .text((d) => d.name);
+
+          const linkLabel = svg
+            .selectAll(".link-label")
+            .data(this.links)
+            .enter()
+            .append("text")
+            .attr("class", "label")
+            .text((d) => d.name);
+
+          const simulation = d3
+            .forceSimulation(this.nodes)
+            .force(
+              "link",
+              d3
+                .forceLink(this.links)
+                .id((d) => d.id)
+                .distance(80)
+            )
+            .force("charge", d3.forceManyBody().strength(-200))
+            .force("center", d3.forceCenter(this.width / 2, this.height / 2));
+
+          node.append("title").text((d) => d.id);
+          simulation.on("tick", () => {
+            node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
+            link
+              .attr("x1", (d) => d.source.x)
+              .attr("y1", (d) => d.source.y)
+              .attr("x2", (d) => d.target.x)
+              .attr("y2", (d) => d.target.y);
+            nodeLabel.attr("x", (d) => d.x).attr("y", (d) => d.y + 30);
+            linkLabel
+              .attr("x", (d) => (d.source.x + d.target.x) / 2)
+              .attr("y", (d) => (d.source.y + d.target.y) / 2);
+          });
+        },
+      });
+      app.mount("#app");
+    </script>
+  </body>
+</html>

+ 278 - 0
src/views/extract/subTaskDetail/index.vue.bak

@@ -0,0 +1,278 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="子任务id" prop="subTaskId">
+        <el-input
+          v-model="queryParams.subTaskId"
+          placeholder="请输入子任务id"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="关系" prop="relation">
+        <el-input
+          v-model="queryParams.relation"
+          placeholder="请输入关系"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['extract:subTaskDetail:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['extract:subTaskDetail:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['extract:subTaskDetail:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['extract:subTaskDetail:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="subTaskDetailList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="子任务id" align="center" prop="subTaskId" />
+      <el-table-column label="起点实体" align="center" prop="start" />
+      <el-table-column label="关系" align="center" prop="relation" />
+      <el-table-column label="终点实体" align="center" prop="end" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['extract:subTaskDetail:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['extract:subTaskDetail:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改知识抽取子任务明细对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="子任务id" prop="subTaskId">
+          <el-input v-model="form.subTaskId" placeholder="请输入子任务id" />
+        </el-form-item>
+        <el-form-item label="起点实体" prop="start">
+          <el-input v-model="form.start" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="关系" prop="relation">
+          <el-input v-model="form.relation" placeholder="请输入关系" />
+        </el-form-item>
+        <el-form-item label="终点实体" prop="end">
+          <el-input v-model="form.end" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listSubTaskDetail, getSubTaskDetail, delSubTaskDetail, addSubTaskDetail, updateSubTaskDetail } from "@/api/extract/subTaskDetail";
+
+export default {
+  name: "SubTaskDetail",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 知识抽取子任务明细表格数据
+      subTaskDetailList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        subTaskId: null,
+        start: null,
+        relation: null,
+        end: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        subTaskId: [
+          { required: true, message: "子任务id不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询知识抽取子任务明细列表 */
+    getList() {
+      this.loading = true;
+      listSubTaskDetail(this.queryParams).then(response => {
+        this.subTaskDetailList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        subTaskId: null,
+        start: null,
+        relation: null,
+        end: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加知识抽取子任务明细";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getSubTaskDetail(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改知识抽取子任务明细";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateSubTaskDetail(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addSubTaskDetail(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除知识抽取子任务明细编号为"' + ids + '"的数据项?').then(function() {
+        return delSubTaskDetail(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('extract/subTaskDetail/export', {
+        ...this.queryParams
+      }, `subTaskDetail_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>

+ 101 - 0
src/views/knowledge/search/chartByD3.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="app-container" ref="svgContainer"></div>
+</template>
+
+<script>
+import * as d3 from 'd3';
+
+export default {
+  mounted() {
+    const svgContainer = this.$refs.svgContainer;
+    const width = svgContainer.clientWidth;
+    const height = svgContainer.clientHeight;
+
+    const links = [
+      { source: "A", target: "B", value: 1 },
+      { source: "A", target: "C", value: 2 },
+      { source: "B", target: "C", value: 3 },
+      { source: "B", target: "D", value: 4 },
+      { source: "C", target: "D", value: 5 },
+    ];
+
+    const nodes = [
+      { id: "A", x: 100, y: 100 },
+      { id: "B", x: 200, y: 100 },
+      { id: "C", x: 150, y: 200 },
+      { id: "D", x: 250, y: 200 },
+    ];
+
+    const svg = d3.select(svgContainer).append("svg")
+      .attr("width", width)
+      .attr("height", height);
+
+    const link = svg.selectAll("line")
+      .data(links)
+      .join("line")
+      .attr("stroke", "black")
+      .attr("stroke-width", d => d.value);
+
+    const node = svg.selectAll("circle")
+      .data(nodes)
+      .join("circle")
+      .attr("r", 20)
+      .attr("fill", "red")
+      .call(drag(simulation));
+
+    const label = svg.selectAll("text")
+      .data(nodes)
+      .join("text")
+      .text(d => d.id)
+      .attr("x", d => d.x)
+      .attr("y", d => d.y);
+
+    const simulation = d3.forceSimulation(nodes)
+      .force("link", d3.forceLink(links).id(d => d.id))
+      .force("charge", d3.forceManyBody())
+      .force("center", d3.forceCenter(width / 2, height / 2));
+
+    simulation.on("tick", () => {
+      link
+        .attr("x1", d => d.source.x)
+        .attr("y1", d => d.source.y)
+        .attr("x2", d => d.target.x)
+        .attr("y2", d => d.target.y);
+
+      node
+        .attr("cx", d => d.x)
+        .attr("cy", d => d.y);
+
+      label
+        .attr("x", d => d.x)
+        .attr("y", d => d.y - 25);
+    });
+
+    function drag(simulation) {
+
+      function dragstarted(event) {
+        if (!event.active) simulation.alphaTarget(0.3).restart();
+        event.subject.fx = event.subject.x;
+        event.subject.fy = event.subject.y;
+      }
+
+      function dragged(event) {
+        event.subject.fx = event.x;
+        event.subject.fy = event.y;
+      }
+
+      function dragended(event) {
+        if (!event.active) simulation.alphaTarget(0);
+        event.subject.fx = null;
+        event.subject.fy = null;
+      }
+
+      return d3.drag()
+        .on("start", dragstarted)
+        .on("drag",
+          dragged)
+        .on("end", dragended);
+    }
+  }
+}
+</script>

+ 107 - 0
src/views/knowledge/search/chartByD3v1.vue

@@ -0,0 +1,107 @@
+<template>
+  <div class="app-container" ref="svgContainer"></div>
+</template>
+
+<script>
+import * as d3 from 'd3';
+
+export default {
+  mounted() {
+    const svgContainer = this.$refs.svgContainer;
+    const width = svgContainer.clientWidth;
+    const height = svgContainer.clientHeight;
+
+    const links = [
+      { source: "A", target: "B", value: 1 },
+      { source: "A", target: "C", value: 2 },
+      { source: "B", target: "C", value: 3 },
+      { source: "B", target: "D", value: 4 },
+      { source: "C", target: "D", value: 5 },
+    ];
+
+    const nodes = [
+      { id: "A", x: 100, y: 100 },
+      { id: "B", x: 200, y: 100 },
+      { id: "C", x: 150, y: 200 },
+      { id: "D", x: 250, y: 200 },
+    ];
+
+    const svg = d3.select(svgContainer).append("svg")
+      .attr("width", width)
+      .attr("height", height);
+
+    const link = svg.selectAll("line")
+      .data(links)
+      .join("line")
+      .attr("stroke", "black")
+      .attr("stroke-width", d => d.value);
+
+    const node = svg.selectAll("circle")
+      .data(nodes)
+      .join("circle")
+      .attr("r", 20)
+      .attr("fill", "red")
+      .call(drag(simulation));
+
+    const label = svg.selectAll("text")
+      .data(nodes)
+      .join("text")
+      .text(d => d.id)
+      .attr("x", d => d.x)
+      .attr("y", d => d.y);
+
+    const simulation = d3.forceSimulation(nodes)
+      .force("link", d3.forceLink(links).id(d => d.id))
+      .force("charge", d3.forceManyBody())
+      .force("center", d3.forceCenter(width / 2, height / 2));
+
+    simulation.on("tick", () => {
+      link
+        .attr("x1", d => d.source.x)
+        .attr("y1", d => d.source.y)
+        .attr("x2", d => d.target.x)
+        .attr("y2", d => d.target.y);
+
+      node
+        .attr("cx", d => d.x)
+        .attr("cy", d => d.y);
+
+      label
+        .attr("x", d => d.x)
+        .attr("y", d => d.y - 25);
+    });
+
+    function drag(simulation) {
+
+      function dragstarted(event) {
+        if (!event.active) simulation.alphaTarget(0.3).restart();
+        event.subject.fx = event.subject.x;
+        event.subject.fy = event.subject.y;
+      }
+
+      function dragged(event) {
+        event.subject.fx = event.x;
+        event.subject.fy = event.y;
+      }
+
+      function dragended(event) {
+        if (!event.active) simulation.alphaTarget(0);
+        event.subject.fx = null;
+        event.subject.fy = null;
+      }
+
+      return d3.drag()
+        .on("start", dragstarted)
+        .on("drag",
+          dragged)
+        .on("end", dragended);
+    }
+  }
+}
+</script>
+
+<style>
+svg {
+  background-color: #eee;
+}
+</style>

+ 175 - 0
src/views/knowledge/search/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="app-container">
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item prop="firstName">
+        <el-input
+          v-model="queryParams.firstName"
+          placeholder="请输入"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item prop="secondName">
+        <el-input
+          v-model="queryParams.secondName"
+          placeholder="请输入"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item prop="length">
+        <!-- <el-input
+          v-model="queryParams.length"
+          placeholder="请输入"
+          clearable
+          @keyup.enter.native="handleQuery"
+        /> -->
+        <el-select v-model="queryParams.length" placeholder="请选择任务状态">
+          <el-option
+            v-for="dict in dict.type.graph_search_length"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"
+          >搜索</el-button
+        >
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <Chart
+      ref="chart"
+      @changeRoot="redrawChart"
+      @c_click="getInfoTooltip"
+      :isShowChart="true"
+      :enable="true"
+      @reloadChart="reloadChart"
+      :showRelKey="true"
+      :nodes="nodes"
+      :links="links"
+      :isEntChart="true"
+      :contextMenu="['delete']"
+      :isShowContextMenu="true"
+      @delete="delNode"
+    />
+  </div>
+</template>
+
+<script>
+import Chart from "@/views/knowledge/common/chart";
+import { getGraphByEntiry } from "@/api/knowledge/search";
+
+// 获取路径参数
+function getQueryVariable(variable) {
+	let url = window.location.hash
+	let index = url.indexOf('?')
+	var query = url.substring(index + 1, url.length)
+	var vars = query.split('&')
+	for (var i = 0; i < vars.length; i++) {
+		var pair = vars[i].split('=')
+		if (pair[0] == variable) {
+			return pair[1]
+		}
+	}
+	return ''
+}
+
+export default {
+  name: "GranphSearch",
+  dicts: ["graph_search_length"],
+  components: { Chart },
+  data() {
+    return {
+      queryParams: {
+        firstName: "转向机",
+        secondName: "转向轴",
+        length: "0",
+      },
+      nodes: [],
+      links: [],
+      spinning : false,
+      tooltip: { entId: false, relID: false }, // 点击的实体或关系的悬浮层
+      chartType: true,
+    };
+  },
+  methods: {
+    handleQuery() {
+      this.redrawChart()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      alert("clear");
+    },
+    /**
+     * 点击搜索重新绘图
+     * @params id 选中的实力的ID
+     * */
+    redrawChart() {
+      this.spinning = true;
+      getGraphByEntiry(this.queryParams).then((resp) => {
+        let respData = resp.data
+        this.rootId = 1;
+        this.tooltip.entId = false;
+        this.tooltip.relID = false;
+        this.nodes = respData.data;
+        this.links = respData.links;
+        this.$refs.chart.reDraw(1, respData.data, respData.links);
+        this.spinning = false;
+      });
+    },
+    /**
+     * 获取实体或关系的悬浮框
+     * @params event:zoomchart返回的event,args:zoomchart返回的变量,包含了当前点击的实体或关系的数据
+     * */
+    getInfoTooltip(event, args) {
+      const vm = this;
+      this.$set(this.tooltip, "x", event.pageX + "px");
+      this.$set(this.tooltip, "y", event.pageY + "px");
+      if (args.clickNode) {
+        vm.tooltip.entId = args.clickNode.data.entId;
+        vm.tooltip.relID = false;
+      } else if (args.clickLink) {
+        vm.tooltip.entId = false;
+        vm.tooltip.relID = args.clickLink.data.relID;
+      } else {
+        vm.tooltip.entId = false;
+        vm.tooltip.relID = false;
+      }
+    },
+    reloadChart(nodes, links) {
+      const id = getQueryVariable("entId");
+      this.$refs.chart.drawChart(id, nodes, links);
+    },
+    // 选中一个图谱节点后的回调,排除
+    delNode(item) {
+      if (item[0].id == this.rootId) {
+        this.$message.info("中心点不能删除");
+        return;
+      }
+      if (this.delEntIds.length > 0) {
+        this.delEntIds.forEach((v, i) => {
+          if (v.id !== item[0].id) {
+            this.delEntIds.push(item[0]);
+          }
+        });
+      } else {
+        this.delEntIds.push(item[0]);
+      }
+      getGraphByEntiry(this.queryParams).then((resp) => {
+        let respData = resp.data
+        this.$refs.chart.reDraw(1, respData.data, respData.links);
+      });
+    },
+  },
+};
+</script>