完善培训内容
This commit is contained in:
@ -1,12 +0,0 @@
|
|||||||
import { http } from '@/http/alova'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取首页轮播图
|
|
||||||
*/
|
|
||||||
export function getHomeBannerList() {
|
|
||||||
return http.Post<{ list: Array<{ address: string;}> }>('/api/index/carouselLists', null,
|
|
||||||
{
|
|
||||||
meta: { ignoreAuth: true }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -309,9 +309,34 @@ export function addStoreQual(data: IAddStoreQualiParams) {
|
|||||||
return http.Post('/storeapi/store/addQual', data)
|
return http.Post('/storeapi/store/addQual', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑门店资质信息
|
||||||
|
*/
|
||||||
|
export interface IEditStoreQualiParams extends IAddStoreQualiParams {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editStoreQual(data: IEditStoreQualiParams) {
|
||||||
|
return http.Post('/storeapi/store/editQual', data)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取门店资质信息
|
* 获取门店资质信息
|
||||||
*/
|
*/
|
||||||
export function getStoreQual(store_id: number) {
|
export function getStoreQual(store_id: number) {
|
||||||
return http.Post<any>('/storeapi/store/qualDetails', { store_id })
|
return http.Post<any>('/storeapi/store/qualDetails', { store_id })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商家培训
|
||||||
|
*/
|
||||||
|
export function getTeachingList(data: {page: number, size: number, search: string}) {
|
||||||
|
return http.Post<any>('/storeapi/training/trainingList', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 培训详情
|
||||||
|
*/
|
||||||
|
export function getTeachingDetail(id: number) {
|
||||||
|
return http.Post<any>('/storeapi/training/trainingDetails', { id })
|
||||||
}
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="pb-100rpx">
|
<view class="pb-100rpx">
|
||||||
<navbar title="添加资质信息" custom-class='!bg-[#F6F7F8]'></navbar>
|
<navbar :title="title" custom-class='!bg-[#F6F7F8]'></navbar>
|
||||||
|
|
||||||
<view class="mx-30rpx bg-white rounded-16rpx py-26rpx px-30rpx mt-38rpx">
|
<view class="mx-30rpx bg-white rounded-16rpx py-26rpx px-30rpx mt-38rpx">
|
||||||
<view class="flex items-center">
|
<view class="flex items-center">
|
||||||
@ -104,90 +104,113 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { addStoreQual, type IAddStoreQualiParams } from '@/api/store'
|
import { addStoreQual, type IAddStoreQualiParams, getStoreQual, editStoreQual } from '@/api/store'
|
||||||
import { useToast } from 'wot-design-uni'
|
import { useToast } from 'wot-design-uni'
|
||||||
import { useStoreStore } from '@/store'
|
import { useStoreStore } from '@/store'
|
||||||
import { router, removeImageUrlPrefix } from '@/utils/tools'
|
import { router, removeImageUrlPrefix } from '@/utils/tools'
|
||||||
|
|
||||||
const useStore = useStoreStore()
|
const useStore = useStoreStore()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
store_id: 0,
|
store_id: 0,
|
||||||
card: '', // 证件号码
|
card: '', // 证件号码
|
||||||
name: '', // 企业名称
|
name: '', // 企业名称
|
||||||
legal_person: '', // 法定代表
|
legal_person: '', // 法定代表
|
||||||
operation_type: 1, // 有效期 1-长期 2-非长期
|
operation_type: 1, // 有效期 1-长期 2-非长期
|
||||||
start_time: '',
|
start_time: '',
|
||||||
end_time: ''
|
end_time: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const token = ref<string>('') // 用户token
|
const token = ref<string>('') // 用户token
|
||||||
const OSS = inject('OSS')
|
const OSS = inject('OSS')
|
||||||
const startTime = ref<number>(Date.now())
|
const startTime = ref<number>(Date.now())
|
||||||
const endTime = ref<number>(Date.now())
|
const endTime = ref<number>(Date.now())
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
const fileList = ref<any[]>([]) // 营业执照
|
const fileList = ref<any[]>([]) // 营业执照
|
||||||
const action = import.meta.env.VITE_UPLOAD_BASEURL
|
const action = import.meta.env.VITE_UPLOAD_BASEURL
|
||||||
|
|
||||||
onLoad((options) => {
|
const id = ref<number>(0)
|
||||||
token.value = uni.getStorageSync('token')
|
const title = ref<string>('添加经营资质')
|
||||||
|
|
||||||
if (options && options.store_id) {
|
onLoad((args) => {
|
||||||
form.store_id = Number(options.store_id)
|
token.value = uni.getStorageSync('token')
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const Add = {
|
if (args && args.id) {
|
||||||
handleAddConfirmTime: (date: {value: number}) => {
|
id.value = Number(args.id)
|
||||||
form.start_time = Add.handleFormatTime(date.value)
|
title.value = '编辑经营资质'
|
||||||
},
|
Add.handleGetDetail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
handleEndConfirmTime: (date: {value: number}) => {
|
const Add = {
|
||||||
form.end_time = Add.handleFormatTime(date.value)
|
handleGetDetail: async () => {
|
||||||
},
|
const res = await getStoreQual(useStore.defaultStore.id)
|
||||||
|
const details = res.details
|
||||||
|
form.card = details.card
|
||||||
|
form.name = details.name
|
||||||
|
form.legal_person = details.legal_person
|
||||||
|
form.operation_type = details.effective
|
||||||
|
form.start_time = details.start_time
|
||||||
|
form.end_time = details.end_time
|
||||||
|
fileList.value = [{url: details.license_img, name: 'license.jpg'}]
|
||||||
|
},
|
||||||
|
|
||||||
handleFormatTime: (value: any) => {
|
handleAddConfirmTime: (date: {value: number}) => {
|
||||||
const d = new Date(value)
|
form.start_time = Add.handleFormatTime(date.value)
|
||||||
const year = d.getFullYear()
|
},
|
||||||
const month = (d.getMonth() + 1).toString().padStart(2, '0')
|
|
||||||
const day = d.getDate().toString().padStart(2, '0')
|
|
||||||
return `${year}-${month}-${day}`
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSubmit: async () => {
|
handleEndConfirmTime: (date: {value: number}) => {
|
||||||
if (!form.card) return toast.error('请输入证件号码')
|
form.end_time = Add.handleFormatTime(date.value)
|
||||||
if (!form.name) return toast.error('请输入企业名称')
|
},
|
||||||
if (!form.legal_person) return toast.error('请输入法人名称')
|
|
||||||
if (form.operation_type === 2) {
|
|
||||||
if (!form.start_time) return toast.error('请选择起始日期')
|
|
||||||
if (!form.end_time) return toast.error('请选择截止日期')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileList.value.length === 0) return toast.error('请上传营业执照')
|
handleFormatTime: (value: any) => {
|
||||||
|
const d = new Date(value)
|
||||||
const params: IAddStoreQualiParams = {
|
const year = d.getFullYear()
|
||||||
store_id: useStore.defaultStore.id,
|
const month = (d.getMonth() + 1).toString().padStart(2, '0')
|
||||||
name: form.name,
|
const day = d.getDate().toString().padStart(2, '0')
|
||||||
card: form.card,
|
return `${year}-${month}-${day}`
|
||||||
legal_person: form.legal_person,
|
},
|
||||||
license_img: removeImageUrlPrefix(fileList.value)[0],
|
|
||||||
effective: form.operation_type,
|
|
||||||
start_time: form.operation_type === 1 ? '' : form.start_time,
|
|
||||||
end_time: form.operation_type === 1 ? '' : form.end_time
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
handleSubmit: async () => {
|
||||||
await addStoreQual(params)
|
if (!form.card) return toast.error('请输入证件号码')
|
||||||
setTimeout(() => {
|
if (!form.name) return toast.error('请输入企业名称')
|
||||||
router.reLaunch('/pages/my/my')
|
if (!form.legal_person) return toast.error('请输入法人名称')
|
||||||
}, 1000)
|
if (form.operation_type === 2) {
|
||||||
} catch (e) {
|
if (!form.start_time) return toast.error('请选择起始日期')
|
||||||
console.error(e)
|
if (!form.end_time) return toast.error('请选择截止日期')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileList.value.length === 0) return toast.error('请上传营业执照')
|
||||||
|
|
||||||
|
const params: any = {
|
||||||
|
store_id: useStore.defaultStore.id,
|
||||||
|
name: form.name,
|
||||||
|
card: form.card,
|
||||||
|
legal_person: form.legal_person,
|
||||||
|
license_img: removeImageUrlPrefix(fileList.value)[0],
|
||||||
|
effective: form.operation_type,
|
||||||
|
start_time: form.operation_type === 1 ? '' : form.start_time,
|
||||||
|
end_time: form.operation_type === 1 ? '' : form.end_time
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (id.value) {
|
||||||
|
// 编辑
|
||||||
|
params.id = id.value
|
||||||
|
await editStoreQual(params)
|
||||||
|
} else {
|
||||||
|
await addStoreQual(params)
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
router.reLaunch('/pages/my/my')
|
||||||
|
}, 1000)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@ -11,8 +11,13 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="flex flex-col min-h-screen">
|
<view class="flex flex-col min-h-screen">
|
||||||
<view class="bg-[#fff] mt-28rpx px-30rpx">
|
<view class="bg-[#fff] pt-28rpx px-30rpx">
|
||||||
<view class="font-800 text-36rpx text-[#303133] leading-50rpx">经营资质</view>
|
<view class="font-800 text-36rpx text-[#303133] leading-50rpx flex items-center">
|
||||||
|
<view class="mr-20rpx">经营资质</view>
|
||||||
|
<view @click="router.navigateTo(`/bundle/store-license/add?id=${licenses.id}`)">
|
||||||
|
<wd-icon name="edit-outline" size="32rpx"></wd-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="flex items-center mt-28rpx text-28rpx leading-40rpx">
|
<view class="flex items-center mt-28rpx text-28rpx leading-40rpx">
|
||||||
<view class="mr-20rpx text-[#606266]">证件号码:</view>
|
<view class="mr-20rpx text-[#606266]">证件号码:</view>
|
||||||
<view class="text-[#303133]">{{ licenses.card }}</view>
|
<view class="text-[#303133]">{{ licenses.card }}</view>
|
||||||
@ -29,7 +34,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="flex items-center mt-28rpx text-28rpx leading-40rpx">
|
<view class="flex items-center mt-28rpx text-28rpx leading-40rpx">
|
||||||
<view class="mr-20rpx text-[#606266]">有效期至:{{ licenses.effective == 1 ? '有效期至:永久有效' : licenses.end_time }}</view>
|
<view class="mr-20rpx text-[#606266]">有效期至:{{ licenses.effective == 1 ? '永久有效' : licenses.end_time }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="mt-24rpx mb-34rpx">
|
<view class="mt-24rpx mb-34rpx">
|
||||||
@ -47,12 +52,19 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getStoreQual } from '@/api/store'
|
import { getStoreQual } from '@/api/store'
|
||||||
import { useStoreStore } from '@/store'
|
import { useStoreStore } from '@/store'
|
||||||
import type { IAddStoreQualiParams } from '@/api/store'
|
import { previewImage, router } from '@/utils/tools'
|
||||||
import { previewImage } from '@/utils/tools'
|
|
||||||
|
|
||||||
const useStore = useStoreStore()
|
const useStore = useStoreStore()
|
||||||
|
|
||||||
const licenses = ref<IAddStoreQualiParams>()
|
const licenses = ref({
|
||||||
|
id: 0,
|
||||||
|
card: '', // 证件号码
|
||||||
|
name: '', // 企业名称
|
||||||
|
legal_person: '', // 法定代表
|
||||||
|
effective: 0, // 有效期 1-长期 2-非长期
|
||||||
|
end_time: '', // 结束时间
|
||||||
|
license_img: '' // 营业执照图片地址
|
||||||
|
})
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getStoreQual(useStore.defaultStore.id).then(res => {
|
getStoreQual(useStore.defaultStore.id).then(res => {
|
||||||
|
|||||||
56
src/bundle/teaching/detail.vue
Normal file
56
src/bundle/teaching/detail.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<route lang="jsonc" type="page">{
|
||||||
|
"needLogin": true,
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
}</route>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="">
|
||||||
|
<navbar title="详情" custom-class="!bg-[#fff]"></navbar>
|
||||||
|
|
||||||
|
<view class="mt-36rpx mx-40rpx">
|
||||||
|
<view class="text-36rpx font-500 text-[#333] leading-56rpx">{{ detail.title }}</view>
|
||||||
|
<view class="mt-20rpx text-[#9A9A9A] text-24rpx font-400">{{ detail.admin_name }} | {{ detail.dtime }}</view>
|
||||||
|
<view class="mt-30rpx">
|
||||||
|
<wd-img width="670rpx" height="320rpx" radius="16rpx" :src="detail.image" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
<view class="mt-40rpx">
|
||||||
|
<uv-parse :content="detail.content"></uv-parse>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { getTeachingDetail } from '@/api/store'
|
||||||
|
|
||||||
|
const detail = ref<any>({
|
||||||
|
title: '',
|
||||||
|
admin_name: '',
|
||||||
|
dtime: '',
|
||||||
|
image: '',
|
||||||
|
content: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
onLoad((args) => {
|
||||||
|
Detail.handleGetDetail(args.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
const Detail = {
|
||||||
|
/**
|
||||||
|
* 获取文章详情
|
||||||
|
*/
|
||||||
|
handleGetDetail: async (id: number) => {
|
||||||
|
const res = await getTeachingDetail(id)
|
||||||
|
detail.value = res.details
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
132
src/bundle/teaching/list.vue
Normal file
132
src/bundle/teaching/list.vue
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<route lang="jsonc" type="page">{
|
||||||
|
"needLogin": true,
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationBarBackgroundColor": "#F6F7F9",
|
||||||
|
"navigationBarTitleText": "商家培训"
|
||||||
|
}
|
||||||
|
}</route>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="pb-100rpx">
|
||||||
|
<view class="search-box">
|
||||||
|
<wd-search @search="List.handleSearch" v-model="keywords" placeholder="搜索培训信息" hide-cancel :placeholder-left="true"
|
||||||
|
placeholderStyle="text-align:left;line-heigt: 44rpx;color: #C9C9C9; font-size: 32rpx;font-weight: normal;">
|
||||||
|
</wd-search>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bg-white mt-28rpx mx-30rpx rounded-16rpx py-28rpx px-30rpx">
|
||||||
|
<view class="flex items-center mb-30rpx">
|
||||||
|
<wd-img :src="`${OSS}icon/icon_store.png`" width="48rpx" height="48rpx"></wd-img>
|
||||||
|
<view class="flex items-center ml-10rpx">
|
||||||
|
<view class="text-32rpx text-[#303133]">商家培训</view>
|
||||||
|
<wd-divider vertical />
|
||||||
|
<view class="text-24rpx text-[#909399]">商家运营赋能</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-body ref="mescrollItem0" @init="mescrollInit" @down="downCallback" @up="List.upCallback" :down="downOption" :up="upOption">
|
||||||
|
<view v-for="item in list" :key="item.id">
|
||||||
|
<view class="flex items-center justify-between" @click="router.navigateTo(`/bundle/teaching/detail?id=${item.id}`)">
|
||||||
|
<view class="mr-26rpx">
|
||||||
|
<view class="font-400 text-26rpx text-[#303133] leading-40rpx w-440rpx line-2">{{ item.title }}</view>
|
||||||
|
<view class="font-400 text-22rpx text-[#909399] leading-32rpx">{{ item.dtime }}</view>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<wd-img width="164rpx" height="108rpx" radius="4rpx" :src="item.image" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mt-22rpx mb-30rpx" v-if="list.length > 1 && list[list.length - 1].id !== item.id">
|
||||||
|
<wd-gap bg-color="#F6F7F9" height="2rpx"></wd-gap>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</mescroll-body>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||||
|
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js"
|
||||||
|
import { getTeachingList } from '@/api/store'
|
||||||
|
import { router } from '@/utils/tools'
|
||||||
|
|
||||||
|
const OSS = inject('OSS')
|
||||||
|
|
||||||
|
/* mescroll */
|
||||||
|
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom) // 调用mescroll的hook
|
||||||
|
const downOption = {
|
||||||
|
auto: true
|
||||||
|
}
|
||||||
|
const upOption = {
|
||||||
|
auto: true,
|
||||||
|
textNoMore: '~ 已经到底啦 ~', //无更多数据的提示
|
||||||
|
}
|
||||||
|
const list = ref<Array<any>>([]) // 茶艺师列表
|
||||||
|
const keywords = ref<string>('')
|
||||||
|
|
||||||
|
const List = {
|
||||||
|
|
||||||
|
upCallback: (mescroll) => {
|
||||||
|
const filter = {
|
||||||
|
page: mescroll.num,
|
||||||
|
size: mescroll.size,
|
||||||
|
search: keywords.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直营店订单
|
||||||
|
getTeachingList(filter).then((res) => {
|
||||||
|
const curPageData = res.list || [] // 当前页数据
|
||||||
|
if(mescroll.num == 1) list.value = [] // 第一页需手动制空列表
|
||||||
|
list.value = list.value.concat(curPageData) //追加新数据
|
||||||
|
console.log("🚀 ~ list.value:", list.value)
|
||||||
|
mescroll.endSuccess(curPageData.length, Boolean(res.more))
|
||||||
|
}).catch(() => {
|
||||||
|
mescroll.endErr() // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
*/
|
||||||
|
handleSearch: () => {
|
||||||
|
list.value = []
|
||||||
|
getMescroll().resetUpScroll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $cz-page-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
margin: 10rpx 50rpx 0;
|
||||||
|
--wot-search-padding: 0;
|
||||||
|
--wot-search-side-padding: 0;
|
||||||
|
|
||||||
|
:deep() {
|
||||||
|
.wd-search {
|
||||||
|
background: transparent !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-search__block {
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-search__input {
|
||||||
|
// #ifdef MP
|
||||||
|
padding-left: 32px !important;
|
||||||
|
padding-right: 32px !important;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef MP
|
||||||
|
padding-right: 0 !important;
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -99,23 +99,26 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="">
|
<view class="">
|
||||||
<text class="font-400 text-24rpx text-[#909399] leading-34rpx">更多</text>
|
<text class="font-400 text-24rpx text-[#909399] leading-34rpx" @click="router.navigateTo('/bundle/teaching/list')">更多</text>
|
||||||
<wd-icon name="arrow-right" size="20rpx" color="#C9C9C9" class="ml-4rpx"></wd-icon>
|
<wd-icon name="arrow-right" size="20rpx" color="#C9C9C9" class="ml-4rpx"></wd-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="mt-30rpx">
|
<view class="mt-30rpx">
|
||||||
<view v-for="i in 4" :key="i">
|
<view v-for="item in teachingList" :key="item.id">
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between" @click="router.navigateTo(`/bundle/teaching/detail?id=${item.id}`)">
|
||||||
<view class="mr-26rpx">
|
<view class="mr-26rpx">
|
||||||
<view class="font-400 text-26rpx text-[#303133] leading-40rpx w-440rpx line-2">必备课,如何做好门店评价管理。客户为什么给好评?</view>
|
<view class="font-400 text-26rpx text-[#303133] leading-40rpx w-440rpx line-2">{{ item.title }}</view>
|
||||||
<view class="font-400 text-22rpx text-[#909399] leading-32rpx">2025-08-09 17:21</view>
|
<view class="font-400 text-22rpx text-[#909399] leading-32rpx">{{ item.dtime }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view>
|
<view>
|
||||||
<wd-img width="164rpx" height="108rpx" radius="4rpx" :src="`${OSS}images/banner1.png`" mode="aspectFit" />
|
<wd-img width="164rpx" height="108rpx" radius="4rpx" :src="item.image" mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="mt-22rpx mb-30rpx" v-if="i !== 4">
|
<view
|
||||||
|
class="mt-22rpx mb-30rpx"
|
||||||
|
v-if="teachingList.length > 1 && teachingList[teachingList.length - 1].id !== item.id"
|
||||||
|
>
|
||||||
<wd-gap bg-color="#F6F7F9" height="2rpx"></wd-gap>
|
<wd-gap bg-color="#F6F7F9" height="2rpx"></wd-gap>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -130,9 +133,9 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { router } from '@/utils/tools'
|
import { router } from '@/utils/tools'
|
||||||
import { getStoreList, getStoreDetails, getStoreStatistics, scanVerifyCoupon } from '@/api/store'
|
import { getStoreList, getStoreDetails, getStoreStatistics, scanVerifyCoupon, getTeachingList } from '@/api/store'
|
||||||
import { useStoreStore } from '@/store'
|
import { useStoreStore } from '@/store'
|
||||||
import { useToast } from 'wot-design-uni'
|
import { useToast } from 'wot-design-uni'
|
||||||
|
|
||||||
const OSS = inject('OSS')
|
const OSS = inject('OSS')
|
||||||
const navbarHeight = inject('navbarHeight')
|
const navbarHeight = inject('navbarHeight')
|
||||||
@ -170,16 +173,27 @@
|
|||||||
yesterday_yan_price: 0 // 昨日验券
|
yesterday_yan_price: 0 // 昨日验券
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 培训列表
|
||||||
|
const teachingList = ref<Array<any>>([])
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 初始化页面数据
|
// 初始化页面数据
|
||||||
Index.handleInit()
|
Index.handleInit()
|
||||||
})
|
})
|
||||||
|
|
||||||
const Index = {
|
const Index = {
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
handleInit: async() => {
|
handleInit: async() => {
|
||||||
await Index.handleGetStoreList()
|
await Index.handleGetStoreList()
|
||||||
await Index.handleGetStoreDetails()
|
await Index.handleGetStoreDetails()
|
||||||
await Index.handleGetStoreStatistics()
|
await Index.handleGetStoreStatistics()
|
||||||
|
|
||||||
|
// 获取商家培训内容
|
||||||
|
getTeachingList({ page: 1, size: 5, search: '' }).then(res => {
|
||||||
|
teachingList.value = res.list
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -62,16 +62,9 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- <view class="tabs">
|
|
||||||
<wd-tabs v-model="tab" swipeable slidable="always" :lazy="false">
|
|
||||||
<wd-tab title="门店信息"></wd-tab>
|
|
||||||
<wd-tab title="门店服务"></wd-tab>
|
|
||||||
</wd-tabs>
|
|
||||||
</view> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 门店信息区域 -->
|
<!-- 门店信息区域 -->
|
||||||
<view class="store-info-card mt-28rpx bg-white pt-10rpx pl-30rpx">
|
<view class="store-info-card mt-28rpx bg-white pt-10rpx relative">
|
||||||
<view class="my-tabs">
|
<view class="my-tabs">
|
||||||
<wd-tabs v-model="tab" swipeable slidable="always" :lazy="false">
|
<wd-tabs v-model="tab" swipeable slidable="always" :lazy="false">
|
||||||
<wd-tab title="门店信息"></wd-tab>
|
<wd-tab title="门店信息"></wd-tab>
|
||||||
@ -79,8 +72,16 @@
|
|||||||
</wd-tabs>
|
</wd-tabs>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view v-if="tab == 0" class="modify-btn absolute top-340rpx right-0 flex items-center px-20rpx py-8rpx"
|
||||||
|
:style="{ backgroundImage: `url('${OSS}images/store/my/image3.png')` }"
|
||||||
|
@click="router.navigateTo('/bundle/store/edit-store')">
|
||||||
|
<wd-img width="24rpx" height="24rpx" :src="`${OSS}images/store/my/image4.png`"
|
||||||
|
class="mr-8rpx" />
|
||||||
|
<text class="text-24rpx text-[#fff]">修改</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<template v-if="tab == 0">
|
<template v-if="tab == 0">
|
||||||
<view class="mt-34rpx">
|
<view class="mt-34rpx px-30rpx">
|
||||||
<view class="mb-24rpx text-32rpx text-[#303133] font-bold leading-44rpx">
|
<view class="mb-24rpx text-32rpx text-[#303133] font-bold leading-44rpx">
|
||||||
{{ storeInfo.name }}
|
{{ storeInfo.name }}
|
||||||
</view>
|
</view>
|
||||||
@ -98,13 +99,7 @@
|
|||||||
<text class="flex-1 text-[#000]">{{ `${storeInfo.start_time}-${storeInfo.end_time}` ||
|
<text class="flex-1 text-[#000]">{{ `${storeInfo.start_time}-${storeInfo.end_time}` ||
|
||||||
'-' }}</text>
|
'-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="modify-btn absolute right-0 flex items-center px-20rpx py-8rpx"
|
|
||||||
:style="{ backgroundImage: `url('${OSS}images/store/my/image3.png')` }"
|
|
||||||
@click="router.navigateTo('/bundle/store/edit-store')">
|
|
||||||
<wd-img width="24rpx" height="24rpx" :src="`${OSS}images/store/my/image4.png`"
|
|
||||||
class="mr-8rpx" />
|
|
||||||
<text class="text-24rpx text-[#fff]">修改</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="flex items-center text-24rpx text-[#606266] leading-40rpx"
|
<view class="flex items-center text-24rpx text-[#606266] leading-40rpx"
|
||||||
@click="My.handleCall(storeInfo.contact_phone)">
|
@click="My.handleCall(storeInfo.contact_phone)">
|
||||||
|
|||||||
13
src/uni_modules/uv-parse/changelog.md
Normal file
13
src/uni_modules/uv-parse/changelog.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
## 1.0.4(2023-07-17)
|
||||||
|
1. 优化文档
|
||||||
|
2. 优化其他
|
||||||
|
## 1.0.3(2023-06-19)
|
||||||
|
1. 修复nvue模式下不显示的BUG
|
||||||
|
## 1.0.2(2023-06-02)
|
||||||
|
1. 修复可能存在的BUG
|
||||||
|
2. 优化
|
||||||
|
## 1.0.1(2023-05-16)
|
||||||
|
1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
|
||||||
|
2. 优化部分功能
|
||||||
|
## 1.0.0(2023-05-10)
|
||||||
|
uv-parse 富文本解析器
|
||||||
576
src/uni_modules/uv-parse/components/uv-parse/node/node.vue
Normal file
576
src/uni_modules/uv-parse/components/uv-parse/node/node.vue
Normal file
@ -0,0 +1,576 @@
|
|||||||
|
<template>
|
||||||
|
<view :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="attrs.style">
|
||||||
|
<block v-for="(n, i) in childs" v-bind:key="i">
|
||||||
|
<!-- 图片 -->
|
||||||
|
<!-- 占位图 -->
|
||||||
|
<image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
|
||||||
|
<!-- 显示图片 -->
|
||||||
|
<!-- #ifdef H5 || (APP-PLUS && VUE2) -->
|
||||||
|
<img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 || (APP-PLUS && VUE2) -->
|
||||||
|
<!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
|
||||||
|
<rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="[{attrs:{style:n.attrs.style,src:n.attrs.src},name:'img'}]" :data-i="i" @tap.stop="imgTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 || APP-PLUS -->
|
||||||
|
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-PLUS && VUE3 -->
|
||||||
|
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- 文本 -->
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
|
||||||
|
<text v-else-if="n.text" decode>{{n.text}}</text>
|
||||||
|
<!-- #endif -->
|
||||||
|
<text v-else-if="n.name==='br'">\n</text>
|
||||||
|
<!-- 链接 -->
|
||||||
|
<view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
|
||||||
|
<node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
|
||||||
|
</view>
|
||||||
|
<!-- 视频 -->
|
||||||
|
<!-- #ifdef APP-PLUS -->
|
||||||
|
<view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef APP-PLUS -->
|
||||||
|
<video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef H5 || APP-PLUS -->
|
||||||
|
<iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
|
||||||
|
<embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
|
||||||
|
<!-- 音频 -->
|
||||||
|
<audio v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
|
||||||
|
<node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
|
||||||
|
<view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
|
||||||
|
<node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
|
||||||
|
<block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
|
||||||
|
<view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
|
||||||
|
<node :childs="tr.children" :opts="opts" />
|
||||||
|
</view>
|
||||||
|
<view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
|
||||||
|
<view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
|
||||||
|
<node :childs="td.children" :opts="opts" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 富文本 -->
|
||||||
|
<!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||||
|
<rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||||
|
<rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;'+n.f" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- 继续递归 -->
|
||||||
|
<view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
|
||||||
|
<node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="opts" />
|
||||||
|
</view>
|
||||||
|
<node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script module="handler" lang="wxs">
|
||||||
|
// 行内标签列表
|
||||||
|
var inlineTags = {
|
||||||
|
abbr: true,
|
||||||
|
b: true,
|
||||||
|
big: true,
|
||||||
|
code: true,
|
||||||
|
del: true,
|
||||||
|
em: true,
|
||||||
|
i: true,
|
||||||
|
ins: true,
|
||||||
|
label: true,
|
||||||
|
q: true,
|
||||||
|
small: true,
|
||||||
|
span: true,
|
||||||
|
strong: true,
|
||||||
|
sub: true,
|
||||||
|
sup: true
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 判断是否为行内标签
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
isInline: function (tagName, style) {
|
||||||
|
return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import node from './node'
|
||||||
|
export default {
|
||||||
|
name: 'node',
|
||||||
|
options: {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
virtualHost: true,
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
addGlobalClass: false
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
ctrl: {},
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
isiOS: uni.getSystemInfoSync().system.includes('iOS')
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
attrs: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
childs: Array,
|
||||||
|
opts: Array
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
|
||||||
|
// #ifndef (H5 || APP-PLUS) && VUE3
|
||||||
|
node
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
for (this.root = this.$parent; this.root.$options.name !== 'uv-parse'; this.root = this.root.$parent);
|
||||||
|
})
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
if (this.opts[0]) {
|
||||||
|
let i
|
||||||
|
for (i = this.childs.length; i--;) {
|
||||||
|
if (this.childs[i].name === 'img') break
|
||||||
|
}
|
||||||
|
if (i !== -1) {
|
||||||
|
this.observer = uni.createIntersectionObserver(this).relativeToViewport({
|
||||||
|
top: 500,
|
||||||
|
bottom: 500
|
||||||
|
})
|
||||||
|
this.observer.observe('._img', res => {
|
||||||
|
if (res.intersectionRatio) {
|
||||||
|
this.$set(this.ctrl, 'load', 1)
|
||||||
|
this.observer.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
if (this.observer) {
|
||||||
|
this.observer.disconnect()
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
toJSON () { return this },
|
||||||
|
// #endif
|
||||||
|
/**
|
||||||
|
* @description 播放视频事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
play (e) {
|
||||||
|
this.root.$emit('play')
|
||||||
|
// #ifndef APP-PLUS
|
||||||
|
if (this.root.pauseVideo) {
|
||||||
|
let flag = false
|
||||||
|
const id = e.target.id
|
||||||
|
for (let i = this.root._videos.length; i--;) {
|
||||||
|
if (this.root._videos[i].id === id) {
|
||||||
|
flag = true
|
||||||
|
} else {
|
||||||
|
this.root._videos[i].pause() // 自动暂停其他视频
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将自己加入列表
|
||||||
|
if (!flag) {
|
||||||
|
const ctx = uni.createVideoContext(id
|
||||||
|
// #ifndef MP-BAIDU
|
||||||
|
, this
|
||||||
|
// #endif
|
||||||
|
)
|
||||||
|
ctx.id = id
|
||||||
|
if (this.root.playbackRate) {
|
||||||
|
ctx.playbackRate(this.root.playbackRate)
|
||||||
|
}
|
||||||
|
this.root._videos.push(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 图片点击事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
imgTap (e) {
|
||||||
|
const node = this.childs[e.currentTarget.dataset.i]
|
||||||
|
if (node.a) {
|
||||||
|
this.linkTap(node.a)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (node.attrs.ignore) return
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
node.attrs.src = node.attrs.src || node.attrs['data-src']
|
||||||
|
// #endif
|
||||||
|
this.root.$emit('imgtap', node.attrs)
|
||||||
|
// 自动预览图片
|
||||||
|
if (this.root.previewImg) {
|
||||||
|
uni.previewImage({
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
showmenu: this.root.showImgMenu,
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
enablesavephoto: this.root.showImgMenu,
|
||||||
|
enableShowPhotoDownload: this.root.showImgMenu,
|
||||||
|
// #endif
|
||||||
|
current: parseInt(node.attrs.i),
|
||||||
|
urls: this.root.imgList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 图片长按
|
||||||
|
*/
|
||||||
|
imgLongTap (e) {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const attrs = this.childs[e.currentTarget.dataset.i].attrs
|
||||||
|
if (this.opts[3] && !attrs.ignore) {
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ['保存图片'],
|
||||||
|
success: () => {
|
||||||
|
const save = path => {
|
||||||
|
uni.saveImageToPhotosAlbum({
|
||||||
|
filePath: path,
|
||||||
|
success () {
|
||||||
|
uni.showToast({
|
||||||
|
title: '保存成功'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.root.imgList[attrs.i].startsWith('http')) {
|
||||||
|
uni.downloadFile({
|
||||||
|
url: this.root.imgList[attrs.i],
|
||||||
|
success: res => save(res.tempFilePath)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
save(this.root.imgList[attrs.i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 图片加载完成事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
imgLoad (e) {
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
/* #ifndef H5 || (APP-PLUS && VUE2) */
|
||||||
|
if (!this.childs[i].w) {
|
||||||
|
// 设置原宽度
|
||||||
|
this.$set(this.ctrl, i, e.detail.width)
|
||||||
|
} else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
|
||||||
|
// 加载完毕,取消加载中占位图
|
||||||
|
this.$set(this.ctrl, i, 1)
|
||||||
|
}
|
||||||
|
this.checkReady()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 检查是否所有图片加载完毕
|
||||||
|
*/
|
||||||
|
checkReady () {
|
||||||
|
if (this.root && !this.root.lazyLoad) {
|
||||||
|
this.root._unloadimgs -= 1
|
||||||
|
if (!this.root._unloadimgs) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.root.getRect().then(rect => {
|
||||||
|
this.root.$emit('ready', rect)
|
||||||
|
}).catch(() => {
|
||||||
|
this.root.$emit('ready', {})
|
||||||
|
})
|
||||||
|
}, 350)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 链接点击事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
linkTap (e) {
|
||||||
|
const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
|
||||||
|
const attrs = node.attrs || e
|
||||||
|
const href = attrs.href
|
||||||
|
this.root.$emit('linktap', Object.assign({
|
||||||
|
innerText: this.root.getText(node.children || []) // 链接内的文本内容
|
||||||
|
}, attrs))
|
||||||
|
if (href) {
|
||||||
|
if (href[0] === '#') {
|
||||||
|
// 跳转锚点
|
||||||
|
this.root.navigateTo(href.substring(1)).catch(() => { })
|
||||||
|
} else if (href.split('?')[0].includes('://')) {
|
||||||
|
// 复制外部链接
|
||||||
|
if (this.root.copyLink) {
|
||||||
|
// #ifdef H5
|
||||||
|
window.open(href)
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: href,
|
||||||
|
success: () =>
|
||||||
|
uni.showToast({
|
||||||
|
title: '链接已复制'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
plus.runtime.openWeb(href)
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 跳转页面
|
||||||
|
uni.navigateTo({
|
||||||
|
url: href,
|
||||||
|
fail () {
|
||||||
|
uni.switchTab({
|
||||||
|
url: href,
|
||||||
|
fail () { }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 错误事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
mediaError (e) {
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
const node = this.childs[i]
|
||||||
|
// 加载其他源
|
||||||
|
if (node.name === 'video' || node.name === 'audio') {
|
||||||
|
let index = (this.ctrl[i] || 0) + 1
|
||||||
|
if (index > node.src.length) {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
if (index < node.src.length) {
|
||||||
|
this.$set(this.ctrl, i, index)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if (node.name === 'img') {
|
||||||
|
// #ifdef H5 && VUE3
|
||||||
|
if (this.opts[0] && !this.ctrl.load) return
|
||||||
|
// #endif
|
||||||
|
// 显示错误占位图
|
||||||
|
if (this.opts[2]) {
|
||||||
|
this.$set(this.ctrl, i, -1)
|
||||||
|
}
|
||||||
|
this.checkReady()
|
||||||
|
}
|
||||||
|
if (this.root) {
|
||||||
|
this.root.$emit('error', {
|
||||||
|
source: node.name,
|
||||||
|
attrs: node.attrs,
|
||||||
|
// #ifndef H5 && VUE3
|
||||||
|
errMsg: e.detail.errMsg
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/* a 标签默认效果 */
|
||||||
|
._a {
|
||||||
|
padding: 1.5px 0 1.5px 0;
|
||||||
|
color: #366092;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a 标签点击态效果 */
|
||||||
|
._hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图片默认效果 */
|
||||||
|
._img {
|
||||||
|
max-width: 100%;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内部样式 */
|
||||||
|
|
||||||
|
._block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
._b,
|
||||||
|
._strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
._code {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
._del {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
._em,
|
||||||
|
._i {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h2 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h3 {
|
||||||
|
font-size: 1.17em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h5 {
|
||||||
|
font-size: 0.83em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h6 {
|
||||||
|
font-size: 0.67em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h1,
|
||||||
|
._h2,
|
||||||
|
._h3,
|
||||||
|
._h4,
|
||||||
|
._h5,
|
||||||
|
._h6 {
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
._image {
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ins {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
._li {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ol,
|
||||||
|
._ul {
|
||||||
|
display: block;
|
||||||
|
padding-left: 40px;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._q::before {
|
||||||
|
content: '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
._q::after {
|
||||||
|
content: '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
._sub {
|
||||||
|
font-size: smaller;
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
._sup {
|
||||||
|
font-size: smaller;
|
||||||
|
vertical-align: super;
|
||||||
|
}
|
||||||
|
|
||||||
|
._thead,
|
||||||
|
._tbody,
|
||||||
|
._tfoot {
|
||||||
|
display: table-row-group;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
._td,
|
||||||
|
._th {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
._th {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ul ._ul {
|
||||||
|
margin: 0;
|
||||||
|
list-style-type: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ul ._ul ._ul {
|
||||||
|
list-style-type: square;
|
||||||
|
}
|
||||||
|
|
||||||
|
._abbr,
|
||||||
|
._b,
|
||||||
|
._code,
|
||||||
|
._del,
|
||||||
|
._em,
|
||||||
|
._i,
|
||||||
|
._ins,
|
||||||
|
._label,
|
||||||
|
._q,
|
||||||
|
._span,
|
||||||
|
._strong,
|
||||||
|
._sub,
|
||||||
|
._sup {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef APP-PLUS */
|
||||||
|
._video {
|
||||||
|
width: 300px;
|
||||||
|
height: 225px;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
1335
src/uni_modules/uv-parse/components/uv-parse/parser.js
Normal file
1335
src/uni_modules/uv-parse/components/uv-parse/parser.js
Normal file
File diff suppressed because it is too large
Load Diff
498
src/uni_modules/uv-parse/components/uv-parse/uv-parse.vue
Normal file
498
src/uni_modules/uv-parse/components/uv-parse/uv-parse.vue
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
<template>
|
||||||
|
<view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
|
||||||
|
<slot v-if="!nodes[0]" />
|
||||||
|
<!-- #ifndef APP-PLUS-NVUE -->
|
||||||
|
<node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-PLUS-NVUE -->
|
||||||
|
<web-view ref="web" src="/uni_modules/uv-parse/static/app-plus/uv-parse/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* uv-parse v1.0.3
|
||||||
|
* @description 富文本组件
|
||||||
|
* @tutorial https://www.uvui.cn/components/parse.html
|
||||||
|
* @property {String} container-style 容器的样式
|
||||||
|
* @property {String} content 用于渲染的 html 字符串
|
||||||
|
* @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
|
||||||
|
* @property {String} domain 主域名,用于拼接链接
|
||||||
|
* @property {String} error-img 图片出错时的占位图链接
|
||||||
|
* @property {Boolean} lazy-load 是否开启图片懒加载
|
||||||
|
* @property {string} loading-img 图片加载过程中的占位图链接
|
||||||
|
* @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
|
||||||
|
* @property {Boolean} preview-img 是否允许图片被点击时自动预览
|
||||||
|
* @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
|
||||||
|
* @property {Boolean | String} selectable 是否开启长按复制
|
||||||
|
* @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
|
||||||
|
* @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
|
||||||
|
* @property {Object} tag-style 标签的默认样式
|
||||||
|
* @property {Boolean | Number} use-anchor 是否使用锚点链接
|
||||||
|
* @event {Function} load dom 结构加载完毕时触发
|
||||||
|
* @event {Function} ready 所有图片加载完毕时触发
|
||||||
|
* @event {Function} imgtap 图片被点击时触发
|
||||||
|
* @event {Function} linktap 链接被点击时触发
|
||||||
|
* @event {Function} play 音视频播放时触发
|
||||||
|
* @event {Function} error 媒体加载出错时触发
|
||||||
|
*/
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
import node from './node/node'
|
||||||
|
// #endif
|
||||||
|
import Parser from './parser'
|
||||||
|
const plugins=[]
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
const dom = weex.requireModule('dom')
|
||||||
|
// #endif
|
||||||
|
export default {
|
||||||
|
name: 'uv-parse',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
nodes: [],
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
height: 3
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
containerStyle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
copyLink: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
domain: String,
|
||||||
|
errorImg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
lazyLoad: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
loadingImg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
pauseVideo: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
previewImg: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
scrollTable: [Boolean, String],
|
||||||
|
selectable: [Boolean, String],
|
||||||
|
setTitle: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showImgMenu: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
tagStyle: Object,
|
||||||
|
useAnchor: [Boolean, Number]
|
||||||
|
},
|
||||||
|
// #ifdef VUE3
|
||||||
|
emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
components: {
|
||||||
|
node
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
watch: {
|
||||||
|
content (content) {
|
||||||
|
this.setContent(content)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.plugins = []
|
||||||
|
for (let i = plugins.length; i--;) {
|
||||||
|
this.plugins.push(new plugins[i](this))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (this.content && !this.nodes.length) {
|
||||||
|
this.setContent(this.content)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this._hook('onDetached')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @description 将锚点跳转的范围限定在一个 scroll-view 内
|
||||||
|
* @param {Object} page scroll-view 所在页面的示例
|
||||||
|
* @param {String} selector scroll-view 的选择器
|
||||||
|
* @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
|
||||||
|
*/
|
||||||
|
in (page, selector, scrollTop) {
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
if (page && selector && scrollTop) {
|
||||||
|
this._in = {
|
||||||
|
page,
|
||||||
|
selector,
|
||||||
|
scrollTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 锚点跳转
|
||||||
|
* @param {String} id 要跳转的锚点 id
|
||||||
|
* @param {Number} offset 跳转位置的偏移量
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
navigateTo (id, offset) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.useAnchor) {
|
||||||
|
reject(Error('Anchor is disabled'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset = offset || parseInt(this.useAnchor) || 0
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
if (!id) {
|
||||||
|
dom.scrollToElement(this.$refs.web, {
|
||||||
|
offset
|
||||||
|
})
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
this._navigateTo = {
|
||||||
|
resolve,
|
||||||
|
reject,
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
let deep = ' '
|
||||||
|
// #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
|
||||||
|
deep = '>>>'
|
||||||
|
// #endif
|
||||||
|
const selector = uni.createSelectorQuery()
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
|
.in(this._in ? this._in.page : this)
|
||||||
|
// #endif
|
||||||
|
.select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
|
||||||
|
if (this._in) {
|
||||||
|
selector.select(this._in.selector).scrollOffset()
|
||||||
|
.select(this._in.selector).boundingClientRect()
|
||||||
|
} else {
|
||||||
|
// 获取 scroll-view 的位置和滚动距离
|
||||||
|
selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
|
||||||
|
}
|
||||||
|
selector.exec(res => {
|
||||||
|
if (!res[0]) {
|
||||||
|
reject(Error('Label not found'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
|
||||||
|
if (this._in) {
|
||||||
|
// scroll-view 跳转
|
||||||
|
this._in.page[this._in.scrollTop] = scrollTop
|
||||||
|
} else {
|
||||||
|
// 页面跳转
|
||||||
|
uni.pageScrollTo({
|
||||||
|
scrollTop,
|
||||||
|
duration: 300
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取文本内容
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getText (nodes) {
|
||||||
|
let text = '';
|
||||||
|
(function traversal (nodes) {
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
const node = nodes[i]
|
||||||
|
if (node.type === 'text') {
|
||||||
|
text += node.text.replace(/&/g, '&')
|
||||||
|
} else if (node.name === 'br') {
|
||||||
|
text += '\n'
|
||||||
|
} else {
|
||||||
|
// 块级标签前后加换行
|
||||||
|
const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
|
||||||
|
if (isBlock && text && text[text.length - 1] !== '\n') {
|
||||||
|
text += '\n'
|
||||||
|
}
|
||||||
|
// 递归获取子节点的文本
|
||||||
|
if (node.children) {
|
||||||
|
traversal(node.children)
|
||||||
|
}
|
||||||
|
if (isBlock && text[text.length - 1] !== '\n') {
|
||||||
|
text += '\n'
|
||||||
|
} else if (node.name === 'td' || node.name === 'th') {
|
||||||
|
text += '\t'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(nodes || this.nodes)
|
||||||
|
return text
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取内容大小和位置
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
getRect () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.createSelectorQuery()
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
|
.in(this)
|
||||||
|
// #endif
|
||||||
|
.select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 暂停播放媒体
|
||||||
|
*/
|
||||||
|
pauseMedia () {
|
||||||
|
for (let i = (this._videos || []).length; i--;) {
|
||||||
|
this._videos[i].pause()
|
||||||
|
}
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
let page = this.$parent
|
||||||
|
while (!page.$scope) page = page.$parent
|
||||||
|
page.$scope.$getAppWebview().evalJS(command)
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
this.$refs.web.evalJs(command)
|
||||||
|
// #endif
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 设置媒体播放速率
|
||||||
|
* @param {Number} rate 播放速率
|
||||||
|
*/
|
||||||
|
setPlaybackRate (rate) {
|
||||||
|
this.playbackRate = rate
|
||||||
|
for (let i = (this._videos || []).length; i--;) {
|
||||||
|
this._videos[i].playbackRate(rate)
|
||||||
|
}
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
let page = this.$parent
|
||||||
|
while (!page.$scope) page = page.$parent
|
||||||
|
page.$scope.$getAppWebview().evalJS(command)
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
this.$refs.web.evalJs(command)
|
||||||
|
// #endif
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 设置内容
|
||||||
|
* @param {String} content html 内容
|
||||||
|
* @param {Boolean} append 是否在尾部追加
|
||||||
|
*/
|
||||||
|
setContent (content, append) {
|
||||||
|
if (!append || !this.imgList) {
|
||||||
|
this.imgList = []
|
||||||
|
}
|
||||||
|
const nodes = new Parser(this).parse(content)
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
if (this._ready) {
|
||||||
|
this._set(nodes, append)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
|
||||||
|
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
this._videos = []
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this._hook('onLoad')
|
||||||
|
this.$emit('load')
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
|
||||||
|
// 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
|
||||||
|
let height = 0
|
||||||
|
const callback = rect => {
|
||||||
|
if (!rect || !rect.height) rect = {}
|
||||||
|
// 350ms 总高度无变化就触发 ready 事件
|
||||||
|
if (rect.height === height) {
|
||||||
|
this.$emit('ready', rect)
|
||||||
|
} else {
|
||||||
|
height = rect.height
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getRect().then(callback).catch(callback)
|
||||||
|
}, 350)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getRect().then(callback).catch(callback)
|
||||||
|
} else {
|
||||||
|
// 未设置懒加载,等待所有图片加载完毕
|
||||||
|
if (!this.imgList._unloadimgs) {
|
||||||
|
this.getRect().then(rect => {
|
||||||
|
this.$emit('ready', rect)
|
||||||
|
}).catch(() => {
|
||||||
|
this.$emit('ready', {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 调用插件钩子函数
|
||||||
|
*/
|
||||||
|
_hook (name) {
|
||||||
|
for (let i = plugins.length; i--;) {
|
||||||
|
if (this.plugins[i][name]) {
|
||||||
|
this.plugins[i][name]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
/**
|
||||||
|
* @description 设置内容
|
||||||
|
*/
|
||||||
|
_set (nodes, append) {
|
||||||
|
this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 接收到 web-view 消息
|
||||||
|
*/
|
||||||
|
_onMessage (e) {
|
||||||
|
const message = e.detail.data[0]
|
||||||
|
switch (message.action) {
|
||||||
|
// web-view 初始化完毕
|
||||||
|
case 'onJSBridgeReady':
|
||||||
|
this._ready = true
|
||||||
|
if (this.nodes) {
|
||||||
|
this._set(this.nodes)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// 内容 dom 加载完毕
|
||||||
|
case 'onLoad':
|
||||||
|
this.height = message.height
|
||||||
|
this._hook('onLoad')
|
||||||
|
this.$emit('load')
|
||||||
|
break
|
||||||
|
// 所有图片加载完毕
|
||||||
|
case 'onReady':
|
||||||
|
this.getRect().then(res => {
|
||||||
|
this.$emit('ready', res)
|
||||||
|
}).catch(() => {
|
||||||
|
this.$emit('ready', {})
|
||||||
|
})
|
||||||
|
break
|
||||||
|
// 总高度发生变化
|
||||||
|
case 'onHeightChange':
|
||||||
|
this.height = message.height
|
||||||
|
break
|
||||||
|
// 图片点击
|
||||||
|
case 'onImgTap':
|
||||||
|
this.$emit('imgtap', message.attrs)
|
||||||
|
if (this.previewImg) {
|
||||||
|
uni.previewImage({
|
||||||
|
current: parseInt(message.attrs.i),
|
||||||
|
urls: this.imgList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// 链接点击
|
||||||
|
case 'onLinkTap': {
|
||||||
|
const href = message.attrs.href
|
||||||
|
this.$emit('linktap', message.attrs)
|
||||||
|
if (href) {
|
||||||
|
// 锚点跳转
|
||||||
|
if (href[0] === '#') {
|
||||||
|
if (this.useAnchor) {
|
||||||
|
dom.scrollToElement(this.$refs.web, {
|
||||||
|
offset: message.offset
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (href.includes('://')) {
|
||||||
|
// 打开外链
|
||||||
|
if (this.copyLink) {
|
||||||
|
plus.runtime.openWeb(href)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: href,
|
||||||
|
fail () {
|
||||||
|
uni.switchTab({
|
||||||
|
url: href
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'onPlay':
|
||||||
|
this.$emit('play')
|
||||||
|
break
|
||||||
|
// 获取到锚点的偏移量
|
||||||
|
case 'getOffset':
|
||||||
|
if (typeof message.offset === 'number') {
|
||||||
|
dom.scrollToElement(this.$refs.web, {
|
||||||
|
offset: message.offset + this._navigateTo.offset
|
||||||
|
})
|
||||||
|
this._navigateTo.resolve()
|
||||||
|
} else {
|
||||||
|
this._navigateTo.reject(Error('Label not found'))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// 点击
|
||||||
|
case 'onClick':
|
||||||
|
this.$emit('tap')
|
||||||
|
this.$emit('click')
|
||||||
|
break
|
||||||
|
// 出错
|
||||||
|
case 'onError':
|
||||||
|
this.$emit('error', {
|
||||||
|
source: message.source,
|
||||||
|
attrs: message.attrs
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* #ifndef APP-PLUS-NVUE */
|
||||||
|
/* 根节点样式 */
|
||||||
|
._root {
|
||||||
|
padding: 1px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 长按复制 */
|
||||||
|
._select {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
87
src/uni_modules/uv-parse/package.json
Normal file
87
src/uni_modules/uv-parse/package.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"id": "uv-parse",
|
||||||
|
"displayName": "uv-parse 富文本解析器 全面兼容vue3+2、app、h5、小程序等多端",
|
||||||
|
"version": "1.0.4",
|
||||||
|
"description": "uv-parse 该组件一般用于富文本解析场景,比如解析文章内容,商品详情,带原生HTML标签的各类字符串等,此组件和uni-app官方的rich-text组件功能有重合之处,但是也有不同的地方。",
|
||||||
|
"keywords": [
|
||||||
|
"uv-parse",
|
||||||
|
"uvui",
|
||||||
|
"uv-ui",
|
||||||
|
"parse",
|
||||||
|
"富文本"
|
||||||
|
],
|
||||||
|
"repository": "",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": "^3.1.0"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"type": "component-vue",
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "插件不采集任何数据",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": ""
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [
|
||||||
|
"uv-ui-tools"
|
||||||
|
],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
},
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y",
|
||||||
|
"钉钉": "u",
|
||||||
|
"快手": "u",
|
||||||
|
"飞书": "u",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/uni_modules/uv-parse/readme.md
Normal file
21
src/uni_modules/uv-parse/readme.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
## Parse 富文本解析器
|
||||||
|
|
||||||
|
> **组件名:uv-parse**
|
||||||
|
|
||||||
|
该组件一般用于富文本解析场景,比如解析文章内容,商品详情,带原生`HTML`标签的各类字符串等,此组件和`uni-app`官方的`rich-text`组件功能有重合之处,但是也有不同的地方。
|
||||||
|
|
||||||
|
该插件只提供富文本的解析,该功能已经足够丰富。如果需要富文本的编辑,可使用`uniapp`官方提供的组件。
|
||||||
|
|
||||||
|
# <a href="https://www.uvui.cn/components/parse.html" target="_blank">查看文档</a>
|
||||||
|
|
||||||
|
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)
|
||||||
|
|
||||||
|
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
|
||||||
|
|
||||||
|
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
|
||||||
224
src/uni_modules/uv-parse/static/app-plus/uv-parse/js/handler.js
Normal file
224
src/uni_modules/uv-parse/static/app-plus/uv-parse/js/handler.js
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
// 等待初始化完毕
|
||||||
|
document.addEventListener('UniAppJSBridgeReady', () => {
|
||||||
|
document.body.onclick = function () {
|
||||||
|
return uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onClick'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onJSBridgeReady'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let options
|
||||||
|
let medias = []
|
||||||
|
/**
|
||||||
|
* @description 获取标签的所有属性
|
||||||
|
* @param {Element} ele
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getAttrs(ele) {
|
||||||
|
const attrs = Object.create(null)
|
||||||
|
|
||||||
|
for (let i = ele.attributes.length; i--;) {
|
||||||
|
attrs[ele.attributes[i].name] = ele.attributes[i].value
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 图片加载出错
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onImgError() {
|
||||||
|
if (options[1]) {
|
||||||
|
this.src = options[1]
|
||||||
|
this.onerror = null
|
||||||
|
} // 取消监听点击
|
||||||
|
|
||||||
|
this.onclick = null
|
||||||
|
this.ontouchstart = null
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onError',
|
||||||
|
source: 'img',
|
||||||
|
attrs: getAttrs(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 创建 dom 结构
|
||||||
|
* @param {object[]} nodes 节点数组
|
||||||
|
* @param {Element} parent 父节点
|
||||||
|
* @param {string} namespace 命名空间
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createDom(nodes, parent, namespace) {
|
||||||
|
const _loop = function _loop(i) {
|
||||||
|
const node = nodes[i]
|
||||||
|
let ele = void 0
|
||||||
|
|
||||||
|
if (!node.type || node.type == 'node') {
|
||||||
|
let { name } = node // svg 需要设置 namespace
|
||||||
|
|
||||||
|
if (name == 'svg') namespace = 'http://www.w3.org/2000/svg'
|
||||||
|
if (name == 'html' || name == 'body') name = 'div' // 创建标签
|
||||||
|
|
||||||
|
if (!namespace) ele = document.createElement(name); else ele = document.createElementNS(namespace, name) // 设置属性
|
||||||
|
|
||||||
|
for (const item in node.attrs) {
|
||||||
|
ele.setAttribute(item, node.attrs[item])
|
||||||
|
} // 递归创建子节点
|
||||||
|
|
||||||
|
if (node.children) createDom(node.children, ele, namespace) // 处理图片
|
||||||
|
|
||||||
|
if (name == 'img') {
|
||||||
|
if (!ele.src && ele.getAttribute('data-src')) ele.src = ele.getAttribute('data-src')
|
||||||
|
|
||||||
|
if (!node.attrs.ignore) {
|
||||||
|
// 监听图片点击事件
|
||||||
|
ele.onclick = function (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onImgTap',
|
||||||
|
attrs: getAttrs(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options[2]) {
|
||||||
|
image = new Image()
|
||||||
|
image.src = ele.src
|
||||||
|
ele.src = options[2]
|
||||||
|
|
||||||
|
image.onload = function () {
|
||||||
|
ele.src = this.src
|
||||||
|
}
|
||||||
|
|
||||||
|
image.onerror = function () {
|
||||||
|
ele.onerror()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ele.onerror = onImgError
|
||||||
|
} // 处理链接
|
||||||
|
else if (name == 'a') {
|
||||||
|
ele.addEventListener('click', function (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault() // 阻止默认跳转
|
||||||
|
|
||||||
|
const href = this.getAttribute('href')
|
||||||
|
let offset
|
||||||
|
if (href && href[0] == '#') offset = (document.getElementById(href.substr(1)) || {}).offsetTop
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onLinkTap',
|
||||||
|
attrs: getAttrs(this),
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, true)
|
||||||
|
} // 处理音视频
|
||||||
|
else if (name == 'video' || name == 'audio') {
|
||||||
|
medias.push(ele)
|
||||||
|
|
||||||
|
if (!node.attrs.autoplay) {
|
||||||
|
if (!node.attrs.controls) ele.setAttribute('controls', 'true') // 空白图占位
|
||||||
|
|
||||||
|
if (!node.attrs.poster) ele.setAttribute('poster', "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'/>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options[3]) {
|
||||||
|
ele.onplay = function () {
|
||||||
|
for (let _i = 0; _i < medias.length; _i++) {
|
||||||
|
if (medias[_i] != this) medias[_i].pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ele.onerror = function () {
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onError',
|
||||||
|
source: name,
|
||||||
|
attrs: getAttrs(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} // 处理表格
|
||||||
|
else if (name == 'table' && options[4] && !ele.style.cssText.includes('inline')) {
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.style.overflow = 'auto'
|
||||||
|
div.appendChild(ele)
|
||||||
|
ele = div
|
||||||
|
} else if (name == 'svg') namespace = void 0
|
||||||
|
} else ele = document.createTextNode(node.text.replace(/&/g, '&'))
|
||||||
|
|
||||||
|
parent.appendChild(ele)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
var image
|
||||||
|
|
||||||
|
_loop(i)
|
||||||
|
}
|
||||||
|
} // 设置 html 内容
|
||||||
|
|
||||||
|
window.setContent = function (nodes, opts, append) {
|
||||||
|
const ele = document.getElementById('content') // 背景颜色
|
||||||
|
|
||||||
|
if (opts[0]) document.body.bgColor = opts[0] // 长按复制
|
||||||
|
|
||||||
|
if (!opts[5]) ele.style.userSelect = 'none'
|
||||||
|
|
||||||
|
if (!append) {
|
||||||
|
ele.innerHTML = '' // 不追加则先清空
|
||||||
|
|
||||||
|
medias = []
|
||||||
|
}
|
||||||
|
|
||||||
|
options = opts
|
||||||
|
const fragment = document.createDocumentFragment()
|
||||||
|
createDom(nodes, fragment)
|
||||||
|
ele.appendChild(fragment) // 触发事件
|
||||||
|
|
||||||
|
let height = ele.scrollHeight
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onLoad',
|
||||||
|
height
|
||||||
|
}
|
||||||
|
})
|
||||||
|
clearInterval(window.timer)
|
||||||
|
let ready = false
|
||||||
|
window.timer = setInterval(() => {
|
||||||
|
if (ele.scrollHeight != height) {
|
||||||
|
height = ele.scrollHeight
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onHeightChange',
|
||||||
|
height
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (!ready) {
|
||||||
|
ready = true
|
||||||
|
uni.postMessage({
|
||||||
|
data: {
|
||||||
|
action: 'onReady'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 350)
|
||||||
|
} // 回收计时器
|
||||||
|
|
||||||
|
window.onunload = function () {
|
||||||
|
clearInterval(window.timer)
|
||||||
|
}
|
||||||
19
src/uni_modules/uv-parse/static/app-plus/uv-parse/js/uni.webview.min.js
vendored
Normal file
19
src/uni_modules/uv-parse/static/app-plus/uv-parse/js/uni.webview.min.js
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
!(function (e, n) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = n() : typeof define === 'function' && define.amd ? define(n) : (e = e || self).uni = n() }(this, (() => {
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
try { const e = {}; Object.defineProperty(e, 'passive', { get() { !0 } }), window.addEventListener('test-passive', null, e) } catch (e) {} const n = Object.prototype.hasOwnProperty; function t(e, t) { return n.call(e, t) } const i = []; const a = function (e, n) { const t = { options: { timestamp: +new Date() }, name: e, arg: n }; if (window.__dcloud_weex_postMessage || window.__dcloud_weex_) { if (e === 'postMessage') { const a = { data: [n] }; return window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessage(a) : window.__dcloud_weex_.postMessage(JSON.stringify(a)) } const o = { type: 'WEB_INVOKE_APPSERVICE', args: { data: t, webviewIds: i } }; window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessageToService(o) : window.__dcloud_weex_.postMessageToService(JSON.stringify(o)) } if (!window.plus) return window.parent.postMessage({ type: 'WEB_INVOKE_APPSERVICE', data: t, pageId: '' }, '*'); if (i.length === 0) { const r = plus.webview.currentWebview(); if (!r) throw new Error('plus.webview.currentWebview() is undefined'); const d = r.parent(); let s = ''; s = d ? d.id : r.id, i.push(s) } if (plus.webview.getWebviewById('__uniapp__service'))plus.webview.postMessageToUniNView({ type: 'WEB_INVOKE_APPSERVICE', args: { data: t, webviewIds: i } }, '__uniapp__service'); else { const w = JSON.stringify(t); plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat('WEB_INVOKE_APPSERVICE', '",').concat(w, ',').concat(JSON.stringify(i), ');')) } }; const o = {
|
||||||
|
navigateTo() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('navigateTo', { url: encodeURI(n) }) }, navigateBack() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.delta; a('navigateBack', { delta: parseInt(n) || 1 }) }, switchTab() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('switchTab', { url: encodeURI(n) }) }, reLaunch() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('reLaunch', { url: encodeURI(n) }) }, redirectTo() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('redirectTo', { url: encodeURI(n) }) }, getEnv(e) { window.plus ? e({ plus: !0 }) : e({ h5: !0 }) }, postMessage() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; a('postMessage', e.data || {}) }
|
||||||
|
}; const r = /uni-app/i.test(navigator.userAgent); const d = /Html5Plus/i.test(navigator.userAgent); const s = /complete|loaded|interactive/; const w = window.my && navigator.userAgent.indexOf('AlipayClient') > -1; const u = window.swan && window.swan.webView && /swan/i.test(navigator.userAgent); const c = window.qq && window.qq.miniProgram && /QQ/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent); const g = window.tt && window.tt.miniProgram && /toutiaomicroapp/i.test(navigator.userAgent); const v = window.wx && window.wx.miniProgram && /micromessenger/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent); const p = window.qa && /quickapp/i.test(navigator.userAgent); for (var l, _ = function () { window.UniAppJSBridge = !0, document.dispatchEvent(new CustomEvent('UniAppJSBridgeReady', { bubbles: !0, cancelable: !0 })) }, f = [function (e) { if (r || d) return window.__dcloud_weex_postMessage || window.__dcloud_weex_ ? document.addEventListener('DOMContentLoaded', e) : window.plus && s.test(document.readyState) ? setTimeout(e, 0) : document.addEventListener('plusready', e), o }, function (e) { if (v) return window.WeixinJSBridge && window.WeixinJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener('WeixinJSBridgeReady', e), window.wx.miniProgram }, function (e) { if (c) return window.QQJSBridge && window.QQJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener('QQJSBridgeReady', e), window.qq.miniProgram }, function (e) {
|
||||||
|
if (w) {
|
||||||
|
document.addEventListener('DOMContentLoaded', e); const n = window.my; return {
|
||||||
|
navigateTo: n.navigateTo, navigateBack: n.navigateBack, switchTab: n.switchTab, reLaunch: n.reLaunch, redirectTo: n.redirectTo, postMessage: n.postMessage, getEnv: n.getEnv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, function (e) { if (u) return document.addEventListener('DOMContentLoaded', e), window.swan.webView }, function (e) { if (g) return document.addEventListener('DOMContentLoaded', e), window.tt.miniProgram }, function (e) {
|
||||||
|
if (p) {
|
||||||
|
window.QaJSBridge && window.QaJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener('QaJSBridgeReady', e); const n = window.qa; return {
|
||||||
|
navigateTo: n.navigateTo, navigateBack: n.navigateBack, switchTab: n.switchTab, reLaunch: n.reLaunch, redirectTo: n.redirectTo, postMessage: n.postMessage, getEnv: n.getEnv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, function (e) { return document.addEventListener('DOMContentLoaded', e), o }], m = 0; m < f.length && !(l = f[m](_)); m++);l || (l = {}); const E = typeof uni !== 'undefined' ? uni : {}; if (!E.navigateTo) for (const b in l)t(l, b) && (E[b] = l[b]); return E.webView = l, E
|
||||||
|
})))
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>body,html{width:100%;height:100%;overflow:hidden}body{margin:0}video{width:300px;height:225px}img{max-width:100%;-webkit-touch-callout:none}@keyframes show{0%{opacity:0}100%{opacity:1}}</style></head><body><div id="content"></div><script type="text/javascript" src="./js/uni.webview.min.js"></script><script type="text/javascript" src="./js/handler.js"></script></body>
|
||||||
Reference in New Issue
Block a user