소스 검색

用户项目、机构权限设置

Michael Wang 3 년 전
부모
커밋
e2b93a7324

+ 3 - 4
components.d.ts

@@ -19,17 +19,16 @@ declare module 'vue' {
     ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
     ASpin: typeof import('ant-design-vue/es')['Spin']
     ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
+    ASwitch: typeof import('ant-design-vue/es')['Switch']
     ATable: typeof import('ant-design-vue/es')['Table']
-    ATextarea: typeof import('ant-design-vue/es')['Textarea']
+    ATabPane: typeof import('ant-design-vue/es')['TabPane']
+    ATabs: typeof import('ant-design-vue/es')['Tabs']
     CourseTypeSelect: typeof import('./src/components/CourseTypeSelect.vue')['default']
     Layout: typeof import('./src/components/Layout.vue')['default']
     QmButton: typeof import('./src/components/QmButton.vue')['default']
     RoleSelect: typeof import('./src/components/RoleSelect.vue')['default']
     RootOrgSelect: typeof import('./src/components/RootOrgSelect.vue')['default']
-    'RootOrgSelect copy': typeof import('./src/components/RootOrgSelect copy.vue')['default']
-    Select: typeof import('./src/components/Select.vue')['default']
     StateSelect: typeof import('./src/components/StateSelect.vue')['default']
-    'StateSelect copy': typeof import('./src/components/StateSelect copy.vue')['default']
   }
 }
 

+ 75 - 2
src/api/userManagementPage.ts

@@ -1,12 +1,14 @@
 import { httpApp } from "@/plugins/axiosApp";
