浏览代码

Merge branch 'master' into feature-flow

chen.cheng 2 月之前
父节点
当前提交
8af3024270

+ 44 - 0
src/api/system/tenant.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询租户列表
+export function listTenant(query) {
+  return request({
+    url: '/system/tenant/list?pageSize=9999',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询租户详细
+export function getTenant(id) {
+  return request({
+    url: '/system/tenant/' + id,
+    method: 'get'
+  })
+}
+
+// 新增租户
+export function addTenant(data) {
+  return request({
+    url: '/system/tenant',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改租户
+export function updateTenant(data) {
+  return request({
+    url: '/system/tenant',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除租户
+export function delTenant(id) {
+  return request({
+    url: '/system/tenant/' + id,
+    method: 'delete'
+  })
+}

二进制
src/assets/images/login-background.png


+ 37 - 0
src/components/map/GeoJson.js

@@ -0,0 +1,37 @@
+import {uuid} from "@/utils";
+
+export const Circle = ({radius, coordinates, symbol = []}) => {
+  const uuidstr = uuid();
+  const [
+    line = {
+      lineColor: "#FF0000",
+      lineWidth: 3,
+      polygonOpacity: 0.4,
+      polygonFill: "#DCE372"
+    },
+    text = {
+      // textName: "geom2",
+      // textFill: "#FF0000",
+      // textSize: 20
+    }
+  ] = symbol;
+  return {
+    name: uuidstr,
+    geojson: {
+      feature: {
+        type: "Feature",
+        geometry: {"type": "Polygon"},
+        id: uuidstr,
+        properties: {"name": "geom2"}
+      },
+      subType: "Circle",
+      coordinates: coordinates,
+      radius: radius,
+      options: {},
+      symbol: [
+        line,
+        text
+      ]
+    }
+  }
+}

+ 5 - 1
src/components/map/index.vue

@@ -18,13 +18,17 @@ export default {
       default: () => {
       },
     },
+    center: {
+      type: Array,
+      default: () => [121.9580475686964, 30.949993496740227]
+    },
   },
   mounted() {
     this.$nextTick(() => {
       const options = {
         mapType: BDLayers.Lib.Constant.BaseLayerType.Blank,
         mapModel: BDLayers.Lib.Constant.BaseLayerModel.Satellite,
-        center: [104.03533, 1.38137],
+        center: this.center,
         defaultZoom: 20,
         showCenter: true,
         baseControl: false,

+ 2 - 2
src/components/map/maphandle.js

@@ -69,7 +69,7 @@ export default {
       }
       return [];
     },
-    createLayer(mapIns) {
+    createLayer(mapIns, zIndex = 1) {
       const uid = uuid();
       const layerId = `poly_layer${uid}`;
       const polyLayer = new BDLayers.Lib.Layer.CBVectorLayer(
@@ -81,7 +81,7 @@ export default {
           mapIns.removeLayersById(layerId);
         }
       }
-      mapIns.addCustomLayers(polyLayer, 1);
+      mapIns.addCustomLayers(polyLayer, zIndex);
       return polyLayer;
     },
     clearLayer(layer) {

+ 0 - 1
src/directive/permission/hasRole.js

@@ -13,7 +13,6 @@ export default {
 
     if (value && value instanceof Array && value.length > 0) {
       const roleFlag = value
-
       const hasRole = roles.some(role => {
         return super_admin === role || roleFlag.includes(role)
       })

+ 2 - 0
src/i18n/en.js

@@ -80,6 +80,7 @@ export default {
     "1107": "Process Definition",
     "1118": "Pending Tasks",
     "1122": "Completed Tasks",
+    "1125": "Tenant Management",
     "2006": "CC Tasks",
     "2007": "Inspection Items",
     "2013": "Patrol Management",
@@ -156,6 +157,7 @@ export default {
     "desDepth": "Design Depth",
     "actualDepth": "Actual Depth",
     "pullValue": "Pull",
+    pushValue: "Push",
     "pressure": "Pressure",
     "consStartTime": "Start Time",
     "consEndTime": "End Time",

+ 3 - 0
src/i18n/zh.js

@@ -98,6 +98,7 @@ export default {
     "1107": "流程定义",
     "1118": "待办任务",
     "1122": "已办任务",
+    "1125": "租户",
     "2006": "抄送任务",
     "2007": "巡检项",
     "2013": "巡防管理",
@@ -120,6 +121,7 @@ export default {
     "2095": "工程坐标配置",
     "2101": "施工单元",
     "2102": "施工大屏",
+
   },
   error: {
     401: "认证失败,无法访问系统资源",
@@ -174,6 +176,7 @@ export default {
     "desDepth": "设计深度",
     "actualDepth": "实际深度",
     "pullValue": "回带量",
+    "pushValue": "送带量",
     "pressure": "灌入压力",
     "consStartTime": "施工开始时间",
     "consEndTime": "施工结束时间",

+ 1 - 1
src/layout/components/Navbar.vue

@@ -87,7 +87,7 @@ export default {
       this.$store.dispatch('app/toggleSideBar')
     },
     async logout() {
-      this.$confirm(this.$t("logoutTips"), '提示', {
+      this.$confirm(this.$t("sysSetting.logoutTips"), this.$t("common.tip"), {
         confirmButtonText: this.$t("common.confirm"),
         cancelButtonText: this.$t("common.cancel"),
         type: 'warning'

+ 89 - 44
src/layout/components/Sidebar/index.vue

@@ -1,57 +1,102 @@
 <template>
-    <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
-        <logo v-if="showLogo" :collapse="isCollapse" />
-        <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
-            <el-menu
-                :default-active="activeMenu"
-                :collapse="isCollapse"
-                :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
-                :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
-                :unique-opened="true"
-                :active-text-color="settings.theme"
-                :collapse-transition="false"
-                mode="vertical"
-            >
-                <sidebar-item
-                    v-for="(route, index) in sidebarRouters"
-                    :key="route.path  + index"
-                    :item="route"
-                    :base-path="route.path"
-                />
-            </el-menu>
-        </el-scrollbar>
+  <div :class="{'has-logo':showLogo}"
+       :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
+    <logo v-if="showLogo" :collapse="isCollapse"/>
+    <div style="position: relative">
+      <el-select
+        :style="{
+        position: 'relative',
+        left: '50%',
+        top: '50%',
+        transform: 'translate(-50%, -50%)'
+      }"
+        v-model="tenantId" placeholder="请选择租户"
+        v-has-role="['admin']"
+      >
+        <el-option
+          v-for="item in tenantList"
+          :key="item.id"
+          :label="item.tenantName"
+          :value="item.id"
+        ></el-option>
+      </el-select>
     </div>
+
+    <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
+      <el-menu
+        :default-active="activeMenu"
+        :collapse="isCollapse"
+        :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
+        :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
+        :unique-opened="true"
+        :active-text-color="settings.theme"
+        :collapse-transition="false"
+        mode="vertical"
+      >
+        <sidebar-item
+          v-for="(route, index) in sidebarRouters"
+          :key="route.path  + index"
+          :item="route"
+          :base-path="route.path"
+        />
+      </el-menu>
+    </el-scrollbar>
+  </div>
 </template>
 
 <script>
-import { mapGetters, mapState } from "vuex";
+import {mapGetters, mapState} from "vuex";
 import Logo from "./Logo";
 import SidebarItem from "./SidebarItem";
 import variables from "@/assets/styles/variables.scss";
+import {listTenant} from "@/api/system/tenant";
 
 export default {
-    components: { SidebarItem, Logo },
-    computed: {
-        ...mapState(["settings"]),
-        ...mapGetters(["sidebarRouters", "sidebar"]),
-        activeMenu() {
-            const route = this.$route;
-            const { meta, path } = route;
-            // if set path, the sidebar will highlight the path you set
-            if (meta.activeMenu) {
-                return meta.activeMenu;
-            }
-            return path;
-        },
-        showLogo() {
-            return this.$store.state.settings.sidebarLogo;
-        },
-        variables() {
-            return variables;
-        },
-        isCollapse() {
-            return !this.sidebar.opened;
-        }
+  components: {SidebarItem, Logo},
+  computed: {
+    ...mapState(["settings"]),
+    ...mapGetters(["sidebarRouters", "sidebar"]),
+    activeMenu() {
+      const route = this.$route;
+      const {meta, path} = route;
+      // if set path, the sidebar will highlight the path you set
+      if (meta.activeMenu) {
+        return meta.activeMenu;
+      }
+      return path;
+    },
+    showLogo() {
+      return this.$store.state.settings.sidebarLogo;
+    },
+    variables() {
+      return variables;
+    },
+    isCollapse() {
+      return !this.sidebar.opened;
+    }
+  },
+  watch: {
+    tenantId(val) {
+      this.$store.dispatch("setTenant", val)
+      // 刷新页面
+      window.location.reload()
+    }
+  },
+  data() {
+    return {
+      tenantId: this.$store.getters.tenant,
+      tenantList: []
     }
+  },
+  created() {
+    this.getTenantList();
+  },
+  methods: {
+    getTenantList() {
+      listTenant().then(response => {
+        this.tenantList = response.rows
+      })
+    },
+  }
 };
 </script>

+ 4 - 3
src/store/getters.js

@@ -8,12 +8,13 @@ const getters = {
   token: state => state.user.token,
   avatar: state => state.user.avatar,
   name: state => state.user.name,
+  tenant: state => state.user.tenant,
   introduction: state => state.user.introduction,
   roles: state => state.user.roles,
   permissions: state => state.user.permissions,
   permission_routes: state => state.permission.routes,
-  topbarRouters:state => state.permission.topbarRouters,
-  defaultRoutes:state => state.permission.defaultRoutes,
-  sidebarRouters:state => state.permission.sidebarRouters,
+  topbarRouters: state => state.permission.topbarRouters,
+  defaultRoutes: state => state.permission.defaultRoutes,
+  sidebarRouters: state => state.permission.sidebarRouters,
 }
 export default getters

+ 29 - 8
src/store/modules/user.js

@@ -1,5 +1,6 @@
-import { login, logout, getInfo } from '@/api/login'
-import { getToken, setToken, removeToken } from '@/utils/auth'
+import {getInfo, login, logout} from '@/api/login'
+import {getTenant, getToken, removeToken, setTenant as setTenantCookie, setToken} from '@/utils/auth'
+import {listTenant} from "@/api/system/tenant";
 
 const user = {
   state: {
@@ -8,7 +9,8 @@ const user = {
     name: '',
     avatar: '',
     roles: [],
-    permissions: []
+    permissions: [],
+    tenant: getTenant()
   },
 
   mutations: {
@@ -29,12 +31,16 @@ const user = {
     },
     SET_PERMISSIONS: (state, permissions) => {
       state.permissions = permissions
+    },
+    SET_TENANT: (state, tenant) => {
+      state.tenant = tenant
+      setTenantCookie(tenant)
     }
   },
 
   actions: {
     // 登录
-    Login({ commit }, userInfo) {
+    Login({commit}, userInfo) {
       const username = userInfo.username.trim()
       const password = userInfo.password
       const code = userInfo.code
@@ -44,15 +50,25 @@ const user = {
           setToken(res.token)
           commit('SET_TOKEN', res.token)
           resolve()
+
         }).catch(error => {
           reject(error)
         })
       })
     },
 
+    setTenant({commit}, tenant) {
+      commit('SET_TENANT', tenant)
+    },
+
     // 获取用户信息
-    GetInfo({ commit, state }) {
-      return new Promise((resolve, reject) => {
+    GetInfo({commit, state}) {
+      return new Promise(async (resolve, reject) => {
+        let defaultTenant;
+        const {rows} = await listTenant()
+        if (rows.length > 0) {
+          defaultTenant = state.tenant || rows[0].id
+        }
         getInfo().then(res => {
           const user = res.user
           const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
@@ -65,6 +81,10 @@ const user = {
           commit('SET_ID', user.userId)
           commit('SET_NAME', user.userName)
           commit('SET_AVATAR', avatar)
+          if (user.tenantId) {
+            defaultTenant = user.tenantId
+          }
+          commit('SET_TENANT', defaultTenant)
           resolve(res)
         }).catch(error => {
           reject(error)
@@ -73,12 +93,13 @@ const user = {
     },
 
     // 退出系统
-    LogOut({ commit, state }) {
+    LogOut({commit, state}) {
       return new Promise((resolve, reject) => {
         logout(state.token).then(() => {
           commit('SET_TOKEN', '')
           commit('SET_ROLES', [])
           commit('SET_PERMISSIONS', [])
+          commit('SET_TENANT', '')
           removeToken()
           resolve()
         }).catch(error => {
@@ -88,7 +109,7 @@ const user = {
     },
 
     // 前端 登出
-    FedLogOut({ commit }) {
+    FedLogOut({commit}) {
       return new Promise(resolve => {
         commit('SET_TOKEN', '')
         removeToken()

+ 58 - 0
src/utils/ComponentHandle.js

@@ -0,0 +1,58 @@
+import store from '@/store';
+import Vue from 'vue';
+import i18n from "@/i18n";
+
+/**
+ * 组件处理对象,用于创建和管理Vue组件。
+ */
+const ComponentHandle = {
+  /**
+   * 创建一个组件实例。
+   *
+   * @param {Object} options 组件配置对象。
+   * @param {string} options.wrapper 组件挂载的DOM元素ID,默认为'left-side-window-ins'。
+   * @param {Object} options.component 要创建的组件对象。
+   * @param {Object} options.props 组件的props配置。
+   * @param {Function} options.onclose 组件关闭时的回调函数,默认为空函数。
+   * @returns {Object} 返回创建的组件实例。
+   */
+  createComponent({
+                    wrapper = 'left-side-window-ins',
+                    component,
+                    props,
+                    onclose = () => {
+                      console.log('ComponentHandle onclose');
+                    },
+                  }) {
+    let comp;
+    // 自定义弹出窗口组件
+    //自定义弹框
+    let Content = Vue.extend({
+      // 自定义模板
+      //自定义模板继承
+      template: `
+        <base-info class='window-content' :propData='nameExtend'
+                   :close='close'></base-info>`,
+      name: 'child',
+      components: {
+        'base-info': component, // 引用传入的组件作为子组件
+      },
+      data() {
+        return {
+          nameExtend: props, // 传递props数据给子组件
+        };
+      },
+      methods: {
+        close(params) {
+          onclose && onclose(params); // 调用关闭回调函数
+        },
+      },
+    });
+    // 获取挂载容器并创建组件实例
+    const div = document.getElementById(wrapper);
+    comp = new Content({store, i18n}).$mount();
+    div.appendChild(comp.$el);
+    return comp;
+  },
+};
+export default ComponentHandle;

+ 44 - 0
src/utils/EnumConst.js

@@ -1,3 +1,5 @@
+import i18n from "@/i18n";
+
 export const MachineStatus = {
   "00": {
     label: "online",
@@ -18,3 +20,45 @@ export const MachineStatus = {
     code: "01"
   }
 }
+
+export const NodeType = {
+  desFile: {
+    label: "desFile",
+    color: "#5cb85c",
+    code: 2
+  }
+}
+export const PileHoleStatus = {
+  DIC: {
+    NotStated: {
+      color: '#C1C1C1',
+      name: i18n.t("screen.notStart")
+    },
+    InProcess: {
+      color: '#FF5454',
+      name: i18n.t("screen.inProcess")
+    },
+    Completed: {
+      color: '#93D467',
+      name: i18n.t("screen.completed")
+    },
+    Deviation: {
+      color: '#F6E65C',
+      name: i18n.t("screen.deviation")
+    }
+  },
+  codeToStatus: function (code) {
+    switch (code) {
+      case "00":
+        return this.DIC.Completed;
+      case "01":
+        return this.DIC.NotStated;
+      case "02":
+        return this.DIC.InProcess;
+      case "03":
+        return tthis.DIC.Deviation;
+      default:
+        return this.DIC.NotStated;
+    }
+  },
+}

+ 9 - 0
src/utils/auth.js

@@ -1,6 +1,7 @@
 import Cookies from 'js-cookie'
 
 const TokenKey = 'Admin-Token'
+const tenantKey = 'X-Tenant'
 
 export function getToken() {
   return Cookies.get(TokenKey)
@@ -13,3 +14,11 @@ export function setToken(token) {
 export function removeToken() {
   return Cookies.remove(TokenKey)
 }
+
+export function getTenant() {
+  return Cookies.get(tenantKey)
+}
+
+export function setTenant(tenant) {
+  return Cookies.set(tenantKey, tenant)
+}

+ 1 - 0
src/utils/request.js

@@ -48,6 +48,7 @@ service.interceptors.request.use(config => {
     config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
   }
   config.headers['lang'] = sysLanguage()
+  config.headers['X-Tenant'] = store.getters.tenant || '';
   // get请求映射params参数
   if (config.method === 'get' && config.params) {
     let url = config.url + '?' + tansParams(config.params);

+ 118 - 104
src/views/cons/consUnit/index.vue

@@ -3,12 +3,12 @@
     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
       <el-form-item :label="$t('cons.unitName')" prop="name">
         <el-input
-            v-model="queryParams.name"
-            :placeholder="$t('common.typeInfo',{
+          v-model="queryParams.name"
+          :placeholder="$t('common.typeInfo',{
             name: $t('cons.unitName')
           })"
-            clearable
-            @keyup.enter.native="handleQuery"
+          clearable
+          @keyup.enter.native="handleQuery"
         />
       </el-form-item>
       <el-form-item>
@@ -23,23 +23,23 @@
     <el-row :gutter="10" class="mb8">
       <el-col :span="1.5">
         <el-button
-            type="primary"
-            plain
-            icon="el-icon-plus"
-            size="mini"
-            @click="handleAdd"
-            v-hasPermi="['cons:consUnitInfo:add']"
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['cons:consUnitInfo:add']"
         >
           {{ $t('common.add') }}
         </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button
-            type="info"
-            plain
-            icon="el-icon-sort"
-            size="mini"
-            @click="toggleExpandAll"
+          type="info"
+          plain
+          icon="el-icon-sort"
+          size="mini"
+          @click="toggleExpandAll"
         >
           {{ $t('common.expand_collapse') }}
         </el-button>
@@ -48,12 +48,12 @@
     </el-row>
 
     <el-table
-        v-if="refreshTable"
-        v-loading="loading"
-        :data="consUnitInfoList"
-        row-key="id"
-        :default-expand-all="isExpandAll"
-        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+      v-if="refreshTable"
+      v-loading="loading"
+      :data="consUnitInfoList"
+      row-key="id"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
     >
       <el-table-column :label="$t('cons.unitName')" width="200" prop="name"/>
       <el-table-column :label="$t('cons.nodeType')" prop="type">
@@ -61,7 +61,11 @@
           <dict-tag :options="dict.type.cons_unit_type" :value="scope.row.type"/>
         </template>
       </el-table-column>
-      <el-table-column :label="$t('cons.designFileType')" prop="classifyType"/>
+      <el-table-column :label="$t('cons.designFileType')" prop="classifyType">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.classify_type" :value="scope.row.classifyType"/>
+        </template>
+      </el-table-column>
       <el-table-column :label="$t('common.updateTime')" align="center" prop="updateTime" width="200">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.updateTime) }}</span>
@@ -76,34 +80,34 @@
       <el-table-column :label="$t('common.operation')" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
-              size="mini"
-              type="text"
-              icon="el-icon-edit"
-              @click="handleUpdate(scope.row)"
-              v-hasPermi="['cons:consUnitInfo:edit']"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:edit']"
           >
             {{
               $t('common.edit')
             }}
           </el-button>
           <el-button
-              size="mini"
-              type="text"
-              icon="el-icon-plus"
-              @click="handleAdd(scope.row)"
-              v-hasPermi="['cons:consUnitInfo:add']"
+            size="mini"
+            type="text"
+            icon="el-icon-plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:add']"
           >
             {{
               $t('common.add')
             }}
           </el-button>
           <el-button
-              v-if="scope.row.parentId != 0"
-              size="mini"
-              type="text"
-              icon="el-icon-delete"
-              @click="handleDelete(scope.row)"
-              v-hasPermi="['cons:consUnitInfo:remove']"
+            v-if="scope.row.parentId != 0"
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:remove']"
           >
             {{
               $t('common.delete')
@@ -111,46 +115,48 @@
           </el-button>
           <br/>
           <el-button
-              v-if="scope.row.type==='2'"
-              size="mini"
-              type="text"
-              icon="el-icon-upload"
-              @click="handleImport(scope.row)"
-              v-hasPermi="['cons:consUnitInfo:edit']"
+            v-if="scope.row.type==='2'"
+            size="mini"
+            type="text"
+            icon="el-icon-upload"
+            @click="handleImport(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:editCAD']"
           >
             {{
               $t('cons.uploadCAD')
             }}
           </el-button>
           <el-button
-              v-if="scope.row.type==='2'"
-              size="mini"
-              type="text"
-              icon="el-icon-set-up"
-              @click="handleAssign(scope.row)"
-              v-hasPermi="['cons:consUnitInfo:edit']"
+            v-if="scope.row.type==='2'"
+            size="mini"
+            type="text"
+            icon="el-icon-set-up"
+            @click="handleAssign(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:assignMachine']"
           >
             {{
               $t('cons.assignMachine')
             }}
           </el-button>
           <el-button
-              v-if="scope.row.type==='2'"
-              size="mini"
-              type="text"
-              icon="el-icon-download"
-              @click="handleExport(scope.row)"
+            v-if="scope.row.type==='2'"
+            size="mini"
+            type="text"
+            icon="el-icon-download"
+            @click="handleExport(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:downloadCAD']"
           >
             {{
               $t('cons.downloadFinishDrawing')
             }}
           </el-button>
           <el-button
-              v-if="scope.row.type==='2'"
-              size="mini"
-              type="text"
-              icon="el-icon-download"
-              @click="handleExportCsv(scope.row)"
+            v-if="scope.row.type==='2'"
+            size="mini"
+            type="text"
+            icon="el-icon-download"
+            @click="handleExportCsv(scope.row)"
+            v-hasPermi="['cons:consUnitInfo:downloadCSV']"
           >
             {{
               $t('cons.downloadPileData')
@@ -177,8 +183,8 @@
           <el-col :span="12">
             <el-form-item :label="$t('cons.unitName')" prop="name">
               <el-input
-                  v-model="form.name"
-                  :placeholder="$t('common.typeInfo',{
+                v-model="form.name"
+                :placeholder="$t('common.typeInfo',{
                             name: $t('cons.unitName')
                           })"
               />
@@ -200,49 +206,49 @@
           <!--          </el-col>-->
           <el-col :span="12">
             <el-form-item :label="$t('cons.nodeType')" prop="type">
-              <el-select v-model="form.type" :placeholder="$t('common.select',{
+              <el-select
+                v-model="form.type"
+                :placeholder="$t('common.select',{
                             name: $t('cons.nodeType')
                           })">
                 <el-option
-                    v-for="dict in dict.type.cons_unit_type"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.value"
+                  v-for="dict in dict.type.cons_unit_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
                 ></el-option>
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
+          <el-col :span="12" v-if="form.type == NodeType.desFile.code">
             <el-form-item :label="$t('cons.designFileType')" prop="classifyType">
-              <el-input
-                  v-model="form.classifyType"
-                  :placeholder="$t('common.typeInfo',{
+              <el-select
+                v-model="form.classifyType"
+                :placeholder="$t('common.select',{
                             name: $t('cons.designFileType')
                           })"
-              />
+                clearable
+              >
+                <el-option
+                  v-for="dict in dict.type.classify_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
             </el-form-item>
           </el-col>
         </el-row>
-        <!--        <el-row>-->
-        <!--          <el-col :span="12">-->
-        <!--            <el-form-item label="设计文件类型" prop="classifyType">-->
-        <!--              <el-input v-model="form.classifyType" placeholder="请输入设计文件类型"/>-->
-        <!--            </el-form-item>-->
-        <!--          </el-col>-->
-        <!--          <el-col :span="12">-->
-
-        <!--          </el-col>-->
-        <!--        </el-row>-->
         <el-row>
-          <el-col :span="24">
+          <el-col :span="24" v-if="form.type == NodeType.desFile.code">
             <el-form-item :label="$t('cons.machine')" prop="toMachineId">
               <el-select style="width: 100%" v-model="form.machineId" multiple
                          :placeholder="$t('common.select',{name:$t('cons.machine')})">
                 <el-option
-                    v-for="machine in machineList"
-                    :key="machine.id"
-                    :label="`${machine.machineNum}(${machine.name})`"
-                    :value="machine.id"
+                  v-for="machine in machineList"
+                  :key="machine.id"
+                  :label="`${machine.machineNum}(${machine.name})`"
+                  :value="machine.id"
                 ></el-option>
               </el-select>
             </el-form-item>
@@ -256,17 +262,17 @@
     </el-dialog>
     <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
       <el-upload
-          ref="upload"
-          :limit="1"
-          name="files"
-          accept=".dwg,.xls,.xlsx"
-          :headers="upload.headers"
-          :action="upload.url + '?updateSupport=' + upload.updateSupport"
-          :disabled="upload.isUploading"
-          :on-progress="handleFileUploadProgress"
-          :on-success="handleFileSuccess"
-          :auto-upload="false"
-          drag
+        ref="upload"
+        :limit="1"
+        name="files"
+        accept=".dwg,.xls,.xlsx"
+        :headers="upload.headers"
+        :action="upload.url + '?updateSupport=' + upload.updateSupport"
+        :disabled="upload.isUploading"
+        :on-progress="handleFileUploadProgress"
+        :on-success="handleFileSuccess"
+        :auto-upload="false"
+        drag
       >
         <i class="el-icon-upload"></i>
         <div class="el-upload__text">{{ $t("common.importModeMsg") }}</div>
@@ -298,10 +304,10 @@
               <el-select style="width: 100%" v-model="form.machineId" multiple
                          :placeholder="$t('common.select',{name:$t('cons.machine')})">
                 <el-option
-                    v-for="machine in machineList"
-                    :key="machine.id"
-                    :label="`${machine.machineNum}(${machine.name})`"
-                    :value="machine.id"
+                  v-for="machine in machineList"
+                  :key="machine.id"
+                  :label="`${machine.machineNum}(${machine.name})`"
+                  :value="machine.id"
                 ></el-option>
               </el-select>
             </el-form-item>
@@ -331,10 +337,16 @@ import {
 } from "@/api/cons/consUnitInfo";
 import {listAllPileMachineInfo} from "@/api/cons/pileMachineInfo";
 import {getToken} from "@/utils/auth";
+import {NodeType} from "@/utils/EnumConst";
 
 export default {
   name: "cons-unit",
-  dicts: ['cons_unit_type'],
+  computed: {
+    NodeType() {
+      return NodeType
+    }
+  },
+  dicts: ['cons_unit_type', 'classify_type'],
   components: {Treeselect},
   data() {
     return {
@@ -481,7 +493,7 @@ export default {
         type: "0",
         parentId: null,
         createType: 1,
-        classifyType: "dwg",
+        classifyType: null,
         name: null,
       };
       this.resetForm("form");
@@ -520,6 +532,8 @@ export default {
       this.reset();
       getConsUnitInfo(row.id).then(response => {
         this.form = response.data;
+        const {classifyType} = response.data;
+        this.form.classifyType = classifyType && classifyType + '';
         this.open = true;
         this.title = this.$t("common.modifyDialog", {name: this.$t("cons.consUnit")});
         listAllConsUnitExcludeChild(row.id).then(response => {

+ 1 - 1
src/views/cons/pileHoleInfo/index.vue

@@ -390,7 +390,7 @@ export default {
         if (valid) {
           if (this.form.id != null) {
             updatePileHoleInfo(this.form).then(response => {
-              this.$modal.msgSuccess(this.$t("tips.deletedSuccess"));
+              this.$modal.msgSuccess(this.$t("tips.modifySuccess"));
               this.open = false;
               this.getList();
             });

+ 47 - 17
src/views/cons/screen/PileHoleDetail.vue

@@ -1,15 +1,11 @@
 <template>
-  <el-dialog
-      class="screen-dialog"
-      :title="$t('screen.pileHoleIndex')"
-      :visible.sync="open"
-      :modal="false"
-      append-to-body
-      :destroy-on-close="true"
-      :before-close="closeDialog"
-  >
+  <div class="screen-dialog">
+    <div class="dialog-header">
+      {{ $t('screen.pileHoleIndex') }}
+      <i class="el-icon-close" @click="closeDialog" style="margin-left: auto;cursor: pointer"/>
+    </div>
     <div class="dialog-content">
-      <el-descriptions :column="2">
+      <el-descriptions :column="2" :colon="false">
         <el-descriptions-item :label="$t('screen.pileNumber')">
           {{
             realtimeIndex.holeNum
@@ -42,14 +38,22 @@
             realtimeIndex.sprayPressure
           }}
         </el-descriptions-item>
+        <el-descriptions-item :label="`${$t('screen.pushValue')} (m)`">
+          {{
+            realtimeIndex.sendSprayVolume
+          }}
+        </el-descriptions-item>
+        <el-descriptions-item :colon="false">
+
+        </el-descriptions-item>
         <el-descriptions-item :label="$t('screen.consStartTime')">
           {{
-            realtimeIndex.startTime || '--'
+            realtimeIndex.indexStartTime || '--'
           }}
         </el-descriptions-item>
         <el-descriptions-item :label="$t('screen.consEndTime')">
           {{
-            realtimeIndex.endTime || '--'
+            realtimeIndex.indexEndTime || '--'
           }}
         </el-descriptions-item>
       </el-descriptions>
@@ -62,7 +66,7 @@
         </div>
       </div>
     </div>
-  </el-dialog>
+  </div>
 </template>
 
 <script>
@@ -71,13 +75,25 @@ import {listPileHoleHisIndex, pileHoleRealtimeIndex} from "@/api/cons/pileHoleIn
 
 export default {
   components: {LineChartBlock},
-  props: {},
+  props: {
+    propData: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    close: {
+      type: Function,
+      default: () => {
+      }
+    },
+  },
   dicts: ['pile_hole_status'],
   data() {
     return {
-      open: false,
       loaded: false,
       realtimeIndex: {},
+      timer: null,
       lineOpt: {
         tooltip: {
           trigger: 'axis',
@@ -137,9 +153,18 @@ export default {
       }
     };
   },
+  created() {
+    this.showDialog(this.propData)
+    this.timer = setInterval(() => {
+      this.loaded = false
+      this.showDialog(this.propData)
+    }, 1000 * 30)
+  },
+  beforeDestroy() {
+    this.timer && clearInterval(this.timer)
+  },
   methods: {
     showDialog(pileHolleInfo) {
-      this.open = true
       pileHoleRealtimeIndex(pileHolleInfo.id).then(response => {
         this.realtimeIndex = response.data
       })
@@ -186,10 +211,15 @@ export default {
     },
 
     closeDialog() {
-      this.open = false
       this.loaded = false
+      this.close()
     },
   },
 };
 </script>
 <style lang="scss" src="./index.scss" scoped/>
+<style lang="scss">
+.maptalks-close {
+  display: none;
+}
+</style>

+ 15 - 12
src/views/cons/screen/index.scss

@@ -351,22 +351,25 @@
 
 
 .screen-dialog {
-  ::v-deep {
-    .el-dialog {
-      background: #02102C;
-      border: solid 2px rgba(49, 185, 253, 0.8);
-      box-sizing: border-box;
-      border-radius: 4px;
-      width: fit-content;
-    }
+  background: #02102C;
+  border: solid 2px rgba(49, 185, 253, 0.8);
+  box-sizing: border-box;
+  border-radius: 4px;
+  width: fit-content;
+  padding: 10px;
 
-    .el-dialog__header {
-      padding: 10px;
+  ::v-deep {
+    .dialog-header {
+      font-family: PingFangSC-Medium;
+      font-weight: 500;
+      height: 25px;
+      font-size: 13px;
+      letter-spacing: 1px;
+      color: #FFFFFF;
       display: flex;
-      justify-content: space-between;
+      justify-content: flex-start;
       align-items: center;
 
-
       .el-dialog__headerbtn {
         position: unset;
 

+ 139 - 51
src/views/cons/screen/index.vue

@@ -1,20 +1,23 @@
 <template>
   <div class="screen-container">
-    <bd-map :loaded="loaded"/>
+    <bd-map :center="[121.9580475686964, 30.949993496740227]" :loaded="loaded"/>
     <div class="screen-title-container"><span class="title-content">{{ $t("screen.title") }}</span></div>
     <content-block :title="$t('screen.consManage')" class="screen-left-container">
       <template v-slot:content>
         <div class="control-content">
           <div class="ctl-item">
-            <el-input :placeholder="$t('common.typeInfo',{name: $t('common.content')})" v-model="searchVal"
-                      class="input-with-select">
+            <el-input
+              :placeholder="$t('common.typeInfo',{name: $t('common.content')})"
+              v-model="searchVal"
+              class="input-with-select"
+            >
               <el-button slot="append" icon="el-icon-search"></el-button>
             </el-input>
           </div>
           <div class="ctl-item">
             <cons-unit-tree
-                :placeholder="$t('common.select', {name: $t('cons.consUnit')})"
-                v-model="consUnit"
+              :placeholder="$t('common.select', {name: $t('cons.consUnit')})"
+              v-model="consUnit"
             />
           </div>
         </div>
@@ -74,31 +77,30 @@
       <MachineIndex v-if="selectMachine" :select-machine="selectMachine">
         <template v-slot:title-right="scop">
           <el-tooltip
-              class="item"
-              effect="dark"
-              content="click to machine"
-              placement="top"
+            class="item"
+            effect="dark"
+            content="click to machine"
+            placement="top"
           >
             <svg-icon icon-class="location" @click="()=>{locationMachine(scop.data)}"/>
           </el-tooltip>
           <el-tooltip
-              class="item"
-              effect="dark"
-              content="close"
-              placement="top"
+            class="item"
+            effect="dark"
+            content="close"
+            placement="top"
           >
             <i class="el-icon-close" @click="()=>{locationClose()}" style="margin-left: 5px"/>
           </el-tooltip>
         </template>
       </MachineIndex>
       <div class="pile-status-legend">
-        <div class="legend-item" v-for="item in LegendItem">
+        <div class="legend-item" v-for="item in PileHoleStatus.DIC">
           <i :style="{ backgroundColor:item.color }"/>
           {{ item.name }}
         </div>
       </div>
     </div>
-    <PileHoleDetail ref="pileHoleDialog"/>
   </div>
 </template>
 
@@ -115,9 +117,12 @@ import maphandle from "@/components/map/maphandle";
 import MachineIndex from "@/views/cons/screen/MachineIndex.vue";
 import PileHoleDetail from "@/views/cons/screen/PileHoleDetail.vue";
 import {copyObj} from "@/utils";
+import {Circle} from "@/components/map/GeoJson";
 import pileMachine from "./img/pile-machine.svg"
-import {MachineStatus} from "@/utils/EnumConst";
+import {MachineStatus, PileHoleStatus} from "@/utils/EnumConst";
+import ComponentHandle from "@/utils/ComponentHandle"
 
+const gemoCache = {}
 export default {
   components: {
     PileHoleDetail,
@@ -135,8 +140,12 @@ export default {
       type: String,
       default: '',
     },
+
   },
   computed: {
+    PileHoleStatus() {
+      return PileHoleStatus
+    },
     MachineStatus() {
       return MachineStatus
     },
@@ -173,8 +182,10 @@ export default {
       machineLatextIndex: {},
       pileHoleList: [],
       pileHoleLayer: null,
+      geoms: [],
       machineStatusCnt: {},
       onlineMachine: [],
+      hisClickGeom: null,
       machineOpt: {
         color: ['#006699', '#4cabce'],
         tooltip: {
@@ -217,30 +228,15 @@ export default {
           },
         ],
       },
-      LegendItem: {
-        NotStated: {
-          color: '#C1C1C1',
-          name: this.$t("screen.notStart")
-        },
-        InProcess: {
-          color: '#FF5454',
-          name: this.$t("screen.inProcess")
-        },
-        Completed: {
-          color: '#93D467',
-          name: this.$t("screen.completed")
-        },
-        Deviation: {
-          color: '#F6E65C',
-          name: this.$t("screen.deviation")
-        }
-      }
+      timer: null,
+      layerOnLoad: false
     };
   },
   // 组件卸载前清空图层信息
   beforeDestroy() {
     this.destroyLayer(this.pileHoleLayer.cust.layerId, this.mapIns)
     this.destroyLayer(this.pileMachineLayer.cust.layerId, this.mapIns)
+    this.timer && clearInterval(this.timer)
   },
   created() {
 
@@ -273,6 +269,7 @@ export default {
       });
     },
     addMachineMarker() {
+      this.pileMachineLayer.removeAll()
       this.onlineMachine.forEach(item => {
         let marker = new BDLayers.Lib.Overlays.Marker(`marker${item.id}`, [item.lng, item.lat], {
           symbol: {
@@ -316,30 +313,124 @@ export default {
     loadPileHole() {
       listPileHoleRealtimeIndex({}).then(response => {
         this.pileHoleList = response.data
-        this.pileHoleList.forEach((item, index) => {
-          let circle = new BDLayers.Lib.Overlays.Circle(`circle${index}`, {
-            center: [item.lng, item.lat], // 圆的中心点点坐标
-            radius: 2,
-            symbol: {
+        this.calcPileHole(response.data)
+      })
+    },
+    addPileHoleToMap(holes) {
+      const geoms = []
+      holes.map((item, index) => {
+        const codeToStatus = PileHoleStatus.codeToStatus(item.consStatus);
+        const geom = new BDLayers.Lib.Overlays.FromGeoJson(Circle({
+          radius: 0.4,
+          coordinates: [item.lng, item.lat],
+          symbol: [
+            {
               lineColor: '#34495e',
               lineWidth: 1,
-              polygonFill: '#1bbc9b',
-              polygonOpacity: 0.2
-            },
+              polygonFill: codeToStatus.color,
+              polygonOpacity: 0.8
+            }
+          ]
+        }).geojson);
+
+        geom.cust = item
+        geom.on('click', (e) => {
+          if (this.hisClickGeom) {
+            this.hisClickGeom.updateSymbol([
+              {
+                lineColor: '#34495e',
+                lineWidth: 1,
+                polygonOpacity: 0.8
+              }
+            ])
+          }
+          this.hisClickGeom = geom
+          geom.updateSymbol([
+            {
+              lineColor: 'green',
+              lineWidth: 1,
+              polygonOpacity: 1
+            }
+          ])
+          const pileHoleInfo = e.target.cust
+          geom.setPopWindow({
+            autoPan: true,
+            content: `<div id='pop-window' class="window-content"></div>`
+          });
+          ComponentHandle.createComponent({
+            wrapper: 'pop-window',
+            component: PileHoleDetail,
+            props: pileHoleInfo,
+            onclose: () => {
+              if (this.hisClickGeom) {
+                this.hisClickGeom.updateSymbol([
+                  {
+                    lineColor: '#34495e',
+                    lineWidth: 1
+                  }
+                ])
+                this.hisClickGeom = null
+              }
+              geom.closePopWindow();
+            }
           });
-          circle.cust = item
-          circle.on('click', (e) => {
-            this.pileHoleClick(e.target.cust)
-          })
-          this.pileHoleLayer.addGeometry(circle);
         })
+        gemoCache[item.id].marker = geom
+        geoms.push(geom)
+      })
+      geoms.length && this.pileHoleLayer.addGeometries(geoms);
+      if (!this.layerOnLoad) {
+        this.layerOnLoad = true
+        this.mapIns.fitExtent(this.pileHoleLayer.getExtent());
+      }
+    },
+    updatePileHole(newList) {
+      newList.forEach(
+        item => {
+          if (gemoCache[item.id]) {
+            const codeToStatus = PileHoleStatus.codeToStatus(item.consStatus);
+            gemoCache[item.id].marker.updateSymbol([
+              {
+                lineColor: '#34495e',
+                lineWidth: 1,
+                polygonFill: codeToStatus.color,
+                polygonOpacity: 0.8
+              }
+            ])
+          }
+        }
+      )
+    },
+    calcPileHole(newList) {
+      if (!newList || !newList.length) {
+        return
+      }
+      const changeHole = []
+      const addList = []
+      newList.forEach(item => {
+        // 先比对已经存在的是否是变更状态
+        if (gemoCache[item.id] && gemoCache[item.id].consStatus !== item.consStatus) {
+          gemoCache[item.id].consStatus = item.consStatus;
+          changeHole.push(item)
+        }
+        if (!gemoCache[item.id]) {
+          gemoCache[item.id] = item;
+          addList.push(item);
+        }
       })
+      this.addPileHoleToMap(addList)
+      this.updatePileHole(changeHole)
     },
     loaded(map) {
       this.mapIns = map
       this.pileHoleLayer = this.createLayer(map)
-      this.pileMachineLayer = this.createLayer(map)
+      this.pileMachineLayer = this.createLayer(map, 2)
+
       this.loadPileHole()
+      this.timer = setInterval(() => {
+        this.loadPileHole()
+        this.loadOnlineMachine()
+      }, 30000)
       this.init();
     },
     handleClick(e) {
@@ -361,9 +452,6 @@ export default {
     locationClose() {
       this.selectMachine = null
     },
-    pileHoleClick(pileHole) {
-      this.$refs.pileHoleDialog.showDialog(pileHole)
-    },
   },
 };
 </script>

+ 42 - 56
src/views/system/config/index.vue

@@ -55,29 +55,8 @@
           size="mini"
           @click="handleAdd"
           v-hasPermi="['system:config:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['system:config:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['system:config:remove']"
-        >删除</el-button>
+        >新增
+        </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button
@@ -87,7 +66,8 @@
           size="mini"
           @click="handleExport"
           v-hasPermi="['system:config:export']"
-        >导出</el-button>
+        >导出
+        </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button
@@ -97,23 +77,24 @@
           size="mini"
           @click="handleRefreshCache"
           v-hasPermi="['system:config:remove']"
-        >刷新缓存</el-button>
+        >刷新缓存
+        </el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
     <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="参数主键" align="center" prop="configId" />
-      <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
-      <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
-      <el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="参数主键" align="center" prop="configId"/>
+      <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true"/>
+      <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true"/>
+      <el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true"/>
       <el-table-column label="系统内置" align="center" prop="configType">
         <template slot-scope="scope">
           <dict-tag :options="dict.type.sys_yes_no" :value="scope.row.configType"/>
         </template>
       </el-table-column>
-      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true"/>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createTime) }}</span>
@@ -126,15 +107,18 @@
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
+            v-if="scope.row.configType !== 'Y'"
             v-hasPermi="['system:config:edit']"
-          >修改</el-button>
+          >修改
+          </el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
             v-hasPermi="['system:config:remove']"
-          >删除</el-button>
+          >删除
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -151,13 +135,13 @@
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="参数名称" prop="configName">
-          <el-input v-model="form.configName" placeholder="请输入参数名称" />
+          <el-input v-model="form.configName" placeholder="请输入参数名称"/>
         </el-form-item>
         <el-form-item label="参数键名" prop="configKey">
-          <el-input v-model="form.configKey" placeholder="请输入参数键名" />
+          <el-input v-model="form.configKey" placeholder="请输入参数键名"/>
         </el-form-item>
         <el-form-item label="参数键值" prop="configValue">
-          <el-input v-model="form.configValue" placeholder="请输入参数键值" />
+          <el-input v-model="form.configValue" placeholder="请输入参数键值"/>
         </el-form-item>
         <el-form-item label="系统内置" prop="configType">
           <el-radio-group v-model="form.configType">
@@ -165,20 +149,21 @@
               v-for="dict in dict.type.sys_yes_no"
               :key="dict.value"
               :label="dict.value"
-            >{{dict.label}}</el-radio>
+            >{{ dict.label }}
+            </el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="json配置" prop="cfgJson">
           <vue-json-editor
-              v-model="cfgJson"
-              :showBtns="false"
-              mode="code"
-              lang="zh"
-              :expanded-on-start="true"
+            v-model="cfgJson"
+            :showBtns="false"
+            mode="code"
+            lang="zh"
+            :expanded-on-start="true"
           />
         </el-form-item>
         <el-form-item label="备注" prop="remark">
-          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"/>
         </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -190,12 +175,12 @@
 </template>
 
 <script>
-import { addConfig, delConfig, getConfig, listConfig, refreshCache, updateConfig } from '@/api/system/config';
+import {addConfig, delConfig, getConfig, listConfig, refreshCache, updateConfig} from '@/api/system/config';
 import vueJsonEditor from 'vue-json-editor';
 
 export default {
   name: "Config",
-  components: { vueJsonEditor },
+  components: {vueJsonEditor},
   dicts: ['sys_yes_no'],
   data() {
     return {
@@ -233,13 +218,13 @@ export default {
       // 表单校验
       rules: {
         configName: [
-          { required: true, message: "参数名称不能为空", trigger: "blur" }
+          {required: true, message: "参数名称不能为空", trigger: "blur"}
         ],
         configKey: [
-          { required: true, message: "参数键名不能为空", trigger: "blur" }
+          {required: true, message: "参数键名不能为空", trigger: "blur"}
         ],
         configValue: [
-          { required: true, message: "参数键值不能为空", trigger: "blur" }
+          {required: true, message: "参数键值不能为空", trigger: "blur"}
         ],
       }
     };
@@ -308,7 +293,7 @@ export default {
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.configId)
-      this.single = selection.length!=1
+      this.single = selection.length != 1
       this.multiple = !selection.length
     },
     /** 修改按钮操作 */
@@ -325,7 +310,7 @@ export default {
       });
     },
     /** 提交按钮 */
-    submitForm: function() {
+    submitForm: function () {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.configId != undefined) {
@@ -347,12 +332,13 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const configIds = row.configId || this.ids;
-      this.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function() {
-          return delConfig(configIds);
-        }).then(() => {
-          this.getList();
-          this.$modal.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function () {
+        return delConfig(configIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {
+      });
     },
     /** 导出按钮操作 */
     handleExport() {

+ 263 - 0
src/views/system/tenant/index.vue

@@ -0,0 +1,263 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="租户名称" prop="tenantName">
+        <el-input
+          v-model="queryParams.tenantName"
+          placeholder="请输入租户名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="租户编码" prop="tenantCode">
+        <el-input
+          v-model="queryParams.tenantCode"
+          placeholder="请输入租户编码"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:tenant:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:tenant:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:tenant:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:tenant:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="租户名称" align="center" prop="tenantName" />
+      <el-table-column label="租户编码" align="center" prop="tenantCode" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:tenant:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:tenant:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改租户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="租户名称" prop="tenantName">
+          <el-input v-model="form.tenantName" placeholder="请输入租户名称" />
+        </el-form-item>
+        <el-form-item label="租户编码" prop="tenantCode">
+          <el-input v-model="form.tenantCode" placeholder="请输入租户编码" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listTenant, getTenant, delTenant, addTenant, updateTenant } from "@/api/system/tenant";
+
+export default {
+  name: "Tenant",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 租户表格数据
+      tenantList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        tenantName: null,
+        tenantCode: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询租户列表 */
+    getList() {
+      this.loading = true;
+      listTenant(this.queryParams).then(response => {
+        this.tenantList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        tenantName: null,
+        tenantCode: null,
+        updateTime: null,
+        createTime: null,
+        createBy: null,
+        updateBy: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加租户";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getTenant(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改租户";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateTenant(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTenant(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除租户编号为"' + ids + '"的数据项?').then(function() {
+        return delTenant(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('system/tenant/export', {
+        ...this.queryParams
+      }, `tenant_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>

+ 105 - 60
src/views/system/user/index.vue

@@ -29,7 +29,8 @@
       </el-col>
       <!--用户数据-->
       <el-col :span="20" :xs="24">
-        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
+                 label-width="68px">
           <el-form-item label="用户名称" prop="userName">
             <el-input
               v-model="queryParams.userName"
@@ -89,7 +90,8 @@
               size="mini"
               @click="handleAdd"
               v-hasPermi="['system:user:add']"
-            >新增</el-button>
+            >新增
+            </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button
@@ -100,7 +102,8 @@
               :disabled="single"
               @click="handleUpdate"
               v-hasPermi="['system:user:edit']"
-            >修改</el-button>
+            >修改
+            </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button
@@ -111,7 +114,8 @@
               :disabled="multiple"
               @click="handleDelete"
               v-hasPermi="['system:user:remove']"
-            >删除</el-button>
+            >删除
+            </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button
@@ -121,7 +125,8 @@
               size="mini"
               @click="handleImport"
               v-hasPermi="['system:user:import']"
-            >导入</el-button>
+            >导入
+            </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button
@@ -131,18 +136,23 @@
               size="mini"
               @click="handleExport"
               v-hasPermi="['system:user:export']"
-            >导出</el-button>
+            >导出
+            </el-button>
           </el-col>
           <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
         </el-row>
 
         <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
-          <el-table-column type="selection" width="50" align="center" />
-          <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
-          <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
-          <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
-          <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
-          <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
+          <el-table-column type="selection" width="50" align="center"/>
+          <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible"/>
+          <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible"
+                           :show-overflow-tooltip="true"/>
+          <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible"
+                           :show-overflow-tooltip="true"/>
+          <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible"
+                           :show-overflow-tooltip="true"/>
+          <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber"
+                           v-if="columns[4].visible" width="120"/>
           <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
             <template slot-scope="scope">
               <el-switch
@@ -171,21 +181,26 @@
                 icon="el-icon-edit"
                 @click="handleUpdate(scope.row)"
                 v-hasPermi="['system:user:edit']"
-              >修改</el-button>
+              >修改
+              </el-button>
               <el-button
                 size="mini"
                 type="text"
                 icon="el-icon-delete"
                 @click="handleDelete(scope.row)"
                 v-hasPermi="['system:user:remove']"
-              >删除</el-button>
-              <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
+              >删除
+              </el-button>
+              <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
+                           v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
                 <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
                 <el-dropdown-menu slot="dropdown">
                   <el-dropdown-item command="handleResetPwd" icon="el-icon-key"
-                    v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
+                                    v-hasPermi="['system:user:resetPwd']">重置密码
+                  </el-dropdown-item>
                   <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
-                    v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
+                                    v-hasPermi="['system:user:edit']">分配角色
+                  </el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
             </template>
@@ -208,36 +223,37 @@
         <el-row>
           <el-col :span="12">
             <el-form-item label="用户昵称" prop="nickName">
-              <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
+              <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="归属部门" prop="deptId">
-              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+              <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门"/>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row>
           <el-col :span="12">
             <el-form-item label="手机号码" prop="phonenumber">
-              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="邮箱" prop="email">
-              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50"/>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row>
           <el-col :span="12">
             <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
-              <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
+              <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
-              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password/>
+              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20"
+                        show-password/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -261,7 +277,8 @@
                   v-for="dict in dict.type.sys_normal_disable"
                   :key="dict.value"
                   :label="dict.value"
-                >{{dict.label}}</el-radio>
+                >{{ dict.label }}
+                </el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -326,10 +343,13 @@
         <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
         <div class="el-upload__tip text-center" slot="tip">
           <div class="el-upload__tip" slot="tip">
-            <el-checkbox v-model="upload.updateSupport" /> 是否更新已经存在的用户数据
+            <el-checkbox v-model="upload.updateSupport"/>
+            是否更新已经存在的用户数据
           </div>
           <span>仅允许导入xls、xlsx格式文件。</span>
-          <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
+          <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
+                   @click="importTemplate">下载模板
+          </el-link>
         </div>
       </el-upload>
       <div slot="footer" class="dialog-footer">
@@ -341,15 +361,29 @@
 </template>
 
 <script>
-import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user";
-import { getToken } from "@/utils/auth";
+import {
+  addUser,
+  changeUserStatus,
+  delUser,
+  deptTreeSelect,
+  getUser,
+  listUser,
+  resetUserPwd,
+  updateUser
+} from "@/api/system/user";
+import {mapGetters, mapState} from "vuex";
+import {getToken} from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
 export default {
   name: "User",
   dicts: ['sys_normal_disable', 'sys_user_sex'],
-  components: { Treeselect },
+  components: {Treeselect},
+  computed: {
+    ...mapState(["user"]),
+    ...mapGetters(["tenant"]),
+  },
   data() {
     return {
       // 遮罩层
@@ -383,7 +417,9 @@ export default {
       // 角色选项
       roleOptions: [],
       // 表单参数
-      form: {},
+      form: {
+        tenantId: this.tenant,
+      },
       defaultProps: {
         children: "children",
         label: "label"
@@ -399,9 +435,12 @@ export default {
         // 是否更新已经存在的用户数据
         updateSupport: 0,
         // 设置上传的请求头部
-        headers: { Authorization: "Bearer " + getToken() },
+        headers: {
+          Authorization: "Bearer " + getToken(),
+          "X-Tenant": this.tenant
+        },
         // 上传的地址
-        url: process.env.VUE_APP_BASE_API + "/system/user/importData"
+        url: process.env.VUE_APP_BASE_API + "/system/user/importData",
       },
       // 查询参数
       queryParams: {
@@ -414,27 +453,27 @@ export default {
       },
       // 列信息
       columns: [
-        { key: 0, label: `用户编号`, visible: true },
-        { key: 1, label: `用户名称`, visible: true },
-        { key: 2, label: `用户昵称`, visible: true },
-        { key: 3, label: `部门`, visible: true },
-        { key: 4, label: `手机号码`, visible: true },
-        { key: 5, label: `状态`, visible: true },
-        { key: 6, label: `创建时间`, visible: true }
+        {key: 0, label: `用户编号`, visible: true},
+        {key: 1, label: `用户名称`, visible: true},
+        {key: 2, label: `用户昵称`, visible: true},
+        {key: 3, label: `部门`, visible: true},
+        {key: 4, label: `手机号码`, visible: true},
+        {key: 5, label: `状态`, visible: true},
+        {key: 6, label: `创建时间`, visible: true}
       ],
       // 表单校验
       rules: {
         userName: [
-          { required: true, message: "用户名称不能为空", trigger: "blur" },
-          { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
+          {required: true, message: "用户名称不能为空", trigger: "blur"},
+          {min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur'}
         ],
         nickName: [
-          { required: true, message: "用户昵称不能为空", trigger: "blur" }
+          {required: true, message: "用户昵称不能为空", trigger: "blur"}
         ],
         password: [
-          { required: true, message: "用户密码不能为空", trigger: "blur" },
-          { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
-          { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
+          {required: true, message: "用户密码不能为空", trigger: "blur"},
+          {min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur'},
+          {pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur"}
         ],
         email: [
           {
@@ -496,11 +535,11 @@ export default {
     // 用户状态修改
     handleStatusChange(row) {
       let text = row.status === "0" ? "启用" : "停用";
-      this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
+      this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
         return changeUserStatus(row.userId, row.status);
       }).then(() => {
         this.$modal.msgSuccess(text + "成功");
-      }).catch(function() {
+      }).catch(function () {
         row.status = row.status === "0" ? "1" : "0";
       });
     },
@@ -522,6 +561,7 @@ export default {
         sex: undefined,
         status: "0",
         remark: undefined,
+        tenantId: this.tenant,
         postIds: [],
         roleIds: []
       };
@@ -598,19 +638,20 @@ export default {
             return "不能包含非法字符:< > \" ' \\\ |"
           }
         },
-      }).then(({ value }) => {
-          resetUserPwd(row.userId, value).then(response => {
-            this.$modal.msgSuccess("修改成功,新密码是:" + value);
-          });
-        }).catch(() => {});
+      }).then(({value}) => {
+        resetUserPwd(row.userId, value).then(response => {
+          this.$modal.msgSuccess("修改成功,新密码是:" + value);
+        });
+      }).catch(() => {
+      });
     },
     /** 分配角色操作 */
-    handleAuthRole: function(row) {
+    handleAuthRole: function (row) {
       const userId = row.userId;
       this.$router.push("/system/user-auth/role/" + userId);
     },
     /** 提交按钮 */
-    submitForm: function() {
+    submitForm: function () {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.userId != undefined) {
@@ -632,12 +673,13 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const userIds = row.userId || this.ids;
-      this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
+      this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
         return delUser(userIds);
       }).then(() => {
         this.getList();
         this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
+      }).catch(() => {
+      });
     },
     /** 导出按钮操作 */
     handleExport() {
@@ -652,8 +694,7 @@ export default {
     },
     /** 下载模板操作 */
     importTemplate() {
-      this.download('system/user/importTemplate', {
-      }, `user_template_${new Date().getTime()}.xlsx`)
+      this.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`)
     },
     // 文件上传中处理
     handleFileUploadProgress(event, file, fileList) {
@@ -664,13 +705,17 @@ export default {
       this.upload.open = false;
       this.upload.isUploading = false;
       this.$refs.upload.clearFiles();
-      this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
+      this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", {dangerouslyUseHTMLString: true});
       this.getList();
     },
     // 提交上传文件
     submitFileForm() {
+      if (!this.upload.tenantId) {
+        this.$modal.msgError("请选择租户");
+        return;
+      }
       this.$refs.upload.submit();
     }
   }
 };
-</script>
+</script>

+ 1 - 0
vue.config.js

@@ -14,6 +14,7 @@ const port = process.env.port || process.env.npm_config_port || 80 // 端口
 //官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
 // 这里只列一部分,具体配置参考文档
 module.exports = {
+  runtimeCompiler: true,
   // 部署生产环境和开发环境下的URL。
   // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
   // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。