Ver Fonte

完成视频 滑动的问题

XSXS há 1 semana atrás
pai
commit
6295eb05bb

+ 533 - 0
components/DomVideoPlayer/DomVideoPlayer.vue

@@ -0,0 +1,533 @@
+<!-- eslint-disable -->
+<template>
+  <view
+    class="player-wrapper"
+    :id="videoWrapperId"
+    :parentId="id"
+    :randomNum="randomNum"
+    :change:randomNum="domVideoPlayer.randomNumChange"
+    :viewportProps="viewportProps"
+    :change:viewportProps="domVideoPlayer.viewportChange"
+    :videoSrc="videoSrc"
+    :change:videoSrc="domVideoPlayer.initVideoPlayer"
+    :command="eventCommand"
+    :change:command="domVideoPlayer.triggerCommand"
+    :func="renderFunc"
+    :change:func="domVideoPlayer.triggerFunc"
+  />
+</template>
+
+<script>
+export default {
+  props: {
+    src: {
+      type: String,
+      default: ''
+    },
+    autoplay: {
+      type: Boolean,
+      default: false
+    },
+    loop: {
+      type: Boolean,
+      default: false
+    },
+    controls: {
+      type: Boolean,
+      default: false
+    },
+    objectFit: {
+      type: String,
+      default: 'contain'
+    },
+    muted: {
+      type: Boolean,
+      default: false
+    },
+    playbackRate: {
+      type: Number,
+      default: 1
+    },
+    isLoading: {
+      type: Boolean,
+      default: false
+    },
+    poster: {
+      type: String,
+      default: ''
+    },
+    id: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      randomNum: Math.floor(Math.random() * 100000000),
+      videoSrc: '',
+      // 父组件向子组件传递的事件指令(video的原生事件)
+      eventCommand: null,
+      // 父组件传递过来的,对 renderjs 层的函数执行(对视频控制的自定义事件)
+      renderFunc: {
+        name: null,
+        params: null
+      },
+      // 提供给父组件进行获取的视频属性
+      currentTime: 0,
+      duration: 0,
+      playing: false
+    }
+  },
+  watch: {
+    // 监听视频资源地址更新
+    src: {
+      handler(val) {
+        if (!val) return
+        setTimeout(() => {
+          this.videoSrc = val
+        }, 0)
+      },
+      immediate: true
+    }
+  },
+  computed: {
+    videoWrapperId() {
+      return `video-wrapper-${this.randomNum}`
+    },
+    // 聚合视图层的所有数据变化,传给renderjs的渲染层
+    viewportProps() {
+      return {
+        autoplay: this.autoplay,
+        muted: this.muted,
+        controls: this.controls,
+        loop: this.loop,
+        objectFit: this.objectFit,
+        poster: this.poster,
+        isLoading: this.isLoading,
+        playbackRate: this.playbackRate
+      }
+    }
+  },
+  // 方法
+  methods: {
+    // 传递事件指令给父组件
+    eventEmit({ event, data }) {
+      this.$emit(event, data)
+    },
+    // 修改view视图层的data数据
+    setViewData({ key, value }) {
+      key && this.$set(this, key, value)
+    },
+    // 重置事件指令
+    resetEventCommand() {
+      this.eventCommand = null
+    },
+    // 播放指令
+    play() {
+      this.eventCommand = 'play'
+    },
+    // 暂停指令
+    pause() {
+      this.eventCommand = 'pause'
+    },
+    // 重置自定义函数指令
+    resetFunc() {
+      this.renderFunc = {
+        name: null,
+        params: null
+      }
+    },
+    // 自定义函数 - 移除视频
+    remove(params) {
+      this.renderFunc = {
+        name: 'removeHandler',
+        params
+      }
+    },
+    // 自定义函数 - 全屏播放
+    fullScreen(params) {
+      this.renderFunc = {
+        name: 'fullScreenHandler',
+        params
+      }
+    },
+    // 自定义函数 - 跳转到指定时间点
+    toSeek(sec, isDelay = false) {
+      this.renderFunc = {
+        name: 'toSeekHandler',
+        params: { sec, isDelay }
+      }
+    }
+  }
+}
+</script>
+
+
+<script module="domVideoPlayer" lang="renderjs">
+const PLAYER_ID = 'DOM_VIDEO_PLAYER'
+export default {
+  data() {
+    return {
+      num: '',
+      videoEl: null,
+      loadingEl: null,
+      // 延迟生效的函数
+      delayFunc: null,
+      renderProps: {}
+    }
+  },
+  computed: {
+    playerId() {
+      return `${PLAYER_ID}_${this.num}`
+    },
+    wrapperId() {
+      return `video-wrapper-${this.num}`
+    }
+  },
+  methods: {
+    isApple() {
+      const ua = navigator.userAgent.toLowerCase()
+      return ua.indexOf('iphone') !== -1 || ua.indexOf('ipad') !== -1
+    },
+    async initVideoPlayer(src) {
+      this.delayFunc = null
+      await this.$nextTick()
+      if (!src) return
+      if (this.videoEl) {
+        // 切换视频源
+        if (!this.isApple() && this.loadingEl) {
+          this.loadingEl.style.display = 'block'
+        }
+        this.videoEl.src = src
+        return
+      }
+
+      const videoEl = document.createElement('video')
+      this.videoEl = videoEl
+      // 开始监听视频相关事件
+      this.listenVideoEvent()
+
+      const { autoplay, muted, controls, loop, playbackRate, objectFit, poster } = this.renderProps
+      videoEl.src = src
+      videoEl.autoplay = autoplay
+      videoEl.controls = controls
+      videoEl.loop = loop
+      videoEl.muted = muted
+      videoEl.playbackRate = playbackRate
+      videoEl.id = this.playerId
+      // videoEl.setAttribute('x5-video-player-type', 'h5')
+      videoEl.setAttribute('preload', 'auto')
+      videoEl.setAttribute('playsinline', true)
+      videoEl.setAttribute('webkit-playsinline', true)
+      videoEl.setAttribute('crossorigin', 'anonymous')
+      videoEl.setAttribute('controlslist', 'nodownload')
+      videoEl.setAttribute('disablePictureInPicture', true)
+      videoEl.style.objectFit = objectFit
+      poster && (videoEl.poster = poster)
+      videoEl.style.width = '100%'
+      videoEl.style.height = '100%'
+
+      // 插入视频元素
+      // document.getElementById(this.wrapperId).appendChild(videoEl)
+      const playerWrapper = document.getElementById(this.wrapperId)
+      playerWrapper.insertBefore(videoEl, playerWrapper.firstChild)
+
+      // 插入loading 元素(遮挡安卓的默认加载过程中的黑色播放按钮)
+      this.createLoading()
+    },
+    // 创建 loading
+    createLoading() {
+      const { isLoading } = this.renderProps
+      if (!this.isApple() && isLoading) {
+        const loadingEl = document.createElement('div')
+        this.loadingEl = loadingEl
+        loadingEl.className = 'loading-wrapper'
+        loadingEl.style.position = 'absolute'
+        loadingEl.style.top = '0'
+        loadingEl.style.left = '0'
+        loadingEl.style.zIndex = '1'
+        loadingEl.style.width = '100%'
+        loadingEl.style.height = '100%'
+        loadingEl.style.backgroundColor = 'black'
+        document.getElementById(this.wrapperId).appendChild(loadingEl)
+
+        // 创建 loading 动画
+        const animationEl = document.createElement('div')
+        animationEl.className = 'loading'
+        animationEl.style.zIndex = '2'
+        animationEl.style.position = 'absolute'
+        animationEl.style.top = '50%'
+        animationEl.style.left = '50%'
+        animationEl.style.marginTop = '-15px'
+        animationEl.style.marginLeft = '-15px'
+        animationEl.style.width = '30px'
+        animationEl.style.height = '30px'
+        animationEl.style.border = '2px solid #FFF'
+        animationEl.style.borderTopColor = 'rgba(255, 255, 255, 0.2)'
+        animationEl.style.borderRightColor = 'rgba(255, 255, 255, 0.2)'
+        animationEl.style.borderBottomColor = 'rgba(255, 255, 255, 0.2)'
+        animationEl.style.borderRadius = '100%'
+        animationEl.style.animation = 'circle infinite 0.75s linear'
+        loadingEl.appendChild(animationEl)
+
+        // 创建 loading 动画所需的 keyframes
+        const style = document.createElement('style')
+        const keyframes = `
+          @keyframes circle {
+            0% {
+              transform: rotate(0);
+            }
+            100% {
+              transform: rotate(360deg);
+            }
+          }
+        `
+        style.type = 'text/css'
+        if (style.styleSheet) {
+          style.styleSheet.cssText = keyframes
+        } else {
+          style.appendChild(document.createTextNode(keyframes))
+        }
+        document.head.appendChild(style)
+      }
+    },
+    // 监听视频相关事件
+    listenVideoEvent() {
+      // 播放事件监听
+      const playHandler = () => {
+        this.$ownerInstance.callMethod('eventEmit', { event: 'play' })
+        this.$ownerInstance.callMethod('setViewData', {
+          key: 'playing',
+          value: true
+        })
+
+        if (this.loadingEl) {
+          this.loadingEl.style.display = 'none'
+        }
+      }
+      this.videoEl.removeEventListener('play', playHandler)
+      this.videoEl.addEventListener('play', playHandler)
+
+      // 暂停事件监听
+      const pauseHandler = () => {
+        this.$ownerInstance.callMethod('eventEmit', { event: 'pause' })
+        this.$ownerInstance.callMethod('setViewData', {
+          key: 'playing',
+          value: false
+        })
+      }
+      this.videoEl.removeEventListener('pause', pauseHandler)
+      this.videoEl.addEventListener('pause', pauseHandler)
+
+      // 结束事件监听
+      const endedHandler = () => {
+        this.$ownerInstance.callMethod('eventEmit', { event: 'ended' })
+        this.$ownerInstance.callMethod('resetEventCommand')
+      }
+      this.videoEl.removeEventListener('ended', endedHandler)
+      this.videoEl.addEventListener('ended', endedHandler)
+
+      // 加载完成事件监听
+      const canPlayHandler = () => {
+        this.$ownerInstance.callMethod('eventEmit', { event: 'canplay' })
+        this.execDelayFunc()
+      }
+      this.videoEl.removeEventListener('canplay', canPlayHandler)
+      this.videoEl.addEventListener('canplay', canPlayHandler)
+
+      // 加载失败事件监听
+      const errorHandler = (e) => {
+        if (this.loadingEl) {
+          this.loadingEl.style.display = 'block'
+        }
+        this.$ownerInstance.callMethod('eventEmit', { event: 'error' })
+      }
+      this.videoEl.removeEventListener('error', errorHandler)
+      this.videoEl.addEventListener('error', errorHandler)
+
+      // loadedmetadata 事件监听
+      const loadedMetadataHandler = () => {
+        this.$ownerInstance.callMethod('eventEmit', { event: 'loadedmetadata' })
+        // 获取视频的长度
+        const duration = this.videoEl.duration
+        this.$ownerInstance.callMethod('eventEmit', {
+          event: 'durationchange',
+          data: duration
+        })
+
+        this.$ownerInstance.callMethod('setViewData', {
+          key: 'duration',
+          value: duration
+        })
+
+        // 加载首帧视频 模拟出封面图
+        this.loadFirstFrame()
+      }
+      this.videoEl.removeEventListener('loadedmetadata', loadedMetadataHandler)
+      this.videoEl.addEventListener('loadedmetadata', loadedMetadataHandler)
+
+      // 播放进度监听
+      const timeupdateHandler = (e) => {
+        const currentTime = e.target.currentTime
+        this.$ownerInstance.callMethod('eventEmit', {
+          event: 'timeupdate',
+          data: currentTime
+        })
+
+        this.$ownerInstance.callMethod('setViewData', {
+          key: 'currentTime',
+          value: currentTime
+        })
+
+      }
+      this.videoEl.removeEventListener('timeupdate', timeupdateHandler)
+      this.videoEl.addEventListener('timeupdate', timeupdateHandler)
+
+      // 倍速播放监听
+      const ratechangeHandler = (e) => {
+        const playbackRate = e.target.playbackRate
+        this.$ownerInstance.callMethod('eventEmit', {
+          event: 'ratechange',
+          data: playbackRate
+        })
+      }
+      this.videoEl.removeEventListener('ratechange', ratechangeHandler)
+      this.videoEl.addEventListener('ratechange', ratechangeHandler)
+
+      // 全屏事件监听
+      if (this.isApple()) {
+        const webkitbeginfullscreenHandler = () => {
+          const presentationMode = this.videoEl.webkitPresentationMode
+          let isFullScreen = null
+          if (presentationMode === 'fullscreen') {
+            isFullScreen = true
+          } else {
+            isFullScreen = false
+          }
+          this.$ownerInstance.callMethod('eventEmit', {
+            event: 'fullscreenchange',
+            data: isFullScreen
+          })
+        }
+        this.videoEl.removeEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
+        this.videoEl.addEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
+      } else {
+        const fullscreenchangeHandler = () => {
+          let isFullScreen = null
+          if (document.fullscreenElement) {
+            isFullScreen = true
+          } else {
+            isFullScreen = false
+          }
+          this.$ownerInstance.callMethod('eventEmit', {
+            event: 'fullscreenchange',
+            data: isFullScreen
+          })
+        }
+        document.removeEventListener('fullscreenchange', fullscreenchangeHandler)
+        document.addEventListener('fullscreenchange', fullscreenchangeHandler)
+      }
+    },
+    // 加载首帧视频,模拟出封面图
+    loadFirstFrame() {
+      let { autoplay, muted } = this.renderProps
+      if (this.isApple()) {
+        this.videoEl.play()
+        if (!autoplay) {
+          this.videoEl.pause()
+        }
+      } else {
+        // optimize: timeout 延迟调用是为了规避控制台的`https://goo.gl/LdLk22`这个报错
+        /**
+         * 原因:chromium 内核中,谷歌协议规定,视频不允许在非静音状态下进行自动播放
+         * 解决:在自动播放时,先将视频静音,然后延迟调用 play 方法,播放视频
+         * 说明:iOS 的 Safari 内核不会有这个,仅在 Android 设备出现,即使有这个报错也不影响的,所以不介意控制台报错的话是可以删掉这个 timeout 的
+         */
+        this.videoEl.muted = true
+        setTimeout(() => {
+          this.videoEl.play()
+          this.videoEl.muted = muted
+          if (!autoplay) {
+            setTimeout(() => {
+              this.videoEl.pause()
+            }, 100)
+          }
+        }, 10)
+      }
+    },
+    triggerCommand(eventType) {
+      if (eventType) {
+        this.$ownerInstance.callMethod('resetEventCommand')
+        this.videoEl && this.videoEl[eventType]()
+      }
+    },
+    triggerFunc(func) {
+      const { name, params } = func || {}
+      if (name) {
+        this[name](params)
+        this.$ownerInstance.callMethod('resetFunc')
+      }
+    },
+    removeHandler() {
+      if (this.videoEl) {
+        this.videoEl.pause()
+        this.videoEl.src = ''
+        this.$ownerInstance.callMethod('setViewData', {
+          key: 'videoSrc',
+          value: ''
+        })
+        this.videoEl.load()
+      }
+    },
+    fullScreenHandler() {
+      if (this.isApple()) {
+        this.videoEl.webkitEnterFullscreen()
+      } else {
+        this.videoEl.requestFullscreen()
+      }
+    },
+    toSeekHandler({ sec, isDelay }) {
+      const func = () => {
+        if (this.videoEl) {
+          this.videoEl.currentTime = sec
+        }
+      }
+
+      // 延迟执行
+      if (isDelay) {
+        this.delayFunc = func
+      } else {
+        func()
+      }
+    },
+    // 执行延迟函数
+    execDelayFunc() {
+      this.delayFunc && this.delayFunc()
+      this.delayFunc = null
+    },
+    viewportChange(props) {
+      this.renderProps = props
+      const { autoplay, muted, controls, loop, playbackRate } = props
+      if (this.videoEl) {
+        this.videoEl.autoplay = autoplay
+        this.videoEl.controls = controls
+        this.videoEl.loop = loop
+        this.videoEl.muted = muted
+        this.videoEl.playbackRate = playbackRate
+      }
+    },
+    randomNumChange(val) {
+      this.num = val
+    }
+  }
+}
+</script>
+
+<style scoped>
+.player-wrapper {
+  overflow: hidden;
+  height: 100%;
+  padding: 0;
+  position: relative;
+}
+</style>

