2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+1
View File
@@ -0,0 +1 @@
module.exports = {}
@@ -0,0 +1,127 @@
<template>
<uni-tabbar v-if="hasTabBar" v-show="showTabBar">
<div
:style="{
'flex-direction': direction === 'vertical' ? 'column' : 'row',
backgroundColor: tabBar.backgroundColor,
}"
class="uni-tabbar"
>
<template v-for="(item, index) in tabBar.list" :key="item.pagePath">
<div
v-if="item.visible !== false"
class="uni-tabbar__item"
@click="switchTab(item, index)"
>
<div class="uni-tabbar__bd">
<div
v-if="showIcon && item.iconPath"
:class="{ 'uni-tabbar__icon__diff': !item.text }"
class="uni-tabbar__icon"
>
<img
:src="
getRealPath(
selectedIndex === index
? item.selectedIconPath
: item.iconPath
)
"
/>
<div
v-if="item.redDot"
:class="{ 'uni-tabbar__badge': !!item.badge }"
class="uni-tabbar__reddot"
>
{{ item.badge }}
</div>
</div>
<div
v-if="item.text"
:style="{
color:
selectedIndex === index ? tabBar.selectedColor : tabBar.color,
fontSize: showIcon && item.iconPath ? '10px' : '14px',
}"
class="uni-tabbar__label"
>
{{ item.text }}
<div
v-if="item.redDot && (!showIcon || !item.iconPath)"
:class="{ 'uni-tabbar__badge': !!item.badge }"
class="uni-tabbar__reddot"
>
{{ item.badge }}
</div>
</div>
</div>
</div>
</template>
</div>
</uni-tabbar>
</template>
<script>
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { getRealPath } from '@dcloudio/uni-h5'
import { useTabBar } from '@dcloudio/uni-h5'
export default {
name: 'CustomTabBar',
props: {
selected: {
type: Number,
default: 0
},
showIcon: {
type: Boolean,
default: true
},
direction: {
type: String,
default: 'horizontal'
}
},
setup(props, { emit }) {
const tabBar = useTabBar()
const route = useRoute()
const hasTabBar = computed(() => tabBar.list && tabBar.list.length)
const selectedIndex = ref(props.selected)
watch(() => props.selected, value => selectedIndex.value = value)
watch(() => selectedIndex.value, value => tabBar.selectedIndex = value)
watch(() => {
const meta = route.meta
return [meta.isTabBar, meta.route]
}, ([isTabBar, pagePath]) => {
if (isTabBar) {
const index = tabBar.list.findIndex(item => pagePath === item.pagePath)
if (index > -1) {
selectedIndex.value = index
}
}
})
function switchTab(item, index) {
selectedIndex.value = index
const detail = {
index,
text: item.text,
pagePath: item.pagePath,
}
emit('onTabItemTap', detail)
}
return {
tabBar,
getRealPath,
selectedIndex,
hasTabBar,
showTabBar: true,
switchTab,
}
}
}
</script>
<style>
</style>
@@ -0,0 +1,10 @@
<template>
<teleport to="head">
<slot />
</teleport>
</template>
<script>
export default {
name: 'PageMetaHead',
}
</script>
+10
View File
@@ -0,0 +1,10 @@
<template>
<view style="display: none;">
<slot />
</view>
</template>
<script>
export default {
name: 'PageMeta'
}
</script>
+317
View File
@@ -0,0 +1,317 @@
type SuccessCallback<T> = (res : T | null) => void | null
type FailCallback = (err : any | null) => void | null
type CompleteCallback = () => void | null
export type MixinDatacomPaginationType = {
current : number,
size : number,
count : number
}
export type MixinDatacomGetOptions = {
collection ?: UTSJSONObject,
field ?: string,
orderBy ?: string,
where ?: any,
pageData ?: string,
pageCurrent ?: number,
pageSize ?: number,
getCount ?: boolean,
getTree ?: any,
getTreePath ?: UTSJSONObject,
startWith ?: string,
limitLevel ?: number,
groupBy ?: string,
groupField ?: string,
distinct ?: boolean,
pageIndistinct ?: boolean,
foreignKey ?: string,
loadtime ?: string,
manual ?: boolean
}
export type MixinDatacomEasyGetOptions = {
success ?: SuccessCallback<UniCloudDBGetResult>,
fail ?: FailCallback,
complete ?: CompleteCallback,
}
export const mixinDatacom = defineMixin({
slots: Object as SlotsType<{
default : {
data : Array<UTSJSONObject>,
loading : boolean,
hasMore : boolean,
pagination : MixinDatacomPaginationType,
error : UniCloudError | null
}
}>,
props: {
localdata: {
type: Array as PropType<Array<UTSJSONObject>>,
default: [] as Array<UTSJSONObject>
},
collection: {
type: Object,
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: Object,
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: Boolean,
default: false
},
gettree: {
type: Object,
default: ''
},
gettreepath: {
type: Boolean,
default: false
},
startwith: {
type: String,
default: ''
},
limitlevel: {
type: Number,
default: 10
},
groupby: {
type: String,
default: ''
},
groupField: {
type: String,
default: ''
},
distinct: {
type: Boolean,
default: false
},
pageIndistinct: {
type: Boolean,
default: false
},
foreignKey: {
type: String,
default: ''
},
loadtime: {
type: String,
default: 'auto'
},
manual: {
type: Boolean,
default: false
}
},
data() {
return {
mixinDatacomResData: [] as Array<UTSJSONObject>, // 请求返回的数据,调用 loadData 后会更新
mixinDatacomLoading: false, // 网络请求状态
mixinDatacomHasMore: false, // 是否有更多数据
mixinDatacomPage: {
current: 1,
size: 20,
count: 0,
} as MixinDatacomPaginationType, // 分页信息,详情见 created 生命周期
mixinDatacomError: null as UniCloudError | null, // 请求出错时的错误消息
}
},
created() {
this.mixinDatacomPage.current = this.pageCurrent
this.mixinDatacomPage.size = this.pageSize
const PROPS_NAME = ['', '', 'collection', 'field', 'getcount', 'orderby', 'where', 'groupby', 'groupField', 'distinct']
this.$watch(
() : any => [
this.pageCurrent,
this.pageSize,
this.collection,
this.field,
this.getcount,
this.orderby,
this.where,
this.groupby,
this.groupField,
this.distinct
],
(newValue : Array<any>, oldValue : Array<any>) => {
this.mixinDatacomPage.size = this.pageSize
if (newValue[0] !== oldValue[0]) {
this.mixinDatacomPage.current = this.pageCurrent
}
let needReset = false
let changed : Array<string> = []
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] !== oldValue[i]) {
needReset = true
changed.push(PROPS_NAME[i])
}
}
this.onMixinDatacomPropsChange(needReset, changed)
}
)
},
methods: {
// props发生变化时被调用,在组件中覆盖此方法
// 非 pageCurrentpageSize 改变时 needReset=true,需要重置数据
// changed,发生变化的属性名,类型为Array,例如 ['collection', 'action']
onMixinDatacomPropsChange(_ : boolean, changed : Array<string>) {
},
mixinDatacomEasyGet(options ?: MixinDatacomEasyGetOptions) {
if (this.mixinDatacomLoading) {
return
}
this.mixinDatacomLoading = true
this.mixinDatacomError = null
this.mixinDatacomGet(null).then((res : UniCloudDBGetResult) => {
const data = res.data
const count = res.count
if (this.getcount && count != null) {
this.mixinDatacomPage.count = count
}
this.mixinDatacomHasMore = !((count != null) ? (this.mixinDatacomPage.current * this.mixinDatacomPage.size >= count) : (data.length < this.pageSize))
this.mixinDatacomResData = data
options?.success?.(res)
}).catch((err : any | null) => {
this.mixinDatacomError = err as UniCloudError
options?.fail?.(err)
}).then(() => {
this.mixinDatacomLoading = false
options?.complete?.()
}, () => {
this.mixinDatacomLoading = false
options?.complete?.()
})
},
mixinDatacomGet(options: MixinDatacomGetOptions | null) : Promise<UniCloudDBGetResult> {
let db = uniCloud.databaseForJQL()
let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array<any>)) : db.collection(this.collection)
let filter : UniCloudDBFilter | null = null
if (this.foreignKey.length > 0) {
filter = collection.foreignKey(this.foreignKey)
}
const where : any = options?.where ?? this.where
if (typeof where == 'string') {
const whereString = where as string
if (whereString.length > 0) {
filter = (filter != null) ? filter.where(where) : collection.where(where)
}
} else {
filter = (filter != null) ? filter.where(where) : collection.where(where)
}
let query : UniCloudDBQuery | null = null
if (this.field.length > 0) {
query = (filter != null) ? filter.field(this.field) : collection.field(this.field)
}
if (this.groupby.length > 0) {
if (query != null) {
query = query.groupBy(this.groupby)
} else if (filter != null) {
query = filter.groupBy(this.groupby)
}
}
if (this.groupField.length > 0) {
if (query != null) {
query = query.groupField(this.groupField)
} else if (filter != null) {
query = filter.groupField(this.groupField)
}
}
if (this.distinct == true) {
if (query != null) {
query = query.distinct(this.field)
} else if (filter != null) {
query = filter.distinct(this.field)
}
}
if (this.orderby.length > 0) {
if (query != null) {
query = query.orderBy(this.orderby)
} else if (filter != null) {
query = filter.orderBy(this.orderby)
}
}
const size = this.mixinDatacomPage.size
const current = this.mixinDatacomPage.current
if (query != null) {
query = query.skip(size * (current - 1)).limit(size)
} else if (filter != null) {
query = filter.skip(size * (current - 1)).limit(size)
} else {
query = collection.skip(size * (current - 1)).limit(size)
}
const getOptions = {} as UTSJSONObject
const treeOptions = {
limitLevel: this.limitlevel,
startWith: this.startwith
}
const getCount : boolean = options?.getCount ?? this.getcount
if (this.getcount == true) {
getOptions['getCount'] = getCount
}
const getTree : any = options?.getTree ?? this.gettree
if (typeof getTree == 'string') {
const getTreeString = getTree as string
if (getTreeString.length > 0) {
getOptions['getTree'] = treeOptions
}
} else if (typeof getTree == 'object') {
getOptions['getTree'] = treeOptions
} else {
getOptions['getTree'] = getTree
}
const getTreePath = options?.getTreePath ?? this.gettreepath
if (typeof getTreePath == 'string') {
const getTreePathString = getTreePath as string
if (getTreePathString.length > 0) {
getOptions['getTreePath'] = getTreePath
}
} else {
getOptions['getTreePath'] = getTreePath
}
return query.get(getOptions)
}
}
})
+727
View File
@@ -0,0 +1,727 @@
<template>
<uni-cloud-db-element ref="UniCloudDB">
<slot :data="dataList" :loading="loading" :hasMore="hasMore" :pagination="pagination" :error="error" />
</uni-cloud-db-element>
</template>
<script lang="uts">
//#ifdef APP
import { SlotsType } from 'vue'
//#endif
//#ifdef WEB || APP-IOS || MP
let registerFlag = false
//#endif
const EVENT_LOAD = 'load'
const EVENT_ERROR = 'error'
const PAGE_MODE_ADD = 'add'
const PAGE_MODE_REPLACE = 'replace'
const LOAD_MODE_AUTO = 'auto'
const LOAD_MODE_MANUAL = 'manual'
// const LOAD_MODE_ONREADY = 'onready'
type SuccessCallback<T> = (res : T | null) => void | null
type FailCallback = (err : any | null) => void | null
type CompleteCallback = () => void | null
type GetSuccessCallback = SuccessCallback<UniCloudDBGetResult>
type AddSuccessCallback = SuccessCallback<UniCloudDBAddResult>
type RemoveSuccessCallback = SuccessCallback<UniCloudDBRemoveResult>
type UpdateSuccessCallback = SuccessCallback<UniCloudDBUpdateResult>
export type UniCloudDBComponentPaginationType = {
current : number,
size : number,
count : number
}
export type UniCloudDBComponentLoadDataOptions = {
clear ?: boolean | null,
current ?: number | null,
success ?: GetSuccessCallback,
fail ?: FailCallback,
complete ?: CompleteCallback,
}
export type UniCloudDBComponentAddOptions = {
/**
* @default true
*/
showToast ?: boolean | null,
toastTitle ?: string | null,
/**
* @default true
*/
needLoading ?: boolean | null,
loadingTitle ?: string | null,
success ?: AddSuccessCallback,
fail ?: FailCallback,
complete ?: CompleteCallback,
}
export type UniCloudDBComponentRemoveOptions = {
confirmTitle ?: string | null,
confirmContent ?: string | null,
/**
* @default true
*/
needConfirm ?: boolean | null,
/**
* @default true
*/
needLoading ?: boolean | null,
loadingTitle ?: string | null,
success ?: RemoveSuccessCallback,
fail ?: FailCallback,
complete ?: CompleteCallback,
}
export type UniCloudDBComponentUpdateOptions = {
/**
* @default true
*/
showToast ?: boolean | null,
toastTitle ?: string | null,
confirmTitle ?: string | null,
confirmContent ?: string | null,
/**
* @default true
*/
needConfirm ?: boolean | null,
/**
* @default true
*/
needLoading ?: boolean | null,
loadingTitle ?: string | null,
success ?: UpdateSuccessCallback,
fail ?: FailCallback,
complete ?: CompleteCallback,
}
function cast_callback<T>(options : any | null) : T | null {
return options as T | null
}
//#ifdef APP-ANDROID
export class UniCloudDBElement extends UniViewElementImpl {
constructor(data : INodeData, pageNode : PageNode) {
super(data, pageNode)
}
//#endif
//#ifdef WEB || APP-IOS || MP
const RealUniElementImpl = typeof UniElementImpl === 'undefined' ? class {} : UniElementImpl
export class UniCloudDBElement extends RealUniElementImpl {
constructor(data : INodeData, pageNode : PageNode) {
super(data, pageNode);
const TagName = 'UNICLOUD-DB';
Object.defineProperty(this, 'tagName', {
value: TagName,
writable: false
});
Object.defineProperty(this, 'nodeName', {
value: TagName,
writable: false
});
}
//#endif
dataList : Array<UTSJSONObject> = []
loadData(options : UTSJSONObject = {}) {
this.onLoadData({
clear: options.getBoolean('clear'),
current: options.getNumber('current'),
success: cast_callback<GetSuccessCallback>(options['success']),
fail: cast_callback<FailCallback>(options['fail']),
complete: cast_callback<CompleteCallback>(options['complete'])
} as UniCloudDBComponentLoadDataOptions)
}
loadMore() {
this.onLoadMore()
}
add(value : UTSJSONObject, options : UTSJSONObject) {
this.onAdd(value, {
showToast: options.getBoolean('showToast') ?? true,
toastTitle: options.getString('toastTitle'),
needLoading: options.getBoolean('needLoading') ?? true,
loadingTitle: options.getString('loadingTitle'),
success: cast_callback<AddSuccessCallback>(options['success']),
fail: cast_callback<FailCallback>(options['fail']),
complete: cast_callback<CompleteCallback>(options['complete'])
} as UniCloudDBComponentAddOptions)
}
// @ts-ignore
remove(id : any, options : UTSJSONObject) {
//#ifdef WEB || APP-IOS
// @ts-ignore
if (arguments.length == 0) {
super.remove()
return
}
//#endif
this.onRemove(id, {
confirmTitle: options.getString('confirmTitle'),
confirmContent: options.getString('confirmContent'),
needConfirm: options.getBoolean('needConfirm') ?? true,
needLoading: options.getBoolean('needLoading') ?? true,
loadingTitle: options.getString('loadingTitle'),
success: cast_callback<RemoveSuccessCallback>(options['success']),
fail: cast_callback<FailCallback>(options['fail']),
complete: cast_callback<CompleteCallback>(options['complete'])
} as UniCloudDBComponentRemoveOptions)
}
update(id : string, value : UTSJSONObject, options : UTSJSONObject) {
this.onUpdate(id, value, {
showToast: options.getBoolean('showToast') ?? true,
toastTitle: options.getString('toastTitle'),
confirmTitle: options.getString('confirmTitle'),
confirmContent: options.getString('confirmContent'),
needConfirm: options.getBoolean('needConfirm') ?? true,
needLoading: options.getBoolean('needLoading') ?? true,
loadingTitle: options.getString('loadingTitle'),
success: cast_callback<UpdateSuccessCallback>(options['success']),
fail: cast_callback<FailCallback>(options['fail']),
complete: cast_callback<CompleteCallback>(options['complete'])
} as UniCloudDBComponentUpdateOptions)
}
onLoadData! : (_ : UniCloudDBComponentLoadDataOptions) => Promise<void>
onLoadMore! : () => void
onAdd! : (value : UTSJSONObject, options : UniCloudDBComponentAddOptions) => void
onUpdate!: (id : string, value : UTSJSONObject, options : UniCloudDBComponentUpdateOptions) => void
onRemove!: (id : any, options : UniCloudDBComponentRemoveOptions) => void
}
export default {
name: 'UniCloudDB',
rootElement: {
name: 'uni-cloud-db-element',
class: UniCloudDBElement
},
slots: Object as SlotsType<{
default : {
data : Array<UTSJSONObject>,
loading : boolean,
hasMore : boolean,
pagination : UniCloudDBComponentPaginationType,
error : UniCloudError | null
}
}>,
props: {
collection: {
type: [String, Object],
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: Boolean,
default: false
},
gettree: {
type: [String, Object],
default: ''
},
gettreepath: {
type: Boolean,
default: false
},
startwith: {
type: String,
default: ''
},
limitlevel: {
type: Number,
default: 10
},
groupby: {
type: String,
default: ''
},
groupField: {
type: String,
default: ''
},
distinct: {
type: Boolean,
default: false
},
pageIndistinct: {
type: Boolean,
default: false
},
foreignKey: {
type: String,
default: ''
},
loadtime: {
type: String,
default: 'auto'
},
manual: {
type: Boolean,
default: false
},
ssrKey: {
type: String,
default: ""
}
},
data() {
return {
//#ifdef WEB || MP
// TODO 修复类型错误
// @ts-ignore
dataList: ssrRef([] as Array<UTSJSONObject>) as Array<UTSJSONObject>,
//#endif
//#ifndef WEB
dataList: [] as Array<UTSJSONObject>,
//#endif
// dataList: [] as Array<UTSJSONObject>,
loading: false,
hasMore: false,
isEnded: false,
pagination: {
current: 1,
size: 20,
count: 0,
} as UniCloudDBComponentPaginationType,
error: null as UniCloudError | null
}
},
//#ifdef WEB || APP-IOS || MP
beforeCreate() {
if (!registerFlag) {
registerFlag = true
// @ts-ignore
typeof customElements !== 'undefined' && customElements.define(
'uni-cloud-db-element',
// @ts-ignore
UniCloudDBElement,
)
}
},
//#endif
//#ifdef WEB
async serverPrefetch() : Promise<any> {
// @ts-ignore
if (!this.manual && this.loadtime === 'auto') {
// @ts-ignore
return this.loadData({})
}
},
//#endif
created() {
this.pagination.current = this.pageCurrent
this.pagination.size = this.pageSize
this.$watch(
() : any => [
this.pageCurrent,
this.pageSize,
this.collection,
this.field,
this.getcount,
this.orderby,
this.where,
this.groupby,
this.groupField,
this.distinct
],
(newValue : Array<any>, oldValue : Array<any>) => {
this.pagination.size = this.pageSize
if (newValue[0] !== oldValue[0]) {
this.pagination.current = this.pageCurrent
}
if (this.loadtime == LOAD_MODE_MANUAL) {
return
}
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] !== oldValue[i]) {
needReset = true
break
}
}
if (needReset) {
this.clear()
this.reset()
}
this.get(null)
}
)
if (!this.manual && this.loadtime == LOAD_MODE_AUTO && this.dataList.length == 0) {
if (typeof this.collection == 'string') {
const collectionString = this.collection as string
if (collectionString.length == 0) {
return
}
} else if (Array.isArray(this.collection)) {
const collectionArray = this.collection as Array<any>
if (collectionArray.length == 0) {
return
}
}
this.get(null)
}
},
mounted() {
const uniCloudDBElement = this.$refs['UniCloudDB'] as UniCloudDBElement
uniCloudDBElement.dataList = this.dataList;
//#ifdef APP
uniCloudDBElement.onLoadData = this.loadData;
uniCloudDBElement.onLoadMore = this.loadMore;
uniCloudDBElement.onAdd = this.add;
uniCloudDBElement.onUpdate = this.update;
uniCloudDBElement.onRemove = this.remove;
//#endif
//#ifdef WEB || MP
uniCloudDBElement.onLoadData = this.loadData.bind(this);
uniCloudDBElement.onLoadMore = this.loadMore.bind(this);
uniCloudDBElement.onAdd = this.add.bind(this);
uniCloudDBElement.onUpdate = this.update.bind(this);
uniCloudDBElement.onRemove = this.remove.bind(this);
//#endif
},
methods: {
async loadData(options : UniCloudDBComponentLoadDataOptions) : Promise<void> {
let clear = (options.clear != null && options.clear == true)
if (clear == true) {
if (this.pageData == PAGE_MODE_REPLACE) {
this.clear()
}
this.reset()
}
await this.get(options)
},
loadMore() {
if (this.isEnded || this.loading) {
return
}
if (this.pageData == PAGE_MODE_ADD) {
this.pagination.current++
}
this.get(null)
},
refresh() {
this.clear()
this.get(null)
},
clear() {
this.isEnded = false
this.dataList.length = 0
},
reset() {
this.pagination.current = 1
},
async get(options? : UniCloudDBComponentLoadDataOptions | null) : Promise<void> {
let loadAfterClear = false
if (options != null && options.clear != null && options.clear == true) {
loadAfterClear = true
}
if (options != null && options.current != null) {
this.pagination.current = options.current!
}
this.error = null
this.loading = true
await this.getExec().then((res : UniCloudDBGetResult) => {
const data = res.data
const count = res.count
this.isEnded = (count != null) ? (this.pagination.current * this.pagination.size >= count) : (data.length < this.pageSize)
this.hasMore = !this.isEnded
if (this.getcount && count != null) {
this.pagination.count = count
}
this._dispatchEvent(EVENT_LOAD, data)
if (loadAfterClear || this.pageData == PAGE_MODE_REPLACE) {
this.dataList = data
} else {
this.dataList.push(...data)
}
options?.success?.(res)
}).catch((err : any | null) => {
this._requestFail(err, null)
options?.fail?.(err)
}).then(() => {
this.loading = false
options?.complete?.()
}, () => {
this.loading = false
options?.complete?.()
})
},
add(value : UTSJSONObject, options : UniCloudDBComponentAddOptions) {
this._needLoading(options.needLoading, options.loadingTitle)
const db = uniCloud.databaseForJQL()
db.collection(this._getMainCollection()).add(value).then<void>((res : UniCloudDBAddResult) => {
options.success?.(res)
this._isShowToast(options.showToast ?? false, options.toastTitle ?? 'add success')
}).catch((err) => {
this._requestFail(err, options.fail)
}).then(() => {
this._requestComplete(options.complete, options.needLoading)
}, () => {
this._requestComplete(options.complete, options.needLoading)
})
},
update(id : string, value : UTSJSONObject, options : UniCloudDBComponentUpdateOptions) {
if (options.needConfirm == true) {
uni.showModal({
title: options.confirmTitle,
content: options.confirmContent,
showCancel: true,
success: (res) => {
if (res.confirm) {
this._update(id, value, options)
}
}
})
} else {
this._update(id, value, options)
}
},
remove(id : any, options : UniCloudDBComponentRemoveOptions) {
const ids = Array.isArray(id) ? (id as Array<any>) : [id]
if (options.needConfirm == true) {
uni.showModal({
title: options.confirmTitle,
content: options.confirmContent,
showCancel: true,
success: (res) => {
if (res.confirm) {
this._remove(ids, options)
}
}
})
} else {
this._remove(ids, options)
}
},
_update(id : string, value : UTSJSONObject, options : UniCloudDBComponentUpdateOptions) {
this._needLoading(options.needLoading, options.loadingTitle)
const db = uniCloud.databaseForJQL()
db.collection(this._getMainCollection()).doc(id).update(value).then((res) => {
options.success?.(res)
this._isShowToast(options.showToast ?? false, options.toastTitle ?? 'update success')
}).catch((err : any | null) => {
this._requestFail(err, options.fail)
}).then(() => {
this._requestComplete(options.complete, options.needLoading)
}, () => {
this._requestComplete(options.complete, options.needLoading)
})
},
_remove(ids : Array<any>, options : UniCloudDBComponentRemoveOptions) {
this._needLoading(options.needLoading, options.loadingTitle)
const db = uniCloud.databaseForJQL()
const dbCommand = db.command
db.collection(this._getMainCollection()).where({
_id: dbCommand.in(ids)
}).remove().then((res) => {
options.success?.(res)
if (this.pageData == PAGE_MODE_REPLACE) {
this.refresh()
} else {
this._removeData(ids)
}
}).catch((err : any | null) => {
this._requestFail(err, options.fail)
}).then(() => {
this._requestComplete(options.complete, options.needLoading)
}, () => {
this._requestComplete(options.complete, options.needLoading)
})
},
_removeData(ids : Array<any>) {
const il = ids.slice(0)
const dl = this.dataList
for (let i = dl.length - 1; i >= 0; i--) {
const index = il.indexOf(dl[i]['_id'])
if (index >= 0) {
dl.splice(i, 1)
il.splice(index, 1)
}
}
},
_isShowToast(showToast : boolean, title : string) {
if (showToast == true) {
uni.showToast({
title: title
})
}
},
_needLoading(needLoading ?: boolean | null, title ?: string | null) {
if (needLoading == true) {
uni.showLoading({
mask: true,
title: title ?? ''
})
}
},
_requestFail(err ?: any | null, callback ?: FailCallback | null) {
callback?.(err)
this.error = err as UniCloudError
this.$emit(EVENT_ERROR, err)
},
_requestComplete(callback ?: CompleteCallback | null, needLoading ?: boolean | null) {
callback?.()
if (needLoading == true) {
uni.hideLoading()
}
},
getExec() : Promise<UniCloudDBGetResult> {
return this.getTemp()
},
getTemp() : Promise<UniCloudDBGetResult> {
let db = uniCloud.databaseForJQL()
let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array<any>)) : db.collection(this.collection)
let filter : UniCloudDBFilter | null = null
if (this.foreignKey.length > 0) {
filter = collection.foreignKey(this.foreignKey)
}
if (typeof this.where == 'string') {
const whereString = this.where as string
if (whereString.length > 0) {
filter = (filter != null) ? filter.where(this.where) : collection.where(this.where)
}
} else if (typeof this.where == 'object') {
filter = (filter != null) ? filter.where(this.where) : collection.where(this.where)
}
let query : UniCloudDBQuery | null = null
if (this.field.length > 0) {
query = (filter != null) ? filter.field(this.field) : collection.field(this.field)
}
if (this.groupby.length > 0) {
if (query != null) {
query = query.groupBy(this.groupby)
} else if (filter != null) {
query = filter.groupBy(this.groupby)
}
}
if (this.groupField.length > 0) {
if (query != null) {
query = query.groupField(this.groupField)
} else if (filter != null) {
query = filter.groupField(this.groupField)
}
}
if (this.distinct == true) {
if (query != null) {
query = query.distinct(this.field)
} else if (filter != null) {
query = filter.distinct(this.field)
}
}
if (this.orderby.length > 0) {
if (query != null) {
query = query.orderBy(this.orderby)
} else if (filter != null) {
query = filter.orderBy(this.orderby)
} else {
query = collection.orderBy(this.orderby)
}
}
const size = this.pagination.size
const current = this.pagination.current
const skipSize = size * (current - 1)
if (query != null) {
query = query.skip(skipSize).limit(size)
} else if (filter != null) {
query = filter.skip(skipSize).limit(size)
} else {
query = collection.skip(skipSize).limit(size)
}
const getOptions = {}
const treeOptions = {
limitLevel: this.limitlevel,
startWith: this.startwith
}
if (this.getcount == true) {
getOptions['getCount'] = this.getcount
}
if (typeof this.gettree == 'string') {
const getTreeString = this.gettree as string
if (getTreeString.length > 0) {
getOptions['getTree'] = treeOptions
}
} else if (typeof this.gettree == 'object') {
getOptions['getTree'] = treeOptions
}
if (this.gettreepath == true) {
getOptions['getTreePath'] = treeOptions
}
return query.get(getOptions)
},
_getMainCollection() : string {
if (typeof this.collection === 'string') {
return (this.collection as string).split(',')[0]
}
if (Array.isArray(this.collection)) {
const array = this.collection as Array<any>
const index = array[0] as UTSJSONObject
const collection = index.getString('$db[0].$param[0]')
return collection ?? ''
}
return ''
},
_dispatchEvent(type : string, data : Array<UTSJSONObject>) {
this.$emit(type, data, this.isEnded, {
current: this.pagination.current,
size: this.pagination.size,
count: this.pagination.count
})
}
}
}
</script>
@@ -0,0 +1,37 @@
<template>
<view @click="_onclick">
<slot :options="options" :loading="loading" :error="errorMessage" />
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" :unit-id="unitId" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" @create="_handleAdRef" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef APP
import adMixin from "../ad/ad.mixin.app.js"
// #endif
// #ifdef MP-WEIXIN
import adMixin from "../ad/ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "../ad/ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'AdFullscreenVideo',
mixins: [adMixin],
props: {
adType: {
type: String,
default: 'FullScreenVideo'
}
},
methods: {
}
}
</script>
@@ -0,0 +1,151 @@
<template>
<view @click="onclick">
<slot :options="options" :data="adData" :loading="loading" :error="errorMessage" />
</view>
</template>
<script>
const AD_URL = 'https://wxac1.dcloud.net.cn/openPage/acs'
const AD_REPORT_URL = 'https://wxac1.dcloud.net.cn/openPage/acs'
//const WEBVIEW_PATH = '/uni_modules/uni-ad-interactive/pages/uni-ad-interactive/uni-ad-interactive'
const events = {
load: 'load',
close: 'close',
error: 'error'
}
const OpenTypes = {
Interactive: 'interactive'
}
export default {
name: 'AdInteractive',
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
disabled: {
type: [Boolean, String],
default: false
},
adpid: {
type: [Number, String],
default: ''
},
openType: {
type: String,
default: 'interactive'
},
openPagePath: {
type: String,
default: ""
}
},
data() {
return {
adData: null,
loading: false,
errorMessage: ""
}
},
created() {
this._interactiveUrl = null
if (this.openPagePath) {
this.getAdData()
}
},
methods: {
getAdData() {
if (!this.adpid) {
this.$emit(events.error, {
code: -5002,
message: 'invalid adpid'
})
return
}
this.loading = true
uni.request({
url: AD_URL,
method: 'POST',
data: {
adpid: this.adpid
},
timeout: 5000,
dataType: 'json',
success: (res) => {
if (res.statusCode !== 200) {
this.$emit(events.error, {
errCode: res.statusCode,
errMsg: res.statusCode
})
return
}
const responseData = res.data
if (responseData.ret === 0) {
this._interactiveUrl = responseData.data.adp_url
this.adData = {
imgUrl: responseData.data.icon_url,
openPath: this.openPagePath + '?url=' + encodeURIComponent(this._interactiveUrl)
}
this.$emit(events.load, this.adData)
} else {
const errMsg = {
errCode: responseData.ret,
errMsg: responseData.msg
}
this.errorMessage = errMsg
this.$emit(events.error, errMsg)
}
},
fail: (err) => {
this.$emit(events.error, {
errCode: '',
errMsg: err.errMsg
})
},
complete: () => {
this.loading = false
}
})
},
onclick() {
if (this.disabled) {
return
}
if (!this._interactiveUrl) {
return
}
uni.navigateTo({
url: this.adData.openPath
})
this._report()
},
_report() {
uni.request({
url: AD_REPORT_URL,
data: {
adpid: this.adpid,
t: '10019'
},
timeout: 5000,
dataType: 'json'
})
}
}
}
</script>
<style>
view {
display: block;
}
</style>
@@ -0,0 +1,43 @@
<template>
<view @click="_onclick">
<slot :options="options" :loading="loading" :error="errorMessage" />
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" :unit-id="unitId" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" @create="_handleAdRef" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<!-- #endif -->
<!-- #ifdef H5 -->
<div ref="container" />
<!-- #endif -->
</view>
</template>
<script>
// #ifdef APP
import adMixin from "../ad/ad.mixin.app.js"
// #endif
// #ifdef H5
import adMixin from "../ad/ad-interstitial.web.js"
// #endif
// #ifdef MP-WEIXIN
import adMixin from "../ad/ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "../ad/ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'AdInterstitial',
mixins: [adMixin],
props: {
adType: {
type: String,
default: 'Interstitial'
}
},
methods: {
}
}
</script>
@@ -0,0 +1,39 @@
<template>
<view @click="_onclick">
<slot :options="options" :loading="loading" :error="errorMessage" />
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" :unit-id="unitId" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" @create="_handleAdRef" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef APP
import adMixin from "../ad/ad.mixin.app.js"
// #endif
// #ifdef H5
import adMixin from "../ad/ad.mixin.web.js"
// #endif
// #ifdef MP-WEIXIN
import adMixin from "../ad/ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "../ad/ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'AdRewardedVideo',
mixins: [adMixin],
props: {
adType: {
type: String,
default: 'RewardedVideo'
}
},
methods: {}
}
</script>
+327
View File
@@ -0,0 +1,327 @@
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
}
},
watch: {
adpid (val) {
if (val) {
this._loadData(val)
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
created () {
this._pc = {}
this._pl = []
this._loadData()
},
methods: {
load () {
this._dispatchEvent(EventType.Load, {})
},
show () {
this.errorMessage = null
const data = this._pl[0]
const providerConfig = this._pc[data.a1][data.t]
AdScript.instance.load(data.t, providerConfig.script, () => {
this._renderData(data)
}, (err) => {
this.errorMessage = err.message
this._dispatchEvent(EventType.Error, err)
})
},
_onclick () {
this.show()
},
_loadData (adpid) {
this.loading = true
const id = adpid || this.adpid
AdConfig.instance.get(id, (a, b) => {
this._pc = a
this._pl = b
this.loading = false
}, (err) => {
this.loading = false
this.errorMessage = err
this._dispatchEvent(EventType.Error, err)
})
},
_renderData (data) {
const id = this._createView()
const coral = new window.CoralAdv({
app_id: data.a2,
placement_id: data.a3,
type: data.a4,
display_type: data.a5,
container_id: id,
count: 1
})
coral.ready().then(async (res) => {
if (res.ret === 0) {
} else {
this._dispatchEvent(EventType.Error, res)
}
}).catch((err) => {
this._dispatchEvent(EventType.Error, err)
})
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
},
_createView () {
const id = this._randomId()
const adView = document.createElement('div')
adView.setAttribute('id', id)
this.$refs.container.innerHTML = ''
this.$refs.container.append(adView)
return id
},
_randomId () {
let result = ''
for (let i = 0; i < 4; i++) {
result += (65536 * (1 + Math.random()) | 0).toString(16).substring(1)
}
return '_u' + result
}
}
}
// let IC = 0
// let IS = 0
class AdConfig {
static get instance () {
if (this._instance == null) {
this._instance = new AdConfig()
this._instance._init()
}
return this._instance
}
constructor () {
this._instance = null
this._adConfig = null
this._isLoading = false
this._lastError = null
this._callbacks = []
}
get adConfig () {
return this._adConfig
}
get isExpired () {
if (this._adConfig == null) {
return true
}
return (Math.abs(Date.now() - this._adConfig.last) > this.CACHE_TIME)
}
_init () {
var config = this._getConfig()
if (config === null || !config.last) {
return
}
if (!this.isExpired) {
this._adConfig = config.data
}
}
get (adpid, success, fail) {
// IC++
if (this._adConfig != null) {
this._doCallback(adpid, success, fail)
if (this.isExpired) {
this._loadAdConfig(adpid)
}
return
}
this._callbacks.push({
adpid: adpid,
success: success,
fail: fail
})
this._loadAdConfig(adpid)
}
_doCallback (adpid, success, fail) {
// IS++
var { a, b } = this._adConfig
if (a[adpid]) {
success(b, a[adpid])
} else {
fail(this.ERROR_INVALID_ADPID)
}
}
_loadAdConfig (adpid) {
if (this._isLoading === true) {
return
}
this._isLoading = true
uni.request({
url: this.URL,
method: 'GET',
timeout: 8000,
data: {
d: location.hostname,
a: adpid
},
dataType: 'json',
success: (res) => {
const rd = res.data
if (rd.ret === 0) {
const data = rd.data
this._adConfig = data
this._setConfig(data)
this._callbacks.forEach(({ adpid, success, fail }) => {
this._doCallback(adpid, success, fail)
})
} else {
this._callbacks.forEach((i) => {
i.fail({ errCode: rd.ret, errMsg: rd.msg })
})
}
this._callbacks = []
},
fail: (err) => {
this._callbacks.forEach((i) => {
i.fail(err)
})
this._callbacks = []
},
complete: (c) => {
this._isLoading = false
}
})
}
_getConfig () {
if (!navigator.cookieEnabled || !window.localStorage) {
return null
}
var data = localStorage.getItem(this.KEY)
return data ? JSON.parse(data) : null
}
_setConfig (data) {
if (!navigator.cookieEnabled || !window.localStorage) {
return null
}
localStorage.setItem(this.KEY, JSON.stringify({
last: Date.now(),
data: data
}))
}
}
Object.assign(AdConfig.prototype, {
URL: 'https://hac1.dcloud.net.cn/ah5',
KEY: 'uni_app_ad_config',
CACHE_TIME: 1000 * 60 * 10,
ERROR_INVALID_ADPID: {
'-5002': 'invalid adpid'
}
})
class AdScript {
static get instance () {
if (this._instance == null) {
this._instance = new AdScript()
}
return this._instance
}
constructor () {
this._instance = null
this._callback = {}
this._cache = {}
}
load (provider, script, success, fail) {
if (this._cache[provider] === undefined) {
this.loadScript(provider, script)
}
if (this._cache[provider] === 1) {
success()
} else {
if (!this._callback[provider]) {
this._callback[provider] = []
}
this._callback[provider].push({
success,
fail
})
}
}
loadScript (provider, script) {
this._cache[provider] = 0
var ads = document.createElement('script')
ads.setAttribute('id', 'uniad_provider' + provider)
for (const var1 in script) {
ads.setAttribute(var1, script[var1])
}
ads.onload = () => {
this._cache[provider] = 1
this._callback[provider].forEach(({ success }) => {
success()
})
this._callback[provider].length = 0
}
ads.onerror = (err) => {
this._cache[provider] = undefined
this._callback[provider].forEach(({ fail }) => {
fail(err)
})
this._callback[provider].length = 0
}
document.body.append(ads)
}
}
+556
View File
@@ -0,0 +1,556 @@
const ADType = {
RewardedVideo: 'RewardedVideo',
FullScreenVideo: 'FullScreenVideo',
Interstitial: 'Interstitial'
}
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const EXPIRED_TIME = 1000 * 60 * 30
const ProviderType = {
CSJ: 'csj',
GDT: 'gdt'
}
const RETRY_COUNT = 1
class AdBase {
constructor (adInstance, options = {}) {
this._isLoad = false
this._isLoading = false
this._isPlaying = false
this._lastLoadTime = 0
this._lastError = null
this._retryCount = 0
if (options.retry !== undefined) {
this._retry = options.retry
} else {
this._retry = true
}
this._loadCallback = null
this._closeCallback = null
this._errorCallback = null
const ad = this._ad = adInstance
ad.onLoad((e) => {
this._isLoading = false
this._isLoad = true
this._lastLoadTime = Date.now()
this.onLoad()
})
ad.onClose((e) => {
this._isLoad = false
this._isPlaying = false
this.onClose(e)
})
ad.onVerify && ad.onVerify((e) => {
// e.isValid
})
ad.onError(({
code,
message,
detail
}) => {
this._isLoading = false
const data = {
code: code,
errMsg: message,
detail: detail
}
if (code === -5008 && this._retry && this._retryCount < RETRY_COUNT) {
this._retryCount += 1
this._loadAd()
return
}
this._lastError = data
this.onError(data)
})
}
get isExpired () {
return (this._lastLoadTime !== 0 && (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME))
}
get isLoad () {
return this._isLoad
}
get isLoading () {
return this._isLoading
}
getProvider () {
return this._ad.getProvider()
}
load (onload, onerror) {
this._loadCallback = onload
this._errorCallback = onerror
if (this._isPlaying) {
onerror && onerror()
return
}
if (this._isLoading) {
return
}
if (this._isLoad) {
this.onLoad()
return
}
this._retryCount = 0
this._loadAd()
}
show (onclose, onshow) {
this._closeCallback = onclose
if (this._isLoading || this._isPlaying || !this._isLoad) {
return
}
if (this._lastError !== null) {
this.onError(this._lastError)
return
}
const provider = this.getProvider()
if (provider === ProviderType.CSJ && this.isExpired) {
if (this._retry) {
this._loadAd()
} else {
this.onError(this._lastError)
}
return
}
this._isPlaying = true
this._ad.show()
onshow && onshow()
}
onLoad (e) {
if (this._loadCallback != null) {
this._loadCallback()
}
}
onClose (e) {
if (this._closeCallback != null) {
this._closeCallback({
isEnded: e.isEnded
})
}
}
onError (e) {
if (this._errorCallback != null) {
this._errorCallback(e)
}
}
destroy () {
this._ad.destroy()
}
_loadAd () {
this._isLoad = false
this._isLoading = true
this._lastError = null
this._ad.load()
}
}
class RewardedVideo extends AdBase {
constructor (options = {}) {
super(plus.ad.createRewardedVideoAd(options), options)
}
}
class FullScreenVideo extends AdBase {
constructor (options = {}) {
super(plus.ad.createFullScreenVideoAd(options), options)
}
}
class Interstitial extends AdBase {
constructor (options = {}) {
super(plus.ad.createInterstitialAd(options), options)
}
}
class AdHelper {
constructor (adType) {
this._ads = {}
this._adType = adType
this._lastWaterfallIndex = -1
}
load (options, onload, onerror) {
if (!options.adpid || this.isBusy(options.adpid)) {
return
}
this.get(options).load(onload, onerror)
}
show (options, onload, onerror, onclose, onshow) {
const ad = this.get(options)
if (ad.isLoad) {
this._lastWaterfallIndex = -1
ad.show((e) => {
onclose && onclose(e)
}, () => {
onshow && onshow()
})
} else {
ad.load(() => {
this._lastWaterfallIndex = -1
onload && onload()
ad.show((e) => {
onclose && onclose(e)
}, () => {
onshow && onshow()
})
}, (err) => {
onerror && onerror(err)
})
}
}
// 底价预载逻辑
loadWaterfall (options, onload, onfail, index = 0) {
const {
adpid,
urlCallback
} = options
if (!Array.isArray(adpid)) {
return
}
const options2 = {
adpid: adpid[index],
urlCallback,
retry: false
}
console.log('ad.loadWaterfall::index=' + index)
this.load(options2, (res) => {
this._lastWaterfallIndex = index
onload(options2)
}, (err) => {
index++
if (index >= adpid.length) {
onfail(err)
} else {
this.loadWaterfall(options, onload, onfail, index)
}
})
}
// 底价逻辑,失败后下一个,无重试机制
showWaterfall (options, onload, onfail, onclose, onshow, index = 0) {
const {
adpid,
urlCallback
} = options
if (!Array.isArray(adpid)) {
return
}
if (this._lastWaterfallIndex > -1) {
index = this._lastWaterfallIndex
}
const options2 = {
adpid: adpid[index],
urlCallback,
retry: false
}
console.log('ad.showWaterfall::index=' + index)
this.show(options2, () => {
onload()
}, (err) => {
index++
if (index >= adpid.length) {
onfail(err)
} else {
this.showWaterfall(options, onload, onfail, onclose, onshow, index)
}
}, (res) => {
onclose(res)
}, () => {
onshow()
})
}
// 预载底价瀑布流
preloadWaterfall (options, index = 0, step = 1) {
if (step === 1) {
this.loadWaterfall(options, (res) => {
console.log('preloadWaterfall.success::', res)
}, (err) => {
console.log('loadWaterfall.fail', err)
})
return
}
const {
adpid,
urlCallback
} = options
for (let i = 0; i < step; i++) {
if (index < adpid.length) {
const options2 = {
adpid: adpid[index],
urlCallback
}
this.loadWaterfall(options2, (res) => {
console.log('preloadWaterfall.success::', res)
}, (err) => {
console.log('loadWaterfall.fail', err)
this.preloadWaterfall(options, index, step)
})
index++
} else {
break
}
}
}
isBusy (adpid) {
return (this._ads[adpid] && this._ads[adpid].isLoading)
}
get (options) {
const {
adpid
} = options
if (!this._ads[adpid]) {
this._ads[adpid] = this._createInstance(options)
}
return this._ads[adpid]
}
getProvider (adpid) {
if (this._ads[adpid]) {
return this._ads[adpid].getProvider()
}
return null
}
remove (adpid) {
if (this._ads[adpid]) {
this._ads[adpid].destroy()
delete this._ads[adpid]
}
}
_createInstance (options) {
const adType = options.adType || this._adType
delete options.adType
let ad = null
if (adType === ADType.RewardedVideo) {
ad = new RewardedVideo(options)
} else if (adType === ADType.FullScreenVideo) {
ad = new FullScreenVideo(options)
} else if (adType === ADType.Interstitial) {
ad = new Interstitial(options, true)
}
return ad
}
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
disabled: {
type: [Boolean, String],
default: false
},
adpid: {
type: [Number, String, Array],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
watch: {
adpid (newValue, oldValue) {
this._removeInstance(oldValue)
if (this.preload) {
this._loadAd()
}
},
// 服务器回调透传参数,仅在创建广告实例时可传递参数,如果发生变化需要重新创建广告实例
urlCallback: {
deep: true,
handler() {
this._removeInstance()
}
}
},
created () {
this._adHelper = new AdHelper(this.adType)
setTimeout(() => {
if (this.preload) {
this._loadAd()
}
}, 100)
},
methods: {
load () {
if (this.isLoading) {
return
}
this._startLoading()
const invoke = this._isWaterfall() ? 'loadWaterfall' : 'load'
this._adHelper[invoke](this._getAdOptions(), () => {
this._onLoad()
}, (err) => {
this._onLoadFail(err)
})
},
show () {
if (this.isLoading) {
return
}
this._startLoading()
const invoke = this._isWaterfall() ? 'showWaterfall' : 'show'
this._adHelper[invoke](this._getAdOptions(), () => {
this._onLoad()
}, (err) => {
this._onLoadFail(err)
}, (res) => {
this._dispatchEvent(EventType.Close, res)
if (this.loadnext) {
this.load()
}
}, () => {
// show
this.loading = false
})
},
getProvider () {
if (Array.isArray(this.adpid)) {
return null
}
return this._adHelper.getProvider(this.adpid)
},
_loadAd () {
if (this._canCreateAd()) {
this.load()
}
},
_onclick () {
if (!this.disabled) {
this.show()
}
},
_getAdOptions () {
return {
adpid: this.adpid,
urlCallback: this.urlCallback
}
},
_isWaterfall () {
return (Array.isArray(this.adpid) && this.adpid.length > 0)
},
_canCreateAd () {
let result = false
if (Array.isArray(this.adpid) && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_removeInstance (adpid) {
const id = adpid || this.adpid
if (Array.isArray(id)) {
id.forEach((item) => {
this._adHelper.remove(item)
})
} else if (id) {
this._adHelper.remove(id)
}
},
_startLoading () {
this.loading = true
this.errorMessage = null
},
_onLoad () {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onLoadFail (err) {
this.loading = false
this.errorMessage = JSON.stringify(err)
this._dispatchEvent(EventType.Error, err)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
}
}
}
+556
View File
@@ -0,0 +1,556 @@
const ADType = {
RewardedVideo: 'RewardedVideo',
FullScreenVideo: 'FullScreenVideo',
Interstitial: 'Interstitial'
}
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const EXPIRED_TIME = 1000 * 60 * 30
const ProviderType = {
CSJ: 'csj',
GDT: 'gdt'
}
const RETRY_COUNT = 1
class AdBase {
constructor (adInstance, options = {}) {
this._isLoad = false
this._isLoading = false
this._isPlaying = false
this._lastLoadTime = 0
this._lastError = null
this._retryCount = 0
if (options.retry !== undefined) {
this._retry = options.retry
} else {
this._retry = true
}
this._loadCallback = null
this._closeCallback = null
this._errorCallback = null
const ad = this._ad = adInstance
ad.onLoad((e) => {
this._isLoading = false
this._isLoad = true
this._lastLoadTime = Date.now()
this.onLoad()
})
ad.onClose((e) => {
this._isLoad = false
this._isPlaying = false
this.onClose(e)
})
ad.onVerify && ad.onVerify((e) => {
// e.isValid
})
ad.onError(({
code,
message
}) => {
this._isLoading = false
const data = {
code: code,
errMsg: message
}
if (this._retry && code === -5008) {
this._loadAd()
return
}
if (this._retry && this._retryCount < RETRY_COUNT) {
this._retryCount += 1
this._loadAd()
return
}
this._lastError = data
this.onError(data)
})
}
get isExpired () {
return (this._lastLoadTime !== 0 && (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME))
}
get isLoad () {
return this._isLoad
}
get isLoading () {
return this._isLoading
}
getProvider () {
return this._ad.getProvider()
}
load (onload, onerror) {
this._loadCallback = onload
this._errorCallback = onerror
if (this._isPlaying) {
onerror && onerror()
return
}
if (this._isLoading) {
return
}
if (this._isLoad) {
this.onLoad()
return
}
this._retryCount = 0
this._loadAd()
}
show (onclose, onshow) {
this._closeCallback = onclose
if (this._isLoading || this._isPlaying || !this._isLoad) {
return
}
if (this._lastError !== null) {
this.onError(this._lastError)
return
}
const provider = this.getProvider()
if (provider === ProviderType.CSJ && this.isExpired) {
if (this._retry) {
this._loadAd()
} else {
this.onError(this._lastError)
}
return
}
this._isPlaying = true
this._ad.show()
onshow && onshow()
}
onLoad (e) {
if (this._loadCallback != null) {
this._loadCallback()
}
}
onClose (e) {
if (this._closeCallback != null) {
this._closeCallback({
isEnded: e.isEnded
})
}
}
onError (e) {
if (this._errorCallback != null) {
this._errorCallback(e)
}
}
destroy () {
this._ad.destroy()
}
_loadAd () {
this._isLoad = false
this._isLoading = true
this._lastError = null
this._ad.load()
}
}
class RewardedVideo extends AdBase {
constructor (options = {}) {
super(plus.ad.createRewardedVideoAd(options), options)
}
}
class FullScreenVideo extends AdBase {
constructor (options = {}) {
super(plus.ad.createFullScreenVideoAd(options), options)
}
}
class Interstitial extends AdBase {
constructor (options = {}) {
super(plus.ad.createInterstitialAd(options), options)
}
}
class AdHelper {
constructor (adType) {
this._ads = {}
this._adType = adType
this._lastWaterfallIndex = -1
}
load (options, onload, onerror) {
if (!options.adpid || this.isBusy(options.adpid)) {
return
}
this.get(options).load(onload, onerror)
}
show (options, onload, onerror, onclose, onshow) {
const ad = this.get(options)
if (ad.isLoad) {
this._lastWaterfallIndex = -1
ad.show((e) => {
onclose && onclose(e)
}, () => {
onshow && onshow()
})
} else {
ad.load(() => {
this._lastWaterfallIndex = -1
onload && onload()
ad.show((e) => {
onclose && onclose(e)
}, () => {
onshow && onshow()
})
}, (err) => {
onerror && onerror(err)
})
}
}
// 底价预载逻辑
loadWaterfall (options, onload, onfail, index = 0) {
const {
adpid,
urlCallback
} = options
if (!Array.isArray(adpid)) {
return
}
const options2 = {
adpid: adpid[index],
urlCallback,
retry: false
}
console.log('ad.loadWaterfall::index=' + index)
this.load(options2, (res) => {
this._lastWaterfallIndex = index
onload(options2)
}, (err) => {
index++
if (index >= adpid.length) {
onfail(err)
} else {
this.loadWaterfall(options, onload, onfail, index)
}
})
}
// 底价逻辑,失败后下一个,无重试机制
showWaterfall (options, onload, onfail, onclose, onshow, index = 0) {
const {
adpid,
urlCallback
} = options
if (!Array.isArray(adpid)) {
return
}
if (this._lastWaterfallIndex > -1) {
index = this._lastWaterfallIndex
}
const options2 = {
adpid: adpid[index],
urlCallback,
retry: false
}
console.log('ad.showWaterfall::index=' + index)
this.show(options2, () => {
onload()
}, (err) => {
index++
if (index >= adpid.length) {
onfail(err)
} else {
this.showWaterfall(options, onload, onfail, onclose, onshow, index)
}
}, (res) => {
onclose(res)
}, () => {
onshow()
})
}
// 预载底价瀑布流
preloadWaterfall (options, index = 0, step = 1) {
if (step === 1) {
this.loadWaterfall(options, (res) => {
console.log('preloadWaterfall.success::', res)
}, (err) => {
console.log('loadWaterfall.fail', err)
})
return
}
const {
adpid,
urlCallback
} = options
for (let i = 0; i < step; i++) {
if (index < adpid.length) {
const options2 = {
adpid: adpid[index],
urlCallback
}
this.loadWaterfall(options2, (res) => {
console.log('preloadWaterfall.success::', res)
}, (err) => {
console.log('loadWaterfall.fail', err)
this.preloadWaterfall(options, index, step)
})
index++
} else {
break
}
}
}
isBusy (adpid) {
return (this._ads[adpid] && this._ads[adpid].isLoading)
}
get (options) {
const {
adpid
} = options
if (!this._ads[adpid]) {
this._ads[adpid] = this._createInstance(options)
}
return this._ads[adpid]
}
getProvider (adpid) {
if (this._ads[adpid]) {
return this._ads[adpid].getProvider()
}
return null
}
remove (adpid) {
if (this._ads[adpid]) {
this._ads[adpid].destroy()
delete this._ads[adpid]
}
}
_createInstance (options) {
const adType = options.adType || this._adType
delete options.adType
let ad = null
if (adType === ADType.RewardedVideo) {
ad = new RewardedVideo(options)
} else if (adType === ADType.FullScreenVideo) {
ad = new FullScreenVideo(options)
} else if (adType === ADType.Interstitial) {
ad = new Interstitial(options, true)
}
return ad
}
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
disabled: {
type: [Boolean, String],
default: false
},
adpid: {
type: [Number, String, Array],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
created() {
this.$watch('adpid', (newValue, oldValue) => {
this._removeInstance(oldValue)
if (this.preload) {
this._loadAd()
}
})
// 服务器回调透传参数,仅在创建广告实例时可传递参数,如果发生变化需要重新创建广告实例
this.$watch('urlCallback', () => {
this._removeInstance()
})
this._adHelper = new AdHelper(this.adType)
setTimeout(() => {
if (this.preload) {
this._loadAd()
}
}, 100)
},
methods: {
load () {
if (this.isLoading) {
return
}
this._startLoading()
const invoke = this._isWaterfall() ? 'loadWaterfall' : 'load'
this._adHelper[invoke](this._getAdOptions(), () => {
this._onLoad()
}, (err) => {
this._onLoadFail(err)
})
},
show () {
if (this.isLoading) {
return
}
this._startLoading()
const invoke = this._isWaterfall() ? 'showWaterfall' : 'show'
this._adHelper[invoke](this._getAdOptions(), () => {
this._onLoad()
}, (err) => {
this._onLoadFail(err)
}, (res) => {
this._dispatchEvent(EventType.Close, res)
if (this.loadnext) {
this.load()
}
}, () => {
// show
this.loading = false
})
},
getProvider () {
if (Array.isArray(this.adpid)) {
return null
}
return this._adHelper.getProvider(this.adpid)
},
_loadAd () {
if (this._canCreateAd()) {
this.load()
}
},
_onclick () {
if (!this.disabled) {
this.show()
}
},
_getAdOptions () {
return {
adpid: this.adpid,
urlCallback: this.urlCallback
}
},
_isWaterfall () {
return (Array.isArray(this.adpid) && this.adpid.length > 0)
},
_canCreateAd () {
let result = false
if (Array.isArray(this.adpid) && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_removeInstance (adpid) {
const id = adpid || this.adpid
if (Array.isArray(id)) {
id.forEach((item) => {
this._adHelper.remove(item)
})
} else if (id) {
this._adHelper.remove(id)
}
},
_startLoading () {
this.loading = true
this.errorMessage = null
},
_onLoad () {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onLoadFail (err) {
this.loading = false
this.errorMessage = JSON.stringify(err)
this._dispatchEvent(EventType.Error, err)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
}
}
}
+110
View File
@@ -0,0 +1,110 @@
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
unitId: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
created () {
this._ad = null
},
methods: {
load () {
if (this.loading) {
return
}
this._startLoading()
},
show () {
this.errorMessage = null
this._refAdPlugin.show()
},
_handleAdRef(c) {
this._refAdPlugin = c.detail
if (this.preload && this._canCreateAd()) {
this._startLoading()
}
},
_onclick () {
this.show()
},
_startLoading () {
this.loading = true
this.errorMessage = null
this._refAdPlugin.load()
},
_canCreateAd () {
let result = false
if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_hasCallback () {
return (typeof this.urlCallback === 'object' && Object.keys(this.urlCallback).length > 0)
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onmpclose (e) {
this._dispatchEvent(EventType.Close, e)
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e)
this._dispatchEvent(EventType.Error, e)
},
_dispatchEvent (type, data) {
this.$emit(type, data)
}
}
}
+357
View File
@@ -0,0 +1,357 @@
const adPlugin = requirePlugin("uni-ad");
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const AdType = {
Banner: "banner",
RewardedVideo: "rewardedVideo",
Interstitial: "interstitial"
}
const ProviderType = {
WeChat: 10018,
UserWeChat: 10017,
ShanHu: 10020
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
unitId: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
wxchannel: false,
errorMessage: null
}
},
created () {
this._ad = null
this._providerType = ProviderType.ShanHu
if (this.preload && this._canCreateAd()) {
this.load()
}
},
methods: {
load () {
if (this.loading) {
return
}
this._startLoading()
if (this._providerType == ProviderType.ShanHu) {
} else if (this._providerType == ProviderType.WeChat) {
this.selectComponent('.uniad-plugin-wx').load()
} else if (this._providerType == ProviderType.UserWeChat) {
this._loadWxAd()
}
},
show (e) {
this.errorMessage = null
if (this._providerType == ProviderType.ShanHu) {
this._showAdInPlugin(this.selectComponent('.uniad-plugin'))
} else if (this._providerType == ProviderType.WeChat) {
this._showAdInPlugin(this.selectComponent('.uniad-plugin-wx'))
} else if (this._providerType == ProviderType.UserWeChat) {
this._showWxAd(e)
}
},
_onclick () {
this.show()
},
_startLoading () {
this.loading = true
this.errorMessage = null
},
_canCreateAd () {
let result = false
if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_hasCallback () {
return (typeof this.urlCallback === 'object' && Object.keys(this.urlCallback).length > 0)
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onmpclose (e) {
this._dispatchEvent(EventType.Close, e.detail)
if (e.detail.adsdata) {
const adv = e.detail.adv
const adsdata = e.detail.adsdata
const version = e.detail.version
/* eslint-disable no-undef */
uniCloud.callFunction({
name: 'uniAdCallback',
data: {
adv: adv,
adsdata: adsdata,
version: version
},
secretType: 'both',
success: (res) => {
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
delete e.detail.adv
delete e.detail.adsdata
delete e.detail.version
}
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e.detail)
this._dispatchEvent(EventType.Error, e.detail)
},
_onnextchannel (e) {
this.wxchannel = true
const adData = e[1];
this.$nextTick(() => {
if (adData.provider == 10017) {
this._providerType = ProviderType.UserWeChat
switch(e._nt_) {
case 4:
case 21:
case 22:
case 23:
break;
case 9:
this._createRewardedAd(adData.posid)
break;
case 15:
this._createInterstitialAd(adData.posid)
break;
}
} else if (adData.provider == 10018) {
this._providerType = ProviderType.WeChat
this.selectComponent('.uniad-plugin-wx').setConfig(e)
}
})
},
_onwxchannelerror(e) {
this.wxchannel = false
this.$nextTick(() => {
this._providerType = ProviderType.ShanHu
this.selectComponent('.uniad-plugin').shanhuChannel()
})
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
},
_showAdInPlugin(adComponent) {
if (this._hasCallback()) {
const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
success: ({
encryptKey,
iv,
version,
expireTime
}) => {
adComponent.show({
userId: this.urlCallback.userId || '',
extra: this.urlCallback.extra || '',
encryptKey,
iv,
version,
expireTime
})
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
} else {
adComponent.show({
userId: this.urlCallback.userId || '',
extra: this.urlCallback.extra || ''
})
}
},
_loadWxAd () {
this._userInvokeLoadFlag = true
switch (this.wxAdType) {
case AdType.RewardedVideo:
if (!this.rewardedAd) {
return;
}
this.rewardedAd.load();
break;
case AdType.Interstitial:
if (!this.interstitialAd) {
return;
}
this.interstitialAd.load();
break;
}
},
// 加载/显示广告
_showWxAd (options) {
this._urlCallback = options || this.urlCallback;
switch (this.wxAdType) {
case AdType.RewardedVideo:
if (!this.rewardedAd) {
this._userInvokeShowFlag = true
return;
}
this.rewardedAd.show().catch((err) => {
this.rewardedAd.load().then(() => {
this.rewardedAd.show();
}).catch((err) => {
this.triggerEvent(EventType.Error, err);
});
});
break;
case AdType.Interstitial:
if (!this.interstitialAd) {
this._userInvokeShowFlag = true
return;
}
this.interstitialAd.show().catch((err) => {
this.interstitialAd.load().then(() => {
this.interstitialAd.show();
}).catch((err) => {
this.triggerEvent(EventType.Error, err);
});
});
break;
}
},
// 微信激励视频
_createRewardedAd(adUnitId) {
if (this.rewardedAd) {
return;
}
this.rewardedAd = wx.createRewardedVideoAd({ adUnitId: adUnitId, multiton: true });
this.rewardedAd.onLoad(() => {
this.triggerEvent(EventType.Load, {})
if (this._userInvokeShowFlag) {
this._userInvokeShowFlag = false;
this.rewardedAd.show();
}
});
this.rewardedAd.onError(err => {
this.triggerEvent(EventType.Error, err);
});
this.rewardedAd.onClose(res => {
if (res.isEnded) {
this._callServer()
} else {
this.triggerEvent(EventType.Close, res);
}
});
this.rewardedAd.load().catch((err) => {});
},
// 微信插屏
_createInterstitialAd(adUnitId) {
if (this.interstitialAd) {
return;
}
this.interstitialAd = wx.createInterstitialAd({ adUnitId: adUnitId });
this.interstitialAd.onLoad(() => {
this.triggerEvent(EventType.Load, {})
if (this._userInvokeShowFlag) {
this._userInvokeShowFlag = false;
this.interstitialAd.show();
}
});
this.interstitialAd.onError(err => {
this.triggerEvent(EventType.Error, err);
});
this.interstitialAd.onClose(res => {
this.triggerEvent(EventType.Close, res);
});
this.interstitialAd.load().catch((err) => {});
},
_callServer() {
const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
success: (encryptConfig) => {
const callbackData = adPlugin.buildCallbackData(this.adpid, this.urlCallback, {}, encryptConfig)
uniCloud.callFunction({
name: 'uniAdCallback',
data: callbackData,
secretType: 'both',
success: (res) => {
this.triggerEvent(EventType.Close, res);
},
fail: (err) => {
this.triggerEvent(EventType.Error, err);
}
})
},
fail: (err) => {
this.triggerEvent(EventType.Error, err);
}
})
}
}
}
+159
View File
@@ -0,0 +1,159 @@
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
unitId: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
created () {
this._ad = null
setTimeout(() => {
if (this.preload && this._canCreateAd()) {
this.load()
}
}, 100)
},
methods: {
load () {
if (this.loading) {
return
}
this._startLoading()
},
show () {
this.errorMessage = null
this._ad = this.selectComponent('.uniad-plugin')
if (this._hasCallback()) {
const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
success: ({
encryptKey,
iv,
version,
expireTime
}) => {
this._ad.show({
userId: this.urlCallback.userId || '',
extra: this.urlCallback.extra || '',
encryptKey,
iv,
version,
expireTime
})
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
} else {
this._ad.show()
}
},
_onclick () {
this.show()
},
_startLoading () {
this.loading = true
this.errorMessage = null
},
_canCreateAd () {
let result = false
if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_hasCallback () {
return (typeof this.urlCallback === 'object' && Object.keys(this.urlCallback).length > 0)
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onmpclose (e) {
this._dispatchEvent(EventType.Close, e.detail)
if (e.detail.adsdata) {
const adv = e.detail.adv
const adsdata = e.detail.adsdata
const version = e.detail.version
/* eslint-disable no-undef */
uniCloud.callFunction({
name: 'uniAdCallback',
data: {
adv: adv,
adsdata: adsdata,
version: version
},
secretType: 'both',
success: (res) => {
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
delete e.detail.adv
delete e.detail.adsdata
delete e.detail.version
}
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e.detail)
this._dispatchEvent(EventType.Error, e.detail)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
}
}
}
+173
View File
@@ -0,0 +1,173 @@
const AD_SERVER_URL = 'https://hac1.dcloud.net.cn/h5/gs'
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const ProviderType = 'wm'
class Process {
static Start (cmd, args) {
return new Process().openScheme(cmd)
}
constructor () {
this._a = null
}
openScheme (url) {
if (this._a == null) {
this._a = document.createElement('a')
}
this._a.href = url
this._a.click()
}
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
adData: null,
loading: false,
showModel: false,
errorMessage: null
}
},
created () {
this._loading = false
this.adConfigData = null
},
methods: {
load () {
setTimeout(() => {
this._onmpload()
}, 200)
},
show (options) {
if (!this._isMobile()) {
this._dispatchEvent(EventType.Error, {
errCode: -1,
errMsg: '当前设备环境无效'
})
return
}
this.errorMessage = null
if (this._loading) {
return
}
this._loading = true
this._requestScheme(options)
},
getProvider () {
return ProviderType
},
_onclick () {
if (this.disabled) {
return
}
this.show()
},
_requestScheme (options = {}) {
const urlCallback = options.urlCallback || this.urlCallback
uni.request({
url: AD_SERVER_URL,
method: 'POST',
data: {
adpid: this.adpid,
userId: urlCallback.userId,
extra: urlCallback.extra
},
timeout: 5000,
dataType: 'json',
success: (res) => {
if (res.statusCode !== 200) {
this._dispatchEvent(EventType.Error, {
errCode: res.statusCode,
errMsg: res.statusCode
})
return
}
const responseData = res.data
if (responseData.ret === 0) {
Process.Start(responseData.data.openlink)
} else {
this._dispatchEvent(EventType.Error, {
errCode: responseData.ret,
errMsg: responseData.msg
})
}
},
fail: (err) => {
this.$emit(EventType.Error, {
errCode: '',
errMsg: err.errMsg
})
},
complete: () => {
this.loading = false
}
})
},
_isMobile () {
return /android|iphone/i.test(navigator.userAgent.toLowerCase())
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onmpclose (e) {
this._dispatchEvent(EventType.Close, e.detail)
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e.detail)
this._dispatchEvent(EventType.Error, e.detail)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
}
}
}
@@ -0,0 +1,127 @@
<template>
<uni-tabbar v-if="hasTabBar" v-show="showTabBar">
<div
:style="{
'flex-direction': direction === 'vertical' ? 'column' : 'row',
backgroundColor: tabBar.backgroundColor,
}"
class="uni-tabbar"
>
<template v-for="(item, index) in tabBar.list" :key="item.pagePath">
<div
v-if="item.visible !== false"
class="uni-tabbar__item"
@click="switchTab(item, index)"
>
<div class="uni-tabbar__bd">
<div
v-if="showIcon && item.iconPath"
:class="{ 'uni-tabbar__icon__diff': !item.text }"
class="uni-tabbar__icon"
>
<img
:src="
getRealPath(
selectedIndex === index
? item.selectedIconPath
: item.iconPath
)
"
/>
<div
v-if="item.redDot"
:class="{ 'uni-tabbar__badge': !!item.badge }"
class="uni-tabbar__reddot"
>
{{ item.badge }}
</div>
</div>
<div
v-if="item.text"
:style="{
color:
selectedIndex === index ? tabBar.selectedColor : tabBar.color,
fontSize: showIcon && item.iconPath ? '10px' : '14px',
}"
class="uni-tabbar__label"
>
{{ item.text }}
<div
v-if="item.redDot && (!showIcon || !item.iconPath)"
:class="{ 'uni-tabbar__badge': !!item.badge }"
class="uni-tabbar__reddot"
>
{{ item.badge }}
</div>
</div>
</div>
</div>
</template>
</div>
</uni-tabbar>
</template>
<script>
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { getRealPath } from '@dcloudio/uni-h5'
import { useTabBar } from '@dcloudio/uni-h5'
export default {
name: 'CustomTabBar',
props: {
selected: {
type: Number,
default: 0
},
showIcon: {
type: Boolean,
default: true
},
direction: {
type: String,
default: 'horizontal'
}
},
setup(props, { emit }) {
const tabBar = useTabBar()
const route = useRoute()
const hasTabBar = computed(() => tabBar.list && tabBar.list.length)
const selectedIndex = ref(props.selected)
watch(() => props.selected, value => selectedIndex.value = value)
watch(() => selectedIndex.value, value => tabBar.selectedIndex = value)
watch(() => {
const meta = route.meta
return [meta.isTabBar, meta.route]
}, ([isTabBar, pagePath]) => {
if (isTabBar) {
const index = tabBar.list.findIndex(item => pagePath === item.pagePath)
if (index > -1) {
selectedIndex.value = index
}
}
})
function switchTab(item, index) {
selectedIndex.value = index
const detail = {
index,
text: item.text,
pagePath: item.pagePath,
}
emit('onTabItemTap', detail)
}
return {
tabBar,
getRealPath,
selectedIndex,
hasTabBar,
showTabBar: true,
switchTab,
}
}
}
</script>
<style>
</style>
@@ -0,0 +1,159 @@
<template>
<view style="display: none;" />
</template>
<script>
const attrs = [
'titleIcon',
'titleIconRadius',
'subtitleText',
'subtitleSize',
'subtitleColor',
'subtitleOverflow',
'titleAlign',
'backgroundImage',
'backgroundRepeat',
'blurEffect'
]
export default {
props: {
title: {
type: String,
default: ''
},
titleIcon: {
type: String,
default: ''
},
titleIconRadius: {
type: String,
default: ''
},
subtitleText: {
type: String,
default: ''
},
subtitleSize: {
type: String,
default: ''
},
subtitleColor: {
type: String,
default: ''
},
subtitleOverflow: {
type: String,
default: ''
},
titleAlign: {
type: String,
default: ''
},
backgroundImage: {
type: String,
default: ''
},
backgroundRepeat: {
type: String,
default: ''
},
blurEffect: {
type: String,
default: ''
},
loading: {
type: Boolean,
default: false
},
frontColor: {
type: String,
default: '#ffffff'
},
backgroundColor: {
type: String,
default: '#000000'
},
colorAnimationDuration: {
type: Number,
default: 0
},
colorAnimationTimingFunc: {
type: String,
default: 'linear'
}
},
created () {
const pages = getCurrentPages()
const page = pages[pages.length - 1]
this.__$page = page
this.$watch('title', () => {
this.setNavigationBarTitle()
})
this.$watch('loading', () => {
this.setNavigationBarLoading()
})
this.$watch(() => [
this.frontColor,
this.backgroundColor,
this.colorAnimationDuration,
this.colorAnimationTimingFunc
],
() => {
this.setNavigationBarColor()
})
// #ifdef APP-PLUS
this.__$webview = page.$getAppWebview()
attrs.forEach(key => {
const titleNView = {}
if (this[key] || this[key].length > 0) {
titleNView[key] = this[key]
}
this.setTitleNView(titleNView)
this.$watch(key, (val) => {
const titleStyle = {}
titleStyle[key] = val
this.setTitleNView(titleStyle)
})
})
// #endif
},
beforeMount () {
this.title && this.setNavigationBarTitle()
this.setNavigationBarLoading()
this.setNavigationBarColor()
},
methods: {
setNavigationBarTitle () {
uni.setNavigationBarTitle({
__page__: this.__$page,
title: this.title
})
},
setNavigationBarLoading () {
uni[(this.loading ? 'show' : 'hide') + 'NavigationBarLoading']({
__page__: this.__$page
})
},
setNavigationBarColor () {
uni.setNavigationBarColor({
__page__: this.__$page,
frontColor: this.frontColor,
backgroundColor: this.backgroundColor,
animation: {
duration: this.colorAnimationDuration,
timingFunc: this.colorAnimationTimingFunc
}
})
},
setTitleNView (titleNView) {
const webview = this.__$webview
const style = webview.getStyle()
if (style && style.titleNView) {
webview.setStyle({
titleNView: titleNView
})
}
}
}
}
</script>
@@ -0,0 +1,10 @@
<template>
<teleport to="head">
<slot />
</teleport>
</template>
<script>
export default {
name: 'PageMetaHead',
}
</script>
+207
View File
@@ -0,0 +1,207 @@
<template>
<view style="display: none;">
<slot />
</view>
</template>
<script>
import { onMounted } from 'vue'
// #ifndef H5
import { onResize } from '@dcloudio/uni-app'
// #endif
// #ifdef H5
import { onWindowResize } from '@dcloudio/uni-h5'
// #endif
const scrolldoneEvent = {
type: 'scrolldone',
target: {
id: '',
offsetLeft: 0,
offsetTop: 0,
dataset: {}
},
currentTarget: {
id: '',
offsetLeft: 0,
offsetTop: 0,
dataset: {}
},
detail: {}
}
export default {
name: 'PageMeta',
setup(props, { emit }) {
// #ifndef H5
onResize((evt) => {
emit('resize', evt)
})
// #endif
// #ifdef H5
onMounted(() => {
onWindowResize(evt => {
emit('resize', evt)
})
})
// #endif
// let currentInstance = getCurrentInstance()
// let proxy = currentInstance.proxy
// onPageScroll((evt) => {
// if (proxy._invokePageScrollToFlag === true && evt.scrollTop === proxy._invokeScrollTop) {
// proxy._invokePageScrollToFlag = false
// emit('scrolldone', scrolldoneEvent)
// }
// })
},
props: {
backgroundTextStyle: {
type: String,
default: 'dark',
validator (value) {
return ['dark', 'light'].indexOf(value) !== -1
}
},
backgroundColor: {
type: String,
default: '#ffffff'
},
backgroundColorTop: {
type: String,
default: '#ffffff'
},
backgroundColorBottom: {
type: String,
default: '#ffffff'
},
scrollTop: {
type: String,
default: ''
},
scrollDuration: {
type: Number,
default: 300
},
pageStyle: {
type: String,
default: ''
},
enablePullDownRefresh: {
type: [Boolean, String],
default: false
},
rootFontSize: {
type: String,
default: ''
}
},
created () {
const page = getCurrentPages()[0]
this.$pageVm = page.$vm || page
// #ifdef APP-PLUS
this._currentWebview = page.$getAppWebview()
if (this.enablePullDownRefresh) {
this.setPullDownRefresh(this._currentWebview, true)
}
this.$watch('enablePullDownRefresh', (val) => {
this.setPullDownRefresh(this._currentWebview, val)
})
// #endif
// props
this.$watch('backgroundTextStyle', () => {
this.setBackgroundTextStyle()
})
this.$watch(() => [
this.rootFontSize,
this.pageStyle
], () => {
this.setPageMeta()
})
this.$watch(() => [
this.backgroundColor,
this.backgroundColorTop,
this.backgroundColorBottom
], () => {
this.setBackgroundColor()
})
this.$watch(() => [
this.scrollTop,
this.scrollDuration
], () => {
this.pageScrollTo()
})
// this._invokeScrollTop = -1
// this._invokePageScrollToFlag = false
},
beforeMount () {
this.setBackgroundColor()
if (this.rootFontSize || this.pageStyle) {
this.setPageMeta()
}
this.backgroundTextStyle && this.setBackgroundTextStyle()
},
mounted() {
this.scrollTop && this.pageScrollTo()
},
methods: {
setPullDownRefresh (webview, enabled) {
webview.setStyle({
pullToRefresh: {
support: enabled,
style: plus.os.name === 'Android' ? 'circle' : 'default'
}
})
},
setPageMeta () {
// h5 和 app-plus 设置 rootFontSize
// #ifdef H5 || APP-PLUS
uni.setPageMeta({
pageStyle: this.pageStyle,
rootFontSize: this.rootFontSize
})
// #endif
},
setBackgroundTextStyle () {
// TODO h5 app-plus 暂不支持
// #ifdef MP
uni.setBackgroundTextStyle && uni.setBackgroundTextStyle({
textStyle: this.backgroundTextStyle
})
// #endif
},
setBackgroundColor () {
// TODO h5 app-plus 暂不支持
// #ifdef MP
uni.setBackgroundColor && uni.setBackgroundColor({
backgroundColor: this.backgroundColor,
backgroundColorTop: this.backgroundColorTop,
backgroundColorBottom: this.backgroundColorBottom
})
// #endif
},
pageScrollTo () {
let scrollTop = String(this.scrollTop)
if (scrollTop.indexOf('rpx') !== -1) {
scrollTop = uni.upx2px(scrollTop.replace('rpx', ''))
}
scrollTop = parseFloat(scrollTop)
if (isNaN(scrollTop)) {
return
}
// this._invokeScrollTop = scrollTop
uni.pageScrollTo({
scrollTop,
duration: this.scrollDuration,
success: () => {
//this._invokePageScrollToFlag = true
}
})
}
}
}
</script>
@@ -0,0 +1,77 @@
<template>
<view v-show="matches">
<slot />
</view>
</template>
<script>
let mediaQueryObserver
export default {
name: 'UniMatchMedia',
props: {
width: {
type: [Number, String],
default: ''
},
minWidth: {
type: [Number, String],
default: ''
},
maxWidth: {
type: [Number, String],
default: ''
},
height: {
type: [Number, String],
default: ''
},
minHeight: {
type: [Number, String],
default: ''
},
maxHeight: {
type: [Number, String],
default: ''
},
orientation: {
type: String,
default: ''
}
},
data () {
return {
matches: true
}
},
mounted () {
let parent = this.$parent
while (parent.$parent) {
parent = parent.$parent
}
mediaQueryObserver = uni.createMediaQueryObserver(parent)
mediaQueryObserver.observe({
width: this.width,
maxWidth: this.maxWidth,
minWidth: this.minWidth,
height: this.height,
minHeight: this.minHeight,
maxHeight: this.maxHeight,
orientation: this.orientation
}, matches => {
this.matches = matches
})
},
destroyed () {
mediaQueryObserver.disconnect()
}
}
</script>
<style>
view {
display: block;
}
</style>
+29
View File
@@ -0,0 +1,29 @@
<template>
<view @click="onclick">
<uniad-plugin
class="uniad-plugin"
:adpid="adpid"
:unit-id="unitId"
@load="_onmpload"
@close="_onmpclose"
@error="_onmperror"
/>
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef MP-WEIXIN
import adMixin from "../ad/ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "../ad/ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'Uniad',
mixins: [adMixin]
}
</script>
+6
View File
@@ -0,0 +1,6 @@
{
"uniCloud.component.add.success": "Success",
"uniCloud.component.update.success": "Success",
"uniCloud.component.remove.showModal.title": "Tips",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+6
View File
@@ -0,0 +1,6 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+6
View File
@@ -0,0 +1,6 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+12
View File
@@ -0,0 +1,12 @@
import en from './en.json'
import es from './es.json'
import fr from './fr.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
es,
fr,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}
@@ -0,0 +1,6 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
@@ -0,0 +1,6 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否刪除數據"
}
+632
View File
@@ -0,0 +1,632 @@
<template>
<view>
<slot
:options="options"
:data="dataList"
:pagination="paginationInternal"
:loading="loading"
:hasMore="hasMore"
:error="errorMessage"
/>
</view>
</template>
<script>
import { onMounted, getCurrentInstance } from 'vue'
import { ssrRef, shallowSsrRef } from '@dcloudio/uni-app'
import { initVueI18n } from '@dcloudio/uni-i18n'
import messages from './i18n/index'
const isArray = Array.isArray
const { t } = initVueI18n(messages)
const events = {
load: 'load',
error: 'error'
}
const pageMode = {
add: 'add',
replace: 'replace'
}
const loadMode = {
auto: 'auto',
onready: 'onready',
manual: 'manual'
}
const attrs = [
'pageCurrent',
'pageSize',
'collection',
'action',
'field',
'getcount',
'orderby',
'where',
'groupby',
'groupField',
'distinct'
]
export default {
name: 'UniClouddb',
// #ifdef VUE3
setup(props) {
// 单条记录时,使用shallowRef(仅支持赋值修改),列表时,采用ref(支持push等修改)
const dataListRef = props.ssrKey ? (props.getone ? shallowSsrRef(undefined, props.ssrKey) : ssrRef([], props.ssrKey)) : (props.getone ? shallowSsrRef(undefined) : ssrRef([]))
const instance = getCurrentInstance()
onMounted(() => {
// client端判断是否需要再次请求数据(正常情况下,SSR返回的html中已包含此数据状态,无需再次额外请求)
if ((!dataListRef.value || dataListRef.value.length === 0) && !props.manual && props.loadtime === loadMode.auto) {
instance.proxy.loadData()
}
})
return { dataList: dataListRef }
},
// 服务端serverPrefetch生命周期,用于服务端加载数据,等将来全端支持Suspense时,可以采用 Suspense + async setup 来实现一版
async serverPrefetch() {
if (!this.manual && this.loadtime === loadMode.auto) {
return this.loadData()
}
},
// #endif
props: {
options: {
type: [Object, Array],
default() {
return {}
}
},
spaceInfo: {
type: Object,
default() {
return {}
}
},
collection: {
type: [String, Array],
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
getone: {
type: [Boolean, String],
default: false
},
gettree: {
type: [Boolean, String, Object],
default: false
},
gettreepath: {
type: [Boolean, String],
default: false
},
startwith: {
type: String,
default: ''
},
limitlevel: {
type: Number,
default: 10
},
groupby: {
type: String,
default: ''
},
groupField: {
type: String,
default: ''
},
distinct: {
type: [Boolean, String],
default: false
},
pageIndistinct: {
type: [Boolean, String],
default: false
},
foreignKey: {
type: String,
default: ''
},
loadtime: {
type: String,
default: 'auto'
},
manual: {
type: Boolean,
default: false
},
ssrKey: {
type: [String, Number],
default: ""
}
},
data() {
return {
loading: false,
hasMore: false,
// #ifndef VUE3
dataList: [],
// #endif
paginationInternal: {},
errorMessage: ''
}
},
computed: {
collectionArgs () {
return isArray(this.collection) ? this.collection : [this.collection]
},
isLookup () {
return (isArray(this.collection) && this.collection.length > 1) || (typeof this.collection === 'string' && this.collection.indexOf(',') > -1)
},
mainCollection () {
if (typeof this.collection === 'string') {
return this.collection.split(',')[0]
}
const mainQuery = JSON.parse(JSON.stringify(this.collection[0]))
return mainQuery.$db[0].$param[0]
}
},
created() {
this._isEnded = false
this.paginationInternal = {
current: this.pageCurrent,
size: this.pageSize,
count: 0
}
// #ifndef VUE3
if (this.getone) {
this.dataList = undefined
}
// #endif
this.$watch(() => {
var al = []
attrs.forEach(key => {
al.push(this[key])
})
return al
}, (newValue, oldValue) => {
this.paginationInternal.size = this.pageSize
if (newValue[0] !== oldValue[0]) {
this.paginationInternal.current = this.pageCurrent
}
if (this.loadtime === loadMode.manual) {
return
}
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] !== oldValue[i]) {
needReset = true
break
}
}
if (needReset) {
this.clear()
this.reset()
}
this._execLoadData()
})
// #ifdef MP-TOUTIAO
let changeName
const events = this.$scope.dataset.eventOpts || []
for (var i = 0; i < events.length; i++) {
const event = events[i]
if (event[0].includes('^load')) {
changeName = event[1][0][0]
}
}
if (changeName) {
let parent = this.$parent
let maxDepth = 16
this._changeDataFunction = null
while (parent && maxDepth > 0) {
const fun = parent[changeName]
if (fun && typeof fun === 'function') {
this._changeDataFunction = fun
maxDepth = 0
break
}
parent = parent.$parent
maxDepth--
}
}
// #endif
},
// #ifndef VUE3
mounted() {
if (!this.manual && this.loadtime === loadMode.auto) {
this.loadData()
}
},
// #endif
methods: {
loadData(args1, args2) {
let callback = null
let clear = false
if (typeof args1 === 'object') {
if (args1.clear) {
if (this.pageData === pageMode.replace) {
this.clear()
} else {
clear = args1.clear
}
this.reset()
}
if (args1.current !== undefined) {
this.paginationInternal.current = args1.current
}
if (typeof args2 === 'function') {
callback = args2
}
} else if (typeof args1 === 'function') {
callback = args1
}
return this._execLoadData(callback, clear)
},
loadMore() {
if (this._isEnded || this.loading) {
return
}
if (this.pageData === pageMode.add) {
this.paginationInternal.current++
}
this._execLoadData()
},
refresh() {
this.clear()
this._execLoadData()
},
clear() {
this._isEnded = false
this.dataList = []
},
reset() {
this.paginationInternal.current = 1
},
add(value, {
action,
showToast = true,
toastTitle,
success,
fail,
complete,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (needLoading) {
uni.showLoading({
title: loadingTitle
})
}
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
if (action) {
db = db.action(action)
}
db.collection(this.mainCollection).add(value).then((res) => {
success && success(res)
if (showToast) {
uni.showToast({
title: toastTitle || t('uniCloud.component.add.success')
})
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
remove(id, {
action,
success,
fail,
complete,
confirmTitle,
confirmContent,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (!id || !id.length) {
return
}
if (!needConfirm) {
this._execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle)
return
}
uni.showModal({
title: confirmTitle || t('uniCloud.component.remove.showModal.title'),
content: confirmContent || t('uniCloud.component.remove.showModal.content'),
showCancel: true,
success: (res) => {
if (!res.confirm) {
return
}
this._execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle)
}
})
},
update(id, value, {
action,
showToast = true,
toastTitle,
success,
fail,
complete,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (needLoading) {
uni.showLoading({
title: loadingTitle
})
}
let db = uniCloud.database(this.spaceInfo)
if (action) {
db = db.action(action)
}
return db.collection(this.mainCollection).doc(id).update(value).then((res) => {
success && success(res)
if (showToast) {
uni.showToast({
title: toastTitle || t('uniCloud.component.update.success')
})
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
getTemp(isTemp = true) {
let db = uniCloud.database(this.spaceInfo)
if (this.action) {
db = db.action(this.action)
}
db = db.collection(...this.collectionArgs)
if (this.foreignKey) {
db = db.foreignKey(this.foreignKey)
}
if (!(!this.where || !Object.keys(this.where).length)) {
db = db.where(this.where)
}
if (this.field) {
db = db.field(this.field)
}
if (this.groupby) {
db = db.groupBy(this.groupby)
}
if (this.groupField) {
db = db.groupField(this.groupField)
}
if (this.distinct === true) {
db = db.distinct()
}
if (this.orderby) {
db = db.orderBy(this.orderby)
}
const {
current,
size
} = this.paginationInternal
const getOptions = {}
if (this.getcount) {
getOptions.getCount = this.getcount
}
const treeOptions = {
limitLevel: this.limitlevel,
startWith: this.startwith
}
if (this.gettree) {
getOptions.getTree = treeOptions
}
if (this.gettreepath) {
getOptions.getTreePath = treeOptions
}
db = db.skip(size * (current - 1)).limit(size)
if (isTemp) {
db = db.getTemp(getOptions)
db.udb = this
} else {
db = db.get(getOptions)
}
return db
},
setResult(result) {
if (result.code === 0) {
this._execLoadDataSuccess(result)
} else {
this._execLoadDataFail(new Error(result.message))
}
},
_execLoadData(callback, clear) {
if (this.loading) {
return
}
this.loading = true
this.errorMessage = ''
return this._getExec().then((res) => {
this.loading = false
this._execLoadDataSuccess(res.result, callback, clear)
}).catch((err) => {
this.loading = false
this._execLoadDataFail(err, callback)
})
},
_execLoadDataSuccess(result, callback, clear) {
const {
data,
count
} = result
this._isEnded = count !== undefined ? (this.paginationInternal.current * this.paginationInternal.size >= count) : (data.length < this.pageSize)
this.hasMore = !this._isEnded
const data2 = this.getone ? (data.length ? data[0] : undefined) : data
if (this.getcount) {
this.paginationInternal.count = count
}
callback && callback(data2, this._isEnded, this.paginationInternal)
this._dispatchEvent(events.load, data2)
if (this.getone || this.pageData === pageMode.replace) {
this.dataList = data2
} else {
if (clear) {
this.dataList = data2
} else {
this.dataList.push(...data2)
}
}
},
_execLoadDataFail(err, callback) {
this.errorMessage = err
callback && callback()
this.$emit(events.error, err)
if (process.env.NODE_ENV === 'development') {
console.error(err)
}
},
_getExec() {
return this.getTemp(false)
},
_execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle) {
if (!this.collection || !id) {
return
}
const ids = isArray(id) ? id : [id]
if (!ids.length) {
return
}
if (needLoading) {
uni.showLoading({
mask: true,
title: loadingTitle
})
}
const db = uniCloud.database(this.spaceInfo)
const dbCmd = db.command
let exec = db
if (action) {
exec = exec.action(action)
}
exec.collection(this.mainCollection).where({
_id: dbCmd.in(ids)
}).remove().then((res) => {
success && success(res.result)
if (this.pageData === pageMode.replace) {
this.refresh()
} else {
this.removeData(ids)
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
removeData(ids) {
const il = ids.slice(0)
const dl = this.dataList
for (let i = dl.length - 1; i >= 0; i--) {
const index = il.indexOf(dl[i]._id)
if (index >= 0) {
dl.splice(i, 1)
il.splice(index, 1)
}
}
},
_dispatchEvent(type, data) {
if (this._changeDataFunction) {
this._changeDataFunction(data, this._isEnded, this.paginationInternal)
} else {
this.$emit(type, data, this._isEnded, this.paginationInternal)
}
}
}
}
</script>
+1
View File
@@ -0,0 +1 @@
[https://dcloud.io/license/uni-app.html](https://dcloud.io/license/uni-app.html)
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@dcloudio/uni-components",
"version": "3.0.0-4030620241128001",
"description": "@dcloudio/uni-components",
"main": "index.js",
"files": [
"style",
"style-x",
"lib",
"lib-x"
],
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-components"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/dcloudio/uni-app/issues"
},
"gitHead": "33e807d66e1fe47e2ee08ad9c59247e37b8884da",
"dependencies": {
"@dcloudio/uni-cloud": "3.0.0-4030620241128001",
"@dcloudio/uni-h5": "3.0.0-4030620241128001",
"@dcloudio/uni-i18n": "3.0.0-4030620241128001"
},
"devDependencies": {
"@dcloudio/uni-shared": "3.0.0-4030620241128001",
"@types/quill": "1.3.10"
}
}
+79
View File
@@ -0,0 +1,79 @@
uni-slider {
display: block;
margin-top: 1px;
margin-bottom: 1px;
}
uni-slider[hidden] {
display: none;
}
uni-slider .uni-slider-browser-input-range {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
opacity: 0;
}
uni-slider .uni-slider-wrapper {
position: relative;
display: flex;
align-items: center;
min-height: 8px;
margin-top: 4px;
margin-bottom: 4px;
}
uni-slider .uni-slider-input {
position: relative;
flex: 1;
}
uni-slider .uni-slider-track {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin-top: auto;
margin-bottom: auto;
height: 2px;
border-radius: 5px;
background-color: #e9e9e9;
cursor: pointer;
transition: background-color 0.3s ease;
-webkit-tap-highlight-color: transparent;
}
uni-slider .uni-slider-track-value {
height: 100%;
border-radius: 6px;
background-color: #007aff;
transition: background-color 0.3s ease;
}
uni-slider .uni-slider-thumb-value {
position: relative;
cursor: pointer;
border-radius: 50%;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
transition: border-color 0.3s ease;
}
uni-slider .uni-slider-value {
width: 4ch;
color: #888;
font-size: 14px;
margin-left: 3px;
}
uni-slider .uni-slider-disabled .uni-slider-track {
background-color: #ccc;
}
uni-slider .uni-slider-disabled .uni-slider-thumb-value {
background-color: #fff;
border-color: #ccc;
}
+113
View File
@@ -0,0 +1,113 @@
uni-switch {
-webkit-tap-highlight-color: transparent;
display: inline-block;
cursor: pointer;
}
uni-switch[hidden] {
display: none;
}
uni-switch[disabled] {
cursor: not-allowed;
}
uni-switch[disabled] .uni-switch-input {
opacity: 0.7;
}
.uni-switch-wrapper {
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.uni-switch-input {
appearance: none;
position: relative;
width: 52px;
height: 32px;
margin-right: 5px;
border: 2px solid transparent;
outline: 0;
border-radius: 16px;
box-sizing: border-box;
background-color: #e9e9ea;
transition: background-color 0.1s, border 0.1s;
}
.uni-switch-input.uni-switch-input-checked {
border-color: #007aff;
background-color: #007aff;
}
uni-switch .uni-switch-thumb {
width: 28px;
height: 28px;
background-color: #fff;
border-radius: 15px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.06);
transition-duration: 0.3s;
transition-property: transform;
transform: translateX(0px);
overflow: visible;
}
uni-switch .uni-switch-thumb-checked {
transform: translateX(20px);
}
uni-switch .uni-checkbox-input {
margin-right: 5px;
appearance: none;
outline: 0;
border: 1px solid #d1d1d1;
background-color: #ffffff;
border-radius: 3px;
width: 22px;
height: 22px;
position: relative;
color: #007aff;
}
uni-switch:not([disabled]) .uni-checkbox-input:hover {
border-color: #007aff;
}
uni-switch .uni-checkbox-input svg {
fill: #007aff;
font-size: 22px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -48%) scale(0.73);
}
.uni-checkbox-input.uni-checkbox-input-disabled {
background-color: #e1e1e1;
}
.uni-checkbox-input.uni-checkbox-input-disabled:before {
color: #adadad;
}
@media (prefers-color-scheme: dark) {
uni-switch .uni-switch-input {
border-color: #3b3b3f;
}
uni-switch .uni-switch-input,
uni-switch .uni-switch-input:before {
background-color: #3b3b3f;
}
uni-switch .uni-switch-input:after {
background-color: #fff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
uni-switch .uni-checkbox-input {
background-color: #2c2c2c;
border: 1px solid #656565;
}
}
+305
View File
@@ -0,0 +1,305 @@
uni-button {
position: relative;
display: block;
margin-left: auto;
margin-right: auto;
padding-left: 14px;
padding-right: 14px;
box-sizing: border-box;
font-size: 18px;
text-align: center;
text-decoration: none;
line-height: 2.55555556;
border-radius: 5px;
-webkit-tap-highlight-color: transparent;
overflow: hidden;
color: #000000;
background-color: #f8f8f8;
cursor: pointer;
}
uni-button[hidden] {
display: none !important;
}
uni-button:after {
content: ' ';
width: 200%;
height: 200%;
position: absolute;
top: 0;
left: 0;
border: 1px solid rgba(0, 0, 0, 0.2);
transform: scale(0.5);
transform-origin: 0 0;
box-sizing: border-box;
border-radius: 10px;
}
uni-button[native] {
padding-left: 0;
padding-right: 0;
}
uni-button[native] .uni-button-cover-view-wrapper {
border: inherit;
border-color: inherit;
border-radius: inherit;
background-color: inherit;
}
uni-button[native] .uni-button-cover-view-inner {
padding-left: 14px;
padding-right: 14px;
}
uni-button uni-cover-view {
line-height: inherit;
white-space: inherit;
}
uni-button[type='default'] {
color: #000000;
background-color: #f8f8f8;
}
uni-button[type='primary'] {
color: #ffffff;
background-color: #007aff;
}
uni-button[type='warn'] {
color: #ffffff;
background-color: #e64340;
}
uni-button[disabled] {
color: rgba(255, 255, 255, 0.6);
cursor: not-allowed;
}
uni-button[disabled][type='default'],
uni-button[disabled]:not([type]) {
color: rgba(0, 0, 0, 0.3);
background-color: #f7f7f7;
}
uni-button[disabled][type='primary'] {
background-color: rgba(0, 122, 255, 0.6);
}
uni-button[disabled][type='warn'] {
background-color: #ec8b89;
}
uni-button[type='primary'][plain] {
color: #007aff;
border: 1px solid #007aff;
background-color: transparent;
}
uni-button[type='primary'][plain][disabled] {
color: rgba(0, 0, 0, 0.2);
border-color: rgba(0, 0, 0, 0.2);
}
uni-button[type='primary'][plain]:after {
border-width: 0;
}
uni-button[type='default'][plain] {
color: #353535;
border: 1px solid #353535;
background-color: transparent;
}
uni-button[type='default'][plain][disabled] {
color: rgba(0, 0, 0, 0.2);
border-color: rgba(0, 0, 0, 0.2);
}
uni-button[type='default'][plain]:after {
border-width: 0;
}
uni-button[plain] {
color: #353535;
border: 1px solid #353535;
background-color: transparent;
}
uni-button[plain][disabled] {
color: rgba(0, 0, 0, 0.2);
border-color: rgba(0, 0, 0, 0.2);
}
uni-button[plain]:after {
border-width: 0;
}
uni-button[plain][native] .uni-button-cover-view-inner {
padding: 0;
}
uni-button[type='warn'][plain] {
color: #e64340;
border: 1px solid #e64340;
background-color: transparent;
}
uni-button[type='warn'][plain][disabled] {
color: rgba(0, 0, 0, 0.2);
border-color: rgba(0, 0, 0, 0.2);
}
uni-button[type='warn'][plain]:after {
border-width: 0;
}
uni-button[size='mini'] {
display: inline-block;
line-height: 2.3;
font-size: 13px;
padding: 0 1.34em;
}
uni-button[size='mini'][native] {
padding: 0;
}
uni-button[size='mini'][native] .uni-button-cover-view-inner {
padding: 0 1.34em;
}
uni-button[loading]:not([disabled]) {
cursor: progress;
}
uni-button[loading]:before {
content: ' ';
display: inline-block;
width: 18px;
height: 18px;
vertical-align: middle;
animation: uni-loading 1s steps(12, end) infinite;
background-size: 100%;
}
uni-button[loading][type='primary'] {
color: rgba(255, 255, 255, 0.6);
background-color: #0062cc;
}
uni-button[loading][type='primary'][plain] {
color: #007aff;
background-color: transparent;
}
uni-button[loading][type='default'] {
color: rgba(0, 0, 0, 0.6);
background-color: #dedede;
}
uni-button[loading][type='default'][plain] {
color: #353535;
background-color: transparent;
}
uni-button[loading][type='warn'] {
color: rgba(255, 255, 255, 0.6);
background-color: #ce3c39;
}
uni-button[loading][type='warn'][plain] {
color: #e64340;
background-color: transparent;
}
uni-button[loading][native]:before {
content: none;
}
.button-hover {
color: rgba(0, 0, 0, 0.6);
background-color: #dedede;
}
.button-hover[plain] {
color: rgba(53, 53, 53, 0.6);
border-color: rgba(53, 53, 53, 0.6);
background-color: transparent;
}
.button-hover[type='primary'] {
color: rgba(255, 255, 255, 0.6);
background-color: #0062cc;
}
.button-hover[type='primary'][plain] {
color: rgba(0, 122, 255, 0.6);
border-color: rgba(0, 122, 255, 0.6);
background-color: transparent;
}
.button-hover[type='default'] {
color: rgba(0, 0, 0, 0.6);
background-color: #dedede;
}
.button-hover[type='default'][plain] {
color: rgba(53, 53, 53, 0.6);
border-color: rgba(53, 53, 53, 0.6);
background-color: transparent;
}
.button-hover[type='warn'] {
color: rgba(255, 255, 255, 0.6);
background-color: #ce3c39;
}
.button-hover[type='warn'][plain] {
color: rgba(230, 67, 64, 0.6);
border-color: rgba(230, 67, 64, 0.6);
background-color: transparent;
}
@media (prefers-color-scheme: dark) {
uni-button,
uni-button[type='default'] {
color: #d6d6d6;
background-color: #343434;
}
.button-hover,
.button-hover[type='default'] {
color: #d6d6d6;
background-color: rgba(255, 255, 255, 0.1);
}
uni-button[disabled][type='default'],
uni-button[disabled]:not([type]) {
color: rgba(255, 255, 255, 0.2);
background-color: rgba(255, 255, 255, 0.08);
}
uni-button[type='primary'][plain][disabled] {
color: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.2);
}
uni-button[type='default'][plain] {
color: #d6d6d6;
border: 1px solid #d6d6d6;
}
.button-hover[type='default'][plain] {
color: rgba(150, 150, 150, 0.6);
border-color: rgba(150, 150, 150, 0.6);
background-color: rgba(50, 50, 50, 0.2);
}
uni-button[type='default'][plain][disabled] {
border-color: hsla(0, 0%, 100%, 0.2);
color: hsla(0, 0%, 100%, 0.2);
}
}
+14
View File
@@ -0,0 +1,14 @@
uni-canvas {
width: 300px;
height: 150px;
display: block;
position: relative;
}
uni-canvas > .uni-canvas-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
+7
View File
@@ -0,0 +1,7 @@
uni-checkbox-group {
display: block;
}
uni-checkbox-group[hidden] {
display: none;
}
+58
View File
@@ -0,0 +1,58 @@
uni-checkbox {
-webkit-tap-highlight-color: transparent;
display: inline-block;
cursor: pointer;
}
uni-checkbox[hidden] {
display: none;
}
uni-checkbox[disabled] {
cursor: not-allowed;
}
.uni-checkbox-wrapper {
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.uni-checkbox-input {
margin-right: 5px;
appearance: none;
outline: 0;
border: 1px solid #d1d1d1;
background-color: #ffffff;
border-radius: 3px;
width: 22px;
height: 22px;
position: relative;
}
.uni-checkbox-input svg {
color: #007aff;
font-size: 22px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -48%) scale(0.73);
}
@media (hover: hover) {
uni-checkbox:not([disabled]) .uni-checkbox-input:hover {
border-color: var(--HOVER-BD-COLOR, #007aff) !important;
}
}
.uni-checkbox-input.uni-checkbox-input-disabled {
background-color: #e1e1e1;
}
.uni-checkbox-input.uni-checkbox-input-disabled:before {
color: #adadad;
}
uni-checkbox-group {
display: block;
}
+393
View File
@@ -0,0 +1,393 @@
.ql-container {
display: block;
position: relative;
box-sizing: border-box;
user-select: text;
outline: none;
overflow: hidden;
width: 100%;
height: 200px;
min-height: 200px;
}
.ql-container[hidden] {
display: none;
}
.ql-container .ql-editor {
position: relative;
font-size: inherit;
line-height: inherit;
font-family: inherit;
min-height: inherit;
width: 100%;
height: 100%;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-overflow-scrolling: touch;
}
.ql-container .ql-editor::-webkit-scrollbar {
width: 0 !important;
}
.ql-container .ql-editor.scroll-disabled {
overflow: hidden;
}
.ql-container .ql-image-overlay {
display: flex;
position: absolute;
box-sizing: border-box;
border: 1px dashed #ccc;
justify-content: center;
align-items: center;
user-select: none;
}
.ql-container .ql-image-overlay .ql-image-size {
position: absolute;
padding: 4px 8px;
text-align: center;
background-color: #fff;
color: #888;
border: 1px solid #ccc;
box-sizing: border-box;
opacity: 0.8;
right: 4px;
top: 4px;
font-size: 12px;
display: inline-block;
width: auto;
}
.ql-container .ql-image-overlay .ql-image-toolbar {
position: relative;
text-align: center;
box-sizing: border-box;
background: #000;
border-radius: 5px;
color: #fff;
font-size: 0;
min-height: 24px;
z-index: 100;
}
.ql-container .ql-image-overlay .ql-image-toolbar span {
display: inline-block;
cursor: pointer;
padding: 5px;
font-size: 12px;
border-right: 1px solid #fff;
}
.ql-container .ql-image-overlay .ql-image-toolbar span:last-child {
border-right: 0;
}
.ql-container .ql-image-overlay .ql-image-toolbar span.triangle-up {
padding: 0;
position: absolute;
top: -12px;
left: 50%;
transform: translatex(-50%);
width: 0;
height: 0;
border-width: 6px;
border-style: solid;
border-color: transparent transparent black transparent;
}
.ql-container .ql-image-overlay .ql-image-handle {
position: absolute;
height: 12px;
width: 12px;
border-radius: 50%;
border: 1px solid #ccc;
box-sizing: border-box;
background: #fff;
}
.ql-container img {
display: inline-block;
max-width: 100%;
}
.ql-clipboard p {
margin: 0;
padding: 0;
}
.ql-editor {
box-sizing: border-box;
height: 100%;
outline: none;
overflow-y: auto;
tab-size: 4;
-moz-tab-size: 4;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
.ql-editor > * {
cursor: text;
}
.ql-editor p,
.ql-editor ol,
.ql-editor ul,
.ql-editor pre,
.ql-editor blockquote,
.ql-editor h1,
.ql-editor h2,
.ql-editor h3,
.ql-editor h4,
.ql-editor h5,
.ql-editor h6 {
margin: 0;
padding: 0;
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol > li,
.ql-editor ul > li {
list-style-type: none;
}
.ql-editor ul > li::before {
content: '\2022';
}
.ql-editor ul[data-checked=true],
.ql-editor ul[data-checked=false] {
pointer-events: none;
}
.ql-editor ul[data-checked=true] > li *,
.ql-editor ul[data-checked=false] > li * {
pointer-events: all;
}
.ql-editor ul[data-checked=true] > li::before,
.ql-editor ul[data-checked=false] > li::before {
color: #777;
cursor: pointer;
pointer-events: all;
}
.ql-editor ul[data-checked=true] > li::before {
content: '\2611';
}
.ql-editor ul[data-checked=false] > li::before {
content: '\2610';
}
.ql-editor li::before {
display: inline-block;
white-space: nowrap;
width: 2em;
}
.ql-editor ol li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-0;
}
.ql-editor ol li:before {
content: counter(list-0, decimal) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-increment: list-1;
}
.ql-editor ol li.ql-indent-1:before {
content: counter(list-1, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-2 {
counter-increment: list-2;
}
.ql-editor ol li.ql-indent-2:before {
content: counter(list-2, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-2 {
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-3 {
counter-increment: list-3;
}
.ql-editor ol li.ql-indent-3:before {
content: counter(list-3, decimal) '. ';
}
.ql-editor ol li.ql-indent-3 {
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-4 {
counter-increment: list-4;
}
.ql-editor ol li.ql-indent-4:before {
content: counter(list-4, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-4 {
counter-reset: list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-5 {
counter-increment: list-5;
}
.ql-editor ol li.ql-indent-5:before {
content: counter(list-5, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-5 {
counter-reset: list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-6 {
counter-increment: list-6;
}
.ql-editor ol li.ql-indent-6:before {
content: counter(list-6, decimal) '. ';
}
.ql-editor ol li.ql-indent-6 {
counter-reset: list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-7 {
counter-increment: list-7;
}
.ql-editor ol li.ql-indent-7:before {
content: counter(list-7, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-7 {
counter-reset: list-8 list-9;
}
.ql-editor ol li.ql-indent-8 {
counter-increment: list-8;
}
.ql-editor ol li.ql-indent-8:before {
content: counter(list-8, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-8 {
counter-reset: list-9;
}
.ql-editor ol li.ql-indent-9 {
counter-increment: list-9;
}
.ql-editor ol li.ql-indent-9:before {
content: counter(list-9, decimal) '. ';
}
.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
padding-left: 2em;
}
.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
padding-left: 2em;
}
.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 2em;
}
.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 2em;
}
.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
padding-left: 4em;
}
.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
padding-left: 4em;
}
.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 4em;
}
.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 4em;
}
.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
padding-left: 8em;
}
.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
padding-left: 8em;
}
.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 8em;
}
.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 8em;
}
.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
padding-left: 10em;
}
.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
padding-left: 10em;
}
.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 10em;
}
.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 10em;
}
.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
padding-left: 14em;
}
.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
padding-left: 14em;
}
.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 14em;
}
.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 14em;
}
.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
padding-left: 16em;
}
.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
padding-left: 16em;
}
.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 16em;
}
.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 16em;
}
.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor .ql-direction-rtl {
direction: rtl;
text-align: inherit;
}
.ql-editor .ql-align-center {
text-align: center;
}
.ql-editor .ql-align-justify {
text-align: justify;
}
.ql-editor .ql-align-right {
text-align: right;
}
.ql-editor.ql-blank::before {
color: rgba(0, 0, 0, 0.6);
content: attr(data-placeholder);
font-style: italic;
pointer-events: none;
position: absolute;
}
.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
pointer-events: none;
}
.ql-clipboard {
left: -100000px;
height: 1px;
overflow-y: hidden;
position: absolute;
top: 50%;
}
View File
+9
View File
@@ -0,0 +1,9 @@
uni-icon {
display: inline-block;
font-size: 0;
box-sizing: border-box;
}
uni-icon[hidden] {
display: none;
}
+33
View File
@@ -0,0 +1,33 @@
uni-image {
width: 320px;
height: 240px;
display: inline-block;
overflow: hidden;
position: relative;
}
uni-image[hidden] {
display: none;
}
uni-image > div {
width: 100%;
height: 100%;
background-repeat:no-repeat;
}
uni-image > img {
-webkit-touch-callout: none;
user-select: none;
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
uni-image > .uni-image-will-change {
will-change: transform;
}
+87
View File
@@ -0,0 +1,87 @@
uni-input {
display: block;
font-size: 16px;
line-height: 1.4em;
height: 1.4em;
min-height: 1.4em;
overflow: hidden;
}
uni-input[hidden] {
display: none;
}
.uni-input-wrapper,
.uni-input-placeholder,
.uni-input-form,
.uni-input-input {
outline: none;
border: none;
padding: 0;
margin: 0;
text-decoration: inherit;
}
.uni-input-wrapper,
.uni-input-form {
display: flex;
position: relative;
width: 100%;
height: 100%;
flex-direction: column;
justify-content: center;
}
.uni-input-placeholder,
.uni-input-input {
width: 100%;
}
.uni-input-placeholder {
position: absolute;
top: auto !important;
left: 0;
color: gray;
overflow: hidden;
text-overflow: clip;
white-space: pre;
word-break: keep-all;
pointer-events: none;
line-height: inherit;
}
.uni-input-input {
position: relative;
display: block;
height: 100%;
background: none;
color: inherit;
opacity: 1;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
text-indent: inherit;
text-transform: inherit;
text-shadow: inherit;
}
.uni-input-input[type='search']::-webkit-search-cancel-button,
.uni-input-input[type="search"]::-webkit-search-decoration {
display: none;
}
.uni-input-input::-webkit-outer-spin-button,
.uni-input-input::-webkit-inner-spin-button {
appearance: none;
margin: 0;
}
.uni-input-input[type='number'] {
-moz-appearance: textfield;
}
.uni-input-input:disabled {
/* 用于重置iOS14以下禁用状态文字颜色 */
-webkit-text-fill-color: currentcolor;
}
+3
View File
@@ -0,0 +1,3 @@
.uni-label-pointer {
cursor: pointer;
}
+3
View File
@@ -0,0 +1,3 @@
uni-list-item {
display: block;
}
+28
View File
@@ -0,0 +1,28 @@
uni-list-view {
display: block;
width: 100%;
}
.uni-list-view-container {
position: relative;
-webkit-overflow-scrolling: touch;
width: 100%;
height: 100%;
}
.uni-list-view-content {
position: relative;
}
.uni-list-view-visible {
position: absolute;
}
.uni-list-view-scrollbar-hidden::-webkit-scrollbar {
display: none;
}
.uni-list-view-scrollbar-hidden {
-moz-scrollbars: none;
scrollbar-width: none;
}
+10
View File
@@ -0,0 +1,10 @@
uni-movable-area {
display: block;
position: relative;
width: 10px;
height: 10px;
}
uni-movable-area[hidden] {
display: none;
}
+13
View File
@@ -0,0 +1,13 @@
uni-movable-view {
display: inline-block;
width: 10px;
height: 10px;
top: 0px;
left: 0px;
position: absolute;
cursor: grab;
}
uni-movable-view[hidden] {
display: none;
}
+45
View File
@@ -0,0 +1,45 @@
uni-navigator {
height: auto;
width: auto;
display: block;
cursor: pointer;
}
uni-navigator[hidden] {
display: none;
}
.navigator-hover {
background-color: rgba(0, 0, 0, 0.1);
opacity: 0.7;
}
.navigator-wrap {
text-decoration: none;
color: inherit;
cursor: pointer;
}
.navigator-wrap:link {
text-decoration: none;
color: inherit;
cursor: pointer;
}
.navigator-wrap:visited {
text-decoration: none;
color: inherit;
cursor: pointer;
}
.navigator-wrap:hover {
text-decoration: none;
color: inherit;
cursor: pointer;
}
.navigator-wrap:active {
text-decoration: none;
color: inherit;
cursor: pointer;
}
+117
View File
@@ -0,0 +1,117 @@
uni-picker-view-column {
flex: 1;
position: relative;
height: 100%;
overflow: hidden;
}
uni-picker-view-column[hidden] {
display: none;
}
.uni-picker-view-group {
height: 100%;
overflow: hidden;
}
.uni-picker-view-mask {
transform: translateZ(0);
}
.uni-picker-view-indicator,
.uni-picker-view-mask {
position: absolute;
left: 0;
width: 100%;
z-index: 3;
pointer-events: none;
}
.uni-picker-view-mask {
top: 0;
height: 100%;
margin: 0 auto;
background-image: linear-gradient(
180deg,
hsla(0, 0%, 100%, 0.95),
hsla(0, 0%, 100%, 0.6)
),
linear-gradient(0deg, hsla(0, 0%, 100%, 0.95), hsla(0, 0%, 100%, 0.6));
background-position: top, bottom;
background-size: 100% 102px;
background-repeat: no-repeat;
transform: translateZ(0);
}
.uni-picker-view-indicator {
height: 34px;
/* top: 102px; */
top: 50%;
transform: translateY(-50%);
}
.uni-picker-view-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
will-change: transform;
padding: 102px 0;
cursor: pointer;
}
.uni-picker-view-content > * {
height: var(--picker-view-column-indicator-height);
overflow: hidden;
}
.uni-picker-view-indicator:after,
.uni-picker-view-indicator:before {
content: ' ';
position: absolute;
left: 0;
right: 0;
height: 1px;
color: #e5e5e5;
}
.uni-picker-view-indicator:before {
top: 0;
border-top: 1px solid #e5e5e5;
transform-origin: 0 0;
transform: scaleY(0.5);
}
.uni-picker-view-indicator:after {
bottom: 0;
border-bottom: 1px solid #e5e5e5;
transform-origin: 0 100%;
transform: scaleY(0.5);
}
.uni-picker-view-indicator:after,
.uni-picker-view-indicator:before {
content: ' ';
position: absolute;
left: 0;
right: 0;
height: 1px;
color: #e5e5e5;
}
@media (prefers-color-scheme: dark) {
.uni-picker-view-indicator:before {
border-top-color: var(--UI-FG-3);
}
.uni-picker-view-indicator:after {
border-bottom-color: var(--UI-FG-3);
}
.uni-picker-view-mask {
background-image: linear-gradient(
180deg,
rgba(35, 35, 35, 0.95),
rgba(35, 35, 35, 0.6)
),
linear-gradient(0deg, rgba(35, 35, 35, 0.95), rgba(35, 35, 35, 0.6));
}
}
+14
View File
@@ -0,0 +1,14 @@
uni-picker-view {
display: block;
}
.uni-picker-view-wrapper {
display: flex;
position: relative;
overflow: hidden;
height: 100%;
}
uni-picker-view[hidden] {
display: none;
}
+25
View File
@@ -0,0 +1,25 @@
uni-progress {
display: flex;
align-items: center;
}
uni-progress[hidden] {
display: none;
}
.uni-progress-bar {
flex: 1;
}
.uni-progress-inner-bar {
width: 0;
height: 100%;
}
.uni-progress-info {
margin-top: 0;
margin-bottom: 0;
min-width: 2em;
margin-left: 15px;
font-size: 16px;
}
+6
View File
@@ -0,0 +1,6 @@
uni-radio-group {
display: block;
}
uni-radio-group[hidden] {
display: none;
}
+55
View File
@@ -0,0 +1,55 @@
uni-radio {
-webkit-tap-highlight-color: transparent;
display: inline-block;
cursor: pointer;
}
uni-radio[hidden] {
display: none;
}
uni-radio[disabled] {
cursor: not-allowed;
}
.uni-radio-wrapper {
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.uni-radio-input {
appearance: none;
margin-right: 5px;
outline: 0;
border: 1px solid #d1d1d1;
background-color: #ffffff;
border-radius: 50%;
width: 22px;
height: 22px;
position: relative;
}
@media (hover: hover) {
uni-radio:not([disabled]) .uni-radio-input:hover {
border-color: var(--HOVER-BD-COLOR, #007aff) !important;
}
}
.uni-radio-input svg {
color: #ffffff;
font-size: 18px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -48%) scale(0.73);
}
.uni-radio-input.uni-radio-input-disabled {
background-color: #e1e1e1;
border-color: #d1d1d1;
}
.uni-radio-input.uni-radio-input-disabled svg{
color: #adadad;
}
+76
View File
@@ -0,0 +1,76 @@
.uni-scroll-view-refresher {
position: relative;
overflow: hidden;
flex-shrink: 0;
}
.uni-scroll-view-refresher-container {
position: absolute;
width: 100%;
bottom: 0;
display: flex;
flex-direction: column-reverse;
}
.uni-scroll-view-refresh {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.uni-scroll-view-refresh-inner {
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #fff;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.117647),
0 1px 4px rgba(0, 0, 0, 0.117647);
}
.uni-scroll-view-refresh__spinner {
transform-origin: center center;
animation: uni-scroll-view-refresh-rotate 2s linear infinite;
}
.uni-scroll-view-refresh__spinner > circle {
stroke: currentColor;
stroke-linecap: round;
animation: uni-scroll-view-refresh-dash 2s linear infinite;
}
@keyframes uni-scroll-view-refresh-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes uni-scroll-view-refresh-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
+33
View File
@@ -0,0 +1,33 @@
@keyframes once-show {
from {
top: 0;
}
}
uni-resize-sensor,
uni-resize-sensor > div {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
uni-resize-sensor {
display: block;
z-index: -1;
visibility: hidden;
animation: once-show 1ms;
}
uni-resize-sensor > div > div {
position: absolute;
left: 0;
top: 0;
}
uni-resize-sensor > div:first-child > div {
width: 100000px;
height: 100000px;
}
uni-resize-sensor > div:last-child > div {
width: 200%;
height: 200%;
}
View File
+31
View File
@@ -0,0 +1,31 @@
uni-scroll-view {
display: block;
width: 100%;
}
uni-scroll-view[hidden] {
display: none;
}
.uni-scroll-view {
position: relative;
-webkit-overflow-scrolling: touch;
width: 100%;
/* display: flex; 时在安卓下会导致scrollWidth和offsetWidth一样 */
height: 100%;
max-height: inherit;
}
.uni-scroll-view-scrollbar-hidden::-webkit-scrollbar {
display: none;
}
.uni-scroll-view-scrollbar-hidden {
-moz-scrollbars: none;
scrollbar-width: none;
}
.uni-scroll-view-content {
width: 100%;
height: 100%;
}
+89
View File
@@ -0,0 +1,89 @@
uni-slider {
margin: 10px 18px;
padding: 0;
display: block;
}
uni-slider[hidden] {
display: none;
}
uni-slider .uni-slider-wrapper {
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
min-height: 16px;
}
uni-slider .uni-slider-tap-area {
-webkit-flex: 1;
flex: 1;
padding: 8px 0;
}
uni-slider .uni-slider-handle-wrapper {
position: relative;
height: 2px;
border-radius: 5px;
background-color: #e9e9e9;
cursor: pointer;
transition: background-color 0.3s ease;
-webkit-tap-highlight-color: transparent;
}
uni-slider .uni-slider-track {
height: 100%;
border-radius: 6px;
background-color: #007aff;
transition: background-color 0.3s ease;
}
uni-slider .uni-slider-handle,
uni-slider .uni-slider-thumb {
position: absolute;
left: 50%;
top: 50%;
cursor: pointer;
border-radius: 50%;
transition: border-color 0.3s ease;
}
uni-slider .uni-slider-handle {
width: 28px;
height: 28px;
margin-top: -14px;
margin-left: -14px;
background-color: transparent;
z-index: 3;
cursor: grab;
}
uni-slider .uni-slider-thumb {
z-index: 2;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
}
uni-slider .uni-slider-step {
position: absolute;
width: 100%;
height: 2px;
background: transparent;
z-index: 1;
}
uni-slider .uni-slider-value {
width: 3ch;
color: #888;
font-size: 14px;
margin-left: 1em;
}
uni-slider .uni-slider-disabled .uni-slider-track {
background-color: #ccc;
}
uni-slider .uni-slider-disabled .uni-slider-thumb {
background-color: #fff;
border-color: #ccc;
}
+6
View File
@@ -0,0 +1,6 @@
uni-sticky-header {
position: -webkit-sticky !important;
position: sticky !important;
top: 0px;
z-index: 1;
}
+3
View File
@@ -0,0 +1,3 @@
uni-sticky-section {
display: flex;
}
+13
View File
@@ -0,0 +1,13 @@
uni-swiper-item {
display: block;
overflow: hidden;
will-change: transform;
position: absolute;
width: 100%;
height: 100%;
cursor: grab;
}
uni-swiper-item[hidden] {
display: none;
}
+151
View File
@@ -0,0 +1,151 @@
uni-swiper {
display: block;
height: 150px;
}
uni-swiper[hidden] {
display: none;
}
.uni-swiper-wrapper {
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
transform: translateZ(0);
}
.uni-swiper-slides {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.uni-swiper-slide-frame {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
will-change: transform;
}
.uni-swiper-dots {
position: absolute;
font-size: 0;
}
.uni-swiper-dots-horizontal {
left: 50%;
bottom: 10px;
text-align: center;
white-space: nowrap;
transform: translate(-50%, 0);
}
.uni-swiper-dots-horizontal .uni-swiper-dot {
margin-right: 8px;
}
.uni-swiper-dots-horizontal .uni-swiper-dot:last-child {
margin-right: 0;
}
.uni-swiper-dots-vertical {
right: 10px;
top: 50%;
text-align: right;
transform: translate(0, -50%);
}
.uni-swiper-dots-vertical .uni-swiper-dot {
display: block;
margin-bottom: 9px;
}
.uni-swiper-dots-vertical .uni-swiper-dot:last-child {
margin-bottom: 0;
}
.uni-swiper-dot {
display: inline-block;
width: 8px;
height: 8px;
cursor: pointer;
transition-property: background-color;
transition-timing-function: ease;
background: rgba(0, 0, 0, 0.3);
border-radius: 50%;
}
.uni-swiper-dot-active {
background-color: #000000;
}
.uni-swiper-navigation {
width: 26px;
height: 26px;
cursor: pointer;
position: absolute;
top: 50%;
margin-top: -13px;
display: flex;
align-items: center;
transition: all 0.2s;
border-radius: 50%;
opacity: 1;
}
.uni-swiper-navigation-disabled {
opacity: 0.35;
cursor: not-allowed;
}
.uni-swiper-navigation-hide {
opacity: 0;
cursor: auto;
pointer-events: none;
}
.uni-swiper-navigation-prev {
left: 10px;
}
.uni-swiper-navigation-prev svg {
margin-left: -1px;
left: 10px;
}
.uni-swiper-navigation-prev.uni-swiper-navigation-vertical {
top: 18px;
left: 50%;
margin-left: -13px;
}
.uni-swiper-navigation-prev.uni-swiper-navigation-vertical svg {
transform: rotate(90deg);
margin-left: auto;
margin-top: -2px;
}
.uni-swiper-navigation-next {
right: 10px;
}
.uni-swiper-navigation-next svg {
transform: rotate(180deg);
}
.uni-swiper-navigation-next.uni-swiper-navigation-vertical {
top: auto;
bottom: 5px;
left: 50%;
margin-left: -13px;
}
.uni-swiper-navigation-next.uni-swiper-navigation-vertical svg {
margin-top: 2px;
transform: rotate(270deg);
}
+132
View File
@@ -0,0 +1,132 @@
uni-switch {
-webkit-tap-highlight-color: transparent;
display: inline-block;
cursor: pointer;
}
uni-switch[hidden] {
display: none;
}
uni-switch[disabled] {
cursor: not-allowed;
}
uni-switch[disabled] .uni-switch-input {
opacity: 0.7;
}
.uni-switch-wrapper {
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.uni-switch-input {
appearance: none;
position: relative;
width: 52px;
height: 32px;
margin-right: 5px;
border: 1px solid #dfdfdf;
outline: 0;
border-radius: 16px;
box-sizing: border-box;
background-color: #dfdfdf;
transition: background-color 0.1s, border 0.1s;
}
.uni-switch-input:before {
content: ' ';
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 30px;
border-radius: 15px;
background-color: #fdfdfd;
transition: transform 0.3s;
}
.uni-switch-input:after {
content: ' ';
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 30px;
border-radius: 15px;
background-color: #ffffff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
}
.uni-switch-input.uni-switch-input-checked {
border-color: #007aff;
background-color: #007aff;
}
.uni-switch-input.uni-switch-input-checked:before {
transform: scale(0);
}
.uni-switch-input.uni-switch-input-checked:after {
transform: translateX(20px);
}
uni-switch .uni-checkbox-input {
margin-right: 5px;
appearance: none;
outline: 0;
border: 1px solid #d1d1d1;
background-color: #ffffff;
border-radius: 3px;
width: 22px;
height: 22px;
position: relative;
color: #007aff;
}
uni-switch:not([disabled]) .uni-checkbox-input:hover {
border-color: #007aff;
}
uni-switch .uni-checkbox-input svg {
fill: #007aff;
font-size: 22px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -48%) scale(0.73);
}
.uni-checkbox-input.uni-checkbox-input-disabled {
background-color: #e1e1e1;
}
.uni-checkbox-input.uni-checkbox-input-disabled:before {
color: #adadad;
}
@media (prefers-color-scheme: dark) {
uni-switch .uni-switch-input {
border-color: #3b3b3f;
}
uni-switch .uni-switch-input,
uni-switch .uni-switch-input:before {
background-color: #3b3b3f;
}
uni-switch .uni-switch-input:after {
background-color: #fff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
uni-switch .uni-checkbox-input {
background-color: #2c2c2c;
border: 1px solid #656565;
}
}
+8
View File
@@ -0,0 +1,8 @@
uni-text[selectable] {
cursor: auto;
user-select: text;
}
uni-text {
white-space: pre-line;
}
+79
View File
@@ -0,0 +1,79 @@
uni-textarea {
width: 300px;
height: 150px;
display: block;
position: relative;
font-size: 16px;
line-height: normal;
white-space: pre-wrap;
word-break: break-all;
}
uni-textarea[hidden] {
display: none;
}
.uni-textarea-wrapper,
.uni-textarea-placeholder,
.uni-textarea-line,
.uni-textarea-compute,
.uni-textarea-textarea {
outline: none;
border: none;
padding: 0;
margin: 0;
text-decoration: inherit;
}
.uni-textarea-wrapper {
display: block;
position: relative;
width: 100%;
height: 100%;
min-height: inherit;
overflow-y: hidden;
}
.uni-textarea-placeholder,
.uni-textarea-line,
.uni-textarea-compute,
.uni-textarea-textarea {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
white-space: inherit;
word-break: inherit;
}
.uni-textarea-placeholder {
color: grey;
overflow: hidden;
}
.uni-textarea-line,
.uni-textarea-compute {
visibility: hidden;
height: auto;
}
.uni-textarea-line {
width: 1em;
}
.uni-textarea-textarea {
resize: none;
background: none;
color: inherit;
opacity: 1;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
text-indent: inherit;
text-transform: inherit;
text-shadow: inherit;
}
/* 用于解决 iOS textarea 内部默认边距 */
.uni-textarea-textarea-fix-margin {
width: auto;
right: 0;
margin: 0 -3px;
}
.uni-textarea-textarea:disabled {
/* 用于重置iOS14以下禁用状态文字颜色 */
-webkit-text-fill-color: currentcolor;
}
+6
View File
@@ -0,0 +1,6 @@
uni-view {
display: block;
}
uni-view[hidden] {
display: none;
}