Ver código fonte

添加服务路由配置

Lin Qilong 5 meses atrás
pai
commit
9f7637759b

+ 2 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -119,6 +119,8 @@ xss:
   urlPatterns: /system/*,/monitor/*,/tool/*
 
 sys:
+  gateway:
+    url: http://localhost:8080
   report:
     upload:
       path: D:/tmp/report/

+ 65 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/GatewayRoutesController.java

@@ -0,0 +1,65 @@
+package com.ruoyi.interfaces.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.interfaces.domain.GatewayRoutes;
+import com.ruoyi.interfaces.service.GatewayRoutesService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author lql
+ * @date 2025-8-19
+ */
+@Api(value = "路由配置", tags = "路由配置")
+@RestController
+@RequestMapping("/gateway/routes")
+public class GatewayRoutesController extends BaseController {
+
+    @Autowired
+    private GatewayRoutesService gatewayRoutesService;
+
+
+    @ApiOperation(value = "新增/修改路由配置")
+    @PostMapping("")
+    public AjaxResult save(@ApiParam(name = "gatewayRoutes", value = "GatewayRoutes", required = true) @RequestBody GatewayRoutes gatewayRoutes) {
+        boolean result = gatewayRoutesService.saveOrUpdate(gatewayRoutes);
+        if (result) {
+            gatewayRoutesService.refreshRoutes();
+        }
+        return AjaxResult.success(result);
+    }
+
+    @ApiOperation(value = "根据ID删除路由配置")
+    @DeleteMapping(value = "/{id}")
+    public AjaxResult delete(@ApiParam(name = "id", value = "id", required = true) @PathVariable String id) {
+        return AjaxResult.success(gatewayRoutesService.removeById(id));
+    }
+
+    @ApiOperation(value = "根据ID获取路由配置(单表)")
+    @GetMapping("/{id}")
+    public AjaxResult get(@ApiParam(name = "id", value = "id", required = true) @PathVariable String id) {
+        return AjaxResult.success(gatewayRoutesService.getById(id));
+    }
+
+
+    @ApiOperation("根据主键获取数据")
+    @GetMapping(value = "/listOfPage")
+    public TableDataInfo listOfPage(GatewayRoutes gatewayRoutes) {
+        startPage();
+        QueryWrapper<GatewayRoutes> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(StringUtils.isNotBlank(gatewayRoutes.getStatus()), "status", gatewayRoutes.getStatus())
+                .like(StringUtils.isNotBlank(gatewayRoutes.getServiceName()), "service_name", gatewayRoutes.getServiceName());
+        List<GatewayRoutes> list = gatewayRoutesService.list(queryWrapper);
+        return getDataTable(list);
+    }
+
+}

+ 19 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/GatewayRoutes.java

@@ -0,0 +1,19 @@
+package com.ruoyi.interfaces.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@TableName
+public class GatewayRoutes implements Serializable {
+
+    private String id;
+    private String serviceName;
+    private String uri;
+    private String predicates;
+    private String filters;
+    private String status;
+
+}

+ 9 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/GatewayRoutesMapper.java

@@ -0,0 +1,9 @@
+package com.ruoyi.interfaces.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.interfaces.domain.GatewayRoutes;
+
+public interface GatewayRoutesMapper extends BaseMapper<GatewayRoutes> {
+
+
+}

+ 10 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/GatewayRoutesService.java

@@ -0,0 +1,10 @@
+package com.ruoyi.interfaces.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.interfaces.domain.GatewayRoutes;
+
+public interface GatewayRoutesService extends IService<GatewayRoutes> {
+
+    void refreshRoutes();
+
+}

+ 26 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/GatewayRoutesServiceImpl.java

@@ -0,0 +1,26 @@
+package com.ruoyi.interfaces.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.utils.OkHttpUtils;
+import com.ruoyi.interfaces.domain.GatewayRoutes;
+import com.ruoyi.interfaces.mapper.GatewayRoutesMapper;
+import com.ruoyi.interfaces.service.GatewayRoutesService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class GatewayRoutesServiceImpl extends ServiceImpl<GatewayRoutesMapper, GatewayRoutes> implements GatewayRoutesService {
+
+    @Value("${sys.gateway.url}")
+    private String gatewayUrl;
+
+    @Async
+    public void refreshRoutes() {
+        OkHttpUtils.get(gatewayUrl + "/gateway/refresh");
+        log.info("刷新路由");
+    }
+
+}

+ 40 - 0
ruoyi-ui/src/api/gateway/gatewayRouters.js

