Skip to content
On this page

供应商登录后维护企业信息

TIP

项目需求: 供应商登录系统后,如果企业信息联系人、银行、地址、组织信息未维护完全,强制供应商维护企业信息;否则不允许该供应商任何系统操作;

实现

txt
需求实现步骤:

1. 需要新增接口 `/supplier/supplierMaster/checkSupplier`, 用于查询当前供应商是否已维护联系人、银行等企业信息;
2. 本地路由, 新增 `关联企业编辑` 路由配置;
3. 登录页, 判断当前大B账号是否为供应商;
4. 全局路由守卫, 供应商登录或每次刷新浏览器时调用 `/checkSupplier` 接口, 如果信息未维护则执行页面跳转;
5. `关联企业编辑`页面,用户保存后再次调用`/checkSupplier` 接口, 如果信息已维护则跳转至首页, 完成业务闭环。
txt
# .env
#采购大B账号
VITE_PURCHASE_ELSACCOUNT = 1664299
ts
const PROJECT_PORTAL_LOGIN_PAGE_PATH = import.meta.env
  .VITE_PROJECT_PORTAL_LOGIN_PAGE_PATH;

export const secondDevRoutes = [
  {
    path: PROJECT_PORTAL_LOGIN_PAGE_PATH,
    name: "login",
    component: () => import("@views/secondDev/user/login.vue"),
  },
  {
    path: "/publicService/enterpriseEdit/:id",
    route: "1",
    meta: {
      keepAlive: false,
      title: "关联企业编辑",
      titleI18nKey: "",
    },
    name: "publicService-enterpriseEdit",
    component: () =>
      import("@views/secondDev/publicService/enterprise/enterpriseEdit.vue"),
  },
];
vue
<template>
  <aside class="log-pg h-100-vh h-w100">
    <!--头部-->
    <header class="log-pg-hd nav-w-1275 p-t-20-px">
      <CompanyLogo />
    </header>

    <!--内容-->
    <section class="log-pg-cn nav-w-1275">
      <div class="pg-cn-lf">
        <div class="lf-hi-txt display-center w-585-px">
          <span class="w-50-pc txt-center">
            {{ srmI18n("i18n_alert_jEnR_253e53c4", "优化采购") }}
          </span>
          <span class="w-50-pc txt-center">
            {{ srmI18n("i18n_alert_MlRd_2f0adf22", "携手共赢") }}</span
          >
        </div>
        <div class="w-585-px display-center lf-nomr-txt txt-center p-t-30-px">
          {{
            srmI18n(
              "i18n_alert_IOLXPuRQEQODxRdKRvXI_7f47687d",
              "已经为上千家制造业快速提高供应链管理效率"
            )
          }}75%
        </div>
        <div class="lf-img">
          <img
            class="w-100-pc"
            style="height: 96%; width: 96%"
            src="@/assets/img/common/login_bg.png"
            alt=""
          />
        </div>
      </div>
      <div class="pg-cn-rgt">
        <QLogin
          v-if="showPage"
          :isLoginLoading="loginLoading"
          :onBeforeFinish="onBeforeFinish"
          :theme="'light'"
          :isFeiShu="true"
          :thirdUserUUid="thirdUserUUid"
          @onFormFinish="onLginFinish"
          @onHandleForEmitgetPss="handleForEmitgetPss"
          @onhandleEmitSign="handleSign"
          @onFormError="handleOnFormError"
        />
      </div>
    </section>
  </aside>
</template>

<script lang="ts" setup>
import { srmI18n } from "@/utils/srmI18n";
import CompanyLogo from "./components/CompanyLogo.vue";
import { ref, onBeforeMount, onUnmounted, nextTick } from "vue";
import { useUserStore } from "@/stores/user";
import { useTabsStore } from "@/stores/tabs";
import { usePermissionStore } from "@/stores/permission";
import { usePageStore } from "@/stores/page";
import { useRoute, useRouter } from "vue-router";
import qqtApi from "@qqt-product/api";
import { useLanguageStore } from "@/stores/language";
import { generateIndexRouter } from "@/utils/util";
import { message as Message } from "ant-design-vue";
import type { MapObject } from "@/types";
import { storeToRefs } from "pinia";

const PURCHASE_ELSACCOUNT = import.meta.env.VITE_PURCHASE_ELSACCOUNT;

export interface FormState {
  elsAccount: string;
  subAccount: string;
  password: string;
}
export interface EncryptedKey {
  key: string;
  keyId: string;
}
defineOptions({
  name: "user-login",
});
const route = useRoute();
const router = useRouter();
const getRoutes = router.getRoutes();
const userStore = useUserStore();
const tabsStore = useTabsStore();
const pageStore = usePageStore();
const {
  setToken,
  setSrmVersion,
  setUserInfo,
  setCompanySet,
  setUserOrg,
  setBaseHomePath,
} = userStore;
const { userInfo } = storeToRefs(userStore);
const Request: qqtApi.Request = qqtApi.useHttp();
const useLanguage = useLanguageStore();
const thirdUserUUid = ref("");
const permissionStore = usePermissionStore();
const { setAllAuth, setAuth, setDoc, setMenu } = permissionStore;
const loginLoading = ref<boolean>(false);
const showPage = ref(false);
const onBeforeFinish = function () {
  loginLoading.value = true;
};

