save
653
public/data/goods.json
Normal 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
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
BIN
public/images/icon/love.webp
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
@ -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})
|
||||
}
|
||||
@ -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,
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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('复制成功')
|
||||
},
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
@ -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&line=0&file_id=bed51c00899b458cbc5d8280147c22a1&sign=7749aec7bd62a3760065f60e40fc1867&is_play_url=1&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;
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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>
|
||||
@ -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%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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/>
|
||||
|
||||
|
||||
@ -67,6 +67,7 @@ export default {
|
||||
.avatar {
|
||||
margin-top: 55rem;
|
||||
width: 55rem;
|
||||
height: 55rem;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 20rem;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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>
|
||||
201
src/pages/other/VideoDetail2.vue
Normal 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>
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||