浏览代码

feat(login): 增加商户列表功能

- 新增商户列表展示和选择功能
- 实现根据账号获取店铺配置列表的接口和逻辑
- 优化登录流程,支持多店铺选择和单店铺直接登录
- 在 workbench 和 shop 页面中集成店铺 ID 缓存
tangy 1 月之前
父节点
当前提交
dac3c4dd7f
共有 4 个文件被更改,包括 195 次插入146 次删除
  1. 5 1
      src/api/shop.ts
  2. 168 137
      src/views/account/login.vue
  3. 11 4
      src/views/shop/info.vue
  4. 11 4
      src/views/workbench/index.vue

+ 5 - 1
src/api/shop.ts

@@ -4,6 +4,10 @@ export function getShopConfig(params?: any) {
     return request.get({ url: '/shop/config', params })
 }
 
+export function getShopConfigList(params?: any) {
+    return request.get({ url: '/shop/configs', params })
+}
+
 export function changeShopStatus(params?: any) {
     return request.get({ url: '/shop/change', params })
 }
@@ -38,4 +42,4 @@ export function delPrinter(params?: any) {
 
 export function print(params?: any) {
     return request.post({ url: '/printer/print', params })
-}
+}

+ 168 - 137
src/views/account/login.vue

@@ -1,83 +1,85 @@
 <template>
-    <div class="login flex flex-col">
-        <div class="flex-1 flex items-center justify-center">
-            <div class="login-card flex rounded-md">
-                <div class="flex-1 h-full hidden md:inline-block">
-                    <image-contain :src="config.webBackdrop" :width="400" height="100%" />
-                </div>
-                <div
-                    class="login-form bg-body flex flex-col justify-center px-10 py-10 md:w-[400px] w-[375px] flex-none mx-auto"
+  <div class="login flex flex-col">
+    <div class="flex-1 flex items-center justify-center">
+      <div class="login-card flex rounded-md">
+        <div class="flex-1 h-full hidden md:inline-block">
+          <image-contain :src="config.webBackdrop" :width="400" height="100%"/>
+        </div>
+        <div
+            class="login-form bg-body flex flex-col justify-center px-10 py-10 md:w-[400px] w-[375px] flex-none mx-auto"
+        >
+          <div class="text-center text-3xl font-medium mb-8">{{ config.webName }}</div>
+          <div v-if="!showMerchant">
+            <el-form ref="formRef" :model="formData" size="large" :rules="rules">
+              <el-form-item prop="account">
+                <el-input
+                    v-model.trim="formData.account"
+                    placeholder="请输入账号"
+                    @keyup.enter="handleEnter"
+                >
+                  <template #prepend>
+                    <icon name="el-icon-User"/>
+                  </template>
+                </el-input>
+              </el-form-item>
+              <el-form-item prop="password">
+                <el-input
+                    ref="passwordRef"
+                    v-model="formData.password"
+                    show-password
+                    placeholder="请输入密码"
+                    @keyup.enter="handleLogin"
                 >
-                    <div class="text-center text-3xl font-medium mb-8">{{ config.webName }}</div>
-                    <el-form ref="formRef" :model="formData" size="large" :rules="rules">
-                        <el-form-item prop="account">
-                            <el-input
-                                v-model.trim="formData.account"
-                                placeholder="请输入账号"
-                                @keyup.enter="handleEnter"
-                            >
-                                <template #prepend>
-                                    <icon name="el-icon-User" />
-                                </template>
-                            </el-input>
-                        </el-form-item>
-                        <el-form-item prop="password">
-                            <el-input
-                                ref="passwordRef"
-                                v-model="formData.password"
-                                show-password
-                                placeholder="请输入密码"
-                                @keyup.enter="handleLogin"
-                            >
-                                <template #prepend>
-                                    <icon name="el-icon-Lock" />
-                                </template>
-                            </el-input>
-                        </el-form-item>
-                        <!-- <el-form-item prop="code">
-                            <div class="flex items-center">
-                                <el-input
-                                    v-model="formData.code"
-                                    placeholder="请输入验证码"
-                                    @keyup.enter="handleLogin"
-                                >
-                                    <template #prepend>
-                                        <icon name="local-icon-anquan" />
-                                    </template>
-                                </el-input>
-                                <div
-                                    class="ml-4 w-[100px] flex-none cursor-pointer"
-                                    @click="getLoginCaptcha"
-                                >
-                                    <img class="w-full" :src="codeImg" alt="" />
-                                </div>
-                            </div>
-                        </el-form-item> -->
-                    </el-form>
-                    <div class="mb-5">
-                        <el-checkbox v-model="remAccount" label="记住账号"></el-checkbox>
-                    </div>
-                    <el-button type="primary" size="large" :loading="isLock" @click="lockLogin">
-                        登录
-                    </el-button>
-                </div>
+                  <template #prepend>
+                    <icon name="el-icon-Lock"/>
+                  </template>
+                </el-input>
+              </el-form-item>
+            </el-form>
+            <div class="mb-5">
+              <el-checkbox v-model="remAccount" label="记住账号"></el-checkbox>
             </div>
