使用商城源码,但是不全面升级为vue3

This commit is contained in:
wangzimeng 2025-07-16 14:46:59 +08:00
parent 0def47b3fb
commit c15433bb8f
32 changed files with 741 additions and 1135 deletions

28
main.js
View File

@ -1,23 +1,15 @@
import App from './App';
import {
createSSRApp
} from 'vue';
import {
setupPinia
} from './sheep/store';
import { createPinia } from 'pinia'
import uView from 'uview-plus';
import { createSSRApp } from 'vue';
import { setupPinia } from './sheep/store';
export function createApp() {
// Vue.use(uView);
const app = createSSRApp(App);
const pinia = createPinia()
app.use(pinia)
app.use(uView)
setupPinia(app);
const app = createSSRApp(App);
setupPinia(app);
return {
app,
};
}
return {
app,
};
}

View File

@ -1,5 +1,5 @@
{
"name": "Shopro",
"name": "团餐宝典",
"appid": "__UNI__B256060",
"description": "Shopro是由SheepJS团队开发使用Uniapp+Vue3技术驱动的在线商城系统内含诸多功能与丰富的活动期待您的使用和反馈。",
"versionName": "3.1.0",

View File

@ -1,104 +1,102 @@
{
"id": "shopro",
"name": "shopro",
"displayName": "Shopro商城",
"version": "3.1.0",
"description": "Shopro-B2C商城一套代码同时发行到iOS、Android、H5、微信小程序多个平台请使用手机扫码快速体验强大功能",
"scripts": {
"prettier": "prettier --write \"{pages,sheep}/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
},
"repository": "https://github.com/sheepjs/shop.git",
"keywords": [
"商城",
"B2C",
"Shopro",
"商城模板"
],
"author": "",
"license": "MIT",
"homepage": "https://www.shopro.top",
"dcloudext": {
"category": [
"前端页面模板",
"uni-app前端项目模板"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"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",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "u",
"vue3": "y"
}
}
}
},
"dependencies": {
"@hyoga/uni-socket.io": "^1.0.1",
"dayjs": "^1.11.9",
"lodash": "^4.17.21",
"luch-request": "^3.1.0",
"pinia": "^2.1.4",
"pinia-plugin-persist-uni": "1.2.0",
"qs-canvas": "^1.0.11",
"uview-plus": "^3.4.51",
"vue": "^3.5.17",
"weixin-js-sdk": "^1.6.0"
},
"devDependencies": {
"prettier": "^3.0.0",
"vconsole": "^3.15.1"
}
"id": "shopro",
"name": "shopro",
"displayName": "Shopro商城",
"version": "3.1.0",
"description": "Shopro-B2C商城一套代码同时发行到iOS、Android、H5、微信小程序多个平台请使用手机扫码快速体验强大功能",
"scripts": {
"prettier": "prettier --write \"{pages,sheep}/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
},
"repository": "https://github.com/sheepjs/shop.git",
"keywords": [
"商城",
"B2C",
"Shopro",
"商城模板"
],
"author": "",
"license": "MIT",
"homepage": "https://www.shopro.top",
"dcloudext": {
"category": [
"前端页面模板",
"uni-app前端项目模板"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"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",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "u",
"vue3": "y"
}
}
}
},
"dependencies": {
"@hyoga/uni-socket.io": "^1.0.1",
"dayjs": "^1.11.9",
"lodash": "^4.17.21",
"luch-request": "^3.1.0",
"pinia": "2.1.4",
"pinia-plugin-persist-uni": "1.2.0",
"qs-canvas": "^1.0.11",
"weixin-js-sdk": "^1.6.0"
},
"devDependencies": {
"prettier": "^3.0.0",
"vconsole": "^3.15.1"
}
}

View File

@ -46,10 +46,6 @@
activeMenu: [Number, String],
pagination: Object,
});
onload(() => {
console.log('onload',props.data.children[activeMenu].children);
})
</script>
<style lang="scss" scoped>

View File

@ -1,9 +0,0 @@
<template>
<view>发布</view>
</template>
<script>
</script>
<style>
</style>

View File