@@ -0,0 +1,40 @@
+import request from "@/utils/request";
+
+/**
+ * 保存路由
+ * @param data
+ */
+export function saveGatewayRouter(data) {
+    return request({
+        url: `/gateway/routes`,
+        method: "post",
+        data: data,
+    });
+}
+
+
+/**
+ * 删除路由
+ * @param id 路由id
+ */
+export function deleteGatewayRouter(id) {
+    return request({
+        url: `/gateway/routes/${id}`,
+        method: "delete",
+    });
+}
+
+
+/**
+ * 查询选择器列表
+ * @param data
+ */
+export function getGatewayRoutersList(data) {
+    return request({
+        url: `/gateway/routes/listOfPage`,
+        method: "get",
+        params: data,
+    });
+}
+
+

+ 254 - 416
ruoyi-ui/src/views/service/gateway/index.vue

@@ -1,456 +1,294 @@
 <template>
   <div class="app-container">
     <el-row :gutter="20">
-      <!--选择器数据-->
-      <el-col :span="10" :xs="24">
-        <el-form
-          ref="formRef"
-          :inline="true"
-          size="mini"
-          :model="selectorParam"
-        >
-          <el-form-item>
-            <span>选择器列表</span>
+      <el-col :span="24" :xs="24">
+        <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+          <el-form-item label="服务名称" prop="serviceName">
+            <el-input
+                v-model="queryParams.serviceName"
+                placeholder="请输入服务名称"
+                clearable
+                style="width: 240px"
+                @keyup.enter="handleQuery"
+            />
           </el-form-item>
-          <div style="float: right">
-            <el-form-item>
-              <el-input v-model="selectorParam.name">
-                <template #append>
-                  <el-button
-                    type="primary"
-                    icon="el-icon-search"
-                    placeholder="选择器名称"
-                    @click="getSelectorList"
-                  />
-                </template>
-              </el-input>
-            </el-form-item>
-            <el-form-item>
-              <!-- <el-button type="primary" @click="selectorVisible = true">
-                添加选择器
-              </el-button> -->
-            </el-form-item>
-          </div>
-        </el-form>
-        <el-table
-          stripe
-          ref="selectorTable"
-          :data="selectorData"
-          :height="tableHeight"
-          highlight-current-row
-          @current-change="handleCurrentChange"
-          :header-cell-style="{
-            background: '#ebf3fb',
-            color: '#333',
-            padding: '4px 0',
-            'border-right': '1px solid #fff',
-          }"
-        >
-          <el-table-column
-            show-overflow-tooltip
-            header-align="center"
-            align="center"
-            prop="name"
-            label="名称"
-          />
-          <el-table-column
-            show-overflow-tooltip
-            header-align="center"
-            align="center"
-            prop="enabled"
-            label="状态"
-          >
-            <template slot-scope="scope">
-              <el-tag
-                :type="scope.row.enabled ? 'success' : 'warning'"
-                disable-transitions
-              >
-                {{ scope.row.enabled ? "开启" : "关闭" }}
-              </el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column
-            fixed="right"
-            align="center"
-            label="操作"
-            width="220"
-          >
-            <template #default="scope">
-              <!-- <el-button
-                v-hasPermi="['service:info:update']"
-                @click="handleEditSelector(scope.row)"
-                size="mini"
-              >
-                编辑
-              </el-button> -->
-              <el-button
-                type="danger"
-                @click="handleDeleteSelector(scope.row)"
-                v-hasPermi="['service:info:delete']"
-                size="mini"
-              >
-                删除
-              </el-button>
-            </template>
-          </el-table-column>
-        </el-table>
-        <pagination
-          v-show="selectorDataTotal > 0"
-          :total="selectorDataTotal"
-          :page.sync="selectorParam.currentPage"
-          :limit.sync="selectorParam.pageSize"
-          @pagination="getSelectorList"
-        />
-      </el-col>
-      <!--选择器规则列表-->
-      <el-col :span="14" :xs="24">
-        <el-form ref="formRef" :inline="true" size="mini" :model="ruleParam">
-          <el-form-item>
-            <span>选择器规则列表</span>
+          <el-form-item label="状态" prop="status">
+            <el-select
+                v-model="queryParams.status"
+                placeholder="服务状态"
+                clearable
+                style="width: 240px"
+            >
+              <el-option
+                  v-for="dict in sys_normal_disable"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+              />
+            </el-select>
           </el-form-item>
           <el-form-item>
