6 Commits 88ac2d2adb ... 6b0c5b77bf

Author SHA1 Message Date
  peter 6b0c5b77bf change: 商品碳相关内容调整. 1 month ago
  peter badd9349ed change: 商品碳值数据字段调整. 1 month ago
  peter 17b5dc9ae7 fix: 修复从au合并esg功能导致的代码疏漏. 1 month ago
  peter d53ce39d60 lint: 代码风格格式化. 1 month ago
  peter f523d619a9 feat: 主导航增加碳足迹商品页入口.商品分类页增加碳足迹商品标签搜索. 1 month ago
  Ken 6b3a308b07 feat: 从au release分支合并ESG相关功能.解决代码冲突. 1 month ago

+ 1 - 0
.prettierrc

@@ -1,4 +1,5 @@
 {
+  "printWidth": 120,
   "semi": false,
   "singleQuote": true,
   "trailingComma": "es5",

+ 3 - 2
assets/css/common.scss

@@ -1,4 +1,4 @@
-$deep-blue: #004a97;
+$deep-blue: #00213b;
 html,
 body,
 #__nuxt,
@@ -136,7 +136,8 @@ textarea {
     background-color: $deep-blue !important;
     border-color: $deep-blue !important;
     &:hover {
-        background-color: #013269;
+        background-color: $deep-blue !important;
+        opacity: 0.8;
     }
 }
 

BIN
assets/img/esg/air.png


BIN
assets/img/esg/aircraft.png


BIN
assets/img/esg/bg_city.png


BIN
assets/img/esg/co2.png


BIN
assets/img/esg/co2_green.png


BIN
assets/img/esg/electricity.png


BIN
assets/img/esg/iphone.png


BIN
assets/img/esg/leaf.png


BIN
assets/img/esg/sea.png


BIN
assets/img/esg/ship.png


BIN
assets/img/esg/tree.png


BIN
assets/img/order/artwork.png


BIN
assets/img/order/cer.png


BIN
assets/img/order/invo.png


BIN
assets/img/order/link.png


BIN
assets/img/order/qc.png


+ 36 - 4
components/Card.vue

@@ -4,11 +4,18 @@
       <!-- <nuxt-link :to="{ name: 'product-code', params: { code: cardData.product_code } }"> -->
       <div class="card-img">
         <el-image  
-          :src="comImg"
-          class="card-img-1"
-          fit="cover"
-          style="width: 100%; height: 100%"
+        :src="comImg"
+        class="card-img-1"
+        fit="cover"
+        style="width: 100%; height: 100%"
         ></el-image>
+        <div class="co2-info" v-if="cardData.co2_uk_air && cardData.co2_uk_sea">
+            <img src="@/assets/img/esg/ship.png" alt="CO2" class="co2-icon" />
+            <span>{{ cardData.co2_uk_sea || 0 }} kg</span>
+          <div></div>
+            <img src="@/assets/img/esg/aircraft.png" alt="CO2" class="co2-icon" />
+            <span>{{ cardData.co2_uk_air || 0 }} kg</span>
+        </div>
         <img class="best_icon" :src="comBestIcon" v-if="comBestIcon"/>
         <div class="cycle_icon">
           <img
@@ -101,6 +108,7 @@ export default {
     padding: 10px;
     box-sizing: border-box;
     overflow: hidden;
+    position: relative;
     .card-img-1{
       transition: all 0.5s ;
     }
@@ -109,6 +117,30 @@ export default {
       top: 0;
       left: 0;
     }
+    .co2-info {
+      display: flex;
+      align-items: center;
+      background: #07A73A;
+      color: #fff;
+      font-weight: bold;
+      border-radius: 2px;
+      padding: 5px;
+      position: absolute;
+      bottom: 10px;
+      box-shadow: 0 2px 8px rgba(0,0,0,0.08);
+      div{
+        display: inline-block;
+        margin: 0 10px;
+        width: 2px;
+        height: 12px;
+        border-right: 2px solid #fff;
+      }
+      .co2-icon {
+        width: 20px;
+        height: 20px;
+        margin-right: 4px;
+      }
+    }
     .cycle_icon {
       position: absolute;
       top: 0;

+ 0 - 1
components/DesignFormDialog.vue

@@ -118,7 +118,6 @@ export default {
 
 <style lang="scss" scoped>
 :deep(.el-dialog__header){
-    padding: 20px;
     border-bottom:1px solid #eee;
 }
 textarea{

+ 235 - 0
components/FootprintReportDialog.vue

@@ -0,0 +1,235 @@
+<template>
+  <el-dialog :visible.sync="visible" width="550px" :title="'Carbon Footprint Report'" :before-close="handleClose" :lock-scroll="false">
+    <div>
+      <el-form label-width="70px">
+        <el-form-item label="Model">
+          <el-select v-model="form.model" placeholder="Please select" style="width:100%;" clearable filterable>
+            <el-option
+                :label="item.accountName.replace(/\s*[\(\(][^)\)]*[\)\)]$/, '')"
+              v-for="(item, idx) in carbon"
+              :value="idx"
+              :key="idx"
+            />
+          </el-select>
+        </el-form-item>
+        <div class="form-row">
+          <el-form-item label="Quantity" style="flex:1;">
+            <el-input v-model="form.quantity" type="number" :min="1" :step="1" :controls="false"
+              placeholder="Please input" class="left-input-number" />
+          </el-form-item>
+          <el-form-item label="Transport" style="flex:1;margin-left:10px;">
+            <el-select v-model="form.transport" placeholder="Please select" style="width:100%;" clearable>
+              <el-option label="UK-Sea" value="UK-Sea" />
+              <el-option label="UK-Air" value="UK-Air" />
+            </el-select>
+          </el-form-item>
+        </div>
+      </el-form>
+      <div class="carbon-report-card">
+        <div class="carbon-report-main">
+          <div class="carbon-report-header">
+            <span>Product Carbon Footprint</span>
+          </div>
+          <div class="carbon-report-value">{{ comEmissionTotal }}</div>
+          <div class="carbon-report-date">kgCO₂e per product unit</div>
+          <div class="carbon-report-date">Accounting Period:{{ this.carbon[this.form.model]?.accountTime }}</div>
+          <img src="@/assets/img/esg/bg_city.png" alt="bg" class="carbon-bg" />
+          <div class="carbon-report-equal">
+            <div class="equal-title">Equivalent to</div>
+            <div class="equal-list">
+              <div class="equal-item">
+                <img src="@/assets/img/esg/tree.png" alt="tree" />
+                <div>{{ multiply(comEquallist.equallist[0]?.amount, form.quantity) || 0 }} <span>tree</span></div>
+                <div class="equal-desc">CO₂ uptake by 1 ammodendron tree</div>
+              </div>
+              <div class="equal-item">
+                <img src="@/assets/img/esg/electricity.png" alt="electricity" />
+                <div>{{ multiply(comEquallist.equallist[1]?.amount, form.quantity) || 0 }} <span>kWh</span></div>
+                <div class="equal-desc">Household electricity consumption</div>
+              </div>
+              <div class="equal-item">
+                <img src="@/assets/img/esg/iphone.png" alt="iphone" />
+                <div>{{ multiply(comEquallist.equallist[2]?.amount, form.quantity) || 0 }} <span>day</span></div>
+                <div class="equal-desc">The number of days an iPhone is used</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div style="text-align:right;margin-top:20px;">
+        <el-button type="primary" class="report-btn"
+          @click="download(comEquallist?.url)">Download</el-button>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { times as npTimes } from 'number-precision';
+
+export default {
+  props: {
+    visible: { type: Boolean, default: false },
+    carbon: { type: Array, default: () => [] }
+  },
+  data() {
+    return {
+      form: {
+        model: '',
+        quantity: 1,
+        transport: ''
+      }
+    }
+  },
+  computed: {
+    comEquallist() {
+      return this.carbon[this.form.model]?.accountlist?.find(item => item.code === this.form.transport) || { equallist: [], emissionTotal: 0 };
+    },
+    comEmissionTotal() {
+      return this.multiply(this.comEquallist.emissionTotal, this.form.quantity).toFixed(2) || 0;
+    }
+  },
+  methods: {
+    handleClose() {
+      this.$emit('update:visible', false);
+    },
+    multiply(a, b) {
+      return npTimes(Number(a), b);
+    },
+    download(url) {
+      if (!url) {
+        this.$message.error('No report available for download');
+        return
+      }
+      var urlStr = url.match('[^/]+(?!.*/)')[0]
+      this.$utils.downloadBlob(url, urlStr)
+    },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+$green: #006D28;
+$blue-dark: #15395A;
+$white: #fff;
+$gray: #666;
+$radius-lg: 16px;
+$shadow-green: 0 2px 8px rgba($green, 0.08);
+
+:deep(.el-dialog__header) {
+  padding: 20px;
+  border-bottom: 1px solid #eee;
+}
+
+.form-row {
+  display: flex;
+  gap: 10px;
+}
+
+.carbon-report-card {
+  background: transparent;
+
+  .carbon-report-main {
+    background: $green;
+    border-radius: 10px;
+    color: $white;
+    padding: 18px;
+    position: relative;
+    overflow: hidden;
+    min-height: 120px;
+
+    .carbon-report-header {
+      font-size: 20px;
+      font-weight: bold;
+      margin-bottom: 8px;
+    }
+
+    .carbon-report-value {
+      font-size: 32px;
+      font-weight: bold;
+
+      .unit {
+        font-size: 18px;
+        font-weight: normal;
+      }
+    }
+
+    .carbon-report-date {
+      font-size: 14px;
+      margin-bottom: 10px;
+    }
+  }
+
+  .carbon-bg {
+    position: absolute;
+    right: 20PX;
+    top: 20PX;
+    width: 232px;
+    height: 126px;
+    opacity: 0.7;
+    pointer-events: none;
+  }
+
+  .carbon-report-equal {
+    background: $white;
+    color: $green;
+    border-radius: 10px;
+    padding: 18px;
+    position: relative;
+    z-index: 2;
+    box-shadow: $shadow-green;
+
+    .equal-title {
+      font-size: 14px;
+      font-weight: 600;
+      margin-bottom: 8px;
+      color: #000;
+    }
+
+    .equal-list {
+      display: flex;
+      justify-content: space-around;
+      align-items: flex-start;
+      margin-top: 20px;
+
+      .equal-item {
+        text-align: center;
+        width: 130px;
+
+        img {
+          width: 32px;
+          height: 32px;
+          margin-bottom: 4px;
+        }
+
+        div {
+          &:nth-child(2) {
+            font-size: 14px;
+            font-weight: 600;
+            color: #000;
+          }
+        }
+
+        .equal-desc {
+          font-size: 12px;
+          color: $gray;
+          margin-top: 2px;
+          word-break: break-word;
+        }
+      }
+    }
+  }
+}
+
+.report-btn {
+  background: $blue-dark !important;
+  border: none !important;
+  height: 40px;
+  font-size: 16px;
+  font-weight: 500;
+}
+
+:deep(.el-input__inner) {
+  padding-right: 0;
+}
+</style>

+ 49 - 109
components/PcHeader.vue

@@ -25,9 +25,7 @@
           :style="{ display: showType }">
           <div
             class="flex-auto flex center stretch no-result"
-            v-if="
-              !loading && result.cate.length < 1 && productsList.length < 1
-            ">
+            v-if="!loading && result.cate.length < 1 && productsList.length < 1">
             No results found for “{{ keyword }}”
           </div>
           <div
@@ -45,10 +43,7 @@
                     :to="{
                       name: 'category-firstCategory',
                       params: {
-                        firstCategory: item.name
-                          .replace(/\s+/g, '-')
-                          .replace('-&', '')
-                          .toLowerCase(),
+                        firstCategory: item.name.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
                       },
                     }">
                     <p>{{ item.name }}</p>
@@ -69,14 +64,8 @@
                     :to="{
                       name: 'category-firstCategory-secondCategory',
                       params: {
-                        firstCategory: item.parentName
-                          .replace(/\s+/g, '-')
-                          .replace('-&', '')
-                          .toLowerCase(),
-                        secondCategory: item.name
-                          .replace(/\s+/g, '-')
-                          .replace('-&', '')
-                          .toLowerCase(),
+                        firstCategory: item.parentName.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
+                        secondCategory: item.name.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
                       },
                     }">
                     <p>{{ item.name }}</p>
@@ -86,18 +75,9 @@
                     :to="{
                       name: 'category-firstCategory-secondCategory-thirdCategory',
                       params: {
-                        firstCategory: item.grandName
-                          .replace(/\s+/g, '-')
-                          .replace('-&', '')
-                          .toLowerCase(),
-                        secondCategory: item.parentName
-                          .replace(/\s+/g, '-')
-                          .replace('-&', '')
-                          .toLowerCase(),
-                        thirdCategory: item.name
-                          .replace(/\s+/g, '-')
-                          .replace('-&', '')
-                          .toLowerCase(),
+                        firstCategory: item.grandName.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
+                        secondCategory: item.parentName.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
+                        thirdCategory: item.name.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
                       },
                     }">
                     <p>{{ item.name }}</p>
@@ -114,9 +94,7 @@
                     name: 'category-searchResult',
                     query: { keyword: keyword },
                   }">
-                  <div class="seeAllResult">
-                    Show all {{ result.total }} Results
-                  </div>
+                  <div class="seeAllResult">Show all {{ result.total }} Results</div>
                 </nuxt-link>
               </div>
               <ul
@@ -138,7 +116,9 @@
                       "
                       alt="" />
                     <div class="product-info">
-                      <p style="width:94%;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">{{ item.alias_name || item.product_name }}</p>
+                      <p style="width: 94%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
+                        {{ item.alias_name || item.product_name }}
+                      </p>
                       <p>{{ item.product_code }}</p>
                     </div>
                   </nuxt-link>
@@ -267,8 +247,7 @@
                     </nuxt-link>
                   </div>
                   <div class="sub-menu">
-                    <a
-                      href="mailto:Info@promocollection.uk?subject=Sample%20Request">
+                    <a href="mailto:Info@promocollection.uk?subject=Sample%20Request">
                       <div class="flex">
                         <div class="icon mail"></div>
                         <div class="sub-title">Sample Request</div>
@@ -276,8 +255,7 @@
                     </a>
                   </div>
                   <div class="sub-menu">
-                    <a
-                      href="mailto:Info@promocollection.uk?subject=Free%20Mockup%20Request">
+                    <a href="mailto:Info@promocollection.uk?subject=Free%20Mockup%20Request">
                       <div class="flex">
                         <div class="icon mail"></div>
                         <div class="sub-title">Mockup Request</div>
@@ -315,10 +293,7 @@
               class="shopProducts"
               @click.stop="openShopProduct">
               Shop Products
-              <i
-                :class="
-                  isShopBlock ? 'el-icon-arrow-up' : 'el-icon-arrow-down'
-                "></i>
+              <i :class="isShopBlock ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
             </span>
           </div>
           <Transition name="category">
@@ -336,18 +311,13 @@
                       :to="{
                         name: 'category-firstCategory',
                         params: {
-                          firstCategory: item1.name
-                            .replace(/\s+/g, '-')
-                            .replace('-&', '')
-                            .toLowerCase(),
+                          firstCategory: item1.name.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
                         },
                       }">
                       <div class="menu-item-icon">
                         <img
                           :src="
-                            item1.style && !$mediaRegExp.test(item1.style)
-                              ? $OSS_PREFIX + item1.style
-                              : item1.style
+                            item1.style && !$mediaRegExp.test(item1.style) ? $OSS_PREFIX + item1.style : item1.style
                           "
                           alt="" />
                       </div>
@@ -365,14 +335,8 @@
                       :to="{
                         name: 'category-firstCategory-secondCategory',
                         params: {
-                          firstCategory: item1.name
-                            .replace(/\s+/g, '-')
-                            .replace('-&', '')
-                            .toLowerCase(),
-                          secondCategory: item2.name
-                            .replace(/\s+/g, '-')
-                            .replace('-&', '')
-                            .toLowerCase(),
+                          firstCategory: item1.name.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
+                          secondCategory: item2.name.replace(/\s+/g, '-').replace('-&', '').toLowerCase(),
                         },
                       }">
                       {{ item2.name }}
@@ -450,7 +414,6 @@
         <li
           class="nav-list"
           @click="closeAllBlock">
-          <!-- <a :href="'/category?feature=54'"> New products</a> -->
           <div class="nav-list-title">
             <nuxt-link
               :to="{ name: 'category', query: { feature: 54 } }"
@@ -463,9 +426,7 @@
           class="nav-list"
           @click="closeAllBlock">
           <div class="nav-list-title">
-            <a href="/article/Compliance">
-              Compliance
-            </a>
+            <a href="/article/Compliance"> Compliance </a>
           </div>
         </li>
         <li
@@ -483,6 +444,17 @@
             </nuxt-link>
           </div>
         </li>
+        <li
+          class="nav-list"
+          @click="closeAllBlock">
+          <div class="nav-list-title">
+            <nuxt-link
+              :to="{ name: 'category', query: { feature: 282 } }"
+              target="_self">
+              Carbon Footprint
+            </nuxt-link>
+          </div>
+        </li>
         <!-- <li
           class="nav-list"
           @click="closeAllBlock">
@@ -649,16 +621,12 @@ export default {
     //       this.budget = res.result
     //     }
     //   })
-    const p4 = this.$axios
-      .post('/uk-api/home/articleList', { keyword: 'Indent Ideas' })
-      .then(res => {
-        this.indentIdeasArticle = res.result.data[0] || {}
-      })
-    const p5 = this.$axios
-      .post('/uk-api/home/articleList', { keyword: 'Compliance' })
-      .then(res => {
-        this.complianceArticle = res.result.data[0] || {}
-      })
+    const p4 = this.$axios.post('/uk-api/home/articleList', { keyword: 'Indent Ideas' }).then(res => {
+      this.indentIdeasArticle = res.result.data[0] || {}
+    })
+    const p5 = this.$axios.post('/uk-api/home/articleList', { keyword: 'Compliance' }).then(res => {
+      this.complianceArticle = res.result.data[0] || {}
+    })
     // 并联异步操作,总耗时===耗时最长的单个请求。之前的逻辑是串联,总耗时为所有请求耗时的累加
     await Promise.all([p1, p4, p5])
   },
@@ -676,9 +644,7 @@ export default {
             ...item,
           }
           if (item.img) {
-            temp.image = !this.$mediaRegExp.test(item.img)
-              ? this.$OSS_PREFIX + item.img
-              : item.img
+            temp.image = !this.$mediaRegExp.test(item.img) ? this.$OSS_PREFIX + item.img : item.img
           }
           return temp
         })