+            <el-button class="w-80" type="primary" size="large" :loading="isLock" @click="lockLogin">
+              登录
+            </el-button>
+          </div>
+          <!-- 商户列表 -->
+          <div v-if="showMerchant">
+            <el-table
+                :data="tableData" class="w-80" height="180"
+                highlight-current-row
+                highlight-selection-row
+                :showHeader="false"
+                @current-change="handleCurrentChange">
+              <el-table-column
+                  prop="name"
+                  label="店铺名称">
+              </el-table-column>
+            </el-table>
+            <el-button class="w-80" type="primary" size="large" @click="handleEnterStore" style="margin-top: 15px">
+              进入店铺
+            </el-button>
+          </div>
         </div>
-        <layout-footer />
+      </div>
     </div>
+    <layout-footer/>
+  </div>
 </template>
 
 <script lang="ts" setup>
-import { computed, onMounted, reactive, ref, shallowRef } from 'vue'
-import type { InputInstance, FormInstance } from 'element-plus'
+import {computed, onMounted, reactive, ref, shallowRef} from 'vue'
+import type {FormInstance, InputInstance} from 'element-plus'
 import LayoutFooter from '@/layout/components/footer.vue'
 import useAppStore from '@/stores/modules/app'
 import useUserStore from '@/stores/modules/user'
 import cache from '@/utils/cache'
-import { ACCOUNT_KEY } from '@/enums/cacheEnums'
-import { PageEnum } from '@/enums/pageEnum'
-import { useLockFn } from '@/hooks/useLockFn'
-import { loginCaptcha } from '@/api/user'
+import {ACCOUNT_KEY, SHOP_ID} from '@/enums/cacheEnums'
+import {PageEnum} from '@/enums/pageEnum'
+import {useLockFn} from '@/hooks/useLockFn'
+import {getShopConfigList} from "@/api/shop";
+import feedback from "@/utils/feedback";
+
 const passwordRef = shallowRef<InputInstance>()
 const formRef = shallowRef<FormInstance>()
 const appStore = useAppStore()
@@ -86,94 +88,123 @@ const route = useRoute()
 const router = useRouter()
 const remAccount = ref(false)
 const config = computed(() => appStore.config)
-const codeImg = ref()
+const showMerchant = ref(false)
+const currentRow = ref({})
 const formData = reactive({
-    account: '',
-    password: '',
-    // code: '',
-    uuid: ''
+  account: '',
+  password: '',
+  // code: '',
+  uuid: ''
 })
 const rules = {
-    account: [
-        {
-            required: true,
-            message: '请输入账号',
-            trigger: ['blur']
-        }
-    ],
-    password: [
-        {
-            required: true,
-            message: '请输入密码',
-            trigger: ['blur']
-        }
-    ]
-    // code: [
-    //     {
-    //         required: true,
-    //         message: '请输入验证码',
-    //         trigger: ['blur']
-    //     }
-    // ]
+  account: [
+    {
+      required: true,
+      message: '请输入账号',
+      trigger: ['blur']
+    }
+  ],
+  password: [
+    {
+      required: true,
+      message: '请输入密码',
+      trigger: ['blur']
+    }
+  ]
 }
