Authored by 沈志敏

全球购列表

  1 +'use strict';
  2 +
  3 +const headerModel = require('../../../doraemon/models/header');
  4 +const model = require('../models/global');
  5 +
  6 +const list = (req, res, next) => {
  7 + let brand = req.query.brand;
  8 + let sort = req.query.sort;
  9 + let title = req.query.title;
  10 +
  11 + if (!brand && !sort) {
  12 + return res.redirect('//m.yohobuy.com');
  13 + }
  14 +
  15 + let param = {
  16 + limit: 12,
  17 + order: 's_t_desc',
  18 + page: 1,
  19 + uid: req.user.uid || 0
  20 + };
  21 +
  22 + if (brand) {
  23 + param.brand = brand;
  24 + } else if (sort) {
  25 + param.sort = sort;
  26 + }
  27 +
  28 + let arrs = [model.list(param)];
  29 +
  30 + if (brand) {
  31 + arrs.push(model.getBrand({
  32 + brandId: brand,
  33 + uid: req.user.uid || 0,
  34 + client_type: 'iphone' // todo
  35 + }));
  36 + }
  37 +
  38 + Promise.all(arrs).then((result) => {
  39 + res.render('global/list', {
  40 + module: 'product',
  41 + page: 'global-list',
  42 + pageHeader: headerModel.setNav({
  43 + navTitle: (result[1] || {}).brand_name || title
  44 + }),
  45 + list: result[0].list,
  46 + filter: result[0].filter,
  47 + pageFooter: true,
  48 + });
  49 + }).catch(next);
  50 +};
  51 +
  52 +const search = (req, res, next) => {
  53 + let query = req.query;
  54 +
  55 + if (query.type === 'new') {
  56 + query.order = 's_t_desc';
  57 + } else if (query.type === 'price') {
  58 + query.order = query.order === '1' ? 's_p_asc' : 's_p_desc';
  59 + }
  60 +
  61 + model.list(query).then((result) => {
  62 + res.render('global/search', {
  63 + list: result.list,
  64 + layout: false
  65 + });
  66 + }).catch(next);
  67 +};
  68 +
  69 +
  70 +module.exports = {
  71 + list,
  72 + search,
  73 + detail: function() {
  74 +
  75 + },
  76 +};
  1 +'use strict';
  2 +
  3 +const utils = '../../../utils';
  4 +const productProcess = require(`${utils}/product-process`);
  5 +const globalapi = global.yoho.GlobalAPI;
  6 +
  7 +exports.list = (param) => {
  8 + return globalapi.get('product/api/v2/detail/getlist', param).then((result) => {
  9 + if (!result || !result.data) {
  10 + return {};
  11 + }
  12 +
  13 + return {
  14 + filter: productProcess.processFilter(result.data.filter || []),
  15 + list: result.data.product_list.map((data) => {
  16 + return {
  17 + product_url: `//m.yohobuy.com/product/global/${data.product_skn}.html`,
  18 + product_img: data.default_images,
  19 + price: data.formart_final_price,
  20 + product_name: data.product_name,
  21 + country_name: data.country_name,
  22 + is_stock: data.is_stock,
  23 + is_limited: data.is_limited,
  24 + is_plane: data.is_plane
  25 + };
  26 + })
  27 + };
  28 + });
  29 +};
  30 +
  31 +exports.getBrand = (param) => {
  32 + return globalapi.get('editor/api/v1/brand/get', param).then((data) => {
  33 + return data.data || {};
  34 + });
  35 +};
@@ -53,6 +53,9 @@ const newShop = require(`${cRoot}/new-shop`); @@ -53,6 +53,9 @@ const newShop = require(`${cRoot}/new-shop`);
53 // 套装 53 // 套装
54 const bundle = require(`${cRoot}/bundle`); 54 const bundle = require(`${cRoot}/bundle`);
55 55
  56 +// 全球购
  57 +const globalPro = require(`${cRoot}/global`);
  58 +