-            <el-button
-              type="primary"
-              plain
-              icon="el-icon-refresh-right"
-              @click="syncProxyData"
-            >
-              同步数据
-            </el-button>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
           </el-form-item>
-          <div style="float: right">
-            <el-form-item>
-              <el-input v-model="ruleParam.name">
-                <template #append>
-                  <el-button
-                    type="primary"
-                    icon="el-icon-search"
-                    placeholder="规则名称"
-                    @click="getRuleList"
-                  />
-                </template>
-              </el-input>
-            </el-form-item>
-            <el-form-item>
-              <!-- <el-button type="primary" @click="ruleVisible = true">
-                添加规则
-              </el-button> -->
-            </el-form-item>
-          </div>
         </el-form>
-        <el-table
-          stripe
-          :data="ruleData"
-          :height="tableHeight"
-          :header-cell-style="{
-            background: '#ebf3fb',
-            color: '#333',
-            padding: '4px 0',
-            'border-right': '1px solid #fff',
-          }"
-        >
-          <el-table-column
-            show-overflow-tooltip
-            align="center"
-            prop="name"
-            label="规则名称"
-          />
-          <el-table-column
-            show-overflow-tooltip
-            header-align="center"
-            align="center"
-            width="70"
-            prop="enabled"
-            label="状态"
-          >
-            <template slot-scope="scope">
-              <el-tag
-                :type="scope.row.enabled ? 'success' : 'warning'"
-                disable-transitions
-              >
-                {{ scope.row.enabled ? "开启" : "关闭" }}
-              </el-tag>
+
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+                type="primary"
+                plain
+                icon="Plus"
+                @click="handleAdd"
+                v-hasPermi="['system:user:add']"
+            >新增
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+                type="success"
+                plain
+                icon="Edit"
+                :disabled="single"
+                @click="handleUpdate"
+                v-hasPermi="['system:user:edit']"
+            >修改
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+                type="danger"
+                plain
+                icon="Delete"
+                :disabled="multiple"
+                @click="handleDelete"
+                v-hasPermi="['system:user:remove']"
+            >删除
+            </el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
+        </el-row>
+
+        <el-table v-loading="loading" :data="gatewayList" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="50" align="center"/>
+          <el-table-column label="服务名称" align="center" key="serviceName" prop="serviceName"
+                           v-if="columns[0].visible" :show-overflow-tooltip="true"/>
+          <el-table-column label="服务地址" align="center" key="uri" prop="uri" v-if="columns[1].visible"
+                           :show-overflow-tooltip="true"/>
+          <el-table-column label="状态" align="center" key="status" v-if="columns[2].visible">
+            <template #default="scope">
+              <el-switch
+                  v-model="scope.row.status"
+                  active-value="0"
+                  inactive-value="1"
+                  @change="handleStatusChange(scope.row)"
+              ></el-switch>
             </template>
           </el-table-column>
-          <el-table-column
-            show-overflow-tooltip
-            align="center"
-            width="150"
-            prop="dateUpdated"
-            label="更新时间"
-          />
-          <el-table-column
-            fixed="right"
-            align="center"
-            label="操作"
-            width="180"
-          >
+          <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
             <template #default="scope">
-              <!-- <el-button
-                v-hasPermi="['service:info:update']"
-                @click="handleEditRule(scope.row)"
-                size="mini"
-              >
-                编辑
-              </el-button> -->
-              <el-button
-                type="danger"
-                @click="handleDeleteRule(scope.row)"
-                v-hasPermi="['service:info:delete']"
-                size="mini"
-              >
-                删除
-              </el-button>
+              <el-tooltip content="修改" placement="top" v-if="scope.row.id !== 1">
+                <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
+                           v-hasPermi="['system:user:edit']"></el-button>
+              </el-tooltip>
+              <el-tooltip content="删除" placement="top" v-if="scope.row.id !== 1">
+                <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
+                           v-hasPermi="['system:user:remove']"></el-button>
+              </el-tooltip>
             </template>
           </el-table-column>
         </el-table>
         <pagination
-          v-show="ruleDataTotal > 0"
-          :total="ruleDataTotal"
-          :page.sync="ruleParam.currentPage"
-          :limit.sync="ruleParam.pageSize"
-          @pagination="getRuleList"
+            v-show="total > 0"
+            :total="total"
+            v-model:page="queryParams.pageNum"
+            v-model:limit="queryParams.pageSize"
+            @pagination="getList"
         />
       </el-col>
     </el-row>