-
-const getLoginCaptcha = async () => {
-    const data = await loginCaptcha()
-    formData.uuid = data.uuid
-    codeImg.value = data.img
+const tableData = ref([])
+const handleCurrentChange = (row: any) => {
+  currentRow.value = row
+}
+const handleEnterStore = () => {
+  if (!currentRow.value.id) {
+    feedback.msgWarning('请选择一个店铺进入平台')
+    return
+  }
+  if (currentRow.value.id) {
+    cache.set(SHOP_ID, currentRow.value.id)
+    const {
+      query: {redirect}
+    } = route
+    const path = typeof redirect === 'string' ? redirect : PageEnum.INDEX
+    router.push(path)
+  }
 }
 // 回车按键监听
 const handleEnter = () => {
-    if (!formData.password) {
-        return passwordRef.value?.focus()
-    }
-    handleLogin()
+  if (!formData.password) {
+    return passwordRef.value?.focus()
+  }
+  handleLogin()
 }
 // 登录处理
 const handleLogin = async () => {
-    await formRef.value?.validate()
-    // 记住账号,缓存
-    cache.set(ACCOUNT_KEY, {
-        remember: remAccount.value,
-        account: formData.account
-    })
-    try {
-        let _data = {
-            "mobile": formData.account,
-            "passWord": formData.password,
-            "platform":1,//平台 1.大麦数字营销 2.大麦后台 3.麦芽 4.淘房客 5.电商中心
-        }
-        await userStore.login(_data)
-    } catch (error) {
-        // getLoginCaptcha()
+  await formRef.value?.validate()
+  // 记住账号,缓存
+  cache.set(ACCOUNT_KEY, {
+    remember: remAccount.value,
+    account: formData.account
+  })
+  try {
+    let _data = {
+      "mobile": formData.account,
+      "passWord": formData.password,
+      "platform": 1,//平台 1.大麦数字营销 2.大麦后台 3.麦芽 4.淘房客 5.电商中心
     }
-    const {
-        query: { redirect }
-    } = route
-    const path = typeof redirect === 'string' ? redirect : PageEnum.INDEX
-    router.push(path)
+    await userStore.login(_data)
+  } catch (error) {
+    // getLoginCaptcha()
+  }
+  getShopConfigList({"contactTel": formData.account}).then((res) => {
+    if (res && res.length > 0) {
+      if (res.length == 1) {
+        cache.set(SHOP_ID, res[0].id)
+        const {
+          query: {redirect}
+        } = route
+        const path = typeof redirect === 'string' ? redirect : PageEnum.INDEX
+        router.push(path)
+      } else {
+        showMerchant.value = true
+        tableData.value = res.map((item: any) => {
+          return {
+            id: item.id,
+            name: item.name
+          }
+        })
+      }
+    } else {
+      router.push(PageEnum.ERROR_403)
+    }
+  })
+  /*const {
+    query: {redirect}
+  } = route
+  const path = typeof redirect === 'string' ? redirect : PageEnum.INDEX
+  router.push(path)*/
 }
-const { isLock, lockFn: lockLogin } = useLockFn(handleLogin)
+const {isLock, lockFn: lockLogin} = useLockFn(handleLogin)
 
 onMounted(() => {
-    const value = cache.get(ACCOUNT_KEY)
-    // getLoginCaptcha()
-    if (value?.remember) {
-        remAccount.value = value.remember
-        formData.account = value.account
-    }
+  const value = cache.get(ACCOUNT_KEY)
+  // getLoginCaptcha()
+  if (value?.remember) {
+    remAccount.value = value.remember
+    formData.account = value.account
+  }
 })
 </script>
 
 <style lang="scss" scoped>
 .login {
-    background-image: url('./images/login_bg.png');
-    @apply min-h-screen bg-no-repeat bg-center bg-cover;
-    .login-card {
-        height: 400px;
-        :deep(.el-input-group__prepend) {
-            padding: 0 15px;
-        }
+  background-image: url('./images/login_bg.png');
+  @apply min-h-screen bg-no-repeat bg-center bg-cover;
+  .login-card {
+    height: 400px;
+
+    :deep(.el-input-group__prepend) {
+      padding: 0 15px;
     }
+  }
 }
 </style>

+ 11 - 4
src/views/shop/info.vue

@@ -144,12 +144,19 @@ const formData = reactive({
 
 // 获取店铺信息
 const getData = async () => {
-  const accountCache = cache.get(ACCOUNT_KEY)
+  const shopId = cache.get(SHOP_ID);
   let account = ''
-  if (accountCache) {
-    account = JSON.parse(accountCache).value.account
+  if(!shopId){
+    const accountCache = cache.get(ACCOUNT_KEY)
+    if (accountCache) {
+      account = JSON.parse(accountCache).value.account
+    }
   }
-  const data = await getShopConfig({"contactTel": account})
+  var params = {
+    "shopId": cache.get(SHOP_ID),
+    "contactTel": account
+  }
+  const data = await getShopConfig(params)
   for (const key in formData) {
     //@ts-ignore
     formData[key] = data[key]

+ 11 - 4
src/views/workbench/index.vue

@@ -418,12 +418,19 @@ const getData = async () => {
     workbenchData.visitorOption.series[0].data = res.visitor.list
 }
 const shopInfo = () => {
-  const accountCache = cache.get(ACCOUNT_KEY)
+  const shopId = cache.get(SHOP_ID);
   let account = ''
-  if (accountCache) {
-    account = JSON.parse(accountCache).value.account
+  if(!shopId){
+    const accountCache = cache.get(ACCOUNT_KEY)
+    if (accountCache) {
+      account = JSON.parse(accountCache).value.account
+    }
+  }
+  var params = {
+    "shopId": cache.get(SHOP_ID),
+    "contactTel": account
   }
-    getShopConfig({"contactTel": account}).then((res) => {
+    getShopConfig(params).then((res) => {
         workbenchData.shopId = res.id
         workbenchData.shopName = res.name
         workbenchData.shopStatus = res.status