Bläddra i källkod

feat:超管切换供应商业务公司

snow 2 år sedan
förälder
incheckning
4f28085b66

+ 4 - 0
src/api/supplierManage/supplierAccoutManage/index.ts

@@ -50,3 +50,7 @@ export const httpRoleAll = (data: object): ResponseType => {
 export const httpSetRole = (data: object): ResponseType => {
   return http.request("post", `${yewuApi}setrole`, { data });
 };
+
+export const httpSupplierList = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}supplier_by_super`, { data });
+};

+ 38 - 0
src/api/supplierManage/supplierRole/index.ts

@@ -0,0 +1,38 @@
+import { http } from "/@/utils/http";
+import { loadEnv } from "@build/index";
+const { VITE_PROXY_DOMAIN_REAL, VITE_PROXY_USER_REAL } = loadEnv();
+// const userAPi = VITE_PROXY_DOMAIN_REAL;
+const yewuApi = VITE_PROXY_USER_REAL + "/admin/";
+interface ResponseType extends Promise<any> {
+  data?: object;
+  code?: number;
+  msg?: string;
+}
+// 添加
+export const httpAdd = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}roleadd`, { data });
+};
+// 列表
+export const httpList = (data: object = {}): ResponseType => {
+  return http.request("post", `${yewuApi}rolelist`, { data: { ...data, level: "3"} });
+};
+// 详情
+export const httpDetail = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}roleinfo`, { data });
+};
+// 更新
+export const httpUpdate = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}rolesave`, { data });
+};
+// 状态
+export const httpStatus = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}rolestatus`, { data });
+};
+// 删除
+export const httpDelete = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}menustatus`, { data });
+};
+// 全部菜单按钮
+export const httpMenuAll = (data: object): ResponseType => {
+  return http.request("post", `${yewuApi}menuactionlist`, { data });
+};

+ 12 - 0
src/api/user.ts

@@ -65,6 +65,18 @@ export const httpSupplierall = (data: object): any => {
   });
 };
 
