zhengnaiwen_citu 1 月之前
父节点
当前提交
fbaac26b74

+ 42 - 0
src/api/dataGovernance.js

@@ -223,6 +223,45 @@ const dataIndicator = {
   }
 }
 
+const dataFlow = {
+  // 获取数据流列表
+  getDataFlowList: (param) => {
+    return http.get('/dataflow/get-dataflows-list', param)
+  },
+  // 获取数据流详情
+  getDataFlowDetails: (id) => {
+    return http.get(`/dataflow/get-dataflow/${id}`)
+  },
+  // 新增数据流
+  addDataFlow: (param) => {
+    return http.post('/dataflow/add-dataflow', param)
+  },
+  // 更新数据流
+  updateDataFlow: (id, param) => {
+    return http.put(`/dataflow/update-dataflow/${id}`, param)
+  },
+  // 删除数据流
+  deleteDataFlow: (id) => {
+    return http.delete(`/dataflow/delete-dataflow/${id}`)
+  },
+  // 运行数据流
+  runDataFlow: (id, param) => {
+    return http.post(`/dataflow/execute-dataflow/${id}`, param)
+  },
+  // 数据流运行进度
+  getDataFlowExecute: (id) => {
+    return http.get(`/dataflow/get-dataflow-status/${id}`)
+  },
+  // 数据流运行日志
+  getDataFlowLog: (id) => {
+    return http.get(`/dataflow/get-dataflow-logs/${id}`)
+  },
+  // AI生成脚本
+  getDataFlowScript: (param) => {
+    return http.post('/dataflow/create-script', param)
+  }
+}
+
 const LLM = {
 
   // 模型训练
@@ -301,6 +340,9 @@ export const api = {
   // 数据指标
   ...dataIndicator,
 
+  // 数据流程
+  ...dataFlow,
+
   // 大语言模型对话接口
   ...LLM,
 

+ 6 - 4
src/views/dataGovernance/dataIndicator/components/edit.vue

@@ -32,6 +32,7 @@
                 @input="updateContent"
               >
               </div>
+              <v-btn class="contenteditable-box-btn" color="primary" @click="handleCodeGenerate" :loading="codeLoading">代码生成</v-btn>
               <div class="labelTxt" :class="{'active': indicator}">指标计算规则</div>
             </div>
           </div>
@@ -45,9 +46,6 @@
               v-model="pythonCode"
               label="指标计算代码段"
             >
-              <template #append>
-                <v-btn class="ml-5" small color="primary" @click="handleCodeGenerate" :loading="codeLoading">代码生成</v-btn>
-              </template>
             </v-textarea>
           </div>
         </div>
@@ -372,6 +370,11 @@ export default {
   $color: #1976D2;
   position: relative;
   height: 100%;
+  &-btn {
+    position: absolute;
+    right: 10px;
+    bottom: 10px;
+  }
   .contenteditable {
     border: 1px solid #999;
     padding: 12px;
@@ -447,5 +450,4 @@ export default {
     z-index:-1;
   }
 }
-
 </style>

+ 96 - 26
src/views/dataGovernance/dataProcess/components/edit.vue

@@ -1,6 +1,6 @@
 <template>
-  <div class="d-flex fullscreen">
-    <v-card style="width: 400px;" class="mr-3 fullHeight"  v-loading="loading">
+  <div class="d-flex fullscreen" v-loading="loading">
+    <v-card style="width: 400px;" class="mr-3 fullHeight">
       <v-banner single-line>
         <div class="py-2 title">方案列表</div>
       </v-banner>
@@ -27,13 +27,24 @@
     <v-card class="width-auto">
       <div class="pa-3 fullscreen">
         <div class="fullscreen d-flex flex-column">
+          <div class="mb-3">
+            <v-text-field
+              outlined
+              dense
+              hide-details
+              label="请输入来源表 *"
+              v-model="changeObj.source_table"
+              placeholder="请输入来源表"
+              :rules="[v => !!v || '请输入来源表']"
+            ></v-text-field>
+          </div>
           <v-card outlined class="height-auto">
             <Toolbar
                 style="border-bottom: 1px solid #ccc"
                 :editor="editor"
                 :defaultConfig="toolbarConfig"
                 :mode="mode"
-            >11</Toolbar>
+            ></Toolbar>
             <Editor
                 style="overflow-y: hidden; height: calc(100% - 100px);"
                 v-model="editorHtml"
@@ -42,12 +53,23 @@
                 @onCreated="onCreated"
             />
             <div class="d-flex align-end justify-end pa-3">
-              <v-btn color="primary">生成代码</v-btn>
+              <v-btn color="primary" @click="onGenerating">生成代码</v-btn>
             </div>
           </v-card>
+          <div class="mt-3">
+            <v-text-field
+              outlined
+              dense
+              hide-details
+              label="请输入目标表 *"
+              v-model="changeObj.target_table"
+              placeholder="请输入目标表"
+              :rules="[v => !!v || '请输入目标表']">
+            </v-text-field>
+          </div>
           <div class="mt-3">
             <v-textarea
-              v-model="code"
+              v-model="changeObj.script_content"
               outlined
               hide-details
               label="请输入执行代码"
@@ -66,24 +88,15 @@
             text
             class="ml-3"
             color="primary"
-            :disabled="submitLoading"
             @click="handleSubmit"
           >
-            <v-progress-circular
-              v-if="submitLoading"
-              indeterminate
-              :size="18"
-              width="2"
-              color="primary"
-              class="mr-1"
-            ></v-progress-circular>
-            <v-icon left v-else>mdi-send-variant</v-icon>
+            <v-icon left>mdi-send-variant</v-icon>
             确认提交
           </v-btn>
         </template>
       </v-banner>
       <div class="pt-3 height-auto overflow-y-auto">
-        <EditBase></EditBase>
+        <EditBase ref="editBaseRefs"></EditBase>
       </div>
     </v-card>
     <v-navigation-drawer
@@ -182,6 +195,9 @@ import '@wangeditor/editor/dist/css/style.css'
 // import NonePage from '@/components/Common/empty.vue'
 import EditBase from './editBase.vue'
 import axios from 'axios'
+import {
+  api
+} from '@/api/dataGovernance'
 export default {
   name: 'editPage',
   components: { Editor, Toolbar, EditBase },
@@ -201,8 +217,6 @@ export default {
       },
       editorConfig: { placeholder: '请输入内容...' },
       mode: 'default', // or 'simple'
-
-      code: null,
       loading: false,
       items: [],
       rulesItems: [],
@@ -211,7 +225,12 @@ export default {
       panelActive: [],
       clickItem: null,
       clickId: null,
-      submitLoading: false
+      changeObj: {
+        script_content: null,
+        script_requirement: null,
+        source_table: null,
+        target_table: null
+      }
     }
   },
   computed: {
@@ -225,8 +244,11 @@ export default {
       return this.clickItem[this.active]
     }
   },
-  created () {
-    this.init()
+  async created () {
+    this.loading = true
+    await this.getList()
+    await this.getDetails()
+    this.loading = false
   },
   beforeDestroy () {
     const editor = this.editor
@@ -237,9 +259,12 @@ export default {
     onCreated (editor) {
       this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
     },
-    async init () {
+    // 详情
+    async getDetails () {
+
+    },
+    async getList () {
       try {
-        this.loading = true
         const { data } = await this.fetchData('/op/base/performance/solution/page', {
           page: {
             size: 999,
@@ -250,8 +275,6 @@ export default {
       } catch (err) {
         this.items = []
         this.$snackbar.error(err)
-      } finally {
-        this.loading = false
       }
     },
     fetchData (url, params) {
@@ -272,7 +295,54 @@ export default {
         }).catch(reject)
       })
     },
-    handleSubmit () {},
+    async onGenerating () {
+      const text = this.editor.getText()
+      if (!text) {
+        this.$snackbar.warning('请输入内容')
+        return
+      }
+      this.loading = true
+      try {
+        const { data } = await api.getDataFlowScript({
+          request_data: text
+        })
+        this.changeObj.script_requirement = text
+        this.changeObj.script_content = data.script_content
+      } catch (error) {
+        this.$snackbar.error(error)
+      } finally {
+        this.loading = false
+      }
+    },
+    async handleSubmit () {
+      const params = this.$refs.editBaseRefs.getValue()
+      if (!params) {
+        return
+      }
+      const { script_content: scriptContent, source_table: sourceTable, target_table: targetTable } = this.changeObj
+      if (!scriptContent) {
+        this.$snackbar.warning('请先生成脚本')
+        return
+      }
+      if (!sourceTable) {
+        this.$snackbar.warning('请先填写来源表')
+        return
+      }
+      if (!targetTable) {
+        this.$snackbar.warning('请先填写目标表')
+        return
+      }
+      try {
+        await api.addDataFlow({
+          ...params,
+          ...this.changeObj
+        })
+        this.$snackbar.success('操作成功')
+        this.$emit('success')
+      } catch (error) {
+        this.$snackbar.error(error)
+      }
+    },
     async onClick (e) {
       this.loading = true
       try {

+ 56 - 48
src/views/dataGovernance/dataProcess/components/editBase.vue

@@ -14,8 +14,8 @@ import MForm from '@/components/MForm'
 // import { combinationTagsPage } from '@/api/dataBook'
 import {
   metadata,
-  frequency,
-  sensitivity
+  frequency
+  // sensitivity
 } from '@/utils/dataGovernance'
 import SearchNodes from '../../components/searchNodes.vue'
 import { api } from '@/api/dataGovernance'
@@ -32,13 +32,14 @@ export default {
     return {
       formValues: {
         name: null,
-        en_name: null,
+        name_en: null,
         category: '应用类',
-        organization: this.$store.getters.userInfo.username,
-        leader: this.$store.getters.userInfo.username,
-        childrenId: [],
-        frequency: '日',
-        data_sensitivity: '低',
+        leader: 'system',
+        organization: null,
+        script_type: 'sql',
+        update_mode: 'append',
+        frequency: '月',
+        // data_sensitivity: '低',
         tag: null,
         describe: null,
         status: true
@@ -56,60 +57,67 @@ export default {
     formItems () {
       return [
         { type: 'text', key: 'name', label: '名称 *', rules: [v => !!v || '请输入名称'] },
-        { type: 'text', key: 'en_name', label: '英文名称 *', rules: [v => !!v || '请输入英文名称'] },
-        { type: 'autocomplete', key: 'category', label: '分类 *', rules: [v => !!v || '请选择分类'], items: metadata },
-        { type: 'text', key: 'organization', label: '所属机构 *', rules: [v => !!v || '请输入所属机构'] },
-        { type: 'text', key: 'leader', label: '负责人 *', rules: [v => !!v || '请输入负责人'] },
+        { type: 'text', key: 'name_en', label: '英文名称 *', rules: [v => !!v || '请输入英文名称'] },
+        { type: 'autocomplete', key: 'category', label: '请选择分类 *', rules: [v => !!v || '请选择分类'], items: [...metadata] },
+        { type: 'text', key: 'leader', label: '创建者 *', rules: [v => !!v || '请输入负责人'] },
+        { type: 'text', key: 'organization', label: '请输入所属机构 *', rules: [v => !!v || '请输入所属机构'] },
         {
-          key: 'childrenId',
-          slotName: 'childrenId',
-          search: null,
-          options: {
-            label: '数据来源',
-            attach: true
-          }
+          type: 'autocomplete',
+          key: 'script_type',
+          label: '脚本类型 *',
+          rules: [v => !!v || '请选择脚本类型'],
+          items: [
+            { label: 'SQL', value: 'sql' },
+            { label: 'Python', value: 'python' },
+            { label: 'PythonScript', value: 'python_script' },
+            { label: 'SQLScript', value: 'sql_script' }
+          ]
+        },
+        {
+          type: 'autocomplete',
+          key: 'update_mode',
+          label: '更新模式 *',
+          rules: [v => !!v || '请选择更新模式'],
+          items: [
+            { label: '追加', value: 'append' },
+            { label: '全量更新', value: 'full_refresh' }
+          ]
+        },
+        { type: 'autocomplete', key: 'frequency', label: '更新频率 *', rules: [v => !!v || '请选择更新频率'], items: [...frequency] },
+        {
+          type: 'autocomplete',
+          key: 'tag',
+          label: '标签',
+          itemText: 'name',
+          itemValue: 'id',
+          items: this.tagItems
         },
-        { type: 'autocomplete', key: 'frequency', label: '更新频率 *', rules: [v => !!v || '请选择更新频率'], items: frequency },
-        { type: 'autocomplete', key: 'data_sensitivity', label: '数据敏感度 *', rules: [v => !!v || '请选择数据敏感度'], items: sensitivity },
-        { type: 'autocomplete', key: 'tag', label: '标签', itemText: 'name', itemValue: 'id', items: this.tagItems },
         { type: 'text', key: 'describe', label: '描述' },
         {
           type: 'ifRadio',
           key: 'status',
           label: '启用',
           width: 120,
-          items: [{ label: '是', value: true }, { label: '否', value: false }]
+          items: [{ label: '是', value: 'active' }, { label: '否', value: 'inactive' }]
         }
       ]
     }
   },
   created () {
     this.init()
-    if (!Object.keys(this.itemData).length) {
-      return
-    }
-    Object.keys(this.formValues).forEach(key => {
-      if (!Object.prototype.hasOwnProperty.call(this.itemData, key)) {
-        return
-      }
-      if (key === 'childrenId') {
-        if (this.itemData.childrenId.length === 1 && this.itemData.childrenId[0].id === null) {
-          return
-        }
-        this.formValues[key] = this.itemData.childrenId.map(e => {
-          return {
-            value: e.id,
-            text: e.name
-          }
-        })
-        return
-      }
-      if (key === 'tag') {
-        this.formValues[key] = this.itemData.tag?.id ?? null
-        return
-      }
-      this.formValues[key] = this.itemData[key]
-    })
+    // if (!Object.keys(this.itemData).length) {
+    //   return
+    // }
+    // Object.keys(this.formValues).forEach(key => {
+    //   if (!Object.prototype.hasOwnProperty.call(this.itemData, key)) {
+    //     return
+    //   }
+    //   if (key === 'tag') {
+    //     this.formValues[key] = this.itemData.tag
+    //     return
+    //   }
+    //   this.formValues[key] = this.itemData[key]
+    // })
   },
   methods: {
     async init () {

+ 42 - 13
src/views/dataGovernance/dataProcess/index.vue

@@ -11,14 +11,22 @@
       :show-select="false"
       :can-delete="false"
       @add="handleAdd"
-      @edit="handleEdit"
-      @delete="handleDelete"
       @pageHandleChange="pageHandleChange"
       @sort="handleSort"
     >
+      <template #status="{ item }">
+        <v-chip small :color="item.status === 'active' ? 'success' : 'error'">
+          {{ item.status === 'active' ? '启用' : '禁用' }}
+        </v-chip>
+      </template>
+      <template #actions="{ item }">
+        <v-btn color="primary" text class="mr-2" @click="onEdit(item)">编辑</v-btn>
+        <v-btn color="success" text class="mr-2"  @click="onRun(item)">运行</v-btn>
+        <v-btn color="error" text  @click="onDelete(item)">删除</v-btn>
+      </template>
     </m-table>
-    <m-dialog :title="title" :visible.sync="show" showDrawer @submit="handleSubmit">
-      <edit-page v-if="show" ref="edit" :item-data="itemData"></edit-page>
+    <m-dialog :title="title" :visible.sync="show" showDrawer :footer="false">
+      <edit-page v-if="show" ref="edit" :item-data="itemData" @success="show = false; init()"></edit-page>
     </m-dialog>
   </div>
 </template>
@@ -28,6 +36,7 @@ import MFilter from '@/components/Filter'
 import MTable from '@/components/List/table.vue'
 import MDialog from '@/components/Dialog'
 import EditPage from './components/edit'
+import { api } from '@/api/dataGovernance'
 export default {
   name: 'template-name',
   components: { MFilter, MTable, MDialog, EditPage },
@@ -37,15 +46,21 @@ export default {
       show: false,
       filter: {
         list: [
-          { type: 'textField', value: '', label: '名称', key: 'name' },
-          { type: 'autocomplete', value: null, label: '选择', key: 'type', items: [] }
+          { type: 'textField', value: '', label: '关键词', key: 'title' }
         ]
       },
       queryData: {
-        name: null
+        title: null
       },
       headers: [
-        { text: '名称', align: 'start', value: 'name' }
+        { text: '中文名称', align: 'start', value: 'name' },
+        { text: '英文名称', align: 'start', value: 'name' },
+        { text: '状态', align: 'center', value: 'status' },
+        { text: '作者', align: 'center', value: 'description' },
+        { text: '描述', align: 'start', value: 'description' },
+        { text: '创建时间', align: 'start', value: 'created_by' },
+        { text: '更新时间', align: 'start', value: 'updated_at' },
+        { text: '操作', align: 'start', value: 'actions' }
       ],
       itemData: {},
       items: [],
@@ -66,7 +81,22 @@ export default {
     this.init()
   },
   methods: {
-    async init () {},
+    async init () {
+      this.loading = true
+      try {
+        const { data } = await api.getDataFlowList({
+          page: this.pageInfo.current,
+          page_size: this.pageInfo.size,
+          search: this.queryData.title || undefined
+        })
+        this.items = data.list
+        this.total = data.pagination.total
+      } catch (error) {
+        this.$snackbar.error(error)
+      } finally {
+        this.loading = false
+      }
+    },
     handleSearch (val) {
       Object.assign(this.queryData, val)
       this.pageInfo.current = 1
@@ -80,11 +110,11 @@ export default {
       this.itemData = item
       this.show = true
     },
-    handleDelete (ids) {
-      if (Array.isArray(ids) && !ids.length) return this.$snackbar.warning('请选择要删除的选项')
+    onDelete ({ id }) {
       this.$confirm('提示', '是否删除该选项')
         .then(async () => {
           try {
+            await api.deleteDataFlow(id)
             this.$snackbar.success('删除成功')
             this.init()
           } catch (error) {
@@ -99,8 +129,7 @@ export default {
     handleSort (val) {
       this.orders = val
       this.init()
-    },
-    handleSubmit () {}
+    }
   }
 }
 </script>