@ -1,425 +1,70 @@
<template>
<view v-if="template" class="recharge flex align-items justify-start flex-column" :style="{
zIndex: '-1',
backgroundPosition: 'top',
backgroundRepeat: 'no-repeat',
}">
<s-layout title="团餐宝典" navbar="custom" tabbar="/pages/index/index" :bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar" onShareAppMessage :showFloatButton="true">
<view class="box" style="position: relative;">
<!-- logo
<view class="logo_css">
<view class="logo_name">团餐宝典</view>
<view class="logo_con">寻味餐饮铺 商机在线等</view>
</view>-->
<view class="top-content">
<!-- 省市
<view class="top_location">
<image style="width: 34rpx;height: 34rpx;margin-right: 10rpx;" src="/static/index/locationTop.png" mode=""></image>
<view>河南省 洛阳市</view>
</view>-->
<!-- 搜索
<view class="serch_top">
<view class="serch_top1">
<u-search class="u-search" v-model="keywords" placeholder="搜索您要找的内容" :showAction="false"
search-icon="/static/index/search.png" @change="search()">
</u-search>
</view>
</view>-->
</view>
<!-- 轮播图
<view>
<scroll-view scroll-x="true"></scroll-view>
</view>-->
</view>
</s-layout>
<!-- <tab-bar :tabBarShow="0"></tab-bar> -->
</view>
<s-tabbar v-if="tabbar !== ''" :path="tabbar" />
<!-- <view v-if="template">
<s-layout title="首页" navbar="custom" tabbar="/pages/index/index" :bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar" onShareAppMessage :showFloatButton="true">
</s-layout>
<s-block v-for="(item, index) in template.data" :key="index" :styles="item.style">
<s-block-item :type="item.type" :data="item.data" :styles="item.style" />
</s-block>
广告模块
<s-popup-image />
</view> -->
<view v-if="template">
<s-layout
title="首页"
navbar="custom"
tabbar="/pages/index/index"
:bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar"
onShareAppMessage
:showFloatButton="true"
>
<s-block v-for="(item, index) in template.data" :key="index" :styles="item.style">
<s-block-item :type="item.type" :data="item.data" :styles="item.style" />
</s-block>
<!-- 广告模块 -->
<s-popup-image />
</s-layout>
</view>
</template>
<script setup>
import {
computed,
ref,
reactive
} from 'vue';
import {
onLoad,
onPageScroll,
onPullDownRefresh
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import $share from '@/sheep/platform/share';
// import {
// dateWeek
// } from '../../utils/dateFormat'
import { computed } from 'vue';
import { onLoad, onPageScroll, onPullDownRefresh } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import $share from '@/sheep/platform/share';
const swiperList = ref([]);
const keywords = ref(''); // keywords
// tabBar
uni.hideTabBar({
fail: () => {},
});
// tabBar
uni.hideTabBar({
fail: () => {},
});
const template = computed(() => sheep.$store('app').template?.home);
const template = computed(() => sheep.$store('app').template?.home);
onLoad((options) => {
// #ifdef MP
//
if (options.scene) {
const sceneParams = decodeURIComponent(options.scene).split('=');
options[sceneParams[0]] = sceneParams[1];
}
// #endif
onLoad((options) => {
// #ifdef MP
//
if (options.scene) {
const sceneParams = decodeURIComponent(options.scene).split('=');
options[sceneParams[0]] = sceneParams[1];
}
// #endif
//
if (options.templateId) {
sheep.$store('app').init(options.templateId);
}
//
if (options.templateId) {
sheep.$store('app').init(options.templateId);
}
//
if (options.spm) {
$share.decryptSpm(options.spm);
}
//
if (options.spm) {
$share.decryptSpm(options.spm);
}
// ()
if (options.page) {
sheep.$router.go(decodeURIComponent(options.page));
}
});
// ()
if (options.page) {
sheep.$router.go(decodeURIComponent(options.page));
}
});
//
onPullDownRefresh(() => {
sheep.$store('app').init();
setTimeout(function () {
uni.stopPullDownRefresh();
}, 800);
});
//
onPullDownRefresh(() => {
sheep.$store('app').init();
setTimeout(function() {
uni.stopPullDownRefresh();
}, 800);
});
onPageScroll(() => {});
onPageScroll(() => {});
</script>
<style lang="scss" scoped>
.w-100 {
width: 100%;
}
.flex {
display: flex;
}
.justify-center {
justify-content: center;
}
.space-between {
justify-content: space-between;
}
.align-items {
align-items: center;
}
.flex-column {
flex-flow: column;
}
.justify-start {
justify-content: start;
}
.mar-top-30 {
margin-top: 30rpx;
}
.recharge {
width: 750rpx;
height: 100vh;
background-color: #f7f7f7;
background: linear-gradient(to bottom, #fcc74e 0%, #f7f7f7 50%);;
// background-image: url("https://naweigetetest2.hschool.com.cn/dyqc/bgx2.png");
background-size: 100%;
.box {
width: 690rpx;
margin-top: 30rpx;
.logo_css {
width: 430rpx;
height: 80rpx;
display: flex;
align-items: first baseline;
justify-content: flex-start;
// #ifdef MP-WEIXIN
margin-top: 65rpx;
// #endif
.logo_name{
color: #333333;
font-size: 38rpx;
font-weight: 400;
font-weight: bold;
font-family: PingFang SC-Bold;
line-height: 38rpx;
margin-right: 20rpx;
}
.logo_con {
color: #333333;
font-size: 26rpx;
font-weight: 400;
font-family: PingFang SC-Regular;
line-height: 26rpx;
}
}
.top-content{
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.top_location{
width: 45%;
display: flex;
align-items: center;
justify-content: flex-start;
}
.serch_top {
display: flex;
position: relative;
// top: 200rpx;
.serch_top1 {
margin-top: 10rpx;
margin-bottom: 30rpx;
position: relative;
width: 400rpx;
border-radius: 20rpx;
.u-search {
width: 100%;
border-radius: 20rpx;
background-color: #ffffff;
::v-deep .u-search__content {
background: rgba($color: #FFFFFF,$alpha: 1) !important;
}
::v-deep .u-search__content__input {
background-color: rgba($color: #FFFFFF,$alpha: 1) !important;
}
::v-deep .u-icon__img {
width: 36rpx !important;
height: 36rpx !important;
}
}
}
.imgstop_ye {
// margin-left: 30rpx;
width: 176rpx;
position: absolute;
right: -30rpx;
}
}
}
.hot {
// margin-top: 30rpx;
margin-bottom: 50rpx;
}
}
}
.white-space {
overflow: hidden;
/* 确保超出容器的文本被隐藏 */
white-space: nowrap;
/* 确保文本在一行内显示 */
text-overflow: ellipsis;
/* 使用省略号表示被截断的文本 */
width: 100%;
}
</style>
<style lang="scss">
.serch_top {
background-color: #ffffff;
.u-search {
border-radius: 20rpx;
::v-deep .u-search__content {
background: rgba($color: #FFFFFF,$alpha: 1) !important;
}
::v-deep .u-search__content__input {
background-color: rgba($color: #FFFFFF,$alpha: 1) !important;
}
::v-deep .u-icon__img {
width: 36rpx !important;
height: 36rpx !important;
}
}
}
.swiper_s {
width: 100%;
height: 100%;
}
.swiper-image {
width: 100%;
height: 100%;
border-radius: 36rpx;
object-fit: contain;
}
.text {
position: absolute;
/* 确保文字在模糊背景之上 */
z-index: 200;
/* 提高z-index以确保文字位于最上层 */
font-family: "YouSheBiaoTiHei";
font-weight: 400;
font-size: 38rpx;
color: #ffffff;
text-align: center;
width: 100%;
bottom: 70rpx;
transform: translateZ(0);
}
.fnon_tit {
position: absolute;
left: 5%;
z-index: 1;
width: 630rpx;
height: 117rpx;
line-height: 100rpx;
background: rgba(0, 0, 0, 0.24);
backdrop-filter: blur(4px);
border-radius: 36rpx;
bottom: 30rpx;
}
// .fnon_tit::before {
// content: "";
// position: absolute;
// top: 0;
// left: 0;
// right: 0;
// bottom: 0;
// backdrop-filter: blur(4px);
// /* */
// pointer-events: none;
// /* */
// border-radius: 36rpx;
// z-index: 0;
// /* */
// }
.dots {
position: absolute;
bottom: 50rpx;
width: 100%;
display: flex;
justify-content: center;
.dot {
background-color: #ffffff;
width: 30rpx;
height: 6rpx;
border-radius: 0;
margin-right: 10rpx;
&.active {
background: #0DAE11;
// transform: scale(0.9);
}
}
}
.line-row {
margin: 40rpx 0rpx;
height: 1rpx;
width: 100%;
background: #eeeeee;
}
.input {
text-align: right;
font-family: PingFang SC, PingFang SC;
font-size: 26rpx;
color: #343434;
line-height: 32rpx;
}
.plasty {
color: #999999;
font-weight: 300;
font-size: 28rpx;
}
.textarea_mph {
::v-deep .u-textarea {
height: 237rpx;
padding: 20rpx;
border: none;
font-size: 26rpx;
color: #9C9C9C;
background-color: #F8F8F8 !important;
border-radius: 18rpx;
}
}
.btn_1 {
width: 100%;
height: 90rpx;
background: #323232;
border-radius: 198rpx 198rpx 198rpx 198rpx;
font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
font-weight: 400;
font-size: 32rpx;
color: #BBFC5B;
line-height: 90rpx;
text-align: center;
margin-top: 50rpx;
}
</style>
<style></style>

View File

@ -1,6 +1,6 @@
<template>
<s-layout
title="个人中心"
title="我的"
tabbar="/pages/index/user"
navbar="custom"
:bgStyle="template.style?.background"

View File

@ -1,25 +0,0 @@
{
"setting": {
"es6": true,
"postcss": true,
"minified": true,
"uglifyFileName": false,
"enhance": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"useCompilerPlugins": false,
"minifyWXML": true
},
"compileType": "miniprogram",
"simulatorPluginLibVersion": {},
"packOptions": {
"ignore": [],
"include": []
},
"appid": "wx7186c52223ec81e8",
"editorSetting": {}
}

View File

@ -1,14 +0,0 @@
{
"libVersion": "3.8.11",
"projectname": "zhongtuanCatering",
"setting": {
"urlCheck": true,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,
"preloadBackgroundData": false,
"autoAudits": false,
"showShadowRootInWxmlPanel": true,
"compileHotReLoad": false
}
}

View File

@ -1,14 +1,12 @@
<template>
<view>
<s-image-block v-if="type === 'imageBlock'" :data="data" :styles="styles" />
<!-- 首页顶部轮播图 -->
<s-image-banner v-if="type === 'imageBanner'" :data="data" :styles="styles" />
<s-video-block v-if="type === 'videoPlayer'" :data="data" :styles="styles" />
<s-image-cube v-if="type === 'imageCube'" :data="data" :styles="styles" />
<s-notice-block v-if="type === 'noticeBlock'" :data="data" />
<s-search-block v-if="type === 'searchBlock'" :data="data" :navbar="false" />
<!-- 首页精选榜单&查看更多 -->
<s-title-block v-if="type === 'titleBlock'" :data="data" :styles="styles" />
<s-line-block v-if="type === 'lineBlock'" :data="data" />
@ -18,11 +16,9 @@
<s-user-card v-if="type === 'userCard'" />
<s-wallet-card v-if="type === 'walletCard'" />
<!-- 个人中心的订单的那一行 -->
<s-order-card v-if="type === 'orderCard'" :data="data" />
<s-coupon-card v-if="type === 'couponCard'" />
<!-- 首页精选商品列表 -->
<s-goods-card v-if="type === 'goodsCard'" :data="data" :styles="styles" />
<s-score-block v-if="type === 'scoreGoods'" :data="data" :styles="styles" />
<s-goods-shelves v-if="type === 'goodsShelves'" :data="data" :styles="styles" />

View File

@ -1,7 +1,7 @@
<template>
<!-- 商品卡片 -->
<view>
<!-- 1 100%宽卡片列表 单列展示-->
<!-- 1 100%宽卡片列表-->
<view v-if="mode === 1 && state.goodsList.length" class="goods-sl-box">
<view
class="goods-box"

View File

@ -7,7 +7,6 @@
@tap="sheep.$router.go(item.url)"
>
<image class="cube-img" :src="sheep.$url.cdn(item.src)" mode="aspectFill"></image>
s-image-cube
</view>
</view>
</view>

View File

@ -21,7 +21,6 @@
</view>
</su-popup>
</view>
<!-- <view>11</view> -->
</view>
</template>

View File

@ -12,8 +12,7 @@ if (process.env.NODE_ENV === 'development') {
if (typeof baseUrl === 'undefined') {
console.error('请检查.env配置文件是否存在');
} else {
// console.log(`[Shopro ${version}] https://www.sheepjs.com/`);
console.log(`[Shopro ${version}] https://jiangxiaoxian.hschool.com.cn/`);
console.log(`[Shopro ${version}] https://www.sheepjs.com/`);
}
export const apiPath = import.meta.env.SHOPRO_API_PATH;

View File

@ -1,126 +1,130 @@
<template>
<image v-if="!state.isError" class="su-img" :style="customStyle" :draggable="false" :mode="mode"
:src="sheep.$url.cdn(src)" @tap="onImgPreview" @load="onImgLoad" @error="onImgError">
<!-- su-image -->
</image>
<image
v-if="!state.isError"
class="su-img"
:style="customStyle"
:draggable="false"
:mode="mode"
:src="sheep.$url.cdn(src)"
@tap="onImgPreview"
@load="onImgLoad"
@error="onImgError"
></image>
</template>
<script setup>
/**
* 图片组件
*
* @property {String} src - 图片地址
* @property {Number} mode - 裁剪方式
* @property {String} isPreview - 是否开启预览
* @property {Number} previewList - 预览列表
* @property {String} current - 预览首张下标
*
* @event {Function} load - 图片加载完毕触发
* @event {Function} error - 图片加载错误触发
*
*/
/**
* 图片组件
*
* @property {String} src - 图片地址
* @property {Number} mode - 裁剪方式
* @property {String} isPreview - 是否开启预览
* @property {Number} previewList - 预览列表
* @property {String} current - 预览首张下标
*
* @event {Function} load - 图片加载完毕触发
* @event {Function} error - 图片加载错误触发
*
*/
import {
reactive,
computed
} from 'vue';
import sheep from '@/sheep';
import { reactive, computed } from 'vue';
import sheep from '@/sheep';
//
const state = reactive({
isError: false,
imgHeight: 600,
});
//
const state = reactive({
isError: false,
imgHeight: 600,
});
//
const props = defineProps({
src: {
type: String,
default: '',
},
errorSrc: {
type: String,
default: '/assets/addons/shopro/uniapp/empty_network.png',
},
mode: {
type: String,
default: 'widthFix',
},
isPreview: {
type: Boolean,
default: false,
},
previewList: {
type: Array,
default () {
return [];
},
},
current: {
type: Number,
default: -1,
},
height: {
type: Number,
default: 0,
},
width: {
type: Number,
default: 0,
},
radius: {
type: Number,
default: 0,
},
});
//
const props = defineProps({
src: {
type: String,
default: '',
},
errorSrc: {
type: String,
default: '/assets/addons/shopro/uniapp/empty_network.png',
},
mode: {
type: String,
default: 'widthFix',
},
isPreview: {
type: Boolean,
default: false,
},
previewList: {
type: Array,
default() {
return [];
},
},
current: {
type: Number,
default: -1,
},
height: {
type: Number,
default: 0,
},
width: {
type: Number,
default: 0,
},
radius: {
type: Number,
default: 0,
},
});
const emits = defineEmits(['load', 'error']);
const emits = defineEmits(['load', 'error']);
const customStyle = computed(() => {
return {
height: (props.height || state.imgHeight) + 'rpx',
width: props.width ? props.width + 'rpx' : '100%',
borderRadius: props.radius ? props.radius + 'rpx' : '',
};
});
const customStyle = computed(() => {
return {
height: (props.height || state.imgHeight) + 'rpx',
width: props.width ? props.width + 'rpx' : '100%',
borderRadius: props.radius ? props.radius + 'rpx' : '',
};
});
//
function onImgLoad(e) {
if (props.height === 0) {
state.imgHeight = (e.detail.height / e.detail.width) * 750;
}
}
//
function onImgLoad(e) {
if (props.height === 0) {
state.imgHeight = (e.detail.height / e.detail.width) * 750;
}
}
//
function onImgError(e) {
state.isError = true;
emits('error', e);
}
//
function onImgError(e) {
state.isError = true;
emits('error', e);
}
//
function onImgPreview() {
if (!props.isPreview) return;
uni.previewImage({
urls: props.previewList.length < 1 ? [props.src] : props.previewList,
current: props.current,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function(data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function(err) {
console.log(err.errMsg);
},
},
});
}
//
function onImgPreview() {
if (!props.isPreview) return;
uni.previewImage({
urls: props.previewList.length < 1 ? [props.src] : props.previewList,
current: props.current,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function (data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function (err) {
console.log(err.errMsg);
},
},
});
}
</script>
<style lang="scss" scoped>
.su-img {
position: relative;
width: 100%;
height: 100%;
display: block;
}
</style>
.su-img {
position: relative;
width: 100%;
height: 100%;
display: block;
}
</style>

View File

@ -1,480 +1,507 @@
<template>
<!-- 首页banner图 -->
<view>
<view class="ui-swiper" :class="[props.mode, props.bg, props.ui]">
<swiper :circular="props.circular" :current="state.cur" :autoplay="props.autoplay && !state.videoPlaySataus"
:interval="props.interval" :duration="props.duration" @transition="transition"
@animationfinish="animationfinish" :style="customStyle" @change="swiperChange">
<swiper-item class="swiper-item" v-for="(item, index) in props.list" :key="index"
:class="{ cur: state.cur == index }" @tap="onSwiperItem(item)">
<view class="ui-swiper-main">
<image v-if="item.type === 'image'" class="swiper-image" :mode="props.imageMode" :src="item.src"
width="100%" height="100%" @load="onImgLoad"></image>
<su-video v-else :ref="(el) => (refs.videoRef[`video_${index}`] = el)"
:poster="sheep.$url.cdn(item.poster)" :src="sheep.$url.cdn(item.src)" :index="index"
:moveX="state.moveX" :initialTime="item.currentTime || 0" @videoTimeupdate="videoTimeupdate"
:height="seizeHeight"></su-video>
</view>
</swiper-item>
</swiper>
<template v-if="!state.videoPlaySataus">
<view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle != 'tag'">
<view class="line-box" v-for="(item, index) in props.list" :key="index"
:class="[state.cur == index ? 'cur' : '', props.dotCur]"></view>
</view>
<view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle == 'tag'">
<view class="ui-tag radius-lg" :class="[props.dotCur]"
style="pointer-events: none; padding: 0 10rpx">
<view style="transform: scale(0.7)">{{ state.cur + 1 }} / {{ props.list.length }}</view>
</view>
</view>
</template>
</view>
</view>
<view>
<view class="ui-swiper" :class="[props.mode, props.bg, props.ui]">
<swiper
:circular="props.circular"
:current="state.cur"
:autoplay="props.autoplay && !state.videoPlaySataus"
:interval="props.interval"
:duration="props.duration"
@transition="transition"
@animationfinish="animationfinish"
:style="customStyle"
@change="swiperChange"
>
<swiper-item
class="swiper-item"
v-for="(item, index) in props.list"
:key="index"
:class="{ cur: state.cur == index }"
@tap="onSwiperItem(item)"
>
<view class="ui-swiper-main">
<image
v-if="item.type === 'image'"
class="swiper-image"
:mode="props.imageMode"
:src="item.src"
width="100%"
height="100%"
@load="onImgLoad"
></image>
<su-video
v-else
:ref="(el) => (refs.videoRef[`video_${index}`] = el)"
:poster="sheep.$url.cdn(item.poster)"
:src="sheep.$url.cdn(item.src)"
:index="index"
:moveX="state.moveX"
:initialTime="item.currentTime || 0"
@videoTimeupdate="videoTimeupdate"
:height="seizeHeight"
></su-video>
</view>
</swiper-item>
</swiper>
<template v-if="!state.videoPlaySataus">
<view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle != 'tag'">
<view
class="line-box"
v-for="(item, index) in props.list"
:key="index"
:class="[state.cur == index ? 'cur' : '', props.dotCur]"
></view>
</view>
<view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle == 'tag'">
<view
class="ui-tag radius-lg"
:class="[props.dotCur]"
style="pointer-events: none; padding: 0 10rpx"
>
<view style="transform: scale(0.7)">{{ state.cur + 1 }} / {{ props.list.length }}</view>
</view>
</view>
</template>
</view>
</view>
</template>
<script setup>
/**
* 轮播组件
*
* @property {Boolean} circular = false - 是否采用衔接滑动即播放到末尾后重新回到开头
* @property {Boolean} autoplay = true - 是否自动切换
* @property {Number} interval = 5000 - 自动切换时间间隔
* @property {Number} duration = 500 - 滑动动画时长,app-nvue不支持
* @property {Array} list = [] - 轮播数据
* @property {String} ui = '' - 样式class
* @property {String} mode - 模式
* @property {String} dotStyle - 指示点样式
* @property {String} dotCur= 'ui-BG-Main' - 当前指示点样式,默认主题色
* @property {String} bg - 背景
* @property {String} height = 300 - 组件高度
* @property {String} imgHeight = 300 - 图片高度
*
* @example list = [{url:'跳转路径',urlType:'跳转方式',type:'轮播类型',src:'轮播内容地址',poster:'视频必传'}]
*/
/**
* 轮播组件
*
* @property {Boolean} circular = false - 是否采用衔接滑动即播放到末尾后重新回到开头
* @property {Boolean} autoplay = true - 是否自动切换
* @property {Number} interval = 5000 - 自动切换时间间隔
* @property {Number} duration = 500 - 滑动动画时长,app-nvue不支持
* @property {Array} list = [] - 轮播数据
* @property {String} ui = '' - 样式class
* @property {String} mode - 模式
* @property {String} dotStyle - 指示点样式
* @property {String} dotCur= 'ui-BG-Main' - 当前指示点样式,默认主题色
* @property {String} bg - 背景
* @property {String} height = 300 - 组件高度
* @property {String} imgHeight = 300 - 图片高度
*
* @example list = [{url:'跳转路径',urlType:'跳转方式',type:'轮播类型',src:'轮播内容地址',poster:'视频必传'}]
*/
import {
reactive,
computed
} from 'vue';
import sheep from '@/sheep';
import {
clone
} from 'lodash';
import { reactive, computed } from 'vue';
import sheep from '@/sheep';
import { clone } from 'lodash';
//
const state = reactive({
imgHeight: 0,
cur: 0,
moveX: 0,
videoPlaySataus: false,
heightList: [],
});
//
const state = reactive({
imgHeight: 0,
cur: 0,
moveX: 0,
videoPlaySataus: false,
heightList: [],
});
const refs = reactive({
videoRef: {},
});
const refs = reactive({
videoRef: {},
});
//
//
const props = defineProps({
circular: {
type: Boolean,
default: true,
},
autoplay: {
type: Boolean,
default: false,
},
interval: {
type: Number,
default: 5000,
},
duration: {
type: Number,
default: 500,
},
mode: {
type: String,
default: 'default',
},
imageMode: {
type: String,
default: 'scaleToFill',
},
list: {
type: Array,
default () {
return [];
},
},
dotStyle: {
type: String,
default: 'long', //default long tag
},
dotCur: {
type: String,
default: 'ss-bg-opactity-block',
},
bg: {
type: String,
default: 'bg-none',
},
height: {
type: Number,
default: 0,
},
imgHeight: {
type: Number,
default: 0,
},
imgTopRadius: {
type: Number,
default: 0,
},
imgBottomRadius: {
type: Number,
default: 0,
},
isPreview: {
type: Boolean,
default: false,
},
seizeHeight: {
type: Number,
default: 200,
},
});
const props = defineProps({
circular: {
type: Boolean,
default: true,
},
autoplay: {
type: Boolean,
default: false,
},
interval: {
type: Number,
default: 5000,
},
duration: {
type: Number,
default: 500,
},
mode: {
type: String,
default: 'default',
},
imageMode: {
type: String,
default: 'scaleToFill',
},
list: {
type: Array,
default() {
return [];
},
},
dotStyle: {
type: String,
default: 'long', //default long tag
},
dotCur: {
type: String,
default: 'ss-bg-opactity-block',
},
bg: {
type: String,
default: 'bg-none',
},
height: {
type: Number,
default: 0,
},
imgHeight: {
type: Number,
default: 0,
},
imgTopRadius: {
type: Number,
default: 0,
},
imgBottomRadius: {
type: Number,
default: 0,
},
isPreview: {
type: Boolean,
default: false,
},
seizeHeight: {
type: Number,
default: 200,
},
});
// current change
const swiperChange = (e) => {
if (e.detail.source !== 'touch' && e.detail.source !== 'autoplay') return;
state.cur = e.detail.current;
state.videoPlaySataus = false;
if (props.list[state.cur].type === 'video') {
refs.videoRef[`video_${state.cur}`].pausePlay();
}
};
//
const onSwiperItem = (item) => {
if (item.type === 'video') {
state.videoPlaySataus = true;
} else {
sheep.$router.go(item.url);
onPreview();
}
};
// current change
const swiperChange = (e) => {
if (e.detail.source !== 'touch' && e.detail.source !== 'autoplay') return;
state.cur = e.detail.current;
state.videoPlaySataus = false;
if (props.list[state.cur].type === 'video') {
refs.videoRef[`video_${state.cur}`].pausePlay();
}
};
//
const onSwiperItem = (item) => {
if (item.type === 'video') {
state.videoPlaySataus = true;
} else {
sheep.$router.go(item.url);
onPreview();
}
};
const onPreview = () => {
if (!props.isPreview) return;
let previewImage = clone(props.list);
previewImage.forEach((item, index) => {
if (item.type === 'video') {
previewImage.splice(index, 1);
}
})
// props.list.splice(
// props.list.findIndex((item) => item.type === 'video'),
// 1,
// );
// let previewImage = props.list;
uni.previewImage({
urls: previewImage.length < 1 ?
[props.src] :
previewImage.reduce((pre, cur) => {
pre.push(cur.src);
return pre;
}, []),
current: state.cur,
// longPressActions: {
// itemList: ['', '', ''],
// success: function (data) {
// console.log('' + (data.tapIndex + 1) + ',' + (data.index + 1) + '');
// },
// fail: function (err) {
// console.log(err.errMsg);
// },
// },
});
};
//
const onPreview = () => {
if (!props.isPreview) return;
let previewImage = clone(props.list);
previewImage.forEach((item,index) => {
if(item.type === 'video') {
previewImage.splice(index, 1);
}
})
// props.list.splice(
// props.list.findIndex((item) => item.type === 'video'),
// 1,
// );
// let previewImage = props.list;
uni.previewImage({
urls:
previewImage.length < 1
? [props.src]
: previewImage.reduce((pre, cur) => {
pre.push(cur.src);
return pre;
}, []),
current: state.cur,
// longPressActions: {
// itemList: ['', '', ''],
// success: function (data) {
// console.log('' + (data.tapIndex + 1) + ',' + (data.index + 1) + '');
// },
// fail: function (err) {
// console.log(err.errMsg);
// },
// },
});
};
//
// swiper-item transition
const transition = (e) => {
// #ifdef APP-PLUS
state.moveX = e.detail.dx;
// #endif
};
// swiper-item transition
const transition = (e) => {
// #ifdef APP-PLUS
state.moveX = e.detail.dx;
// #endif
};
// animationfinish
const animationfinish = (e) => {
state.moveX = 0;
};
// animationfinish
const animationfinish = (e) => {
state.moveX = 0;
};
const videoTimeupdate = (e) => {
props.list[state.cur].currentTime = e.detail.currentTime;
};
const videoTimeupdate = (e) => {
props.list[state.cur].currentTime = e.detail.currentTime;
};
//
const customStyle = computed(() => {
let height;
//
const customStyle = computed(() => {
let height;
//
if (props.height !== 0) {
height = props.height;
}
//
if (props.height !== 0) {
height = props.height;
}
//
if (props.height === 0) {
//
if (state.imgHeight !== 0) {
height = state.imgHeight;
} else if (props.seizeHeight !== 0) {
height = props.seizeHeight;
}
}
//
if (props.height === 0) {
//
if (state.imgHeight !== 0) {
height = state.imgHeight;
} else if (props.seizeHeight !== 0) {
height = props.seizeHeight;
}
}
return {
height: height + 'rpx',
};
});
return {
height: height + 'rpx',
};
});
//
function onImgLoad(e) {
if (props.height === 0) {
let newHeight = (e.detail.height / e.detail.width) * 750;
if (state.imgHeight < newHeight) {
state.imgHeight = newHeight;
}
}
}
//
function onImgLoad(e) {
if (props.height === 0) {
let newHeight = (e.detail.height / e.detail.width) * 750;
if (state.imgHeight < newHeight) {
state.imgHeight = newHeight;
}
}
}
</script>
<style lang="scss" scoped>
.ui-swiper {
position: relative;
.ui-swiper {
position: relative;
.ui-swiper-main {
width: 100%;
height: 100%;
position: relative;
top: 400rpx;
}
.ui-swiper-main {
width: 100%;
height: 100%;
}
.ui-swiper-main .swiper-image {
width: 100%;
height: 100%;
}
.ui-swiper-main .swiper-image {
width: 100%;
height: 100%;
}
.ui-swiper-dot {
position: absolute;
width: 100%;
bottom: 20rpx;
height: 30rpx;
display: flex;
align-items: center;
justify-content: center;
.ui-swiper-dot {
position: absolute;
width: 100%;
bottom: 20rpx;
height: 30rpx;
display: flex;
align-items: center;
justify-content: center;
&.default .line-box {
display: inline-flex;
border-radius: 50rpx;
width: 6px;
height: 6px;
border: 2px solid transparent;
margin: 0 10rpx;
opacity: 0.3;
position: relative;
justify-content: center;
align-items: center;
&.default .line-box {
display: inline-flex;
border-radius: 50rpx;
width: 6px;
height: 6px;
border: 2px solid transparent;
margin: 0 10rpx;
opacity: 0.3;
position: relative;
justify-content: center;
align-items: center;
&.cur {
width: 8px;
height: 8px;
opacity: 1;
border: 0px solid transparent;
}
&.cur {
width: 8px;
height: 8px;
opacity: 1;
border: 0px solid transparent;
}
&.cur::after {
content: '';
border-radius: 50rpx;
width: 4px;
height: 4px;
background-color: #fff;
}
}
&.cur::after {
content: '';
border-radius: 50rpx;
width: 4px;
height: 4px;
background-color: #fff;
}
}
&.long .line-box {
display: inline-block;
border-radius: 100rpx;
width: 6px;
height: 6px;
margin: 0 10rpx;
opacity: 0.3;
position: relative;
&.long .line-box {
display: inline-block;
border-radius: 100rpx;
width: 6px;
height: 6px;
margin: 0 10rpx;
opacity: 0.3;
position: relative;
&.cur {
width: 24rpx;
opacity: 1;
}
&.cur {
width: 24rpx;
opacity: 1;
}
&.cur::after {}
}
&.cur::after {
}
}
&.line {
bottom: 20rpx;
&.line {
bottom: 20rpx;
.line-box {
display: inline-block;
width: 30px;
height: 3px;
opacity: 0.3;
position: relative;
.line-box {
display: inline-block;
width: 30px;
height: 3px;
opacity: 0.3;
position: relative;
&.cur {
opacity: 1;
}
}
}
&.cur {
opacity: 1;
}
}
}
&.tag {
justify-content: flex-end;
position: absolute;
bottom: 20rpx;
right: 20rpx;
}
}
&.tag {
justify-content: flex-end;
position: absolute;
bottom: 20rpx;
right: 20rpx;
}
}
&.card {
.swiper-item {
width: 610rpx !important;
left: 70rpx;
box-sizing: border-box;
padding: 20rpx 0rpx 60rpx;
overflow: initial;
}
&.card {
.swiper-item {
width: 610rpx !important;
left: 70rpx;
box-sizing: border-box;
padding: 20rpx 0rpx 60rpx;
overflow: initial;
}
.swiper-item .ui-swiper-main {
width: 100%;
display: block;
height: 100%;
transform: scale(0.9);
transition: all 0.2s ease-in 0s;
position: relative;
background-size: cover;
.swiper-item .ui-swiper-main {
width: 100%;
display: block;
height: 100%;
transform: scale(0.9);
transition: all 0.2s ease-in 0s;
position: relative;
background-size: cover;
.swiper-image {
height: 100%;
}
}
.swiper-image {
height: 100%;
}
}
.swiper-item .ui-swiper-main::before {
content: '';
display: block;
background: inherit;
filter: blur(5px);
position: absolute;
width: 100%;
height: 100%;
top: 10rpx;
left: 10rpx;
z-index: -1;
opacity: 0.3;
transform-origin: 0 0;
transform: scale(1, 1);
}
.swiper-item .ui-swiper-main::before {
content: '';
display: block;
background: inherit;
filter: blur(5px);
position: absolute;
width: 100%;
height: 100%;
top: 10rpx;
left: 10rpx;
z-index: -1;
opacity: 0.3;
transform-origin: 0 0;
transform: scale(1, 1);
}
.swiper-item.cur .ui-swiper-main {
transform: scale(1);
transition: all 0.2s ease-in 0s;
}
.swiper-item.cur .ui-swiper-main {
transform: scale(1);
transition: all 0.2s ease-in 0s;
}
.ui-swiper-dot.tag {
position: absolute;
bottom: 85rpx;
right: 75rpx;
}
}
.ui-swiper-dot.tag {
position: absolute;
bottom: 85rpx;
right: 75rpx;
}
}
&.hotelCard {
.swiper-item {
width: 650rpx !important;
left: 30rpx;
box-sizing: border-box;
padding: 0rpx 0rpx 50rpx;
overflow: initial;
}
&.hotelCard {
.swiper-item {
width: 650rpx !important;
left: 30rpx;
box-sizing: border-box;
padding: 0rpx 0rpx 50rpx;
overflow: initial;
}
.swiper-item .ui-swiper-main {
width: 100%;
display: block;
height: 100%;
transform: scale(0.9);
opacity: 0.8;
transition: all 0.2s ease-in 0s;
position: relative;
background-size: cover;
.swiper-item .ui-swiper-main {
width: 100%;
display: block;
height: 100%;
transform: scale(0.9);
opacity: 0.8;
transition: all 0.2s ease-in 0s;
position: relative;
background-size: cover;
.swiper-image {
width: 100%;
height: 400rpx;
}
}
.swiper-image {
width: 100%;
height: 400rpx;
}
}
.swiper-item .ui-swiper-main::before {
content: '';
display: block;
background: inherit;
filter: blur(5px);
position: absolute;
width: 100%;
height: 100%;
top: 10rpx;
left: 10rpx;
z-index: -1;
opacity: 0.3;
transform-origin: 0 0;
transform: scale(1, 1);
}
.swiper-item .ui-swiper-main::before {
content: '';
display: block;
background: inherit;
filter: blur(5px);
position: absolute;
width: 100%;
height: 100%;
top: 10rpx;
left: 10rpx;
z-index: -1;
opacity: 0.3;
transform-origin: 0 0;
transform: scale(1, 1);
}
.swiper-item.cur .ui-swiper-main {
transform: scale(1);
transition: all 0.2s ease-in 0s;
opacity: 1;
}
.swiper-item.cur .ui-swiper-main {
transform: scale(1);
transition: all 0.2s ease-in 0s;
opacity: 1;
}
.ui-swiper-dot {
display: none;
}
}
.ui-swiper-dot {
display: none;
}
}
&.hotelDetail {
.swiper-item {
width: 690rpx !important;
left: 30rpx;
box-sizing: border-box;
padding: 20rpx 0rpx;
overflow: initial;
}
&.hotelDetail {
.swiper-item {
width: 690rpx !important;
left: 30rpx;
box-sizing: border-box;
padding: 20rpx 0rpx;
overflow: initial;
}
.swiper-item .ui-swiper-main {
width: 100%;
display: block;
height: 100%;
transform: scale(0.96);
transition: all 0.2s ease-in 0s;
position: relative;
background-size: cover;
.swiper-item .ui-swiper-main {
width: 100%;
display: block;
height: 100%;
transform: scale(0.96);
transition: all 0.2s ease-in 0s;
position: relative;
background-size: cover;
.swiper-image {
height: 100%;
}
}
.swiper-image {
height: 100%;
}
}
.swiper-item.cur .ui-swiper-main {
transform: scale(0.96);
transition: all 0.2s ease-in 0s;
}
}
}
</style>
.swiper-item.cur .ui-swiper-main {
transform: scale(0.96);
transition: all 0.2s ease-in 0s;
}
}
}
</style>

View File

@ -20,7 +20,6 @@
@ended="end"
:poster="poster"
>
<!-- su-video -->
</video>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB