Browse Source

14.3 init

bding 3 months ago
parent
commit
81d1fed04e

+ 8 - 1
config/config.js

@@ -7,7 +7,8 @@ let baseUrl = "http://8.136.199.33:8500/api",
   reportLinkUrl,
   intemalLinkUrl,
   reportStrategyUrl,
-  ficcReport;
+  ficcReport,
+  pushRulesUrl;
 
 if (env.envVersion === "develop") {
   //开发
@@ -17,6 +18,7 @@ if (env.envVersion === "develop") {
   intemalLinkUrl = "http://xcxh5test.hzinsights.com/xcx_h5/internalDetials";
   reportStrategyUrl = "http://xcxh5test.hzinsights.com/xcx_h5/strategyReport";
   ficcReport = "http://xcxh5test.hzinsights.com/xcx_h5/ficcReportDtl";
+  pushRulesUrl = "http://xcxh5test.hzinsights.com/xcx_h5/pushrulesPages";
 } else if (env.envVersion === "trial") {
   //体验版
 
@@ -35,6 +37,9 @@ if (env.envVersion === "develop") {
   //reportStrategyUrl = "https://details.hzinsights.com/strategyReport"; //生产
 
   ficcReport = "http://xcxh5test.hzinsights.com/xcx_h5/ficcReportDtl";
+
+  pushRulesUrl = "http://xcxh5test.hzinsights.com/xcx_h5/pushrulesPages";
+
 } else if (env.envVersion === "release") {
   //正式版
   baseUrl = "https://cygx.hzinsights.com/api";
@@ -43,6 +48,7 @@ if (env.envVersion === "develop") {
   intemalLinkUrl = "https://details.hzinsights.com/internalDetials"; //生产
   reportStrategyUrl = "https://details.hzinsights.com/strategyReport"; //生产
   ficcReport = "https://details.hzinsights.com/ficcReportDtl";
+  pushRulesUrl = "https://details.hzinsights.com/pushrulesPages";
 
 }
 
@@ -53,4 +59,5 @@ module.exports = {
   reportStrategyUrl,
   intemalLinkUrl,
   ficcReport,
+  pushRulesUrl
 };

+ 80 - 3
pages-purchaser/researchTheme/researchTheme.vue

@@ -12,8 +12,14 @@
           <view style="display: flex" class="text_oneLine hot-new" @click="themeDetails(item, '主题热度榜')">
             <text class="text_oneLine global_title" style="display: inline">{{ item.IndustryName }} </text>
           </view>
-          <view :class="['follw', 'global_content_center', item.IsFollw && 'cancel-follw']" @click="isAttention(item, '主题')">
-            {{ item.IsFollw ? "取消关注" : "+ 关注" }}
+          <view class="item-wrap">
+            <zb-popover placement="bottom-end" :options="actions" theme="dark" ref="Popover1" @handleClick="() => popoverHandleClick(item)" @select="selectOption($event, item)">
+              <view :class="['follw', 'global_content_center']">
+                <image class="follw-image" :src="getDisplayImg(item)"></image>
+
+                {{ getDisplayText(item) }}
+              </view>
+            </zb-popover>
           </view>
         </view>
         <view class="li-item read-more" @click="themeDetails(item, '主题热度榜')">
@@ -59,6 +65,11 @@ export default {
           value: 1,
         },
       ],
+      actions: [
+        { text: "接受推送", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/AcceptBtn.png", key: 0 },
+        { text: "重点关注", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/FocusBtn.png", key: 1 },
+        { text: "不感兴趣", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/uninterestedBtn.png", key: 3 },
+      ], // 动态设置的气泡选项内容
     };
   },
   mixins: [mixinsAuthorTheme],
@@ -80,6 +91,45 @@ export default {
         this.dataList = this.page_no === 1 ? res.Data.List || [] : [...this.dataList, ...res.Data.List];
       }
     },
+    popoverHandleClick(option) {
+      this.actions = [
+        { text: "接受推送", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/AcceptBtn.png", key: 0 },
+        { text: "重点关注", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/FocusBtn.png", key: 1 },
+        { text: "不感兴趣", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/uninterestedBtn.png", key: 3 },
+      ].filter((item) => item.key !== option.FollowType);
+    },
+    async selectOption(e, item) {
+      console.log();
+      if (!e) return;
+      await this.$store.dispatch("showLoginModal");
+      const res = await Reports.reportFllow({ IndustrialManagementId: item.IndustrialManagementId, PageRouter: this.$store.state.pageRouterReport, FollowType: e.key });
+      if (res.Ret === 200) {
+        item.FollowType = res.Data.Status;
+        let content =
+          res.Data.Status == 1
+            ? "请关注【查研观向小助手】公众号及时获取产业内容更新提醒"
+            : res.Data.Status == 0
+            ? "请关注【查研观向小助手】公众号给您推送产业内容更新"
+            : "产业内容更新将不再以公众号消息推送给您";
+        uni.showModal({
+          title: res.Data.Status == 1 ? "已设置为重点关注产业" : "设置成功",
+          content,
+          confirmText: "知道了",
+          confirmColor: "#376CBB",
+          showCancel: false,
+        });
+      }
+    },
+    getDisplayText(item) {
+      return item.FollowType == 1 ? "重点关注" : item.IsFollow == 0 ? "接受推送" : "不感兴趣";
+    },
+    getDisplayImg(item) {
+      return item.FollowType == 1
+        ? "https://hzstatic.hzinsights.com/new_cygx/FocusBtn.png"
+        : item.IsFollow == 0
+        ? "https://hzstatic.hzinsights.com/new_cygx/AcceptBtn.png"
+        : "https://hzstatic.hzinsights.com/new_cygx/uninterestedBtn.png";
+    },
   },
 };
 </script>
@@ -216,8 +266,8 @@ export default {
       color: #fff;
       border-radius: 4rpx;
       font-size: 24rpx;
-      width: 110rpx;
       height: 42rpx;
+      padding: 0 12rpx;
       background-color: $uni-color-new;
     }
     .cancel-follw {
@@ -225,5 +275,32 @@ export default {
       color: $uni-color-new;
     }
   }
+  .bottom-btn-content {
+    padding: 15rpx 30px 30rpx;
+    .opne-content {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      image {
+        width: 24rpx;
+        height: 24rpx;
+      }
+      .content-text {
+        color: #376cbb;
+        margin: 0 5rpx 0 10rpx;
+      }
+      margin-bottom: 15rpx;
+    }
+    .all-setup {
+      .content-text {
+        text-decoration: underline;
+      }
+    }
+  }
+  .follw-image {
+    width: 32rpx;
+    height: 32rpx;
+    margin-right: 10rpx;
+  }
 }
 </style>

+ 8 - 0
pages.json

@@ -269,6 +269,14 @@
             "navigationBarTitleText": "策略系列培训",
             "enablePullDownRefresh": false
           }
+        },
+        {
+        	"path" : "pushrules/pushrules",
+        	"style" : 
+        	{
+        		"navigationBarTitleText" : "推送规则",
+        		"enablePullDownRefresh" : false
+        	}
         }
       ]
     },