const onLginFinish = function (res: MapObject) {
  const result = res.result;
  setToken(result.token);
  setSrmVersion(result.srmVersion);
  setUserInfo(result.userInfo);
  setCompanySet(result.companySet);
  setUserOrg(result.userOrg);
  localStorage.setItem("t_token", result.token);
  tabsStore.closeAllTab(router);
  useLanguage.modifyCompanyListLangData();
  // TODO 原逻辑只跳转至首页,在beforeEach 勾子里处理redirect跳转逻辑
  // 现移动到这里
  if (route.query.redirect) {
    if (typeof route.query.redirect === "string") {
      router.push({ path: route.query.redirect });
    }
    loginLoading.value = false;
  } else {
    if (userInfo.value.elsAccount !== PURCHASE_ELSACCOUNT) {
      router.push({ path: "/" });
    } else {
      // 跳转至首页
      loginLoading.value = true;
      Request.registerModuleAction("queryPermissionsByUser", {
        token: result.token,
      })
        .then(async (res: MapObject) => {
          if (res.success && res.result) {
            let { menu = [], allAuth = [], auth = [], doc = [] } = res.result;
            setAllAuth(allAuth);
            setAuth(auth);
            setDoc(doc);
            setMenu(menu);
            if (menu && menu.length) {
              const dynamicRoute = generateIndexRouter(menu);
              console.log("dynamicRoute", dynamicRoute);
              router.addRoute(dynamicRoute);
              let baseHomePath = menu[0].path || menu[0].fullPath;
              setBaseHomePath(baseHomePath);
              await router.push({ path: baseHomePath });
            } else {
              Message.error("未获取到已授权的菜单信息");
            }
          }
        })
        .finally(() => {
          loginLoading.value = false;
        });
    }
  }
};

const handleForEmitgetPss = function () {
  router.push({ path: "/user/forgetPassword" });
};

const handleSign = function () {
  router.push({ path: "/user/register" });
};
const handleOnFormError = () => {
  loginLoading.value = false;
};

const resetStore = () => {
  nextTick(() => {
    // 清空各模块列表页当前行缓存数据
    pageStore.$reset();
    // 清空当前登录人动态授权信息
    userStore.$reset();
    // 清空动态路由权限
    permissionStore.$reset();
    // 清空tabs
    tabsStore.$reset();
  });
};

const loginByToken = () => {
  let token = route.query?.token;
  if (token) {
    resetStore();
    loginLoading.value = true;
    Request.registerModuleAction("LoginModule/loginByToken", {
      token: token,
    }).then((res) => {
      loginLoading.value = false;
      if (res && res.success) {
        onLginFinish(res);
      } else {
        Message.error(res.message);
        router.replace({ path: "/user/login" });
      }
    });
  }
};

onBeforeMount(() => {
  if (localStorage.getItem("THIRD_USER_UUID")) {
    thirdUserUUid.value = localStorage.getItem("THIRD_USER_UUID") as string;
  }
  loginByToken();
});
setTimeout(() => {
  showPage.value = true;
}, 500);
onUnmounted(() => {
  if (localStorage.getItem("THIRD_USER_UUID")) {
    localStorage.removeItem("THIRD_USER_UUID");
  }
});
</script>

