This commit is contained in:
zyronon 2024-04-01 03:19:49 +08:00
parent e53c2db532
commit a8f0f64868
49 changed files with 1592 additions and 655 deletions

653
public/data/goods.json Normal file
View File

@ -0,0 +1,653 @@
[
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
},
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
},
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
},
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
},
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
},
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
},
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": "g6-0.jpg",
"imgs": [
"g6-0.jpg",
"g6-1.jpg",
"g6-2.jpg",
"g6-3.jpg",
"g6-4.jpg"
],
"price": 6699,
"real_price": 399,
"isLowPrice": false,
"discount": "",
"sold": 863
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": "g1-0.jpg",
"imgs": [
"g1-0.jpg",
"g1-1.jpg",
"g1-2.jpg",
"g1-3.jpg"
],
"isLowPrice": true,
"discount": "满4减3",
"sold": 134,
"price": 39.9,
"real_price": 9.9
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"imgs": [
"g2-0.webp",
"g2-1.webp",
"g2-2.webp",
"g2-3.webp"
],
"cover": "g2-0.webp",
"real_price": 9.9,
"price": 49.99,
"isLowPrice": false,
"discount": "满20减5",
"sold": 3314
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": "g3-0.jpg",
"imgs": [
"g3-0.jpg",
"g3-1.jpg",
"g3-2.jpg",
"g3-3.jpg",
"g3-4.jpg"
],
"real_price": 9.9,
"price": 22.90,
"isLowPrice": true,
"discount": "满10减3",
"sold": 129
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": "g4-0.png",
"imgs": [
"g4-0.png",
"g4-1.png",
"g4-2.png",
"g4-3.png"
],
"real_price": 199.9,
"price": 2999,
"isLowPrice": true,
"discount": "",
"sold": 967
},
{
"name": "小米笔记本Pro X 14",
"imgs": [
"g5-0.jpg",
"g5-1.jpg",
"g5-2.jpg",
"g5-3.jpg",
"g5-4.jpg"
],
"cover": "g5-0.jpg",
"real_price": 1559.9,
"price": 6999,
"isLowPrice": false,
"discount": "",
"sold": 473
}
]

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 231 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -3,6 +3,7 @@ import request from "../utils/request";
export function userinfo(params, data) {
return request({url: '/user/userinfo', method: 'get', params, data})
}
export function userVideoList(params, data) {
return request({url: '/user/video_list', method: 'get', params, data})
}
@ -21,4 +22,8 @@ export function userCollect(params, data) {
export function recommendedPost(params, data) {
return request({url: '/post/recommended', method: 'get', params, data})
}
export function recommendedShop(params, data) {
return request({url: '/shop/recommended', method: 'get', params, data})
}

View File

@ -1,65 +0,0 @@
export default {
list: [
{
"name": "小米电视6 65\" OLED 65英寸",
"cover": new URL('@/assets/img/goods/g6-0.jpg', import.meta.url).href,
imgs:[
new URL('../img/goods/g6-0.jpg', import.meta.url).href,
new URL('../img/goods/g6-1.jpg', import.meta.url).href,
new URL('../img/goods/g6-2.jpg', import.meta.url).href,
new URL('../img/goods/g6-3.jpg', import.meta.url).href,
new URL('../img/goods/g6-4.jpg', import.meta.url).href,
],
price: 6699,
isLowPrice: false,
discount: '',
sold: 863,
},
{
"name": "红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫",
"cover": new URL('../img/goods/g1-0.jpg', import.meta.url).href,
imgs:[
new URL('../img/goods/g1-0.jpg', import.meta.url).href,
new URL('../img/goods/g1-1.jpg', import.meta.url).href,
new URL('../img/goods/g1-2.jpg', import.meta.url).href,
new URL('../img/goods/g1-3.jpg', import.meta.url).href,
],
isLowPrice: true,
discount: '满4减3',
sold: 134,
price: 39.9,
},
{
"name": "森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮",
"cover": new URL('../img/goods/g2-0.webp', import.meta.url).href,
price: 49.99,
isLowPrice: false,
discount: '满20减5',
sold: 3314,
},
{
"name": "ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫",
"cover": new URL('../img/goods/g3-0.jpg', import.meta.url).href,
price: 22.90,
isLowPrice: true,
discount: '满10减3',
sold: 129,
},
{
"name": "Redmi K60狠快狠强狠旗舰2023第一台梦幻手机",
"cover": new URL('../img/goods/g4-0.png', import.meta.url).href,
price: 2999,
isLowPrice: true,
discount: '',
sold: 967,
},
{
"name": "小米笔记本Pro X 14",
"cover": new URL('../img/goods/g5-0.jpg', import.meta.url).href,
price: 6999,
isLowPrice: false,
discount: '',
sold: 473,
},
]
}

View File

@ -3,12 +3,12 @@
<div class="DouyinCode" v-if="modelValue">
<div class="content">
<div class="video-poster">
<img src="../assets/img/poster/1.jpg" class="poster">
<img :src="_checkImgUrl(item.video.cover.url_list[0])" class="poster">
</div>
<div class="desc">
<div class="left">
<div class="user">@名字</div>
<div class="title">#窃书不能算偷窃书读书人的事能算偷么</div>
<div class="user">@{{item.author.nickname}}</div>
<div class="title">{{item.desc}}</div>
</div>
<img class="code" src="../assets/img/icon/components/video/douyin-code.jpg" alt="">
</div>
@ -43,9 +43,12 @@
</transition>
</template>
<script>
import {_checkImgUrl} from "@/utils";
export default {
name: "DouyinCode",
props: {
item:{},
modelValue: false
},
data() {
@ -55,6 +58,7 @@ export default {
created() {
},
methods: {
_checkImgUrl,
cancel() {
this.$emit('update:modelValue', false)
}
@ -87,16 +91,22 @@ export default {
overflow: hidden;
.desc {
margin-bottom: 20rem;
display: flex;
gap: 20rem;
padding: 10rem;
.left {
font-size: 18rem;
.title {
margin-top: 10rem;
font-size: 14rem;
color: var(--second-text-color);
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; //
-webkit-box-orient: vertical; //--
-webkit-line-clamp: 1; //
}
}
.code {
@ -134,11 +144,11 @@ export default {
.shares {
display: flex;
padding-right: @space-width * 2;
margin-bottom: @space-width;
gap: 20rem;
padding-left: 20rem;
.share-to {
margin-left: 28rem;
margin-bottom: @space-width;
img {
width: @icon-width;
@ -159,6 +169,7 @@ export default {
.cancel {
font-size: 16rem;
background: rgb(38, 38, 38);
color: rgba(white,.8);
padding: 15rem;
text-align: center;
}

View File

@ -27,7 +27,7 @@
</div>
<div class="shares list">
<template v-if="mode === 'video'">
<div class="option" @click.stop="$no">
<div class="option" @click.stop="closeShare($emit('ShareToFriend'))">
<img class="avatar" src="../assets/img/icon/components/video/torichang.png" alt="">
<span>转发</span>
</div>
@ -51,7 +51,7 @@
<img class="small" src="../assets/img/icon/components/video/warring.png" alt="">
<span>举报</span>
</div>
<div class="option" @click.stop="$nav('/home/report',{mode:this.mode})">
<div class="option" @click.stop="closeShare($emit('ShareToFriend'))">
<Icon icon="ion:paper-plane"/>
<span>私信朋友</span>
</div>
@ -73,7 +73,7 @@
<span>不感兴趣</span>
</div>
<div class="option" @click.stop="closeShare($emit('showDouyinCode'))">
<img class="small" src="../assets/img/icon/components/video/dislike.png" alt="">
<Icon icon="tabler:photo"/>
<span>生成图片</span>
</div>
<div class="option" @click.stop="$no">
@ -133,7 +133,7 @@ import Check from "./Check";
import FromBottomDialog from "./dialog/FromBottomDialog";
import DouyinCode from "./DouyinCode";
import {useBaseStore} from "@/store/pinia";
import {$no} from "@/utils";
import {$no, _copy} from "@/utils";
export default {
name: "Share",
@ -144,6 +144,7 @@ export default {
},
props: {
modelValue: false,
item: {},
videoId: {
type: String,
default: null
@ -170,8 +171,7 @@ export default {
}
},
data() {
return {
}
return {}
},
methods: {
$no,
@ -180,6 +180,7 @@ export default {
this.$showLoading()
await this.$sleep(500)
this.$hideLoading()
_copy(this.item.share_info.share_link_desc + this.item.share_info.share_url)
//TODO
this.$notice('复制成功')
},

View File

@ -62,7 +62,7 @@ export default {
},
borderRadius: {
type: String,
default: '5rem 5rem 0 0'
default: '15rem 15rem 0 0'
},
tag: {
type: String,
@ -218,11 +218,11 @@ export default {
}
.heng-gang {
border-radius: 5rem 5rem 0 0;
border-radius: 15rem 15rem 0 0;
z-index: 3;
width: 100%;
position: fixed;
height: 20rem;
height: 30rem;
display: flex;
transform: translateY(-24rem);
justify-content: center;

View File

@ -20,57 +20,67 @@
<p> 您的浏览器不支持 video 标签</p>
</video>
<Icon icon="fluent:play-28-filled" class="pause-icon" v-if="!isPlaying"/>
<div class="float" :style="{opacity: isUp?0:1}">
<div :style="{opacity:isMove ? 0:1}" class="normal">
<template v-if="!commentVisible">
<ItemToolbar v-model:item="localItem"
:position="position"
v-bind="$attrs"
/>
<ItemDesc
v-model:item="localItem"
:position="position"
/>
</template>
<div v-if="isMy" class="comment-status">
<div class="comment">
<div class="type-comment">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar">
<div class="right">
<p>
<span class="name">zzzzz</span>
<span class="time">2020-01-20</span>
</p>
<p class="text">北京</p>
</div>
</div>
<transition-group name="comment-status" tag="div" class="loveds">
<div class="type-loved" :key="i" v-for="i in test">
<div class="float">
<template v-if="isLive">
<div class="living">点击进入直播间</div>
<ItemDesc
:is-live="true"
v-model:item="localItem"
:position="position"
/>
</template>
<template v-else>
<div :style="{opacity:isMove ? 0:1}" class="normal">
<template v-if="!commentVisible">
<ItemToolbar v-model:item="localItem"
:position="position"
v-bind="$attrs"
/>
<ItemDesc
v-model:item="localItem"
:position="position"
/>
</template>
<div v-if="isMy" class="comment-status">
<div class="comment">
<div class="type-comment">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar">
<img src="../../assets/img/icon/love.svg" alt="" class="loved">
<div class="right">
<p>
<span class="name">zzzzz</span>
<span class="time">2020-01-20</span>
</p>
<p class="text">北京</p>
</div>
</div>
</transition-group>
<transition-group name="comment-status" tag="div" class="loveds">
<div class="type-loved" :key="i" v-for="i in test">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar">
<img src="../../assets/img/icon/love.svg" alt="" class="loved">
</div>
</transition-group>
</div>
</div>
</div>
</div>
<div class="progress"
:class="progressClass"
ref="progress"
@click="null"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
>
<div class="time" v-if="isMove">
<span class="currentTime">{{ LUtils.$duration(currentTime) }}</span>
<span class="duration"> / {{ LUtils.$duration(duration) }}</span>
<div class="progress"
:class="progressClass"
ref="progress"
@click="null"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
>
<div class="time" v-if="isMove">
<span class="currentTime">{{ LUtils.$duration(currentTime) }}</span>
<span class="duration"> / {{ LUtils.$duration(duration) }}</span>
</div>
<template v-if="duration > 15 || isMove || !isPlaying">
<div class="bg"></div>
<div class="progress-line" :style="durationStyle"></div>
<div class="point"></div>
</template>
</div>
<template v-if="duration > 15 || isMove || !isPlaying">
<div class="bg"></div>
<div class="progress-line" :style="durationStyle"></div>
<div class="point"></div>
</template>
</div>
</template>
</div>
</div>
</template>
@ -125,7 +135,7 @@ export default {
return false
}
},
isUp: {
isLive: {
type: Boolean,
default: () => {
return false
@ -290,29 +300,34 @@ export default {
}
},
click({uniqueId, index, type}) {
// console.log(this.position)
if (
this.position.uniqueId === uniqueId &&
this.position.index === index
) {
if (type === EVENT_KEY.ITEM_TOGGLE) {
if (this.status === SlideItemPlayStatus.Play) {
this.pause()
} else {
this.play()
if (this.isLive) {
if (type === EVENT_KEY.ITEM_TOGGLE) {
bus.emit(EVENT_KEY.NAV, {path: '/home/live', query: {id: this.item.id}})
}
} else {
if (type === EVENT_KEY.ITEM_TOGGLE) {
if (this.status === SlideItemPlayStatus.Play) {
this.pause()
} else {
this.play()
}
}
if (type === EVENT_KEY.ITEM_STOP) {
this.$refs.video.currentTime = 0
this.ignoreWaiting = true
this.pause()
setTimeout(() => this.ignoreWaiting = false, 300)
}
if (type === EVENT_KEY.ITEM_PLAY) {
this.$refs.video.currentTime = 0
this.ignoreWaiting = true
this.play()
setTimeout(() => this.ignoreWaiting = false, 300)
}
}
if (type === EVENT_KEY.ITEM_STOP) {
this.$refs.video.currentTime = 0
this.ignoreWaiting = true
this.pause()
setTimeout(() => this.ignoreWaiting = false, 300)
}
if (type === EVENT_KEY.ITEM_PLAY) {
this.$refs.video.currentTime = 0
this.ignoreWaiting = true
this.play()
setTimeout(() => this.ignoreWaiting = false, 300)
}
}
},
@ -713,4 +728,17 @@ export default {
}
}
.living {
position: absolute;
left: 50%;
font-size: 18rem;
border-radius: 50rem;
border: 1px solid #e0e0e0;
padding: 15rem 20rem;
line-height: 1;
color: white;
top: 70%;
transform: translate(-50%, -50%);
}
</style>

View File

@ -22,6 +22,12 @@ const props = defineProps({
return false
}
},
isLive: {
type: Boolean,
default: () => {
return false
}
},
})
const state = reactive({
@ -43,6 +49,7 @@ const state = reactive({
<span>{{ props.item.address }}</span>
</div>
</div>
<div class="live" v-if="props.isLive">直播中</div>
<div class="name mb1r f18 fb" @click.stop="$emit('goUserInfo')">@{{ props.item.author.nickname }}</div>
<div class="description">
{{ props.item.desc }}
@ -113,6 +120,16 @@ const state = reactive({
}
}
.live{
border-radius: 3rem;
margin-bottom: 10rem;
padding: 3rem 6rem;
font-size: 11rem;
display: inline-flex;
background: var(--primary-btn-color);
color: white;
}
.music {
position: relative;
display: flex;

View File

@ -203,15 +203,16 @@ function getInsEl(item, index, play = false) {
}
})
return parent
} else {
const app = createApp({
render() {
return <SlideItem data-index={index}>{slideVNode}</SlideItem>
}
})
const ins = app.mount(parent)
appInsMap.set(index, app)
return ins.$el
}
const app = createApp({
render() {
return <SlideItem data-index={index}>{slideVNode}</SlideItem>
}
})
const ins = app.mount(parent)
appInsMap.set(index, app)
return ins.$el
}
function touchStart(e) {

View File

@ -78,7 +78,7 @@ async function fetchData() {
export async function startMock() {
mock.onGet(/video\/recommended/).reply(async (config) => {
let page = getPage2(config.params)
console.log('allRecommendVideos', cloneDeep(allRecommendVideos.length),page)
console.log('allRecommendVideos', cloneDeep(allRecommendVideos.length), page)
return [200, {
data: {
total: 844,
@ -143,7 +143,7 @@ export async function startMock() {
if (!userVideos.length) {
// let r = await fetch(BASE_URL + '/data/user-71158770.json')
// let r = await fetch(BASE_URL + '/data/user-8357999.json')
let r = await fetch(BASE_URL + '/data/user-12345xiaolaohu.json')
let r = await fetch(BASE_URL + '/data/user_video_list/user-12345xiaolaohu.json')
let list = await r.json()
const baseStore = useBaseStore()
let userList = cloneDeep(baseStore.users)
@ -243,5 +243,18 @@ export async function startMock() {
}]
})
mock.onGet(/shop\/recommended/).reply(async (config) => {
let page = getPage2(config.params)
let r2 = await fetch(BASE_URL + '/data/goods.json')
let v = await r2.json()
return [200, {
data: {
total: v.length,
list: v.slice(page.offset, page.limit)
}, code: 200
}]
})
setTimeout(fetchData, 1000)
}

View File

@ -1,16 +1,30 @@
<template>
<div class="LivePage" ref="page">
<div class="live-wrapper">
<img src="../../assets/img/poster/1.jpg" alt="">
<video
src="https://www.douyin.com/aweme/v1/play/?video_id=v0d00fg10000cj1lq4jc77u0ng6s1gt0&amp;line=0&amp;file_id=bed51c00899b458cbc5d8280147c22a1&amp;sign=7749aec7bd62a3760065f60e40fc1867&amp;is_play_url=1&amp;source=PackSourceEnum_PUBLISH"
poster="/images/jwWCPZVTIA4IKM-8WipLF.png"
preload=""
loop=""
muted
x5-video-player-type="h5-page"
x5-video-player-fullscreen="false"
webkit-playsinline="true"
x5-playsinline="true"
playsinline="true"
fullscreen="false"
autoplay="">
<p> 您的浏览器不支持 video 标签</p>
</video>
</div>
<div class="float">
<div class="top">
<div class="left">
<div class="liver">
<img class="avatar" src="../../assets/img/icon/avatar/10.png" alt="">
<img class="avatar" :src="_checkImgUrl(userinfo.avatar_168x168.url_list[0])" alt="">
<div class="desc">
<div class="desc-wrapper">
<div class="name">大司马大司马大司马</div>
<div class="name">{{ userinfo.nickname }}</div>
<div class="count">2万本场点赞</div>
</div>
<div class="follow-btn">关注</div>
@ -58,8 +72,8 @@
<span>30</span>
</div>
</div>
<span class="name">嘻嘻哈哈</span>
<span class="text">{{ i }}</span>
<span class="name">{{ i.name}}</span>
<span class="text">{{ i.text }}</span>
</div>
</div>
</div>
@ -85,8 +99,6 @@
</div>
</div>
</div>
<base-button @click="sendComment">点击</base-button>
</div>
</template>
@ -94,6 +106,10 @@
import BaseButton from "../../components/BaseButton";
import Dom from "../../utils/dom";
import {nextTick} from "vue";
import {mapState} from "pinia";
import {useBaseStore} from "@/store/pinia";
import {_checkImgUrl, random} from "@/utils";
import Mock from "mockjs";
export default {
name: "LivePage",
@ -101,23 +117,25 @@ export default {
props: {},
data() {
return {
timer1: -1,
timer2: -1,
timer3: -1,
isFollowed: false,
list: [
'asdfasdf',
'asdfasdf',
'asdfasdf',
],
list: [],
barrage: [],
barrageTemplate: () => {
let name = Mock.mock('@cname')
let a = Mock.mock('@csentence')
return `
<div class="barrage">
<div class="type">管理</div>
<div class="text">感谢老铁送的火箭</div>
<div class="type">${name}</div>
<div class="text">${a}</div>
</div>
`
},
userJoinedTemplate: () => {
let src = new URL('../../assets/img/icon/home/level.webp')
let src = '/images/icon/love.webp'
let name = Mock.mock('@cname')
return `
<div class="user-joined">
<div class="level">
@ -126,23 +144,36 @@ export default {
<span>30</span>
</div>
</div>
<span class="name">嘻嘻哈哈</span>
<span class="name">${name}</span>
<span class="text">加入了直播间</span>
</div>
`
},
sendGiftTemplate: () => {
let avatar = new URL('../../assets/img/icon/avatar/3.png')
let gift = new URL('../../assets/img/icon/home/love.webp')
let avatarList = [
'/images/EPsQ7u4sNnrHC-ix-a9yQ.png',
'/images/Xex2IhY-Zm338cNlcGuNW.png',
'/images/gddHyRZrdk0Em3RRgVa9g.png',
'/images/LJ-8p2jF3HydBD5j28PgQ.png',
'/images/KwJ9N7yFjYylfwYeThWjx.png',
'/images/EKkC06GI4yXC2mNHMrm46.png',
'/images/rlkpmpGPdhYZRJl3J4Xl7.png',
'/images/Ge4mMWQoICdpyTyixk3Sf.png',
]
let avatar = avatarList[random(0, avatarList.length - 1)]
let gift = '/images/icon/love.webp'
let name = Mock.mock('@cname')
let name2 = Mock.mock('@cname')
let num = Mock.mock('@integer(60,400)')
return `
<div class="send-gift">
<div class="left">
<img src="${avatar}" alt="" class="avatar">
<div class="desc">
<div class="name">哈哈哈哈哈哈哈哈哈</div>
<div class="name">${name}</div>
<div class="sendto">
<span class="send"></span>
<span class="to">嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻</span>
<span class="to">${name2}</span>
</div>
</div>
<div class="gift-wrapper">
@ -150,7 +181,7 @@ export default {
</div>
</div>
<div class="right">
x339
x${num}
</div>
</div>
`
@ -158,25 +189,33 @@ export default {
page: null,
}
},
computed: {},
computed: {
...mapState(useBaseStore, ['friends', 'userinfo']),
},
created() {
},
mounted() {
this.page = this.$refs.page
// setInterval(async () => {
// this.sendGift()
// await this.$sleep(300)
// this.sendGift()
// this.joinUser()
// }, 3000)
// setInterval(async () => {
// this.sendBarrage()
// }, 5100)
// setInterval(async () => {
// this.sendComment()
// }, 500)
this.timer1 = setInterval(async () => {
this.sendGift()
await this.$sleep(300)
this.sendGift()
this.joinUser()
}, 1000)
this.timer2 = setInterval(async () => {
this.sendBarrage()
}, 1500)
this.timer3 = setInterval(async () => {
this.sendComment()
}, 700)
},
unmounted() {
clearInterval(this.timer1)
clearInterval(this.timer2)
clearInterval(this.timer3)
},
methods: {
_checkImgUrl,
sendGift() {
let page = new Dom(this.page)
let sendGift = new Dom().create(this.sendGiftTemplate())
@ -188,6 +227,10 @@ export default {
if (oldSendGift.els.length !== 0) {
top = sendGift.removePx(oldSendGift.css('top')) - 70
}
if (top < 100) {
top = document.body.clientHeight * .6
}
console.log('top', top)
sendGift.css('top', top)
page.append(sendGift)
},
@ -210,11 +253,17 @@ export default {
if (oldBarrages.els.length !== 0) {
top = barrage.removePx(oldBarrages.css('top')) + 20
}
if (top > document.body.clientHeight * .5) {
top = document.body.clientHeight * .35
}
barrage.css('top', top)
page.append(barrage)
},
sendComment() {
this.list.push('评论评论评论评论评论评论评论评论评论评论' + this.list.length)
this.list.push({
name: Mock.mock('@cname'),
text: Mock.mock('@csentence')
})
nextTick(() => {
let comments = this.$refs['comments']
comments.scrollTo({top: comments.scrollHeight - comments.clientHeight, behavior: 'smooth'})
@ -272,6 +321,8 @@ export default {
.avatar {
margin-right: 5rem;
width: 40rem;
height: 40rem;
object-fit: cover;
border-radius: 50%;
}
@ -417,6 +468,14 @@ export default {
width: 100vw;
height: calc(var(--vh, 1vh) * 100);
background: black;
display: flex;
align-items: center;
justify-content: center;
video {
width: 100%;
object-fit: cover;
}
img {
width: 100vw;

View File

@ -146,6 +146,7 @@
ref="share"
page-id="home-index"
@dislike="dislike"
:item="state.currentItem"
:videoId="state.recommendList[state.itemIndex]?.id"
:canDownload="state.recommendList[state.itemIndex]?.canDownload"
@play-feedback="state.showPlayFeedback = true"
@ -156,7 +157,9 @@
<PlayFeedback v-model="state.showPlayFeedback"/>
<DouyinCode v-model="state.showDouyinCode"/>
<DouyinCode
:item="state.currentItem"
v-model="state.showDouyinCode"/>
<ShareTo v-model:type="state.shareType"
:videoId="state.recommendList[state.itemIndex]?.id"
@ -195,7 +198,7 @@ import SlideItem from '@/components/slide/SlideItem.vue'
import Comment from "../../components/Comment.vue";
import Share from "../../components/Share.vue";
import IndicatorHome from "./components/IndicatorHome.vue";
import {onMounted, onUnmounted, reactive} from "vue";
import {onActivated, onDeactivated, onMounted, onUnmounted, reactive} from "vue";
import bus, {EVENT_KEY} from "../../utils/bus";
import {useNav} from "@/utils/hooks/useNav";
import PlayFeedback from "@/pages/home/components/PlayFeedback.vue";
@ -221,6 +224,7 @@ const nav = useNav()
const baseStore = useBaseStore()
const state = reactive({
active: true,
baseIndex: 1,
navIndex: 4,
test: '',
@ -253,6 +257,7 @@ function delayShowDialog(cb) {
}
function setCurrentItem(item) {
if (!state.active) return
// console.log('sss',item,state.baseIndex)
if (state.baseIndex !== 1) return
if (state.currentItem.author.uid !== item.author.uid) {
@ -266,21 +271,34 @@ function setCurrentItem(item) {
}
onMounted(() => {
bus.on(EVENT_KEY.ENTER_FULLSCREEN, (e) => state.fullScreen = true)
bus.on(EVENT_KEY.EXIT_FULLSCREEN, (e) => state.fullScreen = false)
bus.on(EVENT_KEY.ENTER_FULLSCREEN, (e) => {
if (!state.active) return
state.fullScreen = true
})
bus.on(EVENT_KEY.EXIT_FULLSCREEN, (e) => {
if (!state.active) return
state.fullScreen = false
})
bus.on(EVENT_KEY.OPEN_COMMENTS, (e) => {
if (!state.active) return
bus.emit(EVENT_KEY.ENTER_FULLSCREEN)
state.commentVisible = true
})
bus.on(EVENT_KEY.CLOSE_COMMENTS, (e) => {
if (!state.active) return
bus.emit(EVENT_KEY.EXIT_FULLSCREEN)
state.commentVisible = false
})
bus.on(EVENT_KEY.SHOW_SHARE, (e) => {
if (!state.active) return
state.isSharing = true
})
bus.on(EVENT_KEY.NAV, ({path, query}) => nav(path, query))
bus.on(EVENT_KEY.NAV, ({path, query}) => {
if (!state.active) return
nav(path, query)
})
bus.on(EVENT_KEY.GO_USERINFO, () => {
if (!state.active) return
state.baseIndex = 2
})
bus.on(EVENT_KEY.CURRENT_ITEM, setCurrentItem)
@ -290,6 +308,15 @@ onUnmounted(() => {
bus.offAll()
})
onActivated(() => {
state.active = true
})
onDeactivated(() => {
state.active = false
})
function closeComments() {
bus.emit(EVENT_KEY.CLOSE_COMMENTS)
}

View File

@ -1,228 +0,0 @@
<script setup>
import {onMounted, onUnmounted, reactive, watch} from "vue";
import {_checkImgUrl, _duration, _formatNumber} from "@/utils";
import {recommendedVideo} from "@/api/videos";
import {useBaseStore} from "@/store/pinia";
const baseStore = useBaseStore()
const props = defineProps({
active: Boolean
})
const p = {
onShowComments() {
console.log('onShowComments')
}
}
const state = reactive({
index: 0,
list: [],
totalSize: 0,
pageSize: 10,
pageNo: 0,
})
function loadMore() {
if (!baseStore.loading) {
state.pageNo++
getData()
}
}
async function getData(refresh = false) {
if (baseStore.loading) return
baseStore.loading = true
let res = await recommendedVideo({pageNo: refresh ? 0 : state.pageNo, pageSize: state.pageSize})
console.log('getSlide4Data-', 'refresh', refresh, res)
baseStore.loading = false
if (res.code === 200) {
state.totalSize = res.data.total
if (refresh) {
state.list = []
}
state.list = state.list.concat(res.data.list)
} else {
state.pageNo--
}
}
watch(() => props.active, n => {
if (!state.list.length && n) {
baseStore.loading = false
getData()
}
})
onMounted(() => {
})
onUnmounted(() => {
})
</script>
<template>
<div class="page">
<div class="item"
:class="[
i % 5 === 0 && 'big',
i % 5 === 0 ? '' : (i % 2 === 1 && 'l'),
i % 5 === 0 ? '' : (i % 2 === 0 && 'r'),
]"
v-for="(item,i) in state.list">
<video
controls
:poster="_checkImgUrl(item.video.cover.url_list[0])"
:src="item.video.play_addr.url_list[0]"
></video>
<img v-lazy="_checkImgUrl(item.video.cover.url_list[0])" alt="" class="poster">
<div class="duration">{{ _duration(item.duration / 1000) }}</div>
<div class="title">
{{ item.desc }}
</div>
<div class="bottom">
<div class="l">
<img v-lazy="_checkImgUrl(item.author.avatar_168x168.url_list[0])" alt="" class="avatar">
<div class="name">{{ item.author.nickname }}</div>
</div>
<div class="r">
<Icon icon="icon-park-outline:like"/>
<div class="num">{{ _formatNumber(item.statistics.digg_count) }}</div>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="less">
.page {
display: grid;
grid-template-columns: repeat(2, 1fr);
row-gap: 15rem;
height: calc(var(--vh, 1vh) * 100 - var(--common-header-height) - var(--footer-height));
margin-top: var(--common-header-height);
overflow: auto;
box-sizing: border-box;
.item {
margin: 0 10rem;
display: flex;
flex-direction: column;
gap: 8rem;
position: relative;
.poster {
border-radius: 12rem;
width: 100%;
height: 140rem;
object-fit: cover;
}
video {
display: none;
height: 220rem;
object-fit: cover;
}
.title {
height: 36rem;
color: white;
font-size: 14rem;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; //
-webkit-box-orient: vertical; //--
-webkit-line-clamp: 2; //
}
.f {
display: flex;
align-items: center;
justify-content: space-between;
gap: 5rem;
}
.duration {
color: white;
position: absolute;
bottom: 80rem;
right: 10rem;
font-size: 13rem;
}
.bottom {
color: gray;
.f;
font-size: 13rem;
.l {
.f;
justify-content: flex-start;
.name {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; //
-webkit-box-orient: vertical; //--
-webkit-line-clamp: 1; //
}
.avatar {
@w: 20rem;
width: @w;
height: @w;
object-fit: cover;
border-radius: 50%;
}
}
.r {
word-break: keep-all;
.f;
svg {
font-size: 16rem;
}
}
}
&.big {
grid-column-start: 1;
grid-column-end: 3;
margin: 0;
.duration {
display: none;
}
.poster {
display: none;
}
video {
display: block;
}
.title {
height: unset;
-webkit-line-clamp: 1;
}
.title, .bottom {
padding: 0 10rem;
}
}
&.l {
margin-right: 5rem;
}
&.r {
margin-left: 5rem;
}
}
}
</style>

View File

@ -4,17 +4,18 @@
:class="state.subTypeIsTop?'top':''"
ref="subTypeRef">
<div class="card" @touchmove.capture="stop">
<div class="nav-item" v-for="i in 2">
<img src="@/assets/img/icon/msg-icon9.webp" alt="">
<span>美食美食美食美食美食美食美食</span>
<div class="nav-item" v-for="i in store.users">
<img :src="_checkImgUrl(i.avatar_168x168.url_list[0])" alt="">
<span>{{ i.nickname }}</span>
</div>
</div>
</div>
<div class="sub-type-notice"
v-if="state.subType===-1 && !state.subTypeVisible"
@click="showSubType">1个直播
@click.stop="showSubType">{{store.users.length}}个直播
</div>
<SlideList
:cbs="{isLive:true}"
:active="props.active"
:style="{background: 'black',marginTop:state.subTypeVisible?state.subTypeHeight:0}"
:api="recommendedVideo"
@ -27,10 +28,12 @@
import SlideItem from '@/components/slide/SlideItem.vue'
import {onMounted, onUnmounted, reactive, ref} from "vue";
import bus, {EVENT_KEY} from "@/utils/bus";
import Utils from "@/utils";
import Utils, {_checkImgUrl} from "@/utils";
import SlideList from './SlideList.vue';
import {recommendedVideo} from "@/api/videos";
import {useBaseStore} from "@/store/pinia";
const store = useBaseStore()
const props = defineProps({
active: {
type: Boolean,
@ -104,6 +107,8 @@ onUnmounted(() => {
box-sizing: border-box;
display: flex;
overflow: auto;
gap: 10rem;
padding-left: 20rem;
}
.nav-item {
@ -126,7 +131,7 @@ onUnmounted(() => {
img {
width: @width;
height: @width;
margin-bottom: 5rem;
border-radius: 50%;
}
}
}

View File

@ -62,6 +62,30 @@
</div>
</div>
</div>
<!-- 消息-->
<div class="message" @click="$nav('/message/chat')">
<div class="avatar on-line">
<img src="../../assets/img/icon/avatar/2.png" alt="" class="head-image">
</div>
<div class="content">
<div class="left">
<div class="name">
<span>{{ userinfo.nickname }}</span>
</div>
<div class="detail">
哈哈哈哈哈哈
<div class="point"></div>
10-10
</div>
</div>
<div class="right">
<!-- <div class="not-read"></div>-->
<!-- <img class="camera" src="../../assets/img/icon/close-white.png" alt="">-->
<!-- <img class="arrow" src="../../assets/img/icon/close-white.png" alt="">-->
<div class="badge">12</div>
</div>
</div>
</div>
<!-- 抖音小助手-->
<div class="message" @click="$nav('/message/douyin-helper')">
<div class="avatar">
@ -195,30 +219,6 @@
</div>
</div>
<!-- 消息-->
<div class="message" @click="$nav('/message/chat')">
<div class="avatar on-line">
<img src="../../assets/img/icon/avatar/2.png" alt="" class="head-image">
</div>
<div class="content">
<div class="left">
<div class="name">
<span>{{ userinfo.nickname }}</span>
</div>
<div class="detail">
哈哈哈哈哈哈
<div class="point"></div>
10-10
</div>
</div>
<div class="right">
<!-- <div class="not-read"></div>-->
<!-- <img class="camera" src="../../assets/img/icon/close-white.png" alt="">-->
<!-- <img class="arrow" src="../../assets/img/icon/close-white.png" alt="">-->
<div class="badge">12</div>
</div>
</div>
</div>
<NoMore/>

View File

@ -67,6 +67,7 @@ export default {
.avatar {
margin-top: 55rem;
width: 55rem;
height: 55rem;
border-radius: 50%;
margin-bottom: 20rem;
}

View File

@ -219,36 +219,7 @@ export default {
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.MULTIPLE,
data: {
money: 5.11,
title: '大吉大利',
state: '未领取'
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.SINGLE,
data: {
money: 5.11,
title: '大吉大利',
state: '已过期'
},
time: '2021-01-02 21:21',
user: {
id: 1,
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.MEME,
state: AUDIO_STATE.NORMAL,
@ -441,6 +412,36 @@ export default {
avatar: '../../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.MULTIPLE,
data: {
money: 5.11,
title: '大吉大利',
state: '未领取'
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.SINGLE,
data: {
money: 5.11,
title: '大吉大利',
state: '已过期'
},
time: '2021-01-02 21:21',
user: {
id: 1,
avatar: '../../assets/img/icon/head-image.jpg'
}
},
],
typing: false,
loading: false,
@ -466,15 +467,19 @@ export default {
created() {
},
mounted() {
$('img').on('load', this.scrollBottom)
this.scrollBottom()
},
unmounted() {
$('img').off('load', this.scrollBottom)
},
methods: {
_checkImgUrl,
scrollBottom() {
nextTick(() => {
let wrapper = this.$refs.msgWrapper
console.log('wrapper.clientHeight', wrapper.clientHeight)
console.log('wrapper.scrollHeight', wrapper.scrollHeight)
// console.log('wrapper.clientHeight', wrapper.clientHeight)
// console.log('wrapper.scrollHeight', wrapper.scrollHeight)
wrapper.scrollTo({top: wrapper.scrollHeight - wrapper.clientHeight})
})
@ -804,6 +809,7 @@ export default {
.avatar {
margin-top: 60rem;
width: 55rem;
height: 55rem;
border-radius: 50%;
margin-bottom: 20rem;
}

View File

@ -15,7 +15,6 @@
</div>
<div class="content">
<SlideVerticalInfinite
v-if="false"
ref="listRef"
v-love="state.uniqueId"
:id="state.uniqueId"
@ -31,7 +30,7 @@
<div class="footer">
<div class="comment">
<div class="left">
<img :src="_checkImgUrl(store.userinfo.avatar_168x168.url_list[0])" class="avatar" alt=""/>
<img :src="_checkImgUrl(baseStore.userinfo.avatar_168x168.url_list[0])" class="avatar" alt=""/>
<span>善语结善缘恶言伤人心</span>
</div>
<div class="right">
@ -41,22 +40,92 @@
</div>
</div>
</div>
<Comment page-id="video-detail"
:video-id="state.currentItem.aweme_id"
v-model="state.commentVisible"
@close="closeComments"
/>
<Share v-model="state.isSharing"
ref="share"
page-id="video-detail"
@dislike="dislike"
:item="state.currentItem"
:videoId="state.recommendList[state.itemIndex]?.id"
:canDownload="state.recommendList[state.itemIndex]?.canDownload"
@play-feedback="state.showPlayFeedback = true"
@shareToFriend="delayShowDialog(e => state.shareToFriend = true)"
@showDouyinCode="state.showDouyinCode = true"
@download="state.shareType = 9"
/>
<PlayFeedback v-model="state.showPlayFeedback"/>
<DouyinCode
:item="state.currentItem"
v-model="state.showDouyinCode"/>
<ShareTo v-model:type="state.shareType"
:videoId="state.recommendList[state.itemIndex]?.id"
:canDownload="state.recommendList[state.itemIndex]?.canDownload"
/>
<FollowSetting
v-model:currentItem="state.currentItem"
@showChangeNote="delayShowDialog( e => state.showChangeNote = true)"
@showBlockDialog="delayShowDialog(e => state.showBlockDialog = true)"
@showShare="delayShowDialog( e => state.isSharing = true)"
v-model="state.showFollowSetting"/>
<FollowSetting2
v-model:currentItem="state.currentItem"
@cancelFollow="$refs.uploader.cancelFollow()"
v-model="state.showFollowSetting2"/>
<BlockDialog v-model="state.showBlockDialog"/>
<ConfirmDialog
title="设置备注名"
ok-text="确认"
v-model:visible="state.showChangeNote"
>
<Search mode="light" v-model="state.test" :isShowSearchIcon="false"/>
</ConfirmDialog>
<ShareToFriend v-model="state.shareToFriend"/>
</div>
</template>
<script setup>
import {onMounted, reactive} from "vue";
<script setup lang="jsx">
import Comment from "../../components/Comment.vue";
import Share from "../../components/Share.vue";
import {onMounted, onUnmounted, reactive} from "vue";
import bus, {EVENT_KEY} from "../../utils/bus";
import {useNav} from "@/utils/hooks/useNav";
import PlayFeedback from "@/pages/home/components/PlayFeedback.vue";
import ShareTo from "@/pages/home/components/ShareTo.vue";
import DouyinCode from "../../components/DouyinCode.vue";
import FollowSetting from "@/pages/home/components/FollowSetting.vue";
import BlockDialog from "../message/components/BlockDialog.vue";
import Search from "../../components/Search.vue";
import ConfirmDialog from "../../components/dialog/ConfirmDialog.vue";
import FollowSetting2 from "@/pages/home/components/FollowSetting2.vue";
import ShareToFriend from "@/pages/home/components/ShareToFriend.vue";
import {DefaultUser} from "@/utils/const_var";
import {_checkImgUrl} from "@/utils";
import {useBaseStore} from "@/store/pinia";
import SlideVerticalInfinite from "@/components/slide/SlideVerticalInfinite.vue";
import {useSlideListItemRender} from "@/utils/hooks/useSlideListItemRender";
import {_checkImgUrl} from "@/utils";
import {useNav} from "@/utils/hooks/useNav";
import {useRouter} from "vue-router";
defineOptions({
name: 'VideoDetail'
})
const nav = useNav()
const store = useBaseStore()
const router = useRouter()
const baseStore = useBaseStore()
const data = reactive({
dialog: {
shareToFriend: false,
@ -65,7 +134,33 @@ const data = reactive({
},
isMy: false
})
const state = reactive({
baseIndex: 1,
navIndex: 4,
test: '',
recommendList: [],
isSharing: false,
canMove: true,
shareType: -1,
showPlayFeedback: false,
showShareDuoshan: false,
showShareDialog: false,
showShare2WeChatZone: false,
showDouyinCode: false,
showFollowSetting: false,
showFollowSetting2: false,
showBlockDialog: false,
showChangeNote: false,
shareToFriend: false,
commentVisible: false,
fullScreen: false,
currentItem: {
author: DefaultUser,
isRequest: false,
aweme_list: [],
},
index: 0,
list: [],
uniqueId: 'uniqueId_2',
@ -73,18 +168,72 @@ const state = reactive({
pageSize: 10,
pageNo: 0,
})
const render = useSlideListItemRender()
onMounted(() => {
// console.log('s', store.routeData)
state.index = store.routeData.index
state.list = store.routeData.list
state.index = baseStore.routeData.index
state.list = baseStore.routeData.list
// console.log('sss', state.list[state.index])
})
function delayShowDialog(cb) {
setTimeout(cb, 400)
}
function setCurrentItem(item) {
// console.log('sss',item,state.baseIndex)
if (state.baseIndex !== 1) return
if (state.currentItem.author.uid !== item.author.uid) {
state.currentItem = {
...item,
isRequest: false,
aweme_list: [],
}
}
// console.log('item', item)
}
onMounted(() => {
bus.on(EVENT_KEY.ENTER_FULLSCREEN, (e) => state.fullScreen = true)
bus.on(EVENT_KEY.EXIT_FULLSCREEN, (e) => state.fullScreen = false)
bus.on(EVENT_KEY.OPEN_COMMENTS, (e) => {
bus.emit(EVENT_KEY.ENTER_FULLSCREEN)
state.commentVisible = true
})
bus.on(EVENT_KEY.CLOSE_COMMENTS, (e) => {
bus.emit(EVENT_KEY.EXIT_FULLSCREEN)
state.commentVisible = false
})
bus.on(EVENT_KEY.SHOW_SHARE, (e) => {
state.isSharing = true
})
bus.on(EVENT_KEY.NAV, ({path, query}) => nav(path, query))
bus.on(EVENT_KEY.GO_USERINFO, () => {
router.back()
})
bus.on(EVENT_KEY.CURRENT_ITEM, setCurrentItem)
})
onUnmounted(() => {
bus.offAll()
})
function closeComments() {
bus.emit(EVENT_KEY.CLOSE_COMMENTS)
}
function dislike() {
// listRef.value.dislike(state.list[1])
// state.list[state.index] = state.list[1]
// Utils.$notice('')
}
</script>
<style scoped lang="less">
@import "../../assets/less/index";
#video-detail {
position: fixed;
@ -199,4 +348,5 @@ onMounted(() => {
}
}
}
</style>

View File

@ -0,0 +1,201 @@
<template>
<div id="video-detail">
<div class="search-wrapper">
<Icon class="back" icon="icon-park-outline:left" @click="$back"/>
<div class="search" @click="nav('/home/search')">
<div class="left">
<Icon class="icon" icon="ion:search"/>
<span>搜你想看的</span>
</div>
<div class="right">
<span class="gang">|</span>
<span class="txt">搜索</span>
</div>
</div>
</div>
<div class="content">
<SlideVerticalInfinite
ref="listRef"
v-love="state.uniqueId"
:id="state.uniqueId"
:uniqueId="state.uniqueId"
name="main"
:active="true"
:loading="false"
v-model:index="state.index"
:render="render"
:list="state.list"
/>
</div>
<div class="footer">
<div class="comment">
<div class="left">
<img :src="_checkImgUrl(store.userinfo.avatar_168x168.url_list[0])" class="avatar" alt=""/>
<span>善语结善缘恶言伤人心</span>
</div>
<div class="right">
<Icon icon="tabler:photo"/>
<Icon icon="ion:at-sharp"/>
<Icon icon="fa-regular:laugh"/>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {onMounted, reactive} from "vue";
import {useBaseStore} from "@/store/pinia";
import SlideVerticalInfinite from "@/components/slide/SlideVerticalInfinite.vue";
import {useSlideListItemRender} from "@/utils/hooks/useSlideListItemRender";
import {_checkImgUrl} from "@/utils";
import {useNav} from "@/utils/hooks/useNav";
defineOptions({
name: 'VideoDetail'
})
const nav = useNav()
const store = useBaseStore()
const data = reactive({
dialog: {
shareToFriend: false,
permissionDialog: false,
test: false,
},
isMy: false
})
const state = reactive({
index: 0,
list: [],
uniqueId: 'uniqueId_2',
totalSize: 0,
pageSize: 10,
pageNo: 0,
})
const render = useSlideListItemRender()
onMounted(() => {
// console.log('s', store.routeData)
state.index = store.routeData.index
state.list = store.routeData.list
// console.log('sss', state.list[state.index])
})
</script>
<style scoped lang="less">
@import "../../assets/less/index";
#video-detail {
position: fixed;
font-size: 14rem;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
width: 100%;
background: black;
.search-wrapper {
z-index: 9;
position: fixed;
top: 8rem;
left: 0;
width: 100vw;
padding: 0 15rem;
box-sizing: border-box;
display: flex;
align-items: center;
gap: 15rem;
.back {
color: white;
font-size: 30rem;
}
.search {
color: var(--second-btn-color);
display: flex;
background: rgba(171, 169, 169, 0.4);
border-radius: 8rem;
flex: 1;
padding: 8rem;
justify-content: space-between;
.left {
font-size: 15rem;
display: flex;
align-items: center;
color: gainsboro;
gap: 5rem;
line-height: 1;
svg {
font-size: 14rem;
}
}
.right {
display: flex;
align-items: center;
gap: 10rem;
font-size: 16rem;
.gang {
color: dimgrey;
}
.txt {
color: white;
}
}
}
}
.content {
height: calc(var(--vh, 1vh) * 100 - var(--footer-height));
}
.footer {
height: var(--footer-height);
position: fixed;
bottom: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.comment {
color: var(--second-text-color);
z-index: 9;
width: 95%;
height: 75%;
box-sizing: border-box;
padding: 0 10px;
display: flex;
justify-content: space-between;
align-items: center;
background: rgb(37, 37, 37);
border-radius: 50rem;
.avatar {
height: 70%;
border-radius: 50%;
}
.left {
height: 100%;
display: flex;
align-items: center;
gap: 10rem;
}
.right {
.left;
gap: 15rem;
font-size: 24rem;
}
}
}
</style>

View File

@ -56,7 +56,7 @@
<div class="slide-imgs">
<SlideHorizontal v-model:index="state.index">
<SlideItem v-for="item in state.detail.imgs">
<img :src="item" alt="">
<img v-lazy="_checkImgUrl('goods/'+item)" alt=""/>
</SlideItem>
</SlideHorizontal>
<div class="index">{{ state.index + 1 }}/{{ state.detail.imgs.length }}</div>
@ -66,20 +66,20 @@
<div class="price-wrap">
<div class="price">
<span class="symbol"></span>
<span class="int">8</span>
<span class="decimal">.8</span>
<span class="int">{{ state.detail.price }}</span>
<!-- <span class="decimal">.8</span>-->
</div>
<div class="discount">
<span class="text">热销款券后</span>
<div class="price">
<span class="symbol"></span>
<span class="int">5</span>
<span class="decimal">.9</span>
<span class="int">{{ state.detail.real_price }}</span>
<!-- <span class="decimal">.9</span>-->
</div>
</div>
</div>
<div class="name">{{ state.detail.name }}</div>
<div class="num">已售20/100</div>
<div class="num">已售{{ state.detail.sold }}</div>
</div>
<div class="card desc-wrapper">
@ -145,9 +145,9 @@
<div class="tag">推荐 <span class="gray">18</span></div>
<div class="tag">商用服务好 <span class="gray">15</span></div>
</div>
<div class="comment" v-for="i in 2">
<div class="comment">
<header>
<img src="https://cdn.seovx.com/?mom=302" alt="" class="avatar">
<img :src="_checkImgUrl('2S9bbgb-Sf2kIdSTxoeTw.png')" alt="" class="avatar">
<span class="gray">***</span>
</header>
<div class="w">
@ -159,14 +159,31 @@
china款/超值买る双+送2双共5双
</div>
</div>
<img src="https://cdn.seovx.com/?mom=302" alt="" class="avatar">
<img :src="_checkImgUrl('NYEfuYS-LVZ620UYgQNAM.png')" alt="" class="avatar">
</div>
</div>
<div class="comment">
<header>
<img :src="_checkImgUrl('9Tx6cZkUOoHqPkbETUZ5Y.png')" alt="" class="avatar">
<span class="gray">***</span>
</header>
<div class="w">
<div class="left">
<div class="d">
东西不错质量也很好 性价比很高 良心商家就冲这图必须给好评
</div>
<div class="c2">
china款/超值买る双+送2双共5双
</div>
</div>
<img :src="_checkImgUrl('2b2rpive_RVzDrYgo-F9K.png')" alt="" class="avatar">
</div>
</div>
</div>
<div class="card shop">
<header>
<img src="https://cdn.seovx.com/?mom=302" alt="" class="avatar">
<img :src="_checkImgUrl('LJ-8p2jF3HydBD5j28PgQ.png')" alt="" class="avatar">
<div class="right">
<div class="l">
<div class="name">店铺名</div>
@ -207,9 +224,36 @@
</div>
</header>
<div class="wrap">
<div class="item" v-for="i in 4">
<img src="https://cdn.seovx.com/?mom=302" alt="" class="avatar">
<div class="name">热销中袜子男潮流百搭中筒袜子袜子男潮流百搭中筒袜子</div>
<div class="item">
<img :src="_checkImgUrl('/goods/g6-0.jpg')" alt="" class="avatar">
<div class="name">小米电视6 65" OLED 65英寸</div>
<div class="price">
<span class="symbol"></span>
<span class="int">8</span>
<span class="decimal">.8</span>
</div>
</div>
<div class="item">
<img :src="_checkImgUrl('/goods/g1-0.jpg')" alt="" class="avatar">
<div class="name">红白撞色条纹软糯针织上衣女2022年秋季新款甜美减龄短款毛衣开衫</div>
<div class="price">
<span class="symbol"></span>
<span class="int">8</span>
<span class="decimal">.8</span>
</div>
</div>
<div class="item">
<img :src="_checkImgUrl('/goods/g2-0.webp')" alt="" class="avatar">
<div class="name">森马t恤男2023男士纯棉上衣白色情侣装凉感短袖打底衫纯色体恤潮</div>
<div class="price">
<span class="symbol"></span>
<span class="int">8</span>
<span class="decimal">.8</span>
</div>
</div>
<div class="item">
<img :src="_checkImgUrl('/goods/g3-0.jpg')" alt="" class="avatar">
<div class="name">ins潮牌长袖t恤男宽松纯色内搭上衣潮牌百搭秋冬季潮流帅气打底衫</div>
<div class="price">
<span class="symbol"></span>
<span class="int">8</span>
@ -221,7 +265,7 @@
</div>
</div>
<div class="img-list" v-if="true">
<div class="img-list">
<header>
<div class="l"></div>
<span class="gray">商品详情</span>
@ -229,7 +273,7 @@
</header>
<div class="imgs">
<img v-lazy="`https://cdn.seovx.com/?mom=302&d=${i}`" alt="" class="avatar" v-for="i in 5">
<img v-lazy="_checkImgUrl('goods/'+i)" alt="" class="avatar" v-for="i in state.detail.imgs">
</div>
</div>
@ -254,34 +298,39 @@
你可以还会喜欢
</header>
<div v-masonry class="goods-list"
:class="{fixed:state.fixed}"
transition-duration="0s"
item-selector=".goods">
<div v-masonry-tile class="goods"
@click="nav('/shop/detail')"
v-for="(item, index) in state.list">
<div class="item">
<img class="poster" v-lazy="Utils.$imgPreview(item.cover)"/>
<div class="bottom">
<div class="desc">
{{ item.name }}
</div>
<div class="discounts" v-if="item.discount">{{ item.discount }}</div>
<div class="info">
<div class="price">
<div class="big">{{ item.price }}</div>
<ScrollList
class="Scroll"
:api="recommendedShop"
>
<template v-slot="{list}">
<WaterfallList :list="list">
<template v-slot="{item}">
<div class="goods"
@click="nav('/shop/detail',{},item)">
<div class="item">
<img class="poster" v-lazy="_checkImgUrl('goods/'+item.cover)"/>
<div class="bottom">
<div class="desc">
{{ item.name }}
</div>
<div class="discounts" v-if="item.discount">{{ item.discount }}</div>
<div class="info">
<div class="price">
<div class="big">{{ item.price }}</div>
</div>
<div class="num">已售{{ item.sold }}</div>
</div>
<div class="low" v-if="item.isLowPrice">
近30天低价
</div>
</div>
</div>
<div class="num">已售{{ item.sold }}</div>
</div>
<div class="low" v-if="item.isLowPrice">
近30天低价
</div>
</div>
</div>
</div>
</div>
</template>
</WaterfallList>
</template>
</ScrollList>
</div>
</div>
@ -312,19 +361,21 @@
<script setup>
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";
import SlideItem from "@/components/slide/SlideItem.vue";
import {reactive, ref} from "vue";
import goods from "@/assets/data/goods";
import {onMounted, onUnmounted, reactive, ref} from "vue";
import {useNav} from "@/utils/hooks/useNav";
import Utils from "@/utils";
import {_checkImgUrl} from "@/utils";
import {useBaseStore} from "@/store/pinia";
import {recommendedShop} from "@/api/user";
import WaterfallList from "@/components/WaterfallList.vue";
import ScrollList from "@/components/ScrollList.vue";
defineOptions({
name: 'GoodsDetail'
})
let activeIndexs = ref([])
const nav = useNav()
const props = defineProps({
id: {
type: String,
default: () => ''
}
})
const store = useBaseStore()
let page = ref()
let header = ref()
let headerShadow = ref()
@ -341,9 +392,10 @@ function scroll() {
}
const state = reactive({
detail: goods.list[1],
detail: {
imgs: []
},
index: 0,
list: goods.list,
listEl: null,
fixed: false
})
@ -356,6 +408,15 @@ function toggle(i) {
activeIndexs.value.push(i)
}
}
onMounted(() => {
console.log('r', store.routeData.imgs)
state.detail = store.routeData
})
onUnmounted(() => {
console.log('onUnmounted')
})
</script>
<style scoped lang="less">
@ -946,7 +1007,6 @@ function toggle(i) {
& > header {
padding: 15rem;
padding-bottom: 5rem;
font-weight: 900;
font-size: 15rem;
}
@ -959,14 +1019,13 @@ function toggle(i) {
@p: 5rem;
.goods-list {
padding-bottom: 20rem;
.Scroll {
padding: 5rem;
}
.goods {
width: 50%;
box-sizing: border-box;
padding: 5rem;
margin-bottom: 10rem;
.item {
border-radius: 8rem;

View File

@ -13,106 +13,105 @@
</div>
</div>
</div>
<Scroll class="Scroll"
fixedHeight="100"
@fixed="e=>state.fixed = e"
@pulldown="loadData">
<div class="wrapper">
<div class="card">
<div class="options">
<div class="option" @click="$no">
<Icon icon="lets-icons:order-light"/>
<div>我的订单</div>
</div>
<div class="option" @click="$no">
<Icon icon="material-symbols-light:charging-station-outline"/>
<div>手机充值</div>
</div>
<div class="option" @click="$no">
<Icon icon="lucide:message-square-quote"/>
<div>购物消息</div>
</div>
<div class="option" @click="$no">
<Icon icon="fluent:location-16-regular"/>
<div>小时达</div>
</div>
<div class="option" @click="$no">
<Icon icon="ri:refund-2-fill"/>
<div>退款/售后</div>
</div>
<div class="option" @click="$no">
<Icon icon="icon-park-outline:clothes-turtleneck"/>
<div>潮流服饰</div>
<ScrollList
class="Scroll"
:api="recommendedShop"
>
<template v-slot="{list}">
<div class="top-card">
<div class="card">
<div class="options">
<div class="option" @click="$no">
<Icon icon="lets-icons:order-light"/>
<div>我的订单</div>
</div>
<div class="option" @click="$no">
<Icon icon="material-symbols-light:charging-station-outline"/>
<div>手机充值</div>
</div>
<div class="option" @click="$no">
<Icon icon="system-uicons:message" />
<div>购物消息</div>
</div>
<div class="option" @click="$no">
<Icon icon="fluent:location-16-regular"/>
<div>小时达</div>
</div>
<div class="option" @click="$no">
<Icon icon="dashicons:money-alt" />
<div>退款/售后</div>
</div>
<div class="option" @click="$no">
<Icon icon="icon-park-outline:clothes-turtleneck"/>
<div>潮流服饰</div>
</div>
</div>
</div>
</div>
<div class="card" style="margin-bottom: 5rem;">
<div class="baiyibutie">
<div class="item">
<img src="@/assets/img/icon/shop/baiyibutie.png" alt="">
<span>38节补贴</span>
</div>
<div class="item">
<img src="@/assets/img/icon/shop/1.webp" alt="">
<span class="price">
<div class="card" style="margin-bottom: 5rem;">
<div class="baiyibutie">
<div class="item">
<img src="@/assets/img/icon/shop/baiyibutie.png" alt="">
<span>38节补贴</span>
</div>
<div class="item">
<img src="@/assets/img/icon/shop/1.webp" alt="">
<span class="price">
<span class="m"></span>
<span>470</span>
</span>
</div>
<div class="item">
<img src="@/assets/img/icon/shop/2.webp" alt="">
<span class="price">
</div>
<div class="item">
<img src="@/assets/img/icon/shop/2.webp" alt="">
<span class="price">
<span class="m"></span>
<span>699</span>
</span>
</div>
<div class="item">
<img src="@/assets/img/icon/shop/3.png" alt="">
<span class="price">
</div>
<div class="item">
<img src="@/assets/img/icon/shop/3.png" alt="">
<span class="price">
<span class="m"></span>
<span>8.8</span>
</span>
</div>
<div class="item">
<img src="@/assets/img/icon/shop/4.jpg" alt="">
<span class="price">
</div>
<div class="item">
<img src="@/assets/img/icon/shop/4.jpg" alt="">
<span class="price">
<span class="m"></span>
<span>2.99</span>
</span>
</div>
</div>
</div>
</div>
</div>
<div v-masonry class="goods-list"
:class="{fixed:state.fixed}"
transition-duration="0s"
item-selector=".goods">
<div v-masonry-tile class="goods"
@click="nav('/shop/detail')"
v-for="(item, index) in state.list">
<div class="item">
<img class="poster" :src="Utils.$imgPreview(item.cover)"/>
<div class="bottom">
<div class="desc">
{{ item.name }}
</div>
<div class="discounts" v-if="item.discount">{{ item.discount }}</div>
<div class="info">
<div class="price">
<div class="big">{{ item.price }}</div>
<WaterfallList :list="list">
<template v-slot="{item}">
<div class="goods"
@click="nav('/shop/detail',{},item)">
<div class="item">
<img class="poster" v-lazy="_checkImgUrl('goods/'+item.cover)"/>
<div class="bottom">
<div class="desc">
{{ item.name }}
</div>
<div class="discounts" v-if="item.discount">{{ item.discount }}</div>
<div class="info">
<div class="price">
<div class="big">{{ item.price }}</div>
</div>
<div class="num">已售{{ item.sold }}</div>
</div>
<div class="low" v-if="item.isLowPrice">
近30天低价
</div>
</div>
<div class="num">已售{{ item.sold }}</div>
</div>
<div class="low" v-if="item.isLowPrice">
近30天低价
</div>
</div>
</div>
</div>
</div>
</Scroll>
</template>
</WaterfallList>
</template>
</ScrollList>
<Footer v-bind:init-tab="2"
:is-white="true"
style="position: fixed;left: 0;"/>
@ -124,9 +123,10 @@
import {onMounted, reactive} from "vue";
import {useNav} from "@/utils/hooks/useNav";
import Utils, {$no} from "@/utils";
import Scroll from "@/components/Scroll.vue";
import goods from "@/assets/data/goods";
import {$no, _checkImgUrl} from "@/utils";
import ScrollList from "@/components/ScrollList.vue";
import {recommendedShop} from "@/api/user";
import WaterfallList from "@/components/WaterfallList.vue";
defineOptions({
name: 'Shop'
@ -134,15 +134,10 @@ defineOptions({
const nav = useNav()
const state = reactive({
list: goods.list,
listEl: null,
fixed: false
})
function loadData() {
console.log('loadData')
}
onMounted(() => {
})
</script>
@ -155,13 +150,11 @@ onMounted(() => {
#Shop {
font-size: 14rem;
position: relative;
background: @fColor;
background: #f1f1f1;
padding: 10rem 5rem;
background: #f8f8f8;
padding: 10rem;
color: black;
.wrapper {
padding: 0 5rem;
}
.search {
@ -174,12 +167,13 @@ onMounted(() => {
margin-bottom: 10rem;
svg {
font-size: 22rem;
color: gray;
font-size: 20rem;
}
.search-input {
border: 1rem solid rgb(140, 48, 74);
border-radius: 8rem;
border: 2rem solid red;
border-radius: 12rem;
height: 100%;
padding: 0 10rem;
padding-right: 3rem;
@ -200,7 +194,7 @@ onMounted(() => {
background: rgb(242, 62, 92);
padding: 0 10rem;
height: 85%;
border-radius: 6rem;
border-radius: 10rem;
display: flex;
justify-content: center;
align-items: center;
@ -284,16 +278,15 @@ onMounted(() => {
background: @fColor;
}
@p: 5rem;
.goods-list {
padding-bottom: 20rem;
.top-card {
margin-bottom: 10rem;
}
@p: 5rem;
.goods {
width: 50%;
box-sizing: border-box;
padding: 5rem;
margin-bottom: 10rem;
.item {
border-radius: 8rem;