Browse Source

feat:新加分销商模块

liyangbin 1 year ago
parent
commit
1a508f7992

+ 1 - 1
.env

@@ -1 +1 @@
-VITE_BASE_URL = http://124.223.7.184:8032
+VITE_BASE_URL = http://139.196.160.101:8032

+ 1 - 1
.env.preparing

@@ -1 +1 @@
-VITE_BASE_URL = http://124.223.7.184:8032
+VITE_BASE_URL = http://139.196.160.101:8032

+ 12 - 0
src/components/sideMenu.vue

@@ -90,6 +90,8 @@ export default {
         return 'Super Admin'
       } else if (this.role?.indexOf("2") !== -1){
         return 'Team Admin'
+      } else if (this.role?.indexOf("4") !== -1){
+        return 'Reseller'
       } else {
         return 'Team member'
       }
@@ -142,6 +144,16 @@ export default {
             <span>Device Management</span>
           </el-menu-item>
         </div>
+        <div v-if="role?.indexOf('4') !== -1">
+          <el-menu-item index="/reseller-product">
+            <Product />
+            <span>Product Management</span>
+          </el-menu-item>
+          <el-menu-item index="/reseller-license">
+            <License />
+            <span>License Management</span>
+          </el-menu-item>
+        </div>
         <el-menu-item index="/settings">
           <Settings />
           <span>Settings</span>

+ 17 - 10
src/router/index.js

@@ -206,17 +206,24 @@ const router = new VueRouter({
             title: 'Support | PDF Tech Console'
           }
         },
+        {
+          path: "/reseller-product",
+          name: "ResellerProduct",
+          component: () => import("../views/Reseller/Product.vue"),
+          meta: {
+            title: 'Reseller Product | PDF Tech Console'
+          }
+        },
+        {
+          path: "/reseller-license",
+          name: "ResellerLicense",
+          component: () => import("../views/Reseller/License.vue"),
+          meta: {
+            title: 'Reseller License | PDF Tech Console'
+          }
+        },
       ]
     },
