瀏覽代碼

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	src/types/components.d.ts
hmm 7 月之前
父節點
當前提交
7067278f14

+ 1 - 1
.env.development

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 应急指挥一张图
+VITE_APP_TITLE = 茂名智慧应急一张图
 
 # 开发环境配置
 VITE_APP_ENV = 'development'

+ 1 - 1
.env.production

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 应急指挥一张图
+VITE_APP_TITLE = 茂名智慧应急一张图
 
 # 生产环境配置
 VITE_APP_ENV = 'production'

+ 1 - 1
index.html

@@ -18,7 +18,7 @@
     <script src="/Decoder.js"></script>
     <script src="/ol-plot.js"></script>
 
-    <title>应急指挥一张图</title>
+    <title>茂名智慧应急一张图</title>
     <!--[if lt IE 11
       ]><script>
         window.location.href = '/html/ie.html';

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "name": "yjdp-web",
   "version": "5.2.1",
-  "description": "应急指挥一张图",
+  "description": "茂名智慧应急一张图",
   "license": "MIT",
   "type": "module",
   "scripts": {

二進制
src/assets/images/login-background.jpg


二進制
src/assets/images/password.png


二進制
src/assets/images/user2.png


二進制
src/assets/images/verify.png


+ 1 - 1
src/components/HKVideo/video-container2.vue

@@ -12,7 +12,7 @@
       <div class="tag" :title="item.name">
         <div class="name">{{ item.name }}</div>
       </div>
-      <HKVideo :dot_data="item" :height="8" />
+      <HKVideo :dot_data="item" :height="558" />
     </div>
   </div>
   <div v-else-if="videoData.length >= 5 && videoData.length <= 6" class="video-container3">

+ 2 - 1
src/components/TimeAxis/index.vue

@@ -268,8 +268,9 @@ onMounted(() => {
   &::after {
     content: '';
     position: absolute;
-    top: 0;
+    top: 50%;
     right: -15px;
+    transform: translateY(-50%);
     width: 9px;
     height: 142px;
     background: url('@/assets/images/timeAxis/timeRight.png') no-repeat;

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

@@ -155,7 +155,7 @@ const logout = async () => {
     type: 'warning'
   });
   await userStore.logout();
-  location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
+  location.href = import.meta.env.VITE_APP_CONTEXT_PATH + '#' + 'index';
 };
 
 const emits = defineEmits(['setLayout']);

+ 2 - 2
src/layout/components/SocialCallback/index.vue

@@ -30,14 +30,14 @@ const processResponse = async (res: any) => {
   }
   ElMessage.success(res.msg);
   setTimeout(() => {
-    location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
+    location.href = import.meta.env.VITE_APP_CONTEXT_PATH + '#' + 'index';
   }, 2000);
 };
 
 const handleError = (error: any) => {
   ElMessage.error(error.message);
   setTimeout(() => {
-    location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
+    location.href = import.meta.env.VITE_APP_CONTEXT_PATH + '#' + 'index';
   }, 2000);
 };
 

+ 17 - 0
src/types/components.d.ts

@@ -20,6 +20,7 @@ declare module 'vue' {
     ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
     ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
     ElButton: typeof import('element-plus/es')['ElButton']
+    ElCard: typeof import('element-plus/es')['ElCard']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
     ElCol: typeof import('element-plus/es')['ElCol']
     ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
@@ -41,17 +42,28 @@ declare module 'vue' {
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
+    ElPopover: typeof import('element-plus/es')['ElPopover']
+    ElRadio: typeof import('element-plus/es')['ElRadio']
+    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
     ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
     ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
     ElSlider: typeof import('element-plus/es')['ElSlider']
+    ElStep: typeof import('element-plus/es')['ElStep']
+    ElSteps: typeof import('element-plus/es')['ElSteps']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
+    ElTable: typeof import('element-plus/es')['ElTable']
+    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElTabPane: typeof import('element-plus/es')['ElTabPane']
+    ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTimeline: typeof import('element-plus/es')['ElTimeline']
     ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
+    ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ElTree: typeof import('element-plus/es')['ElTree']
+    ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
     FooterSection: typeof import('./../components/FooterSection/index.vue')['default']
@@ -62,6 +74,7 @@ declare module 'vue' {
     HikvisionPlayer: typeof import('./../components/HKVideo/hikvision-player.vue')['default']
     HKVideo: typeof import('./../components/HKVideo/index.vue')['default']
     IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
+    IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default']
     IFrame: typeof import('./../components/iFrame/index.vue')['default']
     ImagePreview: typeof import('./../components/ImagePreview/index.vue')['default']
     ImageUpload: typeof import('./../components/ImageUpload/index.vue')['default']
@@ -94,6 +107,10 @@ declare module 'vue' {
     VideoContainer: typeof import('./../components/HKVideo/video-container.vue')['default']
     VideoContainer2: typeof import('./../components/HKVideo/video-container2.vue')['default']
     YMap: typeof import('./../components/Map/YMap.vue')['default']
+    YMapold: typeof import('./../components/Map/YMapold.vue')['default']
     YztMap: typeof import('./../components/Map/YztMap/index.vue')['default']
   }
+  export interface ComponentCustomProperties {
+    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+  }
 }

+ 1 - 1
src/utils/request.ts

@@ -134,7 +134,7 @@ service.interceptors.response.use(
         }).then(() => {
           isRelogin.show = false;
           useUserStore().logout().then(() => {
-              location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
+              location.href = import.meta.env.VITE_APP_CONTEXT_PATH + '#' + 'index';
             });
         }).catch(() => {
           isRelogin.show = false;

+ 3 - 2
src/views/emergencyCommandMap/RightSection/RenWuGenZong.vue

@@ -155,10 +155,11 @@ watch(
     align-items: center;
   }
   .box2 {
-    flex: 1;
+    width: 1642px;
+    min-height: 170px;
     background-image: url('@/assets/images/taskTracking/box1.png');
     background-repeat: no-repeat;
-    background-size: 1642px 377px;
+    background-size: 100% 100%;
     background-position: bottom left;
     padding: 20px 20px 20px 60px;
     margin-top: 20px;

+ 3 - 4
src/views/globalMap/LeftMenu.vue

@@ -205,9 +205,9 @@ defineExpose({ setMenuChange });
     top: 100px;
     left: 0;
     background-color: #0d1d4e;
-    border: 1px solid #2C81FF;
+    border: 1px solid #2c81ff;
     width: 815px;
-    color: #000;
+    color: #00e8ff;
     font-size: 46px;
     z-index: 9;
 
@@ -260,7 +260,7 @@ defineExpose({ setMenuChange });
   .menu-header {
     display: flex;
     margin-top: 65px;
-    height: 78px;
+    height: 88px;
 
     .menu-item {
       width: 339px;
@@ -297,7 +297,6 @@ defineExpose({ setMenuChange });
     overflow-x: hidden;
     .content-box {
       padding: 0 10px;
-      margin-top: 10px;
       width: 779px;
       background: url('@/assets/images/menu/menuContent.png') no-repeat;
       background-size: 100% 100%;

+ 189 - 50
src/views/login.vue

@@ -1,49 +1,81 @@
 <template>
   <div class="login">
     <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">应急指挥一张图</h3>
-      <el-form-item prop="username">
-        <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
-          <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
-        </el-input>
-      </el-form-item>
-      <el-form-item prop="password">
-        <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
-          <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
-        </el-input>
-      </el-form-item>
-      <el-form-item v-if="captchaEnabled" prop="code">
-        <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
-          <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
-        </el-input>
-        <div class="login-code">
-          <img :src="codeUrl" class="login-code-img" @click="getCode" />
+      <div class="title">欢迎登录</div>
+      <div class="title2">茂名智慧应急一张图</div>
+      <div class="login-box">
+        <div class="login-tabs">
+          <div v-for="(item, index) in tabs" :key="index" :class="tabActive === index ? 'login-tab tab-active' : 'login-tab'">{{ item }}</div>
         </div>
-      </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">记住密码</el-checkbox>
-      <el-form-item style="width: 100%">
-        <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
-          <span v-if="!loading">登 录</span>
-          <span v-else>登 录 中...</span>
-        </el-button>
-      </el-form-item>
+        <el-form-item prop="username">
+          <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
+            <template #prefix><i class="icon-user" /></template>
+          </el-input>
+        </el-form-item>
+        <el-form-item prop="password">
+          <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
+            <template #prefix><i class="icon-password" /></template>
+          </el-input>
+        </el-form-item>
+        <el-form-item v-if="captchaEnabled" prop="code">
+          <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
+            <template #prefix><i class="icon-verify" /></template>
+          </el-input>
+          <div class="login-code">
+            <img :src="codeUrl" class="login-code-img" @click="getCode" />
+          </div>
+        </el-form-item>
+        <!--        <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">记住密码</el-checkbox>-->
+        <!--
+        <el-form-item style="float: right">
+          <el-button circle title="微信登录" @click="doSocialLogin('wechat')">
+            <svg-icon icon-class="wechat" />
+          </el-button>
+          <el-button circle title="MaxKey登录" @click="doSocialLogin('maxkey')">
+            <svg-icon icon-class="maxkey" />
+          </el-button>
+          <el-button circle title="TopIam登录" @click="doSocialLogin('topiam')">
+            <svg-icon icon-class="topiam" />
+          </el-button>
+          <el-button circle title="Gitee登录" @click="doSocialLogin('gitee')">
+            <svg-icon icon-class="gitee" />
+          </el-button>
+          <el-button circle title="Github登录" @click="doSocialLogin('github')">
+            <svg-icon icon-class="github" />
+          </el-button>
+        </el-form-item>
+        -->
+        <el-form-item style="width: 100%">
+          <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
+            <span v-if="!loading">登 录</span>
+            <span v-else>登 录 中...</span>
+          </el-button>
+          <div v-if="register" style="float: right">
+            <router-link class="link-type" :to="'/register'">立即注册</router-link>
+          </div>
+        </el-form-item>
+      </div>
     </el-form>
     <!--  底部  -->
     <div class="el-login-footer">
-      <span v-if="false">Copyright © 2018-2024</span>
+      <span v-if="false"></span>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { getCodeImg } from '@/api/login';
+import { getCodeImg, getTenantList } from '@/api/login';
+import { authBinding } from '@/api/system/social/auth';
 import { useUserStore } from '@/store/modules/user';
-import { LoginData } from '@/api/types';
+import { LoginData, TenantVO } from '@/api/types';
 import { to } from 'await-to-js';
+import { HttpStatus } from '@/enums/RespEnum';
 
 const userStore = useUserStore();
 const router = useRouter();
-
+const tabActive = ref(0);
+// '粤政易扫码登录',
+const tabs = reactive(['账号密码登录']);
 const loginForm = ref<LoginData>({
   tenantId: '000000',
   username: 'admin',
@@ -54,6 +86,7 @@ const loginForm = ref<LoginData>({
 } as LoginData);
 
 const loginRules: ElFormRules = {
+  tenantId: [{ required: true, trigger: 'blur', message: '请输入您的租户编号' }],
   username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
   password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
   code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
@@ -63,10 +96,15 @@ const codeUrl = ref('');
 const loading = ref(false);
 // 验证码开关
 const captchaEnabled = ref(true);
+// 租户开关
+const tenantEnabled = ref(true);
 
 // 注册开关
+const register = ref(false);
 const redirect = ref(undefined);
 const loginRef = ref<ElFormInstance>();
+// 租户列表
+const tenantList = ref<TenantVO[]>([]);
 
 watch(
   () => router.currentRoute.value,
@@ -81,16 +119,18 @@ const handleLogin = () => {
     if (valid) {
       loading.value = true;
       // 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码
-      if (loginForm.value.rememberMe) {
-        localStorage.setItem('username', String(loginForm.value.username));
-        localStorage.setItem('password', String(loginForm.value.password));
-        localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
-      } else {
-        // 否则移除
-        localStorage.removeItem('username');
-        localStorage.removeItem('password');
-        localStorage.removeItem('rememberMe');
-      }
+      // if (loginForm.value.rememberMe) {
+      //   localStorage.setItem('tenantId', String(loginForm.value.tenantId));
+      //   localStorage.setItem('username', String(loginForm.value.username));
+      //   localStorage.setItem('password', String(loginForm.value.password));
+      //   localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
+      // } else {
+      //   // 否则移除
+      //   localStorage.removeItem('tenantId');
+      //   localStorage.removeItem('username');
+      //   localStorage.removeItem('password');
+      //   localStorage.removeItem('rememberMe');
+      // }
       // 调用action的登录方法
       const [err] = await to(userStore.login(loginForm.value));
       if (!err) {
@@ -124,19 +164,50 @@ const getCode = async () => {
 };
 
 const getLoginData = () => {
+  const tenantId = localStorage.getItem('tenantId');
   const username = localStorage.getItem('username');
   const password = localStorage.getItem('password');
   const rememberMe = localStorage.getItem('rememberMe');
   loginForm.value = {
-    tenantId: '000000',
+    tenantId: tenantId === null ? String(loginForm.value.tenantId) : tenantId,
     username: username === null ? String(loginForm.value.username) : username,
     password: password === null ? String(loginForm.value.password) : String(password),
     rememberMe: rememberMe === null ? false : Boolean(rememberMe)
   } as LoginData;
 };
 
+/**
+ * 获取租户列表
+ */
+const initTenantList = async () => {
+  const { data } = await getTenantList();
+  tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
+  if (tenantEnabled.value) {
+    tenantList.value = data.voList;
+    if (tenantList.value != null && tenantList.value.length !== 0) {
+      loginForm.value.tenantId = tenantList.value[0].tenantId;
+    }
+  }
+};
+
+/**
+ * 第三方登录
+ * @param type
+ */
+const doSocialLogin = (type: string) => {
+  authBinding(type, loginForm.value.tenantId).then((res: any) => {
+    if (res.code === HttpStatus.SUCCESS) {
+      // 获取授权地址跳转
+      window.location.href = res.data;
+    } else {
+      ElMessage.error(res.msg);
+    }
+  });
+};
+
 onMounted(() => {
   getCode();
+  initTenantList();
   getLoginData();
 });
 </script>
@@ -147,23 +218,31 @@ onMounted(() => {
   justify-content: center;
   align-items: center;
   height: 100%;
-  background-color: #020935;
-  //background-image: url('../assets/images/login-background.jpg');
-  //background-size: cover;
+  background-image: url('../assets/images/login-background.jpg');
+  background-size: cover;
 }
 
 .title {
-  margin: 0px auto 30px auto;
-  text-align: center;
-  color: #707070;
+  font-size: 24px;
+  font-weight: bold;
+  color: #25282e;
+}
+
+.title2 {
+  font-size: 36px;
+  font-weight: bold;
+  margin: 6px 0 20px;
+  color: #25282e;
 }
 
 .login-form {
-  border-radius: 6px;
-  background: #ffffff;
   width: 400px;
-  padding: 25px 25px 5px 25px;
-
+  .login-box {
+    border-radius: 6px;
+    box-shadow: 0 0 4px #d4e9fe;
+    width: 400px;
+    padding: 25px 25px 5px 25px;
+  }
   .el-input {
     height: 40px;
 
@@ -213,4 +292,64 @@ onMounted(() => {
   height: 40px;
   padding-left: 12px;
 }
+
+.login-tabs {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 40px;
+  line-height: 40px;
+  border-bottom: 1px solid #eeeeee;
+  margin-bottom: 15px;
+  .login-tab {
+  }
+  .tab-active {
+    color: #5695eb;
+    position: relative;
+    &::before {
+      content: '';
+      width: 100%;
+      height: 1px;
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      background-color: #5695eb;
+    }
+  }
+}
+:deep(.el-input--large) {
+  .el-input__wrapper {
+    padding: 1px 5px !important;
+  }
+}
+
+.icon-user {
+  background: url('@/assets/images/user2.png') no-repeat;
+}
+.icon-password {
+  background: url('@/assets/images/password.png') no-repeat;
+}
+.icon-verify {
+  background: url('@/assets/images/verify.png') no-repeat;
+}
+.icon-user,
+.icon-password,
+.icon-verify {
+  width: 24px;
+  height: 24px;
+  background-size: 100% 100%;
+  margin-right: 10px;
+  position: relative;
+  &::after {
+    content: '';
+    display: inline-block;
+    width: 1px;
+    height: 18px;
+    background-color: #d9d9d9;
+    position: absolute;
+    top: 3px;
+    right: -5px;
+  }
+}
 </style>

+ 1 - 2
src/views/routineCommandMap/PositionMap.vue

@@ -12,7 +12,7 @@
                 <i class="el-icon-close" style="float: right; font-size: 20px; cursor: pointer" @click="closeSearchList()" />
               </div>
 
-              <el-scrollbar class="scroll" style="height: 250px">
+              <el-scrollbar class="scroll" style="height: 600px">
                 <div v-for="(item, index) in searchList" v-show="searchList.length" :key="index" class="item" @click="handlePanTo(index)">
                   <el-image class="img" :src="item.img" :alt="item.name" lazy>
                     <template #error>
@@ -392,7 +392,6 @@ function submit() {
 }
 .scroll {
   width: 100%;
-  height: auto !important;
 
   .item {
     display: flex;

+ 4 - 0
src/views/routineCommandMap/RightSection/index.vue

@@ -339,4 +339,8 @@ onMounted(() => {
     }
   }
 }
+.table-content {
+  height: 240px;
+  overflow-y: auto;
+}
 </style>