Browse Source

feat:新手引导

liyangbin 4 months ago
parent
commit
b1e2a35d1a

+ 6 - 0
package-lock.json

@@ -10,6 +10,7 @@
       "dependencies": {
         "axios": "^1.2.1",
         "crypto-js": "^4.1.1",
+        "driver.js": "^1.3.1",
         "echarts": "^5.4.1",
         "element-ui": "^2.15.12",
         "pinia": "^2.0.16",
@@ -1658,6 +1659,11 @@
         "node": ">=12"
       }
     },
+    "node_modules/driver.js": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmmirror.com/driver.js/-/driver.js-1.3.1.tgz",
+      "integrity": "sha512-MvUdXbqSgEsgS/H9KyWb5Rxy0aE6BhOVT4cssi2x2XjmXea6qQfgdx32XKVLLSqTaIw7q/uxU5Xl3NV7+cN6FQ=="
+    },
     "node_modules/duplexer": {
       "version": "0.1.2",
       "resolved": "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz",

+ 1 - 0
package.json

@@ -14,6 +14,7 @@
   "dependencies": {
     "axios": "^1.2.1",
     "crypto-js": "^4.1.1",
+    "driver.js": "^1.3.1",
     "echarts": "^5.4.1",
     "element-ui": "^2.15.12",
     "pinia": "^2.0.16",

BIN
src/assets/images/step_arrow.png


+ 99 - 0
src/assets/style/main.scss

@@ -3,23 +3,27 @@ html {
   font-style: normal;
   min-width: 1280px;
 }
+
 h1 {
   font-weight: 700;
   font-size: 28px;
   line-height: 40px;
   color: #232A40;
 }
+
 h2 {
   font-weight: 700;
   font-size: 16px;
   line-height: 20px;
   color: #232A40;
 }
+
 .block {
   background: #FFFFFF;
   box-shadow: 0px 0px 12px rgba(35, 97, 169, 0.05);
   border-radius: 8px;
 }
+
 select {
   height: 28px;
   border: 1px solid #D9D9D9;
@@ -33,4 +37,99 @@ select {
   -moz-appearance: none;
   -webkit-appearance: none;
   background: url('/src/assets/images/dashboard/select.svg') no-repeat calc(100% - 7px) transparent;
+}
+
+div.noviceGuide {
+  max-width: 379px;
+
+  .driver-popover-arrow {
+    display: none;
+  }
+
+  .driver-popover-title {
+    font-size: 16px;
+    color: #396FFA;
+    font-weight: 700;
+    text-align: left;
+    line-height: 24px;
+    user-select: none;
+  }
+
+  .driver-popover-description {
+    font-size: 14px;
+    line-height: 20px;
+    color: #232A40;
+    text-align: left;
+
+    a {
+      margin: 0 4px;
+      text-decoration: underline;
+    }
+  }
+
+  .driver-popover-prev-btn {
+    display: none !important;
+  }
+
+  footer.driver-popover-footer {
+    div {
+      display: flex;
+      align-items: center;
+
+      input {
+        width: 18px;
+        height: 18px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+        border: 2px solid #94969D;
+      }
+
+      p {
+        font-size: 14px;
+        color: #94969D;
+        line-height: 20px;
+        font-family: 'Poppins';
+      }
+
+      svg {
+        zoom: 0.74;
+      }
+
+      .img {
+        display: flex;
+        margin-right: 8px;
+      }
+    }
+
+    .driver-popover-navigation-btns {
+      display: inline;
+      flex-grow: initial;
+      display: flex;
+      flex-direction: row-reverse;
+      align-items: center;
+
+      span {
+        font-size: 14px;
+        font-weight: 500;
+        line-height: 20px;
+        color: #808185;
+        cursor: pointer;
+      }
+
+      .driver-popover-next-btn {
+        border: 1px solid #1460F3;
+        border-radius: 5px;
+        display: flex;
+        font-size: 14px;
+        font-weight: 700;
+        margin-left: 8px;
+        color: #1460F3;
+        line-height: 24px;
+        text-shadow: none;
+        min-width: 89px;
+        text-align: center;
+      }
+    }
+  }
 }

+ 111 - 7
src/components/sideMenu.vue

@@ -1,5 +1,6 @@
 <script>
-import { onMounted, ref } from "vue"
+import { driver } from 'driver.js'
+import 'driver.js/dist/driver.css'
 import { get } from '../../utils/request'
 import Dashboard from '@/components/icon/menu_dashboard.vue'
 import Product from '@/components/icon/menu_product.vue'
@@ -40,6 +41,108 @@ export default {
     if (this.$route.query && this.$route.query.type === 'isNoAdmin') {
       this.isNoAdmin = true
     }
+    const isFirstTimeLogin = localStorage.getItem('isFirstTimeLogin')
+    if (isFirstTimeLogin === 'true') {
+      this.$nextTick(() => {
+        const driverObj = driver({
+          allowClose: false,
+          showProgress: true,
+          overlayOpacity: .5,
+          popoverClass: 'noviceGuide',
+          disableActiveInteraction: true,
+          nextBtnText: 'Next Step',
+          showButtons: [
+            'next', "close"
+          ],
+          doneBtnText: 'Get',
+          progressText: '{{current}} / {{total}}',
+          steps: [
+            {
+              element: '.step_part1',
+              popover: {
+                title: 'Copy & Activate License Code',
+                description: 'Copy the license code in the Manage License segment. Launch LynxPDF Editor and enter your license code to activate software.',
+                side: 'left',
+                align: 'start',
+                onPopoverRender: (popover, { config, state }) => {
+                  const next = document.querySelector('.driver-popover-next-btn')
+                  const firstButton = document.createElement("span")
+                  firstButton.innerText = "Skip"
+                  popover.footerButtons.appendChild(firstButton)
+  
+                  firstButton.addEventListener("click", () => {
+                    localStorage.setItem('isFirstTimeLogin', 'false')
+                    driverObj.destroy()
+                  })
+                },
+                onNextClick: async () => {
+                  localStorage.setItem('isFirstTimeLogin', 'false')
+                  this.$router.push('/manage-member')
+                  driverObj.moveNext()
+                }
+              }
+            },
+            {
+              element: '.step_part2 .el-submenu__title',
+              popover: {
+                title: 'Create & Manage Team',
+                description: 'Add or remove team members. Assign license codes to a team with one click. Greatly simplifies workflow.',
+                side: 'left',
+                align: 'start',
+                onPopoverRender: (popover, { config, state }) => {
+                  const next = document.querySelector('.driver-popover-next-btn')
+                  const firstButton = document.createElement("span")
+                  firstButton.innerText = "Skip"
+                  popover.footerButtons.appendChild(firstButton)
+  
+                  firstButton.addEventListener("click", () => {
+                    driverObj.destroy()
+                  })
+                },
+                onNextClick: async () => {
+                  this.$router.push('/license-management')
+                  driverObj.moveNext()
+                }
+              }
+            },
+            {
+              element: '.step_part3 .el-submenu__title',
+              popover:
+              {
+                title: 'Manage License Code',
+                description: 'Assign the license code for team members or remove the license code for those already leaving.',
+                side: 'left',
+                align: 'start',
+                onPopoverRender: (popover, { config, state }) => {
+                  const next = document.querySelector('.driver-popover-next-btn')
+                  const firstButton = document.createElement("span")
+                  firstButton.innerText = "Skip"
+                  popover.footerButtons.appendChild(firstButton)
+  
+                  firstButton.addEventListener("click", () => {
+                    driverObj.destroy()
+                  })
+                },
+                onNextClick: async () => {
+                  this.$router.push('/manage-device')
+                  driverObj.moveNext()
+                }
+              }
+            },
+            {
+              element: '.step_part4',
+              popover: {
+                title: 'Unbind License Code',
+                description: 'Unbind device and enable team members to activate license codes on new devices.',
+                side: 'left',
+                align: 'start',
+              }
+            }
+          ]
+        })
+        driverObj.drive()
+      })
+    }
   },
   methods: {
     logout() {
@@ -120,10 +223,10 @@ export default {
         </div>
         <div class="type">{{ roles }}</div>
       </div>
-      <el-menu :default-active="path" active-text-color="#1460F3" text-color="#232A40" router>
+      <el-menu ref="menu" :default-active="path" active-text-color="#1460F3" text-color="#232A40" router>
         <!-- <div v-if="role?.indexOf('2') !== -1 || role?.indexOf('1') !== -1"> -->
         <div>
-          <el-menu-item index="/dashboard" :disabled="isNoAdmin">
+          <el-menu-item index="/dashboard" :disabled="isNoAdmin" class="dashboard">
             <Dashboard />
             <span>Home</span>
           </el-menu-item>
@@ -135,7 +238,7 @@ export default {
             <Order />
             <span>Order</span>
           </el-menu-item>
-          <el-submenu index="3" :disabled="isNoAdmin">
+          <el-submenu index="3" :disabled="isNoAdmin" class="step_part2">
             <template slot="title">
               <Team />
               <span>Team Management</span>
@@ -144,16 +247,17 @@ export default {
             <el-menu-item index="/manage-member" :disabled="isNoAdmin">Manage Member</el-menu-item>
             <el-menu-item index="/manage-admin" :disabled="isNoAdmin">Manage Admin</el-menu-item>
           </el-submenu>
-          <el-submenu index="4" :disabled="isNoAdmin">
+          <el-submenu index="4" :disabled="isNoAdmin" class="step_part3">
             <template slot="title">
               <License />
               <span>Manage License</span>
             </template>
-            <el-menu-item index="/license-management" :disabled="isNoAdmin">Manage License</el-menu-item>
+            <el-menu-item index="/license-management" :disabled="isNoAdmin" class="step_part1">Manage
+              License</el-menu-item>
             <el-menu-item index="/assign-license" :disabled="isNoAdmin">Assign License</el-menu-item>
             <el-menu-item index="/batch-cancel-license" :disabled="isNoAdmin">Batch Remove</el-menu-item>
           </el-submenu>
-          <el-menu-item index="/manage-device" :disabled="isNoAdmin">
+          <el-menu-item index="/manage-device" :disabled="isNoAdmin" class="step_part4">
             <Device />
             <span>Unbind Device</span>
           </el-menu-item>

+ 147 - 131
src/views/LicenseManage.vue

@@ -25,40 +25,42 @@ const toggleKey = ref(0)
 const showFiled = ref(['Product', 'User Name', 'Email', 'Team', 'License Code', 'Status', 'Remaining Activatable Devices', 'Number of Activated Devices', 'Action'])
 const fieldSelect = ref(['Product', 'User Name', 'Email', 'Team', 'License Code', 'Status', 'Remaining Activatable Devices', 'Number of Activated Devices', 'Action'])
 const fieldOptions = ref([{
-        value: 'Product',
-        label: 'Product'
-      }, {
-        value: 'User Name',
-        label: 'User Name'
-      }, {
-        value: 'Email',
-        label: 'Email'
-      }, {
-        value: 'Team',
-        label: 'Team'
-      }, {
-        value: 'License Code',
-        label: 'License Code'
-      }, {
-        value: 'Status',
-        label: 'Status'
-      }, {
-        value: 'Operated Date',
-        label: 'Operated Date'
-      }, {
-        value: 'Expiration Data',
-        label: 'Expiration Data'
-      }, {
-        value: 'Action',
-        label: 'Action'
-      }, {
-        value: 'Remaining Activatable Devices',
-        label: 'Remaining Activatable Devices'
-      }, {
-        value: 'Number of Activated Devices',
-        label: 'Number of Activated Devices'
-      }])
+  value: 'Product',
+  label: 'Product'
+}, {
+  value: 'User Name',
+  label: 'User Name'
+}, {
+  value: 'Email',
+  label: 'Email'
+}, {
+  value: 'Team',
+  label: 'Team'
+}, {
+  value: 'License Code',
+  label: 'License Code'
+}, {
+  value: 'Status',
+  label: 'Status'
+}, {
+  value: 'Operated Date',
+  label: 'Operated Date'
+}, {
+  value: 'Expiration Data',
+  label: 'Expiration Data'
+}, {
+  value: 'Action',
+  label: 'Action'
+}, {
+  value: 'Remaining Activatable Devices',
+  label: 'Remaining Activatable Devices'
+}, {
+  value: 'Number of Activated Devices',
+  label: 'Number of Activated Devices'
+}])
 const downloadLoading = ref(false)
+const isFirstTimeLogin = localStorage.getItem('isFirstTimeLogin') === 'true'
+
 onMounted(() => {
   let pageText = document.getElementsByClassName('el-pagination__jump')[0]
   if (pageText) {
@@ -73,22 +75,22 @@ const pagingQuery = (val) => {
   tableData.value = []
   get(
     '/pdf-tech/vppLicenseCode/page?page=' +
-      currentPage.value +
-      '&' +
-      'pageSize=' +
-      size.value +
-      '&' +
-      'productId=' +
-      productId.value +
-      '&' +
-      'teamId=' +
-      teamId.value +
-      '&' +
-      'status=' +
-      status.value +
-      '&' +
-      'queryString=' +
-      queryString.value
+    currentPage.value +
+    '&' +
+    'pageSize=' +
+    size.value +
+    '&' +
+    'productId=' +
+    productId.value +
+    '&' +
+    'teamId=' +
+    teamId.value +
+    '&' +
+    'status=' +
+    status.value +
+    '&' +
+    'queryString=' +
+    queryString.value
   ).then((res) => {
     const data = res.data.result.list
     for (let i = 0; i < data.length; i++) {
@@ -108,6 +110,7 @@ const pagingQuery = (val) => {
         data[i].validFlag = 'Canceled'
         // data[i].endDate = ''
       }
+      data[i].stepIndex = i
     }
     tableData.value = productListNameMapping(data)
     total.value = res.data.result.total
@@ -185,13 +188,13 @@ const download = () => {
   urlencoded.append("productId", productId.value)
   urlencoded.append("teamId", teamId.value)
   urlencoded.append("status", status.value)
-  downLoad('/pdf-tech/vppLicenseCode/download',urlencoded).then(
+  downLoad('/pdf-tech/vppLicenseCode/download', urlencoded).then(
     (res) => {
       setTimeout(() => {
         downloadLoading.value = false
       }, 2000)
       let url = window.URL.createObjectURL(new Blob([res.data], { type: '.xlsx' }))
-      let a= document.createElement('a')
+      let a = document.createElement('a')
       a.style.display = 'none'
       a.href = url
       // 自定义文件名
@@ -201,7 +204,7 @@ const download = () => {
       a.click()
       // 释放内存
       url = window.URL.revokeObjectURL(url)
-      document.body.removeChild(a) 
+      document.body.removeChild(a)
     }
   )
 }
@@ -253,8 +256,7 @@ const searchInfo = (val) => {
   <div class="flex flex-col items-center">
     <div class="w-full">
       <h1 class="leading-40px">Manage License</h1>
-      <div
-        class="
+      <div class="
           mt-36px
           mb-16px
           leading-20px
@@ -262,19 +264,11 @@ const searchInfo = (val) => {
           font-bold
           flex
           justify-between
-        "
-      >
+        ">
         <span>Content</span>
         <div class="flex">
-          <el-tooltip
-          class="item"
-          effect="dark"
-          content="Export Data (.xlsx)"
-          placement="bottom"
-        >
-          <span
-            @click="download()"
-            class="
+          <el-tooltip class="item" effect="dark" content="Export Data (.xlsx)" placement="bottom">
+            <span @click="download()" class="
               flex
               justify-center
               items-center
@@ -282,14 +276,11 @@ const searchInfo = (val) => {
               min-w-28px min-h-28px
               bg-[#fff]
               cursor-pointer
-            "
-          >
-            <Download />
-          </span>
+            ">
+              <Download />
+            </span>
           </el-tooltip>
-          <router-link
-            to="/assign-license"
-            class="
+          <router-link to="/assign-license" class="
               bg-[#1460F3]
               h-28px
               w-111px
@@ -302,13 +293,10 @@ const searchInfo = (val) => {
               rounded-4px
               text-[#fff]
               hover:opacity-80
-            "
-          >
+            ">
             Assign License
           </router-link>
-          <router-link
-            to="/batch-cancel-license"
-            class="
+          <router-link to="/batch-cancel-license" class="
               bg-[#1460F3]
               h-28px
               w-111px
@@ -321,21 +309,17 @@ const searchInfo = (val) => {
               rounded-4px
               text-[#fff]
               hover:opacity-80
-            "
-          >
+            ">
             Batch Remove
           </router-link>
         </div>
       </div>
       <div class="w-full bg-[#fff] rounded-t-8px pt-32px px-24px">
         <span>Header Display Fields</span>
-        <el-select v-model="fieldSelect" @change='changeSelectField' @remove-tag='removeTag' multiple placeholder="Please select" class="w-600px mx-20px">
+        <el-select v-model="fieldSelect" @change='changeSelectField' @remove-tag='removeTag' multiple
+          placeholder="Please select" class="w-600px mx-20px">
           <el-option v-if="fieldOptions.length" value="all" label="all" @click.native='selectAllField'></el-option>
-          <el-option
-            v-for="item in fieldOptions"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value">
+          <el-option v-for="item in fieldOptions" :key="item.value" :label="item.label" :value="item.value">
           </el-option>
         </el-select>
         <el-button type="primary" @click="changeTableField">Confirm</el-button>
@@ -343,11 +327,7 @@ const searchInfo = (val) => {
       <div class="flex bg-[#fff] pt-32px px-24px w-full" :class="fieldSelect ? 'p-20px rounded-b-8px' : ''">
         <select class="w-140px" v-model="productId" :class="{ '!text-[#232A40]': productId !== '' }">
           <option value="" selected>Product</option>
-          <option
-            v-for="item in productList"
-            :key="item.value"
-            :value="item.id"
-          >
+          <option v-for="item in productList" :key="item.value" :value="item.id">
             {{ item.name }}
           </option>
         </select>
@@ -367,19 +347,14 @@ const searchInfo = (val) => {
           </option>
         </select>
         <div class="relative">
-          <el-input
-            v-model="queryString"
-            size="mini"
-            class="!w-316px ml-16px input-with-select"
-            placeholder="Search User Name / Email / License Code"
-          >
+          <el-input v-model="queryString" size="mini" class="!w-316px ml-16px input-with-select"
+            placeholder="Search User Name / Email / License Code">
           </el-input>
-          <button class="absolute top-8px right-8px" @click="searchInfo()"><Search /></button>
+          <button class="absolute top-8px right-8px" @click="searchInfo()">
+            <Search />
+          </button>
         </div>
-        <button
-          type="button"
-          @click="searchInfo()"
-          class="
+        <button type="button" @click="searchInfo()" class="
             w-70px
             h-28px
             border-1px border-[#1460F3]
@@ -387,38 +362,49 @@ const searchInfo = (val) => {
             ml-16px
             text-[#1460F3]
             hover:opacity-80
-          "
-        >
+          ">
           Confirm
         </button>
       </div>
-      <el-table :data="tableData" class="px-24px rounded-b-8px w-full" :key="toggleKey">
+      <el-table :data="tableData" class="step_part1_table px-24px rounded-b-8px w-full" :key="toggleKey">
         <el-table-column v-if="showFiled.includes('Product')" prop="productName" label="Product"> </el-table-column>
-        <el-table-column v-if="showFiled.includes('User Name')" prop="userName" label="User Name" label-class-name="wordBreak"> </el-table-column>
+        <el-table-column v-if="showFiled.includes('User Name')" prop="userName" label="User Name"
+          label-class-name="wordBreak"> </el-table-column>
         <el-table-column v-if="showFiled.includes('Email')" prop="email" label="Email"> </el-table-column>
         <el-table-column v-if="showFiled.includes('Team')" prop="teamName" label="Team"> </el-table-column>
-        <el-table-column v-if="showFiled.includes('License Code')" prop="cdkey" label="License Code" label-class-name="wordBreak"> </el-table-column>
+        <el-table-column v-if="showFiled.includes('License Code')" prop="cdkey" label="License Code"
+          label-class-name="wordBreak">
+          <template slot-scope="scope">
+            <div :class="{ step_part1_first: scope.row.stepIndex === 0 && isFirstTimeLogin }" class="step_part1">
+              {{ scope.row.cdkey }}
+              <img src="@/assets/images/step_arrow.png" alt="step_arrow">
+            </div>
+          </template>
+        </el-table-column>
         <el-table-column v-if="showFiled.includes('Status')" prop="validFlag" label="Status"> </el-table-column>
-        <el-table-column v-if="showFiled.includes('Operated Date')" prop="updatedAt" label="Operated Date" label-class-name="wordBreak"></el-table-column>
-        <el-table-column v-if="showFiled.includes('Expiration Data')" prop="endDate" label="Expiration Data" label-class-name="wordBreak"> </el-table-column>
-        <el-table-column v-if="showFiled.includes('Remaining Activatable Devices')" prop="availableDevices" label="Remaining Activatable Devices" label-class-name="wordBreak"> </el-table-column>
-        <el-table-column v-if="showFiled.includes('Number of Activated Devices')" prop="activatedDevices" label="Number of Activated Devices" label-class-name="wordBreak"> </el-table-column>
+        <el-table-column v-if="showFiled.includes('Operated Date')" prop="updatedAt" label="Operated Date"
+          label-class-name="wordBreak"></el-table-column>
+        <el-table-column v-if="showFiled.includes('Expiration Data')" prop="endDate" label="Expiration Data"
+          label-class-name="wordBreak"> </el-table-column>
+        <el-table-column v-if="showFiled.includes('Remaining Activatable Devices')" prop="availableDevices"
+          label="Remaining Activatable Devices" label-class-name="wordBreak"> </el-table-column>
+        <el-table-column v-if="showFiled.includes('Number of Activated Devices')" prop="activatedDevices"
+          label="Number of Activated Devices" label-class-name="wordBreak"> </el-table-column>
         <el-table-column v-if="showFiled.includes('Action')" prop="operate" label="Action" min-width="120">
-          <p slot="label">Action<Down /></p>
+          <p slot="label">Action
+            <Down />
+          </p>
           <template slot-scope="scope">
             <button
               v-if="scope.row.validFlag === 'Assigned' || scope.row.validFlag === 'Activated' || scope.row.validFlag === 'Partially activated'"
-              @click="handleClick(scope.row)"
-              type="text"
-              class="
+              @click="handleClick(scope.row)" type="text" class="
                 w-70px
                 h-20px
                 rounded-4px
                 border-1px border-[#1460F3]
                 text-[#1460F3]
                 leading-12px
-              "
-            >
+              ">
               Remove
             </button>
             <el-dialog :visible.sync="dialogVisible" width="376px" top="30vh" center :show-close="false">
@@ -438,17 +424,10 @@ const searchInfo = (val) => {
         </el-table-column>
         <p slot="empty">No Data Available</p>
       </el-table>
-      <el-pagination
-        @size-change="handleSizeChange"
-        @current-change="handleCurrentChange"
-        :current-page.sync="currentPage"
-        :page-sizes="[5, 10, 20]"
-        :page-size="size"
-        :background="true"
-        layout="prev, pager, next, sizes, jumper"
-        :total="total"
-        class="px-24px !rounded-0 rounded-b-8px mt-20px flex justify-end"
-      >
+      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page.sync="currentPage" :page-sizes="[5, 10, 20]" :page-size="size" :background="true"
+        layout="prev, pager, next, sizes, jumper" :total="total"
+        class="px-24px !rounded-0 rounded-b-8px mt-20px flex justify-end">
       </el-pagination>
     </div>
   </div>
@@ -465,7 +444,7 @@ const searchInfo = (val) => {
   width: 1100px !important;
 }
 
-.el-table::v-deep .el-table__cell{
+.el-table::v-deep .el-table__cell {
   padding-right: 20px !important;
   padding-left: 20px !important;
 }
@@ -473,21 +452,58 @@ const searchInfo = (val) => {
 .el-table::v-deep thead {
   color: #000 !important;
 }
+
+::v-deep .step_part1_table {
+  overflow: unset;
+
+  .cell {
+    overflow: unset;
+
+    & .step_part1 {
+      margin: -10px;
+      padding: 10px;
+      img {
+        display: none;
+      }
+    }
+
+    .step_part1_first {
+      position: relative;
+      z-index: 10001;
+      background: #fff;
+      border-radius: 6px;
+
+      img {
+        display: block;
+        position: absolute;
+        z-index: 10001;
+        top: -10px;
+        left: -30px;
+        transform: translate(-100%, 0);
+        width: 100px;
+      }
+    }
+  }
+}
+
 ::v-deep .input-with-select .el-input__inner {
   padding: 0 20px 0 8px;
   border-color: #d9d9d9;
   font-size: 14px;
   color: #232A40;
 }
+
 ::v-deep .input-with-select .el-input__inner::placeholder {
   font-size: 14px;
   font-weight: 400;
   color: #808185;
 }
-.el-table::v-deep .el-table__cell .wordBreak{
-  word-break: normal!important;
+
+.el-table::v-deep .el-table__cell .wordBreak {
+  word-break: normal !important;
 }
-.el-table::v-deep .cell{
+
+.el-table::v-deep .cell {
   word-break: break-word;
 }
 </style>

+ 9 - 1
src/views/Login.vue

@@ -176,7 +176,15 @@ export default {
         if (
           res.data.result.role?.indexOf("2") !== -1 || res.data.result.role?.indexOf("1") !== -1
         ) {
-          this.$router.push('/dashboard')
+          // 判断普通用户是否是第一次登录,是的话激活新手引导
+          get('/pdf-tech/vppMember/verifyFirstTimeLogin').then(res => {
+            if (res.data.result) {
+              this.$router.push('/license-management')
+              localStorage.setItem('isFirstTimeLogin', 'true')
+            } else {
+              this.$router.push('/dashboard')
+            }
+          })
         } else {
           this.$router.push('/non-admin-user')
           // this.$router.push('/product?type=isNoAdmin')