+ 1 - 3
manifest.json

@@ -82,9 +82,7 @@
                     }
                 },
                 "speech" : {},
-                "oauth" : {
-                    "univerify" : {}
-                },
+                "oauth" : {},
                 "push" : {
                     "unipush" : {
                         "version" : "2",

+ 19 - 107
package.json

@@ -1,108 +1,20 @@
 {
-	"id": "uni-load-more",
-	"displayName": "uni-load-more 加载更多",
-	"version": "1.3.3",
-	"description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
-	"keywords": [
-		"uni-ui",
-		"uniui",
-		"加载更多",
-		"load-more"
-	],
-	"repository": "https://github.com/dcloudio/uni-ui",
-	"engines": {
-		"HBuilderX": ""
-	},
-	"directories": {
-		"example": "../../temps/example_temps"
-	},
-	"dcloudext": {
-		"category": [
-			"前端组件",
-			"通用组件"
-		],
-		"sale": {
-			"regular": {
-				"price": "0.00"
-			},
-			"sourcecode": {
-				"price": "0.00"
-			}
-		},
-		"contact": {
-			"qq": ""
-		},
-		"declaration": {
-			"ads": "无",
-			"data": "无",
-			"permissions": "无"
-		},
-		"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
-	},
-	"uni_modules": {
-		"dependencies": [
-			"uni-scss"
-		],
-		"encrypt": [],
-		"platforms": {
-			"cloud": {
-				"tcb": "y",
-				"aliyun": "y"
-			},
-			"client": {
-				"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"
-				},
-				"Vue": {
-					"vue2": "y",
-					"vue3": "y"
-				}
-			}
-		}
-	},
-	"devDependencies": {
-		"postcss": "^8.4.47",
-		"postcss-loader": "^8.1.1"
-	},
-	"dependencies": {
-		"@testing-library/jest-dom": "^6.1.6",
-		"@unicode/unicode-16.0.0": "^1.0.0",
-		"@vitejs/plugin-vue": "^5.2.3",
-		"amfe-flexible": "^2.2.1",
-		"axios": "^1.9.0",
-		"element-plus": "^2.9.10",
-		"postcss-pxtorem": "^6.1.0",
-		"sass": "^1.88.0",
-		"swiper": "^9.4.1",
-		"vite": "^6.3.5",
-		"vue": "^3.5.13",
-		"vue-router": "^4.5.1",
-		"vuex": "^4.1.0",
-		"vuex-persistedstate": "^4.1.0"
-	}
-}
+    "id": "lius-DomVideoPlayer",
+    "name": "video-player 视频播放器 html5视频播放器-解决频层级、覆盖",
+    "displayName": "video-player 视频播放器 html5视频播放器-解决频层级、覆盖",
+    "version": "2.0.0",
+    "description": "APP 项目中,uniapp 提供的的 video 原生视频组件层级太高,难以遮挡;该视频播放器可以被其他元素进行覆盖、遮挡,页面具有更高的定制性。",
+    "keywords": [
+        "video-player",
+        "视频播放器",
+        "视频覆盖",
+        "视频层级",
+        "视频遮挡"
+    ],
+    "dcloudext": {
+        "category": [
+            "前端组件",
+            "通用组件"
+        ]
+    }
+}