+import { Privilege_Type } from "@/types";
 
 /** 用户分页查询 */
 export function getUserList(params: {
+  id?: number;
   loginName?: string;
   name?: string;
   enable?: boolean;
-  roleId: number;
-  rootOrgId: number;
+  roleId?: number;
+  rootOrgId?: number;
   pageNo?: number;
   pageSize?: number;
 }) {
@@ -60,3 +62,74 @@ export function exportUsers(params: {
 }) {
   return httpApp.post(`/api/ess/user/export`, params);
 }
+
+/** 用户科目/机构数据权限分页查询 */
+export function getUserPrivilegegList(params: {
+  type: Privilege_Type;
+  userId?: number;
+  pageNo?: number;
+  pageSize?: number;
+}) {
+  return httpApp.post(
+    `/api/ess/user/data/rule/list/for/${params.type.toLowerCase()}`,
+    params
+  );
+}
+
+/** 用户数据权限默认全部查询 */
+export function getUserPrivilegegDefaultAll(params: {
+  type: Privilege_Type;
+  userId: number;
+}) {
+  const f = new FormData();
+  f.append("userId", params.userId + "");
+  f.append("type", params.type);
+  return httpApp.post(`/api/ess/user/data/rule/default/status`, f);
+}
+
+/** 修改用户数据权限默认全部 */
+export function modifyUserPrivilegegDefaultAll(params: {
+  type: Privilege_Type;
+  userId: number;
+  enabled: boolean;
+}) {
+  const f = new FormData();
+  f.append("userId", params.userId + "");
+  f.append("type", params.type);
+  f.append("enabled", params.enabled + "");
+  return httpApp.post(`/api/ess/user/data/rule/default/status/update`, f);
+}
+
+/** 添加科目权限-分页查询科目 添加机构权限-分页查询机构 */
+export function getToAddListForUserPrivilege(params: {
+  type: Privilege_Type;
+  rootOrgId: number;
+  userId?: number;
+  enable?: boolean;
+  name?: string;
+  pageNo?: number;
+  pageSize?: number;
+}) {
+  return httpApp.post(
+    `/api/ess/${params.type.toLowerCase()}/page/data/rule`,
+    params
+  );
+}
+
+/** 新增用户数据权限 */
+export function addListForUserPrivilege(params: {
+  type: Privilege_Type;
+  userId: number;
+  refIds: number[];
+}) {
+  return httpApp.post("/api/ess/user/data/rule/add", params);
+}
+
+/** 删除用户数据权限 */
+export function deleteListForUserPrivilege(params: {
+  type: Privilege_Type;
+  userId: number;
+  refIds: number[];
+}) {
+  return httpApp.post("/api/ess/user/data/rule/delete", params);
+}

+ 8 - 0
src/features/userManagement/UserManagement.vue

@@ -68,6 +68,9 @@
               {{ record.enable ? "禁用" : "启用" }}
             </a-button>
             <a-button @click="handleResetUsers([record.id])">重置密码</a-button>
+            <a-button @click="handleUserPrivilege(record.id)">
+              权限设置
+            </a-button>
           </span>
         </template>
       </a-table>
@@ -151,6 +154,7 @@ import {
   toggleUsers,
   updateUser,
 } from "@/api/userManagementPage";
+import router from "@/router";
 import { useMainStore } from "@/store";
 import { downloadFileURL } from "@/utils/utils";
 import { message, Modal } from "ant-design-vue";
@@ -337,4 +341,8 @@ const rowSelection = {
 async function downloadTpl() {
   downloadFileURL("/api/ess/org/template");
 }
+
+function handleUserPrivilege(userId: number) {
+  router.push("/basic/user/privilege/" + userId);
+}
 </script>

+ 54 - 0
src/features/userManagement/UserPrivilege.vue

@@ -0,0 +1,54 @@
+<template>
+  <div>
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl tw-mb-5">
+      <span>{{ theUser.name }}</span> <span> {{ theUser.roleName }}</span>
+      <span class="tw-mr-4"></span>
+      <a-button @click="goBack">返回</a-button>
+    </div>
+
+    <a-tabs>
+      <a-tab-pane key="1" tab="科目范围"><UserPrivilegeCourse /> </a-tab-pane>
+      <a-tab-pane key="2" tab="机构范围"><UserPrivilegeOrg /></a-tab-pane>
+    </a-tabs>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { getUserList } from "@/api/userManagementPage";
+import router from "@/router";
+import { useMainStore } from "@/store";
+import { onMounted, reactive } from "vue-demi";
+import { useRoute } from "vue-router";
+import UserPrivilegeCourse from "./UserPrivilegeCourse.vue";
+import UserPrivilegeOrg from "./UserPrivilegeOrg.vue";
+
+const store = useMainStore();
+store.currentLocation = "基础管理 / 用户管理 / 权限管理";
+
+const route = useRoute();
+const userId = route.params.userId as string;
+
+let theUser = reactive<{ name: string; roleName: string }>({
+  name: "",
+  roleName: "",
+});
+
+async function search() {
+  await fetchData();
+}
+
+async function fetchData() {
+  const user = await getUserList({
+    id: +userId,
+  });
+  theUser = user.data && user.data[0];
+}
+
+onMounted(async () => {
+  await search();
+});
+
+function goBack() {
+  router.back();
+}
+</script>

+ 270 - 0
src/features/userManagement/UserPrivilegeCourse.vue

@@ -0,0 +1,270 @@
+<template>
+  <div>
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl tw-mb-5">
+      <a-switch v-model:checked="checked" @click="toggleAll" /> 全部课程
+      <span class="tw-mr-4"></span>
+      <a-button @click="handleDeletePrivilege" :danger="true">删除</a-button>
+      <span class="tw-mr-4"></span>
+      <a-button @click="showModal">添加</a-button>
+    </div>
+
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl">
+      <a-table
+        row-key="id"
+        :columns="columns"
+        :data-source="data"
+        :row-selection="rowSelection"
+        :pagination="{
+          pageSize: pageSize,
+          current: pageNo,
+          total: totalElements,
+          showTotal: (total: number) => `总数:${total}`,
+          onChange: (pageNoChanged: number, pageSizeChanged: number) => {
+            pageNo = pageNoChanged; 
+            pageSize = pageSizeChanged;
+          }
+        }"
+      >
+      </a-table>
+    </div>
+
+    <a-modal
+      v-model:visible="visible"
+      title="信息页"
+      @ok="handleOk"
+      ok-text="确定"
+      cancel-text="取消"
+    >
+      <a-form>
+        <a-form-item label="科目名称">
+          <a-input v-model:value="userObj.name"></a-input>
+        </a-form-item>
+        <!-- <a-form-item label="状态">
+          <a-radio-group v-model:value="userObj.enable">
+            <a-radio :value="true">启用</a-radio>
+            <a-radio :value="false">禁用</a-radio>
+          </a-radio-group>
+        </a-form-item> -->
+
+        <a-button @click="fetchData2">查询</a-button>
+      </a-form>
+      <div class="tw-bg-white tw-p-5 tw-rounded-xl">
+        <a-table
+          row-key="id"
+          :columns="columns2"
+          :data-source="data2"
+          :row-selection="rowSelection2"
+          :pagination="{
+          pageSize: pageSize2,
+          current: pageNo2,
+          total: totalElements2,
+          showTotal: (total: number) => `总数:${total}`,
+          onChange: (pageNoChanged: number, pageSizeChanged: number) => {
+            pageNo2 = pageNoChanged; 
+            pageSize2 = pageSizeChanged;
+          }
+        }"
+        >
+          <template #enable="{ text }">
+            <a>{{ $filters.booleanEnableDisableFilter(text) }}</a>
+          </template>
+        </a-table>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {
+  addListForUserPrivilege,
+  deleteListForUserPrivilege,
+  getToAddListForUserPrivilege,
+  getUserPrivilegegDefaultAll,
+  getUserPrivilegegList,
+  modifyUserPrivilegegDefaultAll,
+} from "@/api/userManagementPage";
+import { useMainStore } from "@/store";
+import { message } from "ant-design-vue";
+import { watch, onMounted, reactive } from "vue-demi";
+import { useRoute } from "vue-router";
+
+const PRIVI_TYPE = "COURSE";
+const store = useMainStore();
+
+const route = useRoute();
+const userId = +route.params.userId;
+
+let checked = $ref(false);
+async function toggleAll() {
+  await modifyUserPrivilegegDefaultAll({
+    enabled: checked,
+    type: PRIVI_TYPE,
+    userId,
+  });
+  message.success({ content: "修改成功" });
+  await search();
+}
+
+let data = $ref([]);
+let pageSize = $ref(10);
+let pageNo = $ref(1);
+let totalElements = $ref(0);
+
+async function search() {
+  await fetchData();
+}
+
+watch(() => [pageNo, pageSize], fetchData);
+
+async function fetchData() {
+  const res0 = await getUserPrivilegegDefaultAll({
+    userId,
+    type: PRIVI_TYPE,
+  });
+  checked = res0.data;
+
+  const res = await getUserPrivilegegList({
+    type: PRIVI_TYPE,
+    userId,
+    pageSize,
+    pageNo,
+  });
+  // console.log(res);
+  data = res.data.content;
+  pageNo = res.data.pageNo;
+  pageSize = res.data.pageSize;
+  totalElements = res.data.totalElements;
+}
+
+const columns = [
+  {
+    title: "科目ID",
+    dataIndex: "courseId",
+    width: 150,
+  },
+  {
+    title: "科目编码",
+    dataIndex: "courseCode",
+    width: 150,
+  },
+  {
+    title: "科目名称",
+    dataIndex: "courseName",
+  },
+];
+
+onMounted(async () => {
+  await search();
+});
+
+let visible = $ref<boolean>(false);
+
+const showModal = () => {
+  Object.assign(userObj, initUser);
+  visible = true;
+};
+
+const initUser = {
+  code: "",
+  name: "",
+  enable: true,
+  rootOrgId: store.userInfo.rootOrgId,
+};
+const userObj = reactive({ ...initUser });
+
+function checkEmpty(selectIds: number[]): boolean {
+  if (selectIds && selectIds.length > 0) {
+    return false;
+  } else {
+    message.warn({ content: "请先选择行" });
+    return true;
+  }
+}
+async function handleDeletePrivilege() {
+  if (checkEmpty(selectIds)) return;
+  await deleteListForUserPrivilege({
+    type: PRIVI_TYPE,
+    userId,
+    refIds: selectIds,
+  });
+  await search();
+}
+
+let selectIds = $ref<number[]>([]);
+const rowSelection = {
+  onChange: (selectedRowKeys: (string | number)[]) => {
+    console.log(`selectedRowKeys: ${selectedRowKeys}`);
+    selectIds = selectedRowKeys as number[];
+  },
+};
+
+/** <Modal> */
+let data2 = $ref([]);
+let pageSize2 = $ref(10);
+let pageNo2 = $ref(1);
+let totalElements2 = $ref(0);
+
+const columns2 = [
+  {
+    title: "科目编码",
+    dataIndex: "code",
+    width: 150,
+  },
+  {
+    title: "科目名称",
+    dataIndex: "name",
+  },
+  {
+    title: "状态",
+    dataIndex: "enable",
+    slots: { customRender: "enable" },
+  },
+];
+
+watch(() => [pageNo2, pageSize2], fetchData2);
+
+async function fetchData2() {
+  const res = await getToAddListForUserPrivilege({
+    type: PRIVI_TYPE,
+    rootOrgId: store.userInfo.rootOrgId,
+    userId,
+    name: userObj.name,
+    // enable: userObj.enable,
+    pageSize,
+    pageNo,
+  });
+  // console.log(res);
+  data2 = res.data.content;
+  pageNo2 = res.data.pageNo;
+  pageSize2 = res.data.pageSize;
+  totalElements2 = res.data.totalElements;
+}
+
+let selectIds2 = $ref<number[]>([]);
+const rowSelection2 = {
+  onChange: (selectedRowKeys: (string | number)[]) => {
+    console.log(`selectedRowKeys: ${selectedRowKeys}`);
+    selectIds2 = selectedRowKeys as number[];
+  },
+};
+
+function checkEmpty2(selectIds: number[]): boolean {
+  if (selectIds2 && selectIds2.length > 0) {
+    return false;
+  } else {
+    message.warn({ content: "请先选择行" });
+    return true;
+  }
+}
+async function handleOk() {
+  if (checkEmpty2(selectIds2)) return;
+  await addListForUserPrivilege({
+    type: PRIVI_TYPE,
+    userId,
+    refIds: selectIds2,
+  });
+  await search();
+  visible = false;
+}
+/** </Modal> */
+</script>

