mirror of
				https://gitee.com/lab1024/smart-admin.git
				synced 2025-11-04 10:23:43 +08:00 
			
		
		
		
	修复几个显示问题
This commit is contained in:
		@@ -1,13 +1,13 @@
 | 
			
		||||
### SmartAdmin
 | 
			
		||||
 | 
			
		||||
SmartAdmin 由河南·洛阳 [1024 创新实验室](https://www.1024lab.net/)使用SpringBoot2 和 Vue3 Setup标签、 Composition Api (同时支持JavaScript和TypeScript双版本) ,开发出的一套简洁、易用的中后台解决方案!  
 | 
			
		||||
SmartAdmin 由河南·洛阳 [1024 创新实验室](https://www.1024lab.net/)使用SpringBoot2 和 Vue3 Setup语法糖、 Composition Api (同时支持JavaScript和TypeScript双版本) ,开发出的一套简洁、易用的中后台解决方案!  
 | 
			
		||||
 | 
			
		||||
**我们开源一套漂亮的代码和一套整洁的代码规范**,让大家在这浮躁的代码世界里感受到一股把代码写好的清流!同时又让开发者节省大量的时间,减少加班,快乐工作,保持谦逊,保持学习,热爱代码,更热爱生活!
 | 
			
		||||
 | 
			
		||||
### 地址
 | 
			
		||||
 | 
			
		||||
在线预览: [http://preview.smartadmin.1024lab.net](http://preview.smartadmin.1024lab.net)  
 | 
			
		||||
部署文档:[https://smartadmin.1024lab.net](https://smartadmin.1024lab.net)  (文档在努力更新中)  
 | 
			
		||||
在线预览: [https://preview.smartadmin.vip](https://preview.smartadmin.vip)  
 | 
			
		||||
部署文档:[https://smartadmin.vip](https://smartadmin.vip)
 | 
			
		||||
vue2版本:请查看 feature/1.x 分支
 | 
			
		||||
 | 
			
		||||
### 理念与思想
 | 
			
		||||
 
 | 
			
		||||
@@ -29,33 +29,33 @@
 | 
			
		||||
        WHERE notice_id = #{noticeId}
 | 
			
		||||
    </update>
 | 
			
		||||
    <select id="queryPage" resultType="net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeVO">
 | 
			
		||||
        SELECT tn.*,
 | 
			
		||||
        e.actual_name AS createUserName
 | 
			
		||||
        FROM t_notice tn
 | 
			
		||||
        LEFT JOIN t_employee e ON tn.create_user_id = e.employee_id
 | 
			
		||||
        SELECT t_notice.*,
 | 
			
		||||
        t_employee.actual_name AS createUserName
 | 
			
		||||
        FROM t_notice
 | 
			
		||||
        LEFT JOIN t_employee  ON t_notice.create_user_id = t_employee.employee_id
 | 
			
		||||
        <where>
 | 
			
		||||
            tn.deleted_flag = #{queryForm.deletedFlag}
 | 
			
		||||
            t_notice.deleted_flag = #{queryForm.deletedFlag}
 | 
			
		||||
            <if test="queryForm.keywords != null and queryForm.keywords != ''">
 | 
			
		||||
                AND (INSTR(tn.notice_title,#{queryForm.keywords}) OR INSTR(e.actual_name,#{queryForm.keywords}))
 | 
			
		||||
                AND (INSTR(t_notice.notice_title,#{queryForm.keywords}) OR INSTR(t_employee.actual_name,#{queryForm.keywords}))
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="queryForm.noticeType != null">
 | 
			
		||||
                AND tn.notice_type = #{queryForm.noticeType}
 | 
			
		||||
                AND t_notice.notice_type = #{queryForm.noticeType}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="queryForm.noticeBelongType != null">
 | 
			
		||||
                AND tn.notice_belong_type = #{queryForm.noticeBelongType}
 | 
			
		||||
                AND t_notice.notice_belong_type = #{queryForm.noticeBelongType}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="queryForm.startTime != null">
 | 
			
		||||
                AND DATE_FORMAT(tn.publish_time, '%Y-%m-%d') >= #{queryForm.startTime}
 | 
			
		||||
                AND DATE_FORMAT(t_notice.publish_time, '%Y-%m-%d') >= #{queryForm.startTime}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="queryForm.endTime != null">
 | 
			
		||||
                AND DATE_FORMAT(tn.publish_time, '%Y-%m-%d') <= #{queryForm.endTime}
 | 
			
		||||
                AND DATE_FORMAT(t_notice.publish_time, '%Y-%m-%d') <= #{queryForm.endTime}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="queryForm.disabledFlag != null">
 | 
			
		||||
                AND tn.disabled_flag = #{queryForm.disabledFlag}
 | 
			
		||||
                AND t_notice.disabled_flag = #{queryForm.disabledFlag}
 | 
			
		||||
            </if>
 | 
			
		||||
        </where>
 | 
			
		||||
        <if test="queryForm.sortItemList == null or queryForm.sortItemList.size == 0">
 | 
			
		||||
            ORDER BY tn.top_flag DESC,tn.publish_time DESC
 | 
			
		||||
            ORDER BY t_notice.top_flag DESC,t_notice.publish_time DESC
 | 
			
		||||
        </if>
 | 
			
		||||
    </select>
 | 
			
		||||
    <select id="getDetail" resultType="net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeVO">
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,8 @@ public abstract class AbstractSecurityConfig extends WebSecurityConfigurerAdapte
 | 
			
		||||
        // token filter 进行校验
 | 
			
		||||
        httpSecurity.addFilterBefore(new SecurityTokenFilter(this.userFunction()), UsernamePasswordAuthenticationFilter.class);
 | 
			
		||||
        httpSecurity.addFilterBefore(corsFilter, SecurityTokenFilter.class);
 | 
			
		||||
        // 禁用spring security 使用 X-Frame-Options防止网页被Frame
 | 
			
		||||
        httpSecurity.headers().frameOptions().disable();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ package net.lab1024.sa.common.config;
 | 
			
		||||
import net.lab1024.sa.common.common.interceptor.AbstractInterceptor;
 | 
			
		||||
import org.apache.commons.collections4.CollectionUtils;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.web.servlet.HandlerInterceptor;
 | 
			
		||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 | 
			
		||||
@@ -28,9 +27,6 @@ public class MvcConfig implements WebMvcConfigurer {
 | 
			
		||||
    @Autowired(required = false)
 | 
			
		||||
    private List<HandlerInterceptor> interceptorList;
 | 
			
		||||
 | 
			
		||||
    @Value("${file.storage.local.path}")
 | 
			
		||||
    private String uploadPath;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void addInterceptors (InterceptorRegistry registry) {
 | 
			
		||||
        if (CollectionUtils.isEmpty(interceptorList)) {
 | 
			
		||||
@@ -43,8 +39,7 @@ public class MvcConfig implements WebMvcConfigurer {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
 | 
			
		||||
        registry.addResourceHandler("/preview/**")
 | 
			
		||||
                .addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","file:" + uploadPath);;
 | 
			
		||||
        registry.addResourceHandler("/preview/**");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
 | 
			
		||||
SmartAdmin v2.X ,作者:1024创新实验室 @copyright:【 1024lab 】
 | 
			
		||||
 | 
			
		||||
SmartAdmin 文档地址:https://smartadmin.1024lab.net
 | 
			
		||||
SmartAdmin 文档地址:https://smartadmin.vip
 | 
			
		||||
 | 
			
		||||
1024创新实验室:https://www.1024lab.net
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
 | 
			
		||||
VITE_APP_API_URL = 'http://preview.smartadmin.1024lab.net/smart-admin-api'
 | 
			
		||||
VITE_APP_API_URL = 'https://preview.smartadmin.vip/smart-admin-api'
 | 
			
		||||
 | 
			
		||||
VITE_APP_PROJECT_TITLE = 'SmartAdmin V2.X'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								smart-admin-web/javascript-ant-design-vue3/dist.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								smart-admin-web/javascript-ant-design-vue3/dist.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -9,14 +9,17 @@
 | 
			
		||||
  *
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <a-modal title="文件预览" v-model:visible="visibleFlag" :width="768" @cancel="onClose">
 | 
			
		||||
    <div class="container">
 | 
			
		||||
      <img class="img-prev" :src="previewUrl" />
 | 
			
		||||
      <a-image
 | 
			
		||||
        class="img-prev"
 | 
			
		||||
        :style="{ display: 'none' }"
 | 
			
		||||
        :preview="{
 | 
			
		||||
          visible,
 | 
			
		||||
          onVisibleChange: setVisible,
 | 
			
		||||
        }"
 | 
			
		||||
        :src="previewUrl"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <template #footer>
 | 
			
		||||
      <a-button @click="onClose">关闭</a-button>
 | 
			
		||||
    </template>
 | 
			
		||||
  </a-modal>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
@@ -26,7 +29,6 @@
 | 
			
		||||
  import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
  import { SmartLoading } from '/@/components/framework/smart-loading';
 | 
			
		||||
 | 
			
		||||
  const visibleFlag = ref(false);
 | 
			
		||||
  const imgFileType = ['jpg', 'jpeg', 'png', 'gif'];
 | 
			
		||||
  const previewUrl = ref();
 | 
			
		||||
 | 
			
		||||
@@ -49,10 +51,15 @@
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const visible = ref(false);
 | 
			
		||||
  const setVisible = (value) => {
 | 
			
		||||
    visible.value = value;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function showFile(fileItem) {
 | 
			
		||||
    if (isImg(fileItem.fileType)) {
 | 
			
		||||
      previewUrl.value = fileItem.fileUrl;
 | 
			
		||||
      visibleFlag.value = true;
 | 
			
		||||
      setVisible(true);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    download(fileItem.fileName, fileItem.fileUrl);
 | 
			
		||||
@@ -63,10 +70,6 @@
 | 
			
		||||
    return imgFileType.includes(fileType);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function onClose() {
 | 
			
		||||
    visibleFlag.value = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  defineExpose({
 | 
			
		||||
    showPreview,
 | 
			
		||||
  });
 | 
			
		||||
@@ -77,11 +80,5 @@
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    .img-prev {
 | 
			
		||||
      display: block;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 600px;
 | 
			
		||||
      object-fit: contain;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,4 +14,11 @@ export default {
 | 
			
		||||
  antdLocale: antd,
 | 
			
		||||
  dayjsLocale: dayjs,
 | 
			
		||||
  'setting.title': 'Setting',
 | 
			
		||||
  'setting.menu.layout': 'Menu Layout',
 | 
			
		||||
  'setting.menu.width': 'Menu Width',
 | 
			
		||||
  'setting.menu.theme': 'Menu Theme',
 | 
			
		||||
  'setting.bread': 'Show Bread',
 | 
			
		||||
  'setting.pagetag': 'Show PageTag',
 | 
			
		||||
  'setting.footer': 'Show Footer',
 | 
			
		||||
  'setting.helpdoc': 'Show Helpdoc',
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -14,4 +14,11 @@ export default {
 | 
			
		||||
  antdLocale: antd,
 | 
			
		||||
  dayjsLocale: dayjs,
 | 
			
		||||
  'setting.title': '网站设置',
 | 
			
		||||
  'setting.menu.layout': '菜单布局',
 | 
			
		||||
  'setting.menu.width': '菜单宽度',
 | 
			
		||||
  'setting.menu.theme': '菜单主题',
 | 
			
		||||
  'setting.bread': '面包屑',
 | 
			
		||||
  'setting.pagetag': '标签页',
 | 
			
		||||
  'setting.footer': '页脚',
 | 
			
		||||
  'setting.helpdoc': '帮助文档',
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -16,33 +16,33 @@
 | 
			
		||||
          <a-select-option v-for="item in i18nList" :key="item.value" :value="item.value">{{ item.text }}</a-select-option>
 | 
			
		||||
        </a-select>
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="菜单布局">
 | 
			
		||||
      <a-form-item :label="$t('setting.menu.layout')">
 | 
			
		||||
        <a-radio-group @change="changeLayout" button-style="solid" v-model:value="formState.layout">
 | 
			
		||||
          <a-radio-button v-for="item in $smartEnumPlugin.getValueDescList('LAYOUT_ENUM')" :key="item.value" :value="item.value">
 | 
			
		||||
            {{ item.desc }}
 | 
			
		||||
          </a-radio-button>
 | 
			
		||||
        </a-radio-group>
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="菜单宽度" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
 | 
			
		||||
      <a-form-item :label="$t('setting.menu.width')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
 | 
			
		||||
        <a-input-number @change="changeSideMenuWidth" v-model:value="formState.sideMenuWidth" :min="1" />
 | 
			
		||||
        像素(px)
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="菜单主题">
 | 
			
		||||
      <a-form-item :label="$t('setting.menu.theme')">
 | 
			
		||||
        <a-radio-group v-model:value="formState.sideMenuTheme" button-style="solid" @change="changeMenuTheme">
 | 
			
		||||
          <a-radio-button value="dark">Dark</a-radio-button>
 | 
			
		||||
          <a-radio-button value="light">Light</a-radio-button>
 | 
			
		||||
        </a-radio-group>
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="面包屑">
 | 
			
		||||
      <a-form-item :label="$t('setting.bread')">
 | 
			
		||||
        <a-switch @change="changeBreadCrumbFlag" v-model:checked="formState.breadCrumbFlag" checked-children="显示" un-checked-children="隐藏" />
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="标签页">
 | 
			
		||||
      <a-form-item :label="$t('setting.pagetag')">
 | 
			
		||||
        <a-switch @change="changePageTagFlag" v-model:checked="formState.pageTagFlag" checked-children="显示" un-checked-children="隐藏" />
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="页脚">
 | 
			
		||||
      <a-form-item :label="$t('setting.footer')">
 | 
			
		||||
        <a-switch @change="changeFooterFlag" v-model:checked="formState.footerFlag" checked-children="显示" un-checked-children="隐藏" />
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="帮助文档">
 | 
			
		||||
      <a-form-item :label="$t('setting.helpdoc')">
 | 
			
		||||
        <a-switch @change="changeHelpDocFlag" v-model:checked="formState.helpDocFlag" checked-children="显示" un-checked-children="隐藏" />
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
    </a-form>
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@
 | 
			
		||||
    <!-----文档列表---->
 | 
			
		||||
    <div class="help-doc-list">
 | 
			
		||||
      <div class="help-doc-item-all">
 | 
			
		||||
        <router-link tag="a" target="_blank" :to="{ path: '/help-doc/detail' }">查看全部文档 >></router-link>
 | 
			
		||||
        <router-link tag="a" target="_blank" :to="{ path: '/help-doc/detail' }">系统手册文档 >></router-link>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="help-doc-item" v-for="item in helpDocList" :key="item.helpDocId">
 | 
			
		||||
        <router-link tag="a" target="_blank" :to="{ path: '/help-doc/detail', query: { helpDocId: item.helpDocId } }">{{ item.title }}</router-link>
 | 
			
		||||
@@ -64,7 +64,8 @@
 | 
			
		||||
  import FeedbackModal from './components/feedback-modal.vue';
 | 
			
		||||
  import { useAppConfigStore } from '/@/store/modules/system/app-config';
 | 
			
		||||
  import { feedbackApi } from '/@/api/support/feedback/feedback-api';
 | 
			
		||||
import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
  import { HOME_PAGE_NAME } from '/@/constants/system/home-const';
 | 
			
		||||
  import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
 | 
			
		||||
  function hideHelpDoc() {
 | 
			
		||||
    useAppConfigStore().hideHelpDoc();
 | 
			
		||||
@@ -142,11 +143,15 @@ import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
      //SmartAdmin中 router的name 就是 后端存储menu的id
 | 
			
		||||
      let menuId = -1;
 | 
			
		||||
      try {
 | 
			
		||||
        menuId = _.toNumber(currentRoute.name);
 | 
			
		||||
        if(currentRoute.name === HOME_PAGE_NAME){
 | 
			
		||||
          menuId = 0;
 | 
			
		||||
        }else{
 | 
			
		||||
          menuId = _.toNumber(currentRoute.name);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        smartSentry.captureError(e);
 | 
			
		||||
      }
 | 
			
		||||
      if (menuId > 0) {
 | 
			
		||||
      if (menuId > -1) {
 | 
			
		||||
        queryHelpDocList(menuId);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,11 @@ import { useUserStore } from '/@/store/modules/system/user';
 | 
			
		||||
import '/@/theme/index.less';
 | 
			
		||||
import { getTokenFromCookie } from '/@/utils/cookie-util';
 | 
			
		||||
 | 
			
		||||
let url = location.href;
 | 
			
		||||
if(url.indexOf('1024lab.net') > -1){
 | 
			
		||||
    location.href = "https://preview.smartadmin.vip";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * -------------------- ※ 着重 解释说明下main.js的初始化逻辑 begin ※ --------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <a-drawer
 | 
			
		||||
    :title="formData.helpDocId ? '编辑' : '新建'"
 | 
			
		||||
    :title="formData.helpDocId ? '编辑系统手册' : '新建系统手册'"
 | 
			
		||||
    :visible="visibleFlag"
 | 
			
		||||
    :width="1000"
 | 
			
		||||
    :footerStyle="{ textAlign: 'right' }"
 | 
			
		||||
@@ -29,7 +29,13 @@
 | 
			
		||||
      <a-form-item label="排序" name="sort">
 | 
			
		||||
        <a-input-number v-model:value="formData.sort" placeholder="值越小越靠前" />(值越小越靠前)
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="关联菜单">
 | 
			
		||||
      <a-form-item label="是否首页显示">
 | 
			
		||||
        <a-radio-group v-model:value="relateHomeFlag" button-style="solid">
 | 
			
		||||
          <a-radio-button :value="true">首页显示</a-radio-button>
 | 
			
		||||
          <a-radio-button :value="false">首页不用显示</a-radio-button>
 | 
			
		||||
        </a-radio-group>
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="关联菜单" v-if="!relateHomeFlag">
 | 
			
		||||
        <MenuTreeSelect v-model:value="formData.relationIdList" ref="menuTreeSelect" />
 | 
			
		||||
      </a-form-item>
 | 
			
		||||
      <a-form-item label="公告内容" name="contentHtml">
 | 
			
		||||
@@ -69,7 +75,7 @@
 | 
			
		||||
  import HelpDocCatalogTreeSelect from './help-doc-catalog-tree-select.vue';
 | 
			
		||||
  import MenuTreeSelect from '/@/components/system/menu-tree-select/index.vue';
 | 
			
		||||
  import _ from 'lodash';
 | 
			
		||||
import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
  import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
 | 
			
		||||
  const emits = defineEmits(['reloadList']);
 | 
			
		||||
 | 
			
		||||
@@ -99,6 +105,7 @@ import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
  const formRef = ref();
 | 
			
		||||
  const contentRef = ref();
 | 
			
		||||
  const noticeFormVisibleModal = ref();
 | 
			
		||||
  const relateHomeFlag = ref(false);
 | 
			
		||||
 | 
			
		||||
  const defaultFormData = {
 | 
			
		||||
    helpDocId: undefined,
 | 
			
		||||
@@ -135,6 +142,11 @@ import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
      }
 | 
			
		||||
      Object.assign(formData, result.data);
 | 
			
		||||
      formData.relationIdList = result.data.relationList ? result.data.relationList.map((e) => e.relationId) : [];
 | 
			
		||||
      if (formData.relationIdList.length === 1 && formData.relationIdList[0].relationId === 0) {
 | 
			
		||||
        relateHomeFlag.value = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        relateHomeFlag.value = false;
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      smartSentry.captureError(err);
 | 
			
		||||
    } finally {
 | 
			
		||||
@@ -161,8 +173,18 @@ import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
    try {
 | 
			
		||||
      SmartLoading.show();
 | 
			
		||||
      let param = _.cloneDeep(formData);
 | 
			
		||||
      let relationList = menuTreeSelect.value.getMenuListByIdList(formData.relationIdList);
 | 
			
		||||
      param.relationList = relationList.map((e) => Object.assign({}, { relationId: e.menuId, relationName: e.menuName }));
 | 
			
		||||
      // 首页显示的话,为0
 | 
			
		||||
      if (relateHomeFlag.value) {
 | 
			
		||||
        param.relationList = [
 | 
			
		||||
          {
 | 
			
		||||
            relationName: '首页',
 | 
			
		||||
            relationId: 0,
 | 
			
		||||
          },
 | 
			
		||||
        ];
 | 
			
		||||
      } else {
 | 
			
		||||
        let relationList = menuTreeSelect.value.getMenuListByIdList(formData.relationIdList);
 | 
			
		||||
        param.relationList = relationList.map((e) => Object.assign({}, { relationId: e.menuId, relationName: e.menuName }));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (param.helpDocId) {
 | 
			
		||||
        await helpDocApi.update(param);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@
 | 
			
		||||
      <div>
 | 
			
		||||
        关键字:
 | 
			
		||||
        <a-input style="width: 250px" v-model:value="queryForm.keywords" placeholder="姓名/手机号/登录账号" />
 | 
			
		||||
 | 
			
		||||
        <a-button class="button-style" v-if="selectRoleId" type="primary" @click="queryRoleEmployee">搜索</a-button>
 | 
			
		||||
        <a-button class="button-style" v-if="selectRoleId" type="default" @click="resetQueryRoleEmployee">重置</a-button>
 | 
			
		||||
      </div>
 | 
			
		||||
@@ -28,6 +27,7 @@
 | 
			
		||||
        >
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
    <a-table
 | 
			
		||||
      :loading="tableLoading"
 | 
			
		||||
      :dataSource="tableData"
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
      <a-col flex="200px">
 | 
			
		||||
        <RoleList ref="roleList" />
 | 
			
		||||
      </a-col>
 | 
			
		||||
      <a-col flex="1">
 | 
			
		||||
      <a-col flex="1" class="role-setting">
 | 
			
		||||
        <RoleSetting />
 | 
			
		||||
      </a-col>
 | 
			
		||||
    </a-row>
 | 
			
		||||
@@ -42,4 +42,7 @@
 | 
			
		||||
  .height100 {
 | 
			
		||||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .role-setting{
 | 
			
		||||
    width:calc(100% - 250px)
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
            height="60"
 | 
			
		||||
            frameborder="0"
 | 
			
		||||
            allowtransparency="true"
 | 
			
		||||
            src="//i.tianqi.com/index.php?c=code&id=12&icon=1&num=5&site=12"
 | 
			
		||||
            src="//i.tianqi.com/index.php?c=code&id=12&icon=1&num=3&site=12"
 | 
			
		||||
          ></iframe>
 | 
			
		||||
        </div>
 | 
			
		||||
      </a-row>
 | 
			
		||||
@@ -136,7 +136,7 @@
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
 | 
			
		||||
    .heart-sentence {
 | 
			
		||||
      width: calc(100% - 660px);
 | 
			
		||||
      width: calc(100% - 420px);
 | 
			
		||||
      h3 {
 | 
			
		||||
        color: rgba(0, 0, 0, 0.75);
 | 
			
		||||
      }
 | 
			
		||||
@@ -146,7 +146,7 @@
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      .weather {
 | 
			
		||||
        width: 650px;
 | 
			
		||||
        width: 400px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -70,11 +70,12 @@
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        width:50%;
 | 
			
		||||
        width: 50%;
 | 
			
		||||
        > img {
 | 
			
		||||
          width: 112px;
 | 
			
		||||
          height: 112px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .qr-desc {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
@@ -89,6 +90,37 @@
 | 
			
		||||
            margin-right: 9px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .qr-desc-marquee {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          margin-top: 11px;
 | 
			
		||||
          font-size: 12px;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          color: #ffffff;
 | 
			
		||||
 | 
			
		||||
          @keyframes marquee {
 | 
			
		||||
            0% {
 | 
			
		||||
              transform: translateX(0);
 | 
			
		||||
            }
 | 
			
		||||
            100% {
 | 
			
		||||
              transform: translateX(-220%);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .marquee {
 | 
			
		||||
            flex: 1;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            span {
 | 
			
		||||
              display: inline-block;
 | 
			
		||||
              width: 100%;
 | 
			
		||||
              white-space: nowrap;
 | 
			
		||||
              animation: marquee 15s linear infinite;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .login-title {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,8 @@
 | 
			
		||||
        <p>欢迎登录 SmartAdmin V2</p>
 | 
			
		||||
        <p class="desc">
 | 
			
		||||
          SmartAdmin 是由 河南·洛阳
 | 
			
		||||
          <a target="_blank" href="https://www.1024lab.net" style="color: white; weight: bolder; font-size: 15px; text-decoration: underline"
 | 
			
		||||
            >1024创新实验室(1024Lab)</a
 | 
			
		||||
          >
 | 
			
		||||
          <a target="_blank" href="https://www.1024lab.net"
 | 
			
		||||
            style="color: white; weight: bolder; font-size: 15px; text-decoration: underline">1024创新实验室(1024Lab)</a>
 | 
			
		||||
          使用SpringBoot2.x 和 Vue3.2 Setup语法糖、 Composition Api (同时支持JavaScript和TypeScript双版本) ,开发出的一套简洁、易用的中后台解决方案!
 | 
			
		||||
          <br />
 | 
			
		||||
          <br />
 | 
			
		||||
@@ -29,8 +28,9 @@
 | 
			
		||||
            保持谦逊,保持学习,热爱代码,更热爱生活 !<br />
 | 
			
		||||
            永远年轻,永远前行 !<br />
 | 
			
		||||
            <span class="author">
 | 
			
		||||
              <a target="_blank" href="https://zhuoda.vip" style="color: white;  font-size: 13px; text-decoration: underline">
 | 
			
		||||
                1024创新实验室-主任:卓大 ( 2022年 · 洛阳 )
 | 
			
		||||
              <a target="_blank" href="https://zhuoda.vip"
 | 
			
		||||
                style="color: white;  font-size: 13px; text-decoration: underline">
 | 
			
		||||
                1024创新实验室-主任:卓大 
 | 
			
		||||
              </a>
 | 
			
		||||
            </span>
 | 
			
		||||
          </span>
 | 
			
		||||
@@ -43,7 +43,7 @@
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="app-qr">
 | 
			
		||||
          <img :src="xiaozhen" />
 | 
			
		||||
          <marquee  class="qr-desc" scrolldelay="130"> 关注:小镇程序员,了解二三线城市程序员的代码与“钱途”,技术与生活,城市可能无法选择,但未来可以拼搏。</marquee>
 | 
			
		||||
          <div class="qr-desc-marquee"><div class="marquee"><span>关注:小镇程序员,了解二三线城市程序员的代码与“钱途”,技术与生活,城市可能无法选择,但未来可以拼搏。</span></div></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@@ -55,12 +55,8 @@
 | 
			
		||||
          <a-input v-model:value.trim="loginForm.loginName" placeholder="请输入用户名" />
 | 
			
		||||
        </a-form-item>
 | 
			
		||||
        <a-form-item name="password">
 | 
			
		||||
          <a-input-password
 | 
			
		||||
            v-model:value="loginForm.password"
 | 
			
		||||
            autocomplete="on"
 | 
			
		||||
            :type="showPassword ? 'text' : 'password'"
 | 
			
		||||
            placeholder="请输入密码"
 | 
			
		||||
          />
 | 
			
		||||
          <a-input-password v-model:value="loginForm.password" autocomplete="on"
 | 
			
		||||
            :type="showPassword ? 'text' : 'password'" placeholder="请输入密码" />
 | 
			
		||||
        </a-form-item>
 | 
			
		||||
        <a-form-item name="captchaCode">
 | 
			
		||||
          <a-input class="captcha-input" v-model:value.trim="loginForm.captchaCode" placeholder="请输入验证码" />
 | 
			
		||||
@@ -88,119 +84,117 @@
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup>
 | 
			
		||||
  import { message } from 'ant-design-vue';
 | 
			
		||||
  import { onMounted, onUnmounted, reactive, ref } from 'vue';
 | 
			
		||||
  import { useRouter } from 'vue-router';
 | 
			
		||||
  import { loginApi } from '/@/api/system/login/login-api';
 | 
			
		||||
  import { SmartLoading } from '/@/components/framework/smart-loading';
 | 
			
		||||
  import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
 | 
			
		||||
  import { useUserStore } from '/@/store/modules/system/user';
 | 
			
		||||
  import { saveTokenToCookie } from '/@/utils/cookie-util';
 | 
			
		||||
import { message } from 'ant-design-vue';
 | 
			
		||||
import { onMounted, onUnmounted, reactive, ref } from 'vue';
 | 
			
		||||
import { useRouter } from 'vue-router';
 | 
			
		||||
import { loginApi } from '/@/api/system/login/login-api';
 | 
			
		||||
import { SmartLoading } from '/@/components/framework/smart-loading';
 | 
			
		||||
import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
 | 
			
		||||
import { useUserStore } from '/@/store/modules/system/user';
 | 
			
		||||
import { saveTokenToCookie } from '/@/utils/cookie-util';
 | 
			
		||||
 | 
			
		||||
  import gongzhonghao from '/@/assets/images/1024lab/1024lab-gzh.jpg';
 | 
			
		||||
  import zhuoda from '/@/assets/images/1024lab/zhuoda-wechat.jpg';
 | 
			
		||||
  import loginQR from '/@/assets/images/login/login-qr.png';
 | 
			
		||||
  import xiaozhen from '/@/assets/images/1024lab/xiaozhen-gzh.jpg';
 | 
			
		||||
import gongzhonghao from '/@/assets/images/1024lab/1024lab-gzh.jpg';
 | 
			
		||||
import zhuoda from '/@/assets/images/1024lab/zhuoda-wechat.jpg';
 | 
			
		||||
import loginQR from '/@/assets/images/login/login-qr.png';
 | 
			
		||||
import xiaozhen from '/@/assets/images/1024lab/xiaozhen-gzh.jpg';
 | 
			
		||||
 | 
			
		||||
  import aliLogin from '/@/assets/images/login/ali-icon.png';
 | 
			
		||||
  import googleLogin from '/@/assets/images/login/google-icon.png';
 | 
			
		||||
  import qqLogin from '/@/assets/images/login/qq-icon.png';
 | 
			
		||||
  import weiboLogin from '/@/assets/images/login/weibo-icon.png';
 | 
			
		||||
import aliLogin from '/@/assets/images/login/ali-icon.png';
 | 
			
		||||
import googleLogin from '/@/assets/images/login/google-icon.png';
 | 
			
		||||
import qqLogin from '/@/assets/images/login/qq-icon.png';
 | 
			
		||||
import weiboLogin from '/@/assets/images/login/weibo-icon.png';
 | 
			
		||||
 | 
			
		||||
  import { buildRoutes } from '/@/router/index';
 | 
			
		||||
  import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
import { buildRoutes } from '/@/router/index';
 | 
			
		||||
import { smartSentry } from '/@/lib/smart-sentry';
 | 
			
		||||
 | 
			
		||||
  //--------------------- 登录表单 ---------------------------------
 | 
			
		||||
//--------------------- 登录表单 ---------------------------------
 | 
			
		||||
 | 
			
		||||
  const loginForm = reactive({
 | 
			
		||||
    loginName: 'admin',
 | 
			
		||||
    password: '',
 | 
			
		||||
    captchaCode: '',
 | 
			
		||||
    captchaUuid: '',
 | 
			
		||||
    loginDevice: LOGIN_DEVICE_ENUM.PC.value,
 | 
			
		||||
  });
 | 
			
		||||
  const rules = {
 | 
			
		||||
    loginName: [{ required: true, message: '用户名不能为空' }],
 | 
			
		||||
    password: [{ required: true, message: '密码不能为空' }],
 | 
			
		||||
    captchaCode: [{ required: true, message: '验证码不能为空' }],
 | 
			
		||||
const loginForm = reactive({
 | 
			
		||||
  loginName: 'admin',
 | 
			
		||||
  password: '',
 | 
			
		||||
  captchaCode: '',
 | 
			
		||||
  captchaUuid: '',
 | 
			
		||||
  loginDevice: LOGIN_DEVICE_ENUM.PC.value,
 | 
			
		||||
});
 | 
			
		||||
const rules = {
 | 
			
		||||
  loginName: [{ required: true, message: '用户名不能为空' }],
 | 
			
		||||
  password: [{ required: true, message: '密码不能为空' }],
 | 
			
		||||
  captchaCode: [{ required: true, message: '验证码不能为空' }],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showPassword = ref(false);
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const formRef = ref();
 | 
			
		||||
const rememberPwd = ref(false);
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  document.onkeyup = (e) => {
 | 
			
		||||
    if (e.keyCode == 13) {
 | 
			
		||||
      onLogin();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
  const showPassword = ref(false);
 | 
			
		||||
  const router = useRouter();
 | 
			
		||||
  const formRef = ref();
 | 
			
		||||
  const rememberPwd = ref(false);
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  document.onkeyup = null;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
  onMounted(() => {
 | 
			
		||||
    document.onkeyup = (e) => {
 | 
			
		||||
      if (e.keyCode == 13) {
 | 
			
		||||
        onLogin();
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  onUnmounted(() => {
 | 
			
		||||
    document.onkeyup = null;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  //登录
 | 
			
		||||
  async function onLogin() {
 | 
			
		||||
    formRef.value.validate().then(async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        SmartLoading.show();
 | 
			
		||||
        const res = await loginApi.login(loginForm);
 | 
			
		||||
        stopRefrestCaptchaInterval();
 | 
			
		||||
        saveTokenToCookie(res.data.token ? res.data.token : '');
 | 
			
		||||
        message.success('登录成功');
 | 
			
		||||
        //更新用户信息到pinia
 | 
			
		||||
        useUserStore().setUserLoginInfo(res.data);
 | 
			
		||||
        //构建系统的路由
 | 
			
		||||
        buildRoutes();
 | 
			
		||||
        router.push('/home');
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        if (e.data && e.data.code === 30001) {
 | 
			
		||||
          loginForm.captchaCode = '';
 | 
			
		||||
          getCaptcha();
 | 
			
		||||
        }
 | 
			
		||||
        smartSentry.captureError(e);
 | 
			
		||||
      } finally {
 | 
			
		||||
        SmartLoading.hide();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //--------------------- 验证码 ---------------------------------
 | 
			
		||||
 | 
			
		||||
  const captchaBase64Image = ref('');
 | 
			
		||||
  async function getCaptcha() {
 | 
			
		||||
//登录
 | 
			
		||||
async function onLogin() {
 | 
			
		||||
  formRef.value.validate().then(async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      let captchaResult = await loginApi.getCaptcha();
 | 
			
		||||
      captchaBase64Image.value = captchaResult.data.captchaBase64Image;
 | 
			
		||||
      loginForm.captchaUuid = captchaResult.data.captchaUuid;
 | 
			
		||||
      beginRefrestCaptchaInterval(captchaResult.data.expireSeconds);
 | 
			
		||||
      SmartLoading.show();
 | 
			
		||||
      const res = await loginApi.login(loginForm);
 | 
			
		||||
      stopRefrestCaptchaInterval();
 | 
			
		||||
      saveTokenToCookie(res.data.token ? res.data.token : '');
 | 
			
		||||
      message.success('登录成功');
 | 
			
		||||
      //更新用户信息到pinia
 | 
			
		||||
      useUserStore().setUserLoginInfo(res.data);
 | 
			
		||||
      //构建系统的路由
 | 
			
		||||
      buildRoutes();
 | 
			
		||||
      router.push('/home');
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.log(e);
 | 
			
		||||
      if (e.data && e.data.code === 30001) {
 | 
			
		||||
        loginForm.captchaCode = '';
 | 
			
		||||
        getCaptcha();
 | 
			
		||||
      }
 | 
			
		||||
      smartSentry.captureError(e);
 | 
			
		||||
    } finally {
 | 
			
		||||
      SmartLoading.hide();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  let refrestCaptchaInterval = null;
 | 
			
		||||
  function beginRefrestCaptchaInterval(expireSeconds) {
 | 
			
		||||
    if (refrestCaptchaInterval === null) {
 | 
			
		||||
      refrestCaptchaInterval = setInterval(getCaptcha, (expireSeconds - 5) * 1000);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
//--------------------- 验证码 ---------------------------------
 | 
			
		||||
 | 
			
		||||
  function stopRefrestCaptchaInterval() {
 | 
			
		||||
    if (refrestCaptchaInterval != null) {
 | 
			
		||||
      clearInterval(refrestCaptchaInterval);
 | 
			
		||||
      refrestCaptchaInterval = null;
 | 
			
		||||
    }
 | 
			
		||||
const captchaBase64Image = ref('');
 | 
			
		||||
async function getCaptcha() {
 | 
			
		||||
  try {
 | 
			
		||||
    let captchaResult = await loginApi.getCaptcha();
 | 
			
		||||
    captchaBase64Image.value = captchaResult.data.captchaBase64Image;
 | 
			
		||||
    loginForm.captchaUuid = captchaResult.data.captchaUuid;
 | 
			
		||||
    beginRefrestCaptchaInterval(captchaResult.data.expireSeconds);
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    console.log(e);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  onMounted(getCaptcha);
 | 
			
		||||
let refrestCaptchaInterval = null;
 | 
			
		||||
function beginRefrestCaptchaInterval(expireSeconds) {
 | 
			
		||||
  if (refrestCaptchaInterval === null) {
 | 
			
		||||
    refrestCaptchaInterval = setInterval(getCaptcha, (expireSeconds - 5) * 1000);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function stopRefrestCaptchaInterval() {
 | 
			
		||||
  if (refrestCaptchaInterval != null) {
 | 
			
		||||
    clearInterval(refrestCaptchaInterval);
 | 
			
		||||
    refrestCaptchaInterval = null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(getCaptcha);
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="less" scoped>
 | 
			
		||||
  @import './login.less';
 | 
			
		||||
</style>
 | 
			
		||||
<style lang="less" scoped>@import './login.less';</style>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user