+ 2 - 2
pages/reportForm/index.scss

@@ -455,7 +455,7 @@
   text-align: center;
 }
 .follw-image {
-  width: 32rpx;
-  height: 32rpx;
+  width: 40rpx;
+  height: 40rpx;
   margin-right: 10rpx;
 }

+ 115 - 9
pages/reportForm/reportForm.vue

@@ -109,14 +109,16 @@
         <view class="forindustry global_card_content" v-for="item in industryList" :key="item.IndustrialManagementId" @click="goIndustryReport(item.IndustrialManagementId)">
           <image class="image-box" v-if="item.IsNew" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/new_cygx/new_report.png"></image>
           <image class="image-box" v-if="item.IsHot" src="https://hzchart.oss-cn-shanghai.aliyuncs.com/new_cygx/hot_report.png"></image>
+
           <!-- 火锅底料这个位置 -->
           <view class="industry-content">
             <view class="industry-box-left">
-              <image
-                class="follw-image"
-                @click.stop="reportFllow(item.IndustrialManagementId)"
-                :src="item.IsFollow ? 'https://hzchart.oss-cn-shanghai.aliyuncs.com/new_cygx/collected_icon.png' : 'https://hzchart.oss-cn-shanghai.aliyuncs.com/new_cygx/not_collected.png'"
-              ></image>
+              <view class="item-wrap">
+                <zb-popover placement="bottom-start" :options="actions" theme="dark" ref="Popover1" @handleClick="() => popoverHandleClick(item)" @select="selectOption($event, item)">
+                  <image class="follw-image" :src="getDisplayText(item)"></image>
+                </zb-popover>
+              </view>
+
               <view class="global_title">{{ item.IndustryName }} </view>
             </view>
             <view class="ndustry-box-tiem global_content_center">
