瀏覽代碼

新增商城相关页面切换新老接口按钮插件

chenguo 1 周之前
父節點
當前提交
1e7a0b9e7b
共有 2 個文件被更改,包括 266 次插入1 次删除
  1. 238 0
      src/components/SmartEndpointToggle/ScrmEndpointButton.vue
  2. 28 1
      src/utils/request.js

+ 238 - 0
src/components/SmartEndpointToggle/ScrmEndpointButton.vue

@@ -0,0 +1,238 @@
+
+<!--add by chenguo 2025年7月31日
+    可用于不修改api/*.js 接口,实现前端代码复用
+    通过添加请求前缀的方式访问接口 如:/his/store/productList => [your-prefix]/his/store/productList
+    使用说明:引入组件并指定prefix及componentName(尽可能唯一)
+            添加组件方式:
+            <smart-endpoint-toggle-button
+            prefix="[your-prefix]"
+            component-name="[your-component-name]">
+            </smart-endpoint-toggle-button>
+            提供可用的回调
+            @afterEndpoint="handleAfterEndpointToggle"
+            @beforeEndpoint="handleBeforeEndpointToggle"
+ -->
+<template>
+  <div class="endpoint-toggle-container">
+    <div class="toggle-switch" :class="{ 'new-endpoint': isUsingNewEndpoint }">
+      <div class="toggle-option old-endpoint" @click="selectOldEndpoint">
+        <span>旧接口</span>
+      </div>
+      <div class="toggle-option new-endpoint" @click="selectNewEndpoint">
+        <span>新接口</span>
+      </div>
+      <div class="toggle-slider"></div>
+    </div>
+  </div>
+</template>
+
+<script>import {
+  resetEndpoint, setActive,
+} from '@/utils/request'
+
+export default {
+  name: 'ScrmEndpointButton',
+  props: {
+    //prefix:加在js请求前的方法
+    prefix: {
+      type: String,
+      required: true
+    },
+    // 组件名称,用于生成唯一标识
+    componentName: {
+      type: String,
+      required: true
+    },
+    // 默认选中状态(false表示默认选中旧接口,true表示默认选中新接口)
+    defaultNewEndpoint: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      isUsingNewEndpoint: false,
+      stateKey: ''
+    }
+  },
+  created() {
+    console.log('SmartEndpointToggleButton created');
+    // 生成基于组件名和路由的唯一状态键
+    this.stateKey = this.generateStateKey()
+    // 初始化状态
+    this.initializeState()
+  },
+  activated() {
+    console.log('SmartEndpointToggleButton activated,stateKey='+this.stateKey+',prefix='+this.prefix+',is='+this.isUsingNewEndpoint);
+    setActive(this.stateKey);
+    // 页面激活时恢复状态
+    this.restoreState()
+  },
+  deactivated() {
+    console.log('SmartEndpointToggleButton deactivated');
+    // 页面失活时保存状态
+    this.saveState()
+  },
+  destroyed() {
+    console.log('SmartEndpointToggleButton destroyed');
+    // 组件销毁
+    resetEndpoint(this.stateKey)
+  },
+  methods: {
+    // 生成状态存储的唯一键
+    generateStateKey() {
+      const routePath = this.$route ? this.$route.path : ''
+      const routeQuery = this.$route && this.$route.query ? JSON.stringify(this.$route.query) : ''
+      return `endpoint_toggle_${this.componentName}_${routePath}_${routeQuery}`
+    },
+
+    // 初始化状态
+    initializeState() {
+      setActive(this.stateKey)
+      // 默认选中旧接口
+      this.isUsingNewEndpoint = this.defaultNewEndpoint
+      this.saveState();
+    },
+
+    // 保存状态到 sessionStorage
+    saveState() {
+      try {
+        const state = {
+          prefix: this.prefix,
+          isUsingNewEndpoint: this.isUsingNewEndpoint,
+          timestamp: Date.now()
+        }
+        sessionStorage.setItem(this.stateKey, JSON.stringify(state))
+      } catch (e) {
+        console.warn('Failed to save endpoint toggle state:', e)
+      }
+    },
+
+    // 从 sessionStorage 恢复状态
+    restoreState() {
+      try {
+        const stateStr = sessionStorage.getItem(this.stateKey)
+        if (stateStr) {
+          const state = JSON.parse(stateStr)
+          this.isUsingNewEndpoint = state.isUsingNewEndpoint || false
+        } else {
+          this.isUsingNewEndpoint = this.defaultNewEndpoint
+        }
+      } catch (e) {
+        console.warn('Failed to restore endpoint toggle state:', e)
+        this.isUsingNewEndpoint = this.defaultNewEndpoint
+      }
+    },
+
+    // 选择旧接口
+    selectOldEndpoint() {
+      if (this.isUsingNewEndpoint) {
+        this.toggleEndpointState(false)
+      }
+    },
+
+    // 选择新接口
+    selectNewEndpoint() {
+      if (!this.isUsingNewEndpoint) {
+        this.toggleEndpointState(true)
+      }
+    },
+
+    // 切换端点状态
+    async toggleEndpointState(newState) {
+      // 触发切换前事件
+      const beforeResult = this.$emit('beforeEndpoint', this.isUsingNewEndpoint)
+      if (beforeResult === false) {
+        return
+      }
+
+      try {
+        // 更新状态
+        this.isUsingNewEndpoint = newState
+
+        // 保存状态
+        this.saveState()
+
+        // 触发切换后事件
+        this.$emit('afterEndpoint', this.isUsingNewEndpoint)
+
+        // 执行回调
+        //if (this.$listeners.afterToggle) {
+        //  await this.$listeners.afterToggle(this.isUsingNewEndpoint)
+        //}
+      } catch (error) {
+        console.error('Failed to toggle endpoint state:', error)
+        // 发生错误时回滚状态
+        this.isUsingNewEndpoint = !newState
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>.endpoint-toggle-container {
+  display: inline-block;
+  vertical-align: middle;
+}
+
+.toggle-switch {
+  position: relative;
+  display: flex;
+  width: 145px;
+  height: 32px;
+  background-color: #f5f7fa;
+  border-radius: 16px;
+  cursor: pointer;
+  overflow: hidden;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) inset;
+}
+
+.toggle-option {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2;
+  transition: color 0.3s ease;
+  font-size: 12px;
+  font-weight: 500;
+}
+
+.toggle-option.old-endpoint {
+  color: #ffffff;
+}
+
+.toggle-option.new-endpoint {
+  color: #606266;
+}
+
+.toggle-switch.new-endpoint .toggle-option.old-endpoint {
+  color: #606266;
+}
+
+.toggle-switch.new-endpoint .toggle-option.new-endpoint {
+  color: #ffffff;
+}
+
+.toggle-slider {
+  position: absolute;
+  top: 2px;
+  left: 2px;
+  width: calc(50% - 2px);
+  height: calc(100% - 4px);
+  background-color: #3576f8;
+  border-radius: 14px;
+  transition: transform 0.3s ease;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+  z-index: 1;
+}
+
+.toggle-switch.new-endpoint .toggle-slider {
+  transform: translateX(100%);
+}
+
+/* 悬停效果 */
+.toggle-option:hover {
+  opacity: 0.6;
+}
+</style>

+ 28 - 1
src/utils/request.js

@@ -12,13 +12,40 @@ const service = axios.create({
   // 超时
   timeout: 1200000
 })
+
+// 存储当前激活的组件状态键
+let activeStateKey = null;
+
+// 重置指定页面的状态
+export function resetEndpoint() {
+  setActive(null);
+}
+// 设置当前激活状态键
+export function setActive(stateKey) {
+  activeStateKey = stateKey;
+}
+
+
 // request拦截器
 service.interceptors.request.use(config => {
+
+  // 使用当前激活的组件状态来决定是否添加前缀
+  let useNewEndpoint = false
+  let routePrefix = ''
+  if (activeStateKey) {
+    const state = JSON.parse(sessionStorage.getItem(activeStateKey));
+    useNewEndpoint = state.isUsingNewEndpoint;
+    routePrefix = state.prefix;
+  }
+  if (useNewEndpoint) {
+    config.url = routePrefix + config.url;
+  }
+
   //判断watch请求
   if(config.url.indexOf('/watch-api') == -1){
     config.url = process.env.VUE_APP_BASE_API + config.url
   }
- 
+
   // 是否需要设置 token
   const isToken = (config.headers || {}).isToken === false
   if (getToken() && !isToken) {