perf: 优化锁屏页面功能

新增更新功能
This commit is contained in:
nongyehong
2024-07-11 23:58:57 +08:00
parent 14073438d5
commit 85b6cad03f
22 changed files with 330 additions and 166 deletions

View File

@@ -1,12 +0,0 @@
# 后端服务地址
VITE_SERVICE_URL="http://localhost:9190"
# websocket服务地址
VITE_WEBSOCKET_URL="ws://localhost:8090"
# 项目标题
VITE_APP_TITLE="HuLa—IM"
# 标签后缀
VITE_TITLE_SUFFIX=" | HuLa"
# 项目备案号
VITE_APP_ICP="桂ICP备2021000000号"
# 项目名称
VITE_APP_NAME="HuLa-IM-Tauri"

10
.env.development Normal file
View File

@@ -0,0 +1,10 @@
# 后端服务地址
VITE_SERVICE_URL="http://127.0.0.1:9190"
# websocket服务地址
VITE_WEBSOCKET_URL="ws://127.0.0.1:8090"
# 项目标题
VITE_APP_TITLE="HuLa—IM"
# 项目名称
VITE_APP_NAME="HuLa-IM-Tauri"
# gitee token
VITE_GITEE_TOKEN="xxxxxxxxxxxxxxx"

View File

@@ -1,12 +0,0 @@
# 后端服务地址
VITE_SERVICE_URL="http://192.168.10.5:9190"
# websocket服务地址
VITE_WEBSOCKET_URL="ws://192.168.10.5:8090"
# 项目标题
VITE_APP_TITLE="HuLa—IM"
# 标签后缀
VITE_TITLE_SUFFIX=" | HuLa"
# 项目备案号
VITE_APP_ICP="桂ICP备2021000000号"
# 项目名称
VITE_APP_NAME="HuLa-IM-Tauri"

3
.gitignore vendored
View File

@@ -22,3 +22,6 @@ dist-ssr
*.njsproj
*.sln
*.sw?
src-tauri/target
.env.production

View File

@@ -7,7 +7,7 @@
<title>HuLa</title>
<!--引入iconpark图标库-->
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_99.048ec543532d88124abbf0d8647e30c9.js"></script>
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_111.4a4828943d33d677b9abb7a0669ca950.js"></script>
</head>
<body>

View File

@@ -24,12 +24,12 @@
]
},
"scripts": {
"dev": "vite --mode dev",
"prod": "vite --mode prod",
"build": "vue-tsc --noEmit && vite build --mode pord",
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"tauri:dev": "tauri dev",
"tauri:build": "tauri build",
"tauri:build->debug": "tauri build --debug",
"tauri:icon": "tauri icon public/logo.png",
"preinstall": "npx only-allow pnpm",
"commit": "git add . && git-cz",

View File

@@ -2,7 +2,7 @@
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devPath": "http://localhost:6130",
"devPath": "http://127.0.0.1:6130",
"distDir": "../dist",
"withGlobalTauri": true
},
@@ -34,7 +34,7 @@
"http": {
"all": true,
"request": true,
"scope": ["http://192.168.10.5:9190/*", "http://192.168.10.5:8090/*"]
"scope": ["http://127.0.0.1:9190/*", "https://**"]
},
"fs": {
"all": true,

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24"><circle cx="12" cy="2" r="0" fill="#ffffff"><animate attributeName="r" begin="0" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(45 12 12)"><animate attributeName="r" begin="0.125s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(90 12 12)"><animate attributeName="r" begin="0.25s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(135 12 12)"><animate attributeName="r" begin="0.375s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(180 12 12)"><animate attributeName="r" begin="0.5s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(225 12 12)"><animate attributeName="r" begin="0.625s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(270 12 12)"><animate attributeName="r" begin="0.75s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle><circle cx="12" cy="2" r="0" fill="#ffffff" transform="rotate(315 12 12)"><animate attributeName="r" begin="0.875s" calcMode="spline" dur="1s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0"/></circle></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
src/assets/img/lock_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -30,7 +30,9 @@
{ 'active-reply': activeReply === item.message.id }
]">
<!-- 信息间隔时间 -->
<span class="text-(12px #909090) select-none bg-[--time-color] p-4px rounded-6px" v-if="item.timeBlock">
<span
class="text-(12px #909090) select-none bg-[--time-color] p-4px rounded-6px shadow-md"
v-if="item.timeBlock">
{{ item.timeBlock }}
</span>
<!-- 消息为撤回消息 -->
@@ -236,7 +238,7 @@
:size="6"
v-if="item.message.body.reply"
@click="jumpToReplyMsg(item.message.body.reply.id)"
class="reply-bubble relative w-fit">
class="reply-bubble relative w-fit shadow-md">
<svg class="size-14px"><use href="#to-top"></use></svg>
<span>{{ `${item.message.body.reply.username}` }}</span>
<!-- 当回复消息为图片时渲染 -->

