ソースを参照

新用户引导

zhoujump 3 週間 前
コミット
853980f319

ファイルの差分が大きいため隠しています
+ 2 - 2
src/permission.js


+ 35 - 2
src/router/index.js

@@ -17,10 +17,10 @@ export const constantRoutes = [
         meta: {
           title: '首页看板',
           icon: 'el-icon-house',
-          roles: 'dashboard',
+          roles: 'dashboard',//roles为权限控制标识
           func: [
             {
-              name: '头部概览',
+              name: '头部概览',//这里是更为细化的控制
               roles: 'dashboard.head'
             }
           ]
@@ -357,6 +357,39 @@ export const constantRoutes = [
         ]
       },
       {
+        path: 'share&utm',
+        component: () => import('@/views/shareUtm/index'),
+        name: 'shareUtm',
+        meta: {
+          title: '分享与UTM',
+          icon: 'el-icon-data-line',
+          roles: 'share&utm'
+        },
+        redirect: '/share&utm/share',
+        children: [
+          {
+            path: 'share',
+            component: () => import('@/views/shareUtm/share'),
+            name: 'share',
+            meta: {
+              title: '分享中心',
+              icon: 'el-icon-share',
+              roles: 'share&utm.share'
+            }
+          },
+          {
+            path: 'utm',
+            component: () => import('@/views/shareUtm/utm'),
+            name: 'utm',
+            meta: {
+              title: 'UTM中心',
+              icon: 'el-icon-link',
+              roles: 'share&utm.utm'
+            }
+          }
+        ]
+      },
+      {
         path: 'setting',
         component: () => import('@/views/setting/index'),
         name: 'setting',

+ 10 - 10
src/views/dashboard/index.vue

@@ -29,16 +29,16 @@
             </div>
           </div>
         </div>
-<!--        <div class="starter-box card">-->
-<!--          <div class="icon el-icon-position"></div>-->
-<!--          <div class="title">创建展会</div>-->
-<!--          <div class="desc">十分钟创建一个展会<br/>通过表单系统收集与管理观众信息</div>-->
-<!--        </div>-->
-<!--        <div class="invitation-box card">-->
-<!--          <div class="icon el-icon-notebook-2"></div>-->
-<!--          <div class="title">创建邀请函</div>-->
-<!--          <div class="desc">十分钟创建一个邀请函<br/>集成表单系统快速填充信息并发送</div>-->
-<!--        </div>-->
+        <div class="starter-box card">
+          <div class="icon el-icon-position"></div>
+          <div class="title">创建展会</div>
+          <div class="desc">十分钟创建一个展会<br/>通过表单系统收集与管理观众信息</div>
+        </div>
+        <div class="invitation-box card">
+          <div class="icon el-icon-notebook-2"></div>
+          <div class="title">创建邀请函</div>
+          <div class="desc">十分钟创建一个邀请函<br/>集成表单系统快速填充信息并发送</div>
+        </div>
       </div>
     </div>
   </div>

+ 15 - 0
src/views/shareUtm/index.vue

@@ -0,0 +1,15 @@
+<script lang="ts">
+import Vue from 'vue'
+
+export default Vue.extend({
+  name: "index"
+})
+</script>
+
+<template>
+  <router-view></router-view>
+</template>
+
+<style scoped>
+
+</style>

+ 287 - 0
src/views/shareUtm/share.vue

@@ -0,0 +1,287 @@
+<script lang="ts">
+import Vue from 'vue'
+import vueQr from 'vue-qr'
+import { getExpoList, getMyExpoInfo } from '@/api/expo'
+export default Vue.extend({
+  name: 'Share',
+  components: {
+    vueQr
+  },
+  data() {
+    return {
+      rootPath: window.location.origin,
+      shareType: 'link',
+      currentExpo: {},
+      shareData: {
+        qrLogo: '',
+        qrLogoSize: 2,
+        qrLogoName: '',
+        qrImage: ''
+      },
+      expoId: '',
+      expoList: []
+    }
+  },
+  mounted() {
+    this.getExpoList()
+  },
+  methods: {
+    getExpoList() {
+      getExpoList(1, 1000).then(res => {
+        this.expoList = res.data.data
+      }).catch(err => {
+        this.$notify({
+          title: '提示',
+          message: '获取展会列表失败' + err,
+          type: 'error'
+        })
+      })
+    },
+    getExpo() {
+      getMyExpoInfo(this.expoId).then(res => {
+        this.currentExpo = res.data
+        console.log(this.currentExpo)
+      }).catch(err => {
+        this.$notify({
+          title: '提示',
+          message: '获取展会信息失败' + err,
+          type: 'error'
+        })
+      })
+    },
+    copyText(text) {
+      navigator.clipboard.writeText(text)
+      this.$notify({
+        title: '提示',
+        message: '复制成功',
+        type: 'success'
+      })
+    },
+    qrImageReady(e) {
+      this.shareData.qrImage = e
+    },
+    downloadQrImage() {
+      const a = document.createElement('a')
+      a.href = this.shareData.qrImage
+      a.download = '二维码.png'
+      a.click()
+    },
+    setQrLogo(file) {
+      this.shareData.qrLogoName = file.name
+      this.shareData.qrLogo = URL.createObjectURL(file)
+    },
+    goto(url) {
+      window.open(url, '_blank')
+    }
+  }
+})
+</script>
+
+<template>
+  <div class="share-center">
+    <div class="share-type">
+      <div class="sub-title">分享展会</div>
+      <el-select v-model="expoId" placeholder="请选择参展名称" @change="getExpo()">
+        <el-option v-for="item in expoList" :value="item.id" :label="item.expo_name" />
+      </el-select>
+      <div class="sub-title">分享方式</div>
+      <el-radio-group class="radio-list" v-model="shareType">
+        <el-radio border label="link" >网页链接</el-radio>
+        <el-radio border label="qrcode" >二维码图片</el-radio>
+<!--        <el-radio border label="social_media" >社交媒体/社交软件</el-radio>-->
+        <el-radio border label="post_image" >生成海报图片</el-radio>
+        <el-radio border label="wechat_insert" >微信公众平台嵌入</el-radio>
+        <el-radio border label="code_insert" >网页代码嵌入</el-radio>
+      </el-radio-group>
+    </div>
+    <div class="share-view">
+      <div v-if="!expoId" class="chose-expo">
+        <div class="sub-title">选择需要分享的展会</div>
+        <el-select v-model="expoId" placeholder="请选择参展名称" @change="getExpo()">
+          <el-option v-for="item in expoList" :value="item.id" :label="item.expo_name" />
+        </el-select>
+      </div>
+      <div v-if="shareType==='link' && expoId" class="link-share">
+        <div class="link-inner">
+          {{ rootPath }}/register/{{ currentExpo.urla }}
+        </div>
+        <div class="button-list">
+          <el-button size="small" icon="el-icon-link" round @click="goto(rootPath+'/register/'+currentExpo.urla)">打开链接</el-button>
+          <el-button size="small" icon="el-icon-document-copy" round @click="copyText(rootPath+'/register/'+currentExpo.urla)">复制链接</el-button>
+        </div>
+      </div>
+      <div v-if="shareType==='qrcode' && expoId" class="qrcode-share">
+        <div class="qrcode-inner">
+          <vue-qr :callback="qrImageReady" :logo-margin="4" :logo-src="shareData.qrLogo" :logo-scale="shareData.qrLogoSize*0.1" :text="rootPath+'/register/'+currentExpo.urla" :margin="16" :size="260" />
+          <div class="title">{{ currentExpo.expo_name }}</div>
+        </div>
+        <div class="button-list">
+          <el-button size="small" icon="el-icon-download" round @click="downloadQrImage">下载图片</el-button>
+        </div>
+      </div>
+      <div v-if="shareType==='social_media' && expoId" class="social-share">
+      </div>
+      <div v-if="shareType==='post_image' && expoId" class="post-share">
+        <div class="post-inner">
+
+        </div>
+      </div>
+    </div>
+    <div class="share-config">
+      <template v-if="shareType==='qrcode'">
+        <div class="sub-title">二维码logo</div>
+        <div class="logo-input">
+          <img v-if="shareData.qrLogo" class="logo" :src="shareData.qrLogo">
+          <div v-else class="logo" />
+          <div class="file-name">{{ shareData.qrLogoName||'点击选择/拖拽logo图片' }}</div>
+          <input type="file" accept="image/*" @change="setQrLogo($event.target.files[0])">
+          <div v-if="shareData.qrLogo" class="del el-icon-close" @click="shareData.qrLogo=shareData.qrLogoName=''" />
+        </div>
+        <div class="sub-title">logo尺寸</div>
+        <el-slider v-model="shareData.qrLogoSize" :min="1.5" :max="3.5" :step="0.1" show-tooltip />
+      </template>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+  .share-center{
+    overflow: hidden;
+    padding: 0 !important;
+    height: 100%;
+    display: grid;
+    grid-template-columns: 360px 1fr 360px;
+    .sub-title{
+      font-size: 14px;
+      margin-left: 4px;
+      color: grey;
+      font-weight: 500;
+      margin-bottom: 8px;
+    }
+    .share-type{
+      z-index: 2;
+      position: relative;
+      box-shadow: 0 1px 4px 0 #00000022;
+      padding: 16px;
+      .el-select{
+        width: 100%;
+        margin-bottom: 4px;
+      }
+      .radio-list{
+        display: flex;
+        flex-direction: column;
+        gap: 6px;
+        .el-radio{
+          margin: 0;
+          width: 100%;
+        }
+      }
+    }
+    .share-config{
+      z-index: 2;
+      position: relative;
+      box-shadow: 0 1px 4px 0 #00000022;
+      padding: 16px;
+      .logo-input{
+        transition-duration: 300ms;
+        overflow: hidden;
+        position: relative;
+        border-radius: 8px;
+        background-color: #f6f6f6;
+        width: 100%;
+        height: 80px;
+        padding: 12px;
+        display: grid;
+        grid-gap: 12px;
+        grid-template-columns: 56px 1fr;
+        align-items: center;
+        .del{
+          padding: 6px;
+          position: absolute;
+          right: 6px;
+          top: 6px;
+          border-radius: 50%;
+          cursor: pointer;
+          &:hover{
+            background-color: #e3e3e3;
+          }
+        }
+        .logo{
+          border-radius: 6px;
+          object-fit: cover;
+          background-color: white;
+          width: 56px;
+          height: 56px;
+        }
+        .file-name{
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+          flex: 1;
+          font-size: 13px;
+        }
+        input{
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          height: 100%;
+          opacity: 0;
+        }
+      }
+    }
+    .share-view{
+      z-index: 1;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      position: relative;
+      background-color: #F9FAFB;
+      .chose-expo{
+        box-shadow: 0 1px 4px 0 #00000022;
+        padding: 16px;
+        border-radius: 8px;
+        background-color: white;
+        width: 360px;
+        .el-select{
+          width: 100%;
+        }
+      }
+      .button-list{
+        text-align: right;
+        margin-top: 8px;
+      }
+      .qrcode-share{
+        .qrcode-inner{
+          overflow: hidden;
+          background-color: white;
+          box-shadow: 0 1px 4px 0 #00000022;
+          border-radius: 8px;
+          .title{
+            font-size: 14px;
+            font-weight: bold;
+            text-align: center;
+            margin-bottom: 16px;
+          }
+        }
+      }
+      .post-share{
+        width: 100%;
+        height: 100%;
+        background-size: cover;
+        background-position: center;
+        position: relative;
+        background-image: url("/static/image/prototype/wallpost/prototypewall.jpg");
+      }
+      .link-share{
+        .link-inner{
+          font-size: 15px;
+          border-radius: 8px;
+          box-shadow: 0 1px 4px 0 #00000022;
+          padding: 16px 24px;
+          background-color: white;
+        }
+      }
+    }
+  }
+</style>

+ 15 - 0
src/views/shareUtm/utm.vue

@@ -0,0 +1,15 @@
+<script lang="ts">
+import Vue from 'vue'
+
+export default Vue.extend({
+  name: "utm"
+})
+</script>
+
+<template>
+
+</template>
+
+<style scoped>
+
+</style>

+ 30 - 0
src/权限控制指南.md

@@ -0,0 +1,30 @@
+由于代码写得实在太烂了所以有必要解释一下权限是如何管理的
+### 路由配置
+[router/index.js](router/index.js)路由配置`meta`属性中的`roles`属性为权限控制标识,`func`属性为元素的权限控制。
+```json
+{
+  path: 'dashboard',
+    component: () => import('@/views/dashboard/index'),
+    name: 'Dashboard',
+    meta: {
+    title: '首页看板',
+      icon: 'el-icon-house',
+      roles: 'dashboard',//roles为权限控制标识
+      func: [
+      {
+        name: '头部概览',//这里是更为细化的控制
+        roles: 'dashboard.head'
+      }
+    ]
+  }
+}
+```
+
+### `v-permission`指令
+如果某个元素需要被权限控制,使用以下方式。需要注意的是非'relative','absolute','sticky'定位的元素,都会被替换为'relative'
+```vue
+<div v-permission="'权限标识'"></div>
+```
+
+### 那如何控制呢
+在[permission.js](permission.js)文件中第一行export的就是了,目前写死了。通过增删数组内的权限标识就能控制不同套餐的权限。