Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
basic-uniapp-v3
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-uniapp-v3
Commits
593878d8
提交
593878d8
authored
10月 24, 2024
作者:
方治民
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 添加 app-notice 全局通知模块 + 云函数 + 数据库表定义相关配置及示例
上级
81229b53
显示空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
500 行增加
和
30 行删除
+500
-30
pages.json
src/pages.json
+22
-1
index.ts
src/pages/common/notice/index.ts
+142
-0
index.vue
src/pages/common/notice/index.vue
+137
-0
index.vue
src/pages/index/index.vue
+4
-19
index.ts
src/utils/upgrade/index.ts
+12
-9
tsconfig.json
tsconfig.json
+3
-1
index.js
uniCloud-aliyun/cloudfunctions/app-notice-inspect/index.js
+118
-0
package.json
...oud-aliyun/cloudfunctions/app-notice-inspect/package.json
+7
-0
app-notice.schema.json
uniCloud-aliyun/database/app-notice.schema.json
+55
-0
没有找到文件。
src/pages.json
浏览文件 @
593878d8
...
@@ -64,7 +64,28 @@
...
@@ -64,7 +64,28 @@
"backgroundColorTop"
:
"transparent"
,
"backgroundColorTop"
:
"transparent"
,
"popGesture"
:
"none"
,
"popGesture"
:
"none"
,
"scrollIndicator"
:
false
,
"scrollIndicator"
:
false
,
"titleNView"
:
false
"titleNView"
:
false
,
"bounce"
:
"none"
},
"disableScroll"
:
true
}
},
//
===
应用全屏通知弹窗(场景:应用维护通知、用户通知公告等)
===
{
"path"
:
"pages/common/notice/index"
,
"style"
:
{
"navigationStyle"
:
"custom"
,
"background"
:
"transparent"
,
"app-plus"
:
{
"animationDuration"
:
200
,
"animationType"
:
"fade-in"
,
"background"
:
"transparent"
,
"backgroundColorTop"
:
"transparent"
,
"popGesture"
:
"none"
,
"scrollIndicator"
:
false
,
"webviewBGTransparent"
:
true
,
"titleNView"
:
false
,
"bounce"
:
"none"
},
},
"disableScroll"
:
true
"disableScroll"
:
true
}
}
...
...
src/pages/common/notice/index.ts
0 → 100644
浏览文件 @
593878d8
import
dayjs
from
'dayjs'
import
{
useRuntime
}
from
'@/hooks/app/useRuntime'
import
{
Storage
}
from
'@/utils/storage'
export
interface
Notice
{
/**
* 通知 ID
*/
id
:
number
|
string
/**
* 标题
*/
title
?:
string
/**
* 内容
*/
content
:
string
/**
* 按钮集合,confirm: 确认,exit: 退出
*/
buttons
?:
string
[]
/**
* 是否已确认
*/
confirmed
?:
boolean
}
export
interface
NoticeMessage
extends
Notice
{
/**
* 版本号(code)规则 JSON, 例如 { '>': '10000', '<': '20000' }
*/
version
?:
Recordable
/**
* 平台,默认为 all,支持 'android' | 'ios' | 'harmonyos' | 'windows' | 'macos' | 'linux' | 'all'
*/
os
?:
[
'android'
|
'ios'
|
'harmonyos'
|
'windows'
|
'macos'
|
'linux'
|
'all'
]
/**
* 验证参数,用于校验当前用户是否需要弹出通知,例如:用户信息,租户信息等
*/
verify
:
Recordable
}
/**
* 检查是否有应用通知,如果有自动跳转到通知页面,没有则返回 false
* @param verify 扩展校验参数,校验与通知中的 verify 字段一致
* @returns Promise<boolean> 是否有应用通知
*/
export
async
function
inspect
(
verify
:
Recordable
=
{}):
Promise
<
boolean
>
{
const
{
app
}
=
useRuntime
()
const
system
=
uni
.
getSystemInfoSync
()
const
params
=
{
datetime
:
dayjs
().
format
(
'YYYY-MM-DD HH:mm:ss'
),
app
:
{
id
:
system
.
appId
,
name
:
system
.
appName
,
version
:
system
.
appVersion
,
versionCode
:
system
.
appVersionCode
,
wgetVersion
:
app
.
value
.
version
||
system
.
appWgtVersion
||
system
.
appVersion
,
language
:
system
.
appLanguage
,
},
os
:
{
name
:
system
.
osName
,
version
:
system
.
osVersion
,
},
net
:
{
type
:
(
await
uni
.
getNetworkType
()).
networkType
,
},
rom
:
{
name
:
system
.
romName
,
version
:
system
.
romVersion
,
},
device
:
{
type
:
system
.
deviceType
,
brand
:
system
.
deviceBrand
,
model
:
system
.
deviceModel
,
},
browser
:
{
name
:
system
.
browserName
,
version
:
system
.
browserVersion
,
ua
:
system
.
ua
,
},
runtime
:
{
platform
:
system
.
platform
,
uniPlatform
:
system
.
uniPlatform
,
version
:
system
.
uniRuntimeVersion
,
compileVersion
:
system
.
uniCompileVersion
,
mode
:
import
.
meta
.
env
.
MODE
,
lastBuildTime
:
$app
.
lastBuildTime
,
},
// 自定义校验参数(例如:用户信息/租户信息,可参与校验是否需要弹窗,实现精确到指定用户的提醒)
verify
,
}
try
{
// 调用云函数查询
const
result
=
await
uniCloud
.
callFunction
({
name
:
'app-notice-inspect'
,
data
:
{
params
,
},
})
const
body
=
result
.
result
as
{
id
:
number
|
string
;
params
:
typeof
params
;
data
:
NoticeMessage
}
console
.
log
(
'[Notice] Response'
,
params
,
body
)
// 检查是否有通知
const
id
=
body
.
id
if
(
!
id
)
{
return
false
}
// 缓存通知数据
const
data
:
Notice
=
{
id
,
confirmed
:
getConfirm
(
id
),
...
body
.
data
,
}
getApp
().
globalData
.
notice
=
data
if
(
!
data
.
confirmed
)
{
uni
.
navigateTo
({
url
:
'/pages/common/notice/index'
})
return
true
}
}
catch
(
e
)
{
console
.
warn
(
e
)
}
return
false
}
export
function
setConfirm
(
id
:
number
|
string
)
{
if
(
getApp
().
globalData
.
notice
)
{
Storage
.
set
(
`notice-
${
id
}
`
,
'1'
)
getApp
().
globalData
.
notice
.
confirmed
=
true
}
}
export
function
getConfirm
(
id
:
number
|
string
)
{
return
Storage
.
get
(
`notice-
${
id
}
`
)
===
'1'
}
src/pages/common/notice/index.vue
0 → 100644
浏览文件 @
593878d8
<
script
setup
lang=
"ts"
>
import
type
{
Notice
}
from
'.'
import
{
setConfirm
}
from
'.'
// 获取通知信息
const
notice
=
ref
<
Notice
>
(
getApp
().
globalData
.
notice
||
{})
// 内容初始化高度
const
height
=
ref
(
100
)
onLoad
(()
=>
{
// 没有通知消息或者已经确认过
if
(
!
notice
.
value
.
id
||
notice
.
value
.
confirmed
)
{
Message
.
toast
(
'暂无通知消息 ~'
)
uni
.
navigateBack
()
return
}
// 禁止页面侧滑返回
const
pages
=
getCurrentPages
()
const
currentPage
=
pages
[
pages
.
length
-
1
]
const
currentWebview
=
currentPage
.
$getAppWebview
()
currentWebview
.
setStyle
({
popGesture
:
'none'
})
nextTick
(()
=>
{
setTimeout
(()
=>
{
uni
.
createSelectorQuery
()
.
select
(
'.notice-content'
)
.
boundingClientRect
((
data
:
UniNamespace
.
NodeInfo
)
=>
{
// 获取高度, 默认为 100-340
height
.
value
=
Math
.
max
(
100
,
Math
.
min
(
340
,
data
.
height
))
})
.
exec
()
},
300
)
})
})
// 预览图片
function
preview
(
e
:
{
src
:
string
;
imageUrls
:
string
[]
})
{
uni
.
previewImage
({
urls
:
[
e
.
src
],
current
:
0
,
})
}
// 点击链接
function
atap
(
href
:
string
)
{
if
(
href
.
startsWith
(
'http'
))
{
// 打开外部链接
uni
.
setClipboardData
({
data
:
href
,
success
:
()
=>
{
Message
.
toast
(
'已复制链接,请在浏览器中粘贴打开'
)
},
})
}
else
if
(
href
.
startsWith
(
'/pages/'
))
{
// 打开内部链接
uni
.
navigateTo
({
url
:
href
,
})
}
}
// 退出应用
function
quit
()
{
// 退出应用
// #ifdef APP-PLUS
if
(
uni
.
getSystemInfoSync
().
platform
===
'ios'
)
{
try
{
// @ts-expect-error
plus
.
ios
.
import
(
'UIApplication'
).
sharedApplication
().
performSelector
(
'abort'
)
}
catch
(
e
)
{
console
.
error
(
e
)
}
}
else
{
plus
.
runtime
.
quit
()
}
// #endif
}
// 确认知道到了
function
confirm
()
{
notice
.
value
.
id
&&
setConfirm
(
notice
.
value
.
id
)
uni
.
navigateBack
()
}
</
script
>
<
template
>
<view
class=
"notice-mask"
>
<view
class=
"w-80% p-3 bg-white rd-2 shadow shadow-2xl overflow-hidden"
>
<view
class=
"flex-center mt-2"
v-if=
"notice.title"
>
<text
class=
"font-bold text-36"
>
{{
notice
.
title
}}
</text>
</view>
<FuiDivider
text=
"·"
:height=
"50"
v-if=
"notice.title"
/>
<view
class=
"h-auto p-1"
>
<scroll-view
scroll-y
:style=
"
{ height: `${height}px` }">
<FuiParseGroup
class=
"notice-content"
@
preview=
"preview"
@
atap=
"atap"
>
<FuiParse
:nodes=
"notice.content"
language=
"md"
/>
</FuiParseGroup>
</scroll-view>
</view>
<view
class=
"flex gap-3 mt-3"
v-if=
"notice.buttons.length"
>
<FuiButton
type=
"gray"
@
click=
"confirm"
v-if=
"notice.buttons.includes('confirm')"
>
我知道了
</FuiButton>
<FuiButton
color=
"#fff"
background=
"#ff6363"
borderColor=
"#ff6363"
@
click=
"quit"
v-if=
"notice.buttons.includes('exit')"
>
退出应用
</FuiButton>
</view>
</view>
</view>
</
template
>
<
style
lang=
"less"
>
//
...
page
{
background
:
transparent
;
user-select
:
none
;
}
.notice-mask
{
position
:
fixed
;
inset
:
0
;
/* #ifndef APP-NVUE */
display
:
flex
;
/* #endif */
justify-content
:
center
;
align-items
:
center
;
background-color
:
rgb
(
0
0
0
/
40%
);
}
</
style
>
src/pages/index/index.vue
浏览文件 @
593878d8
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
import
{
checkUpgrade
,
closeSplashscreenAndChechUpgrade
}
from
'@/utils/upgrade'
import
{
checkUpgrade
,
closeSplashscreenAndChechUpgrade
}
from
'@/utils/upgrade'
import
{
useRuntime
}
from
'@/hooks/app/useRuntime'
import
{
useRuntime
}
from
'@/hooks/app/useRuntime'
import
{
useConcealedExit
}
from
'@/hooks/app/useConcealedExit'
import
{
useConcealedExit
}
from
'@/hooks/app/useConcealedExit'
import
*
as
Notice
from
'@/pages/common/notice'
const
{
exit
}
=
useConcealedExit
()
const
{
exit
}
=
useConcealedExit
()
const
{
app
}
=
useRuntime
()
const
{
app
}
=
useRuntime
()
...
@@ -13,27 +14,11 @@
...
@@ -13,27 +14,11 @@
onLoad
(()
=>
{
onLoad
(()
=>
{
// 关闭启动页并检查更新
// 关闭启动页并检查更新
closeSplashscreenAndChechUpgrade
()
closeSplashscreenAndChechUpgrade
()
// test API
API
.
example
.
hello
.
request
()
.
then
((
body
)
=>
{
title
.
value
=
body
console
.
log
(
'[API]'
,
body
,
$app
.
name
,
$app
.
version
)
Message
.
toast
(
body
)
})
.
catch
((
err
)
=>
{
console
.
error
(
'[API]'
,
err
)
})
// test WebSocket(STOMP)
Stomp
.
connect
(()
=>
{
Stomp
.
send
(
'/app/ping'
,
'ping'
)
})
})
// test uni-stat
onShow
(()
=>
{
uni
.
report
(
'onLoad'
,
`[Test] onLoad:
${
dayjs
().
format
(
'YYYY-MM-DD HH:mm:ss'
)}
`
)
// 检查是否有全局通知
Notice
.
inspect
()
})
})
function
surprise
()
{
function
surprise
()
{
...
...
src/utils/upgrade/index.ts
浏览文件 @
593878d8
...
@@ -3,23 +3,22 @@ import checkVersion from '@/uni_modules/uni-upgrade-center-app/utils/check-updat
...
@@ -3,23 +3,22 @@ import checkVersion from '@/uni_modules/uni-upgrade-center-app/utils/check-updat
// #endif
// #endif
export
function
checkUpgrade
(
toast
=
false
)
{
export
async
function
checkUpgrade
(
toast
=
false
):
Promise
<
void
>
{
// #ifdef APP-PLUS
// #ifdef APP-PLUS
// 版本更新检查
// 版本更新检查
if
(
toast
)
{
if
(
toast
)
{
Message
.
loading
(
'正在检查更新...'
)
Message
.
loading
(
'正在检查更新...'
)
}
}
checkVersion
()
try
{
.
then
((
res
)
=>
{
const
res
=
await
checkVersion
()
if
(
toast
&&
res
?.
code
===
0
)
{
if
(
toast
&&
res
?.
code
===
0
)
{
Message
.
toast
(
'已是最新版本~'
)
Message
.
toast
(
'已是最新版本~'
)
}
}
})
}
finally
{
.
finally
(()
=>
{
if
(
toast
)
{
if
(
toast
)
{
Message
.
hideLoading
()
Message
.
hideLoading
()
}
}
})
}
// #endif
// #endif
}
}
...
@@ -27,7 +26,7 @@ export function checkUpgrade(toast = false) {
...
@@ -27,7 +26,7 @@ export function checkUpgrade(toast = false) {
* 关闭 splashscreen 并检查更新
* 关闭 splashscreen 并检查更新
*/
*/
export
function
closeSplashscreenAndChechUpgrade
()
{
export
function
closeSplashscreenAndChechUpgrade
()
{
return
new
Promise
<
void
>
((
resolve
)
=>
{
return
new
Promise
<
void
>
((
resolve
,
reject
)
=>
{
// FIXED: pages 第一路由页面为登录页,加上 splashscreen 配置控制使得用户体验更好
// FIXED: pages 第一路由页面为登录页,加上 splashscreen 配置控制使得用户体验更好
// #ifdef APP-PLUS
// #ifdef APP-PLUS
nextTick
(()
=>
{
nextTick
(()
=>
{
...
@@ -35,11 +34,15 @@ export function closeSplashscreenAndChechUpgrade() {
...
@@ -35,11 +34,15 @@ export function closeSplashscreenAndChechUpgrade() {
const
{
platform
}
=
uni
.
getSystemInfoSync
()
const
{
platform
}
=
uni
.
getSystemInfoSync
()
const
isAndroid
=
platform
===
'android'
const
isAndroid
=
platform
===
'android'
setTimeout
(
setTimeout
(
()
=>
{
async
()
=>
{
plus
.
navigator
.
closeSplashscreen
()
plus
.
navigator
.
closeSplashscreen
()
try
{
// 检查更新
// 检查更新
checkUpgrade
()
await
checkUpgrade
()
resolve
()
resolve
()
}
catch
(
e
)
{
reject
(
e
)
}
},
},
isAndroid
?
1000
:
50
,
isAndroid
?
1000
:
50
,
)
)
...
...
tsconfig.json
浏览文件 @
593878d8
...
@@ -28,7 +28,9 @@
...
@@ -28,7 +28,9 @@
"@/*"
:
[
"src/*"
],
"@/*"
:
[
"src/*"
],
"/@/*"
:
[
"src/*"
],
"/@/*"
:
[
"src/*"
],
"/#/*"
:
[
"types/*"
]
"/#/*"
:
[
"types/*"
]
}
},
"rootDir"
:
"."
,
"outDir"
:
"dist"
},
},
"include"
:
[
"include"
:
[
"src/**/*.ts"
,
"src/**/*.ts"
,
...
...
uniCloud-aliyun/cloudfunctions/app-notice-inspect/index.js
0 → 100644
浏览文件 @
593878d8
'use strict'
exports
.
main
=
async
(
event
,
context
)
=>
{
// eslint-disable-next-line no-undef
const
db
=
uniCloud
.
database
()
const
dbCmd
=
db
.
command
const
{
total
}
=
await
db
.
collection
(
'opendb-app-list'
).
where
({
appid
:
context
.
appId
}).
count
()
if
(
total
<
1
)
{
return
{
errCode
:
1
,
errMsg
:
'应用信息不存在'
}
}
// 查询优先级最高且在生效中的 APP 通知
const
{
params
}
=
event
const
{
data
:
notices
}
=
await
db
.
collection
(
'app-notice'
)
.
where
({
appid
:
context
.
appId
,
enabled
:
true
,
expired
:
dbCmd
.
gt
(
Date
.
now
()),
})
.
orderBy
(
'priority'
,
'asc'
)
.
limit
(
1
)
.
get
()
if
(
notices
.
length
<
1
)
{
return
{
errCode
:
1
,
errMsg
:
'暂无生效中的通知'
}
}
// 获取通知信息
const
notice
=
notices
[
0
]
console
.
log
(
'notice'
,
notice
)
// 检查运行环境
if
(
notice
.
mode
!==
params
.
runtime
.
mode
)
{
return
{
errCode
:
1
,
errMsg
:
'运行环境不匹配'
,
message
:
`
${
params
.
runtime
.
mode
}
->
${
notice
.
mode
}
`
}
}
// 检查平台
if
(
notice
.
os
&&
notice
.
os
.
length
>
0
&&
!
notice
.
os
.
includes
(
'all'
)
&&
!
notice
.
os
.
includes
(
params
.
os
.
name
))
{
return
{
errCode
:
1
,
errMsg
:
'平台不匹配'
,
message
:
`
${
params
.
os
.
name
}
->
${
JSON
.
stringify
(
notice
.
os
)}
`
}
}
// 检查版本号
if
(
notice
.
version
)
{
const
keys
=
Object
.
keys
(
notice
.
version
)
const
code
=
Number
(
context
.
appWgtVersion
.
split
(
'.'
)
.
map
((
v
)
=>
String
(
v
).
padStart
(
2
,
'0'
))
.
join
(
''
),
)
const
mismatching
=
keys
.
map
((
v
)
=>
{
switch
(
v
)
{
case
'>'
:
if
(
code
<=
notice
.
version
[
v
])
{
return
false
}
break
case
'<'
:
if
(
code
>=
notice
.
version
[
v
])
{
return
false
}
break
case
'='
:
if
(
code
!==
notice
.
version
[
v
])
{
return
false
}
break
case
'>='
:
if
(
code
<
notice
.
version
[
v
])
{
return
false
}
break
case
'<='
:
if
(
code
>
notice
.
version
[
v
])
{
return
false
}
break
default
:
return
false
}
return
true
})
.
some
((
v
)
=>
!
v
)
if
(
mismatching
)
{
return
{
errCode
:
1
,
errMsg
:
'版本号不匹配'
,
message
:
`
${
context
.
appWgtVersion
}
->
${
code
}
->
${
JSON
.
stringify
(
notice
.
version
)}
`
,
}
}
}
// 检查自定义参数
const
verifyKeys
=
Object
.
keys
(
params
.
verify
)
if
(
verifyKeys
.
length
<
Object
.
keys
(
notice
.
verify
).
length
||
verifyKeys
.
some
((
v
)
=>
notice
.
verify
[
v
]
!==
params
.
verify
[
v
])
)
{
return
{
errCode
:
1
,
errMsg
:
'校验参数不匹配'
,
message
:
`
${
JSON
.
stringify
(
params
.
verify
)}
->
${
JSON
.
stringify
(
notice
.
verify
)}
`
,
}
}
// 返回数据给客户端
return
{
id
:
notice
.
_id
,
params
:
{
app
:
params
.
app
,
verify
:
params
.
verify
,
},
data
:
{
...
notice
,
},
}
}
uniCloud-aliyun/cloudfunctions/app-notice-inspect/package.json
0 → 100644
浏览文件 @
593878d8
{
"name"
:
"app-notice-inspect"
,
"dependencies"
:
{},
"extensions"
:
{
"uni-cloud-jql"
:
{}
}
}
uniCloud-aliyun/database/app-notice.schema.json
0 → 100644
浏览文件 @
593878d8
//
文档教程
:
https
:
//uniapp.dcloud.net.cn/uniCloud/schema
{
"bsonType"
:
"object"
,
"required"
:
[],
"permission"
:
{
"read"
:
true
,
"create"
:
false
,
"update"
:
false
,
"delete"
:
false
},
"properties"
:
{
"_id"
:
{
"description"
:
"ID,系统自动生成"
},
"created_at"
:
{
"description"
:
"创建时间"
},
"update_at"
:
{
"description"
:
"更新时间"
},
"appid"
:
{
"description"
:
"appId"
},
"title"
:
{
"description"
:
"标题"
},
"content"
:
{
"description"
:
"内容"
},
"buttons"
:
{
"description"
:
"按钮列表"
},
"priority"
:
{
"description"
:
"优先级,数值越小,优先级越高"
},
"enabled"
:
{
"description"
:
"是否启用"
},
"expired"
:
{
"description"
:
"过期时间"
},
"platform"
:
{
"description"
:
"平台"
},
"mode"
:
{
"description"
:
"运行模式,development:开发模式,preview:预览模式,production:生产模式"
},
"version"
:
{
"description"
:
"版本号规则 JSON, 例如 { '>': '1.0.0', '<': '2.0.0' }"
},
"verify"
:
{
"description"
:
"自定义校验参数 JSON, 例如 { 'userId': '1', 'tenant': 'YR' }"
}
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论