View File

@@ -74,7 +74,11 @@ export const useChatMain = (activeItem?: SessionItem) => {
label: '撤回',
icon: 'corner-down-left',
click: async (item: MessageType) => {
await apis.recallMsg({ roomId: 1, msgId: item.message.id })
const res = await apis.recallMsg({ roomId: 1, msgId: item.message.id })
if (res.errMsg) {
window.$message.error(res.errMsg)
return
}
chatStore.updateRecallStatus({ msgId: item.message.id })
}
}

View File

@@ -136,10 +136,17 @@ export const leftHook = () => {
})
}
/** 佩戴卸下徽章 */
/** 佩戴徽章 */
const toggleWarningBadge = async (badge: BadgeType) => {
if (!badge?.id) return
await apis.setUserBadge(badge.id)
const res = await apis.setUserBadge(badge.id)
if (res.success) {
window.$message.success('佩戴成功')
/** 获取用户信息 */
apis.getUserInfo().then((res) => {
editInfo.value.content = res.data
})
}
}
/** 计算字符长度 */

View File

@@ -1,9 +1,24 @@
import { NAvatar, NButton, NFlex, NFormItem, NInput, NModal, NForm } from 'naive-ui'
import {
NAvatar,
NButton,
NFlex,
NFormItem,
NInput,
NModal,
NForm,
NTimelineItem,
NTimeline,
NScrollbar,
NSkeleton,
NIcon
} from 'naive-ui'
import { FormInst } from 'naive-ui'
import { setting } from '@/stores/setting.ts'
import { storeToRefs } from 'pinia'
import { emit } from '@tauri-apps/api/event'
import { EventEnum } from '@/enums'
import pkg from '~/package.json'
import { handRelativeTime } from '@/utils/Day.ts'
const formRef = ref<FormInst | null>()
const formValue = ref({
@@ -16,7 +31,7 @@ export const lock = ref({
lockPassword: {
required: true,
message: '请输入锁屏密码',
trigger: ['input', 'blur']
trigger: ['input']
}
},
async handleLock() {
@@ -40,6 +55,7 @@ export const lock = ref({
})
/*============================================ model =====================================================*/
/** 锁屏弹窗 */
export const LockScreen = defineComponent(() => {
const settingStore = setting()
const { login } = storeToRefs(settingStore)
@@ -79,14 +95,153 @@ export const LockScreen = defineComponent(() => {
)
})
/** 检查更新弹窗 */
export const CheckUpdate = defineComponent(() => {
const url = `https://gitee.com/api/v5/repos/nongyehong/HuLa-IM-Tauri/releases/tags/${pkg.version}?access_token=${import.meta.env.VITE_GITEE_TOKEN}`
/** 项目提交日志记录 */
const commitLog = ref<{ message: string; icon: string }[]>([])
const loading = ref(false)
const checkLoading = ref(false)
/** 版本更新日期 */
const versionTime = ref('')
const commitTypeMap: { [key: string]: string } = {
feat: 'feat',
fix: 'fix',
docs: 'docs',
style: 'style',
refactor: 'refactor',
perf: 'perf',
test: 'test',
build: 'build',
ci: 'ci',
revert: 'revert',
chore: 'chore'
}
const mapCommitType = (commitMessage: string) => {
for (const type in commitTypeMap) {
if (new RegExp(`^${type}`, 'i').test(commitMessage)) {
return commitTypeMap[type]
}
}
}
/* 记录检测更新的版本 */
let lastVersion: string | null = null
const checkUpdate = () => {
const url = `https://gitee.com/api/v5/repos/nongyehong/HuLa-IM-Tauri/tags?access_token=${import.meta.env.VITE_GITEE_TOKEN}&sort=name&direction=desc&page=1&per_page=1`
if (lastVersion && lastVersion === pkg.version) {
window.$message.success('当前已是最新版本')
return
}
checkLoading.value = true
fetch(url).then((res) => {
res
.json()
.then(async (data) => {
if (data[0].name === pkg.version) {
checkLoading.value = false
window.$message.success('当前已是最新版本')
lastVersion = pkg.version
} else {
// TODO 获取最新版本的提交日志,并且更换按钮文字为下载最新版本 (nyh -> 2024-07-11 22:20:33)
}
})
.catch(() => {
checkLoading.value = false
window.$message.error('请检查配置配置好token后再试')
})
})
}
const init = () => {
loading.value = true
fetch(url).then((res) => {
if (!res.ok) {
commitLog.value = [{ message: '获取更新日志失败请配置token后再试', icon: 'cloudError' }]
loading.value = false
return
}
res.json().then(async (data) => {
versionTime.value = data.created_at
await nextTick(() => {
// 使用正则表达式提取 * 号后面的内容
const regex = /\* (.+)/g
let match
const logs = []
while ((match = regex.exec(data.body)) !== null) {
logs.push(match[1])
}
commitLog.value = logs.map((commit) => {
// 获取最后一个 : 号的位置
const lastColonIndex = commit.lastIndexOf(':')
// 截取最后一个 : 号后的内容
const message = lastColonIndex !== -1 ? commit.substring(lastColonIndex + 1).trim() : commit
return {
message: message,
icon: mapCommitType(commit)!
}
})
loading.value = false
})
})
})
}
onMounted(() => {
init()
})
return () => (
<NModal v-model:show={lock.value.modalShow} maskClosable={false} class="w-350px border-rd-8px">
<div class="bg-[--bg-popover] w-360px h-full p-6px box-border flex flex-col">
<div class="bg-[--bg-popover] w-500px h-full p-6px box-border flex flex-col">
<svg onClick={() => (lock.value.modalShow = false)} class="w-12px h-12px ml-a cursor-pointer select-none">
<use href="#close"></use>
</svg>
<p>123</p>
{loading.value ? (
<NFlex vertical justify={'center'} size={10}>
<NSkeleton text repeat={1} class="rounded-8px h-30px w-120px" />
<NSkeleton text repeat={1} class="rounded-8px h-300px" />
<NSkeleton text repeat={1} class="rounded-8px w-80px h-30px m-[0_0_0_auto]" />
</NFlex>
) : (
<NFlex size={10} vertical justify={'center'} class="p-14px box-border select-none">
<NFlex justify={'space-between'} align={'center'}>
<NFlex align={'center'} size={10}>
<p>:</p>
<p class="text-(24px #909090) font-bold">{pkg.version}</p>
</NFlex>
<NFlex align={'center'} size={10}>
<p class="text-(12px #909090)">:</p>
<p class="text-(12px #13987f)">{handRelativeTime(versionTime.value)}</p>
</NFlex>
</NFlex>
<p class="text-(14px #909090)"></p>
<NScrollbar class="max-h-460px p-[0_10px] box-border">
<NTimeline class="p-[0_6px] box-border">
{commitLog.value.map((log, index) => (
<NTimelineItem key={index} content={log.message}>
{{
icon: () => (
<NIcon size={20}>
<svg>
<use href={`#${log.icon}`}></use>
</svg>
</NIcon>
)
}}
</NTimelineItem>
))}
</NTimeline>
</NScrollbar>
<NFlex justify={'end'}>
<NButton loading={checkLoading.value} onClick={checkUpdate} secondary type="tertiary">
</NButton>
</NFlex>
</NFlex>
)}
</div>
</NModal>
)

View File

@@ -103,11 +103,6 @@ const routes: Array<RouteRecordRaw> = [
name: 'general',
component: () => import('@/views/home-window/more/settings/General.vue')
},
{
path: '/remind',
name: 'remind',
component: () => import('@/views/home-window/more/settings/Remind.vue')
},
{
path: '/loginSetting',
name: 'loginSetting',

View File

@@ -49,8 +49,7 @@ export const createAxios = (config?: AxiosRequestConfig): AxiosInstance => {
return Promise.reject(
window.$message.create('当前为测试环境,请注意辨别', {
type: 'warning',
closable: true,
duration: 0
closable: true
})
)
}

View File

@@ -1,7 +1,7 @@
import { URLEnum } from '@/enums'
const { PROD, VITE_SERVICE_URL } = import.meta.env
// 本地配置到 .env.dev 里面修改。生产配置在 .env.prod 里面
// 本地配置到 .env.development 里面修改。生产配置在 .env.production 里面
const prefix = PROD ? VITE_SERVICE_URL : ''
export default {

View File

@@ -27,6 +27,7 @@ declare module 'vue' {
NButton: (typeof import('naive-ui'))['NButton']
NButtonGroup: (typeof import('naive-ui'))['NButtonGroup']
NCheckbox: (typeof import('naive-ui'))['NCheckbox']
NCode: (typeof import('naive-ui'))['NCode']
NCollapse: (typeof import('naive-ui'))['NCollapse']
NCollapseItem: (typeof import('naive-ui'))['NCollapseItem']
NConfigProvider: (typeof import('naive-ui'))['NConfigProvider']
@@ -34,8 +35,6 @@ declare module 'vue' {
NDropdown: (typeof import('naive-ui'))['NDropdown']
NEllipsis: (typeof import('naive-ui'))['NEllipsis']
NFlex: (typeof import('naive-ui'))['NFlex']
NForm: (typeof import('naive-ui'))['NForm']
NFormItem: (typeof import('naive-ui'))['NFormItem']
NIcon: (typeof import('naive-ui'))['NIcon']
NIconWrapper: (typeof import('naive-ui'))['NIconWrapper']
NImage: (typeof import('naive-ui'))['NImage']

39
src/typings/env.d.ts vendored
View File

@@ -8,30 +8,6 @@ interface ImportMetaEnv {
readonly VITE_APP_NAME: string
/** 项目标题 */
readonly VITE_APP_TITLE: string
/** 页面标题后缀*/
readonly VITE_TITLE_SUFFIX: string
/** 项目ICP备案号 */
readonly VITE_APP_ICP: string
/** 项目描述 */
readonly VITE_APP_DESC: string
/** 后端服务的环境类型 */
readonly VITE_SERVICE_ENV?: ServiceEnvType
/**
* 权限路由模式:
* - static - 前端声明的静态
* - dynamic - 后端返回的动态
*/
readonly VITE_AUTH_ROUTE_MODE: 'static' | 'dynamic'
/** 路由首页的路径 */
readonly VITE_ROUTE_HOME_PATH: AuthRoute.RoutePath
/** iconify图标作为组件的前缀 */
readonly VITE_ICON_PREFIX: string
/**
* 本地SVG图标作为组件的前缀, 请注意一定要包含 VITE_ICON_PREFIX
* - 格式 {VITE_ICON_PREFIX}-{本地图标集合名称}
* - 例如icon-local
*/
readonly VITE_ICON_LOCAL_PREFIX: string
/** 开启请求代理 */
readonly VITE_HTTP_PROXY?: 'Y' | 'N'
/** 是否开启打包文件大小结果分析 */
@@ -40,19 +16,8 @@ interface ImportMetaEnv {
readonly VITE_COMPRESS?: 'Y' | 'N'
/** 压缩算法类型 */
readonly VITE_COMPRESS_TYPE?: 'gzip' | 'brotliCompress' | 'deflate' | 'deflateRaw'
/** 是否应用pwa */
readonly VITE_PWA?: 'Y' | 'N'
/**
* 是否开启生产模式下的mock
* @description 生产模式下会拦截XHR导致无法获取response不使用mock请求时设置为N
*/
readonly VITE_PROD_MOCK?: 'Y' | 'N'
/** hash路由模式 */
readonly VITE_HASH_ROUTE?: 'Y' | 'N'
/** 是否应用自动生成路由的插件 */
readonly VITE_SOYBEAN_ROUTE_PLUGIN?: 'Y' | 'N'
/** 是否是部署的vercel */
readonly VITE_VERCEL?: 'Y' | 'N'
/** giteeToken */
readonly VITE_GITEE_TOKEN: string
}
interface ImportMeta {

View File

@@ -1,88 +1,108 @@
<template>
<!-- 锁屏页面 -->
<div class="login-box select-none absolute top-0 left-0 w-full h-full z-9999 transition-all duration-300 ease-in-out">
<ActionBar :current-label="appWindow.label" :shrink="false" />
<div
data-tauri-drag-region
class="lock-bg select-none absolute top-0 left-0 w-full h-full z-9999 transition-all duration-300 ease-in-out">
<ActionBar class="absolute top-0 right-0 z-99999" :current-label="appWindow.label" :shrink="false" />
<Transition name="slide-fade" appear>
<!-- 壁纸界面 -->
<div v-if="!isUnlockPage" data-tauri-drag-region @click.stop="isUnlockPage = true" class="size-full">
<n-flex vertical align="center" :size="120" class="size-full mt-60px">
<n-flex vertical align="center" :size="20">
<p class="text-(80px #808080) font-bold">{{ currentTime }}</p>
<n-flex align="center" :size="30" class="text-(26px #909090)">
<div v-if="!isUnlockPage" @click.stop="isUnlockPage = true" class="size-full">
<n-flex vertical align="center" :size="120" class="size-full mt-10%">
<n-flex vertical align="center" :size="20" class="will-change-auto will-change-contents">
<p class="text-(100px #f1f1f1) font-bold">{{ currentTime }}</p>
<n-flex align="center" :size="30" class="text-(30px #f1f1f1)">
<p>{{ currentMonthAndDate }}</p>
<p>{{ currentWeekday }}</p>
</n-flex>
</n-flex>
<n-flex
vertical
justify="center"
align="center"
:size="20"
style="transition: all 0.6s ease-in-out"
class="cursor-pointer p-12px rounded-8px hover:bg-#13987f33">
<svg class="size-24px color-#808080 p-4px bg-#e3e3e3 rounded-8px"><use href="#search"></use></svg>
<p class="text-(16px #909090) w-240px line-clamp-2">
<n-flex vertical justify="center" align="center" :size="20" class="tips">
<svg><use href="#search"></use></svg>
<p class="text-(16px #f1f1f1) text-center">
这是一个开源的即时通讯(IM)应用它采用了一些最新的前端技术包括 TauriVue3Vite5UnoCSS
TypeScript这个项目的目标是提供一个高效稳定且易于使用的即时通讯平台
TypeScript
</p>
<p class="text-(12px #909090) opacity-0">这个项目的目标是提供一个高效稳定且易于使用的即时通讯平台</p>
<a
@click.stop="$event.stopPropagation()"
target="_blank"
rel="noopener noreferrer"
href="https://github.com/nongyehong/HuLa-IM-Tauri"
class="no-underline text-(14px #f3f3f3) opacity-0">
了解更多
</a>
</n-flex>
</n-flex>
</div>
<!-- 解锁界面 -->
<n-flex v-else data-tauri-drag-region vertical align="center" justify="center" :size="10" class="h-full">
<n-flex
v-else
data-tauri-drag-region
vertical
align="center"
justify="center"
:size="16"
class="h-full backdrop-blur-md">
<n-flex vertical align="center" justify="center" :size="30" class="mt--75px">
<n-avatar round bordered :size="120" :src="login.accountInfo.avatar" />
<p class="text-(18px #606060)">{{ login.accountInfo.name }}</p>
<n-avatar round style="border: 2px solid #f1f1f1" :size="120" :src="login.accountInfo.avatar" />
<p class="text-(24px #f1f1f1) font-bold">{{ login.accountInfo.name }}</p>
<!-- 密码输入框 -->
<n-input
v-if="!isLogining && !isWrongPassword"
ref="inputInstRef"
style="
width: 320px;
border: 2px solid rgba(104, 104, 104, 0.2);
border-bottom-color: rgba(19, 152, 127, 0.8);
"
placeholder="锁屏密码"
show-password-on="click"
type="password"
@keyup.enter.prevent="unlock"
v-model:value="password">
<template #suffix>
<n-popover trigger="hover">
<template #trigger>
<svg
@click.stop="unlock"
class="size-16px mr-6px p-[4px_6px] rounded-8px cursor-pointer transition-all duration-300 ease-in-out hover:(bg-#13987fe6 color-#e3e3e3)">
<use href="#arrow-right"></use>
</svg>
</template>
<p>进入系统</p>
</n-popover>
</template>
</n-input>
<n-config-provider :theme="lightTheme">
<n-input
v-if="!isLogining && !isWrongPassword"
ref="inputInstRef"
style="
width: 320px;
border: 2px solid rgba(255, 255, 255, 0.4);
border-bottom-color: rgba(19, 152, 127, 0.8);
background-color: #404040;
color: #fff;
"
placeholder="锁屏密码"
show-password-on="click"
type="password"
@keyup.enter.prevent="unlock"
v-model:value="password">
<template #suffix>
<n-popover trigger="hover">
<template #trigger>
<svg
@click.stop="unlock"
class="size-16px color-#e3e3e3 mr-6px p-[4px_6px] rounded-8px cursor-pointer transition-all duration-300 ease-in-out hover:bg-#13987fe6">
<use href="#arrow-right"></use>
</svg>
</template>
<p>进入系统</p>
</n-popover>
</template>
</n-input>
</n-config-provider>
<!-- 登录时显示的文字 -->
<n-flex vertical align="center" justify="center" :size="30" v-if="isLogining && !isWrongPassword">
<img class="size-32px" src="@/assets/img/loading-one.svg" alt="" />
<p class="text-(18px #404040)">登录中...</p>
<img class="size-42px" src="@/assets/img/loading-bright.svg" alt="" />
<p class="text-(20px #f1f1f1)">解锁中</p>
</n-flex>
<!-- 密码不正常时显示 -->
<n-flex v-if="isWrongPassword" vertical justify="center" align="center" :size="30">
<p class="text-(16px #707070)">密码不正确, 请再试一次</p>
<n-button @click="init" secondary class="w-120px"> 确定 </n-button>
<p class="text-(18px #f1f1f1)">密码不正确, 请再试一次</p>
<p
@click="init"
class="w-120px bg-[rgba(255,255,255,0.1)] backdrop-blur-xl cursor-pointer p-10px rounded-8px text-(14px #323232 center) font-bold">
确定
</p>
</n-flex>
</n-flex>
<n-flex v-if="!isLogining && !isWrongPassword" justify="space-between" align="center" :size="0" class="options">
<n-button quaternary color="#606060" @click="isUnlockPage = false">返回</n-button>
<n-button @click="logout" quaternary color="#707070">退出登录</n-button>
<n-button quaternary color="#707070">忘记密码</n-button>
<n-button @click="unlock" quaternary type="primary">进入系统</n-button>
<n-flex v-if="!isLogining && !isWrongPassword" justify="space-around" align="center" :size="0" class="options">
<p class="text-(14px #f1f1f1)" @click="isUnlockPage = false">返回</p>
<p class="text-(14px #e3e3e3)" @click="logout">退出登录</p>
<p class="text-(14px #e3e3e3)">忘记密码</p>
<p class="text-(14px #fff)" @click="unlock">进入系统</p>
</n-flex>
</n-flex>
</Transition>
@@ -94,7 +114,7 @@ import { setting } from '@/stores/setting.ts'
import { storeToRefs } from 'pinia'
import { useLogin } from '@/hooks/useLogin.ts'
import { onKeyStroke } from '@vueuse/core'
import { InputInst } from 'naive-ui'
import { InputInst, lightTheme } from 'naive-ui'
import { getWeekday } from '@/utils/Day.ts'
import dayjs from 'dayjs'
@@ -139,6 +159,7 @@ watch(isWrongPassword, (val) => {
}
})
/** 解锁 */
const unlock = () => {
if (password.value === '') {
window.$message.error('请输入密码')
@@ -170,7 +191,6 @@ const init = () => {
}
onMounted(() => {
console.log(currentWeekday.value)
intervalId = setInterval(() => {
currentTime.value = dayjs().format('HH:mm')
currentMonthAndDate.value = dayjs().format('MM/DD')
@@ -191,20 +211,53 @@ onUnmounted(() => {
})
</script>
<style scoped lang="scss">
@import '@/styles/scss/global/login-bg';
.lock-bg {
background-image: url('@/assets/img/lock_bg.png');
}
.options {
@apply w-320px;
p {
@apply text-(14px [--chat-text-color]) cursor-pointer select-none p-8px bg-#ccc rounded-lg;
@apply cursor-pointer select-none;
}
}
.tips {
@apply cursor-pointer w-240px p-12px rounded-8px transition-all duration-300 ease-in-out hover:bg-#323232;
svg {
@apply size-24px color-#f1f1f1 p-4px bg-#323232 rounded-8px;
}
&:hover {
p {
@apply opacity-100;
}
a {
@apply opacity-100 hover:underline;
}
}
}
:deep(.hover-box),
:deep(.action-close) {
svg {
color: #fff;
}
}
:deep(.hover-box) {
&:hover {
background-color: #464646;
}
}
:deep(.n-input .n-input__input-el, .n-input .n-input__textarea-el) {
color: #fff;
}
/*
进入和离开动画可以使用不同
持续时间和速度曲线。
*/
.slide-fade-enter-active {
transition: all 0.2s ease-out;
transition: all 0.2s ease-in-out;
}
.slide-fade-leave-active {

View File

@@ -1,7 +0,0 @@
<template>
<!-- 消息通知设置 -->
<main class="bg-blue">消息提醒</main>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss"></style>

View File

@@ -5,16 +5,6 @@ const sideOptions = ref<OPT.L.SettingSide[]>([
label: '通用',
icon: 'setting-config'
},
{
url: '/remind',
label: '消息通知',
icon: 'remind'
},
{
url: '/collection',
label: '存储管理',
icon: 'mini-sd-card'
},
{
url: '/loginSetting',
label: '登录设置',

View File

@@ -63,8 +63,8 @@ const loading = ref(true)
const loadText = ref('加载中...')
const QRCode = ref()
const scanStatus = ref<{
status: 'error' | 'success'
icon: 'cloudError' | 'success'
status: 'error' | 'success' | 'auth'
icon: 'cloudError' | 'success' | 'Security'
text: string
show: boolean
}>({ status: 'success', icon: 'success', text: '扫码成功', show: false })
@@ -72,7 +72,7 @@ const scanStatus = ref<{
watchEffect(() => {
// 等待授权中
if (loginStatus.value === LoginStatus.Waiting) {
loadText.value = '等待授权...'
handleAuth()
}
})
@@ -111,6 +111,18 @@ const handleError = (e: any) => {
loadText.value = '请稍后再试'
}
/** 处理授权场景 */
const handleAuth = () => {
loading.value = false
scanStatus.value = {
status: 'auth',
icon: 'Security',
text: '扫码成功,等待授权',
show: true
}
loadText.value = '等待授权...'
}
// TODO 做一个二维码过期时间重新刷新二维码的功能 (nyh -> 2024-01-27 00:37:18)
onMounted(() => {
if (!localStorage.getItem('wsLogin')) {