-    <el-dialog :visible.sync="selectorVisible" title="选择器">
-      <el-form ref="selectorForm" :model="selectorForm">
-        <el-form-item label="名称">
-          <el-input v-model="selectorForm.name"></el-input>
+
+    <!-- 添加或修改服务配置对话框 -->
+    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
+      <el-form :model="form" :rules="rules" ref="userRef" label-width="80px">
+        <el-form-item label="服务名称" prop="serviceName">
+          <el-input v-model="form.serviceName" placeholder="请输入服务名称" maxlength="30"/>
         </el-form-item>
-        <el-form-item label="类型">
-          <el-select v-model="selectorForm.type" placeholder="类型">
-            <el-option label="全流量" value="0"></el-option>
-            <el-option label="自定义" value="1"></el-option>
-          </el-select>
+        <el-form-item label="服务地址" prop="uri">
+          <el-input v-model="form.uri" placeholder="请输入服务地址" maxlength="200"/>
         </el-form-item>
-        <el-form-item v-if="selectorForm.type == '1'" label="类型">
-          <el-select v-model="selectorForm.matchMode" placeholder="类型">
-            <el-option
-              v-for="matchMode in matchModes"
-              :key="matchMode.id"
-              :value="matchMode.dictValue"
-            >{{ matchMode.dictName }}
-            </el-option
-            >
-          </el-select>
+        <el-form-item label="服务匹配" prop="predicates">
+          <el-input v-model="form.predicates" placeholder="请输入服务匹配"/>
         </el-form-item>
-        <el-row :gutter="5">
-          <el-col :span="7">
-            <el-form-item label="继续后续选择器:">
-              <el-switch v-model="selectorForm.continued"></el-switch>
-            </el-form-item>
-          </el-col>
-          <el-col :span="7">
-            <el-form-item label="打印日志:">
-              <el-switch v-model="selectorForm.loged"></el-switch>
-            </el-form-item>
-          </el-col>
-          <el-col :span="7">
-            <el-form-item label="是否开启:">
-              <el-switch v-model="selectorForm.enabled"></el-switch>
+        <el-form-item label="服务拦截" prop="filters">
+          <el-input v-model="form.filters" placeholder="请输入服务拦截"/>
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="状态">
+              <el-radio-group v-model="form.status">
+                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">
+                  {{ dict.label }}
+                </el-radio>
+              </el-radio-group>
             </el-form-item>
           </el-col>
         </el-row>
-        <el-form-item label="处理">
-          <el-row :gutter="5">
-            <el-col
-              :span="6"
-              v-for="handler in pluginHandles"
-              :key="handler.id"
-            >
-              <el-input v-model="selectorForm[handler.field]">
-                <template slot="prepend">{{ handler.label }}</template>
-              </el-input>
-            </el-col>
-          </el-row>
-        </el-form-item>
-        <el-form-item label="执行顺序">
-          <el-input v-model="selectorForm.sort"></el-input>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="selectorVisible = true">
-            确认
-          </el-button>
-        </el-form-item>
       </el-form>
-    </el-dialog>
-    <el-dialog :visible.sync="ruleVisible" title="选择器规则">
-      <!-- @close="closeDialog" -->
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
     </el-dialog>
   </div>
 </template>
 
-<script>
-import "@/assets/styles/common.scss";
-import {
-  getSelectorList,
-  getRuleList,
-  syncProxyData,
-  getShenyuToken,
-  addSelector,
-  deleteSelector,
-  deleteRule,
-  getOperatorList,
-  getMatchModeList,
-  getParamTypeList,
-  getPluginHandleList,
-} from "@/api/gateway/proxy.js";
-import useDictStore from '@/store/modules/dict.js'
-export default {
-  name: "proxy",
-  data() {
-    return {
-      token: undefined,
-      selectorVisible: false,
-      ruleVisible: false,
-      currentRow: undefined,
-      tableHeight: window.innerHeight - 300,
-      selectorData: [],
-      selectorDataTotal: 0,
-      selectorParam: {
-        currentPage: 1,
-        pageSize: 20,
-        pluginId: 5,
-        name: "",
-      },
-      ruleData: [],
-      ruleDataTotal: 0,
-      ruleParam: {
-        currentPage: 1,
-        pageSize: 20,
-        pluginId: 5,
-        name: "",
-        selectorId: "",
-      },
-      selectorForm: {},
-      ruleForm: {},
+<script setup name="User">
+import {deleteGatewayRouter, getGatewayRoutersList, saveGatewayRouter} from "@/api/gateway/gatewayRouters.js";
 
-      operators: undefined,
-      matchModes: undefined,
-      paramTypes: undefined,
-      pluginHandles: undefined,
-    };
-  },
-  mounted() {
-    getShenyuToken().then((r) => {
-      this.token = r.data.token;
-      this.getSelectorList();
-      this.getBaseData();
-    });
+const {proxy} = getCurrentInstance();
+const {sys_normal_disable} = proxy.useDict("sys_normal_disable");
+
+const gatewayList = ref([]);
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+
+// 列显隐信息
+const columns = ref([
+  {key: 0, label: `服务名称`, visible: true},
+  {key: 1, label: `服务地址`, visible: true},
+  {key: 2, label: `状态`, visible: true}
+]);
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    serviceName: undefined,
+    status: undefined,
   },
-  methods: {
-    // 获取选择器列表
-    getSelectorList() {
-      getSelectorList(this.selectorParam, this.token).then((r) => {
-        this.selectorData = r.data.dataList;
-        this.selectorDataTotal = r.data.page.totalCount;
-        this.setCurrent(this.selectorData[0]);
-      });
-    },
-    // 获取选择器规则列表
-    getRuleList() {
-      this.ruleParam.selectorId = this.currentRow.id;
-      getRuleList(this.ruleParam, this.token).then((r) => {
-        this.ruleData = r.data.dataList;
-        this.ruleDataTotal = r.data.page.totalCount;
-      });
-    },
-    // 同步信息
-    syncProxyData() {
-      syncProxyData(this.token).then((r) => {
-        this.$modal.msgSuccess("同步成功");
-      });
-    },
-    // 设置当前行
-    setCurrent(row) {
-      this.$refs.selectorTable.setCurrentRow(row);
-    },
-    // 选中执行操作
-    handleCurrentChange(val) {
-      this.currentRow = val;
-      this.getRuleList();
-    },
-    // 编辑选择器
-    handleEditSelector(selector) {
-    },
-    // 编辑选择器规则
-    handleEditRule(rule) {
-    },
-    // 删除选择器
-    handleDeleteSelector(selector) {
-      this.$modal
-        .confirm('是否确认删除选择器 "' + selector.name + '" ?')
-        .then(() => deleteSelector([selector.id], this.token))
-        .then(() => {
-          this.getSelectorList();
-          this.$modal.msgSuccess("删除成功");
-        })
-        .catch(() => {
-        });
-    },
-    // 删除选择器规则
-    handleDeleteRule(rule) {
-      this.$modal
-        .confirm('是否确认删除选择器 "' + rule.name + '" ?')
-        .then(() => deleteRule([rule.id], this.token))
-        .then(() => {
-          this.getRuleList();
-          this.$modal.msgSuccess("删除成功");
-        })
-        .catch(() => {
-        });
-    },
-    getBaseData() {
-      getOperatorList(this.token).then((r) => {
-        this.operators = r.data;
-      });
-      getMatchModeList(this.token).then((r) => {
-        this.matchModes = r.data;
-      });
-      getParamTypeList(this.token).then((r) => {
-        this.paramTypes = r.data;
-      });
-      getPluginHandleList(this.token).then((r) => {
-        this.pluginHandles = r.data;
+  rules: {
+    serviceName: [
+      {required: true, message: "服务名称不能为空", trigger: "blur"},
+      {min: 2, max: 20, message: "服务名称长度必须介于 2 和 20 之间", trigger: "blur"}
+    ],
+  }
+});
+
+const {queryParams, form, rules} = toRefs(data);
+
+/** 查询服务列表 */
+function getList() {
+  loading.value = true;
+  getGatewayRoutersList(queryParams.value)
+      .then(res => {
+        loading.value = false;
+        gatewayList.value = res.rows;
+        total.value = res.total;
       });
-    },
-  },
-};
-</script>
-<style lang="scss" scoped>
-::v-deep .el-table {
-  border: 1px solid #e6e6e6;
-  border-right: 1px solid #e6e6e6;
-  border-bottom: none;
-  border-radius: 5px;
 }
 
-::v-deep .el-dialog {
-  position: relative;
-  background: #ffffff;
-  border-radius: 2px;
-  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
-  -webkit-box-sizing: border-box;
-  box-sizing: border-box;
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef");
+  queryParams.value.deptId = undefined;
+  proxy.$refs.deptTreeRef.setCurrentKey(null);
+  handleQuery();
+};
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const ids = row.id || ids.value;
+  proxy.$modal.confirm('是否确认删除服务编号为"' + ids + '"的数据项?')
+      .then(() => deleteGatewayRouter(ids))
+      .then(() => {
+        getList();
+        proxy.$modal.msgSuccess("删除成功");
+      }).catch(() => {
+  });
 }
 