<style lang="scss" scoped>
.log-pg {
  background-image: linear-gradient(-20deg, #b721ff 0%, #4a04e6 100%);
  overflow: hidden;
  .nav-w-1275 {
    width: 1275px;
    margin: 0 auto;
  }
  .log-pg-hd {
    display: flex;
    justify-content: flex-start;
  }
  .log-pg-cn {
    overflow: hidden;
    display: flex;
    position: relative;
    .pg-cn-lf {
      width: 820px;
      color: #fff;
      margin-top: 9vh;
      .lf-hi-txt {
        font-size: 40px;
        font-weight: 600;
        span {
          display: inline-block;
          &:first-child {
            text-indent: 30px;
          }
          &:last-child {
            text-indent: -30px;
          }
        }
      }
      .lf-nomr-txt {
        font-size: 22px;
      }
      .lf-img {
        width: 950px;
        height: 713px;
        margin-top: -5vh;
      }
    }
    .pg-cn-rgt {
      position: absolute;
      right: 1vw;
      top: 12vh;
    }
  }
}

.w-585-px {
  width: 585px;
}
.display-center {
  margin: 0 auto;
}
</style>
ts
/**
 * Navigation Guards
 * @description 路由守卫
 * @tutorial https://router.vuejs.org/guide/advanced/navigation-guards.html
 */
import { storeToRefs } from "pinia";
import { useUserStore } from "@/stores/user";
import { usePageStore } from "@/stores/page";
import { usePermissionStore } from "@/stores/permission";
import qqtUtils from "@qqt-product/utils";
import { ROUTER_WHITE_LIST } from "../whiteList";
import { generateIndexRouter, formatDate } from "@/utils/util";
import Request from "@/utils/qApiPlugin";
// ui组件库 types
import { GlobalPageLayoutTypes } from "@qqt-product/ui";
import { notification as Notification } from "ant-design-vue";

import type {
  // NavigationGuardWithThis,
  RouteLocationNormalized,
  NavigationGuardNext,
  Router,
} from "vue-router";
const PROJECT_PORTAL_PAGE_PATH = import.meta.env.VITE_PROJECT_PORTAL_PAGE_PATH;
const PROJECT_PORTAL_LOGIN_PAGE_PATH = import.meta.env
  .VITE_PROJECT_PORTAL_LOGIN_PAGE_PATH;
const PURCHASE_ELSACCOUNT = import.meta.env.VITE_PURCHASE_ELSACCOUNT;

const watermarkFn = () => {
  const userStore = useUserStore();
  const { userInfo, companySet } = userStore;
  if (userInfo) {
    const waterMarkTip =
      userInfo.elsAccount +
      "-" +
      userInfo.subAccount +
      "-" +
      formatDate(new Date().getTime(), "yyyy/MM/dd");
    if (companySet.watermark && companySet.watermark === "1") {
      qqtUtils.waterMark.set(waterMarkTip);
    }
  }
};
// 动态路由权限校验
// TODO 页面加载虚拟进度条(如:Nprogress)
export const createPermissionGuard = (router: Router) => {
  router.beforeEach(
    (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized,
      next: NavigationGuardNext
    ): void => {
      // 白名单免登状态
      if (ROUTER_WHITE_LIST.includes(to.path)) {
        return next();
      }
      const userStore = useUserStore();
      const { userInfo, token } = storeToRefs(userStore);
      const { setBaseHomePath } = userStore;
      // 处理未登录, 无token状态
      // TODO token在有效期内不清埋,注意清理token时一并清理pinia路由模块的动态路由缓存
      // 跳转至登录页面, 缓存原路由路转地址
      if (!token.value) {
        // 排除当前路径为'/',跳转到门户页面,否则跳转到门户登录页
        if (!to.path || to.path === "/") {
          next({
            path: PROJECT_PORTAL_PAGE_PATH,
            query: { redirect: to.fullPath },
          });
        } else {
          next({
            path: PROJECT_PORTAL_LOGIN_PAGE_PATH,
            query: { redirect: to.fullPath },
          });
        }
      } else {
        const pageStore = usePageStore();
        const { setCurrentRow } = pageStore;
        const permissionStore = usePermissionStore();
        const { setAllAuth, setAuth, setDoc, setMenu, setIsUnPass } =
          permissionStore;
        const { isUnPass, menu } = storeToRefs(permissionStore);

        const setUserPermissionData = () => {
          // 处理登录获取token后跳转情况
          // TODO 动态注册权限路由
          Request.get({
            url: `/account/permission/getUserPermission`,
          }).then((res) => {
            if (res && res.success) {
              // 设置 permission 状态管理Pinia
              const result = res.result;
              setAllAuth(result.allAuth);
              setAuth(result.auth);
              setDoc(result.doc);
              setMenu(result.menu);
              const dynamicRoute = generateIndexRouter(result.menu);
              router.addRoute(dynamicRoute);

              const toBaseHome = () => {
                // 如果接口返回的权限路由数据不包含根目录'/'
                // next()时会导致死循环,此处增加判断
                // 根目录默认跳转至首页地址
                const fullPath = to.fullPath;
                const baseHomePath =
                  fullPath !== "/" ? fullPath : result.menu[0].path;
                setBaseHomePath(result.menu[0].path);
                /**
                 * Remember you can await router.replace() if you need to wait for the new route to be displayed.
                 */
                router.replace(baseHomePath).then(() => {
                  return baseHomePath;
                });
              };

              // toBaseHome()

              if (userInfo.value.elsAccount === PURCHASE_ELSACCOUNT) {
                toBaseHome();
              } else {
                Request.get({ url: `/supplier/supplierMaster/checkSupplier` })
                  .then((res) => {
                    if (res && res.success) {
                      setIsUnPass(!!res.result);
                    }
                  })
                  .finally(() => {
                    if (isUnPass.value) {
                      const url = "/supplier/supplierMaster/supplierlist";
                      const params = {
                        column: "id",
                        order: "desc",
                        pageSize: 20,
                        pageNo: 1,
                      };
                      Request.get({ url, params }).then((res) => {
                        const records =
                          (res.result
                            .records as GlobalPageLayoutTypes.CurrentRow[]) ||
                          [];
                        if (records.length) {
                          const { id, ...others } = records[0] || {};
                          setCurrentRow({ id, ...others });
                          const path = `/publicService/enterpriseEdit/${id}`;
                          Notification.warning({
                            message: "提示",
                            description: "请维护关联企业-联系人信息页签内容",
                            duration: null,
                          });
                          next({ path });
                        } else {
                          toBaseHome();
                        }
                      });
                    } else {
                      toBaseHome();
                    }
                  });
              }
            }
          });
        };

        // 处理已登录情况
        // 如果permission模块中menu
        if (menu.value && menu.value.length) {
          watermarkFn();
          next();
        } else {
          setUserPermissionData();
        }
      }
    }
  );
};
vue
<template>
  <div class="edit-page enterpriseEdit">
    <a-alert
      message="警告"
      description="请维护企业信息, 否则不能查看订单和报价"
      type="warning"
      show-icon
    />
    <div class="content-box">
      <a-spin :spinning="customLoading">
        <q-edit-page-layout
          ref="layoutRef"
          v-bind="options"
          @bankFileDownload="handleBankFileDownload"
          @back="back"
          @customSave="handleCustomSave"
          @customPublish="handleCustomPublish"
          @validate-success="handleValidateSuccess"
          @addSupplierContactsInfo="handleAddSupplierContactsInfo"
          @deleteSupplierContactsInfo="handleDeleteSupplierContactsInfo"
          @addAddressItem="handleAddAddressItem"
          @delAddressItem="handleDelAddressItem"
          @addBankItem="handleAddBankItem"
          @delBankItem="handleDelBankItem"
          @customAdd="handleCustomAdd"
          @customDel="handleCustomDel"
          @pageBack="handlePageBack"
          @customLogout="handleLogout"
        ></q-edit-page-layout>
      </a-spin>
    </div>
  </div>
</template>

<script lang="tsx" setup>
import { ref, reactive, nextTick } from "vue";
import type { ComponentPublicInstance } from "vue";
import { useRouter } from "vue-router";
// 国际化
import { srmI18n } from "@/utils/srmI18n";
// ui组件库 types
import { GlobalPageLayoutTypes } from "@qqt-product/ui";
import { usePromiseStepHook, useRefInstanceHook } from "@qqt-product/ui";
import type { VxeColumnSlotTypes, VxeTableDataRow } from "vxe-table";
// 按钮常量引用
import {
  BUTTON_SUBMIT,
  BUTTON_SAVE,
  BUTTON_CUSTOM_PRIMARY,
  BUTTON_CUSTOM_DANGER,
  BUTTON_ADD_ONE_ROW,
  BUTTON_DELETE_ROW,
  BUTTON_UPLOAD,
  BUTTON_DOWNLOAD_ALL,
} from "@qqt-product/ui";

// 全局数据缓存
// 当前行 currentRow, 当前用户信息 userInfo
import { useGlobalStoreWithDefaultValue } from "@/use/useGlobalStore";
import { useFileColumnHook } from "@qqt-product/ui";
import qqtUtils from "@qqt-product/utils";

import { notification as Notification, message, Modal } from "ant-design-vue";

import { useUserStore } from "@/stores/user";
import { usePermissionStore } from "@/stores/permission";
import { usePageStore } from "@/stores/page";
import { useTabsStore } from "@/stores/tabs";
import { storeToRefs } from "pinia";

const PURCHASE_ELSACCOUNT = import.meta.env.VITE_PURCHASE_ELSACCOUNT;

const userStore = useUserStore();
const permissionStore = usePermissionStore();
const pageStore = usePageStore();
const tabsStore = useTabsStore();

const { setIsUnPass } = permissionStore;
const { isUnPass } = storeToRefs(permissionStore);
const { baseHomePath } = storeToRefs(userStore);

const { uniqueId, remove, createPromise } = qqtUtils;
const { isCreate, getCurrentRow, userInfo } = useGlobalStoreWithDefaultValue();
const currentRow = getCurrentRow();
import type { CreatePromise } from "@qqt-product/utils";

import qqtApi from "@qqt-product/api";
defineOptions({
  name: "publicService-enterprise-edit",
});

const Request: qqtApi.Request = qqtApi.useHttp();

const router = useRouter();

const apiUrls = reactive({
  edit: "/supplier/supplierInfoChangeHead/edit",
  detail:
    currentRow.changeNumber && currentRow.initiatorElsAccount
      ? "/supplier/supplierInfoChangeHead/queryAfterInfoById"
      : "/supplier/supplierMaster/queryById",
  submit: "/supplier/supplierInfoChangeHead/submit",
  release: "/supplier/supplierInfoChangeHead/releaseByIds",
  download: "/attachment/purchaseAttachment/download",
});
// 编辑组件 ref
const layoutRef = ref<ComponentPublicInstance | null>(null);
const { pageData, layoutConfig, defaultValues } = useRefInstanceHook(layoutRef);

// 退出登录
const handleLogout = () => {
  Modal.confirm({
    title: "提示",
    content: "是否确定退出",
    onOk() {
      logout();
    },
  });
};
const logout = () => {
  Request.post({ url: "/account/logout" }).then(() => {
    // 重置状态管理Pinia
    nextTick(() => {
      // 清空各模块列表页当前行缓存数据
      pageStore.$reset();
      // 清空当前登录人动态授权信息
      userStore.$reset();
      // 清空动态路由权限
      permissionStore.$reset();
      // 清空tabs
      tabsStore.$reset();
    });
    router.push({
      path: `/user/login`,
    });
  });
};

// 省份字段插槽配置
/**
 * @description: 业务规则:
 * 国家/地区的值为”中国“时, 省份字段允许设置为远程下拉搜索,否则为输入框
 */
const provinceColumns: GlobalPageLayoutTypes.ColumnItem = {
  groupCode: "supplierAddressInfoList",
  title: "省份",
  fieldLabelI18nKey: "i18n_title_province",
  field: "province",
  fieldType: "",
  width: 150,
  editRender: {
    enabled: true,
  },
  slots: {
    default({
      row,
      column,
    }: VxeColumnSlotTypes.DefaultSlotParams<VxeTableDataRow>) {
      return [
        <span>{row[`${column.field}_dictText`] || row[column.field]}</span>,
      ];
    },
    edit({
      row,
      column,
      $rowIndex,
    }: VxeColumnSlotTypes.EditSlotParams<VxeTableDataRow>) {
      // 处理手输
      if (
        row.country === "中国" ||
        row.country === "CN" ||
        row.country === "CN_中国"
      ) {
        const props = {
          config: {
            extend: {
              modalColumns: [
                {
                  field: "provinceName",
                  title: "省份名称",
                  fieldLabelI18nKey: "i18n_field_bzRL_374bc89f",
                  with: 350,
                },
                {
                  field: "cityName",
                  title: "城市名称",
                  fieldLabelI18nKey: "i18n_field_city",
                  with: 350,
                },
                {
                  field: "areasName",
                  title: "地区名称",
                  fieldLabelI18nKey: "i18n_field_nMRL_28e52f0d",
                  with: 350,
                },
                {
                  field: "streetsName",
                  title: "乡道/街道名称",
                  fieldLabelI18nKey: "i18n_field_duyuRL_bb7eb13c",
                  with: 350,
                },
              ],
              modalUrl: "/base/dict/queryDzAddressPage",
              params: {},
              selectModal: "single",
              handleAfter: ({ row }) => {
                row.province = "";
                row.city = "";
                row.address = "";
              },
            },
          },
        };

        const onVxeSelectModalChange = (
          data: GlobalPageLayoutTypes.RecordString[]
        ) => {
          if (!data || !data.length) {
            return;
          }

          const {
            provinceName = "",
            cityName = "",
            areasName = "",
            streetsName = "",
          } = data[0] || {};
          const address = `${areasName}${streetsName}`;
          row.province = provinceName;
          row.city = cityName;
          row.address = address;
          if ($rowIndex === 0) {
            // 地区
            pageData.value.fbk10 = provinceName;
            // 城市
            pageData.value.fbk9 = cityName;
            // 详细地址
            pageData.value.fbk3 = address;
          }
        };

        return [
          <q-select-modal
            v-model:value={row[column.field]}
            {...props}
            onChange={onVxeSelectModalChange}
          ></q-select-modal>,
        ];
      }

      const onVxeInputBlur = ({ value }: { value: string }) => {
        if ($rowIndex === 0) {
          // 地区
          pageData.value.fbk10 = value;
        }
      };

      return [
        <vxe-input
          v-model={row[column.field]}
          onBlur={onVxeInputBlur}
        ></vxe-input>,
      ];
    },
  },
};

const handleAfterDetailApiResponse: (
  payload: GlobalPageLayoutTypes.Expose
) => void = (payload) => {
  const { pageData, layoutConfig, defaultValues } = payload;

  if (pageData.id) {
    layoutConfig.groups.forEach((group) => {
      const regex = /supplierMasterCustom.*List/;
      console.log("regex.test(group.groupCode)", group.groupCode);
      if (group.groupCode === "supplierAddressInfoList") {
        if (group.groupType === "item") {
          let columns = group.columns || [];
          const idx = columns.findIndex((n) => n.field === "province");
          if (idx !== -1) {
            columns.splice(idx, 1, provinceColumns);
            group.columns = columns;
          }
        }
      }

      if (regex.test(group.groupCode)) {
        group.buttons = [
          {
            ...BUTTON_ADD_ONE_ROW,
            emit: true,
            emitKey: "customAdd",
          },
          {
            ...BUTTON_DELETE_ROW,
            emit: true,
            emitKey: "customDel",
          },
        ];
      }
    });
  }
};

// 配置
const options = reactive<Partial<GlobalPageLayoutTypes.EditPageLayoutProps>>({
  showBackIcon: false,
  pageTitle: "关联企业列表",
  /**
   * 模块业务类型 string
   * 取值根据各模块配置
   * 当定义为"custom"时,使用本地配置
   */
  businessType: "supplierMasterData",
  role: userInfo.value.elsAccount === PURCHASE_ELSACCOUNT ? "purchase" : "sale",
  // 布局模式
  pattern: "vertical",
  // 当前已选行数据
  currentRow: currentRow,
  refreshMethods(row?: GlobalPageLayoutTypes.CurrentRow) {
    if (options.currentRow) {
      options.currentRow =
        row ||
        Object.assign({}, options.currentRow, {
          _t: +new Date(),
        });
    }
  },
  // 当前登录租户信息
  userInfo: userInfo.value as GlobalPageLayoutTypes.UserInfo,
  // 明细接口 -- 接口字符串
  detailApi: apiUrls.detail,
  handleAfterDetailApiResponse: handleAfterDetailApiResponse,
  // 本地页面数据配置
  localConfig: {
    groups: [
      {
        groupName: "拓展信息",
        // groupNameI18nKey: 'i18n_field_expendForm',
        groupCode: "expandForm",
        groupType: "head",
        // sortOrder: '2',
        show: false,
      },
      {
        groupName: "组织信息",
        // groupNameI18nKey: 'i18n_title_organizationInfo',
        groupCode: "supplierOrgInfoList",
        groupType: "item",
        // sortOrder: '6',
        show: false,
      },
      {
        groupName: "自定义表一",
        // groupNameI18nKey: 'i18n_field_JIIBI_5193f5b1',
        groupCode: "supplierMasterCustom1List",
        groupType: "item",
        // sortOrder: '8',
        show: false,
      },
      {
        groupName: "自定义表二",
        // groupNameI18nKey: 'i18n_field_JIIBx_5193f63d',
        groupCode: "supplierMasterCustom2List",
        groupType: "item",
        // sortOrder: '9',
        show: false,
      },
      {
        groupName: "自定义表三",
        // groupNameI18nKey: 'i18n_field_JIIBI_5193f5ba',
        groupCode: "supplierMasterCustom3List",
        groupType: "item",
        // sortOrder: '10',
        show: false,
      },
      {
        groupName: "自定义表四",
        // groupNameI18nKey: 'i18n_field_JIIBC_5193fe8c',
        groupCode: "supplierMasterCustom4List",
        groupType: "item",
        // sortOrder: '11',
        show: false,
      },
      {
        groupName: "自定义表五",
        // groupNameI18nKey: 'i18n_field_JIIBS_5193f645',
        groupCode: "supplierMasterCustom5List",
        groupType: "item",
        // sortOrder: '12',
        show: false,
      },
      {
        groupName: "自定义表六",
        // groupNameI18nKey: 'i18n_field_JIIBQ_5193f91e',
        groupCode: "supplierMasterCustom6List",
        groupType: "item",
        // sortOrder: '13',
        show: false,
      },
      {
        groupName: "自定义表七",
        // groupNameI18nKey: 'i18n_field_JIIBA_5193f5b4',
        groupCode: "supplierMasterCustom7List",
        groupType: "item",
        // sortOrder: '14',
        show: false,
      },
      {
        groupName: "自定义表八",
        // groupNameI18nKey: 'i18n_field_JIIBd_5193f91c',
        groupCode: "supplierMasterCustom8List",
        groupType: "item",
        // sortOrder: '15',
        show: false,
      },
      {
        groupName: "自定义表九",
        // groupNameI18nKey: 'i18n_field_JIIBO_5193f60e',
        groupCode: "supplierMasterCustom9List",
        groupType: "item",
        // sortOrder: '16',
        show: false,
      },
      {
        groupName: "自定义表十",
        // groupNameI18nKey: 'i18n_field_JIIBK_5193faf2',
        groupCode: "supplierMasterCustom10List",
        groupType: "item",
        // sortOrder: '17',
        show: false,
      },
      {
        groupName: srmI18n(`i18n_field_AEVHAHBI_2f93ce75`, "企业信息变更附件"),
        groupCode: "supplierInfoChangeAttachmentList",
        groupType: "item",
        buttons: [BUTTON_UPLOAD, BUTTON_DELETE_ROW, BUTTON_DOWNLOAD_ALL],
      },
      {
        groupName: "联系人信息",
        groupNameI18nKey: "i18n_title_contactInfo",
        groupCode: "supplierContactsInfoList",
        groupType: "item",
        buttons: [
          {
            ...BUTTON_ADD_ONE_ROW,
            emit: true,
            emitKey: "addSupplierContactsInfo",
          },
          {
            ...BUTTON_DELETE_ROW,
            emit: true,
            emitKey: "deleteSupplierContactsInfo",
          },
        ],
      },
      {
        groupName: "地址信息",
        groupNameI18nKey: "i18n_title_addressInfo",
        groupCode: "supplierAddressInfoList",
        groupType: "item",
        buttons: [
          {
            ...BUTTON_ADD_ONE_ROW,
            emit: true,
            emitKey: "addAddressItem",
          },
          {
            ...BUTTON_DELETE_ROW,
            emit: true,
            emitKey: "delAddressItem",
          },
        ],
      },
      {
        groupName: "银行信息",
        groupNameI18nKey: "i18n_field_WEVHWW_d7693444",
        groupCode: "supplierBankInfoList",
        groupType: "item",
        buttons: [
          {
            ...BUTTON_ADD_ONE_ROW,
            emit: true,
            emitKey: "addBankItem",
          },
          {
            ...BUTTON_DELETE_ROW,
            emit: true,
            emitKey: "delBankItem",
          },
          {
            ...BUTTON_DOWNLOAD_ALL,
            title: srmI18n("i18n_btn_zRIKBI_35c36afa", "批量下载附件"),
            args: {
              url: "",
              idKey: "fileId",
            },
          },
        ],
      },
    ],
    itemColumns: [
      {
        groupCode: "supplierBankInfoList",
        title: srmI18n("i18n_title_accessory", "附件"),
        field: "fileUpload",
        width: 150,
        fieldType: "file",
        extend: {
          businessType: "supplierMasterData",
        },
        callback: (ctx, { fileData, row }) => {
          if (fileData) {
            row.fileName = fileData[0].fileName;
            row.filePath = fileData[0].filePath;
            row.fileId = fileData[0].id;
          }
        },
      },
      ...useFileColumnHook({ groupCode: "supplierInfoChangeAttachmentList" }),
    ],
  },
  // 页面按钮
  pageButtons: [
    {
      ...BUTTON_SAVE,
      args: {
        url: "/supplier/supplierInfoChangeHead/edit",
      },
      emit: true,
      emitKey: "customSave",
    },
    // {
    //   ...BUTTON_CUSTOM_PRIMARY,
    //   title: '发布',
    //   i18nKey: 'i18n_title_publish',
    //   emit: true,
    //   emitKey: 'customPublish',
    //   checkBefore: false,
    // },
    {
      ...BUTTON_CUSTOM_DANGER,
      title: "退出登录",
      emit: true,
      emitKey: "customLogout",
    },
  ],
});

const { customLoading, stepTriggerValidate, composeSave } = usePromiseStepHook({
  pageData,
  layoutConfig,
  defaultValues,
  options,
});

const handleDownload = async (row) => {
  const { id, fileName } = row;
  const res = await Request.get({
    url: apiUrls.download,
    responseType: "blob",
    params: {
      id,
    },
  });
  let url = window.URL.createObjectURL(new Blob([res as Blob]));
  let link = document.createElement("a");
  link.style.display = "none";
  link.href = url;
  link.setAttribute("download", fileName);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link); //下载完成移除元素
  window.URL.revokeObjectURL(url); //释放掉blob对象
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleBankFileDownload = ({ row }: any) => {
  if (!row.fileName) {
    message.warning(
      srmI18n(`i18n_title_lineNotDownload`, "该行没有可下载的附件")
    );
    return;
  }
  let param = {
    id: row.fileName.split("-")[0],
    fileName: row.fileName.split("-")[1],
    filePath: row.filePath,
  };
  handleDownload(param);
};

const back = (btn: GlobalPageLayoutTypes.PageButton) => {
  if (btn.key === BUTTON_SAVE.key) {
    Request.get({ url: `/supplier/supplierMaster/checkSupplier` })
      .then((res) => {
        if (res && res.success) {
          setIsUnPass(!!res.result);
        }
      })
      .finally(() => {
        if (!isUnPass.value) {
          router.push({ path: baseHomePath.value });
        }
      });
  }
  if (btn.key === BUTTON_SUBMIT.key) {
    // 发布完成后返回列表需要刷新
    // 返回列表path
    const path = "/publicService/enterprise/list";
    router.push({ path, query: { t: new Date().getTime() } });
  }
};

// 执行自定义校验
const customCheck: () => boolean = () => {
  // 联系人信息
  const supplierContactsInfoList =
    pageData.value.supplierContactsInfoList || [];
  if (!supplierContactsInfoList || !supplierContactsInfoList.length) {
    message.error("请维护联系人信息");
    return false;
  }
  // 地址信息
  const supplierAddressInfoList = pageData.value.supplierAddressInfoList || [];
  if (!supplierAddressInfoList || !supplierAddressInfoList.length) {
    message.error("请维护地址信息");
    return false;
  }
  // 银行信息
  const supplierBankInfoList = pageData.value.supplierBankInfoList || [];
  if (!supplierBankInfoList || !supplierBankInfoList.length) {
    message.error("请维护银行信息");
    return false;
  }

  return true;
};

const handleCustomSave = () => {
  if (!customCheck()) {
    return;
  }
  stepTriggerValidate();
};
// 自定义提交审批
const handleCustomPublish = () => {
  stepTriggerValidate();
};
const handleValidateSuccess = (button: GlobalPageLayoutTypes.PageButton) => {
  if (button.key === BUTTON_SAVE.key) {
    composeSave();
  }
  if (button.key === BUTTON_CUSTOM_PRIMARY.key) {
    Modal.confirm({
      title: srmI18n(`i18n_title_release`, "发布"),
      content: srmI18n(`i18n_title_isConfirmPublishing`, "是否确认发布?"),
      onOk() {
        Request.post({
          url: apiUrls.edit,
          data: pageData.value,
        }).then((res) => {
          if (res.success) {
            const result = res.result;
            const supplierInfoChangeId = result.supplierInfoChangeId;
            Request.get({
              url: apiUrls.release,
              params: {
                id: supplierInfoChangeId,
              },
            }).then((res) => {
              if (res.success) {
                // router.push({ path: '/publicService/enterprise/list', query: { t: +new Date() } })
                if (
                  pageData.value.changeNumber &&
                  pageData.value.initiatorElsAccount
                ) {
                  message.success(
                    srmI18n(
                      `i18n_alert_tkLRAEVHAHtIHVGhx_e7a85afe`,
                      "操作成功,企业信息变更单已更新并发布"
                    )
                  );
                } else {
                  message.success(
                    srmI18n(
                      `i18n_alert_tkLRAEVHAHtIcIGhx_bed3651b`,
                      "操作成功,企业信息变更单已创建并发布"
                    )
                  );
                }
                Notification.warning({
                  message: "提示",
                  description:
                    "请等待采购方审批通过后,刷新浏览器或重新登录进入系统主页",
                  duration: null,
                });
              } else {
                message.warning(res.message);
              }
            });
          } else {
            message.warning(res.message);
          }
        });
      },
    });
  }
};
// 通用新增
const handleCustomAdd = (
  btn: GlobalPageLayoutTypes.PageButtonWithGroupCode
) => {
  const tableData = pageData.value[
    `${btn.groupCode}`
  ] as GlobalPageLayoutTypes.RecordString[];
  let others = {
    elsAccount: pageData.value.toElsAccount || "",
    toElsAccount: pageData.value.elsAccount || "",
  };
  tableData.unshift({ _row_id: uniqueId("_row_id_"), ...others });
};
// 通用删除逻辑
const handleCustomDel = (
  btn: GlobalPageLayoutTypes.PageButtonWithGroupCode
) => {
  const tableData = pageData.value[
    `${btn.groupCode}`
  ] as GlobalPageLayoutTypes.RecordString[];
  const selectedRows = tableData.filter((n) => !!n._checked);
  if (!selectedRows.length) {
    message.warn(srmI18n("i18n_title_selectDataMsg", "请选择数据"));
  }
  let orderText = "";
  for (const [idx, item] of selectedRows.entries()) {
    if (!item.toElsAccount) {
      orderText = orderText + `[${idx + 1}]`;
    }
  }
  if (orderText !== "") {
    let msg =
      srmI18n("", "已选行") +
      orderText +
      srmI18n(
        "i18n_alert_jWFKRdXLDjRRWFWxKAE_85c4c950",
        "的数据是供应商维护的公共数据,不是企业"
      ) +
      "[" +
      pageData.value.elsAccount +
      "]" +
      srmI18n(
        "i18n_alert_CjjWLxOKmQGWNTQGWVuAEtvVHntskQGWQGSPdddjnRX_9394ca1f",
        "私有的,您不能在此删除。如需删除,请到企业基本信息菜单中做删除,删除后将影响所有采购商"
      );
    message.warn(msg);
    return false;
  }
  const ids = selectedRows.map((n) => n.id || n._row_id);
  remove(tableData, function (n) {
    const id = (n.id || n._row_id) as string;
    return ids.includes(id);
  });
};
// 添加联系人
const handleAddSupplierContactsInfo = () => {
  const tableData = pageData.value[
    "supplierContactsInfoList"
  ] as GlobalPageLayoutTypes.RecordString[];
  let others = {
    elsAccount: pageData.value.toElsAccount || "",
    toElsAccount: pageData.value.elsAccount || "",
  };
  tableData.unshift({ _row_id: uniqueId("_row_id_"), ...others });
};
// 删除联系人
const handleDeleteSupplierContactsInfo = (
  btn: GlobalPageLayoutTypes.PageButtonWithGroupCode
) => {
  handleCustomDel(btn);
};
// 地址信息新增
const handleAddAddressItem = () => {
  const tableData = pageData.value[
    "supplierAddressInfoList"
  ] as GlobalPageLayoutTypes.RecordString[];
  const row = defaultValues[
    "supplierAddressInfoList"
  ] as GlobalPageLayoutTypes.RecordString;
  let others = {
    ...row,
    elsAccount: pageData.value.toElsAccount || "",
    toElsAccount: pageData.value.elsAccount || "",
  };
  tableData.unshift({ _row_id: uniqueId("_row_id_"), ...others });
};
// 地址信息删除
const handleDelAddressItem = (
  btn: GlobalPageLayoutTypes.PageButtonWithGroupCode
) => {
  handleCustomDel(btn);
};
// 银行信息新增
const handleAddBankItem = () => {
  const tableData = pageData.value[
    "supplierBankInfoList"
  ] as GlobalPageLayoutTypes.RecordString[];
  const row = defaultValues[
    "supplierBankInfoList"
  ] as GlobalPageLayoutTypes.RecordString;
  let others = {
    ...row,
    elsAccount: pageData.value.toElsAccount || "",
    toElsAccount: pageData.value.elsAccount || "",
    bankAccountName: pageData.value.name || "",
  };
  tableData.unshift({ _row_id: uniqueId("_row_id_"), ...others });
};
// 银行信息删除
const handleDelBankItem = (
  btn: GlobalPageLayoutTypes.PageButtonWithGroupCode
) => {
  handleCustomDel(btn);
};
const handlePageBack = () => {
  router.push({
    path: "/publicService/enterprise/list",
    query: isCreate.value ? { t: +new Date() } : {},
  });
};
</script>

<style scoped lang="scss">
.enterpriseEdit {
  .content-box {
    height: calc(100vh - 84px);
    background-color: var(--qTabLayoutContentBoxBackgroundColor, #eff2f5);
    overflow: auto;
  }
}
</style>

示例

enterpriseEdit.jpg