+ 270 - 0
src/features/userManagement/UserPrivilegeOrg.vue

@@ -0,0 +1,270 @@
+<template>
+  <div>
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl tw-mb-5">
+      <a-switch v-model:checked="checked" @click="toggleAll" /> 全部课程
+      <span class="tw-mr-4"></span>
+      <a-button @click="handleDeletePrivilege" :danger="true">删除</a-button>
+      <span class="tw-mr-4"></span>
+      <a-button @click="showModal">添加</a-button>
+    </div>
+
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl">
+      <a-table
+        row-key="id"
+        :columns="columns"
+        :data-source="data"
+        :row-selection="rowSelection"
+        :pagination="{
+          pageSize: pageSize,
+          current: pageNo,
+          total: totalElements,
+          showTotal: (total: number) => `总数:${total}`,
+          onChange: (pageNoChanged: number, pageSizeChanged: number) => {
+            pageNo = pageNoChanged; 
+            pageSize = pageSizeChanged;
+          }
+        }"
+      >
+      </a-table>
+    </div>
+
+    <a-modal
+      v-model:visible="visible"
+      title="信息页"
+      @ok="handleOk"
+      ok-text="确定"
+      cancel-text="取消"
+    >
+      <a-form>
+        <a-form-item label="机构名称">
+          <a-input v-model:value="userObj.name"></a-input>
+        </a-form-item>
+        <!-- <a-form-item label="状态">
+          <a-radio-group v-model:value="userObj.enable">
+            <a-radio :value="true">启用</a-radio>
+            <a-radio :value="false">禁用</a-radio>
+          </a-radio-group>
+        </a-form-item> -->
+
+        <a-button @click="fetchData2">查询</a-button>
+      </a-form>
+      <div class="tw-bg-white tw-p-5 tw-rounded-xl">
+        <a-table
+          row-key="id"
+          :columns="columns2"
+          :data-source="data2"
+          :row-selection="rowSelection2"
+          :pagination="{
+          pageSize: pageSize2,
+          current: pageNo2,
+          total: totalElements2,
+          showTotal: (total: number) => `总数:${total}`,
+          onChange: (pageNoChanged: number, pageSizeChanged: number) => {
+            pageNo2 = pageNoChanged; 
+            pageSize2 = pageSizeChanged;
+          }
+        }"
+        >
+          <template #enable="{ text }">
+            <a>{{ $filters.booleanEnableDisableFilter(text) }}</a>
+          </template>
+        </a-table>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {
+  addListForUserPrivilege,
+  deleteListForUserPrivilege,
+  getToAddListForUserPrivilege,
+  getUserPrivilegegDefaultAll,
+  getUserPrivilegegList,
+  modifyUserPrivilegegDefaultAll,
+} from "@/api/userManagementPage";
+import { useMainStore } from "@/store";
+import { message } from "ant-design-vue";
+import { watch, onMounted, reactive } from "vue-demi";
+import { useRoute } from "vue-router";
+
+const PRIVI_TYPE = "ORG";
+const store = useMainStore();
+
+const route = useRoute();
+const userId = +route.params.userId;
+
+let checked = $ref(false);
+async function toggleAll() {
+  await modifyUserPrivilegegDefaultAll({
+    enabled: checked,
+    type: PRIVI_TYPE,
+    userId,
+  });
+  message.success({ content: "修改成功" });
+  await search();
+}
+
+let data = $ref([]);
+let pageSize = $ref(10);
+let pageNo = $ref(1);
+let totalElements = $ref(0);
+
+async function search() {
+  await fetchData();
+}
+
+watch(() => [pageNo, pageSize], fetchData);
+
+async function fetchData() {
+  const res0 = await getUserPrivilegegDefaultAll({
+    userId,
+    type: PRIVI_TYPE,
+  });
+  checked = res0.data;
+
+  const res = await getUserPrivilegegList({
+    type: PRIVI_TYPE,
+    userId,
+    pageSize,
+    pageNo,
+  });
+  // console.log(res);
+  data = res.data.content;
+  pageNo = res.data.pageNo;
+  pageSize = res.data.pageSize;
+  totalElements = res.data.totalElements;
+}
+
+const columns = [
+  {
+    title: "机构ID",
+    dataIndex: "orgId",
+    width: 150,
+  },
+  {
+    title: "机构编码",
+    dataIndex: "orgCode",
+    width: 150,
+  },
+  {
+    title: "机构名称",
+    dataIndex: "orgName",
+  },
+];
+
+onMounted(async () => {
+  await search();
+});
+
+let visible = $ref<boolean>(false);
+
+const showModal = () => {
+  Object.assign(userObj, initUser);
+  visible = true;
+};
+
+const initUser = {
+  code: "",
+  name: "",
+  enable: true,
+  rootOrgId: store.userInfo.rootOrgId,
+};
+const userObj = reactive({ ...initUser });
+
+function checkEmpty(selectIds: number[]): boolean {
+  if (selectIds && selectIds.length > 0) {
+    return false;
+  } else {
+    message.warn({ content: "请先选择行" });
+    return true;
+  }
+}
+async function handleDeletePrivilege() {
+  if (checkEmpty(selectIds)) return;
+  await deleteListForUserPrivilege({
+    type: PRIVI_TYPE,
+    userId,
+    refIds: selectIds,
+  });
+  await search();
+}
+
+let selectIds = $ref<number[]>([]);
+const rowSelection = {
+  onChange: (selectedRowKeys: (string | number)[]) => {
+    console.log(`selectedRowKeys: ${selectedRowKeys}`);
+    selectIds = selectedRowKeys as number[];
+  },
+};
+
+/** <Modal> */
+let data2 = $ref([]);
+let pageSize2 = $ref(10);
+let pageNo2 = $ref(1);
+let totalElements2 = $ref(0);
+
+const columns2 = [
+  {
+    title: "机构编码",
+    dataIndex: "code",
+    width: 150,
+  },
+  {
+    title: "机构名称",
+    dataIndex: "name",
+  },
+  {
+    title: "状态",
+    dataIndex: "enable",
+    slots: { customRender: "enable" },
+  },
+];
+
+watch(() => [pageNo2, pageSize2], fetchData2);
+
+async function fetchData2() {
+  const res = await getToAddListForUserPrivilege({
+    type: PRIVI_TYPE,
+    rootOrgId: store.userInfo.rootOrgId,
+    userId,
+    name: userObj.name,
+    // enable: userObj.enable,
+    pageSize,
+    pageNo,
+  });
+  // console.log(res);
+  data2 = res.data.content;
+  pageNo2 = res.data.pageNo;
+  pageSize2 = res.data.pageSize;
+  totalElements2 = res.data.totalElements;
+}
+
+let selectIds2 = $ref<number[]>([]);
+const rowSelection2 = {
+  onChange: (selectedRowKeys: (string | number)[]) => {
+    console.log(`selectedRowKeys: ${selectedRowKeys}`);
+    selectIds2 = selectedRowKeys as number[];
+  },
+};
+
+function checkEmpty2(selectIds: number[]): boolean {
+  if (selectIds2 && selectIds2.length > 0) {
+    return false;
+  } else {
+    message.warn({ content: "请先选择行" });
+    return true;
+  }
+}
+async function handleOk() {
+  if (checkEmpty2(selectIds2)) return;
+  await addListForUserPrivilege({
+    type: PRIVI_TYPE,
+    userId,
+    refIds: selectIds2,
+  });
+  await search();
+  visible = false;
+}
+/** </Modal> */
+</script>

+ 3 - 0
src/plugins/axiosNotice.ts

@@ -5,6 +5,9 @@ import { logout } from "@/api/loginPage";
 import router, { routeLogout } from "@/router";
 
 export const notifyInvalidTokenThrottled = throttle(() => {
+  if (router.currentRoute.value.name === "Login") {
+    return;
+  }
   message.error({
     content: "登录失效,请重新登录!",
     duration: 10,

+ 4 - 0
src/router/index.ts

@@ -31,6 +31,10 @@ const routes = [
         path: "user",
         component: () => import("@/features/userManagement/UserManagement.vue"),
       },
+      {
+        path: "user/privilege/:userId",
+        component: () => import("@/features/userManagement/UserPrivilege.vue"),
+      },
       {
         path: "course",
         component: () =>

+ 2 - 0
src/types/index.ts

@@ -5,3 +5,5 @@ export interface Role {
 }
 
 export type Course_Type = "PUBLIC" | "MAJOR";
+
+export type Privilege_Type = "COURSE" | "ORG";