Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
ds147000
/
react-native-project-storage
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 5dec9443
authored
Dec 09, 2020
by
杨周龙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化代码
1 parent
71e5cdaf
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
440 additions
and
312 deletions
.eslintIgnore
.eslintrc.json
App.tsx
src/api/version.ts
src/components/privacy-alert/style.ts
src/components/privacy-alert/view.tsx
src/config/app.ts
src/libs/check.ts
src/libs/fetch.ts
src/libs/format.ts
src/libs/http-request.ts
src/libs/utils.ts
src/router/config.tsx
src/router/index.tsx
src/router/ref.ts
src/router/route/index.tsx
src/router/tab/index.tsx
src/store/context.ts
src/theme/colors.ts
src/views/about/feature-detail/style.ts
src/views/about/feature-detail/view.tsx
src/views/about/features/style.ts
src/views/about/features/view.tsx
src/views/about/privacy/style.ts
src/views/about/privacy/view.tsx
src/views/about/style.ts
src/views/about/view.tsx
src/views/home/view.tsx
.eslintIgnore
View file @
5dec944
...
...
@@ -3,3 +3,5 @@ lib/
babel.config.js
metro.config.js
prod.js
__test*
mock/
.eslintrc.json
View file @
5dec944
{
"env"
:
{
"browser"
:
true
,
"es
2021
"
:
true
,
"es
6
"
:
true
,
"node"
:
true
,
"mocha"
:
true
,
"jest"
:
true
,
...
...
@@ -19,7 +19,7 @@
"ecmaFeatures"
:
{
"jsx"
:
true
},
"ecmaVersion"
:
12
,
"ecmaVersion"
:
8
,
"sourceType"
:
"module"
},
"plugins"
:
[
...
...
App.tsx
View file @
5dec944
...
...
@@ -18,33 +18,35 @@ import { APP } from './src/config'
import SplashScreen from 'react-native-splash-screen'
import store from './src/store'
//阻止系统缩放
TextInput.defaultProps = Object.assign({}, TextInput.defaultProps, { allowFontScaling: false })
Text.defaultProps = Object.assign({}, Text.defaultProps, { allowFontScaling: false })
const Page = () => {
useLayoutEffect(() => {
SplashScreen.hide()
}, [])
useEffect(() => {
(async () => Update(`${APP.appAdminUrl}/api/app/version/${APP.APP_CODE}`, await getVersionCode()))()
}, [])
return (
<Provider store={store}>
{Platform.OS === 'ios' && <StatusBar translucent={true} backgroundColor="rgba(255,255,255,0)" barStyle="dark-content" />}
<PortalHot>
<SafeAreaProvider>
<RouterView />
<PrivacyAlert />
</SafeAreaProvider>
</PortalHot>
</Provider>
)
// 阻止系统缩放
TextInput['defaultProps'] = Object.assign({}, TextInput['defaultProps'], { allowFontScaling: false })
Text['defaultProps'] = Object.assign({}, Text['defaultProps'], { allowFontScaling: false })
const Page: React.FC = () => {
useLayoutEffect(() => {
SplashScreen.hide()
}, [])
useEffect(() => {
const get = async (): Promise<void> => {
Update(`${APP.appAdminUrl}/api/app/version/${APP.APP_CODE}`, await getVersionCode())
return
}
get()
}, [])
return (
<Provider store={store}>
{Platform.OS === 'ios' && <StatusBar translucent={true} backgroundColor="rgba(255,255,255,0)" barStyle="dark-content" />}
<PortalHot>
<SafeAreaProvider>
<RouterView />
<PrivacyAlert />
</SafeAreaProvider>
</PortalHot>
</Provider>
)
}
export default Page
src/api/version.ts
0 → 100644
View file @
5dec944
import
{
FETCH
}
from
'../libs/fetch'
import
{
APP
}
from
'../config/app'
import
{
CancelTokenSource
}
from
'axios'
export
const
getTopVersion
=
(
successCall
,
errorCall
):
CancelTokenSource
=>
{
return
FETCH
.
sourceRequest
({
url
:
`
${
APP
.
appAdminUrl
}
/api/app/version/
${
APP
.
APP_CODE
}
`
},
successCall
,
errorCall
)
}
/** 获取版本更新列表 */
export
const
getVersionList
=
(
successCall
,
errorCall
):
CancelTokenSource
=>
{
return
FETCH
.
sourceRequest
({
url
:
`
${
APP
.
appAdminUrl
}
/api/app_version/
${
APP
.
APP_CODE
}
`
},
successCall
,
errorCall
)
}
src/components/privacy-alert/style.ts
View file @
5dec944
import
{
StyleSheet
}
from
'react-native'
import
{
setUnit
}
from
'../../libs/utils'
import
{
Alert
}
from
'../../theme/colors'
const
styles
=
StyleSheet
.
create
({
content
:
{
color
:
'#333'
,
color
:
Alert
.
content
,
fontSize
:
setUnit
(
30
)
},
privacy
:
{
color
:
'#1892FF'
,
color
:
Alert
.
privacy
,
fontSize
:
setUnit
(
30
)
}
})
...
...
src/components/privacy-alert/view.tsx
View file @
5dec944
...
...
@@ -7,29 +7,28 @@ import React, { useCallback, useEffect, useState } from 'react'
import { Text, Linking } from 'react-native'
import { Modal, Storage } from 'react-native-mb-ui'
import { APP } from '../../config'
import { setUnit } from '../../libs/utils'
import { styles } from './style'
const PrivacyAlert = () => {
const PrivacyAlert
: React.FC
= () => {
const [visible, setVisible] = useState(false)
useEffect(() => {
const showPrivacy = async (): Promise<void> => {
const notFirst = await Storage.getItem(APP.notFirstInstall)
if (notFirst === null)
setVisible(true)
}
showPrivacy()
}, [])
const goPrivacy = useCallback(() => Linking.openURL(APP.privacyLink), [])
const showPrivacy = async () => {
const notFirst = await Storage.getItem(APP.notFirstInstall)
if (notFirst === null)
setVisible(true)
}
const onOk = useCallback(() => {
setVisible(false)
Storage.setItem(APP.notFirstInstall, true)
})
}
, []
)
return (
<Modal
...
...
@@ -37,7 +36,6 @@ const PrivacyAlert = () => {
title='温馨提示'
onClose={onOk}
button={[{ text: '我知道了' }]}
style={{ width: setUnit(560) }}
content={
<Text style={styles.content}>{`欢迎来到信巴迪商品交易所, 感谢您对信巴迪的信任和支持!\n`}
为了提供给您更加优质和个性化的服务, 我们会收集或使用您的搜索、浏览与购买等信息。具体内容请您详阅
...
...
src/config/app.ts
View file @
5dec944
const
isBuildDebug
=
process
.
env
.
NODE_ENV
===
'development'
||
false
const
APP
=
{
appName
:
''
,
/** @description token存储的名称 */
tokenName
:
'jwt'
,
/** @description token在存储的时长,单位 天 */
tokenExpires
:
7
,
/**@description 初始的HTTP请求的全局header头*/
/**
@description 初始的HTTP请求的全局header头*/
header
:
{},
/**@description API基础请求地址*/
baseUrl
:
isBuildDebug
?
`https://gateway-dev.b2bwings.com/`
:
'https://gateway.b2bwings.com'
,
/**
@description API基础请求地址*/
baseUrl
:
isBuildDebug
?
`https://gateway-dev.b2bwings.com/`
:
'https://gateway.b2bwings.com'
,
/**@description 应用的登陆API的PATH*/
/**
@description 应用的登陆API的PATH*/
loginPath
:
'/user/sysLogin/login'
,
/**@description 401页面地址,用于提醒用户登陆状态失效*/
/**
@description 401页面地址,用于提醒用户登陆状态失效*/
error404
:
'/404'
,
/**@description 静态资源目录,必须。用于菜单图标显示*/
/**
@description 静态资源目录,必须。用于菜单图标显示*/
STATIS_URL
:
'https://b2bwings-system-image.oss-cn-shenzhen.aliyuncs.com/'
,
/**@description 静态资源目录,必须。图片地址*/
/**
@description 静态资源目录,必须。图片地址*/
IMG_URL
:
'https://images.b2bwings.com/'
,
/**@description tab按钮颜色配置*/
/**
@description tab按钮颜色配置*/
tabConfig
:
{
activeTintColor
:
'#F77116'
,
inactiveTintColor
:
'#434343'
...
...
@@ -53,22 +54,22 @@ const APP = {
/** @description 配置发送邮件接口中的跳转链接(link参数),重置邮箱用 */
emailLinkSetEmail
:
isBuildDebug
?
'https://xbd-dev.b2bwings.com/setMail'
:
'https://xbd.b2bwings.com/setMail'
,
/**@description 用户信息本地存储名称 */
/**
@description 用户信息本地存储名称 */
authCacheName
:
'_auth'
,
/**@description 查询版本更新的API地址 */
/**
@description 查询版本更新的API地址 */
updateApi
:
isBuildDebug
?
'http://app-admin-dev.b2bwings.com/api/app/version/'
:
'http://app-admin.b2bwings.com/api/app/version/'
,
/**@description app版本管理url */
/**
@description app版本管理url */
appAdminUrl
:
isBuildDebug
?
'http://app-admin-dev.b2bwings.com'
:
'http://app-admin.b2bwings.com'
,
/**@public APP编码 */
/**
@public APP编码 */
APP_CODE
:
isBuildDebug
?
''
:
''
,
/**@description 隐私政策链接 */
/**
@description 隐私政策链接 */
privacyLink
:
'https://app-static.b2bwings.com/static/page/privacy-policy/PrivacyPolicy.html'
,
/**@description 是否首次安装进入app */
/**
@description 是否首次安装进入app */
notFirstInstall
:
'_not_first_install'
}
...
...
src/libs/check.ts
View file @
5dec944
...
...
@@ -5,21 +5,21 @@
*/
class
CheckUtil
{
/**校验邮箱格式 */
static
isEmail
(
str
)
{
le
t
reg
=
/^
[
a-zA-Z0-9.!#$%&'*+
/
=?^_`{|}~-
]
+@
[
a-zA-Z0-9
](?:[
a-zA-Z0-9-
]{0,61}[
a-zA-Z0-9
])?(?:\.[
a-zA-Z0-9
](?:[
a-zA-Z0-9-
]{0,61}[
a-zA-Z0-9
])?)
*$/
/**
校验邮箱格式 */
static
isEmail
(
str
)
:
boolean
{
cons
t
reg
=
/^
[
a-zA-Z0-9.!#$%&'*+
/
=?^_`{|}~-
]
+@
[
a-zA-Z0-9
](?:[
a-zA-Z0-9-
]{0,61}[
a-zA-Z0-9
])?(?:\.[
a-zA-Z0-9
](?:[
a-zA-Z0-9-
]{0,61}[
a-zA-Z0-9
])?)
*$/
return
reg
.
test
(
str
)
}
/**校验手机号 */
static
isMobile
(
str
)
{
le
t
reg
=
/^
(?:(?:\+
|00
)
86
)?
1
[
3-9
]\d{9}
$/
/**
校验手机号 */
static
isMobile
(
str
)
:
boolean
{
cons
t
reg
=
/^
(?:(?:\+
|00
)
86
)?
1
[
3-9
]\d{9}
$/
return
reg
.
test
(
str
)
}
/**校验用户账号 */
static
checkAccount
(
str
)
{
le
t
reg
=
/^
\d{9}
$/
/**
校验用户账号 */
static
checkAccount
(
str
)
:
boolean
{
cons
t
reg
=
/^
\d{9}
$/
return
reg
.
test
(
str
)
}
}
...
...
src/libs/fetch.ts
View file @
5dec944
import
h
ttp
from
'./http-request'
import
H
ttp
from
'./http-request'
import
{
APP
}
from
'../config'
const
FETCH
=
new
h
ttp
(
APP
.
baseUrl
)
const
FETCH
=
new
H
ttp
(
APP
.
baseUrl
)
export
{
FETCH
}
src/libs/format.ts
View file @
5dec944
...
...
@@ -4,25 +4,25 @@
* @param {String|Number} num
* @returns {String}
*/
export
function
formatPhoneNo
(
num
)
{
return
num
.
toString
().
replace
(
/
(\d{3})\d{4}(\d{4})
/
,
'$1****$2'
)
export
function
formatPhoneNo
(
num
)
:
string
{
return
num
.
toString
().
replace
(
/
(\d{3})\d{4}(\d{4})
/
,
'$1****$2'
)
}
/**
* 格式化Email为 h****@b2bwings.com 的格式
* @param {*} str
*/
export
function
formatEmail
(
str
)
{
if
(
!
str
)
{
return
''
}
le
t
i
=
str
.
indexOf
(
'@'
)
if
(
i
<=
0
)
{
return
''
}
le
t
start
=
str
.
substring
(
0
,
1
)
le
t
end
=
str
.
substring
(
i
)
return
`
${
start
}
****
${
end
}
`
export
function
formatEmail
(
str
)
:
string
{
if
(
!
str
)
return
''
cons
t
i
=
str
.
indexOf
(
'@'
)
if
(
i
<=
0
)
return
''
cons
t
start
=
str
.
substring
(
0
,
1
)
cons
t
end
=
str
.
substring
(
i
)
return
`
${
start
}
****
${
end
}
`
}
/**
...
...
@@ -31,13 +31,10 @@ export function formatEmail(str) {
* @author sheng
* @date 2020/04/26
*/
export
function
thousandBitSeparator
(
num
)
{
return
num
&&
(
num
.
toString
().
indexOf
(
'.'
)
!=
-
1
?
num
.
toString
().
replace
(
/
(\d)(?=(\d{3})
+
\.)
/g
,
function
(
$0
,
$1
)
{
return
$1
+
","
})
:
num
.
toString
().
replace
(
/
(\d)(?=(\d{3})
+$
)
/g
,
function
(
$0
,
$1
)
{
return
$1
+
","
}))
export
function
thousandBitSeparator
(
num
):
string
{
return
num
&&
(
num
.
toString
().
indexOf
(
'.'
)
!==
-
1
?
num
.
toString
().
replace
(
/
(\d)(?=(\d{3})
+
\.)
/g
,
function
(
$0
,
$1
)
{
return
$1
+
","
})
:
num
.
toString
().
replace
(
/
(\d)(?=(\d{3})
+$
)
/g
,
function
(
$0
,
$1
)
{
return
$1
+
","
}))
}
/**
...
...
@@ -45,8 +42,8 @@ export function thousandBitSeparator(num) {
* @param {number} stmp 毫秒时间戳
* @returns {number} 毫秒时间戳
*/
export
function
getDateStartTime
(
stmp
)
{
return
new
Date
(
new
Date
(
Number
(
stmp
)).
toLocaleDateString
()).
getTime
()
export
function
getDateStartTime
(
stmp
)
:
number
{
return
new
Date
(
new
Date
(
Number
(
stmp
)).
toLocaleDateString
()).
getTime
()
}
/**
...
...
@@ -54,12 +51,12 @@ export function getDateStartTime(stmp) {
* @param {date} date 毫秒时间戳
* @returns {number} 毫秒时间戳
*/
export
function
getDateEndTime
(
stmp
)
{
return
new
Date
(
new
Date
(
new
Date
(
Number
(
stmp
)).
toLocaleDateString
()).
getTime
()
+
24
*
60
*
60
*
1000
-
1
)
export
function
getDateEndTime
(
stmp
)
:
Date
{
return
new
Date
(
new
Date
(
new
Date
(
Number
(
stmp
)).
toLocaleDateString
()).
getTime
()
+
24
*
60
*
60
*
1000
-
1
)
}
/**
...
...
@@ -67,26 +64,27 @@ export function getDateEndTime(stmp) {
* @param {*} fmt
* @param {*} time 毫秒时间戳
*/
export
function
dateFormat
(
fmt
,
time
)
{
let
ret
let
newDate
=
new
Date
()
//实例化一个Date对象
newDate
.
setTime
(
time
)
const
opt
=
{
"Y+"
:
newDate
.
getFullYear
().
toString
(),
// 年
"M+"
:
(
newDate
.
getMonth
()
+
1
).
toString
(),
// 月
"D+"
:
newDate
.
getDate
().
toString
(),
// 日
"h+"
:
newDate
.
getHours
().
toString
(),
// 时
"m+"
:
newDate
.
getMinutes
().
toString
(),
// 分
"s+"
:
newDate
.
getSeconds
().
toString
()
// 秒
}
for
(
let
k
in
opt
)
{
ret
=
new
RegExp
(
"("
+
k
+
")"
).
exec
(
fmt
)
if
(
ret
)
{
fmt
=
fmt
.
replace
(
ret
[
1
],
(
ret
[
1
].
length
==
1
)
?
(
opt
[
k
])
:
(
opt
[
k
].
padStart
(
ret
[
1
].
length
,
"0"
)))
export
function
dateFormat
(
fmt
,
time
):
string
{
let
ret
const
newDate
=
new
Date
()
// 实例化一个Date对象
newDate
.
setTime
(
time
)
const
opt
=
{
"Y+"
:
newDate
.
getFullYear
().
toString
(),
// 年
"M+"
:
(
newDate
.
getMonth
()
+
1
).
toString
(),
// 月
"D+"
:
newDate
.
getDate
().
toString
(),
// 日
"h+"
:
newDate
.
getHours
().
toString
(),
// 时
"m+"
:
newDate
.
getMinutes
().
toString
(),
// 分
"s+"
:
newDate
.
getSeconds
().
toString
()
// 秒
}
for
(
const
k
in
opt
)
{
ret
=
new
RegExp
(
"("
+
k
+
")"
).
exec
(
fmt
)
if
(
ret
)
{
fmt
=
fmt
.
replace
(
ret
[
1
],
(
ret
[
1
].
length
===
1
)
?
(
opt
[
k
])
:
(
opt
[
k
].
padStart
(
ret
[
1
].
length
,
"0"
)))
}
}
}
return
fmt
return
fmt
}
/**
...
...
@@ -95,27 +93,25 @@ export function dateFormat(fmt, time) {
* @author sheng
* @date 2020/06/23
*/
export
function
formatQuery
(
query
)
{
if
(
typeof
query
!==
'object'
)
{
return
''
}
let
params
=
[]
if
(
query
)
{
for
(
let
item
in
query
)
{
let
vals
=
query
[
item
]
if
(
vals
!==
undefined
)
{
params
.
push
(
item
+
'='
+
query
[
item
])
}
export
function
formatQuery
(
query
):
string
{
if
(
typeof
query
!==
'object'
)
return
''
const
params
=
[]
if
(
query
)
{
for
(
const
item
in
query
)
{
const
vals
=
query
[
item
]
if
(
vals
!==
undefined
)
params
.
push
(
item
+
'='
+
query
[
item
])
}
}
}
return
params
.
length
?
'?'
+
params
.
join
(
'&'
)
:
''
return
params
.
length
?
'?'
+
params
.
join
(
'&'
)
:
''
}
/**minutes */
export
function
getRemainTime
(
minutes
)
{
/**
剩余小时 */
le
t
hour
=
Math
.
floor
(
minutes
/
60
)
/**
剩余分钟 */
le
t
min
=
Math
.
round
(
minutes
%
60
)
return
hour
<=
0
?
`
${
min
}
分钟`
:
`
${
hour
}
小时
${
min
}
分钟`
/**
minutes */
export
function
getRemainTime
(
minutes
)
:
string
{
/**
剩余小时 */
cons
t
hour
=
Math
.
floor
(
minutes
/
60
)
/**
剩余分钟 */
cons
t
min
=
Math
.
round
(
minutes
%
60
)
return
hour
<=
0
?
`
${
min
}
分钟`
:
`
${
hour
}
小时
${
min
}
分钟`
}
src/libs/http-request.ts
View file @
5dec944
import
axios
from
'axios'
import
axios
,
{
AxiosInstance
,
AxiosResponse
,
CancelTokenSource
}
from
'axios'
import
{
APP
}
from
'../config'
import
{
getStore
}
from
'../store/context'
import
{
navigate
}
from
'../router/ref'
import
{
ModalManager
}
from
'react-native-mb-ui'
class
HttpRequest
{
public
instance
=
null
public
instance
:
AxiosInstance
=
null
public
header
=
null
constructor
(
private
baseUrl
)
{
this
.
header
=
{
...
APP
.
header
}
this
.
init
()
}
/**初始化 */
init
()
{
le
t
instance
=
axios
.
create
({
baseURL
:
this
.
baseUrl
,
headers
:
this
.
header
})
/**
初始化 */
init
()
:
void
{
cons
t
instance
=
axios
.
create
({
baseURL
:
this
.
baseUrl
,
headers
:
this
.
header
})
this
.
interceptors
(
instance
)
this
.
instance
=
instance
}
/**绑定请求拦截器 */
interceptors
(
instance
)
{
/**
绑定请求拦截器 */
interceptors
(
instance
)
:
void
{
// 请求
instance
.
interceptors
.
request
.
use
(
config
=>
{
return
config
...
...
@@ -34,14 +34,16 @@ class HttpRequest {
return
this
.
handleRespone
(
res
)
},
error
=>
{
/* eslint-disable no-console */
if
(
process
.
env
.
NODE_ENV
===
'development'
)
console
.
warn
(
error
)
return
Promise
.
reject
(
error
.
response
?
`发生错误,错误代码:
${
error
.
response
.
status
}
;详情:
${
error
.
response
.
message
||
''
}
`
:
error
.
message
+
""
)
})
}
/**请求 */
async
request
(
options
)
{
/**
请求 */
async
request
(
options
)
:
Promise
<
AxiosResponse
<
unknown
>>
{
return
this
.
instance
(
options
)
}
...
...
@@ -51,8 +53,8 @@ class HttpRequest {
* @param {function} successCallback
* @param {function} errorCallback
*/
sourceRequest
(
options
,
successCallback
,
errorCallback
)
{
const
source
=
axios
.
CancelToken
.
source
()
sourceRequest
(
options
,
successCallback
,
errorCallback
)
:
CancelTokenSource
{
const
source
:
CancelTokenSource
=
axios
.
CancelToken
.
source
()
options
=
Object
.
assign
(
options
,
{
cancelToken
:
source
.
token
})
this
.
instance
(
options
)
.
then
(
successCallback
)
...
...
@@ -66,7 +68,7 @@ class HttpRequest {
* @param {string} key
* @param {any} value
*/
setHeader
(
key
,
value
)
{
setHeader
(
key
,
value
)
:
void
{
this
.
instance
.
defaults
.
headers
.
common
[
key
]
=
value
}
...
...
@@ -74,7 +76,7 @@ class HttpRequest {
* 设置URL
* @param {string} url
*/
setBaseUrl
(
url
)
{
setBaseUrl
(
url
)
:
void
{
this
.
instance
.
defaults
.
baseURL
=
url
}
...
...
@@ -82,10 +84,10 @@ class HttpRequest {
* 处理响用体
* @param {response} res
*/
handleRespone
(
res
)
{
handleRespone
(
res
)
:
Promise
<
string
|
unknown
>
{
const
{
code
,
message
,
data
}
=
res
.
data
switch
(
code
)
{
case
200
:
1590
case
200
:
return
data
case
401
:
ModalManager
.
alert
({
title
:
'提示'
,
content
:
'登陆状态失效,请重新登陆'
})
...
...
@@ -99,7 +101,7 @@ class HttpRequest {
}
}
resetState
()
{
resetState
()
:
void
{
getStore
().
dispatch
.
user
.
reset
()
getStore
().
dispatch
.
me
.
reset
()
navigate
(
'Login'
)
...
...
src/libs/utils.ts
View file @
5dec944
...
...
@@ -16,18 +16,18 @@ const UI_SACEL = WINDOWS.width / UI_WIDTH
* 设置px单位
* @param {*} num
*/
export
const
setUnit
=
num
=>
{
export
const
setUnit
=
(
num
):
number
=>
{
return
num
*
UI_SACEL
}
/** 获取版本号 */
export
const
getVersionCode
=
async
()
=>
await
DeviceInfo
.
getBuildNumber
(
)
export
const
getVersionCode
=
async
()
:
Promise
<
number
>
=>
Number
(
await
DeviceInfo
.
getBuildNumber
()
)
/** 获取版本名称 */
export
const
getVersion
=
async
()
=>
await
DeviceInfo
.
getVersion
()
export
const
getVersion
=
async
()
:
Promise
<
string
>
=>
DeviceInfo
.
getVersion
()
/** 获取屏幕高度 */
export
const
getHeight
=
()
=>
WINDOWS
.
height
export
const
getHeight
=
()
:
number
=>
WINDOWS
.
height
/**
...
...
@@ -35,16 +35,16 @@ export const getHeight = () => WINDOWS.height
* @param {string} phone
* @returns {Object}
*/
export
const
checkPhoneAndCode
=
(
phone
,
code
)
=>
{
if
(
!
phone
.
trim
().
length
)
{
export
const
checkPhoneAndCode
=
(
phone
,
code
)
:
{
status
:
number
;
msg
:
string
}
=>
{
if
(
!
phone
.
trim
().
length
)
return
{
status
:
0
,
msg
:
'手机号不能为空'
}
}
if
(
!
CheckUtil
.
isMobile
(
phone
))
{
if
(
!
CheckUtil
.
isMobile
(
phone
))
return
{
status
:
0
,
msg
:
'手机号格式不正确'
}
}
if
(
!
code
.
trim
().
length
)
{
if
(
!
code
.
trim
().
length
)
return
{
status
:
0
,
msg
:
'验证码不能为空'
}
}
return
{
status
:
1
,
msg
:
''
}
}
...
...
@@ -54,16 +54,16 @@ export const checkPhoneAndCode = (phone, code) => {
* @param {*} confirmEmail
* @returns {Object}
*/
export
const
checkEmails
=
(
email
,
confirmEmail
)
=>
{
if
(
!
email
.
trim
().
length
)
{
export
const
checkEmails
=
(
email
,
confirmEmail
)
:
{
status
:
number
;
msg
:
string
}
=>
{
if
(
!
email
.
trim
().
length
)
return
{
status
:
0
,
msg
:
'邮箱不能为空'
}
}
if
(
!
CheckUtil
.
isEmail
(
email
))
{
if
(
!
CheckUtil
.
isEmail
(
email
))
return
{
status
:
0
,
msg
:
'邮箱格式不正确'
}
}
if
(
email
!==
confirmEmail
)
{
if
(
email
!==
confirmEmail
)
return
{
status
:
0
,
msg
:
'两次输入邮箱不一致'
}
}
return
{
status
:
1
,
msg
:
''
}
}
...
...
@@ -71,8 +71,8 @@ export const checkEmails = (email, confirmEmail) => {
* 判断token是否过期
* @param {*} saveTime token存储时间
*/
export
const
isTokenExpired
=
(
saveTime
)
=>
{
le
t
now
=
new
Date
().
getTime
()
export
const
isTokenExpired
=
(
saveTime
)
:
boolean
=>
{
cons
t
now
=
new
Date
().
getTime
()
return
now
-
saveTime
>
APP
.
tokenExpires
*
24
*
60
*
60
*
1000
}
...
...
@@ -81,7 +81,7 @@ export const isTokenExpired = (saveTime) => {
* @param {*} jwt
* @param {*} sessionId
*/
export
const
setHeader
=
(
jwt
,
sessionId
)
=>
{
export
const
setHeader
=
(
jwt
,
sessionId
)
:
void
=>
{
FETCH
.
setHeader
(
'Authorization'
,
jwt
)
FETCH
.
setHeader
(
'Sessionid'
,
sessionId
)
}
...
...
@@ -91,14 +91,42 @@ export const setHeader = (jwt, sessionId) => {
* 重置路由栈
* @param {*} navigation
*/
export
const
resetRoutes
=
navigation
=>
{
export
const
resetRoutes
=
(
navigation
):
void
=>
{
navigation
.
dispatch
(
CommonActions
.
reset
({
index
:
1
,
routes
:
[
{
name
:
'Index'
},
{
name
:
'Login'
}
]
,
]
})
)
}
/**
* 日期格式化
* @param {*} fmt
* @param {*} time 毫秒时间戳
*/
export
function
dateFormat
(
fmt
,
time
):
string
{
let
ret
const
newDate
:
Date
=
new
Date
()
// 实例化一个Date对象
newDate
.
setTime
(
time
)
const
opt
=
{
"Y+"
:
newDate
.
getFullYear
().
toString
(),
// 年
"M+"
:
(
newDate
.
getMonth
()
+
1
).
toString
(),
// 月
"D+"
:
newDate
.
getDate
().
toString
(),
// 日
"h+"
:
newDate
.
getHours
().
toString
(),
// 时
"m+"
:
newDate
.
getMinutes
().
toString
(),
// 分
"s+"
:
newDate
.
getSeconds
().
toString
()
// 秒
}
for
(
const
k
in
opt
)
{
ret
=
new
RegExp
(
"("
+
k
+
")"
).
exec
(
fmt
)
if
(
ret
)
{
fmt
=
fmt
.
replace
(
ret
[
1
],
(
ret
[
1
].
length
===
1
)
?
(
opt
[
k
])
:
(
opt
[
k
].
padStart
(
ret
[
1
].
length
,
"0"
)))
}
}
return
fmt
}
src/router/config.tsx
View file @
5dec944
...
...
@@ -5,7 +5,6 @@ import { CardStyleInterpolators } from '@react-navigation/stack'
import { setUnit } from '../libs/utils'
import { Icons } from '../assets/icons'
const headerStyle = {
headerTitleAlign: 'center', // 文字居中
headerStyle: {
...
...
@@ -19,21 +18,13 @@ const headerStyle = {
fontSize: setUnit(38)
},
headerShown: false,
headerBackImage: Platform.OS === 'ios' ? undefined : () => <Icons name="fanhui" size={setUnit(33)} color="#262626" />, // 标题栏返回图标
headerBackImage: Platform.OS === 'ios' ? undefined : ()
: React.ReactNode
=> <Icons name="fanhui" size={setUnit(33)} color="#262626" />, // 标题栏返回图标
headerBackTitleVisible: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS, // 设置左右滑动
gestureDirection: 'horizontal', // 初始化右滑手势配置
gestureEnabled: true, // 启用右滑返回
gestureResponseDistance: { horizontal: 20 }
gestureResponseDistance: { horizontal: 20 },
headerTitleAllowFontScaling: false
}
const headerRightButton = StyleSheet.create({
text: {
fontWeight: '400',
fontSize: setUnit(29),
color: '#6c6c6c',
paddingRight: setUnit(25)
}
})
export { headerStyle, headerRightButton }
export { headerStyle }
src/router/index.tsx
View file @
5dec944
...
...
@@ -5,7 +5,7 @@ import { Route } from './route'
import { navigateRef } from './ref'
/** 路由视图 */
const RouterView = () => {
const RouterView
: React.FC
= () => {
return (
<NavigationContainer ref={navigateRef}>
<Route />
...
...
src/router/ref.ts
View file @
5dec944
...
...
@@ -8,6 +8,6 @@ export const navigateRef: React.RefObject<NavigationContainerRef> = React.create
* @param {*} name
* @param {*} params
*/
export
const
navigate
=
(
name
:
string
,
params
:
Record
<
string
,
unknown
>
|
undefined
):
void
=>
{
export
const
navigate
=
(
name
:
string
,
params
?
:
Record
<
string
,
unknown
>
|
undefined
):
void
=>
{
if
(
navigateRef
.
current
)
navigateRef
.
current
.
navigate
(
name
,
params
)
}
src/router/route/index.tsx
View file @
5dec944
// 路由配置
import React from 'react'
import { createStackNavigator } from '@react-navigation/stack'
import { createStackNavigator
, StackNavigationOptions
} from '@react-navigation/stack'
import { headerStyle } from '../config'
import TabRouter from '../tab'
...
...
@@ -9,20 +9,54 @@ import Privacy from '../../views/about/privacy'
import Features from '../../views/about/features'
import FeatureDetail from '../../views/about/feature-detail'
interface Route {
name: string;
options?: StackNavigationOptions;
component: React.FC;
}
const Routes: Route[] = [
{
name: 'Index',
options: { title: '首页' },
component: TabRouter
},
{
name: 'About',
options: { title: '', headerShown: true, headerStyle: { elevation: 0, backgroundColor: '#fff' }},
component: About
},
{
name: 'Privacy',
component: Privacy,
options: { title: '隐私协议', headerShown: true }
},
{
name: 'Features',
component: Features,
options: { headerShown: true, title: '功能介绍' }
},
{
name: 'FeatureDetail',
component: FeatureDetail,
options: { headerShown: true, title: '', headerStyle: { elevation: 0, backgroundColor: '#fff' } }
}
]
export type RouteList = {
Index: undefined;
About: undefined;
Privacy: undefined;
Features: undefined;
FeatureDetail: { content?: string };
}
const Stack = createStackNavigator()
const Route = () => {
const Route
: React.FC
= () => {
return (
<Stack.Navigator initialRouteName="Index" screenOptions={{ ...headerStyle }} mode={'card'} >
<Stack.Screen name="Index" options={{ title: '首页' }} component={TabRouter} />
{/* 关于 */}
<Stack.Screen name='About' options={{ title: '', headerShown: true, headerStyle: { elevation: 0, backgroundColor: '#fff' } }} component={About} />
{/* 隐私协议与政策 */}
<Stack.Screen name='Privacy' options={{ title: '隐私协议', headerShown: true }} component={Privacy} />
{/* 功能介绍 */}
<Stack.Screen name='Features' options={{ headerShown: true, title: '功能介绍' }} component={Features} />
{/* 功能介绍 */}
<Stack.Screen name='FeatureDetail' options={{ headerShown: true, title: '', headerStyle: { elevation: 0, backgroundColor: '#fff' } }} component={FeatureDetail} />
<Stack.Navigator initialRouteName="Index" screenOptions={{ ...headerStyle as StackNavigationOptions }} mode={'card'} >
{Routes.map(item => <Stack.Screen {...item} key={item.name} />)}
</Stack.Navigator>
)
}
...
...
src/router/tab/index.tsx
View file @
5dec944
// 底部tab路由配置
import React from 'react'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import {
BottomTabNavigationOptions,
createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { APP } from '../../config'
import Home from '../../views/home'
const Tab = createBottomTabNavigator() // 创建tab栈堆
/** 选项配置函数 */
const tabScreen = ({ route }) => ({
tabBarIcon: (
{ focused, size })
=> {
const tabScreen = ({ route })
: BottomTabNavigationOptions
=> ({
tabBarIcon: (
): React.ReactNode | null
=> {
switch (route.name) {
case 'home':
return null
default:
return null
}
}
})
const TabRoute = () => {
const TabRoute
: React.FC
= () => {
return (
<Tab.Navigator backBehavior={'none'} screenOptions={tabScreen} tabBarOptions={APP.tabConfig}>
<Tab.Screen options={{ title: '首页' }} name="home" component={Home} />
...
...
src/store/context.ts
View file @
5dec944
var
STORE_CONTEXT
=
null
/* eslint-disable @typescript-eslint/explicit-function-return-type */
export
const
createConetxt
=
store
=>
STORE_CONTEXT
=
store
let
STORE_CONTEXT
=
null
export
const
getStore
=
()
=>
STORE_CONTEXT
\ No newline at end of file
export
const
createConetxt
=
(
store
)
=>
STORE_CONTEXT
=
store
export
const
getStore
=
()
=>
STORE_CONTEXT
src/theme/colors.ts
0 → 100644
View file @
5dec944
export
const
Alert
=
{
content
:
'#333'
,
privacy
:
'#1892FF'
}
export
const
View
=
{
background
:
'#fff'
}
export
const
desc
=
'#434343'
export
const
subTitle
=
'#8c8c8c'
export
const
title
=
'#262626'
export
const
tips
=
'#6292D0'
src/views/about/feature-detail/style.ts
View file @
5dec944
import
{
StyleSheet
}
from
'react-native'
import
{
setUnit
}
from
'../../../libs/utils'
import
{
View
,
desc
}
from
'../../../theme/colors'
const
styles
=
StyleSheet
.
create
({
container
:
{
backgroundColor
:
View
.
background
,
flex
:
1
,
padding
:
setUnit
(
32
),
backgroundColor
:
'#fff'
padding
:
setUnit
(
32
)
},
desc
:
{
color
:
'#434343'
,
color
:
desc
,
fontSize
:
setUnit
(
24
)
}
})
...
...
src/views/about/feature-detail/view.tsx
View file @
5dec944
...
...
@@ -8,18 +8,23 @@ import { View, Text } from 'react-native'
import { styles } from './style'
import { Icons } from '../../../assets/icons'
import { setUnit } from '../../../libs/utils'
import { NavigationProp, RouteProp } from '@react-navigation/native'
import { RouteList } from '../../../router/route'
const Page = ({ route, navigation }) => {
const Page: React.FC<{
route: RouteProp<RouteList, 'FeatureDetail'>;
navigation: NavigationProp<RouteList>;
}> = ({ route, navigation }) => {
useLayoutEffect(() => {
navigation.setOptions({
headerLeft: () => (
headerLeft: ()
: React.ReactNode
=> (
<Icons
name='guanbi'
color='#555'
size={setUnit(32)}
style={{ paddingHorizontal: setUnit(24) }}
onPress={() => navigation.goBack()}
onPress={()
: void
=> navigation.goBack()}
/>
)
})
...
...
src/views/about/features/style.ts
View file @
5dec944
import
{
StyleSheet
}
from
'react-native'
import
{
setUnit
}
from
'../../../libs/utils'
import
{
View
,
desc
,
subTitle
}
from
'../../../theme/colors'
const
styles
=
StyleSheet
.
create
({
container
:
{
flex
:
1
,
backgroundColor
:
'#fff'
backgroundColor
:
View
.
background
,
flex
:
1
},
item
:
{
paddingHorizontal
:
setUnit
(
25
),
paddingVertical
:
setUnit
(
16
),
containerStyle
:
{
alignItems
:
'center'
,
flexDirection
:
'row'
flex
:
1
,
justifyContent
:
'center'
},
content
:
{
flex
:
1
},
title
:
{
fontSize
:
setUnit
(
28
),
color
:
'#434343'
emptyText
:
{
color
:
desc
,
fontSize
:
setUnit
(
33
)
},
item
:
{
alignItems
:
'center'
,
flexDirection
:
'row'
,
paddingHorizontal
:
setUnit
(
25
),
paddingVertical
:
setUnit
(
16
)
},
subtitle
:
{
color
:
'#8c8c8c'
,
color
:
subTitle
,
fontSize
:
setUnit
(
24
)
},
emptyText
:
{
fontSize
:
setUnit
(
33
),
color
:
'#434343'
},
containerStyle
:
{
flex
:
1
,
justifyContent
:
'center'
,
alignItems
:
'center'
title
:
{
color
:
desc
,
fontSize
:
setUnit
(
28
)
}
})
...
...
src/views/about/features/view.tsx
View file @
5dec944
/* eslint-disable @typescript-eslint/camelcase */
/**
* @author sheng
* @description 功能介绍列表页
* @date 2020/09/03
*/
import React, { memo, useState, useLayoutEffect, use
Callback, use
Effect } from 'react'
import React, { memo, useState, useLayoutEffect, useEffect } from 'react'
import { Text, View, FlatList, Pressable, InteractionManager } from 'react-native'
import { Icons } from '../../../assets/icons'
import { styles } from './style'
import { dateFormat, setUnit } from '../../../libs/utils'
import { Toast, Divider, Empty } from 'react-native-mb-ui'
import { Toast, Divider, Empty
, ModalManager
} from 'react-native-mb-ui'
import { getVersionList } from '../../../api/version'
import { NavigationProp } from '@react-navigation/native'
import { RouteList } from '../../../router/route'
const Item = memo(({ navigation, item }) => {
const { version, create_time, remark } = item
interface Items {
version: string;
create_time: number;
remark: string;
id: number;
}
interface ItemProp {
onClick: () => void;
item: Items;
}
const Item = memo(({ onClick, item }: ItemProp) => {
const { version, create_time } = item
return (
<>
<Pressable
style={styles.item}
android_ripple={{ color: '#eee' }}
onPress={
() => { navigation.navigate('FeatureDetail', { content: remark || '' }) }
}
onPress={
onClick
}
>
<View style={styles.content}>
<Text style={styles.title}>商品交易所{version}主要更新</Text>
...
...
@@ -32,7 +47,7 @@ const Item = memo(({ navigation, item }) => {
})
let http
const Page = ({ navigation }) => {
const Page
: React.FC<{ navigation: NavigationProp<RouteList> }>
= ({ navigation }) => {
const [records, setRecords] = useState([])
useLayoutEffect(() => {
...
...
@@ -43,40 +58,49 @@ const Page = ({ navigation }) => {
color='#555'
size={setUnit(32)}
style={{ paddingHorizontal: setUnit(24) }}
onPress={() => navigation.goBack()}
onPress={()
: void
=> navigation.goBack()}
/>
)
})
}, [navigation])
useEffect(() => {
const fetchData = (): void => {
InteractionManager.runAfterInteractions(() => {
Toast.loading()
http = getVersionList(res => {
setRecords(res?.reverse() || [])
Toast.hideLoading()
}, err => {
Toast.hideLoading()
ModalManager.alert({
title: '错误',
content: err
})
})
})
}
fetchData()
return () => {
http &&
http.cancel()
return ()
: void
=> {
if (http)
http.cancel()
}
}, [])
const fetchData = useCallback(() => {
InteractionManager.runAfterInteractions(() => {
Toast.loading()
http = getVersionList(res => {
setRecords(res?.reverse() || [])
Toast.hideLoading()
}, err => {
Toast.hideLoading()
alert(err)
})
})
}, [])
return (
<View style={styles.container}>
<FlatList
data={records}
contentContainerStyle={!records.length ? styles.containerStyle : {}}
keyExtractor={(item, index) => item.id?.toString()}
renderItem={({ item }) => <Item navigation={navigation} item={item} />}
ListEmptyComponent={() => <Empty style={{ paddingTop: 100 }} />}
keyExtractor={(item: Items): string => item.id?.toString()}
renderItem={({ item }: { item: Items }): React.ReactElement => (
<Item
onClick={(): void => navigation.navigate('FeatureDetail', { content: item.remark || '' })}
item={item}
/>
)}
ListEmptyComponent={(): React.ReactElement => <Empty style={{ paddingTop: 100 }} />}
/>
</View>
)
...
...
src/views/about/privacy/style.ts
View file @
5dec944
...
...
@@ -2,13 +2,13 @@ import { StyleSheet } from 'react-native'
const
styles
=
StyleSheet
.
create
({
wrapper
:
{
position
:
'absolute'
,
left
:
0
,
alignItems
:
'center'
,
bottom
:
0
,
right
:
0
,
top
:
0
,
justifyContent
:
'center'
,
alignItems
:
'center'
left
:
0
,
position
:
'absolute'
,
right
:
0
,
top
:
0
}
})
...
...
src/views/about/privacy/view.tsx
View file @
5dec944
...
...
@@ -3,19 +3,20 @@
* @description 隐私政策
* @date 2020/09/03
*/
import { NavigationProp } from '@react-navigation/native'
import React, { useEffect, useState } from 'react'
import { View, ActivityIndicator } from 'react-native'
import WebView from 'react-native-webview'
import { Colors } from '../../../commo/theme'
import { APP } from '../../../config'
import { RouteList } from '../../../router/route'
import { styles } from './style'
const Page = ({ navigation }) => {
const Page
: React.FC<{ navigation: NavigationProp<RouteList> }>
= ({ navigation }) => {
const [show, setShow] = useState(false)
const indicator = () => {
const indicator = ()
: React.ReactNode
=> {
return (
<View style={styles.wrapper}>
<ActivityIndicator size={'large'}
color={Colors.primary}
/>
<ActivityIndicator size={'large'} />
</View>
)
}
...
...
@@ -29,7 +30,7 @@ const Page = ({ navigation }) => {
navigation.goBack()
})
return () => remove && remove()
return ()
: void
=> remove && remove()
}, [])
return (
...
...
src/views/about/style.ts
View file @
5dec944
import
{
StyleSheet
}
from
'react-native'
import
{
setUnit
}
from
'../../libs/utils'
import
{
subTitle
,
View
,
title
,
tips
}
from
'../../theme/colors'
const
styles
=
StyleSheet
.
create
({
center
:
{
marginTop
:
setUnit
(
56
)
},
container
:
{
flex
:
1
,
backgroundColor
:
'#fff'
backgroundColor
:
View
.
background
,
flex
:
1
},
copyright
:
{
color
:
subTitle
,
marginTop
:
setUnit
(
24
),
textAlign
:
'center'
},
footer
:
{
alignItems
:
'center'
,
paddingBottom
:
setUnit
(
48
)
},
header
:
{
marginTop
:
setUnit
(
112
)
,
alignItems
:
'center'
alignItems
:
'center'
,
marginTop
:
setUnit
(
112
)
},
logo
:
{
width
:
setUnit
(
160
),
height
:
setUnit
(
160
)
height
:
setUnit
(
160
),
width
:
setUnit
(
160
)
},
name
:
{
marginTop
:
setUnit
(
32
)
,
color
:
'#262626'
,
color
:
title
,
fontSize
:
setUnit
(
40
)
,
fontWeight
:
'500'
,
fontSize
:
setUnit
(
40
)
},
version
:
{
marginTop
:
setUnit
(
12
),
color
:
'#262626'
,
fontSize
:
setUnit
(
32
)
},
center
:
{
marginTop
:
setUnit
(
56
)
},
footer
:
{
alignItems
:
'center'
,
paddingBottom
:
setUnit
(
48
)
marginTop
:
setUnit
(
32
)
},
private
:
{
fontSize
:
setUnit
(
26
)
,
color
:
'#6292D0'
color
:
tips
,
fontSize
:
setUnit
(
26
)
},
copyright
:
{
marginTop
:
setUnit
(
24
)
,
textAlign
:
'center'
,
color
:
'#8c8c8c'
,
version
:
{
color
:
title
,
fontSize
:
setUnit
(
32
)
,
marginTop
:
setUnit
(
12
)
}
})
...
...
src/views/about/view.tsx
View file @
5dec944
/* eslint-disable @typescript-eslint/camelcase */
/**
* @author sheng
* @description 关于信巴迪
...
...
@@ -11,30 +12,38 @@ import { styles } from './style'
import { getVersion, getVersionCode, setUnit } from '../../libs/utils'
import { getTopVersion } from '../../api/version'
import { APP } from '../../config'
import { RouteList } from '../../router/route'
import { NavigationProp } from '@react-navigation/native'
let http
const Page = ({ navigation }) => {
const Page
: React.FC<{ navigation: NavigationProp<RouteList, 'About'> }>
= ({ navigation }) => {
const [version, setVersion] = useState('')
const downUrl = useRef('')
useEffect(() => {
getCurVersion()
return () => http && http.cancel()
(async (): Promise<void> => {
const version = await getVersion()
setVersion(version)
})()
return (): void => http && http.cancel()
}, [])
/** 打开下载链接 */
const openDown = () => {
const openDown = ()
: void
=> {
Linking.openURL(downUrl.current)
.then(() => { })
.catch(
err
=> Toast.info('打开下载地址失败,请重试'))
.catch(
()
=> Toast.info('打开下载地址失败,请重试'))
}
const getUpdate = async () => {
const getUpdate = async ()
: Promise<void>
=> {
const versionCode = await getVersionCode()
http = getTopVersion(res => {
if (res === null) return Toast.info('已是最新版本')
if (res === null) {
Toast.info('已是最新版本')
return
}
const { version_code, down, version } = res
downUrl.current = down
...
...
@@ -47,19 +56,13 @@ const Page = ({ navigation }) => {
{ text: '立即更新', onPress: openDown }
]
})
} else
{
} else
Toast.info('已是最新版本')
}
}, err => Toast.info(err))
}
/**获取当前版本号 */
const getCurVersion = useCallback(async () => {
const version = await getVersion()
setVersion(version)
}, [])
const goPage = useCallback(() => {
navigation.navigate('Privacy')
}, [navigation])
...
...
@@ -77,7 +80,7 @@ const Page = ({ navigation }) => {
</View>
<View style={styles.center}>
<Divider style={{ marginHorizontal: setUnit(25) }} />
<Cell label={'功能介绍'} onClick={() => navigation.navigate('Features')} />
<Cell label={'功能介绍'} onClick={()
: void
=> navigation.navigate('Features')} />
<Cell label={'版本更新'} onClick={getUpdate} />
</View>
</View>
...
...
src/views/home/view.tsx
View file @
5dec944
import React from 'react'
import { View, Text } from 'react-native'
import { styles } from './styles'
import { name as appName } from '../../../app.json';
import { name as appName } from '../../../app.json'
import { NavigationProp } from '@react-navigation/native'
import { RouteList } from '../../router/route'
const Page = ({ navigation }) => {
const Page
: React.FC<{ navigation: NavigationProp<RouteList> }>
= ({ navigation }) => {
return (
<View >
<Text style={styles.title} >{appName}</Text>
<Text style={styles.title} onPress={() => navigation.navigate('About')} >查看APP详细信息</Text>
<Text style={styles.title} onPress={()
: void
=> navigation.navigate('About')} >查看APP详细信息</Text>
</View>
)
}
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment