使用商城源码,但是不全面升级为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

26
main.js
View File

@ -1,23 +1,15 @@
import App from './App'; import App from './App';
import { import { createSSRApp } from 'vue';
createSSRApp import { setupPinia } from './sheep/store';
} from 'vue';
import {
setupPinia
} from './sheep/store';
import { createPinia } from 'pinia'
import uView from 'uview-plus';
export function createApp() { 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);
return { setupPinia(app);
app,
}; return {
app,
};
} }

View File

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

View File

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

View File

@ -46,10 +46,6 @@
activeMenu: [Number, String], activeMenu: [Number, String],
pagination: Object, pagination: Object,
}); });
onload(() => {
console.log('onload',props.data.children[activeMenu].children);
})
</script> </script>
<style lang="scss" scoped> <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> <template>
<view v-if="template" class="recharge flex align-items justify-start flex-column" :style="{ <view v-if="template">
zIndex: '-1', <s-layout
backgroundPosition: 'top', title="首页"
backgroundRepeat: 'no-repeat', navbar="custom"
}"> tabbar="/pages/index/index"
<s-layout title="团餐宝典" navbar="custom" tabbar="/pages/index/index" :bgStyle="template.style?.background" :bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar" onShareAppMessage :showFloatButton="true"> :navbarStyle="template.style?.navbar"
<view class="box" style="position: relative;"> onShareAppMessage
<!-- logo :showFloatButton="true"
<view class="logo_css"> >
<view class="logo_name">团餐宝典</view> <s-block v-for="(item, index) in template.data" :key="index" :styles="item.style">
<view class="logo_con">寻味餐饮铺 商机在线等</view> <s-block-item :type="item.type" :data="item.data" :styles="item.style" />
</view>--> </s-block>
<view class="top-content"> <!-- 广告模块 -->
<!-- 省市 <s-popup-image />
<view class="top_location"> </s-layout>
<image style="width: 34rpx;height: 34rpx;margin-right: 10rpx;" src="/static/index/locationTop.png" mode=""></image> </view>
<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> -->
</template> </template>
<script setup> <script setup>
import { import { computed } from 'vue';
computed, import { onLoad, onPageScroll, onPullDownRefresh } from '@dcloudio/uni-app';
ref, import sheep from '@/sheep';
reactive import $share from '@/sheep/platform/share';
} 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'
const swiperList = ref([]); // tabBar
const keywords = ref(''); // keywords uni.hideTabBar({
fail: () => {},
});
// tabBar const template = computed(() => sheep.$store('app').template?.home);
uni.hideTabBar({
fail: () => {},
});
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.templateId) {
// sheep.$store('app').init(options.templateId);
if (options.scene) { }
const sceneParams = decodeURIComponent(options.scene).split('=');
options[sceneParams[0]] = sceneParams[1];
}
// #endif
// //
if (options.templateId) { if (options.spm) {
sheep.$store('app').init(options.templateId); $share.decryptSpm(options.spm);
} }
// // ()
if (options.spm) { if (options.page) {
$share.decryptSpm(options.spm); sheep.$router.go(decodeURIComponent(options.page));
} }
});
// () //
if (options.page) { onPullDownRefresh(() => {
sheep.$router.go(decodeURIComponent(options.page)); sheep.$store('app').init();
} setTimeout(function () {
}); uni.stopPullDownRefresh();
}, 800);
});
// onPageScroll(() => {});
onPullDownRefresh(() => {
sheep.$store('app').init();
setTimeout(function() {
uni.stopPullDownRefresh();
}, 800);
});
onPageScroll(() => {});
</script> </script>
<style lang="scss" scoped> <style></style>
.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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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