lianghongjie 1 an în urmă
părinte
comite
9a28f83b13

+ 1 - 0
package.json

@@ -52,6 +52,7 @@
     "core-js": "^3.8.3",
     "dayjs": "^1.11.7",
     "dom-to-image": "^2.6.0",
+    "echarts": "^5.4.2",
     "file-saver": "^2.0.5",
     "hotkeys-js": "^3.10.2",
     "howler": "^2.2.3",

+ 8 - 0
src/hooks/initAuthDef.ts

@@ -1,4 +1,5 @@
 import { Dict_Apis } from "@/dict";
+import { cookieStorage } from "@/utils/cookieStorage";
 import { initAuth } from "@queenjs-modules/auth";
 
 export function initAuthDef() {
@@ -19,6 +20,13 @@ export function initAuthDef() {
         key: "queenshow",
       },
     },
+    actions: {
+      logout() {
+        this.store.clearUserInfo();
+        this.actions.jump("logout");
+        cookieStorage.removeItem("clientId");
+      },
+    },
     https: {
       getProfile() {
         return (this as any).request("/profile?appKey=" + this.config.key, {

+ 15 - 3
src/modules/editor/module/actions/init.ts

@@ -1,9 +1,11 @@
+import { nanoid } from "nanoid";
 import { EditorModule } from "..";
 import { CompObject } from "../../controllers/SelectCtrl/compObj";
 import { DesignComp } from "../../objects/DesignTemp/DesignComp";
 import { createProxyEffect } from "../../objects/ProxyStore/create";
 import { EditorMode } from "../../typings";
 import { editActions } from "./edit";
+import { cookieStorage } from "@/utils/cookieStorage";
 
 export const initActions = EditorModule.action({
   // 模块初始化
@@ -27,9 +29,8 @@ export const initActions = EditorModule.action({
 
   // 初始化数据
   async initDesign(id: string) {
-    const ret = await this.https[
-      this.store.isEditComp ? "getCompDetail" : "getDesignDetail"
-    ](id);
+    this.actions.setCookieClientId();
+    const ret = await this.https.getDesignDetail(id);
     this.store.setDesignData(ret.result);
   },
   // 切换模式
@@ -47,4 +48,15 @@ export const initActions = EditorModule.action({
       this.controls.selectCtrl.selecteObjs([new CompObject(comp)]);
     }
   },
+
+  setCookieClientId() {
+    let clientId = undefined;
+    try {
+      const userInfo = JSON.parse(localStorage.getItem("userInfo") || "{}");
+      clientId = userInfo._id || nanoid();
+    } catch (error) {
+      clientId = nanoid();
+    }
+    cookieStorage.setItem("clientId", clientId);
+  },
 });

+ 0 - 0
src/pages/share/Promotion/index.tsx → src/pages/h5/share/Promotion.tsx


+ 1 - 1
src/pages/share/index.ts → src/pages/h5/share/index.ts

@@ -1,8 +1,8 @@
 import { startApp } from "@/App";
 import { initViewportSize } from "@/hooks/initViewportSize";
 import CKEditor from "@ckeditor/ckeditor5-vue";
-import router from "./router";
 import "./style.less";
+import router from "./router";
 
 document.title = "分享";
 startApp(router, [initViewportSize], (app) => {

+ 0 - 3
src/pages/share/router.ts → src/pages/h5/share/router.ts

@@ -4,9 +4,6 @@ const routes: Array<RouteRecordRaw> = [
   {
     path: "/",
     name: "share",
-    meta: {
-      needAuth: true,
-    },
     component: () => import("./Promotion"),
   },
 ];

+ 0 - 0
src/pages/share/style.less → src/pages/h5/share/style.less


+ 97 - 0
src/pages/h5/statistics/Stat/EchartMap.tsx

@@ -0,0 +1,97 @@
+import * as echarts from "echarts";
+import { defineComponent, onMounted, ref, watch } from "vue";
+import { array } from "vue-types";
+
+export default defineComponent({
+  props: {
+    data: array().isRequired,
+  },
+  setup(props) {
+    const params = new URLSearchParams(location.href.split("?")[1]);
+    const id = params.get("id");
+    const echartRef = ref();
+
+    let chartInstance: any;
+
+    const option = {
+      tooltip: {
+        trigger: "item",
+        showDelay: 0,
+        transitionDuration: 0.2,
+      },
+      visualMap: {
+        show: false,
+        inRange: {
+          color: [
+            "#313695",
+            "#4575b4",
+            "#74add1",
+            "#abd9e9",
+            "#e0f3f8",
+            "#ffffbf",
+            "#fee090",
+            "#fdae61",
+            "#f46d43",
+            "#d73027",
+            "#a50026",
+          ],
+        },
+      },
+      series: [
+        {
+          name: "统计分析",
+          type: "map",
+          roam: true,
+          map: "china",
+          boundingCoords: [
+            // 定位左上角经纬度
+            [68.99814, 50.74432],
+            // 定位右下角经纬度
+            [139.93812, 25.23403],
+          ],
+          emphasis: {
+            label: {
+              show: true,
+            },
+          },
+          data: [] as any[],
+        },
+      ],
+    };
+
+    onMounted(() => {
+      initEchart(echartRef.value);
+    });
+
+    watch(
+      () => props.data,
+      () => {
+        updateEchart();
+      }
+    );
+
+    function updateEchart() {
+      option.series[0].data = props.data;
+      chartInstance.setOption(option);
+    }
+
+    function initEchart(el: HTMLElement) {
+      chartInstance = echarts.init(el);
+      chartInstance.showLoading();
+
+      fetch(
+        "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json"
+      ).then(async (res) => {
+        const json = await res.json();
+        chartInstance.hideLoading();
+
+        echarts.registerMap("china", json);
+        updateEchart();
+      });
+    }
+
+    return () => {
+      return <div class="h-300px" ref={echartRef}></div>;
+    };
+  },
+});

+ 89 - 0
src/pages/h5/statistics/Stat/index.tsx

@@ -0,0 +1,89 @@
+import { defineComponent, onMounted, reactive, ref } from "vue";
+import { Dict_Apis } from "@/dict";
+import EchartMap from "./EchartMap";
+import { css } from "@linaria/core";
+
+export default defineComponent(() => {
+  const params = new URLSearchParams(location.href.split("?")[1]);
+  const id = params.get("id");
+  const mapData = ref();
+  const state = reactive({
+    total: {
+      uv: 0,
+      pv: 0,
+      ip: 0,
+    },
+    currType: "pv",
+    currMapData: [],
+  });
+
+  fetch(`${Dict_Apis.promotion}/count/${id}`).then((res) => {
+    res.json().then((ret) => {
+      console.log(ret);
+    });
+  });
+
+  const tabs = [
+    {
+      label: "浏览量(PV)",
+      value: "pv" as const,
+    },
+    {
+      label: "访客量(UV)",
+      value: "uv" as const,
+    },
+    {
+      label: "IP数",
+      value: "ip" as const,
+    },
+  ];
+
+  function switchStatType(type: string) {
+    state.currType = type;
+  }
+
+  return () => (
+    <div class="p-20px space-y-20px">
+      <div class="grid grid-cols-3 py-16px bg-white rounded text-center">
+        {tabs.map((d) => {
+          return (
+            <div class={topTabCls}>
+              <div class="text-[#333] text-22px font-500 mb-8px">
+                {state.total[d.value]}
+              </div>
+              <div class="text-[#666] text-12px">{d.label}</div>
+            </div>
+          );
+        })}
+      </div>
+      <div class="bg-white rounded text-center font-500">
+        <div class="grid grid-cols-3 leading-48px text-14px">
+          {tabs.map((d) => {
+            return (
+              <div
+                class={[mapTabCls, d.value === state.currType && "active"]}
+                onClick={() => switchStatType(d.value)}
+              >
+                {d.label}
+              </div>
+            );
+          })}
+        </div>
+        <EchartMap data={state.currMapData} />
+      </div>
+    </div>
+  );
+});
+
+const topTabCls = css`
+  &:not(:first-child) {
+    border-left: 1px solid #f1f1f1;
+  }
+`;
+
+const mapTabCls = css`
+  background-color: #f1f1f1;
+  &.active {
+    background-color: #fff;
+  }
+`;

+ 7 - 0
src/pages/h5/statistics/index.ts

@@ -0,0 +1,7 @@
+import { startApp } from "@/App";
+import { initViewportSize } from "@/hooks/initViewportSize";
+import "./style.less";
+import router from "./router";
+
+document.title = "统计分析";
+startApp(router, [initViewportSize]);

+ 19 - 0
src/pages/h5/statistics/router.ts

@@ -0,0 +1,19 @@
+import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
+
+const routes: Array<RouteRecordRaw> = [
+  {
+    path: "/",
+    name: "stat",
+    meta: {
+      needAuth: true,
+    },
+    component: () => import("./Stat"),
+  },
+];
+
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes,
+});
+
+export default router;

+ 5 - 0
src/pages/h5/statistics/style.less

@@ -0,0 +1,5 @@
+#app {
+  min-height: 100vh;
+  min-width: 100vw;
+  background-color: #f5f6f7;
+}

+ 0 - 5
src/pages/share/Statistics/index.tsx

@@ -1,5 +0,0 @@
-import { defineComponent } from "vue";
-
-export default defineComponent(() => {
-  return () => <div></div>;
-});

+ 81 - 0
src/utils/cookieStorage.ts

@@ -0,0 +1,81 @@
+export const cookieStorage = {
+  getItem: function (sKey: string) {
+    return (
+      decodeURIComponent(
+        document.cookie.replace(
+          new RegExp(
+            "(?:(?:^|.*;)\\s*" +
+              encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") +
+              "\\s*\\=\\s*([^;]*).*$)|^.*$"
+          ),
+          "$1"
+        )
+      ) || null
+    );
+  },
+  setItem: function (
+    sKey: string,
+    sValue: string,
+    vEnd?: number | string | Date,
+    sPath?: string,
+    sDomain?: string,
+    bSecure?: boolean
+  ) {
+    if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
+      return false;
+    }
+    let sExpires = "";
+    if (vEnd) {
+      switch (vEnd.constructor) {
+        case Number:
+          sExpires =
+            vEnd === Infinity
+              ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT"
+              : "; max-age=" + vEnd;
+          break;
+        case String:
+          sExpires = "; expires=" + vEnd;
+          break;
+        case Date:
+          sExpires = "; expires=" + (vEnd as Date).toUTCString();
+          break;
+      }
+    }
+    document.cookie =
+      encodeURIComponent(sKey) +
+      "=" +
+      encodeURIComponent(sValue) +
+      sExpires +
+      (sDomain ? "; domain=" + sDomain : "") +
+      (sPath ? "; path=" + sPath : "") +
+      (bSecure ? "; secure" : "");
+    return true;
+  },
+  removeItem: function (sKey: string, sPath?: string, sDomain?: string) {
+    if (!sKey || !this.hasItem(sKey)) {
+      return false;
+    }
+    document.cookie =
+      encodeURIComponent(sKey) +
+      "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" +
+      (sDomain ? "; domain=" + sDomain : "") +
+      (sPath ? "; path=" + sPath : "");
+    return true;
+  },
+  hasItem: function (sKey: string) {
+    return new RegExp(
+      "(?:^|;\\s*)" +
+        encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") +
+        "\\s*\\="
+    ).test(document.cookie);
+  },
+  keys: /* optional method: you can safely remove it! */ function () {
+    let aKeys = document.cookie
+      .replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "")
+      .split(/\s*(?:=[^;]*)?;\s*/);
+    for (let nIdx = 0; nIdx < aKeys.length; nIdx++) {
+      aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
+    }
+    return aKeys;
+  },
+};

+ 2 - 1
vue.config.js

@@ -17,7 +17,8 @@ module.exports = defineConfig({
   pages: {
     index: "src/pages/website/index.ts",
     editor: "src/pages/editor/index.ts",
-    share: "src/pages/share/index.ts",
+    share: "src/pages/h5/share/index.ts",
+    // stat: "src/pages/h5/statistics/index.ts",
     treeapi: "src/pages/queentree/index.ts",
   },
   publicPath: publicPath,

+ 20 - 0
yarn.lock

@@ -4218,6 +4218,14 @@ easy-stack@1.0.1:
   resolved "http://124.70.149.18:4873/easy-stack/-/easy-stack-1.0.1.tgz#8afe4264626988cabb11f3c704ccd0c835411066"
   integrity sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==
 
+echarts@^5.4.2:
+  version "5.4.2"
+  resolved "http://124.70.149.18:4873/echarts/-/echarts-5.4.2.tgz#9f38781c9c6ae323e896956178f6956952c77a48"
+  integrity sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==
+  dependencies:
+    tslib "2.3.0"
+    zrender "5.4.3"
+
 ee-first@1.1.1, ee-first@~1.1.1:
   version "1.1.1"
   resolved "http://124.70.149.18:4873/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -8342,6 +8350,11 @@ ts-loader@^9.2.5:
     micromatch "^4.0.0"
     semver "^7.3.4"
 
+tslib@2.3.0:
+  version "2.3.0"
+  resolved "http://124.70.149.18:4873/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
+  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
+
 tslib@^1.8.1:
   version "1.14.1"
   resolved "http://124.70.149.18:4873/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@@ -9075,3 +9088,10 @@ yorkie@^2.0.0:
     is-ci "^1.0.10"
     normalize-path "^1.0.0"
     strip-indent "^2.0.0"
+
+zrender@5.4.3:
+  version "5.4.3"
+  resolved "http://124.70.149.18:4873/zrender/-/zrender-5.4.3.tgz#41ffaf835f3a3210224abd9d6964b48ff01e79f5"
+  integrity sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==
+  dependencies:
+    tslib "2.3.0"