@@ -147,7 +149,21 @@
             </block>
           </view>
         </view>
-        <u-loadmore :status="status" icon-type="flower" :load-text="loadText" margin-top="20" v-if="totalPage > 1" />
+        <u-loadmore :status="status" icon-type="flower" :load-text="loadText" margin-top="20" v-if="totalPage > 1 && !isShowOpen" />
+        <view class="bottom-btn-content">
+          <view class="opne-content">
+            已为您折叠不感兴趣的产业
+            <view @click="isShowOpenHandler" class="content-text">
+              {{ isShowOpen ? "展开" : "收起" }}
+            </view>
+            <image :src="isShowOpen ?'https://hzstatic.hzinsights.com/yx_xcx/expand_icon.png':'https://hzstatic.hzinsights.com/yx_xcx/collapse_icon.png'"></image>
+          </view>
+          <view class="opne-content all-setup">
+            您也可以
+            <view @click="allSetupHandler" class="content-text"> 批量设置 </view>
+            兴趣度
+          </view>
+        </view>
       </view>
     </view>
     <u-modal
@@ -252,6 +268,13 @@ export default {
       timeLine: [], //时间线数据
       bannerDataList: [],
       bulletinData: {},
+      actions: [
+        { text: "接受推送", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/AcceptBtn.png", key: 0 },
+        { text: "重点关注", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/FocusBtn.png", key: 1 },
+        { text: "不感兴趣", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/uninterestedBtn.png", key: 3 },
+      ], // 动态设置的气泡选项内容
+      isShowOpen: true, // 展开收起
+      page_no_open: 1,
     };
   },
   onLoad(option) {
@@ -397,12 +420,13 @@ export default {
         ChartPermissionId: this.tabAct_id,
         OrderColumn: this.OrderColumn,
         PageSize: this.pageSize,
-        CurrentIndex: this.page_no,
+        CurrentIndex: this.isShowOpen ? this.page_no : this.page_no_open,
+        IsOpen: this.isShowOpen ? 0 : 1,
         DeepCover: this.deepCoverFocus.includes("cover") ? 1 : 0,
         RecommendFocus: this.deepCoverFocus.includes("focus") ? 1 : 0,
       }).then((res) => {
         // this.industryList=res.Data.List
-        this.status = this.page_no < res.Data.Paging.Pages ? "loadmore" : "nomore";
+        this.status = res.Data.Paging.IsEnd ? "nomore" : "loadmore";
         this.totalPage = res.Data.Paging.Pages; //总页数
         if (this.page_no === 1) {
           this.industryList = res.Data.List || [];
@@ -634,6 +658,64 @@ export default {
         url: "/reportPages/selectedBulletin/selectedBulletin",
       });
     },
+    popoverHandleClick(option) {
+      this.actions = [
+        { text: "接受推送", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/AcceptBtn.png", key: 0 },
+        { text: "重点关注", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/FocusBtn.png", key: 1 },
+        { text: "不感兴趣", imgUrl: "https://hzstatic.hzinsights.com/new_cygx/uninterestedBtn.png", key: 3 },
+      ].filter((item) => item.key !== option.FollowType);
+    },
+    async selectOption(e, item) {
+      if (!e) return;
+      await this.$store.dispatch("showLoginModal");
+      const res = await Reports.reportFllow({
+        IndustrialManagementId: item.IndustrialManagementId,
+        FollowType: e.key,
+        PageRouter: "细分产业列表",
+      });
+      if (res.Ret === 200) {
+        item.FollowType = res.Data.Status;
+        let content =
+          res.Data.Status == 1
+            ? "请关注【查研观向小助手】公众号及时获取产业内容更新提醒"
+            : res.Data.Status == 0
+            ? "请关注【查研观向小助手】公众号给您推送产业内容更新"
+            : "产业内容更新将不再以公众号消息推送给您";
+        uni.showModal({
+          title: res.Data.Status == 1 ? "已设置为重点关注产业" : "设置成功",
+          content,
+          confirmText: "知道了",
+          confirmColor: "#376CBB",
+          showCancel: false,
+        });
+      }
+    },
+    getDisplayText(item) {
+      return item.FollowType == 1
+        ? "https://hzstatic.hzinsights.com/new_cygx/FocusIcon.png"
+        : item.IsFollow == 0
+        ? "https://hzstatic.hzinsights.com/new_cygx/AcceptIcon.png"
+        : "https://hzstatic.hzinsights.com/new_cygx/uninterested.png";
+    },
+    // 点击展开收起
+    isShowOpenHandler() {
+      this.isShowOpen = !this.isShowOpen;
+      if (!this.isShowOpen) {
+        this.page_no = 1;
+        this.status = "loading";
+        this.getIndustryList();
+      } else if (this.status === "nomore" || this.isShowOpen) {
+        this.page_no_open = 1;
+        this.status = "loading";
+        this.getIndustryList();
+      }
+    },
+    // 批量设置
+    allSetupHandler() {
+      uni.navigateTo({
+        url: "/reportPages/pushrules/pushrules",
+      });
+    },
   },
   /* 触底 */
   onReachBottom: Throttle(function () {
@@ -641,9 +723,10 @@ export default {
       this.isNum++;
       return;
     }
-    if (this.status === "nomore") return;
+    if (this.status === "nomore" || this.isShowOpen) return;
     this.status = "loading";
     this.page_no++;
+    this.page_no_open++;
     this.tabAct_idTwo != 99999 ? this.getIndustryList() : this.getTimeLineList();
   }),
   /* 下拉刷新 */
@@ -655,6 +738,7 @@ export default {
       this.pageNumFather = null;
       this.page_no = 1;
       this.refresh = true;
+      this.isShowOpen = true;
       this.getIndustryList();
       this.getTradeList();
     }
@@ -863,4 +947,26 @@ export default {
     border-radius: 47rpx;
   }
 }
+.bottom-btn-content {
+  padding: 15rpx 30px 30rpx;
+  .opne-content {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    image {
+      width: 24rpx;
+      height: 24rpx;
+    }
+    .content-text {
+      color: #376cbb;
+      margin: 0 5rpx 0 10rpx;
+    }
+    margin-bottom: 15rpx;
+  }
+  .all-setup {
+    .content-text {
+      text-decoration: underline;
+    }
+  }
+}
 </style>

+ 23 - 0
reportPages/pushrules/pushrules.vue

@@ -0,0 +1,23 @@
+<template>
+  <view>
+    <web-view :src="linkurl"></web-view>
+  </view>
+</template>
+
+<script>
+import { pushRulesUrl } from "@/config/config";
+
+export default {
+  data() {
+    return {};
+  },
+  computed: {
+    linkurl() {
+      return pushRulesUrl + "?token=" + this.$db.get("access_token");
+    },
+  },
+  methods: {},
+};
+</script>
+
+<style></style>

+ 513 - 0
uni_modules/zb-popover/components/zb-popover/zb-popover.vue

@@ -0,0 +1,513 @@
+<template>
+  <view
+    class="zbPopover"
+    :style="{
+      '--theme-bg-color': bgStyleColor,
+    }"
+  >
+    <view @click.stop="handleClick" class="zb-button-popover">
+      <slot></slot>
+    </view>
+    <view class="mask-content" v-if="inited" @click.stop="maskHandler"></view>
+    <view class="zb-popover" v-show="inited" ref="zb-transition" :class="[classes, `zb-popover-${placement}`]" :style="[mergeStyle]" @touchmove="noop">
+      <view
+        class="zb-popover-arrow"
+        :style="[arrowStyle]"
+        :class="[
+          {
+            zb_popper__up: placement.indexOf('bottom') === 0,
+            zb_popper__arrow: placement.indexOf('top') === 0,
+            zb_popper__right: placement.indexOf('right') === 0,
+            zb_popper__left: placement.indexOf('left') === 0,
+          },
+        ]"
+      >
+      </view>
+      <slot name="content">
+        <view
+          :class="[
+            {
+              horizontal__action: actionsDirection === 'horizontal',
+            },
+          ]"
+        >
+          <view
+            @click.stop="actionAction(item)"
+            v-for="(item, index) in options"
+            class="zb-popover__action"
+            :class="[
+              {
+                dark__action: theme === 'dark',
+              },
+            ]"
+            :key="index"
+          >
+            <view class="popover__action_content">
+              <image :src="item.imgUrl"></image>
+              <view class="zb-popover__action-text">{{ item.text }}</view>
+            </view>
+          </view>
+        </view>
+      </slot>
+    </view>
+  </view>
+</template>
+
+<script>
+const tranClass = {
+  enter: "zb-fade-zoom-enter zb-fade-zoom-enter-active",
+  "enter-to": "zb-fade-zoom-enter-to zb-fade-zoom-enter-active",
+  leave: "zb-fade-zoom-leave zb-fade-zoom-leave-active",
+  "leave-to": "zb-fade-zoom-leave-to zb-fade-zoom-leave-active",
+};
+export default {
+  props: {
+    options: {
+      type: Array,
+      default: () => [],
+    },
+    placement: {
+      type: String,
+      default: "bottom-start",
+    },
+    bgColor: {
+      type: String,
+    },
+    // light dark
+    theme: {
+      type: String,
+      default: "light",
+    },
+    // horizontal vertical
+    actionsDirection: {
+      type: String,
+      default: "vertical",
+    },
+  },
+  name: "Popover",
+  watch: {
+    show: {
+      handler(newVal) {
+        newVal ? this.vueEnter() : this.vueLeave();
+      },
+      // 表示同时监听初始化时的props的show的意思
+      immediate: true,
+    },
+  },
+  data() {
+    return {
+      show: false,
+      inited: false, // 是否显示/隐藏组件
+      classes: "", // 应用的类名
+      display: false, // 组件是否展示
+      duration: 100,
+      popoverStyle: {},
+      arrowOldStyle: {},
+    };
+  },
+  computed: {
+    bgStyleColor() {
+      if (this.bgColor) {
+        return this.bgColor;
+      }
+      if (this.theme === "light") {
+        return "white";
+      }
+      if (this.theme === "dark") {
+        return "#4a4a4a";
+      }
+    },
+
+    mergeStyle() {
+      return {
+        transitionDuration: `${this.duration}ms`,
+        transitionTimingFunction: `ease-out`,
+        ...this.popoverStyle,
+      };
+    },
+    arrowStyle() {
+      return {
+        ...this.arrowOldStyle,
+      };
+    },
+  },
+  mounted() {
+    // #ifdef H5
+    window.addEventListener("click", () => {
+      this.show = false;
+    });
+    // #endif
+  },
+  methods: {
+    handleClick() {
+      if (this.show) {
+        this.show = false;
+      } else {
+        this.show = true;
+      }
+      this.$emit("handleClick", this.show);
+    },
+    close() {
+      this.show = false;
+    },
+    actionAction(item) {
+      this.$emit("select", item);
+      this.show = false;
+    },
+    maskHandler() {
+      this.$emit("select");
+      this.show = false;
+    },
+    sleep(value) {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          resolve();
+        }, value);
+      });
+    },
+    vueEnter() {
+      this.inited = true;
+      this.getPosition();
+      this.classes = tranClass.enter;
+      this.$nextTick(async () => {
+        await this.sleep(30);
+        this.classes = tranClass["enter-to"];
+      });
+    },
+    vueLeave() {
+      this.classes = tranClass.leave;
+
+      this.$nextTick(async () => {
+        this.classes = tranClass["leave-to"];
+        await this.sleep(120);
+        this.inited = false;
+      });
+    },
+    // 阻止事件冒泡
+    preventEvent(e) {
+      e && typeof e.stopPropagation === "function" && e.stopPropagation();
+    },
+
+    getPosition() {
+      return new Promise((resolve) => {
+        this.$nextTick(() => {
+          let selectorQuery = uni.createSelectorQuery().in(this).selectAll(".zb-button-popover,.zb-popover");
+          selectorQuery
+            .boundingClientRect(async (data) => {
+              let { left, bottom, right, top, width, height } = data[0];
+              let popoverClientRect = data[1];
+              let popoverStyle = {};
+              let arrowOldStyle = {};
+
+              switch (this.placement) {
+                case "top":
+                  if (popoverClientRect.width > width) {
+                    popoverStyle.left = `-${(popoverClientRect.width - width) / 2}px`;
+                  } else {
+                    popoverStyle.left = `${Math.abs(popoverClientRect.width - width) / 2}px`;
+                  }
+                  popoverStyle.bottom = `${height + 8}px`;
+                  arrowOldStyle.left = popoverClientRect.width / 2 - 6 + "px";
+                  break;
+                case "top-start":
+                  popoverStyle.left = `0px`;
+                  popoverStyle.bottom = `${height + 8}px`;
+                  arrowOldStyle.left = "16px";
+                  break;
+                case "top-end":
+                  popoverStyle.right = `0px`;
+                  popoverStyle.bottom = `${height + 8}px`;
+                  arrowOldStyle.right = "16px";
+                  break;
+                case "bottom":
+                  if (popoverClientRect.width > width) {
+                    popoverStyle.left = `-${(popoverClientRect.width - width) / 2}px`;
+                  } else {
+                    popoverStyle.left = `${Math.abs(popoverClientRect.width - width) / 2}px`;
+                  }
+                  popoverStyle.top = `${height + 8}px`;
+                  arrowOldStyle.left = popoverClientRect.width / 2 - 6 + "px";
+                  break;
+                case "bottom-start":
+                  popoverStyle.top = `${height + 8}px`;
+                  popoverStyle.left = `0px`;
+                  arrowOldStyle.left = "16px";
+                  break;
+                case "bottom-end":
+                  popoverStyle.top = `${height + 8}px`;
+                  popoverStyle.right = `0px`;
+                  arrowOldStyle.right = "16px";
+                  break;
+                case "right":
+                  popoverStyle.left = `${width + 8}px`;
+                  if (popoverClientRect.height > height) {
+                    popoverStyle.top = `-${(popoverClientRect.height - height) / 2}px`;
+                  } else {
+                    popoverStyle.top = `${Math.abs((popoverClientRect.height - height) / 2)}px`;
+                  }
+                  arrowOldStyle.top = `${popoverClientRect.height / 2 - 6}px`;
+                  break;
+                case "right-start":
+                  popoverStyle.left = `${width + 8}px`;
+                  popoverStyle.top = `0px`;
+                  arrowOldStyle.top = `8px`;
+                  break;
+                case "right-end":
+                  popoverStyle.left = `${width + 8}px`;
+                  popoverStyle.bottom = `0px`;
+                  arrowOldStyle.bottom = `8px`;
+                  break;
+                case "left":
+                  popoverStyle.right = `${width + 8}px`;
+                  if (popoverClientRect.height > height) {
+                    popoverStyle.top = `-${(popoverClientRect.height - height) / 2}px`;
+                  } else {
+                    popoverStyle.top = `${Math.abs((popoverClientRect.height - height) / 2)}px`;
+                  }
+                  arrowOldStyle.top = `${popoverClientRect.height / 2 - 6}px`;
+                  break;
+                case "left-start":
+                  popoverStyle.right = `${width + 8}px`;
+                  popoverStyle.top = `0px`;
+                  arrowOldStyle.top = `8px`;
+                  break;
+
+                case "left-end":
+                  popoverStyle.right = `${width + 8}px`;
+                  popoverStyle.bottom = `0px`;
+                  arrowOldStyle.bottom = `8px`;
+                  break;
+              }
+
+              this.popoverStyle = popoverStyle;
+              this.arrowOldStyle = arrowOldStyle;
+              resolve();
+            })
+            .exec();
+        });
+      });
+    },
+    // 空操作
+    noop(e) {
+      this.preventEvent(e);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+$theme-bg-color: var(--theme-bg-color);
+.zbPopover {
+  position: relative;
+}
+.zb-button-popover {
+  display: inline-block;
+}
+.zb-popover {
+  border-radius: 8px;
+  z-index: 2144;
+  position: absolute;
+  background-color: $theme-bg-color;
+  box-shadow: 0 2px 12px #3232331f;
+}
+.mask-content {
+  width: 100vw;
+  height: 100vh;
+  position: fixed;
+  z-index: 100;
+  top: 0;
+  left: 0;
+  background-color: rgba(0, 0, 0, 0.6);
+}
+.zb-popover-top {
+  transform-origin: 50% bottom;
+}
+.zb-popover-top-start {
+  transform-origin: 50% bottom;
+}
+.zb-popover-top-end {
+  transform-origin: 0 bottom;
+}
+.zb-popover-bottom {
+  transform-origin: 50% 0;
+}
+.zb-popover-bottom-end {
+  transform-origin: 100% 0;
+}
+.zb-popover-bottom-start {
+  transform-origin: 0 0;
+}
+.zb-popover-right {
+  transform-origin: left 50%;
+}
+.zb-popover-right-start {
+  transform-origin: left 0;
+}
+.zb-popover-right-end {
+  transform-origin: left 100%;
+}
+.zb-popover-left {
+  transform-origin: right 50%;
+}
+.zb-popover-left-start {
+  transform-origin: right 0;
+}
+.zb-popover-left-end {
+  transform-origin: right 100%;
+}
+.zb-popover-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+  border-width: 6px;
+  color: $theme-bg-color;
+}
+.zb_popper__up {
+  border-top-width: 0;
+  border-bottom-color: currentColor;
+  top: -6px;
+}
+.zb_popper__right {
+  border-left-width: 0;
+  border-right-color: currentColor;
+  left: -5px;
+}
+.zb_popper__left {
+  border-right-width: 0;
+  border-left-color: currentColor;
+  right: -5px;
+}
+.zb_popper__arrow {
+  border-bottom-width: 0;
+  border-top-color: currentColor;
+  bottom: -6px;
+}
+.zb-popover__action {
+  position: relative;
+  display: flex;
+  align-items: center;
+  box-sizing: border-box;
+  height: 88rpx;
+  padding: 0 40rpx;
+  font-size: 32rpx;
+  cursor: pointer;
+}
+.zb-popover__action:last-child .popover__action_content {
+    border-bottom: none;
+}
+
+.popover__action_content {
+  padding: 0 25rpx;
+  display: flex;
+  align-items: center;
+  image {
+    display: inline-block;
+    width: 40rpx;
+    height: 40rpx;
+    margin-right: 8px;
+  }
+  height: 100%;
+  border-bottom: 1rpx solid #ebedf0;
+  // &:last-child {
+  //   border-bottom: none;
+  // }
+}
+
+.zb-popover__action-text {
+  display: flex;
+  flex: 1;
+  align-items: center;
+  justify-content: center;
+  word-wrap: break-word;
+  white-space: nowrap;
+}
+
+.dark__action {
+  color: white;
+}
+.horizontal__action {
+  display: flex;
+  .zb-popover__action {
+    padding: 0 20rpx;
+    border-right: 1rpx solid #ebedf0;
+  }
+  .zb-popover__action-text {
+    padding: 0;
+    //border-right:1rpx solid #ebedf0;
+  }
+}
+
+$u-zoom-scale: scale(0.95);
+
+.zb-fade-enter-active,
+.zb-fade-leave-active {
+  transition-property: opacity;
+}
+
+.zb-fade-enter,
+.zb-fade-leave-to {
+  opacity: 0;
+}
+
+.zb-fade-zoom-enter,
+.zb-fade-zoom-leave-to {
+  transform: $u-zoom-scale;
+  opacity: 0;
+}
+
+.zb-fade-zoom-enter-active,
+.zb-fade-zoom-leave-active {
+  transition-property: transform, opacity;
+}
+
+.zb-fade-down-enter-active,
+.zb-fade-down-leave-active,
+.zb-fade-left-enter-active,
+.zb-fade-left-leave-active,
+.zb-fade-right-enter-active,
+.zb-fade-right-leave-active,
+.zb-fade-up-enter-active,
+.zb-fade-up-leave-active {
+  transition-property: opacity, transform;
+}
+
+.zb-fade-up-enter,
+.zb-fade-up-leave-to {
+  transform: translate3d(0, 100%, 0);
+  opacity: 0;
+}
+
+.zb-fade-down-enter,
+.zb-fade-down-leave-to {
+  transform: translate3d(0, -100%, 0);
+  opacity: 0;
+}
+
+.zb-fade-left-enter,
+.zb-fade-left-leave-to {
+  transform: translate3d(-100%, 0, 0);
+  opacity: 0;
+}
+
+.zb-fade-right-enter,
+.zb-fade-right-leave-to {
+  transform: translate3d(100%, 0, 0);
+  opacity: 0;
+}
+
+.zb-popover__action {
+  &:active {
+    background-color: rgba(0, 0, 0, 0.2);
+  }
+
+  &--disabled {
+    color: var(--van-popover-dark-action-disabled-text-color);
+
+    &:active {
+      background-color: transparent;
+    }
+  }
+}
+</style>

