Bladeren bron

feat: 联系优化
1. 产品页面添加购买联系弹窗
2. 将部分数据配置为可自定义更改
3. 优化渲染产品页面下的样式

kindring 1 jaar geleden
bovenliggende
commit
f146640591

+ 3 - 1
assets/productList.css

@@ -3,6 +3,7 @@
   flex-direction: column;
   box-sizing: border-box;
   align-items: center;
+
 }
 .product{
   display: flex;
@@ -28,9 +29,10 @@
 @media screen and (min-width: 1024px) {
   .productCenter{
     display: grid;
-    grid-template-columns: repeat(4,365px);
+    grid-template-columns: repeat(auto-fill, 365px);
     grid-gap: 25px;
     box-sizing: border-box;
+    justify-content: center;
   }
   .product{
     display: block;

+ 27 - 48
components/newCenter.vue

@@ -1,24 +1,24 @@
 <template>
-  <div class="w-screen pad:w-full">
+  <div class="newCenter pad:w-full">
     <big-title>{{lang===langType.cn?"新闻中心":getAbbrText("新闻中心")}}</big-title>
     <div class="container mx-auto newView">
       <a
         v-for="(news,i) in newArr"
         :key="news.key"
-        :href="news.src"
+        :href="`/news/${news.key}/${news.id}`"
         :class="`newChunk chunk${i}`">
         <span class="imgBox" v-if="news.img">
-          <img :src="news.img" alt=""/>
+          <img :src="imagePathBabel(news.img)" alt=""/>
         </span>
         <p class="newsContext">
           <span class="newsType">
-            <span>{{getNewsTypeStr(news.type)}}</span>
+            <span>{{news.type_name}}</span>
           </span>
           <span class="title">
-            {{lang===langType.cn?news.title:getLangText(news.title)}}
+            {{lang===langType.cn?news.title:news.title_en||news.title}}
           </span>
           <span class="description">
-            {{lang===langType.cn?news.description:getLangText(news.description)}}
+            {{lang===langType.cn?news.remark:news.remark_en||news.remark}}
           </span>
           <span class="time">
             {{news.time}}
@@ -37,6 +37,7 @@ import langMap from "@/map/langMap";
 import {hrefs} from "@/map/hrefMap";
 import {newsType,getNewsTypeStr} from "@/map/newMap";
 import BigTitle from "~/components/public/bigTitle.vue";
+import {imagePathBabel} from "@/tools/imagePath";
 
 export default {
   name: "newCenter",
@@ -51,52 +52,26 @@ export default {
       langType: langMap.lang,
       hrefs: hrefs,
       newsType: newsType,
-      newArr:[
-        {
-          key: 'one',
-          title: "智慧能源解决方案",
-          img: 'image/showing/fire_s.jpg',
-          type: 2,
-          description: "目前家庭光伏电站的运行维护主要基于对逆变器的监控,那么主流监控模式有哪些呢?小编带你逐一分解",
-          src: '/solution',
-          time: '2023-04-02',
 
-        },
-        {
-          key: 'two',
-          title: "解锁家庭光伏电站监控全姿势",
-          type: 2,
-          description: "目前家庭光伏电站的运行维护主要基于对逆变器的监控,那么主流监控模式有哪些呢?小编带你逐一分解",
-          src: '/solution',
-          time: '2022-01-02'
-        },
-        {
-          key: 'three',
-          title: "G8100 4G低功耗LTE无线模块简介",
-          type: 2,
-          description: "工业级高性能、高通平台,超低功耗,多种无线通信方式,丰富的I/O接口",
-          src: '/solution',
-          time: '2021-11-30'
-        },
-        {
-          key: 'four',
-          title: "ETC停车场的发展前景",
-          type: 3,
-          description: "1.无需人值守降低人工成本;2.非现金支付,杜绝跑冒滴漏;3.集中式管理,财务一目了然;4.无缝对接各类基于ETC的应用系统;5.兼容全国高速公路,ETC收费系统;6.不停车通行,提升通行效率;",
-          src: '/news/info/pa?id=47',
-          time: '2022-09-20'
-        },{
-          key: 'five',
-          title: "森林防火4G摄像机视频监控解决方案",
-          type: 1,
-          description: "采用4G摄像机4G高清网络摄像机或4G高清视频服务器+摄像头组合,将监控点附近的相关视频实时回传至监控中心,林区负责人或监管部门可实时了解林区状态,如有隐患或火灾,可第一时间发现并采取相应措施。\n" ,
-          src: '/solution/info/sol?id=49',
-          time: '2022-01-02'
-        }
-      ]
+    }
+  },
+  computed: {
+    newArr(){
+      let arr = this.$store.getters.platform.news;
+      console.log(arr)
+      return arr.map((item,i)=>{
+         let res = {
+           ...item
+         }
+         if(i === 0){
+           res.img = res.image;
+         }
+        return res
+      })
     }
   },
   methods:{
+    imagePathBabel,
     getLangText(str) {
       return langMap.getText(this.lang, str);
     },
@@ -114,6 +89,10 @@ export default {
 </script>
 
 <style scoped>
+.newCenter{
+  width: calc(100vw - 20px);
+  margin: 0 auto;
+}
 .newView{
   display: flex;
   align-items: center;

+ 116 - 1
components/product/productInfo.vue

@@ -67,7 +67,7 @@ export default {
       if(this.unescape){
         data.detail = unescapeHtml(data.detail);
         data.overview = unescapeHtml(data.overview);
-        data.paramter = unescapeHtml(data.paramter);
+        data.parameter = unescapeHtml(data.parameter);
       }
 
       data.add_time = timestampToTime(data.add_time);
@@ -345,4 +345,119 @@ h1{
 }
 
 
+
+
+</style>
+
+<style>
+
+/** table style */
+.table {
+  background: white;
+  border-radius:3px;
+  border-collapse: collapse;
+  padding:5px;
+  width: auto;
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
+  animation: float 5s infinite;
+}
+th {
+  color:#D5DDE5;;
+  background:#1b1e24;
+  border-bottom:4px solid #9ea7af;
+  border-right: 1px solid #343a45;
+  font-size:23px;
+  font-weight: 100;
+  padding:24px;
+  text-align:left;
+  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+  vertical-align:middle;
+}
+
+th:first-child {
+  border-top-left-radius:3px;
+}
+
+th:last-child {
+  border-top-right-radius:3px;
+  border-right:none;
+}
+
+tr {
+  border-top: 1px solid #C1C3D1;
+  border-bottom-: 1px solid #C1C3D1;
+  color:#666B85;
+  font-size:16px;
+  font-weight:normal;
+  text-shadow: 0 1px 1px rgba(256, 256, 256, 0.1);
+}
+
+tr:hover td {
+  background:#4E5066;
+  color:#FFFFFF;
+  border-top: 1px solid #22262e;
+}
+
+tr:first-child {
+  border-top:none;
+}
+
+tr:last-child {
+  border-bottom:none;
+}
+
+tr:nth-child(odd) td {
+  background:#EBEBEB;
+}
+
+tr:nth-child(odd):hover td {
+  background:#4E5066;
+}
+
+tr:last-child td:first-child {
+  border-bottom-left-radius:3px;
+}
+
+tr:last-child td:last-child {
+  border-bottom-right-radius:3px;
+}
+
+td {
+  background:#FFFFFF;
+  padding:20px;
+  text-align:left;
+  vertical-align:middle;
+  font-weight:300;
+  font-size:18px;
+  text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
+  border-right: 1px solid #C1C3D1;
+}
+
+td:last-child {
+  border-right: 0px;
+}
+
+th.text-left {
+  text-align: left;
+}
+
+th.text-center {
+  text-align: center;
+}
+
+th.text-right {
+  text-align: right;
+}
+
+td.text-left {
+  text-align: left;
+}
+
+td.text-center {
+  text-align: center;
+}
+
+td.text-right {
+  text-align: right;
+}
 </style>

+ 6 - 37
components/productCenter.vue

@@ -5,16 +5,17 @@
         <a class="product"
            v-for="(product,i) in products"
            :key="'pro-'+product.key"
+           :href="`/product/${product.key}/${product.id}`"
         >
           <span class="imgBox">
-             <img :src="product.img" :alt="product.title" class="img">
+             <img :src="imagePathBabel(product.image)" :alt="product.name" class="img">
           </span>
           <span class="more">
             {{lang===langType.cn?"了解更多":getAbbrText("了解更多")}}
           </span>
           <p class="product-info">
             <span class="title">
-              {{lang===langType.cn?product.title:getAbbrText(product.title)}}
+              {{lang===langType.cn?product.name:product.name_en||product.name}}
             </span>
             <span class="description" v-if="product.sellPointer">
               <span v-for="sell in product.sellPointer">
@@ -30,6 +31,7 @@
 <script>
 import langMap from "~/map/langMap";
 import BigTitle from "~/components/public/bigTitle.vue";
+import {imagePathBabel} from "@/tools/imagePath";
 
 export default {
   name: "productCenter",
@@ -42,44 +44,11 @@ export default {
   data(){
     return {
       langType: langMap.lang,
-      products:[
-        {
-          title: '20倍自动变焦摄像头',
-          img: 'image/product/20Cam.png',
-          key: 'p1',
-          sellPointer: [
-            '20倍超级变焦',
-            '高清影像',
-            '多种可选倍率'
-          ]
-        },
-        {
-          title: '车牌识别摄像头',
-          key: 'p2',
-          img: 'image/product/car.jpg',
-          sellPointer: [
-            'ai识别',
-            '智能联动',
-          ]
-        },
-        {
-          title: '火情识别摄像头',
-          key: 'p3',
-          img: 'image/product/fire.png',
-          sellPointer: [
-            '烟火识别',
-            '自动巡检',
-          ]
-        },
-        {
-          title: '4G低功耗智能摄像头',
-          key: 'p4',
-          img: 'image/showing/lowCam.jpg'
-        },
-      ]
+      products: this.$store.getters.platform.products
     }
   },
   methods:{
+    imagePathBabel,
     getLangText(str) {
       return langMap.getText(this.lang, str);
     },

+ 3 - 9
components/public/pop.vue

@@ -8,15 +8,9 @@
       v-if="mask"
   ></div>
 
-  <a-spin
-      :spinning="loading"
-      size="large"
-      class="w-full h-full flex justify-center items-center"
-  >
-    <div class="w-full h-full flex justify-center items-center">
-      <slot/>
-    </div>
-  </a-spin>
+  <div class="w-full h-full flex justify-center items-center">
+    <slot/>
+  </div>
 
 </div>
 </template>

+ 9 - 5
components/siteBar.vue

@@ -2,7 +2,7 @@
   <div class="site-bar" v-show="1">
     <div class="btn wechat">
       <svg-icon icon-class="wechat"  />
-      <img class="show-img z-50" :src="wechatSrc" alt="">
+      <img class="show-img z-50" :src="imagePathBabel(platform.wx_qrc)" alt="">
     </div>
     <div class="btn top" @click="toTop" >
       <svg-icon icon-class="top" />
@@ -12,6 +12,8 @@
 
 <script>
 // 网页侧边栏小工具
+import {imagePathBabel} from "@/tools/imagePath";
+
 export default {
   name: "siteBar",
   props:{
@@ -19,9 +21,10 @@ export default {
       type: String,
       default: 'cn'
     },
-    wechatSrc: {
-      type: String,
-      default: ''
+  },
+  data() {
+    return {
+      platform: this.$store.getters.platform
     }
   },
   // 指令
@@ -56,7 +59,8 @@ export default {
         top: 0,
         behavior: "smooth"
       });
-    }
+    },
+    imagePathBabel
   }
 }
 </script>

+ 6 - 2
components/typeEdit.vue

@@ -109,6 +109,8 @@ export default {
     init (title, api, object, queryParams) {
 
       this.api = api
+      console.log('init')
+      console.log(queryParams)
       this.queryParams = queryParams ? queryParams : {}
       if (!api){
         this.$message.error('请设置api地址')
@@ -200,10 +202,12 @@ export default {
           return this.$message.error('参数错误')
       }
       let params = formVerify.getFormData()
+      console.log(this.queryParams)
       params = {
         ...params,
         ...this.queryParams,
       }
+      console.log(params)
       let [err, res] = await handle(axios.post(url, params))
       if(err){
         this.$message.error(`[${this.title}] 失败:${err.message}`)
@@ -212,7 +216,7 @@ export default {
       }
       let result = res.data
       if(result.code !== rCode.OK) {
-        this.$message.error(`[${this.title}] 失败:${res.msg}`)
+        this.$message.error(`[${this.title}] 失败:${result.msg}`)
         return result
       }
       this.$message.success(`[${this.title}] 成功`)
@@ -259,7 +263,7 @@ export default {
                label="类型关键字key">
       <a-tooltip>
         <template slot="title">
-          用于浏览器的搜索关键字, 优化用户访问体验, 禁止重复
+          用于浏览器的搜索关键字, 优化用户访问体验, 禁止重复, 为英文字母
         </template>
         <a-input v-model="formType.type_key.val" placeholder="类型关键字key"></a-input>
       </a-tooltip>

+ 3 - 0
map/apiMap.js

@@ -84,6 +84,9 @@ export const apiMap = {
   newsEdit: {
     path: `/api/news/edit`
   },
+  newsDelete: {
+    path: `/api/news/del`
+  },
   downloads: {
     path: `/api/download/list`
   },

+ 1 - 1
pages/about/index.vue

@@ -122,7 +122,7 @@
     </div>
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 1 - 1
pages/ad/index.vue

@@ -6,7 +6,7 @@
     <showing-ad :lang="lang"/>
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 
 </template>

+ 1 - 1
pages/ad/zhny/index.vue

@@ -8,7 +8,7 @@
     </div>
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 
 </template>

+ 1 - 1
pages/errorPage/404.vue

@@ -12,7 +12,7 @@
     </div>
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 
 </template>

+ 1 - 1
pages/index.vue

@@ -14,7 +14,7 @@
 <!--    页脚 -->
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 1 - 1
pages/manger/news/add.vue

@@ -88,7 +88,7 @@ export default {
 
 
     // 判断是否为编辑文章
-    if(isEmpty(this.article)){
+    if(!isEmpty(this.article)){
       this.isEdit = true;
 
       console.log(this.article);

+ 1 - 0
pages/manger/news/index.vue

@@ -278,6 +278,7 @@ export default {
          class="px-10 h-full ml-5 rounded bg-blue-400 text-white
          cursor-pointer hover:text-orange-500 ">
         文章分类管理</a>
+      <a href="/manger/product/add" class="px-10 h-full ml-5 rounded bg-blue-400 text-white cursor-pointer hover:text-orange-500 ">新增文章</a>
     </rounded-title>
 
     <div class="w-full rounded border mt-2 bg-white p-2">

+ 33 - 1
pages/manger/news/info.vue

@@ -61,6 +61,35 @@ export default {
       }else{
         this.$message.error(`获取文章信息失败,${result.msg}`);
       }
+    },
+    deleteArticle(){
+      this.$confirm({
+        content: '确定要删除吗?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk: () => {
+          this.executeDeleteArticle();
+        }});
+    },
+    async executeDeleteArticle(){
+      let newsId = this.newsInfo.id;
+      if (!newsId)
+        return this.$message.error('未获取到文章id');
+      let url = apiMap.newsDelete.path;
+      url += `?id=${newsId}`
+      let [err,res] = await handle(this.$axios.delete(url, {id: newsId}));
+      if(err){
+        this.$message.error(`[删除文章] 失败:${err.message}`)
+        console.log(err)
+        return err
+      }
+      let result = res.data
+      if(result.code !== rCode.OK) {
+        this.$message.error(`[删除文章] 失败:${result.msg}`)
+        return result
+      }
+      this.$message.success(`[删除文章] 成功`)
+      window.location.href = "/manger/news";
     }
   }
 }
@@ -68,7 +97,7 @@ export default {
 
 <template>
   <div class="w-full p-2">
-    <rounded-title class="text-xl">
+    <rounded-title class="text-xl flex align-items justify-around">
       <div>
         <span>文章详情</span>
         <a href="/manger/news"
@@ -79,6 +108,9 @@ export default {
       <a
         :href="editUrl"
         class="edit-btn custom-btn btn-13">编辑</a>
+      <a-button @click="deleteArticle">
+        <a-icon type="delete" />
+      </a-button>
     </rounded-title>
     <div class="page-content-box w-full mt-2 p-0.5  rounded bg-white">
       <div class="page-title">{{newsInfo.title}}</div>

+ 3 - 2
pages/manger/news/type.vue

@@ -116,6 +116,7 @@ export default {
       this.opentypeEdit();
       this.$nextTick(() => {
         this.$refs.type_edit.init("文章类型", apiMap.addNewsType.path,
+          null,
           {
             parent_type: this.parentType,
           })
@@ -165,7 +166,7 @@ export default {
       this.getTypes();
     },
     async executeDeleteType(item){
-      let url = apiMap.productDeleteType.path;
+      let url = apiMap.deleteNewsType.path;
       url += `?id=${item.type_id}`
       let [err,res] = await handle(axios.delete(url, {id: item.type_id}));
       if(err){
@@ -252,7 +253,7 @@ export default {
         <template slot="close-group">
           <a-button type="danger" @click="handleCloseEdit">关闭</a-button>
         </template>
-        <type-edit ref="type_edit" @close="handleCloseEdit"></type-edit>
+        <type-edit ref="type_edit"  @close="handleCloseEdit"></type-edit>
       </pop-card>
     </pop>
   </div>

+ 4 - 3
pages/manger/product/index.vue

@@ -9,6 +9,7 @@ import {isEmpty} from "../../../until/typeTool";
 import TableSelect from "../../../components/public/tableSelect.vue";
 import dbField_esm from "../../../map/dbField_esm";
 import ImageViewer from "../../../components/public/imageViewer.vue";
+import {imagePathBabel} from "@/tools/imagePath";
 
 const productColumns = [
   {
@@ -192,9 +193,8 @@ export default {
       let type = this.productTypes.find(item=>item.key === key);
       return type ? type.text : '';
     },
-    imagePathBabel(text){
-      return text?text.charAt(0) == '/'? text : '/public/'+text : ''
-    }
+    imagePathBabel,
+
 
   }
 }
@@ -205,6 +205,7 @@ export default {
     <rounded-title class="text-xl">
       <span>产品管理,产品中心</span>
       <a href="/manger/product/type" class="px-10 h-full ml-5 rounded bg-blue-400 text-white cursor-pointer hover:text-orange-500 ">产品分类管理</a>
+      <a href="/manger/product/add" class="px-10 h-full ml-5 rounded bg-blue-400 text-white cursor-pointer hover:text-orange-500 ">新增产品</a>
     </rounded-title>
 
     <div class="w-full rounded border mt-2 bg-white p-2">

+ 1 - 1
pages/manger/product/info.vue

@@ -15,7 +15,7 @@ export default {
       loading: false,
       productInfo: {},
       // 英文的产品信息
-      productId: '',
+      productId: 0,
       lang: langMap.lang.zh,
       showImage: ''
     }

+ 1 - 1
pages/news/index.vue

@@ -8,7 +8,7 @@
 
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 1 - 1
pages/news/info/index.vue

@@ -21,7 +21,7 @@
 
     </div>
     <default-footer :lang="lang"/>
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 1 - 1
pages/product/index.vue

@@ -217,7 +217,7 @@ export default {
     <page-select :page="page" :count="nowCount" :total="nowTotal"></page-select>
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 91 - 8
pages/product/info/index.vue

@@ -13,15 +13,33 @@
 <!--    页脚 -->
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
 
 
     <pop :show="buyShow" :loading="buyLoading"
     >
-      <div class="product-show">
-        <div class="absolute top-0 right-0 p-2 text-red-500 text-xl">
-          <a-icon type="close" @click="cancelBuy"/>
+      <div class="product-buy">
+        <div class="product-buy-con">
+          <big-title>
+            <span>{{productDetail.name}}</span>
+          </big-title>
+          <div class="buy-fn" v-if="productDetail.shop_addr||platform.shop_addr">
+            <div class="fn-name">网店购买</div>
+            <div class="fn-show">
+              <a :href="productDetail.shop_addr?productDetail.shop_addr:platform.shop_addr" trget="_blank">打开网店</a>
+            </div>
+          </div>
+          <div class="buy-fn">
+            <div class="fn-name">联系销售</div>
+            <div class="fn-show">
+              <img class=" wx-qrc z-50" :src="imagePathBabel(platform.wx_qrc)" alt="销售微信">
+            </div>
+          </div>
         </div>
+        <div class="close-btn" @click="cancelBuy">
+          <svg-icon icon-class="close" />
+        </div>
+
       </div>
     </pop>
   </div>
@@ -44,10 +62,12 @@ import {apiMap, baseUrl} from "~/map/apiMap";
 import BigTitle from "~/components/public/bigTitle.vue";
 import {toNumber,isEmpty} from "../../../until/typeTool";
 import Pop from "@/components/public/pop.vue";
+import ImageViewer from "@/components/public/imageViewer.vue";
+import {imagePathBabel} from "@/tools/imagePath";
 
 export default {
   name: "itemIndex",
-  components: {Pop, BigTitle, ItemBanner, LucencyHeader, DefaultFooter, qTab},
+  components: {ImageViewer, Pop, BigTitle, ItemBanner, LucencyHeader, DefaultFooter, qTab},
   props:['uLang','pType', 'pInfo'],
   head() {
     let headInfo = {
@@ -147,6 +167,10 @@ export default {
       if(!resultType.sub_text) resultType.sub_text = type.sub_text;
       resultType.type_key = type.type_key;
       return resultType;
+    },
+    platform(){
+      let info = this.$store.getters.platform;
+      return info
     }
   },
 
@@ -169,6 +193,7 @@ export default {
 
   },
   methods:{
+    imagePathBabel,
     getLangText(str) {
       return langMap.getText(this.lang, str);
     },
@@ -280,12 +305,70 @@ export default {
 }
 
 
-.product-show{
-  width: 80%;
-  height: calc(100% - 50px);
+.product-buy{
+  width: 70%;
+  max-width: 1200px;
+  height: calc(100% - 260px);
   overflow: auto;
   background-color: #fff;
   border-radius: 10px;
   position: relative;
+  padding: 10px;
+}
+.close-btn{
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  cursor: pointer;
+  color: #fff;
+  font-size: 1.6rem;
+  transition: all 0.3s;
+  background-color: orangered;
+  border-radius: 50%;
+  box-shadow: 0 0 5px gainsboro;
+  width: 30px;
+  height: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.product-buy-con{
+  width: 100%;
+  height: 100%;
+  position: relative;
+  overflow: hidden;
+}
+.buy-fn{
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  margin-top: 10px;
+}
+.buy-fn:nth-child(1){
+  margin-top: 0;
 }
+.buy-fn .fn-name{
+  width: 120px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+}
+.buy-fn .fn-show{
+  width: calc(100% - 130px);
+  height: auto;
+  max-height: 260px;
+  overflow: auto;
+  box-sizing: border-box;
+  padding: 5px;
+  border-left: 1px solid gainsboro;
+  margin-left: 10px;
+}
+.wx-qrc{
+  width: 220px;
+  height: 220px;
+}
+
+
+
 </style>

+ 1 - 1
pages/solution/index.vue

@@ -9,7 +9,7 @@
 
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 2 - 1
pages/solution/info/index.vue

@@ -21,7 +21,7 @@
     </div>
     <default-footer :lang="lang"/>
 
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 
@@ -111,6 +111,7 @@ export default {
       desc: '',
       enDesc: '',
       seo_key: '',
+
       langType: langMap.lang,
       lang: this.uLang?this.uLang:langMap.lang.cn,
       solutionId: this.pId,

+ 1 - 1
pages/support/index.vue

@@ -13,7 +13,7 @@
       </q-tab>
     </div>
     <default-footer :lang="lang"></default-footer>
-    <site-bar wechat-src="/image/wechat.jpg"></site-bar>
+    <site-bar></site-bar>
   </div>
 </template>
 

+ 11 - 3
server/control/c_base.js

@@ -297,9 +297,11 @@ async function deleteFile(fileId){
 
 async function getBaseData(){
   // 同时获取所有需要获取的基础数据
-  let err,pType,nType,carousel;
+  let err,pType,nType,carousel,baseInfo,products,articles;
   // todo 同时获取所有需要获取的基础数据
-  [err, baseInfo, pType, nType, carousel] = await handleAll(
+  [err, products, articles, baseInfo, pType, nType, carousel] = await handleAll(
+    d_product.searchProducts('array', {}, '', 1, 4),
+    d_news.searchAllNewsMini('array', {}, '', 1, 5),
     d_base.getBaseInfo(),
     d_product.loadTypes(),
     d_news.loadTypes(),
@@ -309,9 +311,13 @@ async function getBaseData(){
     log.error(`[基础数据] 获取基础数据类型分类失败 ${err.message}`);
     return [{eCode: codeMap.ServerError, eMsg: `获取基础数据失败`}, null];
   }
+  baseInfo = baseInfo? baseInfo[0]: {};
+  baseInfo.products = products;
+  baseInfo.news = articles;
+
   // 合并数据
   let baseData = {
-    baseInfo: baseInfo? baseInfo[0]: {},
+    baseInfo,
     pType,
     nType,
     carousel,
@@ -323,6 +329,8 @@ async function getBaseData(){
   });
   // todo 缓存接口数据
   log.info(`[基础数据] 类型分类获取成功
+                展示程序数据数量:${products.length}
+                展示文章数据数量:${articles.length}
                 程序类型数量:${pType.length}
                 文章类型数量:${nType.length}
                 轮播数据数量:${carousel.length}

+ 47 - 11
server/control/c_news.js

@@ -7,6 +7,7 @@ const d_news = require("../database/d_news");
 const d_product = require("../database/d_product");
 const {filePathToUrl} = require("../tools/filePathTool");
 const dbField = require("../map/dbField");
+const typeTool = require("../tools/typeTool_cjs");
 
 async function addReadNum(newId){
   let [err,res] = await handle(d_news.addReadNum(newId));
@@ -103,6 +104,32 @@ async function editArticle(article){
   return [null, res];
 }
 
+async function delArticle(id){
+  let [err, res] = await handle(d_news.getMiniNewsById(id));
+  if(err){
+    log.error(`[删除文章] 获取文章失败 ${err.message}`);
+    return [{
+      code: codeMap.ServerError,
+      message: `服务器错误,获取文章失败`
+    }, null];
+  }
+  if(res.length === 0){
+    log.error(`[删除文章] 文章不存在`);
+    return [{
+      code: codeMap.NotFound,
+      message: `文章不存在`
+    }, null];
+  }
+  [err, res] = await handle(d_news.delArticle(res[0].id));
+  if(err){
+    log.error(`[删除文章] 删除文章失败 ${err.message}`);
+    return [{
+      code: codeMap.ServerError,
+      message: `[服务器异常] 获取文章类型失败`
+    }, null];
+  }
+  return [null, res];
+}
 async function getArticleTypes(){
   [err, res] = await handle(d_news.loadTypes());
   if(err){
@@ -123,11 +150,14 @@ async function editType( id, articleType)
     return [err,null];
   }
   if(res.length){
-    return [
-      {
-        eCode:codeMap.DataRepeat,
-        eMsg:`类型关键字重复`
-      },null]
+    let nowType = res.find(item => typeTool.toNumber(item.type_id) === typeTool.toNumber(id))
+    if(!nowType){
+      return [
+        {
+          eCode:codeMap.DataRepeat,
+          eMsg:`类型关键字重复`
+        },null]
+    }
   }
   [err,res] = await handle(d_news.editArticleType(id, articleType));
   if(err){
@@ -136,11 +166,12 @@ async function editType( id, articleType)
   return [null,res];
 }
 
-async function addType( id, articleType)
+async function addType( articleType)
 {
   // 数据校验
-  let parentType = articleType.parentType;
-  if(parentType !== dbField.db_base.newsType.solution ||
+  let parentType = articleType.parent_type;
+  parentType = typeTool.toNumber(parentType);
+  if(parentType !== dbField.db_base.newsType.solution &&
     parentType !== dbField.db_base.newsType.news){
     return [
       {
@@ -161,7 +192,7 @@ async function addType( id, articleType)
       },null]
   }
 
-  [err,res] = await handle(d_news.addArticleType(id, articleType, parentType));
+  [err,res] = await handle(d_news.addArticleType( articleType, parentType));
   if(err){
     return [err,null];
   }
@@ -173,13 +204,17 @@ async function deleteType(id) {
   let err, res;
 
   // 检索产品类型下是否有产品
-  [err, res] = await handle(d_news.getAriticleByTypeId(id));
+  [err, res] = await handle(d_news.getArticleTotalByTypeId(id));
   if (err) {
     // 删除失败
     log.error('[移除文章分类] 寻找文章失败' + err.message);
     return [err, null];
   }
-  if (res.length > 0) {
+  if(!res[0]){
+    log.warn(`未能搜索到数据`)
+  }
+  console.log(res)
+  if (res[0].total > 0) {
     // 存在产品
     log.warn('[移除文章分类] 存在文章,无法删除');
     return [
@@ -200,6 +235,7 @@ module.exports = {
   searchNewsByMini,
   addArticle,
   editArticle,
+  delArticle,
   getArticleTypes,
   editType,
   addType,

+ 9 - 5
server/control/product.js

@@ -4,6 +4,7 @@ const {handle} = require('../tools/handle_cjs');
 const codeMap = require("../map/rcodeMap");
 const log = require("../logger").logger("c_product","info")
 const time = require("../tools/time_cjs")
+const typeTool = require("../tools/typeTool_cjs");
 /**
  * 加载产品
  * @param key 产品类别
@@ -198,11 +199,14 @@ async function editType( id, productType)
     return [err,null];
   }
   if(res.length){
-    return [
-      {
-        eCode:codeMap.DataRepeat,
-        eMsg:`产品类型关键字重复`
-      },null]
+    let nowType = res.find(item => typeTool.toNumber(item.type_id) === typeTool.toNumber(id))
+    if(!nowType){
+      return [
+        {
+          eCode:codeMap.DataRepeat,
+          eMsg:`类型关键字重复`
+        },null]
+    }
   }
   [err,res] = await handle(d_product.editProductType(id, productType));
   if(err){

+ 42 - 7
server/database/d_news.js

@@ -19,6 +19,10 @@ function getTypeByKey(key){
   let sql = `SELECT * FROM hfy_news_type WHERE type_key = ? limit 1`;
   return mysql.pq(sql,[key]);
 }
+function getTypeById(id){
+  let sql = `SELECT * FROM hfy_news_type WHERE type_id = ? limit 1`;
+  return mysql.pq(sql,[id]);
+}
 
 
 
@@ -30,10 +34,14 @@ function searchAllNewsMini(type='array',searchParam,sort,page,limit){
     sql = `select count(*) as total `;
   }else{
     sql = `select
-    news.id as id ,
-    news.title as name,
-    n_type.type_key
-    `;
+    news.id ,
+    news.title,
+    news.remark ,
+    news.author,
+    news.image,
+    news.date_time ,
+    n_type.type_name,
+    n_type.type_key`;
   }
   sql += `
    from
@@ -48,6 +56,7 @@ function searchAllNewsMini(type='array',searchParam,sort,page,limit){
     sql += ` and n_type.type_key = ?`
     values.push(searchParam.type)
   }
+  sql += ` order by news.sort DESC , news.date_time DESC`
   return searchSql(mysql.pq,type,sql,values,limit,page);
 }
 
@@ -56,6 +65,25 @@ function getNewsById(id){
   return mysql.pq(sql,[id]);
 }
 
+function getMiniNewsById(id){
+  let sql = `
+            SELECT
+                news.title, news.id, news.remark, news.author, news.image, news.date_time,
+                n_type.type_key as type_key
+            FROM
+                hfy_news as news,
+                hfy_news_type as n_type
+            WHERE
+                news.type_id = n_type.type_id
+            and id = ? limit 1`;
+  return mysql.pq(sql,[id]);
+}
+
+function getArticleTotalByTypeId(id){
+  let sql = `SELECT count(*) as total FROM hfy_news WHERE type_id = ?`;
+  return mysql.pq(sql,[id]);
+}
+
 function addArticle(article, typeId){
   let sql = `INSERT INTO hfy_news (title, remark, author, content, type_id, image, date_time) VALUES (?, ?, ?, ?, ?, ?, ?)`;
   let values = [];
@@ -86,7 +114,10 @@ function editArticle(article, typeId){
   return mysql.pq(sql,values);
 }
 
-
+function delArticle(id){
+  let sql = `DELETE FROM hfy_news WHERE id = ? limit 1`;
+  return mysql.pq(sql,[id]);
+}
 
 // 编辑产品类型
 function editArticleType(id, typeChange) {
@@ -133,8 +164,8 @@ function deleteArticleType(id) {
 function addArticleType(type, parentId) {
   let sql =
     `INSERT INTO hfy_news_type (
-date_time, type_name, type_key, type_sort, type_logo, seo_key, sub_text,parent_id)
-VALUES (?, ?, ?, ?, ?, ?, ?)`;
+date_time, type_name, type_key, type_sort, type_logo, seo_key, sub_text, parent_type)
+VALUES (?, ?, ?, ?, ?, ?, ?, ?)`;
   let values = [];
   values.push(time.getUnixTimeStamp());
   values.push(type.type_name);
@@ -153,9 +184,13 @@ module.exports = {
   loadTypes,
   searchAllNewsMini,
   getNewsById,
+  getMiniNewsById,
   getTypeByKey,
+  getTypeById,
   addArticle,
+  getArticleTotalByTypeId,
   editArticle,
+  delArticle,
   editArticleType,
   deleteArticleType,
   addArticleType,

+ 1 - 0
server/database/d_product.js

@@ -126,6 +126,7 @@ function searchProducts(type='array',searchParam,sort,page,limit){
     sql = `select count(*) as total `;
   }else{
     sql = `select
+    p.proid,
     p.proid as id,
     p.remark,p.name,
     p.image,p.source,

+ 18 - 0
server/router/r_news.js

@@ -135,6 +135,24 @@ router.post('/edit',async(req,res)=>{
   }
 });
 
+router.delete('/del', checkLogin(progressField.session_hfy), async(req,res)=>{
+  try{
+    let err, result;
+    let id = req.query.id;
+    id = typeTool.toNumber(id);
+    console.log(`删除文章`)
+    if(!id){
+      paramFail(res, "id is required");
+      return;
+    }
+    [err, result] = await c.delArticle(id);
+    if(err){ return controlError(res, err, null);}
+    success(res, result);
+  }catch (e) {
+    ServerError(res, null, e.message);
+  }
+})
+
 // 获取文章分类
 router.get('/types', async (req, res) => {
   try{

File diff suppressed because it is too large
+ 45 - 0
sql/site.sql


+ 1 - 0
store/index.js

@@ -77,6 +77,7 @@ export const modules = {
       },
     },
     getters: {
+      platform: state => state.platform,
       pTypes: state => state.pTypes,
       nTypes: state => state.nTypes,
       carousel: state => state.carousel,

+ 3 - 0
tools/imagePath.js

@@ -0,0 +1,3 @@
+export function imagePathBabel(text){
+  return text?text.charAt(0) == '/'? text : '/public/'+text : ''
+}

Some files were not shown because too many files changed in this diff