From e15dbdbc396f61a645c8d8a504b45476f1fcea08 Mon Sep 17 00:00:00 2001 From: xiangpei <xiangpei@timesnew.cn> Date: 星期五, 30 五月 2025 17:16:17 +0800 Subject: [PATCH] 评论点赞功能 --- pages/tabbar/video/video.vue | 600 ++++++++++++++++++++++++++++++++++------------------------- 1 files changed, 348 insertions(+), 252 deletions(-) diff --git a/pages/tabbar/video/video.vue b/pages/tabbar/video/video.vue index d6beb2f..edab4fc 100644 --- a/pages/tabbar/video/video.vue +++ b/pages/tabbar/video/video.vue @@ -11,10 +11,13 @@ <view class="video-preview" v-else> <video :src="videoInfo.url" - controls + :object-fit="formData.videoFit" class="video-player" :poster="videoInfo.cover || ''" ></video> + <view class="progress-box"> + <progress style="width: 100%;" :percent="videoUploadProgress" active-mode="forwards" show-info stroke-width="6" :active="true" active-color="#ff573e" /> + </view> <view class="video-actions"> <u-button type="error" size="mini" @click="reUpload">閲嶆柊涓婁紶</u-button> <u-button type="primary" size="mini" @click="chooseCover" v-if="videoInfo.url">閫夋嫨灏侀潰</u-button> @@ -29,8 +32,9 @@ <u-form-item label="鏍囬" prop="title" borderBottom> <u-input v-model="formData.title" - placeholder="璇疯緭鍏ヨ棰戞爣棰�" - maxlength="30" + placeholder="璇疯緭鍏ヨ棰戞爣棰�,20瀛椾互鍐�" + maxlength="20" + show-word-limit clearable /> </u-form-item> @@ -44,46 +48,43 @@ clearable @confirm="addTag" @blur="addTag" - @input="searchHotTopics" + @input="searchTags" ></u-input> <!-- 宸查�夎瘽棰樺睍绀� --> <view class="tags-display" v-if="formData.tags.length > 0"> - <u-tag + <my-tag v-for="(tag, index) in formData.tags" :key="index" - :text="tag" - closable + :text="tag.tagName" + :index="index" + type="error" @close="removeTag(index)" - size="medium" - type="primary" - style="margin-right: 10rpx; margin-bottom: 10rpx;" /> </view> <text class="tags-count" v-if="formData.tags.length > 0"> 宸查�� {{ formData.tags.length }}/5 </text> </view> + <!-- 璇濋鎺ㄨ崘 --> + <view class="hot-topics" v-if="showTopicRecommendations"> + <text class="section-title">{{ tagInput ? '鎺ㄨ崘璇濋' : '鐑棬璇濋' }}</text> + <view class="topic-list"> + <my-tag + v-for="(tag, index) in recommendedTags" + :key="index" + :text="tag.tagName" + :index="index" + type="primary" + :closeable="false" + @click="selectTopic(index)" + /> + </view> + </view> </u-form-item> - - <!-- 璇濋鎺ㄨ崘 --> - <view class="hot-topics" v-if="showTopicRecommendations"> - <text class="section-title">{{ tagInput ? '鎺ㄨ崘璇濋' : '鐑棬璇濋' }}</text> - <view class="topic-list"> - <u-tag - v-for="(topic, index) in recommendedTopics" - :key="index" - :text="topic" - size="medium" - type="info" - @click="selectTopic(topic)" - style="margin-right: 10rpx; margin-bottom: 10rpx;" - /> - </view> - </view> <!-- 鍟嗗搧閾炬帴 --> - <u-form-item label="鍟嗗搧" prop="goodsLink" borderBottom> + <u-form-item label="鍟嗗搧" prop="goodsId" borderBottom> <view class="goods-link-container"> <u-input placeholder="鍙�夋嫨鎺ㄨ崘鍟嗗搧" @@ -170,23 +171,47 @@ </template> <script> +import UIcon from '@/uview-components/uview-ui/components/u-icon/u-icon.vue'; +import UButton from '@/uview-components/uview-ui/components/u-button/u-button.vue'; +import UForm from '@/uview-components/uview-ui/components/u-form/u-form.vue'; +import UFormItem from '@/uview-components/uview-ui/components/u-form-item/u-form-item.vue'; +import UInput from '@/uview-components/uview-ui/components/u-input/u-input.vue'; +import USearch from '@/uview-components/uview-ui/components/u-search/u-search.vue'; +import UPopup from '@/uview-components/uview-ui/components/u-popup/u-popup.vue'; +import MyTag from "@/components/my-tag.vue" +import { getSTSToken } from "@/api/common.js"; +import { publish } from "@/api/video.js"; +import { getRecommendTag3 } from "@/api/video-tag.js"; +import { getFileKey } from "@/utils/file.js"; export default { + components: {MyTag,UIcon,UButton,UForm,UFormItem,UInput,USearch,UPopup}, data() { return { + cosClient: null, + bucket: '', + region: '', + videoUploadProgress: 0, loading: false, showGoodsPicker: false, goodsSearch: '', tagInput: '', videoInfo: { - url: '', - cover: '', - duration: 0, - size: 0 - }, + url: '', + fileKey: '', + fileType: '', + fileSize: 0, + originalFileName: '', + cover: '' + }, formData: { + id: '', title: '', - goodsLink: '', - tags: [] + videoFileKey: '', + videoDuration: 0, + videoFit: 'cover', + goodsId: '', + tags: [], + fileInfo: {} }, selectedGoods: null, goodsList: [ @@ -201,57 +226,20 @@ name: '鏅鸿兘鎵嬬幆杩愬姩鎵嬭〃', price: '299.00', image: 'https://via.placeholder.com/100' - }, - { - id: '3', - name: '渚挎惡寮忓厖鐢靛疂10000mAh', - price: '99.00', - image: 'https://via.placeholder.com/100' - }, - { - id: '4', - name: '楂樻竻骞胯鎵嬫満闀滃ご', - price: '59.00', - image: 'https://via.placeholder.com/100' - }, - { - id: '5', - name: '澶氬姛鑳芥姌鍙犻敭鐩�', - price: '159.00', - image: 'https://via.placeholder.com/100' } ], - hotTopics: [ - '#浜斾竴鏃呰鎵撳崱', - '#缇庨鎺㈠簵', - '#绉戞妧鏂板搧', - '#鍋ヨ韩鏃ュ父', - '#瀹犵墿钀屽疇' - ], - recommendedTopics: [], + recommendedTags: [], rules: { title: [ { required: true, message: '璇疯緭鍏ヨ棰戞爣棰�', trigger: 'blur' }, - { min: 2, max: 30, message: '鏍囬闀垮害鍦�2鍒�30涓瓧绗�', trigger: 'blur' } - ], - goodsLink: [ - { required: true, message: '璇烽�夋嫨鍟嗗搧閾炬帴', trigger: 'change' } - ], - tags: [ - { validator: (rule, value, callback) => { - if (value.length === 0) { - callback(new Error('璇疯嚦灏戞坊鍔犱竴涓瘽棰�')); - } else { - callback(); - } - }, trigger: 'change' } + { min: 1, max: 20, message: '鏍囬闀垮害鍦�1鍒�20涓瓧绗�', trigger: 'blur' } ] } }; }, computed: { canPublish() { - return this.videoInfo.url && this.formData.title && this.formData.goodsLink && this.formData.tags.length > 0; + return this.formData.videoFileKey && this.formData.title; }, filteredGoods() { if (!this.goodsSearch) return this.goodsList; @@ -260,14 +248,50 @@ ); }, showTopicRecommendations() { - return (this.tagInput === '' || this.recommendedTopics.length > 0) && this.formData.tags.length < 5; + return (this.tagInput === '' || this.recommendedTags.length > 0) && this.formData.tags.length < 5; } }, created() { - // 鍒濆鍖栨帹鑽愯瘽棰� - this.recommendedTopics = this.hotTopics.slice(0, 3); + + }, + onShow() { + this.initCOS() + // 鍒濆鍖栨帹鑽愭爣绛� + this.getRecommendTags() }, methods: { + // 鑾峰彇鎺ㄨ崘鏍囩 + async getRecommendTags(type) { + const params = { + tagName: this.tagInput.trim(), + searchType: type + } + getRecommendTag3(params).then(res => { + this.recommendedTags = res.data.data + }) + }, + // 鍒濆鍖栬吘璁簯cos瀹㈡埛绔� + initCOS() { + console.log("鎵ц浜�"); + // 璋冪敤鍚庣鑾峰彇sts涓存椂璁块棶鍑瘉 + getSTSToken().then(res => { + const COS = require('@/lib/cos-wx-sdk-v5.js'); // 寮�鍙戞椂浣跨敤 + // const COS = require('./lib/cos-wx-sdk-v5.min.js'); // 涓婄嚎鏃朵娇鐢ㄥ帇缂╁寘 + + // console.log(COS.version); sdk 鐗堟湰闇�瑕佷笉浣庝簬 1.7.2 + this.cosClient = new COS({ + SecretId: res.data.data.tmpSecretId, // sts 鏈嶅姟涓嬪彂鐨勪复鏃� secretId + SecretKey: res.data.data.tmpSecretKey, // sts 鏈嶅姟涓嬪彂鐨勪复鏃� secretKey + SecurityToken: res.data.data.sessionToken, // sts 鏈嶅姟涓嬪彂鐨勪复鏃� SessionToken + StartTime: res.data.data.stsStartTime, // 寤鸿浼犲叆鏈嶅姟绔椂闂达紝鍙伩鍏嶅鎴风鏃堕棿涓嶅噯瀵艰嚧鐨勭鍚嶉敊璇� + ExpiredTime: res.data.data.stsEndTime, // 涓存椂瀵嗛挜杩囨湡鏃堕棿 + SimpleUploadMethod: 'putObject', // 寮虹儓寤鸿锛岄珮绾т笂浼犮�佹壒閲忎笂浼犲唴閮ㄥ灏忔枃浠跺仛绠�鍗曚笂浼犳椂浣跨敤 putObject,sdk 鐗堟湰鑷冲皯闇�瑕乿1.3.0 + }); + this.bucket = res.data.data.bucket + this.region = res.data.data.region + }) + + }, // 閫夋嫨瑙嗛 chooseVideo() { uni.chooseVideo({ @@ -275,23 +299,78 @@ maxDuration: 60, camera: 'back', success: (res) => { - this.videoInfo = { - url: res.tempFilePath, - duration: res.duration, - size: res.size, - cover: res.thumbTempFilePath - }; + this.videoUploadProgress = 0 + // 鑾峰彇鏂囦欢鍚� + const tempPath = res.tempFilePath; + let fileName = tempPath.substring(tempPath.lastIndexOf('/') + 1); + + // 澶勭悊瀹夊崜鍙兘鐨刄RI缂栫爜 + if(fileName.indexOf('%') > -1) { + fileName = decodeURIComponent(fileName); + } + const fileKey = getFileKey(fileName); + this.videoInfo = { + url: res.tempFilePath, + fileKey: fileKey, + fileType: fileKey.split('/')[0], + fileSize: res.size, + originalFileName: fileName, + cover: '' + }; + this.formData.videoFileKey = fileKey; + this.formData.videoDuration = res.duration; + // 鍒ゆ柇瑙嗛鐨勫~鍏呮ā寮� + this.formData.videoFit = this.calculateVideoFit(res.width, res.height) + + this.cosClient.uploadFile({ + Bucket: this.bucket, + Region: this.region, + Key: fileKey, + FilePath: res.tempFilePath, + SliceSize: 1024 * 1024 * 5, /* 瑙﹀彂鍒嗗潡涓婁紶鐨勯槇鍊�,5M */ + onProgress: (progressData) => { + console.log(progressData.percent); + this.videoUploadProgress = progressData.percent * 100 + } + }, (err, data) => { + if (err) { + console.log('涓婁紶澶辫触', err); + this.videoInfo = { + url: '', + fileKey: '', + fileType: '', + fileSize: 0, + originalFileName: '', + cover: '' + } + } else { + console.log(this.videoInfo); + } + }); }, fail: (err) => { uni.showToast({ - title: '閫夋嫨瑙嗛澶辫触', + title: '鏈�夋嫨瑙嗛', icon: 'none' }); console.error(err); } }); }, - + // 鏍规嵁瀹介珮姣旈�夋嫨瑙嗛濉厖妯″紡 + calculateVideoFit(width, height) { + const viewportRatio = uni.getSystemInfoSync().windowWidth / uni.getSystemInfoSync().windowHeight; + const videoRatio = width / height; + + // 瑙勫垯1锛氳秴瀹借棰戯紙濡傜數褰�21:9锛� + if (videoRatio > 2) return 'contain'; + + // 瑙勫垯2锛氱珫灞忚棰戯紙濡�9:16锛� + if (videoRatio < 0.8) return 'cover'; + + // 瑙勫垯3锛氭帴杩戝睆骞曟瘮渚嬬殑妯睆瑙嗛 + return Math.abs(videoRatio - viewportRatio) > 0.3 ? 'contain' : 'cover'; + }, // 閲嶆柊涓婁紶 reUpload() { this.videoInfo = { @@ -323,68 +402,64 @@ // 閫夋嫨鍏蜂綋鍟嗗搧 selectGoods(goods) { this.selectedGoods = goods; - this.formData.goodsLink = `https://example.com/goods/${goods.id}`; + this.formData.goodsId = goods.id; this.showGoodsPicker = false; }, // 娓呴櫎鍟嗗搧 clearGoods() { this.selectedGoods = null; - this.formData.goodsLink = ''; + this.formData.goodsId = ''; }, // 鎼滅储鐑棬璇濋 - searchHotTopics() { - if (this.tagInput.trim() === '') { - // 鏄剧ず鐑棬璇濋 - this.recommendedTopics = this.hotTopics.slice(0, 3); - } else { - // 妯℃嫙鎼滅储鎺ㄨ崘璇濋 - const input = this.tagInput.trim().toLowerCase(); - this.recommendedTopics = this.hotTopics - .filter(topic => topic.toLowerCase().includes(input)) - .slice(0, 3); + searchTags() { + if (this.tagInput.trim() !== '') { + this.getRecommendTags("SEARCH") } }, - // 娣诲姞鏍囩 addTag() { - const newTag = this.tagInput.trim(); + if(!this.tagInput.trim()) { + return + } + const newTag = {'id': '', 'tagName': this.tagInput.trim()}; if (newTag && this.formData.tags.length < 5) { - if (!this.formData.tags.includes(newTag)) { + if (this.formData.tags.filter(item => item.tagName === newTag.tagName).length < 1) { this.formData.tags.push(newTag); this.tagInput = ''; - this.recommendedTopics = this.hotTopics.slice(0, 3); // 閲嶇疆鎺ㄨ崘 + this.getRecommendTags() // 閲嶇疆鎺ㄨ崘 } else { uni.showToast({ - title: '璇濋宸叉坊鍔�', + title: '璇ヨ瘽棰樺凡娣诲姞杩囦簡~', icon: 'none' }); } } else if (this.formData.tags.length >= 5) { uni.showToast({ - title: '鏈�澶氭坊鍔�5涓瘽棰�', + title: '鏈�澶氭坊鍔�5涓瘽棰榽', icon: 'none' }); } }, // 閫夋嫨鎺ㄨ崘璇濋 - selectTopic(topic) { + selectTopic(index) { + const tag = this.recommendedTags[index] if (this.formData.tags.length >= 5) { uni.showToast({ - title: '鏈�澶氭坊鍔�5涓瘽棰�', + title: '鏈�澶氭坊鍔�5涓瘽棰榽', icon: 'none' }); return; } - if (!this.formData.tags.includes(topic)) { - this.formData.tags.push(topic); + if (this.formData.tags.filter(item => item.tagName === tag.tagName).length < 1) { + this.formData.tags.push(tag); this.tagInput = ''; } else { uni.showToast({ - title: '璇濋宸叉坊鍔�', + title: '璇ヨ瘽棰樺凡娣诲姞杩囦簡~', icon: 'none' }); } @@ -400,40 +475,47 @@ this.$refs.formRef.validate(valid => { if (valid && this.canPublish) { this.loading = true; - - // 杩欓噷搴旇鏄笂浼犺棰戝埌鏈嶅姟鍣ㄧ殑閫昏緫 - // 妯℃嫙涓婁紶杩囩▼ - setTimeout(() => { - this.loading = false; - uni.showToast({ - title: '鍙戝竷鎴愬姛', - icon: 'success' - }); - - // 閲嶇疆琛ㄥ崟 - this.videoInfo = { - url: '', - cover: '', - duration: 0, - size: 0 - }; - this.formData = { - title: '', - goodsLink: '', - tags: [] - }; - this.selectedGoods = null; - this.tagInput = ''; - this.recommendedTopics = this.hotTopics.slice(0, 3); - - // 杩斿洖涓婁竴椤� - setTimeout(() => { - uni.navigateBack(); - }, 1500); - }, 2000); + this.formData.fileInfo = this.videoInfo; + console.log(this.formData); + publish(this.formData).then(res => { + uni.showToast({ + title: '瑙嗛宸叉彁浜ゅ鏍竳', + icon: 'success' + }); + this.loading = false + // 閲嶇疆琛ㄥ崟 + this.videoInfo = { + url: '', + fileKey: '', + fileType: '', + fileSize: 0, + originalFileName: '', + cover: '' + }; + this.formData = { + id: '', + title: '', + videoFileKey: '', + videoFit: 'cover', + videoDuration: 0, + goodsId: '', + tags: [], + fileInfo: {} + }; + this.selectedGoods = null; + this.tagInput = ''; + this.recommendedTags = []; + + // TODO 鍏堣烦棣栭〉,鍚庨潰璺虫垜鐨勮棰戦〉闈� + setTimeout(() => { + uni.switchTab({ + url: '/pages/tabbar/index/home' + }); + }, 1500); + }) } else { uni.showToast({ - title: '璇峰畬鍠勮棰戜俊鎭�', + title: '璇峰畬鍠勮棰戜俊鎭瘇', icon: 'none' }); } @@ -443,7 +525,7 @@ }; </script> -<style lang="scss" scoped> +<style scoped> .publish-container { padding: 20rpx; padding-bottom: 120rpx; @@ -515,67 +597,74 @@ background-color: #f9f9f9; border-radius: 8rpx; margin-top: 15rpx; - - .goods-image { - width: 80rpx; - height: 80rpx; - border-radius: 8rpx; - margin-right: 15rpx; - } - - .goods-info { - flex: 1; - display: flex; - flex-direction: column; - - .goods-name { - font-size: 26rpx; - color: #333; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .goods-price { - font-size: 28rpx; - color: #f44; - font-weight: bold; - } - } +} + +.goods-preview .goods-image { + width: 80rpx; + height: 80rpx; + border-radius: 8rpx; + margin-right: 15rpx; +} + +.goods-preview .goods-info { + flex: 1; + display: flex; + flex-direction: column; +} + +.goods-preview .goods-info .goods-name { + font-size: 26rpx; + color: #333; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.goods-preview .goods-info .goods-price { + font-size: 28rpx; + color: #f44; + font-weight: bold; +} + +.topic-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + line-height: 22px; } .tags-input-container { width: 100%; - - .tags-display { - display: flex; - flex-wrap: wrap; - margin-top: 15rpx; - } - - .hot-topics { - margin-top: 15rpx; - - .section-title { - font-size: 24rpx; - color: #999; - display: block; - margin-bottom: 10rpx; - } - - .topic-list { - display: flex; - flex-wrap: wrap; - } - } - - .tags-count { - display: block; - font-size: 24rpx; - color: #999; - margin-top: 10rpx; - text-align: right; - } +} + +.tags-display { + display: flex; + flex-wrap: wrap; + margin-top: 15rpx; + line-height: 22px; +} + +.hot-topics { + display: flex; + flex-direction: column; + margin-top: 15rpx; + margin-bottom: 15rpx; +} + +.section-title { + font-size: 12px; + color: #999; + line-height: 12px; + margin-bottom: 6rpx; +} + +.tags-count { + display: block; + font-size: 12px; + line-height: 12px; + color: #999; + margin-top: 10rpx; + text-align: right; } .publish-btn { @@ -590,60 +679,67 @@ height: 100%; display: flex; flex-direction: column; - - .picker-header { +} + +.goods-picker .picker-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30rpx; +} + +.goods-picker .picker-header .picker-title { + font-size: 36rpx; + font-weight: bold; +} + +.goods-picker .search-bar { + margin-bottom: 20rpx; +} + +.goods-picker .goods-list { + flex: 1; + overflow: hidden; +} + +.goods-picker .goods-list .goods-item { + display: flex; + align-items: center; + padding: 20rpx 0; + border-bottom: 1rpx solid #f5f5f5; +} + +.goods-picker .goods-list .goods-item .goods-image { + width: 100rpx; + height: 100rpx; + border-radius: 8rpx; + margin-right: 20rpx; +} + +.goods-picker .goods-list .goods-item .goods-info { + flex: 1; +} + +.goods-picker .goods-list .goods-item .goods-info .goods-name { + font-size: 28rpx; + color: #333; + margin-bottom: 10rpx; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.goods-picker .goods-list .goods-item .goods-info .goods-price { + font-size: 28rpx; + color: #f44; + font-weight: bold; +} + +.progress-box { + width: 100%; display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 30rpx; - - .picker-title { - font-size: 36rpx; - font-weight: bold; - } - } - - .search-bar { - margin-bottom: 20rpx; - } - - .goods-list { - flex: 1; - overflow: hidden; - - .goods-item { - display: flex; - align-items: center; - padding: 20rpx 0; - border-bottom: 1rpx solid #f5f5f5; - - .goods-image { - width: 100rpx; - height: 100rpx; - border-radius: 8rpx; - margin-right: 20rpx; - } - - .goods-info { - flex: 1; - - .goods-name { - font-size: 28rpx; - color: #333; - margin-bottom: 10rpx; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - } - - .goods-price { - font-size: 28rpx; - color: #f44; - font-weight: bold; - } - } - } - } + height: 25px; + margin-top: 10px; } </style> \ No newline at end of file -- Gitblit v1.8.0