zhangwei
2025-08-19 78921416615f450f4cc29ec4f740fbf1b47d8b00
注册登录更改
16个文件已修改
1个文件已添加
926 ■■■■■ 已修改文件
src/api/register/index.ts 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system.ts 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/types.ts 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/user.ts 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/hooks/useNav.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/modules/item.ts 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.ts 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/types.ts 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/auth.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/home/index.vue 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.vue 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mine/index.vue 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/newregister/index.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/newregister/utils/hook.tsx 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/newregister/utils/types.ts 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/index.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/utils/hook.tsx 86 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/register/index.ts
@@ -8,7 +8,7 @@
import { http } from "@/utils/http";
import { baseUrlApi } from "../util";
import type { Result, CaptchaResult } from "../types";
import type { Result, CaptchaResult, RoleData } from "../types";
export const register = (data?: object) => {
  return http.request<Result>(
@@ -24,7 +24,7 @@
//获取角色
export const exRole = () => {
  return http.request<Result>("get", baseUrlApi("/api/customer/exRole"));
  return http.request<RoleData>("get", baseUrlApi("/api/customer/exRole"));
};
// 获取手机验证码
@@ -66,3 +66,10 @@
  );
};
// 申请角色
export const applyRole = params => {
  return http.request<Result>(
    "get",
    baseUrlApi(`/api/customer/createrExRolsInformation/${params.ruleCode}`)
  );
};
src/api/system.ts
New file
@@ -0,0 +1,92 @@
import { http } from "@/utils/http";
import { baseUrlApi } from "./util";
type Result = {
  success: boolean;
  data?: Array<any>;
};
type ResultTable = {
  success: boolean;
  data?: {
    /** 列表数据 */
    list: Array<any>;
    /** 总条目数 */
    total?: number;
    /** 每页显示条目个数 */
    pageSize?: number;
    /** 当前页数 */
    currentPage?: number;
  };
};
/** 获取账户列表 */
export const getUserList = () => {
  return http.request<ResultTable>(
    "get",
    baseUrlApi("/api/customer/custormerUsersList")
  );
};
/** 系统管理-用户管理-获取所有角色列表 */
export const getAllRoleList = () => {
  return http.request<Result>(
    "get",
    baseUrlApi("/api/customer/custormerUsersList")
  );
};
/** 系统管理-用户管理-根据userId,获取对应角色id列表(userId:用户id) */
export const getRoleIds = (data?: object) => {
  return http.request<Result>("post", "/list-role-ids", { data });
};
/** 获取系统管理-角色管理列表 */
export const getRoleList = (data?: object) => {
  return http.request<ResultTable>("post", "/role", { data });
};
/** 获取系统管理-菜单管理列表 */
export const getMenuList = (data?: object) => {
  return http.request<Result>("post", "/menu", { data });
};
/** 获取系统管理-部门管理列表 */
export const getDeptList = (data?: object) => {
  return http.request<Result>("post", "/dept", { data });
};
/** 获取系统监控-在线用户列表 */
export const getOnlineLogsList = (data?: object) => {
  return http.request<ResultTable>("post", "/online-logs", { data });
};
/** 获取系统监控-登录日志列表 */
export const getLoginLogsList = (data?: object) => {
  return http.request<ResultTable>("post", "/login-logs", { data });
};
/** 获取系统监控-操作日志列表 */
export const getOperationLogsList = (data?: object) => {
  return http.request<ResultTable>("post", "/operation-logs", { data });
};
/** 获取系统监控-系统日志列表 */
export const getSystemLogsList = (data?: object) => {
  return http.request<ResultTable>("post", "/system-logs", { data });
};
/** 获取系统监控-系统日志-根据 id 查日志详情 */
export const getSystemLogsDetail = (data?: object) => {
  return http.request<Result>("post", "/system-logs-detail", { data });
};
/** 获取角色管理-权限-菜单权限 */
export const getRoleMenu = (data?: object) => {
  return http.request<Result>("post", "/role-menu", { data });
};
/** 获取角色管理-权限-菜单权限-根据角色 id 查对应菜单 */
export const getRoleMenuIds = (data?: object) => {
  return http.request<Result>("post", "/role-menu-ids", { data });
};
src/api/types.ts
@@ -48,3 +48,71 @@
  result: captchaImg;
  code: string | number;
};
export type UserResult = {
  success: boolean;
  data: {
    /** 头像 */
    avatar: string;
    /** 用户名 */
    username: string;
    /** 昵称 */
    nickname: string;
    /** 当前登录用户的角色 */
    roles: Array<string>;
    /** 按钮级别权限 */
    permissions: Array<string>;
    /** `token` */
    accessToken: string;
    /** 用于调用刷新`accessToken`的接口时所需的`token` */
    refreshToken: string;
    /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
    expires: Date;
  };
};
// 企业信息项类型
interface CustomerEx {
  customerUserID: number;
  enterpriseName: string;
  isManger: boolean; // 注意:原数据中可能存在拼写错误(应为isManager),此处保持与原数据一致
  unifiedSocialCreditCode: string;
}
// 整体结果类型
export interface LoginResult {
  theLastLogo: boolean;
  accessToken: string | null;
  refreshToken: string | null;
  exRoles: any | null; // exRoles为null,具体类型可根据实际业务场景细化
  code: string;
  customerExs: CustomerEx[];
  expires: string;
  roles: [];
  username: string;
  avatar: string;
  nickname: string;
  permissions: [];
}
export type LoginData = {
  message: string;
  success: boolean;
  code: string | number;
  result: LoginResult;
};
export interface RoleItem {
  id: number;
  name: string;
  code: string;
  orderNo: number;
  dataScope: number;
  remark: string | null; // 可能为null或字符串
  status: number;
}
// 角色列表
export type RoleData = {
  message: string;
  success: boolean;
  code: string | number;
  result: RoleItem[];
};
src/api/user.ts
@@ -1,79 +1,23 @@
import { http } from "@/utils/http";
import { baseUrlApi } from "./util";
export type UserResult = {
  success: boolean;
  data: {
    /** 头像 */
    avatar: string;
    /** 用户名 */
    username: string;
    /** 昵称 */
    nickname: string;
    /** 当前登录用户的角色 */
    roles: Array<string>;
    /** 按钮级别权限 */
    permissions: Array<string>;
    /** `token` */
    accessToken: string;
    /** 用于调用刷新`accessToken`的接口时所需的`token` */
    refreshToken: string;
    /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
    expires: Date;
  };
};
export type LoginResult = {
  success: boolean;
  code: string | number;
  result: {
    /** 头像 */
    avatar: string;
    /** 用户名 */
    username: string;
    /** 昵称 */
    nickname: string;
    /** 当前登录用户的角色 */
    exRoles: Array<string>;
    /** 按钮级别权限 */
    permissions: Array<string>;
    /** `token` */
    accessToken: string;
    /** 用于调用刷新`accessToken`的接口时所需的`token` */
    refreshToken: string;
    /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
    expires: Date;
  };
};
export type RefreshTokenResult = {
  success: boolean;
  data: {
    /** `token` */
    accessToken: string;
    /** 用于调用刷新`accessToken`的接口时所需的`token` */
    refreshToken: string;
    /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
    expires: Date;
  };
};
import type { LoginData } from "./types";
/** 登录 */
export const getLogin = (data?: object) => {
  return http.request<LoginResult>("post", baseUrlApi("/api/auth/loginPhone"), {
  return http.request<LoginData>("post", baseUrlApi("/api/auth/loginPhone"), {
    data
  });
  // return http.request<UserResult>("post", "/login", { data });
};
/** 刷新`token` */
export const refreshTokenApi = (data?: object) => {
  return http.request<RefreshTokenResult>("post", "/refresh-token1", { data });
};
// /** 刷新`token` */
// export const refreshTokenApi = (data?: object) => {
//   return http.request<RefreshTokenResult>("post", "/refresh-token1", { data });
// };
// 切换角色
export const getChangeLogoInExRule = params => {
  return http.request<LoginResult>(
  return http.request<LoginData>(
    "post",
    baseUrlApi(`/api/auth/changeLogoInExRule/${params.ruleCode}`)
  );
src/layout/hooks/useNav.ts
@@ -15,6 +15,7 @@
import ExitFullscreen from "~icons/ri/fullscreen-exit-fill";
import Fullscreen from "~icons/ri/fullscreen-fill";
import { unref } from "vue";
import { message } from "@/utils/message";
const errorInfo =
  "The current routing configuration is incorrect, please check the configuration";
@@ -109,6 +110,8 @@
          // 获取后端路由
          initRouter();
          onFresh();
        } else {
          message(res?.message, { type: "warning" });
        }
      });
  };
