Quellcode durchsuchen

feat: 修改框架

snihwxf vor 3 Monaten
Ursprung
Commit
835feb02cc

+ 1 - 1
apps/web-baicai/src/api/system/cache.ts

@@ -9,5 +9,5 @@ export namespace CacheApi {
     });
 
   export const deleteDetail = (key: string) =>
-    requestClient.delete('/cache', { data: { key } });
+    requestClient.delete(`/cache/${key}`);
 }

+ 1 - 0
apps/web-baicai/src/api/system/enum.ts

@@ -4,6 +4,7 @@ import { requestClient } from '#/api/request';
 
 export namespace EnumApi {
   export enum EnumType {
+    DataScope = 'DataScope',
     Gender = 'Gender',
     MenuType = 'MenuType',
     PathType = 'PathType',

+ 6 - 0
apps/web-baicai/src/api/system/role.ts

@@ -62,4 +62,10 @@ export namespace RoleApi {
 
   export const getStatistics = () =>
     requestClient.get<StatisticsItem[]>('/role/statistics');
+
+  export const getDataScope = (id: number) =>
+    requestClient.get<RelationRequest>('/role/data-scope', { params: { id } });
+
+  export const updateDataScope = (data: RelationRequest) =>
+    requestClient.put('/role/data-scope', data);
 }

+ 92 - 6
apps/web-baicai/src/views/system/cache/index.vue

@@ -1,33 +1,92 @@
 <script lang="ts" setup>
+import type { BasicTreeOptionResult } from '#/api/model';
+
 import { onMounted, reactive } from 'vue';
 
-import { BcNav, BcPage, JsonViewer, VbenScrollbar } from '@vben/common-ui';
+import {
+  BcNav,
+  BcPage,
+  confirm,
+  JsonViewer,
+  VbenScrollbar,
+} from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
 
 import { CacheApi } from '#/api';
+import { BcTree } from '#/components/bc-tree';
 
 const props = reactive({
   defaultLayout: [20, 80, 0],
   title: '缓存Key',
 });
 
-const state = reactive<{ jsonValue: any; navList: any[] }>({
+const state = reactive<{
+  cacheKey: string;
+  isTree: boolean;
+  jsonValue: any;
+  navList: any[];
+  treeData: BasicTreeOptionResult[];
+}>({
   navList: [],
   jsonValue: {},
+  cacheKey: '',
+  treeData: [],
+  isTree: true,
 });
 
 const fetch = async () => {
   const data = await CacheApi.getList();
+  state.treeData = [];
+  data.forEach((element) => {
+    const keyNames = element.split(':');
+    const pName = keyNames[0] as string;
+    const filterItem = state.treeData.filter((x: any) => x.value === pName);
+    if (filterItem.length === 0) {
+      state.treeData.push({
+        value: keyNames.length > 1 ? pName : element,
+        label: pName,
+        children: [],
+        parentId: 0,
+      });
+    }
+    if (keyNames.length > 1) {
+      const pNode = (state.treeData.find((x: any) => x.value === pName) || {
+        children: [],
+      }) as BasicTreeOptionResult;
+      pNode.children.push({
+        value: element,
+        label: element.slice(pName.length + 1),
+        children: [],
+        parentId: 0,
+      });
+    }
+  });
+
   state.navList = data.map((item) => {
     return { title: item };
   });
-  if (state.navList.length > 0) {
+  if (state.navList.length > 0 && !state.isTree) {
     await handleChange(state.navList[0]);
   }
 };
 
 const handleChange = async (item: Record<string, any>) => {
+  state.cacheKey = item.title;
   state.jsonValue = await CacheApi.getDetail(item.title);
 };
+const handleDelete = () => {
+  if (state.cacheKey) {
+    confirm(`确证要删除缓存[${state.cacheKey}]`).then(async () => {
+      await CacheApi.deleteDetail(state.cacheKey);
+      await fetch();
+    });
+  }
+};
+
+const handleTreeChange = async (keys: any[]) => {
+  await handleChange({ title: keys[0] });
+};
 onMounted(async () => {
   await fetch();
 });
@@ -35,7 +94,7 @@ onMounted(async () => {
 <template>
   <BcPage auto-content-height v-bind="props">
     <template #left="{ isCollapsed, expand }">
-      <VbenScrollbar class="h-full">
+      <VbenScrollbar class="h-full" v-if="!state.isTree">
         <BcNav
           :is-collapsed="isCollapsed"
           @collapse="expand"
@@ -43,9 +102,36 @@ onMounted(async () => {
           @change="handleChange"
         />
       </VbenScrollbar>
+      <BcTree
+        v-else
+        title="缓存列表"
+        :tree-data="state.treeData"
+        @change="handleTreeChange"
+      />
     </template>
-    <div class="m-4">
-      <JsonViewer :value="state.jsonValue" />
+    <div class="h-full">
+      <div class="h-[45px] border-b">
+        <div class="ml-4 mr-4 flex h-full items-center justify-between">
+          <div>缓存数据【{{ state.cacheKey }}】</div>
+          <Button
+            type="primary"
+            size="small"
+            v-access:code="'cache:delete'"
+            @click="() => handleDelete()"
+          >
+            删除
+          </Button>
+        </div>
+      </div>
+      <div class="h-[calc(100%-45px)]">
+        <VbenScrollbar class="h-full">
+          <JsonViewer
+            :value="state.jsonValue"
+            preview-mode
+            :show-array-index="false"
+          />
+        </VbenScrollbar>
+      </div>
     </div>
   </BcPage>
 </template>

+ 1 - 0
apps/web-baicai/src/views/system/design/database/components/editColumn.vue

@@ -23,6 +23,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
 const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
+  closeOnClickModal: false,
   onCancel() {
     close();
   },

+ 1 - 0
apps/web-baicai/src/views/system/dict/item/edit.vue

@@ -24,6 +24,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
 const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
+  closeOnClickModal: false,
   onCancel() {
     close();
   },

+ 1 - 0
apps/web-baicai/src/views/system/dict/type/edit.vue

@@ -24,6 +24,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
 const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
+  closeOnClickModal: false,
   onConfirm: async () => {
     try {
       const { valid } = await validate();

+ 1 - 0
apps/web-baicai/src/views/system/menu/components/edit.vue

@@ -27,6 +27,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
 );
 
 const [Drawer, { close, setState, getData, lock, unlock }] = useVbenDrawer({
+  closeOnClickModal: false,
   onCancel() {
     close();
   },

+ 1 - 0
apps/web-baicai/src/views/system/role/components/edit.vue

@@ -24,6 +24,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
 const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
+  closeOnClickModal: false,
   onCancel() {
     close();
   },

+ 141 - 0
apps/web-baicai/src/views/system/role/components/grant.vue

@@ -0,0 +1,141 @@
+<script lang="ts" setup>
+import type { DataNode } from 'ant-design-vue/es/tree';
+
+import type { Recordable } from '@vben/types';
+
+import type { RelationRequest } from '#/api/model';
+
+import { onMounted, reactive, ref, unref } from 'vue';
+
+import { alert, useVbenModal, VbenTree } from '@vben/common-ui';
+
+import { Spin } from 'ant-design-vue';
+
+import { useFormOptions, useVbenForm } from '#/adapter';
+import { DepartmentApi, EnumApi, RoleApi } from '#/api';
+
+defineOptions({
+  name: 'DataGrant',
+});
+const emit = defineEmits(['success']);
+
+const modelRef = ref<Recordable<any>>({});
+
+const state = reactive<{
+  loadingTree: boolean;
+  treeData: DataNode[];
+}>({
+  treeData: [],
+  loadingTree: false,
+});
+
+const [Form, { setValues, validate, getValues }] = useVbenForm(
+  useFormOptions({
+    schema: [
+      {
+        component: 'ApiSelect',
+        fieldName: 'dataScope',
+        componentProps: {
+          api: EnumApi.getList,
+          params: { name: EnumApi.EnumType.DataScope },
+          showSearch: true,
+        },
+        label: '数据范围',
+        rules: 'required',
+      },
+      {
+        component: 'Input',
+        fieldName: 'relationIds',
+        formItemClass: 'items-start',
+        label: '机构',
+        modelPropName: 'modelValue',
+        dependencies: {
+          triggerFields: ['dataScope'],
+          show(values: any) {
+            return [5].includes(values.dataScope);
+          },
+        },
+        rules: 'required',
+      },
+    ],
+  }),
+);
+
+const getRoleDetailData = async () => {
+  const data = await RoleApi.getDataScope(unref(modelRef).id);
+  setValues({ ...data });
+};
+
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
+  fullscreenButton: false,
+  draggable: true,
+  closeOnClickModal: false,
+  onConfirm: async () => {
+    const { valid } = await validate();
+    if (!valid) return;
+
+    const values = await getValues();
+    try {
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      if (postParams.dataScope !== 5) {
+        postParams.relationIds = [];
+      }
+      await RoleApi.updateDataScope(postParams as RelationRequest);
+      alert('操作成功');
+      close();
+      emit('success');
+    } finally {
+      unlock();
+    }
+  },
+  onOpenChange: async (isOpen: boolean) => {
+    if (isOpen) {
+      setState({ loading: true });
+      const data = getData<Recordable<any>>();
+      modelRef.value = { ...data.baseData };
+
+      if (state.treeData.length === 0) {
+        await loadTreeData();
+      }
+
+      await getRoleDetailData();
+
+      setState({ loading: false });
+    }
+  },
+});
+
+onMounted(async () => {});
+
+const loadTreeData = async () => {
+  state.loadingTree = true;
+  try {
+    const res = await DepartmentApi.getTreeOptions();
+    state.treeData = res as unknown as DataNode[];
+  } finally {
+    state.loadingTree = false;
+  }
+};
+</script>
+<template>
+  <Modal class="w-[1000px]" title="数据范围">
+    <Form>
+      <template #relationIds="slotProps">
+        <Spin :spinning="state.loadingTree" wrapper-class-name="w-full">
+          <VbenTree
+            :tree-data="state.treeData"
+            multiple
+            :bordered="false"
+            v-bind="slotProps"
+            :default-expanded-level="2"
+            value-field="value"
+            label-field="label"
+          />
+        </Spin>
+      </template>
+    </Form>
+  </Modal>
+</template>
+<style lang="less" scoped></style>

+ 5 - 0
apps/web-baicai/src/views/system/role/data.config.ts

@@ -65,6 +65,11 @@ export function useColumns(
             label: '添加成员',
             auth: ['role:grantUser'],
           },
+          {
+            code: 'grantData',
+            label: '授权数据',
+            auth: ['role:grantData'],
+          },
           {
             code: 'setStatus',
             label: (row: RoleApi.RecordItem) => {

+ 17 - 0
apps/web-baicai/src/views/system/role/index.vue

@@ -11,6 +11,7 @@ import { SelectCard } from '#/components/select-card';
 import MenuGrant from '#/views/system/menu/components/grant.vue';
 
 import FormEdit from './components/edit.vue';
+import DataGrant from './components/grant.vue';
 import { useColumns, useSearchSchema } from './data.config';
 
 const handleDelete = async (id: number) => {
@@ -31,6 +32,10 @@ const handleActionClick = async ({
       handleEdit(row, true);
       break;
     }
+    case 'grantData': {
+      await handleGrantData(row.id);
+      break;
+    }
     case 'grantMenu': {
       await handleGrantMenu(row.id);
       break;
@@ -80,6 +85,10 @@ const [SelectCardModal, selectCardApi] = useVbenModal({
   connectedComponent: SelectCard,
 });
 
+const [DataGrantModal, dataGrantApi] = useVbenModal({
+  connectedComponent: DataGrant,
+});
+
 const handleUpdateStatus = async (record: any) => {
   await RoleApi.updateStatus({
     id: record.id,
@@ -105,6 +114,13 @@ const handleGrantMenu = async (id: number) => {
     .open();
 };
 
+const handleGrantData = async (id: number) => {
+  dataGrantApi
+    .setData({
+      baseData: { id },
+    })
+    .open();
+};
 const handleGrantUser = async (id: number) => {
   const selectedIds = await RoleApi.getUserIds(id);
   selectCardApi
@@ -143,6 +159,7 @@ const handelUserSuccess = async (data: any) => {
     <FormEditModal @success="handelSuccess" />
     <MenuGrantModal />
     <SelectCardModal title="用户" @success="handelUserSuccess" />
+    <DataGrantModal />
     <Grid>
       <template #table-title>
         <span class="border-l-primary border-l-8 border-solid pl-2">