shuishen
2025-09-29 1681cdaa1074f57d49579a6ae2adb0140a166851
feat:移动端基础配置调整、登录页基础配置调整
9 files modified
1 files added
386 ■■■■■ changed files
env/.env 2 ●●● patch | view | raw | blame | history
env/.env.development 2 ●●● patch | view | raw | blame | history
env/.env.production 2 ●●● patch | view | raw | blame | history
env/.env.test 2 ●●● patch | view | raw | blame | history
package.json 4 ●●● patch | view | raw | blame | history
pnpm-lock.yaml 14 ●●●●● patch | view | raw | blame | history
src/api/user/index.js 45 ●●●●● patch | view | raw | blame | history
src/config/website.js 83 ●●●●● patch | view | raw | blame | history
src/pages/login/index.vue 49 ●●●● patch | view | raw | blame | history
src/utils/request/interceptors.js 183 ●●●● patch | view | raw | blame | history
env/.env
@@ -5,7 +5,7 @@
VITE_APP_ENV=development
# 接口地址
VITE_API_BASE_URL=http://localhost:8080
VITE_API_BASE_URL=https://wrj.shuixiongit.com/api
# 端口号
VITE_APP_PORT=9527
env/.env.development
@@ -2,7 +2,7 @@
VITE_APP_ENV=development
# 接口地址
VITE_API_BASE_URL=http://localhost:8080
VITE_API_BASE_URL=https://wrj.shuixiongit.com/api
# 删除console
VITE_DROP_CONSOLE=false
env/.env.production
@@ -2,7 +2,7 @@
VITE_APP_ENV=production
# 接口地址
VITE_API_BASE_URL=http://localhost:8080/prod
VITE_API_BASE_URL=https://wrj.shuixiongit.com/api
# 删除console
VITE_DROP_CONSOLE=true
env/.env.test
@@ -2,7 +2,7 @@
VITE_APP_ENV=staging
# 接口地址
VITE_API_BASE_URL=http://localhost:8080/staging
VITE_API_BASE_URL=https://wrj.shuixiongit.com/api
# 删除console
VITE_DROP_CONSOLE=true
package.json
@@ -84,7 +84,9 @@
    "uview-plus": "^3.5.41",
    "vue": "3.4.21",
    "vue-i18n": "9.1.9",
    "z-paging": "^2.8.8"
    "z-paging": "^2.8.8",
    "js-md5": "^0.7.3",
    "js-base64": "^3.7.4"
  },
  "devDependencies": {
    "@antfu/eslint-config": "5.0.0",
pnpm-lock.yaml
@@ -59,6 +59,12 @@
  dayjs:
    specifier: ^1.11.18
    version: 1.11.18
  js-base64:
    specifier: ^3.7.4
    version: 3.7.4
  js-md5:
    specifier: ^0.7.3
    version: 0.7.3
  leaflet:
    specifier: ^1.9.4
    version: 1.9.4
@@ -7795,6 +7801,14 @@
    resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==}
    dev: false
  /js-base64@3.7.4:
    resolution: {integrity: sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ==}
    dev: false
  /js-md5@0.7.3:
    resolution: {integrity: sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==}
    dev: false
  /js-tokens@4.0.0:
    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
src/api/user/index.js
@@ -1,14 +1,51 @@
import { get, post } from "@/utils/request"
import {
  get,
  post,
  request
} from "@/utils/request"
import website from '@/config/website'
/** 获取用户信息 */
export const profile = params => get("/user/profile", { params })
export const profile = params => get("/user/profile", {
  params
})
/** 登录 */
export const login = data =>
  post("/user/login", { data, custom: { auth: false } })
  post("/user/login", {
    data,
    custom: {
      auth: false
    }
  })
/** 验证码登录 */
export const loginByCode = data => post("/user/loginByCode", { data })
export const loginByCode = data => post("/user/loginByCode", {
  data
})
/** 退出登录 */
export const logout = () => post("/user/logout")
// 用户登录接口
export const loginByUsername = (tenantId, deptId, roleId, username, password, type, key, code) =>
  request({
    url: '/blade-auth/oauth/token',
    method: 'post',
    header: {
      'Tenant-Id': tenantId,
      'Dept-Id': website.switchMode ? deptId : '',
      'Role-Id': website.switchMode ? roleId : '',
      'Captcha-Key': key,
      'Captcha-Code': code,
    },
    params: {
      tenantId,
      username,
      password,
      grant_type: 'password',
      scope: 'all',
      type,
    },
  })
src/config/website.js
New file
@@ -0,0 +1,83 @@
/**
 * 全局配置文件
 */