56 // routers 59 // routers
57 60
58 // /pro_136349_455445/HEARTSOFARMianMaShuJiaoXiuXianKuPS1684.html 61 // /pro_136349_455445/HEARTSOFARMianMaShuJiaoXiuXianKuPS1684.html
@@ -200,4 +203,8 @@ router.get('/detail/limitHelp', newDetail.limitHelp); @@ -200,4 +203,8 @@ router.get('/detail/limitHelp', newDetail.limitHelp);
200 203
201 router.get('/index/allBrand', newShop.allBrand); // 店铺全部品牌 204 router.get('/index/allBrand', newShop.allBrand); // 店铺全部品牌
202 205
  206 +router.get('/global/list', globalPro.list); // 全球购列表页
  207 +router.get('/global/search', globalPro.search); // 全球购列表页搜索数据
  208 +router.get(/^\/global\/(\d+)\.html/, globalPro.detail); // 全球购店铺详情页
  209 +
203 module.exports = router; 210 module.exports = router;
  1 +<div class="global-list-page yoho-page">
  2 + <div class="filter-tab">
  3 + <ul id="list-nav" class="list-nav clearfix">
  4 + <li class="active new buriedpoint" data-bp-id="shop_listnav_new_1">
  5 + <a href="javascript:void(0);">
  6 + <span class="nav-txt">最新</span>
  7 + </a>
  8 + </li>
  9 + <li class="price buriedpoint" data-bp-id="shop_listnav_price_1">
  10 + <a href="javascript:void(0);">
  11 + <span class="nav-txt">价格</span>
  12 + <span class="icon">
  13 + <i class="iconfont up cur">&#xe615;</i>
  14 + <i class="iconfont down">&#xe616;</i>
  15 + </span>
  16 + </a>
  17 + </li>
  18 + <li class="filter buriedpoint" data-bp-id="shop_listnav_filter_1">
  19 + <a href="javascript:void(0);">
  20 + <span class="nav-txt">筛选</span>
  21 + <span class="iconfont cur">&#xe613;</span>
  22 + </a>
  23 + </li>
  24 + </ul>
  25 + </div>
  26 + <div id="global-container" class="global-container">
  27 + <div class="new-goods container clearfix">
  28 + <div class="global-list clearfix">
  29 + {{# list}}
  30 + <div class="good-info">
  31 + <div class="global-tag-container clearfix">
  32 + <div class="global-country">
  33 + {{#isEqualOr is_plane 'Y'}}
  34 + <span class="global-plane"></span>
  35 + {{/isEqualOr}}
  36 + <span>{{country_name}}</span>
  37 + </div>
  38 + {{#isEqualOr is_limited 'Y'}}
  39 + <div class="global-limited">
  40 + <span>限量</span>
  41 + </div>
  42 + {{/isEqualOr}}
  43 + </div>
  44 + <div class="good-detail-img">
  45 + {{#isEqualOr is_stock 'N'}}
  46 + <div class="global-saleout">
  47 + <div class="bg"></div>
  48 + <span class="text">售罄</span>
  49 + </div>
  50 + {{/isEqualOr}}
  51 + <a class="good-thumb" href="{{product_url}}">
  52 + <img src="{{image2 product_img w=235 h=314 q=60}}">
  53 + </a>
  54 + </div>
  55 + <div class="good-detail-text">
  56 + <div class="name">
  57 + <a href="{{product_url}}">{{product_name}}</a>
  58 + </div>
  59 + <div class="price">
  60 + <span class="sale-price">{{price}}</span>
  61 + </div>
  62 + </div>
  63 + </div>
  64 + {{/ list}}
  65 + </div>
  66 + </div>
  67 + <div class="price-goods container clearfix hide"></div>
  68 + {{> common/filter}}
  69 + </div>
  70 +</div>
  1 +{{# list}}
  2 + <div class="good-info">
  3 + <div class="global-tag-container clearfix">
  4 + <div class="global-country">
  5 + {{#isEqualOr is_plane 'Y'}}
  6 + <span class="global-plane"></span>
  7 + {{/isEqualOr}}
  8 + <span>{{country_name}}</span>
  9 + </div>
  10 + {{#isEqualOr is_limited 'Y'}}
  11 + <div class="global-limited">
  12 + <span>限量</span>
  13 + </div>
  14 + {{/isEqualOr}}
  15 + </div>
  16 + <div class="good-detail-img">
  17 + {{#isEqualOr is_stock 'N'}}
  18 + <div class="global-saleout">
  19 + <div class="bg"></div>
  20 + <span class="text">售罄</span>
  21 + </div>
  22 + {{/isEqualOr}}
  23 + <a class="good-thumb" href="{{product_url}}">
  24 + <img src="{{image2 product_img w=235 h=314 q=60}}">
  25 + </a>
  26 + </div>
  27 + <div class="good-detail-text">
  28 + <div class="name">
  29 + <a href="{{product_url}}">{{product_name}}</a>
  30 + </div>
  31 + <div class="price">
  32 + <span class="sale-price">{{price}}</span>
  33 + </div>
  34 + </div>
  35 + </div>
  36 +{{/ list}}
@@ -13,8 +13,11 @@ const domains = { @@ -13,8 +13,11 @@ const domains = {
13 liveApi: 'http://testapi.live.yohops.com:9999/', 13 liveApi: 'http://testapi.live.yohops.com:9999/',
14 singleApi: 'http://api-test3.yohops.com:9999/', 14 singleApi: 'http://api-test3.yohops.com:9999/',
15 15
16 - api: 'http://api-test3.yohops.com:9999/',  
17 - service: 'http://service-test3.yohops.com:9999/', 16 + // api: 'http://api-test3.yohops.com:9999/',
  17 + // service: 'http://service-test3.yohops.com:9999/',
  18 + api: 'http://api.yoho.cn/',
  19 + service: 'http://service.yoho.cn/',
  20 + global: 'http://api-global.yohobuy.com',
18 21
19 // liveApi: 'http://api.live.yoho.cn/', 22 // liveApi: 'http://api.live.yoho.cn/',
20 // singleApi: 'http://single.yoho.cn/', 23 // singleApi: 'http://single.yoho.cn/',
@@ -116,6 +119,7 @@ if (isProduction) { @@ -116,6 +119,7 @@ if (isProduction) {
116 domains: { 119 domains: {
117 api: 'http://api.yoho.yohoops.org/', 120 api: 'http://api.yoho.yohoops.org/',
118 service: 'http://service.yoho.yohoops.org/', 121 service: 'http://service.yoho.yohoops.org/',
  122 + global: 'http://api-global.yohobuy.com',
119 liveApi: 'http://api.live.yoho.cn/', 123 liveApi: 'http://api.live.yoho.cn/',
120 singleApi: 'http://single.yoho.cn/', 124 singleApi: 'http://single.yoho.cn/',
121 imSocket: 'wss://imsocket.yohobuy.com:443', 125 imSocket: 'wss://imsocket.yohobuy.com:443',
@@ -164,6 +168,7 @@ if (isProduction) { @@ -164,6 +168,7 @@ if (isProduction) {
164 domains: { 168 domains: {
165 api: process.env.TEST_API || 'http://api-test1.yohops.com:9999/', 169 api: process.env.TEST_API || 'http://api-test1.yohops.com:9999/',
166 service: process.env.TEST_SERVICE || 'http://service-test1.yohops.com:9999/', 170 service: process.env.TEST_SERVICE || 'http://service-test1.yohops.com:9999/',
  171 + global: process.env.TEST_GLOBAL || 'http://api-global.yohobuy.com',
167 liveApi: process.env.TEST_LIVE || 'http://testapi.live.yohops.com:9999/', 172 liveApi: process.env.TEST_LIVE || 'http://testapi.live.yohops.com:9999/',
168 singleApi: process.env.TEST_SINGLE || 'http://api-test1.yohops.com:9999/', 173 singleApi: process.env.TEST_SINGLE || 'http://api-test1.yohops.com:9999/',
169 imSocket: process.env.TEST_IM_SOCKET || 'ws://socket.yohobuy.com:10240', 174 imSocket: process.env.TEST_IM_SOCKET || 'ws://socket.yohobuy.com:10240',
  1 +'use strict';
  2 +import {
  3 + Controller
  4 +} from 'yoho-mvc';
  5 +
  6 +import {
  7 + NavView,
  8 + ContentView
  9 +} from './view';
  10 +
  11 +import {
  12 + search
  13 +} from '../models';
  14 +
  15 +let filter = require('plugin/filter');
  16 +let noResultHbs = require('product/search/no-result-new.hbs');
  17 +
  18 +class ListController extends Controller {
  19 + constructor() {
  20 + super();
  21 + this.navView = new NavView();
  22 + this.content = new ContentView();
  23 + this.page = 1;
  24 + this.searching = false;
  25 + this.nav = this.navView.getDefaultNav();
  26 + this.nav.reload = false;
  27 + this.query = $.extend(this.queryString(), {
  28 + type: 'new',
  29 + order: this.nav.order
  30 + });
  31 +
  32 + this.navView.on('nav-change', this.doNavChange.bind(this));
  33 + this.content.on('search', this.doSearch.bind(this));
  34 +
  35 + this.created();
  36 + }
  37 +
  38 + queryString() {
  39 + let vars = {},
  40 + hash,
  41 + i;
  42 + let hashes = window.location.search.slice(1).split('&');
  43 +
  44 + for (i = 0; i < hashes.length; i++) {
  45 + hash = hashes[i].split('=');
  46 + vars[hash[0]] = hash[1];
  47 + }
  48 + return vars;
  49 + }
  50 +
  51 + doNavChange(e, nav, navType) {
  52 + this.content.doContentChange(e, navType);
  53 + this.nav = nav;
  54 +
  55 + if (nav.reload) {
  56 + this.nav.page = 0;
  57 + } else if (nav.end) {
  58 + return;
  59 + }
  60 + this.query = $.extend(this.query, {
  61 + type: navType,
  62 + order: nav.order
  63 + });
  64 + if (this.nav.page === 0) {
  65 + this.search();
  66 + }
  67 + }
  68 +
  69 + doSearch() {
  70 + this.search();
  71 + }
  72 +
  73 + search(opt) {
  74 + if (this.searching || this.nav.end) {
  75 + return;
  76 + }
  77 +
  78 + let ext = {};
  79 +
  80 + if (opt) {
  81 + switch (opt.type) {
  82 + case 'ageLevel':
  83 + ext = {
  84 + age_level: opt.id
  85 + };
  86 + break;
  87 + default:
  88 + ext[opt.type] = opt.id;
  89 + break;
  90 + }
  91 + this.query = $.extend({}, this.query, ext);
  92 + this.nav.reload = true;
  93 + this.nav.page = 0;
  94 + }
  95 +
  96 + let page = this.nav.page + 1;
  97 + let params = $.extend({}, this.query, {
  98 + page: page
  99 + });
  100 +
  101 + this.searching = true;
  102 + search(params).then(data => {
  103 + this.nav.page = page;
  104 +
  105 + if (!data) {
  106 + this.nav.end = true;
  107 + if (this.nav.reload) {
  108 + this.content.setList(noResultHbs(), {
  109 + reload: true
  110 + });
  111 + }
  112 + } else {
  113 + if (this.nav.reload) {
  114 + this.content.setList(data, {
  115 + reload: true
  116 + });
  117 + } else {
  118 + this.content.setList(data, {});
  119 + }
  120 + }
  121 + }).catch(() => {
  122 + }).finally(() => {
  123 + this.nav.reload = false;
  124 + this.searching = false;
  125 + });
  126 + }
  127 +
  128 + created() {
  129 + this.navView.setFilter(filter);
  130 + filter.initFilter({
  131 + fCbFn: this.search.bind(this),
  132 + hCbFn: () => {
  133 + this.navView.preActive();
  134 + }
  135 + });
  136 + }
  137 +}
  138 +
  139 +module.exports = ListController;
  1 +require('product/global/list.page.css');
  2 +
  3 +const ListController = require('./controller');
  4 +
  5 +require('common/footer');
  6 +
  7 +new ListController();
  1 +import {
  2 + View
  3 +} from 'yoho-mvc';
  4 +
  5 +/**
  6 + * 排序 nav view
  7 + */
  8 +class NavView extends View {
  9 + constructor() {
  10 + super('#list-nav');
  11 +
  12 + // 初始化变量
  13 + this.navType = '';
  14 + this.navInfo = {
  15 + new: {
  16 + order: 0,
  17 + reload: true,
  18 + page: 1,
  19 + end: false
  20 + },
  21 + price: {
  22 + order: 1,
  23 + reload: true,
  24 + page: 0,
  25 + end: false
  26 + }
  27 + };
  28 +
  29 + this.$pre = this.$base.find('.active');
  30 +
  31 + // 事件委托
  32 + this.on('touchend touchcancel', 'li', this.onTabClick.bind(this));
  33 + }
  34 +
  35 + /**
  36 + * nav tab click 事件处理
  37 + * @param {*} e
  38 + */
  39 + onTabClick(e) {
  40 + let $this = $(e.currentTarget);
  41 + let $active;
  42 +
  43 + if ($this.hasClass('filter')) {
  44 + // 筛选面板切换状态
  45 + if ($this.hasClass('active')) {
  46 + this.filter.hideFilter();
  47 + } else {
  48 + this.$pre = $this.siblings('.active');
  49 + this.filter.showFilter();
  50 + }
  51 + this.$pre.toggleClass('active');
  52 + $this.toggleClass('active');
  53 + return;
  54 + } else {
  55 + if ($this.hasClass('new')) {
  56 + this.navType = 'new';
  57 + } else if ($this.hasClass('price')) {
  58 + this.navType = 'price';
  59 + }
  60 + }
  61 +
  62 + let nav = this.navInfo[this.navType];
  63 +
  64 + if ($this.hasClass('active')) {
  65 +
  66 + // 最新无排序切换
  67 + if ($this.hasClass('new')) {
  68 + return;
  69 + }
  70 +
  71 + if ($this.hasClass('price')) {
  72 +
  73 + // 价格切换排序状态
  74 + $this.find('.icon > .iconfont').toggleClass('cur');
  75 + this.$pre = $this; // 更新pre为当前项
  76 + nav.reload = true; // 重置reload,HTML会被替换为逆序的HTML
  77 + nav.order = nav.order === 0 ? 1 : 0; // 切换排序
  78 + }
  79 + } else {
  80 + $active = $this.siblings('.active');
  81 +
  82 + this.$pre = $this; // $pre为除筛选导航的其他导航项,若当前active的为筛选,则把$pre置为当前点击项
  83 +
  84 + if ($active.hasClass('filter')) {
  85 +
  86 + // 若之前active项为筛选,则隐藏筛选面板
  87 + this.filter.hideFilter();
  88 + }
  89 +
  90 + $active.removeClass('active');
  91 + $this.addClass('active');
  92 + }
  93 +
  94 + this.emit('nav-change', nav, this.navType);
  95 + }
  96 +
  97 + // 获取默认排序
  98 + getDefaultNav() {
  99 + return this.navInfo.new;
  100 + }
  101 +
  102 + // 设置前一个tab为选中状态
  103 + preActive() {
  104 + this.$pre.addClass('active');
  105 + this.$pre.siblings('.filter').removeClass('active');
  106 + }
  107 +
  108 + setFilter(filter) {
  109 + this.filter = filter;
  110 + }
  111 +}
  112 +
  113 +/**
  114 + * 商品列表 view
  115 + */
  116 +class ContentView extends View {
  117 + constructor() {
  118 + super('#global-container');
  119 + this.$ngc = this.$base.children('.new-goods');
  120 + this.$pgc = this.$base.children('.price-goods');
  121 + this.$current = this.$ngc;
  122 +
  123 + this.winH = $(window).height();
  124 +
  125 + // srcoll to load more
  126 + $(window).scroll(() => {
  127 + window.requestAnimationFrame(this.scrollHandler.bind(this));
  128 + });
  129 + }
  130 +
  131 + /**
  132 + * 滚动事件处理
  133 + */
  134 + scrollHandler() {
  135 + // 当scroll到1/2$goodsContainer高度后继续请求下一页数据
  136 + if ($(window).scrollTop() + this.winH >
  137 + $(document).height() - 0.5 * this.$current.height()) {
  138 + this.emit('search');
  139 + }
  140 + }
  141 +
  142 + /**
  143 + * 商品列表切换
  144 + * @param {*} e
  145 + * @param {*} navType
  146 + */
  147 + doContentChange(e, navType) {
  148 + // 切换container显示
  149 + this.$base.children('.container:not(.hide)').addClass('hide');
  150 +
  151 + switch (navType) {
  152 + case 'new':
  153 + this.$ngc.removeClass('hide');
  154 + this.$current = this.$ngc;
  155 + break;
  156 + case 'price':
  157 + this.$pgc.removeClass('hide');
  158 + this.$current = this.$pgc;
  159 + break;
  160 + default:
  161 + break;
  162 + }
  163 + }
  164 +
  165 + setList(data, opts) {
  166 + if (opts.reload) {
  167 + this.$current.html(data);
  168 + } else {
  169 + this.$current.append(data);
  170 + }
  171 + }
  172 +}
  173 +
  174 +export {
  175 + NavView,
  176 + ContentView
  177 +};
  1 +'use strict';
  2 +
  3 +import {
  4 + http
  5 +} from 'yoho-mvc';
  6 +
  7 +function search(data) {
  8 + return http({
  9 + type: 'GET',
  10 + url: location.protocol + '//m.yohobuy.com/product/global/search',
  11 + data: data,
  12 + xhrFields: {
  13 + withCredentials: true
  14 + }
  15 + });
  16 +}
  17 +
  18 +export {
  19 + search
  20 +};
  1 +'use strict';
  2 +
  3 +const $ = require('yoho-jquery');
  4 +
  5 +class View {
  6 + constructor(ele) {
  7 + this.$base = $(ele);
  8 + }
  9 +
  10 + on(event, target, fn) {
  11 + if (typeof target === 'function') {
  12 + fn = target;
  13 + target = null;
  14 + }
  15 +
  16 + if (this.$base) {
  17 + if (target) {
  18 + this.$base.on(event, target, fn);
  19 + } else {
  20 + this.$base.on(event, fn);
  21 + }
  22 + }
  23 + }
  24 +
  25 + emit(event, ...data) {
  26 + this.$base.trigger(event, data);
  27 + }
  28 +
  29 +}
  30 +
  31 +class Controller {
  32 + constructor() {
  33 +
  34 + }
  35 +
  36 +}
  37 +
  38 +function http(options) {
  39 + let ajax = $.ajax(options);
  40 +
  41 + ajax.then = ajax.done.bind(ajax);
  42 + ajax.catch = ajax.fail.bind(ajax);
  43 + ajax.finally = ajax.always.bind(ajax);
  44 + return ajax;
  45 +}
  46 +
  47 +export {
  48 + View, Controller, http
  49 +};
  1 +.global-list-page {
  2 + .list-nav {
  3 + border-top: 2px solid #fff;
  4 + border-bottom: 1px solid #e6e6e6;
  5 +
  6 + > li {
  7 + float: left;
  8 + width: 33%;
  9 + height: 33PX;
  10 + line-height: 33PX;
  11 + text-align: center;
  12 + font-size: 14PX;
  13 + }
  14 +
  15 + a {
  16 + display: block;
  17 + box-sizing: border-box;
  18 + width: 100%;
  19 + height: 100%;
  20 + color: #999;
  21 + }
  22 +
  23 + .nav-txt {
  24 + display: inline-block;
  25 + height: 100%;
  26 + box-sizing: border-box;
  27 + }
  28 +
  29 + .active > a {
  30 + color: #000;
  31 +
  32 + .iconfont {
  33 + color: #999;
  34 +
  35 + &.cur {
  36 + color: #000;
  37 + }
  38 + }
  39 + }
  40 +
  41 + .new .iconfont {
  42 + transform: scale(0.8);
  43 + font-weight: bold;
  44 + font-size: 12PX;
  45 + }
  46 +
  47 + .filter .iconfont {
  48 + font-size: 12PX;
  49 + transition: transform 0.1 ease-in;
  50 + }
  51 +
  52 + .filter.active .iconfont {
  53 + transform: rotate(-180deg);
  54 + }
  55 +
  56 + .icon {
  57 + position: relative;
  58 +
  59 + i {
  60 + position: absolute;
  61 + transform: scale(0.8);
  62 + font-weight: bold;
  63 + }
  64 +
  65 + .up {
  66 + top: -11PX;
  67 + }
  68 +
  69 + .down {
  70 + top: -4PX;
  71 + }
  72 + }
  73 + }
  74 +
  75 + .global-container {
  76 + position: relative;
  77 + min-height: auto !important;
  78 + padding-left: 15px;
  79 + padding-top: 20px;
  80 +
  81 + .global-country {
  82 + float: left;
  83 + background: rgb(70, 46, 61);
  84 + color: #fff;
  85 + padding: 2px 8px;
  86 + font-size: 16px;
  87 +
  88 + span {
  89 + float: left;
  90 + }
  91 + }
  92 +
  93 + .global-limited {
  94 + float: left;
  95 + border: 1px solid rgb(70, 46, 61);
  96 + margin-left: 2px;
  97 + padding: 0 5px;
  98 + font-size: 16px;
  99 + }
  100 +
  101 + .global-saleout {
  102 + width: 50px;
  103 + height: 50px;
  104 + position: absolute;
  105 + top: 0;
  106 + right: 5px;
  107 +
  108 + .text {
  109 + width: 100%;
  110 + text-align: center;
  111 + font-size: 16px;
  112 + line-height: 24px;
  113 + position: absolute;
  114 + color: #fff;
  115 + top: 50%;
  116 + left: 50%;
  117 + transform: translate(-50%, -50%);
  118 + }
  119 +
  120 + .bg {
  121 + width: 100%;
  122 + height: 100%;
  123 + position: absolute;
  124 + top: 0;
  125 + left: 0;
  126 + background: #999;
  127 + border-radius: 30%;
  128 + transform: rotate(45deg);
  129 + }
  130 + }
  131 +
  132 + .global-plane {
  133 + width: 21px;
  134 + height: 21px;
  135 + background-image: resolve("product/airplane.png");
  136 + background-repeat: no-repeat;
  137 + background-size: cover;
  138 + margin-right: 10px;
  139 + margin-top: 2px;
  140 + }
  141 +
  142 + .sale-price {
  143 + color: #000;
  144 + }
  145 + }
  146 +
  147 + .no-result-new {
  148 + text-align: center;
  149 + padding-top: 90px;
  150 + padding-bottom: 110px;
  151 +
  152 + p {
  153 + color: #ccc;
  154 + margin-bottom: 25px;
  155 + font-size: 26px;
  156 +
  157 + &:first-child {
  158 + color: #444;
  159 + font-size: 32px;
  160 + }
  161 + }
  162 + }
  163 +}