mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-14 06:33:47 +08:00
v3.0.0
This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_PAGE_NAME } from '/@/constants/system/home-const';
|
||||
|
||||
const router = useRouter();
|
||||
function goHome() {
|
||||
useRouter().push({ name: HOME_PAGE_NAME });
|
||||
router.push({ name: HOME_PAGE_NAME });
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-result status="404 title="对不起,您访问的内容不存在!">
|
||||
<a-result status="404" title="对不起,您访问的内容不存在!">
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="goHome">返回首页</a-button>
|
||||
</template>
|
||||
@@ -18,7 +18,8 @@
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HOME_PAGE_NAME } from '/@/constants/system/home-const';
|
||||
|
||||
const router = useRouter();
|
||||
function goHome() {
|
||||
useRouter().push({ name: HOME_PAGE_NAME });
|
||||
router.push({ name: HOME_PAGE_NAME });
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import emitter from '/@/views/system/employee/department/department-mitt';
|
||||
import emitter from '../../department-mitt';
|
||||
|
||||
const props = defineProps({
|
||||
breadcrumb: Array,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" :title="formState.departmentId ? '编辑部门' : '添加部门'" @ok="handleOk" destroyOnClose>
|
||||
<a-modal v-model:open="visible" :title="formState.departmentId ? '编辑部门' : '添加部门'" @ok="handleOk" destroyOnClose>
|
||||
<a-form ref="formRef" :model="formState" :rules="rules" layout="vertical">
|
||||
<a-form-item label="上级部门" name="parentId" v-if="formState.parentId != 0">
|
||||
<DepartmentTreeSelect ref="departmentTreeSelect" v-model:value="formState.parentId" :defaultValueFlag="false" width="100%" />
|
||||
@@ -28,7 +28,7 @@
|
||||
<script setup lang="ts">
|
||||
import message from 'ant-design-vue/lib/message';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { departmentApi } from '/@/api/system/department/department-api';
|
||||
import { departmentApi } from '/@/api/system/department-api';
|
||||
import DepartmentTreeSelect from '/@/components/system/department-tree-select/index.vue';
|
||||
import EmployeeSelect from '/@/components/system/employee-select/index.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
@@ -69,9 +69,9 @@
|
||||
import _ from 'lodash';
|
||||
import { createVNode, onMounted } from 'vue';
|
||||
import DepartmentFormModal from '../department-form-modal/index.vue';
|
||||
import { departmentApi } from '/@/api/system/department/department-api';
|
||||
import { departmentApi } from '/@/api/system/department-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import departmentEmitter from '/@/views/system/employee/department/department-mitt';
|
||||
import departmentEmitter from '../../department-mitt';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const DEPARTMENT_PARENT_ID = 0;
|
||||
@@ -330,7 +330,6 @@
|
||||
|
||||
.sort-span {
|
||||
margin-left: 5px;
|
||||
color: @success-color;
|
||||
}
|
||||
.no-data {
|
||||
margin: 10px;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="调整部门" :footer="null" destroyOnClose>
|
||||
<a-modal v-model:open="visible" title="调整部门" :footer="null" destroyOnClose>
|
||||
<DepartmentTree ref="departmentTree" :height="400" :showMenu="false" />
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 8px" @click="closeModal">取消</a-button>
|
||||
@@ -18,12 +18,12 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { ref } from 'vue';
|
||||
import DepartmentTree from '../department-tree/index.vue';
|
||||
import { employeeApi } from '/@/api/system/employee/employee-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import _ from 'lodash';
|
||||
import { ref } from 'vue';
|
||||
import DepartmentTree from '../department-tree/index.vue';
|
||||
import { employeeApi } from '/@/api/system/employee-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
|
||||
// ----------------------- 以下是字段定义 emits props ---------------------
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<a-drawer
|
||||
:title="form.employeeId ? '编辑' : '添加'"
|
||||
:width="600"
|
||||
:visible="visible"
|
||||
:open="visible"
|
||||
:body-style="{ paddingBottom: '80px' }"
|
||||
@close="onClose"
|
||||
destroyOnClose
|
||||
@@ -56,8 +56,8 @@
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import { employeeApi } from '/@/api/system/employee/employee-api';
|
||||
import { roleApi } from '/@/api/system/role/role-api';
|
||||
import { employeeApi } from '/@/api/system/employee-api';
|
||||
import { roleApi } from '/@/api/system/role-api';
|
||||
import DepartmentTreeSelect from '/@/components/system/department-tree-select/index.vue';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
import { GENDER_ENUM } from '/@/constants/common-const';
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { computed, createVNode, reactive, ref, watch } from 'vue';
|
||||
import { employeeApi } from '/@/api/system/employee/employee-api';
|
||||
import { employeeApi } from '/@/api/system/employee-api';
|
||||
import { PAGE_SIZE } from '/@/constants/common-const';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import EmployeeFormModal from '../employee-form-modal/index.vue';
|
||||
@@ -202,7 +202,7 @@
|
||||
params.departmentId = props.departmentId;
|
||||
let res = await employeeApi.queryEmployee(params);
|
||||
for (const item of res.data.list) {
|
||||
item.roleNameList = _.join(item.roleNameList,',');
|
||||
item.roleNameList = _.join(item.roleNameList, ',');
|
||||
}
|
||||
tableData.value = res.data.list;
|
||||
total.value = res.data.total;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" :zIndex="9999" :width="500" title="提示" :closable="false" :maskClosable="false">
|
||||
<a-modal v-model:open="visible" :zIndex="9999" :width="500" title="提示" :closable="false" :maskClosable="false">
|
||||
<!-- -->
|
||||
<ul>
|
||||
<li>登录名: {{ showLoginName }}</li>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div>
|
||||
<div class="btn-group">
|
||||
<a-button class="button-style" type="primary" @click="updateDataScope" v-privilege="'system:role:dataScope:update'"> 保存 </a-button>
|
||||
<a-button class="button-style" @click="getDataScope" v-privilege="'role:query'"> 刷新 </a-button>
|
||||
<a-button class="button-style" @click="getDataScope" > 刷新 </a-button>
|
||||
</div>
|
||||
<a-row class="header">
|
||||
<a-col class="tab-margin" :span="4">业务单据</a-col>
|
||||
@@ -46,7 +46,7 @@
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { inject, onMounted, ref, watch } from 'vue';
|
||||
import { roleApi } from '/@/api/system/role/role-api';
|
||||
import { roleApi } from '/@/api/system/role-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<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="primary" @click="onSearch">搜索</a-button>
|
||||
<a-button class="button-style" v-if="selectRoleId" type="default" @click="resetQueryRoleEmployee">重置</a-button>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { computed, inject, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { roleApi } from '/@/api/system/role/role-api';
|
||||
import { roleApi } from '/@/api/system/role-api';
|
||||
import { PAGE_SIZE, showTableTotal, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import EmployeeTableSelectModal from '/@/components/system/employee-table-select-modal/index.vue';
|
||||
@@ -110,6 +110,11 @@
|
||||
queryRoleEmployee();
|
||||
}
|
||||
|
||||
function onSearch(){
|
||||
queryForm.pageNum = 1;
|
||||
queryRoleEmployee();
|
||||
}
|
||||
|
||||
async function queryRoleEmployee() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
*
|
||||
-->
|
||||
<template>
|
||||
<a-modal :title="form.roleId ? '编辑角色' : '添加角色'" :width="600" :visible="modalVisible" @cancel="onClose" :footer="null">
|
||||
<a-modal :title="form.roleId ? '编辑角色' : '添加角色'" :width="600" :open="modalVisible" @cancel="onClose" :footer="null">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :labelCol="{ span: 4 }">
|
||||
<a-form-item label="角色名称" name="roleName">
|
||||
<a-input style="width: 100%" placeholder="请输入角色名称" v-model:value="form.roleName" />
|
||||
</a-form-item>
|
||||
<a-form-item label="角色编码" name="roleCode">
|
||||
<a-input style="width: 100%" placeholder="请输入角色编码" v-model:value="form.roleCode" />
|
||||
</a-form-item>
|
||||
<a-form-item label="角色备注">
|
||||
<a-input style="width: 100%" placeholder="请输入角色备注" v-model:value="form.remark" />
|
||||
</a-form-item>
|
||||
@@ -29,8 +32,8 @@
|
||||
<script setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { roleApi } from '/@/api/system/role/role-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { roleApi } from '/@/api/system/role-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
// ----------------------- 以下是字段定义 emits props ---------------------
|
||||
let emits = defineEmits(['refresh']);
|
||||
@@ -62,6 +65,7 @@ import { smartSentry } from '/@/lib/smart-sentry';
|
||||
const formDefault = {
|
||||
id: undefined,
|
||||
remark: undefined,
|
||||
roleCode: undefined,
|
||||
roleName: undefined,
|
||||
};
|
||||
|
||||
@@ -70,6 +74,7 @@ import { smartSentry } from '/@/lib/smart-sentry';
|
||||
// 表单规则
|
||||
const rules = {
|
||||
roleName: [{ required: true, message: '请输入角色名称' }],
|
||||
roleCode: [{ required: true, message: '请输入角色编码' }],
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { roleApi } from '/@/api/system/role/role-api';
|
||||
import { roleApi } from '/@/api/system/role-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import RoleFormModal from '../role-form-modal/index.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import RoleTreeCheckbox from './role-tree-checkbox.vue';
|
||||
import { roleMenuApi } from '/@/api/system/role-menu/role-menu-api';
|
||||
import { roleMenuApi } from '/@/api/system/role-menu-api';
|
||||
import { useRoleStore } from '/@/store/modules/system/role';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
-->
|
||||
<template>
|
||||
<div style="height: 542px; overflow: auto">
|
||||
<div style="overflow: auto">
|
||||
<a-checkbox-group v-model:value="checkedData">
|
||||
<div class="checked-box">
|
||||
<ul>
|
||||
@@ -32,7 +32,7 @@
|
||||
default: [],
|
||||
},
|
||||
});
|
||||
defineEmits('update:value');
|
||||
defineEmits(['update:value']);
|
||||
|
||||
let roleStore = useRoleStore();
|
||||
let checkedData = ref();
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
defineEmits('update:value');
|
||||
defineEmits(['update:value']);
|
||||
let roleStore = useRoleStore();
|
||||
function selectCheckbox(module) {
|
||||
if (!module.menuId) {
|
||||
|
||||
@@ -28,6 +28,6 @@
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
let emits = defineEmits('selectCheckbox');
|
||||
let emits = defineEmits(['selectCheckbox']);
|
||||
</script>
|
||||
<style scoped lang="less"></style>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
defineProps({
|
||||
value: Object,
|
||||
});
|
||||
defineEmits('update:value');
|
||||
defineEmits(['update:value']);
|
||||
|
||||
let roleList = ref();
|
||||
const selectRoleId = computed(() => {
|
||||
@@ -42,7 +42,7 @@
|
||||
.height100 {
|
||||
height: 100%;
|
||||
}
|
||||
.role-setting{
|
||||
width:calc(100% - 250px)
|
||||
.role-setting {
|
||||
width: calc(100% - 250px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { changeLogApi } from '/@/api/support/change-log/change-log-api';
|
||||
import { changeLogApi } from '/@/api/support/change-log-api';
|
||||
import DefaultHomeCard from '/@/views/system/home/components/default-home-card.vue';
|
||||
import ChangeLogForm from '/@/views/support/change-log/change-log-modal.vue';
|
||||
|
||||
@@ -88,20 +88,7 @@
|
||||
|
||||
.time {
|
||||
flex-shrink: 0;
|
||||
color: @text-color-secondary;
|
||||
min-width: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
ul li :hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
.un-read a {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.read a {
|
||||
color: @text-color-secondary;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<default-home-card icon="ProfileTwoTone" title="【1024创新实验室】人员饭量">
|
||||
<default-home-card icon="ProfileTwoTone" title="销量统计">
|
||||
<div class="echarts-box">
|
||||
<div class="category-main" id="category-main"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<default-home-card icon="FundTwoTone" title="【1024创新实验室】代码提交量">
|
||||
<default-home-card icon="FundTwoTone" title="代码提交量">
|
||||
<div class="echarts-box">
|
||||
<div class="gradient-main" id="gradient-main"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<default-home-card icon="PieChartTwoTone" title="【1024创新实验室】上班摸鱼次数">
|
||||
<default-home-card icon="PieChartTwoTone" title="加班统计">
|
||||
<div class="echarts-box">
|
||||
<div class="pie-main" id="pie-main"></div>
|
||||
</div>
|
||||
@@ -25,7 +25,7 @@ function init(){
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '摸鱼次数',
|
||||
name: '加班次数',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
-->
|
||||
<template>
|
||||
<default-home-card icon="SmileTwoTone" title="添加微信,关注【小镇程序员】、【1024创新实验室】">
|
||||
<default-home-card icon="SmileTwoTone" title="联系我们">
|
||||
<div class="app-qr-box">
|
||||
<div class="app-qr">
|
||||
<img :src="zhuoda" />
|
||||
@@ -18,22 +18,16 @@
|
||||
</div>
|
||||
<div class="app-qr">
|
||||
<img :src="xiaozhen" />
|
||||
<span class="qr-desc strong"> 小镇程序员 </span>
|
||||
<span class="qr-desc"> 代码与生活,还有钱途 </span>
|
||||
</div>
|
||||
<div class="app-qr">
|
||||
<img :src="lab1024" />
|
||||
<span class="qr-desc strong"> 1024创新实验室 </span>
|
||||
<span class="qr-desc"> 官方账号 </span>
|
||||
<span class="qr-desc strong"> 六边形工程师 </span>
|
||||
<span class="qr-desc"> 赚钱、代码、生活 </span>
|
||||
</div>
|
||||
</div>
|
||||
</default-home-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import DefaultHomeCard from '/@/views/system/home/components/default-home-card.vue';
|
||||
import lab1024 from '/@/assets/images/1024lab/1024lab-gzh.jpg';
|
||||
import zhuoda from '/@/assets/images/1024lab/zhuoda-wechat.jpg';
|
||||
import xiaozhen from '/@/assets/images/1024lab/xiaozhen-gzh.jpg';
|
||||
import xiaozhen from '/@/assets/images/1024lab/gzh.jpg';
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.app-qr-box {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="新建快捷入口" @close="onClose">
|
||||
<a-modal v-model:open="visible" title="新建快捷入口" @close="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules">
|
||||
<a-form-item label="图标" name="icon">
|
||||
<IconSelect @updateIcon="selectIcon">
|
||||
<template #iconSelect>
|
||||
<a-input v-model:value="form.icon" placeholder="请输入菜单图标" style="width: 200px"/>
|
||||
<component :is="$antIcons[form.icon]" class="smart-margin-left15" style="font-size: 20px"/>
|
||||
<a-input v-model:value="form.icon" placeholder="请输入菜单图标" style="width: 200px" />
|
||||
<component :is="$antIcons[form.icon]" class="smart-margin-left15" style="font-size: 20px" />
|
||||
</template>
|
||||
</IconSelect>
|
||||
</a-form-item>
|
||||
<a-form-item label="标题" name="title">
|
||||
<a-input v-model:value="form.title" placeholder="请输入标题"/>
|
||||
<a-input v-model:value="form.title" placeholder="请输入标题" />
|
||||
</a-form-item>
|
||||
<a-form-item label="路径" name="path">
|
||||
<a-input v-model:value="form.path" placeholder="请输入路径"/>
|
||||
<a-input v-model:value="form.path" placeholder="请输入路径" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
@@ -23,59 +23,58 @@
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup>
|
||||
import {reactive, ref} from "vue";
|
||||
import {message} from "ant-design-vue";
|
||||
import IconSelect from '/@/components/framework/icon-select/index.vue';
|
||||
import _ from "lodash";
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import IconSelect from '/@/components/framework/icon-select/index.vue';
|
||||
import _ from 'lodash';
|
||||
|
||||
defineExpose({
|
||||
showModal
|
||||
})
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
|
||||
const emit = defineEmits("addQuickEntry");
|
||||
const emit = defineEmits(['addQuickEntry']);
|
||||
|
||||
// 组件ref
|
||||
const formRef = ref();
|
||||
// 组件ref
|
||||
const formRef = ref();
|
||||
|
||||
const formDefault = {
|
||||
icon: undefined,
|
||||
title: "",
|
||||
path: "",
|
||||
};
|
||||
let form = reactive({...formDefault});
|
||||
const rules = {
|
||||
icon: [{required: true, message: "请选择图标"}],
|
||||
title: [{required: true, message: "标题不能为空"}],
|
||||
path: [{required: true, message: "路径不能为空"}],
|
||||
};
|
||||
const formDefault = {
|
||||
icon: undefined,
|
||||
title: '',
|
||||
path: '',
|
||||
};
|
||||
let form = reactive({ ...formDefault });
|
||||
const rules = {
|
||||
icon: [{ required: true, message: '请选择图标' }],
|
||||
title: [{ required: true, message: '标题不能为空' }],
|
||||
path: [{ required: true, message: '路径不能为空' }],
|
||||
};
|
||||
|
||||
const visible = ref(false);
|
||||
const visible = ref(false);
|
||||
|
||||
function showModal() {
|
||||
visible.value = true;
|
||||
}
|
||||
function showModal() {
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
function selectIcon(icon) {
|
||||
form.icon = icon;
|
||||
}
|
||||
function selectIcon(icon) {
|
||||
form.icon = icon;
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
Object.assign(form, formDefault);
|
||||
visible.value = false;
|
||||
}
|
||||
function onClose() {
|
||||
Object.assign(form, formDefault);
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
emit("addQuickEntry", _.cloneDeep(form));
|
||||
emit('addQuickEntry', _.cloneDeep(form));
|
||||
onClose();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error", error);
|
||||
message.error("参数验证错误,请仔细填写表单数据!");
|
||||
console.log('error', error);
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang='less' scoped></style>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export default [
|
||||
'每个人的一生好比一根蜡烛,看似不经意间散发的光和热,都可能照亮和温暖他人。这是生活赋予我们的智慧,也让我们在寻常的日子成为一个温暖善良的人。',
|
||||
'立规矩的目的,不是禁锢、限制,而是教育;孩子犯了错,父母不能帮孩子逃避,而应该让孩子学会承担责任。让孩子有面对错误的诚实和勇气,这才是立规矩的意义所在。',
|
||||
'人这一辈子,格局大了、善良有了,成功自然也就近了。格局越大,人生越宽。你的人生会是什么样,与你在为人处世时的表现有很大关系。世间美好都是环环相扣的,善良的人总不会被亏待。',
|
||||
'平日里的千锤百炼,才能托举出光彩时刻;逆境中的亮剑、失败后的奋起,才能让梦想成真。哪有什么一战成名,其实都是百炼成钢。“天才”都是汗水浇灌出来的,天赋或许可以决定起点,但唯有坚持和努力才能达到终点。',
|
||||
'家,不在于奢华,而在于温馨;家,不在于大小,而在于珍惜。在家里,有父母的呵护,有爱人的陪伴,有子女的欢笑。一家人整整齐齐、和和睦睦,就是人生最大的幸福!',
|
||||
'每一个不向命运低头、努力生活的人,都值得被尊重。',
|
||||
'青年的肩上,从不只有清风明月,更有责任担当。岁月因青春慨然以赴而更加美好,世间因少年挺身向前而更加瑰丽。请相信,不会有人永远年轻,但永远有人年轻。',
|
||||
'人生路上,总有人走得比你快,但不必介意,也不必着急。一味羡慕别人的成绩,只会给自己平添压力、徒增烦恼。不盲从别人的脚步,坚定目标,才能找到自己的节奏,进而逢山开路、遇水搭桥。',
|
||||
'如果你真的在乎一个人,首先要学会的就是感恩对方的好。这样,对方才会在和你的相处中找到价值感,相处起来也会更加舒适愉悦。',
|
||||
'一个人只有心里装得下别人,有换位思考的品质,有为他人谋幸福的信念,才能真正做到慷慨施予。同样,也只有赠人玫瑰而无所求时,你才会手有余香、真有所得。',
|
||||
];
|
||||
@@ -10,26 +10,23 @@
|
||||
-->
|
||||
<template>
|
||||
<div class="user-header">
|
||||
<a-page-header :title="welcomeSentence" :sub-title="departmentName" >
|
||||
<template #tags>
|
||||
<a-tag color="blue">努力工作</a-tag>
|
||||
<a-tag color="success">主动 / 皮实 / 可靠 </a-tag>
|
||||
<a-tag color="error">自省 / 精进 / 创新</a-tag>
|
||||
<a-page-header :title="welcomeSentence">
|
||||
<template #subTitle>
|
||||
<span style="color: #666; margin-left: 20px;">所属部门:{{ departmentName }} </span>
|
||||
</template>
|
||||
<template #extra>
|
||||
<p>{{ dayInfo }}</p>
|
||||
<p style="color: #333">{{ dayInfo }}</p>
|
||||
</template>
|
||||
<a-row class="content">
|
||||
<span class="heart-sentence">
|
||||
<h3>{{ heartSentence }}</h3>
|
||||
<p class="last-login-info">{{ lastLoginInfo }}</p>
|
||||
<div></div>
|
||||
<span class="left-content">
|
||||
<p class="last-login-info"><AlertOutlined />{{ lastLoginInfo }}</p>
|
||||
<a class="sentence" href="https://sentence.1024lab.net/" target="_blank"> <smile-outlined spin /> {{ heartSentence }} </a>
|
||||
</span>
|
||||
<div class="weather">
|
||||
<iframe
|
||||
width="100%"
|
||||
scrolling="no"
|
||||
height="60"
|
||||
height="50"
|
||||
frameborder="0"
|
||||
allowtransparency="true"
|
||||
src="//i.tianqi.com/index.php?c=code&id=12&icon=1&num=3&site=12"
|
||||
@@ -45,10 +42,11 @@
|
||||
import uaparser from 'ua-parser-js';
|
||||
import { Solar, Lunar } from 'lunar-javascript';
|
||||
import _ from 'lodash';
|
||||
import heartSentenceArray from './heart-sentence';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const departmentName = computed(() => useUserStore.departmentName);
|
||||
const departmentName = computed(() => userStore.departmentName);
|
||||
|
||||
// 欢迎语
|
||||
const welcomeSentence = computed(() => {
|
||||
@@ -74,9 +72,7 @@
|
||||
if (userStore.$state.lastLoginTime) {
|
||||
info = info + '上次登录:' + userStore.$state.lastLoginTime;
|
||||
}
|
||||
if (userStore.$state.lastLoginIp) {
|
||||
info = info + '; IP:' + userStore.$state.lastLoginIp;
|
||||
}
|
||||
|
||||
if (userStore.$state.lastLoginUserAgent) {
|
||||
let ua = uaparser(userStore.$state.lastLoginUserAgent);
|
||||
info = info + '; 设备:';
|
||||
@@ -88,9 +84,16 @@
|
||||
}
|
||||
let device = ua.device.vendor ? ua.device.vendor + ua.device.model : null;
|
||||
if (device) {
|
||||
info = info + ' ' + device;
|
||||
info = info + ' ' + device + ';';
|
||||
}
|
||||
}
|
||||
|
||||
if (userStore.$state.lastLoginIpRegion) {
|
||||
info = info + '; ' + userStore.$state.lastLoginIpRegion;
|
||||
}
|
||||
if (userStore.$state.lastLoginIp) {
|
||||
info = info + '; ' + userStore.$state.lastLoginIp;
|
||||
}
|
||||
return info;
|
||||
});
|
||||
|
||||
@@ -113,18 +116,6 @@
|
||||
});
|
||||
|
||||
// 毒鸡汤
|
||||
const heartSentenceArray = [
|
||||
'每个人的一生好比一根蜡烛,看似不经意间散发的光和热,都可能照亮和温暖他人。这是生活赋予我们的智慧,也让我们在寻常的日子成为一个温暖善良的人。',
|
||||
'立规矩的目的,不是禁锢、限制,而是教育;孩子犯了错,父母不能帮孩子逃避,而应该让孩子学会承担责任。让孩子有面对错误的诚实和勇气,这才是立规矩的意义所在。',
|
||||
'人这一辈子,格局大了、善良有了,成功自然也就近了。格局越大,人生越宽。你的人生会是什么样,与你在为人处世时的表现有很大关系。世间美好都是环环相扣的,善良的人总不会被亏待。',
|
||||
'平日里的千锤百炼,才能托举出光彩时刻;逆境中的亮剑、失败后的奋起,才能让梦想成真。哪有什么一战成名,其实都是百炼成钢。“天才”都是汗水浇灌出来的,天赋或许可以决定起点,但唯有坚持和努力才能达到终点。',
|
||||
'家,不在于奢华,而在于温馨;家,不在于大小,而在于珍惜。在家里,有父母的呵护,有爱人的陪伴,有子女的欢笑。一家人整整齐齐、和和睦睦,就是人生最大的幸福!',
|
||||
'每一个不向命运低头、努力生活的人,都值得被尊重。',
|
||||
'青年的肩上,从不只有清风明月,更有责任担当。岁月因青春慨然以赴而更加美好,世间因少年挺身向前而更加瑰丽。请相信,不会有人永远年轻,但永远有人年轻。',
|
||||
'人生路上,总有人走得比你快,但不必介意,也不必着急。一味羡慕别人的成绩,只会给自己平添压力、徒增烦恼。不盲从别人的脚步,坚定目标,才能找到自己的节奏,进而逢山开路、遇水搭桥。',
|
||||
'如果你真的在乎一个人,首先要学会的就是感恩对方的好。这样,对方才会在和你的相处中找到价值感,相处起来也会更加舒适愉悦。',
|
||||
'一个人只有心里装得下别人,有换位思考的品质,有为他人谋幸福的信念,才能真正做到慷慨施予。同样,也只有赠人玫瑰而无所求时,你才会手有余香、真有所得。',
|
||||
];
|
||||
const heartSentence = computed(() => {
|
||||
return heartSentenceArray[_.random(0, heartSentenceArray.length - 1)];
|
||||
});
|
||||
@@ -135,7 +126,7 @@
|
||||
background-color: #fff;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.heart-sentence {
|
||||
.left-content {
|
||||
width: calc(100% - 420px);
|
||||
h3 {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
@@ -152,8 +143,23 @@
|
||||
|
||||
.last-login-info {
|
||||
font-size: 13px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
color: #333;
|
||||
overflow-wrap: break-word;
|
||||
padding: 0;
|
||||
margin: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.sentence {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #acacac;
|
||||
overflow-wrap: break-word;
|
||||
padding: 5px 0 0 0;
|
||||
margin: 6px 0 0 0;
|
||||
}
|
||||
.sentence:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,32 +11,36 @@
|
||||
<template>
|
||||
<default-home-card extra="更多" icon="SoundTwoTone" title="通知公告" @extraClick="onMore">
|
||||
<a-spin :spinning="loading">
|
||||
<div class="content-wrapper">
|
||||
<a-empty v-if="$lodash.isEmpty(data)" />
|
||||
<ul v-else>
|
||||
<li v-for="(item, index) in data" :key="index" :class="[item.viewFlag ? 'read' : 'un-read']">
|
||||
<a-tooltip placement="top">
|
||||
<template #title>
|
||||
<span>{{ item.title }}</span>
|
||||
</template>
|
||||
<a class="content" @click="toDetail(item.noticeId)">
|
||||
<a-badge :status="item.viewFlag ? 'default' : 'error'" />
|
||||
{{ item.title }}
|
||||
</a>
|
||||
</a-tooltip>
|
||||
<span class="time"> {{ item.publishDate }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content-wrapper">
|
||||
<a-empty v-if="$lodash.isEmpty(data)" />
|
||||
<ul v-else>
|
||||
<li v-for="(item, index) in data" :key="index" :class="[item.viewFlag ? 'read' : 'un-read']">
|
||||
<a-tooltip placement="top">
|
||||
<template #title>
|
||||
<span>{{ item.title }}</span>
|
||||
</template>
|
||||
<a class="content" @click="toDetail(item.noticeId)">
|
||||
<a-badge :status="item.viewFlag ? 'default' : 'error'" />
|
||||
{{ item.title }}
|
||||
</a>
|
||||
</a-tooltip>
|
||||
<span class="time"> {{ item.publishDate }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</a-spin>
|
||||
</default-home-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import DefaultHomeCard from '/@/views/system/home/components/default-home-card.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import DefaultHomeCard from '/@/views/system/home/components/default-home-card.vue';
|
||||
import { theme } from 'ant-design-vue';
|
||||
const { useToken } = theme;
|
||||
const { token } = useToken();
|
||||
const colorPrimary = token.value.colorPrimary;
|
||||
|
||||
const props = defineProps({
|
||||
noticeTypeId: {
|
||||
@@ -90,7 +94,7 @@ import DefaultHomeCard from '/@/views/system/home/components/default-home-card.v
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@read-color: #666;
|
||||
.content-wrapper{
|
||||
.content-wrapper {
|
||||
height: 150px;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
@@ -106,6 +110,7 @@ import DefaultHomeCard from '/@/views/system/home/components/default-home-card.v
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
margin-right: 5px;
|
||||
color: v-bind(colorPrimary);
|
||||
}
|
||||
|
||||
.time {
|
||||
@@ -115,15 +120,7 @@ import DefaultHomeCard from '/@/views/system/home/components/default-home-card.v
|
||||
}
|
||||
}
|
||||
|
||||
ul li :hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
.un-read a {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.read a {
|
||||
color: @read-color;
|
||||
color: @read-color !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
margin: 40px 0 60px 0;
|
||||
line-height: 21px;
|
||||
|
||||
.setence {
|
||||
font-size: 13px;
|
||||
@@ -106,7 +107,7 @@
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-220%);
|
||||
transform: translateX(-30%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
animation: marquee 15s linear infinite;
|
||||
animation: marquee 5s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,10 +129,9 @@
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
color: #1e1e1e;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
.login-form {
|
||||
margin-top: 37px;
|
||||
|
||||
.captcha-input {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
<div class="login-container">
|
||||
<div class="box-item desc">
|
||||
<div class="welcome">
|
||||
<p>欢迎登录 SmartAdmin V2</p>
|
||||
<p>欢迎登录 SmartAdmin V3</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>
|
||||
使用SpringBoot2.x 和 Vue3.2 Setup语法糖、 Composition Api (同时支持JavaScript和TypeScript双版本) ,开发出的一套简洁、易用的中后台解决方案!
|
||||
<a target="_blank" href="https://www.1024lab.net" style="color: white; weight: bolder; font-size: 15px; text-decoration: underline"
|
||||
>1024创新实验室(1024Lab)</a
|
||||
>
|
||||
基于SpringBoot + Sa-Token + Mybatis-Plus 和 Vue3 + Vite5 + Ant Design Vue 4 (同时支持JavaScript和TypeScript双版本)
|
||||
以「高质量代码」为核心,「简洁、高效、安全」的快速开发平台。
|
||||
<br />
|
||||
<br />
|
||||
<span class="setence">
|
||||
@@ -28,9 +30,8 @@
|
||||
保持谦逊,保持学习,热爱代码,更热爱生活 !<br />
|
||||
永远年轻,永远前行 !<br />
|
||||
<span class="author">
|
||||
<a target="_blank" href="https://zhuoda.vip"
|
||||
style="color: white; font-size: 13px; text-decoration: underline">
|
||||
1024创新实验室-主任:卓大
|
||||
<a target="_blank" href="https://zhuoda.vip" style="color: white; font-size: 13px; text-decoration: underline">
|
||||
1024创新实验室-主任:卓大
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
@@ -42,8 +43,12 @@
|
||||
<span class="qr-desc"> 加微信,骚扰卓大 :) </span>
|
||||
</div>
|
||||
<div class="app-qr">
|
||||
<img :src="xiaozhen" />
|
||||
<div class="qr-desc-marquee"><div class="marquee"><span>关注:小镇程序员,了解二三线城市程序员的代码与“钱途”,技术与生活,城市可能无法选择,但未来可以拼搏。</span></div></div>
|
||||
<img :src="gzh" />
|
||||
<div class="qr-desc-marquee">
|
||||
<div class="marquee">
|
||||
<span>关注:六边形工程师,分享:赚钱、代码、生活</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,8 +60,12 @@
|
||||
<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="请输入密码:至少三种字符,最小 8 位"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="captchaCode">
|
||||
<a-input class="captcha-input" v-model:value.trim="loginForm.captchaCode" placeholder="请输入验证码" />
|
||||
@@ -84,117 +93,124 @@
|
||||
</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-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 gzh from '/@/assets/images/1024lab/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';
|
||||
import { encryptData } from '/@/lib/encrypt';
|
||||
|
||||
//--------------------- 登录表单 ---------------------------------
|
||||
//--------------------- 登录表单 ---------------------------------
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
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 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);
|
||||
|
||||
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(() => {
|
||||
document.onkeyup = (e) => {
|
||||
if (e.keyCode == 13) {
|
||||
onLogin();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
document.onkeyup = null;
|
||||
});
|
||||
|
||||
//登录
|
||||
async function onLogin() {
|
||||
formRef.value.validate().then(async () => {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
// 密码加密
|
||||
let encryptPasswordForm = Object.assign({}, loginForm, {
|
||||
password: encryptData(loginForm.password),
|
||||
});
|
||||
const res = await loginApi.login(encryptPasswordForm);
|
||||
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 !== 0) {
|
||||
loginForm.captchaCode = '';
|
||||
getCaptcha();
|
||||
}
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let refrestCaptchaInterval = null;
|
||||
function beginRefrestCaptchaInterval(expireSeconds) {
|
||||
if (refrestCaptchaInterval === null) {
|
||||
refrestCaptchaInterval = setInterval(getCaptcha, (expireSeconds - 5) * 1000);
|
||||
//--------------------- 验证码 ---------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopRefrestCaptchaInterval() {
|
||||
if (refrestCaptchaInterval != null) {
|
||||
clearInterval(refrestCaptchaInterval);
|
||||
refrestCaptchaInterval = null;
|
||||
let refrestCaptchaInterval = null;
|
||||
function beginRefrestCaptchaInterval(expireSeconds) {
|
||||
if (refrestCaptchaInterval === null) {
|
||||
refrestCaptchaInterval = setInterval(getCaptcha, (expireSeconds - 5) * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(getCaptcha);
|
||||
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>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
:body-style="{ paddingBottom: '80px' }"
|
||||
:maskClosable="true"
|
||||
:title="form.menuId ? '编辑' : '添加'"
|
||||
:visible="visible"
|
||||
:width="550"
|
||||
:open="visible"
|
||||
:width="600"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-form ref="formRef" :labelCol="{ span: labelColSpan }" :labelWrap="true" :model="form" :rules="rules">
|
||||
@@ -28,7 +28,7 @@
|
||||
<MenuTreeSelect ref="parentMenuTreeSelect" v-model:value="form.parentId" />
|
||||
</a-form-item>
|
||||
<!-- 目录 菜单 start -->
|
||||
<template v-if="form.menuType == MENU_TYPE_ENUM.CATALOG.value || form.menuType == MENU_TYPE_ENUM.MENU.value">
|
||||
<template v-if="form.menuType === MENU_TYPE_ENUM.CATALOG.value || form.menuType === MENU_TYPE_ENUM.MENU.value">
|
||||
<a-form-item label="菜单名称" name="menuName">
|
||||
<a-input v-model:value="form.menuName" placeholder="请输入菜单名称" />
|
||||
</a-form-item>
|
||||
@@ -40,14 +40,10 @@
|
||||
</template>
|
||||
</IconSelect>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="form.menuType == MENU_TYPE_ENUM.MENU.value" label="路由地址" name="path">
|
||||
<a-form-item v-if="form.menuType === MENU_TYPE_ENUM.MENU.value" label="路由地址" name="path">
|
||||
<a-input v-model:value="form.path" placeholder="请输入路由地址" />
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" name="sort">
|
||||
<a-input-number v-model:value="form.sort" :min="0" placeholder="请输入排序" style="width: 100%" />
|
||||
<h6 style="color: #ababab">值越小越靠前</h6>
|
||||
</a-form-item>
|
||||
<template v-if="form.menuType == MENU_TYPE_ENUM.MENU.value">
|
||||
<template v-if="form.menuType === MENU_TYPE_ENUM.MENU.value">
|
||||
<a-form-item v-if="form.frameFlag" label="外链地址" name="frameUrl">
|
||||
<a-input v-model:value="form.frameUrl" placeholder="请输入外链地址" />
|
||||
</a-form-item>
|
||||
@@ -55,11 +51,10 @@
|
||||
<a-input v-model:value="form.component" placeholder="请输入组件地址 默认带有开头/@/views" />
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<a-form-item v-if="form.menuType == MENU_TYPE_ENUM.MENU.value" label="是否缓存" name="cacheFlag">
|
||||
<a-form-item v-if="form.menuType === MENU_TYPE_ENUM.MENU.value" label="是否缓存" name="cacheFlag">
|
||||
<a-switch v-model:checked="form.cacheFlag" checked-children="开启缓存" un-checked-children="不缓存" />
|
||||
</a-form-item>
|
||||
<a-form-item v-if="form.menuType == MENU_TYPE_ENUM.MENU.value" label="是否外链" name="frameFlag">
|
||||
<a-form-item v-if="form.menuType === MENU_TYPE_ENUM.MENU.value" label="是否外链" name="frameFlag">
|
||||
<a-switch v-model:checked="form.frameFlag" checked-children="是外链" un-checked-children="不是外链" />
|
||||
</a-form-item>
|
||||
<a-form-item label="显示状态" name="frameFlag">
|
||||
@@ -71,7 +66,7 @@
|
||||
</template>
|
||||
<!-- 目录 菜单 end -->
|
||||
<!-- 按钮 start -->
|
||||
<template v-if="form.menuType == MENU_TYPE_ENUM.POINTS.value">
|
||||
<template v-if="form.menuType === MENU_TYPE_ENUM.POINTS.value">
|
||||
<a-form-item label="功能点名称" name="menuName">
|
||||
<a-input v-model:value="form.menuName" placeholder="请输入功能点名称" />
|
||||
</a-form-item>
|
||||
@@ -82,22 +77,24 @@
|
||||
<a-switch v-model:checked="form.disabledFlag" checked-children="启用" un-checked-children="禁用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限类型" name="permsType">
|
||||
<a-radio-group v-model:value="form.permsType" >
|
||||
<a-radio-group v-model:value="form.permsType">
|
||||
<a-radio v-for="item in MENU_PERMS_TYPE_ENUM" :key="item.value" :value="item.value">
|
||||
{{ item.desc }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item :label="form.permsType === MENU_PERMS_TYPE_ENUM.SPRING_SECURITY.value ? '权限字符' : '前端权限字符'" name="webPerms">
|
||||
<a-input v-model:value="form.webPerms" placeholder="请输入权限字符" />
|
||||
<a-form-item label="前端权限" name="webPerms" help="用于前端按钮等功能的展示和隐藏,搭配v-privilege使用">
|
||||
<a-input v-model:value="form.webPerms" placeholder="请输入前端权限" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限URL" name="apiPermsList" v-if="form.permsType === MENU_PERMS_TYPE_ENUM.URL.value">
|
||||
<a-select v-model:value="form.apiPermsList" mode="multiple" placeholder="请选择接口权限" style="width: 100%">
|
||||
<a-select-option v-for="item in allUrlData" :key="item.name">{{ item.url }} </a-select-option>
|
||||
</a-select>
|
||||
<a-form-item label="后端权限" name="apiPerms" help="后端@SaCheckPermission中的权限字符串,多个以英文逗号,分割">
|
||||
<a-input v-model:value="form.apiPerms" placeholder="请输入后端权限" />
|
||||
</a-form-item>
|
||||
</template>
|
||||
<!-- 按钮 end -->
|
||||
<a-form-item label="排序" name="sort">
|
||||
<a-input-number v-model:value="form.sort" :min="0" placeholder="请输入排序" style="width: 100px" />
|
||||
<h6 style="color: #ababab">值越小越靠前</h6>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
|
||||
@@ -109,11 +106,11 @@
|
||||
<script setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
||||
import { computed, nextTick, reactive, ref } from 'vue';
|
||||
import MenuTreeSelect from './menu-tree-select.vue';
|
||||
import { menuApi } from '/@/api/system/menu/menu-api';
|
||||
import { menuApi } from '/@/api/system/menu-api';
|
||||
import IconSelect from '/@/components/framework/icon-select/index.vue';
|
||||
import { MENU_DEFAULT_PARENT_ID, MENU_TYPE_ENUM, MENU_PERMS_TYPE_ENUM } from '/@/constants/system/menu-const';
|
||||
import { MENU_DEFAULT_PARENT_ID, MENU_PERMS_TYPE_ENUM, MENU_TYPE_ENUM } from '/@/constants/system/menu-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
|
||||
@@ -127,18 +124,12 @@
|
||||
const visible = ref(false);
|
||||
|
||||
const labelColSpan = computed(() => {
|
||||
if (form.menuType == MENU_TYPE_ENUM.POINTS.value) {
|
||||
if (form.menuType === MENU_TYPE_ENUM.POINTS.value) {
|
||||
return 6;
|
||||
}
|
||||
return 4;
|
||||
});
|
||||
|
||||
watch(visible, (e) => {
|
||||
if (e) {
|
||||
getAuthUrl();
|
||||
}
|
||||
});
|
||||
|
||||
const contextMenuTreeSelect = ref();
|
||||
const parentMenuTreeSelect = ref();
|
||||
|
||||
@@ -173,16 +164,6 @@
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
// ----------------------- 预加载数据 ------------------------
|
||||
|
||||
let allUrlData = ref([]);
|
||||
|
||||
// url数据
|
||||
async function getAuthUrl() {
|
||||
let res = await menuApi.getAuthUrl();
|
||||
allUrlData.value = res.data;
|
||||
}
|
||||
|
||||
// ----------------------- form表单相关操作 ------------------------
|
||||
|
||||
const formRef = ref();
|
||||
@@ -193,12 +174,12 @@
|
||||
icon: undefined,
|
||||
parentId: undefined,
|
||||
path: undefined,
|
||||
permsType: MENU_PERMS_TYPE_ENUM.SPRING_SECURITY.value,
|
||||
permsType: MENU_PERMS_TYPE_ENUM.SA_TOKEN.value,
|
||||
webPerms: undefined,
|
||||
apiPermsList: undefined,
|
||||
apiPerms: undefined,
|
||||
sort: undefined,
|
||||
visibleFlag: true,
|
||||
cacheFlag: false,
|
||||
cacheFlag: true,
|
||||
component: undefined,
|
||||
contextMenuId: undefined,
|
||||
disabledFlag: false,
|
||||
@@ -237,7 +218,6 @@
|
||||
{ required: true, message: '路由地址不能为空' },
|
||||
{ max: 100, message: '路由地址不能大于100个字符', trigger: 'blur' },
|
||||
],
|
||||
webPerms: [{ required: true, message: '前端权限字符不能为空' }],
|
||||
};
|
||||
|
||||
function validateForm(formRef) {
|
||||
|
||||
@@ -23,9 +23,8 @@
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { menuApi } from '/@/api/system/menu/menu-api';
|
||||
import _ from 'lodash';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { menuApi } from '/@/api/system/menu-api';
|
||||
|
||||
const props = defineProps({
|
||||
value: Number,
|
||||
|
||||
@@ -35,11 +35,6 @@ export const columns = ref([
|
||||
dataIndex: 'component',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '权限模式',
|
||||
dataIndex: 'permsType',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '后端权限',
|
||||
dataIndex: 'apiPerms',
|
||||
@@ -50,26 +45,6 @@ export const columns = ref([
|
||||
dataIndex: 'webPerms',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '外链',
|
||||
dataIndex: 'frameFlag',
|
||||
width: 45,
|
||||
},
|
||||
{
|
||||
title: '缓存',
|
||||
dataIndex: 'cacheFlag',
|
||||
width: 45,
|
||||
},
|
||||
{
|
||||
title: '显示',
|
||||
dataIndex: 'visibleFlag',
|
||||
width: 45,
|
||||
},
|
||||
{
|
||||
title: '禁用',
|
||||
dataIndex: 'disabledFlag',
|
||||
width: 45,
|
||||
},
|
||||
{
|
||||
title: '顺序',
|
||||
dataIndex: 'sort',
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
查询
|
||||
</a-button>
|
||||
|
||||
<a-button @click="resetQuery">
|
||||
<a-button @click="resetQuery" class="smart-margin-left10">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
@@ -71,7 +71,7 @@
|
||||
添加菜单
|
||||
</a-button>
|
||||
|
||||
<a-button v-privilege="'system:menu:batch:delete'" type="primary" danger size="small" @click="batchDelete" :disabled="!hasSelected">
|
||||
<a-button v-privilege="'system:menu:batchDelete'" type="primary" danger size="small" @click="batchDelete" :disabled="!hasSelected">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
@@ -79,7 +79,7 @@
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="smart-table-setting-block">
|
||||
<TableOperator v-model="columns" :tableId="TABLE_ID_CONST.SYSTEM.MENU" :refresh="query" />
|
||||
<TableOperator v-model="columns" :tableId="TABLE_ID_CONST.SYSTEM.MENU" :refresh="query" />
|
||||
</div>
|
||||
</a-row>
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
<template v-if="column.dataIndex === 'operate'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button v-privilege="'system:menu:update'" type="link" size="small" @click="showDrawer(record)">编辑</a-button>
|
||||
<a-button v-privilege="'system:menu:delete'" danger type="link" @click="singleDelete(record)">删除</a-button>
|
||||
<a-button v-privilege="'system:menu:batchDelete'" danger type="link" @click="singleDelete(record)">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
@@ -148,7 +148,7 @@
|
||||
import MenuOperateModal from './components/menu-operate-modal.vue';
|
||||
import { buildMenuTableTree, filterMenuByQueryForm } from './menu-data-handler';
|
||||
import { columns } from './menu-list-table-columns';
|
||||
import { menuApi } from '/@/api/system/menu/menu-api';
|
||||
import { menuApi } from '/@/api/system/menu-api';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
Reference in New Issue
Block a user