+ 7 - 0
pages.json

@@ -514,6 +514,13 @@
 				"navigationStyle": "custom"
 			}
 		},
+		{
+			"path": "pages/crowdFunding/searchOrder",
+			"style": {
+				"navigationBarTitleText": "搜索", 
+				"navigationStyle": "custom"
+			}
+		},
 		{
 			"path": "pages/crowdFunding/customerService",
 			"style": {

+ 3 - 0
pages/crowdFunding/crowdfundingDetails - 副本.vue → pages/crowdFunding/crowdfundingDetails copy.vue

@@ -512,6 +512,9 @@ export default {
 		this.projectId = options.id || null;
 		this.getDetail();
 	},
+	onShow() {
+		this.getDetail();
+	},
 	
 }
 </script>

+ 39 - 31
pages/crowdFunding/crowdfundingDetails.vue

@@ -17,10 +17,13 @@
 				@change="handleSwiperChange" :duration="300">
 				<swiper-item v-for="(item, idx) in mediaList" :key="idx" class="swiper-item">
 					<view v-if="item.type === 'video'" class="media-wrapper">
-						<video class="swiper-video" :src="item.src" :poster="item.poster" :id="'video-' + idx" controls
-							object-fit="contain" enable-progress-gesture="false" :loop="false"
-							:show-fullscreen-btn="false" :show-play-btn="true" :enable-play-gesture="false"
-							@ended="onVideoEnded" @play="onVideoPlay(idx)" @pause="onVideoPause"></video>
+						<!-- <DomVideoPlayer style="z-index: -100; position: static;" :src="item.src" :poster="item.poster"
+							:id="'video-' + idx" :controls="false" :autoplay="false" :loop="false" :muted="false"
+							:objectFit="'contain'" @play="onVideoPlay(idx)" @pause="onVideoPause"
+							@ended="onVideoEnded" /> -->
+						<DomVideoPlayer :ref="'domVideoPlayer' + idx"
+							:src="item.src" autoplay
+							loop controls muted  @play="onVideoPlay(idx)" @pause="onVideoPause(idx)"/>
 					</view>
 					<image v-else class="swiper-img" :src="item.src" mode="aspectFill" />
 				</swiper-item>
@@ -40,7 +43,8 @@
 					<uv-line-progress height="8rpx" :showText="false"
 						:percentage="(detail.current_amount / detail.goal_amount * 100).toFixed(2)"
 						inactiveColor="#F0F0F0" activeColor="#ACF934"></uv-line-progress>
-					<view class="progress-percent">{{ (detail.current_amount / detail.goal_amount * 100).toFixed(2) + '%'
+					<view class="progress-percent">{{ (detail.current_amount / detail.goal_amount * 100).toFixed(2) +
+						'%'
 						}}</view>
 				</view>
 				<view class="project-stats">
@@ -115,7 +119,10 @@
 					<image class="initiator-avatar" :src="detail.creator_avatar" />
 					<view class="initiator-info">
 						<text class="initiator-name">{{ detail.creator_nickname }}</text>
-						<div class="initiator-tag" @click="certificationTips()"><image src="@/static/crowdFunding/authentication.png" mode="widthFix"></image> <div>发起人</div></div>
+						<div class="initiator-tag" @click="certificationTips()">
+							<image src="@/static/crowdFunding/authentication.png" mode="widthFix"></image>
+							<div>发起人</div>
+						</div>
 					</view>
 					<view class="initiator-service-btn  blick-btn-animation"
 						@click="goPage('/pages/crowdFunding/customerService?id=' + detail.creator_id + '&zc_id=' + detail.id)">
@@ -132,20 +139,21 @@
 
 			<!-- 风险说明 -->
 			<view class="section risk-section">
-				<view class="risk-row"  @click="goWeb('https://e.zhichao.art/web/refund.php', '退款说明')">
+				<view class="risk-row" @click="goWeb('https://e.zhichao.art/web/refund.php', '退款说明')">
 					<view class="risk-title">退款政策</view>
 					<view class="risk-more  ">查看更多
 						<image src="@/static/crowdFunding/right.png" class="risk-more-icon" />
 					</view>
 				</view>
 				<view class="risk-desc">众筹结束前最后1个小时无法申请退款</view>
-				<view class="risk-row risk-row-border"  @click="goWeb('https://e.zhichao.art/web/crowdtips.php', '风险提示')">
+				<view class="risk-row risk-row-border"
+					@click="goWeb('https://e.zhichao.art/web/crowdtips.php', '风险提示')">
 					<view class="risk-title">风险提示</view>
 					<view class="risk-more  ">查看更多
 						<image src="@/static/crowdFunding/right.png" class="risk-more-icon" />
 					</view>
 				</view>
-				<view class="risk-content" >
+				<view class="risk-content">
 					<view>1. 您参与众筹是支持将创意变为现实的过程,而不是直接的商品交易,因此存在一定风险。请您根据自己的判断选择,支持众筹项目。</view>
 					<view>2. 众筹存在于发起人与支持者之间,摩点作为第三方平台,提供网络空间、技术支持等服务。众筹的回报产品和承诺由发起人负责。</view>
 				</view>
@@ -173,7 +181,8 @@
 
 		<!-- 分享弹窗 -->
 		<SharePopup :visible="showShare" :userId="0" :share-title="shareTitle" :share-desc="shareDesc"
-			:share-img="shareImg" view="crowdfundingDetails" :link="shareLink" @close="showShare = false" :isReportContent="true" />
+			:share-img="shareImg" view="crowdfundingDetails" :link="shareLink" @close="showShare = false"
+			:isReportContent="true" />
 
 		<productSpecifications ref="specSheet" :rewards="rewards" :title="detail.title" @confirm="onSpecConfirm" />
 
@@ -184,12 +193,13 @@
 import VideoPlayer from "@/components/VideoPlayer/VideoPlayer.vue";
 import SharePopup from "@/components/SharePopup/SharePopup.vue";
 import productSpecifications from "./components/productSpecifications/productSpecifications.vue";
-
+import DomVideoPlayer from "@/components/DomVideoPlayer/DomVideoPlayer.vue";
 export default {
 	components: {
 		VideoPlayer,
 		SharePopup,
-		productSpecifications
+		productSpecifications,
+		DomVideoPlayer
 	},
 	data() {
 		return {
@@ -204,7 +214,7 @@ export default {
 			shareTitle: '',
 			shareDesc: '',
 			shareImg: '',
-			shareLink:"https://e.zhichao.art/site/#/mobile-download",
+			shareLink: "https://e.zhichao.art/site/#/mobile-download",
 			userId: 0, // 可根据实际登录用户赋值
 			isFavorite: false, // 是否已收藏
 			projectId: null, // 当前项目id
@@ -263,13 +273,10 @@ export default {
 		},
 		onVideoPlay(idx) {
 			// 更新当前播放的视频索引
-			this.videoPlaying = true;
-			if (this.currentMediaIndex !== idx) {
-				this.currentMediaIndex = idx;
-			}
+			this.$refs['domVideoPlayer' + idx].play();
 		},
-		onVideoPause() {
-			this.videoPlaying = false;
+		onVideoPause(idx) {
+			this.$refs['domVideoPlayer' + idx].pause();
 		},
 		onVideoEnded() {
 			this.videoPlaying = false;
@@ -420,15 +427,15 @@ export default {
 					this.commentList = [];
 				}
 			});
-			
+
 		},
 		goWeb(url, title) {
-		uni.navigateTo({
-			url: `/pages/webview/index?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}`
-		})
-	},
+			uni.navigateTo({
+				url: `/pages/webview/index?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}`
+			})
+		},
 		processingDataDetails(data) {
-			
+
 			this.detail = data;
 			// 确保 image_list 始终是一个数组
 			data.image_list = data.image_list || [];
@@ -438,7 +445,7 @@ export default {
 				poster: data.main_image,
 				src: data.video_url,
 			}] : [];
-			
+
 			const imageItems = data.image_list.map(v => ({
 				type: 'image',
 				src: v
@@ -482,7 +489,7 @@ export default {
 			console.log("顶部轮播数据", this.mediaList, "mediaList");
 			console.log("详情", this.detail, "detail");
 		},
-		certificationTips(){
+		certificationTips() {
 			uni.showToast({
 				title: '官方已实名认证',
 				icon: 'none'
@@ -498,7 +505,7 @@ export default {
 				}
 			}).exec();
 		});
-	},  
+	},
 	onPageScroll(e) {
 		const threshold = this.swiperHeight || uni.upx2px(400); // 优先用实际高度
 		let opacity = 0;
@@ -515,7 +522,7 @@ export default {
 	onShow() {
 		this.getDetail();
 	},
-	
+
 }
 </script>
 
@@ -995,9 +1002,10 @@ export default {
 		margin-left: 2rpx;
 		display: inline-flex;
 		align-items: center;
-		image{
+
+		image {
 			width: 28rpx;
-			height: 28rpx; 
+			height: 28rpx;
 		}
 	}
 

+ 15 - 22
pages/crowdFunding/crowdfundingDetailsDesign.vue

@@ -17,10 +17,12 @@
 				@change="handleSwiperChange" :duration="300">
 				<swiper-item v-for="(item, idx) in mediaList" :key="idx" class="swiper-item">
 					<view v-if="item.type === 'video'" class="media-wrapper">
-						<video class="swiper-video" :src="item.src" :poster="item.poster" :id="'video-' + idx" controls
+						<!-- <video class="swiper-video" :src="item.src" :poster="item.poster" :id="'video-' + idx" controls
 							object-fit="contain" enable-progress-gesture="false" :loop="false"
 							:show-fullscreen-btn="false" :show-play-btn="true" :enable-play-gesture="false"
-							@ended="onVideoEnded" @play="onVideoPlay(idx)" @pause="onVideoPause"></video>
+							@ended="onVideoEnded" @play="onVideoPlay(idx)" @pause="onVideoPause"></video> -->
+						<DomVideoPlayer :ref="'domVideoPlayer' + idx" :src="item.src" autoplay loop controls muted
+							@play="onVideoPlay(idx)" @pause="onVideoPause(idx)" />
 					</view>
 					<image v-else class="swiper-img" :src="item.src" mode="aspectFill" />
 				</swiper-item>
@@ -170,7 +172,8 @@
 
 		<!-- 分享弹窗 -->
 		<SharePopup :visible="showShare" :userId="0" :share-title="shareTitle" :share-desc="shareDesc"
-			:share-img="shareImg" view="crowdfundingDetails" :link="shareLink" @close="showShare = false" :isReportContent="true" />
+			:share-img="shareImg" view="crowdfundingDetails" :link="shareLink" @close="showShare = false"
+			:isReportContent="true" />
 
 		<!-- <productSpecifications ref="specSheet" :rewards="rewards" :title="detail.title" @confirm="onSpecConfirm" /> -->
 
@@ -201,7 +204,7 @@ export default {
 			shareTitle: '',
 			shareDesc: '',
 			shareImg: '',
-			shareLink:"https://e.zhichao.art/site/#/mobile-download",
+			shareLink: "https://e.zhichao.art/site/#/mobile-download",
 			userId: 0, // 可根据实际登录用户赋值
 			isFavorite: false, // 是否已收藏
 			projectId: null, // 当前项目id
@@ -237,10 +240,7 @@ export default {
 
 			// 如果当前在播放视频,先暂停
 			if (this.mediaList[this.currentMediaIndex]?.type === 'video') {
-				const videoContext = uni.createVideoContext('video-' + this.currentMediaIndex, this);
-				if (videoContext) {
-					videoContext.pause();
-				}
+				this.onVideoPause(this.currentMediaIndex)
 			}
 
 			this.currentMediaIndex = index;
@@ -251,22 +251,15 @@ export default {
 
 			// 如果上一个是视频,暂停它
 			if (this.mediaList[lastIndex]?.type === 'video') {
-				const videoContext = uni.createVideoContext('video-' + lastIndex, this);
-				if (videoContext) {
-					videoContext.pause();
-					this.videoPlaying = false;
-				}
+				this.onVideoPause(lastIndex)
 			}
 		},
 		onVideoPlay(idx) {
 			// 更新当前播放的视频索引
-			this.videoPlaying = true;
-			if (this.currentMediaIndex !== idx) {
-				this.currentMediaIndex = idx;
-			}
+			this.$refs['domVideoPlayer' + idx].play();
 		},
-		onVideoPause() {
-			this.videoPlaying = false;
+		onVideoPause(idx) {
+			this.$refs['domVideoPlayer' + idx].pause();
 		},
 		onVideoEnded() {
 			this.videoPlaying = false;
@@ -307,7 +300,7 @@ export default {
 						this.detail.like_count += 1;
 						// 强制更新视图
 						this.$forceUpdate();
-					}else if (res.data.str == "取消点赞") {
+					} else if (res.data.str == "取消点赞") {
 						uni.showToast({
 							title: '取消支持',
 							icon: 'none'
@@ -317,7 +310,7 @@ export default {
 						this.detail.like_count -= 1;
 						// 强制更新视图
 						this.$forceUpdate();
-					}else{
+					} else {
 						uni.showToast({
 							title: res.data.str,
 							icon: 'none'
@@ -496,7 +489,7 @@ export default {
 			this.mediaList = [...videoItem, ...imageItems];
 
 
-			
+
 			this.shareTitle = data.title;
 			this.shareDesc = data.content;
 			this.shareImg = data.image;

+ 5 - 0
pages/crowdFunding/orderConfirm.vue

@@ -281,6 +281,8 @@ export default {
     },
     // 轮询查支付状态
     checkPayStatus() {
+      console.log(this.linkid, "支付订单号");
+      
       uni.request({
         url: this.$apiHost + "/Order/getstatus",
         data: {
@@ -292,7 +294,10 @@ export default {
           sign: getApp().globalData.headerSign
         },
         success: (res) => {
+          console.log(res.data, "支付状态");
+          
           if (res.data.success == "yes") {
+
             uni.hideLoading();
             uni.showToast({ title: "支付成功", icon: "none" });
             // 跳转到订单详情或列表

+ 48 - 13
pages/crowdFunding/orderDetail.vue

@@ -6,7 +6,7 @@
 				<text class="fa fa-angle-left" @click="goBack"></text>
 			</view>
 
-			<view class="navbar-right scale-tap" @click="goPages('/pages/crowdFunding/customerService')">
+			<view class="navbar-right scale-tap" @click="goPages('/pages/crowdFunding/customerService?id=' + product.creator_id + '&zc_id=' + product.id)">
 				<image src="@/static/crowdFunding/customer-service-btn.png" style="width: 60rpx; height: 60rpx"
 					mode="widthFix">
 				</image>
@@ -165,13 +165,14 @@ export default {
 			paymentMethod: 'alipay', // 默认支付宝支付
 			isWeChatPay: true, // 是否显示微信支付选项
 			orderId: "",
+			linkid: "",
 		};
 	},
 	onLoad(options) {
 		this.getOrderDetail(options.orderId);
 		this.orderId = options.orderId;
 
-	},
+	}, 
 	methods: {
 		goBack() {
 			uni.navigateBack();
@@ -256,7 +257,7 @@ export default {
 		commentOrder() { },
 		orderAction(act, payType = '') {
 
-			var order_id = this.orderId; 
+			var order_id = this.orderId;
 			var _this = this;
 			console.log({
 				order_id,
@@ -275,11 +276,11 @@ export default {
 				},
 				success: (res) => {
 					console.log(res.data, "订单操作结果");
-
-					if (res.data && res.data.success == 'yes') { 
+					this.linkid = res.data.linkid;
+					if (res.data && res.data.success == 'yes') {
 						// 微信支付
 						console.log(payType, "支付方式");
-						
+
 						if (payType === 'wx') {
 							console.log(res.data.wepay, "微信支付");
 
@@ -295,11 +296,11 @@ export default {
 									sign: res.data.wepay.sign
 								},
 								success: (payRes) => {
-									that.checkPayStatus();
+									_this.checkPayStatus();
 								},
 								fail: (err) => {
 									uni.hideLoading();
-									that.isSubmitting = false;
+									_this.isSubmitting = false;
 									uni.showToast({ title: '支付取消', icon: 'none' });
 								}
 							});
@@ -308,17 +309,17 @@ export default {
 						// 支付宝支付
 						else if (payType === 'alipay') {
 							console.log(res.data.ali_pay, "支付宝支付");
-							
+
 							uni.requestPayment({
 								provider: "alipay",
 								orderInfo: res.data.ali_pay,
 								success: (payRes) => {
-									that.checkPayStatus();
+									_this.checkPayStatus();
 								},
 								fail: (err) => {
 									uni.hideLoading();
-									
-									that.isSubmitting = false;
+
+									_this.isSubmitting = false;
 									uni.showToast({ title: '支付取消', icon: 'none' });
 								}
 							});
@@ -348,6 +349,39 @@ export default {
 				}
 			});
 		},
+		// 轮询查支付状态
+		checkPayStatus() { 
+			
+			uni.request({
+				url: this.$apiHost + "/Order/getstatus",
+				data: {
+					uuid: getApp().globalData.uuid,
+					linkid: this.linkid,
+				},
+				header: {
+					"content-type": "application/json",
+					sign: getApp().globalData.headerSign
+				},
+				success: (res) => {
+					console.log(res.data, "支付成功11");
+					if (res.data.success == "yes") {
+						console.log(res.data, "支付成功11");
+						
+						uni.hideLoading();
+						uni.showToast({ title: "支付成功", icon: "none" });
+						// 跳转到订单详情或列表
+						// uni.redirectTo({ url: '/pages/crowdFunding/orderList' });
+						this.getOrderDetail(this.orderId);
+					} else {
+						setTimeout(() => { this.checkPayStatus(); }, 1000);
+					}
+				},
+				fail: (err) => {
+					uni.hideLoading();
+					uni.showToast({ title: "网络错误,请重试", icon: "none" });
+				}
+			});
+		},
 		getOrderDetail(orderId) {
 			uni.request({
 				url: this.$apiHost + '/Order/detail?order_id=' + orderId,
@@ -366,7 +400,7 @@ export default {
 						this.order = {
 							orderNo: data.linkid,
 							createTime: data.create_time,
-							payTime: data.order_time,
+							payTime: data.order_time, 
 						}
 						if (data.crowdfund) {
 							this.product = {
@@ -379,6 +413,7 @@ export default {
 								total: data.money,
 								deliveryTime: data.crowdfund.delivery,
 								id: data.crowdfund.id,
+								creator_id: data.crowdfund.creator_id,
 								// tip: "温馨提示:该链接仅购买线下实物卡片!不含线上卡牌壁纸",
 							}
 						}

+ 8 - 3
pages/crowdFunding/orderList.vue

@@ -10,10 +10,10 @@
         订单
         </view>
       </view>
-      <view class="navbar-right"  >
+      <view class="navbar-right"  @click="goPages('/pages/crowdFunding/searchOrder')">
         <image
-          src="@/static/icon/more2.png"
-          style="width: 64rpx; height: 64rpx; margin-top: 15rpx"
+          src="@/static/crowdFunding/search2.png"
+          style="width: 40rpx; height: 40rpx; margin-top: 15rpx"
           mode="widthFix"
         ></image>
       </view>
@@ -161,6 +161,11 @@ export default {
     },
   },
   methods: {
+    goPages(url) {
+      uni.navigateTo({
+        url: url,
+      });
+    },
     goBack() {
       uni.navigateBack();
     },

+ 1045 - 0
pages/crowdFunding/searchOrder.vue

@@ -0,0 +1,1045 @@
+<template>
+  <view class="search-container">
+    <!-- 搜索框 -->
+    <view class="search-header">
+      <view class="cancel-btn" @click="goBack">
+        <uni-icons type="left" size="22" color="#1F1F1F"></uni-icons>
+      </view>
+      <view class="search-box">
+        <!-- <uni-icons type="search" size="16" color="#999"></uni-icons> -->
+        <input type="text" v-model="searchKeyword" placeholder="请输入关键词" confirm-type="search" @confirm="onSearch"
+          @input="handleInput" />
+        <uni-icons v-if="searchKeyword" type="clear" size="16" color="#999" @click="clearKeyword"></uni-icons>
+        <view class="searchImgBox" @click="onSearch">
+          <image class="image" src="@/static/home/sy_icon_sousuo.png"></image>
+        </view>
+      </view>
+    </view>
+    <view class="reserveASeat" :style="{ height: reserveASeatHeight + 'px' }"></view>
+    <!-- 搜索历史 -->
+    <view class="search-history" v-if="searchStatus && historyList.length > 0">
+      <view class="history-header">
+        <text class="title">搜索历史</text>
+        <image @click="clearHistory" style="width: 32rpx;height: 32rpx;" class="deleteAll"
+          src="@/static/home/sy_icon_shanchu.png"></image>
+      </view>
+      <view class="history-list">
+        <view class="history-item" v-for="(item, index) in displayedHistoryList" :key="index"
+          @click="useHistoryKeyword(item)">
+          <view>
+            <uni-icons type="clock" size="14" color="#999"></uni-icons>
+            <view class="history-text">
+              <image src="@/static/home/sy_icon_lishijilu.png"></image> {{ item }}
+            </view>
+          </view>
+          <image class="deleteBtn" @click.stop="deleteHistoryItem(item)" src="@/static/icon/close.png"></image>
+        </view>
+        <view class="expandBtn" @click="toggleHistory">
+          <view v-if="!isExpanded">
+            <template v-if="historyList.length > 5">
+              查看全部
+              <image src="@/static/home/sy_icon_chakanquanbu.png"></image>
+            </template>
+          </view>
+          <view v-else class="fold">
+            折叠历史记录
+            <image src="@/static/home/sy_icon_chakanquanbu.png"></image>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 搜索结果 -->
+    <view class="search-result" v-if="!searchStatus">
+
+         <!-- Tab导航  -->
+    <view class="tabs-section" :style="{ height: tabsSectionHeight + 'px' }">
+      <scroll-view
+        scroll-x
+        class="tabs-scroll-view"
+        :show-scrollbar="false"
+        :scroll-into-view="'tab-' + (currentTab - 1)"
+        scroll-with-animation
+      >
+        <view class="tabs-wrapper">
+          <view
+            v-for="(tab, index) in tabs"
+            :key="index"
+            :id="'tab-' + index"
+            :class="['tab-item', currentTab === index ? 'active' : '']"
+            @click="switchTab(index)"
+          >
+            <view class="tab" :class="{ active: currentTab === index }">
+              <text class="left">{{ tab.name }}</text>
+              <view class="line"></view>
+            </view>
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+    <!-- <view class="tabs-reserveaseat"></view> -->
+
+      <block v-if="searchResult.length > 0">
+        <swiper
+      :current="currentTab"
+      @change="onSwiperChange"
+      class="order-swiper"
+      :style="'height:' + swiperHeight + 'px'"
+    >
+      <swiper-item v-for="tab in tabs" :key="tab.type">
+        <view class="order-list">
+          <view
+            class="order-card"
+            v-for="order in getOrdersByTab(tab.type)"
+            :key="order.id"
+          >
+            <view class="order-header">
+              <text class="project-title one-omit">{{ order.projectTitle }}</text>
+              <text class="tag-initiator" v-if="order.isInitiator">发起人</text>
+              <text
+                class="order-status"
+                :class="'status-' + order.statusType"
+                >{{ order.statusText }}</text
+              >
+            </view>
+            <view class="order-main" @click="goToOrderDetail(order)">
+              <image class="order-img" :src="order.img" />
+              <view class="order-info">
+                <view class="order-title">{{ order.title }}</view>
+                <view class="order-spec">{{ order.spec }}</view>
+              </view>
+              <view class="order-price">
+                <view>¥{{ order.price }}</view>
+                <view class="order-count">x{{ order.count }}</view>
+              </view>
+            </view>
+            <view class="order-actions">
+              <!-- 1. 支付失败 -->
+              <template v-if="order.statusType === 'payFail'">
+                <view class="btn btn-delete" @click="deleteOrder(order)"
+                  >删除订单</view
+                >
+              </template>
+              <!-- 2. 待支付 -->
+              <template v-else-if="order.statusType === 'waitPay'">
+                <view class="btn btn-pay" @click="pay(order)">立即支付</view>
+                <view class="btn btn-cancel" @click="cancelOrder(order)"
+                  >取消订单</view
+                >
+              </template>
+              <!-- 3. 已付款待发货 -->
+              <template v-else-if="order.statusType === 'paid'">
+                <view class="btn btn-cancel" @click="cancelOrder(order)"
+                  >取消订单</view
+                >
+              </template>
+              <!-- 4. 商品已发货 -->
+              <template v-else-if="order.statusType === 'waitReceive'">
+                <view class="btn btn-confirm" @click="confirmReceive(order)"
+                  >确认收货</view
+                >
+              </template>
+              <!-- 5. 交易完成 -->
+              <template v-else-if="order.statusType === 'finish'">
+                <!-- <view class="btn btn-comment" @click="commentOrder(order)">去评价</view> -->
+                <view class="btn btn-delete" @click="deleteOrder(order)"
+                  >删除订单</view
+                >
+              </template>
+              <!-- 6. 已退款 -->
+              <template v-else-if="order.statusType === 'refund'">
+                <view class="btn btn-delete" @click="deleteOrder(order)"
+                  >删除订单</view
+                >
+              </template>
+            </view>
+          </view>
+        </view>
+      </swiper-item>
+    </swiper>
+      </block>
+      <view class="no-data" v-else-if="!isLoading">
+        <text>暂无数据</text>
+      </view>
+    </view>
+    <DialogBox ref="DialogBox"></DialogBox>
+  </view>
+</template>
+
+<script>
+import CrowdFundingItem from './components/CrowdFundingItem/CrowdFundingItem.vue';
+const HISTORY_KEY = 'search_history';
+const MAX_HISTORY = 20;
+
+export default {
+  components: { CrowdFundingItem },
+  data() {
+    return {
+      searchKeyword: '', // 搜索关键词
+      historyList: [], // 搜索历史
+      searchResult: [],
+      page: 1,
+      pageSize: 20,
+      hasMore: true,
+      isLoading: false,
+      isExpanded: false, // 添加展开/折叠状态变量
+      searchStatus: true,//显示搜索历史  false显示搜索结果
+
+      currentTab: 0,
+      tabs: [
+        { name: "全部", type: "all" },
+        { name: "待支付", type: "waitPay" },
+        // { name: "已付款", type: "paid" },
+        { name: "待发货", type: "waitSend" },
+        { name: "待收货", type: "waitReceive" },
+        { name: "交易完成", type: "finish" },
+        { name: "退款中", type: "refund" },
+        { name: "已关闭", type: "payFail" },
+      ],
+      searchResult: [],
+      swiperHeight: 600, // 默认高度,后续可动态调整
+      reserveASeatHeight: 0, // 预留空间高度
+      tabsSectionHeight: 0, // 标签栏高度
+    }
+  },
+  onLoad() {
+    // 加载历史记录
+    this.loadHistory();
+  },
+  onPullDownRefresh() {
+    this.onSearch(true);
+    uni.stopPullDownRefresh();
+  },
+  onReachBottom() {
+    this.onSearch(false);
+  },
+  computed: {
+    // 添加计算属性以控制显示的历史记录数量
+    displayedHistoryList() {
+      return this.isExpanded ? this.historyList : this.historyList.slice(0, 5);
+    }
+  },
+  methods: {
+    // 加载历史记录
+    loadHistory() {
+      try {
+        const history = uni.getStorageSync(HISTORY_KEY);
+        this.historyList = history ? JSON.parse(history) : [];
+      } catch (e) {
+        console.error('Failed to load search history:', e);
+        this.historyList = [];
+      }
+    },
+
+    // 保存历史记录
+    saveHistory() {
+      try {
+        // 将当前搜索词添加到历史记录开头
+        if (this.searchKeyword && !this.historyList.includes(this.searchKeyword)) {
+          console.log(this.historyList, 11111);
+          this.historyList.unshift(this.searchKeyword);
+          console.log(this.historyList, 11111);
+
+          // 限制历史记录数量
+          if (this.historyList.length > MAX_HISTORY) {
+            this.historyList = this.historyList.slice(0, MAX_HISTORY);
+          }
+          uni.setStorageSync(HISTORY_KEY, JSON.stringify(this.historyList));
+        }
+      } catch (e) {
+        console.error('Failed to save search history:', e);
+      }
+    },
+
+    // 清空历史记录
+    clearHistory() {
+
+      this.$refs['DialogBox'].confirm({
+        title: '提示',
+        content: '确定要清空搜索历史吗?',
+        DialogType: 'inquiry',
+        btn1: '否',
+        btn2: '是',
+        animation: 0
+      }).then((res) => {
+        if (res.isConfirm) {
+          this.historyList = [];
+          uni.setStorageSync(HISTORY_KEY, '[]');
+        }
+      })
+
+
+    },
+    // 清空单个历史记录
+    deleteHistoryItem(item) {
+      console.log(item, '删除历史记录');
+
+      this.$refs['DialogBox'].confirm({
+        title: '提示',
+        content: '确定要删除搜索历史吗?',
+        DialogType: 'inquiry',
+        btn1: '否',
+        btn2: '是',
+        animation: 0
+      }).then((res) => {
+        if (res.isConfirm) {
+          const index = this.historyList.indexOf(item);
+          if (index !== -1) {
+            this.historyList.splice(index, 1);
+          }
+          uni.setStorageSync(HISTORY_KEY, JSON.stringify(this.historyList));
+        }
+      })
+
+
+    },
+
+    // 使用历史记录中的关键词
+    useHistoryKeyword(keyword) {
+      this.searchKeyword = keyword;
+      this.onSearch();
+    },
+
+    // 处理搜索
+    async onSearch(isRefresh = true) {
+      if (!this.searchKeyword.trim()) return;
+      if (isRefresh) {
+        this.page = 1;
+        this.hasMore = true;
+        this.searchResult = [];
+      }
+      if (!this.hasMore || this.isLoading) return;
+      this.isLoading = true;
+   
+      try {
+        const [err, res] = await uni.request({
+          url: this.$apiHost + '/Order/getlist?type=buyCrowdfund',
+          method: 'GET',
+          data: {
+            offset: this.page,
+            keyword: this.searchKeyword,
+            uuid: getApp().globalData.uuid,
+          skey: getApp().globalData.skey,
+          }
+        });
+        
+        if (!err && res && res.data && res.data.list) {
+          var list = res.data.list;  
+          list = res.data.list.map(order => {
+            let statusType = '';
+            let statusText = ''; 
+            switch (order.status) {
+              case 0:
+                statusType = 'waitPay';
+                statusText = '待支付';
+                break;
+              case 1:
+                statusType = 'waitSend';
+                statusText = '待发货';
+                break;
+              case 2:
+                statusType = 'waitReceive';
+                statusText = '商品已发货';
+                break;
+              case 3:
+                statusType = 'finish';
+                statusText = '已收货';
+                break;
+              case 5:
+                statusType = 'finish';
+                statusText = '交易完成';
+                break;
+              case 6:
+                statusType = 'refund';
+                statusText = '退款中';
+                break;
+              case 8:
+                statusType = 'payFail';
+                statusText = '已关闭';
+                break;
+              case 9:
+                statusType = 'finish';
+                statusText = '已完成';
+                break;
+              default:
+                statusType = 'waitPay';
+                statusText = '待支付';
+            }
+            return {
+              ...order,
+              statusType,
+              statusText,
+              projectTitle: order.name,
+              title: order.name,
+              spec: order.name2,
+              img: order.image,
+              price: order.money,
+              count: order.num,
+              isInitiator: false
+            };
+          });
+          
+          console.log(list, "搜索结果2");
+          if (isRefresh) {
+            this.searchResult = list;
+          } else {
+            this.searchResult = [...this.searchResult, ...list];
+          }
+          this.hasMore = this.searchResult.length < (res.data.data.total || 0);
+          this.page++;
+        } else {
+          this.hasMore = false;
+        }
+      } catch (e) {
+        this.hasMore = false;
+      }
+      this.isLoading = false;
+      // 保存历史记录
+      this.saveHistory();
+      this.searchStatus = false;
+    },
+
+    // 清空搜索框
+    clearKeyword() {
+      this.searchKeyword = '';
+    },
+
+    // 处理输入
+    handleInput(e) {
+      this.searchKeyword = e.detail.value;
+      if (this.searchKeyword.trim() == '') {
+        this.searchStatus = true;
+      }
+      console.log(this.historyList, e.detail.value);
+
+    },
+
+    // 返回上一页
+    goBack() {
+      uni.navigateBack();
+    },
+
+    // 添加展开/折叠方法
+    toggleHistory() {
+      this.isExpanded = !this.isExpanded;
+    },
+    goToDetail(id) {
+      uni.navigateTo({ url: '/pages/crowdFunding/crowdfundingDetails?id=' + id });
+    },
+    handleSearch() {
+      if (!this.searchKeyword.trim()) return;
+      // 保存到历史记录
+      this.saveHistory();
+      this.searchStatus = false;
+      // 加载搜索结果
+      this.queryList();
+    },
+
+    goPages(url) {
+      uni.navigateTo({
+        url: url,
+      });
+    },
+    goBack() {
+      uni.navigateBack();
+    },
+    switchTab(index) {
+      this.currentTab = index;
+      // 切换标签时刷新数据
+      this.onSearch();
+    },
+    onSwiperChange(e) {
+      this.currentTab = e.detail.current;
+      this.$nextTick(() => {
+        this.updateSwiperHeight();
+      });
+    },
+    getOrdersByTab(type) {
+      if (type === "all") return this.searchResult; 
+      return this.searchResult.filter((o) => o.statusType === type);
+    },
+    updateSwiperHeight() {
+      // 动态获取当前swiper-item内容高度
+      this.$nextTick(() => {
+        const query = uni.createSelectorQuery().in(this);
+        query
+          .selectAll(".reserveASeat, .tabs-section")
+          .boundingClientRect((rects) => {
+            if (rects && rects.length >= 2) {
+              this.reserveASeatHeight = rects[0].height || 0;
+              this.tabsSectionHeight = rects[1].height || 0;
+              
+              // 计算swiper高度 = 视窗高度 - 预留空间高度 - 标签栏高度 - 状态栏高度
+              const windowHeight = uni.getSystemInfoSync().windowHeight;
+              this.swiperHeight = windowHeight - this.reserveASeatHeight - this.tabsSectionHeight;
+            }
+          })
+          .exec();
+      });
+    },
+    goToOrderDetail(order) {
+      uni.navigateTo({
+        url: "/pages/crowdFunding/orderDetail?orderId=" + order.id,
+      });
+    },
+    pay(order) {
+      uni.navigateTo({
+        url: "/pages/crowdFunding/orderDetail?orderId=" + order.id,
+      });
+      /* 支付逻辑 */
+    },
+    deleteOrder(order) {
+      /* 删除逻辑 */
+       uni.navigateTo({
+        url: "/pages/crowdFunding/orderDetail?orderId=" + order.id,
+      });
+    },
+    cancelOrder(order) {
+      /* 取消/退款逻辑 */
+       uni.navigateTo({
+        url: "/pages/crowdFunding/orderDetail?orderId=" + order.id,
+      });
+    },
+    confirmReceive(order) {
+      /* 确认收货逻辑 */
+       uni.navigateTo({
+        url: "/pages/crowdFunding/orderDetail?orderId=" + order.id,
+      });
+    },
+    commentOrder(order) {
+      /* 评价逻辑 */
+       uni.navigateTo({
+        url: "/pages/crowdFunding/orderDetail?orderId=" + order.id,
+      });
+    },
+   
+  },
+  mounted() {
+    this.updateSwiperHeight();
+  },
+  watch: {
+    currentTab() {
+      this.$nextTick(() => {
+        this.updateSwiperHeight();
+      });
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+.search-container {
+  background-color: #f2f6f2;
+  min-height: 100vh;
+  width: 100%;
+  overflow-x: hidden;
+  position: relative;
+
+  .search-header {
+    background-color: #ffffff;
+    padding: 16rpx 30rpx;
+    display: flex;
+    align-items: center;
+    padding-top: calc(16rpx + var(--status-bar-height));
+    padding-left: 40rpx;
+    padding-right: 28rpx;
+    padding-bottom: 16rpx;
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 9;
+    width: 100%;
+    box-sizing: border-box;
+
+    .search-box {
+      flex: 1;
+      height: 72rpx;
+      background-color: #f1f1f1;
+      border-radius: 36rpx;
+      display: flex;
+      align-items: center;
+      padding: 0 24rpx;
+      padding-left: 14rpx;
+      width: 622rpx;
+      height: 72rpx;
+      background: #FFFFFF;
+      border-radius: 36rpx;
+      border: 6rpx solid #000000;
+      position: relative;
+      left: 0;
+      top: 0;
+      box-sizing: border-box;
+      max-width: calc(100% - 60rpx);
+
+      input {
+        flex: 1;
+        height: 100%;
+        margin: 0 16rpx;
+        font-size: 24rpx;
+        font-family: 'PingFang SC-Medium';
+        width: auto;
+        min-width: 0;
+      }
+
+      .searchImgBox {
+        width: 88rpx;
+        height: 56rpx;
+        background: #1F1F1F;
+        border-radius: 32rpx;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        position: absolute;
+        top: 50%;
+        right: 6rpx;
+        transform: translateY(-50%);
+        flex-shrink: 0;
+
+        .image {
+          width: 36rpx;
+          height: 36rpx;
+        }
+      }
+    }
+
+    .cancel-btn {
+      color: #1f1f1f;
+      width: 36rpx;
+      height: 100%;
+      margin-right: 24rpx;
+      font-weight: 700;
+      flex-shrink: 0;
+    }
+  }
+
+  .reserveASeat {
+    width: 100%;
+    min-height: calc(108rpx + var(--status-bar-height));
+  }
+
+  .search-history {
+    background-color: #ffffff;
+    padding: 30rpx;
+    padding-top: 15rpx;
+    width: 100%;
+    box-sizing: border-box;
+
+    .history-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15rpx;
+      width: 100%;
+      box-sizing: border-box;
+
+      .title {
+        font-size: 30rpx;
+        color: #333;
+        font-weight: bold;
+      }
+    }
+
+    .history-list {
+      transition: all 1s;
+      overflow: hidden;
+      width: 100%;
+      box-sizing: border-box;
+
+      .history-item {
+        display: flex;
+        align-items: center;
+        padding: 18rpx 0;
+        justify-content: space-between;
+        width: 100%;
+        box-sizing: border-box;
+
+        .history-text {
+          font-size: 28rpx;
+          color: #666;
+          display: flex;
+          align-items: center;
+          justify-content: flex-start;
+          font-weight: 400;
+          color: #1F1F1F;
+          margin-left: 6rpx;
+          font-family: 'PingFang SC-Bold';
+          flex: 1;
+          overflow: hidden;
+          min-width: 0;
+
+          image {
+            width: 32rpx;
+            height: 32rpx;
+            margin-right: 16rpx;
+            flex-shrink: 0;
+          }
+        }
+
+        .deleteBtn {
+          width: 30rpx;
+          height: 30rpx;
+          flex-shrink: 0;
+        }
+      }
+    }
+  }
+
+  .search-result {
+    background-color: #f6faf6;
+    height: calc(100vh - 108rpx - var(--status-bar-height) );  
+    width: 100%;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .no-data {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 60rpx 0;
+    // background-color: #fff;
+    width: 100%;
+    box-sizing: border-box;
+
+    text {
+      color: #808080;
+      font-size: 28rpx;
+    }
+  }
+}
+
+.expandBtn {
+  view {
+    font-family: 'PingFang SC-Bold';
+    color: #999999;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    &.fold {
+      image {
+        transform: rotate(180deg) translateY(-2rpx);
+      }
+    }
+
+    image {
+      width: 28rpx;
+      height: 28rpx;
+    }
+  }
+}
+
+.items-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 24rpx 12rpx;
+  padding: 16rpx 12rpx 0 12rpx;
+  background: #f2f6f2;
+}
+.loading-more { text-align: center; color: #999; font-size: 26rpx; padding: 24rpx 0; }
+.no-more { text-align: center; color: #ccc; font-size: 24rpx; padding: 20rpx 0; }
+
+
+.search-result {
+   
+  background: #f6faf6;
+  .custom-navbar {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    height: 90rpx;
+    padding: 0 20rpx;
+    padding-top: var(--status-bar-height);
+    background-color: #ffffff;
+    position: sticky;
+    top: 0;
+    height: calc(90rpx + var(--status-bar-height));
+    z-index: 100;
+
+    .navbar-left {
+      height: 80rpx;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      .fa-angle-left {
+        font-size: 48rpx;
+        color: #333;
+      }
+
+    }
+    .navbar-center {
+      .navbar-title {
+        max-width: 450rpx;
+        font-family: "PingFang SC-Bold";
+        font-weight: 400;
+        font-size: 32rpx;
+        color: #1f1f1f;
+        padding-left: 20rpx;
+      }
+    }
+
+    .navbar-right {
+      width: 80rpx;
+      height: 80rpx;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+
+      .fa-ellipsis-h {
+        font-size: 36rpx;
+        color: #333;
+      }
+    }
+  }
+  .tabs-reserveaseat{
+    width: 100vw;
+    height: 72rpx;
+  }
+  .tabs-section {
+    background: #fff;
+    border-bottom: 6rpx solid #f6faf6;
+    z-index: 100;
+    min-height: 72rpx;
+    .tabs-scroll-view {
+      width: 100vw;
+      box-sizing: border-box;
+      padding-left: 50rpx;
+
+      .tabs-wrapper {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        height: 72rpx;
+
+        .tab {
+          position: relative;
+          width: auto;
+          height: 48rpx;
+          font-size: 32rpx;
+          font-family: "PingFang SC-Bold";
+          color: #999;
+          font-weight: 400;
+          transition: all 0.5s;
+          margin-right: 40rpx;
+
+          .left {
+            white-space: nowrap;
+            display: inline-block;
+          }
+
+          ::after {
+            content: "";
+            position: absolute;
+            right: -15rpx;
+            top: 0;
+            width: 96rpx;
+            height: 48rpx;
+            background-image: url("../../static/me/wd_img_qiehuan.png");
+            background-size: auto 100%;
+            background-repeat: no-repeat;
+            opacity: 0;
+          }
+
+          &.active {
+            color: #1f1f1f;
+
+            text {
+              font-family: "PingFang SC-Bold";
+            }
+
+            ::after {
+              opacity: 0.7;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .order-list {
+    padding: 0 0 32rpx 0;
+    height: calc(100vh - 180rpx - var(--status-bar-height));
+    overflow-y: auto;
+    -webkit-overflow-scrolling: touch;
+    
+    .order-card {
+      background: #fff;
+      border-radius: 18rpx;
+      margin: 32rpx 24rpx 0 24rpx;
+      padding: 24rpx;
+
+      .order-header {
+        display: flex;
+        align-items: center;
+        margin-bottom: 12rpx;
+
+        .project-title {
+          font-size: 28rpx;
+          font-weight: bold;
+          color: #1f1f1f;
+          margin-right: 40rpx;
+        }
+
+        .tag-initiator {
+          font-size: 20rpx;
+          color: #b6ff4b;
+          background: #1f1f1f;
+          border-radius: 8rpx;
+          padding: 2rpx 12rpx;
+          margin-right: 12rpx;
+        }
+
+        .order-status {
+          font-size: 24rpx;
+          margin-left: auto;
+          white-space: nowrap;
+
+          &.status-waitPay {
+            color: #888;
+          }
+
+          &.status-paid {
+            color: #1f1f1f;
+          }
+
+          &.status-waitSend {
+            color: #888;
+          }
+
+          &.status-waitReceive {
+            color: #888;
+          }
+
+          &.status-waitComment {
+            color: #ff9900;
+          }
+
+          &.status-refund {
+            color: #1f1f1f;
+          }
+
+          &.status-finish {
+            color: #888;
+          }
+        }
+      }
+
+      .order-main {
+        display: flex;
+        align-items: center;
+        margin-bottom: 12rpx;
+
+        .order-img {
+          width: 120rpx;
+          height: 120rpx;
+          border-radius: 12rpx;
+          margin-right: 18rpx;
+        }
+
+        .order-info {
+          flex: 1;
+
+          .order-title {
+            font-size: 28rpx;
+            color: #1f1f1f;
+            font-weight: bold;
+            margin-bottom: 8rpx;
+          }
+
+          .order-spec {
+            font-size: 24rpx;
+            color: #888;
+          }
+        }
+
+        .order-price {
+          text-align: right;
+
+          view {
+            font-size: 28rpx;
+            color: #1f1f1f;
+          }
+
+          .order-count {
+            font-size: 22rpx;
+            color: #888;
+          }
+        }
+      }
+
+      .order-actions {
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        gap: 18rpx;
+
+        .btn {
+          min-width: 120rpx;
+          height: 56rpx;
+          line-height: 56rpx;
+          border-radius: 32rpx;
+          text-align: center;
+          font-size: 26rpx;
+          padding: 0 24rpx;
+          background: #f6faf6;
+          color: #1f1f1f;
+          border: 2rpx solid #e5e5e5;
+
+          &.btn-pay {
+            background: #1f1f1f;
+            color: #acf934;
+            border: none;
+          }
+
+          &.btn-delete {
+            background: #f6faf6;
+            color: #888;
+            border: 2rpx solid #e5e5e5;
+          }
+
+          &.btn-cancel {
+            background: #f6faf6;
+            color: #888;
+            border: 2rpx solid #e5e5e5;
+          }
+
+          &.btn-remind {
+            background: #fffbe6;
+            color: #1f1f1f;
+            border: 2rpx solid #ffe58f;
+          }
+
+          &.btn-confirm {
+            background: #1f1f1f;
+            color: #acf934;
+            border: none;
+          }
+
+          &.btn-comment {
+            background: #fff;
+            color: #1f1f1f;
+            border: 2rpx solid #e5e5e5;
+          }
+
+          &.btn-refund {
+            background: #fff;
+            color: #1f1f1f;
+            border: 2rpx solid #e5e5e5;
+          }
+        }
+      }
+    }
+  }
+
+  .order-swiper {
+    width: 100vw;
+    background: transparent;
+    transition: height 0.3s;
+    flex: 1;
+  }
+}
+</style>

+ 3 - 4
pages/index/workDetail.vue

@@ -682,13 +682,12 @@ export default {
         }
       });
     },
-    goCreate() {
-		console.log(222222222);
+    goCreate() { 
 		let url=''
 	if(this.articleInfo.lyrics ){
-		url = "/pages/makedetail/makeMusicDetail"
+		url = "/pages/makedetail/intelligentMusicProduction"
 	}else{
-		url = "/pages/makedetail/makeImgDetail"
+		url = "/pages/makedetail/intelligentLifeChart"
 	}
 	
 	uni.navigateTo({

+ 1 - 1
pages/login/login.vue

@@ -44,7 +44,7 @@
 					<block v-if="type == 'mobile'">
 						<view class="name">验证码:</view>
 						<view class="item">
-							<input type="text" class="input" v-model="code" placeholder="请输入验证码" maxlength="6" />
+							<input type="number" class="input" v-model="code" placeholder="请输入验证码" maxlength="6" />
 							<view class="btn blick-btn-animation" v-if="captchaTime === 0" @click="getCode">获取验证码</view>
 							 <!-- 使用云函数发送验证码 -->
 							<!-- <view class="btn blick-btn-animation" v-if="captchaTime === 0" @click="sendSms()">获取验证码</view> -->

+ 8 - 2
pages/message/mailMessage.vue

@@ -100,14 +100,14 @@
 			<template v-if="true || offset">
 				<block v-for="(item, index) in list3" :key="index">
 					<view class="msg-card"   @click="goPages('/pages/crowdFunding/customerService?id='+item.id)">
-						<image class="avatar" :src="item&&item.kefu_info&&item.kefu_info.avatar" />
+						<image class="avatar" :src="item&&item.user_avatar" />
 						<view class="msg-main">
 							<view class="msg-header">
 								<text class="nickname">{{ item&&item.kefu_info&&item.kefu_info.nickname }}</text>
 								<text class="tag"  > 发起人</text>
 								<text class="time">{{ item.create_time }}</text>
 							</view>
-							<view class="msg-content">{{ item.last_message }}</view>
+							<view class="msg-content">{{ item.message || item.last_message  }}</view>
 						</view>
 						<view v-if="item.unread_count >0" class="red-dot">{{ item.unread_count }}</view>
 					</view>
@@ -354,6 +354,7 @@ export default {
 				return url.split("|")[0];
 			}
 		},
+		 
 		getKefuConversations() {
 			uni.request({
 				url: this.$apiHost + '/App/kefuGetConversations',
@@ -366,6 +367,11 @@ export default {
 					console.log(res.data, "获取客服消息列表");
 					if (res.data && res.data.success == 'yes') {
 						this.list3 = res.data.data.conversations || [];
+						this.list3.forEach(item => {
+							item.message = JSON.parse(item.last_message).title || '';
+						});
+						console.log(this.list3, "获取客服消息列表");
+						
 						console.log(res.data.data.conversations, "获取客服消息列表");
 						
 					} else {

BIN
static/crowdFunding/search2.png


BIN
static/crowdFunding/wd_bg_bianjiziliao@3x.png


BIN
static/image/1080x1882.9.png


BIN
static/image/1082x1884.9.png