CzRger hai 1 mes
pai
achega
23c1587b06

+ 7 - 1
src/api/modules/center/tenant.ts

@@ -1,4 +1,10 @@
 import { get, post, put, del } from '@/api/request'
 
-// 租户管理分页
+// 租户管理-分页
 export const tenantsPage = (params) => get(`/tenants`, params, {})
+// 租户管理-新增
+export const tenantsAdd = (params) => post(`/tenants`, params, {})
+// 租户管理-编辑
+export const tenantsEdit = (params) => put(`/tenants`, params, {})
+// 租户管理-详情
+export const tenantsDetail = (id) => get(`/tenants/${id}`, {}, {})

+ 9 - 0
src/api/modules/workflow/chart.ts

@@ -0,0 +1,9 @@
+import { get, post, put, del, patch } from '@/api/request'
+
+const proxy = (import.meta as any).env.VITE_WORKFLOW_API_PROXY
+// 查询指定工作流的草稿数据
+export const workflowDraftDetail = (id) =>
+  get(`/workflow/draft/${id}`, {}, {}, proxy)
+// 自动保存
+export const workflowDraftSave = (id) =>
+  post(`/workflow/draft/${id}`, {}, {}, proxy)

+ 14 - 14
src/api/modules/workflow/meta.ts

@@ -1,15 +1,15 @@
-import { get, post, put, del } from '@/api/request'
+import { get, post, put, del, patch } from '@/api/request'
 
-// 用户管理-分页
-export const userPage = (params) => get(`/user`, params, {})
-// 用户管理-新增
-export const userAdd = (params) => post(`/user`, params, {})
-// 用户管理-编辑
-export const userEdit = (params) => put(`/user`, params, {})
-// 用户管理-详情
-export const userDetail = (id) => get(`/user/${id}`, {}, {})
-// 用户管理-删除
-export const userDel = (id) => del(`/user/${id}`, {}, {})
-// 用户管理-生成邀请链接
-export const accountGenerateFriendlyCode = (params) =>
-  get(`/account/generateFriendlyCode`, params, {})
+const proxy = (import.meta as any).env.VITE_WORKFLOW_API_PROXY
+// 工作流-分页
+export const workflowMetaPage = (params) =>
+  post(`/workflow/meta/page`, params, {}, proxy)
+// 工作流-新增
+export const workflowMetaAdd = (params) =>
+  post(`/workflow/meta`, params, {}, proxy)
+// 工作流-编辑
+export const workflowMetaEdit = (id, params) =>
+  patch(`/workflow/meta/${id}`, params, {}, proxy)
+// 工作流-详情
+export const workflowMetaDetail = (id) =>
+  get(`/workflow/meta/${id}`, {}, {}, proxy)

+ 2 - 4
src/layout/top-left/head/index.vue

@@ -32,7 +32,7 @@
       <template #dropdown>
         <el-dropdown-menu>
           <template
-            v-for="item in DictionaryStore.tenants.list.filter(
+            v-for="item in AppStore.tenants.filter(
               (v) => v.id !== AppStore.tenantInfo.id,
             )"
           >
@@ -172,9 +172,7 @@ const logout = () => {
     },
   })
 }
-onMounted(() => {
-  DictionaryStore.initTenants()
-})
+onMounted(() => {})
 </script>
 
 <style lang="scss" scoped>

+ 2 - 0
src/stores/modules/app.ts

@@ -5,6 +5,7 @@ export const useAppStore = defineStore('app', {
   state: () => ({
     userInfo: null,
     tenantInfo: null,
+    tenants: [],
   }),
   getters: {},
   actions: {
@@ -14,6 +15,7 @@ export const useAppStore = defineStore('app', {
           .then(({ data }: any) => {
             this.userInfo = data
             this.tenantInfo = data?.tenant
+            this.tenants = data?.tenants || []
             resolve(this.userInfo)
           })
           .catch((e) => {

+ 65 - 45
src/views/manage/app/make/workflow-select.vue

@@ -29,51 +29,59 @@
           />
         </CzrForm>
       </div>
-      <div
-        class="mt-4 grid max-h-[600px] flex-1 grid-cols-1 gap-4 overflow-y-auto"
-      >
-        <template v-for="row in state.query.result.data">
-          <div
-            class="model cursor-pointer"
-            :class="{
-              active: state.selected?.id == row.id,
-            }"
-            @click="state.selected = row"
-          >
-            <div class="flex">
-              <img
-                src="@/assets/images/workflow/workflow-default-icon.png"
-                class="mr-2.5 size-13"
-              />
-              <div class="flex flex-1 flex-col justify-around overflow-hidden">
-                <div class="text-xl font-bold text-[#2E3238]" v-title>
-                  {{ row.name }}
-                </div>
-                <div class="flex items-center justify-between gap-2">
-                  <div class="flex-1 text-[#909399]" v-title>
-                    {{ row.description }}
+      <template v-if="state.query.result.data.length > 0">
+        <div
+          class="mt-4 grid max-h-[600px] flex-1 grid-cols-1 gap-4 overflow-y-auto"
+        >
+          <template v-for="row in state.query.result.data">
+            <div
+              class="model cursor-pointer"
+              :class="{
+                active: state.selected?.id == row.id,
+              }"
+              @click="state.selected = row"
+            >
+              <div class="flex">
+                <img
+                  src="@/assets/images/workflow/workflow-default-icon.png"
+                  class="mr-2.5 size-13"
+                />
+                <div
+                  class="flex flex-1 flex-col justify-around overflow-hidden"
+                >
+                  <div class="text-xl font-bold text-[#2E3238]" v-title>
+                    {{ row.name }}
                   </div>
-                  <div
-                    class="__hover ml-auto text-xs text-[var(--czr-main-color)]"
-                    @click.capture.stop="onView(row)"
-                  >
-                    查看
+                  <div class="flex items-center justify-between gap-2">
+                    <div class="flex-1 text-[#909399]" v-title>
+                      {{ row.description }}
+                    </div>
+                    <div
+                      class="__hover ml-auto text-xs text-[var(--czr-main-color)]"
+                      @click.capture.stop="onView(row)"
+                    >
+                      查看
+                    </div>
                   </div>
                 </div>
               </div>
+              <template v-if="state.selected?.id == row.id">
+                <div
+                  class="absolute top-0 right-0 h-[2rem] w-[2rem] bg-[url('@/assets/images/knowledge/checked.png')]"
+                ></div>
+              </template>
             </div>
-            <template v-if="state.selected?.id == row.id">
-              <div
-                class="absolute top-0 right-0 h-[2rem] w-[2rem] bg-[url('@/assets/images/knowledge/checked.png')]"
-              ></div>
-            </template>
-          </div>
-        </template>
-      </div>
+          </template>
+        </div>
+      </template>
+      <template v-else>
+        <div class="flex h-40 w-full items-center justify-center">暂无数据</div>
+      </template>
     </div>
     <detailCom
       v-model:show="state.detail.show"
       :transfer="state.detail.transfer"
+      @refresh="onSearch"
     />
   </CzrDialog>
 </template>
@@ -95,10 +103,13 @@ import { Search } from '@element-plus/icons-vue'
 import { pluginGetInstanceList } from '@/api/modules/model'
 import { YMDHms } from '@/utils/czr-util'
 import { ElMessage, ElMessageBox } from 'element-plus'
-import detailCom from '@/views/manage/app/make/workflow-detail.vue'
+import detailCom from '@/views/workflow/detail/index.vue'
+import { workflowMetaPage } from '@/api/modules/workflow/meta'
+import { useRouter } from 'vue-router'
 
 const DialogStore = useDialogStore()
 const DictionaryStore = useDictionaryStore()
+const router = useRouter()
 const emit = defineEmits(['update:show', 'refresh'])
 const { proxy } = getCurrentInstance()
 const props = defineProps({
@@ -139,7 +150,7 @@ watch(
   },
 )
 const setText = debounce((v) => {
-  state.query.form.keyword = v
+  state.query.form.name = v
 }, 1000)
 watch(
   () => state.text,
@@ -169,20 +180,21 @@ const onPage = (pageNum, pageSize) => {
     pageSize: pageSize,
   }
   const params = {
-    page: state.query.page.pageNum,
+    page: state.query.page.pageNum - 1,
     size: state.query.page.pageSize,
+    queryVO: {},
   }
   //  添加表单参数
   for (const [k, v] of Object.entries(state.query.formReal)) {
     if (proxy.$czrUtil.isValue(v)) {
-      params[k] = v
+      params.queryVO[k] = v
     }
   }
-  // state.query.loading = true
-  pluginGetInstanceList(params)
+  state.query.loading = true
+  workflowMetaPage(params)
     .then(({ data }: any) => {
-      state.query.result.total = data.total
-      state.query.result.data = data.records
+      state.query.result.total = data.totalElements
+      state.query.result.data = data.content
       state.query.result.data.forEach((v: any) => {
         if (v.id == props.transfer.id) {
           state.selected = v
@@ -203,7 +215,15 @@ const onSubmit = () => {
   emit('update:show', false)
 }
 
-const onView = (row) => {}
+const onView = (row) => {
+  const routerUrl = router.resolve({
+    name: '37d34d52-78c7-4272-8715-fdc88f599c4f',
+    params: {
+      id: row.id,
+    },
+  })
+  window.open(routerUrl.href, '_blank')
+}
 const onAdd = () => {
   state.detail.transfer = {
     mode: 'add',

+ 35 - 11
src/views/manage/app/workflow/index.vue

@@ -14,7 +14,9 @@
           src="@/assets/images/workflow/workflow-default-icon.png"
           class="size-13"
         />
-        <div class="text-2xl font-bold text-[#303133]">工作流名称</div>
+        <div class="text-2xl font-bold text-[#303133]">
+          {{ state.detail.name }}
+        </div>
         <el-tooltip content="编辑" placement="top">
           <SvgIcon name="czr_edit" class="__hover" @click="onEdit" />
         </el-tooltip>
@@ -26,29 +28,35 @@
         <CzrButton type="primary" title="发布" />
       </div>
       <div class="mt-4 flex-1 rounded-sm bg-[var(--czr-main-color)]/5 shadow">
-        <workflowGraph />
+        <workflowGraph :ID="state.ID" />
       </div>
     </div>
     <detailCom
-      v-model:show="state.detail.show"
-      :transfer="state.detail.transfer"
+      v-model:show="state.detailCom.show"
+      :transfer="state.detailCom.transfer"
+      @refresh="initDetail"
     />
   </div>
 </template>
 
 <script setup lang="ts">
-import { reactive, watch } from 'vue'
+import { onMounted, reactive, watch } from 'vue'
 import toBackCom from '@/views/manage/components/to-back.vue'
 import { debounce } from 'lodash'
-import { ElLoading } from 'element-plus'
+import { ElLoading, ElMessage } from 'element-plus'
 import { YMDHms } from '@/utils/czr-util'
 import workflowGraph from '@/views/workflow/index.vue'
-import detailCom from '@/views/manage/app/make/workflow-detail.vue'
+import detailCom from '@/views/workflow/detail/index.vue'
+import { useRoute } from 'vue-router'
+import { workflowMetaDetail } from '@/api/modules/workflow/meta'
 
+const route = useRoute()
 const state: any = reactive({
+  ID: route.params.id,
+  detail: {},
   autoSaveTimestamp: '',
   form: {},
-  detail: {
+  detailCom: {
     show: false,
     transfer: {},
   },
@@ -71,11 +79,27 @@ const autoSave = debounce((v) => {
   }, 1000)
 }, 3000)
 const onEdit = () => {
-  state.detail.transfer = {
+  state.detailCom.transfer = {
     mode: 'edit',
-    row: {},
+    id: state.ID,
+  }
+  state.detailCom.show = true
+}
+onMounted(() => {
+  initDetail()
+})
+const initDetail = () => {
+  if (state.ID) {
+    state.detail = {}
+    workflowMetaDetail(state.ID)
+      .then(({ data }: any) => {
+        state.detail = data
+      })
+      .catch(() => {})
+      .finally(() => {})
+  } else {
+    ElMessage.error('未查询到工作流信息!')
   }
-  state.detail.show = true
 }
 </script>
 

+ 93 - 81
src/views/manage/center/tenant/detail.vue

@@ -16,34 +16,37 @@
             <CzrFormColumn
               required
               :span="12"
-              label="户名称"
+              label="户名称"
               v-model:param="state.form.name"
             />
             <CzrFormColumn
               required
               :span="12"
               label="租户状态"
-              v-model:param="state.form.name"
+              v-model:param="state.form.enabled"
               link="switch"
+              :options="DictionaryStore.trueFalseStatus"
             />
             <CzrFormColumn
               :span="12"
               label="用户配额"
-              v-model:param="state.form.name"
+              v-model:param="state.form.userQuota"
+              link="number"
             />
             <CzrFormColumn
+              v-if="state.form.id"
               :span="12"
               label="租户启用时间"
-              v-model:param="state.form.name"
-              link="date"
+              v-model:param="state.form.startDate"
+              link="datetime"
               :disabled="true"
             />
             <CzrFormColumn
               required
               :span="12"
               label="租户停用时间"
-              v-model:param="state.form.name"
-              link="date"
+              v-model:param="state.form.endDate"
+              link="datetime"
             />
           </el-row>
         </el-col>
@@ -62,25 +65,27 @@
             />
           </el-row>
         </el-col>
-        <div class="__czr-title_1">
-          管理员账号
-          <CzrButton
-            type="normal"
-            title="新增"
-            class="ml-auto"
-            @click="onInvite"
-          />
-        </div>
-        <div class="mt-4 w-full">
-          <CzrTable
-            :data="state.admins.data"
-            :head="state.admins.head"
-            :full="true"
-            no-foot
-            maxHeight="300px"
-          >
-          </CzrTable>
-        </div>
+        <template v-if="state.form.id">
+          <div class="__czr-title_1">
+            管理员账号
+            <CzrButton
+              type="normal"
+              title="新增"
+              class="ml-auto"
+              @click="onInvite"
+            />
+          </div>
+          <div class="mt-4 w-full">
+            <CzrTable
+              :data="state.form.userTenants || []"
+              :head="state.admins.head"
+              :full="true"
+              no-foot
+              maxHeight="300px"
+            >
+            </CzrTable>
+          </div>
+        </template>
       </CzrForm>
     </div>
     <CzrDialog
@@ -130,6 +135,12 @@ import { useAppStore, useDialogStore, useDictionaryStore } from '@/stores'
 import { useRouter } from 'vue-router'
 import { CopyDocument } from '@element-plus/icons-vue'
 import { copy } from '@/utils/czr-util'
+import {
+  tenantsAdd,
+  tenantsDetail,
+  tenantsEdit,
+} from '@/api/modules/center/tenant'
+import { accountGenerateFriendlyCode } from '@/api/modules/global/invite'
 
 const router = useRouter()
 const AppStore = useAppStore()
@@ -147,9 +158,9 @@ const state: any = reactive({
   file: [],
   admins: {
     head: [
-      { value: 'name', label: '账号', show: true },
+      { value: 'loginId', label: '账号', show: true },
       { value: 'name', label: '用户名', show: true },
-      { value: 'name', label: '状态', show: true },
+      { value: 'status', label: '状态', show: true },
       {
         value: 'caozuo',
         label: '操作',
@@ -188,7 +199,7 @@ watch(
   (n) => {
     if (n) {
       initDictionary()
-      state.form = {}
+      state.form = { enabled: true }
       state.file = []
       if (props.transfer.mode !== 'add') {
         initData()
@@ -201,16 +212,15 @@ watch(
 )
 const initDictionary = () => {}
 const initData = () => {
-  // state.loading = true
-  // datasetsDetail(props.transfer.id)
-  //   .then(({ data }: any) => {
-  //     state.form = data
-  //     ref_modelConfig.value.init(data)
-  //   })
-  //   .catch(() => {})
-  //   .finally(() => {
-  //     state.loading = false
-  //   })
+  state.loading = true
+  tenantsDetail(props.transfer.id)
+    .then(({ data }: any) => {
+      state.form = data
+    })
+    .catch(() => {})
+    .finally(() => {
+      state.loading = false
+    })
 }
 const onSubmit = (isImport) => {
   ref_form.value
@@ -219,46 +229,34 @@ const onSubmit = (isImport) => {
       DialogStore.confirm({
         content: `请确认是否${titleCpt.value}?${isImport ? '创建成功后将自动跳转至文档上传页面!' : ''}`,
         onSubmit: () => {
-          // state.loading = true
-          // if (props.transfer.mode === 'add') {
-          //   datasetsCreate({
-          //     ...state.form,
-          //     ...ref_modelConfig.value.getData(),
-          //   })
-          //     .then(({ data }: any) => {
-          //       ElMessage.success(`${titleCpt.value}成功!`)
-          //       if (isImport) {
-          //         router.push({
-          //           name: '18e6009c-a72c-4359-864b-e7725fccca69',
-          //           params: {
-          //             id: data.id,
-          //           },
-          //         })
-          //       } else {
-          //         emit('update:show', false)
-          //         emit('refresh')
-          //       }
-          //     })
-          //     .catch(() => {})
-          //     .finally(() => {
-          //       state.loading = false
-          //     })
-          // } else {
-          //   datasetsUpdate({
-          //     ...state.form,
-          //     ...ref_modelConfig.value.getData(),
-          //     tenantId: AppStore.tenantInfo?.id,
-          //   })
-          //     .then(({ data }: any) => {
-          //       ElMessage.success(`${titleCpt.value}成功!`)
-          //       emit('update:show', false)
-          //       emit('refresh')
-          //     })
-          //     .catch(() => {})
-          //     .finally(() => {
-          //       state.loading = false
-          //     })
-          // }
+          if (state.file[0]) {
+            state.form.picture = state.file[0].url
+          }
+          state.loading = true
+          if (props.transfer.mode === 'add') {
+            tenantsAdd(state.form)
+              .then(({ data }: any) => {
+                ElMessage.success(`${titleCpt.value}成功!`)
+
+                emit('update:show', false)
+                emit('refresh')
+              })
+              .catch(() => {})
+              .finally(() => {
+                state.loading = false
+              })
+          } else {
+            tenantsEdit(state.form)
+              .then(({ data }: any) => {
+                ElMessage.success(`${titleCpt.value}成功!`)
+                emit('update:show', false)
+                emit('refresh')
+              })
+              .catch(() => {})
+              .finally(() => {
+                state.loading = false
+              })
+          }
         },
       })
     })
@@ -271,8 +269,22 @@ const onSubmit = (isImport) => {
     })
 }
 const onInvite = () => {
-  state.invite.url = 'https://cn.element-plus.org/zh-CN/component/input.html'
-  state.invite.show = true
+  accountGenerateFriendlyCode({
+    userId: AppStore.userInfo?.id,
+    tenantId: state.form.id,
+  })
+    .then(({ data }: any) => {
+      const routerUrl = router.resolve({
+        name: 'invite',
+        query: {
+          inviteCode: data,
+        },
+      })
+      state.invite.url = location.origin + routerUrl.href
+      state.invite.show = true
+    })
+    .catch(() => {})
+    .finally(() => {})
 }
 const onCopy = (str) => {
   copy(str)

+ 1 - 0
src/views/manage/center/user/index.vue

@@ -336,6 +336,7 @@ const onInvite = () => {
   accountGenerateFriendlyCode({
     userId: AppStore.userInfo?.id,
     tenantId: AppStore.tenantInfo?.id,
+    // tenantId: '1952283047189794816',
   })
     .then(({ data }: any) => {
       const routerUrl = router.resolve({

+ 38 - 34
src/views/manage/app/make/workflow-detail.vue

@@ -19,7 +19,7 @@
         <CzrFormColumn
           label="工作流简介"
           :span="24"
-          v-model:param="state.form.name"
+          v-model:param="state.form.description"
           type="textarea"
           :rows="4"
         />
@@ -39,6 +39,11 @@ import {
 } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { useAppStore, useDialogStore, useDictionaryStore } from '@/stores'
+import {
+  workflowMetaAdd,
+  workflowMetaDetail,
+  workflowMetaEdit,
+} from '@/api/modules/workflow/meta'
 
 const AppStore = useAppStore()
 const DictionaryStore = useDictionaryStore()
@@ -75,7 +80,9 @@ watch(
   (n) => {
     if (n) {
       initDictionary()
-      state.form = {}
+      state.form = {
+        type: 'workflow',
+      }
       if (props.transfer.mode !== 'add') {
         initData()
       }
@@ -86,18 +93,15 @@ watch(
   },
 )
 const initData = () => {
-  // state.loading = true
-  // appDetail(props.transfer.id)
-  //   .then(({ data }: any) => {
-  //     state.form = data
-  //     if (data.icon) {
-  //       state.icon = [{ url: data.icon, name: data.icon }]
-  //     }
-  //   })
-  //   .catch(() => {})
-  //   .finally(() => {
-  //     state.loading = false
-  //   })
+  state.loading = true
+  workflowMetaDetail(props.transfer.id)
+    .then(({ data }: any) => {
+      state.form = data
+    })
+    .catch(() => {})
+    .finally(() => {
+      state.loading = false
+    })
 }
 const onSubmit = () => {
   ref_form.value
@@ -108,27 +112,27 @@ const onSubmit = () => {
         onSubmit: () => {
           state.loading = true
           if (props.transfer.mode === 'add') {
-            // appAdd(state.form)
-            //   .then(() => {
-            //     ElMessage.success(`${titleCpt.value}成功!`)
-            //     emit('update:show', false)
-            //     emit('refresh')
-            //   })
-            //   .catch(() => {})
-            //   .finally(() => {
-            //     state.loading = false
-            //   })
+            workflowMetaAdd(state.form)
+              .then(() => {
+                ElMessage.success(`${titleCpt.value}成功!`)
+                emit('update:show', false)
+                emit('refresh')
+              })
+              .catch(() => {})
+              .finally(() => {
+                state.loading = false
+              })
           } else if (props.transfer.mode === 'edit') {
-            // appEdit(state.form)
-            //   .then(() => {
-            //     ElMessage.success(`${titleCpt.value}成功!`)
-            //     emit('update:show', false)
-            //     emit('refresh')
-            //   })
-            //   .catch(() => {})
-            //   .finally(() => {
-            //     state.loading = false
-            //   })
+            workflowMetaEdit(state.form.id, state.form)
+              .then(() => {
+                ElMessage.success(`${titleCpt.value}成功!`)
+                emit('update:show', false)
+                emit('refresh')
+              })
+              .catch(() => {})
+              .finally(() => {
+                state.loading = false
+              })
           }
         },
       })

+ 8 - 1
src/views/workflow/index.vue

@@ -30,11 +30,17 @@ import envVarsPanel from './instance/component/vars/evn-index.vue'
 import { getTeleport } from '@antv/x6-vue-shape'
 import { data0, data1 } from './mockJson'
 import { useWorkflowStore } from '@/stores'
+import {
+  workflowDraftDetail,
+  workflowDraftSave,
+} from '@/api/modules/workflow/chart'
 
 const TeleportContainer = getTeleport()
 const WorkflowStore = useWorkflowStore()
 const emit = defineEmits([])
-const props = defineProps({})
+const props = defineProps({
+  ID: {},
+})
 const { proxy }: any = getCurrentInstance()
 const state: any = reactive({
   workflowData: null,
@@ -81,6 +87,7 @@ const getJsonData = () => {
   console.log(res)
 }
 const initData = () => {
+  workflowDraftDetail(props.ID)
   const d = data0
   WorkflowStore.$patch((s: any) => (s.envVars.vars = d.envVars || []))
   state.workflowData = d.graph