-::v-deep .el-dialog__body {
-  // border-top: 1px solid #dcdfe6;
-  overflow-y: auto;
+/** 服务状态修改  */
+function handleStatusChange(row) {
+  let text = row.status === "0" ? "启用" : "停用";
+  proxy.$modal.confirm('确认要"' + text + '""' + row.serviceName + '"服务吗?').then(function () {
+    return saveGatewayRouter({id: row.id, status: row.status});
+  }).then(() => {
+    proxy.$modal.msgSuccess(text + "成功");
+  }).catch(function () {
+    row.status = row.status === "0" ? "1" : "0";
+  });
+};
 
-  &::-webkit-scrollbar {
-    width: 2px;
-    background-color: #ccc;
-  }
+/** 选择条数  */
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
 
-  &::-webkit-scrollbar-thumb {
-    background-color: #0ae;
-  }
 
-  &::-webkit-scrollbar-track {
-    background-color: #ccc;
-  }
+/** 重置操作表单 */
+function reset() {
+  form.value = {
+    id: undefined,
+    serviceName: undefined,
+    uri: undefined,
+    predicates: [],
+    filters: [],
+    status: "0"
+  };
+  proxy.resetForm("userRef");
+};
+
+/** 取消按钮 */
+function cancel() {
+  open.value = false;
+  reset();
+};
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "添加服务";
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset();
+  form.value = row;
+  open.value = true;
+  title.value = "修改服务";
 }
-</style>
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["userRef"].validate(valid => {
+    if (valid) {
+      saveGatewayRouter(form.value).then(response => {
+        proxy.$modal.msgSuccess("保存成功");
+        open.value = false;
+        getList();
+      });
+    }
+  });
+};
+
+getList();
+</script>

+ 455 - 0
ruoyi-ui/src/views/service/gateway/index2.vue