+export const httpSupplierList = (data: object): any => {
+  return http.request("post", `${yewuApi}supplier_by_super`, {
+    data
+  });
+};
+
+export const httpBusinessList = (data: object): any => {
+  return http.request("post", `${yewuApi}companylist`, {
+    data
+  });
+};
+
 export const httpGetAllCompany = (data: object) => {
   return http.request("post", `${yewuApi}supplierall`, {
     data

+ 1 - 1
src/layout/components/company/index.vue

@@ -170,7 +170,7 @@ requesetSupplierAll("");
     />
     <p class="super-loading" v-if="state.loading">
       <IconifyIconOffline class="animate-spin" icon="Loading" />
-      加载中
+      加载中...
     </p>
 
     <p class="super-no-more" v-if="state.noMore">没有更多数据了...</p>

+ 41 - 12
src/layout/components/company/super.vue

@@ -1,9 +1,10 @@
 <script setup lang="ts">
 import { useDebounceFn } from "@vueuse/core";
-import { ref, onMounted, reactive, onUnmounted } from "vue";
-import { httpSupplierall } from "/@/api/user";
+import { ref, onMounted, reactive, onUnmounted, watch } from "vue";
+import { httpBusinessList, httpSupplierList } from "/@/api/user";
 import { useResponseHandle } from "/@/hooks/core/useAsync";
 import { useCompany } from "/@/hooks/core/useCompany";
+import { useUserInfo } from "/@/hooks/core/useUser";
 
 const emit = defineEmits(["change", "update:code"]);
 
@@ -21,6 +22,8 @@ const props = withDefaults(
 const { setCurrentCompany } = useCompany();
 const responseHandle = useResponseHandle();
 
+const { userLevel } = useUserInfo();
+
 const code = ref(props.code);
 const selectRef = ref(null);
 const list = ref<any[]>([]);
@@ -37,22 +40,33 @@ let scrollWrapper: HTMLDivElement | null = null;
 
 const debouceScroll = useDebounceFn(handleScroll, 500);
 
+function convertList(list){
+  const isSupplier = userLevel.value === "3"
+  if (isSupplier) return list
+  return list.map(item => ({
+    ...item,
+    code: item.companyNo,
+    name: item.company_name
+  }));
+}
+
 async function requesetSupplierAll(name: string, companyNo: string) {
   state.name = name;
   state.page = 1;
   state.noMore = false;
-
-  const { data, message, code } = await httpSupplierall({
-    name: state.name,
+  const isSupplier = userLevel.value === "3"
+  const api = isSupplier ? httpSupplierList : httpBusinessList;
+  const { data, message, code } = await api({
+    [isSupplier ? "name" : 'companyName']: state.name,
+    [isSupplier ? "code" : 'companyNo']: companyNo,
     page: state.page,
-    companyNo
   });
 
   responseHandle({
     code,
     message,
     handler: () => {
-      list.value = data.list;
+      list.value = convertList(data.list);
       state.count = data.count;
       state.loading = false;
       const maxPage = Math.ceil(state.count / 10);
@@ -78,12 +92,14 @@ async function handleScroll() {
     state.page++;
     state.loading = true;
 
-    const { data, message, code } = await httpSupplierall({
+    const api = userLevel.value === "3" ? httpSupplierList : httpBusinessList;
+
+    const { data, message, code } = await api({
       name: state.name,
       page: state.page
     });
     const pushCompany = (_list: any[]) => {
-      list.value = [...list.value, ..._list];
+      list.value = [...list.value, ...convertList(_list)];
     };
 
     responseHandle({
@@ -108,11 +124,8 @@ async function handleScroll() {
 onMounted(() => {
   setTimeout(() => {
     const superItem = document.querySelector(".super-item");
-
     if (!superItem) return;
-
     scrollWrapper = superItem.parentElement?.parentElement as HTMLDivElement;
-
     if (scrollWrapper) {
       scrollWrapper.addEventListener("scroll", debouceScroll, false);
     }
@@ -130,6 +143,18 @@ onUnmounted(() => {
   }
 });
 
+watch(
+  () => userLevel.value,
+  () => {
+    state.loading = false;
+    state.noMore = false;
+    state.name = "";
+    state.page = 1;
+    list.value = [];
+    requesetSupplierAll(undefined, props.code);
+  }
+);
+
 const getLabel = company => {
   const { code, name, type } = company;
   const isCompany = type === "3" || type === "业务公司";
@@ -138,6 +163,10 @@ const getLabel = company => {
 };
 
 requesetSupplierAll(undefined, props.code);
+
+defineExpose({
+  selectAll: () => (code.value = "")
+});
 </script>
 
 <template>

+ 14 - 10
src/layout/components/navbar.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { computed, ref, watch } from "vue";
+import { computed, ref, nextTick } from "vue";
 import { useNav } from "../hooks/nav";
 import mixNav from "./sidebar/mixNav.vue";
 import avatars from "/@/assets/avatars.jpg";
@@ -7,24 +7,27 @@ import Hamburger from "./sidebar/hamBurger.vue";
 import Breadcrumb from "./sidebar/breadCrumb.vue";
 import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 import { useRouter, useRoute } from "vue-router";
-import { deviceDetection } from "@pureadmin/utils";
 import Company from "../components/company/index.vue";
 import Super from "../components/company/super.vue";
 import { useUserInfo } from "/@/hooks/core/useUser";
 import { getToken, SECRET_KEY } from "/@/utils/auth";
 import SystemNotify from "./system-notify.vue";
 import HelpModal from "./help-modal.vue";
-import CryptoJS from "crypto-js";
 import { initRouter } from "/@/router/utils";
+import { useCompany } from "/@/hooks/core/useCompany";
+import CryptoJS from "crypto-js";
 
 const route = useRoute();
-const { push, replace } = useRouter();
+const { push } = useRouter();
 const showBackButton = computed(() => route.path.indexOf("Detail") >= 0);
 const helpModalRef = ref<InstanceType<typeof HelpModal> | null>(null);
 const systemNotifyRef = ref<InstanceType<typeof SystemNotify>>(null);
 const { logout, toggleSideBar, pureApp, avatarsStyle } = useNav();
 
+const SuperCompanyRef = ref<InstanceType<typeof Super> | null>(null)
+
 const { isSuperUser, userInfo, userLevel, setUserLevel } = useUserInfo();
+const { setCurrentCompany } = useCompany();
 
 const switchAccountModeText = computed(() =>
   userLevel.value === "3" ? "切换至业务公司" : "切换至供应商"
@@ -53,13 +56,13 @@ function openPurchaseSystem() {
 //超管切换供应商、业务公司视角
 async function onSwitchAccountMode() {
   const isSupplier = userLevel.value === "3";
-
   setUserLevel(isSupplier ? "1" : "3");
   await initRouter({ level: isSupplier ? "1" : "3" });
-  console.log(route.path);
-  await replace(
-    route.path + "?reload=" + (isSupplier ? "supplier" : "business")
-  );
+
+  await nextTick(() => {
+    setCurrentCompany("");
+    SuperCompanyRef.value && SuperCompanyRef.value.selectAll();
+  });
 }
 </script>
 
@@ -117,7 +120,7 @@ async function onSwitchAccountMode() {
       </el-tooltip>
 
       <!-- 公司名称筛选 -->
-      <Super v-if="isSuperUser" />
+      <Super v-if="isSuperUser" ref="SuperCompanyRef" />
       <Company v-else />
 
       <p class="bell-icon" @click="() => systemNotifyRef.onDisplay()">
@@ -149,6 +152,7 @@ async function onSwitchAccountMode() {
               <IconifyIconOffline icon="dict" style="margin: 5px" />
               使用说明
             </el-dropdown-item>
+
             <el-dropdown-item @click="logout">
               <IconifyIconOffline
                 icon="logout-circle-r-line"

+ 2 - 2
src/utils/status.ts

@@ -12,8 +12,8 @@ const menuPrivateList = [
   { value: "0", label: "隐藏", type: "warning" }
 ];
 const levelList = [
-  { value: "2", label: "管理员", type: "primary" },
-  { value: "3", label: "专员", type: "warning" }
+  { value: "2", label: "业务公司", type: "primary" },
+  { value: "3", label: "供应商", type: "warning" }
 ];
 const cg_order_type_options = [
   { value: "1", label: "库存品" },

+ 11 - 11
src/views/netOrderEnter/netOrderEntry/components/supplier.vue

@@ -1,29 +1,29 @@
 <script setup lang="ts">
-import { ref } from "vue"
+import { ref } from "vue";
 import { useVModel } from "@vueuse/core";
-import RemoteSelect from '/@/components/RemoteSelect';
+import RemoteSelect from "/@/components/RemoteSelect";
 import { httpSupplierlist } from "/@/api/netOrderEnter/netOrderEntry";
 
 const props = defineProps<{
   modelValue?: string;
 }>();
 
-const value = useVModel(props, 'modelValue');
-const RemoteSelectRef = ref<InstanceType<typeof RemoteSelect> | null>(null)
+const value = useVModel(props, "modelValue");
+const RemoteSelectRef = ref<InstanceType<typeof RemoteSelect> | null>(null);
 
 defineExpose({
-  initalData:(data) => (RemoteSelectRef.value as any).initalData(data)
-})
+  initalData: data => (RemoteSelectRef.value as any).initalData(data)
+});
 </script>
 
 <template>
-  <RemoteSelect 
-    v-model="value" 
+  <RemoteSelect
+    v-model="value"
     ref="RemoteSelectRef"
-    style="width:100%;" 
+    style="width: 100%"
     :api="httpSupplierlist"
     requset-prop="name"
-    response-label-prop="name" 
-    response-val-prop="code" 
+    response-label-prop="name"
+    response-val-prop="code"
   />
 </template>

+ 2 - 2
src/views/supplierManage/supplierAccoutManage/components/company-modal.vue

@@ -2,7 +2,7 @@
 import { ElTable } from "element-plus";
 import { reactive, ref, unref } from "vue";
 import { useResponseHandle } from "/@/hooks/core/useAsync";
-import { httpList } from "/@/api/parameter/supplierPay";
+import { httpSupplierList } from "/@/api/supplierManage/supplierAccoutManage";
 
 const paymentList = ref<Array<Record<string, string>>>([]);
 const selectOrder = ref<Array<Record<string, string>>>([]);
@@ -27,7 +27,7 @@ const pagination = reactive({
 async function requestPaymentList() {
   const { pageSize: size, currentPage: page } = pagination;
   loading.value = true;
-  const { code, message, data } = await httpList({
+  const { code, message, data } = await httpSupplierList({
     ...params.value,
     size,
     page

+ 804 - 0
src/views/supplierManage/supplierRole/addEdit.vue

@@ -0,0 +1,804 @@
+<script setup lang="ts">
+import { ElMessage, FormInstance, FormRules } from "element-plus";
+import { reactive, ref, watch, nextTick, computed } from "vue";
+import { useNav } from "/@/layout/hooks/nav";
+import { levelList } from "/@/utils/status";
+import { menuType } from "./types";
+import { useCompany } from "/@/hooks/core/useCompany";
+
+import {
+  httpAdd,
+  httpUpdate,
+  httpMenuAll,
+  httpDetail
+} from "/@/api/supplierManage/supplierRole";
+
+const { logout } = useNav();
+const formSize = ref("small");
+
+const ruleFormRef = ref<FormInstance>();
+
+const { currentCompany } = useCompany();
+
+const props = defineProps({
+  itemId: {
+    type: String,
+    default: ""
+  },
+  showModel: {
+    type: Boolean,
+    default: false
+  },
+  isDetails: {
+    type: String,
+    default: "add"
+  }
+});
+const showModelThis = ref(false);
+const emit = defineEmits<{
+  (e: "cancel"): void;
+  (e: "refresh"): void;
+}>();
+const id = ref("");
+const editType = ref("add");
+const menuactionList = ref([]);
+const action_list = ref([]);
+const action_data_list = ref([]);
+const private_data_list = ref([]);
+const formModel = {
+  roleid: "",
+  role_name: "",
+  level: "3",
+  action: "",
+  private_data: ""
+};
+const ruleForm = reactive<menuType>({ ...formModel });
+const rules = reactive<FormRules>({
+  role_name: [
+    { required: true, message: "请输入角色名称", trigger: "blur" },
+    { min: 2, max: 12, message: "长度在 2 到 12 个字符", trigger: "blur" }
+  ],
+  level: [
+    {
+      required: true,
+      message: "请选择角色等级",
+      trigger: "change"
+    }
+  ]
+});
+// 全选/全不选
+const handleCheckAllChange = (checkAll, index, item, subIndex) => {
+  menuactionList.value[index].child[subIndex].checkAll = checkAll;
+  // this.$set(menuactionList.value, index, item);
+  menuactionList.value[index].child[subIndex].action.forEach(element => {
+    const findindex = menuactionList.value[index].child[
+      subIndex
+    ].checkList.findIndex(findItem => findItem === String(element.id));
+    if (checkAll && findindex == -1) {
+      menuactionList.value[index].child[subIndex].checkList.push(
+        String(element.id)
+      );
+    } else if (!checkAll && findindex > -1) {
+      menuactionList.value[index].child[subIndex].checkList.splice(
+        findindex,
+        1
+      );
+    }
+  });
+};
+// 全选/全不选
+const handleFieldAllChange = (fieldAll, index, item, subIndex) => {
+  menuactionList.value[index].child[subIndex].fieldAll = fieldAll;
+  // this.$set(menuactionList.value, index, item);
+  menuactionList.value[index].child[subIndex].action_data.forEach(element => {
+    const findindex = menuactionList.value[index].child[
+      subIndex
+    ].fieldList.findIndex(findItem => findItem === String(element.id));
+    if (fieldAll && findindex == -1) {
+      menuactionList.value[index].child[subIndex].fieldList.push(
+        String(element.id)
+      );
+    } else if (!fieldAll && findindex > -1) {
+      menuactionList.value[index].child[subIndex].fieldList.splice(
+        findindex,
+        1
+      );
+    }
+  });
+};
+// 复选框组内的选中/不选中
+const handleCheckedGroupChange = (event, index, item, subIndex) => {
+  menuactionList.value[index].child[subIndex].checkAll = menuactionList.value[
+    index
+  ].child[subIndex].action.every(
+    evitem =>
+      menuactionList.value[index].child[subIndex].checkList.findIndex(
+        finditem => finditem == evitem.id
+      ) > -1
+  );
+  // this.$set(menuactionList.value, index, item);
+};
+// 复选框组内的选中/不选中
+const handleFieldGroupChange = (event, index, item, subIndex) => {
+  menuactionList.value[index].child[subIndex].fieldAll = menuactionList.value[
+    index
+  ].child[subIndex].action_data.every(
+    evitem =>
+      menuactionList.value[index].child[subIndex].fieldList.findIndex(
+        finditem => finditem == evitem.id
+      ) > -1
+  );
+  // this.$set(menuactionList.value, index, item);
+};
+
+// 单项复选框选中/不选中
+const handleCheckedChange = (checked, id, index, subIndex, item) => {
+  // console.log(checked, id, index, subIndex);
+  if (checked) {
+    // 选中时检查pid的选中状态
+    menuactionList.value[index].child[subIndex].checkList.indexOf(id) == -1 &&
+      menuactionList.value[index].child[subIndex].checkList.push(id);
+  } else {
+    const find = menuactionList.value[index].child[
+      subIndex
+    ].checkList.findIndex(e => e == id);
+    if (find > -1) {
+      menuactionList.value[index].child[subIndex].checkList.splice(find, 1);
+    }
+    menuactionList.value[index].child[subIndex].checkAll = false;
+  }
+  // this.$set(menuactionList.value, index, item);
+};
+// 单项复选框选中/不选中
+const handleFieldChange = (checked, id, index, subIndex, item) => {
+  // console.log(checked, id, index, subIndex);
+  if (checked) {
+    // 选中时检查pid的选中状态
+    menuactionList.value[index].child[subIndex].fieldList.indexOf(id) == -1 &&
+      menuactionList.value[index].child[subIndex].fieldList.push(id);
+  } else {
+    const find = menuactionList.value[index].child[
+      subIndex
+    ].fieldList.findIndex(e => e == id);
+    if (find > -1) {
+      menuactionList.value[index].child[subIndex].fieldList.splice(find, 1);
+    }
+    menuactionList.value[index].child[subIndex].fieldAll = false;
+  }
+  // this.$set(menuactionList.value, index, item);
+  // console.log(menuactionList.value[index].child[subIndex]);
+};
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+
+  // if (!currentCompany.value.companyNo) {
+  //   ElMessage.warning("请选择一个公司");
+  //   return;
+  // }
+
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      if (loading.value == true) return;
+      loading.value = true;
+      const { level, role_name, roleid } = ruleForm;
+
+      action_list.value = []; // 字段数据
+      action_data_list.value = []; // 功能数据
+      private_data_list.value = [];
+      console.log(menuactionList.value);
+      menuactionList.value.forEach(x => {
+        x.child.forEach(y => {
+          action_list.value.push(...y.fieldList);
+          action_data_list.value.push(...y.checkList);
+          if (y.is_private_change == "1") {
+            private_data_list.value.push(y.id);
+          }
+        });
+      });
+      if (action_data_list.value.length == 0) {
+        ElMessage.error("请选择功能!");
+        loading.value = false;
+        return;
+      }
+      let model = {
+        level,
+        role_name,
+        roleid,
+        action: action_data_list.value, //按钮权限
+        companyNo: currentCompany.value.companyNo,
+        private_data: private_data_list.value //私有权限
+      };
+
+      if (editType.value == "add") {
+        delete model["roleid"];
+      }
+
+      // if (!currentCompany.value.companyNo) {
+      //   ElMessage.warning("请选择一个公司");
+      //   return;
+      // }
+
+      const { code, message } =
+        editType.value == "add"
+          ? await httpAdd(model)
+          : await httpUpdate(model);
+      loading.value = false;
+      if (code == 0) {
+        ElMessage.success(titleType.value + "成功!");
+        showModelThis.value = false;
+        emit("refresh");
+      } else if (code > 100 && code < 140) {
+        showModelThis.value = false;
+        logout();
+      } else {
+        ElMessage.error(message);
+      }
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+};
+const resetForm = async (formEl: FormInstance | undefined, item) => {
+  if (!formEl) return;
+  formEl.clearValidate();
+  formEl.resetFields();
+  await nextTick(async () => {
+    for (let key in ruleForm) {
+      if (key == "role") {
+        ruleForm[key] = item["roleid"] || "";
+      } else {
+        ruleForm[key] = item[key];
+      }
+    }
+  });
+};
+const closeDialog = () => {
+  showModelThis.value = false;
+  emit("cancel");
+};
+
+const loading = ref(true);
+const titleType = ref("");
+async function initForm(item: Object) {
+  loading.value = true;
+  switch (editType.value) {
+    case "add":
+      titleType.value = "新建角色";
+      break;
+    case "edit":
+      titleType.value = "编辑角色";
+      break;
+    case "view":
+      titleType.value = "角色详情";
+      break;
+    default:
+      titleType.value = "新建角色";
+  }
+  const { code, data, message } = await httpMenuAll({ level: "2" });
+  if (code == 0) {
+    let arr = JSON.parse(JSON.stringify(data ?? []));
+    arr = arr.filter(item => item.child && item.child.length > 0);
+    arr = arr.map(x => {
+      x.child.map(y => {
+        y.checkAll = false;
+        y.checkList = [];
+        y.fieldAll = false;
+        y.fieldList = [];
+        y.is_private_change = "0";
+        if (y.is_private == "0") {
+          y.private = [];
+        } else {
+          y.private = [
+            {
+              id: "0",
+              label: "公有数据"
+            },
+            {
+              id: "1",
+              label: "私有数据"
+            }
+          ];
+        }
+        return y;
+      });
+      return x;
+    });
+    menuactionList.value = arr;
+    // console.log(menuactionList.value);
+  } else if (code > 100 && code < 140) {
+    logout();
+  } else {
+    ElMessage.error(message);
+  }
+  await resetForm(ruleFormRef.value, item);
+  if (editType.value !== "add") {
+    await initData();
+  }
+  // console.log(ruleForm);
+  loading.value = false;
+}
+
+const initData = async () => {
+  const { code, data, message } = await httpDetail({ roleid: id.value });
+  if (code == 0) {
+    const { action, action_data, private_data, role_name, level } = data ?? {};
+    ruleForm.roleid = id.value;
+    ruleForm.role_name = role_name ?? "";
+    ruleForm.level = level ?? "1";
+    action_list.value = action ?? [];
+    action_data_list.value = action_data ?? [];
+    private_data_list.value = private_data ?? [];
+    const arr = JSON.parse(JSON.stringify(menuactionList.value));
+    arr.map(x => {
+      if (x.child && x.child.length > 0) {
+        x.child.map(y => {
+          if (y.action && y.action.length > 0) {
+            y.action.map(z => {
+              const Aindex =
+                action_list.value.length > 0
+                  ? action_list.value.findIndex(a => a == z.id)
+                  : -1;
+              if (Aindex !== -1) {
+                y.checkList.push(action_list.value[Aindex]);
+              }
+              return z;
+            });
+            if (y.action.length == y.checkList.length) {
+              y.checkAll = true;
+            }
+          }
+          if (y.action_data && y.action_data.length > 0) {
+            y.action.map(z => {
+              const Bindex =
+                action_data_list.value.length > 0
+                  ? action_data_list.value.findIndex(a => a == z.id)
+                  : -1;
+              if (Bindex !== -1) {
+                y.fieldList.push(action_data_list.value[Bindex]);
+              }
+              return z;
+            });
+            if (y.action_data.length == y.fieldList.length) {
+              y.fieldAll = true;
+            }
+          }
+          console.log(private_data_list.value);
+          // console.log(y.private);
+          if (y.private && y.private.length == 2) {
+            let Cindex =
+              private_data_list.value.length > 0
+                ? private_data_list.value.findIndex(a => a == y.id)
+                : -1;
+            if (Cindex !== -1) {
+              y.is_private_change = "1";
+            } else {
+              y.is_private_change = "0";
+            }
+          } else {
+            y.is_private_change = "0";
+          }
+          return y;
+        });
+      }
+      return x;
+    });
+
+    menuactionList.value = arr;
+    console.log(menuactionList.value);
+  } else if (code >= 100 && code <= 104) {
+    logout();
+  } else {
+    ElMessage.warning(message);
+  }
+};
+watch(
+  () => {
+    return props.showModel;
+  },
+  () => {
+    const { showModel, itemId, isDetails } = props;
+    showModelThis.value = showModel;
+    if (showModelThis.value) {
+      id.value = itemId;
+      editType.value = isDetails;
+      initForm(formModel);
+    }
+  }
+);
+let indeterminateCheck = computed(() => {
+  return item => {
+    // 选中子节点的数量
+    const selectItemLength = item.action.filter(
+      filitem =>
+        item.checkList.findIndex(finditem => finditem == filitem.id) > -1
+    ).length;
+    // 未选中子节点的数量
+    const noSlectItemLength = item.action.filter(
+      filitem =>
+        item.checkList.findIndex(finditem => finditem == filitem.id) == -1
+    ).length;
+    // // 当前节点的index
+    // 存在选中子节点且存在未选中子节点为中间态
+    return selectItemLength > 0 && noSlectItemLength > 0;
+  };
+});
+
+let indeterminateField = computed(() => {
+  return item => {
+    // console.log(item);
+    // 选中子节点的数量
+    const selectItemLength = item.action_data.filter(
+      filitem =>
+        item.fieldList.findIndex(finditem => finditem == filitem.id) > -1
+    ).length;
+    // 未选中子节点的数量
+    const noSlectItemLength = item.action_data.filter(
+      filitem =>
+        item.fieldList.findIndex(finditem => finditem == filitem.id) == -1
+    ).length;
+    // // 当前节点的index
+    // 存在选中子节点且存在未选中子节点为中间态
+    return selectItemLength > 0 && noSlectItemLength > 0;
+  };
+});
+</script>
+
+<template>
+  <el-dialog
+    :close-on-press-escape="false"
+    v-model="showModelThis"
+    append-to-body
+    center
+    :top="'5vh'"
+    :width="'900px'"
+    :title="titleType"
+    v-loading="loading"
+    @close="closeDialog"
+  >
+    <el-form
+      ref="ruleFormRef"
+      :model="ruleForm"
+      :rules="rules"
+      label-width="90px"
+      class="role-addedit"
+      :size="formSize"
+      status-icon
+      v-loading="loading"
+    >
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="角色名称" prop="role_name">
+            <el-input
+              v-model="ruleForm.role_name"
+              :disabled="editType == 'view'"
+              placeholder="角色名称"
+            /> </el-form-item
+        ></el-col>
+        <el-col :span="12">
+          <el-form-item label="角色等级" prop="level">
+            <el-select
+              v-model="ruleForm.level"
+              style="width: 100%"
+              placeholder="菜单类型"
+              disabled
+            >
+              <el-option
+                v-for="(si, sii) in levelList"
+                :key="'type' + si.value + sii"
+                :label="si.label"
+                :value="si.value"
+              />
+            </el-select> </el-form-item
+        ></el-col>
+        <el-col :span="24">
+          <div class="quanxian-main">
+            <div class="quanxian-title">
+              <div style="color: #ff8888">*</div>
+              <div>功</div>
+              <div>能</div>
+              <div>权</div>
+              <div>限</div>
+            </div>
+            <div class="rule-view">
+              <div class="rule-list">
+                <el-row
+                  v-for="(item, index) in menuactionList"
+                  :key="'menu' + item.id + index"
+                >
+                  <el-col
+                    v-if="item.child && item.child.length > 0"
+                    class="ffff"
+                    :span="24"
+                  >
+                    <div class="ftitle">
+                      <div
+                        v-for="(si, sii) in item.menu_name"
+                        :key="'title' + sii + si"
+                      >
+                        {{ si }}
+                      </div>
+                    </div>
+                    <div class="fbody">
+                      <div
+                        class="fbody-item"
+                        v-for="(subItem, subIndex) in item.child"
+                        :key="'yemian' + subItem.id + subIndex"
+                      >
+                        <template
+                          v-if="
+                            !(
+                              subItem.action &&
+                              subItem.action.length == 0 &&
+                              subItem.action_data &&
+                              subItem.action_data.length == 0
+                            )
+                          "
+                        >
+                          <div class="stitle clear">
+                            <span class="_h2 fl">{{ subItem.menu_name }}</span>
+                            <el-radio-group
+                              style="margin: 0 0 0 20px"
+                              class="fl"
+                              size="small"
+                              v-if="
+                                subItem &&
+                                subItem.private &&
+                                subItem.private.length == 2
+                              "
+                              v-model="subItem.is_private_change"
+                            >
+                              <el-radio-button
+                                size="small"
+                                v-for="(radioN, ri) in subItem.private"
+                                :key="radioN.label + ri"
+                                :label="String(radioN.id)"
+                                >{{ radioN.label }}</el-radio-button
+                              >
+                            </el-radio-group>
+                          </div>
+                          <div
+                            class="scheck"
+                            v-if="subItem.action && subItem.action.length > 0"
+                          >
+                            <div class="checkAll">
+                              <el-checkbox
+                                v-model="subItem.checkAll"
+                                :disabled="editType == 'view'"
+                                :indeterminate="indeterminateCheck(subItem)"
+                                @change="
+                                  handleCheckAllChange(
+                                    $event,
+                                    index,
+                                    item,
+                                    subIndex
+                                  )
+                                "
+                                >功能全选</el-checkbox
+                              >
+                            </div>
+                            <div class="checkItem">
+                              <el-checkbox-group
+                                v-model="subItem.checkList"
+                                :disabled="editType == 'view'"
+                                @change="
+                                  handleCheckedGroupChange(
+                                    $event,
+                                    index,
+                                    item,
+                                    subIndex
+                                  )
+                                "
+                              >
+                                <el-checkbox
+                                  :disabled="editType == 'view'"
+                                  v-for="children in subItem.action"
+                                  :key="'checkItem' + children.id"
+                                  :label="String(children.id)"
+                                  @change="
+                                    handleCheckedChange(
+                                      $event,
+                                      String(children.id),
+                                      index,
+                                      subIndex,
+                                      item
+                                    )
+                                  "
+                                  >{{ children.action_name }}</el-checkbox
+                                >
+                              </el-checkbox-group>
+                            </div>
+                          </div>
+                          <div
+                            class="sfield"
+                            v-if="
+                              subItem.action_data &&
+                              subItem.action_data.length > 0
+                            "
+                          >
+                            <div class="checkAll">
+                              <el-checkbox
+                                v-model="subItem.fieldAll"
+                                :disabled="editType == 'view'"
+                                :indeterminate="indeterminateField(subItem)"
+                                @change="
+                                  handleFieldAllChange(
+                                    $event,
+                                    index,
+                                    item,
+                                    subIndex
+                                  )
+                                "
+                                >字段全选</el-checkbox
+                              >
+                            </div>
+                            <div class="checkItem">
+                              <el-checkbox-group
+                                v-model="subItem.fieldList"
+                                :disabled="editType == 'view'"
+                                @change="
+                                  handleFieldGroupChange(
+                                    $event,
+                                    index,
+                                    item,
+                                    subIndex
+                                  )
+                                "
+                              >
+                                <el-checkbox
+                                  v-for="children in subItem.action_data"
+                                  :key="'FieldItem' + children.id"
+                                  :label="String(children.id)"
+                                  :disabled="editType == 'view'"
+                                  @change="
+                                    handleFieldChange(
+                                      $event,
+                                      String(children.id),
+                                      index,
+                                      subIndex,
+                                      item
+                                    )
+                                  "
+                                  >{{ children.field_name }}</el-checkbox
+                                >
+                              </el-checkbox-group>
+                            </div>
+                          </div>
+                        </template>
+                      </div>
+                    </div>
+                  </el-col>
+                </el-row>
+              </div>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-col :span="24" class="clear">
+        <el-button
+          v-if="editType == 'add' || editType == 'edit'"
+          type="primary"
+          class="fr"
+          :loading="loading"
+          style="margin: 0 0 0 16px"
+          @click="submitForm(ruleFormRef)"
+          >保存</el-button
+        >
+        <el-button class="fr" style="margin: 0 0 0 16px" @click="closeDialog"
+          >关闭</el-button
+        >
+      </el-col>
+    </el-form>
+  </el-dialog>
+</template>
+<style lang="scss" scoped>
+.role-addedit {
+  .quanxian-main {
+    width: 100%;
+    display: flex;
+
+    .quanxian-title {
+      width: 50px;
+      position: relative;
+      padding: 6px 0 0 7px;
+      text-align: center;
+
+      div {
+        font-size: 14px;
+        color: #606266;
+        font-weight: 700;
+      }
+    }
+
+    .rule-view {
+      width: calc(100% - 50px);
+      position: relative;
+      height: 550px;
+      overflow-y: scroll;
+      border-top: 1px solid #dfe6ec;
+      border-left: 1px solid #dfe6ec;
+
+      // padding: 0 0 0 16px;
+      .ffff {
+        width: 100%;
+        display: flex;
+        align-items: stretch;
+
+        .ftitle {
+          width: 40px;
+          text-align: center;
+          border-right: 1px solid #dfe6ec;
+          border-bottom: 1px solid #dfe6ec;
+          padding: 10px 0;
+          display: flex;
+          align-items: center;
+          flex-direction: column;
+          justify-content: center;
+
+          div {
+            font-size: 17px;
+            height: 22px;
+            line-height: 22px;
+            text-align: center;
+            color: #97a8be;
+          }
+        }
+
+        .fbody {
+          width: calc(100% - 40px);
+          border-right: 1px solid #dfe6ec;
+
+          .fbody-item {
+            // border-right: 1px solid #dfe6ec;
+            border-bottom: 1px solid #dfe6ec;
+
+            .stitle {
+              padding: 15px 18px 10px 18px;
+              border-bottom: 1px dashed #dfe6ec;
+              font-size: 14px;
+              color: #97a8be;
+
+              ._h2 {
+                display: inline-block;
+                height: 24px;
+                line-height: 24px;
+              }
+            }
+
+            .scheck {
+              padding: 15px 0 10px 0;
+              display: flex;
+              width: 100%;
+
+              .checkAll {
+                width: 110px;
+                text-align: right;
+                padding: 0 25px 0 0;
+              }
+
+              .checkItem {
+                width: calc(100% - 120px);
+              }
+            }
+
+            .sfield {
+              padding: 0 0 10px 0;
+              display: flex;
+              width: 100%;
+
+              .checkAll {
+                width: 140px;
+                text-align: right;
+                padding: 0 35px 0 0;
+              }
+
+              .checkItem {
+                width: calc(100% - 140px);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 77 - 0
src/views/supplierManage/supplierRole/columns.tsx

@@ -0,0 +1,77 @@
+import { ref } from "vue";
+import dayjs from "dayjs";
+import { statusList, levelList } from "/@/utils/status";
+export function useColumns() {
+  const columns = ref([
+    {
+      type: "selection",
+      width: 55,
+      hide: ({ checkList }) => !checkList.includes("勾选列")
+    },
+    {
+      label: "序号",
+      type: "index",
+      width: 70,
+      hide: ({ checkList }) => !checkList.includes("序号列")
+    },
+
+    {
+      label: "角色名称",
+      prop: "role_name"
+    },
+    {
+      label: "业务公司",
+      prop: "companyName"
+    },
+    {
+      label: "等级",
+      prop: "level",
+      cellRenderer: ({ row, props }) => (
+        <el-tag
+          size={props.size}
+          type={
+            (levelList.find(item => item.value == row.level + "") || {}).type ||
+            "info"
+          }
+          effect="plain"
+        >
+          {(levelList.find(item => item.value == row.level + "") || {}).label ||
+            "--"}
+        </el-tag>
+      )
+    },
+    {
+      label: "状态",
+      prop: "status",
+      cellRenderer: ({ row, props }) => (
+        <el-tag
+          size={props.size}
+          type={
+            (statusList.find(item => item.value == row.status + "") || {})
+              .type || "info"
+          }
+          effect="plain"
+        >
+          {(statusList.find(item => item.value == row.status + "") || {})
+            .label || "--"}
+        </el-tag>
+      )
+    },
+
+    {
+      label: "创建时间",
+      prop: "createTime",
+      formatter: ({ addtime }) => dayjs(addtime).format("YYYY-MM-DD HH:mm:ss")
+    },
+    {
+      label: "操作",
+      fixed: "right",
+      width: 145,
+      slot: "operation"
+    }
+  ]);
+
+  return {
+    columns
+  };
+}

+ 281 - 0
src/views/supplierManage/supplierRole/index.vue

@@ -0,0 +1,281 @@
+<script setup lang="ts">
+import { reactive, ref, onMounted, watch } from "vue";
+import { useColumns } from "./columns";
+import { httpList, httpStatus } from "/@/api/supplierManage/supplierRole";
+import { type FormInstance } from "element-plus";
+import { ElMessage } from "element-plus";
+import { TableProBar } from "/@/components/ReTable";
+import { type PaginationProps } from "@pureadmin/table";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { useNav } from "/@/layout/hooks/nav";
+import { statusList } from "/@/utils/status";
+import { responseHandle } from "/@/utils/responseHandle";
+import { useUserStoreHook } from "/@/store/modules/user";
+import addEdit from "./addEdit.vue";
+import { useCompany } from "/@/hooks/core/useCompany";
+const { logout } = useNav();
+
+defineOptions({
+  name: "role"
+});
+
+const form = reactive({
+  level: "",
+  role_name: "",
+  status: "",
+  page: 1,
+  size: 15
+});
+
+const powers = ref([]);
+const dataList = ref([]);
+const loading = ref(true);
+const { columns } = useColumns();
+const showModel = ref(false);
+const itemId = ref("");
+const isDetails = ref("add");
+const formRef = ref<FormInstance>();
+
+const { currentCompany } = useCompany();
+
+const pagination = reactive<PaginationProps>({
+  total: 0,
+  pageSize: 15,
+  currentPage: 1,
+  background: true
+});
+//修改状态
+const handleStatus = async row => {
+  const { id, status } = row;
+  const { code, message } = await httpStatus({
+    roleid: id,
+    status: status + "" === "1" ? "0" : "1"
+  });
+  responseHandle({
+    code,
+    message,
+    logout,
+    handler: () => onSearch()
+  });
+};
+
+async function handleCurrentChange(val: number) {
+  form.page = val;
+  await onSearch();
+}
+
+async function handleSizeChange(val: number) {
+  form.size = val;
+  form.page = 1;
+  await onSearch();
+}
+
+function handleSelectionChange(val) {
+  console.log("handleSelectionChange", val);
+}
+
+async function onSearch() {
+  loading.value = true;
+  const { code, data, message } = await httpList({
+    ...form,
+    companyNo: currentCompany.value.companyNo
+  });
+  if (code === 0) {
+    const { list, count } = data;
+    dataList.value = list ?? [];
+    pagination.total = count ?? 0;
+    pagination.pageSize = form.size;
+    pagination.currentPage = form.page;
+  } else if (code > 100 && code < 140) {
+    logout();
+  } else {
+    ElMessage.error(message);
+  }
+  loading.value = false;
+}
+async function resetSearch() {
+  form.page = 1;
+  await onSearch();
+}
+//新建/编辑/详情弹窗
+function editItem(id, type) {
+  // if (!currentCompany.value.companyNo) {
+  //   ElMessage.warning("请选择一个公司");
+  //   return;
+  // }
+
+  itemId.value = id;
+  isDetails.value = type;
+  showModel.value = true;
+}
+const submitRefresh = () => {
+  showModel.value = false;
+  onSearch();
+};
+const submitCancel = () => {
+  showModel.value = false;
+};
+
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  form.page = 1;
+  onSearch();
+};
+
+onMounted(() => {
+  powers.value = useUserStoreHook().getMenuActions("role");
+  if (powers.value.some(i => i == "001")) {
+    onSearch();
+  }
+});
+
+watch(
+  () => currentCompany.value,
+  () => onSearch()
+);
+</script>
+
+<template>
+  <div class="main role">
+    <div v-show="powers.some(i => i == '001')">
+      <el-form
+        ref="formRef"
+        :inline="true"
+        :model="form"
+        size="small"
+        :label-width="0"
+        class="bg-white w-99/100 pl-8 pt-4"
+      >
+        <el-form-item prop="status">
+          <el-select
+            v-model="form.status"
+            style="width: 100%"
+            placeholder="角色状态"
+            clearable
+          >
+            <el-option
+              v-for="(si, sii) in statusList"
+              :key="'status' + si.value + sii"
+              :label="si.label"
+              :value="si.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item prop="role_name">
+          <el-input v-model="form.role_name" placeholder="角色名称" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            :icon="useRenderIcon('search')"
+            :loading="loading"
+            @click="resetSearch"
+          >
+            搜索
+          </el-button>
+          <el-button
+            :icon="useRenderIcon('refresh')"
+            @click="resetForm(formRef)"
+          >
+            重置
+          </el-button>
+        </el-form-item>
+      </el-form>
+
+      <TableProBar
+        title="公司角色管理"
+        :loading="loading"
+        :dataList="dataList"
+        @refresh="onSearch"
+      >
+        <template #buttons>
+          <el-button
+            type="primary"
+            size="small"
+            v-if="powers.some(i => i == '002')"
+            :icon="useRenderIcon('add')"
+            @click="editItem('', 'add')"
+          >
+            新增角色
+          </el-button>
+        </template>
+        <template v-slot="{ size, checkList }">
+          <PureTable
+            border
+            align="left"
+            showOverflowTooltip
+            table-layout="auto"
+            size="small"
+            :data="dataList"
+            :columns="columns"
+            :checkList="checkList"
+            :pagination="pagination"
+            :paginationSmall="size === 'small' ? true : false"
+            :header-cell-style="{ background: '#fafafa', color: '#606266' }"
+            @selection-change="handleSelectionChange"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+          >
+            <template #operation="{ row }">
+              <el-button
+                class="reset-margin"
+                link
+                type="primary"
+                v-if="powers.some(i => i == '007')"
+                :size="size"
+                @click="editItem(row.id, 'view')"
+                :icon="useRenderIcon('eye-view')"
+              />
+              <el-button
+                class="reset-margin"
+                link
+                type="primary"
+                :size="size"
+                v-if="powers.some(i => i == '005')"
+                @click="editItem(row.id, 'edit')"
+                :icon="useRenderIcon('edits')"
+              />
+              <el-popconfirm
+                :title="row.status === '1' ? '改为禁用?' : '改为启用?'"
+                v-if="
+                  (powers.some(i => i == '004') && row.status + '' === '1') ||
+                  (powers.some(i => i == '003') && row.status + '' === '0')
+                "
+                @confirm="handleStatus(row)"
+              >
+                <template #reference>
+                  <el-button
+                    class="reset-margin"
+                    link
+                    type="primary"
+                    :size="size"
+                    :icon="
+                      useRenderIcon(
+                        row.status === '1'
+                          ? 'close-circle-line'
+                          : 'checkbox-circle-line'
+                      )
+                    " /></template
+              ></el-popconfirm>
+            </template>
+          </PureTable>
+        </template>
+      </TableProBar>
+      <addEdit
+        :itemId="itemId"
+        :isDetails="isDetails"
+        :show-model="showModel"
+        @refresh="submitRefresh"
+        @cancel="submitCancel"
+      />
+    </div>
+    <NoAuth v-show="!powers.some(i => i == '001')" />
+  </div>
+</template>
+
+<style scoped lang="scss">
+:deep(.el-dropdown-menu__item i) {
+  margin: 0;
+}
+</style>

+ 7 - 0
src/views/supplierManage/supplierRole/types.ts

@@ -0,0 +1,7 @@
+export interface menuType {
+  roleid?: string; //角色id
+  role_name?: string; //角色名称
+  level?: string; //级别
+  action?: string; //按钮权限
+  private_data?: string; //私有权限
+}