补齐邮箱登录国际化,登录样式修改,通知中心根据tab标签跳转,首页修改

This commit is contained in:
YUN-PC5\user 2023-10-24 16:47:55 +08:00
parent 7297634be5
commit 603772532a
10 changed files with 523 additions and 160 deletions

View File

@ -19,7 +19,7 @@
.login-form {
border-radius: 6px;
background: #ffffff;
width: calc(100% - 30px - 70px);
width: calc(100% - 70px - 30px);
margin: 0 auto;
padding: 15px;
position: relative;

View File

@ -2,7 +2,7 @@
<div class="title-container">
<img class="logo" src="/favicon.ico" />
<div class="title">
<!-- <span class="white"></span>-->
<!-- <span class="white"></span>-->
<span class="blue">&nbsp;{{ title }}&nbsp;</span>
</div>
<el-tag class="tag" type="info" effect="plain" disable-transitions>BETA</el-tag>
@ -25,7 +25,7 @@ const title = ref(import.meta.env.VITE_APP_TITLE)
.title {
font-size: 26px;
font-weight: 700;
width: 300px;
width: 400px;
line-height: 50px;
float: left;
}

View File

@ -140,7 +140,7 @@ const viewNoticeDetail = (notice: noticeInfo) => {
}
//
const viewMoreNotice = () => {
router.push({ path: '/notice/center' })
router.push({ path: '/notice/center', query: { activeTab: activeTab.value } })
}
const formatDate = (dateTime) => {
const dateObj = new Date(dateTime)

View File

@ -114,7 +114,8 @@
"female": "Female",
"male": "male",
"sex": "gender",
"systemTips": "system hint"
"systemTips": "system hint",
"currentTime": "Current Time"
},
"btn": {
"add": "Add",

View File

@ -115,7 +115,8 @@
"sex": "性别",
"male": "男",
"female": "女",
"systemTips": "系统提示"
"systemTips": "系统提示",
"currentTime": "当前时间"
},
"btn": {
"add": "新增",

View File

@ -13,5 +13,14 @@
"register": "Sign up now",
"toLoginByEmail": "Log in By Email",
"btnLoginLoading": "Loginning..."
},
"loginByEmail": {
"toLogin": "Log in By Password",
"email": "Email",
"getDragVerify": "Get Verify Code",
"checkDragVerifyDuration": "Try again in seconds"
},
"roleSelectDialog": {
"close": "Dialog closes,please re-enter the CAPTCHA"
}
}

View File

@ -13,5 +13,19 @@
"register": "注册",
"toLoginByEmail": "邮箱登录",
"btnLoginLoading": "登录中..."
},
"loginByEmail": {
"toLogin": "密码登录",
"email": "邮箱",
"getDragVerify": "获取验证码",
"checkDragVerifyDuration": "秒后重试",
"loginRules": {
"dragVerifyRequired": "请输入验证码",
"emailRequired": "请输入您的邮箱",
"emailFormat": "请输入正确格式的邮箱"
}
},
"roleSelectDialog": {
"close": "弹窗关闭,请重新输入验证码"
}
}

View File