export default {
    title: '',
    logo: 'S',
    key: 'saber', //配置主键,目前用于存储
    indexTitle: 'BladeX 微服务平台',
    clientId: 'drone', // 客户端id
    clientSecret: 'drone_secret', // 客户端密钥
    tenantMode: false, // 是否开启租户模式
    tenantId: '000000', // 管理组租户编号
    captchaMode: false, // 是否开启验证码模式
    switchMode: false, // 是否开启登录切换角色部门
    lockPage: '/lock',
    tokenTime: 3000,
    tokenHeader: 'Blade-Auth',
    //HTTP状态码白名单
    statusWhiteList: [],
    //配置首页不可关闭
    setting: {
        sidebar: 'vertical',
        tag: true,
        debug: true,
        collapse: true,
        search: true,
        color: true,
        lock: true,
        screenshot: true,
        fullscreen: true,
        theme: true,
        menu: true,
    },
    //首页配置
    fistPage: {
        // name: '首页',
        // path: '/wel/index',
        name: '门户页',
        path: '/wel/gatewayPage',
    },
    //配置菜单的属性
    menu: {
        iconDefault: 'icon-caidan',
        label: 'name',
        path: 'path',
        icon: 'source',
        children: 'children',
        query: 'query',
        href: 'path',
        meta: 'meta',
    },
    //水印配置
    watermark: {
        mode: false,
        text: 'BladeX',
    },
    //oauth2配置
    oauth2: {
        // 是否开启注册功能
        registerMode: true,
        // 使用后端工程 @org.springblade.test.Sm2KeyGenerator 获取
        publicKey: '请配置国密sm2公钥',
        // 第三方系统授权地址
        authUrl: 'http://localhost/blade-auth/oauth/render',
        // 单点登录系统认证
        ssoMode: false, // 是否开启单点登录功能
        ssoBaseUrl: 'http://localhost:8100', // 单点登录系统地址(cloud端口为8100,boot端口为80)
        ssoAuthUrl: '/oauth/authorize?client_id=saber3&response_type=code&redirect_uri=', // 单点登录授权地址
        ssoLogoutUrl: '/oauth/authorize/logout?redirect_uri=', // 单点登录退出地址
        redirectUri: 'http://localhost:2888/login', // 单点登录回调地址(Saber服务的登录界面地址)
    },
    //设计器配置
    design: {
        // 流程设计器类型(true->nutflow,false->flowable)
        designMode: true,
        // 流程设计器地址(flowable模式)
        designUrl: 'http://localhost:9999',
        // 报表设计器地址(cloud端口为8108,boot端口为80)
        reportUrl: 'http://localhost:8108/ureport',
        // 规则设计引擎地址
        edgeUrl: 'http://localhost:1880',
    },
}
src/pages/login/index.vue
@@ -3,19 +3,9 @@
  <view>
    <view class="login-form-wrap">
      <view class="title"> 欢迎登录 </view>
      <input
        v-model="tel"
        class="u-border-bottom"
        type="number"
        placeholder="请输入手机号"
      />
      <input v-model="tel" class="u-border-bottom" type="number" placeholder="请输入手机号" />
      <view class="u-border-bottom my-40rpx flex">
        <input
          v-model="code"
          class="flex-1"
          type="number"
          placeholder="请输入验证码"
        />
        <input v-model="code" class="flex-1" type="number" placeholder="请输入验证码" />
        <view>
          <u-code ref="uCodeRef" @change="codeChange" />
          <u-button :text="tips" type="success" size="mini" @click="getCode" />
@@ -55,13 +45,19 @@
</template>
<script setup>
  import md5 from 'js-md5'
  import {
    loginByUsername
  } from '@/api/user/index.js'
import {
  HOME_PATH,
  isTabBarPath,
  LOGIN_PATH,
  removeQueryString,
} from "@/router";
import { setToken } from "@/utils/auth";
  import {
    setToken
  } from "@/utils/auth";