+ 82 - 0
uni_modules/zb-popover/package.json

@@ -0,0 +1,82 @@
+{
+  "id": "zb-popover",
+  "displayName": "zb-popover 气泡弹出框",
+  "version": "1.0.2",
+  "description": "Popover  气泡弹出框",
+  "keywords": [
+    "Popover",
+    "气泡弹出框"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.1.0"
+  },
+  "dcloudext": {
+    "type": "component-vue",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "Vue": {
+          "vue2": "y",
+          "vue3": "y"
+        },
+        "App": {
+          "app-vue": "u",
+          "app-nvue": "u"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y",
+          "钉钉": "y",
+          "快手": "y",
+          "飞书": "y",
+          "京东": "y"
+        },
+        "快应用": {
+          "华为": "y",
+          "联盟": "y"
+        }
+      }
+    }
+  }
+}

+ 73 - 0
uni_modules/zb-popover/readme.md

@@ -0,0 +1,73 @@
+## 介绍
+弹出式的气泡菜单。
+
+
+## 友情链接
+#### vue-admin-perfect —— [企业级、通用型中后台前端解决方案 预览地址](https://yuanzbz.gitee.io/vue-admin-perfect/#/home/)
+#### vue-admin-perfect —— [企业级、通用型中后台前端解决方案(基于vue3.0+TS+Element-Plus  最新版,同时支持电脑,手机,平板)](https://github.com/zouzhibin/vue-admin-perfect)
+
+## Events 事件
+|事件名 | 说明 | 回调参数 |
+| ------ | ------ |
+| select | 点击选项时触发	 | item |
+| handleClick | 点击按钮事件	 | boolean |
+
+
+
+## Tooltip 属性
+| 参数 | 说明 | 类型 | 可选值 | 默认值 |
+| ------ | ------ | ------ | ------ | ------ |
+| options | 选项列表 | Array |-- | [] |
+| theme | 主题风格,可选值为 dark| String |dark,light | light |
+| actionsDirection | 选项列表的排列方向,可选值为 horizontal| String |vertical,horizontal | vertical |
+| placement | Tooltip 的出现位置 | String |top/top-start/top-end/bottom/bottom-start/bottom-end/left/left-start/left-end/right/right-start/right-end | top |
+
+
+placement 支持以下值:
+```
+top           # 顶部中间位置
+top-start     # 顶部左侧位置
+top-end       # 顶部右侧位置
+left          # 左侧中间位置
+left-start    # 左侧上方位置
+left-end      # 左侧下方位置
+right         # 右侧中间位置
+right-start   # 右侧上方位置
+right-end     # 右侧下方位置
+bottom        # 底部中间位置
+bottom-start  # 底部左侧位置
+bottom-end    # 底部右侧位置
+```
+
+## Slots 插槽
+| 参数 | 说明 |
+| ------ | ------ |
+| content | 显示提示框得内容 |
+
+
+```
+因为uniapp 中小程序中没有window对象,需手动调用 关闭
+ 第一种办法关闭:this.$refs.Popover.close()
+
+```
+
+示例
+```
+<zb-popover placement="bottom-start"
+                 :options="actions"
+                 ref="Popover1"
+                 @handleClick="handleClick"
+                 @select="onSelect"
+                 class="item-popover">
+          <button class="mini-btn"
+                  type="primary"
+                  size="mini">浅色风格</button>
+        </zb-popover>
+
+
+const actions = [
+		{ text: '选项一' },
+		{ text: '选项二' },
+		{ text: '选项三' },
+	];
+```