@ -1,168 +1,501 @@
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :lg="16" :sm="24">
<h2>ZRAdmin.NET {{ $t('layout.backstageManagement') }}</h2>
<p>
ZRAdmin.NET借鉴了很多开源项目的优点让你开发Web管理系统更简单所以我也把它给开源了前端
<code>vue页面</code>主要参考若依在此表示感谢.)
</p>
<p>{{ $t('layout.content1') }}</p>
<p>
<b>{{ $t('layout.currentVersion') }}:</b> <span>v{{ version }}</span>
<el-link
class="ml10"
type="primary"
size="small"
icon="Document"
plain
@click="goTarget('http://www.izhaorui.cn/doc/changelog.html#' + version)"
>{{ $t('layout.changeLog') }}
</el-link>
</p>
<p>
<el-button type="primary" size="small" icon="Cloudy" plain @click="goTarget('https://gitee.com/izory/ZrAdminNetCore')">Gitee </el-button>
<el-button type="primary" size="small" icon="Cloudy" plain @click="goTarget('https://github.com/izhaorui/ZrAdmin.NET')"
>Github
</el-button>
</p>
<p></p>
<h3>{{ $t('layout.tip1') }}</h3>
</el-col>
<el-col :lg="8" :sm="24">
<h2>{{ $t('layout.technicalSelection') }}</h2>
<div style="float: left; width: 50%">
<h4>{{ $t('layout.backendTechnology') }}</h4>
<ul>
<li>NET7</li>
<li>JWT</li>
<li>SqlSugar</li>
<li>Quartz.Net</li>
<li>MySql</li>
<li>Mapster</li>
<li>MiniExcel</li>
<li>Redis</li>
<li>Signalr</li>
<li>...</li>
</ul>
</div>
<div style="float: right; width: 50%">
<h4>{{ $t('layout.frontendTechnology') }}</h4>
<ul>
<li>Vue3</li>
<li>Pinia</li>
<li>Element plus</li>
<li>Axios</li>
<li>Sass</li>
<li>Wangeditor</li>
<li>Vite</li>
<li>Composition api</li>
<li>I18n</li>
<li>...</li>
</ul>
</div>
</el-col>
</el-row>
<el-divider />
<el-row :gutter="20" class="mt10">
<el-col :sm="24" :lg="8">
<el-card>
<template #header>
<span>{{ $t('layout.contactUs') }}</span>
</template>
<div class="body">
<p>
<el-icon> <promotion /> </el-icon>{{ $t('layout.officialWebsite') }}
<el-link href="http://www.izhaorui.cn/doc" target="_blank"> http://www.izhaorui.cn/doc </el-link>
</p>
<p>
<el-icon> <UserFilled /> </el-icon>{{ $t('layout.qqGroup') }}
<s>满191349103</s>
<el-link
target="_black"
href="https://qm.qq.com/cgi-bin/qm/qr?k=kgt4HsckdljU0VM-0kxND6d_igmfuPlL&authKey=r55YUbruiKQ5iwC/folG7KLCmZ++Y4rQVgNlvLbUniUMkbk24Y9+zNuOmOnjAjRc&noverify=0">
&nbsp;462862273
</el-link>
</p>
<div class="dashboard-editor-container home">
<el-row :gutter="10">
<!-- 左侧区域 -->
<el-col :lg="16" :md="24">
<el-card style="margin: 5px 0">
<!-- 设置显示项目 -->
<div style="position: relative; height: 45px; border-bottom: 1px solid var(--el-card-border-color)">
<el-popover placement="bottom-end" trigger="click">
<template #reference>
<el-button circle title="设置显示项目" style="position: absolute; top: 0; right: 0">
<el-icon><Tools /></el-icon>
</el-button>
</template>
<el-checkbox-group v-model="checkboxGroup">
<el-checkbox v-for="(item, index) in checkBoxArray" :label="item.label" :key="index" />
</el-checkbox-group>
</el-popover>
</div>
<el-scrollbar view-style="overflow: hidden;" height="calc(100vh - 255px)">
<!-- 业务日历 -->
<el-card v-if="checkboxGroup.includes('业务日历')" class="no-padding-card" style="margin: 10px 0">
<!-- 日历 -->
<el-calendar ref="calendar" class="custom-calendar" v-model="calValue">
<template #header="{ date }">
<b>业务日历</b>
<span>{{ date }}</span>
<el-button-group>
<el-button size="small" @click="selectDate('prev-month')"> 上个月 </el-button>
<el-button size="small" @click="selectDate('today')"> 今天 </el-button>
<el-button size="small" @click="selectDate('next-month')"> 下个月 </el-button>
</el-button-group>
</template>
<template #date-cell="{ data }">
<el-row class="day-block-wrapper">
<el-col :span="6" style="height: 100%">
{{ data.day.split('-')[2] }}
</el-col>
<!-- <el-col :span="18" style="height: 100%">
<div v-if="monthlyWorkCalendarDataPopover(data)">
<div v-for="item in monthlyWorkCalendarData" :key="item.theDay">
<div v-for="(workStatus, index) in item.workStatusListVos" :key="index">
<el-tag
effect="dark"
style="width: 100%; margin: 4px 0 0"
:type="computeWorkStatusTagType(workStatus.status)"
class="tag-cla"
v-if="item.theDay === data.day"
:key="workStatus.status">
{{ workStatus.statusName }} {{ workStatus.workItemNum }}
</el-tag>
</div>
</div>
</div>
<el-popover placement="right" :width="30" trigger="hover" v-else>
<template #reference>
<el-scrollbar height="70px">
<div v-for="(item, index) in monthlyWorkCalendarData" :key="item.theDay">
<div v-for="(workStatus, index) in item.workStatusListVos">
<el-tag
effect="dark"
style="width: 100%; margin: 4px 0 0"
:type="computeWorkStatusTagType(workStatus.status)"
class="tag-cla"
v-if="item.theDay === data.day"
:key="workStatus.status">
{{ workStatus.statusName }} {{ workStatus.workItemNum }}
</el-tag>
</div>
</div>
</el-scrollbar>
</template>
<div v-for="(item, index) in monthlyWorkCalendarData" :key="item.theDay">
<div v-for="(workStatus, index) in item.workStatusListVos">
<el-tag
effect="dark"
style="width: 100%; margin: 4px 0 0"
:type="computeWorkStatusTagType(workStatus.status)"
class="tag-cla"
v-if="item.theDay === data.day"
:key="workStatus.status">
{{ workStatus.statusName }} {{ workStatus.workItemNum }}
</el-tag>
</div>
</div>
</el-popover>
</el-col> -->
</el-row>
</template>
</el-calendar>
</el-card>
</el-scrollbar>
</el-card>
</el-col>
<!-- 右侧区域 -->
<el-col :lg="8" :md="24">
<el-row>
<el-col>
<el-card style="margin: 5px 0">
<el-scrollbar view-style="overflow: hidden;" height="calc(100vh - 210px)">
<el-descriptions :column="1" border>
<template #title>
<el-row>
<el-col>{{ userInfo.welcomeMessage }}</el-col>
</el-row>
<el-row>
<el-col>{{ userInfo.welcomeContent }}</el-col>
</el-row>
</template>
<template #extra>
<el-image :src="userInfo.avatar">
<template #error>
<div class="image-slot">
<el-icon :size="40"><Avatar /></el-icon>
</div>
</template>
</el-image>
</template>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<user />
</el-icon>
{{ $t('user.userName') }}
</div>
</template>
{{ userInfo.nickName }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon><Calendar /></el-icon>
{{ $t('common.currentTime') }}
</div>
</template>
{{ nowTime }}</el-descriptions-item
>
</el-descriptions>
<!-- 待办事项 -->
<el-divider content-position="left">
<b>待办事项</b>
</el-divider>
<div v-if="!toDoSumData.length" style="text-align: center">
<el-text type="info">暂无待办项</el-text>
</div>
<!-- 系统通知 -->
<div style="display: flex">
<el-divider content-position="left">
<b>系统通知</b>
</el-divider>
<el-divider content-position="right">
<el-button type="primary" link icon="bell" @click="viewMoreNotice">前往通知中心</el-button>
</el-divider>
</div>
<div style="position: absolute; width: 100%">
<el-tabs v-model="activeNoticeTab">
<el-tab-pane name="notice">
<template #label>
<el-badge :value="unreadNoticeList.length" style="line-height: 18px" :hidden="unreadNoticeList.length === 0">
通知公告
</el-badge>
</template>
<el-empty :image-size="150" description="暂无未读通知公告" v-if="unreadNoticeList.length === 0" />
<el-table :data="unreadNoticeList" height="250" :show-header="false" v-else>
<el-table-column prop="noticeTitle" label="标题">
<template #default="{ row }">
<el-icon :size="20" color="#409EFF"><bell /></el-icon>
<el-link
:type="row.isRead ? 'primary' : 'danger'"
style="margin-left: 8px"
@click="viewNoticeDetail({ ...row, noticeType: NoticeType.notice })"
>{{ row.noticeTitle }}</el-link
>
</template>
</el-table-column>
<el-table-column prop="create_time" label="时间" width="180">
<template #default="{ row }">
{{ formatDate(row.create_time) }}
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane name="aimMsg">
<template #label>
<el-badge :value="unreadAimList.length" style="line-height: 18px" :hidden="unreadAimList.length === 0"> 业务信息 </el-badge>
</template>
<el-empty :image-size="150" description="暂无未读业务信息" v-if="unreadAimList.length === 0" />
<el-table :data="unreadAimList" height="600" :show-header="false" v-else>
<el-table-column prop="noticeTitle" label="标题">
<template #default="{ row }">
<el-icon :size="20" color="#409EFF"><bell /></el-icon>
<el-link
:type="row.isRead ? 'primary' : 'danger'"
style="margin-left: 8px"
@click="viewNoticeDetail({ ...row, noticeType: NoticeType.aimMsg })"
>{{ row.noticeTitle }}</el-link
>
</template>
</el-table-column>
<el-table-column prop="create_time" label="时间" width="180">
<template #default="{ row }">
{{ formatDate(row.create_time) }}
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<el-popconfirm title="是否确定把全部内容消息设为已读?" :teleported="false" :width="300" @confirm="onAllReadClick">
<template #reference>
<el-button style="position: absolute; top: 0; right: 0">全部标为已读</el-button>
</template>
</el-popconfirm>
</div>
</el-scrollbar>
</el-card>
</el-col>
</el-row>
</el-col>
</el-row>
<noticeDialog v-model="noticeDialogOpen" :notice-model="info" />
</div>
</template>
<script setup name="index">
import defaultSettings from '@/settings'
const version = defaultSettings.version
function goTarget(url) {
window.open(url, '__blank')
<script setup lang="ts">
import noticeDialog from '@/components/Notice/noticeDialog/index.vue'
import signalR from '@/signalr'
import useSocketStore from '@/store/modules/socket'
import useUserStore from '@/store/modules/user'
const router = useRouter()
enum NoticeType {
notice = 1,
aimMsg = 2,
chat = 3
}
const userInfo = computed<any>(() => {
return useUserStore().userInfo
})
const checkboxGroup = ref(['业务日历'])
const checkBoxArray = ref(
checkboxGroup.value.map((item) => ({
label: item
}))
)
const calendar = ref()
const calValue = ref(new Date())
const selectDate = (val: any) => {
if (!calendar.value) return
calendar.value.selectDate(val)
}
const activeNoticeTab = ref('notice')
const unreadNoticeList = computed(() => {
return useSocketStore().unreadNoticeList
})
const unreadAimList = computed(() => {
return useSocketStore().unreadAimList
})
const noticeDialogOpen = ref(false)
interface noticeInfo {
noticeId: string
noticeTitle: string
noticeContent: string
noticeType: NoticeType
isRead: boolean
create_name: string
create_time: string
}
const info = ref<noticeInfo>({
noticeId: '',
noticeTitle: '',
noticeContent: '',
noticeType: NoticeType.notice,
isRead: false,
create_name: '',
create_time: ''
})
const viewNoticeDetail = (notice: noticeInfo) => {
noticeDialogOpen.value = true
info.value = notice
}
const viewMoreNotice = () => {
router.push({ path: '/notice/center', query: { activeTab: activeNoticeTab.value } })
}
const onAllReadClick = () => {
if (activeNoticeTab.value === 'notice') {
signalR.AllReadNotice()
} else {
signalR.AllReadAimMsg()
}
}
const formatDate = (dateTime) => {
const dateObj = new Date(dateTime)
const options: any = {
year: 'numeric',
month: 'short',
day: 'numeric'
// hour: '2-digit',
// minute: '2-digit',
// second: '2-digit'
}
return dateObj.toLocaleDateString('zh-CN', options)
}
const nowTime = ref<string>('')
// XXXXXXXXXXXXXX X
const complement = function (value: any) {
return value < 10 ? `0${value}` : value
}
const formateDate = (date: any) => {
const time = new Date(date)
const year = time.getFullYear()
const month = complement(time.getMonth() + 1)
const day = complement(time.getDate())
const hour = complement(time.getHours())
const minute = complement(time.getMinutes())
const second = complement(time.getSeconds())
const week = '星期' + '日一二三四五六'.charAt(time.getDay())
return `${year}${month}${day}${week} ${hour}:${minute}:${second}`
}
const toDoSumData = ref<any[]>([])
const buildToDoSumData = async () => {}
onMounted(() => {
setInterval(() => {
nowTime.value = formateDate(new Date())
})
buildToDoSumData()
})
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
:deep(.no-padding-card) > .el-card__body {
padding: 0 0 10px 0;
.el-calendar__header {
padding: 18px 20px;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul {
padding: 0;
margin: 0;
}
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
//font-size: 13px;
color: #676a6c;
overflow-x: hidden;
ul {
list-style-type: none;
}
h4 {
margin-top: 0px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
p {
margin-top: 10px;
b {
font-weight: 700;
}
}
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
}
.el-calendar__body {
padding: 12px 20px;
}
}
:deep(.custom-calendar) {
.el-calendar-day {
padding: 0;
height: 90px;
}
.day-block-wrapper {
width: 100%;
height: 100%;
padding: 8px;
box-sizing: border-box;
border: 2px dashed #00000000;
}
.el-calendar-table td.is-selected .day-block-wrapper {
border: 2px dashed var(--el-color-primary);
}
}
:deep(.custom-carousel .el-carousel__indicator) {
.el-carousel__button {
background-color: #d3dce6;
width: 25px;
height: 15px;
}
.el-carousel__button .is-active {
background-color: #99a9bf;
}
}
.typography-1 {
border-left: 4px solid var(--el-color-primary);
padding-left: 5px;
margin: 10px 0;
position: relative;
}
.card-label {
font-weight: bold;
width: 90px;
color: var(--el-text-color-regular);
vertical-align: top;
}
.card-value {
width: 180px;
white-space: nowrap; /* 防止文字换行 */
overflow: hidden; /* 文字溢出隐藏 */
text-overflow: ellipsis; /* 出现省略号 */
}
.settings {
display: flex;
justify-content: flex-end;
}
.tag-name {
min-width: 30px;
margin: 0 5px 5px 0;
}
.tag-cla {
min-width: 50px;
margin: 0 0 5px 0;
}
.list-group-striped > .list-group-item {
border-left: 0;
border-right: 0;
border-radius: 0;
padding-left: 0;
padding-right: 0;
}
.list-group {
padding-left: 0px;
list-style: none;
}
.list-group-item {
border-bottom: 1px solid #e7eaec;
border-top: 1px solid #e7eaec;
margin-bottom: -1px;
padding: 11px 0px;
font-size: 13px;
}
.vertical-center {
display: flex;
justify-content: center;
align-items: center;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.custom-tabs {
margin-top: 10px;
:deep(.el-tabs__item) {
min-width: 111px;
justify-content: center;
}
}
.minibox {
width: 200px;
display: flex;
box-sizing: border-box;
.icon {
margin: auto;
text-align: center;
}
.word {
width: 150px;
line-height: 26px;
margin: auto;
}
}
.card:hover {
border: 1px solid var(--el-color-primary);
background-color: #f5f7fa;
cursor: pointer;
.icon {
color: var(--el-color-primary);
}
.word {
color: var(--el-color-primary);
}
}
.nested-enter-active,
.nested-leave-active {
transition: all 0.3s ease-in-out;
}
/* delay leave of parent element */
.nested-leave-active {
transition-delay: 0.25s;
}
.nested-enter-from,
.nested-leave-to {
transform: translateY(30px);
opacity: 0;
}
/* we can also transition nested elements using nested selectors */
.nested-enter-active .inner,
.nested-leave-active .inner {
transition: all 0.3s ease-in-out;
}
/* delay enter of nested element */
.nested-enter-active .inner {
transition-delay: 0.25s;
}
.nested-enter-from .inner,
.nested-leave-to .inner {
transform: translateX(30px);
/*
Hack around a Chrome 96 bug in handling nested opacity transitions.
This is not needed in other browsers or Chrome 99+ where the bug
has been fixed.
*/
opacity: 0.001;
}
</style>

View File

@ -76,7 +76,12 @@ import useSocketStore from '@/store/modules/socket'
import signalR from '@/signalr'
import noticeDialog from '@/components/Notice/noticeDialog/index.vue'
import { ElTable } from 'element-plus'
const route = useRoute()
onMounted(() => {
if (route.query.activeTab) {
activeTab.value = route.query.activeTab as string
}
})
enum NoticeType {
notice = 1,
aimMsg = 2,

View File

@ -68,9 +68,9 @@
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="handleFieldScope" icon="SetUp">{{ $t('menu.fieldPermi') }}</el-dropdown-item>
<el-dropdown-item command="handleDataScope" icon="circle-check">{{ $t('menu.menuPermi') }}</el-dropdown-item>
<el-dropdown-item command="handleAuthUser" icon="user">{{ $t('menu.assignUsers') }}</el-dropdown-item>
<el-dropdown-item command="handleFieldScope" icon="SetUp">{{ $t('menu.fieldPermi') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>