-    // {
-    //   path: "/404",
-    //   name: "404",
-    //   component: () => import("../views/notFind.vue"),
-    // },
-    // {
-    //   path: "*",
-    //   redirect: "/404"
-    // },
     { // 当没有匹配到正确路由的时候,匹配404组件
       path: '*',
       name: "404",
@@ -228,7 +235,7 @@ router.beforeEach((to, from, next) => {
   const whiteList = '/login'
   //路由守卫,进行权限判断
   if (to.path !== whiteList && to.path !== '/sign-up' && to.path !== '/non-admin-user' && to.path !== '/forget-password') {
-    if (userStore().user.role?.indexOf("2") !== -1 || userStore().user.role?.indexOf("1") !== -1) {
+    if (userStore().user.role?.indexOf("2") !== -1 || userStore().user.role?.indexOf("1") !== -1 || userStore().user.role?.indexOf("4") !== -1) {
       next()
     } else {
       next('/non-admin-user')

+ 11 - 0
src/views/Dashboard.vue

@@ -1,8 +1,19 @@
 <script>
 import { get } from '../../utils/request'
 import * as echarts from 'echarts'
+import { userStore } from '@/store/userInfo'
+
 
 export default {
+  beforeRouteEnter(to, from, next) {
+    // 根据需要进行路由守卫逻辑的判断
+    const role = userStore().user.role||''
+    if(role.indexOf('4') !== -1){
+      next('/reseller-product')
+    }else{
+      next()
+    }
+  },
   data () {
     return {
       overview: {

+ 14 - 8
src/views/Login.vue

@@ -151,14 +151,20 @@ export default {
       get('/pdf-tech/vppMember/getMemberInfo').then((res) => {
         if (res.data.code === 200 && res.data.msg == 'success') {
           userStore().setUserInfo(res.data.result)
-          get(
-            '/pdf-tech/vppLicenseCode/checkCompanyLicense?companyId='+res.data.result.companyId
-          ).then((res)=>{
-            if(!res.data.result){
-              this.$router.push('/non-admin-user')
-              return
-            }
-          })
+          // 判断是否是分销商
+          if(res.data.result.role !== '4'){
+            get(
+              '/pdf-tech/vppLicenseCode/checkCompanyLicense?companyId='+res.data.result.companyId
+            ).then((res)=>{
+              if(!res.data.result){
+                this.$router.push('/non-admin-user')
+                return
+              }
+            })
+          } else {
+            this.$router.push('/reseller-product')
+            return
+          }
         }
         if (
           res.data.result.role?.indexOf("2") !== -1 || res.data.result.role?.indexOf("1") !== -1

+ 1 - 1
src/views/ProductManagement.vue

@@ -61,7 +61,7 @@ const handleClick = (val) => {
   cancelUniqueSn.value = val.uniqueSn
 }
 const handleSizeChange = (value) => {
-  size.value = val
+  size.value = value
   currentPage.value = 1
   pagingQuery()
 }

+ 285 - 0
src/views/Reseller/License.vue

@@ -0,0 +1,285 @@
+<script setup>
+import { onMounted, ref, getCurrentInstance } from 'vue'
+import Download from '@/components/icon/download.vue'
+import Warning from '@/components/icon/warning.vue'
+import Search from '@/components/icon/search.vue'
+import { get, post, downLoad } from '../../../utils/request'
+
+const { proxy } = getCurrentInstance()
+const currentPage = ref(1)
+const size = ref(5)
+const productId = ref('')
+const status = ref('')
+const queryString = ref('')
+const total = ref(0)
+const licenseCodeId = ref('')
+const licenseStatus = ref('')
+const tableData = ref([])
+const productList = ref([])
+const dialogVisible = ref(false)
+const cancelLicense = ref('')
+const downloadLoading = ref(false)
+onMounted(() => {
+  let pageText = document.getElementsByClassName('el-pagination__jump')[0]
+  if (pageText) {
+    pageText.childNodes[0].nodeValue = 'Jump to Page'
+  }
+  pagingQuery()
+  getproductList()
+})
+const pagingQuery = (val) => {
+  //初始化表格
+  tableData.value = []
+  get(
+    '/pdf-tech/vppLicenseCode/pageForReseller?page=' +
+      currentPage.value +
+      '&' +
+      'pageSize=' +
+      size.value +
+      '&' +
+      'productId=' +
+      productId.value +
+      '&' +
+      'status=' +
+      status.value +
+      '&' +
+      'queryString=' +
+      queryString.value
+  ).then((res) => {
+    const data = res.data.result.list
+    for (let i = 0; i < data.length; i++) {
+      // 3-Activated,6-Refunded,7-Unactive
+      if (data[i].validFlag === 3) {
+        data[i].validFlag = 'Activated'
+      } else if (data[i].validFlag === 6) {
+        data[i].validFlag = 'Refunded'
+      } else if (data[i].validFlag === 7) {
+        data[i].validFlag = 'Unactive'
+      }
+    }
+    tableData.value = data
+    total.value = res.data.result.total
+  })
+}
+//获取已购买产品
+const getproductList = (val) => {
+  get('/pdf-tech/product/listWithAll').then(
+    (res) => {
+      productList.value = res.data.result
+    }
+  )
+}
+
+//打开对话框
+const handleClick = (val) => {
+  dialogVisible.value = true
+  cancelLicense.value = val.cdkey
+  licenseCodeId.value = val.id
+  licenseStatus.value = val.validFlag
+}
+//取消授权序列码
+const cancelAssign = () => {
+  if (downloadLoading.value) return
+  downloadLoading.value = true
+  if (licenseStatus.value === 'Unactive' || licenseStatus.value === 'Activated') {
+    var urlencoded = new URLSearchParams()
+    urlencoded.append('licenseCodeId', licenseCodeId.value)
+    post(
+      '/pdf-tech/vppLicenseCode/disable',
+      urlencoded
+    ).then((res) => {
+      setTimeout(() => {
+        downloadLoading.value = false
+      }, 2000)
+      if (res.data.code === 200) {
+        pagingQuery()
+        dialogVisible.value = false
+        proxy.$message({
+          duration: 5000,
+          message: 'Cancel Successfully',
+          type: 'success'
+        })
+      }
+    })
+  }
+}
+//切换每页条数
+const handleSizeChange = (val) => {
+  size.value = val
+  currentPage.value = 1
+  pagingQuery()
+}
+//切换分页
+const handleCurrentChange = (val) => {
+  currentPage.value = val
+  pagingQuery()
+}
+//筛选
+const searchInfo = (val) => {
+  currentPage.value = 1
+  pagingQuery()
+}
+</script>
+
+<template>
+  <div class="flex flex-col items-center">
+    <div class="w-full">
+      <h1 class="leading-40px">License Management</h1>
+      <div
+        class="
+          mt-36px
+          mb-16px
+          leading-20px
+          text-16px
+          font-bold
+          flex
+          justify-between
+        "
+      >
+        <span>Content</span>
+      </div>
+      <div class="flex bg-[#fff] pt-32px px-24px rounded-t-8px w-full">
+        <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"
+          >
+            {{ item.name }}
+          </option>
+        </select>
+        <select class="w-140px ml-16px" v-model="status" :class="{ '!text-[#232A40]': status !== '' }">
+          <option value="" selected>Status</option>
+          <option value="7">Unactive</option>
+          <option value="3">Activated</option>
+          <option value="6">Refunded</option>
+        </select>
+        <div class="relative">
+          <el-input
+            v-model="queryString"
+            size="mini"
+            class="!w-316px ml-16px input-with-select"
+            placeholder="License Code"
+          >
+          </el-input>
+          <button class="absolute top-8px right-8px" @click="searchInfo()"><Search /></button>
+        </div>
+        <button
+          type="button"
+          @click="searchInfo()"
+          class="
+            w-70px
+            h-28px
+            border-1px border-[#1460F3]
+            rounded-4px
+            ml-16px
+            text-[#1460F3]
+            hover:opacity-80
+          "
+        >
+          Confirm
+        </button>
+      </div>
+      <el-table :data="tableData" class="px-24px rounded-b-8px w-full">
+        <el-table-column prop="productName" label="Product"> </el-table-column>
+        <el-table-column prop="cdkey" label="License Code" label-class-name="wordBreak"> </el-table-column>
+        <el-table-column prop="validFlag" label="Status"> </el-table-column>
+        <el-table-column prop="operate" label="Action">
+          <template slot-scope="scope">
+            <button
+              v-if="scope.row.validFlag === 'Unactive' || scope.row.validFlag === 'Activated'"
+              @click="handleClick(scope.row)"
+              type="text"
+              class="
+                w-70px
+                h-20px
+                rounded-4px
+                border-1px border-[#1460F3]
+                text-[#1460F3]
+                leading-12px
+              "
+            >
+              Ban
+            </button>
+            <el-dialog :visible.sync="dialogVisible" width="376px" top="30vh" center :show-close="false">
+              <Warning />
+              <p class="mt-16px">Are you sure you want to cancel the license?</p>
+              <p>
+                License: <span class="text-16px font-bold">{{
+                  cancelLicense
+                }}</span>
+              </p>
+              <div class="el-dialog__footer_div flex w-full justify-between">
+                <el-button @click="dialogVisible = false">No</el-button>
+                <el-button type="primary" @click="cancelAssign()">
+                  Yes
+                </el-button>
+              </div>
+            </el-dialog>
+          </template>
+        </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>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.el-table__header-wrapper::v-deep .el-table__header {
+  display: flex;
+  width: 1100px !important;
+}
+
+.el-table__header {
+  display: flex;
+  width: 1100px !important;
+}
+
+.el-table::v-deep .el-table__cell{
+  padding-right: 20px !important;
+  padding-left: 20px !important;
+}
+
+.el-table::v-deep thead {
+  color: #000 !important;
+}
+::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 .cell{
+  word-break: break-word;
+}
+</style>
+
+<style lang="scss">
+::v-deep .input-with-select .el-input__inner::placeholder {
+  font-size: 14px;
+  font-weight: 400;
+  color: #808185;
+}
+</style>
+

+ 160 - 0
src/views/Reseller/Product.vue

@@ -0,0 +1,160 @@
+<script setup>
+import { onMounted, ref } from 'vue'
+import { get } from '../../../utils/request'
+
+const currentPage = ref(1)
+const size = ref(5)
+const tableData = ref([])
+const total = ref(0)
+const productList = ref([])
+const code = ref('')
+
+onMounted(() => {
+  let pageText = document.getElementsByClassName('el-pagination__jump')[0]
+  if (pageText) {
+    pageText.childNodes[0].nodeValue = 'Jump to Page'
+  }
+  pagingQuery()
+  getproductList()
+})
+//筛选
+const searchInfo = () => {
+  currentPage.value = 1
+  pagingQuery()
+}
+//获取分页数据
+const pagingQuery = () => {
+  //初始化表格
+  tableData.value = []
+  get(
+    '/pdf-tech/vppOrderDetail/pageForReseller?page=' +
+      currentPage.value +
+      '&' +
+      'pageSize=' +
+      size.value +
+      '&' +
+      'code=' +
+      code.value
+  ).then((res) => {
+    tableData.value = res.data.result.list
+    total.value = res.data.result.total
+  })
+}
+//获取已购买产品
+const getproductList = (val) => {
+  get('/pdf-tech/product/listWithAll').then(
+    (res) => {
+      productList.value = res.data.result
+    }
+  )
+}
+
+const handleSizeChange = (value) => {
+  size.value = value
+  currentPage.value = 1
+  pagingQuery()
+}
+const handleCurrentChange = (value) => {
+  currentPage.value = value
+  pagingQuery()
+}
+</script>
+
+<template>
+  <div class="flex flex-col items-center">
+    <div class="w-full">
+      <h1 class="leading-40px">Product Management</h1>
+      <div
+        class="
+          mt-36px
+          mb-16px
+          leading-20px
+          text-16px
+          font-bold
+          flex
+          justify-between
+        "
+      >
+        <span>Content</span>
+      </div>
+      <div class="flex bg-[#fff] pt-32px px-24px rounded-t-8px w-full">
+        <select v-model="code" class="w-140px" :class="{ '!text-[#232A40]': code !== '' }">
+          <option value="" selected>Product</option>
+          <option
+            v-for="item in productList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.code"
+          ></option>
+        </select>
+        <button
+          @click="searchInfo()"
+          class="
+            w-70px
+            h-28px
+            border-1px border-[#1460F3]
+            rounded-4px
+            ml-16px
+            text-[#1460F3]
+            hover:opacity-80
+          "
+        >
+          Confirm
+        </button>
+      </div>
+      <el-table :data="tableData" class="px-24px pb-40px rounded-b-8px !w-full">
+        <el-table-column prop="name" label="Product"> </el-table-column>
+        <el-table-column prop="totalNumber" label="Total License Number" label-class-name="wordBreak">
+        </el-table-column>
+        <el-table-column prop="activatedNumber" label="Activated License Number">
+        </el-table-column>
+        <el-table-column prop="refundNumber" label="Refunded License Number">
+        </el-table-column>
+        <el-table-column prop="createdAt" label="Creation Date" min-width="100">
+        </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="5"
+        :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>
+</template>
+
+<style lang="scss" scoped>
+.el-table__header-wrapper::v-deep .el-table__header {
+  display: flex;
+  width: 1100px !important;
+}
+
+.el-table__header {
+  display: flex;
+  width: 1100px !important;
+}
+
+.el-table::v-deep .el-table__cell{
+  padding-right: 20px !important;
+  padding-left: 20px !important;
+}
+
+.el-table::v-deep thead {
+  color: #000 !important;
+}
+
+.el-table::v-deep .el-table__cell .wordBreak{
+  word-break: normal!important;
+}
+.el-table::v-deep .cell{
+  word-break: break-word;
+}
+</style>
+

+ 18 - 5
src/views/Settings.vue

@@ -46,7 +46,8 @@ export default {
           }
         ]
       },
-      generalLoading: false
+      generalLoading: false,
+      role: ''
     }
   },
   methods: {
@@ -153,6 +154,7 @@ export default {
     this.ruleForm.email = userStore().user.email
     this.ruleForm.userName = userStore().user.userName
     this.ruleForm.area = userStore().user.area || ''
+    this.role = userStore().user.role
   }
 }
 </script>
@@ -206,7 +208,18 @@ export default {
         class="p-40px"
         v-show="active === 0"
       >
-        <el-form-item label="User Name" prop="userName">
+        <el-form-item label="Reseller Name" prop="userName" v-if="role === '4'">
+          <div style="display: flex">
+            <el-input
+              v-model="ruleForm.userName"
+              class="username"
+              disabled="true"
+              placeholder="Reseller Name"
+            >
+            </el-input>
+          </div>
+        </el-form-item>
+        <el-form-item label="User Name" prop="userName" v-else>
           <div style="display: flex">
             <el-input
               v-model="ruleForm.userName"
@@ -276,7 +289,7 @@ export default {
               type="password"
               class="username"
               v-model.trim="ruleFormPass.oldPassword"
-              placeholder="Old Password"
+              placeholder="Please enter an old password "
             >
             </el-input>
           </div>
@@ -290,7 +303,7 @@ export default {
               type="password"
               class="username"
               v-model.trim="ruleFormPass.newPassword"
-              placeholder="New Password"
+              placeholder="Please enter a new password "
             >
             </el-input>
           </div>
@@ -304,7 +317,7 @@ export default {
               type="password"
               class="username"
               v-model.trim="ruleFormPass.confirmPassword"
-              placeholder="Confirm Password"
+              placeholder="Please confirm the new password "
             >
             </el-input>
           </div>