@@ -0,0 +1,455 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--选择器数据-->
+      <el-col :span="10" :xs="24">
+        <el-form
+            ref="formRef"
+            :inline="true"
+            size="mini"
+            :model="selectorParam"
+        >
+          <el-form-item>
+            <span>选择器列表</span>
+          </el-form-item>
+          <div style="float: right">
+            <el-form-item>
+              <el-input v-model="selectorParam.name">
+                <template #append>
+                  <el-button
+                      type="primary"
+                      icon="el-icon-search"
+                      placeholder="选择器名称"
+                      @click="getSelectorList"
+                  />
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item>
+              <!-- <el-button type="primary" @click="selectorVisible = true">
+                添加选择器
+              </el-button> -->
+            </el-form-item>
+          </div>
+        </el-form>
+        <el-table
+            stripe
+            ref="selectorTable"
+            :data="selectorData"
+            :height="tableHeight"
+            highlight-current-row
+            @current-change="handleCurrentChange"
+            :header-cell-style="{
+            background: '#ebf3fb',
+            color: '#333',
+            padding: '4px 0',
+            'border-right': '1px solid #fff',
+          }"
+        >
+          <el-table-column
+              show-overflow-tooltip
+              header-align="center"
+              align="center"
+              prop="name"
+              label="名称"
+          />
+          <el-table-column
+              show-overflow-tooltip
+              header-align="center"
+              align="center"
+              prop="enabled"
+              label="状态"
+          >
+            <template slot-scope="scope">
+              <el-tag
+                  :type="scope.row.enabled ? 'success' : 'warning'"
+                  disable-transitions
+              >
+                {{ scope.row.enabled ? "开启" : "关闭" }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column
+              fixed="right"
+              align="center"
+              label="操作"
+              width="220"
+          >
+            <template #default="scope">
+              <!-- <el-button
+                v-hasPermi="['service:info:update']"
+                @click="handleEditSelector(scope.row)"
+                size="mini"
+              >
+                编辑
+              </el-button> -->
+              <el-button
+                  type="danger"
+                  @click="handleDeleteSelector(scope.row)"
+                  v-hasPermi="['service:info:delete']"
+                  size="mini"
+              >
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+            v-show="selectorDataTotal > 0"
+            :total="selectorDataTotal"
+            :page.sync="selectorParam.currentPage"
+            :limit.sync="selectorParam.pageSize"
+            @pagination="getSelectorList"
+        />
+      </el-col>
+      <!--选择器规则列表-->
+      <el-col :span="14" :xs="24">
+        <el-form ref="formRef" :inline="true" size="mini" :model="ruleParam">
+          <el-form-item>
+            <span>选择器规则列表</span>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+                type="primary"
+                plain
+                icon="el-icon-refresh-right"
+                @click="syncProxyData"
+            >
+              同步数据
+            </el-button>
+          </el-form-item>
+          <div style="float: right">
+            <el-form-item>
+              <el-input v-model="ruleParam.name">
+                <template #append>
+                  <el-button
+                      type="primary"
+                      icon="el-icon-search"
+                      placeholder="规则名称"
+                      @click="getRuleList"
+                  />
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item>
+              <!-- <el-button type="primary" @click="ruleVisible = true">
+                添加规则
+              </el-button> -->
+            </el-form-item>
+          </div>
+        </el-form>
+        <el-table
+            stripe
+            :data="ruleData"
+            :height="tableHeight"
+            :header-cell-style="{
+            background: '#ebf3fb',
+            color: '#333',
+            padding: '4px 0',
+            'border-right': '1px solid #fff',
+          }"
+        >
+          <el-table-column
+              show-overflow-tooltip
+              align="center"
+              prop="name"
+              label="规则名称"
+          />
+          <el-table-column
+              show-overflow-tooltip
+              header-align="center"
+              align="center"
+              width="70"
+              prop="enabled"
+              label="状态"
+          >
+            <template slot-scope="scope">
+              <el-tag
+                  :type="scope.row.enabled ? 'success' : 'warning'"
+                  disable-transitions
+              >
+                {{ scope.row.enabled ? "开启" : "关闭" }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column
+              show-overflow-tooltip
+              align="center"
+              width="150"
+              prop="dateUpdated"
+              label="更新时间"
+          />
+          <el-table-column
+              fixed="right"
+              align="center"
+              label="操作"
+              width="180"
+          >
+            <template #default="scope">
+              <!-- <el-button
+                v-hasPermi="['service:info:update']"
+                @click="handleEditRule(scope.row)"
+                size="mini"
+              >
+                编辑
+              </el-button> -->
+              <el-button
+                  type="danger"
+                  @click="handleDeleteRule(scope.row)"
+                  v-hasPermi="['service:info:delete']"
+                  size="mini"
+              >
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+            v-show="ruleDataTotal > 0"
+            :total="ruleDataTotal"
+            :page.sync="ruleParam.currentPage"
+            :limit.sync="ruleParam.pageSize"
+            @pagination="getRuleList"
+        />
+      </el-col>
+    </el-row>
+    <el-dialog :visible.sync="selectorVisible" title="选择器">
+      <el-form ref="selectorForm" :model="selectorForm">
+        <el-form-item label="名称">
+          <el-input v-model="selectorForm.name"></el-input>
+        </el-form-item>
+        <el-form-item label="类型">
+          <el-select v-model="selectorForm.type" placeholder="类型">
+            <el-option label="全流量" value="0"></el-option>
+            <el-option label="自定义" value="1"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item v-if="selectorForm.type == '1'" label="类型">
+          <el-select v-model="selectorForm.matchMode" placeholder="类型">
+            <el-option
+                v-for="matchMode in matchModes"
+                :key="matchMode.id"
+                :value="matchMode.dictValue"
+            >{{ matchMode.dictName }}
+            </el-option
+            >
+          </el-select>
+        </el-form-item>
+        <el-row :gutter="5">
+          <el-col :span="7">
+            <el-form-item label="继续后续选择器:">
+              <el-switch v-model="selectorForm.continued"></el-switch>
+            </el-form-item>
+          </el-col>
+          <el-col :span="7">
+            <el-form-item label="打印日志:">
+              <el-switch v-model="selectorForm.loged"></el-switch>
+            </el-form-item>
+          </el-col>
+          <el-col :span="7">
+            <el-form-item label="是否开启:">
+              <el-switch v-model="selectorForm.enabled"></el-switch>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="处理">
+          <el-row :gutter="5">
+            <el-col
+                :span="6"
+                v-for="handler in pluginHandles"
+                :key="handler.id"
+            >
+              <el-input v-model="selectorForm[handler.field]">
+                <template slot="prepend">{{ handler.label }}</template>
+              </el-input>
+            </el-col>
+          </el-row>
+        </el-form-item>
+        <el-form-item label="执行顺序">
+          <el-input v-model="selectorForm.sort"></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="selectorVisible = true">
+            确认
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <el-dialog :visible.sync="ruleVisible" title="选择器规则">
+      <!-- @close="closeDialog" -->
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import "@/assets/styles/common.scss";
+import {
+  deleteRule,
+  deleteSelector,
+  getMatchModeList,
+  getOperatorList,
+  getParamTypeList,
+  getPluginHandleList,
+  getRuleList,
+  getSelectorList,
+  getShenyuToken,
+  syncProxyData,
+} from "@/api/gateway/proxy.js";
+
+export default {
+  name: "proxy",
+  data() {
+    return {
+      token: undefined,
+      selectorVisible: false,
+      ruleVisible: false,
+      currentRow: undefined,
+      tableHeight: window.innerHeight - 300,
+      selectorData: [],
+      selectorDataTotal: 0,
+      selectorParam: {
+        currentPage: 1,
+        pageSize: 20,
+        pluginId: 5,
+        name: "",
+      },
+      ruleData: [],
+      ruleDataTotal: 0,
+      ruleParam: {
+        currentPage: 1,
+        pageSize: 20,
+        pluginId: 5,
+        name: "",
+        selectorId: "",
+      },
+      selectorForm: {},
+      ruleForm: {},
+
+      operators: undefined,
+      matchModes: undefined,
+      paramTypes: undefined,
+      pluginHandles: undefined,
+    };
+  },
+  mounted() {
+    getShenyuToken().then((r) => {
+      this.token = r.data.token;
+      this.getSelectorList();
+      this.getBaseData();
+    });
+  },
+  methods: {
+    // 获取选择器列表
+    getSelectorList() {
+      getSelectorList(this.selectorParam, this.token).then((r) => {
+        this.selectorData = r.data.dataList;
+        this.selectorDataTotal = r.data.page.totalCount;
+        this.setCurrent(this.selectorData[0]);
+      });
+    },
+    // 获取选择器规则列表
+    getRuleList() {
+      this.ruleParam.selectorId = this.currentRow.id;
+      getRuleList(this.ruleParam, this.token).then((r) => {
+        this.ruleData = r.data.dataList;
+        this.ruleDataTotal = r.data.page.totalCount;
+      });
+    },
+    // 同步信息
+    syncProxyData() {
+      syncProxyData(this.token).then((r) => {
+        this.$modal.msgSuccess("同步成功");
+      });
+    },
+    // 设置当前行
+    setCurrent(row) {
+      this.$refs.selectorTable.setCurrentRow(row);
+    },
+    // 选中执行操作
+    handleCurrentChange(val) {
+      this.currentRow = val;
+      this.getRuleList();
+    },
+    // 编辑选择器
+    handleEditSelector(selector) {
+    },
+    // 编辑选择器规则
+    handleEditRule(rule) {
+    },
+    // 删除选择器
+    handleDeleteSelector(selector) {
+      this.$modal
+          .confirm('是否确认删除选择器 "' + selector.name + '" ?')
+          .then(() => deleteSelector([selector.id], this.token))
+          .then(() => {
+            this.getSelectorList();
+            this.$modal.msgSuccess("删除成功");
+          })
+          .catch(() => {
+          });
+    },
+    // 删除选择器规则
+    handleDeleteRule(rule) {
+      this.$modal
+          .confirm('是否确认删除选择器 "' + rule.name + '" ?')
+          .then(() => deleteRule([rule.id], this.token))
+          .then(() => {
+            this.getRuleList();
+            this.$modal.msgSuccess("删除成功");
+          })
+          .catch(() => {
+          });
+    },
+    getBaseData() {
+      getOperatorList(this.token).then((r) => {
+        this.operators = r.data;
+      });
+      getMatchModeList(this.token).then((r) => {
+        this.matchModes = r.data;
+      });
+      getParamTypeList(this.token).then((r) => {
+        this.paramTypes = r.data;
+      });
+      getPluginHandleList(this.token).then((r) => {
+        this.pluginHandles = r.data;
+      });
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-table {
+  border: 1px solid #e6e6e6;
+  border-right: 1px solid #e6e6e6;
+  border-bottom: none;
+  border-radius: 5px;
+}
+
+::v-deep .el-dialog {
+  position: relative;
+  background: #ffffff;
+  border-radius: 2px;
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+::v-deep .el-dialog__body {
+  // border-top: 1px solid #dcdfe6;
+  overflow-y: auto;
+
+  &::-webkit-scrollbar {
+    width: 2px;
+    background-color: #ccc;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #0ae;
+  }
+
+  &::-webkit-scrollbar-track {
+    background-color: #ccc;
+  }
+}
+</style>