src/router/modules/item.ts
@@ -21,6 +21,26 @@
    ]
  },
  {
    path: "/user",
    meta: {
      title: "用户管理",
      icon: "mdi:chart-timeline"
    },
    children: [
      {
        // path随便写,但前面必须有个 `/`
        path: "/user",
        // component对应的值前不需要加 / 值对应的是实际业务 `.vue` 或 `.tsx` 代码路径
        component: () => import("@/views/system/user/index.vue"),
        name: "user",
        meta: {
          title: "用户管理"
          // showLink:false
        }
      }
    ]
  },
  {
    path: "/aboutItem",
    meta: {
      title: "关注项目",
src/store/modules/user.ts
@@ -8,12 +8,11 @@
  storageLocal
} from "../utils";
import {
  type LoginResult,
  type RefreshTokenResult,
  getLogin,
  refreshTokenApi,
  // refreshTokenApi,
  getChangeLogoInExRule
} from "@/api/user";
import type { LoginData, RoleData, RoleItem } from "@/api/types";
import { useMultiTagsStoreHook } from "./multiTags";
import {
  type DataInfo,
@@ -29,6 +28,8 @@
import { exRole } from "@/api/register/index";
import { cusExtendInfo } from "@/api/mine";
import type { nowRoleType } from "@/store/types";
import { cloneDeep } from "@pureadmin/utils";
import { message } from "@/utils/message";
export const useUserStore = defineStore("pure-user", {
  state: (): userType => ({
@@ -51,7 +52,7 @@
    enterpriseInfo:
      storageLocal().getItem<CusExtendDto>("enterpriseInfo") ?? {},
    nowRole: storageLocal().getItem<nowRoleType>("nowRole") ?? {},
    rolesList: storageLocal().getItem<DataInfo<number>>("rolesList") ?? [],
    rolesList: storageLocal().getItem<RoleItem[]>("rolesList") ?? [],
    // 页面级别权限
    roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? []
  }),
@@ -81,7 +82,7 @@
      this.nowRole = nowRole;
    },
    /** 存储角色列表 */
    SET_EXROLES_LIST(rolesList: Array<string>) {
    SET_EXROLES_LIST(rolesList: RoleItem[]) {
      this.rolesList = rolesList;
    },
    /** 存储按钮级别权限 */
@@ -102,13 +103,16 @@
    },
    /** 登入 */
    async loginByUsername(obj) {
      return new Promise<LoginResult>((resolve, reject) => {
      return new Promise<LoginData>((resolve, reject) => {
        getLogin(obj)
          .then(data => {
            if (data?.code == 200) {
              data.result.roles = [obj.exRuleCode];
              setToken(data.result);
              if (data.result.theLastLogo) {
                const resObj = cloneDeep(data.result);
                resObj.roles = [obj.exRuleCode];
                setToken(resObj);
              this.getNowRole(obj.exRuleCode);
              }
            }
            resolve(data);
          })
@@ -119,7 +123,7 @@
    },
    /** 获取角色列表 */
    async getRoleList() {
      return new Promise<LoginResult>((resolve, reject) => {
      return new Promise<RoleData>((resolve, reject) => {
        exRole()
          .then(data => {
            if (data?.code == 200) {
@@ -137,7 +141,7 @@
    },
    /** 获取当前角色 */
    async getNowRole(code) {
      return new Promise<LoginResult>((resolve, reject) => {
      return new Promise(resolve => {
        const data = this.rolesList.find(item => {
          return item.code == code;
        });
@@ -147,15 +151,18 @@
    },
    /** 切换角色 */
    async changeLogoInExRule(obj) {
      return new Promise<LoginResult>((resolve, reject) => {
      return new Promise<LoginData>((resolve, reject) => {
        getChangeLogoInExRule(obj)
          .then(async data => {
            if (data?.code == 200) {
              data.result.roles = [obj.ruleCode];
              setToken(data.result);
              const resObj = cloneDeep(data.result);
              resObj.roles = [obj.ruleCode];
              setToken(resObj);
              this.getNowRole(obj.ruleCode);
              await this.getCusExtendInfo();
              resolve(data);
            } else {
              message(data?.message, { type: "warning" });
            }
          })
          .catch(error => {
@@ -169,8 +176,9 @@
          .then(data => {
            setEnterpriseInfo(data.result);
            if (data?.code == 200) {
              data.result.username = data.result?.enterpriseName;
              resolve(data);
              const resData = cloneDeep(data);
              resData.result.username = data.result?.enterpriseName;
              resolve(resData);
            }
          })
          .catch(error => {
@@ -190,19 +198,19 @@
      router.push("/index");
    },
    /** 刷新`token` */
    async handRefreshToken(data) {
      return new Promise<RefreshTokenResult>((resolve, reject) => {
        refreshTokenApi(data)
          .then(data => {
            if (data) {
              setToken(data.data);
              resolve(data);
            }
          })
          .catch(error => {
            reject(error);
          });
      });
    async handRefreshToken() {
      // return new Promise<RefreshTokenResult>((resolve, reject) => {
      //   refreshTokenApi(data)
      //     .then(data => {
      //       if (data) {
      //         setToken(data.data);
      //         resolve(data);
      //       }
      //     })
      //     .catch(error => {
      //       reject(error);
      //     });
      // });
    }
  }
});
src/store/types.ts
@@ -1,5 +1,5 @@
import type { RouteRecordName } from "vue-router";
import type { RoleItem } from "@/api/types";
export type cacheType = {
  mode: string;
  name?: RouteRecordName;
@@ -37,21 +37,21 @@
};
export type nowRoleType = {
  code: string;
  name: string;
  hasFlsh: boolean;
  code?: string;
  name?: string;
  hasFlsh?: boolean;
};
export type userType = {
  avatar?: string;
  username?: string;
  nickname?: string;
  exRoles?: Array<string>;
  exRoles?: RoleItem[];
  roles?: Array<string>;
  permissions?: Array<string>;
  isRemembered?: boolean;
  loginDay?: number;
  enterpriseInfo: object;
  nowRole: nowRoleType;
  rolesList: object;
  rolesList: RoleItem[];
};
src/utils/auth.ts
@@ -2,6 +2,7 @@
import { useUserStoreHook } from "@/store/modules/user";
import { storageLocal, isString, isIncludeAllChildren } from "@pureadmin/utils";
import type { nowRoleType } from "@/store/types";
import type { LoginResult, RoleItem } from "@/api/types";
export interface DataInfo<T> {
  /** token */
@@ -172,7 +173,7 @@
 * 将`accessToken`、`expires`、`refreshToken`这三条信息放在key值为authorized-token的cookie里(过期自动销毁)
 * 将`avatar`、`username`、`nickname`、`exRoles`、`permissions`、`refreshToken`、`expires`这七条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
 */
export function setToken(data: DataInfo<Date>) {
export function setToken(data: LoginResult) {
  let expires = 0;
  const { accessToken, refreshToken } = data;
  const { isRemembered, loginDay } = useUserStoreHook();
@@ -264,7 +265,7 @@
  storageLocal().setItem(userKey, obj);
}
export function setRoleListInfo(data: DataInfo<string>) {
export function setRoleListInfo(data: RoleItem[]) {
  useUserStoreHook().SET_EXROLES_LIST(data);
  storageLocal().setItem("rolesList", data);
}
@@ -275,7 +276,7 @@
    const obj = list.find(item => {
      return item.code == data.code;
    });
    data = { ...obj, ...data };
    data = Object.assign(obj, data);
  }
  useUserStoreHook().SET_ROLES([data.name]);
  useUserStoreHook().SET_NOW_ROLE(data);
src/views/home/index.vue
@@ -378,18 +378,24 @@
  <my-footer />
</template>
<script lang="ts" setup>
<script lang="tsx" setup>
import { onMounted, ref, computed, reactive } from "vue";
import MyFooter from "./component/myFooter.vue";
import MyHeader from "./component/myHeader.vue";
import { useUserStoreHook } from "@/store/modules/user";
import { exRole } from "@/api/register/index";
import { storageLocal, isString, isIncludeAllChildren } from "@pureadmin/utils";
import { initRouter, getTopMenu } from "@/router/utils";
import { getToken } from "@/utils/auth";
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
import { useUserStore } from "@/store/modules/user";
import { addDialog } from "@/components/ReDialog";
import { applyRole } from "@/api/register/index";
import { message } from "@/utils/message";
import type { userType } from "@/store/types";
import type { RoleItem } from "@/api/types";
const userStore = useUserStore();
@@ -402,14 +408,14 @@
/** 角色(如果昵称为空则显示用户名) */
const getUseRoles = () => {
  state.userInfo = storageLocal().getItem("user-info");
  state.userInfo?.exRoles.forEach(element => {
  state.userInfo?.exRoles.forEach((element: RoleItem) => {
    state.rolesCode.push(element.code);
  });
};
const state = reactive({
  roleList: [],
  rolesCode: [],
  userInfo: {},
  userInfo: {} as userType,
  accessToken: ""
});
onMounted(() => {
@@ -432,20 +438,42 @@
};
// 申请
const toApply = item => {
  router.push({ name: "RegisterNav", query: { code: item.code } });
  addDialog({
    width: "20%",
    title: "确认信息",
    contentRenderer: () => <p>是否申请为{item.name}!</p>, // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx")
    closeCallBack: ({ options, args }) => {
      if (args?.command === "cancel") {
        // 您点击了取消按钮
      } else if (args?.command === "sure") {
        applyRole({ ruleCode: item.code }).then(res => {
          if (res.code == 200) {
            message("申请成功!", { type: "success" });
          } else {
            message(res?.message || "申请失败!", { type: "error" });
          }
        });
      } else {
      }
    }
  });
  // router.push({ name: "RegisterNav", query: { code: item.code } });
};
// 去首页
const toWelcome = async item => {
  if (useUserStoreHook().nowRole.code !== item.code) {
    await useUserStoreHook().changeLogoInExRule({
    // 获取后端路由
    initRouter().then(() => {
      useUserStoreHook().changeLogoInExRule({
      ruleCode: item.code
    });
    });
  }
  router.push({ name: "Mine" });
  router.push({ name: "Welcome" });
};
// 去登录
const toLogin = item => {
  router.push({ name: "Login", query: item });
  router.push({ name: "Login" });
};
</script>
src/views/login/index.vue
@@ -7,13 +7,14 @@
  reactive,
  computed,
  ref,
  Ref,
  h,
  onMounted,
  defineAsyncComponent,
  onUnmounted,
  watch
} from "vue";
import { debounce } from "@pureadmin/utils";
import { debounce, storageLocal } from "@pureadmin/utils";
import { useNav } from "@/layout/hooks/useNav";
import { useEventListener } from "@vueuse/core";
import type { FormInstance } from "element-plus";
@@ -120,6 +121,8 @@
  myEnterpriseList: [],
  nowRole: {}
});
let secondCode = "";
let secondId: Ref<string | number | boolean> = ref("");
// 验证码过期计时器
let timer: any = null;
let phonetimer: any = null;
@@ -127,18 +130,6 @@
// 页面初始化
onMounted(async () => {
  getCaptcha();
  exRole().then(res => {
    state.roleList = res.result;
    const role = route.query;
    if (role.code) {
      state.nowRole = state.roleList.find(item => {
        return item.code == role.code;
      });
    } else {
      state.nowRole = state.roleList[0];
    }
    state.ruleForm.exRoleCode = state.nowRole.code;
  });
  // 注册验证码过期计时器
  timer = setInterval(() => {
    if (state.expirySeconds > 0) state.expirySeconds -= 1;
@@ -157,131 +148,104 @@
    width: "30%",
    title: "选择登录公司",
    contentRenderer: () =>
    h(ElForm, {
      h(
        ElForm,
        {
      ref: ruleFormRef,
      model: state.ruleForm,
      rules: loginRules,
      size: 'large'
    }, [
      h(Motion, { delay: 150 }, [
        h(ElFormItem, {
          prop: 'exRoleCode',
          label: '主体角色' // 可添加表单项标签
        }, [
          // 单选框组 - 父容器添加样式控制
          h(ElRadioGroup, {
            modelValue: state.ruleForm.exRoleCode,
            'onUpdate:modelValue': (val) => {
              state.ruleForm.exRoleCode = val
          size: "large"
            },
            style: {
              display: 'flex',
              flexDirection: 'column',
              gap: '8px' // 单选框之间的间距
        [
          h(Motion, { delay: 150 }, [
            h(
              ElFormItem,
              {
                prop: "exRoleCode",
                label: ""
              },
              [
                // 单选框组 - 纵向排列
                h(
                  ElRadioGroup,
                  {
                    modelValue: secondId.value,
                    "onUpdate:modelValue": val => {
                      secondId.value = val;
            }
          }, [
            // 循环渲染单选框 - 每个单选框单独占一行
            state.myEnterpriseList.map(item => h(ElRadio, {
              key: item.id,
              value: item.code,
                  },
                  [
                    // 循环渲染单选框 - 根据每项的isManager显示标签
                    state.myEnterpriseList.map(item =>
                      h(
                        "el-row",
                        {
              style: {
                display: 'block', // 让每个单选框分行显示
                padding: '4px 0'
                            width: "100%"
              }
            }, item.name),)
          ]),
          // 管理员标签 - 显示在单选框后面
                        },
                        [
                          h(
                            "el-col",
                            {
                              span: 24
                            },
                            [
                              h(
                                ElRadio,
                                {
                                  key: item.customerUserID,
                                  value: item.customerUserID,
                                  label: item.enterpriseName
                                },
                                [
                                  // 单选框文本
                                  // 根据当前项的isManager显示标签(放在文本后面)
                                  item.isManger
                                    ? h(
                                        ElTag,
                                        {
                                          type: "primary",
                                          size: "small",
                                          style: {
                                            marginLeft: "8px",
                                            alignSelf: "center"
                                          }
                                        },
                                        "管理员"
                                      )
                                    : null
                                ]
                              )
                            ]
                          )
                        ]
                      )
                    )
                  ]
                )
              ]
            )
        ])
      ])
    ])
      // <>
      //   <el-form
      //     ref="ruleFormRef"
      //     model={state.ruleForm}
      //     rules={loginRules}
      //     size="large"
      //   >
      //     <Motion delay={150}>
      //       <el-form-item prop="exRoleCode">
      //         <el-radio-group v-model={state.ruleForm.exRoleCode}>
      //           <el-radio
      //             v-for={item in state.myEnterpriseList}
      //             key={item.id}
      //             value={item.code}
      //           >
      //             {item.name}
      //           </el-radio>
      //         </el-radio-group>
      //       </el-form-item>
      //     </Motion>
      //   </el-form>
      // </>
      // h(
      //   ElForm,
      //   {
      //     ref: ruleFormRef,
      //     model: state.ruleForm,
      //     rules: loginRules,
      //     size: "large"
      //   },
      //   [
      //     h(Motion, { delay: 150 }, [
      //       h(ElFormItem, { prop: "exRoleCode" }, [
      //         h(
      //           ElRadioGroup,
      //           {
      //             modelValue: state.ruleForm.exRoleCode,
      //             "onUpdate:modelValue": val => {
      //               state.ruleForm.exRoleCode = val;
      //             }
      //           },
      //           [
      //             // 用map实现v-for循环
      //             state.myEnterpriseList.map(item =>
      //               h(ElRow, {}, [
      //                 h(
      //                   ElRadio,
      //                   {
      //                     key: item.customerUserID,
      //                     value: item.customerUserID
      //                   },
      //                   item.enterpriseName
      //                 ),
      //                 item.isManager ? 444 : "" // 标签内容
      //               ])
      //             )
      //           ]
      //         )
      //       ])
      //     ])
      //   ]
      // ),
        ]
      ),
      // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx")
    closeCallBack: ({ options, args }) => {
      // options.props 是响应式的
      // const { formInline } = options.props as FormProps;
      // const text = `姓名:${formInline.user} 城市:${formInline.region}`;
      if (args?.command === "cancel") {
        // 您点击了取消按钮
        // active.value -= 1;
      } else if (args?.command === "sure") {
        let obj = {
          phone: state.ruleForm.phone,
          code: state.ruleForm.phoneVCode,
          exRuleCode: state.ruleForm.exRoleCode
          code: secondCode,
          id: secondId.value
        };
        useUserStoreHook()
          .loginByUsername(obj)
          .then(res => {
            if (res?.code == 200) {
              message("注册成功!", { type: "success" });
              message("登录成功!", { type: "success" });
              router.replace({
                path: "/RegisterSucess",
                query: {
                  code: obj.exRoleCode
                }
                path: "/Index"
              });
            } else {
              message(res?.message, { type: "warning" });
@@ -292,6 +256,8 @@
    }
  });
};
// 点击登录
const onLogin = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate(valid => {
@@ -320,45 +286,23 @@
                  .finally(() => (disabled.value = false));
              } else {
                state.myEnterpriseList = obj.customerExs;
                secondCode = obj.code;
                openDialog();
              }
              if (res.result.exRoles.length == 0) {
                disabled.value = true;
                router
                  .replace({
                    name: "RegisterNav",
                    query: { code: state.ruleForm.exRoleCode }
                  })
                  .then(() => {
                    message("登录成功", { type: "success" });
                  })
                  .finally(() => (disabled.value = false));
              } else if (res.result.exRoles.length > 0) {
                let data = res.result.exRoles.find(item => {
                  return item.code == state.ruleForm.exRoleCode;
                });
                if (!data) {
                  router.replace({
                    name: "RegisterNav",
                    query: { code: state.ruleForm.exRoleCode }
                  });
                } else if (data?.hasFlsh) {
                  router.replace("index");
                } else {
                  router.replace("mine");
                }
              }
              useUserStoreHook().getCusExtendInfo();
            });
          } else {
            message(res?.message || "登录失败", { type: "error" });
          }
        })
        .finally(() => (loading.value = false));
        .finally(() => {
          loading.value = false;
          disabled.value = false;
        });
    }
  });
};
// 发送手机验证码
const sendValidationCode = async () => {
  if (!state.ruleForm.phone) {
    return message("请先输入手机号", { type: "warning" });
@@ -396,26 +340,12 @@
    <div class="wave">
      <img width="400px" :src="logo1" class="logo1" />
    </div>
    <!-- <img :src="bg" class="wave" /> -->
    <!-- <div class="flex-c absolute right-5 top-3"> -->
    <!-- 主题 -->
    <!-- <el-switch
        v-model="dataTheme"
        inline-prompt
        :active-icon="dayIcon"
        :inactive-icon="darkIcon"
        @change="dataThemeChange"
      />
    </div> -->
    <div class="login-container">
      <div class="img">
        <!-- <component :is="toRaw(illustration)" /> -->
      </div>
      <div class="img" />
      <div class="login-box">
        <div class="login-form">
          <!-- <avatar class="avatar" /> -->
          <Motion>
            <h2 class="logintitle">{{ state.nowRole.name }}登录</h2>
            <h2 class="logintitle">登录</h2>
          </Motion>
          <el-form
@@ -424,18 +354,6 @@
            :rules="loginRules"
            size="large"
          >
            <!-- <Motion :delay="150">
              <el-form-item prop="exRoleCode">
                <el-radio-group v-model="state.ruleForm.exRoleCode">
                  <el-radio
                    v-for="item in state.roleList"
                    :key="item.id"
                    :value="item.code"
                    >{{ item.name }}</el-radio
                  >
                </el-radio-group>
              </el-form-item>
            </Motion> -->
            <Motion :delay="100">
              <el-form-item
                :rules="[
@@ -488,16 +406,6 @@
                  </div>
                </el-col>
              </el-form-item>
              <!-- <el-form-item prop="password">
                <el-input
                  v-model="ruleForm.password"
                  clearable
                  show-password
                  placeholder="密码"
                  :prefix-icon="useRenderIcon(Lock)"
                />
              </el-form-item> -->
            </Motion>
            <Motion :delay="150">
              <el-form-item prop="phoneVCode">
@@ -511,7 +419,7 @@
                      <span
                        id="suffix-span-2"
                        ref="spanRef"
                        @click="sendValidationCode(state.ruleForm.phone)"
                        @click="sendValidationCode"
                      >
                        获取验证码
                      </span>
src/views/mine/index.vue
@@ -78,7 +78,8 @@
    // 企业开户行
    bankName: null, // string,可空
    // 企业银行账号
    bankAccount: null // string,可空
    bankAccount: null, // string,可空
    bankAccountIMG: null
  },
  enterpriseList: [],
  type: "",
@@ -338,6 +339,22 @@
    });
  }
};
const handlebankAccountIMG: UploadProps["onSuccess"] = (
  response,
  uploadFile
) => {
  if (response.code == "200") {
    // state.ruleForm.businessLicense = URL.createObjectURL(uploadFile.raw!);
    state.ruleForm.bankAccountIMG = response.result;
  } else {
    message(response.message, {
      type: "error"
    });
  }
  isLoading.value = false;
};
defineOptions({
  name: "mine"
});
@@ -348,7 +365,7 @@
    <el-descriptions
      v-if="state.userInfo.enterpriseName"
      class="margin-top"
      title=""
      title="企业资料"
      :column="3"
      border
    >
@@ -404,7 +421,7 @@
        <template #label>
          <div class="cell-item">联系电话</div>
        </template>
        {{ userInfo.legalRepresentativePhone }}
        {{ userInfo.enterprisePhone }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
@@ -478,6 +495,14 @@
          <div class="cell-item">银行账号</div>
        </template>
        {{ userInfo.bankAccount }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">银行收款二维码</div>
        </template>
        <span style="margin-right: auto" @click="showImg('bankAccountIMG')">
          <el-link type="primary" underline>查看二维码</el-link>
        </span>
      </el-descriptions-item>
    </el-descriptions>
    <div class="m-5">
@@ -556,8 +581,8 @@
                  <img
                    v-if="state.ruleForm.businessLicense"
                    :src="state.ruleForm.businessLicense"
                    width="200px"
                    height="150px"
                    width="80px"
                    height="50px"
                  />
                  <el-button v-else type="primary">上传</el-button>
                </el-upload>
@@ -652,7 +677,43 @@
                />
              </el-form-item>
            </el-col>
            <el-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
              <el-form-item label="开户行" prop="bankName">
                <el-input
                  v-model="state.ruleForm.bankName"
                  placeholder="请输入"
                />
              </el-form-item>
            </el-col>
            <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
              <el-form-item label="银行账号" prop="bankAccount">
                <el-input
                  v-model="state.ruleForm.bankAccount"
                  placeholder="请输入"
                />
              </el-form-item>
            </el-col>
            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
              <el-form-item label="开户行收款二维码" prop="bankAccountIMG">
                <el-upload
                  :action="`${baseUrlApi('/api/upFile/file')}`"
                  :show-file-list="false"
                  :on-success="handlebankAccountIMG"
                  :before-upload="beforeAvatarUpload"
                  :headers="state.headers"
                >
                  <img
                    v-if="state.ruleForm.bankAccountIMG"
                    :src="state.ruleForm.bankAccountIMG"
                    width="85.6px"
                    height="5.4px"
                  />
                  <el-button v-else type="primary">上传</el-button>
                </el-upload>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
              <el-form-item label="法定代表人" prop="legalRepresentativeIdCard">
@@ -746,22 +807,6 @@
              <el-form-item label="联系电话" prop="operatorPhone">
                <el-input
                  v-model="state.ruleForm.operatorPhone"
                  placeholder="请输入"
                />
              </el-form-item>
            </el-col>
            <el-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
              <el-form-item label="开户行" prop="bankName">
                <el-input
                  v-model="state.ruleForm.bankName"
                  placeholder="请输入"
                />
              </el-form-item>
            </el-col>
            <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
              <el-form-item label="银行账号" prop="bankAccount">
                <el-input
                  v-model="state.ruleForm.bankAccount"
                  placeholder="请输入"
                />
              </el-form-item>
src/views/newregister/index.vue
@@ -14,7 +14,7 @@
          >
        </div>
        <el-divider />
        <div class="formContent">
        <div v-loading="isLoading" class="formContent">
          <el-form
            ref="ruleFormRef"
            style="width: 95%"
@@ -234,6 +234,7 @@
              <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
                <el-form-item label="身份证" prop="legalRepresentativeIdCard">
                  <el-upload
                    :ref="uploadSFZ"
                    :action="`${baseUrlApi('/api/upFile/uploadIdCord?PageName=FRONT')}`"
                    :show-file-list="false"
                    :on-success="handleAvatarSuccessLegalRepresentative"
@@ -400,7 +401,7 @@
                v-model="state.checkedAgree"
                name="type"
              />我已阅读并同意
              <el-link type="primary" :underline="false"
              <el-link type="primary" :underline="false" @click="openAgreement"
                >《非政采招标采购交易平台用户协议》</el-link
              >
            </el-form-item>
@@ -437,7 +438,10 @@
  sumbitData,
  handleAvatarSuccess,
  loadNode,
  handlebankAccountIMG
  handlebankAccountIMG,
  isLoading,
  uploadSFZ,
  openAgreement
} = useRegister();
defineOptions({
src/views/newregister/utils/hook.tsx
@@ -2,6 +2,7 @@
  reactive,
  computed,
  ref,
  h,
  onMounted,
  defineAsyncComponent,
  onUnmounted,
@@ -33,7 +34,7 @@
} from "@/api/register/index";
import { cloneDeep } from "@pureadmin/utils";
import { changeCusExtend } from "@/api/mine";
import agreement from "../component/agreement.vue";
const route = useRoute();
export function useRegister() {
  const isLoading = ref(false);
@@ -45,7 +46,7 @@
    isShowPassword: false,
    ruleForm: {
      id: null, // 主键Id,可为空
      enterpriseType: "", // 企业类型,不可空,最小长度1
      enterpriseType: [], // 企业类型,不可空,最小长度1
      exRoleCode: "", // 主体角色代码,不可空,最小长度1
      transactionCode: "", // 交易主体代码(同角色代码exRoleCode,不可空,最小长度1)
      businessLicense: "", // 营业执照文件路径,不可空,最小长度1
@@ -327,7 +328,7 @@
  // 验证码区域文字说明
  const spanRef = ref();
  const uploadSFZ = ref();
  async function sendValidationCode() {
    if (!state.ruleForm.operatorPhone) {
      return message("请先输入业务经办人联系电话", { type: "warning" });
@@ -359,13 +360,8 @@
  async function sumbitData(formEl: FormInstance | undefined) {
    if (!formEl) return;
    await formEl.validate((valid, fields) => {
      router.replace({
        path: "/RegisterSucess",
        query: {
          code: state.ruleForm.exRoleCode
        }
      });
      if (valid && state.checkedAgree) {
      if (valid) {
        if (state.checkedAgree) {
        addDialog({
          width: "20%",
          title: "确认信息",
@@ -375,12 +371,8 @@
            </p>
          ), // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx")
          closeCallBack: ({ options, args }) => {
            // options.props 是响应式的
            // const { formInline } = options.props as FormProps;
            // const text = `姓名:${formInline.user} 城市:${formInline.region}`;
            if (args?.command === "cancel") {
              // 您点击了取消按钮
              // active.value -= 1;
            } else if (args?.command === "sure") {
              state.ruleForm.account = state.ruleForm.operatorPhone;
              const obj = cloneDeep(state.ruleForm);
@@ -402,8 +394,18 @@
            }
          }
        });
        return;
      } else message("请勾选用户协议", { type: "warning" });
        } else {
          message("请勾选用户协议", { type: "warning" });
        }
      } else {
        const fail = [];
        for (const key in fields) {
          fail.push(fields[key][0].message);
        }
        message(fail[0], {
          type: "warning"
        });
      }
    });
  }
  function handleAvatarSuccess(
@@ -437,8 +439,12 @@
    if (response.code == "200") {
      // state.ruleForm.businessLicense = URL.createObjectURL(uploadFile.raw!);
      const res = response.result;
      // if (res.info.Name !== state.ruleForm.enterpriseName) {
      //   message("请上传法定代表人身份证!", { type: "error" });
      // } else {
      state.ruleForm.legalRepresentativeIdCard = res.url; // 法定代表人身份证文件路径
      state.ruleForm.legalRepresentativeIdNumber = res.info.IdNum; // 法定代表人身份证号码
      // }
    } else {
      message(response.message, {
        type: "error"
@@ -513,6 +519,20 @@
      return resolve([]);
    }
  }
  function openAgreement() {
    addDialog({
      width: "40%",
      title: "确认信息",
      contentRenderer: () => h(agreement), // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx")
      closeCallBack: ({ options, args }) => {
        if (args?.command === "cancel") {
          // 您点击了取消按钮
        } else if (args?.command === "sure") {
        } else {
        }
      }
    });
  }
  return {
    state,
    resetForm,
@@ -520,12 +540,15 @@
    getCaptcha,
    ruleFormRef,
    spanRef,
    uploadSFZ,
    isLoading,
    beforeAvatarUpload,
    handleAvatarSuccessOperator,
    handleAvatarSuccessLegalRepresentative,
    sumbitData,
    handleAvatarSuccess,
    loadNode,
    handlebankAccountIMG
    handlebankAccountIMG,
    openAgreement
  };
}
src/views/newregister/utils/types.ts
@@ -4,7 +4,7 @@
  /** 主键Id */
  id?: number | null;
  /** 企业类型(不可空) */
  enterpriseType: string;
  enterpriseType: [];
  /** 主体角色代码(不可空,原字段TransactionCode) */
  exRoleCode: string;
  /** 交易主体代码(同角色代码,不可空) */
@@ -50,6 +50,7 @@
  /** 电话号码校验码(不可空) */
  phoneVCode: string;
  bankAccountIMG: string;
  account?: string;
}
interface RoleInfo {
  /** 角色编码 */
src/views/system/user/index.vue
@@ -40,7 +40,6 @@
  onTreeSelect,
  handleUpdate,
  handleDelete,
  handleUpload,
  handleReset,
  handleRole,
  handleSizeChange,
@@ -52,16 +51,14 @@
<template>
  <div :class="['flex', 'justify-between', deviceDetection() && 'flex-wrap']">
    <tree
    <!-- <tree
      ref="treeRef"
      :class="['mr-2', deviceDetection() ? 'w-full' : 'min-w-[200px]']"
      :treeData="treeData"
      :treeLoading="treeLoading"
      @tree-select="onTreeSelect"
    />
    <div
      :class="[deviceDetection() ? ['w-full', 'mt-2'] : 'w-[calc(100%-200px)]']"
    >
    /> -->
    <div class="w-full mt-2">
      <el-form
        ref="formRef"
        :inline="true"
@@ -110,11 +107,7 @@
        </el-form-item>
      </el-form>
      <PureTableBar
        title="用户管理(仅演示,操作后不生效)"
        :columns="columns"
        @refresh="onSearch"
      >
      <PureTableBar title="" :columns="columns" @refresh="onSearch">
        <template #buttons>
          <el-button
            type="primary"
@@ -160,7 +153,6 @@
            :size="size"
            :data="dataList"
            :columns="dynamicColumns"
            :pagination="{ ...pagination, size }"
            :header-cell-style="{
              background: 'var(--el-fill-color-light)',
              color: 'var(--el-text-color-primary)'
src/views/system/user/utils/hook.tsx
@@ -2,14 +2,14 @@
import dayjs from "dayjs";
import roleForm from "../form/role.vue";
import editForm from "../form/index.vue";
import { zxcvbn } from "@zxcvbn-ts/core";
// import { zxcvbn } from "@zxcvbn-ts/core";
import { handleTree } from "@/utils/tree";
import { message } from "@/utils/message";
import userAvatar from "@/assets/user.jpg";
import { usePublicHooks } from "../../hooks";
import { addDialog } from "@/components/ReDialog";
import type { PaginationProps } from "@pureadmin/table";
import ReCropperPreview from "@/components/ReCropperPreview";
// import ReCropperPreview from "@/components/ReCropperPreview";
import type { FormItemProps, RoleFormItemProps } from "../utils/types";
import {
  getKeyList,
@@ -95,7 +95,7 @@
    },
    {
      label: "用户名称",
      prop: "username",
      prop: "name",
      minWidth: 130
    },
    {
@@ -104,16 +104,16 @@
      minWidth: 130
    },
    {
      label: "性别",
      prop: "sex",
      label: "角色",
      prop: "isManager",
      minWidth: 90,
      cellRenderer: ({ row, props }) => (
        <el-tag
          size={props.size}
          type={row.sex === 1 ? "danger" : null}
          type={row.isManager ? "danger" : null}
          effect="plain"
        >
          {row.sex === 1 ? "女" : "男"}
          {row.isManager ? "管理员" : "员工"}
        </el-tag>
      )
    },
@@ -124,9 +124,10 @@
    },
    {
      label: "手机号码",
      prop: "phone",
      prop: "phoneNumber",
      minWidth: 90,
      formatter: ({ phone }) => hideTextAtIndex(phone, { start: 3, end: 6 })
      formatter: ({ phoneNumber }) =>
        hideTextAtIndex(phoneNumber, { start: 3, end: 6 })
    },
    {
      label: "状态",
@@ -272,15 +273,15 @@
  async function onSearch() {
    loading.value = true;
    const { data } = await getUserList(toRaw(form));
    dataList.value = data.list;
    pagination.total = data.total;
    pagination.pageSize = data.pageSize;
    pagination.currentPage = data.currentPage;
    const { result } = await getUserList(toRaw(form));
    dataList.value = result;
    // pagination.total = data.total;
    // pagination.pageSize = data.pageSize;
    // pagination.currentPage = data.currentPage;
    setTimeout(() => {
    // setTimeout(() => {
      loading.value = false;
    }, 500);
    // }, 500);
  }
  const resetForm = formEl => {
@@ -361,33 +362,32 @@
  const cropRef = ref();
  /** 上传头像 */
  function handleUpload(row) {
    addDialog({
      title: "裁剪、上传头像",
      width: "40%",
      closeOnClickModal: false,
      fullscreen: deviceDetection(),
      contentRenderer: () =>
        h(ReCropperPreview, {
          ref: cropRef,
          imgSrc: row.avatar || userAvatar,
          onCropper: info => (avatarInfo.value = info)
        }),
      beforeSure: done => {
        console.log("裁剪后的图片信息:", avatarInfo.value);
        // 根据实际业务使用avatarInfo.value和row里的某些字段去调用上传头像接口即可
        done(); // 关闭弹框
        onSearch(); // 刷新表格数据
      },
      closeCallBack: () => cropRef.value.hidePopover()
    });
  }
  // function handleUpload(row) {
  //   addDialog({
  //     title: "裁剪、上传头像",
  //     width: "40%",
  //     closeOnClickModal: false,
  //     fullscreen: deviceDetection(),
  //     contentRenderer: () =>
  //       h(ReCropperPreview, {
  //         ref: cropRef,
  //         imgSrc: row.avatar || userAvatar,
  //         onCropper: info => (avatarInfo.value = info)
  //       }),
  //     beforeSure: done => {
  //       console.log("裁剪后的图片信息:", avatarInfo.value);
  //       // 根据实际业务使用avatarInfo.value和row里的某些字段去调用上传头像接口即可
  //       done(); // 关闭弹框
  //       onSearch(); // 刷新表格数据
  //     },
  //     closeCallBack: () => cropRef.value.hidePopover()
  //   });
  // }
  watch(
    pwdForm,
    ({ newPwd }) =>
      (curScore.value = isAllEmpty(newPwd) ? -1 : zxcvbn(newPwd).score)
  );
  watch();
  // pwdForm
  // ({ newPwd }) =>
  //   (curScore.value = isAllEmpty(newPwd) ? -1 : zxcvbn(newPwd).score)
  /** 重置密码 */
  function handleReset(row) {
@@ -524,7 +524,7 @@
    onTreeSelect,
    handleUpdate,
    handleDelete,
    handleUpload,
    // handleUpload,
    handleReset,
    handleRole,
    handleSizeChange,