// import { useUserStore } from '@/store';
// const userStore = useUserStore();
@@ -121,6 +117,33 @@
      url: redirect,
    });
  }, 800);
    let userInfo = {
      "tenantId": "000000",
      "deptId": "",
      "roleId": "",
      "username": "shuishen",
      "password": "Dashabi....",
      "type": "account",
      "code": "",
      "key": "",
      "image": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
    }
    loginByUsername(
      userInfo.tenantId,
      userInfo.deptId,
      userInfo.roleId,
      userInfo.username,
      md5(userInfo.password),
      userInfo.type,
      userInfo.key,
      userInfo.code
    ).then(res => {
      uni.switchTab({
        url: '/pages/map/index'
      })
    })
}
onLoad((options) => {
src/utils/request/interceptors.js
@@ -1,8 +1,17 @@
import { useUserStore } from "@/store"
import { getToken } from "@/utils/auth"
import {
  useUserStore
} from "@/store"
import {
  getToken
} from "@/utils/auth"
import storage from "@/utils/storage"
import { showMessage } from "./status"
import {
  showMessage
} from "./status"
import website from '@/config/website'
import {
  Base64
} from 'js-base64'
// 重试队列,每一项将是一个待执行的函数形式
let requestQueue = []
@@ -10,10 +19,8 @@
const repeatSubmit = config => {
  const requestObj = {
    url: config.url,
    data:
      typeof config.data === "object"
        ? JSON.stringify(config.data)
        : config.data,
    data: typeof config.data === "object" ?
      JSON.stringify(config.data) : config.data,
    time: new Date().getTime()
  }
  const sessionObj = storage.getJSON("sessionObj")
@@ -67,105 +74,85 @@
}
function requestInterceptors (http) {
  /**
   * 请求拦截
   * @param {object} http
   */
  http.interceptors.request.use(
    config => {
      // 可使用async await 做异步操作
      // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
      config.data = config.data || {}
      // 自定义参数
      const custom = config?.custom
      // 是否需要设置 token
      const isToken = custom?.auth === false
      if (getToken() && !isToken && config.header) {
        // token设置
        config.header.token = getToken()
  http.interceptors.request.use((config) => { // 可使用async await 做异步操作
    // 假设有token值需要在头部需要携带
    let accessToken = uni.getStorageSync('accessToken');
    if (accessToken) {
      config.header['Blade-Auth'] = 'bearer ' + accessToken;
      }
      // 是否显示 loading
      if (custom?.loading) {
        uni.showLoading({
          title: "加载中",
          mask: true
    // 安全请求header
    config.header['Blade-Requested-With'] = 'BladeHttpRequest';
    // 客户端认证参数
    config.header['Authorization'] = 'Basic ' + Base64.encode(website.clientId + ':' + website.clientSecret);
    // #ifndef H5
    let url = config.url
    if (process.env.NODE_ENV == 'development' && !url.startsWith("http")) {
      url = url.substring(url.indexOf('/api') + 4)
      config.url = url
    }
    // #endif
    // 额外参数
    // config.data = config.data || {};
    // config.data.pf = uni.getSystemInfoSync().platform;
    // config.data.sys = uni.getSystemInfoSync().system;
    // 演示custom 用处
    // if (config.custom.auth) {
    //   config.header.token = 'token'
    // }
    // if (config.custom.loading) {
    //  uni.showLoading()
    // }
    /**
     /* 演示
     if (!token) { // 如果token不存在,return Promise.reject(config) 会取消本次请求
        return Promise.reject(config)
      }
     **/
    return config
  }, config => { // 可使用async await 做异步操作
    return Promise.reject(config)
        })
      }
      // 是否需要防止数据重复提交
      const isRepeatSubmit = custom?.repeatSubmit === false
      if (
        !isRepeatSubmit &&
        (config.method === "POST" || config.method === "UPLOAD")
      ) {
        repeatSubmit(config)
      }
      return config
    },
    (
      config // 可使用async await 做异步操作
    ) => Promise.reject(config)
  )
}
function responseInterceptors (http) {
  /**
   * 响应拦截
   * @param {object} http
   */
  http.interceptors.response.use(
    response => {
      /* 对响应成功做点什么 可使用async await 做异步操作 */
      const data = response.data
      // 配置参数
      const config = response.config
      // 自定义参数
      const custom = config?.custom
      // 登录状态失效,重新登录
      if (data.code === 401) {
        return refreshToken(http, config)
  http.interceptors.response.use((response) => {
    console.log(response, 2222)
    // 若有数据返回则通过
    if (response.data.access_token || response.data.key) {
      return response.data
      }
      // 隐藏loading
      if (custom?.loading) {
        uni.hideLoading()
    // 服务端返回的状态码不等于200,则reject()
    if (response.data.code !== 200) {
      uni.showToast({
        title: response.data.msg,
        icon: 'none'
      });
      return Promise.reject(response);
      }
      // 请求成功则返回结果
      if (data.code === 200) {
        return response || {}
    return response.data;
  }, (response) => {
    console.log(response, 111)
    /*  对响应错误做点什么 (statusCode !== 200)*/
    uni.showToast({
      title: response.data.msg,
      icon: 'none'
    });
    if (response.statusCode == 401) {
      const pages = getCurrentPages()
      const currentPage = pages[pages.length - 1]
      uni.redirectTo({
        url: `/pages/login/login-account?redirect=/${currentPage.route}`
      })
      }
      // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
      if (custom?.toast !== false) {
        uni.$u.toast(data.message)
      }
      // 请求失败则抛出错误
      return Promise.reject(data)
    },
    response => {
      // 自定义参数
      const custom = response.config?.custom
      // 隐藏loading
      if (custom?.loading !== false) {
        uni.hideLoading()
      }
      // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
      if (custom?.toast !== false) {
        const message = response.statusCode
          ? showMessage(response.statusCode)
          : "网络连接异常,请稍后再试!"
        uni.$u.toast(message)
      }
      return Promise.reject(response)
    }
  )
  })
}
export { requestInterceptors, responseInterceptors }
export {
  requestInterceptors,
  responseInterceptors
}