perf: ⚡ 优化锁屏页面功能
新增更新功能
This commit is contained in:
12
.env.dev
12
.env.dev
@@ -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
10
.env.development
Normal 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"
|
||||
12
.env.prod
12
.env.prod
@@ -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
3
.gitignore
vendored
@@ -22,3 +22,6 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
src-tauri/target
|
||||
.env.production
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
1
src/assets/img/loading-bright.svg
Normal file
1
src/assets/img/loading-bright.svg
Normal 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
BIN
src/assets/img/lock_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
@@ -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>
|
||||
<!-- 当回复消息为图片时渲染 -->
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** 计算字符长度 */
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -49,8 +49,7 @@ export const createAxios = (config?: AxiosRequestConfig): AxiosInstance => {
|
||||
return Promise.reject(
|
||||
window.$message.create('当前为测试环境,请注意辨别', {
|
||||
type: 'warning',
|
||||
closable: true,
|
||||
duration: 0
|
||||
closable: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
3
src/typings/components.d.ts
vendored
3
src/typings/components.d.ts
vendored
@@ -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
39
src/typings/env.d.ts
vendored
@@ -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 {
|
||||
|
||||
@@ -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)应用,它采用了一些最新的前端技术,包括 Tauri、Vue3、Vite5、UnoCSS 和
|
||||
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 {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<!-- 消息通知设置 -->
|
||||
<main class="bg-blue">消息提醒</main>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -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: '登录设置',
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
Reference in New Issue
Block a user