@@ -730,16 +696,10 @@ export default {
     window.addEventListener('click', this.closeLeadtimeAndBudget)
 
     if (process.env.NODE_ENV === 'development') {
-      const client = algoliasearch(
-        '7KGEFE6I2Z',
-        'e39e202ace0a2fa12ea61095e6ede35d'
-      )
+      const client = algoliasearch('7KGEFE6I2Z', 'e39e202ace0a2fa12ea61095e6ede35d')
       this.index = client.initIndex('test_uk')
     } else {
-      const client = algoliasearch(
-        '2340OWI595',
-        '2d4c53cdcf2bab0c361e589c2c2272fa'
-      )
+      const client = algoliasearch('2340OWI595', '2d4c53cdcf2bab0c361e589c2c2272fa')
       this.index = client.initIndex('product_uk')
     }
   },
@@ -786,20 +746,11 @@ export default {
                 let colorImg = ''
                 item.colour_imgs = JSON.parse(item.colour_imgs)
                 item.colour_imgs.sort((a, b) => a.name.length - b.name.length)
-                if (
-                  Array.isArray(item.colour_imgs) &&
-                  item.colour_imgs.length
-                ) {
+                if (Array.isArray(item.colour_imgs) && item.colour_imgs.length) {
                   item.colour_imgs.forEach(colorItem => {
                     if (colorItem.name && colorItem.name.length) {
-                      if (
-                        new RegExp(colorItem.name.toLowerCase(), 'i').test(key)
-                      ) {
-                        console.log(
-                          item.product_code,
-                          colorItem.name,
-                          'replace'
-                        )
+                      if (new RegExp(colorItem.name.toLowerCase(), 'i').test(key)) {
+                        console.log(item.product_code, colorItem.name, 'replace')
                         colorImg = colorItem.img
                       } else if (
                         /\s/.test(colorItem.name) &&
@@ -808,11 +759,7 @@ export default {
                           .filter(a => a.length > 0)
                           .some(b => new RegExp(b.toLowerCase(), 'i').test(key))
                       ) {
-                        console.log(
-                          item.product_code,
-                          colorItem.name,
-                          'advance replace'
-                        )
+                        console.log(item.product_code, colorItem.name, 'advance replace')
                         colorImg = colorItem.img
                       }
                     }
@@ -820,11 +767,7 @@ export default {
                   item.colour_imgs.forEach(i => {
                     if (i.name && i.name.length) {
                       if (key.toLowerCase().includes(i.name.toLowerCase())) {
-                        console.log(
-                          item.product_code,
-                          i.name,
-                          'complete replace'
-                        )
+                        console.log(item.product_code, i.name, 'complete replace')
                         colorImg = i.img
                       }
                     }
@@ -838,10 +781,7 @@ export default {
                 })
                 if (!item.category_id) return
                 const id = parseInt(item.category_id)
-                const categoryResult = this.getCategoryFromTree(
-                  id,
-                  this.categoryList
-                )
+                const categoryResult = this.getCategoryFromTree(id, this.categoryList)
                 switch (categoryResult.lev) {
                   case 1:
                     if (!t1.includes(id)) {
@@ -888,9 +828,7 @@ export default {
       //   name: 'category-searchResult',
       //   query: { keyword: this.keyword },
       // })
-      location.href =
-        location.origin +
-        `/category/searchResult?keyword=${encodeURIComponent(this.keyword)}`
+      location.href = location.origin + `/category/searchResult?keyword=${encodeURIComponent(this.keyword)}`
     },
     logout() {
       this.$store.dispatch('logout').then(() => {
@@ -1008,7 +946,9 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.product-info {width:100%;}
+.product-info {
+  width: 100%;
+}
 header {
   width: 100%;
   position: fixed;

+ 12 - 1
components/Project.vue

@@ -50,11 +50,16 @@
             src="@/assets/img/tick.png" /><span>Item Record</span>
         </div>
       </a>
+      <div v-if="productInfo.carbon?.length"
+        class="flex btn-nav" @click="openFootprint">
+        <img src="@/assets/img/esg/co2.png" />
+        <span>Carbon Footprint</span>
+      </div>
     </div>
   </section>
 </template>
-
 <script>
+
 export default {
   props: {
     productInfo: {
@@ -147,6 +152,12 @@ export default {
           location.origin + `/product-builder/${this.$route.params.code}`
       }, 0)
     },
+    openTicket(){
+      this.$emit('handleOpenTicket')
+    },
+    openFootprint(){
+      this.$emit('handleOpenFootprint')
+    }
   },
 }
 </script>

+ 40 - 55
components/product/ProductRight.vue

@@ -79,6 +79,19 @@
           <h3>Description</h3>
           <p v-html="comInfo.description"></p>
         </div>
+        <div
+          class="details-1"
+          v-if="pageData.carbon?.length">
+          <h3>Carbon Footprint Transparency</h3>
+          <p>
+            This product has undergone mid-lifecycle carbon footprint assessment. Click the
+            <span>Carbon Footprint</span> project to view detailed calculations by transport mode;
+          </p>
+          <p>
+            We offer <span>Gold Standard-ceriied carbon offset proiects</span> for neutralization, ensuring full
+            transparency and compliance with global sustainability standards. Contact us for detailed reports.
+          </p>
+        </div>
         <div
           class="details-2"
           v-if="pageData.pbo">
@@ -133,17 +146,9 @@
                 <nuxt-link
                   v-if="isProduct(item.trim())"
                   :to="{ name: 'product-code', params: { code: item.trim() } }"
-                  ><span
-                    >{{ item
-                    }}<em v-if="i < comIncluded_packaging.length - 1"
-                      >,</em
-                    ></span
-                  ></nuxt-link
-                >
-                <span v-else
-                  >{{ item
-                  }}<em v-if="i < comIncluded_packaging.length - 1">,</em></span
+                  ><span>{{ item }}<em v-if="i < comIncluded_packaging.length - 1">,</em></span></nuxt-link
                 >
+                <span v-else>{{ item }}<em v-if="i < comIncluded_packaging.length - 1">,</em></span>
               </div>
             </li>
             <li v-if="comInfo.optional_packaging">
@@ -155,17 +160,9 @@
                 <nuxt-link
                   v-if="isProduct(item.trim())"
                   :to="{ name: 'product-code', params: { code: item.trim() } }"
-                  ><span
-                    >{{ item
-                    }}<em v-if="i < comOptional_packaging.length - 1"
-                      >,</em
-                    ></span
-                  ></nuxt-link
-                >
-                <span v-else
-                  >{{ item
-                  }}<em v-if="i < comOptional_packaging.length - 1">,</em></span
+                  ><span>{{ item }}<em v-if="i < comOptional_packaging.length - 1">,</em></span></nuxt-link
                 >
+                <span v-else>{{ item }}<em v-if="i < comOptional_packaging.length - 1">,</em></span>
               </div>
             </li>
             <li v-if="comInfo.optional_attachments">
@@ -175,12 +172,7 @@
                   :to="{ name: 'product-code', params: { code: item } }"
                   v-for="(item, i) in comOptional_attachments"
                   :key="item"
-                  ><span
-                    >{{ item
-                    }}<em v-if="i < comOptional_attachments.length - 1"
-                      >,</em
-                    ></span
-                  ></nuxt-link
+                  ><span>{{ item }}<em v-if="i < comOptional_attachments.length - 1">,</em></span></nuxt-link
                 >
               </div>
             </li>
@@ -199,12 +191,7 @@
           </ul>
           <!-- <el-button @click="ticketFormVisible = true"
           v-if="isLogin && /\@promocollection.uk/.test(userInfo.email)">Ticket</el-button> -->
-          <ul
-            v-if="
-              comInfo.print_position ||
-              comInfo.print_size_area ||
-              comInfo.print_marketing
-            ">
+          <ul v-if="comInfo.print_position || comInfo.print_size_area || comInfo.print_marketing">
             <li>
               <div class="title">Print Info</div>
             </li>
@@ -285,9 +272,8 @@
           </ul>
         </div>
         <p class="details-1">
-          Due to differences between production batches, product sizes may vary
-          slightly. The above Colours and measurements are approximate, and for
-          guidance only.
+          Due to differences between production batches, product sizes may vary slightly. The above Colours and
+          measurements are approximate, and for guidance only.
         </p>
         <!-- <div v-for="(item,index) in pageData.showcase" :key="index" class="showcase">
             <a :href="item.url">
@@ -308,16 +294,12 @@
         v-show="false">
         <div v-if="stockData.length > 0">
           <stock-table :data="stockData"></stock-table>
-          <p class="quote-tips">
-            For quantities over available stock levels, please contact us for
-            pricing and timing
-          </p>
+          <p class="quote-tips">For quantities over available stock levels, please contact us for pricing and timing</p>
         </div>
         <div
           class="quote-tips"
           v-else>
-          This product is made offshore, and is available for any quantity equal
-          to, or above the listed MOQ
+          This product is made offshore, and is available for any quantity equal to, or above the listed MOQ
         </div>
       </div>
       <div v-show="typeTab == 3">
@@ -377,8 +359,19 @@
           :visible.sync="ticketFormVisible"
           @handleSend="sendTicket"
           :rules="rules"></form-dialog> -->
+      <footprint-report-dialog
+        :visible.sync="footprintVisible"
+        :carbon="pageData.carbon"></footprint-report-dialog>
       <!-- 右侧project浮动框 -->
-      <project :productInfo="pageData"></project>
+      <project
+        :productInfo="pageData"
+        @handleOpenFootprint="footprintVisible = true"></project>
+      <!-- 加入project弹框 -->
+      <!-- <project-dialog
+        :visible.sync="projectdDialogVisible"
+        :id="pageData.id"
+        :projectObj="projectObj"
+        :isCopy="false"></project-dialog> -->
       <ElImageViewer
         v-if="showViewer"
         :on-close="closeViewer"
@@ -460,13 +453,10 @@ export default {
         { prop: '反馈详情', type: 'textarea' },
       ],
       rules: {
-        问题类型: [
-          { required: true, message: 'Please select', trigger: 'change' },
-        ],
-        反馈详情: [
-          { required: true, message: 'Please enter', trigger: 'blur' },
-        ],
+        问题类型: [{ required: true, message: 'Please select', trigger: 'change' }],
+        反馈详情: [{ required: true, message: 'Please enter', trigger: 'blur' }],
       },
+      footprintVisible: false,
     }
   },
   computed: {
@@ -551,9 +541,7 @@ export default {
       if (Array.isArray(printService) && printService.length) {
         printService.forEach(item => {
           if (item.decorationSelectId) {
-            const temp = item.decorationList.filter(
-              i => i.id === item.decorationSelectId
-            )
+            const temp = item.decorationList.filter(i => i.id === item.decorationSelectId)
             result.printService[`${item.id}`] = {
               id: item.decorationSelectId,
               num: temp[0].num,
@@ -561,10 +549,7 @@ export default {
           }
         })
       }
-      localStorage.setItem(
-        `product-user-select-${this.$route.params.code}`,
-        JSON.stringify(result)
-      )
+      localStorage.setItem(`product-user-select-${this.$route.params.code}`, JSON.stringify(result))
     },
     // getStock() {
     //   this.$axios.get('/api/quote/stock_new', { params: {id: this.id} }).then(res => {

+ 14 - 3
components/product/product.scss

@@ -41,8 +41,7 @@ $deep-blue: #004a97;
           cursor: pointer;
           width: 28px;
           height: 28px;
-          box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16),
-            0 1px 2px rgba(0, 0, 0, 0.23);
+          box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 1px 2px rgba(0, 0, 0, 0.23);
           border-radius: 20px;
           transition: all 0.2s;
           img {
@@ -74,9 +73,18 @@ $deep-blue: #004a97;
       }
       .details-1 {
         margin-bottom: 15px;
-        p,
+        p {
+          color: #4a596c;
+          word-break: keep-all;
+          span {
+            color: #444;
+            font-weight: 600;
+          }
+        }
         li {
           color: #4a596c;
+          // white-space: pre-wrap;
+          word-break: keep-all;
         }
         ul {
           padding-left: 20px;
@@ -195,5 +203,8 @@ $deep-blue: #004a97;
     .quote-tips {
       font-size: 16px;
     }
+    .red-text {
+      color: #ef4135;
+    }
   }
 }

+ 6 - 0
mixins/category.js

@@ -455,6 +455,11 @@ export default {
               return b.ranking - a.ranking
             }
           }
+        } else if (
+          this.$route.query.feature &&
+          Number(this.$route.query.feature) === 282) {
+          keyword = 'Carbon Footprint'
+          config.restrictSearchableAttributes = 'filter'
         } else {
           config.restrictSearchableAttributes = 'cat_name'
         }
@@ -523,6 +528,7 @@ export default {
                 console.log('---')
               }
               const result = {
+                ...item,
                 // img: item.img || '',
                 // colour_imgs: item.colour_imgs,
                 price_min: parseFloat(item.price_min),

+ 97 - 11
pages/home/myDetail/components/orderDetailPart.vue

@@ -5,6 +5,23 @@
       v-loading="true"
       class="com-loading"></div>
     <template v-else-if="isLoading == 2">
+      <!-- <div class="eco-tip"  v-if="orderDetail.Emission_Total_Kg && orderDetail.Emission_Total_Kg != '0'">
+        <div class="eco-tip-title">
+          <img
+            src="@/assets/img/esg/leaf.png"
+            alt="eco"
+            class="eco-tip-icon" />
+          <span> Protecting Nature Starts with Your Choice</span>
+        </div>
+        <div class="eco-tip-desc">
+          Your Eco-Friendly Purchase Generated
+          <span class="eco-tip-co2"
+            >{{ orderDetail.Emission_Total_Kg || 0 }} KG</span
+          >
+          Of Carbon Emissions. Together, We<br />
+          Embrace Enyironmental Responsibility For A More Sustainable Future.
+        </div>
+      </div> -->
       <section class="main-header">
         <div class="main-header-mid flex between">
           <h1>Job Name:{{ orderDetail.Sales_Order_Title_Job_Name }}</h1>
@@ -13,14 +30,21 @@
             class="user_logo"
             v-if="orderDetail.user_logo" />
         </div>
-        <div class="main-header-mid flex between">
+        <div class="main-header-mid">
           <ul class="left">
             <li
-              class="left-i"
-              @click="shareDialogVisible = true"
+              class="left-i link-div"
               v-if="isShow">
-              <i class="el-icon-share"></i>
-              <span>Client Tracking Share</span>
+              <div @click="shareDialogVisible = true">
+                <i class="el-icon-share"></i>
+                <span>Client Tracking Share</span>
+              </div>
+              <!-- <div v-for="(item) in orderDetail.crm_esg_res?.flat()"
+              @click="downloadEsg(item)" 
+              :key="item.id">
+                <img src="@/assets/img/order/cer.png" />
+                <span> DownLoad {{ item.name }}</span>
+              </div> -->
             </li>
             <li
               class="left-i"
@@ -252,6 +276,10 @@
             min-width="300">
             <template slot-scope="scope">
               <p class="colorBlue">{{ scope.row.product_name }}</p>
+              <!-- <p class="table-list-co2" v-if="scope.row.Emision_Details_value && scope.row.Emision_Details_value != '0'">
+                  <img src="@/assets/img/esg/co2_green.png" alt="CO2" class="co2-icon" />
+                  <span>{{ scope.row.Emision_Details_value }} kg CO₂e</span>
+                </p> -->
               <p v-html="scope.row.product_description"></p>
               <!-- <p :class="scope.row.showMore?'ellipsis':''" v-html="scope.row.product_description"></p>
                     <p class="colorBlue cursor" @click="toggleShow(scope.row)" v-if="scope.row.product_description">{{scope.row.showMore?'Show More':'Conceal'}}<i  :class="scope.row.showMore?'el-icon-caret-bottom':'el-icon-caret-top'"></i></p> -->
@@ -344,13 +372,17 @@
             </tr>
           </table>
         </div>
-        <template v-if="isShow">
-          <p class="notes-1">Notes</p>
-          <p class="notes-2">Terms & conditions</p>
-          <p class="notes-2">Artwork Approval</p>
-          <p class="notes-3">{{ orderDetail.Subject }}</p>
-        </template>
       </section>
+      <!-- <section 
+        v-if="orderDetail.Order_Stage === 'Sales Order Created'" style="text-align: right;border: none;">
+        <el-button
+        v-if="orderDetail.Order_Stage === 'Sales Order Created'"
+        @click="openApproved(orderDetail)"
+        size="small"
+        style="background-color: rgb(0, 33, 59); color: #fff;"
+        plain
+        >Approved</el-button>
+      </section> -->
     </template>
     <div v-else>
       <el-empty description="No Data"></el-empty>
@@ -558,6 +590,60 @@ export default {
       this.Tracking_URL = url
       this.urlDialogShow = true
     },
+    download(url) {
+      var urlStr = url.match('[^/]+(?!.*/)')[0]
+      this.$utils.downloadBlob(url, urlStr)
+    },
+    downloadEsg(item) {
+      if (!item.id) {
+        this.$message.error('No report available for download')
+        return
+      }
+
+      this.$axios
+        .post('Crmdata/downloadreport', { id: item.id, name: item.name })
+        .then(res => {
+          if (res.result) {
+            this.$utils.downloadBlob(
+              res.result?.data,
+              decodeURIComponent(res.result?.url_name)
+            )
+          } else {
+            this.$message.error('Download failed, please try again later')
+          }
+        })
+        .catch(() => {
+          this.$message.error('Download failed, please try again later')
+        })
+    },
+    openApproved(row) {
+      this.$confirm(
+        `
+        <div style="text-align:center;">
+          <h3 style="margin:0 0 10px;color:#333;">Ready to order?</h3>
+          <p style="margin:0;font-size:16px;color:#333;">Your total is <b>${this.transformNumber(
+            row.Grand_Total
+          )}</b>. Confirm to place your order.</p>
+        </div>
+        `,
+        '',
+        {
+          dangerouslyUseHTMLString: true,
+          confirmButtonText: 'Confirm',
+          cancelButtonText: 'Cancel',
+          confirmButtonClass: 'el-button',
+          cancelButtonClass: 'el-button--info',
+          center: true,
+          showClose: false,
+          confirmButtonClass: 'com-btnblack',
+        }
+      ).then(() => {
+        this.$router.push({
+          path: '/so-confirm',
+          query: { id: row.sales_orders_id, pc_psw: row.HASH },
+        })
+      })
+    },
   },
 }
 </script>

+ 82 - 3
pages/home/myDetail/detail.scss

@@ -13,6 +13,45 @@
     margin-top: 23px;
     padding: 0 20px;
   }
+  .eco-tip {
+    background: #f7fbff;
+    border-radius: 10px;
+    padding: 28px 0 18px 0;
+    margin: 24px 0 18px 0;
+    text-align: center;
+    box-sizing: border-box;
+    .eco-tip-title {
+      font-size: 26px;
+      font-weight: bold;
+      color: #FF3F0B;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 10px;
+      .eco-tip-icon {
+        width: 40px;
+        height: 40px;
+        margin-right: 8px;
+        vertical-align: middle;
+      }
+    }
+    .eco-tip-desc {
+      font-size: 22px;
+      color: #102f47;
+      font-weight: 500;
+      line-height: 2;
+      .eco-tip-co2 {
+        color: #19b94a;
+        font-weight: bold;
+        font-size: 24px;
+      }
+      .eco-tip-tree {
+        color: #19b94a;
+        font-weight: bold;
+        font-size: 24px;
+      }
+    }
+  }
   section {
     width: 100%;
     max-width: 1300px;
@@ -38,12 +77,23 @@
       .left {
         font-size: 20px;
         align-self: flex-start;
+        .link-div{
+          div {
+            display: inline-block;
+            margin-right: 10px;
+            margin-bottom: 10px;
+            img{
+              vertical-align: middle;
+              width: 20px;
+            }
+          }
+        }
         li {
           i {
             vertical-align: middle;
           }
           span {
-            color: #1890ff;
+            color: #1D4992;
             cursor: pointer;
           }
         }
@@ -170,6 +220,22 @@
   .colorBlue {
     color: #1890ff;
   }
+  .table-list-co2{
+    display: inline-flex;
+    align-items: center;
+    background: #f4fcf6;
+    border: 2px solid #7ed7a5;
+    border-radius: 4px;
+    padding: 1px 6px;
+    font-weight: bold;
+    color: #07A73A;
+    font-size: 12px;
+    .co2-icon {
+      width: 18px;
+      height: 18px;
+      margin-right: 4px;
+    }
+  }
   .ellipsis {
     text-overflow: ellipsis;
     overflow: hidden;
@@ -191,8 +257,21 @@
   }
   .notes-2 {
     margin-bottom: 10px;
-    font-size: 14px;
-    font-weight: 600;
+    font-size: 18px;
+    display: flex;
+    align-items: center;
+    img{
+      width: 20px;
+      margin-right: 10px;
+    }
+    i{
+      font-size: 20px;
+    }
+    span{
+      color: #1D4992;
+      cursor: pointer;
+      font-weight: 500;
+    }
   }
   .notes-3 {
     width: 70%;

+ 93 - 4
pages/home/myDetail/index.vue

@@ -145,6 +145,7 @@
             </el-input>
           </div>
           <el-table
+            class="table-order-list"
             :data="enquiryList"
             stripe
             style="width: 100%"
@@ -317,14 +318,26 @@
             >
           </div>
           <el-table
+            class="table-order-list"
             :data="tableData"
             v-loading="tableLoading"
             stripe
-            style="width: 100%"
-            :header-cell-style="{ background: '#00213b', color: '#ffffff' }">
+            :header-cell-style="{ background: '#00213b', color: '#ffffff' }"
+            style="width: 100%">
             <el-table-column
               prop="Sales_Order_Title_Job_Name"
               label="Job Name">
+              <template slot-scope="scope">
+                <p class="table-list-p1">
+                  {{ scope.row.Sales_Order_Title_Job_Name }}
+                </p>
+                <!-- <p class="table-list-co2" v-if="scope.row.Emission_Total_Kg && scope.row.Emission_Total_Kg != '0'">
+                  <img src="@/assets/img/esg/co2_green.png" alt="CO2" class="co2-icon" />
+                  <span>{{ scope.row.Emission_Total_Kg }} kg CO₂e</span>
+                </p> 
+                <p class="table-list-p2">Brand Name:{{ scope.row.Brand_Name }}</p>
+                <p class="table-list-p2">ETA:{{ $utils.formatTime(scope.row.Expected_Delivery_Date,'DD/MM/YYYY') }}</p> -->
+              </template>
             </el-table-column>
             <el-table-column
               width="100"
@@ -376,13 +389,29 @@
             </el-table-column>
             <el-table-column
               label="Action"
-              width="80"
+              width="100"
               align="center">
               <template slot-scope="scope">
+                <!-- <el-button
+                  v-if="scope.row.Order_Stage_new === 'Sales Order Created'"
+                  @click="openApproved(scope.row)"
+                  size="small"
+                  style="
+                    background-color: rgb(0, 33, 59);
+                    color: #fff;
+                    width: 85px;
+                  "
+                  plain
+                  >Approved</el-button> -->
                 <el-button
                   @click="goOrderDetail(scope.row)"
                   size="small"
-                  style="background-color: rgb(0, 33, 59); color: #fff"
+                  style="
+                    background-color: rgb(0, 33, 59);
+                    color: #fff;
+                    width: 85px;
+                    margin: 0;
+                  "
                   plain
                   >View</el-button
                 >
@@ -714,6 +743,34 @@ export default {
       })
       window.open(routeUrl.href, '_blank')
     },
+    openApproved(row) {
+      this.$confirm(
+        `
+        <div style="text-align:center;">
+          <h3 style="margin:0 0 10px;color:#333;">Ready to order?</h3>
+          <p style="margin:0;font-size:16px;color:#333;">Your total is <b>${this.transformNumber(
+            row.Grand_Total
+          )}</b>. Confirm to place your order.</p>
+        </div>
+        `,
+        '',
+        {
+          dangerouslyUseHTMLString: true,
+          confirmButtonText: 'Confirm',
+          cancelButtonText: 'Cancel',
+          confirmButtonClass: 'el-button',
+          cancelButtonClass: 'el-button--info',
+          center: true,
+          showClose: false,
+          confirmButtonClass: 'com-btnblack',
+        }
+      ).then(() => {
+        this.$router.push({
+          path: '/so-confirm',
+          query: { id: row.sales_orders_id, pc_psw: row.HASH },
+        })
+      })
+    },
     getEnquiryList() {
       this.tableLoading = true
       this.$axios
@@ -935,7 +992,39 @@ export default {
         }
       }
     }
+    .table-order-list {
+      width: 100%;
+      border: 1px solid #c2c2c2;
+      .table-list-p1 {
+        font-weight: 600;
+        color: #333;
+        font-size: 16px;
+      }
+      .table-list-p2 {
+        font-size: 14px;
+      }
+      .table-list-co2 {
+        display: inline-flex;
+        align-items: center;
+        background: #f4fcf6;
+        border: 2px solid #7ed7a5;
+        border-radius: 4px;
+        padding: 1px 6px;
+        font-weight: bold;
+        color: #07a73a;
+        font-size: 12px;
+        .co2-icon {
+          width: 18px;
+          height: 18px;
+          margin-right: 4px;
+        }
+      }
+    }
     .upload-item {
+      position: absolute;
+      right: 50px;
+      top: 0;
+      z-index: 2;
       .el-form-item__content {
         z-index: 1;
       }